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