Home | History | Annotate | Download | only in mtp
      1 /*
      2  * Copyright (C) 2017 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 #include <android-base/logging.h>
     18 #include <sys/types.h>
     19 
     20 #include "MtpDescriptors.h"
     21 
     22 namespace android {
     23 
     24 const struct usb_interface_descriptor mtp_interface_desc = {
     25     .bLength = USB_DT_INTERFACE_SIZE,
     26     .bDescriptorType = USB_DT_INTERFACE,
     27     .bInterfaceNumber = 0,
     28     .bNumEndpoints = 3,
     29     .bInterfaceClass = USB_CLASS_STILL_IMAGE,
     30     .bInterfaceSubClass = 1,
     31     .bInterfaceProtocol = 1,
     32     .iInterface = 1,
     33 };
     34 
     35 const struct usb_interface_descriptor ptp_interface_desc = {
     36     .bLength = USB_DT_INTERFACE_SIZE,
     37     .bDescriptorType = USB_DT_INTERFACE,
     38     .bInterfaceNumber = 0,
     39     .bNumEndpoints = 3,
     40     .bInterfaceClass = USB_CLASS_STILL_IMAGE,
     41     .bInterfaceSubClass = 1,
     42     .bInterfaceProtocol = 1,
     43 };
     44 
     45 const struct usb_endpoint_descriptor_no_audio fs_sink = {
     46     .bLength = USB_DT_ENDPOINT_SIZE,
     47     .bDescriptorType = USB_DT_ENDPOINT,
     48     .bEndpointAddress = 1 | USB_DIR_IN,
     49     .bmAttributes = USB_ENDPOINT_XFER_BULK,
     50     .wMaxPacketSize = MAX_PACKET_SIZE_FS,
     51 };
     52 
     53 const struct usb_endpoint_descriptor_no_audio fs_source = {
     54     .bLength = USB_DT_ENDPOINT_SIZE,
     55     .bDescriptorType = USB_DT_ENDPOINT,
     56     .bEndpointAddress = 2 | USB_DIR_OUT,
     57     .bmAttributes = USB_ENDPOINT_XFER_BULK,
     58     .wMaxPacketSize = MAX_PACKET_SIZE_FS,
     59 };
     60 
     61 const struct usb_endpoint_descriptor_no_audio intr = {
     62     .bLength = USB_DT_ENDPOINT_SIZE,
     63     .bDescriptorType = USB_DT_ENDPOINT,
     64     .bEndpointAddress = 3 | USB_DIR_IN,
     65     .bmAttributes = USB_ENDPOINT_XFER_INT,
     66     .wMaxPacketSize = MAX_PACKET_SIZE_EV,
     67     .bInterval = 6,
     68 };
     69 
     70 const struct usb_endpoint_descriptor_no_audio hs_sink = {
     71     .bLength = USB_DT_ENDPOINT_SIZE,
     72     .bDescriptorType = USB_DT_ENDPOINT,
     73     .bEndpointAddress = 1 | USB_DIR_IN,
     74     .bmAttributes = USB_ENDPOINT_XFER_BULK,
     75     .wMaxPacketSize = MAX_PACKET_SIZE_HS,
     76 };
     77 
     78 const struct usb_endpoint_descriptor_no_audio hs_source = {
     79     .bLength = USB_DT_ENDPOINT_SIZE,
     80     .bDescriptorType = USB_DT_ENDPOINT,
     81     .bEndpointAddress = 2 | USB_DIR_OUT,
     82     .bmAttributes = USB_ENDPOINT_XFER_BULK,
     83     .wMaxPacketSize = MAX_PACKET_SIZE_HS,
     84 };
     85 
     86 const struct usb_endpoint_descriptor_no_audio ss_sink = {
     87     .bLength = USB_DT_ENDPOINT_SIZE,
     88     .bDescriptorType = USB_DT_ENDPOINT,
     89     .bEndpointAddress = 1 | USB_DIR_IN,
     90     .bmAttributes = USB_ENDPOINT_XFER_BULK,
     91     .wMaxPacketSize = MAX_PACKET_SIZE_SS,
     92 };
     93 
     94 const struct usb_endpoint_descriptor_no_audio ss_source = {
     95     .bLength = USB_DT_ENDPOINT_SIZE,
     96     .bDescriptorType = USB_DT_ENDPOINT,
     97     .bEndpointAddress = 2 | USB_DIR_OUT,
     98     .bmAttributes = USB_ENDPOINT_XFER_BULK,
     99     .wMaxPacketSize = MAX_PACKET_SIZE_SS,
    100 };
    101 
    102 const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
    103     .bLength = sizeof(ss_sink_comp),
    104     .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
    105     .bMaxBurst = 6,
    106 };
    107 
    108 const struct usb_ss_ep_comp_descriptor ss_source_comp = {
    109     .bLength = sizeof(ss_source_comp),
    110     .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
    111     .bMaxBurst = 6,
    112 };
    113 
    114 const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
    115     .bLength = sizeof(ss_intr_comp),
    116     .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
    117 };
    118 
    119 const struct func_desc mtp_fs_descriptors = {
    120     .intf = mtp_interface_desc,
    121     .sink = fs_sink,
    122     .source = fs_source,
    123     .intr = intr,
    124 };
    125 
    126 const struct func_desc mtp_hs_descriptors = {
    127     .intf = mtp_interface_desc,
    128     .sink = hs_sink,
    129     .source = hs_source,
    130     .intr = intr,
    131 };
    132 
    133 const struct ss_func_desc mtp_ss_descriptors = {
    134     .intf = mtp_interface_desc,
    135     .sink = ss_sink,
    136     .sink_comp = ss_sink_comp,
    137     .source = ss_source,
    138     .source_comp = ss_source_comp,
    139     .intr = intr,
    140     .intr_comp = ss_intr_comp,
    141 };
    142 
    143 const struct func_desc ptp_fs_descriptors = {
    144     .intf = ptp_interface_desc,
    145     .sink = fs_sink,
    146     .source = fs_source,
    147     .intr = intr,
    148 };
    149 
    150 const struct func_desc ptp_hs_descriptors = {
    151     .intf = ptp_interface_desc,
    152     .sink = hs_sink,
    153     .source = hs_source,
    154     .intr = intr,
    155 };
    156 
    157 const struct ss_func_desc ptp_ss_descriptors = {
    158     .intf = ptp_interface_desc,
    159     .sink = ss_sink,
    160     .sink_comp = ss_sink_comp,
    161     .source = ss_source,
    162     .source_comp = ss_source_comp,
    163     .intr = intr,
    164     .intr_comp = ss_intr_comp,
    165 };
    166 
    167 const struct functionfs_strings mtp_strings = {
    168     .header = {
    169         .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
    170         .length = htole32(sizeof(mtp_strings)),
    171         .str_count = htole32(1),
    172         .lang_count = htole32(1),
    173     },
    174     .lang0 = {
    175         .code = htole16(0x0409),
    176         .str1 = STR_INTERFACE,
    177     },
    178 };
    179 
    180 const struct usb_os_desc_header mtp_os_desc_header = {
    181     .interface = htole32(1),
    182     .dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
    183     .bcdVersion = htole16(1),
    184     .wIndex = htole16(4),
    185     .bCount = htole16(1),
    186     .Reserved = htole16(0),
    187 };
    188 
    189 const struct usb_ext_compat_desc mtp_os_desc_compat = {
    190     .bFirstInterfaceNumber = 0,
    191     .Reserved1 = htole32(1),
    192     .CompatibleID = { 'M', 'T', 'P' },
    193     .SubCompatibleID = {0},
    194     .Reserved2 = {0},
    195 };
    196 
    197 const struct usb_ext_compat_desc ptp_os_desc_compat = {
    198     .bFirstInterfaceNumber = 0,
    199     .Reserved1 = htole32(1),
    200     .CompatibleID = { 'P', 'T', 'P' },
    201     .SubCompatibleID = {0},
    202     .Reserved2 = {0},
    203 };
    204 
    205 const struct desc_v2 mtp_desc_v2 = {
    206     .header = {
    207         .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
    208         .length = htole32(sizeof(struct desc_v2)),
    209         .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
    210                  FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC,
    211     },
    212     .fs_count = 4,
    213     .hs_count = 4,
    214     .ss_count = 7,
    215     .os_count = 1,
    216     .fs_descs = mtp_fs_descriptors,
    217     .hs_descs = mtp_hs_descriptors,
    218     .ss_descs = mtp_ss_descriptors,
    219     .os_header = mtp_os_desc_header,
    220     .os_desc = mtp_os_desc_compat,
    221 };
    222 
    223 const struct desc_v2 ptp_desc_v2 = {
    224     .header = {
    225         .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
    226         .length = htole32(sizeof(struct desc_v2)),
    227         .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
    228                  FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC,
    229     },
    230     .fs_count = 4,
    231     .hs_count = 4,
    232     .ss_count = 7,
    233     .os_count = 1,
    234     .fs_descs = ptp_fs_descriptors,
    235     .hs_descs = ptp_hs_descriptors,
    236     .ss_descs = ptp_ss_descriptors,
    237     .os_header = mtp_os_desc_header,
    238     .os_desc = ptp_os_desc_compat,
    239 };
    240 
    241 const struct desc_v1 mtp_desc_v1 = {
    242     .header = {
    243         .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
    244         .length = htole32(sizeof(struct desc_v1)),
    245         .fs_count = 4,
    246         .hs_count = 4,
    247     },
    248     .fs_descs = mtp_fs_descriptors,
    249     .hs_descs = mtp_hs_descriptors,
    250 };
    251 
    252 const struct desc_v1 ptp_desc_v1 = {
    253     .header = {
    254         .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
    255         .length = htole32(sizeof(struct desc_v1)),
    256         .fs_count = 4,
    257         .hs_count = 4,
    258     },
    259     .fs_descs = ptp_fs_descriptors,
    260     .hs_descs = ptp_hs_descriptors,
    261 };
    262 
    263 bool writeDescriptors(int fd, bool ptp) {
    264     ssize_t ret = TEMP_FAILURE_RETRY(write(fd,
    265                 &(ptp ? ptp_desc_v2 : mtp_desc_v2), sizeof(desc_v2)));
    266     if (ret < 0) {
    267         PLOG(ERROR) << fd << "Switching to V1 descriptor format";
    268         ret = TEMP_FAILURE_RETRY(write(fd,
    269                     &(ptp ? ptp_desc_v1 : mtp_desc_v1), sizeof(desc_v1)));
    270         if (ret < 0) {
    271             PLOG(ERROR) << fd << "Writing descriptors failed";
    272             return false;
    273         }
    274     }
    275     ret = TEMP_FAILURE_RETRY(write(fd, &mtp_strings, sizeof(mtp_strings)));
    276     if (ret < 0) {
    277         PLOG(ERROR) << fd << "Writing strings failed";
    278         return false;
    279     }
    280     return true;
    281 }
    282 
    283 }; // namespace android
    284