mirror of
https://github.com/qemu/qemu.git
synced 2024-11-24 03:13:44 +08:00
qtest: improve ehci/uhci test
usb: misc fixes, mostly for usb3/xhci -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJTjIziAAoJEEy22O7T6HE4HNMP/A9kbK49yK4o+/9tdemCsNnD KfDlt8K+NPnI1VzhOTOpbFN1ci5Oq1VQ0syw6uIwU5v8E0ZXKoS7uqIYKTx2rjfX w5tGSlK/gjYGLeN/VhbIOcELuBo2hdUDzYEpjdcUZ0L4xkKRVwoN30P292/KlRTu ZBOdaz4JlrGJRTUgb35GaVNhtSFAdIPNUHlzdyq+lJJuJq4quQh4mO3J/eQqRveJ EiLRKvc1FV4Z0tLZ3tzKemDYGJoA6conRCe+Xt+fmdlROm/037HjQ+/KqUyXKdFs hpYAj58bKrtIE9Dyo3MwD7/4R2XgkDYNGXeGlrGTgmkhwujme8vB/K57sqYlLnE1 1iCf03gXd+Ap1zU7BTv+abFfuA/7SFnkIgs3+zU68UFfmiBKGDQgxLCnqGMWlari DpIf94T7ZLdNz6sc4FG4gQCP+aVJYTUjkjtunfJMfE/qz6Xb5BJQIPc3aHnAsqrb LG75rjJfS1rh1+SvNm7f46fC+7A9eKYOlbkbH8c3BQDCJkZyeWovnml4xIlLkvkg 8xJB5UJVb4B4MKQW7Zi0hrDaN8/GVVyWymtt3Dl/I2iHBdV2Z/U+2/rFtLtZQ1zi oLl+ZteHaU3hnr5DNns3DuMSG33UT+o9gzaHsUldetwLiyGOiUC2i4P3xPD7fPID mJKO98266m9KMshEdw7k =4LqT -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-8' into staging qtest: improve ehci/uhci test usb: misc fixes, mostly for usb3/xhci # gpg: Signature made Mon 02 Jun 2014 15:40:34 BST using RSA key ID D3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" * remotes/kraxel/tags/pull-usb-8: xhci: order superspeed ports first xhci: make port reset trace point more verbose usb: add usb_pick_speed usb-host: add HAVE_STREAMS define usb-host: allow attaching usb3 devices to ehci usb: improve ehci/uhci test usb: move ehci register defines to header file usb: add uhci port status reserved bit usb: move uhci register defines to header file qtest: fix qpci_config_writel Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
82ea61c6da
@ -28,6 +28,26 @@
|
|||||||
#include "qemu/iov.h"
|
#include "qemu/iov.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
|
void usb_pick_speed(USBPort *port)
|
||||||
|
{
|
||||||
|
static const int speeds[] = {
|
||||||
|
USB_SPEED_SUPER,
|
||||||
|
USB_SPEED_HIGH,
|
||||||
|
USB_SPEED_FULL,
|
||||||
|
USB_SPEED_LOW,
|
||||||
|
};
|
||||||
|
USBDevice *udev = port->dev;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(speeds); i++) {
|
||||||
|
if ((udev->speedmask & (1 << speeds[i])) &&
|
||||||
|
(port->speedmask & (1 << speeds[i]))) {
|
||||||
|
udev->speed = speeds[i];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void usb_attach(USBPort *port)
|
void usb_attach(USBPort *port)
|
||||||
{
|
{
|
||||||
USBDevice *dev = port->dev;
|
USBDevice *dev = port->dev;
|
||||||
@ -35,6 +55,7 @@ void usb_attach(USBPort *port)
|
|||||||
assert(dev != NULL);
|
assert(dev != NULL);
|
||||||
assert(dev->attached);
|
assert(dev->attached);
|
||||||
assert(dev->state == USB_STATE_NOTATTACHED);
|
assert(dev->state == USB_STATE_NOTATTACHED);
|
||||||
|
usb_pick_speed(port);
|
||||||
port->ops->attach(port);
|
port->ops->attach(port);
|
||||||
dev->state = USB_STATE_ATTACHED;
|
dev->state = USB_STATE_ATTACHED;
|
||||||
usb_device_handle_attach(dev);
|
usb_device_handle_attach(dev);
|
||||||
|
@ -518,18 +518,6 @@ void usb_desc_init(USBDevice *dev)
|
|||||||
|
|
||||||
void usb_desc_attach(USBDevice *dev)
|
void usb_desc_attach(USBDevice *dev)
|
||||||
{
|
{
|
||||||
const USBDesc *desc = usb_device_get_usb_desc(dev);
|
|
||||||
|
|
||||||
assert(desc != NULL);
|
|
||||||
if (desc->super && (dev->port->speedmask & USB_SPEED_MASK_SUPER)) {
|
|
||||||
dev->speed = USB_SPEED_SUPER;
|
|
||||||
} else if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
|
|
||||||
dev->speed = USB_SPEED_HIGH;
|
|
||||||
} else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) {
|
|
||||||
dev->speed = USB_SPEED_FULL;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
usb_desc_setdefaults(dev);
|
usb_desc_setdefaults(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,87 +27,10 @@
|
|||||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "hw/usb/ehci-regs.h"
|
||||||
#include "hw/usb/hcd-ehci.h"
|
#include "hw/usb/hcd-ehci.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
/* Capability Registers Base Address - section 2.2 */
|
|
||||||
#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */
|
|
||||||
#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */
|
|
||||||
#define HCSPARAMS 0x0004 /* 4-bytes, structural params */
|
|
||||||
#define HCCPARAMS 0x0008 /* 4-bytes, capability params */
|
|
||||||
#define EECP HCCPARAMS + 1
|
|
||||||
#define HCSPPORTROUTE1 0x000c
|
|
||||||
#define HCSPPORTROUTE2 0x0010
|
|
||||||
|
|
||||||
#define USBCMD 0x0000
|
|
||||||
#define USBCMD_RUNSTOP (1 << 0) // run / Stop
|
|
||||||
#define USBCMD_HCRESET (1 << 1) // HC Reset
|
|
||||||
#define USBCMD_FLS (3 << 2) // Frame List Size
|
|
||||||
#define USBCMD_FLS_SH 2 // Frame List Size Shift
|
|
||||||
#define USBCMD_PSE (1 << 4) // Periodic Schedule Enable
|
|
||||||
#define USBCMD_ASE (1 << 5) // Asynch Schedule Enable
|
|
||||||
#define USBCMD_IAAD (1 << 6) // Int Asynch Advance Doorbell
|
|
||||||
#define USBCMD_LHCR (1 << 7) // Light Host Controller Reset
|
|
||||||
#define USBCMD_ASPMC (3 << 8) // Async Sched Park Mode Count
|
|
||||||
#define USBCMD_ASPME (1 << 11) // Async Sched Park Mode Enable
|
|
||||||
#define USBCMD_ITC (0x7f << 16) // Int Threshold Control
|
|
||||||
#define USBCMD_ITC_SH 16 // Int Threshold Control Shift
|
|
||||||
|
|
||||||
#define USBSTS 0x0004
|
|
||||||
#define USBSTS_RO_MASK 0x0000003f
|
|
||||||
#define USBSTS_INT (1 << 0) // USB Interrupt
|
|
||||||
#define USBSTS_ERRINT (1 << 1) // Error Interrupt
|
|
||||||
#define USBSTS_PCD (1 << 2) // Port Change Detect
|
|
||||||
#define USBSTS_FLR (1 << 3) // Frame List Rollover
|
|
||||||
#define USBSTS_HSE (1 << 4) // Host System Error
|
|
||||||
#define USBSTS_IAA (1 << 5) // Interrupt on Async Advance
|
|
||||||
#define USBSTS_HALT (1 << 12) // HC Halted
|
|
||||||
#define USBSTS_REC (1 << 13) // Reclamation
|
|
||||||
#define USBSTS_PSS (1 << 14) // Periodic Schedule Status
|
|
||||||
#define USBSTS_ASS (1 << 15) // Asynchronous Schedule Status
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Interrupt enable bits correspond to the interrupt active bits in USBSTS
|
|
||||||
* so no need to redefine here.
|
|
||||||
*/
|
|
||||||
#define USBINTR 0x0008
|
|
||||||
#define USBINTR_MASK 0x0000003f
|
|
||||||
|
|
||||||
#define FRINDEX 0x000c
|
|
||||||
#define CTRLDSSEGMENT 0x0010
|
|
||||||
#define PERIODICLISTBASE 0x0014
|
|
||||||
#define ASYNCLISTADDR 0x0018
|
|
||||||
#define ASYNCLISTADDR_MASK 0xffffffe0
|
|
||||||
|
|
||||||
#define CONFIGFLAG 0x0040
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bits that are reserved or are read-only are masked out of values
|
|
||||||
* written to us by software
|
|
||||||
*/
|
|
||||||
#define PORTSC_RO_MASK 0x007001c0
|
|
||||||
#define PORTSC_RWC_MASK 0x0000002a
|
|
||||||
#define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable
|
|
||||||
#define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable
|
|
||||||
#define PORTSC_WKCN_E (1 << 20) // Wake on Connect Enable
|
|
||||||
#define PORTSC_PTC (15 << 16) // Port Test Control
|
|
||||||
#define PORTSC_PTC_SH 16 // Port Test Control shift
|
|
||||||
#define PORTSC_PIC (3 << 14) // Port Indicator Control
|
|
||||||
#define PORTSC_PIC_SH 14 // Port Indicator Control Shift
|
|
||||||
#define PORTSC_POWNER (1 << 13) // Port Owner
|
|
||||||
#define PORTSC_PPOWER (1 << 12) // Port Power
|
|
||||||
#define PORTSC_LINESTAT (3 << 10) // Port Line Status
|
|
||||||
#define PORTSC_LINESTAT_SH 10 // Port Line Status Shift
|
|
||||||
#define PORTSC_PRESET (1 << 8) // Port Reset
|
|
||||||
#define PORTSC_SUSPEND (1 << 7) // Port Suspend
|
|
||||||
#define PORTSC_FPRES (1 << 6) // Force Port Resume
|
|
||||||
#define PORTSC_OCC (1 << 5) // Over Current Change
|
|
||||||
#define PORTSC_OCA (1 << 4) // Over Current Active
|
|
||||||
#define PORTSC_PEDC (1 << 3) // Port Enable/Disable Change
|
|
||||||
#define PORTSC_PED (1 << 2) // Port Enable/Disable
|
|
||||||
#define PORTSC_CSC (1 << 1) // Connect Status Change
|
|
||||||
#define PORTSC_CONNECT (1 << 0) // Current Connect Status
|
|
||||||
|
|
||||||
#define FRAME_TIMER_FREQ 1000
|
#define FRAME_TIMER_FREQ 1000
|
||||||
#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ)
|
#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ)
|
||||||
#define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8)
|
#define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8)
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "hw/hw.h"
|
#include "hw/hw.h"
|
||||||
#include "hw/usb.h"
|
#include "hw/usb.h"
|
||||||
|
#include "hw/usb/uhci-regs.h"
|
||||||
#include "hw/pci/pci.h"
|
#include "hw/pci/pci.h"
|
||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
#include "qemu/iov.h"
|
#include "qemu/iov.h"
|
||||||
@ -37,41 +38,6 @@
|
|||||||
//#define DEBUG
|
//#define DEBUG
|
||||||
//#define DEBUG_DUMP_DATA
|
//#define DEBUG_DUMP_DATA
|
||||||
|
|
||||||
#define UHCI_CMD_FGR (1 << 4)
|
|
||||||
#define UHCI_CMD_EGSM (1 << 3)
|
|
||||||
#define UHCI_CMD_GRESET (1 << 2)
|
|
||||||
#define UHCI_CMD_HCRESET (1 << 1)
|
|
||||||
#define UHCI_CMD_RS (1 << 0)
|
|
||||||
|
|
||||||
#define UHCI_STS_HCHALTED (1 << 5)
|
|
||||||
#define UHCI_STS_HCPERR (1 << 4)
|
|
||||||
#define UHCI_STS_HSERR (1 << 3)
|
|
||||||
#define UHCI_STS_RD (1 << 2)
|
|
||||||
#define UHCI_STS_USBERR (1 << 1)
|
|
||||||
#define UHCI_STS_USBINT (1 << 0)
|
|
||||||
|
|
||||||
#define TD_CTRL_SPD (1 << 29)
|
|
||||||
#define TD_CTRL_ERROR_SHIFT 27
|
|
||||||
#define TD_CTRL_IOS (1 << 25)
|
|
||||||
#define TD_CTRL_IOC (1 << 24)
|
|
||||||
#define TD_CTRL_ACTIVE (1 << 23)
|
|
||||||
#define TD_CTRL_STALL (1 << 22)
|
|
||||||
#define TD_CTRL_BABBLE (1 << 20)
|
|
||||||
#define TD_CTRL_NAK (1 << 19)
|
|
||||||
#define TD_CTRL_TIMEOUT (1 << 18)
|
|
||||||
|
|
||||||
#define UHCI_PORT_SUSPEND (1 << 12)
|
|
||||||
#define UHCI_PORT_RESET (1 << 9)
|
|
||||||
#define UHCI_PORT_LSDA (1 << 8)
|
|
||||||
#define UHCI_PORT_RD (1 << 6)
|
|
||||||
#define UHCI_PORT_ENC (1 << 3)
|
|
||||||
#define UHCI_PORT_EN (1 << 2)
|
|
||||||
#define UHCI_PORT_CSC (1 << 1)
|
|
||||||
#define UHCI_PORT_CCS (1 << 0)
|
|
||||||
|
|
||||||
#define UHCI_PORT_READ_ONLY (0x1bb)
|
|
||||||
#define UHCI_PORT_WRITE_CLEAR (UHCI_PORT_CSC | UHCI_PORT_ENC)
|
|
||||||
|
|
||||||
#define FRAME_TIMER_FREQ 1000
|
#define FRAME_TIMER_FREQ 1000
|
||||||
|
|
||||||
#define FRAME_MAX_LOOPS 256
|
#define FRAME_MAX_LOOPS 256
|
||||||
|
@ -498,6 +498,7 @@ typedef struct XHCIEvRingSeg {
|
|||||||
enum xhci_flags {
|
enum xhci_flags {
|
||||||
XHCI_FLAG_USE_MSI = 1,
|
XHCI_FLAG_USE_MSI = 1,
|
||||||
XHCI_FLAG_USE_MSI_X,
|
XHCI_FLAG_USE_MSI_X,
|
||||||
|
XHCI_FLAG_SS_FIRST,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
|
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
|
||||||
@ -714,10 +715,18 @@ static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
|
|||||||
case USB_SPEED_LOW:
|
case USB_SPEED_LOW:
|
||||||
case USB_SPEED_FULL:
|
case USB_SPEED_FULL:
|
||||||
case USB_SPEED_HIGH:
|
case USB_SPEED_HIGH:
|
||||||
index = uport->index;
|
if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
|
||||||
|
index = uport->index + xhci->numports_3;
|
||||||
|
} else {
|
||||||
|
index = uport->index;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case USB_SPEED_SUPER:
|
case USB_SPEED_SUPER:
|
||||||
index = uport->index + xhci->numports_2;
|
if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
|
||||||
|
index = uport->index;
|
||||||
|
} else {
|
||||||
|
index = uport->index + xhci->numports_2;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -2856,7 +2865,7 @@ static void xhci_port_update(XHCIPort *port, int is_detach)
|
|||||||
|
|
||||||
static void xhci_port_reset(XHCIPort *port, bool warm_reset)
|
static void xhci_port_reset(XHCIPort *port, bool warm_reset)
|
||||||
{
|
{
|
||||||
trace_usb_xhci_port_reset(port->portnr);
|
trace_usb_xhci_port_reset(port->portnr, warm_reset);
|
||||||
|
|
||||||
if (!xhci_port_have_device(port)) {
|
if (!xhci_port_have_device(port)) {
|
||||||
return;
|
return;
|
||||||
@ -2972,7 +2981,11 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
|
|||||||
ret = 0x20425355; /* "USB " */
|
ret = 0x20425355; /* "USB " */
|
||||||
break;
|
break;
|
||||||
case 0x28: /* Supported Protocol:08 */
|
case 0x28: /* Supported Protocol:08 */
|
||||||
ret = 0x00000001 | (xhci->numports_2<<8);
|
if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
|
||||||
|
ret = (xhci->numports_2<<8) | (xhci->numports_3+1);
|
||||||
|
} else {
|
||||||
|
ret = (xhci->numports_2<<8) | 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0x2c: /* Supported Protocol:0c */
|
case 0x2c: /* Supported Protocol:0c */
|
||||||
ret = 0x00000000; /* reserved */
|
ret = 0x00000000; /* reserved */
|
||||||
@ -2984,7 +2997,11 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
|
|||||||
ret = 0x20425355; /* "USB " */
|
ret = 0x20425355; /* "USB " */
|
||||||
break;
|
break;
|
||||||
case 0x38: /* Supported Protocol:08 */
|
case 0x38: /* Supported Protocol:08 */
|
||||||
ret = 0x00000000 | (xhci->numports_2+1) | (xhci->numports_3<<8);
|
if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
|
||||||
|
ret = (xhci->numports_3<<8) | 1;
|
||||||
|
} else {
|
||||||
|
ret = (xhci->numports_3<<8) | (xhci->numports_2+1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0x3c: /* Supported Protocol:0c */
|
case 0x3c: /* Supported Protocol:0c */
|
||||||
ret = 0x00000000; /* reserved */
|
ret = 0x00000000; /* reserved */
|
||||||
@ -3517,8 +3534,13 @@ static void usb_xhci_init(XHCIState *xhci)
|
|||||||
for (i = 0; i < usbports; i++) {
|
for (i = 0; i < usbports; i++) {
|
||||||
speedmask = 0;
|
speedmask = 0;
|
||||||
if (i < xhci->numports_2) {
|
if (i < xhci->numports_2) {
|
||||||
port = &xhci->ports[i];
|
if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
|
||||||
port->portnr = i + 1;
|
port = &xhci->ports[i + xhci->numports_3];
|
||||||
|
port->portnr = i + 1 + xhci->numports_3;
|
||||||
|
} else {
|
||||||
|
port = &xhci->ports[i];
|
||||||
|
port->portnr = i + 1;
|
||||||
|
}
|
||||||
port->uport = &xhci->uports[i];
|
port->uport = &xhci->uports[i];
|
||||||
port->speedmask =
|
port->speedmask =
|
||||||
USB_SPEED_MASK_LOW |
|
USB_SPEED_MASK_LOW |
|
||||||
@ -3528,8 +3550,13 @@ static void usb_xhci_init(XHCIState *xhci)
|
|||||||
speedmask |= port->speedmask;
|
speedmask |= port->speedmask;
|
||||||
}
|
}
|
||||||
if (i < xhci->numports_3) {
|
if (i < xhci->numports_3) {
|
||||||
port = &xhci->ports[i + xhci->numports_2];
|
if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
|
||||||
port->portnr = i + 1 + xhci->numports_2;
|
port = &xhci->ports[i];
|
||||||
|
port->portnr = i + 1;
|
||||||
|
} else {
|
||||||
|
port = &xhci->ports[i + xhci->numports_2];
|
||||||
|
port->portnr = i + 1 + xhci->numports_2;
|
||||||
|
}
|
||||||
port->uport = &xhci->uports[i];
|
port->uport = &xhci->uports[i];
|
||||||
port->speedmask = USB_SPEED_MASK_SUPER;
|
port->speedmask = USB_SPEED_MASK_SUPER;
|
||||||
snprintf(port->name, sizeof(port->name), "usb3 port #%d", i+1);
|
snprintf(port->name, sizeof(port->name), "usb3 port #%d", i+1);
|
||||||
@ -3788,6 +3815,8 @@ static const VMStateDescription vmstate_xhci = {
|
|||||||
static Property xhci_properties[] = {
|
static Property xhci_properties[] = {
|
||||||
DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true),
|
DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true),
|
||||||
DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
|
DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
|
||||||
|
DEFINE_PROP_BIT("superspeed-ports-first",
|
||||||
|
XHCIState, flags, XHCI_FLAG_SS_FIRST, true),
|
||||||
DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS),
|
DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS),
|
||||||
DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS),
|
DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS),
|
||||||
DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
|
DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
|
||||||
|
@ -111,6 +111,7 @@ struct USBHostRequest {
|
|||||||
unsigned char *buffer;
|
unsigned char *buffer;
|
||||||
unsigned char *cbuf;
|
unsigned char *cbuf;
|
||||||
unsigned int clen;
|
unsigned int clen;
|
||||||
|
bool usb3ep0quirk;
|
||||||
QTAILQ_ENTRY(USBHostRequest) next;
|
QTAILQ_ENTRY(USBHostRequest) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -146,6 +147,10 @@ static void usb_host_attach_kernel(USBHostDevice *s);
|
|||||||
#define BULK_TIMEOUT 0 /* unlimited */
|
#define BULK_TIMEOUT 0 /* unlimited */
|
||||||
#define INTR_TIMEOUT 0 /* unlimited */
|
#define INTR_TIMEOUT 0 /* unlimited */
|
||||||
|
|
||||||
|
#if LIBUSBX_API_VERSION >= 0x01000103
|
||||||
|
# define HAVE_STREAMS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char *speed_name[] = {
|
static const char *speed_name[] = {
|
||||||
[LIBUSB_SPEED_UNKNOWN] = "?",
|
[LIBUSB_SPEED_UNKNOWN] = "?",
|
||||||
[LIBUSB_SPEED_LOW] = "1.5",
|
[LIBUSB_SPEED_LOW] = "1.5",
|
||||||
@ -346,6 +351,13 @@ static void usb_host_req_complete_ctrl(struct libusb_transfer *xfer)
|
|||||||
r->p->actual_length = xfer->actual_length;
|
r->p->actual_length = xfer->actual_length;
|
||||||
if (r->in && xfer->actual_length) {
|
if (r->in && xfer->actual_length) {
|
||||||
memcpy(r->cbuf, r->buffer + 8, xfer->actual_length);
|
memcpy(r->cbuf, r->buffer + 8, xfer->actual_length);
|
||||||
|
|
||||||
|
/* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
|
||||||
|
* to work redirected to a not superspeed capable hcd */
|
||||||
|
if (r->usb3ep0quirk && xfer->actual_length >= 18 &&
|
||||||
|
r->cbuf[7] == 9) {
|
||||||
|
r->cbuf[7] = 64;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
trace_usb_host_req_complete(s->bus_num, s->addr, r->p,
|
trace_usb_host_req_complete(s->bus_num, s->addr, r->p,
|
||||||
r->p->status, r->p->actual_length);
|
r->p->status, r->p->actual_length);
|
||||||
@ -672,11 +684,17 @@ static void usb_host_iso_data_out(USBHostDevice *s, USBPacket *p)
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
static bool usb_host_full_speed_compat(USBHostDevice *s)
|
static void usb_host_speed_compat(USBHostDevice *s)
|
||||||
{
|
{
|
||||||
|
USBDevice *udev = USB_DEVICE(s);
|
||||||
struct libusb_config_descriptor *conf;
|
struct libusb_config_descriptor *conf;
|
||||||
const struct libusb_interface_descriptor *intf;
|
const struct libusb_interface_descriptor *intf;
|
||||||
const struct libusb_endpoint_descriptor *endp;
|
const struct libusb_endpoint_descriptor *endp;
|
||||||
|
#ifdef HAVE_STREAMS
|
||||||
|
struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
|
||||||
|
#endif
|
||||||
|
bool compat_high = true;
|
||||||
|
bool compat_full = true;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
int rc, c, i, a, e;
|
int rc, c, i, a, e;
|
||||||
|
|
||||||
@ -693,10 +711,27 @@ static bool usb_host_full_speed_compat(USBHostDevice *s)
|
|||||||
type = endp->bmAttributes & 0x3;
|
type = endp->bmAttributes & 0x3;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0x01: /* ISO */
|
case 0x01: /* ISO */
|
||||||
return false;
|
compat_full = false;
|
||||||
|
compat_high = false;
|
||||||
|
break;
|
||||||
|
case 0x02: /* BULK */
|
||||||
|
#ifdef HAVE_STREAMS
|
||||||
|
rc = libusb_get_ss_endpoint_companion_descriptor
|
||||||
|
(ctx, endp, &endp_ss_comp);
|
||||||
|
if (rc == LIBUSB_SUCCESS) {
|
||||||
|
libusb_free_ss_endpoint_companion_descriptor
|
||||||
|
(endp_ss_comp);
|
||||||
|
compat_full = false;
|
||||||
|
compat_high = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
case 0x03: /* INTERRUPT */
|
case 0x03: /* INTERRUPT */
|
||||||
if (endp->wMaxPacketSize > 64) {
|
if (endp->wMaxPacketSize > 64) {
|
||||||
return false;
|
compat_full = false;
|
||||||
|
}
|
||||||
|
if (endp->wMaxPacketSize > 1024) {
|
||||||
|
compat_high = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -705,7 +740,17 @@ static bool usb_host_full_speed_compat(USBHostDevice *s)
|
|||||||
}
|
}
|
||||||
libusb_free_config_descriptor(conf);
|
libusb_free_config_descriptor(conf);
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
udev->speedmask = (1 << udev->speed);
|
||||||
|
if (udev->speed == USB_SPEED_SUPER && compat_high) {
|
||||||
|
udev->speedmask |= USB_SPEED_HIGH;
|
||||||
|
}
|
||||||
|
if (udev->speed == USB_SPEED_SUPER && compat_full) {
|
||||||
|
udev->speedmask |= USB_SPEED_FULL;
|
||||||
|
}
|
||||||
|
if (udev->speed == USB_SPEED_HIGH && compat_full) {
|
||||||
|
udev->speedmask |= USB_SPEED_FULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_host_ep_update(USBHostDevice *s)
|
static void usb_host_ep_update(USBHostDevice *s)
|
||||||
@ -720,7 +765,7 @@ static void usb_host_ep_update(USBHostDevice *s)
|
|||||||
struct libusb_config_descriptor *conf;
|
struct libusb_config_descriptor *conf;
|
||||||
const struct libusb_interface_descriptor *intf;
|
const struct libusb_interface_descriptor *intf;
|
||||||
const struct libusb_endpoint_descriptor *endp;
|
const struct libusb_endpoint_descriptor *endp;
|
||||||
#if LIBUSBX_API_VERSION >= 0x01000103
|
#ifdef HAVE_STREAMS
|
||||||
struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
|
struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
|
||||||
#endif
|
#endif
|
||||||
uint8_t devep, type;
|
uint8_t devep, type;
|
||||||
@ -768,7 +813,7 @@ static void usb_host_ep_update(USBHostDevice *s)
|
|||||||
usb_ep_set_type(udev, pid, ep, type);
|
usb_ep_set_type(udev, pid, ep, type);
|
||||||
usb_ep_set_ifnum(udev, pid, ep, i);
|
usb_ep_set_ifnum(udev, pid, ep, i);
|
||||||
usb_ep_set_halted(udev, pid, ep, 0);
|
usb_ep_set_halted(udev, pid, ep, 0);
|
||||||
#if LIBUSBX_API_VERSION >= 0x01000103
|
#ifdef HAVE_STREAMS
|
||||||
if (type == LIBUSB_TRANSFER_TYPE_BULK &&
|
if (type == LIBUSB_TRANSFER_TYPE_BULK &&
|
||||||
libusb_get_ss_endpoint_companion_descriptor(ctx, endp,
|
libusb_get_ss_endpoint_companion_descriptor(ctx, endp,
|
||||||
&endp_ss_comp) == LIBUSB_SUCCESS) {
|
&endp_ss_comp) == LIBUSB_SUCCESS) {
|
||||||
@ -813,10 +858,7 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev)
|
|||||||
usb_host_ep_update(s);
|
usb_host_ep_update(s);
|
||||||
|
|
||||||
udev->speed = speed_map[libusb_get_device_speed(dev)];
|
udev->speed = speed_map[libusb_get_device_speed(dev)];
|
||||||
udev->speedmask = (1 << udev->speed);
|
usb_host_speed_compat(s);
|
||||||
if (udev->speed == USB_SPEED_HIGH && usb_host_full_speed_compat(s)) {
|
|
||||||
udev->speedmask |= USB_SPEED_MASK_FULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->ddesc.iProduct) {
|
if (s->ddesc.iProduct) {
|
||||||
libusb_get_string_descriptor_ascii(s->dh, s->ddesc.iProduct,
|
libusb_get_string_descriptor_ascii(s->dh, s->ddesc.iProduct,
|
||||||
@ -1162,6 +1204,14 @@ static void usb_host_handle_control(USBDevice *udev, USBPacket *p,
|
|||||||
memcpy(r->buffer + 8, r->cbuf, r->clen);
|
memcpy(r->buffer + 8, r->cbuf, r->clen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
|
||||||
|
* to work redirected to a not superspeed capable hcd */
|
||||||
|
if (udev->speed == USB_SPEED_SUPER &&
|
||||||
|
!((udev->port->speedmask & USB_SPEED_MASK_SUPER)) &&
|
||||||
|
request == 0x8006 && value == 0x100 && index == 0) {
|
||||||
|
r->usb3ep0quirk = true;
|
||||||
|
}
|
||||||
|
|
||||||
libusb_fill_control_transfer(r->xfer, s->dh, r->buffer,
|
libusb_fill_control_transfer(r->xfer, s->dh, r->buffer,
|
||||||
usb_host_req_complete_ctrl, r,
|
usb_host_req_complete_ctrl, r,
|
||||||
CONTROL_TIMEOUT);
|
CONTROL_TIMEOUT);
|
||||||
@ -1215,7 +1265,7 @@ static void usb_host_handle_data(USBDevice *udev, USBPacket *p)
|
|||||||
}
|
}
|
||||||
ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
|
ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
|
||||||
if (p->stream) {
|
if (p->stream) {
|
||||||
#if LIBUSBX_API_VERSION >= 0x01000103
|
#ifdef HAVE_STREAMS
|
||||||
libusb_fill_bulk_stream_transfer(r->xfer, s->dh, ep, p->stream,
|
libusb_fill_bulk_stream_transfer(r->xfer, s->dh, ep, p->stream,
|
||||||
r->buffer, size,
|
r->buffer, size,
|
||||||
usb_host_req_complete_data, r,
|
usb_host_req_complete_data, r,
|
||||||
@ -1296,7 +1346,7 @@ static void usb_host_handle_reset(USBDevice *udev)
|
|||||||
static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps,
|
static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps,
|
||||||
int nr_eps, int streams)
|
int nr_eps, int streams)
|
||||||
{
|
{
|
||||||
#if LIBUSBX_API_VERSION >= 0x01000103
|
#ifdef HAVE_STREAMS
|
||||||
USBHostDevice *s = USB_HOST_DEVICE(udev);
|
USBHostDevice *s = USB_HOST_DEVICE(udev);
|
||||||
unsigned char endpoints[30];
|
unsigned char endpoints[30];
|
||||||
int i, rc;
|
int i, rc;
|
||||||
@ -1326,7 +1376,7 @@ static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps,
|
|||||||
static void usb_host_free_streams(USBDevice *udev, USBEndpoint **eps,
|
static void usb_host_free_streams(USBDevice *udev, USBEndpoint **eps,
|
||||||
int nr_eps)
|
int nr_eps)
|
||||||
{
|
{
|
||||||
#if LIBUSBX_API_VERSION >= 0x01000103
|
#ifdef HAVE_STREAMS
|
||||||
USBHostDevice *s = USB_HOST_DEVICE(udev);
|
USBHostDevice *s = USB_HOST_DEVICE(udev);
|
||||||
unsigned char endpoints[30];
|
unsigned char endpoints[30];
|
||||||
int i;
|
int i;
|
||||||
|
@ -271,6 +271,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
|
|||||||
.driver = "apic",\
|
.driver = "apic",\
|
||||||
.property = "version",\
|
.property = "version",\
|
||||||
.value = stringify(0x11),\
|
.value = stringify(0x11),\
|
||||||
|
},{\
|
||||||
|
.driver = "nec-usb-xhci",\
|
||||||
|
.property = "superspeed-ports-first",\
|
||||||
|
.value = "off",\
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PC_COMPAT_1_7 \
|
#define PC_COMPAT_1_7 \
|
||||||
|
@ -458,6 +458,7 @@ void usb_ep_combine_input_packets(USBEndpoint *ep);
|
|||||||
void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p);
|
void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p);
|
||||||
void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p);
|
void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p);
|
||||||
|
|
||||||
|
void usb_pick_speed(USBPort *port);
|
||||||
void usb_attach(USBPort *port);
|
void usb_attach(USBPort *port);
|
||||||
void usb_detach(USBPort *port);
|
void usb_detach(USBPort *port);
|
||||||
void usb_port_reset(USBPort *port);
|
void usb_port_reset(USBPort *port);
|
||||||
|
82
include/hw/usb/ehci-regs.h
Normal file
82
include/hw/usb/ehci-regs.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#ifndef HW_USB_EHCI_REGS_H
|
||||||
|
#define HW_USB_EHCI_REGS_H 1
|
||||||
|
|
||||||
|
/* Capability Registers Base Address - section 2.2 */
|
||||||
|
#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */
|
||||||
|
#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */
|
||||||
|
#define HCSPARAMS 0x0004 /* 4-bytes, structural params */
|
||||||
|
#define HCCPARAMS 0x0008 /* 4-bytes, capability params */
|
||||||
|
#define EECP HCCPARAMS + 1
|
||||||
|
#define HCSPPORTROUTE1 0x000c
|
||||||
|
#define HCSPPORTROUTE2 0x0010
|
||||||
|
|
||||||
|
#define USBCMD 0x0000
|
||||||
|
#define USBCMD_RUNSTOP (1 << 0) // run / Stop
|
||||||
|
#define USBCMD_HCRESET (1 << 1) // HC Reset
|
||||||
|
#define USBCMD_FLS (3 << 2) // Frame List Size
|
||||||
|
#define USBCMD_FLS_SH 2 // Frame List Size Shift
|
||||||
|
#define USBCMD_PSE (1 << 4) // Periodic Schedule Enable
|
||||||
|
#define USBCMD_ASE (1 << 5) // Asynch Schedule Enable
|
||||||
|
#define USBCMD_IAAD (1 << 6) // Int Asynch Advance Doorbell
|
||||||
|
#define USBCMD_LHCR (1 << 7) // Light Host Controller Reset
|
||||||
|
#define USBCMD_ASPMC (3 << 8) // Async Sched Park Mode Count
|
||||||
|
#define USBCMD_ASPME (1 << 11) // Async Sched Park Mode Enable
|
||||||
|
#define USBCMD_ITC (0x7f << 16) // Int Threshold Control
|
||||||
|
#define USBCMD_ITC_SH 16 // Int Threshold Control Shift
|
||||||
|
|
||||||
|
#define USBSTS 0x0004
|
||||||
|
#define USBSTS_RO_MASK 0x0000003f
|
||||||
|
#define USBSTS_INT (1 << 0) // USB Interrupt
|
||||||
|
#define USBSTS_ERRINT (1 << 1) // Error Interrupt
|
||||||
|
#define USBSTS_PCD (1 << 2) // Port Change Detect
|
||||||
|
#define USBSTS_FLR (1 << 3) // Frame List Rollover
|
||||||
|
#define USBSTS_HSE (1 << 4) // Host System Error
|
||||||
|
#define USBSTS_IAA (1 << 5) // Interrupt on Async Advance
|
||||||
|
#define USBSTS_HALT (1 << 12) // HC Halted
|
||||||
|
#define USBSTS_REC (1 << 13) // Reclamation
|
||||||
|
#define USBSTS_PSS (1 << 14) // Periodic Schedule Status
|
||||||
|
#define USBSTS_ASS (1 << 15) // Asynchronous Schedule Status
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupt enable bits correspond to the interrupt active bits in USBSTS
|
||||||
|
* so no need to redefine here.
|
||||||
|
*/
|
||||||
|
#define USBINTR 0x0008
|
||||||
|
#define USBINTR_MASK 0x0000003f
|
||||||
|
|
||||||
|
#define FRINDEX 0x000c
|
||||||
|
#define CTRLDSSEGMENT 0x0010
|
||||||
|
#define PERIODICLISTBASE 0x0014
|
||||||
|
#define ASYNCLISTADDR 0x0018
|
||||||
|
#define ASYNCLISTADDR_MASK 0xffffffe0
|
||||||
|
|
||||||
|
#define CONFIGFLAG 0x0040
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bits that are reserved or are read-only are masked out of values
|
||||||
|
* written to us by software
|
||||||
|
*/
|
||||||
|
#define PORTSC_RO_MASK 0x007001c0
|
||||||
|
#define PORTSC_RWC_MASK 0x0000002a
|
||||||
|
#define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable
|
||||||
|
#define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable
|
||||||
|
#define PORTSC_WKCN_E (1 << 20) // Wake on Connect Enable
|
||||||
|
#define PORTSC_PTC (15 << 16) // Port Test Control
|
||||||
|
#define PORTSC_PTC_SH 16 // Port Test Control shift
|
||||||
|
#define PORTSC_PIC (3 << 14) // Port Indicator Control
|
||||||
|
#define PORTSC_PIC_SH 14 // Port Indicator Control Shift
|
||||||
|
#define PORTSC_POWNER (1 << 13) // Port Owner
|
||||||
|
#define PORTSC_PPOWER (1 << 12) // Port Power
|
||||||
|
#define PORTSC_LINESTAT (3 << 10) // Port Line Status
|
||||||
|
#define PORTSC_LINESTAT_SH 10 // Port Line Status Shift
|
||||||
|
#define PORTSC_PRESET (1 << 8) // Port Reset
|
||||||
|
#define PORTSC_SUSPEND (1 << 7) // Port Suspend
|
||||||
|
#define PORTSC_FPRES (1 << 6) // Force Port Resume
|
||||||
|
#define PORTSC_OCC (1 << 5) // Over Current Change
|
||||||
|
#define PORTSC_OCA (1 << 4) // Over Current Active
|
||||||
|
#define PORTSC_PEDC (1 << 3) // Port Enable/Disable Change
|
||||||
|
#define PORTSC_PED (1 << 2) // Port Enable/Disable
|
||||||
|
#define PORTSC_CSC (1 << 1) // Connect Status Change
|
||||||
|
#define PORTSC_CONNECT (1 << 0) // Current Connect Status
|
||||||
|
|
||||||
|
#endif /* HW_USB_EHCI_REGS_H */
|
40
include/hw/usb/uhci-regs.h
Normal file
40
include/hw/usb/uhci-regs.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef HW_USB_UHCI_REGS_H
|
||||||
|
#define HW_USB_UHCI_REGS_H 1
|
||||||
|
|
||||||
|
#define UHCI_CMD_FGR (1 << 4)
|
||||||
|
#define UHCI_CMD_EGSM (1 << 3)
|
||||||
|
#define UHCI_CMD_GRESET (1 << 2)
|
||||||
|
#define UHCI_CMD_HCRESET (1 << 1)
|
||||||
|
#define UHCI_CMD_RS (1 << 0)
|
||||||
|
|
||||||
|
#define UHCI_STS_HCHALTED (1 << 5)
|
||||||
|
#define UHCI_STS_HCPERR (1 << 4)
|
||||||
|
#define UHCI_STS_HSERR (1 << 3)
|
||||||
|
#define UHCI_STS_RD (1 << 2)
|
||||||
|
#define UHCI_STS_USBERR (1 << 1)
|
||||||
|
#define UHCI_STS_USBINT (1 << 0)
|
||||||
|
|
||||||
|
#define TD_CTRL_SPD (1 << 29)
|
||||||
|
#define TD_CTRL_ERROR_SHIFT 27
|
||||||
|
#define TD_CTRL_IOS (1 << 25)
|
||||||
|
#define TD_CTRL_IOC (1 << 24)
|
||||||
|
#define TD_CTRL_ACTIVE (1 << 23)
|
||||||
|
#define TD_CTRL_STALL (1 << 22)
|
||||||
|
#define TD_CTRL_BABBLE (1 << 20)
|
||||||
|
#define TD_CTRL_NAK (1 << 19)
|
||||||
|
#define TD_CTRL_TIMEOUT (1 << 18)
|
||||||
|
|
||||||
|
#define UHCI_PORT_SUSPEND (1 << 12)
|
||||||
|
#define UHCI_PORT_RESET (1 << 9)
|
||||||
|
#define UHCI_PORT_LSDA (1 << 8)
|
||||||
|
#define UHCI_PORT_RSVD1 (1 << 7)
|
||||||
|
#define UHCI_PORT_RD (1 << 6)
|
||||||
|
#define UHCI_PORT_ENC (1 << 3)
|
||||||
|
#define UHCI_PORT_EN (1 << 2)
|
||||||
|
#define UHCI_PORT_CSC (1 << 1)
|
||||||
|
#define UHCI_PORT_CCS (1 << 0)
|
||||||
|
|
||||||
|
#define UHCI_PORT_READ_ONLY (0x1bb)
|
||||||
|
#define UHCI_PORT_WRITE_CLEAR (UHCI_PORT_CSC | UHCI_PORT_ENC)
|
||||||
|
|
||||||
|
#endif /* HW_USB_UHCI_REGS_H */
|
@ -154,6 +154,8 @@ gcov-files-i386-y += hw/pci-bridge/ioh3420.c
|
|||||||
check-qtest-i386-y += tests/usb-hcd-ehci-test$(EXESUF)
|
check-qtest-i386-y += tests/usb-hcd-ehci-test$(EXESUF)
|
||||||
gcov-files-i386-y += hw/usb/hcd-ehci.c
|
gcov-files-i386-y += hw/usb/hcd-ehci.c
|
||||||
gcov-files-i386-y += hw/usb/hcd-uhci.c
|
gcov-files-i386-y += hw/usb/hcd-uhci.c
|
||||||
|
gcov-files-i386-y += hw/usb/dev-hid.c
|
||||||
|
gcov-files-i386-y += hw/usb/dev-storage.c
|
||||||
check-qtest-x86_64-y = $(check-qtest-i386-y)
|
check-qtest-x86_64-y = $(check-qtest-i386-y)
|
||||||
gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c
|
gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c
|
||||||
gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
|
gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
|
||||||
@ -319,7 +321,7 @@ tests/ac97-test$(EXESUF): tests/ac97-test.o
|
|||||||
tests/es1370-test$(EXESUF): tests/es1370-test.o
|
tests/es1370-test$(EXESUF): tests/es1370-test.o
|
||||||
tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
|
tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
|
||||||
tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
|
tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
|
||||||
tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o
|
tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-pc-obj-y)
|
||||||
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
|
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
|
||||||
tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a
|
tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value)
|
|||||||
|
|
||||||
void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
|
void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
|
||||||
{
|
{
|
||||||
dev->bus->config_writew(dev->bus, dev->devfn, offset, value);
|
dev->bus->config_writel(dev->bus, dev->devfn, offset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,12 +9,149 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include "libqtest.h"
|
#include "libqtest.h"
|
||||||
|
#include "libqos/pci-pc.h"
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "hw/usb/uhci-regs.h"
|
||||||
|
#include "hw/usb/ehci-regs.h"
|
||||||
|
|
||||||
/* Tests only initialization so far. TODO: Replace with functional tests */
|
struct qhc {
|
||||||
static void pci_nop(void)
|
QPCIDevice *dev;
|
||||||
|
void *base;
|
||||||
|
};
|
||||||
|
|
||||||
|
static QPCIBus *pcibus;
|
||||||
|
static struct qhc uhci1;
|
||||||
|
static struct qhc uhci2;
|
||||||
|
static struct qhc uhci3;
|
||||||
|
static struct qhc ehci1;
|
||||||
|
|
||||||
|
/* helpers */
|
||||||
|
|
||||||
|
static void pci_init_one(struct qhc *hc, uint32_t devfn, int bar)
|
||||||
{
|
{
|
||||||
|
hc->dev = qpci_device_find(pcibus, devfn);
|
||||||
|
g_assert(hc->dev != NULL);
|
||||||
|
qpci_device_enable(hc->dev);
|
||||||
|
hc->base = qpci_iomap(hc->dev, bar);
|
||||||
|
g_assert(hc->base != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void uhci_port_update(struct qhc *hc, int port,
|
||||||
|
uint16_t set, uint16_t clear)
|
||||||
|
{
|
||||||
|
void *addr = hc->base + 0x10 + 2 * port;
|
||||||
|
uint16_t value;
|
||||||
|
|
||||||
|
value = qpci_io_readw(hc->dev, addr);
|
||||||
|
value |= set;
|
||||||
|
value &= ~clear;
|
||||||
|
qpci_io_writew(hc->dev, addr, value);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void uhci_port_test(struct qhc *hc, int port, uint16_t expect)
|
||||||
|
{
|
||||||
|
void *addr = hc->base + 0x10 + 2 * port;
|
||||||
|
uint16_t value = qpci_io_readw(hc->dev, addr);
|
||||||
|
uint16_t mask = ~(UHCI_PORT_WRITE_CLEAR | UHCI_PORT_RSVD1);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
fprintf(stderr, "%s: %d, have 0x%04x, want 0x%04x\n",
|
||||||
|
__func__, port, value & mask, expect & mask);
|
||||||
|
#endif
|
||||||
|
g_assert((value & mask) == (expect & mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ehci_port_test(struct qhc *hc, int port, uint32_t expect)
|
||||||
|
{
|
||||||
|
void *addr = hc->base + 0x64 + 4 * port;
|
||||||
|
uint32_t value = qpci_io_readl(hc->dev, addr);
|
||||||
|
uint16_t mask = ~(PORTSC_CSC | PORTSC_PEDC | PORTSC_OCC);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
fprintf(stderr, "%s: %d, have 0x%08x, want 0x%08x\n",
|
||||||
|
__func__, port, value & mask, expect & mask);
|
||||||
|
#endif
|
||||||
|
g_assert((value & mask) == (expect & mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tests */
|
||||||
|
|
||||||
|
static void pci_init(void)
|
||||||
|
{
|
||||||
|
if (pcibus) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pcibus = qpci_init_pc();
|
||||||
|
g_assert(pcibus != NULL);
|
||||||
|
|
||||||
|
pci_init_one(&uhci1, QPCI_DEVFN(0x1d, 0), 4);
|
||||||
|
pci_init_one(&uhci2, QPCI_DEVFN(0x1d, 1), 4);
|
||||||
|
pci_init_one(&uhci3, QPCI_DEVFN(0x1d, 2), 4);
|
||||||
|
pci_init_one(&ehci1, QPCI_DEVFN(0x1d, 7), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pci_uhci_port_1(void)
|
||||||
|
{
|
||||||
|
g_assert(pcibus != NULL);
|
||||||
|
|
||||||
|
uhci_port_test(&uhci1, 0, UHCI_PORT_CCS); /* usb-tablet */
|
||||||
|
uhci_port_test(&uhci1, 1, UHCI_PORT_CCS); /* usb-storage */
|
||||||
|
uhci_port_test(&uhci2, 0, 0);
|
||||||
|
uhci_port_test(&uhci2, 1, 0);
|
||||||
|
uhci_port_test(&uhci3, 0, 0);
|
||||||
|
uhci_port_test(&uhci3, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pci_ehci_port_1(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
g_assert(pcibus != NULL);
|
||||||
|
|
||||||
|
for (i = 0; i < 6; i++) {
|
||||||
|
ehci_port_test(&ehci1, i, PORTSC_POWNER | PORTSC_PPOWER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pci_ehci_config(void)
|
||||||
|
{
|
||||||
|
/* hands over all ports from companion uhci to ehci */
|
||||||
|
qpci_io_writew(ehci1.dev, ehci1.base + 0x60, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pci_uhci_port_2(void)
|
||||||
|
{
|
||||||
|
g_assert(pcibus != NULL);
|
||||||
|
|
||||||
|
uhci_port_test(&uhci1, 0, 0); /* usb-tablet, @ehci */
|
||||||
|
uhci_port_test(&uhci1, 1, 0); /* usb-storage, @ehci */
|
||||||
|
uhci_port_test(&uhci2, 0, 0);
|
||||||
|
uhci_port_test(&uhci2, 1, 0);
|
||||||
|
uhci_port_test(&uhci3, 0, 0);
|
||||||
|
uhci_port_test(&uhci3, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pci_ehci_port_2(void)
|
||||||
|
{
|
||||||
|
static uint32_t expect[] = {
|
||||||
|
PORTSC_PPOWER | PORTSC_CONNECT, /* usb-tablet */
|
||||||
|
PORTSC_PPOWER | PORTSC_CONNECT, /* usb-storage */
|
||||||
|
PORTSC_PPOWER,
|
||||||
|
PORTSC_PPOWER,
|
||||||
|
PORTSC_PPOWER,
|
||||||
|
PORTSC_PPOWER,
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
g_assert(pcibus != NULL);
|
||||||
|
|
||||||
|
for (i = 0; i < 6; i++) {
|
||||||
|
ehci_port_test(&ehci1, i, expect[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
@ -22,7 +159,12 @@ int main(int argc, char **argv)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
qtest_add_func("/ehci/pci/nop", pci_nop);
|
qtest_add_func("/ehci/pci/init", pci_init);
|
||||||
|
qtest_add_func("/ehci/pci/uhci-port-1", pci_uhci_port_1);
|
||||||
|
qtest_add_func("/ehci/pci/ehci-port-1", pci_ehci_port_1);
|
||||||
|
qtest_add_func("/ehci/pci/ehci-config", pci_ehci_config);
|
||||||
|
qtest_add_func("/ehci/pci/uhci-port-2", pci_uhci_port_2);
|
||||||
|
qtest_add_func("/ehci/pci/ehci-port-2", pci_ehci_port_2);
|
||||||
|
|
||||||
qtest_start("-machine q35 -device ich9-usb-ehci1,bus=pcie.0,addr=1d.7,"
|
qtest_start("-machine q35 -device ich9-usb-ehci1,bus=pcie.0,addr=1d.7,"
|
||||||
"multifunction=on,id=ich9-ehci-1 "
|
"multifunction=on,id=ich9-ehci-1 "
|
||||||
@ -31,7 +173,10 @@ int main(int argc, char **argv)
|
|||||||
"-device ich9-usb-uhci2,bus=pcie.0,addr=1d.1,"
|
"-device ich9-usb-uhci2,bus=pcie.0,addr=1d.1,"
|
||||||
"multifunction=on,masterbus=ich9-ehci-1.0,firstport=2 "
|
"multifunction=on,masterbus=ich9-ehci-1.0,firstport=2 "
|
||||||
"-device ich9-usb-uhci3,bus=pcie.0,addr=1d.2,"
|
"-device ich9-usb-uhci3,bus=pcie.0,addr=1d.2,"
|
||||||
"multifunction=on,masterbus=ich9-ehci-1.0,firstport=4");
|
"multifunction=on,masterbus=ich9-ehci-1.0,firstport=4 "
|
||||||
|
"-drive if=none,id=usbcdrom,media=cdrom "
|
||||||
|
"-device usb-tablet,bus=ich9-ehci-1.0,port=1,usb_version=1 "
|
||||||
|
"-device usb-storage,bus=ich9-ehci-1.0,port=2,drive=usbcdrom ");
|
||||||
ret = g_test_run();
|
ret = g_test_run();
|
||||||
|
|
||||||
qtest_end();
|
qtest_end();
|
||||||
|
@ -371,7 +371,7 @@ usb_xhci_irq_msix_use(uint32_t nr) "nr %d"
|
|||||||
usb_xhci_irq_msix_unuse(uint32_t nr) "nr %d"
|
usb_xhci_irq_msix_unuse(uint32_t nr) "nr %d"
|
||||||
usb_xhci_queue_event(uint32_t vector, uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "v %d, idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
usb_xhci_queue_event(uint32_t vector, uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "v %d, idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
||||||
usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x"
|
||||||
usb_xhci_port_reset(uint32_t port) "port %d"
|
usb_xhci_port_reset(uint32_t port, bool warm) "port %d, warm %d"
|
||||||
usb_xhci_port_link(uint32_t port, uint32_t pls) "port %d, pls %d"
|
usb_xhci_port_link(uint32_t port, uint32_t pls) "port %d, pls %d"
|
||||||
usb_xhci_port_notify(uint32_t port, uint32_t pls) "port %d, bits %x"
|
usb_xhci_port_notify(uint32_t port, uint32_t pls) "port %d, bits %x"
|
||||||
usb_xhci_slot_enable(uint32_t slotid) "slotid %d"
|
usb_xhci_slot_enable(uint32_t slotid) "slotid %d"
|
||||||
|
Loading…
Reference in New Issue
Block a user