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>
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 */
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 */
114 extern unsigned char aux_device_present
;
115 extern unsigned char kbd_read_mask
; /* from keyboard.c */
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);
145 * Write to aux device
148 static void aux_write_dev(int val
)
151 outb_p(AUX_MAGIC_WRITE
,AUX_COMMAND
); /* write magic cookie */
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
)
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
));
176 #endif /* INITIALIZE_DEVICE */
179 * Write aux device command
182 static void aux_write_cmd(int val
)
185 outb_p(AUX_CMD_WRITE
,AUX_COMMAND
);
187 outb_p(val
,AUX_OUTPUT_PORT
);
191 static unsigned int get_from_queue(void)
198 result
= queue
->buf
[queue
->tail
];
199 queue
->tail
= (queue
->tail
+ 1) & (AUX_BUF_SIZE
-1);
200 restore_flags(flags
);
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
)
225 add_mouse_randomness(queue
->buf
[head
] = inb(AUX_INPUT_PORT
));
226 if (head
!= maxhead
) {
228 head
&= AUX_BUF_SIZE
-1;
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
) {
251 head
&= AUX_BUF_SIZE
-1;
256 kill_fasync(queue
->fasync
, SIGIO
);
257 wake_up_interruptible(&queue
->proc_list
);
262 static int release_aux(struct inode
* inode
, struct file
* file
)
264 fasync_aux(inode
, file
, 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 */
271 outb_p(AUX_DISABLE
,AUX_COMMAND
); /* Disable Aux device */
273 /* reenable kbd bh */
274 enable_bh(KEYBOARD_BH
);
276 free_irq(AUX_IRQ
, inode
);
278 free_irq(AUX_IRQ
, NULL
);
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);
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
);
304 static int fasync_aux(struct inode
*inode
, struct file
*filp
, int on
)
308 retval
= fasync_helper(inode
, filp
, on
, &queue
->fasync
);
315 * Install interrupt handler.
316 * Enable auxiliary device.
319 static int open_aux(struct inode
* inode
, struct file
* file
)
325 if (!poll_aux_status()) {
329 queue
->head
= queue
->tail
= 0; /* Flush input queue */
331 if (request_irq(AUX_IRQ
, aux_interrupt
, MCA_bus
? SA_SHIRQ
: 0, "PS/2 Mouse", inode
)) {
333 if (request_irq(AUX_IRQ
, aux_interrupt
, 0, "PS/2 Mouse", NULL
)) {
339 /* disable kbd bh to avoid mixing of cmd bytes */
340 disable_bh(KEYBOARD_BH
);
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 */
346 /* reenable kbd bh */
347 enable_bh(KEYBOARD_BH
);
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
;
369 if (request_irq(QP_IRQ
, qp_interrupt
, 0, "PS/2 Mouse", NULL
)) {
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");
387 status
&= ~(QP_ENABLE
|QP_INTS_ON
);
388 outb_p(status
, qp_status
);
389 free_irq(QP_IRQ
, NULL
);
393 outb_p(AUX_ENABLE_DEV
, qp_data
); /* Wake up mouse */
400 * Write to the aux device.
403 static long write_aux(struct inode
* inode
, struct file
* file
,
404 const char * buffer
, unsigned long count
)
411 /* disable kbd bh to avoid mixing of cmd bytes */
412 disable_bh(KEYBOARD_BH
);
416 if (!poll_aux_status())
418 outb_p(AUX_MAGIC_WRITE
,AUX_COMMAND
);
419 if (!poll_aux_status())
421 get_user(c
, buffer
++);
422 outb_p(c
, AUX_OUTPUT_PORT
);
425 /* reenable kbd bh */
426 enable_bh(KEYBOARD_BH
);
430 inode
->i_mtime
= CURRENT_TIME
;
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
)
450 if (!poll_qp_status())
452 get_user(c
, buffer
++);
455 inode
->i_mtime
= CURRENT_TIME
;
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
};
473 if (file
->f_flags
& O_NONBLOCK
)
475 add_wait_queue(&queue
->proc_list
, &wait
);
477 current
->state
= TASK_INTERRUPTIBLE
;
478 if (queue_empty() && !(current
->signal
& ~current
->blocked
)) {
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
++);
490 aux_ready
= !queue_empty();
492 inode
->i_atime
= CURRENT_TIME
;
495 if (current
->signal
& ~current
->blocked
)
501 static unsigned int aux_poll(struct file
*file
, poll_table
* wait
)
503 poll_wait(&queue
->proc_list
, wait
);
505 return POLLIN
| POLLRDNORM
;
510 struct file_operations psaux_fops
= {
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))
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); */
542 psaux_fops
.write
= write_qp
;
543 psaux_fops
.open
= open_qp
;
544 psaux_fops
.release
= release_qp
;
547 if (aux_device_present
== 0xaa) {
548 printk(KERN_INFO
"PS/2 auxiliary pointing device detected -- driver installed.\n");
551 kbd_read_mask
= AUX_OBUF_FULL
;
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
;
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 */
581 int init_module(void)
583 return psaux_init(); /*?? Bjorn */
586 void cleanup_module(void)
588 misc_deregister(&psaux_mouse
);
593 static int poll_aux_status(void)
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;
605 return !(retries
==MAX_RETRIES
);
608 static int poll_aux_status_nosleep(void)
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
);
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)
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
))
635 current
->state
= TASK_INTERRUPTIBLE
;
636 current
->timeout
= jiffies
+ (5*HZ
+ 99) / 100;
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;
669 outb_p(0x0f, 0x391); /* Close config mode */