diff options
author | Mike Lockwood <lockwood@android.com> | 2010-05-25 19:08:48 -0400 |
---|---|---|
committer | Mike Lockwood <lockwood@android.com> | 2010-06-01 22:12:44 -0400 |
commit | 5ed68d29a140e14c8d46980fa844548eb33b1e87 (patch) | |
tree | 76b370bbfac9fe8e2105c57bf21154f6dd245d38 /media/mtp | |
parent | 77995c32095cc192823de3eedf0d5a404fbca72e (diff) | |
download | frameworks_av-5ed68d29a140e14c8d46980fa844548eb33b1e87.zip frameworks_av-5ed68d29a140e14c8d46980fa844548eb33b1e87.tar.gz frameworks_av-5ed68d29a140e14c8d46980fa844548eb33b1e87.tar.bz2 |
Prototype Content Provider support for MTP/PTP devices.
At this point much of the plumbing is in place, but only a few simple queries
are supported.
This is enough to support a proof of concept sample program that navigates
the file hierarchy of a digital camera connected via USB.
Also removed obsolete ptptest host test program.
Change-Id: I17644344b9f0ce1ecc302bc0478c1f3d44a1647f
Signed-off-by: Mike Lockwood <lockwood@android.com>
Diffstat (limited to 'media/mtp')
-rw-r--r-- | media/mtp/Android.mk | 17 | ||||
-rw-r--r-- | media/mtp/MtpClient.cpp | 250 | ||||
-rw-r--r-- | media/mtp/MtpClient.h | 47 | ||||
-rw-r--r-- | media/mtp/MtpCursor.cpp | 332 | ||||
-rw-r--r-- | media/mtp/MtpCursor.h | 75 | ||||
-rw-r--r-- | media/mtp/MtpDevice.cpp | 230 | ||||
-rw-r--r-- | media/mtp/MtpDevice.h | 83 | ||||
-rw-r--r-- | media/mtp/MtpTypes.h | 22 | ||||
-rw-r--r-- | media/mtp/ptptest.cpp | 166 |
9 files changed, 859 insertions, 363 deletions
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk index d9c69a4..9e9ae2f 100644 --- a/media/mtp/Android.mk +++ b/media/mtp/Android.mk @@ -47,16 +47,16 @@ include $(BUILD_EXECUTABLE) endif -ifeq ($(HOST_OS),linux) - include $(CLEAR_VARS) -LOCAL_MODULE := ptptest +LOCAL_MODULE := libmtphost + LOCAL_SRC_FILES:= \ - ptptest.cpp \ MtpClient.cpp \ + MtpCursor.cpp \ MtpDataPacket.cpp \ MtpDebug.cpp \ + MtpDevice.cpp \ MtpDeviceInfo.cpp \ MtpObjectInfo.cpp \ MtpPacket.cpp \ @@ -65,17 +65,12 @@ LOCAL_SRC_FILES:= \ MtpStorageInfo.cpp \ MtpStringBuffer.cpp \ MtpUtils.cpp \ - ../../libs/utils/VectorImpl.cpp \ - ../../libs/utils/SharedBuffer.cpp \ -LOCAL_STATIC_LIBRARIES := libusbhost libcutils -LOCAL_LDLIBS := -lpthread - LOCAL_CFLAGS := -g -DMTP_HOST LOCAL_LDFLAGS := -g -include $(BUILD_HOST_EXECUTABLE) +include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) @@ -103,5 +98,3 @@ LOCAL_CFLAGS := -g LOCAL_LDFLAGS := -g include $(BUILD_EXECUTABLE) - -endif
\ No newline at end of file diff --git a/media/mtp/MtpClient.cpp b/media/mtp/MtpClient.cpp index de3c199..31874e9 100644 --- a/media/mtp/MtpClient.cpp +++ b/media/mtp/MtpClient.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +#define LOG_TAG "MtpClient" +#include "utils/Log.h" + #include <stdio.h> #include <stdlib.h> #include <sys/types.h> @@ -23,180 +26,143 @@ #include <errno.h> #include <usbhost/usbhost.h> +#include <linux/version.h> +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20) +#include <linux/usb/ch9.h> +#else +#include <linux/usb_ch9.h> +#endif #include "MtpClient.h" +#include "MtpDevice.h" #include "MtpDebug.h" -#include "MtpDeviceInfo.h" -#include "MtpObjectInfo.h" -#include "MtpStorageInfo.h" -#include "MtpStringBuffer.h" namespace android { -MtpClient::MtpClient(struct usb_endpoint *ep_in, struct usb_endpoint *ep_out, - struct usb_endpoint *ep_intr) - : mEndpointIn(ep_in), - mEndpointOut(ep_out), - mEndpointIntr(ep_intr), - mSessionID(0), - mTransactionID(0) +MtpClient::MtpClient() + : mStarted(false) { - } MtpClient::~MtpClient() { } -bool MtpClient::openSession() { -printf("openSession\n"); - mSessionID = 0; - mTransactionID = 0; - MtpSessionID newSession = 1; - mRequest.reset(); - mRequest.setParameter(1, newSession); - if (!sendRequest(MTP_OPERATION_OPEN_SESSION)) - return false; - MtpResponseCode ret = readResponse(); - if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN) - newSession = mResponse.getParameter(1); - else if (ret != MTP_RESPONSE_OK) - return false; +bool MtpClient::start() { + if (mStarted) + return true; - mSessionID = newSession; - mTransactionID = 1; + if (usb_host_init(usb_device_added, usb_device_removed, this)) { + LOGE("MtpClient::start failed\n"); + return false; + } + mStarted = true; return true; } -bool MtpClient::closeSession() { - // FIXME - return true; -} +void MtpClient::usbDeviceAdded(const char *devname) { + struct usb_descriptor_header* desc; + struct usb_descriptor_iter iter; -MtpDeviceInfo* MtpClient::getDeviceInfo() { - mRequest.reset(); - if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO)) - return NULL; - if (!readData()) - return NULL; - MtpResponseCode ret = readResponse(); -printf("getDeviceInfo returned %04X\n", ret); - if (ret == MTP_RESPONSE_OK) { - MtpDeviceInfo* info = new MtpDeviceInfo; - info->read(mData); - return info; + struct usb_device *device = usb_device_open(devname); + if (!device) { + LOGE("usb_device_open failed\n"); + return; } - return NULL; -} -MtpStorageIDList* MtpClient::getStorageIDs() { - mRequest.reset(); - if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS)) - return NULL; - if (!readData()) - return NULL; - MtpResponseCode ret = readResponse(); - if (ret == MTP_RESPONSE_OK) { - return mData.getAUInt32(); + usb_descriptor_iter_init(device, &iter); + + while ((desc = usb_descriptor_iter_next(&iter)) != NULL) { + if (desc->bDescriptorType == USB_DT_INTERFACE) { + struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc; + + if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE && + interface->bInterfaceSubClass == 1 && // Still Image Capture + interface->bInterfaceProtocol == 1) // Picture Transfer Protocol (PIMA 15470) + { + LOGD("Found camera: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device), + usb_device_get_product_name(device)); + + // interface should be followed by three endpoints + struct usb_endpoint_descriptor *ep; + struct usb_endpoint_descriptor *ep_in_desc = NULL; + struct usb_endpoint_descriptor *ep_out_desc = NULL; + struct usb_endpoint_descriptor *ep_intr_desc = NULL; + for (int i = 0; i < 3; i++) { + ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter); + if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) { + LOGE("endpoints not found\n"); + return; + } + if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { + if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) + ep_in_desc = ep; + else + ep_out_desc = ep; + } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT && + ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { + ep_intr_desc = ep; + } + } + if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) { + LOGE("endpoints not found\n"); + return; + } + + struct usb_endpoint *ep_in = usb_endpoint_open(device, ep_in_desc); + struct usb_endpoint *ep_out = usb_endpoint_open(device, ep_out_desc); + struct usb_endpoint *ep_intr = usb_endpoint_open(device, ep_intr_desc); + + if (usb_device_claim_interface(device, interface->bInterfaceNumber)) { + LOGE("usb_device_claim_interface failed\n"); + usb_endpoint_close(ep_in); + usb_endpoint_close(ep_out); + usb_endpoint_close(ep_intr); + return; + } + + MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber, + ep_in, ep_out, ep_intr); + mDeviceList.add(mtpDevice); + mtpDevice->initialize(); + deviceAdded(mtpDevice); + return; + } + } } - return NULL; -} -MtpStorageInfo* MtpClient::getStorageInfo(MtpStorageID storageID) { - mRequest.reset(); - mRequest.setParameter(1, storageID); - if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO)) - return NULL; - if (!readData()) - return NULL; - MtpResponseCode ret = readResponse(); -printf("getStorageInfo returned %04X\n", ret); - if (ret == MTP_RESPONSE_OK) { - MtpStorageInfo* info = new MtpStorageInfo(storageID); - info->read(mData); - return info; - } - return NULL; + usb_device_close(device); } -MtpObjectHandleList* MtpClient::getObjectHandles(MtpStorageID storageID, - MtpObjectFormat format, MtpObjectHandle parent) { - mRequest.reset(); - mRequest.setParameter(1, storageID); - mRequest.setParameter(2, format); - mRequest.setParameter(3, parent); - if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES)) - return NULL; - if (!readData()) - return NULL; - MtpResponseCode ret = readResponse(); -printf("getObjectHandles returned %04X\n", ret); - if (ret == MTP_RESPONSE_OK) { - return mData.getAUInt32(); +MtpDevice* MtpClient::getDevice(int id) { + for (int i = 0; i < mDeviceList.size(); i++) { + MtpDevice* device = mDeviceList[i]; + if (device->getID() == id) + return device; } return NULL; } -MtpObjectInfo* MtpClient::getObjectInfo(MtpObjectHandle handle) { - mRequest.reset(); - mRequest.setParameter(1, handle); - if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO)) - return NULL; - if (!readData()) - return NULL; - MtpResponseCode ret = readResponse(); -printf("getObjectInfo returned %04X\n", ret); - if (ret == MTP_RESPONSE_OK) { - MtpObjectInfo* info = new MtpObjectInfo(handle); - info->read(mData); - return info; +void MtpClient::usbDeviceRemoved(const char *devname) { + for (int i = 0; i < mDeviceList.size(); i++) { + MtpDevice* device = mDeviceList[i]; + if (!strcmp(devname, device->getDeviceName())) { + deviceRemoved(device); + mDeviceList.removeAt(i); + delete device; + LOGD("Camera removed!\n"); + break; + } } - return NULL; } -bool MtpClient::sendRequest(MtpOperationCode operation) { - printf("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation)); - mRequest.setOperationCode(operation); - if (mTransactionID > 0) - mRequest.setTransactionID(mTransactionID++); - int ret = mRequest.write(mEndpointOut); - mRequest.dump(); - return (ret > 0); +void MtpClient::usb_device_added(const char *devname, void* client_data) { + LOGD("usb_device_added %s\n", devname); + ((MtpClient *)client_data)->usbDeviceAdded(devname); } -bool MtpClient::sendData(MtpOperationCode operation) { - printf("sendData\n"); - mData.setOperationCode(mRequest.getOperationCode()); - mData.setTransactionID(mRequest.getTransactionID()); - int ret = mData.write(mEndpointOut); - mData.dump(); - return (ret > 0); -} - -bool MtpClient::readData() { - mData.reset(); - int ret = mData.read(mEndpointIn); - printf("readData returned %d\n", ret); - if (ret >= MTP_CONTAINER_HEADER_SIZE) { - mData.dump(); - return true; - } - else { - printf("readResponse failed\n"); - return false; - } -} - -MtpResponseCode MtpClient::readResponse() { - printf("readResponse\n"); - int ret = mResponse.read(mEndpointIn); - if (ret >= MTP_CONTAINER_HEADER_SIZE) { - mResponse.dump(); - return mResponse.getResponseCode(); - } - else { - printf("readResponse failed\n"); - return -1; - } +void MtpClient::usb_device_removed(const char *devname, void* client_data) { + LOGD("usb_device_removed %s\n", devname); + ((MtpClient *)client_data)->usbDeviceRemoved(devname); } } // namespace android diff --git a/media/mtp/MtpClient.h b/media/mtp/MtpClient.h index 76d9648..d87c226 100644 --- a/media/mtp/MtpClient.h +++ b/media/mtp/MtpClient.h @@ -17,52 +17,33 @@ #ifndef _MTP_CLIENT_H #define _MTP_CLIENT_H -#include "MtpRequestPacket.h" -#include "MtpDataPacket.h" -#include "MtpResponsePacket.h" #include "MtpTypes.h" namespace android { -class MtpDeviceInfo; -class MtpObjectInfo; -class MtpStorageInfo; - class MtpClient { private: - struct usb_endpoint* mEndpointIn; - struct usb_endpoint* mEndpointOut; - struct usb_endpoint* mEndpointIntr; - - // current session ID - MtpSessionID mSessionID; - // current transaction ID - MtpTransactionID mTransactionID; - - MtpRequestPacket mRequest; - MtpDataPacket mData; - MtpResponsePacket mResponse; + MtpDeviceList mDeviceList; + bool mStarted; public: - MtpClient(struct usb_endpoint *ep_in, struct usb_endpoint *ep_out, - struct usb_endpoint *ep_intr); + MtpClient(); virtual ~MtpClient(); - bool openSession(); - bool closeSession(); + bool start(); - MtpDeviceInfo* getDeviceInfo(); - MtpStorageIDList* getStorageIDs(); - MtpStorageInfo* getStorageInfo(MtpStorageID storageID); - MtpObjectHandleList* getObjectHandles(MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent); - MtpObjectInfo* getObjectInfo(MtpObjectHandle handle); + inline MtpDeviceList& getDeviceList() { return mDeviceList; } + MtpDevice* getDevice(int id); -private: - bool sendRequest(MtpOperationCode operation); - bool sendData(MtpOperationCode operation); - bool readData(); - MtpResponseCode readResponse(); + virtual void deviceAdded(MtpDevice *device) = 0; + virtual void deviceRemoved(MtpDevice *device) = 0; + +private: + void usbDeviceAdded(const char *devname); + void usbDeviceRemoved(const char *devname); + static void usb_device_added(const char *devname, void* client_data); + static void usb_device_removed(const char *devname, void* client_data); }; }; // namespace android diff --git a/media/mtp/MtpCursor.cpp b/media/mtp/MtpCursor.cpp new file mode 100644 index 0000000..9c9ce64 --- /dev/null +++ b/media/mtp/MtpCursor.cpp @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "MtpCursor" +#include "utils/Log.h" + +#include "MtpClient.h" +#include "MtpCursor.h" +#include "MtpDevice.h" +#include "MtpDeviceInfo.h" +#include "MtpObjectInfo.h" +#include "MtpStorageInfo.h" + +#include "binder/CursorWindow.h" + +namespace android { + +/* Device Column IDs */ +#define DEVICE_ROW_ID 1 +#define DEVICE_MANUFACTURER 2 +#define DEVICE_MODEL 3 + +/* Storage Column IDs */ +#define STORAGE_ROW_ID 101 +#define STORAGE_IDENTIFIER 102 +#define STORAGE_DESCRIPTION 103 + +/* Object Column IDs */ +#define OBJECT_ROW_ID 201 +#define OBJECT_NAME 202 + +MtpCursor::MtpCursor(MtpClient* client, int queryType, int deviceID, + int storageID, int objectID, int columnCount, int* columns) + : mClient(client), + mQueryType(queryType), + mDeviceID(deviceID), + mStorageID(storageID), + mQbjectID(objectID), + mColumnCount(columnCount), + mColumns(NULL) +{ + if (columns) { + mColumns = new int[columnCount]; + memcpy(mColumns, columns, columnCount * sizeof(int)); + } +} + +MtpCursor::~MtpCursor() { + delete[] mColumns; +} + +int MtpCursor::fillWindow(CursorWindow* window, int startPos) { + LOGD("MtpCursor::fillWindow mQueryType: %d\n", mQueryType); + + switch (mQueryType) { + case DEVICE: + return fillDevices(window, startPos); + case DEVICE_ID: + return fillDevice(window, startPos); + case STORAGE: + return fillStorages(window, startPos); + case STORAGE_ID: + return fillStorage(window, startPos); + case OBJECT: + return fillObjects(window, 0, startPos); + case OBJECT_ID: + return fillObject(window, startPos); + case STORAGE_CHILDREN: + return fillObjects(window, -1, startPos); + case OBJECT_CHILDREN: + return fillObjects(window, mQbjectID, startPos); + default: + LOGE("MtpCursor::fillWindow: unknown query type %d\n", mQueryType); + return 0; + } +} + +int MtpCursor::fillDevices(CursorWindow* window, int startPos) { + int count = 0; + MtpDeviceList& deviceList = mClient->getDeviceList(); + for (int i = 0; i < deviceList.size(); i++) { + MtpDevice* device = deviceList[i]; + if (fillDevice(window, device, startPos)) { + count++; + startPos++; + } else { + break; + } + } + return count; +} + +int MtpCursor::fillDevice(CursorWindow* window, int startPos) { + MtpDevice* device = mClient->getDevice(mDeviceID); + if (device && fillDevice(window, device, startPos)) + return 1; + else + return 0; +} + +int MtpCursor::fillStorages(CursorWindow* window, int startPos) { + int count = 0; + MtpDevice* device = mClient->getDevice(mDeviceID); + if (!device) + return 0; + MtpStorageIDList* storageIDs = device->getStorageIDs(); + if (!storageIDs) + return 0; + + for (int i = 0; i < storageIDs->size(); i++) { + MtpStorageID storageID = (*storageIDs)[i]; + if (fillStorage(window, device, storageID, startPos)) { + count++; + startPos++; + } else { + break; + } + } + delete storageIDs; + return count; +} + +int MtpCursor::fillStorage(CursorWindow* window, int startPos) { + MtpDevice* device = mClient->getDevice(mDeviceID); + if (device && fillStorage(window, device, mStorageID, startPos)) + return 1; + else + return 0; +} + +int MtpCursor::fillObjects(CursorWindow* window, int parent, int startPos) { + int count = 0; + MtpDevice* device = mClient->getDevice(mDeviceID); + if (!device) + return 0; + MtpObjectHandleList* handles = device->getObjectHandles(mStorageID, 0, parent); + if (!handles) + return 0; + + for (int i = 0; i < handles->size(); i++) { + MtpObjectHandle handle = (*handles)[i]; + if (fillObject(window, device, handle, startPos)) { + count++; + startPos++; + } else { + break; + } + } + delete handles; + return count; +} + +int MtpCursor::fillObject(CursorWindow* window, int startPos) { + MtpDevice* device = mClient->getDevice(mDeviceID); + if (device && fillObject(window, device, mQbjectID, startPos)) + return 1; + else + return 0; +} + +bool MtpCursor::fillDevice(CursorWindow* window, MtpDevice* device, int row) { + MtpDeviceInfo* deviceInfo = device->getDeviceInfo(); + if (!deviceInfo) + return false; + if (!prepareRow(window)) + return false; + + for (int i = 0; i < mColumnCount; i++) { + switch (mColumns[i]) { + case DEVICE_ROW_ID: + if (!putLong(window, device->getID(), row, i)) + return false; + break; + case DEVICE_MANUFACTURER: + if (!putString(window, deviceInfo->mManufacturer, row, i)) + return false; + break; + case DEVICE_MODEL: + if (!putString(window, deviceInfo->mModel, row, i)) + return false; + break; + default: + LOGE("fillDevice: unknown column %d\n", mColumns[i]); + return false; + } + } + + return true; +} + +bool MtpCursor::fillStorage(CursorWindow* window, MtpDevice* device, + MtpStorageID storageID, int row) { + +LOGD("fillStorage %d\n", storageID); + + MtpStorageInfo* storageInfo = device->getStorageInfo(storageID); + if (!storageInfo) + return false; + if (!prepareRow(window)) { + delete storageInfo; + return false; + } + + const char* text; + for (int i = 0; i < mColumnCount; i++) { + switch (mColumns[i]) { + case STORAGE_ROW_ID: + if (!putLong(window, storageID, row, i)) + goto fail; + break; + case STORAGE_IDENTIFIER: + text = storageInfo->mVolumeIdentifier; + if (!text || !text[0]) + text = "Camera Storage"; + if (!putString(window, text, row, i)) + goto fail; + break; + case STORAGE_DESCRIPTION: + text = storageInfo->mStorageDescription; + if (!text || !text[0]) + text = "Storage Description"; + if (!putString(window, text, row, i)) + goto fail; + break; + default: + LOGE("fillStorage: unknown column %d\n", mColumns[i]); + goto fail; + } + } + + delete storageInfo; + return true; + +fail: + delete storageInfo; + return false; +} + +bool MtpCursor::fillObject(CursorWindow* window, MtpDevice* device, + MtpObjectHandle objectID, int row) { + +LOGD("fillObject %d\n", objectID); + + MtpObjectInfo* objectInfo = device->getObjectInfo(objectID); + if (!objectInfo) + return false; + if (!prepareRow(window)) { + delete objectInfo; + return false; + } + + for (int i = 0; i < mColumnCount; i++) { + switch (mColumns[i]) { + case OBJECT_ROW_ID: + if (!putLong(window, objectID, row, i)) + goto fail; + break; + case OBJECT_NAME: + if (!putString(window, objectInfo->mName, row, i)) + goto fail; + break; + default: + LOGE("fillStorage: unknown column %d\n", mColumns[i]); + goto fail; + } + } + + delete objectInfo; + return true; + +fail: + delete objectInfo; + return false; +} + +bool MtpCursor::prepareRow(CursorWindow* window) { + if (!window->setNumColumns(mColumnCount)) { + LOGE("Failed to change column count from %d to %d", window->getNumColumns(), mColumnCount); + return false; + } + field_slot_t * fieldDir = window->allocRow(); + if (!fieldDir) { + LOGE("Failed allocating fieldDir"); + return false; + } + return true; +} + + +bool MtpCursor::putLong(CursorWindow* window, int value, int row, int column) { + + if (!window->putLong(row, column, value)) { + window->freeLastRow(); + LOGE("Failed allocating space for a long in column %d", column); + return false; + } + return true; +} + +bool MtpCursor::putString(CursorWindow* window, const char* text, int row, int column) { + int size = strlen(text) + 1; + int offset = window->alloc(size); + if (!offset) { + window->freeLastRow(); + LOGE("Failed allocating %u bytes for text/blob %s", size, text); + return false; + } + window->copyIn(offset, (const uint8_t*)text, size); + + // This must be updated after the call to alloc(), since that + // may move the field around in the window + field_slot_t * fieldSlot = window->getFieldSlot(row, column); + fieldSlot->type = FIELD_TYPE_STRING; + fieldSlot->data.buffer.offset = offset; + fieldSlot->data.buffer.size = size; + return true; +} + +} // namespace android diff --git a/media/mtp/MtpCursor.h b/media/mtp/MtpCursor.h new file mode 100644 index 0000000..422f0c9 --- /dev/null +++ b/media/mtp/MtpCursor.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_CURSOR_H +#define _MTP_CURSOR_H + +#include "MtpTypes.h" + +namespace android { + +class CursorWindow; + +class MtpCursor { +private: + enum { + DEVICE = 1, + DEVICE_ID = 2, + STORAGE = 3, + STORAGE_ID = 4, + OBJECT = 5, + OBJECT_ID = 6, + STORAGE_CHILDREN = 7, + OBJECT_CHILDREN = 8, + }; + + MtpClient* mClient; + int mQueryType; + int mDeviceID; + int mStorageID; + int mQbjectID; + int mColumnCount; + int* mColumns; + +public: + MtpCursor(MtpClient* client, int queryType, int deviceID, + int storageID, int objectID, int columnCount, int* columns); + virtual ~MtpCursor(); + + int fillWindow(CursorWindow* window, int startPos); + +private: + int fillDevices(CursorWindow* window, int startPos); + int fillDevice(CursorWindow* window, int startPos); + int fillStorages(CursorWindow* window, int startPos); + int fillStorage(CursorWindow* window, int startPos); + int fillObjects(CursorWindow* window, int parent, int startPos); + int fillObject(CursorWindow* window, int startPos); + + bool fillDevice(CursorWindow* window, MtpDevice* device, int startPos); + bool fillStorage(CursorWindow* window, MtpDevice* device, + MtpStorageID storageID, int row); + bool fillObject(CursorWindow* window, MtpDevice* device, + MtpObjectHandle objectID, int row); + + bool prepareRow(CursorWindow* window); + bool putLong(CursorWindow* window, int value, int row, int column); + bool putString(CursorWindow* window, const char* text, int row, int column); +}; + +}; // namespace android + +#endif // _MTP_CURSOR_H diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp new file mode 100644 index 0000000..0282086 --- /dev/null +++ b/media/mtp/MtpDevice.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include <usbhost/usbhost.h> + +#include "MtpDevice.h" +#include "MtpDebug.h" +#include "MtpDeviceInfo.h" +#include "MtpObjectInfo.h" +#include "MtpStorageInfo.h" +#include "MtpStringBuffer.h" + +namespace android { + +MtpDevice::MtpDevice(struct usb_device* device, int interface, + struct usb_endpoint *ep_in, struct usb_endpoint *ep_out, + struct usb_endpoint *ep_intr) + : mDevice(device), + mInterface(interface), + mEndpointIn(ep_in), + mEndpointOut(ep_out), + mEndpointIntr(ep_intr), + mDeviceInfo(NULL), + mID(usb_device_get_unique_id(device)), + mSessionID(0), + mTransactionID(0) +{ +} + +MtpDevice::~MtpDevice() { + close(); +} + +void MtpDevice::initialize() { + openSession(); + mDeviceInfo = getDeviceInfo(); + if (mDeviceInfo) { + mDeviceInfo->print(); + } +} + +void MtpDevice::close() { + if (mDevice) { + usb_device_release_interface(mDevice, mInterface); + usb_device_close(mDevice); + mDevice = NULL; + } +} + +const char* MtpDevice::getDeviceName() { + if (mDevice) + return usb_device_get_name(mDevice); + else + return "???"; +} + +bool MtpDevice::openSession() { +printf("openSession\n"); + mSessionID = 0; + mTransactionID = 0; + MtpSessionID newSession = 1; + mRequest.reset(); + mRequest.setParameter(1, newSession); + if (!sendRequest(MTP_OPERATION_OPEN_SESSION)) + return false; + MtpResponseCode ret = readResponse(); + if (ret == MTP_RESPONSE_SESSION_ALREADY_OPEN) + newSession = mResponse.getParameter(1); + else if (ret != MTP_RESPONSE_OK) + return false; + + mSessionID = newSession; + mTransactionID = 1; + return true; +} + +bool MtpDevice::closeSession() { + // FIXME + return true; +} + +MtpDeviceInfo* MtpDevice::getDeviceInfo() { + mRequest.reset(); + if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO)) + return NULL; + if (!readData()) + return NULL; + MtpResponseCode ret = readResponse(); +printf("getDeviceInfo returned %04X\n", ret); + if (ret == MTP_RESPONSE_OK) { + MtpDeviceInfo* info = new MtpDeviceInfo; + info->read(mData); + return info; + } + return NULL; +} + +MtpStorageIDList* MtpDevice::getStorageIDs() { + mRequest.reset(); + if (!sendRequest(MTP_OPERATION_GET_STORAGE_IDS)) + return NULL; + if (!readData()) + return NULL; + MtpResponseCode ret = readResponse(); + if (ret == MTP_RESPONSE_OK) { + return mData.getAUInt32(); + } + return NULL; +} + +MtpStorageInfo* MtpDevice::getStorageInfo(MtpStorageID storageID) { + mRequest.reset(); + mRequest.setParameter(1, storageID); + if (!sendRequest(MTP_OPERATION_GET_STORAGE_INFO)) + return NULL; + if (!readData()) + return NULL; + MtpResponseCode ret = readResponse(); +printf("getStorageInfo returned %04X\n", ret); + if (ret == MTP_RESPONSE_OK) { + MtpStorageInfo* info = new MtpStorageInfo(storageID); + info->read(mData); + return info; + } + return NULL; +} + +MtpObjectHandleList* MtpDevice::getObjectHandles(MtpStorageID storageID, + MtpObjectFormat format, MtpObjectHandle parent) { + mRequest.reset(); + mRequest.setParameter(1, storageID); + mRequest.setParameter(2, format); + mRequest.setParameter(3, parent); + if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES)) + return NULL; + if (!readData()) + return NULL; + MtpResponseCode ret = readResponse(); +printf("getObjectHandles returned %04X\n", ret); + if (ret == MTP_RESPONSE_OK) { + return mData.getAUInt32(); + } + return NULL; +} + +MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) { + mRequest.reset(); + mRequest.setParameter(1, handle); + if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO)) + return NULL; + if (!readData()) + return NULL; + MtpResponseCode ret = readResponse(); +printf("getObjectInfo returned %04X\n", ret); + if (ret == MTP_RESPONSE_OK) { + MtpObjectInfo* info = new MtpObjectInfo(handle); + info->read(mData); + return info; + } + return NULL; +} + +bool MtpDevice::sendRequest(MtpOperationCode operation) { + printf("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation)); + mRequest.setOperationCode(operation); + if (mTransactionID > 0) + mRequest.setTransactionID(mTransactionID++); + int ret = mRequest.write(mEndpointOut); + mRequest.dump(); + return (ret > 0); +} + +bool MtpDevice::sendData(MtpOperationCode operation) { + printf("sendData\n"); + mData.setOperationCode(mRequest.getOperationCode()); + mData.setTransactionID(mRequest.getTransactionID()); + int ret = mData.write(mEndpointOut); + mData.dump(); + return (ret > 0); +} + +bool MtpDevice::readData() { + mData.reset(); + int ret = mData.read(mEndpointIn); + printf("readData returned %d\n", ret); + if (ret >= MTP_CONTAINER_HEADER_SIZE) { + mData.dump(); + return true; + } + else { + printf("readResponse failed\n"); + return false; + } +} + +MtpResponseCode MtpDevice::readResponse() { + printf("readResponse\n"); + int ret = mResponse.read(mEndpointIn); + if (ret >= MTP_CONTAINER_HEADER_SIZE) { + mResponse.dump(); + return mResponse.getResponseCode(); + } + else { + printf("readResponse failed\n"); + return -1; + } +} + +} // namespace android diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h new file mode 100644 index 0000000..fe4f1bd --- /dev/null +++ b/media/mtp/MtpDevice.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_DEVICE_H +#define _MTP_DEVICE_H + +#include "MtpRequestPacket.h" +#include "MtpDataPacket.h" +#include "MtpResponsePacket.h" +#include "MtpTypes.h" + +namespace android { + +class MtpDeviceInfo; +class MtpObjectInfo; +class MtpStorageInfo; + +class MtpDevice { +private: + struct usb_device* mDevice; + int mInterface; + struct usb_endpoint* mEndpointIn; + struct usb_endpoint* mEndpointOut; + struct usb_endpoint* mEndpointIntr; + MtpDeviceInfo* mDeviceInfo; + + // a unique ID for the device + int mID; + + // current session ID + MtpSessionID mSessionID; + // current transaction ID + MtpTransactionID mTransactionID; + + MtpRequestPacket mRequest; + MtpDataPacket mData; + MtpResponsePacket mResponse; + +public: + MtpDevice(struct usb_device* device, int interface, + struct usb_endpoint *ep_in, struct usb_endpoint *ep_out, + struct usb_endpoint *ep_intr); + virtual ~MtpDevice(); + + inline int getID() const { return mID; } + + void initialize(); + void close(); + const char* getDeviceName(); + + bool openSession(); + bool closeSession(); + + MtpDeviceInfo* getDeviceInfo(); + MtpStorageIDList* getStorageIDs(); + MtpStorageInfo* getStorageInfo(MtpStorageID storageID); + MtpObjectHandleList* getObjectHandles(MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent); + MtpObjectInfo* getObjectInfo(MtpObjectHandle handle); + +private: + bool sendRequest(MtpOperationCode operation); + bool sendData(MtpOperationCode operation); + bool readData(); + MtpResponseCode readResponse(); + +}; + +}; // namespace android + +#endif // _MTP_DEVICE_H diff --git a/media/mtp/MtpTypes.h b/media/mtp/MtpTypes.h index 3ec844f..e3389c0 100644 --- a/media/mtp/MtpTypes.h +++ b/media/mtp/MtpTypes.h @@ -52,17 +52,19 @@ typedef uint32_t MtpObjectHandle; #define kObjectHandleIndexMask 0x0FFFFFFF // mask for object index in file table class MtpStorage; +class MtpDevice; -typedef android::Vector<MtpStorage *> MtpStorageList; +typedef Vector<MtpStorage *> MtpStorageList; +typedef Vector<MtpDevice*> MtpDeviceList; -typedef android::Vector<uint8_t> UInt8List; -typedef android::Vector<uint32_t> UInt16List; -typedef android::Vector<uint32_t> UInt32List; -typedef android::Vector<uint64_t> UInt64List; -typedef android::Vector<int8_t> Int8List; -typedef android::Vector<int32_t> Int16List; -typedef android::Vector<int32_t> Int32List; -typedef android::Vector<int64_t> Int64List; +typedef Vector<uint8_t> UInt8List; +typedef Vector<uint32_t> UInt16List; +typedef Vector<uint32_t> UInt32List; +typedef Vector<uint64_t> UInt64List; +typedef Vector<int8_t> Int8List; +typedef Vector<int32_t> Int16List; +typedef Vector<int32_t> Int32List; +typedef Vector<int64_t> Int64List; typedef UInt16List MtpDevicePropertyList; typedef UInt16List MtpObjectFormatList; @@ -70,7 +72,7 @@ typedef UInt32List MtpObjectHandleList; typedef UInt16List MtpObjectPropertyList; typedef UInt32List MtpStorageIDList; -typedef android::String8 MtpString; +typedef String8 MtpString; }; // namespace android diff --git a/media/mtp/ptptest.cpp b/media/mtp/ptptest.cpp deleted file mode 100644 index 3b09070..0000000 --- a/media/mtp/ptptest.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <unistd.h> -#include <stdio.h> -#include <string.h> - -#include <usbhost/usbhost.h> -#include <linux/usb/ch9.h> - -#include "MtpClient.h" -#include "MtpDeviceInfo.h" -#include "MtpObjectInfo.h" -#include "MtpStorageInfo.h" - -using namespace android; - -static struct usb_device *sCameraDevice = NULL; -static int sCameraInterface = 0; -static MtpClient *sClient = NULL; - - -static void start_session(struct usb_endpoint *ep_in, struct usb_endpoint *ep_out, - struct usb_endpoint *ep_intr) -{ - if (sClient) - delete sClient; - sClient = new MtpClient(ep_in, ep_out, ep_intr); - sClient->openSession(); - MtpDeviceInfo* info = sClient->getDeviceInfo(); - if (info) { - info->print(); - delete info; - } - MtpStorageIDList* storageIDs = sClient->getStorageIDs(); - if (storageIDs) { - for (int i = 0; i < storageIDs->size(); i++) { - MtpStorageID storageID = (*storageIDs)[i]; - MtpStorageInfo* info = sClient->getStorageInfo(storageID); - if (info) { - info->print(); - delete info; - } - MtpObjectHandleList* objects = sClient->getObjectHandles(storageID, 0, MTP_PARENT_ROOT); - if (objects) { - for (int j = 0; j < objects->size(); j++) { - MtpObjectHandle handle = (*objects)[j]; - MtpObjectInfo* info = sClient->getObjectInfo(handle); - if (info) { - info->print(); - delete info; - } - } - delete objects; - } - } - } -} - -static void usb_device_added(const char *devname, void *client_data) -{ - struct usb_descriptor_header* desc; - struct usb_descriptor_iter iter; - - struct usb_device *device = usb_device_open(devname); - if (!device) return; - - usb_descriptor_iter_init(device, &iter); - - while ((desc = usb_descriptor_iter_next(&iter)) != NULL) { - if (desc->bDescriptorType == USB_DT_INTERFACE) { - struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc; - - if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE && - interface->bInterfaceSubClass == 1 && // Still Image Capture - interface->bInterfaceProtocol == 1) // Picture Transfer Protocol (PIMA 15470) - { - printf("Found camera: \"%s\" \"%s\"\n", usb_device_get_manufacturer_name(device), - usb_device_get_product_name(device)); - - // interface should be followed by three endpoints - struct usb_endpoint_descriptor *ep, *ep_in_desc = NULL, *ep_out_desc = NULL, *ep_intr_desc = NULL; - for (int i = 0; i < 3; i++) { - ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter); - if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) { - fprintf(stderr, "endpoints not found\n"); - return; - } - if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { - if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - ep_in_desc = ep; - else - ep_out_desc = ep; - } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT && - ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { - ep_intr_desc = ep; - } - } - if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) { - fprintf(stderr, "endpoints not found\n"); - return; - } - - struct usb_endpoint *ep_in = usb_endpoint_open(device, ep_in_desc); - struct usb_endpoint *ep_out = usb_endpoint_open(device, ep_out_desc); - struct usb_endpoint *ep_intr = usb_endpoint_open(device, ep_intr_desc); - - if (usb_device_claim_interface(device, interface->bInterfaceNumber)) { - fprintf(stderr, "usb_device_claim_interface failed\n"); - usb_endpoint_close(ep_in); - usb_endpoint_close(ep_out); - usb_endpoint_close(ep_intr); - return; - } - - if (sCameraDevice) { - usb_device_release_interface(sCameraDevice, sCameraInterface); - usb_device_close(sCameraDevice); - } - sCameraDevice = device; - start_session(ep_in, ep_out, ep_intr); - } - } - } - - if (device != sCameraDevice) - usb_device_close(device); -} - -static void usb_device_removed(const char *devname, void *client_data) -{ - if (sCameraDevice && !strcmp(devname, usb_device_get_name(sCameraDevice))) { - delete sClient; - printf("Camera removed!\n"); - usb_device_release_interface(sCameraDevice, sCameraInterface); - usb_device_close(sCameraDevice); - sCameraDevice = NULL; - } -} - -int main(int argc, char* argv[]) -{ - if (usb_host_init(usb_device_added, usb_device_removed, NULL)) { - fprintf(stderr, "usb_host_init failed\n"); - return -1; - } - - while (1) { - sleep(1); - } - - return 0; -} |