Import 2.1.36
[davej-history.git] / drivers / char / psaux.c
blob28239579c0124c18fdbbae1c0b0c9ed91057d521
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>
33 /* Uncomment the following line if your mouse needs initialization. */
35 /* #define INITIALIZE_DEVICE */
37 #include <linux/module.h>
39 #include <linux/sched.h>
40 #include <linux/kernel.h>
41 #include <linux/interrupt.h>
42 #include <linux/fcntl.h>
43 #include <linux/errno.h>
44 #include <linux/timer.h>
45 #include <linux/malloc.h>
46 #include <linux/miscdevice.h>
47 #include <linux/random.h>
48 #include <linux/poll.h>
49 #include <linux/init.h>
51 #include <asm/io.h>
52 #include <asm/uaccess.h>
53 #include <asm/system.h>
55 #include <linux/config.h>
57 #define PSMOUSE_MINOR 1 /* minor device # for this mouse */
59 /* aux controller ports */
60 #define AUX_INPUT_PORT 0x60 /* Aux device output buffer */
61 #define AUX_OUTPUT_PORT 0x60 /* Aux device input buffer */
62 #define AUX_COMMAND 0x64 /* Aux device command buffer */
63 #define AUX_STATUS 0x64 /* Aux device status reg */
65 /* aux controller status bits */
66 #define AUX_OBUF_FULL 0x21 /* output buffer (from device) full */
67 #define AUX_IBUF_FULL 0x02 /* input buffer (to device) full */
69 /* aux controller commands */
70 #define AUX_CMD_WRITE 0x60 /* value to write to controller */
71 #define AUX_MAGIC_WRITE 0xd4 /* value to send aux device data */
73 #define AUX_INTS_ON 0x47 /* enable controller interrupts */
74 #define AUX_INTS_OFF 0x65 /* disable controller interrupts */
76 #define AUX_DISABLE 0xa7 /* disable aux */
77 #define AUX_ENABLE 0xa8 /* enable aux */
79 /* aux device commands */
80 #define AUX_SET_RES 0xe8 /* set resolution */
81 #define AUX_SET_SCALE11 0xe6 /* set 1:1 scaling */
82 #define AUX_SET_SCALE21 0xe7 /* set 2:1 scaling */
83 #define AUX_GET_SCALE 0xe9 /* get scaling factor */
84 #define AUX_SET_STREAM 0xea /* set stream mode */
85 #define AUX_SET_SAMPLE 0xf3 /* set sample rate */
86 #define AUX_ENABLE_DEV 0xf4 /* enable aux device */
87 #define AUX_DISABLE_DEV 0xf5 /* disable aux device */
88 #define AUX_RESET 0xff /* reset aux device */
90 #define MAX_RETRIES 60 /* some aux operations take long time*/
91 #if defined(__alpha__) && !defined(CONFIG_PCI)
92 # define AUX_IRQ 9 /* Jensen is odd indeed */
93 #else
94 # define AUX_IRQ 12
95 #endif
96 #define AUX_BUF_SIZE 2048
98 /* 82C710 definitions */
100 #define QP_DATA 0x310 /* Data Port I/O Address */
101 #define QP_STATUS 0x311 /* Status Port I/O Address */
103 #define QP_DEV_IDLE 0x01 /* Device Idle */
104 #define QP_RX_FULL 0x02 /* Device Char received */
105 #define QP_TX_IDLE 0x04 /* Device XMIT Idle */
106 #define QP_RESET 0x08 /* Device Reset */
107 #define QP_INTS_ON 0x10 /* Device Interrupt On */
108 #define QP_ERROR_FLAG 0x20 /* Device Error */
109 #define QP_CLEAR 0x40 /* Device Clear */
110 #define QP_ENABLE 0x80 /* Device Enable */
112 #define QP_IRQ 12
114 extern unsigned char aux_device_present;
115 extern unsigned char kbd_read_mask; /* from keyboard.c */
117 struct aux_queue {
118 unsigned long head;
119 unsigned long tail;
120 struct wait_queue *proc_list;
121 struct fasync_struct *fasync;
122 unsigned char buf[AUX_BUF_SIZE];
125 static struct aux_queue *queue;
126 static int aux_ready = 0;
127 static int aux_count = 0;
128 static int aux_present = 0;
129 static int poll_aux_status(void);
130 static int poll_aux_status_nosleep(void);
131 static int fasync_aux(struct inode *inode, struct file *filp, int on);
133 #ifdef CONFIG_82C710_MOUSE
134 static int qp_present = 0;
135 static int qp_count = 0;
136 static int qp_data = QP_DATA;
137 static int qp_status = QP_STATUS;
139 static int poll_qp_status(void);
140 static int probe_qp(void);
141 #endif
145 * Write to aux device
148 static void aux_write_dev(int val)
150 poll_aux_status();
151 outb_p(AUX_MAGIC_WRITE,AUX_COMMAND); /* write magic cookie */
152 poll_aux_status();
153 outb_p(val,AUX_OUTPUT_PORT); /* write data */
157 * Write to device & handle returned ack
159 #if defined INITIALIZE_DEVICE
160 static int aux_write_ack(int val)
162 int retries = 0;
164 poll_aux_status_nosleep();
165 outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);
166 poll_aux_status_nosleep();
167 outb_p(val,AUX_OUTPUT_PORT);
168 poll_aux_status_nosleep();
170 if ((inb(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)
172 return (inb(AUX_INPUT_PORT));
174 return 0;
176 #endif /* INITIALIZE_DEVICE */
179 * Write aux device command
182 static void aux_write_cmd(int val)
184 poll_aux_status();
185 outb_p(AUX_CMD_WRITE,AUX_COMMAND);
186 poll_aux_status();
187 outb_p(val,AUX_OUTPUT_PORT);
191 static unsigned int get_from_queue(void)
193 unsigned int result;
194 unsigned long flags;
196 save_flags(flags);
197 cli();
198 result = queue->buf[queue->tail];
199 queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
200 restore_flags(flags);
201 return result;
205 static inline int queue_empty(void)
207 return queue->head == queue->tail;
213 * Interrupt from the auxiliary device: a character
214 * is waiting in the keyboard/aux controller.
217 static void aux_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
219 int head = queue->head;
220 int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
222 if ((inb(AUX_STATUS) & AUX_OBUF_FULL) != AUX_OBUF_FULL)
223 return;
225 add_mouse_randomness(queue->buf[head] = inb(AUX_INPUT_PORT));
226 if (head != maxhead) {
227 head++;
228 head &= AUX_BUF_SIZE-1;
230 queue->head = head;
231 aux_ready = 1;
232 if (queue->fasync)
233 kill_fasync(queue->fasync, SIGIO);
234 wake_up_interruptible(&queue->proc_list);
238 * Interrupt handler for the 82C710 mouse port. A character
239 * is waiting in the 82C710.
242 #ifdef CONFIG_82C710_MOUSE
243 static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
245 int head = queue->head;
246 int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
248 add_mouse_randomness(queue->buf[head] = inb(qp_data));
249 if (head != maxhead) {
250 head++;
251 head &= AUX_BUF_SIZE-1;
253 queue->head = head;
254 aux_ready = 1;
255 if (queue->fasync)
256 kill_fasync(queue->fasync, SIGIO);
257 wake_up_interruptible(&queue->proc_list);
259 #endif
262 static int release_aux(struct inode * inode, struct file * file)
264 fasync_aux(inode, file, 0);
265 if (--aux_count)
266 return 0;
267 /* disable kbd bh to avoid mixing of cmd bytes */
268 disable_bh(KEYBOARD_BH);
269 aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */
270 poll_aux_status();
271 outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */
272 poll_aux_status();
273 /* reenable kbd bh */
274 enable_bh(KEYBOARD_BH);
275 #ifdef CONFIG_MCA
276 free_irq(AUX_IRQ, inode);
277 #else
278 free_irq(AUX_IRQ, NULL);
279 #endif
280 MOD_DEC_USE_COUNT;
281 return 0;
284 #ifdef CONFIG_82C710_MOUSE
285 static int release_qp(struct inode * inode, struct file * file)
287 unsigned char status;
289 fasync_aux(inode, file, 0);
290 if (!--qp_count) {
291 if (!poll_qp_status())
292 printk("Warning: Mouse device busy in release_qp()\n");
293 status = inb_p(qp_status);
294 outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
295 if (!poll_qp_status())
296 printk("Warning: Mouse device busy in release_qp()\n");
297 free_irq(QP_IRQ, NULL);
298 MOD_DEC_USE_COUNT;
300 return 0;
302 #endif
304 static int fasync_aux(struct inode *inode, struct file *filp, int on)
306 int retval;
308 retval = fasync_helper(inode, filp, on, &queue->fasync);
309 if (retval < 0)
310 return retval;
311 return 0;
315 * Install interrupt handler.
316 * Enable auxiliary device.
319 static int open_aux(struct inode * inode, struct file * file)
321 if (!aux_present)
322 return -ENODEV;
323 if (aux_count++)
324 return 0;
325 if (!poll_aux_status()) {
326 aux_count--;
327 return -EBUSY;
329 queue->head = queue->tail = 0; /* Flush input queue */
330 #ifdef CONFIG_MCA
331 if (request_irq(AUX_IRQ, aux_interrupt, MCA_bus ? SA_SHIRQ : 0, "PS/2 Mouse", inode)) {
332 #else
333 if (request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL)) {
334 #endif
335 aux_count--;
336 return -EBUSY;
338 MOD_INC_USE_COUNT;
339 /* disable kbd bh to avoid mixing of cmd bytes */
340 disable_bh(KEYBOARD_BH);
341 poll_aux_status();
342 outb_p(AUX_ENABLE,AUX_COMMAND); /* Enable Aux */
343 aux_write_dev(AUX_ENABLE_DEV); /* enable aux device */
344 aux_write_cmd(AUX_INTS_ON); /* enable controller ints */
345 poll_aux_status();
346 /* reenable kbd bh */
347 enable_bh(KEYBOARD_BH);
349 aux_ready = 0;
350 return 0;
353 #ifdef CONFIG_82C710_MOUSE
355 * Install interrupt handler.
356 * Enable the device, enable interrupts.
359 static int open_qp(struct inode * inode, struct file * file)
361 unsigned char status;
363 if (!qp_present)
364 return -EINVAL;
366 if (qp_count++)
367 return 0;
369 if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse", NULL)) {
370 qp_count--;
371 return -EBUSY;
374 status = inb_p(qp_status);
375 status |= (QP_ENABLE|QP_RESET);
376 outb_p(status, qp_status);
377 status &= ~(QP_RESET);
378 outb_p(status, qp_status);
380 queue->head = queue->tail = 0; /* Flush input queue */
381 status |= QP_INTS_ON;
382 outb_p(status, qp_status); /* Enable interrupts */
384 while (!poll_qp_status()) {
385 printk("Error: Mouse device busy in open_qp()\n");
386 qp_count--;
387 status &= ~(QP_ENABLE|QP_INTS_ON);
388 outb_p(status, qp_status);
389 free_irq(QP_IRQ, NULL);
390 return -EBUSY;
393 outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */
394 MOD_INC_USE_COUNT;
395 return 0;
397 #endif
400 * Write to the aux device.
403 static long write_aux(struct inode * inode, struct file * file,
404 const char * buffer, unsigned long count)
406 int retval = 0;
408 if (count) {
409 int written = 0;
411 /* disable kbd bh to avoid mixing of cmd bytes */
412 disable_bh(KEYBOARD_BH);
414 do {
415 char c;
416 if (!poll_aux_status())
417 break;
418 outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);
419 if (!poll_aux_status())
420 break;
421 get_user(c, buffer++);
422 outb_p(c, AUX_OUTPUT_PORT);
423 written++;
424 } while (--count);
425 /* reenable kbd bh */
426 enable_bh(KEYBOARD_BH);
427 retval = -EIO;
428 if (written) {
429 retval = written;
430 inode->i_mtime = CURRENT_TIME;
434 return retval;
438 #ifdef CONFIG_82C710_MOUSE
440 * Write to the 82C710 mouse device.
443 static long write_qp(struct inode * inode, struct file * file,
444 const char * buffer, unsigned long count)
446 int i = count;
448 while (i--) {
449 char c;
450 if (!poll_qp_status())
451 return -EIO;
452 get_user(c, buffer++);
453 outb_p(c, qp_data);
455 inode->i_mtime = CURRENT_TIME;
456 return count;
458 #endif
462 * Put bytes from input queue to buffer.
465 static long read_aux(struct inode * inode, struct file * file,
466 char * buffer, unsigned long count)
468 struct wait_queue wait = { current, NULL };
469 int i = count;
470 unsigned char c;
472 if (queue_empty()) {
473 if (file->f_flags & O_NONBLOCK)
474 return -EAGAIN;
475 add_wait_queue(&queue->proc_list, &wait);
476 repeat:
477 current->state = TASK_INTERRUPTIBLE;
478 if (queue_empty() && !(current->signal & ~current->blocked)) {
479 schedule();
480 goto repeat;
482 current->state = TASK_RUNNING;
483 remove_wait_queue(&queue->proc_list, &wait);
485 while (i > 0 && !queue_empty()) {
486 c = get_from_queue();
487 put_user(c, buffer++);
488 i--;
490 aux_ready = !queue_empty();
491 if (count-i) {
492 inode->i_atime = CURRENT_TIME;
493 return count-i;
495 if (current->signal & ~current->blocked)
496 return -ERESTARTSYS;
497 return 0;
501 static unsigned int aux_poll(struct file *file, poll_table * wait)
503 poll_wait(&queue->proc_list, wait);
504 if (aux_ready)
505 return POLLIN | POLLRDNORM;
506 return 0;
510 struct file_operations psaux_fops = {
511 NULL, /* seek */
512 read_aux,
513 write_aux,
514 NULL, /* readdir */
515 aux_poll,
516 NULL, /* ioctl */
517 NULL, /* mmap */
518 open_aux,
519 release_aux,
520 NULL,
521 fasync_aux,
526 * Initialize driver. First check for a 82C710 chip; if found
527 * forget about the Aux port and use the *_qp functions.
529 static struct miscdevice psaux_mouse = {
530 PSMOUSE_MINOR, "ps2aux", &psaux_fops
533 __initfunc(int psaux_init(void))
535 int qp_found = 0;
537 #ifdef CONFIG_82C710_MOUSE
538 if ((qp_found = probe_qp())) {
539 printk(KERN_INFO "82C710 type pointing device detected -- driver installed.\n");
540 /* printk("82C710 address = %x (should be 0x310)\n", qp_data); */
541 qp_present = 1;
542 psaux_fops.write = write_qp;
543 psaux_fops.open = open_qp;
544 psaux_fops.release = release_qp;
545 } else
546 #endif
547 if (aux_device_present == 0xaa) {
548 printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n");
549 aux_present = 1;
550 #ifdef CONFIG_VT
551 kbd_read_mask = AUX_OBUF_FULL;
552 #endif
553 } else {
554 return -EIO;
556 misc_register(&psaux_mouse);
557 queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
558 memset(queue, 0, sizeof(*queue));
559 queue->head = queue->tail = 0;
560 queue->proc_list = NULL;
561 if (!qp_found) {
562 #if defined INITIALIZE_DEVICE
563 outb_p(AUX_ENABLE,AUX_COMMAND); /* Enable Aux */
564 aux_write_ack(AUX_SET_SAMPLE);
565 aux_write_ack(100); /* 100 samples/sec */
566 aux_write_ack(AUX_SET_RES);
567 aux_write_ack(3); /* 8 counts per mm */
568 aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
569 poll_aux_status_nosleep();
570 #endif /* INITIALIZE_DEVICE */
571 outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */
572 poll_aux_status_nosleep();
573 outb_p(AUX_CMD_WRITE,AUX_COMMAND);
574 poll_aux_status_nosleep(); /* Disable interrupts */
575 outb_p(AUX_INTS_OFF, AUX_OUTPUT_PORT); /* on the controller */
577 return 0;
580 #ifdef MODULE
581 int init_module(void)
583 return psaux_init(); /*?? Bjorn */
586 void cleanup_module(void)
588 misc_deregister(&psaux_mouse);
589 kfree(queue);
591 #endif
593 static int poll_aux_status(void)
595 int retries=0;
597 while ((inb(AUX_STATUS)&0x03) && retries < MAX_RETRIES) {
598 if ((inb_p(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)
599 inb_p(AUX_INPUT_PORT);
600 current->state = TASK_INTERRUPTIBLE;
601 current->timeout = jiffies + (5*HZ + 99) / 100;
602 schedule();
603 retries++;
605 return !(retries==MAX_RETRIES);
608 static int poll_aux_status_nosleep(void)
610 int retries = 0;
612 while ((inb(AUX_STATUS)&0x03) && retries < 1000000) {
613 if ((inb_p(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)
614 inb_p(AUX_INPUT_PORT);
615 retries++;
617 return !(retries == 1000000);
620 #ifdef CONFIG_82C710_MOUSE
622 * Wait for device to send output char and flush any input char.
625 static int poll_qp_status(void)
627 int retries=0;
629 while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE))
630 != (QP_DEV_IDLE|QP_TX_IDLE)
631 && retries < MAX_RETRIES) {
633 if (inb_p(qp_status)&(QP_RX_FULL))
634 inb_p(qp_data);
635 current->state = TASK_INTERRUPTIBLE;
636 current->timeout = jiffies + (5*HZ + 99) / 100;
637 schedule();
638 retries++;
640 return !(retries==MAX_RETRIES);
644 * Function to read register in 82C710.
647 static inline unsigned char read_710(unsigned char index)
649 outb_p(index, 0x390); /* Write index */
650 return inb_p(0x391); /* Read the data */
654 * See if we can find a 82C710 device. Read mouse address.
657 __initfunc(static int probe_qp(void))
659 outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */
660 outb_p(0xaa, 0x3fa); /* Inverse of 55 */
661 outb_p(0x36, 0x3fa); /* Address the chip */
662 outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */
663 outb_p(0x1b, 0x2fa); /* Inverse of e4 */
664 if (read_710(0x0f) != 0xe4) /* Config address found? */
665 return 0; /* No: no 82C710 here */
666 qp_data = read_710(0x0d)*4; /* Get mouse I/O address */
667 qp_status = qp_data+1;
668 outb_p(0x0f, 0x390);
669 outb_p(0x0f, 0x391); /* Close config mode */
670 return 1;
672 #endif