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

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

📁 最近新学linux对一个鼠标驱动的分析
💻 CPP
📖 第 1 页 / 共 2 页
字号:
		fops_put(new_fops);
		return -ENODEV;
	}
	old_fops = file->f_op;
	file->f_op = new_fops;//将句柄的操作函数集给file->f_op
	
	err = new_fops->open(inode, file);//执行输入驱动器的打开操作
	
	if (err) {
		fops_put(file->f_op);
		file->f_op = fops_get(old_fops);
	}
	fops_put(old_fops);
	return err;
}

联系err = new_fops->open(inode, file);
和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
};
这个就相当于调用mousedev_handler.fops中的函数也即mousedev_fops的函数,
而mousedev_fops的open函数是mousedev_open

分配一个mousedev_list结构保存给file结构的私有数据
mousedev_list里保存了一个mousedev结构。。而mousedev也有个文件链表。这样当
中断发生时可以根据链表反向找到file结构,而后驱动器打开他拥有并存在的未打开的所有设备句柄
调用了input_open_device函数
“/input/mousedev . c”
static int mousedev_open(struct inode * inode, struct file * file)
{
	struct mousedev_list *list;
	struct input_handle *handle;
	struct mousedev *mousedev;
	int i;
	
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
	if (imajor(inode) == MISC_MAJOR)
		i = MOUSEDEV_MIX;
	else
#endif
		i = iminor(inode) - MOUSEDEV_MINOR_BASE;
	
	if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
		return -ENODEV;
	
	if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
		return -ENOMEM;
	memset(list, 0, sizeof(struct mousedev_list));
	
	spin_lock_init(&list->packet_lock);
	list->pos_x = xres / 2;
	list->pos_y = yres / 2;
	list->mousedev = mousedev_table[i];
	list_add_tail(&list->node, &mousedev_table[i]->list);
	file->private_data = list;
	
	if (!list->mousedev->open++) {
		if (list->mousedev->minor == MOUSEDEV_MIX) {
			list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
				mousedev = handle->private;
				if (!mousedev->open && mousedev->exist)
					input_open_device(handle);
			}
		} else
			if (!mousedev_mix.open && list->mousedev->exist)
				input_open_device(&list->mousedev->handle);
	}
	
	return 0;
}
input_open_device 调用设柄句柄中保存的设备指针的open函数直接打开设备
“/input/input . c”
int input_open_device(struct input_handle *handle)//在mousedev里的mousedevopen调用
{
	handle->open++;
	if (handle->dev->open)
		return handle->dev->open(handle->dev);//调用具体设备的OPEN比如amimouse里的Open
	return 0;
}
这就相当于打开了第三节中input_dev::open函数既amimouse_open函数
amimouse_open函数为设备申请了中断资源并设定了中断服务程序amimouse_interrupt
“/input/mouse/amimouse . c”
static int amimouse_open(struct input_dev *dev)
{
	unsigned short joy0dat;
	
	if (amimouse_used++)
		return 0;
	
	joy0dat = custom.joy0dat;
	
	amimouse_lastx = joy0dat & 0xff;
	amimouse_lasty = joy0dat >> 8;
	
	if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
		amimouse_used--;
		printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
		return -EBUSY;
	}
	
	return 0;
}
中断服务程序amimouse_interrupt从内存得到数据//amimouse中断发生时会把数据存在一块固定地址
通过input_report_rel等函数通知设备已获得数据
“/input/mouse/amimouse . c”
static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
/**/
		unsigned short joy0dat, potgor;
	int nx, ny, dx, dy;
	
	joy0dat = custom.joy0dat;
	
	nx = joy0dat & 0xff;
	ny = joy0dat >> 8;
	
	dx = nx - amimouse_lastx;
	dy = ny - amimouse_lasty;
	
	if (dx < -127) dx = (256 + nx) - amimouse_lastx;
	if (dx >  127) dx = (nx - 256) - amimouse_lastx;
	if (dy < -127) dy = (256 + ny) - amimouse_lasty;
	if (dy >  127) dy = (ny - 256) - amimouse_lasty;
	
	amimouse_lastx = nx;
	amimouse_lasty = ny;
	
	potgor = custom.potgor;
	input_regs(&amimouse_dev, fp);
	
	input_report_rel(&amimouse_dev, REL_X, dx);
	input_report_rel(&amimouse_dev, REL_Y, dy);
	
	input_report_key(&amimouse_dev, BTN_LEFT,   ciaa.pra & 0x40);
	input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100);
	input_report_key(&amimouse_dev, BTN_RIGHT,  potgor & 0x0400);
	
	input_sync(&amimouse_dev);
	.......
	return IRQ_HANDLED;
}

input_report_rel,input_report_key函数只是简单调用input_event函数
“/linux/input.h”
static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
{
	input_event(dev, EV_REL, code, value);
}

