summaryrefslogtreecommitdiffstats
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell2022-03-04 23:13:35 +0100
committerPeter Maydell2022-03-04 23:13:35 +0100
commit5c8463886d50eeb0337bd121ab877cf692731e36 (patch)
tree0140f272447424272065def0a4389d7adc529812 /hw
parentMerge remote-tracking branch 'remotes/nvme/tags/nvme-next-pull-request' into ... (diff)
parenthw/display/vmware_vga: replace fprintf calls with trace events (diff)
downloadqemu-5c8463886d50eeb0337bd121ab877cf692731e36.tar.gz
qemu-5c8463886d50eeb0337bd121ab877cf692731e36.tar.xz
qemu-5c8463886d50eeb0337bd121ab877cf692731e36.zip
Merge remote-tracking branch 'remotes/kraxel/tags/kraxel-20220304-pull-request' into staging
usb: fixes for ohci, xhci, mtp and redirect audio: latency fixes ui: opengl and cocoa fixes firmware: ovmf tabel aprser fixes # gpg: Signature made Fri 04 Mar 2022 14:18:47 GMT # gpg: using RSA key A0328CFFB93A17A79901FE7D4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full] # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full] # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full] # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/kraxel-20220304-pull-request: (35 commits) hw/display/vmware_vga: replace fprintf calls with trace events edid: Fix clock of Detailed Timing Descriptor softmmu/qdev-monitor: Add virtio-gpu-gl aliases ui/cocoa: Add Services menu ui/clipboard: fix use-after-free regression ui: do not create a surface when resizing a GL scanout ui/console: fix texture leak when calling surface_gl_create_texture() ui/console: fix crash when using gl context with non-gl listeners docs: Add spec of OVMF GUIDed table for SEV guests hw/i386: Replace magic number with field length calculation hw/i386: Improve bounds checking in OVMF table parsing coreaudio: Notify error in coreaudio_init_out hw/usb/redirect.c: Stop using qemu_oom_check() sdlaudio: fix samples vs. frames mix-up paaudio: fix samples vs. frames mix-up ossaudio: reduce effective playback buffer size dsoundaudio: reduce effective playback buffer size paaudio: reduce effective playback buffer size audio: restore mixing-engine playback buffer size Revert "audio: fix wavcapture segfault" ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/display/edid-generate.c66
-rw-r--r--hw/display/trace-events3
-rw-r--r--hw/display/vmware_vga.c30
-rw-r--r--hw/i386/pc_sysfw_ovmf.c18
-rw-r--r--hw/usb/dev-mtp.c4
-rw-r--r--hw/usb/hcd-ohci.c297
-rw-r--r--hw/usb/hcd-xhci.c2
-rw-r--r--hw/usb/redirect.c17
-rw-r--r--hw/usb/trace-events2
9 files changed, 230 insertions, 209 deletions
diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c
index bccf32af69..2cb819675e 100644
--- a/hw/display/edid-generate.c
+++ b/hw/display/edid-generate.c
@@ -255,33 +255,31 @@ static void edid_desc_dummy(uint8_t *desc)
edid_desc_type(desc, 0x10);
}
-static void edid_desc_timing(uint8_t *desc, uint32_t refresh_rate,
+static void edid_desc_timing(uint8_t *desc, const Timings *timings,
uint32_t xres, uint32_t yres,
uint32_t xmm, uint32_t ymm)
{
- Timings timings;
- generate_timings(&timings, refresh_rate, xres, yres);
- stl_le_p(desc, timings.clock);
+ stw_le_p(desc, timings->clock);
desc[2] = xres & 0xff;
- desc[3] = timings.xblank & 0xff;
+ desc[3] = timings->xblank & 0xff;
desc[4] = (((xres & 0xf00) >> 4) |
- ((timings.xblank & 0xf00) >> 8));
+ ((timings->xblank & 0xf00) >> 8));
desc[5] = yres & 0xff;
- desc[6] = timings.yblank & 0xff;
+ desc[6] = timings->yblank & 0xff;
desc[7] = (((yres & 0xf00) >> 4) |
- ((timings.yblank & 0xf00) >> 8));
+ ((timings->yblank & 0xf00) >> 8));
- desc[8] = timings.xfront & 0xff;
- desc[9] = timings.xsync & 0xff;
+ desc[8] = timings->xfront & 0xff;
+ desc[9] = timings->xsync & 0xff;
- desc[10] = (((timings.yfront & 0x00f) << 4) |
- ((timings.ysync & 0x00f) << 0));
- desc[11] = (((timings.xfront & 0x300) >> 2) |
- ((timings.xsync & 0x300) >> 4) |
- ((timings.yfront & 0x030) >> 2) |
- ((timings.ysync & 0x030) >> 4));
+ desc[10] = (((timings->yfront & 0x00f) << 4) |
+ ((timings->ysync & 0x00f) << 0));
+ desc[11] = (((timings->xfront & 0x300) >> 2) |
+ ((timings->xsync & 0x300) >> 4) |
+ ((timings->yfront & 0x030) >> 2) |
+ ((timings->ysync & 0x030) >> 4));
desc[12] = xmm & 0xff;
desc[13] = ymm & 0xff;
@@ -348,13 +346,10 @@ static void init_displayid(uint8_t *did)
edid_checksum(did + 1, did[2] + 4);
}
-static void qemu_displayid_generate(uint8_t *did, uint32_t refresh_rate,
+static void qemu_displayid_generate(uint8_t *did, const Timings *timings,
uint32_t xres, uint32_t yres,
uint32_t xmm, uint32_t ymm)
{
- Timings timings;
- generate_timings(&timings, refresh_rate, xres, yres);
-
did[0] = 0x70; /* display id extension */
did[1] = 0x13; /* version 1.3 */
did[2] = 23; /* length */
@@ -364,21 +359,21 @@ static void qemu_displayid_generate(uint8_t *did, uint32_t refresh_rate,
did[6] = 0x00; /* revision */
did[7] = 0x14; /* block length */
- did[8] = timings.clock & 0xff;
- did[9] = (timings.clock & 0xff00) >> 8;
- did[10] = (timings.clock & 0xff0000) >> 16;
+ did[8] = timings->clock & 0xff;
+ did[9] = (timings->clock & 0xff00) >> 8;
+ did[10] = (timings->clock & 0xff0000) >> 16;
did[11] = 0x88; /* leave aspect ratio undefined */
stw_le_p(did + 12, 0xffff & (xres - 1));
- stw_le_p(did + 14, 0xffff & (timings.xblank - 1));
- stw_le_p(did + 16, 0xffff & (timings.xfront - 1));
- stw_le_p(did + 18, 0xffff & (timings.xsync - 1));
+ stw_le_p(did + 14, 0xffff & (timings->xblank - 1));
+ stw_le_p(did + 16, 0xffff & (timings->xfront - 1));
+ stw_le_p(did + 18, 0xffff & (timings->xsync - 1));
stw_le_p(did + 20, 0xffff & (yres - 1));
- stw_le_p(did + 22, 0xffff & (timings.yblank - 1));
- stw_le_p(did + 24, 0xffff & (timings.yfront - 1));
- stw_le_p(did + 26, 0xffff & (timings.ysync - 1));
+ stw_le_p(did + 22, 0xffff & (timings->yblank - 1));
+ stw_le_p(did + 24, 0xffff & (timings->yfront - 1));
+ stw_le_p(did + 26, 0xffff & (timings->ysync - 1));
edid_checksum(did + 1, did[2] + 4);
}
@@ -386,6 +381,7 @@ static void qemu_displayid_generate(uint8_t *did, uint32_t refresh_rate,
void qemu_edid_generate(uint8_t *edid, size_t size,
qemu_edid_info *info)
{
+ Timings timings;
uint8_t *desc = edid + 54;
uint8_t *xtra3 = NULL;
uint8_t *dta = NULL;
@@ -409,9 +405,6 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
if (!info->prefy) {
info->prefy = 800;
}
- if (info->prefx >= 4096 || info->prefy >= 4096) {
- large_screen = 1;
- }
if (info->width_mm && info->height_mm) {
width_mm = info->width_mm;
height_mm = info->height_mm;
@@ -421,6 +414,11 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
height_mm = qemu_edid_dpi_to_mm(dpi, info->prefy);
}
+ generate_timings(&timings, refresh_rate, info->prefx, info->prefy);
+ if (info->prefx >= 4096 || info->prefy >= 4096 || timings.clock >= 65536) {
+ large_screen = 1;
+ }
+
/* =============== extensions =============== */
if (size >= 256) {
@@ -501,7 +499,7 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
if (!large_screen) {
/* The DTD section has only 12 bits to store the resolution */
- edid_desc_timing(desc, refresh_rate, info->prefx, info->prefy,
+ edid_desc_timing(desc, &timings, info->prefx, info->prefy,
width_mm, height_mm);
desc = edid_desc_next(edid, dta, desc);
}
@@ -536,7 +534,7 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
/* =============== display id extensions =============== */
if (did && large_screen) {
- qemu_displayid_generate(did, refresh_rate, info->prefx, info->prefy,
+ qemu_displayid_generate(did, &timings, info->prefx, info->prefy,
width_mm, height_mm);
}
diff --git a/hw/display/trace-events b/hw/display/trace-events
index 4a687d1b8e..91efc88f04 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -21,6 +21,9 @@ vmware_palette_write(uint32_t index, uint32_t value) "index %d, value 0x%x"
vmware_scratch_read(uint32_t index, uint32_t value) "index %d, value 0x%x"
vmware_scratch_write(uint32_t index, uint32_t value) "index %d, value 0x%x"
vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp"
+vmware_verify_rect_less_than_zero(const char *name, const char *param, int x) "%s: %s was < 0 (%d)"
+vmware_verify_rect_greater_than_bound(const char *name, const char *param, int bound, int x) "%s: %s was > %d (%d)"
+vmware_verify_rect_surface_bound_exceeded(const char *name, const char *component, int bound, const char *param1, int value1, const char *param2, int value2) "%s: %s > %d (%s: %d, %s: %d)"
# virtio-gpu-base.c
virtio_gpu_features(bool virgl) "virgl %d"
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index e2969a6c81..0cc43a1f15 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -297,46 +297,52 @@ static inline bool vmsvga_verify_rect(DisplaySurface *surface,
int x, int y, int w, int h)
{
if (x < 0) {
- fprintf(stderr, "%s: x was < 0 (%d)\n", name, x);
+ trace_vmware_verify_rect_less_than_zero(name, "x", x);
return false;
}
if (x > SVGA_MAX_WIDTH) {
- fprintf(stderr, "%s: x was > %d (%d)\n", name, SVGA_MAX_WIDTH, x);
+ trace_vmware_verify_rect_greater_than_bound(name, "x", SVGA_MAX_WIDTH,
+ x);
return false;
}
if (w < 0) {
- fprintf(stderr, "%s: w was < 0 (%d)\n", name, w);
+ trace_vmware_verify_rect_less_than_zero(name, "w", w);
return false;
}
if (w > SVGA_MAX_WIDTH) {
- fprintf(stderr, "%s: w was > %d (%d)\n", name, SVGA_MAX_WIDTH, w);
+ trace_vmware_verify_rect_greater_than_bound(name, "w", SVGA_MAX_WIDTH,
+ w);
return false;
}
if (x + w > surface_width(surface)) {
- fprintf(stderr, "%s: width was > %d (x: %d, w: %d)\n",
- name, surface_width(surface), x, w);
+ trace_vmware_verify_rect_surface_bound_exceeded(name, "width",
+ surface_width(surface),
+ "x", x, "w", w);
return false;
}
if (y < 0) {
- fprintf(stderr, "%s: y was < 0 (%d)\n", name, y);
+ trace_vmware_verify_rect_less_than_zero(name, "y", y);
return false;
}
if (y > SVGA_MAX_HEIGHT) {
- fprintf(stderr, "%s: y was > %d (%d)\n", name, SVGA_MAX_HEIGHT, y);
+ trace_vmware_verify_rect_greater_than_bound(name, "y", SVGA_MAX_HEIGHT,
+ y);
return false;
}
if (h < 0) {
- fprintf(stderr, "%s: h was < 0 (%d)\n", name, h);
+ trace_vmware_verify_rect_less_than_zero(name, "h", h);
return false;
}
if (h > SVGA_MAX_HEIGHT) {
- fprintf(stderr, "%s: h was > %d (%d)\n", name, SVGA_MAX_HEIGHT, h);
+ trace_vmware_verify_rect_greater_than_bound(name, "y", SVGA_MAX_HEIGHT,
+ y);
return false;
}
if (y + h > surface_height(surface)) {
- fprintf(stderr, "%s: update height > %d (y: %d, h: %d)\n",
- name, surface_height(surface), y, h);
+ trace_vmware_verify_rect_surface_bound_exceeded(name, "height",
+ surface_height(surface),
+ "y", y, "h", h);
return false;
}
diff --git a/hw/i386/pc_sysfw_ovmf.c b/hw/i386/pc_sysfw_ovmf.c
index f4dd92c588..07a4c267fa 100644
--- a/hw/i386/pc_sysfw_ovmf.c
+++ b/hw/i386/pc_sysfw_ovmf.c
@@ -24,11 +24,14 @@
*/
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
#include "hw/i386/pc.h"
#include "cpu.h"
#define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d"
+static const int bytes_after_table_footer = 32;
+
static bool ovmf_flash_parsed;
static uint8_t *ovmf_table;
static int ovmf_table_len;
@@ -52,12 +55,13 @@ void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size)
/*
* if this is OVMF there will be a table footer
- * guid 48 bytes before the end of the flash file. If it's
- * not found, silently abort the flash parsing.
+ * guid 48 bytes before the end of the flash file
+ * (= 32 bytes after the table + 16 bytes the GUID itself).
+ * If it's not found, silently abort the flash parsing.
*/
qemu_uuid_parse(OVMF_TABLE_FOOTER_GUID, &guid);
guid = qemu_uuid_bswap(guid); /* guids are LE */
- ptr = flash_ptr + flash_size - 48;
+ ptr = flash_ptr + flash_size - (bytes_after_table_footer + sizeof(guid));
if (!qemu_uuid_is_equal((QemuUUID *)ptr, &guid)) {
return;
}
@@ -66,7 +70,13 @@ void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size)
ptr -= sizeof(uint16_t);
tot_len = le16_to_cpu(*(uint16_t *)ptr) - sizeof(guid) - sizeof(uint16_t);
- if (tot_len <= 0) {
+ if (tot_len < 0 || tot_len > (ptr - flash_ptr)) {
+ error_report("OVMF table has invalid size %d", tot_len);
+ return;
+ }
+
+ if (tot_len == 0) {
+ /* no entries in the OVMF table */
return;
}
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 1e6ac76bef..e6b77a2a94 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -1607,7 +1607,7 @@ static void usb_mtp_write_data(MTPState *s, uint32_t handle)
usb_mtp_object_lookup(s, s->dataset.parent_handle);
char *path = NULL;
uint64_t rc;
- mode_t mask = 0644;
+ mode_t mask = 0755;
int ret = 0;
assert(d != NULL);
@@ -1635,7 +1635,7 @@ static void usb_mtp_write_data(MTPState *s, uint32_t handle)
}
d->fd = open(path, O_CREAT | O_WRONLY |
- O_CLOEXEC | O_NOFOLLOW, mask);
+ O_CLOEXEC | O_NOFOLLOW, mask & 0666);
if (d->fd == -1) {
ret = 1;
goto done;
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index a93d6b2e98..895b29fb86 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -58,8 +58,6 @@ struct ohci_hcca {
#define ED_WBACK_OFFSET offsetof(struct ohci_ed, head)
#define ED_WBACK_SIZE 4
-static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
-
/* Bitfields for the first word of an Endpoint Desciptor. */
#define OHCI_ED_FA_SHIFT 0
#define OHCI_ED_FA_MASK (0x7f<<OHCI_ED_FA_SHIFT)
@@ -261,92 +259,6 @@ static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
ohci_intr_update(ohci);
}
-/* Attach or detach a device on a root hub port. */
-static void ohci_attach(USBPort *port1)
-{
- OHCIState *s = port1->opaque;
- OHCIPort *port = &s->rhport[port1->index];
- uint32_t old_state = port->ctrl;
-
- /* 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);
- }
-
- trace_usb_ohci_port_attach(port1->index);
-
- if (old_state != port->ctrl) {
- ohci_set_interrupt(s, OHCI_INTR_RHSC);
- }
-}
-
-static void ohci_detach(USBPort *port1)
-{
- OHCIState *s = port1->opaque;
- OHCIPort *port = &s->rhport[port1->index];
- uint32_t old_state = port->ctrl;
-
- ohci_async_cancel_device(s, port1->dev);
-
- /* set connect status */
- if (port->ctrl & OHCI_PORT_CCS) {
- port->ctrl &= ~OHCI_PORT_CCS;
- port->ctrl |= OHCI_PORT_CSC;
- }
- /* disable port */
- if (port->ctrl & OHCI_PORT_PES) {
- port->ctrl &= ~OHCI_PORT_PES;
- port->ctrl |= OHCI_PORT_PESC;
- }
- trace_usb_ohci_port_detach(port1->index);
-
- if (old_state != port->ctrl) {
- ohci_set_interrupt(s, OHCI_INTR_RHSC);
- }
-}
-
-static void ohci_wakeup(USBPort *port1)
-{
- OHCIState *s = port1->opaque;
- OHCIPort *port = &s->rhport[port1->index];
- uint32_t intr = 0;
- if (port->ctrl & OHCI_PORT_PSS) {
- trace_usb_ohci_port_wakeup(port1->index);
- port->ctrl |= OHCI_PORT_PSSC;
- port->ctrl &= ~OHCI_PORT_PSS;
- intr = OHCI_INTR_RHSC;
- }
- /* Note that the controller can be suspended even if this port is not */
- if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
- trace_usb_ohci_remote_wakeup(s->name);
- /* This is the one state transition the controller can do by itself */
- s->ctl &= ~OHCI_CTL_HCFS;
- s->ctl |= OHCI_USB_RESUME;
- /* In suspend mode only ResumeDetected is possible, not RHSC:
- * see the OHCI spec 5.1.2.3.
- */
- intr = OHCI_INTR_RD;
- }
- ohci_set_interrupt(s, intr);
-}
-
-static void ohci_child_detach(USBPort *port1, USBDevice *child)
-{
- OHCIState *s = port1->opaque;
-
- ohci_async_cancel_device(s, child);
-}
-
static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr)
{
USBDevice *dev;
@@ -369,6 +281,10 @@ void ohci_stop_endpoints(OHCIState *ohci)
USBDevice *dev;
int i, j;
+ if (ohci->async_td) {
+ usb_cancel_packet(&ohci->usb_packet);
+ ohci->async_td = 0;
+ }
for (i = 0; i < ohci->num_ports; i++) {
dev = ohci->rhport[i].port.dev;
if (dev && dev->attached) {
@@ -398,10 +314,6 @@ static void ohci_roothub_reset(OHCIState *ohci)
usb_port_reset(&port->port);
}
}
- if (ohci->async_td) {
- usb_cancel_packet(&ohci->usb_packet);
- ohci->async_td = 0;
- }
ohci_stop_endpoints(ohci);
}
@@ -634,21 +546,9 @@ static int ohci_copy_iso_td(OHCIState *ohci,
return 0;
}
-static void ohci_process_lists(OHCIState *ohci, int completion);
-
-static void ohci_async_complete_packet(USBPort *port, USBPacket *packet)
-{
- OHCIState *ohci = container_of(packet, OHCIState, usb_packet);
-
- trace_usb_ohci_async_complete();
- ohci->async_complete = true;
- ohci_process_lists(ohci, 1);
-}
-
#define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b)))
-static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
- int completion)
+static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed)
{
int dir;
size_t len = 0;
@@ -658,6 +558,9 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
int i;
USBDevice *dev;
USBEndpoint *ep;
+ USBPacket *pkt;
+ uint8_t buf[8192];
+ bool int_req;
struct ohci_iso_td iso_td;
uint32_t addr;
uint16_t starting_frame;
@@ -792,40 +695,42 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
} else {
len = end_addr - start_addr + 1;
}
- if (len > sizeof(ohci->usb_buf)) {
- len = sizeof(ohci->usb_buf);
+ if (len > sizeof(buf)) {
+ len = sizeof(buf);
}
if (len && dir != OHCI_TD_DIR_IN) {
- if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len,
+ if (ohci_copy_iso_td(ohci, start_addr, end_addr, buf, len,
DMA_DIRECTION_TO_DEVICE)) {
ohci_die(ohci);
return 1;
}
}
- if (!completion) {
- bool int_req = relative_frame_number == frame_count &&
- OHCI_BM(iso_td.flags, TD_DI) == 0;
- dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
- if (dev == NULL) {
- trace_usb_ohci_td_dev_error();
- return 1;
- }
- ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
- usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, false, int_req);
- usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
- usb_handle_packet(dev, &ohci->usb_packet);
- if (ohci->usb_packet.status == USB_RET_ASYNC) {
- usb_device_flush_ep_queue(dev, ep);
- return 1;
- }
+ dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
+ if (dev == NULL) {
+ trace_usb_ohci_td_dev_error();
+ return 1;
}
- if (ohci->usb_packet.status == USB_RET_SUCCESS) {
- ret = ohci->usb_packet.actual_length;
+ ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
+ pkt = g_new0(USBPacket, 1);
+ usb_packet_init(pkt);
+ int_req = relative_frame_number == frame_count &&
+ OHCI_BM(iso_td.flags, TD_DI) == 0;
+ usb_packet_setup(pkt, pid, ep, 0, addr, false, int_req);
+ usb_packet_addbuf(pkt, buf, len);
+ usb_handle_packet(dev, pkt);
+ if (pkt->status == USB_RET_ASYNC) {
+ usb_device_flush_ep_queue(dev, ep);
+ g_free(pkt);
+ return 1;
+ }
+ if (pkt->status == USB_RET_SUCCESS) {
+ ret = pkt->actual_length;
} else {
- ret = ohci->usb_packet.status;
+ ret = pkt->status;
}
+ g_free(pkt);
trace_usb_ohci_iso_td_so(start_offset, end_offset, start_addr, end_addr,
str, len, ret);
@@ -833,7 +738,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
/* Writeback */
if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
/* IN transfer succeeded */
- if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret,
+ if (ohci_copy_iso_td(ohci, start_addr, end_addr, buf, ret,
DMA_DIRECTION_FROM_DEVICE)) {
ohci_die(ohci);
return 1;
@@ -1033,21 +938,21 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
ohci->async_td = 0;
ohci->async_complete = false;
} else {
+ dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
+ if (dev == NULL) {
+ trace_usb_ohci_td_dev_error();
+ return 1;
+ }
+ ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
if (ohci->async_td) {
/* ??? The hardware should allow one active packet per
endpoint. We only allow one active packet per controller.
This should be sufficient as long as devices respond in a
timely manner.
*/
- trace_usb_ohci_td_too_many_pending();
+ trace_usb_ohci_td_too_many_pending(ep->nr);
return 1;
}
- dev = ohci_find_device(ohci, OHCI_BM(ed->flags, ED_FA));
- if (dev == NULL) {
- trace_usb_ohci_td_dev_error();
- return 1;
- }
- ep = usb_ep_get(dev, pid, OHCI_BM(ed->flags, ED_EN));
usb_packet_setup(&ohci->usb_packet, pid, ep, 0, addr, !flag_r,
OHCI_BM(td.flags, TD_DI) == 0);
usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen);
@@ -1156,7 +1061,7 @@ exit_no_retire:
}
/* Service an endpoint list. Returns nonzero if active TD were found. */
-static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
+static int ohci_service_ed_list(OHCIState *ohci, uint32_t head)
{
struct ohci_ed ed;
uint32_t next_ed;
@@ -1207,8 +1112,9 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
break;
} else {
/* Handle isochronous endpoints */
- if (ohci_service_iso_td(ohci, &ed, completion))
+ if (ohci_service_iso_td(ohci, &ed)) {
break;
+ }
}
}
@@ -1235,20 +1141,20 @@ static void ohci_sof(OHCIState *ohci)
}
/* Process Control and Bulk lists. */
-static void ohci_process_lists(OHCIState *ohci, int completion)
+static void ohci_process_lists(OHCIState *ohci)
{
if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) {
if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head) {
trace_usb_ohci_process_lists(ohci->ctrl_head, ohci->ctrl_cur);
}
- if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) {
+ if (!ohci_service_ed_list(ohci, ohci->ctrl_head)) {
ohci->ctrl_cur = 0;
ohci->status &= ~OHCI_STATUS_CLF;
}
}
if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) {
- if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) {
+ if (!ohci_service_ed_list(ohci, ohci->bulk_head)) {
ohci->bulk_cur = 0;
ohci->status &= ~OHCI_STATUS_BLF;
}
@@ -1272,19 +1178,15 @@ static void ohci_frame_boundary(void *opaque)
int n;
n = ohci->frame_number & 0x1f;
- ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0);
+ ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]));
}
/* Cancel all pending packets if either of the lists has been disabled. */
if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) {
- if (ohci->async_td) {
- usb_cancel_packet(&ohci->usb_packet);
- ohci->async_td = 0;
- }
ohci_stop_endpoints(ohci);
}
ohci->old_ctl = ohci->ctl;
- ohci_process_lists(ohci, 0);
+ ohci_process_lists(ohci);
/* Stop if UnrecoverableError happened or ohci_sof will crash */
if (ohci->intr_status & OHCI_INTR_UE) {
@@ -1793,8 +1695,45 @@ static void ohci_mem_write(void *opaque,
}
}
-static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
+static const MemoryRegionOps ohci_mem_ops = {
+ .read = ohci_mem_read,
+ .write = ohci_mem_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+/* USBPortOps */
+static void ohci_attach(USBPort *port1)
{
+ OHCIState *s = port1->opaque;
+ OHCIPort *port = &s->rhport[port1->index];
+ uint32_t old_state = port->ctrl;
+
+ /* 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);
+ }
+
+ trace_usb_ohci_port_attach(port1->index);
+
+ if (old_state != port->ctrl) {
+ ohci_set_interrupt(s, OHCI_INTR_RHSC);
+ }
+}
+
+static void ohci_child_detach(USBPort *port1, USBDevice *dev)
+{
+ OHCIState *ohci = port1->opaque;
+
if (ohci->async_td &&
usb_packet_is_inflight(&ohci->usb_packet) &&
ohci->usb_packet.ep->dev == dev) {
@@ -1803,11 +1742,65 @@ static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
}
}
-static const MemoryRegionOps ohci_mem_ops = {
- .read = ohci_mem_read,
- .write = ohci_mem_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
+static void ohci_detach(USBPort *port1)
+{
+ OHCIState *s = port1->opaque;
+ OHCIPort *port = &s->rhport[port1->index];
+ uint32_t old_state = port->ctrl;
+
+ ohci_child_detach(port1, port1->dev);
+
+ /* set connect status */
+ if (port->ctrl & OHCI_PORT_CCS) {
+ port->ctrl &= ~OHCI_PORT_CCS;
+ port->ctrl |= OHCI_PORT_CSC;
+ }
+ /* disable port */
+ if (port->ctrl & OHCI_PORT_PES) {
+ port->ctrl &= ~OHCI_PORT_PES;
+ port->ctrl |= OHCI_PORT_PESC;
+ }
+ trace_usb_ohci_port_detach(port1->index);
+
+ if (old_state != port->ctrl) {
+ ohci_set_interrupt(s, OHCI_INTR_RHSC);
+ }
+}
+
+static void ohci_wakeup(USBPort *port1)
+{
+ OHCIState *s = port1->opaque;
+ OHCIPort *port = &s->rhport[port1->index];
+ uint32_t intr = 0;
+ if (port->ctrl & OHCI_PORT_PSS) {
+ trace_usb_ohci_port_wakeup(port1->index);
+ port->ctrl |= OHCI_PORT_PSSC;
+ port->ctrl &= ~OHCI_PORT_PSS;
+ intr = OHCI_INTR_RHSC;
+ }
+ /* Note that the controller can be suspended even if this port is not */
+ if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
+ trace_usb_ohci_remote_wakeup(s->name);
+ /* This is the one state transition the controller can do by itself */
+ s->ctl &= ~OHCI_CTL_HCFS;
+ s->ctl |= OHCI_USB_RESUME;
+ /*
+ * In suspend mode only ResumeDetected is possible, not RHSC:
+ * see the OHCI spec 5.1.2.3.
+ */
+ intr = OHCI_INTR_RD;
+ }
+ ohci_set_interrupt(s, intr);
+}
+
+static void ohci_async_complete_packet(USBPort *port, USBPacket *packet)
+{
+ OHCIState *ohci = container_of(packet, OHCIState, usb_packet);
+
+ trace_usb_ohci_async_complete();
+ ohci->async_complete = true;
+ ohci_process_lists(ohci);
+}
static USBPortOps ohci_port_ops = {
.attach = ohci_attach,
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 14bdb89676..0cd0a5e540 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -2523,7 +2523,7 @@ static void xhci_process_commands(XHCIState *xhci)
case CR_VENDOR_NEC_FIRMWARE_REVISION:
if (xhci->nec_quirks) {
event.type = 48; /* NEC reply */
- event.length = 0x3025;
+ event.length = 0x3034;
} else {
event.ccode = CC_TRB_ERROR;
}
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 5f0ef9cb3b..8692ea2561 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -1239,7 +1239,11 @@ static void usbredir_create_parser(USBRedirDevice *dev)
DPRINTF("creating usbredirparser\n");
- dev->parser = qemu_oom_check(usbredirparser_create());
+ dev->parser = usbredirparser_create();
+ if (!dev->parser) {
+ error_report("usbredirparser_create() failed");
+ exit(1);
+ }
dev->parser->priv = dev;
dev->parser->log_func = usbredir_log;
dev->parser->read_func = usbredir_read;
@@ -2239,7 +2243,10 @@ static int usbredir_put_parser(QEMUFile *f, void *priv, size_t unused,
}
usbredirparser_serialize(dev->parser, &data, &len);
- qemu_oom_check(data);
+ if (!data) {
+ error_report("usbredirparser_serialize failed");
+ exit(1);
+ }
qemu_put_be32(f, len);
qemu_put_buffer(f, data, len);
@@ -2330,7 +2337,11 @@ static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused,
bufp->len = qemu_get_be32(f);
bufp->status = qemu_get_be32(f);
bufp->offset = 0;
- bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */
+ bufp->data = malloc(bufp->len); /* regular malloc! */
+ if (!bufp->data) {
+ error_report("usbredir_get_bufpq: out of memory");
+ exit(1);
+ }
bufp->free_on_destroy = bufp->data;
qemu_get_buffer(f, bufp->data, bufp->len);
QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next);
diff --git a/hw/usb/trace-events b/hw/usb/trace-events
index b8287b63f1..9773cb5330 100644
--- a/hw/usb/trace-events
+++ b/hw/usb/trace-events
@@ -51,7 +51,7 @@ usb_ohci_td_skip_async(void) ""
usb_ohci_td_pkt_hdr(uint32_t addr, int64_t pktlen, int64_t len, const char *s, int flag_r, uint32_t cbp, uint32_t be) " TD @ 0x%.8x %" PRId64 " of %" PRId64 " bytes %s r=%d cbp=0x%.8x be=0x%.8x"
usb_ohci_td_pkt_short(const char *dir, const char *buf) "%s data: %s"
usb_ohci_td_pkt_full(const char *dir, const char *buf) "%s data: %s"
-usb_ohci_td_too_many_pending(void) ""
+usb_ohci_td_too_many_pending(int ep) "ep=%d"
usb_ohci_td_packet_status(int status) "status=%d"
usb_ohci_ed_read_error(uint32_t addr) "ED read error at 0x%x"
usb_ohci_ed_pkt(uint32_t cur, int h, int c, uint32_t head, uint32_t tail, uint32_t next) "ED @ 0x%.8x h=%u c=%u\n head=0x%.8x tailp=0x%.8x next=0x%.8x"