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