linux input设备驱动

本文深入探讨了Linux系统中的输入设备驱动,包括输入设备结构体、系统初始化、字符设备接口、设备类型设置、注册注销流程、输入处理器以及事件处理机制。通过对/proc/bus/input下devices和handlers文件的分析,展示了如何获取和解析设备信息。
摘要由CSDN通过智能技术生成

一. 输入设备结构体

     1. input_dev 输入设备

struct input_dev {
	const char *name;		//设备名
	const char *phys;		//设备系统层的物理路径
	const char *uniq;		//
	struct input_id id;	//输入设备id 总线类型;厂商编号,产品id,产品版本

	unsigned long evbit[BITS_TO_LONGS(EV_CNT)];	//事件类型标志位
	unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];	//键盘事件标志位
	unsigned long relbit[BITS_TO_LONGS(REL_CNT)];	//相对位移事件标志位
	unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];	//绝对位移事件标志位
	unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];	//杂项事件标志位
	unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];	//led指示灯标志位
	unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];	//声音事件
	unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];	//强制反馈事件
	unsigned long swbit[BITS_TO_LONGS(SW_CNT)];	//开关事件标志位

	unsigned int hint_events_per_packet;
	unsigned int keycodemax;		//键盘码表大小
	unsigned int keycodesize;		//键盘码大小
	void *keycode;			//键盘码表指针

	int (*setkeycode)(struct input_dev *dev,unsigned int scancode, unsigned int keycode);	//设置键盘码
	int (*getkeycode)(struct input_dev *dev,unsigned int scancode, unsigned int *keycode);	//获取键盘码
	int (*setkeycode_new)(struct input_dev *dev,const struct input_keymap_entry *ke,unsigned int *old_keycode);	
	int (*getkeycode_new)(struct input_dev *dev,struct input_keymap_entry *ke);

	struct ff_device *ff;	//强制反馈设备
	unsigned int repeat_key;	//重复按键标志位
	struct timer_list timer;	//定时器
	int rep[REP_CNT];		//重复次数
	struct input_mt_slot *mt;
	int mtsize;
	int slot;
	struct input_absinfo *absinfo;
	unsigned long key[BITS_TO_LONGS(KEY_CNT)];	//
	unsigned long led[BITS_TO_LONGS(LED_CNT)];	//
	unsigned long snd[BITS_TO_LONGS(SND_CNT)];	//
	unsigned long sw[BITS_TO_LONGS(SW_CNT)];	//

	int (*open)(struct input_dev *dev);		//open方法
	void (*close)(struct input_dev *dev);	//close方法
	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 __rcu *grab;
	spinlock_t event_lock;
	struct mutex mutex;
	unsigned int users;
	bool going_away;
	bool sync;
	struct device dev;		//设备文件
	struct list_head	h_list;	//input_handler处理器链表头
	struct list_head	node;	//input_device设备链表头
};

      2. input_handler 输入处理器

struct input_handler {
	void *private;	//私有数据
	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);	//事件处理
	bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);	//过滤器
	bool (*match)(struct input_handler *handler, struct input_dev *dev);	//设备匹配
	int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);	//设备连接
	void (*disconnect)(struct input_handle *handle);	//设备断开连接
	void (*start)(struct input_handle *handle);
	const struct file_operations *fops;	//输入操作函数集
	int minor;	//次设备号
	const char *name;	//设备名
	const struct input_device_id *id_table;	//输入设备 id表
	struct list_head	h_list;	//input_handler处理器链表头
	struct list_head	node;	//input_device设备链表头
};

 

二. 输入系统初始化

     1 input_init

static int __init input_init(void)
{
	int err;

	err = class_register(&input_class);	//注册类 创建"/sys/input" 
	if (err) {
		printk(KERN_ERR "input: unable to register input_dev class\n");
		return err;
	}

	err = input_proc_init();	//初始化"/proc/bus/input"接口
	if (err)
		goto fail1;

	err = register_chrdev(INPUT_MAJOR, "input", &input_fops);	//注册所有输入字符设备,并捆绑input_fops
	if (err) {
		printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
		goto fail2;
	}

	return 0;

 fail2:	input_proc_exit();
 fail1:	class_unregister(&input_class);
	return err;
}

     2. /proc 接口

     2.1 创建/proc/bus/input下的文件

static int __init input_proc_init(void)
{
	struct proc_dir_entry *entry;

	proc_bus_input_dir = proc_mkdir("bus/input", NULL);	//创建"/proc/bus/input"
	if (!proc_bus_input_dir)
		return -ENOMEM;

	entry = proc_create("devices", 0, proc_bus_input_dir,&input_devices_fileops);	//创建"/proc/bus/input/devices"
	if (!entry)
		goto fail1;

	entry = proc_create("handlers", 0, proc_bus_input_dir,&input_handlers_fileops);	//创建"/proc/bus/input/handlers"
	if (!entry)
		goto fail2;

	return 0;

 fail2:	remove_proc_entry("devices", proc_bus_input_dir);
 fail1: remove_proc_entry("bus/input", NULL);
	return -ENOMEM;
}

     2.2 devices文件 

static const struct file_operations input_devices_fileops = {
	.owner		= THIS_MODULE,
	.open		= input_proc_devices_open,
	.poll		= input_proc_devices_poll,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

    2.2.1 限于篇幅及省略啰嗦

这里当我们去cat /proc/bus/input/devices时候,会调用input_proc_devices_open函数,接着调用seq_open(file, &input_devices_seq_ops),捆绑了input_devices_seq_ops操作函数集,

其seq_operations函数集中声明了.show方法为input_devices_seq_show,该方法打印了些信息到seq文件,接着cat命令会调用read方法,read方法会调用.show方法,

接着把打印到文件的信息复制用户空间的缓冲区中.这里主要看看.show方法吧

     2.2.2 input_devices_seq_show

static int input_devices_seq_show(struct seq_file *seq, void *v)
{
	struct input_dev *d
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值