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;
325ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        if (info->read(mData))
326ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            return info;
327ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        else
328ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            delete info;
3295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3335ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageIDList* MtpDevice::getStorageIDs() {
3340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
3385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
3445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3485ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
3490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3500cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
3535ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
3545ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3595ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpStorageInfo* info = new MtpStorageInfo(storageID);
360ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        if (info->read(mData))
361ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            return info;
362ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        else
363ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            delete info;
3645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3685ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
3695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            MtpObjectFormat format, MtpObjectHandle parent) {
3700cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
3745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(2, format);
3755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(3, parent);
3765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
3775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
3835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3875ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
3880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3890cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3906afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    // FIXME - we might want to add some caching here
3916afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
3925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, handle);
3945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
3955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3965ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3985ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3995ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
4005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpObjectInfo* info = new MtpObjectInfo(handle);
401ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        if (info->read(mData))
402ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            return info;
403ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        else
404ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            delete info;
4055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
4065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
4075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
4085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
4093e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwoodvoid* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
4100cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4110cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4123e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.reset();
4133e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.setParameter(1, handle);
4143e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
4153e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        MtpResponseCode ret = readResponse();
4163e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
4173e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood            return mData.getData(outLength);
4183e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        }
4193e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    }
4203e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    outLength = 0;
4213e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    return NULL;
4226afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
4236afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
4240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike LockwoodMtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
4250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4270cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
4280cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpObjectHandle parent = info->mParent;
4290cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (parent == 0)
4300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        parent = MTP_PARENT_ROOT;
4310cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4320cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mStorageID);
4330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(2, info->mParent);
4340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mStorageID);
4360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mFormat);
4370cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mProtectionStatus);
4380cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mCompressedSize);
4390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mThumbFormat);
4400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbCompressedSize);
4410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixWidth);
4420cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixHeight);
4430cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixWidth);
4440cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixHeight);
4450cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixDepth);
4460cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mParent);
4470cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mAssociationType);
4480cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mAssociationDesc);
4490cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mSequenceNumber);
4500cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(info->mName);
4510cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4520cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    char created[100], modified[100];
4530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateCreated, created, sizeof(created));
4540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateModified, modified, sizeof(modified));
4550cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(created);
4570cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(modified);
4580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (info->mKeywords)
4590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putString(info->mKeywords);
4600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    else
4610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putEmptyString();
4620cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4630cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood   if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
4640cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        MtpResponseCode ret = readResponse();
4650cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
4660cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mStorageID = mResponse.getParameter(1);
4670cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mParent = mResponse.getParameter(2);
4680cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mHandle = mResponse.getParameter(3);
4690cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            return info->mHandle;
4700cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
4720cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (MtpObjectHandle)-1;
4730cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
4740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
4760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    int remaining = info->mCompressedSize;
4790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
4800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mHandle);
4810cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
4820cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        // send data header
4830cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
4840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4850cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        char buffer[65536];
4860cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        while (remaining > 0) {
4870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            int count = read(srcFD, buffer, sizeof(buffer));
4880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            if (count > 0) {
48942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                int written = mData.write(mRequestOut, buffer, count);
4900cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                // FIXME check error
4910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                remaining -= count;
4920cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
4930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                break;
4940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
4950cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
4960cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
4970cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpResponseCode ret = readResponse();
4980cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (remaining == 0 && ret == MTP_RESPONSE_OK);
4990cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
5000cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
5016afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwoodbool MtpDevice::deleteObject(MtpObjectHandle handle) {
5020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
5030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
5046afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.reset();
5056afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.setParameter(1, handle);
5066afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
5076afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        MtpResponseCode ret = readResponse();
5086afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        if (ret == MTP_RESPONSE_OK)
5096afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood            return true;
5106afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    }
5116afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    return false;
5126afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
5136afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
5146afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
5156afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
51631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    if (info) {
51731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        MtpObjectHandle parent = info->mParent;
51831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        delete info;
51931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        return parent;
52031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    } else {
5216afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
52231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    }
5236afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
5243e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
5256afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
5266afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
52731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    if (info) {
52831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        MtpObjectHandle storageId = info->mStorageID;
52931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        delete info;
53031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        return storageId;
53131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    } else {
5326afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
53331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    }
5343e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood}
5353e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
53698693f674125484de8873d969c209276a6dd604bMike LockwoodMtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
53798693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
53898693f674125484de8873d969c209276a6dd604bMike Lockwood
53998693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
54098693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, format);
54198693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED))
54298693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
54398693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
54498693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
54598693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
54698693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
54798693f674125484de8873d969c209276a6dd604bMike Lockwood        return mData.getAUInt16();
54898693f674125484de8873d969c209276a6dd604bMike Lockwood    }
54998693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
55098693f674125484de8873d969c209276a6dd604bMike Lockwood
55198693f674125484de8873d969c209276a6dd604bMike Lockwood}
55298693f674125484de8873d969c209276a6dd604bMike Lockwood
553a6c490b8b2d96ebaab632286029463f932ae3b6bMike LockwoodMtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
5540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
5550cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
556a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.reset();
557a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.setParameter(1, code);
558a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
559a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
560a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!readData())
561a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
562a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    MtpResponseCode ret = readResponse();
563a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
564a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        MtpProperty* property = new MtpProperty;
565ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        if (property->read(mData))
566ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            return property;
567ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        else
568ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            delete property;
569a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    }
570a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    return NULL;
571a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood}
572a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
57399e393a39a31bfbdeb435462939519e2d0279433Mike LockwoodMtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
57498693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
57598693f674125484de8873d969c209276a6dd604bMike Lockwood
57698693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
57798693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, code);
57899e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood    mRequest.setParameter(2, format);
57998693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC))
58098693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
58198693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
58298693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
58398693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
58498693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
58598693f674125484de8873d969c209276a6dd604bMike Lockwood        MtpProperty* property = new MtpProperty;
586ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        if (property->read(mData))
587ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            return property;
588ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        else
589ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            delete property;
59098693f674125484de8873d969c209276a6dd604bMike Lockwood    }
59198693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
59298693f674125484de8873d969c209276a6dd604bMike Lockwood}
59398693f674125484de8873d969c209276a6dd604bMike Lockwood
59423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle,
59523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        bool (* callback)(void* data, int offset, int length, void* clientData),
596ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        size_t objectSize, void* clientData) {
59723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    Mutex::Autolock autoLock(mMutex);
59823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    bool result = false;
59923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
60023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    mRequest.reset();
60123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    mRequest.setParameter(1, handle);
60223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
60323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            && mData.readDataHeader(mRequestIn1)) {
60423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        uint32_t length = mData.getContainerLength();
60523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) {
60629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("readObject error objectSize: %d, length: %d",
60723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    objectSize, length);
60823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            goto fail;
60923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
61023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
61123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        uint32_t remaining = length;
61223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int offset = 0;
61323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
61423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int initialDataLength = 0;
61523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        void* initialData = mData.getData(initialDataLength);
61623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (initialData) {
61723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (initialDataLength > 0) {
61823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!callback(initialData, 0, initialDataLength, clientData))
61923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
62023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                remaining -= initialDataLength;
62123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                offset += initialDataLength;
62223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
62323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            free(initialData);
62423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
62523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
62623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        // USB reads greater than 16K don't work
62723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        char buffer1[16384], buffer2[16384];
62823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        mRequestIn1->buffer = buffer1;
62923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        mRequestIn2->buffer = buffer2;
63023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        struct usb_request* req = mRequestIn1;
63123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        void* writeBuffer = NULL;
63223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        int writeLength = 0;
63323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
63423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        while (remaining > 0 || writeBuffer) {
63523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (remaining > 0) {
63623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // queue up a read request
63723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
63823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (mData.readDataAsync(req)) {
63929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("readDataAsync failed");
64023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
64123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
64223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            } else {
64323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                req = NULL;
64423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
64523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
64623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (writeBuffer) {
64723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // write previous buffer
64823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!callback(writeBuffer, offset, writeLength, clientData)) {
64929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("write failed");
65023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    // wait for pending read before failing
65123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    if (req)
65223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        mData.readDataWait(mDevice);
65323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
65423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
65523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                offset += writeLength;
65623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                writeBuffer = NULL;
65723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
65823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
65923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // wait for read to complete
66023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (req) {
66123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                int read = mData.readDataWait(mDevice);
66223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read < 0)
66323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    goto fail;
66423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
66523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read > 0) {
66623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = req->buffer;
66723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeLength = read;
66823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    remaining -= read;
66923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
67023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
67123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = NULL;
67223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
67323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
67423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
67523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
67623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        MtpResponseCode response = readResponse();
67723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (response == MTP_RESPONSE_OK)
67823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            result = true;
67923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
68023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
68123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodfail:
68223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return result;
68323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
68423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
68523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
686b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood// reads the object's data and writes it to the specified file path
68727afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
688b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("readObject: %s", destPath);
689af8e8aa1ada2948972555592570ec9ad90cbf372Nick Kralevich    int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
690b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (fd < 0) {
69129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("open failed for %s", destPath);
692b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        return false;
6930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
6940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
69527afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchown(fd, getuid(), group);
69627afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    // set permissions
69727afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    int mask = umask(0);
69827afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchmod(fd, perm);
69927afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    umask(mask);
70027afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood
701b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    Mutex::Autolock autoLock(mMutex);
702b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    bool result = false;
7030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
704b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.reset();
705b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.setParameter(1, handle);
706b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (sendRequest(MTP_OPERATION_GET_OBJECT)
70742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            && mData.readDataHeader(mRequestIn1)) {
708b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t length = mData.getContainerLength();
709b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (length < MTP_CONTAINER_HEADER_SIZE)
710b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            goto fail;
711b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        length -= MTP_CONTAINER_HEADER_SIZE;
712b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        uint32_t remaining = length;
713b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
714b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int initialDataLength = 0;
715b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        void* initialData = mData.getData(initialDataLength);
716b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (initialData) {
717b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (initialDataLength > 0) {
71831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                if (write(fd, initialData, initialDataLength) != initialDataLength) {
71931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    free(initialData);
720b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
72131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                }
722b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                remaining -= initialDataLength;
7230cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
724b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            free(initialData);
7250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
7260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
727b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        // USB reads greater than 16K don't work
728b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        char buffer1[16384], buffer2[16384];
72942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn1->buffer = buffer1;
73042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn2->buffer = buffer2;
73142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        struct usb_request* req = mRequestIn1;
73242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        void* writeBuffer = NULL;
733b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int writeLength = 0;
734b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
735b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        while (remaining > 0 || writeBuffer) {
736b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (remaining > 0) {
737b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // queue up a read request
73842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
73942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                if (mData.readDataAsync(req)) {
74029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("readDataAsync failed");
741b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
742b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
7430cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
74442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                req = NULL;
7450cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
7460cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
747b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (writeBuffer) {
748b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                // write previous buffer
749b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (write(fd, writeBuffer, writeLength) != writeLength) {
75029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("write failed");
751b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    // wait for pending read before failing
75242d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                    if (req)
75342d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                        mData.readDataWait(mDevice);
754b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
755b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                }
756b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                writeBuffer = NULL;
757b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
7580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
759b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            // wait for read to complete
76042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            if (req) {
76142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood                int read = mData.readDataWait(mDevice);
762b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                if (read < 0)
763b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood                    goto fail;
7640cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
76523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (read > 0) {
76623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = req->buffer;
76723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeLength = read;
76823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    remaining -= read;
76923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
77023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
77123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    writeBuffer = NULL;
77223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
773b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
774b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        }
775b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
776b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        MtpResponseCode response = readResponse();
777b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (response == MTP_RESPONSE_OK)
778b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            result = true;
7790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
780