mirror of https://github.com/xqemu/xqemu.git
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:
parent
0d86d2bebb
commit
618c169b57
30
hw/usb-hub.c
30
hw/usb-hub.c
|
@ -218,38 +218,31 @@ static const uint8_t qemu_hub_hub_descriptor[] =
|
||||||
/* DeviceRemovable and PortPwrCtrlMask patched in later */
|
/* 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;
|
USBHubState *s = port1->opaque;
|
||||||
USBHubPort *port = &s->ports[port1->index];
|
USBHubPort *port = &s->ports[port1->index];
|
||||||
|
|
||||||
if (dev) {
|
|
||||||
if (port->port.dev)
|
|
||||||
usb_attach(port1, NULL);
|
|
||||||
|
|
||||||
port->wPortStatus |= PORT_STAT_CONNECTION;
|
port->wPortStatus |= PORT_STAT_CONNECTION;
|
||||||
port->wPortChange |= PORT_STAT_C_CONNECTION;
|
port->wPortChange |= PORT_STAT_C_CONNECTION;
|
||||||
if (dev->speed == USB_SPEED_LOW)
|
if (port->port.dev->speed == USB_SPEED_LOW) {
|
||||||
port->wPortStatus |= PORT_STAT_LOW_SPEED;
|
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);
|
|
||||||
} else {
|
} else {
|
||||||
dev = port->port.dev;
|
port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
|
||||||
if (dev) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_hub_detach(USBPort *port1)
|
||||||
|
{
|
||||||
|
USBHubState *s = port1->opaque;
|
||||||
|
USBHubPort *port = &s->ports[port1->index];
|
||||||
|
|
||||||
port->wPortStatus &= ~PORT_STAT_CONNECTION;
|
port->wPortStatus &= ~PORT_STAT_CONNECTION;
|
||||||
port->wPortChange |= PORT_STAT_C_CONNECTION;
|
port->wPortChange |= PORT_STAT_C_CONNECTION;
|
||||||
if (port->wPortStatus & PORT_STAT_ENABLE) {
|
if (port->wPortStatus & PORT_STAT_ENABLE) {
|
||||||
port->wPortStatus &= ~PORT_STAT_ENABLE;
|
port->wPortStatus &= ~PORT_STAT_ENABLE;
|
||||||
port->wPortChange |= PORT_STAT_C_ENABLE;
|
port->wPortChange |= PORT_STAT_C_ENABLE;
|
||||||
}
|
}
|
||||||
/* send the detach message */
|
|
||||||
usb_send_msg(dev, USB_MSG_DETACH);
|
|
||||||
port->port.dev = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_hub_handle_reset(USBDevice *dev)
|
static void usb_hub_handle_reset(USBDevice *dev)
|
||||||
|
@ -508,6 +501,7 @@ static void usb_hub_handle_destroy(USBDevice *dev)
|
||||||
|
|
||||||
static USBPortOps usb_hub_port_ops = {
|
static USBPortOps usb_hub_port_ops = {
|
||||||
.attach = usb_hub_attach,
|
.attach = usb_hub_attach,
|
||||||
|
.detach = usb_hub_detach,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int usb_hub_initfn(USBDevice *dev)
|
static int usb_hub_initfn(USBDevice *dev)
|
||||||
|
|
|
@ -259,10 +259,12 @@
|
||||||
#endif
|
#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 = {
|
static USBPortOps musb_port_ops = {
|
||||||
.attach = musb_attach,
|
.attach = musb_attach,
|
||||||
|
.detach = musb_detach,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
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. */
|
/* 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;
|
MUSBState *s = (MUSBState *) port->opaque;
|
||||||
USBDevice *curr;
|
|
||||||
|
|
||||||
port = &s->port;
|
|
||||||
curr = port->dev;
|
|
||||||
|
|
||||||
if (dev) {
|
|
||||||
if (curr) {
|
|
||||||
usb_attach(port, NULL);
|
|
||||||
/* TODO: signal some interrupts */
|
|
||||||
}
|
|
||||||
|
|
||||||
musb_intr_set(s, musb_irq_vbus_request, 1);
|
musb_intr_set(s, musb_irq_vbus_request, 1);
|
||||||
|
musb_session_update(s, 0, s->session);
|
||||||
|
}
|
||||||
|
|
||||||
/* Send the attach message to device */
|
static void musb_detach(USBPort *port)
|
||||||
usb_send_msg(dev, USB_MSG_ATTACH);
|
{
|
||||||
} else if (curr) {
|
MUSBState *s = (MUSBState *) port->opaque;
|
||||||
/* Send the detach message */
|
|
||||||
usb_send_msg(curr, USB_MSG_DETACH);
|
|
||||||
|
|
||||||
musb_intr_set(s, musb_irq_disconnect, 1);
|
musb_intr_set(s, musb_irq_disconnect, 1);
|
||||||
}
|
musb_session_update(s, 1, s->session);
|
||||||
|
|
||||||
port->dev = dev;
|
|
||||||
|
|
||||||
musb_session_update(s, !!curr, s->session);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void musb_cb_tick0(void *opaque)
|
static inline void musb_cb_tick0(void *opaque)
|
||||||
|
|
|
@ -322,34 +322,35 @@ static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attach or detach a device on a root hub port. */
|
/* 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;
|
OHCIState *s = port1->opaque;
|
||||||
OHCIPort *port = &s->rhport[port1->index];
|
OHCIPort *port = &s->rhport[port1->index];
|
||||||
uint32_t old_state = port->ctrl;
|
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 */
|
/* set connect status */
|
||||||
if (port->ctrl & OHCI_PORT_CCS) {
|
if (port->ctrl & OHCI_PORT_CCS) {
|
||||||
port->ctrl &= ~OHCI_PORT_CCS;
|
port->ctrl &= ~OHCI_PORT_CCS;
|
||||||
|
@ -360,14 +361,7 @@ static void ohci_attach(USBPort *port1, USBDevice *dev)
|
||||||
port->ctrl &= ~OHCI_PORT_PES;
|
port->ctrl &= ~OHCI_PORT_PES;
|
||||||
port->ctrl |= OHCI_PORT_PESC;
|
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);
|
DPRINTF("usb-ohci: Detached port %d\n", port1->index);
|
||||||
}
|
|
||||||
|
|
||||||
if (old_state != port->ctrl)
|
if (old_state != port->ctrl)
|
||||||
ohci_set_interrupt(s, OHCI_INTR_RHSC);
|
ohci_set_interrupt(s, OHCI_INTR_RHSC);
|
||||||
|
@ -413,8 +407,9 @@ static void ohci_reset(void *opaque)
|
||||||
{
|
{
|
||||||
port = &ohci->rhport[i];
|
port = &ohci->rhport[i];
|
||||||
port->ctrl = 0;
|
port->ctrl = 0;
|
||||||
if (port->port.dev)
|
if (port->port.dev) {
|
||||||
ohci_attach(&port->port, port->port.dev);
|
usb_attach(&port->port, port->port.dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ohci->async_td) {
|
if (ohci->async_td) {
|
||||||
usb_cancel_packet(&ohci->usb_packet);
|
usb_cancel_packet(&ohci->usb_packet);
|
||||||
|
@ -1671,6 +1666,7 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={
|
||||||
|
|
||||||
static USBPortOps ohci_port_ops = {
|
static USBPortOps ohci_port_ops = {
|
||||||
.attach = ohci_attach,
|
.attach = ohci_attach,
|
||||||
|
.detach = ohci_detach,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
|
static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
|
||||||
|
|
|
@ -307,8 +307,6 @@ static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uhci_attach(USBPort *port1, USBDevice *dev);
|
|
||||||
|
|
||||||
static void uhci_update_irq(UHCIState *s)
|
static void uhci_update_irq(UHCIState *s)
|
||||||
{
|
{
|
||||||
int level;
|
int level;
|
||||||
|
@ -348,8 +346,9 @@ static void uhci_reset(void *opaque)
|
||||||
for(i = 0; i < NB_PORTS; i++) {
|
for(i = 0; i < NB_PORTS; i++) {
|
||||||
port = &s->ports[i];
|
port = &s->ports[i];
|
||||||
port->ctrl = 0x0080;
|
port->ctrl = 0x0080;
|
||||||
if (port->port.dev)
|
if (port->port.dev) {
|
||||||
uhci_attach(&port->port, port->port.dev);
|
usb_attach(&port->port, port->port.dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uhci_async_cancel_all(s);
|
uhci_async_cancel_all(s);
|
||||||
|
@ -593,30 +592,29 @@ static void uhci_resume (void *opaque)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uhci_attach(USBPort *port1, USBDevice *dev)
|
static void uhci_attach(USBPort *port1)
|
||||||
{
|
{
|
||||||
UHCIState *s = port1->opaque;
|
UHCIState *s = port1->opaque;
|
||||||
UHCIPort *port = &s->ports[port1->index];
|
UHCIPort *port = &s->ports[port1->index];
|
||||||
|
|
||||||
if (dev) {
|
|
||||||
if (port->port.dev) {
|
|
||||||
usb_attach(port1, NULL);
|
|
||||||
}
|
|
||||||
/* set connect status */
|
/* set connect status */
|
||||||
port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
|
port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
|
||||||
|
|
||||||
/* update speed */
|
/* update speed */
|
||||||
if (dev->speed == USB_SPEED_LOW)
|
if (port->port.dev->speed == USB_SPEED_LOW) {
|
||||||
port->ctrl |= UHCI_PORT_LSDA;
|
port->ctrl |= UHCI_PORT_LSDA;
|
||||||
else
|
} else {
|
||||||
port->ctrl &= ~UHCI_PORT_LSDA;
|
port->ctrl &= ~UHCI_PORT_LSDA;
|
||||||
|
}
|
||||||
|
|
||||||
uhci_resume(s);
|
uhci_resume(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uhci_detach(USBPort *port1)
|
||||||
|
{
|
||||||
|
UHCIState *s = port1->opaque;
|
||||||
|
UHCIPort *port = &s->ports[port1->index];
|
||||||
|
|
||||||
port->port.dev = dev;
|
|
||||||
/* send the attach message */
|
|
||||||
usb_send_msg(dev, USB_MSG_ATTACH);
|
|
||||||
} else {
|
|
||||||
/* set connect status */
|
/* set connect status */
|
||||||
if (port->ctrl & UHCI_PORT_CCS) {
|
if (port->ctrl & UHCI_PORT_CCS) {
|
||||||
port->ctrl &= ~UHCI_PORT_CCS;
|
port->ctrl &= ~UHCI_PORT_CCS;
|
||||||
|
@ -629,14 +627,6 @@ static void uhci_attach(USBPort *port1, USBDevice *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
uhci_resume(s);
|
uhci_resume(s);
|
||||||
|
|
||||||
dev = port->port.dev;
|
|
||||||
if (dev) {
|
|
||||||
/* send the detach message */
|
|
||||||
usb_send_msg(dev, USB_MSG_DETACH);
|
|
||||||
}
|
|
||||||
port->port.dev = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
|
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 = {
|
static USBPortOps uhci_port_ops = {
|
||||||
.attach = uhci_attach,
|
.attach = uhci_attach,
|
||||||
|
.detach = uhci_detach,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int usb_uhci_common_initfn(UHCIState *s)
|
static int usb_uhci_common_initfn(UHCIState *s)
|
||||||
|
|
20
hw/usb.c
20
hw/usb.c
|
@ -28,7 +28,25 @@
|
||||||
|
|
||||||
void usb_attach(USBPort *port, USBDevice *dev)
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************/
|
/**********************/
|
||||||
|
|
4
hw/usb.h
4
hw/usb.h
|
@ -147,6 +147,7 @@ struct USBDescString {
|
||||||
struct USBDevice {
|
struct USBDevice {
|
||||||
DeviceState qdev;
|
DeviceState qdev;
|
||||||
USBDeviceInfo *info;
|
USBDeviceInfo *info;
|
||||||
|
USBPort *port;
|
||||||
void *opaque;
|
void *opaque;
|
||||||
|
|
||||||
int speed;
|
int speed;
|
||||||
|
@ -217,7 +218,8 @@ struct USBDeviceInfo {
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct USBPortOps {
|
typedef struct USBPortOps {
|
||||||
void (*attach)(USBPort *port, USBDevice *dev);
|
void (*attach)(USBPort *port);
|
||||||
|
void (*detach)(USBPort *port);
|
||||||
} USBPortOps;
|
} USBPortOps;
|
||||||
|
|
||||||
/* USB port on which a device can be connected */
|
/* USB port on which a device can be connected */
|
||||||
|
|
Loading…
Reference in New Issue