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>
57 #include <asm/uaccess.h>
58 #include <asm/system.h>
59 #include <asm/semaphore.h>
61 #include <linux/config.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
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;
89 static unsigned int get_from_queue(void)
96 result
= queue
->buf
[queue
->tail
];
97 queue
->tail
= (queue
->tail
+ 1) & (AUX_BUF_SIZE
-1);
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
)
112 retval
= fasync_helper(fd
, filp
, on
, &queue
->fasync
);
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 */
136 static int poll_aux_status(void)
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
)
143 current
->state
= TASK_INTERRUPTIBLE
;
144 current
->timeout
= jiffies
+ (5*HZ
+ 99) / 100;
148 return (retries
< MAX_RETRIES
);
152 * Write to aux device
155 static void aux_write_dev(int val
)
158 outb_p(KBD_CCMD_WRITE_MOUSE
, KBD_CNTL_REG
); /* Write magic cookie */
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
))
173 if ((inb(KBD_STATUS_REG
) & AUX_STAT_OBF
) == AUX_STAT_OBF
)
175 return (inb(KBD_DATA_REG
));
179 #endif /* INITIALIZE_DEVICE */
182 * Write aux device command
185 static void aux_write_cmd(int val
)
188 outb_p(KBD_CCMD_WRITE_MODE
, KBD_CNTL_REG
);
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)
209 disable_bh(KEYBOARD_BH
);
212 static inline void aux_end_atomic(void)
214 enable_bh(KEYBOARD_BH
);
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
)
231 add_mouse_randomness(queue
->buf
[head
] = inb(KBD_DATA_REG
));
232 if (head
!= maxhead
) {
234 head
&= AUX_BUF_SIZE
-1;
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);
249 aux_write_cmd(AUX_INTS_OFF
); /* Disable controller ints */
251 outb_p(KBD_CCMD_MOUSE_DISABLE
, KBD_CNTL_REG
); /* Disable Aux device */
255 free_irq(AUX_IRQ
, inode
);
257 free_irq(AUX_IRQ
, NULL
);
264 * Install interrupt handler.
265 * Enable auxiliary device.
268 static int open_aux(struct inode
* inode
, struct file
* file
)
277 if (!poll_aux_status()) { /* FIXME: Race condition */
282 queue
->head
= queue
->tail
= 0; /* Flush input queue */
284 if (request_irq(AUX_IRQ
, aux_interrupt
, MCA_bus
? SA_SHIRQ
: 0, "PS/2 Mouse", inode
)) {
286 if (request_irq(AUX_IRQ
, aux_interrupt
, 0, "PS/2 Mouse", NULL
)) {
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 */
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
)
319 if (!poll_aux_status())
321 outb_p(KBD_CCMD_WRITE_MOUSE
, KBD_CNTL_REG
);
322 if (!poll_aux_status())
324 get_user(c
, buffer
++);
325 outb_p(c
, KBD_DATA_REG
);
332 file
->f_dentry
->d_inode
->i_mtime
= CURRENT_TIME
;
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 */
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
) {
380 head
&= AUX_BUF_SIZE
-1;
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);
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
);
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
;
422 if (request_irq(QP_IRQ
, qp_interrupt
, 0, "PS/2 Mouse", NULL
)) {
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");
440 status
&= ~(QP_ENABLE
|QP_INTS_ON
);
441 outb_p(status
, qp_status
);
442 free_irq(QP_IRQ
, NULL
);
446 outb_p(AUX_ENABLE_DEV
, qp_data
); /* Wake up mouse */
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
)
462 if (!poll_qp_status())
464 get_user(c
, buffer
++);
467 file
->f_dentry
->d_inode
->i_mtime
= CURRENT_TIME
;
472 * Wait for device to send output char and flush any input char.
475 static int poll_qp_status(void)
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
))
485 current
->state
= TASK_INTERRUPTIBLE
;
486 current
->timeout
= jiffies
+ (5*HZ
+ 99) / 100;
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;
519 outb_p(0x0f, 0x391); /* Close config mode */
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
};
541 if (file
->f_flags
& O_NONBLOCK
)
543 add_wait_queue(&queue
->proc_list
, &wait
);
545 current
->state
= TASK_INTERRUPTIBLE
;
546 if (queue_empty() && !signal_pending(current
)) {
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
++);
558 aux_ready
= !queue_empty();
560 file
->f_dentry
->d_inode
->i_atime
= CURRENT_TIME
;
563 if (signal_pending(current
))
568 static unsigned int aux_poll(struct file
*file
, poll_table
* wait
)
570 poll_wait(file
, &queue
->proc_list
, wait
);
572 return POLLIN
| POLLRDNORM
;
576 struct file_operations psaux_fops
= {
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))
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); */
608 psaux_fops
.write
= write_qp
;
609 psaux_fops
.open
= open_qp
;
610 psaux_fops
.release
= release_qp
;
613 if (aux_device_present
== 0xaa) {
614 printk(KERN_INFO
"PS/2 auxiliary pointing device detected -- driver installed.\n");
617 pckbd_read_mask
= AUX_STAT_OBF
;
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
;
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 */
637 #endif /* INITIALIZE_DEVICE */
638 outb_p(KBD_CCMD_MOUSE_DISABLE
, KBD_CNTL_REG
); /* Disable Aux device */
640 outb_p(KBD_CCMD_WRITE_MODE
, KBD_CNTL_REG
); /* Disable controller interrupts */
642 outb_p(AUX_INTS_OFF
, KBD_DATA_REG
);
650 int init_module(void)
655 void cleanup_module(void)
657 misc_deregister(&psaux_mouse
);