ms.c revision 1.12 1 /* $NetBSD: ms.c,v 1.12 2002/10/23 09:10:53 jdolecek Exp $ */
2
3 /*
4 * Copyright (c) 1995 Leo Weppelman.
5 * All rights reserved.
6 *
7 * based on:
8 *
9 * Copyright (c) 1992, 1993
10 * The Regents of the University of California. All rights reserved.
11 *
12 * This software was developed by the Computer Systems Engineering group
13 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
14 * contributed to Berkeley.
15 *
16 * All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Lawrence Berkeley Laboratory.
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
23 * are met:
24 * 1. Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 * 3. All advertising materials mentioning features or use of this software
30 * must display the following acknowledgement:
31 * This product includes software developed by the University of
32 * California, Berkeley and its contributors.
33 * 4. Neither the name of the University nor the names of its contributors
34 * may be used to endorse or promote products derived from this software
35 * without specific prior written permission.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 *
49 * @(#)ms.c 8.1 (Berkeley) 6/11/93
50 *
51 * Header: ms.c,v 1.5 92/11/26 01:28:47 torek Exp (LBL)
52 */
53
54 /*
55 * Mouse driver.
56 */
57
58 #include <sys/param.h>
59 #include <sys/conf.h>
60 #include <sys/ioctl.h>
61 #include <sys/kernel.h>
62 #include <sys/proc.h>
63 #include <sys/systm.h>
64 #include <sys/callout.h>
65 #include <sys/tty.h>
66 #include <sys/signalvar.h>
67
68 #include <machine/msioctl.h>
69 #include <atari/dev/event_var.h>
70 #include <atari/dev/vuid_event.h>
71 #include <atari/dev/kbdvar.h>
72 #include <atari/dev/msvar.h>
73
74 #include "mouse.h"
75 #if NMOUSE > 0
76
77 /* there's really no more physical ports on an atari. */
78 #if NMOUSE > 1
79 #undef NMOUSE
80 #define NMOUSE 1
81 #endif
82
83 typedef void (*FPV) __P((void *));
84
85 static struct ms_softc ms_softc[NMOUSE];
86
87 dev_type_open(msopen);
88 dev_type_close(msclose);
89 dev_type_read(msread);
90 dev_type_ioctl(msioctl);
91 dev_type_poll(mspoll);
92 dev_type_kqfilter(mskqfilter);
93
94 const struct cdevsw ms_cdevsw = {
95 msopen, msclose, msread, nowrite, msioctl,
96 nostop, notty, mspoll, nommap, mskqfilter,
97 };
98
99 static void ms_3b_delay __P((struct ms_softc *));
100
101 int
102 mouseattach(cnt)
103 int cnt;
104 {
105 printf("1 mouse configured\n");
106 ms_softc[0].ms_emul3b = 1;
107 callout_init(&ms_softc[0].ms_delay_ch);
108 return(NMOUSE);
109 }
110
111 static void
112 ms_3b_delay(ms)
113 struct ms_softc *ms;
114 {
115 REL_MOUSE rel_ms;
116
117 rel_ms.id = TIMEOUT_ID;
118 rel_ms.dx = rel_ms.dy = 0;
119 mouse_soft(&rel_ms, sizeof(rel_ms), KBD_TIMEO_PKG);
120 }
121 /*
122 * Note that we are called from the keyboard software interrupt!
123 */
124 void
125 mouse_soft(rel_ms, size, type)
126 REL_MOUSE *rel_ms;
127 int size, type;
128 {
129 struct ms_softc *ms = &ms_softc[0];
130 struct firm_event *fe, *fe2;
131 REL_MOUSE fake_mouse;
132 int get, put;
133 int sps;
134 u_char mbut, bmask;
135 int flush_buttons;
136
137 if (ms->ms_events.ev_io == NULL)
138 return;
139
140 switch (type) {
141 case KBD_JOY1_PKG:
142 /*
143 * Ignore if in emulation mode
144 */
145 if (ms->ms_emul3b)
146 return;
147
148 /*
149 * There are some mice that have their middle button
150 * wired to the 'up' bit of joystick 1....
151 * Simulate a mouse packet with dx = dy = 0, the middle
152 * button state set by UP and the other buttons unchanged.
153 * Flush all button changes.
154 */
155 flush_buttons = 1;
156 fake_mouse.id = (rel_ms->dx & 1 ? 4 : 0) | (ms->ms_buttons & 3);
157 fake_mouse.dx = fake_mouse.dy = 0;
158 rel_ms = &fake_mouse;
159 break;
160 case KBD_TIMEO_PKG:
161 /*
162 * Timeout package. No button changes and no movement.
163 * Flush all button changes.
164 */
165 flush_buttons = 1;
166 fake_mouse.id = ms->ms_buttons;
167 fake_mouse.dx = fake_mouse.dy = 0;
168 rel_ms = &fake_mouse;
169 break;
170 case KBD_RMS_PKG:
171 /*
172 * Normal mouse package. Always copy the middle button
173 * status. The emulation code decides if button changes
174 * must be flushed.
175 */
176 rel_ms->id = (ms->ms_buttons & 4) | (rel_ms->id & 3);
177 flush_buttons = (ms->ms_emul3b) ? 0 : 1;
178 break;
179 default:
180 return;
181 }
182
183 sps = splev();
184 get = ms->ms_events.ev_get;
185 put = ms->ms_events.ev_put;
186 fe = &ms->ms_events.ev_q[put];
187
188 if ((type != KBD_TIMEO_PKG) && ms->ms_emul3b && ms->ms_bq_idx)
189 callout_stop(&ms->ms_delay_ch);
190
191 /*
192 * Button states are encoded in the lower 3 bits of 'id'
193 */
194 if (!(mbut = (rel_ms->id ^ ms->ms_buttons)) && (put != get)) {
195 /*
196 * Compact dx/dy messages. Always generate an event when
197 * a button is pressed or the event queue is empty.
198 */
199 ms->ms_dx += rel_ms->dx;
200 ms->ms_dy += rel_ms->dy;
201 goto out;
202 }
203 rel_ms->dx += ms->ms_dx;
204 rel_ms->dy += ms->ms_dy;
205 ms->ms_dx = ms->ms_dy = 0;
206
207 /*
208 * Output location events _before_ button events ie. make sure
209 * the button is pressed at the correct location.
210 */
211 if (rel_ms->dx) {
212 if ((++put) % EV_QSIZE == get) {
213 put--;
214 goto out;
215 }
216 fe->id = LOC_X_DELTA;
217 fe->value = rel_ms->dx;
218 fe->time = time;
219 if (put >= EV_QSIZE) {
220 put = 0;
221 fe = &ms->ms_events.ev_q[0];
222 }
223 else fe++;
224 }
225 if (rel_ms->dy) {
226 if ((++put) % EV_QSIZE == get) {
227 put--;
228 goto out;
229 }
230 fe->id = LOC_Y_DELTA;
231 fe->value = rel_ms->dy;
232 fe->time = time;
233 if (put >= EV_QSIZE) {
234 put = 0;
235 fe = &ms->ms_events.ev_q[0];
236 }
237 else fe++;
238 }
239 if (mbut && (type != KBD_TIMEO_PKG)) {
240 for (bmask = 1; bmask < 0x08; bmask <<= 1) {
241 if (!(mbut & bmask))
242 continue;
243 fe2 = &ms->ms_bq[ms->ms_bq_idx++];
244 if (bmask == 1)
245 fe2->id = MS_RIGHT;
246 else if (bmask == 2)
247 fe2->id = MS_LEFT;
248 else fe2->id = MS_MIDDLE;
249 fe2->value = rel_ms->id & bmask ? VKEY_DOWN : VKEY_UP;
250 fe2->time = time;
251 }
252 }
253
254 /*
255 * Handle 3rd button emulation.
256 */
257 if (ms->ms_emul3b && ms->ms_bq_idx && (type != KBD_TIMEO_PKG)) {
258 /*
259 * If the middle button is pressed, any change to
260 * one of the other buttons releases all.
261 */
262 if ((ms->ms_buttons & 4) && (mbut & 3)) {
263 ms->ms_bq[0].id = MS_MIDDLE;
264 ms->ms_bq_idx = 1;
265 rel_ms->id = 0;
266 flush_buttons = 1;
267 goto out;
268 }
269 if (ms->ms_bq_idx == 2) {
270 if (ms->ms_bq[0].value == ms->ms_bq[1].value) {
271 /* Must be 2 button presses! */
272 ms->ms_bq[0].id = MS_MIDDLE;
273 ms->ms_bq_idx = 1;
274 rel_ms->id = 7;
275 }
276 }
277 else if (ms->ms_bq[0].value == VKEY_DOWN) {
278 callout_reset(&ms->ms_delay_ch, 10,
279 (FPV)ms_3b_delay, (void *)ms);
280 goto out;
281 }
282 flush_buttons = 1;
283 }
284 out:
285 if (flush_buttons) {
286 int i;
287
288 for (i = 0; i < ms->ms_bq_idx; i++) {
289 if ((++put) % EV_QSIZE == get) {
290 ms->ms_bq_idx = 0;
291 put--;
292 goto out;
293 }
294 *fe = ms->ms_bq[i];
295 if (put >= EV_QSIZE) {
296 put = 0;
297 fe = &ms->ms_events.ev_q[0];
298 }
299 else fe++;
300 }
301 ms->ms_bq_idx = 0;
302 }
303 ms->ms_events.ev_put = put;
304 ms->ms_buttons = rel_ms->id;
305 splx(sps);
306 EV_WAKEUP(&ms->ms_events);
307 }
308
309 int
310 msopen(dev, flags, mode, p)
311 dev_t dev;
312 int flags, mode;
313 struct proc *p;
314 {
315 u_char report_ms_joy[] = { 0x14, 0x08 };
316 struct ms_softc *ms;
317 int unit;
318
319 unit = minor(dev);
320 ms = &ms_softc[unit];
321
322 if (unit >= NMOUSE)
323 return(EXDEV);
324
325 if (ms->ms_events.ev_io)
326 return(EBUSY);
327
328 ms->ms_events.ev_io = p;
329 ms->ms_dx = ms->ms_dy = 0;
330 ms->ms_buttons = 0;
331 ms->ms_bq[0].id = ms->ms_bq[1].id = 0;
332 ms->ms_bq_idx = 0;
333 ev_init(&ms->ms_events); /* may cause sleep */
334
335 /*
336 * Enable mouse reporting.
337 */
338 kbd_write(report_ms_joy, sizeof(report_ms_joy));
339 return(0);
340 }
341
342 int
343 msclose(dev, flags, mode, p)
344 dev_t dev;
345 int flags, mode;
346 struct proc *p;
347 {
348 u_char disable_ms_joy[] = { 0x12, 0x1a };
349 int unit;
350 struct ms_softc *ms;
351
352 unit = minor (dev);
353 ms = &ms_softc[unit];
354
355 /*
356 * Turn off mouse interrogation.
357 */
358 kbd_write(disable_ms_joy, sizeof(disable_ms_joy));
359 ev_fini(&ms->ms_events);
360 ms->ms_events.ev_io = NULL;
361 return(0);
362 }
363
364 int
365 msread(dev, uio, flags)
366 dev_t dev;
367 struct uio *uio;
368 int flags;
369 {
370 struct ms_softc *ms;
371
372 ms = &ms_softc[minor(dev)];
373 return(ev_read(&ms->ms_events, uio, flags));
374 }
375
376 int
377 msioctl(dev, cmd, data, flag, p)
378 dev_t dev;
379 u_long cmd;
380 register caddr_t data;
381 int flag;
382 struct proc *p;
383 {
384 struct ms_softc *ms;
385 int unit;
386
387 unit = minor(dev);
388 ms = &ms_softc[unit];
389
390 switch (cmd) {
391 case MIOCS3B_EMUL:
392 ms->ms_emul3b = (*(int *)data != 0) ? 1 : 0;
393 return (0);
394 case MIOCG3B_EMUL:
395 *(int *)data = ms->ms_emul3b;
396 return (0);
397 case FIONBIO: /* we will remove this someday (soon???) */
398 return(0);
399 case FIOASYNC:
400 ms->ms_events.ev_async = *(int *)data != 0;
401 return(0);
402 case TIOCSPGRP:
403 if (*(int *)data != ms->ms_events.ev_io->p_pgid)
404 return(EPERM);
405 return(0);
406 case VUIDGFORMAT: /* we only do firm_events */
407 *(int *)data = VUID_FIRM_EVENT;
408 return(0);
409 case VUIDSFORMAT:
410 if (*(int *)data != VUID_FIRM_EVENT)
411 return(EINVAL);
412 return(0);
413 }
414 return(ENOTTY);
415 }
416
417 int
418 mspoll(dev, events, p)
419 dev_t dev;
420 int events;
421 struct proc *p;
422 {
423 struct ms_softc *ms;
424
425 ms = &ms_softc[minor(dev)];
426 return(ev_poll(&ms->ms_events, events, p));
427 }
428
429 int
430 mskqfilter(dev_t dev, struct knote *kn)
431 {
432 struct ms_softc *ms;
433
434 ms = &ms_softc[minor(dev)];
435 return (ev_kqfilter(&ms->ms_events, kn));
436 }
437 #endif /* NMOUSE > 0 */
438