Goldfish_events浅析

来源:互联网 发布:js字符串转base64编码 编辑:程序博客网 时间:2024/04/29 12:03


oldfish_events是键盘驱动,跟其它驱动一样,Goldfish_events也是从模块初始化开始:



module_init(events_init);


static int __devinit events_init(void)

{

return platform_driver_register(&events_driver);

}


初始的过程就是一个注册的过程:

由于

static struct platform_driver events_driver = {

.probe = events_probe,

.driver = {

.name = "goldfish_events",

},

};

所以,在platform_driver_register函数中,会执行:

drv->driver.bus = &platform_bus_type;

if (drv->probe)

drv->driver.probe = platform_drv_probe;



所以,最后调用到platform_drv_probe函数:

static int platform_drv_probe(struct device *_dev)

{

struct platform_driver *drv = to_platform_driver(_dev->driver);

struct platform_device *dev = to_platform_device(_dev);


return drv->probe(dev);

}


to_platform_driver(X)个宏,而这个宏最终由另外一个经典的宏来完成,container_of(X)

to_platform_driver(_dev->driver);的作用是返回一个platform_driver型的指针,而to_platform_device(_dev);则是返回一个platform_device的指针,这个从它赋给的drvdev的类型就可以知道。


因此,最终从platform_drv_probe返回return drv->probe(dev);platform_driver_register

platform_driver_register返回return driver_register(&drv->driver);events_init。这样就完成了一初始化过程。


由上易知,return drv->probe(dev);将获得的参数dev传到了events_probeevents_probe函数完成的功能如下:


input_dev = input_allocate_device();


addr = (unsigned) ioremap(res->start, 4096); //获取虚拟地址

irq = platform_get_irq(pdev, 0); //获取中断


edev->input = input_dev;

edev->addr = addr;

edev->irq = irq;

ret = input_register_device(input_dev); //input.c中注册输入设备(键盘)


request_irq(edev->irq, events_interrupt, 0, "goldfish-events-keypad", edev)

//申请中断

中断申请过程中,传入了一个很关键的参数:events_interrupt这个参数是个函数名,函数原型为:

static irqreturn_t events_interrupt(int irq, void *dev_id) 

之所以说这个函数很关键,一是因为这个函数在input.c中,建立了与input.c的联系,二是因为在这个函数里调用了一个核心函数:

input_event(edev->input, type, code, value);

它通过调用input_handle_event对输入事件进行处理。然后将返回值传入中断申请函数。






在键盘驱动中,并没有建立键盘的设备结点。那么设备结点是在哪建立的呢?

其实,这个步骤是在input.c的初始化过程中完成的。

input_init(void)


err = input_proc_init(); //输入过程初始化


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

//设备结点的创建

在这里,主设备号为13&input_fops 则传入生个file_operations结构的地址。


static const struct file_operations input_fops = {

.owner = THIS_MODULE,

.open = input_open_file,

};




这三个驱动层中与用户态函数关系最密切的要属evdev.c了。从上面的分析我们知道,用户态调用了

fd = open(deviceName, O_RDWR);

if(ioctl(fd, EVIOCGVERSION, &version))

等函数对底层进行了操作,这个接口函数正是evdev.c提供的。、


这个函数主要负责对输入事件进行处理。所谓的输入事件是经input.c封装好的事件,如键盘事件、鼠标事件、触摸层事件等等。对于evdev.c来说,这些事件都是一样的,而这些事件的类型则有相应的变量进行标识(在结构体input_dev中的字段keybit)。如:

Ø EV_KEY    0x01   按键
Ø EV_REL    0x02   鼠标
Ø EV_ABS    0x03   触摸屏

原创粉丝点击