[PATCH] update copyright and licensing
[linux-2.6/history.git] / drivers / input / tsdev.c
blobd2362bbf6615357b0237c4d10109174bccb9accd
1 /*
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
9 */
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
49 #endif
50 #ifndef CONFIG_INPUT_TSDEV_SCREEN_Y
51 #define CONFIG_INPUT_TSDEV_SCREEN_Y 320
52 #endif
54 struct tsdev {
55 int exist;
56 int open;
57 int minor;
58 char name[16];
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) */
65 typedef struct {
66 short pressure;
67 short x;
68 short y;
69 short millisecs;
70 } TS_EVENT;
72 struct tsdev_list {
73 struct fasync_struct *fasync;
74 struct list_head node;
75 struct tsdev *tsdev;
76 int head, tail;
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;
91 int retval;
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])
103 return -ENODEV;
105 if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
106 return -ENOMEM;
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);
116 return 0;
119 static void tsdev_free(struct tsdev *tsdev)
121 devfs_remove("input/ts%d", tsdev->minor);
122 tsdev_table[tsdev->minor] = NULL;
123 kfree(tsdev);
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);
136 else
137 tsdev_free(list->tsdev);
139 kfree(list);
140 return 0;
143 static ssize_t tsdev_read(struct file *file, char *buffer, size_t count,
144 loff_t * ppos)
146 struct tsdev_list *list = file->private_data;
147 int retval = 0;
149 if (list->head == list->tail && list->tsdev->exist && (file->f_flags & O_NONBLOCK))
150 return -EAGAIN;
152 retval = wait_event_interruptible(list->tsdev->wait,
153 (list->head != list->tail) && list->tsdev->exist);
155 if (retval)
156 return retval;
158 if (!list->tsdev->exist)
159 return -ENODEV;
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)))
163 return -EFAULT;
164 list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
165 retval += sizeof(TS_EVENT);
168 return retval;
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;
179 return 0;
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;
189 int retval;
191 switch (cmd) {
192 case HHEHE:
193 return 0;
194 case hjff:
195 return 0;
196 default:
197 return 0;
200 return -EINVAL;
203 struct file_operations tsdev_fops = {
204 .owner = THIS_MODULE,
205 .open = tsdev_open,
206 .release = tsdev_release,
207 .read = tsdev_read,
208 .poll = tsdev_poll,
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;
218 struct timeval time;
219 int size;
221 list_for_each_entry(list, &tsdev->list, node) {
222 switch (type) {
223 case EV_ABS:
224 switch (code) {
225 case ABS_X:
226 if (!list->pendown)
227 return;
228 size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
229 if (size > 0)
230 list->oldx = ((value - handle->dev->absmin[ABS_X]) * xres / size);
231 else
232 list->oldx = ((value - handle->dev->absmin[ABS_X]));
233 break;
234 case ABS_Y:
235 if (!list->pendown)
236 return;
237 size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
238 if (size > 0)
239 list->oldy = ((value - handle->dev->absmin[ABS_Y]) * yres / size);
240 else
241 list->oldy = ((value - handle->dev->absmin[ABS_Y]));
242 break;
243 case ABS_PRESSURE:
244 list->pendown = ((value > handle->dev-> absmin[ABS_PRESSURE])) ?
245 value - handle->dev->absmin[ABS_PRESSURE] : 0;
246 break;
248 break;
250 case EV_REL:
251 switch (code) {
252 case REL_X:
253 if (!list->pendown)
254 return;
255 list->oldx += value;
256 if (list->oldx < 0)
257 list->oldx = 0;
258 else if (list->oldx > xres)
259 list->oldx = xres;
260 break;
261 case REL_Y:
262 if (!list->pendown)
263 return;
264 list->oldy += value;
265 if (list->oldy < 0)
266 list->oldy = 0;
267 else if (list->oldy > xres)
268 list->oldy = xres;
269 break;
271 break;
273 case EV_KEY:
274 if (code == BTN_TOUCH || code == BTN_MOUSE) {
275 switch (value) {
276 case 0:
277 list->pendown = 0;
278 break;
279 case 1:
280 if (!list->pendown)
281 list->pendown = 1;
282 break;
283 case 2:
284 return;
286 } else
287 return;
288 break;
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)
305 struct tsdev *tsdev;
306 int minor;
308 for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor];
309 minor++);
310 if (minor == TSDEV_MINORS) {
311 printk(KERN_ERR
312 "tsdev: You have way too many touchscreens\n");
313 return NULL;
316 if (!(tsdev = kmalloc(sizeof(struct tsdev), GFP_KERNEL)))
317 return NULL;
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);
325 tsdev->exist = 1;
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;
344 tsdev->exist = 0;
346 if (tsdev->open) {
347 input_close_device(handle);
348 wake_up_interruptible(&tsdev->wait);
349 } else
350 tsdev_free(tsdev);
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,
377 .fops = &tsdev_fops,
378 .minor = TSDEV_MINOR_BASE,
379 .name = "tsdev",
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");
387 return 0;
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");