mirror of https://gitee.com/openkylin/qemu.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 */
|
||||
};
|
||||
|
||||
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)
|
||||
if (port->port.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);
|
||||
} else {
|
||||
dev = port->port.dev;
|
||||
if (dev) {
|
||||
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;
|
||||
}
|
||||
/* send the detach message */
|
||||
usb_send_msg(dev, USB_MSG_DETACH);
|
||||
port->port.dev = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 = {
|
||||
.attach = usb_hub_attach,
|
||||
.detach = usb_hub_detach,
|
||||
};
|
||||
|
||||
static int usb_hub_initfn(USBDevice *dev)
|
||||
|
|
|
@ -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;
|
||||
|
||||
if (dev) {
|
||||
if (curr) {
|
||||
usb_attach(port, NULL);
|
||||
/* TODO: signal some interrupts */
|
||||
}
|
||||
|
||||
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);
|
||||
musb_session_update(s, 0, s->session);
|
||||
}
|
||||
|
||||
port->dev = dev;
|
||||
static void musb_detach(USBPort *port)
|
||||
{
|
||||
MUSBState *s = (MUSBState *) port->opaque;
|
||||
|
||||
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)
|
||||
|
|
|
@ -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. */
|
||||
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;
|
||||
|
@ -360,14 +361,7 @@ static void ohci_attach(USBPort *port1, USBDevice *dev)
|
|||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -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,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;
|
||||
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;
|
||||
|
||||
/* update speed */
|
||||
if (dev->speed == USB_SPEED_LOW)
|
||||
if (port->port.dev->speed == USB_SPEED_LOW) {
|
||||
port->ctrl |= UHCI_PORT_LSDA;
|
||||
else
|
||||
} else {
|
||||
port->ctrl &= ~UHCI_PORT_LSDA;
|
||||
}
|
||||
|
||||
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 */
|
||||
if (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);
|
||||
|
||||
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)
|
||||
|
@ -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)
|
||||
|
|
20
hw/usb.c
20
hw/usb.c
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************/
|
||||
|
|
4
hw/usb.h
4
hw/usb.h
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue