xref: /netbsd-src/sys/arch/amiga/dev/ms.c (revision d9158b13b5dfe46201430699a3f7a235ecf28df3)
1 /*
2  * based on:
3  *
4  * Copyright (c) 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This software was developed by the Computer Systems Engineering group
8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9  * contributed to Berkeley.
10  *
11  * All advertising materials mentioning features or use of this software
12  * must display the following acknowledgement:
13  *	This product includes software developed by the University of
14  *	California, Lawrence Berkeley Laboratory.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  * 3. All advertising materials mentioning features or use of this software
25  *    must display the following acknowledgement:
26  *	This product includes software developed by the University of
27  *	California, Berkeley and its contributors.
28  * 4. Neither the name of the University nor the names of its contributors
29  *    may be used to endorse or promote products derived from this software
30  *    without specific prior written permission.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  *
44  *	@(#)ms.c	8.1 (Berkeley) 6/11/93
45  *
46  * from: Header: ms.c,v 1.5 92/11/26 01:28:47 torek Exp  (LBL)
47  *	$Id: ms.c,v 1.4 1994/06/05 07:45:17 chopps Exp $
48  */
49 
50 /*
51  * Mouse driver.
52  */
53 
54 #include <sys/param.h>
55 #include <sys/conf.h>
56 #include <sys/ioctl.h>
57 #include <sys/kernel.h>
58 #include <sys/proc.h>
59 #include <sys/syslog.h>
60 #include <sys/systm.h>
61 #include <sys/tty.h>
62 
63 #include <amiga/dev/event_var.h>
64 #include <amiga/dev/vuid_event.h>
65 
66 #include <amiga/amiga/custom.h>
67 #include <amiga/amiga/cia.h>
68 
69 #include "mouse.h"
70 #if NMOUSE > 0
71 
72 /* there's really no more physical ports on an amiga.. */
73 #if NMOUSE > 2
74 #undef NMOUSE
75 #define NMOUSE 2
76 #endif
77 
78 void msintr __P((void *));
79 void ms_enable __P((dev_t));
80 void ms_disable __P((dev_t));
81 
82 int
83 mouseattach(cnt)
84 	int cnt;
85 {
86 	printf("%d %s configured\n", NMOUSE, NMOUSE == 1 ? "mouse" : "mice");
87 	return(NMOUSE);
88 }
89 
90 /*
91  * Amiga mice are hooked up to one of the two "game" ports, where
92  * the main mouse is usually on the first port, and port 2 can
93  * be used by a joystick. Nevertheless, we support two mouse
94  * devices, /dev/mouse0 and /dev/mouse1 (with a link of /dev/mouse to
95  * the device that represents the port of the mouse in use).
96  */
97 struct ms_softc {
98 	u_char	ms_horc;	   /* horizontal counter on last scan */
99   	u_char	ms_verc;	   /* vertical counter on last scan */
100 	char	ms_mb;		   /* mouse button state */
101 	char	ms_ub;		   /* user button state */
102 	int	ms_dx;		   /* delta-x */
103 	int	ms_dy;		   /* delta-y */
104 	volatile int ms_ready;	   /* event queue is ready */
105 	struct	evvar ms_events;   /* event queue state */
106 } ms_softc[NMOUSE];
107 
108 
109 /*
110  * enable scanner, called when someone opens the device.
111  * Assume caller already validated range of dev.
112  */
113 void
114 ms_enable(dev)
115 	dev_t dev;
116 {
117 	struct ms_softc *ms;
118 
119 	ms = &ms_softc[minor(dev)];
120 	/*
121 	 * use this as flag to the "interrupt" to tell it when to
122 	 * shut off (when it's reset to 0).
123 	 */
124 	ms->ms_ready = 1;
125 
126 	timeout(msintr, (void *)minor(dev), 2);
127 }
128 
129 /*
130  * disable scanner. Just set ms_ready to 0, and after the next
131  * timeout taken, no further timeouts will be initiated.
132  */
133 void
134 ms_disable(dev)
135 	dev_t dev;
136 {
137 	struct ms_softc *ms;
138 	int s;
139 
140 	ms = &ms_softc[minor(dev)];
141 	s = splhigh ();
142 	ms->ms_ready = 0;
143 	/*
144 	 * sync with the interrupt
145 	 */
146 	tsleep(ms, PZERO - 1, "mouse-disable", 0);
147 	splx(s);
148 }
149 
150 
151 /*
152  * we're emulating a mousesystems serial mouse here..
153  */
154 void
155 msintr(arg)
156 	void *arg;
157 {
158 	static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 };
159 	static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT };
160 	struct ms_softc *ms;
161 	struct firm_event *fe;
162 	int mb, ub, d, get, put, any, unit;
163 	u_char pra, *horc, *verc;
164 	u_short pot, count;
165 	short dx, dy;
166 
167 	unit = (int)arg;
168 	ms = &ms_softc[unit];
169 	horc = ((u_char *) &count) + 1;
170 	verc = (u_char *) &count;
171 
172 	/*
173 	 * first read the three buttons.
174 	 */
175 	pot  = custom.potgor;
176 	pra  = ciaa.pra;
177 	pot >>= unit == 0 ? 8 : 12;	/* contains right and middle button */
178 	pra >>= unit == 0 ? 6 : 7;	/* contains left button */
179 	mb = (pot & 4) / 4 + (pot & 1) * 2 + (pra & 1) * 4;
180 	mb ^= 0x07;
181 
182 	/*
183 	 * read current values of counter registers
184 	 */
185 	if (unit == 0)
186 		count = custom.joy0dat;
187 	else
188 		count = custom.joy1dat;
189 
190 	/*
191 	 * take care of wraparound
192 	 */
193 	dx = *horc - ms->ms_horc;
194 	if (dx < -127)
195 		dx += 255;
196 	else if (dx > 127)
197 		dx -= 255;
198 	dy = *verc - ms->ms_verc;
199 	if (dy < -127)
200 		dy += 255;
201 	else if (dy > 127)
202 		dy -= 255;
203 
204 	/*
205 	 * remember current values for next scan
206 	 */
207 	ms->ms_horc = *horc;
208 	ms->ms_verc = *verc;
209 
210 	ms->ms_dx = dx;
211 	ms->ms_dy = dy;
212 	ms->ms_mb = mb;
213 
214 	if (dx || dy || ms->ms_ub != ms->ms_mb) {
215 		/*
216 		 * We have at least one event (mouse button, delta-X, or
217 		 * delta-Y; possibly all three, and possibly three separate
218 		 * button events).  Deliver these events until we are out of
219 		 * changes or out of room.  As events get delivered, mark them
220 		 * `unchanged'.
221 		 */
222 		any = 0;
223 		get = ms->ms_events.ev_get;
224 		put = ms->ms_events.ev_put;
225 		fe = &ms->ms_events.ev_q[put];
226 
227 		mb = ms->ms_mb;
228 		ub = ms->ms_ub;
229 		while ((d = mb ^ ub) != 0) {
230 			/*
231 			 * Mouse button change.  Convert up to three changes
232 			 * to the `first' change, and drop it into the event
233 			 * queue.
234 			 */
235 			if ((++put) % EV_QSIZE == get) {
236 				put--;
237 				goto out;
238 			}
239 
240 			d = to_one[d - 1];	/* from 1..7 to {1,2,4} */
241 			fe->id = to_id[d - 1];	/* from {1,2,4} to ID */
242 			fe->value = mb & d ? VKEY_DOWN : VKEY_UP;
243 			fe->time = time;
244 			fe++;
245 
246 			if (put >= EV_QSIZE) {
247 				put = 0;
248 				fe = &ms->ms_events.ev_q[0];
249 			}
250 			any = 1;
251 
252 			ub ^= d;
253 		}
254 		if (ms->ms_dx) {
255 			if ((++put) % EV_QSIZE == get) {
256 				put--;
257 				goto out;
258 			}
259 
260 			fe->id = LOC_X_DELTA;
261 			fe->value = ms->ms_dx;
262 			fe->time = time;
263 			fe++;
264 
265 			if (put >= EV_QSIZE) {
266 				put = 0;
267 				fe = &ms->ms_events.ev_q[0];
268 			}
269 			any = 1;
270 
271 			ms->ms_dx = 0;
272 		}
273 		if (ms->ms_dy) {
274 			if ((++put) % EV_QSIZE == get) {
275 				put--;
276 				goto out;
277 			}
278 
279 			fe->id = LOC_Y_DELTA;
280 			fe->value = ms->ms_dy;
281 			fe->time = time;
282 			fe++;
283 
284 			if (put >= EV_QSIZE) {
285 				put = 0;
286 				fe = &ms->ms_events.ev_q[0];
287 			}
288 			any = 1;
289 
290 			ms->ms_dy = 0;
291 		}
292 out:
293 		if (any) {
294 			ms->ms_ub = ub;
295 			ms->ms_events.ev_put = put;
296 			EV_WAKEUP(&ms->ms_events);
297 		}
298 	}
299 
300 	/*
301 	 * reschedule handler, or if terminating,
302 	 * handshake with ms_disable
303 	 */
304 	if (ms->ms_ready)
305 		timeout(msintr, (void *)unit, 2);
306 	else
307 		wakeup(ms);
308 }
309 
310 int
311 msopen(dev, flags, mode, p)
312 	dev_t dev;
313 	int flags, mode;
314 	struct proc *p;
315 {
316 	struct ms_softc *ms;
317 	int s, error, unit;
318 
319 	unit = minor(dev);
320 	ms = &ms_softc[unit];
321 
322 	if (unit >= NMOUSE)
323 		return(EXDEV);
324 
325 	if (ms->ms_events.ev_io)
326 		return(EBUSY);
327 
328 	ms->ms_events.ev_io = p;
329 	ev_init(&ms->ms_events);	/* may cause sleep */
330 	ms_enable(dev);
331 	return(0);
332 }
333 
334 int
335 msclose(dev, flags, mode, p)
336 	dev_t dev;
337 	int flags, mode;
338 	struct proc *p;
339 {
340 	int unit;
341 	struct ms_softc *ms;
342 
343 	unit = minor (dev);
344 	ms = &ms_softc[unit];
345 
346 	ms_disable(dev);
347 	ev_fini(&ms->ms_events);
348 	ms->ms_events.ev_io = NULL;
349 	return(0);
350 }
351 
352 int
353 msread(dev, uio, flags)
354 	dev_t dev;
355 	struct uio *uio;
356 	int flags;
357 {
358 	struct ms_softc *ms;
359 
360 	ms = &ms_softc[minor(dev)];
361 	return(ev_read(&ms->ms_events, uio, flags));
362 }
363 
364 /*
365  * XXX this routine should not exist,
366  * but is convenient to write here for now
367  */
368 int
369 mswrite(dev, uio, flags)
370 	dev_t dev;
371 	struct uio *uio;
372 	int flags;
373 {
374 	return(EOPNOTSUPP);
375 }
376 
377 int
378 msioctl(dev, cmd, data, flag, p)
379      dev_t dev;
380      int cmd;
381      register caddr_t data;
382      int flag;
383      struct proc *p;
384 {
385 	struct ms_softc *ms;
386 	int unit;
387 
388 	unit = minor(dev);
389 	ms = &ms_softc[unit];
390 
391 	switch (cmd) {
392 	case FIONBIO:		/* we will remove this someday (soon???) */
393 		return(0);
394 	case FIOASYNC:
395 		ms->ms_events.ev_async = *(int *)data != 0;
396 		return(0);
397 	case TIOCSPGRP:
398 		if (*(int *)data != ms->ms_events.ev_io->p_pgid)
399 			return(EPERM);
400 		return(0);
401 	case VUIDGFORMAT:	/* we only do firm_events */
402 		*(int *)data = VUID_FIRM_EVENT;
403 		return(0);
404 	case VUIDSFORMAT:
405 		if (*(int *)data != VUID_FIRM_EVENT)
406 			return(EINVAL);
407 		return(0);
408 	}
409 	return(ENOTTY);
410 }
411 
412 int
413 msselect(dev, rw, p)
414 	dev_t dev;
415 	int rw;
416 	struct proc *p;
417 {
418 	struct ms_softc *ms;
419 
420 	ms = &ms_softc[minor(dev)];
421 	return(ev_select(&ms->ms_events, rw, p));
422 }
423 #endif /* NMOUSE > 0 */
424