aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2011-10-14 10:46:35 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2011-10-14 10:46:35 -0500
commitbdc792d3875ee0e8c824bcd7820ab08ff2bd5e24 (patch)
treece9dae3c409a2614c0d58dbc0894ecef9e8dcc76 /hw
parent36f490b176afab3096e9c2877b365354f67e269d (diff)
parent80cf7cf74f29a219e02b50f27c12b1c792ebf99b (diff)
Merge remote-tracking branch 'kraxel/usb.28' into staging
Diffstat (limited to 'hw')
-rw-r--r--hw/usb-ehci.c4
-rw-r--r--hw/usb-hid.c11
-rw-r--r--hw/usb-hub.c12
-rw-r--r--hw/usb-msd.c5
-rw-r--r--hw/usb-ohci.c41
-rw-r--r--hw/usb-uhci.c2
-rw-r--r--hw/usb.c12
-rw-r--r--hw/usb.h1
8 files changed, 68 insertions, 20 deletions
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 27376a2351..bd374c1de6 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -880,6 +880,7 @@ static void ehci_reset(void *opaque)
}
if (devs[i] && devs[i]->attached) {
usb_attach(&s->ports[i]);
+ usb_send_msg(devs[i], USB_MSG_RESET);
}
}
ehci_queues_rip_all(s);
@@ -978,8 +979,7 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
trace_usb_ehci_port_reset(port, 0);
if (dev && dev->attached) {
- usb_attach(&s->ports[port]);
- usb_send_msg(dev, USB_MSG_RESET);
+ usb_reset(&s->ports[port]);
*portsc &= ~PORTSC_CSC;
}
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index ba79466401..a110c74dda 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -527,10 +527,21 @@ static int usb_keyboard_initfn(USBDevice *dev)
return usb_hid_initfn(dev, HID_KEYBOARD);
}
+static int usb_ptr_post_load(void *opaque, int version_id)
+{
+ USBHIDState *s = opaque;
+
+ if (s->dev.remote_wakeup) {
+ hid_pointer_activate(&s->hid);
+ }
+ return 0;
+}
+
static const VMStateDescription vmstate_usb_ptr = {
.name = "usb-ptr",
.version_id = 1,
.minimum_version_id = 1,
+ .post_load = usb_ptr_post_load,
.fields = (VMStateField []) {
VMSTATE_USB_DEVICE(dev, USBHIDState),
VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState),
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 286e3ad85d..09c65160c2 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -207,10 +207,14 @@ static void usb_hub_complete(USBPort *port, USBPacket *packet)
/*
* Just pass it along upstream for now.
*
- * If we ever inplement usb 2.0 split transactions this will
+ * If we ever implement usb 2.0 split transactions this will
* become a little more complicated ...
+ *
+ * Can't use usb_packet_complete() here because packet->owner is
+ * cleared already, go call the ->complete() callback directly
+ * instead.
*/
- usb_packet_complete(&s->dev, packet);
+ s->dev.port->ops->complete(s->dev.port, packet);
}
static void usb_hub_handle_reset(USBDevice *dev)
@@ -289,7 +293,7 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
port->wPortStatus |= PORT_STAT_SUSPEND;
break;
case PORT_RESET:
- if (dev) {
+ if (dev && dev->attached) {
usb_send_msg(dev, USB_MSG_RESET);
port->wPortChange |= PORT_STAT_C_RESET;
/* set enable bit */
@@ -429,7 +433,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p)
for(i = 0; i < NUM_PORTS; i++) {
port = &s->ports[i];
dev = port->port.dev;
- if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
+ if (dev && dev->attached && (port->wPortStatus & PORT_STAT_ENABLE)) {
ret = usb_handle_packet(dev, p);
if (ret != USB_RET_NODEV) {
return ret;
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index e92434cc94..08d2d2ac77 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -325,7 +325,10 @@ static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p)
{
MSDState *s = DO_UPCAST(MSDState, dev, dev);
- scsi_req_cancel(s->req);
+
+ if (s->req) {
+ scsi_req_cancel(s->req);
+ }
}
static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index c3be65a2e9..c2981c59a4 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -150,7 +150,7 @@ static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
#define OHCI_TD_DI_SHIFT 21
#define OHCI_TD_DI_MASK (7<<OHCI_TD_DI_SHIFT)
#define OHCI_TD_T0 (1<<24)
-#define OHCI_TD_T1 (1<<24)
+#define OHCI_TD_T1 (1<<25)
#define OHCI_TD_EC_SHIFT 26
#define OHCI_TD_EC_MASK (3<<OHCI_TD_EC_SHIFT)
#define OHCI_TD_CC_SHIFT 28
@@ -449,7 +449,7 @@ static void ohci_reset(void *opaque)
port = &ohci->rhport[i];
port->ctrl = 0;
if (port->port.dev && port->port.dev->attached) {
- usb_attach(&port->port);
+ usb_reset(&port->port);
}
}
if (ohci->async_td) {
@@ -872,7 +872,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
{
int dir;
- size_t len = 0;
+ size_t len = 0, pktlen = 0;
#ifdef DEBUG_PACKET
const char *str = NULL;
#endif
@@ -940,20 +940,30 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
len = (td.be - td.cbp) + 1;
}
- if (len && dir != OHCI_TD_DIR_IN && !completion) {
- ohci_copy_td(ohci, &td, ohci->usb_buf, len, 0);
+ pktlen = len;
+ if (len && dir != OHCI_TD_DIR_IN) {
+ /* The endpoint may not allow us to transfer it all now */
+ pktlen = (ed->flags & OHCI_ED_MPS_MASK) >> OHCI_ED_MPS_SHIFT;
+ if (pktlen > len) {
+ pktlen = len;
+ }
+ if (!completion) {
+ ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen, 0);
+ }
}
}
flag_r = (td.flags & OHCI_TD_R) != 0;
#ifdef DEBUG_PACKET
- DPRINTF(" TD @ 0x%.8x %" PRId64 " bytes %s r=%d cbp=0x%.8x be=0x%.8x\n",
- addr, (int64_t)len, str, flag_r, td.cbp, td.be);
+ DPRINTF(" TD @ 0x%.8x %" PRId64 " of %" PRId64
+ " bytes %s r=%d cbp=0x%.8x be=0x%.8x\n",
+ addr, (int64_t)pktlen, (int64_t)len, str, flag_r, td.cbp, td.be);
- if (len > 0 && dir != OHCI_TD_DIR_IN) {
+ if (pktlen > 0 && dir != OHCI_TD_DIR_IN) {
DPRINTF(" data:");
- for (i = 0; i < len; i++)
+ for (i = 0; i < pktlen; i++) {
printf(" %.2x", ohci->usb_buf[i]);
+ }
DPRINTF("\n");
}
#endif
@@ -982,7 +992,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
usb_packet_setup(&ohci->usb_packet, pid,
OHCI_BM(ed->flags, ED_FA),
OHCI_BM(ed->flags, ED_EN));
- usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
+ usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret != USB_RET_NODEV)
break;
@@ -1005,12 +1015,12 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
DPRINTF("\n");
#endif
} else {
- ret = len;
+ ret = pktlen;
}
}
/* Writeback */
- if (ret == len || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
+ if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) {
/* Transmission succeeded. */
if (ret == len) {
td.cbp = 0;
@@ -1026,6 +1036,12 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR);
OHCI_SET_BM(td.flags, TD_EC, 0);
+ if ((dir != OHCI_TD_DIR_IN) && (ret != len)) {
+ /* Partial packet transfer: TD not ready to retire yet */
+ goto exit_no_retire;
+ }
+
+ /* Setting ED_C is part of the TD retirement process */
ed->head &= ~OHCI_ED_C;
if (td.flags & OHCI_TD_T0)
ed->head |= OHCI_ED_C;
@@ -1066,6 +1082,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
i = OHCI_BM(td.flags, TD_DI);
if (i < ohci->done_count)
ohci->done_count = i;
+exit_no_retire:
ohci_put_td(ohci, addr, &td);
return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR;
}
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 17992cf003..171d7870b7 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -341,7 +341,7 @@ static void uhci_reset(void *opaque)
port = &s->ports[i];
port->ctrl = 0x0080;
if (port->port.dev && port->port.dev->attached) {
- usb_attach(&port->port);
+ usb_reset(&port->port);
}
}
diff --git a/hw/usb.c b/hw/usb.c
index fa90204c5e..2216efe077 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -33,6 +33,7 @@ void usb_attach(USBPort *port)
assert(dev != NULL);
assert(dev->attached);
+ assert(dev->state == USB_STATE_NOTATTACHED);
port->ops->attach(port);
usb_send_msg(dev, USB_MSG_ATTACH);
}
@@ -42,10 +43,21 @@ void usb_detach(USBPort *port)
USBDevice *dev = port->dev;
assert(dev != NULL);
+ assert(dev->state != USB_STATE_NOTATTACHED);
port->ops->detach(port);
usb_send_msg(dev, USB_MSG_DETACH);
}
+void usb_reset(USBPort *port)
+{
+ USBDevice *dev = port->dev;
+
+ assert(dev != NULL);
+ usb_detach(port);
+ usb_attach(port);
+ usb_send_msg(dev, USB_MSG_RESET);
+}
+
void usb_wakeup(USBDevice *dev)
{
if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
diff --git a/hw/usb.h b/hw/usb.h
index c08d469496..c6e1870e59 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -306,6 +306,7 @@ void usb_cancel_packet(USBPacket * p);
void usb_attach(USBPort *port);
void usb_detach(USBPort *port);
+void usb_reset(USBPort *port);
void usb_wakeup(USBDevice *dev);
int usb_generic_handle_packet(USBDevice *s, USBPacket *p);
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);