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 | } |
