1 /* $OpenBSD: usb.c,v 1.4 1999/08/31 07:42:50 fgsch Exp $ */ 2 /* $NetBSD: usb.c,v 1.17 1999/08/17 16:06:21 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/poll.h> 62 #include <sys/proc.h> 63 #include <sys/select.h> 64 65 #include <dev/usb/usb.h> 66 #include <dev/usb/usbdi.h> 67 #include <dev/usb/usbdi_util.h> 68 69 #if defined(__FreeBSD__) 70 MALLOC_DEFINE(M_USB, "USB", "USB"); 71 MALLOC_DEFINE(M_USBDEV, "USBdev", "USB device"); 72 MALLOC_DEFINE(M_USBHC, "USBHC", "USB host controller"); 73 74 #include "usb_if.h" 75 #endif /* defined(__FreeBSD__) */ 76 77 #include <dev/usb/usbdivar.h> 78 #include <dev/usb/usb_quirks.h> 79 80 #ifdef USB_DEBUG 81 #define DPRINTF(x) if (usbdebug) logprintf x 82 #define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x 83 int usbdebug = 0; 84 int uhcidebug; 85 int ohcidebug; 86 #else 87 #define DPRINTF(x) 88 #define DPRINTFN(n,x) 89 #endif 90 91 #define USBUNIT(dev) (minor(dev)) 92 93 struct usb_softc { 94 bdevice sc_dev; /* base device */ 95 usbd_bus_handle sc_bus; /* USB controller */ 96 struct usbd_port sc_port; /* dummy port for root hub */ 97 char sc_running; 98 char sc_exploring; 99 struct selinfo sc_consel; /* waiting for connect change */ 100 int shutdown; 101 struct proc *event_thread; 102 }; 103 104 #if defined(__NetBSD__) || defined(__OpenBSD__) 105 int usbopen __P((dev_t, int, int, struct proc *)); 106 int usbclose __P((dev_t, int, int, struct proc *)); 107 int usbioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); 108 int usbpoll __P((dev_t, int, struct proc *)); 109 110 #elif defined(__FreeBSD__) 111 d_open_t usbopen; 112 d_close_t usbclose; 113 d_ioctl_t usbioctl; 114 int usbpoll __P((dev_t, int, struct proc *)); 115 116 struct cdevsw usb_cdevsw = { 117 usbopen, usbclose, noread, nowrite, 118 usbioctl, nullstop, nullreset, nodevtotty, 119 usbpoll, nommap, nostrat, 120 "usb", NULL, -1 121 }; 122 #endif 123 124 usbd_status usb_discover __P((struct usb_softc *)); 125 void usb_create_event_thread __P((void *)); 126 void usb_event_thread __P((void *)); 127 128 USB_DECLARE_DRIVER_INIT(usb, DEVMETHOD(bus_print_child, usbd_print_child)); 129 130 USB_MATCH(usb) 131 { 132 DPRINTF(("usbd_match\n")); 133 return (UMATCH_GENERIC); 134 } 135 136 USB_ATTACH(usb) 137 { 138 #if defined(__NetBSD__) || defined(__OpenBSD__) 139 struct usb_softc *sc = (struct usb_softc *)self; 140 #elif defined(__FreeBSD__) 141 struct usb_softc *sc = device_get_softc(self); 142 void *aux = device_get_ivars(self); 143 #endif 144 usbd_device_handle dev; 145 usbd_status r; 146 147 #if defined(__NetBSD__) || defined(__OpenBSD__) 148 printf("\n"); 149 #elif defined(__FreeBSD__) 150 sc->sc_dev = self; 151 #endif 152 153 DPRINTF(("usbd_attach\n")); 154 usbd_init(); 155 sc->sc_bus = aux; 156 sc->sc_bus->usbctl = sc; 157 sc->sc_running = 1; 158 sc->sc_bus->use_polling = 1; 159 sc->sc_port.power = USB_MAX_POWER; 160 r = usbd_new_device(&sc->sc_dev, sc->sc_bus, 0,0,0, &sc->sc_port); 161 162 if (r == USBD_NORMAL_COMPLETION) { 163 dev = sc->sc_port.device; 164 if (!dev->hub) { 165 sc->sc_running = 0; 166 printf("%s: root device is not a hub\n", 167 USBDEVNAME(sc->sc_dev)); 168 USB_ATTACH_ERROR_RETURN; 169 } 170 sc->sc_bus->root_hub = dev; 171 dev->hub->explore(sc->sc_bus->root_hub); 172 } else { 173 printf("%s: root hub problem, error=%d\n", 174 USBDEVNAME(sc->sc_dev), r); 175 sc->sc_running = 0; 176 } 177 sc->sc_bus->use_polling = 0; 178 179 #if defined(__OpenBSD__) 180 kthread_create_deferred(usb_create_event_thread, sc); 181 #else 182 kthread_create(usb_create_event_thread, sc); 183 #endif 184 185 USB_ATTACH_SUCCESS_RETURN; 186 } 187 188 void 189 usb_create_event_thread(arg) 190 void *arg; 191 { 192 struct usb_softc *sc = arg; 193 194 #if !defined(__OpenBSD__) 195 if (kthread_create1(usb_event_thread, sc, &sc->event_thread, 196 #else 197 if (kthread_create(usb_event_thread, sc, &sc->event_thread, 198 #endif 199 "%s", sc->sc_dev.dv_xname)) { 200 printf("%s: unable to create event thread for\n", 201 sc->sc_dev.dv_xname); 202 panic("usb_create_event_thread"); 203 } 204 } 205 206 void 207 usb_event_thread(arg) 208 void *arg; 209 { 210 struct usb_softc *sc = arg; 211 212 while (!sc->shutdown) { 213 (void)tsleep(&sc->sc_bus->needs_explore, 214 PWAIT, "usbevt", hz*30); 215 DPRINTFN(2,("usb_event_thread: woke up\n")); 216 usb_discover(sc); 217 } 218 sc->event_thread = 0; 219 220 /* In case parent is waiting for us to exit. */ 221 wakeup(sc); 222 223 kthread_exit(0); 224 } 225 226 #if defined(__NetBSD__) || defined(__OpenBSD__) 227 int 228 usbctlprint(aux, pnp) 229 void *aux; 230 const char *pnp; 231 { 232 /* only "usb"es can attach to host controllers */ 233 if (pnp) 234 printf("usb at %s", pnp); 235 236 return (UNCONF); 237 } 238 #endif 239 240 int 241 usbopen(dev, flag, mode, p) 242 dev_t dev; 243 int flag, mode; 244 struct proc *p; 245 { 246 USB_GET_SC_OPEN(usb, USBUNIT(dev), sc); 247 248 if (sc == 0 || !sc->sc_running) 249 return (ENXIO); 250 251 return (0); 252 } 253 254 int 255 usbclose(dev, flag, mode, p) 256 dev_t dev; 257 int flag, mode; 258 struct proc *p; 259 { 260 return (0); 261 } 262 263 int 264 usbioctl(dev, cmd, data, flag, p) 265 dev_t dev; 266 u_long cmd; 267 caddr_t data; 268 int flag; 269 struct proc *p; 270 { 271 USB_GET_SC(usb, USBUNIT(dev), sc); 272 273 if (sc == 0 || !sc->sc_running) 274 return (ENXIO); 275 switch (cmd) { 276 #ifdef USB_DEBUG 277 case USB_SETDEBUG: 278 usbdebug = uhcidebug = ohcidebug = *(int *)data; 279 break; 280 #endif 281 #if 0 282 case USB_DISCOVER: 283 usb_discover(sc); 284 break; 285 #endif 286 case USB_REQUEST: 287 { 288 struct usb_ctl_request *ur = (void *)data; 289 int len = UGETW(ur->request.wLength); 290 struct iovec iov; 291 struct uio uio; 292 void *ptr = 0; 293 int addr = ur->addr; 294 usbd_status r; 295 int error = 0; 296 297 DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len)); 298 if (len < 0 || len > 32768) 299 return (EINVAL); 300 if (addr < 0 || addr >= USB_MAX_DEVICES || 301 sc->sc_bus->devices[addr] == 0) 302 return (EINVAL); 303 if (len != 0) { 304 iov.iov_base = (caddr_t)ur->data; 305 iov.iov_len = len; 306 uio.uio_iov = &iov; 307 uio.uio_iovcnt = 1; 308 uio.uio_resid = len; 309 uio.uio_offset = 0; 310 uio.uio_segflg = UIO_USERSPACE; 311 uio.uio_rw = 312 ur->request.bmRequestType & UT_READ ? 313 UIO_READ : UIO_WRITE; 314 uio.uio_procp = p; 315 ptr = malloc(len, M_TEMP, M_WAITOK); 316 if (uio.uio_rw == UIO_WRITE) { 317 error = uiomove(ptr, len, &uio); 318 if (error) 319 goto ret; 320 } 321 } 322 r = usbd_do_request_flags(sc->sc_bus->devices[addr], 323 &ur->request, ptr, 324 ur->flags, &ur->actlen); 325 if (r != USBD_NORMAL_COMPLETION) { 326 error = EIO; 327 goto ret; 328 } 329 if (len != 0) { 330 if (uio.uio_rw == UIO_READ) { 331 error = uiomove(ptr, len, &uio); 332 if (error) 333 goto ret; 334 } 335 } 336 ret: 337 if (ptr) 338 free(ptr, M_TEMP); 339 return (error); 340 } 341 342 case USB_DEVICEINFO: 343 { 344 struct usb_device_info *di = (void *)data; 345 int addr = di->addr; 346 usbd_device_handle dev; 347 348 if (addr < 1 || addr >= USB_MAX_DEVICES) 349 return (EINVAL); 350 dev = sc->sc_bus->devices[addr]; 351 if (dev == 0) 352 return (ENXIO); 353 usbd_fill_deviceinfo(dev, di); 354 break; 355 } 356 357 case USB_DEVICESTATS: 358 *(struct usb_device_stats *)data = sc->sc_bus->stats; 359 break; 360 361 default: 362 return (ENXIO); 363 } 364 return (0); 365 } 366 367 int 368 usbpoll(dev, events, p) 369 dev_t dev; 370 int events; 371 struct proc *p; 372 { 373 int revents, s; 374 USB_GET_SC(usb, USBUNIT(dev), sc); 375 376 DPRINTFN(2, ("usbpoll: sc=%p events=0x%x\n", sc, events)); 377 s = splusb(); 378 revents = 0; 379 if (events & (POLLOUT | POLLWRNORM)) 380 if (sc->sc_bus->needs_explore) 381 revents |= events & (POLLOUT | POLLWRNORM); 382 DPRINTFN(2, ("usbpoll: revents=0x%x\n", revents)); 383 if (revents == 0) { 384 if (events & (POLLOUT | POLLWRNORM)) { 385 DPRINTFN(2, ("usbpoll: selrecord\n")); 386 selrecord(p, &sc->sc_consel); 387 } 388 } 389 splx(s); 390 return (revents); 391 } 392 393 #if 0 394 int 395 usb_bus_count() 396 { 397 int i, n; 398 399 for (i = n = 0; i < usb_cd.cd_ndevs; i++) 400 if (usb_cd.cd_devs[i]) 401 n++; 402 return (n); 403 } 404 #endif 405 406 #if 0 407 usbd_status 408 usb_get_bus_handle(n, h) 409 int n; 410 usbd_bus_handle *h; 411 { 412 int i; 413 414 for (i = 0; i < usb_cd.cd_ndevs; i++) 415 if (usb_cd.cd_devs[i] && n-- == 0) { 416 *h = usb_cd.cd_devs[i]; 417 return (USBD_NORMAL_COMPLETION); 418 } 419 return (USBD_INVAL); 420 } 421 #endif 422 423 usbd_status 424 usb_discover(sc) 425 struct usb_softc *sc; 426 { 427 int s; 428 429 /* Explore device tree from the root */ 430 /* We need mutual exclusion while traversing the device tree. */ 431 do { 432 s = splusb(); 433 while (sc->sc_exploring) 434 tsleep(&sc->sc_exploring, PRIBIO, "usbdis", 0); 435 sc->sc_exploring = 1; 436 sc->sc_bus->needs_explore = 0; 437 splx(s); 438 439 sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub); 440 441 s = splusb(); 442 sc->sc_exploring = 0; 443 wakeup(&sc->sc_exploring); 444 splx(s); 445 } while (sc->sc_bus->needs_explore); 446 return (USBD_NORMAL_COMPLETION); 447 } 448 449 void 450 usb_needs_explore(bus) 451 usbd_bus_handle bus; 452 { 453 bus->needs_explore = 1; 454 selwakeup(&bus->usbctl->sc_consel); 455 wakeup(&bus->needs_explore); 456 } 457 458 int 459 usb_activate(self, act) 460 bdevice *self; 461 enum devact act; 462 { 463 panic("usb_activate\n"); 464 return (0); 465 } 466 467 int 468 usb_detach(self, flags) 469 bdevice *self; 470 int flags; 471 { 472 panic("usb_detach\n"); 473 return (0); 474 } 475 476 #if defined(__FreeBSD__) 477 DRIVER_MODULE(usb, root, usb_driver, usb_devclass, 0, 0); 478 #endif 479