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