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