MtpDevice.cpp revision f7454622eaac287d20ab43013d7015fe42b894f8
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
415ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::MtpDevice(struct usb_device* device, int interface,
425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            struct usb_endpoint *ep_in, struct usb_endpoint *ep_out,
435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            struct usb_endpoint *ep_intr)
445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    :   mDevice(device),
455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mInterface(interface),
465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mEndpointIn(ep_in),
475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mEndpointOut(ep_out),
485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mEndpointIntr(ep_intr),
495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDeviceInfo(NULL),
505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mID(usb_device_get_unique_id(device)),
515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mSessionID(0),
52f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mTransactionID(0),
53f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mReceivedResponse(false)
545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood{
555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
575ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::~MtpDevice() {
585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    close();
59a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    for (int i = 0; i < mDeviceProperties.size(); i++)
60a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        delete mDeviceProperties[i];
615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::initialize() {
645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    openSession();
655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mDeviceInfo = getDeviceInfo();
665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDeviceInfo) {
67a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        if (mDeviceInfo->mDeviceProperties) {
68a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
69a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            for (int i = 0; i < count; i++) {
70a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
71a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
720c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property)
73a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                    mDeviceProperties.push(property);
74a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            }
75a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        }
765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::close() {
805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice) {
815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_release_interface(mDevice, mInterface);
825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_close(mDevice);
835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDevice = NULL;
845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
870c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwoodvoid MtpDevice::print() {
880c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo) {
890c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        mDeviceInfo->print();
900c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
910c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        if (mDeviceInfo->mDeviceProperties) {
920c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("***** DEVICE PROPERTIES *****\n");
930c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
940c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            for (int i = 0; i < count; i++) {
950c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
960c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
970c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property) {
980c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    property->print();
990c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
1000c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
1010c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
1020c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
1030c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
1040c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo->mPlaybackFormats) {
1050c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("***** OBJECT PROPERTIES *****\n");
1060c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        int count = mDeviceInfo->mPlaybackFormats->size();
1070c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        for (int i = 0; i < count; i++) {
1080c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i];
1090c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format));
1100c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectPropertyList* props = getObjectPropsSupported(format);
1110c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            if (props) {
1120c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                for (int j = 0; j < props->size(); j++) {
1130c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    MtpObjectProperty prop = (*props)[j];
11499e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood                    MtpProperty* property = getObjectPropDesc(prop, format);
1150c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    if (property)
1160c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                        property->print();
1170c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    else
1180c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                        LOGE("could not fetch property: %s",
1190c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                                MtpDebug::getObjectPropCodeName(prop));
1200c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
1210c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
1220c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
1230c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
1240c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood}
1250c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
1265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodconst char* MtpDevice::getDeviceName() {
1275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice)
1285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return usb_device_get_name(mDevice);
1295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else
1305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return "???";
1315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::openSession() {
1340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = 0;
1375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 0;
1385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpSessionID newSession = 1;
1395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, newSession);
1415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
1425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
1435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
1455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        newSession = mResponse.getParameter(1);
1465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else if (ret != MTP_RESPONSE_OK)
1475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
1485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = newSession;
1505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 1;
1515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
1525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::closeSession() {
1555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    // FIXME
1565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
1575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1595ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDeviceInfo* MtpDevice::getDeviceInfo() {
1600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
1645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
1665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
1695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpDeviceInfo* info = new MtpDeviceInfo;
1705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
1715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
1725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
1735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
1745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1765ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageIDList* MtpDevice::getStorageIDs() {
1770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
1815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
1835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
1865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
1875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
1885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
1895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1915ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
1920cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
1965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
1975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
1995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
2025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpStorageInfo* info = new MtpStorageInfo(storageID);
2035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
2045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
2055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
2075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2095ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
2105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            MtpObjectFormat format, MtpObjectHandle parent) {
2110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2120cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
2145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
2155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(2, format);
2165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(3, parent);
2175ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
2185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
2205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
2235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
2245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
2265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2285ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
2290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2316afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    // FIXME - we might want to add some caching here
2326afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
2335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
2345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, handle);
2355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
2365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
2385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
2415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpObjectInfo* info = new MtpObjectInfo(handle);
2425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
2435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
2445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
2465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2483e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwoodvoid* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
2490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2500cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2513e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.reset();
2523e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.setParameter(1, handle);
2533e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
2543e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        MtpResponseCode ret = readResponse();
2553e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
2563e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood            return mData.getData(outLength);
2573e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        }
2583e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    }
2593e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    outLength = 0;
2603e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    return NULL;
2616afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
2626afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
2630cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike LockwoodMtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
2640cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2650cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2660cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
2670cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpObjectHandle parent = info->mParent;
2680cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (parent == 0)
2690cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        parent = MTP_PARENT_ROOT;
2700cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mStorageID);
2720cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(2, info->mParent);
2730cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mStorageID);
2750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mFormat);
2760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mProtectionStatus);
2770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mCompressedSize);
2780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mThumbFormat);
2790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbCompressedSize);
2800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixWidth);
2810cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixHeight);
2820cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixWidth);
2830cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixHeight);
2840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixDepth);
2850cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mParent);
2860cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mAssociationType);
2870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mAssociationDesc);
2880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mSequenceNumber);
2890cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(info->mName);
2900cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    char created[100], modified[100];
2920cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateCreated, created, sizeof(created));
2930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateModified, modified, sizeof(modified));
2940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2950cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(created);
2960cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(modified);
2970cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (info->mKeywords)
2980cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putString(info->mKeywords);
2990cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    else
3000cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putEmptyString();
3010cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood   if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
3030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        MtpResponseCode ret = readResponse();
3040cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
3050cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mStorageID = mResponse.getParameter(1);
3060cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mParent = mResponse.getParameter(2);
3070cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mHandle = mResponse.getParameter(3);
3080cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            return info->mHandle;
3090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
3100cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
3110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (MtpObjectHandle)-1;
3120cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
3130cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3140cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
3150cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3170cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    int remaining = info->mCompressedSize;
3180cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
3190cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mHandle);
3200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
3210cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        // send data header
3220cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
3230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        char buffer[65536];
3250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        while (remaining > 0) {
3260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            int count = read(srcFD, buffer, sizeof(buffer));
3270cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            if (count > 0) {
3280cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                int written = mData.write(mEndpointOut, buffer, count);
3290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                // FIXME check error
3300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                remaining -= count;
3310cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
3320cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                break;
3330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
3340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
3350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
3360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpResponseCode ret = readResponse();
3370cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (remaining == 0 && ret == MTP_RESPONSE_OK);
3380cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
3390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3406afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwoodbool MtpDevice::deleteObject(MtpObjectHandle handle) {
3410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3420cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3436afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.reset();
3446afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.setParameter(1, handle);
3456afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
3466afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        MtpResponseCode ret = readResponse();
3476afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        if (ret == MTP_RESPONSE_OK)
3486afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood            return true;
3496afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    }
3506afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    return false;
3516afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
3526afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
3536afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
3546afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
3556afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (info)
3566afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return info->mParent;
3576afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    else
3586afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
3596afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
3603e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
3616afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
3626afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
3636afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (info)
3646afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return info->mStorageID;
3656afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    else
3666afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
3673e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood}
3683e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
36998693f674125484de8873d969c209276a6dd604bMike LockwoodMtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
37098693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
37198693f674125484de8873d969c209276a6dd604bMike Lockwood
37298693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
37398693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, format);
37498693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED))
37598693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
37698693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
37798693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
37898693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
37998693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
38098693f674125484de8873d969c209276a6dd604bMike Lockwood        return mData.getAUInt16();
38198693f674125484de8873d969c209276a6dd604bMike Lockwood    }
38298693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
38398693f674125484de8873d969c209276a6dd604bMike Lockwood
38498693f674125484de8873d969c209276a6dd604bMike Lockwood}
38598693f674125484de8873d969c209276a6dd604bMike Lockwood
386a6c490b8b2d96ebaab632286029463f932ae3b6bMike LockwoodMtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
3870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
389a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.reset();
390a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.setParameter(1, code);
391a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
392a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
393a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!readData())
394a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
395a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    MtpResponseCode ret = readResponse();
396a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
397a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        MtpProperty* property = new MtpProperty;
398e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        property->read(mData);
399a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return property;
400a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    }
401a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    return NULL;
402a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood}
403a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
40499e393a39a31bfbdeb435462939519e2d0279433Mike LockwoodMtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
40598693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
40698693f674125484de8873d969c209276a6dd604bMike Lockwood
40798693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
40898693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, code);
40999e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood    mRequest.setParameter(2, format);
41098693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC))
41198693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
41298693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
41398693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
41498693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
41598693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
41698693f674125484de8873d969c209276a6dd604bMike Lockwood        MtpProperty* property = new MtpProperty;
41798693f674125484de8873d969c209276a6dd604bMike Lockwood        property->read(mData);
41898693f674125484de8873d969c209276a6dd604bMike Lockwood        return property;
41998693f674125484de8873d969c209276a6dd604bMike Lockwood    }
42098693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
42198693f674125484de8873d969c209276a6dd604bMike Lockwood}
42298693f674125484de8873d969c209276a6dd604bMike Lockwood
423b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood// reads the object's data and writes it to the specified file path
42427afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
425b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    LOGD("readObject: %s", destPath);
426b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC);
427b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (fd < 0) {
428b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        LOGE("open failed for %s", destPath);
429b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        return false;
4300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
4310cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
43227afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchown(fd, getuid(), group);
43327afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    // set permissions
43427afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    int mask = umask(0);
43527afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchmod(fd, perm);
43627afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    umask(mask);
43727afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood
438b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    Mutex::Autolock autoLock(mMutex);
439b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    bool result = false;
4400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
441b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.reset();
442b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.setParameter(1, handle);
443b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
444b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            && mData.readDataHeader(mEndpointIn)) {
445b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t length = mData.getContainerLength();
446b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (length < MTP_CONTAINER_HEADER_SIZE)
447b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            goto fail;
448b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
449b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t remaining = length;
450b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
451b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int initialDataLength = 0;
452b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        void* initialData = mData.getData(initialDataLength);
453b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (initialData) {
454b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (initialDataLength > 0) {
455b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, initialData, initialDataLength) != initialDataLength)
456b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
457b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                remaining -= initialDataLength;
4580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
459b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            free(initialData);
4600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
462b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        // USB reads greater than 16K don't work
463b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char buffer1[16384], buffer2[16384];
464b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char* readBuffer = buffer1;
465b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char* writeBuffer = NULL;
466b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int writeLength = 0;
467b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
468b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        while (remaining > 0 || writeBuffer) {
469b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (remaining > 0) {
470b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // queue up a read request
471b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                int readSize = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
472b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (mData.readDataAsync(mEndpointIn, readBuffer, readSize)) {
473b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    LOGE("readDataAsync failed");
474b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
475b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
4760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
477b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                readBuffer = NULL;
4780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
4790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
480b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (writeBuffer) {
481b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // write previous buffer
482b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, writeBuffer, writeLength) != writeLength) {
483b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    LOGE("write failed");
484b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    // wait for pending read before failing
485b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    if (readBuffer)
486b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                        mData.readDataWait(mEndpointIn);
487b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
488b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
489b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeBuffer = NULL;
490b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
4910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
492b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            // wait for read to complete
493b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (readBuffer) {
494b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                int read = mData.readDataWait(mEndpointIn);
495b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (read < 0)
496b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
4970cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
498b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeBuffer = readBuffer;
499b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeLength = read;
500b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                remaining -= read;
501b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                readBuffer = (readBuffer == buffer1 ? buffer2 : buffer1);
502b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
503b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        }
504b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
505b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        MtpResponseCode response = readResponse();
506b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (response == MTP_RESPONSE_OK)
507b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            result = true;
5080cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
509b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
510b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwoodfail:
511b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    ::close(fd);
512b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    return result;
5130cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
514a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
5155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::sendRequest(MtpOperationCode operation) {
516f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
517f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    mReceivedResponse = false;
5185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setOperationCode(operation);
5195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mTransactionID > 0)
5205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mRequest.setTransactionID(mTransactionID++);
5215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    int ret = mRequest.write(mEndpointOut);
5225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.dump();
5235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
5245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendData() {
527f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("sendData\n");
5285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
5295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
5305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    int ret = mData.write(mEndpointOut);
5315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.dump();
5325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
5335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::readData() {
5365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.reset();
5375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    int ret = mData.read(mEndpointIn);
538f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("readData returned %d\n", ret);
5395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
540f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
541f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            LOGD("got response packet instead of data packet");
542f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // we got a response packet rather than data
543f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // copy it to mResponse
544f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mResponse.copyFrom(mData);
545f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mReceivedResponse = true;
546f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            return false;
547f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        }
5485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mData.dump();
5495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return true;
5505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else {
552f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood        LOGV("readResponse failed\n");
5535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
5545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5570cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
5580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setOperationCode(operation);
5590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
5600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (!mData.writeDataHeader(mEndpointOut, dataLength));
5610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
5620cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
5635ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpResponseCode MtpDevice::readResponse() {
564f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("readResponse\n");
565f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    if (mReceivedResponse) {
566f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mReceivedResponse = false;
567f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        return mResponse.getResponseCode();
568f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    }
5695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    int ret = mResponse.read(mEndpointIn);
5705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
5715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mResponse.dump();
5725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mResponse.getResponseCode();
573f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    } else {
574a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        LOGD("readResponse failed\n");
5755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return -1;
5765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}  // namespace android
580