Home | History | Annotate | Line # | Download | only in pckbport
pms.c revision 1.1
      1 /* $NetBSD: pms.c,v 1.1 2004/03/13 17:31:33 bjh21 Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 1994 Charles M. Hannum.
      5  * Copyright (c) 1992, 1993 Erik Forsberg.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
     15  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     16  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
     17  * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     23  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include <sys/cdefs.h>
     27 __KERNEL_RCSID(0, "$NetBSD: pms.c,v 1.1 2004/03/13 17:31:33 bjh21 Exp $");
     28 
     29 #include <sys/param.h>
     30 #include <sys/systm.h>
     31 #include <sys/device.h>
     32 #include <sys/ioctl.h>
     33 #include <sys/kernel.h>
     34 #include <sys/kthread.h>
     35 
     36 #include <machine/bus.h>
     37 
     38 #include <dev/pckbport/pckbportvar.h>
     39 
     40 #include <dev/pckbport/pmsreg.h>
     41 
     42 #include <dev/wscons/wsconsio.h>
     43 #include <dev/wscons/wsmousevar.h>
     44 
     45 #ifdef PMSDEBUG
     46 int pmsdebug = 1;
     47 #define DPRINTF(x)      if (pmsdebug) printf x
     48 #else
     49 #define DPRINTF(x)
     50 #endif
     51 
     52 enum pms_type { PMS_UNKNOWN, PMS_STANDARD, PMS_SCROLL3, PMS_SCROLL5 };
     53 
     54 struct pms_protocol {
     55 	int rates[3];
     56 	int response;
     57 	const char *name;
     58 } pms_protocols[] = {
     59 	{ { 0, 0, 0 }, 0, "unknown protocol" },
     60 	{ { 0, 0, 0 }, 0, "no scroll wheel (3 buttons)" },
     61 	{ { 200, 100, 80 }, 3, "scroll wheel (3 buttons)" },
     62 	{ { 200, 200, 80 }, 4, "scroll wheel (5 buttons)" }
     63 };
     64 
     65 enum pms_type tries[] = {
     66 	PMS_SCROLL5, PMS_SCROLL3, PMS_STANDARD, PMS_UNKNOWN
     67 };
     68 
     69 struct pms_softc {		/* driver status information */
     70 	struct device sc_dev;
     71 
     72 	pckbport_tag_t sc_kbctag;
     73 	int sc_kbcslot;
     74 
     75 	int sc_enabled;		/* input enabled? */
     76 #ifndef PMS_DISABLE_POWERHOOK
     77 	void *sc_powerhook;	/* cookie from power hook */
     78 	int sc_suspended;	/* suspended? */
     79 #endif /* !PMS_DISABLE_POWERHOOK */
     80 	int inputstate;		/* number of bytes received for this packet */
     81 	u_int buttons;		/* mouse button status */
     82 	enum pms_type protocol;
     83 	unsigned char packet[4];
     84 	struct timeval last, current;
     85 
     86 	struct device *sc_wsmousedev;
     87 	struct proc *sc_event_thread;
     88 };
     89 
     90 int pmsprobe __P((struct device *, struct cfdata *, void *));
     91 void pmsattach __P((struct device *, struct device *, void *));
     92 void pmsinput __P((void *, int));
     93 
     94 CFATTACH_DECL(pms, sizeof(struct pms_softc),
     95     pmsprobe, pmsattach, NULL, NULL);
     96 
     97 static int	pms_protocol __P((pckbport_tag_t, pckbport_slot_t));
     98 static void	do_enable __P((struct pms_softc *));
     99 static void	do_disable __P((struct pms_softc *));
    100 static void	pms_reset_thread __P((void*));
    101 static void	pms_spawn_reset_thread __P((void*));
    102 int	pms_enable __P((void *));
    103 int	pms_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
    104 void	pms_disable __P((void *));
    105 #ifndef PMS_DISABLE_POWERHOOK
    106 void	pms_power __P((int, void *));
    107 #endif /* !PMS_DISABLE_POWERHOOK */
    108 
    109 const struct wsmouse_accessops pms_accessops = {
    110 	pms_enable,
    111 	pms_ioctl,
    112 	pms_disable,
    113 };
    114 
    115 static int
    116 pms_protocol(tag, slot)
    117 	pckbport_tag_t tag;
    118 	pckbport_slot_t slot;
    119 {
    120 	u_char cmd[2], resp[1];
    121 	int i, j, res;
    122 	struct pms_protocol *p;
    123 
    124 	for (j = 0; j < sizeof(tries) / sizeof(tries[0]); ++j) {
    125 		p = &pms_protocols[tries[j]];
    126 		if (!p->rates[0])
    127 			break;
    128 		cmd[0] = PMS_SET_SAMPLE;
    129 		for (i = 0; i < 3; i++) {
    130 			cmd[1] = p->rates[i];
    131 			res = pckbport_enqueue_cmd(tag, slot, cmd, 2, 0, 1, 0);
    132 			if (res)
    133 				return PMS_STANDARD;
    134 		}
    135 
    136 		cmd[0] = PMS_SEND_DEV_ID;
    137 		res = pckbport_enqueue_cmd(tag, slot, cmd, 1, 1, 1, resp);
    138 		if (res)
    139 			return PMS_UNKNOWN;
    140 		if (resp[0] == p->response) {
    141 			DPRINTF(("pms_protocol: found mouse protocol %d\n",
    142 				tries[j]));
    143 			return tries[j];
    144 		}
    145 	}
    146 	DPRINTF(("pms_protocol: standard PS/2 protocol (no scroll wheel)\n"));
    147 	return PMS_STANDARD;
    148 }
    149 
    150 int
    151 pmsprobe(parent, match, aux)
    152 	struct device *parent;
    153 	struct cfdata *match;
    154 	void *aux;
    155 {
    156 	struct pckbport_attach_args *pa = aux;
    157 	u_char cmd[1], resp[2];
    158 	int res;
    159 
    160 	if (pa->pa_slot != PCKBPORT_AUX_SLOT)
    161 		return (0);
    162 
    163 	/* Flush any garbage. */
    164 	pckbport_flush(pa->pa_tag, pa->pa_slot);
    165 
    166 	/* reset the device */
    167 	cmd[0] = PMS_RESET;
    168 	res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1);
    169 	if (res) {
    170 #ifdef DEBUG
    171 		printf("pmsprobe: reset error %d\n", res);
    172 #endif
    173 		return (0);
    174 	}
    175 	if (resp[0] != PMS_RSTDONE) {
    176 		printf("pmsprobe: reset response 0x%x\n", resp[0]);
    177 		return (0);
    178 	}
    179 
    180 	/* get type number (0 = mouse) */
    181 	if (resp[1] != 0) {
    182 #ifdef DEBUG
    183 		printf("pmsprobe: type 0x%x\n", resp[1]);
    184 #endif
    185 		return (0);
    186 	}
    187 
    188 	return (10);
    189 }
    190 
    191 void
    192 pmsattach(parent, self, aux)
    193 	struct device *parent, *self;
    194 	void *aux;
    195 {
    196 	struct pms_softc *sc = (void *)self;
    197 	struct pckbport_attach_args *pa = aux;
    198 	struct wsmousedev_attach_args a;
    199 	u_char cmd[1], resp[2];
    200 	int res;
    201 
    202 	sc->sc_kbctag = pa->pa_tag;
    203 	sc->sc_kbcslot = pa->pa_slot;
    204 
    205 	printf("\n");
    206 
    207 	/* Flush any garbage. */
    208 	pckbport_flush(pa->pa_tag, pa->pa_slot);
    209 
    210 	/* reset the device */
    211 	cmd[0] = PMS_RESET;
    212 	res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 2, resp, 1);
    213 #ifdef DEBUG
    214 	if (res || resp[0] != PMS_RSTDONE || resp[1] != 0) {
    215 		printf("pmsattach: reset error\n");
    216 		return;
    217 	}
    218 #endif
    219 	sc->inputstate = 0;
    220 	sc->buttons = 0;
    221 	sc->protocol = PMS_UNKNOWN;
    222 
    223 	pckbport_set_inputhandler(sc->sc_kbctag, sc->sc_kbcslot,
    224 			       pmsinput, sc, sc->sc_dev.dv_xname);
    225 
    226 	a.accessops = &pms_accessops;
    227 	a.accesscookie = sc;
    228 
    229 	/*
    230 	 * Attach the wsmouse, saving a handle to it.
    231 	 * Note that we don't need to check this pointer against NULL
    232 	 * here or in pmsintr, because if this fails pms_enable() will
    233 	 * never be called, so pmsinput() will never be called.
    234 	 */
    235 	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
    236 
    237 	/* no interrupts until enabled */
    238 	cmd[0] = PMS_DEV_DISABLE;
    239 	res = pckbport_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 0, 0, 0);
    240 	if (res)
    241 		printf("pmsattach: disable error\n");
    242 	pckbport_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0);
    243 
    244 	kthread_create(pms_spawn_reset_thread, sc);
    245 
    246 #ifndef PMS_DISABLE_POWERHOOK
    247 	sc->sc_powerhook = powerhook_establish(pms_power, sc);
    248 	sc->sc_suspended = 0;
    249 #endif /* !PMS_DISABLE_POWERHOOK */
    250 }
    251 
    252 static void
    253 do_enable(sc)
    254 	struct pms_softc *sc;
    255 {
    256 	u_char cmd[1];
    257 	int res;
    258 
    259 	sc->inputstate = 0;
    260 	sc->buttons = 0;
    261 
    262 	pckbport_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 1);
    263 
    264 	cmd[0] = PMS_DEV_ENABLE;
    265 	res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, cmd, 1, 0, 1, 0);
    266 	if (res)
    267 		printf("pms_enable: command error %d\n", res);
    268 
    269 	if (sc->protocol == PMS_UNKNOWN)
    270 		sc->protocol = pms_protocol(sc->sc_kbctag, sc->sc_kbcslot);
    271 	DPRINTF(("pms_enable: using %s protocol\n",
    272 	    pms_protocols[sc->protocol].name));
    273 #if 0
    274 	{
    275 		u_char scmd[2];
    276 
    277 		scmd[0] = PMS_SET_RES;
    278 		scmd[1] = 3; /* 8 counts/mm */
    279 		res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, scmd,
    280 		    2, 0, 1, 0);
    281 		if (res)
    282 			printf("pms_enable: setup error1 (%d)\n", res);
    283 
    284 		scmd[0] = PMS_SET_SCALE21;
    285 		res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, scmd,
    286 		    1, 0, 1, 0);
    287 		if (res)
    288 			printf("pms_enable: setup error2 (%d)\n", res);
    289 
    290 		scmd[0] = PMS_SET_SAMPLE;
    291 		scmd[1] = 100; /* 100 samples/sec */
    292 		res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, scmd,
    293 		    2, 0, 1, 0);
    294 		if (res)
    295 			printf("pms_enable: setup error3 (%d)\n", res);
    296 	}
    297 #endif
    298 }
    299 
    300 static void
    301 do_disable(sc)
    302 	struct pms_softc *sc;
    303 {
    304 	u_char cmd[1];
    305 	int res;
    306 
    307 	cmd[0] = PMS_DEV_DISABLE;
    308 	res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, cmd, 1, 0, 1, 0);
    309 	if (res)
    310 		printf("pms_disable: command error\n");
    311 
    312 	pckbport_slot_enable(sc->sc_kbctag, sc->sc_kbcslot, 0);
    313 }
    314 
    315 int
    316 pms_enable(v)
    317 	void *v;
    318 {
    319 	struct pms_softc *sc = v;
    320 	int s;
    321 
    322 	if (sc->sc_enabled)
    323 		return EBUSY;
    324 
    325 	do_enable(sc);
    326 
    327 	s = spltty();
    328 	sc->sc_enabled = 1;
    329 	splx(s);
    330 
    331 	return 0;
    332 }
    333 
    334 void
    335 pms_disable(v)
    336 	void *v;
    337 {
    338 	struct pms_softc *sc = v;
    339 	int s;
    340 
    341 	do_disable(sc);
    342 
    343 	s = spltty();
    344 	sc->sc_enabled = 0;
    345 	splx(s);
    346 }
    347 
    348 #ifndef PMS_DISABLE_POWERHOOK
    349 void
    350 pms_power(why, v)
    351 	int why;
    352 	void *v;
    353 {
    354 	struct pms_softc *sc = v;
    355 
    356 	switch (why) {
    357 	case PWR_STANDBY:
    358 		break;
    359 	case PWR_SUSPEND:
    360 		if (sc->sc_enabled) {
    361 			do_disable(sc);
    362 			sc->sc_suspended = 1;
    363 		}
    364 		break;
    365 	case PWR_RESUME:
    366 		if (sc->sc_enabled && sc->sc_suspended) {
    367 			sc->protocol = PMS_UNKNOWN;	/* recheck protocol & init mouse */
    368 			sc->sc_suspended = 0;
    369 			do_enable(sc); /* only if we were suspended */
    370 		}
    371 	case PWR_SOFTSUSPEND:
    372 	case PWR_SOFTSTANDBY:
    373 	case PWR_SOFTRESUME:
    374 		break;
    375 	}
    376 }
    377 #endif /* !PMS_DISABLE_POWERHOOK */
    378 
    379 int
    380 pms_ioctl(v, cmd, data, flag, p)
    381 	void *v;
    382 	u_long cmd;
    383 	caddr_t data;
    384 	int flag;
    385 	struct proc *p;
    386 {
    387 	struct pms_softc *sc = v;
    388 	u_char kbcmd[2];
    389 	int i;
    390 
    391 	switch (cmd) {
    392 	case WSMOUSEIO_GTYPE:
    393 		*(u_int *)data = WSMOUSE_TYPE_PS2;
    394 		break;
    395 
    396 	case WSMOUSEIO_SRES:
    397 		i = (*(u_int *)data - 12) / 25;
    398 
    399 		if (i < 0)
    400 			i = 0;
    401 
    402 		if (i > 3)
    403 			i = 3;
    404 
    405 		kbcmd[0] = PMS_SET_RES;
    406 		kbcmd[1] = i;
    407 		i = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, kbcmd,
    408 		    2, 0, 1, 0);
    409 
    410 		if (i)
    411 			printf("pms_ioctl: SET_RES command error\n");
    412 		break;
    413 
    414 	default:
    415 		return (EPASSTHROUGH);
    416 	}
    417 	return (0);
    418 }
    419 
    420 static void
    421 pms_spawn_reset_thread(arg)
    422 	void *arg;
    423 {
    424 	struct pms_softc *sc = arg;
    425 
    426 	kthread_create1(pms_reset_thread, sc, &sc->sc_event_thread,
    427 	    sc->sc_dev.dv_xname);
    428 }
    429 
    430 static void
    431 pms_reset_thread(arg)
    432 	void *arg;
    433 {
    434 	struct pms_softc *sc = arg;
    435 	u_char cmd[1], resp[2];
    436 	int res;
    437 	int save_protocol;
    438 
    439 	for (;;) {
    440 		tsleep(&sc->sc_enabled, PWAIT, "pmsreset", 0);
    441 #ifdef PMSDEBUG
    442 		if (pmsdebug)
    443 #endif
    444 #if defined(PMSDEBUG) || defined(DIAGNOSTIC)
    445 			printf("%s: resetting mouse interface\n",
    446 			    sc->sc_dev.dv_xname);
    447 #endif
    448 		save_protocol = sc->protocol;
    449 		pms_disable(sc);
    450 		cmd[0] = PMS_RESET;
    451 		res = pckbport_enqueue_cmd(sc->sc_kbctag, sc->sc_kbcslot, cmd, 1,
    452 		    2, 1, resp);
    453 		if (res)
    454 			DPRINTF(("%s: reset error %d\n", sc->sc_dev.dv_xname,
    455 			    res));
    456 		sc->protocol = PMS_UNKNOWN;
    457 		pms_enable(sc);
    458 		if (sc->protocol != save_protocol) {
    459 #if defined(PMSDEBUG) || defined(DIAGNOSTIC)
    460 			printf("%s: protocol change, sleeping and retrying\n",
    461 			    sc->sc_dev.dv_xname);
    462 #endif
    463 			pms_disable(sc);
    464 			cmd[0] = PMS_RESET;
    465 			res = pckbport_enqueue_cmd(sc->sc_kbctag,
    466 			    sc->sc_kbcslot, cmd, 1, 2, 1, resp);
    467 			if (res)
    468 				DPRINTF(("%s: reset error %d\n",
    469 				    sc->sc_dev.dv_xname, res));
    470 			tsleep(pms_reset_thread, PWAIT, "pmsreset", hz);
    471 			cmd[0] = PMS_RESET;
    472 			res = pckbport_enqueue_cmd(sc->sc_kbctag,
    473 			    sc->sc_kbcslot, cmd, 1, 2, 1, resp);
    474 			if (res)
    475 				DPRINTF(("%s: reset error %d\n",
    476 				    sc->sc_dev.dv_xname, res));
    477 			sc->protocol = PMS_UNKNOWN;	/* reprobe protocol */
    478 			pms_enable(sc);
    479 #if defined(PMSDEBUG) || defined(DIAGNOSTIC)
    480 			if (sc->protocol != save_protocol) {
    481 				printf("%s: protocol changed.\n",
    482 				    sc->sc_dev.dv_xname);
    483 			}
    484 #endif
    485 		}
    486 	}
    487 }
    488 
    489 /* Masks for the first byte of a packet */
    490 #define PMS_LBUTMASK 0x01
    491 #define PMS_RBUTMASK 0x02
    492 #define PMS_MBUTMASK 0x04
    493 #define PMS_4BUTMASK 0x10
    494 #define PMS_5BUTMASK 0x20
    495 
    496 void
    497 pmsinput(vsc, data)
    498 	void *vsc;
    499 	int data;
    500 {
    501 	struct pms_softc *sc = vsc;
    502 	u_int changed;
    503 	int dx, dy, dz = 0;
    504 	int newbuttons = 0;
    505 	int s;
    506 
    507 	if (!sc->sc_enabled) {
    508 		/* Interrupts are not expected.	 Discard the byte. */
    509 		return;
    510 	}
    511 
    512 	s = splclock();
    513 	sc->current = mono_time;
    514 	splx(s);
    515 
    516 	if (sc->inputstate > 0) {
    517 		struct timeval diff;
    518 
    519 		timersub(&sc->current, &sc->last, &diff);
    520 		/*
    521 		 * Empirically, the delay should be about 1700us on a standard
    522 		 * PS/2 port.  I have seen delays as large as 4500us (rarely)
    523 		 * in regular use.  When using a confused mouse, I generally
    524 		 * see delays at least as large as 30,000us.  -seebs
    525 		 *
    526 		 * The thinkpad trackball returns at 22-23ms. So we use
    527 		 * >= 40ms. In the future, I'll implement adaptable timeout
    528 		 * by increasing the timeout if the mouse reset happens
    529 		 * too frequently -christos
    530 		 */
    531 		if (diff.tv_sec > 0 || diff.tv_usec >= 40000) {
    532 			DPRINTF(("pms_input: unusual delay (%ld.%06ld s), "
    533 			    "scheduling reset\n",
    534 			    (long)diff.tv_sec, (long)diff.tv_usec));
    535 			sc->inputstate = 0;
    536 			sc->sc_enabled = 0;
    537 			wakeup(&sc->sc_enabled);
    538 			return;
    539 		}
    540 	}
    541 	sc->last = sc->current;
    542 
    543 	if (sc->inputstate == 0) {
    544 		/*
    545 		 * Some devices (seen on trackballs anytime, and on some mice shortly after
    546 		 * reset) output garbage bytes between packets.
    547 		 * Just ignore them.
    548 		 */
    549 		if ((data & 0xc0) != 0)
    550 			return;	/* not in sync yet, discard input */
    551 	}
    552 
    553 	sc->packet[sc->inputstate++] = data & 0xff;
    554 	switch (sc->inputstate) {
    555 	case 0:
    556 		/* no useful processing can be done yet */
    557 		break;
    558 
    559 	case 1:
    560 		/*
    561 		 * Why should we test for bit 0x8 and insist on it here?
    562 		 * The old (psm.c and psm_intelli.c) drivers didn't do
    563 		 * it, and there are devices where it does harm (that's
    564 		 * why it is not used if using PMS_STANDARD protocol).
    565 		 * Anyway, it does not to cause any harm to accept packets
    566 		 * without this bit.
    567 		 */
    568 #if 0
    569 		if (sc->protocol == PMS_STANDARD)
    570 			break;
    571 		if (!(sc->packet[0] & 0x8)) {
    572 			DPRINTF(("pmsinput: 0x8 not set in first byte "
    573 			    "[0x%02x], resetting\n", sc->packet[0]));
    574 			sc->inputstate = 0;
    575 			sc->sc_enabled = 0;
    576 			wakeup(&sc->sc_enabled);
    577 			return;
    578 		}
    579 #endif
    580 		break;
    581 
    582 	case 2:
    583 		break;
    584 
    585 	case 4:
    586 		/* Case 4 is a superset of case 3. This is *not* an accident. */
    587 		if (sc->protocol == PMS_SCROLL3) {
    588 			dz = sc->packet[3];
    589 			if (dz >= 128)
    590 				dz -= 256;
    591 			if (dz == -128)
    592 				dz = -127;
    593 		} else if (sc->protocol == PMS_SCROLL5) {
    594 			dz = sc->packet[3] & 0xf;
    595 			if (dz >= 8)
    596 				dz -= 16;
    597                 	if (sc->packet[3] & PMS_4BUTMASK)
    598 				newbuttons |= 0x8;
    599                 	if (sc->packet[3] & PMS_5BUTMASK)
    600 				newbuttons |= 0x10;
    601 		} else {
    602 			DPRINTF(("pmsinput: why am I looking at this byte?\n"));
    603 			dz = 0;
    604 		}
    605 		/* FALLTHROUGH */
    606 	case 3:
    607 		/*
    608 		 * This is only an endpoint for scroll protocols with 4
    609 		 * bytes, or the standard protocol with 3.
    610 		 */
    611 		if (sc->protocol != PMS_STANDARD && sc->inputstate == 3)
    612 			break;
    613 
    614 		newbuttons |= ((sc->packet[0] & PMS_LBUTMASK) ? 0x1 : 0) |
    615 		    ((sc->packet[0] & PMS_MBUTMASK) ? 0x2 : 0) |
    616 		    ((sc->packet[0] & PMS_RBUTMASK) ? 0x4 : 0);
    617 
    618 		dx = sc->packet[1];
    619 		if (dx >= 128)
    620 			dx -= 256;
    621 		if (dx == -128)
    622 			dx = -127;
    623 
    624 		dy = sc->packet[2];
    625 		if (dy >= 128)
    626 			dy -= 256;
    627 		if (dy == -128)
    628 			dy = -127;
    629 
    630 		sc->inputstate = 0;
    631 		changed = (sc->buttons ^ newbuttons);
    632 		sc->buttons = newbuttons;
    633 
    634 #ifdef PMSDEBUG
    635 		if (sc->protocol == PMS_STANDARD) {
    636 			DPRINTF(("pms: packet: 0x%02x%02x%02x\n",
    637 			    sc->packet[0], sc->packet[1], sc->packet[2]));
    638 		} else {
    639 			DPRINTF(("pms: packet: 0x%02x%02x%02x%02x\n",
    640 			    sc->packet[0], sc->packet[1], sc->packet[2],
    641 			    sc->packet[3]));
    642 		}
    643 #endif
    644 		if (dx || dy || dz || changed) {
    645 #ifdef PMSDEBUG
    646 			DPRINTF(("pms: x %+03d y %+03d z %+03d "
    647 			    "buttons 0x%02x\n",	dx, dy, dz, sc->buttons));
    648 #endif
    649 			wsmouse_input(sc->sc_wsmousedev,
    650 			    sc->buttons, dx, dy, dz,
    651 			    WSMOUSE_INPUT_DELTA);
    652 		}
    653 		memset(sc->packet, 0, 4);
    654 		break;
    655 
    656 	/* If we get here, we have problems. */
    657 	default:
    658 		printf("pmsinput: very confused.  resetting.\n");
    659 		sc->inputstate = 0;
    660 		sc->sc_enabled = 0;
    661 		wakeup(&sc->sc_enabled);
    662 		return;
    663 	}
    664 }
    665