usb.c revision 1.23 1 /* $NetBSD: usb.c,v 1.23 1999/09/15 14:17:15 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__) || defined(__OpenBSD__)
51 #include <sys/device.h>
52 #include <sys/kthread.h>
53 #elif defined(__FreeBSD__)
54 #include <sys/module.h>
55 #include <sys/bus.h>
56 #include <sys/ioccom.h>
57 #include <sys/uio.h>
58 #include <sys/conf.h>
59 #endif
60 #include <sys/conf.h>
61 #include <sys/poll.h>
62 #include <sys/proc.h>
63 #include <sys/select.h>
64
65 #include <dev/usb/usb.h>
66 #include <dev/usb/usbdi.h>
67 #include <dev/usb/usbdi_util.h>
68
69 #if defined(__FreeBSD__)
70 MALLOC_DEFINE(M_USB, "USB", "USB");
71 MALLOC_DEFINE(M_USBDEV, "USBdev", "USB device");
72 MALLOC_DEFINE(M_USBHC, "USBHC", "USB host controller");
73
74 #include "usb_if.h"
75 #endif /* defined(__FreeBSD__) */
76
77 #include <machine/bus.h>
78
79 #include <dev/usb/usbdivar.h>
80 #include <dev/usb/usb_quirks.h>
81
82 #ifdef USB_DEBUG
83 #define DPRINTF(x) if (usbdebug) logprintf x
84 #define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
85 int usbdebug = 0;
86 int uhcidebug;
87 int ohcidebug;
88 int usb_noexplore = 0;
89 #else
90 #define DPRINTF(x)
91 #define DPRINTFN(n,x)
92 #endif
93
94 int usb_nbus = 0;
95
96 #define USBUNIT(dev) (minor(dev))
97
98 struct usb_softc {
99 USBBASEDEVICE sc_dev; /* base device */
100 usbd_bus_handle sc_bus; /* USB controller */
101 struct usbd_port sc_port; /* dummy port for root hub */
102 char sc_exploring;
103 char sc_dying;
104 struct selinfo sc_consel; /* waiting for connect change */
105 struct proc *sc_event_thread;
106 };
107
108 #if defined(__NetBSD__) || defined(__OpenBSD__)
109 cdev_decl(usb);
110 #elif defined(__FreeBSD__)
111 d_open_t usbopen;
112 d_close_t usbclose;
113 d_ioctl_t usbioctl;
114 int usbpoll __P((dev_t, int, struct proc *));
115
116 struct cdevsw usb_cdevsw = {
117 usbopen, usbclose, noread, nowrite,
118 usbioctl, nullstop, nullreset, nodevtotty,
119 usbpoll, nommap, nostrat,
120 "usb", NULL, -1
121 };
122 #endif
123
124 usbd_status usb_discover __P((struct usb_softc *));
125 void usb_create_event_thread __P((void *));
126 void usb_event_thread __P((void *));
127
128 /* Flag to see if we are in the cold boot process. */
129 extern int cold;
130
131 USB_DECLARE_DRIVER_INIT(usb, DEVMETHOD(bus_print_child, usbd_print_child));
132
133 USB_MATCH(usb)
134 {
135 DPRINTF(("usbd_match\n"));
136 return (UMATCH_GENERIC);
137 }
138
139 USB_ATTACH(usb)
140 {
141 #if defined(__NetBSD__) || defined(__OpenBSD__)
142 struct usb_softc *sc = (struct usb_softc *)self;
143 #elif defined(__FreeBSD__)
144 struct usb_softc *sc = device_get_softc(self);
145 void *aux = device_get_ivars(self);
146 #endif
147 usbd_device_handle dev;
148 usbd_status r;
149
150 #if defined(__NetBSD__) || defined(__OpenBSD__)
151 printf("\n");
152 #elif defined(__FreeBSD__)
153 sc->sc_dev = self;
154 #endif
155
156 DPRINTF(("usbd_attach\n"));
157 usbd_init();
158 sc->sc_bus = aux;
159 sc->sc_bus->usbctl = sc;
160 if (cold)
161 sc->sc_bus->use_polling++;
162 sc->sc_port.power = USB_MAX_POWER;
163 r = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0,0,0,
164 &sc->sc_port);
165
166 if (r == USBD_NORMAL_COMPLETION) {
167 dev = sc->sc_port.device;
168 if (!dev->hub) {
169 sc->sc_dying = 1;
170 printf("%s: root device is not a hub\n",
171 USBDEVNAME(sc->sc_dev));
172 USB_ATTACH_ERROR_RETURN;
173 }
174 sc->sc_bus->root_hub = dev;
175 dev->hub->explore(sc->sc_bus->root_hub);
176 } else {
177 printf("%s: root hub problem, error=%d\n",
178 USBDEVNAME(sc->sc_dev), r);
179 sc->sc_dying = 1;
180 }
181 if (cold)
182 sc->sc_bus->use_polling--;
183
184 kthread_create(usb_create_event_thread, sc);
185
186 usb_nbus++;
187 USB_ATTACH_SUCCESS_RETURN;
188 }
189
190 void
191 usb_create_event_thread(arg)
192 void *arg;
193 {
194 struct usb_softc *sc = arg;
195
196 if (kthread_create1(usb_event_thread, sc, &sc->sc_event_thread,
197 "%s", sc->sc_dev.dv_xname)) {
198 printf("%s: unable to create event thread for\n",
199 sc->sc_dev.dv_xname);
200 panic("usb_create_event_thread");
201 }
202 }
203
204 void
205 usb_event_thread(arg)
206 void *arg;
207 {
208 struct usb_softc *sc = arg;
209
210 while (!sc->sc_dying) {
211 #ifdef USB_DEBUG
212 if (!usb_noexplore)
213 #endif
214 usb_discover(sc);
215 (void)tsleep(&sc->sc_bus->needs_explore,
216 PWAIT, "usbevt", hz*60);
217 DPRINTFN(2,("usb_event_thread: woke up\n"));
218 }
219 sc->sc_event_thread = 0;
220
221 /* In case parent is waiting for us to exit. */
222 wakeup(sc);
223
224 kthread_exit(0);
225 }
226
227 #if defined(__NetBSD__) || defined(__OpenBSD__)
228 int
229 usbctlprint(aux, pnp)
230 void *aux;
231 const char *pnp;
232 {
233 /* only "usb"es can attach to host controllers */
234 if (pnp)
235 printf("usb at %s", pnp);
236
237 return (UNCONF);
238 }
239 #endif
240
241 int
242 usbopen(dev, flag, mode, p)
243 dev_t dev;
244 int flag, mode;
245 struct proc *p;
246 {
247 USB_GET_SC_OPEN(usb, USBUNIT(dev), sc);
248
249 if (sc == 0)
250 return (ENXIO);
251 if (sc->sc_dying)
252 return (EIO);
253
254 return (0);
255 }
256
257 int
258 usbclose(dev, flag, mode, p)
259 dev_t dev;
260 int flag, mode;
261 struct proc *p;
262 {
263 return (0);
264 }
265
266 int
267 usbioctl(dev, cmd, data, flag, p)
268 dev_t dev;
269 u_long cmd;
270 caddr_t data;
271 int flag;
272 struct proc *p;
273 {
274 USB_GET_SC(usb, USBUNIT(dev), sc);
275
276 if (sc->sc_dying)
277 return (EIO);
278
279 switch (cmd) {
280 #ifdef USB_DEBUG
281 case USB_SETDEBUG:
282 usbdebug = uhcidebug = ohcidebug = *(int *)data;
283 break;
284 #endif
285 #if 0
286 case USB_DISCOVER:
287 usb_discover(sc);
288 break;
289 #endif
290 case USB_REQUEST:
291 {
292 struct usb_ctl_request *ur = (void *)data;
293 int len = UGETW(ur->request.wLength);
294 struct iovec iov;
295 struct uio uio;
296 void *ptr = 0;
297 int addr = ur->addr;
298 usbd_status r;
299 int error = 0;
300
301 DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len));
302 if (len < 0 || len > 32768)
303 return (EINVAL);
304 if (addr < 0 || addr >= USB_MAX_DEVICES ||
305 sc->sc_bus->devices[addr] == 0)
306 return (EINVAL);
307 if (len != 0) {
308 iov.iov_base = (caddr_t)ur->data;
309 iov.iov_len = len;
310 uio.uio_iov = &iov;
311 uio.uio_iovcnt = 1;
312 uio.uio_resid = len;
313 uio.uio_offset = 0;
314 uio.uio_segflg = UIO_USERSPACE;
315 uio.uio_rw =
316 ur->request.bmRequestType & UT_READ ?
317 UIO_READ : UIO_WRITE;
318 uio.uio_procp = p;
319 ptr = malloc(len, M_TEMP, M_WAITOK);
320 if (uio.uio_rw == UIO_WRITE) {
321 error = uiomove(ptr, len, &uio);
322 if (error)
323 goto ret;
324 }
325 }
326 r = usbd_do_request_flags(sc->sc_bus->devices[addr],
327 &ur->request, ptr,
328 ur->flags, &ur->actlen);
329 if (r != USBD_NORMAL_COMPLETION) {
330 error = EIO;
331 goto ret;
332 }
333 if (len != 0) {
334 if (uio.uio_rw == UIO_READ) {
335 error = uiomove(ptr, len, &uio);
336 if (error)
337 goto ret;
338 }
339 }
340 ret:
341 if (ptr)
342 free(ptr, M_TEMP);
343 return (error);
344 }
345
346 case USB_DEVICEINFO:
347 {
348 struct usb_device_info *di = (void *)data;
349 int addr = di->addr;
350 usbd_device_handle dev;
351
352 if (addr < 1 || addr >= USB_MAX_DEVICES)
353 return (EINVAL);
354 dev = sc->sc_bus->devices[addr];
355 if (dev == 0)
356 return (ENXIO);
357 usbd_fill_deviceinfo(dev, di);
358 break;
359 }
360
361 case USB_DEVICESTATS:
362 *(struct usb_device_stats *)data = sc->sc_bus->stats;
363 break;
364
365 default:
366 return (ENXIO);
367 }
368 return (0);
369 }
370
371 int
372 usbpoll(dev, events, p)
373 dev_t dev;
374 int events;
375 struct proc *p;
376 {
377 int revents, s;
378 USB_GET_SC(usb, USBUNIT(dev), sc);
379
380 if (sc->sc_dying)
381 return (EIO);
382
383 DPRINTFN(2, ("usbpoll: sc=%p events=0x%x\n", sc, events));
384 s = splusb();
385 revents = 0;
386 if (events & (POLLOUT | POLLWRNORM))
387 if (sc->sc_bus->needs_explore)
388 revents |= events & (POLLOUT | POLLWRNORM);
389 DPRINTFN(2, ("usbpoll: revents=0x%x\n", revents));
390 if (revents == 0) {
391 if (events & (POLLOUT | POLLWRNORM)) {
392 DPRINTFN(2, ("usbpoll: selrecord\n"));
393 selrecord(p, &sc->sc_consel);
394 }
395 }
396 splx(s);
397 return (revents);
398 }
399
400 usbd_status
401 usb_discover(sc)
402 struct usb_softc *sc;
403 {
404 int s;
405
406 /* Explore device tree from the root */
407 /* We need mutual exclusion while traversing the device tree. */
408 do {
409 s = splusb();
410 while (sc->sc_exploring)
411 tsleep(&sc->sc_exploring, PRIBIO, "usbdis", 0);
412 sc->sc_exploring = 1;
413 sc->sc_bus->needs_explore = 0;
414 splx(s);
415
416 sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub);
417
418 s = splusb();
419 sc->sc_exploring = 0;
420 wakeup(&sc->sc_exploring);
421 splx(s);
422 } while (sc->sc_bus->needs_explore && !sc->sc_dying);
423 return (USBD_NORMAL_COMPLETION);
424 }
425
426 void
427 usb_needs_explore(bus)
428 usbd_bus_handle bus;
429 {
430 bus->needs_explore = 1;
431 selwakeup(&bus->usbctl->sc_consel);
432 wakeup(&bus->needs_explore);
433 }
434
435 int
436 usb_activate(self, act)
437 device_ptr_t self;
438 enum devact act;
439 {
440 struct usb_softc *sc = (struct usb_softc *)self;
441 int rv = 0;
442
443 switch (act) {
444 case DVACT_ACTIVATE:
445 return (EOPNOTSUPP);
446 break;
447
448 case DVACT_DEACTIVATE:
449 sc->sc_dying = 1;
450 break;
451 }
452 return (rv);
453 }
454
455 int
456 usb_detach(self, flags)
457 device_ptr_t self;
458 int flags;
459 {
460 struct usb_softc *sc = (struct usb_softc *)self;
461
462 sc->sc_dying = 1;
463
464 /* Make all devices disconnect. */
465 usb_disconnect_port(&sc->sc_port);
466
467 /* Kill off event thread. */
468 if (sc->sc_event_thread) {
469 wakeup(&sc->sc_bus->needs_explore);
470 if (tsleep(sc, PWAIT, "usbdet", hz * 60))
471 printf("%s: event thread didn't die\n",
472 USBDEVNAME(sc->sc_dev));
473 }
474
475 usb_nbus--;
476 return (0);
477 }
478
479 int
480 usbread(dev, uio, flag)
481 dev_t dev;
482 struct uio *uio;
483 int flag;
484 {
485 /* XXX */
486 return (0);
487 }
488
489 #if defined(__FreeBSD__)
490 DRIVER_MODULE(usb, root, usb_driver, usb_devclass, 0, 0);
491 #endif
492