mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
@@ -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)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "arm-misc.h"
|
||||
#include "loader.h"
|
||||
#include "exynos4210.h"
|
||||
#include "usb/hcd-ehci.h"
|
||||
|
||||
#define EXYNOS4210_CHIPID_ADDR 0x10000000
|
||||
|
||||
@@ -72,6 +73,9 @@
|
||||
/* Display controllers (FIMD) */
|
||||
#define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000
|
||||
|
||||
/* EHCI */
|
||||
#define EXYNOS4210_EHCI_BASE_ADDR 0x12580000
|
||||
|
||||
static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
|
||||
0x09, 0x00, 0x00, 0x00 };
|
||||
|
||||
@@ -338,5 +342,8 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
||||
s->irq_table[exynos4210_get_irq(11, 2)],
|
||||
NULL);
|
||||
|
||||
sysbus_create_simple(TYPE_EXYNOS4210_EHCI, EXYNOS4210_EHCI_BASE_ADDR,
|
||||
s->irq_table[exynos4210_get_irq(28, 3)]);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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 },
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -189,6 +189,14 @@ void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep)
|
||||
}
|
||||
}
|
||||
|
||||
void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep)
|
||||
{
|
||||
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->ep_stopped) {
|
||||
klass->ep_stopped(dev, ep);
|
||||
}
|
||||
}
|
||||
|
||||
static int usb_qdev_init(DeviceState *qdev)
|
||||
{
|
||||
USBDevice *dev = USB_DEVICE(qdev);
|
||||
|
||||
+1
-1
@@ -761,7 +761,7 @@ USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
|
||||
struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
|
||||
USBPacket *p;
|
||||
|
||||
while ((p = QTAILQ_FIRST(&uep->queue)) != NULL) {
|
||||
QTAILQ_FOREACH(p, &uep->queue, queue) {
|
||||
if (p->id == id) {
|
||||
return p;
|
||||
}
|
||||
|
||||
+3
-5
@@ -501,7 +501,7 @@ static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
|
||||
break;
|
||||
case SET_IDLE:
|
||||
hs->idle = (uint8_t) (value >> 8);
|
||||
hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock));
|
||||
hid_set_next_idle(hs);
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
|
||||
hid_pointer_activate(hs);
|
||||
}
|
||||
@@ -523,16 +523,14 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p)
|
||||
switch (p->pid) {
|
||||
case USB_TOKEN_IN:
|
||||
if (p->ep->nr == 1) {
|
||||
int64_t curtime = qemu_get_clock_ns(vm_clock);
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
|
||||
hid_pointer_activate(hs);
|
||||
}
|
||||
if (!hid_has_events(hs) &&
|
||||
(!hs->idle || hs->next_idle_clock - curtime > 0)) {
|
||||
if (!hid_has_events(hs)) {
|
||||
p->status = USB_RET_NAK;
|
||||
return;
|
||||
}
|
||||
hid_set_next_idle(hs, curtime);
|
||||
hid_set_next_idle(hs);
|
||||
if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
|
||||
len = hid_pointer_poll(hs, buf, p->iov.size);
|
||||
} else if (hs->kind == HID_KEYBOARD) {
|
||||
|
||||
+24
-15
@@ -16,14 +16,8 @@
|
||||
*/
|
||||
|
||||
#include "hw/usb/hcd-ehci.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "qemu/range.h"
|
||||
|
||||
typedef struct EHCIPCIState {
|
||||
PCIDevice pcidev;
|
||||
EHCIState ehci;
|
||||
} EHCIPCIState;
|
||||
|
||||
typedef struct EHCIPCIInfo {
|
||||
const char *name;
|
||||
uint16_t vendor_id;
|
||||
@@ -33,7 +27,7 @@ typedef struct EHCIPCIInfo {
|
||||
|
||||
static int usb_ehci_pci_initfn(PCIDevice *dev)
|
||||
{
|
||||
EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
|
||||
EHCIPCIState *i = PCI_EHCI(dev);
|
||||
EHCIState *s = &i->ehci;
|
||||
uint8_t *pci_conf = dev->config;
|
||||
|
||||
@@ -83,7 +77,7 @@ static int usb_ehci_pci_initfn(PCIDevice *dev)
|
||||
static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr,
|
||||
uint32_t val, int l)
|
||||
{
|
||||
EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
|
||||
EHCIPCIState *i = PCI_EHCI(dev);
|
||||
bool busmaster;
|
||||
|
||||
pci_default_write_config(dev, addr, val, l);
|
||||
@@ -115,12 +109,8 @@ static void ehci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
EHCIPCIInfo *i = data;
|
||||
|
||||
k->init = usb_ehci_pci_initfn;
|
||||
k->vendor_id = i->vendor_id;
|
||||
k->device_id = i->device_id;
|
||||
k->revision = i->revision;
|
||||
k->class_id = PCI_CLASS_SERIAL_USB;
|
||||
k->config_write = usb_ehci_pci_write_config;
|
||||
k->no_hotplug = 1;
|
||||
@@ -128,6 +118,24 @@ static void ehci_class_init(ObjectClass *klass, void *data)
|
||||
dc->props = ehci_pci_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo ehci_pci_type_info = {
|
||||
.name = TYPE_PCI_EHCI,
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(EHCIPCIState),
|
||||
.abstract = true,
|
||||
.class_init = ehci_class_init,
|
||||
};
|
||||
|
||||
static void ehci_data_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
EHCIPCIInfo *i = data;
|
||||
|
||||
k->vendor_id = i->vendor_id;
|
||||
k->device_id = i->device_id;
|
||||
k->revision = i->revision;
|
||||
}
|
||||
|
||||
static struct EHCIPCIInfo ehci_pci_info[] = {
|
||||
{
|
||||
.name = "usb-ehci",
|
||||
@@ -150,12 +158,13 @@ static struct EHCIPCIInfo ehci_pci_info[] = {
|
||||
static void ehci_pci_register_types(void)
|
||||
{
|
||||
TypeInfo ehci_type_info = {
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(EHCIPCIState),
|
||||
.class_init = ehci_class_init,
|
||||
.parent = TYPE_PCI_EHCI,
|
||||
.class_init = ehci_data_class_init,
|
||||
};
|
||||
int i;
|
||||
|
||||
type_register_static(&ehci_pci_type_info);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ehci_pci_info); i++) {
|
||||
ehci_type_info.name = ehci_pci_info[i].name;
|
||||
ehci_type_info.class_data = ehci_pci_info + i;
|
||||
|
||||
+38
-11
@@ -16,12 +16,6 @@
|
||||
*/
|
||||
|
||||
#include "hw/usb/hcd-ehci.h"
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
typedef struct EHCISysBusState {
|
||||
SysBusDevice busdev;
|
||||
EHCIState ehci;
|
||||
} EHCISysBusState;
|
||||
|
||||
static const VMStateDescription vmstate_ehci_sysbus = {
|
||||
.name = "ehci-sysbus",
|
||||
@@ -40,11 +34,12 @@ static Property ehci_sysbus_properties[] = {
|
||||
|
||||
static int usb_ehci_sysbus_initfn(SysBusDevice *dev)
|
||||
{
|
||||
EHCISysBusState *i = FROM_SYSBUS(EHCISysBusState, dev);
|
||||
EHCISysBusState *i = SYS_BUS_EHCI(dev);
|
||||
SysBusEHCIClass *sec = SYS_BUS_EHCI_GET_CLASS(dev);
|
||||
EHCIState *s = &i->ehci;
|
||||
|
||||
s->capsbase = 0x100;
|
||||
s->opregbase = 0x140;
|
||||
s->capsbase = sec->capsbase;
|
||||
s->opregbase = sec->opregbase;
|
||||
s->dma = &dma_context_memory;
|
||||
|
||||
usb_ehci_initfn(s, DEVICE(dev));
|
||||
@@ -63,16 +58,48 @@ static void ehci_sysbus_class_init(ObjectClass *klass, void *data)
|
||||
dc->props = ehci_sysbus_properties;
|
||||
}
|
||||
|
||||
TypeInfo ehci_xlnx_type_info = {
|
||||
.name = "xlnx,ps7-usb",
|
||||
static const TypeInfo ehci_type_info = {
|
||||
.name = TYPE_SYS_BUS_EHCI,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(EHCISysBusState),
|
||||
.abstract = true,
|
||||
.class_init = ehci_sysbus_class_init,
|
||||
.class_size = sizeof(SysBusEHCIClass),
|
||||
};
|
||||
|
||||
static void ehci_xlnx_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
|
||||
|
||||
sec->capsbase = 0x100;
|
||||
sec->opregbase = 0x140;
|
||||
}
|
||||
|
||||
static const TypeInfo ehci_xlnx_type_info = {
|
||||
.name = "xlnx,ps7-usb",
|
||||
.parent = TYPE_SYS_BUS_EHCI,
|
||||
.class_init = ehci_xlnx_class_init,
|
||||
};
|
||||
|
||||
static void ehci_exynos4210_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
|
||||
|
||||
sec->capsbase = 0x0;
|
||||
sec->opregbase = 0x10;
|
||||
}
|
||||
|
||||
static const TypeInfo ehci_exynos4210_type_info = {
|
||||
.name = TYPE_EXYNOS4210_EHCI,
|
||||
.parent = TYPE_SYS_BUS_EHCI,
|
||||
.class_init = ehci_exynos4210_class_init,
|
||||
};
|
||||
|
||||
static void ehci_sysbus_register_types(void)
|
||||
{
|
||||
type_register_static(&ehci_type_info);
|
||||
type_register_static(&ehci_xlnx_type_info);
|
||||
type_register_static(&ehci_exynos4210_type_info);
|
||||
}
|
||||
|
||||
type_init(ehci_sysbus_register_types)
|
||||
|
||||
+216
-131
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,8 @@
|
||||
#include "trace.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
#ifndef EHCI_DEBUG
|
||||
#define EHCI_DEBUG 0
|
||||
@@ -248,6 +250,7 @@ struct EHCIQueue {
|
||||
EHCIqh qh; /* copy of current QH (being worked on) */
|
||||
uint32_t qhaddr; /* address QH read from */
|
||||
uint32_t qtdaddr; /* address QTD read from */
|
||||
int last_pid; /* pid of last packet executed */
|
||||
USBDevice *dev;
|
||||
QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
|
||||
};
|
||||
@@ -321,4 +324,43 @@ extern const VMStateDescription vmstate_ehci;
|
||||
|
||||
void usb_ehci_initfn(EHCIState *s, DeviceState *dev);
|
||||
|
||||
#define TYPE_PCI_EHCI "pci-ehci-usb"
|
||||
#define PCI_EHCI(obj) OBJECT_CHECK(EHCIPCIState, (obj), TYPE_PCI_EHCI)
|
||||
|
||||
typedef struct EHCIPCIState {
|
||||
/*< private >*/
|
||||
PCIDevice pcidev;
|
||||
/*< public >*/
|
||||
|
||||
EHCIState ehci;
|
||||
} EHCIPCIState;
|
||||
|
||||
|
||||
#define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb"
|
||||
#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
|
||||
|
||||
#define SYS_BUS_EHCI(obj) \
|
||||
OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI)
|
||||
#define SYS_BUS_EHCI_CLASS(class) \
|
||||
OBJECT_CLASS_CHECK(SysBusEHCIClass, (class), TYPE_SYS_BUS_EHCI)
|
||||
#define SYS_BUS_EHCI_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(SysBusEHCIClass, (obj), TYPE_SYS_BUS_EHCI)
|
||||
|
||||
typedef struct EHCISysBusState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
EHCIState ehci;
|
||||
} EHCISysBusState;
|
||||
|
||||
typedef struct SysBusEHCIClass {
|
||||
/*< private >*/
|
||||
SysBusDeviceClass parent_class;
|
||||
/*< public >*/
|
||||
|
||||
uint16_t capsbase;
|
||||
uint16_t opregbase;
|
||||
} SysBusEHCIClass;
|
||||
|
||||
#endif
|
||||
|
||||
+26
-4
@@ -430,6 +430,23 @@ static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ohci_stop_endpoints(OHCIState *ohci)
|
||||
{
|
||||
USBDevice *dev;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < ohci->num_ports; i++) {
|
||||
dev = ohci->rhport[i].port.dev;
|
||||
if (dev && dev->attached) {
|
||||
usb_device_ep_stopped(dev, &dev->ep_ctl);
|
||||
for (j = 0; j < USB_MAX_ENDPOINTS; j++) {
|
||||
usb_device_ep_stopped(dev, &dev->ep_in[j]);
|
||||
usb_device_ep_stopped(dev, &dev->ep_out[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset the controller */
|
||||
static void ohci_reset(void *opaque)
|
||||
{
|
||||
@@ -478,6 +495,7 @@ static void ohci_reset(void *opaque)
|
||||
usb_cancel_packet(&ohci->usb_packet);
|
||||
ohci->async_td = 0;
|
||||
}
|
||||
ohci_stop_endpoints(ohci);
|
||||
DPRINTF("usb-ohci: Reset %s\n", ohci->name);
|
||||
}
|
||||
|
||||
@@ -1147,6 +1165,8 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
|
||||
if (ohci->async_td && addr == ohci->async_td) {
|
||||
usb_cancel_packet(&ohci->usb_packet);
|
||||
ohci->async_td = 0;
|
||||
usb_device_ep_stopped(ohci->usb_packet.ep->dev,
|
||||
ohci->usb_packet.ep);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -1227,10 +1247,12 @@ static void ohci_frame_boundary(void *opaque)
|
||||
}
|
||||
|
||||
/* Cancel all pending packets if either of the lists has been disabled. */
|
||||
if (ohci->async_td &&
|
||||
ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) {
|
||||
usb_cancel_packet(&ohci->usb_packet);
|
||||
ohci->async_td = 0;
|
||||
if (ohci->old_ctl & (~ohci->ctl) & (OHCI_CTL_BLE | OHCI_CTL_CLE)) {
|
||||
if (ohci->async_td) {
|
||||
usb_cancel_packet(&ohci->usb_packet);
|
||||
ohci->async_td = 0;
|
||||
}
|
||||
ohci_stop_endpoints(ohci);
|
||||
}
|
||||
ohci->old_ctl = ohci->ctl;
|
||||
ohci_process_lists(ohci, 0);
|
||||
|
||||
+76
-98
@@ -75,6 +75,11 @@
|
||||
|
||||
#define FRAME_MAX_LOOPS 256
|
||||
|
||||
/* Must be large enough to handle 10 frame delay for initial isoc requests */
|
||||
#define QH_VALID 32
|
||||
|
||||
#define MAX_FRAMES_PER_TICK (QH_VALID / 2)
|
||||
|
||||
#define NB_PORTS 2
|
||||
|
||||
enum {
|
||||
@@ -166,6 +171,7 @@ struct UHCIState {
|
||||
/* Properties */
|
||||
char *masterbus;
|
||||
uint32_t firstport;
|
||||
uint32_t maxframes;
|
||||
};
|
||||
|
||||
typedef struct UHCI_TD {
|
||||
@@ -206,9 +212,7 @@ static UHCIQueue *uhci_queue_new(UHCIState *s, uint32_t qh_addr, UHCI_TD *td,
|
||||
queue->ep = ep;
|
||||
QTAILQ_INIT(&queue->asyncs);
|
||||
QTAILQ_INSERT_HEAD(&s->queues, queue, next);
|
||||
/* valid needs to be large enough to handle 10 frame delay
|
||||
* for initial isochronous requests */
|
||||
queue->valid = 32;
|
||||
queue->valid = QH_VALID;
|
||||
trace_usb_uhci_queue_add(queue->token);
|
||||
return queue;
|
||||
}
|
||||
@@ -222,6 +226,7 @@ static void uhci_queue_free(UHCIQueue *queue, const char *reason)
|
||||
async = QTAILQ_FIRST(&queue->asyncs);
|
||||
uhci_async_cancel(async);
|
||||
}
|
||||
usb_device_ep_stopped(queue->ep->dev, queue->ep);
|
||||
|
||||
trace_usb_uhci_queue_del(queue->token, reason);
|
||||
QTAILQ_REMOVE(&s->queues, queue, next);
|
||||
@@ -433,7 +438,7 @@ static int uhci_post_load(void *opaque, int version_id)
|
||||
|
||||
static const VMStateDescription vmstate_uhci = {
|
||||
.name = "uhci",
|
||||
.version_id = 2,
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = uhci_post_load,
|
||||
@@ -451,44 +456,16 @@ static const VMStateDescription vmstate_uhci = {
|
||||
VMSTATE_UINT8(status2, UHCIState),
|
||||
VMSTATE_TIMER(frame_timer, UHCIState),
|
||||
VMSTATE_INT64_V(expire_time, UHCIState, 2),
|
||||
VMSTATE_UINT32_V(pending_int_mask, UHCIState, 3),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||
static void uhci_port_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
UHCIState *s = opaque;
|
||||
|
||||
addr &= 0x1f;
|
||||
switch(addr) {
|
||||
case 0x0c:
|
||||
s->sof_timing = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr)
|
||||
{
|
||||
UHCIState *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
addr &= 0x1f;
|
||||
switch(addr) {
|
||||
case 0x0c:
|
||||
val = s->sof_timing;
|
||||
break;
|
||||
default:
|
||||
val = 0xff;
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
UHCIState *s = opaque;
|
||||
|
||||
addr &= 0x1f;
|
||||
trace_usb_uhci_mmio_writew(addr, val);
|
||||
|
||||
switch(addr) {
|
||||
@@ -498,7 +475,7 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||
trace_usb_uhci_schedule_start();
|
||||
s->expire_time = qemu_get_clock_ns(vm_clock) +
|
||||
(get_ticks_per_sec() / FRAME_TIMER_FREQ);
|
||||
qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
|
||||
qemu_mod_timer(s->frame_timer, s->expire_time);
|
||||
s->status &= ~UHCI_STS_HCHALTED;
|
||||
} else if (!(val & UHCI_CMD_RS)) {
|
||||
s->status |= UHCI_STS_HCHALTED;
|
||||
@@ -537,6 +514,17 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||
if (s->status & UHCI_STS_HCHALTED)
|
||||
s->frnum = val & 0x7ff;
|
||||
break;
|
||||
case 0x08:
|
||||
s->fl_base_addr &= 0xffff0000;
|
||||
s->fl_base_addr |= val & ~0xfff;
|
||||
break;
|
||||
case 0x0a:
|
||||
s->fl_base_addr &= 0x0000ffff;
|
||||
s->fl_base_addr |= (val << 16);
|
||||
break;
|
||||
case 0x0c:
|
||||
s->sof_timing = val & 0xff;
|
||||
break;
|
||||
case 0x10 ... 0x1f:
|
||||
{
|
||||
UHCIPort *port;
|
||||
@@ -568,12 +556,11 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr)
|
||||
static uint64_t uhci_port_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
UHCIState *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
addr &= 0x1f;
|
||||
switch(addr) {
|
||||
case 0x00:
|
||||
val = s->cmd;
|
||||
@@ -587,6 +574,15 @@ static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr)
|
||||
case 0x06:
|
||||
val = s->frnum;
|
||||
break;
|
||||
case 0x08:
|
||||
val = s->fl_base_addr & 0xffff;
|
||||
break;
|
||||
case 0x0a:
|
||||
val = (s->fl_base_addr >> 16) & 0xffff;
|
||||
break;
|
||||
case 0x0c:
|
||||
val = s->sof_timing;
|
||||
break;
|
||||
case 0x10 ... 0x1f:
|
||||
{
|
||||
UHCIPort *port;
|
||||
@@ -609,38 +605,6 @@ static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr)
|
||||
return val;
|
||||
}
|
||||
|
||||
static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
UHCIState *s = opaque;
|
||||
|
||||
addr &= 0x1f;
|
||||
trace_usb_uhci_mmio_writel(addr, val);
|
||||
|
||||
switch(addr) {
|
||||
case 0x08:
|
||||
s->fl_base_addr = val & ~0xfff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr)
|
||||
{
|
||||
UHCIState *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
addr &= 0x1f;
|
||||
switch(addr) {
|
||||
case 0x08:
|
||||
val = s->fl_base_addr;
|
||||
break;
|
||||
default:
|
||||
val = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
trace_usb_uhci_mmio_readl(addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* signal resume if controller suspended */
|
||||
static void uhci_resume (void *opaque)
|
||||
{
|
||||
@@ -853,7 +817,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
|
||||
}
|
||||
|
||||
if (q) {
|
||||
q->valid = 32;
|
||||
q->valid = QH_VALID;
|
||||
}
|
||||
|
||||
/* Is active ? */
|
||||
@@ -1174,10 +1138,10 @@ static void uhci_bh(void *opaque)
|
||||
static void uhci_frame_timer(void *opaque)
|
||||
{
|
||||
UHCIState *s = opaque;
|
||||
uint64_t t_now, t_last_run;
|
||||
int i, frames;
|
||||
const uint64_t frame_t = get_ticks_per_sec() / FRAME_TIMER_FREQ;
|
||||
|
||||
/* prepare the timer for the next frame */
|
||||
s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ);
|
||||
s->frame_bytes = 0;
|
||||
s->completions_only = false;
|
||||
qemu_bh_cancel(s->bh);
|
||||
|
||||
@@ -1191,7 +1155,35 @@ static void uhci_frame_timer(void *opaque)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Complete the previous frame */
|
||||
/* We still store expire_time in our state, for migration */
|
||||
t_last_run = s->expire_time - frame_t;
|
||||
t_now = qemu_get_clock_ns(vm_clock);
|
||||
|
||||
/* Process up to MAX_FRAMES_PER_TICK frames */
|
||||
frames = (t_now - t_last_run) / frame_t;
|
||||
if (frames > s->maxframes) {
|
||||
int skipped = frames - s->maxframes;
|
||||
s->expire_time += skipped * frame_t;
|
||||
s->frnum = (s->frnum + skipped) & 0x7ff;
|
||||
frames -= skipped;
|
||||
}
|
||||
if (frames > MAX_FRAMES_PER_TICK) {
|
||||
frames = MAX_FRAMES_PER_TICK;
|
||||
}
|
||||
|
||||
for (i = 0; i < frames; i++) {
|
||||
s->frame_bytes = 0;
|
||||
trace_usb_uhci_frame_start(s->frnum);
|
||||
uhci_async_validate_begin(s);
|
||||
uhci_process_frame(s);
|
||||
uhci_async_validate_end(s);
|
||||
/* The spec says frnum is the frame currently being processed, and
|
||||
* the guest must look at frnum - 1 on interrupt, so inc frnum now */
|
||||
s->frnum = (s->frnum + 1) & 0x7ff;
|
||||
s->expire_time += frame_t;
|
||||
}
|
||||
|
||||
/* Complete the previous frame(s) */
|
||||
if (s->pending_int_mask) {
|
||||
s->status2 |= s->pending_int_mask;
|
||||
s->status |= UHCI_STS_USBINT;
|
||||
@@ -1199,32 +1191,17 @@ static void uhci_frame_timer(void *opaque)
|
||||
}
|
||||
s->pending_int_mask = 0;
|
||||
|
||||
/* Start new frame */
|
||||
s->frnum = (s->frnum + 1) & 0x7ff;
|
||||
|
||||
trace_usb_uhci_frame_start(s->frnum);
|
||||
|
||||
uhci_async_validate_begin(s);
|
||||
|
||||
uhci_process_frame(s);
|
||||
|
||||
uhci_async_validate_end(s);
|
||||
|
||||
qemu_mod_timer(s->frame_timer, s->expire_time);
|
||||
qemu_mod_timer(s->frame_timer, t_now + frame_t);
|
||||
}
|
||||
|
||||
static const MemoryRegionPortio uhci_portio[] = {
|
||||
{ 0, 32, 2, .write = uhci_ioport_writew, },
|
||||
{ 0, 32, 2, .read = uhci_ioport_readw, },
|
||||
{ 0, 32, 4, .write = uhci_ioport_writel, },
|
||||
{ 0, 32, 4, .read = uhci_ioport_readl, },
|
||||
{ 0, 32, 1, .write = uhci_ioport_writeb, },
|
||||
{ 0, 32, 1, .read = uhci_ioport_readb, },
|
||||
PORTIO_END_OF_LIST()
|
||||
};
|
||||
|
||||
static const MemoryRegionOps uhci_ioport_ops = {
|
||||
.old_portio = uhci_portio,
|
||||
.read = uhci_port_read,
|
||||
.write = uhci_port_write,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.impl.min_access_size = 2,
|
||||
.impl.max_access_size = 2,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static USBPortOps uhci_port_ops = {
|
||||
@@ -1311,6 +1288,7 @@ static Property uhci_properties[] = {
|
||||
DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
|
||||
DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
|
||||
DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280),
|
||||
DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
+13
-1
@@ -1177,6 +1177,7 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
|
||||
XHCISlot *slot;
|
||||
XHCIEPContext *epctx;
|
||||
int i, xferi, killed = 0;
|
||||
USBEndpoint *ep = NULL;
|
||||
assert(slotid >= 1 && slotid <= xhci->numslots);
|
||||
assert(epid >= 1 && epid <= 31);
|
||||
|
||||
@@ -1192,9 +1193,15 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
|
||||
|
||||
xferi = epctx->next_xfer;
|
||||
for (i = 0; i < TD_QUEUE; i++) {
|
||||
if (epctx->transfers[xferi].packet.ep) {
|
||||
ep = epctx->transfers[xferi].packet.ep;
|
||||
}
|
||||
killed += xhci_ep_nuke_one_xfer(&epctx->transfers[xferi]);
|
||||
xferi = (xferi + 1) % TD_QUEUE;
|
||||
}
|
||||
if (ep) {
|
||||
usb_device_ep_stopped(ep->dev, ep);
|
||||
}
|
||||
return killed;
|
||||
}
|
||||
|
||||
@@ -1963,13 +1970,18 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
|
||||
if (bsr) {
|
||||
slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT;
|
||||
} else {
|
||||
USBPacket p;
|
||||
slot->devaddr = xhci->devaddr++;
|
||||
slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slot->devaddr;
|
||||
DPRINTF("xhci: device address is %d\n", slot->devaddr);
|
||||
usb_device_reset(dev);
|
||||
usb_device_handle_control(dev, NULL,
|
||||
usb_packet_setup(&p, USB_TOKEN_OUT,
|
||||
usb_ep_get(dev, USB_TOKEN_OUT, 0),
|
||||
0, false, false);
|
||||
usb_device_handle_control(dev, &p,
|
||||
DeviceOutRequest | USB_REQ_SET_ADDRESS,
|
||||
slot->devaddr, 0, 0, NULL);
|
||||
assert(p.status != USB_RET_ASYNC);
|
||||
}
|
||||
|
||||
res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* USB quirk handling
|
||||
*
|
||||
* Copyright (c) 2012 Red Hat, Inc.
|
||||
*
|
||||
* Red Hat Authors:
|
||||
* Hans de Goede <hdegoede@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "quirks.h"
|
||||
#include "hw/usb.h"
|
||||
|
||||
static bool usb_id_match(const struct usb_device_id *ids,
|
||||
uint16_t vendor_id, uint16_t product_id,
|
||||
uint8_t interface_class, uint8_t interface_subclass,
|
||||
uint8_t interface_protocol) {
|
||||
int i;
|
||||
|
||||
for (i = 0; ids[i].vendor_id != -1; i++) {
|
||||
if (ids[i].vendor_id == vendor_id &&
|
||||
ids[i].product_id == product_id &&
|
||||
(ids[i].interface_class == -1 ||
|
||||
(ids[i].interface_class == interface_class &&
|
||||
ids[i].interface_subclass == interface_subclass &&
|
||||
ids[i].interface_protocol == interface_protocol))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int usb_get_quirks(uint16_t vendor_id, uint16_t product_id,
|
||||
uint8_t interface_class, uint8_t interface_subclass,
|
||||
uint8_t interface_protocol)
|
||||
{
|
||||
int quirks = 0;
|
||||
|
||||
if (usb_id_match(usbredir_raw_serial_ids, vendor_id, product_id,
|
||||
interface_class, interface_subclass, interface_protocol)) {
|
||||
quirks |= USB_QUIRK_BUFFER_BULK_IN;
|
||||
}
|
||||
if (usb_id_match(usbredir_ftdi_serial_ids, vendor_id, product_id,
|
||||
interface_class, interface_subclass, interface_protocol)) {
|
||||
quirks |= USB_QUIRK_BUFFER_BULK_IN | USB_QUIRK_IS_FTDI;
|
||||
}
|
||||
|
||||
return quirks;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user