MtpDevice.cpp revision f41ef0ee0da4c497352df42d09c3d89940c25e14
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "MtpDevice"
18
19#include "MtpDebug.h"
20#include "MtpDevice.h"
21#include "MtpDeviceInfo.h"
22#include "MtpObjectInfo.h"
23#include "MtpProperty.h"
24#include "MtpStorageInfo.h"
25#include "MtpStringBuffer.h"
26#include "MtpUtils.h"
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <sys/types.h>
31#include <sys/ioctl.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#include <errno.h>
35#include <endian.h>
36
37#include <usbhost/usbhost.h>
38
39namespace android {
40
41static bool isMtpDevice(uint16_t vendor, uint16_t product) {
42    // Sandisk Sansa Fuze
43    if (vendor == 0x0781 && product == 0x74c2)
44        return true;
45    // Samsung YP-Z5
46    if (vendor == 0x04e8 && product == 0x503c)
47        return true;
48    return false;
49}
50
51MtpDevice* MtpDevice::open(const char* deviceName, int fd) {
52    struct usb_device *device = usb_device_new(deviceName, fd);
53    if (!device) {
54        LOGE("usb_device_new failed for %s", deviceName);
55        return NULL;
56    }
57
58    struct usb_descriptor_header* desc;
59    struct usb_descriptor_iter iter;
60
61    usb_descriptor_iter_init(device, &iter);
62
63    while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
64        if (desc->bDescriptorType == USB_DT_INTERFACE) {
65            struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
66
67            if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE &&
68                interface->bInterfaceSubClass == 1 && // Still Image Capture
69                interface->bInterfaceProtocol == 1)     // Picture Transfer Protocol (PIMA 15470)
70            {
71                LOGD("Found camera: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device),
72                        usb_device_get_product_name(device));
73            } else if (interface->bInterfaceClass == 0xFF &&
74                    interface->bInterfaceSubClass == 0xFF &&
75                    interface->bInterfaceProtocol == 0) {
76                char* interfaceName = usb_device_get_string(device, interface->iInterface);
77                if (!interfaceName || strcmp(interfaceName, "MTP"))
78                    continue;
79                // Looks like an android style MTP device
80                LOGD("Found MTP device: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device),
81                        usb_device_get_product_name(device));
82            } else {
83                // look for special cased devices based on vendor/product ID
84                // we are doing this mainly for testing purposes
85                uint16_t vendor = usb_device_get_vendor_id(device);
86                uint16_t product = usb_device_get_product_id(device);
87                if (!isMtpDevice(vendor, product)) {
88                    // not an MTP or PTP device
89                    continue;
90                }
91                // request MTP OS string and descriptor
92                // some music players need to see this before entering MTP mode.
93                char buffer[256];
94                memset(buffer, 0, sizeof(buffer));
95                int ret = usb_device_control_transfer(device,
96                        USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD,
97                        USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE,
98                        0, buffer, sizeof(buffer), 0);
99                printf("usb_device_control_transfer returned %d errno: %d\n", ret, errno);
100                if (ret > 0) {
101                    printf("got MTP string %s\n", buffer);
102                    ret = usb_device_control_transfer(device,
103                            USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1,
104                            0, 4, buffer, sizeof(buffer), 0);
105                    printf("OS descriptor got %d\n", ret);
106                } else {
107                    printf("no MTP string\n");
108                }
109            }
110
111            // if we got here, then we have a likely MTP or PTP device
112
113            // interface should be followed by three endpoints
114            struct usb_endpoint_descriptor *ep;
115            struct usb_endpoint_descriptor *ep_in_desc = NULL;
116            struct usb_endpoint_descriptor *ep_out_desc = NULL;
117            struct usb_endpoint_descriptor *ep_intr_desc = NULL;
118            for (int i = 0; i < 3; i++) {
119                ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
120                if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
121                    LOGE("endpoints not found\n");
122                    return NULL;
123                }
124                if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
125                    if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
126                        ep_in_desc = ep;
127                    else
128                        ep_out_desc = ep;
129                } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT &&
130                    ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
131                    ep_intr_desc = ep;
132                }
133            }
134            if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
135                LOGE("endpoints not found\n");
136                return NULL;
137            }
138
139            if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
140                LOGE("usb_device_claim_interface failed errno: %d\n", errno);
141                return NULL;
142            }
143
144            MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber,
145                        ep_in_desc, ep_out_desc, ep_intr_desc);
146            mtpDevice->initialize();
147            return mtpDevice;
148        }
149    }
150
151    usb_device_close(device);
152    LOGE("device not found");
153    return NULL;
154}
155
156MtpDevice::MtpDevice(struct usb_device* device, int interface,
157            const struct usb_endpoint_descriptor *ep_in,
158            const struct usb_endpoint_descriptor *ep_out,
159            const struct usb_endpoint_descriptor *ep_intr)
160    :   mDevice(device),
161        mInterface(interface),
162        mRequestIn1(NULL),
163        mRequestIn2(NULL),
164        mRequestOut(NULL),
165        mRequestIntr(NULL),
166        mDeviceInfo(NULL),
167        mSessionID(0),
168        mTransactionID(0),
169        mReceivedResponse(false)
170{
171    mRequestIn1 = usb_request_new(device, ep_in);
172    mRequestIn2 = usb_request_new(device, ep_in);
173    mRequestOut = usb_request_new(device, ep_out);
174    mRequestIntr = usb_request_new(device, ep_intr);
175}
176
177MtpDevice::~MtpDevice() {
178    close();
179    for (int i = 0; i < mDeviceProperties.size(); i++)
180        delete mDeviceProperties[i];
181    usb_request_free(mRequestIn1);
182    usb_request_free(mRequestIn2);
183    usb_request_free(mRequestOut);
184    usb_request_free(mRequestIntr);
185}
186
187void MtpDevice::initialize() {
188    openSession();
189    mDeviceInfo = getDeviceInfo();
190    if (mDeviceInfo) {
191        if (mDeviceInfo->mDeviceProperties) {
192            int count = mDeviceInfo->mDeviceProperties->size();
193            for (int i = 0; i < count; i++) {
194                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
195                MtpProperty* property = getDevicePropDesc(propCode);
196                if (property)
197                    mDeviceProperties.push(property);
198            }
199        }
200    }
201}
202
203void MtpDevice::close() {
204    if (mDevice) {
205        usb_device_release_interface(mDevice, mInterface);
206        usb_device_close(mDevice);
207        mDevice = NULL;
208    }
209}
210
211void MtpDevice::print() {
212    if (mDeviceInfo) {
213        mDeviceInfo->print();
214
215        if (mDeviceInfo->mDeviceProperties) {
216            LOGI("***** DEVICE PROPERTIES *****\n");
217            int count = mDeviceInfo->mDeviceProperties->size();
218            for (int i = 0; i < count; i++) {
219                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
220                MtpProperty* property = getDevicePropDesc(propCode);
221                if (property) {
222                    property->print();
223                }
224            }
225        }
226    }
227
228    if (mDeviceInfo->mPlaybackFormats) {
229            LOGI("***** OBJECT PROPERTIES *****\n");
230        int count = mDeviceInfo->mPlaybackFormats->size();
231        for (int i = 0; i < count; i++) {
232            MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i];
233            LOGI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format));
234            MtpObjectPropertyList* props = getObjectPropsSupported(format);
235            if (props) {
236                for (int j = 0; j < props->size(); j++) {
237                    MtpObjectProperty prop = (*props)[j];
238                    MtpProperty* property = getObjectPropDesc(prop, format);
239                    if (property)
240                        property->print();
241                    else
242                        LOGE("could not fetch property: %s",
243                                MtpDebug::getObjectPropCodeName(prop));
244                }
245            }
246        }
247    }
248}
249
250const char* MtpDevice::getDeviceName() {
251    if (mDevice)
252        return usb_device_get_name(mDevice);
253    else
254        return "???";
255}
256
257bool MtpDevice::openSession() {
258    Mutex::Autolock autoLock(mMutex);
259
260    mSessionID = 0;
261    mTransactionID = 0;
262    MtpSessionID newSession = 1;
263    mRequest.reset();
264    mRequest.setParameter(1, newSession);
265    if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
266        return false;
267    MtpResponseCode ret = readResponse();
268    if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
269        newSession = mResponse.getParameter(1);
270    else if (ret != MTP_RESPONSE_OK)
271        return false;
272
273    mSessionID = newSession;
274    mTransactionID = 1;
275    return true;
276}
277
278bool MtpDevice::closeSession() {
279    // FIXME
280    return true;
281}
282
283MtpDeviceInfo* MtpDevice::getDeviceInfo() {
284    Mutex::Autolock autoLock(mMutex);
285
286    mRequest.reset();
287    if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
288        return NULL;
289    if (!readData())
290        return NULL;
291    MtpResponseCode ret = readResponse();
292    if (ret == MTP_RESPONSE_OK) {
293        MtpDeviceInfo* info = new MtpDeviceInfo;
294        info->read(mData);
295        return info;
296    }
297    return NULL;
298}
299
300MtpStorageIDList* MtpDevice::getStorageIDs() {
301    Mutex::Autolock autoLock(mMutex);
302
303    mRequest.reset();
304    if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
305        return NULL;
306    if (!readData())
307        return NULL;
308    MtpResponseCode ret = readResponse();
309    if (ret == MTP_RESPONSE_OK) {
310        return mData.getAUInt32();
311    }
312    return NULL;
313}
314
315MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
316    Mutex::Autolock autoLock(mMutex);
317
318    mRequest.reset();
319    mRequest.setParameter(1, storageID);
320    if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
321        return NULL;
322    if (!readData())
323        return NULL;
324    MtpResponseCode ret = readResponse();
325    if (ret == MTP_RESPONSE_OK) {
326        MtpStorageInfo* info = new MtpStorageInfo(storageID);
327        info->read(mData);
328        return info;
329    }
330    return NULL;
331}
332
333MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
334            MtpObjectFormat format, MtpObjectHandle parent) {
335    Mutex::Autolock autoLock(mMutex);
336
337    mRequest.reset();
338    mRequest.setParameter(1, storageID);
339    mRequest.setParameter(2, format);
340    mRequest.setParameter(3, parent);
341    if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
342        return NULL;
343    if (!readData())
344        return NULL;
345    MtpResponseCode ret = readResponse();
346    if (ret == MTP_RESPONSE_OK) {
347        return mData.getAUInt32();
348    }
349    return NULL;
350}
351
352MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
353    Mutex::Autolock autoLock(mMutex);
354
355    // FIXME - we might want to add some caching here
356
357    mRequest.reset();
358    mRequest.setParameter(1, handle);
359    if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
360        return NULL;
361    if (!readData())
362        return NULL;
363    MtpResponseCode ret = readResponse();
364    if (ret == MTP_RESPONSE_OK) {
365        MtpObjectInfo* info = new MtpObjectInfo(handle);
366        info->read(mData);
367        return info;
368    }
369    return NULL;
370}
371
372void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
373    Mutex::Autolock autoLock(mMutex);
374
375    mRequest.reset();
376    mRequest.setParameter(1, handle);
377    if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
378        MtpResponseCode ret = readResponse();
379        if (ret == MTP_RESPONSE_OK) {
380            return mData.getData(outLength);
381        }
382    }
383    outLength = 0;
384    return NULL;
385}
386
387MtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
388    Mutex::Autolock autoLock(mMutex);
389
390    mRequest.reset();
391    MtpObjectHandle parent = info->mParent;
392    if (parent == 0)
393        parent = MTP_PARENT_ROOT;
394
395    mRequest.setParameter(1, info->mStorageID);
396    mRequest.setParameter(2, info->mParent);
397
398    mData.putUInt32(info->mStorageID);
399    mData.putUInt16(info->mFormat);
400    mData.putUInt16(info->mProtectionStatus);
401    mData.putUInt32(info->mCompressedSize);
402    mData.putUInt16(info->mThumbFormat);
403    mData.putUInt32(info->mThumbCompressedSize);
404    mData.putUInt32(info->mThumbPixWidth);
405    mData.putUInt32(info->mThumbPixHeight);
406    mData.putUInt32(info->mImagePixWidth);
407    mData.putUInt32(info->mImagePixHeight);
408    mData.putUInt32(info->mImagePixDepth);
409    mData.putUInt32(info->mParent);
410    mData.putUInt16(info->mAssociationType);
411    mData.putUInt32(info->mAssociationDesc);
412    mData.putUInt32(info->mSequenceNumber);
413    mData.putString(info->mName);
414
415    char created[100], modified[100];
416    formatDateTime(info->mDateCreated, created, sizeof(created));
417    formatDateTime(info->mDateModified, modified, sizeof(modified));
418
419    mData.putString(created);
420    mData.putString(modified);
421    if (info->mKeywords)
422        mData.putString(info->mKeywords);
423    else
424        mData.putEmptyString();
425
426   if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
427        MtpResponseCode ret = readResponse();
428        if (ret == MTP_RESPONSE_OK) {
429            info->mStorageID = mResponse.getParameter(1);
430            info->mParent = mResponse.getParameter(2);
431            info->mHandle = mResponse.getParameter(3);
432            return info->mHandle;
433        }
434    }
435    return (MtpObjectHandle)-1;
436}
437
438bool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
439    Mutex::Autolock autoLock(mMutex);
440
441    int remaining = info->mCompressedSize;
442    mRequest.reset();
443    mRequest.setParameter(1, info->mHandle);
444    if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
445        // send data header
446        writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
447
448        char buffer[65536];
449        while (remaining > 0) {
450            int count = read(srcFD, buffer, sizeof(buffer));
451            if (count > 0) {
452                int written = mData.write(mRequestOut, buffer, count);
453                // FIXME check error
454                remaining -= count;
455            } else {
456                break;
457            }
458        }
459    }
460    MtpResponseCode ret = readResponse();
461    return (remaining == 0 && ret == MTP_RESPONSE_OK);
462}
463
464bool MtpDevice::deleteObject(MtpObjectHandle handle) {
465    Mutex::Autolock autoLock(mMutex);
466
467    mRequest.reset();
468    mRequest.setParameter(1, handle);
469    if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
470        MtpResponseCode ret = readResponse();
471        if (ret == MTP_RESPONSE_OK)
472            return true;
473    }
474    return false;
475}
476
477MtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
478    MtpObjectInfo* info = getObjectInfo(handle);
479    if (info)
480        return info->mParent;
481    else
482        return -1;
483}
484
485MtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
486    MtpObjectInfo* info = getObjectInfo(handle);
487    if (info)
488        return info->mStorageID;
489    else
490        return -1;
491}
492
493MtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
494    Mutex::Autolock autoLock(mMutex);
495
496    mRequest.reset();
497    mRequest.setParameter(1, format);
498    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED))
499        return NULL;
500    if (!readData())
501        return NULL;
502    MtpResponseCode ret = readResponse();
503    if (ret == MTP_RESPONSE_OK) {
504        return mData.getAUInt16();
505    }
506    return NULL;
507
508}
509
510MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
511    Mutex::Autolock autoLock(mMutex);
512
513    mRequest.reset();
514    mRequest.setParameter(1, code);
515    if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
516        return NULL;
517    if (!readData())
518        return NULL;
519    MtpResponseCode ret = readResponse();
520    if (ret == MTP_RESPONSE_OK) {
521        MtpProperty* property = new MtpProperty;
522        property->read(mData);
523        return property;
524    }
525    return NULL;
526}
527
528MtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
529    Mutex::Autolock autoLock(mMutex);
530
531    mRequest.reset();
532    mRequest.setParameter(1, code);
533    mRequest.setParameter(2, format);
534    if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC))
535        return NULL;
536    if (!readData())
537        return NULL;
538    MtpResponseCode ret = readResponse();
539    if (ret == MTP_RESPONSE_OK) {
540        MtpProperty* property = new MtpProperty;
541        property->read(mData);
542        return property;
543    }
544    return NULL;
545}
546
547bool MtpDevice::readObject(MtpObjectHandle handle,
548        bool (* callback)(void* data, int offset, int length, void* clientData),
549        int objectSize, void* clientData) {
550    Mutex::Autolock autoLock(mMutex);
551    bool result = false;
552
553    mRequest.reset();
554    mRequest.setParameter(1, handle);
555    if (sendRequest(MTP_OPERATION_GET_OBJECT)
556            && mData.readDataHeader(mRequestIn1)) {
557        uint32_t length = mData.getContainerLength();
558        if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) {
559            LOGE("readObject error objectSize: %d, length: %d",
560                    objectSize, length);
561            goto fail;
562        }
563        length -= MTP_CONTAINER_HEADER_SIZE;
564        uint32_t remaining = length;
565        int offset = 0;
566
567        int initialDataLength = 0;
568        void* initialData = mData.getData(initialDataLength);
569        if (initialData) {
570            if (initialDataLength > 0) {
571                if (!callback(initialData, 0, initialDataLength, clientData))
572                    goto fail;
573                remaining -= initialDataLength;
574                offset += initialDataLength;
575            }
576            free(initialData);
577        }
578
579        // USB reads greater than 16K don't work
580        char buffer1[16384], buffer2[16384];
581        mRequestIn1->buffer = buffer1;
582        mRequestIn2->buffer = buffer2;
583        struct usb_request* req = mRequestIn1;
584        void* writeBuffer = NULL;
585        int writeLength = 0;
586
587        while (remaining > 0 || writeBuffer) {
588            if (remaining > 0) {
589                // queue up a read request
590                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
591                if (mData.readDataAsync(req)) {
592                    LOGE("readDataAsync failed");
593                    goto fail;
594                }
595            } else {
596                req = NULL;
597            }
598
599            if (writeBuffer) {
600                // write previous buffer
601                if (!callback(writeBuffer, offset, writeLength, clientData)) {
602                    LOGE("write failed");
603                    // wait for pending read before failing
604                    if (req)
605                        mData.readDataWait(mDevice);
606                    goto fail;
607                }
608                offset += writeLength;
609                writeBuffer = NULL;
610            }
611
612            // wait for read to complete
613            if (req) {
614                int read = mData.readDataWait(mDevice);
615                if (read < 0)
616                    goto fail;
617
618                if (read > 0) {
619                    writeBuffer = req->buffer;
620                    writeLength = read;
621                    remaining -= read;
622                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
623                } else {
624                    writeBuffer = NULL;
625                }
626            }
627        }
628
629        MtpResponseCode response = readResponse();
630        if (response == MTP_RESPONSE_OK)
631            result = true;
632    }
633
634fail:
635    return result;
636}
637
638
639// reads the object's data and writes it to the specified file path
640bool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
641    LOGD("readObject: %s", destPath);
642    int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC);
643    if (fd < 0) {
644        LOGE("open failed for %s", destPath);
645        return false;
646    }
647
648    fchown(fd, getuid(), group);
649    // set permissions
650    int mask = umask(0);
651    fchmod(fd, perm);
652    umask(mask);
653
654    Mutex::Autolock autoLock(mMutex);
655    bool result = false;
656
657    mRequest.reset();
658    mRequest.setParameter(1, handle);
659    if (sendRequest(MTP_OPERATION_GET_OBJECT)
660            && mData.readDataHeader(mRequestIn1)) {
661        uint32_t length = mData.getContainerLength();
662        if (length < MTP_CONTAINER_HEADER_SIZE)
663            goto fail;
664        length -= MTP_CONTAINER_HEADER_SIZE;
665        uint32_t remaining = length;
666
667        int initialDataLength = 0;
668        void* initialData = mData.getData(initialDataLength);
669        if (initialData) {
670            if (initialDataLength > 0) {
671                if (write(fd, initialData, initialDataLength) != initialDataLength)
672                    goto fail;
673                remaining -= initialDataLength;
674            }
675            free(initialData);
676        }
677
678        // USB reads greater than 16K don't work
679        char buffer1[16384], buffer2[16384];
680        mRequestIn1->buffer = buffer1;
681        mRequestIn2->buffer = buffer2;
682        struct usb_request* req = mRequestIn1;
683        void* writeBuffer = NULL;
684        int writeLength = 0;
685
686        while (remaining > 0 || writeBuffer) {
687            if (remaining > 0) {
688                // queue up a read request
689                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
690                if (mData.readDataAsync(req)) {
691                    LOGE("readDataAsync failed");
692                    goto fail;
693                }
694            } else {
695                req = NULL;
696            }
697
698            if (writeBuffer) {
699                // write previous buffer
700                if (write(fd, writeBuffer, writeLength) != writeLength) {
701                    LOGE("write failed");
702                    // wait for pending read before failing
703                    if (req)
704                        mData.readDataWait(mDevice);
705                    goto fail;
706                }
707                writeBuffer = NULL;
708            }
709
710            // wait for read to complete
711            if (req) {
712                int read = mData.readDataWait(mDevice);
713                if (read < 0)
714                    goto fail;
715
716                if (read > 0) {
717                    writeBuffer = req->buffer;
718                    writeLength = read;
719                    remaining -= read;
720                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
721                } else {
722                    writeBuffer = NULL;
723                }
724            }
725        }
726
727        MtpResponseCode response = readResponse();
728        if (response == MTP_RESPONSE_OK)
729            result = true;
730    }
731
732fail:
733    ::close(fd);
734    return result;
735}
736
737bool MtpDevice::sendRequest(MtpOperationCode operation) {
738    LOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
739    mReceivedResponse = false;
740    mRequest.setOperationCode(operation);
741    if (mTransactionID > 0)
742        mRequest.setTransactionID(mTransactionID++);
743    int ret = mRequest.write(mRequestOut);
744    mRequest.dump();
745    return (ret > 0);
746}
747
748bool MtpDevice::sendData() {
749    LOGV("sendData\n");
750    mData.setOperationCode(mRequest.getOperationCode());
751    mData.setTransactionID(mRequest.getTransactionID());
752    int ret = mData.write(mRequestOut);
753    mData.dump();
754    return (ret > 0);
755}
756
757bool MtpDevice::readData() {
758    mData.reset();
759    int ret = mData.read(mRequestIn1);
760    LOGV("readData returned %d\n", ret);
761    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
762        if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
763            LOGD("got response packet instead of data packet");
764            // we got a response packet rather than data
765            // copy it to mResponse
766            mResponse.copyFrom(mData);
767            mReceivedResponse = true;
768            return false;
769        }
770        mData.dump();
771        return true;
772    }
773    else {
774        LOGV("readResponse failed\n");
775        return false;
776    }
777}
778
779bool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
780    mData.setOperationCode(operation);
781    mData.setTransactionID(mRequest.getTransactionID());
782    return (!mData.writeDataHeader(mRequestOut, dataLength));
783}
784
785MtpResponseCode MtpDevice::readResponse() {
786    LOGV("readResponse\n");
787    if (mReceivedResponse) {
788        mReceivedResponse = false;
789        return mResponse.getResponseCode();
790    }
791    int ret = mResponse.read(mRequestIn1);
792    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
793        mResponse.dump();
794        return mResponse.getResponseCode();
795    } else {
796        LOGD("readResponse failed\n");
797        return -1;
798    }
799}
800
801}  // namespace android
802