X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Finput%2Fmousedev.c;h=664bcc8116fc7676d159b2e035015f212ad5f357;hb=refs%2Fheads%2Fvserver;hp=bd1a6d98bde572fd939bdefb0c58751c54550c02;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index bd1a6d98b..664bcc811 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -9,7 +9,7 @@ * the Free Software Foundation. */ -#define MOUSEDEV_MINOR_BASE 32 +#define MOUSEDEV_MINOR_BASE 32 #define MOUSEDEV_MINORS 32 #define MOUSEDEV_MIX 31 @@ -19,12 +19,10 @@ #include #include #include -#include #include #include #include #include -#include #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX #include #endif @@ -41,15 +39,15 @@ MODULE_LICENSE("GPL"); #endif static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X; -module_param(xres, uint, 0); +module_param(xres, uint, 0644); MODULE_PARM_DESC(xres, "Horizontal screen resolution"); static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; -module_param(yres, uint, 0); +module_param(yres, uint, 0644); MODULE_PARM_DESC(yres, "Vertical screen resolution"); static unsigned tap_time = 200; -module_param(tap_time, uint, 0); +module_param(tap_time, uint, 0644); MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)"); struct mousedev_hw_data { @@ -71,6 +69,7 @@ struct mousedev { struct mousedev_hw_data packet; unsigned int pkt_count; int old_x[4], old_y[4]; + int frac_dx, frac_dy; unsigned long touch; }; @@ -100,6 +99,7 @@ struct mousedev_list { unsigned char ready, buffer, bufsiz; unsigned char imexseq, impsseq; enum mousedev_emul mode; + unsigned long last_buttons; }; #define MOUSEDEV_SEQ_LEN 6 @@ -115,20 +115,35 @@ static struct mousedev mousedev_mix; #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) -static void mousedev_touchpad_event(struct mousedev *mousedev, unsigned int code, int value) +static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value) { + int size, tmp; + enum { FRACTION_DENOM = 128 }; + if (mousedev->touch) { + size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; + if (size == 0) + size = 256 * 2; + switch (code) { case ABS_X: fx(0) = value; - if (mousedev->pkt_count >= 2) - mousedev->packet.dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8; + if (mousedev->pkt_count >= 2) { + tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size; + tmp += mousedev->frac_dx; + mousedev->packet.dx = tmp / FRACTION_DENOM; + mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM; + } break; case ABS_Y: fy(0) = value; - if (mousedev->pkt_count >= 2) - mousedev->packet.dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8; + if (mousedev->pkt_count >= 2) { + tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size; + tmp += mousedev->frac_dy; + mousedev->packet.dy = tmp / FRACTION_DENOM; + mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM; + } break; } } @@ -141,18 +156,24 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, switch (code) { case ABS_X: size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; - if (size == 0) size = xres; - if (value > dev->absmax[ABS_X]) value = dev->absmax[ABS_X]; - if (value < dev->absmin[ABS_X]) value = dev->absmin[ABS_X]; + if (size == 0) + size = xres ? : 1; + if (value > dev->absmax[ABS_X]) + value = dev->absmax[ABS_X]; + if (value < dev->absmin[ABS_X]) + value = dev->absmin[ABS_X]; mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size; mousedev->packet.abs_event = 1; break; case ABS_Y: size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; - if (size == 0) size = yres; - if (value > dev->absmax[ABS_Y]) value = dev->absmax[ABS_Y]; - if (value < dev->absmin[ABS_Y]) value = dev->absmin[ABS_Y]; + if (size == 0) + size = yres ? : 1; + if (value > dev->absmax[ABS_Y]) + value = dev->absmax[ABS_Y]; + if (value < dev->absmin[ABS_Y]) + value = dev->absmin[ABS_Y]; mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size; mousedev->packet.abs_event = 1; break; @@ -175,12 +196,12 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int switch (code) { case BTN_TOUCH: case BTN_0: - case BTN_FORWARD: case BTN_LEFT: index = 0; break; case BTN_STYLUS: case BTN_1: case BTN_RIGHT: index = 1; break; case BTN_2: + case BTN_FORWARD: case BTN_STYLUS2: case BTN_MIDDLE: index = 2; break; case BTN_3: @@ -188,7 +209,7 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int case BTN_SIDE: index = 3; break; case BTN_4: case BTN_EXTRA: index = 4; break; - default: return; + default: return; } if (value) { @@ -205,12 +226,13 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h struct mousedev_list *list; struct mousedev_motion *p; unsigned long flags; + int wake_readers = 0; list_for_each_entry(list, &mousedev->list, node) { spin_lock_irqsave(&list->packet_lock, flags); p = &list->packets[list->head]; - if (list->ready && p->buttons != packet->buttons) { + if (list->ready && p->buttons != mousedev->packet.buttons) { unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN; if (new_head != list->tail) { p = &list->packets[list->head = new_head]; @@ -235,13 +257,19 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h p->dz += packet->dz; p->buttons = mousedev->packet.buttons; - list->ready = 1; + if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons) + list->ready = 1; spin_unlock_irqrestore(&list->packet_lock, flags); - kill_fasync(&list->fasync, SIGIO, POLL_IN); + + if (list->ready) { + kill_fasync(&list->fasync, SIGIO, POLL_IN); + wake_readers = 1; + } } - wake_up_interruptible(&mousedev->wait); + if (wake_readers) + wake_up_interruptible(&mousedev->wait); } static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) @@ -262,10 +290,11 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) clear_bit(0, &mousedev_mix.packet.buttons); } mousedev->touch = mousedev->pkt_count = 0; - } - else - if (!mousedev->touch) - mousedev->touch = jiffies; + mousedev->frac_dx = 0; + mousedev->frac_dy = 0; + + } else if (!mousedev->touch) + mousedev->touch = jiffies; } static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) @@ -279,7 +308,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig return; if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) - mousedev_touchpad_event(mousedev, code, value); + mousedev_touchpad_event(handle->dev, mousedev, code, value); else mousedev_abs_event(handle->dev, mousedev, code, value); @@ -304,7 +333,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig mousedev->pkt_count++; /* Input system eats duplicate events, but we need all of them * to do correct averaging so apply present one forward - */ + */ fx(0) = fx(1); fy(0) = fy(1); } @@ -323,19 +352,19 @@ static int mousedev_fasync(int fd, struct file *file, int on) { int retval; struct mousedev_list *list = file->private_data; + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; } static void mousedev_free(struct mousedev *mousedev) { - devfs_remove("input/mouse%d", mousedev->minor); - class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); mousedev_table[mousedev->minor] = NULL; kfree(mousedev); } -static int mixdev_release(void) +static void mixdev_release(void) { struct input_handle *handle; @@ -349,8 +378,6 @@ static int mixdev_release(void) mousedev_free(mousedev); } } - - return 0; } static int mousedev_release(struct inode * inode, struct file * file) @@ -363,9 +390,8 @@ static int mousedev_release(struct inode * inode, struct file * file) if (!--list->mousedev->open) { if (list->mousedev->minor == MOUSEDEV_MIX) - return mixdev_release(); - - if (!mousedev_mix.open) { + mixdev_release(); + else if (!mousedev_mix.open) { if (list->mousedev->exist) input_close_device(&list->mousedev->handle); else @@ -394,9 +420,8 @@ static int mousedev_open(struct inode * inode, struct file * file) if (i >= MOUSEDEV_MINORS || !mousedev_table[i]) return -ENODEV; - if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL))) + if (!(list = kzalloc(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; @@ -441,7 +466,7 @@ static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data) switch (list->mode) { case MOUSEDEV_EMUL_EXPS: - ps2_data[3] = mousedev_limit_delta(p->dz, 127); + ps2_data[3] = mousedev_limit_delta(p->dz, 7); p->dz -= ps2_data[3]; ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); list->bufsiz = 4; @@ -463,10 +488,11 @@ static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data) } 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) + if (list->tail == list->head) { list->ready = 0; + list->last_buttons = p->buttons; + } else + list->tail = (list->tail + 1) % PACKET_QUEUE_LEN; } spin_unlock_irqrestore(&list->packet_lock, flags); @@ -489,14 +515,16 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si list->imexseq = 0; list->mode = MOUSEDEV_EMUL_EXPS; } - } else list->imexseq = 0; + } 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; + } else + list->impsseq = 0; list->ps2[0] = 0xfa; @@ -580,13 +608,13 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co 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; + return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) | + (list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); } -struct file_operations mousedev_fops = { +static const struct file_operations mousedev_fops = { .owner = THIS_MODULE, .read = mousedev_read, .write = mousedev_write, @@ -596,9 +624,11 @@ struct file_operations mousedev_fops = { .fasync = mousedev_fasync, }; -static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) +static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct mousedev *mousedev; + struct class_device *cdev; int minor = 0; for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); @@ -607,9 +637,8 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru return NULL; } - if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL))) + if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL))) return NULL; - memset(mousedev, 0, sizeof(struct mousedev)); INIT_LIST_HEAD(&mousedev->list); init_waitqueue_head(&mousedev->wait); @@ -627,11 +656,13 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru 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); + cdev = class_device_create(&input_class, &dev->cdev, + MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor), + dev->cdev.dev, mousedev->name); + + /* temporary symlink to keep userspace happy */ + sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, + mousedev->name); return &mousedev->handle; } @@ -639,11 +670,18 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru static void mousedev_disconnect(struct input_handle *handle) { struct mousedev *mousedev = handle->private; + struct mousedev_list *list; + sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name); + class_device_destroy(&input_class, + MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor)); mousedev->exist = 0; if (mousedev->open) { input_close_device(handle); + wake_up_interruptible(&mousedev->wait); + list_for_each_entry(list, &mousedev->list, node) + kill_fasync(&list->fasync, SIGIO, POLL_HUP); } else { if (mousedev_mix.open) input_close_device(handle); @@ -651,7 +689,7 @@ static void mousedev_disconnect(struct input_handle *handle) } } -static struct input_device_id mousedev_ids[] = { +static const 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) }, @@ -700,7 +738,12 @@ static int psaux_registered; static int __init mousedev_init(void) { - input_register_handler(&mousedev_handler); + struct class_device *cdev; + int error; + + error = input_register_handler(&mousedev_handler); + if (error) + return error; memset(&mousedev_mix, 0, sizeof(struct mousedev)); INIT_LIST_HEAD(&mousedev_mix.list); @@ -709,14 +752,20 @@ static int __init mousedev_init(void) 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"); + cdev = class_device_create(&input_class, NULL, + MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); + if (IS_ERR(cdev)) { + input_unregister_handler(&mousedev_handler); + return PTR_ERR(cdev); + } #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX - if (!(psaux_registered = !misc_register(&psaux_mouse))) - printk(KERN_WARNING "mice: could not misc_register the device\n"); + error = misc_register(&psaux_mouse); + if (error) + printk(KERN_WARNING "mice: could not register psaux device, " + "error: %d\n", error); + else + psaux_registered = 1; #endif printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); @@ -730,8 +779,8 @@ static void __exit mousedev_exit(void) if (psaux_registered) misc_deregister(&psaux_mouse); #endif - devfs_remove("input/mice"); - class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX)); + class_device_destroy(&input_class, + MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX)); input_unregister_handler(&mousedev_handler); }