#define NLPTR_TYPE_FSTN 3 // frame span traversal node
#define SET_LAST_RUN_CLOCK(s) \
- (s)->last_run_ns = qemu_get_clock_ns(vm_clock);
+ (s)->last_run_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
/* nifty macros from Arnon's EHCI version */
#define get_field(data, field) \
{
int i;
- if (!ehci->dma) {
+ if (!ehci->as) {
ehci_raise_irq(ehci, USBSTS_HSE);
ehci->usbcmd &= ~USBCMD_RUNSTOP;
trace_usb_ehci_dma_error();
}
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- dma_memory_read(ehci->dma, addr, buf, sizeof(*buf));
+ dma_memory_read(ehci->as, addr, buf, sizeof(*buf));
*buf = le32_to_cpu(*buf);
}
{
int i;
- if (!ehci->dma) {
+ if (!ehci->as) {
ehci_raise_irq(ehci, USBSTS_HSE);
ehci->usbcmd &= ~USBCMD_RUNSTOP;
trace_usb_ehci_dma_error();
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
uint32_t tmp = cpu_to_le32(*buf);
- dma_memory_write(ehci->dma, addr, &tmp, sizeof(tmp));
+ dma_memory_write(ehci->as, addr, &tmp, sizeof(tmp));
}
return num;
static void ehci_free_packet(EHCIPacket *p)
{
- if (p->async == EHCI_ASYNC_FINISHED) {
+ if (p->async == EHCI_ASYNC_FINISHED &&
+ !(p->queue->qh.token & QTD_TOKEN_HALT)) {
ehci_writeback_async_complete_packet(p);
return;
}
trace_usb_ehci_packet_action(p->queue, p, "free");
- if (p->async == EHCI_ASYNC_INITIALIZED) {
- usb_packet_unmap(&p->packet, &p->sgl);
- qemu_sglist_destroy(&p->sgl);
- }
if (p->async == EHCI_ASYNC_INFLIGHT) {
usb_cancel_packet(&p->packet);
+ }
+ if (p->async == EHCI_ASYNC_FINISHED &&
+ p->packet.status == USB_RET_SUCCESS) {
+ fprintf(stderr,
+ "EHCI: Dropping completed packet from halted %s ep %02X\n",
+ (p->pid == USB_TOKEN_IN) ? "in" : "out",
+ get_field(p->queue->qh.epchar, QH_EPCHAR_EP));
+ }
+ if (p->async != EHCI_ASYNC_NONE) {
usb_packet_unmap(&p->packet, &p->sgl);
qemu_sglist_destroy(&p->sgl);
}
}
ehci_queues_rip_all(s, 0);
ehci_queues_rip_all(s, 1);
- qemu_del_timer(s->frame_timer);
+ timer_del(s->frame_timer);
qemu_bh_cancel(s->async_bh);
}
uint32_t val;
val = s->portsc[addr >> 2];
- trace_usb_ehci_portsc_read(addr + PORTSC_BEGIN, addr >> 2, val);
+ trace_usb_ehci_portsc_read(addr + s->portscbase, addr >> 2, val);
return val;
}
uint32_t old = *portsc;
USBDevice *dev = s->ports[port].dev;
- trace_usb_ehci_portsc_write(addr + PORTSC_BEGIN, addr >> 2, val);
+ trace_usb_ehci_portsc_write(addr + s->portscbase, addr >> 2, val);
/* Clear rwc bits */
*portsc &= ~(val & PORTSC_RWC_MASK);
*portsc &= ~PORTSC_RO_MASK;
*portsc |= val;
- trace_usb_ehci_portsc_change(addr + PORTSC_BEGIN, addr >> 2, *portsc, old);
+ trace_usb_ehci_portsc_change(addr + s->portscbase, addr >> 2, *portsc, old);
}
static void ehci_opreg_write(void *ptr, hwaddr addr,
cpage = get_field(p->qtd.token, QTD_TOKEN_CPAGE);
bytes = get_field(p->qtd.token, QTD_TOKEN_TBYTES);
offset = p->qtd.bufptr[0] & ~QTD_BUFPTR_MASK;
- qemu_sglist_init(&p->sgl, 5, p->queue->ehci->dma);
+ qemu_sglist_init(&p->sgl, p->queue->ehci->device, 5, p->queue->ehci->as);
while (bytes > 0) {
if (cpage > 4) {
default:
/* should not be triggerable */
fprintf(stderr, "USB invalid response %d\n", p->packet.status);
- assert(0);
+ g_assert_not_reached();
break;
}
return -1;
}
- qemu_sglist_init(&ehci->isgl, 2, ehci->dma);
+ qemu_sglist_init(&ehci->isgl, ehci->device, 2, ehci->as);
if (off + len > 4096) {
/* transfer crosses page border */
uint32_t len2 = off + len - 4096;
default:
fprintf(stderr, "Bad state!\n");
again = -1;
- assert(0);
+ g_assert_not_reached();
break;
}
/* this should only be due to a developer mistake */
fprintf(stderr, "ehci: Bad asynchronous state %d. "
"Resetting to active\n", ehci->astate);
- assert(0);
+ g_assert_not_reached();
}
}
/* this should only be due to a developer mistake */
fprintf(stderr, "ehci: Bad periodic state %d. "
"Resetting to active\n", ehci->pstate);
- assert(0);
+ g_assert_not_reached();
}
}
int uframes, skipped_uframes;
int i;
- t_now = qemu_get_clock_ns(vm_clock);
+ t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
ns_elapsed = t_now - ehci->last_run_ns;
uframes = ns_elapsed / UFRAME_TIMER_NS;
expire_time = t_now + (get_ticks_per_sec()
* (ehci->async_stepdown+1) / FRAME_TIMER_FREQ);
}
- qemu_mod_timer(ehci->frame_timer, expire_time);
+ timer_mod(ehci->frame_timer, expire_time);
}
}
}
};
-void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
+void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp)
{
int i;
+ if (s->portnr > NB_PORTS) {
+ error_setg(errp, "Too many ports! Max. port number is %d.",
+ NB_PORTS);
+ return;
+ }
+
+ usb_bus_new(&s->bus, sizeof(s->bus), &ehci_bus_ops, dev);
+ for (i = 0; i < s->portnr; i++) {
+ usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
+ USB_SPEED_MASK_HIGH);
+ s->ports[i].dev = 0;
+ }
+
+ s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ehci_frame_timer, s);
+ s->async_bh = qemu_bh_new(ehci_frame_timer, s);
+ s->device = dev;
+
+ qemu_register_reset(ehci_reset, s);
+ qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s);
+}
+
+void usb_ehci_init(EHCIState *s, DeviceState *dev)
+{
/* 2.2 host controller interface version */
s->caps[0x00] = (uint8_t)(s->opregbase - s->capsbase);
s->caps[0x01] = 0x00;
s->caps[0x02] = 0x00;
s->caps[0x03] = 0x01; /* HC version */
- s->caps[0x04] = NB_PORTS; /* Number of downstream ports */
+ s->caps[0x04] = s->portnr; /* Number of downstream ports */
s->caps[0x05] = 0x00; /* No companion ports at present */
s->caps[0x06] = 0x00;
s->caps[0x07] = 0x00;
s->caps[0x0a] = 0x00;
s->caps[0x0b] = 0x00;
- usb_bus_new(&s->bus, &ehci_bus_ops, dev);
- for(i = 0; i < NB_PORTS; i++) {
- usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
- USB_SPEED_MASK_HIGH);
- s->ports[i].dev = 0;
- }
-
- s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s);
- s->async_bh = qemu_bh_new(ehci_frame_timer, s);
QTAILQ_INIT(&s->aqueues);
QTAILQ_INIT(&s->pqueues);
usb_packet_init(&s->ipacket);
- qemu_register_reset(ehci_reset, s);
- qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s);
-
- memory_region_init(&s->mem, "ehci", MMIO_SIZE);
- memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s,
+ memory_region_init(&s->mem, OBJECT(dev), "ehci", MMIO_SIZE);
+ memory_region_init_io(&s->mem_caps, OBJECT(dev), &ehci_mmio_caps_ops, s,
"capabilities", CAPA_SIZE);
- memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s,
- "operational", PORTSC_BEGIN);
- memory_region_init_io(&s->mem_ports, &ehci_mmio_port_ops, s,
- "ports", PORTSC_END - PORTSC_BEGIN);
+ memory_region_init_io(&s->mem_opreg, OBJECT(dev), &ehci_mmio_opreg_ops, s,
+ "operational", s->portscbase);
+ memory_region_init_io(&s->mem_ports, OBJECT(dev), &ehci_mmio_port_ops, s,
+ "ports", 4 * s->portnr);
memory_region_add_subregion(&s->mem, s->capsbase, &s->mem_caps);
memory_region_add_subregion(&s->mem, s->opregbase, &s->mem_opreg);
- memory_region_add_subregion(&s->mem, s->opregbase + PORTSC_BEGIN,
+ memory_region_add_subregion(&s->mem, s->opregbase + s->portscbase,
&s->mem_ports);
}