linux 内核 input,ARM Linux内核Input输入子系统浅解

list = evdev->grab;

do_gettimeofday(&list->buffer[list->head].time);

list->buffer[list->head].type = type;

list->buffer[list->head].code = code;

list->buffer[list->head].value = value;

list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);

kill_fasync(&list->fasync, SIGIO, POLL_IN);

} else

list_for_each_entry(list, &evdev->list, node) {

do_gettimeofday(&list->buffer[list->head].time);     //给buffer成员赋值

list->buffer[list->head].type = type;

list->buffer[list->head].code = code;

list->buffer[list->head].value = value;

list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);

kill_fasync(&list->fasync, SIGIO, POLL_IN);

}

wake_up_interruptible(&evdev->wait);      //用来唤醒一个等待队列(我也不懂)

}

先看前面的struct evdev *evdev = handle->private,还记得handler->private吗,在input_handle结构体中它是一个空指针,在前面有讲到在执行static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)函数的时候就被赋值了(evdev->handle.private = evdev;)。

再看最后代码加粗的部分,显然是给evdev_list结构体中的buffer成员赋上从设备中传过来的数据,当数据存放好了之后,head加1,当head的值达到EVDEV_BUFFER_SIZE时又回到0;

至此数据的传递就算是结束了,接下来就是等着被读走,只要在用户空间进行read操作即可。

第五章、数据读取过程

读取就变得很简单了,做过linux编程的都能知道,只要在应用中定义了个input_event结构体,通过open打开设备,然后进行read即可,再来看该设备的read函数:

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

{

struct evdev_list *list = file->private_data;

int retval;

if (count < evdev_event_size())//每次读取的字节数至少是input_event的大小

return -EINVAL;

if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))      //是否满足读取条件

return -EAGAIN;

retval = wait_event_interruptible(list->evdev->wait,

list->head != list->tail || (!list->evdev->exist));      //等待唤醒,和前面说的等待队列对应(我也不懂)

if (retval)

return retval;

if (!list->evdev->exist)

return -ENODEV;

while (list->head != list->tail && retval + evdev_event_size() <= count) {

struct input_event *event = (struct input_event *) list->buffer + list->tail;

if (evdev_event_to_user(buffer + retval, event))      //复制数据到用户空间

return -EFAULT;

list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);

retval += evdev_event_size();

}

return retval;

}

函数前面基本上都是在做一系列的条件判断,判断是否符合读取的条件,evdev_event_to_user(buffer + retval, event)这句是真正的把数据复制到用户空间,进入查看:

static int evdev_event_to_user(char __user *buffer, const struct input_event *event)

{

if (copy_to_user(buffer, event, sizeof(struct input_event)))

return -EFAULT;

return 0;

}

该函里面也只是调用了copy_to_user()函数而已,该函数相比我们都不会陌生了,就是把event所指向地址空间的数据复制到buffer所指向的地址空间中而已。

再回到read函数中来,函数在末尾返回读取到的字节数,至于要把这些数据拿去干什么用,那就是应用层的事情了。

可以看到接口函数中除了read以外还有write、ioctl等函数,因为对于触摸屏来说我们主要就是要获取触笔在触摸屏上点击的坐标位置而已,所以write、ioctl等函数会很少用到,这里就不再做介绍。

注:本文只在一定的层面(本人的理解)上对linux下的input子系统的介绍,里边还有很多要点没有办法去涉及,只是一个入门级的学习过程,紧限于在在完善的input子系统下进行做驱动修改,而不具备做驱动开发的能力。--以触摸屏驱动为例

第一章、了解linux input子系统

Linux输入设备总类繁杂,常见的包括有按键、键盘、触摸屏、鼠标、摇杆等等,他们本身就是字符设备,而linux内核将这些设备的共同性抽象出来,简化驱动开发建立了一个input子系统。子系统共分为三层,如图1所示。1ce1d1919e079a3931dc88004d2b1b8f.png

图1  input输入子系统

驱动层和硬件相关,直接捕捉和获取硬件设备的数据信息等(包括触摸屏被按下、按下位置、鼠标移动、键盘按下等等),然后将数据信息报告到核心层。核心层负责连接驱动层和事件处理层,设备驱动(device driver)和处理程序(handler)的注册需要通过核心层来完成,核心层接收来自驱动层的数据信息,并将数据信息选择对应的handler去处理,最终handler将数据复制到用户空间。

先了解三个定义在/linux/input.h下重要的结构体input_dev、input_handler、input_handle。

struct input_dev {

void *private;

const char *name;

const char *phys;

const char *uniq;

struct input_id id;      //与input_handler匹配用的id

unsigned long evbit[NBITS(EV_MAX)];            //设备支持的事件类型

unsigned long keybit[NBITS(KEY_MAX)];      //按键事件支持的子事件类型

unsigned long relbit[NBITS(REL_MAX)];

unsigned long absbit[NBITS(ABS_MAX)];      //绝对坐标事件支持的子事件类型

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)];

int ff_effects_max;

unsigned int keycodemax;

unsigned int keycodesize;

void *keycode;

unsigned int repeat_key;

struct timer_list timer;

struct pt_regs *regs;

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 (*accept)(struct input_dev *dev, struct file *file);

int (*flush)(struct input_dev *dev, struct file *file);

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

int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect);

int (*erase_effect)(struct input_dev *dev, int effect_id);

struct input_handle *grab;      //当前占有该设备的handle

struct mutex mutex;      /* serializes open and close operations */

unsigned int users;            //打开该设备的用户量

struct class_device cdev;

struct device *dev;      /* will be removed soon */

int dynalloc;      /* temporarily */

struct list_head      h_list;      //该链表头用于链接该设备所关联的input_handle

c2c9ed493cd281aa86d8a6f5178c4c01.gif [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] ..[12] 610626052e95c7fbe3d254abc769d9ad.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值