@@ -14,6 +14,7 @@ import (
1414 "path"
1515 "path/filepath"
1616 "runtime"
17+ "sort"
1718 "strings"
1819 "sync"
1920 "time"
@@ -402,6 +403,9 @@ func newGPIOChip(path string) (*GPIOChip, error) {
402403
403404 chip .name = strings .Trim (string (info .name [:]), "\x00 " )
404405 chip .label = strings .Trim (string (info .label [:]), "\x00 " )
406+ if len (chip .label ) == 0 {
407+ chip .label = chip .name
408+ }
405409 chip .lineCount = int (info .lines )
406410 var line_info gpio_v2_line_info
407411 for line := 0 ; line < int (info .lines ); line ++ {
@@ -591,32 +595,82 @@ func (d *driverGPIO) After() []string {
591595//
592596// https://docs.kernel.org/userspace-api/gpio/chardev.html
593597func (d * driverGPIO ) Init () (bool , error ) {
594- if runtime .GOOS == "linux" {
595- items , err := filepath .Glob ("/dev/gpiochip*" )
596- if err != nil {
597- return true , err
598- }
599- if len (items ) == 0 {
600- return false , errors .New ("no GPIO chips found" )
598+ if runtime .GOOS != "linux" {
599+ return true , nil
600+ }
601+ items , err := filepath .Glob ("/dev/gpiochip*" )
602+ if err != nil {
603+ return true , fmt .Errorf ("gpioioctl: %w" , err )
604+ }
605+ if len (items ) == 0 {
606+ return false , errors .New ("no GPIO chips found" )
607+ }
608+ // First, get all of the chips on the system.
609+ var chips []* GPIOChip
610+ var chip * GPIOChip
611+ for _ , item := range items {
612+ chip , err = newGPIOChip (item )
613+ if err == nil {
614+ chips = append (chips , chip )
615+ } else {
616+ log .Println ("gpioioctl.driverGPIO.Init() Error" , err )
601617 }
602- Chips = make ([]* GPIOChip , 0 )
603- for _ , item := range items {
604- chip , err := newGPIOChip (item )
605- if err != nil {
606- log .Println ("gpioioctl.driverGPIO.Init() Error" , err )
607- return false , err
618+ }
619+ // Now, sort the chips so that those labeled with pinctrl- ( a Pi kernel standard)
620+ // come first. Otherwise, sort them by label. This _should_ protect us from any
621+ // random changes in chip naming/ordering.
622+ sort .Slice (chips , func (i , j int ) bool {
623+ I := chips [i ]
624+ J := chips [j ]
625+ if strings .HasPrefix (I .Label (), "pinctrl-" ) {
626+ if strings .HasPrefix (J .Label (), "pinctrl-" ) {
627+ return I .Label () < J .Label ()
608628 }
629+ return true
630+ } else if strings .HasPrefix (J .Label (), "pinctrl-" ) {
631+ return false
632+ }
633+ return I .Label () < J .Label ()
634+ })
635+
636+ mName := make (map [string ]struct {})
637+ // Get a list of already registered GPIO Line names.
638+ registeredPins := make (map [string ]struct {})
639+ for _ , pin := range gpioreg .All () {
640+ registeredPins [pin .Name ()] = struct {}{}
641+ }
642+
643+ // Now, iterate over the chips we found and add their lines to conn/gpio/gpioreg
644+ for _ , chip := range chips {
645+ // On a pi, gpiochip0 is also symlinked to gpiochip4, checking the map
646+ // ensures we don't duplicate the chip.
647+ if _ , found := mName [chip .Name ()]; ! found {
609648 Chips = append (Chips , chip )
649+ mName [chip .Name ()] = struct {}{}
650+ // Now, iterate over the lines on this chip.
610651 for _ , line := range chip .lines {
652+ // If the line has some sort of reasonable name...
611653 if len (line .name ) > 0 && line .name != "_" && line .name != "-" {
654+ // See if the name is already registered. On the Pi5, there are at
655+ // least two chips that export "2712_WAKE" as the line name.
656+ if _ , ok := registeredPins [line .Name ()]; ok {
657+ // This is a duplicate name. Prefix the line name with the
658+ // chip name.
659+ line .name = chip .Name () + "-" + line .Name ()
660+ if _ , found := registeredPins [line .Name ()]; found {
661+ // It's still not unique. Skip it.
662+ continue
663+ }
664+ }
665+ registeredPins [line .Name ()] = struct {}{}
612666 if err = gpioreg .Register (line ); err != nil {
613667 log .Println ("chip" , chip .Name (), " gpioreg.Register(line) " , line , " returned " , err )
614668 }
615669 }
616670 }
617671 }
618672 }
619- return true , nil
673+ return len ( Chips ) > 0 , nil
620674}
621675
622676var drvGPIO driverGPIO
0 commit comments