diff options
Diffstat (limited to 'hw/usb')
-rw-r--r-- | hw/usb/bus.c | 1 | ||||
-rw-r--r-- | hw/usb/ccid-card-emulated.c | 1 | ||||
-rw-r--r-- | hw/usb/ccid-card-passthru.c | 3 | ||||
-rw-r--r-- | hw/usb/desc.c | 6 | ||||
-rw-r--r-- | hw/usb/dev-audio.c | 1 | ||||
-rw-r--r-- | hw/usb/dev-bluetooth.c | 1 | ||||
-rw-r--r-- | hw/usb/dev-hid.c | 6 | ||||
-rw-r--r-- | hw/usb/dev-hub.c | 1 | ||||
-rw-r--r-- | hw/usb/dev-network.c | 1 | ||||
-rw-r--r-- | hw/usb/dev-serial.c | 2 | ||||
-rw-r--r-- | hw/usb/dev-smartcard-reader.c | 3 | ||||
-rw-r--r-- | hw/usb/dev-storage.c | 16 | ||||
-rw-r--r-- | hw/usb/dev-uas.c | 1 | ||||
-rw-r--r-- | hw/usb/dev-wacom.c | 1 | ||||
-rw-r--r-- | hw/usb/hcd-ehci-pci.c | 29 | ||||
-rw-r--r-- | hw/usb/hcd-ehci-sysbus.c | 132 | ||||
-rw-r--r-- | hw/usb/hcd-ehci.c | 80 | ||||
-rw-r--r-- | hw/usb/hcd-ehci.h | 30 | ||||
-rw-r--r-- | hw/usb/hcd-ohci.c | 243 | ||||
-rw-r--r-- | hw/usb/hcd-uhci.c | 12 | ||||
-rw-r--r-- | hw/usb/hcd-xhci.c | 354 | ||||
-rw-r--r-- | hw/usb/host-libusb.c | 6 | ||||
-rw-r--r-- | hw/usb/host-linux.c | 1 | ||||
-rw-r--r-- | hw/usb/libhw.c | 4 | ||||
-rw-r--r-- | hw/usb/redirect.c | 2 |
25 files changed, 714 insertions, 223 deletions
diff --git a/hw/usb/bus.c b/hw/usb/bus.c index d1827be101..f83d1de6cd 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -13,6 +13,7 @@ static int usb_qdev_exit(DeviceState *qdev); static Property usb_props[] = { DEFINE_PROP_STRING("port", USBDevice, port_path), + DEFINE_PROP_STRING("serial", USBDevice, serial), DEFINE_PROP_BIT("full-path", USBDevice, flags, USB_DEV_FLAG_FULL_PATH, true), DEFINE_PROP_END_OF_LIST() diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c index deb6d4703b..aa913df853 100644 --- a/hw/usb/ccid-card-emulated.c +++ b/hw/usb/ccid-card-emulated.c @@ -592,6 +592,7 @@ static void emulated_class_initfn(ObjectClass *klass, void *data) cc->exitfn = emulated_exitfn; cc->get_atr = emulated_get_atr; cc->apdu_from_guest = emulated_apdu_from_guest; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "emulated smartcard"; dc->props = emulated_card_properties; } diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c index 01c7e6f20d..10f1d309a6 100644 --- a/hw/usb/ccid-card-passthru.c +++ b/hw/usb/ccid-card-passthru.c @@ -364,7 +364,7 @@ static int passthru_exitfn(CCIDCardState *base) } static VMStateDescription passthru_vmstate = { - .name = PASSTHRU_DEV_NAME, + .name = "ccid-card-passthru", .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { @@ -392,6 +392,7 @@ static void passthru_class_initfn(ObjectClass *klass, void *data) cc->exitfn = passthru_exitfn; cc->get_atr = passthru_get_atr; cc->apdu_from_guest = passthru_apdu_from_guest; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "passthrough smartcard"; dc->vmsd = &passthru_vmstate; dc->props = passthru_card_properties; diff --git a/hw/usb/desc.c b/hw/usb/desc.c index fce303e9c8..bf6c522682 100644 --- a/hw/usb/desc.c +++ b/hw/usb/desc.c @@ -566,6 +566,12 @@ void usb_desc_create_serial(USBDevice *dev) char *path; int dst; + if (dev->serial) { + /* 'serial' usb bus property has priority if present */ + usb_desc_set_string(dev, index, dev->serial); + return; + } + assert(index != 0 && desc->str[index] != NULL); dst = snprintf(serial, sizeof(serial), "%s", desc->str[index]); path = qdev_get_dev_path(hcd); diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index 04933a985a..c5420eb057 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -673,6 +673,7 @@ static void usb_audio_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_audio; dc->props = usb_audio_properties; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); k->product_desc = "QEMU USB Audio Interface"; k->usb_desc = &desc_audio; k->init = usb_audio_initfn; diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c index 68cc1d4fab..f2fc2a8034 100644 --- a/hw/usb/dev-bluetooth.c +++ b/hw/usb/dev-bluetooth.c @@ -553,6 +553,7 @@ static void usb_bt_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usb_bt_handle_data; uc->handle_destroy = usb_bt_handle_destroy; dc->vmsd = &vmstate_usb_bt; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo bt_info = { diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 13c8adb585..d266361cea 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -570,6 +570,9 @@ static int usb_hid_initfn(USBDevice *dev, int kind) { USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); + if (dev->serial) { + usb_desc_set_string(dev, STR_SERIALNUMBER, dev->serial); + } usb_desc_init(dev); us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); hid_init(&us->hid, kind, usb_hid_changed); @@ -668,6 +671,7 @@ static void usb_tablet_class_initfn(ObjectClass *klass, void *data) uc->product_desc = "QEMU USB Tablet"; dc->vmsd = &vmstate_usb_ptr; dc->props = usb_tablet_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo usb_tablet_info = { @@ -687,6 +691,7 @@ static void usb_mouse_class_initfn(ObjectClass *klass, void *data) uc->product_desc = "QEMU USB Mouse"; uc->usb_desc = &desc_mouse; dc->vmsd = &vmstate_usb_ptr; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo usb_mouse_info = { @@ -706,6 +711,7 @@ static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) uc->product_desc = "QEMU USB Keyboard"; uc->usb_desc = &desc_keyboard; dc->vmsd = &vmstate_usb_kbd; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo usb_keyboard_info = { diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 0b71abd028..e865a98751 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -574,6 +574,7 @@ static void usb_hub_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usb_hub_handle_control; uc->handle_data = usb_hub_handle_data; uc->handle_destroy = usb_hub_handle_destroy; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->fw_name = "hub"; dc->vmsd = &vmstate_usb_hub; } diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 5473ac2cd5..660d7743fe 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1429,6 +1429,7 @@ static void usb_net_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usb_net_handle_control; uc->handle_data = usb_net_handle_data; uc->handle_destroy = usb_net_handle_destroy; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->fw_name = "network"; dc->vmsd = &vmstate_usb_net; dc->props = net_properties; diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index 2fc8a3b136..0b150d43fb 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -590,6 +590,7 @@ static void usb_serial_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usb_serial_handle_data; dc->vmsd = &vmstate_usb_serial; dc->props = serial_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo serial_info = { @@ -617,6 +618,7 @@ static void usb_braille_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usb_serial_handle_data; dc->vmsd = &vmstate_usb_serial; dc->props = braille_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo braille_info = { diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index 125cc2c221..2233c548fa 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1397,7 +1397,7 @@ static VMStateDescription usb_device_vmstate = { }; static VMStateDescription ccid_vmstate = { - .name = CCID_DEV_NAME, + .name = "usb-ccid", .version_id = 1, .minimum_version_id = 1, .post_load = ccid_post_load, @@ -1449,6 +1449,7 @@ static void ccid_class_initfn(ObjectClass *klass, void *data) dc->desc = "CCID Rev 1.1 smartcard reader"; dc->vmsd = &ccid_vmstate; dc->props = ccid_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo ccid_info = { diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 2532de8838..5864b1aa44 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -62,7 +62,6 @@ typedef struct { USBPacket *packet; /* usb-storage only */ BlockConf conf; - char *serial; uint32_t removable; } MSDState; @@ -607,13 +606,14 @@ static int usb_msd_initfn_storage(USBDevice *dev) MSDState *s = DO_UPCAST(MSDState, dev, dev); BlockDriverState *bs = s->conf.bs; SCSIDevice *scsi_dev; + Error *err = NULL; if (!bs) { error_report("drive property not set"); return -1; } - blkconf_serial(&s->conf, &s->serial); + blkconf_serial(&s->conf, &dev->serial); /* * Hack alert: this pretends to be a block device, but it's really @@ -627,16 +627,12 @@ static int usb_msd_initfn_storage(USBDevice *dev) bdrv_detach_dev(bs, &s->dev.qdev); s->conf.bs = NULL; - if (s->serial) { - usb_desc_set_string(dev, STR_SERIALNUMBER, s->serial); - } else { - usb_desc_create_serial(dev); - } - + usb_desc_create_serial(dev); usb_desc_init(dev); scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_storage, NULL); scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable, - s->conf.bootindex, s->serial); + s->conf.bootindex, dev->serial, + &err); if (!scsi_dev) { return -1; } @@ -752,7 +748,6 @@ static const VMStateDescription vmstate_usb_msd = { static Property msd_properties[] = { DEFINE_BLOCK_PROPERTIES(MSDState, conf), - DEFINE_PROP_STRING("serial", MSDState, serial), DEFINE_PROP_BIT("removable", MSDState, removable, 0, false), DEFINE_PROP_END_OF_LIST(), }; @@ -772,6 +767,7 @@ static void usb_msd_class_initfn_common(ObjectClass *klass) #ifdef CONFIG_MARU uc->handle_destroy = usb_msd_handle_destroy; #endif + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->fw_name = "storage"; dc->vmsd = &vmstate_usb_msd; } diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 6efab62544..63ad12ea6b 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -916,6 +916,7 @@ static void usb_uas_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usb_uas_handle_control; uc->handle_data = usb_uas_handle_data; uc->handle_destroy = usb_uas_handle_destroy; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->fw_name = "storage"; dc->vmsd = &vmstate_usb_uas; } diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index 3be5cdefda..1b092358f9 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -362,6 +362,7 @@ static void usb_wacom_class_init(ObjectClass *klass, void *data) uc->handle_control = usb_wacom_handle_control; uc->handle_data = usb_wacom_handle_data; uc->handle_destroy = usb_wacom_handle_destroy; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "QEMU PenPartner Tablet"; dc->vmsd = &vmstate_usb_wacom; } diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index 0eb78269f7..4d21a0b7bb 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -60,20 +60,30 @@ static int usb_ehci_pci_initfn(PCIDevice *dev) pci_conf[0x6e] = 0x00; pci_conf[0x6f] = 0xc0; /* USBLEFCTLSTS */ - s->caps[0x09] = 0x68; /* EECP */ - s->irq = dev->irq[3]; - s->dma = pci_dma_context(dev); - - s->capsbase = 0x00; - s->opregbase = 0x20; + s->as = pci_get_address_space(dev); - usb_ehci_initfn(s, DEVICE(dev)); + usb_ehci_realize(s, DEVICE(dev), NULL); pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem); return 0; } +static void usb_ehci_pci_init(Object *obj) +{ + EHCIPCIState *i = PCI_EHCI(obj); + EHCIState *s = &i->ehci; + + s->caps[0x09] = 0x68; /* EECP */ + + s->capsbase = 0x00; + s->opregbase = 0x20; + s->portscbase = 0x44; + s->portnr = NB_PORTS; + + usb_ehci_init(s, DEVICE(obj)); +} + static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int l) { @@ -86,7 +96,7 @@ static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr, return; } busmaster = pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_MASTER; - i->ehci.dma = busmaster ? pci_dma_context(dev) : NULL; + i->ehci.as = busmaster ? pci_get_address_space(dev) : &address_space_memory; } static Property ehci_pci_properties[] = { @@ -122,6 +132,7 @@ static const TypeInfo ehci_pci_type_info = { .name = TYPE_PCI_EHCI, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(EHCIPCIState), + .instance_init = usb_ehci_pci_init, .abstract = true, .class_init = ehci_class_init, }; @@ -129,11 +140,13 @@ static const TypeInfo ehci_pci_type_info = { static void ehci_data_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); EHCIPCIInfo *i = data; k->vendor_id = i->vendor_id; k->device_id = i->device_id; k->revision = i->revision; + set_bit(DEVICE_CATEGORY_USB, dc->categories); } static struct EHCIPCIInfo ehci_pci_info[] = { diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index b68a66a63b..fe6eea5908 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -32,36 +32,52 @@ static Property ehci_sysbus_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static int usb_ehci_sysbus_initfn(SysBusDevice *dev) +static void usb_ehci_sysbus_realize(DeviceState *dev, Error **errp) { + SysBusDevice *d = SYS_BUS_DEVICE(dev); EHCISysBusState *i = SYS_BUS_EHCI(dev); - SysBusEHCIClass *sec = SYS_BUS_EHCI_GET_CLASS(dev); + EHCIState *s = &i->ehci; + + usb_ehci_realize(s, dev, errp); + sysbus_init_irq(d, &s->irq); +} + +static void ehci_sysbus_init(Object *obj) +{ + SysBusDevice *d = SYS_BUS_DEVICE(obj); + EHCISysBusState *i = SYS_BUS_EHCI(obj); + SysBusEHCIClass *sec = SYS_BUS_EHCI_GET_CLASS(obj); EHCIState *s = &i->ehci; s->capsbase = sec->capsbase; s->opregbase = sec->opregbase; - s->dma = &dma_context_memory; + s->portscbase = sec->portscbase; + s->portnr = sec->portnr; + s->as = &address_space_memory; - usb_ehci_initfn(s, DEVICE(dev)); - sysbus_init_irq(dev, &s->irq); - sysbus_init_mmio(dev, &s->mem); - return 0; + usb_ehci_init(s, DEVICE(obj)); + sysbus_init_mmio(d, &s->mem); } static void ehci_sysbus_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass); + + sec->portscbase = 0x44; + sec->portnr = NB_PORTS; - k->init = usb_ehci_sysbus_initfn; + dc->realize = usb_ehci_sysbus_realize; dc->vmsd = &vmstate_ehci_sysbus; dc->props = ehci_sysbus_properties; + set_bit(DEVICE_CATEGORY_USB, dc->categories); } static const TypeInfo ehci_type_info = { .name = TYPE_SYS_BUS_EHCI, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(EHCISysBusState), + .instance_init = ehci_sysbus_init, .abstract = true, .class_init = ehci_sysbus_class_init, .class_size = sizeof(SysBusEHCIClass), @@ -70,7 +86,9 @@ static const TypeInfo ehci_type_info = { static void ehci_xlnx_class_init(ObjectClass *oc, void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); + set_bit(DEVICE_CATEGORY_USB, dc->categories); sec->capsbase = 0x100; sec->opregbase = 0x140; } @@ -84,9 +102,11 @@ static const TypeInfo ehci_xlnx_type_info = { static void ehci_exynos4210_class_init(ObjectClass *oc, void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); sec->capsbase = 0x0; sec->opregbase = 0x10; + set_bit(DEVICE_CATEGORY_USB, dc->categories); } static const TypeInfo ehci_exynos4210_type_info = { @@ -95,11 +115,105 @@ static const TypeInfo ehci_exynos4210_type_info = { .class_init = ehci_exynos4210_class_init, }; +static void ehci_tegra2_class_init(ObjectClass *oc, void *data) +{ + SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); + + sec->capsbase = 0x100; + sec->opregbase = 0x140; + set_bit(DEVICE_CATEGORY_USB, dc->categories); +} + +static const TypeInfo ehci_tegra2_type_info = { + .name = TYPE_TEGRA2_EHCI, + .parent = TYPE_SYS_BUS_EHCI, + .class_init = ehci_tegra2_class_init, +}; + +/* + * Faraday FUSBH200 USB 2.0 EHCI + */ + +/** + * FUSBH200EHCIRegs: + * @FUSBH200_REG_EOF_ASTR: EOF/Async. Sleep Timer Register + * @FUSBH200_REG_BMCSR: Bus Monitor Control/Status Register + */ +enum FUSBH200EHCIRegs { + FUSBH200_REG_EOF_ASTR = 0x34, + FUSBH200_REG_BMCSR = 0x40, +}; + +static uint64_t fusbh200_ehci_read(void *opaque, hwaddr addr, unsigned size) +{ + EHCIState *s = opaque; + hwaddr off = s->opregbase + s->portscbase + 4 * s->portnr + addr; + + switch (off) { + case FUSBH200_REG_EOF_ASTR: + return 0x00000041; + case FUSBH200_REG_BMCSR: + /* High-Speed, VBUS valid, interrupt level-high active */ + return (2 << 9) | (1 << 8) | (1 << 3); + } + + return 0; +} + +static void fusbh200_ehci_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ +} + +static const MemoryRegionOps fusbh200_ehci_mmio_ops = { + .read = fusbh200_ehci_read, + .write = fusbh200_ehci_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void fusbh200_ehci_init(Object *obj) +{ + EHCISysBusState *i = SYS_BUS_EHCI(obj); + FUSBH200EHCIState *f = FUSBH200_EHCI(obj); + EHCIState *s = &i->ehci; + + memory_region_init_io(&f->mem_vendor, OBJECT(f), &fusbh200_ehci_mmio_ops, s, + "fusbh200", 0x4c); + memory_region_add_subregion(&s->mem, + s->opregbase + s->portscbase + 4 * s->portnr, + &f->mem_vendor); +} + +static void fusbh200_ehci_class_init(ObjectClass *oc, void *data) +{ + SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); + + sec->capsbase = 0x0; + sec->opregbase = 0x10; + sec->portscbase = 0x20; + sec->portnr = 1; + set_bit(DEVICE_CATEGORY_USB, dc->categories); +} + +static const TypeInfo ehci_fusbh200_type_info = { + .name = TYPE_FUSBH200_EHCI, + .parent = TYPE_SYS_BUS_EHCI, + .instance_size = sizeof(FUSBH200EHCIState), + .instance_init = fusbh200_ehci_init, + .class_init = fusbh200_ehci_class_init, +}; + static void ehci_sysbus_register_types(void) { type_register_static(&ehci_type_info); type_register_static(&ehci_xlnx_type_info); type_register_static(&ehci_exynos4210_type_info); + type_register_static(&ehci_tegra2_type_info); + type_register_static(&ehci_fusbh200_type_info); } type_init(ehci_sysbus_register_types) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 0d3799d443..010a0d0d32 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -446,7 +446,7 @@ static inline int get_dwords(EHCIState *ehci, uint32_t addr, { int i; - if (!ehci->dma) { + if (!ehci->as) { ehci_raise_irq(ehci, USBSTS_HSE); ehci->usbcmd &= ~USBCMD_RUNSTOP; trace_usb_ehci_dma_error(); @@ -454,7 +454,7 @@ static inline int get_dwords(EHCIState *ehci, uint32_t addr, } 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); } @@ -467,7 +467,7 @@ static inline int put_dwords(EHCIState *ehci, uint32_t addr, { int i; - if (!ehci->dma) { + if (!ehci->as) { ehci_raise_irq(ehci, USBSTS_HSE); ehci->usbcmd &= ~USBCMD_RUNSTOP; trace_usb_ehci_dma_error(); @@ -476,7 +476,7 @@ static inline int put_dwords(EHCIState *ehci, uint32_t addr, 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; @@ -995,7 +995,7 @@ static uint64_t ehci_port_read(void *ptr, hwaddr addr, 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; } @@ -1036,7 +1036,7 @@ static void ehci_port_write(void *ptr, hwaddr addr, 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); @@ -1069,7 +1069,7 @@ static void ehci_port_write(void *ptr, hwaddr addr, *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, @@ -1241,11 +1241,13 @@ static int ehci_init_transfer(EHCIPacket *p) { uint32_t cpage, offset, bytes, plen; dma_addr_t page; + USBBus *bus = &p->queue->ehci->bus; + BusState *qbus = BUS(bus); 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, qbus->parent, 5, p->queue->ehci->as); while (bytes > 0) { if (cpage > 4) { @@ -1355,7 +1357,7 @@ static void ehci_execute_complete(EHCIQueue *q) default: /* should not be triggerable */ fprintf(stderr, "USB invalid response %d\n", p->packet.status); - assert(0); + g_assert_not_reached(); break; } @@ -1484,7 +1486,7 @@ static int ehci_process_itd(EHCIState *ehci, return -1; } - qemu_sglist_init(&ehci->isgl, 2, ehci->dma); + qemu_sglist_init(&ehci->isgl, DEVICE(ehci), 2, ehci->as); if (off + len > 4096) { /* transfer crosses page border */ uint32_t len2 = off + len - 4096; @@ -2140,7 +2142,7 @@ static void ehci_advance_state(EHCIState *ehci, int async) default: fprintf(stderr, "Bad state!\n"); again = -1; - assert(0); + g_assert_not_reached(); break; } @@ -2204,7 +2206,7 @@ static void ehci_advance_async_state(EHCIState *ehci) /* 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(); } } @@ -2254,7 +2256,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) /* 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(); } } @@ -2508,16 +2510,38 @@ const VMStateDescription vmstate_ehci = { } }; -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, &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 = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s); + s->async_bh = qemu_bh_new(ehci_frame_timer, s); + + 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; @@ -2525,33 +2549,21 @@ void usb_ehci_initfn(EHCIState *s, DeviceState *dev) 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); } diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index e95bb7ec46..15a28e8b31 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -40,11 +40,7 @@ #define MMIO_SIZE 0x1000 #define CAPA_SIZE 0x10 -#define PORTSC 0x0044 -#define PORTSC_BEGIN PORTSC -#define PORTSC_END (PORTSC + 4 * NB_PORTS) - -#define NB_PORTS 6 /* Number of downstream ports */ +#define NB_PORTS 6 /* Max. Number of downstream ports */ typedef struct EHCIPacket EHCIPacket; typedef struct EHCIQueue EHCIQueue; @@ -261,13 +257,15 @@ struct EHCIState { USBBus bus; qemu_irq irq; MemoryRegion mem; - DMAContext *dma; + AddressSpace *as; MemoryRegion mem_caps; MemoryRegion mem_opreg; MemoryRegion mem_ports; int companion_count; uint16_t capsbase; uint16_t opregbase; + uint16_t portscbase; + uint16_t portnr; /* properties */ uint32_t maxframes; @@ -278,7 +276,7 @@ struct EHCIState { */ uint8_t caps[CAPA_SIZE]; union { - uint32_t opreg[PORTSC_BEGIN/sizeof(uint32_t)]; + uint32_t opreg[0x44/sizeof(uint32_t)]; struct { uint32_t usbcmd; uint32_t usbsts; @@ -322,7 +320,8 @@ struct EHCIState { extern const VMStateDescription vmstate_ehci; -void usb_ehci_initfn(EHCIState *s, DeviceState *dev); +void usb_ehci_init(EHCIState *s, DeviceState *dev); +void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp); #define TYPE_PCI_EHCI "pci-ehci-usb" #define PCI_EHCI(obj) OBJECT_CHECK(EHCIPCIState, (obj), TYPE_PCI_EHCI) @@ -338,6 +337,8 @@ typedef struct EHCIPCIState { #define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb" #define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb" +#define TYPE_TEGRA2_EHCI "tegra2-ehci-usb" +#define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb" #define SYS_BUS_EHCI(obj) \ OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI) @@ -361,6 +362,19 @@ typedef struct SysBusEHCIClass { uint16_t capsbase; uint16_t opregbase; + uint16_t portscbase; + uint16_t portnr; } SysBusEHCIClass; +#define FUSBH200_EHCI(obj) \ + OBJECT_CHECK(FUSBH200EHCIState, (obj), TYPE_FUSBH200_EHCI) + +typedef struct FUSBH200EHCIState { + /*< private >*/ + EHCISysBusState parent_obj; + /*< public >*/ + + MemoryRegion mem_vendor; +} FUSBH200EHCIState; + #endif diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 51241cda78..d7836d6803 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -22,7 +22,6 @@ * o Allocate bandwidth in frames properly * o Disable timers when nothing needs to be done, or remove timer usage * all together. - * o Handle unrecoverable errors properly * o BIOS work to boot from USB storage */ @@ -62,7 +61,7 @@ typedef struct { USBBus bus; qemu_irq irq; MemoryRegion mem; - DMAContext *dma; + AddressSpace *as; int num_ports; const char *name; @@ -308,6 +307,8 @@ struct ohci_iso_td { #define OHCI_HRESET_FSBIR (1 << 0) +static void ohci_die(OHCIState *ohci); + /* Update IRQ levels */ static inline void ohci_intr_update(OHCIState *ohci) { @@ -508,11 +509,13 @@ static inline int get_dwords(OHCIState *ohci, addr += ohci->localmem_base; for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - dma_memory_read(ohci->dma, addr, buf, sizeof(*buf)); + if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) { + return -1; + } *buf = le32_to_cpu(*buf); } - return 1; + return 0; } /* Put an array of dwords in to main memory */ @@ -525,10 +528,12 @@ static inline int put_dwords(OHCIState *ohci, for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { uint32_t tmp = cpu_to_le32(*buf); - dma_memory_write(ohci->dma, addr, &tmp, sizeof(tmp)); + if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) { + return -1; + } } - return 1; + return 0; } /* Get an array of words from main memory */ @@ -540,11 +545,13 @@ static inline int get_words(OHCIState *ohci, addr += ohci->localmem_base; for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { - dma_memory_read(ohci->dma, addr, buf, sizeof(*buf)); + if (dma_memory_read(ohci->as, addr, buf, sizeof(*buf))) { + return -1; + } *buf = le16_to_cpu(*buf); } - return 1; + return 0; } /* Put an array of words in to main memory */ @@ -557,10 +564,12 @@ static inline int put_words(OHCIState *ohci, for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) { uint16_t tmp = cpu_to_le16(*buf); - dma_memory_write(ohci->dma, addr, &tmp, sizeof(tmp)); + if (dma_memory_write(ohci->as, addr, &tmp, sizeof(tmp))) { + return -1; + } } - return 1; + return 0; } static inline int ohci_read_ed(OHCIState *ohci, @@ -578,15 +587,15 @@ static inline int ohci_read_td(OHCIState *ohci, static inline int ohci_read_iso_td(OHCIState *ohci, dma_addr_t addr, struct ohci_iso_td *td) { - return (get_dwords(ohci, addr, (uint32_t *)td, 4) && - get_words(ohci, addr + 16, td->offset, 8)); + return get_dwords(ohci, addr, (uint32_t *)td, 4) || + get_words(ohci, addr + 16, td->offset, 8); } static inline int ohci_read_hcca(OHCIState *ohci, dma_addr_t addr, struct ohci_hcca *hcca) { - dma_memory_read(ohci->dma, addr + ohci->localmem_base, hcca, sizeof(*hcca)); - return 1; + return dma_memory_read(ohci->as, addr + ohci->localmem_base, + hcca, sizeof(*hcca)); } static inline int ohci_put_ed(OHCIState *ohci, @@ -610,23 +619,22 @@ static inline int ohci_put_td(OHCIState *ohci, static inline int ohci_put_iso_td(OHCIState *ohci, dma_addr_t addr, struct ohci_iso_td *td) { - return (put_dwords(ohci, addr, (uint32_t *)td, 4) && - put_words(ohci, addr + 16, td->offset, 8)); + return put_dwords(ohci, addr, (uint32_t *)td, 4 || + put_words(ohci, addr + 16, td->offset, 8)); } static inline int ohci_put_hcca(OHCIState *ohci, dma_addr_t addr, struct ohci_hcca *hcca) { - dma_memory_write(ohci->dma, - addr + ohci->localmem_base + HCCA_WRITEBACK_OFFSET, - (char *)hcca + HCCA_WRITEBACK_OFFSET, - HCCA_WRITEBACK_SIZE); - return 1; + return dma_memory_write(ohci->as, + addr + ohci->localmem_base + HCCA_WRITEBACK_OFFSET, + (char *)hcca + HCCA_WRITEBACK_OFFSET, + HCCA_WRITEBACK_SIZE); } /* Read/Write the contents of a TD from/to main memory. */ -static void ohci_copy_td(OHCIState *ohci, struct ohci_td *td, - uint8_t *buf, int len, DMADirection dir) +static int ohci_copy_td(OHCIState *ohci, struct ohci_td *td, + uint8_t *buf, int len, DMADirection dir) { dma_addr_t ptr, n; @@ -634,18 +642,26 @@ static void ohci_copy_td(OHCIState *ohci, struct ohci_td *td, n = 0x1000 - (ptr & 0xfff); if (n > len) n = len; - dma_memory_rw(ohci->dma, ptr + ohci->localmem_base, buf, n, dir); - if (n == len) - return; + + if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) { + return -1; + } + if (n == len) { + return 0; + } ptr = td->be & ~0xfffu; buf += n; - dma_memory_rw(ohci->dma, ptr + ohci->localmem_base, buf, len - n, dir); + if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, + len - n, dir)) { + return -1; + } + return 0; } /* Read/Write the contents of an ISO TD from/to main memory. */ -static void ohci_copy_iso_td(OHCIState *ohci, - uint32_t start_addr, uint32_t end_addr, - uint8_t *buf, int len, DMADirection dir) +static int ohci_copy_iso_td(OHCIState *ohci, + uint32_t start_addr, uint32_t end_addr, + uint8_t *buf, int len, DMADirection dir) { dma_addr_t ptr, n; @@ -653,12 +669,20 @@ static void ohci_copy_iso_td(OHCIState *ohci, n = 0x1000 - (ptr & 0xfff); if (n > len) n = len; - dma_memory_rw(ohci->dma, ptr + ohci->localmem_base, buf, n, dir); - if (n == len) - return; + + if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, n, dir)) { + return -1; + } + if (n == len) { + return 0; + } ptr = end_addr & ~0xfffu; buf += n; - dma_memory_rw(ohci->dma, ptr + ohci->localmem_base, buf, len - n, dir); + if (dma_memory_rw(ohci->as, ptr + ohci->localmem_base, buf, + len - n, dir)) { + return -1; + } + return 0; } static void ohci_process_lists(OHCIState *ohci, int completion); @@ -698,8 +722,9 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, addr = ed->head & OHCI_DPTR_MASK; - if (!ohci_read_iso_td(ohci, addr, &iso_td)) { + if (ohci_read_iso_td(ohci, addr, &iso_td)) { printf("usb-ohci: ISO_TD read error at %x\n", addr); + ohci_die(ohci); return 0; } @@ -740,7 +765,10 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, i = OHCI_BM(iso_td.flags, TD_DI); if (i < ohci->done_count) ohci->done_count = i; - ohci_put_iso_td(ohci, addr, &iso_td); + if (ohci_put_iso_td(ohci, addr, &iso_td)) { + ohci_die(ohci); + return 1; + } return 0; } @@ -821,8 +849,11 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, } if (len && dir != OHCI_TD_DIR_IN) { - ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, - DMA_DIRECTION_TO_DEVICE); + if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, + DMA_DIRECTION_TO_DEVICE)) { + ohci_die(ohci); + return 1; + } } if (!completion) { @@ -852,8 +883,11 @@ 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 */ - ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, - DMA_DIRECTION_FROM_DEVICE); + if (ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, + DMA_DIRECTION_FROM_DEVICE)) { + ohci_die(ohci); + return 1; + } OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, OHCI_CC_NOERROR); OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret); @@ -910,7 +944,9 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, if (i < ohci->done_count) ohci->done_count = i; } - ohci_put_iso_td(ohci, addr, &iso_td); + if (ohci_put_iso_td(ohci, addr, &iso_td)) { + ohci_die(ohci); + } return 1; } @@ -943,8 +979,9 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) #endif return 1; } - if (!ohci_read_td(ohci, addr, &td)) { + if (ohci_read_td(ohci, addr, &td)) { fprintf(stderr, "usb-ohci: TD read error at %x\n", addr); + ohci_die(ohci); return 0; } @@ -997,8 +1034,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) pktlen = len; } if (!completion) { - ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen, - DMA_DIRECTION_TO_DEVICE); + if (ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen, + DMA_DIRECTION_TO_DEVICE)) { + ohci_die(ohci); + } } } } @@ -1055,8 +1094,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) if (ret >= 0) { if (dir == OHCI_TD_DIR_IN) { - ohci_copy_td(ohci, &td, ohci->usb_buf, ret, - DMA_DIRECTION_FROM_DEVICE); + if (ohci_copy_td(ohci, &td, ohci->usb_buf, ret, + DMA_DIRECTION_FROM_DEVICE)) { + ohci_die(ohci); + } #ifdef DEBUG_PACKET DPRINTF(" data:"); for (i = 0; i < ret; i++) @@ -1133,7 +1174,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) if (i < ohci->done_count) ohci->done_count = i; exit_no_retire: - ohci_put_td(ohci, addr, &td); + if (ohci_put_td(ohci, addr, &td)) { + ohci_die(ohci); + return 1; + } return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR; } @@ -1151,8 +1195,9 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) return 0; for (cur = head; cur; cur = next_ed) { - if (!ohci_read_ed(ohci, cur, &ed)) { + if (ohci_read_ed(ohci, cur, &ed)) { fprintf(stderr, "usb-ohci: ED read error at %x\n", cur); + ohci_die(ohci); return 0; } @@ -1194,7 +1239,10 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) } } - ohci_put_ed(ohci, cur, &ed); + if (ohci_put_ed(ohci, cur, &ed)) { + ohci_die(ohci); + return 0; + } } return active; @@ -1236,7 +1284,11 @@ static void ohci_frame_boundary(void *opaque) OHCIState *ohci = opaque; struct ohci_hcca hcca; - ohci_read_hcca(ohci, ohci->hcca, &hcca); + if (ohci_read_hcca(ohci, ohci->hcca, &hcca)) { + fprintf(stderr, "usb-ohci: HCCA read error at %x\n", ohci->hcca); + ohci_die(ohci); + return; + } /* Process all the lists at the end of the frame */ if (ohci->ctl & OHCI_CTL_PLE) { @@ -1257,6 +1309,11 @@ static void ohci_frame_boundary(void *opaque) ohci->old_ctl = ohci->ctl; ohci_process_lists(ohci, 0); + /* Stop if UnrecoverableError happened or ohci_sof will crash */ + if (ohci->intr_status & OHCI_INTR_UE) { + return; + } + /* Frame boundary, so do EOF stuf here */ ohci->frt = ohci->fit; @@ -1282,7 +1339,9 @@ static void ohci_frame_boundary(void *opaque) ohci_sof(ohci); /* Writeback HCCA */ - ohci_put_hcca(ohci, ohci->hcca, &hcca); + if (ohci_put_hcca(ohci, ohci->hcca, &hcca)) { + ohci_die(ohci); + } } /* Start sending SOF tokens across the USB bus, lists are processed in @@ -1296,7 +1355,7 @@ static int ohci_bus_start(OHCIState *ohci) if (ohci->eof_timer == NULL) { fprintf(stderr, "usb-ohci: %s: qemu_new_timer_ns failed\n", ohci->name); - /* TODO: Signal unrecoverable error */ + ohci_die(ohci); return 0; } @@ -1788,11 +1847,11 @@ static USBBusOps ohci_bus_ops = { static int usb_ohci_init(OHCIState *ohci, DeviceState *dev, int num_ports, dma_addr_t localmem_base, char *masterbus, uint32_t firstport, - DMAContext *dma) + AddressSpace *as) { int i; - ohci->dma = dma; + ohci->as = as; if (usb_frame_time == 0) { #ifdef OHCI_TIME_WARP @@ -1830,7 +1889,8 @@ static int usb_ohci_init(OHCIState *ohci, DeviceState *dev, } } - memory_region_init_io(&ohci->mem, &ohci_mem_ops, ohci, "ohci", 256); + memory_region_init_io(&ohci->mem, OBJECT(dev), &ohci_mem_ops, + ohci, "ohci", 256); ohci->localmem_base = localmem_base; ohci->name = object_get_typename(OBJECT(dev)); @@ -1842,51 +1902,77 @@ static int usb_ohci_init(OHCIState *ohci, DeviceState *dev, return 0; } +#define TYPE_PCI_OHCI "pci-ohci" +#define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI) + typedef struct { - PCIDevice pci_dev; + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ + OHCIState state; char *masterbus; uint32_t num_ports; uint32_t firstport; } OHCIPCIState; -static int usb_ohci_initfn_pci(struct PCIDevice *dev) +/** A typical O/EHCI will stop operating, set itself into error state + * (which can be queried by MMIO) and will set PERR in its config + * space to signal that it got an error + */ +static void ohci_die(OHCIState *ohci) { - OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev); + OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state); - ohci->pci_dev.config[PCI_CLASS_PROG] = 0x10; /* OHCI */ - ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ + fprintf(stderr, "%s: DMA error\n", __func__); - if (usb_ohci_init(&ohci->state, &dev->qdev, ohci->num_ports, 0, + ohci_set_interrupt(ohci, OHCI_INTR_UE); + ohci_bus_stop(ohci); + pci_set_word(dev->parent_obj.config + PCI_STATUS, + PCI_STATUS_DETECTED_PARITY); +} + +static int usb_ohci_initfn_pci(PCIDevice *dev) +{ + OHCIPCIState *ohci = PCI_OHCI(dev); + + dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */ + dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ + + if (usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0, ohci->masterbus, ohci->firstport, - pci_dma_context(dev)) != 0) { + pci_get_address_space(dev)) != 0) { return -1; } - ohci->state.irq = ohci->pci_dev.irq[0]; + ohci->state.irq = dev->irq[0]; - /* TODO: avoid cast below by using dev */ - pci_register_bar(&ohci->pci_dev, 0, 0, &ohci->state.mem); + pci_register_bar(dev, 0, 0, &ohci->state.mem); return 0; } +#define TYPE_SYSBUS_OHCI "sysbus-ohci" +#define SYSBUS_OHCI(obj) OBJECT_CHECK(OHCISysBusState, (obj), TYPE_SYSBUS_OHCI) + typedef struct { - SysBusDevice busdev; + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + OHCIState ohci; uint32_t num_ports; dma_addr_t dma_offset; } OHCISysBusState; -static int ohci_init_pxa(SysBusDevice *dev) +static void ohci_realize_pxa(DeviceState *dev, Error **errp) { - OHCISysBusState *s = FROM_SYSBUS(OHCISysBusState, dev); + OHCISysBusState *s = SYSBUS_OHCI(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); /* Cannot fail as we pass NULL for masterbus */ - usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset, NULL, 0, - &dma_context_memory); - sysbus_init_irq(dev, &s->ohci.irq); - sysbus_init_mmio(dev, &s->ohci.mem); - - return 0; + usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset, NULL, 0, + &address_space_memory); + sysbus_init_irq(sbd, &s->ohci.irq); + sysbus_init_mmio(sbd, &s->ohci.mem); } static Property ohci_pci_properties[] = { @@ -1906,12 +1992,13 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB; k->class_id = PCI_CLASS_SERIAL_USB; k->no_hotplug = 1; + set_bit(DEVICE_CATEGORY_USB, dc->categories); dc->desc = "Apple USB Controller"; dc->props = ohci_pci_properties; } static const TypeInfo ohci_pci_info = { - .name = "pci-ohci", + .name = TYPE_PCI_OHCI, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(OHCIPCIState), .class_init = ohci_pci_class_init, @@ -1926,15 +2013,15 @@ static Property ohci_sysbus_properties[] = { static void ohci_sysbus_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); - sbc->init = ohci_init_pxa; + dc->realize = ohci_realize_pxa; + set_bit(DEVICE_CATEGORY_USB, dc->categories); dc->desc = "OHCI USB Controller"; dc->props = ohci_sysbus_properties; } static const TypeInfo ohci_sysbus_info = { - .name = "sysbus-ohci", + .name = TYPE_SYSBUS_OHCI, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OHCISysBusState), .class_init = ohci_sysbus_class_init, diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index c85b2038a2..ac8283313e 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -189,6 +189,7 @@ typedef struct UHCI_QH { static void uhci_async_cancel(UHCIAsync *async); static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td); +static void uhci_resume(void *opaque); static inline int32_t uhci_queue_token(UHCI_TD *td) { @@ -498,6 +499,12 @@ static void uhci_port_write(void *opaque, hwaddr addr, return; } s->cmd = val; + if (val & UHCI_CMD_EGSM) { + if ((s->ports[0].ctrl & UHCI_PORT_RD) || + (s->ports[1].ctrl & UHCI_PORT_RD)) { + uhci_resume(s); + } + } break; case 0x02: s->status &= ~val; @@ -1259,7 +1266,9 @@ static int usb_uhci_common_initfn(PCIDevice *dev) qemu_register_reset(uhci_reset, s); - memory_region_init_io(&s->io_bar, &uhci_ioport_ops, s, "uhci", 0x20); + memory_region_init_io(&s->io_bar, OBJECT(s), &uhci_ioport_ops, s, + "uhci", 0x20); + /* Use region 4 for consistency with real hardware. BSD guests seem to rely on this. */ pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar); @@ -1313,6 +1322,7 @@ static void uhci_class_init(ObjectClass *klass, void *data) k->no_hotplug = 1; dc->vmsd = &vmstate_uhci; dc->props = uhci_properties; + set_bit(DEVICE_CATEGORY_USB, dc->categories); u->info = *info; } diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 8813bdf904..58c88b8a6b 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -405,6 +405,7 @@ struct XHCIEPContext { typedef struct XHCISlot { bool enabled; + bool addressed; dma_addr_t ctx; USBPort *uport; XHCIEPContext * eps[31]; @@ -442,7 +443,10 @@ typedef struct XHCIInterrupter { } XHCIInterrupter; struct XHCIState { - PCIDevice pci_dev; + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ + USBBus bus; qemu_irq irq; MemoryRegion mem; @@ -481,6 +485,11 @@ struct XHCIState { XHCIRing cmd_ring; }; +#define TYPE_XHCI "nec-usb-xhci" + +#define XHCI(obj) \ + OBJECT_CHECK(XHCIState, (obj), TYPE_XHCI) + typedef struct XHCIEvRingSeg { uint32_t addr_low; uint32_t addr_high; @@ -653,7 +662,7 @@ static inline void xhci_dma_read_u32s(XHCIState *xhci, dma_addr_t addr, assert((len % sizeof(uint32_t)) == 0); - pci_dma_read(&xhci->pci_dev, addr, buf, len); + pci_dma_read(PCI_DEVICE(xhci), addr, buf, len); for (i = 0; i < (len / sizeof(uint32_t)); i++) { buf[i] = le32_to_cpu(buf[i]); @@ -671,7 +680,7 @@ static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr, for (i = 0; i < (len / sizeof(uint32_t)); i++) { tmp[i] = cpu_to_le32(buf[i]); } - pci_dma_write(&xhci->pci_dev, addr, tmp, len); + pci_dma_write(PCI_DEVICE(xhci), addr, tmp, len); } static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport) @@ -698,10 +707,11 @@ static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport) static void xhci_intx_update(XHCIState *xhci) { + PCIDevice *pci_dev = PCI_DEVICE(xhci); int level = 0; - if (msix_enabled(&xhci->pci_dev) || - msi_enabled(&xhci->pci_dev)) { + if (msix_enabled(pci_dev) || + msi_enabled(pci_dev)) { return; } @@ -717,9 +727,10 @@ static void xhci_intx_update(XHCIState *xhci) static void xhci_msix_update(XHCIState *xhci, int v) { + PCIDevice *pci_dev = PCI_DEVICE(xhci); bool enabled; - if (!msix_enabled(&xhci->pci_dev)) { + if (!msix_enabled(pci_dev)) { return; } @@ -730,17 +741,19 @@ static void xhci_msix_update(XHCIState *xhci, int v) if (enabled) { trace_usb_xhci_irq_msix_use(v); - msix_vector_use(&xhci->pci_dev, v); + msix_vector_use(pci_dev, v); xhci->intr[v].msix_used = true; } else { trace_usb_xhci_irq_msix_unuse(v); - msix_vector_unuse(&xhci->pci_dev, v); + msix_vector_unuse(pci_dev, v); xhci->intr[v].msix_used = false; } } static void xhci_intr_raise(XHCIState *xhci, int v) { + PCIDevice *pci_dev = PCI_DEVICE(xhci); + xhci->intr[v].erdp_low |= ERDP_EHB; xhci->intr[v].iman |= IMAN_IP; xhci->usbsts |= USBSTS_EINT; @@ -753,15 +766,15 @@ static void xhci_intr_raise(XHCIState *xhci, int v) return; } - if (msix_enabled(&xhci->pci_dev)) { + if (msix_enabled(pci_dev)) { trace_usb_xhci_irq_msix(v); - msix_notify(&xhci->pci_dev, v); + msix_notify(pci_dev, v); return; } - if (msi_enabled(&xhci->pci_dev)) { + if (msi_enabled(pci_dev)) { trace_usb_xhci_irq_msi(v); - msi_notify(&xhci->pci_dev, v); + msi_notify(pci_dev, v); return; } @@ -784,6 +797,7 @@ static void xhci_die(XHCIState *xhci) static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v) { + PCIDevice *pci_dev = PCI_DEVICE(xhci); XHCIInterrupter *intr = &xhci->intr[v]; XHCITRB ev_trb; dma_addr_t addr; @@ -802,7 +816,7 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v) ev_trb.status, ev_trb.control); addr = intr->er_start + TRB_SIZE*intr->er_ep_idx; - pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE); + pci_dma_write(pci_dev, addr, &ev_trb, TRB_SIZE); intr->er_ep_idx++; if (intr->er_ep_idx >= intr->er_size) { @@ -949,9 +963,11 @@ static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring, static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb, dma_addr_t *addr) { + PCIDevice *pci_dev = PCI_DEVICE(xhci); + while (1) { TRBType type; - pci_dma_read(&xhci->pci_dev, ring->dequeue, trb, TRB_SIZE); + pci_dma_read(pci_dev, ring->dequeue, trb, TRB_SIZE); trb->addr = ring->dequeue; trb->ccs = ring->ccs; le64_to_cpus(&trb->parameter); @@ -984,6 +1000,7 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb, static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) { + PCIDevice *pci_dev = PCI_DEVICE(xhci); XHCITRB trb; int length = 0; dma_addr_t dequeue = ring->dequeue; @@ -993,7 +1010,7 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) while (1) { TRBType type; - pci_dma_read(&xhci->pci_dev, dequeue, &trb, TRB_SIZE); + pci_dma_read(pci_dev, dequeue, &trb, TRB_SIZE); le64_to_cpus(&trb.parameter); le32_to_cpus(&trb.status); le32_to_cpus(&trb.control); @@ -1045,7 +1062,7 @@ static void xhci_er_reset(XHCIState *xhci, int v) return; } dma_addr_t erstba = xhci_addr64(intr->erstba_low, intr->erstba_high); - pci_dma_read(&xhci->pci_dev, erstba, &seg, sizeof(seg)); + pci_dma_read(PCI_DEVICE(xhci), erstba, &seg, sizeof(seg)); le32_to_cpus(&seg.addr_low); le32_to_cpus(&seg.addr_high); le32_to_cpus(&seg.size); @@ -1197,31 +1214,30 @@ static void xhci_ep_kick_timer(void *opaque) xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid, 0); } -static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, - unsigned int epid, dma_addr_t pctx, - uint32_t *ctx) +static XHCIEPContext *xhci_alloc_epctx(XHCIState *xhci, + unsigned int slotid, + unsigned int epid) { - XHCISlot *slot; XHCIEPContext *epctx; - dma_addr_t dequeue; int i; - trace_usb_xhci_ep_enable(slotid, epid); - assert(slotid >= 1 && slotid <= xhci->numslots); - assert(epid >= 1 && epid <= 31); - - slot = &xhci->slots[slotid-1]; - if (slot->eps[epid-1]) { - xhci_disable_ep(xhci, slotid, epid); - } - - epctx = g_malloc(sizeof(XHCIEPContext)); - memset(epctx, 0, sizeof(XHCIEPContext)); + epctx = g_new0(XHCIEPContext, 1); epctx->xhci = xhci; epctx->slotid = slotid; epctx->epid = epid; - slot->eps[epid-1] = epctx; + for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) { + usb_packet_init(&epctx->transfers[i].packet); + } + epctx->kick_timer = qemu_new_timer_ns(vm_clock, xhci_ep_kick_timer, epctx); + + return epctx; +} + +static void xhci_init_epctx(XHCIEPContext *epctx, + dma_addr_t pctx, uint32_t *ctx) +{ + dma_addr_t dequeue; dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]); @@ -1237,16 +1253,34 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, if (epctx->max_pstreams) { xhci_alloc_streams(epctx, dequeue); } else { - xhci_ring_init(xhci, &epctx->ring, dequeue); + xhci_ring_init(epctx->xhci, &epctx->ring, dequeue); epctx->ring.ccs = ctx[2] & 1; } - for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) { - usb_packet_init(&epctx->transfers[i].packet); - } epctx->interval = 1 << (ctx[0] >> 16) & 0xff; +} + +static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, + unsigned int epid, dma_addr_t pctx, + uint32_t *ctx) +{ + XHCISlot *slot; + XHCIEPContext *epctx; + + trace_usb_xhci_ep_enable(slotid, epid); + assert(slotid >= 1 && slotid <= xhci->numslots); + assert(epid >= 1 && epid <= 31); + + slot = &xhci->slots[slotid-1]; + if (slot->eps[epid-1]) { + xhci_disable_ep(xhci, slotid, epid); + } + + epctx = xhci_alloc_epctx(xhci, slotid, epid); + slot->eps[epid-1] = epctx; + xhci_init_epctx(epctx, pctx, ctx); + epctx->mfindex_last = 0; - epctx->kick_timer = qemu_new_timer_ns(vm_clock, xhci_ep_kick_timer, epctx); epctx->state = EP_RUNNING; ctx[0] &= ~EP_STATE_MASK; @@ -1395,7 +1429,6 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid, { XHCISlot *slot; XHCIEPContext *epctx; - USBDevice *dev; trace_usb_xhci_ep_reset(slotid, epid); assert(slotid >= 1 && slotid <= xhci->numslots); @@ -1431,8 +1464,8 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid, ep |= 0x80; } - dev = xhci->slots[slotid-1].uport->dev; - if (!dev) { + if (!xhci->slots[slotid-1].uport || + !xhci->slots[slotid-1].uport->dev) { return CC_USB_TRANSACTION_ERROR; } @@ -1503,7 +1536,7 @@ static int xhci_xfer_create_sgl(XHCITransfer *xfer, int in_xfer) int i; xfer->int_req = false; - pci_dma_sglist_init(&xfer->sgl, &xhci->pci_dev, xfer->trb_count); + pci_dma_sglist_init(&xfer->sgl, PCI_DEVICE(xhci), xfer->trb_count); for (i = 0; i < xfer->trb_count; i++) { XHCITRB *trb = &xfer->trbs[i]; dma_addr_t addr; @@ -1707,6 +1740,7 @@ static int xhci_complete_packet(XHCITransfer *xfer) trace_usb_xhci_xfer_error(xfer, xfer->packet.status); switch (xfer->packet.status) { case USB_RET_NODEV: + case USB_RET_IOERROR: xfer->status = CC_USB_TRANSACTION_ERROR; xhci_xfer_report(xfer); xhci_stall_ep(xfer); @@ -2041,6 +2075,7 @@ static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid) } xhci->slots[slotid-1].enabled = 0; + xhci->slots[slotid-1].addressed = 0; return CC_SUCCESS; } @@ -2087,7 +2122,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, assert(slotid >= 1 && slotid <= xhci->numslots); dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high); - poctx = ldq_le_pci_dma(&xhci->pci_dev, dcbaap + 8*slotid); + poctx = ldq_le_pci_dma(PCI_DEVICE(xhci), dcbaap + 8 * slotid); ictx = xhci_mask64(pictx); octx = xhci_mask64(poctx); @@ -2167,6 +2202,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx)); xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx)); + xhci->slots[slotid-1].addressed = 1; return res; } @@ -2407,7 +2443,7 @@ static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) /* TODO: actually implement real values here */ bw_ctx[0] = 0; memset(&bw_ctx[1], 80, xhci->numports); /* 80% */ - pci_dma_write(&xhci->pci_dev, ctx, bw_ctx, sizeof(bw_ctx)); + pci_dma_write(PCI_DEVICE(xhci), ctx, bw_ctx, sizeof(bw_ctx)); return CC_SUCCESS; } @@ -2430,11 +2466,12 @@ static uint32_t xhci_nec_challenge(uint32_t hi, uint32_t lo) static void xhci_via_challenge(XHCIState *xhci, uint64_t addr) { + PCIDevice *pci_dev = PCI_DEVICE(xhci); uint32_t buf[8]; uint32_t obuf[8]; dma_addr_t paddr = xhci_mask64(addr); - pci_dma_read(&xhci->pci_dev, paddr, &buf, 32); + pci_dma_read(pci_dev, paddr, &buf, 32); memcpy(obuf, buf, sizeof(obuf)); @@ -2450,7 +2487,7 @@ static void xhci_via_challenge(XHCIState *xhci, uint64_t addr) obuf[7] = obuf[2] ^ obuf[3] ^ 0x65866593; } - pci_dma_write(&xhci->pci_dev, paddr, &obuf, 32); + pci_dma_write(pci_dev, paddr, &obuf, 32); } static void xhci_process_commands(XHCIState *xhci) @@ -2635,7 +2672,7 @@ static void xhci_port_update(XHCIPort *port, int is_detach) xhci_port_notify(port, PORTSC_CSC); } -static void xhci_port_reset(XHCIPort *port) +static void xhci_port_reset(XHCIPort *port, bool warm_reset) { trace_usb_xhci_port_reset(port->portnr); @@ -2646,6 +2683,11 @@ static void xhci_port_reset(XHCIPort *port) usb_device_reset(port->uport->dev); switch (port->uport->dev->speed) { + case USB_SPEED_SUPER: + if (warm_reset) { + port->portsc |= PORTSC_WRC; + } + /* fall through */ case USB_SPEED_LOW: case USB_SPEED_FULL: case USB_SPEED_HIGH: @@ -2661,7 +2703,7 @@ static void xhci_port_reset(XHCIPort *port) static void xhci_reset(DeviceState *dev) { - XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev.qdev, dev); + XHCIState *xhci = XHCI(dev); int i; trace_usb_xhci_reset(); @@ -2808,8 +2850,12 @@ static void xhci_port_write(void *ptr, hwaddr reg, switch (reg) { case 0x00: /* PORTSC */ /* write-1-to-start bits */ + if (val & PORTSC_WPR) { + xhci_port_reset(port, true); + break; + } if (val & PORTSC_PR) { - xhci_port_reset(port); + xhci_port_reset(port, false); break; } @@ -2906,6 +2952,7 @@ static void xhci_oper_write(void *ptr, hwaddr reg, uint64_t val, unsigned size) { XHCIState *xhci = ptr; + DeviceState *d = DEVICE(ptr); trace_usb_xhci_oper_write(reg, val); @@ -2919,7 +2966,7 @@ static void xhci_oper_write(void *ptr, hwaddr reg, xhci->usbcmd = val & 0xc0f; xhci_mfwrap_update(xhci); if (val & USBCMD_HCRST) { - xhci_reset(&xhci->pci_dev.qdev); + xhci_reset(d); } xhci_intx_update(xhci); break; @@ -3245,8 +3292,9 @@ static USBBusOps xhci_bus_ops = { .wakeup_endpoint = xhci_wakeup_endpoint, }; -static void usb_xhci_init(XHCIState *xhci, DeviceState *dev) +static void usb_xhci_init(XHCIState *xhci) { + DeviceState *dev = DEVICE(xhci); XHCIPort *port; int i, usbports, speedmask; @@ -3261,7 +3309,7 @@ static void usb_xhci_init(XHCIState *xhci, DeviceState *dev) usbports = MAX(xhci->numports_2, xhci->numports_3); xhci->numports = xhci->numports_2 + xhci->numports_3; - usb_bus_new(&xhci->bus, &xhci_bus_ops, &xhci->pci_dev.qdev); + usb_bus_new(&xhci->bus, &xhci_bus_ops, dev); for (i = 0; i < usbports; i++) { speedmask = 0; @@ -3293,14 +3341,14 @@ static int usb_xhci_initfn(struct PCIDevice *dev) { int i, ret; - XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev); + XHCIState *xhci = XHCI(dev); - xhci->pci_dev.config[PCI_CLASS_PROG] = 0x30; /* xHCI */ - xhci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */ - xhci->pci_dev.config[PCI_CACHE_LINE_SIZE] = 0x10; - xhci->pci_dev.config[0x60] = 0x30; /* release number */ + dev->config[PCI_CLASS_PROG] = 0x30; /* xHCI */ + dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */ + dev->config[PCI_CACHE_LINE_SIZE] = 0x10; + dev->config[0x60] = 0x30; /* release number */ - usb_xhci_init(xhci, &dev->qdev); + usb_xhci_init(xhci); if (xhci->numintrs > MAXINTRS) { xhci->numintrs = MAXINTRS; @@ -3320,16 +3368,16 @@ static int usb_xhci_initfn(struct PCIDevice *dev) xhci->mfwrap_timer = qemu_new_timer_ns(vm_clock, xhci_mfwrap_timer, xhci); - xhci->irq = xhci->pci_dev.irq[0]; + xhci->irq = dev->irq[0]; - memory_region_init(&xhci->mem, "xhci", LEN_REGS); - memory_region_init_io(&xhci->mem_cap, &xhci_cap_ops, xhci, + memory_region_init(&xhci->mem, OBJECT(xhci), "xhci", LEN_REGS); + memory_region_init_io(&xhci->mem_cap, OBJECT(xhci), &xhci_cap_ops, xhci, "capabilities", LEN_CAP); - memory_region_init_io(&xhci->mem_oper, &xhci_oper_ops, xhci, + memory_region_init_io(&xhci->mem_oper, OBJECT(xhci), &xhci_oper_ops, xhci, "operational", 0x400); - memory_region_init_io(&xhci->mem_runtime, &xhci_runtime_ops, xhci, + memory_region_init_io(&xhci->mem_runtime, OBJECT(xhci), &xhci_runtime_ops, xhci, "runtime", LEN_RUNTIME); - memory_region_init_io(&xhci->mem_doorbell, &xhci_doorbell_ops, xhci, + memory_region_init_io(&xhci->mem_doorbell, OBJECT(xhci), &xhci_doorbell_ops, xhci, "doorbell", LEN_DOORBELL); memory_region_add_subregion(&xhci->mem, 0, &xhci->mem_cap); @@ -3341,23 +3389,23 @@ static int usb_xhci_initfn(struct PCIDevice *dev) XHCIPort *port = &xhci->ports[i]; uint32_t offset = OFF_OPER + 0x400 + 0x10 * i; port->xhci = xhci; - memory_region_init_io(&port->mem, &xhci_port_ops, port, + memory_region_init_io(&port->mem, OBJECT(xhci), &xhci_port_ops, port, port->name, 0x10); memory_region_add_subregion(&xhci->mem, offset, &port->mem); } - pci_register_bar(&xhci->pci_dev, 0, + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64, &xhci->mem); - ret = pcie_endpoint_cap_init(&xhci->pci_dev, 0xa0); + ret = pcie_endpoint_cap_init(dev, 0xa0); assert(ret >= 0); if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) { - msi_init(&xhci->pci_dev, 0x70, xhci->numintrs, true, false); + msi_init(dev, 0x70, xhci->numintrs, true, false); } if (xhci->flags & (1 << XHCI_FLAG_USE_MSI_X)) { - msix_init(&xhci->pci_dev, xhci->numintrs, + msix_init(dev, xhci->numintrs, &xhci->mem, 0, OFF_MSIX_TABLE, &xhci->mem, 0, OFF_MSIX_PBA, 0x90); @@ -3366,9 +3414,172 @@ static int usb_xhci_initfn(struct PCIDevice *dev) return 0; } +static int usb_xhci_post_load(void *opaque, int version_id) +{ + XHCIState *xhci = opaque; + PCIDevice *pci_dev = PCI_DEVICE(xhci); + XHCISlot *slot; + XHCIEPContext *epctx; + dma_addr_t dcbaap, pctx; + uint32_t slot_ctx[4]; + uint32_t ep_ctx[5]; + int slotid, epid, state, intr; + + dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high); + + for (slotid = 1; slotid <= xhci->numslots; slotid++) { + slot = &xhci->slots[slotid-1]; + if (!slot->addressed) { + continue; + } + slot->ctx = + xhci_mask64(ldq_le_pci_dma(pci_dev, dcbaap + 8 * slotid)); + xhci_dma_read_u32s(xhci, slot->ctx, slot_ctx, sizeof(slot_ctx)); + slot->uport = xhci_lookup_uport(xhci, slot_ctx); + assert(slot->uport && slot->uport->dev); + + for (epid = 1; epid <= 32; epid++) { + pctx = slot->ctx + 32 * epid; + xhci_dma_read_u32s(xhci, pctx, ep_ctx, sizeof(ep_ctx)); + state = ep_ctx[0] & EP_STATE_MASK; + if (state == EP_DISABLED) { + continue; + } + epctx = xhci_alloc_epctx(xhci, slotid, epid); + slot->eps[epid-1] = epctx; + xhci_init_epctx(epctx, pctx, ep_ctx); + epctx->state = state; + if (state == EP_RUNNING) { + /* kick endpoint after vmload is finished */ + qemu_mod_timer(epctx->kick_timer, qemu_get_clock_ns(vm_clock)); + } + } + } + + for (intr = 0; intr < xhci->numintrs; intr++) { + if (xhci->intr[intr].msix_used) { + msix_vector_use(pci_dev, intr); + } else { + msix_vector_unuse(pci_dev, intr); + } + } + + return 0; +} + +static const VMStateDescription vmstate_xhci_ring = { + .name = "xhci-ring", + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(dequeue, XHCIRing), + VMSTATE_BOOL(ccs, XHCIRing), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_xhci_port = { + .name = "xhci-port", + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(portsc, XHCIPort), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_xhci_slot = { + .name = "xhci-slot", + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_BOOL(enabled, XHCISlot), + VMSTATE_BOOL(addressed, XHCISlot), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_xhci_event = { + .name = "xhci-event", + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(type, XHCIEvent), + VMSTATE_UINT32(ccode, XHCIEvent), + VMSTATE_UINT64(ptr, XHCIEvent), + VMSTATE_UINT32(length, XHCIEvent), + VMSTATE_UINT32(flags, XHCIEvent), + VMSTATE_UINT8(slotid, XHCIEvent), + VMSTATE_UINT8(epid, XHCIEvent), + } +}; + +static bool xhci_er_full(void *opaque, int version_id) +{ + struct XHCIInterrupter *intr = opaque; + return intr->er_full; +} + +static const VMStateDescription vmstate_xhci_intr = { + .name = "xhci-intr", + .version_id = 1, + .fields = (VMStateField[]) { + /* registers */ + VMSTATE_UINT32(iman, XHCIInterrupter), + VMSTATE_UINT32(imod, XHCIInterrupter), + VMSTATE_UINT32(erstsz, XHCIInterrupter), + VMSTATE_UINT32(erstba_low, XHCIInterrupter), + VMSTATE_UINT32(erstba_high, XHCIInterrupter), + VMSTATE_UINT32(erdp_low, XHCIInterrupter), + VMSTATE_UINT32(erdp_high, XHCIInterrupter), + + /* state */ + VMSTATE_BOOL(msix_used, XHCIInterrupter), + VMSTATE_BOOL(er_pcs, XHCIInterrupter), + VMSTATE_UINT64(er_start, XHCIInterrupter), + VMSTATE_UINT32(er_size, XHCIInterrupter), + VMSTATE_UINT32(er_ep_idx, XHCIInterrupter), + + /* event queue (used if ring is full) */ + VMSTATE_BOOL(er_full, XHCIInterrupter), + VMSTATE_UINT32_TEST(ev_buffer_put, XHCIInterrupter, xhci_er_full), + VMSTATE_UINT32_TEST(ev_buffer_get, XHCIInterrupter, xhci_er_full), + VMSTATE_STRUCT_ARRAY_TEST(ev_buffer, XHCIInterrupter, EV_QUEUE, + xhci_er_full, 1, + vmstate_xhci_event, XHCIEvent), + + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_xhci = { .name = "xhci", - .unmigratable = 1, + .version_id = 1, + .post_load = usb_xhci_post_load, + .fields = (VMStateField[]) { + VMSTATE_PCIE_DEVICE(parent_obj, XHCIState), + VMSTATE_MSIX(parent_obj, XHCIState), + + VMSTATE_STRUCT_VARRAY_UINT32(ports, XHCIState, numports, 1, + vmstate_xhci_port, XHCIPort), + VMSTATE_STRUCT_VARRAY_UINT32(slots, XHCIState, numslots, 1, + vmstate_xhci_slot, XHCISlot), + VMSTATE_STRUCT_VARRAY_UINT32(intr, XHCIState, numintrs, 1, + vmstate_xhci_intr, XHCIInterrupter), + + /* Operational Registers */ + VMSTATE_UINT32(usbcmd, XHCIState), + VMSTATE_UINT32(usbsts, XHCIState), + VMSTATE_UINT32(dnctrl, XHCIState), + VMSTATE_UINT32(crcr_low, XHCIState), + VMSTATE_UINT32(crcr_high, XHCIState), + VMSTATE_UINT32(dcbaap_low, XHCIState), + VMSTATE_UINT32(dcbaap_high, XHCIState), + VMSTATE_UINT32(config, XHCIState), + + /* Runtime Registers & state */ + VMSTATE_INT64(mfindex_start, XHCIState), + VMSTATE_TIMER(mfwrap_timer, XHCIState), + VMSTATE_STRUCT(cmd_ring, XHCIState, 1, vmstate_xhci_ring, XHCIRing), + + VMSTATE_END_OF_LIST() + } }; static Property xhci_properties[] = { @@ -3389,6 +3600,7 @@ static void xhci_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_xhci; dc->props = xhci_properties; dc->reset = xhci_reset; + set_bit(DEVICE_CATEGORY_USB, dc->categories); k->init = usb_xhci_initfn; k->vendor_id = PCI_VENDOR_ID_NEC; k->device_id = PCI_DEVICE_ID_NEC_UPD720200; @@ -3399,7 +3611,7 @@ static void xhci_class_init(ObjectClass *klass, void *data) } static const TypeInfo xhci_info = { - .name = "nec-usb-xhci", + .name = TYPE_XHCI, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(XHCIState), .class_init = xhci_class_init, diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index 3a582c526d..f660770076 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -241,7 +241,11 @@ static int usb_host_get_port(libusb_device *dev, char *port, size_t len) size_t off; int rc, i; +#if LIBUSBX_API_VERSION >= 0x01000102 + rc = libusb_get_port_numbers(dev, path, 7); +#else rc = libusb_get_port_path(ctx, dev, path, 7); +#endif if (rc < 0) { return 0; } @@ -891,6 +895,7 @@ static int usb_host_initfn(USBDevice *udev) USBHostDevice *s = USB_HOST_DEVICE(udev); loglevel = s->loglevel; + udev->flags |= (1 << USB_DEV_FLAG_IS_HOST); udev->auto_attach = 0; QTAILQ_INIT(&s->requests); QTAILQ_INIT(&s->isorings); @@ -1346,6 +1351,7 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) uc->flush_ep_queue = usb_host_flush_ep_queue; dc->vmsd = &vmstate_usb_host; dc->props = usb_host_dev_properties; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } static TypeInfo usb_host_dev_info = { diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index ca09a891ee..7901f4c01a 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1530,6 +1530,7 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) uc->handle_destroy = usb_host_handle_destroy; dc->vmsd = &vmstate_usb_host; dc->props = usb_host_dev_properties; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } static const TypeInfo usb_host_dev_info = { diff --git a/hw/usb/libhw.c b/hw/usb/libhw.c index d2d4b51b94..8df11c461f 100644 --- a/hw/usb/libhw.c +++ b/hw/usb/libhw.c @@ -37,7 +37,7 @@ int usb_packet_map(USBPacket *p, QEMUSGList *sgl) while (len) { dma_addr_t xlen = len; - mem = dma_memory_map(sgl->dma, base, &xlen, dir); + mem = dma_memory_map(sgl->as, base, &xlen, dir); if (!mem) { goto err; } @@ -63,7 +63,7 @@ void usb_packet_unmap(USBPacket *p, QEMUSGList *sgl) int i; for (i = 0; i < p->iov.niov; i++) { - dma_memory_unmap(sgl->dma, p->iov.iov[i].iov_base, + dma_memory_unmap(sgl->as, p->iov.iov[i].iov_base, p->iov.iov[i].iov_len, dir, p->iov.iov[i].iov_len); } diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index a594e954e4..e3b9f324b3 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -1334,6 +1334,7 @@ static void usbredir_handle_destroy(USBDevice *udev) USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); qemu_chr_delete(dev->cs); + dev->cs = NULL; /* Note must be done after qemu_chr_close, as that causes a close event */ qemu_bh_delete(dev->chardev_close_bh); @@ -2362,6 +2363,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) uc->ep_stopped = usbredir_ep_stopped; dc->vmsd = &usbredir_vmstate; dc->props = usbredir_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo usbredir_dev_info = { |