summary refs log tree commit diff stats
path: root/hw/usb/dev-mtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/usb/dev-mtp.c')
-rw-r--r--hw/usb/dev-mtp.c35
1 files changed, 23 insertions, 12 deletions
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 8b44032900..943f930404 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -50,6 +50,7 @@ enum mtp_code {
     RES_INVALID_TRANSACTION_ID     = 0x2004,
     RES_OPERATION_NOT_SUPPORTED    = 0x2005,
     RES_PARAMETER_NOT_SUPPORTED    = 0x2006,
+    RES_INCOMPLETE_TRANSFER        = 0x2007,
     RES_INVALID_STORAGE_ID         = 0x2008,
     RES_INVALID_OBJECT_HANDLE      = 0x2009,
     RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014,
@@ -294,7 +295,7 @@ static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
         goto ignore;
     }
 
-    fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path);
+    trace_usb_mtp_object_alloc(s->dev.addr, o->handle, o->path);
 
     QTAILQ_INSERT_TAIL(&s->objects, o, next);
     return o;
@@ -310,7 +311,7 @@ static void usb_mtp_object_free(MTPState *s, MTPObject *o)
 {
     int i;
 
-    fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path);
+    trace_usb_mtp_object_free(s->dev.addr, o->handle, o->path);
 
     QTAILQ_REMOVE(&s->objects, o, next);
     for (i = 0; i < o->nchildren; i++) {
@@ -416,7 +417,7 @@ static void usb_mtp_add_u32(MTPData *data, uint32_t val)
 
 static void usb_mtp_add_u64(MTPData *data, uint64_t val)
 {
-    usb_mtp_realloc(data, 4);
+    usb_mtp_realloc(data, 8);
     data->data[data->length++] = (val >>  0) & 0xff;
     data->data[data->length++] = (val >>  8) & 0xff;
     data->data[data->length++] = (val >> 16) & 0xff;
@@ -424,7 +425,7 @@ static void usb_mtp_add_u64(MTPData *data, uint64_t val)
     data->data[data->length++] = (val >> 32) & 0xff;
     data->data[data->length++] = (val >> 40) & 0xff;
     data->data[data->length++] = (val >> 48) & 0xff;
-    data->data[data->length++] = (val >> 54) & 0xff;
+    data->data[data->length++] = (val >> 56) & 0xff;
 }
 
 static void usb_mtp_add_u16_array(MTPData *data, uint32_t len,
@@ -533,7 +534,7 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c)
 
     trace_usb_mtp_op_get_device_info(s->dev.addr);
 
-    usb_mtp_add_u16(d, 0x0100);
+    usb_mtp_add_u16(d, 100);
     usb_mtp_add_u32(d, 0xffffffff);
     usb_mtp_add_u16(d, 0x0101);
     usb_mtp_add_wstr(d, L"");
@@ -548,7 +549,7 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c)
     usb_mtp_add_wstr(d, L"" MTP_MANUFACTURER);
     usb_mtp_add_wstr(d, L"" MTP_PRODUCT);
     usb_mtp_add_wstr(d, L"0.1");
-    usb_mtp_add_wstr(d, L"123456789abcdef123456789abcdef");
+    usb_mtp_add_wstr(d, L"0123456789abcdef0123456789abcdef");
 
     return d;
 }
@@ -669,6 +670,7 @@ static MTPData *usb_mtp_get_object(MTPState *s, MTPControl *c,
 
     d->fd = open(o->path, O_RDONLY);
     if (d->fd == -1) {
+        usb_mtp_data_free(d);
         return NULL;
     }
     d->length = o->stat.st_size;
@@ -688,6 +690,7 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
 
     d->fd = open(o->path, O_RDONLY);
     if (d->fd == -1) {
+        usb_mtp_data_free(d);
         return NULL;
     }
 
@@ -843,8 +846,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
         res0 = data_in->length;
         break;
     default:
-        fprintf(stderr, "%s: unknown command code 0x%04x\n",
-                __func__, c->code);
+        trace_usb_mtp_op_unknown(s->dev.addr, c->code);
         usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED,
                              c->trans, 0, 0, 0);
         return;
@@ -892,6 +894,7 @@ static void usb_mtp_handle_control(USBDevice *dev, USBPacket *p,
 
 static void usb_mtp_cancel_packet(USBDevice *dev, USBPacket *p)
 {
+    /* we don't use async packets, so this should never be called */
     fprintf(stderr, "%s\n", __func__);
 }
 
@@ -944,7 +947,8 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
                 }
                 rc = read(d->fd, d->data, dlen);
                 if (rc != dlen) {
-                    fprintf(stderr, "%s: TODO: handle read error\n", __func__);
+                    memset(d->data, 0, dlen);
+                    s->result->code = RES_INCOMPLETE_TRANSFER;
                 }
                 usb_packet_copy(p, d->data, dlen);
             }
@@ -996,6 +1000,14 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
             cmd.argc = (le32_to_cpu(container.length) - sizeof(container))
                 / sizeof(uint32_t);
             cmd.trans = le32_to_cpu(container.trans);
+            if (cmd.argc > ARRAY_SIZE(cmd.argv)) {
+                cmd.argc = ARRAY_SIZE(cmd.argv);
+            }
+            if (p->iov.size < sizeof(container) + cmd.argc * sizeof(uint32_t)) {
+                trace_usb_mtp_stall(s->dev.addr, "packet too small");
+                p->status = USB_RET_STALL;
+                return;
+            }
             usb_packet_copy(p, &params, cmd.argc * sizeof(uint32_t));
             for (i = 0; i < cmd.argc; i++) {
                 cmd.argv[i] = le32_to_cpu(params[i]);
@@ -1009,8 +1021,7 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
             usb_mtp_command(s, &cmd);
             break;
         default:
-            iov_hexdump(p->iov.iov, p->iov.niov, stderr, "mtp-out", 32);
-            trace_usb_mtp_stall(s->dev.addr, "TODO: implement data-out");
+            /* not needed as long as the mtp device is read-only */
             p->status = USB_RET_STALL;
             return;
         }
@@ -1044,7 +1055,7 @@ static int usb_mtp_initfn(USBDevice *dev)
     QTAILQ_INIT(&s->objects);
     if (s->desc == NULL) {
         s->desc = strrchr(s->root, '/');
-        if (s->desc) {
+        if (s->desc && s->desc[0]) {
             s->desc = g_strdup(s->desc + 1);
         } else {
             s->desc = g_strdup("none");