1
1
#define _FILE_OFFSET_BITS 64
2
2
#include <assert.h>
3
+ #include <dirent.h>
3
4
#include <errno.h>
4
5
#include <inttypes.h>
5
6
#include <fcntl.h>
@@ -51,14 +52,24 @@ static GPIO_CHIP_INSTANCE_T *gpio_create_instance(const GPIO_CHIP_T *chip,
51
52
const char * name ,
52
53
const char * dtnode )
53
54
{
54
- GPIO_CHIP_INSTANCE_T * inst = & gpio_chips [num_gpio_chips ];
55
+ GPIO_CHIP_INSTANCE_T * inst ;
56
+ unsigned i ;
57
+
58
+ // Skip it if already discovered
59
+ for (i = 0 ; i < num_gpio_chips ; i ++ )
60
+ {
61
+ if (!strcmp (gpio_chips [i ].dtnode , dtnode ))
62
+ return NULL ;
63
+ }
55
64
56
65
if (num_gpio_chips >= MAX_GPIO_CHIPS )
57
66
{
58
67
assert (0 );
59
68
return NULL ;
60
69
}
61
70
71
+ inst = & gpio_chips [num_gpio_chips ];
72
+
62
73
inst -> chip = chip ;
63
74
inst -> name = name ? name : chip -> name ;
64
75
inst -> dtnode = dtnode ;
@@ -411,19 +422,66 @@ static const GPIO_CHIP_T *gpio_find_chip(const char *name)
411
422
return NULL ;
412
423
}
413
424
425
+ static GPIO_CHIP_INSTANCE_T * gpio_add_chip_instance (const char * dtnode , const char * gpiomem_idx )
426
+ {
427
+ char pathbuf [FILENAME_MAX ];
428
+ GPIO_CHIP_INSTANCE_T * inst ;
429
+ const GPIO_CHIP_T * chip ;
430
+ uint64_t phys_addr ;
431
+ char * compatible ;
432
+
433
+ compatible = dt_read_prop (dtnode , "compatible" , NULL );
434
+ if (!compatible )
435
+ {
436
+ sprintf (pathbuf , "%s/.." , dtnode );
437
+ compatible = dt_read_prop (pathbuf , "compatible" , NULL );
438
+ }
439
+
440
+ chip = gpio_find_chip (compatible );
441
+ dt_free (compatible );
442
+
443
+ // Skip unknown gpio chips
444
+ if (!chip )
445
+ return NULL ;
446
+
447
+ if (chip -> size )
448
+ {
449
+ phys_addr = dt_parse_addr (dtnode );
450
+ if (phys_addr == INVALID_ADDRESS )
451
+ return NULL ;
452
+ }
453
+ else
454
+ {
455
+ phys_addr = 0 ;
456
+ }
457
+
458
+ inst = gpio_create_instance (chip , phys_addr , NULL , dtnode );
459
+ // Skip duplicates (or if there is an error)
460
+ if (!inst )
461
+ return NULL ;
462
+
463
+ sprintf (pathbuf , "/dev/gpiomem%s" , gpiomem_idx );
464
+ inst -> mem_fd = open (pathbuf , O_RDWR |O_SYNC );
465
+ return inst ;
466
+ }
467
+
414
468
int gpiolib_init (void )
415
469
{
416
470
const GPIO_CHIP_T * chip ;
417
471
GPIO_CHIP_INSTANCE_T * inst ;
418
472
char pathbuf [FILENAME_MAX ];
419
473
char gpiomem_idx [4 ];
420
- const char * dtpath = "/proc/device-tree" ;
474
+ const char * dtpath = "/sys/firmware/devicetree/base" ;
475
+ const char * ofnode_prefix = dtpath + 4 ;
476
+ const char * gpiopath = "/sys/bus/gpio/devices" ;
477
+ DIR * dir ;
478
+ struct dirent * de ;
421
479
const char * p ;
422
- char * alias = NULL , * names , * end , * compatible ;
423
- uint64_t phys_addr ;
480
+ char * alias = NULL , * names , * end ;
424
481
size_t names_len ;
425
482
unsigned gpio_base ;
426
483
unsigned pin , i ;
484
+ int prefix_len , len ;
427
485
428
486
for (pin = 0 ; pin <= NUM_HDR_PINS ; pin ++ )
429
487
hdr_gpios [pin ] = GPIO_INVALID ;
@@ -447,6 +505,7 @@ int gpiolib_init(void)
447
505
448
506
dt_set_path (dtpath );
449
507
508
+ // Scan the gpio<n> aliases, stopping at the first absence
450
509
for (i = 0 ; ; i ++ )
451
510
{
452
511
sprintf (pathbuf , "gpio%d" , i );
@@ -459,40 +518,32 @@ int gpiolib_init(void)
459
518
}
460
519
if (!alias )
461
520
break ;
462
-
463
- compatible = dt_read_prop (alias , "compatible" , NULL );
464
- if (!compatible )
465
- {
466
- sprintf (pathbuf , "%s/.." , alias );
467
- compatible = dt_read_prop (pathbuf , "compatible" , NULL );
468
- }
469
-
470
- chip = gpio_find_chip (compatible );
471
- dt_free (compatible );
472
-
473
- if (!chip )
474
- {
475
- // Skip the unknown gpio chip
476
- dt_free (alias );
477
- continue ;
478
- }
479
-
480
- phys_addr = dt_parse_addr (alias );
481
- if (phys_addr == INVALID_ADDRESS )
482
- {
521
+ if (!gpio_add_chip_instance (alias , gpiomem_idx ))
483
522
dt_free (alias );
484
- return -1 ;
485
- }
523
+ }
486
524
487
- inst = gpio_create_instance (chip , phys_addr , NULL , alias );
488
- if (!inst )
525
+ // Now look for other gpio chips without aliases
526
+ dir = opendir (gpiopath );
527
+ prefix_len = strlen (ofnode_prefix );
528
+ while (dir && ((de = readdir (dir )) != NULL ))
529
+ {
530
+ if (de -> d_name [0 ] != '.' )
489
531
{
490
- dt_free (alias );
491
- return -1 ;
532
+ char symlink [FILENAME_MAX ];
533
+ char * match ;
534
+ char * dtnode ;
535
+ sprintf (pathbuf , "%s/%s/of_node" , gpiopath , de -> d_name );
536
+ len = readlink (pathbuf , symlink , sizeof (symlink ));
537
+ if (len < 0 )
538
+ continue ;
539
+ symlink [len ] = '\0' ;
540
+ match = strstr (symlink , ofnode_prefix );
541
+ if (!match )
542
+ continue ;
543
+ dtnode = strdup (match + prefix_len );
544
+ if (dtnode && !gpio_add_chip_instance (dtnode , gpiomem_idx ))
545
+ free (dtnode );
492
546
}
493
-
494
- sprintf (pathbuf , "/dev/gpiomem%s" , gpiomem_idx );
495
- inst -> mem_fd = open (pathbuf , O_RDWR |O_SYNC );
496
547
}
497
548
498
549
gpio_base = 0 ;
@@ -663,6 +714,9 @@ int gpiolib_mmap(void)
663
714
inst = & gpio_chips [i ];
664
715
chip = inst -> chip ;
665
716
717
+ if (!chip -> interface -> gpio_probe_instance || !chip -> size )
718
+ continue ;
719
+
666
720
align = inst -> phys_addr & (pagesize - 1 );
667
721
668
722
if (inst -> mem_fd >= 0 )
0 commit comments