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