Home | History | Annotate | Line # | Download | only in usb
usb.c revision 1.8
      1 /*	$NetBSD: usb.c,v 1.8 1998/12/28 02:20:28 augustss Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Lennart Augustsson (augustss (at) carlstedt.se) at
      9  * Carlstedt Research & Technology.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. All advertising materials mentioning features or use of this software
     20  *    must display the following acknowledgement:
     21  *        This product includes software developed by the NetBSD
     22  *        Foundation, Inc. and its contributors.
     23  * 4. Neither the name of The NetBSD Foundation nor the names of its
     24  *    contributors may be used to endorse or promote products derived
     25  *    from this software without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37  * POSSIBILITY OF SUCH DAMAGE.
     38  */
     39 
     40 /*
     41  * USB specifications and other documentation can be found at
     42  * http://www.usb.org/developers/data/ and
     43  * http://www.usb.org/developers/index.html .
     44  */
     45 
     46 #include <sys/param.h>
     47 #include <sys/systm.h>
     48 #include <sys/kernel.h>
     49 #include <sys/malloc.h>
     50 #if defined(__NetBSD__)
     51 #include <sys/device.h>
     52 #elif defined(__FreeBSD__)
     53 #include <sys/module.h>
     54 #include <sys/bus.h>
     55 #include <sys/ioccom.h>
     56 #include <sys/uio.h>
     57 #include <sys/conf.h>
     58 #endif
     59 #include <sys/poll.h>
     60 #include <sys/proc.h>
     61 #include <sys/select.h>
     62 
     63 #include <dev/usb/usb.h>
     64 
     65 #if defined(__FreeBSD__)
     66 MALLOC_DEFINE(M_USB, "USB", "USB");
     67 MALLOC_DEFINE(M_USBDEV, "USBdev", "USB device");
     68 
     69 #include "usb_if.h"
     70 #endif /* defined(__FreeBSD__) */
     71 
     72 #include <dev/usb/usbdi.h>
     73 #include <dev/usb/usbdivar.h>
     74 #include <dev/usb/usb_quirks.h>
     75 
     76 #ifdef USB_DEBUG
     77 #define DPRINTF(x)	if (usbdebug) printf x
     78 #define DPRINTFN(n,x)	if (usbdebug>(n)) printf x
     79 int	usbdebug = 0;
     80 int	uhcidebug;
     81 int	ohcidebug;
     82 #else
     83 #define DPRINTF(x)
     84 #define DPRINTFN(n,x)
     85 #endif
     86 
     87 #define USBUNIT(dev) (minor(dev))
     88 
     89 struct usb_softc {
     90 	bdevice sc_dev;			/* base device */
     91 	usbd_bus_handle sc_bus;		/* USB controller */
     92 	struct usbd_port sc_port;	/* dummy port for root hub */
     93 	char sc_running;
     94 	char sc_exploring;
     95 	struct selinfo sc_consel;	/* waiting for connect change */
     96 };
     97 
     98 #if defined(__NetBSD__)
     99 int usbopen __P((dev_t, int, int, struct proc *));
    100 int usbclose __P((dev_t, int, int, struct proc *));
    101 int usbioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
    102 int usbpoll __P((dev_t, int, struct proc *));
    103 
    104 #elif defined(__FreeBSD__)
    105 static device_probe_t usb_match;
    106 static device_attach_t usb_attach;
    107 static bus_print_child_t usb_print_child;
    108 
    109 d_open_t  usbopen;
    110 d_close_t usbclose;
    111 d_ioctl_t usbioctl;
    112 int usbpoll __P((dev_t, int, struct proc *));
    113 
    114 struct cdevsw usb_cdevsw = {
    115 	usbopen,     usbclose,    noread,         nowrite,
    116 	usbioctl,    nullstop,    nullreset,      nodevtotty,
    117 	usbpoll,     nommap,      nostrat,
    118 	"usb",        NULL,   -1
    119 };
    120 #endif
    121 
    122 usbd_status usb_discover __P((struct usb_softc *));
    123 
    124 USB_DECLARE_DRIVER_INIT(usb, DEVMETHOD(bus_print_child, usb_print_child));
    125 
    126 USB_MATCH(usb)
    127 {
    128 	DPRINTF(("usbd_match\n"));
    129 	return (UMATCH_GENERIC);
    130 }
    131 
    132 USB_ATTACH(usb)
    133 {
    134 #if defined(__NetBSD__)
    135 	struct usb_softc *sc = (struct usb_softc *)self;
    136 #elif defined(__FreeBSD__)
    137 	struct usb_softc *sc = device_get_softc(device);
    138 	void *aux = device_get_ivars(device);
    139 #endif
    140 	usbd_device_handle dev;
    141 	usbd_status r;
    142 
    143 #if defined(__NetBSD__)
    144 	printf("\n");
    145 #elif defined(__FreeBSD__)
    146 	sc->sc_dev = device;
    147 #endif
    148 
    149 	DPRINTF(("usbd_attach\n"));
    150 	usbd_init();
    151 	sc->sc_bus = aux;
    152 	sc->sc_bus->usbctl = sc;
    153 	sc->sc_running = 1;
    154 	sc->sc_bus->use_polling = 1;
    155 	sc->sc_port.power = USB_MAX_POWER;
    156 	r = usbd_new_device(&sc->sc_dev, sc->sc_bus, 0, 0, 0, &sc->sc_port);
    157 
    158 	if (r == USBD_NORMAL_COMPLETION) {
    159 		dev = sc->sc_port.device;
    160 		if (!dev->hub) {
    161 			sc->sc_running = 0;
    162 			printf("%s: root device is not a hub\n",
    163 			       USBDEVNAME(sc->sc_dev));
    164 			USB_ATTACH_ERROR_RETURN;
    165 		}
    166 		sc->sc_bus->root_hub = dev;
    167 		dev->hub->explore(sc->sc_bus->root_hub);
    168 	} else {
    169 		printf("%s: root hub problem, error=%d\n",
    170 		       USBDEVNAME(sc->sc_dev), r);
    171 		sc->sc_running = 0;
    172 	}
    173 	sc->sc_bus->use_polling = 0;
    174 
    175 	USB_ATTACH_SUCCESS_RETURN;
    176 }
    177 
    178 #if defined(__NetBSD__)
    179 int
    180 usbctlprint(aux, pnp)
    181 	void *aux;
    182 	const char *pnp;
    183 {
    184 	/* only "usb"es can attach to host controllers */
    185 	if (pnp)
    186 		printf("usb at %s", pnp);
    187 
    188 	return (UNCONF);
    189 }
    190 
    191 #elif defined(__FreeBSD__)
    192 static void
    193 usb_print_child(device_t parent, device_t child)
    194 {
    195 	struct usb_softc *sc = device_get_softc(child);
    196 
    197 	printf(" at %s%d", device_get_name(parent), device_get_unit(parent));
    198 
    199 	/* How do we get to the usbd_device_handle???
    200 	usbd_device_handle dev = invalidadosch;
    201 
    202 	printf(" addr %d", dev->addr);
    203 
    204 	if (bootverbose) {
    205 		if (dev->lowspeed)
    206 			printf(", lowspeed");
    207 		if (dev->self_powered)
    208 			printf(", self powered");
    209 		else
    210 			printf(", %dmA", dev->power);
    211 		printf(", config %d", dev->config);
    212 	}
    213 	 */
    214 }
    215 
    216 /* Reconfigure all the USB busses in the system. */
    217 int
    218 usb_driver_load(module_t mod, int what, void *arg)
    219 {
    220 	/* subroutine is there but inactive at the moment
    221 	 * the reconfiguration process has not been thought through yet.
    222 	 */
    223 	devclass_t ugen_devclass = devclass_find("ugen");
    224 	device_t *devlist;
    225 	int devcount;
    226 	int error;
    227 
    228 	switch (what) {
    229 	case MOD_LOAD:
    230 	case MOD_UNLOAD:
    231 		if (!usb_devclass)
    232 			return 0;	/* just ignore call */
    233 
    234 		if (ugen_devclass) {
    235 			/* detach devices from generic driver if possible
    236 			 */
    237 			error = devclass_get_devices(ugen_devclass, &devlist,
    238 						     &devcount);
    239 			if (!error)
    240 				for (devcount--; devcount >= 0; devcount--)
    241 					(void)DEVICE_DETACH(devlist[devcount]);
    242 		}
    243 
    244 		error = devclass_get_devices(usb_devclass, &devlist, &devcount);
    245 		if (error)
    246 			return 0;	/* XXX maybe transient, or error? */
    247 
    248 		for (devcount--; devcount >= 0; devcount--)
    249 			USB_RECONFIGURE(devlist[devcount]);
    250 
    251 		free(devlist, M_TEMP);
    252 		return 0;
    253 	}
    254 
    255 	return 0;			/* nothing to do by us */
    256 }
    257 
    258 /* Set the description of the device including a malloc and copy. */
    259 void
    260 usb_device_set_desc(device_t device, char *devinfo)
    261 {
    262 	size_t l;
    263 	char *desc;
    264 
    265 	if ( devinfo ) {
    266 		l = strlen(devinfo);
    267 		desc = malloc(l+1, M_USB, M_NOWAIT);
    268 		if (desc)
    269 			memcpy(desc, devinfo, l+1);
    270 	} else
    271 		desc = NULL;
    272 
    273 	device_set_desc(device, desc);
    274 }
    275 
    276 /*
    277  * A static buffer is a loss if this routine is used from an interrupt,
    278  * but it's not fatal.
    279  */
    280 char *
    281 usb_devname(struct device *bdev)
    282 {
    283 	static char buf[20];
    284 
    285 	sprintf(buf, "%s%d", device_get_name(*bdev), device_get_unit(*bdev));
    286 	return (buf);
    287 }
    288 
    289 #endif
    290 
    291 int
    292 usbopen(dev, flag, mode, p)
    293 	dev_t dev;
    294 	int flag, mode;
    295 	struct proc *p;
    296 {
    297 	USB_GET_SC_OPEN(usb, USBUNIT(dev), sc);
    298 
    299 	if (sc == 0 || !sc->sc_running)
    300 		return (ENXIO);
    301 
    302 	return (0);
    303 }
    304 
    305 int
    306 usbclose(dev, flag, mode, p)
    307 	dev_t dev;
    308 	int flag, mode;
    309 	struct proc *p;
    310 {
    311 	return (0);
    312 }
    313 
    314 int
    315 usbioctl(dev, cmd, data, flag, p)
    316 	dev_t dev;
    317 	u_long cmd;
    318 	caddr_t data;
    319 	int flag;
    320 	struct proc *p;
    321 {
    322 	USB_GET_SC(usb, USBUNIT(dev), sc);
    323 
    324 	if (sc == 0 || !sc->sc_running)
    325 		return (ENXIO);
    326 	switch (cmd) {
    327 #ifdef USB_DEBUG
    328 	case USB_SETDEBUG:
    329 		usbdebug = uhcidebug = ohcidebug = *(int *)data;
    330 		break;
    331 #endif
    332 	case USB_DISCOVER:
    333 		usb_discover(sc);
    334 		break;
    335 	case USB_REQUEST:
    336 	{
    337 		struct usb_ctl_request *ur = (void *)data;
    338 		int len = UGETW(ur->request.wLength);
    339 		struct iovec iov;
    340 		struct uio uio;
    341 		void *ptr = 0;
    342 		int addr = ur->addr;
    343 		usbd_status r;
    344 		int error = 0;
    345 
    346 		if (len < 0 || len > 32768)
    347 			return EINVAL;
    348 		if (addr < 0 || addr >= USB_MAX_DEVICES ||
    349 		    sc->sc_bus->devices[addr] == 0)
    350 			return EINVAL;
    351 		if (len != 0) {
    352 			iov.iov_base = (caddr_t)ur->data;
    353 			iov.iov_len = len;
    354 			uio.uio_iov = &iov;
    355 			uio.uio_iovcnt = 1;
    356 			uio.uio_resid = len;
    357 			uio.uio_offset = 0;
    358 			uio.uio_segflg = UIO_USERSPACE;
    359 			uio.uio_rw =
    360 				ur->request.bmRequestType & UT_READ ?
    361 				UIO_READ : UIO_WRITE;
    362 			uio.uio_procp = p;
    363 			ptr = malloc(len, M_TEMP, M_WAITOK);
    364 			if (uio.uio_rw == UIO_WRITE) {
    365 				error = uiomove(ptr, len, &uio);
    366 				if (error)
    367 					goto ret;
    368 			}
    369 		}
    370 		r = usbd_do_request(sc->sc_bus->devices[addr],
    371 				    &ur->request, ptr);
    372 		if (r) {
    373 			error = EIO;
    374 			goto ret;
    375 		}
    376 		if (len != 0) {
    377 			if (uio.uio_rw == UIO_READ) {
    378 				error = uiomove(ptr, len, &uio);
    379 				if (error)
    380 					goto ret;
    381 			}
    382 		}
    383 	ret:
    384 		if (ptr)
    385 			free(ptr, M_TEMP);
    386 		return (error);
    387 	}
    388 
    389 	case USB_DEVICEINFO:
    390 	{
    391 		struct usb_device_info *di = (void *)data;
    392 		int addr = di->addr;
    393 		usbd_device_handle dev;
    394 
    395 		if (addr < 1 || addr >= USB_MAX_DEVICES)
    396 			return (EINVAL);
    397 		dev = sc->sc_bus->devices[addr];
    398 		if (dev == 0)
    399 			return (ENXIO);
    400 		usbd_fill_deviceinfo(dev, di);
    401 		break;
    402 	}
    403 
    404 	case USB_DEVICESTATS:
    405 		*(struct usb_device_stats *)data = sc->sc_bus->stats;
    406 		break;
    407 
    408 	default:
    409 		return (ENXIO);
    410 	}
    411 	return (0);
    412 }
    413 
    414 int
    415 usbpoll(dev, events, p)
    416 	dev_t dev;
    417 	int events;
    418 	struct proc *p;
    419 {
    420 	int revents, s;
    421 	USB_GET_SC(usb, USBUNIT(dev), sc);
    422 
    423 	DPRINTFN(2, ("usbpoll: sc=%p events=0x%x\n", sc, events));
    424 	s = splusb();
    425 	revents = 0;
    426 	if (events & (POLLOUT | POLLWRNORM))
    427 		if (sc->sc_bus->needs_explore)
    428 			revents |= events & (POLLOUT | POLLWRNORM);
    429 	DPRINTFN(2, ("usbpoll: revents=0x%x\n", revents));
    430 	if (revents == 0) {
    431 		if (events & (POLLOUT | POLLWRNORM)) {
    432 			DPRINTFN(2, ("usbpoll: selrecord\n"));
    433 			selrecord(p, &sc->sc_consel);
    434 		}
    435 	}
    436 	splx(s);
    437 	return (revents);
    438 }
    439 
    440 int
    441 usb_bus_count()
    442 {
    443 	int i, n;
    444 
    445 	for (i = n = 0; i < usb_cd.cd_ndevs; i++)
    446 		if (usb_cd.cd_devs[i])
    447 			n++;
    448 	return (n);
    449 }
    450 
    451 usbd_status
    452 usb_get_bus_handle(n, h)
    453 	int n;
    454 	usbd_bus_handle *h;
    455 {
    456 	int i;
    457 
    458 	for (i = 0; i < usb_cd.cd_ndevs; i++)
    459 		if (usb_cd.cd_devs[i] && n-- == 0) {
    460 			*h = usb_cd.cd_devs[i];
    461 			return (USBD_NORMAL_COMPLETION);
    462 		}
    463 	return (USBD_INVAL);
    464 }
    465 
    466 usbd_status
    467 usb_discover(sc)
    468 	struct usb_softc *sc;
    469 {
    470 	int s;
    471 
    472 	/* Explore device tree from the root */
    473 	/* We need mutual exclusion while traversing the device tree. */
    474 	s = splusb();
    475 	while (sc->sc_exploring)
    476 		tsleep(&sc->sc_exploring, PRIBIO, "usbdis", 0);
    477 	sc->sc_exploring = 1;
    478 	sc->sc_bus->needs_explore = 0;
    479 	splx(s);
    480 
    481 	sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub);
    482 
    483 	s = splusb();
    484 	sc->sc_exploring = 0;
    485 	wakeup(&sc->sc_exploring);
    486 	splx(s);
    487 	/* XXX should we start over if sc_needsexplore is set again? */
    488 	return (0);
    489 }
    490 
    491 void
    492 usb_needs_explore(bus)
    493 	usbd_bus_handle bus;
    494 {
    495 	bus->needs_explore = 1;
    496 	selwakeup(&bus->usbctl->sc_consel);
    497 }
    498 
    499 #if defined(__FreeBSD__)
    500 int
    501 usb_detach(device_t self)
    502 {
    503 	struct usb_softc *sc = device_get_softc(self);
    504 	char *devinfo = (char *) device_get_desc(self);
    505 
    506 	if (devinfo) {
    507 		device_set_desc(self, NULL);
    508 		free(devinfo, M_USB);
    509 	}
    510 
    511 	return (0);
    512 }
    513 
    514 DRIVER_MODULE(usb, root, usb_driver, usb_devclass, 0, 0);
    515 #endif
    516