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