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
writeDescriptors(int fd,bool ptp)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