• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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