Home | History | Annotate | Line # | Download | only in usb
usb.c revision 1.11
      1 /*	$NetBSD: usb.c,v 1.11 1999/01/08 11:58:25 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 d_open_t  usbopen;
    106 d_close_t usbclose;
    107 d_ioctl_t usbioctl;
    108 int usbpoll __P((dev_t, int, struct proc *));
    109 
    110 struct cdevsw usb_cdevsw = {
    111 	usbopen,     usbclose,    noread,         nowrite,
    112 	usbioctl,    nullstop,    nullreset,      nodevtotty,
    113 	usbpoll,     nommap,      nostrat,
    114 	"usb",        NULL,   -1
    115 };
    116 #endif
    117 
    118 usbd_status usb_discover __P((struct usb_softc *));
    119 
    120 USB_DECLARE_DRIVER_INIT(usb, DEVMETHOD(bus_print_child, usbd_print_child));
    121 
    122 USB_MATCH(usb)
    123 {
    124 	DPRINTF(("usbd_match\n"));
    125 	return (UMATCH_GENERIC);
    126 }
    127 
    128 USB_ATTACH(usb)
    129 {
    130 #if defined(__NetBSD__)
    131 	struct usb_softc *sc = (struct usb_softc *)self;
    132 #elif defined(__FreeBSD__)
    133 	struct usb_softc *sc = device_get_softc(self);
    134 	void *aux = device_get_ivars(self);
    135 #endif
    136 	usbd_device_handle dev;
    137 	usbd_status r;
    138 
    139 #if defined(__NetBSD__)
    140 	printf("\n");
    141 #elif defined(__FreeBSD__)
    142 	sc->sc_dev = self;
    143 #endif
    144 
    145 	DPRINTF(("usbd_attach\n"));
    146 	usbd_init();
    147 	sc->sc_bus = aux;
    148 	sc->sc_bus->usbctl = sc;
    149 	sc->sc_running = 1;
    150 	sc->sc_bus->use_polling = 1;
    151 	sc->sc_port.power = USB_MAX_POWER;
    152 	r = usbd_new_device(&sc->sc_dev, sc->sc_bus, 0, 0, 0, &sc->sc_port);
    153 
    154 	if (r == USBD_NORMAL_COMPLETION) {
    155 		dev = sc->sc_port.device;
    156 		if (!dev->hub) {
    157 			sc->sc_running = 0;
    158 			printf("%s: root device is not a hub\n",
    159 			       USBDEVNAME(sc->sc_dev));
    160 			USB_ATTACH_ERROR_RETURN;
    161 		}
    162 		sc->sc_bus->root_hub = dev;
    163 		dev->hub->explore(sc->sc_bus->root_hub);
    164 	} else {
    165 		printf("%s: root hub problem, error=%d\n",
    166 		       USBDEVNAME(sc->sc_dev), r);
    167 		sc->sc_running = 0;
    168 	}
    169 	sc->sc_bus->use_polling = 0;
    170 
    171 	USB_ATTACH_SUCCESS_RETURN;
    172 }
    173 
    174 #if defined(__NetBSD__)
    175 int
    176 usbctlprint(aux, pnp)
    177 	void *aux;
    178 	const char *pnp;
    179 {
    180 	/* only "usb"es can attach to host controllers */
    181 	if (pnp)
    182 		printf("usb at %s", pnp);
    183 
    184 	return (UNCONF);
    185 }
    186 #endif
    187 
    188 int
    189 usbopen(dev, flag, mode, p)
    190 	dev_t dev;
    191 	int flag, mode;
    192 	struct proc *p;
    193 {
    194 	USB_GET_SC_OPEN(usb, USBUNIT(dev), sc);
    195 
    196 	if (sc == 0 || !sc->sc_running)
    197 		return (ENXIO);
    198 
    199 	return (0);
    200 }
    201 
    202 int
    203 usbclose(dev, flag, mode, p)
    204 	dev_t dev;
    205 	int flag, mode;
    206 	struct proc *p;
    207 {
    208 	return (0);
    209 }
    210 
    211 int
    212 usbioctl(dev, cmd, data, flag, p)
    213 	dev_t dev;
    214 	u_long cmd;
    215 	caddr_t data;
    216 	int flag;
    217 	struct proc *p;
    218 {
    219 	USB_GET_SC(usb, USBUNIT(dev), sc);
    220 
    221 	if (sc == 0 || !sc->sc_running)
    222 		return (ENXIO);
    223 	switch (cmd) {
    224 #ifdef USB_DEBUG
    225 	case USB_SETDEBUG:
    226 		usbdebug = uhcidebug = ohcidebug = *(int *)data;
    227 		break;
    228 #endif
    229 	case USB_DISCOVER:
    230 		usb_discover(sc);
    231 		break;
    232 	case USB_REQUEST:
    233 	{
    234 		struct usb_ctl_request *ur = (void *)data;
    235 		int len = UGETW(ur->request.wLength);
    236 		struct iovec iov;
    237 		struct uio uio;
    238 		void *ptr = 0;
    239 		int addr = ur->addr;
    240 		usbd_status r;
    241 		int error = 0;
    242 
    243 		DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len));
    244 		if (len < 0 || len > 32768)
    245 			return (EINVAL);
    246 		if (addr < 0 || addr >= USB_MAX_DEVICES ||
    247 		    sc->sc_bus->devices[addr] == 0)
    248 			return (EINVAL);
    249 		if (len != 0) {
    250 			iov.iov_base = (caddr_t)ur->data;
    251 			iov.iov_len = len;
    252 			uio.uio_iov = &iov;
    253 			uio.uio_iovcnt = 1;
    254 			uio.uio_resid = len;
    255 			uio.uio_offset = 0;
    256 			uio.uio_segflg = UIO_USERSPACE;
    257 			uio.uio_rw =
    258 				ur->request.bmRequestType & UT_READ ?
    259 				UIO_READ : UIO_WRITE;
    260 			uio.uio_procp = p;
    261 			ptr = malloc(len, M_TEMP, M_WAITOK);
    262 			if (uio.uio_rw == UIO_WRITE) {
    263 				error = uiomove(ptr, len, &uio);
    264 				if (error)
    265 					goto ret;
    266 			}
    267 		}
    268 		r = usbd_do_request_flags(sc->sc_bus->devices[addr],
    269 					  &ur->request, ptr,
    270 					  ur->flags, &ur->actlen);
    271 		if (r) {
    272 			error = EIO;
    273 			goto ret;
    274 		}
    275 		if (len != 0) {
    276 			if (uio.uio_rw == UIO_READ) {
    277 				error = uiomove(ptr, len, &uio);
    278 				if (error)
    279 					goto ret;
    280 			}
    281 		}
    282 	ret:
    283 		if (ptr)
    284 			free(ptr, M_TEMP);
    285 		return (error);
    286 	}
    287 
    288 	case USB_DEVICEINFO:
    289 	{
    290 		struct usb_device_info *di = (void *)data;
    291 		int addr = di->addr;
    292 		usbd_device_handle dev;
    293 
    294 		if (addr < 1 || addr >= USB_MAX_DEVICES)
    295 			return (EINVAL);
    296 		dev = sc->sc_bus->devices[addr];
    297 		if (dev == 0)
    298 			return (ENXIO);
    299 		usbd_fill_deviceinfo(dev, di);
    300 		break;
    301 	}
    302 
    303 	case USB_DEVICESTATS:
    304 		*(struct usb_device_stats *)data = sc->sc_bus->stats;
    305 		break;
    306 
    307 	default:
    308 		return (ENXIO);
    309 	}
    310 	return (0);
    311 }
    312 
    313 int
    314 usbpoll(dev, events, p)
    315 	dev_t dev;
    316 	int events;
    317 	struct proc *p;
    318 {
    319 	int revents, s;
    320 	USB_GET_SC(usb, USBUNIT(dev), sc);
    321 
    322 	DPRINTFN(2, ("usbpoll: sc=%p events=0x%x\n", sc, events));
    323 	s = splusb();
    324 	revents = 0;
    325 	if (events & (POLLOUT | POLLWRNORM))
    326 		if (sc->sc_bus->needs_explore)
    327 			revents |= events & (POLLOUT | POLLWRNORM);
    328 	DPRINTFN(2, ("usbpoll: revents=0x%x\n", revents));
    329 	if (revents == 0) {
    330 		if (events & (POLLOUT | POLLWRNORM)) {
    331 			DPRINTFN(2, ("usbpoll: selrecord\n"));
    332 			selrecord(p, &sc->sc_consel);
    333 		}
    334 	}
    335 	splx(s);
    336 	return (revents);
    337 }
    338 
    339 #if 0
    340 int
    341 usb_bus_count()
    342 {
    343 	int i, n;
    344 
    345 	for (i = n = 0; i < usb_cd.cd_ndevs; i++)
    346 		if (usb_cd.cd_devs[i])
    347 			n++;
    348 	return (n);
    349 }
    350 #endif
    351 
    352 usbd_status
    353 usb_get_bus_handle(n, h)
    354 	int n;
    355 	usbd_bus_handle *h;
    356 {
    357 	int i;
    358 
    359 	for (i = 0; i < usb_cd.cd_ndevs; i++)
    360 		if (usb_cd.cd_devs[i] && n-- == 0) {
    361 			*h = usb_cd.cd_devs[i];
    362 			return (USBD_NORMAL_COMPLETION);
    363 		}
    364 	return (USBD_INVAL);
    365 }
    366 
    367 usbd_status
    368 usb_discover(sc)
    369 	struct usb_softc *sc;
    370 {
    371 	int s;
    372 
    373 	/* Explore device tree from the root */
    374 	/* We need mutual exclusion while traversing the device tree. */
    375 	s = splusb();
    376 	while (sc->sc_exploring)
    377 		tsleep(&sc->sc_exploring, PRIBIO, "usbdis", 0);
    378 	sc->sc_exploring = 1;
    379 	sc->sc_bus->needs_explore = 0;
    380 	splx(s);
    381 
    382 	sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub);
    383 
    384 	s = splusb();
    385 	sc->sc_exploring = 0;
    386 	wakeup(&sc->sc_exploring);
    387 	splx(s);
    388 	/* XXX should we start over if sc_needsexplore is set again? */
    389 	return (0);
    390 }
    391 
    392 void
    393 usb_needs_explore(bus)
    394 	usbd_bus_handle bus;
    395 {
    396 	bus->needs_explore = 1;
    397 	selwakeup(&bus->usbctl->sc_consel);
    398 }
    399 
    400 #if defined(__FreeBSD__)
    401 int
    402 usb_detach(device_t self)
    403 {
    404 	struct usb_softc *sc = device_get_softc(self);
    405 	char *devinfo = (char *) device_get_desc(self);
    406 
    407 	if (devinfo) {
    408 		device_set_desc(self, NULL);
    409 		free(devinfo, M_USB);
    410 	}
    411 
    412 	return (0);
    413 }
    414 
    415 DRIVER_MODULE(usb, root, usb_driver, usb_devclass, 0, 0);
    416 #endif
    417