ms.c revision 1.17 1 /* $NetBSD: ms.c,v 1.17 2000/05/18 15:39:23 kleink 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/callout.h>
63 #include <sys/tty.h>
64 #include <sys/signalvar.h>
65
66 #include <amiga/dev/event_var.h>
67 #include <amiga/dev/vuid_event.h>
68
69 #include <amiga/amiga/custom.h>
70 #include <amiga/amiga/cia.h>
71 #include <amiga/amiga/device.h>
72
73 #include <sys/conf.h>
74 #include <machine/conf.h>
75
76 void msattach __P((struct device *, struct device *, void *));
77 int msmatch __P((struct device *, struct cfdata *, void *));
78
79 /* per-port state */
80 struct ms_port {
81 int ms_portno; /* which hardware port, for msintr() */
82
83 struct callout ms_intr_ch;
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 #define MS_NPORTS 2
96
97 struct ms_softc {
98 struct device sc_dev; /* base device */
99 struct ms_port sc_ports[MS_NPORTS];
100 };
101
102 struct cfattach ms_ca = {
103 sizeof(struct ms_softc), msmatch, msattach
104 };
105
106 void msintr __P((void *));
107 void ms_enable __P((struct ms_port *));
108 void ms_disable __P((struct ms_port *));
109
110 extern struct cfdriver ms_cd;
111
112 #define MS_UNIT(d) ((minor(d) & ~0x1) >> 1)
113 #define MS_PORT(d) (minor(d) & 0x1)
114
115 /*
116 * Given a dev_t, return a pointer to the port's hardware state.
117 * Assumes the unit to be valid, so do *not* utilize this in msopen().
118 */
119 #define MS_DEV2MSPORT(d) \
120 (&(((struct ms_softc *)getsoftc(ms_cd, MS_UNIT(d)))->sc_ports[MS_PORT(d)]))
121
122 int
123 msmatch(pdp, cfp, auxp)
124 struct device *pdp;
125 struct cfdata *cfp;
126 void *auxp;
127 {
128 static int ms_matched = 0;
129
130 /* Allow only one instance. */
131 if (!matchname((char *)auxp, "ms") || ms_matched)
132 return 0;
133
134 ms_matched = 1;
135 return 1;
136 }
137
138 void
139 msattach(pdp, dp, auxp)
140 struct device *pdp, *dp;
141 void *auxp;
142 {
143 struct ms_softc *sc = (void *) dp;
144 int i;
145
146 printf("\n");
147 for (i = 0; i < MS_NPORTS; i++) {
148 sc->sc_ports[i].ms_portno = i;
149 callout_init(&sc->sc_ports[i].ms_intr_ch);
150 }
151 }
152
153 /*
154 * Amiga mice are hooked up to one of the two "game" ports, where
155 * the main mouse is usually on the first port, and port 2 can
156 * be used by a joystick. Nevertheless, we support two mouse
157 * devices, /dev/mouse0 and /dev/mouse1 (with a link of /dev/mouse to
158 * the device that represents the port of the mouse in use).
159 */
160
161 /*
162 * enable scanner, called when someone opens the port.
163 */
164 void
165 ms_enable(ms)
166 struct ms_port *ms;
167 {
168
169 /*
170 * use this as flag to the "interrupt" to tell it when to
171 * shut off (when it's reset to 0).
172 */
173 ms->ms_ready = 1;
174
175 callout_reset(&ms->ms_intr_ch, 2, msintr, ms);
176 }
177
178 /*
179 * disable scanner. Just set ms_ready to 0, and after the next
180 * timeout taken, no further timeouts will be initiated.
181 */
182 void
183 ms_disable(ms)
184 struct ms_port *ms;
185 {
186 int s;
187
188 s = splhigh ();
189 ms->ms_ready = 0;
190 /*
191 * sync with the interrupt
192 */
193 tsleep(ms, PZERO - 1, "mouse-disable", 0);
194 splx(s);
195 }
196
197
198 /*
199 * we're emulating a mousesystems serial mouse here..
200 */
201 void
202 msintr(arg)
203 void *arg;
204 {
205 static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 };
206 static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT };
207 struct ms_port *ms = arg;
208 struct firm_event *fe;
209 int mb, ub, d, get, put, any, port;
210 u_char pra, *horc, *verc;
211 u_short pot, count;
212 short dx, dy;
213
214 port = ms->ms_portno;
215
216 horc = ((u_char *) &count) + 1;
217 verc = (u_char *) &count;
218
219 /*
220 * first read the three buttons.
221 */
222 pot = custom.potgor;
223 pra = ciaa.pra;
224 pot >>= port == 0 ? 8 : 12; /* contains right and middle button */
225 pra >>= port == 0 ? 6 : 7; /* contains left button */
226 mb = (pot & 4) / 4 + (pot & 1) * 2 + (pra & 1) * 4;
227 mb ^= 0x07;
228
229 /*
230 * read current values of counter registers
231 */
232 if (port == 0)
233 count = custom.joy0dat;
234 else
235 count = custom.joy1dat;
236
237 /*
238 * take care of wraparound
239 */
240 dx = *horc - ms->ms_horc;
241 if (dx < -127)
242 dx += 255;
243 else if (dx > 127)
244 dx -= 255;
245 dy = *verc - ms->ms_verc;
246 if (dy < -127)
247 dy += 255;
248 else if (dy > 127)
249 dy -= 255;
250
251 /*
252 * remember current values for next scan
253 */
254 ms->ms_horc = *horc;
255 ms->ms_verc = *verc;
256
257 ms->ms_dx = dx;
258 ms->ms_dy = dy;
259 ms->ms_mb = mb;
260
261 if (dx || dy || ms->ms_ub != ms->ms_mb) {
262 /*
263 * We have at least one event (mouse button, delta-X, or
264 * delta-Y; possibly all three, and possibly three separate
265 * button events). Deliver these events until we are out of
266 * changes or out of room. As events get delivered, mark them
267 * `unchanged'.
268 */
269 any = 0;
270 get = ms->ms_events.ev_get;
271 put = ms->ms_events.ev_put;
272 fe = &ms->ms_events.ev_q[put];
273
274 mb = ms->ms_mb;
275 ub = ms->ms_ub;
276 while ((d = mb ^ ub) != 0) {
277 /*
278 * Mouse button change. Convert up to three changes
279 * to the `first' change, and drop it into the event
280 * queue.
281 */
282 if ((++put) % EV_QSIZE == get) {
283 put--;
284 goto out;
285 }
286
287 d = to_one[d - 1]; /* from 1..7 to {1,2,4} */
288 fe->id = to_id[d - 1]; /* from {1,2,4} to ID */
289 fe->value = mb & d ? VKEY_DOWN : VKEY_UP;
290 fe->time = time;
291 fe++;
292
293 if (put >= EV_QSIZE) {
294 put = 0;
295 fe = &ms->ms_events.ev_q[0];
296 }
297 any = 1;
298
299 ub ^= d;
300 }
301 if (ms->ms_dx) {
302 if ((++put) % EV_QSIZE == get) {
303 put--;
304 goto out;
305 }
306
307 fe->id = LOC_X_DELTA;
308 fe->value = ms->ms_dx;
309 fe->time = time;
310 fe++;
311
312 if (put >= EV_QSIZE) {
313 put = 0;
314 fe = &ms->ms_events.ev_q[0];
315 }
316 any = 1;
317
318 ms->ms_dx = 0;
319 }
320 if (ms->ms_dy) {
321 if ((++put) % EV_QSIZE == get) {
322 put--;
323 goto out;
324 }
325
326 fe->id = LOC_Y_DELTA;
327 fe->value = ms->ms_dy;
328 fe->time = time;
329 fe++;
330
331 if (put >= EV_QSIZE) {
332 put = 0;
333 fe = &ms->ms_events.ev_q[0];
334 }
335 any = 1;
336
337 ms->ms_dy = 0;
338 }
339 out:
340 if (any) {
341 ms->ms_ub = ub;
342 ms->ms_events.ev_put = put;
343 EV_WAKEUP(&ms->ms_events);
344 }
345 }
346
347 /*
348 * reschedule handler, or if terminating,
349 * handshake with ms_disable
350 */
351 if (ms->ms_ready)
352 callout_reset(&ms->ms_intr_ch, 2, msintr, ms);
353 else
354 wakeup(ms);
355 }
356
357 int
358 msopen(dev, flags, mode, p)
359 dev_t dev;
360 int flags, mode;
361 struct proc *p;
362 {
363 struct ms_softc *sc;
364 struct ms_port *ms;
365 int unit, port;
366
367 unit = MS_UNIT(dev);
368 sc = (struct ms_softc *)getsoftc(ms_cd, unit);
369
370 if (sc == NULL)
371 return(EXDEV);
372
373 port = MS_PORT(dev);
374 ms = &sc->sc_ports[port];
375
376 if (ms->ms_events.ev_io)
377 return(EBUSY);
378
379 ms->ms_events.ev_io = p;
380 ev_init(&ms->ms_events); /* may cause sleep */
381 ms_enable(ms);
382 return(0);
383 }
384
385 int
386 msclose(dev, flags, mode, p)
387 dev_t dev;
388 int flags, mode;
389 struct proc *p;
390 {
391 struct ms_port *ms;
392
393 ms = MS_DEV2MSPORT(dev);
394
395 ms_disable(ms);
396 ev_fini(&ms->ms_events);
397 ms->ms_events.ev_io = NULL;
398 return(0);
399 }
400
401 int
402 msread(dev, uio, flags)
403 dev_t dev;
404 struct uio *uio;
405 int flags;
406 {
407 struct ms_port *ms;
408
409 ms = MS_DEV2MSPORT(dev);
410
411 return(ev_read(&ms->ms_events, uio, flags));
412 }
413
414 int
415 msioctl(dev, cmd, data, flag, p)
416 dev_t dev;
417 u_long cmd;
418 register caddr_t data;
419 int flag;
420 struct proc *p;
421 {
422 struct ms_port *ms;
423
424 ms = MS_DEV2MSPORT(dev);
425
426 switch (cmd) {
427 case FIONBIO: /* we will remove this someday (soon???) */
428 return(0);
429 case FIOASYNC:
430 ms->ms_events.ev_async = *(int *)data != 0;
431 return(0);
432 case TIOCSPGRP:
433 if (*(int *)data != ms->ms_events.ev_io->p_pgid)
434 return(EPERM);
435 return(0);
436 case VUIDGFORMAT: /* we only do firm_events */
437 *(int *)data = VUID_FIRM_EVENT;
438 return(0);
439 case VUIDSFORMAT:
440 if (*(int *)data != VUID_FIRM_EVENT)
441 return(EINVAL);
442 return(0);
443 }
444 return(ENOTTY);
445 }
446
447 int
448 mspoll(dev, events, p)
449 dev_t dev;
450 int events;
451 struct proc *p;
452 {
453 struct ms_port *ms;
454
455 ms = MS_DEV2MSPORT(dev);
456
457 return(ev_poll(&ms->ms_events, events, p));
458 }
459