⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 最近新学linux对一个鼠标驱动的分析.cpp

📁 最近新学linux对一个鼠标驱动的分析
💻 CPP
📖 第 1 页 / 共 2 页
字号:
一个鼠标驱动程序的分析(/driver/input/mouse/amimouse.c)

一:Input设备驱动,(我称为虚拟输入设备)//drivers/input/input.c文件
	 input设备是一种字符设备在模块初始化时创建设备类"input",注册Input字符设备,input的操作函数只有Open函数。当打开特
	 定设备时才将特定的设备操作函数
	 static struct file_operations input_fops = {
	.owner = THIS_MODULE,
		.open = input_open_file,
	};
函数调用如下:
“/input/input . c”
input_init()//这是虚拟输入设备的入口,既模块加载时调用
{
	class_simple_create(THIS_MODULE,"input");//创建设备类
	input_proc_init()//创建proc下的文件节点
		retval = register_chrdev(INPUT_MAJOR, "input", &input_fops);//注册字符设备驱动程序,在系统字符设备数组中添加一个字符设
	
	备,主设备号为INPUT—MAJOR,操作函数集为input_fops,在特殊文件打开时会根据文件的节点结构INODE中的主设备
		
		号在系统字符设备数组中搜索主设备号相同的字符设备驱动程序的操作函数集并将此操作函数集付给FILE结构的操
		
		作函数集指针f_ops并执行该函数集中的打开操作。。对于本input类设备即为input_fops中的input_open_file
		
		devfs_mk_dir("input")//在设备目录"/dev"下创建devfs文件系统的"input"目录,以后的具体输入设备也将在这个目录下建立
		
		特殊设备文件,当打开该特殊文件时即对设备进行操作
}
当打开具体文件时既执行input_ipen_file
此函数会寻到具体设备的文件操作函数集并付给file->f_op(这是一个文件的操作函数集,当系统打开一个文件时即产生一个file结构
对该文件的操作都通过file中的f_opes 如读取即调用FILE->f_op->read等


二:输入驱动器,输入驱动器是指一类的输入设备(比如鼠标输入驱动器,键盘输入驱动器等等)
这里说的是鼠标输入驱动器。。(我也称之为虚拟鼠标驱动器,因为他并不完成真正的硬件相关的鼠标驱动,
真正的硬件IO驱动要在device中完成)他的描述结构是
struct input_handler {
	
	void *private;//私有数据
	
	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);//响应输入事件的函数
	struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id);//连接设备的函数
	void (*disconnect)(struct input_handle *handle);//断开设备
	
	struct file_operations *fops;//文件操作函数集
	int minor;//次设备号
	char *name;//设备名
	
	.....
};
static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
static struct input_handler mousedev_handler = {
	.event =	mousedev_event,//鼠标事件回调函数
		.connect =	mousedev_connect,//连接device
		.disconnect =	mousedev_disconnect,
		.fops =		&mousedev_fops,//文件操作函数集
		.minor =	MOUSEDEV_MINOR_BASE,//次设备号基数
		.name =		"mousedev",//设备名
		.id_table =	mousedev_ids,//本驱动支持的设备ID
};

