MtpDevice.cpp revision 8d20945c08dfdd85c252c8ba92d197bf1bd2b208
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"
224fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono#include "MtpEventPacket.h"
23b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpObjectInfo.h"
24b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpProperty.h"
25b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpStorageInfo.h"
26b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "MtpStringBuffer.h"
270cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood#include "MtpUtils.h"
28a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <stdio.h>
305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <stdlib.h>
315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <sys/types.h>
325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <sys/ioctl.h>
335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <sys/stat.h>
345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <fcntl.h>
355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <errno.h>
360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood#include <endian.h>
375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood#include <usbhost/usbhost.h>
395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodnamespace android {
415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
42d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood#if 0
4323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodstatic bool isMtpDevice(uint16_t vendor, uint16_t product) {
4423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    // Sandisk Sansa Fuze
4523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (vendor == 0x0781 && product == 0x74c2)
4623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        return true;
4723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    // Samsung YP-Z5
4823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (vendor == 0x04e8 && product == 0x503c)
4923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        return true;
5023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return false;
5123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
52d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood#endif
5323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
544fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirononamespace {
554fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono
564a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hironobool writeToFd(void* data, uint32_t /* unused_offset */, uint32_t length, void* clientData) {
574fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    const int fd = *static_cast<int*>(clientData);
584a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    const ssize_t result = write(fd, data, length);
594a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    if (result < 0) {
604a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono        return false;
614a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    }
624a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    return static_cast<uint32_t>(result) == length;
634fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono}
644fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono
654a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono}  // namespace
664fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono
6723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike LockwoodMtpDevice* MtpDevice::open(const char* deviceName, int fd) {
6823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    struct usb_device *device = usb_device_new(deviceName, fd);
6923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    if (!device) {
7029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("usb_device_new failed for %s", deviceName);
7123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        return NULL;
7223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
7323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
7423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    struct usb_descriptor_header* desc;
7523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    struct usb_descriptor_iter iter;
7623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
7723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    usb_descriptor_iter_init(device, &iter);
7823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
7923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
8023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        if (desc->bDescriptorType == USB_DT_INTERFACE) {
8123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
8223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
8323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE &&
8423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                interface->bInterfaceSubClass == 1 && // Still Image Capture
8523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                interface->bInterfaceProtocol == 1)     // Picture Transfer Protocol (PIMA 15470)
8623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            {
8731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* manufacturerName = usb_device_get_manufacturer_name(device);
8831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* productName = usb_device_get_product_name(device);
89b8a805261bf0282e992d3608035e47d05a898710Steve Block                ALOGD("Found camera: \"%s\" \"%s\"\n", manufacturerName, productName);
9031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(manufacturerName);
9131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(productName);
9223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            } else if (interface->bInterfaceClass == 0xFF &&
9323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    interface->bInterfaceSubClass == 0xFF &&
9423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    interface->bInterfaceProtocol == 0) {
9523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                char* interfaceName = usb_device_get_string(device, interface->iInterface);
9631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                if (!interfaceName) {
9723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    continue;
9831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                } else if (strcmp(interfaceName, "MTP")) {
9931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    free(interfaceName);
10031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    continue;
10131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                }
10231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(interfaceName);
10331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root
10423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // Looks like an android style MTP device
10531c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* manufacturerName = usb_device_get_manufacturer_name(device);
10631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                char* productName = usb_device_get_product_name(device);
107b8a805261bf0282e992d3608035e47d05a898710Steve Block                ALOGD("Found MTP device: \"%s\" \"%s\"\n", manufacturerName, productName);
10831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(manufacturerName);
10931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                free(productName);
110d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood            }
111d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood#if 0
112d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood             else {
11323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // look for special cased devices based on vendor/product ID
11423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // we are doing this mainly for testing purposes
11523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                uint16_t vendor = usb_device_get_vendor_id(device);
11623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                uint16_t product = usb_device_get_product_id(device);
11723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!isMtpDevice(vendor, product)) {
11823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    // not an MTP or PTP device
11923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    continue;
12023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
12123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // request MTP OS string and descriptor
12223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                // some music players need to see this before entering MTP mode.
12323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                char buffer[256];
12423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                memset(buffer, 0, sizeof(buffer));
125f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                int ret = usb_device_control_transfer(device,
12623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD,
12723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE,
128f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                        0, buffer, sizeof(buffer), 0);
129f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                printf("usb_device_control_transfer returned %d errno: %d\n", ret, errno);
13023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (ret > 0) {
13123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("got MTP string %s\n", buffer);
132f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                    ret = usb_device_control_transfer(device,
13323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                            USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1,
134f41ef0ee0da4c497352df42d09c3d89940c25e14Mike Lockwood                            0, 4, buffer, sizeof(buffer), 0);
13523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("OS descriptor got %d\n", ret);
13623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else {
13723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    printf("no MTP string\n");
13823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
13923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
140d6dabe95eb59c3d95f94825d08a6028bab06cbdcDaichi Hirono#else
141d6dabe95eb59c3d95f94825d08a6028bab06cbdcDaichi Hirono            else {
142d6dabe95eb59c3d95f94825d08a6028bab06cbdcDaichi Hirono                continue;
143d6dabe95eb59c3d95f94825d08a6028bab06cbdcDaichi Hirono            }
144d4fb52e3031578119ecd53087b1bcb4828c333c5Mike Lockwood#endif
14523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // if we got here, then we have a likely MTP or PTP device
14623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
14723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            // interface should be followed by three endpoints
14823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep;
14923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_in_desc = NULL;
15023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_out_desc = NULL;
15123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            struct usb_endpoint_descriptor *ep_intr_desc = NULL;
1528023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang            //USB3 add USB_DT_SS_ENDPOINT_COMP as companion descriptor;
1538023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang            struct usb_ss_ep_comp_descriptor *ep_ss_ep_comp_desc = NULL;
15423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            for (int i = 0; i < 3; i++) {
15523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
1568023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang                if (ep && ep->bDescriptorType == USB_DT_SS_ENDPOINT_COMP) {
1578023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang                    ALOGD("Descriptor type is USB_DT_SS_ENDPOINT_COMP for USB3 \n");
1588023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang                    ep_ss_ep_comp_desc = (usb_ss_ep_comp_descriptor*)ep;
1598023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang                    ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
1608023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang                 }
1618023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang
16223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
16329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    ALOGE("endpoints not found\n");
16431c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    usb_device_close(device);
16523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    return NULL;
16623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
1678023f3af62795b7816f36a9423f8e0a39e616e49Bo Huang
16823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
16923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
17023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_in_desc = ep;
17123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    else
17223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_out_desc = ep;
17323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT &&
17423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
17523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                    ep_intr_desc = ep;
17623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                }
17723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
17823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
17929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("endpoints not found\n");
18031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                usb_device_close(device);
18123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                return NULL;
18223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
18323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
18433d58162896868f387416289c8b33266be0a3360Jaesung Chung            int ret = usb_device_claim_interface(device, interface->bInterfaceNumber);
18533d58162896868f387416289c8b33266be0a3360Jaesung Chung            if (ret && errno == EBUSY) {
18633d58162896868f387416289c8b33266be0a3360Jaesung Chung                // disconnect kernel driver and try again
18733d58162896868f387416289c8b33266be0a3360Jaesung Chung                usb_device_connect_kernel_driver(device, interface->bInterfaceNumber, false);
18833d58162896868f387416289c8b33266be0a3360Jaesung Chung                ret = usb_device_claim_interface(device, interface->bInterfaceNumber);
18933d58162896868f387416289c8b33266be0a3360Jaesung Chung            }
19033d58162896868f387416289c8b33266be0a3360Jaesung Chung            if (ret) {
19129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("usb_device_claim_interface failed errno: %d\n", errno);
19231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                usb_device_close(device);
19323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                return NULL;
19423f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            }
19523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
19623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber,
19723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood                        ep_in_desc, ep_out_desc, ep_intr_desc);
19823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            mtpDevice->initialize();
19923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood            return mtpDevice;
20023f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood        }
20123f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    }
20223f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
20323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    usb_device_close(device);
20429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block    ALOGE("device not found");
20523f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood    return NULL;
20623f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
20723f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
2085ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::MtpDevice(struct usb_device* device, int interface,
20942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_in,
21042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_out,
21142d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood            const struct usb_endpoint_descriptor *ep_intr)
2125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    :   mDevice(device),
2135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mInterface(interface),
21442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn1(NULL),
21542d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIn2(NULL),
21642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestOut(NULL),
21742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        mRequestIntr(NULL),
2185ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDeviceInfo(NULL),
2195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mSessionID(0),
220f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mTransactionID(0),
2218a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono        mReceivedResponse(false),
2228a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono        mProcessingEvent(false),
2238d20945c08dfdd85c252c8ba92d197bf1bd2b208Daichi Hirono        mCurrentEventHandle(0),
2248d20945c08dfdd85c252c8ba92d197bf1bd2b208Daichi Hirono        mLastSendObjectInfoTransactionID(0),
2258d20945c08dfdd85c252c8ba92d197bf1bd2b208Daichi Hirono        mLastSendObjectInfoObjectHandle(0)
2265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood{
22742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIn1 = usb_request_new(device, ep_in);
22842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIn2 = usb_request_new(device, ep_in);
22942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestOut = usb_request_new(device, ep_out);
23042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    mRequestIntr = usb_request_new(device, ep_intr);
2315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2335ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDevice::~MtpDevice() {
2345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    close();
2353ab368e0810d894dcbc0971350c095049478a055Mark Salyzyn    for (size_t i = 0; i < mDeviceProperties.size(); i++)
236a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        delete mDeviceProperties[i];
23742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIn1);
23842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIn2);
23942d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestOut);
24042d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    usb_request_free(mRequestIntr);
2415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2435ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::initialize() {
2445ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    openSession();
2455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mDeviceInfo = getDeviceInfo();
2465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDeviceInfo) {
247a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        if (mDeviceInfo->mDeviceProperties) {
248a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
249a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            for (int i = 0; i < count; i++) {
250a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
251a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
2520c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property)
253a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood                    mDeviceProperties.push(property);
254a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood            }
255a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        }
2565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2595ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodvoid MtpDevice::close() {
2605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice) {
2615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_release_interface(mDevice, mInterface);
2625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        usb_device_close(mDevice);
2635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mDevice = NULL;
2645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
2655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
2665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
2670c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwoodvoid MtpDevice::print() {
2680c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo) {
2690c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        mDeviceInfo->print();
2700c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2710c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        if (mDeviceInfo->mDeviceProperties) {
272df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("***** DEVICE PROPERTIES *****\n");
2730c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            int count = mDeviceInfo->mDeviceProperties->size();
2740c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            for (int i = 0; i < count; i++) {
2750c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
2760c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                MtpProperty* property = getDevicePropDesc(propCode);
2770c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                if (property) {
2780c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    property->print();
27931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    delete property;
2800c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
2810c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
2820c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
2830c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
2840c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
2850c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    if (mDeviceInfo->mPlaybackFormats) {
286df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("***** OBJECT PROPERTIES *****\n");
2870c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        int count = mDeviceInfo->mPlaybackFormats->size();
2880c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        for (int i = 0; i < count; i++) {
2890c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i];
290df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block            ALOGI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format));
2910c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            MtpObjectPropertyList* props = getObjectPropsSupported(format);
2920c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            if (props) {
2933ab368e0810d894dcbc0971350c095049478a055Mark Salyzyn                for (size_t j = 0; j < props->size(); j++) {
2940c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                    MtpObjectProperty prop = (*props)[j];
29599e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood                    MtpProperty* property = getObjectPropDesc(prop, format);
29631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    if (property) {
2970c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                        property->print();
29831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                        delete property;
29931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    } else {
30029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                        ALOGE("could not fetch property: %s",
3010c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                                MtpDebug::getObjectPropCodeName(prop));
30231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                    }
3030c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood                }
3040c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood            }
3050c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood        }
3060c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood    }
3070c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood}
3080c7c7c76a96a82ec728a2d5c091941c4057ffb25Mike Lockwood
3095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodconst char* MtpDevice::getDeviceName() {
3105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mDevice)
3115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return usb_device_get_name(mDevice);
3125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else
3135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return "???";
3145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3155ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3165ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::openSession() {
3170cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3180cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3195ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = 0;
3205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 0;
3215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpSessionID newSession = 1;
3225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, newSession);
3245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
3255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
3265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
3285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        newSession = mResponse.getParameter(1);
3295ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else if (ret != MTP_RESPONSE_OK)
3305ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
3315ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3325ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mSessionID = newSession;
3335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mTransactionID = 1;
3345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
3355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3375ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::closeSession() {
3385ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    // FIXME
3395ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return true;
3405ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3415ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3425ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpDeviceInfo* MtpDevice::getDeviceInfo() {
3430cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3440cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
3475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3485ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpDeviceInfo* info = new MtpDeviceInfo;
353ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        if (info->read(mData))
354ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            return info;
355ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        else
356ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            delete info;
3575ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3595ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3615ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageIDList* MtpDevice::getStorageIDs() {
3620cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3630cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3645ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3655ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
3665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3675ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3685ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3695ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3705ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3715ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
3725ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3735ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3745ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3765ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
3770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
3795ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
3805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
3815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
3825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
3845ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
3855ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
3865ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
3875ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpStorageInfo* info = new MtpStorageInfo(storageID);
388ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        if (info->read(mData))
389ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            return info;
390ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        else
391ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            delete info;
3925ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
3935ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
3945ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
3955ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
3965ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
3975ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood            MtpObjectFormat format, MtpObjectHandle parent) {
3980cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
3990cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4005ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
4015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, storageID);
4025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(2, format);
4035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(3, parent);
4045ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
4055ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
4065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
4075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
4085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
4095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
4105ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mData.getAUInt32();
4115ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
4125ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
4135ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
4145ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
4155ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
4160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4170cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4186afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    // FIXME - we might want to add some caching here
4196afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
4205ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.reset();
4215ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setParameter(1, handle);
4225ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
4235ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
4245ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (!readData())
4255ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return NULL;
4265ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    MtpResponseCode ret = readResponse();
4275ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret == MTP_RESPONSE_OK) {
4285ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        MtpObjectInfo* info = new MtpObjectInfo(handle);
429ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        if (info->read(mData))
430ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            return info;
431ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        else
432ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            delete info;
4335ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
4345ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return NULL;
4355ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
4365ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
4373e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwoodvoid* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
4380cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4403e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.reset();
4413e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    mRequest.setParameter(1, handle);
4423e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
4433e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        MtpResponseCode ret = readResponse();
4443e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
4454fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono            return mData.getData(&outLength);
4463e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood        }
4473e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    }
4483e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    outLength = 0;
4493e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood    return NULL;
4506afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
4516afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
4520cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike LockwoodMtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
4530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
4540cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4550cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
4560cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpObjectHandle parent = info->mParent;
4570cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (parent == 0)
4580cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        parent = MTP_PARENT_ROOT;
4590cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4600cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.setParameter(1, info->mStorageID);
46164c948bf5041fdfe391553315c9d028e1ee56382Tomasz Mikolajewski    mRequest.setParameter(2, parent);
4620cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
46364c948bf5041fdfe391553315c9d028e1ee56382Tomasz Mikolajewski    mData.reset();
4640cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mStorageID);
4650cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mFormat);
4660cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mProtectionStatus);
4670cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mCompressedSize);
4680cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mThumbFormat);
4690cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbCompressedSize);
4700cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixWidth);
4710cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mThumbPixHeight);
4720cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixWidth);
4730cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixHeight);
4740cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mImagePixDepth);
4750cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mParent);
4760cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt16(info->mAssociationType);
4770cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mAssociationDesc);
4780cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putUInt32(info->mSequenceNumber);
4790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(info->mName);
4800cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4810cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    char created[100], modified[100];
4820cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateCreated, created, sizeof(created));
4830cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    formatDateTime(info->mDateModified, modified, sizeof(modified));
4840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4850cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(created);
4860cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.putString(modified);
4870cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (info->mKeywords)
4880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putString(info->mKeywords);
4890cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    else
4900cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        mData.putEmptyString();
4910cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
4920cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood   if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
4930cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        MtpResponseCode ret = readResponse();
4940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        if (ret == MTP_RESPONSE_OK) {
4958d20945c08dfdd85c252c8ba92d197bf1bd2b208Daichi Hirono            mLastSendObjectInfoTransactionID = mRequest.getTransactionID();
4968d20945c08dfdd85c252c8ba92d197bf1bd2b208Daichi Hirono            mLastSendObjectInfoObjectHandle = mResponse.getParameter(3);
4970cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mStorageID = mResponse.getParameter(1);
4980cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mParent = mResponse.getParameter(2);
4990cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            info->mHandle = mResponse.getParameter(3);
5000cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            return info->mHandle;
5010cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
5020cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
5030cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    return (MtpObjectHandle)-1;
5040cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
5050cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
506532b4f23c7e08fdae9fff189c4b565f6216ffd2aTomasz Mikolajewskibool MtpDevice::sendObject(MtpObjectHandle handle, int size, int srcFD) {
5070cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
5080cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
5098d20945c08dfdd85c252c8ba92d197bf1bd2b208Daichi Hirono    if (mLastSendObjectInfoTransactionID + 1 != mTransactionID ||
5108d20945c08dfdd85c252c8ba92d197bf1bd2b208Daichi Hirono            mLastSendObjectInfoObjectHandle != handle) {
5118d20945c08dfdd85c252c8ba92d197bf1bd2b208Daichi Hirono        ALOGE("A sendObject request must follow the sendObjectInfo request.");
5128d20945c08dfdd85c252c8ba92d197bf1bd2b208Daichi Hirono        return false;
5138d20945c08dfdd85c252c8ba92d197bf1bd2b208Daichi Hirono    }
5148d20945c08dfdd85c252c8ba92d197bf1bd2b208Daichi Hirono
515532b4f23c7e08fdae9fff189c4b565f6216ffd2aTomasz Mikolajewski    int remaining = size;
5160cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mRequest.reset();
517b3be006498f28f2630264135e88d266b540bcec3Daichi Hirono    bool error = false;
5180cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
5190cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        // send data header
5200cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
5210cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
522532b4f23c7e08fdae9fff189c4b565f6216ffd2aTomasz Mikolajewski        // USB writes greater than 16K don't work
523532b4f23c7e08fdae9fff189c4b565f6216ffd2aTomasz Mikolajewski        char buffer[MTP_BUFFER_SIZE];
5240cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        while (remaining > 0) {
5250cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            int count = read(srcFD, buffer, sizeof(buffer));
5260cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            if (count > 0) {
527b3be006498f28f2630264135e88d266b540bcec3Daichi Hirono                if (mData.write(mRequestOut, buffer, count) < 0) {
528b3be006498f28f2630264135e88d266b540bcec3Daichi Hirono                    error = true;
529b3be006498f28f2630264135e88d266b540bcec3Daichi Hirono                }
5300cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                // FIXME check error
5310cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                remaining -= count;
5320cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            } else {
5330cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood                break;
5340cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
5350cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
5360cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
5370cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    MtpResponseCode ret = readResponse();
538b3be006498f28f2630264135e88d266b540bcec3Daichi Hirono    return (remaining == 0 && ret == MTP_RESPONSE_OK && !error);
5390cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
5400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
5416afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwoodbool MtpDevice::deleteObject(MtpObjectHandle handle) {
5420cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
5430cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
5446afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.reset();
5456afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    mRequest.setParameter(1, handle);
5466afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
5476afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        MtpResponseCode ret = readResponse();
5486afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        if (ret == MTP_RESPONSE_OK)
5496afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood            return true;
5506afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    }
5516afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    return false;
5526afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
5536afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood
5546afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
5556afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
55631c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    if (info) {
55731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        MtpObjectHandle parent = info->mParent;
55831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        delete info;
55931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        return parent;
56031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    } else {
5616afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
56231c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    }
5636afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood}
5643e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
5656afc41d095ccb159f6c4705bed903b6c048b922aMike LockwoodMtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
5666afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood    MtpObjectInfo* info = getObjectInfo(handle);
56731c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    if (info) {
56831c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        MtpObjectHandle storageId = info->mStorageID;
56931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        delete info;
57031c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root        return storageId;
57131c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    } else {
5726afc41d095ccb159f6c4705bed903b6c048b922aMike Lockwood        return -1;
57331c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root    }
5743e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood}
5753e072b354d1e1e3ee62d58492f0739139df8aff1Mike Lockwood
57698693f674125484de8873d969c209276a6dd604bMike LockwoodMtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
57798693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
57898693f674125484de8873d969c209276a6dd604bMike Lockwood
57998693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
58098693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, format);
58198693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED))
58298693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
58398693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
58498693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
58598693f674125484de8873d969c209276a6dd604bMike Lockwood    MtpResponseCode ret = readResponse();
58698693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
58798693f674125484de8873d969c209276a6dd604bMike Lockwood        return mData.getAUInt16();
58898693f674125484de8873d969c209276a6dd604bMike Lockwood    }
58998693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
59098693f674125484de8873d969c209276a6dd604bMike Lockwood
59198693f674125484de8873d969c209276a6dd604bMike Lockwood}
59298693f674125484de8873d969c209276a6dd604bMike Lockwood
593a6c490b8b2d96ebaab632286029463f932ae3b6bMike LockwoodMtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
5940cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    Mutex::Autolock autoLock(mMutex);
5950cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
596a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.reset();
597a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    mRequest.setParameter(1, code);
598a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
599a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
600a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (!readData())
601a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        return NULL;
602a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    MtpResponseCode ret = readResponse();
603a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
604a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood        MtpProperty* property = new MtpProperty;
605ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        if (property->read(mData))
606ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            return property;
607ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        else
608ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            delete property;
609a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    }
610a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood    return NULL;
611a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood}
612a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
61399e393a39a31bfbdeb435462939519e2d0279433Mike LockwoodMtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
61498693f674125484de8873d969c209276a6dd604bMike Lockwood    Mutex::Autolock autoLock(mMutex);
61598693f674125484de8873d969c209276a6dd604bMike Lockwood
61698693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.reset();
61798693f674125484de8873d969c209276a6dd604bMike Lockwood    mRequest.setParameter(1, code);
61899e393a39a31bfbdeb435462939519e2d0279433Mike Lockwood    mRequest.setParameter(2, format);
61998693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC))
62098693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
62198693f674125484de8873d969c209276a6dd604bMike Lockwood    if (!readData())
62298693f674125484de8873d969c209276a6dd604bMike Lockwood        return NULL;
62366a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono    const MtpResponseCode ret = readResponse();
62498693f674125484de8873d969c209276a6dd604bMike Lockwood    if (ret == MTP_RESPONSE_OK) {
62598693f674125484de8873d969c209276a6dd604bMike Lockwood        MtpProperty* property = new MtpProperty;
626ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        if (property->read(mData))
627ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            return property;
628ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood        else
629ab063847e6e893740749029a04cce1f6b7345ed5Mike Lockwood            delete property;
63098693f674125484de8873d969c209276a6dd604bMike Lockwood    }
63198693f674125484de8873d969c209276a6dd604bMike Lockwood    return NULL;
63298693f674125484de8873d969c209276a6dd604bMike Lockwood}
63398693f674125484de8873d969c209276a6dd604bMike Lockwood
63466a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hironobool MtpDevice::getObjectPropValue(MtpObjectHandle handle, MtpProperty* property) {
63566a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono    if (property == nullptr)
63666a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono        return false;
63766a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono
63866a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono    Mutex::Autolock autoLock(mMutex);
63966a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono
64066a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono    mRequest.reset();
64166a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono    mRequest.setParameter(1, handle);
64266a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono    mRequest.setParameter(2, property->getPropertyCode());
64366a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_VALUE))
64466a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono        return false;
64566a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono    if (!readData())
64666a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono        return false;
64766a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono    if (readResponse() != MTP_RESPONSE_OK)
64866a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono        return false;
64966a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono    property->setCurrentValue(mData);
65066a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono    return true;
65166a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono}
65266a9abef47f7c8bd438bb1897617ebad3858c736Daichi Hirono
65323f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle,
6544fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono                           ReadObjectCallback callback,
6554a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono                           uint32_t expectedLength,
6564fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono                           void* clientData) {
6574fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    return readObjectInternal(handle, callback, &expectedLength, clientData);
65823f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood}
65923f1b33c5f88f07510ca5dc01b3afd7af6843d6cMike Lockwood
660b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood// reads the object's data and writes it to the specified file path
66127afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwoodbool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
662b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("readObject: %s", destPath);
663af8e8aa1ada2948972555592570ec9ad90cbf372Nick Kralevich    int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
664b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    if (fd < 0) {
66529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("open failed for %s", destPath);
666b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        return false;
6670cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
6680cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
66927afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchown(fd, getuid(), group);
67027afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    // set permissions
67127afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    int mask = umask(0);
67227afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    fchmod(fd, perm);
67327afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood    umask(mask);
67427afe3a1cc9c07ac4884a7720087a597aea3c76fMike Lockwood
675025ffd9c17a7b30d862436954aa0db8d08bfaa9fTomasz Mikolajewski    bool result = readObject(handle, fd);
676025ffd9c17a7b30d862436954aa0db8d08bfaa9fTomasz Mikolajewski    ::close(fd);
677025ffd9c17a7b30d862436954aa0db8d08bfaa9fTomasz Mikolajewski    return result;
678025ffd9c17a7b30d862436954aa0db8d08bfaa9fTomasz Mikolajewski}
679025ffd9c17a7b30d862436954aa0db8d08bfaa9fTomasz Mikolajewski
680025ffd9c17a7b30d862436954aa0db8d08bfaa9fTomasz Mikolajewskibool MtpDevice::readObject(MtpObjectHandle handle, int fd) {
681025ffd9c17a7b30d862436954aa0db8d08bfaa9fTomasz Mikolajewski    ALOGD("readObject: %d", fd);
6824fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    return readObjectInternal(handle, writeToFd, NULL /* expected size */, &fd);
6834fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono}
684025ffd9c17a7b30d862436954aa0db8d08bfaa9fTomasz Mikolajewski
6854fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hironobool MtpDevice::readObjectInternal(MtpObjectHandle handle,
6864fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono                                   ReadObjectCallback callback,
6874a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono                                   const uint32_t* expectedLength,
6884fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono                                   void* clientData) {
689b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    Mutex::Autolock autoLock(mMutex);
6900cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
691b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.reset();
692b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood    mRequest.setParameter(1, handle);
6934fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    if (!sendRequest(MTP_OPERATION_GET_OBJECT)) {
6944fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        ALOGE("Failed to send a read request.");
6954fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        return false;
6964fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    }
6974fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono
6984a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    return readData(callback, expectedLength, nullptr, clientData);
6994a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono}
7004a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono
7014a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hironobool MtpDevice::readData(ReadObjectCallback callback,
7024a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono                            const uint32_t* expectedLength,
7034a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono                            uint32_t* writtenSize,
7044a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono                            void* clientData) {
7054fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    if (!mData.readDataHeader(mRequestIn1)) {
7064fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        ALOGE("Failed to read header.");
7074fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        return false;
7084fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    }
7094fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono
710a04e6fa61391f1ef64266579760f315c6b3e70b9Daichi Hirono    // If object size 0 byte, the remote device can reply response packet
711a04e6fa61391f1ef64266579760f315c6b3e70b9Daichi Hirono    // without sending any data packets.
712a04e6fa61391f1ef64266579760f315c6b3e70b9Daichi Hirono    if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
713a04e6fa61391f1ef64266579760f315c6b3e70b9Daichi Hirono        mResponse.copyFrom(mData);
714a04e6fa61391f1ef64266579760f315c6b3e70b9Daichi Hirono        return mResponse.getResponseCode() == MTP_RESPONSE_OK;
715a04e6fa61391f1ef64266579760f315c6b3e70b9Daichi Hirono    }
716a04e6fa61391f1ef64266579760f315c6b3e70b9Daichi Hirono
7174fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    const uint32_t fullLength = mData.getContainerLength();
7184a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    if (fullLength < MTP_CONTAINER_HEADER_SIZE) {
7194a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono        ALOGE("fullLength is too short: %d", fullLength);
7204a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono        return false;
7214a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    }
7224a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    const uint32_t length = fullLength - MTP_CONTAINER_HEADER_SIZE;
7234a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    if (expectedLength && length != *expectedLength) {
7244fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        ALOGE("readObject error length: %d", fullLength);
7254fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        return false;
7264fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    }
7274fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono
7284fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    uint32_t offset = 0;
7294fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    bool writingError = false;
730b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
7314fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    {
732b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int initialDataLength = 0;
7334fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        void* const initialData = mData.getData(&initialDataLength);
734b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        if (initialData) {
735b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            if (initialDataLength > 0) {
7364fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono                if (!callback(initialData, offset, initialDataLength, clientData)) {
73781ca5ade77ea518aa21fdd7434d2db5df088a115Daichi Hirono                    ALOGE("Failed to write initial data.");
73881ca5ade77ea518aa21fdd7434d2db5df088a115Daichi Hirono                    writingError = true;
73931c52e7c8c01e1db6ff9bcf66135c72544b1235aKenny Root                }
7404fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono                offset += initialDataLength;
7410cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
742b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            free(initialData);
7430cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood        }
7444fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    }
7450cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
7464fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    // USB reads greater than 16K don't work.
7474fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    char buffer1[MTP_BUFFER_SIZE], buffer2[MTP_BUFFER_SIZE];
7484fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    mRequestIn1->buffer = buffer1;
7494fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    mRequestIn2->buffer = buffer2;
7504fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    struct usb_request* req = NULL;
7514fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono
7524fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono    while (offset < length) {
7534fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        // Wait for previous read to complete.
75442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood        void* writeBuffer = NULL;
755b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        int writeLength = 0;
7564fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        if (req) {
7574fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono            const int read = mData.readDataWait(mDevice);
7584fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono            if (read < 0) {
7594fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono                ALOGE("readDataWait failed.");
7604fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono                return false;
7610cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood            }
7624fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono            writeBuffer = req->buffer;
7634fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono            writeLength = read;
7644fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        }
7650cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
7664fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        // Request to read next chunk.
7674fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        const uint32_t nextOffset = offset + writeLength;
7684fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        if (nextOffset < length) {
7694fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono            // Queue up a read request.
7704fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono            const size_t remaining = length - nextOffset;
7714fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono            req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
7724a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono            req->buffer_length = remaining > MTP_BUFFER_SIZE ?
7734a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono                    static_cast<size_t>(MTP_BUFFER_SIZE) : remaining;
7744fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono            if (mData.readDataAsync(req) != 0) {
7754fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono                ALOGE("readDataAsync failed");
7764fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono                return false;
777b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
7784fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        }
7790cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
7804fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        // Write previous buffer.
7814fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        if (writeBuffer && !writingError) {
7824fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono            if (!callback(writeBuffer, offset, writeLength, clientData)) {
7834fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono                ALOGE("write failed");
7844fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono                writingError = true;
785b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood            }
786b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood        }
7874fd9a8b9865addfedbcd84d5c9efea0f647086a0Daichi Hirono        offset = nextOffset;
7880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    }
789b9ff444a7eaf7ffd43970c0477110c6808bd4a7cMike Lockwood
7904a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    if (writtenSize) {
7914a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono        *writtenSize = length;
7924a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    }
7934a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono
7944a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    return readResponse() == MTP_RESPONSE_OK;
7954a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono}
7964a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono
7974a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hironobool MtpDevice::readPartialObject(MtpObjectHandle handle,
7984a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono                                  uint32_t offset,
7994a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono                                  uint32_t size,
8004a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono                                  uint32_t *writtenSize,
8014a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono                                  ReadObjectCallback callback,
8024a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono                                  void* clientData) {
8034a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    Mutex::Autolock autoLock(mMutex);
8044a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono
8054a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    mRequest.reset();
8064a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    mRequest.setParameter(1, handle);
8074a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    mRequest.setParameter(2, offset);
8084a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    mRequest.setParameter(3, size);
8094a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    if (!sendRequest(MTP_OPERATION_GET_PARTIAL_OBJECT)) {
8104a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono        ALOGE("Failed to send a read request.");
8114a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono        return false;
8124a7cea889d81bbf8f555df006fe384a405b3ba53Daichi Hirono    }
813610d4a125f0144ec4915e5cef9f53e431cb117afDaichi Hirono    // The expected size is null because it requires the exact number of bytes to read though
814610d4a125f0144ec4915e5cef9f53e431cb117afDaichi Hirono    // MTP_OPERATION_GET_PARTIAL_OBJECT allows devices to return shorter length of bytes than
815610d4a125f0144ec4915e5cef9f53e431cb117afDaichi Hirono    // requested. Destination's buffer length should be checked in |callback|.
816326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono    return readData(callback, nullptr /* expected size */, writtenSize, clientData);
817326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono}
818326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono
819326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hironobool MtpDevice::readPartialObject64(MtpObjectHandle handle,
820326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono                                    uint64_t offset,
821326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono                                    uint32_t size,
822326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono                                    uint32_t *writtenSize,
823326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono                                    ReadObjectCallback callback,
824326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono                                    void* clientData) {
825326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono    Mutex::Autolock autoLock(mMutex);
826326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono
827326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono    mRequest.reset();
828326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono    mRequest.setParameter(1, handle);
829326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono    mRequest.setParameter(2, 0xffffffff & offset);
830326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono    mRequest.setParameter(3, 0xffffffff & (offset >> 32));
831326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono    mRequest.setParameter(4, size);
832326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono    if (!sendRequest(MTP_OPERATION_GET_PARTIAL_OBJECT_64)) {
833326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono        ALOGE("Failed to send a read request.");
834326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono        return false;
835326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono    }
836610d4a125f0144ec4915e5cef9f53e431cb117afDaichi Hirono    // The expected size is null because it requires the exact number of bytes to read though
837610d4a125f0144ec4915e5cef9f53e431cb117afDaichi Hirono    // MTP_OPERATION_GET_PARTIAL_OBJECT_64 allows devices to return shorter length of bytes than
838610d4a125f0144ec4915e5cef9f53e431cb117afDaichi Hirono    // requested. Destination's buffer length should be checked in |callback|.
839326edd98bbc52d41de6e0943ca8a343228ed87a5Daichi Hirono    return readData(callback, nullptr /* expected size */, writtenSize, clientData);
8400cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
841a6c490b8b2d96ebaab632286029463f932ae3b6bMike Lockwood
8425ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::sendRequest(MtpOperationCode operation) {
8433856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
844f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    mReceivedResponse = false;
8455ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.setOperationCode(operation);
8465ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (mTransactionID > 0)
8475ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mRequest.setTransactionID(mTransactionID++);
84842d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mRequest.write(mRequestOut);
8495ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mRequest.dump();
8505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    return (ret > 0);
8515ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
8525ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
8530cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::sendData() {
8543856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("sendData\n");
8555ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setOperationCode(mRequest.getOperationCode());
8565ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
85742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mData.write(mRequestOut);
8585ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.dump();
85964c948bf5041fdfe391553315c9d028e1ee56382Tomasz Mikolajewski    return (ret >= 0);
8605ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
8615ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
8625ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwoodbool MtpDevice::readData() {
8635ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    mData.reset();
86442d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mData.read(mRequestIn1);
8653856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("readData returned %d\n", ret);
8665ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
867f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
868b8a805261bf0282e992d3608035e47d05a898710Steve Block            ALOGD("got response packet instead of data packet");
869f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // we got a response packet rather than data
870f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            // copy it to mResponse
871f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mResponse.copyFrom(mData);
872f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            mReceivedResponse = true;
873f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood            return false;
874f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        }
8755ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mData.dump();
8765ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return true;
8775ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
8785ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    else {
8793856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("readResponse failed\n");
8805ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return false;
8815ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
8825ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
8835ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
8840cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwoodbool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
8850cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setOperationCode(operation);
8860cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood    mData.setTransactionID(mRequest.getTransactionID());
88742d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    return (!mData.writeDataHeader(mRequestOut, dataLength));
8880cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood}
8890cf89f2e622aa53f31fa5762ca4bc805bb509ed3Mike Lockwood
8905ed68d29a140e14c8d46980fa844548eb33b1e87Mike LockwoodMtpResponseCode MtpDevice::readResponse() {
8913856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("readResponse\n");
892f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    if (mReceivedResponse) {
893f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        mReceivedResponse = false;
894f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood        return mResponse.getResponseCode();
895f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    }
89642d0b79a787814d42e4c6f9dfe14f13cc0f6a758Mike Lockwood    int ret = mResponse.read(mRequestIn1);
8973d74457b66533b170606347e60628e55a2af255eMike Lockwood    // handle zero length packets, which might occur if the data transfer
8983d74457b66533b170606347e60628e55a2af255eMike Lockwood    // ends on a packet boundary
8993d74457b66533b170606347e60628e55a2af255eMike Lockwood    if (ret == 0)
9003d74457b66533b170606347e60628e55a2af255eMike Lockwood        ret = mResponse.read(mRequestIn1);
9015ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
9025ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        mResponse.dump();
9035ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return mResponse.getResponseCode();
904f7454622eaac287d20ab43013d7015fe42b894f8Mike Lockwood    } else {
905b8a805261bf0282e992d3608035e47d05a898710Steve Block        ALOGD("readResponse failed\n");
9065ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood        return -1;
9075ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood    }
9085ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}
9095ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood
9108a7ffae09a019de7109b30c505561c453910bde1Daichi Hironoint MtpDevice::submitEventRequest() {
9118a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    if (mEventMutex.tryLock()) {
9128a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono        // An event is being reaped on another thread.
9138a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono        return -1;
9148a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    }
9158a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    if (mProcessingEvent) {
9168a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono        // An event request was submitted, but no reapEventRequest called so far.
9178a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono        return -1;
9188a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    }
9198a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    Mutex::Autolock autoLock(mEventMutexForInterrupt);
9208a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    mEventPacket.sendRequest(mRequestIntr);
9218a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    const int currentHandle = ++mCurrentEventHandle;
9228a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    mProcessingEvent = true;
9238a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    mEventMutex.unlock();
9248a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    return currentHandle;
9258a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono}
9268a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono
92759a90609cc340d2933c119aa47045a5c95530b48Daichi Hironoint MtpDevice::reapEventRequest(int handle, uint32_t (*parameters)[3]) {
9288a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    Mutex::Autolock autoLock(mEventMutex);
92959a90609cc340d2933c119aa47045a5c95530b48Daichi Hirono    if (!mProcessingEvent || mCurrentEventHandle != handle || !parameters) {
9308a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono        return -1;
9318a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    }
9328a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    mProcessingEvent = false;
9338a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    const int readSize = mEventPacket.readResponse(mRequestIntr->dev);
9348a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    const int result = mEventPacket.getEventCode();
93559a90609cc340d2933c119aa47045a5c95530b48Daichi Hirono    // MTP event has three parameters.
93659a90609cc340d2933c119aa47045a5c95530b48Daichi Hirono    (*parameters)[0] = mEventPacket.getParameter(1);
93759a90609cc340d2933c119aa47045a5c95530b48Daichi Hirono    (*parameters)[1] = mEventPacket.getParameter(2);
93859a90609cc340d2933c119aa47045a5c95530b48Daichi Hirono    (*parameters)[2] = mEventPacket.getParameter(3);
93959a90609cc340d2933c119aa47045a5c95530b48Daichi Hirono    return readSize != 0 ? result : 0;
9408a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono}
9418a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono
9428a7ffae09a019de7109b30c505561c453910bde1Daichi Hironovoid MtpDevice::discardEventRequest(int handle) {
9438a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    Mutex::Autolock autoLock(mEventMutexForInterrupt);
9448a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    if (mCurrentEventHandle != handle) {
9458a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono        return;
9468a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    }
9478a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono    usb_request_cancel(mRequestIntr);
9488a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono}
9498a7ffae09a019de7109b30c505561c453910bde1Daichi Hirono
9505ed68d29a140e14c8d46980fa844548eb33b1e87Mike Lockwood}  // namespace android
951