MtpDevice.cpp revision 31c52e7c8c01e1db6ff9bcf66135c72544b1235a
15ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood/*
25ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * Copyright (C) 2010 The Android Open Source Project
35ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood *
45ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
55ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * you may not use this file except in compliance with the License.
65ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * You may obtain a copy of the License at
75ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood *
85ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
95ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood *
105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * Unless required by applicable law or agreed to in writing, software
115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * See the License for the specific language governing permissions and
145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood * limitations under the License.
155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood */
165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
17a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood#define LOG_TAG "MtpDevice"
18b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood
19b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpDebug.h"
20b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpDevice.h"
21b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpDeviceInfo.h"
22b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpObjectInfo.h"
23b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpProperty.h"
24b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpStorageInfo.h"
25b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpStringBuffer.h"
260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood#include "MtpUtils.h"
27a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <stdio.h>
295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <stdlib.h>
305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <sys/types.h>
315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <sys/ioctl.h>
325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <sys/stat.h>
335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <fcntl.h>
345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <errno.h>
350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood#include <endian.h>
365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <usbhost/usbhost.h>
385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodnamespace android {
405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
4123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodstatic bool isMtpDevice(uint16_t vendor, uint16_t product) {
4223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    // Sandisk Sansa Fuze
4323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (vendor == 0x0781 && product == 0x74c2)
4423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        return true;
4523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    // Samsung YP-Z5
4623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (vendor == 0x04e8 && product == 0x503c)
4723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        return true;
4823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return false;
4923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
5023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
5123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike LockwoodMtpDevice* MtpDevice::open(const char* deviceName, int fd) {
5223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    struct usb_device *device = usb_device_new(deviceName, fd);
5323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (!device) {
5423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        LOGE("usb_device_new failed for %s", deviceName);
5523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        return NULL;
5623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
5723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
5823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    struct usb_descriptor_header* desc;
5923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    struct usb_descriptor_iter iter;
6023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
6123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    usb_descriptor_iter_init(device, &iter);
6223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
6323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
6423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (desc->bDescriptorType == USB_DT_INTERFACE) {
6523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
6623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
6723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE &&
6823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                interface->bInterfaceSubClass == 1 && // Still Image Capture
6923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                interface->bInterfaceProtocol == 1)     // Picture Transfer Protocol (PIMA 15470)
7023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            {
7131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* manufacturerName = usb_device_get_manufacturer_name(device);
7231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* productName = usb_device_get_product_name(device);
7331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                LOGD("Found camera: \"%s\" \"%s\"\n", manufacturerName, productName);
7431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(manufacturerName);
7531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(productName);
7623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            } else if (interface->bInterfaceClass == 0xFF &&
7723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    interface->bInterfaceSubClass == 0xFF &&
7823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    interface->bInterfaceProtocol == 0) {
7923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                char* interfaceName = usb_device_get_string(device, interface->iInterface);
8031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                if (!interfaceName) {
8123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    continue;
8231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                } else if (strcmp(interfaceName, "MTP")) {
8331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    free(interfaceName);
8431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    continue;
8531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                }
8631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(interfaceName);
8731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root
8823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // Looks like an android style MTP device
8931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* manufacturerName = usb_device_get_manufacturer_name(device);
9031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* productName = usb_device_get_product_name(device);
9131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                LOGD("Found MTP device: \"%s\" \"%s\"\n", manufacturerName, productName);
9231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(manufacturerName);
9331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(productName);
9423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            } else {
9523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // look for special cased devices based on vendor/product ID
9623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // we are doing this mainly for testing purposes
9723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                uint16_t vendor = usb_device_get_vendor_id(device);
9823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                uint16_t product = usb_device_get_product_id(device);
9923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!isMtpDevice(vendor, product)) {
10023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    // not an MTP or PTP device
10123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    continue;
10223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
10323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // request MTP OS string and descriptor
10423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // some music players need to see this before entering MTP mode.
10523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                char buffer[256];
10623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                memset(buffer, 0, sizeof(buffer));
107f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                int ret = usb_device_control_transfer(device,
10823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD,
10923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE,
110f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                        0, buffer, sizeof(buffer), 0);
111f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                printf("usb_device_control_transfer returned %d errno: %d\n", ret, errno);
11223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (ret > 0) {
11323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("got MTP string %s\n", buffer);
114f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                    ret = usb_device_control_transfer(device,
11523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                            USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1,
116f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                            0, 4, buffer, sizeof(buffer), 0);
11723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("OS descriptor got %d\n", ret);
11823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
11923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("no MTP string\n");
12023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
12123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
12223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
12323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // if we got here, then we have a likely MTP or PTP device
12423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
12523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // interface should be followed by three endpoints
12623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep;
12723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_in_desc = NULL;
12823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_out_desc = NULL;
12923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_intr_desc = NULL;
13023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            for (int i = 0; i < 3; i++) {
13123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
13223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
13323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    LOGE("endpoints not found\n");
13431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    usb_device_close(device);
13523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    return NULL;
13623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
13723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
13823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
13923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_in_desc = ep;
14023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    else
14123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_out_desc = ep;
14223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT &&
14323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
14423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    ep_intr_desc = ep;
14523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
14623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
14723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
14823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                LOGE("endpoints not found\n");
14931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                usb_device_close(device);
15023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                return NULL;
15123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
15223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
15323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
15423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                LOGE("usb_device_claim_interface failed errno: %d\n", errno);
15531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                usb_device_close(device);
15623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                return NULL;
15723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
15823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
15923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber,
16023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_in_desc, ep_out_desc, ep_intr_desc);
16123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            mtpDevice->initialize();
16223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            return mtpDevice;
16323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
16423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
16523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
16623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    usb_device_close(device);
16723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    LOGE("device not found");
16823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return NULL;
16923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
17023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
1715ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::MtpDevice(struct usb_device* device, int interface,
17242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_in,
17342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_out,
17442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_intr)
1755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    :   mDevice(device),
1765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mInterface(interface),
17742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn1(NULL),
17842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn2(NULL),
17942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestOut(NULL),
18042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIntr(NULL),
1815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDeviceInfo(NULL),
1825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mSessionID(0),
183f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mTransactionID(0),
184f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mReceivedResponse(false)
1855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood{
18642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIn1 = usb_request_new(device, ep_in);
18742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIn2 = usb_request_new(device, ep_in);
18842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestOut = usb_request_new(device, ep_out);
18942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIntr = usb_request_new(device, ep_intr);
1905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1925ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::~MtpDevice() {
1935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    close();
194a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    for (int i = 0; i < mDeviceProperties.size(); i++)
195a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        delete mDeviceProperties[i];
19642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIn1);
19742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIn2);
19842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestOut);
19942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIntr);
2005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::initialize() {
2035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    openSession();
2045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mDeviceInfo = getDeviceInfo();
2055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDeviceInfo) {
206a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        if (mDeviceInfo->mDeviceProperties) {
207a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
208a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            for (int i = 0; i < count; i++) {
209a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
210a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
2110c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property)
212a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                    mDeviceProperties.push(property);
213a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            }
214a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        }
2155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2175ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::close() {
2195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice) {
2205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_release_interface(mDevice, mInterface);
2215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_close(mDevice);
2225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDevice = NULL;
2235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2260c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwoodvoid MtpDevice::print() {
2270c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo) {
2280c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        mDeviceInfo->print();
2290c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2300c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        if (mDeviceInfo->mDeviceProperties) {
2310c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("***** DEVICE PROPERTIES *****\n");
2320c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
2330c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            for (int i = 0; i < count; i++) {
2340c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
2350c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
2360c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property) {
2370c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    property->print();
23831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    delete property;
2390c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
2400c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
2410c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
2420c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
2430c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2440c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo->mPlaybackFormats) {
2450c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("***** OBJECT PROPERTIES *****\n");
2460c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        int count = mDeviceInfo->mPlaybackFormats->size();
2470c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        for (int i = 0; i < count; i++) {
2480c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i];
2490c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format));
2500c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectPropertyList* props = getObjectPropsSupported(format);
2510c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            if (props) {
2520c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                for (int j = 0; j < props->size(); j++) {
2530c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    MtpObjectProperty prop = (*props)[j];
25499e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood                    MtpProperty* property = getObjectPropDesc(prop, format);
25531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    if (property) {
2560c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                        property->print();
25731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                        delete property;
25831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    } else {
2590c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                        LOGE("could not fetch property: %s",
2600c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                                MtpDebug::getObjectPropCodeName(prop));
26131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    }
2620c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
2630c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
2640c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
2650c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
2660c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood}
2670c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodconst char* MtpDevice::getDeviceName() {
2695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice)
2705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return usb_device_get_name(mDevice);
2715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else
2725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return "???";
2735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::openSession() {
2760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = 0;
2795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 0;
2805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpSessionID newSession = 1;
2815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
2825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, newSession);
2835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
2845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
2855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
2875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        newSession = mResponse.getParameter(1);
2885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else if (ret != MTP_RESPONSE_OK)
2895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
2905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = newSession;
2925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 1;
2935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
2945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::closeSession() {
2975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    // FIXME
2985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
2995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3015ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDeviceInfo* MtpDevice::getDeviceInfo() {
3020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
3065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpDeviceInfo* info = new MtpDeviceInfo;
3125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
3135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
3145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3175ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3185ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageIDList* MtpDevice::getStorageIDs() {
3190cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
3235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
3295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3335ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
3340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
3385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
3395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpStorageInfo* info = new MtpStorageInfo(storageID);
3455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
3465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
3475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3515ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
3525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            MtpObjectFormat format, MtpObjectHandle parent) {
3530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
3575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(2, format);
3585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(3, parent);
3595ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
3605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
3665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3705ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
3710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3720cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3736afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    // FIXME - we might want to add some caching here
3746afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
3755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, handle);
3775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
3785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpObjectInfo* info = new MtpObjectInfo(handle);
3845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
3855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
3865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3903e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwoodvoid* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
3910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3920cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3933e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.reset();
3943e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.setParameter(1, handle);
3953e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
3963e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        MtpResponseCode ret = readResponse();
3973e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
3983e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood            return mData.getData(outLength);
3993e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        }
4003e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    }
4013e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    outLength = 0;
4023e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    return NULL;
4036afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
4046afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
4050cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike LockwoodMtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
4060cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4070cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4080cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
4090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpObjectHandle parent = info->mParent;
4100cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (parent == 0)
4110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        parent = MTP_PARENT_ROOT;
4120cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4130cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mStorageID);
4140cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(2, info->mParent);
4150cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mStorageID);
4170cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mFormat);
4180cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mProtectionStatus);
4190cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mCompressedSize);
4200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mThumbFormat);
4210cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbCompressedSize);
4220cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixWidth);
4230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixHeight);
4240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixWidth);
4250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixHeight);
4260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixDepth);
4270cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mParent);
4280cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mAssociationType);
4290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mAssociationDesc);
4300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mSequenceNumber);
4310cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(info->mName);
4320cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    char created[100], modified[100];
4340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateCreated, created, sizeof(created));
4350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateModified, modified, sizeof(modified));
4360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4370cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(created);
4380cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(modified);
4390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (info->mKeywords)
4400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putString(info->mKeywords);
4410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    else
4420cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putEmptyString();
4430cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4440cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood   if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
4450cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        MtpResponseCode ret = readResponse();
4460cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
4470cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mStorageID = mResponse.getParameter(1);
4480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mParent = mResponse.getParameter(2);
4490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mHandle = mResponse.getParameter(3);
4500cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            return info->mHandle;
4510cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4520cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
4530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (MtpObjectHandle)-1;
4540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
4550cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
4570cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    int remaining = info->mCompressedSize;
4600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
4610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mHandle);
4620cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
4630cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        // send data header
4640cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
4650cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4660cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        char buffer[65536];
4670cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        while (remaining > 0) {
4680cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            int count = read(srcFD, buffer, sizeof(buffer));
4690cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            if (count > 0) {
47042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                int written = mData.write(mRequestOut, buffer, count);
4710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                // FIXME check error
4720cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                remaining -= count;
4730cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
4740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                break;
4750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
4760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
4780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpResponseCode ret = readResponse();
4790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (remaining == 0 && ret == MTP_RESPONSE_OK);
4800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
4810cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4826afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwoodbool MtpDevice::deleteObject(MtpObjectHandle handle) {
4830cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4856afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.reset();
4866afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.setParameter(1, handle);
4876afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
4886afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        MtpResponseCode ret = readResponse();
4896afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        if (ret == MTP_RESPONSE_OK)
4906afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood            return true;
4916afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    }
4926afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    return false;
4936afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
4946afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
4956afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
4966afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
49731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    if (info) {
49831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        MtpObjectHandle parent = info->mParent;
49931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        delete info;
50031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        return parent;
50131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    } else {
5026afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
50331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    }
5046afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
5053e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
5066afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
5076afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
50831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    if (info) {
50931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        MtpObjectHandle storageId = info->mStorageID;
51031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        delete info;
51131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        return storageId;
51231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    } else {
5136afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
51431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    }
5153e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood}
5163e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
51798693f674125484de8873d969c209276a6dd604bMike LockwoodMtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
51898693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
51998693f674125484de8873d969c209276a6dd604bMike Lockwood
52098693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
52198693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, format);
52298693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED))
52398693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
52498693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
52598693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
52698693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
52798693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
52898693f674125484de8873d969c209276a6dd604bMike Lockwood        return mData.getAUInt16();
52998693f674125484de8873d969c209276a6dd604bMike Lockwood    }
53098693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
53198693f674125484de8873d969c209276a6dd604bMike Lockwood
53298693f674125484de8873d969c209276a6dd604bMike Lockwood}
53398693f674125484de8873d969c209276a6dd604bMike Lockwood
534a6c490b8b2d96ebaab632286029463f932ae3b6bMike LockwoodMtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
5350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
5360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
537a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.reset();
538a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.setParameter(1, code);
539a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
540a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
541a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!readData())
542a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
543a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    MtpResponseCode ret = readResponse();
544a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
545a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        MtpProperty* property = new MtpProperty;
546e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        property->read(mData);
547a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return property;
548a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    }
549a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    return NULL;
550a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood}
551a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
55299e393a39a31bfbdeb435462939519e2d0279433Mike LockwoodMtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
55398693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
55498693f674125484de8873d969c209276a6dd604bMike Lockwood
55598693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
55698693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, code);
55799e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood    mRequest.setParameter(2, format);
55898693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC))
55998693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
56098693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
56198693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
56298693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
56398693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
56498693f674125484de8873d969c209276a6dd604bMike Lockwood        MtpProperty* property = new MtpProperty;
56598693f674125484de8873d969c209276a6dd604bMike Lockwood        property->read(mData);
56698693f674125484de8873d969c209276a6dd604bMike Lockwood        return property;
56798693f674125484de8873d969c209276a6dd604bMike Lockwood    }
56898693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
56998693f674125484de8873d969c209276a6dd604bMike Lockwood}
57098693f674125484de8873d969c209276a6dd604bMike Lockwood
57123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle,
57223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        bool (* callback)(void* data, int offset, int length, void* clientData),
57323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int objectSize, void* clientData) {
57423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    Mutex::Autolock autoLock(mMutex);
57523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    bool result = false;
57623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
57723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    mRequest.reset();
57823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    mRequest.setParameter(1, handle);
57923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
58023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            && mData.readDataHeader(mRequestIn1)) {
58123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        uint32_t length = mData.getContainerLength();
58223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) {
58323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            LOGE("readObject error objectSize: %d, length: %d",
58423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    objectSize, length);
58523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            goto fail;
58623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
58723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
58823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        uint32_t remaining = length;
58923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int offset = 0;
59023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
59123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int initialDataLength = 0;
59223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        void* initialData = mData.getData(initialDataLength);
59323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (initialData) {
59423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (initialDataLength > 0) {
59523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!callback(initialData, 0, initialDataLength, clientData))
59623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
59723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                remaining -= initialDataLength;
59823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                offset += initialDataLength;
59923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
60023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            free(initialData);
60123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
60223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
60323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        // USB reads greater than 16K don't work
60423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        char buffer1[16384], buffer2[16384];
60523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        mRequestIn1->buffer = buffer1;
60623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        mRequestIn2->buffer = buffer2;
60723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        struct usb_request* req = mRequestIn1;
60823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        void* writeBuffer = NULL;
60923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int writeLength = 0;
61023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
61123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        while (remaining > 0 || writeBuffer) {
61223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (remaining > 0) {
61323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // queue up a read request
61423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
61523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (mData.readDataAsync(req)) {
61623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    LOGE("readDataAsync failed");
61723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
61823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
61923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            } else {
62023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                req = NULL;
62123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
62223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
62323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (writeBuffer) {
62423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // write previous buffer
62523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!callback(writeBuffer, offset, writeLength, clientData)) {
62623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    LOGE("write failed");
62723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    // wait for pending read before failing
62823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    if (req)
62923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        mData.readDataWait(mDevice);
63023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
63123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
63223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                offset += writeLength;
63323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                writeBuffer = NULL;
63423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
63523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
63623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // wait for read to complete
63723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (req) {
63823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                int read = mData.readDataWait(mDevice);
63923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read < 0)
64023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
64123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
64223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read > 0) {
64323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = req->buffer;
64423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeLength = read;
64523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    remaining -= read;
64623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
64723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
64823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = NULL;
64923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
65023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
65123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
65223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
65323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        MtpResponseCode response = readResponse();
65423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (response == MTP_RESPONSE_OK)
65523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            result = true;
65623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
65723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
65823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodfail:
65923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return result;
66023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
66123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
66223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
663b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood// reads the object's data and writes it to the specified file path
66427afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
665b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    LOGD("readObject: %s", destPath);
666b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC);
667b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (fd < 0) {
668b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        LOGE("open failed for %s", destPath);
669b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        return false;
6700cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
6710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
67227afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchown(fd, getuid(), group);
67327afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    // set permissions
67427afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    int mask = umask(0);
67527afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchmod(fd, perm);
67627afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    umask(mask);
67727afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood
678b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    Mutex::Autolock autoLock(mMutex);
679b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    bool result = false;
6800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
681b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.reset();
682b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.setParameter(1, handle);
683b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
68442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            && mData.readDataHeader(mRequestIn1)) {
685b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t length = mData.getContainerLength();
686b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (length < MTP_CONTAINER_HEADER_SIZE)
687b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            goto fail;
688b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
689b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t remaining = length;
690b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
691b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int initialDataLength = 0;
692b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        void* initialData = mData.getData(initialDataLength);
693b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (initialData) {
694b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (initialDataLength > 0) {
69531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                if (write(fd, initialData, initialDataLength) != initialDataLength) {
69631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    free(initialData);
697b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
69831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                }
699b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                remaining -= initialDataLength;
7000cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
701b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            free(initialData);
7020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
7030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
704b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        // USB reads greater than 16K don't work
705b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char buffer1[16384], buffer2[16384];
70642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn1->buffer = buffer1;
70742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn2->buffer = buffer2;
70842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        struct usb_request* req = mRequestIn1;
70942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        void* writeBuffer = NULL;
710b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int writeLength = 0;
711b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
712b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        while (remaining > 0 || writeBuffer) {
713b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (remaining > 0) {
714b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // queue up a read request
71542d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
71642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                if (mData.readDataAsync(req)) {
717b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    LOGE("readDataAsync failed");
718b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
719b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
7200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
72142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                req = NULL;
7220cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
7230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
724b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (writeBuffer) {
725b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // write previous buffer
726b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, writeBuffer, writeLength) != writeLength) {
727b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    LOGE("write failed");
728b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    // wait for pending read before failing
72942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                    if (req)
73042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                        mData.readDataWait(mDevice);
731b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
732b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
733b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeBuffer = NULL;
734b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
7350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
736b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            // wait for read to complete
73742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            if (req) {
73842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                int read = mData.readDataWait(mDevice);
739b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (read < 0)
740b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
7410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
74223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read > 0) {
74323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = req->buffer;
74423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeLength = read;
74523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    remaining -= read;
74623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
74723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
74823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = NULL;
74923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
750b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
751b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        }
752b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
753b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        MtpResponseCode response = readResponse();
754b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (response == MTP_RESPONSE_OK)
755b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            result = true;
7560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
757b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
758b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwoodfail:
759b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    ::close(fd);
760b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    return result;
7610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
762a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
7635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::sendRequest(MtpOperationCode operation) {
764f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
765f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    mReceivedResponse = false;
7665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setOperationCode(operation);
7675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mTransactionID > 0)
7685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mRequest.setTransactionID(mTransactionID++);
76942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mRequest.write(mRequestOut);
7705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.dump();
7715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
7725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
7735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
7740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendData() {
775f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("sendData\n");
7765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
7775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
77842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mData.write(mRequestOut);
7795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.dump();
7805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
7815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
7825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
7835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::readData() {
7845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.reset();
78542d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mData.read(mRequestIn1);
786f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("readData returned %d\n", ret);
7875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
788f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
789f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            LOGD("got response packet instead of data packet");
790f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // we got a response packet rather than data
791f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // copy it to mResponse
792f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mResponse.copyFrom(mData);
793f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mReceivedResponse = true;
794f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            return false;
795f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        }
7965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mData.dump();
7975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return true;
7985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
7995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else {
800f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood        LOGV("readResponse failed\n");
8015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
8025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
8035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
8045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
8050cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
8060cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setOperationCode(operation);
8070cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
80842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    return (!mData.writeDataHeader(mRequestOut, dataLength));
8090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
8100cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
8115ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpResponseCode MtpDevice::readResponse() {
812f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("readResponse\n");
813f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    if (mReceivedResponse) {
814f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mReceivedResponse = false;
815f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        return mResponse.getResponseCode();
816f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    }
81742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mResponse.read(mRequestIn1);
8185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
8195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mResponse.dump();
8205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mResponse.getResponseCode();
821f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    } else {
822a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        LOGD("readResponse failed\n");
8235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return -1;
8245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
8255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
8265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
8275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}  // namespace android
828