File: /usr/src/linux/drivers/acorn/char/mouse_ps2.c
1 /*
2 * Driver for PS/2 mouse on IOMD interface
3 */
4
5 #include <linux/config.h>
6 #include <linux/sched.h>
7 #include <linux/interrupt.h>
8 #include <linux/tty.h>
9 #include <linux/tty_flip.h>
10 #include <linux/mm.h>
11 #include <linux/slab.h>
12 #include <linux/ptrace.h>
13 #include <linux/signal.h>
14 #include <linux/timer.h>
15 #include <linux/random.h>
16 #include <linux/ctype.h>
17 #include <linux/kbd_ll.h>
18 #include <linux/delay.h>
19 #include <linux/init.h>
20 #include <linux/poll.h>
21 #include <linux/miscdevice.h>
22
23 #include <asm/bitops.h>
24 #include <asm/irq.h>
25 #include <asm/hardware.h>
26 #include <asm/io.h>
27 #include <asm/hardware/iomd.h>
28 #include <asm/system.h>
29 #include <asm/uaccess.h>
30
31 /*
32 * PS/2 Auxiliary Device
33 */
34
35 static struct aux_queue *queue; /* Mouse data buffer. */
36 static int aux_count = 0;
37 /* used when we send commands to the mouse that expect an ACK. */
38 static unsigned char mouse_reply_expected = 0;
39
40 #define MAX_RETRIES 60 /* some aux operations take long time*/
41
42 /*
43 * Mouse Commands
44 */
45
46 #define AUX_SET_RES 0xE8 /* Set resolution */
47 #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
48 #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
49 #define AUX_GET_SCALE 0xE9 /* Get scaling factor */
50 #define AUX_SET_STREAM 0xEA /* Set stream mode */
51 #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
52 #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
53 #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
54 #define AUX_RESET 0xFF /* Reset aux device */
55 #define AUX_ACK 0xFA /* Command byte ACK. */
56
57 #define AUX_BUF_SIZE 2048 /* This might be better divisible by
58 three to make overruns stay in sync
59 but then the read function would
60 need a lock etc - ick */
61
62 struct aux_queue {
63 unsigned long head;
64 unsigned long tail;
65 wait_queue_head_t proc_list;
66 struct fasync_struct *fasync;
67 unsigned char buf[AUX_BUF_SIZE];
68 };
69
70 /*
71 * Send a byte to the mouse.
72 */
73 static void aux_write_dev(int val)
74 {
75 while (!(iomd_readb(IOMD_MSECTL) & 0x80));
76 iomd_writeb(val, IOMD_MSEDAT);
77 }
78
79 /*
80 * Send a byte to the mouse & handle returned ack
81 */
82 static void aux_write_ack(int val)
83 {
84 while (!(iomd_readb(IOMD_MSECTL) & 0x80));
85 iomd_writeb(val, IOMD_MSEDAT);
86
87 /* we expect an ACK in response. */
88 mouse_reply_expected++;
89 }
90
91 static unsigned char get_from_queue(void)
92 {
93 unsigned char result;
94
95 result = queue->buf[queue->tail];
96 queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
97 return result;
98 }
99
100 static void psaux_interrupt(int irq, void *dev_id, struct pt_regs *regs)
101 {
102 int val = iomd_readb(IOMD_MSEDAT);
103
104 if (mouse_reply_expected) {
105 if (val == AUX_ACK) {
106 mouse_reply_expected--;
107 return;
108 }
109 mouse_reply_expected = 0;
110 }
111
112 add_mouse_randomness(val);
113 if (aux_count) {
114 int head = queue->head;
115
116 queue->buf[head] = val;
117 head = (head + 1) & (AUX_BUF_SIZE-1);
118 if (head != queue->tail) {
119 queue->head = head;
120 kill_fasync(&queue->fasync, SIGIO, POLL_IN);
121 wake_up_interruptible(&queue->proc_list);
122 }
123 }
124 }
125
126 static inline int queue_empty(void)
127 {
128 return queue->head == queue->tail;
129 }
130
131 static int fasync_aux(int fd, struct file *filp, int on)
132 {
133 int retval;
134
135 retval = fasync_helper(fd, filp, on, &queue->fasync);
136 if (retval < 0)
137 return retval;
138 return 0;
139 }
140
141
142 /*
143 * Random magic cookie for the aux device
144 */
145 #define AUX_DEV ((void *)queue)
146
147 static int release_aux(struct inode * inode, struct file * file)
148 {
149 fasync_aux(-1, file, 0);
150 if (--aux_count)
151 return 0;
152 free_irq(IRQ_MOUSERX, AUX_DEV);
153 return 0;
154 }
155
156 /*
157 * Install interrupt handler.
158 * Enable auxiliary device.
159 */
160
161 static int open_aux(struct inode * inode, struct file * file)
162 {
163 if (aux_count++)
164 return 0;
165
166 queue->head = queue->tail = 0; /* Flush input queue */
167 if (request_irq(IRQ_MOUSERX, psaux_interrupt, SA_SHIRQ, "ps/2 mouse",
168 AUX_DEV)) {
169 aux_count--;
170 return -EBUSY;
171 }
172
173 aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
174
175 return 0;
176 }
177
178 /*
179 * Put bytes from input queue to buffer.
180 */
181
182 static ssize_t read_aux(struct file * file, char * buffer,
183 size_t count, loff_t *ppos)
184 {
185 DECLARE_WAITQUEUE(wait, current);
186 ssize_t i = count;
187 unsigned char c;
188
189 if (queue_empty()) {
190 if (file->f_flags & O_NONBLOCK)
191 return -EAGAIN;
192 add_wait_queue(&queue->proc_list, &wait);
193 repeat:
194 current->state = TASK_INTERRUPTIBLE;
195 if (queue_empty() && !signal_pending(current)) {
196 schedule();
197 goto repeat;
198 }
199 current->state = TASK_RUNNING;
200 remove_wait_queue(&queue->proc_list, &wait);
201 }
202 while (i > 0 && !queue_empty()) {
203 c = get_from_queue();
204 put_user(c, buffer++);
205 i--;
206 }
207 if (count-i) {
208 file->f_dentry->d_inode->i_atime = CURRENT_TIME;
209 return count-i;
210 }
211 if (signal_pending(current))
212 return -ERESTARTSYS;
213 return 0;
214 }
215
216 /*
217 * Write to the aux device.
218 */
219
220 static ssize_t write_aux(struct file * file, const char * buffer,
221 size_t count, loff_t *ppos)
222 {
223 ssize_t retval = 0;
224
225 if (count) {
226 ssize_t written = 0;
227
228 if (count > 32)
229 count = 32; /* Limit to 32 bytes. */
230 do {
231 char c;
232 get_user(c, buffer++);
233 aux_write_dev(c);
234 written++;
235 } while (--count);
236 retval = -EIO;
237 if (written) {
238 retval = written;
239 file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
240 }
241 }
242
243 return retval;
244 }
245
246 static unsigned int aux_poll(struct file *file, poll_table * wait)
247 {
248 poll_wait(file, &queue->proc_list, wait);
249 if (!queue_empty())
250 return POLLIN | POLLRDNORM;
251 return 0;
252 }
253
254 struct file_operations psaux_fops = {
255 read: read_aux,
256 write: write_aux,
257 poll: aux_poll,
258 open: open_aux,
259 release: release_aux,
260 fasync: fasync_aux,
261 };
262
263 /*
264 * Initialize driver.
265 */
266 static struct miscdevice psaux_mouse = {
267 PSMOUSE_MINOR, "psaux", &psaux_fops
268 };
269
270 int __init psaux_init(void)
271 {
272 /* Reset the mouse state machine. */
273 iomd_writeb(0, IOMD_MSECTL);
274 iomd_writeb(8, IOMD_MSECTL);
275
276 misc_register(&psaux_mouse);
277 queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
278 memset(queue, 0, sizeof(*queue));
279 queue->head = queue->tail = 0;
280 init_waitqueue_head(&queue->proc_list);
281
282 aux_write_ack(AUX_SET_SAMPLE);
283 aux_write_ack(100); /* 100 samples/sec */
284 aux_write_ack(AUX_SET_RES);
285 aux_write_ack(3); /* 8 counts per mm */
286 aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
287
288 return 0;
289 }
290