ams.c revision 1.5 1 /* $NetBSD: ams.c,v 1.5 1999/02/17 14:56:56 tsubai Exp $ */
2
3 /*
4 * Copyright (C) 1998 Colin Wood
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Colin Wood.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/param.h>
34 #include <sys/device.h>
35 #include <sys/fcntl.h>
36 #include <sys/poll.h>
37 #include <sys/select.h>
38 #include <sys/proc.h>
39 #include <sys/signalvar.h>
40 #include <sys/systm.h>
41
42 #include <dev/wscons/wsconsio.h>
43 #include <dev/wscons/wsmousevar.h>
44
45 #include <machine/autoconf.h>
46 #include <machine/keyboard.h>
47
48 #include <macppc/dev/adbvar.h>
49 #include <macppc/dev/aedvar.h>
50 #include <macppc/dev/amsvar.h>
51
52 #include "aed.h"
53
54 /*
55 * Function declarations.
56 */
57 static int amsmatch __P((struct device *, struct cfdata *, void *));
58 static void amsattach __P((struct device *, struct device *, void *));
59 static void ems_init __P((struct ams_softc *));
60 static void ms_processevent __P((adb_event_t *event, struct ams_softc *));
61
62 /*
63 * Global variables.
64 */
65 extern int kbd_polling; /* Are we polling (Debugger mode)? from kbd.c */
66
67 /*
68 * Local variables.
69 */
70 static volatile int extdms_done; /* Did ADBOp() complete? */
71
72
73 /* Driver definition. */
74 struct cfattach ams_ca = {
75 sizeof(struct ams_softc), amsmatch, amsattach
76 };
77
78 extern struct cfdriver ms_cd;
79
80 int ams_enable __P((void *));
81 int ams_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
82 void ams_disable __P((void *));
83
84 const struct wsmouse_accessops ams_accessops = {
85 ams_enable,
86 ams_ioctl,
87 ams_disable,
88 };
89
90 static int
91 amsmatch(parent, cf, aux)
92 struct device *parent;
93 struct cfdata *cf;
94 void *aux;
95 {
96 struct adb_attach_args * aa_args = (struct adb_attach_args *)aux;
97
98 if (aa_args->origaddr == ADBADDR_MS)
99 return 1;
100 else
101 return 0;
102 }
103
104 static void
105 amsattach(parent, self, aux)
106 struct device *parent, *self;
107 void *aux;
108 {
109 ADBSetInfoBlock adbinfo;
110 struct ams_softc *sc = (struct ams_softc *)self;
111 struct adb_attach_args * aa_args = (struct adb_attach_args *)aux;
112 int error;
113 struct wsmousedev_attach_args a;
114
115 sc->origaddr = aa_args->origaddr;
116 sc->adbaddr = aa_args->adbaddr;
117 sc->handler_id = aa_args->handler_id;
118
119 sc->sc_class = MSCLASS_MOUSE;
120 sc->sc_buttons = 1;
121 sc->sc_res = 100;
122 sc->sc_devid[0] = 0;
123 sc->sc_devid[4] = 0;
124
125 adbinfo.siServiceRtPtr = (Ptr)ms_adbcomplete;
126 adbinfo.siDataAreaAddr = (caddr_t)sc;
127
128 ems_init(sc);
129
130 /* print out the type of mouse we have */
131 switch (sc->handler_id) {
132 case ADBMS_100DPI:
133 printf("%d-button, %d dpi mouse\n", sc->sc_buttons,
134 (int)(sc->sc_res));
135 break;
136 case ADBMS_200DPI:
137 sc->sc_res = 200;
138 printf("%d-button, %d dpi mouse\n", sc->sc_buttons,
139 (int)(sc->sc_res));
140 break;
141 case ADBMS_MSA3:
142 printf("Mouse Systems A3 mouse, %d-button, %d dpi\n",
143 sc->sc_buttons, (int)(sc->sc_res));
144 break;
145 case ADBMS_USPEED:
146 printf("MicroSpeed mouse, default parameters\n");
147 break;
148 case ADBMS_UCONTOUR:
149 printf("Contour mouse, default parameters\n");
150 break;
151 case ADBMS_EXTENDED:
152 if (sc->sc_devid[0] == '\0') {
153 printf("Logitech ");
154 switch (sc->sc_class) {
155 case MSCLASS_MOUSE:
156 printf("MouseMan (non-EMP) mouse");
157 break;
158 case MSCLASS_TRACKBALL:
159 printf("TrackMan (non-EMP) trackball");
160 break;
161 default:
162 printf("non-EMP relative positioning device");
163 break;
164 }
165 printf("\n");
166 } else {
167 printf("EMP ");
168 switch (sc->sc_class) {
169 case MSCLASS_TABLET:
170 printf("tablet");
171 break;
172 case MSCLASS_MOUSE:
173 printf("mouse");
174 break;
175 case MSCLASS_TRACKBALL:
176 printf("trackball");
177 break;
178 default:
179 printf("unknown device");
180 break;
181 }
182 printf(" <%s> %d-button, %d dpi\n", sc->sc_devid,
183 sc->sc_buttons, (int)(sc->sc_res));
184 }
185 break;
186 default:
187 printf("relative positioning device (mouse?) (%d)\n",
188 sc->handler_id);
189 break;
190 }
191 error = SetADBInfo(&adbinfo, sc->adbaddr);
192 #ifdef ADB_DEBUG
193 if (adb_debug)
194 printf("ms: returned %d from SetADBInfo\n", error);
195 #endif
196
197 a.accessops = &ams_accessops;
198 a.accesscookie = sc;
199 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
200 }
201
202
203 /*
204 * Initialize extended mouse support -- probes devices as described
205 * in Inside Macintosh: Devices, Chapter 5 "ADB Manager".
206 *
207 * Extended Mouse Protocol is documented in TechNote HW1:
208 * "ADB - The Untold Story: Space Aliens Ate My Mouse"
209 *
210 * Supports: Extended Mouse Protocol, MicroSpeed Mouse Deluxe,
211 * Mouse Systems A^3 Mouse, Logitech non-EMP MouseMan
212 */
213 void
214 ems_init(sc)
215 struct ams_softc *sc;
216 {
217 int adbaddr, count;
218 short cmd;
219 u_char buffer[9];
220
221 adbaddr = sc->adbaddr;
222 if (sc->origaddr != ADBADDR_MS)
223 return;
224 if (sc->handler_id == ADBMS_USPEED ||
225 sc->handler_id == ADBMS_UCONTOUR) {
226 /* Found MicroSpeed Mouse Deluxe Mac or Contour Mouse */
227 cmd = ((adbaddr<<4)&0xF0)|0x9; /* listen 1 */
228
229 /*
230 * To setup the MicroSpeed or the Contour, it appears
231 * that we can send the following command to the mouse
232 * and then expect data back in the form:
233 * buffer[0] = 4 (bytes)
234 * buffer[1], buffer[2] as std. mouse
235 * buffer[3] = buffer[4] = 0xff when no buttons
236 * are down. When button N down, bit N is clear.
237 * buffer[4]'s locking mask enables a
238 * click to toggle the button down state--sort of
239 * like the "Easy Access" shift/control/etc. keys.
240 * buffer[3]'s alternative speed mask enables using
241 * different speed when the corr. button is down
242 */
243 buffer[0] = 4;
244 buffer[1] = 0x00; /* Alternative speed */
245 buffer[2] = 0x00; /* speed = maximum */
246 buffer[3] = 0x10; /* enable extended protocol,
247 * lower bits = alt. speed mask
248 * = 0000b
249 */
250 buffer[4] = 0x07; /* Locking mask = 0000b,
251 * enable buttons = 0111b
252 */
253 extdms_done = 0;
254 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
255 (Ptr)&extdms_done, cmd);
256 while (!extdms_done)
257 /* busy wait until done */;
258
259 sc->sc_buttons = 3;
260 sc->sc_res = 200;
261 return;
262 }
263 if ((sc->handler_id == ADBMS_100DPI) ||
264 (sc->handler_id == ADBMS_200DPI)) {
265 /* found a mouse */
266 cmd = ((adbaddr << 4) & 0xf0) | 0x3;
267
268 extdms_done = 0;
269 cmd = (cmd & 0xf3) | 0x0c; /* talk command */
270 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
271 (Ptr)&extdms_done, cmd);
272
273 /* Wait until done, but no more than 2 secs */
274 count = 40000;
275 while (!extdms_done && count-- > 0)
276 delay(50);
277
278 if (!extdms_done) {
279 #ifdef ADB_DEBUG
280 if (adb_debug)
281 printf("adb: extdms_init timed out\n");
282 #endif
283 return;
284 }
285
286 /* Attempt to initialize Extended Mouse Protocol */
287 buffer[2] = '\004'; /* make handler ID 4 */
288 extdms_done = 0;
289 cmd = (cmd & 0xf3) | 0x08; /* listen command */
290 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
291 (Ptr)&extdms_done, cmd);
292 while (!extdms_done)
293 /* busy wait until done */;
294
295 /*
296 * Check to see if successful, if not
297 * try to initialize it as other types
298 */
299 cmd = ((adbaddr << 4) & 0xf0) | 0x3;
300 extdms_done = 0;
301 cmd = (cmd & 0xf3) | 0x0c; /* talk command */
302 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
303 (Ptr)&extdms_done, cmd);
304 while (!extdms_done)
305 /* busy wait until done */;
306
307 if (buffer[2] == ADBMS_EXTENDED) {
308 sc->handler_id = ADBMS_EXTENDED;
309 extdms_done = 0;
310 /* talk register 1 */
311 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
312 (Ptr)&extdms_done, (adbaddr << 4) | 0xd);
313 while (!extdms_done)
314 /* busy-wait until done */;
315 if (buffer[0] == 8) {
316 /* we have a true EMP device */
317 sc->sc_class = buffer[7];
318 sc->sc_buttons = buffer[8];
319 sc->sc_res = (int)*(short *)&buffer[5];
320 bcopy(&(buffer[1]), sc->sc_devid, 4);
321 } else if (buffer[1] == 0x9a &&
322 ((buffer[2] == 0x20) || (buffer[2] == 0x21))) {
323 /*
324 * Set up non-EMP Mouseman/Trackman to put
325 * button bits in 3rd byte instead of sending
326 * via pseudo keyboard device.
327 */
328 extdms_done = 0;
329 /* listen register 1 */
330 buffer[0]=2;
331 buffer[1]=0x00;
332 buffer[2]=0x81;
333 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
334 (Ptr)&extdms_done, (adbaddr << 4) | 0x9);
335 while (!extdms_done)
336 /* busy-wait until done */;
337 extdms_done = 0;
338 /* listen register 1 */
339 buffer[0]=2;
340 buffer[1]=0x01;
341 buffer[2]=0x81;
342 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
343 (Ptr)&extdms_done, (adbaddr << 4) | 0x9);
344 while (!extdms_done)
345 /* busy-wait until done */;
346 extdms_done = 0;
347 /* listen register 1 */
348 buffer[0]=2;
349 buffer[1]=0x02;
350 buffer[2]=0x81;
351 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
352 (Ptr)&extdms_done, (adbaddr << 4) | 0x9);
353 while (!extdms_done)
354 /* busy-wait until done */;
355 extdms_done = 0;
356 /* listen register 1 */
357 buffer[0]=2;
358 buffer[1]=0x03;
359 buffer[2]=0x38;
360 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
361 (Ptr)&extdms_done, (adbaddr << 4) | 0x9);
362 while (!extdms_done)
363 /* busy-wait until done */;
364 sc->sc_buttons = 3;
365 sc->sc_res = 400;
366 if (buffer[2] == 0x21)
367 sc->sc_class = MSCLASS_TRACKBALL;
368 else
369 sc->sc_class = MSCLASS_MOUSE;
370 } else
371 /* unknown device? */;
372 } else {
373 /* Attempt to initialize as an A3 mouse */
374 buffer[2] = 0x03; /* make handler ID 3 */
375 extdms_done = 0;
376 cmd = (cmd & 0xf3) | 0x08; /* listen command */
377 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
378 (Ptr)&extdms_done, cmd);
379 while (!extdms_done)
380 /* busy wait until done */;
381
382 /*
383 * Check to see if successful, if not
384 * try to initialize it as other types
385 */
386 cmd = ((adbaddr << 4) & 0xf0) | 0x3;
387 extdms_done = 0;
388 cmd = (cmd & 0xf3) | 0x0c; /* talk command */
389 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
390 (Ptr)&extdms_done, cmd);
391 while (!extdms_done)
392 /* busy wait until done */;
393
394 if (buffer[2] == ADBMS_MSA3) {
395 sc->handler_id = ADBMS_MSA3;
396 /* Initialize as above */
397 cmd = ((adbaddr << 4) & 0xF0) | 0xA;
398 /* listen 2 */
399 buffer[0] = 3;
400 buffer[1] = 0x00;
401 /* Irrelevant, buffer has 0x77 */
402 buffer[2] = 0x07;
403 /*
404 * enable 3 button mode = 0111b,
405 * speed = normal
406 */
407 extdms_done = 0;
408 ADBOp((Ptr)buffer, (Ptr)extdms_complete,
409 (Ptr)&extdms_done, cmd);
410 while (!extdms_done)
411 /* busy wait until done */;
412 sc->sc_buttons = 3;
413 sc->sc_res = 300;
414 } else {
415 /* No special support for this mouse */
416 }
417 }
418 }
419 }
420
421 /*
422 * Handle putting the mouse data received from the ADB into
423 * an ADB event record.
424 */
425 void
426 ms_adbcomplete(buffer, data_area, adb_command)
427 caddr_t buffer;
428 caddr_t data_area;
429 int adb_command;
430 {
431 adb_event_t event;
432 struct ams_softc *msc;
433 int adbaddr;
434 #ifdef ADB_DEBUG
435 int i;
436
437 if (adb_debug)
438 printf("adb: transaction completion\n");
439 #endif
440
441 adbaddr = (adb_command & 0xf0) >> 4;
442 msc = (struct ams_softc *)data_area;
443
444 if ((msc->handler_id == ADBMS_EXTENDED) && (msc->sc_devid[0] == 0)) {
445 /* massage the data to look like EMP data */
446 if ((buffer[3] & 0x04) == 0x04)
447 buffer[1] &= 0x7f;
448 else
449 buffer[1] |= 0x80;
450 if ((buffer[3] & 0x02) == 0x02)
451 buffer[2] &= 0x7f;
452 else
453 buffer[2] |= 0x80;
454 if ((buffer[3] & 0x01) == 0x01)
455 buffer[3] = 0x00;
456 else
457 buffer[3] = 0x80;
458 }
459
460 event.addr = adbaddr;
461 event.hand_id = msc->handler_id;
462 event.def_addr = msc->origaddr;
463 event.byte_count = buffer[0];
464 memcpy(event.bytes, buffer + 1, event.byte_count);
465
466 #ifdef ADB_DEBUG
467 if (adb_debug) {
468 printf("ms: from %d at %d (org %d) %d:", event.addr,
469 event.hand_id, event.def_addr, buffer[0]);
470 for (i = 1; i <= buffer[0]; i++)
471 printf(" %x", buffer[i]);
472 printf("\n");
473 }
474 #endif
475
476 microtime(&event.timestamp);
477
478 ms_processevent(&event, msc);
479 }
480
481 /*
482 * Given a mouse ADB event, record the button settings, calculate the
483 * x- and y-axis motion, and handoff the event to the appropriate subsystem.
484 */
485 static void
486 ms_processevent(event, msc)
487 adb_event_t *event;
488 struct ams_softc *msc;
489 {
490 adb_event_t new_event;
491 int i, button_bit, max_byte, mask, buttons;
492
493 new_event = *event;
494 buttons = 0;
495
496 /*
497 * This should handle both plain ol' Apple mice and mice
498 * that claim to support the Extended Apple Mouse Protocol.
499 */
500 max_byte = event->byte_count;
501 button_bit = 1;
502 switch (event->hand_id) {
503 case ADBMS_USPEED:
504 case ADBMS_UCONTOUR:
505 /* MicroSpeed mouse and Contour mouse */
506 if (max_byte == 4)
507 buttons = (~event->bytes[2]) & 0xff;
508 else
509 buttons = (event->bytes[0] & 0x80) ? 0 : 1;
510 break;
511 case ADBMS_MSA3:
512 /* Mouse Systems A3 mouse */
513 if (max_byte == 3)
514 buttons = (~event->bytes[2]) & 0x07;
515 else
516 buttons = (event->bytes[0] & 0x80) ? 0 : 1;
517 break;
518 default:
519 /* Classic Mouse Protocol (up to 2 buttons) */
520 for (i = 0; i < 2; i++, button_bit <<= 1)
521 /* 0 when button down */
522 if (!(event->bytes[i] & 0x80))
523 buttons |= button_bit;
524 else
525 buttons &= ~button_bit;
526 /* Extended Protocol (up to 6 more buttons) */
527 for (mask = 0x80; i < max_byte;
528 i += (mask == 0x80), button_bit <<= 1) {
529 /* 0 when button down */
530 if (!(event->bytes[i] & mask))
531 buttons |= button_bit;
532 else
533 buttons &= ~button_bit;
534 mask = ((mask >> 4) & 0xf)
535 | ((mask & 0xf) << 4);
536 }
537 break;
538 }
539 new_event.u.m.buttons = msc->sc_mb | buttons;
540 new_event.u.m.dx = ((signed int) (event->bytes[1] & 0x3f)) -
541 ((event->bytes[1] & 0x40) ? 64 : 0);
542 new_event.u.m.dy = ((signed int) (event->bytes[0] & 0x3f)) -
543 ((event->bytes[0] & 0x40) ? 64 : 0);
544
545 if (msc->sc_wsmousedev)
546 wsmouse_input(msc->sc_wsmousedev, new_event.u.m.buttons,
547 new_event.u.m.dx, -new_event.u.m.dy, 0);
548 #if NAED > 0
549 aed_input(&new_event);
550 #endif
551 }
552
553 void
554 extdms_complete(buffer, compdata, cmd)
555 caddr_t buffer, compdata;
556 int cmd;
557 {
558 long *p = (long *)compdata;
559
560 *p= -1;
561 }
562
563 int
564 ams_enable(v)
565 void *v;
566 {
567 return 0;
568 }
569
570 int
571 ams_ioctl(v, cmd, data, flag, p)
572 void *v;
573 u_long cmd;
574 caddr_t data;
575 int flag;
576 struct proc *p;
577 {
578 return -1;
579 }
580
581 void
582 ams_disable(v)
583 void *v;
584 {
585 }
586