1 /* $NetBSD: ams.c,v 1.18 2007/03/04 06:00:07 christos Exp $ */
4 * Copyright (C) 1998 Colin Wood
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: ams.c,v 1.18 2007/03/04 06:00:07 christos Exp $");
36 #include <sys/param.h>
37 #include <sys/device.h>
38 #include <sys/fcntl.h>
40 #include <sys/select.h>
42 #include <sys/signalvar.h>
43 #include <sys/systm.h>
48 #include <dev/wscons/wsconsio.h>
49 #include <dev/wscons/wsmousevar.h>
51 #include <machine/autoconf.h>
52 #include <machine/keyboard.h>
54 #include <mac68k/mac68k/macrom.h>
55 #include <mac68k/dev/adbvar.h>
56 #include <mac68k/dev/aedvar.h>
57 #include <mac68k/dev/amsvar.h>
60 * Function declarations.
62 static int amsmatch(struct device
*, struct cfdata
*, void *);
63 static void amsattach(struct device
*, struct device
*, void *);
64 static void ems_init(struct ams_softc
*);
65 static void ms_processevent(adb_event_t
*, struct ams_softc
*);
70 extern int kbd_polling
; /* Are we polling (Debugger mode)? from kbd.c */
76 /* Driver definition. */
77 CFATTACH_DECL(ams
, sizeof(struct ams_softc
),
78 amsmatch
, amsattach
, NULL
, NULL
);
80 extern struct cfdriver ams_cd
;
82 int ams_enable(void *);
83 int ams_ioctl(void *, u_long
, void *, int, struct lwp
*);
84 void ams_disable(void *);
86 const struct wsmouse_accessops ams_accessops
= {
93 amsmatch(struct device
*parent
, struct cfdata
*cf
, void *aux
)
95 struct adb_attach_args
* aa_args
= (struct adb_attach_args
*)aux
;
97 if (aa_args
->origaddr
== ADBADDR_MS
)
104 amsattach(struct device
*parent
, struct device
*self
, void *aux
)
106 ADBSetInfoBlock adbinfo
;
107 struct ams_softc
*sc
= (struct ams_softc
*)self
;
108 struct adb_attach_args
* aa_args
= (struct adb_attach_args
*)aux
;
111 struct wsmousedev_attach_args a
;
114 sc
->origaddr
= aa_args
->origaddr
;
115 sc
->adbaddr
= aa_args
->adbaddr
;
116 sc
->handler_id
= aa_args
->handler_id
;
118 sc
->sc_class
= MSCLASS_MOUSE
;
124 adbinfo
.siServiceRtPtr
= (Ptr
)adb_ms_asmcomplete
;
125 adbinfo
.siDataAreaAddr
= (void *)sc
;
129 /* print out the type of mouse we have */
130 switch (sc
->handler_id
) {
132 printf("%d-button, %d dpi mouse\n", sc
->sc_buttons
,
137 printf("%d-button, %d dpi mouse\n", sc
->sc_buttons
,
141 printf("Mouse Systems A3 mouse, %d-button, %d dpi\n",
142 sc
->sc_buttons
, (int)(sc
->sc_res
));
145 printf("MicroSpeed mouse, default parameters\n");
148 printf("Contour mouse, default parameters\n");
151 if (sc
->sc_devid
[0] == '\0') {
153 switch (sc
->sc_class
) {
155 printf("MouseMan (non-EMP) mouse");
157 case MSCLASS_TRACKBALL
:
158 printf("TrackMan (non-EMP) trackball");
161 printf("non-EMP relative positioning device");
167 switch (sc
->sc_class
) {
174 case MSCLASS_TRACKBALL
:
178 printf("unknown device");
181 printf(" <%s> %d-button, %d dpi\n", sc
->sc_devid
,
182 sc
->sc_buttons
, (int)(sc
->sc_res
));
186 printf("relative positioning device (mouse?) (%d)\n",
190 error
= SetADBInfo(&adbinfo
, sc
->adbaddr
);
193 printf("ams: returned %d from SetADBInfo\n", error
);
197 a
.accessops
= &ams_accessops
;
199 sc
->sc_wsmousedev
= config_found(self
, &a
, wsmousedevprint
);
205 * Initialize extended mouse support -- probes devices as described
206 * in Inside Macintosh: Devices, Chapter 5 "ADB Manager".
208 * Extended Mouse Protocol is documented in TechNote HW1:
209 * "ADB - The Untold Story: Space Aliens Ate My Mouse"
211 * Supports: Extended Mouse Protocol, MicroSpeed Mouse Deluxe,
212 * Mouse Systems A^3 Mouse, Logitech non-EMP MouseMan
215 ems_init(struct ams_softc
*sc
)
221 adbaddr
= sc
->adbaddr
;
222 if (sc
->origaddr
!= ADBADDR_MS
)
224 if (sc
->handler_id
== ADBMS_USPEED
||
225 sc
->handler_id
== ADBMS_UCONTOUR
) {
226 /* Found MicroSpeed Mouse Deluxe Mac or Contour Mouse */
227 cmd
= ADBLISTEN(adbaddr
, 1);
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
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
250 buffer
[4] = 0x07; /* Locking mask = 0000b,
251 * enable buttons = 0111b
253 adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
);
259 if ((sc
->handler_id
== ADBMS_100DPI
) ||
260 (sc
->handler_id
== ADBMS_200DPI
)) {
262 cmd
= ADBTALK(adbaddr
, 3);
263 if (adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
)) {
266 printf("adb: ems_init timed out\n");
271 /* Attempt to initialize Extended Mouse Protocol */
272 buffer
[2] = 4; /* make handler ID 4 */
273 cmd
= ADBLISTEN(adbaddr
, 3);
274 if (adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
)) {
277 printf("adb: ems_init timed out\n");
283 * Check to see if successful, if not
284 * try to initialize it as other types
286 cmd
= ADBTALK(adbaddr
, 3);
287 if (adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
) == 0 &&
288 buffer
[2] == ADBMS_EXTENDED
) {
289 sc
->handler_id
= ADBMS_EXTENDED
;
290 cmd
= ADBTALK(adbaddr
, 1);
291 if (adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
)) {
294 printf("adb: ems_init timed out\n");
296 } else if (buffer
[0] == 8) {
297 /* we have a true EMP device */
298 sc
->sc_class
= buffer
[7];
299 sc
->sc_buttons
= buffer
[8];
300 sc
->sc_res
= (int)*(short *)&buffer
[5];
301 memcpy(sc
->sc_devid
, &(buffer
[1]), 4);
302 } else if (buffer
[1] == 0x9a &&
303 ((buffer
[2] == 0x20) || (buffer
[2] == 0x21))) {
305 * Set up non-EMP Mouseman/Trackman to put
306 * button bits in 3rd byte instead of sending
307 * via pseudo keyboard device.
309 cmd
= ADBLISTEN(adbaddr
, 1);
313 adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
);
315 cmd
= ADBLISTEN(adbaddr
, 1);
319 adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
);
321 cmd
= ADBLISTEN(adbaddr
, 1);
325 adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
);
327 cmd
= ADBLISTEN(adbaddr
, 1);
331 adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
);
335 if (buffer
[2] == 0x21)
336 sc
->sc_class
= MSCLASS_TRACKBALL
;
338 sc
->sc_class
= MSCLASS_MOUSE
;
340 /* unknown device? */;
342 /* Attempt to initialize as an A3 mouse */
343 buffer
[2] = 0x03; /* make handler ID 3 */
344 cmd
= ADBLISTEN(adbaddr
, 3);
345 if (adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
)) {
348 printf("adb: ems_init timed out\n");
354 * Check to see if successful, if not
355 * try to initialize it as other types
357 cmd
= ADBTALK(adbaddr
, 3);
358 if (adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
) == 0
359 && buffer
[2] == ADBMS_MSA3
) {
360 sc
->handler_id
= ADBMS_MSA3
;
361 /* Initialize as above */
362 cmd
= ADBLISTEN(adbaddr
, 2);
366 /* Irrelevant, buffer has 0x77 */
369 * enable 3 button mode = 0111b,
372 adb_op_sync((Ptr
)buffer
, (Ptr
)0, (Ptr
)0, cmd
);
376 /* No special support for this mouse */
383 * Handle putting the mouse data received from the ADB into
384 * an ADB event record.
387 ms_adbcomplete(void *buffer
, void *data_area
, int adb_command
)
390 struct ams_softc
*amsc
;
391 uint8_t *buf
= (uint8_t*)buffer
;
397 printf("adb: transaction completion\n");
400 adbaddr
= ADB_CMDADDR(adb_command
);
401 amsc
= (struct ams_softc
*)data_area
;
403 if ((amsc
->handler_id
== ADBMS_EXTENDED
) && (amsc
->sc_devid
[0] == 0)) {
404 /* massage the data to look like EMP data */
405 if ((buf
[3] & 0x04) == 0x04)
409 if ((buf
[3] & 0x02) == 0x02)
413 if ((buf
[3] & 0x01) == 0x01)
419 event
.addr
= adbaddr
;
420 event
.hand_id
= amsc
->handler_id
;
421 event
.def_addr
= amsc
->origaddr
;
422 event
.byte_count
= buf
[0];
423 memcpy(event
.bytes
, buf
+ 1, event
.byte_count
);
427 printf("ams: from %d at %d (org %d) %u:", event
.addr
,
428 event
.hand_id
, event
.def_addr
, buf
[0]);
429 for (i
= 1; i
<= buf
[0]; i
++)
430 printf(" %x", buf
[i
]);
435 microtime(&event
.timestamp
);
437 ms_processevent(&event
, amsc
);
441 * Given a mouse ADB event, record the button settings, calculate the
442 * x- and y-axis motion, and handoff the event to the appropriate subsystem.
445 ms_processevent(adb_event_t
*event
, struct ams_softc
*amsc
)
447 adb_event_t new_event
;
448 int i
, button_bit
, max_byte
, mask
, buttons
;
454 * This should handle both plain ol' Apple mice and mice
455 * that claim to support the Extended Apple Mouse Protocol.
457 max_byte
= event
->byte_count
;
459 switch (event
->hand_id
) {
462 /* MicroSpeed mouse and Contour mouse */
464 buttons
= (~event
->bytes
[2]) & 0xff;
466 buttons
= (event
->bytes
[0] & 0x80) ? 0 : 1;
469 /* Mouse Systems A3 mouse */
471 buttons
= (~event
->bytes
[2]) & 0x07;
473 buttons
= (event
->bytes
[0] & 0x80) ? 0 : 1;
476 /* Classic Mouse Protocol (up to 2 buttons) */
477 for (i
= 0; i
< 2; i
++, button_bit
<<= 1)
478 /* 0 when button down */
479 if (!(event
->bytes
[i
] & 0x80))
480 buttons
|= button_bit
;
482 buttons
&= ~button_bit
;
483 /* Extended Protocol (up to 6 more buttons) */
484 for (mask
= 0x80; i
< max_byte
;
485 i
+= (mask
== 0x80), button_bit
<<= 1) {
486 /* 0 when button down */
487 if (!(event
->bytes
[i
] & mask
))
488 buttons
|= button_bit
;
490 buttons
&= ~button_bit
;
491 mask
= ((mask
>> 4) & 0xf)
492 | ((mask
& 0xf) << 4);
496 new_event
.u
.m
.buttons
= amsc
->sc_mb
| buttons
;
497 new_event
.u
.m
.dx
= ((signed int) (event
->bytes
[1] & 0x3f)) -
498 ((event
->bytes
[1] & 0x40) ? 64 : 0);
499 new_event
.u
.m
.dy
= ((signed int) (event
->bytes
[0] & 0x3f)) -
500 ((event
->bytes
[0] & 0x40) ? 64 : 0);
503 if (!aed_input(&new_event
))
506 if (amsc
->sc_wsmousedev
!= NULL
) /* wsmouse is attached? */
507 wsmouse_input(amsc
->sc_wsmousedev
,
508 new_event
.u
.m
.buttons
,
509 new_event
.u
.m
.dx
, new_event
.u
.m
.dy
, 0, 0,
510 WSMOUSE_INPUT_DELTA
);
523 ams_ioctl(void *v
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
525 return (EPASSTHROUGH
);