新闻资讯
Group news
青岛广盛源肥业有限公司    您的位置: 首页  >  新闻资讯  >  正文

Linux输入子系统:怎样使用输入设备编程

2019年10月11日 文章来源:网络整理 热度:115℃ 作者:刘英

以下是一个非常简单的输入设备驱动程序。该设备只有一个按键,它通过BUTTON_PORT这一i/o端口访问,当按下或释放该按键,会发生BUTTON_IRQ中断,驱动程序看起来就像这样:

[cpp] view plain copy

#include   

#include   

#include   

#include   

#include   

static struct input_dev *button_dev;  

staTIc irqreturn_t button_interrupt(int irq, void *dummy)  

{  

input_report_key(button_dev, BTN_0, inb(BUTTON_PORT) & 1);  

input_sync(button_dev);  

return IRQ_HANDLED;  

}  

staTIc int __init button_init(void)  

{  

int error;  

if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {  

printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);  

return -EBUSY;  

}  

button_dev = input_allocate_device();  

if (!button_dev) {  

printk(KERN_ERR "button.c: Not enough memory\n");  

error = -ENOMEM;  

goto err_free_irq;  

}  

button_dev->evbit[0] = BIT_MASK(EV_KEY);  

button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);  

error = input_register_device(button_dev);  

if (error) {  

printk(KERN_ERR "button.c: Failed to register device\n");  

goto err_free_dev;  

}  

return 0;  

err_free_dev:  

input_free_device(button_dev);  

err_free_irq:  

free_irq(BUTTON_IRQ, button_interrupt);  

return error;  

}  

staTIc void __exit button_exit(void)  

{  

input_unregister_device(button_dev);  

free_irq(BUTTON_IRQ, button_interrupt);  

}  

module_init(button_init);  

module_exit(button_exit);  

1.1 例子驱动的工作过程

首先它必须包含头文件,它是input子系统的接口,它提供了所有必要的定义信息。

_init初始化函数,可以通过模块进行加载,也可以编译进内核中,它收集设备需要的资源(也会检查设备是否存在)。

接着,它用input_allocate_device()分配了一个input device结构,设置它的bitfields,设备驱动程序通过这一方式把自身的信息通知input子系统的其他部分:它能产生或者接受什么事件。我们的例子设备只能产生EV_KEY类型的事件,而且只能发出BTN_0事件code。这样我们只需要设置这两个bits,我们也可以用

[cpp] view plain copy

set_bit(EV_KEY, button_dev.evbit);  

set_bit(BTN_0, button_dev.keybit);  

进行设置,但是上面例子代码中的方法可以一次设置更多的位。

然后,例子驱动用下面的函数注册input device结构:

[cpp] view plain copy

input_register_device(&button_dev);  

这会把button_dev结构添加到input driver的全局链表中,调用device handler模块中的_connect函数来通知他一个新的设备出现了。input_register_device()可能会休眠,所以他不能在中断或者持有一个spinlock的情况下被使用。

功能上,该驱动只使用了函数:

[cpp] view plain copy

button_interrupt()  

在每次中断中通过检查按键的状态,并通过以下函数上报:

[cpp] view plain copy

input_report_key()  

该函数会进入input子系统。中断服务程序不必检查它是否会给input子系统报告value重复的事件(例如:按下,按下)。因为input_report_*函数自己会对此进行检查。

然后就是调用:

[cpp] view plain copy

input_sync()  

该函数告诉事件的接收者,我们已经发送了一次完整的报告信息。这对于我们这个只有一个按键的设备好像不太重要,但有些情况下它是非常重要的,例如当鼠标移动后,你不希望X和Y值被分开解释,因为那样会被解释为两次移动。

1.2 dev->open() and dev->close()

当驱动因为设备没有提供中断能力时,它需要不停地查询设备的状态,但是如果一直进行这个查询显得有点浪费。有时设备需要使用一些有价值的资源(例如中断)。这时,我们可以使用open和close回调函数来实现动态地停止查询和释放中断和决定何时再次恢复查询和获取中断。要实现这一功能,我们的例子驱动需要添加以下代码:

[cpp] view plain copy

staTIc int button_open(struct input_dev *dev)  

{  

if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {  

printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);  

return -EBUSY;  

}  

return 0;  

}  

static void button_close(struct input_dev *dev)  

{  

free_irq(IRQ_AMIGA_VERTB, button_interrupt);  

}  

static int __init button_init(void)  

{  

...  

button_dev->open = button_open;  

button_dev->close = button_close;  

...  

}  

上一篇:Linux输入子系统:事件的编码


下一篇:Linux调试器中的处理变问题

友情链接
Links