From 69e25d26b46a6e37698de4489eed5b07853bfe9e Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Sun, 13 Apr 2014 20:42:34 +1000 Subject: usb-ohci: Add vmstate descriptor This adds migration support for OHCI. This defines a descriptor for OHCIState. This changes some OHCIState field types to be migration compatible. This adds a descriptor for OHCIPort. This migrates the EOF timer if the USB was started at the time of migration. Cc: Gerd Hoffmann Cc: Peter Maydell Signed-off-by: Alexey Kardashevskiy Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ohci.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 111 insertions(+), 8 deletions(-) (limited to 'hw') diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 93f186f..cd87074 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -80,13 +80,13 @@ typedef struct { uint32_t bulk_head, bulk_cur; uint32_t per_cur; uint32_t done; - int done_count; + int32_t done_count; /* Frame counter partition */ - uint32_t fsmps:15; - uint32_t fit:1; - uint32_t fi:14; - uint32_t frt:1; + uint16_t fsmps; + uint8_t fit; + uint16_t fi; + uint8_t frt; uint16_t frame_number; uint16_t padding; uint32_t pstart; @@ -111,7 +111,7 @@ typedef struct { USBPacket usb_packet; uint8_t usb_buf[8192]; uint32_t async_td; - int async_complete; + bool async_complete; } OHCIState; @@ -693,7 +693,7 @@ static void ohci_async_complete_packet(USBPort *port, USBPacket *packet) #ifdef DEBUG_PACKET DPRINTF("Async packet complete\n"); #endif - ohci->async_complete = 1; + ohci->async_complete = true; ohci_process_lists(ohci, 1); } @@ -1058,7 +1058,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) #endif if (completion) { ohci->async_td = 0; - ohci->async_complete = 0; + ohci->async_complete = false; } else { if (ohci->async_td) { /* ??? The hardware should allow one active packet per @@ -1984,6 +1984,108 @@ static Property ohci_pci_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static const VMStateDescription vmstate_ohci_state_port = { + .name = "ohci-core/port", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(ctrl, OHCIPort), + VMSTATE_END_OF_LIST() + }, +}; + +static bool ohci_eof_timer_needed(void *opaque) +{ + OHCIState *ohci = opaque; + + return ohci->eof_timer != NULL; +} + +static int ohci_eof_timer_pre_load(void *opaque) +{ + OHCIState *ohci = opaque; + + ohci_bus_start(ohci); + + return 0; +} + +static const VMStateDescription vmstate_ohci_eof_timer = { + .name = "ohci-core/eof-timer", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_load = ohci_eof_timer_pre_load, + .fields = (VMStateField []) { + VMSTATE_TIMER(eof_timer, OHCIState), + VMSTATE_END_OF_LIST() + }, +}; + +const VMStateDescription vmstate_ohci_state = { + .name = "ohci-core", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_INT64(sof_time, OHCIState), + VMSTATE_UINT32(ctl, OHCIState), + VMSTATE_UINT32(status, OHCIState), + VMSTATE_UINT32(intr_status, OHCIState), + VMSTATE_UINT32(intr, OHCIState), + VMSTATE_UINT32(hcca, OHCIState), + VMSTATE_UINT32(ctrl_head, OHCIState), + VMSTATE_UINT32(ctrl_cur, OHCIState), + VMSTATE_UINT32(bulk_head, OHCIState), + VMSTATE_UINT32(bulk_cur, OHCIState), + VMSTATE_UINT32(per_cur, OHCIState), + VMSTATE_UINT32(done, OHCIState), + VMSTATE_INT32(done_count, OHCIState), + VMSTATE_UINT16(fsmps, OHCIState), + VMSTATE_UINT8(fit, OHCIState), + VMSTATE_UINT16(fi, OHCIState), + VMSTATE_UINT8(frt, OHCIState), + VMSTATE_UINT16(frame_number, OHCIState), + VMSTATE_UINT16(padding, OHCIState), + VMSTATE_UINT32(pstart, OHCIState), + VMSTATE_UINT32(lst, OHCIState), + VMSTATE_UINT32(rhdesc_a, OHCIState), + VMSTATE_UINT32(rhdesc_b, OHCIState), + VMSTATE_UINT32(rhstatus, OHCIState), + VMSTATE_STRUCT_ARRAY(rhport, OHCIState, OHCI_MAX_PORTS, 0, + vmstate_ohci_state_port, OHCIPort), + VMSTATE_UINT32(hstatus, OHCIState), + VMSTATE_UINT32(hmask, OHCIState), + VMSTATE_UINT32(hreset, OHCIState), + VMSTATE_UINT32(htest, OHCIState), + VMSTATE_UINT32(old_ctl, OHCIState), + VMSTATE_UINT8_ARRAY(usb_buf, OHCIState, 8192), + VMSTATE_UINT32(async_td, OHCIState), + VMSTATE_BOOL(async_complete, OHCIState), + VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection []) { + { + .vmsd = &vmstate_ohci_eof_timer, + .needed = ohci_eof_timer_needed, + } , { + /* empty */ + } + } +}; + +static const VMStateDescription vmstate_ohci = { + .name = "ohci", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState), + VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState), + VMSTATE_END_OF_LIST() + } +}; + static void ohci_pci_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1997,6 +2099,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data) dc->desc = "Apple USB Controller"; dc->props = ohci_pci_properties; dc->hotpluggable = false; + dc->vmsd = &vmstate_ohci; } static const TypeInfo ohci_pci_info = { -- cgit v1.1 From 1c76551fae0daa681f0c3298cc16fcb3d4ee01fd Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 25 Apr 2014 11:51:50 +0200 Subject: usb: mtp: replace debug printfs with trace points Signed-off-by: Gerd Hoffmann Reviewed-by: Peter Wu Reviewed-by: Stefan Hajnoczi --- hw/usb/dev-mtp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 8b44032..17df447 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -294,7 +294,7 @@ static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle, goto ignore; } - fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path); + trace_usb_mtp_object_alloc(s->dev.addr, o->handle, o->path); QTAILQ_INSERT_TAIL(&s->objects, o, next); return o; @@ -310,7 +310,7 @@ static void usb_mtp_object_free(MTPState *s, MTPObject *o) { int i; - fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path); + trace_usb_mtp_object_free(s->dev.addr, o->handle, o->path); QTAILQ_REMOVE(&s->objects, o, next); for (i = 0; i < o->nchildren; i++) { @@ -843,8 +843,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c) res0 = data_in->length; break; default: - fprintf(stderr, "%s: unknown command code 0x%04x\n", - __func__, c->code); + trace_usb_mtp_op_unknown(s->dev.addr, c->code); usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED, c->trans, 0, 0, 0); return; @@ -892,6 +891,7 @@ static void usb_mtp_handle_control(USBDevice *dev, USBPacket *p, static void usb_mtp_cancel_packet(USBDevice *dev, USBPacket *p) { + /* we don't use async packets, so this should never be called */ fprintf(stderr, "%s\n", __func__); } -- cgit v1.1 From ada435f47ea97546354d6990a952a4825dfb286e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 25 Apr 2014 11:53:22 +0200 Subject: usb: mtp: fix usb_mtp_add_u64 Signed-off-by: Gerd Hoffmann Reviewed-by: Peter Wu Reviewed-by: Stefan Hajnoczi --- hw/usb/dev-mtp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 17df447..063a426 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -416,7 +416,7 @@ static void usb_mtp_add_u32(MTPData *data, uint32_t val) static void usb_mtp_add_u64(MTPData *data, uint64_t val) { - usb_mtp_realloc(data, 4); + usb_mtp_realloc(data, 8); data->data[data->length++] = (val >> 0) & 0xff; data->data[data->length++] = (val >> 8) & 0xff; data->data[data->length++] = (val >> 16) & 0xff; @@ -424,7 +424,7 @@ static void usb_mtp_add_u64(MTPData *data, uint64_t val) data->data[data->length++] = (val >> 32) & 0xff; data->data[data->length++] = (val >> 40) & 0xff; data->data[data->length++] = (val >> 48) & 0xff; - data->data[data->length++] = (val >> 54) & 0xff; + data->data[data->length++] = (val >> 56) & 0xff; } static void usb_mtp_add_u16_array(MTPData *data, uint32_t len, -- cgit v1.1 From f7eaed85559278556cd4573eeb763475c1c2ff9a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 25 Apr 2014 11:55:32 +0200 Subject: usb: mtp: fix version (is decimal not bcd) Signed-off-by: Gerd Hoffmann Reviewed-by: Peter Wu Reviewed-by: Stefan Hajnoczi --- hw/usb/dev-mtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 063a426..dff2618 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -533,7 +533,7 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c) trace_usb_mtp_op_get_device_info(s->dev.addr); - usb_mtp_add_u16(d, 0x0100); + usb_mtp_add_u16(d, 100); usb_mtp_add_u32(d, 0xffffffff); usb_mtp_add_u16(d, 0x0101); usb_mtp_add_wstr(d, L""); -- cgit v1.1 From 9e4eff5b54a5f99537420e75fe2c686ec430d32a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 25 Apr 2014 11:57:07 +0200 Subject: usb: mtp: fix serial (must be exact 32 chars) Signed-off-by: Gerd Hoffmann Reviewed-by: Peter Wu Reviewed-by: Stefan Hajnoczi --- hw/usb/dev-mtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index dff2618..775dc8d 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -548,7 +548,7 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c) usb_mtp_add_wstr(d, L"" MTP_MANUFACTURER); usb_mtp_add_wstr(d, L"" MTP_PRODUCT); usb_mtp_add_wstr(d, L"0.1"); - usb_mtp_add_wstr(d, L"123456789abcdef123456789abcdef"); + usb_mtp_add_wstr(d, L"0123456789abcdef0123456789abcdef"); return d; } -- cgit v1.1 From 2dc7fdf33d28940255f171b8ea4b692d9d5b7a7d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 25 Apr 2014 12:01:55 +0200 Subject: usb: mtp: fix error path memory leak Signed-off-by: Gerd Hoffmann Reviewed-by: Peter Wu Reviewed-by: Stefan Hajnoczi --- hw/usb/dev-mtp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'hw') diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 775dc8d..45f9562 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -669,6 +669,7 @@ static MTPData *usb_mtp_get_object(MTPState *s, MTPControl *c, d->fd = open(o->path, O_RDONLY); if (d->fd == -1) { + usb_mtp_data_free(d); return NULL; } d->length = o->stat.st_size; @@ -688,6 +689,7 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c, d->fd = open(o->path, O_RDONLY); if (d->fd == -1) { + usb_mtp_data_free(d); return NULL; } -- cgit v1.1 From 457d397a2485225a96d6a9fc33cfe04f99e1e0f4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 25 Apr 2014 12:06:47 +0200 Subject: usb: mtp: avoid empty description string Signed-off-by: Gerd Hoffmann Reviewed-by: Peter Wu Reviewed-by: Stefan Hajnoczi --- hw/usb/dev-mtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 45f9562..a30a886 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -1046,7 +1046,7 @@ static int usb_mtp_initfn(USBDevice *dev) QTAILQ_INIT(&s->objects); if (s->desc == NULL) { s->desc = strrchr(s->root, '/'); - if (s->desc) { + if (s->desc && s->desc[0]) { s->desc = g_strdup(s->desc + 1); } else { s->desc = g_strdup("none"); -- cgit v1.1 From 9cd04ccf75759b660ab3d5e98b2653f3e8ee8b3e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 25 Apr 2014 12:09:21 +0200 Subject: usb: mtp: drop data-out hexdump Signed-off-by: Gerd Hoffmann Reviewed-by: Peter Wu Reviewed-by: Stefan Hajnoczi --- hw/usb/dev-mtp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index a30a886..b6eaeae 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -1011,8 +1011,7 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) usb_mtp_command(s, &cmd); break; default: - iov_hexdump(p->iov.iov, p->iov.niov, stderr, "mtp-out", 32); - trace_usb_mtp_stall(s->dev.addr, "TODO: implement data-out"); + /* not needed as long as the mtp device is read-only */ p->status = USB_RET_STALL; return; } -- cgit v1.1 From afa82daf1627645d3ad3e05954b098fff001ab32 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 25 Apr 2014 12:05:15 +0200 Subject: usb: mtp: fix possible buffer overflow Signed-off-by: Gerd Hoffmann Reviewed-by: Peter Wu Reviewed-by: Stefan Hajnoczi --- hw/usb/dev-mtp.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'hw') diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index b6eaeae..62428d8 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -998,6 +998,14 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) cmd.argc = (le32_to_cpu(container.length) - sizeof(container)) / sizeof(uint32_t); cmd.trans = le32_to_cpu(container.trans); + if (cmd.argc > ARRAY_SIZE(cmd.argv)) { + cmd.argc = ARRAY_SIZE(cmd.argv); + } + if (p->iov.size < sizeof(container) + cmd.argc * sizeof(uint32_t)) { + trace_usb_mtp_stall(s->dev.addr, "packet too small"); + p->status = USB_RET_STALL; + return; + } usb_packet_copy(p, ¶ms, cmd.argc * sizeof(uint32_t)); for (i = 0; i < cmd.argc; i++) { cmd.argv[i] = le32_to_cpu(params[i]); -- cgit v1.1 From 8ebb87635790e7033e19e9a26e8c5eef22560bcc Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 25 Apr 2014 12:37:49 +0200 Subject: usb: mtp: reply INCOMPLETE_TRANSFER on read errors Signed-off-by: Gerd Hoffmann Reviewed-by: Peter Wu Reviewed-by: Stefan Hajnoczi --- hw/usb/dev-mtp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 62428d8..943f930 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -50,6 +50,7 @@ enum mtp_code { RES_INVALID_TRANSACTION_ID = 0x2004, RES_OPERATION_NOT_SUPPORTED = 0x2005, RES_PARAMETER_NOT_SUPPORTED = 0x2006, + RES_INCOMPLETE_TRANSFER = 0x2007, RES_INVALID_STORAGE_ID = 0x2008, RES_INVALID_OBJECT_HANDLE = 0x2009, RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014, @@ -946,7 +947,8 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) } rc = read(d->fd, d->data, dlen); if (rc != dlen) { - fprintf(stderr, "%s: TODO: handle read error\n", __func__); + memset(d->data, 0, dlen); + s->result->code = RES_INCOMPLETE_TRANSFER; } usb_packet_copy(p, d->data, dlen); } -- cgit v1.1