本文主要是介绍linux驱动—input输入子系统—The simplest example(一个最简单的实例)分析(1),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Programming input drivers(摘于Documentation\input\input-programming.txt)
这篇文档说明的输入设备驱动的编写。
Here comes a very simple example of an input device driver. The device hasjust one button and the button is accessible at i/o port BUTTON_PORT. When
pressed or released a BUTTON_IRQ happens.
The driver could look like:
#include <linux/input.h>#include <linux/module.h>
#include <linux/init.h>
#include <asm/irq.h>
#include <asm/io.h>
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;
}
module_init(button_init);
{
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;
}
/**
* input_allocate_device - allocate memory for new input device
*
* Returns prepared struct input_dev or NULL.
*
* NOTE: Use input_free_device() to free devices that have not been
* registered; input_unregister_device() should be used for already
* registered devices.
*/
struct input_dev *input_allocate_device(void)
{
struct input_dev *dev;
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); 分配一个input_dev结构体
if (dev) {
dev->dev.type = &input_dev_type; 初始化设备的类型
dev->dev.class = &input_class; 设置为输入设备类
device_initialize(&dev->dev); 初始化device结构
mutex_init(&dev->mutex); 初始化互斥锁
spin_lock_init(&dev->event_lock); 初始化事件自旋锁
INIT_LIST_HEAD(&dev->h_list); 初始化链表
INIT_LIST_HEAD(&dev->node);
__module_get(THIS_MODULE); 增加模块引用计数
}
return dev;
}
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;
}
/**
* input_register_device - register device with input core
* @dev: device to be registered
*
* This function registers device with input core. The device must be
* allocated with input_allocate_device() and all it's capabilities
* set up before registering.
* If function fails the device must be freed with input_free_device().
* Once device has been successfully registered it can be unregistered
* with input_unregister_device(); input_free_device() should not be
* called in this case.
*/
int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0);
struct input_handler *handler;
const char *path;
int error;
__set_bit(EV_SYN, dev->evbit);设置input_dev所支持的事件类型。事件类型由input_dev的evbit成员来表示,在这里将其EV_SYN置位,表示设备支持所有的事件。常用的事件类型如下:
1. #define EV_SYN 0x00 /*表示设备支持所有的事件*/
2. #define EV_KEY 0x01 /*键盘或者按键,表示一个键码*/
3. #define EV_REL 0x02 /*鼠标设备,表示一个相对的光标位置结果*/
4. #define EV_ABS 0x03 /*手写板产生的值,其是一个绝对整数值*/
5. #define EV_MSC 0x04 /*其他类型*/
6. #define EV_LED 0x11 /*LED灯设备*/
7. #define EV_SND 0x12 /*蜂鸣器,输入声音*/
8. #define EV_REP 0x14 /*允许重复按键类型*/
9. #define EV_PWR 0x16 /*电源管理事件*/
/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
*/
init_timer(&dev->timer); 初始化一个timer定时器
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
dev->rep[REP_DELAY] = 250;
dev->rep[REP_PERIOD] = 33;
}
if (!dev->getkeycode)
dev->getkeycode = input_default_getkeycode;
if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;
检查getkeycode()函数和setkeycode()函数是否被定义,如果没定义,则使用默认的处理函数,这两个函数为 input_default_getkeycode()和input_default_setkeycode()。 input_default_getkeycode()函数用来得到指定位置的键值。input_default_setkeycode()函数用来设置键值。
snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
error = device_add(&dev->dev); 注册到设备模型中
if (error)
return error;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
printk(KERN_INFO "input: %s as %s\n",
dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
kfree(path);
error = mutex_lock_interruptible(&input_mutex);
if (error) {
device_del(&dev->dev);
return error;
}
list_add_tail(&dev->node, &input_dev_list);调用此函数将input_dev加入全局量input_dev_list链表, 如下定义:static LIST_HEAD(input_dev_list);
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler); 此函数用来匹配input_dev和handler,只有匹配成功,才能进行下一步的关联操作。源码如下:
static int input_attach_handler(structinput_dev *dev, struct input_handler *handler)
{
const struct input_device_id *id; 输入设备的指针
struct input_device_id {
kernel_ulong_t flags;
__u16 bustype; 总线类型
__u16 vendor; 制造商ID
__u16 product; 产品ID
__u16 version; 版本号
kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];
kernel_ulong_t driver_info;
};
int error;
if (handler->blacklist && input_match_device(handler->blacklist, dev))
return -ENODEV;
首先判断handle的blacklist是否被赋值,如果被赋值,则匹配blacklist中的数据跟dev->id的数据是否匹配。blacklist是一个input_device_id*的类型,其指向input_device_ids的一个表,这个表中存放了驱动程序应该忽略的设备。即使在id_table中找到支持的项,也应该忽略这种设备。
id = input_match_device(handler->id_table, dev); 此函数数匹配handle->id_table和dev->id中的数据。handler->id_table也是一个input_device_id类型的指针,其表示驱动支持的设备列表。其中handler结构体在另一篇博客中有说明。这个函数还有后面的下篇再分析。
if (!id)
return -ENODEV;
error = handler->connect(handler, dev, id);
if (error && error != -ENODEV)
printk(KERN_ERR
"input: failed to attach handler %s to device %s, "
"error: %d\n",
handler->name, kobject_name(&dev->dev.kobj), error);
return error;
}
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
return 0;
}
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_exit(button_exit);
linux驱动—input输入子系统—The simplest example(一个最简单的实例)分析(2)的链接地址
这篇关于linux驱动—input输入子系统—The simplest example(一个最简单的实例)分析(1)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!