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