输入子系统设备层 和 handler层分析



输入事件驱动层源码分析: kernel/driver/input/Evdev.c 


static int __init evdev_init(void)
input_register_handler(&evdev_handler);
//第一点:在input.c定义的static struct input_handler *input_table[8]; 填充到一个input_table[]数组中
//第二点:加入到相关链表中
//第三点:在input_dev_list链表中进行匹配 
//第四点:匹配结束后:error = handler->connect(handler, dev, id);


-------------------------------------------------------------------------
struct input_handler
{
重点成员:
void *private;  到时候方便引用
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
    int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
const struct file_operations *fops;
int minor;
const char *name;


const struct input_device_id *id_table;//handler所支持的devices
}




第二点分析:static struct input_handler evdev_handler这个结构体
static struct input_handler evdev_handler = {

.event = evdev_event,   //上报事件 
.connect = evdev_connect, //链接
.disconnect = evdev_disconnect, //失去链接
.fops = &evdev_fops, //用户层read write 的接口
.minor = EVDEV_MINOR_BASE, //基准次设备号  这个元素的作用
.name = "evdev", //名字 
.id_table = evdev_ids, //id_table 主要是记录了id_table使用的devices的特征
};


第一步:
.id_table = evdev_ids,


第二步:
static struct evdev *evdev_table[EVDEV_MINORS];
//这个结构体主要是
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)
第一步://for循环就是在 找minor这个下表  每一handler都有32位空间

第二步:创建一个evdev结构体 

第三步:填充这个结构体 
  主要是填充:
evdev->minor = minor; //作用 evdev_table[minor]
evdev->handle.dev = input_get_device(dev);
evdev->handle.handler = handler;   
evdev->handle.private = evdev; //handler的私有数据  将来有可能在以后需要用到
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
第四步:创建/dev/devices这个文件目录 
 device_initialize(&evdev->dev);
 device_add(&evdev->dev);
第五步:
//相应的链表中去
//把handle放入到一个链表中  主要是通过这个handle来链接 handler和设备
error = input_register_handle(&evdev->handle);
//创建一个handle进行复制 
//如果handler->start存在 则调用handler->start()函数


-------------------------------------------------------------------------------
app在调用read /dev/xxx.c函数时
static ssize_t evdev_read(struct file *file, char __user *buffer,size_t count, loff_t *ppos)
第一步:检查用户传进来的大小 
第二步:检查你是否是以非阻塞方式打开 ,缓冲区中的数据是否已满


第三步:
/*
* wait_event_interruptible - sleep until a condition gets true
 * @wq: the waitqueue to wait on
 * @condition: a C expression for the event to wait for
 * //当应用进程来读的时候
 * The process is put to sleep (TASK_INTERRUPTIBLE) until the
 * @condition evaluates to true or a signal is received.
 * The @condition is checked each time the waitqueue @wq is woken up.
 *
 * wake_up() has to be called after changing any variable that could
 * change the result of the wait condition.
 *
 * The function will return -ERESTARTSYS if it was interrupted by a
 * signal and 0 if @condition evaluated to true.
*/
/*
注意1:
第一种可能:条件成立
第一点:client这个队列有数据
第二点:evdev->exist为0的 这个handler不存在
condition 为真的时候  函数返回 retval = 0。

第二种可能:
中断返回:return -ERESTARTSYS 


注意2:
wake_up() has to be called after changing any variable that could
change the result of the wait condition.
当你发现,condition这个条件要改变的地方时,一定要调用wake_up()
*/
retval = wait_event_interruptible(evdev->wait,client->head != client->tail || !evdev->exist);


第四步:发送给用户
while (retval + input_event_size() <= count &&
      evdev_fetch_next_event(client, &event)) {
//在这里实现 把用户空间的数据放到用户空间上去了
if (input_event_to_user(buffer + retval, &event))
return -EFAULT;


retval += input_event_size();
}

static int evdev_open(struct inode *inode, struct file *file) //打开
{
struct evdev *evdev;
struct evdev_client *client;
evdev = evdev_table[i];
client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
client->evdev = evdev;
file->private_data = client; //重点:产生数据

}

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


驱动层:
Button-x210.c 
//按键类事件
input_report_key(input, s3c_Keycode[0], 0);
/*
参数1:input
参数2:EV_KEY
参数3:s3c_Keycode[0]
参数4:0
*/
input_event(dev, EV_KEY, code, !!value);
参数1:input
参数2:EV_KEY
参数3:s3c_Keycode[0]
参数4:0 
input_handle_event(dev, type, code, value);
static void input_pass_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)
handle->handler->event(handle, type, code, value);//就是与你进行挂在的那个handler

static void evdev_event(struct input_handle *handle,unsigned int type, unsigned int code, int value)
struct evdev *evdev = handle->private;
struct input_event event;
event.time.tv_sec = ts.tv_sec;
event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
event.type = type;
event.code = code;
event.value = value;
client = rcu_dereference(evdev->grab);
if (client)
evdev_pass_event(client, &event);
client->buffer[client->head++] = *event;
client->head &= EVDEV_BUFFER_SIZE - 1;//把数据放入
//唤醒机制  --------在应用层那边就可以进行读了
wake_up_interruptible(&evdev->wait);//那个队列就会被唤醒

驱动层:------提供给我们的接口函数
1.注册 与一个handler相互匹配  static struct input_dev * input;
2.input_report_key(input, s3c_Keycode[0], 0);
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值