Add preliminary (untested) code for detaching the USB host controller

(needed for CardBus based controllers).
This commit is contained in:
augustss 1999-09-15 10:25:30 +00:00
parent f7c22e9eaa
commit 7049e8eb1b
11 changed files with 238 additions and 141 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ohci_pci.c,v 1.12 1999/09/14 01:07:13 augustss Exp $ */
/* $NetBSD: ohci_pci.c,v 1.13 1999/09/15 10:25:30 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -67,7 +67,8 @@ int ohci_pci_match __P((struct device *, struct cfdata *, void *));
void ohci_pci_attach __P((struct device *, struct device *, void *));
struct cfattach ohci_pci_ca = {
sizeof(struct ohci_softc), ohci_pci_match, ohci_pci_attach
sizeof(struct ohci_softc), ohci_pci_match, ohci_pci_attach,
ohci_detach, ohci_activate
};
int
@ -157,5 +158,5 @@ ohci_pci_attach(parent, self, aux)
}
/* Attach usb device. */
config_found((void *)sc, &sc->sc_bus, usbctlprint);
sc->sc_child = config_found((void *)sc, &sc->sc_bus, usbctlprint);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: uhci_pci.c,v 1.10 1999/09/14 09:29:05 augustss Exp $ */
/* $NetBSD: uhci_pci.c,v 1.11 1999/09/15 10:25:30 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -60,7 +60,8 @@ int uhci_pci_match __P((struct device *, struct cfdata *, void *));
void uhci_pci_attach __P((struct device *, struct device *, void *));
struct cfattach uhci_pci_ca = {
sizeof(uhci_softc_t), uhci_pci_match, uhci_pci_attach
sizeof(uhci_softc_t), uhci_pci_match, uhci_pci_attach,
uhci_detach, uhci_activate
};
int
@ -163,5 +164,5 @@ uhci_pci_attach(parent, self, aux)
}
/* Attach usb device. */
config_found((void *)sc, &sc->sc_bus, usbctlprint);
sc->sc_child = config_found((void *)sc, &sc->sc_bus, usbctlprint);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ohci.c,v 1.46 1999/09/13 21:33:25 augustss Exp $ */
/* $NetBSD: ohci.c,v 1.47 1999/09/15 10:25:31 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -283,6 +283,45 @@ struct usbd_pipe_methods ohci_device_isoc_methods = {
};
#endif
int
ohci_activate(self, act)
device_ptr_t self;
enum devact act;
{
/*struct ohci_softc *sc = (struct ohci_softc *)self;*/
int rv = 0;
switch (act) {
case DVACT_ACTIVATE:
return (EOPNOTSUPP);
break;
case DVACT_DEACTIVATE:
break;
}
return (rv);
}
int
ohci_detach(self, flags)
device_ptr_t self;
int flags;
{
struct ohci_softc *sc = (struct ohci_softc *)self;
int rv = 0;
if (sc->sc_child != NULL)
rv = config_detach(sc->sc_child, flags);
if (rv != 0)
return (rv);
powerhook_disestablish(sc->sc_powerhook);
/* free data structures XXX */
return (rv);
}
ohci_soft_ed_t *
ohci_alloc_sed(sc)
ohci_softc_t *sc;
@ -539,7 +578,7 @@ ohci_init(sc)
sc->sc_bus.methods = &ohci_bus_methods;
sc->sc_bus.pipe_size = sizeof(struct ohci_pipe);
powerhook_establish(ohci_power, sc);
sc->sc_powerhook = powerhook_establish(ohci_power, sc);
return (USBD_NORMAL_COMPLETION);

View File

