提交 9f16390c 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-20160914-1' into staging

usb-mtp: add support for files larger than 4g (gsoc)
xhci & usb-host: bugfixes.

# gpg: Signature made Wed 14 Sep 2016 10:30:38 BST
# gpg:                using RSA key 0x4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/pull-usb-20160914-1:
  usb-mtp: added object properties
  usb-mtp: fix sending files larger than 4gb
  usb:xhci:fix memory leak in usb_xhci_exit
  usb-host: fix streams detection in usb_host_speed_compat
  xhci: Fix remainder field for TR_SETUP completion event.
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
...@@ -48,6 +48,9 @@ enum mtp_code { ...@@ -48,6 +48,9 @@ enum mtp_code {
CMD_GET_OBJECT_INFO = 0x1008, CMD_GET_OBJECT_INFO = 0x1008,
CMD_GET_OBJECT = 0x1009, CMD_GET_OBJECT = 0x1009,
CMD_GET_PARTIAL_OBJECT = 0x101b, CMD_GET_PARTIAL_OBJECT = 0x101b,
CMD_GET_OBJECT_PROPS_SUPPORTED = 0x9801,
CMD_GET_OBJECT_PROP_DESC = 0x9802,
CMD_GET_OBJECT_PROP_VALUE = 0x9803,
/* response codes */ /* response codes */
RES_OK = 0x2001, RES_OK = 0x2001,
...@@ -59,10 +62,12 @@ enum mtp_code { ...@@ -59,10 +62,12 @@ enum mtp_code {
RES_INCOMPLETE_TRANSFER = 0x2007, RES_INCOMPLETE_TRANSFER = 0x2007,
RES_INVALID_STORAGE_ID = 0x2008, RES_INVALID_STORAGE_ID = 0x2008,
RES_INVALID_OBJECT_HANDLE = 0x2009, RES_INVALID_OBJECT_HANDLE = 0x2009,
RES_INVALID_OBJECT_FORMAT_CODE = 0x200b,
RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014, RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014,
RES_INVALID_PARENT_OBJECT = 0x201a, RES_INVALID_PARENT_OBJECT = 0x201a,
RES_INVALID_PARAMETER = 0x201d, RES_INVALID_PARAMETER = 0x201d,
RES_SESSION_ALREADY_OPEN = 0x201e, RES_SESSION_ALREADY_OPEN = 0x201e,
RES_INVALID_OBJECT_PROP_CODE = 0xA801,
/* format codes */ /* format codes */
FMT_UNDEFINED_OBJECT = 0x3000, FMT_UNDEFINED_OBJECT = 0x3000,
...@@ -72,6 +77,22 @@ enum mtp_code { ...@@ -72,6 +77,22 @@ enum mtp_code {
EVT_OBJ_ADDED = 0x4002, EVT_OBJ_ADDED = 0x4002,
EVT_OBJ_REMOVED = 0x4003, EVT_OBJ_REMOVED = 0x4003,
EVT_OBJ_INFO_CHANGED = 0x4007, EVT_OBJ_INFO_CHANGED = 0x4007,
/* object properties */
PROP_STORAGE_ID = 0xDC01,
PROP_OBJECT_FORMAT = 0xDC02,
PROP_OBJECT_COMPRESSED_SIZE = 0xDC04,
PROP_PARENT_OBJECT = 0xDC0B,
PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER = 0xDC41,
PROP_NAME = 0xDC44,
};
enum mtp_data_type {
DATA_TYPE_UINT16 = 0x0004,
DATA_TYPE_UINT32 = 0x0006,
DATA_TYPE_UINT64 = 0x0008,
DATA_TYPE_UINT128 = 0x000a,
DATA_TYPE_STRING = 0xffff,
}; };
typedef struct { typedef struct {
...@@ -115,8 +136,8 @@ struct MTPControl { ...@@ -115,8 +136,8 @@ struct MTPControl {
struct MTPData { struct MTPData {
uint16_t code; uint16_t code;
uint32_t trans; uint32_t trans;
uint32_t offset; uint64_t offset;
uint32_t length; uint64_t length;
uint32_t alloc; uint32_t alloc;
uint8_t *data; uint8_t *data;
bool first; bool first;
...@@ -778,6 +799,9 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c) ...@@ -778,6 +799,9 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c)
CMD_GET_OBJECT_INFO, CMD_GET_OBJECT_INFO,
CMD_GET_OBJECT, CMD_GET_OBJECT,
CMD_GET_PARTIAL_OBJECT, CMD_GET_PARTIAL_OBJECT,
CMD_GET_OBJECT_PROPS_SUPPORTED,
CMD_GET_OBJECT_PROP_DESC,
CMD_GET_OBJECT_PROP_VALUE,
}; };
static const uint16_t fmt[] = { static const uint16_t fmt[] = {
FMT_UNDEFINED_OBJECT, FMT_UNDEFINED_OBJECT,
...@@ -883,7 +907,12 @@ static MTPData *usb_mtp_get_object_info(MTPState *s, MTPControl *c, ...@@ -883,7 +907,12 @@ static MTPData *usb_mtp_get_object_info(MTPState *s, MTPControl *c,
usb_mtp_add_u32(d, QEMU_STORAGE_ID); usb_mtp_add_u32(d, QEMU_STORAGE_ID);
usb_mtp_add_u16(d, o->format); usb_mtp_add_u16(d, o->format);
usb_mtp_add_u16(d, 0); usb_mtp_add_u16(d, 0);
usb_mtp_add_u32(d, o->stat.st_size);
if (o->stat.st_size > 0xFFFFFFFF) {
usb_mtp_add_u32(d, 0xFFFFFFFF);
} else {
usb_mtp_add_u32(d, o->stat.st_size);
}
usb_mtp_add_u16(d, 0); usb_mtp_add_u16(d, 0);
usb_mtp_add_u32(d, 0); usb_mtp_add_u32(d, 0);
...@@ -966,6 +995,122 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c, ...@@ -966,6 +995,122 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
return d; return d;
} }
static MTPData *usb_mtp_get_object_props_supported(MTPState *s, MTPControl *c)
{
static const uint16_t props[] = {
PROP_STORAGE_ID,
PROP_OBJECT_FORMAT,
PROP_OBJECT_COMPRESSED_SIZE,
PROP_PARENT_OBJECT,
PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER,
PROP_NAME,
};
MTPData *d = usb_mtp_data_alloc(c);
usb_mtp_add_u16_array(d, ARRAY_SIZE(props), props);
return d;
}
static MTPData *usb_mtp_get_object_prop_desc(MTPState *s, MTPControl *c)
{
MTPData *d = usb_mtp_data_alloc(c);
switch (c->argv[0]) {
case PROP_STORAGE_ID:
usb_mtp_add_u16(d, PROP_STORAGE_ID);
usb_mtp_add_u16(d, DATA_TYPE_UINT32);
usb_mtp_add_u8(d, 0x00);
usb_mtp_add_u32(d, 0x00000000);
usb_mtp_add_u32(d, 0x00000000);
usb_mtp_add_u8(d, 0x00);
break;
case PROP_OBJECT_FORMAT:
usb_mtp_add_u16(d, PROP_OBJECT_FORMAT);
usb_mtp_add_u16(d, DATA_TYPE_UINT16);
usb_mtp_add_u8(d, 0x00);
usb_mtp_add_u16(d, 0x0000);
usb_mtp_add_u32(d, 0x00000000);
usb_mtp_add_u8(d, 0x00);
break;
case PROP_OBJECT_COMPRESSED_SIZE:
usb_mtp_add_u16(d, PROP_OBJECT_COMPRESSED_SIZE);
usb_mtp_add_u16(d, DATA_TYPE_UINT64);
usb_mtp_add_u8(d, 0x00);
usb_mtp_add_u64(d, 0x0000000000000000);
usb_mtp_add_u32(d, 0x00000000);
usb_mtp_add_u8(d, 0x00);
break;
case PROP_PARENT_OBJECT:
usb_mtp_add_u16(d, PROP_PARENT_OBJECT);
usb_mtp_add_u16(d, DATA_TYPE_UINT32);
usb_mtp_add_u8(d, 0x00);
usb_mtp_add_u32(d, 0x00000000);
usb_mtp_add_u32(d, 0x00000000);
usb_mtp_add_u8(d, 0x00);
break;
case PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER:
usb_mtp_add_u16(d, PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER);
usb_mtp_add_u16(d, DATA_TYPE_UINT128);
usb_mtp_add_u8(d, 0x00);
usb_mtp_add_u64(d, 0x0000000000000000);
usb_mtp_add_u64(d, 0x0000000000000000);
usb_mtp_add_u32(d, 0x00000000);
usb_mtp_add_u8(d, 0x00);
break;
case PROP_NAME:
usb_mtp_add_u16(d, PROP_NAME);
usb_mtp_add_u16(d, DATA_TYPE_STRING);
usb_mtp_add_u8(d, 0x00);
usb_mtp_add_u8(d, 0x00);
usb_mtp_add_u32(d, 0x00000000);
usb_mtp_add_u8(d, 0x00);
break;
default:
usb_mtp_data_free(d);
return NULL;
}
return d;
}
static MTPData *usb_mtp_get_object_prop_value(MTPState *s, MTPControl *c,
MTPObject *o)
{
MTPData *d = usb_mtp_data_alloc(c);
switch (c->argv[1]) {
case PROP_STORAGE_ID:
usb_mtp_add_u32(d, QEMU_STORAGE_ID);
break;
case PROP_OBJECT_FORMAT:
usb_mtp_add_u16(d, o->format);
break;
case PROP_OBJECT_COMPRESSED_SIZE:
usb_mtp_add_u64(d, o->stat.st_size);
break;
case PROP_PARENT_OBJECT:
if (o->parent == NULL) {
usb_mtp_add_u32(d, 0x00000000);
} else {
usb_mtp_add_u32(d, o->parent->handle);
}
break;
case PROP_PERSISTENT_UNIQUE_OBJECT_IDENTIFIER:
/* Should be persistant between sessions,
* but using our objedt ID is "good enough"
* for now */
usb_mtp_add_u64(d, 0x0000000000000000);
usb_mtp_add_u64(d, o->handle);
break;
case PROP_NAME:
usb_mtp_add_str(d, o->name);
break;
default:
usb_mtp_data_free(d);
return NULL;
}
return d;
}
static void usb_mtp_command(MTPState *s, MTPControl *c) static void usb_mtp_command(MTPState *s, MTPControl *c)
{ {
MTPData *data_in = NULL; MTPData *data_in = NULL;
...@@ -1113,6 +1258,43 @@ static void usb_mtp_command(MTPState *s, MTPControl *c) ...@@ -1113,6 +1258,43 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
nres = 1; nres = 1;
res0 = data_in->length; res0 = data_in->length;
break; break;
case CMD_GET_OBJECT_PROPS_SUPPORTED:
if (c->argv[0] != FMT_UNDEFINED_OBJECT &&
c->argv[0] != FMT_ASSOCIATION) {
usb_mtp_queue_result(s, RES_INVALID_OBJECT_FORMAT_CODE,
c->trans, 0, 0, 0);
return;
}
data_in = usb_mtp_get_object_props_supported(s, c);
break;
case CMD_GET_OBJECT_PROP_DESC:
if (c->argv[1] != FMT_UNDEFINED_OBJECT &&
c->argv[1] != FMT_ASSOCIATION) {
usb_mtp_queue_result(s, RES_INVALID_OBJECT_FORMAT_CODE,
c->trans, 0, 0, 0);
return;
}
data_in = usb_mtp_get_object_prop_desc(s, c);
if (data_in == NULL) {
usb_mtp_queue_result(s, RES_INVALID_OBJECT_PROP_CODE,
c->trans, 0, 0, 0);
return;
}
break;
case CMD_GET_OBJECT_PROP_VALUE:
o = usb_mtp_object_lookup(s, c->argv[0]);
if (o == NULL) {
usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
c->trans, 0, 0, 0);
return;
}
data_in = usb_mtp_get_object_prop_value(s, c, o);
if (data_in == NULL) {
usb_mtp_queue_result(s, RES_INVALID_OBJECT_PROP_CODE,
c->trans, 0, 0, 0);
return;
}
break;
default: default:
trace_usb_mtp_op_unknown(s->dev.addr, c->code); trace_usb_mtp_op_unknown(s->dev.addr, c->code);
usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED, usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED,
...@@ -1193,10 +1375,15 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p) ...@@ -1193,10 +1375,15 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
} }
if (s->data_in != NULL) { if (s->data_in != NULL) {
MTPData *d = s->data_in; MTPData *d = s->data_in;
int dlen = d->length - d->offset; uint64_t dlen = d->length - d->offset;
if (d->first) { if (d->first) {
trace_usb_mtp_data_in(s->dev.addr, d->trans, d->length); trace_usb_mtp_data_in(s->dev.addr, d->trans, d->length);
container.length = cpu_to_le32(d->length + sizeof(container)); if (d->length + sizeof(container) > 0xFFFFFFFF) {
container.length = cpu_to_le32(0xFFFFFFFF);
} else {
container.length =
cpu_to_le32(d->length + sizeof(container));
}
container.type = cpu_to_le16(TYPE_DATA); container.type = cpu_to_le16(TYPE_DATA);
container.code = cpu_to_le16(d->code); container.code = cpu_to_le16(d->code);
container.trans = cpu_to_le32(d->trans); container.trans = cpu_to_le32(d->trans);
......
...@@ -1753,6 +1753,12 @@ static void xhci_xfer_report(XHCITransfer *xfer) ...@@ -1753,6 +1753,12 @@ static void xhci_xfer_report(XHCITransfer *xfer)
unsigned int chunk = 0; unsigned int chunk = 0;
switch (TRB_TYPE(*trb)) { switch (TRB_TYPE(*trb)) {
case TR_SETUP:
chunk = trb->status & 0x1ffff;
if (chunk > 8) {
chunk = 8;
}
break;
case TR_DATA: case TR_DATA:
case TR_NORMAL: case TR_NORMAL:
case TR_ISOCH: case TR_ISOCH:
...@@ -3709,8 +3715,7 @@ static void usb_xhci_exit(PCIDevice *dev) ...@@ -3709,8 +3715,7 @@ static void usb_xhci_exit(PCIDevice *dev)
/* destroy msix memory region */ /* destroy msix memory region */
if (dev->msix_table && dev->msix_pba if (dev->msix_table && dev->msix_pba
&& dev->msix_entry_used) { && dev->msix_entry_used) {
memory_region_del_subregion(&xhci->mem, &dev->msix_table_mmio); msix_uninit(dev, &xhci->mem, &xhci->mem);
memory_region_del_subregion(&xhci->mem, &dev->msix_pba_mmio);
} }
usb_bus_release(&xhci->bus); usb_bus_release(&xhci->bus);
......
...@@ -743,10 +743,13 @@ static void usb_host_speed_compat(USBHostDevice *s) ...@@ -743,10 +743,13 @@ static void usb_host_speed_compat(USBHostDevice *s)
rc = libusb_get_ss_endpoint_companion_descriptor rc = libusb_get_ss_endpoint_companion_descriptor
(ctx, endp, &endp_ss_comp); (ctx, endp, &endp_ss_comp);
if (rc == LIBUSB_SUCCESS) { if (rc == LIBUSB_SUCCESS) {
int streams = endp_ss_comp->bmAttributes & 0x1f;
if (streams) {
compat_full = false;
compat_high = false;
}
libusb_free_ss_endpoint_companion_descriptor libusb_free_ss_endpoint_companion_descriptor
(endp_ss_comp); (endp_ss_comp);
compat_full = false;
compat_high = false;
} }
#endif #endif
break; break;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册