1 /*
2 * linux/drivers/char/qpmouse.c
3 *
4 * Driver for a 82C710 C&T mouse interface chip.
5 *
6 * Based on the PS/2 driver by Johan Myreen.
7 *
8 * Corrections in device setup for some laptop mice & trackballs.
9 * 02Feb93 (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca)
10 *
11 * Modified by Johan Myreen (jem@iki.fi) 04Aug93
12 * to include support for QuickPort mouse.
13 *
14 * Changed references to "QuickPort" with "82C710" since "QuickPort"
15 * is not what this driver is all about -- QuickPort is just a
16 * connector type, and this driver is for the mouse port on the Chips
17 * & Technologies 82C710 interface chip. 15Nov93 jem@iki.fi
18 *
19 * Added support for SIGIO. 28Jul95 jem@iki.fi
20 *
21 * Rearranged SIGIO support to use code from tty_io. 9Sept95 ctm@ardi.com
22 *
23 * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
24 */
25
26 #include <linux/module.h>
27
28 #include <linux/sched.h>
29 #include <linux/kernel.h>
30 #include <linux/interrupt.h>
31 #include <linux/fcntl.h>
32 #include <linux/errno.h>
33 #include <linux/timer.h>
34 #include <linux/malloc.h>
35 #include <linux/miscdevice.h>
36 #include <linux/random.h>
37 #include <linux/poll.h>
38 #include <linux/init.h>
39 #include <linux/smp_lock.h>
40
41 #include <asm/io.h>
42 #include <asm/uaccess.h>
43 #include <asm/system.h>
44 #include <asm/semaphore.h>
45
46 #include <linux/pc_keyb.h> /* mouse enable command.. */
47
48
49 /*
50 * We use the same minor number as the PS/2 mouse for (bad) historical
51 * reasons..
52 */
53 #define PSMOUSE_MINOR 1 /* Minor device # for this mouse */
54 #define QP_BUF_SIZE 2048
55
56 struct qp_queue {
57 unsigned long head;
58 unsigned long tail;
59 wait_queue_head_t proc_list;
60 struct fasync_struct *fasync;
61 unsigned char buf[QP_BUF_SIZE];
62 };
63
64 static struct qp_queue *queue;
65
66 static unsigned int get_from_queue(void)
67 {
68 unsigned int result;
69 unsigned long flags;
70
71 save_flags(flags);
72 cli();
73 result = queue->buf[queue->tail];
74 queue->tail = (queue->tail + 1) & (QP_BUF_SIZE-1);
75 restore_flags(flags);
76 return result;
77 }
78
79
80 static inline int queue_empty(void)
81 {
82 return queue->head == queue->tail;
83 }
84
85 static int fasync_qp(int fd, struct file *filp, int on)
86 {
87 int retval;
88
89 retval = fasync_helper(fd, filp, on, &queue->fasync);
90 if (retval < 0)
91 return retval;
92 return 0;
93 }
94
95 /*
96 * 82C710 Interface
97 */
98
99 #define QP_DATA 0x310 /* Data Port I/O Address */
100 #define QP_STATUS 0x311 /* Status Port I/O Address */
101
102 #define QP_DEV_IDLE 0x01 /* Device Idle */
103 #define QP_RX_FULL 0x02 /* Device Char received */
104 #define QP_TX_IDLE 0x04 /* Device XMIT Idle */
105 #define QP_RESET 0x08 /* Device Reset */
106 #define QP_INTS_ON 0x10 /* Device Interrupt On */
107 #define QP_ERROR_FLAG 0x20 /* Device Error */
108 #define QP_CLEAR 0x40 /* Device Clear */
109 #define QP_ENABLE 0x80 /* Device Enable */
110
111 #define QP_IRQ 12
112
113 static int qp_present;
114 static int qp_count;
115 static int qp_data = QP_DATA;
116 static int qp_status = QP_STATUS;
117
118 static int poll_qp_status(void);
119 static int probe_qp(void);
120
121 /*
122 * Interrupt handler for the 82C710 mouse port. A character
123 * is waiting in the 82C710.
124 */
125
126 static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
127 {
128 int head = queue->head;
129 int maxhead = (queue->tail-1) & (QP_BUF_SIZE-1);
130
131 add_mouse_randomness(queue->buf[head] = inb(qp_data));
132 if (head != maxhead) {
133 head++;
134 head &= QP_BUF_SIZE-1;
135 }
136 queue->head = head;
137 kill_fasync(&queue->fasync, SIGIO, POLL_IN);
138 wake_up_interruptible(&queue->proc_list);
139 }
140
141 static int release_qp(struct inode * inode, struct file * file)
142 {
143 unsigned char status;
144
145 lock_kernel();
146 fasync_qp(-1, file, 0);
147 if (!--qp_count) {
148 if (!poll_qp_status())
149 printk("Warning: Mouse device busy in release_qp()\n");
150 status = inb_p(qp_status);
151 outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
152 if (!poll_qp_status())
153 printk("Warning: Mouse device busy in release_qp()\n");
154 free_irq(QP_IRQ, NULL);
155 }
156 unlock_kernel();
157 return 0;
158 }
159
160 /*
161 * Install interrupt handler.
162 * Enable the device, enable interrupts.
163 */
164
165 static int open_qp(struct inode * inode, struct file * file)
166 {
167 unsigned char status;
168
169 if (!qp_present)
170 return -EINVAL;
171
172 if (qp_count++)
173 return 0;
174
175 if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse", NULL)) {
176 qp_count--;
177 return -EBUSY;
178 }
179
180 status = inb_p(qp_status);
181 status |= (QP_ENABLE|QP_RESET);
182 outb_p(status, qp_status);
183 status &= ~(QP_RESET);
184 outb_p(status, qp_status);
185
186 queue->head = queue->tail = 0; /* Flush input queue */
187 status |= QP_INTS_ON;
188 outb_p(status, qp_status); /* Enable interrupts */
189
190 while (!poll_qp_status()) {
191 printk("Error: Mouse device busy in open_qp()\n");
192 qp_count--;
193 status &= ~(QP_ENABLE|QP_INTS_ON);
194 outb_p(status, qp_status);
195 free_irq(QP_IRQ, NULL);
196 return -EBUSY;
197 }
198
199 outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */
200 return 0;
201 }
202
203 /*
204 * Write to the 82C710 mouse device.
205 */
206
207 static ssize_t write_qp(struct file * file, const char * buffer,
208 size_t count, loff_t *ppos)
209 {
210 ssize_t i = count;
211
212 while (i--) {
213 char c;
214 if (!poll_qp_status())
215 return -EIO;
216 get_user(c, buffer++);
217 outb_p(c, qp_data);
218 }
219 file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
220 return count;
221 }
222
223 static unsigned int poll_qp(struct file *file, poll_table * wait)
224 {
225 poll_wait(file, &queue->proc_list, wait);
226 if (!queue_empty())
227 return POLLIN | POLLRDNORM;
228 return 0;
229 }
230
231 /*
232 * Wait for device to send output char and flush any input char.
233 */
234
235 #define MAX_RETRIES (60)
236
237 static int poll_qp_status(void)
238 {
239 int retries=0;
240
241 while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE))
242 != (QP_DEV_IDLE|QP_TX_IDLE)
243 && retries < MAX_RETRIES) {
244
245 if (inb_p(qp_status)&(QP_RX_FULL))
246 inb_p(qp_data);
247 current->state = TASK_INTERRUPTIBLE;
248 schedule_timeout((5*HZ + 99) / 100);
249 retries++;
250 }
251 return !(retries==MAX_RETRIES);
252 }
253
254 /*
255 * Put bytes from input queue to buffer.
256 */
257
258 static ssize_t read_qp(struct file * file, char * buffer,
259 size_t count, loff_t *ppos)
260 {
261 DECLARE_WAITQUEUE(wait, current);
262 ssize_t i = count;
263 unsigned char c;
264
265 if (queue_empty()) {
266 if (file->f_flags & O_NONBLOCK)
267 return -EAGAIN;
268 add_wait_queue(&queue->proc_list, &wait);
269 repeat:
270 set_current_state(TASK_INTERRUPTIBLE);
271 if (queue_empty() && !signal_pending(current)) {
272 schedule();
273 goto repeat;
274 }
275 current->state = TASK_RUNNING;
276 remove_wait_queue(&queue->proc_list, &wait);
277 }
278 while (i > 0 && !queue_empty()) {
279 c = get_from_queue();
280 put_user(c, buffer++);
281 i--;
282 }
283 if (count-i) {
284 file->f_dentry->d_inode->i_atime = CURRENT_TIME;
285 return count-i;
286 }
287 if (signal_pending(current))
288 return -ERESTARTSYS;
289 return 0;
290 }
291
292 struct file_operations qp_fops = {
293 owner: THIS_MODULE,
294 read: read_qp,
295 write: write_qp,
296 poll: poll_qp,
297 open: open_qp,
298 release: release_qp,
299 fasync: fasync_qp,
300 };
301
302 /*
303 * Initialize driver.
304 */
305 static struct miscdevice qp_mouse = {
306 PSMOUSE_MINOR, "QPmouse", &qp_fops
307 };
308
309 /*
310 * Function to read register in 82C710.
311 */
312
313 static inline unsigned char read_710(unsigned char index)
314 {
315 outb_p(index, 0x390); /* Write index */
316 return inb_p(0x391); /* Read the data */
317 }
318
319
320 /*
321 * See if we can find a 82C710 device. Read mouse address.
322 */
323
324 static int __init probe_qp(void)
325 {
326 outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */
327 outb_p(0xaa, 0x3fa); /* Inverse of 55 */
328 outb_p(0x36, 0x3fa); /* Address the chip */
329 outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */
330 outb_p(0x1b, 0x2fa); /* Inverse of e4 */
331 if (read_710(0x0f) != 0xe4) /* Config address found? */
332 return 0; /* No: no 82C710 here */
333 qp_data = read_710(0x0d)*4; /* Get mouse I/O address */
334 qp_status = qp_data+1;
335 outb_p(0x0f, 0x390);
336 outb_p(0x0f, 0x391); /* Close config mode */
337 return 1;
338 }
339
340 int __init qpmouse_init(void)
341 {
342 if (!probe_qp())
343 return -EIO;
344
345 printk(KERN_INFO "82C710 type pointing device detected -- driver installed.\n");
346 /* printk("82C710 address = %x (should be 0x310)\n", qp_data); */
347 queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
348 if(queue==NULL)
349 {
350 printk(KERN_ERR "qpmouse: no queue memory.\n");
351 return -ENOMEM;
352 }
353 qp_present = 1;
354 misc_register(&qp_mouse);
355 memset(queue, 0, sizeof(*queue));
356 queue->head = queue->tail = 0;
357 init_waitqueue_head(&queue->proc_list);
358
359 return 0;
360 }
361
362 #ifdef MODULE
363 int init_module(void)
364 {
365 return qpmouse_init();
366 }
367
368 void cleanup_module(void)
369 {
370 misc_deregister(&qp_mouse);
371 kfree(queue);
372 }
373 #endif
374
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.