MtpDevice.cpp revision 31c52e7c8c01e1db6ff9bcf66135c72544b1235a
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 { 7131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root char* manufacturerName = usb_device_get_manufacturer_name(device); 7231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root char* productName = usb_device_get_product_name(device); 7331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root LOGD("Found camera: \"%s\" \"%s\"\n", manufacturerName, productName); 7431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root free(manufacturerName); 7531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root free(productName); 7623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else if (interface->bInterfaceClass == 0xFF && 7723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood interface->bInterfaceSubClass == 0xFF && 7823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood interface->bInterfaceProtocol == 0) { 7923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood char* interfaceName = usb_device_get_string(device, interface->iInterface); 8031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root if (!interfaceName) { 8123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood continue; 8231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root } else if (strcmp(interfaceName, "MTP")) { 8331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root free(interfaceName); 8431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root continue; 8531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root } 8631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root free(interfaceName); 8731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root 8823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // Looks like an android style MTP device 8931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root char* manufacturerName = usb_device_get_manufacturer_name(device); 9031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root char* productName = usb_device_get_product_name(device); 9131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root LOGD("Found MTP device: \"%s\" \"%s\"\n", manufacturerName, productName); 9231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root free(manufacturerName); 9331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root free(productName); 9423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else { 9523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // look for special cased devices based on vendor/product ID 9623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // we are doing this mainly for testing purposes 9723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood uint16_t vendor = usb_device_get_vendor_id(device); 9823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood uint16_t product = usb_device_get_product_id(device); 9923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (!isMtpDevice(vendor, product)) { 10023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // not an MTP or PTP device 10123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood continue; 10223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 10323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // request MTP OS string and descriptor 10423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // some music players need to see this before entering MTP mode. 10523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood char buffer[256]; 10623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood memset(buffer, 0, sizeof(buffer)); 107f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood int ret = usb_device_control_transfer(device, 10823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD, 10923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE, 110f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood 0, buffer, sizeof(buffer), 0); 111f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood printf("usb_device_control_transfer returned %d errno: %d\n", ret, errno); 11223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (ret > 0) { 11323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood printf("got MTP string %s\n", buffer); 114f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood ret = usb_device_control_transfer(device, 11523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1, 116f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood 0, 4, buffer, sizeof(buffer), 0); 11723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood printf("OS descriptor got %d\n", ret); 11823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else { 11923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood printf("no MTP string\n"); 12023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 12123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 12223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 12323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // if we got here, then we have a likely MTP or PTP device 12423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 12523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // interface should be followed by three endpoints 12623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_endpoint_descriptor *ep; 12723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_endpoint_descriptor *ep_in_desc = NULL; 12823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_endpoint_descriptor *ep_out_desc = NULL; 12923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_endpoint_descriptor *ep_intr_desc = NULL; 13023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood for (int i = 0; i < 3; i++) { 13123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter); 13223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) { 13323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("endpoints not found\n"); 13431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root usb_device_close(device); 13523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return NULL; 13623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 13723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { 13823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) 13923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood ep_in_desc = ep; 14023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood else 14123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood ep_out_desc = ep; 14223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT && 14323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { 14423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood ep_intr_desc = ep; 14523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 14623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 14723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) { 14823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("endpoints not found\n"); 14931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root usb_device_close(device); 15023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return NULL; 15123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 15223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 15323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (usb_device_claim_interface(device, interface->bInterfaceNumber)) { 15423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("usb_device_claim_interface failed errno: %d\n", errno); 15531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root usb_device_close(device); 15623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return NULL; 15723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 15823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 15923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber, 16023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood ep_in_desc, ep_out_desc, ep_intr_desc); 16123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood mtpDevice->initialize(); 16223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return mtpDevice; 16323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 16423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 16523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 16623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood usb_device_close(device); 16723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("device not found"); 16823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return NULL; 16923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood} 17023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 1715ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::MtpDevice(struct usb_device* device, int interface, 17242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood const struct usb_endpoint_descriptor *ep_in, 17342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood const struct usb_endpoint_descriptor *ep_out, 17442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood const struct usb_endpoint_descriptor *ep_intr) 1755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood : mDevice(device), 1765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mInterface(interface), 17742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIn1(NULL), 17842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIn2(NULL), 17942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestOut(NULL), 18042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIntr(NULL), 1815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mDeviceInfo(NULL), 1825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mSessionID(0), 183f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood mTransactionID(0), 184f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood mReceivedResponse(false) 1855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood{ 18642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIn1 = usb_request_new(device, ep_in); 18742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIn2 = usb_request_new(device, ep_in); 18842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestOut = usb_request_new(device, ep_out); 18942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIntr = usb_request_new(device, ep_intr); 1905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 1915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 1925ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::~MtpDevice() { 1935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood close(); 194a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood for (int i = 0; i < mDeviceProperties.size(); i++) 195a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood delete mDeviceProperties[i]; 19642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood usb_request_free(mRequestIn1); 19742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood usb_request_free(mRequestIn2); 19842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood usb_request_free(mRequestOut); 19942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood usb_request_free(mRequestIntr); 2005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 2015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 2025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::initialize() { 2035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood openSession(); 2045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mDeviceInfo = getDeviceInfo(); 2055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (mDeviceInfo) { 206a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood if (mDeviceInfo->mDeviceProperties) { 207a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood int count = mDeviceInfo->mDeviceProperties->size(); 208a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood for (int i = 0; i < count; i++) { 209a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i]; 210a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood MtpProperty* property = getDevicePropDesc(propCode); 2110c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood if (property) 212a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood mDeviceProperties.push(property); 213a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood } 214a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood } 2155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 2165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 2175ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 2185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::close() { 2195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (mDevice) { 2205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood usb_device_release_interface(mDevice, mInterface); 2215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood usb_device_close(mDevice); 2225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mDevice = NULL; 2235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 2245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 2255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 2260c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwoodvoid MtpDevice::print() { 2270c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood if (mDeviceInfo) { 2280c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood mDeviceInfo->print(); 2290c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood 2300c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood if (mDeviceInfo->mDeviceProperties) { 2310c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood LOGI("***** DEVICE PROPERTIES *****\n"); 2320c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood int count = mDeviceInfo->mDeviceProperties->size(); 2330c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood for (int i = 0; i < count; i++) { 2340c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i]; 2350c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood MtpProperty* property = getDevicePropDesc(propCode); 2360c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood if (property) { 2370c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood property->print(); 23831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root delete property; 2390c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2400c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2410c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2420c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2430c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood 2440c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood if (mDeviceInfo->mPlaybackFormats) { 2450c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood LOGI("***** OBJECT PROPERTIES *****\n"); 2460c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood int count = mDeviceInfo->mPlaybackFormats->size(); 2470c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood for (int i = 0; i < count; i++) { 2480c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i]; 2490c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood LOGI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format)); 2500c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood MtpObjectPropertyList* props = getObjectPropsSupported(format); 2510c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood if (props) { 2520c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood for (int j = 0; j < props->size(); j++) { 2530c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood MtpObjectProperty prop = (*props)[j]; 25499e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood MtpProperty* property = getObjectPropDesc(prop, format); 25531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root if (property) { 2560c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood property->print(); 25731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root delete property; 25831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root } else { 2590c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood LOGE("could not fetch property: %s", 2600c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood MtpDebug::getObjectPropCodeName(prop)); 26131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root } 2620c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2630c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2640c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2650c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood } 2660c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood} 2670c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood 2685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodconst char* MtpDevice::getDeviceName() { 2695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (mDevice) 2705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return usb_device_get_name(mDevice); 2715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood else 2725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return "???"; 2735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 2745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 2755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::openSession() { 2760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 2770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 2785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mSessionID = 0; 2795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mTransactionID = 0; 2805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpSessionID newSession = 1; 2815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.reset(); 2825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setParameter(1, newSession); 2835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!sendRequest(MTP_OPERATION_OPEN_SESSION)) 2845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return false; 2855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpResponseCode ret = readResponse(); 2865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN) 2875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood newSession = mResponse.getParameter(1); 2885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood else if (ret != MTP_RESPONSE_OK) 2895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return false; 2905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 2915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mSessionID = newSession; 2925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mTransactionID = 1; 2935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return true; 2945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 2955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 2965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::closeSession() { 2975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood // FIXME 2985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return true; 2995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 3005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 3015ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDeviceInfo* MtpDevice::getDeviceInfo() { 3020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 3030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.reset(); 3055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO)) 3065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!readData()) 3085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpResponseCode ret = readResponse(); 3105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret == MTP_RESPONSE_OK) { 3115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpDeviceInfo* info = new MtpDeviceInfo; 3125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood info->read(mData); 3135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return info; 3145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 3155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 3175ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 3185ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageIDList* MtpDevice::getStorageIDs() { 3190cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 3200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.reset(); 3225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS)) 3235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!readData()) 3255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpResponseCode ret = readResponse(); 3275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret == MTP_RESPONSE_OK) { 3285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return mData.getAUInt32(); 3295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 3305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 3325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 3335ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) { 3340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 3350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.reset(); 3375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setParameter(1, storageID); 3385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO)) 3395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!readData()) 3415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpResponseCode ret = readResponse(); 3435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret == MTP_RESPONSE_OK) { 3445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpStorageInfo* info = new MtpStorageInfo(storageID); 3455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood info->read(mData); 3465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return info; 3475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 3485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 3505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 3515ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID, 3525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpObjectFormat format, MtpObjectHandle parent) { 3530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 3540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.reset(); 3565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setParameter(1, storageID); 3575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setParameter(2, format); 3585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setParameter(3, parent); 3595ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES)) 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 return mData.getAUInt32(); 3665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 3675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 3695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 3705ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) { 3710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 3720cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3736afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood // FIXME - we might want to add some caching here 3746afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood 3755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.reset(); 3765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setParameter(1, handle); 3775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO)) 3785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (!readData()) 3805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpResponseCode ret = readResponse(); 3825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret == MTP_RESPONSE_OK) { 3835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood MtpObjectInfo* info = new MtpObjectInfo(handle); 3845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood info->read(mData); 3855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return info; 3865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 3875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return NULL; 3885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 3895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 3903e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwoodvoid* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) { 3910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 3920cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 3933e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood mRequest.reset(); 3943e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood mRequest.setParameter(1, handle); 3953e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) { 3963e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood MtpResponseCode ret = readResponse(); 3973e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood if (ret == MTP_RESPONSE_OK) { 3983e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood return mData.getData(outLength); 3993e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood } 4003e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood } 4013e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood outLength = 0; 4023e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood return NULL; 4036afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood} 4046afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood 4050cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike LockwoodMtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) { 4060cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 4070cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4080cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mRequest.reset(); 4090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood MtpObjectHandle parent = info->mParent; 4100cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood if (parent == 0) 4110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood parent = MTP_PARENT_ROOT; 4120cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4130cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mRequest.setParameter(1, info->mStorageID); 4140cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mRequest.setParameter(2, info->mParent); 4150cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mStorageID); 4170cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt16(info->mFormat); 4180cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt16(info->mProtectionStatus); 4190cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mCompressedSize); 4200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt16(info->mThumbFormat); 4210cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mThumbCompressedSize); 4220cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mThumbPixWidth); 4230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mThumbPixHeight); 4240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mImagePixWidth); 4250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mImagePixHeight); 4260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mImagePixDepth); 4270cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mParent); 4280cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt16(info->mAssociationType); 4290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mAssociationDesc); 4300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putUInt32(info->mSequenceNumber); 4310cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putString(info->mName); 4320cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood char created[100], modified[100]; 4340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood formatDateTime(info->mDateCreated, created, sizeof(created)); 4350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood formatDateTime(info->mDateModified, modified, sizeof(modified)); 4360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4370cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putString(created); 4380cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putString(modified); 4390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood if (info->mKeywords) 4400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putString(info->mKeywords); 4410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood else 4420cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.putEmptyString(); 4430cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4440cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) { 4450cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood MtpResponseCode ret = readResponse(); 4460cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood if (ret == MTP_RESPONSE_OK) { 4470cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood info->mStorageID = mResponse.getParameter(1); 4480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood info->mParent = mResponse.getParameter(2); 4490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood info->mHandle = mResponse.getParameter(3); 4500cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood return info->mHandle; 4510cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 4520cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 4530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood return (MtpObjectHandle)-1; 4540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood} 4550cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) { 4570cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 4580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood int remaining = info->mCompressedSize; 4600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mRequest.reset(); 4610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mRequest.setParameter(1, info->mHandle); 4620cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood if (sendRequest(MTP_OPERATION_SEND_OBJECT)) { 4630cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood // send data header 4640cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining); 4650cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4660cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood char buffer[65536]; 4670cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood while (remaining > 0) { 4680cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood int count = read(srcFD, buffer, sizeof(buffer)); 4690cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood if (count > 0) { 47042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood int written = mData.write(mRequestOut, buffer, count); 4710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood // FIXME check error 4720cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood remaining -= count; 4730cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } else { 4740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood break; 4750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 4760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 4770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 4780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood MtpResponseCode ret = readResponse(); 4790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood return (remaining == 0 && ret == MTP_RESPONSE_OK); 4800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood} 4810cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4826afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwoodbool MtpDevice::deleteObject(MtpObjectHandle handle) { 4830cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 4840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 4856afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood mRequest.reset(); 4866afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood mRequest.setParameter(1, handle); 4876afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) { 4886afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood MtpResponseCode ret = readResponse(); 4896afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood if (ret == MTP_RESPONSE_OK) 4906afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood return true; 4916afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood } 4926afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood return false; 4936afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood} 4946afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood 4956afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) { 4966afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood MtpObjectInfo* info = getObjectInfo(handle); 49731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root if (info) { 49831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root MtpObjectHandle parent = info->mParent; 49931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root delete info; 50031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root return parent; 50131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root } else { 5026afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood return -1; 50331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root } 5046afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood} 5053e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood 5066afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) { 5076afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood MtpObjectInfo* info = getObjectInfo(handle); 50831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root if (info) { 50931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root MtpObjectHandle storageId = info->mStorageID; 51031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root delete info; 51131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root return storageId; 51231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root } else { 5136afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood return -1; 51431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root } 5153e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood} 5163e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood 51798693f674125484de8873d969c209276a6dd604bMike LockwoodMtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) { 51898693f674125484de8873d969c209276a6dd604bMike Lockwood Mutex::Autolock autoLock(mMutex); 51998693f674125484de8873d969c209276a6dd604bMike Lockwood 52098693f674125484de8873d969c209276a6dd604bMike Lockwood mRequest.reset(); 52198693f674125484de8873d969c209276a6dd604bMike Lockwood mRequest.setParameter(1, format); 52298693f674125484de8873d969c209276a6dd604bMike Lockwood if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED)) 52398693f674125484de8873d969c209276a6dd604bMike Lockwood return NULL; 52498693f674125484de8873d969c209276a6dd604bMike Lockwood if (!readData()) 52598693f674125484de8873d969c209276a6dd604bMike Lockwood return NULL; 52698693f674125484de8873d969c209276a6dd604bMike Lockwood MtpResponseCode ret = readResponse(); 52798693f674125484de8873d969c209276a6dd604bMike Lockwood if (ret == MTP_RESPONSE_OK) { 52898693f674125484de8873d969c209276a6dd604bMike Lockwood return mData.getAUInt16(); 52998693f674125484de8873d969c209276a6dd604bMike Lockwood } 53098693f674125484de8873d969c209276a6dd604bMike Lockwood return NULL; 53198693f674125484de8873d969c209276a6dd604bMike Lockwood 53298693f674125484de8873d969c209276a6dd604bMike Lockwood} 53398693f674125484de8873d969c209276a6dd604bMike Lockwood 534a6c490b8b2d96ebaab632286029463f932ae3b6bMike LockwoodMtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) { 5350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood Mutex::Autolock autoLock(mMutex); 5360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 537a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood mRequest.reset(); 538a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood mRequest.setParameter(1, code); 539a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC)) 540a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood return NULL; 541a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood if (!readData()) 542a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood return NULL; 543a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood MtpResponseCode ret = readResponse(); 544a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood if (ret == MTP_RESPONSE_OK) { 545a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood MtpProperty* property = new MtpProperty; 546e3e76c456baee122de6715ae280130abaddc906cMike Lockwood property->read(mData); 547a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood return property; 548a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood } 549a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood return NULL; 550a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood} 551a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood 55299e393a39a31bfbdeb435462939519e2d0279433Mike LockwoodMtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) { 55398693f674125484de8873d969c209276a6dd604bMike Lockwood Mutex::Autolock autoLock(mMutex); 55498693f674125484de8873d969c209276a6dd604bMike Lockwood 55598693f674125484de8873d969c209276a6dd604bMike Lockwood mRequest.reset(); 55698693f674125484de8873d969c209276a6dd604bMike Lockwood mRequest.setParameter(1, code); 55799e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood mRequest.setParameter(2, format); 55898693f674125484de8873d969c209276a6dd604bMike Lockwood if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC)) 55998693f674125484de8873d969c209276a6dd604bMike Lockwood return NULL; 56098693f674125484de8873d969c209276a6dd604bMike Lockwood if (!readData()) 56198693f674125484de8873d969c209276a6dd604bMike Lockwood return NULL; 56298693f674125484de8873d969c209276a6dd604bMike Lockwood MtpResponseCode ret = readResponse(); 56398693f674125484de8873d969c209276a6dd604bMike Lockwood if (ret == MTP_RESPONSE_OK) { 56498693f674125484de8873d969c209276a6dd604bMike Lockwood MtpProperty* property = new MtpProperty; 56598693f674125484de8873d969c209276a6dd604bMike Lockwood property->read(mData); 56698693f674125484de8873d969c209276a6dd604bMike Lockwood return property; 56798693f674125484de8873d969c209276a6dd604bMike Lockwood } 56898693f674125484de8873d969c209276a6dd604bMike Lockwood return NULL; 56998693f674125484de8873d969c209276a6dd604bMike Lockwood} 57098693f674125484de8873d969c209276a6dd604bMike Lockwood 57123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, 57223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood bool (* callback)(void* data, int offset, int length, void* clientData), 57323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood int objectSize, void* clientData) { 57423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood Mutex::Autolock autoLock(mMutex); 57523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood bool result = false; 57623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 57723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood mRequest.reset(); 57823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood mRequest.setParameter(1, handle); 57923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (sendRequest(MTP_OPERATION_GET_OBJECT) 58023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood && mData.readDataHeader(mRequestIn1)) { 58123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood uint32_t length = mData.getContainerLength(); 58223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) { 58323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("readObject error objectSize: %d, length: %d", 58423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood objectSize, length); 58523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood goto fail; 58623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 58723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood length -= MTP_CONTAINER_HEADER_SIZE; 58823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood uint32_t remaining = length; 58923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood int offset = 0; 59023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 59123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood int initialDataLength = 0; 59223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood void* initialData = mData.getData(initialDataLength); 59323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (initialData) { 59423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (initialDataLength > 0) { 59523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (!callback(initialData, 0, initialDataLength, clientData)) 59623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood goto fail; 59723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood remaining -= initialDataLength; 59823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood offset += initialDataLength; 59923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 60023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood free(initialData); 60123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 60223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 60323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // USB reads greater than 16K don't work 60423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood char buffer1[16384], buffer2[16384]; 60523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood mRequestIn1->buffer = buffer1; 60623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood mRequestIn2->buffer = buffer2; 60723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood struct usb_request* req = mRequestIn1; 60823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood void* writeBuffer = NULL; 60923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood int writeLength = 0; 61023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 61123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood while (remaining > 0 || writeBuffer) { 61223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (remaining > 0) { 61323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // queue up a read request 61423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining); 61523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (mData.readDataAsync(req)) { 61623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("readDataAsync failed"); 61723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood goto fail; 61823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 61923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else { 62023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood req = NULL; 62123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 62223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 62323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (writeBuffer) { 62423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // write previous buffer 62523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (!callback(writeBuffer, offset, writeLength, clientData)) { 62623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood LOGE("write failed"); 62723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // wait for pending read before failing 62823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (req) 62923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood mData.readDataWait(mDevice); 63023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood goto fail; 63123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 63223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood offset += writeLength; 63323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeBuffer = NULL; 63423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 63523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 63623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood // wait for read to complete 63723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (req) { 63823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood int read = mData.readDataWait(mDevice); 63923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (read < 0) 64023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood goto fail; 64123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 64223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (read > 0) { 64323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeBuffer = req->buffer; 64423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeLength = read; 64523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood remaining -= read; 64623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1); 64723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else { 64823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeBuffer = NULL; 64923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 65023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 65123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 65223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 65323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood MtpResponseCode response = readResponse(); 65423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (response == MTP_RESPONSE_OK) 65523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood result = true; 65623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 65723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 65823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodfail: 65923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood return result; 66023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood} 66123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 66223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood 663b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood// reads the object's data and writes it to the specified file path 66427afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) { 665b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood LOGD("readObject: %s", destPath); 666b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC); 667b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (fd < 0) { 668b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood LOGE("open failed for %s", destPath); 669b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood return false; 6700cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 6710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 67227afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood fchown(fd, getuid(), group); 67327afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood // set permissions 67427afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood int mask = umask(0); 67527afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood fchmod(fd, perm); 67627afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood umask(mask); 67727afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood 678b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood Mutex::Autolock autoLock(mMutex); 679b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood bool result = false; 6800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 681b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood mRequest.reset(); 682b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood mRequest.setParameter(1, handle); 683b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (sendRequest(MTP_OPERATION_GET_OBJECT) 68442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood && mData.readDataHeader(mRequestIn1)) { 685b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood uint32_t length = mData.getContainerLength(); 686b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (length < MTP_CONTAINER_HEADER_SIZE) 687b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood goto fail; 688b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood length -= MTP_CONTAINER_HEADER_SIZE; 689b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood uint32_t remaining = length; 690b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood 691b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood int initialDataLength = 0; 692b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood void* initialData = mData.getData(initialDataLength); 693b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (initialData) { 694b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (initialDataLength > 0) { 69531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root if (write(fd, initialData, initialDataLength) != initialDataLength) { 69631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root free(initialData); 697b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood goto fail; 69831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root } 699b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood remaining -= initialDataLength; 7000cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 701b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood free(initialData); 7020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 7030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 704b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood // USB reads greater than 16K don't work 705b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood char buffer1[16384], buffer2[16384]; 70642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIn1->buffer = buffer1; 70742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mRequestIn2->buffer = buffer2; 70842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood struct usb_request* req = mRequestIn1; 70942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood void* writeBuffer = NULL; 710b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood int writeLength = 0; 711b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood 712b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood while (remaining > 0 || writeBuffer) { 713b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (remaining > 0) { 714b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood // queue up a read request 71542d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining); 71642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood if (mData.readDataAsync(req)) { 717b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood LOGE("readDataAsync failed"); 718b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood goto fail; 719b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood } 7200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } else { 72142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood req = NULL; 7220cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 7230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 724b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (writeBuffer) { 725b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood // write previous buffer 726b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (write(fd, writeBuffer, writeLength) != writeLength) { 727b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood LOGE("write failed"); 728b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood // wait for pending read before failing 72942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood if (req) 73042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood mData.readDataWait(mDevice); 731b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood goto fail; 732b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood } 733b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood writeBuffer = NULL; 734b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood } 7350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 736b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood // wait for read to complete 73742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood if (req) { 73842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood int read = mData.readDataWait(mDevice); 739b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (read < 0) 740b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood goto fail; 7410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 74223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood if (read > 0) { 74323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeBuffer = req->buffer; 74423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeLength = read; 74523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood remaining -= read; 74623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1); 74723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } else { 74823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood writeBuffer = NULL; 74923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood } 750b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood } 751b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood } 752b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood 753b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood MtpResponseCode response = readResponse(); 754b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood if (response == MTP_RESPONSE_OK) 755b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood result = true; 7560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood } 757b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood 758b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwoodfail: 759b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood ::close(fd); 760b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood return result; 7610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood} 762a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood 7635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::sendRequest(MtpOperationCode operation) { 764f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood LOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation)); 765f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood mReceivedResponse = false; 7665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setOperationCode(operation); 7675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (mTransactionID > 0) 7685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.setTransactionID(mTransactionID++); 76942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood int ret = mRequest.write(mRequestOut); 7705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mRequest.dump(); 7715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return (ret > 0); 7725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 7735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 7740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendData() { 775f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood LOGV("sendData\n"); 7765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mData.setOperationCode(mRequest.getOperationCode()); 7775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mData.setTransactionID(mRequest.getTransactionID()); 77842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood int ret = mData.write(mRequestOut); 7795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mData.dump(); 7805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return (ret > 0); 7815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 7825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 7835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::readData() { 7845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mData.reset(); 78542d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood int ret = mData.read(mRequestIn1); 786f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood LOGV("readData returned %d\n", ret); 7875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret >= MTP_CONTAINER_HEADER_SIZE) { 788f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) { 789f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood LOGD("got response packet instead of data packet"); 790f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood // we got a response packet rather than data 791f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood // copy it to mResponse 792f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood mResponse.copyFrom(mData); 793f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood mReceivedResponse = true; 794f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood return false; 795f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood } 7965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mData.dump(); 7975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return true; 7985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 7995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood else { 800f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood LOGV("readResponse failed\n"); 8015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return false; 8025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 8035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 8045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 8050cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) { 8060cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.setOperationCode(operation); 8070cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood mData.setTransactionID(mRequest.getTransactionID()); 80842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood return (!mData.writeDataHeader(mRequestOut, dataLength)); 8090cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood} 8100cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood 8115ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpResponseCode MtpDevice::readResponse() { 812f43c641bf3f8bcb5748f4ae504d434896edc94f5Mike Lockwood LOGV("readResponse\n"); 813f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood if (mReceivedResponse) { 814f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood mReceivedResponse = false; 815f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood return mResponse.getResponseCode(); 816f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood } 81742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood int ret = mResponse.read(mRequestIn1); 8185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood if (ret >= MTP_CONTAINER_HEADER_SIZE) { 8195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood mResponse.dump(); 8205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return mResponse.getResponseCode(); 821f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood } else { 822a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood LOGD("readResponse failed\n"); 8235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood return -1; 8245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood } 8255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} 8265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood 8275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood} // namespace android 828