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