MtpDevice.cpp revision 8023f3af62795b7816f36a9423f8e0a39e616e49
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
41d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood#if 0
4223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodstatic bool isMtpDevice(uint16_t vendor, uint16_t product) {
4323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    // Sandisk Sansa Fuze
4423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (vendor == 0x0781 && product == 0x74c2)
4523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        return true;
4623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    // Samsung YP-Z5
4723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (vendor == 0x04e8 && product == 0x503c)
4823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        return true;
4923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return false;
5023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
51d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood#endif
5223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
5323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike LockwoodMtpDevice* MtpDevice::open(const char* deviceName, int fd) {
5423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    struct usb_device *device = usb_device_new(deviceName, fd);
5523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (!device) {
5629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("usb_device_new failed for %s", deviceName);
5723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        return NULL;
5823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
5923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
6023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    struct usb_descriptor_header* desc;
6123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    struct usb_descriptor_iter iter;
6223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
6323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    usb_descriptor_iter_init(device, &iter);
6423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
6523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
6623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (desc->bDescriptorType == USB_DT_INTERFACE) {
6723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
6823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
6923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE &&
7023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                interface->bInterfaceSubClass == 1 && // Still Image Capture
7123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                interface->bInterfaceProtocol == 1)     // Picture Transfer Protocol (PIMA 15470)
7223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            {
7331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* manufacturerName = usb_device_get_manufacturer_name(device);
7431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* productName = usb_device_get_product_name(device);
75b8a805261bf0282e992d3608035e47d05a898710Steve Block                ALOGD("Found camera: \"%s\" \"%s\"\n", manufacturerName, productName);
7631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(manufacturerName);
7731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(productName);
7823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            } else if (interface->bInterfaceClass == 0xFF &&
7923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    interface->bInterfaceSubClass == 0xFF &&
8023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    interface->bInterfaceProtocol == 0) {
8123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                char* interfaceName = usb_device_get_string(device, interface->iInterface);
8231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                if (!interfaceName) {
8323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    continue;
8431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                } else if (strcmp(interfaceName, "MTP")) {
8531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    free(interfaceName);
8631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    continue;
8731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                }
8831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(interfaceName);
8931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root
9023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // Looks like an android style MTP device
9131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* manufacturerName = usb_device_get_manufacturer_name(device);
9231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* productName = usb_device_get_product_name(device);
93b8a805261bf0282e992d3608035e47d05a898710Steve Block                ALOGD("Found MTP device: \"%s\" \"%s\"\n", manufacturerName, productName);
9431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(manufacturerName);
9531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(productName);
96d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood            }
97d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood#if 0
98d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood             else {
9923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // look for special cased devices based on vendor/product ID
10023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // we are doing this mainly for testing purposes
10123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                uint16_t vendor = usb_device_get_vendor_id(device);
10223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                uint16_t product = usb_device_get_product_id(device);
10323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!isMtpDevice(vendor, product)) {
10423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    // not an MTP or PTP device
10523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    continue;
10623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
10723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // request MTP OS string and descriptor
10823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // some music players need to see this before entering MTP mode.
10923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                char buffer[256];
11023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                memset(buffer, 0, sizeof(buffer));
111f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                int ret = usb_device_control_transfer(device,
11223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD,
11323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE,
114f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                        0, buffer, sizeof(buffer), 0);
115f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                printf("usb_device_control_transfer returned %d errno: %d\n", ret, errno);
11623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (ret > 0) {
11723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("got MTP string %s\n", buffer);
118f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                    ret = usb_device_control_transfer(device,
11923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                            USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1,
120f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                            0, 4, buffer, sizeof(buffer), 0);
12123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("OS descriptor got %d\n", ret);
12223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
12323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("no MTP string\n");
12423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
12523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
126d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood#endif
12723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // if we got here, then we have a likely MTP or PTP device
12823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
12923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // interface should be followed by three endpoints
13023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep;
13123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_in_desc = NULL;
13223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_out_desc = NULL;
13323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_intr_desc = NULL;
1348023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang            //USB3 add USB_DT_SS_ENDPOINT_COMP as companion descriptor;
1358023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang            struct usb_ss_ep_comp_descriptor *ep_ss_ep_comp_desc = NULL;
13623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            for (int i = 0; i < 3; i++) {
13723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
1388023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang                if (ep && ep->bDescriptorType == USB_DT_SS_ENDPOINT_COMP) {
1398023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang                    ALOGD("Descriptor type is USB_DT_SS_ENDPOINT_COMP for USB3 \n");
1408023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang                    ep_ss_ep_comp_desc = (usb_ss_ep_comp_descriptor*)ep;
1418023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang                    ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
1428023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang                 }
1438023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang
14423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
14529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("endpoints not found\n");
14631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    usb_device_close(device);
14723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    return NULL;
14823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
1498023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang
15023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
15123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
15223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_in_desc = ep;
15323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    else
15423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_out_desc = ep;
15523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT &&
15623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
15723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    ep_intr_desc = ep;
15823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
15923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
16023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
16129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("endpoints not found\n");
16231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                usb_device_close(device);
16323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                return NULL;
16423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
16523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
16623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
16729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("usb_device_claim_interface failed errno: %d\n", errno);
16831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                usb_device_close(device);
16923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                return NULL;
17023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
17123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
17223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber,
17323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_in_desc, ep_out_desc, ep_intr_desc);
17423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            mtpDevice->initialize();
17523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            return mtpDevice;
17623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
17723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
17823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
17923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    usb_device_close(device);
18029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block    ALOGE("device not found");
18123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return NULL;
18223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
18323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
1845ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::MtpDevice(struct usb_device* device, int interface,
18542d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_in,
18642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_out,
18742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_intr)
1885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    :   mDevice(device),
1895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mInterface(interface),
19042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn1(NULL),
19142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn2(NULL),
19242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestOut(NULL),
19342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIntr(NULL),
1945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDeviceInfo(NULL),
1955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mSessionID(0),
196f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mTransactionID(0),
197f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mReceivedResponse(false)
1985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood{
19942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIn1 = usb_request_new(device, ep_in);
20042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIn2 = usb_request_new(device, ep_in);
20142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestOut = usb_request_new(device, ep_out);
20242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIntr = usb_request_new(device, ep_intr);
2035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2055ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::~MtpDevice() {
2065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    close();
2073ab368e0810d894dcbc0971350c095049478a055Mark Salyzyn    for (size_t i = 0; i < mDeviceProperties.size(); i++)
208a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        delete mDeviceProperties[i];
20942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIn1);
21042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIn2);
21142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestOut);
21242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIntr);
2135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::initialize() {
2165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    openSession();
2175ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mDeviceInfo = getDeviceInfo();
2185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDeviceInfo) {
219a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        if (mDeviceInfo->mDeviceProperties) {
220a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
221a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            for (int i = 0; i < count; i++) {
222a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
223a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
2240c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property)
225a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                    mDeviceProperties.push(property);
226a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            }
227a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        }
2285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::close() {
2325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice) {
2335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_release_interface(mDevice, mInterface);
2345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_close(mDevice);
2355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDevice = NULL;
2365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2390c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwoodvoid MtpDevice::print() {
2400c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo) {
2410c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        mDeviceInfo->print();
2420c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2430c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        if (mDeviceInfo->mDeviceProperties) {
244df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("***** DEVICE PROPERTIES *****\n");
2450c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
2460c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            for (int i = 0; i < count; i++) {
2470c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
2480c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
2490c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property) {
2500c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    property->print();
25131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    delete property;
2520c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
2530c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
2540c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
2550c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
2560c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2570c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo->mPlaybackFormats) {
258df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("***** OBJECT PROPERTIES *****\n");
2590c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        int count = mDeviceInfo->mPlaybackFormats->size();
2600c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        for (int i = 0; i < count; i++) {
2610c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i];
262df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format));
2630c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectPropertyList* props = getObjectPropsSupported(format);
2640c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            if (props) {
2653ab368e0810d894dcbc0971350c095049478a055Mark Salyzyn                for (size_t j = 0; j < props->size(); j++) {
2660c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    MtpObjectProperty prop = (*props)[j];
26799e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood                    MtpProperty* property = getObjectPropDesc(prop, format);
26831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    if (property) {
2690c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                        property->print();
27031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                        delete property;
27131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    } else {
27229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                        ALOGE("could not fetch property: %s",
2730c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                                MtpDebug::getObjectPropCodeName(prop));
27431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    }
2750c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
2760c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
2770c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
2780c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
2790c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood}
2800c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodconst char* MtpDevice::getDeviceName() {
2825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice)
2835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return usb_device_get_name(mDevice);
2845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else
2855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return "???";
2865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::openSession() {
2890cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
2900cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
2915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = 0;
2925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 0;
2935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpSessionID newSession = 1;
2945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
2955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, newSession);
2965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
2975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
2985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
2995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
3005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        newSession = mResponse.getParameter(1);
3015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else if (ret != MTP_RESPONSE_OK)
3025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
3035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = newSession;
3055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 1;
3065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
3075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::closeSession() {
3105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    // FIXME
3115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
3125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3145ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDeviceInfo* MtpDevice::getDeviceInfo() {
3150cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3175ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
3195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpDeviceInfo* info = new MtpDeviceInfo;
3255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
3265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
3275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3315ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageIDList* MtpDevice::getStorageIDs() {
3320cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
3365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
3425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3465ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
3470cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
3515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
3525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpStorageInfo* info = new MtpStorageInfo(storageID);
3585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
3595ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
3605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3645ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
3655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            MtpObjectFormat format, MtpObjectHandle parent) {
3660cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3670cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
3705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(2, format);
3715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(3, parent);
3725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
3735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
3795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3835ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
3840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3850cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3866afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    // FIXME - we might want to add some caching here
3876afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
3885ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, handle);
3905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
3915ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpObjectInfo* info = new MtpObjectInfo(handle);
3975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        info->read(mData);
3985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return info;
3995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
4005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
4015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
4025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
4033e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwoodvoid* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
4040cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4050cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4063e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.reset();
4073e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.setParameter(1, handle);
4083e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
4093e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        MtpResponseCode ret = readResponse();
4103e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
4113e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood            return mData.getData(outLength);
4123e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        }
4133e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    }
4143e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    outLength = 0;
4153e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    return NULL;
4166afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
4176afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
4180cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike LockwoodMtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
4190cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4210cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
4220cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpObjectHandle parent = info->mParent;
4230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (parent == 0)
4240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        parent = MTP_PARENT_ROOT;
4250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mStorageID);
4270cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(2, info->mParent);
4280cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mStorageID);
4300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mFormat);
4310cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mProtectionStatus);
4320cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mCompressedSize);
4330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mThumbFormat);
4340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbCompressedSize);
4350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixWidth);
4360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixHeight);
4370cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixWidth);
4380cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixHeight);
4390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixDepth);
4400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mParent);
4410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mAssociationType);
4420cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mAssociationDesc);
4430cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mSequenceNumber);
4440cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(info->mName);
4450cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4460cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    char created[100], modified[100];
4470cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateCreated, created, sizeof(created));
4480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateModified, modified, sizeof(modified));
4490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4500cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(created);
4510cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(modified);
4520cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (info->mKeywords)
4530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putString(info->mKeywords);
4540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    else
4550cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putEmptyString();
4560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4570cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood   if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
4580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        MtpResponseCode ret = readResponse();
4590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
4600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mStorageID = mResponse.getParameter(1);
4610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mParent = mResponse.getParameter(2);
4620cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mHandle = mResponse.getParameter(3);
4630cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            return info->mHandle;
4640cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4650cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
4660cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (MtpObjectHandle)-1;
4670cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
4680cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4690cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
4700cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4720cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    int remaining = info->mCompressedSize;
4730cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
4740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mHandle);
4750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
4760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        // send data header
4770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
4780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        char buffer[65536];
4800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        while (remaining > 0) {
4810cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            int count = read(srcFD, buffer, sizeof(buffer));
4820cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            if (count > 0) {
48342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                int written = mData.write(mRequestOut, buffer, count);
4840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                // FIXME check error
4850cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                remaining -= count;
4860cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
4870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                break;
4880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
4890cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4900cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
4910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpResponseCode ret = readResponse();
4920cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (remaining == 0 && ret == MTP_RESPONSE_OK);
4930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
4940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4956afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwoodbool MtpDevice::deleteObject(MtpObjectHandle handle) {
4960cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4970cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4986afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.reset();
4996afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.setParameter(1, handle);
5006afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
5016afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        MtpResponseCode ret = readResponse();
5026afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        if (ret == MTP_RESPONSE_OK)
5036afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood            return true;
5046afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    }
5056afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    return false;
5066afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
5076afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
5086afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
5096afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
51031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    if (info) {
51131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        MtpObjectHandle parent = info->mParent;
51231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        delete info;
51331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        return parent;
51431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    } else {
5156afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
51631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    }
5176afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
5183e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
5196afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
5206afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
52131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    if (info) {
52231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        MtpObjectHandle storageId = info->mStorageID;
52331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        delete info;
52431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        return storageId;
52531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    } else {
5266afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
52731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    }
5283e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood}
5293e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
53098693f674125484de8873d969c209276a6dd604bMike LockwoodMtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
53198693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
53298693f674125484de8873d969c209276a6dd604bMike Lockwood
53398693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
53498693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, format);
53598693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED))
53698693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
53798693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
53898693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
53998693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
54098693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
54198693f674125484de8873d969c209276a6dd604bMike Lockwood        return mData.getAUInt16();
54298693f674125484de8873d969c209276a6dd604bMike Lockwood    }
54398693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
54498693f674125484de8873d969c209276a6dd604bMike Lockwood
54598693f674125484de8873d969c209276a6dd604bMike Lockwood}
54698693f674125484de8873d969c209276a6dd604bMike Lockwood
547a6c490b8b2d96ebaab632286029463f932ae3b6bMike LockwoodMtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
5480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
5490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
550a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.reset();
551a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.setParameter(1, code);
552a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
553a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
554a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!readData())
555a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
556a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    MtpResponseCode ret = readResponse();
557a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
558a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        MtpProperty* property = new MtpProperty;
559e3e76c456baee122de6715ae280130abaddc906cMike Lockwood        property->read(mData);
560a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return property;
561a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    }
562a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    return NULL;
563a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood}
564a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
56599e393a39a31bfbdeb435462939519e2d0279433Mike LockwoodMtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
56698693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
56798693f674125484de8873d969c209276a6dd604bMike Lockwood
56898693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
56998693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, code);
57099e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood    mRequest.setParameter(2, format);
57198693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC))
57298693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
57398693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
57498693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
57598693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
57698693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
57798693f674125484de8873d969c209276a6dd604bMike Lockwood        MtpProperty* property = new MtpProperty;
57898693f674125484de8873d969c209276a6dd604bMike Lockwood        property->read(mData);
57998693f674125484de8873d969c209276a6dd604bMike Lockwood        return property;
58098693f674125484de8873d969c209276a6dd604bMike Lockwood    }
58198693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
58298693f674125484de8873d969c209276a6dd604bMike Lockwood}
58398693f674125484de8873d969c209276a6dd604bMike Lockwood
58423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle,
58523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        bool (* callback)(void* data, int offset, int length, void* clientData),
58623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int objectSize, void* clientData) {
58723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    Mutex::Autolock autoLock(mMutex);
58823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    bool result = false;
58923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
59023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    mRequest.reset();
59123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    mRequest.setParameter(1, handle);
59223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
59323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            && mData.readDataHeader(mRequestIn1)) {
59423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        uint32_t length = mData.getContainerLength();
59523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) {
59629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("readObject error objectSize: %d, length: %d",
59723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    objectSize, length);
59823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            goto fail;
59923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
60023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
60123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        uint32_t remaining = length;
60223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int offset = 0;
60323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
60423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int initialDataLength = 0;
60523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        void* initialData = mData.getData(initialDataLength);
60623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (initialData) {
60723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (initialDataLength > 0) {
60823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!callback(initialData, 0, initialDataLength, clientData))
60923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
61023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                remaining -= initialDataLength;
61123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                offset += initialDataLength;
61223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
61323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            free(initialData);
61423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
61523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
61623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        // USB reads greater than 16K don't work
61723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        char buffer1[16384], buffer2[16384];
61823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        mRequestIn1->buffer = buffer1;
61923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        mRequestIn2->buffer = buffer2;
62023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        struct usb_request* req = mRequestIn1;
62123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        void* writeBuffer = NULL;
62223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int writeLength = 0;
62323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
62423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        while (remaining > 0 || writeBuffer) {
62523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (remaining > 0) {
62623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // queue up a read request
62723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
62823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (mData.readDataAsync(req)) {
62929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("readDataAsync failed");
63023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
63123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
63223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            } else {
63323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                req = NULL;
63423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
63523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
63623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (writeBuffer) {
63723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // write previous buffer
63823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!callback(writeBuffer, offset, writeLength, clientData)) {
63929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("write failed");
64023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    // wait for pending read before failing
64123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    if (req)
64223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        mData.readDataWait(mDevice);
64323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
64423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
64523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                offset += writeLength;
64623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                writeBuffer = NULL;
64723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
64823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
64923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // wait for read to complete
65023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (req) {
65123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                int read = mData.readDataWait(mDevice);
65223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read < 0)
65323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
65423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
65523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read > 0) {
65623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = req->buffer;
65723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeLength = read;
65823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    remaining -= read;
65923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
66023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
66123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = NULL;
66223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
66323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
66423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
66523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
66623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        MtpResponseCode response = readResponse();
66723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (response == MTP_RESPONSE_OK)
66823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            result = true;
66923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
67023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
67123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodfail:
67223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return result;
67323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
67423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
67523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
676b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood// reads the object's data and writes it to the specified file path
67727afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
678b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("readObject: %s", destPath);
679af8e8aa1ada2948972555592570ec9ad90cbf372Nick Kralevich    int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
680b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (fd < 0) {
68129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("open failed for %s", destPath);
682b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        return false;
6830cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
6840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
68527afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchown(fd, getuid(), group);
68627afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    // set permissions
68727afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    int mask = umask(0);
68827afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchmod(fd, perm);
68927afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    umask(mask);
69027afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood
691b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    Mutex::Autolock autoLock(mMutex);
692b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    bool result = false;
6930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
694b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.reset();
695b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.setParameter(1, handle);
696b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
69742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            && mData.readDataHeader(mRequestIn1)) {
698b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t length = mData.getContainerLength();
699b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (length < MTP_CONTAINER_HEADER_SIZE)
700b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            goto fail;
701b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
702b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t remaining = length;
703b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
704b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int initialDataLength = 0;
705b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        void* initialData = mData.getData(initialDataLength);
706b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (initialData) {
707b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (initialDataLength > 0) {
70831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                if (write(fd, initialData, initialDataLength) != initialDataLength) {
70931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    free(initialData);
710b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
71131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                }
712b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                remaining -= initialDataLength;
7130cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
714b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            free(initialData);
7150cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
7160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
717b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        // USB reads greater than 16K don't work
718b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char buffer1[16384], buffer2[16384];
71942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn1->buffer = buffer1;
72042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn2->buffer = buffer2;
72142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        struct usb_request* req = mRequestIn1;
72242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        void* writeBuffer = NULL;
723b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int writeLength = 0;
724b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
725b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        while (remaining > 0 || writeBuffer) {
726b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (remaining > 0) {
727b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // queue up a read request
72842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
72942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                if (mData.readDataAsync(req)) {
73029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("readDataAsync failed");
731b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
732b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
7330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
73442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                req = NULL;
7350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
7360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
737b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (writeBuffer) {
738b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // write previous buffer
739b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, writeBuffer, writeLength) != writeLength) {
74029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("write failed");
741b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    // wait for pending read before failing
74242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                    if (req)
74342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                        mData.readDataWait(mDevice);
744b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
745b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
746b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeBuffer = NULL;
747b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
7480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
749b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            // wait for read to complete
75042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            if (req) {
75142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                int read = mData.readDataWait(mDevice);
752b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (read < 0)
753b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
7540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
75523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read > 0) {
75623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = req->buffer;
75723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeLength = read;
75823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    remaining -= read;
75923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
76023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
76123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = NULL;
76223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
763b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
764b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        }
765b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
766b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        MtpResponseCode response = readResponse();
767b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (response == MTP_RESPONSE_OK)
768b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            result = true;
7690cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
770b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
771b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwoodfail:
772b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    ::close(fd);
773b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    return result;
7740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
775a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
7765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::sendRequest(MtpOperationCode operation) {
7773856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
778f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    mReceivedResponse = false;
7795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setOperationCode(operation);
7805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mTransactionID > 0)
7815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mRequest.setTransactionID(mTransactionID++);
78242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mRequest.write(mRequestOut);
7835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.dump();
7845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
7855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
7865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
7870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendData() {
7883856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendData\n");
7895ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
7905ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
79142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mData.write(mRequestOut);
7925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.dump();
7935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
7945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
7955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
7965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::readData() {
7975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.reset();
79842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mData.read(mRequestIn1);
7993856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("readData returned %d\n", ret);
8005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
801f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
802b8a805261bf0282e992d3608035e47d05a898710Steve Block            ALOGD("got response packet instead of data packet");
803f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // we got a response packet rather than data
804f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // copy it to mResponse
805f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mResponse.copyFrom(mData);
806f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mReceivedResponse = true;
807f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            return false;
808f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        }
8095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mData.dump();
8105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return true;
8115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
8125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else {
8133856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("readResponse failed\n");
8145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
8155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
8165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
8175ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
8180cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
8190cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setOperationCode(operation);
8200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
82142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    return (!mData.writeDataHeader(mRequestOut, dataLength));
8220cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
8230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
8245ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpResponseCode MtpDevice::readResponse() {
8253856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("readResponse\n");
826f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    if (mReceivedResponse) {
827f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mReceivedResponse = false;
828f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        return mResponse.getResponseCode();
829f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    }
83042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mResponse.read(mRequestIn1);
8313d74457b66533b170606347e60628e55a2af255eMike Lockwood    // handle zero length packets, which might occur if the data transfer
8323d74457b66533b170606347e60628e55a2af255eMike Lockwood    // ends on a packet boundary
8333d74457b66533b170606347e60628e55a2af255eMike Lockwood    if (ret == 0)
8343d74457b66533b170606347e60628e55a2af255eMike Lockwood        ret = mResponse.read(mRequestIn1);
8355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
8365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mResponse.dump();
8375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mResponse.getResponseCode();
838f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    } else {
839b8a805261bf0282e992d3608035e47d05a898710Steve Block        ALOGD("readResponse failed\n");
8405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return -1;
8415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
8425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
8435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
8445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}  // namespace android
845