[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-arm] [PATCH for-4.1] hw/usb/hcd-ohci: Move PCI-related code in
From: |
Philippe Mathieu-Daudé |
Subject: |
Re: [Qemu-arm] [PATCH for-4.1] hw/usb/hcd-ohci: Move PCI-related code into a separate file |
Date: |
Thu, 18 Apr 2019 14:35:37 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 |
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 <address@hidden>
> ---
> 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
>