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