MtpDevice.cpp revision 42d0b79a787814d42e4c6f9dfe14f13cc0f6a758
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,
4242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_in,
4342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_out,
4442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_intr)
455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    :   mDevice(device),
465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mInterface(interface),
4742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn1(NULL),
4842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn2(NULL),
4942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestOut(NULL),
5042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIntr(NULL),
515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDeviceInfo(NULL),
525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mID(usb_device_get_unique_id(device)),
535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mSessionID(0),
54f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mTransactionID(0),
55f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mReceivedResponse(false)
565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood{
5742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIn1 = usb_request_new(device, ep_in);
5842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIn2 = usb_request_new(device, ep_in);
5942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestOut = usb_request_new(device, ep_out);
6042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIntr = usb_request_new(device, ep_intr);
615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
635ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::~MtpDevice() {
645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    close();
65a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    for (int i = 0; i < mDeviceProperties.size(); i++)
66a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        delete mDeviceProperties[i];
6742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIn1);
6842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIn2);
6942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestOut);
7042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIntr);
715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::initialize() {
745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    openSession();
755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mDeviceInfo = getDeviceInfo();
765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDeviceInfo) {
77a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        if (mDeviceInfo->mDeviceProperties) {
78a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
79a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            for (int i = 0; i < count; i++) {
80a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
81a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
820c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property)
83a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                    mDeviceProperties.push(property);
84a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            }
85a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        }
865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::close() {
905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice) {
915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_release_interface(mDevice, mInterface);
925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_close(mDevice);
935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDevice = NULL;
945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
970c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwoodvoid MtpDevice::print() {
980c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo) {
990c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        mDeviceInfo->print();
1000c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
1010c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        if (mDeviceInfo->mDeviceProperties) {
1020c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("***** DEVICE PROPERTIES *****\n");
1030c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
1040c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            for (int i = 0; i < count; i++) {
1050c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
1060c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
1070c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property) {
1080c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    property->print();
1090c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
1100c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
1110c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
1120c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
1130c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
1140c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo->mPlaybackFormats) {
1150c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("***** OBJECT PROPERTIES *****\n");
1160c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        int count = mDeviceInfo->mPlaybackFormats->size();
1170c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        for (int i = 0; i < count; i++) {
1180c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i];
1190c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            LOGI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format));
1200c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectPropertyList* props = getObjectPropsSupported(format);
1210c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            if (props) {
1220c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                for (int j = 0; j < props->size(); j++) {
1230c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    MtpObjectProperty prop = (*props)[j];
12499e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood                    MtpProperty* property = getObjectPropDesc(prop, format);
1250c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    if (property)
1260c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                        property->print();
1270c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    else
1280c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                        LOGE("could not fetch property: %s",
1290c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                                MtpDebug::getObjectPropCodeName(prop));
1300c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
1310c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
1320c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
1330c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
1340c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood}
1350c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
1365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodconst char* MtpDevice::getDeviceName() {
1375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice)
1385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return usb_device_get_name(mDevice);
1395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else
1405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return "???";
1415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::openSession() {
1440cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1450cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = 0;
1475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 0;
1485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpSessionID newSession = 1;
1495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, newSession);
1515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
1525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
1535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
1555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        newSession = mResponse.getParameter(1);
1565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else if (ret != MTP_RESPONSE_OK)
1575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
1585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1595ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = newSession;
1605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 1;
1615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
1625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::closeSession() {
1655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    // FIXME
1665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
1675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1695ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDeviceInfo* MtpDevice::getDeviceInfo() {
1700cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
1745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
1765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
1795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpDeviceInfo* info = new MtpDeviceInfo;
1805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
1815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
1825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
1835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
1845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
1855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
1865ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageIDList* MtpDevice::getStorageIDs() {
1870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
1880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
1895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
1905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
1915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
1935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
1945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
1955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
1965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
1975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
1985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
1995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2015ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
2020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
2055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
2065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
2075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
2095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
2125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpStorageInfo* info = new MtpStorageInfo(storageID);
2135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
2145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
2155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
2175ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2195ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
2205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            MtpObjectFormat format, MtpObjectHandle parent) {
2210cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2220cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
2245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
2255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(2, format);
2265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(3, parent);
2275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
2285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
2305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
2335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
2345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
2365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2385ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
2390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2416afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    // FIXME - we might want to add some caching here
2426afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
2435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
2445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, handle);
2455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
2465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
2485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
2495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
2515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpObjectInfo* info = new MtpObjectInfo(handle);
2525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
2535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
2545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
2565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2583e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwoodvoid* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
2590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2613e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.reset();
2623e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.setParameter(1, handle);
2633e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
2643e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        MtpResponseCode ret = readResponse();
2653e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
2663e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood            return mData.getData(outLength);
2673e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        }
2683e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    }
2693e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    outLength = 0;
2703e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    return NULL;
2716afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
2726afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
2730cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike LockwoodMtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
2740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
2770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpObjectHandle parent = info->mParent;
2780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (parent == 0)
2790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        parent = MTP_PARENT_ROOT;
2800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2810cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mStorageID);
2820cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(2, info->mParent);
2830cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mStorageID);
2850cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mFormat);
2860cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mProtectionStatus);
2870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mCompressedSize);
2880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mThumbFormat);
2890cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbCompressedSize);
2900cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixWidth);
2910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixHeight);
2920cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixWidth);
2930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixHeight);
2940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixDepth);
2950cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mParent);
2960cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mAssociationType);
2970cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mAssociationDesc);
2980cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mSequenceNumber);
2990cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(info->mName);
3000cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3010cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    char created[100], modified[100];
3020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateCreated, created, sizeof(created));
3030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateModified, modified, sizeof(modified));
3040cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3050cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(created);
3060cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(modified);
3070cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (info->mKeywords)
3080cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putString(info->mKeywords);
3090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    else
3100cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putEmptyString();
3110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3120cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood   if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
3130cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        MtpResponseCode ret = readResponse();
3140cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
3150cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mStorageID = mResponse.getParameter(1);
3160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mParent = mResponse.getParameter(2);
3170cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mHandle = mResponse.getParameter(3);
3180cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            return info->mHandle;
3190cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
3200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
3210cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (MtpObjectHandle)-1;
3220cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
3230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
3250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3270cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    int remaining = info->mCompressedSize;
3280cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
3290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mHandle);
3300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
3310cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        // send data header
3320cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
3330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        char buffer[65536];
3350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        while (remaining > 0) {
3360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            int count = read(srcFD, buffer, sizeof(buffer));
3370cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            if (count > 0) {
33842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                int written = mData.write(mRequestOut, buffer, count);
3390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                // FIXME check error
3400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                remaining -= count;
3410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
3420cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                break;
3430cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
3440cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
3450cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
3460cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpResponseCode ret = readResponse();
3470cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (remaining == 0 && ret == MTP_RESPONSE_OK);
3480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
3490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3506afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwoodbool MtpDevice::deleteObject(MtpObjectHandle handle) {
3510cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3520cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3536afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.reset();
3546afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.setParameter(1, handle);
3556afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
3566afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        MtpResponseCode ret = readResponse();
3576afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        if (ret == MTP_RESPONSE_OK)
3586afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood            return true;
3596afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    }
3606afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    return false;
3616afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
3626afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
3636afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
3646afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
3656afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (info)
3666afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return info->mParent;
3676afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    else
3686afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
3696afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
3703e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
3716afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
3726afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
3736afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (info)
3746afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return info->mStorageID;
3756afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    else
3766afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
3773e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood}
3783e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
37998693f674125484de8873d969c209276a6dd604bMike LockwoodMtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
38098693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
38198693f674125484de8873d969c209276a6dd604bMike Lockwood
38298693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
38398693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, format);
38498693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED))
38598693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
38698693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
38798693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
38898693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
38998693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
39098693f674125484de8873d969c209276a6dd604bMike Lockwood        return mData.getAUInt16();
39198693f674125484de8873d969c209276a6dd604bMike Lockwood    }
39298693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
39398693f674125484de8873d969c209276a6dd604bMike Lockwood
39498693f674125484de8873d969c209276a6dd604bMike Lockwood}
39598693f674125484de8873d969c209276a6dd604bMike Lockwood
396a6c490b8b2d96ebaab632286029463f932ae3b6bMike LockwoodMtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
3970cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3980cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
399a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.reset();
400a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.setParameter(1, code);
401a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
402a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
403a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!readData())
404a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
405a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    MtpResponseCode ret = readResponse();
406a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
407a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        MtpProperty* property = new MtpProperty;
408e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        property->read(mData);
409a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return property;
410a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    }
411a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    return NULL;
412a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood}
413a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
41499e393a39a31bfbdeb435462939519e2d0279433Mike LockwoodMtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
41598693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
41698693f674125484de8873d969c209276a6dd604bMike Lockwood
41798693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
41898693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, code);
41999e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood    mRequest.setParameter(2, format);
42098693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC))
42198693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
42298693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
42398693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
42498693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
42598693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
42698693f674125484de8873d969c209276a6dd604bMike Lockwood        MtpProperty* property = new MtpProperty;
42798693f674125484de8873d969c209276a6dd604bMike Lockwood        property->read(mData);
42898693f674125484de8873d969c209276a6dd604bMike Lockwood        return property;
42998693f674125484de8873d969c209276a6dd604bMike Lockwood    }
43098693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
43198693f674125484de8873d969c209276a6dd604bMike Lockwood}
43298693f674125484de8873d969c209276a6dd604bMike Lockwood
433b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood// reads the object's data and writes it to the specified file path
43427afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
435b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    LOGD("readObject: %s", destPath);
436b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC);
437b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (fd < 0) {
438b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        LOGE("open failed for %s", destPath);
439b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        return false;
4400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
4410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
44227afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchown(fd, getuid(), group);
44327afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    // set permissions
44427afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    int mask = umask(0);
44527afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchmod(fd, perm);
44627afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    umask(mask);
44727afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood
448b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    Mutex::Autolock autoLock(mMutex);
449b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    bool result = false;
4500cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
451b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.reset();
452b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.setParameter(1, handle);
453b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
45442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            && mData.readDataHeader(mRequestIn1)) {
455b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t length = mData.getContainerLength();
456b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (length < MTP_CONTAINER_HEADER_SIZE)
457b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            goto fail;
458b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
459b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t remaining = length;
460b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
461b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int initialDataLength = 0;
462b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        void* initialData = mData.getData(initialDataLength);
463b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (initialData) {
464b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (initialDataLength > 0) {
465b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, initialData, initialDataLength) != initialDataLength)
466b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
467b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                remaining -= initialDataLength;
4680cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
469b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            free(initialData);
4700cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
472b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        // USB reads greater than 16K don't work
473b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char buffer1[16384], buffer2[16384];
47442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn1->buffer = buffer1;
47542d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn2->buffer = buffer2;
47642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        struct usb_request* req = mRequestIn1;
47742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        void* writeBuffer = NULL;
478b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int writeLength = 0;
479b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
480b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        while (remaining > 0 || writeBuffer) {
481b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (remaining > 0) {
482b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // queue up a read request
48342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
48442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                if (mData.readDataAsync(req)) {
485b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    LOGE("readDataAsync failed");
486b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
487b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
4880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
48942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                req = NULL;
4900cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
4910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
492b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (writeBuffer) {
493b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // write previous buffer
494b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, writeBuffer, writeLength) != writeLength) {
495b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    LOGE("write failed");
496b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    // wait for pending read before failing
49742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                    if (req)
49842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                        mData.readDataWait(mDevice);
499b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
500b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
501b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeBuffer = NULL;
502b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
5030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
504b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            // wait for read to complete
50542d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            if (req) {
50642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                int read = mData.readDataWait(mDevice);
507b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (read < 0)
508b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
5090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
51042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                writeBuffer = req->buffer;
511b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeLength = read;
512b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                remaining -= read;
51342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
514b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
515b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        }
516b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
517b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        MtpResponseCode response = readResponse();
518b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (response == MTP_RESPONSE_OK)
519b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            result = true;
5200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
521b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
522b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwoodfail:
523b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    ::close(fd);
524b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    return result;
5250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
526a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
5275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::sendRequest(MtpOperationCode operation) {
528f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
529f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    mReceivedResponse = false;
5305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setOperationCode(operation);
5315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mTransactionID > 0)
5325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mRequest.setTransactionID(mTransactionID++);
53342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mRequest.write(mRequestOut);
5345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.dump();
5355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
5365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5380cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendData() {
539f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("sendData\n");
5405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
5415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
54242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mData.write(mRequestOut);
5435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.dump();
5445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
5455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::readData() {
5485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.reset();
54942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mData.read(mRequestIn1);
550f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("readData returned %d\n", ret);
5515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
552f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
553f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            LOGD("got response packet instead of data packet");
554f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // we got a response packet rather than data
555f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // copy it to mResponse
556f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mResponse.copyFrom(mData);
557f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mReceivedResponse = true;
558f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            return false;
559f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        }
5605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mData.dump();
5615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return true;
5625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else {
564f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood        LOGV("readResponse failed\n");
5655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
5665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5690cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
5700cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setOperationCode(operation);
5710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
57242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    return (!mData.writeDataHeader(mRequestOut, dataLength));
5730cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
5740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
5755ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpResponseCode MtpDevice::readResponse() {
576f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood    LOGV("readResponse\n");
577f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    if (mReceivedResponse) {
578f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mReceivedResponse = false;
579f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        return mResponse.getResponseCode();
580f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    }
58142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mResponse.read(mRequestIn1);
5825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
5835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mResponse.dump();
5845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mResponse.getResponseCode();
585f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    } else {
586a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        LOGD("readResponse failed\n");
5875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return -1;
5885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
5895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
5905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
5915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}  // namespace android
592