summaryrefslogtreecommitdiff
path: root/hw/usb-uhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/usb-uhci.c')
-rw-r--r--hw/usb-uhci.c98
1 files changed, 57 insertions, 41 deletions
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index b9b822fcb1..b384e1ddec 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -57,13 +57,18 @@
#define TD_CTRL_NAK (1 << 19)
#define TD_CTRL_TIMEOUT (1 << 18)
+#define UHCI_PORT_SUSPEND (1 << 12)
#define UHCI_PORT_RESET (1 << 9)
#define UHCI_PORT_LSDA (1 << 8)
+#define UHCI_PORT_RD (1 << 6)
#define UHCI_PORT_ENC (1 << 3)
#define UHCI_PORT_EN (1 << 2)
#define UHCI_PORT_CSC (1 << 1)
#define UHCI_PORT_CCS (1 << 0)
+#define UHCI_PORT_READ_ONLY (0x1bb)
+#define UHCI_PORT_WRITE_CLEAR (UHCI_PORT_CSC | UHCI_PORT_ENC)
+
#define FRAME_TIMER_FREQ 1000
#define FRAME_MAX_LOOPS 100
@@ -307,8 +312,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 +351,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);
@@ -498,9 +502,10 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
usb_send_msg(dev, USB_MSG_RESET);
}
}
- port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb);
+ port->ctrl &= UHCI_PORT_READ_ONLY;
+ port->ctrl |= (val & ~UHCI_PORT_READ_ONLY);
/* some bits are reset when a '1' is written to them */
- port->ctrl &= ~(val & 0x000a);
+ port->ctrl &= ~(val & UHCI_PORT_WRITE_CLEAR);
}
break;
}
@@ -593,49 +598,52 @@ 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;
+ /* update speed */
+ if (port->port.dev->speed == USB_SPEED_LOW) {
+ port->ctrl |= UHCI_PORT_LSDA;
+ } else {
+ port->ctrl &= ~UHCI_PORT_LSDA;
+ }
- uhci_resume(s);
+ uhci_resume(s);
+}
- 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;
- port->ctrl |= UHCI_PORT_CSC;
- }
- /* disable port */
- if (port->ctrl & UHCI_PORT_EN) {
- port->ctrl &= ~UHCI_PORT_EN;
- port->ctrl |= UHCI_PORT_ENC;
- }
+static void uhci_detach(USBPort *port1)
+{
+ UHCIState *s = port1->opaque;
+ UHCIPort *port = &s->ports[port1->index];
- uhci_resume(s);
+ /* 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;
+ }
- dev = port->port.dev;
- if (dev) {
- /* send the detach message */
- usb_send_msg(dev, USB_MSG_DETACH);
- }
- port->port.dev = NULL;
+ uhci_resume(s);
+}
+
+static void uhci_wakeup(USBDevice *dev)
+{
+ USBBus *bus = usb_bus_from_device(dev);
+ UHCIState *s = container_of(bus, UHCIState, bus);
+ UHCIPort *port = s->ports + dev->port->index;
+
+ if (port->ctrl & UHCI_PORT_SUSPEND && !(port->ctrl & UHCI_PORT_RD)) {
+ port->ctrl |= UHCI_PORT_RD;
+ uhci_resume(s);
}
}
@@ -1101,6 +1109,12 @@ static void uhci_map(PCIDevice *pci_dev, int region_num,
register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
}
+static USBPortOps uhci_port_ops = {
+ .attach = uhci_attach,
+ .detach = uhci_detach,
+ .wakeup = uhci_wakeup,
+};
+
static int usb_uhci_common_initfn(UHCIState *s)
{
uint8_t *pci_conf = s->dev.config;
@@ -1115,7 +1129,9 @@ static int usb_uhci_common_initfn(UHCIState *s)
usb_bus_new(&s->bus, &s->dev.qdev);
for(i = 0; i < NB_PORTS; i++) {
- usb_register_port(&s->bus, &s->ports[i].port, s, i, NULL, uhci_attach);
+ usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+ usb_port_location(&s->ports[i].port, NULL, i+1);
}
s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
s->expire_time = qemu_get_clock(vm_clock) +