Hi Thomas, On 4/18/19 1:10 PM, Thomas Huth wrote: > Some machines (like the pxa2xx-based ARM machines) only have a sysbus > OHCI controller, but no PCI. With the new Kconfig-style build system, > it will soon be possible to create QEMU binaries that only contain > such PCI-less machines. However, the two OHCI controllers, for sysbus > and for PCI, are currently both located in one file, so the PCI code > is still required for linking here. Move the OHCI-PCI device code > into a separate file, so that it is possible to use the sysbus OHCI > device also without the PCI dependency. > > Apart from moving code to a new file (and a new header), this patch > might also fix one subtle bug: The ohci_die() function always assumed > to be running with a OHCI-PCI controller and called some PCI-specific > functions - but if I got the code right, ohci_die() might also get > called for the sysbus-OHCI device, so it likely failed in that case. > I've changed this part of the code now, so that there are two ohci_die() > implementations now, one for sysbus and one for PCI.
Can this be done in 2 patches? > Signed-off-by: Thomas Huth <th...@redhat.com> > --- > hw/usb/Kconfig | 6 +- > hw/usb/Makefile.objs | 1 + > hw/usb/hcd-ohci-pci.c | 166 ++++++++++++++++++++++++++++ > hw/usb/hcd-ohci.c | 244 +++--------------------------------------- > hw/usb/hcd-ohci.h | 132 +++++++++++++++++++++++ > 5 files changed, 321 insertions(+), 228 deletions(-) > create mode 100644 hw/usb/hcd-ohci-pci.c > create mode 100644 hw/usb/hcd-ohci.h > > diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig > index a1b7acb12a..564305e283 100644 > --- a/hw/usb/Kconfig > +++ b/hw/usb/Kconfig > @@ -8,10 +8,14 @@ config USB_UHCI > select USB > > config USB_OHCI > + bool > + select USB > + > +config USB_OHCI_PCI > bool > default y if PCI_DEVICES > depends on PCI > - select USB > + select USB_OHCI > > config USB_EHCI > bool > diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs > index 2b929649ac..81688f6e70 100644 > --- a/hw/usb/Makefile.objs > +++ b/hw/usb/Makefile.objs > @@ -5,6 +5,7 @@ common-obj-$(CONFIG_USB) += desc.o desc-msos.o > # usb host adapters > common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o > common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o > +common-obj-$(CONFIG_USB_OHCI_PCI) += hcd-ohci-pci.o > common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o > common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci.o hcd-ehci-sysbus.o > common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o > diff --git a/hw/usb/hcd-ohci-pci.c b/hw/usb/hcd-ohci-pci.c > new file mode 100644 > index 0000000000..e972df35c9 > --- /dev/null > +++ b/hw/usb/hcd-ohci-pci.c > @@ -0,0 +1,166 @@ > +/* > + * QEMU USB OHCI Emulation > + * Copyright (c) 2004 Gianni Tedesco > + * Copyright (c) 2006 CodeSourcery > + * Copyright (c) 2006 Openedhand Ltd. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see > <http://www.gnu.org/licenses/>. > + */ > + > +#include "qemu/osdep.h" > +#include "hw/hw.h" > +#include "qapi/error.h" > +#include "qemu/timer.h" > +#include "hw/usb.h" > +#include "hw/pci/pci.h" > +#include "hw/sysbus.h" > +#include "hw/qdev-dma.h" > +#include "trace.h" > +#include "hcd-ohci.h" > + > +#define TYPE_PCI_OHCI "pci-ohci" > +#define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI) > + > +typedef struct { > + /*< private >*/ > + PCIDevice parent_obj; > + /*< public >*/ > + > + OHCIState state; > + char *masterbus; > + uint32_t num_ports; > + uint32_t firstport; > +} OHCIPCIState; > + > +/** > + * 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_pci_die(OHCIState *ohci) > +{ > + OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state); > + > + trace_usb_ohci_die(); > + > + 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 void usb_ohci_realize_pci(PCIDevice *dev, Error **errp) > +{ > + Error *err = NULL; > + OHCIPCIState *ohci = PCI_OHCI(dev); > + > + dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */ > + dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ > + > + usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0, > + ohci->masterbus, ohci->firstport, > + pci_get_address_space(dev), ohci_pci_die, &err); > + if (err) { > + error_propagate(errp, err); > + return; > + } > + > + ohci->state.irq = pci_allocate_irq(dev); > + pci_register_bar(dev, 0, 0, &ohci->state.mem); > +} > + > +static void usb_ohci_exit(PCIDevice *dev) > +{ > + OHCIPCIState *ohci = PCI_OHCI(dev); > + OHCIState *s = &ohci->state; > + > + trace_usb_ohci_exit(s->name); > + ohci_bus_stop(s); > + > + if (s->async_td) { > + usb_cancel_packet(&s->usb_packet); > + s->async_td = 0; > + } > + ohci_stop_endpoints(s); > + > + if (!ohci->masterbus) { > + usb_bus_release(&s->bus); > + } > + > + timer_del(s->eof_timer); > + timer_free(s->eof_timer); > +} > + > +static void usb_ohci_reset_pci(DeviceState *d) > +{ > + PCIDevice *dev = PCI_DEVICE(d); > + OHCIPCIState *ohci = PCI_OHCI(dev); > + OHCIState *s = &ohci->state; > + > + ohci_hard_reset(s); > +} > + > +static Property ohci_pci_properties[] = { > + DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus), > + DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3), > + DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > +static const VMStateDescription vmstate_ohci = { > + .name = "ohci", > + .version_id = 1, > + .minimum_version_id = 1, > + .fields = (VMStateField[]) { > + VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState), > + VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, > OHCIState), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static void ohci_pci_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); > + > + k->realize = usb_ohci_realize_pci; > + k->exit = usb_ohci_exit; > + k->vendor_id = PCI_VENDOR_ID_APPLE; > + k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB; > + k->class_id = PCI_CLASS_SERIAL_USB; > + set_bit(DEVICE_CATEGORY_USB, dc->categories); > + dc->desc = "Apple USB Controller"; > + dc->props = ohci_pci_properties; > + dc->hotpluggable = false; > + dc->vmsd = &vmstate_ohci; > + dc->reset = usb_ohci_reset_pci; > +} > + > +static const TypeInfo ohci_pci_info = { > + .name = TYPE_PCI_OHCI, > + .parent = TYPE_PCI_DEVICE, > + .instance_size = sizeof(OHCIPCIState), > + .class_init = ohci_pci_class_init, > + .interfaces = (InterfaceInfo[]) { > + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, > + { }, > + }, > +}; > + > +static void ohci_pci_register_types(void) > +{ > + type_register_static(&ohci_pci_info); > +} > + > +type_init(ohci_pci_register_types) > diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c > index 81cf5ab7a5..343816d561 100644 > --- a/hw/usb/hcd-ohci.c > +++ b/hw/usb/hcd-ohci.c > @@ -30,86 +30,19 @@ > #include "qapi/error.h" > #include "qemu/timer.h" > #include "hw/usb.h" > -#include "hw/pci/pci.h" > #include "hw/sysbus.h" > #include "hw/qdev-dma.h" > #include "trace.h" > +#include "hcd-ohci.h" > > /* This causes frames to occur 1000x slower */ > //#define OHCI_TIME_WARP 1 > > -/* Number of Downstream Ports on the root hub. */ > - > -#define OHCI_MAX_PORTS 15 > - > #define ED_LINK_LIMIT 32 > > static int64_t usb_frame_time; > static int64_t usb_bit_time; > > -typedef struct OHCIPort { > - USBPort port; > - uint32_t ctrl; > -} OHCIPort; > - > -typedef struct { > - USBBus bus; > - qemu_irq irq; > - MemoryRegion mem; > - AddressSpace *as; > - uint32_t num_ports; > - const char *name; > - > - QEMUTimer *eof_timer; > - int64_t sof_time; > - > - /* OHCI state */ > - /* Control partition */ > - uint32_t ctl, status; > - uint32_t intr_status; > - uint32_t intr; > - > - /* memory pointer partition */ > - uint32_t hcca; > - uint32_t ctrl_head, ctrl_cur; > - uint32_t bulk_head, bulk_cur; > - uint32_t per_cur; > - uint32_t done; > - int32_t done_count; > - > - /* Frame counter partition */ > - uint16_t fsmps; > - uint8_t fit; > - uint16_t fi; > - uint8_t frt; > - uint16_t frame_number; > - uint16_t padding; > - uint32_t pstart; > - uint32_t lst; > - > - /* Root Hub partition */ > - uint32_t rhdesc_a, rhdesc_b; > - uint32_t rhstatus; > - OHCIPort rhport[OHCI_MAX_PORTS]; > - > - /* PXA27x Non-OHCI events */ > - uint32_t hstatus; > - uint32_t hmask; > - uint32_t hreset; > - uint32_t htest; > - > - /* SM501 local memory offset */ > - dma_addr_t localmem_base; > - > - /* Active packets. */ > - uint32_t old_ctl; > - USBPacket usb_packet; > - uint8_t usb_buf[8192]; > - uint32_t async_td; > - bool async_complete; > - > -} OHCIState; > - > /* Host Controller Communications Area */ > struct ohci_hcca { > uint32_t intr[32]; > @@ -122,7 +55,6 @@ struct ohci_hcca { > #define ED_WBACK_OFFSET offsetof(struct ohci_ed, head) > #define ED_WBACK_SIZE 4 > > -static void ohci_bus_stop(OHCIState *ohci); > static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev); > > /* Bitfields for the first word of an Endpoint Desciptor. */ > @@ -229,16 +161,6 @@ struct ohci_iso_td { > #define OHCI_STATUS_OCR (1<<3) > #define OHCI_STATUS_SOC ((1<<6)|(1<<7)) > > -#define OHCI_INTR_SO (1U<<0) /* Scheduling overrun */ > -#define OHCI_INTR_WD (1U<<1) /* HcDoneHead writeback */ > -#define OHCI_INTR_SF (1U<<2) /* Start of frame */ > -#define OHCI_INTR_RD (1U<<3) /* Resume detect */ > -#define OHCI_INTR_UE (1U<<4) /* Unrecoverable error */ > -#define OHCI_INTR_FNO (1U<<5) /* Frame number overflow */ > -#define OHCI_INTR_RHSC (1U<<6) /* Root hub status change */ > -#define OHCI_INTR_OC (1U<<30) /* Ownership change */ > -#define OHCI_INTR_MIE (1U<<31) /* Master Interrupt Enable */ > - > #define OHCI_HCCA_SIZE 0x100 > #define OHCI_HCCA_MASK 0xffffff00 > > @@ -302,25 +224,9 @@ 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) > +static inline void ohci_die(OHCIState *ohci) > { > - int level = 0; > - > - if ((ohci->intr & OHCI_INTR_MIE) && > - (ohci->intr_status & ohci->intr)) > - level = 1; > - > - qemu_set_irq(ohci->irq, level); > -} > - > -/* Set an interrupt */ > -static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) > -{ > - ohci->intr_status |= intr; > - ohci_intr_update(ohci); > + ohci->ohci_die(ohci); > } > > /* Attach or detach a device on a root hub port. */ > @@ -426,7 +332,7 @@ static USBDevice *ohci_find_device(OHCIState *ohci, > uint8_t addr) > return NULL; > } > > -static void ohci_stop_endpoints(OHCIState *ohci) > +void ohci_stop_endpoints(OHCIState *ohci) > { > USBDevice *dev; > int i, j; > @@ -498,7 +404,7 @@ static void ohci_soft_reset(OHCIState *ohci) > ohci->lst = OHCI_LS_THRESH; > } > > -static void ohci_hard_reset(OHCIState *ohci) > +void ohci_hard_reset(OHCIState *ohci) > { > ohci_soft_reset(ohci); > ohci->ctl = 0; > @@ -1372,7 +1278,7 @@ static int ohci_bus_start(OHCIState *ohci) > } > > /* Stop sending SOF tokens on the bus */ > -static void ohci_bus_stop(OHCIState *ohci) > +void ohci_bus_stop(OHCIState *ohci) > { > trace_usb_ohci_stop(ohci->name); > timer_del(ohci->eof_timer); > @@ -1852,15 +1758,16 @@ static USBPortOps ohci_port_ops = { > static USBBusOps ohci_bus_ops = { > }; > > -static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, > - uint32_t num_ports, dma_addr_t localmem_base, > - char *masterbus, uint32_t firstport, > - AddressSpace *as, Error **errp) > +void usb_ohci_init(OHCIState *ohci, DeviceState *dev, uint32_t num_ports, > + dma_addr_t localmem_base, char *masterbus, > + uint32_t firstport, AddressSpace *as, > + void (*ohci_die_func)(OHCIState *ohci), Error **errp) > { > Error *err = NULL; > int i; > > ohci->as = as; > + ohci->ohci_die = ohci_die_func; > > if (num_ports > OHCI_MAX_PORTS) { > error_setg(errp, "OHCI num-ports=%u is too big (limit is %u ports)", > @@ -1919,85 +1826,16 @@ static void usb_ohci_init(OHCIState *ohci, > DeviceState *dev, > ohci_frame_boundary, ohci); > } > > -#define TYPE_PCI_OHCI "pci-ohci" > -#define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI) > - > -typedef struct { > - /*< private >*/ > - PCIDevice parent_obj; > - /*< public >*/ > - > - OHCIState state; > - char *masterbus; > - uint32_t num_ports; > - uint32_t firstport; > -} OHCIPCIState; > - > -/** 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 > +/** > + * A typical O/EHCI will stop operating, set itself into error state > + * (which can be queried by MMIO) to signal that it got an error > */ > -static void ohci_die(OHCIState *ohci) > +static void ohci_sysbus_die(OHCIState *ohci) > { > - OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state); > - > trace_usb_ohci_die(); > > 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 void usb_ohci_realize_pci(PCIDevice *dev, Error **errp) > -{ > - Error *err = NULL; > - OHCIPCIState *ohci = PCI_OHCI(dev); > - > - dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */ > - dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ > - > - usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0, > - ohci->masterbus, ohci->firstport, > - pci_get_address_space(dev), &err); > - if (err) { > - error_propagate(errp, err); > - return; > - } > - > - ohci->state.irq = pci_allocate_irq(dev); > - pci_register_bar(dev, 0, 0, &ohci->state.mem); > -} > - > -static void usb_ohci_exit(PCIDevice *dev) > -{ > - OHCIPCIState *ohci = PCI_OHCI(dev); > - OHCIState *s = &ohci->state; > - > - trace_usb_ohci_exit(s->name); > - ohci_bus_stop(s); > - > - if (s->async_td) { > - usb_cancel_packet(&s->usb_packet); > - s->async_td = 0; > - } > - ohci_stop_endpoints(s); > - > - if (!ohci->masterbus) { > - usb_bus_release(&s->bus); > - } > - > - timer_del(s->eof_timer); > - timer_free(s->eof_timer); > -} > - > -static void usb_ohci_reset_pci(DeviceState *d) > -{ > - PCIDevice *dev = PCI_DEVICE(d); > - OHCIPCIState *ohci = PCI_OHCI(dev); > - OHCIState *s = &ohci->state; > - > - ohci_hard_reset(s); > } > > #define TYPE_SYSBUS_OHCI "sysbus-ohci" > @@ -2023,7 +1861,7 @@ static void ohci_realize_pxa(DeviceState *dev, Error > **errp) > > usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset, > s->masterbus, s->firstport, > - &address_space_memory, &err); > + &address_space_memory, ohci_sysbus_die, &err); > if (err) { > error_propagate(errp, err); > return; > @@ -2040,13 +1878,6 @@ static void usb_ohci_reset_sysbus(DeviceState *dev) > ohci_hard_reset(ohci); > } > > -static Property ohci_pci_properties[] = { > - DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus), > - DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3), > - DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0), > - DEFINE_PROP_END_OF_LIST(), > -}; > - > static const VMStateDescription vmstate_ohci_state_port = { > .name = "ohci-core/port", > .version_id = 1, > @@ -2075,7 +1906,7 @@ static const VMStateDescription vmstate_ohci_eof_timer > = { > }, > }; > > -static const VMStateDescription vmstate_ohci_state = { > +const VMStateDescription vmstate_ohci_state = { > .name = "ohci-core", > .version_id = 1, > .minimum_version_id = 1, > @@ -2122,46 +1953,6 @@ static const VMStateDescription vmstate_ohci_state = { > } > }; > > -static const VMStateDescription vmstate_ohci = { > - .name = "ohci", > - .version_id = 1, > - .minimum_version_id = 1, > - .fields = (VMStateField[]) { > - VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState), > - VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, > OHCIState), > - VMSTATE_END_OF_LIST() > - } > -}; > - > -static void ohci_pci_class_init(ObjectClass *klass, void *data) > -{ > - DeviceClass *dc = DEVICE_CLASS(klass); > - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); > - > - k->realize = usb_ohci_realize_pci; > - k->exit = usb_ohci_exit; > - k->vendor_id = PCI_VENDOR_ID_APPLE; > - k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB; > - k->class_id = PCI_CLASS_SERIAL_USB; > - set_bit(DEVICE_CATEGORY_USB, dc->categories); > - dc->desc = "Apple USB Controller"; > - dc->props = ohci_pci_properties; > - dc->hotpluggable = false; > - dc->vmsd = &vmstate_ohci; > - dc->reset = usb_ohci_reset_pci; > -} > - > -static const TypeInfo ohci_pci_info = { > - .name = TYPE_PCI_OHCI, > - .parent = TYPE_PCI_DEVICE, > - .instance_size = sizeof(OHCIPCIState), > - .class_init = ohci_pci_class_init, > - .interfaces = (InterfaceInfo[]) { > - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, > - { }, > - }, > -}; > - > static Property ohci_sysbus_properties[] = { > DEFINE_PROP_STRING("masterbus", OHCISysBusState, masterbus), > DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3), > @@ -2190,7 +1981,6 @@ static const TypeInfo ohci_sysbus_info = { > > static void ohci_register_types(void) > { > - type_register_static(&ohci_pci_info); > type_register_static(&ohci_sysbus_info); > } > > diff --git a/hw/usb/hcd-ohci.h b/hw/usb/hcd-ohci.h > new file mode 100644 > index 0000000000..481ceba7ff > --- /dev/null > +++ b/hw/usb/hcd-ohci.h > @@ -0,0 +1,132 @@ > +/* > + * QEMU USB OHCI Emulation > + * Copyright (c) 2004 Gianni Tedesco > + * Copyright (c) 2006 CodeSourcery > + * Copyright (c) 2006 Openedhand Ltd. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see > <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef HCD_OHCI_H > +#define HCD_OHCI_H > + > +#include "sysemu/dma.h" > + > +/* Number of Downstream Ports on the root hub: */ > +#define OHCI_MAX_PORTS 15 > + > +typedef struct OHCIPort { > + USBPort port; > + uint32_t ctrl; > +} OHCIPort; > + > +typedef struct OHCIState { > + USBBus bus; > + qemu_irq irq; > + MemoryRegion mem; > + AddressSpace *as; > + uint32_t num_ports; > + const char *name; > + > + QEMUTimer *eof_timer; > + int64_t sof_time; > + > + /* OHCI state */ > + /* Control partition */ > + uint32_t ctl, status; > + uint32_t intr_status; > + uint32_t intr; > + > + /* memory pointer partition */ > + uint32_t hcca; > + uint32_t ctrl_head, ctrl_cur; > + uint32_t bulk_head, bulk_cur; > + uint32_t per_cur; > + uint32_t done; > + int32_t done_count; > + > + /* Frame counter partition */ > + uint16_t fsmps; > + uint8_t fit; > + uint16_t fi; > + uint8_t frt; > + uint16_t frame_number; > + uint16_t padding; > + uint32_t pstart; > + uint32_t lst; > + > + /* Root Hub partition */ > + uint32_t rhdesc_a, rhdesc_b; > + uint32_t rhstatus; > + OHCIPort rhport[OHCI_MAX_PORTS]; > + > + /* PXA27x Non-OHCI events */ > + uint32_t hstatus; > + uint32_t hmask; > + uint32_t hreset; > + uint32_t htest; > + > + /* SM501 local memory offset */ > + dma_addr_t localmem_base; > + > + /* Active packets. */ > + uint32_t old_ctl; > + USBPacket usb_packet; > + uint8_t usb_buf[8192]; > + uint32_t async_td; > + bool async_complete; > + > + void (*ohci_die)(struct OHCIState *ohci); > +} OHCIState; > + > +extern const VMStateDescription vmstate_ohci_state; > + > +#define OHCI_INTR_SO (1U << 0) /* Scheduling overrun */ > +#define OHCI_INTR_WD (1U << 1) /* HcDoneHead writeback */ > +#define OHCI_INTR_SF (1U << 2) /* Start of frame */ > +#define OHCI_INTR_RD (1U << 3) /* Resume detect */ > +#define OHCI_INTR_UE (1U << 4) /* Unrecoverable error */ > +#define OHCI_INTR_FNO (1U << 5) /* Frame number overflow */ > +#define OHCI_INTR_RHSC (1U << 6) /* Root hub status change */ > +#define OHCI_INTR_OC (1U << 30) /* Ownership change */ > +#define OHCI_INTR_MIE (1U << 31) /* Master Interrupt Enable */ > + > +/* Update IRQ levels */ > +static inline void ohci_intr_update(OHCIState *ohci) > +{ > + int level = 0; > + > + if ((ohci->intr & OHCI_INTR_MIE) && > + (ohci->intr_status & ohci->intr)) > + level = 1; > + > + qemu_set_irq(ohci->irq, level); > +} > + > +/* Set an interrupt */ > +static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) > +{ > + ohci->intr_status |= intr; > + ohci_intr_update(ohci); > +} > + > +void usb_ohci_init(OHCIState *ohci, DeviceState *dev, uint32_t num_ports, > + dma_addr_t localmem_base, char *masterbus, > + uint32_t firstport, AddressSpace *as, > + void (*ohci_die_func)(OHCIState *ohci), Error **errp); > +void ohci_hard_reset(OHCIState *ohci); > +void ohci_bus_stop(OHCIState *ohci); > +void ohci_stop_endpoints(OHCIState *ohci); > + > +#endif >