diff options
Diffstat (limited to 'drivers/input/tsdev.c')
-rw-r--r-- | drivers/input/tsdev.c | 110 |
1 files changed, 59 insertions, 51 deletions
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index a23aedc64ab1..fbef35d2d76c 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c | |||
@@ -111,13 +111,13 @@ struct tsdev { | |||
111 | int minor; | 111 | int minor; |
112 | char name[8]; | 112 | char name[8]; |
113 | wait_queue_head_t wait; | 113 | wait_queue_head_t wait; |
114 | struct list_head list; | 114 | struct list_head client_list; |
115 | struct input_handle handle; | 115 | struct input_handle handle; |
116 | int x, y, pressure; | 116 | int x, y, pressure; |
117 | struct ts_calibration cal; | 117 | struct ts_calibration cal; |
118 | }; | 118 | }; |
119 | 119 | ||
120 | struct tsdev_list { | 120 | struct tsdev_client { |
121 | struct fasync_struct *fasync; | 121 | struct fasync_struct *fasync; |
122 | struct list_head node; | 122 | struct list_head node; |
123 | struct tsdev *tsdev; | 123 | struct tsdev *tsdev; |
@@ -139,17 +139,18 @@ static struct tsdev *tsdev_table[TSDEV_MINORS/2]; | |||
139 | 139 | ||
140 | static int tsdev_fasync(int fd, struct file *file, int on) | 140 | static int tsdev_fasync(int fd, struct file *file, int on) |
141 | { | 141 | { |
142 | struct tsdev_list *list = file->private_data; | 142 | struct tsdev_client *client = file->private_data; |
143 | int retval; | 143 | int retval; |
144 | 144 | ||
145 | retval = fasync_helper(fd, file, on, &list->fasync); | 145 | retval = fasync_helper(fd, file, on, &client->fasync); |
146 | return retval < 0 ? retval : 0; | 146 | return retval < 0 ? retval : 0; |
147 | } | 147 | } |
148 | 148 | ||
149 | static int tsdev_open(struct inode *inode, struct file *file) | 149 | static int tsdev_open(struct inode *inode, struct file *file) |
150 | { | 150 | { |
151 | int i = iminor(inode) - TSDEV_MINOR_BASE; | 151 | int i = iminor(inode) - TSDEV_MINOR_BASE; |
152 | struct tsdev_list *list; | 152 | struct tsdev_client *client; |
153 | struct tsdev *tsdev; | ||
153 | 154 | ||
154 | printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled " | 155 | printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled " |
155 | "for removal.\nSee Documentation/feature-removal-schedule.txt " | 156 | "for removal.\nSee Documentation/feature-removal-schedule.txt " |
@@ -158,19 +159,22 @@ static int tsdev_open(struct inode *inode, struct file *file) | |||
158 | if (i >= TSDEV_MINORS) | 159 | if (i >= TSDEV_MINORS) |
159 | return -ENODEV; | 160 | return -ENODEV; |
160 | 161 | ||
161 | if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL))) | 162 | tsdev = tsdev_table[i & TSDEV_MINOR_MASK]; |
163 | if (!tsdev || !tsdev->exist) | ||
164 | return -ENODEV; | ||
165 | |||
166 | client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL); | ||
167 | if (!client) | ||
162 | return -ENOMEM; | 168 | return -ENOMEM; |
163 | 169 | ||
164 | list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0; | 170 | client->tsdev = tsdev; |
171 | client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0; | ||
172 | list_add_tail(&client->node, &tsdev->client_list); | ||
165 | 173 | ||
166 | i &= TSDEV_MINOR_MASK; | 174 | if (!tsdev->open++ && tsdev->exist) |
167 | list->tsdev = tsdev_table[i]; | 175 | input_open_device(&tsdev->handle); |
168 | list_add_tail(&list->node, &tsdev_table[i]->list); | ||
169 | file->private_data = list; | ||
170 | 176 | ||
171 | if (!list->tsdev->open++) | 177 | file->private_data = client; |
172 | if (list->tsdev->exist) | ||
173 | input_open_device(&list->tsdev->handle); | ||
174 | return 0; | 178 | return 0; |
175 | } | 179 | } |
176 | 180 | ||
@@ -182,45 +186,48 @@ static void tsdev_free(struct tsdev *tsdev) | |||
182 | 186 | ||
183 | static int tsdev_release(struct inode *inode, struct file *file) | 187 | static int tsdev_release(struct inode *inode, struct file *file) |
184 | { | 188 | { |
185 | struct tsdev_list *list = file->private_data; | 189 | struct tsdev_client *client = file->private_data; |
190 | struct tsdev *tsdev = client->tsdev; | ||
186 | 191 | ||
187 | tsdev_fasync(-1, file, 0); | 192 | tsdev_fasync(-1, file, 0); |
188 | list_del(&list->node); | ||
189 | 193 | ||
190 | if (!--list->tsdev->open) { | 194 | list_del(&client->node); |
191 | if (list->tsdev->exist) | 195 | kfree(client); |
192 | input_close_device(&list->tsdev->handle); | 196 | |
197 | if (!--tsdev->open) { | ||
198 | if (tsdev->exist) | ||
199 | input_close_device(&tsdev->handle); | ||
193 | else | 200 | else |
194 | tsdev_free(list->tsdev); | 201 | tsdev_free(tsdev); |
195 | } | 202 | } |
196 | kfree(list); | 203 | |
197 | return 0; | 204 | return 0; |
198 | } | 205 | } |
199 | 206 | ||
200 | static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, | 207 | static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, |
201 | loff_t * ppos) | 208 | loff_t *ppos) |
202 | { | 209 | { |
203 | struct tsdev_list *list = file->private_data; | 210 | struct tsdev_client *client = file->private_data; |
211 | struct tsdev *tsdev = client->tsdev; | ||
204 | int retval = 0; | 212 | int retval = 0; |
205 | 213 | ||
206 | if (list->head == list->tail && list->tsdev->exist && (file->f_flags & O_NONBLOCK)) | 214 | if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK)) |
207 | return -EAGAIN; | 215 | return -EAGAIN; |
208 | 216 | ||
209 | retval = wait_event_interruptible(list->tsdev->wait, | 217 | retval = wait_event_interruptible(tsdev->wait, |
210 | list->head != list->tail || !list->tsdev->exist); | 218 | client->head != client->tail || !tsdev->exist); |
211 | |||
212 | if (retval) | 219 | if (retval) |
213 | return retval; | 220 | return retval; |
214 | 221 | ||
215 | if (!list->tsdev->exist) | 222 | if (!tsdev->exist) |
216 | return -ENODEV; | 223 | return -ENODEV; |
217 | 224 | ||
218 | while (list->head != list->tail && | 225 | while (client->head != client->tail && |
219 | retval + sizeof (struct ts_event) <= count) { | 226 | retval + sizeof (struct ts_event) <= count) { |
220 | if (copy_to_user (buffer + retval, list->event + list->tail, | 227 | if (copy_to_user (buffer + retval, client->event + client->tail, |
221 | sizeof (struct ts_event))) | 228 | sizeof (struct ts_event))) |
222 | return -EFAULT; | 229 | return -EFAULT; |
223 | list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1); | 230 | client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1); |
224 | retval += sizeof (struct ts_event); | 231 | retval += sizeof (struct ts_event); |
225 | } | 232 | } |
226 | 233 | ||
@@ -228,20 +235,21 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, | |||
228 | } | 235 | } |
229 | 236 | ||
230 | /* No kernel lock - fine */ | 237 | /* No kernel lock - fine */ |
231 | static unsigned int tsdev_poll(struct file *file, poll_table * wait) | 238 | static unsigned int tsdev_poll(struct file *file, poll_table *wait) |
232 | { | 239 | { |
233 | struct tsdev_list *list = file->private_data; | 240 | struct tsdev_client *client = file->private_data; |
241 | struct tsdev *tsdev = client->tsdev; | ||
234 | 242 | ||
235 | poll_wait(file, &list->tsdev->wait, wait); | 243 | poll_wait(file, &tsdev->wait, wait); |
236 | return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) | | 244 | return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) | |
237 | (list->tsdev->exist ? 0 : (POLLHUP | POLLERR)); | 245 | (tsdev->exist ? 0 : (POLLHUP | POLLERR)); |
238 | } | 246 | } |
239 | 247 | ||
240 | static int tsdev_ioctl(struct inode *inode, struct file *file, | 248 | static int tsdev_ioctl(struct inode *inode, struct file *file, |
241 | unsigned int cmd, unsigned long arg) | 249 | unsigned int cmd, unsigned long arg) |
242 | { | 250 | { |
243 | struct tsdev_list *list = file->private_data; | 251 | struct tsdev_client *client = file->private_data; |
244 | struct tsdev *tsdev = list->tsdev; | 252 | struct tsdev *tsdev = client->tsdev; |
245 | int retval = 0; | 253 | int retval = 0; |
246 | 254 | ||
247 | switch (cmd) { | 255 | switch (cmd) { |
@@ -279,7 +287,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, | |||
279 | unsigned int code, int value) | 287 | unsigned int code, int value) |
280 | { | 288 | { |
281 | struct tsdev *tsdev = handle->private; | 289 | struct tsdev *tsdev = handle->private; |
282 | struct tsdev_list *list; | 290 | struct tsdev_client *client; |
283 | struct timeval time; | 291 | struct timeval time; |
284 | 292 | ||
285 | switch (type) { | 293 | switch (type) { |
@@ -343,18 +351,18 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, | |||
343 | if (type != EV_SYN || code != SYN_REPORT) | 351 | if (type != EV_SYN || code != SYN_REPORT) |
344 | return; | 352 | return; |
345 | 353 | ||
346 | list_for_each_entry(list, &tsdev->list, node) { | 354 | list_for_each_entry(client, &tsdev->client_list, node) { |
347 | int x, y, tmp; | 355 | int x, y, tmp; |
348 | 356 | ||
349 | do_gettimeofday(&time); | 357 | do_gettimeofday(&time); |
350 | list->event[list->head].millisecs = time.tv_usec / 100; | 358 | client->event[client->head].millisecs = time.tv_usec / 100; |
351 | list->event[list->head].pressure = tsdev->pressure; | 359 | client->event[client->head].pressure = tsdev->pressure; |
352 | 360 | ||
353 | x = tsdev->x; | 361 | x = tsdev->x; |
354 | y = tsdev->y; | 362 | y = tsdev->y; |
355 | 363 | ||
356 | /* Calibration */ | 364 | /* Calibration */ |
357 | if (!list->raw) { | 365 | if (!client->raw) { |
358 | x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; | 366 | x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; |
359 | y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; | 367 | y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; |
360 | if (tsdev->cal.xyswap) { | 368 | if (tsdev->cal.xyswap) { |
@@ -362,10 +370,10 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, | |||
362 | } | 370 | } |
363 | } | 371 | } |
364 | 372 | ||
365 | list->event[list->head].x = x; | 373 | client->event[client->head].x = x; |
366 | list->event[list->head].y = y; | 374 | client->event[client->head].y = y; |
367 | list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1); | 375 | client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1); |
368 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | 376 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
369 | } | 377 | } |
370 | wake_up_interruptible(&tsdev->wait); | 378 | wake_up_interruptible(&tsdev->wait); |
371 | } | 379 | } |
@@ -390,7 +398,7 @@ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
390 | if (!tsdev) | 398 | if (!tsdev) |
391 | return -ENOMEM; | 399 | return -ENOMEM; |
392 | 400 | ||
393 | INIT_LIST_HEAD(&tsdev->list); | 401 | INIT_LIST_HEAD(&tsdev->client_list); |
394 | init_waitqueue_head(&tsdev->wait); | 402 | init_waitqueue_head(&tsdev->wait); |
395 | 403 | ||
396 | sprintf(tsdev->name, "ts%d", minor); | 404 | sprintf(tsdev->name, "ts%d", minor); |
@@ -451,7 +459,7 @@ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
451 | static void tsdev_disconnect(struct input_handle *handle) | 459 | static void tsdev_disconnect(struct input_handle *handle) |
452 | { | 460 | { |
453 | struct tsdev *tsdev = handle->private; | 461 | struct tsdev *tsdev = handle->private; |
454 | struct tsdev_list *list; | 462 | struct tsdev_client *client; |
455 | 463 | ||
456 | input_unregister_handle(handle); | 464 | input_unregister_handle(handle); |
457 | 465 | ||
@@ -463,8 +471,8 @@ static void tsdev_disconnect(struct input_handle *handle) | |||
463 | if (tsdev->open) { | 471 | if (tsdev->open) { |
464 | input_close_device(handle); | 472 | input_close_device(handle); |
465 | wake_up_interruptible(&tsdev->wait); | 473 | wake_up_interruptible(&tsdev->wait); |
466 | list_for_each_entry(list, &tsdev->list, node) | 474 | list_for_each_entry(client, &tsdev->client_list, node) |
467 | kill_fasync(&list->fasync, SIGIO, POLL_HUP); | 475 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); |
468 | } else | 476 | } else |
469 | tsdev_free(tsdev); | 477 | tsdev_free(tsdev); |
470 | } | 478 | } |