mousedev.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 740 行 · 第 1/2 页

C
740
字号
			else				mousedev_free(list->mousedev);		}	}	kfree(list);	return 0;}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;}static inline int mousedev_limit_delta(int delta, int limit){	return delta > limit ? limit : (delta < -limit ? -limit : delta);}static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data){	struct mousedev_motion *p;	unsigned long flags;	spin_lock_irqsave(&list->packet_lock, flags);	p = &list->packets[list->tail];	ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);	ps2_data[1] = mousedev_limit_delta(p->dx, 127);	ps2_data[2] = mousedev_limit_delta(p->dy, 127);	p->dx -= ps2_data[1];	p->dy -= ps2_data[2];	switch (list->mode) {		case MOUSEDEV_EMUL_EXPS:			ps2_data[3] = mousedev_limit_delta(p->dz, 127);			p->dz -= ps2_data[3];			ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);			list->bufsiz = 4;			break;		case MOUSEDEV_EMUL_IMPS:			ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);			ps2_data[3] = mousedev_limit_delta(p->dz, 127);			p->dz -= ps2_data[3];			list->bufsiz = 4;			break;		case MOUSEDEV_EMUL_PS2:		default:			ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);			p->dz = 0;			list->bufsiz = 3;			break;	}	if (!p->dx && !p->dy && !p->dz) {		if (list->tail != list->head)			list->tail = (list->tail + 1) % PACKET_QUEUE_LEN;		if (list->tail == list->head)			list->ready = 0;	}	spin_unlock_irqrestore(&list->packet_lock, flags);}static ssize_t mousedev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos){	struct mousedev_list *list = file->private_data;	unsigned char c;	unsigned int i;	for (i = 0; i < count; i++) {		if (get_user(c, buffer + i))			return -EFAULT;		if (c == mousedev_imex_seq[list->imexseq]) {			if (++list->imexseq == MOUSEDEV_SEQ_LEN) {				list->imexseq = 0;				list->mode = MOUSEDEV_EMUL_EXPS;			}		} else list->imexseq = 0;		if (c == mousedev_imps_seq[list->impsseq]) {			if (++list->impsseq == MOUSEDEV_SEQ_LEN) {				list->impsseq = 0;				list->mode = MOUSEDEV_EMUL_IMPS;			}		} else list->impsseq = 0;		list->ps2[0] = 0xfa;		switch (c) {			case 0xeb: /* Poll */				mousedev_packet(list, &list->ps2[1]);				list->bufsiz++; /* account for leading ACK */				break;			case 0xf2: /* Get ID */				switch (list->mode) {					case MOUSEDEV_EMUL_PS2:  list->ps2[1] = 0; break;					case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break;					case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break;				}				list->bufsiz = 2;				break;			case 0xe9: /* Get info */				list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200;				list->bufsiz = 4;				break;			case 0xff: /* Reset */				list->impsseq = list->imexseq = 0;				list->mode = MOUSEDEV_EMUL_PS2;				list->ps2[1] = 0xaa; list->ps2[2] = 0x00;				list->bufsiz = 3;				break;			default:				list->bufsiz = 1;				break;		}		list->buffer = list->bufsiz;	}	kill_fasync(&list->fasync, SIGIO, POLL_IN);	wake_up_interruptible(&list->mousedev->wait);	return count;}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;}/* No kernel lock - fine */static unsigned int mousedev_poll(struct file *file, poll_table *wait){	struct mousedev_list *list = file->private_data;	poll_wait(file, &list->mousedev->wait, wait);	if (list->ready || list->buffer)		return POLLIN | POLLRDNORM;	return 0;}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,};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_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;}static void mousedev_disconnect(struct input_handle *handle){	struct mousedev *mousedev = handle->private;	mousedev->exist = 0;	if (mousedev->open) {		input_close_device(handle);	} else {		if (mousedev_mix.open)			input_close_device(handle);		mousedev_free(mousedev);	}}static struct input_device_id mousedev_ids[] = {	{		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,		.evbit = { BIT(EV_KEY) | BIT(EV_REL) },		.keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },		.relbit = { BIT(REL_X) | BIT(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(EV_KEY) | BIT(EV_REL) },		.relbit = { BIT(REL_WHEEL) },	},	/* A separate scrollwheel */	{		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,		.evbit = { BIT(EV_KEY) | BIT(EV_ABS) },		.keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },		.absbit = { BIT(ABS_X) | BIT(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(EV_KEY) | BIT(EV_ABS) },		.keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) },		.absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) },	},	/* A touchpad */	{ }, 	/* Terminating entry */};MODULE_DEVICE_TABLE(input, mousedev_ids);static struct input_handler mousedev_handler = {	.event =	mousedev_event,	.connect =	mousedev_connect,	.disconnect =	mousedev_disconnect,	.fops =		&mousedev_fops,	.minor =	MOUSEDEV_MINOR_BASE,	.name =		"mousedev",	.id_table =	mousedev_ids,};#ifdef CONFIG_INPUT_MOUSEDEV_PSAUXstatic struct miscdevice psaux_mouse = {	PSMOUSE_MINOR, "psaux", &mousedev_fops};static int psaux_registered;#endifstatic 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;	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");	class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX),				NULL, "mice");#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX	if (!(psaux_registered = !misc_register(&psaux_mouse)))		printk(KERN_WARNING "mice: could not misc_register the device\n");#endif	printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");	return 0;}static void __exit mousedev_exit(void){#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX	if (psaux_registered)		misc_deregister(&psaux_mouse);#endif	devfs_remove("input/mice");	class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX));	input_unregister_handler(&mousedev_handler);}module_init(mousedev_init);module_exit(mousedev_exit);

⌨️ 快捷键说明

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