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