MtpDevice.cpp revision 98693f674125484de8873d969c209276a6dd604b
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),
525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mTransactionID(0)
535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood{
545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
565ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::~MtpDevice() {
575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    close();
58a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    for (int i = 0; i < mDeviceProperties.size(); i++)
59a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        delete mDeviceProperties[i];
605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::initialize() {
635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    openSession();
645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mDeviceInfo = getDeviceInfo();
655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDeviceInfo) {
665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDeviceInfo->print();
67a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
68a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        if (mDeviceInfo->mDeviceProperties) {
69a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
70a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            for (int i = 0; i < count; i++) {
71a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
72a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
73a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                if (property) {
74a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                    property->print();
75a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                    mDeviceProperties.push(property);
76a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                }
77a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            }
78a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        }
795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::close() {
835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice) {
845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_release_interface(mDevice, mInterface);
855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_close(mDevice);
865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDevice = NULL;
875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodconst char* MtpDevice::getDeviceName() {
915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice)
925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return usb_device_get_name(mDevice);
935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else
945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return "???";
955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::openSession() {
980cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
990cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = 0;
1015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 0;
1025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpSessionID newSession = 1;
1035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, newSession);
1055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
1065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
1075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
1095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        newSession = mResponse.getParameter(1);
1105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else if (ret != MTP_RESPONSE_OK)
1115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
1125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = newSession;
1145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 1;
1155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
1165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1175ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::closeSession() {
1195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    // FIXME
1205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
1215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1235ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDeviceInfo* MtpDevice::getDeviceInfo() {
1240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
1285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
1305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
1335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpDeviceInfo* info = new MtpDeviceInfo;
1345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
1355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
1365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
1375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
1385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1405ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageIDList* MtpDevice::getStorageIDs() {
1410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1420cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
1455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
1475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
1505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
1515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
1525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
1535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1555ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
1560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1570cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1595ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
1605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
1615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
1635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
1665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpStorageInfo* info = new MtpStorageInfo(storageID);
1675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
1685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
1695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
1705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
1715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1735ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
1745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            MtpObjectFormat format, MtpObjectHandle parent) {
1750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
1795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(2, format);
1805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(3, parent);
1815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
1825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
1845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
1875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
1885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
1895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
1905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1925ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
1930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1956afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    // FIXME - we might want to add some caching here
1966afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
1975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, handle);
1995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
2005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
2025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
2055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpObjectInfo* info = new MtpObjectInfo(handle);
2065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
2075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
2085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
2105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2123e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwoodvoid* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
2130cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2140cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2153e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.reset();
2163e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.setParameter(1, handle);
2173e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
2183e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        MtpResponseCode ret = readResponse();
2193e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
2203e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood            return mData.getData(outLength);
2213e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        }
2223e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    }
2233e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    outLength = 0;
2243e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    return NULL;
2256afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
2266afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
2270cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike LockwoodMtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
2280cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
2310cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpObjectHandle parent = info->mParent;
2320cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (parent == 0)
2330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        parent = MTP_PARENT_ROOT;
2340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mStorageID);
2360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(2, info->mParent);
2370cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2380cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mStorageID);
2390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mFormat);
2400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mProtectionStatus);
2410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mCompressedSize);
2420cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mThumbFormat);
2430cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbCompressedSize);
2440cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixWidth);
2450cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixHeight);
2460cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixWidth);
2470cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixHeight);
2480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixDepth);
2490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mParent);
2500cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mAssociationType);
2510cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mAssociationDesc);
2520cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mSequenceNumber);
2530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(info->mName);
2540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2550cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    char created[100], modified[100];
2560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateCreated, created, sizeof(created));
2570cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateModified, modified, sizeof(modified));
2580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(created);
2600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(modified);
2610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (info->mKeywords)
2620cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putString(info->mKeywords);
2630cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    else
2640cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putEmptyString();
2650cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2660cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood   if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
2670cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        MtpResponseCode ret = readResponse();
2680cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
2690cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mStorageID = mResponse.getParameter(1);
2700cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mParent = mResponse.getParameter(2);
2710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mHandle = mResponse.getParameter(3);
2720cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            return info->mHandle;
2730cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
2740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
2750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (MtpObjectHandle)-1;
2760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
2770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
2790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2810cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    int remaining = info->mCompressedSize;
2820cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
2830cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mHandle);
2840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
2850cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        // send data header
2860cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
2870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        char buffer[65536];
2890cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        while (remaining > 0) {
2900cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            int count = read(srcFD, buffer, sizeof(buffer));
2910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            if (count > 0) {
2920cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                int written = mData.write(mEndpointOut, buffer, count);
2930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                // FIXME check error
2940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                remaining -= count;
2950cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
2960cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                break;
2970cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
2980cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
2990cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
3000cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpResponseCode ret = readResponse();
3010cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (remaining == 0 && ret == MTP_RESPONSE_OK);
3020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
3030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3046afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwoodbool MtpDevice::deleteObject(MtpObjectHandle handle) {
3050cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3060cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3076afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.reset();
3086afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.setParameter(1, handle);
3096afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
3106afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        MtpResponseCode ret = readResponse();
3116afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        if (ret == MTP_RESPONSE_OK)
3126afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood            return true;
3136afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    }
3146afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    return false;
3156afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
3166afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
3176afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
3186afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
3196afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (info)
3206afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return info->mParent;
3216afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    else
3226afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
3236afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
3243e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
3256afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
3266afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
3276afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (info)
3286afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return info->mStorageID;
3296afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    else
3306afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
3313e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood}
3323e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
33398693f674125484de8873d969c209276a6dd604bMike LockwoodMtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
33498693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
33598693f674125484de8873d969c209276a6dd604bMike Lockwood
33698693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
33798693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, format);
33898693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED))
33998693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
34098693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
34198693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
34298693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
34398693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
34498693f674125484de8873d969c209276a6dd604bMike Lockwood        return mData.getAUInt16();
34598693f674125484de8873d969c209276a6dd604bMike Lockwood    }
34698693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
34798693f674125484de8873d969c209276a6dd604bMike Lockwood
34898693f674125484de8873d969c209276a6dd604bMike Lockwood}
34998693f674125484de8873d969c209276a6dd604bMike Lockwood
350a6c490b8b2d96ebaab632286029463f932ae3b6bMike LockwoodMtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
3510cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3520cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
353a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.reset();
354a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.setParameter(1, code);
355a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
356a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
357a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!readData())
358a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
359a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    MtpResponseCode ret = readResponse();
360a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
361a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        MtpProperty* property = new MtpProperty;
362e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        property->read(mData);
363a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return property;
364a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    }
365a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    return NULL;
366a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood}
367a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
36898693f674125484de8873d969c209276a6dd604bMike LockwoodMtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code) {
36998693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
37098693f674125484de8873d969c209276a6dd604bMike Lockwood
37198693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
37298693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, code);
37398693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC))
37498693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
37598693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
37698693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
37798693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
37898693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
37998693f674125484de8873d969c209276a6dd604bMike Lockwood        MtpProperty* property = new MtpProperty;
38098693f674125484de8873d969c209276a6dd604bMike Lockwood        property->read(mData);
38198693f674125484de8873d969c209276a6dd604bMike Lockwood        return property;
38298693f674125484de8873d969c209276a6dd604bMike Lockwood    }
38398693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
38498693f674125484de8873d969c209276a6dd604bMike Lockwood}
38598693f674125484de8873d969c209276a6dd604bMike Lockwood
386b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood// reads the object's data and writes it to the specified file path
38727afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
388b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    LOGD("readObject: %s", destPath);
389b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC);
390b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (fd < 0) {
391b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        LOGE("open failed for %s", destPath);
392b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        return false;
3930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
3940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
39527afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchown(fd, getuid(), group);
39627afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    // set permissions
39727afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    int mask = umask(0);
39827afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchmod(fd, perm);
39927afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    umask(mask);
40027afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood
401b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    Mutex::Autolock autoLock(mMutex);
402b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    bool result = false;
4030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
404b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.reset();
405b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.setParameter(1, handle);
406b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
407b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            && mData.readDataHeader(mEndpointIn)) {
408b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t length = mData.getContainerLength();
409b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (length < MTP_CONTAINER_HEADER_SIZE)
410b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            goto fail;
411b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
412b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t remaining = length;
413b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
414b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int initialDataLength = 0;
415b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        void* initialData = mData.getData(initialDataLength);
416b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (initialData) {
417b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (initialDataLength > 0) {
418b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, initialData, initialDataLength) != initialDataLength)
419b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
420b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                remaining -= initialDataLength;
4210cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
422b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            free(initialData);
4230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
425b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        // USB reads greater than 16K don't work
426b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char buffer1[16384], buffer2[16384];
427b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char* readBuffer = buffer1;
428b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char* writeBuffer = NULL;
429b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int writeLength = 0;
430b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
431b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        while (remaining > 0 || writeBuffer) {
432b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (remaining > 0) {
433b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // queue up a read request
434b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                int readSize = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
435b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (mData.readDataAsync(mEndpointIn, readBuffer, readSize)) {
436b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    LOGE("readDataAsync failed");
437b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
438b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
4390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
440b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                readBuffer = NULL;
4410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
4420cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
443b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (writeBuffer) {
444b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // write previous buffer
445b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, writeBuffer, writeLength) != writeLength) {
446b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    LOGE("write failed");
447b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    // wait for pending read before failing
448b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    if (readBuffer)
449b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                        mData.readDataWait(mEndpointIn);
450b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
451b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
452b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeBuffer = NULL;
453b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
4540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
455b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            // wait for read to complete
456b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (readBuffer) {
457b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                int read = mData.readDataWait(mEndpointIn);
458b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (read < 0)
459b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
4600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
461b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeBuffer = readBuffer;
462b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeLength = read;
463b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                remaining -= read;
464b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                readBuffer = (readBuffer == buffer1 ? buffer2 : buffer1);
465b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
466b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        }
467b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
468b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        MtpResponseCode response = readResponse();
469b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (response == MTP_RESPONSE_OK)
470b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            result = true;
4710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
472b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
473b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwoodfail:
474b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    ::close(fd);
475b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    return result;
4760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
477a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
4785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::sendRequest(MtpOperationCode operation) {
479f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
4805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setOperationCode(operation);
4815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mTransactionID > 0)
4825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mRequest.setTransactionID(mTransactionID++);
4835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    int ret = mRequest.write(mEndpointOut);
4845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.dump();
4855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
4865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
4875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
4880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendData() {
489f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("sendData\n");
4905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
4915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
4925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    int ret = mData.write(mEndpointOut);
4935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.dump();
4945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
4955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
4965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
4975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::readData() {
4985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.reset();
4995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    int ret = mData.read(mEndpointIn);
500f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("readData returned %d\n", ret);
5015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
5025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mData.dump();
5035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return true;
5045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else {
506f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood        LOGV("readResponse failed\n");
5075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
5085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
5120cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setOperationCode(operation);
5130cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
5140cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (!mData.writeDataHeader(mEndpointOut, dataLength));
5150cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
5160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
5175ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpResponseCode MtpDevice::readResponse() {
518f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("readResponse\n");
5195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    int ret = mResponse.read(mEndpointIn);
5205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
5215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mResponse.dump();
5225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mResponse.getResponseCode();
5235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else {
525a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        LOGD("readResponse failed\n");
5265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return -1;
5275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}  // namespace android
531