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
commit 560c30b1db
23 changed files with 3280 additions and 333 deletions

2
configure vendored
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)

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;
}

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 },

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;
}

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);

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

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

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);

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;
}

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) {

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;

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)

View File

@ -109,12 +109,13 @@
#define FRAME_TIMER_FREQ 1000
#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ)
#define UFRAME_TIMER_NS (FRAME_TIMER_NS / 8)
#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
#define MAX_QH 100 // Max allowable queue heads in a chain
#define MIN_FR_PER_TICK 3 // Min frames to process when catching up
#define PERIODIC_ACTIVE 64
#define MIN_UFR_PER_TICK 24 /* Min frames to process when catching up */
#define PERIODIC_ACTIVE 512 /* Micro-frames */
/* Internal periodic / asynchronous schedule state machine states
*/
@ -192,6 +193,7 @@ static int ehci_state_executing(EHCIQueue *q);
static int ehci_state_writeback(EHCIQueue *q);
static int ehci_state_advqueue(EHCIQueue *q);
static int ehci_fill_queue(EHCIPacket *p);
static void ehci_free_packet(EHCIPacket *p);
static const char *nr2str(const char **n, size_t len, uint32_t nr)
{
@ -438,6 +440,136 @@ static inline bool ehci_periodic_enabled(EHCIState *s)
return ehci_enabled(s) && (s->usbcmd & USBCMD_PSE);
}
/* Get an array of dwords from main memory */
static inline int get_dwords(EHCIState *ehci, uint32_t addr,
uint32_t *buf, int num)
{
int i;
if (!ehci->dma) {
ehci_raise_irq(ehci, USBSTS_HSE);
ehci->usbcmd &= ~USBCMD_RUNSTOP;
trace_usb_ehci_dma_error();
return -1;
}
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
dma_memory_read(ehci->dma, addr, buf, sizeof(*buf));
*buf = le32_to_cpu(*buf);
}
return num;
}
/* Put an array of dwords in to main memory */
static inline int put_dwords(EHCIState *ehci, uint32_t addr,
uint32_t *buf, int num)
{
int i;
if (!ehci->dma) {
ehci_raise_irq(ehci, USBSTS_HSE);
ehci->usbcmd &= ~USBCMD_RUNSTOP;
trace_usb_ehci_dma_error();
return -1;
}
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
uint32_t tmp = cpu_to_le32(*buf);
dma_memory_write(ehci->dma, addr, &tmp, sizeof(tmp));
}
return num;
}
static int ehci_get_pid(EHCIqtd *qtd)
{
switch (get_field(qtd->token, QTD_TOKEN_PID)) {
case 0:
return USB_TOKEN_OUT;
case 1:
return USB_TOKEN_IN;
case 2:
return USB_TOKEN_SETUP;
default:
fprintf(stderr, "bad token\n");
return 0;
}
}
static bool ehci_verify_qh(EHCIQueue *q, EHCIqh *qh)
{
uint32_t devaddr = get_field(qh->epchar, QH_EPCHAR_DEVADDR);
uint32_t endp = get_field(qh->epchar, QH_EPCHAR_EP);
if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) ||
(endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) ||
(qh->current_qtd != q->qh.current_qtd) ||
(q->async && qh->next_qtd != q->qh.next_qtd) ||
(memcmp(&qh->altnext_qtd, &q->qh.altnext_qtd,
7 * sizeof(uint32_t)) != 0) ||
(q->dev != NULL && q->dev->addr != devaddr)) {
return false;
} else {
return true;
}
}
static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd)
{
if (p->qtdaddr != p->queue->qtdaddr ||
(p->queue->async && !NLPTR_TBIT(p->qtd.next) &&
(p->qtd.next != qtd->next)) ||
(!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd->altnext)) ||
p->qtd.token != qtd->token ||
p->qtd.bufptr[0] != qtd->bufptr[0]) {
return false;
} else {
return true;
}
}
static bool ehci_verify_pid(EHCIQueue *q, EHCIqtd *qtd)
{
int ep = get_field(q->qh.epchar, QH_EPCHAR_EP);
int pid = ehci_get_pid(qtd);
/* Note the pid changing is normal for ep 0 (the control ep) */
if (q->last_pid && ep != 0 && pid != q->last_pid) {
return false;
} else {
return true;
}
}
/* Finish executing and writeback a packet outside of the regular
fetchqh -> fetchqtd -> execute -> writeback cycle */
static void ehci_writeback_async_complete_packet(EHCIPacket *p)
{
EHCIQueue *q = p->queue;
EHCIqtd qtd;
EHCIqh qh;
int state;
/* Verify the qh + qtd, like we do when going through fetchqh & fetchqtd */
get_dwords(q->ehci, NLPTR_GET(q->qhaddr),
(uint32_t *) &qh, sizeof(EHCIqh) >> 2);
get_dwords(q->ehci, NLPTR_GET(q->qtdaddr),
(uint32_t *) &qtd, sizeof(EHCIqtd) >> 2);
if (!ehci_verify_qh(q, &qh) || !ehci_verify_qtd(p, &qtd)) {
p->async = EHCI_ASYNC_INITIALIZED;
ehci_free_packet(p);
return;
}
state = ehci_get_state(q->ehci, q->async);
ehci_state_executing(q);
ehci_state_writeback(q); /* Frees the packet! */
if (!(q->qh.token & QTD_TOKEN_HALT)) {
ehci_state_advqueue(q);
}
ehci_set_state(q->ehci, q->async, state);
}
/* packet management */
static EHCIPacket *ehci_alloc_packet(EHCIQueue *q)
@ -455,17 +587,7 @@ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q)
static void ehci_free_packet(EHCIPacket *p)
{
if (p->async == EHCI_ASYNC_FINISHED) {
EHCIQueue *q = p->queue;
int state = ehci_get_state(q->ehci, q->async);
/* This is a normal, but rare condition (cancel racing completion) */
fprintf(stderr, "EHCI: Warning packet completed but not processed\n");
ehci_state_executing(q);
ehci_state_writeback(q);
if (!(q->qh.token & QTD_TOKEN_HALT)) {
ehci_state_advqueue(q);
}
ehci_set_state(q->ehci, q->async, state);
/* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */
ehci_writeback_async_complete_packet(p);
return;
}
trace_usb_ehci_packet_action(p->queue, p, "free");
@ -500,6 +622,17 @@ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async)
return q;
}
static void ehci_queue_stopped(EHCIQueue *q)
{
int endp = get_field(q->qh.epchar, QH_EPCHAR_EP);
if (!q->last_pid || !q->dev) {
return;
}
usb_device_ep_stopped(q->dev, usb_ep_get(q->dev, q->last_pid, endp));
}
static int ehci_cancel_queue(EHCIQueue *q)
{
EHCIPacket *p;
@ -507,7 +640,7 @@ static int ehci_cancel_queue(EHCIQueue *q)
p = QTAILQ_FIRST(&q->packets);
if (p == NULL) {
return 0;
goto leave;
}
trace_usb_ehci_queue_action(q, "cancel");
@ -515,6 +648,9 @@ static int ehci_cancel_queue(EHCIQueue *q)
ehci_free_packet(p);
packets++;
} while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
leave:
ehci_queue_stopped(q);
return packets;
}
@ -526,6 +662,7 @@ static int ehci_reset_queue(EHCIQueue *q)
packets = ehci_cancel_queue(q);
q->dev = NULL;
q->qtdaddr = 0;
q->last_pid = 0;
return packets;
}
@ -634,7 +771,6 @@ static void ehci_attach(USBPort *port)
*portsc |= PORTSC_CSC;
ehci_raise_irq(s, USBSTS_PCD);
ehci_commit_irq(s);
}
static void ehci_detach(USBPort *port)
@ -664,7 +800,6 @@ static void ehci_detach(USBPort *port)
*portsc |= PORTSC_CSC;
ehci_raise_irq(s, USBSTS_PCD);
ehci_commit_irq(s);
}
static void ehci_child_detach(USBPort *port, USBDevice *child)
@ -833,7 +968,15 @@ static uint64_t ehci_opreg_read(void *ptr, hwaddr addr,
EHCIState *s = ptr;
uint32_t val;
val = s->opreg[addr >> 2];
switch (addr) {
case FRINDEX:
/* Round down to mult of 8, else it can go backwards on migration */
val = s->frindex & ~7;
break;
default:
val = s->opreg[addr >> 2];
}
trace_usb_ehci_opreg_read(addr + s->opregbase, addr2str(addr), val);
return val;
}
@ -984,7 +1127,8 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
break;
case FRINDEX:
val &= 0x00003ff8; /* frindex is 14bits and always a multiple of 8 */
val &= 0x00003fff; /* frindex is 14bits */
s->usbsts_frindex = val;
break;
case CONFIGFLAG:
@ -1017,48 +1161,6 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
*mmio, old);
}
/* Get an array of dwords from main memory */
static inline int get_dwords(EHCIState *ehci, uint32_t addr,
uint32_t *buf, int num)
{
int i;
if (!ehci->dma) {
ehci_raise_irq(ehci, USBSTS_HSE);
ehci->usbcmd &= ~USBCMD_RUNSTOP;
trace_usb_ehci_dma_error();
return -1;
}
for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
dma_memory_read(ehci->dma, addr, buf, sizeof(*buf));
*buf = le32_to_cpu(*buf);
}
return num;
}
/* Put an array of dwords in to main memory */
static inline int put_dwords(EHCIState *ehci, uint32_t addr,
uint32_t *buf, int num)
{
int i;
if (!ehci->dma) {
ehci_raise_irq(ehci, USBSTS_HSE);
ehci->usbcmd &= ~USBCMD_RUNSTOP;
trace_usb_ehci_dma_error();
return -1;
}
for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
uint32_t tmp = cpu_to_le32(*buf);
dma_memory_write(ehci->dma, addr, &tmp, sizeof(tmp));
}
return num;
}
/*
* Write the qh back to guest physical memory. This step isn't
* in the EHCI spec but we need to do it since we don't share
@ -1257,6 +1359,9 @@ static void ehci_execute_complete(EHCIQueue *q)
if (tbytes) {
/* 4.15.1.2 must raise int on a short input packet */
ehci_raise_irq(q->ehci, USBSTS_INT);
if (q->async) {
q->ehci->int_req_by_async = true;
}
}
} else {
tbytes = 0;
@ -1301,22 +1406,11 @@ static int ehci_execute(EHCIPacket *p, const char *action)
return -1;
}
p->pid = (p->qtd.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
switch (p->pid) {
case 0:
p->pid = USB_TOKEN_OUT;
break;
case 1:
p->pid = USB_TOKEN_IN;
break;
case 2:
p->pid = USB_TOKEN_SETUP;
break;
default:
fprintf(stderr, "bad token\n");
break;
if (!ehci_verify_pid(p->queue, &p->qtd)) {
ehci_queue_stopped(p->queue); /* Mark the ep in the prev dir stopped */
}
p->pid = ehci_get_pid(&p->qtd);
p->queue->last_pid = p->pid;
endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
ep = usb_ep_get(p->queue->dev, p->pid, endp);
@ -1551,8 +1645,7 @@ out:
static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
{
EHCIPacket *p;
uint32_t entry, devaddr, endp;
uint32_t entry;
EHCIQueue *q;
EHCIqh qh;
@ -1561,7 +1654,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
if (NULL == q) {
q = ehci_alloc_queue(ehci, entry, async);
}
p = QTAILQ_FIRST(&q->packets);
q->seen++;
if (q->seen > 1) {
@ -1582,19 +1674,10 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
* The overlay area of the qh should never be changed by the guest,
* except when idle, in which case the reset is a nop.
*/
devaddr = get_field(qh.epchar, QH_EPCHAR_DEVADDR);
endp = get_field(qh.epchar, QH_EPCHAR_EP);
if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) ||
(endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) ||
(qh.current_qtd != q->qh.current_qtd) ||
(q->async && qh.next_qtd != q->qh.next_qtd) ||
(memcmp(&qh.altnext_qtd, &q->qh.altnext_qtd,
7 * sizeof(uint32_t)) != 0) ||
(q->dev != NULL && q->dev->addr != devaddr)) {
if (!ehci_verify_qh(q, &qh)) {
if (ehci_reset_queue(q) > 0) {
ehci_trace_guest_bug(ehci, "guest updated active QH");
}
p = NULL;
}
q->qh = qh;
@ -1604,14 +1687,8 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
}
if (q->dev == NULL) {
q->dev = ehci_find_device(q->ehci, devaddr);
}
if (p && p->async == EHCI_ASYNC_FINISHED) {
/* I/O finished -- continue processing queue */
trace_usb_ehci_packet_action(p->queue, p, "complete");
ehci_set_state(ehci, async, EST_EXECUTING);
goto out;
q->dev = ehci_find_device(q->ehci,
get_field(q->qh.epchar, QH_EPCHAR_DEVADDR));
}
if (async && (q->qh.epchar & QH_EPCHAR_H)) {
@ -1762,13 +1839,11 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
p = QTAILQ_FIRST(&q->packets);
if (p != NULL) {
if (p->qtdaddr != q->qtdaddr ||
(q->async && !NLPTR_TBIT(p->qtd.next) &&
(p->qtd.next != qtd.next)) ||
(!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) ||
p->qtd.bufptr[0] != qtd.bufptr[0]) {
if (!ehci_verify_qtd(p, &qtd)) {
ehci_cancel_queue(q);
ehci_trace_guest_bug(q->ehci, "guest updated active QH or qTD");
if (qtd.token & QTD_TOKEN_ACTIVE) {
ehci_trace_guest_bug(q->ehci, "guest updated active qTD");
}
p = NULL;
} else {
p->qtd = qtd;
@ -1777,11 +1852,6 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
}
if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
if (p != NULL) {
/* transfer canceled by guest (clear active) */
ehci_cancel_queue(q);
p = NULL;
}
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
} else if (p != NULL) {
switch (p->async) {
@ -1797,10 +1867,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
break;
case EHCI_ASYNC_FINISHED:
/*
* We get here when advqueue moves to a packet which is already
* finished, which can happen with packets queued up by fill_queue
*/
/* Complete executing of the packet */
ehci_set_state(q->ehci, q->async, EST_EXECUTING);
break;
}
@ -1859,6 +1926,10 @@ static int ehci_fill_queue(EHCIPacket *p)
if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
break;
}
if (!ehci_verify_pid(q, &qtd)) {
ehci_trace_guest_bug(q->ehci, "guest queued token with wrong pid");
break;
}
p = ehci_alloc_packet(q);
p->qtdaddr = qtdaddr;
p->qtd = qtd;
@ -2176,16 +2247,16 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
}
}
static void ehci_update_frindex(EHCIState *ehci, int frames)
static void ehci_update_frindex(EHCIState *ehci, int uframes)
{
int i;
if (!ehci_enabled(ehci)) {
if (!ehci_enabled(ehci) && ehci->pstate == EST_INACTIVE) {
return;
}
for (i = 0; i < frames; i++) {
ehci->frindex += 8;
for (i = 0; i < uframes; i++) {
ehci->frindex++;
if (ehci->frindex == 0x00002000) {
ehci_raise_irq(ehci, USBSTS_FLR);
@ -2209,33 +2280,33 @@ static void ehci_frame_timer(void *opaque)
int need_timer = 0;
int64_t expire_time, t_now;
uint64_t ns_elapsed;
int frames, skipped_frames;
int uframes, skipped_uframes;
int i;
t_now = qemu_get_clock_ns(vm_clock);
ns_elapsed = t_now - ehci->last_run_ns;
frames = ns_elapsed / FRAME_TIMER_NS;
uframes = ns_elapsed / UFRAME_TIMER_NS;
if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) {
need_timer++;
if (frames > ehci->maxframes) {
skipped_frames = frames - ehci->maxframes;
ehci_update_frindex(ehci, skipped_frames);
ehci->last_run_ns += FRAME_TIMER_NS * skipped_frames;
frames -= skipped_frames;
DPRINTF("WARNING - EHCI skipped %d frames\n", skipped_frames);
if (uframes > (ehci->maxframes * 8)) {
skipped_uframes = uframes - (ehci->maxframes * 8);
ehci_update_frindex(ehci, skipped_uframes);
ehci->last_run_ns += UFRAME_TIMER_NS * skipped_uframes;
uframes -= skipped_uframes;
DPRINTF("WARNING - EHCI skipped %d uframes\n", skipped_uframes);
}
for (i = 0; i < frames; i++) {
for (i = 0; i < uframes; i++) {
/*
* If we're running behind schedule, we should not catch up
* too fast, as that will make some guests unhappy:
* 1) We must process a minimum of MIN_FR_PER_TICK frames,
* 1) We must process a minimum of MIN_UFR_PER_TICK frames,
* otherwise we will never catch up
* 2) Process frames until the guest has requested an irq (IOC)
*/
if (i >= MIN_FR_PER_TICK) {
if (i >= MIN_UFR_PER_TICK) {
ehci_commit_irq(ehci);
if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) {
break;
@ -2245,13 +2316,15 @@ static void ehci_frame_timer(void *opaque)
ehci->periodic_sched_active--;
}
ehci_update_frindex(ehci, 1);
ehci_advance_periodic_state(ehci);
ehci->last_run_ns += FRAME_TIMER_NS;
if ((ehci->frindex & 7) == 0) {
ehci_advance_periodic_state(ehci);
}
ehci->last_run_ns += UFRAME_TIMER_NS;
}
} else {
ehci->periodic_sched_active = 0;
ehci_update_frindex(ehci, frames);
ehci->last_run_ns += FRAME_TIMER_NS * frames;
ehci_update_frindex(ehci, uframes);
ehci->last_run_ns += UFRAME_TIMER_NS * uframes;
}
if (ehci->periodic_sched_active) {
@ -2282,7 +2355,7 @@ static void ehci_frame_timer(void *opaque)
/* If we've raised int, we speed up the timer, so that we quickly
* notice any new packets queued up in response */
if (ehci->int_req_by_async && (ehci->usbsts & USBSTS_INT)) {
expire_time = t_now + get_ticks_per_sec() / (FRAME_TIMER_FREQ * 2);
expire_time = t_now + get_ticks_per_sec() / (FRAME_TIMER_FREQ * 4);
ehci->int_req_by_async = false;
} else {
expire_time = t_now + (get_ticks_per_sec()
@ -2330,6 +2403,17 @@ static USBBusOps ehci_bus_ops = {
.wakeup_endpoint = ehci_wakeup_endpoint,
};
static void usb_ehci_pre_save(void *opaque)
{
EHCIState *ehci = opaque;
uint32_t new_frindex;
/* Round down frindex to a multiple of 8 for migration compatibility */
new_frindex = ehci->frindex & ~7;
ehci->last_run_ns -= (ehci->frindex - new_frindex) * UFRAME_TIMER_NS;
ehci->frindex = new_frindex;
}
static int usb_ehci_post_load(void *opaque, int version_id)
{
EHCIState *s = opaque;
@ -2380,6 +2464,7 @@ const VMStateDescription vmstate_ehci = {
.name = "ehci-core",
.version_id = 2,
.minimum_version_id = 1,
.pre_save = usb_ehci_pre_save,
.post_load = usb_ehci_post_load,
.fields = (VMStateField[]) {
/* mmio registers */

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

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);

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(),
};

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);

1255
hw/usb/quirks-ftdi-ids.h Normal file

File diff suppressed because it is too large Load Diff

150
hw/usb/quirks-pl2303-ids.h Normal file
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
hw/usb/quirks.c Normal file
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;
}

910
hw/usb/quirks.h Normal file
View File

@ -0,0 +1,910 @@
/*
* 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.
*/
/* 1 on 1 copy of linux/drivers/usb/serial/ftdi_sio_ids.h */
#include "quirks-ftdi-ids.h"
/* 1 on 1 copy of linux/drivers/usb/serial/pl2303.h */
#include "quirks-pl2303-ids.h"
struct usb_device_id {
int vendor_id;
int product_id;
int interface_class;
int interface_subclass;
int interface_protocol;
};
#define USB_DEVICE(vendor, product) \
.vendor_id = vendor, .product_id = product, .interface_class = -1,
#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, iclass, isubclass, iproto) \
.vendor_id = vend, .product_id = prod, .interface_class = iclass, \
.interface_subclass = isubclass, .interface_protocol = iproto
static const struct usb_device_id usbredir_raw_serial_ids[] = {
/*
* Silicon Laboratories CP210x USB to RS232 serial adapter ids
* copied from linux/drivers/usb/serial/cp210x.c
*
* Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk)
*/
{ USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */
{ USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */
{ USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
{ USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
{ USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */
{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
{ USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
{ USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */
{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
{ USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
{ USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */
{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
{ USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */
{ USB_DEVICE(0x10C4, 0x1101) }, /* Arkham Technology DS101 Bus Monitor */
{ USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */
{ USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
{ USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
{ USB_DEVICE(0x10C4, 0x8044) }, /* Cygnal Debug Adapter */
{ USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */
{ USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
{ USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */
{ USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
{ USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */
{ USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */
{ USB_DEVICE(0x10C4, 0x80C4) }, /* Cygnal Integrated Products, Inc., Optris infrared thermometer */
{ USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */
{ USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */
{ USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
{ USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */
{ USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
{ USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */
{ USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */
{ USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */
{ USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */
{ USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
{ USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */
{ USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */
{ USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */
{ USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */
{ USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */
{ USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
{ USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */
{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
{ USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
{ USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
{ USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */
{ USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */
{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
{ USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */
{ USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */
{ USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */
{ USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
{ USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
{ USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
{ USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */
{ USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */
{ USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */
{ USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
{ USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */
{ USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */
{ USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */
{ USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */
{ USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */
{ USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
{ USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
{ USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */
{ USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
{ USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
{ USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */
{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
{ USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */
{ USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */
{ USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */
{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
{ USB_DEVICE(0x166A, 0x0304) }, /* Clipsal 5000CT2 C-Bus Black and White Touchscreen */
{ USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */
{ USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */
{ USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
{ USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */
{ USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
{ USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */
{ USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */
{ USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */
{ USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */
{ USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
{ USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */
{ USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */
{ USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */
{ USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */
{ USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */
{ USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */
{ USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
/*
* Prolific pl2303 USB to RS232 serial adapter ids
* copied from linux/drivers/usb/serial/pl2303.c
*
* Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2003 IBM Corp.
*/
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
{ USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) },
{ USB_DEVICE(-1, -1) } /* Terminating Entry */
};
static const struct usb_device_id usbredir_ftdi_serial_ids[] = {
/*
* FTDI USB to RS232 serial adapter ids
* copied from linux/drivers/usb/serial/ftdi_sio.c
*
* Copyright (C) 2009 - 2010
* Johan Hovold (jhovold@gmail.com)
* Copyright (C) 1999 - 2001
* Greg Kroah-Hartman (greg@kroah.com)
* Bill Ryder (bryder@sgi.com)
* Copyright (C) 2002
* Kuba Ober (kuba@mareimbrium.org)
*/
{ USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_USINT_CAT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_USINT_WKEY_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_USINT_RS232_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IPLUS2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_DMX4ALL) },
{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_232RL_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_232H_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_FTX_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_SNIFFER_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SPROG_II) },
{ USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_633_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_631_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_635_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) },
{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_3_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) },
{ USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0103_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0104_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0105_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0106_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0107_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0108_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0109_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010A_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010B_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010C_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010D_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010E_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010F_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0110_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0111_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0112_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0113_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0114_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0115_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0116_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0117_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0118_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0119_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011A_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011B_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011C_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011D_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011E_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011F_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0120_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0121_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0122_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0123_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0124_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0125_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0126_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0127_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0128_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0129_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012A_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012B_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012C_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012D_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012E_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012F_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0130_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0131_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0132_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0133_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0134_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0135_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0136_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0137_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0138_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0139_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013A_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013B_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013C_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013D_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013E_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013F_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0140_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0141_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0142_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0143_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0144_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0145_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0146_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0147_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0148_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0149_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014A_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014B_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014C_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014D_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014E_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014F_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0150_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0151_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0152_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0153_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0154_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0155_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0156_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0157_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0158_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0159_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015A_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015B_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015C_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015D_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015E_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015F_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0160_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0161_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0162_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0163_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0164_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0165_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0166_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0167_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0168_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0169_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016A_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016B_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016C_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016D_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016E_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016F_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0170_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0171_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0172_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0173_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0174_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0175_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0176_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0177_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0178_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0179_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017A_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017B_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017C_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017D_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017E_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017F_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0180_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0181_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0182_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0183_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0184_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0185_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0186_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0187_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0188_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0189_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018A_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018B_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018C_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018D_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018E_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018F_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0190_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0191_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0192_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0193_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0194_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0195_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0196_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0197_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0198_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0199_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019A_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019B_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019C_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019D_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019E_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019F_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A0_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A1_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A2_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A3_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A4_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A5_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A6_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A7_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A8_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A9_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AA_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AB_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AC_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AD_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AE_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AF_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B0_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B1_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B2_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B3_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B4_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B5_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B6_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B7_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B8_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B9_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BA_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BB_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BC_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BD_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BE_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BF_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C0_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C1_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C2_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C3_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C4_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C5_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C6_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C7_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C8_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C9_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CA_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CB_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CC_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CD_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CE_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CF_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D0_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D1_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D2_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D3_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D4_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D5_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D6_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D7_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D8_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D9_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DA_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DB_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DC_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DD_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DE_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DF_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E0_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E1_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E2_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E3_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E4_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E5_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E6_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E7_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E8_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E9_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EA_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EB_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EC_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01ED_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EE_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EF_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F0_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F1_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F2_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F3_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F4_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F5_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F6_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F7_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F8_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F9_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FA_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FB_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FC_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) },
{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_USBX_707_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2106_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_3_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_4_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_3_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_4_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_3_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_4_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_3_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_4_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_5_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_6_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_7_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_8_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_3_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_4_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_5_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_6_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_7_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_8_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_3_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_4_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_5_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_3_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_4_PID) },
{ USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) },
{ USB_DEVICE(OCT_VID, OCT_US101_PID) },
{ USB_DEVICE(OCT_VID, OCT_DK201_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) },
{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) },
{ USB_DEVICE(FTDI_VID, PROTEGO_R2X0) },
{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) },
{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E808_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E809_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80A_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80B_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80C_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80D_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80E_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80F_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E888_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E889_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88A_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88B_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88C_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88D_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88E_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IBS_US485_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IBS_PICPRO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IBS_PCMCIA_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IBS_PK1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IBS_RS232MON_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IBS_APP70_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID) },
/*
* ELV devices:
*/
{ USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS550_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_EC3000_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS888_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_TWS550_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_FEM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UTP8_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS444PC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_EM1010PC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_HS485_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UMS100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_TFD128_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_FM3RX_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS777_PID) },
{ USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
{ USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSLOAD_N_GO_3_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU64_4_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSPRIME8_5_PID) },
{ USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
{ USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
{ USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) },
{ USB_DEVICE(FALCOM_VID, FALCOM_SAMBA_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) },
{ USB_DEVICE(TTI_VID, TTI_QL355P_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
{ USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) },
{ USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USOPTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USPTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_2_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR2_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_485USB9F_2W_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_485USB9F_4W_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_232USB9M_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_485USBTB_2W_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_485USBTB_4W_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_TTL5USB9M_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_TTL3USB9M_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_ZZ_PROG1_USB_PID) },
{ USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_3_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_1_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_2_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_3_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_4_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) },
{ USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MHAM_YS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MHAM_IC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MHAM_DB9_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MHAM_RS232_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y9_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_VCP_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_D2XX_PID) },
{ USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
{ USB_DEVICE(EVOLUTION_VID, EVO_HYBRID_PID) },
{ USB_DEVICE(EVOLUTION_VID, EVO_RCM4_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) },
{ USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) },
{ USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) },
{ USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TTUSB_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ECLO_COM_1WIRE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_NZR_SEM_USB_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2C2_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2D_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2VT_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2VR_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVT_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVR_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVT_PID) },
{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVR_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) },
{ USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
{ USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_NDI_SPECTRA_SCU_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_3_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID) },
{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) },
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) },
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) },
{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID) },
{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID) },
{ USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID) },
{ USB_DEVICE(FTDI_VID, LMI_LM3S_DEVEL_BOARD_PID) },
{ USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID) },
{ USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID) },
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
{ USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
/* Papouch devices based on FTDI chip */
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_2_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_2_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_2_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485S_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485C_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_LEC_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB232_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_IRAMP_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK5_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO8x8_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x2_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO10x1_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO30x3_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO60x3_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x16_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO3x32_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK6_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_UPSUSB_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_MU_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SIMUKEY_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_AD4USB_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMUX_PID) },
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMSR_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DGQG_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) },
{ USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) },
{ USB_DEVICE(FTDI_VID, DIEBOLD_BCS_SE923_PID) },
{ USB_DEVICE(ATMEL_VID, STK541_PID) },
{ USB_DEVICE(DE_VID, STB_PID) },
{ USB_DEVICE(DE_VID, WHT_PID) },
{ USB_DEVICE(ADI_VID, ADI_GNICE_PID) },
{ USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID) },
{ USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID,
0xff, 0xff, 0x00) },
{ USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
{ USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID) },
{ USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
{ USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) },
{ USB_DEVICE(FTDI_VID, PI_C865_PID) },
{ USB_DEVICE(FTDI_VID, PI_C857_PID) },
{ USB_DEVICE(PI_VID, PI_C866_PID) },
{ USB_DEVICE(PI_VID, PI_C663_PID) },
{ USB_DEVICE(PI_VID, PI_C725_PID) },
{ USB_DEVICE(PI_VID, PI_E517_PID) },
{ USB_DEVICE(PI_VID, PI_C863_PID) },
{ USB_DEVICE(PI_VID, PI_E861_PID) },
{ USB_DEVICE(PI_VID, PI_C867_PID) },
{ USB_DEVICE(PI_VID, PI_E609_PID) },
{ USB_DEVICE(PI_VID, PI_E709_PID) },
{ USB_DEVICE(PI_VID, PI_100F_PID) },
{ USB_DEVICE(PI_VID, PI_1011_PID) },
{ USB_DEVICE(PI_VID, PI_1012_PID) },
{ USB_DEVICE(PI_VID, PI_1013_PID) },
{ USB_DEVICE(PI_VID, PI_1014_PID) },
{ USB_DEVICE(PI_VID, PI_1015_PID) },
{ USB_DEVICE(PI_VID, PI_1016_PID) },
{ USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) },
{ USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
{ USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID) },
{ USB_DEVICE(FTDI_VID, TI_XDS100V2_PID) },
{ USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
{ USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) },
{ USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) },
{ USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) },
{ USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) },
{ USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) },
{ USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) },
{ USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) },
{ USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_ST_PID) },
{ USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SLITE_PID) },
{ USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH2_PID) },
{ USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID) },
{ USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) },
{ USB_DEVICE(FTDI_VID, ACCESIO_COM4SM_PID) },
{ USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_24_MASTER_WING_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_PC_WING_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_USB_DMX_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MIDI_TIMECODE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MINI_WING_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MAXI_WING_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MEDIA_WING_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_WING_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
{ USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID) },
{ USB_DEVICE(ST_VID, ST_STMCLT1030_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RF_R106) },
{ USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
{ USB_DEVICE(-1, -1) } /* Terminating Entry */
};
#undef USB_DEVICE
#undef USB_DEVICE_AND_INTERFACE_INFO

View File

@ -44,18 +44,26 @@
#define NO_INTERFACE_INFO 255 /* Valid interface_count always <= 32 */
#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f))
#define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f))
#define USBEP2I(usb_ep) (((usb_ep)->pid == USB_TOKEN_IN) ? \
((usb_ep)->nr | 0x10) : ((usb_ep)->nr))
#define I2USBEP(d, i) (usb_ep_get(&(d)->dev, \
((i) & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, \
(i) & 0x0f))
typedef struct USBRedirDevice USBRedirDevice;
/* Struct to hold buffered packets (iso or int input packets) */
/* Struct to hold buffered packets */
struct buf_packet {
uint8_t *data;
int len;
int status;
void *free_on_destroy;
uint16_t len;
uint16_t offset;
uint8_t status;
QTAILQ_ENTRY(buf_packet)next;
};
struct endp_data {
USBRedirDevice *dev;
uint8_t type;
uint8_t interval;
uint8_t interface; /* bInterfaceNumber this ep belongs to */
@ -64,11 +72,14 @@ struct endp_data {
uint8_t iso_error; /* For reporting iso errors to the HC */
uint8_t interrupt_started;
uint8_t interrupt_error;
uint8_t bulk_receiving_enabled;
uint8_t bulk_receiving_started;
uint8_t bufpq_prefilled;
uint8_t bufpq_dropping_packets;
QTAILQ_HEAD(, buf_packet) bufpq;
int32_t bufpq_size;
int32_t bufpq_target_size;
USBPacket *pending_async_packet;
};
struct PacketIdQueueEntry {
@ -102,6 +113,7 @@ struct USBRedirDevice {
struct endp_data endpoint[MAX_ENDPOINTS];
struct PacketIdQueue cancelled;
struct PacketIdQueue already_in_flight;
void (*buffered_bulk_in_complete)(USBRedirDevice *, USBPacket *, uint8_t);
/* Data for device filtering */
struct usb_redir_device_connect_header device_info;
struct usb_redir_interface_info_header interface_info;
@ -129,6 +141,8 @@ static void usbredir_interrupt_receiving_status(void *priv, uint64_t id,
*interrupt_receiving_status);
static void usbredir_bulk_streams_status(void *priv, uint64_t id,
struct usb_redir_bulk_streams_status_header *bulk_streams_status);
static void usbredir_bulk_receiving_status(void *priv, uint64_t id,
struct usb_redir_bulk_receiving_status_header *bulk_receiving_status);
static void usbredir_control_packet(void *priv, uint64_t id,
struct usb_redir_control_packet_header *control_packet,
uint8_t *data, int data_len);
@ -141,6 +155,9 @@ static void usbredir_iso_packet(void *priv, uint64_t id,
static void usbredir_interrupt_packet(void *priv, uint64_t id,
struct usb_redir_interrupt_packet_header *interrupt_header,
uint8_t *data, int data_len);
static void usbredir_buffered_bulk_packet(void *priv, uint64_t id,
struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet,
uint8_t *data, int data_len);
static void usbredir_handle_status(USBRedirDevice *dev, USBPacket *p,
int status);
@ -314,12 +331,19 @@ static void packet_id_queue_empty(struct PacketIdQueue *q)
static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
{
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
int i = USBEP2I(p->ep);
if (p->combined) {
usb_combined_packet_cancel(udev, p);
return;
}
if (dev->endpoint[i].pending_async_packet) {
assert(dev->endpoint[i].pending_async_packet == p);
dev->endpoint[i].pending_async_packet = NULL;
return;
}
packet_id_queue_add(&dev->cancelled, p->id);
usbredirparser_send_cancel_data_packet(dev->parser, p->id);
usbredirparser_do_write(dev->parser);
@ -338,6 +362,11 @@ static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev,
{
static USBPacket *p;
/* async handled packets for bulk receiving eps do not count as inflight */
if (dev->endpoint[USBEP2I(ep)].bulk_receiving_started) {
return;
}
QTAILQ_FOREACH(p, &ep->queue, queue) {
/* Skip combined packets, except for the first */
if (p->combined && p != p->combined->first) {
@ -385,8 +414,8 @@ static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev,
return p;
}
static void bufp_alloc(USBRedirDevice *dev,
uint8_t *data, int len, int status, uint8_t ep)
static void bufp_alloc(USBRedirDevice *dev, uint8_t *data, uint16_t len,
uint8_t status, uint8_t ep, void *free_on_destroy)
{
struct buf_packet *bufp;
@ -410,7 +439,9 @@ static void bufp_alloc(USBRedirDevice *dev,
bufp = g_malloc(sizeof(struct buf_packet));
bufp->data = data;
bufp->len = len;
bufp->offset = 0;
bufp->status = status;
bufp->free_on_destroy = free_on_destroy;
QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
dev->endpoint[EP2I(ep)].bufpq_size++;
}
@ -420,7 +451,7 @@ static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp,
{
QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
dev->endpoint[EP2I(ep)].bufpq_size--;
free(bufp->data);
free(bufp->free_on_destroy);
g_free(bufp);
}
@ -571,19 +602,162 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep)
usbredir_free_bufpq(dev, ep);
}
/*
* The usb-host may poll the endpoint faster then our guest, resulting in lots
* of smaller bulkp-s. The below buffered_bulk_in_complete* functions combine
* data from multiple bulkp-s into a single packet, avoiding bufpq overflows.
*/
static void usbredir_buffered_bulk_add_data_to_packet(USBRedirDevice *dev,
struct buf_packet *bulkp, int count, USBPacket *p, uint8_t ep)
{
usb_packet_copy(p, bulkp->data + bulkp->offset, count);
bulkp->offset += count;
if (bulkp->offset == bulkp->len) {
/* Store status in the last packet with data from this bulkp */
usbredir_handle_status(dev, p, bulkp->status);
bufp_free(dev, bulkp, ep);
}
}
static void usbredir_buffered_bulk_in_complete_raw(USBRedirDevice *dev,
USBPacket *p, uint8_t ep)
{
struct buf_packet *bulkp;
int count;
while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) &&
p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) {
count = bulkp->len - bulkp->offset;
if (count > (p->iov.size - p->actual_length)) {
count = p->iov.size - p->actual_length;
}
usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep);
}
}
static void usbredir_buffered_bulk_in_complete_ftdi(USBRedirDevice *dev,
USBPacket *p, uint8_t ep)
{
const int maxp = dev->endpoint[EP2I(ep)].max_packet_size;
uint8_t header[2] = { 0, 0 };
struct buf_packet *bulkp;
int count;
while ((bulkp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq)) &&
p->actual_length < p->iov.size && p->status == USB_RET_SUCCESS) {
if (bulkp->len < 2) {
WARNING("malformed ftdi bulk in packet\n");
bufp_free(dev, bulkp, ep);
continue;
}
if ((p->actual_length % maxp) == 0) {
usb_packet_copy(p, bulkp->data, 2);
memcpy(header, bulkp->data, 2);
} else {
if (bulkp->data[0] != header[0] || bulkp->data[1] != header[1]) {
break; /* Different header, add to next packet */
}
}
if (bulkp->offset == 0) {
bulkp->offset = 2; /* Skip header */
}
count = bulkp->len - bulkp->offset;
/* Must repeat the header at maxp interval */
if (count > (maxp - (p->actual_length % maxp))) {
count = maxp - (p->actual_length % maxp);
}
usbredir_buffered_bulk_add_data_to_packet(dev, bulkp, count, p, ep);
}
}
static void usbredir_buffered_bulk_in_complete(USBRedirDevice *dev,
USBPacket *p, uint8_t ep)
{
p->status = USB_RET_SUCCESS; /* Clear previous ASYNC status */
dev->buffered_bulk_in_complete(dev, p, ep);
DPRINTF("bulk-token-in ep %02X status %d len %d id %"PRIu64"\n",
ep, p->status, p->actual_length, p->id);
}
static void usbredir_handle_buffered_bulk_in_data(USBRedirDevice *dev,
USBPacket *p, uint8_t ep)
{
/* Input bulk endpoint, buffered packet input */
if (!dev->endpoint[EP2I(ep)].bulk_receiving_started) {
int bpt;
struct usb_redir_start_bulk_receiving_header start = {
.endpoint = ep,
.stream_id = 0,
.no_transfers = 5,
};
/* Round bytes_per_transfer up to a multiple of max_packet_size */
bpt = 512 + dev->endpoint[EP2I(ep)].max_packet_size - 1;
bpt /= dev->endpoint[EP2I(ep)].max_packet_size;
bpt *= dev->endpoint[EP2I(ep)].max_packet_size;
start.bytes_per_transfer = bpt;
/* No id, we look at the ep when receiving a status back */
usbredirparser_send_start_bulk_receiving(dev->parser, 0, &start);
usbredirparser_do_write(dev->parser);
DPRINTF("bulk receiving started bytes/transfer %u count %d ep %02X\n",
start.bytes_per_transfer, start.no_transfers, ep);
dev->endpoint[EP2I(ep)].bulk_receiving_started = 1;
/* We don't really want to drop bulk packets ever, but
having some upper limit to how much we buffer is good. */
dev->endpoint[EP2I(ep)].bufpq_target_size = 5000;
dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
}
if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) {
DPRINTF("bulk-token-in ep %02X, no bulkp\n", ep);
assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL);
dev->endpoint[EP2I(ep)].pending_async_packet = p;
p->status = USB_RET_ASYNC;
return;
}
usbredir_buffered_bulk_in_complete(dev, p, ep);
}
static void usbredir_stop_bulk_receiving(USBRedirDevice *dev, uint8_t ep)
{
struct usb_redir_stop_bulk_receiving_header stop_bulk = {
.endpoint = ep,
.stream_id = 0,
};
if (dev->endpoint[EP2I(ep)].bulk_receiving_started) {
usbredirparser_send_stop_bulk_receiving(dev->parser, 0, &stop_bulk);
DPRINTF("bulk receiving stopped ep %02X\n", ep);
dev->endpoint[EP2I(ep)].bulk_receiving_started = 0;
}
usbredir_free_bufpq(dev, ep);
}
static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
uint8_t ep)
{
struct usb_redir_bulk_packet_header bulk_packet;
size_t size = (p->combined) ? p->combined->iov.size : p->iov.size;
DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id);
const int maxp = dev->endpoint[EP2I(ep)].max_packet_size;
if (usbredir_already_in_flight(dev, p->id)) {
p->status = USB_RET_ASYNC;
return;
}
if (dev->endpoint[EP2I(ep)].bulk_receiving_enabled) {
if (size != 0 && (size % maxp) == 0) {
usbredir_handle_buffered_bulk_in_data(dev, p, ep);
return;
}
WARNING("bulk recv invalid size %zd ep %02x, disabling\n", size, ep);
assert(dev->endpoint[EP2I(ep)].pending_async_packet == NULL);
usbredir_stop_bulk_receiving(dev, ep);
dev->endpoint[EP2I(ep)].bulk_receiving_enabled = 0;
}
DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id);
bulk_packet.endpoint = ep;
bulk_packet.length = size;
bulk_packet.stream_id = 0;
@ -720,9 +894,6 @@ static void usbredir_handle_data(USBDevice *udev, USBPacket *p)
ERROR("handle_data called for control transfer on ep %02X\n", ep);
p->status = USB_RET_NAK;
break;
case USB_ENDPOINT_XFER_ISOC:
usbredir_handle_iso_data(dev, p, ep);
break;
case USB_ENDPOINT_XFER_BULK:
if (p->state == USB_PACKET_SETUP && p->pid == USB_TOKEN_IN &&
p->ep->pipeline) {
@ -731,6 +902,9 @@ static void usbredir_handle_data(USBDevice *udev, USBPacket *p)
}
usbredir_handle_bulk_data(dev, p, ep);
break;
case USB_ENDPOINT_XFER_ISOC:
usbredir_handle_iso_data(dev, p, ep);
break;
case USB_ENDPOINT_XFER_INT:
if (ep & USB_DIR_IN) {
usbredir_handle_interrupt_in_data(dev, p, ep);
@ -752,6 +926,36 @@ static void usbredir_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
}
}
static void usbredir_stop_ep(USBRedirDevice *dev, int i)
{
uint8_t ep = I2EP(i);
switch (dev->endpoint[i].type) {
case USB_ENDPOINT_XFER_BULK:
if (ep & USB_DIR_IN) {
usbredir_stop_bulk_receiving(dev, ep);
}
break;
case USB_ENDPOINT_XFER_ISOC:
usbredir_stop_iso_stream(dev, ep);
break;
case USB_ENDPOINT_XFER_INT:
if (ep & USB_DIR_IN) {
usbredir_stop_interrupt_receiving(dev, ep);
}
break;
}
usbredir_free_bufpq(dev, ep);
}
static void usbredir_ep_stopped(USBDevice *udev, USBEndpoint *uep)
{
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
usbredir_stop_ep(dev, USBEP2I(uep));
usbredirparser_do_write(dev->parser);
}
static void usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
int config)
{
@ -761,17 +965,7 @@ static void usbredir_set_config(USBRedirDevice *dev, USBPacket *p,
DPRINTF("set config %d id %"PRIu64"\n", config, p->id);
for (i = 0; i < MAX_ENDPOINTS; i++) {
switch (dev->endpoint[i].type) {
case USB_ENDPOINT_XFER_ISOC:
usbredir_stop_iso_stream(dev, I2EP(i));
break;
case USB_ENDPOINT_XFER_INT:
if (i & 0x10) {
usbredir_stop_interrupt_receiving(dev, I2EP(i));
}
break;
}
usbredir_free_bufpq(dev, I2EP(i));
usbredir_stop_ep(dev, i);
}
set_config.configuration = config;
@ -799,17 +993,7 @@ static void usbredir_set_interface(USBRedirDevice *dev, USBPacket *p,
for (i = 0; i < MAX_ENDPOINTS; i++) {
if (dev->endpoint[i].interface == interface) {
switch (dev->endpoint[i].type) {
case USB_ENDPOINT_XFER_ISOC:
usbredir_stop_iso_stream(dev, I2EP(i));
break;
case USB_ENDPOINT_XFER_INT:
if (i & 0x10) {
usbredir_stop_interrupt_receiving(dev, I2EP(i));
}
break;
}
usbredir_free_bufpq(dev, I2EP(i));
usbredir_stop_ep(dev, i);
}
}
@ -931,10 +1115,12 @@ static void usbredir_create_parser(USBRedirDevice *dev)
dev->parser->interrupt_receiving_status_func =
usbredir_interrupt_receiving_status;
dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status;
dev->parser->bulk_receiving_status_func = usbredir_bulk_receiving_status;
dev->parser->control_packet_func = usbredir_control_packet;
dev->parser->bulk_packet_func = usbredir_bulk_packet;
dev->parser->iso_packet_func = usbredir_iso_packet;
dev->parser->interrupt_packet_func = usbredir_interrupt_packet;
dev->parser->buffered_bulk_packet_func = usbredir_buffered_bulk_packet;
dev->read_buf = NULL;
dev->read_buf_size = 0;
@ -943,6 +1129,7 @@ static void usbredir_create_parser(USBRedirDevice *dev)
usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size);
usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids);
usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length);
usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving);
if (runstate_check(RUN_STATE_INMIGRATE)) {
flags |= usbredirparser_fl_no_hello;
@ -969,6 +1156,8 @@ static void usbredir_do_attach(void *opaque)
if ((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER) && !(
usbredirparser_peer_has_cap(dev->parser,
usb_redir_cap_ep_info_max_packet_size) &&
usbredirparser_peer_has_cap(dev->parser,
usb_redir_cap_32bits_bulk_length) &&
usbredirparser_peer_has_cap(dev->parser,
usb_redir_cap_64bits_ids))) {
ERROR("usb-redir-host lacks capabilities needed for use with XHCI\n");
@ -1051,6 +1240,18 @@ static void usbredir_vm_state_change(void *priv, int running, RunState state)
}
}
static void usbredir_init_endpoints(USBRedirDevice *dev)
{
int i;
usb_ep_init(&dev->dev);
memset(dev->endpoint, 0, sizeof(dev->endpoint));
for (i = 0; i < MAX_ENDPOINTS; i++) {
dev->endpoint[i].dev = dev;
QTAILQ_INIT(&dev->endpoint[i].bufpq);
}
}
static int usbredir_initfn(USBDevice *udev)
{
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
@ -1077,9 +1278,7 @@ static int usbredir_initfn(USBDevice *udev)
packet_id_queue_init(&dev->cancelled, dev, "cancelled");
packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight");
for (i = 0; i < MAX_ENDPOINTS; i++) {
QTAILQ_INIT(&dev->endpoint[i].bufpq);
}
usbredir_init_endpoints(dev);
/* We'll do the attach once we receive the speed from the usb-host */
udev->auto_attach = 0;
@ -1169,6 +1368,52 @@ error:
return -1;
}
static void usbredir_check_bulk_receiving(USBRedirDevice *dev)
{
int i, j, quirks;
if (!usbredirparser_peer_has_cap(dev->parser,
usb_redir_cap_bulk_receiving)) {
return;
}
for (i = EP2I(USB_DIR_IN); i < MAX_ENDPOINTS; i++) {
dev->endpoint[i].bulk_receiving_enabled = 0;
}
for (i = 0; i < dev->interface_info.interface_count; i++) {
quirks = usb_get_quirks(dev->device_info.vendor_id,
dev->device_info.product_id,
dev->interface_info.interface_class[i],
dev->interface_info.interface_subclass[i],
dev->interface_info.interface_protocol[i]);
if (!(quirks & USB_QUIRK_BUFFER_BULK_IN)) {
continue;
}
if (quirks & USB_QUIRK_IS_FTDI) {
dev->buffered_bulk_in_complete =
usbredir_buffered_bulk_in_complete_ftdi;
} else {
dev->buffered_bulk_in_complete =
usbredir_buffered_bulk_in_complete_raw;
}
for (j = EP2I(USB_DIR_IN); j < MAX_ENDPOINTS; j++) {
if (dev->endpoint[j].interface ==
dev->interface_info.interface[i] &&
dev->endpoint[j].type == USB_ENDPOINT_XFER_BULK &&
dev->endpoint[j].max_packet_size != 0) {
dev->endpoint[j].bulk_receiving_enabled = 1;
/*
* With buffering pipelining is not necessary. Also packet
* combining and bulk in buffering don't play nice together!
*/
I2USBEP(dev, j)->pipeline = false;
break; /* Only buffer for the first ep of each intf */
}
}
}
}
/*
* usbredirparser packet complete callbacks
*/
@ -1277,13 +1522,13 @@ static void usbredir_device_connect(void *priv,
return;
}
usbredir_check_bulk_receiving(dev);
qemu_mod_timer(dev->attach_timer, dev->next_attach_time);
}
static void usbredir_device_disconnect(void *priv)
{
USBRedirDevice *dev = priv;
int i;
/* Stop any pending attaches */
qemu_del_timer(dev->attach_timer);
@ -1300,11 +1545,7 @@ static void usbredir_device_disconnect(void *priv)
/* Reset state so that the next dev connected starts with a clean slate */
usbredir_cleanup_device_queues(dev);
memset(dev->endpoint, 0, sizeof(dev->endpoint));
for (i = 0; i < MAX_ENDPOINTS; i++) {
QTAILQ_INIT(&dev->endpoint[i].bufpq);
}
usb_ep_init(&dev->dev);
usbredir_init_endpoints(dev);
dev->interface_info.interface_count = NO_INTERFACE_INFO;
dev->dev.addr = 0;
dev->dev.speed = 0;
@ -1320,9 +1561,10 @@ static void usbredir_interface_info(void *priv,
/*
* If we receive interface info after the device has already been
* connected (ie on a set_config), re-check the filter.
* connected (ie on a set_config), re-check interface dependent things.
*/
if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) {
usbredir_check_bulk_receiving(dev);
if (usbredir_check_filter(dev)) {
ERROR("Device no longer matches filter after interface info "
"change, disconnecting!\n");
@ -1354,11 +1596,10 @@ static void usbredir_set_pipeline(USBRedirDevice *dev, struct USBEndpoint *uep)
static void usbredir_setup_usb_eps(USBRedirDevice *dev)
{
struct USBEndpoint *usb_ep;
int i, pid;
int i;
for (i = 0; i < MAX_ENDPOINTS; i++) {
pid = (i & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT;
usb_ep = usb_ep_get(&dev->dev, pid, i & 0x0f);
usb_ep = I2USBEP(dev, i);
usb_ep->type = dev->endpoint[i].type;
usb_ep->ifnum = dev->endpoint[i].interface;
usb_ep->max_packet_size = dev->endpoint[i].max_packet_size;
@ -1424,6 +1665,7 @@ static void usbredir_ep_info(void *priv,
return;
}
usbredir_setup_usb_eps(dev);
usbredir_check_bulk_receiving(dev);
}
static void usbredir_configuration_status(void *priv, uint64_t id,
@ -1514,6 +1756,25 @@ static void usbredir_bulk_streams_status(void *priv, uint64_t id,
{
}
static void usbredir_bulk_receiving_status(void *priv, uint64_t id,
struct usb_redir_bulk_receiving_status_header *bulk_receiving_status)
{
USBRedirDevice *dev = priv;
uint8_t ep = bulk_receiving_status->endpoint;
DPRINTF("bulk recv status %d ep %02X id %"PRIu64"\n",
bulk_receiving_status->status, ep, id);
if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].bulk_receiving_started) {
return;
}
if (bulk_receiving_status->status == usb_redir_stall) {
DPRINTF("bulk receiving stopped by peer ep %02X\n", ep);
dev->endpoint[EP2I(ep)].bulk_receiving_started = 0;
}
}
static void usbredir_control_packet(void *priv, uint64_t id,
struct usb_redir_control_packet_header *control_packet,
uint8_t *data, int data_len)
@ -1619,7 +1880,7 @@ static void usbredir_iso_packet(void *priv, uint64_t id,
}
/* bufp_alloc also adds the packet to the ep queue */
bufp_alloc(dev, data, data_len, iso_packet->status, ep);
bufp_alloc(dev, data, data_len, iso_packet->status, ep, data);
}
static void usbredir_interrupt_packet(void *priv, uint64_t id,
@ -1650,7 +1911,7 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
}
/* bufp_alloc also adds the packet to the ep queue */
bufp_alloc(dev, data, data_len, interrupt_packet->status, ep);
bufp_alloc(dev, data, data_len, interrupt_packet->status, ep, data);
} else {
/*
* We report output interrupt packets as completed directly upon
@ -1663,6 +1924,52 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
}
}
static void usbredir_buffered_bulk_packet(void *priv, uint64_t id,
struct usb_redir_buffered_bulk_packet_header *buffered_bulk_packet,
uint8_t *data, int data_len)
{
USBRedirDevice *dev = priv;
uint8_t status, ep = buffered_bulk_packet->endpoint;
void *free_on_destroy;
int i, len;
DPRINTF("buffered-bulk-in status %d ep %02X len %d id %"PRIu64"\n",
buffered_bulk_packet->status, ep, data_len, id);
if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_BULK) {
ERROR("received buffered-bulk packet for non bulk ep %02X\n", ep);
free(data);
return;
}
if (dev->endpoint[EP2I(ep)].bulk_receiving_started == 0) {
DPRINTF("received buffered-bulk packet on not started ep %02X\n", ep);
free(data);
return;
}
/* Data must be in maxp chunks for buffered_bulk_add_*_data_to_packet */
len = dev->endpoint[EP2I(ep)].max_packet_size;
status = usb_redir_success;
free_on_destroy = NULL;
for (i = 0; i < data_len; i += len) {
if (len >= (data_len - i)) {
len = data_len - i;
status = buffered_bulk_packet->status;
free_on_destroy = data;
}
/* bufp_alloc also adds the packet to the ep queue */
bufp_alloc(dev, data + i, len, status, ep, free_on_destroy);
}
if (dev->endpoint[EP2I(ep)].pending_async_packet) {
USBPacket *p = dev->endpoint[EP2I(ep)].pending_async_packet;
dev->endpoint[EP2I(ep)].pending_async_packet = NULL;
usbredir_buffered_bulk_in_complete(dev, p, ep);
usb_packet_complete(&dev->dev, p);
}
}
/*
* Migration code
*/
@ -1697,6 +2004,7 @@ static int usbredir_post_load(void *priv, int version_id)
dev->dev.speedmask = (1 << dev->dev.speed);
usbredir_setup_usb_eps(dev);
usbredir_check_bulk_receiving(dev);
return 0;
}
@ -1768,22 +2076,27 @@ static const VMStateInfo usbredir_parser_vmstate_info = {
static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused)
{
struct endp_data *endp = priv;
USBRedirDevice *dev = endp->dev;
struct buf_packet *bufp;
int remain = endp->bufpq_size;
int len, i = 0;
qemu_put_be32(f, endp->bufpq_size);
QTAILQ_FOREACH(bufp, &endp->bufpq, next) {
qemu_put_be32(f, bufp->len);
len = bufp->len - bufp->offset;
DPRINTF("put_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size,
len, bufp->status);
qemu_put_be32(f, len);
qemu_put_be32(f, bufp->status);
qemu_put_buffer(f, bufp->data, bufp->len);
remain--;
qemu_put_buffer(f, bufp->data + bufp->offset, len);
i++;
}
assert(remain == 0);
assert(i == endp->bufpq_size);
}
static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused)
{
struct endp_data *endp = priv;
USBRedirDevice *dev = endp->dev;
struct buf_packet *bufp;
int i;
@ -1792,9 +2105,13 @@ static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused)
bufp = g_malloc(sizeof(struct buf_packet));
bufp->len = qemu_get_be32(f);
bufp->status = qemu_get_be32(f);
bufp->offset = 0;
bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */
bufp->free_on_destroy = bufp->data;
qemu_get_buffer(f, bufp->data, bufp->len);
QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next);
DPRINTF("get_bufpq %d/%d len %d status %d\n", i + 1, endp->bufpq_size,
bufp->len, bufp->status);
}
return 0;
}
@ -1807,6 +2124,23 @@ static const VMStateInfo usbredir_ep_bufpq_vmstate_info = {
/* For endp_data migration */
static const VMStateDescription usbredir_bulk_receiving_vmstate = {
.name = "usb-redir-ep/bulk-receiving",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT8(bulk_receiving_started, struct endp_data),
VMSTATE_END_OF_LIST()
}
};
static bool usbredir_bulk_receiving_needed(void *priv)
{
struct endp_data *endp = priv;
return endp->bulk_receiving_started;
}
static const VMStateDescription usbredir_ep_vmstate = {
.name = "usb-redir-ep",
.version_id = 1,
@ -1833,6 +2167,14 @@ static const VMStateDescription usbredir_ep_vmstate = {
},
VMSTATE_INT32(bufpq_target_size, struct endp_data),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &usbredir_bulk_receiving_vmstate,
.needed = usbredir_bulk_receiving_needed,
}, {
/* empty */
}
}
};
@ -1994,6 +2336,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data)
uc->handle_data = usbredir_handle_data;
uc->handle_control = usbredir_handle_control;
uc->flush_ep_queue = usbredir_flush_ep_queue;
uc->ep_stopped = usbredir_ep_stopped;
dc->vmsd = &usbredir_vmstate;
dc->props = usbredir_properties;
}

View File

@ -307,8 +307,6 @@ usb_uhci_frame_loop_stop_idle(void) ""
usb_uhci_frame_loop_continue(void) ""
usb_uhci_mmio_readw(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%04x"
usb_uhci_mmio_writew(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%04x"
usb_uhci_mmio_readl(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%08x"
usb_uhci_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%08x"
usb_uhci_queue_add(uint32_t token) "token 0x%x"
usb_uhci_queue_del(uint32_t token, const char *reason) "token 0x%x: %s"
usb_uhci_packet_add(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x"