在内核模块 IOCTL 中使用 GPIO

Working with GPIOs in kernel module IOCTLs

我在内核模块中使用 GPIO,当我从 IOCTL 设置或重置 GPIOS 时,我在 "dmesg" 日志中收到以下警告。

[11115.549204] WARNING: CPU: 1 PID: 5199 at drivers/gpio/gpiolib.c:2415 gpiod_get_raw_value+0x7c/0xb8
[11115.558267] Modules linked in: ariodrv(O) [last unloaded: ariodrv]
[11115.564570] CPU: 1 PID: 5199 Comm: ARIO_RMG Tainted: G        W  O    4.9.166.RMG.-00002-gcbd9807b6c03-dirty #13
[11115.574776] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
[11115.581320] Backtrace: 
[11115.583816] [<8010b150>] (dump_backtrace) from [<8010b3fc>] (show_stack+0x18/0x1c)
[11115.591426]  r7:00000009 r6:600b0013 r5:80c1ae70 r4:00000000
[11115.597119] [<8010b3e4>] (show_stack) from [<803f51d4>] (dump_stack+0x9c/0xb0)
[11115.604380] [<803f5138>] (dump_stack) from [<80124878>] (__warn+0xec/0x104)
[11115.611367]  r7:00000009 r6:80a39e28 r5:00000000 r4:00000000
[11115.617050] [<8012478c>] (__warn) from [<80124948>] (warn_slowpath_null+0x28/0x30)
[11115.624653]  r9:8d696000 r8:7ea8cfa0 r7:0000000e r6:8d26e600 r5:8c1f9c54 r4:8c207f10
[11115.632434] [<80124920>] (warn_slowpath_null) from [<8042fbb8>] (gpiod_get_raw_value+0x7c/0xb8)
[11115.641177] [<8042fb3c>] (gpiod_get_raw_value) from [<7f00cd78>] (device_ioctl+0x334/0x9f8 [ariodrv])
[11115.650428]  r5:8004d282 r4:7ea8cfa0
[11115.654034] [<7f00ca44>] (device_ioctl [ariodrv]) from [<80219c58>] (do_vfs_ioctl+0xa8/0x914)
[11115.662595]  r7:0000000e r6:8d26e600 r5:8ccc5bc0 r4:7ea8cfa0
[11115.668278] [<80219bb0>] (do_vfs_ioctl) from [<8021a500>] (SyS_ioctl+0x3c/0x64)
[11115.675618]  r10:00000036 r9:8d696000 r8:7ea8cfa0 r7:8004d282 r6:8d26e600 r5:0000000e
[11115.683477]  r4:8d26e601
[11115.686035] [<8021a4c4>] (SyS_ioctl) from [<80107960>] (ret_fast_syscall+0x0/0x48)
[11115.693645]  r9:8d696000 r8:80107b44 r7:00000036 r6:00000000 r5:768c611c r4:7ea8cf98
[11115.701504] ---[ end trace 7be84f1e05fd36af ]---

但是如果我在另一个函数中为 GPIO 引脚设置或获取值,例如我的模块的初始化函数,我不会收到这些警告...

所以问题是我应该如何在 IOCTL 调用中使用 GPIO 引脚?

这是我的 GPIO 设置 IOCTL 代码的一部分:

IOCTL_FUNC(...) {

....

case IOCTL_RMG_GPIO_SET:
            {
                ....
                //I have initialized the GPIO pin as output before, and assume my gpio pin number is 4.
                //int gpioNumber = 4;
                //int value = 1;
                gpio_set_value(gpioNumber, value);

                break;
            }
 ....
}

获取或设置值都没有关系。如果我在 IOCTL 调用中使用这些 GPIO,我会收到警告。但是在 init_module()module_release() 等其他内部函数中,我可以在没有警告的情况下设置和获取这些值。

编辑 1:

我的问题出在我的 IO 扩展器(MCP23xxx 系列)上的 GPIO 上,这个 IO 扩展器在 i2c 总线上工作。 使用处理器 (iMX6DL) 上的 GPIO 时,我没有遇到任何问题或任何警告。

编辑 2:

@Tsyvarev 和@0andriy 谢谢你们,从 this link 我发现 gpiod_get_raw_value_cansleep() 函数不是我需要的,因为这个函数需要一个 GPIO 描述符才能工作,我的内核错误是那。但是函数gpio_get_value_cansleep()gpio_set_value_cansleep()函数是适合i2c IO扩展器的函数。

非常感谢你帮助我,现在的工作代码是:

IOCTL_FUNC(...) {

....

case IOCTL_RMG_GPIO_SET:
            {
                ....
                //I have initialized the GPIO pin as output before, and assume my gpio pin number is 4.
                //int gpioNumber = 4;
                //int value = 1;
                gpio_set_value_cansleep(gpioNumber, value);

                break;
            }
case IOCTL_RMG_GPIO_GET:
            {
                ....
                //I have initialized the GPIO pin as output before, and assume my gpio pin number is 4.
                //int gpioNumber = 4;
                value = gpio_get_value_cansleep(gpioNumber);

                break;
            }
 ....
}

如果您在警告处阅读 linux 来源,它会告诉您:

* This function should be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
WARN_ON(desc->gdev->chip->can_sleep);

你应该打电话给 gpio_get_value_cansleep