Merge remote-tracking branch 'kraxel/usb.75' into staging

* kraxel/usb.75: (32 commits)
  uhci: stop using portio lists
  usbredir: Add support for buffered bulk input (v2)
  exynos4210: Add EHCI support
  usb/ehci: Add SysBus EHCI device for Exynos4210
  usb/ehci: Move capsbase and opregbase into SysBus EHCI class
  usb/ehci: Clean up SysBus and PCI EHCI split
  xhci: call set-address with dummy usbpacket
  usb-redir: Add debugging to bufpq save / restore
  usbredir: Add usbredir_init_endpoints() helper
  usbredir: Verify we have 32 bits bulk length cap when redirecting to xhci
  usbredir: Add ep_stopped USBDevice method
  usbredir: Add USBEP2I and I2USBEP helper macros
  usbredir: Add an usbredir_stop_ep helper function
  usb: Add an usb_device_ep_stopped USBDevice method
  usb: Fix usb_ep_find_packet_by_id
  hid: Change idle handling to use a timer
  uhci: Maximize how many frames we catch up when behind
  uhci: Limit amount of frames processed in one go
  uhci: Add a QH_VALID define
  uhci: Fix pending interrupts getting lost on migration
  ...

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Anthony Liguori
2013-01-08 10:36:20 -06:00
23 changed files with 3280 additions and 333 deletions
Vendored
+1 -1
View File
@@ -2851,7 +2851,7 @@ fi
# check for usbredirparser for usb network redirection support
if test "$usb_redir" != "no" ; then
if $pkg_config --atleast-version=0.5.3 libusbredirparser-0.5 >/dev/null 2>&1 ; then
if $pkg_config --atleast-version=0.6 libusbredirparser-0.5 >/dev/null 2>&1 ; then
usb_redir="yes"
usb_redir_cflags=$($pkg_config --cflags libusbredirparser-0.5 2>/dev/null)
usb_redir_libs=$($pkg_config --libs libusbredirparser-0.5 2>/dev/null)
+7
View File
@@ -27,6 +27,7 @@
#include "arm-misc.h"
#include "loader.h"
#include "exynos4210.h"
#include "usb/hcd-ehci.h"
#define EXYNOS4210_CHIPID_ADDR 0x10000000
@@ -72,6 +73,9 @@
/* Display controllers (FIMD) */
#define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000
/* EHCI */
#define EXYNOS4210_EHCI_BASE_ADDR 0x12580000
static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
0x09, 0x00, 0x00, 0x00 };
@@ -338,5 +342,8 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
s->irq_table[exynos4210_get_irq(11, 2)],
NULL);
sysbus_create_simple(TYPE_EXYNOS4210_EHCI, EXYNOS4210_EHCI_BASE_ADDR,
s->irq_table[exynos4210_get_irq(28, 3)]);
return s;
}
+1 -1
View File
@@ -140,7 +140,7 @@ combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = {
EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6,
EXT_GIC_ID_I2C7 },
/* int combiner group 28 */
{ EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 },
{ EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 , EXT_GIC_ID_USB_HOST},
/* int combiner group 29 */
{ EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2,
EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC },
+37 -6
View File
@@ -71,12 +71,38 @@ static const uint8_t hid_usage_keys[0x100] = {
bool hid_has_events(HIDState *hs)
{
return hs->n > 0;
return hs->n > 0 || hs->idle_pending;
}
void hid_set_next_idle(HIDState *hs, int64_t curtime)
static void hid_idle_timer(void *opaque)
{
hs->next_idle_clock = curtime + (get_ticks_per_sec() * hs->idle * 4) / 1000;
HIDState *hs = opaque;
hs->idle_pending = true;
hs->event(hs);
}
static void hid_del_idle_timer(HIDState *hs)
{
if (hs->idle_timer) {
qemu_del_timer(hs->idle_timer);
qemu_free_timer(hs->idle_timer);
hs->idle_timer = NULL;
}
}
void hid_set_next_idle(HIDState *hs)
{
if (hs->idle) {
uint64_t expire_time = qemu_get_clock_ns(vm_clock) +
get_ticks_per_sec() * hs->idle * 4 / 1000;
if (!hs->idle_timer) {
hs->idle_timer = qemu_new_timer_ns(vm_clock, hid_idle_timer, hs);
}
qemu_mod_timer_ns(hs->idle_timer, expire_time);
} else {
hid_del_idle_timer(hs);
}
}
static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
@@ -232,6 +258,8 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
int index;
HIDPointerEvent *e;
hs->idle_pending = false;
hid_pointer_activate(hs);
/* When the buffer is empty, return the last event. Relative
@@ -319,6 +347,8 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
{
hs->idle_pending = false;
if (len < 2) {
return 0;
}
@@ -377,6 +407,8 @@ void hid_reset(HIDState *hs)
hs->n = 0;
hs->protocol = 1;
hs->idle = 0;
hs->idle_pending = false;
hid_del_idle_timer(hs);
}
void hid_free(HIDState *hs)
@@ -390,6 +422,7 @@ void hid_free(HIDState *hs)
qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
break;
}
hid_del_idle_timer(hs);
}
void hid_init(HIDState *hs, int kind, HIDEventFunc event)
@@ -412,9 +445,7 @@ static int hid_post_load(void *opaque, int version_id)
{
HIDState *s = opaque;
if (s->idle) {
hid_set_next_idle(s, qemu_get_clock_ns(vm_clock));
}
hid_set_next_idle(s);
return 0;
}
+3 -2
View File
@@ -43,7 +43,8 @@ struct HIDState {
int kind;
int32_t protocol;
uint8_t idle;
int64_t next_idle_clock;
bool idle_pending;
QEMUTimer *idle_timer;
HIDEventFunc event;
};
@@ -52,7 +53,7 @@ void hid_reset(HIDState *hs);
void hid_free(HIDState *hs);
bool hid_has_events(HIDState *hs);
void hid_set_next_idle(HIDState *hs, int64_t curtime);
void hid_set_next_idle(HIDState *hs);
void hid_pointer_activate(HIDState *hs);
int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len);
int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len);
+19 -1
View File
@@ -307,6 +307,12 @@ typedef struct USBDeviceClass {
*/
void (*flush_ep_queue)(USBDevice *dev, USBEndpoint *ep);
/*
* Called by the hcd to let the device know the queue for an endpoint
* has been unlinked / stopped. Optional may be NULL.
*/
void (*ep_stopped)(USBDevice *dev, USBEndpoint *ep);
const char *product_desc;
const USBDesc *usb_desc;
} USBDeviceClass;
@@ -539,11 +545,23 @@ void usb_device_set_interface(USBDevice *dev, int interface,
void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep);
void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep);
const char *usb_device_get_product_desc(USBDevice *dev);
const USBDesc *usb_device_get_usb_desc(USBDevice *dev);
int ehci_create_ich9_with_companions(PCIBus *bus, int slot);
#endif
/* quirks.c */
/* In bulk endpoints are streaming data sources (iow behave like isoc eps) */
#define USB_QUIRK_BUFFER_BULK_IN 0x01
/* Bulk pkts in FTDI format, need special handling when combining packets */
#define USB_QUIRK_IS_FTDI 0x02
int usb_get_quirks(uint16_t vendor_id, uint16_t product_id,
uint8_t interface_class, uint8_t interface_subclass,
uint8_t interface_protocol);
#endif
+1 -1
View File
@@ -5,7 +5,7 @@ common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
common-obj-y += libhw.o
common-obj-$(CONFIG_SMARTCARD) += dev-smartcard-reader.o
common-obj-$(CONFIG_USB_REDIR) += redirect.o
common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
common-obj-y += core.o combined-packet.o bus.o desc.o dev-hub.o
common-obj-y += host-$(HOST_USB).o dev-bluetooth.o
+8
View File
@@ -189,6 +189,14 @@ void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
}
}
void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep)
{
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
if (klass->ep_stopped) {
klass->ep_stopped(dev, ep);
}
}
static int usb_qdev_init(DeviceState *qdev)
{
USBDevice *dev = USB_DEVICE(qdev);
+1 -1
View File
@@ -761,7 +761,7 @@ USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
USBPacket *p;
while ((p = QTAILQ_FIRST(&uep->queue)) != NULL) {
QTAILQ_FOREACH(p, &uep->queue, queue) {
if (p->id == id) {
return p;
}
+3 -5
View File
@@ -501,7 +501,7 @@ static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
break;
case SET_IDLE:
hs->idle = (uint8_t) (value >> 8);
hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock));
hid_set_next_idle(hs);
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
hid_pointer_activate(hs);
}
@@ -523,16 +523,14 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
switch (p->pid) {
case USB_TOKEN_IN:
if (p->ep->nr == 1) {
int64_t curtime = qemu_get_clock_ns(vm_clock);
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
hid_pointer_activate(hs);
}
if (!hid_has_events(hs) &&
(!hs->idle || hs->next_idle_clock - curtime > 0)) {
if (!hid_has_events(hs)) {
p->status = USB_RET_NAK;
return;
}
hid_set_next_idle(hs, curtime);
hid_set_next_idle(hs);
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
len = hid_pointer_poll(hs, buf, p->iov.size);
} else if (hs->kind == HID_KEYBOARD) {
+24 -15
View File
@@ -16,14 +16,8 @@
*/
#include "hw/usb/hcd-ehci.h"
#include "hw/pci/pci.h"
#include "qemu/range.h"
typedef struct EHCIPCIState {
PCIDevice pcidev;
EHCIState ehci;
} EHCIPCIState;
typedef struct EHCIPCIInfo {
const char *name;
uint16_t vendor_id;
@@ -33,7 +27,7 @@ typedef struct EHCIPCIInfo {
static int usb_ehci_pci_initfn(PCIDevice *dev)
{
EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
EHCIPCIState *i = PCI_EHCI(dev);
EHCIState *s = &i->ehci;
uint8_t *pci_conf = dev->config;
@@ -83,7 +77,7 @@ static int usb_ehci_pci_initfn(PCIDevice *dev)
static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr,
uint32_t val, int l)
{
EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
EHCIPCIState *i = PCI_EHCI(dev);
bool busmaster;
pci_default_write_config(dev, addr, val, l);
@@ -115,12 +109,8 @@ static void ehci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
EHCIPCIInfo *i = data;
k->init = usb_ehci_pci_initfn;
k->vendor_id = i->vendor_id;
k->device_id = i->device_id;
k->revision = i->revision;
k->class_id = PCI_CLASS_SERIAL_USB;
k->config_write = usb_ehci_pci_write_config;
k->no_hotplug = 1;
@@ -128,6 +118,24 @@ static void ehci_class_init(ObjectClass *klass, void *data)
dc->props = ehci_pci_properties;
}
static const TypeInfo ehci_pci_type_info = {
.name = TYPE_PCI_EHCI,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(EHCIPCIState),
.abstract = true,
.class_init = ehci_class_init,
};
static void ehci_data_class_init(ObjectClass *klass, void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
EHCIPCIInfo *i = data;
k->vendor_id = i->vendor_id;
k->device_id = i->device_id;
k->revision = i->revision;
}
static struct EHCIPCIInfo ehci_pci_info[] = {
{
.name = "usb-ehci",
@@ -150,12 +158,13 @@ static struct EHCIPCIInfo ehci_pci_info[] = {
static void ehci_pci_register_types(void)
{
TypeInfo ehci_type_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(EHCIPCIState),
.class_init = ehci_class_init,
.parent = TYPE_PCI_EHCI,
.class_init = ehci_data_class_init,
};
int i;
type_register_static(&ehci_pci_type_info);
for (i = 0; i < ARRAY_SIZE(ehci_pci_info); i++) {
ehci_type_info.name = ehci_pci_info[i].name;
ehci_type_info.class_data = ehci_pci_info + i;
+38 -11
View File
@@ -16,12 +16,6 @@
*/
#include "hw/usb/hcd-ehci.h"
#include "hw/sysbus.h"
typedef struct EHCISysBusState {
SysBusDevice busdev;
EHCIState ehci;
} EHCISysBusState;
static const VMStateDescription vmstate_ehci_sysbus = {
.name = "ehci-sysbus",
@@ -40,11 +34,12 @@ static Property ehci_sysbus_properties[] = {
static int usb_ehci_sysbus_initfn(SysBusDevice *dev)
{
EHCISysBusState *i = FROM_SYSBUS(EHCISysBusState, dev);
EHCISysBusState *i = SYS_BUS_EHCI(dev);
SysBusEHCIClass *sec = SYS_BUS_EHCI_GET_CLASS(dev);
EHCIState *s = &i->ehci;
s->capsbase = 0x100;
s->opregbase = 0x140;
s->capsbase = sec->capsbase;
s->opregbase = sec->opregbase;
s->dma = &dma_context_memory;
usb_ehci_initfn(s, DEVICE(dev));
@@ -63,16 +58,48 @@ static void ehci_sysbus_class_init(ObjectClass *klass, void *data)
dc->props = ehci_sysbus_properties;
}
TypeInfo ehci_xlnx_type_info = {
.name = "xlnx,ps7-usb",
static const TypeInfo ehci_type_info = {
.name = TYPE_SYS_BUS_EHCI,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(EHCISysBusState),
.abstract = true,
.class_init = ehci_sysbus_class_init,
.class_size = sizeof(SysBusEHCIClass),
};
static void ehci_xlnx_class_init(ObjectClass *oc, void *data)
{
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
sec->capsbase = 0x100;
sec->opregbase = 0x140;
}
static const TypeInfo ehci_xlnx_type_info = {
.name = "xlnx,ps7-usb",
.parent = TYPE_SYS_BUS_EHCI,
.class_init = ehci_xlnx_class_init,
};
static void ehci_exynos4210_class_init(ObjectClass *oc, void *data)
{
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
sec->capsbase = 0x0;
sec->opregbase = 0x10;
}
static const TypeInfo ehci_exynos4210_type_info = {
.name = TYPE_EXYNOS4210_EHCI,
.parent = TYPE_SYS_BUS_EHCI,
.class_init = ehci_exynos4210_class_init,
};
static void ehci_sysbus_register_types(void)
{
type_register_static(&ehci_type_info);
type_register_static(&ehci_xlnx_type_info);
type_register_static(&ehci_exynos4210_type_info);
}
type_init(ehci_sysbus_register_types)
+216 -131
View File
File diff suppressed because it is too large Load Diff
+42
View File
@@ -24,6 +24,8 @@
#include "trace.h"
#include "sysemu/dma.h"
#include "sysemu/sysemu.h"
#include "hw/pci/pci.h"
#include "hw/sysbus.h"
#ifndef EHCI_DEBUG
#define EHCI_DEBUG 0
@@ -248,6 +250,7 @@ struct EHCIQueue {
EHCIqh qh; /* copy of current QH (being worked on) */
uint32_t qhaddr; /* address QH read from */
uint32_t qtdaddr; /* address QTD read from */
int last_pid; /* pid of last packet executed */
USBDevice *dev;
QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
};
@@ -321,4 +324,43 @@ extern const VMStateDescription vmstate_ehci;
void usb_ehci_initfn(EHCIState *s, DeviceState *dev);
#define TYPE_PCI_EHCI "pci-ehci-usb"
#define PCI_EHCI(obj) OBJECT_CHECK(EHCIPCIState, (obj), TYPE_PCI_EHCI)
typedef struct EHCIPCIState {
/*< private >*/
PCIDevice pcidev;
/*< public >*/
EHCIState ehci;
} EHCIPCIState;
#define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb"
#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
#define SYS_BUS_EHCI(obj) \
OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI)
#define SYS_BUS_EHCI_CLASS(class) \
OBJECT_CLASS_CHECK(SysBusEHCIClass, (class), TYPE_SYS_BUS_EHCI)
#define SYS_BUS_EHCI_GET_CLASS(obj) \
OBJECT_GET_CLASS(SysBusEHCIClass, (obj), TYPE_SYS_BUS_EHCI)
typedef struct EHCISysBusState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
EHCIState ehci;
} EHCISysBusState;
typedef struct SysBusEHCIClass {
/*< private >*/
SysBusDeviceClass parent_class;
/*< public >*/
uint16_t capsbase;
uint16_t opregbase;
} SysBusEHCIClass;
#endif
+26 -4
View File
@@ -430,6 +430,23 @@ static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr)
return NULL;
}
static void ohci_stop_endpoints(OHCIState *ohci)
{
USBDevice *dev;
int i, j;
for (i = 0; i < ohci->num_ports; i++) {
dev = ohci->rhport[i].port.dev;
if (dev && dev->attached) {
usb_device_ep_stopped(dev, &dev->ep_ctl);
for (j = 0; j < USB_MAX_ENDPOINTS; j++) {
usb_device_ep_stopped(dev, &dev->ep_in[j]);
usb_device_ep_stopped(dev, &dev->ep_out[j]);
}
}
}
}
/* Reset the controller */
static void ohci_reset(void *opaque)
{
@@ -478,6 +495,7 @@ static void ohci_reset(void *opaque)
usb_cancel_packet(&ohci->usb_packet);
ohci->async_td = 0;
}
ohci_stop_endpoints(ohci);
DPRINTF("usb-ohci: Reset %s\n", ohci->name);
}
@@ -1147,6 +1165,8 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
if (ohci->async_td && addr == ohci->async_td) {
usb_cancel_packet(&ohci->usb_packet);
ohci->async_td = 0;
usb_device_ep_stopped(ohci->usb_packet.ep->dev,
ohci->usb_packet.ep);
}
continue;
}
@@ -1227,10 +1247,12 @@ static void ohci_frame_boundary(void *opaque)
}
/* Cancel all pending packets if either of the lists has been disabled. */
if (ohci->async_td &&
ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) {
usb_cancel_packet(&ohci->usb_packet);
ohci->async_td = 0;
if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) {
if (ohci->async_td) {
usb_cancel_packet(&ohci->usb_packet);
ohci->async_td = 0;
}
ohci_stop_endpoints(ohci);
}
ohci->old_ctl = ohci->ctl;
ohci_process_lists(ohci, 0);
+76 -98
View File
@@ -75,6 +75,11 @@
#define FRAME_MAX_LOOPS 256
/* Must be large enough to handle 10 frame delay for initial isoc requests */
#define QH_VALID 32
#define MAX_FRAMES_PER_TICK (QH_VALID / 2)
#define NB_PORTS 2
enum {
@@ -166,6 +171,7 @@ struct UHCIState {
/* Properties */
char *masterbus;
uint32_t firstport;
uint32_t maxframes;
};
typedef struct UHCI_TD {
@@ -206,9 +212,7 @@ static UHCIQueue *uhci_queue_new(UHCIState *s, uint32_t qh_addr, UHCI_TD *td,
queue->ep = ep;
QTAILQ_INIT(&queue->asyncs);
QTAILQ_INSERT_HEAD(&s->queues, queue, next);
/* valid needs to be large enough to handle 10 frame delay
* for initial isochronous requests */
queue->valid = 32;
queue->valid = QH_VALID;
trace_usb_uhci_queue_add(queue->token);
return queue;
}
@@ -222,6 +226,7 @@ static void uhci_queue_free(UHCIQueue *queue, const char *reason)
async = QTAILQ_FIRST(&queue->asyncs);
uhci_async_cancel(async);
}
usb_device_ep_stopped(queue->ep->dev, queue->ep);
trace_usb_uhci_queue_del(queue->token, reason);
QTAILQ_REMOVE(&s->queues, queue, next);
@@ -433,7 +438,7 @@ static int uhci_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_uhci = {
.name = "uhci",
.version_id = 2,
.version_id = 3,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.post_load = uhci_post_load,
@@ -451,44 +456,16 @@ static const VMStateDescription vmstate_uhci = {
VMSTATE_UINT8(status2, UHCIState),
VMSTATE_TIMER(frame_timer, UHCIState),
VMSTATE_INT64_V(expire_time, UHCIState, 2),
VMSTATE_UINT32_V(pending_int_mask, UHCIState, 3),
VMSTATE_END_OF_LIST()
}
};
static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
static void uhci_port_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
UHCIState *s = opaque;
addr &= 0x1f;
switch(addr) {
case 0x0c:
s->sof_timing = val;
break;
}
}
static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr)
{
UHCIState *s = opaque;
uint32_t val;
addr &= 0x1f;
switch(addr) {
case 0x0c:
val = s->sof_timing;
break;
default:
val = 0xff;
break;
}
return val;
}
static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
{
UHCIState *s = opaque;
addr &= 0x1f;
trace_usb_uhci_mmio_writew(addr, val);
switch(addr) {
@@ -498,7 +475,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
trace_usb_uhci_schedule_start();
s->expire_time = qemu_get_clock_ns(vm_clock) +
(get_ticks_per_sec() / FRAME_TIMER_FREQ);
qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
qemu_mod_timer(s->frame_timer, s->expire_time);
s->status &= ~UHCI_STS_HCHALTED;
} else if (!(val & UHCI_CMD_RS)) {
s->status |= UHCI_STS_HCHALTED;
@@ -537,6 +514,17 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
if (s->status & UHCI_STS_HCHALTED)
s->frnum = val & 0x7ff;
break;
case 0x08:
s->fl_base_addr &= 0xffff0000;
s->fl_base_addr |= val & ~0xfff;
break;
case 0x0a:
s->fl_base_addr &= 0x0000ffff;
s->fl_base_addr |= (val << 16);
break;
case 0x0c:
s->sof_timing = val & 0xff;
break;
case 0x10 ... 0x1f:
{
UHCIPort *port;
@@ -568,12 +556,11 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
}
}
static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr)
static uint64_t uhci_port_read(void *opaque, hwaddr addr, unsigned size)
{
UHCIState *s = opaque;
uint32_t val;
addr &= 0x1f;
switch(addr) {
case 0x00:
val = s->cmd;
@@ -587,6 +574,15 @@ static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr)
case 0x06:
val = s->frnum;
break;
case 0x08:
val = s->fl_base_addr & 0xffff;
break;
case 0x0a:
val = (s->fl_base_addr >> 16) & 0xffff;
break;
case 0x0c:
val = s->sof_timing;
break;
case 0x10 ... 0x1f:
{
UHCIPort *port;
@@ -609,38 +605,6 @@ static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr)
return val;
}
static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
{
UHCIState *s = opaque;
addr &= 0x1f;
trace_usb_uhci_mmio_writel(addr, val);
switch(addr) {
case 0x08:
s->fl_base_addr = val & ~0xfff;
break;
}
}
static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr)
{
UHCIState *s = opaque;
uint32_t val;
addr &= 0x1f;
switch(addr) {
case 0x08:
val = s->fl_base_addr;
break;
default:
val = 0xffffffff;
break;
}
trace_usb_uhci_mmio_readl(addr, val);
return val;
}
/* signal resume if controller suspended */
static void uhci_resume (void *opaque)
{
@@ -853,7 +817,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
}
if (q) {
q->valid = 32;
q->valid = QH_VALID;
}
/* Is active ? */
@@ -1174,10 +1138,10 @@ static void uhci_bh(void *opaque)
static void uhci_frame_timer(void *opaque)
{
UHCIState *s = opaque;
uint64_t t_now, t_last_run;
int i, frames;
const uint64_t frame_t = get_ticks_per_sec() / FRAME_TIMER_FREQ;
/* prepare the timer for the next frame */
s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ);
s->frame_bytes = 0;
s->completions_only = false;
qemu_bh_cancel(s->bh);
@@ -1191,7 +1155,35 @@ static void uhci_frame_timer(void *opaque)
return;
}
/* Complete the previous frame */
/* We still store expire_time in our state, for migration */
t_last_run = s->expire_time - frame_t;
t_now = qemu_get_clock_ns(vm_clock);
/* Process up to MAX_FRAMES_PER_TICK frames */
frames = (t_now - t_last_run) / frame_t;
if (frames > s->maxframes) {
int skipped = frames - s->maxframes;
s->expire_time += skipped * frame_t;
s->frnum = (s->frnum + skipped) & 0x7ff;
frames -= skipped;
}
if (frames > MAX_FRAMES_PER_TICK) {
frames = MAX_FRAMES_PER_TICK;
}
for (i = 0; i < frames; i++) {
s->frame_bytes = 0;
trace_usb_uhci_frame_start(s->frnum);
uhci_async_validate_begin(s);
uhci_process_frame(s);
uhci_async_validate_end(s);
/* The spec says frnum is the frame currently being processed, and
* the guest must look at frnum - 1 on interrupt, so inc frnum now */
s->frnum = (s->frnum + 1) & 0x7ff;
s->expire_time += frame_t;
}
/* Complete the previous frame(s) */
if (s->pending_int_mask) {
s->status2 |= s->pending_int_mask;
s->status |= UHCI_STS_USBINT;
@@ -1199,32 +1191,17 @@ static void uhci_frame_timer(void *opaque)
}
s->pending_int_mask = 0;
/* Start new frame */
s->frnum = (s->frnum + 1) & 0x7ff;
trace_usb_uhci_frame_start(s->frnum);
uhci_async_validate_begin(s);
uhci_process_frame(s);
uhci_async_validate_end(s);
qemu_mod_timer(s->frame_timer, s->expire_time);
qemu_mod_timer(s->frame_timer, t_now + frame_t);
}
static const MemoryRegionPortio uhci_portio[] = {
{ 0, 32, 2, .write = uhci_ioport_writew, },
{ 0, 32, 2, .read = uhci_ioport_readw, },
{ 0, 32, 4, .write = uhci_ioport_writel, },
{ 0, 32, 4, .read = uhci_ioport_readl, },
{ 0, 32, 1, .write = uhci_ioport_writeb, },
{ 0, 32, 1, .read = uhci_ioport_readb, },
PORTIO_END_OF_LIST()
};
static const MemoryRegionOps uhci_ioport_ops = {
.old_portio = uhci_portio,
.read = uhci_port_read,
.write = uhci_port_write,
.valid.min_access_size = 1,
.valid.max_access_size = 4,
.impl.min_access_size = 2,
.impl.max_access_size = 2,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static USBPortOps uhci_port_ops = {
@@ -1311,6 +1288,7 @@ static Property uhci_properties[] = {
DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280),
DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128),
DEFINE_PROP_END_OF_LIST(),
};
+13 -1
View File
@@ -1177,6 +1177,7 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
XHCISlot *slot;
XHCIEPContext *epctx;
int i, xferi, killed = 0;
USBEndpoint *ep = NULL;
assert(slotid >= 1 && slotid <= xhci->numslots);
assert(epid >= 1 && epid <= 31);
@@ -1192,9 +1193,15 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
xferi = epctx->next_xfer;
for (i = 0; i < TD_QUEUE; i++) {
if (epctx->transfers[xferi].packet.ep) {
ep = epctx->transfers[xferi].packet.ep;
}
killed += xhci_ep_nuke_one_xfer(&epctx->transfers[xferi]);
xferi = (xferi + 1) % TD_QUEUE;
}
if (ep) {
usb_device_ep_stopped(ep->dev, ep);
}
return killed;
}
@@ -1963,13 +1970,18 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
if (bsr) {
slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT;
} else {
USBPacket p;
slot->devaddr = xhci->devaddr++;
slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slot->devaddr;
DPRINTF("xhci: device address is %d\n", slot->devaddr);
usb_device_reset(dev);
usb_device_handle_control(dev, NULL,
usb_packet_setup(&p, USB_TOKEN_OUT,
usb_ep_get(dev, USB_TOKEN_OUT, 0),
0, false, false);
usb_device_handle_control(dev, &p,
DeviceOutRequest | USB_REQ_SET_ADDRESS,
slot->devaddr, 0, 0, NULL);
assert(p.status != USB_RET_ASYNC);
}
res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx);
File diff suppressed because it is too large Load Diff
+150
View File
@@ -0,0 +1,150 @@
/*
* Prolific PL2303 USB to serial adaptor driver header file
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#define BENQ_VENDOR_ID 0x04a5
#define BENQ_PRODUCT_ID_S81 0x4027
#define PL2303_VENDOR_ID 0x067b
#define PL2303_PRODUCT_ID 0x2303
#define PL2303_PRODUCT_ID_RSAQ2 0x04bb
#define PL2303_PRODUCT_ID_DCU11 0x1234
#define PL2303_PRODUCT_ID_PHAROS 0xaaa0
#define PL2303_PRODUCT_ID_RSAQ3 0xaaa2
#define PL2303_PRODUCT_ID_ALDIGA 0x0611
#define PL2303_PRODUCT_ID_MMX 0x0612
#define PL2303_PRODUCT_ID_GPRS 0x0609
#define PL2303_PRODUCT_ID_HCR331 0x331a
#define PL2303_PRODUCT_ID_MOTOROLA 0x0307
#define ATEN_VENDOR_ID 0x0557
#define ATEN_VENDOR_ID2 0x0547
#define ATEN_PRODUCT_ID 0x2008
#define IODATA_VENDOR_ID 0x04bb
#define IODATA_PRODUCT_ID 0x0a03
#define IODATA_PRODUCT_ID_RSAQ5 0x0a0e
#define ELCOM_VENDOR_ID 0x056e
#define ELCOM_PRODUCT_ID 0x5003
#define ELCOM_PRODUCT_ID_UCSGT 0x5004
#define ITEGNO_VENDOR_ID 0x0eba
#define ITEGNO_PRODUCT_ID 0x1080
#define ITEGNO_PRODUCT_ID_2080 0x2080
#define MA620_VENDOR_ID 0x0df7
#define MA620_PRODUCT_ID 0x0620
#define RATOC_VENDOR_ID 0x0584
#define RATOC_PRODUCT_ID 0xb000
#define TRIPP_VENDOR_ID 0x2478
#define TRIPP_PRODUCT_ID 0x2008
#define RADIOSHACK_VENDOR_ID 0x1453
#define RADIOSHACK_PRODUCT_ID 0x4026
#define DCU10_VENDOR_ID 0x0731
#define DCU10_PRODUCT_ID 0x0528
#define SITECOM_VENDOR_ID 0x6189
#define SITECOM_PRODUCT_ID 0x2068
/* Alcatel OT535/735 USB cable */
#define ALCATEL_VENDOR_ID 0x11f7
#define ALCATEL_PRODUCT_ID 0x02df
/* Samsung I330 phone cradle */
#define SAMSUNG_VENDOR_ID 0x04e8
#define SAMSUNG_PRODUCT_ID 0x8001
#define SIEMENS_VENDOR_ID 0x11f5
#define SIEMENS_PRODUCT_ID_SX1 0x0001
#define SIEMENS_PRODUCT_ID_X65 0x0003
#define SIEMENS_PRODUCT_ID_X75 0x0004
#define SIEMENS_PRODUCT_ID_EF81 0x0005
#define SYNTECH_VENDOR_ID 0x0745
#define SYNTECH_PRODUCT_ID 0x0001
/* Nokia CA-42 Cable */
#define NOKIA_CA42_VENDOR_ID 0x078b
#define NOKIA_CA42_PRODUCT_ID 0x1234
/* CA-42 CLONE Cable www.ca-42.com chipset: Prolific Technology Inc */
#define CA_42_CA42_VENDOR_ID 0x10b5
#define CA_42_CA42_PRODUCT_ID 0xac70
#define SAGEM_VENDOR_ID 0x079b
#define SAGEM_PRODUCT_ID 0x0027
/* Leadtek GPS 9531 (ID 0413:2101) */
#define LEADTEK_VENDOR_ID 0x0413
#define LEADTEK_9531_PRODUCT_ID 0x2101
/* USB GSM cable from Speed Dragon Multimedia, Ltd */
#define SPEEDDRAGON_VENDOR_ID 0x0e55
#define SPEEDDRAGON_PRODUCT_ID 0x110b
/* DATAPILOT Universal-2 Phone Cable */
#define DATAPILOT_U2_VENDOR_ID 0x0731
#define DATAPILOT_U2_PRODUCT_ID 0x2003
/* Belkin "F5U257" Serial Adapter */
#define BELKIN_VENDOR_ID 0x050d
#define BELKIN_PRODUCT_ID 0x0257
/* Alcor Micro Corp. USB 2.0 TO RS-232 */
#define ALCOR_VENDOR_ID 0x058F
#define ALCOR_PRODUCT_ID 0x9720
/* Willcom WS002IN Data Driver (by NetIndex Inc.) */
#define WS002IN_VENDOR_ID 0x11f6
#define WS002IN_PRODUCT_ID 0x2001
/* Corega CG-USBRS232R Serial Adapter */
#define COREGA_VENDOR_ID 0x07aa
#define COREGA_PRODUCT_ID 0x002a
/* Y.C. Cable U.S.A., Inc - USB to RS-232 */
#define YCCABLE_VENDOR_ID 0x05ad
#define YCCABLE_PRODUCT_ID 0x0fba
/* "Superial" USB - Serial */
#define SUPERIAL_VENDOR_ID 0x5372
#define SUPERIAL_PRODUCT_ID 0x2303
/* Hewlett-Packard LD220-HP POS Pole Display */
#define HP_VENDOR_ID 0x03f0
#define HP_LD220_PRODUCT_ID 0x3524
/* Cressi Edy (diving computer) PC interface */
#define CRESSI_VENDOR_ID 0x04b8
#define CRESSI_EDY_PRODUCT_ID 0x0521
/* Zeagle dive computer interface */
#define ZEAGLE_VENDOR_ID 0x04b8
#define ZEAGLE_N2ITION3_PRODUCT_ID 0x0522
/* Sony, USB data cable for CMD-Jxx mobile phones */
#define SONY_VENDOR_ID 0x054c
#define SONY_QN3USB_PRODUCT_ID 0x0437
/* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */
#define SANWA_VENDOR_ID 0x11ad
#define SANWA_PRODUCT_ID 0x0001
/* ADLINK ND-6530 RS232,RS485 and RS422 adapter */
#define ADLINK_VENDOR_ID 0x0b63
#define ADLINK_ND6530_PRODUCT_ID 0x6530
/* SMART USB Serial Adapter */
#define SMART_VENDOR_ID 0x0b8c
#define SMART_PRODUCT_ID 0x2303
+53
View File
@@ -0,0 +1,53 @@
/*
* USB quirk handling
*
* Copyright (c) 2012 Red Hat, Inc.
*
* Red Hat Authors:
* Hans de Goede <hdegoede@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include "quirks.h"
#include "hw/usb.h"
static bool usb_id_match(const struct usb_device_id *ids,
uint16_t vendor_id, uint16_t product_id,
uint8_t interface_class, uint8_t interface_subclass,
uint8_t interface_protocol) {
int i;
for (i = 0; ids[i].vendor_id != -1; i++) {
if (ids[i].vendor_id == vendor_id &&
ids[i].product_id == product_id &&
(ids[i].interface_class == -1 ||
(ids[i].interface_class == interface_class &&
ids[i].interface_subclass == interface_subclass &&
ids[i].interface_protocol == interface_protocol))) {
return true;
}
}
return false;
}
int usb_get_quirks(uint16_t vendor_id, uint16_t product_id,
uint8_t interface_class, uint8_t interface_subclass,
uint8_t interface_protocol)
{
int quirks = 0;
if (usb_id_match(usbredir_raw_serial_ids, vendor_id, product_id,
interface_class, interface_subclass, interface_protocol)) {
quirks |= USB_QUIRK_BUFFER_BULK_IN;
}
if (usb_id_match(usbredir_ftdi_serial_ids, vendor_id, product_id,
interface_class, interface_subclass, interface_protocol)) {
quirks |= USB_QUIRK_BUFFER_BULK_IN | USB_QUIRK_IS_FTDI;
}
return quirks;
}

Some files were not shown because too many files have changed in this diff Show More