MtpDevice.cpp revision 3e072b354d1e1e3ee62d58492f0739139df8aff1
1/*
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
17#define LOG_TAG "MtpDevice"
18#include "utils/Log.h"
19
20#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"
34#include "MtpProperty.h"
35#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();
57    for (int i = 0; i < mDeviceProperties.size(); i++)
58        delete mDeviceProperties[i];
59}
60
61void MtpDevice::initialize() {
62    openSession();
63    mDeviceInfo = getDeviceInfo();
64    if (mDeviceInfo) {
65        mDeviceInfo->print();
66
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        }
78    }
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() {
97    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();
127    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();
156    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();
175    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();
189    if (ret == MTP_RESPONSE_OK) {
190        MtpObjectInfo* info = new MtpObjectInfo(handle);
191        info->read(mData);
192        return info;
193    }
194    return NULL;
195}
196
197void* 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
211MtpProperty* 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
228bool MtpDevice::sendRequest(MtpOperationCode operation) {
229    LOGD("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
230    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) {
239    LOGD("sendData\n");
240    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);
250    LOGD("readData returned %d\n", ret);
251    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
252        mData.dump();
253        return true;
254    }
255    else {
256        LOGD("readResponse failed\n");
257        return false;
258    }
259}
260
261MtpResponseCode MtpDevice::readResponse() {
262    LOGD("readResponse\n");
263    int ret = mResponse.read(mEndpointIn);
264    if (ret >= MTP_CONTAINER_HEADER_SIZE) {
265        mResponse.dump();
266        return mResponse.getResponseCode();
267    }
268    else {
269        LOGD("readResponse failed\n");
270        return -1;
271    }
272}
273
274}  // namespace android
275