Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / bus / usb / usb.c
1 /*      $NetBSD: usb.c,v 1.33 1999/11/22 21:57:09 augustss Exp $        */
2 /*      $FreeBSD: src/sys/dev/usb/usb.c,v 1.26.2.9 2002/11/13 15:15:22 joe Exp $        */
3
4 /*
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Lennart Augustsson (lennart@augustsson.net) at
10  * Carlstedt Research & Technology.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *        This product includes software developed by the NetBSD
23  *        Foundation, Inc. and its contributors.
24  * 4. Neither the name of The NetBSD Foundation nor the names of its
25  *    contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40
41 /*
42  * USB specifications and other documentation can be found at
43  * http://www.usb.org/developers/data/ and
44  * http://www.usb.org/developers/index.html .
45  */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/malloc.h>
51 #if defined(__NetBSD__) || defined(__OpenBSD__)
52 #include <sys/device.h>
53 #include <sys/kthread.h>
54 #include <sys/proc.h>
55 #elif defined(__FreeBSD__)
56 #include <sys/module.h>
57 #include <sys/bus.h>
58 #include <sys/filio.h>
59 #include <sys/uio.h>
60 #endif
61 #include <sys/conf.h>
62 #include <sys/poll.h>
63 #include <sys/select.h>
64 #include <sys/vnode.h>
65 #include <sys/signalvar.h>
66 #include <sys/sysctl.h>
67
68 #include <dev/usb/usb.h>
69 #include <dev/usb/usbdi.h>
70 #include <dev/usb/usbdi_util.h>
71
72 #define USBUNIT(d)      (minor(d))      /* usb_discover device nodes, kthread */
73 #define USB_DEV_MINOR   255             /* event queue device */
74
75 #if defined(__FreeBSD__)
76 MALLOC_DEFINE(M_USB, "USB", "USB");
77 MALLOC_DEFINE(M_USBDEV, "USBdev", "USB device");
78 MALLOC_DEFINE(M_USBHC, "USBHC", "USB host controller");
79
80 #include "usb_if.h"
81 #endif /* defined(__FreeBSD__) */
82
83 #include <machine/bus.h>
84
85 #include <dev/usb/usbdivar.h>
86 #include <dev/usb/usb_quirks.h>
87
88 /* Define this unconditionally in case a kernel module is loaded that
89  * has been compiled with debugging options.
90  */
91 SYSCTL_NODE(_hw, OID_AUTO, usb, CTLFLAG_RW, 0, "USB debugging");
92
93 #ifdef USB_DEBUG
94 #define DPRINTF(x)      if (usbdebug) logprintf x
95 #define DPRINTFN(n,x)   if (usbdebug>(n)) logprintf x
96 int     usbdebug = 0;
97 SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW,
98            &usbdebug, 0, "usb debug level");
99 #ifdef USB_DEBUG
100 extern int uhcidebug;
101 #endif
102 #ifdef USB_DEBUG
103 extern int ohcidebug;
104 #endif
105 /* 
106  * 0  - do usual exploration
107  * 1  - do not use timeout exploration
108  * >1 - do no exploration
109  */
110 int     usb_noexplore = 0;
111 #else
112 #define DPRINTF(x)
113 #define DPRINTFN(n,x)
114 #endif
115
116 struct usb_softc {
117         USBBASEDEVICE   sc_dev;         /* base device */
118         usbd_bus_handle sc_bus;         /* USB controller */
119         struct usbd_port sc_port;       /* dummy port for root hub */
120
121 #if defined(__FreeBSD__)
122         /* This part should be deleted when kthreads is available */
123         struct selinfo  sc_consel;      /* waiting for connect change */
124 #else
125         struct proc    *sc_event_thread;
126 #endif
127
128         char            sc_dying;
129 };
130
131 #if defined(__NetBSD__) || defined(__OpenBSD__)
132 cdev_decl(usb);
133 #elif defined(__FreeBSD__)
134 d_open_t  usbopen; 
135 d_close_t usbclose;
136 d_read_t usbread;
137 d_ioctl_t usbioctl;
138 int usbpoll(dev_t, int, usb_proc_ptr);
139
140 struct cdevsw usb_cdevsw = {
141         /* open */      usbopen,
142         /* close */     usbclose,
143         /* read */      usbread,
144         /* write */     nowrite,
145         /* ioctl */     usbioctl,
146         /* poll */      usbpoll,
147         /* mmap */      nommap,
148         /* strategy */  nostrategy,
149         /* name */      "usb",
150         /* maj */       USB_CDEV_MAJOR,
151         /* dump */      nodump,
152         /* psize */     nopsize,
153         /* flags */     0,
154         /* bmaj */      -1
155 };
156 #endif
157
158 Static usbd_status usb_discover(struct usb_softc *);
159 #if defined(__NetBSD__) || defined(__OpenBSD__)
160 Static void     usb_create_event_thread(void *);
161 Static void     usb_event_thread(void *);
162 #endif
163
164 #define USB_MAX_EVENTS 50
165 struct usb_event_q {
166         struct usb_event ue;
167         SIMPLEQ_ENTRY(usb_event_q) next;
168 };
169 Static SIMPLEQ_HEAD(, usb_event_q) usb_events =
170         SIMPLEQ_HEAD_INITIALIZER(usb_events);
171 Static int usb_nevents = 0;
172 Static struct selinfo usb_selevent;
173 Static struct proc *usb_async_proc;  /* process who wants USB SIGIO */
174 Static int usb_dev_open = 0;
175
176 Static int usb_get_next_event(struct usb_event *);
177
178 #if defined(__NetBSD__) || defined(__OpenBSD__)
179 /* Flag to see if we are in the cold boot process. */
180 extern int cold;
181 #endif
182
183 Static const char *usbrev_str[] = USBREV_STR;
184
185 USB_DECLARE_DRIVER_INIT(usb,
186                         DEVMETHOD(device_suspend, bus_generic_suspend),
187                         DEVMETHOD(device_resume, bus_generic_resume),
188                         DEVMETHOD(device_shutdown, bus_generic_shutdown)
189                         );
190
191 USB_MATCH(usb)
192 {
193         DPRINTF(("usbd_match\n"));
194         return (UMATCH_GENERIC);
195 }
196
197 USB_ATTACH(usb)
198 {
199 #if defined(__NetBSD__) || defined(__OpenBSD__)
200         struct usb_softc *sc = (struct usb_softc *)self;
201 #elif defined(__FreeBSD__)
202         struct usb_softc *sc = device_get_softc(self);
203         void *aux = device_get_ivars(self);
204         static int global_init_done = 0;
205 #endif
206         usbd_device_handle dev;
207         usbd_status err;
208         int usbrev;
209
210         sc->sc_dev = self;
211
212         DPRINTF(("usbd_attach\n"));
213
214         usbd_init();
215         sc->sc_bus = aux;
216         sc->sc_bus->usbctl = sc;
217         sc->sc_port.power = USB_MAX_POWER;
218
219 #if defined(__FreeBSD__)
220         printf("%s", USBDEVNAME(sc->sc_dev));
221 #endif
222         usbrev = sc->sc_bus->usbrev;
223         printf(": USB revision %s", usbrev_str[usbrev]);
224         if (usbrev != USBREV_1_0 && usbrev != USBREV_1_1) {
225                 printf(", not supported\n");
226                 USB_ATTACH_ERROR_RETURN;
227         }
228         printf("\n");
229
230         err = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0, 0, 0,
231                   &sc->sc_port);
232         if (!err) {
233                 dev = sc->sc_port.device;
234                 if (dev->hub == NULL) {
235                         sc->sc_dying = 1;
236                         printf("%s: root device is not a hub\n", 
237                                USBDEVNAME(sc->sc_dev));
238                         USB_ATTACH_ERROR_RETURN;
239                 }
240                 sc->sc_bus->root_hub = dev;
241 #if 1
242                 /* 
243                  * Turning this code off will delay attachment of USB devices
244                  * until the USB event thread is running, which means that
245                  * the keyboard will not work until after cold boot.
246                  */
247                 if (cold) {
248                         sc->sc_bus->use_polling++;
249                         dev->hub->explore(sc->sc_bus->root_hub);
250                         sc->sc_bus->use_polling--;
251                 }
252 #endif
253         } else {
254                 printf("%s: root hub problem, error=%d\n", 
255                        USBDEVNAME(sc->sc_dev), err); 
256                 sc->sc_dying = 1;
257         }
258
259         kthread_create(usb_create_event_thread, sc);
260
261 #if defined(__FreeBSD__)
262         /* The per controller devices (used for usb_discover) */
263         make_dev(&usb_cdevsw, device_get_unit(self), UID_ROOT, GID_OPERATOR,
264                 0644, "usb%d", device_get_unit(self));
265         if (!global_init_done) {
266                 /* The device spitting out events */
267                 make_dev(&usb_cdevsw, USB_DEV_MINOR, UID_ROOT, GID_OPERATOR,
268                         0644, "usb");
269                 global_init_done = 1;
270         }
271 #endif
272
273         USB_ATTACH_SUCCESS_RETURN;
274 }
275
276 #if defined(__NetBSD__) || defined(__OpenBSD__)
277 void
278 usb_create_event_thread(void *arg)
279 {
280         struct usb_softc *sc = arg;
281
282         if (kthread_create1(usb_event_thread, sc, &sc->sc_event_thread,
283                            "%s", sc->sc_dev.dv_xname)) {
284                 printf("%s: unable to create event thread for\n",
285                        sc->sc_dev.dv_xname);
286                 panic("usb_create_event_thread");
287         }
288 }
289
290 void
291 usb_event_thread(void *arg)
292 {
293         struct usb_softc *sc = arg;
294
295         DPRINTF(("usb_event_thread: start\n"));
296
297         while (!sc->sc_dying) {
298 #ifdef USB_DEBUG
299                 if (usb_noexplore < 2)
300 #endif
301                 usb_discover(sc);
302                 (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
303 #ifdef USB_DEBUG
304                              usb_noexplore ? 0 :
305 #endif
306                              hz*60
307                        );
308                 DPRINTFN(2,("usb_event_thread: woke up\n"));
309         }
310         sc->sc_event_thread = 0;
311
312         /* In case parent is waiting for us to exit. */
313         wakeup(sc);
314
315         DPRINTF(("usb_event_thread: exit\n"));
316         kthread_exit(0);
317 }
318
319 int
320 usbctlprint(void *aux, const char *pnp)
321 {
322         /* only "usb"es can attach to host controllers */
323         if (pnp)
324                 printf("usb at %s", pnp);
325
326         return (UNCONF);
327 }
328 #endif /* defined(__NetBSD__) || defined(__OpenBSD__) */
329
330 int
331 usbopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
332 {
333         int unit = USBUNIT(dev);
334         struct usb_softc *sc;
335
336         if (unit == USB_DEV_MINOR) {
337                 if (usb_dev_open)
338                         return (EBUSY);
339                 usb_dev_open = 1;
340                 usb_async_proc = 0;
341                 return (0);
342         } else {
343                 USB_GET_SC_OPEN(usb, unit, sc);
344
345                 if (sc->sc_dying)
346                         return (EIO);
347
348                 return (0);
349         }
350 }
351
352 int
353 usbread(dev_t dev, struct uio *uio, int flag)
354 {
355         struct usb_event ue;
356         int unit = USBUNIT(dev);
357         int s, error, n;
358
359         if (unit != USB_DEV_MINOR)
360                 return (ENODEV);
361
362         if (uio->uio_resid != sizeof(struct usb_event))
363                 return (EINVAL);
364
365         error = 0;
366         s = splusb();
367         for (;;) {
368                 n = usb_get_next_event(&ue);
369                 if (n != 0)
370                         break;
371                 if (flag & IO_NDELAY) {
372                         error = EWOULDBLOCK;
373                         break;
374                 }
375                 error = tsleep(&usb_events, PZERO | PCATCH, "usbrea", 0);
376                 if (error)
377                         break;
378         }
379         splx(s);
380         if (!error)
381                 error = uiomove((void *)&ue, uio->uio_resid, uio);
382
383         return (error);
384 }
385
386 int
387 usbclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
388 {
389         int unit = USBUNIT(dev);
390
391         if (unit == USB_DEV_MINOR) {
392                 usb_async_proc = 0;
393                 usb_dev_open = 0;
394         }
395
396         return (0);
397 }
398
399 int
400 usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
401 {
402         struct usb_softc *sc;
403         int unit = USBUNIT(devt);
404
405         if (unit == USB_DEV_MINOR) {
406                 switch (cmd) {
407                 case FIONBIO:
408                         /* All handled in the upper FS layer. */
409                         return (0);
410                         
411                 case FIOASYNC:
412                         if (*(int *)data)
413                                 usb_async_proc = p;
414                         else
415                                 usb_async_proc = 0;
416                         return (0);
417
418                 default:
419                         return (EINVAL);
420                 }
421         }
422
423         USB_GET_SC(usb, unit, sc);
424
425         if (sc->sc_dying)
426                 return (EIO);
427
428         switch (cmd) {
429 #if defined(__FreeBSD__) 
430         /* This part should be deleted when kthreads is available */
431         case USB_DISCOVER:
432                 usb_discover(sc);
433                 break;
434 #endif
435 #ifdef USB_DEBUG
436         case USB_SETDEBUG:
437                 usbdebug  = ((*(int *)data) & 0x000000ff);
438                 uhcidebug = ((*(int *)data) & 0x0000ff00) >> 8;
439                 ohcidebug = ((*(int *)data) & 0x00ff0000) >> 16;
440                 break;
441 #endif
442         case USB_REQUEST:
443         {
444                 struct usb_ctl_request *ur = (void *)data;
445                 int len = UGETW(ur->ucr_request.wLength);
446                 struct iovec iov;
447                 struct uio uio;
448                 void *ptr = 0;
449                 int addr = ur->ucr_addr;
450                 usbd_status err;
451                 int error = 0;
452
453                 DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len));
454                 if (len < 0 || len > 32768)
455                         return (EINVAL);
456                 if (addr < 0 || addr >= USB_MAX_DEVICES || 
457                     sc->sc_bus->devices[addr] == 0)
458                         return (EINVAL);
459                 if (len != 0) {
460                         iov.iov_base = (caddr_t)ur->ucr_data;
461                         iov.iov_len = len;
462                         uio.uio_iov = &iov;
463                         uio.uio_iovcnt = 1;
464                         uio.uio_resid = len;
465                         uio.uio_offset = 0;
466                         uio.uio_segflg = UIO_USERSPACE;
467                         uio.uio_rw =
468                                 ur->ucr_request.bmRequestType & UT_READ ? 
469                                 UIO_READ : UIO_WRITE;
470                         uio.uio_procp = p;
471                         ptr = malloc(len, M_TEMP, M_WAITOK);
472                         if (uio.uio_rw == UIO_WRITE) {
473                                 error = uiomove(ptr, len, &uio);
474                                 if (error)
475                                         goto ret;
476                         }
477                 }
478                 err = usbd_do_request_flags(sc->sc_bus->devices[addr],
479                           &ur->ucr_request, ptr, ur->ucr_flags, &ur->ucr_actlen);
480                 if (err) {
481                         error = EIO;
482                         goto ret;
483                 }
484                 if (len != 0) {
485                         if (uio.uio_rw == UIO_READ) {
486                                 error = uiomove(ptr, len, &uio);
487                                 if (error)
488                                         goto ret;
489                         }
490                 }
491         ret:
492                 if (ptr)
493                         free(ptr, M_TEMP);
494                 return (error);
495         }
496
497         case USB_DEVICEINFO:
498         {
499                 struct usb_device_info *di = (void *)data;
500                 int addr = di->udi_addr;
501                 usbd_device_handle dev;
502
503                 if (addr < 1 || addr >= USB_MAX_DEVICES)
504                         return (EINVAL);
505                 dev = sc->sc_bus->devices[addr];
506                 if (dev == 0)
507                         return (ENXIO);
508                 usbd_fill_deviceinfo(dev, di);
509                 break;
510         }
511
512         case USB_DEVICESTATS:
513                 *(struct usb_device_stats *)data = sc->sc_bus->stats;
514                 break;
515
516         default:
517                 return (EINVAL);
518         }
519         return (0);
520 }
521
522 int
523 usbpoll(dev_t dev, int events, usb_proc_ptr p)
524 {
525         int revents, mask, s;
526         int unit = USBUNIT(dev);
527
528         if (unit == USB_DEV_MINOR) {
529                 revents = 0;
530                 mask = POLLIN | POLLRDNORM;
531
532                 s = splusb();
533                 if ((events & mask) && usb_nevents > 0)
534                         revents |= events & mask;
535                 if (revents == 0 && (events & mask)) {
536                         DPRINTFN(2,("usb: sleeping on %p\n", &usb_selevent));
537                         selrecord(p, &usb_selevent);
538                 }
539                 splx(s);
540
541                 return (revents);
542         } else {
543 #if defined(__FreeBSD__)
544                 /* This part should be deleted when kthreads is available */
545                 struct usb_softc *sc;
546
547                 USB_GET_SC(usb, unit, sc);
548
549                 revents = 0;
550                 mask = POLLOUT | POLLRDNORM;
551
552                 s = splusb();
553                 if ((events & mask) && sc->sc_bus->needs_explore)
554                         revents |= events & mask;
555                 if (revents == 0 && (events & mask))
556                         selrecord(p, &sc->sc_consel);
557                 splx(s);
558
559                 return (revents);
560 #else
561                 return (ENXIO);
562 #endif
563         }
564 }
565
566 /* Explore device tree from the root. */
567 usbd_status
568 usb_discover(struct usb_softc *sc)
569 {
570 #if defined(__FreeBSD__)
571         /* The splxxx parts should be deleted when kthreads is available */
572         int s;
573 #endif
574
575         /* 
576          * We need mutual exclusion while traversing the device tree,
577          * but this is guaranteed since this function is only called
578          * from the event thread for the controller.
579          */
580 #if defined(__FreeBSD__)
581         s = splusb();
582 #endif
583         while (sc->sc_bus->needs_explore && !sc->sc_dying) {
584                 sc->sc_bus->needs_explore = 0;
585 #if defined(__FreeBSD__)
586                 splx(s);
587 #endif
588                 sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub);
589 #if defined(__FreeBSD__)
590                 s = splusb();
591 #endif
592         }
593 #if defined(__FreeBSD__)
594         splx(s);
595 #endif
596
597         return (USBD_NORMAL_COMPLETION);
598 }
599
600 void
601 usb_needs_explore(usbd_bus_handle bus)
602 {
603         bus->needs_explore = 1;
604 #if defined(__FreeBSD__)
605         /* This part should be deleted when kthreads is available */
606         selwakeup(&bus->usbctl->sc_consel);
607 #endif
608         wakeup(&bus->needs_explore);
609 }
610
611 /* Called at splusb() */
612 int
613 usb_get_next_event(struct usb_event *ue)
614 {
615         struct usb_event_q *ueq;
616
617         if (usb_nevents <= 0)
618                 return (0);
619         ueq = SIMPLEQ_FIRST(&usb_events);
620         *ue = ueq->ue;
621         SIMPLEQ_REMOVE_HEAD(&usb_events, ueq, next);
622         free(ueq, M_USBDEV);
623         usb_nevents--;
624         return (1);
625 }
626
627 void
628 usbd_add_event(int type, usbd_device_handle dev)
629 {
630         struct usb_event_q *ueq;
631         struct usb_event ue;
632         struct timeval thetime;
633         int s;
634
635         s = splusb();
636         if (++usb_nevents >= USB_MAX_EVENTS) {
637                 /* Too many queued events, drop an old one. */
638                 DPRINTF(("usb: event dropped\n"));
639                 (void)usb_get_next_event(&ue);
640         }
641         /* Don't want to wait here inside splusb() */
642         ueq = malloc(sizeof *ueq, M_USBDEV, M_NOWAIT);
643         if (ueq == NULL) {
644                 printf("usb: no memory, event dropped\n");
645                 splx(s);
646                 return;
647         }
648         ueq->ue.ue_type = type;
649         ueq->ue.u.ue_driver.ue_cookie = dev->cookie;
650         usbd_fill_deviceinfo(dev, &ueq->ue.u.ue_device);
651         microtime(&thetime);
652         TIMEVAL_TO_TIMESPEC(&thetime, &ueq->ue.ue_time);
653         SIMPLEQ_INSERT_TAIL(&usb_events, ueq, next);
654         wakeup(&usb_events);
655         selwakeup(&usb_selevent);
656         if (usb_async_proc != NULL)
657                 psignal(usb_async_proc, SIGIO);
658         splx(s);
659 }
660
661 #if defined(__NetBSD__) || defined(__OpenBSD__)
662 int
663 usb_activate(device_ptr_t self, devact act)
664 {
665         struct usb_softc *sc = (struct usb_softc *)self;
666         usbd_device_handle dev = sc->sc_port.device;
667         int i, rv = 0;
668
669         switch (act) {
670         case DVACT_ACTIVATE:
671                 return (EOPNOTSUPP);
672                 break;
673
674         case DVACT_DEACTIVATE:
675                 sc->sc_dying = 1;
676                 if (dev && dev->cdesc && dev->subdevs) {
677                         for (i = 0; dev->subdevs[i]; i++)
678                                 rv |= config_deactivate(dev->subdevs[i]);
679                 }
680                 break;
681         }
682         return (rv);
683 }
684
685 int
686 usb_detach(device_ptr_t self, int flags)
687 {
688         struct usb_softc *sc = (struct usb_softc *)self;
689
690         DPRINTF(("usb_detach: start\n"));
691
692         sc->sc_dying = 1;
693
694         /* Make all devices disconnect. */
695         if (sc->sc_port.device)
696                 usb_disconnect_port(&sc->sc_port, self);
697
698         /* Kill off event thread. */
699         if (sc->sc_event_thread) {
700                 wakeup(&sc->sc_bus->needs_explore);
701                 if (tsleep(sc, PWAIT, "usbdet", hz * 60))
702                         printf("%s: event thread didn't die\n",
703                                USBDEVNAME(sc->sc_dev));
704                 DPRINTF(("usb_detach: event thread dead\n"));
705         }
706
707         usbd_finish();
708         return (0);
709 }
710 #elif defined(__FreeBSD__)
711 int
712 usb_detach(device_t self)
713 {
714         DPRINTF(("%s: unload, prevented\n", USBDEVNAME(self)));
715
716         return (EINVAL);
717 }
718 #endif
719
720
721 #if defined(__FreeBSD__)
722 DRIVER_MODULE(usb, ohci, usb_driver, usb_devclass, 0, 0);
723 DRIVER_MODULE(usb, uhci, usb_driver, usb_devclass, 0, 0);
724 #endif