?? psmouse-base.c
字號:
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 + -