summaryrefslogtreecommitdiffstats
path: root/drivers/char/joystick.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-01-04 16:03:48 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-01-04 16:03:48 +0000
commit78c388aed2b7184182c08428db1de6c872d815f5 (patch)
tree4b2003b1b4ceb241a17faa995da8dd1004bb8e45 /drivers/char/joystick.c
parenteb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (diff)
Merge with Linux 2.1.131 and more MIPS goodies.
(Did I mention that CVS is buggy ...)
Diffstat (limited to 'drivers/char/joystick.c')
-rw-r--r--drivers/char/joystick.c861
1 files changed, 0 insertions, 861 deletions
diff --git a/drivers/char/joystick.c b/drivers/char/joystick.c
deleted file mode 100644
index 4f940f4d5..000000000
--- a/drivers/char/joystick.c
+++ /dev/null
@@ -1,861 +0,0 @@
-/*
- * linux/drivers/char/joystick.c Version 1.0.9
- * Copyright (C) 1996-1998 Vojtech Pavlik
- */
-
-/*
- * This is joystick driver for Linux. It supports up to two analog joysticks
- * on a PC compatible machine. See Documentation/joystick.txt for changelog
- * and credits.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/malloc.h>
-#include <linux/poll.h>
-#include <linux/major.h>
-#include <linux/joystick.h>
-#include <asm/io.h>
-
-#define PIT_HZ 1193180L /* PIT clock is 1.19318 MHz */
-
-#define JS_MAXTIME PIT_HZ/250 /* timeout for read (4 ms) */
-
-#define JS_TIMER_PERIOD HZ/50 /* button valid time (20 ms) */
-#define JS_BH_MIN_PERIOD HZ/25 /* axis min valid time (40 ms) */
-#define JS_BH_MAX_PERIOD HZ/25*2 /* axis max valid time (80 ms) */
-
-#define JS_FIFO_SIZE 16 /* number of FIFO entries */
-#define JS_BUFF_SIZE 32 /* output buffer size */
-#define JS_RETRIES 4 /* number of retries */
-#define JS_DEF_PREC 16 /* initial precision for all axes */
-
-#define JS_NUM 2 /* number of joysticks */
-
-#define JS_AXES 0x0f /* bit mask for all axes */
-#define JS_BUTTONS 0xf0 /* bit mask for all buttons */
-
-#define PIT_MODE 0x43 /* timer mode port */
-#define PIT_DATA 0x40 /* timer 0 data port */
-#define JS_PORT 0x201 /* joystick port */
-
-#define JS_TRIGGER 0xff /* triggers one-shots */
-#define PIT_READ_TIMER 0x00 /* to read timer 0 */
-
-#define DELTA(X,Y,Z) ((X)-(Y)+(((X)>=(Y))?0:Z)) /* cyclic delta */
-#define DELTA_T(X,Y) DELTA((X),(Y),(PIT_HZ/HZ)) /* for time measurement */
-#define DELTA_TX(X,Y,Z) DELTA_T((X),((Y)&0xFF)|(((Z)&0xFF)<<8))
-#define ROT(A,B,C) ((((A)<(C))&&(((B)>(A))&&((B)<(C))))||(((A)>(C))&&(((B)>(A))||((B)<(C)))))
-#define GOF(X) (((X)==JS_BUFF_SIZE-1)?0:(X)+1)
-#define GOFF(X) (((X)==JS_FIFO_SIZE-1)?0:(X)+1)
-#define GOB(X) ((X)?(X)-1:JS_BUFF_SIZE-1)
-
-struct js_data {
- int ahead;
- int bhead;
- int tail;
- struct js_event buff[JS_BUFF_SIZE];
- struct js_list *list;
- struct wait_queue *wait;
- unsigned int exist;
-};
-
-struct js_axis {
- int value;
- struct js_corr corr;
-};
-
-struct js_list {
- struct js_list *next; /* next-in-list pointer */
- unsigned long time; /* when the device was open */
- int tail; /* a tail for js_buff */
- char startup;
-};
-
-struct js_fifo {
- unsigned long time;
- unsigned long event;
-};
-
-static struct js_data jsd[JS_NUM]; /* joystick data */
-static struct timer_list js_timer; /* joystick timer */
-
-static unsigned char js_fifo_head = 0; /* head of the fifo */
-static unsigned char js_fifo_tail = JS_FIFO_SIZE - 1; /* tail of the fifo */
-static struct js_fifo js_fifo[JS_FIFO_SIZE]; /* the fifo */
-
-static unsigned char js_last_buttons = 0; /* last read button state */
-static unsigned long js_bh_time = 0; /* last read axis time */
-static unsigned long js_mark_time = 0;
-
-static unsigned char js_axes_exist; /* all axes that exist */
-static unsigned char js_buttons_exist; /* all buttons that exist */
-
-static struct js_axis js_axis[4];
-static unsigned int js_buttons = 0;
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@atrey.karlin.mff.cuni.cz>");
-MODULE_SUPPORTED_DEVICE("js");
-MODULE_PARM(js, "1-2b");
-
-static char js[] = {0, 0};
-
-/*
- * get_pit() returns the immediate state of PIT0. Must be run
- * with interrupts disabled.
- */
-
-static inline int get_pit(void)
-{
- int t, flags;
-
- save_flags(flags);
- cli();
- outb(PIT_READ_TIMER, PIT_MODE);
- t = inb(PIT_DATA);
- t |= (int) inb(PIT_DATA) << 8;
- restore_flags(flags);
- return t;
-}
-
-/*
- * count_bits() counts set bits in a byte.
- */
-
-static int count_bits(unsigned int c)
-{
- int i = 0;
- while (c) {
- i += c & 1;
- c >>= 1;
- }
- return i;
-}
-
-/*
- * js_correct() performs correction of raw joystick data.
- */
-
-static int js_correct(int value, struct js_corr *corr)
-{
- int t;
-
- if (corr->type == JS_CORR_NONE) return value;
- t = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : value - corr->coef[1]) : value - corr->coef[0];
-
- switch (corr->type) {
- case JS_CORR_BROKEN:
- t = t < 0 ? ((corr->coef[2] * t) >> 14) : ((corr->coef[3] * t) >> 14);
- break;
- default:
- return 0;
- }
-
- if (t < -32767) return -32767;
- if (t > 32767) return 32767;
-
- return t;
-}
-
-/*
- * js_compare() compares two close axis values and decides
- * whether they are "same".
- */
-
-static int js_compare(int x, int y, int prec)
-{
- return (x < y + prec) && (y < x + prec);
-}
-
-/*
- * js_probe() probes for joysticks
- */
-
-inline int js_probe(void)
-{
- int t;
-
- outb(JS_TRIGGER, JS_PORT);
- t = get_pit();
- while (DELTA_T(t, get_pit()) < JS_MAXTIME);
- t = inb(JS_PORT);
-
- if (js[0] || js[1]) {
- jsd[0].exist = js[0] & ~(t & JS_AXES);
- jsd[1].exist = js[1] & ~(t & JS_AXES);
- } else
- switch (t & JS_AXES) {
- case 0x0c: jsd[0].exist = 0x33; jsd[1].exist = 0x00; break; /* joystick 0 connected */
- case 0x03: jsd[0].exist = 0xcc; jsd[1].exist = 0x00; break; /* joystick 1 connected */
- case 0x04: jsd[0].exist = 0xfb; jsd[1].exist = 0x00; break; /* 3-axis joystick connected */
- case 0x00: jsd[0].exist = 0x33; jsd[1].exist = 0xcc; break; /* joysticks 0 and 1 connected */
- default: jsd[0].exist = 0x00; jsd[1].exist = 0x00; return -1; /* no joysticks */
- }
-
- js_axes_exist = (jsd[0].exist | jsd[1].exist) & JS_AXES;
- js_buttons_exist = (jsd[0].exist | jsd[1].exist) & JS_BUTTONS;
-
- return 0;
-}
-
-/*
- * js_do_timer() controls the action by adding entries to the event
- * fifo each time a button changes its state or axis valid time
- * expires.
- */
-
-static void js_do_timer(unsigned long data)
-{
- int t = ~inb(JS_PORT) & js_buttons_exist;
- if ((js_last_buttons != t) && (js_fifo_head != js_fifo_tail)) {
- js_fifo[js_fifo_head].event = js_last_buttons = t;
- js_fifo[js_fifo_head].time = jiffies;
- js_fifo_head++;
- if (js_fifo_head == JS_FIFO_SIZE) js_fifo_head = 0;
- if (!js_mark_time) {
- js_mark_time = jiffies;
- mark_bh(JS_BH);
- }
- }
- else
- if ((jiffies > js_bh_time + JS_BH_MAX_PERIOD) && !js_mark_time) {
- js_mark_time = jiffies;
- mark_bh(JS_BH);
- }
- js_timer.expires = jiffies + JS_TIMER_PERIOD;
- add_timer(&js_timer);
-}
-
-
-/*
- * Put an event in the buffer. This requires additional queue processing
- * done by js_sync_buff, otherwise the buffer will be corrupted.
- */
-
-static void js_add_event(int i, __u32 time, __u8 type, __u8 number, __u16 value)
-{
- int ahead = jsd[i].ahead++;
- jsd[i].buff[ahead].time = time;
- jsd[i].buff[ahead].type = type;
- jsd[i].buff[ahead].number = number;
- jsd[i].buff[ahead].value = value;
- if (jsd[i].ahead == JS_BUFF_SIZE) jsd[i].ahead=0;
-}
-
-/*
- * This checks for all owerflows caused by recent additions to the buffer.
- * It does anything only if some processes are reading the data too slowly.
- */
-
-static void js_sync_buff(void)
-{
- int i;
-
- for (i = 0; i < JS_NUM; i++)
- if (jsd[i].list)
- if (jsd[i].bhead != jsd[i].ahead) {
- if (ROT(jsd[i].bhead, jsd[i].tail, jsd[i].ahead) || (jsd[i].tail == jsd[i].bhead)) {
- struct js_list *curl;
- curl = jsd[i].list;
- while (curl) {
- if (ROT(jsd[i].bhead, curl->tail, jsd[i].ahead) || (curl->tail == jsd[i].bhead)) {
- curl->tail = jsd[i].ahead;
- curl->startup = jsd[i].exist;
- }
- curl = curl->next;
- }
- jsd[i].tail = jsd[i].ahead;
- }
- jsd[i].bhead = jsd[i].ahead;
- wake_up_interruptible(&jsd[i].wait);
- }
-}
-
-/*
- * js_do_bh() does the main processing and adds events to output buffers.
- */
-
-static void js_do_bh(void)
-{
-
- int i, j, k;
- unsigned int t;
-
- if (jiffies > js_bh_time + JS_BH_MIN_PERIOD) {
-
- unsigned int old_axis[4];
- unsigned int t_low, t_high;
- unsigned int flags, joy_state;
- unsigned int t1l, t1h, jsm;
- unsigned char jss;
- unsigned char again;
- unsigned char retries = 0;
-
- for (i = 0; i < 4; i++)
- old_axis[i] = js_axis[i].value;
-
- do {
- i = 0;
- again = 0;
- t_low = 0;
- t_high = 0;
- joy_state = JS_AXES;
-
-/*
- * Measure the axes.
- */
-
- save_flags(flags);
- cli(); /* no interrupts */
- outb(JS_TRIGGER, JS_PORT); /* trigger one-shots */
- outb(PIT_READ_TIMER, PIT_MODE); /* read timer */
- t = (t1l = inb(PIT_DATA)) |
- (t1h = inb(PIT_DATA)) << 8;
- restore_flags(flags);
-
- do {
- jss = inb(JS_PORT);
- if ((jss ^ joy_state) & js_axes_exist) {
- t_low = (t_low << 8) | t1l;
- t_high = (t_high << 8) | t1h;
- joy_state = (joy_state << 8) | jss;
- i++;
- }
-
- cli();
- outb(PIT_READ_TIMER, PIT_MODE);
- t1l = inb(PIT_DATA);
- t1h = inb(PIT_DATA);
- restore_flags(flags);
-
- } while ((jss & js_axes_exist) && (DELTA_TX(t, t1l, t1h) < JS_MAXTIME));
-
-/*
- * Process the gathered axis data in joy_state.
- */
-
- joy_state ^= ((joy_state >> 8) | 0xff000000L); /* More magic */
-
- for (; i > 0; i--) {
- for (j = 0; j < 4; j++)
- if (joy_state & js_axes_exist & (1 << j)) {
- jsm = DELTA_TX(t, t_low, t_high);
- if (!js_compare(jsm, js_axis[j].value, js_axis[j].corr.prec)) {
- if (jsm < js_axis[j].value || !retries)
- js_axis[j].value = jsm;
- again = 1;
- }
- }
- joy_state = joy_state >> 8;
- t_low = t_low >> 8;
- t_high = t_high >> 8;
- }
-
- } while (retries++ < JS_RETRIES && again);
-
-/*
- * Check if joystick lost.
- */
-
- for (i = 0; i < JS_NUM; i++) {
-
- if (jsd[i].exist && ((jss & jsd[i].exist & JS_AXES) == (jsd[i].exist & JS_AXES))) {
- printk(KERN_WARNING "js%d: joystick lost.\n", i);
- js_buttons_exist &= ~jsd[i].exist;
- js_axes_exist &= ~jsd[i].exist;
- jsd[i].exist = 0;
- wake_up_interruptible(&jsd[i].wait);
- }
-
- if ((jss & jsd[i].exist & JS_AXES)) {
- printk(KERN_WARNING "js%d: joystick broken. Check cables.\n", i);
- }
-
- }
-
-/*
- * Put changed axes into output buffer.
- */
-
- if (retries > 1)
- for (i = 0; i < JS_NUM; i++)
- if (jsd[i].list) {
- k = 0;
- for (j = 0; j < 4; j++)
- if ((1 << j) & jsd[i].exist) {
- if ((t = js_correct(js_axis[j].value, &js_axis[j].corr)) !=
- js_correct(old_axis[j], &js_axis[j].corr))
- js_add_event(i, js_mark_time, JS_EVENT_AXIS, k, t);
- k++;
- }
- }
- js_bh_time = jiffies;
- }
- js_mark_time = 0;
-
-/*
- * And now process the button fifo.
- */
-
- while (js_fifo_head != (t = GOFF(js_fifo_tail))) {
- for (i = 0; i < JS_NUM; i++)
- if (jsd[i].list) {
- k = 0;
- for (j = 4; j < 8; j++)
- if ((1 << j) & jsd[i].exist) {
- if ((1 << j) & (js_buttons ^ js_fifo[t].event))
- js_add_event(i, js_fifo[t].time, JS_EVENT_BUTTON, k, (js_fifo[t].event >> j) & 1);
- k++;
- }
- }
- js_buttons = js_fifo[js_fifo_tail = t].event;
- }
-
-/*
- * Synchronize the buffer.
- */
-
- js_sync_buff();
-
-}
-
-/*
- * js_lseek() just returns with error.
- */
-
-static loff_t js_lseek(struct file *file, loff_t offset, int origin)
-{
- return -ESPIPE;
-}
-
-/*
- * js_read() copies one or more entries from jsd[].buff to user
- * space.
- */
-
-static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-{
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
- struct wait_queue wait = { current, NULL };
- struct js_list *curl = file->private_data;
- struct js_event *buff = (void *) buf;
- unsigned long blocks = count / sizeof(struct js_event);
- unsigned long i = 0, j;
- int t, u = curl->tail;
- int retval = 0;
-
-/*
- * Check user data.
- */
-
- if (MAJOR(file->f_dentry->d_inode->i_rdev) != JOYSTICK_MAJOR)
- return -EINVAL;
- if (file->f_pos < 0)
- return -EINVAL;
- if (!blocks)
- return -EINVAL;
- if (!curl)
- return -EINVAL;
-
- if (minor > JS_NUM)
- return -ENODEV;
- if (!jsd[minor].exist)
- return -ENODEV;
-
-/*
- * Handle (non)blocking i/o.
- */
-
-
- if ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup && count != sizeof(struct JS_DATA_TYPE))
- || (curl->startup && !js_bh_time)) {
-
- add_wait_queue(&jsd[minor].wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- while ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup && count != sizeof(struct JS_DATA_TYPE))
- || (curl->startup && !js_bh_time)) {
-
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- schedule();
- if (!jsd[minor].exist) {
- retval = -ENODEV;
- break;
- }
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&jsd[minor].wait, &wait);
- }
-
- if (retval) return retval;
-
-/*
- * Do the i/o.
- */
- if (count != sizeof(struct JS_DATA_TYPE)) {
-
- if (curl->startup) {
- struct js_event tmpevent;
-/*
- * Initial button state.
- */
-
- t = 0;
- for (j = 0; j < 4 && (i < blocks) && !retval; j++)
- if (jsd[minor].exist & (1 << j)) {
- if (curl->startup & (1 << j)) {
- tmpevent.type = JS_EVENT_AXIS | JS_EVENT_INIT;
- tmpevent.number = t;
- tmpevent.value = js_correct(js_axis[j].value, &js_axis[j].corr);
- if (copy_to_user(&buff[i], &tmpevent, sizeof(struct js_event)))
- retval = -EFAULT;
- if (put_user((__u32)((jiffies - curl->time) * (1000/HZ)), &buff[i].time))
- retval = -EFAULT;
- curl->startup &= ~(1 << j);
- i++;
- }
- t++;
- }
-
-/*
- * Initial axis state.
- */
-
- t = 0;
- for (j = 4; j < 8 && (i < blocks) && !retval; j++)
- if (jsd[minor].exist & (1 << j)) {
- if (curl->startup & (1 << j)) {
- tmpevent.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
- tmpevent.number = t;
- tmpevent.value = (js_buttons >> j) & 1;
- if (copy_to_user(&buff[i], &tmpevent, sizeof(struct js_event)))
- retval = -EFAULT;
- if (put_user((__u32)((jiffies - curl->time) * (1000/HZ)), &buff[i].time))
- retval = -EFAULT;
- curl->startup &= ~(1 << j);
- i++;
- }
- t++;
- }
- }
-
-/*
- * Buffer data.
- */
-
- while ((jsd[minor].ahead != (t = GOF(curl->tail))) && (i < blocks) && !retval) {
- if (copy_to_user(&buff[i], &jsd[minor].buff[t], sizeof(struct js_event)))
- retval = -EFAULT;
- if (put_user((__u32)((jsd[minor].buff[t].time - curl->time) * (1000/HZ)), &buff[i].time))
- retval = -EFAULT;
- curl->tail = t;
- i++;
- }
-
- }
-
- else
-
-/*
- * Handle version 0.x compatibility.
- */
-
- {
- struct JS_DATA_TYPE *bufo = (void *) buf;
- int buttons = 0;
-
- while (~jsd[minor].exist & (1<<i)) i++;
- copy_to_user(&bufo->x, &js_axis[i].value, sizeof(int));
-
- i++;
- while (~jsd[minor].exist & (1<<i)) i++;
- copy_to_user(&bufo->y, &js_axis[i].value, sizeof(int));
-
- i = 0;
- for (j = 4; j < 8; j++)
- if ((1 << j) & jsd[minor].exist)
- buttons |= (!!(js_last_buttons & (1 << j))) << (i++);
- copy_to_user(&bufo->buttons, &buttons, sizeof(int));
-
- curl->startup = 0;
- curl->tail = GOB(jsd[minor].ahead);
- retval = sizeof(struct JS_DATA_TYPE);
- }
-
-/*
- * Check main tail and move it.
- */
-
- if (u == jsd[minor].tail) {
- t = curl->tail;
- curl = jsd[minor].list;
- while (curl && curl->tail != jsd[minor].tail) {
- if (ROT(jsd[minor].ahead, t, curl->tail) ||
- (jsd[minor].ahead == curl->tail)) t = curl->tail;
- curl = curl->next;
- }
- if (!curl) jsd[minor].tail = t;
- }
-
- return retval ? retval : i*sizeof(struct js_event);
-}
-
-/*
- * js_poll() does select() support.
- */
-
-static unsigned int js_poll(struct file *file, poll_table *wait)
-{
- struct js_list *curl;
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
- curl = file->private_data;
-
- poll_wait(file, &jsd[minor].wait, wait);
- if (GOF(curl->tail) != jsd[minor].ahead)
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-/*
- * js_ioctl handles misc ioctl calls.
- */
-
-static int js_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- unsigned int minor = MINOR(inode->i_rdev);
- int i, j;
-
- if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR)
- return -EINVAL;
- if (minor > JS_NUM)
- return -ENODEV;
- if (!jsd[minor].exist)
- return -ENODEV;
-
- switch (cmd) {
- case JSIOCGVERSION:
- if(put_user(JS_VERSION, (__u32 *) arg)) return -EFAULT;
- break;
- case JSIOCGAXES:
- if(put_user(count_bits(jsd[minor].exist & JS_AXES), (__u8 *) arg)) return -EFAULT;
- break;
- case JSIOCGBUTTONS:
- if(put_user(count_bits(jsd[minor].exist & JS_BUTTONS), (__u8 *) arg)) return -EFAULT;
- break;
- case JSIOCSCORR:
- j = 0;
- for (i = 0; i < 4; i++)
- if ((1 << i) & jsd[minor].exist) {
- if (copy_from_user(&js_axis[i].corr, (void *) arg + j * sizeof(struct js_corr),
- sizeof(struct js_corr))) return -EFAULT;
- j++;
- }
- js_bh_time = 0;
- break;
- case JSIOCGCORR:
- j = 0;
- for (i = 0; i < 4; i++)
- if ((1 << i) & jsd[minor].exist) {
- if (copy_to_user((void *) arg + j * sizeof(struct js_corr), &js_axis[i].corr,
- sizeof(struct js_corr))) return -EFAULT;
- j++;
- }
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * js_open() performs necessary initialization and adds
- * an entry to the linked list.
- */
-
-static int js_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = MINOR(inode->i_rdev);
- struct js_list *curl;
- int t;
-
- if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR)
- return -EINVAL;
- if (minor > JS_NUM)
- return -ENODEV;
- if (!jsd[minor].exist) {
- js_probe();
- if (jsd[minor].exist) printk(KERN_INFO "js%d: %d-axis %d-button joystick at %#x\n",
- minor, count_bits(jsd[minor].exist & JS_AXES), count_bits(jsd[minor].exist & JS_BUTTONS), JS_PORT);
- else return -ENODEV;
- }
-
- MOD_INC_USE_COUNT;
-
- if (!jsd[0].list && !jsd[1].list) {
- js_timer.expires = jiffies + JS_TIMER_PERIOD;
- add_timer(&js_timer);
- }
-
- curl = jsd[minor].list;
- jsd[minor].list = kmalloc(sizeof(struct js_list), GFP_KERNEL);
- jsd[minor].list->next = curl;
- jsd[minor].list->startup = jsd[minor].exist;
- jsd[minor].list->tail = t = GOB(jsd[minor].ahead);
- jsd[minor].list->time = jiffies;
-
- file->private_data = jsd[minor].list;
-
- return 0;
-}
-
-/*
- * js_release() removes an entry from list and deallocates memory
- * used by it.
- */
-
-static int js_release(struct inode *inode, struct file *file)
-{
- unsigned int minor = MINOR(inode->i_rdev);
- struct js_list **curp, *curl;
- int t;
-
- curp = &jsd[minor].list;
- curl = file->private_data;
-
- while (*curp && (*curp != curl)) curp = &((*curp)->next);
- *curp = (*curp)->next;
-
- if (jsd[minor].list) {
- if (curl->tail == jsd[minor].tail) {
- curl = jsd[minor].list;
- t = curl->tail;
- while (curl && curl->tail != jsd[minor].tail) {
- if (ROT(jsd[minor].ahead, t, curl->tail) ||
- (jsd[minor].ahead == curl->tail)) t = curl->tail;
- curl = curl->next;
- }
- if (!curl) jsd[minor].tail = t;
- }
- }
-
- kfree(file->private_data);
- if (!jsd[0].list && !jsd[1].list) del_timer(&js_timer);
-
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-/*
- * The operations structure.
- */
-
-static struct file_operations js_fops =
-{
- js_lseek, /* js_lseek */
- js_read, /* js_read */
- NULL, /* js_write */
- NULL, /* js_readdir */
- js_poll, /* js_poll */
- js_ioctl, /* js_ioctl */
- NULL, /* js_mmap */
- js_open, /* js_open */
- NULL, /* js_flush */
- js_release, /* js_release */
- NULL /* js_sync */
-};
-
-/*
- * js_setup() parses kernel command line parametres.
- */
-
-#ifndef MODULE
-__initfunc(void js_setup(char *str, int *ints))
-
-{
- js[0] = ((ints[0] > 0) ? ints[1] : 0 );
- js[1] = ((ints[0] > 1) ? ints[2] : 0 );
-}
-#endif
-
-/*
- * js_init() registres the driver and calls the probe function.
- * also initializes some crucial variables.
- */
-
-#ifdef MODULE
-int init_module(void)
-#else
-__initfunc(int js_init(void))
-#endif
-{
- int i;
-
- if (check_region(JS_PORT, 1)) {
- printk(KERN_ERR "js: port %#x already in use\n", JS_PORT);
- return -EBUSY;
- }
-
- if (js_probe() < 0) {
- printk(KERN_INFO "js: no joysticks found\n");
- return -ENODEV;
- }
-
- if (register_chrdev(JOYSTICK_MAJOR, "js", &js_fops)) {
- printk(KERN_ERR "js: unable to get major %d for joystick\n", JOYSTICK_MAJOR);
- return -EBUSY;
- }
-
- for (i = 0; i < JS_NUM; i++) {
- if (jsd[i].exist) printk(KERN_INFO "js%d: %d-axis %d-button joystick at %#x\n",
- i, count_bits(jsd[i].exist & JS_AXES), count_bits(jsd[i].exist & JS_BUTTONS), JS_PORT);
- jsd[i].ahead = jsd[i].bhead = 0;
- jsd[i].tail = JS_BUFF_SIZE - 1;
- jsd[i].list = NULL;
- jsd[i].wait = NULL;
- memset(jsd[i].buff, 0, JS_BUFF_SIZE * sizeof(struct js_event));
- }
-
- for (i = 0; i < 4; i++) {
- js_axis[i].corr.type = JS_CORR_NONE;
- js_axis[i].corr.prec = JS_DEF_PREC;
- }
-
- request_region(JS_PORT, 1, "js");
- init_bh(JS_BH, &js_do_bh);
- enable_bh(JS_BH);
- init_timer(&js_timer);
- js_timer.function = js_do_timer;
-
- return 0;
-}
-
-/*
- * cleanup_module() handles module removal.
- */
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- if (MOD_IN_USE)
- printk(KERN_NOTICE "js: device busy, remove delayed\n");
- else {
- del_timer(&js_timer);
- disable_bh(JS_BH);
- if (unregister_chrdev(JOYSTICK_MAJOR, "js"))
- printk(KERN_ERR "js: module cleanup failed\n");
- release_region(JS_PORT, 1);
- }
-}
-#endif