如果设备自已有专用event函数既input_dev结构中event非空 input_event调用event函数
如果与设备相关的设备句柄是唯一指定的保存在grab中就调用该句柄所指向的驱动器handler的event函数
否则遍历设备设备句柄链表调用句柄指向的驱动器event函数。。
这里因为amimouse没有专属的event函数而grab在input_register_device时在mousedev_connect函数中也没给值,
但其返回的设备句柄在设备的句柄链表里。所以会调用mousedev驱动器的event函数既mousedev_event函数
“/input/input . c”
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
	struct input_handle *handle;

	if (type > EV_MAX || !test_bit(type, dev->evbit))
		return;

	add_input_randomness(type, code, value);
	switch (type) {

		case EV_SYN:
			switch (code) {
				case SYN_CONFIG:
					if (dev->event) dev->event(dev, type, code, value);
					break;
					...
					...
					...
			}
			break;
	}
	if (dev->grab)
		dev->grab->handler->event(dev->grab, type, code, value);
	else
		list_for_each_entry(handle, &dev->h_list, d_node)
			if (handle->open)
				handle->handler->event(handle, type, code, value);//见line 439
}

“/input/mousedev . c”
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
	struct mousedev *mousedev = handle->private;//在mousedev_connect中给handle的私有变量的mousedev指针
	
	switch (type) {
		....
	case EV_SYN:
		if (code == SYN_REPORT) {
			if (mousedev->touch) {
				mousedev->pkt_count++;
				/* Input system eats duplicate events, but we need all of them
				* to do correct averaging so apply present one forward
				*/
				fx(0) = fx(1);
				fy(0) = fy(1);
			}
			
			mousedev_notify_readers(mousedev, &mousedev->packet);//通知设备有数据到达读取
			
			mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
			mousedev->packet.abs_event = 0;
		}
		break;
	case EV_REL:
		mousedev_rel_event(mousedev, code, value);
		/****/
		break;
		....
	}
}
static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value)
{
	switch (code) {
	case REL_X:	mousedev->packet.dx += value; break;
	case REL_Y:	mousedev->packet.dy -= value; break;
	case REL_WHEEL:	mousedev->packet.dz -= value; break;
	}
}

读取鼠标位置时
同打开文件一样,读取file时会调用file的f_op函数集的函数,但此是f_op已经在打开时付值为驱动器的函数集指针了。
既mousedev_fops函数集,其中的read函数为mousedev_read,他在本设备等待有输入发生。
“/input/mousedev . c”
static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
{
	struct mousedev_list *list = file->private_data;
	int retval = 0;
	
	if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK))
		return -EAGAIN;
	
	retval = wait_event_interruptible(list->mousedev->wait,
		!list->mousedev->exist || list->ready || list->buffer);
	
	if (retval)
		return retval;
	
	if (!list->mousedev->exist)
		return -ENODEV;
	
	if (!list->buffer && list->ready) {
		mousedev_packet(list, list->ps2);
		list->buffer = list->bufsiz;
	}
	
	if (count > list->buffer)
		count = list->buffer;
	
	list->buffer -= count;
	
	if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count))
		return -EFAULT;
	
	return count;
}
通过mousedev->list遍历打开本设备的所有mousedev_list结构并对他们付值,mousedev_list结构是在打开设备时
链接进list的,而在打开此设备的文件描述符File中的privatedata指向些list指针。。。而后置
list->ready为真表有数据到达,再唤醒一个在本设备等待读数据的进程
“/input/mousedev . c”
static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet)
{
	struct mousedev_list *list;
	struct mousedev_motion *p;
	unsigned long flags;
	
	list_for_each_entry(list, &mousedev->list, node) {
		spin_lock_irqsave(&list->packet_lock, flags);
		
		p = &list->packets[list->head];
		if (list->ready && p->buttons != mousedev->packet.buttons) {
			unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
			if (new_head != list->tail) {
				p = &list->packets[list->head = new_head];
				memset(p, 0, sizeof(struct mousedev_motion));
			}
		}
		
		if (packet->abs_event) {
			p->dx += packet->x - list->pos_x;
			p->dy += packet->y - list->pos_y;
			list->pos_x = packet->x;
			list->pos_y = packet->y;
		}
		
		list->pos_x += packet->dx;
		list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x);
		list->pos_y += packet->dy;
		list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y);
		
		p->dx += packet->dx;
		p->dy += packet->dy;
		p->dz += packet->dz;
		p->buttons = mousedev->packet.buttons;
		
		if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons)
			list->ready = 1;
		
		spin_unlock_irqrestore(&list->packet_lock, flags);
		
		if (list->ready)
			kill_fasync(&list->fasync, SIGIO, POLL_IN);
	}
	
	wake_up_interruptible(&mousedev->wait);
}

⌨️ 快捷键说明

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