Import 2.1.118
[davej-history.git] / drivers / char / psaux.c
blobe4a54097bcecc79a31f6312319c839609a46c52f
1 /*
2 * linux/drivers/char/psaux.c
4 * Driver for PS/2 type mouse by Johan Myreen.
6 * Supports pointing devices attached to a PS/2 type
7 * Keyboard and Auxiliary Device Controller.
9 * Corrections in device setup for some laptop mice & trackballs.
10 * 02Feb93 (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca)
12 * Changed to prevent keyboard lockups on AST Power Exec.
13 * 28Jul93 Brad Bosch - brad@lachman.com
15 * Modified by Johan Myreen (jem@pandora.pp.fi) 04Aug93
16 * to include support for QuickPort mouse.
18 * Changed references to "QuickPort" with "82C710" since "QuickPort"
19 * is not what this driver is all about -- QuickPort is just a
20 * connector type, and this driver is for the mouse port on the Chips
21 * & Technologies 82C710 interface chip. 15Nov93 jem@pandora.pp.fi
23 * Added support for SIGIO. 28Jul95 jem@pandora.pp.fi
25 * Rearranged SIGIO support to use code from tty_io. 9Sept95 ctm@ardi.com
27 * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
29 * Fixed keyboard lockups at open time
30 * 3-Jul-96, 22-Aug-96 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
32 * Cleanup by Martin Mares, 01-Jun-97 (now uses the new PC kbd include)
34 * Renamed misc. name to "psaux",more in keeping with Documentation/devices.txt
35 * 13-Jan-1998, Richard Gooch <rgooch@atnf.csiro.au>
38 /* Uncomment the following line if your mouse needs initialization. */
40 /* #define INITIALIZE_DEVICE */
42 #include <linux/module.h>
44 #include <linux/sched.h>
45 #include <linux/kernel.h>
46 #include <linux/interrupt.h>
47 #include <linux/fcntl.h>
48 #include <linux/errno.h>
49 #include <linux/timer.h>
50 #include <linux/malloc.h>
51 #include <linux/miscdevice.h>
52 #include <linux/random.h>
53 #include <linux/poll.h>
54 #include <linux/init.h>
56 #include <asm/io.h>
57 #include <asm/uaccess.h>
58 #include <asm/system.h>
59 #include <asm/semaphore.h>
61 #include <linux/config.h>
63 #include "pc_keyb.h"
66 * Generic declarations for both PS2 and 82C710
69 #define PSMOUSE_MINOR 1 /* Minor device # for this mouse */
70 #define AUX_BUF_SIZE 2048
72 struct aux_queue {
73 unsigned long head;
74 unsigned long tail;
75 struct wait_queue *proc_list;
76 struct fasync_struct *fasync;
77 unsigned char buf[AUX_BUF_SIZE];
80 static struct aux_queue *queue;
81 static int aux_ready = 0;
82 static int aux_count = 0;
83 static int aux_present = 0;
86 * Shared subroutines
89 static unsigned int get_from_queue(void)
91 unsigned int result;
92 unsigned long flags;
94 save_flags(flags);
95 cli();
96 result = queue->buf[queue->tail];
97 queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
98 restore_flags(flags);
99 return result;
103 static inline int queue_empty(void)
105 return queue->head == queue->tail;
108 static int fasync_aux(int fd, struct file *filp, int on)
110 int retval;
112 retval = fasync_helper(fd, filp, on, &queue->fasync);
113 if (retval < 0)
114 return retval;
115 return 0;
119 * PS/2 Aux Device
122 #define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
123 #define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
125 #define MAX_RETRIES 60 /* some aux operations take long time*/
126 #if defined(__alpha__) && !defined(CONFIG_PCI)
127 # define AUX_IRQ 9 /* Jensen is odd indeed */
128 #else
129 # define AUX_IRQ 12
130 #endif
133 * Status polling
136 static int poll_aux_status(void)
138 int retries=0;
140 while ((inb(KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < MAX_RETRIES) {
141 if ((inb_p(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
142 inb_p(KBD_DATA_REG);
143 current->state = TASK_INTERRUPTIBLE;
144 current->timeout = jiffies + (5*HZ + 99) / 100;
145 schedule();
146 retries++;
148 return (retries < MAX_RETRIES);
152 * Write to aux device
155 static void aux_write_dev(int val)
157 poll_aux_status();
158 outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); /* Write magic cookie */
159 poll_aux_status();
160 outb_p(val, KBD_DATA_REG); /* Write data */
164 * Write to device & handle returned ack
167 #ifdef INITIALIZE_DEVICE
168 __initfunc(static int aux_write_ack(int val))
170 aux_write_dev(val);
171 poll_aux_status();
173 if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
175 return (inb(KBD_DATA_REG));
177 return 0;
179 #endif /* INITIALIZE_DEVICE */
182 * Write aux device command
185 static void aux_write_cmd(int val)
187 poll_aux_status();
188 outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG);
189 poll_aux_status();
190 outb_p(val, KBD_DATA_REG);
194 * AUX handler critical section start and end.
196 * Only one process can be in the critical section and all keyboard sends are
197 * deferred as long as we're inside. This is necessary as we may sleep when
198 * waiting for the keyboard controller and other processes / BH's can
199 * preempt us. Please note that the input buffer must be flushed when
200 * aux_end_atomic() is called and the interrupt is no longer enabled as not
201 * doing so might cause the keyboard driver to ignore all incoming keystrokes.
204 static struct semaphore aux_sema4 = MUTEX;
206 static inline void aux_start_atomic(void)
208 down(&aux_sema4);
209 disable_bh(KEYBOARD_BH);
212 static inline void aux_end_atomic(void)
214 enable_bh(KEYBOARD_BH);
215 up(&aux_sema4);
219 * Interrupt from the auxiliary device: a character
220 * is waiting in the keyboard/aux controller.
223 static void aux_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
225 int head = queue->head;
226 int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
228 if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) != AUX_STAT_OBF)
229 return;
231 add_mouse_randomness(queue->buf[head] = inb(KBD_DATA_REG));
232 if (head != maxhead) {
233 head++;
234 head &= AUX_BUF_SIZE-1;
236 queue->head = head;
237 aux_ready = 1;
238 if (queue->fasync)
239 kill_fasync(queue->fasync, SIGIO);
240 wake_up_interruptible(&queue->proc_list);
243 static int release_aux(struct inode * inode, struct file * file)
245 fasync_aux(-1, file, 0);
246 if (--aux_count)
247 return 0;
248 aux_start_atomic();
249 aux_write_cmd(AUX_INTS_OFF); /* Disable controller ints */
250 poll_aux_status();
251 outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */
252 poll_aux_status();
253 aux_end_atomic();
254 #ifdef CONFIG_MCA
255 free_irq(AUX_IRQ, inode);
256 #else
257 free_irq(AUX_IRQ, NULL);
258 #endif
259 MOD_DEC_USE_COUNT;
260 return 0;
264 * Install interrupt handler.
265 * Enable auxiliary device.
268 static int open_aux(struct inode * inode, struct file * file)
270 if (!aux_present)
271 return -ENODEV;
272 aux_start_atomic();
273 if (aux_count++) {
274 aux_end_atomic();
275 return 0;
277 if (!poll_aux_status()) { /* FIXME: Race condition */
278 aux_count--;
279 aux_end_atomic();
280 return -EBUSY;
282 queue->head = queue->tail = 0; /* Flush input queue */
283 #ifdef CONFIG_MCA
284 if (request_irq(AUX_IRQ, aux_interrupt, MCA_bus ? SA_SHIRQ : 0, "PS/2 Mouse", inode)) {
285 #else
286 if (request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL)) {
287 #endif
288 aux_count--;
289 aux_end_atomic();
290 return -EBUSY;
292 MOD_INC_USE_COUNT;
293 poll_aux_status();
294 outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */
295 aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */
296 aux_write_cmd(AUX_INTS_ON); /* Enable controller ints */
297 poll_aux_status();
298 aux_end_atomic();
300 aux_ready = 0;
301 return 0;
305 * Write to the aux device.
308 static ssize_t write_aux(struct file * file, const char * buffer,
309 size_t count, loff_t *ppos)
311 ssize_t retval = 0;
313 if (count) {
314 ssize_t written = 0;
316 aux_start_atomic();
317 do {
318 char c;
319 if (!poll_aux_status())
320 break;
321 outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);
322 if (!poll_aux_status())
323 break;
324 get_user(c, buffer++);
325 outb_p(c, KBD_DATA_REG);
326 written++;
327 } while (--count);
328 aux_end_atomic();
329 retval = -EIO;
330 if (written) {
331 retval = written;
332 file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
336 return retval;
340 * 82C710 Interface
343 #ifdef CONFIG_82C710_MOUSE
345 #define QP_DATA 0x310 /* Data Port I/O Address */
346 #define QP_STATUS 0x311 /* Status Port I/O Address */
348 #define QP_DEV_IDLE 0x01 /* Device Idle */
349 #define QP_RX_FULL 0x02 /* Device Char received */
350 #define QP_TX_IDLE 0x04 /* Device XMIT Idle */
351 #define QP_RESET 0x08 /* Device Reset */
352 #define QP_INTS_ON 0x10 /* Device Interrupt On */
353 #define QP_ERROR_FLAG 0x20 /* Device Error */
354 #define QP_CLEAR 0x40 /* Device Clear */
355 #define QP_ENABLE 0x80 /* Device Enable */
357 #define QP_IRQ 12
359 static int qp_present = 0;
360 static int qp_count = 0;
361 static int qp_data = QP_DATA;
362 static int qp_status = QP_STATUS;
364 static int poll_qp_status(void);
365 static int probe_qp(void);
368 * Interrupt handler for the 82C710 mouse port. A character
369 * is waiting in the 82C710.
372 static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
374 int head = queue->head;
375 int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
377 add_mouse_randomness(queue->buf[head] = inb(qp_data));
378 if (head != maxhead) {
379 head++;
380 head &= AUX_BUF_SIZE-1;
382 queue->head = head;
383 aux_ready = 1;
384 if (queue->fasync)
385 kill_fasync(queue->fasync, SIGIO);
386 wake_up_interruptible(&queue->proc_list);
389 static int release_qp(struct inode * inode, struct file * file)
391 unsigned char status;
393 fasync_aux(-1, file, 0);
394 if (!--qp_count) {
395 if (!poll_qp_status())
396 printk("Warning: Mouse device busy in release_qp()\n");
397 status = inb_p(qp_status);
398 outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
399 if (!poll_qp_status())
400 printk("Warning: Mouse device busy in release_qp()\n");
401 free_irq(QP_IRQ, NULL);
402 MOD_DEC_USE_COUNT;
404 return 0;
408 * Install interrupt handler.
409 * Enable the device, enable interrupts.
412 static int open_qp(struct inode * inode, struct file * file)
414 unsigned char status;
416 if (!qp_present)
417 return -EINVAL;
419 if (qp_count++)
420 return 0;
422 if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse", NULL)) {
423 qp_count--;
424 return -EBUSY;
427 status = inb_p(qp_status);
428 status |= (QP_ENABLE|QP_RESET);
429 outb_p(status, qp_status);
430 status &= ~(QP_RESET);
431 outb_p(status, qp_status);
433 queue->head = queue->tail = 0; /* Flush input queue */
434 status |= QP_INTS_ON;
435 outb_p(status, qp_status); /* Enable interrupts */
437 while (!poll_qp_status()) {
438 printk("Error: Mouse device busy in open_qp()\n");
439 qp_count--;
440 status &= ~(QP_ENABLE|QP_INTS_ON);
441 outb_p(status, qp_status);
442 free_irq(QP_IRQ, NULL);
443 return -EBUSY;
446 outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */
447 MOD_INC_USE_COUNT;
448 return 0;
452 * Write to the 82C710 mouse device.
455 static ssize_t write_qp(struct file * file, const char * buffer,
456 size_t count, loff_t *ppos)
458 ssize_t i = count;
460 while (i--) {
461 char c;
462 if (!poll_qp_status())
463 return -EIO;
464 get_user(c, buffer++);
465 outb_p(c, qp_data);
467 file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
468 return count;
472 * Wait for device to send output char and flush any input char.
475 static int poll_qp_status(void)
477 int retries=0;
479 while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE))
480 != (QP_DEV_IDLE|QP_TX_IDLE)
481 && retries < MAX_RETRIES) {
483 if (inb_p(qp_status)&(QP_RX_FULL))
484 inb_p(qp_data);
485 current->state = TASK_INTERRUPTIBLE;
486 current->timeout = jiffies + (5*HZ + 99) / 100;
487 schedule();
488 retries++;
490 return !(retries==MAX_RETRIES);
494 * Function to read register in 82C710.
497 static inline unsigned char read_710(unsigned char index)
499 outb_p(index, 0x390); /* Write index */
500 return inb_p(0x391); /* Read the data */
504 * See if we can find a 82C710 device. Read mouse address.
507 __initfunc(static int probe_qp(void))
509 outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */
510 outb_p(0xaa, 0x3fa); /* Inverse of 55 */
511 outb_p(0x36, 0x3fa); /* Address the chip */
512 outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */
513 outb_p(0x1b, 0x2fa); /* Inverse of e4 */
514 if (read_710(0x0f) != 0xe4) /* Config address found? */
515 return 0; /* No: no 82C710 here */
516 qp_data = read_710(0x0d)*4; /* Get mouse I/O address */
517 qp_status = qp_data+1;
518 outb_p(0x0f, 0x390);
519 outb_p(0x0f, 0x391); /* Close config mode */
520 return 1;
523 #endif
526 * Generic part continues...
530 * Put bytes from input queue to buffer.
533 static ssize_t read_aux(struct file * file, char * buffer,
534 size_t count, loff_t *ppos)
536 struct wait_queue wait = { current, NULL };
537 ssize_t i = count;
538 unsigned char c;
540 if (queue_empty()) {
541 if (file->f_flags & O_NONBLOCK)
542 return -EAGAIN;
543 add_wait_queue(&queue->proc_list, &wait);
544 repeat:
545 current->state = TASK_INTERRUPTIBLE;
546 if (queue_empty() && !signal_pending(current)) {
547 schedule();
548 goto repeat;
550 current->state = TASK_RUNNING;
551 remove_wait_queue(&queue->proc_list, &wait);
553 while (i > 0 && !queue_empty()) {
554 c = get_from_queue();
555 put_user(c, buffer++);
556 i--;
558 aux_ready = !queue_empty();
559 if (count-i) {
560 file->f_dentry->d_inode->i_atime = CURRENT_TIME;
561 return count-i;
563 if (signal_pending(current))
564 return -ERESTARTSYS;
565 return 0;
568 static unsigned int aux_poll(struct file *file, poll_table * wait)
570 poll_wait(file, &queue->proc_list, wait);
571 if (aux_ready)
572 return POLLIN | POLLRDNORM;
573 return 0;
576 struct file_operations psaux_fops = {
577 NULL, /* seek */
578 read_aux,
579 write_aux,
580 NULL, /* readdir */
581 aux_poll,
582 NULL, /* ioctl */
583 NULL, /* mmap */
584 open_aux,
585 NULL, /* flush */
586 release_aux,
587 NULL,
588 fasync_aux,
592 * Initialize driver. First check for a 82C710 chip; if found
593 * forget about the Aux port and use the *_qp functions.
595 static struct miscdevice psaux_mouse = {
596 PSMOUSE_MINOR, "psaux", &psaux_fops
599 __initfunc(int psaux_init(void))
601 int qp_found = 0;
603 #ifdef CONFIG_82C710_MOUSE
604 if ((qp_found = probe_qp())) {
605 printk(KERN_INFO "82C710 type pointing device detected -- driver installed.\n");
606 /* printk("82C710 address = %x (should be 0x310)\n", qp_data); */
607 qp_present = 1;
608 psaux_fops.write = write_qp;
609 psaux_fops.open = open_qp;
610 psaux_fops.release = release_qp;
611 } else
612 #endif
613 if (aux_device_present == 0xaa) {
614 printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n");
615 aux_present = 1;
616 #ifdef CONFIG_VT
617 pckbd_read_mask = AUX_STAT_OBF;
618 #endif
619 } else {
620 return -EIO;
622 misc_register(&psaux_mouse);
623 queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
624 memset(queue, 0, sizeof(*queue));
625 queue->head = queue->tail = 0;
626 queue->proc_list = NULL;
627 if (!qp_found) {
628 aux_start_atomic();
629 #ifdef INITIALIZE_DEVICE
630 outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */
631 aux_write_ack(AUX_SET_SAMPLE);
632 aux_write_ack(100); /* 100 samples/sec */
633 aux_write_ack(AUX_SET_RES);
634 aux_write_ack(3); /* 8 counts per mm */
635 aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
636 poll_aux_status();
637 #endif /* INITIALIZE_DEVICE */
638 outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */
639 poll_aux_status();
640 outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG); /* Disable controller interrupts */
641 poll_aux_status();
642 outb_p(AUX_INTS_OFF, KBD_DATA_REG);
643 poll_aux_status();
644 aux_end_atomic();
646 return 0;
649 #ifdef MODULE
650 int init_module(void)
652 return psaux_init();
655 void cleanup_module(void)
657 misc_deregister(&psaux_mouse);
658 kfree(queue);
660 #endif