【问题标题】:Working with GPIOs in kernel module IOCTLs在内核模块 IOCTL 中使用 GPIO
【发布时间】:2020-05-17 07:50:44
【问题描述】:

我在内核模块中使用 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 引脚设置或获取值,例如我的模块的 init 函数,我不会收到这些警告...

所以问题是我应该如何在 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:

我遇到的问题是我的 IOexpander(MCP23xxx 系列)上的 GPIO,这个 IOexpander 在 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;
            }
 ....
}

【问题讨论】:

  • 您是否检查过警告所指的drivers/gpio/gpiolib.c:2415 行?例如。 this warning 在其上方的行中有一个描述性很强的注释。
  • 如果您恰好触发了这个警告,那么它的注释“应该使用 gpiod_get_raw_value_cansleep()”建议使用 gpiod_get_raw_value_cansleep 而不是 gpiod_get_raw_value。你试过吗?请注意,您可以找到触发了哪个确切警告,因为警告消息是指您机器上的内核源代码。
  • 您的代码中可能还有其他一些问题。只知道问题帖子中提供的信息是不可能帮助它的。
  • 你读过你使用的函数的描述吗? gpiod_get_raw_value 适用于无法休眠的 GPIO,gpiod_get_raw_value_cansleep 适用于可休眠的 GPIO。因此,不同类型的 GPIO 可能需要不同的功能来使用它们(以及不同的场景)。
  • I2C 总线通信可以休眠,你不能在原子上下文中调用这些 GPIO 函数。

标签: linux linux-kernel kernel-module gpio


【解决方案1】:

如果您阅读警告中的 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

【讨论】:

    猜你喜欢
    • 2018-08-07
    • 2020-10-30
    • 1970-01-01
    • 2013-09-25
    • 2015-02-03
    • 2014-10-19
    • 2017-07-03
    • 2017-11-20
    • 2017-10-01
    相关资源
    最近更新 更多