1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <ddk/binding.h>
6 #include <ddk/debug.h>
7 #include <ddk/protocol/usb.h>
8 #include <ddk/protocol/usb/composite.h>
9 #include <usb/usb-request.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13
14 #include "usb-composite.h"
15 #include "usb-interface.h"
16
usb_interface_get_protocol(void * ctx,uint32_t proto_id,void * out)17 static zx_status_t usb_interface_get_protocol(void* ctx, uint32_t proto_id, void* out) {
18 usb_interface_t* intf = ctx;
19 switch (proto_id) {
20 case ZX_PROTOCOL_USB: {
21 usb_protocol_t* proto = (usb_protocol_t *)out;
22 proto->ctx = intf;
23 proto->ops = &usb_device_protocol;
24 return ZX_OK;
25 }
26 case ZX_PROTOCOL_USB_COMPOSITE: {
27 usb_composite_protocol_t* proto = (usb_composite_protocol_t *)out;
28 proto->ctx = intf;
29 proto->ops = &usb_composite_device_protocol;
30 return ZX_OK;
31 }
32 default:
33 return ZX_ERR_NOT_SUPPORTED;
34 }
35 }
36
usb_interface_unbind(void * ctx)37 static void usb_interface_unbind(void* ctx) {
38 usb_interface_t* intf = ctx;
39 device_remove(intf->zxdev);
40 }
41
usb_interface_release(void * ctx)42 static void usb_interface_release(void* ctx) {
43 usb_interface_t* intf = ctx;
44
45 free(intf->descriptor);
46 free(intf);
47 }
48
49 zx_protocol_device_t usb_interface_proto = {
50 .version = DEVICE_OPS_VERSION,
51 .get_protocol = usb_interface_get_protocol,
52 .unbind = usb_interface_unbind,
53 .release = usb_interface_release,
54 };
55
56 #define NEXT_DESCRIPTOR(header) ((usb_descriptor_header_t*)((void*)header + header->bLength))
57
58 // for determining index into active_endpoints[]
59 // bEndpointAddress has 4 lower order bits, plus high bit to signify direction
60 // shift high bit to bit 4 so index is in range 0 - 31.
61 #define get_usb_endpoint_index(ep) (((ep)->bEndpointAddress & 0x0F) | ((ep)->bEndpointAddress >> 3))
62
usb_interface_configure_endpoints(usb_interface_t * intf,uint8_t interface_id,uint8_t alt_setting)63 zx_status_t usb_interface_configure_endpoints(usb_interface_t* intf, uint8_t interface_id,
64 uint8_t alt_setting) {
65 usb_endpoint_descriptor_t* new_endpoints[USB_MAX_EPS] = {};
66 bool interface_endpoints[USB_MAX_EPS] = {};
67 zx_status_t status = ZX_OK;
68
69 // iterate through our descriptors to find which endpoints should be active
70 usb_descriptor_header_t* header = intf->descriptor;
71 usb_descriptor_header_t* end = (usb_descriptor_header_t*)((void*)header +
72 intf->descriptor_length);
73 int cur_interface = -1;
74
75 bool enable_endpoints = false;
76 while (header < end) {
77 if (header->bDescriptorType == USB_DT_INTERFACE) {
78 usb_interface_descriptor_t* intf_desc = (usb_interface_descriptor_t*)header;
79 cur_interface = intf_desc->bInterfaceNumber;
80 enable_endpoints = (intf_desc->bAlternateSetting == alt_setting);
81 } else if (header->bDescriptorType == USB_DT_ENDPOINT && cur_interface == interface_id) {
82 usb_endpoint_descriptor_t* ep = (usb_endpoint_descriptor_t*)header;
83 int ep_index = get_usb_endpoint_index(ep);
84 interface_endpoints[ep_index] = true;
85 if (enable_endpoints) {
86 new_endpoints[ep_index] = ep;
87 }
88 }
89 header = NEXT_DESCRIPTOR(header);
90 }
91
92 // update to new set of endpoints
93 // FIXME - how do we recover if we fail half way through processing the endpoints?
94 for (size_t i = 0; i < countof(new_endpoints); i++) {
95 if (interface_endpoints[i]) {
96 usb_endpoint_descriptor_t* old_ep = intf->active_endpoints[i];
97 usb_endpoint_descriptor_t* new_ep = new_endpoints[i];
98 if (old_ep != new_ep) {
99 if (old_ep) {
100 zx_status_t ret = usb_enable_endpoint(&intf->comp->usb, old_ep, NULL, false);
101 if (ret != ZX_OK) status = ret;
102 }
103 if (new_ep) {
104 usb_ss_ep_comp_descriptor_t* ss_comp_desc = NULL;
105 usb_descriptor_header_t* next =
106 (usb_descriptor_header_t *)((void *)new_ep + new_ep->bLength);
107 if (next + sizeof(*ss_comp_desc) <= end
108 && next->bDescriptorType == USB_DT_SS_EP_COMPANION) {
109 ss_comp_desc = (usb_ss_ep_comp_descriptor_t *)next;
110 }
111 zx_status_t ret = usb_enable_endpoint(&intf->comp->usb, new_ep, ss_comp_desc,
112 true);
113 if (ret != ZX_OK) {
114 status = ret;
115 }
116 }
117 intf->active_endpoints[i] = new_ep;
118 }
119 }
120 }
121 return status;
122 }
123
usb_interface_control_out(void * ctx,uint8_t request_type,uint8_t request,uint16_t value,uint16_t index,zx_time_t timeout,const void * write_buffer,size_t write_size)124 static zx_status_t usb_interface_control_out(void* ctx, uint8_t request_type, uint8_t request,
125 uint16_t value, uint16_t index, zx_time_t timeout,
126 const void* write_buffer, size_t write_size) {
127 usb_interface_t* intf = ctx;
128 return usb_control_out(&intf->comp->usb, request_type, request, value, index, timeout,
129 write_buffer, write_size);
130 }
131
usb_interface_control_in(void * ctx,uint8_t request_type,uint8_t request,uint16_t value,uint16_t index,zx_time_t timeout,void * out_read_buffer,size_t read_size,size_t * out_read_actual)132 static zx_status_t usb_interface_control_in(void* ctx, uint8_t request_type, uint8_t request,
133 uint16_t value, uint16_t index, zx_time_t timeout,
134 void* out_read_buffer, size_t read_size,
135 size_t* out_read_actual) {
136 usb_interface_t* intf = ctx;
137 return usb_control_in(&intf->comp->usb, request_type, request, value, index, timeout,
138 out_read_buffer, read_size, out_read_actual);
139 }
140
usb_interface_request_queue(void * ctx,usb_request_t * usb_request,const usb_request_complete_t * complete_cb)141 static void usb_interface_request_queue(void* ctx, usb_request_t* usb_request,
142 const usb_request_complete_t* complete_cb) {
143 usb_interface_t* intf = ctx;
144 usb_request_queue(&intf->comp->usb, usb_request, complete_cb);
145 }
146
usb_interface_configure_batch_callback(void * ctx,uint8_t ep_address,const usb_batch_request_complete_t * complete_cb)147 static zx_status_t usb_interface_configure_batch_callback(void* ctx, uint8_t ep_address,
148 const usb_batch_request_complete_t*
149 complete_cb) {
150 usb_interface_t* intf = ctx;
151 return usb_configure_batch_callback(&intf->comp->usb, ep_address, complete_cb);
152 }
153
usb_interface_get_speed(void * ctx)154 static usb_speed_t usb_interface_get_speed(void* ctx) {
155 usb_interface_t* intf = ctx;
156 return usb_get_speed(&intf->comp->usb);
157 }
158
usb_interface_set_interface(void * ctx,uint8_t interface_number,uint8_t alt_setting)159 static zx_status_t usb_interface_set_interface(void* ctx, uint8_t interface_number,
160 uint8_t alt_setting) {
161 usb_interface_t* intf = ctx;
162 return usb_composite_set_interface(intf->comp, interface_number, alt_setting);
163 }
164
usb_interface_get_configuration(void * ctx)165 static uint8_t usb_interface_get_configuration(void* ctx) {
166 usb_interface_t* intf = ctx;
167 return usb_get_configuration(&intf->comp->usb);
168 }
169
usb_interface_set_configuration(void * ctx,uint8_t configuration)170 static zx_status_t usb_interface_set_configuration(void* ctx, uint8_t configuration) {
171 usb_interface_t* intf = ctx;
172 return usb_set_configuration(&intf->comp->usb, configuration);
173 }
174
usb_interface_enable_endpoint(void * ctx,const usb_endpoint_descriptor_t * ep_desc,const usb_ss_ep_comp_descriptor_t * ss_comp_desc,bool enable)175 static zx_status_t usb_interface_enable_endpoint(void* ctx,
176 const usb_endpoint_descriptor_t* ep_desc,
177 const usb_ss_ep_comp_descriptor_t* ss_comp_desc,
178 bool enable) {
179 return ZX_ERR_NOT_SUPPORTED;
180 }
181
usb_interface_reset_endpoint(void * ctx,uint8_t ep_address)182 static zx_status_t usb_interface_reset_endpoint(void* ctx, uint8_t ep_address) {
183 usb_interface_t* intf = ctx;
184 return usb_reset_endpoint(&intf->comp->usb, ep_address);
185 }
186
usb_interface_reset_device(void * ctx)187 static zx_status_t usb_interface_reset_device(void* ctx) {
188 usb_interface_t* intf = ctx;
189 return usb_reset_device(&intf->comp->usb);
190 }
191
usb_interface_get_max_transfer_size(void * ctx,uint8_t ep_address)192 static size_t usb_interface_get_max_transfer_size(void* ctx, uint8_t ep_address) {
193 usb_interface_t* intf = ctx;
194 return usb_get_max_transfer_size(&intf->comp->usb, ep_address);
195 }
196
usb_interface_get_device_id(void * ctx)197 static uint32_t usb_interface_get_device_id(void* ctx) {
198 usb_interface_t* intf = ctx;
199 return usb_get_device_id(&intf->comp->usb);
200 }
201
usb_interface_get_device_descriptor(void * ctx,usb_device_descriptor_t * out_desc)202 static void usb_interface_get_device_descriptor(void* ctx, usb_device_descriptor_t* out_desc) {
203 usb_interface_t* intf = ctx;
204 return usb_get_device_descriptor(&intf->comp->usb, out_desc);
205 }
206
usb_interface_get_configuration_descriptor_length(void * ctx,uint8_t configuration,size_t * out_length)207 zx_status_t usb_interface_get_configuration_descriptor_length(void* ctx, uint8_t configuration,
208 size_t* out_length) {
209 usb_interface_t* intf = ctx;
210 return usb_get_configuration_descriptor_length(&intf->comp->usb, configuration, out_length);
211 }
212
usb_interface_get_configuration_descriptor(void * ctx,uint8_t configuration,void * out_desc_buffer,size_t desc_size,size_t * out_desc_actual)213 static zx_status_t usb_interface_get_configuration_descriptor(void* ctx, uint8_t configuration,
214 void* out_desc_buffer,
215 size_t desc_size,
216 size_t* out_desc_actual) {
217 usb_interface_t* intf = ctx;
218 return usb_get_configuration_descriptor(&intf->comp->usb, configuration, out_desc_buffer,
219 desc_size, out_desc_actual);
220 }
221
usb_interface_get_descriptors_length(void * ctx)222 static size_t usb_interface_get_descriptors_length(void* ctx) {
223 usb_interface_t* intf = ctx;
224 return intf->descriptor_length;
225 }
226
usb_interface_get_descriptors(void * ctx,void * out_descs_buffer,size_t descs_size,size_t * out_descs_actual)227 static void usb_interface_get_descriptors(void* ctx, void* out_descs_buffer, size_t descs_size,
228 size_t* out_descs_actual) {
229 usb_interface_t* intf = ctx;
230 size_t length = intf->descriptor_length;
231 if (length > descs_size) {
232 length = descs_size;
233 }
234 memcpy(out_descs_buffer, intf->descriptor, length);
235 *out_descs_actual = length;
236 }
237
usb_interface_get_additional_descriptor_length(void * ctx)238 static size_t usb_interface_get_additional_descriptor_length(void* ctx) {
239 usb_interface_t* intf = ctx;
240
241 usb_composite_t* comp = intf->comp;
242 usb_configuration_descriptor_t* config = comp->config_desc;
243 usb_descriptor_header_t* header = NEXT_DESCRIPTOR(config);
244 usb_descriptor_header_t* end = (usb_descriptor_header_t*)((void*)config +
245 le16toh(config->wTotalLength));
246
247 usb_interface_descriptor_t* result = NULL;
248 while (header < end) {
249 if (header->bDescriptorType == USB_DT_INTERFACE) {
250 usb_interface_descriptor_t* test_intf = (usb_interface_descriptor_t*)header;
251 // We are only interested in descriptors past the last stored descriptor
252 // for the current interface.
253 if (test_intf->bAlternateSetting == 0 &&
254 test_intf->bInterfaceNumber > intf->last_interface_id) {
255 result = test_intf;
256 break;
257 }
258 }
259 header = NEXT_DESCRIPTOR(header);
260 }
261 if (!result) {
262 return 0;
263 }
264 return (uint8_t*)end - (uint8_t*)result;
265 }
266
usb_interface_get_additional_descriptor_list(void * ctx,uint8_t * out_desc_list,size_t desc_count,size_t * out_desc_actual)267 static zx_status_t usb_interface_get_additional_descriptor_list(void* ctx, uint8_t* out_desc_list,
268 size_t desc_count,
269 size_t* out_desc_actual) {
270 usb_interface_t* intf = ctx;
271 *out_desc_actual = 0;
272
273 usb_composite_t* comp = intf->comp;
274 usb_configuration_descriptor_t* config = comp->config_desc;
275 usb_descriptor_header_t* header = NEXT_DESCRIPTOR(config);
276 usb_descriptor_header_t* end = (usb_descriptor_header_t*)((void*)config +
277 le16toh(config->wTotalLength));
278
279 usb_interface_descriptor_t* result = NULL;
280 while (header < end) {
281 if (header->bDescriptorType == USB_DT_INTERFACE) {
282 usb_interface_descriptor_t* test_intf = (usb_interface_descriptor_t*)header;
283 // We are only interested in descriptors past the last stored descriptor
284 // for the current interface.
285 if (test_intf->bAlternateSetting == 0 &&
286 test_intf->bInterfaceNumber > intf->last_interface_id) {
287 result = test_intf;
288 break;
289 }
290 }
291 header = NEXT_DESCRIPTOR(header);
292 }
293 if (!result) {
294 return ZX_OK;
295 }
296 size_t length = (void*)end - (void*)result;
297 if (length > desc_count) {
298 return ZX_ERR_BUFFER_TOO_SMALL;
299 }
300 memcpy(out_desc_list, result, length);
301 *out_desc_actual = length;
302 return ZX_OK;
303 }
304
usb_interface_get_string_descriptor(void * ctx,uint8_t desc_id,uint16_t lang_id,uint16_t * out_lang_id,void * out_string_buffer,size_t string_size,size_t * out_string_actual)305 zx_status_t usb_interface_get_string_descriptor(void* ctx, uint8_t desc_id, uint16_t lang_id,
306 uint16_t* out_lang_id, void* out_string_buffer,
307 size_t string_size, size_t* out_string_actual) {
308 usb_interface_t* intf = ctx;
309 return usb_get_string_descriptor(&intf->comp->usb, desc_id, lang_id, out_lang_id,
310 out_string_buffer, string_size, out_string_actual);
311 }
312
usb_interface_claim_device_interface(void * ctx,const usb_interface_descriptor_t * desc,uint32_t claim_length)313 static zx_status_t usb_interface_claim_device_interface(void* ctx,
314 const usb_interface_descriptor_t* desc,
315 uint32_t claim_length) {
316 usb_interface_t* intf = ctx;
317
318 zx_status_t status = usb_composite_do_claim_interface(intf->comp, desc->bInterfaceNumber);
319 if (status != ZX_OK) {
320 return status;
321 }
322 // Copy claimed interface descriptors to end of descriptor array.
323 void* descriptors = realloc(intf->descriptor,
324 intf->descriptor_length + claim_length);
325 if (!descriptors) {
326 return ZX_ERR_NO_MEMORY;
327 }
328 memcpy(descriptors + intf->descriptor_length, desc, claim_length);
329 intf->descriptor = descriptors;
330 intf->descriptor_length += claim_length;
331
332 if (desc->bInterfaceNumber > intf->last_interface_id) {
333 intf->last_interface_id = desc->bInterfaceNumber;
334 }
335 return ZX_OK;
336 }
337
usb_interface_cancel_all(void * ctx,uint8_t ep_address)338 static zx_status_t usb_interface_cancel_all(void* ctx, uint8_t ep_address) {
339 usb_interface_t* intf = ctx;
340 return usb_cancel_all(&intf->comp->usb, ep_address);
341 }
342
usb_interface_get_current_frame(void * ctx)343 static uint64_t usb_interface_get_current_frame(void* ctx) {
344 usb_interface_t* intf = ctx;
345 return usb_get_current_frame(&intf->comp->usb);
346 }
347
usb_interface_get_request_size(void * ctx)348 static size_t usb_interface_get_request_size(void* ctx) {
349 usb_interface_t* intf = ctx;
350 return usb_get_request_size(&intf->comp->usb);
351 }
352
353 usb_protocol_ops_t usb_device_protocol = {
354 .control_out = usb_interface_control_out,
355 .control_in = usb_interface_control_in,
356 .request_queue = usb_interface_request_queue,
357 .configure_batch_callback = usb_interface_configure_batch_callback,
358 .get_speed = usb_interface_get_speed,
359 .set_interface = usb_interface_set_interface,
360 .get_configuration = usb_interface_get_configuration,
361 .set_configuration = usb_interface_set_configuration,
362 .enable_endpoint = usb_interface_enable_endpoint,
363 .reset_endpoint = usb_interface_reset_endpoint,
364 .reset_device = usb_interface_reset_device,
365 .get_max_transfer_size = usb_interface_get_max_transfer_size,
366 .get_device_id = usb_interface_get_device_id,
367 .get_device_descriptor = usb_interface_get_device_descriptor,
368 .get_configuration_descriptor_length = usb_interface_get_configuration_descriptor_length,
369 .get_configuration_descriptor = usb_interface_get_configuration_descriptor,
370 .get_descriptors_length = usb_interface_get_descriptors_length,
371 .get_descriptors = usb_interface_get_descriptors,
372 .get_string_descriptor = usb_interface_get_string_descriptor,
373 .cancel_all = usb_interface_cancel_all,
374 .get_current_frame = usb_interface_get_current_frame,
375 .get_request_size = usb_interface_get_request_size,
376 };
377
378 usb_composite_protocol_ops_t usb_composite_device_protocol = {
379 .get_additional_descriptor_length = usb_interface_get_additional_descriptor_length,
380 .get_additional_descriptor_list = usb_interface_get_additional_descriptor_list,
381 .claim_interface = usb_interface_claim_device_interface,
382 };
383
usb_interface_contains_interface(usb_interface_t * intf,uint8_t interface_id)384 bool usb_interface_contains_interface(usb_interface_t* intf, uint8_t interface_id) {
385 usb_descriptor_header_t* header = intf->descriptor;
386 usb_descriptor_header_t* end = (usb_descriptor_header_t*)((void*)header +
387 intf->descriptor_length);
388
389 while (header < end) {
390 if (header->bDescriptorType == USB_DT_INTERFACE) {
391 usb_interface_descriptor_t* intf_desc = (usb_interface_descriptor_t*)header;
392 if (intf_desc->bInterfaceNumber == interface_id) {
393 return true;
394 }
395 }
396 header = NEXT_DESCRIPTOR(header);
397 }
398 return false;
399 }
400
usb_interface_set_alt_setting(usb_interface_t * intf,uint8_t interface_id,uint8_t alt_setting)401 zx_status_t usb_interface_set_alt_setting(usb_interface_t* intf, uint8_t interface_id,
402 uint8_t alt_setting) {
403 zx_status_t status = usb_interface_configure_endpoints(intf, interface_id, alt_setting);
404 if (status != ZX_OK) {
405 return status;
406 }
407
408 return usb_control_out(&intf->comp->usb, USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE,
409 USB_REQ_SET_INTERFACE, alt_setting, interface_id, ZX_TIME_INFINITE,
410 NULL, 0);
411 }
412