gpioirq(4) version 2 This update makes this driver more than just an example and allows for: o More than one pin to be attached to a gpioirq instance. That is, the mask parameter can be greater than 0x01 now. o A /dev/gpioirqN device that allows GPIO pin interrupts to be transported into userland. This is a device that can be opened for reading with a simple fixed output indicating the device unit, pin number and current pin state. This update was used as part of a physical intrusion detection system where multiple switches (i.e. window magnetic reed switches and etc.) are tied to a bunch of GPIO inputs with userland software that reacts to the pins changing state.diff -r1.3015 -r1.3016 src/doc/CHANGES
(brad)
--- src/doc/CHANGES 2023/11/05 18:32:01 1.3015
+++ src/doc/CHANGES 2023/11/06 00:35:06 1.3016
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | # LIST OF CHANGES FROM LAST RELEASE: <$Revision: 1.3015 $> | 1 | # LIST OF CHANGES FROM LAST RELEASE: <$Revision: 1.3016 $> | |
2 | # | 2 | # | |
3 | # | 3 | # | |
4 | # [Note: This file does not mention every change made to the NetBSD source tree. | 4 | # [Note: This file does not mention every change made to the NetBSD source tree. | |
5 | # For an exhaustive list, please subscribe to the `source-changes' mailing list, | 5 | # For an exhaustive list, please subscribe to the `source-changes' mailing list, | |
6 | # or see the mailing list archives. For more information, send a message | 6 | # or see the mailing list archives. For more information, send a message | |
7 | # containing just the word `help' to `majordomo@NetBSD.org'.] | 7 | # containing just the word `help' to `majordomo@NetBSD.org'.] | |
8 | # | 8 | # | |
9 | # ---------------------------------------------------------------------------- | 9 | # ---------------------------------------------------------------------------- | |
10 | # PLEASE USE THE FOLLOWING STYLE WHEN ADDING ITEMS: | 10 | # PLEASE USE THE FOLLOWING STYLE WHEN ADDING ITEMS: | |
11 | # | 11 | # | |
12 | # theme: Content ... | 12 | # theme: Content ... | |
13 | # more content ... | 13 | # more content ... | |
14 | # more content. [developer DATE-FORMAT] | 14 | # more content. [developer DATE-FORMAT] | |
@@ -248,13 +248,16 @@ Changes from NetBSD 10.0 to NetBSD 11.0: | @@ -248,13 +248,16 @@ Changes from NetBSD 10.0 to NetBSD 11.0: | |||
248 | graphical console on EFI-only hardware. [bouyer 20231017] | 248 | graphical console on EFI-only hardware. [bouyer 20231017] | |
249 | lagg(4): Copy the MTU of lagg to interfaces added to lagg | 249 | lagg(4): Copy the MTU of lagg to interfaces added to lagg | |
250 | [yamaguchi 20231018] | 250 | [yamaguchi 20231018] | |
251 | dhcpcd: Import version 10.0.4. [roy 20231019] | 251 | dhcpcd: Import version 10.0.4. [roy 20231019] | |
252 | eqos(4): Add support for Intel Elkhart Lake internal Ethernet devices. | 252 | eqos(4): Add support for Intel Elkhart Lake internal Ethernet devices. | |
253 | [msaitoh 20231019] | 253 | [msaitoh 20231019] | |
254 | top(1): Add network in & out bytes to the top display. [mrg 20231021] | 254 | top(1): Add network in & out bytes to the top display. [mrg 20231021] | |
255 | OpenSSL: Imported 3.0.12. [christos 20231025] | 255 | OpenSSL: Imported 3.0.12. [christos 20231025] | |
256 | OpenSSH: Import 9.5. [christos 20231025] | 256 | OpenSSH: Import 9.5. [christos 20231025] | |
257 | newsmips: Add support for LCD-MONO framebuffer on NWS-32x0 laptop | 257 | newsmips: Add support for LCD-MONO framebuffer on NWS-32x0 laptop | |
258 | machines. [tsutsui 20231104] | 258 | machines. [tsutsui 20231104] | |
259 | ena(4): MP-enable always, add RSS support, and reliability fixes. | 259 | ena(4): MP-enable always, add RSS support, and reliability fixes. | |
260 | [jdolecek 20231105] | 260 | [jdolecek 20231105] | |
261 | gpioirq(4): allow multiple pins per gpioirq instance, add the ability | |||
262 | to use a /dev/gpioirqN device to get pin interrupts into userland. | |||
263 | [brad 20231105] |
--- src/etc/MAKEDEV.tmpl 2022/12/28 19:23:02 1.233
+++ src/etc/MAKEDEV.tmpl 2023/11/06 00:35:05 1.234
@@ -1,15 +1,15 @@ | @@ -1,15 +1,15 @@ | |||
1 | #!/bin/sh - | 1 | #!/bin/sh - | |
2 | # $NetBSD: MAKEDEV.tmpl,v 1.233 2022/12/28 19:23:02 jakllsch Exp $ | 2 | # $NetBSD: MAKEDEV.tmpl,v 1.234 2023/11/06 00:35:05 brad Exp $ | |
3 | # | 3 | # | |
4 | # Copyright (c) 2003,2007,2008 The NetBSD Foundation, Inc. | 4 | # Copyright (c) 2003,2007,2008 The NetBSD Foundation, Inc. | |
5 | # All rights reserved. | 5 | # All rights reserved. | |
6 | # | 6 | # | |
7 | # Redistribution and use in source and binary forms, with or without | 7 | # Redistribution and use in source and binary forms, with or without | |
8 | # modification, are permitted provided that the following conditions | 8 | # modification, are permitted provided that the following conditions | |
9 | # are met: | 9 | # are met: | |
10 | # 1. Redistributions of source code must retain the above copyright | 10 | # 1. Redistributions of source code must retain the above copyright | |
11 | # notice, this list of conditions and the following disclaimer. | 11 | # notice, this list of conditions and the following disclaimer. | |
12 | # 2. Redistributions in binary form must reproduce the above copyright | 12 | # 2. Redistributions in binary form must reproduce the above copyright | |
13 | # notice, this list of conditions and the following disclaimer in the | 13 | # notice, this list of conditions and the following disclaimer in the | |
14 | # documentation and/or other materials provided with the distribution. | 14 | # documentation and/or other materials provided with the distribution. | |
15 | # | 15 | # | |
@@ -222,26 +222,27 @@ | @@ -222,26 +222,27 @@ | |||
222 | # cfs* Coda file system device | 222 | # cfs* Coda file system device | |
223 | # ch* SCSI media changer | 223 | # ch* SCSI media changer | |
224 | # cir* Consumer IR | 224 | # cir* Consumer IR | |
225 | # clockctl clock control for non root users | 225 | # clockctl clock control for non root users | |
226 | # cpuctl CPU control | 226 | # cpuctl CPU control | |
227 | # crypto hardware crypto access driver | 227 | # crypto hardware crypto access driver | |
228 | # dmoverio hardware-assisted data movers | 228 | # dmoverio hardware-assisted data movers | |
229 | # dpt* DPT/Adaptec EATA RAID management interface | 229 | # dpt* DPT/Adaptec EATA RAID management interface | |
230 | # dpti* DPT/Adaptec I2O RAID management interface | 230 | # dpti* DPT/Adaptec I2O RAID management interface | |
231 | # drm* Direct Rendering Manager interface | 231 | # drm* Direct Rendering Manager interface | |
232 | # dtv* Digital TV interface | 232 | # dtv* Digital TV interface | |
233 | # fb* PMAX generic framebuffer pseudo-device | 233 | # fb* PMAX generic framebuffer pseudo-device | |
234 | # fd file descriptors | 234 | # fd file descriptors | |
235 | # gpioirq* Interrupts on GPIO pins | |||
235 | # gpiopps* 1PPS signals on GPIO pins | 236 | # gpiopps* 1PPS signals on GPIO pins | |
236 | # grf* graphics frame buffer device | 237 | # grf* graphics frame buffer device | |
237 | # hdaudio* High Definition audio control device | 238 | # hdaudio* High Definition audio control device | |
238 | # hdmicec* HDMI CEC devices | 239 | # hdmicec* HDMI CEC devices | |
239 | # hil HP300 HIL input devices | 240 | # hil HP300 HIL input devices | |
240 | # icp ICP-Vortex/Intel RAID control interface | 241 | # icp ICP-Vortex/Intel RAID control interface | |
241 | # iic* IIC bus device | 242 | # iic* IIC bus device | |
242 | # io x86 IOPL access for COMPAT_10, COMPAT_FREEBSD | 243 | # io x86 IOPL access for COMPAT_10, COMPAT_FREEBSD | |
243 | # iop* I2O IOP control interface | 244 | # iop* I2O IOP control interface | |
244 | # ipmi* OpenIPMI compatible interface | 245 | # ipmi* OpenIPMI compatible interface | |
245 | # ipl IP Filter | 246 | # ipl IP Filter | |
246 | # irframe* IrDA physical frame | 247 | # irframe* IrDA physical frame | |
247 | # ite* terminal emulator interface to HP300 graphics devices | 248 | # ite* terminal emulator interface to HP300 graphics devices | |
@@ -820,27 +821,27 @@ all) | @@ -820,27 +821,27 @@ all) | |||
820 | makedev fss0 fss1 fss2 fss3 | 821 | makedev fss0 fss1 fss2 fss3 | |
821 | makedev md0 md1 | 822 | makedev md0 md1 | |
822 | makedev raid0 raid1 raid2 raid3 raid4 raid5 raid6 raid7 | 823 | makedev raid0 raid1 raid2 raid3 raid4 raid5 raid6 raid7 | |
823 | makedev vnd0 vnd1 vnd2 vnd3 | 824 | makedev vnd0 vnd1 vnd2 vnd3 | |
824 | makedev iscsi0 | 825 | makedev iscsi0 | |
825 | makedev bpf npf | 826 | makedev bpf npf | |
826 | makedev tun0 tun1 tun2 tun3 | 827 | makedev tun0 tun1 tun2 tun3 | |
827 | makedev ipl pf crypto random | 828 | makedev ipl pf crypto random | |
828 | makedev lockstat clockctl cpuctl | 829 | makedev lockstat clockctl cpuctl | |
829 | makedev atabus0 atabus1 atabus2 atabus3 atabus4 atabus5 atabus6 atabus7 | 830 | makedev atabus0 atabus1 atabus2 atabus3 atabus4 atabus5 atabus6 atabus7 | |
830 | makedev srt0 srt1 srt2 srt3 | 831 | makedev srt0 srt1 srt2 srt3 | |
831 | makedev tap tap0 tap1 tap2 tap3 | 832 | makedev tap tap0 tap1 tap2 tap3 | |
832 | makedev gpio gpio0 gpio1 gpio2 gpio3 gpio4 gpio5 gpio6 gpio7 | 833 | makedev gpio gpio0 gpio1 gpio2 gpio3 gpio4 gpio5 gpio6 gpio7 | |
833 | makedev gpiopps0 | 834 | makedev gpioirq0 gpiopps0 | |
834 | makedev pad pad0 pad1 pad2 pad3 | 835 | makedev pad pad0 pad1 pad2 pad3 | |
835 | makedev bthub | 836 | makedev bthub | |
836 | makedev putter | 837 | makedev putter | |
837 | makedev drvctl | 838 | makedev drvctl | |
838 | makedev video | 839 | makedev video | |
839 | makedev dtv | 840 | makedev dtv | |
840 | makedev drm0 drm1 drm2 drm3 | 841 | makedev drm0 drm1 drm2 drm3 | |
841 | makedev altmem | 842 | makedev altmem | |
842 | makedev zfs | 843 | makedev zfs | |
843 | makedev lua | 844 | makedev lua | |
844 | makedev hdmicec0 | 845 | makedev hdmicec0 | |
845 | makedev dtrace | 846 | makedev dtrace | |
846 | makedev veriexec | 847 | makedev veriexec | |
@@ -863,26 +864,30 @@ audio) | @@ -863,26 +864,30 @@ audio) | |||
863 | makedev audio0 audio1 audio2 audio3 | 864 | makedev audio0 audio1 audio2 audio3 | |
864 | makedev hdaudio0 hdaudio1 hdaudio2 hdaudio3 | 865 | makedev hdaudio0 hdaudio1 hdaudio2 hdaudio3 | |
865 | lndev sound0 sound | 866 | lndev sound0 sound | |
866 | lndev audio0 audio | 867 | lndev audio0 audio | |
867 | lndev mixer0 mixer | 868 | lndev mixer0 mixer | |
868 | lndev audioctl0 audioctl | 869 | lndev audioctl0 audioctl | |
869 | ;; | 870 | ;; | |
870 | 871 | |||
871 | gpio) | 872 | gpio) | |
872 | makedev gpio0 gpio1 gpio2 gpio3 gpio4 gpio5 gpio6 gpio7 | 873 | makedev gpio0 gpio1 gpio2 gpio3 gpio4 gpio5 gpio6 gpio7 | |
873 | lndev gpio0 gpio | 874 | lndev gpio0 gpio | |
874 | ;; | 875 | ;; | |
875 | 876 | |||
877 | gpioirq) | |||
878 | makedev gpioirq0 | |||
879 | ;; | |||
880 | ||||
876 | gpiopps) | 881 | gpiopps) | |
877 | makedev gpiopps0 | 882 | makedev gpiopps0 | |
878 | lndev gpiopps0 gpiopps | 883 | lndev gpiopps0 gpiopps | |
879 | ;; | 884 | ;; | |
880 | 885 | |||
881 | lua) | 886 | lua) | |
882 | makedev lua0 | 887 | makedev lua0 | |
883 | lndev lua0 lua | 888 | lndev lua0 lua | |
884 | ;; | 889 | ;; | |
885 | 890 | |||
886 | pad) | 891 | pad) | |
887 | makedev pad0 pad1 pad2 pad3 | 892 | makedev pad0 pad1 pad2 pad3 | |
888 | lndev pad0 pad | 893 | lndev pad0 pad | |
@@ -1537,26 +1542,31 @@ hdaudio[0-9]*) | @@ -1537,26 +1542,31 @@ hdaudio[0-9]*) | |||
1537 | mkdev hdaudio$unit c %hdaudio_chr% $unit 644 | 1542 | mkdev hdaudio$unit c %hdaudio_chr% $unit 644 | |
1538 | ;; | 1543 | ;; | |
1539 | 1544 | |||
1540 | hdmicec[0-9]*) | 1545 | hdmicec[0-9]*) | |
1541 | uint=${i#hdmicec} | 1546 | uint=${i#hdmicec} | |
1542 | mkdev hdmicec$unit c %hdmicec_chr% $unit 644 | 1547 | mkdev hdmicec$unit c %hdmicec_chr% $unit 644 | |
1543 | ;; | 1548 | ;; | |
1544 | 1549 | |||
1545 | gpio[0-9]*) | 1550 | gpio[0-9]*) | |
1546 | unit=${i#gpio} | 1551 | unit=${i#gpio} | |
1547 | mkdev gpio$unit c %gpio_chr% $unit 664 $g_gpio | 1552 | mkdev gpio$unit c %gpio_chr% $unit 664 $g_gpio | |
1548 | ;; | 1553 | ;; | |
1549 | 1554 | |||
1555 | gpioirq[0-9]*) | |||
1556 | unit=${i#gpioirq} | |||
1557 | mkdev gpioirq$unit c %gpioirq_chr% $unit 444 $g_gpio | |||
1558 | ;; | |||
1559 | ||||
1550 | gpiopps[0-9]*) | 1560 | gpiopps[0-9]*) | |
1551 | unit=${i#gpiopps} | 1561 | unit=${i#gpiopps} | |
1552 | mkdev gpiopps$unit c %gpiopps_chr% $unit 664 $g_gpio | 1562 | mkdev gpiopps$unit c %gpiopps_chr% $unit 664 $g_gpio | |
1553 | ;; | 1563 | ;; | |
1554 | 1564 | |||
1555 | lua[0-9]*) | 1565 | lua[0-9]*) | |
1556 | unit=${i#lua} | 1566 | unit=${i#lua} | |
1557 | mkdev lua$unit c %lua_chr% $unit 664 | 1567 | mkdev lua$unit c %lua_chr% $unit 664 | |
1558 | ;; | 1568 | ;; | |
1559 | 1569 | |||
1560 | rmidi[0-9]*) | 1570 | rmidi[0-9]*) | |
1561 | unit=${i#rmidi} | 1571 | unit=${i#rmidi} | |
1562 | mkdev rmidi$unit c %midi_chr% $unit 666 | 1572 | mkdev rmidi$unit c %midi_chr% $unit 666 |
--- src/share/man/man4/gpioirq.4 2023/08/01 20:39:15 1.3
+++ src/share/man/man4/gpioirq.4 2023/11/06 00:35:05 1.4
--- src/sys/conf/majors 2022/08/12 11:15:42 1.102
+++ src/sys/conf/majors 2023/11/06 00:35:05 1.103
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | # $NetBSD: majors,v 1.102 2022/08/12 11:15:42 riastradh Exp $ | 1 | # $NetBSD: majors,v 1.103 2023/11/06 00:35:05 brad Exp $ | |
2 | # | 2 | # | |
3 | # Device majors for Machine-Independent drivers. | 3 | # Device majors for Machine-Independent drivers. | |
4 | # | 4 | # | |
5 | # Majors 0-143 are reserved for machine-dependent drivers and | 5 | # Majors 0-143 are reserved for machine-dependent drivers and | |
6 | # for traditional machine-specific MI driver major mapping. | 6 | # for traditional machine-specific MI driver major mapping. | |
7 | # | 7 | # | |
8 | # Majors 144-159 are reserved for local/vendor use. | 8 | # Majors 144-159 are reserved for local/vendor use. | |
9 | # | 9 | # | |
10 | # Majors 160-511 are used for the MI drivers. | 10 | # Majors 160-511 are used for the MI drivers. | |
11 | 11 | |||
12 | device-major crypto char 160 crypto single | 12 | device-major crypto char 160 crypto single | |
13 | device-major pf char 161 pf single | 13 | device-major pf char 161 pf single | |
14 | #obsolete vinum char 162 vinum | 14 | #obsolete vinum char 162 vinum | |
@@ -86,13 +86,14 @@ device-major spi char 347 spi | @@ -86,13 +86,14 @@ device-major spi char 347 spi | |||
86 | # Major 352 is reserved for external/cddl/osnet/dev/fbt/fbt.c | 86 | # Major 352 is reserved for external/cddl/osnet/dev/fbt/fbt.c | |
87 | # Major 353 is reserved for external/cddl/osnet/dev/sdt/sdt.c | 87 | # Major 353 is reserved for external/cddl/osnet/dev/sdt/sdt.c | |
88 | device-major ipmi char 354 ipmi | 88 | device-major ipmi char 354 ipmi | |
89 | device-major vhci char 355 vhci | 89 | device-major vhci char 355 vhci | |
90 | device-major vio9p char 356 vio9p | 90 | device-major vio9p char 356 vio9p | |
91 | device-major fault char 357 fault | 91 | device-major fault char 357 fault | |
92 | device-major wwanc char 358 wwanc | 92 | device-major wwanc char 358 wwanc | |
93 | device-major acpi char 359 acpi | 93 | device-major acpi char 359 acpi | |
94 | device-major smbios char 360 smbios | 94 | device-major smbios char 360 smbios | |
95 | device-major efi char 361 efi | 95 | device-major efi char 361 efi | |
96 | device-major sht3xtemp char 362 sht3xtemp | 96 | device-major sht3xtemp char 362 sht3xtemp | |
97 | device-major scmd char 363 scmd | 97 | device-major scmd char 363 scmd | |
98 | device-major viocon char 364 viocon | 98 | device-major viocon char 364 viocon | |
99 | device-major gpioirq char 365 gpioirq |
--- src/sys/dev/gpio/gpio.c 2022/12/13 21:50:43 1.72
+++ src/sys/dev/gpio/gpio.c 2023/11/06 00:35:05 1.73
@@ -1,39 +1,39 @@ | @@ -1,39 +1,39 @@ | |||
1 | /* $NetBSD: gpio.c,v 1.72 2022/12/13 21:50:43 jakllsch Exp $ */ | 1 | /* $NetBSD: gpio.c,v 1.73 2023/11/06 00:35:05 brad Exp $ */ | |
2 | /* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */ | 2 | /* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2008, 2009, 2010, 2011 Marc Balmer <marc@msys.ch> | 5 | * Copyright (c) 2008, 2009, 2010, 2011 Marc Balmer <marc@msys.ch> | |
6 | * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org> | 6 | * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org> | |
7 | * | 7 | * | |
8 | * Permission to use, copy, modify, and distribute this software for any | 8 | * Permission to use, copy, modify, and distribute this software for any | |
9 | * purpose with or without fee is hereby granted, provided that the above | 9 | * purpose with or without fee is hereby granted, provided that the above | |
10 | * copyright notice and this permission notice appear in all copies. | 10 | * copyright notice and this permission notice appear in all copies. | |
11 | * | 11 | * | |
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
19 | */ | 19 | */ | |
20 | 20 | |||
21 | #ifdef _KERNEL_OPT | 21 | #ifdef _KERNEL_OPT | |
22 | #include "opt_fdt.h" | 22 | #include "opt_fdt.h" | |
23 | #endif | 23 | #endif | |
24 | 24 | |||
25 | #include <sys/cdefs.h> | 25 | #include <sys/cdefs.h> | |
26 | __KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.72 2022/12/13 21:50:43 jakllsch Exp $"); | 26 | __KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.73 2023/11/06 00:35:05 brad Exp $"); | |
27 | 27 | |||
28 | /* | 28 | /* | |
29 | * General Purpose Input/Output framework. | 29 | * General Purpose Input/Output framework. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/param.h> | 32 | #include <sys/param.h> | |
33 | #include <sys/callout.h> | 33 | #include <sys/callout.h> | |
34 | #include <sys/systm.h> | 34 | #include <sys/systm.h> | |
35 | #include <sys/conf.h> | 35 | #include <sys/conf.h> | |
36 | #include <sys/device.h> | 36 | #include <sys/device.h> | |
37 | #include <sys/fcntl.h> | 37 | #include <sys/fcntl.h> | |
38 | #include <sys/ioctl.h> | 38 | #include <sys/ioctl.h> | |
39 | #include <sys/gpio.h> | 39 | #include <sys/gpio.h> | |
@@ -609,26 +609,34 @@ gpio_intr_str(void *gpio, struct gpio_pi | @@ -609,26 +609,34 @@ gpio_intr_str(void *gpio, struct gpio_pi | |||
609 | return (false); | 609 | return (false); | |
610 | 610 | |||
611 | if (! (*sc->sc_gc->gp_intr_str)(sc->sc_gc->gp_cookie, | 611 | if (! (*sc->sc_gc->gp_intr_str)(sc->sc_gc->gp_cookie, | |
612 | sc->sc_pins[map->pm_map[pin]].pin_num, | 612 | sc->sc_pins[map->pm_map[pin]].pin_num, | |
613 | irqmode, hwstr, sizeof(hwstr))) | 613 | irqmode, hwstr, sizeof(hwstr))) | |
614 | return (false); | 614 | return (false); | |
615 | 615 | |||
616 | (void) snprintf(intrstr, intrstrlen, "%s (%s)", hwstr, mode); | 616 | (void) snprintf(intrstr, intrstrlen, "%s (%s)", hwstr, mode); | |
617 | 617 | |||
618 | return (true); | 618 | return (true); | |
619 | } | 619 | } | |
620 | 620 | |||
621 | int | 621 | int | |
622 | gpio_pin_to_pin_num(void *gpio, struct gpio_pinmap *map, int pin) | |||
623 | { | |||
624 | struct gpio_softc *sc = gpio; | |||
625 | ||||
626 | return sc->sc_pins[map->pm_map[pin]].pin_num; | |||
627 | } | |||
628 | ||||
629 | int | |||
622 | gpio_npins(uint32_t mask) | 630 | gpio_npins(uint32_t mask) | |
623 | { | 631 | { | |
624 | int npins, i; | 632 | int npins, i; | |
625 | 633 | |||
626 | for (npins = 0, i = 0; i < 32; i++) | 634 | for (npins = 0, i = 0; i < 32; i++) | |
627 | if (mask & (1 << i)) | 635 | if (mask & (1 << i)) | |
628 | npins++; | 636 | npins++; | |
629 | 637 | |||
630 | return npins; | 638 | return npins; | |
631 | } | 639 | } | |
632 | 640 | |||
633 | int | 641 | int | |
634 | gpio_lock(void *data) | 642 | gpio_lock(void *data) |
--- src/sys/dev/gpio/gpioirq.c 2018/05/19 14:15:39 1.1
+++ src/sys/dev/gpio/gpioirq.c 2023/11/06 00:35:05 1.2
@@ -1,228 +1,480 @@ | @@ -1,228 +1,480 @@ | |||
1 | /* $NetBSD: gpioirq.c,v 1.1 2018/05/19 14:15:39 thorpej Exp $ */ | 1 | /* $NetBSD: gpioirq.c,v 1.2 2023/11/06 00:35:05 brad Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2016 Brad Spencer <brad@anduin.eldar.org> | 4 | * Copyright (c) 2016, 2023 Brad Spencer <brad@anduin.eldar.org> | |
5 | * | 5 | * | |
6 | * Permission to use, copy, modify, and distribute this software for any | 6 | * Permission to use, copy, modify, and distribute this software for any | |
7 | * purpose with or without fee is hereby granted, provided that the above | 7 | * purpose with or without fee is hereby granted, provided that the above | |
8 | * copyright notice and this permission notice appear in all copies. | 8 | * copyright notice and this permission notice appear in all copies. | |
9 | * | 9 | * | |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 | */ | 17 | */ | |
18 | 18 | |||
19 | #include <sys/cdefs.h> | 19 | #include <sys/cdefs.h> | |
20 | __KERNEL_RCSID(0, "$NetBSD: gpioirq.c,v 1.1 2018/05/19 14:15:39 thorpej Exp $"); | 20 | __KERNEL_RCSID(0, "$NetBSD: gpioirq.c,v 1.2 2023/11/06 00:35:05 brad Exp $"); | |
21 | 21 | |||
22 | /* | 22 | /* | |
23 | * Example GPIO driver that uses interrupts. | 23 | * GPIO driver that uses interrupts and can send that fact to userland. | |
24 | */ | 24 | */ | |
25 | 25 | |||
26 | #include <sys/param.h> | 26 | #include <sys/param.h> | |
27 | #include <sys/systm.h> | 27 | #include <sys/systm.h> | |
28 | #include <sys/device.h> | 28 | #include <sys/device.h> | |
29 | #include <sys/device_impl.h> | |||
29 | #include <sys/gpio.h> | 30 | #include <sys/gpio.h> | |
30 | #include <sys/module.h> | 31 | #include <sys/module.h> | |
32 | #include <sys/conf.h> | |||
33 | #include <sys/proc.h> | |||
34 | #include <sys/pool.h> | |||
35 | #include <sys/kmem.h> | |||
36 | #include <sys/condvar.h> | |||
31 | 37 | |||
32 | #include <dev/gpio/gpiovar.h> | 38 | #include <dev/gpio/gpiovar.h> | |
33 | 39 | |||
34 | #define GPIOIRQ_NPINS 1 | 40 | #define GPIOIRQ_NPINS 64 | |
41 | ||||
42 | struct gpioirq_iv { | |||
43 | char sc_intrstr[128]; | |||
44 | void * sc_ih; | |||
45 | int i_thispin_index; | |||
46 | uint8_t i_thispin_num; | |||
47 | uint8_t i_parentunit; | |||
48 | struct gpioirq_softc *sc; | |||
49 | }; | |||
35 | 50 | |||
36 | struct gpioirq_softc { | 51 | struct gpioirq_softc { | |
37 | device_t sc_dev; | 52 | device_t sc_dev; | |
53 | device_t sc_parentdev; | |||
38 | void * sc_gpio; | 54 | void * sc_gpio; | |
39 | struct gpio_pinmap sc_map; | 55 | struct gpio_pinmap sc_map; | |
40 | int _map[GPIOIRQ_NPINS]; | 56 | int _map[GPIOIRQ_NPINS]; | |
41 | char sc_intrstr[128]; | 57 | struct gpioirq_iv sc_intrs[GPIOIRQ_NPINS]; | |
42 | void * sc_ih; | 58 | int sc_npins; | |
43 | kmutex_t sc_lock; | 59 | kmutex_t sc_lock; | |
60 | kmutex_t sc_read_mutex; | |||
61 | kmutex_t sc_dying_mutex; | |||
44 | bool sc_verbose; | 62 | bool sc_verbose; | |
45 | bool sc_functional; | 63 | bool sc_functional; | |
64 | bool sc_opened; | |||
65 | bool sc_dying; | |||
66 | kcondvar_t sc_condreadready; | |||
67 | kcondvar_t sc_cond_dying; | |||
68 | pool_cache_t sc_readpool; | |||
69 | char *sc_readpoolname; | |||
70 | SIMPLEQ_HEAD(,gpioirq_read_q) sc_read_queue; | |||
71 | }; | |||
72 | ||||
73 | struct gpioirq_read_q { | |||
74 | int parentunit; | |||
75 | int thepin; | |||
76 | int theval; | |||
77 | SIMPLEQ_ENTRY(gpioirq_read_q) read_q; | |||
46 | }; | 78 | }; | |
47 | 79 | |||
48 | #define GPIOIRQ_FLAGS_IRQMODE GPIO_INTR_MODE_MASK | 80 | #define GPIOIRQ_FLAGS_IRQMODE GPIO_INTR_MODE_MASK | |
49 | #define GPIOIRQ_FLAGS_VERBOSE 0x1000 | 81 | #define GPIOIRQ_FLAGS_VERBOSE 0x1000 | |
50 | 82 | |||
51 | static int gpioirq_match(device_t, cfdata_t, void *); | 83 | static int gpioirq_match(device_t, cfdata_t, void *); | |
52 | static void gpioirq_attach(device_t, device_t, void *); | 84 | static void gpioirq_attach(device_t, device_t, void *); | |
53 | static int gpioirq_detach(device_t, int); | 85 | static int gpioirq_detach(device_t, int); | |
54 | static int gpioirq_activate(device_t, enum devact); | 86 | static int gpioirq_activate(device_t, enum devact); | |
55 | ||||
56 | static int gpioirq_intr(void *); | 87 | static int gpioirq_intr(void *); | |
88 | static uint8_t gpioirq_index_to_pin_num(struct gpioirq_softc *, int); | |||
89 | static uint8_t gpioirq_parent_unit(struct gpioirq_softc *); | |||
57 | 90 | |||
58 | CFATTACH_DECL_NEW(gpioirq, sizeof(struct gpioirq_softc), | 91 | CFATTACH_DECL_NEW(gpioirq, sizeof(struct gpioirq_softc), | |
59 | gpioirq_match, gpioirq_attach, | 92 | gpioirq_match, gpioirq_attach, | |
60 | gpioirq_detach, gpioirq_activate); | 93 | gpioirq_detach, gpioirq_activate); | |
61 | 94 | |||
62 | extern struct cfdriver gpioirq_cd; | 95 | extern struct cfdriver gpioirq_cd; | |
63 | 96 | |||
97 | static dev_type_open(gpioirq_open); | |||
98 | static dev_type_read(gpioirq_read); | |||
99 | static dev_type_close(gpioirq_close); | |||
100 | const struct cdevsw gpioirq_cdevsw = { | |||
101 | .d_open = gpioirq_open, | |||
102 | .d_close = gpioirq_close, | |||
103 | .d_read = gpioirq_read, | |||
104 | .d_write = nowrite, | |||
105 | .d_ioctl = noioctl, | |||
106 | .d_stop = nostop, | |||
107 | .d_tty = notty, | |||
108 | .d_poll = nopoll, | |||
109 | .d_mmap = nommap, | |||
110 | .d_kqfilter = nokqfilter, | |||
111 | .d_discard = nodiscard, | |||
112 | .d_flag = D_OTHER | |||
113 | }; | |||
114 | ||||
115 | static uint8_t | |||
116 | gpioirq_index_to_pin_num(struct gpioirq_softc *sc, int index) | |||
117 | { | |||
118 | return (uint8_t)gpio_pin_to_pin_num(sc->sc_gpio, &sc->sc_map, index); | |||
119 | } | |||
120 | ||||
121 | static uint8_t | |||
122 | gpioirq_parent_unit(struct gpioirq_softc *sc) | |||
123 | { | |||
124 | device_t parent = sc->sc_parentdev; | |||
125 | ||||
126 | return (uint8_t)parent->dv_unit; | |||
127 | } | |||
128 | ||||
64 | static int | 129 | static int | |
65 | gpioirq_match(device_t parent, cfdata_t cf, void *aux) | 130 | gpioirq_match(device_t parent, cfdata_t cf, void *aux) | |
66 | { | 131 | { | |
67 | struct gpio_attach_args *ga = aux; | 132 | struct gpio_attach_args *ga = aux; | |
68 | int npins; | |||
69 | 133 | |||
70 | if (strcmp(ga->ga_dvname, cf->cf_name)) | 134 | if (strcmp(ga->ga_dvname, cf->cf_name)) | |
71 | return (0); | 135 | return (0); | |
72 | ||||
73 | if (ga->ga_offset == -1) | |||
74 | return (0); | |||
75 | 136 | |||
76 | npins = gpio_npins(ga->ga_mask); | 137 | if (ga->ga_offset == -1) | |
77 | if (npins > 1) | |||
78 | return (0); | 138 | return (0); | |
79 | 139 | |||
80 | return (1); | 140 | return (1); | |
81 | } | 141 | } | |
82 | 142 | |||
83 | static void | 143 | static void | |
84 | gpioirq_attach(device_t parent, device_t self, void *aux) | 144 | gpioirq_attach(device_t parent, device_t self, void *aux) | |
85 | { | 145 | { | |
86 | struct gpioirq_softc *sc = device_private(self); | 146 | struct gpioirq_softc *sc = device_private(self); | |
87 | struct gpio_attach_args *ga = aux; | 147 | struct gpio_attach_args *ga = aux; | |
88 | int npins = gpio_npins(ga->ga_mask); | 148 | int mask = ga->ga_mask; | |
89 | int irqmode, flags; | 149 | int irqmode, flags; | |
90 | 150 | |||
91 | sc->sc_dev = self; | 151 | sc->sc_dev = self; | |
152 | sc->sc_parentdev = parent; | |||
153 | sc->sc_opened = false; | |||
154 | sc->sc_dying = false; | |||
155 | sc->sc_readpoolname = NULL; | |||
92 | 156 | |||
93 | /* Map pins */ | 157 | /* Map pins */ | |
94 | sc->sc_gpio = ga->ga_gpio; | 158 | sc->sc_gpio = ga->ga_gpio; | |
95 | sc->sc_map.pm_map = sc->_map; | 159 | sc->sc_map.pm_map = sc->_map; | |
96 | 160 | |||
97 | /* We always map just 1 pin. */ | 161 | /* Determine our pin configuation. */ | |
162 | sc->sc_npins = gpio_npins(mask); | |||
163 | if (sc->sc_npins == 0) { | |||
164 | sc->sc_npins = 1; | |||
165 | mask = 0x1; | |||
166 | } | |||
167 | ||||
168 | /* XXX - exit if more than allowed number of pins */ | |||
169 | ||||
98 | if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, | 170 | if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, | |
99 | npins ? ga->ga_mask : 0x1, &sc->sc_map)) { | 171 | mask, &sc->sc_map)) { | |
100 | aprint_error(": can't map pins\n"); | 172 | aprint_error(": can't map pins\n"); | |
101 | return; | 173 | return; | |
102 | } | 174 | } | |
103 | 175 | |||
104 | aprint_normal("\n"); | 176 | aprint_normal("\n"); | |
105 | 177 | |||
106 | if (ga->ga_flags & GPIOIRQ_FLAGS_VERBOSE) | 178 | if (ga->ga_flags & GPIOIRQ_FLAGS_VERBOSE) | |
107 | sc->sc_verbose = true; | 179 | sc->sc_verbose = true; | |
108 | 180 | |||
109 | irqmode = ga->ga_flags & GPIOIRQ_FLAGS_IRQMODE; | 181 | irqmode = ga->ga_flags & GPIOIRQ_FLAGS_IRQMODE; | |
110 | 182 | |||
111 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM); | 183 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM); | |
112 | 184 | mutex_init(&sc->sc_dying_mutex, MUTEX_DEFAULT, IPL_VM); | ||
113 | if (!gpio_intr_str(sc->sc_gpio, &sc->sc_map, 0, irqmode, | 185 | mutex_init(&sc->sc_read_mutex, MUTEX_DEFAULT, IPL_VM); | |
114 | sc->sc_intrstr, sizeof(sc->sc_intrstr))) { | 186 | cv_init(&sc->sc_cond_dying, "girqdie"); | |
115 | aprint_error_dev(self, "failed to decode interrupt\n"); | 187 | cv_init(&sc->sc_condreadready,"girqrr"); | |
116 | return; | 188 | sc->sc_readpoolname = kmem_asprintf("girqread%d",device_unit(self)); | |
117 | } | 189 | sc->sc_readpool = pool_cache_init(sizeof(struct gpioirq_read_q),0,0,0,sc->sc_readpoolname,NULL,IPL_VM,NULL,NULL,NULL); | |
118 | 190 | pool_cache_sethiwat(sc->sc_readpool,100); | ||
119 | if (!gpio_pin_irqmode_issupported(sc->sc_gpio, &sc->sc_map, 0, | 191 | SIMPLEQ_INIT(&sc->sc_read_queue); | |
120 | irqmode)) { | 192 | ||
121 | aprint_error_dev(self, | 193 | for(int apin = 0; apin < sc->sc_npins; apin++) { | |
122 | "irqmode not supported: %s\n", sc->sc_intrstr); | 194 | if (!gpio_intr_str(sc->sc_gpio, &sc->sc_map, apin, irqmode, | |
123 | gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); | 195 | sc->sc_intrs[apin].sc_intrstr, sizeof(sc->sc_intrs[apin].sc_intrstr))) { | |
124 | return; | 196 | aprint_error_dev(self, "failed to decode interrupt\n"); | |
125 | } | 197 | return; | |
126 | 198 | } | ||
127 | flags = gpio_pin_get_conf(sc->sc_gpio, &sc->sc_map, 0); | 199 | ||
128 | flags = (flags & ~(GPIO_PIN_OUTPUT|GPIO_PIN_INOUT)) | | 200 | if (!gpio_pin_irqmode_issupported(sc->sc_gpio, &sc->sc_map, apin, | |
129 | GPIO_PIN_INPUT; | 201 | irqmode)) { | |
130 | if (!gpio_pin_set_conf(sc->sc_gpio, &sc->sc_map, 0, flags)) { | 202 | aprint_error_dev(self, | |
131 | aprint_error_dev(sc->sc_dev, "pin not capable of input\n"); | 203 | "irqmode not supported: %s\n", sc->sc_intrs[apin].sc_intrstr); | |
132 | gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); | 204 | gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); | |
133 | return; | 205 | return; | |
206 | } | |||
207 | ||||
208 | flags = gpio_pin_get_conf(sc->sc_gpio, &sc->sc_map, apin); | |||
209 | flags = (flags & ~(GPIO_PIN_OUTPUT|GPIO_PIN_INOUT)) | | |||
210 | GPIO_PIN_INPUT; | |||
211 | if (!gpio_pin_set_conf(sc->sc_gpio, &sc->sc_map, apin, flags)) { | |||
212 | aprint_error_dev(sc->sc_dev, "pin not capable of input\n"); | |||
213 | gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); | |||
214 | return; | |||
215 | } | |||
216 | ||||
217 | /* These are static for each pin, so just stuff them in here, | |||
218 | * so they don't need to be looked up again. | |||
219 | */ | |||
220 | sc->sc_intrs[apin].i_thispin_index = apin; | |||
221 | sc->sc_intrs[apin].i_thispin_num = gpioirq_index_to_pin_num(sc,apin); | |||
222 | sc->sc_intrs[apin].i_parentunit = gpioirq_parent_unit(sc); | |||
223 | sc->sc_intrs[apin].sc = sc; | |||
224 | ||||
225 | sc->sc_intrs[apin].sc_ih = gpio_intr_establish(sc->sc_gpio, &sc->sc_map, apin, IPL_VM, | |||
226 | irqmode | GPIO_INTR_MPSAFE, | |||
227 | gpioirq_intr, &sc->sc_intrs[apin]); | |||
228 | if (sc->sc_intrs[apin].sc_ih == NULL) { | |||
229 | aprint_error_dev(self, | |||
230 | "unable to establish interrupt on %s\n", sc->sc_intrs[apin].sc_intrstr); | |||
231 | gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); | |||
232 | return; | |||
233 | } | |||
234 | aprint_normal_dev(self, "interrupting on %s\n", sc->sc_intrs[apin].sc_intrstr); | |||
134 | } | 235 | } | |
135 | 236 | |||
136 | sc->sc_ih = gpio_intr_establish(sc->sc_gpio, &sc->sc_map, 0, IPL_VM, | |||
137 | irqmode | GPIO_INTR_MPSAFE, | |||
138 | gpioirq_intr, sc); | |||
139 | if (sc->sc_ih == NULL) { | |||
140 | aprint_error_dev(self, | |||
141 | "unable to establish interrupt on %s\n", sc->sc_intrstr); | |||
142 | gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); | |||
143 | return; | |||
144 | } | |||
145 | aprint_normal_dev(self, "interrupting on %s\n", sc->sc_intrstr); | |||
146 | ||||
147 | sc->sc_functional = true; | 237 | sc->sc_functional = true; | |
148 | } | 238 | } | |
149 | 239 | |||
150 | int | 240 | int | |
151 | gpioirq_intr(void *arg) | 241 | gpioirq_intr(void *arg) | |
152 | { | 242 | { | |
153 | struct gpioirq_softc *sc = arg; | 243 | struct gpioirq_iv *is = arg; | |
244 | struct gpioirq_softc *sc = is->sc; | |||
245 | struct gpioirq_read_q *q; | |||
154 | int val; | 246 | int val; | |
155 | 247 | |||
156 | mutex_enter(&sc->sc_lock); | 248 | mutex_enter(&sc->sc_lock); | |
157 | 249 | |||
158 | val = gpio_pin_read(sc->sc_gpio, &sc->sc_map, 0); | 250 | val = gpio_pin_read(sc->sc_gpio, &sc->sc_map, is->i_thispin_index); | |
159 | 251 | |||
160 | if (sc->sc_verbose) | 252 | if (sc->sc_verbose) | |
161 | printf("%s: interrupt on %s --> %d\n", | 253 | printf("%s: interrupt on %s --> %d\n", | |
162 | device_xname(sc->sc_dev), sc->sc_intrstr, val); | 254 | device_xname(sc->sc_dev), sc->sc_intrs[is->i_thispin_index].sc_intrstr, val); | |
163 | 255 | |||
164 | mutex_exit(&sc->sc_lock); | 256 | mutex_exit(&sc->sc_lock); | |
165 | 257 | |||
258 | if (sc->sc_opened) { | |||
259 | mutex_enter(&sc->sc_read_mutex); | |||
260 | q = pool_cache_get(sc->sc_readpool,PR_NOWAIT); | |||
261 | if (q != NULL) { | |||
262 | q->thepin = is->i_thispin_num; | |||
263 | q->parentunit = is->i_parentunit; | |||
264 | q->theval = val; | |||
265 | SIMPLEQ_INSERT_TAIL(&sc->sc_read_queue,q,read_q); | |||
266 | cv_signal(&sc->sc_condreadready); | |||
267 | } else { | |||
268 | aprint_error("Could not allocate memory for read pool\n"); | |||
269 | } | |||
270 | mutex_exit(&sc->sc_read_mutex); | |||
271 | } | |||
272 | ||||
166 | return (1); | 273 | return (1); | |
167 | } | 274 | } | |
168 | 275 | |||
276 | static int | |||
277 | gpioirq_open(dev_t dev, int flags, int fmt, struct lwp *l) | |||
278 | { | |||
279 | struct gpioirq_softc *sc; | |||
280 | ||||
281 | sc = device_lookup_private(&gpioirq_cd, minor(dev)); | |||
282 | if (!sc) | |||
283 | return (ENXIO); | |||
284 | ||||
285 | if (sc->sc_opened) | |||
286 | return (EBUSY); | |||
287 | ||||
288 | mutex_enter(&sc->sc_lock); | |||
289 | sc->sc_opened = true; | |||
290 | mutex_exit(&sc->sc_lock); | |||
291 | ||||
292 | return (0); | |||
293 | } | |||
294 | ||||
295 | static int | |||
296 | gpioirq_read(dev_t dev, struct uio *uio, int flags) | |||
297 | { | |||
298 | struct gpioirq_softc *sc; | |||
299 | struct gpioirq_read_q *chp; | |||
300 | int error = 0,any; | |||
301 | uint8_t obuf[3]; | |||
302 | ||||
303 | sc = device_lookup_private(&gpioirq_cd, minor(dev)); | |||
304 | if (!sc) | |||
305 | return (ENXIO); | |||
306 | ||||
307 | while (uio->uio_resid > 0) { | |||
308 | any = 0; | |||
309 | error = 0; | |||
310 | mutex_enter(&sc->sc_read_mutex); | |||
311 | ||||
312 | while (any == 0) { | |||
313 | chp = SIMPLEQ_FIRST(&sc->sc_read_queue); | |||
314 | if (chp != NULL) { | |||
315 | SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q); | |||
316 | any = 1; | |||
317 | break; | |||
318 | } else { | |||
319 | error = cv_wait_sig(&sc->sc_condreadready,&sc->sc_read_mutex); | |||
320 | if (sc->sc_dying) | |||
321 | error = EIO; | |||
322 | if (error == 0) | |||
323 | continue; | |||
324 | break; | |||
325 | } | |||
326 | } | |||
327 | ||||
328 | if (any == 1 && error == 0) { | |||
329 | obuf[0] = (uint8_t)chp->parentunit; | |||
330 | obuf[1] = (uint8_t)chp->thepin; | |||
331 | obuf[2] = (uint8_t)chp->theval; | |||
332 | pool_cache_put(sc->sc_readpool,chp); | |||
333 | mutex_exit(&sc->sc_read_mutex); | |||
334 | if ((error = uiomove(&obuf[0], 3, uio)) != 0) { | |||
335 | break; | |||
336 | } | |||
337 | } else { | |||
338 | mutex_exit(&sc->sc_read_mutex); | |||
339 | if (error) { | |||
340 | break; | |||
341 | } | |||
342 | } | |||
343 | } | |||
344 | ||||
345 | if (sc->sc_dying) { | |||
346 | mutex_enter(&sc->sc_dying_mutex); | |||
347 | cv_signal(&sc->sc_cond_dying); | |||
348 | mutex_exit(&sc->sc_dying_mutex); | |||
349 | } | |||
350 | return error; | |||
351 | } | |||
352 | ||||
353 | static int | |||
354 | gpioirq_close(dev_t dev, int flags, int fmt, struct lwp *l) | |||
355 | { | |||
356 | struct gpioirq_softc *sc; | |||
357 | struct gpioirq_read_q *q; | |||
358 | ||||
359 | sc = device_lookup_private(&gpioirq_cd, minor(dev)); | |||
360 | ||||
361 | mutex_enter(&sc->sc_lock); | |||
362 | while ((q = SIMPLEQ_FIRST(&sc->sc_read_queue)) != NULL) { | |||
363 | SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q); | |||
364 | pool_cache_put(sc->sc_readpool,q); | |||
365 | } | |||
366 | sc->sc_opened = false; | |||
367 | mutex_exit(&sc->sc_lock); | |||
368 | ||||
369 | return(0); | |||
370 | } | |||
371 | ||||
169 | int | 372 | int | |
170 | gpioirq_detach(device_t self, int flags) | 373 | gpioirq_detach(device_t self, int flags) | |
171 | { | 374 | { | |
172 | struct gpioirq_softc *sc = device_private(self); | 375 | struct gpioirq_softc *sc = device_private(self); | |
376 | struct gpioirq_read_q *q; | |||
173 | 377 | |||
174 | /* Clear the handler and disable the interrupt. */ | 378 | /* Clear the handler and disable the interrupt. */ | |
175 | gpio_intr_disestablish(sc->sc_gpio, sc->sc_ih); | 379 | for(int apin = 0;apin < sc->sc_npins;apin++) { | |
380 | gpio_intr_disestablish(sc->sc_gpio, sc->sc_intrs[apin].sc_ih); | |||
381 | } | |||
176 | 382 | |||
177 | /* Release the pin. */ | 383 | /* Release the pin. */ | |
178 | gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); | 384 | gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); | |
179 | 385 | |||
386 | sc->sc_dying = true; | |||
387 | ||||
388 | if (sc->sc_opened) { | |||
389 | mutex_enter(&sc->sc_dying_mutex); | |||
390 | mutex_enter(&sc->sc_read_mutex); | |||
391 | cv_signal(&sc->sc_condreadready); | |||
392 | mutex_exit(&sc->sc_read_mutex); | |||
393 | /* In the worst case this will time out after 5 seconds. | |||
394 | * It really should not take that long for the drain / whatever | |||
395 | * to happen | |||
396 | */ | |||
397 | cv_timedwait_sig(&sc->sc_cond_dying, | |||
398 | &sc->sc_dying_mutex, mstohz(5000)); | |||
399 | mutex_exit(&sc->sc_dying_mutex); | |||
400 | cv_destroy(&sc->sc_condreadready); | |||
401 | cv_destroy(&sc->sc_cond_dying); | |||
402 | } | |||
403 | ||||
404 | /* Drain any read pools */ | |||
405 | while ((q = SIMPLEQ_FIRST(&sc->sc_read_queue)) != NULL) { | |||
406 | SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q); | |||
407 | pool_cache_put(sc->sc_readpool,q); | |||
408 | } | |||
409 | ||||
410 | if (sc->sc_readpoolname != NULL) { | |||
411 | kmem_free(sc->sc_readpoolname,strlen(sc->sc_readpoolname) + 1); | |||
412 | } | |||
413 | ||||
414 | mutex_destroy(&sc->sc_read_mutex); | |||
415 | mutex_destroy(&sc->sc_lock); | |||
416 | ||||
180 | return (0); | 417 | return (0); | |
181 | } | 418 | } | |
182 | 419 | |||
183 | int | 420 | int | |
184 | gpioirq_activate(device_t self, enum devact act) | 421 | gpioirq_activate(device_t self, enum devact act) | |
185 | { | 422 | { | |
186 | 423 | |||
424 | struct gpioirq_softc *sc = device_private(self); | |||
425 | ||||
187 | switch (act) { | 426 | switch (act) { | |
188 | case DVACT_DEACTIVATE: | 427 | case DVACT_DEACTIVATE: | |
189 | /* We don't really need to do anything. */ | 428 | sc->sc_dying = true; | |
190 | return (0); | 429 | return (0); | |
191 | default: | 430 | default: | |
192 | return (EOPNOTSUPP); | 431 | return (EOPNOTSUPP); | |
193 | } | 432 | } | |
194 | } | 433 | } | |
195 | 434 | |||
196 | MODULE(MODULE_CLASS_DRIVER, gpioirq, "gpio"); | 435 | MODULE(MODULE_CLASS_DRIVER, gpioirq, "gpio"); | |
197 | 436 | |||
198 | #ifdef _MODULE | 437 | #ifdef _MODULE | |
199 | #include "ioconf.c" | 438 | #include "ioconf.c" | |
200 | #endif | 439 | #endif | |
201 | 440 | |||
202 | static int | 441 | static int | |
203 | gpioirq_modcmd(modcmd_t cmd, void *opaque) | 442 | gpioirq_modcmd(modcmd_t cmd, void *opaque) | |
204 | { | 443 | { | |
205 | int error = 0; | 444 | int error = 0; | |
445 | #ifdef _MODULE | |||
446 | int bmaj = -1, cmaj = -1; | |||
447 | #endif | |||
206 | 448 | |||
207 | switch (cmd) { | 449 | switch (cmd) { | |
208 | case MODULE_CMD_INIT: | 450 | case MODULE_CMD_INIT: | |
209 | #ifdef _MODULE | 451 | #ifdef _MODULE | |
210 | error = config_init_component(cfdriver_ioconf_gpioirq, | 452 | error = config_init_component(cfdriver_ioconf_gpioirq, | |
211 | cfattach_ioconf_gpioirq, cfdata_ioconf_gpioirq); | 453 | cfattach_ioconf_gpioirq, cfdata_ioconf_gpioirq); | |
212 | if (error) | 454 | if (error) { | |
213 | aprint_error("%s: unable to init component\n", | 455 | aprint_error("%s: unable to init component\n", | |
214 | gpioirq_cd.cd_name); | 456 | gpioirq_cd.cd_name); | |
457 | return (error); | |||
458 | } | |||
459 | ||||
460 | error = devsw_attach("gpioirq", NULL, &bmaj, | |||
461 | &gpioirq_cdevsw, &cmaj); | |||
462 | if (error) { | |||
463 | aprint_error("%s: unable to attach devsw\n", | |||
464 | gpioirq_cd.cd_name); | |||
465 | config_fini_component(cfdriver_ioconf_gpioirq, | |||
466 | cfattach_ioconf_gpioirq, cfdata_ioconf_gpioirq); | |||
467 | } | |||
215 | #endif | 468 | #endif | |
216 | break; | 469 | return (error); | |
217 | case MODULE_CMD_FINI: | 470 | case MODULE_CMD_FINI: | |
218 | #ifdef _MODULE | 471 | #ifdef _MODULE | |
472 | devsw_detach(NULL, &gpioirq_cdevsw); | |||
219 | config_fini_component(cfdriver_ioconf_gpioirq, | 473 | config_fini_component(cfdriver_ioconf_gpioirq, | |
220 | cfattach_ioconf_gpioirq, cfdata_ioconf_gpioirq); | 474 | cfattach_ioconf_gpioirq, cfdata_ioconf_gpioirq); | |
221 | #endif | 475 | #endif | |
222 | break; | 476 | return (0); | |
223 | default: | 477 | default: | |
224 | error = ENOTTY; | 478 | return (ENOTTY); | |
225 | } | 479 | } | |
226 | ||||
227 | return (error); | |||
228 | } | 480 | } |
--- src/sys/dev/gpio/gpiovar.h 2018/05/19 13:59:06 1.18
+++ src/sys/dev/gpio/gpiovar.h 2023/11/06 00:35:05 1.19
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: gpiovar.h,v 1.18 2018/05/19 13:59:06 thorpej Exp $ */ | 1 | /* $NetBSD: gpiovar.h,v 1.19 2023/11/06 00:35:05 brad Exp $ */ | |
2 | /* $OpenBSD: gpiovar.h,v 1.3 2006/01/14 12:33:49 grange Exp $ */ | 2 | /* $OpenBSD: gpiovar.h,v 1.3 2006/01/14 12:33:49 grange Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org> | 5 | * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org> | |
6 | * | 6 | * | |
7 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any | |
8 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above | |
9 | * copyright notice and this permission notice appear in all copies. | 9 | * copyright notice and this permission notice appear in all copies. | |
10 | * | 10 | * | |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
@@ -108,18 +108,19 @@ int gpio_pin_caps(void *, struct gpio_pi | @@ -108,18 +108,19 @@ int gpio_pin_caps(void *, struct gpio_pi | |||
108 | int gpio_pin_get_conf(void *, struct gpio_pinmap *, int); | 108 | int gpio_pin_get_conf(void *, struct gpio_pinmap *, int); | |
109 | bool gpio_pin_set_conf(void *, struct gpio_pinmap *, int, int); | 109 | bool gpio_pin_set_conf(void *, struct gpio_pinmap *, int, int); | |
110 | void gpio_pin_ctl(void *, struct gpio_pinmap *, int, int); | 110 | void gpio_pin_ctl(void *, struct gpio_pinmap *, int, int); | |
111 | int gpio_pin_intrcaps(void *, struct gpio_pinmap *, int); | 111 | int gpio_pin_intrcaps(void *, struct gpio_pinmap *, int); | |
112 | bool gpio_pin_irqmode_issupported(void *, struct gpio_pinmap *, int, int); | 112 | bool gpio_pin_irqmode_issupported(void *, struct gpio_pinmap *, int, int); | |
113 | int gpio_pin_wait(void *, int); | 113 | int gpio_pin_wait(void *, int); | |
114 | int gpio_npins(uint32_t); | 114 | int gpio_npins(uint32_t); | |
115 | 115 | |||
116 | void * gpio_intr_establish(void *, struct gpio_pinmap *, int, int, int, | 116 | void * gpio_intr_establish(void *, struct gpio_pinmap *, int, int, int, | |
117 | int (*)(void *), void *); | 117 | int (*)(void *), void *); | |
118 | void gpio_intr_disestablish(void *, void *); | 118 | void gpio_intr_disestablish(void *, void *); | |
119 | bool gpio_intr_str(void *, struct gpio_pinmap *, int, int, | 119 | bool gpio_intr_str(void *, struct gpio_pinmap *, int, int, | |
120 | char *, size_t); | 120 | char *, size_t); | |
121 | int gpio_pin_to_pin_num(void *, struct gpio_pinmap *, int); | |||
121 | 122 | |||
122 | int gpio_lock(void *); | 123 | int gpio_lock(void *); | |
123 | void gpio_unlock(void *); | 124 | void gpio_unlock(void *); | |
124 | 125 | |||
125 | #endif /* !_DEV_GPIO_GPIOVAR_H_ */ | 126 | #endif /* !_DEV_GPIO_GPIOVAR_H_ */ |