usb: rework attach/detach workflow

Add separate detach callback to USBPortOps, split
uhci/ohci/musb/usbhub attach functions into two.

Move common code to the usb_attach() function, only
the hardware-specific bits remain in the attach/detach
callbacks.

Keep track of the port it is attached to for each usb device.

[ v3: fix tyops in usb-musb.c ]

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
Gerd Hoffmann 2010-12-01 11:27:05 +01:00
parent 0d86d2bebb
commit 618c169b57
6 changed files with 124 additions and 135 deletions

View File

@ -218,37 +218,30 @@ static const uint8_t qemu_hub_hub_descriptor[] =
/* DeviceRemovable and PortPwrCtrlMask patched in later */
};
static void usb_hub_attach(USBPort *port1, USBDevice *dev)
static void usb_hub_attach(USBPort *port1)
{
USBHubState *s = port1->opaque;
USBHubPort *port = &s->ports[port1->index];
if (dev) {
if (port->port.dev)
usb_attach(port1, NULL);
port->wPortStatus |= PORT_STAT_CONNECTION;
port->wPortChange |= PORT_STAT_C_CONNECTION;
if (dev->speed == USB_SPEED_LOW)
port->wPortStatus |= PORT_STAT_LOW_SPEED;
else
port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
port->port.dev = dev;
/* send the attach message */
usb_send_msg(dev, USB_MSG_ATTACH);
port->wPortStatus |= PORT_STAT_CONNECTION;
port->wPortChange |= PORT_STAT_C_CONNECTION;
if (port->port.dev->speed == USB_SPEED_LOW) {
port->wPortStatus |= PORT_STAT_LOW_SPEED;
} else {
dev = port->port.dev;
if (dev) {
port->wPortStatus &= ~PORT_STAT_CONNECTION;
port->wPortChange |= PORT_STAT_C_CONNECTION;
if (port->wPortStatus & PORT_STAT_ENABLE) {
port->wPortStatus &= ~PORT_STAT_ENABLE;
port->wPortChange |= PORT_STAT_C_ENABLE;
}
/* send the detach message */
usb_send_msg(dev, USB_MSG_DETACH);
port->port.dev = NULL;
}
port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
}
}
static void usb_hub_detach(USBPort *port1)
{
USBHubState *s = port1->opaque;
USBHubPort *port = &s->ports[port1->index];
port->wPortStatus &= ~PORT_STAT_CONNECTION;
port->wPortChange |= PORT_STAT_C_CONNECTION;
if (port->wPortStatus & PORT_STAT_ENABLE) {
port->wPortStatus &= ~PORT_STAT_ENABLE;
port->wPortChange |= PORT_STAT_C_ENABLE;
}
}
@ -508,6 +501,7 @@ static void usb_hub_handle_destroy(USBDevice *dev)
static USBPortOps usb_hub_port_ops = {
.attach = usb_hub_attach,
.detach = usb_hub_detach,
};
static int usb_hub_initfn(USBDevice *dev)

View File

@ -259,10 +259,12 @@
#endif
static void musb_attach(USBPort *port, USBDevice *dev);
static void musb_attach(USBPort *port);
static void musb_detach(USBPort *port);
static USBPortOps musb_port_ops = {
.attach = musb_attach,
.detach = musb_detach,
};
typedef struct {
@ -464,34 +466,20 @@ static void musb_session_update(MUSBState *s, int prev_dev, int prev_sess)
}
/* Attach or detach a device on our only port. */
static void musb_attach(USBPort *port, USBDevice *dev)
static void musb_attach(USBPort *port)
{
MUSBState *s = (MUSBState *) port->opaque;
USBDevice *curr;
port = &s->port;
curr = port->dev;
musb_intr_set(s, musb_irq_vbus_request, 1);
musb_session_update(s, 0, s->session);
}
if (dev) {
if (curr) {
usb_attach(port, NULL);
/* TODO: signal some interrupts */
}
static void musb_detach(USBPort *port)
{
MUSBState *s = (MUSBState *) port->opaque;
musb_intr_set(s, musb_irq_vbus_request, 1);
/* Send the attach message to device */
usb_send_msg(dev, USB_MSG_ATTACH);
} else if (curr) {
/* Send the detach message */
usb_send_msg(curr, USB_MSG_DETACH);
musb_intr_set(s, musb_irq_disconnect, 1);
}
port->dev = dev;
musb_session_update(s, !!curr, s->session);
musb_intr_set(s, musb_irq_disconnect, 1);
musb_session_update(s, 1, s->session);
}
static inline void musb_cb_tick0(void *opaque)

View File

@ -322,52 +322,46 @@ static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
}
/* Attach or detach a device on a root hub port. */
static void ohci_attach(USBPort *port1, USBDevice *dev)
static void ohci_attach(USBPort *port1)
{
OHCIState *s = port1->opaque;
OHCIPort *port = &s->rhport[port1->index];
/* set connect status */
port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
/* update speed */
if (port->port.dev->speed == USB_SPEED_LOW) {
port->ctrl |= OHCI_PORT_LSDA;
} else {
port->ctrl &= ~OHCI_PORT_LSDA;
}
/* notify of remote-wakeup */
if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
ohci_set_interrupt(s, OHCI_INTR_RD);
}
DPRINTF("usb-ohci: Attached port %d\n", port1->index);
}
static void ohci_detach(USBPort *port1)
{
OHCIState *s = port1->opaque;
OHCIPort *port = &s->rhport[port1->index];
uint32_t old_state = port->ctrl;
if (dev) {
if (port->port.dev) {
usb_attach(port1, NULL);
}
/* set connect status */
port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
/* update speed */
if (dev->speed == USB_SPEED_LOW)
port->ctrl |= OHCI_PORT_LSDA;
else
port->ctrl &= ~OHCI_PORT_LSDA;
port->port.dev = dev;
/* notify of remote-wakeup */
if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND)
ohci_set_interrupt(s, OHCI_INTR_RD);
/* send the attach message */
usb_send_msg(dev, USB_MSG_ATTACH);
DPRINTF("usb-ohci: Attached port %d\n", port1->index);
} else {
/* set connect status */
if (port->ctrl & OHCI_PORT_CCS) {
port->ctrl &= ~OHCI_PORT_CCS;
port->ctrl |= OHCI_PORT_CSC;
}
/* disable port */
if (port->ctrl & OHCI_PORT_PES) {
port->ctrl &= ~OHCI_PORT_PES;
port->ctrl |= OHCI_PORT_PESC;
}
dev = port->port.dev;
if (dev) {
/* send the detach message */
usb_send_msg(dev, USB_MSG_DETACH);
}
port->port.dev = NULL;
DPRINTF("usb-ohci: Detached port %d\n", port1->index);
/* set connect status */
if (port->ctrl & OHCI_PORT_CCS) {
port->ctrl &= ~OHCI_PORT_CCS;
port->ctrl |= OHCI_PORT_CSC;
}
/* disable port */
if (port->ctrl & OHCI_PORT_PES) {
port->ctrl &= ~OHCI_PORT_PES;
port->ctrl |= OHCI_PORT_PESC;
}
DPRINTF("usb-ohci: Detached port %d\n", port1->index);
if (old_state != port->ctrl)
ohci_set_interrupt(s, OHCI_INTR_RHSC);
@ -413,8 +407,9 @@ static void ohci_reset(void *opaque)
{
port = &ohci->rhport[i];
port->ctrl = 0;
if (port->port.dev)
ohci_attach(&port->port, port->port.dev);
if (port->port.dev) {
usb_attach(&port->port, port->port.dev);
}
}
if (ohci->async_td) {
usb_cancel_packet(&ohci->usb_packet);
@ -1671,6 +1666,7 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={
static USBPortOps ohci_port_ops = {
.attach = ohci_attach,
.detach = ohci_detach,
};
static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,

View File

@ -307,8 +307,6 @@ static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token
return match;
}
static void uhci_attach(USBPort *port1, USBDevice *dev);
static void uhci_update_irq(UHCIState *s)
{
int level;
@ -348,8 +346,9 @@ static void uhci_reset(void *opaque)
for(i = 0; i < NB_PORTS; i++) {
port = &s->ports[i];
port->ctrl = 0x0080;
if (port->port.dev)
uhci_attach(&port->port, port->port.dev);
if (port->port.dev) {
usb_attach(&port->port, port->port.dev);
}
}
uhci_async_cancel_all(s);
@ -593,50 +592,41 @@ static void uhci_resume (void *opaque)
}
}
static void uhci_attach(USBPort *port1, USBDevice *dev)
static void uhci_attach(USBPort *port1)
{
UHCIState *s = port1->opaque;
UHCIPort *port = &s->ports[port1->index];
if (dev) {
if (port->port.dev) {
usb_attach(port1, NULL);
}
/* set connect status */
port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
/* set connect status */
port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
/* update speed */
if (dev->speed == USB_SPEED_LOW)
port->ctrl |= UHCI_PORT_LSDA;
else
port->ctrl &= ~UHCI_PORT_LSDA;
uhci_resume(s);
port->port.dev = dev;
/* send the attach message */
usb_send_msg(dev, USB_MSG_ATTACH);
/* update speed */
if (port->port.dev->speed == USB_SPEED_LOW) {
port->ctrl |= UHCI_PORT_LSDA;
} else {
/* set connect status */
if (port->ctrl & UHCI_PORT_CCS) {
port->ctrl &= ~UHCI_PORT_CCS;
port->ctrl |= UHCI_PORT_CSC;
}
/* disable port */
if (port->ctrl & UHCI_PORT_EN) {
port->ctrl &= ~UHCI_PORT_EN;
port->ctrl |= UHCI_PORT_ENC;
}
uhci_resume(s);
dev = port->port.dev;
if (dev) {
/* send the detach message */
usb_send_msg(dev, USB_MSG_DETACH);
}
port->port.dev = NULL;
port->ctrl &= ~UHCI_PORT_LSDA;
}
uhci_resume(s);
}
static void uhci_detach(USBPort *port1)
{
UHCIState *s = port1->opaque;
UHCIPort *port = &s->ports[port1->index];
/* set connect status */
if (port->ctrl & UHCI_PORT_CCS) {
port->ctrl &= ~UHCI_PORT_CCS;
port->ctrl |= UHCI_PORT_CSC;
}
/* disable port */
if (port->ctrl & UHCI_PORT_EN) {
port->ctrl &= ~UHCI_PORT_EN;
port->ctrl |= UHCI_PORT_ENC;
}
uhci_resume(s);
}
static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
@ -1103,6 +1093,7 @@ static void uhci_map(PCIDevice *pci_dev, int region_num,
static USBPortOps uhci_port_ops = {
.attach = uhci_attach,
.detach = uhci_detach,
};
static int usb_uhci_common_initfn(UHCIState *s)

View File

@ -28,7 +28,25 @@
void usb_attach(USBPort *port, USBDevice *dev)
{
port->ops->attach(port, dev);
if (dev != NULL) {
/* attach */
if (port->dev) {
usb_attach(port, NULL);
}
dev->port = port;
port->dev = dev;
port->ops->attach(port);
usb_send_msg(dev, USB_MSG_ATTACH);
} else {
/* detach */
dev = port->dev;
port->ops->detach(port);
if (dev) {
usb_send_msg(dev, USB_MSG_DETACH);
dev->port = NULL;
port->dev = NULL;
}
}
}
/**********************/

View File

@ -147,6 +147,7 @@ struct USBDescString {
struct USBDevice {
DeviceState qdev;
USBDeviceInfo *info;
USBPort *port;
void *opaque;
int speed;
@ -217,7 +218,8 @@ struct USBDeviceInfo {
};
typedef struct USBPortOps {
void (*attach)(USBPort *port, USBDevice *dev);
void (*attach)(USBPort *port);
void (*detach)(USBPort *port);
} USBPortOps;
/* USB port on which a device can be connected */