MtpDevice.cpp revision b14e588bec4d5e39e61b020b5b575f2ce555d316
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "MtpDevice" 18 19#include "MtpDebug.h" 20#include "MtpDevice.h" 21#include "MtpDeviceInfo.h" 22#include "MtpObjectInfo.h" 23#include "MtpProperty.h" 24#include "MtpStorageInfo.h" 25#include "MtpStringBuffer.h" 26 27#include <stdio.h> 28#include <stdlib.h> 29#include <sys/types.h> 30#include <sys/ioctl.h> 31#include <sys/stat.h> 32#include <fcntl.h> 33#include <errno.h> 34 35#include <usbhost/usbhost.h> 36 37namespace android { 38 39MtpDevice::MtpDevice(struct usb_device* device, int interface, 40 struct usb_endpoint *ep_in, struct usb_endpoint *ep_out, 41 struct usb_endpoint *ep_intr) 42 : mDevice(device), 43 mInterface(interface), 44 mEndpointIn(ep_in), 45 mEndpointOut(ep_out), 46 mEndpointIntr(ep_intr), 47 mDeviceInfo(NULL), 48 mID(usb_device_get_unique_id(device)), 49 mSessionID(0), 50 mTransactionID(0) 51{ 52} 53 54MtpDevice::~MtpDevice() { 55 close(); 56 for (int i = 0; i < mDeviceProperties.size(); i++) 57 delete mDeviceProperties[i]; 58} 59 60void MtpDevice::initialize() { 61 openSession(); 62 mDeviceInfo = getDeviceInfo(); 63 if (mDeviceInfo) { 64 mDeviceInfo->print(); 65 66 if (mDeviceInfo->mDeviceProperties) { 67 int count = mDeviceInfo->mDeviceProperties->size(); 68 for (int i = 0; i < count; i++) { 69 MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i]; 70 MtpProperty* property = getDevicePropDesc(propCode); 71 if (property) { 72 property->print(); 73 mDeviceProperties.push(property); 74 } 75 } 76 } 77 } 78} 79 80void MtpDevice::close() { 81 if (mDevice) { 82 usb_device_release_interface(mDevice, mInterface); 83 usb_device_close(mDevice); 84 mDevice = NULL; 85 } 86} 87 88const char* MtpDevice::getDeviceName() { 89 if (mDevice) 90 return usb_device_get_name(mDevice); 91 else 92 return "???"; 93} 94 95bool MtpDevice::openSession() { 96 mSessionID = 0; 97 mTransactionID = 0; 98 MtpSessionID newSession = 1; 99 mRequest.reset(); 100 mRequest.setParameter(1, newSession); 101 if (!sendRequest(MTP_OPERATION_OPEN_SESSION)) 102 return false; 103 MtpResponseCode ret = readResponse(); 104 if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN) 105 newSession = mResponse.getParameter(1); 106 else if (ret != MTP_RESPONSE_OK) 107 return false; 108 109 mSessionID = newSession; 110 mTransactionID = 1; 111 return true; 112} 113 114bool MtpDevice::closeSession() { 115 // FIXME 116 return true; 117} 118 119MtpDeviceInfo* MtpDevice::getDeviceInfo() { 120 mRequest.reset(); 121 if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO)) 122 return NULL; 123 if (!readData()) 124 return NULL; 125 MtpResponseCode ret = readResponse(); 126 if (ret == MTP_RESPONSE_OK) { 127 MtpDeviceInfo* info = new MtpDeviceInfo; 128 info->read(mData); 129 return info; 130 } 131 return NULL; 132} 133 134MtpStorageIDList* MtpDevice::getStorageIDs() { 135 mRequest.reset(); 136 if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS)) 137 return NULL; 138 if (!readData()) 139 return NULL; 140 MtpResponseCode ret = readResponse(); 141 if (ret == MTP_RESPONSE_OK) { 142 return mData.getAUInt32(); 143 } 144 return NULL; 145} 146 147MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) { 148 mRequest.reset(); 149 mRequest.setParameter(1, storageID); 150 if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO)) 151 return NULL; 152 if (!readData()) 153 return NULL; 154 MtpResponseCode ret = readResponse(); 155 if (ret == MTP_RESPONSE_OK) { 156 MtpStorageInfo* info = new MtpStorageInfo(storageID); 157 info->read(mData); 158 return info; 159 } 160 return NULL; 161} 162 163MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID, 164 MtpObjectFormat format, MtpObjectHandle parent) { 165 mRequest.reset(); 166 mRequest.setParameter(1, storageID); 167 mRequest.setParameter(2, format); 168 mRequest.setParameter(3, parent); 169 if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES)) 170 return NULL; 171 if (!readData()) 172 return NULL; 173 MtpResponseCode ret = readResponse(); 174 if (ret == MTP_RESPONSE_OK) { 175 return mData.getAUInt32(); 176 } 177 return NULL; 178} 179 180MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) { 181 // FIXME - we might want to add some caching here 182 183 mRequest.reset(); 184 mRequest.setParameter(1, handle); 185 if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO)) 186 return NULL; 187 if (!readData()) 188 return NULL; 189 MtpResponseCode ret = readResponse(); 190 if (ret == MTP_RESPONSE_OK) { 191 MtpObjectInfo* info = new MtpObjectInfo(handle); 192 info->read(mData); 193 return info; 194 } 195 return NULL; 196} 197 198void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) { 199 mRequest.reset(); 200 mRequest.setParameter(1, handle); 201 if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) { 202 MtpResponseCode ret = readResponse(); 203 if (ret == MTP_RESPONSE_OK) { 204 return mData.getData(outLength); 205 } 206 } 207 outLength = 0; 208 return NULL; 209} 210 211bool MtpDevice::deleteObject(MtpObjectHandle handle) { 212 mRequest.reset(); 213 mRequest.setParameter(1, handle); 214 if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) { 215 MtpResponseCode ret = readResponse(); 216 if (ret == MTP_RESPONSE_OK) 217 return true; 218 } 219 return false; 220} 221 222MtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) { 223 MtpObjectInfo* info = getObjectInfo(handle); 224 if (info) 225 return info->mParent; 226 else 227 return -1; 228} 229 230MtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) { 231 MtpObjectInfo* info = getObjectInfo(handle); 232 if (info) 233 return info->mStorageID; 234 else 235 return -1; 236} 237 238MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) { 239 mRequest.reset(); 240 mRequest.setParameter(1, code); 241 if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC)) 242 return NULL; 243 if (!readData()) 244 return NULL; 245 MtpResponseCode ret = readResponse(); 246 if (ret == MTP_RESPONSE_OK) { 247 MtpProperty* property = new MtpProperty; 248 property->read(mData); 249 return property; 250 } 251 return NULL; 252} 253 254 255bool MtpDevice::sendRequest(MtpOperationCode operation) { 256 LOGD("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation)); 257 mRequest.setOperationCode(operation); 258 if (mTransactionID > 0) 259 mRequest.setTransactionID(mTransactionID++); 260 int ret = mRequest.write(mEndpointOut); 261 mRequest.dump(); 262 return (ret > 0); 263} 264 265bool MtpDevice::sendData(MtpOperationCode operation) { 266 LOGD("sendData\n"); 267 mData.setOperationCode(mRequest.getOperationCode()); 268 mData.setTransactionID(mRequest.getTransactionID()); 269 int ret = mData.write(mEndpointOut); 270 mData.dump(); 271 return (ret > 0); 272} 273 274bool MtpDevice::readData() { 275 mData.reset(); 276 int ret = mData.read(mEndpointIn); 277 LOGD("readData returned %d\n", ret); 278 if (ret >= MTP_CONTAINER_HEADER_SIZE) { 279 mData.dump(); 280 return true; 281 } 282 else { 283 LOGD("readResponse failed\n"); 284 return false; 285 } 286} 287 288MtpResponseCode MtpDevice::readResponse() { 289 LOGD("readResponse\n"); 290 int ret = mResponse.read(mEndpointIn); 291 if (ret >= MTP_CONTAINER_HEADER_SIZE) { 292 mResponse.dump(); 293 return mResponse.getResponseCode(); 294 } 295 else { 296 LOGD("readResponse failed\n"); 297 return -1; 298 } 299} 300 301} // namespace android 302