adb_ms.c revision 1.4 1 /* $NetBSD: adb_ms.c,v 1.4 2007/02/10 03:38:47 tsutsui 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/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: adb_ms.c,v 1.4 2007/02/10 03:38:47 tsutsui Exp $");
35
36 #include <sys/param.h>
37 #include <sys/device.h>
38 #include <sys/fcntl.h>
39 #include <sys/poll.h>
40 #include <sys/select.h>
41 #include <sys/proc.h>
42 #include <sys/signalvar.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/sysctl.h>
46
47 #include <machine/autoconf.h>
48
49 #include <dev/wscons/wsconsio.h>
50 #include <dev/wscons/wsmousevar.h>
51
52 #include <machine/adbsys.h>
53 #include <dev/adb/adbvar.h>
54
55 #include "adbdebug.h"
56
57 #ifdef ADBMS_DEBUG
58 #define DPRINTF printf
59 #else
60 #define DPRINTF while (0) printf
61 #endif
62
63 /*
64 * State info, per mouse instance.
65 */
66 struct adbms_softc {
67 struct device sc_dev;
68 struct adb_device *sc_adbdev;
69 struct adb_bus_accessops *sc_ops;
70
71 /* Extended Mouse Protocol info, faked for non-EMP mice */
72 u_int8_t sc_class; /* mouse class (mouse, trackball) */
73 u_int8_t sc_buttons; /* number of buttons */
74 u_int32_t sc_res; /* mouse resolution (dpi) */
75 char sc_devid[5]; /* device indentifier */
76 uint8_t sc_us; /* cmd to watch for */
77 int sc_mb; /* current button state */
78 struct device *sc_wsmousedev;
79 /* helpers for trackpads */
80 int sc_down;
81 /*
82 * trackpad protocol variant. Known so far:
83 * 2 buttons - PowerBook 3400, single events on button 3 and 4 indicate
84 * finger down and up
85 * 4 buttons - iBook G4, button 6 indicates finger down, button 4 is
86 * always down
87 */
88 int sc_x, sc_y;
89 int sc_tapping;
90 /* buffers */
91 int sc_poll;
92 int sc_msg_len;
93 int sc_event;
94 uint8_t sc_buffer[16];
95 };
96
97 /* EMP device classes */
98 #define MSCLASS_TABLET 0
99 #define MSCLASS_MOUSE 1
100 #define MSCLASS_TRACKBALL 2
101 #define MSCLASS_TRACKPAD 3
102
103 /*
104 * Function declarations.
105 */
106 static int adbms_match(struct device *, struct cfdata *, void *);
107 static void adbms_attach(struct device *, struct device *, void *);
108 static void ems_init(struct adbms_softc *);
109 //static void ms_processevent(adb_event_t *event, struct adbms_softc *);
110 static void init_trackpad(struct adbms_softc *);
111 static void adbms_init_mouse(struct adbms_softc *);
112 static void adbms_init_turbo(struct adbms_softc *);
113 static void adbms_init_uspeed(struct adbms_softc *);
114 static void adbms_process_event(struct adbms_softc *, int, uint8_t *);
115 static int adbms_send_sync(struct adbms_softc *, uint8_t, int, uint8_t *);
116
117 /* Driver definition. */
118 CFATTACH_DECL(adbms, sizeof(struct adbms_softc),
119 adbms_match, adbms_attach, NULL, NULL);
120
121 static int adbms_enable(void *);
122 static int adbms_ioctl(void *, u_long, caddr_t, int, struct lwp *);
123 static void adbms_disable(void *);
124
125 /*
126 * handle tapping the trackpad
127 * different pads report different button counts and use slightly different
128 * protocols
129 */
130 static void adbms_mangle_2(struct adbms_softc *, int);
131 static void adbms_mangle_4(struct adbms_softc *, int);
132 static void adbms_handler(void *, int, uint8_t *);
133 static int adbms_wait(struct adbms_softc *, int);
134 static int sysctl_adbms_tap(SYSCTLFN_ARGS);
135
136 const struct wsmouse_accessops adbms_accessops = {
137 adbms_enable,
138 adbms_ioctl,
139 adbms_disable,
140 };
141
142 static int
143 adbms_match(struct device *parent, struct cfdata *cf, void *aux)
144 {
145 struct adb_attach_args *aaa = aux;
146
147 if (aaa->dev->original_addr == ADBADDR_MS)
148 return 1;
149 else
150 return 0;
151 }
152
153 static void
154 adbms_attach(struct device *parent, struct device *self, void *aux)
155 {
156 struct adbms_softc *sc = (struct adbms_softc *)self;
157 struct adb_attach_args *aaa = aux;
158 struct wsmousedev_attach_args a;
159
160 sc->sc_ops = aaa->ops;
161 sc->sc_adbdev = aaa->dev;
162 sc->sc_adbdev->cookie = sc;
163 sc->sc_adbdev->handler = adbms_handler;
164 sc->sc_us = ADBTALK(sc->sc_adbdev->current_addr, 0);
165 printf(" addr %d ", sc->sc_adbdev->current_addr);
166
167 sc->sc_class = MSCLASS_MOUSE;
168 sc->sc_buttons = 1;
169 sc->sc_res = 100;
170 sc->sc_devid[0] = 0;
171 sc->sc_devid[4] = 0;
172 sc->sc_poll = 0;
173 sc->sc_msg_len = 0;
174 sc->sc_tapping = 1;
175
176 ems_init(sc);
177
178 /* print out the type of mouse we have */
179 switch (sc->sc_adbdev->handler_id) {
180 case ADBMS_100DPI:
181 printf("%d-button, %d dpi mouse\n", sc->sc_buttons,
182 (int)(sc->sc_res));
183 break;
184 case ADBMS_200DPI:
185 sc->sc_res = 200;
186 printf("%d-button, %d dpi mouse\n", sc->sc_buttons,
187 (int)(sc->sc_res));
188 break;
189 case ADBMS_MSA3:
190 printf("Mouse Systems A3 mouse, %d-button, %d dpi\n",
191 sc->sc_buttons, (int)(sc->sc_res));
192 break;
193 case ADBMS_USPEED:
194 printf("MicroSpeed mouse, default parameters\n");
195 break;
196 case ADBMS_UCONTOUR:
197 printf("Contour mouse, default parameters\n");
198 break;
199 case ADBMS_TURBO:
200 printf("Kensington Turbo Mouse\n");
201 break;
202 case ADBMS_EXTENDED:
203 if (sc->sc_devid[0] == '\0') {
204 printf("Logitech ");
205 switch (sc->sc_class) {
206 case MSCLASS_MOUSE:
207 printf("MouseMan (non-EMP) mouse");
208 break;
209 case MSCLASS_TRACKBALL:
210 printf("TrackMan (non-EMP) trackball");
211 break;
212 default:
213 printf("non-EMP relative positioning device");
214 break;
215 }
216 printf("\n");
217 } else {
218 printf("EMP ");
219 switch (sc->sc_class) {
220 case MSCLASS_TABLET:
221 printf("tablet");
222 break;
223 case MSCLASS_MOUSE:
224 printf("mouse");
225 break;
226 case MSCLASS_TRACKBALL:
227 printf("trackball");
228 break;
229 case MSCLASS_TRACKPAD:
230 printf("trackpad");
231 init_trackpad(sc);
232 break;
233 default:
234 printf("unknown device");
235 break;
236 }
237 printf(" <%s> %d-button, %d dpi\n", sc->sc_devid,
238 sc->sc_buttons, (int)(sc->sc_res));
239 }
240 break;
241 default:
242 printf("relative positioning device (mouse?) (%d)\n",
243 sc->sc_adbdev->handler_id);
244 break;
245 }
246
247 a.accessops = &adbms_accessops;
248 a.accesscookie = sc;
249 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
250 }
251
252
253 /*
254 * Initialize extended mouse support -- probes devices as described
255 * in Inside Macintosh: Devices, Chapter 5 "ADB Manager".
256 *
257 * Extended Mouse Protocol is documented in TechNote HW1:
258 * "ADB - The Untold Story: Space Aliens Ate My Mouse"
259 *
260 * Supports: Extended Mouse Protocol, MicroSpeed Mouse Deluxe,
261 * Mouse Systems A^3 Mouse, Logitech non-EMP MouseMan
262 */
263 void
264 ems_init(struct adbms_softc *sc)
265 {
266
267 DPRINTF("ems_init %d\n", sc->sc_adbdev->handler_id);
268
269 switch (sc->sc_adbdev->handler_id) {
270 case ADBMS_USPEED:
271 case ADBMS_UCONTOUR:
272 adbms_init_uspeed(sc);
273 return;
274 case ADBMS_TURBO:
275 adbms_init_turbo(sc);
276 return;
277 case ADBMS_100DPI:
278 case ADBMS_200DPI:
279 adbms_init_mouse(sc);
280 }
281 }
282
283 static void
284 adbms_init_uspeed(struct adbms_softc *sc)
285 {
286 uint8_t cmd, addr, buffer[4];
287
288 addr = sc->sc_adbdev->current_addr;
289
290 /* Found MicroSpeed Mouse Deluxe Mac or Contour Mouse */
291 cmd = ADBLISTEN(addr, 1);
292
293 /*
294 * To setup the MicroSpeed or the Contour, it appears
295 * that we can send the following command to the mouse
296 * and then expect data back in the form:
297 * buffer[0] = 4 (bytes)
298 * buffer[1], buffer[2] as std. mouse
299 * buffer[3] = buffer[4] = 0xff when no buttons
300 * are down. When button N down, bit N is clear.
301 * buffer[4]'s locking mask enables a
302 * click to toggle the button down state--sort of
303 * like the "Easy Access" shift/control/etc. keys.
304 * buffer[3]'s alternative speed mask enables using
305 * different speed when the corr. button is down
306 */
307 buffer[0] = 0x00; /* Alternative speed */
308 buffer[1] = 0x00; /* speed = maximum */
309 buffer[2] = 0x10; /* enable extended protocol,
310 * lower bits = alt. speed mask
311 * = 0000b
312 */
313 buffer[3] = 0x07; /* Locking mask = 0000b,
314 * enable buttons = 0111b
315 */
316 adbms_send_sync(sc, cmd, 4, buffer);
317
318 sc->sc_buttons = 3;
319 sc->sc_res = 200;
320 }
321
322 static void
323 adbms_init_turbo(struct adbms_softc *sc)
324 {
325 uint8_t addr;
326
327 /* Found Kensington Turbo Mouse */
328 static u_char data1[] =
329 { 0xe7, 0x8c, 0, 0, 0, 0xff, 0xff, 0x94 };
330 static u_char data2[] =
331 { 0xa5, 0x14, 0, 0, 0x69, 0xff, 0xff, 0x27 };
332
333 addr = sc->sc_adbdev->current_addr;
334
335 adbms_send_sync(sc, ADBFLUSH(addr), 0, NULL);
336 adbms_send_sync(sc, ADBLISTEN(addr, 2), 8, data1);
337 adbms_send_sync(sc, ADBFLUSH(addr), 0, NULL);
338 adbms_send_sync(sc, ADBLISTEN(addr, 2), 8, data2);
339 }
340
341 static void
342 adbms_init_mouse(struct adbms_softc *sc)
343 {
344 int len;
345 uint8_t cmd, addr, buffer[16];
346
347 addr = sc->sc_adbdev->current_addr;
348 /* found a mouse */
349 cmd = ADBTALK(addr, 3);
350 if (!adbms_send_sync(sc, cmd, 0, NULL)) {
351 #ifdef ADBMS_DEBUG
352 printf("adb: ems_init timed out\n");
353 #endif
354 return;
355 }
356
357 /* Attempt to initialize Extended Mouse Protocol */
358 len = sc->sc_msg_len;
359 memcpy(buffer, sc->sc_buffer, len);
360 DPRINTF("buffer: %02x %02x\n", buffer[0], buffer[1]);
361 buffer[1] = 4; /* make handler ID 4 */
362 cmd = ADBLISTEN(addr, 3);
363 if (!adbms_send_sync(sc, cmd, len, buffer)) {
364 #ifdef ADBMS_DEBUG
365 printf("adb: ems_init timed out\n");
366 #endif
367 return;
368 }
369
370 /*
371 * Check to see if successful, if not
372 * try to initialize it as other types
373 */
374 cmd = ADBTALK(addr, 3);
375 if (!adbms_send_sync(sc, cmd, 0, NULL)) {
376 DPRINTF("timeout checking for EMP switch\n");
377 return;
378 }
379 DPRINTF("new handler ID: %02x\n", sc->sc_buffer[1]);
380 if (sc->sc_buffer[1] == ADBMS_EXTENDED) {
381 sc->sc_adbdev->handler_id = ADBMS_EXTENDED;
382 cmd = ADBTALK(addr, 1);
383 if(!adbms_send_sync(sc, cmd, 0, NULL)) {
384 DPRINTF("adb: ems_init timed out\n");
385 return;
386 }
387
388 len = sc->sc_msg_len;
389 memcpy(buffer, sc->sc_buffer, len);
390
391 if (sc->sc_msg_len == 8) {
392 /* we have a true EMP device */
393 #ifdef ADB_PRINT_EMP
394
395 printf("EMP: %02x %02x %02x %02x %02x %02x %02x %02x\n",
396 buffer[0], buffer[1], buffer[2], buffer[3],
397 buffer[4], buffer[5], buffer[6], buffer[7]);
398 #endif
399 sc->sc_class = buffer[6];
400 sc->sc_buttons = buffer[7];
401 sc->sc_res = (int)*(short *)&buffer[4];
402 memcpy(sc->sc_devid, &(buffer[0]), 4);
403 } else if (buffer[0] == 0x9a &&
404 ((buffer[1] == 0x20) || (buffer[1] == 0x21))) {
405 /*
406 * Set up non-EMP Mouseman/Trackman to put
407 * button bits in 3rd byte instead of sending
408 * via pseudo keyboard device.
409 */
410 if (buffer[1] == 0x21)
411 sc->sc_class = MSCLASS_TRACKBALL;
412 else
413 sc->sc_class = MSCLASS_MOUSE;
414
415 cmd = ADBLISTEN(addr, 1);
416 buffer[0]=0x00;
417 buffer[1]=0x81;
418 adbms_send_sync(sc, cmd, 2, buffer);
419
420 cmd = ADBLISTEN(addr, 1);
421 buffer[0]=0x01;
422 buffer[1]=0x81;
423 adbms_send_sync(sc, cmd, 2, buffer);
424
425 cmd = ADBLISTEN(addr, 1);
426 buffer[0]=0x02;
427 buffer[1]=0x81;
428 adbms_send_sync(sc, cmd, 2, buffer);
429
430 cmd = ADBLISTEN(addr, 1);
431 buffer[0]=0x03;
432 buffer[1]=0x38;
433 adbms_send_sync(sc, cmd, 2, buffer);
434
435 sc->sc_buttons = 3;
436 sc->sc_res = 400;
437 }
438 } else {
439 /* Attempt to initialize as an A3 mouse */
440 buffer[1] = 0x03; /* make handler ID 3 */
441 cmd = ADBLISTEN(addr, 3);
442 if (!adbms_send_sync(sc, cmd, len, buffer)) {
443 #ifdef ADBMS_DEBUG
444 printf("adb: ems_init timed out\n");
445 #endif
446 return;
447 }
448
449 /*
450 * Check to see if successful, if not
451 * try to initialize it as other types
452 */
453 cmd = ADBTALK(addr, 3);
454 if(adbms_send_sync(sc, cmd, 0, NULL)) {
455 len = sc->sc_msg_len;
456 memcpy(buffer, sc->sc_buffer, len);
457 if (buffer[1] == ADBMS_MSA3) {
458 sc->sc_adbdev->handler_id = ADBMS_MSA3;
459 /* Initialize as above */
460 cmd = ADBLISTEN(addr, 2);
461 /* listen 2 */
462 buffer[0] = 0x00;
463 /* Irrelevant, buffer has 0x77 */
464 buffer[2] = 0x07;
465 /*
466 * enable 3 button mode = 0111b,
467 * speed = normal
468 */
469 adbms_send_sync(sc, cmd, 3, buffer);
470 sc->sc_buttons = 3;
471 sc->sc_res = 300;
472 }
473 }
474 }
475 }
476
477 static void
478 adbms_handler(void *cookie, int len, uint8_t *data)
479 {
480 struct adbms_softc *sc = cookie;
481
482 #ifdef ADBMS_DEBUG
483 int i;
484 printf("%s: %02x - ", sc->sc_dev.dv_xname, sc->sc_us);
485 for (i = 0; i < len; i++) {
486 printf(" %02x", data[i]);
487 }
488 printf("\n");
489 #endif
490 if (len >= 2) {
491 memcpy(sc->sc_buffer, &data[2], len - 2);
492 sc->sc_msg_len = len - 2;
493 if (data[1] == sc->sc_us) {
494 /* make sense of the mouse message */
495 adbms_process_event(sc, sc->sc_msg_len, sc->sc_buffer);
496 return;
497 }
498 wakeup(&sc->sc_event);
499 } else {
500 DPRINTF("bogus message\n");
501 }
502 }
503
504 static void
505 adbms_process_event(struct adbms_softc *sc, int len, uint8_t *buffer)
506 {
507 int buttons = 0, mask, dx, dy, i;
508 int button_bit = 1;
509
510 if ((sc->sc_adbdev->handler_id == ADBMS_EXTENDED) && (sc->sc_devid[0] == 0)) {
511 /* massage the data to look like EMP data */
512 if ((buffer[2] & 0x04) == 0x04)
513 buffer[0] &= 0x7f;
514 else
515 buffer[0] |= 0x80;
516 if ((buffer[2] & 0x02) == 0x02)
517 buffer[1] &= 0x7f;
518 else
519 buffer[1] |= 0x80;
520 if ((buffer[2] & 0x01) == 0x01)
521 buffer[2] = 0x00;
522 else
523 buffer[2] = 0x80;
524 }
525
526 switch (sc->sc_adbdev->handler_id) {
527 case ADBMS_USPEED:
528 case ADBMS_UCONTOUR:
529 /* MicroSpeed mouse and Contour mouse */
530 if (len == 4)
531 buttons = (~buffer[3]) & 0xff;
532 else
533 buttons = (buffer[1] & 0x80) ? 0 : 1;
534 break;
535 case ADBMS_MSA3:
536 /* Mouse Systems A3 mouse */
537 if (len == 3)
538 buttons = (~buffer[2]) & 0x07;
539 else
540 buttons = (buffer[0] & 0x80) ? 0 : 1;
541 break;
542 default:
543 /* Classic Mouse Protocol (up to 2 buttons) */
544 for (i = 0; i < 2; i++, button_bit <<= 1)
545 /* 0 when button down */
546 if (!(buffer[i] & 0x80))
547 buttons |= button_bit;
548 else
549 buttons &= ~button_bit;
550 /* Extended Protocol (up to 6 more buttons) */
551 for (mask = 0x80; i < len;
552 i += (mask == 0x80), button_bit <<= 1) {
553 /* 0 when button down */
554 if (!(buffer[i] & mask))
555 buttons |= button_bit;
556 else
557 buttons &= ~button_bit;
558 mask = ((mask >> 4) & 0xf)
559 | ((mask & 0xf) << 4);
560 }
561 break;
562 }
563
564 dx = ((int)(buffer[1] & 0x3f)) - ((buffer[1] & 0x40) ? 64 : 0);
565 dy = ((int)(buffer[0] & 0x3f)) - ((buffer[0] & 0x40) ? 64 : 0);
566
567 if (sc->sc_class == MSCLASS_TRACKPAD) {
568
569 if (sc->sc_tapping == 1) {
570 if (sc->sc_down) {
571 /* finger is down - collect motion data */
572 sc->sc_x += dx;
573 sc->sc_y += dy;
574 }
575 DPRINTF("buttons: %02x\n", buttons);
576 switch (sc->sc_buttons) {
577 case 2:
578 buttons |= ((buttons & 2) >> 1);
579 adbms_mangle_2(sc, buttons);
580 break;
581 case 4:
582 adbms_mangle_4(sc, buttons);
583 break;
584 }
585 }
586 /* filter the pseudo-buttons out */
587 buttons &= 1;
588 }
589
590 if (sc->sc_wsmousedev)
591 wsmouse_input(sc->sc_wsmousedev, sc->sc_mb | buttons,
592 dx, -dy, 0, 0,
593 WSMOUSE_INPUT_DELTA);
594 #if NAED > 0
595 aed_input(&new_event);
596 #endif
597 }
598
599 static void
600 adbms_mangle_2(struct adbms_softc *sc, int buttons)
601 {
602
603 if (buttons & 4) {
604 /* finger down on pad */
605 if (sc->sc_down == 0) {
606 sc->sc_down = 1;
607 sc->sc_x = 0;
608 sc->sc_y = 0;
609 }
610 }
611 if (buttons & 8) {
612 /* finger up */
613 if (sc->sc_down) {
614 if (((sc->sc_x * sc->sc_x +
615 sc->sc_y * sc->sc_y) < 20) &&
616 (sc->sc_wsmousedev)) {
617 /*
618 * if there wasn't much movement between
619 * finger down and up again we assume
620 * someone tapped the pad and we just
621 * send a mouse button event
622 */
623 wsmouse_input(sc->sc_wsmousedev,
624 1, 0, 0, 0, 0, WSMOUSE_INPUT_DELTA);
625 }
626 sc->sc_down = 0;
627 }
628 }
629 }
630
631 static void
632 adbms_mangle_4(struct adbms_softc *sc, int buttons)
633 {
634
635 if (buttons & 0x20) {
636 /* finger down on pad */
637 if (sc->sc_down == 0) {
638 sc->sc_down = 1;
639 sc->sc_x = 0;
640 sc->sc_y = 0;
641 }
642 }
643 if ((buttons & 0x20) == 0) {
644 /* finger up */
645 if (sc->sc_down) {
646 if (((sc->sc_x * sc->sc_x +
647 sc->sc_y * sc->sc_y) < 20) &&
648 (sc->sc_wsmousedev)) {
649 /*
650 * if there wasn't much movement between
651 * finger down and up again we assume
652 * someone tapped the pad and we just
653 * send a mouse button event
654 */
655 wsmouse_input(sc->sc_wsmousedev,
656 1, 0, 0, 0, 0, WSMOUSE_INPUT_DELTA);
657 }
658 sc->sc_down = 0;
659 }
660 }
661 }
662
663 static int
664 adbms_enable(void *v)
665 {
666 return 0;
667 }
668
669 static int
670 adbms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct lwp *l)
671 {
672
673 switch (cmd) {
674 case WSMOUSEIO_GTYPE:
675 *(u_int *)data = WSMOUSE_TYPE_ADB;
676 break;
677
678 default:
679 return (EPASSTHROUGH);
680 }
681 return (0);
682 }
683
684 static void
685 adbms_disable(void *v)
686 {
687 }
688
689 static void
690 init_trackpad(struct adbms_softc *sc)
691 {
692 struct sysctlnode *me = NULL, *node = NULL;
693 int cmd, addr, ret;
694 uint8_t buffer[16];
695 uint8_t b2[] = {0x99, 0x94, 0x19, 0xff, 0xb2, 0x8a, 0x1b, 0x50};
696
697 addr = sc->sc_adbdev->current_addr;
698 cmd = ADBTALK(addr, 1);
699 if (!adbms_send_sync(sc, cmd, 0, NULL))
700 return;
701
702 if (sc->sc_msg_len != 8)
703 return;
704
705 memcpy(buffer, sc->sc_buffer, 8);
706
707 /* now whack the pad */
708 cmd = ADBLISTEN(addr, 1);
709 buffer[6] = 0x0d;
710 adbms_send_sync(sc, cmd, 8, buffer);
711
712 delay(1000);
713 cmd = ADBLISTEN(addr, 2);
714 adbms_send_sync(sc, cmd, 8, b2);
715
716 delay(1000);
717 cmd = ADBLISTEN(addr, 1);
718 buffer[6] = 0x03;
719 adbms_send_sync(sc, cmd, 8, buffer);
720
721 cmd = ADBFLUSH(addr);
722 adbms_send_sync(sc, cmd, 0, NULL);
723 delay(1000);
724
725 /*
726 * setup a sysctl node to control wether tapping the pad should
727 * trigger mouse button events
728 */
729
730 sc->sc_tapping = 1;
731
732 ret = sysctl_createv(NULL, 0, NULL, (const struct sysctlnode **)&me,
733 CTLFLAG_READWRITE,
734 CTLTYPE_NODE, sc->sc_dev.dv_xname, NULL,
735 NULL, 0, NULL, 0,
736 CTL_MACHDEP, CTL_CREATE, CTL_EOL);
737
738 ret = sysctl_createv(NULL, 0, NULL, (const struct sysctlnode **)&node,
739 CTLFLAG_READWRITE | CTLFLAG_OWNDESC | CTLFLAG_IMMEDIATE,
740 CTLTYPE_INT, "tapping", "tapping the pad causes button events",
741 sysctl_adbms_tap, 1, NULL, 0,
742 CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
743 if (node != NULL) {
744 node->sysctl_data = sc;
745 }
746 }
747
748 static int
749 adbms_wait(struct adbms_softc *sc, int timeout)
750 {
751 int cnt = 0;
752
753 if (sc->sc_poll) {
754 while (sc->sc_msg_len == -1) {
755 sc->sc_ops->poll(sc->sc_ops->cookie);
756 }
757 } else {
758 while ((sc->sc_msg_len == -1) && (cnt < timeout)) {
759 tsleep(&sc->sc_event, 0, "adbkbdio", hz);
760 cnt++;
761 }
762 }
763 return (sc->sc_msg_len > 0);
764 }
765
766 static int
767 adbms_send_sync(struct adbms_softc *sc, uint8_t cmd, int len, uint8_t *msg)
768 {
769 int i;
770
771 sc->sc_msg_len = -1;
772 DPRINTF("send: %02x", cmd);
773 for (i = 0; i < len; i++)
774 DPRINTF(" %02x", msg[i]);
775 DPRINTF("\n");
776 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, len, msg);
777 adbms_wait(sc, 1000);
778 return (sc->sc_msg_len != -1);
779 }
780
781 static int
782 sysctl_adbms_tap(SYSCTLFN_ARGS)
783 {
784 struct sysctlnode node = *rnode;
785 struct adbms_softc *sc = node.sysctl_data;
786
787 node.sysctl_idata = sc->sc_tapping;
788
789 if (newp) {
790
791 /* we're asked to write */
792 node.sysctl_data = &sc->sc_tapping;
793 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
794
795 sc->sc_tapping = (node.sysctl_idata == 0) ? 0 : 1;
796 return 0;
797 }
798 return EINVAL;
799 } else {
800
801 node.sysctl_size = 4;
802 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
803 }
804
805 return 0;
806 }
807
808 SYSCTL_SETUP(sysctl_ams_setup, "sysctl ams subtree setup")
809 {
810
811 sysctl_createv(NULL, 0, NULL, NULL,
812 CTLFLAG_PERMANENT,
813 CTLTYPE_NODE, "machdep", NULL,
814 NULL, 0, NULL, 0,
815 CTL_MACHDEP, CTL_EOL);
816 }
817