Home | History | Annotate | Line # | Download | only in dev
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