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