aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/input/misc/uinput.c81
-rw-r--r--include/linux/uinput.h5
2 files changed, 45 insertions, 41 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
56static int uinput_request_alloc_id(struct input_dev *dev, struct uinput_request *request) 56static 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
87static void uinput_request_init(struct input_dev *dev, struct uinput_request *request, int code) 84static 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)); 91static 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
100static void uinput_request_submit(struct input_dev *dev, struct uinput_request *request) 100static 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
118static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) 115static 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
133static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) 135static 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
148static int uinput_create_device(struct uinput_device *udev) 155static 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:
diff --git a/include/linux/uinput.h b/include/linux/uinput.h
index 4c2c82336d10..84876077027f 100644
--- a/include/linux/uinput.h
+++ b/include/linux/uinput.h
@@ -42,8 +42,7 @@ struct uinput_request {
42 int code; /* UI_FF_UPLOAD, UI_FF_ERASE */ 42 int code; /* UI_FF_UPLOAD, UI_FF_ERASE */
43 43
44 int retval; 44 int retval;
45 wait_queue_head_t waitq; 45 struct completion done;
46 int completed;
47 46
48 union { 47 union {
49 int effect_id; 48 int effect_id;
@@ -62,7 +61,7 @@ struct uinput_device {
62 61
63 struct uinput_request *requests[UINPUT_NUM_REQUESTS]; 62 struct uinput_request *requests[UINPUT_NUM_REQUESTS];
64 wait_queue_head_t requests_waitq; 63 wait_queue_head_t requests_waitq;
65 struct semaphore requests_sem; 64 spinlock_t requests_lock;
66}; 65};
67#endif /* __KERNEL__ */ 66#endif /* __KERNEL__ */
68 67