MtpDevice.cpp revision f41ef0ee0da4c497352df42d09c3d89940c25e14
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 4123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodstatic bool isMtpDevice(uint16_t vendor, uint16_t product) { 4223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // Sandisk Sansa Fuze 4323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (vendor == 0x0781 && product == 0x74c2) 4423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return true; 4523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // Samsung YP-Z5 4623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (vendor == 0x04e8 && product == 0x503c) 4723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return true; 4823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return false; 4923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood} 5023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 5123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike LockwoodMtpDevice* MtpDevice::open(const char* deviceName, int fd) { 5223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_device *device = usb_device_new(deviceName, fd); 5323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (!device) { 5423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("usb_device_new failed for %s", deviceName); 5523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return NULL; 5623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 5723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 5823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_descriptor_header* desc; 5923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_descriptor_iter iter; 6023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 6123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood usb_descriptor_iter_init(device, &iter); 6223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 6323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood while ((desc = usb_descriptor_iter_next(&iter)) != NULL) { 6423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (desc->bDescriptorType == USB_DT_INTERFACE) { 6523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc; 6623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 6723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE && 6823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood interface->bInterfaceSubClass == 1 && // Still Image Capture 6923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood interface->bInterfaceProtocol == 1) // Picture Transfer Protocol (PIMA 15470) 7023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood { 7123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGD("Found camera: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device), 7223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood usb_device_get_product_name(device)); 7323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else if (interface->bInterfaceClass == 0xFF && 7423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood interface->bInterfaceSubClass == 0xFF && 7523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood interface->bInterfaceProtocol == 0) { 7623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood char* interfaceName = usb_device_get_string(device, interface->iInterface); 7723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (!interfaceName || strcmp(interfaceName, "MTP")) 7823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood continue; 7923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // Looks like an android style MTP device 8023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGD("Found MTP device: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device), 8123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood usb_device_get_product_name(device)); 8223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else { 8323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // look for special cased devices based on vendor/product ID 8423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // we are doing this mainly for testing purposes 8523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood uint16_t vendor = usb_device_get_vendor_id(device); 8623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood uint16_t product = usb_device_get_product_id(device); 8723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (!isMtpDevice(vendor, product)) { 8823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // not an MTP or PTP device 8923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood continue; 9023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 9123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // request MTP OS string and descriptor 9223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // some music players need to see this before entering MTP mode. 9323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood char buffer[256]; 9423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood memset(buffer, 0, sizeof(buffer)); 95f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood int ret = usb_device_control_transfer(device, 9623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD, 9723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE, 98f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood 0, buffer, sizeof(buffer), 0); 99f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood printf("usb_device_control_transfer returned %d errno: %d\n", ret, errno); 10023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (ret > 0) { 10123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood printf("got MTP string %s\n", buffer); 102f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood ret = usb_device_control_transfer(device, 10323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1, 104f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood 0, 4, buffer, sizeof(buffer), 0); 10523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood printf("OS descriptor got %d\n", ret); 10623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else { 10723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood printf("no MTP string\n"); 10823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 10923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 11023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 11123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // if we got here, then we have a likely MTP or PTP device 11223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 11323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // interface should be followed by three endpoints 11423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_endpoint_descriptor *ep; 11523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_endpoint_descriptor *ep_in_desc = NULL; 11623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_endpoint_descriptor *ep_out_desc = NULL; 11723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_endpoint_descriptor *ep_intr_desc = NULL; 11823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood for (int i = 0; i < 3; i++) { 11923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter); 12023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) { 12123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("endpoints not found\n"); 12223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return NULL; 12323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 12423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { 12523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) 12623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood ep_in_desc = ep; 12723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood else 12823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood ep_out_desc = ep; 12923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT && 13023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { 13123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood ep_intr_desc = ep; 13223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 13323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 13423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) { 13523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("endpoints not found\n"); 13623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return NULL; 13723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 13823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 13923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (usb_device_claim_interface(device, interface->bInterfaceNumber)) { 14023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("usb_device_claim_interface failed errno: %d\n", errno); 14123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return NULL; 14223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 14323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 14423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber, 14523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood ep_in_desc, ep_out_desc, ep_intr_desc); 14623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood mtpDevice->initialize(); 14723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return mtpDevice; 14823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 14923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 15023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 15123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood usb_device_close(device); 15223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("device not found"); 15323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return NULL; 15423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood} 15523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 1565ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::MtpDevice(struct usb_device* device, int interface, 15742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood const struct usb_endpoint_descriptor *ep_in, 15842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood const struct usb_endpoint_descriptor *ep_out, 15942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood const struct usb_endpoint_descriptor *ep_intr) 1605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood : mDevice(device), 1615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mInterface(interface), 16242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIn1(NULL), 16342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIn2(NULL), 16442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestOut(NULL), 16542d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIntr(NULL), 1665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mDeviceInfo(NULL), 1675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mSessionID(0), 168f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood mTransactionID(0), 169f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood mReceivedResponse(false) 1705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood{ 17142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIn1 = usb_request_new(device, ep_in); 17242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIn2 = usb_request_new(device, ep_in); 17342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestOut = usb_request_new(device, ep_out); 17442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIntr = usb_request_new(device, ep_intr); 1755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 1765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 1775ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::~MtpDevice() { 1785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood close(); 179a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood for (int i = 0; i < mDeviceProperties.size(); i++) 180a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood delete mDeviceProperties[i]; 18142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood usb_request_free(mRequestIn1); 18242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood usb_request_free(mRequestIn2); 18342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood usb_request_free(mRequestOut); 18442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood usb_request_free(mRequestIntr); 1855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 1865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 1875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::initialize() { 1885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood openSession(); 1895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mDeviceInfo = getDeviceInfo(); 1905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (mDeviceInfo) { 191a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood if (mDeviceInfo->mDeviceProperties) { 192a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood int count = mDeviceInfo->mDeviceProperties->size(); 193a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood for (int i = 0; i < count; i++) { 194a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i]; 195a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood MtpProperty* property = getDevicePropDesc(propCode); 1960c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood if (property) 197a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood mDeviceProperties.push(property); 198a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood } 199a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood } 2005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 2015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 2025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 2035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::close() { 2045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (mDevice) { 2055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood usb_device_release_interface(mDevice, mInterface); 2065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood usb_device_close(mDevice); 2075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mDevice = NULL; 2085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 2095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 2105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 2110c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwoodvoid MtpDevice::print() { 2120c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood if (mDeviceInfo) { 2130c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood mDeviceInfo->print(); 2140c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood 2150c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood if (mDeviceInfo->mDeviceProperties) { 2160c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood LOGI("***** DEVICE PROPERTIES *****\n"); 2170c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood int count = mDeviceInfo->mDeviceProperties->size(); 2180c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood for (int i = 0; i < count; i++) { 2190c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i]; 2200c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood MtpProperty* property = getDevicePropDesc(propCode); 2210c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood if (property) { 2220c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood property->print(); 2230c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2240c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2250c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2260c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2270c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood 2280c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood if (mDeviceInfo->mPlaybackFormats) { 2290c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood LOGI("***** OBJECT PROPERTIES *****\n"); 2300c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood int count = mDeviceInfo->mPlaybackFormats->size(); 2310c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood for (int i = 0; i < count; i++) { 2320c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i]; 2330c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood LOGI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format)); 2340c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood MtpObjectPropertyList* props = getObjectPropsSupported(format); 2350c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood if (props) { 2360c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood for (int j = 0; j < props->size(); j++) { 2370c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood MtpObjectProperty prop = (*props)[j]; 23899e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood MtpProperty* property = getObjectPropDesc(prop, format); 2390c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood if (property) 2400c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood property->print(); 2410c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood else 2420c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood LOGE("could not fetch property: %s", 2430c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood MtpDebug::getObjectPropCodeName(prop)); 2440c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2450c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2460c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2470c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2480c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood} 2490c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood 2505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodconst char* MtpDevice::getDeviceName() { 2515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (mDevice) 2525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return usb_device_get_name(mDevice); 2535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood else 2545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return "???"; 2555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 2565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 2575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::openSession() { 2580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 2590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 2605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mSessionID = 0; 2615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mTransactionID = 0; 2625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpSessionID newSession = 1; 2635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.reset(); 2645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setParameter(1, newSession); 2655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!sendRequest(MTP_OPERATION_OPEN_SESSION)) 2665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return false; 2675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpResponseCode ret = readResponse(); 2685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN) 2695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood newSession = mResponse.getParameter(1); 2705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood else if (ret != MTP_RESPONSE_OK) 2715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return false; 2725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 2735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mSessionID = newSession; 2745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mTransactionID = 1; 2755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return true; 2765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 2775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 2785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::closeSession() { 2795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood // FIXME 2805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return true; 2815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 2825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 2835ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDeviceInfo* MtpDevice::getDeviceInfo() { 2840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 2850cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 2865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.reset(); 2875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO)) 2885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 2895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!readData()) 2905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 2915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpResponseCode ret = readResponse(); 2925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret == MTP_RESPONSE_OK) { 2935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpDeviceInfo* info = new MtpDeviceInfo; 2945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood info->read(mData); 2955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return info; 2965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 2975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 2985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 2995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 3005ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageIDList* MtpDevice::getStorageIDs() { 3010cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 3020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.reset(); 3045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS)) 3055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!readData()) 3075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpResponseCode ret = readResponse(); 3095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret == MTP_RESPONSE_OK) { 3105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return mData.getAUInt32(); 3115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 3125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 3145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 3155ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) { 3160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 3170cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.reset(); 3195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setParameter(1, storageID); 3205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO)) 3215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!readData()) 3235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpResponseCode ret = readResponse(); 3255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret == MTP_RESPONSE_OK) { 3265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpStorageInfo* info = new MtpStorageInfo(storageID); 3275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood info->read(mData); 3285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return info; 3295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 3305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 3325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 3335ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID, 3345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpObjectFormat format, MtpObjectHandle parent) { 3350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 3360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.reset(); 3385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setParameter(1, storageID); 3395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setParameter(2, format); 3405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setParameter(3, parent); 3415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES)) 3425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!readData()) 3445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpResponseCode ret = readResponse(); 3465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret == MTP_RESPONSE_OK) { 3475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return mData.getAUInt32(); 3485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 3495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 3515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 3525ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) { 3530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 3540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3556afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood // FIXME - we might want to add some caching here 3566afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood 3575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.reset(); 3585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setParameter(1, handle); 3595ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO)) 3605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!readData()) 3625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpResponseCode ret = readResponse(); 3645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret == MTP_RESPONSE_OK) { 3655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpObjectInfo* info = new MtpObjectInfo(handle); 3665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood info->read(mData); 3675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return info; 3685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 3695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 3715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 3723e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwoodvoid* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) { 3730cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 3740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3753e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood mRequest.reset(); 3763e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood mRequest.setParameter(1, handle); 3773e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) { 3783e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood MtpResponseCode ret = readResponse(); 3793e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood if (ret == MTP_RESPONSE_OK) { 3803e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood return mData.getData(outLength); 3813e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood } 3823e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood } 3833e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood outLength = 0; 3843e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood return NULL; 3856afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood} 3866afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood 3870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike LockwoodMtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) { 3880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 3890cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3900cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mRequest.reset(); 3910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood MtpObjectHandle parent = info->mParent; 3920cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood if (parent == 0) 3930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood parent = MTP_PARENT_ROOT; 3940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3950cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mRequest.setParameter(1, info->mStorageID); 3960cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mRequest.setParameter(2, info->mParent); 3970cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3980cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mStorageID); 3990cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt16(info->mFormat); 4000cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt16(info->mProtectionStatus); 4010cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mCompressedSize); 4020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt16(info->mThumbFormat); 4030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mThumbCompressedSize); 4040cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mThumbPixWidth); 4050cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mThumbPixHeight); 4060cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mImagePixWidth); 4070cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mImagePixHeight); 4080cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mImagePixDepth); 4090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mParent); 4100cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt16(info->mAssociationType); 4110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mAssociationDesc); 4120cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mSequenceNumber); 4130cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putString(info->mName); 4140cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4150cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood char created[100], modified[100]; 4160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood formatDateTime(info->mDateCreated, created, sizeof(created)); 4170cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood formatDateTime(info->mDateModified, modified, sizeof(modified)); 4180cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4190cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putString(created); 4200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putString(modified); 4210cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood if (info->mKeywords) 4220cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putString(info->mKeywords); 4230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood else 4240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putEmptyString(); 4250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) { 4270cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood MtpResponseCode ret = readResponse(); 4280cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood if (ret == MTP_RESPONSE_OK) { 4290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood info->mStorageID = mResponse.getParameter(1); 4300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood info->mParent = mResponse.getParameter(2); 4310cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood info->mHandle = mResponse.getParameter(3); 4320cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood return info->mHandle; 4330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 4340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 4350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood return (MtpObjectHandle)-1; 4360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood} 4370cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4380cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) { 4390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 4400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood int remaining = info->mCompressedSize; 4420cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mRequest.reset(); 4430cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mRequest.setParameter(1, info->mHandle); 4440cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood if (sendRequest(MTP_OPERATION_SEND_OBJECT)) { 4450cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood // send data header 4460cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining); 4470cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood char buffer[65536]; 4490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood while (remaining > 0) { 4500cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood int count = read(srcFD, buffer, sizeof(buffer)); 4510cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood if (count > 0) { 45242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood int written = mData.write(mRequestOut, buffer, count); 4530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood // FIXME check error 4540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood remaining -= count; 4550cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } else { 4560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood break; 4570cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 4580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 4590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 4600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood MtpResponseCode ret = readResponse(); 4610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood return (remaining == 0 && ret == MTP_RESPONSE_OK); 4620cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood} 4630cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4646afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwoodbool MtpDevice::deleteObject(MtpObjectHandle handle) { 4650cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 4660cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4676afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood mRequest.reset(); 4686afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood mRequest.setParameter(1, handle); 4696afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) { 4706afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood MtpResponseCode ret = readResponse(); 4716afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood if (ret == MTP_RESPONSE_OK) 4726afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood return true; 4736afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood } 4746afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood return false; 4756afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood} 4766afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood 4776afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) { 4786afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood MtpObjectInfo* info = getObjectInfo(handle); 4796afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood if (info) 4806afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood return info->mParent; 4816afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood else 4826afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood return -1; 4836afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood} 4843e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood 4856afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) { 4866afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood MtpObjectInfo* info = getObjectInfo(handle); 4876afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood if (info) 4886afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood return info->mStorageID; 4896afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood else 4906afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood return -1; 4913e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood} 4923e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood 49398693f674125484de8873d969c209276a6dd604bMike LockwoodMtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) { 49498693f674125484de8873d969c209276a6dd604bMike Lockwood Mutex::Autolock autoLock(mMutex); 49598693f674125484de8873d969c209276a6dd604bMike Lockwood 49698693f674125484de8873d969c209276a6dd604bMike Lockwood mRequest.reset(); 49798693f674125484de8873d969c209276a6dd604bMike Lockwood mRequest.setParameter(1, format); 49898693f674125484de8873d969c209276a6dd604bMike Lockwood if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED)) 49998693f674125484de8873d969c209276a6dd604bMike Lockwood return NULL; 50098693f674125484de8873d969c209276a6dd604bMike Lockwood if (!readData()) 50198693f674125484de8873d969c209276a6dd604bMike Lockwood return NULL; 50298693f674125484de8873d969c209276a6dd604bMike Lockwood MtpResponseCode ret = readResponse(); 50398693f674125484de8873d969c209276a6dd604bMike Lockwood if (ret == MTP_RESPONSE_OK) { 50498693f674125484de8873d969c209276a6dd604bMike Lockwood return mData.getAUInt16(); 50598693f674125484de8873d969c209276a6dd604bMike Lockwood } 50698693f674125484de8873d969c209276a6dd604bMike Lockwood return NULL; 50798693f674125484de8873d969c209276a6dd604bMike Lockwood 50898693f674125484de8873d969c209276a6dd604bMike Lockwood} 50998693f674125484de8873d969c209276a6dd604bMike Lockwood 510a6c490b8b2d96ebaab632286029463f932ae3b6bMike LockwoodMtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) { 5110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 5120cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 513a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood mRequest.reset(); 514a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood mRequest.setParameter(1, code); 515a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC)) 516a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood return NULL; 517a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood if (!readData()) 518a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood return NULL; 519a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood MtpResponseCode ret = readResponse(); 520a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood if (ret == MTP_RESPONSE_OK) { 521a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood MtpProperty* property = new MtpProperty; 522e3e76c456baee122de6715ae280130abaddc906cMike Lockwood property->read(mData); 523a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood return property; 524a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood } 525a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood return NULL; 526a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood} 527a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood 52899e393a39a31bfbdeb435462939519e2d0279433Mike LockwoodMtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) { 52998693f674125484de8873d969c209276a6dd604bMike Lockwood Mutex::Autolock autoLock(mMutex); 53098693f674125484de8873d969c209276a6dd604bMike Lockwood 53198693f674125484de8873d969c209276a6dd604bMike Lockwood mRequest.reset(); 53298693f674125484de8873d969c209276a6dd604bMike Lockwood mRequest.setParameter(1, code); 53399e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood mRequest.setParameter(2, format); 53498693f674125484de8873d969c209276a6dd604bMike Lockwood if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC)) 53598693f674125484de8873d969c209276a6dd604bMike Lockwood return NULL; 53698693f674125484de8873d969c209276a6dd604bMike Lockwood if (!readData()) 53798693f674125484de8873d969c209276a6dd604bMike Lockwood return NULL; 53898693f674125484de8873d969c209276a6dd604bMike Lockwood MtpResponseCode ret = readResponse(); 53998693f674125484de8873d969c209276a6dd604bMike Lockwood if (ret == MTP_RESPONSE_OK) { 54098693f674125484de8873d969c209276a6dd604bMike Lockwood MtpProperty* property = new MtpProperty; 54198693f674125484de8873d969c209276a6dd604bMike Lockwood property->read(mData); 54298693f674125484de8873d969c209276a6dd604bMike Lockwood return property; 54398693f674125484de8873d969c209276a6dd604bMike Lockwood } 54498693f674125484de8873d969c209276a6dd604bMike Lockwood return NULL; 54598693f674125484de8873d969c209276a6dd604bMike Lockwood} 54698693f674125484de8873d969c209276a6dd604bMike Lockwood 54723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, 54823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood bool (* callback)(void* data, int offset, int length, void* clientData), 54923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood int objectSize, void* clientData) { 55023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood Mutex::Autolock autoLock(mMutex); 55123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood bool result = false; 55223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 55323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood mRequest.reset(); 55423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood mRequest.setParameter(1, handle); 55523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (sendRequest(MTP_OPERATION_GET_OBJECT) 55623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood && mData.readDataHeader(mRequestIn1)) { 55723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood uint32_t length = mData.getContainerLength(); 55823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) { 55923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("readObject error objectSize: %d, length: %d", 56023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood objectSize, length); 56123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood goto fail; 56223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 56323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood length -= MTP_CONTAINER_HEADER_SIZE; 56423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood uint32_t remaining = length; 56523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood int offset = 0; 56623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 56723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood int initialDataLength = 0; 56823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood void* initialData = mData.getData(initialDataLength); 56923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (initialData) { 57023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (initialDataLength > 0) { 57123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (!callback(initialData, 0, initialDataLength, clientData)) 57223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood goto fail; 57323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood remaining -= initialDataLength; 57423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood offset += initialDataLength; 57523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 57623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood free(initialData); 57723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 57823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 57923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // USB reads greater than 16K don't work 58023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood char buffer1[16384], buffer2[16384]; 58123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood mRequestIn1->buffer = buffer1; 58223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood mRequestIn2->buffer = buffer2; 58323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_request* req = mRequestIn1; 58423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood void* writeBuffer = NULL; 58523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood int writeLength = 0; 58623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 58723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood while (remaining > 0 || writeBuffer) { 58823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (remaining > 0) { 58923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // queue up a read request 59023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining); 59123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (mData.readDataAsync(req)) { 59223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("readDataAsync failed"); 59323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood goto fail; 59423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 59523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else { 59623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood req = NULL; 59723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 59823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 59923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (writeBuffer) { 60023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // write previous buffer 60123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (!callback(writeBuffer, offset, writeLength, clientData)) { 60223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("write failed"); 60323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // wait for pending read before failing 60423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (req) 60523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood mData.readDataWait(mDevice); 60623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood goto fail; 60723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 60823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood offset += writeLength; 60923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeBuffer = NULL; 61023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 61123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 61223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // wait for read to complete 61323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (req) { 61423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood int read = mData.readDataWait(mDevice); 61523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (read < 0) 61623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood goto fail; 61723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 61823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (read > 0) { 61923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeBuffer = req->buffer; 62023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeLength = read; 62123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood remaining -= read; 62223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1); 62323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else { 62423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeBuffer = NULL; 62523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 62623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 62723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 62823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 62923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood MtpResponseCode response = readResponse(); 63023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (response == MTP_RESPONSE_OK) 63123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood result = true; 63223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 63323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 63423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodfail: 63523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return result; 63623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood} 63723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 63823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 639b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood// reads the object's data and writes it to the specified file path 64027afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) { 641b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood LOGD("readObject: %s", destPath); 642b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC); 643b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (fd < 0) { 644b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood LOGE("open failed for %s", destPath); 645b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood return false; 6460cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 6470cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 64827afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood fchown(fd, getuid(), group); 64927afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood // set permissions 65027afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood int mask = umask(0); 65127afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood fchmod(fd, perm); 65227afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood umask(mask); 65327afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood 654b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood Mutex::Autolock autoLock(mMutex); 655b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood bool result = false; 6560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 657b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood mRequest.reset(); 658b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood mRequest.setParameter(1, handle); 659b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (sendRequest(MTP_OPERATION_GET_OBJECT) 66042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood && mData.readDataHeader(mRequestIn1)) { 661b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood uint32_t length = mData.getContainerLength(); 662b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (length < MTP_CONTAINER_HEADER_SIZE) 663b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood goto fail; 664b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood length -= MTP_CONTAINER_HEADER_SIZE; 665b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood uint32_t remaining = length; 666b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood 667b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood int initialDataLength = 0; 668b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood void* initialData = mData.getData(initialDataLength); 669b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (initialData) { 670b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (initialDataLength > 0) { 671b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (write(fd, initialData, initialDataLength) != initialDataLength) 672b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood goto fail; 673b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood remaining -= initialDataLength; 6740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 675b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood free(initialData); 6760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 6770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 678b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood // USB reads greater than 16K don't work 679b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood char buffer1[16384], buffer2[16384]; 68042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIn1->buffer = buffer1; 68142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIn2->buffer = buffer2; 68242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood struct usb_request* req = mRequestIn1; 68342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood void* writeBuffer = NULL; 684b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood int writeLength = 0; 685b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood 686b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood while (remaining > 0 || writeBuffer) { 687b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (remaining > 0) { 688b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood // queue up a read request 68942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining); 69042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood if (mData.readDataAsync(req)) { 691b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood LOGE("readDataAsync failed"); 692b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood goto fail; 693b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood } 6940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } else { 69542d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood req = NULL; 6960cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 6970cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 698b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (writeBuffer) { 699b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood // write previous buffer 700b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (write(fd, writeBuffer, writeLength) != writeLength) { 701b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood LOGE("write failed"); 702b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood // wait for pending read before failing 70342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood if (req) 70442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mData.readDataWait(mDevice); 705b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood goto fail; 706b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood } 707b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood writeBuffer = NULL; 708b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood } 7090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 710b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood // wait for read to complete 71142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood if (req) { 71242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood int read = mData.readDataWait(mDevice); 713b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (read < 0) 714b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood goto fail; 7150cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 71623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (read > 0) { 71723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeBuffer = req->buffer; 71823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeLength = read; 71923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood remaining -= read; 72023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1); 72123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else { 72223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeBuffer = NULL; 72323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 724b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood } 725b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood } 726b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood 727b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood MtpResponseCode response = readResponse(); 728b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (response == MTP_RESPONSE_OK) 729b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood result = true; 7300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 731b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood 732b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwoodfail: 733b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood ::close(fd); 734b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood return result; 7350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood} 736a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood 7375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::sendRequest(MtpOperationCode operation) { 738f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood LOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation)); 739f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood mReceivedResponse = false; 7405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setOperationCode(operation); 7415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (mTransactionID > 0) 7425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setTransactionID(mTransactionID++); 74342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood int ret = mRequest.write(mRequestOut); 7445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.dump(); 7455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return (ret > 0); 7465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 7475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 7480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendData() { 749f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood LOGV("sendData\n"); 7505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mData.setOperationCode(mRequest.getOperationCode()); 7515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mData.setTransactionID(mRequest.getTransactionID()); 75242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood int ret = mData.write(mRequestOut); 7535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mData.dump(); 7545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return (ret > 0); 7555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 7565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 7575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::readData() { 7585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mData.reset(); 75942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood int ret = mData.read(mRequestIn1); 760f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood LOGV("readData returned %d\n", ret); 7615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret >= MTP_CONTAINER_HEADER_SIZE) { 762f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) { 763f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood LOGD("got response packet instead of data packet"); 764f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood // we got a response packet rather than data 765f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood // copy it to mResponse 766f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood mResponse.copyFrom(mData); 767f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood mReceivedResponse = true; 768f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood return false; 769f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood } 7705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mData.dump(); 7715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return true; 7725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 7735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood else { 774f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood LOGV("readResponse failed\n"); 7755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return false; 7765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 7775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 7785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 7790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) { 7800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.setOperationCode(operation); 7810cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.setTransactionID(mRequest.getTransactionID()); 78242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood return (!mData.writeDataHeader(mRequestOut, dataLength)); 7830cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood} 7840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 7855ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpResponseCode MtpDevice::readResponse() { 786f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood LOGV("readResponse\n"); 787f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood if (mReceivedResponse) { 788f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood mReceivedResponse = false; 789f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood return mResponse.getResponseCode(); 790f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood } 79142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood int ret = mResponse.read(mRequestIn1); 7925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret >= MTP_CONTAINER_HEADER_SIZE) { 7935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mResponse.dump(); 7945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return mResponse.getResponseCode(); 795f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood } else { 796a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood LOGD("readResponse failed\n"); 7975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return -1; 7985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 7995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 8005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 8015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} // namespace android 802