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