blob: 23e432e92416c0f65b8915c69ba9283c64050978 [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 }
Daichi Hironod6dabe92015-12-02 15:08:48 +0900136#else
137 else {
138 continue;
139 }
Mike Lockwoodd4fb52e2011-02-15 14:55:51 -0500140#endif
Mike Lockwood23f1b332010-12-30 15:38:45 -0500141 // if we got here, then we have a likely MTP or PTP device
142
143 // interface should be followed by three endpoints
144 struct usb_endpoint_descriptor *ep;
145 struct usb_endpoint_descriptor *ep_in_desc = NULL;
146 struct usb_endpoint_descriptor *ep_out_desc = NULL;
147 struct usb_endpoint_descriptor *ep_intr_desc = NULL;
Bo Huang8023f3a2013-06-09 08:53:21 +0800148 //USB3 add USB_DT_SS_ENDPOINT_COMP as companion descriptor;
149 struct usb_ss_ep_comp_descriptor *ep_ss_ep_comp_desc = NULL;
Mike Lockwood23f1b332010-12-30 15:38:45 -0500150 for (int i = 0; i < 3; i++) {
151 ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
Bo Huang8023f3a2013-06-09 08:53:21 +0800152 if (ep && ep->bDescriptorType == USB_DT_SS_ENDPOINT_COMP) {
153 ALOGD("Descriptor type is USB_DT_SS_ENDPOINT_COMP for USB3 \n");
154 ep_ss_ep_comp_desc = (usb_ss_ep_comp_descriptor*)ep;
155 ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter);
156 }
157
Mike Lockwood23f1b332010-12-30 15:38:45 -0500158 if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) {
Steve Block29357bc2012-01-06 19:20:56 +0000159 ALOGE("endpoints not found\n");
Kenny Root31c52e72011-02-02 13:43:55 -0800160 usb_device_close(device);
Mike Lockwood23f1b332010-12-30 15:38:45 -0500161 return NULL;
162 }
Bo Huang8023f3a2013-06-09 08:53:21 +0800163
Mike Lockwood23f1b332010-12-30 15:38:45 -0500164 if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) {
165 if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
166 ep_in_desc = ep;
167 else
168 ep_out_desc = ep;
169 } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT &&
170 ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
171 ep_intr_desc = ep;
172 }
173 }
174 if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) {
Steve Block29357bc2012-01-06 19:20:56 +0000175 ALOGE("endpoints not found\n");
Kenny Root31c52e72011-02-02 13:43:55 -0800176 usb_device_close(device);
Mike Lockwood23f1b332010-12-30 15:38:45 -0500177 return NULL;
178 }
179
180 if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
Steve Block29357bc2012-01-06 19:20:56 +0000181 ALOGE("usb_device_claim_interface failed errno: %d\n", errno);
Kenny Root31c52e72011-02-02 13:43:55 -0800182 usb_device_close(device);
Mike Lockwood23f1b332010-12-30 15:38:45 -0500183 return NULL;
184 }
185
186 MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber,
187 ep_in_desc, ep_out_desc, ep_intr_desc);
188 mtpDevice->initialize();
189 return mtpDevice;
190 }
191 }
192
193 usb_device_close(device);
Steve Block29357bc2012-01-06 19:20:56 +0000194 ALOGE("device not found");
Mike Lockwood23f1b332010-12-30 15:38:45 -0500195 return NULL;
196}
197
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400198MtpDevice::MtpDevice(struct usb_device* device, int interface,
Mike Lockwood42d0b792011-01-04 14:48:57 -0500199 const struct usb_endpoint_descriptor *ep_in,
200 const struct usb_endpoint_descriptor *ep_out,
201 const struct usb_endpoint_descriptor *ep_intr)
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400202 : mDevice(device),
203 mInterface(interface),
Mike Lockwood42d0b792011-01-04 14:48:57 -0500204 mRequestIn1(NULL),
205 mRequestIn2(NULL),
206 mRequestOut(NULL),
207 mRequestIntr(NULL),
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400208 mDeviceInfo(NULL),
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400209 mSessionID(0),
Mike Lockwoodf7454622010-12-09 18:34:18 -0800210 mTransactionID(0),
Daichi Hirono8a7ffae2015-08-20 15:13:40 +0900211 mReceivedResponse(false),
212 mProcessingEvent(false),
213 mCurrentEventHandle(0)
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400214{
Mike Lockwood42d0b792011-01-04 14:48:57 -0500215 mRequestIn1 = usb_request_new(device, ep_in);
216 mRequestIn2 = usb_request_new(device, ep_in);
217 mRequestOut = usb_request_new(device, ep_out);
218 mRequestIntr = usb_request_new(device, ep_intr);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400219}
220
221MtpDevice::~MtpDevice() {
222 close();
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700223 for (size_t i = 0; i < mDeviceProperties.size(); i++)
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400224 delete mDeviceProperties[i];
Mike Lockwood42d0b792011-01-04 14:48:57 -0500225 usb_request_free(mRequestIn1);
226 usb_request_free(mRequestIn2);
227 usb_request_free(mRequestOut);
228 usb_request_free(mRequestIntr);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400229}
230
231void MtpDevice::initialize() {
232 openSession();
233 mDeviceInfo = getDeviceInfo();
234 if (mDeviceInfo) {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400235 if (mDeviceInfo->mDeviceProperties) {
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);
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800240 if (property)
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400241 mDeviceProperties.push(property);
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400242 }
243 }
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400244 }
245}
246
247void MtpDevice::close() {
248 if (mDevice) {
249 usb_device_release_interface(mDevice, mInterface);
250 usb_device_close(mDevice);
251 mDevice = NULL;
252 }
253}
254
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800255void MtpDevice::print() {
256 if (mDeviceInfo) {
257 mDeviceInfo->print();
258
259 if (mDeviceInfo->mDeviceProperties) {
Steve Blockdf64d152012-01-04 20:05:49 +0000260 ALOGI("***** DEVICE PROPERTIES *****\n");
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800261 int count = mDeviceInfo->mDeviceProperties->size();
262 for (int i = 0; i < count; i++) {
263 MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
264 MtpProperty* property = getDevicePropDesc(propCode);
265 if (property) {
266 property->print();
Kenny Root31c52e72011-02-02 13:43:55 -0800267 delete property;
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800268 }
269 }
270 }
271 }
272
273 if (mDeviceInfo->mPlaybackFormats) {
Steve Blockdf64d152012-01-04 20:05:49 +0000274 ALOGI("***** OBJECT PROPERTIES *****\n");
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800275 int count = mDeviceInfo->mPlaybackFormats->size();
276 for (int i = 0; i < count; i++) {
277 MtpObjectFormat format = (*mDeviceInfo->mPlaybackFormats)[i];
Steve Blockdf64d152012-01-04 20:05:49 +0000278 ALOGI("*** FORMAT: %s\n", MtpDebug::getFormatCodeName(format));
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800279 MtpObjectPropertyList* props = getObjectPropsSupported(format);
280 if (props) {
Mark Salyzyn3ab368e2014-04-15 14:55:53 -0700281 for (size_t j = 0; j < props->size(); j++) {
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800282 MtpObjectProperty prop = (*props)[j];
Mike Lockwood99e393a2010-12-07 18:53:04 -0800283 MtpProperty* property = getObjectPropDesc(prop, format);
Kenny Root31c52e72011-02-02 13:43:55 -0800284 if (property) {
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800285 property->print();
Kenny Root31c52e72011-02-02 13:43:55 -0800286 delete property;
287 } else {
Steve Block29357bc2012-01-06 19:20:56 +0000288 ALOGE("could not fetch property: %s",
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800289 MtpDebug::getObjectPropCodeName(prop));
Kenny Root31c52e72011-02-02 13:43:55 -0800290 }
Mike Lockwood0c7c7c72010-12-07 11:24:28 -0800291 }
292 }
293 }
294 }
295}
296
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400297const char* MtpDevice::getDeviceName() {
298 if (mDevice)
299 return usb_device_get_name(mDevice);
300 else
301 return "???";
302}
303
304bool MtpDevice::openSession() {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400305 Mutex::Autolock autoLock(mMutex);
306
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400307 mSessionID = 0;
308 mTransactionID = 0;
309 MtpSessionID newSession = 1;
310 mRequest.reset();
311 mRequest.setParameter(1, newSession);
312 if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
313 return false;
314 MtpResponseCode ret = readResponse();
315 if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
316 newSession = mResponse.getParameter(1);
317 else if (ret != MTP_RESPONSE_OK)
318 return false;
319
320 mSessionID = newSession;
321 mTransactionID = 1;
322 return true;
323}
324
325bool MtpDevice::closeSession() {
326 // FIXME
327 return true;
328}
329
330MtpDeviceInfo* MtpDevice::getDeviceInfo() {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400331 Mutex::Autolock autoLock(mMutex);
332
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400333 mRequest.reset();
334 if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
335 return NULL;
336 if (!readData())
337 return NULL;
338 MtpResponseCode ret = readResponse();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400339 if (ret == MTP_RESPONSE_OK) {
340 MtpDeviceInfo* info = new MtpDeviceInfo;
Mike Lockwoodab063842014-11-12 14:20:06 -0800341 if (info->read(mData))
342 return info;
343 else
344 delete info;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400345 }
346 return NULL;
347}
348
349MtpStorageIDList* MtpDevice::getStorageIDs() {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400350 Mutex::Autolock autoLock(mMutex);
351
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400352 mRequest.reset();
353 if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
354 return NULL;
355 if (!readData())
356 return NULL;
357 MtpResponseCode ret = readResponse();
358 if (ret == MTP_RESPONSE_OK) {
359 return mData.getAUInt32();
360 }
361 return NULL;
362}
363
364MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400365 Mutex::Autolock autoLock(mMutex);
366
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400367 mRequest.reset();
368 mRequest.setParameter(1, storageID);
369 if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
370 return NULL;
371 if (!readData())
372 return NULL;
373 MtpResponseCode ret = readResponse();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400374 if (ret == MTP_RESPONSE_OK) {
375 MtpStorageInfo* info = new MtpStorageInfo(storageID);
Mike Lockwoodab063842014-11-12 14:20:06 -0800376 if (info->read(mData))
377 return info;
378 else
379 delete info;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400380 }
381 return NULL;
382}
383
384MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
385 MtpObjectFormat format, MtpObjectHandle parent) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400386 Mutex::Autolock autoLock(mMutex);
387
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400388 mRequest.reset();
389 mRequest.setParameter(1, storageID);
390 mRequest.setParameter(2, format);
391 mRequest.setParameter(3, parent);
392 if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
393 return NULL;
394 if (!readData())
395 return NULL;
396 MtpResponseCode ret = readResponse();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400397 if (ret == MTP_RESPONSE_OK) {
398 return mData.getAUInt32();
399 }
400 return NULL;
401}
402
403MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400404 Mutex::Autolock autoLock(mMutex);
405
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400406 // FIXME - we might want to add some caching here
407
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400408 mRequest.reset();
409 mRequest.setParameter(1, handle);
410 if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
411 return NULL;
412 if (!readData())
413 return NULL;
414 MtpResponseCode ret = readResponse();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400415 if (ret == MTP_RESPONSE_OK) {
416 MtpObjectInfo* info = new MtpObjectInfo(handle);
Mike Lockwoodab063842014-11-12 14:20:06 -0800417 if (info->read(mData))
418 return info;
419 else
420 delete info;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400421 }
422 return NULL;
423}
424
Mike Lockwood3e072b32010-06-10 16:34:20 -0400425void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400426 Mutex::Autolock autoLock(mMutex);
427
Mike Lockwood3e072b32010-06-10 16:34:20 -0400428 mRequest.reset();
429 mRequest.setParameter(1, handle);
430 if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
431 MtpResponseCode ret = readResponse();
432 if (ret == MTP_RESPONSE_OK) {
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900433 return mData.getData(&outLength);
Mike Lockwood3e072b32010-06-10 16:34:20 -0400434 }
435 }
436 outLength = 0;
437 return NULL;
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400438}
Mike Lockwood3e072b32010-06-10 16:34:20 -0400439
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400440MtpObjectHandle MtpDevice::sendObjectInfo(MtpObjectInfo* info) {
441 Mutex::Autolock autoLock(mMutex);
442
443 mRequest.reset();
444 MtpObjectHandle parent = info->mParent;
445 if (parent == 0)
446 parent = MTP_PARENT_ROOT;
447
448 mRequest.setParameter(1, info->mStorageID);
Tomasz Mikolajewski64c948b2015-08-13 15:31:02 +0900449 mRequest.setParameter(2, parent);
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400450
Tomasz Mikolajewski64c948b2015-08-13 15:31:02 +0900451 mData.reset();
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400452 mData.putUInt32(info->mStorageID);
453 mData.putUInt16(info->mFormat);
454 mData.putUInt16(info->mProtectionStatus);
455 mData.putUInt32(info->mCompressedSize);
456 mData.putUInt16(info->mThumbFormat);
457 mData.putUInt32(info->mThumbCompressedSize);
458 mData.putUInt32(info->mThumbPixWidth);
459 mData.putUInt32(info->mThumbPixHeight);
460 mData.putUInt32(info->mImagePixWidth);
461 mData.putUInt32(info->mImagePixHeight);
462 mData.putUInt32(info->mImagePixDepth);
463 mData.putUInt32(info->mParent);
464 mData.putUInt16(info->mAssociationType);
465 mData.putUInt32(info->mAssociationDesc);
466 mData.putUInt32(info->mSequenceNumber);
467 mData.putString(info->mName);
468
469 char created[100], modified[100];
470 formatDateTime(info->mDateCreated, created, sizeof(created));
471 formatDateTime(info->mDateModified, modified, sizeof(modified));
472
473 mData.putString(created);
474 mData.putString(modified);
475 if (info->mKeywords)
476 mData.putString(info->mKeywords);
477 else
478 mData.putEmptyString();
479
480 if (sendRequest(MTP_OPERATION_SEND_OBJECT_INFO) && sendData()) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400481 MtpResponseCode ret = readResponse();
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400482 if (ret == MTP_RESPONSE_OK) {
483 info->mStorageID = mResponse.getParameter(1);
484 info->mParent = mResponse.getParameter(2);
485 info->mHandle = mResponse.getParameter(3);
486 return info->mHandle;
487 }
488 }
489 return (MtpObjectHandle)-1;
490}
491
Tomasz Mikolajewski532b4f22015-08-25 14:14:36 +0900492bool MtpDevice::sendObject(MtpObjectHandle handle, int size, int srcFD) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400493 Mutex::Autolock autoLock(mMutex);
494
Tomasz Mikolajewski532b4f22015-08-25 14:14:36 +0900495 int remaining = size;
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400496 mRequest.reset();
Tomasz Mikolajewski532b4f22015-08-25 14:14:36 +0900497 mRequest.setParameter(1, handle);
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400498 if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400499 // send data header
500 writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
501
Tomasz Mikolajewski532b4f22015-08-25 14:14:36 +0900502 // USB writes greater than 16K don't work
503 char buffer[MTP_BUFFER_SIZE];
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400504 while (remaining > 0) {
505 int count = read(srcFD, buffer, sizeof(buffer));
506 if (count > 0) {
Mike Lockwood42d0b792011-01-04 14:48:57 -0500507 int written = mData.write(mRequestOut, buffer, count);
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400508 // FIXME check error
509 remaining -= count;
510 } else {
511 break;
512 }
513 }
514 }
515 MtpResponseCode ret = readResponse();
516 return (remaining == 0 && ret == MTP_RESPONSE_OK);
517}
518
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400519bool MtpDevice::deleteObject(MtpObjectHandle handle) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400520 Mutex::Autolock autoLock(mMutex);
521
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400522 mRequest.reset();
523 mRequest.setParameter(1, handle);
524 if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
525 MtpResponseCode ret = readResponse();
526 if (ret == MTP_RESPONSE_OK)
527 return true;
528 }
529 return false;
530}
531
532MtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
533 MtpObjectInfo* info = getObjectInfo(handle);
Kenny Root31c52e72011-02-02 13:43:55 -0800534 if (info) {
535 MtpObjectHandle parent = info->mParent;
536 delete info;
537 return parent;
538 } else {
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400539 return -1;
Kenny Root31c52e72011-02-02 13:43:55 -0800540 }
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400541}
542
543MtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
544 MtpObjectInfo* info = getObjectInfo(handle);
Kenny Root31c52e72011-02-02 13:43:55 -0800545 if (info) {
546 MtpObjectHandle storageId = info->mStorageID;
547 delete info;
548 return storageId;
549 } else {
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400550 return -1;
Kenny Root31c52e72011-02-02 13:43:55 -0800551 }
Mike Lockwood3e072b32010-06-10 16:34:20 -0400552}
553
Mike Lockwood98693f62010-12-07 10:58:56 -0800554MtpObjectPropertyList* MtpDevice::getObjectPropsSupported(MtpObjectFormat format) {
555 Mutex::Autolock autoLock(mMutex);
556
557 mRequest.reset();
558 mRequest.setParameter(1, format);
559 if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED))
560 return NULL;
561 if (!readData())
562 return NULL;
563 MtpResponseCode ret = readResponse();
564 if (ret == MTP_RESPONSE_OK) {
565 return mData.getAUInt16();
566 }
567 return NULL;
568
569}
570
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400571MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400572 Mutex::Autolock autoLock(mMutex);
573
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400574 mRequest.reset();
575 mRequest.setParameter(1, code);
576 if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
577 return NULL;
578 if (!readData())
579 return NULL;
580 MtpResponseCode ret = readResponse();
581 if (ret == MTP_RESPONSE_OK) {
582 MtpProperty* property = new MtpProperty;
Mike Lockwoodab063842014-11-12 14:20:06 -0800583 if (property->read(mData))
584 return property;
585 else
586 delete property;
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400587 }
588 return NULL;
589}
590
Mike Lockwood99e393a2010-12-07 18:53:04 -0800591MtpProperty* MtpDevice::getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format) {
Mike Lockwood98693f62010-12-07 10:58:56 -0800592 Mutex::Autolock autoLock(mMutex);
593
594 mRequest.reset();
595 mRequest.setParameter(1, code);
Mike Lockwood99e393a2010-12-07 18:53:04 -0800596 mRequest.setParameter(2, format);
Mike Lockwood98693f62010-12-07 10:58:56 -0800597 if (!sendRequest(MTP_OPERATION_GET_OBJECT_PROP_DESC))
598 return NULL;
599 if (!readData())
600 return NULL;
601 MtpResponseCode ret = readResponse();
602 if (ret == MTP_RESPONSE_OK) {
603 MtpProperty* property = new MtpProperty;
Mike Lockwoodab063842014-11-12 14:20:06 -0800604 if (property->read(mData))
605 return property;
606 else
607 delete property;
Mike Lockwood98693f62010-12-07 10:58:56 -0800608 }
609 return NULL;
610}
611
Mike Lockwood23f1b332010-12-30 15:38:45 -0500612bool MtpDevice::readObject(MtpObjectHandle handle,
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900613 ReadObjectCallback callback,
614 size_t expectedLength,
615 void* clientData) {
616 return readObjectInternal(handle, callback, &expectedLength, clientData);
Mike Lockwood23f1b332010-12-30 15:38:45 -0500617}
618
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500619// reads the object's data and writes it to the specified file path
Mike Lockwood27afe3a2010-11-19 13:52:20 -0500620bool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
Steve Blockb8a80522011-12-20 16:23:08 +0000621 ALOGD("readObject: %s", destPath);
Nick Kralevichaf8e8aa2012-06-26 13:32:23 -0700622 int fd = ::open(destPath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500623 if (fd < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000624 ALOGE("open failed for %s", destPath);
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400625 return false;
626 }
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400627
Mike Lockwood27afe3a2010-11-19 13:52:20 -0500628 fchown(fd, getuid(), group);
629 // set permissions
630 int mask = umask(0);
631 fchmod(fd, perm);
632 umask(mask);
633
Tomasz Mikolajewski025ffd92015-08-04 18:38:31 +0900634 bool result = readObject(handle, fd);
635 ::close(fd);
636 return result;
637}
638
639bool MtpDevice::readObject(MtpObjectHandle handle, int fd) {
640 ALOGD("readObject: %d", fd);
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900641 return readObjectInternal(handle, writeToFd, NULL /* expected size */, &fd);
642}
Tomasz Mikolajewski025ffd92015-08-04 18:38:31 +0900643
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900644bool MtpDevice::readObjectInternal(MtpObjectHandle handle,
645 ReadObjectCallback callback,
646 const size_t* expectedLength,
647 void* clientData) {
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500648 Mutex::Autolock autoLock(mMutex);
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400649
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500650 mRequest.reset();
651 mRequest.setParameter(1, handle);
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900652 if (!sendRequest(MTP_OPERATION_GET_OBJECT)) {
653 ALOGE("Failed to send a read request.");
654 return false;
655 }
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500656
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900657 if (!mData.readDataHeader(mRequestIn1)) {
658 ALOGE("Failed to read header.");
659 return false;
660 }
661
Daichi Hironoa04e6fa2015-12-24 14:20:44 +0900662 // If object size 0 byte, the remote device can reply response packet
663 // without sending any data packets.
664 if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
665 mResponse.copyFrom(mData);
666 return mResponse.getResponseCode() == MTP_RESPONSE_OK;
667 }
668
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900669 const uint32_t fullLength = mData.getContainerLength();
670 if ((!expectedLength && fullLength < MTP_CONTAINER_HEADER_SIZE) ||
671 (expectedLength && *expectedLength + MTP_CONTAINER_HEADER_SIZE != fullLength)) {
672 ALOGE("readObject error length: %d", fullLength);
673 return false;
674 }
675
676 const uint32_t length = fullLength - MTP_CONTAINER_HEADER_SIZE;
677 uint32_t offset = 0;
678 bool writingError = false;
679
680 {
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500681 int initialDataLength = 0;
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900682 void* const initialData = mData.getData(&initialDataLength);
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500683 if (initialData) {
684 if (initialDataLength > 0) {
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900685 if (!callback(initialData, offset, initialDataLength, clientData)) {
Daichi Hirono81ca5ad2015-08-18 21:13:40 +0900686 ALOGE("Failed to write initial data.");
687 writingError = true;
Kenny Root31c52e72011-02-02 13:43:55 -0800688 }
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900689 offset += initialDataLength;
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500690 }
691 free(initialData);
692 }
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900693 }
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500694
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900695 // USB reads greater than 16K don't work.
696 char buffer1[MTP_BUFFER_SIZE], buffer2[MTP_BUFFER_SIZE];
697 mRequestIn1->buffer = buffer1;
698 mRequestIn2->buffer = buffer2;
699 struct usb_request* req = NULL;
700
701 while (offset < length) {
702 // Wait for previous read to complete.
Mike Lockwood42d0b792011-01-04 14:48:57 -0500703 void* writeBuffer = NULL;
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500704 int writeLength = 0;
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900705 if (req) {
706 const int read = mData.readDataWait(mDevice);
707 if (read < 0) {
708 ALOGE("readDataWait failed.");
709 return false;
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500710 }
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900711 writeBuffer = req->buffer;
712 writeLength = read;
713 }
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500714
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900715 // Request to read next chunk.
716 const uint32_t nextOffset = offset + writeLength;
717 if (nextOffset < length) {
718 // Queue up a read request.
719 const size_t remaining = length - nextOffset;
720 req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
721 req->buffer_length =
722 remaining > MTP_BUFFER_SIZE ? static_cast<size_t>(MTP_BUFFER_SIZE) : remaining;
723 if (mData.readDataAsync(req) != 0) {
724 ALOGE("readDataAsync failed");
725 return false;
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500726 }
727 }
728
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900729 // Write previous buffer.
730 if (writeBuffer && !writingError) {
731 if (!callback(writeBuffer, offset, writeLength, clientData)) {
732 ALOGE("write failed");
733 writingError = true;
734 }
735 }
736 offset = nextOffset;
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400737 }
Mike Lockwoodb9ff4442010-11-19 11:20:19 -0500738
Daichi Hirono4fd9a8b2015-08-20 15:13:40 +0900739 return readResponse() == MTP_RESPONSE_OK && !writingError;
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400740}
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400741
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400742bool MtpDevice::sendRequest(MtpOperationCode operation) {
Steve Block3856b092011-10-20 11:56:00 +0100743 ALOGV("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
Mike Lockwoodf7454622010-12-09 18:34:18 -0800744 mReceivedResponse = false;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400745 mRequest.setOperationCode(operation);
746 if (mTransactionID > 0)
747 mRequest.setTransactionID(mTransactionID++);
Mike Lockwood42d0b792011-01-04 14:48:57 -0500748 int ret = mRequest.write(mRequestOut);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400749 mRequest.dump();
750 return (ret > 0);
751}
752
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400753bool MtpDevice::sendData() {
Steve Block3856b092011-10-20 11:56:00 +0100754 ALOGV("sendData\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400755 mData.setOperationCode(mRequest.getOperationCode());
756 mData.setTransactionID(mRequest.getTransactionID());
Mike Lockwood42d0b792011-01-04 14:48:57 -0500757 int ret = mData.write(mRequestOut);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400758 mData.dump();
Tomasz Mikolajewski64c948b2015-08-13 15:31:02 +0900759 return (ret >= 0);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400760}
761
762bool MtpDevice::readData() {
763 mData.reset();
Mike Lockwood42d0b792011-01-04 14:48:57 -0500764 int ret = mData.read(mRequestIn1);
Steve Block3856b092011-10-20 11:56:00 +0100765 ALOGV("readData returned %d\n", ret);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400766 if (ret >= MTP_CONTAINER_HEADER_SIZE) {
Mike Lockwoodf7454622010-12-09 18:34:18 -0800767 if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
Steve Blockb8a80522011-12-20 16:23:08 +0000768 ALOGD("got response packet instead of data packet");
Mike Lockwoodf7454622010-12-09 18:34:18 -0800769 // we got a response packet rather than data
770 // copy it to mResponse
771 mResponse.copyFrom(mData);
772 mReceivedResponse = true;
773 return false;
774 }
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400775 mData.dump();
776 return true;
777 }
778 else {
Steve Block3856b092011-10-20 11:56:00 +0100779 ALOGV("readResponse failed\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400780 return false;
781 }
782}
783
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400784bool MtpDevice::writeDataHeader(MtpOperationCode operation, int dataLength) {
785 mData.setOperationCode(operation);
786 mData.setTransactionID(mRequest.getTransactionID());
Mike Lockwood42d0b792011-01-04 14:48:57 -0500787 return (!mData.writeDataHeader(mRequestOut, dataLength));
Mike Lockwood0cf89f22010-07-26 20:40:45 -0400788}
789
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400790MtpResponseCode MtpDevice::readResponse() {
Steve Block3856b092011-10-20 11:56:00 +0100791 ALOGV("readResponse\n");
Mike Lockwoodf7454622010-12-09 18:34:18 -0800792 if (mReceivedResponse) {
793 mReceivedResponse = false;
794 return mResponse.getResponseCode();
795 }
Mike Lockwood42d0b792011-01-04 14:48:57 -0500796 int ret = mResponse.read(mRequestIn1);
Mike Lockwood3d744572011-03-14 10:33:22 -0400797 // handle zero length packets, which might occur if the data transfer
798 // ends on a packet boundary
799 if (ret == 0)
800 ret = mResponse.read(mRequestIn1);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400801 if (ret >= MTP_CONTAINER_HEADER_SIZE) {
802 mResponse.dump();
803 return mResponse.getResponseCode();
Mike Lockwoodf7454622010-12-09 18:34:18 -0800804 } else {
Steve Blockb8a80522011-12-20 16:23:08 +0000805 ALOGD("readResponse failed\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400806 return -1;
807 }
808}
809
Daichi Hirono8a7ffae2015-08-20 15:13:40 +0900810int MtpDevice::submitEventRequest() {
811 if (mEventMutex.tryLock()) {
812 // An event is being reaped on another thread.
813 return -1;
814 }
815 if (mProcessingEvent) {
816 // An event request was submitted, but no reapEventRequest called so far.
817 return -1;
818 }
819 Mutex::Autolock autoLock(mEventMutexForInterrupt);
820 mEventPacket.sendRequest(mRequestIntr);
821 const int currentHandle = ++mCurrentEventHandle;
822 mProcessingEvent = true;
823 mEventMutex.unlock();
824 return currentHandle;
825}
826
827int MtpDevice::reapEventRequest(int handle) {
828 Mutex::Autolock autoLock(mEventMutex);
829 if (!mProcessingEvent || mCurrentEventHandle != handle) {
830 return -1;
831 }
832 mProcessingEvent = false;
833 const int readSize = mEventPacket.readResponse(mRequestIntr->dev);
834 const int result = mEventPacket.getEventCode();
835 return readSize == 0 ? 0 : result;
836}
837
838void MtpDevice::discardEventRequest(int handle) {
839 Mutex::Autolock autoLock(mEventMutexForInterrupt);
840 if (mCurrentEventHandle != handle) {
841 return;
842 }
843 usb_request_cancel(mRequestIntr);
844}
845
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400846} // namespace android