1 /* $NetBSD: usb.c,v 1.4 1998/09/21 20:47:25 augustss Exp $ */ 2 3 /* 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Author: Lennart Augustsson <augustss@carlstedt.se> 8 * Carlstedt Research & Technology 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * USB spec: http://www.teleport.com/cgi-bin/mailmerge.cgi/~usb/cgiform.tpl 41 * More USB specs at http://www.usb.org/developers/index.shtml 42 */ 43 44 #include "opt_usbverbose.h" 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/kernel.h> 49 #include <sys/malloc.h> 50 #include <sys/device.h> 51 #include <sys/poll.h> 52 #include <sys/proc.h> 53 #include <sys/select.h> 54 55 #include <dev/usb/usb.h> 56 57 #include <dev/usb/usbdi.h> 58 #include <dev/usb/usbdivar.h> 59 #include <dev/usb/usb_quirks.h> 60 61 #ifdef USB_DEBUG 62 #define DPRINTF(x) if (usbdebug) printf x 63 #define DPRINTFN(n,x) if (usbdebug>(n)) printf x 64 int usbdebug = 0; 65 int uhcidebug; 66 int ohcidebug; 67 #else 68 #define DPRINTF(x) 69 #define DPRINTFN(n,x) 70 #endif 71 72 #define USBUNIT(dev) (minor(dev)) 73 74 struct usb_softc { 75 struct device sc_dev; /* base device */ 76 usbd_bus_handle sc_bus; /* USB controller */ 77 struct usbd_port sc_port; /* dummy port for root hub */ 78 char sc_running; 79 char sc_exploring; 80 struct selinfo sc_consel; /* waiting for connect change */ 81 }; 82 83 int usb_match __P((struct device *, struct cfdata *, void *)); 84 void usb_attach __P((struct device *, struct device *, void *)); 85 int usbopen __P((dev_t, int, int, struct proc *)); 86 int usbclose __P((dev_t, int, int, struct proc *)); 87 int usbioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); 88 int usbpoll __P((dev_t, int, struct proc *)); 89 90 usbd_status usb_discover __P((struct usb_softc *)); 91 92 extern struct cfdriver usb_cd; 93 94 struct cfattach usb_ca = { 95 sizeof(struct usb_softc), usb_match, usb_attach 96 }; 97 98 int 99 usb_match(parent, match, aux) 100 struct device *parent; 101 struct cfdata *match; 102 void *aux; 103 { 104 DPRINTF(("usbd_match\n")); 105 return (1); 106 } 107 108 void 109 usb_attach(parent, self, aux) 110 struct device *parent; 111 struct device *self; 112 void *aux; 113 { 114 struct usb_softc *sc = (struct usb_softc *)self; 115 usbd_device_handle dev; 116 usbd_status r; 117 118 printf("\n"); 119 120 DPRINTF(("usbd_attach\n")); 121 usbd_init(); 122 sc->sc_bus = aux; 123 sc->sc_bus->usbctl = sc; 124 sc->sc_running = 1; 125 sc->sc_bus->use_polling = 1; 126 sc->sc_port.power = USB_MAX_POWER; 127 r = usbd_new_device(&sc->sc_dev, sc->sc_bus, 0, 0, 0, &sc->sc_port); 128 if (r == USBD_NORMAL_COMPLETION) { 129 dev = sc->sc_port.device; 130 if (!dev->hub) { 131 sc->sc_running = 0; 132 printf("%s: root device is not a hub\n", 133 sc->sc_dev.dv_xname); 134 return; 135 } 136 sc->sc_bus->root_hub = dev; 137 dev->hub->explore(&sc->sc_dev, sc->sc_bus->root_hub); 138 } else { 139 printf("%s: root hub problem, error=%d\n", 140 sc->sc_dev.dv_xname, r); 141 sc->sc_running = 0; 142 } 143 sc->sc_bus->use_polling = 0; 144 } 145 146 int 147 usbctlprint(aux, pnp) 148 void *aux; 149 const char *pnp; 150 { 151 /* only "usb"es can attach to host controllers */ 152 if (pnp) 153 printf("usb at %s", pnp); 154 155 return (UNCONF); 156 } 157 158 int 159 usbopen(dev, flag, mode, p) 160 dev_t dev; 161 int flag, mode; 162 struct proc *p; 163 { 164 int unit = USBUNIT(dev); 165 struct usb_softc *sc; 166 167 if (unit >= usb_cd.cd_ndevs) 168 return (ENXIO); 169 sc = usb_cd.cd_devs[unit]; 170 if (sc == 0 || !sc->sc_running) 171 return (ENXIO); 172 173 return (0); 174 } 175 176 int 177 usbclose(dev, flag, mode, p) 178 dev_t dev; 179 int flag, mode; 180 struct proc *p; 181 { 182 return (0); 183 } 184 185 int 186 usbioctl(dev, cmd, data, flag, p) 187 dev_t dev; 188 u_long cmd; 189 caddr_t data; 190 int flag; 191 struct proc *p; 192 { 193 int unit = USBUNIT(dev); 194 struct usb_softc *sc = usb_cd.cd_devs[unit]; 195 196 if (sc == 0 || !sc->sc_running) 197 return (ENXIO); 198 switch (cmd) { 199 #ifdef USB_DEBUG 200 case USB_SETDEBUG: 201 usbdebug = uhcidebug = ohcidebug = *(int *)data; 202 break; 203 #endif 204 case USB_DISCOVER: 205 usb_discover(sc); 206 break; 207 case USB_REQUEST: 208 { 209 struct usb_ctl_request *ur = (void *)data; 210 int len = UGETW(ur->request.wLength); 211 struct iovec iov; 212 struct uio uio; 213 void *ptr = 0; 214 int addr = ur->addr; 215 usbd_status r; 216 int error = 0; 217 218 if (len < 0 || len > 32768) 219 return EINVAL; 220 if (addr < 0 || addr >= USB_MAX_DEVICES || 221 sc->sc_bus->devices[addr] == 0) 222 return EINVAL; 223 if (len != 0) { 224 iov.iov_base = (caddr_t)ur->data; 225 iov.iov_len = len; 226 uio.uio_iov = &iov; 227 uio.uio_iovcnt = 1; 228 uio.uio_resid = len; 229 uio.uio_offset = 0; 230 uio.uio_segflg = UIO_USERSPACE; 231 uio.uio_rw = 232 ur->request.bmRequestType & UT_READ ? 233 UIO_READ : UIO_WRITE; 234 uio.uio_procp = p; 235 ptr = malloc(len, M_TEMP, M_WAITOK); 236 if (uio.uio_rw == UIO_WRITE) { 237 error = uiomove(ptr, len, &uio); 238 if (error) 239 goto ret; 240 } 241 } 242 r = usbd_do_request(sc->sc_bus->devices[addr], 243 &ur->request, ptr); 244 if (r) { 245 error = EIO; 246 goto ret; 247 } 248 if (len != 0) { 249 if (uio.uio_rw == UIO_READ) { 250 error = uiomove(ptr, len, &uio); 251 if (error) 252 goto ret; 253 } 254 } 255 ret: 256 if (ptr) 257 free(ptr, M_TEMP); 258 return (error); 259 break; 260 } 261 262 case USB_DEVICEINFO: 263 { 264 struct usb_device_info *di = (void *)data; 265 int addr = di->addr; 266 usbd_device_handle dev; 267 struct usbd_port *p; 268 int i, r, s; 269 270 if (addr < 1 || addr >= USB_MAX_DEVICES) 271 return (EINVAL); 272 dev = sc->sc_bus->devices[addr]; 273 if (dev == 0) 274 return (ENXIO); 275 di->config = dev->config; 276 usbd_devinfo_vp(dev, di->product, di->vendor); 277 usbd_printBCD(di->revision, UGETW(dev->ddesc.bcdDevice)); 278 di->class = dev->ddesc.bDeviceClass; 279 di->power = dev->self_powered ? 0 : dev->power; 280 di->lowspeed = dev->lowspeed; 281 if (dev->hub) { 282 for (i = 0; 283 i < sizeof(di->ports) / sizeof(di->ports[0]) && 284 i < dev->hub->hubdesc.bNbrPorts; 285 i++) { 286 p = &dev->hub->ports[i]; 287 if (p->device) 288 r = p->device->address; 289 else { 290 s = UGETW(p->status.wPortStatus); 291 if (s & UPS_PORT_ENABLED) 292 r = USB_PORT_ENABLED; 293 else if (s & UPS_SUSPEND) 294 r = USB_PORT_SUSPENDED; 295 else if (s & UPS_PORT_POWER) 296 r = USB_PORT_POWERED; 297 else 298 r = USB_PORT_DISABLED; 299 } 300 di->ports[i] = r; 301 } 302 di->nports = dev->hub->hubdesc.bNbrPorts; 303 } else 304 di->nports = 0; 305 break; 306 } 307 308 case USB_DEVICESTATS: 309 *(struct usb_device_stats *)data = sc->sc_bus->stats; 310 break; 311 312 default: 313 return (ENXIO); 314 } 315 return (0); 316 } 317 318 int 319 usbpoll(dev, events, p) 320 dev_t dev; 321 int events; 322 struct proc *p; 323 { 324 int unit = USBUNIT(dev); 325 struct usb_softc *sc = usb_cd.cd_devs[unit]; 326 int revents, s; 327 328 DPRINTFN(2, ("usbpoll: sc=%p events=0x%x\n", sc, events)); 329 s = splusb(); 330 revents = 0; 331 if (events & (POLLOUT | POLLWRNORM)) 332 if (sc->sc_bus->needs_explore) 333 revents |= events & (POLLOUT | POLLWRNORM); 334 DPRINTFN(2, ("usbpoll: revents=0x%x\n", revents)); 335 if (revents == 0) { 336 if (events & (POLLOUT | POLLWRNORM)) { 337 DPRINTFN(2, ("usbpoll: selrecord\n")); 338 selrecord(p, &sc->sc_consel); 339 } 340 } 341 splx(s); 342 return (revents); 343 } 344 345 int 346 usb_bus_count() 347 { 348 int i, n; 349 350 for (i = n = 0; i < usb_cd.cd_ndevs; i++) 351 if (usb_cd.cd_devs[i]) 352 n++; 353 return (n); 354 } 355 356 usbd_status 357 usb_get_bus_handle(n, h) 358 int n; 359 usbd_bus_handle *h; 360 { 361 int i; 362 363 for (i = 0; i < usb_cd.cd_ndevs; i++) 364 if (usb_cd.cd_devs[i] && n-- == 0) { 365 *h = usb_cd.cd_devs[i]; 366 return (USBD_NORMAL_COMPLETION); 367 } 368 return (USBD_INVAL); 369 } 370 371 usbd_status 372 usb_discover(sc) 373 struct usb_softc *sc; 374 { 375 int s; 376 377 /* Explore device tree from the root */ 378 /* We need mutual exclusion while traversing the device tree. */ 379 s = splusb(); 380 while (sc->sc_exploring) 381 tsleep(&sc->sc_exploring, PRIBIO, "usbdis", 0); 382 sc->sc_exploring = 1; 383 sc->sc_bus->needs_explore = 0; 384 splx(s); 385 386 sc->sc_bus->root_hub->hub->explore(&sc->sc_dev, sc->sc_bus->root_hub); 387 388 s = splusb(); 389 sc->sc_exploring = 0; 390 wakeup(&sc->sc_exploring); 391 splx(s); 392 /* XXX should we start over if sc_needsexplore is set again? */ 393 return (0); 394 } 395 396 void 397 usb_needs_explore(bus) 398 usbd_bus_handle bus; 399 { 400 bus->needs_explore = 1; 401 selwakeup(&bus->usbctl->sc_consel); 402 } 403