Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: uinput - switch to the new FF interface

The userspace interface of the force feedback part is changed and
documentation in uinput.h is updated accordingly. MODULE_VERSION
is also incremented to reflect the revision.

Signed-off-by: Anssi Hannula <anssi.hannula@gmail.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

Anssi Hannula and committed by
Dmitry Torokhov
ff462551 dc76c912

+74 -28
+51 -16
drivers/input/misc/uinput.c
··· 20 20 * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> 21 21 * 22 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 26 * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) 24 27 * - added force feedback support 25 28 * - added UI_SET_PHYS ··· 110 107 return request->retval; 111 108 } 112 109 113 - static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) 110 + static void uinput_dev_set_gain(struct input_dev *dev, u16 gain) 111 + { 112 + uinput_dev_event(dev, EV_FF, FF_GAIN, gain); 113 + } 114 + 115 + static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude) 116 + { 117 + uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude); 118 + } 119 + 120 + static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value) 121 + { 122 + return uinput_dev_event(dev, EV_FF, effect_id, value); 123 + } 124 + 125 + static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) 114 126 { 115 127 struct uinput_request request; 116 128 int retval; 117 129 118 - if (!test_bit(EV_FF, dev->evbit)) 119 - return -ENOSYS; 120 - 121 130 request.id = -1; 122 131 init_completion(&request.done); 123 132 request.code = UI_FF_UPLOAD; 124 - request.u.effect = effect; 133 + request.u.upload.effect = effect; 134 + request.u.upload.old = old; 125 135 126 136 retval = uinput_request_reserve_slot(dev->private, &request); 127 137 if (!retval) ··· 184 168 185 169 static int uinput_create_device(struct uinput_device *udev) 186 170 { 171 + struct input_dev *dev = udev->dev; 187 172 int error; 188 173 189 174 if (udev->state != UIST_SETUP_COMPLETE) { ··· 192 175 return -EINVAL; 193 176 } 194 177 195 - error = input_register_device(udev->dev); 196 - if (error) { 197 - uinput_destroy_device(udev); 198 - return error; 178 + if (udev->ff_effects_max) { 179 + error = input_ff_create(dev, udev->ff_effects_max); 180 + if (error) 181 + goto fail1; 182 + 183 + dev->ff->upload = uinput_dev_upload_effect; 184 + dev->ff->erase = uinput_dev_erase_effect; 185 + dev->ff->playback = uinput_dev_playback; 186 + dev->ff->set_gain = uinput_dev_set_gain; 187 + dev->ff->set_autocenter = uinput_dev_set_autocenter; 199 188 } 189 + 190 + error = input_register_device(udev->dev); 191 + if (error) 192 + goto fail2; 200 193 201 194 udev->state = UIST_CREATED; 202 195 203 196 return 0; 197 + 198 + fail2: input_ff_destroy(dev); 199 + fail1: uinput_destroy_device(udev); 200 + return error; 204 201 } 205 202 206 203 static int uinput_open(struct inode *inode, struct file *file) ··· 274 243 return -ENOMEM; 275 244 276 245 udev->dev->event = uinput_dev_event; 277 - udev->dev->upload_effect = uinput_dev_upload_effect; 278 - udev->dev->erase_effect = uinput_dev_erase_effect; 279 246 udev->dev->private = udev; 280 247 281 248 return 0; ··· 307 278 goto exit; 308 279 } 309 280 281 + udev->ff_effects_max = user_dev->ff_effects_max; 282 + 310 283 size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; 311 284 if (!size) { 312 285 retval = -EINVAL; ··· 327 296 dev->id.vendor = user_dev->id.vendor; 328 297 dev->id.product = user_dev->id.product; 329 298 dev->id.version = user_dev->id.version; 330 - dev->ff_effects_max = user_dev->ff_effects_max; 331 299 332 300 size = sizeof(int) * (ABS_MAX + 1); 333 301 memcpy(dev->absmax, user_dev->absmax, size); ··· 555 525 break; 556 526 } 557 527 req = uinput_request_find(udev, ff_up.request_id); 558 - if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { 528 + if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { 559 529 retval = -EINVAL; 560 530 break; 561 531 } 562 532 ff_up.retval = 0; 563 - memcpy(&ff_up.effect, req->u.effect, sizeof(struct ff_effect)); 533 + memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect)); 534 + if (req->u.upload.old) 535 + memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect)); 536 + else 537 + memset(&ff_up.old, 0, sizeof(struct ff_effect)); 538 + 564 539 if (copy_to_user(p, &ff_up, sizeof(ff_up))) { 565 540 retval = -EFAULT; 566 541 break; ··· 596 561 break; 597 562 } 598 563 req = uinput_request_find(udev, ff_up.request_id); 599 - if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { 564 + if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { 600 565 retval = -EINVAL; 601 566 break; 602 567 } 603 568 req->retval = ff_up.retval; 604 - memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect)); 605 569 uinput_request_done(udev, req); 606 570 break; 607 571 ··· 656 622 MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); 657 623 MODULE_DESCRIPTION("User level driver support for input subsystem"); 658 624 MODULE_LICENSE("GPL"); 625 + MODULE_VERSION("0.3"); 659 626 660 627 module_init(uinput_init); 661 628 module_exit(uinput_exit);
+23 -12
include/linux/uinput.h
··· 22 22 * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> 23 23 * 24 24 * Changes/Revisions: 25 + * 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>) 26 + * - update ff support for the changes in kernel interface 27 + * - add UINPUT_VERSION 25 28 * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) 26 29 * - added force feedback support 27 30 * - added UI_SET_PHYS 28 31 * 0.1 20/06/2002 29 32 * - first public version 30 33 */ 34 + 35 + #define UINPUT_VERSION 3 36 + 31 37 #ifdef __KERNEL__ 32 38 #define UINPUT_MINOR 223 33 39 #define UINPUT_NAME "uinput" ··· 51 45 52 46 union { 53 47 int effect_id; 54 - struct ff_effect* effect; 48 + struct { 49 + struct ff_effect *effect; 50 + struct ff_effect *old; 51 + } upload; 55 52 } u; 56 53 }; 57 54 ··· 67 58 unsigned char head; 68 59 unsigned char tail; 69 60 struct input_event buff[UINPUT_BUFFER_SIZE]; 61 + int ff_effects_max; 70 62 71 63 struct uinput_request *requests[UINPUT_NUM_REQUESTS]; 72 64 wait_queue_head_t requests_waitq; ··· 79 69 int request_id; 80 70 int retval; 81 71 struct ff_effect effect; 72 + struct ff_effect old; 82 73 }; 83 74 84 75 struct uinput_ff_erase { ··· 109 98 #define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase) 110 99 #define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase) 111 100 112 - /* To write a force-feedback-capable driver, the upload_effect 101 + /* 102 + * To write a force-feedback-capable driver, the upload_effect 113 103 * and erase_effect callbacks in input_dev must be implemented. 114 104 * The uinput driver will generate a fake input event when one of 115 105 * these callbacks are invoked. The userspace code then uses 116 106 * ioctls to retrieve additional parameters and send the return code. 117 107 * The callback blocks until this return code is sent. 118 108 * 119 - * The described callback mechanism is only used if EV_FF is set. 120 - * Otherwise, default implementations of upload_effect and erase_effect 121 - * are used. 109 + * The described callback mechanism is only used if ff_effects_max 110 + * is set. 122 111 * 123 112 * To implement upload_effect(): 124 - * 1. Wait for an event with type==EV_UINPUT and code==UI_FF_UPLOAD. 113 + * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_UPLOAD. 125 114 * A request ID will be given in 'value'. 126 115 * 2. Allocate a uinput_ff_upload struct, fill in request_id with 127 116 * the 'value' from the EV_UINPUT event. 128 117 * 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the 129 118 * uinput_ff_upload struct. It will be filled in with the 130 - * ff_effect passed to upload_effect(). 131 - * 4. Perform the effect upload, and place the modified ff_effect 132 - * and a return code back into the uinput_ff_upload struct. 119 + * ff_effects passed to upload_effect(). 120 + * 4. Perform the effect upload, and place a return code back into 121 + the uinput_ff_upload struct. 133 122 * 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the 134 123 * uinput_ff_upload_effect struct. This will complete execution 135 124 * of our upload_effect() handler. 136 125 * 137 126 * To implement erase_effect(): 138 - * 1. Wait for an event with type==EV_UINPUT and code==UI_FF_ERASE. 127 + * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_ERASE. 139 128 * A request ID will be given in 'value'. 140 129 * 2. Allocate a uinput_ff_erase struct, fill in request_id with 141 130 * the 'value' from the EV_UINPUT event. ··· 144 133 * effect ID passed to erase_effect(). 145 134 * 4. Perform the effect erasure, and place a return code back 146 135 * into the uinput_ff_erase struct. 147 - * and a return code back into the uinput_ff_erase struct. 148 136 * 5. Issue a UI_END_FF_ERASE ioctl, also giving it the 149 137 * uinput_ff_erase_effect struct. This will complete execution 150 138 * of our erase_effect() handler. 151 139 */ 152 140 153 - /* This is the new event type, used only by uinput. 141 + /* 142 + * This is the new event type, used only by uinput. 154 143 * 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value' 155 144 * is the unique request ID. This number was picked 156 145 * arbitrarily, above EV_MAX (since the input system