2 * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $
4 * Copyright (c) 2001 "Crazy" james Simmons
6 * Input driver to Touchscreen device driver module.
8 * Sponsored by Transvirtual Technology
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * Should you need to contact me, the author, you can do so either by
27 * e-mail - mail your message to <jsimmons@transvirtual.com>.
30 #define TSDEV_MINOR_BASE 128
31 #define TSDEV_MINORS 32
32 #define TSDEV_BUFFER_SIZE 64
34 #include <linux/slab.h>
35 #include <linux/poll.h>
36 #include <linux/module.h>
37 #include <linux/init.h>
38 #include <linux/input.h>
39 #include <linux/major.h>
40 #include <linux/config.h>
41 #include <linux/smp_lock.h>
42 #include <linux/random.h>
43 #include <linux/time.h>
44 #include <linux/device.h>
45 #include <linux/devfs_fs_kernel.h>
47 #ifndef CONFIG_INPUT_TSDEV_SCREEN_X
48 #define CONFIG_INPUT_TSDEV_SCREEN_X 240
50 #ifndef CONFIG_INPUT_TSDEV_SCREEN_Y
51 #define CONFIG_INPUT_TSDEV_SCREEN_Y 320
59 wait_queue_head_t wait
;
60 struct list_head list
;
61 struct input_handle handle
;
64 /* From Compaq's Touch Screen Specification version 0.2 (draft) */
73 struct fasync_struct
*fasync
;
74 struct list_head node
;
77 int oldx
, oldy
, pendown
;
78 TS_EVENT event
[TSDEV_BUFFER_SIZE
];
81 static struct input_handler tsdev_handler
;
83 static struct tsdev
*tsdev_table
[TSDEV_MINORS
];
85 static int xres
= CONFIG_INPUT_TSDEV_SCREEN_X
;
86 static int yres
= CONFIG_INPUT_TSDEV_SCREEN_Y
;
88 static int tsdev_fasync(int fd
, struct file
*file
, int on
)
90 struct tsdev_list
*list
= file
->private_data
;
93 retval
= fasync_helper(fd
, file
, on
, &list
->fasync
);
94 return retval
< 0 ? retval
: 0;
97 static int tsdev_open(struct inode
*inode
, struct file
*file
)
99 int i
= iminor(inode
) - TSDEV_MINOR_BASE
;
100 struct tsdev_list
*list
;
102 if (i
>= TSDEV_MINORS
|| !tsdev_table
[i
])
105 if (!(list
= kmalloc(sizeof(struct tsdev_list
), GFP_KERNEL
)))
107 memset(list
, 0, sizeof(struct tsdev_list
));
109 list
->tsdev
= tsdev_table
[i
];
110 list_add_tail(&list
->node
, &tsdev_table
[i
]->list
);
111 file
->private_data
= list
;
113 if (!list
->tsdev
->open
++)
114 if (list
->tsdev
->exist
)
115 input_open_device(&list
->tsdev
->handle
);
119 static void tsdev_free(struct tsdev
*tsdev
)
121 devfs_remove("input/ts%d", tsdev
->minor
);
122 tsdev_table
[tsdev
->minor
] = NULL
;
126 static int tsdev_release(struct inode
*inode
, struct file
*file
)
128 struct tsdev_list
*list
= file
->private_data
;
130 tsdev_fasync(-1, file
, 0);
131 list_del(&list
->node
);
133 if (!--list
->tsdev
->open
) {
134 if (list
->tsdev
->exist
)
135 input_close_device(&list
->tsdev
->handle
);
137 tsdev_free(list
->tsdev
);
143 static ssize_t
tsdev_read(struct file
*file
, char *buffer
, size_t count
,
146 struct tsdev_list
*list
= file
->private_data
;
149 if (list
->head
== list
->tail
&& list
->tsdev
->exist
&& (file
->f_flags
& O_NONBLOCK
))
152 retval
= wait_event_interruptible(list
->tsdev
->wait
,
153 (list
->head
!= list
->tail
) && list
->tsdev
->exist
);
158 if (!list
->tsdev
->exist
)
161 while (list
->head
!= list
->tail
&& retval
+ sizeof(TS_EVENT
) <= count
) {
162 if (copy_to_user (buffer
+ retval
, list
->event
+ list
->tail
, sizeof(TS_EVENT
)))
164 list
->tail
= (list
->tail
+ 1) & (TSDEV_BUFFER_SIZE
- 1);
165 retval
+= sizeof(TS_EVENT
);
171 /* No kernel lock - fine */
172 static unsigned int tsdev_poll(struct file
*file
, poll_table
* wait
)
174 struct tsdev_list
*list
= file
->private_data
;
176 poll_wait(file
, &list
->tsdev
->wait
, wait
);
177 if (list
->head
!= list
->tail
)
178 return POLLIN
| POLLRDNORM
;
182 static int tsdev_ioctl(struct inode
*inode
, struct file
*file
,
183 unsigned int cmd
, unsigned long arg
)
186 struct tsdev_list *list = file->private_data;
187 struct tsdev *evdev = list->tsdev;
188 struct input_dev *dev = tsdev->handle.dev;
203 struct file_operations tsdev_fops
= {
204 .owner
= THIS_MODULE
,
206 .release
= tsdev_release
,
209 .fasync
= tsdev_fasync
,
210 .ioctl
= tsdev_ioctl
,
213 static void tsdev_event(struct input_handle
*handle
, unsigned int type
,
214 unsigned int code
, int value
)
216 struct tsdev
*tsdev
= handle
->private;
217 struct tsdev_list
*list
;
221 list_for_each_entry(list
, &tsdev
->list
, node
) {
228 size
= handle
->dev
->absmax
[ABS_X
] - handle
->dev
->absmin
[ABS_X
];
230 list
->oldx
= ((value
- handle
->dev
->absmin
[ABS_X
]) * xres
/ size
);
232 list
->oldx
= ((value
- handle
->dev
->absmin
[ABS_X
]));
237 size
= handle
->dev
->absmax
[ABS_Y
] - handle
->dev
->absmin
[ABS_Y
];
239 list
->oldy
= ((value
- handle
->dev
->absmin
[ABS_Y
]) * yres
/ size
);
241 list
->oldy
= ((value
- handle
->dev
->absmin
[ABS_Y
]));
244 list
->pendown
= ((value
> handle
->dev
-> absmin
[ABS_PRESSURE
])) ?
245 value
- handle
->dev
->absmin
[ABS_PRESSURE
] : 0;
258 else if (list
->oldx
> xres
)
267 else if (list
->oldy
> xres
)
274 if (code
== BTN_TOUCH
|| code
== BTN_MOUSE
) {
290 do_gettimeofday(&time
);
291 list
->event
[list
->head
].millisecs
= time
.tv_usec
/ 100;
292 list
->event
[list
->head
].pressure
= list
->pendown
;
293 list
->event
[list
->head
].x
= list
->oldx
;
294 list
->event
[list
->head
].y
= list
->oldy
;
295 list
->head
= (list
->head
+ 1) & (TSDEV_BUFFER_SIZE
- 1);
296 kill_fasync(&list
->fasync
, SIGIO
, POLL_IN
);
298 wake_up_interruptible(&tsdev
->wait
);
301 static struct input_handle
*tsdev_connect(struct input_handler
*handler
,
302 struct input_dev
*dev
,
303 struct input_device_id
*id
)
308 for (minor
= 0; minor
< TSDEV_MINORS
&& tsdev_table
[minor
];
310 if (minor
== TSDEV_MINORS
) {
312 "tsdev: You have way too many touchscreens\n");
316 if (!(tsdev
= kmalloc(sizeof(struct tsdev
), GFP_KERNEL
)))
318 memset(tsdev
, 0, sizeof(struct tsdev
));
320 INIT_LIST_HEAD(&tsdev
->list
);
321 init_waitqueue_head(&tsdev
->wait
);
323 sprintf(tsdev
->name
, "ts%d", minor
);
326 tsdev
->minor
= minor
;
327 tsdev
->handle
.dev
= dev
;
328 tsdev
->handle
.name
= tsdev
->name
;
329 tsdev
->handle
.handler
= handler
;
330 tsdev
->handle
.private = tsdev
;
332 tsdev_table
[minor
] = tsdev
;
334 devfs_mk_cdev(MKDEV(INPUT_MAJOR
, TSDEV_MINOR_BASE
+ minor
),
335 S_IFCHR
|S_IRUGO
|S_IWUSR
, "input/ts%d", minor
);
337 return &tsdev
->handle
;
340 static void tsdev_disconnect(struct input_handle
*handle
)
342 struct tsdev
*tsdev
= handle
->private;
347 input_close_device(handle
);
348 wake_up_interruptible(&tsdev
->wait
);
353 static struct input_device_id tsdev_ids
[] = {
355 .flags
= INPUT_DEVICE_ID_MATCH_EVBIT
| INPUT_DEVICE_ID_MATCH_KEYBIT
| INPUT_DEVICE_ID_MATCH_RELBIT
,
356 .evbit
= { BIT(EV_KEY
) | BIT(EV_REL
) },
357 .keybit
= { [LONG(BTN_LEFT
)] = BIT(BTN_LEFT
) },
358 .relbit
= { BIT(REL_X
) | BIT(REL_Y
) },
359 },/* A mouse like device, at least one button, two relative axes */
362 .flags
= INPUT_DEVICE_ID_MATCH_EVBIT
| INPUT_DEVICE_ID_MATCH_KEYBIT
| INPUT_DEVICE_ID_MATCH_ABSBIT
,
363 .evbit
= { BIT(EV_KEY
) | BIT(EV_ABS
) },
364 .keybit
= { [LONG(BTN_TOUCH
)] = BIT(BTN_TOUCH
) },
365 .absbit
= { BIT(ABS_X
) | BIT(ABS_Y
) },
366 },/* A tablet like device, at least touch detection, two absolute axes */
368 {},/* Terminating entry */
371 MODULE_DEVICE_TABLE(input
, tsdev_ids
);
373 static struct input_handler tsdev_handler
= {
374 .event
= tsdev_event
,
375 .connect
= tsdev_connect
,
376 .disconnect
= tsdev_disconnect
,
378 .minor
= TSDEV_MINOR_BASE
,
380 .id_table
= tsdev_ids
,
383 static int __init
tsdev_init(void)
385 input_register_handler(&tsdev_handler
);
386 printk(KERN_INFO
"ts: Compaq touchscreen protocol output\n");
390 static void __exit
tsdev_exit(void)
392 input_unregister_handler(&tsdev_handler
);
395 module_init(tsdev_init
);
396 module_exit(tsdev_exit
);
398 MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
399 MODULE_DESCRIPTION("Input driver to touchscreen converter");
400 MODULE_PARM(xres
, "i");
401 MODULE_PARM_DESC(xres
, "Horizontal screen resolution");
402 MODULE_PARM(yres
, "i");
403 MODULE_PARM_DESC(yres
, "Vertical screen resolution");