usb: bugfixes for mtp and xhci, split ohci-pci.

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJcy+bbAAoJEEy22O7T6HE4CaAQANDsvQmMmW/motKB5gimy63Y
 zCkqvw+8XIV1B0WH5HAwCi9CzA0tjH/9RDT3bY85mIXy3wtqdjZe+8AufrRKCfeQ
 pEEpWTWpB9vi1hM7/MDuQdSkWnUm4LefkCVCOcsFezcwbQKu3nKyf+IaHltmlmnK
 xAgrjL9Io5BW/LRhUDvCQOtsTPFEln7cJ6kHZ+Nye5256W7iGuZHDpcML7YtDsj8
 +GM/jp5a1HkWdYxX0Zy8RCM2YrmLL0JjyeWAJqF8cfvV8/9jU6h1abojE9zVIthv
 h4lnRtpAk2dnUAp4THPqukVLe7LPWLPErdEJ+Tr/lB3z37bLbJhwkeKmL//OEzhG
 JRqIj2HCAx1TRtezU7cXLLneZTmpZKw55ma/zFiOBGsCdP9ECiv4rJzStWWowmDt
 9Mr9kCGGsW0RK3l79jjRmOU4WEgwqMXngy/zvlBGfnNTzzpJ1xThoCDrocqJRyqy
 plafDXfLan2FkzGYRnQwVkFQY6Yp79hwx7b26UiLNcGHCo3GkP6Yfl9al1SCMiH7
 vYevlLoyypCuo9/J2+OfHnU8gLSDi1N+gzYs9j6hEJeWHQFphOy4dB/iTcG28LbF
 rGcMki9OJtte9Nsqqy4huMc/x475otnePLtiRe2wNXt6DzHgqBjvsn0kOtd4Pfl1
 rkDlbcqt/Jy4SaeBvPNu
 =w5PA
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kraxel/tags/usb-20190503-v2-pull-request' into staging

usb: bugfixes for mtp and xhci, split ohci-pci.

# gpg: Signature made Fri 03 May 2019 07:59:39 BST
# gpg:                using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/usb-20190503-v2-pull-request:
  hw/usb: avoid format truncation warning when formatting port name
  hw/usb/hcd-ohci: Move PCI-related code into a separate file
  hw/usb/hcd-ohci: Do not use PCI functions with sysbus devices in ohci_die()
  usb/xhci: avoid trigger assertion if guest write wrong epid
  usb-mtp: change default to success for usb_mtp_update_object
  usb-mtp: fix alignment of access of ObjectInfo filename field
  usb-mtp: fix string length for filename when writing metadata

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-05-03 13:57:51 +01:00
commit c58f3911b2
8 changed files with 302 additions and 209 deletions

View File

@ -6,7 +6,7 @@ config R2D
select I82378 if TEST_DEVICES select I82378 if TEST_DEVICES
select IDE_MMIO select IDE_MMIO
select PFLASH_CFI02 select PFLASH_CFI02
select USB_OHCI select USB_OHCI_PCI
select PCI select PCI
select SM501 select SM501
select SH4 select SH4

View File

@ -8,10 +8,14 @@ config USB_UHCI
select USB select USB
config USB_OHCI config USB_OHCI
bool
select USB
config USB_OHCI_PCI
bool bool
default y if PCI_DEVICES default y if PCI_DEVICES
depends on PCI depends on PCI
select USB select USB_OHCI
config USB_EHCI config USB_EHCI
bool bool

View File

@ -5,6 +5,7 @@ common-obj-$(CONFIG_USB) += desc.o desc-msos.o
# usb host adapters # usb host adapters
common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.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) += hcd-ehci.o hcd-ehci-pci.o
common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci.o hcd-ehci-sysbus.o common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci.o hcd-ehci-sysbus.o
common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o

View File

