1 /* $OpenBSD: uhid.c,v 1.77 2020/02/20 16:56:52 visa 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 "fido.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 #include <sys/malloc.h> 44 #include <sys/signalvar.h> 45 #include <sys/device.h> 46 #include <sys/ioctl.h> 47 #include <sys/conf.h> 48 #include <sys/tty.h> 49 #include <sys/selinfo.h> 50 #include <sys/proc.h> 51 #include <sys/vnode.h> 52 #include <sys/poll.h> 53 54 #include <dev/usb/usb.h> 55 #include <dev/usb/usbhid.h> 56 57 #include <dev/usb/usbdevs.h> 58 #include <dev/usb/usbdi.h> 59 #include <dev/usb/usbdi_util.h> 60 61 #include <dev/usb/uhidev.h> 62 #include <dev/usb/uhid.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 int uhid_match(struct device *, void *, void *); 74 75 struct cfdriver uhid_cd = { 76 NULL, "uhid", DV_DULL 77 }; 78 79 const struct cfattach uhid_ca = { 80 sizeof(struct uhid_softc), 81 uhid_match, 82 uhid_attach, 83 uhid_detach, 84 }; 85 86 struct uhid_softc * 87 uhid_lookup(dev_t dev) 88 { 89 struct uhid_softc *sc = NULL; 90 struct cdevsw *cdev; 91 struct cfdriver *cd; 92 93 cdev = &cdevsw[major(dev)]; 94 if (cdev->d_open == uhidopen) 95 cd = &uhid_cd; 96 #if NFIDO > 0 97 else if (cdev->d_open == fidoopen) 98 cd = &fido_cd; 99 #endif 100 else 101 return (NULL); 102 if (UHIDUNIT(dev) < cd->cd_ndevs) 103 sc = cd->cd_devs[UHIDUNIT(dev)]; 104 105 return (sc); 106 } 107 108 int 109 uhid_match(struct device *parent, void *match, void *aux) 110 { 111 struct uhidev_attach_arg *uha = aux; 112 113 if (uha->reportid == UHIDEV_CLAIM_ALLREPORTID) 114 return (UMATCH_NONE); 115 116 return (UMATCH_IFACECLASS_GENERIC); 117 } 118 119 void 120 uhid_attach(struct device *parent, struct device *self, void *aux) 121 { 122 struct uhid_softc *sc = (struct uhid_softc *)self; 123 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 124 int size, repid; 125 void *desc; 126 127 sc->sc_hdev.sc_intr = uhid_intr; 128 sc->sc_hdev.sc_parent = uha->parent; 129 sc->sc_hdev.sc_udev = uha->uaa->device; 130 sc->sc_hdev.sc_report_id = uha->reportid; 131 132 uhidev_get_report_desc(uha->parent, &desc, &size); 133 repid = uha->reportid; 134 sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid); 135 sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid); 136 sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid); 137 138 printf(": input=%d, output=%d, feature=%d\n", 139 sc->sc_hdev.sc_isize, sc->sc_hdev.sc_osize, sc->sc_hdev.sc_fsize); 140 } 141 142 int 143 uhid_detach(struct device *self, int flags) 144 { 145 struct uhid_softc *sc = (struct uhid_softc *)self; 146 int s; 147 int maj, mn; 148 149 DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags)); 150 151 if (sc->sc_hdev.sc_state & UHIDEV_OPEN) { 152 s = splusb(); 153 if (--sc->sc_refcnt >= 0) { 154 /* Wake everyone */ 155 wakeup(&sc->sc_q); 156 /* Wait for processes to go away. */ 157 usb_detach_wait(&sc->sc_hdev.sc_dev); 158 } 159 splx(s); 160 } 161 162 /* locate the major number */ 163 for (maj = 0; maj < nchrdev; maj++) 164 if (cdevsw[maj].d_open == uhidopen) 165 break; 166 167 /* Nuke the vnodes for any open instances (calls close). */ 168 mn = self->dv_unit; 169 vdevgone(maj, mn, mn, VCHR); 170 171 s = splusb(); 172 klist_invalidate(&sc->sc_rsel.si_note); 173 splx(s); 174 175 return (0); 176 } 177 178 void 179 uhid_intr(struct uhidev *addr, void *data, u_int len) 180 { 181 struct uhid_softc *sc = (struct uhid_softc *)addr; 182 183 #ifdef UHID_DEBUG 184 if (uhiddebug > 5) { 185 u_int32_t i; 186 187 DPRINTF(("uhid_intr: data =")); 188 for (i = 0; i < len; i++) 189 DPRINTF((" %02x", ((u_char *)data)[i])); 190 DPRINTF(("\n")); 191 } 192 #endif 193 194 (void)b_to_q(data, len, &sc->sc_q); 195 196 if (sc->sc_state & UHID_ASLP) { 197 sc->sc_state &= ~UHID_ASLP; 198 DPRINTFN(5, ("uhid_intr: waking %p\n", &sc->sc_q)); 199 wakeup(&sc->sc_q); 200 } 201 selwakeup(&sc->sc_rsel); 202 } 203 204 int 205 uhidopen(dev_t dev, int flag, int mode, struct proc *p) 206 { 207 return (uhid_do_open(dev, flag, mode, p)); 208 } 209 210 int 211 uhid_do_open(dev_t dev, int flag, int mode, struct proc *p) 212 { 213 struct uhid_softc *sc; 214 int error; 215 216 if ((sc = uhid_lookup(dev)) == NULL) 217 return (ENXIO); 218 219 DPRINTF(("uhidopen: sc=%p\n", sc)); 220 221 if (usbd_is_dying(sc->sc_hdev.sc_udev)) 222 return (ENXIO); 223 224 error = uhidev_open(&sc->sc_hdev); 225 if (error) 226 return (error); 227 228 clalloc(&sc->sc_q, UHID_BSIZE, 0); 229 230 sc->sc_obuf = malloc(sc->sc_hdev.sc_osize, M_USBDEV, M_WAITOK); 231 232 return (0); 233 } 234 235 int 236 uhidclose(dev_t dev, int flag, int mode, struct proc *p) 237 { 238 struct uhid_softc *sc; 239 240 if ((sc = uhid_lookup(dev)) == NULL) 241 return (ENXIO); 242 243 DPRINTF(("uhidclose: sc=%p\n", sc)); 244 245 clfree(&sc->sc_q); 246 free(sc->sc_obuf, M_USBDEV, sc->sc_hdev.sc_osize); 247 uhidev_close(&sc->sc_hdev); 248 249 return (0); 250 } 251 252 int 253 uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag) 254 { 255 int s; 256 int error = 0; 257 size_t length; 258 u_char buffer[UHID_CHUNK]; 259 260 DPRINTFN(1, ("uhidread\n")); 261 262 s = splusb(); 263 while (sc->sc_q.c_cc == 0) { 264 if (flag & IO_NDELAY) { 265 splx(s); 266 return (EWOULDBLOCK); 267 } 268 sc->sc_state |= UHID_ASLP; 269 DPRINTFN(5, ("uhidread: sleep on %p\n", &sc->sc_q)); 270 error = tsleep_nsec(&sc->sc_q, PZERO|PCATCH, "uhidrea", INFSLP); 271 DPRINTFN(5, ("uhidread: woke, error=%d\n", error)); 272 if (usbd_is_dying(sc->sc_hdev.sc_udev)) 273 error = EIO; 274 if (error) { 275 sc->sc_state &= ~UHID_ASLP; 276 break; 277 } 278 } 279 splx(s); 280 281 /* Transfer as many chunks as possible. */ 282 while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) { 283 length = ulmin(sc->sc_q.c_cc, uio->uio_resid); 284 if (length > sizeof(buffer)) 285 length = sizeof(buffer); 286 287 /* Remove a small chunk from the input queue. */ 288 (void) q_to_b(&sc->sc_q, buffer, length); 289 DPRINTFN(5, ("uhidread: got %zu chars\n", length)); 290 291 /* Copy the data to the user process. */ 292 if ((error = uiomove(buffer, length, uio)) != 0) 293 break; 294 } 295 296 return (error); 297 } 298 299 int 300 uhidread(dev_t dev, struct uio *uio, int flag) 301 { 302 struct uhid_softc *sc; 303 int error; 304 305 if ((sc = uhid_lookup(dev)) == NULL) 306 return (ENXIO); 307 308 sc->sc_refcnt++; 309 error = uhid_do_read(sc, uio, flag); 310 if (--sc->sc_refcnt < 0) 311 usb_detach_wakeup(&sc->sc_hdev.sc_dev); 312 return (error); 313 } 314 315 int 316 uhid_do_write(struct uhid_softc *sc, struct uio *uio, int flag) 317 { 318 int error; 319 int size; 320 321 DPRINTFN(1, ("uhidwrite\n")); 322 323 if (usbd_is_dying(sc->sc_hdev.sc_udev)) 324 return (EIO); 325 326 size = sc->sc_hdev.sc_osize; 327 error = 0; 328 if (uio->uio_resid > size) 329 return (EMSGSIZE); 330 else if (uio->uio_resid < size) { 331 /* don't leak kernel memory to the USB device */ 332 memset(sc->sc_obuf + uio->uio_resid, 0, size - uio->uio_resid); 333 } 334 error = uiomove(sc->sc_obuf, uio->uio_resid, uio); 335 if (!error) { 336 if (uhidev_set_report(sc->sc_hdev.sc_parent, 337 UHID_OUTPUT_REPORT, sc->sc_hdev.sc_report_id, sc->sc_obuf, 338 size) != size) 339 error = EIO; 340 } 341 342 return (error); 343 } 344 345 int 346 uhidwrite(dev_t dev, struct uio *uio, int flag) 347 { 348 struct uhid_softc *sc; 349 int error; 350 351 if ((sc = uhid_lookup(dev)) == NULL) 352 return (ENXIO); 353 354 sc->sc_refcnt++; 355 error = uhid_do_write(sc, uio, flag); 356 if (--sc->sc_refcnt < 0) 357 usb_detach_wakeup(&sc->sc_hdev.sc_dev); 358 return (error); 359 } 360 361 int 362 uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, 363 int flag, struct proc *p) 364 { 365 int rc; 366 367 DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd)); 368 369 if (usbd_is_dying(sc->sc_hdev.sc_udev)) 370 return (EIO); 371 372 switch (cmd) { 373 case FIONBIO: 374 case FIOASYNC: 375 /* All handled in the upper FS layer. */ 376 break; 377 378 case USB_GET_DEVICEINFO: 379 usbd_fill_deviceinfo(sc->sc_hdev.sc_udev, 380 (struct usb_device_info *)addr); 381 break; 382 383 case USB_GET_REPORT_DESC: 384 case USB_GET_REPORT: 385 case USB_SET_REPORT: 386 case USB_GET_REPORT_ID: 387 default: 388 rc = uhidev_ioctl(&sc->sc_hdev, cmd, addr, flag, p); 389 if (rc == -1) 390 rc = EINVAL; 391 return rc; 392 } 393 return (0); 394 } 395 396 int 397 uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 398 { 399 struct uhid_softc *sc; 400 int error; 401 402 if ((sc = uhid_lookup(dev)) == NULL) 403 return (ENXIO); 404 405 sc->sc_refcnt++; 406 error = uhid_do_ioctl(sc, cmd, addr, flag, p); 407 if (--sc->sc_refcnt < 0) 408 usb_detach_wakeup(&sc->sc_hdev.sc_dev); 409 return (error); 410 } 411 412 int 413 uhidpoll(dev_t dev, int events, struct proc *p) 414 { 415 struct uhid_softc *sc; 416 int revents = 0; 417 int s; 418 419 if ((sc = uhid_lookup(dev)) == NULL) 420 return (POLLERR); 421 422 if (usbd_is_dying(sc->sc_hdev.sc_udev)) 423 return (POLLHUP); 424 425 s = splusb(); 426 if (events & (POLLOUT | POLLWRNORM)) 427 revents |= events & (POLLOUT | POLLWRNORM); 428 if (events & (POLLIN | POLLRDNORM)) { 429 if (sc->sc_q.c_cc > 0) 430 revents |= events & (POLLIN | POLLRDNORM); 431 else 432 selrecord(p, &sc->sc_rsel); 433 } 434 435 splx(s); 436 return (revents); 437 } 438 439 void filt_uhidrdetach(struct knote *); 440 int filt_uhidread(struct knote *, long); 441 int uhidkqfilter(dev_t, struct knote *); 442 443 void 444 filt_uhidrdetach(struct knote *kn) 445 { 446 struct uhid_softc *sc = (void *)kn->kn_hook; 447 int s; 448 449 s = splusb(); 450 SLIST_REMOVE(&sc->sc_rsel.si_note, kn, knote, kn_selnext); 451 splx(s); 452 } 453 454 int 455 filt_uhidread(struct knote *kn, long hint) 456 { 457 struct uhid_softc *sc = (void *)kn->kn_hook; 458 459 kn->kn_data = sc->sc_q.c_cc; 460 return (kn->kn_data > 0); 461 } 462 463 const struct filterops uhidread_filtops = { 464 .f_flags = FILTEROP_ISFD, 465 .f_attach = NULL, 466 .f_detach = filt_uhidrdetach, 467 .f_event = filt_uhidread, 468 }; 469 470 const struct filterops uhid_seltrue_filtops = { 471 .f_flags = FILTEROP_ISFD, 472 .f_attach = NULL, 473 .f_detach = filt_uhidrdetach, 474 .f_event = filt_seltrue, 475 }; 476 477 int 478 uhidkqfilter(dev_t dev, struct knote *kn) 479 { 480 struct uhid_softc *sc; 481 struct klist *klist; 482 int s; 483 484 if ((sc = uhid_lookup(dev)) == NULL) 485 return (ENXIO); 486 487 if (usbd_is_dying(sc->sc_hdev.sc_udev)) 488 return (EIO); 489 490 switch (kn->kn_filter) { 491 case EVFILT_READ: 492 klist = &sc->sc_rsel.si_note; 493 kn->kn_fop = &uhidread_filtops; 494 break; 495 496 case EVFILT_WRITE: 497 klist = &sc->sc_rsel.si_note; 498 kn->kn_fop = &uhid_seltrue_filtops; 499 break; 500 501 default: 502 return (EINVAL); 503 } 504 505 kn->kn_hook = (void *)sc; 506 507 s = splusb(); 508 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 509 splx(s); 510 511 return (0); 512 } 513