您的位置:首页 > 其它

输入子系统

2016-05-21 15:25 211 查看
1、核心层:

linux-2.6.22.6\drivers\input\input.c:

static int __init input_init(void)


register_chrdev(INPUT_MAJOR, "input", &input_fops);


static const struct file_operations input_fops
=

{
.owner = THIS_MODULE,
.open = input_open_file,
};


static int input_open_file(struct inode *inode, struct file *file)


struct input_handler *handler = input_table[iminor(inode) >> 5];

const struct file_operations *old_fops, *new_fops = NULL;

...

new_fops = fops_get(handler->fops)

...

file->f_op = new_fops;

new_fops->open(inode, file);


①、注册input_handler:

int input_register_handler(struct input_handler *handler)


list_add_tail(&handler->node, &input_handler_list);
//放入链表尾部

list_for_each_entry(dev, &input_dev_list, node)


input_attach_handler(dev, handler);  //对于每个条目,调用input_attach_handler函数,根据dev的id_table判断能否支持这个input_handler
id = input_match_device(handler->id_table, dev);

if (!id) return -ENODEV;

handler->connect(handler, dev, id); //如果支持,则建立连接
[/code]

②、注册输入设备:

int input_register_device(struct input_dev *dev)


list_add_tail(&dev->node, &input_dev_list);
//放入链表尾部

list_for_each_entry(handler, &input_handler_list, node)


input_attach_handler(dev, handler);   //对于每个条目,调用input_attach_handler函数,根据input_handler的id_table判断能否支持这个dev
id = input_match_device(handler->id_table, dev);

if (!id) return -ENODEV;

handler->connect(handler, dev, id); //如果支持,则建立连接
[/code]

③、如何建立连接:

①②中都要建立连接,用evdev.c来示例如何建立连接:

static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id)


evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);


evdev->handle.dev = dev;
//指向input_dev

evdev->handle.handler = handler;
//指向input_handler

input_register_handle(&evdev->handle);


struct input_handler *handler = handle->handler;


list_add_tail(&handle->d_node, &handle->dev->h_list);
//将handle结构体的d_node放入input_dev结构体的h_list

list_add_tail(&handle->h_node, &handler->h_list);
//将handle结构体的h_node放入input_handler结构体的h_list

这样input_dev和input_handler之间就通过handle建立了连接。

2、稳定程序层:

问:input_table数组由谁赋值?

static int __init evdev_init(void)
//evdev.c、keyboard.c、mouse.c 等的初始化函数,这里以evdev.c的初始化函数为示例

int input_register_handler(struct input_handler *handler)


input_table[handler->minor >> 5] = handler;


3、设备层:

以示例程序gpio_keys.c为例:

struct platform_driver gpio_keys_device_driver = {
.probe      = gpio_keys_probe,
.remove     = __devexit_p(gpio_keys_remove),
.driver     = {
.name   = "gpio-keys",
}
};


static int __init gpio_keys_init(void)
{
return platform_driver_register(&gpio_keys_device_driver);
}


static int __devinit gpio_keys_probe(struct platform_device *pdev)
{
...
struct input_dev *input;
...
input = input_allocate_device();
...
set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM,
button->desc ? button->desc : "gpio_keys", pdev);
...
error = input_register_device(input);
//*************************************************
******             其他硬件相关设置          *******
*************************************************//
}


执行input_register_device函数以开始进行输入设备注册并建立连接。

4、probe是如何被调用的?

安装模块时,①、在xxx_drv.c中xxx_init被执行,进而执行platform_driver_register>>driver_register>>bus_add_driver,把driver放入bus的drv链表,从bus的dev链表中取出每一个dev,用bus的match函数判断dev能否支持drv(通常通过结构体中的名称比较,但也有例外),若可以支持,调用drv的probe函数。②、在xxx_dev.c中xxx_init被执行,进而执行platform_device_register>>platform_device_add>>device_add,把device放入bus的dev链表,从bus的drv链表中取出每一个drv,用bus的match函数判断drv能否支持dev(通常通过结构体中的名称比较,但也有例外),若可以支持,调用dev的probe函数。

5、如何读?

app : read

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

……………

static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)


if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK)) return -EAGAIN;
//无数据并且是非阻塞方式打开,则立即返回

wait_event_interruptible(evdev->wait,client->head != client->tail || !evdev->exist);
//否则休眠

应用程序运行时无数据并且是非阻塞方式打开,线程就会进入休眠,谁来唤醒?由事件来唤醒:

static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)


wake_up_interruptible(&evdev->wait);


那么evdev_event又被谁调用?

以GPIO按键驱动程序为例说明:在设备的中断服务程序里,确定事件是什么,然后调用相应的input_handler的event处理函数

linux-2.6.22.6\drivers\input\keyboard\gpio_keys.c:

static irqreturn_t gpio_keys_isr(int irq, void *dev_id)


input_event(input, type, button->code, !!state);
//上报事件

struct input_handle *handle;


list_for_each_entry(handle, &dev->h_list, d_node)


if (handle->open)

handle->handler->event(handle, type, code, value);


input_sync(input);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: