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 + -
显示快捷键?