File:
[DragonFly] /
src /
sys /
bus /
usb /
usb.c
Revision
1.13:
download - view:
text,
annotated -
select for diffs
Thu May 13 23:49:14 2004 UTC (9 years, 1 month ago) by
dillon
Branches:
MAIN
CVS tags:
HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).
d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device. It was never
used for that purpose.
d_clone will be more fully implemented as work continues. We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads. This is something we will be needing later
on.
1: /*
2: * $NetBSD: usb.c,v 1.68 2002/02/20 20:30:12 christos Exp $
3: * $FreeBSD: src/sys/dev/usb/usb.c,v 1.95 2003/11/09 23:54:21 joe Exp $
4: * $DragonFly: src/sys/bus/usb/usb.c,v 1.13 2004/05/13 23:49:14 dillon Exp $
5: */
6:
7: /* Also already merged from NetBSD:
8: * $NetBSD: usb.c,v 1.70 2002/05/09 21:54:32 augustss Exp $
9: * $NetBSD: usb.c,v 1.71 2002/06/01 23:51:04 lukem Exp $
10: * $NetBSD: usb.c,v 1.73 2002/09/23 05:51:19 simonb Exp $
11: */
12:
13: /*
14: * Copyright (c) 1998 The NetBSD Foundation, Inc.
15: * All rights reserved.
16: *
17: * This code is derived from software contributed to The NetBSD Foundation
18: * by Lennart Augustsson (lennart@augustsson.net) at
19: * Carlstedt Research & Technology.
20: *
21: * Redistribution and use in source and binary forms, with or without
22: * modification, are permitted provided that the following conditions
23: * are met:
24: * 1. Redistributions of source code must retain the above copyright
25: * notice, this list of conditions and the following disclaimer.
26: * 2. Redistributions in binary form must reproduce the above copyright
27: * notice, this list of conditions and the following disclaimer in the
28: * documentation and/or other materials provided with the distribution.
29: * 3. All advertising materials mentioning features or use of this software
30: * must display the following acknowledgement:
31: * This product includes software developed by the NetBSD
32: * Foundation, Inc. and its contributors.
33: * 4. Neither the name of The NetBSD Foundation nor the names of its
34: * contributors may be used to endorse or promote products derived
35: * from this software without specific prior written permission.
36: *
37: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
38: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
39: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
40: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
41: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
43: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
44: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
45: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
47: * POSSIBILITY OF SUCH DAMAGE.
48: */
49:
50: /*
51: * USB specifications and other documentation can be found at
52: * http://www.usb.org/developers/data/ and
53: * http://www.usb.org/developers/index.html .
54: */
55:
56: #include <sys/param.h>
57: #include <sys/systm.h>
58: #include <sys/kernel.h>
59: #include <sys/lock.h>
60: #include <sys/malloc.h>
61: #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
62: #include <sys/mutex.h>
63: #endif
64: #if defined(__NetBSD__) || defined(__OpenBSD__)
65: #include <sys/device.h>
66: #elif defined(__FreeBSD__) || defined(__DragonFly__)
67: #include <sys/unistd.h>
68: #include <sys/module.h>
69: #include <sys/bus.h>
70: #include <sys/filio.h>
71: #include <sys/uio.h>
72: #endif
73: #include <sys/kthread.h>
74: #include <sys/proc.h>
75: #include <sys/conf.h>
76: #include <sys/poll.h>
77: #if defined(__FreeBSD__) && __FreeBSD_version >= 500014
78: #include <sys/selinfo.h>
79: #else
80: #include <sys/select.h>
81: #endif
82: #include <sys/vnode.h>
83: #include <sys/signalvar.h>
84: #include <sys/sysctl.h>
85:
86: #include "usb.h"
87: #include "usbdi.h"
88: #include "usbdi_util.h"
89:
90: #define USBUNIT(d) (minor(d)) /* usb_discover device nodes, kthread */
91: #define USB_DEV_MINOR 255 /* event queue device */
92:
93: #if defined(__FreeBSD__) || defined(__DragonFly__)
94: MALLOC_DEFINE(M_USB, "USB", "USB");
95: MALLOC_DEFINE(M_USBDEV, "USBdev", "USB device");
96: MALLOC_DEFINE(M_USBHC, "USBHC", "USB host controller");
97:
98: #include "usb_if.h"
99: #endif /* defined(__FreeBSD__) */
100:
101: #include <machine/bus.h>
102:
103: #include "usbdivar.h"
104: #include "usb_quirks.h"
105:
106: /* Define this unconditionally in case a kernel module is loaded that
107: * has been compiled with debugging options.
108: */
109: SYSCTL_NODE(_hw, OID_AUTO, usb, CTLFLAG_RW, 0, "USB debugging");
110:
111: #ifdef USB_DEBUG
112: #define DPRINTF(x) if (usbdebug) logprintf x
113: #define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
114: int usbdebug = 0;
115: SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW,
116: &usbdebug, 0, "usb debug level");
117: /*
118: * 0 - do usual exploration
119: * 1 - do not use timeout exploration
120: * >1 - do no exploration
121: */
122: int usb_noexplore = 0;
123: #else
124: #define DPRINTF(x)
125: #define DPRINTFN(n,x)
126: #endif
127:
128: struct usb_softc {
129: USBBASEDEVICE sc_dev; /* base device */
130: usbd_bus_handle sc_bus; /* USB controller */
131: struct usbd_port sc_port; /* dummy port for root hub */
132:
133: struct thread *sc_event_thread;
134:
135: char sc_dying;
136: };
137:
138: TAILQ_HEAD(, usb_task) usb_all_tasks;
139:
140: #if defined(__NetBSD__) || defined(__OpenBSD__)
141: cdev_decl(usb);
142: #elif defined(__FreeBSD__) || defined(__DragonFly__)
143: d_open_t usbopen;
144: d_close_t usbclose;
145: d_read_t usbread;
146: d_ioctl_t usbioctl;
147: int usbpoll(dev_t, int, usb_proc_ptr);
148:
149: struct cdevsw usb_cdevsw = {
150: /* name */ "usb",
151: /* maj */ USB_CDEV_MAJOR,
152: /* flags */ 0,
153: /* port */ NULL,
154: /* clone */ NULL,
155:
156: /* open */ usbopen,
157: /* close */ usbclose,
158: /* read */ usbread,
159: /* write */ nowrite,
160: /* ioctl */ usbioctl,
161: /* poll */ usbpoll,
162: /* mmap */ nommap,
163: /* strategy */ nostrategy,
164: /* dump */ nodump,
165: /* psize */ nopsize
166: };
167: #endif
168:
169: Static void usb_discover(void *);
170: Static void usb_create_event_thread(void *);
171: Static void usb_event_thread(void *);
172: Static void usb_task_thread(void *);
173: Static usb_proc_ptr usb_task_thread_proc = NULL;
174:
175: #define USB_MAX_EVENTS 100
176: struct usb_event_q {
177: struct usb_event ue;
178: TAILQ_ENTRY(usb_event_q) next;
179: };
180: Static TAILQ_HEAD(, usb_event_q) usb_events =
181: TAILQ_HEAD_INITIALIZER(usb_events);
182: Static int usb_nevents = 0;
183: Static struct selinfo usb_selevent;
184: Static struct proc *usb_async_proc; /* process that wants USB SIGIO */
185: Static int usb_dev_open = 0;
186: Static void usb_add_event(int, struct usb_event *);
187:
188: Static int usb_get_next_event(struct usb_event *);
189:
190: #if defined(__NetBSD__) || defined(__OpenBSD__)
191: /* Flag to see if we are in the cold boot process. */
192: extern int cold;
193: #endif
194:
195: Static const char *usbrev_str[] = USBREV_STR;
196:
197: USB_DECLARE_DRIVER_INIT(usb,
198: DEVMETHOD(device_suspend, bus_generic_suspend),
199: DEVMETHOD(device_resume, bus_generic_resume),
200: DEVMETHOD(device_shutdown, bus_generic_shutdown)
201: );
202:
203: #if defined(__FreeBSD__) || defined(__DragonFly__)
204: MODULE_VERSION(usb, 1);
205: #endif
206:
207: USB_MATCH(usb)
208: {
209: DPRINTF(("usbd_match\n"));
210: return (UMATCH_GENERIC);
211: }
212:
213: USB_ATTACH(usb)
214: {
215: #if defined(__NetBSD__) || defined(__OpenBSD__)
216: struct usb_softc *sc = (struct usb_softc *)self;
217: #elif defined(__FreeBSD__) || defined(__DragonFly__)
218: struct usb_softc *sc = device_get_softc(self);
219: void *aux = device_get_ivars(self);
220: static int global_init_done = 0;
221: #endif
222: usbd_device_handle dev;
223: usbd_status err;
224: int usbrev;
225: int speed;
226: struct usb_event ue;
227:
228: sc->sc_dev = self;
229:
230: DPRINTF(("usbd_attach\n"));
231:
232: usbd_init();
233: sc->sc_bus = aux;
234: sc->sc_bus->usbctl = sc;
235: sc->sc_port.power = USB_MAX_POWER;
236:
237: #if defined(__FreeBSD__) || defined(__DragonFly__)
238: printf("%s", USBDEVNAME(sc->sc_dev));
239: #endif
240: usbrev = sc->sc_bus->usbrev;
241: printf(": USB revision %s", usbrev_str[usbrev]);
242: switch (usbrev) {
243: case USBREV_1_0:
244: case USBREV_1_1:
245: speed = USB_SPEED_FULL;
246: break;
247: case USBREV_2_0:
248: speed = USB_SPEED_HIGH;
249: break;
250: default:
251: printf(", not supported\n");
252: sc->sc_dying = 1;
253: USB_ATTACH_ERROR_RETURN;
254: }
255: printf("\n");
256:
257: /* Make sure not to use tsleep() if we are cold booting. */
258: if (cold)
259: sc->sc_bus->use_polling++;
260:
261: ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev);
262: usb_add_event(USB_EVENT_CTRLR_ATTACH, &ue);
263:
264: #ifdef USB_USE_SOFTINTR
265: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
266: /* XXX we should have our own level */
267: sc->sc_bus->soft = softintr_establish(IPL_SOFTNET,
268: sc->sc_bus->methods->soft_intr, sc->sc_bus);
269: if (sc->sc_bus->soft == NULL) {
270: printf("%s: can't register softintr\n", USBDEVNAME(sc->sc_dev));
271: sc->sc_dying = 1;
272: USB_ATTACH_ERROR_RETURN;
273: }
274: #else
275: usb_callout_init(sc->sc_bus->softi);
276: #endif
277: #endif
278:
279: err = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0, speed, 0,
280: &sc->sc_port);
281: if (!err) {
282: dev = sc->sc_port.device;
283: if (dev->hub == NULL) {
284: sc->sc_dying = 1;
285: printf("%s: root device is not a hub\n",
286: USBDEVNAME(sc->sc_dev));
287: USB_ATTACH_ERROR_RETURN;
288: }
289: sc->sc_bus->root_hub = dev;
290: #if 1
291: /*
292: * Turning this code off will delay attachment of USB devices
293: * until the USB event thread is running, which means that
294: * the keyboard will not work until after cold boot.
295: */
296: #if defined(__FreeBSD__) || defined(__DragonFly__)
297: if (cold)
298: #else
299: if (cold && (sc->sc_dev.dv_cfdata->cf_flags & 1))
300: #endif
301: dev->hub->explore(sc->sc_bus->root_hub);
302: #endif
303: } else {
304: printf("%s: root hub problem, error=%d\n",
305: USBDEVNAME(sc->sc_dev), err);
306: sc->sc_dying = 1;
307: }
308: if (cold)
309: sc->sc_bus->use_polling--;
310:
311: config_pending_incr();
312: #if defined(__NetBSD__) || defined(__OpenBSD__)
313: usb_kthread_create(usb_create_event_thread, sc);
314: #endif
315:
316: #if defined(__FreeBSD__) || defined(__DragonFly__)
317: usb_create_event_thread(sc);
318: /* The per controller devices (used for usb_discover) */
319: /* XXX This is redundant now, but old usbd's will want it */
320: make_dev(&usb_cdevsw, device_get_unit(self), UID_ROOT, GID_OPERATOR,
321: 0660, "usb%d", device_get_unit(self));
322: if (!global_init_done) {
323: /* The device spitting out events */
324: make_dev(&usb_cdevsw, USB_DEV_MINOR, UID_ROOT, GID_OPERATOR,
325: 0660, "usb");
326: global_init_done = 1;
327: }
328: #endif
329:
330: USB_ATTACH_SUCCESS_RETURN;
331: }
332:
333: void
334: usb_create_event_thread(void *arg)
335: {
336: struct usb_softc *sc = arg;
337: static int created = 0;
338:
339: if (usb_kthread_create1(usb_event_thread, sc, &sc->sc_event_thread,
340: "%s", USBDEVNAME(sc->sc_dev))) {
341: printf("%s: unable to create event thread for\n",
342: USBDEVNAME(sc->sc_dev));
343: panic("usb_create_event_thread");
344: }
345: if (!created) {
346: created = 1;
347: TAILQ_INIT(&usb_all_tasks);
348: if (usb_kthread_create2(usb_task_thread, NULL,
349: &usb_task_thread_proc, "usbtask")) {
350: printf("unable to create task thread\n");
351: panic("usb_create_event_thread task");
352: }
353: }
354: }
355:
356: /*
357: * Add a task to be performed by the task thread. This function can be
358: * called from any context and the task will be executed in a process
359: * context ASAP.
360: */
361: void
362: usb_add_task(usbd_device_handle dev, struct usb_task *task)
363: {
364: int s;
365:
366: s = splusb();
367: if (!task->onqueue) {
368: DPRINTFN(2,("usb_add_task: task=%p\n", task));
369: TAILQ_INSERT_TAIL(&usb_all_tasks, task, next);
370: task->onqueue = 1;
371: } else {
372: DPRINTFN(3,("usb_add_task: task=%p on q\n", task));
373: }
374: wakeup(&usb_all_tasks);
375: splx(s);
376: }
377:
378: void
379: usb_rem_task(usbd_device_handle dev, struct usb_task *task)
380: {
381: int s;
382:
383: s = splusb();
384: if (task->onqueue) {
385: TAILQ_REMOVE(&usb_all_tasks, task, next);
386: task->onqueue = 0;
387: }
388: splx(s);
389: }
390:
391: void
392: usb_event_thread(void *arg)
393: {
394: struct usb_softc *sc = arg;
395:
396: DPRINTF(("usb_event_thread: start\n"));
397:
398: /*
399: * In case this controller is a companion controller to an
400: * EHCI controller we need to wait until the EHCI controller
401: * has grabbed the port.
402: * XXX It would be nicer to do this with a tsleep(), but I don't
403: * know how to synchronize the creation of the threads so it
404: * will work.
405: */
406: usb_delay_ms(sc->sc_bus, 500);
407:
408: /* Make sure first discover does something. */
409: sc->sc_bus->needs_explore = 1;
410: usb_discover(sc);
411: config_pending_decr();
412:
413: while (!sc->sc_dying) {
414: #ifdef USB_DEBUG
415: if (usb_noexplore < 2)
416: #endif
417: usb_discover(sc);
418: #ifdef USB_DEBUG
419: (void)tsleep(&sc->sc_bus->needs_explore, 0, "usbevt",
420: usb_noexplore ? 0 : hz * 60);
421: #else
422: (void)tsleep(&sc->sc_bus->needs_explore, 0, "usbevt",
423: hz * 60);
424: #endif
425: DPRINTFN(2,("usb_event_thread: woke up\n"));
426: }
427: sc->sc_event_thread = NULL;
428:
429: /* In case parent is waiting for us to exit. */
430: wakeup(sc);
431:
432: DPRINTF(("usb_event_thread: exit\n"));
433: kthread_exit();
434: }
435:
436: void
437: usb_task_thread(void *arg)
438: {
439: struct usb_task *task;
440: int s;
441:
442: #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
443: mtx_lock(&Giant);
444: #endif
445:
446: DPRINTF(("usb_task_thread: start\n"));
447:
448: s = splusb();
449: for (;;) {
450: task = TAILQ_FIRST(&usb_all_tasks);
451: if (task == NULL) {
452: tsleep(&usb_all_tasks, 0, "usbtsk", 0);
453: task = TAILQ_FIRST(&usb_all_tasks);
454: }
455: DPRINTFN(2,("usb_task_thread: woke up task=%p\n", task));
456: if (task != NULL) {
457: TAILQ_REMOVE(&usb_all_tasks, task, next);
458: task->onqueue = 0;
459: splx(s);
460: task->fun(task->arg);
461: s = splusb();
462: }
463: }
464: }
465:
466: #if defined(__NetBSD__) || defined(__OpenBSD__)
467: int
468: usbctlprint(void *aux, const char *pnp)
469: {
470: /* only "usb"es can attach to host controllers */
471: if (pnp)
472: printf("usb at %s", pnp);
473:
474: return (UNCONF);
475: }
476: #endif /* defined(__NetBSD__) || defined(__OpenBSD__) */
477:
478: int
479: usbopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
480: {
481: int unit = USBUNIT(dev);
482: struct usb_softc *sc;
483:
484: if (unit == USB_DEV_MINOR) {
485: if (usb_dev_open)
486: return (EBUSY);
487: usb_dev_open = 1;
488: usb_async_proc = NULL;
489: return (0);
490: }
491:
492: USB_GET_SC_OPEN(usb, unit, sc);
493:
494: if (sc->sc_dying)
495: return (EIO);
496:
497: return (0);
498: }
499:
500: int
501: usbread(dev_t dev, struct uio *uio, int flag)
502: {
503: struct usb_event ue;
504: int unit = USBUNIT(dev);
505: int s, error, n;
506:
507: if (unit != USB_DEV_MINOR)
508: return (ENODEV);
509:
510: if (uio->uio_resid != sizeof(struct usb_event))
511: return (EINVAL);
512:
513: error = 0;
514: s = splusb();
515: for (;;) {
516: n = usb_get_next_event(&ue);
517: if (n != 0)
518: break;
519: if (flag & IO_NDELAY) {
520: error = EWOULDBLOCK;
521: break;
522: }
523: error = tsleep(&usb_events, PCATCH, "usbrea", 0);
524: if (error)
525: break;
526: }
527: splx(s);
528: if (!error)
529: error = uiomove((void *)&ue, uio->uio_resid, uio);
530:
531: return (error);
532: }
533:
534: int
535: usbclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
536: {
537: int unit = USBUNIT(dev);
538:
539: if (unit == USB_DEV_MINOR) {
540: usb_async_proc = NULL;
541: usb_dev_open = 0;
542: }
543:
544: return (0);
545: }
546:
547: int
548: usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
549: {
550: struct usb_softc *sc;
551: int unit = USBUNIT(devt);
552:
553: if (unit == USB_DEV_MINOR) {
554: switch (cmd) {
555: case FIONBIO:
556: /* All handled in the upper FS layer. */
557: return (0);
558:
559: case FIOASYNC:
560: if (*(int *)data)
561: #if defined(__DragonFly__)
562: usb_async_proc = p->td_proc;
563: #elif __FreeBSD_version >= 500000
564: usb_async_proc = p->td_proc;
565: #else
566: usb_async_proc = p;
567: #endif
568: else
569: usb_async_proc = NULL;
570: return (0);
571:
572: default:
573: return (EINVAL);
574: }
575: }
576:
577: USB_GET_SC(usb, unit, sc);
578:
579: if (sc->sc_dying)
580: return (EIO);
581:
582: switch (cmd) {
583: #if defined(__FreeBSD__) || defined(__DragonFly__)
584: /* This part should be deleted */
585: case USB_DISCOVER:
586: break;
587: #endif
588: case USB_REQUEST:
589: {
590: struct usb_ctl_request *ur = (void *)data;
591: int len = UGETW(ur->ucr_request.wLength);
592: struct iovec iov;
593: struct uio uio;
594: void *ptr = 0;
595: int addr = ur->ucr_addr;
596: usbd_status err;
597: int error = 0;
598:
599: DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len));
600: if (len < 0 || len > 32768)
601: return (EINVAL);
602: if (addr < 0 || addr >= USB_MAX_DEVICES ||
603: sc->sc_bus->devices[addr] == 0)
604: return (EINVAL);
605: if (len != 0) {
606: iov.iov_base = (caddr_t)ur->ucr_data;
607: iov.iov_len = len;
608: uio.uio_iov = &iov;
609: uio.uio_iovcnt = 1;
610: uio.uio_resid = len;
611: uio.uio_offset = 0;
612: uio.uio_segflg = UIO_USERSPACE;
613: uio.uio_rw =
614: ur->ucr_request.bmRequestType & UT_READ ?
615: UIO_READ : UIO_WRITE;
616: uio.uio_td = p;
617: ptr = malloc(len, M_TEMP, M_WAITOK);
618: if (uio.uio_rw == UIO_WRITE) {
619: error = uiomove(ptr, len, &uio);
620: if (error)
621: goto ret;
622: }
623: }
624: err = usbd_do_request_flags(sc->sc_bus->devices[addr],
625: &ur->ucr_request, ptr, ur->ucr_flags, &ur->ucr_actlen,
626: USBD_DEFAULT_TIMEOUT);
627: if (err) {
628: error = EIO;
629: goto ret;
630: }
631: if (len != 0) {
632: if (uio.uio_rw == UIO_READ) {
633: error = uiomove(ptr, len, &uio);
634: if (error)
635: goto ret;
636: }
637: }
638: ret:
639: if (ptr)
640: free(ptr, M_TEMP);
641: return (error);
642: }
643:
644: case USB_DEVICEINFO:
645: {
646: struct usb_device_info *di = (void *)data;
647: int addr = di->udi_addr;
648: usbd_device_handle dev;
649:
650: if (addr < 1 || addr >= USB_MAX_DEVICES)
651: return (EINVAL);
652: dev = sc->sc_bus->devices[addr];
653: if (dev == NULL)
654: return (ENXIO);
655: usbd_fill_deviceinfo(dev, di, 1);
656: break;
657: }
658:
659: case USB_DEVICESTATS:
660: *(struct usb_device_stats *)data = sc->sc_bus->stats;
661: break;
662:
663: default:
664: return (EINVAL);
665: }
666: return (0);
667: }
668:
669: int
670: usbpoll(dev_t dev, int events, usb_proc_ptr p)
671: {
672: int revents, mask, s;
673: int unit = USBUNIT(dev);
674:
675: if (unit == USB_DEV_MINOR) {
676: revents = 0;
677: mask = POLLIN | POLLRDNORM;
678:
679: s = splusb();
680: if (events & mask && usb_nevents > 0)
681: revents |= events & mask;
682: if (revents == 0 && events & mask)
683: selrecord(p, &usb_selevent);
684: splx(s);
685:
686: return (revents);
687: } else {
688: #if defined(__FreeBSD__) || defined(__DragonFly__)
689: return (0); /* select/poll never wakes up - back compat */
690: #else
691: return (ENXIO);
692: #endif
693: }
694: }
695:
696: /* Explore device tree from the root. */
697: Static void
698: usb_discover(void *v)
699: {
700: struct usb_softc *sc = v;
701:
702: #if defined(__FreeBSD__) || defined(__DragonFly__)
703: /* splxxx should be changed to mutexes for preemption safety some day */
704: int s;
705: #endif
706:
707: DPRINTFN(2,("usb_discover\n"));
708: #ifdef USB_DEBUG
709: if (usb_noexplore > 1)
710: return;
711: #endif
712:
713: /*
714: * We need mutual exclusion while traversing the device tree,
715: * but this is guaranteed since this function is only called
716: * from the event thread for the controller.
717: */
718: #if defined(__FreeBSD__) || defined(__DragonFly__)
719: s = splusb();
720: #endif
721: while (sc->sc_bus->needs_explore && !sc->sc_dying) {
722: sc->sc_bus->needs_explore = 0;
723: #if defined(__FreeBSD__) || defined(__DragonFly__)
724: splx(s);
725: #endif
726: sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub);
727: #if defined(__FreeBSD__) || defined(__DragonFly__)
728: s = splusb();
729: #endif
730: }
731: #if defined(__FreeBSD__) || defined(__DragonFly__)
732: splx(s);
733: #endif
734: }
735:
736: void
737: usb_needs_explore(usbd_device_handle dev)
738: {
739: DPRINTFN(2,("usb_needs_explore\n"));
740: dev->bus->needs_explore = 1;
741: wakeup(&dev->bus->needs_explore);
742: }
743:
744: /* Called at splusb() */
745: int
746: usb_get_next_event(struct usb_event *ue)
747: {
748: struct usb_event_q *ueq;
749:
750: if (usb_nevents <= 0)
751: return (0);
752: ueq = TAILQ_FIRST(&usb_events);
753: #ifdef DIAGNOSTIC
754: if (ueq == NULL) {
755: printf("usb: usb_nevents got out of sync! %d\n", usb_nevents);
756: usb_nevents = 0;
757: return (0);
758: }
759: #endif
760: *ue = ueq->ue;
761: TAILQ_REMOVE(&usb_events, ueq, next);
762: free(ueq, M_USBDEV);
763: usb_nevents--;
764: return (1);
765: }
766:
767: void
768: usbd_add_dev_event(int type, usbd_device_handle udev)
769: {
770: struct usb_event ue;
771:
772: usbd_fill_deviceinfo(udev, &ue.u.ue_device, USB_EVENT_IS_ATTACH(type));
773: usb_add_event(type, &ue);
774: }
775:
776: void
777: usbd_add_drv_event(int type, usbd_device_handle udev, device_ptr_t dev)
778: {
779: struct usb_event ue;
780:
781: ue.u.ue_driver.ue_cookie = udev->cookie;
782: strncpy(ue.u.ue_driver.ue_devname, USBDEVPTRNAME(dev),
783: sizeof ue.u.ue_driver.ue_devname);
784: usb_add_event(type, &ue);
785: }
786:
787: void
788: usb_add_event(int type, struct usb_event *uep)
789: {
790: struct usb_event_q *ueq;
791: struct usb_event ue;
792: struct timeval thetime;
793: int s;
794:
795: ueq = malloc(sizeof *ueq, M_USBDEV, M_INTWAIT);
796: ueq->ue = *uep;
797: ueq->ue.ue_type = type;
798: microtime(&thetime);
799: TIMEVAL_TO_TIMESPEC(&thetime, &ueq->ue.ue_time);
800:
801: s = splusb();
802: if (USB_EVENT_IS_DETACH(type)) {
803: struct usb_event_q *ueqi, *ueqi_next;
804:
805: for (ueqi = TAILQ_FIRST(&usb_events); ueqi; ueqi = ueqi_next) {
806: ueqi_next = TAILQ_NEXT(ueqi, next);
807: if (ueqi->ue.u.ue_driver.ue_cookie.cookie ==
808: uep->u.ue_device.udi_cookie.cookie) {
809: TAILQ_REMOVE(&usb_events, ueqi, next);
810: free(ueqi, M_USBDEV);
811: usb_nevents--;
812: ueqi_next = TAILQ_FIRST(&usb_events);
813: }
814: }
815: }
816: if (usb_nevents >= USB_MAX_EVENTS) {
817: /* Too many queued events, drop an old one. */
818: DPRINTF(("usb: event dropped\n"));
819: (void)usb_get_next_event(&ue);
820: }
821: TAILQ_INSERT_TAIL(&usb_events, ueq, next);
822: usb_nevents++;
823: wakeup(&usb_events);
824: selwakeuppri(&usb_selevent, 0);
825: if (usb_async_proc != NULL) {
826: PROC_LOCK(usb_async_proc);
827: psignal(usb_async_proc, SIGIO);
828: PROC_UNLOCK(usb_async_proc);
829: }
830: splx(s);
831: }
832:
833: void
834: usb_schedsoftintr(usbd_bus_handle bus)
835: {
836: DPRINTFN(10,("usb_schedsoftintr: polling=%d\n", bus->use_polling));
837: #ifdef USB_USE_SOFTINTR
838: if (bus->use_polling) {
839: bus->methods->soft_intr(bus);
840: } else {
841: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
842: softintr_schedule(bus->soft);
843: #else
844: if (!callout_pending(&bus->softi))
845: callout_reset(&bus->softi, 0, bus->methods->soft_intr,
846: bus);
847: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
848: }
849: #else
850: bus->methods->soft_intr(bus);
851: #endif /* USB_USE_SOFTINTR */
852: }
853:
854:
855: #if defined(__NetBSD__) || defined(__OpenBSD__)
856: int
857: usb_activate(device_ptr_t self, enum devact act)
858: {
859: struct usb_softc *sc = (struct usb_softc *)self;
860: usbd_device_handle dev = sc->sc_port.device;
861: int i, rv = 0;
862:
863: switch (act) {
864: case DVACT_ACTIVATE:
865: return (EOPNOTSUPP);
866:
867: case DVACT_DEACTIVATE:
868: sc->sc_dying = 1;
869: if (dev != NULL && dev->cdesc != NULL && dev->subdevs != NULL) {
870: for (i = 0; dev->subdevs[i]; i++)
871: rv |= config_deactivate(dev->subdevs[i]);
872: }
873: break;
874: }
875: return (rv);
876: }
877:
878: int
879: usb_detach(device_ptr_t self, int flags)
880: {
881: struct usb_softc *sc = (struct usb_softc *)self;
882: struct usb_event ue;
883:
884: DPRINTF(("usb_detach: start\n"));
885:
886: sc->sc_dying = 1;
887:
888: /* Make all devices disconnect. */
889: if (sc->sc_port.device != NULL)
890: usb_disconnect_port(&sc->sc_port, self);
891:
892: /* Kill off event thread. */
893: if (sc->sc_event_thread != NULL) {
894: wakeup(&sc->sc_bus->needs_explore);
895: if (tsleep(sc, 0, "usbdet", hz * 60))
896: printf("%s: event thread didn't die\n",
897: USBDEVNAME(sc->sc_dev));
898: DPRINTF(("usb_detach: event thread dead\n"));
899: }
900:
901: usbd_finish();
902:
903: #ifdef USB_USE_SOFTINTR
904: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
905: if (sc->sc_bus->soft != NULL) {
906: softintr_disestablish(sc->sc_bus->soft);
907: sc->sc_bus->soft = NULL;
908: }
909: #else
910: callout_stop(&sc->sc_bus->softi);
911: #endif
912: #endif
913:
914: ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev);
915: usb_add_event(USB_EVENT_CTRLR_DETACH, &ue);
916:
917: return (0);
918: }
919: #elif defined(__FreeBSD__) || defined(__DragonFly__)
920: int
921: usb_detach(device_t self)
922: {
923: DPRINTF(("%s: unload, prevented\n", USBDEVNAME(self)));
924:
925: return (EINVAL);
926: }
927: #endif
928:
929:
930: #if defined(__FreeBSD__) || defined(__DragonFly__)
931: DRIVER_MODULE(usb, ohci, usb_driver, usb_devclass, 0, 0);
932: DRIVER_MODULE(usb, uhci, usb_driver, usb_devclass, 0, 0);
933: DRIVER_MODULE(usb, ehci, usb_driver, usb_devclass, 0, 0);
934: #endif