1 /*
2 * Copyright (c) 2021 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 /*---------------------------------------------------------------------
9 * Includes
10 *---------------------------------------------------------------------
11 */
12 #include "hpm_usb_host.h"
13 #include "hpm_misc.h"
14 #include "hpm_common.h"
15 #include "board.h"
16
17 /*---------------------------------------------------------------------
18 * Macros
19 *---------------------------------------------------------------------
20 */
21
22 #define USB_QHD_TYP_SHIFT (1U)
23
24 #define USB_PERIOD_1MS (1U)
25 #define USB_PERIOD_2MS (2U)
26 #define USB_PERIOD_4MS (4U)
27 #define USB_PERIOD_8MS (8U)
28
29 #define USB_DEFAULT_ADDR (0U)
30 #define USB_HIGH_SPPED_INTERVAL_MAX (16)
31 #define USB_SETUP_PACKET_LEN (8U)
32
33 #define USB_BIN8(x) ((uint8_t) (0b##x))
34 #define USB_BIN16(b1, b2) ((uint16_t) (0b##b1##b2))
35 #define USB_BIN32(b1, b2, b3, b4) ((uint32_t) (0b##b1##b2##b3##b4))
36
37 /* helper functions */
usb_log2(uint32_t value)38 static uint8_t usb_log2(uint32_t value)
39 {
40 uint8_t result = 0;
41
42 while (value >>= 1) {
43 result++;
44 }
45
46 return result;
47 }
48
49 /*****************************************************************************/
50 /* list functions */
51 /*****************************************************************************/
usb_host_list_insert(hcd_link_t * current,hcd_link_t * new,uint8_t new_type)52 static void usb_host_list_insert(hcd_link_t *current, hcd_link_t *new, uint8_t new_type)
53 {
54 new->address = current->address;
55 current->address = core_local_mem_to_sys_address(USB_HOST_MCU_CORE, (uint32_t)new) | (new_type << USB_QHD_TYP_SHIFT);
56 }
57
usb_host_list_remove_qhd_by_addr(hcd_link_t * list_head,uint8_t dev_addr)58 static void usb_host_list_remove_qhd_by_addr(hcd_link_t *list_head, uint8_t dev_addr)
59 {
60 hcd_qhd_t *qhd;
61
62 for (hcd_link_t *prev = list_head;
63 !prev->terminate && (sys_address_to_core_local_mem(USB_HOST_MCU_CORE, usb_host_align32(prev->address)) != (uint32_t)list_head);
64 prev = (hcd_link_t *)sys_address_to_core_local_mem(USB_HOST_MCU_CORE, (uint32_t)usb_host_list_next(prev))) {
65
66 /* TODO check type for ISO iTD and siTD */
67 qhd = (hcd_qhd_t *)sys_address_to_core_local_mem(USB_HOST_MCU_CORE, (uint32_t)usb_host_list_next(prev));
68
69 if (qhd->dev_addr == dev_addr) {
70 /* TODO deactive all TD, wait for QHD to inactive before removal */
71 prev->address = qhd->next.address;
72
73 /* EHCI link the removed qhd to async head (which always reachable by Host Controller) */
74 qhd->next.address = core_local_mem_to_sys_address(USB_HOST_MCU_CORE, (uint32_t)list_head) | (usb_qtype_qhd << USB_QHD_TYP_SHIFT);
75
76 if (qhd->int_smask) {
77 /* period list queue element is guarantee to be free in the next frame (1 ms) */
78 qhd->used = 0;
79 } else {
80 /* async list use async advance handshake */
81 /* mark as removing, will completely re-usable when async advance isr occurs */
82 qhd->removing = 1;
83 }
84 }
85 }
86 }
87
usb_host_list_next(hcd_link_t * p_link_pointer)88 hcd_link_t *usb_host_list_next(hcd_link_t *p_link_pointer)
89 {
90 return (hcd_link_t *)usb_host_align32(p_link_pointer->address);
91 }
92
93 /*************************************************************/
94 /* qhd functions */
95 /*************************************************************/
usb_host_qhd_control(usb_host_handle_t * handle,uint8_t dev_addr)96 static hcd_qhd_t *usb_host_qhd_control(usb_host_handle_t *handle, uint8_t dev_addr)
97 {
98 return &handle->hcd_data->control[dev_addr].qhd;
99 }
100
usb_host_qhd_next(hcd_qhd_t const * p_qhd)101 hcd_qhd_t *usb_host_qhd_next(hcd_qhd_t const *p_qhd)
102 {
103 return (hcd_qhd_t *)usb_host_align32(p_qhd->next.address);
104 }
105
usb_host_qhd_find_free(usb_host_handle_t * handle)106 static hcd_qhd_t *usb_host_qhd_find_free(usb_host_handle_t *handle)
107 {
108 for (uint32_t i = 0; i < USB_HCD_MAX_QHD_COUNT; i++) {
109 if (!handle->hcd_data->qhd_pool[i].used) {
110 return &handle->hcd_data->qhd_pool[i];
111 }
112 }
113
114 return NULL;
115 }
116
usb_host_qhd_get_from_addr(usb_host_handle_t * handle,uint8_t dev_addr,uint8_t ep_addr)117 static hcd_qhd_t *usb_host_qhd_get_from_addr(usb_host_handle_t *handle, uint8_t dev_addr, uint8_t ep_addr)
118 {
119 hcd_qhd_t *qhd_pool = handle->hcd_data->qhd_pool;
120
121 for (uint32_t i = 0; i < USB_HCD_MAX_QHD_COUNT; i++) {
122 if ((qhd_pool[i].dev_addr == dev_addr) &&
123 ep_addr == usb_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid)) {
124 return &qhd_pool[i];
125 }
126 }
127
128 return NULL;
129 }
130
usb_host_qhd_init(usb_host_handle_t * handle,hcd_qhd_t * p_qhd,uint8_t dev_addr,usb_desc_endpoint_t const * ep_desc)131 static bool usb_host_qhd_init(usb_host_handle_t *handle, hcd_qhd_t *p_qhd, uint8_t dev_addr, usb_desc_endpoint_t const *ep_desc)
132 {
133 uint8_t const xfer_type = ep_desc->bmAttributes.xfer;
134 uint8_t const interval = ep_desc->bInterval;
135
136 /* address 0 is used as async head, which always on the list --> cannot be cleared (ehci halted otherwise) */
137 if (dev_addr != 0) {
138 memset(p_qhd, 0, sizeof(hcd_qhd_t));
139 }
140
141 p_qhd->dev_addr = dev_addr;
142 p_qhd->fl_inactive_next_xact = 0;
143 p_qhd->ep_number = usb_edpt_number(ep_desc->bEndpointAddress);
144 p_qhd->ep_speed = handle->ep_speed;
145 p_qhd->data_toggle_control = (xfer_type == usb_xfer_control) ? 1 : 0;
146 p_qhd->head_list_flag = (dev_addr == USB_DEFAULT_ADDR) ? 1 : 0; /* addr0's endpoint is the static async list head */
147 p_qhd->max_packet_size = ep_desc->wMaxPacketSize.size;
148 p_qhd->fl_ctrl_ep_flag = ((xfer_type == usb_xfer_control) && (p_qhd->ep_speed != usb_speed_high)) ? 1 : 0;
149 p_qhd->nak_reload = 0;
150
151 if (usb_xfer_interrupt == xfer_type) {
152 if (usb_speed_high == p_qhd->ep_speed) {
153 if (interval > USB_HIGH_SPPED_INTERVAL_MAX) {
154 return false;
155 }
156
157 if (interval < 4) { /* sub millisecond interval */
158 p_qhd->interval_ms = 0;
159 p_qhd->int_smask = (interval == 1) ? USB_BIN8(11111111) :
160 (interval == 2) ? USB_BIN8(10101010) : USB_BIN8(01000100);
161 } else {
162 p_qhd->interval_ms = (uint8_t)MIN(1 << (interval - 4), 255);
163 p_qhd->int_smask = HPM_BITSMASK(1, interval % 8);
164 }
165 } else {
166 if (interval == 0) {
167 return false;
168 }
169
170 /* Full/Low:(EHCI) case 1 schedule start split at 1 us & complete split at 2,3,4 uframes */
171 p_qhd->int_smask = 0x01;
172 p_qhd->fl_int_cmask = USB_BIN8(11100);
173 p_qhd->interval_ms = interval;
174 }
175 } else {
176 /* Bulk/Control -> smask = cmask = 0 */
177 p_qhd->int_smask = p_qhd->fl_int_cmask = 0;
178 }
179
180 p_qhd->fl_hub_addr = handle->hub_addr;
181 p_qhd->fl_hub_port = handle->hub_port;
182 p_qhd->mult = 1;
183
184 /* HCD Management Data */
185 p_qhd->used = 1;
186 p_qhd->removing = 0;
187 p_qhd->p_qtd_list_head = NULL;
188 p_qhd->p_qtd_list_tail = NULL;
189 p_qhd->pid = usb_edpt_dir(ep_desc->bEndpointAddress) ? usb_pid_in : usb_pid_out; /* PID for TD under this endpoint */
190
191 /* Active, but no TD list */
192 p_qhd->qtd_overlay.halted = 0;
193 p_qhd->qtd_overlay.next.terminate = 1;
194 p_qhd->qtd_overlay.alternate.terminate = 1;
195
196 if (usb_xfer_bulk == xfer_type && p_qhd->ep_speed == usb_speed_high && p_qhd->pid == usb_pid_out) {
197 p_qhd->qtd_overlay.ping_err = 1; /* Do PING for Highspeed Bulk OUT, EHCI */
198 }
199
200 return true;
201 }
202
usb_host_qhd_async_head(usb_host_handle_t * handle)203 hcd_qhd_t *usb_host_qhd_async_head(usb_host_handle_t *handle)
204 {
205 /* control qhd of dev0 is used as async head */
206 return usb_host_qhd_control(handle, 0);
207 }
208
usb_host_qhd_has_xact_error(hcd_qhd_t * p_qhd)209 bool usb_host_qhd_has_xact_error(hcd_qhd_t *p_qhd)
210 {
211 return (p_qhd->qtd_overlay.buffer_err || p_qhd->qtd_overlay.babble_err || p_qhd->qtd_overlay.xact_err);
212 }
213
usb_host_get_period_head(usb_host_handle_t * handle,uint8_t interval_ms)214 hcd_link_t *usb_host_get_period_head(usb_host_handle_t *handle, uint8_t interval_ms)
215 {
216 return (hcd_link_t *)&handle->hcd_data->period_head_arr[usb_log2(MIN(USB_HOST_FRAMELIST_SIZE, interval_ms))];
217 }
218
219 /*************************************************************/
220 /* qtd functions */
221 /*************************************************************/
usb_host_qtd_find_free(usb_host_handle_t * handle)222 static hcd_qtd_t *usb_host_qtd_find_free(usb_host_handle_t *handle)
223 {
224 for (uint32_t i = 0; i < USB_HCD_MAX_QTD_COUNT; i++) {
225 if (!handle->hcd_data->qtd_pool[i].used) {
226 return &handle->hcd_data->qtd_pool[i];
227 }
228 }
229
230 return NULL;
231 }
232
usb_host_qtd_next(hcd_qtd_t const * p_qtd)233 static hcd_qtd_t *usb_host_qtd_next(hcd_qtd_t const *p_qtd)
234 {
235 return (hcd_qtd_t *)usb_host_align32(p_qtd->next.address);
236 }
237
usb_host_qtd_insert_to_qhd(hcd_qhd_t * p_qhd,hcd_qtd_t * p_qtd_new)238 static void usb_host_qtd_insert_to_qhd(hcd_qhd_t *p_qhd, hcd_qtd_t *p_qtd_new)
239 {
240 if (p_qhd->p_qtd_list_head == NULL) { /* empty list */
241 p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = p_qtd_new;
242 } else {
243 p_qhd->p_qtd_list_tail->next.address = (uint32_t)p_qtd_new;
244 p_qhd->p_qtd_list_tail = p_qtd_new;
245 }
246 }
247
usb_host_qtd_init(hcd_qtd_t * p_qtd,void * buffer,uint16_t total_bytes)248 static void usb_host_qtd_init(hcd_qtd_t *p_qtd, void *buffer, uint16_t total_bytes)
249 {
250 memset(p_qtd, 0, sizeof(hcd_qtd_t));
251
252 p_qtd->used = 1;
253 p_qtd->next.terminate = 1; /* init to null */
254 p_qtd->alternate.terminate = 1; /* not used, always set to terminated */
255 p_qtd->active = 1;
256 p_qtd->err_count = 3;
257 p_qtd->data_toggle = 0;
258 p_qtd->total_bytes = total_bytes;
259 p_qtd->expected_bytes = total_bytes;
260
261 if (buffer != NULL) {
262 p_qtd->buffer[0] = (uint32_t)buffer;
263
264 for (uint8_t i = 1; i < USB_SOC_HCD_QTD_BUFFER_COUNT; i++) {
265 p_qtd->buffer[i] |= usb_host_align4k(p_qtd->buffer[i-1]) + 4096UL;
266 }
267 }
268 }
269
usb_host_qtd_remove_1st_from_qhd(hcd_qhd_t * p_qhd)270 void usb_host_qtd_remove_1st_from_qhd(hcd_qhd_t *p_qhd)
271 {
272 if (p_qhd->p_qtd_list_head == p_qhd->p_qtd_list_tail) { /* last TD --> make it NULL */
273 p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = NULL;
274 } else {
275 p_qhd->p_qtd_list_head = usb_host_qtd_next(p_qhd->p_qtd_list_head);
276 }
277 }
278
usb_host_qtd_control(usb_host_handle_t * handle,uint8_t dev_addr)279 hcd_qtd_t *usb_host_qtd_control(usb_host_handle_t *handle, uint8_t dev_addr)
280 {
281 return &handle->hcd_data->control[dev_addr].qtd;
282 }
283
usb_host_init_async_list(usb_host_handle_t * handle)284 static void usb_host_init_async_list(usb_host_handle_t *handle)
285 {
286 hcd_qhd_t *async_head = usb_host_qhd_async_head(handle);
287
288 memset(async_head, 0, sizeof(hcd_qhd_t));
289
290 async_head->next.address = core_local_mem_to_sys_address(USB_HOST_MCU_CORE, (uint32_t)async_head); /* circular list, next is itself */
291 async_head->next.type = usb_qtype_qhd;
292 async_head->head_list_flag = 1;
293 async_head->qtd_overlay.halted = 1;
294 async_head->qtd_overlay.next.terminate = 1;
295
296 usb_hcd_set_async_list_addr(handle->regs, core_local_mem_to_sys_address(USB_HOST_MCU_CORE, (uint32_t)async_head));
297 }
298
usb_host_init_periodic_list(usb_host_handle_t * handle)299 static void usb_host_init_periodic_list(usb_host_handle_t *handle)
300 {
301 hcd_link_t *framelist;
302 hcd_link_t *period_1ms;
303
304 /* Build the polling interval tree with 1 ms, 2 ms, 4 ms and 8 ms (framesize) only */
305 for (uint32_t i = 0; i < 4; i++) {
306 handle->hcd_data->period_head_arr[i].int_smask = 1; /* queue head in period list must have non-zero smask */
307 handle->hcd_data->period_head_arr[i].qtd_overlay.halted = 1; /* dummy node, always inactive */
308 }
309
310 framelist = handle->hcd_data->period_framelist;
311 period_1ms = usb_host_get_period_head(handle, USB_PERIOD_1MS);
312
313 /* all links --> period_head_arr[0] (1ms)
314 * 0, 2, 4, 6 etc --> period_head_arr[1] (2ms)
315 * 1, 5 --> period_head_arr[2] (4ms)
316 * 3 --> period_head_arr[3] (8ms)
317 */
318 for (uint32_t i = 0; i < USB_HOST_FRAMELIST_SIZE; i++) {
319 framelist[i].address = core_local_mem_to_sys_address(USB_HOST_MCU_CORE, (uint32_t)period_1ms);
320 framelist[i].type = usb_qtype_qhd;
321 }
322
323 for (uint32_t i = 0; i < USB_HOST_FRAMELIST_SIZE; i += 2) {
324 usb_host_list_insert(framelist + i, usb_host_get_period_head(handle, USB_PERIOD_2MS), usb_qtype_qhd);
325 }
326
327 for (uint32_t i = 1; i < USB_HOST_FRAMELIST_SIZE; i += 4) {
328 usb_host_list_insert(framelist + i, usb_host_get_period_head(handle, USB_PERIOD_4MS), usb_qtype_qhd);
329 }
330
331 for (uint32_t i = 3; i < USB_HOST_FRAMELIST_SIZE; i += 8) {
332 usb_host_list_insert(framelist + i, usb_host_get_period_head(handle, USB_PERIOD_8MS), usb_qtype_qhd);
333 }
334
335 period_1ms->terminate = 1;
336
337 usb_hcd_set_periodic_list_addr(handle->regs, core_local_mem_to_sys_address(USB_HOST_MCU_CORE, (uint32_t)framelist));
338 }
339
340 /* enable vbus output */
usb_host_vbus_ctrl(usb_host_handle_t * handle)341 static void usb_host_vbus_ctrl(usb_host_handle_t *handle)
342 {
343 handle->hcd_vbus_ctrl_cb(handle->rhport, 1);
344 }
345
usb_host_init(usb_host_handle_t * handle,uint32_t int_mask,uint16_t framelist_size)346 bool usb_host_init(usb_host_handle_t *handle, uint32_t int_mask, uint16_t framelist_size)
347 {
348 usb_hcd_init(handle->regs, int_mask, framelist_size);
349 memset(handle->hcd_data, 0, sizeof(hcd_data_t));
350 usb_host_init_async_list(handle);
351 usb_host_init_periodic_list(handle);
352 usb_host_vbus_ctrl(handle);
353 usb_hcd_run(handle->regs);
354 usb_hcd_enable_port_power(handle->regs);
355 return true;
356 }
357
usb_host_port_reset(usb_host_handle_t * handle)358 void usb_host_port_reset(usb_host_handle_t *handle)
359 {
360 usb_hcd_port_reset(handle->regs);
361 }
362
usb_host_uframe_number(usb_host_handle_t * handle)363 uint32_t usb_host_uframe_number(usb_host_handle_t *handle)
364 {
365 return handle->hcd_data->uframe_number + usb_hcd_get_frame_index(handle->regs);
366 }
367
usb_host_get_port_ccs(usb_host_handle_t * handle)368 bool usb_host_get_port_ccs(usb_host_handle_t *handle)
369 {
370 return usb_get_port_ccs(handle->regs);
371 }
372
usb_host_port_csc(usb_host_handle_t * handle)373 bool usb_host_port_csc(usb_host_handle_t *handle)
374 {
375 return usb_hcd_get_port_csc(handle->regs);
376 }
377
usb_host_status_flags(usb_host_handle_t * handle)378 uint32_t usb_host_status_flags(usb_host_handle_t *handle)
379 {
380 return usb_get_status_flags(handle->regs);
381 }
382
usb_host_interrupts(usb_host_handle_t * handle)383 uint32_t usb_host_interrupts(usb_host_handle_t *handle)
384 {
385 return usb_get_interrupts(handle->regs);
386 }
387
usb_host_clear_status_flags(usb_host_handle_t * handle,uint32_t status)388 void usb_host_clear_status_flags(usb_host_handle_t *handle, uint32_t status)
389 {
390 usb_clear_status_flags(handle->regs, status);
391 }
392
usb_host_get_port_speed(usb_host_handle_t * handle)393 uint8_t usb_host_get_port_speed(usb_host_handle_t *handle)
394 {
395 return usb_get_port_speed(handle->regs);
396 }
397
398 /* Close all opened endpoint belong to this device */
usb_host_device_close(usb_host_handle_t * handle,uint8_t dev_addr)399 void usb_host_device_close(usb_host_handle_t *handle, uint8_t dev_addr)
400 {
401 /* skip dev0 */
402 if (dev_addr == USB_DEFAULT_ADDR) {
403 return;
404 }
405
406 /* Remove from async list */
407 usb_host_list_remove_qhd_by_addr((hcd_link_t *) usb_host_qhd_async_head(handle), dev_addr);
408
409 /* Remove from all interval period list */
410 for (uint8_t i = 0; i < ARRAY_SIZE(handle->hcd_data->period_head_arr); i++) {
411 usb_host_list_remove_qhd_by_addr((hcd_link_t *)&handle->hcd_data->period_head_arr[i], dev_addr);
412 }
413
414 /* Async doorbell (EHCI for operational details) */
415 usb_hcd_set_command(handle->regs, USB_USBCMD_IAA_MASK);
416 }
417
418 /*---------------------------------------------------------------------
419 * Control Pipe API
420 *---------------------------------------------------------------------
421 */
usb_host_edpt_xfer(usb_host_handle_t * handle,uint8_t dev_addr,uint8_t ep_addr,uint8_t * buffer,uint16_t buflen)422 bool usb_host_edpt_xfer(usb_host_handle_t *handle, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen)
423 {
424 uint8_t const epnum = usb_edpt_number(ep_addr);
425 uint8_t const dir = usb_edpt_dir(ep_addr);
426 hcd_qhd_t *qhd;
427 hcd_qtd_t *qtd;
428 hcd_qhd_t *p_qhd;
429 hcd_qtd_t *p_qtd;
430
431 if (buffer != NULL) {
432 buffer = (uint8_t *)core_local_mem_to_sys_address(USB_HOST_MCU_CORE, (uint32_t)buffer);
433 }
434
435 if (epnum == 0) {
436 qhd = usb_host_qhd_control(handle, dev_addr);
437 qtd = usb_host_qtd_control(handle, dev_addr);
438
439 usb_host_qtd_init(qtd, buffer, buflen);
440
441 /* first first data toggle is always 1 (data & setup stage) */
442 qtd->data_toggle = 1;
443 qtd->pid = dir ? usb_pid_in : usb_pid_out;
444
445 qtd->int_on_complete = 1;
446 qtd->next.terminate = 1;
447
448 /* sw region */
449 qhd->p_qtd_list_head = qtd;
450 qhd->p_qtd_list_tail = qtd;
451
452 /* attach TD */
453 qhd->qtd_overlay.next.address = core_local_mem_to_sys_address(USB_HOST_MCU_CORE, (uint32_t)qtd);
454 } else {
455 p_qhd = usb_host_qhd_get_from_addr(handle, dev_addr, ep_addr);
456 p_qtd = usb_host_qtd_find_free(handle);
457
458 if (p_qhd == NULL || p_qtd == NULL) {
459 return false;
460 }
461
462 usb_host_qtd_init(p_qtd, buffer, buflen);
463 p_qtd->pid = p_qhd->pid;
464
465 /* Insert TD to QH */
466 usb_host_qtd_insert_to_qhd(p_qhd, p_qtd);
467 p_qhd->p_qtd_list_tail->int_on_complete = 1;
468
469 /* attach head QTD to QHD start transferring */
470 p_qhd->qtd_overlay.next.address = core_local_mem_to_sys_address(USB_HOST_MCU_CORE, (uint32_t)p_qhd->p_qtd_list_head);
471 }
472
473 return true;
474 }
475
usb_host_setup_send(usb_host_handle_t * handle,uint8_t dev_addr,const uint8_t * setup_packet)476 bool usb_host_setup_send(usb_host_handle_t *handle, uint8_t dev_addr, const uint8_t *setup_packet)
477 {
478 uint32_t *p = NULL;
479
480 hcd_qhd_t *qhd = &handle->hcd_data->control[dev_addr].qhd;
481 hcd_qtd_t *td = &handle->hcd_data->control[dev_addr].qtd;
482
483 if (setup_packet != NULL) {
484 p = (uint32_t *)core_local_mem_to_sys_address(USB_HOST_MCU_CORE, (uint32_t)setup_packet);
485 }
486
487 usb_host_qtd_init(td, (void *)p, USB_SETUP_PACKET_LEN);
488 td->pid = usb_pid_setup;
489 td->int_on_complete = 1;
490 td->next.terminate = 1;
491
492 /* sw region */
493 qhd->p_qtd_list_head = td;
494 qhd->p_qtd_list_tail = td;
495
496 /* attach TD */
497 qhd->qtd_overlay.next.address = core_local_mem_to_sys_address(USB_HOST_MCU_CORE, (uint32_t)td);
498
499 return true;
500 }
501
usb_host_edpt_open(usb_host_handle_t * handle,uint8_t dev_addr,usb_desc_endpoint_t const * ep_desc)502 bool usb_host_edpt_open(usb_host_handle_t *handle, uint8_t dev_addr, usb_desc_endpoint_t const *ep_desc)
503 {
504 hcd_qhd_t *p_qhd = NULL;
505 hcd_link_t *list_head = NULL;
506
507 if (ep_desc->bmAttributes.xfer == usb_xfer_isochronous) {
508 return false;
509 }
510
511 /* Prepare Queue Head */
512 if (ep_desc->bEndpointAddress == 0) {
513 p_qhd = usb_host_qhd_control(handle, dev_addr);
514 } else {
515 p_qhd = usb_host_qhd_find_free(handle);
516 }
517
518 /* Initialize Qhd */
519 usb_host_qhd_init(handle, p_qhd, dev_addr, ep_desc);
520
521 switch (ep_desc->bmAttributes.xfer) {
522 case usb_xfer_control:
523 case usb_xfer_bulk:
524 list_head = (hcd_link_t *)usb_host_qhd_async_head(handle); /* control of dev0 is always present as async head */
525 break;
526
527 case usb_xfer_interrupt:
528 list_head = usb_host_get_period_head(handle, p_qhd->interval_ms);
529 break;
530
531 case usb_xfer_isochronous:
532 break;
533
534 default:
535 break;
536 }
537
538 /* Insert to list */
539 usb_host_list_insert(list_head, (hcd_link_t *)p_qhd, usb_qtype_qhd);
540
541 return true;
542 }
543
usb_host_pipe_queue_xfer(usb_host_handle_t * handle,uint8_t dev_addr,uint8_t ep_addr,uint8_t buffer[],uint16_t total_bytes)544 bool usb_host_pipe_queue_xfer(usb_host_handle_t *handle, uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes)
545 {
546 hcd_qhd_t *p_qhd = usb_host_qhd_get_from_addr(handle, dev_addr, ep_addr);
547 hcd_qtd_t *p_qtd = usb_host_qtd_find_free(handle);
548
549 if (p_qhd == NULL || p_qtd == NULL) {
550 return false;
551 }
552
553 /* Initialize QTD */
554 usb_host_qtd_init(p_qtd, buffer, total_bytes);
555 p_qtd->pid = p_qhd->pid;
556
557 /* Insert TD to TD list */
558 usb_host_qtd_insert_to_qhd(p_qhd, p_qtd);
559
560 return true;
561 }
562
usb_host_pipe_xfer(usb_host_handle_t * handle,uint8_t dev_addr,uint8_t ep_addr,uint8_t buffer[],uint16_t total_bytes,bool int_on_complete)563 bool usb_host_pipe_xfer(usb_host_handle_t *handle, uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete)
564 {
565 hcd_qhd_t *p_qhd = usb_host_qhd_get_from_addr(handle, dev_addr, ep_addr);
566
567 if (usb_host_pipe_queue_xfer(handle, dev_addr, ep_addr, buffer, total_bytes) == false) {
568 return false;
569 }
570
571 if (int_on_complete) {
572 /* the just added qtd is pointed by list_tail */
573 p_qhd->p_qtd_list_tail->int_on_complete = 1;
574 }
575
576 /* attach head QTD to QHD start transferring */
577 p_qhd->qtd_overlay.next.address = core_local_mem_to_sys_address(USB_HOST_MCU_CORE, (uint32_t)p_qhd->p_qtd_list_head);
578
579 return true;
580 }
581
usb_host_edpt_busy(usb_host_handle_t * handle,uint8_t dev_addr,uint8_t ep_addr)582 bool usb_host_edpt_busy(usb_host_handle_t *handle, uint8_t dev_addr, uint8_t ep_addr)
583 {
584 hcd_qhd_t *p_qhd = usb_host_qhd_get_from_addr(handle, dev_addr, ep_addr);
585
586 return ((!p_qhd->qtd_overlay.halted) && (p_qhd->p_qtd_list_head != NULL));
587 }
588
usb_host_edpt_stalled(usb_host_handle_t * handle,uint8_t dev_addr,uint8_t ep_addr)589 bool usb_host_edpt_stalled(usb_host_handle_t *handle, uint8_t dev_addr, uint8_t ep_addr)
590 {
591 hcd_qhd_t *p_qhd = usb_host_qhd_get_from_addr(handle, dev_addr, ep_addr);
592
593 return p_qhd->qtd_overlay.halted && !usb_host_qhd_has_xact_error(p_qhd);
594 }
595
usb_host_edpt_clear_stall(usb_host_handle_t * handle,uint8_t dev_addr,uint8_t ep_addr)596 bool usb_host_edpt_clear_stall(usb_host_handle_t *handle, uint8_t dev_addr, uint8_t ep_addr)
597 {
598 hcd_qhd_t *p_qhd = usb_host_qhd_get_from_addr(handle, dev_addr, ep_addr);
599
600 p_qhd->qtd_overlay.halted = 0;
601
602 return true;
603 }
604