blob: 56123870f7320ddce11be8b14afa704372cad84a [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"
22#include "MtpObjectInfo.h"
23#include "MtpProperty.h"
24#include "MtpStorageInfo.h"
25#include "MtpStringBuffer.h"
Mike Lockwooda6c490b2010-06-05 22:45:01 -040026
Mike Lockwood5ed68d22010-05-25 19:08:48 -040027#include <stdio.h>
28#include <stdlib.h>
29#include <sys/types.h>
30#include <sys/ioctl.h>
31#include <sys/stat.h>
32#include <fcntl.h>
33#include <errno.h>
34
35#include <usbhost/usbhost.h>
36
Mike Lockwood5ed68d22010-05-25 19:08:48 -040037namespace android {
38
39MtpDevice::MtpDevice(struct usb_device* device, int interface,
40 struct usb_endpoint *ep_in, struct usb_endpoint *ep_out,
41 struct usb_endpoint *ep_intr)
42 : mDevice(device),
43 mInterface(interface),
44 mEndpointIn(ep_in),
45 mEndpointOut(ep_out),
46 mEndpointIntr(ep_intr),
47 mDeviceInfo(NULL),
48 mID(usb_device_get_unique_id(device)),
49 mSessionID(0),
50 mTransactionID(0)
51{
52}
53
54MtpDevice::~MtpDevice() {
55 close();
Mike Lockwooda6c490b2010-06-05 22:45:01 -040056 for (int i = 0; i < mDeviceProperties.size(); i++)
57 delete mDeviceProperties[i];
Mike Lockwood5ed68d22010-05-25 19:08:48 -040058}
59
60void MtpDevice::initialize() {
61 openSession();
62 mDeviceInfo = getDeviceInfo();
63 if (mDeviceInfo) {
64 mDeviceInfo->print();
Mike Lockwooda6c490b2010-06-05 22:45:01 -040065
66 if (mDeviceInfo->mDeviceProperties) {
67 int count = mDeviceInfo->mDeviceProperties->size();
68 for (int i = 0; i < count; i++) {
69 MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
70 MtpProperty* property = getDevicePropDesc(propCode);
71 if (property) {
72 property->print();
73 mDeviceProperties.push(property);
74 }
75 }
76 }
Mike Lockwood5ed68d22010-05-25 19:08:48 -040077 }
78}
79
80void MtpDevice::close() {
81 if (mDevice) {
82 usb_device_release_interface(mDevice, mInterface);
83 usb_device_close(mDevice);
84 mDevice = NULL;
85 }
86}
87
88const char* MtpDevice::getDeviceName() {
89 if (mDevice)
90 return usb_device_get_name(mDevice);
91 else
92 return "???";
93}
94
95bool MtpDevice::openSession() {
Mike Lockwood5ed68d22010-05-25 19:08:48 -040096 mSessionID = 0;
97 mTransactionID = 0;
98 MtpSessionID newSession = 1;
99 mRequest.reset();
100 mRequest.setParameter(1, newSession);
101 if (!sendRequest(MTP_OPERATION_OPEN_SESSION))
102 return false;
103 MtpResponseCode ret = readResponse();
104 if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN)
105 newSession = mResponse.getParameter(1);
106 else if (ret != MTP_RESPONSE_OK)
107 return false;
108
109 mSessionID = newSession;
110 mTransactionID = 1;
111 return true;
112}
113
114bool MtpDevice::closeSession() {
115 // FIXME
116 return true;
117}
118
119MtpDeviceInfo* MtpDevice::getDeviceInfo() {
120 mRequest.reset();
121 if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
122 return NULL;
123 if (!readData())
124 return NULL;
125 MtpResponseCode ret = readResponse();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400126 if (ret == MTP_RESPONSE_OK) {
127 MtpDeviceInfo* info = new MtpDeviceInfo;
128 info->read(mData);
129 return info;
130 }
131 return NULL;
132}
133
134MtpStorageIDList* MtpDevice::getStorageIDs() {
135 mRequest.reset();
136 if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS))
137 return NULL;
138 if (!readData())
139 return NULL;
140 MtpResponseCode ret = readResponse();
141 if (ret == MTP_RESPONSE_OK) {
142 return mData.getAUInt32();
143 }
144 return NULL;
145}
146
147MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) {
148 mRequest.reset();
149 mRequest.setParameter(1, storageID);
150 if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO))
151 return NULL;
152 if (!readData())
153 return NULL;
154 MtpResponseCode ret = readResponse();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400155 if (ret == MTP_RESPONSE_OK) {
156 MtpStorageInfo* info = new MtpStorageInfo(storageID);
157 info->read(mData);
158 return info;
159 }
160 return NULL;
161}
162
163MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID,
164 MtpObjectFormat format, MtpObjectHandle parent) {
165 mRequest.reset();
166 mRequest.setParameter(1, storageID);
167 mRequest.setParameter(2, format);
168 mRequest.setParameter(3, parent);
169 if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
170 return NULL;
171 if (!readData())
172 return NULL;
173 MtpResponseCode ret = readResponse();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400174 if (ret == MTP_RESPONSE_OK) {
175 return mData.getAUInt32();
176 }
177 return NULL;
178}
179
180MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400181 // FIXME - we might want to add some caching here
182
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400183 mRequest.reset();
184 mRequest.setParameter(1, handle);
185 if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
186 return NULL;
187 if (!readData())
188 return NULL;
189 MtpResponseCode ret = readResponse();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400190 if (ret == MTP_RESPONSE_OK) {
191 MtpObjectInfo* info = new MtpObjectInfo(handle);
192 info->read(mData);
193 return info;
194 }
195 return NULL;
196}
197
Mike Lockwood3e072b32010-06-10 16:34:20 -0400198void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
199 mRequest.reset();
200 mRequest.setParameter(1, handle);
201 if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
202 MtpResponseCode ret = readResponse();
203 if (ret == MTP_RESPONSE_OK) {
204 return mData.getData(outLength);
205 }
206 }
207 outLength = 0;
208 return NULL;
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400209}
Mike Lockwood3e072b32010-06-10 16:34:20 -0400210
Mike Lockwood6afc41d2010-06-11 16:34:52 -0400211bool MtpDevice::deleteObject(MtpObjectHandle handle) {
212 mRequest.reset();
213 mRequest.setParameter(1, handle);
214 if (sendRequest(MTP_OPERATION_DELETE_OBJECT)) {
215 MtpResponseCode ret = readResponse();
216 if (ret == MTP_RESPONSE_OK)
217 return true;
218 }
219 return false;
220}
221
222MtpObjectHandle MtpDevice::getParent(MtpObjectHandle handle) {
223 MtpObjectInfo* info = getObjectInfo(handle);
224 if (info)
225 return info->mParent;
226 else
227 return -1;
228}
229
230MtpObjectHandle MtpDevice::getStorageID(MtpObjectHandle handle) {
231 MtpObjectInfo* info = getObjectInfo(handle);
232 if (info)
233 return info->mStorageID;
234 else
235 return -1;
Mike Lockwood3e072b32010-06-10 16:34:20 -0400236}
237
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400238MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
239 mRequest.reset();
240 mRequest.setParameter(1, code);
241 if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
242 return NULL;
243 if (!readData())
244 return NULL;
245 MtpResponseCode ret = readResponse();
246 if (ret == MTP_RESPONSE_OK) {
247 MtpProperty* property = new MtpProperty;
248 property->read(mData);
249 return property;
250 }
251 return NULL;
252}
253
254
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400255bool MtpDevice::sendRequest(MtpOperationCode operation) {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400256 LOGD("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400257 mRequest.setOperationCode(operation);
258 if (mTransactionID > 0)
259 mRequest.setTransactionID(mTransactionID++);
260 int ret = mRequest.write(mEndpointOut);
261 mRequest.dump();
262 return (ret > 0);
263}
264
265bool MtpDevice::sendData(MtpOperationCode operation) {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400266 LOGD("sendData\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400267 mData.setOperationCode(mRequest.getOperationCode());
268 mData.setTransactionID(mRequest.getTransactionID());
269 int ret = mData.write(mEndpointOut);
270 mData.dump();
271 return (ret > 0);
272}
273
274bool MtpDevice::readData() {
275 mData.reset();
276 int ret = mData.read(mEndpointIn);
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400277 LOGD("readData returned %d\n", ret);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400278 if (ret >= MTP_CONTAINER_HEADER_SIZE) {
279 mData.dump();
280 return true;
281 }
282 else {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400283 LOGD("readResponse failed\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400284 return false;
285 }
286}
287
288MtpResponseCode MtpDevice::readResponse() {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400289 LOGD("readResponse\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400290 int ret = mResponse.read(mEndpointIn);
291 if (ret >= MTP_CONTAINER_HEADER_SIZE) {
292 mResponse.dump();
293 return mResponse.getResponseCode();
294 }
295 else {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400296 LOGD("readResponse failed\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400297 return -1;
298 }
299}
300
301} // namespace android