blob: 5c39628eedff58a242f925254634b74f10661d57 [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 Lockwooda6c490b2010-06-05 22:45:01 -0400197MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
198 mRequest.reset();
199 mRequest.setParameter(1, code);
200 if (!sendRequest(MTP_OPERATION_GET_DEVICE_PROP_DESC))
201 return NULL;
202 if (!readData())
203 return NULL;
204 MtpResponseCode ret = readResponse();
205 if (ret == MTP_RESPONSE_OK) {
206 MtpProperty* property = new MtpProperty;
207 property->read(mData);
208 return property;
209 }
210 return NULL;
211}
212
213
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400214bool MtpDevice::sendRequest(MtpOperationCode operation) {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400215 LOGD("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400216 mRequest.setOperationCode(operation);
217 if (mTransactionID > 0)
218 mRequest.setTransactionID(mTransactionID++);
219 int ret = mRequest.write(mEndpointOut);
220 mRequest.dump();
221 return (ret > 0);
222}
223
224bool MtpDevice::sendData(MtpOperationCode operation) {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400225 LOGD("sendData\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400226 mData.setOperationCode(mRequest.getOperationCode());
227 mData.setTransactionID(mRequest.getTransactionID());
228 int ret = mData.write(mEndpointOut);
229 mData.dump();
230 return (ret > 0);
231}
232
233bool MtpDevice::readData() {
234 mData.reset();
235 int ret = mData.read(mEndpointIn);
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400236 LOGD("readData returned %d\n", ret);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400237 if (ret >= MTP_CONTAINER_HEADER_SIZE) {
238 mData.dump();
239 return true;
240 }
241 else {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400242 LOGD("readResponse failed\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400243 return false;
244 }
245}
246
247MtpResponseCode MtpDevice::readResponse() {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400248 LOGD("readResponse\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400249 int ret = mResponse.read(mEndpointIn);
250 if (ret >= MTP_CONTAINER_HEADER_SIZE) {
251 mResponse.dump();
252 return mResponse.getResponseCode();
253 }
254 else {
Mike Lockwooda6c490b2010-06-05 22:45:01 -0400255 LOGD("readResponse failed\n");
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400256 return -1;
257 }
258}
259
260} // namespace android