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

Input: uinput - use completions instead of events and manual wakeups in force feedback code.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

+47 -43
+45 -40
drivers/input/misc/uinput.c
··· 53 53 return 0; 54 54 } 55 55 56 - static int uinput_request_alloc_id(struct input_dev *dev, struct uinput_request *request) 56 + static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request) 57 57 { 58 58 /* Atomically allocate an ID for the given request. Returns 0 on success. */ 59 - struct uinput_device *udev = dev->private; 60 59 int id; 61 60 int err = -1; 62 61 63 - down(&udev->requests_sem); 62 + spin_lock(&udev->requests_lock); 64 63 65 64 for (id = 0; id < UINPUT_NUM_REQUESTS; id++) 66 65 if (!udev->requests[id]) { 67 - udev->requests[id] = request; 68 66 request->id = id; 67 + udev->requests[id] = request; 69 68 err = 0; 70 69 break; 71 70 } 72 71 73 - up(&udev->requests_sem); 72 + spin_unlock(&udev->requests_lock); 74 73 return err; 75 74 } 76 75 ··· 78 79 /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ 79 80 if (id >= UINPUT_NUM_REQUESTS || id < 0) 80 81 return NULL; 81 - if (udev->requests[id]->completed) 82 - return NULL; 83 82 return udev->requests[id]; 84 83 } 85 84 86 - static void uinput_request_init(struct input_dev *dev, struct uinput_request *request, int code) 85 + static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request) 87 86 { 88 - struct uinput_device *udev = dev->private; 89 - 90 - memset(request, 0, sizeof(struct uinput_request)); 91 - request->code = code; 92 - init_waitqueue_head(&request->waitq); 93 - 94 - /* Allocate an ID. If none are available right away, wait. */ 95 - request->retval = wait_event_interruptible(udev->requests_waitq, 96 - !uinput_request_alloc_id(dev, request)); 87 + /* Allocate slot. If none are available right away, wait. */ 88 + return wait_event_interruptible(udev->requests_waitq, 89 + !uinput_request_alloc_id(udev, request)); 97 90 } 98 91 99 - static void uinput_request_submit(struct input_dev *dev, struct uinput_request *request) 92 + static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request) 100 93 { 101 - struct uinput_device *udev = dev->private; 94 + complete(&request->done); 95 + 96 + /* Mark slot as available */ 97 + udev->requests[request->id] = NULL; 98 + wake_up_interruptible(&udev->requests_waitq); 99 + } 100 + 101 + static int uinput_request_submit(struct input_dev *dev, struct uinput_request *request) 102 + { 102 103 int retval; 103 104 104 105 /* Tell our userspace app about this new request by queueing an input event */ 105 106 uinput_dev_event(dev, EV_UINPUT, request->code, request->id); 106 107 107 108 /* Wait for the request to complete */ 108 - retval = wait_event_interruptible(request->waitq, request->completed); 109 - if (retval) 110 - request->retval = retval; 109 + retval = wait_for_completion_interruptible(&request->done); 110 + if (!retval) 111 + retval = request->retval; 111 112 112 - /* Release this request's ID, let others know it's available */ 113 - udev->requests[request->id] = NULL; 114 - wake_up_interruptible(&udev->requests_waitq); 113 + return retval; 115 114 } 116 115 117 116 static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) 118 117 { 119 118 struct uinput_request request; 119 + int retval; 120 120 121 121 if (!test_bit(EV_FF, dev->evbit)) 122 122 return -ENOSYS; 123 123 124 - uinput_request_init(dev, &request, UI_FF_UPLOAD); 125 - if (request.retval) 126 - return request.retval; 124 + request.id = -1; 125 + init_completion(&request.done); 126 + request.code = UI_FF_UPLOAD; 127 127 request.u.effect = effect; 128 - uinput_request_submit(dev, &request); 129 - return request.retval; 128 + 129 + retval = uinput_request_reserve_slot(dev->private, &request); 130 + if (!retval) 131 + retval = uinput_request_submit(dev, &request); 132 + 133 + return retval; 130 134 } 131 135 132 136 static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) 133 137 { 134 138 struct uinput_request request; 139 + int retval; 135 140 136 141 if (!test_bit(EV_FF, dev->evbit)) 137 142 return -ENOSYS; 138 143 139 - uinput_request_init(dev, &request, UI_FF_ERASE); 140 - if (request.retval) 141 - return request.retval; 144 + request.id = -1; 145 + init_completion(&request.done); 146 + request.code = UI_FF_ERASE; 142 147 request.u.effect_id = effect_id; 143 - uinput_request_submit(dev, &request); 144 - return request.retval; 148 + 149 + retval = uinput_request_reserve_slot(dev->private, &request); 150 + if (!retval) 151 + retval = uinput_request_submit(dev, &request); 152 + 153 + return retval; 145 154 } 146 155 147 156 static int uinput_create_device(struct uinput_device *udev) ··· 196 189 if (!newdev) 197 190 goto error; 198 191 memset(newdev, 0, sizeof(struct uinput_device)); 199 - init_MUTEX(&newdev->requests_sem); 192 + spin_lock_init(&newdev->requests_lock); 200 193 init_waitqueue_head(&newdev->requests_waitq); 201 194 202 195 newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL); ··· 558 551 } 559 552 req->retval = ff_up.retval; 560 553 memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect)); 561 - req->completed = 1; 562 - wake_up_interruptible(&req->waitq); 554 + uinput_request_done(udev, req); 563 555 break; 564 556 565 557 case UI_END_FF_ERASE: ··· 572 566 break; 573 567 } 574 568 req->retval = ff_erase.retval; 575 - req->completed = 1; 576 - wake_up_interruptible(&req->waitq); 569 + uinput_request_done(udev, req); 577 570 break; 578 571 579 572 default:
+2 -3
include/linux/uinput.h
··· 42 42 int code; /* UI_FF_UPLOAD, UI_FF_ERASE */ 43 43 44 44 int retval; 45 - wait_queue_head_t waitq; 46 - int completed; 45 + struct completion done; 47 46 48 47 union { 49 48 int effect_id; ··· 61 62 62 63 struct uinput_request *requests[UINPUT_NUM_REQUESTS]; 63 64 wait_queue_head_t requests_waitq; 64 - struct semaphore requests_sem; 65 + spinlock_t requests_lock; 65 66 }; 66 67 #endif /* __KERNEL__ */ 67 68