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