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