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