MtpDevice.cpp revision f41ef0ee0da4c497352df42d09c3d89940c25e14
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            {
7123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                LOGD("Found camera: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device),
7223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        usb_device_get_product_name(device));
7323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            } else if (interface->bInterfaceClass == 0xFF &&
7423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    interface->bInterfaceSubClass == 0xFF &&
7523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    interface->bInterfaceProtocol == 0) {
7623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                char* interfaceName = usb_device_get_string(device, interface->iInterface);
7723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!interfaceName || strcmp(interfaceName, "MTP"))
7823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    continue;
7923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // Looks like an android style MTP device
8023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                LOGD("Found MTP device: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device),
8123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        usb_device_get_product_name(device));
8223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            } else {
8323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // look for special cased devices based on vendor/product ID
8423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // we are doing this mainly for testing purposes
8523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                uint16_t vendor = usb_device_get_vendor_id(device);
8623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                uint16_t product = usb_device_get_product_id(device);
8723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!isMtpDevice(vendor, product)) {
8823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    // not an MTP or PTP device
8923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    continue;
9023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
9123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // request MTP OS string and descriptor
9223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // some music players need to see this before entering MTP mode.
9323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                char buffer[256];
9423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                memset(buffer, 0, sizeof(buffer));
95f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                int ret = usb_device_control_transfer(device,
9623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD,
9723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE,
98f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                        0, buffer, sizeof(buffer), 0);
99f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                printf("usb_device_control_transfer returned %d errno: %d\n", ret, errno);
10023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (ret > 0) {
10123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("got MTP string %s\n", buffer);
102f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                    ret = usb_device_control_transfer(device,
10323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                            USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1,
104f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                            0, 4, buffer, sizeof(buffer), 0);
10523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("OS descriptor got %d\n", ret);
10623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
10723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("no MTP string\n");
10823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
10923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
11023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
11123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // if we got here, then we have a likely MTP or PTP device
11223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
11323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // interface should be followed by three endpoints
11423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep;
11523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_in_desc = NULL;
11623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_out_desc = NULL;
11723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_intr_desc = NULL;
11823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            for (int i = 0; i < 3; i++) {
11923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
12023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
12123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    LOGE("endpoints not found\n");
12223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    return NULL;
12323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
12423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
12523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
12623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_in_desc = ep;
12723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    else
12823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_out_desc = ep;
12923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT &&
13023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
13123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    ep_intr_desc = ep;
13223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
13323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
13423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
13523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                LOGE("endpoints not found\n");
13623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                return NULL;
13723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
13823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
13923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
14023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                LOGE("usb_device_claim_interface failed errno: %d\n", errno);
14123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                return NULL;
14223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
14323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
14423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber,
14523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_in_desc, ep_out_desc, ep_intr_desc);
14623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            mtpDevice->initialize();
14723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            return mtpDevice;
14823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
14923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
15023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
15123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    usb_device_close(device);
15223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    LOGE("device not found");
15323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return NULL;
15423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
15523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
1565ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::MtpDevice(struct usb_device* device, int interface,
15742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_in,
15842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_out,
15942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_intr)
1605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    :   mDevice(device),
1615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mInterface(interface),
16242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn1(NULL),
16342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn2(NULL),
16442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestOut(NULL),
16542d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIntr(NULL),
1665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDeviceInfo(NULL),
1675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mSessionID(0),
168f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mTransactionID(0),
169f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mReceivedResponse(false)
1705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood{
17142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIn1 = usb_request_new(device, ep_in);
17242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIn2 = usb_request_new(device, ep_in);
17342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestOut = usb_request_new(device, ep_out);
17442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIntr = usb_request_new(device, ep_intr);
1755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1775ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::~MtpDevice() {
1785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    close();
179a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    for (int i = 0; i < mDeviceProperties.size(); i++)
180a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        delete mDeviceProperties[i];
18142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIn1);
18242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIn2);
18342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestOut);
18442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIntr);
1855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::initialize() {
1885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    openSession();
1895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mDeviceInfo = getDeviceInfo();
1905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDeviceInfo) {
191a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        if (mDeviceInfo->mDeviceProperties) {
192a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
193a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            for (int i = 0; i < count; i++) {
194a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
195a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
1960c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property)
197a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                    mDeviceProperties.push(property);
198a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            }
199a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        }
2005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::close() {
2045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice) {
2055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_release_interface(mDevice, mInterface);
2065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_close(mDevice);
2075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDevice = NULL;
2085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2110c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwoodvoid MtpDevice::print() {
2120c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo) {
2130c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        mDeviceInfo->print();
2140c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2150c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        if (mDeviceInfo->mDeviceProperties) {
2160c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("***** DEVICE PROPERTIES *****\n");
2170c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
2180c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            for (int i = 0; i < count; i++) {
2190c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
2200c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
2210c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property) {
2220c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    property->print();
2230c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
2240c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
2250c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
2260c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
2270c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2280c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo->mPlaybackFormats) {
2290c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("***** OBJECT PROPERTIES *****\n");
2300c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        int count = mDeviceInfo->mPlaybackFormats->size();
2310c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        for (int i = 0; i < count; i++) {
2320c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i];
2330c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format));
2340c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectPropertyList* props = getObjectPropsSupported(format);
2350c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            if (props) {
2360c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                for (int j = 0; j < props->size(); j++) {
2370c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    MtpObjectProperty prop = (*props)[j];
23899e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood                    MtpProperty* property = getObjectPropDesc(prop, format);
2390c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    if (property)
2400c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                        property->print();
2410c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    else
2420c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                        LOGE("could not fetch property: %s",
2430c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                                MtpDebug::getObjectPropCodeName(prop));
2440c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
2450c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
2460c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
2470c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
2480c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood}
2490c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodconst char* MtpDevice::getDeviceName() {
2515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice)
2525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return usb_device_get_name(mDevice);
2535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else
2545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return "???";
2555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::openSession() {
2580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = 0;
2615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 0;
2625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpSessionID newSession = 1;
2635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
2645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, newSession);
2655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
2665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
2675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
2695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        newSession = mResponse.getParameter(1);
2705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else if (ret != MTP_RESPONSE_OK)
2715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
2725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = newSession;
2745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 1;
2755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
2765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::closeSession() {
2795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    // FIXME
2805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
2815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2835ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDeviceInfo* MtpDevice::getDeviceInfo() {
2840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2850cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
2875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
2885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
2905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
2935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpDeviceInfo* info = new MtpDeviceInfo;
2945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
2955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
2965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
2985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3005ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageIDList* MtpDevice::getStorageIDs() {
3010cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
3055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
3115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3155ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
3160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3170cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
3205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
3215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpStorageInfo* info = new MtpStorageInfo(storageID);
3275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
3285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
3295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3335ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
3345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            MtpObjectFormat format, MtpObjectHandle parent) {
3350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
3395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(2, format);
3405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(3, parent);
3415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
3425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
3485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3525ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
3530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3556afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    // FIXME - we might want to add some caching here
3566afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
3575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, handle);
3595ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
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        MtpObjectInfo* info = new MtpObjectInfo(handle);
3665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
3675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
3685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3723e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwoodvoid* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
3730cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3753e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.reset();
3763e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.setParameter(1, handle);
3773e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
3783e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        MtpResponseCode ret = readResponse();
3793e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
3803e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood            return mData.getData(outLength);
3813e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        }
3823e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    }
3833e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    outLength = 0;
3843e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    return NULL;
3856afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
3866afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
3870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike LockwoodMtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
3880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3890cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3900cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
3910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpObjectHandle parent = info->mParent;
3920cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (parent == 0)
3930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        parent = MTP_PARENT_ROOT;
3940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3950cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mStorageID);
3960cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(2, info->mParent);
3970cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3980cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mStorageID);
3990cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mFormat);
4000cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mProtectionStatus);
4010cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mCompressedSize);
4020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mThumbFormat);
4030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbCompressedSize);
4040cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixWidth);
4050cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixHeight);
4060cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixWidth);
4070cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixHeight);
4080cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixDepth);
4090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mParent);
4100cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mAssociationType);
4110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mAssociationDesc);
4120cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mSequenceNumber);
4130cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(info->mName);
4140cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4150cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    char created[100], modified[100];
4160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateCreated, created, sizeof(created));
4170cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateModified, modified, sizeof(modified));
4180cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4190cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(created);
4200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(modified);
4210cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (info->mKeywords)
4220cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putString(info->mKeywords);
4230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    else
4240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putEmptyString();
4250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood   if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
4270cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        MtpResponseCode ret = readResponse();
4280cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
4290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mStorageID = mResponse.getParameter(1);
4300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mParent = mResponse.getParameter(2);
4310cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mHandle = mResponse.getParameter(3);
4320cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            return info->mHandle;
4330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
4350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (MtpObjectHandle)-1;
4360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
4370cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4380cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
4390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    int remaining = info->mCompressedSize;
4420cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
4430cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mHandle);
4440cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
4450cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        // send data header
4460cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
4470cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        char buffer[65536];
4490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        while (remaining > 0) {
4500cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            int count = read(srcFD, buffer, sizeof(buffer));
4510cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            if (count > 0) {
45242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                int written = mData.write(mRequestOut, buffer, count);
4530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                // FIXME check error
4540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                remaining -= count;
4550cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
4560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                break;
4570cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
4580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
4600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpResponseCode ret = readResponse();
4610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (remaining == 0 && ret == MTP_RESPONSE_OK);
4620cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
4630cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4646afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwoodbool MtpDevice::deleteObject(MtpObjectHandle handle) {
4650cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4660cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4676afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.reset();
4686afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.setParameter(1, handle);
4696afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
4706afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        MtpResponseCode ret = readResponse();
4716afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        if (ret == MTP_RESPONSE_OK)
4726afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood            return true;
4736afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    }
4746afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    return false;
4756afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
4766afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
4776afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
4786afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
4796afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (info)
4806afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return info->mParent;
4816afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    else
4826afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
4836afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
4843e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
4856afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
4866afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
4876afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (info)
4886afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return info->mStorageID;
4896afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    else
4906afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
4913e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood}
4923e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
49398693f674125484de8873d969c209276a6dd604bMike LockwoodMtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
49498693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
49598693f674125484de8873d969c209276a6dd604bMike Lockwood
49698693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
49798693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, format);
49898693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED))
49998693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
50098693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
50198693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
50298693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
50398693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
50498693f674125484de8873d969c209276a6dd604bMike Lockwood        return mData.getAUInt16();
50598693f674125484de8873d969c209276a6dd604bMike Lockwood    }
50698693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
50798693f674125484de8873d969c209276a6dd604bMike Lockwood
50898693f674125484de8873d969c209276a6dd604bMike Lockwood}
50998693f674125484de8873d969c209276a6dd604bMike Lockwood
510a6c490b8b2d96ebaab632286029463f932ae3b6bMike LockwoodMtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
5110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
5120cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
513a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.reset();
514a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.setParameter(1, code);
515a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
516a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
517a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!readData())
518a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
519a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    MtpResponseCode ret = readResponse();
520a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
521a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        MtpProperty* property = new MtpProperty;
522e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        property->read(mData);
523a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return property;
524a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    }
525a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    return NULL;
526a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood}
527a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
52899e393a39a31bfbdeb435462939519e2d0279433Mike LockwoodMtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
52998693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
53098693f674125484de8873d969c209276a6dd604bMike Lockwood
53198693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
53298693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, code);
53399e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood    mRequest.setParameter(2, format);
53498693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC))
53598693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
53698693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
53798693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
53898693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
53998693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
54098693f674125484de8873d969c209276a6dd604bMike Lockwood        MtpProperty* property = new MtpProperty;
54198693f674125484de8873d969c209276a6dd604bMike Lockwood        property->read(mData);
54298693f674125484de8873d969c209276a6dd604bMike Lockwood        return property;
54398693f674125484de8873d969c209276a6dd604bMike Lockwood    }
54498693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
54598693f674125484de8873d969c209276a6dd604bMike Lockwood}
54698693f674125484de8873d969c209276a6dd604bMike Lockwood
54723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle,
54823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        bool (* callback)(void* data, int offset, int length, void* clientData),
54923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int objectSize, void* clientData) {
55023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    Mutex::Autolock autoLock(mMutex);
55123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    bool result = false;
55223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
55323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    mRequest.reset();
55423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    mRequest.setParameter(1, handle);
55523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
55623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            && mData.readDataHeader(mRequestIn1)) {
55723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        uint32_t length = mData.getContainerLength();
55823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) {
55923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            LOGE("readObject error objectSize: %d, length: %d",
56023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    objectSize, length);
56123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            goto fail;
56223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
56323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
56423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        uint32_t remaining = length;
56523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int offset = 0;
56623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
56723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int initialDataLength = 0;
56823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        void* initialData = mData.getData(initialDataLength);
56923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (initialData) {
57023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (initialDataLength > 0) {
57123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!callback(initialData, 0, initialDataLength, clientData))
57223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
57323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                remaining -= initialDataLength;
57423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                offset += initialDataLength;
57523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
57623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            free(initialData);
57723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
57823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
57923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        // USB reads greater than 16K don't work
58023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        char buffer1[16384], buffer2[16384];
58123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        mRequestIn1->buffer = buffer1;
58223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        mRequestIn2->buffer = buffer2;
58323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        struct usb_request* req = mRequestIn1;
58423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        void* writeBuffer = NULL;
58523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int writeLength = 0;
58623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
58723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        while (remaining > 0 || writeBuffer) {
58823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (remaining > 0) {
58923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // queue up a read request
59023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
59123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (mData.readDataAsync(req)) {
59223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    LOGE("readDataAsync failed");
59323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
59423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
59523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            } else {
59623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                req = NULL;
59723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
59823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
59923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (writeBuffer) {
60023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // write previous buffer
60123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!callback(writeBuffer, offset, writeLength, clientData)) {
60223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    LOGE("write failed");
60323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    // wait for pending read before failing
60423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    if (req)
60523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        mData.readDataWait(mDevice);
60623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
60723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
60823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                offset += writeLength;
60923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                writeBuffer = NULL;
61023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
61123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
61223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // wait for read to complete
61323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (req) {
61423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                int read = mData.readDataWait(mDevice);
61523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read < 0)
61623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
61723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
61823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read > 0) {
61923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = req->buffer;
62023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeLength = read;
62123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    remaining -= read;
62223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
62323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
62423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = NULL;
62523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
62623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
62723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
62823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
62923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        MtpResponseCode response = readResponse();
63023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (response == MTP_RESPONSE_OK)
63123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            result = true;
63223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
63323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
63423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodfail:
63523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return result;
63623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
63723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
63823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
639b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood// reads the object's data and writes it to the specified file path
64027afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
641b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    LOGD("readObject: %s", destPath);
642b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC);
643b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (fd < 0) {
644b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        LOGE("open failed for %s", destPath);
645b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        return false;
6460cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
6470cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
64827afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchown(fd, getuid(), group);
64927afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    // set permissions
65027afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    int mask = umask(0);
65127afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchmod(fd, perm);
65227afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    umask(mask);
65327afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood
654b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    Mutex::Autolock autoLock(mMutex);
655b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    bool result = false;
6560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
657b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.reset();
658b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.setParameter(1, handle);
659b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
66042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            && mData.readDataHeader(mRequestIn1)) {
661b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t length = mData.getContainerLength();
662b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (length < MTP_CONTAINER_HEADER_SIZE)
663b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            goto fail;
664b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
665b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t remaining = length;
666b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
667b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int initialDataLength = 0;
668b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        void* initialData = mData.getData(initialDataLength);
669b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (initialData) {
670b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (initialDataLength > 0) {
671b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, initialData, initialDataLength) != initialDataLength)
672b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
673b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                remaining -= initialDataLength;
6740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
675b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            free(initialData);
6760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
6770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
678b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        // USB reads greater than 16K don't work
679b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char buffer1[16384], buffer2[16384];
68042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn1->buffer = buffer1;
68142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn2->buffer = buffer2;
68242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        struct usb_request* req = mRequestIn1;
68342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        void* writeBuffer = NULL;
684b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int writeLength = 0;
685b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
686b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        while (remaining > 0 || writeBuffer) {
687b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (remaining > 0) {
688b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // queue up a read request
68942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
69042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                if (mData.readDataAsync(req)) {
691b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    LOGE("readDataAsync failed");
692b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
693b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
6940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
69542d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                req = NULL;
6960cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
6970cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
698b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (writeBuffer) {
699b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // write previous buffer
700b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, writeBuffer, writeLength) != writeLength) {
701b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    LOGE("write failed");
702b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    // wait for pending read before failing
70342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                    if (req)
70442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                        mData.readDataWait(mDevice);
705b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
706b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
707b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeBuffer = NULL;
708b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
7090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
710b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            // wait for read to complete
71142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            if (req) {
71242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                int read = mData.readDataWait(mDevice);
713b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (read < 0)
714b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
7150cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
71623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read > 0) {
71723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = req->buffer;
71823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeLength = read;
71923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    remaining -= read;
72023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
72123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
72223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = NULL;
72323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
724b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
725b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        }
726b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
727b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        MtpResponseCode response = readResponse();
728b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (response == MTP_RESPONSE_OK)
729b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            result = true;
7300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
731b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
732b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwoodfail:
733b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    ::close(fd);
734b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    return result;
7350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
736a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
7375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::sendRequest(MtpOperationCode operation) {
738f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
739f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    mReceivedResponse = false;
7405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setOperationCode(operation);
7415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mTransactionID > 0)
7425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mRequest.setTransactionID(mTransactionID++);
74342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mRequest.write(mRequestOut);
7445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.dump();
7455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
7465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
7475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
7480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendData() {
749f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("sendData\n");
7505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
7515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
75242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mData.write(mRequestOut);
7535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.dump();
7545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
7555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
7565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
7575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::readData() {
7585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.reset();
75942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mData.read(mRequestIn1);
760f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("readData returned %d\n", ret);
7615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
762f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
763f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            LOGD("got response packet instead of data packet");
764f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // we got a response packet rather than data
765f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // copy it to mResponse
766f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mResponse.copyFrom(mData);
767f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mReceivedResponse = true;
768f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            return false;
769f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        }
7705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mData.dump();
7715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return true;
7725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
7735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else {
774f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood        LOGV("readResponse failed\n");
7755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
7765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
7775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
7785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
7790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
7800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setOperationCode(operation);
7810cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
78242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    return (!mData.writeDataHeader(mRequestOut, dataLength));
7830cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
7840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
7855ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpResponseCode MtpDevice::readResponse() {
786f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("readResponse\n");
787f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    if (mReceivedResponse) {
788f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mReceivedResponse = false;
789f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        return mResponse.getResponseCode();
790f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    }
79142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mResponse.read(mRequestIn1);
7925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
7935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mResponse.dump();
7945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mResponse.getResponseCode();
795f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    } else {
796a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        LOGD("readResponse failed\n");
7975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return -1;
7985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
7995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
8005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
8015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}  // namespace android
802