blob: ee352174e414267a9fe59f977e57a53977e1287e [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) {
182 mRequest.reset();
183 mRequest.setParameter(1, handle);
184 if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
185 return NULL;
186 if (!readData())
187 return NULL;
188 MtpResponseCode ret = readResponse();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400189 if (ret == MTP_RESPONSE_OK) {
190 MtpObjectInfo* info = new MtpObjectInfo(handle);
191 info->read(mData);
192 return info;
193 }
194 return NULL;
195}
196
Mike Lockwood3e072b32010-06-10 16:34:20 -0400197void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
198 mRequest.reset();
199 mRequest.setParameter(1, handle);
200 if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
201 MtpResponseCode ret = readResponse();
202 if (ret == MTP_RESPONSE_OK) {
203 return mData.getData(outLength);
204 }
205 }
206 outLength = 0;
207 return NULL;
208
209}
210
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400211MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
212 mRequest.reset();
213 mRequest.setParameter(1, code);
214 if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
215 return NULL;
216 if (!readData())
217 return NULL;
218 MtpResponseCode ret = readResponse();
219 if (ret == MTP_RESPONSE_OK) {
220 MtpProperty* property = new MtpProperty;
221 property->read(mData);
222 return property;
223 }
224 return NULL;
225}
226
227
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400228bool MtpDevice::sendRequest(MtpOperationCode operation) {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400229 LOGD("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400230 mRequest.setOperationCode(operation);
231 if (mTransactionID > 0)
232 mRequest.setTransactionID(mTransactionID++);
233 int ret = mRequest.write(mEndpointOut);
234 mRequest.dump();
235 return (ret > 0);
236}
237
238bool MtpDevice::sendData(MtpOperationCode operation) {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400239 LOGD("sendData\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400240 mData.setOperationCode(mRequest.getOperationCode());
241 mData.setTransactionID(mRequest.getTransactionID());
242 int ret = mData.write(mEndpointOut);
243 mData.dump();
244 return (ret > 0);
245}
246
247bool MtpDevice::readData() {
248 mData.reset();
249 int ret = mData.read(mEndpointIn);
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400250 LOGD("readData returned %d\n", ret);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400251 if (ret >= MTP_CONTAINER_HEADER_SIZE) {
252 mData.dump();
253 return true;
254 }
255 else {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400256 LOGD("readResponse failed\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400257 return false;
258 }
259}
260
261MtpResponseCode MtpDevice::readResponse() {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400262 LOGD("readResponse\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400263 int ret = mResponse.read(mEndpointIn);
264 if (ret >= MTP_CONTAINER_HEADER_SIZE) {
265 mResponse.dump();
266 return mResponse.getResponseCode();
267 }
268 else {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400269 LOGD("readResponse failed\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400270 return -1;
271 }
272}
273
274} // namespace android