他的入口是:
“/input/mousedev . c”
static int __init mousedev_init(void)
{
	input_register_handler(&mousedev_handler);//在虚拟输入设备中注册鼠标输入驱动器
	
	memset(&mousedev_mix, 0, sizeof(struct mousedev));
	INIT_LIST_HEAD(&mousedev_mix.list);
	init_waitqueue_head(&mousedev_mix.wait);
	mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;//给设备数组一个默认的鼠标device
	mousedev_mix.exist = 1;
	mousedev_mix.minor = MOUSEDEV_MIX;
	
	devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX),
		S_IFCHR|S_IRUGO|S_IWUSR, "input/mice");//建立input/mice文件
	class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX),
		NULL, "mice");//在input_class设备类中增加本设备驱动程序
	
	
	printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
	
	return 0;
}
虚拟鼠标设备驱动器就提供了各种操作的操作集函数,如read,write,ioctrl,等
static struct file_operations mousedev_fops = {
	.owner =	THIS_MODULE,
		.read =		mousedev_read,
		.write =	mousedev_write,
		.poll =		mousedev_poll,
		.open =		mousedev_open,
		.release =	mousedev_release,
		.fasync =	mousedev_fasync,
};
“/input/input . c”
void input_register_handler(struct input_handler *handler)
{
	struct input_dev *dev;//具体设备描述结构
	struct input_handle *handle;//设备句柄
	struct input_device_id *id;//设备ID
	
	if (!handler) return;
	
	INIT_LIST_HEAD(&handler->h_list);//初始化设备驱动器的链表
	
	if (handler->fops != NULL)
		input_table[handler->minor >> 5] = handler;//把驱动器按次设备号放到驱动器数组里,虚拟设备支持最多8个次设备
	
	list_add_tail(&handler->node, &input_handler_list);//加入驱动器链表
	
	list_for_each_entry(dev, &input_dev_list, node)
		if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
			if ((id = input_match_device(handler->id_table, dev)))//用当前所有的输入设备于驱动器适配
				if ((handle = handler->connect(handler, dev, id)))//适配成功与驱动器连接
					input_link_handle(handle);//连接成功将设备句柄加到设备的句柄链表中
}
我们先假设注册驱动器时还没有一个输入设备在链表中,即注册时不需要进行驱动器适配。在后面设备注册时再讲适配
连接
这样就完成了一个驱动器的注册
三,具体设备。。
这里完成的是真实与硬件交互的设备程序。。设备的描述结构是input_dev
struct input_dev {
	
	void *private;//私有数据
	
	char *name;//
	......
	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;//设备句柄
	struct device *dev;//通用设备结构
	
	struct list_head	h_list;//句柄链表input_link_handle函数将设备句柄加入到链表中。dev响应中断时如果没有自己专用的event函数就遍历handle列表找到handle指向的input_handler的evnt函数调用
	struct list_head	node;
};


struct input_handle {
	
	void *private;//私有数据 
	
	int open;
	char *name;
	
	struct input_dev *dev;//设备
	struct input_handler *handler;//句柄拥有者驱动器
	
	struct list_head	d_node;
	struct list_head	h_node;
};
它的入口是:
“/input/mouse/amimouse . c”
static int __init amimouse_init(void)
{
	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
		return -ENODEV;
	
	amimouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
	amimouse_dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
	amimouse_dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
	amimouse_dev.open = amimouse_open;
	amimouse_dev.close = amimouse_close;
	
	amimouse_dev.name = amimouse_name;
	amimouse_dev.phys = amimouse_phys;
	amimouse_dev.id.bustype = BUS_AMIGA;
	amimouse_dev.id.vendor = 0x0001;
	amimouse_dev.id.product = 0x0002;
	amimouse_dev.id.version = 0x0100;
	
	input_register_device(&amimouse_dev);//注册设备
	
	printk(KERN_INFO "input: %s at joy0dat\n", amimouse_name);
	return 0;
}
“/input/input . c”
void input_register_device(struct input_dev *dev)
{
	struct input_handle *handle;
	struct input_handler *handler;
	struct input_device_id *id;
	
	
	/*
	* If delay and period are pre-set by the driver, then autorepeating
	* is handled by the driver itself and we don't do it in input.c.
	*/
	
	init_timer(&dev->timer);//初始化设备的定时器,对鼠标没什么用mousedev里没对他做什么,对键盘有用
	if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
		dev->timer.data = (long) dev;
		dev->timer.function = input_repeat_key;
		dev->rep[REP_DELAY] = 250;
		dev->rep[REP_PERIOD] = 33;
	}
	
	INIT_LIST_HEAD(&dev->h_list);//初始化设备的句柄链表
	list_add_tail(&dev->node, &input_dev_list);
	
	list_for_each_entry(handler, &input_handler_list, node)//遍历驱动器列表
		if (!handler->blacklist || !input_match_device(handler->blacklist, dev))  
			if ((id = input_match_device(handler->id_table, dev)))//找到与设备相配的驱动器,用id_table适配
				if ((handle = handler->connect(handler, dev, id)))//适配成功与驱动器连接// 这里是mouse驱动器
					mousedev的connect函数是mousedev_connect
					input_link_handle(handle);//把Mousedev返回input_handle(注意不是input_handler)加到dev的handle连表中
				//这样dev响应中断时如果没有自己专用的event函数就遍历handle列表找到handle指向的input_handler的evnt函数调用
				
