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