aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/tsdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/tsdev.c')
-rw-r--r--drivers/input/tsdev.c177
1 files changed, 108 insertions, 69 deletions
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
index 0300dca8591d..5e5b5c91d75b 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
120struct tsdev_list { 120struct 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,38 +139,49 @@ static struct tsdev *tsdev_table[TSDEV_MINORS/2];
139 139
140static int tsdev_fasync(int fd, struct file *file, int on) 140static 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
149static int tsdev_open(struct inode *inode, struct file *file) 149static 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;
154 int error;
153 155
154 printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled " 156 printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
155 "for removal.\nSee Documentation/feature-removal-schedule.txt " 157 "for removal.\nSee Documentation/feature-removal-schedule.txt "
156 "for details.\n"); 158 "for details.\n");
157 159
158 if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK]) 160 if (i >= TSDEV_MINORS)
161 return -ENODEV;
162
163 tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
164 if (!tsdev || !tsdev->exist)
159 return -ENODEV; 165 return -ENODEV;
160 166
161 if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL))) 167 client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);
168 if (!client)
162 return -ENOMEM; 169 return -ENOMEM;
163 170
164 list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0; 171 client->tsdev = tsdev;
172 client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0;
173 list_add_tail(&client->node, &tsdev->client_list);
165 174
166 i &= TSDEV_MINOR_MASK; 175 if (!tsdev->open++ && tsdev->exist) {
167 list->tsdev = tsdev_table[i]; 176 error = input_open_device(&tsdev->handle);
168 list_add_tail(&list->node, &tsdev_table[i]->list); 177 if (error) {
169 file->private_data = list; 178 list_del(&client->node);
179 kfree(client);
180 return error;
181 }
182 }
170 183
171 if (!list->tsdev->open++) 184 file->private_data = client;
172 if (list->tsdev->exist)
173 input_open_device(&list->tsdev->handle);
174 return 0; 185 return 0;
175} 186}
176 187
@@ -182,45 +193,48 @@ static void tsdev_free(struct tsdev *tsdev)
182 193
183static int tsdev_release(struct inode *inode, struct file *file) 194static int tsdev_release(struct inode *inode, struct file *file)
184{ 195{
185 struct tsdev_list *list = file->private_data; 196 struct tsdev_client *client = file->private_data;
197 struct tsdev *tsdev = client->tsdev;
186 198
187 tsdev_fasync(-1, file, 0); 199 tsdev_fasync(-1, file, 0);
188 list_del(&list->node);
189 200
190 if (!--list->tsdev->open) { 201 list_del(&client->node);
191 if (list->tsdev->exist) 202 kfree(client);
192 input_close_device(&list->tsdev->handle); 203
204 if (!--tsdev->open) {
205 if (tsdev->exist)
206 input_close_device(&tsdev->handle);
193 else 207 else
194 tsdev_free(list->tsdev); 208 tsdev_free(tsdev);
195 } 209 }
196 kfree(list); 210
197 return 0; 211 return 0;
198} 212}
199 213
200static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, 214static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
201 loff_t * ppos) 215 loff_t *ppos)
202{ 216{
203 struct tsdev_list *list = file->private_data; 217 struct tsdev_client *client = file->private_data;
218 struct tsdev *tsdev = client->tsdev;
204 int retval = 0; 219 int retval = 0;
205 220
206 if (list->head == list->tail && list->tsdev->exist && (file->f_flags & O_NONBLOCK)) 221 if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK))
207 return -EAGAIN; 222 return -EAGAIN;
208 223
209 retval = wait_event_interruptible(list->tsdev->wait, 224 retval = wait_event_interruptible(tsdev->wait,
210 list->head != list->tail || !list->tsdev->exist); 225 client->head != client->tail || !tsdev->exist);
211
212 if (retval) 226 if (retval)
213 return retval; 227 return retval;
214 228
215 if (!list->tsdev->exist) 229 if (!tsdev->exist)
216 return -ENODEV; 230 return -ENODEV;
217 231
218 while (list->head != list->tail && 232 while (client->head != client->tail &&
219 retval + sizeof (struct ts_event) <= count) { 233 retval + sizeof (struct ts_event) <= count) {
220 if (copy_to_user (buffer + retval, list->event + list->tail, 234 if (copy_to_user (buffer + retval, client->event + client->tail,
221 sizeof (struct ts_event))) 235 sizeof (struct ts_event)))
222 return -EFAULT; 236 return -EFAULT;
223 list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1); 237 client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
224 retval += sizeof (struct ts_event); 238 retval += sizeof (struct ts_event);
225 } 239 }
226 240
@@ -228,32 +242,33 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
228} 242}
229 243
230/* No kernel lock - fine */ 244/* No kernel lock - fine */
231static unsigned int tsdev_poll(struct file *file, poll_table * wait) 245static unsigned int tsdev_poll(struct file *file, poll_table *wait)
232{ 246{
233 struct tsdev_list *list = file->private_data; 247 struct tsdev_client *client = file->private_data;
248 struct tsdev *tsdev = client->tsdev;
234 249
235 poll_wait(file, &list->tsdev->wait, wait); 250 poll_wait(file, &tsdev->wait, wait);
236 return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) | 251 return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
237 (list->tsdev->exist ? 0 : (POLLHUP | POLLERR)); 252 (tsdev->exist ? 0 : (POLLHUP | POLLERR));
238} 253}
239 254
240static int tsdev_ioctl(struct inode *inode, struct file *file, 255static int tsdev_ioctl(struct inode *inode, struct file *file,
241 unsigned int cmd, unsigned long arg) 256 unsigned int cmd, unsigned long arg)
242{ 257{
243 struct tsdev_list *list = file->private_data; 258 struct tsdev_client *client = file->private_data;
244 struct tsdev *tsdev = list->tsdev; 259 struct tsdev *tsdev = client->tsdev;
245 int retval = 0; 260 int retval = 0;
246 261
247 switch (cmd) { 262 switch (cmd) {
248 case TS_GET_CAL: 263 case TS_GET_CAL:
249 if (copy_to_user ((void __user *)arg, &tsdev->cal, 264 if (copy_to_user((void __user *)arg, &tsdev->cal,
250 sizeof (struct ts_calibration))) 265 sizeof (struct ts_calibration)))
251 retval = -EFAULT; 266 retval = -EFAULT;
252 break; 267 break;
253 268
254 case TS_SET_CAL: 269 case TS_SET_CAL:
255 if (copy_from_user (&tsdev->cal, (void __user *)arg, 270 if (copy_from_user(&tsdev->cal, (void __user *)arg,
256 sizeof (struct ts_calibration))) 271 sizeof (struct ts_calibration)))
257 retval = -EFAULT; 272 retval = -EFAULT;
258 break; 273 break;
259 274
@@ -279,7 +294,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
279 unsigned int code, int value) 294 unsigned int code, int value)
280{ 295{
281 struct tsdev *tsdev = handle->private; 296 struct tsdev *tsdev = handle->private;
282 struct tsdev_list *list; 297 struct tsdev_client *client;
283 struct timeval time; 298 struct timeval time;
284 299
285 switch (type) { 300 switch (type) {
@@ -343,18 +358,18 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
343 if (type != EV_SYN || code != SYN_REPORT) 358 if (type != EV_SYN || code != SYN_REPORT)
344 return; 359 return;
345 360
346 list_for_each_entry(list, &tsdev->list, node) { 361 list_for_each_entry(client, &tsdev->client_list, node) {
347 int x, y, tmp; 362 int x, y, tmp;
348 363
349 do_gettimeofday(&time); 364 do_gettimeofday(&time);
350 list->event[list->head].millisecs = time.tv_usec / 100; 365 client->event[client->head].millisecs = time.tv_usec / 100;
351 list->event[list->head].pressure = tsdev->pressure; 366 client->event[client->head].pressure = tsdev->pressure;
352 367
353 x = tsdev->x; 368 x = tsdev->x;
354 y = tsdev->y; 369 y = tsdev->y;
355 370
356 /* Calibration */ 371 /* Calibration */
357 if (!list->raw) { 372 if (!client->raw) {
358 x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; 373 x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
359 y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; 374 y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
360 if (tsdev->cal.xyswap) { 375 if (tsdev->cal.xyswap) {
@@ -362,33 +377,35 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
362 } 377 }
363 } 378 }
364 379
365 list->event[list->head].x = x; 380 client->event[client->head].x = x;
366 list->event[list->head].y = y; 381 client->event[client->head].y = y;
367 list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1); 382 client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1);
368 kill_fasync(&list->fasync, SIGIO, POLL_IN); 383 kill_fasync(&client->fasync, SIGIO, POLL_IN);
369 } 384 }
370 wake_up_interruptible(&tsdev->wait); 385 wake_up_interruptible(&tsdev->wait);
371} 386}
372 387
373static struct input_handle *tsdev_connect(struct input_handler *handler, 388static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
374 struct input_dev *dev, 389 const struct input_device_id *id)
375 const struct input_device_id *id)
376{ 390{
377 struct tsdev *tsdev; 391 struct tsdev *tsdev;
378 struct class_device *cdev; 392 struct class_device *cdev;
393 dev_t devt;
379 int minor, delta; 394 int minor, delta;
395 int error;
380 396
381 for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++); 397 for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
382 if (minor >= TSDEV_MINORS / 2) { 398 if (minor >= TSDEV_MINORS / 2) {
383 printk(KERN_ERR 399 printk(KERN_ERR
384 "tsdev: You have way too many touchscreens\n"); 400 "tsdev: You have way too many touchscreens\n");
385 return NULL; 401 return -ENFILE;
386 } 402 }
387 403
388 if (!(tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL))) 404 tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL);
389 return NULL; 405 if (!tsdev)
406 return -ENOMEM;
390 407
391 INIT_LIST_HEAD(&tsdev->list); 408 INIT_LIST_HEAD(&tsdev->client_list);
392 init_waitqueue_head(&tsdev->wait); 409 init_waitqueue_head(&tsdev->wait);
393 410
394 sprintf(tsdev->name, "ts%d", minor); 411 sprintf(tsdev->name, "ts%d", minor);
@@ -415,23 +432,45 @@ static struct input_handle *tsdev_connect(struct input_handler *handler,
415 432
416 tsdev_table[minor] = tsdev; 433 tsdev_table[minor] = tsdev;
417 434
418 cdev = class_device_create(&input_class, &dev->cdev, 435 devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
419 MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), 436
420 dev->cdev.dev, tsdev->name); 437 cdev = class_device_create(&input_class, &dev->cdev, devt,
438 dev->cdev.dev, tsdev->name);
439 if (IS_ERR(cdev)) {
440 error = PTR_ERR(cdev);
441 goto err_free_tsdev;
442 }
421 443
422 /* temporary symlink to keep userspace happy */ 444 /* temporary symlink to keep userspace happy */
423 sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, 445 error = sysfs_create_link(&input_class.subsys.kobj,
424 tsdev->name); 446 &cdev->kobj, tsdev->name);
447 if (error)
448 goto err_cdev_destroy;
449
450 error = input_register_handle(&tsdev->handle);
451 if (error)
452 goto err_remove_link;
425 453
426 return &tsdev->handle; 454 return 0;
455
456 err_remove_link:
457 sysfs_remove_link(&input_class.subsys.kobj, tsdev->name);
458 err_cdev_destroy:
459 class_device_destroy(&input_class, devt);
460 err_free_tsdev:
461 tsdev_table[minor] = NULL;
462 kfree(tsdev);
463 return error;
427} 464}
428 465
429static void tsdev_disconnect(struct input_handle *handle) 466static void tsdev_disconnect(struct input_handle *handle)
430{ 467{
431 struct tsdev *tsdev = handle->private; 468 struct tsdev *tsdev = handle->private;
432 struct tsdev_list *list; 469 struct tsdev_client *client;
470
471 input_unregister_handle(handle);
433 472
434 sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name); 473 sysfs_remove_link(&input_class.subsys.kobj, tsdev->name);
435 class_device_destroy(&input_class, 474 class_device_destroy(&input_class,
436 MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor)); 475 MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor));
437 tsdev->exist = 0; 476 tsdev->exist = 0;
@@ -439,8 +478,8 @@ static void tsdev_disconnect(struct input_handle *handle)
439 if (tsdev->open) { 478 if (tsdev->open) {
440 input_close_device(handle); 479 input_close_device(handle);
441 wake_up_interruptible(&tsdev->wait); 480 wake_up_interruptible(&tsdev->wait);
442 list_for_each_entry(list, &tsdev->list, node) 481 list_for_each_entry(client, &tsdev->client_list, node)
443 kill_fasync(&list->fasync, SIGIO, POLL_HUP); 482 kill_fasync(&client->fasync, SIGIO, POLL_HUP);
444 } else 483 } else
445 tsdev_free(tsdev); 484 tsdev_free(tsdev);
446} 485}