1 /* $OpenBSD: uhid.c,v 1.53 2011/07/03 15:47:17 matthew 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 u_char *sc_obuf; 77 78 struct clist sc_q; 79 struct selinfo sc_rsel; 80 struct process *sc_async; /* process that wants SIGIO */ 81 u_char sc_state; /* driver state */ 82 #define UHID_ASLP 0x01 /* waiting for device data */ 83 #define UHID_IMMED 0x02 /* return read data immediately */ 84 85 int sc_refcnt; 86 u_char sc_dying; 87 }; 88 89 #define UHIDUNIT(dev) (minor(dev)) 90 #define UHID_CHUNK 128 /* chunk size for read */ 91 #define UHID_BSIZE 1020 /* buffer size */ 92 93 void uhid_intr(struct uhidev *, void *, u_int len); 94 95 int uhid_do_read(struct uhid_softc *, struct uio *uio, int); 96 int uhid_do_write(struct uhid_softc *, struct uio *uio, int); 97 int uhid_do_ioctl(struct uhid_softc*, u_long, caddr_t, int, 98 struct proc *); 99 100 int uhid_match(struct device *, void *, void *); 101 void uhid_attach(struct device *, struct device *, void *); 102 int uhid_detach(struct device *, int); 103 int uhid_activate(struct device *, int); 104 105 struct cfdriver uhid_cd = { 106 NULL, "uhid", DV_DULL 107 }; 108 109 const struct cfattach uhid_ca = { 110 sizeof(struct uhid_softc), 111 uhid_match, 112 uhid_attach, 113 uhid_detach, 114 uhid_activate, 115 }; 116 117 int 118 uhid_match(struct device *parent, void *match, void *aux) 119 { 120 struct usb_attach_arg *uaa = aux; 121 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; 122 123 DPRINTF(("uhid_match: report=%d\n", uha->reportid)); 124 125 if (uha->matchlvl) 126 return (uha->matchlvl); 127 return (UMATCH_IFACECLASS_GENERIC); 128 } 129 130 void 131 uhid_attach(struct device *parent, struct device *self, void *aux) 132 { 133 struct uhid_softc *sc = (struct uhid_softc *)self; 134 struct usb_attach_arg *uaa = aux; 135 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; 136 int size, repid; 137 void *desc; 138 139 sc->sc_hdev.sc_intr = uhid_intr; 140 sc->sc_hdev.sc_parent = uha->parent; 141 sc->sc_hdev.sc_report_id = uha->reportid; 142 143 uhidev_get_report_desc(uha->parent, &desc, &size); 144 repid = uha->reportid; 145 sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid); 146 sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid); 147 sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid); 148 149 printf(": input=%d, output=%d, feature=%d\n", 150 sc->sc_hdev.sc_isize, sc->sc_hdev.sc_osize, sc->sc_hdev.sc_fsize); 151 } 152 153 int 154 uhid_activate(struct device *self, int act) 155 { 156 struct uhid_softc *sc = (struct uhid_softc *)self; 157 158 switch (act) { 159 case DVACT_DEACTIVATE: 160 sc->sc_dying = 1; 161 break; 162 } 163 return (0); 164 } 165 166 int 167 uhid_detach(struct device *self, int flags) 168 { 169 struct uhid_softc *sc = (struct uhid_softc *)self; 170 int s; 171 int maj, mn; 172 173 DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags)); 174 175 if (sc->sc_hdev.sc_state & UHIDEV_OPEN) { 176 s = splusb(); 177 if (--sc->sc_refcnt >= 0) { 178 /* Wake everyone */ 179 wakeup(&sc->sc_q); 180 /* Wait for processes to go away. */ 181 usb_detach_wait(&sc->sc_hdev.sc_dev); 182 } 183 splx(s); 184 } 185 186 /* locate the major number */ 187 for (maj = 0; maj < nchrdev; maj++) 188 if (cdevsw[maj].d_open == uhidopen) 189 break; 190 191 /* Nuke the vnodes for any open instances (calls close). */ 192 mn = self->dv_unit; 193 vdevgone(maj, mn, mn, VCHR); 194 195 return (0); 196 } 197 198 void 199 uhid_intr(struct uhidev *addr, void *data, u_int len) 200 { 201 struct uhid_softc *sc = (struct uhid_softc *)addr; 202 203 #ifdef UHID_DEBUG 204 if (uhiddebug > 5) { 205 u_int32_t i; 206 207 DPRINTF(("uhid_intr: data =")); 208 for (i = 0; i < len; i++) 209 DPRINTF((" %02x", ((u_char *)data)[i])); 210 DPRINTF(("\n")); 211 } 212 #endif 213 214 (void)b_to_q(data, len, &sc->sc_q); 215 216 if (sc->sc_state & UHID_ASLP) { 217 sc->sc_state &= ~UHID_ASLP; 218 DPRINTFN(5, ("uhid_intr: waking %p\n", &sc->sc_q)); 219 wakeup(&sc->sc_q); 220 } 221 selwakeup(&sc->sc_rsel); 222 if (sc->sc_async != NULL) { 223 DPRINTFN(3, ("uhid_intr: sending SIGIO %p\n", sc->sc_async)); 224 prsignal(sc->sc_async, SIGIO); 225 } 226 } 227 228 int 229 uhidopen(dev_t dev, int flag, int mode, struct proc *p) 230 { 231 struct uhid_softc *sc; 232 int error; 233 234 if (UHIDUNIT(dev) >= uhid_cd.cd_ndevs) 235 return (ENXIO); 236 sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; 237 if (sc == NULL) 238 return (ENXIO); 239 240 DPRINTF(("uhidopen: sc=%p\n", sc)); 241 242 if (sc->sc_dying) 243 return (ENXIO); 244 245 error = uhidev_open(&sc->sc_hdev); 246 if (error) 247 return (error); 248 249 clalloc(&sc->sc_q, UHID_BSIZE, 0); 250 251 sc->sc_obuf = malloc(sc->sc_hdev.sc_osize, M_USBDEV, M_WAITOK); 252 sc->sc_state &= ~UHID_IMMED; 253 sc->sc_async = NULL; 254 255 return (0); 256 } 257 258 int 259 uhidclose(dev_t dev, int flag, int mode, struct proc *p) 260 { 261 struct uhid_softc *sc; 262 263 sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; 264 265 DPRINTF(("uhidclose: sc=%p\n", sc)); 266 267 clfree(&sc->sc_q); 268 free(sc->sc_obuf, M_USBDEV); 269 sc->sc_async = NULL; 270 uhidev_close(&sc->sc_hdev); 271 272 return (0); 273 } 274 275 int 276 uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag) 277 { 278 int s; 279 int error = 0; 280 int extra; 281 size_t length; 282 u_char buffer[UHID_CHUNK]; 283 usbd_status err; 284 285 DPRINTFN(1, ("uhidread\n")); 286 if (sc->sc_state & UHID_IMMED) { 287 DPRINTFN(1, ("uhidread immed\n")); 288 extra = sc->sc_hdev.sc_report_id != 0; 289 err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, 290 buffer, sc->sc_hdev.sc_isize + extra); 291 if (err) 292 return (EIO); 293 return (uiomove(buffer+extra, sc->sc_hdev.sc_isize, uio)); 294 } 295 296 s = splusb(); 297 while (sc->sc_q.c_cc == 0) { 298 if (flag & IO_NDELAY) { 299 splx(s); 300 return (EWOULDBLOCK); 301 } 302 sc->sc_state |= UHID_ASLP; 303 DPRINTFN(5, ("uhidread: sleep on %p\n", &sc->sc_q)); 304 error = tsleep(&sc->sc_q, PZERO | PCATCH, "uhidrea", 0); 305 DPRINTFN(5, ("uhidread: woke, error=%d\n", error)); 306 if (sc->sc_dying) 307 error = EIO; 308 if (error) { 309 sc->sc_state &= ~UHID_ASLP; 310 break; 311 } 312 } 313 splx(s); 314 315 /* Transfer as many chunks as possible. */ 316 while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) { 317 length = min(sc->sc_q.c_cc, uio->uio_resid); 318 if (length > sizeof(buffer)) 319 length = sizeof(buffer); 320 321 /* Remove a small chunk from the input queue. */ 322 (void) q_to_b(&sc->sc_q, buffer, length); 323 DPRINTFN(5, ("uhidread: got %lu chars\n", (u_long)length)); 324 325 /* Copy the data to the user process. */ 326 if ((error = uiomove(buffer, length, uio)) != 0) 327 break; 328 } 329 330 return (error); 331 } 332 333 int 334 uhidread(dev_t dev, struct uio *uio, int flag) 335 { 336 struct uhid_softc *sc; 337 int error; 338 339 sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; 340 341 sc->sc_refcnt++; 342 error = uhid_do_read(sc, uio, flag); 343 if (--sc->sc_refcnt < 0) 344 usb_detach_wakeup(&sc->sc_hdev.sc_dev); 345 return (error); 346 } 347 348 int 349 uhid_do_write(struct uhid_softc *sc, struct uio *uio, int flag) 350 { 351 int error; 352 int size; 353 usbd_status err; 354 355 DPRINTFN(1, ("uhidwrite\n")); 356 357 if (sc->sc_dying) 358 return (EIO); 359 360 size = sc->sc_hdev.sc_osize; 361 error = 0; 362 if (uio->uio_resid != size) 363 return (EINVAL); 364 error = uiomove(sc->sc_obuf, size, uio); 365 if (!error) { 366 err = uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT, 367 sc->sc_obuf, size); 368 if (err) 369 error = EIO; 370 } 371 372 return (error); 373 } 374 375 int 376 uhidwrite(dev_t dev, struct uio *uio, int flag) 377 { 378 struct uhid_softc *sc; 379 int error; 380 381 sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; 382 383 sc->sc_refcnt++; 384 error = uhid_do_write(sc, uio, flag); 385 if (--sc->sc_refcnt < 0) 386 usb_detach_wakeup(&sc->sc_hdev.sc_dev); 387 return (error); 388 } 389 390 int 391 uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, 392 int flag, struct proc *p) 393 { 394 u_char buffer[UHID_CHUNK]; 395 int size, extra; 396 usbd_status err; 397 int rc; 398 399 DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd)); 400 401 if (sc->sc_dying) 402 return (EIO); 403 404 switch (cmd) { 405 case FIONBIO: 406 /* All handled in the upper FS layer. */ 407 break; 408 409 case FIOASYNC: 410 if (*(int *)addr) { 411 if (sc->sc_async != NULL) 412 return (EBUSY); 413 sc->sc_async = p->p_p; 414 DPRINTF(("uhid_do_ioctl: FIOASYNC %p\n", p)); 415 } else 416 sc->sc_async = NULL; 417 break; 418 419 /* XXX this is not the most general solution. */ 420 case TIOCSPGRP: 421 if (sc->sc_async == NULL) 422 return (EINVAL); 423 if (*(int *)addr != sc->sc_async->ps_pgid) 424 return (EPERM); 425 break; 426 427 case USB_SET_IMMED: 428 if (*(int *)addr) { 429 extra = sc->sc_hdev.sc_report_id != 0; 430 err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, 431 buffer, sc->sc_hdev.sc_isize + extra); 432 if (err) 433 return (EOPNOTSUPP); 434 435 sc->sc_state |= UHID_IMMED; 436 } else 437 sc->sc_state &= ~UHID_IMMED; 438 break; 439 440 case USB_GET_DEVICEINFO: 441 usbd_fill_deviceinfo(sc->sc_hdev.sc_parent->sc_udev, 442 (struct usb_device_info *)addr, 1); 443 break; 444 445 case USB_GET_STRING_DESC: 446 { 447 struct usb_string_desc *si = (struct usb_string_desc *)addr; 448 err = usbd_get_string_desc(sc->sc_hdev.sc_parent->sc_udev, 449 si->usd_string_index, 450 si->usd_language_id, &si->usd_desc, &size); 451 if (err) 452 return (EINVAL); 453 break; 454 } 455 456 case USB_GET_REPORT_DESC: 457 case USB_GET_REPORT: 458 case USB_SET_REPORT: 459 case USB_GET_REPORT_ID: 460 default: 461 rc = uhidev_ioctl(&sc->sc_hdev, cmd, addr, flag, p); 462 if (rc == -1) 463 rc = EINVAL; 464 return rc; 465 } 466 return (0); 467 } 468 469 int 470 uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 471 { 472 struct uhid_softc *sc; 473 int error; 474 475 sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; 476 477 sc->sc_refcnt++; 478 error = uhid_do_ioctl(sc, cmd, addr, flag, p); 479 if (--sc->sc_refcnt < 0) 480 usb_detach_wakeup(&sc->sc_hdev.sc_dev); 481 return (error); 482 } 483 484 int 485 uhidpoll(dev_t dev, int events, struct proc *p) 486 { 487 struct uhid_softc *sc; 488 int revents = 0; 489 int s; 490 491 sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; 492 493 if (sc->sc_dying) 494 return (POLLERR); 495 496 s = splusb(); 497 if (events & (POLLOUT | POLLWRNORM)) 498 revents |= events & (POLLOUT | POLLWRNORM); 499 if (events & (POLLIN | POLLRDNORM)) { 500 if (sc->sc_q.c_cc > 0) 501 revents |= events & (POLLIN | POLLRDNORM); 502 else 503 selrecord(p, &sc->sc_rsel); 504 } 505 506 splx(s); 507 return (revents); 508 } 509 510 void filt_uhidrdetach(struct knote *); 511 int filt_uhidread(struct knote *, long); 512 int uhidkqfilter(dev_t, struct knote *); 513 514 void 515 filt_uhidrdetach(struct knote *kn) 516 { 517 struct uhid_softc *sc = (void *)kn->kn_hook; 518 int s; 519 520 s = splusb(); 521 SLIST_REMOVE(&sc->sc_rsel.si_note, kn, knote, kn_selnext); 522 splx(s); 523 } 524 525 int 526 filt_uhidread(struct knote *kn, long hint) 527 { 528 struct uhid_softc *sc = (void *)kn->kn_hook; 529 530 kn->kn_data = sc->sc_q.c_cc; 531 return (kn->kn_data > 0); 532 } 533 534 struct filterops uhidread_filtops = 535 { 1, NULL, filt_uhidrdetach, filt_uhidread }; 536 537 struct filterops uhid_seltrue_filtops = 538 { 1, NULL, filt_uhidrdetach, filt_seltrue }; 539 540 int 541 uhidkqfilter(dev_t dev, struct knote *kn) 542 { 543 struct uhid_softc *sc; 544 struct klist *klist; 545 int s; 546 547 sc = uhid_cd.cd_devs[UHIDUNIT(dev)]; 548 549 if (sc->sc_dying) 550 return (EIO); 551 552 switch (kn->kn_filter) { 553 case EVFILT_READ: 554 klist = &sc->sc_rsel.si_note; 555 kn->kn_fop = &uhidread_filtops; 556 break; 557 558 case EVFILT_WRITE: 559 klist = &sc->sc_rsel.si_note; 560 kn->kn_fop = &uhid_seltrue_filtops; 561 break; 562 563 default: 564 return (EINVAL); 565 } 566 567 kn->kn_hook = (void *)sc; 568 569 s = splusb(); 570 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 571 splx(s); 572 573 return (0); 574 } 575