Hi tech@,

I wrote a driver to control the APU1 LEDs and read the state of
the pushbutton switch, like skgpio(4).

I would like some reviews and hints about some project decisions 
that I have to make. I am cooking a diff to support APU{2,3,4},
but it is an extension of this code.

Setup:
Machine: APU 1 (dmesg with path applied bellow).
GPIOs: Pushbutton Switch (GPIO 187), LED1 (GPIO 189), LED2 (GPIO 190),
LED3 (GPIO 191).

Implementation: One gpio(4) for pushbutton (gpio0) and other for the
LEDs (gpio1).

apugpio0 at isa0
gpio0 at apugpio0 (You can read, but can't write.)
gpio1 at apugpio0 (You can read and write.)



Questions:

1. It attaches at isabus using iomem. Is it okay?

Kettenis said (here:
https://marc.info/?l=openbsd-tech&m=147023610319035&w=2) that isa
drivers is a risk to probe after hibernate, but is it relevant with
these machines, and considering that it address is fixed and known?
         Alternatives are:
             + I could add the code directly to piixpm(4): gpio0 at
               piixpm(4).
             + Make piixpm(4) like a pcib(4), so I can attach apugpio
               to it (gpio0 at apupgio at piixpm). I think it is 
               intrusive.


2. It has two handlers to map the non contiguous addresses.

It has two handlers, one for the button and the other for the LEDs
(their addresses are contiguous). I did this because I assume that we
must not map GPIOs that we won't use, because we don't know what these
GPIOs does, and if another driver bus_space_map(9) it too the kernel
will panic(4).

Is this approach correct?


3. Is the bus_space_unmap(9) necessary when some of the mappings fails?

The driver is intended to work as a whole (button and leds) or doesn't
work at all. The bus_space_unmap(9) lines in case of failed maps are
necessary? If so, if the second bus_space_map(9) fails, I must unmap
the first one in apugpio_match(), like I am doing inside the attach 
function apugpio_attach().


4. I allow only reading from button, not setting to.

I allow only reading to button, because I think that doesn't make sense to set
its value, and when I tried it the GPIO does not hold the state that I
set. Is that ok?

5. Are there a preferred ordering between the LEDs gpio(4) and the switches one?

Now the button attaches first, but to me it is perfectly natural that
the LEDs, that people may use more, get the gpio0 driver. Any thoughts
about it?


6. Any other comments or suggestions?



Regards,
Rafael


If you have an APU1 and want to test the patch, before using
the gpio(4) devices trough gpioctl(8), you must configure them
before the securelevel is raised. For example, with the 
/etc/rc.securelevel below:

####################################################
#!/bin/sh
#
# $OpenBSD: rc.securelevel,v 1.3 2014/07/14 10:15:33 ajacoutot Exp $
#
# site-specific startup actions, daemons, and other things which
# can be done BEFORE your system goes into securemode.  For actions
# which should be done AFTER your system has gone into securemode
# please see /etc/rc.local.
#

/usr/sbin/gpioctl -q gpio0 0 set

/usr/sbin/gpioctl -q gpio1 0 set
/usr/sbin/gpioctl -q gpio1 1 set
/usr/sbin/gpioctl -q gpio1 2 set
####################################################


dmesg (with patch):
OpenBSD 6.5-beta (GENERIC.MP) #24: Mon Mar 25 00:34:29 WAT 2019
    [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
real mem = 4246003712 (4049MB)
avail mem = 4106997760 (3916MB)
mpath0 at root
scsibus0 at mpath0: 256 targets
mainbus0 at root
bios0 at mainbus0: SMBIOS rev. 2.7 @ 0xdf16d820 (7 entries)
bios0: vendor coreboot version "4.0" date 07/08/2014
bios0: PC Engines APU
acpi0 at bios0: rev 0
acpi0: sleep states S0 S1 S3 S4 S5
acpi0: tables DSDT FACP SPCR HPET APIC HEST SSDT SSDT SSDT
acpi0: wakeup devices AGPB(S4) HDMI(S4) PBR4(S4) PBR5(S4) PBR6(S4) PBR7(S4) 
PE20(S4) PE21(S4) PE22(S4) PE23(S4) PIBR(S4) UOH1(S3) UOH2(S3) UOH3(S3) 
UOH4(S3) UOH5(S3) [...]
acpitimer0 at acpi0: 3579545 Hz, 32 bits
acpihpet0 at acpi0: 14318180 Hz
acpimadt0 at acpi0 addr 0xfee00000: PC-AT compat
cpu0 at mainbus0: apid 0 (boot processor)
cpu0: AMD G-T40E Processor, 1000.15 MHz, 14-02-00
cpu0: 
FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,MWAIT,SSSE3,CX16,POPCNT,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,IBS,SKINIT,ITSC
cpu0: 32KB 64b/line 2-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 
16-way L2 cache
cpu0: 8 4MB entries fully associative
cpu0: DTLB 40 4KB entries fully associative, 8 4MB entries fully associative
cpu0: smt 0, core 0, package 0
mtrr: Pentium Pro MTRR support, 8 var ranges, 88 fixed ranges
cpu0: apic clock running at 199MHz
cpu0: mwait min=64, max=64, IBE
cpu1 at mainbus0: apid 1 (application processor)
cpu1: AMD G-T40E Processor, 1000.00 MHz, 14-02-00
cpu1: 
FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,MWAIT,SSSE3,CX16,POPCNT,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,IBS,SKINIT,ITSC
cpu1: 32KB 64b/line 2-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 
16-way L2 cache
cpu1: 8 4MB entries fully associative
cpu1: DTLB 40 4KB entries fully associative, 8 4MB entries fully associative
cpu1: smt 0, core 1, package 0
ioapic0 at mainbus0: apid 2 pa 0xfec00000, version 21, 24 pins
acpiprt0 at acpi0: bus -1 (AGPB)
acpiprt1 at acpi0: bus -1 (HDMI)
acpiprt2 at acpi0: bus 1 (PBR4)
acpiprt3 at acpi0: bus 2 (PBR5)
acpiprt4 at acpi0: bus 3 (PBR6)
acpiprt5 at acpi0: bus 4 (PBR7)
acpiprt6 at acpi0: bus 6 (PE20)
acpiprt7 at acpi0: bus -1 (PE21)
acpiprt8 at acpi0: bus -1 (PE22)
acpiprt9 at acpi0: bus -1 (PE23)
acpiprt10 at acpi0: bus 0 (PCI0)
acpiprt11 at acpi0: bus 5 (PIBR)
acpicpu0 at acpi0: C2(0@100 io@0x841), C1(@1 halt!), PSS
acpicpu1 at acpi0: C2(0@100 io@0x841), C1(@1 halt!), PSS
acpipci0 at acpi0 PCI0: 0x00000000 0x00000011 0x00000001
acpicmos0 at acpi0
acpibtn0 at acpi0: PWRB
cpu0: 1000 MHz: speeds: 1000 800 MHz
pci0 at mainbus0 bus 0
pchb0 at pci0 dev 0 function 0 "AMD AMD64 14h Host" rev 0x00
ppb0 at pci0 dev 4 function 0 "AMD AMD64 14h PCIE" rev 0x00: msi
pci1 at ppb0 bus 1
re0 at pci1 dev 0 function 0 "Realtek 8168" rev 0x06: RTL8168E/8111E (0x2c00), 
msi, address 00:0d:b9:34:15:c8
rgephy0 at re0 phy 7: RTL8169S/8110S/8211 PHY, rev. 4
ppb1 at pci0 dev 5 function 0 "AMD AMD64 14h PCIE" rev 0x00: msi
pci2 at ppb1 bus 2
re1 at pci2 dev 0 function 0 "Realtek 8168" rev 0x06: RTL8168E/8111E (0x2c00), 
msi, address 00:0d:b9:34:15:c9
rgephy1 at re1 phy 7: RTL8169S/8110S/8211 PHY, rev. 4
ppb2 at pci0 dev 6 function 0 "AMD AMD64 14h PCIE" rev 0x00: msi
pci3 at ppb2 bus 3
re2 at pci3 dev 0 function 0 "Realtek 8168" rev 0x06: RTL8168E/8111E (0x2c00), 
msi, address 00:0d:b9:34:15:ca
rgephy2 at re2 phy 7: RTL8169S/8110S/8211 PHY, rev. 4
ppb3 at pci0 dev 7 function 0 "AMD AMD64 14h PCIE" rev 0x00: msi
pci4 at ppb3 bus 4
athn0 at pci4 dev 0 function 0 "Atheros AR9281" rev 0x01: apic 2 int 19
athn0: AR9280 rev 2 (2T2R), ROM rev 16, address 48:5d:60:77:ad:78
ahci0 at pci0 dev 17 function 0 "ATI SBx00 SATA" rev 0x40: apic 2 int 19, AHCI 
1.2
ahci0: port 0: 6.0Gb/s
scsibus1 at ahci0: 32 targets
sd0 at scsibus1 targ 0 lun 0: <ATA, CHN mSATAQ3 120, Q062> SCSI3 0/direct fixed 
t10.ATA_CHN_mSATAQ3_120_Q320CI10170161_
sd0: 114473MB, 512 bytes/sector, 234441648 sectors, thin
ohci0 at pci0 dev 18 function 0 "ATI SB700 USB" rev 0x00: apic 2 int 18, 
version 1.0, legacy support
ehci0 at pci0 dev 18 function 2 "ATI SB700 USB2" rev 0x00: apic 2 int 17
usb0 at ehci0: USB revision 2.0
uhub0 at usb0 configuration 1 interface 0 "ATI EHCI root hub" rev 2.00/1.00 
addr 1
ohci1 at pci0 dev 19 function 0 "ATI SB700 USB" rev 0x00: apic 2 int 18, 
version 1.0, legacy support
ehci1 at pci0 dev 19 function 2 "ATI SB700 USB2" rev 0x00: apic 2 int 17
usb1 at ehci1: USB revision 2.0
uhub1 at usb1 configuration 1 interface 0 "ATI EHCI root hub" rev 2.00/1.00 
addr 1
piixpm0 at pci0 dev 20 function 0 "ATI SBx00 SMBus" rev 0x42: polling
iic0 at piixpm0
pcib0 at pci0 dev 20 function 3 "ATI SB700 ISA" rev 0x40
ppb4 at pci0 dev 20 function 4 "ATI SB600 PCI" rev 0x40
pci5 at ppb4 bus 5
ohci2 at pci0 dev 20 function 5 "ATI SB700 USB" rev 0x00: apic 2 int 18, 
version 1.0, legacy support
ppb5 at pci0 dev 21 function 0 "ATI SB800 PCIE" rev 0x00
pci6 at ppb5 bus 6
ohci3 at pci0 dev 22 function 0 "ATI SB700 USB" rev 0x00: apic 2 int 18, 
version 1.0, legacy support
ehci2 at pci0 dev 22 function 2 "ATI SB700 USB2" rev 0x00: apic 2 int 17
usb2 at ehci2: USB revision 2.0
uhub2 at usb2 configuration 1 interface 0 "ATI EHCI root hub" rev 2.00/1.00 
addr 1
pchb1 at pci0 dev 24 function 0 "AMD AMD64 14h Link Cfg" rev 0x43
pchb2 at pci0 dev 24 function 1 "AMD AMD64 14h Address Map" rev 0x00
pchb3 at pci0 dev 24 function 2 "AMD AMD64 14h DRAM Cfg" rev 0x00
km0 at pci0 dev 24 function 3 "AMD AMD64 14h Misc Cfg" rev 0x00
pchb4 at pci0 dev 24 function 4 "AMD AMD64 14h CPU Power" rev 0x00
pchb5 at pci0 dev 24 function 5 "AMD AMD64 14h Reserved" rev 0x00
pchb6 at pci0 dev 24 function 6 "AMD AMD64 14h NB Power" rev 0x00
pchb7 at pci0 dev 24 function 7 "AMD AMD64 14h Reserved" rev 0x00
usb3 at ohci0: USB revision 1.0
uhub3 at usb3 configuration 1 interface 0 "ATI OHCI root hub" rev 1.00/1.00 
addr 1
usb4 at ohci1: USB revision 1.0
uhub4 at usb4 configuration 1 interface 0 "ATI OHCI root hub" rev 1.00/1.00 
addr 1
isa0 at pcib0
isadma0 at isa0
com0 at isa0 port 0x3f8/8 irq 4: ns16550a, 16 byte fifo
com0: console
com1 at isa0 port 0x2f8/8 irq 3: ns16550a, 16 byte fifo
pcppi0 at isa0 port 0x61
spkr0 at pcppi0
lpt0 at isa0 port 0x378/4 irq 7
wbsio0 at isa0 port 0x2e/2: NCT5104D rev 0x52
apugpio0 at isa0
gpio0 at apugpio0: 1 pins
gpio1 at apugpio0: 3 pins
usb5 at ohci2: USB revision 1.0
uhub5 at usb5 configuration 1 interface 0 "ATI OHCI root hub" rev 1.00/1.00 
addr 1
usb6 at ohci3: USB revision 1.0
uhub6 at usb6 configuration 1 interface 0 "ATI OHCI root hub" rev 1.00/1.00 
addr 1
vmm0 at mainbus0: SVM/RVI
umsm0 at uhub1 port 1 configuration 1 interface 0 "Sierra Wireless, 
Incorporated MC8790" rev 2.00/0.06 addr 2
ucom0 at umsm0
umsm1 at uhub1 port 1 configuration 1 interface 1 "Sierra Wireless, 
Incorporated MC8790" rev 2.00/0.06 addr 2
ucom1 at umsm1
umsm2 at uhub1 port 1 configuration 1 interface 2 "Sierra Wireless, 
Incorporated MC8790" rev 2.00/0.06 addr 2
ucom2 at umsm2
umsm3 at uhub1 port 1 configuration 1 interface 3 "Sierra Wireless, 
Incorporated MC8790" rev 2.00/0.06 addr 2
ucom3 at umsm3
umsm4 at uhub1 port 1 configuration 1 interface 4 "Sierra Wireless, 
Incorporated MC8790" rev 2.00/0.06 addr 2
ucom4 at umsm4
umsm5 at uhub1 port 1 configuration 1 interface 5 "Sierra Wireless, 
Incorporated MC8790" rev 2.00/0.06 addr 2
ucom5 at umsm5
umsm6 at uhub1 port 1 configuration 1 interface 6 "Sierra Wireless, 
Incorporated MC8790" rev 2.00/0.06 addr 2
ucom6 at umsm6
umass0 at uhub2 port 1 configuration 1 interface 0 "Generic Flash Card 
Reader/Writer" rev 2.01/1.00 addr 2
umass0: using SCSI over Bulk-Only
scsibus2 at umass0: 2 targets, initiator 0
sd1 at scsibus2 targ 1 lun 0: <Multiple, Card Reader, 1.00> SCSI2 0/direct 
removable serial.058f6366058F63666485
vscsi0 at root
scsibus3 at vscsi0: 256 targets
softraid0 at root
scsibus4 at softraid0: 256 targets
root on sd0a (350e2b9c8c888e1d.a) swap on sd0b dump on sd0b




Patch: (available to: https://www.diskless.io/openbsd/apugpio.patch)

Index: sys/arch/amd64/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/amd64/conf/GENERIC,v
retrieving revision 1.467
diff -u -p -u -p -r1.467 GENERIC
--- sys/arch/amd64/conf/GENERIC 22 Mar 2019 12:05:45 -0000      1.467
+++ sys/arch/amd64/conf/GENERIC 25 Mar 2019 00:23:59 -0000
@@ -132,6 +132,12 @@ asmc0      at isa? port 0x300              # Apple SMC
 
 piixpm*        at pci?                 # Intel PIIX PM
 iic*   at piixpm?
+
+
+apugpio* at isa? iomem 0xfed80000      # PC Engines APU 1 GPIO button and LEDs
+gpio* at apugpio?
+
+
 ichiic*        at pci?                 # Intel ICH SMBus controller
 iic*   at ichiic?
 viapm* at pci?                 # VIA SMBus controller
Index: sys/arch/amd64/conf/files.amd64
===================================================================
RCS file: /cvs/src/sys/arch/amd64/conf/files.amd64,v
retrieving revision 1.101
diff -u -p -u -p -r1.101 files.amd64
--- sys/arch/amd64/conf/files.amd64     26 Oct 2018 20:26:19 -0000      1.101
+++ sys/arch/amd64/conf/files.amd64     25 Mar 2019 00:23:59 -0000
@@ -201,6 +201,11 @@ device     skgpio: gpiobus
 attach skgpio at isa
 file   dev/isa/skgpio.c                        skgpio
 
+# APU1 pushbutton switch and LEDs driver
+device apugpio: gpiobus
+attach apugpio at isa
+file   dev/isa/apugpio.c                       apugpio
+
 pseudo-device  pctr
 file   arch/amd64/amd64/pctr.c         pctr needs-flag
 
Index: sys/dev/isa/apugpio.c
===================================================================
RCS file: sys/dev/isa/apugpio.c
diff -N sys/dev/isa/apugpio.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/dev/isa/apugpio.c       25 Mar 2019 00:23:59 -0000
@@ -0,0 +1,227 @@
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+#include <dev/isa/isavar.h>
+#include <dev/isa/isareg.h>
+
+#include <sys/device.h>
+#include <sys/gpio.h>
+#include <dev/gpio/gpiovar.h>
+
+
+
+/* GPIO Base address: AcpiMMioAddr + 0x100 */
+#define        APUGPIO_ACPIMMIOADDR_BASE       0xfed80000 
+#define        APUGPIO_GPIO_BASE               (APUGPIO_ACPIMMIOADDR_BASE + 
0x100)
+
+
+/* Pushbutton switch address (G187)  */
+#define        APUGPIO_BTN_BASE                (APUGPIO_GPIO_BASE + 0xbb) 
+
+#define APUGPIO_BTN_PRESSED            0x28    /* Button pressed value */
+#define APUGPIO_BTN_UNPRESSED          0xa8    /* Button unpressed value */
+
+
+/* LEDs (G189, G190, G191) */
+/* Base address of first LED address */
+#define        APUGPIO_LEDS_BASE               (APUGPIO_GPIO_BASE + 0xbd)
+
+#define        APUGPIO_NLEDS                   3       /* Number of LEDs */
+#define APUGPIO_LED_ON                 0x8     /* LED ON value */
+#define APUGPIO_LED_OFF                        0xc8    /* LED OFF value */
+
+
+extern char *hw_vendor, *hw_prod, *hw_ver;
+
+
+struct apugpio_softc {
+       struct device            sc_dev;
+       bus_space_tag_t          sc_iot;
+
+       /* Pushbutton switch GPIO */
+       bus_space_tag_t          sc_button_iot;
+       bus_space_handle_t       sc_button_ioh;
+
+       struct gpio_chipset_tag  sc_button_gc;
+       gpio_pin_t               sc_button_pin;
+
+       /* LEDs GPIO */
+       bus_space_tag_t          sc_led_iot;
+       bus_space_handle_t       sc_led_ioh;
+
+       struct gpio_chipset_tag  sc_led_gc;
+       gpio_pin_t               sc_led_pins[APUGPIO_NLEDS];
+};
+
+int     apugpio_match(struct device *, void *, void *);
+void    apugpio_attach(struct device *, struct device *, void *);
+void    apugpio_ctl(void *, int, int);
+
+int     apugpio_led_read(void *, int);
+void    apugpio_led_write(void *, int, int);
+void    apugpio_led_ctl(void *, int, int);
+
+
+int     apugpio_button_read(void *, int);
+void    apugpio_button_write(void *, int, int);
+void    apugpio_button_ctl(void *, int, int);
+
+
+
+struct cfattach apugpio_ca = {
+       sizeof(struct apugpio_softc), apugpio_match, apugpio_attach
+};
+
+struct cfdriver apugpio_cd = {
+       NULL, "apugpio", DV_DULL
+};
+
+int
+apugpio_match(struct device *parent, void *match, void *aux)
+{
+       struct isa_attach_args *ia = aux;
+       bus_space_handle_t ioh1, ioh2;
+
+
+       if (hw_vendor == NULL || hw_prod == NULL ||
+           strcmp(hw_vendor, "PC Engines") != 0 ||
+           strcmp(hw_prod, "APU") != 0 ||
+           strcmp(hw_ver, "1.0") != 0)
+               return (0);
+
+        if (ia->ia_maddr != APUGPIO_ACPIMMIOADDR_BASE ||
+           bus_space_map(ia->ia_memt, 
+           APUGPIO_BTN_BASE, 1, 0, &ioh1) != 0 ||
+           bus_space_map(ia->ia_memt, 
+               APUGPIO_LEDS_BASE, APUGPIO_NLEDS, 0, &ioh2) != 0)
+               return (0);
+
+       bus_space_unmap(ia->ia_memt, ioh1, 1);
+       bus_space_unmap(ia->ia_memt, ioh2, APUGPIO_NLEDS);
+
+       ia->ia_iosize = 0;
+       ia->ia_msize = 0;
+
+       return 1;
+}
+
+void
+apugpio_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct apugpio_softc *sc = (void *)self;
+       struct isa_attach_args *ia = aux;
+       struct gpiobus_attach_args gba1, gba2;
+       int i;
+
+
+       sc->sc_iot = ia->ia_memt;
+
+       if (bus_space_map(sc->sc_iot, APUGPIO_BTN_BASE, 1, 0,
+           &sc->sc_button_ioh) != 0) {
+               printf(": can't map button switch i/o space\n");
+               return;
+       }
+
+       if (bus_space_map(sc->sc_iot, APUGPIO_LEDS_BASE, APUGPIO_NLEDS, 0,
+           &sc->sc_led_ioh) != 0) {
+               bus_space_unmap(sc->sc_iot, sc->sc_button_ioh, 1);
+               printf(": can't map leds i/o space\n");
+               return;
+       }
+
+       printf("\n");
+
+
+       /* Configure pushbutton switch */
+       sc->sc_button_pin.pin_num = 0;
+       sc->sc_button_pin.pin_caps = GPIO_PIN_OUTPUT;
+       sc->sc_button_pin.pin_flags = GPIO_PIN_OUTPUT;
+       sc->sc_button_pin.pin_state = apugpio_button_read(sc, i);
+       
+       sc->sc_button_gc.gp_cookie = sc;
+       sc->sc_button_gc.gp_pin_read = apugpio_button_read;
+       sc->sc_button_gc.gp_pin_write = apugpio_button_write;
+       sc->sc_button_gc.gp_pin_ctl = apugpio_button_ctl;
+
+       gba1.gba_name = "gpio";
+       gba1.gba_gc = &sc->sc_button_gc;
+       gba1.gba_pins = &sc->sc_button_pin;
+       gba1.gba_npins = 1;
+
+       (void)config_found(&sc->sc_dev, &gba1, gpiobus_print);
+
+
+       /* Configure LEDs */
+       for (i = 0; i < APUGPIO_NLEDS; i++) {
+               sc->sc_led_pins[i].pin_num = i;
+               sc->sc_led_pins[i].pin_caps = GPIO_PIN_OUTPUT;
+               sc->sc_led_pins[i].pin_flags = GPIO_PIN_OUTPUT;
+               sc->sc_led_pins[i].pin_state = apugpio_led_read(sc, i);
+       }
+
+       sc->sc_led_gc.gp_cookie = sc;
+       sc->sc_led_gc.gp_pin_read = apugpio_led_read;
+       sc->sc_led_gc.gp_pin_write = apugpio_led_write;
+       sc->sc_led_gc.gp_pin_ctl = apugpio_led_ctl;
+
+       gba2.gba_name = "gpio";
+       gba2.gba_gc = &sc->sc_led_gc;
+       gba2.gba_pins = sc->sc_led_pins;
+       gba2.gba_npins = APUGPIO_NLEDS;
+
+       (void)config_found(&sc->sc_dev, &gba2, gpiobus_print);
+}
+
+
+/* LEDs routines */
+int
+apugpio_led_read(void *arg, int pin)
+{
+       struct apugpio_softc *sc = arg;
+       u_int8_t value;
+
+       value = bus_space_read_1(sc->sc_iot, sc->sc_led_ioh, pin);
+       value = (value == APUGPIO_LED_ON) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
+
+        return value;
+}
+
+void
+apugpio_led_write(void *arg, int pin, int value)
+{
+       struct apugpio_softc *sc = arg;
+
+       value = (value == GPIO_PIN_HIGH) ? APUGPIO_LED_ON : APUGPIO_LED_OFF;
+       bus_space_write_1(sc->sc_iot, sc->sc_led_ioh, pin, value);
+}
+
+void
+apugpio_led_ctl(void *arg, int pin, int flags)
+{
+}
+
+
+/* Button routines */
+int
+apugpio_button_read(void *arg, int pin)
+{
+
+       struct apugpio_softc *sc = arg;
+       u_int8_t value;
+
+       value = bus_space_read_1(sc->sc_iot, sc->sc_button_ioh, 0);
+       value = (value == APUGPIO_BTN_PRESSED) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
+
+        return value;
+}
+
+void
+apugpio_button_write(void *arg, int pin, int value)
+{
+}
+
+void
+apugpio_button_ctl(void *arg, int pin, int flags)
+{
+}

Reply via email to