diff options
| author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-02 11:20:33 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-02 11:20:33 -0400 |
| commit | a12f66fccf2e266ad197df142b5ebafc6a169a8c (patch) | |
| tree | 9d0bc76f8aa9c42fb44ce5f5bf6b4b09f4efafed /drivers/input | |
| parent | 12dce6263d43daeb4e16fa4eb964c1c99fa4fa2e (diff) | |
| parent | bb0885900de49b5822d7e8c91c1adf9a0fcc228b (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (35 commits)
Input: wistron - add support for Acer TravelMate 2424NWXCi
Input: wistron - fix setting up special buttons
Input: add KEY_BLUETOOTH and KEY_WLAN definitions
Input: add new BUS_VIRTUAL bus type
Input: add driver for stowaway serial keyboards
Input: make input_register_handler() return error codes
Input: remove cruft that was needed for transition to sysfs
Input: fix input module refcounting
Input: constify input core
Input: libps2 - rearrange exports
Input: atkbd - support Microsoft Natural Elite Pro keyboards
Input: i8042 - disable MUX mode on Toshiba Equium A110
Input: i8042 - get rid of polling timer
Input: send key up events at disconnect
Input: constify psmouse driver
Input: i8042 - add Amoi to the MUX blacklist
Input: logips2pp - add sugnature 56 (Cordless MouseMan Wheel), cleanup
Input: add driver for Touchwin serial touchscreens
Input: add driver for Touchright serial touchscreens
Input: add driver for Penmount serial touchscreens
...
Diffstat (limited to 'drivers/input')
39 files changed, 2716 insertions, 789 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 58223b5d84..96232313b1 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig | |||
| @@ -24,6 +24,20 @@ config INPUT | |||
| 24 | 24 | ||
| 25 | if INPUT | 25 | if INPUT |
| 26 | 26 | ||
| 27 | config INPUT_FF_MEMLESS | ||
| 28 | tristate "Support for memoryless force-feedback devices" | ||
| 29 | default n | ||
| 30 | ---help--- | ||
| 31 | Say Y here if you have memoryless force-feedback input device | ||
| 32 | such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual | ||
| 33 | Power 2, or similar. You will also need to enable hardware-specific | ||
| 34 | driver. | ||
| 35 | |||
| 36 | If unsure, say N. | ||
| 37 | |||
| 38 | To compile this driver as a module, choose M here: the | ||
| 39 | module will be called ff-memless. | ||
| 40 | |||
| 27 | comment "Userland interfaces" | 41 | comment "Userland interfaces" |
| 28 | 42 | ||
| 29 | config INPUT_MOUSEDEV | 43 | config INPUT_MOUSEDEV |
diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 1a6ff4982f..a005b1df5f 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile | |||
| @@ -4,7 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | # Each configuration option enables a list of files. | 5 | # Each configuration option enables a list of files. |
| 6 | 6 | ||
| 7 | obj-$(CONFIG_INPUT) += input.o | 7 | obj-$(CONFIG_INPUT) += input-core.o |
| 8 | input-core-objs := input.o ff-core.o | ||
| 9 | |||
| 10 | obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o | ||
| 11 | |||
| 8 | obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o | 12 | obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o |
| 9 | obj-$(CONFIG_INPUT_JOYDEV) += joydev.o | 13 | obj-$(CONFIG_INPUT_JOYDEV) += joydev.o |
| 10 | obj-$(CONFIG_INPUT_EVDEV) += evdev.o | 14 | obj-$(CONFIG_INPUT_EVDEV) += evdev.o |
diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c index 07358fb51b..5a9653c312 100644 --- a/drivers/input/evbug.c +++ b/drivers/input/evbug.c | |||
| @@ -42,10 +42,12 @@ static char evbug_name[] = "evbug"; | |||
| 42 | 42 | ||
| 43 | static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | 43 | static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) |
| 44 | { | 44 | { |
| 45 | printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value); | 45 | printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", |
| 46 | handle->dev->phys, type, code, value); | ||
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | 49 | static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, |
| 50 | const struct input_device_id *id) | ||
| 49 | { | 51 | { |
| 50 | struct input_handle *handle; | 52 | struct input_handle *handle; |
| 51 | 53 | ||
| @@ -72,7 +74,7 @@ static void evbug_disconnect(struct input_handle *handle) | |||
| 72 | kfree(handle); | 74 | kfree(handle); |
| 73 | } | 75 | } |
| 74 | 76 | ||
| 75 | static struct input_device_id evbug_ids[] = { | 77 | static const struct input_device_id evbug_ids[] = { |
| 76 | { .driver_info = 1 }, /* Matches all devices */ | 78 | { .driver_info = 1 }, /* Matches all devices */ |
| 77 | { }, /* Terminating zero entry */ | 79 | { }, /* Terminating zero entry */ |
| 78 | }; | 80 | }; |
| @@ -89,8 +91,7 @@ static struct input_handler evbug_handler = { | |||
| 89 | 91 | ||
| 90 | static int __init evbug_init(void) | 92 | static int __init evbug_init(void) |
| 91 | { | 93 | { |
| 92 | input_register_handler(&evbug_handler); | 94 | return input_register_handler(&evbug_handler); |
| 93 | return 0; | ||
| 94 | } | 95 | } |
| 95 | 96 | ||
| 96 | static void __exit evbug_exit(void) | 97 | static void __exit evbug_exit(void) |
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 4bf48188cc..6439f378f6 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
| @@ -391,8 +391,10 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, | |||
| 391 | struct evdev *evdev = list->evdev; | 391 | struct evdev *evdev = list->evdev; |
| 392 | struct input_dev *dev = evdev->handle.dev; | 392 | struct input_dev *dev = evdev->handle.dev; |
| 393 | struct input_absinfo abs; | 393 | struct input_absinfo abs; |
| 394 | struct ff_effect effect; | ||
| 394 | int __user *ip = (int __user *)p; | 395 | int __user *ip = (int __user *)p; |
| 395 | int i, t, u, v; | 396 | int i, t, u, v; |
| 397 | int error; | ||
| 396 | 398 | ||
| 397 | if (!evdev->exist) | 399 | if (!evdev->exist) |
| 398 | return -ENODEV; | 400 | return -ENODEV; |
| @@ -460,27 +462,22 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, | |||
| 460 | return 0; | 462 | return 0; |
| 461 | 463 | ||
| 462 | case EVIOCSFF: | 464 | case EVIOCSFF: |
| 463 | if (dev->upload_effect) { | 465 | if (copy_from_user(&effect, p, sizeof(effect))) |
| 464 | struct ff_effect effect; | 466 | return -EFAULT; |
| 465 | int err; | ||
| 466 | |||
| 467 | if (copy_from_user(&effect, p, sizeof(effect))) | ||
| 468 | return -EFAULT; | ||
| 469 | err = dev->upload_effect(dev, &effect); | ||
| 470 | if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) | ||
| 471 | return -EFAULT; | ||
| 472 | return err; | ||
| 473 | } else | ||
| 474 | return -ENOSYS; | ||
| 475 | 467 | ||
| 476 | case EVIOCRMFF: | 468 | error = input_ff_upload(dev, &effect, file); |
| 477 | if (!dev->erase_effect) | ||
| 478 | return -ENOSYS; | ||
| 479 | 469 | ||
| 480 | return dev->erase_effect(dev, (int)(unsigned long) p); | 470 | if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) |
| 471 | return -EFAULT; | ||
| 472 | |||
| 473 | return error; | ||
| 474 | |||
| 475 | case EVIOCRMFF: | ||
| 476 | return input_ff_erase(dev, (int)(unsigned long) p, file); | ||
| 481 | 477 | ||
| 482 | case EVIOCGEFFECTS: | 478 | case EVIOCGEFFECTS: |
| 483 | if (put_user(dev->ff_effects_max, ip)) | 479 | i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0; |
| 480 | if (put_user(i, ip)) | ||
| 484 | return -EFAULT; | 481 | return -EFAULT; |
| 485 | return 0; | 482 | return 0; |
| 486 | 483 | ||
| @@ -604,7 +601,7 @@ static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned lon | |||
| 604 | } | 601 | } |
| 605 | #endif | 602 | #endif |
| 606 | 603 | ||
| 607 | static struct file_operations evdev_fops = { | 604 | static const struct file_operations evdev_fops = { |
| 608 | .owner = THIS_MODULE, | 605 | .owner = THIS_MODULE, |
| 609 | .read = evdev_read, | 606 | .read = evdev_read, |
| 610 | .write = evdev_write, | 607 | .write = evdev_write, |
| @@ -619,7 +616,8 @@ static struct file_operations evdev_fops = { | |||
| 619 | .flush = evdev_flush | 616 | .flush = evdev_flush |
| 620 | }; | 617 | }; |
| 621 | 618 | ||
| 622 | static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | 619 | static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, |
| 620 | const struct input_device_id *id) | ||
| 623 | { | 621 | { |
| 624 | struct evdev *evdev; | 622 | struct evdev *evdev; |
| 625 | struct class_device *cdev; | 623 | struct class_device *cdev; |
| @@ -669,6 +667,7 @@ static void evdev_disconnect(struct input_handle *handle) | |||
| 669 | evdev->exist = 0; | 667 | evdev->exist = 0; |
| 670 | 668 | ||
| 671 | if (evdev->open) { | 669 | if (evdev->open) { |
| 670 | input_flush_device(handle, NULL); | ||
| 672 | input_close_device(handle); | 671 | input_close_device(handle); |
| 673 | wake_up_interruptible(&evdev->wait); | 672 | wake_up_interruptible(&evdev->wait); |
| 674 | list_for_each_entry(list, &evdev->list, node) | 673 | list_for_each_entry(list, &evdev->list, node) |
| @@ -677,7 +676,7 @@ static void evdev_disconnect(struct input_handle *handle) | |||
| 677 | evdev_free(evdev); | 676 | evdev_free(evdev); |
| 678 | } | 677 | } |
| 679 | 678 | ||
| 680 | static struct input_device_id evdev_ids[] = { | 679 | static const struct input_device_id evdev_ids[] = { |
| 681 | { .driver_info = 1 }, /* Matches all devices */ | 680 | { .driver_info = 1 }, /* Matches all devices */ |
| 682 | { }, /* Terminating zero entry */ | 681 | { }, /* Terminating zero entry */ |
| 683 | }; | 682 | }; |
| @@ -696,8 +695,7 @@ static struct input_handler evdev_handler = { | |||
| 696 | 695 | ||
| 697 | static int __init evdev_init(void) | 696 | static int __init evdev_init(void) |
| 698 | { | 697 | { |
| 699 | input_register_handler(&evdev_handler); | 698 | return input_register_handler(&evdev_handler); |
| 700 | return 0; | ||
| 701 | } | 699 | } |
| 702 | 700 | ||
| 703 | static void __exit evdev_exit(void) | 701 | static void __exit evdev_exit(void) |
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c new file mode 100644 index 0000000000..35656cadc9 --- /dev/null +++ b/drivers/input/ff-core.c | |||
| @@ -0,0 +1,367 @@ | |||
| 1 | /* | ||
| 2 | * Force feedback support for Linux input subsystem | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.com> | ||
| 5 | * Copyright (c) 2006 Dmitry Torokhov <dtor@mail.ru> | ||
| 6 | */ | ||
| 7 | |||
| 8 | /* | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | */ | ||
| 23 | |||
| 24 | /* #define DEBUG */ | ||
| 25 | |||
| 26 | #define debug(format, arg...) pr_debug("ff-core: " format "\n", ## arg) | ||
| 27 | |||
| 28 | #include <linux/input.h> | ||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/mutex.h> | ||
| 31 | |||
| 32 | /* | ||
| 33 | * Check that the effect_id is a valid effect and whether the user | ||
| 34 | * is the owner | ||
| 35 | */ | ||
| 36 | static int check_effect_access(struct ff_device *ff, int effect_id, | ||
| 37 | struct file *file) | ||
| 38 | { | ||
| 39 | if (effect_id < 0 || effect_id >= ff->max_effects || | ||
| 40 | !ff->effect_owners[effect_id]) | ||
| 41 | return -EINVAL; | ||
| 42 | |||
| 43 | if (file && ff->effect_owners[effect_id] != file) | ||
| 44 | return -EACCES; | ||
| 45 | |||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | |||
| 49 | /* | ||
| 50 | * Checks whether 2 effects can be combined together | ||
| 51 | */ | ||
| 52 | static inline int check_effects_compatible(struct ff_effect *e1, | ||
| 53 | struct ff_effect *e2) | ||
| 54 | { | ||
| 55 | return e1->type == e2->type && | ||
| 56 | (e1->type != FF_PERIODIC || | ||
| 57 | e1->u.periodic.waveform == e2->u.periodic.waveform); | ||
| 58 | } | ||
| 59 | |||
| 60 | /* | ||
| 61 | * Convert an effect into compatible one | ||
| 62 | */ | ||
| 63 | static int compat_effect(struct ff_device *ff, struct ff_effect *effect) | ||
| 64 | { | ||
| 65 | int magnitude; | ||
| 66 | |||
| 67 | switch (effect->type) { | ||
| 68 | case FF_RUMBLE: | ||
| 69 | if (!test_bit(FF_PERIODIC, ff->ffbit)) | ||
| 70 | return -EINVAL; | ||
| 71 | |||
| 72 | /* | ||
| 73 | * calculate manginude of sine wave as average of rumble's | ||
| 74 | * 2/3 of strong magnitude and 1/3 of weak magnitude | ||
| 75 | */ | ||
| 76 | magnitude = effect->u.rumble.strong_magnitude / 3 + | ||
| 77 | effect->u.rumble.weak_magnitude / 6; | ||
| 78 | |||
| 79 | effect->type = FF_PERIODIC; | ||
| 80 | effect->u.periodic.waveform = FF_SINE; | ||
| 81 | effect->u.periodic.period = 50; | ||
| 82 | effect->u.periodic.magnitude = max(magnitude, 0x7fff); | ||
| 83 | effect->u.periodic.offset = 0; | ||
| 84 | effect->u.periodic.phase = 0; | ||
| 85 | effect->u.periodic.envelope.attack_length = 0; | ||
| 86 | effect->u.periodic.envelope.attack_level = 0; | ||
| 87 | effect->u.periodic.envelope.fade_length = 0; | ||
| 88 | effect->u.periodic.envelope.fade_level = 0; | ||
| 89 | |||
| 90 | return 0; | ||
| 91 | |||
| 92 | default: | ||
| 93 | /* Let driver handle conversion */ | ||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | /** | ||
| 99 | * input_ff_upload() - upload effect into force-feedback device | ||
| 100 | * @dev: input device | ||
| 101 | * @effect: effect to be uploaded | ||
| 102 | * @file: owner of the effect | ||
| 103 | */ | ||
| 104 | int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, | ||
| 105 | struct file *file) | ||
| 106 | { | ||
| 107 | struct ff_device *ff = dev->ff; | ||
| 108 | struct ff_effect *old; | ||
| 109 | int ret = 0; | ||
| 110 | int id; | ||
| 111 | |||
| 112 | if (!test_bit(EV_FF, dev->evbit)) | ||
| 113 | return -ENOSYS; | ||
| 114 | |||
| 115 | if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX || | ||
| 116 | !test_bit(effect->type, dev->ffbit)) { | ||
| 117 | debug("invalid or not supported effect type in upload"); | ||
| 118 | return -EINVAL; | ||
| 119 | } | ||
| 120 | |||
| 121 | if (effect->type == FF_PERIODIC && | ||
| 122 | (effect->u.periodic.waveform < FF_WAVEFORM_MIN || | ||
| 123 | effect->u.periodic.waveform > FF_WAVEFORM_MAX || | ||
| 124 | !test_bit(effect->u.periodic.waveform, dev->ffbit))) { | ||
| 125 | debug("invalid or not supported wave form in upload"); | ||
| 126 | return -EINVAL; | ||
| 127 | } | ||
| 128 | |||
| 129 | if (!test_bit(effect->type, ff->ffbit)) { | ||
| 130 | ret = compat_effect(ff, effect); | ||
| 131 | if (ret) | ||
| 132 | return ret; | ||
| 133 | } | ||
| 134 | |||
| 135 | mutex_lock(&ff->mutex); | ||
| 136 | |||
| 137 | if (effect->id == -1) { | ||
| 138 | for (id = 0; id < ff->max_effects; id++) | ||
| 139 | if (!ff->effect_owners[id]) | ||
| 140 | break; | ||
| 141 | |||
| 142 | if (id >= ff->max_effects) { | ||
| 143 | ret = -ENOSPC; | ||
| 144 | goto out; | ||
| 145 | } | ||
| 146 | |||
| 147 | effect->id = id; | ||
| 148 | old = NULL; | ||
| 149 | |||
| 150 | } else { | ||
| 151 | id = effect->id; | ||
| 152 | |||
| 153 | ret = check_effect_access(ff, id, file); | ||
| 154 | if (ret) | ||
| 155 | goto out; | ||
| 156 | |||
| 157 | old = &ff->effects[id]; | ||
| 158 | |||
| 159 | if (!check_effects_compatible(effect, old)) { | ||
| 160 | ret = -EINVAL; | ||
| 161 | goto out; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | ret = ff->upload(dev, effect, old); | ||
| 166 | if (ret) | ||
| 167 | goto out; | ||
| 168 | |||
| 169 | ff->effects[id] = *effect; | ||
| 170 | ff->effect_owners[id] = file; | ||
| 171 | |||
| 172 | out: | ||
| 173 | mutex_unlock(&ff->mutex); | ||
| 174 | return ret; | ||
| 175 | } | ||
| 176 | EXPORT_SYMBOL_GPL(input_ff_upload); | ||
| 177 | |||
| 178 | /* | ||
| 179 | * Erases the effect if the requester is also the effect owner. The mutex | ||
| 180 | * should already be locked before calling this function. | ||
| 181 | */ | ||
| 182 | static int erase_effect(struct input_dev *dev, int effect_id, | ||
| 183 | struct file *file) | ||
| 184 | { | ||
| 185 | struct ff_device *ff = dev->ff; | ||
| 186 | int error; | ||
| 187 | |||
| 188 | error = check_effect_access(ff, effect_id, file); | ||
| 189 | if (error) | ||
| 190 | return error; | ||
| 191 | |||
| 192 | ff->playback(dev, effect_id, 0); | ||
| 193 | |||
| 194 | if (ff->erase) { | ||
| 195 | error = ff->erase(dev, effect_id); | ||
| 196 | if (error) | ||
| 197 | return error; | ||
| 198 | } | ||
| 199 | |||
| 200 | ff->effect_owners[effect_id] = NULL; | ||
| 201 | |||
| 202 | return 0; | ||
| 203 | } | ||
| 204 | |||
| 205 | /** | ||
| 206 | * input_ff_erase - erase an effect from device | ||
| 207 | * @dev: input device to erase effect from | ||
| 208 | * @effect_id: id of the ffect to be erased | ||
| 209 | * @file: purported owner of the request | ||
| 210 | * | ||
| 211 | * This function erases a force-feedback effect from specified device. | ||
| 212 | * The effect will only be erased if it was uploaded through the same | ||
| 213 | * file handle that is requesting erase. | ||
| 214 | */ | ||
| 215 | int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file) | ||
| 216 | { | ||
| 217 | struct ff_device *ff = dev->ff; | ||
| 218 | int ret; | ||
| 219 | |||
| 220 | if (!test_bit(EV_FF, dev->evbit)) | ||
| 221 | return -ENOSYS; | ||
| 222 | |||
| 223 | mutex_lock(&ff->mutex); | ||
| 224 | ret = erase_effect(dev, effect_id, file); | ||
| 225 | mutex_unlock(&ff->mutex); | ||
| 226 | |||
| 227 | return ret; | ||
| 228 | } | ||
| 229 | EXPORT_SYMBOL_GPL(input_ff_erase); | ||
| 230 | |||
| 231 | /* | ||
| 232 | * flush_effects - erase all effects owned by a file handle | ||
| 233 | */ | ||
| 234 | static int flush_effects(struct input_dev *dev, struct file *file) | ||
| 235 | { | ||
| 236 | struct ff_device *ff = dev->ff; | ||
| 237 | int i; | ||
| 238 | |||
| 239 | debug("flushing now"); | ||
| 240 | |||
| 241 | mutex_lock(&ff->mutex); | ||
| 242 | |||
| 243 | for (i = 0; i < ff->max_effects; i++) | ||
| 244 | erase_effect(dev, i, file); | ||
| 245 | |||
| 246 | mutex_unlock(&ff->mutex); | ||
| 247 | |||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | /** | ||
| 252 | * input_ff_event() - generic handler for force-feedback events | ||
| 253 | * @dev: input device to send the effect to | ||
| 254 | * @type: event type (anything but EV_FF is ignored) | ||
| 255 | * @code: event code | ||
| 256 | * @value: event value | ||
| 257 | */ | ||
| 258 | int input_ff_event(struct input_dev *dev, unsigned int type, | ||
| 259 | unsigned int code, int value) | ||
| 260 | { | ||
| 261 | struct ff_device *ff = dev->ff; | ||
| 262 | |||
| 263 | if (type != EV_FF) | ||
| 264 | return 0; | ||
| 265 | |||
| 266 | mutex_lock(&ff->mutex); | ||
| 267 | |||
| 268 | switch (code) { | ||
| 269 | case FF_GAIN: | ||
| 270 | if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffff) | ||
| 271 | break; | ||
| 272 | |||
| 273 | ff->set_gain(dev, value); | ||
| 274 | break; | ||
| 275 | |||
| 276 | case FF_AUTOCENTER: | ||
| 277 | if (!test_bit(FF_AUTOCENTER, dev->ffbit) || value > 0xffff) | ||
| 278 | break; | ||
| 279 | |||
| 280 | ff->set_autocenter(dev, value); | ||
| 281 | break; | ||
| 282 | |||
| 283 | default: | ||
| 284 | ff->playback(dev, code, value); | ||
| 285 | break; | ||
| 286 | } | ||
| 287 | |||
| 288 | mutex_unlock(&ff->mutex); | ||
| 289 | return 0; | ||
| 290 | } | ||
| 291 | EXPORT_SYMBOL_GPL(input_ff_event); | ||
| 292 | |||
| 293 | /** | ||
| 294 | * input_ff_create() - create force-feedback device | ||
| 295 | * @dev: input device supporting force-feedback | ||
| 296 | * @max_effects: maximum number of effects supported by the device | ||
| 297 | * | ||
| 298 | * This function allocates all necessary memory for a force feedback | ||
| 299 | * portion of an input device and installs all default handlers. | ||
| 300 | * @dev->ffbit should be already set up before calling this function. | ||
| 301 | * Once ff device is created you need to setup its upload, erase, | ||
| 302 | * playback and other handlers before registering input device | ||
| 303 | */ | ||
| 304 | int input_ff_create(struct input_dev *dev, int max_effects) | ||
| 305 | { | ||
| 306 | struct ff_device *ff; | ||
| 307 | int i; | ||
| 308 | |||
| 309 | if (!max_effects) { | ||
| 310 | printk(KERN_ERR | ||
| 311 | "ff-core: cannot allocate device without any effects\n"); | ||
| 312 | return -EINVAL; | ||
| 313 | } | ||
| 314 | |||
| 315 | ff = kzalloc(sizeof(struct ff_device) + | ||
| 316 | max_effects * sizeof(struct file *), GFP_KERNEL); | ||
| 317 | if (!ff) | ||
| 318 | return -ENOMEM; | ||
| 319 | |||
| 320 | ff->effects = kcalloc(max_effects, sizeof(struct ff_effect), | ||
| 321 | GFP_KERNEL); | ||
| 322 | if (!ff->effects) { | ||
| 323 | kfree(ff); | ||
| 324 | return -ENOMEM; | ||
| 325 | } | ||
| 326 | |||
| 327 | ff->max_effects = max_effects; | ||
| 328 | mutex_init(&ff->mutex); | ||
| 329 | |||
| 330 | dev->ff = ff; | ||
| 331 | dev->flush = flush_effects; | ||
| 332 | dev->event = input_ff_event; | ||
| 333 | set_bit(EV_FF, dev->evbit); | ||
| 334 | |||
| 335 | /* Copy "true" bits into ff device bitmap */ | ||
| 336 | for (i = 0; i <= FF_MAX; i++) | ||
| 337 | if (test_bit(i, dev->ffbit)) | ||
| 338 | set_bit(i, ff->ffbit); | ||
| 339 | |||
| 340 | /* we can emulate RUMBLE with periodic effects */ | ||
| 341 | if (test_bit(FF_PERIODIC, ff->ffbit)) | ||
| 342 | set_bit(FF_RUMBLE, dev->ffbit); | ||
| 343 | |||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | EXPORT_SYMBOL_GPL(input_ff_create); | ||
| 347 | |||
| 348 | /** | ||
| 349 | * input_ff_free() - frees force feedback portion of input device | ||
| 350 | * @dev: input device supporintg force feedback | ||
| 351 | * | ||
| 352 | * This function is only needed in error path as input core will | ||
| 353 | * automatically free force feedback structures when device is | ||
| 354 | * destroyed. | ||
| 355 | */ | ||
| 356 | void input_ff_destroy(struct input_dev *dev) | ||
| 357 | { | ||
| 358 | clear_bit(EV_FF, dev->evbit); | ||
| 359 | if (dev->ff) { | ||
| 360 | if (dev->ff->destroy) | ||
| 361 | dev->ff->destroy(dev->ff); | ||
| 362 | kfree(dev->ff->private); | ||
| 363 | kfree(dev->ff); | ||
| 364 | dev->ff = NULL; | ||
| 365 | } | ||
| 366 | } | ||
| 367 | EXPORT_SYMBOL_GPL(input_ff_destroy); | ||
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c new file mode 100644 index 0000000000..cd8b7297e6 --- /dev/null +++ b/drivers/input/ff-memless.c | |||
| @@ -0,0 +1,515 @@ | |||
| 1 | /* | ||
| 2 | * Force feedback support for memoryless devices | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.com> | ||
| 5 | * Copyright (c) 2006 Dmitry Torokhov <dtor@mail.ru> | ||
| 6 | */ | ||
| 7 | |||
| 8 | /* | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | */ | ||
| 23 | |||
| 24 | /* #define DEBUG */ | ||
| 25 | |||
| 26 | #define debug(format, arg...) pr_debug("ff-memless: " format "\n", ## arg) | ||
| 27 | |||
| 28 | #include <linux/input.h> | ||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/mutex.h> | ||
| 31 | #include <linux/spinlock.h> | ||
| 32 | #include <linux/sched.h> | ||
| 33 | |||
| 34 | #include "fixp-arith.h" | ||
| 35 | |||
| 36 | MODULE_LICENSE("GPL"); | ||
| 37 | MODULE_AUTHOR("Anssi Hannula <anssi.hannula@gmail.com>"); | ||
| 38 | MODULE_DESCRIPTION("Force feedback support for memoryless devices"); | ||
| 39 | |||
| 40 | /* Number of effects handled with memoryless devices */ | ||
| 41 | #define FF_MEMLESS_EFFECTS 16 | ||
| 42 | |||
| 43 | /* Envelope update interval in ms */ | ||
| 44 | #define FF_ENVELOPE_INTERVAL 50 | ||
| 45 | |||
| 46 | #define FF_EFFECT_STARTED 0 | ||
| 47 | #define FF_EFFECT_PLAYING 1 | ||
| 48 | #define FF_EFFECT_ABORTING 2 | ||
| 49 | |||
| 50 | struct ml_effect_state { | ||
| 51 | struct ff_effect *effect; | ||
| 52 | unsigned long flags; /* effect state (STARTED, PLAYING, etc) */ | ||
| 53 | int count; /* loop count of the effect */ | ||
| 54 | unsigned long play_at; /* start time */ | ||
| 55 | unsigned long stop_at; /* stop time */ | ||
| 56 | unsigned long adj_at; /* last time the effect was sent */ | ||
| 57 | }; | ||
| 58 | |||
| 59 | struct ml_device { | ||
| 60 | void *private; | ||
| 61 | struct ml_effect_state states[FF_MEMLESS_EFFECTS]; | ||
| 62 | int gain; | ||
| 63 | struct timer_list timer; | ||
| 64 | spinlock_t timer_lock; | ||
| 65 | struct input_dev *dev; | ||
| 66 | |||
| 67 | int (*play_effect)(struct input_dev *dev, void *data, | ||
| 68 | struct ff_effect *effect); | ||
| 69 | }; | ||
| 70 | |||
| 71 | static const struct ff_envelope *get_envelope(const struct ff_effect *effect) | ||
| 72 | { | ||
| 73 | static const struct ff_envelope empty_envelope; | ||
| 74 | |||
| 75 | switch (effect->type) { | ||
| 76 | case FF_PERIODIC: | ||
| 77 | return &effect->u.periodic.envelope; | ||
| 78 | case FF_CONSTANT: | ||
| 79 | return &effect->u.constant.envelope; | ||
| 80 | default: | ||
| 81 | return &empty_envelope; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Check for the next time envelope requires an update on memoryless devices | ||
| 87 | */ | ||
| 88 | static unsigned long calculate_next_time(struct ml_effect_state *state) | ||
| 89 | { | ||
| 90 | const struct ff_envelope *envelope = get_envelope(state->effect); | ||
| 91 | unsigned long attack_stop, fade_start, next_fade; | ||
| 92 | |||
| 93 | if (envelope->attack_length) { | ||
| 94 | attack_stop = state->play_at + | ||
| 95 | msecs_to_jiffies(envelope->attack_length); | ||
| 96 | if (time_before(state->adj_at, attack_stop)) | ||
| 97 | return state->adj_at + | ||
| 98 | msecs_to_jiffies(FF_ENVELOPE_INTERVAL); | ||
| 99 | } | ||
| 100 | |||
| 101 | if (state->effect->replay.length) { | ||
| 102 | if (envelope->fade_length) { | ||
| 103 | /* check when fading should start */ | ||
| 104 | fade_start = state->stop_at - | ||
| 105 | msecs_to_jiffies(envelope->fade_length); | ||
| 106 | |||
| 107 | if (time_before(state->adj_at, fade_start)) | ||
| 108 | return fade_start; | ||
| 109 | |||
| 110 | /* already fading, advance to next checkpoint */ | ||
| 111 | next_fade = state->adj_at + | ||
| 112 | msecs_to_jiffies(FF_ENVELOPE_INTERVAL); | ||
| 113 | if (time_before(next_fade, state->stop_at)) | ||
| 114 | return next_fade; | ||
| 115 | } | ||
| 116 | |||
| 117 | return state->stop_at; | ||
| 118 | } | ||
| 119 | |||
| 120 | return state->play_at; | ||
| 121 | } | ||
| 122 | |||
| 123 | static void ml_schedule_timer(struct ml_device *ml) | ||
| 124 | { | ||
| 125 | struct ml_effect_state *state; | ||
| 126 | unsigned long now = jiffies; | ||
| 127 | unsigned long earliest = 0; | ||
| 128 | unsigned long next_at; | ||
| 129 | int events = 0; | ||
| 130 | int i; | ||
| 131 | |||
| 132 | debug("calculating next timer"); | ||
| 133 | |||
| 134 | for (i = 0; i < FF_MEMLESS_EFFECTS; i++) { | ||
| 135 | |||
| 136 | state = &ml->states[i]; | ||
| 137 | |||
| 138 | if (!test_bit(FF_EFFECT_STARTED, &state->flags)) | ||
| 139 | continue; | ||
| 140 | |||
| 141 | if (test_bit(FF_EFFECT_PLAYING, &state->flags)) | ||
| 142 | next_at = calculate_next_time(state); | ||
| 143 | else | ||
| 144 | next_at = state->play_at; | ||
| 145 | |||
| 146 | if (time_before_eq(now, next_at) && | ||
| 147 | (++events == 1 || time_before(next_at, earliest))) | ||
| 148 | earliest = next_at; | ||
| 149 | } | ||
| 150 | |||
| 151 | if (!events) { | ||
| 152 | debug("no actions"); | ||
| 153 | del_timer(&ml->timer); | ||
| 154 | } else { | ||
| 155 | debug("timer set"); | ||
| 156 | mod_timer(&ml->timer, earliest); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | /* | ||
| 161 | * Apply an envelope to a value | ||
| 162 | */ | ||
| 163 | static int apply_envelope(struct ml_effect_state *state, int value, | ||
| 164 | struct ff_envelope *envelope) | ||
| 165 | { | ||
| 166 | struct ff_effect *effect = state->effect; | ||
| 167 | unsigned long now = jiffies; | ||
| 168 | int time_from_level; | ||
| 169 | int time_of_envelope; | ||
| 170 | int envelope_level; | ||
| 171 | int difference; | ||
| 172 | |||
| 173 | if (envelope->attack_length && | ||
| 174 | time_before(now, | ||
| 175 | state->play_at + msecs_to_jiffies(envelope->attack_length))) { | ||
| 176 | debug("value = 0x%x, attack_level = 0x%x", value, | ||
| 177 | envelope->attack_level); | ||
| 178 | time_from_level = jiffies_to_msecs(now - state->play_at); | ||
| 179 | time_of_envelope = envelope->attack_length; | ||
| 180 | envelope_level = min_t(__s16, envelope->attack_level, 0x7fff); | ||
| 181 | |||
| 182 | } else if (envelope->fade_length && effect->replay.length && | ||
| 183 | time_after(now, | ||
| 184 | state->stop_at - msecs_to_jiffies(envelope->fade_length)) && | ||
| 185 | time_before(now, state->stop_at)) { | ||
| 186 | time_from_level = jiffies_to_msecs(state->stop_at - now); | ||
| 187 | time_of_envelope = envelope->fade_length; | ||
| 188 | envelope_level = min_t(__s16, envelope->fade_level, 0x7fff); | ||
| 189 | } else | ||
| 190 | return value; | ||
| 191 | |||
| 192 | difference = abs(value) - envelope_level; | ||
| 193 | |||
| 194 | debug("difference = %d", difference); | ||
| 195 | debug("time_from_level = 0x%x", time_from_level); | ||
| 196 | debug("time_of_envelope = 0x%x", time_of_envelope); | ||
| 197 | |||
| 198 | difference = difference * time_from_level / time_of_envelope; | ||
| 199 | |||
| 200 | debug("difference = %d", difference); | ||
| 201 | |||
| 202 | return value < 0 ? | ||
| 203 | -(difference + envelope_level) : (difference + envelope_level); | ||
| 204 | } | ||
| 205 | |||
| 206 | /* | ||
| 207 | * Return the type the effect has to be converted into (memless devices) | ||
| 208 | */ | ||
| 209 | static int get_compatible_type(struct ff_device *ff, int effect_type) | ||
| 210 | { | ||
| 211 | |||
| 212 | if (test_bit(effect_type, ff->ffbit)) | ||
| 213 | return effect_type; | ||
| 214 | |||
| 215 | if (effect_type == FF_PERIODIC && test_bit(FF_RUMBLE, ff->ffbit)) | ||
| 216 | return FF_RUMBLE; | ||
| 217 | |||
| 218 | printk(KERN_ERR | ||
| 219 | "ff-memless: invalid type in get_compatible_type()\n"); | ||
| 220 | |||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | /* | ||
| 225 | * Combine two effects and apply gain. | ||
| 226 | */ | ||
| 227 | static void ml_combine_effects(struct ff_effect *effect, | ||
| 228 | struct ml_effect_state *state, | ||
| 229 | int gain) | ||
| 230 | { | ||
| 231 | struct ff_effect *new = state->effect; | ||
| 232 | unsigned int strong, weak, i; | ||
| 233 | int x, y; | ||
| 234 | fixp_t level; | ||
| 235 | |||
| 236 | switch (new->type) { | ||
| 237 | case FF_CONSTANT: | ||
| 238 | i = new->direction * 360 / 0xffff; | ||
| 239 | level = fixp_new16(apply_envelope(state, | ||
| 240 | new->u.constant.level, | ||
| 241 | &new->u.constant.envelope)); | ||
| 242 | x = fixp_mult(fixp_sin(i), level) * gain / 0xffff; | ||
| 243 | y = fixp_mult(-fixp_cos(i), level) * gain / 0xffff; | ||
| 244 | /* | ||
| 245 | * here we abuse ff_ramp to hold x and y of constant force | ||
| 246 | * If in future any driver wants something else than x and y | ||
| 247 | * in s8, this should be changed to something more generic | ||
| 248 | */ | ||
| 249 | effect->u.ramp.start_level = | ||
| 250 | max(min(effect->u.ramp.start_level + x, 0x7f), -0x80); | ||
| 251 | effect->u.ramp.end_level = | ||
| 252 | max(min(effect->u.ramp.end_level + y, 0x7f), -0x80); | ||
| 253 | break; | ||
| 254 | |||
| 255 | case FF_RUMBLE: | ||
| 256 | strong = new->u.rumble.strong_magnitude * gain / 0xffff; | ||
| 257 | weak = new->u.rumble.weak_magnitude * gain / 0xffff; | ||
| 258 | effect->u.rumble.strong_magnitude = | ||
| 259 | min(strong + effect->u.rumble.strong_magnitude, | ||
| 260 | 0xffffU); | ||
| 261 | effect->u.rumble.weak_magnitude = | ||
| 262 | min(weak + effect->u.rumble.weak_magnitude, 0xffffU); | ||
| 263 | break; | ||
| 264 | |||
| 265 | case FF_PERIODIC: | ||
| 266 | i = apply_envelope(state, abs(new->u.periodic.magnitude), | ||
| 267 | &new->u.periodic.envelope); | ||
| 268 | |||
| 269 | /* here we also scale it 0x7fff => 0xffff */ | ||
| 270 | i = i * gain / 0x7fff; | ||
| 271 | |||
| 272 | effect->u.rumble.strong_magnitude = | ||
| 273 | min(i + effect->u.rumble.strong_magnitude, 0xffffU); | ||
| 274 | effect->u.rumble.weak_magnitude = | ||
| 275 | min(i + effect->u.rumble.weak_magnitude, 0xffffU); | ||
| 276 | break; | ||
| 277 | |||
| 278 | default: | ||
| 279 | printk(KERN_ERR "ff-memless: invalid type in ml_combine_effects()\n"); | ||
| 280 | break; | ||
| 281 | } | ||
| 282 | |||
| 283 | } | ||
| 284 | |||
| 285 | |||
| 286 | /* | ||
| 287 | * Because memoryless devices have only one effect per effect type active | ||
| 288 | * at one time we have to combine multiple effects into one | ||
| 289 | */ | ||
| 290 | static int ml_get_combo_effect(struct ml_device *ml, | ||
| 291 | unsigned long *effect_handled, | ||
| 292 | struct ff_effect *combo_effect) | ||
| 293 | { | ||
| 294 | struct ff_effect *effect; | ||
| 295 | struct ml_effect_state *state; | ||
| 296 | int effect_type; | ||
| 297 | int i; | ||
| 298 | |||
| 299 | memset(combo_effect, 0, sizeof(struct ff_effect)); | ||
| 300 | |||
| 301 | for (i = 0; i < FF_MEMLESS_EFFECTS; i++) { | ||
| 302 | if (__test_and_set_bit(i, effect_handled)) | ||
| 303 | continue; | ||
| 304 | |||
| 305 | state = &ml->states[i]; | ||
| 306 | effect = state->effect; | ||
| 307 | |||
| 308 | if (!test_bit(FF_EFFECT_STARTED, &state->flags)) | ||
| 309 | continue; | ||
| 310 | |||
| 311 | if (time_before(jiffies, state->play_at)) | ||
| 312 | continue; | ||
| 313 | |||
| 314 | /* | ||
| 315 | * here we have started effects that are either | ||
| 316 | * currently playing (and may need be aborted) | ||
| 317 | * or need to start playing. | ||
| 318 | */ | ||
| 319 | effect_type = get_compatible_type(ml->dev->ff, effect->type); | ||
| 320 | if (combo_effect->type != effect_type) { | ||
| 321 | if (combo_effect->type != 0) { | ||
| 322 | __clear_bit(i, effect_handled); | ||
| 323 | continue; | ||
| 324 | } | ||
| 325 | combo_effect->type = effect_type; | ||
| 326 | } | ||
| 327 | |||
| 328 | if (__test_and_clear_bit(FF_EFFECT_ABORTING, &state->flags)) { | ||
| 329 | __clear_bit(FF_EFFECT_PLAYING, &state->flags); | ||
| 330 | __clear_bit(FF_EFFECT_STARTED, &state->flags); | ||
| 331 | } else if (effect->replay.length && | ||
| 332 | time_after_eq(jiffies, state->stop_at)) { | ||
| 333 | |||
| 334 | __clear_bit(FF_EFFECT_PLAYING, &state->flags); | ||
| 335 | |||
| 336 | if (--state->count <= 0) { | ||
| 337 | __clear_bit(FF_EFFECT_STARTED, &state->flags); | ||
| 338 | } else { | ||
| 339 | state->play_at = jiffies + | ||
| 340 | msecs_to_jiffies(effect->replay.delay); | ||
| 341 | state->stop_at = state->play_at + | ||
| 342 | msecs_to_jiffies(effect->replay.length); | ||
| 343 | } | ||
| 344 | } else { | ||
| 345 | __set_bit(FF_EFFECT_PLAYING, &state->flags); | ||
| 346 | state->adj_at = jiffies; | ||
| 347 | ml_combine_effects(combo_effect, state, ml->gain); | ||
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 351 | return combo_effect->type != 0; | ||
| 352 | } | ||
| 353 | |||
| 354 | static void ml_play_effects(struct ml_device *ml) | ||
| 355 | { | ||
| 356 | struct ff_effect effect; | ||
| 357 | DECLARE_BITMAP(handled_bm, FF_MEMLESS_EFFECTS); | ||
| 358 | |||
| 359 | memset(handled_bm, 0, sizeof(handled_bm)); | ||
| 360 | |||
| 361 | while (ml_get_combo_effect(ml, handled_bm, &effect)) | ||
| 362 | ml->play_effect(ml->dev, ml->private, &effect); | ||
| 363 | |||
| 364 | ml_schedule_timer(ml); | ||
| 365 | } | ||
| 366 | |||
| 367 | static void ml_effect_timer(unsigned long timer_data) | ||
| 368 | { | ||
| 369 | struct input_dev *dev = (struct input_dev *)timer_data; | ||
| 370 | struct ml_device *ml = dev->ff->private; | ||
| 371 | |||
| 372 | debug("timer: updating effects"); | ||
| 373 | |||
| 374 | spin_lock(&ml->timer_lock); | ||
| 375 | ml_play_effects(ml); | ||
| 376 | spin_unlock(&ml->timer_lock); | ||
| 377 | } | ||
| 378 | |||
| 379 | static void ml_ff_set_gain(struct input_dev *dev, u16 gain) | ||
| 380 | { | ||
| 381 | struct ml_device *ml = dev->ff->private; | ||
| 382 | int i; | ||
| 383 | |||
| 384 | spin_lock_bh(&ml->timer_lock); | ||
| 385 | |||
| 386 | ml->gain = gain; | ||
| 387 | |||
| 388 | for (i = 0; i < FF_MEMLESS_EFFECTS; i++) | ||
| 389 | __clear_bit(FF_EFFECT_PLAYING, &ml->states[i].flags); | ||
| 390 | |||
| 391 | ml_play_effects(ml); | ||
| 392 | |||
| 393 | spin_unlock_bh(&ml->timer_lock); | ||
| 394 | } | ||
| 395 | |||
| 396 | static int ml_ff_playback(struct input_dev *dev, int effect_id, int value) | ||
| 397 | { | ||
| 398 | struct ml_device *ml = dev->ff->private; | ||
| 399 | struct ml_effect_state *state = &ml->states[effect_id]; | ||
| 400 | |||
| 401 | spin_lock_bh(&ml->timer_lock); | ||
| 402 | |||
| 403 | if (value > 0) { | ||
| 404 | debug("initiated play"); | ||
| 405 | |||
| 406 | __set_bit(FF_EFFECT_STARTED, &state->flags); | ||
| 407 | state->count = value; | ||
| 408 | state->play_at = jiffies + | ||
| 409 | msecs_to_jiffies(state->effect->replay.delay); | ||
| 410 | state->stop_at = state->play_at + | ||
| 411 | msecs_to_jiffies(state->effect->replay.length); | ||
| 412 | state->adj_at = state->play_at; | ||
| 413 | |||
| 414 | ml_schedule_timer(ml); | ||
| 415 | |||
| 416 | } else { | ||
| 417 | debug("initiated stop"); | ||
| 418 | |||
| 419 | if (test_bit(FF_EFFECT_PLAYING, &state->flags)) | ||
| 420 | __set_bit(FF_EFFECT_ABORTING, &state->flags); | ||
| 421 | else | ||
| 422 | __clear_bit(FF_EFFECT_STARTED, &state->flags); | ||
| 423 | |||
| 424 | ml_play_effects(ml); | ||
| 425 | } | ||
| 426 | |||
| 427 | spin_unlock_bh(&ml->timer_lock); | ||
| 428 | |||
| 429 | return 0; | ||
| 430 | } | ||
| 431 | |||
| 432 | static int ml_ff_upload(struct input_dev *dev, | ||
| 433 | struct ff_effect *effect, struct ff_effect *old) | ||
| 434 | { | ||
| 435 | struct ml_device *ml = dev->ff->private; | ||
| 436 | struct ml_effect_state *state = &ml->states[effect->id]; | ||
| 437 | |||
| 438 | spin_lock_bh(&ml->timer_lock); | ||
| 439 | |||
| 440 | if (test_bit(FF_EFFECT_STARTED, &state->flags)) { | ||
| 441 | __clear_bit(FF_EFFECT_PLAYING, &state->flags); | ||
| 442 | state->play_at = jiffies + | ||
| 443 | msecs_to_jiffies(state->effect->replay.delay); | ||
| 444 | state->stop_at = state->play_at + | ||
| 445 | msecs_to_jiffies(state->effect->replay.length); | ||
| 446 | state->adj_at = state->play_at; | ||
| 447 | ml_schedule_timer(ml); | ||
| 448 | } | ||
| 449 | |||
| 450 | spin_unlock_bh(&ml->timer_lock); | ||
| 451 | |||
| 452 | return 0; | ||
| 453 | } | ||
| 454 | |||
| 455 | static void ml_ff_destroy(struct ff_device *ff) | ||
| 456 | { | ||
| 457 | struct ml_device *ml = ff->private; | ||
| 458 | |||
| 459 | kfree(ml->private); | ||
| 460 | } | ||
| 461 | |||
| 462 | /** | ||
| 463 | * input_ff_create_memless() - create memoryless FF device | ||
| 464 | * @dev: input device supporting force-feedback | ||
| 465 | * @data: driver-specific data to be passed into @play_effect | ||
| 466 | * @play_effect: driver-specific method for playing FF effect | ||
| 467 | */ | ||
| 468 | int input_ff_create_memless(struct input_dev *dev, void *data, | ||
| 469 | int (*play_effect)(struct input_dev *, void *, struct ff_effect *)) | ||
| 470 | { | ||
| 471 | struct ml_device *ml; | ||
| 472 | struct ff_device *ff; | ||
| 473 | int error; | ||
| 474 | int i; | ||
| 475 | |||
| 476 | ml = kzalloc(sizeof(struct ml_device), GFP_KERNEL); | ||
| 477 | if (!ml) | ||
| 478 | return -ENOMEM; | ||
| 479 | |||
| 480 | ml->dev = dev; | ||
| 481 | ml->private = data; | ||
| 482 | ml->play_effect = play_effect; | ||
| 483 | ml->gain = 0xffff; | ||
| 484 | spin_lock_init(&ml->timer_lock); | ||
| 485 | setup_timer(&ml->timer, ml_effect_timer, (unsigned long)dev); | ||
| 486 | |||
| 487 | set_bit(FF_GAIN, dev->ffbit); | ||
| 488 | |||
| 489 | error = input_ff_create(dev, FF_MEMLESS_EFFECTS); | ||
| 490 | if (error) { | ||
| 491 | kfree(ml); | ||
| 492 | return error; | ||
| 493 | } | ||
| 494 | |||
| 495 | ff = dev->ff; | ||
| 496 | ff->private = ml; | ||
| 497 | ff->upload = ml_ff_upload; | ||
| 498 | ff->playback = ml_ff_playback; | ||
| 499 | ff->set_gain = ml_ff_set_gain; | ||
| 500 | ff->destroy = ml_ff_destroy; | ||
| 501 | |||
| 502 | /* we can emulate periodic effects with RUMBLE */ | ||
| 503 | if (test_bit(FF_RUMBLE, ff->ffbit)) { | ||
| 504 | set_bit(FF_PERIODIC, dev->ffbit); | ||
| 505 | set_bit(FF_SINE, dev->ffbit); | ||
| 506 | set_bit(FF_TRIANGLE, dev->ffbit); | ||
| 507 | set_bit(FF_SQUARE, dev->ffbit); | ||
| 508 | } | ||
| 509 | |||
| 510 | for (i = 0; i < FF_MEMLESS_EFFECTS; i++) | ||
| 511 | ml->states[i].effect = &ff->effects[i]; | ||
| 512 | |||
| 513 | return 0; | ||
| 514 | } | ||
| 515 | EXPORT_SYMBOL_GPL(input_ff_create_memless); | ||
diff --git a/drivers/input/fixp-arith.h b/drivers/input/fixp-arith.h new file mode 100644 index 0000000000..ed3d2da0c4 --- /dev/null +++ b/drivers/input/fixp-arith.h | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | #ifndef _FIXP_ARITH_H | ||
| 2 | #define _FIXP_ARITH_H | ||
| 3 | |||
| 4 | /* | ||
| 5 | * Simplistic fixed-point arithmetics. | ||
| 6 | * Hmm, I'm probably duplicating some code :( | ||
| 7 | * | ||
| 8 | * Copyright (c) 2002 Johann Deneux | ||
| 9 | */ | ||
| 10 | |||
| 11 | /* | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2 of the License, or | ||
| 15 | * (at your option) any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 25 | * | ||
| 26 | * Should you need to contact me, the author, you can do so by | ||
| 27 | * e-mail - mail your message to <deneux@ifrance.com> | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include <linux/types.h> | ||
| 31 | |||
| 32 | /* The type representing fixed-point values */ | ||
| 33 | typedef s16 fixp_t; | ||
| 34 | |||
| 35 | #define FRAC_N 8 | ||
| 36 | #define FRAC_MASK ((1<<FRAC_N)-1) | ||
| 37 | |||
| 38 | /* Not to be used directly. Use fixp_{cos,sin} */ | ||
| 39 | static const fixp_t cos_table[46] = { | ||
| 40 | 0x0100, 0x00FF, 0x00FF, 0x00FE, 0x00FD, 0x00FC, 0x00FA, 0x00F8, | ||
| 41 | 0x00F6, 0x00F3, 0x00F0, 0x00ED, 0x00E9, 0x00E6, 0x00E2, 0x00DD, | ||
| 42 | 0x00D9, 0x00D4, 0x00CF, 0x00C9, 0x00C4, 0x00BE, 0x00B8, 0x00B1, | ||
| 43 | 0x00AB, 0x00A4, 0x009D, 0x0096, 0x008F, 0x0087, 0x0080, 0x0078, | ||
| 44 | 0x0070, 0x0068, 0x005F, 0x0057, 0x004F, 0x0046, 0x003D, 0x0035, | ||
| 45 | 0x002C, 0x0023, 0x001A, 0x0011, 0x0008, 0x0000 | ||
| 46 | }; | ||
| 47 | |||
| 48 | |||
| 49 | /* a: 123 -> 123.0 */ | ||
| 50 | static inline fixp_t fixp_new(s16 a) | ||
| 51 | { | ||
| 52 | return a<<FRAC_N; | ||
| 53 | } | ||
| 54 | |||
| 55 | /* a: 0xFFFF -> -1.0 | ||
| 56 | 0x8000 -> 1.0 | ||
| 57 | 0x0000 -> 0.0 | ||
| 58 | */ | ||
| 59 | static inline fixp_t fixp_new16(s16 a) | ||
| 60 | { | ||
| 61 | return ((s32)a)>>(16-FRAC_N); | ||
| 62 | } | ||
| 63 | |||
| 64 | static inline fixp_t fixp_cos(unsigned int degrees) | ||
| 65 | { | ||
| 66 | int quadrant = (degrees / 90) & 3; | ||
| 67 | unsigned int i = degrees % 90; | ||
| 68 | |||
| 69 | if (quadrant == 1 || quadrant == 3) | ||
| 70 | i = 90 - i; | ||
| 71 | |||
| 72 | i >>= 1; | ||
| 73 | |||
| 74 | return (quadrant == 1 || quadrant == 2)? -cos_table[i] : cos_table[i]; | ||
| 75 | } | ||
| 76 | |||
| 77 | static inline fixp_t fixp_sin(unsigned int degrees) | ||
| 78 | { | ||
| 79 | return -fixp_cos(degrees + 90); | ||
| 80 | } | ||
| 81 | |||
| 82 | static inline fixp_t fixp_mult(fixp_t a, fixp_t b) | ||
| 83 | { | ||
| 84 | return ((s32)(a*b))>>FRAC_N; | ||
| 85 | } | ||
| 86 | |||
| 87 | #endif | ||
diff --git a/drivers/input/input.c b/drivers/input/input.c index 9cb4b9a54f..1c8c8a5bc4 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
| @@ -176,6 +176,10 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in | |||
| 176 | break; | 176 | break; |
| 177 | 177 | ||
| 178 | case EV_FF: | 178 | case EV_FF: |
| 179 | |||
| 180 | if (value < 0) | ||
| 181 | return; | ||
| 182 | |||
| 179 | if (dev->event) | 183 | if (dev->event) |
| 180 | dev->event(dev, type, code, value); | 184 | dev->event(dev, type, code, value); |
| 181 | break; | 185 | break; |
| @@ -309,7 +313,8 @@ static void input_link_handle(struct input_handle *handle) | |||
| 309 | if (i != NBITS(max)) \ | 313 | if (i != NBITS(max)) \ |
| 310 | continue; | 314 | continue; |
| 311 | 315 | ||
| 312 | static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev) | 316 | static const struct input_device_id *input_match_device(const struct input_device_id *id, |
| 317 | struct input_dev *dev) | ||
| 313 | { | 318 | { |
| 314 | int i; | 319 | int i; |
| 315 | 320 | ||
| @@ -762,7 +767,9 @@ static void input_dev_release(struct class_device *class_dev) | |||
| 762 | { | 767 | { |
| 763 | struct input_dev *dev = to_input_dev(class_dev); | 768 | struct input_dev *dev = to_input_dev(class_dev); |
| 764 | 769 | ||
| 770 | input_ff_destroy(dev); | ||
| 765 | kfree(dev); | 771 | kfree(dev); |
| 772 | |||
| 766 | module_put(THIS_MODULE); | 773 | module_put(THIS_MODULE); |
| 767 | } | 774 | } |
| 768 | 775 | ||
| @@ -899,12 +906,13 @@ struct input_dev *input_allocate_device(void) | |||
| 899 | 906 | ||
| 900 | dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); | 907 | dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); |
| 901 | if (dev) { | 908 | if (dev) { |
| 902 | dev->dynalloc = 1; | ||
| 903 | dev->cdev.class = &input_class; | 909 | dev->cdev.class = &input_class; |
| 904 | class_device_initialize(&dev->cdev); | 910 | class_device_initialize(&dev->cdev); |
| 905 | mutex_init(&dev->mutex); | 911 | mutex_init(&dev->mutex); |
| 906 | INIT_LIST_HEAD(&dev->h_list); | 912 | INIT_LIST_HEAD(&dev->h_list); |
| 907 | INIT_LIST_HEAD(&dev->node); | 913 | INIT_LIST_HEAD(&dev->node); |
| 914 | |||
| 915 | __module_get(THIS_MODULE); | ||
| 908 | } | 916 | } |
| 909 | 917 | ||
| 910 | return dev; | 918 | return dev; |
| @@ -929,17 +937,10 @@ int input_register_device(struct input_dev *dev) | |||
| 929 | static atomic_t input_no = ATOMIC_INIT(0); | 937 | static atomic_t input_no = ATOMIC_INIT(0); |
| 930 | struct input_handle *handle; | 938 | struct input_handle *handle; |
| 931 | struct input_handler *handler; | 939 | struct input_handler *handler; |
| 932 | struct input_device_id *id; | 940 | const struct input_device_id *id; |
| 933 | const char *path; | 941 | const char *path; |
| 934 | int error; | 942 | int error; |
| 935 | 943 | ||
| 936 | if (!dev->dynalloc) { | ||
| 937 | printk(KERN_WARNING "input: device %s is statically allocated, will not register\n" | ||
| 938 | "Please convert to input_allocate_device() or contact dtor_core@ameritech.net\n", | ||
| 939 | dev->name ? dev->name : "<Unknown>"); | ||
| 940 | return -EINVAL; | ||
| 941 | } | ||
| 942 | |||
| 943 | set_bit(EV_SYN, dev->evbit); | 944 | set_bit(EV_SYN, dev->evbit); |
| 944 | 945 | ||
| 945 | /* | 946 | /* |
| @@ -955,10 +956,8 @@ int input_register_device(struct input_dev *dev) | |||
| 955 | dev->rep[REP_PERIOD] = 33; | 956 | dev->rep[REP_PERIOD] = 33; |
| 956 | } | 957 | } |
| 957 | 958 | ||
| 958 | INIT_LIST_HEAD(&dev->h_list); | ||
| 959 | list_add_tail(&dev->node, &input_dev_list); | 959 | list_add_tail(&dev->node, &input_dev_list); |
| 960 | 960 | ||
| 961 | dev->cdev.class = &input_class; | ||
| 962 | snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), | 961 | snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), |
| 963 | "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); | 962 | "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); |
| 964 | 963 | ||
| @@ -978,8 +977,6 @@ int input_register_device(struct input_dev *dev) | |||
| 978 | if (error) | 977 | if (error) |
| 979 | goto fail3; | 978 | goto fail3; |
| 980 | 979 | ||
| 981 | __module_get(THIS_MODULE); | ||
| 982 | |||
| 983 | path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL); | 980 | path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL); |
| 984 | printk(KERN_INFO "input: %s as %s\n", | 981 | printk(KERN_INFO "input: %s as %s\n", |
| 985 | dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); | 982 | dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); |
| @@ -1008,9 +1005,12 @@ EXPORT_SYMBOL(input_register_device); | |||
| 1008 | void input_unregister_device(struct input_dev *dev) | 1005 | void input_unregister_device(struct input_dev *dev) |
| 1009 | { | 1006 | { |
| 1010 | struct list_head *node, *next; | 1007 | struct list_head *node, *next; |
| 1008 | int code; | ||
| 1011 | 1009 | ||
| 1012 | if (!dev) | 1010 | for (code = 0; code <= KEY_MAX; code++) |
| 1013 | return; | 1011 | if (test_bit(code, dev->key)) |
| 1012 | input_report_key(dev, code, 0); | ||
| 1013 | input_sync(dev); | ||
| 1014 | 1014 | ||
| 1015 | del_timer_sync(&dev->timer); | 1015 | del_timer_sync(&dev->timer); |
| 1016 | 1016 | ||
| @@ -1037,19 +1037,20 @@ void input_unregister_device(struct input_dev *dev) | |||
| 1037 | } | 1037 | } |
| 1038 | EXPORT_SYMBOL(input_unregister_device); | 1038 | EXPORT_SYMBOL(input_unregister_device); |
| 1039 | 1039 | ||
| 1040 | void input_register_handler(struct input_handler *handler) | 1040 | int input_register_handler(struct input_handler *handler) |
| 1041 | { | 1041 | { |
| 1042 | struct input_dev *dev; | 1042 | struct input_dev *dev; |
| 1043 | struct input_handle *handle; | 1043 | struct input_handle *handle; |
| 1044 | struct input_device_id *id; | 1044 | const struct input_device_id *id; |
| 1045 | |||
| 1046 | if (!handler) | ||
| 1047 | return; | ||
| 1048 | 1045 | ||
| 1049 | INIT_LIST_HEAD(&handler->h_list); | 1046 | INIT_LIST_HEAD(&handler->h_list); |
| 1050 | 1047 | ||
| 1051 | if (handler->fops != NULL) | 1048 | if (handler->fops != NULL) { |
| 1049 | if (input_table[handler->minor >> 5]) | ||
| 1050 | return -EBUSY; | ||
| 1051 | |||
| 1052 | input_table[handler->minor >> 5] = handler; | 1052 | input_table[handler->minor >> 5] = handler; |
| 1053 | } | ||
| 1053 | 1054 | ||
| 1054 | list_add_tail(&handler->node, &input_handler_list); | 1055 | list_add_tail(&handler->node, &input_handler_list); |
| 1055 | 1056 | ||
| @@ -1063,6 +1064,7 @@ void input_register_handler(struct input_handler *handler) | |||
| 1063 | } | 1064 | } |
| 1064 | 1065 | ||
| 1065 | input_wakeup_procfs_readers(); | 1066 | input_wakeup_procfs_readers(); |
| 1067 | return 0; | ||
| 1066 | } | 1068 | } |
| 1067 | EXPORT_SYMBOL(input_register_handler); | 1069 | EXPORT_SYMBOL(input_register_handler); |
| 1068 | 1070 | ||
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index d67157513b..9f3529ad3f 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c | |||
| @@ -451,7 +451,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
| 451 | } | 451 | } |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | static struct file_operations joydev_fops = { | 454 | static const struct file_operations joydev_fops = { |
| 455 | .owner = THIS_MODULE, | 455 | .owner = THIS_MODULE, |
| 456 | .read = joydev_read, | 456 | .read = joydev_read, |
| 457 | .write = joydev_write, | 457 | .write = joydev_write, |
| @@ -465,7 +465,8 @@ static struct file_operations joydev_fops = { | |||
| 465 | .fasync = joydev_fasync, | 465 | .fasync = joydev_fasync, |
| 466 | }; | 466 | }; |
| 467 | 467 | ||
| 468 | static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | 468 | static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, |
| 469 | const struct input_device_id *id) | ||
| 469 | { | 470 | { |
| 470 | struct joydev *joydev; | 471 | struct joydev *joydev; |
| 471 | struct class_device *cdev; | 472 | struct class_device *cdev; |
| @@ -562,7 +563,7 @@ static void joydev_disconnect(struct input_handle *handle) | |||
| 562 | joydev_free(joydev); | 563 | joydev_free(joydev); |
| 563 | } | 564 | } |
| 564 | 565 | ||
| 565 | static struct input_device_id joydev_blacklist[] = { | 566 | static const struct input_device_id joydev_blacklist[] = { |
| 566 | { | 567 | { |
| 567 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | 568 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, |
| 568 | .evbit = { BIT(EV_KEY) }, | 569 | .evbit = { BIT(EV_KEY) }, |
| @@ -571,7 +572,7 @@ static struct input_device_id joydev_blacklist[] = { | |||
| 571 | { } /* Terminating entry */ | 572 | { } /* Terminating entry */ |
| 572 | }; | 573 | }; |
| 573 | 574 | ||
| 574 | static struct input_device_id joydev_ids[] = { | 575 | static const struct input_device_id joydev_ids[] = { |
| 575 | { | 576 | { |
| 576 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 577 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, |
| 577 | .evbit = { BIT(EV_ABS) }, | 578 | .evbit = { BIT(EV_ABS) }, |
| @@ -605,8 +606,7 @@ static struct input_handler joydev_handler = { | |||
| 605 | 606 | ||
| 606 | static int __init joydev_init(void) | 607 | static int __init joydev_init(void) |
| 607 | { | 608 | { |
| 608 | input_register_handler(&joydev_handler); | 609 | return input_register_handler(&joydev_handler); |
| 609 | return 0; | ||
| 610 | } | 610 | } |
| 611 | 611 | ||
| 612 | static void __exit joydev_exit(void) | 612 | static void __exit joydev_exit(void) |
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c index 50c90765ae..8fb0c19cc6 100644 --- a/drivers/input/joystick/iforce/iforce-ff.c +++ b/drivers/input/joystick/iforce/iforce-ff.c | |||
| @@ -165,19 +165,19 @@ static int make_condition_modifier(struct iforce* iforce, | |||
| 165 | data[0] = LO(mod_chunk->start); | 165 | data[0] = LO(mod_chunk->start); |
| 166 | data[1] = HI(mod_chunk->start); | 166 | data[1] = HI(mod_chunk->start); |
| 167 | 167 | ||
| 168 | data[2] = (100*rk)>>15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ | 168 | data[2] = (100 * rk) >> 15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ |
| 169 | data[3] = (100*lk)>>15; /* This code is incorrect on cpus lacking arith shift */ | 169 | data[3] = (100 * lk) >> 15; /* This code is incorrect on cpus lacking arith shift */ |
| 170 | 170 | ||
| 171 | center = (500*center)>>15; | 171 | center = (500 * center) >> 15; |
| 172 | data[4] = LO(center); | 172 | data[4] = LO(center); |
| 173 | data[5] = HI(center); | 173 | data[5] = HI(center); |
| 174 | 174 | ||
| 175 | db = (1000*db)>>16; | 175 | db = (1000 * db) >> 16; |
| 176 | data[6] = LO(db); | 176 | data[6] = LO(db); |
| 177 | data[7] = HI(db); | 177 | data[7] = HI(db); |
| 178 | 178 | ||
| 179 | data[8] = (100*rsat)>>16; | 179 | data[8] = (100 * rsat) >> 16; |
| 180 | data[9] = (100*lsat)>>16; | 180 | data[9] = (100 * lsat) >> 16; |
| 181 | 181 | ||
| 182 | iforce_send_packet(iforce, FF_CMD_CONDITION, data); | 182 | iforce_send_packet(iforce, FF_CMD_CONDITION, data); |
| 183 | iforce_dump_packet("condition", FF_CMD_CONDITION, data); | 183 | iforce_dump_packet("condition", FF_CMD_CONDITION, data); |
| @@ -188,6 +188,7 @@ static int make_condition_modifier(struct iforce* iforce, | |||
| 188 | static unsigned char find_button(struct iforce *iforce, signed short button) | 188 | static unsigned char find_button(struct iforce *iforce, signed short button) |
| 189 | { | 189 | { |
| 190 | int i; | 190 | int i; |
| 191 | |||
| 191 | for (i = 1; iforce->type->btn[i] >= 0; i++) | 192 | for (i = 1; iforce->type->btn[i] >= 0; i++) |
| 192 | if (iforce->type->btn[i] == button) | 193 | if (iforce->type->btn[i] == button) |
| 193 | return i + 1; | 194 | return i + 1; |
| @@ -198,19 +199,17 @@ static unsigned char find_button(struct iforce *iforce, signed short button) | |||
| 198 | * Analyse the changes in an effect, and tell if we need to send an condition | 199 | * Analyse the changes in an effect, and tell if we need to send an condition |
| 199 | * parameter packet | 200 | * parameter packet |
| 200 | */ | 201 | */ |
| 201 | static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new) | 202 | static int need_condition_modifier(struct ff_effect *old, struct ff_effect *new) |
| 202 | { | 203 | { |
| 203 | int id = new->id; | 204 | int ret = 0; |
| 204 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
| 205 | int ret=0; | ||
| 206 | int i; | 205 | int i; |
| 207 | 206 | ||
| 208 | if (new->type != FF_SPRING && new->type != FF_FRICTION) { | 207 | if (new->type != FF_SPRING && new->type != FF_FRICTION) { |
| 209 | printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n"); | 208 | printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n"); |
| 210 | return FALSE; | 209 | return 0; |
| 211 | } | 210 | } |
| 212 | 211 | ||
| 213 | for(i=0; i<2; i++) { | 212 | for (i = 0; i < 2; i++) { |
| 214 | ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation | 213 | ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation |
| 215 | || old->u.condition[i].left_saturation != new->u.condition[i].left_saturation | 214 | || old->u.condition[i].left_saturation != new->u.condition[i].left_saturation |
| 216 | || old->u.condition[i].right_coeff != new->u.condition[i].right_coeff | 215 | || old->u.condition[i].right_coeff != new->u.condition[i].right_coeff |
| @@ -225,35 +224,29 @@ static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new) | |||
| 225 | * Analyse the changes in an effect, and tell if we need to send a magnitude | 224 | * Analyse the changes in an effect, and tell if we need to send a magnitude |
| 226 | * parameter packet | 225 | * parameter packet |
| 227 | */ | 226 | */ |
| 228 | static int need_magnitude_modifier(struct iforce* iforce, struct ff_effect* effect) | 227 | static int need_magnitude_modifier(struct ff_effect *old, struct ff_effect *effect) |
| 229 | { | 228 | { |
| 230 | int id = effect->id; | ||
| 231 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
| 232 | |||
| 233 | if (effect->type != FF_CONSTANT) { | 229 | if (effect->type != FF_CONSTANT) { |
| 234 | printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); | 230 | printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); |
| 235 | return FALSE; | 231 | return 0; |
| 236 | } | 232 | } |
| 237 | 233 | ||
| 238 | return (old->u.constant.level != effect->u.constant.level); | 234 | return old->u.constant.level != effect->u.constant.level; |
| 239 | } | 235 | } |
| 240 | 236 | ||
| 241 | /* | 237 | /* |
| 242 | * Analyse the changes in an effect, and tell if we need to send an envelope | 238 | * Analyse the changes in an effect, and tell if we need to send an envelope |
| 243 | * parameter packet | 239 | * parameter packet |
| 244 | */ | 240 | */ |
| 245 | static int need_envelope_modifier(struct iforce* iforce, struct ff_effect* effect) | 241 | static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effect) |
| 246 | { | 242 | { |
| 247 | int id = effect->id; | ||
| 248 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
| 249 | |||
| 250 | switch (effect->type) { | 243 | switch (effect->type) { |
| 251 | case FF_CONSTANT: | 244 | case FF_CONSTANT: |
| 252 | if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length | 245 | if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length |
| 253 | || old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level | 246 | || old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level |
| 254 | || old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length | 247 | || old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length |
| 255 | || old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level) | 248 | || old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level) |
| 256 | return TRUE; | 249 | return 1; |
| 257 | break; | 250 | break; |
| 258 | 251 | ||
| 259 | case FF_PERIODIC: | 252 | case FF_PERIODIC: |
| @@ -261,30 +254,26 @@ static int need_envelope_modifier(struct iforce* iforce, struct ff_effect* effec | |||
| 261 | || old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level | 254 | || old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level |
| 262 | || old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length | 255 | || old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length |
| 263 | || old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level) | 256 | || old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level) |
| 264 | return TRUE; | 257 | return 1; |
| 265 | break; | 258 | break; |
| 266 | 259 | ||
| 267 | default: | 260 | default: |
| 268 | printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); | 261 | printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); |
| 269 | } | 262 | } |
| 270 | 263 | ||
| 271 | return FALSE; | 264 | return 0; |
| 272 | } | 265 | } |
| 273 | 266 | ||
| 274 | /* | 267 | /* |
| 275 | * Analyse the changes in an effect, and tell if we need to send a periodic | 268 | * Analyse the changes in an effect, and tell if we need to send a periodic |
| 276 | * parameter effect | 269 | * parameter effect |
| 277 | */ | 270 | */ |
| 278 | static int need_period_modifier(struct iforce* iforce, struct ff_effect* new) | 271 | static int need_period_modifier(struct ff_effect *old, struct ff_effect *new) |
| 279 | { | 272 | { |
| 280 | int id = new->id; | ||
| 281 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
| 282 | |||
| 283 | if (new->type != FF_PERIODIC) { | 273 | if (new->type != FF_PERIODIC) { |
| 284 | printk(KERN_WARNING "iforce.c: bad effect type in need_periodic_modifier\n"); | 274 | printk(KERN_WARNING "iforce.c: bad effect type in need_period_modifier\n"); |
| 285 | return FALSE; | 275 | return 0; |
| 286 | } | 276 | } |
| 287 | |||
| 288 | return (old->u.periodic.period != new->u.periodic.period | 277 | return (old->u.periodic.period != new->u.periodic.period |
| 289 | || old->u.periodic.magnitude != new->u.periodic.magnitude | 278 | || old->u.periodic.magnitude != new->u.periodic.magnitude |
| 290 | || old->u.periodic.offset != new->u.periodic.offset | 279 | || old->u.periodic.offset != new->u.periodic.offset |
| @@ -295,19 +284,16 @@ static int need_period_modifier(struct iforce* iforce, struct ff_effect* new) | |||
| 295 | * Analyse the changes in an effect, and tell if we need to send an effect | 284 | * Analyse the changes in an effect, and tell if we need to send an effect |
| 296 | * packet | 285 | * packet |
| 297 | */ | 286 | */ |
| 298 | static int need_core(struct iforce* iforce, struct ff_effect* new) | 287 | static int need_core(struct ff_effect *old, struct ff_effect *new) |
| 299 | { | 288 | { |
| 300 | int id = new->id; | ||
| 301 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
| 302 | |||
| 303 | if (old->direction != new->direction | 289 | if (old->direction != new->direction |
| 304 | || old->trigger.button != new->trigger.button | 290 | || old->trigger.button != new->trigger.button |
| 305 | || old->trigger.interval != new->trigger.interval | 291 | || old->trigger.interval != new->trigger.interval |
| 306 | || old->replay.length != new->replay.length | 292 | || old->replay.length != new->replay.length |
| 307 | || old->replay.delay != new->replay.delay) | 293 | || old->replay.delay != new->replay.delay) |
| 308 | return TRUE; | 294 | return 1; |
| 309 | 295 | ||
| 310 | return FALSE; | 296 | return 0; |
| 311 | } | 297 | } |
| 312 | /* | 298 | /* |
| 313 | * Send the part common to all effects to the device | 299 | * Send the part common to all effects to the device |
| @@ -360,7 +346,7 @@ static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, | |||
| 360 | * Upload a periodic effect to the device | 346 | * Upload a periodic effect to the device |
| 361 | * See also iforce_upload_constant. | 347 | * See also iforce_upload_constant. |
| 362 | */ | 348 | */ |
| 363 | int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int is_update) | 349 | int iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) |
| 364 | { | 350 | { |
| 365 | u8 wave_code; | 351 | u8 wave_code; |
| 366 | int core_id = effect->id; | 352 | int core_id = effect->id; |
| @@ -371,23 +357,25 @@ int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int | |||
| 371 | int param2_err = 1; | 357 | int param2_err = 1; |
| 372 | int core_err = 0; | 358 | int core_err = 0; |
| 373 | 359 | ||
| 374 | if (!is_update || need_period_modifier(iforce, effect)) { | 360 | if (!old || need_period_modifier(old, effect)) { |
| 375 | param1_err = make_period_modifier(iforce, mod1_chunk, | 361 | param1_err = make_period_modifier(iforce, mod1_chunk, |
| 376 | is_update, | 362 | old != NULL, |
| 377 | effect->u.periodic.magnitude, effect->u.periodic.offset, | 363 | effect->u.periodic.magnitude, effect->u.periodic.offset, |
| 378 | effect->u.periodic.period, effect->u.periodic.phase); | 364 | effect->u.periodic.period, effect->u.periodic.phase); |
| 379 | if (param1_err) return param1_err; | 365 | if (param1_err) |
| 366 | return param1_err; | ||
| 380 | set_bit(FF_MOD1_IS_USED, core_effect->flags); | 367 | set_bit(FF_MOD1_IS_USED, core_effect->flags); |
| 381 | } | 368 | } |
| 382 | 369 | ||
| 383 | if (!is_update || need_envelope_modifier(iforce, effect)) { | 370 | if (!old || need_envelope_modifier(old, effect)) { |
| 384 | param2_err = make_envelope_modifier(iforce, mod2_chunk, | 371 | param2_err = make_envelope_modifier(iforce, mod2_chunk, |
| 385 | is_update, | 372 | old !=NULL, |
| 386 | effect->u.periodic.envelope.attack_length, | 373 | effect->u.periodic.envelope.attack_length, |
| 387 | effect->u.periodic.envelope.attack_level, | 374 | effect->u.periodic.envelope.attack_level, |
| 388 | effect->u.periodic.envelope.fade_length, | 375 | effect->u.periodic.envelope.fade_length, |
| 389 | effect->u.periodic.envelope.fade_level); | 376 | effect->u.periodic.envelope.fade_level); |
| 390 | if (param2_err) return param2_err; | 377 | if (param2_err) |
| 378 | return param2_err; | ||
| 391 | set_bit(FF_MOD2_IS_USED, core_effect->flags); | 379 | set_bit(FF_MOD2_IS_USED, core_effect->flags); |
| 392 | } | 380 | } |
| 393 | 381 | ||
| @@ -400,7 +388,7 @@ int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int | |||
| 400 | default: wave_code = 0x20; break; | 388 | default: wave_code = 0x20; break; |
| 401 | } | 389 | } |
| 402 | 390 | ||
| 403 | if (!is_update || need_core(iforce, effect)) { | 391 | if (!old || need_core(old, effect)) { |
| 404 | core_err = make_core(iforce, effect->id, | 392 | core_err = make_core(iforce, effect->id, |
| 405 | mod1_chunk->start, | 393 | mod1_chunk->start, |
| 406 | mod2_chunk->start, | 394 | mod2_chunk->start, |
| @@ -429,7 +417,7 @@ int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int | |||
| 429 | * 0 Ok, effect created or updated | 417 | * 0 Ok, effect created or updated |
| 430 | * 1 effect did not change since last upload, and no packet was therefore sent | 418 | * 1 effect did not change since last upload, and no packet was therefore sent |
| 431 | */ | 419 | */ |
| 432 | int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int is_update) | 420 | int iforce_upload_constant(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) |
| 433 | { | 421 | { |
| 434 | int core_id = effect->id; | 422 | int core_id = effect->id; |
| 435 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | 423 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; |
| @@ -439,26 +427,28 @@ int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int | |||
| 439 | int param2_err = 1; | 427 | int param2_err = 1; |
| 440 | int core_err = 0; | 428 | int core_err = 0; |
| 441 | 429 | ||
| 442 | if (!is_update || need_magnitude_modifier(iforce, effect)) { | 430 | if (!old || need_magnitude_modifier(old, effect)) { |
| 443 | param1_err = make_magnitude_modifier(iforce, mod1_chunk, | 431 | param1_err = make_magnitude_modifier(iforce, mod1_chunk, |
| 444 | is_update, | 432 | old != NULL, |
| 445 | effect->u.constant.level); | 433 | effect->u.constant.level); |
| 446 | if (param1_err) return param1_err; | 434 | if (param1_err) |
| 435 | return param1_err; | ||
| 447 | set_bit(FF_MOD1_IS_USED, core_effect->flags); | 436 | set_bit(FF_MOD1_IS_USED, core_effect->flags); |
| 448 | } | 437 | } |
| 449 | 438 | ||
| 450 | if (!is_update || need_envelope_modifier(iforce, effect)) { | 439 | if (!old || need_envelope_modifier(old, effect)) { |
| 451 | param2_err = make_envelope_modifier(iforce, mod2_chunk, | 440 | param2_err = make_envelope_modifier(iforce, mod2_chunk, |
| 452 | is_update, | 441 | old != NULL, |
| 453 | effect->u.constant.envelope.attack_length, | 442 | effect->u.constant.envelope.attack_length, |
| 454 | effect->u.constant.envelope.attack_level, | 443 | effect->u.constant.envelope.attack_level, |
| 455 | effect->u.constant.envelope.fade_length, | 444 | effect->u.constant.envelope.fade_length, |
| 456 | effect->u.constant.envelope.fade_level); | 445 | effect->u.constant.envelope.fade_level); |
| 457 | if (param2_err) return param2_err; | 446 | if (param2_err) |
| 447 | return param2_err; | ||
| 458 | set_bit(FF_MOD2_IS_USED, core_effect->flags); | 448 | set_bit(FF_MOD2_IS_USED, core_effect->flags); |
| 459 | } | 449 | } |
| 460 | 450 | ||
| 461 | if (!is_update || need_core(iforce, effect)) { | 451 | if (!old || need_core(old, effect)) { |
| 462 | core_err = make_core(iforce, effect->id, | 452 | core_err = make_core(iforce, effect->id, |
| 463 | mod1_chunk->start, | 453 | mod1_chunk->start, |
| 464 | mod2_chunk->start, | 454 | mod2_chunk->start, |
| @@ -483,7 +473,7 @@ int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int | |||
| 483 | /* | 473 | /* |
| 484 | * Upload an condition effect. Those are for example friction, inertia, springs... | 474 | * Upload an condition effect. Those are for example friction, inertia, springs... |
| 485 | */ | 475 | */ |
| 486 | int iforce_upload_condition(struct iforce* iforce, struct ff_effect* effect, int is_update) | 476 | int iforce_upload_condition(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) |
| 487 | { | 477 | { |
| 488 | int core_id = effect->id; | 478 | int core_id = effect->id; |
| 489 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | 479 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; |
| @@ -494,37 +484,39 @@ int iforce_upload_condition(struct iforce* iforce, struct ff_effect* effect, int | |||
| 494 | int core_err = 0; | 484 | int core_err = 0; |
| 495 | 485 | ||
| 496 | switch (effect->type) { | 486 | switch (effect->type) { |
| 497 | case FF_SPRING: type = 0x40; break; | 487 | case FF_SPRING: type = 0x40; break; |
| 498 | case FF_DAMPER: type = 0x41; break; | 488 | case FF_DAMPER: type = 0x41; break; |
| 499 | default: return -1; | 489 | default: return -1; |
| 500 | } | 490 | } |
| 501 | 491 | ||
| 502 | if (!is_update || need_condition_modifier(iforce, effect)) { | 492 | if (!old || need_condition_modifier(old, effect)) { |
| 503 | param_err = make_condition_modifier(iforce, mod1_chunk, | 493 | param_err = make_condition_modifier(iforce, mod1_chunk, |
| 504 | is_update, | 494 | old != NULL, |
| 505 | effect->u.condition[0].right_saturation, | 495 | effect->u.condition[0].right_saturation, |
| 506 | effect->u.condition[0].left_saturation, | 496 | effect->u.condition[0].left_saturation, |
| 507 | effect->u.condition[0].right_coeff, | 497 | effect->u.condition[0].right_coeff, |
| 508 | effect->u.condition[0].left_coeff, | 498 | effect->u.condition[0].left_coeff, |
| 509 | effect->u.condition[0].deadband, | 499 | effect->u.condition[0].deadband, |
| 510 | effect->u.condition[0].center); | 500 | effect->u.condition[0].center); |
| 511 | if (param_err) return param_err; | 501 | if (param_err) |
| 502 | return param_err; | ||
| 512 | set_bit(FF_MOD1_IS_USED, core_effect->flags); | 503 | set_bit(FF_MOD1_IS_USED, core_effect->flags); |
| 513 | 504 | ||
| 514 | param_err = make_condition_modifier(iforce, mod2_chunk, | 505 | param_err = make_condition_modifier(iforce, mod2_chunk, |
| 515 | is_update, | 506 | old != NULL, |
| 516 | effect->u.condition[1].right_saturation, | 507 | effect->u.condition[1].right_saturation, |
| 517 | effect->u.condition[1].left_saturation, | 508 | effect->u.condition[1].left_saturation, |
| 518 | effect->u.condition[1].right_coeff, | 509 | effect->u.condition[1].right_coeff, |
| 519 | effect->u.condition[1].left_coeff, | 510 | effect->u.condition[1].left_coeff, |
| 520 | effect->u.condition[1].deadband, | 511 | effect->u.condition[1].deadband, |
| 521 | effect->u.condition[1].center); | 512 | effect->u.condition[1].center); |
| 522 | if (param_err) return param_err; | 513 | if (param_err) |
| 514 | return param_err; | ||
| 523 | set_bit(FF_MOD2_IS_USED, core_effect->flags); | 515 | set_bit(FF_MOD2_IS_USED, core_effect->flags); |
| 524 | 516 | ||
| 525 | } | 517 | } |
| 526 | 518 | ||
| 527 | if (!is_update || need_core(iforce, effect)) { | 519 | if (!old || need_core(old, effect)) { |
| 528 | core_err = make_core(iforce, effect->id, | 520 | core_err = make_core(iforce, effect->id, |
| 529 | mod1_chunk->start, mod2_chunk->start, | 521 | mod1_chunk->start, mod2_chunk->start, |
| 530 | type, 0xc0, | 522 | type, 0xc0, |
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index b4914e7231..24c684bc63 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c | |||
| @@ -83,103 +83,57 @@ static struct iforce_device iforce_device[] = { | |||
| 83 | { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } | 83 | { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } |
| 84 | }; | 84 | }; |
| 85 | 85 | ||
| 86 | 86 | static int iforce_playback(struct input_dev *dev, int effect_id, int value) | |
| 87 | |||
| 88 | static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
| 89 | { | 87 | { |
| 90 | struct iforce* iforce = dev->private; | 88 | struct iforce* iforce = dev->private; |
| 91 | unsigned char data[3]; | 89 | struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id]; |
| 92 | |||
| 93 | if (type != EV_FF) | ||
| 94 | return -1; | ||
| 95 | |||
| 96 | switch (code) { | ||
| 97 | |||
| 98 | case FF_GAIN: | ||
| 99 | |||
| 100 | data[0] = value >> 9; | ||
| 101 | iforce_send_packet(iforce, FF_CMD_GAIN, data); | ||
| 102 | |||
| 103 | return 0; | ||
| 104 | |||
| 105 | case FF_AUTOCENTER: | ||
| 106 | 90 | ||
| 107 | data[0] = 0x03; | 91 | if (value > 0) |
| 108 | data[1] = value >> 9; | 92 | set_bit(FF_CORE_SHOULD_PLAY, core_effect->flags); |
| 109 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); | 93 | else |
| 94 | clear_bit(FF_CORE_SHOULD_PLAY, core_effect->flags); | ||
| 110 | 95 | ||
| 111 | data[0] = 0x04; | 96 | iforce_control_playback(iforce, effect_id, value); |
| 112 | data[1] = 0x01; | 97 | return 0; |
| 113 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); | 98 | } |
| 114 | 99 | ||
| 115 | return 0; | 100 | static void iforce_set_gain(struct input_dev *dev, u16 gain) |
| 101 | { | ||
| 102 | struct iforce* iforce = dev->private; | ||
| 103 | unsigned char data[3]; | ||
| 116 | 104 | ||
| 117 | default: /* Play or stop an effect */ | 105 | data[0] = gain >> 9; |
| 106 | iforce_send_packet(iforce, FF_CMD_GAIN, data); | ||
| 107 | } | ||
| 118 | 108 | ||
| 119 | if (!CHECK_OWNERSHIP(code, iforce)) { | 109 | static void iforce_set_autocenter(struct input_dev *dev, u16 magnitude) |
| 120 | return -1; | 110 | { |
| 121 | } | 111 | struct iforce* iforce = dev->private; |
| 122 | if (value > 0) { | 112 | unsigned char data[3]; |
| 123 | set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); | ||
| 124 | } | ||
| 125 | else { | ||
| 126 | clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); | ||
| 127 | } | ||
| 128 | 113 | ||
| 129 | iforce_control_playback(iforce, code, value); | 114 | data[0] = 0x03; |
| 130 | return 0; | 115 | data[1] = magnitude >> 9; |
| 131 | } | 116 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); |
| 132 | 117 | ||
| 133 | return -1; | 118 | data[0] = 0x04; |
| 119 | data[1] = 0x01; | ||
| 120 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); | ||
| 134 | } | 121 | } |
| 135 | 122 | ||
| 136 | /* | 123 | /* |
| 137 | * Function called when an ioctl is performed on the event dev entry. | 124 | * Function called when an ioctl is performed on the event dev entry. |
| 138 | * It uploads an effect to the device | 125 | * It uploads an effect to the device |
| 139 | */ | 126 | */ |
| 140 | static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) | 127 | static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) |
| 141 | { | 128 | { |
| 142 | struct iforce* iforce = dev->private; | 129 | struct iforce* iforce = dev->private; |
| 143 | int id; | 130 | struct iforce_core_effect *core_effect = &iforce->core_effects[effect->id]; |
| 144 | int ret; | 131 | int ret; |
| 145 | int is_update; | ||
| 146 | |||
| 147 | /* Check this effect type is supported by this device */ | ||
| 148 | if (!test_bit(effect->type, iforce->dev->ffbit)) | ||
| 149 | return -EINVAL; | ||
| 150 | |||
| 151 | /* | ||
| 152 | * If we want to create a new effect, get a free id | ||
| 153 | */ | ||
| 154 | if (effect->id == -1) { | ||
| 155 | |||
| 156 | for (id = 0; id < FF_EFFECTS_MAX; ++id) | ||
| 157 | if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) | ||
| 158 | break; | ||
| 159 | |||
| 160 | if (id == FF_EFFECTS_MAX || id >= iforce->dev->ff_effects_max) | ||
| 161 | return -ENOMEM; | ||
| 162 | |||
| 163 | effect->id = id; | ||
| 164 | iforce->core_effects[id].owner = current->pid; | ||
| 165 | iforce->core_effects[id].flags[0] = (1 << FF_CORE_IS_USED); /* Only IS_USED bit must be set */ | ||
| 166 | |||
| 167 | is_update = FALSE; | ||
| 168 | } | ||
| 169 | else { | ||
| 170 | /* We want to update an effect */ | ||
| 171 | if (!CHECK_OWNERSHIP(effect->id, iforce)) | ||
| 172 | return -EACCES; | ||
| 173 | |||
| 174 | /* Parameter type cannot be updated */ | ||
| 175 | if (effect->type != iforce->core_effects[effect->id].effect.type) | ||
| 176 | return -EINVAL; | ||
| 177 | 132 | ||
| 133 | if (__test_and_set_bit(FF_CORE_IS_USED, core_effect->flags)) { | ||
| 178 | /* Check the effect is not already being updated */ | 134 | /* Check the effect is not already being updated */ |
| 179 | if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) | 135 | if (test_bit(FF_CORE_UPDATE, core_effect->flags)) |
| 180 | return -EAGAIN; | 136 | return -EAGAIN; |
| 181 | |||
| 182 | is_update = TRUE; | ||
| 183 | } | 137 | } |
| 184 | 138 | ||
| 185 | /* | 139 | /* |
| @@ -188,28 +142,28 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) | |||
| 188 | switch (effect->type) { | 142 | switch (effect->type) { |
| 189 | 143 | ||
| 190 | case FF_PERIODIC: | 144 | case FF_PERIODIC: |
| 191 | ret = iforce_upload_periodic(iforce, effect, is_update); | 145 | ret = iforce_upload_periodic(iforce, effect, old); |
| 192 | break; | 146 | break; |
| 193 | 147 | ||
| 194 | case FF_CONSTANT: | 148 | case FF_CONSTANT: |
| 195 | ret = iforce_upload_constant(iforce, effect, is_update); | 149 | ret = iforce_upload_constant(iforce, effect, old); |
| 196 | break; | 150 | break; |
| 197 | 151 | ||
| 198 | case FF_SPRING: | 152 | case FF_SPRING: |
| 199 | case FF_DAMPER: | 153 | case FF_DAMPER: |
| 200 | ret = iforce_upload_condition(iforce, effect, is_update); | 154 | ret = iforce_upload_condition(iforce, effect, old); |
| 201 | break; | 155 | break; |
| 202 | 156 | ||
| 203 | default: | 157 | default: |
| 204 | return -EINVAL; | 158 | return -EINVAL; |
| 205 | } | 159 | } |
| 160 | |||
| 206 | if (ret == 0) { | 161 | if (ret == 0) { |
| 207 | /* A packet was sent, forbid new updates until we are notified | 162 | /* A packet was sent, forbid new updates until we are notified |
| 208 | * that the packet was updated | 163 | * that the packet was updated |
| 209 | */ | 164 | */ |
| 210 | set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags); | 165 | set_bit(FF_CORE_UPDATE, core_effect->flags); |
| 211 | } | 166 | } |
| 212 | iforce->core_effects[effect->id].effect = *effect; | ||
| 213 | return ret; | 167 | return ret; |
| 214 | } | 168 | } |
| 215 | 169 | ||
| @@ -219,20 +173,9 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) | |||
| 219 | */ | 173 | */ |
| 220 | static int iforce_erase_effect(struct input_dev *dev, int effect_id) | 174 | static int iforce_erase_effect(struct input_dev *dev, int effect_id) |
| 221 | { | 175 | { |
| 222 | struct iforce* iforce = dev->private; | 176 | struct iforce *iforce = dev->private; |
| 177 | struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id]; | ||
| 223 | int err = 0; | 178 | int err = 0; |
| 224 | struct iforce_core_effect* core_effect; | ||
| 225 | |||
| 226 | if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) | ||
| 227 | return -EINVAL; | ||
| 228 | |||
| 229 | core_effect = &iforce->core_effects[effect_id]; | ||
| 230 | |||
| 231 | /* Check who is trying to erase this effect */ | ||
| 232 | if (core_effect->owner != current->pid) { | ||
| 233 | printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, core_effect->owner); | ||
| 234 | return -EACCES; | ||
| 235 | } | ||
| 236 | 179 | ||
| 237 | if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) | 180 | if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) |
| 238 | err = release_resource(&core_effect->mod1_chunk); | 181 | err = release_resource(&core_effect->mod1_chunk); |
| @@ -240,7 +183,7 @@ static int iforce_erase_effect(struct input_dev *dev, int effect_id) | |||
| 240 | if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) | 183 | if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) |
| 241 | err = release_resource(&core_effect->mod2_chunk); | 184 | err = release_resource(&core_effect->mod2_chunk); |
| 242 | 185 | ||
| 243 | /*TODO: remember to change that if more FF_MOD* bits are added */ | 186 | /* TODO: remember to change that if more FF_MOD* bits are added */ |
| 244 | core_effect->flags[0] = 0; | 187 | core_effect->flags[0] = 0; |
| 245 | 188 | ||
| 246 | return err; | 189 | return err; |
| @@ -260,52 +203,31 @@ static int iforce_open(struct input_dev *dev) | |||
| 260 | #endif | 203 | #endif |
| 261 | } | 204 | } |
| 262 | 205 | ||
| 263 | /* Enable force feedback */ | 206 | if (test_bit(EV_FF, dev->evbit)) { |
| 264 | iforce_send_packet(iforce, FF_CMD_ENABLE, "\004"); | 207 | /* Enable force feedback */ |
| 208 | iforce_send_packet(iforce, FF_CMD_ENABLE, "\004"); | ||
| 209 | } | ||
| 265 | 210 | ||
| 266 | return 0; | 211 | return 0; |
| 267 | } | 212 | } |
| 268 | 213 | ||
| 269 | static int iforce_flush(struct input_dev *dev, struct file *file) | 214 | static void iforce_release(struct input_dev *dev) |
| 270 | { | 215 | { |
| 271 | struct iforce *iforce = dev->private; | 216 | struct iforce *iforce = dev->private; |
| 272 | int i; | 217 | int i; |
| 273 | 218 | ||
| 274 | /* Erase all effects this process owns */ | 219 | if (test_bit(EV_FF, dev->evbit)) { |
| 275 | for (i=0; i<dev->ff_effects_max; ++i) { | 220 | /* Check: no effects should be present in memory */ |
| 276 | 221 | for (i = 0; i < dev->ff->max_effects; i++) { | |
| 277 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && | 222 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) { |
| 278 | current->pid == iforce->core_effects[i].owner) { | 223 | printk(KERN_WARNING "iforce_release: Device still owns effects\n"); |
| 279 | 224 | break; | |
| 280 | /* Stop effect */ | ||
| 281 | input_report_ff(dev, i, 0); | ||
| 282 | |||
| 283 | /* Free ressources assigned to effect */ | ||
| 284 | if (iforce_erase_effect(dev, i)) { | ||
| 285 | printk(KERN_WARNING "iforce_flush: erase effect %d failed\n", i); | ||
| 286 | } | 225 | } |
| 287 | } | 226 | } |
| 288 | 227 | ||
| 228 | /* Disable force feedback playback */ | ||
| 229 | iforce_send_packet(iforce, FF_CMD_ENABLE, "\001"); | ||
| 289 | } | 230 | } |
| 290 | return 0; | ||
| 291 | } | ||
| 292 | |||
| 293 | static void iforce_release(struct input_dev *dev) | ||
| 294 | { | ||
| 295 | struct iforce *iforce = dev->private; | ||
| 296 | int i; | ||
| 297 | |||
| 298 | /* Check: no effect should be present in memory */ | ||
| 299 | for (i=0; i<dev->ff_effects_max; ++i) { | ||
| 300 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) | ||
| 301 | break; | ||
| 302 | } | ||
| 303 | if (i<dev->ff_effects_max) { | ||
| 304 | printk(KERN_WARNING "iforce_release: Device still owns effects\n"); | ||
| 305 | } | ||
| 306 | |||
| 307 | /* Disable force feedback playback */ | ||
| 308 | iforce_send_packet(iforce, FF_CMD_ENABLE, "\001"); | ||
| 309 | 231 | ||
| 310 | switch (iforce->bus) { | 232 | switch (iforce->bus) { |
| 311 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | 233 | #ifdef CONFIG_JOYSTICK_IFORCE_USB |
| @@ -342,8 +264,10 @@ void iforce_delete_device(struct iforce *iforce) | |||
| 342 | int iforce_init_device(struct iforce *iforce) | 264 | int iforce_init_device(struct iforce *iforce) |
| 343 | { | 265 | { |
| 344 | struct input_dev *input_dev; | 266 | struct input_dev *input_dev; |
| 267 | struct ff_device *ff; | ||
| 345 | unsigned char c[] = "CEOV"; | 268 | unsigned char c[] = "CEOV"; |
| 346 | int i; | 269 | int i, error; |
| 270 | int ff_effects = 0; | ||
| 347 | 271 | ||
| 348 | input_dev = input_allocate_device(); | 272 | input_dev = input_allocate_device(); |
| 349 | if (!input_dev) | 273 | if (!input_dev) |
| @@ -378,11 +302,6 @@ int iforce_init_device(struct iforce *iforce) | |||
| 378 | input_dev->name = "Unknown I-Force device"; | 302 | input_dev->name = "Unknown I-Force device"; |
| 379 | input_dev->open = iforce_open; | 303 | input_dev->open = iforce_open; |
| 380 | input_dev->close = iforce_release; | 304 | input_dev->close = iforce_release; |
| 381 | input_dev->flush = iforce_flush; | ||
| 382 | input_dev->event = iforce_input_event; | ||
| 383 | input_dev->upload_effect = iforce_upload_effect; | ||
| 384 | input_dev->erase_effect = iforce_erase_effect; | ||
| 385 | input_dev->ff_effects_max = 10; | ||
| 386 | 305 | ||
| 387 | /* | 306 | /* |
| 388 | * On-device memory allocation. | 307 | * On-device memory allocation. |
| @@ -430,15 +349,15 @@ int iforce_init_device(struct iforce *iforce) | |||
| 430 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n"); | 349 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n"); |
| 431 | 350 | ||
| 432 | if (!iforce_get_id_packet(iforce, "N")) | 351 | if (!iforce_get_id_packet(iforce, "N")) |
| 433 | iforce->dev->ff_effects_max = iforce->edata[1]; | 352 | ff_effects = iforce->edata[1]; |
| 434 | else | 353 | else |
| 435 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n"); | 354 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n"); |
| 436 | 355 | ||
| 437 | /* Check if the device can store more effects than the driver can really handle */ | 356 | /* Check if the device can store more effects than the driver can really handle */ |
| 438 | if (iforce->dev->ff_effects_max > FF_EFFECTS_MAX) { | 357 | if (ff_effects > IFORCE_EFFECTS_MAX) { |
| 439 | printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n", | 358 | printk(KERN_WARNING "iforce: Limiting number of effects to %d (device reports %d)\n", |
| 440 | iforce->dev->ff_effects_max, FF_EFFECTS_MAX); | 359 | IFORCE_EFFECTS_MAX, ff_effects); |
| 441 | iforce->dev->ff_effects_max = FF_EFFECTS_MAX; | 360 | ff_effects = IFORCE_EFFECTS_MAX; |
| 442 | } | 361 | } |
| 443 | 362 | ||
| 444 | /* | 363 | /* |
| @@ -472,12 +391,10 @@ int iforce_init_device(struct iforce *iforce) | |||
| 472 | * Set input device bitfields and ranges. | 391 | * Set input device bitfields and ranges. |
| 473 | */ | 392 | */ |
| 474 | 393 | ||
| 475 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); | 394 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF_STATUS); |
| 476 | 395 | ||
| 477 | for (i = 0; iforce->type->btn[i] >= 0; i++) { | 396 | for (i = 0; iforce->type->btn[i] >= 0; i++) |
| 478 | signed short t = iforce->type->btn[i]; | 397 | set_bit(iforce->type->btn[i], input_dev->keybit); |
| 479 | set_bit(t, input_dev->keybit); | ||
| 480 | } | ||
| 481 | set_bit(BTN_DEAD, input_dev->keybit); | 398 | set_bit(BTN_DEAD, input_dev->keybit); |
| 482 | 399 | ||
| 483 | for (i = 0; iforce->type->abs[i] >= 0; i++) { | 400 | for (i = 0; iforce->type->abs[i] >= 0; i++) { |
| @@ -516,9 +433,24 @@ int iforce_init_device(struct iforce *iforce) | |||
| 516 | } | 433 | } |
| 517 | } | 434 | } |
| 518 | 435 | ||
| 519 | for (i = 0; iforce->type->ff[i] >= 0; i++) | 436 | if (ff_effects) { |
| 520 | set_bit(iforce->type->ff[i], input_dev->ffbit); | ||
| 521 | 437 | ||
| 438 | for (i = 0; iforce->type->ff[i] >= 0; i++) | ||
| 439 | set_bit(iforce->type->ff[i], input_dev->ffbit); | ||
| 440 | |||
| 441 | error = input_ff_create(input_dev, ff_effects); | ||
| 442 | if (error) { | ||
| 443 | input_free_device(input_dev); | ||
| 444 | return error; | ||
| 445 | } | ||
| 446 | |||
| 447 | ff = input_dev->ff; | ||
| 448 | ff->upload = iforce_upload_effect; | ||
| 449 | ff->erase = iforce_erase_effect; | ||
| 450 | ff->set_gain = iforce_set_gain; | ||
| 451 | ff->set_autocenter = iforce_set_autocenter; | ||
| 452 | ff->playback = iforce_playback; | ||
| 453 | } | ||
| 522 | /* | 454 | /* |
| 523 | * Register input device. | 455 | * Register input device. |
| 524 | */ | 456 | */ |
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 76cb1f88f4..8632d47a7f 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c | |||
| @@ -140,7 +140,10 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) | |||
| 140 | { | 140 | { |
| 141 | int i; | 141 | int i; |
| 142 | 142 | ||
| 143 | for (i = 0; i < iforce->dev->ff_effects_max; ++i) { | 143 | if (!iforce->dev->ff) |
| 144 | return 0; | ||
| 145 | |||
| 146 | for (i = 0; i < iforce->dev->ff->max_effects; ++i) { | ||
| 144 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && | 147 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && |
| 145 | (iforce->core_effects[i].mod1_chunk.start == addr || | 148 | (iforce->core_effects[i].mod1_chunk.start == addr || |
| 146 | iforce->core_effects[i].mod2_chunk.start == addr)) { | 149 | iforce->core_effects[i].mod2_chunk.start == addr)) { |
| @@ -229,19 +232,17 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, | |||
| 229 | i = data[1] & 0x7f; | 232 | i = data[1] & 0x7f; |
| 230 | if (data[1] & 0x80) { | 233 | if (data[1] & 0x80) { |
| 231 | if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { | 234 | if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { |
| 232 | /* Report play event */ | 235 | /* Report play event */ |
| 233 | input_report_ff_status(dev, i, FF_STATUS_PLAYING); | 236 | input_report_ff_status(dev, i, FF_STATUS_PLAYING); |
| 234 | } | 237 | } |
| 235 | } | 238 | } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { |
| 236 | else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { | ||
| 237 | /* Report stop event */ | 239 | /* Report stop event */ |
| 238 | input_report_ff_status(dev, i, FF_STATUS_STOPPED); | 240 | input_report_ff_status(dev, i, FF_STATUS_STOPPED); |
| 239 | } | 241 | } |
| 240 | if (LO(cmd) > 3) { | 242 | if (LO(cmd) > 3) { |
| 241 | int j; | 243 | int j; |
| 242 | for (j=3; j<LO(cmd); j+=2) { | 244 | for (j = 3; j < LO(cmd); j += 2) |
| 243 | mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); | 245 | mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); |
| 244 | } | ||
| 245 | } | 246 | } |
| 246 | break; | 247 | break; |
| 247 | } | 248 | } |
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index e9924d6f01..947df27398 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h | |||
| @@ -51,10 +51,7 @@ | |||
| 51 | #define IFORCE_232 1 | 51 | #define IFORCE_232 1 |
| 52 | #define IFORCE_USB 2 | 52 | #define IFORCE_USB 2 |
| 53 | 53 | ||
| 54 | #define FALSE 0 | 54 | #define IFORCE_EFFECTS_MAX 32 |
| 55 | #define TRUE 1 | ||
| 56 | |||
| 57 | #define FF_EFFECTS_MAX 32 | ||
| 58 | 55 | ||
| 59 | /* Each force feedback effect is made of one core effect, which can be | 56 | /* Each force feedback effect is made of one core effect, which can be |
| 60 | * associated to at most to effect modifiers | 57 | * associated to at most to effect modifiers |
| @@ -67,24 +64,11 @@ | |||
| 67 | #define FF_CORE_UPDATE 5 /* Effect is being updated */ | 64 | #define FF_CORE_UPDATE 5 /* Effect is being updated */ |
| 68 | #define FF_MODCORE_MAX 5 | 65 | #define FF_MODCORE_MAX 5 |
| 69 | 66 | ||
| 70 | #define CHECK_OWNERSHIP(i, iforce) \ | ||
| 71 | ((i) < FF_EFFECTS_MAX && i >= 0 && \ | ||
| 72 | test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \ | ||
| 73 | (current->pid == 0 || \ | ||
| 74 | (iforce)->core_effects[(i)].owner == current->pid)) | ||
| 75 | |||
| 76 | struct iforce_core_effect { | 67 | struct iforce_core_effect { |
| 77 | /* Information about where modifiers are stored in the device's memory */ | 68 | /* Information about where modifiers are stored in the device's memory */ |
| 78 | struct resource mod1_chunk; | 69 | struct resource mod1_chunk; |
| 79 | struct resource mod2_chunk; | 70 | struct resource mod2_chunk; |
| 80 | unsigned long flags[NBITS(FF_MODCORE_MAX)]; | 71 | unsigned long flags[NBITS(FF_MODCORE_MAX)]; |
| 81 | pid_t owner; | ||
| 82 | /* Used to keep track of parameters of an effect. They are needed | ||
| 83 | * to know what parts of an effect changed in an update operation. | ||
| 84 | * We try to send only parameter packets if possible, as sending | ||
| 85 | * effect parameter requires the effect to be stoped and restarted | ||
| 86 | */ | ||
| 87 | struct ff_effect effect; | ||
| 88 | }; | 72 | }; |
| 89 | 73 | ||
| 90 | #define FF_CMD_EFFECT 0x010e | 74 | #define FF_CMD_EFFECT 0x010e |
| @@ -145,7 +129,7 @@ struct iforce { | |||
| 145 | /* Force Feedback */ | 129 | /* Force Feedback */ |
| 146 | wait_queue_head_t wait; | 130 | wait_queue_head_t wait; |
| 147 | struct resource device_memory; | 131 | struct resource device_memory; |
| 148 | struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; | 132 | struct iforce_core_effect core_effects[IFORCE_EFFECTS_MAX]; |
| 149 | struct mutex mem_mutex; | 133 | struct mutex mem_mutex; |
| 150 | }; | 134 | }; |
| 151 | 135 | ||
| @@ -182,9 +166,9 @@ void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ; | |||
| 182 | int iforce_get_id_packet(struct iforce *iforce, char *packet); | 166 | int iforce_get_id_packet(struct iforce *iforce, char *packet); |
| 183 | 167 | ||
| 184 | /* iforce-ff.c */ | 168 | /* iforce-ff.c */ |
| 185 | int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update); | 169 | int iforce_upload_periodic(struct iforce *, struct ff_effect *, struct ff_effect *); |
| 186 | int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); | 170 | int iforce_upload_constant(struct iforce *, struct ff_effect *, struct ff_effect *); |
| 187 | int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update); | 171 | int iforce_upload_condition(struct iforce *, struct ff_effect *, struct ff_effect *); |
| 188 | 172 | ||
| 189 | /* Public variables */ | 173 | /* Public variables */ |
| 190 | extern struct serio_driver iforce_serio_drv; | 174 | extern struct serio_driver iforce_serio_drv; |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 83eac3a66b..c62e00c79d 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
| @@ -121,6 +121,17 @@ config KEYBOARD_NEWTON | |||
| 121 | To compile this driver as a module, choose M here: the | 121 | To compile this driver as a module, choose M here: the |
| 122 | module will be called newtonkbd. | 122 | module will be called newtonkbd. |
| 123 | 123 | ||
| 124 | config KEYBOARD_STOWAWAY | ||
| 125 | tristate "Stowaway keyboard" | ||
| 126 | select SERIO | ||
| 127 | help | ||
| 128 | Say Y here if you have a Stowaway keyboard on a serial port. | ||
| 129 | Stowaway compatible keyboards like Dicota Input-PDA keyboard | ||
| 130 | are also supported by this driver. | ||
| 131 | |||
| 132 | To compile this driver as a module, choose M here: the | ||
| 133 | module will be called stowaway. | ||
| 134 | |||
| 124 | config KEYBOARD_CORGI | 135 | config KEYBOARD_CORGI |
| 125 | tristate "Corgi keyboard" | 136 | tristate "Corgi keyboard" |
| 126 | depends on PXA_SHARPSL | 137 | depends on PXA_SHARPSL |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index b265391f1f..4c79e7bc9d 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
| @@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o | |||
| 11 | obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o | 11 | obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o |
| 12 | obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o | 12 | obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o |
| 13 | obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o | 13 | obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o |
| 14 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o | ||
| 14 | obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o | 15 | obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o |
| 15 | obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o | 16 | obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o |
| 16 | obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o | 17 | obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o |
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index a86afd0a5e..40244d4ce0 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c | |||
| @@ -652,9 +652,7 @@ static int atkbd_probe(struct atkbd *atkbd) | |||
| 652 | return 0; | 652 | return 0; |
| 653 | } | 653 | } |
| 654 | 654 | ||
| 655 | if (param[0] != 0xab && param[0] != 0xac && /* Regular and NCD Sun keyboards */ | 655 | if (!ps2_is_keyboard_id(param[0])) |
| 656 | param[0] != 0x2b && param[0] != 0x5d && /* Trust keyboard, raw and translated */ | ||
| 657 | param[0] != 0x60 && param[0] != 0x47) /* NMB SGI keyboard, raw and translated */ | ||
| 658 | return -1; | 656 | return -1; |
| 659 | 657 | ||
| 660 | atkbd->id = (param[0] << 8) | param[1]; | 658 | atkbd->id = (param[0] << 8) | param[1]; |
diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c new file mode 100644 index 0000000000..04c54c57f2 --- /dev/null +++ b/drivers/input/keyboard/stowaway.c | |||
| @@ -0,0 +1,187 @@ | |||
| 1 | /* | ||
| 2 | * Stowaway keyboard driver for Linux | ||
| 3 | */ | ||
| 4 | |||
| 5 | /* | ||
| 6 | * Copyright (c) 2006 Marek Vasut | ||
| 7 | * | ||
| 8 | * Based on Newton keyboard driver for Linux | ||
| 9 | * by Justin Cormack | ||
| 10 | */ | ||
| 11 | |||
| 12 | /* | ||
| 13 | * This program is free software; you can redistribute it and/or modify | ||
| 14 | * it under the terms of the GNU General Public License as published by | ||
| 15 | * the Free Software Foundation; either version 2 of the License, or | ||
| 16 | * (at your option) any later version. | ||
| 17 | * | ||
| 18 | * This program is distributed in the hope that it will be useful, | ||
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | * GNU General Public License for more details. | ||
| 22 | * | ||
| 23 | * You should have received a copy of the GNU General Public License | ||
| 24 | * along with this program; if not, write to the Free Software | ||
| 25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 26 | * | ||
| 27 | * Should you need to contact me, the author, you can do so either by | ||
| 28 | * e-mail - mail your message to <marek.vasut@gmail.com>, or by paper mail: | ||
| 29 | * Marek Vasut, Liskovecka 559, Frydek-Mistek, 738 01 Czech Republic | ||
| 30 | */ | ||
| 31 | |||
| 32 | #include <linux/slab.h> | ||
| 33 | #include <linux/module.h> | ||
| 34 | #include <linux/input.h> | ||
| 35 | #include <linux/init.h> | ||
| 36 | #include <linux/serio.h> | ||
| 37 | |||
| 38 | #define DRIVER_DESC "Stowaway keyboard driver" | ||
| 39 | |||
| 40 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); | ||
| 41 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 42 | MODULE_LICENSE("GPL"); | ||
| 43 | |||
| 44 | #define SKBD_KEY_MASK 0x7f | ||
| 45 | #define SKBD_RELEASE 0x80 | ||
| 46 | |||
| 47 | static unsigned char skbd_keycode[128] = { | ||
| 48 | KEY_1, KEY_2, KEY_3, KEY_Z, KEY_4, KEY_5, KEY_6, KEY_7, | ||
| 49 | 0, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_GRAVE, | ||
| 50 | KEY_X, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_SPACE, | ||
| 51 | KEY_CAPSLOCK, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, | ||
| 52 | 0, 0, 0, KEY_LEFTALT, 0, 0, 0, 0, | ||
| 53 | 0, 0, 0, 0, KEY_C, KEY_V, KEY_B, KEY_N, | ||
| 54 | KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_HOME, KEY_8, KEY_9, KEY_0, KEY_ESC, | ||
| 55 | KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_END, KEY_U, KEY_I, KEY_O, KEY_P, | ||
| 56 | KEY_APOSTROPHE, KEY_ENTER, KEY_PAGEUP,0, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, | ||
| 57 | KEY_SLASH, KEY_UP, KEY_PAGEDOWN, 0,KEY_M, KEY_COMMA, KEY_DOT, KEY_INSERT, | ||
| 58 | KEY_DELETE, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, | ||
| 59 | KEY_LEFTSHIFT, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, | ||
| 60 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 61 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 62 | 0, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, | ||
| 63 | KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, 0, 0, 0 | ||
| 64 | }; | ||
| 65 | |||
| 66 | struct skbd { | ||
| 67 | unsigned char keycode[128]; | ||
| 68 | struct input_dev *dev; | ||
| 69 | struct serio *serio; | ||
| 70 | char phys[32]; | ||
| 71 | }; | ||
| 72 | |||
| 73 | static irqreturn_t skbd_interrupt(struct serio *serio, unsigned char data, | ||
| 74 | unsigned int flags, struct pt_regs *regs) | ||
| 75 | { | ||
| 76 | struct skbd *skbd = serio_get_drvdata(serio); | ||
| 77 | struct input_dev *dev = skbd->dev; | ||
| 78 | |||
| 79 | if (skbd->keycode[data & SKBD_KEY_MASK]) { | ||
| 80 | input_regs(dev, regs); | ||
| 81 | input_report_key(dev, skbd->keycode[data & SKBD_KEY_MASK], | ||
| 82 | !(data & SKBD_RELEASE)); | ||
| 83 | input_sync(dev); | ||
| 84 | } | ||
| 85 | |||
| 86 | return IRQ_HANDLED; | ||
| 87 | } | ||
| 88 | |||
| 89 | static int skbd_connect(struct serio *serio, struct serio_driver *drv) | ||
| 90 | { | ||
| 91 | struct skbd *skbd; | ||
| 92 | struct input_dev *input_dev; | ||
| 93 | int err = -ENOMEM; | ||
| 94 | int i; | ||
| 95 | |||
| 96 | skbd = kzalloc(sizeof(struct skbd), GFP_KERNEL); | ||
| 97 | input_dev = input_allocate_device(); | ||
| 98 | if (!skbd || !input_dev) | ||
| 99 | goto fail1; | ||
| 100 | |||
| 101 | skbd->serio = serio; | ||
| 102 | skbd->dev = input_dev; | ||
| 103 | snprintf(skbd->phys, sizeof(skbd->phys), "%s/input0", serio->phys); | ||
| 104 | memcpy(skbd->keycode, skbd_keycode, sizeof(skbd->keycode)); | ||
| 105 | |||
| 106 | input_dev->name = "Stowaway Keyboard"; | ||
| 107 | input_dev->phys = skbd->phys; | ||
| 108 | input_dev->id.bustype = BUS_RS232; | ||
| 109 | input_dev->id.vendor = SERIO_STOWAWAY; | ||
| 110 | input_dev->id.product = 0x0001; | ||
| 111 | input_dev->id.version = 0x0100; | ||
| 112 | input_dev->cdev.dev = &serio->dev; | ||
| 113 | input_dev->private = skbd; | ||
| 114 | |||
| 115 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
| 116 | input_dev->keycode = skbd->keycode; | ||
| 117 | input_dev->keycodesize = sizeof(unsigned char); | ||
| 118 | input_dev->keycodemax = ARRAY_SIZE(skbd_keycode); | ||
| 119 | for (i = 0; i < ARRAY_SIZE(skbd_keycode); i++) | ||
| 120 | set_bit(skbd_keycode[i], input_dev->keybit); | ||
| 121 | clear_bit(0, input_dev->keybit); | ||
| 122 | |||
| 123 | serio_set_drvdata(serio, skbd); | ||
| 124 | |||
| 125 | err = serio_open(serio, drv); | ||
| 126 | if (err) | ||
| 127 | goto fail2; | ||
| 128 | |||
| 129 | err = input_register_device(skbd->dev); | ||
| 130 | if (err) | ||
| 131 | goto fail3; | ||
| 132 | |||
| 133 | return 0; | ||
| 134 | |||
| 135 | fail3: serio_close(serio); | ||
| 136 | fail2: serio_set_drvdata(serio, NULL); | ||
| 137 | fail1: input_free_device(input_dev); | ||
| 138 | kfree(skbd); | ||
| 139 | return err; | ||
| 140 | } | ||
| 141 | |||
| 142 | static void skbd_disconnect(struct serio *serio) | ||
| 143 | { | ||
| 144 | struct skbd *skbd = serio_get_drvdata(serio); | ||
| 145 | |||
| 146 | serio_close(serio); | ||
| 147 | serio_set_drvdata(serio, NULL); | ||
| 148 | input_unregister_device(skbd->dev); | ||
| 149 | kfree(skbd); | ||
| 150 | } | ||
| 151 | |||
| 152 | static struct serio_device_id skbd_serio_ids[] = { | ||
| 153 | { | ||
| 154 | .type = SERIO_RS232, | ||
| 155 | .proto = SERIO_STOWAWAY, | ||
| 156 | .id = SERIO_ANY, | ||
| 157 | .extra = SERIO_ANY, | ||
| 158 | }, | ||
| 159 | { 0 } | ||
| 160 | }; | ||
| 161 | |||
| 162 | MODULE_DEVICE_TABLE(serio, skbd_serio_ids); | ||
| 163 | |||
| 164 | static struct serio_driver skbd_drv = { | ||
| 165 | .driver = { | ||
| 166 | .name = "stowaway", | ||
| 167 | }, | ||
| 168 | .description = DRIVER_DESC, | ||
| 169 | .id_table = skbd_serio_ids, | ||
| 170 | .interrupt = skbd_interrupt, | ||
| 171 | .connect = skbd_connect, | ||
| 172 | .disconnect = skbd_disconnect, | ||
| 173 | }; | ||
| 174 | |||
| 175 | static int __init skbd_init(void) | ||
| 176 | { | ||
| 177 | serio_register_driver(&skbd_drv); | ||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | |||
| 181 | static void __exit skbd_exit(void) | ||
| 182 | { | ||
| 183 | serio_unregister_driver(&skbd_drv); | ||
| 184 | } | ||
| 185 | |||
| 186 | module_init(skbd_init); | ||
| 187 | module_exit(skbd_exit); | ||
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index d723e9ad7c..9516439b7c 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c | |||
| @@ -20,6 +20,9 @@ | |||
| 20 | * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> | 20 | * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> |
| 21 | * | 21 | * |
| 22 | * Changes/Revisions: | 22 | * Changes/Revisions: |
| 23 | * 0.3 09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>) | ||
| 24 | * - updated ff support for the changes in kernel interface | ||
| 25 | * - added MODULE_VERSION | ||
| 23 | * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) | 26 | * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) |
| 24 | * - added force feedback support | 27 | * - added force feedback support |
| 25 | * - added UI_SET_PHYS | 28 | * - added UI_SET_PHYS |
| @@ -107,18 +110,31 @@ static int uinput_request_submit(struct input_dev *dev, struct uinput_request *r | |||
| 107 | return request->retval; | 110 | return request->retval; |
| 108 | } | 111 | } |
| 109 | 112 | ||
| 110 | static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) | 113 | static void uinput_dev_set_gain(struct input_dev *dev, u16 gain) |
| 114 | { | ||
| 115 | uinput_dev_event(dev, EV_FF, FF_GAIN, gain); | ||
| 116 | } | ||
| 117 | |||
| 118 | static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude) | ||
| 119 | { | ||
| 120 | uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude); | ||
| 121 | } | ||
| 122 | |||
| 123 | static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value) | ||
| 124 | { | ||
| 125 | return uinput_dev_event(dev, EV_FF, effect_id, value); | ||
| 126 | } | ||
| 127 | |||
| 128 | static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) | ||
| 111 | { | 129 | { |
| 112 | struct uinput_request request; | 130 | struct uinput_request request; |
| 113 | int retval; | 131 | int retval; |
| 114 | 132 | ||
| 115 | if (!test_bit(EV_FF, dev->evbit)) | ||
| 116 | return -ENOSYS; | ||
| 117 | |||
| 118 | request.id = -1; | 133 | request.id = -1; |
| 119 | init_completion(&request.done); | 134 | init_completion(&request.done); |
| 120 | request.code = UI_FF_UPLOAD; | 135 | request.code = UI_FF_UPLOAD; |
| 121 | request.u.effect = effect; | 136 | request.u.upload.effect = effect; |
| 137 | request.u.upload.old = old; | ||
| 122 | 138 | ||
| 123 | retval = uinput_request_reserve_slot(dev->private, &request); | 139 | retval = uinput_request_reserve_slot(dev->private, &request); |
| 124 | if (!retval) | 140 | if (!retval) |
| @@ -168,6 +184,7 @@ static void uinput_destroy_device(struct uinput_device *udev) | |||
| 168 | 184 | ||
| 169 | static int uinput_create_device(struct uinput_device *udev) | 185 | static int uinput_create_device(struct uinput_device *udev) |
| 170 | { | 186 | { |
| 187 | struct input_dev *dev = udev->dev; | ||
| 171 | int error; | 188 | int error; |
| 172 | 189 | ||
| 173 | if (udev->state != UIST_SETUP_COMPLETE) { | 190 | if (udev->state != UIST_SETUP_COMPLETE) { |
| @@ -175,15 +192,29 @@ static int uinput_create_device(struct uinput_device *udev) | |||
| 175 | return -EINVAL; | 192 | return -EINVAL; |
| 176 | } | 193 | } |
| 177 | 194 | ||
| 178 | error = input_register_device(udev->dev); | 195 | if (udev->ff_effects_max) { |
| 179 | if (error) { | 196 | error = input_ff_create(dev, udev->ff_effects_max); |
| 180 | uinput_destroy_device(udev); | 197 | if (error) |
| 181 | return error; | 198 | goto fail1; |
| 199 | |||
| 200 | dev->ff->upload = uinput_dev_upload_effect; | ||
| 201 | dev->ff->erase = uinput_dev_erase_effect; | ||
| 202 | dev->ff->playback = uinput_dev_playback; | ||
| 203 | dev->ff->set_gain = uinput_dev_set_gain; | ||
| 204 | dev->ff->set_autocenter = uinput_dev_set_autocenter; | ||
| 182 | } | 205 | } |
| 183 | 206 | ||
| 207 | error = input_register_device(udev->dev); | ||
| 208 | if (error) | ||
| 209 | goto fail2; | ||
| 210 | |||
| 184 | udev->state = UIST_CREATED; | 211 | udev->state = UIST_CREATED; |
| 185 | 212 | ||
| 186 | return 0; | 213 | return 0; |
| 214 | |||
| 215 | fail2: input_ff_destroy(dev); | ||
| 216 | fail1: uinput_destroy_device(udev); | ||
| 217 | return error; | ||
| 187 | } | 218 | } |
| 188 | 219 | ||
| 189 | static int uinput_open(struct inode *inode, struct file *file) | 220 | static int uinput_open(struct inode *inode, struct file *file) |
| @@ -243,8 +274,6 @@ static int uinput_allocate_device(struct uinput_device *udev) | |||
| 243 | return -ENOMEM; | 274 | return -ENOMEM; |
| 244 | 275 | ||
| 245 | udev->dev->event = uinput_dev_event; | 276 | udev->dev->event = uinput_dev_event; |
| 246 | udev->dev->upload_effect = uinput_dev_upload_effect; | ||
| 247 | udev->dev->erase_effect = uinput_dev_erase_effect; | ||
| 248 | udev->dev->private = udev; | 277 | udev->dev->private = udev; |
| 249 | 278 | ||
| 250 | return 0; | 279 | return 0; |
| @@ -278,6 +307,8 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu | |||
| 278 | goto exit; | 307 | goto exit; |
| 279 | } | 308 | } |
| 280 | 309 | ||
| 310 | udev->ff_effects_max = user_dev->ff_effects_max; | ||
| 311 | |||
| 281 | size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; | 312 | size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; |
| 282 | if (!size) { | 313 | if (!size) { |
| 283 | retval = -EINVAL; | 314 | retval = -EINVAL; |
| @@ -296,7 +327,6 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu | |||
| 296 | dev->id.vendor = user_dev->id.vendor; | 327 | dev->id.vendor = user_dev->id.vendor; |
| 297 | dev->id.product = user_dev->id.product; | 328 | dev->id.product = user_dev->id.product; |
| 298 | dev->id.version = user_dev->id.version; | 329 | dev->id.version = user_dev->id.version; |
| 299 | dev->ff_effects_max = user_dev->ff_effects_max; | ||
| 300 | 330 | ||
| 301 | size = sizeof(int) * (ABS_MAX + 1); | 331 | size = sizeof(int) * (ABS_MAX + 1); |
| 302 | memcpy(dev->absmax, user_dev->absmax, size); | 332 | memcpy(dev->absmax, user_dev->absmax, size); |
| @@ -525,12 +555,17 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 525 | break; | 555 | break; |
| 526 | } | 556 | } |
| 527 | req = uinput_request_find(udev, ff_up.request_id); | 557 | req = uinput_request_find(udev, ff_up.request_id); |
| 528 | if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { | 558 | if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { |
| 529 | retval = -EINVAL; | 559 | retval = -EINVAL; |
| 530 | break; | 560 | break; |
| 531 | } | 561 | } |
| 532 | ff_up.retval = 0; | 562 | ff_up.retval = 0; |
| 533 | memcpy(&ff_up.effect, req->u.effect, sizeof(struct ff_effect)); | 563 | memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect)); |
| 564 | if (req->u.upload.old) | ||
| 565 | memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect)); | ||
| 566 | else | ||
| 567 | memset(&ff_up.old, 0, sizeof(struct ff_effect)); | ||
| 568 | |||
| 534 | if (copy_to_user(p, &ff_up, sizeof(ff_up))) { | 569 | if (copy_to_user(p, &ff_up, sizeof(ff_up))) { |
| 535 | retval = -EFAULT; | 570 | retval = -EFAULT; |
| 536 | break; | 571 | break; |
| @@ -561,12 +596,11 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 561 | break; | 596 | break; |
| 562 | } | 597 | } |
| 563 | req = uinput_request_find(udev, ff_up.request_id); | 598 | req = uinput_request_find(udev, ff_up.request_id); |
| 564 | if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { | 599 | if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { |
| 565 | retval = -EINVAL; | 600 | retval = -EINVAL; |
| 566 | break; | 601 | break; |
| 567 | } | 602 | } |
| 568 | req->retval = ff_up.retval; | 603 | req->retval = ff_up.retval; |
| 569 | memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect)); | ||
| 570 | uinput_request_done(udev, req); | 604 | uinput_request_done(udev, req); |
| 571 | break; | 605 | break; |
| 572 | 606 | ||
| @@ -622,6 +656,7 @@ static void __exit uinput_exit(void) | |||
| 622 | MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); | 656 | MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); |
| 623 | MODULE_DESCRIPTION("User level driver support for input subsystem"); | 657 | MODULE_DESCRIPTION("User level driver support for input subsystem"); |
| 624 | MODULE_LICENSE("GPL"); | 658 | MODULE_LICENSE("GPL"); |
| 659 | MODULE_VERSION("0.3"); | ||
| 625 | 660 | ||
| 626 | module_init(uinput_init); | 661 | module_init(uinput_init); |
| 627 | module_exit(uinput_exit); | 662 | module_exit(uinput_exit); |
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index de0f46dd96..4639537336 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c | |||
| @@ -248,13 +248,10 @@ static int __init dmi_matched(struct dmi_system_id *dmi) | |||
| 248 | 248 | ||
| 249 | keymap = dmi->driver_data; | 249 | keymap = dmi->driver_data; |
| 250 | for (key = keymap; key->type != KE_END; key++) { | 250 | for (key = keymap; key->type != KE_END; key++) { |
| 251 | if (key->type == KE_WIFI) { | 251 | if (key->type == KE_WIFI) |
| 252 | have_wifi = 1; | 252 | have_wifi = 1; |
| 253 | break; | 253 | else if (key->type == KE_BLUETOOTH) |
| 254 | } else if (key->type == KE_BLUETOOTH) { | ||
| 255 | have_bluetooth = 1; | 254 | have_bluetooth = 1; |
| 256 | break; | ||
| 257 | } | ||
| 258 | } | 255 | } |
| 259 | return 1; | 256 | return 1; |
| 260 | } | 257 | } |
| @@ -389,7 +386,16 @@ static struct dmi_system_id dmi_ids[] __initdata = { | |||
| 389 | }, | 386 | }, |
| 390 | .driver_data = keymap_acer_travelmate_240 | 387 | .driver_data = keymap_acer_travelmate_240 |
| 391 | }, | 388 | }, |
| 392 | { | 389 | { |
| 390 | .callback = dmi_matched, | ||
| 391 | .ident = "Acer TravelMate 2424NWXCi", | ||
| 392 | .matches = { | ||
| 393 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | ||
| 394 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"), | ||
| 395 | }, | ||
| 396 | .driver_data = keymap_acer_travelmate_240 | ||
| 397 | }, | ||
| 398 | { | ||
| 393 | .callback = dmi_matched, | 399 | .callback = dmi_matched, |
| 394 | .ident = "AOpen 1559AS", | 400 | .ident = "AOpen 1559AS", |
| 395 | .matches = { | 401 | .matches = { |
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 070d75330a..450b68a619 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
| @@ -36,7 +36,7 @@ | |||
| 36 | #define ALPS_PASS 0x20 | 36 | #define ALPS_PASS 0x20 |
| 37 | #define ALPS_FW_BK_2 0x40 | 37 | #define ALPS_FW_BK_2 0x40 |
| 38 | 38 | ||
| 39 | static struct alps_model_info alps_model_data[] = { | 39 | static const struct alps_model_info alps_model_data[] = { |
| 40 | { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ | 40 | { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ |
| 41 | { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, | 41 | { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, |
| 42 | { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, | 42 | { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, |
| @@ -209,10 +209,10 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs * | |||
| 209 | return PSMOUSE_GOOD_DATA; | 209 | return PSMOUSE_GOOD_DATA; |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version) | 212 | static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version) |
| 213 | { | 213 | { |
| 214 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 214 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
| 215 | unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 }; | 215 | static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 }; |
| 216 | unsigned char param[4]; | 216 | unsigned char param[4]; |
| 217 | int i; | 217 | int i; |
| 218 | 218 | ||
| @@ -504,7 +504,7 @@ init_fail: | |||
| 504 | int alps_detect(struct psmouse *psmouse, int set_properties) | 504 | int alps_detect(struct psmouse *psmouse, int set_properties) |
| 505 | { | 505 | { |
| 506 | int version; | 506 | int version; |
| 507 | struct alps_model_info *model; | 507 | const struct alps_model_info *model; |
| 508 | 508 | ||
| 509 | if (!(model = alps_get_model(psmouse, &version))) | 509 | if (!(model = alps_get_model(psmouse, &version))) |
| 510 | return -1; | 510 | return -1; |
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index e428f8d5d1..69db7325a4 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h | |||
| @@ -25,7 +25,7 @@ struct alps_data { | |||
| 25 | struct input_dev *dev2; /* Relative device */ | 25 | struct input_dev *dev2; /* Relative device */ |
| 26 | char name[32]; /* Name */ | 26 | char name[32]; /* Name */ |
| 27 | char phys[32]; /* Phys */ | 27 | char phys[32]; /* Phys */ |
| 28 | struct alps_model_info *i; /* Info */ | 28 | const struct alps_model_info *i;/* Info */ |
| 29 | int prev_fin; /* Finger bit from previous packet */ | 29 | int prev_fin; /* Finger bit from previous packet */ |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index c14395ba79..5e9d250675 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c | |||
| @@ -115,13 +115,15 @@ static int lifebook_absolute_mode(struct psmouse *psmouse) | |||
| 115 | 115 | ||
| 116 | static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) | 116 | static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) |
| 117 | { | 117 | { |
| 118 | unsigned char params[] = { 0, 1, 2, 2, 3 }; | 118 | static const unsigned char params[] = { 0, 1, 2, 2, 3 }; |
| 119 | unsigned char p; | ||
| 119 | 120 | ||
| 120 | if (resolution == 0 || resolution > 400) | 121 | if (resolution == 0 || resolution > 400) |
| 121 | resolution = 400; | 122 | resolution = 400; |
| 122 | 123 | ||
| 123 | ps2_command(&psmouse->ps2dev, ¶ms[resolution / 100], PSMOUSE_CMD_SETRES); | 124 | p = params[resolution / 100]; |
| 124 | psmouse->resolution = 50 << params[resolution / 100]; | 125 | ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES); |
| 126 | psmouse->resolution = 50 << p; | ||
| 125 | } | 127 | } |
| 126 | 128 | ||
| 127 | static void lifebook_disconnect(struct psmouse *psmouse) | 129 | static void lifebook_disconnect(struct psmouse *psmouse) |
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 54b696cfe1..7972eecbcf 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c | |||
| @@ -30,9 +30,9 @@ | |||
| 30 | #define PS2PP_NAV_BTN 0x20 | 30 | #define PS2PP_NAV_BTN 0x20 |
| 31 | 31 | ||
| 32 | struct ps2pp_info { | 32 | struct ps2pp_info { |
| 33 | const int model; | 33 | u8 model; |
| 34 | unsigned const int kind; | 34 | u8 kind; |
| 35 | unsigned const int features; | 35 | u16 features; |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | /* | 38 | /* |
| @@ -199,9 +199,9 @@ static void ps2pp_disconnect(struct psmouse *psmouse) | |||
| 199 | device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr); | 199 | device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | static struct ps2pp_info *get_model_info(unsigned char model) | 202 | static const struct ps2pp_info *get_model_info(unsigned char model) |
| 203 | { | 203 | { |
| 204 | static struct ps2pp_info ps2pp_list[] = { | 204 | static const struct ps2pp_info ps2pp_list[] = { |
| 205 | { 12, 0, PS2PP_SIDE_BTN}, | 205 | { 12, 0, PS2PP_SIDE_BTN}, |
| 206 | { 13, 0, 0 }, | 206 | { 13, 0, 0 }, |
| 207 | { 15, PS2PP_KIND_MX, /* MX1000 */ | 207 | { 15, PS2PP_KIND_MX, /* MX1000 */ |
| @@ -215,6 +215,7 @@ static struct ps2pp_info *get_model_info(unsigned char model) | |||
| 215 | { 51, 0, 0 }, | 215 | { 51, 0, 0 }, |
| 216 | { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, | 216 | { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, |
| 217 | { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, | 217 | { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, |
| 218 | { 56, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, /* Cordless MouseMan Wheel */ | ||
| 218 | { 61, PS2PP_KIND_MX, /* MX700 */ | 219 | { 61, PS2PP_KIND_MX, /* MX700 */ |
| 219 | PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | | 220 | PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | |
| 220 | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, | 221 | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, |
| @@ -244,12 +245,11 @@ static struct ps2pp_info *get_model_info(unsigned char model) | |||
| 244 | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, | 245 | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, |
| 245 | { 114, PS2PP_KIND_MX, /* MX310 */ | 246 | { 114, PS2PP_KIND_MX, /* MX310 */ |
| 246 | PS2PP_WHEEL | PS2PP_SIDE_BTN | | 247 | PS2PP_WHEEL | PS2PP_SIDE_BTN | |
| 247 | PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }, | 248 | PS2PP_TASK_BTN | PS2PP_EXTRA_BTN } |
| 248 | { } | ||
| 249 | }; | 249 | }; |
| 250 | int i; | 250 | int i; |
| 251 | 251 | ||
| 252 | for (i = 0; ps2pp_list[i].model; i++) | 252 | for (i = 0; i < ARRAY_SIZE(ps2pp_list); i++) |
| 253 | if (model == ps2pp_list[i].model) | 253 | if (model == ps2pp_list[i].model) |
| 254 | return &ps2pp_list[i]; | 254 | return &ps2pp_list[i]; |
| 255 | 255 | ||
| @@ -261,7 +261,8 @@ static struct ps2pp_info *get_model_info(unsigned char model) | |||
| 261 | * Set up input device's properties based on the detected mouse model. | 261 | * Set up input device's properties based on the detected mouse model. |
| 262 | */ | 262 | */ |
| 263 | 263 | ||
| 264 | static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info, | 264 | static void ps2pp_set_model_properties(struct psmouse *psmouse, |
| 265 | const struct ps2pp_info *model_info, | ||
| 265 | int using_ps2pp) | 266 | int using_ps2pp) |
| 266 | { | 267 | { |
| 267 | struct input_dev *input_dev = psmouse->dev; | 268 | struct input_dev *input_dev = psmouse->dev; |
| @@ -327,7 +328,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) | |||
| 327 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 328 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
| 328 | unsigned char param[4]; | 329 | unsigned char param[4]; |
| 329 | unsigned char model, buttons; | 330 | unsigned char model, buttons; |
| 330 | struct ps2pp_info *model_info; | 331 | const struct ps2pp_info *model_info; |
| 331 | int use_ps2pp = 0; | 332 | int use_ps2pp = 0; |
| 332 | 333 | ||
| 333 | param[0] = 0; | 334 | param[0] = 0; |
| @@ -349,7 +350,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) | |||
| 349 | /* | 350 | /* |
| 350 | * Do Logitech PS2++ / PS2T++ magic init. | 351 | * Do Logitech PS2++ / PS2T++ magic init. |
| 351 | */ | 352 | */ |
| 352 | if (model == 97) { /* Touch Pad 3 */ | 353 | if (model_info->kind == PS2PP_KIND_TP3) { /* Touch Pad 3 */ |
| 353 | 354 | ||
| 354 | /* Unprotect RAM */ | 355 | /* Unprotect RAM */ |
| 355 | param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; | 356 | param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; |
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 343afa38f4..9fb7eb6b0f 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
| @@ -112,8 +112,8 @@ static struct workqueue_struct *kpsmoused_wq; | |||
| 112 | 112 | ||
| 113 | struct psmouse_protocol { | 113 | struct psmouse_protocol { |
| 114 | enum psmouse_type type; | 114 | enum psmouse_type type; |
| 115 | char *name; | 115 | const char *name; |
| 116 | char *alias; | 116 | const char *alias; |
| 117 | int maxproto; | 117 | int maxproto; |
| 118 | int (*detect)(struct psmouse *, int); | 118 | int (*detect)(struct psmouse *, int); |
| 119 | int (*init)(struct psmouse *); | 119 | int (*init)(struct psmouse *); |
| @@ -507,15 +507,17 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties) | |||
| 507 | { | 507 | { |
| 508 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 508 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
| 509 | unsigned char param[2]; | 509 | unsigned char param[2]; |
| 510 | unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20, 0 }; | 510 | static const unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 }; |
| 511 | int i; | 511 | int i; |
| 512 | 512 | ||
| 513 | param[0] = 10; | 513 | param[0] = 10; |
| 514 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | 514 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); |
| 515 | param[0] = 0; | 515 | param[0] = 0; |
| 516 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); | 516 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); |
| 517 | for (i = 0; seq[i]; i++) | 517 | for (i = 0; i < ARRAY_SIZE(seq); i++) { |
| 518 | ps2_command(ps2dev, seq + i, PSMOUSE_CMD_SETRATE); | 518 | param[0] = seq[i]; |
| 519 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
| 520 | } | ||
| 519 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); | 521 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); |
| 520 | 522 | ||
| 521 | if (param[0] != 2) | 523 | if (param[0] != 2) |
| @@ -652,7 +654,7 @@ static int psmouse_extensions(struct psmouse *psmouse, | |||
| 652 | return PSMOUSE_PS2; | 654 | return PSMOUSE_PS2; |
| 653 | } | 655 | } |
| 654 | 656 | ||
| 655 | static struct psmouse_protocol psmouse_protocols[] = { | 657 | static const struct psmouse_protocol psmouse_protocols[] = { |
| 656 | { | 658 | { |
| 657 | .type = PSMOUSE_PS2, | 659 | .type = PSMOUSE_PS2, |
| 658 | .name = "PS/2", | 660 | .name = "PS/2", |
| @@ -726,7 +728,7 @@ static struct psmouse_protocol psmouse_protocols[] = { | |||
| 726 | }, | 728 | }, |
| 727 | }; | 729 | }; |
| 728 | 730 | ||
| 729 | static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) | 731 | static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) |
| 730 | { | 732 | { |
| 731 | int i; | 733 | int i; |
| 732 | 734 | ||
| @@ -738,9 +740,9 @@ static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) | |||
| 738 | return &psmouse_protocols[0]; | 740 | return &psmouse_protocols[0]; |
| 739 | } | 741 | } |
| 740 | 742 | ||
| 741 | static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len) | 743 | static const struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len) |
| 742 | { | 744 | { |
| 743 | struct psmouse_protocol *p; | 745 | const struct psmouse_protocol *p; |
| 744 | int i; | 746 | int i; |
| 745 | 747 | ||
| 746 | for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) { | 748 | for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) { |
| @@ -795,13 +797,15 @@ static int psmouse_probe(struct psmouse *psmouse) | |||
| 795 | 797 | ||
| 796 | void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) | 798 | void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) |
| 797 | { | 799 | { |
| 798 | unsigned char params[] = { 0, 1, 2, 2, 3 }; | 800 | static const unsigned char params[] = { 0, 1, 2, 2, 3 }; |
| 801 | unsigned char p; | ||
| 799 | 802 | ||
| 800 | if (resolution == 0 || resolution > 200) | 803 | if (resolution == 0 || resolution > 200) |
| 801 | resolution = 200; | 804 | resolution = 200; |
| 802 | 805 | ||
| 803 | ps2_command(&psmouse->ps2dev, ¶ms[resolution / 50], PSMOUSE_CMD_SETRES); | 806 | p = params[resolution / 50]; |
| 804 | psmouse->resolution = 25 << params[resolution / 50]; | 807 | ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES); |
| 808 | psmouse->resolution = 25 << p; | ||
| 805 | } | 809 | } |
| 806 | 810 | ||
| 807 | /* | 811 | /* |
| @@ -810,12 +814,14 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) | |||
| 810 | 814 | ||
| 811 | static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) | 815 | static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) |
| 812 | { | 816 | { |
| 813 | unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 }; | 817 | static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 }; |
| 818 | unsigned char r; | ||
| 814 | int i = 0; | 819 | int i = 0; |
| 815 | 820 | ||
| 816 | while (rates[i] > rate) i++; | 821 | while (rates[i] > rate) i++; |
| 817 | ps2_command(&psmouse->ps2dev, &rates[i], PSMOUSE_CMD_SETRATE); | 822 | r = rates[i]; |
| 818 | psmouse->rate = rates[i]; | 823 | ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE); |
| 824 | psmouse->rate = r; | ||
| 819 | } | 825 | } |
| 820 | 826 | ||
| 821 | /* | 827 | /* |
| @@ -1031,7 +1037,7 @@ static void psmouse_disconnect(struct serio *serio) | |||
| 1031 | mutex_unlock(&psmouse_mutex); | 1037 | mutex_unlock(&psmouse_mutex); |
| 1032 | } | 1038 | } |
| 1033 | 1039 | ||
| 1034 | static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto) | 1040 | static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse_protocol *proto) |
| 1035 | { | 1041 | { |
| 1036 | struct input_dev *input_dev = psmouse->dev; | 1042 | struct input_dev *input_dev = psmouse->dev; |
| 1037 | 1043 | ||
| @@ -1362,7 +1368,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co | |||
| 1362 | struct serio *serio = psmouse->ps2dev.serio; | 1368 | struct serio *serio = psmouse->ps2dev.serio; |
| 1363 | struct psmouse *parent = NULL; | 1369 | struct psmouse *parent = NULL; |
| 1364 | struct input_dev *new_dev; | 1370 | struct input_dev *new_dev; |
| 1365 | struct psmouse_protocol *proto; | 1371 | const struct psmouse_protocol *proto; |
| 1366 | int retry = 0; | 1372 | int retry = 0; |
| 1367 | 1373 | ||
| 1368 | if (!(proto = psmouse_protocol_by_name(buf, count))) | 1374 | if (!(proto = psmouse_protocol_by_name(buf, count))) |
| @@ -1459,7 +1465,7 @@ static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, | |||
| 1459 | 1465 | ||
| 1460 | static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) | 1466 | static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) |
| 1461 | { | 1467 | { |
| 1462 | struct psmouse_protocol *proto; | 1468 | const struct psmouse_protocol *proto; |
| 1463 | 1469 | ||
| 1464 | if (!val) | 1470 | if (!val) |
| 1465 | return -EINVAL; | 1471 | return -EINVAL; |
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c index 0023501a5b..680b323538 100644 --- a/drivers/input/mouse/sermouse.c +++ b/drivers/input/mouse/sermouse.c | |||
| @@ -42,7 +42,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |||
| 42 | MODULE_DESCRIPTION(DRIVER_DESC); | 42 | MODULE_DESCRIPTION(DRIVER_DESC); |
| 43 | MODULE_LICENSE("GPL"); | 43 | MODULE_LICENSE("GPL"); |
| 44 | 44 | ||
| 45 | static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", | 45 | static const char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", |
| 46 | "Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse", | 46 | "Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse", |
| 47 | "Logitech MZ++ Mouse"}; | 47 | "Logitech MZ++ Mouse"}; |
| 48 | 48 | ||
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index ad5d0a85e9..392108c436 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c | |||
| @@ -430,11 +430,11 @@ static void synaptics_process_packet(struct psmouse *psmouse) | |||
| 430 | 430 | ||
| 431 | static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type) | 431 | static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type) |
| 432 | { | 432 | { |
| 433 | static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; | 433 | static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; |
| 434 | static unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; | 434 | static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; |
| 435 | static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; | 435 | static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; |
| 436 | static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; | 436 | static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; |
| 437 | static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; | 437 | static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; |
| 438 | 438 | ||
| 439 | if (idx < 0 || idx > 4) | 439 | if (idx < 0 || idx > 4) |
| 440 | return 0; | 440 | return 0; |
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 1f851acab3..a22a74a2a3 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c | |||
| @@ -614,7 +614,7 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait) | |||
| 614 | (list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); | 614 | (list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); |
| 615 | } | 615 | } |
| 616 | 616 | ||
| 617 | static struct file_operations mousedev_fops = { | 617 | static const struct file_operations mousedev_fops = { |
| 618 | .owner = THIS_MODULE, | 618 | .owner = THIS_MODULE, |
| 619 | .read = mousedev_read, | 619 | .read = mousedev_read, |
| 620 | .write = mousedev_write, | 620 | .write = mousedev_write, |
| @@ -624,7 +624,8 @@ static struct file_operations mousedev_fops = { | |||
| 624 | .fasync = mousedev_fasync, | 624 | .fasync = mousedev_fasync, |
| 625 | }; | 625 | }; |
| 626 | 626 | ||
| 627 | static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | 627 | static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, |
| 628 | const struct input_device_id *id) | ||
| 628 | { | 629 | { |
| 629 | struct mousedev *mousedev; | 630 | struct mousedev *mousedev; |
| 630 | struct class_device *cdev; | 631 | struct class_device *cdev; |
| @@ -688,7 +689,7 @@ static void mousedev_disconnect(struct input_handle *handle) | |||
| 688 | } | 689 | } |
| 689 | } | 690 | } |
| 690 | 691 | ||
| 691 | static struct input_device_id mousedev_ids[] = { | 692 | static const struct input_device_id mousedev_ids[] = { |
| 692 | { | 693 | { |
| 693 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | 694 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, |
| 694 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | 695 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
| @@ -737,7 +738,12 @@ static int psaux_registered; | |||
| 737 | 738 | ||
| 738 | static int __init mousedev_init(void) | 739 | static int __init mousedev_init(void) |
| 739 | { | 740 | { |
| 740 | input_register_handler(&mousedev_handler); | 741 | struct class_device *cdev; |
| 742 | int error; | ||
| 743 | |||
| 744 | error = input_register_handler(&mousedev_handler); | ||
| 745 | if (error) | ||
| 746 | return error; | ||
| 741 | 747 | ||
| 742 | memset(&mousedev_mix, 0, sizeof(struct mousedev)); | 748 | memset(&mousedev_mix, 0, sizeof(struct mousedev)); |
| 743 | INIT_LIST_HEAD(&mousedev_mix.list); | 749 | INIT_LIST_HEAD(&mousedev_mix.list); |
| @@ -746,12 +752,20 @@ static int __init mousedev_init(void) | |||
| 746 | mousedev_mix.exist = 1; | 752 | mousedev_mix.exist = 1; |
| 747 | mousedev_mix.minor = MOUSEDEV_MIX; | 753 | mousedev_mix.minor = MOUSEDEV_MIX; |
| 748 | 754 | ||
| 749 | class_device_create(&input_class, NULL, | 755 | cdev = class_device_create(&input_class, NULL, |
| 750 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); | 756 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); |
| 757 | if (IS_ERR(cdev)) { | ||
| 758 | input_unregister_handler(&mousedev_handler); | ||
| 759 | return PTR_ERR(cdev); | ||
| 760 | } | ||
| 751 | 761 | ||
| 752 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | 762 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX |
| 753 | if (!(psaux_registered = !misc_register(&psaux_mouse))) | 763 | error = misc_register(&psaux_mouse); |
| 754 | printk(KERN_WARNING "mice: could not misc_register the device\n"); | 764 | if (error) |
| 765 | printk(KERN_WARNING "mice: could not register psaux device, " | ||
| 766 | "error: %d\n", error); | ||
| 767 | else | ||
| 768 | psaux_registered = 1; | ||
| 755 | #endif | 769 | #endif |
| 756 | 770 | ||
| 757 | printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); | 771 | printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); |
diff --git a/drivers/input/power.c b/drivers/input/power.c index 51a519e24b..ee82464a2f 100644 --- a/drivers/input/power.c +++ b/drivers/input/power.c | |||
| @@ -98,7 +98,7 @@ static void power_event(struct input_handle *handle, unsigned int type, | |||
| 98 | 98 | ||
| 99 | static struct input_handle *power_connect(struct input_handler *handler, | 99 | static struct input_handle *power_connect(struct input_handler *handler, |
| 100 | struct input_dev *dev, | 100 | struct input_dev *dev, |
| 101 | struct input_device_id *id) | 101 | const struct input_device_id *id) |
| 102 | { | 102 | { |
| 103 | struct input_handle *handle; | 103 | struct input_handle *handle; |
| 104 | 104 | ||
| @@ -120,7 +120,7 @@ static void power_disconnect(struct input_handle *handle) | |||
| 120 | kfree(handle); | 120 | kfree(handle); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | static struct input_device_id power_ids[] = { | 123 | static const struct input_device_id power_ids[] = { |
| 124 | { | 124 | { |
| 125 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | 125 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, |
| 126 | .evbit = { BIT(EV_KEY) }, | 126 | .evbit = { BIT(EV_KEY) }, |
| @@ -150,8 +150,7 @@ static struct input_handler power_handler = { | |||
| 150 | 150 | ||
| 151 | static int __init power_init(void) | 151 | static int __init power_init(void) |
| 152 | { | 152 | { |
| 153 | input_register_handler(&power_handler); | 153 | return input_register_handler(&power_handler); |
| 154 | return 0; | ||
| 155 | } | 154 | } |
| 156 | 155 | ||
| 157 | static void __exit power_exit(void) | 156 | static void __exit power_exit(void) |
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index f606e96bc2..8738edda66 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h | |||
| @@ -160,6 +160,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { | |||
| 160 | }, | 160 | }, |
| 161 | }, | 161 | }, |
| 162 | { | 162 | { |
| 163 | .ident = "Toshiba Equium A110", | ||
| 164 | .matches = { | ||
| 165 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
| 166 | DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"), | ||
| 167 | }, | ||
| 168 | }, | ||
| 169 | { | ||
| 163 | .ident = "Alienware Sentia", | 170 | .ident = "Alienware Sentia", |
| 164 | .matches = { | 171 | .matches = { |
| 165 | DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), | 172 | DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), |
| @@ -180,6 +187,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { | |||
| 180 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"), | 187 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"), |
| 181 | }, | 188 | }, |
| 182 | }, | 189 | }, |
| 190 | { | ||
| 191 | .ident = "Amoi M636/A737", | ||
| 192 | .matches = { | ||
| 193 | DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."), | ||
| 194 | DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"), | ||
| 195 | }, | ||
| 196 | }, | ||
| 183 | { } | 197 | { } |
| 184 | }; | 198 | }; |
| 185 | 199 | ||
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 06a3f25657..1bb0c76a92 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c | |||
| @@ -90,46 +90,24 @@ static DEFINE_SPINLOCK(i8042_lock); | |||
| 90 | struct i8042_port { | 90 | struct i8042_port { |
| 91 | struct serio *serio; | 91 | struct serio *serio; |
| 92 | int irq; | 92 | int irq; |
| 93 | unsigned char disable; | ||
| 94 | unsigned char irqen; | ||
| 95 | unsigned char exists; | 93 | unsigned char exists; |
| 96 | signed char mux; | 94 | signed char mux; |
| 97 | char name[8]; | ||
| 98 | }; | 95 | }; |
| 99 | 96 | ||
| 100 | #define I8042_KBD_PORT_NO 0 | 97 | #define I8042_KBD_PORT_NO 0 |
| 101 | #define I8042_AUX_PORT_NO 1 | 98 | #define I8042_AUX_PORT_NO 1 |
| 102 | #define I8042_MUX_PORT_NO 2 | 99 | #define I8042_MUX_PORT_NO 2 |
| 103 | #define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2) | 100 | #define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2) |
| 104 | static struct i8042_port i8042_ports[I8042_NUM_PORTS] = { | 101 | |
| 105 | { | 102 | static struct i8042_port i8042_ports[I8042_NUM_PORTS]; |
| 106 | .disable = I8042_CTR_KBDDIS, | ||
| 107 | .irqen = I8042_CTR_KBDINT, | ||
| 108 | .mux = -1, | ||
| 109 | .name = "KBD", | ||
| 110 | }, | ||
| 111 | { | ||
| 112 | .disable = I8042_CTR_AUXDIS, | ||
| 113 | .irqen = I8042_CTR_AUXINT, | ||
| 114 | .mux = -1, | ||
| 115 | .name = "AUX", | ||
| 116 | } | ||
| 117 | }; | ||
| 118 | 103 | ||
| 119 | static unsigned char i8042_initial_ctr; | 104 | static unsigned char i8042_initial_ctr; |
| 120 | static unsigned char i8042_ctr; | 105 | static unsigned char i8042_ctr; |
| 121 | static unsigned char i8042_mux_open; | ||
| 122 | static unsigned char i8042_mux_present; | 106 | static unsigned char i8042_mux_present; |
| 123 | static struct timer_list i8042_timer; | 107 | static unsigned char i8042_kbd_irq_registered; |
| 108 | static unsigned char i8042_aux_irq_registered; | ||
| 124 | static struct platform_device *i8042_platform_device; | 109 | static struct platform_device *i8042_platform_device; |
| 125 | 110 | ||
| 126 | |||
| 127 | /* | ||
| 128 | * Shared IRQ's require a device pointer, but this driver doesn't support | ||
| 129 | * multiple devices | ||
| 130 | */ | ||
| 131 | #define i8042_request_irq_cookie (&i8042_timer) | ||
| 132 | |||
| 133 | static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); | 111 | static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); |
| 134 | 112 | ||
| 135 | /* | 113 | /* |
| @@ -141,6 +119,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); | |||
| 141 | static int i8042_wait_read(void) | 119 | static int i8042_wait_read(void) |
| 142 | { | 120 | { |
| 143 | int i = 0; | 121 | int i = 0; |
| 122 | |||
| 144 | while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { | 123 | while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { |
| 145 | udelay(50); | 124 | udelay(50); |
| 146 | i++; | 125 | i++; |
| @@ -151,6 +130,7 @@ static int i8042_wait_read(void) | |||
| 151 | static int i8042_wait_write(void) | 130 | static int i8042_wait_write(void) |
| 152 | { | 131 | { |
| 153 | int i = 0; | 132 | int i = 0; |
| 133 | |||
| 154 | while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { | 134 | while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { |
| 155 | udelay(50); | 135 | udelay(50); |
| 156 | i++; | 136 | i++; |
| @@ -192,48 +172,57 @@ static int i8042_flush(void) | |||
| 192 | * encoded in bits 8-11 of the command number. | 172 | * encoded in bits 8-11 of the command number. |
| 193 | */ | 173 | */ |
| 194 | 174 | ||
| 195 | static int i8042_command(unsigned char *param, int command) | 175 | static int __i8042_command(unsigned char *param, int command) |
| 196 | { | 176 | { |
| 197 | unsigned long flags; | 177 | int i, error; |
| 198 | int i, retval, auxerr = 0; | ||
| 199 | 178 | ||
| 200 | if (i8042_noloop && command == I8042_CMD_AUX_LOOP) | 179 | if (i8042_noloop && command == I8042_CMD_AUX_LOOP) |
| 201 | return -1; | 180 | return -1; |
| 202 | 181 | ||
| 203 | spin_lock_irqsave(&i8042_lock, flags); | 182 | error = i8042_wait_write(); |
| 204 | 183 | if (error) | |
| 205 | if ((retval = i8042_wait_write())) | 184 | return error; |
| 206 | goto out; | ||
| 207 | 185 | ||
| 208 | dbg("%02x -> i8042 (command)", command & 0xff); | 186 | dbg("%02x -> i8042 (command)", command & 0xff); |
| 209 | i8042_write_command(command & 0xff); | 187 | i8042_write_command(command & 0xff); |
| 210 | 188 | ||
| 211 | for (i = 0; i < ((command >> 12) & 0xf); i++) { | 189 | for (i = 0; i < ((command >> 12) & 0xf); i++) { |
| 212 | if ((retval = i8042_wait_write())) | 190 | error = i8042_wait_write(); |
| 213 | goto out; | 191 | if (error) |
| 192 | return error; | ||
| 214 | dbg("%02x -> i8042 (parameter)", param[i]); | 193 | dbg("%02x -> i8042 (parameter)", param[i]); |
| 215 | i8042_write_data(param[i]); | 194 | i8042_write_data(param[i]); |
| 216 | } | 195 | } |
| 217 | 196 | ||
| 218 | for (i = 0; i < ((command >> 8) & 0xf); i++) { | 197 | for (i = 0; i < ((command >> 8) & 0xf); i++) { |
| 219 | if ((retval = i8042_wait_read())) | 198 | error = i8042_wait_read(); |
| 220 | goto out; | 199 | if (error) { |
| 200 | dbg(" -- i8042 (timeout)"); | ||
| 201 | return error; | ||
| 202 | } | ||
| 221 | 203 | ||
| 222 | if (command == I8042_CMD_AUX_LOOP && | 204 | if (command == I8042_CMD_AUX_LOOP && |
| 223 | !(i8042_read_status() & I8042_STR_AUXDATA)) { | 205 | !(i8042_read_status() & I8042_STR_AUXDATA)) { |
| 224 | retval = auxerr = -1; | 206 | dbg(" -- i8042 (auxerr)"); |
| 225 | goto out; | 207 | return -1; |
| 226 | } | 208 | } |
| 227 | 209 | ||
| 228 | param[i] = i8042_read_data(); | 210 | param[i] = i8042_read_data(); |
| 229 | dbg("%02x <- i8042 (return)", param[i]); | 211 | dbg("%02x <- i8042 (return)", param[i]); |
| 230 | } | 212 | } |
| 231 | 213 | ||
| 232 | if (retval) | 214 | return 0; |
| 233 | dbg(" -- i8042 (%s)", auxerr ? "auxerr" : "timeout"); | 215 | } |
| 234 | 216 | ||
| 235 | out: | 217 | static int i8042_command(unsigned char *param, int command) |
| 218 | { | ||
| 219 | unsigned long flags; | ||
| 220 | int retval; | ||
| 221 | |||
| 222 | spin_lock_irqsave(&i8042_lock, flags); | ||
| 223 | retval = __i8042_command(param, command); | ||
| 236 | spin_unlock_irqrestore(&i8042_lock, flags); | 224 | spin_unlock_irqrestore(&i8042_lock, flags); |
| 225 | |||
| 237 | return retval; | 226 | return retval; |
| 238 | } | 227 | } |
| 239 | 228 | ||
| @@ -248,7 +237,7 @@ static int i8042_kbd_write(struct serio *port, unsigned char c) | |||
| 248 | 237 | ||
| 249 | spin_lock_irqsave(&i8042_lock, flags); | 238 | spin_lock_irqsave(&i8042_lock, flags); |
| 250 | 239 | ||
| 251 | if(!(retval = i8042_wait_write())) { | 240 | if (!(retval = i8042_wait_write())) { |
| 252 | dbg("%02x -> i8042 (kbd-data)", c); | 241 | dbg("%02x -> i8042 (kbd-data)", c); |
| 253 | i8042_write_data(c); | 242 | i8042_write_data(c); |
| 254 | } | 243 | } |
| @@ -287,100 +276,6 @@ static int i8042_aux_write(struct serio *serio, unsigned char c) | |||
| 287 | } | 276 | } |
| 288 | 277 | ||
| 289 | /* | 278 | /* |
| 290 | * i8042_activate_port() enables port on a chip. | ||
| 291 | */ | ||
| 292 | |||
| 293 | static int i8042_activate_port(struct i8042_port *port) | ||
| 294 | { | ||
| 295 | if (!port->serio) | ||
| 296 | return -1; | ||
| 297 | |||
| 298 | i8042_flush(); | ||
| 299 | |||
| 300 | /* | ||
| 301 | * Enable port again here because it is disabled if we are | ||
| 302 | * resuming (normally it is enabled already). | ||
| 303 | */ | ||
| 304 | i8042_ctr &= ~port->disable; | ||
| 305 | |||
| 306 | i8042_ctr |= port->irqen; | ||
| 307 | |||
| 308 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
| 309 | i8042_ctr &= ~port->irqen; | ||
| 310 | return -1; | ||
| 311 | } | ||
| 312 | |||
| 313 | return 0; | ||
| 314 | } | ||
| 315 | |||
| 316 | |||
| 317 | /* | ||
| 318 | * i8042_open() is called when a port is open by the higher layer. | ||
| 319 | * It allocates the interrupt and calls i8042_enable_port. | ||
| 320 | */ | ||
| 321 | |||
| 322 | static int i8042_open(struct serio *serio) | ||
| 323 | { | ||
| 324 | struct i8042_port *port = serio->port_data; | ||
| 325 | |||
| 326 | if (port->mux != -1) | ||
| 327 | if (i8042_mux_open++) | ||
| 328 | return 0; | ||
| 329 | |||
| 330 | if (request_irq(port->irq, i8042_interrupt, | ||
| 331 | IRQF_SHARED, "i8042", i8042_request_irq_cookie)) { | ||
| 332 | printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", port->irq, port->name); | ||
| 333 | goto irq_fail; | ||
| 334 | } | ||
| 335 | |||
| 336 | if (i8042_activate_port(port)) { | ||
| 337 | printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", port->name); | ||
| 338 | goto activate_fail; | ||
| 339 | } | ||
| 340 | |||
| 341 | i8042_interrupt(0, NULL, NULL); | ||
| 342 | |||
| 343 | return 0; | ||
| 344 | |||
| 345 | activate_fail: | ||
| 346 | free_irq(port->irq, i8042_request_irq_cookie); | ||
| 347 | |||
| 348 | irq_fail: | ||
| 349 | serio_unregister_port_delayed(serio); | ||
| 350 | |||
| 351 | return -1; | ||
| 352 | } | ||
| 353 | |||
| 354 | /* | ||
| 355 | * i8042_close() frees the interrupt, so that it can possibly be used | ||
| 356 | * by another driver. We never know - if the user doesn't have a mouse, | ||
| 357 | * the BIOS could have used the AUX interrupt for PCI. | ||
| 358 | */ | ||
| 359 | |||
| 360 | static void i8042_close(struct serio *serio) | ||
| 361 | { | ||
| 362 | struct i8042_port *port = serio->port_data; | ||
| 363 | |||
| 364 | if (port->mux != -1) | ||
| 365 | if (--i8042_mux_open) | ||
| 366 | return; | ||
| 367 | |||
| 368 | i8042_ctr &= ~port->irqen; | ||
| 369 | |||
| 370 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
| 371 | printk(KERN_WARNING "i8042.c: Can't write CTR while closing %s.\n", port->name); | ||
| 372 | /* | ||
| 373 | * We still want to continue and free IRQ so if more data keeps coming in | ||
| 374 | * kernel will just ignore the irq. | ||
| 375 | */ | ||
| 376 | } | ||
| 377 | |||
| 378 | free_irq(port->irq, i8042_request_irq_cookie); | ||
| 379 | |||
| 380 | i8042_flush(); | ||
| 381 | } | ||
| 382 | |||
| 383 | /* | ||
| 384 | * i8042_start() is called by serio core when port is about to finish | 279 | * i8042_start() is called by serio core when port is about to finish |
| 385 | * registering. It will mark port as existing so i8042_interrupt can | 280 | * registering. It will mark port as existing so i8042_interrupt can |
| 386 | * start sending data through it. | 281 | * start sending data through it. |
| @@ -423,8 +318,6 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
| 423 | unsigned int port_no; | 318 | unsigned int port_no; |
| 424 | int ret; | 319 | int ret; |
| 425 | 320 | ||
| 426 | mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); | ||
| 427 | |||
| 428 | spin_lock_irqsave(&i8042_lock, flags); | 321 | spin_lock_irqsave(&i8042_lock, flags); |
| 429 | str = i8042_read_status(); | 322 | str = i8042_read_status(); |
| 430 | if (unlikely(~str & I8042_STR_OBF)) { | 323 | if (unlikely(~str & I8042_STR_OBF)) { |
| @@ -480,8 +373,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
| 480 | 373 | ||
| 481 | port = &i8042_ports[port_no]; | 374 | port = &i8042_ports[port_no]; |
| 482 | 375 | ||
| 483 | dbg("%02x <- i8042 (interrupt, %s, %d%s%s)", | 376 | dbg("%02x <- i8042 (interrupt, %d, %d%s%s)", |
| 484 | data, port->name, irq, | 377 | data, port_no, irq, |
| 485 | dfl & SERIO_PARITY ? ", bad parity" : "", | 378 | dfl & SERIO_PARITY ? ", bad parity" : "", |
| 486 | dfl & SERIO_TIMEOUT ? ", timeout" : ""); | 379 | dfl & SERIO_TIMEOUT ? ", timeout" : ""); |
| 487 | 380 | ||
| @@ -494,6 +387,58 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
| 494 | } | 387 | } |
| 495 | 388 | ||
| 496 | /* | 389 | /* |
| 390 | * i8042_enable_kbd_port enables keybaord port on chip | ||
| 391 | */ | ||
| 392 | |||
| 393 | static int i8042_enable_kbd_port(void) | ||
| 394 | { | ||
| 395 | i8042_ctr &= ~I8042_CTR_KBDDIS; | ||
| 396 | i8042_ctr |= I8042_CTR_KBDINT; | ||
| 397 | |||
| 398 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
| 399 | printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n"); | ||
| 400 | return -EIO; | ||
| 401 | } | ||
| 402 | |||
| 403 | return 0; | ||
| 404 | } | ||
| 405 | |||
| 406 | /* | ||
| 407 | * i8042_enable_aux_port enables AUX (mouse) port on chip | ||
| 408 | */ | ||
| 409 | |||
| 410 | static int i8042_enable_aux_port(void) | ||
| 411 | { | ||
| 412 | i8042_ctr &= ~I8042_CTR_AUXDIS; | ||
| 413 | i8042_ctr |= I8042_CTR_AUXINT; | ||
| 414 | |||
| 415 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
| 416 | printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n"); | ||
| 417 | return -EIO; | ||
| 418 | } | ||
| 419 | |||
| 420 | return 0; | ||
| 421 | } | ||
| 422 | |||
| 423 | /* | ||
| 424 | * i8042_enable_mux_ports enables 4 individual AUX ports after | ||
| 425 | * the controller has been switched into Multiplexed mode | ||
| 426 | */ | ||
| 427 | |||
| 428 | static int i8042_enable_mux_ports(void) | ||
| 429 | { | ||
| 430 | unsigned char param; | ||
| 431 | int i; | ||
| 432 | |||
| 433 | for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { | ||
| 434 | i8042_command(¶m, I8042_CMD_MUX_PFX + i); | ||
| 435 | i8042_command(¶m, I8042_CMD_AUX_ENABLE); | ||
| 436 | } | ||
| 437 | |||
| 438 | return i8042_enable_aux_port(); | ||
| 439 | } | ||
| 440 | |||
| 441 | /* | ||
| 497 | * i8042_set_mux_mode checks whether the controller has an active | 442 | * i8042_set_mux_mode checks whether the controller has an active |
| 498 | * multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode. | 443 | * multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode. |
| 499 | */ | 444 | */ |
| @@ -510,8 +455,7 @@ static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version) | |||
| 510 | 455 | ||
| 511 | /* | 456 | /* |
| 512 | * Internal loopback test - send three bytes, they should come back from the | 457 | * Internal loopback test - send three bytes, they should come back from the |
| 513 | * mouse interface, the last should be version. Note that we negate mouseport | 458 | * mouse interface, the last should be version. |
| 514 | * command responses for the i8042_check_aux() routine. | ||
| 515 | */ | 459 | */ |
| 516 | 460 | ||
| 517 | param = 0xf0; | 461 | param = 0xf0; |
| @@ -530,67 +474,67 @@ static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version) | |||
| 530 | return 0; | 474 | return 0; |
| 531 | } | 475 | } |
| 532 | 476 | ||
| 533 | |||
| 534 | /* | 477 | /* |
| 535 | * i8042_enable_mux_ports enables 4 individual AUX ports after | 478 | * i8042_check_mux() checks whether the controller supports the PS/2 Active |
| 536 | * the controller has been switched into Multiplexed mode | 479 | * Multiplexing specification by Synaptics, Phoenix, Insyde and |
| 480 | * LCS/Telegraphics. | ||
| 537 | */ | 481 | */ |
| 538 | 482 | ||
| 539 | static int i8042_enable_mux_ports(void) | 483 | static int __devinit i8042_check_mux(void) |
| 540 | { | 484 | { |
| 541 | unsigned char param; | 485 | unsigned char mux_version; |
| 542 | int i; | 486 | |
| 487 | if (i8042_set_mux_mode(1, &mux_version)) | ||
| 488 | return -1; | ||
| 489 | |||
| 543 | /* | 490 | /* |
| 544 | * Disable all muxed ports by disabling AUX. | 491 | * Workaround for interference with USB Legacy emulation |
| 492 | * that causes a v10.12 MUX to be found. | ||
| 545 | */ | 493 | */ |
| 494 | if (mux_version == 0xAC) | ||
| 495 | return -1; | ||
| 496 | |||
| 497 | printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", | ||
| 498 | (mux_version >> 4) & 0xf, mux_version & 0xf); | ||
| 546 | 499 | ||
| 500 | /* | ||
| 501 | * Disable all muxed ports by disabling AUX. | ||
| 502 | */ | ||
| 547 | i8042_ctr |= I8042_CTR_AUXDIS; | 503 | i8042_ctr |= I8042_CTR_AUXDIS; |
| 548 | i8042_ctr &= ~I8042_CTR_AUXINT; | 504 | i8042_ctr &= ~I8042_CTR_AUXINT; |
| 549 | 505 | ||
| 550 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | 506 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { |
| 551 | printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n"); | 507 | printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n"); |
| 552 | return -1; | 508 | return -EIO; |
| 553 | } | 509 | } |
| 554 | 510 | ||
| 555 | /* | 511 | i8042_mux_present = 1; |
| 556 | * Enable all muxed ports. | ||
| 557 | */ | ||
| 558 | |||
| 559 | for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { | ||
| 560 | i8042_command(¶m, I8042_CMD_MUX_PFX + i); | ||
| 561 | i8042_command(¶m, I8042_CMD_AUX_ENABLE); | ||
| 562 | } | ||
| 563 | 512 | ||
| 564 | return 0; | 513 | return 0; |
| 565 | } | 514 | } |
| 566 | 515 | ||
| 567 | |||
| 568 | /* | 516 | /* |
| 569 | * i8042_check_mux() checks whether the controller supports the PS/2 Active | 517 | * The following is used to test AUX IRQ delivery. |
| 570 | * Multiplexing specification by Synaptics, Phoenix, Insyde and | ||
| 571 | * LCS/Telegraphics. | ||
| 572 | */ | 518 | */ |
| 519 | static struct completion i8042_aux_irq_delivered __devinitdata; | ||
| 520 | static int i8042_irq_being_tested __devinitdata; | ||
| 573 | 521 | ||
| 574 | static int __devinit i8042_check_mux(void) | 522 | static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id, struct pt_regs *regs) |
| 575 | { | 523 | { |
| 576 | unsigned char mux_version; | 524 | unsigned long flags; |
| 577 | 525 | unsigned char str, data; | |
| 578 | if (i8042_set_mux_mode(1, &mux_version)) | ||
| 579 | return -1; | ||
| 580 | |||
| 581 | /* Workaround for interference with USB Legacy emulation */ | ||
| 582 | /* that causes a v10.12 MUX to be found. */ | ||
| 583 | if (mux_version == 0xAC) | ||
| 584 | return -1; | ||
| 585 | |||
| 586 | printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", | ||
| 587 | (mux_version >> 4) & 0xf, mux_version & 0xf); | ||
| 588 | 526 | ||
| 589 | if (i8042_enable_mux_ports()) | 527 | spin_lock_irqsave(&i8042_lock, flags); |
| 590 | return -1; | 528 | str = i8042_read_status(); |
| 529 | if (str & I8042_STR_OBF) { | ||
| 530 | data = i8042_read_data(); | ||
| 531 | if (i8042_irq_being_tested && | ||
| 532 | data == 0xa5 && (str & I8042_STR_AUXDATA)) | ||
| 533 | complete(&i8042_aux_irq_delivered); | ||
| 534 | } | ||
| 535 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
| 591 | 536 | ||
| 592 | i8042_mux_present = 1; | 537 | return IRQ_HANDLED; |
| 593 | return 0; | ||
| 594 | } | 538 | } |
| 595 | 539 | ||
| 596 | 540 | ||
| @@ -601,18 +545,10 @@ static int __devinit i8042_check_mux(void) | |||
| 601 | 545 | ||
| 602 | static int __devinit i8042_check_aux(void) | 546 | static int __devinit i8042_check_aux(void) |
| 603 | { | 547 | { |
| 548 | int retval = -1; | ||
| 549 | int irq_registered = 0; | ||
| 550 | unsigned long flags; | ||
| 604 | unsigned char param; | 551 | unsigned char param; |
| 605 | static int i8042_check_aux_cookie; | ||
| 606 | |||
| 607 | /* | ||
| 608 | * Check if AUX irq is available. If it isn't, then there is no point | ||
| 609 | * in trying to detect AUX presence. | ||
| 610 | */ | ||
| 611 | |||
| 612 | if (request_irq(i8042_ports[I8042_AUX_PORT_NO].irq, i8042_interrupt, | ||
| 613 | IRQF_SHARED, "i8042", &i8042_check_aux_cookie)) | ||
| 614 | return -1; | ||
| 615 | free_irq(i8042_ports[I8042_AUX_PORT_NO].irq, &i8042_check_aux_cookie); | ||
| 616 | 552 | ||
| 617 | /* | 553 | /* |
| 618 | * Get rid of bytes in the queue. | 554 | * Get rid of bytes in the queue. |
| @@ -637,9 +573,9 @@ static int __devinit i8042_check_aux(void) | |||
| 637 | * AUX ports, we test for this only when the LOOP command failed. | 573 | * AUX ports, we test for this only when the LOOP command failed. |
| 638 | */ | 574 | */ |
| 639 | 575 | ||
| 640 | if (i8042_command(¶m, I8042_CMD_AUX_TEST) | 576 | if (i8042_command(¶m, I8042_CMD_AUX_TEST) || |
| 641 | || (param && param != 0xfa && param != 0xff)) | 577 | (param && param != 0xfa && param != 0xff)) |
| 642 | return -1; | 578 | return -1; |
| 643 | } | 579 | } |
| 644 | 580 | ||
| 645 | /* | 581 | /* |
| @@ -659,54 +595,80 @@ static int __devinit i8042_check_aux(void) | |||
| 659 | return -1; | 595 | return -1; |
| 660 | 596 | ||
| 661 | /* | 597 | /* |
| 662 | * Disable the interface. | 598 | * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and |
| 599 | * used it for a PCI card or somethig else. | ||
| 663 | */ | 600 | */ |
| 664 | 601 | ||
| 665 | i8042_ctr |= I8042_CTR_AUXDIS; | 602 | if (i8042_noloop) { |
| 666 | i8042_ctr &= ~I8042_CTR_AUXINT; | 603 | /* |
| 604 | * Without LOOP command we can't test AUX IRQ delivery. Assume the port | ||
| 605 | * is working and hope we are right. | ||
| 606 | */ | ||
| 607 | retval = 0; | ||
| 608 | goto out; | ||
| 609 | } | ||
| 667 | 610 | ||
| 668 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) | 611 | if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED, |
| 669 | return -1; | 612 | "i8042", i8042_platform_device)) |
| 613 | goto out; | ||
| 670 | 614 | ||
| 671 | return 0; | 615 | irq_registered = 1; |
| 672 | } | 616 | |
| 617 | if (i8042_enable_aux_port()) | ||
| 618 | goto out; | ||
| 619 | |||
| 620 | spin_lock_irqsave(&i8042_lock, flags); | ||
| 673 | 621 | ||
| 622 | init_completion(&i8042_aux_irq_delivered); | ||
| 623 | i8042_irq_being_tested = 1; | ||
| 624 | |||
| 625 | param = 0xa5; | ||
| 626 | retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff); | ||
| 627 | |||
| 628 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
| 629 | |||
| 630 | if (retval) | ||
| 631 | goto out; | ||
| 674 | 632 | ||
| 633 | if (wait_for_completion_timeout(&i8042_aux_irq_delivered, | ||
| 634 | msecs_to_jiffies(250)) == 0) { | ||
| 675 | /* | 635 | /* |
| 676 | * i8042_port_register() marks the device as existing, | 636 | * AUX IRQ was never delivered so we need to flush the controller to |
| 677 | * registers it, and reports to the user. | 637 | * get rid of the byte we put there; otherwise keyboard may not work. |
| 678 | */ | 638 | */ |
| 639 | i8042_flush(); | ||
| 640 | retval = -1; | ||
| 641 | } | ||
| 679 | 642 | ||
| 680 | static int __devinit i8042_port_register(struct i8042_port *port) | 643 | out: |
| 681 | { | ||
| 682 | i8042_ctr &= ~port->disable; | ||
| 683 | 644 | ||
| 684 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | 645 | /* |
| 685 | printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n"); | 646 | * Disable the interface. |
| 686 | kfree(port->serio); | 647 | */ |
| 687 | port->serio = NULL; | ||
| 688 | i8042_ctr |= port->disable; | ||
| 689 | return -EIO; | ||
| 690 | } | ||
| 691 | 648 | ||
| 692 | printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n", | 649 | i8042_ctr |= I8042_CTR_AUXDIS; |
| 693 | port->name, | 650 | i8042_ctr &= ~I8042_CTR_AUXINT; |
| 694 | (unsigned long) I8042_DATA_REG, | ||
| 695 | (unsigned long) I8042_COMMAND_REG, | ||
| 696 | port->irq); | ||
| 697 | 651 | ||
| 698 | serio_register_port(port->serio); | 652 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) |
| 653 | retval = -1; | ||
| 699 | 654 | ||
| 700 | return 0; | 655 | if (irq_registered) |
| 701 | } | 656 | free_irq(I8042_AUX_IRQ, i8042_platform_device); |
| 702 | 657 | ||
| 658 | return retval; | ||
| 659 | } | ||
| 703 | 660 | ||
| 704 | static void i8042_timer_func(unsigned long data) | 661 | static int i8042_controller_check(void) |
| 705 | { | 662 | { |
| 706 | i8042_interrupt(0, NULL, NULL); | 663 | if (i8042_flush() == I8042_BUFFER_SIZE) { |
| 664 | printk(KERN_ERR "i8042.c: No controller found.\n"); | ||
| 665 | return -ENODEV; | ||
| 666 | } | ||
| 667 | |||
| 668 | return 0; | ||
| 707 | } | 669 | } |
| 708 | 670 | ||
| 709 | static int i8042_ctl_test(void) | 671 | static int i8042_controller_selftest(void) |
| 710 | { | 672 | { |
| 711 | unsigned char param; | 673 | unsigned char param; |
| 712 | 674 | ||
| @@ -715,13 +677,13 @@ static int i8042_ctl_test(void) | |||
| 715 | 677 | ||
| 716 | if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { | 678 | if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { |
| 717 | printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); | 679 | printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); |
| 718 | return -1; | 680 | return -ENODEV; |
| 719 | } | 681 | } |
| 720 | 682 | ||
| 721 | if (param != I8042_RET_CTL_TEST) { | 683 | if (param != I8042_RET_CTL_TEST) { |
| 722 | printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", | 684 | printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", |
| 723 | param, I8042_RET_CTL_TEST); | 685 | param, I8042_RET_CTL_TEST); |
| 724 | return -1; | 686 | return -EIO; |
| 725 | } | 687 | } |
| 726 | 688 | ||
| 727 | return 0; | 689 | return 0; |
| @@ -738,25 +700,12 @@ static int i8042_controller_init(void) | |||
| 738 | unsigned long flags; | 700 | unsigned long flags; |
| 739 | 701 | ||
| 740 | /* | 702 | /* |
| 741 | * Test the i8042. We need to know if it thinks it's working correctly | ||
| 742 | * before doing anything else. | ||
| 743 | */ | ||
| 744 | |||
| 745 | if (i8042_flush() == I8042_BUFFER_SIZE) { | ||
| 746 | printk(KERN_ERR "i8042.c: No controller found.\n"); | ||
| 747 | return -1; | ||
| 748 | } | ||
| 749 | |||
| 750 | if (i8042_ctl_test()) | ||
| 751 | return -1; | ||
| 752 | |||
| 753 | /* | ||
| 754 | * Save the CTR for restoral on unload / reboot. | 703 | * Save the CTR for restoral on unload / reboot. |
| 755 | */ | 704 | */ |
| 756 | 705 | ||
| 757 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { | 706 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { |
| 758 | printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); | 707 | printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); |
| 759 | return -1; | 708 | return -EIO; |
| 760 | } | 709 | } |
| 761 | 710 | ||
| 762 | i8042_initial_ctr = i8042_ctr; | 711 | i8042_initial_ctr = i8042_ctr; |
| @@ -805,7 +754,7 @@ static int i8042_controller_init(void) | |||
| 805 | 754 | ||
| 806 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | 755 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { |
| 807 | printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); | 756 | printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); |
| 808 | return -1; | 757 | return -EIO; |
| 809 | } | 758 | } |
| 810 | 759 | ||
| 811 | return 0; | 760 | return 0; |
| @@ -813,15 +762,12 @@ static int i8042_controller_init(void) | |||
| 813 | 762 | ||
| 814 | 763 | ||
| 815 | /* | 764 | /* |
| 816 | * Reset the controller. | 765 | * Reset the controller and reset CRT to the original value set by BIOS. |
| 817 | */ | 766 | */ |
| 767 | |||
| 818 | static void i8042_controller_reset(void) | 768 | static void i8042_controller_reset(void) |
| 819 | { | 769 | { |
| 820 | /* | 770 | i8042_flush(); |
| 821 | * Reset the controller if requested. | ||
| 822 | */ | ||
| 823 | |||
| 824 | i8042_ctl_test(); | ||
| 825 | 771 | ||
| 826 | /* | 772 | /* |
| 827 | * Disable MUX mode if present. | 773 | * Disable MUX mode if present. |
| @@ -831,12 +777,16 @@ static void i8042_controller_reset(void) | |||
| 831 | i8042_set_mux_mode(0, NULL); | 777 | i8042_set_mux_mode(0, NULL); |
| 832 | 778 | ||
| 833 | /* | 779 | /* |
| 834 | * Restore the original control register setting. | 780 | * Reset the controller if requested. |
| 835 | */ | 781 | */ |
| 836 | 782 | ||
| 837 | i8042_ctr = i8042_initial_ctr; | 783 | i8042_controller_selftest(); |
| 838 | 784 | ||
| 839 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) | 785 | /* |
| 786 | * Restore the original control register setting. | ||
| 787 | */ | ||
| 788 | |||
| 789 | if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) | ||
| 840 | printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); | 790 | printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); |
| 841 | } | 791 | } |
| 842 | 792 | ||
| @@ -850,14 +800,12 @@ static void i8042_controller_cleanup(void) | |||
| 850 | { | 800 | { |
| 851 | int i; | 801 | int i; |
| 852 | 802 | ||
| 853 | i8042_flush(); | ||
| 854 | |||
| 855 | /* | 803 | /* |
| 856 | * Reset anything that is connected to the ports. | 804 | * Reset anything that is connected to the ports. |
| 857 | */ | 805 | */ |
| 858 | 806 | ||
| 859 | for (i = 0; i < I8042_NUM_PORTS; i++) | 807 | for (i = 0; i < I8042_NUM_PORTS; i++) |
| 860 | if (i8042_ports[i].exists) | 808 | if (i8042_ports[i].serio) |
| 861 | serio_cleanup(i8042_ports[i].serio); | 809 | serio_cleanup(i8042_ports[i].serio); |
| 862 | 810 | ||
| 863 | i8042_controller_reset(); | 811 | i8042_controller_reset(); |
| @@ -913,8 +861,7 @@ static long i8042_panic_blink(long count) | |||
| 913 | 861 | ||
| 914 | static int i8042_suspend(struct platform_device *dev, pm_message_t state) | 862 | static int i8042_suspend(struct platform_device *dev, pm_message_t state) |
| 915 | { | 863 | { |
| 916 | del_timer_sync(&i8042_timer); | 864 | i8042_controller_cleanup(); |
| 917 | i8042_controller_reset(); | ||
| 918 | 865 | ||
| 919 | return 0; | 866 | return 0; |
| 920 | } | 867 | } |
| @@ -926,33 +873,39 @@ static int i8042_suspend(struct platform_device *dev, pm_message_t state) | |||
| 926 | 873 | ||
| 927 | static int i8042_resume(struct platform_device *dev) | 874 | static int i8042_resume(struct platform_device *dev) |
| 928 | { | 875 | { |
| 929 | int i; | 876 | int error; |
| 930 | 877 | ||
| 931 | if (i8042_ctl_test()) | 878 | error = i8042_controller_check(); |
| 932 | return -1; | 879 | if (error) |
| 880 | return error; | ||
| 933 | 881 | ||
| 934 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | 882 | error = i8042_controller_selftest(); |
| 935 | printk(KERN_ERR "i8042: Can't write CTR\n"); | 883 | if (error) |
| 936 | return -1; | 884 | return error; |
| 937 | } | ||
| 938 | |||
| 939 | if (i8042_mux_present) | ||
| 940 | if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports()) | ||
| 941 | printk(KERN_WARNING "i8042: failed to resume active multiplexor, mouse won't work.\n"); | ||
| 942 | 885 | ||
| 943 | /* | 886 | /* |
| 944 | * Activate all ports. | 887 | * Restore pre-resume CTR value and disable all ports |
| 945 | */ | 888 | */ |
| 946 | 889 | ||
| 947 | for (i = 0; i < I8042_NUM_PORTS; i++) | 890 | i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS; |
| 948 | i8042_activate_port(&i8042_ports[i]); | 891 | i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT); |
| 892 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
| 893 | printk(KERN_ERR "i8042: Can't write CTR to resume\n"); | ||
| 894 | return -EIO; | ||
| 895 | } | ||
| 949 | 896 | ||
| 950 | /* | 897 | if (i8042_mux_present) { |
| 951 | * Restart timer (for polling "stuck" data) | 898 | if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports()) |
| 952 | */ | 899 | printk(KERN_WARNING |
| 953 | mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); | 900 | "i8042: failed to resume active multiplexor, " |
| 901 | "mouse won't work.\n"); | ||
| 902 | } else if (i8042_ports[I8042_AUX_PORT_NO].serio) | ||
| 903 | i8042_enable_aux_port(); | ||
| 954 | 904 | ||
| 955 | panic_blink = i8042_panic_blink; | 905 | if (i8042_ports[I8042_KBD_PORT_NO].serio) |
| 906 | i8042_enable_kbd_port(); | ||
| 907 | |||
| 908 | i8042_interrupt(0, NULL, NULL); | ||
| 956 | 909 | ||
| 957 | return 0; | 910 | return 0; |
| 958 | } | 911 | } |
| @@ -978,24 +931,24 @@ static int __devinit i8042_create_kbd_port(void) | |||
| 978 | 931 | ||
| 979 | serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; | 932 | serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; |
| 980 | serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; | 933 | serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; |
| 981 | serio->open = i8042_open; | ||
| 982 | serio->close = i8042_close; | ||
| 983 | serio->start = i8042_start; | 934 | serio->start = i8042_start; |
| 984 | serio->stop = i8042_stop; | 935 | serio->stop = i8042_stop; |
| 985 | serio->port_data = port; | 936 | serio->port_data = port; |
| 986 | serio->dev.parent = &i8042_platform_device->dev; | 937 | serio->dev.parent = &i8042_platform_device->dev; |
| 987 | strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); | 938 | strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); |
| 988 | strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); | 939 | strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); |
| 989 | 940 | ||
| 990 | port->serio = serio; | 941 | port->serio = serio; |
| 942 | port->irq = I8042_KBD_IRQ; | ||
| 991 | 943 | ||
| 992 | return i8042_port_register(port); | 944 | return 0; |
| 993 | } | 945 | } |
| 994 | 946 | ||
| 995 | static int __devinit i8042_create_aux_port(void) | 947 | static int __devinit i8042_create_aux_port(int idx) |
| 996 | { | 948 | { |
| 997 | struct serio *serio; | 949 | struct serio *serio; |
| 998 | struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO]; | 950 | int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx; |
| 951 | struct i8042_port *port = &i8042_ports[port_no]; | ||
| 999 | 952 | ||
| 1000 | serio = kzalloc(sizeof(struct serio), GFP_KERNEL); | 953 | serio = kzalloc(sizeof(struct serio), GFP_KERNEL); |
| 1001 | if (!serio) | 954 | if (!serio) |
| @@ -1003,111 +956,191 @@ static int __devinit i8042_create_aux_port(void) | |||
| 1003 | 956 | ||
| 1004 | serio->id.type = SERIO_8042; | 957 | serio->id.type = SERIO_8042; |
| 1005 | serio->write = i8042_aux_write; | 958 | serio->write = i8042_aux_write; |
| 1006 | serio->open = i8042_open; | ||
| 1007 | serio->close = i8042_close; | ||
| 1008 | serio->start = i8042_start; | 959 | serio->start = i8042_start; |
| 1009 | serio->stop = i8042_stop; | 960 | serio->stop = i8042_stop; |
| 1010 | serio->port_data = port; | 961 | serio->port_data = port; |
| 1011 | serio->dev.parent = &i8042_platform_device->dev; | 962 | serio->dev.parent = &i8042_platform_device->dev; |
| 1012 | strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); | 963 | if (idx < 0) { |
| 1013 | strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); | 964 | strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name)); |
| 965 | strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); | ||
| 966 | } else { | ||
| 967 | snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); | ||
| 968 | snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1); | ||
| 969 | } | ||
| 1014 | 970 | ||
| 1015 | port->serio = serio; | 971 | port->serio = serio; |
| 972 | port->mux = idx; | ||
| 973 | port->irq = I8042_AUX_IRQ; | ||
| 1016 | 974 | ||
| 1017 | return i8042_port_register(port); | 975 | return 0; |
| 1018 | } | 976 | } |
| 1019 | 977 | ||
| 1020 | static int __devinit i8042_create_mux_port(int index) | 978 | static void __devinit i8042_free_kbd_port(void) |
| 1021 | { | 979 | { |
| 1022 | struct serio *serio; | 980 | kfree(i8042_ports[I8042_KBD_PORT_NO].serio); |
| 1023 | struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index]; | 981 | i8042_ports[I8042_KBD_PORT_NO].serio = NULL; |
| 982 | } | ||
| 1024 | 983 | ||
| 1025 | serio = kzalloc(sizeof(struct serio), GFP_KERNEL); | 984 | static void __devinit i8042_free_aux_ports(void) |
| 1026 | if (!serio) | 985 | { |
| 1027 | return -ENOMEM; | 986 | int i; |
| 1028 | 987 | ||
| 1029 | serio->id.type = SERIO_8042; | 988 | for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) { |
| 1030 | serio->write = i8042_aux_write; | 989 | kfree(i8042_ports[i].serio); |
| 1031 | serio->open = i8042_open; | 990 | i8042_ports[i].serio = NULL; |
| 1032 | serio->close = i8042_close; | 991 | } |
| 1033 | serio->start = i8042_start; | 992 | } |
| 1034 | serio->stop = i8042_stop; | ||
| 1035 | serio->port_data = port; | ||
| 1036 | serio->dev.parent = &i8042_platform_device->dev; | ||
| 1037 | snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); | ||
| 1038 | snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); | ||
| 1039 | 993 | ||
| 1040 | *port = i8042_ports[I8042_AUX_PORT_NO]; | 994 | static void __devinit i8042_register_ports(void) |
| 1041 | port->exists = 0; | 995 | { |
| 1042 | snprintf(port->name, sizeof(port->name), "AUX%d", index); | 996 | int i; |
| 1043 | port->mux = index; | ||
| 1044 | port->serio = serio; | ||
| 1045 | 997 | ||
| 1046 | return i8042_port_register(port); | 998 | for (i = 0; i < I8042_NUM_PORTS; i++) { |
| 999 | if (i8042_ports[i].serio) { | ||
| 1000 | printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n", | ||
| 1001 | i8042_ports[i].serio->name, | ||
| 1002 | (unsigned long) I8042_DATA_REG, | ||
| 1003 | (unsigned long) I8042_COMMAND_REG, | ||
| 1004 | i8042_ports[i].irq); | ||
| 1005 | serio_register_port(i8042_ports[i].serio); | ||
| 1006 | } | ||
| 1007 | } | ||
| 1047 | } | 1008 | } |
| 1048 | 1009 | ||
| 1049 | static int __devinit i8042_probe(struct platform_device *dev) | 1010 | static void __devinit i8042_unregister_ports(void) |
| 1050 | { | 1011 | { |
| 1051 | int i, have_ports = 0; | 1012 | int i; |
| 1052 | int err; | ||
| 1053 | 1013 | ||
| 1054 | init_timer(&i8042_timer); | 1014 | for (i = 0; i < I8042_NUM_PORTS; i++) { |
| 1055 | i8042_timer.function = i8042_timer_func; | 1015 | if (i8042_ports[i].serio) { |
| 1016 | serio_unregister_port(i8042_ports[i].serio); | ||
| 1017 | i8042_ports[i].serio = NULL; | ||
| 1018 | } | ||
| 1019 | } | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | static void i8042_free_irqs(void) | ||
| 1023 | { | ||
| 1024 | if (i8042_aux_irq_registered) | ||
| 1025 | free_irq(I8042_AUX_IRQ, i8042_platform_device); | ||
| 1026 | if (i8042_kbd_irq_registered) | ||
| 1027 | free_irq(I8042_KBD_IRQ, i8042_platform_device); | ||
| 1028 | |||
| 1029 | i8042_aux_irq_registered = i8042_kbd_irq_registered = 0; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | static int __devinit i8042_setup_aux(void) | ||
| 1033 | { | ||
| 1034 | int (*aux_enable)(void); | ||
| 1035 | int error; | ||
| 1036 | int i; | ||
| 1056 | 1037 | ||
| 1057 | if (i8042_controller_init()) | 1038 | if (i8042_check_aux()) |
| 1058 | return -ENODEV; | 1039 | return -ENODEV; |
| 1059 | 1040 | ||
| 1060 | if (!i8042_noaux && !i8042_check_aux()) { | 1041 | if (i8042_nomux || i8042_check_mux()) { |
| 1061 | if (!i8042_nomux && !i8042_check_mux()) { | 1042 | error = i8042_create_aux_port(-1); |
| 1062 | for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { | 1043 | if (error) |
| 1063 | err = i8042_create_mux_port(i); | 1044 | goto err_free_ports; |
| 1064 | if (err) | 1045 | aux_enable = i8042_enable_aux_port; |
| 1065 | goto err_unregister_ports; | 1046 | } else { |
| 1066 | } | 1047 | for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { |
| 1067 | } else { | 1048 | error = i8042_create_aux_port(i); |
| 1068 | err = i8042_create_aux_port(); | 1049 | if (error) |
| 1069 | if (err) | 1050 | goto err_free_ports; |
| 1070 | goto err_unregister_ports; | ||
| 1071 | } | 1051 | } |
| 1072 | have_ports = 1; | 1052 | aux_enable = i8042_enable_mux_ports; |
| 1073 | } | 1053 | } |
| 1074 | 1054 | ||
| 1075 | if (!i8042_nokbd) { | 1055 | error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED, |
| 1076 | err = i8042_create_kbd_port(); | 1056 | "i8042", i8042_platform_device); |
| 1077 | if (err) | 1057 | if (error) |
| 1078 | goto err_unregister_ports; | 1058 | goto err_free_ports; |
| 1079 | have_ports = 1; | ||
| 1080 | } | ||
| 1081 | 1059 | ||
| 1082 | if (!have_ports) { | 1060 | if (aux_enable()) |
| 1083 | err = -ENODEV; | 1061 | goto err_free_irq; |
| 1084 | goto err_controller_cleanup; | ||
| 1085 | } | ||
| 1086 | 1062 | ||
| 1087 | mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); | 1063 | i8042_aux_irq_registered = 1; |
| 1088 | return 0; | 1064 | return 0; |
| 1089 | 1065 | ||
| 1090 | err_unregister_ports: | 1066 | err_free_irq: |
| 1091 | for (i = 0; i < I8042_NUM_PORTS; i++) | 1067 | free_irq(I8042_AUX_IRQ, i8042_platform_device); |
| 1092 | if (i8042_ports[i].serio) | 1068 | err_free_ports: |
| 1093 | serio_unregister_port(i8042_ports[i].serio); | 1069 | i8042_free_aux_ports(); |
| 1094 | err_controller_cleanup: | 1070 | return error; |
| 1095 | i8042_controller_cleanup(); | 1071 | } |
| 1096 | 1072 | ||
| 1097 | return err; | 1073 | static int __devinit i8042_setup_kbd(void) |
| 1074 | { | ||
| 1075 | int error; | ||
| 1076 | |||
| 1077 | error = i8042_create_kbd_port(); | ||
| 1078 | if (error) | ||
| 1079 | return error; | ||
| 1080 | |||
| 1081 | error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED, | ||
| 1082 | "i8042", i8042_platform_device); | ||
| 1083 | if (error) | ||
| 1084 | goto err_free_port; | ||
| 1085 | |||
| 1086 | error = i8042_enable_kbd_port(); | ||
| 1087 | if (error) | ||
| 1088 | goto err_free_irq; | ||
| 1089 | |||
| 1090 | i8042_kbd_irq_registered = 1; | ||
| 1091 | return 0; | ||
| 1092 | |||
| 1093 | err_free_irq: | ||
| 1094 | free_irq(I8042_KBD_IRQ, i8042_platform_device); | ||
| 1095 | err_free_port: | ||
| 1096 | i8042_free_kbd_port(); | ||
| 1097 | return error; | ||
| 1098 | } | 1098 | } |
| 1099 | 1099 | ||
| 1100 | static int __devexit i8042_remove(struct platform_device *dev) | 1100 | static int __devinit i8042_probe(struct platform_device *dev) |
| 1101 | { | 1101 | { |
| 1102 | int i; | 1102 | int error; |
| 1103 | 1103 | ||
| 1104 | i8042_controller_cleanup(); | 1104 | error = i8042_controller_selftest(); |
| 1105 | if (error) | ||
| 1106 | return error; | ||
| 1105 | 1107 | ||
| 1106 | for (i = 0; i < I8042_NUM_PORTS; i++) | 1108 | error = i8042_controller_init(); |
| 1107 | if (i8042_ports[i].exists) | 1109 | if (error) |
| 1108 | serio_unregister_port(i8042_ports[i].serio); | 1110 | return error; |
| 1111 | |||
| 1112 | if (!i8042_noaux) { | ||
| 1113 | error = i8042_setup_aux(); | ||
| 1114 | if (error && error != -ENODEV && error != -EBUSY) | ||
| 1115 | goto out_fail; | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | if (!i8042_nokbd) { | ||
| 1119 | error = i8042_setup_kbd(); | ||
| 1120 | if (error) | ||
| 1121 | goto out_fail; | ||
| 1122 | } | ||
| 1109 | 1123 | ||
| 1110 | del_timer_sync(&i8042_timer); | 1124 | /* |
| 1125 | * Ok, everything is ready, let's register all serio ports | ||
| 1126 | */ | ||
| 1127 | i8042_register_ports(); | ||
| 1128 | |||
| 1129 | return 0; | ||
| 1130 | |||
| 1131 | out_fail: | ||
| 1132 | i8042_free_aux_ports(); /* in case KBD failed but AUX not */ | ||
| 1133 | i8042_free_irqs(); | ||
| 1134 | i8042_controller_reset(); | ||
| 1135 | |||
| 1136 | return error; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | static int __devexit i8042_remove(struct platform_device *dev) | ||
| 1140 | { | ||
| 1141 | i8042_unregister_ports(); | ||
| 1142 | i8042_free_irqs(); | ||
| 1143 | i8042_controller_reset(); | ||
| 1111 | 1144 | ||
| 1112 | return 0; | 1145 | return 0; |
| 1113 | } | 1146 | } |
| @@ -1134,8 +1167,9 @@ static int __init i8042_init(void) | |||
| 1134 | if (err) | 1167 | if (err) |
| 1135 | return err; | 1168 | return err; |
| 1136 | 1169 | ||
| 1137 | i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ; | 1170 | err = i8042_controller_check(); |
| 1138 | i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ; | 1171 | if (err) |
| 1172 | goto err_platform_exit; | ||
| 1139 | 1173 | ||
| 1140 | err = platform_driver_register(&i8042_driver); | 1174 | err = platform_driver_register(&i8042_driver); |
| 1141 | if (err) | 1175 | if (err) |
| @@ -1151,6 +1185,8 @@ static int __init i8042_init(void) | |||
| 1151 | if (err) | 1185 | if (err) |
| 1152 | goto err_free_device; | 1186 | goto err_free_device; |
| 1153 | 1187 | ||
| 1188 | panic_blink = i8042_panic_blink; | ||
| 1189 | |||
| 1154 | return 0; | 1190 | return 0; |
| 1155 | 1191 | ||
| 1156 | err_free_device: | 1192 | err_free_device: |
| @@ -1167,7 +1203,6 @@ static void __exit i8042_exit(void) | |||
| 1167 | { | 1203 | { |
| 1168 | platform_device_unregister(i8042_platform_device); | 1204 | platform_device_unregister(i8042_platform_device); |
| 1169 | platform_driver_unregister(&i8042_driver); | 1205 | platform_driver_unregister(&i8042_driver); |
| 1170 | |||
| 1171 | i8042_platform_exit(); | 1206 | i8042_platform_exit(); |
| 1172 | 1207 | ||
| 1173 | panic_blink = NULL; | 1208 | panic_blink = NULL; |
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h index af526ab9ec..b3eb7a72d9 100644 --- a/drivers/input/serio/i8042.h +++ b/drivers/input/serio/i8042.h | |||
| @@ -37,15 +37,6 @@ | |||
| 37 | #define I8042_CTL_TIMEOUT 10000 | 37 | #define I8042_CTL_TIMEOUT 10000 |
| 38 | 38 | ||
| 39 | /* | 39 | /* |
| 40 | * When the device isn't opened and it's interrupts aren't used, we poll it at | ||
| 41 | * regular intervals to see if any characters arrived. If yes, we can start | ||
| 42 | * probing for any mouse / keyboard connected. This is the period of the | ||
| 43 | * polling. | ||
| 44 | */ | ||
| 45 | |||
| 46 | #define I8042_POLL_PERIOD HZ/20 | ||
| 47 | |||
| 48 | /* | ||
| 49 | * Status register bits. | 40 | * Status register bits. |
| 50 | */ | 41 | */ |
| 51 | 42 | ||
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index ed202f2f25..dcb16b5cbe 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c | |||
| @@ -27,15 +27,6 @@ MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); | |||
| 27 | MODULE_DESCRIPTION("PS/2 driver library"); | 27 | MODULE_DESCRIPTION("PS/2 driver library"); |
| 28 | MODULE_LICENSE("GPL"); | 28 | MODULE_LICENSE("GPL"); |
| 29 | 29 | ||
| 30 | EXPORT_SYMBOL(ps2_init); | ||
| 31 | EXPORT_SYMBOL(ps2_sendbyte); | ||
| 32 | EXPORT_SYMBOL(ps2_drain); | ||
| 33 | EXPORT_SYMBOL(ps2_command); | ||
| 34 | EXPORT_SYMBOL(ps2_schedule_command); | ||
| 35 | EXPORT_SYMBOL(ps2_handle_ack); | ||
| 36 | EXPORT_SYMBOL(ps2_handle_response); | ||
| 37 | EXPORT_SYMBOL(ps2_cmd_aborted); | ||
| 38 | |||
| 39 | /* Work structure to schedule execution of a command */ | 30 | /* Work structure to schedule execution of a command */ |
| 40 | struct ps2work { | 31 | struct ps2work { |
| 41 | struct work_struct work; | 32 | struct work_struct work; |
| @@ -71,6 +62,7 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout) | |||
| 71 | 62 | ||
| 72 | return -ps2dev->nak; | 63 | return -ps2dev->nak; |
| 73 | } | 64 | } |
| 65 | EXPORT_SYMBOL(ps2_sendbyte); | ||
| 74 | 66 | ||
| 75 | /* | 67 | /* |
| 76 | * ps2_drain() waits for device to transmit requested number of bytes | 68 | * ps2_drain() waits for device to transmit requested number of bytes |
| @@ -96,15 +88,16 @@ void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout) | |||
| 96 | msecs_to_jiffies(timeout)); | 88 | msecs_to_jiffies(timeout)); |
| 97 | mutex_unlock(&ps2dev->cmd_mutex); | 89 | mutex_unlock(&ps2dev->cmd_mutex); |
| 98 | } | 90 | } |
| 91 | EXPORT_SYMBOL(ps2_drain); | ||
| 99 | 92 | ||
| 100 | /* | 93 | /* |
| 101 | * ps2_is_keyboard_id() checks received ID byte against the list of | 94 | * ps2_is_keyboard_id() checks received ID byte against the list of |
| 102 | * known keyboard IDs. | 95 | * known keyboard IDs. |
| 103 | */ | 96 | */ |
| 104 | 97 | ||
| 105 | static inline int ps2_is_keyboard_id(char id_byte) | 98 | int ps2_is_keyboard_id(char id_byte) |
| 106 | { | 99 | { |
| 107 | static char keyboard_ids[] = { | 100 | const static char keyboard_ids[] = { |
| 108 | 0xab, /* Regular keyboards */ | 101 | 0xab, /* Regular keyboards */ |
| 109 | 0xac, /* NCD Sun keyboard */ | 102 | 0xac, /* NCD Sun keyboard */ |
| 110 | 0x2b, /* Trust keyboard, translated */ | 103 | 0x2b, /* Trust keyboard, translated */ |
| @@ -115,6 +108,7 @@ static inline int ps2_is_keyboard_id(char id_byte) | |||
| 115 | 108 | ||
| 116 | return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL; | 109 | return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL; |
| 117 | } | 110 | } |
| 111 | EXPORT_SYMBOL(ps2_is_keyboard_id); | ||
| 118 | 112 | ||
| 119 | /* | 113 | /* |
| 120 | * ps2_adjust_timeout() is called after receiving 1st byte of command | 114 | * ps2_adjust_timeout() is called after receiving 1st byte of command |
| @@ -139,6 +133,19 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout) | |||
| 139 | 133 | ||
| 140 | case PS2_CMD_GETID: | 134 | case PS2_CMD_GETID: |
| 141 | /* | 135 | /* |
| 136 | * Microsoft Natural Elite keyboard responds to | ||
| 137 | * the GET ID command as it were a mouse, with | ||
| 138 | * a single byte. Fail the command so atkbd will | ||
| 139 | * use alternative probe to detect it. | ||
| 140 | */ | ||
| 141 | if (ps2dev->cmdbuf[1] == 0xaa) { | ||
| 142 | serio_pause_rx(ps2dev->serio); | ||
| 143 | ps2dev->flags = 0; | ||
| 144 | serio_continue_rx(ps2dev->serio); | ||
| 145 | timeout = 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | /* | ||
| 142 | * If device behind the port is not a keyboard there | 149 | * If device behind the port is not a keyboard there |
| 143 | * won't be 2nd byte of ID response. | 150 | * won't be 2nd byte of ID response. |
| 144 | */ | 151 | */ |
| @@ -237,6 +244,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) | |||
| 237 | mutex_unlock(&ps2dev->cmd_mutex); | 244 | mutex_unlock(&ps2dev->cmd_mutex); |
| 238 | return rc; | 245 | return rc; |
| 239 | } | 246 | } |
| 247 | EXPORT_SYMBOL(ps2_command); | ||
| 240 | 248 | ||
| 241 | /* | 249 | /* |
| 242 | * ps2_execute_scheduled_command() sends a command, previously scheduled by | 250 | * ps2_execute_scheduled_command() sends a command, previously scheduled by |
| @@ -279,6 +287,7 @@ int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int comman | |||
| 279 | 287 | ||
| 280 | return 0; | 288 | return 0; |
| 281 | } | 289 | } |
| 290 | EXPORT_SYMBOL(ps2_schedule_command); | ||
| 282 | 291 | ||
| 283 | /* | 292 | /* |
| 284 | * ps2_init() initializes ps2dev structure | 293 | * ps2_init() initializes ps2dev structure |
| @@ -290,6 +299,7 @@ void ps2_init(struct ps2dev *ps2dev, struct serio *serio) | |||
| 290 | init_waitqueue_head(&ps2dev->wait); | 299 | init_waitqueue_head(&ps2dev->wait); |
| 291 | ps2dev->serio = serio; | 300 | ps2dev->serio = serio; |
| 292 | } | 301 | } |
| 302 | EXPORT_SYMBOL(ps2_init); | ||
| 293 | 303 | ||
| 294 | /* | 304 | /* |
| 295 | * ps2_handle_ack() is supposed to be used in interrupt handler | 305 | * ps2_handle_ack() is supposed to be used in interrupt handler |
| @@ -335,6 +345,7 @@ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data) | |||
| 335 | 345 | ||
| 336 | return 1; | 346 | return 1; |
| 337 | } | 347 | } |
| 348 | EXPORT_SYMBOL(ps2_handle_ack); | ||
| 338 | 349 | ||
| 339 | /* | 350 | /* |
| 340 | * ps2_handle_response() is supposed to be used in interrupt handler | 351 | * ps2_handle_response() is supposed to be used in interrupt handler |
| @@ -360,6 +371,7 @@ int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data) | |||
| 360 | 371 | ||
| 361 | return 1; | 372 | return 1; |
| 362 | } | 373 | } |
| 374 | EXPORT_SYMBOL(ps2_handle_response); | ||
| 363 | 375 | ||
| 364 | void ps2_cmd_aborted(struct ps2dev *ps2dev) | 376 | void ps2_cmd_aborted(struct ps2dev *ps2dev) |
| 365 | { | 377 | { |
| @@ -371,4 +383,4 @@ void ps2_cmd_aborted(struct ps2dev *ps2dev) | |||
| 371 | 383 | ||
| 372 | ps2dev->flags = 0; | 384 | ps2dev->flags = 0; |
| 373 | } | 385 | } |
| 374 | 386 | EXPORT_SYMBOL(ps2_cmd_aborted); | |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index b1b14f8d4d..9418bbe470 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
| @@ -108,4 +108,40 @@ config TOUCHSCREEN_HP600 | |||
| 108 | To compile this driver as a module, choose M here: the | 108 | To compile this driver as a module, choose M here: the |
| 109 | module will be called hp680_ts_input. | 109 | module will be called hp680_ts_input. |
| 110 | 110 | ||
| 111 | config TOUCHSCREEN_PENMOUNT | ||
| 112 | tristate "Penmount serial touchscreen" | ||
| 113 | select SERIO | ||
| 114 | help | ||
| 115 | Say Y here if you have a Penmount serial touchscreen connected to | ||
| 116 | your system. | ||
| 117 | |||
| 118 | If unsure, say N. | ||
| 119 | |||
| 120 | To compile this driver as a module, choose M here: the | ||
| 121 | module will be called penmount. | ||
| 122 | |||
| 123 | config TOUCHSCREEN_TOUCHRIGHT | ||
| 124 | tristate "Touchright serial touchscreen" | ||
| 125 | select SERIO | ||
| 126 | help | ||
| 127 | Say Y here if you have a Touchright serial touchscreen connected to | ||
| 128 | your system. | ||
| 129 | |||
| 130 | If unsure, say N. | ||
| 131 | |||
| 132 | To compile this driver as a module, choose M here: the | ||
| 133 | module will be called touchright. | ||
| 134 | |||
| 135 | config TOUCHSCREEN_TOUCHWIN | ||
| 136 | tristate "Touchwin serial touchscreen" | ||
| 137 | select SERIO | ||
| 138 | help | ||
| 139 | Say Y here if you have a Touchwin serial touchscreen connected to | ||
| 140 | your system. | ||
| 141 | |||
| 142 | If unsure, say N. | ||
| 143 | |||
| 144 | To compile this driver as a module, choose M here: the | ||
| 145 | module will be called touchwin. | ||
| 146 | |||
| 111 | endif | 147 | endif |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 5e5557c431..1abb8f10d6 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
| @@ -12,3 +12,6 @@ obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o | |||
| 12 | obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o | 12 | obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o |
| 13 | obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o | 13 | obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o |
| 14 | obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o | 14 | obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o |
| 15 | obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o | ||
| 16 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o | ||
| 17 | obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o | ||
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index c86a2eb310..ab565335ee 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/input.h> | 23 | #include <linux/input.h> |
| 24 | #include <linux/serio.h> | 24 | #include <linux/serio.h> |
| 25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
| 26 | #include <linux/ctype.h> | ||
| 26 | 27 | ||
| 27 | #define DRIVER_DESC "Elo serial touchscreen driver" | 28 | #define DRIVER_DESC "Elo serial touchscreen driver" |
| 28 | 29 | ||
| @@ -34,7 +35,19 @@ MODULE_LICENSE("GPL"); | |||
| 34 | * Definitions & global arrays. | 35 | * Definitions & global arrays. |
| 35 | */ | 36 | */ |
| 36 | 37 | ||
| 37 | #define ELO_MAX_LENGTH 10 | 38 | #define ELO_MAX_LENGTH 10 |
| 39 | |||
| 40 | #define ELO10_PACKET_LEN 8 | ||
| 41 | #define ELO10_TOUCH 0x03 | ||
| 42 | #define ELO10_PRESSURE 0x80 | ||
| 43 | |||
| 44 | #define ELO10_LEAD_BYTE 'U' | ||
| 45 | |||
| 46 | #define ELO10_ID_CMD 'i' | ||
| 47 | |||
| 48 | #define ELO10_TOUCH_PACKET 'T' | ||
| 49 | #define ELO10_ACK_PACKET 'A' | ||
| 50 | #define ELI10_ID_PACKET 'I' | ||
| 38 | 51 | ||
| 39 | /* | 52 | /* |
| 40 | * Per-touchscreen data. | 53 | * Per-touchscreen data. |
| @@ -43,51 +56,67 @@ MODULE_LICENSE("GPL"); | |||
| 43 | struct elo { | 56 | struct elo { |
| 44 | struct input_dev *dev; | 57 | struct input_dev *dev; |
| 45 | struct serio *serio; | 58 | struct serio *serio; |
| 59 | struct mutex cmd_mutex; | ||
| 60 | struct completion cmd_done; | ||
| 46 | int id; | 61 | int id; |
| 47 | int idx; | 62 | int idx; |
| 63 | unsigned char expected_packet; | ||
| 48 | unsigned char csum; | 64 | unsigned char csum; |
| 49 | unsigned char data[ELO_MAX_LENGTH]; | 65 | unsigned char data[ELO_MAX_LENGTH]; |
| 66 | unsigned char response[ELO10_PACKET_LEN]; | ||
| 50 | char phys[32]; | 67 | char phys[32]; |
| 51 | }; | 68 | }; |
| 52 | 69 | ||
| 53 | static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_regs *regs) | 70 | static void elo_process_data_10(struct elo *elo, unsigned char data, struct pt_regs *regs) |
| 54 | { | 71 | { |
| 55 | struct input_dev *dev = elo->dev; | 72 | struct input_dev *dev = elo->dev; |
| 56 | 73 | ||
| 57 | elo->csum += elo->data[elo->idx] = data; | 74 | elo->data[elo->idx] = data; |
| 58 | |||
| 59 | switch (elo->idx++) { | 75 | switch (elo->idx++) { |
| 60 | |||
| 61 | case 0: | 76 | case 0: |
| 62 | if (data != 'U') { | 77 | elo->csum = 0xaa; |
| 78 | if (data != ELO10_LEAD_BYTE) { | ||
| 79 | pr_debug("elo: unsynchronized data: 0x%02x\n", data); | ||
| 63 | elo->idx = 0; | 80 | elo->idx = 0; |
| 64 | elo->csum = 0; | ||
| 65 | } | ||
| 66 | break; | ||
| 67 | |||
| 68 | case 1: | ||
| 69 | if (data != 'T') { | ||
| 70 | elo->idx = 0; | ||
| 71 | elo->csum = 0; | ||
| 72 | } | 81 | } |
| 73 | break; | 82 | break; |
| 74 | 83 | ||
| 75 | case 9: | 84 | case 9: |
| 76 | if (elo->csum) { | 85 | elo->idx = 0; |
| 86 | if (data != elo->csum) { | ||
| 87 | pr_debug("elo: bad checksum: 0x%02x, expected 0x%02x\n", | ||
| 88 | data, elo->csum); | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | if (elo->data[1] != elo->expected_packet) { | ||
| 92 | if (elo->data[1] != ELO10_TOUCH_PACKET) | ||
| 93 | pr_debug("elo: unexpected packet: 0x%02x\n", | ||
| 94 | elo->data[1]); | ||
| 95 | break; | ||
| 96 | } | ||
| 97 | if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) { | ||
| 77 | input_regs(dev, regs); | 98 | input_regs(dev, regs); |
| 78 | input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); | 99 | input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); |
| 79 | input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); | 100 | input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); |
| 80 | input_report_abs(dev, ABS_PRESSURE, (elo->data[8] << 8) | elo->data[7]); | 101 | if (elo->data[2] & ELO10_PRESSURE) |
| 81 | input_report_key(dev, BTN_TOUCH, elo->data[8] || elo->data[7]); | 102 | input_report_abs(dev, ABS_PRESSURE, |
| 103 | (elo->data[8] << 8) | elo->data[7]); | ||
| 104 | input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH); | ||
| 82 | input_sync(dev); | 105 | input_sync(dev); |
| 106 | } else if (elo->data[1] == ELO10_ACK_PACKET) { | ||
| 107 | if (elo->data[2] == '0') | ||
| 108 | elo->expected_packet = ELO10_TOUCH_PACKET; | ||
| 109 | complete(&elo->cmd_done); | ||
| 110 | } else { | ||
| 111 | memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN); | ||
| 112 | elo->expected_packet = ELO10_ACK_PACKET; | ||
| 83 | } | 113 | } |
| 84 | elo->idx = 0; | ||
| 85 | elo->csum = 0; | ||
| 86 | break; | 114 | break; |
| 87 | } | 115 | } |
| 116 | elo->csum += data; | ||
| 88 | } | 117 | } |
| 89 | 118 | ||
| 90 | static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_regs *regs) | 119 | static void elo_process_data_6(struct elo *elo, unsigned char data, struct pt_regs *regs) |
| 91 | { | 120 | { |
| 92 | struct input_dev *dev = elo->dev; | 121 | struct input_dev *dev = elo->dev; |
| 93 | 122 | ||
| @@ -135,7 +164,7 @@ static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_re | |||
| 135 | } | 164 | } |
| 136 | } | 165 | } |
| 137 | 166 | ||
| 138 | static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_regs *regs) | 167 | static void elo_process_data_3(struct elo *elo, unsigned char data, struct pt_regs *regs) |
| 139 | { | 168 | { |
| 140 | struct input_dev *dev = elo->dev; | 169 | struct input_dev *dev = elo->dev; |
| 141 | 170 | ||
| @@ -161,7 +190,7 @@ static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_re | |||
| 161 | static irqreturn_t elo_interrupt(struct serio *serio, | 190 | static irqreturn_t elo_interrupt(struct serio *serio, |
| 162 | unsigned char data, unsigned int flags, struct pt_regs *regs) | 191 | unsigned char data, unsigned int flags, struct pt_regs *regs) |
| 163 | { | 192 | { |
| 164 | struct elo* elo = serio_get_drvdata(serio); | 193 | struct elo *elo = serio_get_drvdata(serio); |
| 165 | 194 | ||
| 166 | switch(elo->id) { | 195 | switch(elo->id) { |
| 167 | case 0: | 196 | case 0: |
| @@ -181,17 +210,81 @@ static irqreturn_t elo_interrupt(struct serio *serio, | |||
| 181 | return IRQ_HANDLED; | 210 | return IRQ_HANDLED; |
| 182 | } | 211 | } |
| 183 | 212 | ||
| 213 | static int elo_command_10(struct elo *elo, unsigned char *packet) | ||
| 214 | { | ||
| 215 | int rc = -1; | ||
| 216 | int i; | ||
| 217 | unsigned char csum = 0xaa + ELO10_LEAD_BYTE; | ||
| 218 | |||
| 219 | mutex_lock(&elo->cmd_mutex); | ||
| 220 | |||
| 221 | serio_pause_rx(elo->serio); | ||
| 222 | elo->expected_packet = toupper(packet[0]); | ||
| 223 | init_completion(&elo->cmd_done); | ||
| 224 | serio_continue_rx(elo->serio); | ||
| 225 | |||
| 226 | if (serio_write(elo->serio, ELO10_LEAD_BYTE)) | ||
| 227 | goto out; | ||
| 228 | |||
| 229 | for (i = 0; i < ELO10_PACKET_LEN; i++) { | ||
| 230 | csum += packet[i]; | ||
| 231 | if (serio_write(elo->serio, packet[i])) | ||
| 232 | goto out; | ||
| 233 | } | ||
| 234 | |||
| 235 | if (serio_write(elo->serio, csum)) | ||
| 236 | goto out; | ||
| 237 | |||
| 238 | wait_for_completion_timeout(&elo->cmd_done, HZ); | ||
| 239 | |||
| 240 | if (elo->expected_packet == ELO10_TOUCH_PACKET) { | ||
| 241 | /* We are back in reporting mode, the command was ACKed */ | ||
| 242 | memcpy(packet, elo->response, ELO10_PACKET_LEN); | ||
| 243 | rc = 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | out: | ||
| 247 | mutex_unlock(&elo->cmd_mutex); | ||
| 248 | return rc; | ||
| 249 | } | ||
| 250 | |||
| 251 | static int elo_setup_10(struct elo *elo) | ||
| 252 | { | ||
| 253 | static const char *elo_types[] = { "Accu", "Dura", "Intelli", "Carroll" }; | ||
| 254 | struct input_dev *dev = elo->dev; | ||
| 255 | unsigned char packet[ELO10_PACKET_LEN] = { ELO10_ID_CMD }; | ||
| 256 | |||
| 257 | if (elo_command_10(elo, packet)) | ||
| 258 | return -1; | ||
| 259 | |||
| 260 | dev->id.version = (packet[5] << 8) | packet[4]; | ||
| 261 | |||
| 262 | input_set_abs_params(dev, ABS_X, 96, 4000, 0, 0); | ||
| 263 | input_set_abs_params(dev, ABS_Y, 96, 4000, 0, 0); | ||
| 264 | if (packet[3] & ELO10_PRESSURE) | ||
| 265 | input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); | ||
| 266 | |||
| 267 | printk(KERN_INFO "elo: %sTouch touchscreen, fw: %02x.%02x, " | ||
| 268 | "features: %x02x, controller: 0x%02x\n", | ||
| 269 | elo_types[(packet[1] -'0') & 0x03], | ||
| 270 | packet[5], packet[4], packet[3], packet[7]); | ||
| 271 | |||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | |||
| 184 | /* | 275 | /* |
| 185 | * elo_disconnect() is the opposite of elo_connect() | 276 | * elo_disconnect() is the opposite of elo_connect() |
| 186 | */ | 277 | */ |
| 187 | 278 | ||
| 188 | static void elo_disconnect(struct serio *serio) | 279 | static void elo_disconnect(struct serio *serio) |
| 189 | { | 280 | { |
| 190 | struct elo* elo = serio_get_drvdata(serio); | 281 | struct elo *elo = serio_get_drvdata(serio); |
| 191 | 282 | ||
| 283 | input_get_device(elo->dev); | ||
| 192 | input_unregister_device(elo->dev); | 284 | input_unregister_device(elo->dev); |
| 193 | serio_close(serio); | 285 | serio_close(serio); |
| 194 | serio_set_drvdata(serio, NULL); | 286 | serio_set_drvdata(serio, NULL); |
| 287 | input_put_device(elo->dev); | ||
| 195 | kfree(elo); | 288 | kfree(elo); |
| 196 | } | 289 | } |
| 197 | 290 | ||
| @@ -211,12 +304,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) | |||
| 211 | input_dev = input_allocate_device(); | 304 | input_dev = input_allocate_device(); |
| 212 | if (!elo || !input_dev) { | 305 | if (!elo || !input_dev) { |
| 213 | err = -ENOMEM; | 306 | err = -ENOMEM; |
| 214 | goto fail; | 307 | goto fail1; |
| 215 | } | 308 | } |
| 216 | 309 | ||
| 217 | elo->serio = serio; | 310 | elo->serio = serio; |
| 218 | elo->id = serio->id.id; | 311 | elo->id = serio->id.id; |
| 219 | elo->dev = input_dev; | 312 | elo->dev = input_dev; |
| 313 | elo->expected_packet = ELO10_TOUCH_PACKET; | ||
| 314 | mutex_init(&elo->cmd_mutex); | ||
| 315 | init_completion(&elo->cmd_done); | ||
| 220 | snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); | 316 | snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); |
| 221 | 317 | ||
| 222 | input_dev->private = elo; | 318 | input_dev->private = elo; |
| @@ -231,12 +327,17 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) | |||
| 231 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | 327 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); |
| 232 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | 328 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); |
| 233 | 329 | ||
| 330 | serio_set_drvdata(serio, elo); | ||
| 331 | err = serio_open(serio, drv); | ||
| 332 | if (err) | ||
| 333 | goto fail2; | ||
| 334 | |||
| 234 | switch (elo->id) { | 335 | switch (elo->id) { |
| 235 | 336 | ||
| 236 | case 0: /* 10-byte protocol */ | 337 | case 0: /* 10-byte protocol */ |
| 237 | input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0); | 338 | if (elo_setup_10(elo)) |
| 238 | input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0); | 339 | goto fail3; |
| 239 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); | 340 | |
| 240 | break; | 341 | break; |
| 241 | 342 | ||
| 242 | case 1: /* 6-byte protocol */ | 343 | case 1: /* 6-byte protocol */ |
| @@ -253,17 +354,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) | |||
| 253 | break; | 354 | break; |
| 254 | } | 355 | } |
| 255 | 356 | ||
| 256 | serio_set_drvdata(serio, elo); | 357 | err = input_register_device(elo->dev); |
| 257 | |||
| 258 | err = serio_open(serio, drv); | ||
| 259 | if (err) | 358 | if (err) |
| 260 | goto fail; | 359 | goto fail3; |
| 261 | 360 | ||
| 262 | input_register_device(elo->dev); | ||
| 263 | return 0; | 361 | return 0; |
| 264 | 362 | ||
| 265 | fail: serio_set_drvdata(serio, NULL); | 363 | fail3: serio_close(serio); |
| 266 | input_free_device(input_dev); | 364 | fail2: serio_set_drvdata(serio, NULL); |
| 365 | fail1: input_free_device(input_dev); | ||
| 267 | kfree(elo); | 366 | kfree(elo); |
| 268 | return err; | 367 | return err; |
| 269 | } | 368 | } |
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c new file mode 100644 index 0000000000..f7370109d4 --- /dev/null +++ b/drivers/input/touchscreen/penmount.c | |||
| @@ -0,0 +1,185 @@ | |||
| 1 | /* | ||
| 2 | * Penmount serial touchscreen driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com> | ||
| 5 | * | ||
| 6 | * Based on ELO driver (drivers/input/touchscreen/elo.c) | ||
| 7 | * Copyright (c) 2004 Vojtech Pavlik | ||
| 8 | */ | ||
| 9 | |||
| 10 | /* | ||
| 11 | * This program is free software; you can redistribute it and/or modify it | ||
| 12 | * under the terms of the GNU General Public License version 2 as published | ||
| 13 | * by the Free Software Foundation. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/errno.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/input.h> | ||
| 21 | #include <linux/serio.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | |||
| 24 | #define DRIVER_DESC "Penmount serial touchscreen driver" | ||
| 25 | |||
| 26 | MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>"); | ||
| 27 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 28 | MODULE_LICENSE("GPL"); | ||
| 29 | |||
| 30 | /* | ||
| 31 | * Definitions & global arrays. | ||
| 32 | */ | ||
| 33 | |||
| 34 | #define PM_MAX_LENGTH 5 | ||
| 35 | |||
| 36 | /* | ||
| 37 | * Per-touchscreen data. | ||
| 38 | */ | ||
| 39 | |||
| 40 | struct pm { | ||
| 41 | struct input_dev *dev; | ||
| 42 | struct serio *serio; | ||
| 43 | int idx; | ||
| 44 | unsigned char data[PM_MAX_LENGTH]; | ||
| 45 | char phys[32]; | ||
| 46 | }; | ||
| 47 | |||
| 48 | static irqreturn_t pm_interrupt(struct serio *serio, | ||
| 49 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
| 50 | { | ||
| 51 | struct pm *pm = serio_get_drvdata(serio); | ||
| 52 | struct input_dev *dev = pm->dev; | ||
| 53 | |||
| 54 | pm->data[pm->idx] = data; | ||
| 55 | |||
| 56 | if (pm->data[0] & 0x80) { | ||
| 57 | if (PM_MAX_LENGTH == ++pm->idx) { | ||
| 58 | input_regs(dev, regs); | ||
| 59 | input_report_abs(dev, ABS_X, pm->data[2] * 128 + pm->data[1]); | ||
| 60 | input_report_abs(dev, ABS_Y, pm->data[4] * 128 + pm->data[3]); | ||
| 61 | input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40)); | ||
| 62 | input_sync(dev); | ||
| 63 | pm->idx = 0; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | return IRQ_HANDLED; | ||
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | * pm_disconnect() is the opposite of pm_connect() | ||
| 72 | */ | ||
| 73 | |||
| 74 | static void pm_disconnect(struct serio *serio) | ||
| 75 | { | ||
| 76 | struct pm *pm = serio_get_drvdata(serio); | ||
| 77 | |||
| 78 | input_get_device(pm->dev); | ||
| 79 | input_unregister_device(pm->dev); | ||
| 80 | serio_close(serio); | ||
| 81 | serio_set_drvdata(serio, NULL); | ||
| 82 | input_put_device(pm->dev); | ||
| 83 | kfree(pm); | ||
| 84 | } | ||
| 85 | |||
| 86 | /* | ||
| 87 | * pm_connect() is the routine that is called when someone adds a | ||
| 88 | * new serio device that supports Gunze protocol and registers it as | ||
| 89 | * an input device. | ||
| 90 | */ | ||
| 91 | |||
| 92 | static int pm_connect(struct serio *serio, struct serio_driver *drv) | ||
| 93 | { | ||
| 94 | struct pm *pm; | ||
| 95 | struct input_dev *input_dev; | ||
| 96 | int err; | ||
| 97 | |||
| 98 | pm = kzalloc(sizeof(struct pm), GFP_KERNEL); | ||
| 99 | input_dev = input_allocate_device(); | ||
| 100 | if (!pm || !input_dev) { | ||
| 101 | err = -ENOMEM; | ||
| 102 | goto fail1; | ||
| 103 | } | ||
| 104 | |||
| 105 | pm->serio = serio; | ||
| 106 | pm->dev = input_dev; | ||
| 107 | snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys); | ||
| 108 | |||
| 109 | input_dev->private = pm; | ||
| 110 | input_dev->name = "Penmount Serial TouchScreen"; | ||
| 111 | input_dev->phys = pm->phys; | ||
| 112 | input_dev->id.bustype = BUS_RS232; | ||
| 113 | input_dev->id.vendor = SERIO_PENMOUNT; | ||
| 114 | input_dev->id.product = 0; | ||
| 115 | input_dev->id.version = 0x0100; | ||
| 116 | input_dev->cdev.dev = &serio->dev; | ||
| 117 | |||
| 118 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
| 119 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | ||
| 120 | input_set_abs_params(pm->dev, ABS_X, 0, 0x3ff, 0, 0); | ||
| 121 | input_set_abs_params(pm->dev, ABS_Y, 0, 0x3ff, 0, 0); | ||
| 122 | |||
| 123 | serio_set_drvdata(serio, pm); | ||
| 124 | |||
| 125 | err = serio_open(serio, drv); | ||
| 126 | if (err) | ||
| 127 | goto fail2; | ||
| 128 | |||
| 129 | err = input_register_device(pm->dev); | ||
| 130 | if (err) | ||
| 131 | goto fail3; | ||
| 132 | |||
| 133 | return 0; | ||
| 134 | |||
| 135 | fail3: serio_close(serio); | ||
| 136 | fail2: serio_set_drvdata(serio, NULL); | ||
| 137 | fail1: input_free_device(input_dev); | ||
| 138 | kfree(pm); | ||
| 139 | return err; | ||
| 140 | } | ||
| 141 | |||
| 142 | /* | ||
| 143 | * The serio driver structure. | ||
| 144 | */ | ||
| 145 | |||
| 146 | static struct serio_device_id pm_serio_ids[] = { | ||
| 147 | { | ||
| 148 | .type = SERIO_RS232, | ||
| 149 | .proto = SERIO_PENMOUNT, | ||
| 150 | .id = SERIO_ANY, | ||
| 151 | .extra = SERIO_ANY, | ||
| 152 | }, | ||
| 153 | { 0 } | ||
| 154 | }; | ||
| 155 | |||
| 156 | MODULE_DEVICE_TABLE(serio, pm_serio_ids); | ||
| 157 | |||
| 158 | static struct serio_driver pm_drv = { | ||
| 159 | .driver = { | ||
| 160 | .name = "penmountlpc", | ||
| 161 | }, | ||
| 162 | .description = DRIVER_DESC, | ||
| 163 | .id_table = pm_serio_ids, | ||
| 164 | .interrupt = pm_interrupt, | ||
| 165 | .connect = pm_connect, | ||
| 166 | .disconnect = pm_disconnect, | ||
| 167 | }; | ||
| 168 | |||
| 169 | /* | ||
| 170 | * The functions for inserting/removing us as a module. | ||
| 171 | */ | ||
| 172 | |||
| 173 | static int __init pm_init(void) | ||
| 174 | { | ||
| 175 | serio_register_driver(&pm_drv); | ||
| 176 | return 0; | ||
| 177 | } | ||
| 178 | |||
| 179 | static void __exit pm_exit(void) | ||
| 180 | { | ||
| 181 | serio_unregister_driver(&pm_drv); | ||
| 182 | } | ||
| 183 | |||
| 184 | module_init(pm_init); | ||
| 185 | module_exit(pm_exit); | ||
diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c new file mode 100644 index 0000000000..1c89fa5386 --- /dev/null +++ b/drivers/input/touchscreen/touchright.c | |||
| @@ -0,0 +1,196 @@ | |||
| 1 | /* | ||
| 2 | * Touchright serial touchscreen driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com> | ||
| 5 | * | ||
| 6 | * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c) | ||
| 7 | * Copyright (c) 2004 Vojtech Pavlik | ||
| 8 | * and Dan Streetman <ddstreet@ieee.org> | ||
| 9 | */ | ||
| 10 | |||
| 11 | /* | ||
| 12 | * This program is free software; you can redistribute it and/or modify it | ||
| 13 | * under the terms of the GNU General Public License version 2 as published | ||
| 14 | * by the Free Software Foundation. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/errno.h> | ||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <linux/input.h> | ||
| 22 | #include <linux/serio.h> | ||
| 23 | #include <linux/init.h> | ||
| 24 | |||
| 25 | #define DRIVER_DESC "Touchright serial touchscreen driver" | ||
| 26 | |||
| 27 | MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>"); | ||
| 28 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 29 | MODULE_LICENSE("GPL"); | ||
| 30 | |||
| 31 | /* | ||
| 32 | * Definitions & global arrays. | ||
| 33 | */ | ||
| 34 | |||
| 35 | #define TR_FORMAT_TOUCH_BIT 0x01 | ||
| 36 | #define TR_FORMAT_STATUS_BYTE 0x40 | ||
| 37 | #define TR_FORMAT_STATUS_MASK ~TR_FORMAT_TOUCH_BIT | ||
| 38 | |||
| 39 | #define TR_LENGTH 5 | ||
| 40 | |||
| 41 | #define TR_MIN_XC 0 | ||
| 42 | #define TR_MAX_XC 0x1ff | ||
| 43 | #define TR_MIN_YC 0 | ||
| 44 | #define TR_MAX_YC 0x1ff | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Per-touchscreen data. | ||
| 48 | */ | ||
| 49 | |||
| 50 | struct tr { | ||
| 51 | struct input_dev *dev; | ||
| 52 | struct serio *serio; | ||
| 53 | int idx; | ||
| 54 | unsigned char data[TR_LENGTH]; | ||
| 55 | char phys[32]; | ||
| 56 | }; | ||
| 57 | |||
| 58 | static irqreturn_t tr_interrupt(struct serio *serio, | ||
| 59 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
| 60 | { | ||
| 61 | struct tr *tr = serio_get_drvdata(serio); | ||
| 62 | struct input_dev *dev = tr->dev; | ||
| 63 | |||
| 64 | tr->data[tr->idx] = data; | ||
| 65 | |||
| 66 | if ((tr->data[0] & TR_FORMAT_STATUS_MASK) == TR_FORMAT_STATUS_BYTE) { | ||
| 67 | if (++tr->idx == TR_LENGTH) { | ||
| 68 | input_regs(dev, regs); | ||
| 69 | input_report_abs(dev, ABS_X, | ||
| 70 | (tr->data[1] << 5) | (tr->data[2] >> 1)); | ||
| 71 | input_report_abs(dev, ABS_Y, | ||
| 72 | (tr->data[3] << 5) | (tr->data[4] >> 1)); | ||
| 73 | input_report_key(dev, BTN_TOUCH, | ||
| 74 | tr->data[0] & TR_FORMAT_TOUCH_BIT); | ||
| 75 | input_sync(dev); | ||
| 76 | tr->idx = 0; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | return IRQ_HANDLED; | ||
| 81 | } | ||
| 82 | |||
| 83 | /* | ||
| 84 | * tr_disconnect() is the opposite of tr_connect() | ||
| 85 | */ | ||
| 86 | |||
| 87 | static void tr_disconnect(struct serio *serio) | ||
| 88 | { | ||
| 89 | struct tr *tr = serio_get_drvdata(serio); | ||
| 90 | |||
| 91 | input_get_device(tr->dev); | ||
| 92 | input_unregister_device(tr->dev); | ||
| 93 | serio_close(serio); | ||
| 94 | serio_set_drvdata(serio, NULL); | ||
| 95 | input_put_device(tr->dev); | ||
| 96 | kfree(tr); | ||
| 97 | } | ||
| 98 | |||
| 99 | /* | ||
| 100 | * tr_connect() is the routine that is called when someone adds a | ||
| 101 | * new serio device that supports the Touchright protocol and registers it as | ||
| 102 | * an input device. | ||
| 103 | */ | ||
| 104 | |||
| 105 | static int tr_connect(struct serio *serio, struct serio_driver *drv) | ||
| 106 | { | ||
| 107 | struct tr *tr; | ||
| 108 | struct input_dev *input_dev; | ||
| 109 | int err; | ||
| 110 | |||
| 111 | tr = kzalloc(sizeof(struct tr), GFP_KERNEL); | ||
| 112 | input_dev = input_allocate_device(); | ||
| 113 | if (!tr || !input_dev) { | ||
| 114 | err = -ENOMEM; | ||
| 115 | goto fail1; | ||
| 116 | } | ||
| 117 | |||
| 118 | tr->serio = serio; | ||
| 119 | tr->dev = input_dev; | ||
| 120 | snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys); | ||
| 121 | |||
| 122 | input_dev->private = tr; | ||
| 123 | input_dev->name = "Touchright Serial TouchScreen"; | ||
| 124 | input_dev->phys = tr->phys; | ||
| 125 | input_dev->id.bustype = BUS_RS232; | ||
| 126 | input_dev->id.vendor = SERIO_TOUCHRIGHT; | ||
| 127 | input_dev->id.product = 0; | ||
| 128 | input_dev->id.version = 0x0100; | ||
| 129 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
| 130 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | ||
| 131 | input_set_abs_params(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0); | ||
| 132 | input_set_abs_params(tr->dev, ABS_Y, TR_MIN_YC, TR_MAX_YC, 0, 0); | ||
| 133 | |||
| 134 | serio_set_drvdata(serio, tr); | ||
| 135 | |||
| 136 | err = serio_open(serio, drv); | ||
| 137 | if (err) | ||
| 138 | goto fail2; | ||
| 139 | |||
| 140 | err = input_register_device(tr->dev); | ||
| 141 | if (err) | ||
| 142 | goto fail3; | ||
| 143 | |||
| 144 | return 0; | ||
| 145 | |||
| 146 | fail3: serio_close(serio); | ||
| 147 | fail2: serio_set_drvdata(serio, NULL); | ||
| 148 | fail1: input_free_device(input_dev); | ||
| 149 | kfree(tr); | ||
| 150 | return err; | ||
| 151 | } | ||
| 152 | |||
| 153 | /* | ||
| 154 | * The serio driver structure. | ||
| 155 | */ | ||
| 156 | |||
| 157 | static struct serio_device_id tr_serio_ids[] = { | ||
| 158 | { | ||
| 159 | .type = SERIO_RS232, | ||
| 160 | .proto = SERIO_TOUCHRIGHT, | ||
| 161 | .id = SERIO_ANY, | ||
| 162 | .extra = SERIO_ANY, | ||
| 163 | }, | ||
| 164 | { 0 } | ||
| 165 | }; | ||
| 166 | |||
| 167 | MODULE_DEVICE_TABLE(serio, tr_serio_ids); | ||
| 168 | |||
| 169 | static struct serio_driver tr_drv = { | ||
| 170 | .driver = { | ||
| 171 | .name = "touchright", | ||
| 172 | }, | ||
| 173 | .description = DRIVER_DESC, | ||
| 174 | .id_table = tr_serio_ids, | ||
| 175 | .interrupt = tr_interrupt, | ||
| 176 | .connect = tr_connect, | ||
| 177 | .disconnect = tr_disconnect, | ||
| 178 | }; | ||
| 179 | |||
| 180 | /* | ||
| 181 | * The functions for inserting/removing us as a module. | ||
| 182 | */ | ||
| 183 | |||
| 184 | static int __init tr_init(void) | ||
| 185 | { | ||
| 186 | serio_register_driver(&tr_drv); | ||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | static void __exit tr_exit(void) | ||
| 191 | { | ||
| 192 | serio_unregister_driver(&tr_drv); | ||
| 193 | } | ||
| 194 | |||
| 195 | module_init(tr_init); | ||
| 196 | module_exit(tr_exit); | ||
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c new file mode 100644 index 0000000000..a7b4c75595 --- /dev/null +++ b/drivers/input/touchscreen/touchwin.c | |||
| @@ -0,0 +1,203 @@ | |||
| 1 | /* | ||
| 2 | * Touchwindow serial touchscreen driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com> | ||
| 5 | * | ||
| 6 | * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c) | ||
| 7 | * Copyright (c) 2004 Vojtech Pavlik | ||
| 8 | * and Dan Streetman <ddstreet@ieee.org> | ||
| 9 | */ | ||
| 10 | |||
| 11 | /* | ||
| 12 | * This program is free software; you can redistribute it and/or modify it | ||
| 13 | * under the terms of the GNU General Public License version 2 as published | ||
| 14 | * by the Free Software Foundation. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* | ||
| 18 | * 2005/02/19 Rick Koch: | ||
| 19 | * The Touchwindow I used is made by Edmark Corp. and | ||
| 20 | * constantly outputs a stream of 0's unless it is touched. | ||
| 21 | * It then outputs 3 bytes: X, Y, and a copy of Y. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/errno.h> | ||
| 25 | #include <linux/kernel.h> | ||
| 26 | #include <linux/module.h> | ||
| 27 | #include <linux/slab.h> | ||
| 28 | #include <linux/input.h> | ||
| 29 | #include <linux/serio.h> | ||
| 30 | #include <linux/init.h> | ||
| 31 | |||
| 32 | #define DRIVER_DESC "Touchwindow serial touchscreen driver" | ||
| 33 | |||
| 34 | MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>"); | ||
| 35 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 36 | MODULE_LICENSE("GPL"); | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Definitions & global arrays. | ||
| 40 | */ | ||
| 41 | |||
| 42 | #define TW_LENGTH 3 | ||
| 43 | |||
| 44 | #define TW_MIN_XC 0 | ||
| 45 | #define TW_MAX_XC 0xff | ||
| 46 | #define TW_MIN_YC 0 | ||
| 47 | #define TW_MAX_YC 0xff | ||
| 48 | |||
| 49 | /* | ||
| 50 | * Per-touchscreen data. | ||
| 51 | */ | ||
| 52 | |||
| 53 | struct tw { | ||
| 54 | struct input_dev *dev; | ||
| 55 | struct serio *serio; | ||
| 56 | int idx; | ||
| 57 | int touched; | ||
| 58 | unsigned char data[TW_LENGTH]; | ||
| 59 | char phys[32]; | ||
| 60 | }; | ||
| 61 | |||
| 62 | static irqreturn_t tw_interrupt(struct serio *serio, | ||
| 63 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
| 64 | { | ||
| 65 | struct tw *tw = serio_get_drvdata(serio); | ||
| 66 | struct input_dev *dev = tw->dev; | ||
| 67 | |||
| 68 | if (data) { /* touch */ | ||
| 69 | tw->touched = 1; | ||
| 70 | tw->data[tw->idx++] = data; | ||
| 71 | /* verify length and that the two Y's are the same */ | ||
| 72 | if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) { | ||
| 73 | input_regs(dev, regs); | ||
| 74 | input_report_abs(dev, ABS_X, tw->data[0]); | ||
| 75 | input_report_abs(dev, ABS_Y, tw->data[1]); | ||
| 76 | input_report_key(dev, BTN_TOUCH, 1); | ||
| 77 | input_sync(dev); | ||
| 78 | tw->idx = 0; | ||
| 79 | } | ||
| 80 | } else if (tw->touched) { /* untouch */ | ||
| 81 | input_report_key(dev, BTN_TOUCH, 0); | ||
| 82 | input_sync(dev); | ||
| 83 | tw->idx = 0; | ||
| 84 | tw->touched = 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | return IRQ_HANDLED; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* | ||
| 91 | * tw_disconnect() is the opposite of tw_connect() | ||
| 92 | */ | ||
| 93 | |||
| 94 | static void tw_disconnect(struct serio *serio) | ||
| 95 | { | ||
| 96 | struct tw *tw = serio_get_drvdata(serio); | ||
| 97 | |||
| 98 | input_get_device(tw->dev); | ||
| 99 | input_unregister_device(tw->dev); | ||
| 100 | serio_close(serio); | ||
| 101 | serio_set_drvdata(serio, NULL); | ||
| 102 | input_put_device(tw->dev); | ||
| 103 | kfree(tw); | ||
| 104 | } | ||
| 105 | |||
| 106 | /* | ||
| 107 | * tw_connect() is the routine that is called when someone adds a | ||
| 108 | * new serio device that supports the Touchwin protocol and registers it as | ||
| 109 | * an input device. | ||
| 110 | */ | ||
| 111 | |||
| 112 | static int tw_connect(struct serio *serio, struct serio_driver *drv) | ||
| 113 | { | ||
| 114 | struct tw *tw; | ||
| 115 | struct input_dev *input_dev; | ||
| 116 | int err; | ||
| 117 | |||
| 118 | tw = kzalloc(sizeof(struct tw), GFP_KERNEL); | ||
| 119 | input_dev = input_allocate_device(); | ||
| 120 | if (!tw || !input_dev) { | ||
| 121 | err = -ENOMEM; | ||
| 122 | goto fail1; | ||
| 123 | } | ||
| 124 | |||
| 125 | tw->serio = serio; | ||
| 126 | tw->dev = input_dev; | ||
| 127 | snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys); | ||
| 128 | |||
| 129 | input_dev->private = tw; | ||
| 130 | input_dev->name = "Touchwindow Serial TouchScreen"; | ||
| 131 | input_dev->phys = tw->phys; | ||
| 132 | input_dev->id.bustype = BUS_RS232; | ||
| 133 | input_dev->id.vendor = SERIO_TOUCHWIN; | ||
| 134 | input_dev->id.product = 0; | ||
| 135 | input_dev->id.version = 0x0100; | ||
| 136 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
| 137 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | ||
| 138 | input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0); | ||
| 139 | input_set_abs_params(tw->dev, ABS_Y, TW_MIN_YC, TW_MAX_YC, 0, 0); | ||
| 140 | |||
| 141 | serio_set_drvdata(serio, tw); | ||
| 142 | |||
| 143 | err = serio_open(serio, drv); | ||
| 144 | if (err) | ||
| 145 | goto fail2; | ||
| 146 | |||
| 147 | err = input_register_device(tw->dev); | ||
| 148 | if (err) | ||
| 149 | goto fail3; | ||
| 150 | |||
| 151 | return 0; | ||
| 152 | |||
| 153 | fail3: serio_close(serio); | ||
| 154 | fail2: serio_set_drvdata(serio, NULL); | ||
| 155 | fail1: input_free_device(input_dev); | ||
| 156 | kfree(tw); | ||
| 157 | return err; | ||
| 158 | } | ||
| 159 | |||
| 160 | /* | ||
| 161 | * The serio driver structure. | ||
| 162 | */ | ||
| 163 | |||
| 164 | static struct serio_device_id tw_serio_ids[] = { | ||
| 165 | { | ||
| 166 | .type = SERIO_RS232, | ||
| 167 | .proto = SERIO_TOUCHWIN, | ||
| 168 | .id = SERIO_ANY, | ||
| 169 | .extra = SERIO_ANY, | ||
| 170 | }, | ||
| 171 | { 0 } | ||
| 172 | }; | ||
| 173 | |||
| 174 | MODULE_DEVICE_TABLE(serio, tw_serio_ids); | ||
| 175 | |||
| 176 | static struct serio_driver tw_drv = { | ||
| 177 | .driver = { | ||
| 178 | .name = "touchwin", | ||
| 179 | }, | ||
| 180 | .description = DRIVER_DESC, | ||
| 181 | .id_table = tw_serio_ids, | ||
| 182 | .interrupt = tw_interrupt, | ||
| 183 | .connect = tw_connect, | ||
| 184 | .disconnect = tw_disconnect, | ||
| 185 | }; | ||
| 186 | |||
| 187 | /* | ||
| 188 | * The functions for inserting/removing us as a module. | ||
| 189 | */ | ||
| 190 | |||
| 191 | static int __init tw_init(void) | ||
| 192 | { | ||
| 193 | serio_register_driver(&tw_drv); | ||
| 194 | return 0; | ||
| 195 | } | ||
| 196 | |||
| 197 | static void __exit tw_exit(void) | ||
| 198 | { | ||
| 199 | serio_unregister_driver(&tw_drv); | ||
| 200 | } | ||
| 201 | |||
| 202 | module_init(tw_init); | ||
| 203 | module_exit(tw_exit); | ||
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 00e3929c62..a730c46122 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c | |||
| @@ -135,8 +135,6 @@ struct tsdev_list { | |||
| 135 | #define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) | 135 | #define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) |
| 136 | #define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) | 136 | #define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) |
| 137 | 137 | ||
| 138 | static struct input_handler tsdev_handler; | ||
| 139 | |||
| 140 | static struct tsdev *tsdev_table[TSDEV_MINORS/2]; | 138 | static struct tsdev *tsdev_table[TSDEV_MINORS/2]; |
| 141 | 139 | ||
| 142 | static int tsdev_fasync(int fd, struct file *file, int on) | 140 | static int tsdev_fasync(int fd, struct file *file, int on) |
| @@ -263,7 +261,7 @@ static int tsdev_ioctl(struct inode *inode, struct file *file, | |||
| 263 | return retval; | 261 | return retval; |
| 264 | } | 262 | } |
| 265 | 263 | ||
| 266 | static struct file_operations tsdev_fops = { | 264 | static const struct file_operations tsdev_fops = { |
| 267 | .owner = THIS_MODULE, | 265 | .owner = THIS_MODULE, |
| 268 | .open = tsdev_open, | 266 | .open = tsdev_open, |
| 269 | .release = tsdev_release, | 267 | .release = tsdev_release, |
| @@ -370,7 +368,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, | |||
| 370 | 368 | ||
| 371 | static struct input_handle *tsdev_connect(struct input_handler *handler, | 369 | static struct input_handle *tsdev_connect(struct input_handler *handler, |
| 372 | struct input_dev *dev, | 370 | struct input_dev *dev, |
| 373 | struct input_device_id *id) | 371 | const struct input_device_id *id) |
| 374 | { | 372 | { |
| 375 | struct tsdev *tsdev; | 373 | struct tsdev *tsdev; |
| 376 | struct class_device *cdev; | 374 | struct class_device *cdev; |
| @@ -443,7 +441,7 @@ static void tsdev_disconnect(struct input_handle *handle) | |||
| 443 | tsdev_free(tsdev); | 441 | tsdev_free(tsdev); |
| 444 | } | 442 | } |
| 445 | 443 | ||
| 446 | static struct input_device_id tsdev_ids[] = { | 444 | static const struct input_device_id tsdev_ids[] = { |
| 447 | { | 445 | { |
| 448 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | 446 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, |
| 449 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | 447 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
| @@ -481,9 +479,7 @@ static struct input_handler tsdev_handler = { | |||
| 481 | 479 | ||
| 482 | static int __init tsdev_init(void) | 480 | static int __init tsdev_init(void) |
| 483 | { | 481 | { |
| 484 | input_register_handler(&tsdev_handler); | 482 | return input_register_handler(&tsdev_handler); |
| 485 | printk(KERN_INFO "ts: Compaq touchscreen protocol output\n"); | ||
| 486 | return 0; | ||
| 487 | } | 483 | } |
| 488 | 484 | ||
| 489 | static void __exit tsdev_exit(void) | 485 | static void __exit tsdev_exit(void) |
