Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 56118b5b authored by Mike Lockwood's avatar Mike Lockwood
Browse files

Checkpoint work on MTP and PTP investigation.



This change includes work in progress on a C++ library for both host and device
MTP and PTP support.
Currently the makefile builds two test programs:

mtptest - a command line test program that implements a small subset of device side MTP.
Requires a kernel driver that has not been checked in yet.

ptptest - a host tool to test USB host support for detecting and communicating with
digital cameras over PTP.  Runs on Linux host.

Later this will be reformulated as a native library that will be used in the media process.

Change-Id: I81aab279975b600b59d99013ab97f9adf0b58da7
Signed-off-by: default avatarMike Lockwood <lockwood@android.com>
parent f6860f19
Loading
Loading
Loading
Loading

media/mtp/Android.mk

0 → 100644
+69 −0
Original line number Diff line number Diff line
#
# 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.
#
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:=                                       \
                  mtptest.cpp                           \
                  MtpDatabase.cpp                       \
                  MtpDataPacket.cpp                     \
                  MtpDebug.cpp                          \
                  MtpPacket.cpp                         \
                  MtpRequestPacket.cpp                  \
                  MtpResponsePacket.cpp                 \
                  MtpServer.cpp                         \
                  MtpStringBuffer.cpp                   \
                  MtpStorage.cpp                        \
                  MtpUtils.cpp                          \
                  SqliteDatabase.cpp                    \
                  SqliteStatement.cpp                   \

LOCAL_MODULE:= mtptest

LOCAL_C_INCLUDES := external/sqlite/dist

LOCAL_CFLAGS := -DMTP_DEVICE

LOCAL_SHARED_LIBRARIES := libutils libsqlite

include $(BUILD_EXECUTABLE)

ifeq ($(HOST_OS),linux)

include $(CLEAR_VARS)

LOCAL_MODULE := ptptest
LOCAL_SRC_FILES:=                                       \
                  ptptest.cpp                           \
                  MtpClient.cpp                         \
                  MtpDataPacket.cpp                     \
                  MtpDebug.cpp                          \
                  MtpPacket.cpp                         \
                  MtpRequestPacket.cpp                  \
                  MtpResponsePacket.cpp                 \
                  MtpStringBuffer.cpp                   \


LOCAL_STATIC_LIBRARIES := libusbhost
LOCAL_LDLIBS := -lpthread

LOCAL_CFLAGS := -g -DMTP_HOST
LOCAL_LDFLAGS := -g

include $(BUILD_HOST_EXECUTABLE)

endif
 No newline at end of file
