1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32#include <asm/io.h>
33#include <asm/system.h>
34#include <asm/segment.h>
35#include <linux/delay.h>
36#include <linux/errno.h>
37#include <linux/joystick.h>
38#include <linux/input.h>
39#include <linux/kernel.h>
40#include <linux/major.h>
41#include <linux/slab.h>
42#include <linux/mm.h>
43#include <linux/miscdevice.h>
44#include <linux/module.h>
45#include <linux/poll.h>
46#include <linux/init.h>
47#include <linux/smp_lock.h>
48
49#define JOYDEV_MINOR_BASE 0
50#define JOYDEV_MINORS 32
51#define JOYDEV_BUFFER_SIZE 64
52
53#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
54
55struct joydev {
56 int exist;
57 int open;
58 int minor;
59 struct input_handle handle;
60 wait_queue_head_t wait;
61 devfs_handle_t devfs;
62 struct joydev *next;
63 struct joydev_list *list;
64 struct js_corr corr[ABS_MAX];
65 struct JS_DATA_SAVE_TYPE glue;
66 int nabs;
67 int nkey;
68 __u16 keymap[KEY_MAX - BTN_MISC];
69 __u16 keypam[KEY_MAX - BTN_MISC];
70 __u8 absmap[ABS_MAX];
71 __u8 abspam[ABS_MAX];
72 __s16 abs[ABS_MAX];
73};
74
75struct joydev_list {
76 struct js_event buffer[JOYDEV_BUFFER_SIZE];
77 int head;
78 int tail;
79 int startup;
80 struct fasync_struct *fasync;
81 struct joydev *joydev;
82 struct joydev_list *next;
83};
84
85static struct joydev *joydev_table[JOYDEV_MINORS];
86
87MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
88MODULE_DESCRIPTION("Joystick device driver");
89MODULE_LICENSE("GPL");
90MODULE_SUPPORTED_DEVICE("input/js");
91
92static int joydev_correct(int value, struct js_corr *corr)
93{
94 switch (corr->type) {
95 case JS_CORR_NONE:
96 break;
97 case JS_CORR_BROKEN:
98 value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
99 ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
100 ((corr->coef[2] * (value - corr->coef[0])) >> 14);
101 break;
102 default:
103 return 0;
104 }
105
106 if (value < -32767) return -32767;
107 if (value > 32767) return 32767;
108
109 return value;
110}
111
112static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
113{
114 struct joydev *joydev = handle->private;
115 struct joydev_list *list = joydev->list;
116 struct js_event event;
117
118 switch (type) {
119
120 case EV_KEY:
121 if (code < BTN_MISC || value == 2) return;
122 event.type = JS_EVENT_BUTTON;
123 event.number = joydev->keymap[code - BTN_MISC];
124 event.value = value;
125 break;
126
127 case EV_ABS:
128 event.type = JS_EVENT_AXIS;
129 event.number = joydev->absmap[code];
130 event.value = joydev_correct(value, joydev->corr + event.number);
131 if (event.value == joydev->abs[event.number]) return;
132 joydev->abs[event.number] = event.value;
133 break;
134
135 default:
136 return;
137 }
138
139 event.time = MSECS(jiffies);
140
141 while (list) {
142
143 memcpy(list->buffer + list->head, &event, sizeof(struct js_event));
144
145 if (list->startup == joydev->nabs + joydev->nkey)
146 if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
147 list->startup = 0;
148
149 kill_fasync(&list->fasync, SIGIO, POLL_IN);
150
151 list = list->next;
152 }
153
154 wake_up_interruptible(&joydev->wait);
155}
156
157static int joydev_fasync(int fd, struct file *file, int on)
158{
159 int retval;
160 struct joydev_list *list = file->private_data;
161 retval = fasync_helper(fd, file, on, &list->fasync);
162 return retval < 0 ? retval : 0;
163}
164
165static int joydev_release(struct inode * inode, struct file * file)
166{
167 struct joydev_list *list = file->private_data;
168 struct joydev_list **listptr;
169
170 lock_kernel();
171 listptr = &list->joydev->list;
172 joydev_fasync(-1, file, 0);
173
174 while (*listptr && (*listptr != list))
175 listptr = &((*listptr)->next);
176 *listptr = (*listptr)->next;
177
178 if (!--list->joydev->open) {
179 if (list->joydev->exist) {
180 input_close_device(&list->joydev->handle);
181 } else {
182 input_unregister_minor(list->joydev->devfs);
183 joydev_table[list->joydev->minor] = NULL;
184 kfree(list->joydev);
185 }
186 }
187
188 kfree(list);
189 unlock_kernel();
190
191 return 0;
192}
193
194static int joydev_open(struct inode *inode, struct file *file)
195{
196 struct joydev_list *list;
197 int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE;
198
199 if (i >= JOYDEV_MINORS || !joydev_table[i])
200 return -ENODEV;
201
202 if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL)))
203 return -ENOMEM;
204 memset(list, 0, sizeof(struct joydev_list));
205
206 list->joydev = joydev_table[i];
207 list->next = joydev_table[i]->list;
208 joydev_table[i]->list = list;
209
210 file->private_data = list;
211
212 if (!list->joydev->open++)
213 if (list->joydev->exist)
214 input_open_device(&list->joydev->handle);
215
216 return 0;
217}
218
219static ssize_t joydev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
220{
221 return -EINVAL;
222}
223
224static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *ppos)
225{
226 DECLARE_WAITQUEUE(wait, current);
227 struct joydev_list *list = file->private_data;
228 struct joydev *joydev = list->joydev;
229 struct input_dev *input = joydev->handle.dev;
230 int retval = 0;
231
232 if (count < sizeof(struct js_event))
233 return -EINVAL;
234
235 if (!joydev->exist)
236 return -ENODEV;
237
238 if (count == sizeof(struct JS_DATA_TYPE)) {
239
240 struct JS_DATA_TYPE data;
241 int i;
242
243 for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
244 data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
245 data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
246 data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
247
248 if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
249 return -EFAULT;
250
251 list->startup = 0;
252 list->tail = list->head;
253
254 return sizeof(struct JS_DATA_TYPE);
255 }
256
257 if (list->head == list->tail && list->startup == joydev->nabs + joydev->nkey) {
258
259 add_wait_queue(&list->joydev->wait, &wait);
260 current->state = TASK_INTERRUPTIBLE;
261
262 while (list->head == list->tail) {
263
264 if (!joydev->exist) {
265 retval = -ENODEV;
266 break;
267 }
268 if (file->f_flags & O_NONBLOCK) {
269 retval = -EAGAIN;
270 break;
271 }
272 if (signal_pending(current)) {
273 retval = -ERESTARTSYS;
274 break;
275 }
276
277 schedule();
278 }
279
280 current->state = TASK_RUNNING;
281 remove_wait_queue(&list->joydev->wait, &wait);
282 }
283
284 if (retval)
285 return retval;
286
287 while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
288
289 struct js_event event;
290
291 event.time = MSECS(jiffies);
292
293 if (list->startup < joydev->nkey) {
294 event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
295 event.number = list->startup;
296 event.value = !!test_bit(joydev->keypam[event.number], input->key);
297 } else {
298 event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
299 event.number = list->startup - joydev->nkey;
300 event.value = joydev->abs[event.number];
301 }
302
303 if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
304 return -EFAULT;
305
306 list->startup++;
307 retval += sizeof(struct js_event);
308 }
309
310 while (list->head != list->tail && retval + sizeof(struct js_event) <= count) {
311
312 if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event)))
313 return -EFAULT;
314
315 list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
316 retval += sizeof(struct js_event);
317 }
318
319 return retval;
320}
321
322
323static unsigned int joydev_poll(struct file *file, poll_table *wait)
324{
325 struct joydev_list *list = file->private_data;
326 poll_wait(file, &list->joydev->wait, wait);
327 if (list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey)
328 return POLLIN | POLLRDNORM;
329 return 0;
330}
331
332static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
333{
334 struct joydev_list *list = file->private_data;
335 struct joydev *joydev = list->joydev;
336 struct input_dev *dev = joydev->handle.dev;
337 int i;
338
339 if (!joydev->exist)
340 return -ENODEV;
341
342 switch (cmd) {
343
344 case JS_SET_CAL:
345 return copy_from_user(&joydev->glue.JS_CORR, (struct JS_DATA_TYPE *) arg,
346 sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
347 case JS_GET_CAL:
348 return copy_to_user((struct JS_DATA_TYPE *) arg, &joydev->glue.JS_CORR,
349 sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
350 case JS_SET_TIMEOUT:
351 return get_user(joydev->glue.JS_TIMEOUT, (int *) arg);
352 case JS_GET_TIMEOUT:
353 return put_user(joydev->glue.JS_TIMEOUT, (int *) arg);
354 case JS_SET_TIMELIMIT:
355 return get_user(joydev->glue.JS_TIMELIMIT, (long *) arg);
356 case JS_GET_TIMELIMIT:
357 return put_user(joydev->glue.JS_TIMELIMIT, (long *) arg);
358 case JS_SET_ALL:
359 return copy_from_user(&joydev->glue, (struct JS_DATA_SAVE_TYPE *) arg,
360 sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
361 case JS_GET_ALL:
362 return copy_to_user((struct JS_DATA_SAVE_TYPE *) arg, &joydev->glue,
363 sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
364
365 case JSIOCGVERSION:
366 return put_user(JS_VERSION, (__u32 *) arg);
367 case JSIOCGAXES:
368 return put_user(joydev->nabs, (__u8 *) arg);
369 case JSIOCGBUTTONS:
370 return put_user(joydev->nkey, (__u8 *) arg);
371 case JSIOCSCORR:
372 return copy_from_user(joydev->corr, (struct js_corr *) arg,
373 sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
374 case JSIOCGCORR:
375 return copy_to_user((struct js_corr *) arg, joydev->corr,
376 sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
377 case JSIOCSAXMAP:
378 if (copy_from_user(joydev->abspam, (__u8 *) arg, sizeof(__u8) * ABS_MAX))
379 return -EFAULT;
380 for (i = 0; i < joydev->nabs; i++) {
381 if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
382 joydev->absmap[joydev->abspam[i]] = i;
383 }
384 return 0;
385 case JSIOCGAXMAP:
386 return copy_to_user((__u8 *) arg, joydev->abspam,
387 sizeof(__u8) * ABS_MAX) ? -EFAULT : 0;
388 case JSIOCSBTNMAP:
389 if (copy_from_user(joydev->keypam, (__u16 *) arg, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
390 return -EFAULT;
391 for (i = 0; i < joydev->nkey; i++) {
392 if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
393 joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
394 }
395 return 0;
396 case JSIOCGBTNMAP:
397 return copy_to_user((__u16 *) arg, joydev->keypam,
398 sizeof(__u16) * (KEY_MAX - BTN_MISC)) ? -EFAULT : 0;
399 default:
400 if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
401 int len;
402 if (!dev->name) return 0;
403 len = strlen(dev->name) + 1;
404 if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
405 if (copy_to_user((char *) arg, dev->name, len)) return -EFAULT;
406 return len;
407 }
408 }
409 return -EINVAL;
410}
411
412static struct file_operations joydev_fops = {
413 owner: THIS_MODULE,
414 read: joydev_read,
415 write: joydev_write,
416 poll: joydev_poll,
417 open: joydev_open,
418 release: joydev_release,
419 ioctl: joydev_ioctl,
420 fasync: joydev_fasync,
421};
422
423static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev)
424{
425 struct joydev *joydev;
426 int i, j, t, minor;
427
428 if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) &&
429 (test_bit(ABS_X, dev->absbit) || test_bit(ABS_Y, dev->absbit)) &&
430 (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit)
431 || test_bit(BTN_1, dev->keybit)))) return NULL;
432
433 for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
434 if (minor == JOYDEV_MINORS) {
435 printk(KERN_ERR "joydev: no more free joydev devices\n");
436 return NULL;
437 }
438
439 if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL)))
440 return NULL;
441 memset(joydev, 0, sizeof(struct joydev));
442
443 init_waitqueue_head(&joydev->wait);
444
445 joydev->minor = minor;
446 joydev_table[minor] = joydev;
447
448 joydev->handle.dev = dev;
449 joydev->handle.handler = handler;
450 joydev->handle.private = joydev;
451
452 joydev->exist = 1;
453
454 for (i = 0; i < ABS_MAX; i++)
455 if (test_bit(i, dev->absbit)) {
456 joydev->absmap[i] = joydev->nabs;
457 joydev->abspam[joydev->nabs] = i;
458 joydev->nabs++;
459 }
460
461 for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC; i++)
462 if (test_bit(i + BTN_MISC, dev->keybit)) {
463 joydev->keymap[i] = joydev->nkey;
464 joydev->keypam[joydev->nkey] = i + BTN_MISC;
465 joydev->nkey++;
466 }
467
468 for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++)
469 if (test_bit(i + BTN_MISC, dev->keybit)) {
470 joydev->keymap[i] = joydev->nkey;
471 joydev->keypam[joydev->nkey] = i + BTN_MISC;
472 joydev->nkey++;
473 }
474
475 for (i = 0; i < joydev->nabs; i++) {
476 j = joydev->abspam[i];
477 if (dev->absmax[j] == dev->absmin[j]) {
478 joydev->corr[i].type = JS_CORR_NONE;
479 continue;
480 }
481 joydev->corr[i].type = JS_CORR_BROKEN;
482 joydev->corr[i].prec = dev->absfuzz[j];
483 joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
484 joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
485 if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j])))
486 continue;
487 joydev->corr[i].coef[2] = (1 << 29) / t;
488 joydev->corr[i].coef[3] = (1 << 29) / t;
489
490 joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
491 }
492
493 joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE);
494
495
496
497 return &joydev->handle;
498}
499
500static void joydev_disconnect(struct input_handle *handle)
501{
502 struct joydev *joydev = handle->private;
503
504 joydev->exist = 0;
505
506 if (joydev->open) {
507 input_close_device(handle);
508 } else {
509 input_unregister_minor(joydev->devfs);
510 joydev_table[joydev->minor] = NULL;
511 kfree(joydev);
512 }
513}
514
515static struct input_handler joydev_handler = {
516 event: joydev_event,
517 connect: joydev_connect,
518 disconnect: joydev_disconnect,
519 fops: &joydev_fops,
520 minor: JOYDEV_MINOR_BASE,
521};
522
523static int __init joydev_init(void)
524{
525 input_register_handler(&joydev_handler);
526 return 0;
527}
528
529static void __exit joydev_exit(void)
530{
531 input_unregister_handler(&joydev_handler);
532}
533
534module_init(joydev_init);
535module_exit(joydev_exit);
536