ms.c revision 1.2 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.2 1994/02/13 21:10:50 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 (int unit);
79
80 /* Amiga mice are hooked up to one of the two "game" ports, where
81 the main mouse is usually on the first port, and port 2 can
82 be used by a joystick. Nevertheless, we support two mouse
83 devices, /dev/mouse0 and /dev/mouse1 (with a link of /dev/mouse to
84 the device that represents the port of the mouse in use). */
85
86 struct ms_softc {
87 u_char ms_horc; /* horizontal counter on last scan */
88 u_char ms_verc; /* vertical counter on last scan */
89 char ms_mb; /* mouse button state */
90 char ms_ub; /* user button state */
91 int ms_dx; /* delta-x */
92 int ms_dy; /* delta-y */
93 volatile int ms_ready; /* event queue is ready */
94 struct evvar ms_events; /* event queue state */
95 } ms_softc[NMOUSE];
96
97
98 /* enable scanner, called when someone opens the device.
99 Assume caller already validated range of dev. */
100 void
101 ms_enable (dev_t dev)
102 {
103 int unit = minor (dev);
104 struct ms_softc *ms = &ms_softc[unit];
105
106 /* use this as flag to the "interrupt" to tell it when to
107 shut off (when it's reset to 0). */
108 ms->ms_ready = 1;
109
110 timeout ((timeout_t) msintr, (caddr_t) unit, 2);
111 }
112
113 /* disable scanner. Just set ms_ready to 0, and after the next
114 timeout taken, no further timeouts will be initiated. */
115 void
116 ms_disable (dev_t dev)
117 {
118 struct ms_softc *ms = &ms_softc[minor (dev)];
119 int s = splhigh ();
120
121 ms->ms_ready = 0;
122 /* sync with the interrupt */
123 tsleep ((caddr_t) ms, PZERO - 1, "mouse-disable", 0);
124 splx (s);
125 }
126
127
128 void
129 msintr (int unit)
130 {
131 struct ms_softc *ms = &ms_softc[unit];
132 register struct firm_event *fe;
133 register int mb, ub, d, get, put, any;
134 static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 };
135 static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT };
136 u_short pot;
137 u_char pra;
138 u_short count;
139 u_char *horc = ((u_char *) &count) + 1;
140 u_char *verc = (u_char *) &count;
141 short dx, dy;
142
143 /* BTW: we're emulating a mousesystems serial mouse here.. */
144
145 /* first read the three buttons. */
146 pot = custom.potgor;
147 pra = ciaa.pra;
148 pot >>= unit == 0 ? 8 : 12; /* contains right and middle button */
149 pra >>= unit == 0 ? 6 : 7; /* contains left button */
150 mb = (pot & 4) / 4 + (pot & 1) * 2 + (pra & 1) * 4;
151 mb ^= 0x07;
152
153 /* read current values of counter registers */
154 count = unit == 0 ? custom.joy0dat : custom.joy1dat;
155
156 /* take care of wraparound */
157 dx = *horc - ms->ms_horc;
158 if (dx < -127)
159 dx += 255;
160 else if (dx > 127)
161 dx -= 255;
162 dy = *verc - ms->ms_verc;
163 if (dy < -127)
164 dy += 255;
165 else if (dy > 127)
166 dy -= 255;
167
168 /* remember current values for next scan */
169 ms->ms_horc = *horc;
170 ms->ms_verc = *verc;
171
172 ms->ms_dx = dx;
173 ms->ms_dy = dy;
174 ms->ms_mb = mb;
175
176 if (dx || dy || ms->ms_ub != ms->ms_mb)
177 {
178
179 /* We have at least one event (mouse button, delta-X, or
180 delta-Y; possibly all three, and possibly three separate
181 button events). Deliver these events until we are out
182 of changes or out of room. As events get delivered,
183 mark them `unchanged'. */
184
185 any = 0;
186 get = ms->ms_events.ev_get;
187 put = ms->ms_events.ev_put;
188 fe = &ms->ms_events.ev_q[put];
189
190 /* NEXT prepares to put the next event, backing off if necessary */
191 #define NEXT \
192 if ((++put) % EV_QSIZE == get) \
193 { \
194 put--; \
195 goto out; \
196 }
197 /* ADVANCE completes the `put' of the event */
198 #define ADVANCE \
199 fe++; \
200 if (put >= EV_QSIZE) \
201 { \
202 put = 0; \
203 fe = &ms->ms_events.ev_q[0]; \
204 } \
205 any = 1
206
207 mb = ms->ms_mb;
208 ub = ms->ms_ub;
209 while ((d = mb ^ ub) != 0)
210 {
211 /* Mouse button change. Convert up to three changes
212 to the `first' change, and drop it into the event queue. */
213
214 NEXT;
215 d = to_one[d - 1]; /* from 1..7 to {1,2,4} */
216 fe->id = to_id[d - 1]; /* from {1,2,4} to ID */
217 fe->value = mb & d ? VKEY_DOWN : VKEY_UP;
218 fe->time = time;
219 ADVANCE;
220 ub ^= d;
221 }
222 if (ms->ms_dx)
223 {
224 NEXT;
225 fe->id = LOC_X_DELTA;
226 fe->value = ms->ms_dx;
227 fe->time = time;
228 ADVANCE;
229 ms->ms_dx = 0;
230 }
231 if (ms->ms_dy)
232 {
233 NEXT;
234 fe->id = LOC_Y_DELTA;
235 fe->value = ms->ms_dy;
236 fe->time = time;
237 ADVANCE;
238 ms->ms_dy = 0;
239 }
240 out:
241 if (any)
242 {
243 ms->ms_ub = ub;
244 ms->ms_events.ev_put = put;
245 EV_WAKEUP(&ms->ms_events);
246 }
247 }
248
249 /* reschedule handler, or if terminating, handshake with ms_disable */
250 if (ms->ms_ready)
251 timeout ((timeout_t) msintr, (caddr_t) unit, 2);
252 else
253 wakeup ((caddr_t) ms);
254
255 }
256
257 int
258 msopen (dev, flags, mode, p)
259 dev_t dev;
260 int flags, mode;
261 struct proc *p;
262 {
263 int unit = minor (dev);
264 struct ms_softc *ms = &ms_softc[unit];
265 int s, error;
266
267 if (unit >= NMOUSE)
268 return EXDEV;
269
270 if (ms->ms_events.ev_io)
271 return EBUSY;
272
273 ms->ms_events.ev_io = p;
274 ev_init (&ms->ms_events); /* may cause sleep */
275 ms_enable (dev);
276 return 0;
277 }
278
279 int
280 msclose (dev, flags, mode, p)
281 dev_t dev;
282 int flags, mode;
283 struct proc *p;
284 {
285 int unit = minor (dev);
286 struct ms_softc *ms = &ms_softc[unit];
287
288 ms_disable (dev);
289 ev_fini (&ms->ms_events);
290 ms->ms_events.ev_io = NULL;
291 return 0;
292 }
293
294 int
295 msread (dev, uio, flags)
296 dev_t dev;
297 struct uio *uio;
298 int flags;
299 {
300 int unit = minor (dev);
301 struct ms_softc *ms = &ms_softc[unit];
302
303 return ev_read (&ms->ms_events, uio, flags);
304 }
305
306 /* this routine should not exist, but is convenient to write here for now */
307 int
308 mswrite (dev, uio, flags)
309 dev_t dev;
310 struct uio *uio;
311 int flags;
312 {
313 return EOPNOTSUPP;
314 }
315
316 int
317 msioctl (dev, cmd, data, flag, p)
318 dev_t dev;
319 int cmd;
320 register caddr_t data;
321 int flag;
322 struct proc *p;
323 {
324 int unit = minor (dev);
325 struct ms_softc *ms = &ms_softc[unit];
326
327 switch (cmd)
328 {
329 case FIONBIO: /* we will remove this someday (soon???) */
330 return 0;
331
332 case FIOASYNC:
333 ms->ms_events.ev_async = *(int *)data != 0;
334 return 0;
335
336 case TIOCSPGRP:
337 if (*(int *)data != ms->ms_events.ev_io->p_pgid)
338 return EPERM;
339 return 0;
340
341 case VUIDGFORMAT:
342 /* we only do firm_events */
343 *(int *)data = VUID_FIRM_EVENT;
344 return 0;
345
346 case VUIDSFORMAT:
347 if (*(int *)data != VUID_FIRM_EVENT)
348 return EINVAL;
349 return 0;
350 }
351
352 return ENOTTY;
353 }
354
355 int
356 msselect (dev, rw, p)
357 dev_t dev;
358 int rw;
359 struct proc *p;
360 {
361 int unit = minor (dev);
362 struct ms_softc *ms = &ms_softc[unit];
363
364 return ev_select (&ms->ms_events, rw, p);
365 }
366
367 void
368 mouseattach() {}
369 #endif /* NMOUSE > 0 */
370