1 /* $OpenBSD: uhid.c,v 1.89 2022/07/02 08:50:42 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: 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 error = uhidev_open(&sc->sc_hdev); 229 if (error) 230 return (error); 231 232 clalloc(&sc->sc_q, UHID_BSIZE, 0); 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 FIONBIO: 378 case FIOASYNC: 379 /* All handled in the upper FS layer. */ 380 break; 381 382 case USB_GET_DEVICEINFO: 383 usbd_fill_deviceinfo(sc->sc_hdev.sc_udev, 384 (struct usb_device_info *)addr); 385 break; 386 387 case USB_GET_REPORT_DESC: 388 case USB_GET_REPORT: 389 case USB_SET_REPORT: 390 case USB_GET_REPORT_ID: 391 default: 392 rc = uhidev_ioctl(&sc->sc_hdev, cmd, addr, flag, p); 393 if (rc == -1) 394 rc = ENOTTY; 395 return rc; 396 } 397 return (0); 398 } 399 400 int 401 uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 402 { 403 struct uhid_softc *sc; 404 int error; 405 406 if ((sc = uhid_lookup(dev)) == NULL) 407 return (ENXIO); 408 409 sc->sc_refcnt++; 410 error = uhid_do_ioctl(sc, cmd, addr, flag, p); 411 if (--sc->sc_refcnt < 0) 412 usb_detach_wakeup(&sc->sc_hdev.sc_dev); 413 return (error); 414 } 415 416 void filt_uhidrdetach(struct knote *); 417 int filt_uhidread(struct knote *, long); 418 int uhidkqfilter(dev_t, struct knote *); 419 420 void 421 filt_uhidrdetach(struct knote *kn) 422 { 423 struct uhid_softc *sc = (void *)kn->kn_hook; 424 int s; 425 426 s = splusb(); 427 klist_remove_locked(&sc->sc_rsel.si_note, kn); 428 splx(s); 429 } 430 431 int 432 filt_uhidread(struct knote *kn, long hint) 433 { 434 struct uhid_softc *sc = (void *)kn->kn_hook; 435 436 kn->kn_data = sc->sc_q.c_cc; 437 return (kn->kn_data > 0); 438 } 439 440 const struct filterops uhidread_filtops = { 441 .f_flags = FILTEROP_ISFD, 442 .f_attach = NULL, 443 .f_detach = filt_uhidrdetach, 444 .f_event = filt_uhidread, 445 }; 446 447 int 448 uhidkqfilter(dev_t dev, struct knote *kn) 449 { 450 struct uhid_softc *sc; 451 struct klist *klist; 452 int s; 453 454 if ((sc = uhid_lookup(dev)) == NULL) 455 return (ENXIO); 456 457 if (usbd_is_dying(sc->sc_hdev.sc_udev)) 458 return (ENXIO); 459 460 switch (kn->kn_filter) { 461 case EVFILT_READ: 462 klist = &sc->sc_rsel.si_note; 463 kn->kn_fop = &uhidread_filtops; 464 break; 465 466 case EVFILT_WRITE: 467 return (seltrue_kqfilter(dev, kn)); 468 469 default: 470 return (EINVAL); 471 } 472 473 kn->kn_hook = (void *)sc; 474 475 s = splusb(); 476 klist_insert_locked(klist, kn); 477 splx(s); 478 479 return (0); 480 } 481