QEMUTimer *frame_timer;
QEMUBH *bh;
uint32_t frame_bytes;
+ uint32_t frame_bandwidth;
UHCIPort ports[NB_PORTS];
/* Interrupts that should be raised at the end of the current frame. */
uint32_t pending_int_mask;
+ int irq_pin;
/* Active packets */
QTAILQ_HEAD(, UHCIQueue) queues;
static void uhci_async_cancel_all(UHCIState *s)
{
- UHCIQueue *queue;
+ UHCIQueue *queue, *nq;
UHCIAsync *curr, *n;
- QTAILQ_FOREACH(queue, &s->queues, next) {
+ QTAILQ_FOREACH_SAFE(queue, &s->queues, next, nq) {
QTAILQ_FOREACH_SAFE(curr, &queue->asyncs, next, n) {
uhci_async_unlink(curr);
uhci_async_cancel(curr);
} else {
level = 0;
}
- qemu_set_irq(s->dev.irq[3], level);
+ qemu_set_irq(s->dev.irq[s->irq_pin], level);
}
static void uhci_reset(void *opaque)
uhci_update_irq(s);
}
-static void uhci_pre_save(void *opaque)
-{
- UHCIState *s = opaque;
-
- uhci_async_cancel_all(s);
-}
-
static const VMStateDescription vmstate_uhci_port = {
.name = "uhci port",
.version_id = 1,
}
};
+static int uhci_post_load(void *opaque, int version_id)
+{
+ UHCIState *s = opaque;
+
+ if (version_id < 2) {
+ s->expire_time = qemu_get_clock_ns(vm_clock) +
+ (get_ticks_per_sec() / FRAME_TIMER_FREQ);
+ }
+ return 0;
+}
+
static const VMStateDescription vmstate_uhci = {
.name = "uhci",
.version_id = 2,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
- .pre_save = uhci_pre_save,
+ .post_load = uhci_post_load,
.fields = (VMStateField []) {
VMSTATE_PCI_DEVICE(dev, UHCIState),
VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState),
done:
len = uhci_complete_td(s, td, async, int_mask);
- usb_packet_unmap(&async->packet);
+ usb_packet_unmap(&async->packet, &async->sgl);
uhci_async_free(async);
return len;
}
uhci_async_free(async);
} else {
async->done = 1;
- if (s->frame_bytes < 1280) {
+ if (s->frame_bytes < s->frame_bandwidth) {
qemu_bh_schedule(s->bh);
}
}
qhdb_reset(&qhdb);
for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) {
- if (s->frame_bytes >= 1280) {
+ if (s->frame_bytes >= s->frame_bandwidth) {
/* We've reached the usb 1.1 bandwidth, which is
1280 bytes/frame, stop processing */
trace_usb_uhci_frame_stop_bandwidth();
static int usb_uhci_common_initfn(PCIDevice *dev)
{
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
uint8_t *pci_conf = s->dev.config;
int i;
pci_conf[PCI_CLASS_PROG] = 0x00;
/* TODO: reset value should be 0. */
- pci_conf[PCI_INTERRUPT_PIN] = 4; /* interrupt pin D */
pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
+ switch (pc->device_id) {
+ case PCI_DEVICE_ID_INTEL_82801I_UHCI1:
+ s->irq_pin = 0; /* A */
+ break;
+ case PCI_DEVICE_ID_INTEL_82801I_UHCI2:
+ s->irq_pin = 1; /* B */
+ break;
+ case PCI_DEVICE_ID_INTEL_82801I_UHCI3:
+ s->irq_pin = 2; /* C */
+ break;
+ default:
+ s->irq_pin = 3; /* D */
+ break;
+ }
+ pci_config_set_interrupt_pin(pci_conf, s->irq_pin + 1);
+
if (s->masterbus) {
USBPort *ports[NB_PORTS];
for(i = 0; i < NB_PORTS; i++) {
return usb_uhci_common_initfn(dev);
}
-static int usb_uhci_exit(PCIDevice *dev)
+static void usb_uhci_exit(PCIDevice *dev)
{
UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
memory_region_destroy(&s->io_bar);
- return 0;
}
static Property uhci_properties[] = {
DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
+ DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280),
DEFINE_PROP_END_OF_LIST(),
};