usb.c revision 1.4 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 (at) 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