Navigation

    全志在线开发者论坛

    • Register
    • Login
    • Search
    • Categories
    • Tags
    • 在线文档
    • 社区主页

    Linux4.9 A100 加载 gpio-keys 驱动可以使用,但是装载过程驱动报错,并且无法卸载。

    其它全志芯片讨论区
    4
    11
    515
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • tigger
      tigger LV 7 last edited by whycan

      kernel/linux-4.9/.config 配置:

      CONFIG_KEYBOARD_GPIO=m
      

      board.dts 配置:

                      gpio_keys {
                              device_type = "gpiokey";
                              compatible = "gpio-keys";
                              status = "okay";
      
                              power_key {
                                      device_type = "ok_key";
                                      label = "gpio key power";
                                      linux,code = <KEY_POWER>;
                                      gpios = <&pio PJ 1 0 1 0 1>;
                                      wakeup-source = <0x1>;
                              };
              };
      

      安装驱动 insmod /lib/modules/4.9.170/gpio_keys.ko:

      root@dragonboard:~# insmod /lib/modules/4.9.170/gpio_keys.ko
      [   35.432556] input: gpiokey as /devices/platform/soc/gpiokey/input/input4
      [   35.441194] Unable to handle kernel paging request at virtual address 100000000
      [   35.449447] pgd = ffffffc03c8e8000
      [   35.453317] [100000000] *pgd=0000000000000000, *pud=0000000000000000
      [   35.460308] Internal error: Oops: 86000005 [#1] PREEMPT SMP
      Segmentation fault
      [   35.460311] Modules linked in:root@dragonboard:~#  gpio_keys(+) 8723ds gt9xxnew_ts
      [   35.460325] CPU: 3 PID: 2010 Comm: insmod Not tainted 4.9.170 #41
      [   35.460327] Hardware name: sun50iw10 (DT)
      [   35.460330] task: ffffffc03ad20e00 task.stack: ffffffc03ca28000
      [   35.460335] PC is at 0x100000000
      [   35.460337] LR is at 0x100000000
      [   35.460341] pc : [<0000000100000000>] lr : [<0000000100000000>] pstate: 40000145
      [   35.460342] sp : ffffffc03ca2bab0
      [   35.460347] x29: 0000000100000000 x28: 0000000000000001
      [   35.460352] x27: 0000000000000000 x26: 0000000000000001
      [   35.460356] x25: ffffffc03b32e7d0 x24: ffffff80008d49d0
      [   35.460361] x23: 0000000000000005 x22: ffffff80008d4818
      [   35.460365] x21: 0000000000000000 x20: ffffff8008ae5000
      [   35.460369] x19: ffffffc03d3dec90 x18: 000000000000000a
      [   35.460374] x17: 0000000000000007 x16: 0000000000000001
      [   35.460378] x15: 000000000000033b x14: ffffff8008abd100
      [   35.460383] x13: 000000000214d000 x12: 0000000000000038
      [   35.460387] x11: 0101010101010101 x10: 7f7f7f7f7f7f7f7f
      [   35.460391] x9 : 0000000000000000 x8 : ffffffc03c5c2538
      [   35.460396] x7 : 0000000000000000 x6 : 000000000000448e
      [   35.460400] x5 : 000000003600e0f6 x4 : ffffffc03b0467b0
      [   35.460404] x3 : 0000000000000001 x2 : 0000000000000000
      [   35.460408] x1 : 0000000000000000 x0 : 0000000000000000
      [   35.460411]
      [   35.460411] SP: 0xffffffc03ca2ba30:
      [   35.460424] ba30  008d4818 ffffff80 00000005 00000000 008d49d0 ffffff80 3b32e7d0 ffffffc0
      [   35.460435] ba50  00000001 00000000 00000000 00000000 00000001 00000000 00000000 00000001
      [   35.460446] ba70  00000000 00000001 3ca2bab0 ffffffc0 00000000 00000001 40000145 00000000
      [   35.460458] ba90  3d3dec90 ffffffc0 08ae5000 ffffff80 ffffffff 0000007f 08ae5000 ffffff80
      [   35.460469] bab0  3ca2baf0 ffffffc0 08380314 ffffff80 3d3dec90 ffffffc0 3d3decf0 ffffffc0
      [   35.460481] bad0  008d4818 ffffff80 08a74000 ffffff80 08a74cf0 ffffff80 08a74000 ffffff80
      [   35.460492] baf0  3ca2bb20 ffffffc0 0837e738 ffffff80 00000000 00000000 008d4818 ffffff80
      [   35.460504] bb10  083802a0 ffffff80 0837e724 ffffff80 3ca2bb60 ffffffc0 0837fc0c ffffff80
      [   35.460508]
      [   35.460508] X4: 0xffffffc03b046730:
      [   35.460523] 6730  cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc
      [   35.460535] 6750  cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc
      [   35.460546] 6770  cccccccc cccccccc cccccccc cccccccc 3b03e600 ffffffc0 3d3d9ae0 ffffffc0
      [   35.460558] 6790  08383148 ffffff80 00000001 00000166 00000164 00000010 0887ecba ffffff80
      [   35.460569] 67b0  3b045e88 ffffffc0 3c5c2488 ffffffc0 00000000 00000000 00000000 00000000
      [   35.460580] 67d0  00000000 00000000 00000000 00000000 00000000 00000000 0838de4c ffffff80
      [   35.460591] 67f0  3b0467a8 ffffffc0 00000003 00000000 00000000 00000000 00000000 00000000
      [   35.460602] 6810  00000000 00000000 8f313930 00000000 00000000 00000000 00000000 00000000
      [   35.460606]
      [   35.460606] X8: 0xffffffc03c5c24b8:
      [   35.460618] 24b8  00000000 00000000 0838de4c ffffff80 3c5c2480 ffffffc0 00000003 00000000
      [   35.460628] 24d8  00000000 00000000 00000000 00000000 00000000 00000000 3cb04c66 00000008
      [   35.460639] 24f8  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [   35.460650] 2518  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [   35.460662] 2538  6b6b6b6b 6b6b6b6b 6b6b6b6b 6b6b6b6b 6b6b6b6b 6b6b6b6b 6b6b6b6b 6b6b6b6b
      [   35.460673] 2558  6b6b6b6b 6b6b6b6b 6b6b6b6b 6b6b6b6b 6b6b6b6b 6b6b6b6b 6b6b6b6b 6b6b6b6b
      [   35.460685] 2578  6b6b6b6b a56b6b6b cccccccc cccccccc 3c5c2d80 ffffffc0 0838d5dc ffffff80
      [   35.460696] 2598  081527c0 ffffff80 08153b94 ffffff80 08153cec ffffff80 08153da0 ffffff80
      [   35.460703]
      [   35.460703] X19: 0xffffffc03d3dec10:
      [   35.460714] ec10  cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc
      [   35.460726] ec30  cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc
      [   35.460738] ec50  cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc
      [   35.460749] ec70  cccccccc cccccccc cccccccc cccccccc 3d3d6b00 ffffffc0 ffffffff 00000000
      [   35.460761] ec90  3d006690 ffffffc0 3d36b080 ffffffc0 3d3d6b00 ffffffc0 3d3d92a8 ffffffc0
      [   35.460772] ecb0  3d3d8ca8 ffffffc0 3d0066a0 ffffffc0 3e234800 ffffffc0 08a74770 ffffff80
      [   35.460783] ecd0  3d3f11d8 ffffffc0 00000005 00000007 00000000 00000000 00000000 00000000
      [   35.460794] ecf0  00000000 00030003 3d3decf8 ffffffc0 3d3decf8 ffffffc0 3ad20e00 ffffffc0
      [   35.460799]
      [   35.460799] X25: 0xffffffc03b32e750:
      [   35.460811] e750  00000000 00000000 00000000 00000000 088227db ffffff80 00000124 00000000
      [   35.460822] e770  080fcee0 ffffff80 00000000 00000000 00000000 00000000 00000000 00000000
      [   35.460833] e790  00000000 00000000 0881e79f ffffff80 00000124 00000000 080fcc6c ffffff80
      [   35.460844] e7b0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [   35.460855] e7d0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [   35.460866] e7f0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [   35.460877] e810  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [   35.460887] e830  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [   35.460890]
      [   35.460894] Process insmod (pid: 2010, stack limit = 0xffffffc03ca28000)
      [   35.460897] Stack: (0xffffffc03ca2bab0 to 0xffffffc03ca2c000)
      [   35.460902] baa0:                                   ffffffc03ca2baf0 ffffff8008380314
      [   35.460907] bac0: ffffffc03d3dec90 ffffffc03d3decf0 ffffff80008d4818 ffffff8008a74000
      [   35.460912] bae0: ffffff8008a74cf0 ffffff8008a74000 ffffffc03ca2bb20 ffffff800837e738
      [   35.460917] bb00: 0000000000000000 ffffff80008d4818 ffffff80083802a0 ffffff800837e724
      [   35.460922] bb20: ffffffc03ca2bb60 ffffff800837fc0c ffffff80008d4818 0000000000000000
      [   35.460927] bb40: ffffffc03cb15280 ffffff80086e0484 ffffffc03e197d28 ffffffc03d36b0e8
      [   35.460932] bb60: ffffffc03ca2bb70 ffffff800837f7c8 ffffffc03ca2bbb0 ffffff8008380bd8
      [   35.460937] bb80: ffffff80008d4818 ffffffc03ad20e00 0000000000000000 ffffff800897d000
      [   35.460942] bba0: ffffff80008d7000 ffffff800829e09c ffffffc03ca2bbe0 ffffff8008381a8c
      [   35.460947] bbc0: 00000000ffffffff ffffffc03ad20e00 0000000000000000 0000000100150014
      [   35.460952] bbe0: ffffffc03ca2bbf0 ffffff80008d7018 ffffffc03ca2bc00 ffffff80080839e0
      [   35.460957] bc00: ffffffc03ca2bc90 ffffff8008110f88 ffffff80008d4980 ffffff8008990000
      [   35.460962] bc20: ffffffc03c623048 ffffffc03c621200 0000000000000000 ffffff8008110f5c
      [   35.460967] bc40: ffffff80008d4980 ffffff8008990000 ffffffc03c623048 ffffff8008990000
      [   35.460972] bc60: 0000000000000000 ffffff80008d49d0 ffffffc03b32e7d0 0000000000000001
      [   35.460977] bc80: 0000000000000000 00000000000409aa ffffffc03ca2bcc0 ffffff80080ff83c
      [   35.460982] bca0: ffffff80008d4980 ffffffc03ca2be58 ffffffc03c623048 ffffff8008990000
      [   35.460987] bcc0: ffffffc03ca2be00 ffffff80080ffd50 00000000000001b8 00000000f6f931c0
      [   35.460992] bce0: ffffff800a0ec1b8 0000000000000000 0000000001555008 0000000000010000
      [   35.460997] bd00: ffffffc03ad20e00 0000000000000080 ffffff8008705000 ffffffc03ad20e00
      [   35.461002] bd20: ffffffc03b32aa80 ffffff8008ab2080 ffffff8008705000 ffffff8000000064
      [   35.461007] bd40: ffffff8000000072 ffffff800897d000 ffffffc00000006e 0000000001555008
      [   35.461012] bd60: ffffff8000000124 ffffff80080fccf4 ffffff800870a000 00000000024000c0
      [   35.461017] bd80: ffffffc03ca2bde0 ffffff8008147094 0000000000000000 0000000000000000
      [   35.461022] bda0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
      [   35.461027] bdc0: 00006c656e72656b 0000000000000000 0000000000000000 0000000000000000
      [   35.461031] bde0: 0000000000000000 0000000000000000 0000000000000000 00000000000409aa
      [   35.461036] be00: 0000000000000000 ffffff8008083200 fffffffffffffe76 0000004036dd6000
      [   35.461041] be20: ffffffffffffffff 00000000f7067ad0 0000000060000010 0000000000000011
      [   35.461046] be40: 000000000000018a ffffff80080877c8 0000000000400004 ffffff800a0ac000
      [   35.461051] be60: 00000000000401b8 ffffff800a0eb7f8 ffffff800a0cc280 ffffff800a0cd510
      [   35.461056] be80: 0000000000001c00 00000000000022f0 0000000000000000 0000000000000000
      [   35.461060] bea0: 00000000000018f0 0000002600000025 0000000000000010 000000000000000c
      [   35.461065] bec0: 00000000f6f53008 00000000000401b8 0000000001555008 00000000ff9c3dd1
      [   35.461069] bee0: 00000000000401b8 0000000000000002 00000000ff9c3dd1 0000000000000080
      [   35.461074] bf00: 00000000000b17f8 0000000000000000 00000000f70d7000 0000000000000000
      [   35.461079] bf20: 00000000ff9c3018 00000000ff9c3008 0000000000019a5c 0000000000000000
      [   35.461083] bf40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
      [   35.461087] bf60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
      [   35.461092] bf80: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
      [   35.461096] bfa0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
      [   35.461101] bfc0: 00000000f7067ad0 0000000060000010 00000000f6f53008 0000000000000080
      [   35.461105] bfe0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
      [   35.461108] Call trace:
      [   35.461111] Exception stack(0xffffffc03ca2b8e0 to 0xffffffc03ca2ba10)
      [   35.461116] b8e0: ffffffc03d3dec90 0000007fffffffff ffffffc03ca2bab0 0000000100000000
      [   35.461121] b900: ffffffc03ca2b940 ffffff80080b7f64 ffffff8008ae5bb0 0000000000000000
      [   35.461126] b920: ffffff800838e294 ffffffc03ca2b980 ffffffc03ca2b970 ffffff800838e294
      [   35.461131] b940: ffffffc03ca2b960 ffffff80086e7ddc ffffffc03d3ded40 ffffffc03d3ded40
      [   35.461136] b960: ffffffc03ca2b970 ffffff80086e819c ffffffc03ca2b980 ffffff800838e2d0
      [   35.461140] b980: 0000000000000000 0000000000000000 0000000000000000 0000000000000001
      [   35.461145] b9a0: ffffffc03b0467b0 000000003600e0f6 000000000000448e 0000000000000000
      [   35.461149] b9c0: ffffffc03c5c2538 0000000000000000 7f7f7f7f7f7f7f7f 0101010101010101
      [   35.461154] b9e0: 0000000000000038 000000000214d000 ffffff8008abd100 000000000000033b
      [   35.461157] ba00: 0000000000000001 0000000000000007
      [   35.461160] [<0000000100000000>] 0x100000000
      [   35.461168] Code: bad PC value
      [   35.461172] ---[ end trace 907da43ec18b52e9 ]---
      root@dragonboard:~#
      

      使用测试:

      root@dragonboard:~# evtest /dev/input/event4
      Input driver version is 1.0.1
      Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100
      Input device name: "gpiokey"
      Supported events:
        Event type 0 (Sync)
        Event type 1 (Key)
          Event code 116 (Power)
      Testing ... (interrupt to exit)
      Event: time 1329177649.837142, type 1 (Key), code 116 (Power), value 1
      Event: time 1329177649.837142, -------------- Report Sync ------------
      Event: time 1329177649.884949, type 1 (Key), code 116 (Power), value 0
      Event: time 1329177649.884949, -------------- Report Sync ------------
      Event: time 1329177654.314768, type 1 (Key), code 116 (Power), value 1
      Event: time 1329177654.314768, -------------- Report Sync ------------
      Event: time 1329177654.538283, type 1 (Key), code 116 (Power), value 0
      Event: time 1329177654.538283, -------------- Report Sync ------------
      Event: time 1329177654.538466, type 1 (Key), code 116 (Power), value 1
      Event: time 1329177654.538466, -------------- Report Sync ------------
      Event: time 1329177654.539263, type 1 (Key), code 116 (Power), value 0
      Event: time 1329177654.539263, -------------- Report Sync ------------
      Event: time 1329177654.828112, type 1 (Key), code 116 (Power), value 1
      Event: time 1329177654.828112, -------------- Report Sync ------------
      Event: time 1329177655.048398, type 1 (Key), code 116 (Power), value 0
      Event: time 1329177655.048398, -------------- Report Sync ------------
      Event: time 1329177655.282155, type 1 (Key), code 116 (Power), value 1
      Event: time 1329177655.282155, -------------- Report Sync ------------
      Event: time 1329177655.475772, type 1 (Key), code 116 (Power), value 0
      Event: time 1329177655.475772, -------------- Report Sync ------------
      

      中断正常:

      root@dragonboard:~# cat /proc/interrupts
                 CPU0       CPU1       CPU2       CPU3
        5:      15931      16899      32881      12213     GIC-0  27 Level     arch_timer
        7:          0          0          0          0  wakeupgen 119 Level     ppu_interrupt
        8:          0          0          0          0  wakeupgen  66 Level     30f0000.iommu
       17:          0          0          0          0  sunxi_pio_edge   7 Edge      rtw_wifi_gpio_wakeup
      185:          1          0          0          0  sunxi_pio_edge 134 Edge      sdc0 cd
      308:         13          0          0          0  sunxi_pio_edge 257 Edge      gpio key power
      

      不能卸载:

      root@dragonboard:~# rmmod gpio_keys
      rmmod: can't unload 'gpio_keys': Device or resource busy
      root@dragonboard:~# 
      
      1 Reply Last reply Reply Quote Share 0
      • tigger
        tigger LV 7 last edited by

        参考链接: Linux_GPIO_开发指南.pdf

        d520d153-770e-4c7a-86b5-0c725e45659b-image.png

        a0554512-69bc-4057-840b-2ddff9f1a625-image.png

        1 Reply Last reply Reply Quote Share 0
        • tigger
          tigger LV 7 last edited by

          但是同样的配置用在旋转编码器 CONFIG_INPUT_GPIO_ROTARY_ENCODER=m 完全正常,也是中断模式。

          1 Reply Last reply Reply Quote Share 0
          • tigger
            tigger LV 7 last edited by

            我开始以为这个问题可以不解决,结果Linux是可以用,但是进入安卓系统会直接挂掉:

            [    3.123534] input: soc@03000000:gpio_keys as /devices/platform/soc/soc@03000000:gpio_keys/input/input2
            [    3.134354] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: gpio_keys_probe+0x844/0x848
            

            然后就没然后了。

            D 1 Reply Last reply Reply Quote Share 0
            • YuzukiTsuru
              柚木 鉉 LV 9 last edited by YuzukiTsuru

              改一下驱动

              From 35d26bbc1975aa3b79bce8bcbcde15c0857093dd Mon Sep 17 00:00:00 2001
              From: YuzukiTsuru <gloomyghost@gloomyghost.com>
              Date: Tue, 5 Apr 2022 00:19:12 +0800
              Subject: [PATCH] fix gpio keys sunxi driver
              
              Signed-off-by: YuzukiTsuru <gloomyghost@gloomyghost.com>
              ---
               gpio_keys.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++----
               1 file changed, 88 insertions(+), 6 deletions(-)
              
              diff --git a/gpio_keys.c b/gpio_keys.c
              index 9b8079c..077e50b 100644
              --- a/gpio_keys.c
              +++ b/gpio_keys.c
              @@ -33,6 +33,22 @@
               #include <linux/of_irq.h>
               #include <linux/spinlock.h>
               
              +#ifdef CONFIG_ARCH_SUNXI
              +#include <linux/sunxi-gpio.h>
              +#ifdef CONFIG_GPIOKEYS_AS_POWERKEY
              +#include <linux/kthread.h>
              +#include <linux/reboot.h>
              +#include <linux/jiffies.h>
              +struct long_press_key {
              +	struct delayed_work long_work;
              +	unsigned long start;
              +	int press_sta;
              +};
              +
              +static struct long_press_key long_press_key;
              +#endif
              +#endif
              +
               struct gpio_button_data {
               	const struct gpio_keys_button *button;
               	struct input_dev *input;
              @@ -142,10 +158,14 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
               		 */
               		disable_irq(bdata->irq);
               
              -		if (bdata->gpiod)
              +		if (bdata->gpiod) {
               			cancel_delayed_work_sync(&bdata->work);
              -		else
              +#ifdef CONFIG_GPIOKEYS_AS_POWERKEY
              +			cancel_delayed_work_sync(&long_press_key.long_work);
              +#endif
              +		} else {
               			del_timer_sync(&bdata->release_timer);
              +		}
               
               		bdata->disabled = true;
               	}
              @@ -355,12 +375,33 @@ static struct attribute_group gpio_keys_attr_group = {
               	.attrs = gpio_keys_attrs,
               };
               
              +#ifdef CONFIG_GPIOKEYS_AS_POWERKEY
              +static void gpio_keys_long_press_func(struct work_struct *work)
              +{
              +	struct long_press_key *key = &long_press_key;
              +	unsigned long end;
              +	unsigned long diff_time;
              +
              +	end = jiffies;
              +	diff_time = jiffies_to_msecs(end - key->start);
              +	if ((key->press_sta == 1) && (diff_time >= 5000)) {
              +		orderly_poweroff(true);
              +		return;
              +	} else {
              +		return;
              +	}
              +}
              +#endif
              +
               static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
               {
               	const struct gpio_keys_button *button = bdata->button;
               	struct input_dev *input = bdata->input;
               	unsigned int type = button->type ?: EV_KEY;
               	int state;
              +#ifdef CONFIG_GPIOKEYS_AS_POWERKEY
              +	struct long_press_key *key = &long_press_key;
              +#endif
               
               	state = gpiod_get_value_cansleep(bdata->gpiod);
               	if (state < 0) {
              @@ -373,7 +414,29 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
               		if (state)
               			input_event(input, type, button->code, button->value);
               	} else {
              +#ifdef CONFIG_GPIOKEYS_AS_POWERKEY
              +		if (button->code != KEY_POWER) {
              +			input_event(input, type, button->code, state);
              +		} else {
              +			if (state) {
              +				key->start = jiffies;
              +				key->press_sta = 1;
              +				queue_delayed_work(system_wq, &key->long_work,
              +					msecs_to_jiffies(5 * 1000));
              +			} else if ((!state) && (key->start != 0)) {
              +				key->press_sta = 0;
              +				cancel_delayed_work(&key->long_work);
              +				input_event(input, EV_KEY, button->code, 1);
              +				input_sync(input);
              +				udelay(5000);
              +				input_event(input, EV_KEY, button->code, 0);
              +				input_sync(input);
              +			}
              +		}
              +#else
               		input_event(input, type, button->code, state);
              +#endif
              +
               	}
               	input_sync(input);
               }
              @@ -459,10 +522,14 @@ static void gpio_keys_quiesce_key(void *data)
               {
               	struct gpio_button_data *bdata = data;
               
              -	if (bdata->gpiod)
              +	if (bdata->gpiod) {
               		cancel_delayed_work_sync(&bdata->work);
              -	else
              +#ifdef CONFIG_GPIOKEYS_AS_POWERKEY
              +		cancel_delayed_work_sync(&long_press_key.long_work);
              +#endif
              +	} else {
               		del_timer_sync(&bdata->release_timer);
              +	}
               }
               
               static int gpio_keys_setup_key(struct platform_device *pdev,
              @@ -502,7 +569,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
               		bdata->gpiod = gpio_to_desc(button->gpio);
               		if (!bdata->gpiod)
               			return -EINVAL;
              -
              +#if 0
               		if (button->debounce_interval) {
               			error = gpiod_set_debounce(bdata->gpiod,
               					button->debounce_interval * 1000);
              @@ -511,6 +578,9 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
               				bdata->software_debounce =
               						button->debounce_interval;
               		}
              +#else
              +		bdata->software_debounce = button->debounce_interval;
              +#endif
               
               		if (button->irq) {
               			bdata->irq = button->irq;
              @@ -526,6 +596,10 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
               			bdata->irq = irq;
               		}
               
              +#ifdef CONFIG_GPIOKEYS_AS_POWERKEY
              +		INIT_DELAYED_WORK(&long_press_key.long_work,
              +				gpio_keys_long_press_func);
              +#endif
               		INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);
               
               		isr = gpio_keys_gpio_isr;
              @@ -664,11 +738,15 @@ gpio_keys_get_devtree_pdata(struct device *dev)
               
               	i = 0;
               	for_each_available_child_of_node(node, pp) {
              +#ifdef CONFIG_ARCH_SUNXI
              +		struct gpio_config flags;
              +#else
               		enum of_gpio_flags flags;
              +#endif
               
               		button = &pdata->buttons[i++];
               
              -		button->gpio = of_get_gpio_flags(pp, 0, &flags);
              +		button->gpio = of_get_gpio_flags(pp, 0, (enum of_gpio_flags *)&flags);
               		if (button->gpio < 0) {
               			error = button->gpio;
               			if (error != -ENOENT) {
              @@ -679,7 +757,11 @@ gpio_keys_get_devtree_pdata(struct device *dev)
               				return ERR_PTR(error);
               			}
               		} else {
              +#ifdef CONFIG_ARCH_SUNXI
              +			button->active_low = flags.data & OF_GPIO_ACTIVE_LOW;
              +#else
               			button->active_low = flags & OF_GPIO_ACTIVE_LOW;
              +#endif
               		}
               
               		button->irq = irq_of_parse_and_map(pp, 0);
              -- 
              2.33.0
              
              tigger D 3 Replies Last reply Reply Quote Share 0
              • tigger
                tigger LV 7 @YuzukiTsuru last edited by

                @yuzukitsuru

                感谢大佬,我合并了一下: gpio_keys.c

                现在没有报错了。

                1 Reply Last reply Reply Quote Share 0
                • tigger
                  tigger LV 7 @YuzukiTsuru last edited by

                  @yuzukitsuru
                  意外发现 R818 TINA SDK 里面的 gpio_keys.c 和你的一模一样。

                  tigger 1 Reply Last reply Reply Quote Share 0
                  • tigger
                    tigger LV 7 @tigger last edited by whycan

                    @tigger

                    Kconfig:

                    config GPIOKEYS_AS_POWERKEY
                            bool "gpio-keys used as power-key"
                            default n
                            depends on KEYBOARD_GPIO
                            help
                              Say Y here to enable the function that can add long-press
                              funciton in gpio-keys and use it as power-key.
                    

                    gpio_keys.c:

                    
                    /*
                     * Driver for keys on GPIO lines capable of generating interrupts.
                     *
                     * Copyright 2005 Phil Blundell
                     * Copyright 2010, 2011 David Jander <david@protonic.nl>
                     *
                     * This program is free software; you can redistribute it and/or modify
                     * it under the terms of the GNU General Public License version 2 as
                     * published by the Free Software Foundation.
                     */
                    
                    #include <linux/module.h>
                    
                    #include <linux/init.h>
                    #include <linux/fs.h>
                    #include <linux/interrupt.h>
                    #include <linux/irq.h>
                    #include <linux/sched.h>
                    #include <linux/pm.h>
                    #include <linux/slab.h>
                    #include <linux/sysctl.h>
                    #include <linux/proc_fs.h>
                    #include <linux/delay.h>
                    #include <linux/platform_device.h>
                    #include <linux/input.h>
                    #include <linux/gpio_keys.h>
                    #include <linux/workqueue.h>
                    #include <linux/gpio.h>
                    #include <linux/gpio/consumer.h>
                    #include <linux/of.h>
                    #include <linux/of_platform.h>
                    #include <linux/of_gpio.h>
                    #include <linux/of_irq.h>
                    #include <linux/spinlock.h>
                    
                    #ifdef CONFIG_ARCH_SUNXI
                    #include <linux/sunxi-gpio.h>
                    #ifdef CONFIG_GPIOKEYS_AS_POWERKEY
                    #include <linux/kthread.h>
                    #include <linux/reboot.h>
                    #include <linux/jiffies.h>
                    struct long_press_key {
                            struct delayed_work long_work;
                            unsigned long start;
                            int press_sta;
                    };
                    
                    static struct long_press_key long_press_key;
                    #endif
                    #endif
                    
                    struct gpio_button_data {
                            const struct gpio_keys_button *button;
                            struct input_dev *input;
                            struct gpio_desc *gpiod;
                    
                            struct timer_list release_timer;
                            unsigned int release_delay;     /* in msecs, for IRQ-only buttons */
                    
                            struct delayed_work work;
                            unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */
                    
                            unsigned int irq;
                            spinlock_t lock;
                            bool disabled;
                            bool key_pressed;
                    };
                    
                    struct gpio_keys_drvdata {
                            const struct gpio_keys_platform_data *pdata;
                            struct input_dev *input;
                            struct mutex disable_lock;
                            struct gpio_button_data data[0];
                    };
                    
                    /*
                     * SYSFS interface for enabling/disabling keys and switches:
                     *
                     * There are 4 attributes under /sys/devices/platform/gpio-keys/
                     *      keys [ro]              - bitmap of keys (EV_KEY) which can be
                     *                               disabled
                     *      switches [ro]          - bitmap of switches (EV_SW) which can be
                     *                               disabled
                     *      disabled_keys [rw]     - bitmap of keys currently disabled
                     *      disabled_switches [rw] - bitmap of switches currently disabled
                     *
                     * Userland can change these values and hence disable event generation
                     * for each key (or switch). Disabling a key means its interrupt line
                     * is disabled.
                     *
                     * For example, if we have following switches set up as gpio-keys:
                     *      SW_DOCK = 5
                     *      SW_CAMERA_LENS_COVER = 9
                     *      SW_KEYPAD_SLIDE = 10
                     *      SW_FRONT_PROXIMITY = 11
                     * This is read from switches:
                     *      11-9,5
                     * Next we want to disable proximity (11) and dock (5), we write:
                     *      11,5
                     * to file disabled_switches. Now proximity and dock IRQs are disabled.
                     * This can be verified by reading the file disabled_switches:
                     *      11,5
                     * If we now want to enable proximity (11) switch we write:
                     *      5
                     * to disabled_switches.
                     *
                     * We can disable only those keys which don't allow sharing the irq.
                     */
                    
                    /**
                     * get_n_events_by_type() - returns maximum number of events per @type
                     * @type: type of button (%EV_KEY, %EV_SW)
                     *
                     * Return value of this function can be used to allocate bitmap
                     * large enough to hold all bits for given type.
                     */
                    static int get_n_events_by_type(int type)
                    {
                            BUG_ON(type != EV_SW && type != EV_KEY);
                    
                            return (type == EV_KEY) ? KEY_CNT : SW_CNT;
                    }
                    
                    /**
                     * get_bm_events_by_type() - returns bitmap of supported events per @type
                     * @input: input device from which bitmap is retrieved
                     * @type: type of button (%EV_KEY, %EV_SW)
                     *
                     * Return value of this function can be used to allocate bitmap
                     * large enough to hold all bits for given type.
                     */
                    static const unsigned long *get_bm_events_by_type(struct input_dev *dev,
                                                                      int type)
                    {
                            BUG_ON(type != EV_SW && type != EV_KEY);
                    
                            return (type == EV_KEY) ? dev->keybit : dev->swbit;
                    }
                    
                    /**
                     * gpio_keys_disable_button() - disables given GPIO button
                     * @bdata: button data for button to be disabled
                     *
                     * Disables button pointed by @bdata. This is done by masking
                     * IRQ line. After this function is called, button won't generate
                     * input events anymore. Note that one can only disable buttons
                     * that don't share IRQs.
                     *
                     * Make sure that @bdata->disable_lock is locked when entering
                     * this function to avoid races when concurrent threads are
                     * disabling buttons at the same time.
                     */
                    static void gpio_keys_disable_button(struct gpio_button_data *bdata)
                    {
                            if (!bdata->disabled) {
                                    /*
                                     * Disable IRQ and associated timer/work structure.
                                     */
                                    disable_irq(bdata->irq);
                    
                                    if (bdata->gpiod) {
                                            cancel_delayed_work_sync(&bdata->work);
                    #ifdef CONFIG_GPIOKEYS_AS_POWERKEY
                                            cancel_delayed_work_sync(&long_press_key.long_work);
                    #endif
                                    } else {
                                            del_timer_sync(&bdata->release_timer);
                                    }
                    
                                    bdata->disabled = true;
                            }
                    }
                    
                    /**
                     * gpio_keys_enable_button() - enables given GPIO button
                     * @bdata: button data for button to be disabled
                     *
                     * Enables given button pointed by @bdata.
                     *
                     * Make sure that @bdata->disable_lock is locked when entering
                     * this function to avoid races with concurrent threads trying
                     * to enable the same button at the same time.
                     */
                    static void gpio_keys_enable_button(struct gpio_button_data *bdata)
                    {
                            if (bdata->disabled) {
                                    enable_irq(bdata->irq);
                                    bdata->disabled = false;
                            }
                    }
                    
                    /**
                     * gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons
                     * @ddata: pointer to drvdata
                     * @buf: buffer where stringified bitmap is written
                     * @type: button type (%EV_KEY, %EV_SW)
                     * @only_disabled: does caller want only those buttons that are
                     *                 currently disabled or all buttons that can be
                     *                 disabled
                     *
                     * This function writes buttons that can be disabled to @buf. If
                     * @only_disabled is true, then @buf contains only those buttons
                     * that are currently disabled. Returns 0 on success or negative
                     * errno on failure.
                     */
                    static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
                                                              char *buf, unsigned int type,
                                                              bool only_disabled)
                    {
                            int n_events = get_n_events_by_type(type);
                            unsigned long *bits;
                            ssize_t ret;
                            int i;
                    
                            bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
                            if (!bits)
                                    return -ENOMEM;
                    
                            for (i = 0; i < ddata->pdata->nbuttons; i++) {
                                    struct gpio_button_data *bdata = &ddata->data[i];
                    
                                    if (bdata->button->type != type)
                                            continue;
                    
                                    if (only_disabled && !bdata->disabled)
                                            continue;
                    
                                    __set_bit(bdata->button->code, bits);
                            }
                    
                            ret = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", n_events, bits);
                            buf[ret++] = '\n';
                            buf[ret] = '\0';
                    
                            kfree(bits);
                    
                            return ret;
                    }
                    
                    /**
                     * gpio_keys_attr_store_helper() - enable/disable buttons based on given bitmap
                     * @ddata: pointer to drvdata
                     * @buf: buffer from userspace that contains stringified bitmap
                     * @type: button type (%EV_KEY, %EV_SW)
                     *
                     * This function parses stringified bitmap from @buf and disables/enables
                     * GPIO buttons accordingly. Returns 0 on success and negative error
                     * on failure.
                     */
                    static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
                                                               const char *buf, unsigned int type)
                    {
                            int n_events = get_n_events_by_type(type);
                            const unsigned long *bitmap = get_bm_events_by_type(ddata->input, type);
                            unsigned long *bits;
                            ssize_t error;
                            int i;
                    
                            bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
                            if (!bits)
                                    return -ENOMEM;
                    
                            error = bitmap_parselist(buf, bits, n_events);
                            if (error)
                                    goto out;
                    
                            /* First validate */
                            if (!bitmap_subset(bits, bitmap, n_events)) {
                                    error = -EINVAL;
                                    goto out;
                            }
                    
                            for (i = 0; i < ddata->pdata->nbuttons; i++) {
                                    struct gpio_button_data *bdata = &ddata->data[i];
                    
                                    if (bdata->button->type != type)
                                            continue;
                    
                                    if (test_bit(bdata->button->code, bits) &&
                                        !bdata->button->can_disable) {
                                            error = -EINVAL;
                                            goto out;
                                    }
                            }
                    
                            mutex_lock(&ddata->disable_lock);
                    
                            for (i = 0; i < ddata->pdata->nbuttons; i++) {
                                    struct gpio_button_data *bdata = &ddata->data[i];
                    
                                    if (bdata->button->type != type)
                                            continue;
                    
                                    if (test_bit(bdata->button->code, bits))
                                            gpio_keys_disable_button(bdata);
                                    else
                                            gpio_keys_enable_button(bdata);
                            }
                    
                            mutex_unlock(&ddata->disable_lock);
                    
                    out:
                            kfree(bits);
                            return error;
                    }
                    
                    #define ATTR_SHOW_FN(name, type, only_disabled)                         \
                    static ssize_t gpio_keys_show_##name(struct device *dev,                \
                                                         struct device_attribute *attr,     \
                                                         char *buf)                         \
                    {                                                                       \
                            struct platform_device *pdev = to_platform_device(dev);         \
                            struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);   \
                                                                                            \
                            return gpio_keys_attr_show_helper(ddata, buf,                   \
                                                              type, only_disabled);         \
                    }
                    
                    ATTR_SHOW_FN(keys, EV_KEY, false);
                    ATTR_SHOW_FN(switches, EV_SW, false);
                    ATTR_SHOW_FN(disabled_keys, EV_KEY, true);
                    ATTR_SHOW_FN(disabled_switches, EV_SW, true);
                    
                    /*
                     * ATTRIBUTES:
                     *
                     * /sys/devices/platform/gpio-keys/keys [ro]
                     * /sys/devices/platform/gpio-keys/switches [ro]
                     */
                    static DEVICE_ATTR(keys, S_IRUGO, gpio_keys_show_keys, NULL);
                    static DEVICE_ATTR(switches, S_IRUGO, gpio_keys_show_switches, NULL);
                    
                    #define ATTR_STORE_FN(name, type)                                       \
                    static ssize_t gpio_keys_store_##name(struct device *dev,               \
                                                          struct device_attribute *attr,    \
                                                          const char *buf,                  \
                                                          size_t count)                     \
                    {                                                                       \
                            struct platform_device *pdev = to_platform_device(dev);         \
                            struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);   \
                            ssize_t error;                                                  \
                                                                                            \
                            error = gpio_keys_attr_store_helper(ddata, buf, type);          \
                            if (error)                                                      \
                                    return error;                                           \
                                                                                            \
                            return count;                                                   \
                    }
                    
                    ATTR_STORE_FN(disabled_keys, EV_KEY);
                    ATTR_STORE_FN(disabled_switches, EV_SW);
                    
                    /*
                     * ATTRIBUTES:
                     *
                     * /sys/devices/platform/gpio-keys/disabled_keys [rw]
                     * /sys/devices/platform/gpio-keys/disables_switches [rw]
                     */
                    static DEVICE_ATTR(disabled_keys, S_IWUSR | S_IRUGO,
                                       gpio_keys_show_disabled_keys,
                                       gpio_keys_store_disabled_keys);
                    static DEVICE_ATTR(disabled_switches, S_IWUSR | S_IRUGO,
                                       gpio_keys_show_disabled_switches,
                                       gpio_keys_store_disabled_switches);
                    
                    static struct attribute *gpio_keys_attrs[] = {
                            &dev_attr_keys.attr,
                            &dev_attr_switches.attr,
                            &dev_attr_disabled_keys.attr,
                            &dev_attr_disabled_switches.attr,
                            NULL,
                    };
                    
                    static struct attribute_group gpio_keys_attr_group = {
                            .attrs = gpio_keys_attrs,
                    };
                    
                    #ifdef CONFIG_GPIOKEYS_AS_POWERKEY
                    static void gpio_keys_long_press_func(struct work_struct *work)
                    {
                            struct long_press_key *key = &long_press_key;
                            unsigned long end;
                            unsigned long diff_time;
                    
                            end = jiffies;
                            diff_time = jiffies_to_msecs(end - key->start);
                            if ((key->press_sta == 1) && (diff_time >= 5000)) {
                                    orderly_poweroff(true);
                                    return;
                            } else {
                                    return;
                            }
                    }
                    #endif
                    
                    static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
                    {
                            const struct gpio_keys_button *button = bdata->button;
                            struct input_dev *input = bdata->input;
                            unsigned int type = button->type ?: EV_KEY;
                            int state;
                    #ifdef CONFIG_GPIOKEYS_AS_POWERKEY
                            struct long_press_key *key = &long_press_key;
                    #endif
                    
                            state = gpiod_get_value_cansleep(bdata->gpiod);
                            if (state < 0) {
                                    dev_err(input->dev.parent,
                                            "failed to get gpio state: %d\n", state);
                                    return;
                            }
                    
                            if (type == EV_ABS) {
                                    if (state)
                                            input_event(input, type, button->code, button->value);
                            } else {
                    #ifdef CONFIG_GPIOKEYS_AS_POWERKEY
                                    if (button->code != KEY_POWER) {
                                            input_event(input, type, button->code, state);
                                    } else {
                                            if (state) {
                                                    key->start = jiffies;
                                                    key->press_sta = 1;
                                                    queue_delayed_work(system_wq, &key->long_work,
                                                            msecs_to_jiffies(5 * 1000));
                                            } else if ((!state) && (key->start != 0)) {
                                                    key->press_sta = 0;
                                                    cancel_delayed_work(&key->long_work);
                                                    input_event(input, EV_KEY, button->code, 1);
                                                    input_sync(input);
                                                    udelay(5000);
                                                    input_event(input, EV_KEY, button->code, 0);
                                                    input_sync(input);
                                            }
                                    }
                    #else
                                    input_event(input, type, button->code, state);
                    #endif
                    
                            }
                            input_sync(input);
                    }
                    
                    static void gpio_keys_gpio_work_func(struct work_struct *work)
                    {
                            struct gpio_button_data *bdata =
                                    container_of(work, struct gpio_button_data, work.work);
                    
                            gpio_keys_gpio_report_event(bdata);
                    
                            if (bdata->button->wakeup)
                                    pm_relax(bdata->input->dev.parent);
                    }
                    
                    static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
                    {
                            struct gpio_button_data *bdata = dev_id;
                    
                            BUG_ON(irq != bdata->irq);
                    
                            if (bdata->button->wakeup)
                                    pm_stay_awake(bdata->input->dev.parent);
                    
                            mod_delayed_work(system_wq,
                                             &bdata->work,
                                             msecs_to_jiffies(bdata->software_debounce));
                    
                            return IRQ_HANDLED;
                    }
                    
                    static void gpio_keys_irq_timer(unsigned long _data)
                    {
                            struct gpio_button_data *bdata = (struct gpio_button_data *)_data;
                            struct input_dev *input = bdata->input;
                            unsigned long flags;
                    
                            spin_lock_irqsave(&bdata->lock, flags);
                            if (bdata->key_pressed) {
                                    input_event(input, EV_KEY, bdata->button->code, 0);
                                    input_sync(input);
                                    bdata->key_pressed = false;
                            }
                            spin_unlock_irqrestore(&bdata->lock, flags);
                    }
                    
                    static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
                    {
                            struct gpio_button_data *bdata = dev_id;
                            const struct gpio_keys_button *button = bdata->button;
                            struct input_dev *input = bdata->input;
                            unsigned long flags;
                    
                            BUG_ON(irq != bdata->irq);
                    
                            spin_lock_irqsave(&bdata->lock, flags);
                    
                            if (!bdata->key_pressed) {
                                    if (bdata->button->wakeup)
                                            pm_wakeup_event(bdata->input->dev.parent, 0);
                    
                                    input_event(input, EV_KEY, button->code, 1);
                                    input_sync(input);
                    
                                    if (!bdata->release_delay) {
                                            input_event(input, EV_KEY, button->code, 0);
                                            input_sync(input);
                                            goto out;
                                    }
                    
                                    bdata->key_pressed = true;
                            }
                    
                            if (bdata->release_delay)
                                    mod_timer(&bdata->release_timer,
                                            jiffies + msecs_to_jiffies(bdata->release_delay));
                    out:
                            spin_unlock_irqrestore(&bdata->lock, flags);
                            return IRQ_HANDLED;
                    }
                    
                    static void gpio_keys_quiesce_key(void *data)
                    {
                            struct gpio_button_data *bdata = data;
                    
                            if (bdata->gpiod) {
                                    cancel_delayed_work_sync(&bdata->work);
                    #ifdef CONFIG_GPIOKEYS_AS_POWERKEY
                                    cancel_delayed_work_sync(&long_press_key.long_work);
                    #endif
                            } else {
                                    del_timer_sync(&bdata->release_timer);
                            }
                    }
                    
                    static int gpio_keys_setup_key(struct platform_device *pdev,
                                                    struct input_dev *input,
                                                    struct gpio_button_data *bdata,
                                                    const struct gpio_keys_button *button)
                    {
                            const char *desc = button->desc ? button->desc : "gpio_keys";
                            struct device *dev = &pdev->dev;
                            irq_handler_t isr;
                            unsigned long irqflags;
                            int irq;
                            int error;
                    
                            bdata->input = input;
                            bdata->button = button;
                            spin_lock_init(&bdata->lock);
                    
                            /*
                             * Legacy GPIO number, so request the GPIO here and
                             * convert it to descriptor.
                             */
                            if (gpio_is_valid(button->gpio)) {
                                    unsigned flags = GPIOF_IN;
                    
                                    if (button->active_low)
                                            flags |= GPIOF_ACTIVE_LOW;
                    
                                    error = devm_gpio_request_one(&pdev->dev, button->gpio, flags,
                                                                  desc);
                                    if (error < 0) {
                                            dev_err(dev, "Failed to request GPIO %d, error %d\n",
                                                    button->gpio, error);
                                            return error;
                                    }
                    
                                    bdata->gpiod = gpio_to_desc(button->gpio);
                                    if (!bdata->gpiod)
                                            return -EINVAL;
                    #if 0
                                    if (button->debounce_interval) {
                                            error = gpiod_set_debounce(bdata->gpiod,
                                                            button->debounce_interval * 1000);
                                            /* use timer if gpiolib doesn't provide debounce */
                                            if (error < 0)
                                                    bdata->software_debounce =
                                                                    button->debounce_interval;
                                    }
                    #else
                                    bdata->software_debounce = button->debounce_interval;
                    #endif
                    
                                    if (button->irq) {
                                            bdata->irq = button->irq;
                                    } else {
                                            irq = gpiod_to_irq(bdata->gpiod);
                                            if (irq < 0) {
                                                    error = irq;
                                                    dev_err(dev,
                                                            "Unable to get irq number for GPIO %d, error %d\n",
                                                            button->gpio, error);
                                                    return error;
                                            }
                                            bdata->irq = irq;
                                    }
                    
                    #ifdef CONFIG_GPIOKEYS_AS_POWERKEY
                                    INIT_DELAYED_WORK(&long_press_key.long_work,
                                                    gpio_keys_long_press_func);
                    #endif
                                    INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);
                    
                                    isr = gpio_keys_gpio_isr;
                                    irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
                    
                            } else {
                                    if (!button->irq) {
                                            dev_err(dev, "No IRQ specified\n");
                                            return -EINVAL;
                                    }
                                    bdata->irq = button->irq;
                    
                                    if (button->type && button->type != EV_KEY) {
                                            dev_err(dev, "Only EV_KEY allowed for IRQ buttons.\n");
                                            return -EINVAL;
                                    }
                    
                                    bdata->release_delay = button->debounce_interval;
                                    setup_timer(&bdata->release_timer,
                                                gpio_keys_irq_timer, (unsigned long)bdata);
                    
                                    isr = gpio_keys_irq_isr;
                                    irqflags = 0;
                            }
                    
                            input_set_capability(input, button->type ?: EV_KEY, button->code);
                    
                            /*
                             * Install custom action to cancel release timer and
                             * workqueue item.
                             */
                            error = devm_add_action(&pdev->dev, gpio_keys_quiesce_key, bdata);
                            if (error) {
                                    dev_err(&pdev->dev,
                                            "failed to register quiesce action, error: %d\n",
                                            error);
                                    return error;
                            }
                    
                            /*
                             * If platform has specified that the button can be disabled,
                             * we don't want it to share the interrupt line.
                             */
                            if (!button->can_disable)
                                    irqflags |= IRQF_SHARED;
                    
                            error = devm_request_any_context_irq(&pdev->dev, bdata->irq,
                                                                 isr, irqflags, desc, bdata);
                            if (error < 0) {
                                    dev_err(dev, "Unable to claim irq %d; error %d\n",
                                            bdata->irq, error);
                                    return error;
                            }
                    
                            return 0;
                    }
                    
                    static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
                    {
                            struct input_dev *input = ddata->input;
                            int i;
                    
                            for (i = 0; i < ddata->pdata->nbuttons; i++) {
                                    struct gpio_button_data *bdata = &ddata->data[i];
                                    if (bdata->gpiod)
                                            gpio_keys_gpio_report_event(bdata);
                            }
                            input_sync(input);
                    }
                    
                    static int gpio_keys_open(struct input_dev *input)
                    {
                            struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
                            const struct gpio_keys_platform_data *pdata = ddata->pdata;
                            int error;
                    
                            if (pdata->enable) {
                                    error = pdata->enable(input->dev.parent);
                                    if (error)
                                            return error;
                            }
                    
                            /* Report current state of buttons that are connected to GPIOs */
                            gpio_keys_report_state(ddata);
                    
                            return 0;
                    }
                    
                    static void gpio_keys_close(struct input_dev *input)
                    {
                            struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
                            const struct gpio_keys_platform_data *pdata = ddata->pdata;
                    
                            if (pdata->disable)
                                    pdata->disable(input->dev.parent);
                    }
                    
                    /*
                     * Handlers for alternative sources of platform_data
                     */
                    
                    #ifdef CONFIG_OF
                    /*
                     * Translate OpenFirmware node properties into platform_data
                     */
                    static struct gpio_keys_platform_data *
                    gpio_keys_get_devtree_pdata(struct device *dev)
                    {
                            struct device_node *node, *pp;
                            struct gpio_keys_platform_data *pdata;
                            struct gpio_keys_button *button;
                            int error;
                            int nbuttons;
                            int i;
                    
                            node = dev->of_node;
                            if (!node)
                                    return ERR_PTR(-ENODEV);
                    
                            nbuttons = of_get_available_child_count(node);
                            if (nbuttons == 0)
                                    return ERR_PTR(-ENODEV);
                    
                            pdata = devm_kzalloc(dev,
                                                 sizeof(*pdata) + nbuttons * sizeof(*button),
                                                 GFP_KERNEL);
                            if (!pdata)
                                    return ERR_PTR(-ENOMEM);
                    
                            pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
                            pdata->nbuttons = nbuttons;
                    
                            pdata->rep = !!of_get_property(node, "autorepeat", NULL);
                    
                            of_property_read_string(node, "label", &pdata->name);
                    
                            i = 0;
                            for_each_available_child_of_node(node, pp) {
                    #ifdef CONFIG_ARCH_SUNXI
                                    struct gpio_config flags;
                    #else
                                    enum of_gpio_flags flags;
                    #endif
                    
                                    button = &pdata->buttons[i++];
                    
                                    button->gpio = of_get_gpio_flags(pp, 0, (enum of_gpio_flags *)&flags);
                                    if (button->gpio < 0) {
                                            error = button->gpio;
                                            if (error != -ENOENT) {
                                                    if (error != -EPROBE_DEFER)
                                                            dev_err(dev,
                                                                    "Failed to get gpio flags, error: %d\n",
                                                                    error);
                                                    return ERR_PTR(error);
                                            }
                                    } else {
                    #ifdef CONFIG_ARCH_SUNXI
                                            button->active_low = flags.data & OF_GPIO_ACTIVE_LOW;
                    #else
                                            button->active_low = flags & OF_GPIO_ACTIVE_LOW;
                    #endif
                                    }
                    
                                    button->irq = irq_of_parse_and_map(pp, 0);
                    
                                    if (!gpio_is_valid(button->gpio) && !button->irq) {
                                            dev_err(dev, "Found button without gpios or irqs\n");
                                            return ERR_PTR(-EINVAL);
                                    }
                    
                                    if (of_property_read_u32(pp, "linux,code", &button->code)) {
                                            dev_err(dev, "Button without keycode: 0x%x\n",
                                                    button->gpio);
                                            return ERR_PTR(-EINVAL);
                                    }
                    
                                    button->desc = of_get_property(pp, "label", NULL);
                    
                                    if (of_property_read_u32(pp, "linux,input-type", &button->type))
                                            button->type = EV_KEY;
                    
                                    button->wakeup = of_property_read_bool(pp, "wakeup-source") ||
                                                     /* legacy name */
                                                     of_property_read_bool(pp, "gpio-key,wakeup");
                    
                                    button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL);
                    
                                    if (of_property_read_u32(pp, "debounce-interval",
                                                             &button->debounce_interval))
                                            button->debounce_interval = 5;
                            }
                    
                            if (pdata->nbuttons == 0)
                                    return ERR_PTR(-EINVAL);
                    
                            return pdata;
                    }
                    
                    static const struct of_device_id gpio_keys_of_match[] = {
                            { .compatible = "gpio-keys", },
                            { },
                    };
                    MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
                    
                    #else
                    
                    static inline struct gpio_keys_platform_data *
                    gpio_keys_get_devtree_pdata(struct device *dev)
                    {
                            return ERR_PTR(-ENODEV);
                    }
                    
                    #endif
                    
                    static int gpio_keys_probe(struct platform_device *pdev)
                    {
                            struct device *dev = &pdev->dev;
                            const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
                            struct gpio_keys_drvdata *ddata;
                            struct input_dev *input;
                            size_t size;
                            int i, error;
                            int wakeup = 0;
                    
                            if (!pdata) {
                                    pdata = gpio_keys_get_devtree_pdata(dev);
                                    if (IS_ERR(pdata))
                                            return PTR_ERR(pdata);
                            }
                    
                            size = sizeof(struct gpio_keys_drvdata) +
                                            pdata->nbuttons * sizeof(struct gpio_button_data);
                            ddata = devm_kzalloc(dev, size, GFP_KERNEL);
                            if (!ddata) {
                                    dev_err(dev, "failed to allocate state\n");
                                    return -ENOMEM;
                            }
                    
                            input = devm_input_allocate_device(dev);
                            if (!input) {
                                    dev_err(dev, "failed to allocate input device\n");
                                    return -ENOMEM;
                            }
                    
                            ddata->pdata = pdata;
                            ddata->input = input;
                            mutex_init(&ddata->disable_lock);
                    
                            platform_set_drvdata(pdev, ddata);
                            input_set_drvdata(input, ddata);
                    
                            input->name = pdata->name ? : pdev->name;
                            input->phys = "gpio-keys/input0";
                            input->dev.parent = &pdev->dev;
                            input->open = gpio_keys_open;
                            input->close = gpio_keys_close;
                    
                            input->id.bustype = BUS_HOST;
                            input->id.vendor = 0x0001;
                            input->id.product = 0x0001;
                            input->id.version = 0x0100;
                    
                            /* Enable auto repeat feature of Linux input subsystem */
                            if (pdata->rep)
                                    __set_bit(EV_REP, input->evbit);
                    
                            for (i = 0; i < pdata->nbuttons; i++) {
                                    const struct gpio_keys_button *button = &pdata->buttons[i];
                                    struct gpio_button_data *bdata = &ddata->data[i];
                    
                                    error = gpio_keys_setup_key(pdev, input, bdata, button);
                                    if (error)
                                            return error;
                    
                                    if (button->wakeup)
                                            wakeup = 1;
                            }
                    
                            error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
                            if (error) {
                                    dev_err(dev, "Unable to export keys/switches, error: %d\n",
                                            error);
                                    return error;
                            }
                    
                            error = input_register_device(input);
                            if (error) {
                                    dev_err(dev, "Unable to register input device, error: %d\n",
                                            error);
                                    goto err_remove_group;
                            }
                    
                            device_init_wakeup(&pdev->dev, wakeup);
                    
                            return 0;
                    
                    err_remove_group:
                            sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
                            return error;
                    }
                    
                    static int gpio_keys_remove(struct platform_device *pdev)
                    {
                            sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
                    
                            device_init_wakeup(&pdev->dev, 0);
                    
                            return 0;
                    }
                    
                    #ifdef CONFIG_PM_SLEEP
                    static int gpio_keys_suspend(struct device *dev)
                    {
                            struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
                            struct input_dev *input = ddata->input;
                            int i;
                    
                            if (device_may_wakeup(dev)) {
                                    for (i = 0; i < ddata->pdata->nbuttons; i++) {
                                            struct gpio_button_data *bdata = &ddata->data[i];
                                            if (bdata->button->wakeup)
                                                    enable_irq_wake(bdata->irq);
                                    }
                            } else {
                                    mutex_lock(&input->mutex);
                                    if (input->users)
                                            gpio_keys_close(input);
                                    mutex_unlock(&input->mutex);
                            }
                    
                            return 0;
                    }
                    
                    static int gpio_keys_resume(struct device *dev)
                    {
                            struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
                            struct input_dev *input = ddata->input;
                            int error = 0;
                            int i;
                    
                            if (device_may_wakeup(dev)) {
                                    for (i = 0; i < ddata->pdata->nbuttons; i++) {
                                            struct gpio_button_data *bdata = &ddata->data[i];
                                            if (bdata->button->wakeup)
                                                    disable_irq_wake(bdata->irq);
                                    }
                            } else {
                                    mutex_lock(&input->mutex);
                                    if (input->users)
                                            error = gpio_keys_open(input);
                                    mutex_unlock(&input->mutex);
                            }
                    
                            if (error)
                                    return error;
                    
                            gpio_keys_report_state(ddata);
                            return 0;
                    }
                    #endif
                    
                    static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
                    
                    static struct platform_driver gpio_keys_device_driver = {
                            .probe          = gpio_keys_probe,
                            .remove         = gpio_keys_remove,
                            .driver         = {
                                    .name   = "gpio-keys",
                                    .pm     = &gpio_keys_pm_ops,
                                    .of_match_table = of_match_ptr(gpio_keys_of_match),
                            }
                    };
                    
                    static int __init gpio_keys_init(void)
                    {
                            return platform_driver_register(&gpio_keys_device_driver);
                    }
                    
                    static void __exit gpio_keys_exit(void)
                    {
                            platform_driver_unregister(&gpio_keys_device_driver);
                    }
                    
                    late_initcall(gpio_keys_init);
                    module_exit(gpio_keys_exit);
                    
                    MODULE_LICENSE("GPL");
                    MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
                    MODULE_DESCRIPTION("Keyboard driver for GPIOs");
                    MODULE_ALIAS("platform:gpio-keys");
                    

                    看了一下驱动,按键长按是 电源键。

                    1 Reply Last reply Reply Quote Share 0
                    • W
                      waterworld LV 5 last edited by

                      我现在也遇到了这个情况,gpio-key模块可以正常加载,但是CONFIG_INPUT_GPIO_ROTARY_ENCODER=m,加载的时候报错,然后evtest还是正常使用,这个要怎样修改啊?

                      1 Reply Last reply Reply Quote Share 0
                      • D
                        dream LV 6 @tigger last edited by

                        @tigger 我最近也有遇到相同的问题,不过当时没看到有这个贴。走了点弯路,不过搞清楚原因了。

                        https://bbs.aw-ol.com/topic/2099/全志平台-gpio-keys-驱动应用和-stack-crash-解决?_=1663384404172

                        1 Reply Last reply Reply Quote Share 0
                        • D
                          dream LV 6 @YuzukiTsuru last edited by

                          @yuzukitsuru 看来以后得多逛逛论坛了,前段时间我也遇到这个问题,走了弯路,没想到论坛早有补丁发出来了。哈哈。

                          1 Reply Last reply Reply Quote Share 0
                          • 1 / 1
                          • First post
                            Last post

                          Copyright © 2022 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号

                          行为准则 | 用户协议 | 隐私权政策