This update splits old MTP code and new MTP code from Google into two trees, legacy and ffs. Depending on the SDK level, the build system will select the correct version. The reason for separating the versions out are due to older android trees not supporting the updated MTP code from Google. Most MTP code is from Google, with additions needed from implementing the Java functions in C++ for TWRP and FFS. We assume if you are in android-9.0 or above, your kernel has support for FFS over MTP. Verify that your init.rc is mounting the MTP FFS driver to the proper location. Change-Id: I4b107b239bd9bc5699527f9c8c77d9079f264a7e
283 lines
7.4 KiB
C++
283 lines
7.4 KiB
C++
/*
|
|
* Copyright (C) 2017 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 <android-base/logging.h>
|
|
#include <sys/types.h>
|
|
#include <cutils/properties.h>
|
|
|
|
#include "MtpDescriptors.h"
|
|
#include "MtpDebug.h"
|
|
|
|
const struct usb_interface_descriptor mtp_interface_desc = {
|
|
.bLength = USB_DT_INTERFACE_SIZE,
|
|
.bDescriptorType = USB_DT_INTERFACE,
|
|
.bInterfaceNumber = 0,
|
|
.bNumEndpoints = 3,
|
|
.bInterfaceClass = USB_CLASS_STILL_IMAGE,
|
|
.bInterfaceSubClass = 1,
|
|
.bInterfaceProtocol = 1,
|
|
.iInterface = 1,
|
|
};
|
|
|
|
const struct usb_interface_descriptor ptp_interface_desc = {
|
|
.bLength = USB_DT_INTERFACE_SIZE,
|
|
.bDescriptorType = USB_DT_INTERFACE,
|
|
.bInterfaceNumber = 0,
|
|
.bNumEndpoints = 3,
|
|
.bInterfaceClass = USB_CLASS_STILL_IMAGE,
|
|
.bInterfaceSubClass = 1,
|
|
.bInterfaceProtocol = 1,
|
|
};
|
|
|
|
const struct usb_endpoint_descriptor_no_audio fs_sink = {
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
.bEndpointAddress = 1 | USB_DIR_IN,
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
.wMaxPacketSize = MAX_PACKET_SIZE_FS,
|
|
};
|
|
|
|
const struct usb_endpoint_descriptor_no_audio fs_source = {
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
.bEndpointAddress = 2 | USB_DIR_OUT,
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
.wMaxPacketSize = MAX_PACKET_SIZE_FS,
|
|
};
|
|
|
|
const struct usb_endpoint_descriptor_no_audio intr = {
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
.bEndpointAddress = 3 | USB_DIR_IN,
|
|
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
|
.wMaxPacketSize = MAX_PACKET_SIZE_EV,
|
|
.bInterval = 6,
|
|
};
|
|
|
|
const struct usb_endpoint_descriptor_no_audio hs_sink = {
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
.bEndpointAddress = 1 | USB_DIR_IN,
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
.wMaxPacketSize = MAX_PACKET_SIZE_HS,
|
|
};
|
|
|
|
const struct usb_endpoint_descriptor_no_audio hs_source = {
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
.bEndpointAddress = 2 | USB_DIR_OUT,
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
.wMaxPacketSize = MAX_PACKET_SIZE_HS,
|
|
};
|
|
|
|
const struct usb_endpoint_descriptor_no_audio ss_sink = {
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
.bEndpointAddress = 1 | USB_DIR_IN,
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
.wMaxPacketSize = MAX_PACKET_SIZE_SS,
|
|
};
|
|
|
|
const struct usb_endpoint_descriptor_no_audio ss_source = {
|
|
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
.bDescriptorType = USB_DT_ENDPOINT,
|
|
.bEndpointAddress = 2 | USB_DIR_OUT,
|
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
|
.wMaxPacketSize = MAX_PACKET_SIZE_SS,
|
|
};
|
|
|
|
const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
|
|
.bLength = sizeof(ss_sink_comp),
|
|
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
|
.bMaxBurst = 6,
|
|
};
|
|
|
|
const struct usb_ss_ep_comp_descriptor ss_source_comp = {
|
|
.bLength = sizeof(ss_source_comp),
|
|
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
|
.bMaxBurst = 6,
|
|
};
|
|
|
|
const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
|
|
.bLength = sizeof(ss_intr_comp),
|
|
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
|
};
|
|
|
|
const struct func_desc mtp_fs_descriptors = {
|
|
.intf = mtp_interface_desc,
|
|
.sink = fs_sink,
|
|
.source = fs_source,
|
|
.intr = intr,
|
|
};
|
|
|
|
const struct func_desc mtp_hs_descriptors = {
|
|
.intf = mtp_interface_desc,
|
|
.sink = hs_sink,
|
|
.source = hs_source,
|
|
.intr = intr,
|
|
};
|
|
|
|
const struct ss_func_desc mtp_ss_descriptors = {
|
|
.intf = mtp_interface_desc,
|
|
.sink = ss_sink,
|
|
.sink_comp = ss_sink_comp,
|
|
.source = ss_source,
|
|
.source_comp = ss_source_comp,
|
|
.intr = intr,
|
|
.intr_comp = ss_intr_comp,
|
|
};
|
|
|
|
const struct func_desc ptp_fs_descriptors = {
|
|
.intf = ptp_interface_desc,
|
|
.sink = fs_sink,
|
|
.source = fs_source,
|
|
.intr = intr,
|
|
};
|
|
|
|
const struct func_desc ptp_hs_descriptors = {
|
|
.intf = ptp_interface_desc,
|
|
.sink = hs_sink,
|
|
.source = hs_source,
|
|
.intr = intr,
|
|
};
|
|
|
|
const struct ss_func_desc ptp_ss_descriptors = {
|
|
.intf = ptp_interface_desc,
|
|
.sink = ss_sink,
|
|
.sink_comp = ss_sink_comp,
|
|
.source = ss_source,
|
|
.source_comp = ss_source_comp,
|
|
.intr = intr,
|
|
.intr_comp = ss_intr_comp,
|
|
};
|
|
|
|
const struct functionfs_strings mtp_strings = {
|
|
.header = {
|
|
.magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
|
|
.length = htole32(sizeof(mtp_strings)),
|
|
.str_count = htole32(1),
|
|
.lang_count = htole32(1),
|
|
},
|
|
.lang0 = {
|
|
.code = htole16(0x0409),
|
|
.str1 = STR_INTERFACE,
|
|
},
|
|
};
|
|
|
|
const struct usb_os_desc_header mtp_os_desc_header = {
|
|
.interface = htole32(1),
|
|
.dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
|
|
.bcdVersion = htole16(1),
|
|
.wIndex = htole16(4),
|
|
.bCount = htole16(1),
|
|
.Reserved = htole16(0),
|
|
};
|
|
|
|
const struct usb_ext_compat_desc mtp_os_desc_compat = {
|
|
.bFirstInterfaceNumber = 0,
|
|
.Reserved1 = htole32(1),
|
|
.CompatibleID = { 'M', 'T', 'P' },
|
|
.SubCompatibleID = {0},
|
|
.Reserved2 = {0},
|
|
};
|
|
|
|
const struct usb_ext_compat_desc ptp_os_desc_compat = {
|
|
.bFirstInterfaceNumber = 0,
|
|
.Reserved1 = htole32(1),
|
|
.CompatibleID = { 'P', 'T', 'P' },
|
|
.SubCompatibleID = {0},
|
|
.Reserved2 = {0},
|
|
};
|
|
|
|
const struct desc_v2 mtp_desc_v2 = {
|
|
.header = {
|
|
.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
|
|
.length = htole32(sizeof(struct desc_v2)),
|
|
.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
|
|
FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC,
|
|
},
|
|
.fs_count = 4,
|
|
.hs_count = 4,
|
|
.ss_count = 7,
|
|
.os_count = 1,
|
|
.fs_descs = mtp_fs_descriptors,
|
|
.hs_descs = mtp_hs_descriptors,
|
|
.ss_descs = mtp_ss_descriptors,
|
|
.os_header = mtp_os_desc_header,
|
|
.os_desc = mtp_os_desc_compat,
|
|
};
|
|
|
|
const struct desc_v2 ptp_desc_v2 = {
|
|
.header = {
|
|
.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
|
|
.length = htole32(sizeof(struct desc_v2)),
|
|
.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
|
|
FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC,
|
|
},
|
|
.fs_count = 4,
|
|
.hs_count = 4,
|
|
.ss_count = 7,
|
|
.os_count = 1,
|
|
.fs_descs = ptp_fs_descriptors,
|
|
.hs_descs = ptp_hs_descriptors,
|
|
.ss_descs = ptp_ss_descriptors,
|
|
.os_header = mtp_os_desc_header,
|
|
.os_desc = ptp_os_desc_compat,
|
|
};
|
|
|
|
const struct desc_v1 mtp_desc_v1 = {
|
|
.header = {
|
|
.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
|
|
.length = htole32(sizeof(struct desc_v1)),
|
|
.fs_count = 4,
|
|
.hs_count = 4,
|
|
},
|
|
.fs_descs = mtp_fs_descriptors,
|
|
.hs_descs = mtp_hs_descriptors,
|
|
};
|
|
|
|
const struct desc_v1 ptp_desc_v1 = {
|
|
.header = {
|
|
.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
|
|
.length = htole32(sizeof(struct desc_v1)),
|
|
.fs_count = 4,
|
|
.hs_count = 4,
|
|
},
|
|
.fs_descs = ptp_fs_descriptors,
|
|
.hs_descs = ptp_hs_descriptors,
|
|
};
|
|
|
|
bool writeDescriptors(int fd, bool ptp) {
|
|
ssize_t ret = TEMP_FAILURE_RETRY(write(fd,
|
|
&(ptp ? ptp_desc_v2 : mtp_desc_v2), sizeof(desc_v2)));
|
|
if (ret < 0) {
|
|
MTPE("Switching to V1 descriptor format\n");
|
|
ret = TEMP_FAILURE_RETRY(write(fd,
|
|
&(ptp ? ptp_desc_v1 : mtp_desc_v1), sizeof(desc_v1)));
|
|
if (ret < 0) {
|
|
MTPE("Writing descriptors failed\n");
|
|
return false;
|
|
}
|
|
}
|
|
ret = TEMP_FAILURE_RETRY(write(fd, &mtp_strings, sizeof(mtp_strings)));
|
|
if (ret < 0) {
|
|
MTPE("Writing strings failed\n");
|
|
return false;
|
|
}
|
|
property_set("sys.usb.ffs.mtp.ready", "1");
|
|
return true;
|
|
}
|