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

* kraxel/usb.46: (21 commits)
  usb-ehci: drop assert()
  usb-redir: Notify our peer when we reject a device due to a speed mismatch
  usb-ehci: Drop unused sofv value
  usb-host: rewrite usb_linux_update_endp_table
  usb: use USBDescriptor for endpoint descriptors.
  usb: use USBDescriptor for interface descriptors.
  usb: use USBDescriptor for config descriptors.
  usb: use USBDescriptor for device qualifier descriptors.
  usb: add USBDescriptor, use for device descriptors.
  usb-ehci: frindex always is a 14 bits counter
  usb-ehci: fix ehci_child_detach
  usb-hub: add tracepoints
  usb_packet_set_state: handle p->ep == NULL
  usb-host: add property to turn off pipelining
  usb-host: add usb packet to request tracepoints
  usb-host: trace canceled requests
  usb-host: trace emulated requests
  Add bootindex support to usb-host and usb-redir
  usb-uhci: queuing fix
  usb-uhci: stop queue filling when we find a in-flight td
  ...
master
Anthony Liguori 2012-04-18 07:55:56 -05:00
commit b26d712ecc
12 changed files with 390 additions and 191 deletions

View File

@ -377,6 +377,10 @@ static QEMUMachine pc_machine_v1_1 = {
.driver = "apic",\
.property = "vapic",\
.value = "off",\
},{\
.driver = "USB",\
.property = "full-path",\
.value = "no",\
}
static QEMUMachine pc_machine_v1_0 = {

View File

@ -182,12 +182,17 @@ struct USBEndpoint {
QTAILQ_HEAD(, USBPacket) queue;
};
enum USBDeviceFlags {
USB_DEV_FLAG_FULL_PATH,
};
/* definition of a USB device */
struct USBDevice {
DeviceState qdev;
USBPort *port;
char *port_path;
void *opaque;
uint32_t flags;
/* Actual connected speed */
int speed;

View File

@ -19,6 +19,8 @@ static struct BusInfo usb_bus_info = {
.get_fw_dev_path = usb_get_fw_dev_path,
.props = (Property[]) {
DEFINE_PROP_STRING("port", USBDevice, port_path),
DEFINE_PROP_BIT("full-path", USBDevice, flags,
USB_DEV_FLAG_FULL_PATH, true),
DEFINE_PROP_END_OF_LIST()
},
};
@ -460,7 +462,20 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
static char *usb_get_dev_path(DeviceState *qdev)
{
USBDevice *dev = USB_DEVICE(qdev);
return g_strdup(dev->port->path);
DeviceState *hcd = qdev->parent_bus->parent;
char *id = NULL;
if ((dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) &&
hcd && hcd->parent_bus && hcd->parent_bus->info->get_dev_path) {
id = hcd->parent_bus->info->get_dev_path(hcd);
}
if (id) {
char *ret = g_strdup_printf("%s/%s", id, dev->port->path);
g_free(id);
return ret;
} else {
return g_strdup(dev->port->path);
}
}
static char *usb_get_fw_dev_path(DeviceState *qdev)

View File

@ -484,12 +484,17 @@ void usb_packet_check_state(USBPacket *p, USBPacketState expected)
void usb_packet_set_state(USBPacket *p, USBPacketState state)
{
USBDevice *dev = p->ep->dev;
USBBus *bus = usb_bus_from_device(dev);
trace_usb_packet_state_change(bus->busnr, dev->port->path, p->ep->nr, p,
usb_packet_state_name(p->state),
usb_packet_state_name(state));
if (p->ep) {
USBDevice *dev = p->ep->dev;
USBBus *bus = usb_bus_from_device(dev);
trace_usb_packet_state_change(bus->busnr, dev->port->path, p->ep->nr, p,
usb_packet_state_name(p->state),
usb_packet_state_name(state));
} else {
trace_usb_packet_state_change(-1, "", -1, p,
usb_packet_state_name(p->state),
usb_packet_state_name(state));
}
p->state = state;
}

View File

@ -18,32 +18,33 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
uint8_t *dest, size_t len)
{
uint8_t bLength = 0x12;
USBDescriptor *d = (void *)dest;
if (len < bLength) {
return -1;
}
dest[0x00] = bLength;
dest[0x01] = USB_DT_DEVICE;
d->bLength = bLength;
d->bDescriptorType = USB_DT_DEVICE;
dest[0x02] = usb_lo(dev->bcdUSB);
dest[0x03] = usb_hi(dev->bcdUSB);
dest[0x04] = dev->bDeviceClass;
dest[0x05] = dev->bDeviceSubClass;
dest[0x06] = dev->bDeviceProtocol;
dest[0x07] = dev->bMaxPacketSize0;
d->u.device.bcdUSB_lo = usb_lo(dev->bcdUSB);
d->u.device.bcdUSB_hi = usb_hi(dev->bcdUSB);
d->u.device.bDeviceClass = dev->bDeviceClass;
d->u.device.bDeviceSubClass = dev->bDeviceSubClass;
d->u.device.bDeviceProtocol = dev->bDeviceProtocol;
d->u.device.bMaxPacketSize0 = dev->bMaxPacketSize0;
dest[0x08] = usb_lo(id->idVendor);
dest[0x09] = usb_hi(id->idVendor);
dest[0x0a] = usb_lo(id->idProduct);
dest[0x0b] = usb_hi(id->idProduct);
dest[0x0c] = usb_lo(id->bcdDevice);
dest[0x0d] = usb_hi(id->bcdDevice);
dest[0x0e] = id->iManufacturer;
dest[0x0f] = id->iProduct;
dest[0x10] = id->iSerialNumber;
d->u.device.idVendor_lo = usb_lo(id->idVendor);
d->u.device.idVendor_hi = usb_hi(id->idVendor);
d->u.device.idProduct_lo = usb_lo(id->idProduct);
d->u.device.idProduct_hi = usb_hi(id->idProduct);
d->u.device.bcdDevice_lo = usb_lo(id->bcdDevice);
d->u.device.bcdDevice_hi = usb_hi(id->bcdDevice);
d->u.device.iManufacturer = id->iManufacturer;
d->u.device.iProduct = id->iProduct;
d->u.device.iSerialNumber = id->iSerialNumber;
dest[0x11] = dev->bNumConfigurations;
d->u.device.bNumConfigurations = dev->bNumConfigurations;
return bLength;
}
@ -52,22 +53,23 @@ int usb_desc_device_qualifier(const USBDescDevice *dev,
uint8_t *dest, size_t len)
{
uint8_t bLength = 0x0a;
USBDescriptor *d = (void *)dest;
if (len < bLength) {
return -1;
}
dest[0x00] = bLength;
dest[0x01] = USB_DT_DEVICE_QUALIFIER;
d->bLength = bLength;
d->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
dest[0x02] = usb_lo(dev->bcdUSB);
dest[0x03] = usb_hi(dev->bcdUSB);
dest[0x04] = dev->bDeviceClass;
dest[0x05] = dev->bDeviceSubClass;
dest[0x06] = dev->bDeviceProtocol;
dest[0x07] = dev->bMaxPacketSize0;
dest[0x08] = dev->bNumConfigurations;
dest[0x09] = 0; /* reserved */
d->u.device_qualifier.bcdUSB_lo = usb_lo(dev->bcdUSB);
d->u.device_qualifier.bcdUSB_hi = usb_hi(dev->bcdUSB);
d->u.device_qualifier.bDeviceClass = dev->bDeviceClass;
d->u.device_qualifier.bDeviceSubClass = dev->bDeviceSubClass;
d->u.device_qualifier.bDeviceProtocol = dev->bDeviceProtocol;
d->u.device_qualifier.bMaxPacketSize0 = dev->bMaxPacketSize0;
d->u.device_qualifier.bNumConfigurations = dev->bNumConfigurations;
d->u.device_qualifier.bReserved = 0;
return bLength;
}
@ -76,22 +78,24 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
{
uint8_t bLength = 0x09;
uint16_t wTotalLength = 0;
USBDescriptor *d = (void *)dest;
int i, rc;
if (len < bLength) {
return -1;
}
dest[0x00] = bLength;
dest[0x01] = USB_DT_CONFIG;
dest[0x04] = conf->bNumInterfaces;
dest[0x05] = conf->bConfigurationValue;
dest[0x06] = conf->iConfiguration;
dest[0x07] = conf->bmAttributes;
dest[0x08] = conf->bMaxPower;
d->bLength = bLength;
d->bDescriptorType = USB_DT_CONFIG;
d->u.config.bNumInterfaces = conf->bNumInterfaces;
d->u.config.bConfigurationValue = conf->bConfigurationValue;
d->u.config.iConfiguration = conf->iConfiguration;
d->u.config.bmAttributes = conf->bmAttributes;
d->u.config.bMaxPower = conf->bMaxPower;
wTotalLength += bLength;
/* handle grouped interfaces if any*/
/* handle grouped interfaces if any */
for (i = 0; i < conf->nif_groups; i++) {
rc = usb_desc_iface_group(&(conf->if_groups[i]),
dest + wTotalLength,
@ -111,8 +115,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
wTotalLength += rc;
}
dest[0x02] = usb_lo(wTotalLength);
dest[0x03] = usb_hi(wTotalLength);
d->u.config.wTotalLength_lo = usb_lo(wTotalLength);
d->u.config.wTotalLength_hi = usb_hi(wTotalLength);
return wTotalLength;
}
@ -155,20 +159,22 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
{
uint8_t bLength = 0x09;
int i, rc, pos = 0;
USBDescriptor *d = (void *)dest;
if (len < bLength) {
return -1;
}
dest[0x00] = bLength;
dest[0x01] = USB_DT_INTERFACE;
dest[0x02] = iface->bInterfaceNumber;
dest[0x03] = iface->bAlternateSetting;
dest[0x04] = iface->bNumEndpoints;
dest[0x05] = iface->bInterfaceClass;
dest[0x06] = iface->bInterfaceSubClass;
dest[0x07] = iface->bInterfaceProtocol;
dest[0x08] = iface->iInterface;
d->bLength = bLength;
d->bDescriptorType = USB_DT_INTERFACE;
d->u.interface.bInterfaceNumber = iface->bInterfaceNumber;
d->u.interface.bAlternateSetting = iface->bAlternateSetting;
d->u.interface.bNumEndpoints = iface->bNumEndpoints;
d->u.interface.bInterfaceClass = iface->bInterfaceClass;
d->u.interface.bInterfaceSubClass = iface->bInterfaceSubClass;
d->u.interface.bInterfaceProtocol = iface->bInterfaceProtocol;
d->u.interface.iInterface = iface->iInterface;
pos += bLength;
for (i = 0; i < iface->ndesc; i++) {
@ -194,21 +200,23 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
{
uint8_t bLength = ep->is_audio ? 0x09 : 0x07;
uint8_t extralen = ep->extra ? ep->extra[0] : 0;
USBDescriptor *d = (void *)dest;
if (len < bLength + extralen) {
return -1;
}
dest[0x00] = bLength;
dest[0x01] = USB_DT_ENDPOINT;
dest[0x02] = ep->bEndpointAddress;
dest[0x03] = ep->bmAttributes;
dest[0x04] = usb_lo(ep->wMaxPacketSize);
dest[0x05] = usb_hi(ep->wMaxPacketSize);
dest[0x06] = ep->bInterval;
d->bLength = bLength;
d->bDescriptorType = USB_DT_ENDPOINT;
d->u.endpoint.bEndpointAddress = ep->bEndpointAddress;
d->u.endpoint.bmAttributes = ep->bmAttributes;
d->u.endpoint.wMaxPacketSize_lo = usb_lo(ep->wMaxPacketSize);
d->u.endpoint.wMaxPacketSize_hi = usb_hi(ep->wMaxPacketSize);
d->u.endpoint.bInterval = ep->bInterval;
if (ep->is_audio) {
dest[0x07] = ep->bRefresh;
dest[0x08] = ep->bSynchAddress;
d->u.endpoint.bRefresh = ep->bRefresh;
d->u.endpoint.bSynchAddress = ep->bSynchAddress;
}
if (ep->extra) {
memcpy(dest + bLength, ep->extra, extralen);

View File

@ -3,6 +3,69 @@
#include <inttypes.h>
/* binary representation */
typedef struct USBDescriptor {
uint8_t bLength;
uint8_t bDescriptorType;
union {
struct {
uint8_t bcdUSB_lo;
uint8_t bcdUSB_hi;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint8_t idVendor_lo;
uint8_t idVendor_hi;
uint8_t idProduct_lo;
uint8_t idProduct_hi;
uint8_t bcdDevice_lo;
uint8_t bcdDevice_hi;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} device;
struct {
uint8_t bcdUSB_lo;
uint8_t bcdUSB_hi;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint8_t bNumConfigurations;
uint8_t bReserved;
} device_qualifier;
struct {
uint8_t wTotalLength_lo;
uint8_t wTotalLength_hi;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
} config;
struct {
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} interface;
struct {
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint8_t wMaxPacketSize_lo;
uint8_t wMaxPacketSize_hi;
uint8_t bInterval;
uint8_t bRefresh; /* only audio ep */
uint8_t bSynchAddress; /* only audio ep */
} endpoint;
} u;
} QEMU_PACKED USBDescriptor;
struct USBDescID {
uint16_t idVendor;
uint16_t idProduct;

View File

@ -22,11 +22,10 @@
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "trace.h"
#include "hw/usb.h"
#include "hw/usb/desc.h"
//#define DEBUG
#define NUM_PORTS 8
typedef struct USBHubPort {
@ -157,6 +156,7 @@ static void usb_hub_attach(USBPort *port1)
USBHubState *s = port1->opaque;
USBHubPort *port = &s->ports[port1->index];
trace_usb_hub_attach(s->dev.addr, port1->index + 1);
port->wPortStatus |= PORT_STAT_CONNECTION;
port->wPortChange |= PORT_STAT_C_CONNECTION;
if (port->port.dev->speed == USB_SPEED_LOW) {
@ -172,6 +172,7 @@ static void usb_hub_detach(USBPort *port1)
USBHubState *s = port1->opaque;
USBHubPort *port = &s->ports[port1->index];
trace_usb_hub_detach(s->dev.addr, port1->index + 1);
usb_wakeup(s->intr);
/* Let upstream know the device on this port is gone */
@ -247,6 +248,7 @@ static void usb_hub_handle_reset(USBDevice *dev)
USBHubPort *port;
int i;
trace_usb_hub_reset(s->dev.addr);
for (i = 0; i < NUM_PORTS; i++) {
port = s->ports + i;
port->wPortStatus = PORT_STAT_POWER;
@ -261,12 +263,39 @@ static void usb_hub_handle_reset(USBDevice *dev)
}
}
static const char *feature_name(int feature)
{
static const char *name[] = {
[PORT_CONNECTION] = "connection",
[PORT_ENABLE] = "enable",
[PORT_SUSPEND] = "suspend",
[PORT_OVERCURRENT] = "overcurrent",
[PORT_RESET] = "reset",
[PORT_POWER] = "power",
[PORT_LOWSPEED] = "lowspeed",
[PORT_HIGHSPEED] = "highspeed",
[PORT_C_CONNECTION] = "change connection",
[PORT_C_ENABLE] = "change enable",
[PORT_C_SUSPEND] = "change suspend",
[PORT_C_OVERCURRENT] = "change overcurrent",
[PORT_C_RESET] = "change reset",
[PORT_TEST] = "test",
[PORT_INDICATOR] = "indicator",
};
if (feature < 0 || feature >= ARRAY_SIZE(name)) {
return "?";
}
return name[feature] ?: "?";
}
static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBHubState *s = (USBHubState *)dev;
int ret;
trace_usb_hub_control(s->dev.addr, request, value, index, length);
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return ret;
@ -295,6 +324,9 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
goto fail;
}
port = &s->ports[n];
trace_usb_hub_get_port_status(s->dev.addr, index,
port->wPortStatus,
port->wPortChange);
data[0] = port->wPortStatus;
data[1] = port->wPortStatus >> 8;
data[2] = port->wPortChange;
@ -315,6 +347,10 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
unsigned int n = index - 1;
USBHubPort *port;
USBDevice *dev;
trace_usb_hub_set_port_feature(s->dev.addr, index,
feature_name(value));
if (n >= NUM_PORTS) {
goto fail;
}
@ -345,6 +381,9 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
unsigned int n = index - 1;
USBHubPort *port;
trace_usb_hub_clear_port_feature(s->dev.addr, index,
feature_name(value));
if (n >= NUM_PORTS) {
goto fail;
}

View File

@ -403,7 +403,6 @@ struct EHCIState {
/*
* Internal states, shadow registers, etc
*/
uint32_t sofv;
QEMUTimer *frame_timer;
int attach_poll_counter;
int astate; // Current state in asynchronous schedule
@ -797,7 +796,6 @@ static void ehci_child_detach(USBPort *port, USBDevice *child)
if (portsc & PORTSC_POWNER) {
USBPort *companion = s->companion_ports[port->index];
companion->ops->child_detach(companion, child);
companion->dev = NULL;
return;
}
@ -1103,10 +1101,6 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
val &= USBINTR_MASK;
break;
case FRINDEX:
s->sofv = val >> 3;
break;
case CONFIGFLAG:
val &= 0x1;
if (val) {
@ -2015,7 +2009,6 @@ static void ehci_advance_state(EHCIState *ehci,
fprintf(stderr, "processing error - resetting ehci HC\n");
ehci_reset(ehci);
again = 0;
assert(0);
}
}
while (again);
@ -2150,13 +2143,14 @@ static void ehci_frame_timer(void *opaque)
if ( !(ehci->usbsts & USBSTS_HALT)) {
ehci->frindex += 8;
if (ehci->frindex > 0x00001fff) {
ehci->frindex = 0;
if (ehci->frindex == 0x00002000) {
ehci_set_interrupt(ehci, USBSTS_FLR);
}
ehci->sofv = (ehci->frindex - 1) >> 3;
ehci->sofv &= 0x000003ff;
if (ehci->frindex == 0x00004000) {
ehci_set_interrupt(ehci, USBSTS_FLR);
ehci->frindex = 0;
}
}
if (frames - i > ehci->maxframes) {

View File

@ -795,7 +795,8 @@ out:
return TD_RESULT_NEXT_QH;
}
static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *int_mask)
static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td,
uint32_t *int_mask, bool queuing)
{
UHCIAsync *async;
int len = 0, max_len;
@ -814,6 +815,12 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
if (!async->done)
return TD_RESULT_ASYNC_CONT;
if (queuing) {
/* we are busy filling the queue, we are not prepared
to consume completed packages then, just leave them
in async state */
return TD_RESULT_ASYNC_CONT;
}
uhci_async_unlink(async);
goto done;
@ -964,7 +971,10 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
break;
}
trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token);
ret = uhci_handle_td(s, plink, &ptd, &int_mask);
ret = uhci_handle_td(s, plink, &ptd, &int_mask, true);
if (ret == TD_RESULT_ASYNC_CONT) {
break;
}
assert(ret == TD_RESULT_ASYNC_START);
assert(int_mask == 0);
plink = ptd.link;
@ -1045,7 +1055,7 @@ static void uhci_process_frame(UHCIState *s)
trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token);
old_td_ctrl = td.ctrl;
ret = uhci_handle_td(s, link, &td, &int_mask);
ret = uhci_handle_td(s, link, &td, &int_mask, false);
if (old_td_ctrl != td.ctrl) {
/* update the status bits of the TD */
val = cpu_to_le32(td.ctrl);

View File

@ -42,6 +42,7 @@
#include <linux/usbdevice_fs.h>
#include <linux/version.h>
#include "hw/usb.h"
#include "hw/usb/desc.h"
/* We redefine it to avoid version problems */
struct usb_ctrltransfer {
@ -94,6 +95,10 @@ struct USBAutoFilter {
uint32_t product_id;
};
enum USBHostDeviceOptions {
USB_HOST_OPT_PIPELINE,
};
typedef struct USBHostDevice {
USBDevice dev;
int fd;
@ -104,6 +109,7 @@ typedef struct USBHostDevice {
int descr_len;
int closing;
uint32_t iso_urb_count;
uint32_t options;
Notifier exit;
struct endp_data ep_in[USB_MAX_ENDPOINTS];
@ -115,6 +121,7 @@ typedef struct USBHostDevice {
int addr;
char port[MAX_PORTLEN];
struct USBAutoFilter match;
int32_t bootindex;
int seen, errcount;
QTAILQ_ENTRY(USBHostDevice) next;
@ -374,10 +381,10 @@ static void async_complete(void *opaque)
}
if (aurb->urb.type == USBDEVFS_URB_TYPE_CONTROL) {
trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result);
usb_generic_async_ctrl_complete(&s->dev, p);
} else if (!aurb->more) {
trace_usb_host_req_complete(s->bus_num, s->addr, p->result);
trace_usb_host_req_complete(s->bus_num, s->addr, p, p->result);
usb_packet_complete(&s->dev, p);
}
}
@ -391,12 +398,14 @@ static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev);
AsyncURB *aurb;
trace_usb_host_req_canceled(s->bus_num, s->addr, p);
QLIST_FOREACH(aurb, &s->aurbs, next) {
if (p != aurb->packet) {
continue;
}
DPRINTF("husb: async cancel: packet %p, aurb %p\n", p, aurb);
trace_usb_host_urb_canceled(s->bus_num, s->addr, aurb);
/* Mark it as dead (see async_complete above) */
aurb->packet = NULL;
@ -844,12 +853,12 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
uint8_t *pbuf;
uint8_t ep;
trace_usb_host_req_data(s->bus_num, s->addr,
trace_usb_host_req_data(s->bus_num, s->addr, p,
p->pid == USB_TOKEN_IN,
p->ep->nr, p->iov.size);
if (!is_valid(s, p->pid, p->ep->nr)) {
trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK);
return USB_RET_NAK;
}
@ -864,7 +873,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &arg);
if (ret < 0) {
perror("USBDEVFS_CLEAR_HALT");
trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
trace_usb_host_req_complete(s->bus_num, s->addr, p, USB_RET_NAK);
return USB_RET_NAK;
}
clear_halt(s, p->pid, p->ep->nr);
@ -919,11 +928,13 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
switch(errno) {
case ETIMEDOUT:
trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_NAK);
trace_usb_host_req_complete(s->bus_num, s->addr, p,
USB_RET_NAK);
return USB_RET_NAK;
case EPIPE:
default:
trace_usb_host_req_complete(s->bus_num, s->addr, USB_RET_STALL);
trace_usb_host_req_complete(s->bus_num, s->addr, p,
USB_RET_STALL);
return USB_RET_STALL;
}
}
@ -1030,17 +1041,23 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
*/
/* Note request is (bRequestType << 8) | bRequest */
trace_usb_host_req_control(s->bus_num, s->addr, request, value, index);
trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
switch (request) {
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
return usb_host_set_address(s, value);
ret = usb_host_set_address(s, value);
trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
return ret;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
return usb_host_set_config(s, value & 0xff);
ret = usb_host_set_config(s, value & 0xff);
trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
return ret;
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
return usb_host_set_interface(s, index, value);
ret = usb_host_set_interface(s, index, value);
trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
return ret;
}
/* The rest are asynchronous */
@ -1092,120 +1109,128 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
return USB_RET_ASYNC;
}
static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
uint8_t configuration, uint8_t interface)
{
char device_name[64], line[1024];
int alt_setting;
sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
(int)configuration, (int)interface);
if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
device_name)) {
/* Assume alt 0 on error */
return 0;
}
if (sscanf(line, "%d", &alt_setting) != 1) {
/* Assume alt 0 on error */
return 0;
}
return alt_setting;
}
/* returns 1 on problem encountered or 0 for success */
static int usb_linux_update_endp_table(USBHostDevice *s)
{
uint8_t *descriptors;
uint8_t devep, type, alt_interface;
uint16_t raw;
int interface, length, i, ep, pid;
static const char *tname[] = {
[USB_ENDPOINT_XFER_CONTROL] = "control",
[USB_ENDPOINT_XFER_ISOC] = "isoc",
[USB_ENDPOINT_XFER_BULK] = "bulk",
[USB_ENDPOINT_XFER_INT] = "int",
};
uint8_t devep, type;
uint16_t mps, v, p;
int ep, pid;
unsigned int i, configuration = -1, interface = -1, altsetting = -1;
struct endp_data *epd;
USBDescriptor *d;
bool active = false;
usb_ep_init(&s->dev);
if (s->dev.configuration == 0) {
/* not configured yet -- leave all endpoints disabled */
return 0;
}
/* get the desired configuration, interface, and endpoint descriptors
* from device description */
descriptors = &s->descr[18];
length = s->descr_len - 18;
i = 0;
while (i < length) {
if (descriptors[i + 1] != USB_DT_CONFIG) {
fprintf(stderr, "invalid descriptor data\n");
return 1;
} else if (descriptors[i + 5] != s->dev.configuration) {
DPRINTF("not requested configuration %d\n", s->dev.configuration);
i += (descriptors[i + 3] << 8) + descriptors[i + 2];
continue;
}
i += descriptors[i];
if (descriptors[i + 1] != USB_DT_INTERFACE ||
(descriptors[i + 1] == USB_DT_INTERFACE &&
descriptors[i + 4] == 0)) {
i += descriptors[i];
continue;
}
interface = descriptors[i + 2];
alt_interface = usb_linux_get_alt_setting(s, s->dev.configuration,
interface);
/* the current interface descriptor is the active interface
* and has endpoints */
if (descriptors[i + 3] != alt_interface) {
i += descriptors[i];
continue;
}
/* advance to the endpoints */
while (i < length && descriptors[i +1] != USB_DT_ENDPOINT) {
i += descriptors[i];
}
if (i >= length)
for (i = 0;; i += d->bLength) {
if (i+2 >= s->descr_len) {
break;
while (i < length) {
if (descriptors[i + 1] != USB_DT_ENDPOINT) {
break;
}
d = (void *)(s->descr + i);
if (d->bLength < 2) {
trace_usb_host_parse_error(s->bus_num, s->addr,
"descriptor too short");
goto error;
}
if (i + d->bLength > s->descr_len) {
trace_usb_host_parse_error(s->bus_num, s->addr,
"descriptor too long");
goto error;
}
switch (d->bDescriptorType) {
case 0:
trace_usb_host_parse_error(s->bus_num, s->addr,
"invalid descriptor type");
goto error;
case USB_DT_DEVICE:
if (d->bLength < 0x12) {
trace_usb_host_parse_error(s->bus_num, s->addr,
"device descriptor too short");
goto error;
}
devep = descriptors[i + 2];
v = (d->u.device.idVendor_hi << 8) | d->u.device.idVendor_lo;
p = (d->u.device.idProduct_hi << 8) | d->u.device.idProduct_lo;
trace_usb_host_parse_device(s->bus_num, s->addr, v, p);
break;
case USB_DT_CONFIG:
if (d->bLength < 0x09) {
trace_usb_host_parse_error(s->bus_num, s->addr,
"config descriptor too short");
goto error;
}
configuration = d->u.config.bConfigurationValue;
active = (configuration == s->dev.configuration);
trace_usb_host_parse_config(s->bus_num, s->addr,
configuration, active);
break;
case USB_DT_INTERFACE:
if (d->bLength < 0x09) {
trace_usb_host_parse_error(s->bus_num, s->addr,
"interface descriptor too short");
goto error;
}
interface = d->u.interface.bInterfaceNumber;
altsetting = d->u.interface.bAlternateSetting;
active = (configuration == s->dev.configuration) &&
(altsetting == s->dev.altsetting[interface]);
trace_usb_host_parse_interface(s->bus_num, s->addr,
interface, altsetting, active);
break;
case USB_DT_ENDPOINT:
if (d->bLength < 0x07) {
trace_usb_host_parse_error(s->bus_num, s->addr,
"endpoint descriptor too short");
goto error;
}
devep = d->u.endpoint.bEndpointAddress;
pid = (devep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
ep = devep & 0xf;
if (ep == 0) {
fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
return 1;
trace_usb_host_parse_error(s->bus_num, s->addr,
"invalid endpoint address");
goto error;
}
type = descriptors[i + 3] & 0x3;
raw = descriptors[i + 4] + (descriptors[i + 5] << 8);
usb_ep_set_max_packet_size(&s->dev, pid, ep, raw);
assert(usb_ep_get_type(&s->dev, pid, ep) ==
USB_ENDPOINT_XFER_INVALID);
usb_ep_set_type(&s->dev, pid, ep, type);
usb_ep_set_ifnum(&s->dev, pid, ep, interface);
if (type == USB_ENDPOINT_XFER_BULK) {
usb_ep_set_pipeline(&s->dev, pid, ep, true);
type = d->u.endpoint.bmAttributes & 0x3;
mps = d->u.endpoint.wMaxPacketSize_lo |
(d->u.endpoint.wMaxPacketSize_hi << 8);
trace_usb_host_parse_endpoint(s->bus_num, s->addr, ep,
(devep & USB_DIR_IN) ? "in" : "out",
tname[type], active);
if (active) {
usb_ep_set_max_packet_size(&s->dev, pid, ep, mps);
assert(usb_ep_get_type(&s->dev, pid, ep) ==
USB_ENDPOINT_XFER_INVALID);
usb_ep_set_type(&s->dev, pid, ep, type);
usb_ep_set_ifnum(&s->dev, pid, ep, interface);
if ((s->options & (1 << USB_HOST_OPT_PIPELINE)) &&
(type == USB_ENDPOINT_XFER_BULK)) {
usb_ep_set_pipeline(&s->dev, pid, ep, true);
}
epd = get_endp(s, pid, ep);
epd->halted = 0;
}
epd = get_endp(s, pid, ep);
epd->halted = 0;
i += descriptors[i];
break;
default:
trace_usb_host_parse_unknown(s->bus_num, s->addr,
d->bLength, d->bDescriptorType);
break;
}
}
#ifdef DEBUG
usb_ep_dump(&s->dev);
#endif
return 0;
error:
usb_ep_init(&s->dev);
return 1;
}
/*
@ -1403,6 +1428,7 @@ static int usb_host_initfn(USBDevice *dev)
if (s->match.bus_num != 0 && s->match.port != NULL) {
usb_host_claim_port(s);
}
add_boot_device_path(s->bootindex, &dev->qdev, NULL);
return 0;
}
@ -1418,6 +1444,9 @@ static Property usb_host_dev_properties[] = {
DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
DEFINE_PROP_INT32("bootindex", USBHostDevice, bootindex, -1),
DEFINE_PROP_BIT("pipeline", USBHostDevice, options,
USB_HOST_OPT_PIPELINE, true),
DEFINE_PROP_END_OF_LIST(),
};

View File

@ -74,6 +74,7 @@ struct USBRedirDevice {
CharDriverState *cs;
uint8_t debug;
char *filter_str;
int32_t bootindex;
/* Data passed from chardev the fd_read cb to the usbredirparser read cb */
const uint8_t *read_buf;
int read_buf_size;
@ -835,7 +836,13 @@ static void usbredir_do_attach(void *opaque)
{
USBRedirDevice *dev = opaque;
usb_device_attach(&dev->dev);
if (usb_device_attach(&dev->dev) != 0) {
usbredir_device_disconnect(dev);
if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) {
usbredirparser_send_filter_reject(dev->parser);
usbredirparser_do_write(dev->parser);
}
}
}
/*
@ -923,6 +930,7 @@ static int usbredir_initfn(USBDevice *udev)
qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
usbredir_chardev_read, usbredir_chardev_event, dev);
add_boot_device_path(dev->bootindex, &udev->qdev, NULL);
return 0;
}
@ -1452,6 +1460,7 @@ static Property usbredir_properties[] = {
DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str),
DEFINE_PROP_INT32("bootindex", USBRedirDevice, bootindex, -1),
DEFINE_PROP_END_OF_LIST(),
};

View File

@ -289,7 +289,7 @@ usb_uhci_td_nextqh(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x"
usb_uhci_td_async(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x"
usb_uhci_td_complete(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x"
# hw/usb-desc.c
# hw/usb/desc.c
usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d"
usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d"
@ -301,6 +301,15 @@ usb_set_interface(int addr, int iface, int alt, int ret) "dev %d, interface %d,
usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
# hw/usb/dev-hub.c
usb_hub_reset(int addr) "dev %d"
usb_hub_control(int addr, int request, int value, int index, int length) "dev %d, req 0x%x, value %d, index %d, langth %d"
usb_hub_get_port_status(int addr, int nr, int status, int changed) "dev %d, port %d, status 0x%x, changed 0x%x"
usb_hub_set_port_feature(int addr, int nr, const char *f) "dev %d, port %d, feature %s"
usb_hub_clear_port_feature(int addr, int nr, const char *f) "dev %d, port %d, feature %s"
usb_hub_attach(int addr, int nr) "dev %d, port %d"
usb_hub_detach(int addr, int nr) "dev %d, port %d"
# hw/usb/host-linux.c
usb_host_open_started(int bus, int addr) "dev %d:%d"
usb_host_open_success(int bus, int addr) "dev %d:%d"
@ -312,11 +321,14 @@ usb_host_set_config(int bus, int addr, int config) "dev %d:%d, config %d"
usb_host_set_interface(int bus, int addr, int interface, int alt) "dev %d:%d, interface %d, alt %d"
usb_host_claim_interfaces(int bus, int addr, int config, int nif) "dev %d:%d, config %d, nif %d"
usb_host_release_interfaces(int bus, int addr) "dev %d:%d"
usb_host_req_control(int bus, int addr, int req, int value, int index) "dev %d:%d, req 0x%x, value %d, index %d"
usb_host_req_data(int bus, int addr, int in, int ep, int size) "dev %d:%d, in %d, ep %d, size %d"
usb_host_req_complete(int bus, int addr, int status) "dev %d:%d, status %d"
usb_host_req_control(int bus, int addr, void *p, int req, int value, int index) "dev %d:%d, packet %p, req 0x%x, value %d, index %d"
usb_host_req_data(int bus, int addr, void *p, int in, int ep, int size) "dev %d:%d, packet %p, in %d, ep %d, size %d"
usb_host_req_complete(int bus, int addr, void *p, int status) "dev %d:%d, packet %p, status %d"
usb_host_req_emulated(int bus, int addr, void *p, int status) "dev %d:%d, packet %p, status %d"
usb_host_req_canceled(int bus, int addr, void *p) "dev %d:%d, packet %p"
usb_host_urb_submit(int bus, int addr, void *aurb, int length, int more) "dev %d:%d, aurb %p, length %d, more %d"
usb_host_urb_complete(int bus, int addr, void *aurb, int status, int length, int more) "dev %d:%d, aurb %p, status %d, length %d, more %d"
usb_host_urb_canceled(int bus, int addr, void *aurb) "dev %d:%d, aurb %p"
usb_host_ep_set_halt(int bus, int addr, int ep) "dev %d:%d, ep %d"
usb_host_ep_clear_halt(int bus, int addr, int ep) "dev %d:%d, ep %d"
usb_host_ep_start_iso(int bus, int addr, int ep) "dev %d:%d, ep %d"
@ -325,6 +337,12 @@ usb_host_reset(int bus, int addr) "dev %d:%d"
usb_host_auto_scan_enabled(void)
usb_host_auto_scan_disabled(void)
usb_host_claim_port(int bus, int hub, int port) "bus %d, hub addr %d, port %d"
usb_host_parse_device(int bus, int addr, int vendor, int product) "dev %d:%d, id %04x:%04x"
usb_host_parse_config(int bus, int addr, int value, int active) "dev %d:%d, value %d, active %d"
usb_host_parse_interface(int bus, int addr, int num, int alt, int active) "dev %d:%d, num %d, alt %d, active %d"
usb_host_parse_endpoint(int bus, int addr, int ep, const char *dir, const char *type, int active) "dev %d:%d, ep %d, %s, %s, active %d"
usb_host_parse_unknown(int bus, int addr, int len, int type) "dev %d:%d, len %d, type %d"
usb_host_parse_error(int bus, int addr, const char *errmsg) "dev %d:%d, msg %s"
# hw/scsi-bus.c
scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"