input子系统的输入核心层源码分析

第一点:input子系统架构总览1
input子系统分为三层
(1)最上层:输入事件驱动层,evdev.c和mousedev.c和joydev.c属于这一层
(2)中间层:输入核心层,input.c属于这一层

(3)最下层:输入设备驱动层,drivers/input/xxx 文件夹下   这些文件夹就是各种各样的设备,每一个文件就是一类输入类型的设备

最上层在实现的过程中调用相应的 中间层相应函数
最下层在实现的过程中调用相应的 中间层相应函数
input输入子系统都在 /kernel/drivers/input这些文件夹中


第二点:

input类设备驱动开发方法

//只需要看懂input.c 和 evdev.c 只需要看懂相应的框架,不需要看懂相应的细节

我们的工作:

      输入事件驱动层和输入核心层不需要动,只需要编写设备驱动层

(2)设备驱动层编写的接口和调用模式已定义好,驱动工程师的核心工作量是对具体输入设备硬件的操作和性能调优。


(3)input子系统不算复杂,学习时要注意“标准模式”四个字。
“标准模式”  驱动框架定义好的数据结构和接口,定义好的如何填充
标准流: 先做什么  后做什么 填充什么,搞明白


核心层源码分析: 

分析input.c这个中间层文件
第一步:
static int __init input_init(void)
第一件事情:
err = class_register(&input_class); //立马就会反映设备文件
第二件事情:
err = register_chrdev(INPUT_MAJOR, "input", &input_fops); //主次设备号的问题





subsys_initcall(input_init);//  联想:初始化的先后顺序
总结:
主要干的活  注册一个类   注册一个字符设备  
等着我们真正的驱动来调用 创建文件的函数

分析方法:
1.设备驱动层的接口函数
写设备驱动层那边的工作人员需要
第一步:创建一个input设备结构体 ,填充相关的硬件信息-----主要是属性和操作硬件的相关方法
第二步:调用相关的接口进行相关注册
我们需要分析是相关接口和这个结构体的含义
第一步:struct input_dev 这个结构体关键成员


第二步:相关接口
//函数的功能:
 /*
  函数的功能主要是为了定义一个空间
 */


struct input_dev *input_allocate_device(void)
   dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
   dev->dev.type = &input_dev_type; //类型
   dev->dev.class = &input_class;
总结:定义一个结构体(申请一段空间),填充一些数据结构




/*
接口函数 : input_register_device 
接口的数据结构:struct input_dev *dev
*/
int input_register_device(struct input_dev *dev)
主线:
//设备的添加 注册
error = device_add(&dev->dev);

//名字 input0 input1 input2 //创建设备 /dev/input/input0 input2
dev_set_name(&dev->dev, "input%ld",(unsigned long) atomic_inc_return(&input_no) - 1);

//添加到链表的末尾
list_add_tail(&dev->node, &input_dev_list);


list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);


细节1:
//相应的同步包  
(1)__set_bit(EV_SYN, dev->evbit); //设置同步包  __set_bit接口函数

(2) //
__clear_bit(KEY_RESERVED, dev->keybit);


细节2:
struct input_handler *handler; //定义一个handler结构体
list_for_each_entry(handler, &input_handler_list, node) //在链表中不断的找下一个节点
input_attach_handler(dev, handler);
input.c:
内核中定义一个:static LIST_HEAD(input_handler_list);链表  
/*
参数1:struct input_dev *dev表示这个设备
参数2:handler 来自于static LIST_HEAD(input_handler_list)这个链表
*/
input_attach_handler(dev, handler);//主要的功能是匹配和链接

//用来匹配
//第一步:
id = input_match_device(handler, dev);



//第二步:
//创建了设备文件和file_operation
//调用handler->connect的函数进行链接
error = handler->connect(handler, dev, id); 







input_match_device 最为主要的部分:
举例:这是一个handler的id  
static const struct input_device_id mousedev_ids[] = {


{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT |
INPUT_DEVICE_ID_MATCH_RELBIT,
.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
.keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },
.relbit = { BIT_MASK(REL_X) | BIT_MASK(REL_Y) },
}, /* A mouse like device, at least one button,
  two relative axes */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_RELBIT,
.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
.relbit = { BIT_MASK(REL_WHEEL) },
}, /* A separate scrollwheel */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT |
INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
.keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
}, /* A tablet like device, at least touch detection,
  two absolute axes */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT |
INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
.keybit = { [BIT_WORD(BTN_TOOL_FINGER)] =
BIT_MASK(BTN_TOOL_FINGER) },
.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
BIT_MASK(ABS_PRESSURE) |
BIT_MASK(ABS_TOOL_WIDTH) },
}, /* A touchpad */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT |
INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
.keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },
.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
}, /* Mouse-like device with absolute X and Y but ordinary
  clicks, like hp ILO2 High Performance mouse */


{ }, /* Terminating entry */   //这个是作为结束标志
};

id = input_match_device(handler, dev);
第一步:对handler id的每一项进项进行for循环,进行匹配检查 -------具体看源代码 input.c 

第二步:检查handler是否有match函数 ,如果有就调用handler->match(handler, dev)
if (!handler->match || handler->match(handler, dev))
return id;


细节3:open函数

static int input_open_file(struct inode *inode, struct file *file) //次设备号

handler = input_table[iminor(inode) >> 5];//次设备号

if (handler)
new_fops = fops_get(handler->fops);

//最终调用的是次设备号中的open 函数
err = new_fops->open(inode, file);


重点四:

//这一步再来进行进一步的初始化 表示输入类型的设备的能力
//这个输入设备具有哪些能力
//主要是声明  驱动层向上层到底上报哪些信息
//这里主要来参考input.h
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)


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






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值