1 /* $OpenBSD: usb.c,v 1.5 1999/09/27 18:03:56 fgsch Exp $ */ 2 /* $NetBSD: usb.c,v 1.24 1999/09/15 21:10:11 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 (augustss@carlstedt.se) 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 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the NetBSD 23 * Foundation, Inc. and its contributors. 24 * 4. Neither the name of The NetBSD Foundation nor the names of its 25 * contributors may be used to endorse or promote products derived 26 * from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 /* 42 * USB specifications and other documentation can be found at 43 * http://www.usb.org/developers/data/ and 44 * http://www.usb.org/developers/index.html . 45 */ 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/kernel.h> 50 #include <sys/malloc.h> 51 #if defined(__NetBSD__) || defined(__OpenBSD__) 52 #include <sys/device.h> 53 #include <sys/kthread.h> 54 #elif defined(__FreeBSD__) 55 #include <sys/module.h> 56 #include <sys/bus.h> 57 #include <sys/ioccom.h> 58 #include <sys/uio.h> 59 #include <sys/conf.h> 60 #endif 61 #include <sys/conf.h> 62 #include <sys/poll.h> 63 #include <sys/proc.h> 64 #include <sys/select.h> 65 66 #include <dev/usb/usb.h> 67 #include <dev/usb/usbdi.h> 68 #include <dev/usb/usbdi_util.h> 69 70 #if defined(__FreeBSD__) 71 MALLOC_DEFINE(M_USB, "USB", "USB"); 72 MALLOC_DEFINE(M_USBDEV, "USBdev", "USB device"); 73 MALLOC_DEFINE(M_USBHC, "USBHC", "USB host controller"); 74 75 #include "usb_if.h" 76 #endif /* defined(__FreeBSD__) */ 77 78 #include <machine/bus.h> 79 80 #include <dev/usb/usbdivar.h> 81 #include <dev/usb/usb_quirks.h> 82 83 #ifdef USB_DEBUG 84 #define DPRINTF(x) if (usbdebug) logprintf x 85 #define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x 86 int usbdebug = 0; 87 int uhcidebug; 88 int ohcidebug; 89 int usb_noexplore = 0; 90 #else 91 #define DPRINTF(x) 92 #define DPRINTFN(n,x) 93 #endif 94 95 int usb_nbus = 0; 96 97 #define USBUNIT(dev) (minor(dev)) 98 99 struct usb_softc { 100 USBBASEDEVICE sc_dev; /* base device */ 101 usbd_bus_handle sc_bus; /* USB controller */ 102 struct usbd_port sc_port; /* dummy port for root hub */ 103 104 struct selinfo sc_consel; /* waiting for connect change */ 105 struct proc *sc_event_thread; 106 107 char sc_dying; 108 }; 109 110 #if defined(__NetBSD__) || defined(__OpenBSD__) 111 cdev_decl(usb); 112 #elif defined(__FreeBSD__) 113 d_open_t usbopen; 114 d_close_t usbclose; 115 d_ioctl_t usbioctl; 116 int usbpoll __P((dev_t, int, struct proc *)); 117 118 struct cdevsw usb_cdevsw = { 119 usbopen, usbclose, noread, nowrite, 120 usbioctl, nullstop, nullreset, nodevtotty, 121 usbpoll, nommap, nostrat, 122 "usb", NULL, -1 123 }; 124 #endif 125 126 usbd_status usb_discover __P((struct usb_softc *)); 127 void usb_create_event_thread __P((void *)); 128 void usb_event_thread __P((void *)); 129 130 /* Flag to see if we are in the cold boot process. */ 131 extern int cold; 132 133 USB_DECLARE_DRIVER_INIT(usb, DEVMETHOD(bus_print_child, usbd_print_child)); 134 135 USB_MATCH(usb) 136 { 137 DPRINTF(("usbd_match\n")); 138 return (UMATCH_GENERIC); 139 } 140 141 USB_ATTACH(usb) 142 { 143 #if defined(__NetBSD__) || defined(__OpenBSD__) 144 struct usb_softc *sc = (struct usb_softc *)self; 145 #elif defined(__FreeBSD__) 146 struct usb_softc *sc = device_get_softc(self); 147 void *aux = device_get_ivars(self); 148 #endif 149 usbd_device_handle dev; 150 usbd_status r; 151 152 #if defined(__NetBSD__) || defined(__OpenBSD__) 153 printf("\n"); 154 #elif defined(__FreeBSD__) 155 sc->sc_dev = self; 156 #endif 157 158 DPRINTF(("usbd_attach\n")); 159 usbd_init(); 160 sc->sc_bus = aux; 161 sc->sc_bus->usbctl = sc; 162 sc->sc_port.power = USB_MAX_POWER; 163 r = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0, 0, 0, 164 &sc->sc_port); 165 166 if (r == USBD_NORMAL_COMPLETION) { 167 dev = sc->sc_port.device; 168 if (!dev->hub) { 169 sc->sc_dying = 1; 170 printf("%s: root device is not a hub\n", 171 USBDEVNAME(sc->sc_dev)); 172 USB_ATTACH_ERROR_RETURN; 173 } 174 sc->sc_bus->root_hub = dev; 175 #if 1 176 /* 177 * Turning this code off will delay attachment of USB devices 178 * until the USB event thread is running, which means that 179 * the keyboard will not work until after cold boot. 180 */ 181 if (cold) { 182 sc->sc_bus->use_polling++; 183 dev->hub->explore(sc->sc_bus->root_hub); 184 sc->sc_bus->use_polling--; 185 } 186 #endif 187 } else { 188 printf("%s: root hub problem, error=%d\n", 189 USBDEVNAME(sc->sc_dev), r); 190 sc->sc_dying = 1; 191 } 192 193 #if defined(__OpenBSD__) 194 kthread_create_deferred(usb_create_event_thread, sc); 195 #else 196 kthread_create(usb_create_event_thread, sc); 197 #endif 198 199 usb_nbus++; 200 USB_ATTACH_SUCCESS_RETURN; 201 } 202 203 void 204 usb_create_event_thread(arg) 205 void *arg; 206 { 207 struct usb_softc *sc = arg; 208 209 #if !defined(__OpenBSD__) 210 if (kthread_create1(usb_event_thread, sc, &sc->sc_event_thread, 211 #else 212 if (kthread_create(usb_event_thread, sc, &sc->sc_event_thread, 213 #endif 214 "%s", sc->sc_dev.dv_xname)) { 215 printf("%s: unable to create event thread for\n", 216 sc->sc_dev.dv_xname); 217 panic("usb_create_event_thread"); 218 } 219 } 220 221 void 222 usb_event_thread(arg) 223 void *arg; 224 { 225 struct usb_softc *sc = arg; 226 227 while (!sc->sc_dying) { 228 #ifdef USB_DEBUG 229 if (!usb_noexplore) 230 #endif 231 usb_discover(sc); 232 (void)tsleep(&sc->sc_bus->needs_explore, 233 PWAIT, "usbevt", hz*60); 234 DPRINTFN(2,("usb_event_thread: woke up\n")); 235 } 236 sc->sc_event_thread = 0; 237 238 /* In case parent is waiting for us to exit. */ 239 wakeup(sc); 240 241 kthread_exit(0); 242 } 243 244 #if defined(__NetBSD__) || defined(__OpenBSD__) 245 int 246 usbctlprint(aux, pnp) 247 void *aux; 248 const char *pnp; 249 { 250 /* only "usb"es can attach to host controllers */ 251 if (pnp) 252 printf("usb at %s", pnp); 253 254 return (UNCONF); 255 } 256 #endif 257 258 int 259 usbopen(dev, flag, mode, p) 260 dev_t dev; 261 int flag, mode; 262 struct proc *p; 263 { 264 USB_GET_SC_OPEN(usb, USBUNIT(dev), sc); 265 266 if (sc == 0) 267 return (ENXIO); 268 if (sc->sc_dying) 269 return (EIO); 270 271 return (0); 272 } 273 274 int 275 usbclose(dev, flag, mode, p) 276 dev_t dev; 277 int flag, mode; 278 struct proc *p; 279 { 280 return (0); 281 } 282 283 int 284 usbioctl(dev, cmd, data, flag, p) 285 dev_t dev; 286 u_long cmd; 287 caddr_t data; 288 int flag; 289 struct proc *p; 290 { 291 USB_GET_SC(usb, USBUNIT(dev), sc); 292 293 if (sc->sc_dying) 294 return (EIO); 295 296 switch (cmd) { 297 #ifdef USB_DEBUG 298 case USB_SETDEBUG: 299 usbdebug = uhcidebug = ohcidebug = *(int *)data; 300 break; 301 #endif 302 case USB_REQUEST: 303 { 304 struct usb_ctl_request *ur = (void *)data; 305 int len = UGETW(ur->request.wLength); 306 struct iovec iov; 307 struct uio uio; 308 void *ptr = 0; 309 int addr = ur->addr; 310 usbd_status r; 311 int error = 0; 312 313 DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len)); 314 if (len < 0 || len > 32768) 315 return (EINVAL); 316 if (addr < 0 || addr >= USB_MAX_DEVICES || 317 sc->sc_bus->devices[addr] == 0) 318 return (EINVAL); 319 if (len != 0) { 320 iov.iov_base = (caddr_t)ur->data; 321 iov.iov_len = len; 322 uio.uio_iov = &iov; 323 uio.uio_iovcnt = 1; 324 uio.uio_resid = len; 325 uio.uio_offset = 0; 326 uio.uio_segflg = UIO_USERSPACE; 327 uio.uio_rw = 328 ur->request.bmRequestType & UT_READ ? 329 UIO_READ : UIO_WRITE; 330 uio.uio_procp = p; 331 ptr = malloc(len, M_TEMP, M_WAITOK); 332 if (uio.uio_rw == UIO_WRITE) { 333 error = uiomove(ptr, len, &uio); 334 if (error) 335 goto ret; 336 } 337 } 338 r = usbd_do_request_flags(sc->sc_bus->devices[addr], 339 &ur->request, ptr, 340 ur->flags, &ur->actlen); 341 if (r != USBD_NORMAL_COMPLETION) { 342 error = EIO; 343 goto ret; 344 } 345 if (len != 0) { 346 if (uio.uio_rw == UIO_READ) { 347 error = uiomove(ptr, len, &uio); 348 if (error) 349 goto ret; 350 } 351 } 352 ret: 353 if (ptr) 354 free(ptr, M_TEMP); 355 return (error); 356 } 357 358 case USB_DEVICEINFO: 359 { 360 struct usb_device_info *di = (void *)data; 361 int addr = di->addr; 362 usbd_device_handle dev; 363 364 if (addr < 1 || addr >= USB_MAX_DEVICES) 365 return (EINVAL); 366 dev = sc->sc_bus->devices[addr]; 367 if (dev == 0) 368 return (ENXIO); 369 usbd_fill_deviceinfo(dev, di); 370 break; 371 } 372 373 case USB_DEVICESTATS: 374 *(struct usb_device_stats *)data = sc->sc_bus->stats; 375 break; 376 377 default: 378 return (ENXIO); 379 } 380 return (0); 381 } 382 383 int 384 usbpoll(dev, events, p) 385 dev_t dev; 386 int events; 387 struct proc *p; 388 { 389 int revents, s; 390 USB_GET_SC(usb, USBUNIT(dev), sc); 391 392 if (sc->sc_dying) 393 return (EIO); 394 395 DPRINTFN(2, ("usbpoll: sc=%p events=0x%x\n", sc, events)); 396 s = splusb(); 397 revents = 0; 398 if (events & (POLLOUT | POLLWRNORM)) 399 if (sc->sc_bus->needs_explore) 400 revents |= events & (POLLOUT | POLLWRNORM); 401 DPRINTFN(2, ("usbpoll: revents=0x%x\n", revents)); 402 if (revents == 0) { 403 if (events & (POLLOUT | POLLWRNORM)) { 404 DPRINTFN(2, ("usbpoll: selrecord\n")); 405 selrecord(p, &sc->sc_consel); 406 } 407 } 408 splx(s); 409 return (revents); 410 } 411 412 /* Explore device tree from the root. */ 413 usbd_status 414 usb_discover(sc) 415 struct usb_softc *sc; 416 { 417 /* 418 * We need mutual exclusion while traversing the device tree, 419 * but this is guaranteed since this function is only called 420 * from the event thread for the controller. 421 */ 422 do { 423 sc->sc_bus->needs_explore = 0; 424 sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub); 425 } while (sc->sc_bus->needs_explore && !sc->sc_dying); 426 return (USBD_NORMAL_COMPLETION); 427 } 428 429 void 430 usb_needs_explore(bus) 431 usbd_bus_handle bus; 432 { 433 bus->needs_explore = 1; 434 selwakeup(&bus->usbctl->sc_consel); 435 wakeup(&bus->needs_explore); 436 } 437 438 int 439 usb_activate(self, act) 440 device_ptr_t self; 441 enum devact act; 442 { 443 struct usb_softc *sc = (struct usb_softc *)self; 444 usbd_device_handle dev = sc->sc_port.device; 445 int i, rv = 0; 446 447 switch (act) { 448 case DVACT_ACTIVATE: 449 return (EOPNOTSUPP); 450 break; 451 452 case DVACT_DEACTIVATE: 453 sc->sc_dying = 1; 454 if (dev && dev->cdesc && dev->subdevs) { 455 for (i = 0; dev->subdevs[i]; i++) 456 rv |= config_deactivate(dev->subdevs[i]); 457 } 458 break; 459 } 460 return (rv); 461 } 462 463 int 464 usb_detach(self, flags) 465 device_ptr_t self; 466 int flags; 467 { 468 struct usb_softc *sc = (struct usb_softc *)self; 469 470 sc->sc_dying = 1; 471 472 /* Make all devices disconnect. */ 473 if (sc->sc_port.device) 474 usb_disconnect_port(&sc->sc_port); 475 476 /* Kill off event thread. */ 477 if (sc->sc_event_thread) { 478 wakeup(&sc->sc_bus->needs_explore); 479 if (tsleep(sc, PWAIT, "usbdet", hz * 60)) 480 printf("%s: event thread didn't die\n", 481 USBDEVNAME(sc->sc_dev)); 482 } 483 484 usb_nbus--; 485 return (0); 486 } 487 488 int 489 usbread(dev, uio, flag) 490 dev_t dev; 491 struct uio *uio; 492 int flag; 493 { 494 /* XXX */ 495 return (0); 496 } 497 498 #if defined(__FreeBSD__) 499 DRIVER_MODULE(usb, root, usb_driver, usb_devclass, 0, 0); 500 #endif 501