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