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