1 /* $NetBSD: uhid.c,v 1.69 2006/03/28 17:38:35 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson (lennart@augustsson.net) at 9 * Carlstedt Research & Technology. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf 42 */ 43 44 #include <sys/cdefs.h> 45 __KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.69 2006/03/28 17:38:35 thorpej Exp $"); 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/kernel.h> 50 #include <sys/malloc.h> 51 #include <sys/signalvar.h> 52 #include <sys/device.h> 53 #include <sys/ioctl.h> 54 #include <sys/conf.h> 55 #include <sys/tty.h> 56 #include <sys/file.h> 57 #include <sys/select.h> 58 #include <sys/proc.h> 59 #include <sys/vnode.h> 60 #include <sys/poll.h> 61 62 #include <dev/usb/usb.h> 63 #include <dev/usb/usbhid.h> 64 65 #include <dev/usb/usbdevs.h> 66 #include <dev/usb/usbdi.h> 67 #include <dev/usb/usbdi_util.h> 68 #include <dev/usb/hid.h> 69 #include <dev/usb/usb_quirks.h> 70 71 #include <dev/usb/uhidev.h> 72 73 #ifdef UHID_DEBUG 74 #define DPRINTF(x) if (uhiddebug) logprintf x 75 #define DPRINTFN(n,x) if (uhiddebug>(n)) logprintf x 76 int uhiddebug = 0; 77 #else 78 #define DPRINTF(x) 79 #define DPRINTFN(n,x) 80 #endif 81 82 struct uhid_softc { 83 struct uhidev sc_hdev; 84 85 int sc_isize; 86 int sc_osize; 87 int sc_fsize; 88 89 u_char *sc_obuf; 90 91 struct clist sc_q; 92 struct selinfo sc_rsel; 93 usb_proc_ptr sc_async; /* process that wants SIGIO */ 94 u_char sc_state; /* driver state */ 95 #define UHID_ASLP 0x01 /* waiting for device data */ 96 #define UHID_IMMED 0x02 /* return read data immediately */ 97 98 int sc_refcnt; 99 u_char sc_dying; 100 }; 101 102 #define UHIDUNIT(dev) (minor(dev)) 103 #define UHID_CHUNK 128 /* chunk size for read */ 104 #define UHID_BSIZE 1020 /* buffer size */ 105 106 dev_type_open(uhidopen); 107 dev_type_close(uhidclose); 108 dev_type_read(uhidread); 109 dev_type_write(uhidwrite); 110 dev_type_ioctl(uhidioctl); 111 dev_type_poll(uhidpoll); 112 dev_type_kqfilter(uhidkqfilter); 113 114 const struct cdevsw uhid_cdevsw = { 115 uhidopen, uhidclose, uhidread, uhidwrite, uhidioctl, 116 nostop, notty, uhidpoll, nommap, uhidkqfilter, 117 }; 118 119 Static void uhid_intr(struct uhidev *, void *, u_int len); 120 121 Static int uhid_do_read(struct uhid_softc *, struct uio *uio, int); 122 Static int uhid_do_write(struct uhid_softc *, struct uio *uio, int); 123 Static int uhid_do_ioctl(struct uhid_softc*, u_long, caddr_t, int, struct lwp *); 124 125 USB_DECLARE_DRIVER(uhid); 126 127 int 128 uhid_match(struct device *parent, struct cfdata *match, void *aux) 129 { 130 #ifdef UHID_DEBUG 131 struct uhidev_attach_arg *uha = aux; 132 #endif 133 134 DPRINTF(("uhid_match: report=%d\n", uha->reportid)); 135 136 if (match->cf_flags & 1) 137 return (UMATCH_HIGHEST); 138 else 139 return (UMATCH_IFACECLASS_GENERIC); 140 } 141 142 void 143 uhid_attach(struct device *parent, struct device *self, void *aux) 144 { 145 struct uhid_softc *sc = (struct uhid_softc *)self; 146 struct uhidev_attach_arg *uha = aux; 147 int size, repid; 148 void *desc; 149 150 sc->sc_hdev.sc_intr = uhid_intr; 151 sc->sc_hdev.sc_parent = uha->parent; 152 sc->sc_hdev.sc_report_id = uha->reportid; 153 154 uhidev_get_report_desc(uha->parent, &desc, &size); 155 repid = uha->reportid; 156 sc->sc_isize = hid_report_size(desc, size, hid_input, repid); 157 sc->sc_osize = hid_report_size(desc, size, hid_output, repid); 158 sc->sc_fsize = hid_report_size(desc, size, hid_feature, repid); 159 160 printf(": input=%d, output=%d, feature=%d\n", 161 sc->sc_isize, sc->sc_osize, sc->sc_fsize); 162 163 USB_ATTACH_SUCCESS_RETURN; 164 } 165 166 int 167 uhid_activate(device_ptr_t self, enum devact act) 168 { 169 struct uhid_softc *sc = (struct uhid_softc *)self; 170 171 switch (act) { 172 case DVACT_ACTIVATE: 173 return (EOPNOTSUPP); 174 175 case DVACT_DEACTIVATE: 176 sc->sc_dying = 1; 177 break; 178 } 179 return (0); 180 } 181 182 int 183 uhid_detach(struct device *self, int flags) 184 { 185 struct uhid_softc *sc = (struct uhid_softc *)self; 186 int s; 187 int maj, mn; 188 189 DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags)); 190 191 sc->sc_dying = 1; 192 193 if (sc->sc_hdev.sc_state & UHIDEV_OPEN) { 194 s = splusb(); 195 if (--sc->sc_refcnt >= 0) { 196 /* Wake everyone */ 197 wakeup(&sc->sc_q); 198 /* Wait for processes to go away. */ 199 usb_detach_wait(USBDEV(sc->sc_hdev.sc_dev)); 200 } 201 splx(s); 202 } 203 204 /* locate the major number */ 205 #if defined(__NetBSD__) 206 maj = cdevsw_lookup_major(&uhid_cdevsw); 207 #elif defined(__OpenBSD__) 208 for (maj = 0; maj < nchrdev; maj++) 209 if (cdevsw[maj].d_open == uhidopen) 210 break; 211 #endif 212 213 /* Nuke the vnodes for any open instances (calls close). */ 214 mn = device_unit(self); 215 vdevgone(maj, mn, mn, VCHR); 216 217 #if 0 218 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, 219 sc->sc_hdev.sc_parent->sc_udev, 220 USBDEV(sc->sc_hdev.sc_dev)); 221 #endif 222 223 return (0); 224 } 225 226 void 227 uhid_intr(struct uhidev *addr, void *data, u_int len) 228 { 229 struct uhid_softc *sc = (struct uhid_softc *)addr; 230 231 #ifdef UHID_DEBUG 232 if (uhiddebug > 5) { 233 u_int32_t i; 234 235 DPRINTF(("uhid_intr: data =")); 236 for (i = 0; i < len; i++) 237 DPRINTF((" %02x", ((u_char *)data)[i])); 238 DPRINTF(("\n")); 239 } 240 #endif 241 242 (void)b_to_q(data, len, &sc->sc_q); 243 244 if (sc->sc_state & UHID_ASLP) { 245 sc->sc_state &= ~UHID_ASLP; 246 DPRINTFN(5, ("uhid_intr: waking %p\n", &sc->sc_q)); 247 wakeup(&sc->sc_q); 248 } 249 selnotify(&sc->sc_rsel, 0); 250 if (sc->sc_async != NULL) { 251 DPRINTFN(3, ("uhid_intr: sending SIGIO %p\n", sc->sc_async)); 252 psignal(sc->sc_async, SIGIO); 253 } 254 } 255 256 int 257 uhidopen(dev_t dev, int flag, int mode, struct lwp *l) 258 { 259 struct uhid_softc *sc; 260 int error; 261 262 USB_GET_SC_OPEN(uhid, UHIDUNIT(dev), sc); 263 264 DPRINTF(("uhidopen: sc=%p\n", sc)); 265 266 if (sc->sc_dying) 267 return (ENXIO); 268 269 error = uhidev_open(&sc->sc_hdev); 270 if (error) 271 return (error); 272 273 if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1) { 274 uhidev_close(&sc->sc_hdev); 275 return (ENOMEM); 276 } 277 sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK); 278 sc->sc_state &= ~UHID_IMMED; 279 sc->sc_async = NULL; 280 281 return (0); 282 } 283 284 int 285 uhidclose(dev_t dev, int flag, int mode, struct lwp *l) 286 { 287 struct uhid_softc *sc; 288 289 USB_GET_SC(uhid, UHIDUNIT(dev), sc); 290 291 DPRINTF(("uhidclose: sc=%p\n", sc)); 292 293 clfree(&sc->sc_q); 294 free(sc->sc_obuf, M_USBDEV); 295 sc->sc_async = NULL; 296 uhidev_close(&sc->sc_hdev); 297 298 return (0); 299 } 300 301 int 302 uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag) 303 { 304 int s; 305 int error = 0; 306 int extra; 307 size_t length; 308 u_char buffer[UHID_CHUNK]; 309 usbd_status err; 310 311 DPRINTFN(1, ("uhidread\n")); 312 if (sc->sc_state & UHID_IMMED) { 313 DPRINTFN(1, ("uhidread immed\n")); 314 extra = sc->sc_hdev.sc_report_id != 0; 315 err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, 316 buffer, sc->sc_isize + extra); 317 if (err) 318 return (EIO); 319 return (uiomove(buffer+extra, sc->sc_isize, uio)); 320 } 321 322 s = splusb(); 323 while (sc->sc_q.c_cc == 0) { 324 if (flag & IO_NDELAY) { 325 splx(s); 326 return (EWOULDBLOCK); 327 } 328 sc->sc_state |= UHID_ASLP; 329 DPRINTFN(5, ("uhidread: sleep on %p\n", &sc->sc_q)); 330 error = tsleep(&sc->sc_q, PZERO | PCATCH, "uhidrea", 0); 331 DPRINTFN(5, ("uhidread: woke, error=%d\n", error)); 332 if (sc->sc_dying) 333 error = EIO; 334 if (error) { 335 sc->sc_state &= ~UHID_ASLP; 336 break; 337 } 338 } 339 splx(s); 340 341 /* Transfer as many chunks as possible. */ 342 while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) { 343 length = min(sc->sc_q.c_cc, uio->uio_resid); 344 if (length > sizeof(buffer)) 345 length = sizeof(buffer); 346 347 /* Remove a small chunk from the input queue. */ 348 (void) q_to_b(&sc->sc_q, buffer, length); 349 DPRINTFN(5, ("uhidread: got %lu chars\n", (u_long)length)); 350 351 /* Copy the data to the user process. */ 352 if ((error = uiomove(buffer, length, uio)) != 0) 353 break; 354 } 355 356 return (error); 357 } 358 359 int 360 uhidread(dev_t dev, struct uio *uio, int flag) 361 { 362 struct uhid_softc *sc; 363 int error; 364 365 USB_GET_SC(uhid, UHIDUNIT(dev), sc); 366 367 sc->sc_refcnt++; 368 error = uhid_do_read(sc, uio, flag); 369 if (--sc->sc_refcnt < 0) 370 usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev)); 371 return (error); 372 } 373 374 int 375 uhid_do_write(struct uhid_softc *sc, struct uio *uio, int flag) 376 { 377 int error; 378 int size; 379 usbd_status err; 380 381 DPRINTFN(1, ("uhidwrite\n")); 382 383 if (sc->sc_dying) 384 return (EIO); 385 386 size = sc->sc_osize; 387 error = 0; 388 if (uio->uio_resid != size) 389 return (EINVAL); 390 error = uiomove(sc->sc_obuf, size, uio); 391 if (!error) { 392 err = uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT, 393 sc->sc_obuf, size); 394 if (err) 395 error = EIO; 396 } 397 398 return (error); 399 } 400 401 int 402 uhidwrite(dev_t dev, struct uio *uio, int flag) 403 { 404 struct uhid_softc *sc; 405 int error; 406 407 USB_GET_SC(uhid, UHIDUNIT(dev), sc); 408 409 sc->sc_refcnt++; 410 error = uhid_do_write(sc, uio, flag); 411 if (--sc->sc_refcnt < 0) 412 usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev)); 413 return (error); 414 } 415 416 int 417 uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, 418 int flag, struct lwp *l) 419 { 420 struct usb_ctl_report_desc *rd; 421 struct usb_ctl_report *re; 422 u_char buffer[UHID_CHUNK]; 423 int size, extra; 424 usbd_status err; 425 void *desc; 426 427 DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd)); 428 429 if (sc->sc_dying) 430 return (EIO); 431 432 switch (cmd) { 433 case FIONBIO: 434 /* All handled in the upper FS layer. */ 435 break; 436 437 case FIOASYNC: 438 if (*(int *)addr) { 439 if (sc->sc_async != NULL) 440 return (EBUSY); 441 sc->sc_async = l->l_proc; 442 DPRINTF(("uhid_do_ioctl: FIOASYNC %p\n", l->l_proc)); 443 } else 444 sc->sc_async = NULL; 445 break; 446 447 /* XXX this is not the most general solution. */ 448 case TIOCSPGRP: 449 if (sc->sc_async == NULL) 450 return (EINVAL); 451 if (*(int *)addr != sc->sc_async->p_pgid) 452 return (EPERM); 453 break; 454 455 case FIOSETOWN: 456 if (sc->sc_async == NULL) 457 return (EINVAL); 458 if (-*(int *)addr != sc->sc_async->p_pgid 459 && *(int *)addr != sc->sc_async->p_pid); 460 return (EPERM); 461 break; 462 463 case USB_GET_REPORT_DESC: 464 uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size); 465 rd = (struct usb_ctl_report_desc *)addr; 466 size = min(size, sizeof rd->ucrd_data); 467 rd->ucrd_size = size; 468 memcpy(rd->ucrd_data, desc, size); 469 break; 470 471 case USB_SET_IMMED: 472 if (*(int *)addr) { 473 extra = sc->sc_hdev.sc_report_id != 0; 474 err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, 475 buffer, sc->sc_isize + extra); 476 if (err) 477 return (EOPNOTSUPP); 478 479 sc->sc_state |= UHID_IMMED; 480 } else 481 sc->sc_state &= ~UHID_IMMED; 482 break; 483 484 case USB_GET_REPORT: 485 re = (struct usb_ctl_report *)addr; 486 switch (re->ucr_report) { 487 case UHID_INPUT_REPORT: 488 size = sc->sc_isize; 489 break; 490 case UHID_OUTPUT_REPORT: 491 size = sc->sc_osize; 492 break; 493 case UHID_FEATURE_REPORT: 494 size = sc->sc_fsize; 495 break; 496 default: 497 return (EINVAL); 498 } 499 extra = sc->sc_hdev.sc_report_id != 0; 500 err = uhidev_get_report(&sc->sc_hdev, re->ucr_report, 501 re->ucr_data, size + extra); 502 if (extra) 503 memcpy(re->ucr_data, re->ucr_data+1, size); 504 if (err) 505 return (EIO); 506 break; 507 508 case USB_SET_REPORT: 509 re = (struct usb_ctl_report *)addr; 510 switch (re->ucr_report) { 511 case UHID_INPUT_REPORT: 512 size = sc->sc_isize; 513 break; 514 case UHID_OUTPUT_REPORT: 515 size = sc->sc_osize; 516 break; 517 case UHID_FEATURE_REPORT: 518 size = sc->sc_fsize; 519 break; 520 default: 521 return (EINVAL); 522 } 523 err = uhidev_set_report(&sc->sc_hdev, re->ucr_report, 524 re->ucr_data, size); 525 if (err) 526 return (EIO); 527 break; 528 529 case USB_GET_REPORT_ID: 530 *(int *)addr = sc->sc_hdev.sc_report_id; 531 break; 532 533 case USB_GET_DEVICEINFO: 534 usbd_fill_deviceinfo(sc->sc_hdev.sc_parent->sc_udev, 535 (struct usb_device_info *)addr, 1); 536 break; 537 538 case USB_GET_STRING_DESC: 539 { 540 struct usb_string_desc *si = (struct usb_string_desc *)addr; 541 err = usbd_get_string_desc(sc->sc_hdev.sc_parent->sc_udev, 542 si->usd_string_index, 543 si->usd_language_id, &si->usd_desc, &size); 544 if (err) 545 return (EINVAL); 546 break; 547 } 548 549 default: 550 return (EINVAL); 551 } 552 return (0); 553 } 554 555 int 556 uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct lwp *l) 557 { 558 struct uhid_softc *sc; 559 int error; 560 561 USB_GET_SC(uhid, UHIDUNIT(dev), sc); 562 563 sc->sc_refcnt++; 564 error = uhid_do_ioctl(sc, cmd, addr, flag, l); 565 if (--sc->sc_refcnt < 0) 566 usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev)); 567 return (error); 568 } 569 570 int 571 uhidpoll(dev_t dev, int events, struct lwp *l) 572 { 573 struct uhid_softc *sc; 574 int revents = 0; 575 int s; 576 577 USB_GET_SC(uhid, UHIDUNIT(dev), sc); 578 579 if (sc->sc_dying) 580 return (POLLHUP); 581 582 s = splusb(); 583 if (events & (POLLOUT | POLLWRNORM)) 584 revents |= events & (POLLOUT | POLLWRNORM); 585 if (events & (POLLIN | POLLRDNORM)) { 586 if (sc->sc_q.c_cc > 0) 587 revents |= events & (POLLIN | POLLRDNORM); 588 else 589 selrecord(l, &sc->sc_rsel); 590 } 591 592 splx(s); 593 return (revents); 594 } 595 596 static void 597 filt_uhidrdetach(struct knote *kn) 598 { 599 struct uhid_softc *sc = kn->kn_hook; 600 int s; 601 602 s = splusb(); 603 SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext); 604 splx(s); 605 } 606 607 static int 608 filt_uhidread(struct knote *kn, long hint) 609 { 610 struct uhid_softc *sc = kn->kn_hook; 611 612 kn->kn_data = sc->sc_q.c_cc; 613 return (kn->kn_data > 0); 614 } 615 616 static const struct filterops uhidread_filtops = 617 { 1, NULL, filt_uhidrdetach, filt_uhidread }; 618 619 static const struct filterops uhid_seltrue_filtops = 620 { 1, NULL, filt_uhidrdetach, filt_seltrue }; 621 622 int 623 uhidkqfilter(dev_t dev, struct knote *kn) 624 { 625 struct uhid_softc *sc; 626 struct klist *klist; 627 int s; 628 629 USB_GET_SC(uhid, UHIDUNIT(dev), sc); 630 631 if (sc->sc_dying) 632 return (EIO); 633 634 switch (kn->kn_filter) { 635 case EVFILT_READ: 636 klist = &sc->sc_rsel.sel_klist; 637 kn->kn_fop = &uhidread_filtops; 638 break; 639 640 case EVFILT_WRITE: 641 klist = &sc->sc_rsel.sel_klist; 642 kn->kn_fop = &uhid_seltrue_filtops; 643 break; 644 645 default: 646 return (1); 647 } 648 649 kn->kn_hook = sc; 650 651 s = splusb(); 652 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 653 splx(s); 654 655 return (0); 656 } 657