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