summaryrefslogtreecommitdiff
path: root/sys/dev/usb/usb.c
diff options
context:
space:
mode:
authorAaron Campbell <aaron@cvs.openbsd.org>2000-03-26 08:39:47 +0000
committerAaron Campbell <aaron@cvs.openbsd.org>2000-03-26 08:39:47 +0000
commit28320e899fbfbbe660f759f96511b4ed754a9a0b (patch)
tree789ef853a5b4025e2d189b0a56408bd794bdadbc /sys/dev/usb/usb.c
parentee37c844b6cad757fe1b782a43e759d2e9570934 (diff)
Sync with NetBSD.
Diffstat (limited to 'sys/dev/usb/usb.c')
-rw-r--r--sys/dev/usb/usb.c251
1 files changed, 181 insertions, 70 deletions
diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c
index e23f43d46c0..22a3b3777cd 100644
--- a/sys/dev/usb/usb.c
+++ b/sys/dev/usb/usb.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: usb.c,v 1.7 1999/11/11 15:57:40 ho Exp $ */
-/* $NetBSD: usb.c,v 1.28 1999/10/13 08:10:57 augustss Exp $ */
+/* $OpenBSD: usb.c,v 1.8 2000/03/26 08:39:46 aaron Exp $ */
+/* $NetBSD: usb.c,v 1.41 2000/03/16 00:46:38 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -51,15 +51,15 @@
#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/device.h>
#include <sys/kthread.h>
+#include <sys/proc.h>
#elif defined(__FreeBSD__)
#include <sys/module.h>
#include <sys/bus.h>
-#include <sys/ioccom.h>
+#include <sys/filio.h>
#include <sys/uio.h>
#endif
#include <sys/conf.h>
#include <sys/poll.h>
-#include <sys/proc.h>
#include <sys/select.h>
#include <sys/vnode.h>
#include <sys/signalvar.h>
@@ -87,8 +87,17 @@ MALLOC_DEFINE(M_USBHC, "USBHC", "USB host controller");
#define DPRINTF(x) if (usbdebug) logprintf x
#define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
int usbdebug = 0;
-int uhcidebug;
-int ohcidebug;
+#ifdef UHCI_DEBUG
+int uhcidebug;
+#endif
+#ifdef OHCI_DEBUG
+int ohcidebug;
+#endif
+/*
+ * 0 - do usual exploration
+ * 1 - do not use timeout exploration
+ * >1 - do no exploration
+ */
int usb_noexplore = 0;
#else
#define DPRINTF(x)
@@ -100,8 +109,12 @@ struct usb_softc {
usbd_bus_handle sc_bus; /* USB controller */
struct usbd_port sc_port; /* dummy port for root hub */
+#if defined (__FreeBSD__)
+ /* This part should be deleted when kthreads is available */
struct selinfo sc_consel; /* waiting for connect change */
+#else
struct proc *sc_event_thread;
+#endif
char sc_dying;
};
@@ -111,6 +124,7 @@ cdev_decl(usb);
#elif defined(__FreeBSD__)
d_open_t usbopen;
d_close_t usbclose;
+d_read_t usbread;
d_ioctl_t usbioctl;
int usbpoll __P((dev_t, int, struct proc *));
@@ -136,7 +150,7 @@ usbd_status usb_discover __P((struct usb_softc *));
void usb_create_event_thread __P((void *));
void usb_event_thread __P((void *));
-#define USB_MAX_EVENTS 50
+#define USB_MAX_EVENTS 100
struct usb_event_q {
struct usb_event ue;
SIMPLEQ_ENTRY(usb_event_q) next;
@@ -146,11 +160,16 @@ int usb_nevents = 0;
struct selinfo usb_selevent;
struct proc *usb_async_proc; /* process who wants USB SIGIO */
int usb_dev_open = 0;
+void usb_add_event __P((int, struct usb_event *));
int usb_get_next_event __P((struct usb_event *));
+#if defined(__NetBSD__) || defined(__OpenBSD__)
/* Flag to see if we are in the cold boot process. */
extern int cold;
+#endif
+
+static const char *usbrev_str[] = USBREV_STR;
USB_DECLARE_DRIVER(usb);
@@ -169,25 +188,42 @@ USB_ATTACH(usb)
void *aux = device_get_ivars(self);
#endif
usbd_device_handle dev;
- usbd_status r;
-
-#if defined(__NetBSD__) || defined(__OpenBSD__)
- printf("\n");
-#elif defined(__FreeBSD__)
+ usbd_status err;
+ int usbrev;
+ struct usb_event ue;
+
+#if defined(__FreeBSD__)
+ printf("%s", USBDEVNAME(sc->sc_dev));
sc->sc_dev = self;
#endif
DPRINTF(("usbd_attach\n"));
+
usbd_init();
sc->sc_bus = aux;
sc->sc_bus->usbctl = sc;
sc->sc_port.power = USB_MAX_POWER;
- r = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0, 0, 0,
- &sc->sc_port);
- if (r == USBD_NORMAL_COMPLETION) {
+ usbrev = sc->sc_bus->usbrev;
+ printf(": USB revision %s", usbrev_str[usbrev]);
+ if (usbrev != USBREV_1_0 && usbrev != USBREV_1_1) {
+ printf(", not supported\n");
+ USB_ATTACH_ERROR_RETURN;
+ }
+ printf("\n");
+
+ /* Make sure not to use tsleep() if we are cold booting. */
+ if (cold)
+ sc->sc_bus->use_polling++;
+
+ ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev);
+ usb_add_event(USB_EVENT_CTRLR_ATTACH, &ue);
+
+ err = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0, 0, 0,
+ &sc->sc_port);
+ if (!err) {
dev = sc->sc_port.device;
- if (!dev->hub) {
+ if (dev->hub == NULL) {
sc->sc_dying = 1;
printf("%s: root device is not a hub\n",
USBDEVNAME(sc->sc_dev));
@@ -200,23 +236,18 @@ USB_ATTACH(usb)
* until the USB event thread is running, which means that
* the keyboard will not work until after cold boot.
*/
- if (cold) {
- sc->sc_bus->use_polling++;
+ if (cold && (sc->sc_dev.dv_cfdata->cf_flags & 1)
dev->hub->explore(sc->sc_bus->root_hub);
- sc->sc_bus->use_polling--;
- }
#endif
} else {
printf("%s: root hub problem, error=%d\n",
- USBDEVNAME(sc->sc_dev), r);
+ USBDEVNAME(sc->sc_dev), err);
sc->sc_dying = 1;
}
+ if (cold)
+ sc->sc_bus->use_polling--;
-#if defined(__NetBSD__)
- kthread_create(usb_create_event_thread, sc);
-#elif defined(__OpenBSD__)
kthread_create_deferred(usb_create_event_thread, sc);
-#endif
#if defined(__FreeBSD__)
make_dev(&usb_cdevsw, device_get_unit(self), UID_ROOT, GID_OPERATOR,
@@ -253,13 +284,20 @@ usb_event_thread(arg)
DPRINTF(("usb_event_thread: start\n"));
+ /* Make sure first discover does something. */
+ sc->sc_bus->needs_explore = 1;
+
while (!sc->sc_dying) {
#ifdef USB_DEBUG
- if (!usb_noexplore)
+ if (usb_noexplore < 2)
#endif
usb_discover(sc);
- (void)tsleep(&sc->sc_bus->needs_explore,
- PWAIT, "usbevt", hz*60);
+ (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
+#ifdef USB_DEBUG
+ usb_noexplore ? 0 :
+#endif
+ hz*60
+ );
DPRINTFN(2,("usb_event_thread: woke up\n"));
}
sc->sc_event_thread = 0;
@@ -397,13 +435,20 @@ usbioctl(devt, cmd, data, flag, p)
switch (cmd) {
#if defined(__FreeBSD__)
+ /* This part should be deleted when kthreads is available */
case USB_DISCOVER:
usb_discover(sc);
break;
#endif
#ifdef USB_DEBUG
case USB_SETDEBUG:
- usbdebug = uhcidebug = ohcidebug = *(int *)data;
+ usbdebug = ((*(int *)data) & 0x000000ff);
+#ifdef UHCI_DEBUG
+ uhcidebug = ((*(int *)data) & 0x0000ff00) >> 8;
+#endif
+#ifdef OHCI_DEBUG
+ ohcidebug = ((*(int *)data) & 0x00ff0000) >> 16;
+#endif
break;
#endif
case USB_REQUEST:
@@ -414,7 +459,7 @@ usbioctl(devt, cmd, data, flag, p)
struct uio uio;
void *ptr = 0;
int addr = ur->addr;
- usbd_status r;
+ usbd_status err;
int error = 0;
DPRINTF(("usbioctl: USB_REQUEST addr=%d len=%d\n", addr, len));
@@ -442,10 +487,9 @@ usbioctl(devt, cmd, data, flag, p)
goto ret;
}
}
- r = usbd_do_request_flags(sc->sc_bus->devices[addr],
- &ur->request, ptr,
- ur->flags, &ur->actlen);
- if (r != USBD_NORMAL_COMPLETION) {
+ err = usbd_do_request_flags(sc->sc_bus->devices[addr],
+ &ur->request, ptr, ur->flags, &ur->actlen);
+ if (err) {
error = EIO;
goto ret;
}
@@ -466,14 +510,14 @@ usbioctl(devt, cmd, data, flag, p)
{
struct usb_device_info *di = (void *)data;
int addr = di->addr;
- usbd_device_handle devh;
+ usbd_device_handle dev;
if (addr < 1 || addr >= USB_MAX_DEVICES)
return (EINVAL);
- devh = sc->sc_bus->devices[addr];
- if (devh == 0)
+ dev = sc->sc_bus->devices[addr];
+ if (dev == NULL)
return (ENXIO);
- usbd_fill_deviceinfo(devh, di);
+ usbd_fill_deviceinfo(dev, di);
break;
}
@@ -495,25 +539,41 @@ usbpoll(dev, events, p)
{
int revents, mask, s;
- if (minor(dev) != USB_DEV_MINOR)
- return (ENXIO);
+ if (minor(dev) != USB_DEV_MINOR) {
+ revents = 0;
+ mask = POLLIN | POLLRDNORM;
- revents = 0;
- s = splusb();
- mask = POLLIN | POLLRDNORM;
- if (events & mask)
- if (usb_nevents > 0)
+ s = splusb();
+ if (events & mask && usb_nevents > 0)
revents |= events & mask;
-
- DPRINTFN(2, ("usbpoll: revents=0x%x\n", revents));
- if (revents == 0) {
- if (events & mask) {
- DPRINTFN(2, ("usbpoll: selrecord\n"));
+ if (revents == 0 && events & mask)
selrecord(p, &usb_selevent);
- }
+ splx(s);
+
+ return(revents);
+ } else {
+#if defined(__FreeBSD__)
+ /* This part should be deleted when kthreads is available */
+ struct usb_softc *sc;
+ int unit = minor(dev);
+
+ USB_GET_SC(usb, unit, sc);
+
+ revents = 0;
+ mask = POLLOUT | POLLRDNORM;
+
+ s = splusb();
+ if (events & mask && sc->sc_bus->needs_explore)
+ revents |= events & mask;
+ if (revents == 0 && events & mask)
+ selrecord(p, &sc->sc_consel);
+ splx(s);
+
+ return (revents);
+#else
+ return (ENXIO);
+#endif
}
- splx(s);
- return (revents);
}
/* Explore device tree from the root. */
@@ -521,15 +581,31 @@ usbd_status
usb_discover(sc)
struct usb_softc *sc;
{
+#if defined(__FreeBSD__)
+ /* The splxxx parts should be deleted when kthreads is available */
+ int s;
+#endif
/*
* We need mutual exclusion while traversing the device tree,
* but this is guaranteed since this function is only called
* from the event thread for the controller.
*/
- do {
+#if defined(__FreeBSD__)
+ s = splusb();
+#endif
+ while (sc->sc_bus->needs_explore && !sc->sc_dying) {
sc->sc_bus->needs_explore = 0;
+#if defined(__FreeBSD__)
+ splx(s);
+#endif
sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub);
- } while (sc->sc_bus->needs_explore && !sc->sc_dying);
+#if defined(__FreeBSD__)
+ s = splusb();
+#endif
+ }
+#if defined(__FreeBSD__)
+ splx(s);
+#endif
return (USBD_NORMAL_COMPLETION);
}
@@ -538,6 +614,10 @@ usb_needs_explore(bus)
usbd_bus_handle bus;
{
bus->needs_explore = 1;
+#if defined(__FreeBSD__)
+ /* This part should be deleted when kthreads is available */
+ selwakeup(&bus->usbctl->sc_consel);
+#endif
wakeup(&bus->needs_explore);
}
@@ -559,40 +639,66 @@ usb_get_next_event(ue)
}
void
-usbd_add_event(type, devh)
+usbd_add_dev_event(type, udev)
+ int type;
+ usbd_device_handle udev;
+{
+ struct usb_event ue;
+
+ usbd_fill_deviceinfo(udev, &ue.u.ue_device);
+ usb_add_event(type, &ue);
+}
+
+void
+usbd_add_drv_event(type, udev, dev)
int type;
- usbd_device_handle devh;
+ usbd_device_handle udev;
+ device_ptr_t dev;
+{
+ struct usb_event ue;
+
+ ue.u.ue_driver.ue_cookie = udev->cookie;
+ strncpy(ue.u.ue_driver.ue_devname, USBDEVPTRNAME(dev),
+ sizeof ue.u.ue_driver.ue_devname);
+ usb_add_event(type, &ue);
+}
+
+void
+usb_add_event(type, uep)
+ int type;
+ struct usb_event *uep;
{
struct usb_event_q *ueq;
struct usb_event ue;
struct timeval thetime;
int s;
+ microtime(&thetime);
+ /* Don't want to wait here inside splusb() */
+ ueq = malloc(sizeof *ueq, M_USBDEV, M_WAITOK);
+ ueq->ue = *uep;
+ ueq->ue.ue_type = type;
+ TIMEVAL_TO_TIMESPEC(&thetime, &ueq->ue.ue_time);
+
s = splusb();
if (++usb_nevents >= USB_MAX_EVENTS) {
/* Too many queued events, drop an old one. */
DPRINTFN(-1,("usb: event dropped\n"));
(void)usb_get_next_event(&ue);
}
- /* Don't want to wait here inside splusb() */
- ueq = malloc(sizeof *ueq, M_USBDEV, M_NOWAIT);
- if (ueq == 0) {
- printf("usb: no memory, event dropped\n");
- splx(s);
- return;
- }
- ueq->ue.ue_type = type;
- ueq->ue.ue_cookie = devh->cookie;
- usbd_fill_deviceinfo(devh, &ueq->ue.ue_device);
- microtime(&thetime);
- TIMEVAL_TO_TIMESPEC(&thetime, &ueq->ue.ue_time);
SIMPLEQ_INSERT_TAIL(&usb_events, ueq, next);
wakeup(&usb_events);
selwakeup(&usb_selevent);
- if (usb_async_proc)
+ if (usb_async_proc != NULL)
psignal(usb_async_proc, SIGIO);
splx(s);
}
+void
+usb_schedsoftintr(bus)
+ struct usbd_bus *bus;
+{
+ bus->methods->soft_intr(bus);
+}
#if defined(__NetBSD__) || defined(__OpenBSD__)
int
@@ -626,6 +732,7 @@ usb_detach(self, flags)
int flags;
{
struct usb_softc *sc = (struct usb_softc *)self;
+ struct usb_event ue;
DPRINTF(("usb_detach: start\n"));
@@ -645,6 +752,10 @@ usb_detach(self, flags)
}
usbd_finish();
+
+ ue.u.ue_ctrlr.ue_bus = USBDEVUNIT(sc->sc_dev);
+ usb_add_event(USB_EVENT_CTRLR_DETACH, &ue);
+
return (0);
}
#elif defined(__FreeBSD__)