@ -1,4 +1,4 @@
/* $NetBSD: ohcivar.h,v 1.9 1999/09/13 19:18:17 augustss Exp $ */
/* $NetBSD: ohcivar.h,v 1.10 1999/09/15 10:25:31 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -96,10 +96,15 @@ typedef struct ohci_softc {
char sc_vendor[16];
int sc_id_vendor;
void *sc_powerhook;
device_ptr_t sc_child;
} ohci_softc_t;
usbd_status ohci_init __P((ohci_softc_t *));
int ohci_intr __P((void *));
int ohci_detach __P((device_ptr_t, int));
int ohci_activate __P((device_ptr_t, enum devact));
#define MS_TO_TICKS(ms) ((ms) * hz / 1000)

View File

@ -1,4 +1,4 @@
/* $NetBSD: uhci.c,v 1.52 1999/09/13 21:33:25 augustss Exp $ */
/* $NetBSD: uhci.c,v 1.53 1999/09/15 10:25:31 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -407,7 +407,7 @@ uhci_init(sc)
sc->sc_bus.pipe_size = sizeof(struct uhci_pipe);
sc->sc_suspend = PWR_RESUME;
powerhook_establish(uhci_power, sc);
sc->sc_powerhook = powerhook_establish(uhci_power, sc);
DPRINTFN(1,("uhci_init: enabling\n"));
UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
@ -416,6 +416,45 @@ uhci_init(sc)
return (uhci_run(sc, 1)); /* and here we go... */
}
int
uhci_activate(self, act)
device_ptr_t self;
enum devact act;
{
/*struct uhci_softc *sc = (struct uhci_softc *)self;*/
int rv = 0;
switch (act) {
case DVACT_ACTIVATE:
return (EOPNOTSUPP);
break;
case DVACT_DEACTIVATE:
break;
}
return (rv);
}
int
uhci_detach(self, flags)
device_ptr_t self;
int flags;
{
struct uhci_softc *sc = (struct uhci_softc *)self;
int rv = 0;
if (sc->sc_child != NULL)
rv = config_detach(sc->sc_child, flags);
if (rv != 0)
return (rv);
powerhook_disestablish(sc->sc_powerhook);
/* free data structures XXX */
return (rv);
}
usbd_status
uhci_allocm(bus, dma, size)
struct usbd_bus *bus;

View File

@ -1,4 +1,4 @@
/* $NetBSD: uhcivar.h,v 1.13 1999/09/13 19:18:17 augustss Exp $ */
/* $NetBSD: uhcivar.h,v 1.14 1999/09/15 10:25:31 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -166,13 +166,15 @@ typedef struct uhci_softc {
char sc_vendor[16];
int sc_id_vendor;
void *sc_powerhook;
device_ptr_t sc_child;
} uhci_softc_t;
usbd_status uhci_init __P((uhci_softc_t *));
int uhci_intr __P((void *));
#if 0
void uhci_reset __P((void *));
#endif
int uhci_detach __P((device_ptr_t, int));
int uhci_activate __P((device_ptr_t, enum devact));
#ifdef USB_DEBUG
#define DPRINTF(x) if (uhcidebug) printf x

View File

@ -1,4 +1,4 @@
/* $NetBSD: uhub.c,v 1.28 1999/09/13 19:18:17 augustss Exp $ */
/* $NetBSD: uhub.c,v 1.29 1999/09/15 10:25:31 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -78,7 +78,6 @@ struct uhub_softc {
};
usbd_status uhub_init_port __P((struct usbd_port *));
void uhub_disconnect_port __P((struct usbd_port *up));
usbd_status uhub_explore __P((usbd_device_handle hub));
void uhub_intr __P((usbd_request_handle, usbd_private_handle, usbd_status));
@ -377,7 +376,7 @@ uhub_explore(dev)
DPRINTF(("uhub_explore: device %d disappeared "
"on port %d\n",
up->device->address, port));
uhub_disconnect_port(up);
usb_disconnect_port(up);
usbd_clear_port_feature(dev, port,
UHF_C_PORT_CONNECTION);
}
@ -432,62 +431,6 @@ uhub_explore(dev)
return (USBD_NORMAL_COMPLETION);
}
/*
* The general mechanism for detaching drivers works as follows: Each
* driver is responsible for maintaining a reference count on the
* number of outstanding references to its softc (e.g. from
* processing hanging in a read or write). The detach method of the
* driver decrements this counter and flags in the softc that the
* driver is dying and then wakes any sleepers. It then sleeps on the
* softc. Each place that can sleep must maintain the reference
* count. When the reference count drops to -1 (0 is the normal value
* of the reference count) the a wakeup on the softc is performed
* signaling to the detach waiter that all references are gone.
*/
/*
* Called from process context when we discover that a port has
* been disconnected.
*/
void
uhub_disconnect_port(up)
struct usbd_port *up;
{
usbd_device_handle dev = up->device;
char *hubname;
int i;
DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n",
up, dev, up->portno));
if (!dev->cdesc) {
/* Partially attached device, just drop it. */
dev->bus->devices[dev->address] = 0;
up->device = 0;
return;
}
if (dev->subdevs) {
hubname = USBDEVPTRNAME(up->parent->subdevs[0]);
for (i = 0; dev->subdevs[i]; i++) {
printf("%s: at %s port %d (addr %d) disconnected\n",
USBDEVPTRNAME(dev->subdevs[i]), hubname,
up->portno, dev->address);
config_detach(dev->subdevs[i], DETACH_FORCE);
}
}
dev->bus->devices[dev->address] = 0;
up->device = 0;
usb_free_device(dev);
#if defined(__FreeBSD__)
device_delete_child(
device_get_parent(((struct softc *)dev->softc)->sc_dev),
((struct softc *)dev->softc)->sc_dev);
#endif
}
int
uhub_activate(self, act)
device_ptr_t self;
@ -544,7 +487,7 @@ uhub_detach(self, flags)
for(p = 0; p < nports; p++) {
rup = &dev->hub->ports[p];
if (rup->device)
uhub_disconnect_port(rup);
usb_disconnect_port(rup);
}
free(dev->hub, M_USBDEV);

