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

📄 psmouse-base.c

📁 Serial mouse driver for Linux
💻 C
📖 第 1 页 / 共 3 页
字号:
	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);	/* make sure we don't have a resync in progress */	mutex_unlock(&psmouse_mutex);	flush_workqueue(kpsmoused_wq);	mutex_lock(&psmouse_mutex);	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {		parent = serio_get_drvdata(serio->parent);		psmouse_deactivate(parent);	}	if (psmouse->disconnect)		psmouse->disconnect(psmouse);	if (parent && parent->pt_deactivate)		parent->pt_deactivate(parent);	psmouse_set_state(psmouse, PSMOUSE_IGNORE);	serio_close(serio);	serio_set_drvdata(serio, NULL);	input_unregister_device(psmouse->dev);	kfree(psmouse);	if (parent)		psmouse_activate(parent);	mutex_unlock(&psmouse_mutex);}static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse_protocol *proto){	struct input_dev *input_dev = psmouse->dev;	input_dev->private = psmouse;	input_dev->cdev.dev = &psmouse->ps2dev.serio->dev;	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);	input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);	input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);	psmouse->set_rate = psmouse_set_rate;	psmouse->set_resolution = psmouse_set_resolution;	psmouse->poll = psmouse_poll;	psmouse->protocol_handler = psmouse_process_byte;	psmouse->pktsize = 3;	if (proto && (proto->detect || proto->init)) {		if (proto->detect && proto->detect(psmouse, 1) < 0)			return -1;		if (proto->init && proto->init(psmouse) < 0)			return -1;		psmouse->type = proto->type;	}	else		psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);	/*	 * If mouse's packet size is 3 there is no point in polling the	 * device in hopes to detect protocol reset - we won't get less	 * than 3 bytes response anyhow.	 */	if (psmouse->pktsize == 3)		psmouse->resync_time = 0;	/*	 * Some smart KVMs fake response to POLL command returning just	 * 3 bytes and messing up our resync logic, so if initial poll	 * fails we won't try polling the device anymore. Hopefully	 * such KVM will maintain initially selected protocol.	 */	if (psmouse->resync_time && psmouse->poll(psmouse))		psmouse->resync_time = 0;	snprintf(psmouse->devname, sizeof(psmouse->devname), "%s %s %s",		 psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);	input_dev->name = psmouse->devname;	input_dev->phys = psmouse->phys;	input_dev->id.bustype = BUS_I8042;	input_dev->id.vendor = 0x0002;	input_dev->id.product = psmouse->type;	input_dev->id.version = psmouse->model;	return 0;}/* * psmouse_connect() is a callback from the serio module when * an unhandled serio port is found. */static int psmouse_connect(struct serio *serio, struct serio_driver *drv){	struct psmouse *psmouse, *parent = NULL;	struct input_dev *input_dev;	int retval = -ENOMEM;	mutex_lock(&psmouse_mutex);	/*	 * If this is a pass-through port deactivate parent so the device	 * connected to this port can be successfully identified	 */	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {		parent = serio_get_drvdata(serio->parent);		psmouse_deactivate(parent);	}	psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL);	input_dev = input_allocate_device();	if (!psmouse || !input_dev)		goto out;	ps2_init(&psmouse->ps2dev, serio);	INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse);	psmouse->dev = input_dev;	snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys);	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);	serio_set_drvdata(serio, psmouse);	retval = serio_open(serio, drv);	if (retval)		goto out;	if (psmouse_probe(psmouse) < 0) {		serio_close(serio);		retval = -ENODEV;		goto out;	}	psmouse->rate = psmouse_rate;	psmouse->resolution = psmouse_resolution;	psmouse->resetafter = psmouse_resetafter;	psmouse->resync_time = parent ? 0 : psmouse_resync_time;	psmouse->smartscroll = psmouse_smartscroll;	psmouse_switch_protocol(psmouse, NULL);	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);	psmouse_initialize(psmouse);	input_register_device(psmouse->dev);	if (parent && parent->pt_activate)		parent->pt_activate(parent);	sysfs_create_group(&serio->dev.kobj, &psmouse_attribute_group);	psmouse_activate(psmouse);	retval = 0;out:	if (retval) {		serio_set_drvdata(serio, NULL);		input_free_device(input_dev);		kfree(psmouse);	}	/* If this is a pass-through port the parent needs to be re-activated */	if (parent)		psmouse_activate(parent);	mutex_unlock(&psmouse_mutex);	return retval;}static int psmouse_reconnect(struct serio *serio){	struct psmouse *psmouse = serio_get_drvdata(serio);	struct psmouse *parent = NULL;	struct serio_driver *drv = serio->drv;	int rc = -1;	if (!drv || !psmouse) {		printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");		return -1;	}	mutex_lock(&psmouse_mutex);	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {		parent = serio_get_drvdata(serio->parent);		psmouse_deactivate(parent);	}	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);	if (psmouse->reconnect) {		if (psmouse->reconnect(psmouse))			goto out;	} else if (psmouse_probe(psmouse) < 0 ||		   psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0))		goto out;	/* ok, the device type (and capabilities) match the old one,	 * we can continue using it, complete intialization	 */	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);	psmouse_initialize(psmouse);	if (parent && parent->pt_activate)		parent->pt_activate(parent);	psmouse_activate(psmouse);	rc = 0;out:	/* If this is a pass-through port the parent waits to be activated */	if (parent)		psmouse_activate(parent);	mutex_unlock(&psmouse_mutex);	return rc;}static struct serio_device_id psmouse_serio_ids[] = {	{		.type	= SERIO_8042,		.proto	= SERIO_ANY,		.id	= SERIO_ANY,		.extra	= SERIO_ANY,	},	{		.type	= SERIO_PS_PSTHRU,		.proto	= SERIO_ANY,		.id	= SERIO_ANY,		.extra	= SERIO_ANY,	},	{ 0 }};MODULE_DEVICE_TABLE(serio, psmouse_serio_ids);static struct serio_driver psmouse_drv = {	.driver		= {		.name	= "psmouse",	},	.description	= DRIVER_DESC,	.id_table	= psmouse_serio_ids,	.interrupt	= psmouse_interrupt,	.connect	= psmouse_connect,	.reconnect	= psmouse_reconnect,	.disconnect	= psmouse_disconnect,	.cleanup	= psmouse_cleanup,};ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *devattr,				 char *buf){	struct serio *serio = to_serio_port(dev);	struct psmouse_attribute *attr = to_psmouse_attr(devattr);	struct psmouse *psmouse;	int retval;	retval = serio_pin_driver(serio);	if (retval)		return retval;	if (serio->drv != &psmouse_drv) {		retval = -ENODEV;		goto out;	}	psmouse = serio_get_drvdata(serio);	retval = attr->show(psmouse, attr->data, buf);out:	serio_unpin_driver(serio);	return retval;}ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *devattr,				const char *buf, size_t count){	struct serio *serio = to_serio_port(dev);	struct psmouse_attribute *attr = to_psmouse_attr(devattr);	struct psmouse *psmouse, *parent = NULL;	int retval;	retval = serio_pin_driver(serio);	if (retval)		return retval;	if (serio->drv != &psmouse_drv) {		retval = -ENODEV;		goto out_unpin;	}	retval = mutex_lock_interruptible(&psmouse_mutex);	if (retval)		goto out_unpin;	psmouse = serio_get_drvdata(serio);	if (psmouse->state == PSMOUSE_IGNORE) {		retval = -ENODEV;		goto out_unlock;	}	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {		parent = serio_get_drvdata(serio->parent);		psmouse_deactivate(parent);	}	psmouse_deactivate(psmouse);	retval = attr->set(psmouse, attr->data, buf, count);	if (retval != -ENODEV)		psmouse_activate(psmouse);	if (parent)		psmouse_activate(parent); out_unlock:	mutex_unlock(&psmouse_mutex); out_unpin:	serio_unpin_driver(serio);	return retval;}static ssize_t psmouse_show_int_attr(struct psmouse *psmouse, void *offset, char *buf){	unsigned long *field = (unsigned long *)((char *)psmouse + (size_t)offset);	return sprintf(buf, "%lu\n", *field);}static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const char *buf, size_t count){	unsigned long *field = (unsigned long *)((char *)psmouse + (size_t)offset);	unsigned long value;	char *rest;	value = simple_strtoul(buf, &rest, 10);	if (*rest)		return -EINVAL;	*field = value;	return count;}static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, void *data, char *buf){	return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name);}static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, const char *buf, size_t count){	struct serio *serio = psmouse->ps2dev.serio;	struct psmouse *parent = NULL;	struct input_dev *new_dev;	const struct psmouse_protocol *proto;	int retry = 0;	if (!(proto = psmouse_protocol_by_name(buf, count)))		return -EINVAL;	if (psmouse->type == proto->type)		return count;	if (!(new_dev = input_allocate_device()))		return -ENOMEM;	while (serio->child) {		if (++retry > 3) {			printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n");			input_free_device(new_dev);			return -EIO;		}		mutex_unlock(&psmouse_mutex);		serio_unpin_driver(serio);		serio_unregister_child_port(serio);		serio_pin_driver_uninterruptible(serio);		mutex_lock(&psmouse_mutex);		if (serio->drv != &psmouse_drv) {			input_free_device(new_dev);			return -ENODEV;		}		if (psmouse->type == proto->type) {			input_free_device(new_dev);			return count; /* switched by other thread */		}	}	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {		parent = serio_get_drvdata(serio->parent);		if (parent->pt_deactivate)			parent->pt_deactivate(parent);	}	if (psmouse->disconnect)		psmouse->disconnect(psmouse);	psmouse_set_state(psmouse, PSMOUSE_IGNORE);	input_unregister_device(psmouse->dev);	psmouse->dev = new_dev;	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);	if (psmouse_switch_protocol(psmouse, proto) < 0) {		psmouse_reset(psmouse);		/* default to PSMOUSE_PS2 */		psmouse_switch_protocol(psmouse, &psmouse_protocols[0]);	}	psmouse_initialize(psmouse);	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);	input_register_device(psmouse->dev);	if (parent && parent->pt_activate)		parent->pt_activate(parent);	return count;}static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const char *buf, size_t count){	unsigned long value;	char *rest;	value = simple_strtoul(buf, &rest, 10);	if (*rest)		return -EINVAL;	psmouse->set_rate(psmouse, value);	return count;}static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, const char *buf, size_t count){	unsigned long value;	char *rest;	value = simple_strtoul(buf, &rest, 10);	if (*rest)		return -EINVAL;	psmouse->set_resolution(psmouse, value);	return count;}static int psmouse_set_maxproto(const char *val, struct kernel_param *kp){	const struct psmouse_protocol *proto;	if (!val)		return -EINVAL;	proto = psmouse_protocol_by_name(val, strlen(val));	if (!proto || !proto->maxproto)		return -EINVAL;	*((unsigned int *)kp->arg) = proto->type;	return 0;}static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp){	int type = *((unsigned int *)kp->arg);	return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);}static int __init psmouse_init(void){	kpsmoused_wq = create_singlethread_workqueue("kpsmoused");	if (!kpsmoused_wq) {		printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n");		return -ENOMEM;	}	serio_register_driver(&psmouse_drv);	return 0;}static void __exit psmouse_exit(void){	serio_unregister_driver(&psmouse_drv);	destroy_workqueue(kpsmoused_wq);}module_init(psmouse_init);module_exit(psmouse_exit);

⌨️ 快捷键说明

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