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