xref: /netbsd/sys/arch/atari/dev/ms.c (revision c4a72b64)
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