语境
A平台驱动程序是为片上组件和其他不可发现的设备编写的设备驱动程序。在这种情况下,我关注的是SNVS 电源开/关驱动器适用于基于 i.MX6 的平台。
问题
我希望用户态程序能够在平台的开/关按钮切换时获取信息。我已经确定了两种可能的方法,并消除了至少一种:
- 注册一个字符设备作为与驱动程序共享相同中断的内核模块。允许用户态程序查询very
ioctl
和read/write
操作:不可能:IRQ 不共享 - 在管理设备时监听
uevents
内核发布的信息,然后使用udev
规则匹配驱动程序并采取行动。不幸的是,uevent
按下按钮时不会发布任何信息。这只是因为 的目的uevent
是输出设备加载或卸载时的信息。作为一种平台设备,该设备在启动时立即加载并且永远不会卸载。根据我的内核配置器,它也根本不可删除(必须是内核的一部分)
解决方案1
由于我希望每次通过中断按下按钮时都会发生一个事件,因此我修改了snvs_pwrkey.c
驱动程序以生成自己的uevent
.使用这个帖子作为起点。我对驱动程序进行了以下更改:
...
static irqreturn_t imx_snvs_pwrkey_interrupt (int irq, void *dev_id)
{
...
struct platform_device *pdev = dev_id;
int err = 0;
...
/* Sysfs notify: I chose "change" as the event type */
err = kobject_uevent(&(pdev->dev.kobj), KOBJ_CHANGE);
pr_err("%s :: kobject_uevent = %d\n", __FUNCTION__, err);
return IRQ_HANDLED
}
...
然后我用以下 udev 规则捕获这个:
# /etc/udev/rules.d/90-local.rules
KERNEL="20cc000.snvs:snvs-powerkey", SUBSYSTEM=="platform", DRIVER=="snvs_pwrkey", ACTION=="change", RUN+="/sbin/poweroff"
虽然这确实有效,当它触发时,我确实在 STDOUT 上收到异常和堆栈跟踪(但仅在第一次调用时)。这显然是不可取的,即使它对性能或稳定性没有明显的影响。但更重要的是,我觉得这是对 的滥用uevent
,因为我正在劫持一个用于管理 sysfs 上的设备以向用户空间发送中断通知的系统。
话虽如此,我想知道是否有更好的方法来实现我所要实现的目标。鉴于我无法与我自己的模块共享中断,因此能够在驱动程序中断被触发时通知用户空间应用程序。
附:/proc/interrupts
如果我切换按钮(IRQ 45),我确实可以看到中断计数器增加。但是,我不知道可以使用任何接口来等待或轮询来自用户程序的此类事件。也许阅读这个问题的其他人知道一种利用它作为解决方案的方法。