drivers/input/input.c:
input_init > err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};
怎么读按键呢?
input_open_file
struct input_handler *handler = input_table[iminor(inode) >> 5];
new_fops = fops_get(handler->fops)
file->f_op = new_fops;
err = new_fops->open(inode, file);
app: read > ........... > file->f_op->read
input_table数组由谁构造?
注册input_handler:
input_register_handler
//放入数组
input_table[handler->minor >> 5] = handler;
//放入链表
list_add_tail(&handler->node, &input_handler_list);
//对于每一个input_handler,都调用input_attach_handler
list_for_each_entry(dev, &input_dev_list, node)
input_attach_handler(dev, handler); //根据input_handler的id_table判断能否支持这个input——dev
注册输入设备:
input_register_device:
//放入链表
list_add_tail(&dev->node, &input_dev_list);
//对于每一个input_handler,都调用input_attach_handler
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler); //根据input_handler的id_table判断能否支持这个input——dev
input_attach_handler
id = input_match_device(handler->id_table, dev);
error = handler->connect(handler, dev, id);
//注册input_dev或input_handler时,会两两比较左边的input_dev和右边的input_handler,
根据input_handler的id_table判断这个input_handler能否支持这个input_dev,
如果能支持,则调用input_handler的connect函数建立“连接”
怎么建立连接?
1. 分配一个input_handler结构体
2. evdev->handle.dev = dev; //指向左边的input_dev
evdev->handle.handler = handler; //指向右边的input_handler
3. 注册
input_handler->h_list = &input_handler;
input_dev->h_list = &input_handler;
evdev_connect
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); //分配一个input_handle
//设置
evdev->handle.name = evdev->name;
evdev->handle.private = evdev;
//注册
error = input_register_handle(&evdev->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. 硬件相关的代码,比如在中断服务程序里上报事件
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)];
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
struct ff_device *ff;
unsigned int repeat_key; struct timer_list timer;
int state;
int sync;
int abs[ABS_MAX + 1]; int rep[REP_MAX + 1];
unsigned long key[NBITS(KEY_MAX)];
unsigned long led[NBITS(LED_MAX)];
unsigned long snd[NBITS(SND_MAX)];
unsigned long sw[NBITS(SW_MAX)];
int absmax[ABS_MAX + 1];
int absmin[ABS_MAX + 1];
int absfuzz[ABS_MAX + 1];
int absflat[ABS_MAX + 1];
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
struct input_handle *grab;
struct mutex mutex; /* serializes open and close operations */
unsigned int users;
struct class_device cdev;
union { /* temporarily so while we switching to struct device */
struct device *parent;
} dev;
struct list_head h_list;
struct list_head node;
};
ls -l /dev/event* //查看事件命令
1. hexdump /dev/event1 (open(/dev/event1), read(), )
秒 微秒 类 code value
0000000 4918 0000 7e8c 0005 0001 0026 0001 0000 //按下L
0000010 4918 0000 7e98 0005 0000 0000 0000 0000 //同步事件
0000020 4918 0000 628e 0009 0001 0026 0000 0000 //松开L
0000030 4918 0000 6297 0009 0000 0000 0000 0000 //同步事件
2.如果没有启动QT:
cat /dev/tty1
按:S2,S3,S4, 就可以得到ls
或者
exec 0</dev/tty1
把sh 0号文件由串口输入改为/dev/tty1输入
ls -l /proc/770/fd
查看sh程序打开哪些文件
0:标准输入, 1:标准输出, 2:标准错误