@ -226,7 +226,7 @@ typedef struct {
uint32_t assoc_desc; uint32_t assoc_desc;
uint32_t seq_no; /*unused*/ uint32_t seq_no; /*unused*/
uint8_t length; /*part of filename field*/ uint8_t length; /*part of filename field*/
uint16_t filename[0]; uint8_t filename[0]; /* UTF-16 encoded */
char date_created[0]; /*unused*/ char date_created[0]; /*unused*/
char date_modified[0]; /*unused*/ char date_modified[0]; /*unused*/
char keywords[0]; /*unused*/ char keywords[0]; /*unused*/
@ -1551,7 +1551,7 @@ static void usb_mtp_cancel_packet(USBDevice *dev, USBPacket *p)
fprintf(stderr, "%s\n", __func__); fprintf(stderr, "%s\n", __func__);
} }
static char *utf16_to_str(uint8_t len, uint16_t *arr) static char *utf16_to_str(uint8_t len, uint8_t *str16)
{ {
wchar_t *wstr = g_new0(wchar_t, len + 1); wchar_t *wstr = g_new0(wchar_t, len + 1);
int count, dlen; int count, dlen;
@ -1559,7 +1559,7 @@ static char *utf16_to_str(uint8_t len, uint16_t *arr)
for (count = 0; count < len; count++) { for (count = 0; count < len; count++) {
/* FIXME: not working for surrogate pairs */ /* FIXME: not working for surrogate pairs */
wstr[count] = (wchar_t)arr[count]; wstr[count] = lduw_le_p(str16 + (count * 2));
} }
wstr[count] = 0; wstr[count] = 0;
@ -1587,7 +1587,7 @@ done:
static int usb_mtp_update_object(MTPObject *parent, char *name) static int usb_mtp_update_object(MTPObject *parent, char *name)
{ {
int ret = -1; int ret = 0;
MTPObject *o = MTPObject *o =
usb_mtp_object_lookup_name(parent, name, strlen(name)); usb_mtp_object_lookup_name(parent, name, strlen(name));
@ -1721,7 +1721,7 @@ static void usb_mtp_write_metadata(MTPState *s, uint64_t dlen)
return; return;
} }
o = usb_mtp_object_lookup_name(p, filename, dataset->length); o = usb_mtp_object_lookup_name(p, filename, -1);
if (o != NULL) { if (o != NULL) {
next_handle = o->handle; next_handle = o->handle;
} }

163
hw/usb/hcd-ohci-pci.c Normal file
View File

@ -0,0 +1,163 @@
/*
* 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 PCI OHCI will additionally set PERR in its configspace to
* signal that it got an error.
*/
static void ohci_pci_die(struct OHCIState *ohci)
{
OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state);
ohci_sysbus_die(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)

View File

@ -30,86 +30,19 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#include "hw/usb.h" #include "hw/usb.h"
#include "hw/pci/pci.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/qdev-dma.h" #include "hw/qdev-dma.h"
#include "trace.h" #include "trace.h"
#include "hcd-ohci.h"
/* This causes frames to occur 1000x slower */ /* This causes frames to occur 1000x slower */
//#define OHCI_TIME_WARP 1 //#define OHCI_TIME_WARP 1
/* Number of Downstream Ports on the root hub. */
#define OHCI_MAX_PORTS 15
#define ED_LINK_LIMIT 32 #define ED_LINK_LIMIT 32
static int64_t usb_frame_time; static int64_t usb_frame_time;
static int64_t usb_bit_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 */ /* Host Controller Communications Area */
struct ohci_hcca { struct ohci_hcca {
uint32_t intr[32]; uint32_t intr[32];
@ -122,7 +55,6 @@ struct ohci_hcca {
#define ED_WBACK_OFFSET offsetof(struct ohci_ed, head) #define ED_WBACK_OFFSET offsetof(struct ohci_ed, head)
#define ED_WBACK_SIZE 4 #define ED_WBACK_SIZE 4
static void ohci_bus_stop(OHCIState *ohci);
static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev); static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
/* Bitfields for the first word of an Endpoint Desciptor. */ /* Bitfields for the first word of an Endpoint Desciptor. */
@ -302,7 +234,10 @@ struct ohci_iso_td {
#define OHCI_HRESET_FSBIR (1 << 0) #define OHCI_HRESET_FSBIR (1 << 0)
static void ohci_die(OHCIState *ohci); static void ohci_die(OHCIState *ohci)
{
ohci->ohci_die(ohci);
}
/* Update IRQ levels */ /* Update IRQ levels */
static inline void ohci_intr_update(OHCIState *ohci) static inline void ohci_intr_update(OHCIState *ohci)
@ -426,7 +361,7 @@ static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr)
return NULL; return NULL;
} }
static void ohci_stop_endpoints(OHCIState *ohci) void ohci_stop_endpoints(OHCIState *ohci)
{ {
USBDevice *dev; USBDevice *dev;
int i, j; int i, j;
@ -498,7 +433,7 @@ static void ohci_soft_reset(OHCIState *ohci)
ohci->lst = OHCI_LS_THRESH; ohci->lst = OHCI_LS_THRESH;
} }
static void ohci_hard_reset(OHCIState *ohci) void ohci_hard_reset(OHCIState *ohci)
{ {
ohci_soft_reset(ohci); ohci_soft_reset(ohci);
ohci->ctl = 0; ohci->ctl = 0;
@ -1372,7 +1307,7 @@ static int ohci_bus_start(OHCIState *ohci)
} }
/* Stop sending SOF tokens on the bus */ /* 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); trace_usb_ohci_stop(ohci->name);
timer_del(ohci->eof_timer); timer_del(ohci->eof_timer);
@ -1852,15 +1787,16 @@ static USBPortOps ohci_port_ops = {
static USBBusOps ohci_bus_ops = { static USBBusOps ohci_bus_ops = {
}; };
static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, void usb_ohci_init(OHCIState *ohci, DeviceState *dev, uint32_t num_ports,
uint32_t num_ports, dma_addr_t localmem_base, dma_addr_t localmem_base, char *masterbus,
char *masterbus, uint32_t firstport, uint32_t firstport, AddressSpace *as,
AddressSpace *as, Error **errp) void (*ohci_die_fn)(struct OHCIState *), Error **errp)
{ {
Error *err = NULL; Error *err = NULL;
int i; int i;
ohci->as = as; ohci->as = as;
ohci->ohci_die = ohci_die_fn;
if (num_ports > OHCI_MAX_PORTS) { if (num_ports > OHCI_MAX_PORTS) {
error_setg(errp, "OHCI num-ports=%u is too big (limit is %u ports)", error_setg(errp, "OHCI num-ports=%u is too big (limit is %u ports)",
@ -1919,85 +1855,16 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
ohci_frame_boundary, ohci); ohci_frame_boundary, ohci);
} }
#define TYPE_PCI_OHCI "pci-ohci" /**
#define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI) * A typical OHCI will stop operating and set itself into error state
* (which can be queried by MMIO) to signal that it got an error.
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_die(OHCIState *ohci) void ohci_sysbus_die(struct OHCIState *ohci)
{ {
OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state);
trace_usb_ohci_die(); trace_usb_ohci_die();
ohci_set_interrupt(ohci, OHCI_INTR_UE); ohci_set_interrupt(ohci, OHCI_INTR_UE);
ohci_bus_stop(ohci); 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" #define TYPE_SYSBUS_OHCI "sysbus-ohci"
@ -2023,7 +1890,7 @@ static void ohci_realize_pxa(DeviceState *dev, Error **errp)
usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset, usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset,
s->masterbus, s->firstport, s->masterbus, s->firstport,
&address_space_memory, &err); &address_space_memory, ohci_sysbus_die, &err);
if (err) { if (err) {
error_propagate(errp, err); error_propagate(errp, err);
return; return;
@ -2040,13 +1907,6 @@ static void usb_ohci_reset_sysbus(DeviceState *dev)
ohci_hard_reset(ohci); 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 = { static const VMStateDescription vmstate_ohci_state_port = {
.name = "ohci-core/port", .name = "ohci-core/port",
.version_id = 1, .version_id = 1,
@ -2075,7 +1935,7 @@ static const VMStateDescription vmstate_ohci_eof_timer = {
}, },
}; };
static const VMStateDescription vmstate_ohci_state = { const VMStateDescription vmstate_ohci_state = {
.name = "ohci-core", .name = "ohci-core",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
@ -2122,46 +1982,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[] = { static Property ohci_sysbus_properties[] = {
DEFINE_PROP_STRING("masterbus", OHCISysBusState, masterbus), DEFINE_PROP_STRING("masterbus", OHCISysBusState, masterbus),
DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3), DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
@ -2190,7 +2010,6 @@ static const TypeInfo ohci_sysbus_info = {
static void ohci_register_types(void) static void ohci_register_types(void)
{ {
type_register_static(&ohci_pci_info);
type_register_static(&ohci_sysbus_info); type_register_static(&ohci_sysbus_info);
} }

104
hw/usb/hcd-ohci.h Normal file
View File

@ -0,0 +1,104 @@
/*
* 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;
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_fn)(struct OHCIState *), Error **errp);
void ohci_bus_stop(OHCIState *ohci);
void ohci_stop_endpoints(OHCIState *ohci);
void ohci_hard_reset(OHCIState *ohci);
void ohci_sysbus_die(struct OHCIState *ohci);
#endif

View File

@ -3137,7 +3137,7 @@ static void xhci_doorbell_write(void *ptr, hwaddr reg,
streamid = (val >> 16) & 0xffff; streamid = (val >> 16) & 0xffff;
if (reg > xhci->numslots) { if (reg > xhci->numslots) {
DPRINTF("xhci: bad doorbell %d\n", (int)reg); DPRINTF("xhci: bad doorbell %d\n", (int)reg);
} else if (epid > 31) { } else if (epid == 0 || epid > 31) {
DPRINTF("xhci: bad doorbell %d write: 0x%x\n", DPRINTF("xhci: bad doorbell %d write: 0x%x\n",
(int)reg, (uint32_t)val); (int)reg, (uint32_t)val);
} else { } else {
@ -3306,7 +3306,7 @@ static void usb_xhci_init(XHCIState *xhci)
{ {
DeviceState *dev = DEVICE(xhci); DeviceState *dev = DEVICE(xhci);
XHCIPort *port; XHCIPort *port;
int i, usbports, speedmask; unsigned int i, usbports, speedmask;
xhci->usbsts = USBSTS_HCH; xhci->usbsts = USBSTS_HCH;
@ -3336,6 +3336,7 @@ static void usb_xhci_init(XHCIState *xhci)
USB_SPEED_MASK_LOW | USB_SPEED_MASK_LOW |
USB_SPEED_MASK_FULL | USB_SPEED_MASK_FULL |
USB_SPEED_MASK_HIGH; USB_SPEED_MASK_HIGH;
assert(i < MAXPORTS);
snprintf(port->name, sizeof(port->name), "usb2 port #%d", i+1); snprintf(port->name, sizeof(port->name), "usb2 port #%d", i+1);
speedmask |= port->speedmask; speedmask |= port->speedmask;
} }
@ -3349,6 +3350,7 @@ static void usb_xhci_init(XHCIState *xhci)
} }
port->uport = &xhci->uports[i]; port->uport = &xhci->uports[i];
port->speedmask = USB_SPEED_MASK_SUPER; port->speedmask = USB_SPEED_MASK_SUPER;
assert(i < MAXPORTS);
snprintf(port->name, sizeof(port->name), "usb3 port #%d", i+1); snprintf(port->name, sizeof(port->name), "usb3 port #%d", i+1);
speedmask |= port->speedmask; speedmask |= port->speedmask;
} }