📄 psmouse-base.c
字号:
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); sprintf(psmouse->devname, "%s %s %s", psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name); psmouse->dev.name = psmouse->devname; psmouse->dev.phys = psmouse->phys; psmouse->dev.id.bustype = BUS_I8042; psmouse->dev.id.vendor = 0x0002; psmouse->dev.id.product = psmouse->type; psmouse->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; int retval; down(&psmouse_sem); /* * 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); } if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) { retval = -ENOMEM; goto out; } ps2_init(&psmouse->ps2dev, serio); sprintf(psmouse->phys, "%s/input0", serio->phys); psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); serio_set_drvdata(serio, psmouse); retval = serio_open(serio, drv); if (retval) { serio_set_drvdata(serio, NULL); kfree(psmouse); goto out; } if (psmouse_probe(psmouse) < 0) { serio_close(serio); serio_set_drvdata(serio, NULL); kfree(psmouse); retval = -ENODEV; goto out; } psmouse->rate = psmouse_rate; psmouse->resolution = psmouse_resolution; psmouse->resetafter = psmouse_resetafter; psmouse->smartscroll = psmouse_smartscroll; psmouse_switch_protocol(psmouse, NULL); input_register_device(&psmouse->dev); printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); psmouse_initialize(psmouse); if (parent && parent->pt_activate) parent->pt_activate(parent); device_create_file(&serio->dev, &psmouse_attr_protocol); device_create_file(&serio->dev, &psmouse_attr_rate); device_create_file(&serio->dev, &psmouse_attr_resolution); device_create_file(&serio->dev, &psmouse_attr_resetafter); psmouse_activate(psmouse); retval = 0;out: /* If this is a pass-through port the parent needs to be re-activated */ if (parent) psmouse_activate(parent); up(&psmouse_sem); 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; } down(&psmouse_sem); 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); up(&psmouse_sem); 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, char *buf, ssize_t (*handler)(struct psmouse *, char *)){ struct serio *serio = to_serio_port(dev); int retval; retval = serio_pin_driver(serio); if (retval) return retval; if (serio->drv != &psmouse_drv) { retval = -ENODEV; goto out; } retval = handler(serio_get_drvdata(serio), buf);out: serio_unpin_driver(serio); return retval;}ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t count, ssize_t (*handler)(struct psmouse *, const char *, size_t)){ struct serio *serio = to_serio_port(dev); struct psmouse *psmouse = serio_get_drvdata(serio); struct 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 = down_interruptible(&psmouse_sem); if (retval) goto out_unpin; if (psmouse->state == PSMOUSE_IGNORE) { retval = -ENODEV; goto out_up; } if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { parent = serio_get_drvdata(serio->parent); psmouse_deactivate(parent); } psmouse_deactivate(psmouse); retval = handler(psmouse, buf, count); if (retval != -ENODEV) psmouse_activate(psmouse); if (parent) psmouse_activate(parent); out_up: up(&psmouse_sem); out_unpin: serio_unpin_driver(serio); return retval;}static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, char *buf){ return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name);}static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *buf, size_t count){ struct serio *serio = psmouse->ps2dev.serio; struct psmouse *parent = NULL; struct psmouse_protocol *proto; int retry = 0; if (!(proto = psmouse_protocol_by_name(buf, count))) return -EINVAL; if (psmouse->type == proto->type) return count; while (serio->child) { if (++retry > 3) { printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n"); return -EIO; } up(&psmouse_sem); serio_unpin_driver(serio); serio_unregister_child_port(serio); serio_pin_driver_uninterruptible(serio); down(&psmouse_sem); if (serio->drv != &psmouse_drv) return -ENODEV; if (psmouse->type == proto->type) 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_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); printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); if (parent && parent->pt_activate) parent->pt_activate(parent); return count;}static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf){ return sprintf(buf, "%d\n", psmouse->rate);}static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, 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_show_resolution(struct psmouse *psmouse, char *buf){ return sprintf(buf, "%d\n", psmouse->resolution);}static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, 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 ssize_t psmouse_attr_show_resetafter(struct psmouse *psmouse, char *buf){ return sprintf(buf, "%d\n", psmouse->resetafter);}static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char *buf, size_t count){ unsigned long value; char *rest; value = simple_strtoul(buf, &rest, 10); if (*rest) return -EINVAL; psmouse->resetafter = value; return count;}static int psmouse_set_maxproto(const char *val, struct kernel_param *kp){ 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){ serio_register_driver(&psmouse_drv); return 0;}static void __exit psmouse_exit(void){ serio_unregister_driver(&psmouse_drv);}module_init(psmouse_init);module_exit(psmouse_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -