blob: 01117e683c3b68ba6c5a353e2af2f31502b693cd [file] [log] [blame]
Mike Lockwood5ed68d22010-05-25 19:08:48 -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
Mike Lockwooda6c490b2010-06-05 22:45:01 -040017#define LOG_TAG "MtpDevice"
Mike Lockwoodb14e5882010-06-29 18:11:52 -040018
19#include "MtpDebug.h"
20#include "MtpDevice.h"
21#include "MtpDeviceInfo.h"
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +090022#include "MtpEventPacket.h"
Mike Lockwoodb14e5882010-06-29 18:11:52 -040023#include "MtpObjectInfo.h"
24#include "MtpProperty.h"
25#include "MtpStorageInfo.h"
26#include "MtpStringBuffer.h"
Mike Lockwood0cf89f22010-07-26 20:40:45 -040027#include "MtpUtils.h"
Mike Lockwooda6c490b2010-06-05 22:45:01 -040028
Mike Lockwood5ed68d22010-05-25 19:08:48 -040029#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>
Mike Lockwood0cf89f22010-07-26 20:40:45 -040036#include <endian.h>
Mike Lockwood5ed68d22010-05-25 19:08:48 -040037
38#include <usbhost/usbhost.h>
39
Mike Lockwood5ed68d22010-05-25 19:08:48 -040040namespace android {
41
Mike Lockwoodd4fb52e2011-02-15 14:55:51 -050042#if 0
Mike Lockwood23f1b332010-12-30 15:38:45 -050043static bool isMtpDevice(uint16_t vendor, uint16_t product) {
44 // Sandisk Sansa Fuze
45 if (vendor == 0x0781 && product == 0x74c2)
46 return true;
47 // Samsung YP-Z5
48 if (vendor == 0x04e8 && product == 0x503c)
49 return true;
50 return false;
51}
Mike Lockwoodd4fb52e2011-02-15 14:55:51 -050052#endif
Mike Lockwood23f1b332010-12-30 15:38:45 -050053
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +090054namespace {
55
56bool writeToFd(void* data, int /* unused_offset */, int length, void* clientData) {
57 const int fd = *static_cast<int*>(clientData);
58 return write(fd, data, length) == length;
59}
60
61}
62
Mike Lockwood23f1b332010-12-30 15:38:45 -050063MtpDevice* MtpDevice::open(const char* deviceName, int fd) {
64 struct usb_device *device = usb_device_new(deviceName, fd);
65 if (!device) {
Steve Block29357bc2012-01-06 19:20:56 +000066 ALOGE("usb_device_new failed for %s", deviceName);
Mike Lockwood23f1b332010-12-30 15:38:45 -050067 return NULL;
68 }
69
70 struct usb_descriptor_header* desc;
71 struct usb_descriptor_iter iter;
72
73 usb_descriptor_iter_init(device, &iter);
74
75 while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
76 if (desc->bDescriptorType == USB_DT_INTERFACE) {
77 struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
78
79 if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE &&
80 interface->bInterfaceSubClass == 1 && // Still Image Capture
81 interface->bInterfaceProtocol == 1) // Picture Transfer Protocol (PIMA 15470)
82 {
Kenny Root31c52e72011-02-02 13:43:55 -080083 char* manufacturerName = usb_device_get_manufacturer_name(device);
84 char* productName = usb_device_get_product_name(device);
Steve Blockb8a80522011-12-20 16:23:08 +000085 ALOGD("Found camera: \"%s\" \"%s\"\n", manufacturerName, productName);
Kenny Root31c52e72011-02-02 13:43:55 -080086 free(manufacturerName);
87 free(productName);
Mike Lockwood23f1b332010-12-30 15:38:45 -050088 } else if (interface->bInterfaceClass == 0xFF &&
89 interface->bInterfaceSubClass == 0xFF &&
90 interface->bInterfaceProtocol == 0) {
91 char* interfaceName = usb_device_get_string(device, interface->iInterface);
Kenny Root31c52e72011-02-02 13:43:55 -080092 if (!interfaceName) {
Mike Lockwood23f1b332010-12-30 15:38:45 -050093 continue;
Kenny Root31c52e72011-02-02 13:43:55 -080094 } else if (strcmp(interfaceName, "MTP")) {
95 free(interfaceName);
96 continue;
97 }
98 free(interfaceName);
99
Mike Lockwood23f1b332010-12-30 15:38:45 -0500100 // Looks like an android style MTP device
Kenny Root31c52e72011-02-02 13:43:55 -0800101 char* manufacturerName = usb_device_get_manufacturer_name(device);
102 char* productName = usb_device_get_product_name(device);
Steve Blockb8a80522011-12-20 16:23:08 +0000103 ALOGD("Found MTP device: \"%s\" \"%s\"\n", manufacturerName, productName);
Kenny Root31c52e72011-02-02 13:43:55 -0800104 free(manufacturerName);
105 free(productName);
Mike Lockwoodd4fb52e2011-02-15 14:55:51 -0500106 }
107#if 0
108 else {
Mike Lockwood23f1b332010-12-30 15:38:45 -0500109 // look for special cased devices based on vendor/product ID
110 // we are doing this mainly for testing purposes
111 uint16_t vendor = usb_device_get_vendor_id(device);
112 uint16_t product = usb_device_get_product_id(device);
113 if (!isMtpDevice(vendor, product)) {
114 // not an MTP or PTP device
115 continue;
116 }
117 // request MTP OS string and descriptor
118 // some music players need to see this before entering MTP mode.
119 char buffer[256];
120 memset(buffer, 0, sizeof(buffer));
Mike Lockwoodf41ef0e2011-01-27 10:47:40 -0800121 int ret = usb_device_control_transfer(device,
Mike Lockwood23f1b332010-12-30 15:38:45 -0500122 USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD,
123 USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE,
Mike Lockwoodf41ef0e2011-01-27 10:47:40 -0800124 0, buffer, sizeof(buffer), 0);
125 printf("usb_device_control_transfer returned %d errno: %d\n", ret, errno);
Mike Lockwood23f1b332010-12-30 15:38:45 -0500126 if (ret > 0) {
127 printf("got MTP string %s\n", buffer);
Mike Lockwoodf41ef0e2011-01-27 10:47:40 -0800128 ret = usb_device_control_transfer(device,
Mike Lockwood23f1b332010-12-30 15:38:45 -0500129 USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1,
Mike Lockwoodf41ef0e2011-01-27 10:47:40 -0800130 0, 4, buffer, sizeof(buffer), 0);
Mike Lockwood23f1b332010-12-30 15:38:45 -0500131 printf("OS descriptor got %d\n", ret);
132 } else {
133 printf("no MTP string\n");
134 }
135 }
Mike Lockwoodd4fb52e2011-02-15 14:55:51 -0500136#endif
Mike Lockwood23f1b332010-12-30 15:38:45 -0500137 // if we got here, then we have a likely MTP or PTP device
138
139 // interface should be followed by three endpoints
140 struct usb_endpoint_descriptor *ep;
141 struct usb_endpoint_descriptor *ep_in_desc = NULL;
142 struct usb_endpoint_descriptor *ep_out_desc = NULL;
143 struct usb_endpoint_descriptor *ep_intr_desc = NULL;
Bo Huang8023f3a2013-06-09 08:53:21 +0800144 //USB3 add USB_DT_SS_ENDPOINT_COMP as companion descriptor;
145 struct usb_ss_ep_comp_descriptor *ep_ss_ep_comp_desc = NULL;
Mike Lockwood23f1b332010-12-30 15:38:45 -0500146 for (int i = 0; i < 3; i++) {
147 ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
Bo Huang8023f3a2013-06-09 08:53:21 +0800148 if (ep && ep->bDescriptorType == USB_DT_SS_ENDPOINT_COMP) {
149 ALOGD("Descriptor type is USB_DT_SS_ENDPOINT_COMP for USB3 \n");
150 ep_ss_ep_comp_desc = (usb_ss_ep_comp_descriptor*)ep;
151 ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
152 }
153
Mike Lockwood23f1b332010-12-30 15:38:45 -0500154 if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
Steve Block29357bc2012-01-06 19:20:56 +0000155 ALOGE("endpoints not found\n");
Kenny Root31c52e72011-02-02 13:43:55 -0800156 usb_device_close(device);
Mike Lockwood23f1b332010-12-30 15:38:45 -0500157 return NULL;
158 }
Bo Huang8023f3a2013-06-09 08:53:21 +0800159
Mike Lockwood23f1b332010-12-30 15:38:45 -0500160 if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
161 if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
162 ep_in_desc = ep;
163 else
164 ep_out_desc = ep;
165 } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT &&
166 ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
167 ep_intr_desc = ep;
168 }
169 }
170 if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
Steve Block29357bc2012-01-06 19:20:56 +0000171 ALOGE("endpoints not found\n");
Kenny Root31c52e72011-02-02 13:43:55 -0800172 usb_device_close(device);
Mike Lockwood23f1b332010-12-30 15:38:45 -0500173 return NULL;
174 }
175
176 if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
Steve Block29357bc2012-01-06 19:20:56 +0000177 ALOGE("usb_device_claim_interface failed errno: %d\n", errno);
Kenny Root31c52e72011-02-02 13:43:55 -0800178 usb_device_close(device);
Mike Lockwood23f1b332010-12-30 15:38:45 -0500179 return NULL;
180 }
181
182 MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber,
183 ep_in_desc, ep_out_desc, ep_intr_desc);
184 mtpDevice->initialize();
185 return mtpDevice;
186 }
187 }
188
189 usb_device_close(device);
Steve Block29357bc2012-01-06 19:20:56 +0000190 ALOGE("device not found");
Mike Lockwood23f1b332010-12-30 15:38:45 -0500191 return NULL;
192}
193
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400194MtpDevice::MtpDevice(struct usb_device* device, int interface,
Mike Lockwood42d0b792011-01-04 14:48:57 -0500195 const struct usb_endpoint_descriptor *ep_in,
196 const struct usb_endpoint_descriptor *ep_out,
197 const struct usb_endpoint_descriptor *ep_intr)
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400198 : mDevice(device),
199 mInterface(interface),
Mike Lockwood42d0b792011-01-04 14:48:57 -0500200 mRequestIn1(NULL),
201 mRequestIn2(NULL),
202 mRequestOut(NULL),
203 mRequestIntr(NULL),
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400204 mDeviceInfo(NULL),
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400205 mSessionID(0),
Mike Lockwoodf7454622010-12-09 18:34:18 -0800206 mTransactionID(0),
Daichi Hirono8a7ffae2015-08-20 15:13:40 +0900207 mReceivedResponse(false),
208 mProcessingEvent(false),
209 mCurrentEventHandle(0)
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400210{
Mike Lockwood42d0b792011-01-04 14:48:57 -0500211 mRequestIn1 = usb_request_new(device, ep_in);
212 mRequestIn2 = usb_request_new(device, ep_in);
213 mRequestOut = usb_request_new(device, ep_out);
214 mRequestIntr = usb_request_new(device, ep_intr);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400215}
216
217MtpDevice::~MtpDevice() {
218 close();
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700219 for (size_t i = 0; i < mDeviceProperties.size(); i++)
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400220 delete mDeviceProperties[i];
Mike Lockwood42d0b792011-01-04 14:48:57 -0500221 usb_request_free(mRequestIn1);
222 usb_request_free(mRequestIn2);
223 usb_request_free(mRequestOut);
224 usb_request_free(mRequestIntr);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400225}
226
227void MtpDevice::initialize() {
228 openSession();
229 mDeviceInfo = getDeviceInfo();
230 if (mDeviceInfo) {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400231 if (mDeviceInfo->mDeviceProperties) {
232 int count = mDeviceInfo->mDeviceProperties->size();
233 for (int i = 0; i < count; i++) {
234 MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
235 MtpProperty* property = getDevicePropDesc(propCode);
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800236 if (property)
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400237 mDeviceProperties.push(property);
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400238 }
239 }
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400240 }
241}
242
243void MtpDevice::close() {
244 if (mDevice) {
245 usb_device_release_interface(mDevice, mInterface);
246 usb_device_close(mDevice);
247 mDevice = NULL;
248 }
249}
250
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800251void MtpDevice::print() {
252 if (mDeviceInfo) {
253 mDeviceInfo->print();
254
255 if (mDeviceInfo->mDeviceProperties) {
Steve Blockdf64d152012-01-04 20:05:49 +0000256 ALOGI("***** DEVICE PROPERTIES *****\n");
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800257 int count = mDeviceInfo->mDeviceProperties->size();
258 for (int i = 0; i < count; i++) {
259 MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
260 MtpProperty* property = getDevicePropDesc(propCode);
261 if (property) {
262 property->print();
Kenny Root31c52e72011-02-02 13:43:55 -0800263 delete property;
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800264 }
265 }
266 }
267 }
268
269 if (mDeviceInfo->mPlaybackFormats) {
Steve Blockdf64d152012-01-04 20:05:49 +0000270 ALOGI("***** OBJECT PROPERTIES *****\n");
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800271 int count = mDeviceInfo->mPlaybackFormats->size();
272 for (int i = 0; i < count; i++) {
273 MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i];
Steve Blockdf64d152012-01-04 20:05:49 +0000274 ALOGI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format));
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800275 MtpObjectPropertyList* props = getObjectPropsSupported(format);
276 if (props) {
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700277 for (size_t j = 0; j < props->size(); j++) {
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800278 MtpObjectProperty prop = (*props)[j];
Mike Lockwood99e393a2010-12-07 18:53:04 -0800279 MtpProperty* property = getObjectPropDesc(prop, format);
Kenny Root31c52e72011-02-02 13:43:55 -0800280 if (property) {
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800281 property->print();
Kenny Root31c52e72011-02-02 13:43:55 -0800282 delete property;
283 } else {
Steve Block29357bc2012-01-06 19:20:56 +0000284 ALOGE("could not fetch property: %s",
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800285 MtpDebug::getObjectPropCodeName(prop));
Kenny Root31c52e72011-02-02 13:43:55 -0800286 }
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800287 }
288 }
289 }
290 }
291}
292
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400293const char* MtpDevice::getDeviceName() {
294 if (mDevice)
295 return usb_device_get_name(mDevice);
296 else
297 return "???";
298}
299
300bool MtpDevice::openSession() {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400301 Mutex::Autolock autoLock(mMutex);
302
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400303 mSessionID = 0;
304 mTransactionID = 0;
305 MtpSessionID newSession = 1;
306 mRequest.reset();
307 mRequest.setParameter(1, newSession);
308 if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
309 return false;
310 MtpResponseCode ret = readResponse();
311 if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
312 newSession = mResponse.getParameter(1);
313 else if (ret != MTP_RESPONSE_OK)
314 return false;
315
316 mSessionID = newSession;
317 mTransactionID = 1;
318 return true;
319}
320
321bool MtpDevice::closeSession() {
322 // FIXME
323 return true;
324}
325
326MtpDeviceInfo* MtpDevice::getDeviceInfo() {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400327 Mutex::Autolock autoLock(mMutex);
328
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400329 mRequest.reset();
330 if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
331 return NULL;
332 if (!readData())
333 return NULL;
334 MtpResponseCode ret = readResponse();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400335 if (ret == MTP_RESPONSE_OK) {
336 MtpDeviceInfo* info = new MtpDeviceInfo;
Mike Lockwoodab063842014-11-12 14:20:06 -0800337 if (info->read(mData))
338 return info;
339 else
340 delete info;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400341 }
342 return NULL;
343}
344
345MtpStorageIDList* MtpDevice::getStorageIDs() {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400346 Mutex::Autolock autoLock(mMutex);
347
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400348 mRequest.reset();
349 if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
350 return NULL;
351 if (!readData())
352 return NULL;
353 MtpResponseCode ret = readResponse();
354 if (ret == MTP_RESPONSE_OK) {
355 return mData.getAUInt32();
356 }
357 return NULL;
358}
359
360MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400361 Mutex::Autolock autoLock(mMutex);
362
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400363 mRequest.reset();
364 mRequest.setParameter(1, storageID);
365 if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
366 return NULL;
367 if (!readData())
368 return NULL;
369 MtpResponseCode ret = readResponse();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400370 if (ret == MTP_RESPONSE_OK) {
371 MtpStorageInfo* info = new MtpStorageInfo(storageID);
Mike Lockwoodab063842014-11-12 14:20:06 -0800372 if (info->read(mData))
373 return info;
374 else
375 delete info;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400376 }
377 return NULL;
378}
379
380MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
381 MtpObjectFormat format, MtpObjectHandle parent) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400382 Mutex::Autolock autoLock(mMutex);
383
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400384 mRequest.reset();
385 mRequest.setParameter(1, storageID);
386 mRequest.setParameter(2, format);
387 mRequest.setParameter(3, parent);
388 if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
389 return NULL;
390 if (!readData())
391 return NULL;
392 MtpResponseCode ret = readResponse();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400393 if (ret == MTP_RESPONSE_OK) {
394 return mData.getAUInt32();
395 }
396 return NULL;
397}
398
399MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400400 Mutex::Autolock autoLock(mMutex);
401
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400402 // FIXME - we might want to add some caching here
403
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400404 mRequest.reset();
405 mRequest.setParameter(1, handle);
406 if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
407 return NULL;
408 if (!readData())
409 return NULL;
410 MtpResponseCode ret = readResponse();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400411 if (ret == MTP_RESPONSE_OK) {
412 MtpObjectInfo* info = new MtpObjectInfo(handle);
Mike Lockwoodab063842014-11-12 14:20:06 -0800413 if (info->read(mData))
414 return info;
415 else
416 delete info;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400417 }
418 return NULL;
419}
420
Mike Lockwood3e072b32010-06-10 16:34:20 -0400421void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400422 Mutex::Autolock autoLock(mMutex);
423
Mike Lockwood3e072b32010-06-10 16:34:20 -0400424 mRequest.reset();
425 mRequest.setParameter(1, handle);
426 if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
427 MtpResponseCode ret = readResponse();
428 if (ret == MTP_RESPONSE_OK) {
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900429 return mData.getData(&outLength);
Mike Lockwood3e072b32010-06-10 16:34:20 -0400430 }
431 }
432 outLength = 0;
433 return NULL;
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400434}
Mike Lockwood3e072b32010-06-10 16:34:20 -0400435
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400436MtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
437 Mutex::Autolock autoLock(mMutex);
438
439 mRequest.reset();
440 MtpObjectHandle parent = info->mParent;
441 if (parent == 0)
442 parent = MTP_PARENT_ROOT;
443
444 mRequest.setParameter(1, info->mStorageID);
Tomasz Mikolajewski64c948b2015-08-13 15:31:02 +0900445 mRequest.setParameter(2, parent);
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400446
Tomasz Mikolajewski64c948b2015-08-13 15:31:02 +0900447 mData.reset();
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400448 mData.putUInt32(info->mStorageID);
449 mData.putUInt16(info->mFormat);
450 mData.putUInt16(info->mProtectionStatus);
451 mData.putUInt32(info->mCompressedSize);
452 mData.putUInt16(info->mThumbFormat);
453 mData.putUInt32(info->mThumbCompressedSize);
454 mData.putUInt32(info->mThumbPixWidth);
455 mData.putUInt32(info->mThumbPixHeight);
456 mData.putUInt32(info->mImagePixWidth);
457 mData.putUInt32(info->mImagePixHeight);
458 mData.putUInt32(info->mImagePixDepth);
459 mData.putUInt32(info->mParent);
460 mData.putUInt16(info->mAssociationType);
461 mData.putUInt32(info->mAssociationDesc);
462 mData.putUInt32(info->mSequenceNumber);
463 mData.putString(info->mName);
464
465 char created[100], modified[100];
466 formatDateTime(info->mDateCreated, created, sizeof(created));
467 formatDateTime(info->mDateModified, modified, sizeof(modified));
468
469 mData.putString(created);
470 mData.putString(modified);
471 if (info->mKeywords)
472 mData.putString(info->mKeywords);
473 else
474 mData.putEmptyString();
475
476 if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400477 MtpResponseCode ret = readResponse();
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400478 if (ret == MTP_RESPONSE_OK) {
479 info->mStorageID = mResponse.getParameter(1);
480 info->mParent = mResponse.getParameter(2);
481 info->mHandle = mResponse.getParameter(3);
482 return info->mHandle;
483 }
484 }
485 return (MtpObjectHandle)-1;
486}
487
Tomasz Mikolajewski532b4f22015-08-25 14:14:36 +0900488bool MtpDevice::sendObject(MtpObjectHandle handle, int size, int srcFD) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400489 Mutex::Autolock autoLock(mMutex);
490
Tomasz Mikolajewski532b4f22015-08-25 14:14:36 +0900491 int remaining = size;
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400492 mRequest.reset();
Tomasz Mikolajewski532b4f22015-08-25 14:14:36 +0900493 mRequest.setParameter(1, handle);
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400494 if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400495 // send data header
496 writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
497
Tomasz Mikolajewski532b4f22015-08-25 14:14:36 +0900498 // USB writes greater than 16K don't work
499 char buffer[MTP_BUFFER_SIZE];
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400500 while (remaining > 0) {
501 int count = read(srcFD, buffer, sizeof(buffer));
502 if (count > 0) {
Mike Lockwood42d0b792011-01-04 14:48:57 -0500503 int written = mData.write(mRequestOut, buffer, count);
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400504 // FIXME check error
505 remaining -= count;
506 } else {
507 break;
508 }
509 }
510 }
511 MtpResponseCode ret = readResponse();
512 return (remaining == 0 && ret == MTP_RESPONSE_OK);
513}
514
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400515bool MtpDevice::deleteObject(MtpObjectHandle handle) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400516 Mutex::Autolock autoLock(mMutex);
517
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400518 mRequest.reset();
519 mRequest.setParameter(1, handle);
520 if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
521 MtpResponseCode ret = readResponse();
522 if (ret == MTP_RESPONSE_OK)
523 return true;
524 }
525 return false;
526}
527
528MtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
529 MtpObjectInfo* info = getObjectInfo(handle);
Kenny Root31c52e72011-02-02 13:43:55 -0800530 if (info) {
531 MtpObjectHandle parent = info->mParent;
532 delete info;
533 return parent;
534 } else {
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400535 return -1;
Kenny Root31c52e72011-02-02 13:43:55 -0800536 }
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400537}
538
539MtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
540 MtpObjectInfo* info = getObjectInfo(handle);
Kenny Root31c52e72011-02-02 13:43:55 -0800541 if (info) {
542 MtpObjectHandle storageId = info->mStorageID;
543 delete info;
544 return storageId;
545 } else {
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400546 return -1;
Kenny Root31c52e72011-02-02 13:43:55 -0800547 }
Mike Lockwood3e072b32010-06-10 16:34:20 -0400548}
549
Mike Lockwood98693f62010-12-07 10:58:56 -0800550MtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
551 Mutex::Autolock autoLock(mMutex);
552
553 mRequest.reset();
554 mRequest.setParameter(1, format);
555 if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED))
556 return NULL;
557 if (!readData())
558 return NULL;
559 MtpResponseCode ret = readResponse();
560 if (ret == MTP_RESPONSE_OK) {
561 return mData.getAUInt16();
562 }
563 return NULL;
564
565}
566
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400567MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400568 Mutex::Autolock autoLock(mMutex);
569
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400570 mRequest.reset();
571 mRequest.setParameter(1, code);
572 if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
573 return NULL;
574 if (!readData())
575 return NULL;
576 MtpResponseCode ret = readResponse();
577 if (ret == MTP_RESPONSE_OK) {
578 MtpProperty* property = new MtpProperty;
Mike Lockwoodab063842014-11-12 14:20:06 -0800579 if (property->read(mData))
580 return property;
581 else
582 delete property;
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400583 }
584 return NULL;
585}
586
Mike Lockwood99e393a2010-12-07 18:53:04 -0800587MtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
Mike Lockwood98693f62010-12-07 10:58:56 -0800588 Mutex::Autolock autoLock(mMutex);
589
590 mRequest.reset();
591 mRequest.setParameter(1, code);
Mike Lockwood99e393a2010-12-07 18:53:04 -0800592 mRequest.setParameter(2, format);
Mike Lockwood98693f62010-12-07 10:58:56 -0800593 if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC))
594 return NULL;
595 if (!readData())
596 return NULL;
597 MtpResponseCode ret = readResponse();
598 if (ret == MTP_RESPONSE_OK) {
599 MtpProperty* property = new MtpProperty;
Mike Lockwoodab063842014-11-12 14:20:06 -0800600 if (property->read(mData))
601 return property;
602 else
603 delete property;
Mike Lockwood98693f62010-12-07 10:58:56 -0800604 }
605 return NULL;
606}
607
Mike Lockwood23f1b332010-12-30 15:38:45 -0500608bool MtpDevice::readObject(MtpObjectHandle handle,
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900609 ReadObjectCallback callback,
610 size_t expectedLength,
611 void* clientData) {
612 return readObjectInternal(handle, callback, &expectedLength, clientData);
Mike Lockwood23f1b332010-12-30 15:38:45 -0500613}
614
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500615// reads the object's data and writes it to the specified file path
Mike Lockwood27afe3a2010-11-19 13:52:20 -0500616bool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
Steve Blockb8a80522011-12-20 16:23:08 +0000617 ALOGD("readObject: %s", destPath);
Nick Kralevichaf8e8aa2012-06-26 13:32:23 -0700618 int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500619 if (fd < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000620 ALOGE("open failed for %s", destPath);
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400621 return false;
622 }
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400623
Mike Lockwood27afe3a2010-11-19 13:52:20 -0500624 fchown(fd, getuid(), group);
625 // set permissions
626 int mask = umask(0);
627 fchmod(fd, perm);
628 umask(mask);
629
Tomasz Mikolajewski025ffd92015-08-04 18:38:31 +0900630 bool result = readObject(handle, fd);
631 ::close(fd);
632 return result;
633}
634
635bool MtpDevice::readObject(MtpObjectHandle handle, int fd) {
636 ALOGD("readObject: %d", fd);
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900637 return readObjectInternal(handle, writeToFd, NULL /* expected size */, &fd);
638}
Tomasz Mikolajewski025ffd92015-08-04 18:38:31 +0900639
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900640bool MtpDevice::readObjectInternal(MtpObjectHandle handle,
641 ReadObjectCallback callback,
642 const size_t* expectedLength,
643 void* clientData) {
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500644 Mutex::Autolock autoLock(mMutex);
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400645
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500646 mRequest.reset();
647 mRequest.setParameter(1, handle);
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900648 if (!sendRequest(MTP_OPERATION_GET_OBJECT)) {
649 ALOGE("Failed to send a read request.");
650 return false;
651 }
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500652
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900653 if (!mData.readDataHeader(mRequestIn1)) {
654 ALOGE("Failed to read header.");
655 return false;
656 }
657
658 const uint32_t fullLength = mData.getContainerLength();
659 if ((!expectedLength && fullLength < MTP_CONTAINER_HEADER_SIZE) ||
660 (expectedLength && *expectedLength + MTP_CONTAINER_HEADER_SIZE != fullLength)) {
661 ALOGE("readObject error length: %d", fullLength);
662 return false;
663 }
664
665 const uint32_t length = fullLength - MTP_CONTAINER_HEADER_SIZE;
666 uint32_t offset = 0;
667 bool writingError = false;
668
669 {
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500670 int initialDataLength = 0;
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900671 void* const initialData = mData.getData(&initialDataLength);
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500672 if (initialData) {
673 if (initialDataLength > 0) {
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900674 if (!callback(initialData, offset, initialDataLength, clientData)) {
Daichi Hirono81ca5ad2015-08-18 21:13:40 +0900675 ALOGE("Failed to write initial data.");
676 writingError = true;
Kenny Root31c52e72011-02-02 13:43:55 -0800677 }
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900678 offset += initialDataLength;
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500679 }
680 free(initialData);
681 }
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900682 }
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500683
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900684 // USB reads greater than 16K don't work.
685 char buffer1[MTP_BUFFER_SIZE], buffer2[MTP_BUFFER_SIZE];
686 mRequestIn1->buffer = buffer1;
687 mRequestIn2->buffer = buffer2;
688 struct usb_request* req = NULL;
689
690 while (offset < length) {
691 // Wait for previous read to complete.
Mike Lockwood42d0b792011-01-04 14:48:57 -0500692 void* writeBuffer = NULL;
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500693 int writeLength = 0;
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900694 if (req) {
695 const int read = mData.readDataWait(mDevice);
696 if (read < 0) {
697 ALOGE("readDataWait failed.");
698 return false;
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500699 }
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900700 writeBuffer = req->buffer;
701 writeLength = read;
702 }
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500703
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900704 // Request to read next chunk.
705 const uint32_t nextOffset = offset + writeLength;
706 if (nextOffset < length) {
707 // Queue up a read request.
708 const size_t remaining = length - nextOffset;
709 req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
710 req->buffer_length =
711 remaining > MTP_BUFFER_SIZE ? static_cast<size_t>(MTP_BUFFER_SIZE) : remaining;
712 if (mData.readDataAsync(req) != 0) {
713 ALOGE("readDataAsync failed");
714 return false;
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500715 }
716 }
717
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900718 // Write previous buffer.
719 if (writeBuffer && !writingError) {
720 if (!callback(writeBuffer, offset, writeLength, clientData)) {
721 ALOGE("write failed");
722 writingError = true;
723 }
724 }
725 offset = nextOffset;
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400726 }
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500727
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900728 return readResponse() == MTP_RESPONSE_OK && !writingError;
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400729}
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400730
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400731bool MtpDevice::sendRequest(MtpOperationCode operation) {
Steve Block3856b092011-10-20 11:56:00 +0100732 ALOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
Mike Lockwoodf7454622010-12-09 18:34:18 -0800733 mReceivedResponse = false;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400734 mRequest.setOperationCode(operation);
735 if (mTransactionID > 0)
736 mRequest.setTransactionID(mTransactionID++);
Mike Lockwood42d0b792011-01-04 14:48:57 -0500737 int ret = mRequest.write(mRequestOut);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400738 mRequest.dump();
739 return (ret > 0);
740}
741
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400742bool MtpDevice::sendData() {
Steve Block3856b092011-10-20 11:56:00 +0100743 ALOGV("sendData\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400744 mData.setOperationCode(mRequest.getOperationCode());
745 mData.setTransactionID(mRequest.getTransactionID());
Mike Lockwood42d0b792011-01-04 14:48:57 -0500746 int ret = mData.write(mRequestOut);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400747 mData.dump();
Tomasz Mikolajewski64c948b2015-08-13 15:31:02 +0900748 return (ret >= 0);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400749}
750
751bool MtpDevice::readData() {
752 mData.reset();
Mike Lockwood42d0b792011-01-04 14:48:57 -0500753 int ret = mData.read(mRequestIn1);
Steve Block3856b092011-10-20 11:56:00 +0100754 ALOGV("readData returned %d\n", ret);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400755 if (ret >= MTP_CONTAINER_HEADER_SIZE) {
Mike Lockwoodf7454622010-12-09 18:34:18 -0800756 if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
Steve Blockb8a80522011-12-20 16:23:08 +0000757 ALOGD("got response packet instead of data packet");
Mike Lockwoodf7454622010-12-09 18:34:18 -0800758 // we got a response packet rather than data
759 // copy it to mResponse
760 mResponse.copyFrom(mData);
761 mReceivedResponse = true;
762 return false;
763 }
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400764 mData.dump();
765 return true;
766 }
767 else {
Steve Block3856b092011-10-20 11:56:00 +0100768 ALOGV("readResponse failed\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400769 return false;
770 }
771}
772
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400773bool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
774 mData.setOperationCode(operation);
775 mData.setTransactionID(mRequest.getTransactionID());
Mike Lockwood42d0b792011-01-04 14:48:57 -0500776 return (!mData.writeDataHeader(mRequestOut, dataLength));
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400777}
778
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400779MtpResponseCode MtpDevice::readResponse() {
Steve Block3856b092011-10-20 11:56:00 +0100780 ALOGV("readResponse\n");
Mike Lockwoodf7454622010-12-09 18:34:18 -0800781 if (mReceivedResponse) {
782 mReceivedResponse = false;
783 return mResponse.getResponseCode();
784 }
Mike Lockwood42d0b792011-01-04 14:48:57 -0500785 int ret = mResponse.read(mRequestIn1);
Mike Lockwood3d744572011-03-14 10:33:22 -0400786 // handle zero length packets, which might occur if the data transfer
787 // ends on a packet boundary
788 if (ret == 0)
789 ret = mResponse.read(mRequestIn1);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400790 if (ret >= MTP_CONTAINER_HEADER_SIZE) {
791 mResponse.dump();
792 return mResponse.getResponseCode();
Mike Lockwoodf7454622010-12-09 18:34:18 -0800793 } else {
Steve Blockb8a80522011-12-20 16:23:08 +0000794 ALOGD("readResponse failed\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400795 return -1;
796 }
797}
798
Daichi Hirono8a7ffae2015-08-20 15:13:40 +0900799int MtpDevice::submitEventRequest() {
800 if (mEventMutex.tryLock()) {
801 // An event is being reaped on another thread.
802 return -1;
803 }
804 if (mProcessingEvent) {
805 // An event request was submitted, but no reapEventRequest called so far.
806 return -1;
807 }
808 Mutex::Autolock autoLock(mEventMutexForInterrupt);
809 mEventPacket.sendRequest(mRequestIntr);
810 const int currentHandle = ++mCurrentEventHandle;
811 mProcessingEvent = true;
812 mEventMutex.unlock();
813 return currentHandle;
814}
815
816int MtpDevice::reapEventRequest(int handle) {
817 Mutex::Autolock autoLock(mEventMutex);
818 if (!mProcessingEvent || mCurrentEventHandle != handle) {
819 return -1;
820 }
821 mProcessingEvent = false;
822 const int readSize = mEventPacket.readResponse(mRequestIntr->dev);
823 const int result = mEventPacket.getEventCode();
824 return readSize == 0 ? 0 : result;
825}
826
827void MtpDevice::discardEventRequest(int handle) {
828 Mutex::Autolock autoLock(mEventMutexForInterrupt);
829 if (mCurrentEventHandle != handle) {
830 return;
831 }
832 usb_request_cancel(mRequestIntr);
833}
834
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400835} // namespace android