aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Purdie <rpurdie@rpsys.net>2007-10-13 00:38:52 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2007-10-13 00:38:52 -0400
commit70093178b6eda34e4a4fb18cc4a48a9eacc01d98 (patch)
tree5e35093d48ef2604ab5f8b4d2796691bcc1142c1
parent8f740ef391fc81cb887fa08d213cf67b843cb3b7 (diff)
Input: remove tsdev interface
Remove the obsolete tsdev.c driver as scheduled. Signed-off-by: Richard Purdie <rpurdie@rpsys.net> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--Documentation/feature-removal-schedule.txt14
-rw-r--r--Documentation/kernel-parameters.txt3
-rw-r--r--drivers/input/Kconfig22
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/tsdev.c700
5 files changed, 0 insertions, 740 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 63df2262d41a..fb8258ebc577 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -205,20 +205,6 @@ Who: Len Brown <len.brown@intel.com>
205 205
206--------------------------- 206---------------------------
207 207
208What: Compaq touchscreen device emulation
209When: Oct 2007
210Files: drivers/input/tsdev.c
211Why: The code says it was obsolete when it was written in 2001.
212 tslib is a userspace library which does anything tsdev can do and
213 much more besides in userspace where this code belongs. There is no
214 longer any need for tsdev and applications should have converted to
215 use tslib by now.
216 The name "tsdev" is also extremely confusing and lots of people have
217 it loaded when they don't need/use it.
218Who: Richard Purdie <rpurdie@rpsys.net>
219
220---------------------------
221
222What: i2c-ixp2000, i2c-ixp4xx and scx200_i2c drivers 208What: i2c-ixp2000, i2c-ixp4xx and scx200_i2c drivers
223When: September 2007 209When: September 2007
224Why: Obsolete. The new i2c-gpio driver replaces all hardware-specific 210Why: Obsolete. The new i2c-gpio driver replaces all hardware-specific
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index c323778270ff..01d5c3c5691a 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1883,9 +1883,6 @@ and is between 256 and 4096 characters. It is defined in the file
1883 Format: 1883 Format:
1884 <io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq> 1884 <io>,<irq>,<dma>,<dma2>,<sb_io>,<sb_irq>,<sb_dma>,<mpu_io>,<mpu_irq>
1885 1885
1886 tsdev.xres= [TS] Horizontal screen resolution.
1887 tsdev.yres= [TS] Vertical screen resolution.
1888
1889 turbografx.map[2|3]= [HW,JOY] 1886 turbografx.map[2|3]= [HW,JOY]
1890 TurboGraFX parallel port interface 1887 TurboGraFX parallel port interface
1891 Format: 1888 Format:
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 2d87357e2b2b..63512d906f02 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -114,28 +114,6 @@ config INPUT_JOYDEV
114 To compile this driver as a module, choose M here: the 114 To compile this driver as a module, choose M here: the
115 module will be called joydev. 115 module will be called joydev.
116 116
117config INPUT_TSDEV
118 tristate "Touchscreen interface"
119 ---help---
120 Say Y here if you have an application that only can understand the
121 Compaq touchscreen protocol for absolute pointer data. This is
122 useful namely for embedded configurations.
123
124 If unsure, say N.
125
126 To compile this driver as a module, choose M here: the
127 module will be called tsdev.
128
129config INPUT_TSDEV_SCREEN_X
130 int "Horizontal screen resolution"
131 depends on INPUT_TSDEV
132 default "240"
133
134config INPUT_TSDEV_SCREEN_Y
135 int "Vertical screen resolution"
136 depends on INPUT_TSDEV
137 default "320"
138
139config INPUT_EVDEV 117config INPUT_EVDEV
140 tristate "Event interface" 118 tristate "Event interface"
141 help 119 help
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 15eb752697b3..99af903bd3ce 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
13obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o 13obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
14obj-$(CONFIG_INPUT_JOYDEV) += joydev.o 14obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
15obj-$(CONFIG_INPUT_EVDEV) += evdev.o 15obj-$(CONFIG_INPUT_EVDEV) += evdev.o
16obj-$(CONFIG_INPUT_TSDEV) += tsdev.o
17obj-$(CONFIG_INPUT_EVBUG) += evbug.o 16obj-$(CONFIG_INPUT_EVBUG) += evbug.o
18 17
19obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/ 18obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
deleted file mode 100644
index 120233493758..000000000000
--- a/drivers/input/tsdev.c
+++ /dev/null
@@ -1,700 +0,0 @@
1/*
2 * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $
3 *
4 * Copyright (c) 2001 "Crazy" james Simmons
5 *
6 * Compaq touchscreen protocol driver. The protocol emulated by this driver
7 * is obsolete; for new programs use the tslib library which can read directly
8 * from evdev and perform dejittering, variance filtering and calibration -
9 * all in user space, not at kernel level. The meaning of this driver is
10 * to allow usage of newer input drivers with old applications that use the
11 * old /dev/h3600_ts and /dev/h3600_tsraw devices.
12 *
13 * 09-Apr-2004: Andrew Zabolotny <zap@homelink.ru>
14 * Fixed to actually work, not just output random numbers.
15 * Added support for both h3600_ts and h3600_tsraw protocol
16 * emulation.
17 */
18
19/*
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 *
34 * Should you need to contact me, the author, you can do so either by
35 * e-mail - mail your message to <jsimmons@infradead.org>.
36 */
37
38#define TSDEV_MINOR_BASE 128
39#define TSDEV_MINORS 32
40/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */
41#define TSDEV_MINOR_MASK 15
42#define TSDEV_BUFFER_SIZE 64
43
44#include <linux/slab.h>
45#include <linux/poll.h>
46#include <linux/module.h>
47#include <linux/moduleparam.h>
48#include <linux/init.h>
49#include <linux/input.h>
50#include <linux/major.h>
51#include <linux/random.h>
52#include <linux/time.h>
53#include <linux/device.h>
54
55#ifndef CONFIG_INPUT_TSDEV_SCREEN_X
56#define CONFIG_INPUT_TSDEV_SCREEN_X 240
57#endif
58#ifndef CONFIG_INPUT_TSDEV_SCREEN_Y
59#define CONFIG_INPUT_TSDEV_SCREEN_Y 320
60#endif
61
62/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw
63 * devices. The first one must output X/Y data in 'cooked' format, e.g.
64 * filtered, dejittered and calibrated. Second device just outputs raw
65 * data received from the hardware.
66 *
67 * This driver doesn't support filtering and dejittering; it supports only
68 * calibration. Filtering and dejittering must be done in the low-level
69 * driver, if needed, because it may gain additional benefits from knowing
70 * the low-level details, the nature of noise and so on.
71 *
72 * The driver precomputes a calibration matrix given the initial xres and
73 * yres values (quite innacurate for most touchscreens) that will result
74 * in a more or less expected range of output values. The driver supports
75 * the TS_SET_CAL ioctl, which will replace the calibration matrix with a
76 * new one, supposedly generated from the values taken from the raw device.
77 */
78
79MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
80MODULE_DESCRIPTION("Input driver to touchscreen converter");
81MODULE_LICENSE("GPL");
82
83static int xres = CONFIG_INPUT_TSDEV_SCREEN_X;
84module_param(xres, uint, 0);
85MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)");
86
87static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y;
88module_param(yres, uint, 0);
89MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)");
90
91/* From Compaq's Touch Screen Specification version 0.2 (draft) */
92struct ts_event {
93 short pressure;
94 short x;
95 short y;
96 short millisecs;
97};
98
99struct ts_calibration {
100 int xscale;
101 int xtrans;
102 int yscale;
103 int ytrans;
104 int xyswap;
105};
106
107struct tsdev {
108 int exist;
109 int open;
110 int minor;
111 char name[8];
112 struct input_handle handle;
113 wait_queue_head_t wait;
114 struct list_head client_list;
115 spinlock_t client_lock; /* protects client_list */
116 struct mutex mutex;
117 struct device dev;
118
119 int x, y, pressure;
120 struct ts_calibration cal;
121};
122
123struct tsdev_client {
124 struct fasync_struct *fasync;
125 struct list_head node;
126 struct tsdev *tsdev;
127 struct ts_event buffer[TSDEV_BUFFER_SIZE];
128 int head, tail;
129 spinlock_t buffer_lock; /* protects access to buffer, head and tail */
130 int raw;
131};
132
133/* The following ioctl codes are defined ONLY for backward compatibility.
134 * Don't use tsdev for new developement; use the tslib library instead.
135 * Touchscreen calibration is a fully userspace task.
136 */
137/* Use 'f' as magic number */
138#define IOC_H3600_TS_MAGIC 'f'
139#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration)
140#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
141
142static struct tsdev *tsdev_table[TSDEV_MINORS/2];
143static DEFINE_MUTEX(tsdev_table_mutex);
144
145static int tsdev_fasync(int fd, struct file *file, int on)
146{
147 struct tsdev_client *client = file->private_data;
148 int retval;
149
150 retval = fasync_helper(fd, file, on, &client->fasync);
151
152 return retval < 0 ? retval : 0;
153}
154
155static void tsdev_free(struct device *dev)
156{
157 struct tsdev *tsdev = container_of(dev, struct tsdev, dev);
158
159 kfree(tsdev);
160}
161
162static void tsdev_attach_client(struct tsdev *tsdev, struct tsdev_client *client)
163{
164 spin_lock(&tsdev->client_lock);
165 list_add_tail_rcu(&client->node, &tsdev->client_list);
166 spin_unlock(&tsdev->client_lock);
167 synchronize_sched();
168}
169
170static void tsdev_detach_client(struct tsdev *tsdev, struct tsdev_client *client)
171{
172 spin_lock(&tsdev->client_lock);
173 list_del_rcu(&client->node);
174 spin_unlock(&tsdev->client_lock);
175 synchronize_sched();
176}
177
178static int tsdev_open_device(struct tsdev *tsdev)
179{
180 int retval;
181
182 retval = mutex_lock_interruptible(&tsdev->mutex);
183 if (retval)
184 return retval;
185
186 if (!tsdev->exist)
187 retval = -ENODEV;
188 else if (!tsdev->open++) {
189 retval = input_open_device(&tsdev->handle);
190 if (retval)
191 tsdev->open--;
192 }
193
194 mutex_unlock(&tsdev->mutex);
195 return retval;
196}
197
198static void tsdev_close_device(struct tsdev *tsdev)
199{
200 mutex_lock(&tsdev->mutex);
201
202 if (tsdev->exist && !--tsdev->open)
203 input_close_device(&tsdev->handle);
204
205 mutex_unlock(&tsdev->mutex);
206}
207
208/*
209 * Wake up users waiting for IO so they can disconnect from
210 * dead device.
211 */
212static void tsdev_hangup(struct tsdev *tsdev)
213{
214 struct tsdev_client *client;
215
216 spin_lock(&tsdev->client_lock);
217 list_for_each_entry(client, &tsdev->client_list, node)
218 kill_fasync(&client->fasync, SIGIO, POLL_HUP);
219 spin_unlock(&tsdev->client_lock);
220
221 wake_up_interruptible(&tsdev->wait);
222}
223
224static int tsdev_release(struct inode *inode, struct file *file)
225{
226 struct tsdev_client *client = file->private_data;
227 struct tsdev *tsdev = client->tsdev;
228
229 tsdev_fasync(-1, file, 0);
230 tsdev_detach_client(tsdev, client);
231 kfree(client);
232
233 tsdev_close_device(tsdev);
234 put_device(&tsdev->dev);
235
236 return 0;
237}
238
239static int tsdev_open(struct inode *inode, struct file *file)
240{
241 int i = iminor(inode) - TSDEV_MINOR_BASE;
242 struct tsdev_client *client;
243 struct tsdev *tsdev;
244 int error;
245
246 printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
247 "for removal.\nSee Documentation/feature-removal-schedule.txt "
248 "for details.\n");
249
250 if (i >= TSDEV_MINORS)
251 return -ENODEV;
252
253 error = mutex_lock_interruptible(&tsdev_table_mutex);
254 if (error)
255 return error;
256 tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
257 if (tsdev)
258 get_device(&tsdev->dev);
259 mutex_unlock(&tsdev_table_mutex);
260
261 if (!tsdev)
262 return -ENODEV;
263
264 client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);
265 if (!client) {
266 error = -ENOMEM;
267 goto err_put_tsdev;
268 }
269
270 spin_lock_init(&client->buffer_lock);
271 client->tsdev = tsdev;
272 client->raw = i >= TSDEV_MINORS / 2;
273 tsdev_attach_client(tsdev, client);
274
275 error = tsdev_open_device(tsdev);
276 if (error)
277 goto err_free_client;
278
279 file->private_data = client;
280 return 0;
281
282 err_free_client:
283 tsdev_detach_client(tsdev, client);
284 kfree(client);
285 err_put_tsdev:
286 put_device(&tsdev->dev);
287 return error;
288}
289
290static int tsdev_fetch_next_event(struct tsdev_client *client,
291 struct ts_event *event)
292{
293 int have_event;
294
295 spin_lock_irq(&client->buffer_lock);
296
297 have_event = client->head != client->tail;
298 if (have_event) {
299 *event = client->buffer[client->tail++];
300 client->tail &= TSDEV_BUFFER_SIZE - 1;
301 }
302
303 spin_unlock_irq(&client->buffer_lock);
304
305 return have_event;
306}
307
308static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
309 loff_t *ppos)
310{
311 struct tsdev_client *client = file->private_data;
312 struct tsdev *tsdev = client->tsdev;
313 struct ts_event event;
314 int retval;
315
316 if (client->head == client->tail && tsdev->exist &&
317 (file->f_flags & O_NONBLOCK))
318 return -EAGAIN;
319
320 retval = wait_event_interruptible(tsdev->wait,
321 client->head != client->tail || !tsdev->exist);
322 if (retval)
323 return retval;
324
325 if (!tsdev->exist)
326 return -ENODEV;
327
328 while (retval + sizeof(struct ts_event) <= count &&
329 tsdev_fetch_next_event(client, &event)) {
330
331 if (copy_to_user(buffer + retval, &event,
332 sizeof(struct ts_event)))
333 return -EFAULT;
334
335 retval += sizeof(struct ts_event);
336 }
337
338 return retval;
339}
340
341/* No kernel lock - fine */
342static unsigned int tsdev_poll(struct file *file, poll_table *wait)
343{
344 struct tsdev_client *client = file->private_data;
345 struct tsdev *tsdev = client->tsdev;
346
347 poll_wait(file, &tsdev->wait, wait);
348 return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
349 (tsdev->exist ? 0 : (POLLHUP | POLLERR));
350}
351
352static long tsdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
353{
354 struct tsdev_client *client = file->private_data;
355 struct tsdev *tsdev = client->tsdev;
356 int retval = 0;
357
358 retval = mutex_lock_interruptible(&tsdev->mutex);
359 if (retval)
360 return retval;
361
362 if (!tsdev->exist) {
363 retval = -ENODEV;
364 goto out;
365 }
366
367 switch (cmd) {
368
369 case TS_GET_CAL:
370 if (copy_to_user((void __user *)arg, &tsdev->cal,
371 sizeof (struct ts_calibration)))
372 retval = -EFAULT;
373 break;
374
375 case TS_SET_CAL:
376 if (copy_from_user(&tsdev->cal, (void __user *)arg,
377 sizeof(struct ts_calibration)))
378 retval = -EFAULT;
379 break;
380
381 default:
382 retval = -EINVAL;
383 break;
384 }
385
386 out:
387 mutex_unlock(&tsdev->mutex);
388 return retval;
389}
390
391static const struct file_operations tsdev_fops = {
392 .owner = THIS_MODULE,
393 .open = tsdev_open,
394 .release = tsdev_release,
395 .read = tsdev_read,
396 .poll = tsdev_poll,
397 .fasync = tsdev_fasync,
398 .unlocked_ioctl = tsdev_ioctl,
399};
400
401static void tsdev_pass_event(struct tsdev *tsdev, struct tsdev_client *client,
402 int x, int y, int pressure, int millisecs)
403{
404 struct ts_event *event;
405 int tmp;
406
407 /* Interrupts are already disabled, just acquire the lock */
408 spin_lock(&client->buffer_lock);
409
410 event = &client->buffer[client->head++];
411 client->head &= TSDEV_BUFFER_SIZE - 1;
412
413 /* Calibration */
414 if (!client->raw) {
415 x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
416 y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
417 if (tsdev->cal.xyswap) {
418 tmp = x; x = y; y = tmp;
419 }
420 }
421
422 event->millisecs = millisecs;
423 event->x = x;
424 event->y = y;
425 event->pressure = pressure;
426
427 spin_unlock(&client->buffer_lock);
428
429 kill_fasync(&client->fasync, SIGIO, POLL_IN);
430}
431
432static void tsdev_distribute_event(struct tsdev *tsdev)
433{
434 struct tsdev_client *client;
435 struct timeval time;
436 int millisecs;
437
438 do_gettimeofday(&time);
439 millisecs = time.tv_usec / 1000;
440
441 list_for_each_entry_rcu(client, &tsdev->client_list, node)
442 tsdev_pass_event(tsdev, client,
443 tsdev->x, tsdev->y,
444 tsdev->pressure, millisecs);
445}
446
447static void tsdev_event(struct input_handle *handle, unsigned int type,
448 unsigned int code, int value)
449{
450 struct tsdev *tsdev = handle->private;
451 struct input_dev *dev = handle->dev;
452 int wake_up_readers = 0;
453
454 switch (type) {
455
456 case EV_ABS:
457 switch (code) {
458
459 case ABS_X:
460 tsdev->x = value;
461 break;
462
463 case ABS_Y:
464 tsdev->y = value;
465 break;
466
467 case ABS_PRESSURE:
468 if (value > dev->absmax[ABS_PRESSURE])
469 value = dev->absmax[ABS_PRESSURE];
470 value -= dev->absmin[ABS_PRESSURE];
471 if (value < 0)
472 value = 0;
473 tsdev->pressure = value;
474 break;
475 }
476 break;
477
478 case EV_REL:
479 switch (code) {
480
481 case REL_X:
482 tsdev->x += value;
483 if (tsdev->x < 0)
484 tsdev->x = 0;
485 else if (tsdev->x > xres)
486 tsdev->x = xres;
487 break;
488
489 case REL_Y:
490 tsdev->y += value;
491 if (tsdev->y < 0)
492 tsdev->y = 0;
493 else if (tsdev->y > yres)
494 tsdev->y = yres;
495 break;
496 }
497 break;
498
499 case EV_KEY:
500 if (code == BTN_TOUCH || code == BTN_MOUSE) {
501 switch (value) {
502
503 case 0:
504 tsdev->pressure = 0;
505 break;
506
507 case 1:
508 if (!tsdev->pressure)
509 tsdev->pressure = 1;
510 break;
511 }
512 }
513 break;
514
515 case EV_SYN:
516 if (code == SYN_REPORT) {
517 tsdev_distribute_event(tsdev);
518 wake_up_readers = 1;
519 }
520 break;
521 }
522
523 if (wake_up_readers)
524 wake_up_interruptible(&tsdev->wait);
525}
526
527static int tsdev_install_chrdev(struct tsdev *tsdev)
528{
529 tsdev_table[tsdev->minor] = tsdev;
530 return 0;
531}
532
533static void tsdev_remove_chrdev(struct tsdev *tsdev)
534{
535 mutex_lock(&tsdev_table_mutex);
536 tsdev_table[tsdev->minor] = NULL;
537 mutex_unlock(&tsdev_table_mutex);
538}
539
540/*
541 * Mark device non-existant. This disables writes, ioctls and
542 * prevents new users from opening the device. Already posted
543 * blocking reads will stay, however new ones will fail.
544 */
545static void tsdev_mark_dead(struct tsdev *tsdev)
546{
547 mutex_lock(&tsdev->mutex);
548 tsdev->exist = 0;
549 mutex_unlock(&tsdev->mutex);
550}
551
552static void tsdev_cleanup(struct tsdev *tsdev)
553{
554 struct input_handle *handle = &tsdev->handle;
555
556 tsdev_mark_dead(tsdev);
557 tsdev_hangup(tsdev);
558 tsdev_remove_chrdev(tsdev);
559
560 /* tsdev is marked dead so noone else accesses tsdev->open */
561 if (tsdev->open)
562 input_close_device(handle);
563}
564
565static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
566 const struct input_device_id *id)
567{
568 struct tsdev *tsdev;
569 int delta;
570 int minor;
571 int error;
572
573 for (minor = 0; minor < TSDEV_MINORS / 2; minor++)
574 if (!tsdev_table[minor])
575 break;
576
577 if (minor == TSDEV_MINORS) {
578 printk(KERN_ERR "tsdev: no more free tsdev devices\n");
579 return -ENFILE;
580 }
581
582 tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL);
583 if (!tsdev)
584 return -ENOMEM;
585
586 INIT_LIST_HEAD(&tsdev->client_list);
587 spin_lock_init(&tsdev->client_lock);
588 mutex_init(&tsdev->mutex);
589 init_waitqueue_head(&tsdev->wait);
590
591 snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor);
592 tsdev->exist = 1;
593 tsdev->minor = minor;
594
595 tsdev->handle.dev = dev;
596 tsdev->handle.name = tsdev->name;
597 tsdev->handle.handler = handler;
598 tsdev->handle.private = tsdev;
599
600 /* Precompute the rough calibration matrix */
601 delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
602 if (delta == 0)
603 delta = 1;
604 tsdev->cal.xscale = (xres << 8) / delta;
605 tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8);
606
607 delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1;
608 if (delta == 0)
609 delta = 1;
610 tsdev->cal.yscale = (yres << 8) / delta;
611 tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);
612
613 strlcpy(tsdev->dev.bus_id, tsdev->name, sizeof(tsdev->dev.bus_id));
614 tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor);
615 tsdev->dev.class = &input_class;
616 tsdev->dev.parent = &dev->dev;
617 tsdev->dev.release = tsdev_free;
618 device_initialize(&tsdev->dev);
619
620 error = input_register_handle(&tsdev->handle);
621 if (error)
622 goto err_free_tsdev;
623
624 error = tsdev_install_chrdev(tsdev);
625 if (error)
626 goto err_unregister_handle;
627
628 error = device_add(&tsdev->dev);
629 if (error)
630 goto err_cleanup_tsdev;
631
632 return 0;
633
634 err_cleanup_tsdev:
635 tsdev_cleanup(tsdev);
636 err_unregister_handle:
637 input_unregister_handle(&tsdev->handle);
638 err_free_tsdev:
639 put_device(&tsdev->dev);
640 return error;
641}
642
643static void tsdev_disconnect(struct input_handle *handle)
644{
645 struct tsdev *tsdev = handle->private;
646
647 device_del(&tsdev->dev);
648 tsdev_cleanup(tsdev);
649 input_unregister_handle(handle);
650 put_device(&tsdev->dev);
651}
652
653static const struct input_device_id tsdev_ids[] = {
654 {
655 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
656 .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
657 .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
658 .relbit = { BIT(REL_X) | BIT(REL_Y) },
659 }, /* A mouse like device, at least one button, two relative axes */
660
661 {
662 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
663 .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
664 .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
665 .absbit = { BIT(ABS_X) | BIT(ABS_Y) },
666 }, /* A tablet like device, at least touch detection, two absolute axes */
667
668 {
669 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
670 .evbit = { BIT(EV_ABS) },
671 .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
672 }, /* A tablet like device with several gradations of pressure */
673
674 {} /* Terminating entry */
675};
676
677MODULE_DEVICE_TABLE(input, tsdev_ids);
678
679static struct input_handler tsdev_handler = {
680 .event = tsdev_event,
681 .connect = tsdev_connect,
682 .disconnect = tsdev_disconnect,
683 .fops = &tsdev_fops,
684 .minor = TSDEV_MINOR_BASE,
685 .name = "tsdev",
686 .id_table = tsdev_ids,
687};
688
689static int __init tsdev_init(void)
690{
691 return input_register_handler(&tsdev_handler);
692}
693
694static void __exit tsdev_exit(void)
695{
696 input_unregister_handler(&tsdev_handler);
697}
698
699module_init(tsdev_init);
700module_exit(tsdev_exit);