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