View File

@ -1,4 +1,4 @@
/* $NetBSD: usb.c,v 1.21 1999/09/13 21:33:25 augustss Exp $ */
/* $NetBSD: usb.c,v 1.22 1999/09/15 10:25:31 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -57,6 +57,7 @@
#include <sys/uio.h>
#include <sys/conf.h>
#endif
#include <sys/conf.h>
#include <sys/poll.h>
#include <sys/proc.h>
#include <sys/select.h>
@ -90,25 +91,22 @@ int usb_noexplore = 0;
#define DPRINTFN(n,x)
#endif
int usb_nbus = 0;
#define USBUNIT(dev) (minor(dev))
struct usb_softc {
USBBASEDEVICE sc_dev; /* base device */
usbd_bus_handle sc_bus; /* USB controller */
struct usbd_port sc_port; /* dummy port for root hub */
char sc_running;
char sc_exploring;
char sc_dying;
struct selinfo sc_consel; /* waiting for connect change */
int shutdown;
struct proc *event_thread;
struct proc *sc_event_thread;
};
#if defined(__NetBSD__) || defined(__OpenBSD__)
int usbopen __P((dev_t, int, int, struct proc *));
int usbclose __P((dev_t, int, int, struct proc *));
int usbioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
int usbpoll __P((dev_t, int, struct proc *));
cdev_decl(usb);
#elif defined(__FreeBSD__)
d_open_t usbopen;
d_close_t usbclose;
@ -156,15 +154,15 @@ USB_ATTACH(usb)
usbd_init();
sc->sc_bus = aux;
sc->sc_bus->usbctl = sc;
sc->sc_running = 1;
sc->sc_bus->use_polling = 1;
sc->sc_port.power = USB_MAX_POWER;
r = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0,0,0, &sc->sc_port);
r = usbd_new_device(USBDEV(sc->sc_dev), sc->sc_bus, 0,0,0,
&sc->sc_port);
if (r == USBD_NORMAL_COMPLETION) {
dev = sc->sc_port.device;
if (!dev->hub) {
sc->sc_running = 0;
sc->sc_dying = 1;
printf("%s: root device is not a hub\n",
USBDEVNAME(sc->sc_dev));
USB_ATTACH_ERROR_RETURN;
@ -174,12 +172,13 @@ USB_ATTACH(usb)
} else {
printf("%s: root hub problem, error=%d\n",
USBDEVNAME(sc->sc_dev), r);
sc->sc_running = 0;
sc->sc_dying = 1;
}
sc->sc_bus->use_polling = 0;
kthread_create(usb_create_event_thread, sc);
usb_nbus++;
USB_ATTACH_SUCCESS_RETURN;
}
@ -189,7 +188,7 @@ usb_create_event_thread(arg)
{
struct usb_softc *sc = arg;
if (kthread_create1(usb_event_thread, sc, &sc->event_thread,
if (kthread_create1(usb_event_thread, sc, &sc->sc_event_thread,
"%s", sc->sc_dev.dv_xname)) {
printf("%s: unable to create event thread for\n",
sc->sc_dev.dv_xname);
@ -203,17 +202,16 @@ usb_event_thread(arg)
{
struct usb_softc *sc = arg;
while (!sc->shutdown) {
(void)tsleep(&sc->sc_bus->needs_explore,
PWAIT, "usbevt", hz*30);
while (!sc->sc_dying) {
#ifdef USB_DEBUG
if (usb_noexplore)
continue;
if (!usb_noexplore)
#endif
DPRINTFN(2,("usb_event_thread: woke up\n"));
usb_discover(sc);
(void)tsleep(&sc->sc_bus->needs_explore,
PWAIT, "usbevt", hz*60);
DPRINTFN(2,("usb_event_thread: woke up\n"));
}
sc->event_thread = 0;
sc->sc_event_thread = 0;
/* In case parent is waiting for us to exit. */
wakeup(sc);
@ -243,8 +241,10 @@ usbopen(dev, flag, mode, p)
{
USB_GET_SC_OPEN(usb, USBUNIT(dev), sc);
if (sc == 0 || !sc->sc_running)
if (sc == 0)
return (ENXIO);
if (sc->sc_dying)
return (EIO);
return (0);
}
@ -268,8 +268,9 @@ usbioctl(dev, cmd, data, flag, p)
{
USB_GET_SC(usb, USBUNIT(dev), sc);
if (sc == 0 || !sc->sc_running)
return (ENXIO);
if (sc->sc_dying)
return (EIO);
switch (cmd) {
#ifdef USB_DEBUG
case USB_SETDEBUG:
@ -371,6 +372,9 @@ usbpoll(dev, events, p)
int revents, s;
USB_GET_SC(usb, USBUNIT(dev), sc);
if (sc->sc_dying)
return (EIO);
DPRINTFN(2, ("usbpoll: sc=%p events=0x%x\n", sc, events));
s = splusb();
revents = 0;
@ -388,36 +392,6 @@ usbpoll(dev, events, p)
return (revents);
}
#if 0
int
usb_bus_count()
{
int i, n;
for (i = n = 0; i < usb_cd.cd_ndevs; i++)
if (usb_cd.cd_devs[i])
n++;
return (n);
}
#endif
#if 0
usbd_status
usb_get_bus_handle(n, h)
int n;
usbd_bus_handle *h;
{
int i;
for (i = 0; i < usb_cd.cd_ndevs; i++)
if (usb_cd.cd_devs[i] && n-- == 0) {
*h = usb_cd.cd_devs[i];
return (USBD_NORMAL_COMPLETION);
}
return (USBD_INVAL);
}
#endif
usbd_status
usb_discover(sc)
struct usb_softc *sc;
@ -440,7 +414,7 @@ usb_discover(sc)
sc->sc_exploring = 0;
wakeup(&sc->sc_exploring);
splx(s);
} while (sc->sc_bus->needs_explore);
} while (sc->sc_bus->needs_explore && !sc->sc_dying);
return (USBD_NORMAL_COMPLETION);
}
@ -458,8 +432,19 @@ usb_activate(self, act)
device_ptr_t self;
enum devact act;
{
panic("usb_activate\n");
return (0);
struct usb_softc *sc = (struct usb_softc *)self;
int rv = 0;
switch (act) {
case DVACT_ACTIVATE:
return (EOPNOTSUPP);
break;
case DVACT_DEACTIVATE:
sc->sc_dying = 1;
break;
}
return (rv);
}
int
@ -467,7 +452,32 @@ usb_detach(self, flags)
device_ptr_t self;
int flags;
{
panic("usb_detach\n");
struct usb_softc *sc = (struct usb_softc *)self;
sc->sc_dying = 1;
/* Make all devices disconnect. */
usb_disconnect_port(&sc->sc_port);
/* Kill off event thread. */
if (sc->sc_event_thread) {
wakeup(&sc->sc_bus->needs_explore);
if (tsleep(sc, PWAIT, "usbdet", hz * 60))
printf("%s: event thread didn't die\n",
USBDEVNAME(sc->sc_dev));
}
usb_nbus--;
return (0);
}
int
usbread(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
/* XXX */
return (0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: usb_subr.c,v 1.46 1999/09/13 19:18:17 augustss Exp $ */
/* $NetBSD: usb_subr.c,v 1.47 1999/09/15 10:25:31 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -1169,3 +1169,60 @@ usb_free_device(dev)
free(dev->subdevs, M_USB);
free(dev, M_USB);
}
/*
* The general mechanism for detaching drivers works as follows: Each
* driver is responsible for maintaining a reference count on the
* number of outstanding references to its softc (e.g. from
* processing hanging in a read or write). The detach method of the
* driver decrements this counter and flags in the softc that the
* driver is dying and then wakes any sleepers. It then sleeps on the
* softc. Each place that can sleep must maintain the reference
* count. When the reference count drops to -1 (0 is the normal value
* of the reference count) the a wakeup on the softc is performed
* signaling to the detach waiter that all references are gone.
*/
/*
* Called from process context when we discover that a port has
* been disconnected.
*/
void
usb_disconnect_port(up)
struct usbd_port *up;
{
usbd_device_handle dev = up->device;
char *hubname;
int i;
DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n",
up, dev, up->portno));
if (!dev->cdesc) {
/* Partially attached device, just drop it. */
dev->bus->devices[dev->address] = 0;
up->device = 0;
return;
}
if (dev->subdevs) {
hubname = USBDEVPTRNAME(up->parent->subdevs[0]);
for (i = 0; dev->subdevs[i]; i++) {
printf("%s: at %s port %d (addr %d) disconnected\n",
USBDEVPTRNAME(dev->subdevs[i]), hubname,
up->portno, dev->address);
config_detach(dev->subdevs[i], DETACH_FORCE);
}
}
dev->bus->devices[dev->address] = 0;
up->device = 0;
usb_free_device(dev);
#if defined(__FreeBSD__)
device_delete_child(
device_get_parent(((struct softc *)dev->softc)->sc_dev),
((struct softc *)dev->softc)->sc_dev);
#endif
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: usbdi.c,v 1.40 1999/09/13 21:33:25 augustss Exp $ */
/* $NetBSD: usbdi.c,v 1.41 1999/09/15 10:25:32 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -698,11 +698,10 @@ usbd_ar_pipe(pipe)
return (USBD_NORMAL_COMPLETION);
}
static int usbd_global_init_done = 0;
void
usbd_init()
{
static int usbd_global_init_done = 0;
#if defined(__FreeBSD__)
dev_t dev;
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: usbdivar.h,v 1.33 1999/09/13 21:33:25 augustss Exp $ */
/* $NetBSD: usbdivar.h,v 1.34 1999/09/15 10:25:32 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -216,6 +216,7 @@ void usb_free_device __P((usbd_device_handle));
usbd_status usb_insert_transfer __P((usbd_request_handle reqh));
void usb_transfer_complete __P((usbd_request_handle reqh));
void usb_disconnect_port __P((struct usbd_port *up));
/* Routines from usb.c */
int usb_bus_count __P((void));