scsi: Document intentional fall through in scsi_req_length()
[qemu/armbru.git] / hw / usb / dev-mtp.c
blob8b44032900f756caf35f7846b1f37087fc1f087c
1 /*
2 * Media Transfer Protocol implementation, backed by host filesystem.
4 * Copyright Red Hat, Inc 2014
6 * Author:
7 * Gerd Hoffmann <kraxel@redhat.com>
9 * This code is licensed under the GPL v2 or later.
12 #include <wchar.h>
13 #include <dirent.h>
14 #include <unistd.h>
16 #include <sys/stat.h>
17 #include <sys/statvfs.h>
19 #include "qemu-common.h"
20 #include "qemu/iov.h"
21 #include "trace.h"
22 #include "hw/usb.h"
23 #include "hw/usb/desc.h"
25 /* ----------------------------------------------------------------------- */
27 enum mtp_container_type {
28 TYPE_COMMAND = 1,
29 TYPE_DATA = 2,
30 TYPE_RESPONSE = 3,
31 TYPE_EVENT = 4,
34 enum mtp_code {
35 /* command codes */
36 CMD_GET_DEVICE_INFO = 0x1001,
37 CMD_OPEN_SESSION = 0x1002,
38 CMD_CLOSE_SESSION = 0x1003,
39 CMD_GET_STORAGE_IDS = 0x1004,
40 CMD_GET_STORAGE_INFO = 0x1005,
41 CMD_GET_NUM_OBJECTS = 0x1006,
42 CMD_GET_OBJECT_HANDLES = 0x1007,
43 CMD_GET_OBJECT_INFO = 0x1008,
44 CMD_GET_OBJECT = 0x1009,
45 CMD_GET_PARTIAL_OBJECT = 0x101b,
47 /* response codes */
48 RES_OK = 0x2001,
49 RES_SESSION_NOT_OPEN = 0x2003,
50 RES_INVALID_TRANSACTION_ID = 0x2004,
51 RES_OPERATION_NOT_SUPPORTED = 0x2005,
52 RES_PARAMETER_NOT_SUPPORTED = 0x2006,
53 RES_INVALID_STORAGE_ID = 0x2008,
54 RES_INVALID_OBJECT_HANDLE = 0x2009,
55 RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014,
56 RES_INVALID_PARENT_OBJECT = 0x201a,
57 RES_INVALID_PARAMETER = 0x201d,
58 RES_SESSION_ALREADY_OPEN = 0x201e,
60 /* format codes */
61 FMT_UNDEFINED_OBJECT = 0x3000,
62 FMT_ASSOCIATION = 0x3001,
65 typedef struct {
66 uint32_t length;
67 uint16_t type;
68 uint16_t code;
69 uint32_t trans;
70 } QEMU_PACKED mtp_container;
72 /* ----------------------------------------------------------------------- */
74 typedef struct MTPState MTPState;
75 typedef struct MTPControl MTPControl;
76 typedef struct MTPData MTPData;
77 typedef struct MTPObject MTPObject;
79 enum {
80 EP_DATA_IN = 1,
81 EP_DATA_OUT,
82 EP_EVENT,
85 struct MTPControl {
86 uint16_t code;
87 uint32_t trans;
88 int argc;
89 uint32_t argv[5];
92 struct MTPData {
93 uint16_t code;
94 uint32_t trans;
95 uint32_t offset;
96 uint32_t length;
97 uint32_t alloc;
98 uint8_t *data;
99 bool first;
100 int fd;
103 struct MTPObject {
104 uint32_t handle;
105 uint16_t format;
106 char *name;
107 char *path;
108 struct stat stat;
109 MTPObject *parent;
110 MTPObject **children;
111 int32_t nchildren;
112 QTAILQ_ENTRY(MTPObject) next;
115 struct MTPState {
116 USBDevice dev;
117 char *root;
118 char *desc;
119 uint32_t flags;
121 MTPData *data_in;
122 MTPData *data_out;
123 MTPControl *result;
124 uint32_t session;
125 uint32_t next_handle;
127 QTAILQ_HEAD(, MTPObject) objects;
130 #define QEMU_STORAGE_ID 0x00010001
132 #define MTP_FLAG_WRITABLE 0
134 #define FLAG_SET(_mtp, _flag) ((_mtp)->flags & (1 << (_flag)))
136 /* ----------------------------------------------------------------------- */
138 #define MTP_MANUFACTURER "QEMU"
139 #define MTP_PRODUCT "QEMU filesharing"
141 enum {
142 STR_MANUFACTURER = 1,
143 STR_PRODUCT,
144 STR_SERIALNUMBER,
145 STR_CONFIG_FULL,
146 STR_CONFIG_HIGH,
147 STR_CONFIG_SUPER,
150 static const USBDescStrings desc_strings = {
151 [STR_MANUFACTURER] = MTP_MANUFACTURER,
152 [STR_PRODUCT] = MTP_PRODUCT,
153 [STR_SERIALNUMBER] = "34617",
154 [STR_CONFIG_FULL] = "Full speed config (usb 1.1)",
155 [STR_CONFIG_HIGH] = "High speed config (usb 2.0)",
156 [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)",
159 static const USBDescIface desc_iface_full = {
160 .bInterfaceNumber = 0,
161 .bNumEndpoints = 3,
162 .bInterfaceClass = USB_CLASS_STILL_IMAGE,
163 .bInterfaceSubClass = 0x01,
164 .bInterfaceProtocol = 0x01,
165 .eps = (USBDescEndpoint[]) {
167 .bEndpointAddress = USB_DIR_IN | EP_DATA_IN,
168 .bmAttributes = USB_ENDPOINT_XFER_BULK,
169 .wMaxPacketSize = 64,
171 .bEndpointAddress = USB_DIR_OUT | EP_DATA_OUT,
172 .bmAttributes = USB_ENDPOINT_XFER_BULK,
173 .wMaxPacketSize = 64,
175 .bEndpointAddress = USB_DIR_IN | EP_EVENT,
176 .bmAttributes = USB_ENDPOINT_XFER_INT,
177 .wMaxPacketSize = 8,
178 .bInterval = 0x0a,
183 static const USBDescDevice desc_device_full = {
184 .bcdUSB = 0x0200,
185 .bMaxPacketSize0 = 8,
186 .bNumConfigurations = 1,
187 .confs = (USBDescConfig[]) {
189 .bNumInterfaces = 1,
190 .bConfigurationValue = 1,
191 .iConfiguration = STR_CONFIG_FULL,
192 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
193 .bMaxPower = 2,
194 .nif = 1,
195 .ifs = &desc_iface_full,
200 static const USBDescIface desc_iface_high = {
201 .bInterfaceNumber = 0,
202 .bNumEndpoints = 3,
203 .bInterfaceClass = USB_CLASS_STILL_IMAGE,
204 .bInterfaceSubClass = 0x01,
205 .bInterfaceProtocol = 0x01,
206 .eps = (USBDescEndpoint[]) {
208 .bEndpointAddress = USB_DIR_IN | EP_DATA_IN,
209 .bmAttributes = USB_ENDPOINT_XFER_BULK,
210 .wMaxPacketSize = 512,
212 .bEndpointAddress = USB_DIR_OUT | EP_DATA_OUT,
213 .bmAttributes = USB_ENDPOINT_XFER_BULK,
214 .wMaxPacketSize = 512,
216 .bEndpointAddress = USB_DIR_IN | EP_EVENT,
217 .bmAttributes = USB_ENDPOINT_XFER_INT,
218 .wMaxPacketSize = 8,
219 .bInterval = 0x0a,
224 static const USBDescDevice desc_device_high = {
225 .bcdUSB = 0x0200,
226 .bMaxPacketSize0 = 64,
227 .bNumConfigurations = 1,
228 .confs = (USBDescConfig[]) {
230 .bNumInterfaces = 1,
231 .bConfigurationValue = 1,
232 .iConfiguration = STR_CONFIG_HIGH,
233 .bmAttributes = USB_CFG_ATT_ONE | USB_CFG_ATT_WAKEUP,
234 .bMaxPower = 2,
235 .nif = 1,
236 .ifs = &desc_iface_high,
241 static const USBDescMSOS desc_msos = {
242 .CompatibleID = "MTP",
243 .SelectiveSuspendEnabled = true,
246 static const USBDesc desc = {
247 .id = {
248 .idVendor = 0x46f4, /* CRC16() of "QEMU" */
249 .idProduct = 0x0004,
250 .bcdDevice = 0,
251 .iManufacturer = STR_MANUFACTURER,
252 .iProduct = STR_PRODUCT,
253 .iSerialNumber = STR_SERIALNUMBER,
255 .full = &desc_device_full,
256 .high = &desc_device_high,
257 .str = desc_strings,
258 .msos = &desc_msos,
261 /* ----------------------------------------------------------------------- */
263 static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
264 MTPObject *parent, char *name)
266 MTPObject *o = g_new0(MTPObject, 1);
268 if (name[0] == '.') {
269 goto ignore;
272 o->handle = handle;
273 o->parent = parent;
274 o->name = g_strdup(name);
275 o->nchildren = -1;
276 if (parent == NULL) {
277 o->path = g_strdup(name);
278 } else {
279 o->path = g_strdup_printf("%s/%s", parent->path, name);
282 if (lstat(o->path, &o->stat) != 0) {
283 goto ignore;
285 if (S_ISREG(o->stat.st_mode)) {
286 o->format = FMT_UNDEFINED_OBJECT;
287 } else if (S_ISDIR(o->stat.st_mode)) {
288 o->format = FMT_ASSOCIATION;
289 } else {
290 goto ignore;
293 if (access(o->path, R_OK) != 0) {
294 goto ignore;
297 fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path);
299 QTAILQ_INSERT_TAIL(&s->objects, o, next);
300 return o;
302 ignore:
303 g_free(o->name);
304 g_free(o->path);
305 g_free(o);
306 return NULL;
309 static void usb_mtp_object_free(MTPState *s, MTPObject *o)
311 int i;
313 fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path);
315 QTAILQ_REMOVE(&s->objects, o, next);
316 for (i = 0; i < o->nchildren; i++) {
317 usb_mtp_object_free(s, o->children[i]);
319 g_free(o->children);
320 g_free(o->name);
321 g_free(o->path);
322 g_free(o);
325 static MTPObject *usb_mtp_object_lookup(MTPState *s, uint32_t handle)
327 MTPObject *o;
329 QTAILQ_FOREACH(o, &s->objects, next) {
330 if (o->handle == handle) {
331 return o;
334 return NULL;
337 static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
339 struct dirent *entry;
340 DIR *dir;
342 o->nchildren = 0;
343 dir = opendir(o->path);
344 if (!dir) {
345 return;
347 while ((entry = readdir(dir)) != NULL) {
348 if ((o->nchildren % 32) == 0) {
349 o->children = g_realloc(o->children,
350 (o->nchildren + 32) * sizeof(MTPObject *));
352 o->children[o->nchildren] =
353 usb_mtp_object_alloc(s, s->next_handle++, o, entry->d_name);
354 if (o->children[o->nchildren] != NULL) {
355 o->nchildren++;
358 closedir(dir);
361 /* ----------------------------------------------------------------------- */
363 static MTPData *usb_mtp_data_alloc(MTPControl *c)
365 MTPData *data = g_new0(MTPData, 1);
367 data->code = c->code;
368 data->trans = c->trans;
369 data->fd = -1;
370 data->first = true;
371 return data;
374 static void usb_mtp_data_free(MTPData *data)
376 if (data == NULL) {
377 return;
379 if (data->fd != -1) {
380 close(data->fd);
382 g_free(data->data);
383 g_free(data);
386 static void usb_mtp_realloc(MTPData *data, uint32_t bytes)
388 if (data->length + bytes <= data->alloc) {
389 return;
391 data->alloc = (data->length + bytes + 0xff) & ~0xff;
392 data->data = g_realloc(data->data, data->alloc);
395 static void usb_mtp_add_u8(MTPData *data, uint8_t val)
397 usb_mtp_realloc(data, 1);
398 data->data[data->length++] = val;
401 static void usb_mtp_add_u16(MTPData *data, uint16_t val)
403 usb_mtp_realloc(data, 2);
404 data->data[data->length++] = (val >> 0) & 0xff;
405 data->data[data->length++] = (val >> 8) & 0xff;
408 static void usb_mtp_add_u32(MTPData *data, uint32_t val)
410 usb_mtp_realloc(data, 4);
411 data->data[data->length++] = (val >> 0) & 0xff;
412 data->data[data->length++] = (val >> 8) & 0xff;
413 data->data[data->length++] = (val >> 16) & 0xff;
414 data->data[data->length++] = (val >> 24) & 0xff;
417 static void usb_mtp_add_u64(MTPData *data, uint64_t val)
419 usb_mtp_realloc(data, 4);
420 data->data[data->length++] = (val >> 0) & 0xff;
421 data->data[data->length++] = (val >> 8) & 0xff;
422 data->data[data->length++] = (val >> 16) & 0xff;
423 data->data[data->length++] = (val >> 24) & 0xff;
424 data->data[data->length++] = (val >> 32) & 0xff;
425 data->data[data->length++] = (val >> 40) & 0xff;
426 data->data[data->length++] = (val >> 48) & 0xff;
427 data->data[data->length++] = (val >> 54) & 0xff;
430 static void usb_mtp_add_u16_array(MTPData *data, uint32_t len,
431 const uint16_t *vals)
433 int i;
435 usb_mtp_add_u32(data, len);
436 for (i = 0; i < len; i++) {
437 usb_mtp_add_u16(data, vals[i]);
441 static void usb_mtp_add_u32_array(MTPData *data, uint32_t len,
442 const uint32_t *vals)
444 int i;
446 usb_mtp_add_u32(data, len);
447 for (i = 0; i < len; i++) {
448 usb_mtp_add_u32(data, vals[i]);
452 static void usb_mtp_add_wstr(MTPData *data, const wchar_t *str)
454 uint32_t len = wcslen(str);
455 int i;
457 if (len > 0) {
458 len++; /* include terminating L'\0' */
461 usb_mtp_add_u8(data, len);
462 for (i = 0; i < len; i++) {
463 usb_mtp_add_u16(data, str[i]);
467 static void usb_mtp_add_str(MTPData *data, const char *str)
469 uint32_t len = strlen(str)+1;
470 wchar_t wstr[len];
471 size_t ret;
473 ret = mbstowcs(wstr, str, len);
474 if (ret == -1) {
475 usb_mtp_add_wstr(data, L"Oops");
476 } else {
477 usb_mtp_add_wstr(data, wstr);
481 static void usb_mtp_add_time(MTPData *data, time_t time)
483 char buf[16];
484 struct tm tm;
486 gmtime_r(&time, &tm);
487 strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", &tm);
488 usb_mtp_add_str(data, buf);
491 /* ----------------------------------------------------------------------- */
493 static void usb_mtp_queue_result(MTPState *s, uint16_t code, uint32_t trans,
494 int argc, uint32_t arg0, uint32_t arg1)
496 MTPControl *c = g_new0(MTPControl, 1);
498 c->code = code;
499 c->trans = trans;
500 c->argc = argc;
501 if (argc > 0) {
502 c->argv[0] = arg0;
504 if (argc > 1) {
505 c->argv[1] = arg1;
508 assert(s->result == NULL);
509 s->result = c;
512 /* ----------------------------------------------------------------------- */
514 static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c)
516 static const uint16_t ops[] = {
517 CMD_GET_DEVICE_INFO,
518 CMD_OPEN_SESSION,
519 CMD_CLOSE_SESSION,
520 CMD_GET_STORAGE_IDS,
521 CMD_GET_STORAGE_INFO,
522 CMD_GET_NUM_OBJECTS,
523 CMD_GET_OBJECT_HANDLES,
524 CMD_GET_OBJECT_INFO,
525 CMD_GET_OBJECT,
526 CMD_GET_PARTIAL_OBJECT,
528 static const uint16_t fmt[] = {
529 FMT_UNDEFINED_OBJECT,
530 FMT_ASSOCIATION,
532 MTPData *d = usb_mtp_data_alloc(c);
534 trace_usb_mtp_op_get_device_info(s->dev.addr);
536 usb_mtp_add_u16(d, 0x0100);
537 usb_mtp_add_u32(d, 0xffffffff);
538 usb_mtp_add_u16(d, 0x0101);
539 usb_mtp_add_wstr(d, L"");
540 usb_mtp_add_u16(d, 0x0000);
542 usb_mtp_add_u16_array(d, ARRAY_SIZE(ops), ops);
543 usb_mtp_add_u16_array(d, 0, NULL);
544 usb_mtp_add_u16_array(d, 0, NULL);
545 usb_mtp_add_u16_array(d, 0, NULL);
546 usb_mtp_add_u16_array(d, ARRAY_SIZE(fmt), fmt);
548 usb_mtp_add_wstr(d, L"" MTP_MANUFACTURER);
549 usb_mtp_add_wstr(d, L"" MTP_PRODUCT);
550 usb_mtp_add_wstr(d, L"0.1");
551 usb_mtp_add_wstr(d, L"123456789abcdef123456789abcdef");
553 return d;
556 static MTPData *usb_mtp_get_storage_ids(MTPState *s, MTPControl *c)
558 static const uint32_t ids[] = {
559 QEMU_STORAGE_ID,
561 MTPData *d = usb_mtp_data_alloc(c);
563 trace_usb_mtp_op_get_storage_ids(s->dev.addr);
565 usb_mtp_add_u32_array(d, ARRAY_SIZE(ids), ids);
567 return d;
570 static MTPData *usb_mtp_get_storage_info(MTPState *s, MTPControl *c)
572 MTPData *d = usb_mtp_data_alloc(c);
573 struct statvfs buf;
574 int rc;
576 trace_usb_mtp_op_get_storage_info(s->dev.addr);
578 if (FLAG_SET(s, MTP_FLAG_WRITABLE)) {
579 usb_mtp_add_u16(d, 0x0003);
580 usb_mtp_add_u16(d, 0x0002);
581 usb_mtp_add_u16(d, 0x0000);
582 } else {
583 usb_mtp_add_u16(d, 0x0001);
584 usb_mtp_add_u16(d, 0x0002);
585 usb_mtp_add_u16(d, 0x0001);
588 rc = statvfs(s->root, &buf);
589 if (rc == 0) {
590 usb_mtp_add_u64(d, (uint64_t)buf.f_frsize * buf.f_blocks);
591 usb_mtp_add_u64(d, (uint64_t)buf.f_bavail * buf.f_blocks);
592 usb_mtp_add_u32(d, buf.f_ffree);
593 } else {
594 usb_mtp_add_u64(d, 0xffffffff);
595 usb_mtp_add_u64(d, 0xffffffff);
596 usb_mtp_add_u32(d, 0xffffffff);
599 usb_mtp_add_str(d, s->desc);
600 usb_mtp_add_wstr(d, L"123456789abcdef");
601 return d;
604 static MTPData *usb_mtp_get_object_handles(MTPState *s, MTPControl *c,
605 MTPObject *o)
607 MTPData *d = usb_mtp_data_alloc(c);
608 uint32_t i, handles[o->nchildren];
610 trace_usb_mtp_op_get_object_handles(s->dev.addr, o->handle, o->path);
612 for (i = 0; i < o->nchildren; i++) {
613 handles[i] = o->children[i]->handle;
615 usb_mtp_add_u32_array(d, o->nchildren, handles);
617 return d;
620 static MTPData *usb_mtp_get_object_info(MTPState *s, MTPControl *c,
621 MTPObject *o)
623 MTPData *d = usb_mtp_data_alloc(c);
625 trace_usb_mtp_op_get_object_info(s->dev.addr, o->handle, o->path);
627 usb_mtp_add_u32(d, QEMU_STORAGE_ID);
628 usb_mtp_add_u16(d, o->format);
629 usb_mtp_add_u16(d, 0);
630 usb_mtp_add_u32(d, o->stat.st_size);
632 usb_mtp_add_u16(d, 0);
633 usb_mtp_add_u32(d, 0);
634 usb_mtp_add_u32(d, 0);
635 usb_mtp_add_u32(d, 0);
636 usb_mtp_add_u32(d, 0);
637 usb_mtp_add_u32(d, 0);
638 usb_mtp_add_u32(d, 0);
640 if (o->parent) {
641 usb_mtp_add_u32(d, o->parent->handle);
642 } else {
643 usb_mtp_add_u32(d, 0);
645 if (o->format == FMT_ASSOCIATION) {
646 usb_mtp_add_u16(d, 0x0001);
647 usb_mtp_add_u32(d, 0x00000001);
648 usb_mtp_add_u32(d, 0);
649 } else {
650 usb_mtp_add_u16(d, 0);
651 usb_mtp_add_u32(d, 0);
652 usb_mtp_add_u32(d, 0);
655 usb_mtp_add_str(d, o->name);
656 usb_mtp_add_time(d, o->stat.st_ctime);
657 usb_mtp_add_time(d, o->stat.st_mtime);
658 usb_mtp_add_wstr(d, L"");
660 return d;
663 static MTPData *usb_mtp_get_object(MTPState *s, MTPControl *c,
664 MTPObject *o)
666 MTPData *d = usb_mtp_data_alloc(c);
668 trace_usb_mtp_op_get_object(s->dev.addr, o->handle, o->path);
670 d->fd = open(o->path, O_RDONLY);
671 if (d->fd == -1) {
672 return NULL;
674 d->length = o->stat.st_size;
675 d->alloc = 512;
676 d->data = g_malloc(d->alloc);
677 return d;
680 static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
681 MTPObject *o)
683 MTPData *d = usb_mtp_data_alloc(c);
684 off_t offset;
686 trace_usb_mtp_op_get_partial_object(s->dev.addr, o->handle, o->path,
687 c->argv[1], c->argv[2]);
689 d->fd = open(o->path, O_RDONLY);
690 if (d->fd == -1) {
691 return NULL;
694 offset = c->argv[1];
695 if (offset > o->stat.st_size) {
696 offset = o->stat.st_size;
698 lseek(d->fd, offset, SEEK_SET);
700 d->length = c->argv[2];
701 if (d->length > o->stat.st_size - offset) {
702 d->length = o->stat.st_size - offset;
705 return d;
708 static void usb_mtp_command(MTPState *s, MTPControl *c)
710 MTPData *data_in = NULL;
711 MTPObject *o;
712 uint32_t nres = 0, res0 = 0;
714 /* sanity checks */
715 if (c->code >= CMD_CLOSE_SESSION && s->session == 0) {
716 usb_mtp_queue_result(s, RES_SESSION_NOT_OPEN,
717 c->trans, 0, 0, 0);
718 return;
721 /* process commands */
722 switch (c->code) {
723 case CMD_GET_DEVICE_INFO:
724 data_in = usb_mtp_get_device_info(s, c);
725 break;
726 case CMD_OPEN_SESSION:
727 if (s->session) {
728 usb_mtp_queue_result(s, RES_SESSION_ALREADY_OPEN,
729 c->trans, 1, s->session, 0);
730 return;
732 if (c->argv[0] == 0) {
733 usb_mtp_queue_result(s, RES_INVALID_PARAMETER,
734 c->trans, 0, 0, 0);
735 return;
737 trace_usb_mtp_op_open_session(s->dev.addr);
738 s->session = c->argv[0];
739 usb_mtp_object_alloc(s, s->next_handle++, NULL, s->root);
740 break;
741 case CMD_CLOSE_SESSION:
742 trace_usb_mtp_op_close_session(s->dev.addr);
743 s->session = 0;
744 s->next_handle = 0;
745 usb_mtp_object_free(s, QTAILQ_FIRST(&s->objects));
746 assert(QTAILQ_EMPTY(&s->objects));
747 break;
748 case CMD_GET_STORAGE_IDS:
749 data_in = usb_mtp_get_storage_ids(s, c);
750 break;
751 case CMD_GET_STORAGE_INFO:
752 if (c->argv[0] != QEMU_STORAGE_ID &&
753 c->argv[0] != 0xffffffff) {
754 usb_mtp_queue_result(s, RES_INVALID_STORAGE_ID,
755 c->trans, 0, 0, 0);
756 return;
758 data_in = usb_mtp_get_storage_info(s, c);
759 break;
760 case CMD_GET_NUM_OBJECTS:
761 case CMD_GET_OBJECT_HANDLES:
762 if (c->argv[0] != QEMU_STORAGE_ID &&
763 c->argv[0] != 0xffffffff) {
764 usb_mtp_queue_result(s, RES_INVALID_STORAGE_ID,
765 c->trans, 0, 0, 0);
766 return;
768 if (c->argv[1] != 0x00000000) {
769 usb_mtp_queue_result(s, RES_SPEC_BY_FORMAT_UNSUPPORTED,
770 c->trans, 0, 0, 0);
771 return;
773 if (c->argv[2] == 0x00000000 ||
774 c->argv[2] == 0xffffffff) {
775 o = QTAILQ_FIRST(&s->objects);
776 } else {
777 o = usb_mtp_object_lookup(s, c->argv[2]);
779 if (o == NULL) {
780 usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
781 c->trans, 0, 0, 0);
782 return;
784 if (o->format != FMT_ASSOCIATION) {
785 usb_mtp_queue_result(s, RES_INVALID_PARENT_OBJECT,
786 c->trans, 0, 0, 0);
787 return;
789 if (o->nchildren == -1) {
790 usb_mtp_object_readdir(s, o);
792 if (c->code == CMD_GET_NUM_OBJECTS) {
793 trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path);
794 nres = 1;
795 res0 = o->nchildren;
796 } else {
797 data_in = usb_mtp_get_object_handles(s, c, o);
799 break;
800 case CMD_GET_OBJECT_INFO:
801 o = usb_mtp_object_lookup(s, c->argv[0]);
802 if (o == NULL) {
803 usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
804 c->trans, 0, 0, 0);
805 return;
807 data_in = usb_mtp_get_object_info(s, c, o);
808 break;
809 case CMD_GET_OBJECT:
810 o = usb_mtp_object_lookup(s, c->argv[0]);
811 if (o == NULL) {
812 usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
813 c->trans, 0, 0, 0);
814 return;
816 if (o->format == FMT_ASSOCIATION) {
817 usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
818 c->trans, 0, 0, 0);
819 return;
821 data_in = usb_mtp_get_object(s, c, o);
822 if (NULL == data_in) {
823 fprintf(stderr, "%s: TODO: handle error\n", __func__);
825 break;
826 case CMD_GET_PARTIAL_OBJECT:
827 o = usb_mtp_object_lookup(s, c->argv[0]);
828 if (o == NULL) {
829 usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
830 c->trans, 0, 0, 0);
831 return;
833 if (o->format == FMT_ASSOCIATION) {
834 usb_mtp_queue_result(s, RES_INVALID_OBJECT_HANDLE,
835 c->trans, 0, 0, 0);
836 return;
838 data_in = usb_mtp_get_partial_object(s, c, o);
839 if (NULL == data_in) {
840 fprintf(stderr, "%s: TODO: handle error\n", __func__);
842 nres = 1;
843 res0 = data_in->length;
844 break;
845 default:
846 fprintf(stderr, "%s: unknown command code 0x%04x\n",
847 __func__, c->code);
848 usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED,
849 c->trans, 0, 0, 0);
850 return;
853 /* return results on success */
854 if (data_in) {
855 assert(s->data_in == NULL);
856 s->data_in = data_in;
858 usb_mtp_queue_result(s, RES_OK, c->trans, nres, res0, 0);
861 /* ----------------------------------------------------------------------- */
863 static void usb_mtp_handle_reset(USBDevice *dev)
865 MTPState *s = DO_UPCAST(MTPState, dev, dev);
867 trace_usb_mtp_reset(s->dev.addr);
869 s->session = 0;
870 usb_mtp_data_free(s->data_in);
871 s->data_in = NULL;
872 usb_mtp_data_free(s->data_out);
873 s->data_out = NULL;
874 g_free(s->result);
875 s->result = NULL;
878 static void usb_mtp_handle_control(USBDevice *dev, USBPacket *p,
879 int request, int value, int index,
880 int length, uint8_t *data)
882 int ret;
884 ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
885 if (ret >= 0) {
886 return;
889 trace_usb_mtp_stall(dev->addr, "unknown control request");
890 p->status = USB_RET_STALL;
893 static void usb_mtp_cancel_packet(USBDevice *dev, USBPacket *p)
895 fprintf(stderr, "%s\n", __func__);
898 static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
900 MTPState *s = DO_UPCAST(MTPState, dev, dev);
901 MTPControl cmd;
902 mtp_container container;
903 uint32_t params[5];
904 int i, rc;
906 switch (p->ep->nr) {
907 case EP_DATA_IN:
908 if (s->data_out != NULL) {
909 /* guest bug */
910 trace_usb_mtp_stall(s->dev.addr, "awaiting data-out");
911 p->status = USB_RET_STALL;
912 return;
914 if (p->iov.size < sizeof(container)) {
915 trace_usb_mtp_stall(s->dev.addr, "packet too small");
916 p->status = USB_RET_STALL;
917 return;
919 if (s->data_in != NULL) {
920 MTPData *d = s->data_in;
921 int dlen = d->length - d->offset;
922 if (d->first) {
923 trace_usb_mtp_data_in(s->dev.addr, d->trans, d->length);
924 container.length = cpu_to_le32(d->length + sizeof(container));
925 container.type = cpu_to_le16(TYPE_DATA);
926 container.code = cpu_to_le16(d->code);
927 container.trans = cpu_to_le32(d->trans);
928 usb_packet_copy(p, &container, sizeof(container));
929 d->first = false;
930 if (dlen > p->iov.size - sizeof(container)) {
931 dlen = p->iov.size - sizeof(container);
933 } else {
934 if (dlen > p->iov.size) {
935 dlen = p->iov.size;
938 if (d->fd == -1) {
939 usb_packet_copy(p, d->data + d->offset, dlen);
940 } else {
941 if (d->alloc < p->iov.size) {
942 d->alloc = p->iov.size;
943 d->data = g_realloc(d->data, d->alloc);
945 rc = read(d->fd, d->data, dlen);
946 if (rc != dlen) {
947 fprintf(stderr, "%s: TODO: handle read error\n", __func__);
949 usb_packet_copy(p, d->data, dlen);
951 d->offset += dlen;
952 if (d->offset == d->length) {
953 usb_mtp_data_free(s->data_in);
954 s->data_in = NULL;
956 } else if (s->result != NULL) {
957 MTPControl *r = s->result;
958 int length = sizeof(container) + r->argc * sizeof(uint32_t);
959 if (r->code == RES_OK) {
960 trace_usb_mtp_success(s->dev.addr, r->trans,
961 (r->argc > 0) ? r->argv[0] : 0,
962 (r->argc > 1) ? r->argv[1] : 0);
963 } else {
964 trace_usb_mtp_error(s->dev.addr, r->code, r->trans,
965 (r->argc > 0) ? r->argv[0] : 0,
966 (r->argc > 1) ? r->argv[1] : 0);
968 container.length = cpu_to_le32(length);
969 container.type = cpu_to_le16(TYPE_RESPONSE);
970 container.code = cpu_to_le16(r->code);
971 container.trans = cpu_to_le32(r->trans);
972 for (i = 0; i < r->argc; i++) {
973 params[i] = cpu_to_le32(r->argv[i]);
975 usb_packet_copy(p, &container, sizeof(container));
976 usb_packet_copy(p, &params, length - sizeof(container));
977 g_free(s->result);
978 s->result = NULL;
980 break;
981 case EP_DATA_OUT:
982 if (p->iov.size < sizeof(container)) {
983 trace_usb_mtp_stall(s->dev.addr, "packet too small");
984 p->status = USB_RET_STALL;
985 return;
987 usb_packet_copy(p, &container, sizeof(container));
988 switch (le16_to_cpu(container.type)) {
989 case TYPE_COMMAND:
990 if (s->data_in || s->data_out || s->result) {
991 trace_usb_mtp_stall(s->dev.addr, "transaction inflight");
992 p->status = USB_RET_STALL;
993 return;
995 cmd.code = le16_to_cpu(container.code);
996 cmd.argc = (le32_to_cpu(container.length) - sizeof(container))
997 / sizeof(uint32_t);
998 cmd.trans = le32_to_cpu(container.trans);
999 usb_packet_copy(p, &params, cmd.argc * sizeof(uint32_t));
1000 for (i = 0; i < cmd.argc; i++) {
1001 cmd.argv[i] = le32_to_cpu(params[i]);
1003 trace_usb_mtp_command(s->dev.addr, cmd.code, cmd.trans,
1004 (cmd.argc > 0) ? cmd.argv[0] : 0,
1005 (cmd.argc > 1) ? cmd.argv[1] : 0,
1006 (cmd.argc > 2) ? cmd.argv[2] : 0,
1007 (cmd.argc > 3) ? cmd.argv[3] : 0,
1008 (cmd.argc > 4) ? cmd.argv[4] : 0);
1009 usb_mtp_command(s, &cmd);
1010 break;
1011 default:
1012 iov_hexdump(p->iov.iov, p->iov.niov, stderr, "mtp-out", 32);
1013 trace_usb_mtp_stall(s->dev.addr, "TODO: implement data-out");
1014 p->status = USB_RET_STALL;
1015 return;
1017 break;
1018 case EP_EVENT:
1019 p->status = USB_RET_NAK;
1020 return;
1021 default:
1022 trace_usb_mtp_stall(s->dev.addr, "invalid endpoint");
1023 p->status = USB_RET_STALL;
1024 return;
1027 if (p->actual_length == 0) {
1028 trace_usb_mtp_nak(s->dev.addr, p->ep->nr);
1029 p->status = USB_RET_NAK;
1030 return;
1031 } else {
1032 trace_usb_mtp_xfer(s->dev.addr, p->ep->nr, p->actual_length,
1033 p->iov.size);
1034 return;
1038 static int usb_mtp_initfn(USBDevice *dev)
1040 MTPState *s = DO_UPCAST(MTPState, dev, dev);
1042 usb_desc_create_serial(dev);
1043 usb_desc_init(dev);
1044 QTAILQ_INIT(&s->objects);
1045 if (s->desc == NULL) {
1046 s->desc = strrchr(s->root, '/');
1047 if (s->desc) {
1048 s->desc = g_strdup(s->desc + 1);
1049 } else {
1050 s->desc = g_strdup("none");
1053 return 0;
1056 static const VMStateDescription vmstate_usb_mtp = {
1057 .name = "usb-mtp",
1058 .unmigratable = 1,
1059 .version_id = 1,
1060 .minimum_version_id = 1,
1061 .fields = (VMStateField[]) {
1062 VMSTATE_USB_DEVICE(dev, MTPState),
1063 VMSTATE_END_OF_LIST()
1067 static Property mtp_properties[] = {
1068 DEFINE_PROP_STRING("root", MTPState, root),
1069 DEFINE_PROP_STRING("desc", MTPState, desc),
1070 DEFINE_PROP_END_OF_LIST(),
1073 static void usb_mtp_class_initfn(ObjectClass *klass, void *data)
1075 DeviceClass *dc = DEVICE_CLASS(klass);
1076 USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
1078 uc->init = usb_mtp_initfn;
1079 uc->product_desc = "QEMU USB MTP";
1080 uc->usb_desc = &desc;
1081 uc->cancel_packet = usb_mtp_cancel_packet;
1082 uc->handle_attach = usb_desc_attach;
1083 uc->handle_reset = usb_mtp_handle_reset;
1084 uc->handle_control = usb_mtp_handle_control;
1085 uc->handle_data = usb_mtp_handle_data;
1086 dc->fw_name = "mtp";
1087 dc->vmsd = &vmstate_usb_mtp;
1088 dc->props = mtp_properties;
1091 static TypeInfo mtp_info = {
1092 .name = "usb-mtp",
1093 .parent = TYPE_USB_DEVICE,
1094 .instance_size = sizeof(MTPState),
1095 .class_init = usb_mtp_class_initfn,
1098 static void usb_mtp_register_types(void)
1100 type_register_static(&mtp_info);
1103 type_init(usb_mtp_register_types)