+136 −0
Original line number Diff line number Diff line
/*
 * 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 "MtpClient.h"
#include "MtpDebug.h"
#include "MtpStringBuffer.h"

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() {
}


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;

    mSessionID = newSession;
    mTransactionID = 1;
    return true;
}

bool MtpClient::getDeviceInfo() {
    mRequest.reset();
    if (!sendRequest(MTP_OPERATION_GET_DEVICE_INFO))
        return false;
    if (!readData())
        return false;
    MtpResponseCode ret = readResponse();
    if (ret == MTP_RESPONSE_OK) {
        MtpStringBuffer string;

        // fill in device info
        printf("MTP standard version: %d\n", mData.getUInt16());
        printf("MTP Vendor Extension ID: %d\n", mData.getUInt32());
        printf("MTP vendor extension version: %d\n", mData.getUInt16());
        mData.getString(string);
        printf("vendor extension desc %s\n", (const char *)string);

        return true;
    }
    return false;
}

bool MtpClient::closeSession() {
    return true;
}

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);
}

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() {
     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;
    }
}

media/mtp/MtpClient.h

0 → 100644
+59 −0
Original line number Diff line number Diff line
/*
 * 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_CLIENT_H
#define _MTP_CLIENT_H

#include "MtpRequestPacket.h"
#include "MtpDataPacket.h"
#include "MtpResponsePacket.h"
#include "mtp.h"

#include "MtpUtils.h"

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;

public:
                        MtpClient(struct usb_endpoint *ep_in, struct usb_endpoint *ep_out,
                                    struct usb_endpoint *ep_intr);
    virtual             ~MtpClient();

    bool                openSession();
    bool                getDeviceInfo();
    bool                closeSession();

private:
    bool                sendRequest(MtpOperationCode operation);
    bool                sendData(MtpOperationCode operation);
    bool                readData();
    MtpResponseCode     readResponse();

};

#endif // _MTP_CLIENT_H
+296 −0
Original line number Diff line number Diff line
/*
 * 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 <sys/types.h>
#include <fcntl.h>

#include "MtpDataPacket.h"
#include "MtpStringBuffer.h"

MtpDataPacket::MtpDataPacket()
    :   MtpPacket(512),
        mOffset(MTP_CONTAINER_HEADER_SIZE)
{
}

MtpDataPacket::~MtpDataPacket() {
}

void MtpDataPacket::reset() {
    MtpPacket::reset();
    mOffset = MTP_CONTAINER_HEADER_SIZE;
}

void MtpDataPacket::setOperationCode(MtpOperationCode code) {
    MtpPacket::putUInt16(MTP_CONTAINER_CODE_OFFSET, code);
}

void MtpDataPacket::setTransactionID(MtpTransactionID id) {
    MtpPacket::putUInt32(MTP_CONTAINER_TRANSACTION_ID_OFFSET, id);
}

uint16_t MtpDataPacket::getUInt16() {
    int offset = mOffset;
    uint16_t result = (uint16_t)mBuffer[offset] | ((uint16_t)mBuffer[offset + 1] << 8);
    mOffset += 2;
    return result;
}

uint32_t MtpDataPacket::getUInt32() {
    int offset = mOffset;
    uint32_t result = (uint32_t)mBuffer[offset] | ((uint32_t)mBuffer[offset + 1] << 8) |
           ((uint32_t)mBuffer[offset + 2] << 16)  | ((uint32_t)mBuffer[offset + 3] << 24);
    mOffset += 4;
    return result;
}

uint64_t MtpDataPacket::getUInt64() {
    int offset = mOffset;
    uint64_t result = (uint64_t)mBuffer[offset] | ((uint64_t)mBuffer[offset + 1] << 8) |
           ((uint64_t)mBuffer[offset + 2] << 16) | ((uint64_t)mBuffer[offset + 3] << 24) |
           ((uint64_t)mBuffer[offset + 4] << 32) | ((uint64_t)mBuffer[offset + 5] << 40) |
           ((uint64_t)mBuffer[offset + 6] << 48)  | ((uint64_t)mBuffer[offset + 7] << 56);
    mOffset += 8;
    return result;
}

void MtpDataPacket::getString(MtpStringBuffer& string)
{
    string.readFromPacket(this);
}

void MtpDataPacket::putInt8(int8_t value) {
    allocate(mOffset + 1);
    mBuffer[mOffset++] = (uint8_t)value;
    if (mPacketSize < mOffset)
        mPacketSize = mOffset;
}

void MtpDataPacket::putUInt8(uint8_t value) {
    allocate(mOffset + 1);
    mBuffer[mOffset++] = (uint8_t)value;
    if (mPacketSize < mOffset)
        mPacketSize = mOffset;
}

void MtpDataPacket::putInt16(int16_t value) {
    allocate(mOffset + 2);
    mBuffer[mOffset++] = (uint8_t)(value & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF);
    if (mPacketSize < mOffset)
        mPacketSize = mOffset;
}

void MtpDataPacket::putUInt16(uint16_t value) {
    allocate(mOffset + 2);
    mBuffer[mOffset++] = (uint8_t)(value & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF);
    if (mPacketSize < mOffset)
        mPacketSize = mOffset;
}

void MtpDataPacket::putInt32(int32_t value) {
    allocate(mOffset + 4);
    mBuffer[mOffset++] = (uint8_t)(value & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 16) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 24) & 0xFF);
    if (mPacketSize < mOffset)
        mPacketSize = mOffset;
}

void MtpDataPacket::putUInt32(uint32_t value) {
    allocate(mOffset + 4);
    mBuffer[mOffset++] = (uint8_t)(value & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 16) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 24) & 0xFF);
    if (mPacketSize < mOffset)
        mPacketSize = mOffset;
}

void MtpDataPacket::putInt64(int64_t value) {
    allocate(mOffset + 8);
    mBuffer[mOffset++] = (uint8_t)(value & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 16) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 24) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 32) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 40) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 48) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 56) & 0xFF);
    if (mPacketSize < mOffset)
        mPacketSize = mOffset;
}

void MtpDataPacket::putUInt64(uint64_t value) {
    allocate(mOffset + 8);
    mBuffer[mOffset++] = (uint8_t)(value & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 8) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 16) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 24) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 32) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 40) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 48) & 0xFF);
    mBuffer[mOffset++] = (uint8_t)((value >> 56) & 0xFF);
    if (mPacketSize < mOffset)
        mPacketSize = mOffset;
}

void MtpDataPacket::putAInt8(const int8_t* values, int count) {
    putUInt32(count);
    for (int i = 0; i < count; i++)
        putInt8(*values++);
}

void MtpDataPacket::putAUInt8(const uint8_t* values, int count) {
    putUInt32(count);
    for (int i = 0; i < count; i++)
        putUInt8(*values++);
}

void MtpDataPacket::putAInt16(const int16_t* values, int count) {
    putUInt32(count);
    for (int i = 0; i < count; i++)
        putInt16(*values++);
}

void MtpDataPacket::putAUInt16(const uint16_t* values, int count) {
    putUInt32(count);
    for (int i = 0; i < count; i++)
        putUInt16(*values++);
}

void MtpDataPacket::putAInt32(const int32_t* values, int count) {
    putUInt32(count);
    for (int i = 0; i < count; i++)
        putInt32(*values++);
}

void MtpDataPacket::putAUInt32(const uint32_t* values, int count) {
    putUInt32(count);
    for (int i = 0; i < count; i++)
        putUInt32(*values++);
}

void MtpDataPacket::putAUInt32(const UInt32List* list) {
    if (!list) {
        putEmptyArray();
    } else {
        size_t size = list->size();
        putUInt32(size);
        for (size_t i = 0; i < size; i++)
            putUInt32((*list)[i]);
    }
}

void MtpDataPacket::putAInt64(const int64_t* values, int count) {
    putUInt32(count);
    for (int i = 0; i < count; i++)
        putInt64(*values++);
}

void MtpDataPacket::putAUInt64(const uint64_t* values, int count) {
    putUInt32(count);
    for (int i = 0; i < count; i++)
        putUInt64(*values++);
}

void MtpDataPacket::putString(const MtpStringBuffer& string)
{
    string.writeToPacket(this);
}

void MtpDataPacket::putString(const char* s)
{
    MtpStringBuffer string(s);
    string.writeToPacket(this);
}

#ifdef MTP_DEVICE 
int MtpDataPacket::read(int fd) {
    // first read the header
    int ret = ::read(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
printf("MtpDataPacket::read 1 returned %d\n", ret);
    if (ret != MTP_CONTAINER_HEADER_SIZE)
        return -1;
    // then the following data
    int total = MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET);
    int remaining = total - MTP_CONTAINER_HEADER_SIZE;
printf("total: %d, remaining: %d\n", total, remaining);
    ret = ::read(fd, &mBuffer[0] + MTP_CONTAINER_HEADER_SIZE, remaining);
printf("MtpDataPacket::read 2 returned %d\n", ret);
    if (ret != remaining)
        return -1;

    mPacketSize = total;
    mOffset = MTP_CONTAINER_HEADER_SIZE;
    return total;
}

int MtpDataPacket::readDataHeader(int fd) {
    int ret = ::read(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
    if (ret > 0)
        mPacketSize = ret;
    else
        mPacketSize = 0;
    return ret;
}

int MtpDataPacket::write(int fd) {
    MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
    MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);

    // send header separately from data
    int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
    if (ret == MTP_CONTAINER_HEADER_SIZE)
        ret = ::write(fd, mBuffer + MTP_CONTAINER_HEADER_SIZE,
                        mPacketSize - MTP_CONTAINER_HEADER_SIZE);
    return (ret < 0 ? ret : 0);
}

int MtpDataPacket::writeDataHeader(int fd, uint32_t length) {
    MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
    MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
    int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
    return (ret < 0 ? ret : 0);
}
#endif // MTP_DEVICE

#ifdef MTP_HOST
int MtpDataPacket::read(struct usb_endpoint *ep) {
    // first read the header
    int ret = transfer(ep, mBuffer, mBufferSize);
printf("MtpDataPacket::transfer returned %d\n", ret);
    if (ret >= 0)
        mPacketSize = ret;
    return ret;
}

int MtpDataPacket::write(struct usb_endpoint *ep) {
    MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
    MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);

    // send header separately from data
    int ret = transfer(ep, mBuffer, MTP_CONTAINER_HEADER_SIZE);
    if (ret == MTP_CONTAINER_HEADER_SIZE)
        ret = transfer(ep, mBuffer + MTP_CONTAINER_HEADER_SIZE,
                        mPacketSize - MTP_CONTAINER_HEADER_SIZE);
    return (ret < 0 ? ret : 0);
}

#endif // MTP_HOST
+89 −0
Original line number Diff line number Diff line
/*
 * 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_DATA_PACKET_H
#define _MTP_DATA_PACKET_H

#include "MtpPacket.h"
#include "mtp.h"

class MtpDataPacket : public MtpPacket {
private:
    // current offset for get/put methods
    int                 mOffset;

public:
                        MtpDataPacket();
    virtual             ~MtpDataPacket();

    virtual void        reset();

    void                setOperationCode(MtpOperationCode code);
    void                setTransactionID(MtpTransactionID id);

    inline uint8_t      getUInt8() { return (uint8_t)mBuffer[mOffset++]; }
    inline int8_t       getInt8() { return (int8_t)mBuffer[mOffset++]; }
    uint16_t            getUInt16();
    inline int16_t      getInt16() { return (int16_t)getUInt16(); }
    uint32_t            getUInt32();
    inline int32_t      getInt32() { return (int32_t)getUInt32(); }
    uint64_t            getUInt64();
    inline int64_t      getInt64() { return (int64_t)getUInt64(); }
    void                getString(MtpStringBuffer& string);

    void                putInt8(int8_t value);
    void                putUInt8(uint8_t value);
    void                putInt16(int16_t value);
    void                putUInt16(uint16_t value);
    void                putInt32(int32_t value);
    void                putUInt32(uint32_t value);
    void                putInt64(int64_t value);
    void                putUInt64(uint64_t value);

    void                putAInt8(const int8_t* values, int count);
    void                putAUInt8(const uint8_t* values, int count);
    void                putAInt16(const int16_t* values, int count);
    void                putAUInt16(const uint16_t* values, int count);
    void                putAInt32(const int32_t* values, int count);
    void                putAUInt32(const uint32_t* values, int count);
    void                putAUInt32(const UInt32List* list);
    void                putAInt64(const int64_t* values, int count);
    void                putAUInt64(const uint64_t* values, int count);
    void                putString(const MtpStringBuffer& string);
    void                putString(const char* string);
    inline void         putEmptyString() { putUInt16(0); }
    inline void         putEmptyArray() { putUInt32(0); }


#ifdef MTP_DEVICE
    // fill our buffer with data from the given file descriptor
    int                 read(int fd);
    int                 readDataHeader(int fd);

    // write our data to the given file descriptor
    int                 write(int fd);
    int                 writeDataHeader(int fd, uint32_t length);
#endif

#ifdef MTP_HOST
    int                 read(struct usb_endpoint *ep);
    int                 write(struct usb_endpoint *ep);
#endif

    inline bool         hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; }
};

#endif // _MTP_DATA_PACKET_H
Loading