@@ -122,6 +122,8 @@ struct ohci_hcca {
uint16_t frame, pad;
uint32_t done;
};
+#define HCCA_WRITEBACK_OFFSET offsetof(struct ohci_hcca, frame)
+#define HCCA_WRITEBACK_SIZE 8 /* frame, pad, done */
static void ohci_bus_stop(OHCIState *ohci);
static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
@@ -189,6 +191,10 @@ struct ohci_ed {
uint32_t head;
uint32_t next;
};
+#define ED_TAILP_OFFSET offsetof(struct ohci_ed, tail)
+#define ED_PART1_SIZE ED_TAILP_OFFSET
+#define ED_HEADP_OFFSET offsetof(struct ohci_ed, head)
+#define ED_PART2_SIZE (sizeof(struct ohci_ed) - ED_HEADP_OFFSET)
/* General transfer descriptor */
struct ohci_td {
@@ -569,7 +575,13 @@ static inline int ohci_read_hcca(OHCIState *ohci,
static inline int ohci_put_ed(OHCIState *ohci,
uint32_t addr, struct ohci_ed *ed)
{
- return put_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
+ /* ed->tail is under control of the HCD, so we need to split
+ * the write back into two parts
+ */
+ put_dwords(ohci, addr, (uint32_t *)ed, ED_PART1_SIZE >> 2);
+ return put_dwords(ohci, addr + ED_HEADP_OFFSET,
+ (uint32_t *)((char *)ed + ED_HEADP_OFFSET),
+ ED_PART2_SIZE >> 2);
}
static inline int ohci_put_td(OHCIState *ohci,
@@ -588,7 +600,9 @@ static inline int ohci_put_iso_td(OHCIState *ohci,
static inline int ohci_put_hcca(OHCIState *ohci,
uint32_t addr, struct ohci_hcca *hcca)
{
- cpu_physical_memory_write(addr + ohci->localmem_base, hcca, sizeof(*hcca));
+ cpu_physical_memory_write(addr + ohci->localmem_base + HCCA_WRITEBACK_OFFSET,
+ (char *)hcca + HCCA_WRITEBACK_OFFSET,
+ HCCA_WRITEBACK_SIZE);
return 1;
}