#ifdef CONFIG_HOTPLUG
				input_call_hotplug("add", dev);
#endif
				
#ifdef CONFIG_PROC_FS
				input_devices_state++;
				wake_up(&input_devices_poll_wait);
#endif
}

看看驱动器是怎么连接设备的,他申请一个mousedev结构用来保存鼠标设备信息。将设备和设备句柄及input_handler联系起来
放在mousedev_table指针数组中并给每个mousedev分配一个ID minor进行唯一标志
struct mousedev {
	int exist;//设备是否存在
	int open;//
	int minor;
	char name[16];
	wait_queue_head_t wait;//等待队列
	struct list_head list;//打开mousdev的文件的列表
	struct input_handle handle;//设备句柄-	
	struct mousedev_hw_data packet;
	unsigned int pkt_count;
	int old_x[4], old_y[4];
	int frac_dx, frac_dy;
	unsigned long touch;
};
struct input_handle {
	
	void *private;
	
	int open;
	char *name;
	
	struct input_dev *dev;
	struct input_handler *handler;
	
	struct list_head	d_node;
	struct list_head	h_node;
};
“/input/mousedev . c”
static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
{
	struct mousedev *mousedev;
	int minor = 0;
	
	for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
	if (minor == MOUSEDEV_MINORS) {
		printk(KERN_ERR "mousedev: no more free mousedev devices\n");
		return NULL;
	}
	
	if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
		return NULL;
	memset(mousedev, 0, sizeof(struct mousedev));
	
	INIT_LIST_HEAD(&mousedev->list);
	init_waitqueue_head(&mousedev->wait);
	
	mousedev->minor = minor;
	mousedev->exist = 1;
	mousedev->handle.dev = dev;
	mousedev->handle.name = mousedev->name;
	mousedev->handle.handler = handler;
	mousedev->handle.private = mousedev;
	sprintf(mousedev->name, "mouse%d", minor);
	
	if (mousedev_mix.open)
		input_open_device(&mousedev->handle);//看默认的mousedev是否需要打开,如果需要就打开设备。
	
	mousedev_table[minor] = mousedev;
	
	devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
		S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor);建立设备文件
	class_simple_device_add(input_class,
		MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
		dev->dev, "mouse%d", minor);
	
	return &mousedev->handle;
}
所有的注册已经完成
四:设备控制。。。。
打开设备。
当系统打开一个设备时 如"/dev/input/mouse0",虚拟文件系统根据文件节点INODE中的主设备

号在系统字符设备数组中搜索主设备号相同的字符设备驱动程序的操作函数集并将此操作函数集付给FILE结构的操

作函数集指针f_ops并执行该函数集中的打开操作。。对于input类设备即为input_fops中的input_open_file
“/input/input . c”
static int input_open_file(struct inode *inode, struct file *file)
{
	struct input_handler *handler = input_table[iminor(inode) >> 5];//根据次设备号找到驱动器这里我们就假设是打开
	鼠标既找到了mousedev_handler
	struct file_operations *old_fops, *new_fops = NULL;
	int err;
	
	/* No load-on-demand here? */
	if (!handler || !(new_fops = fops_get(handler->fops)))//得到输入驱动器的操作函数集//输入驱动器。可以是一个鼠标输入驱动器
		//或者一个键盘输入驱动器,这里分析的是鼠标
		return -ENODEV;
	
		/*
		* That's _really_ odd. Usually NULL ->open means "nothing special",
		* not "no device". Oh, well...
	*/
	if (!new_fops->open) {//如果输入驱动器没有打开操作函数,既设备文件无法完成打开操作

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -