1.输入子系统

来源:互联网 发布:蓝牙串口软件ymodem 编辑:程序博客网 时间:2024/06/05 14:21

自己写的驱动:

(1)主设备号

(2)file_operation

(3)register_chrdev

(4)入口函数

(5)出口函数



输入子系统是现成的,是别人做好的。



输入子系统框架(input.c)


drivers/input/input.c:

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

static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};

只有一个open函数,那怎么读呢?

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

struct input_handler *handler = input_table[iminor(inode) >> 5];    //根据所打开文件的次设备好得到一个handler

new_fops = fops_get(handler->fops)                                              //新的fops等于handler里面的某个东西

file->f_op = new_fops;                                                                    //新打开文件的fop等于new_fops

err = new_fops->open(inode, file);                                                 //然后调用open函数


app:read > ... >file -> f_op ->read


input_table[] 数组由谁构造?


input_register_handler构造了这个数组项,这个被evdev.c、keyboard.c、mousedev.c等调用,

这些属于下一层,上面的是核心层。这些向上注册input_register_handler。


注册input_handler:

input_register_handler

input_table[handler->minor >> 5] = handler; //放入数组

ist_add_tail(&handler->node, &input_handler_list); //放入链表

list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler);
//对于每个input_dev,调用nput_attach_handler判断能否支持这个input_dev




dev代表设备,向核心注册input_register_device


handler能不能支持device,输入设备的input_device会和id_table相比较,如果成功就会调用connect函数,给他们

建立连接。


注册输入设备:

input_register_device

list_add_tail(&dev->node, &input_dev_list) //首先会把注册的设备放到链表里面去

list_for_each_entry(handler, &input_handler_list, node) //对于每一个input_handler,都调用input_attach_handler

input_attach_handler(dev, handler); //根据input_handler的id_table判断能否支持这个input_dev


input_attach_handler

id = input_match_device(handler->id_table, dev);                 //首先根据handler的id_table和输入设备来比较一下,看他们是否匹配,如果匹配 调用:

 handler->connect(handler, dev, id);


注册input_dev或input_handler时,会两两比较左边的input_dev和右边的input_handler,

根据input_handler的id_table判断这个input_handler能否支持这个input_dev,

如果能支持,则调用input_handler的connect函数建立“连接”


怎样建立连接?

ecdev_connect

evdev = kzalloc(sizeof(struct_evdev), GFP_KERNEL);                           //分配一个input_handle


//设置

evdev->handle.dev = dev;                                            //指向左边的input_dev结构体

evdev->handle.name = evdev->name;      

evdev->handle.handler = handler;     //指向右边的input_handler结构体

evdev->handle.private = evdev;


//注册

error = input_register_handle(&evdev->handle);


connect的时候注册一个input_handle,其中成员handler指向input_handler,dev指向input_device

input_device中的成员h_list指向input_handle,input_device中的成员h_list指向input_handle

这样我们就可以通过输入设备中的h_list找到input_handle,再从其中的成员handler找到handler;

放过来也一样。


总结:怎样建立连接

1.分配一个input_handle结构体

2.

input_handle.dev = input_dev;                          //指向左边的input_dev

input_handle.handler = input_handler;              //指向右边的input_handler

3.注册

input_handler->h_list = &input_handle;

input_dev->h_list       = &input_handle;




怎么读按键? 

app:read

--------------------------------------

evdev_read

// 无数据并且是非阻塞方式打开,则立刻返回。

if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
return -EAGAIN;

//否则休眠

retval = wait_event_interruptible(evdev->wait,
client->head != client->tail || !evdev->exist);

谁来唤醒

evdev_event

wake_up_interruptible(&evdev->wait);

evdev_event被谁调用?

猜测:应该是硬件相关代码,input_dev那层调用的。

在设备的中断服务程序里,确定事件是什么,然后调用相应的input_handler事件处理函数event

gpio_keys_isr

//上报事件

input_event(input, type, button->code, !!state);

input_sync(input);


input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

struct input_handle *handle;

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

if(handle->open)

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



怎样写符合输入子系统框架的驱动程序?
1.分配一个input_dev结构体

2.设置

3.注册

4.硬件相关代码,比如中断服务程序上报事件



我们需要做的就是

1.分配input_dev

2.设置

3.注册

4.硬件相关操作


struct input_dev {


void *private;


const char *name;
const char *phys;
const char *uniq;
struct input_id id;

 
unsigned long evbit[NBITS(EV_MAX)];                                    //表示能产生哪一类事件
unsigned long keybit[NBITS(KEY_MAX)];                                //表示能产生哪些按键
unsigned long relbit[NBITS(REL_MAX)];                                  //表示能产生哪些相对位移事件, x,y,滑轮
unsigned long absbit[NBITS(ABS_MAX)];                                //表示能产生哪些绝对位移事件,x,y
unsigned long mscbit[NBITS(MSC_MAX)];
unsigned long ledbit[NBITS(LED_MAX)];
unsigned long sndbit[NBITS(SND_MAX)];
unsigned long ffbit[NBITS(FF_MAX)];
unsigned long swbit[NBITS(SW_MAX)];


#define EV_SYN 0x00
#define EV_KEY 0x01
#define EV_REL 0x02
#define EV_ABS 0x03
#define EV_MSC 0x04
#define EV_SW 0x05
#define EV_LED 0x11
#define EV_SND 0x12
#define EV_REP 0x14
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f



原创粉丝点击