1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** USBX Component */
17 /** */
18 /** EHCI Controller Driver */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23
24 /* Include necessary system files. */
25
26 #define UX_SOURCE_CODE
27
28 #include "ux_api.h"
29 #include "ux_hcd_ehci.h"
30 #include "ux_host_stack.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_hcd_ehci_request_transfer_add PORTABLE C */
38 /* 6.1 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function adds a component of a transfer to an existing ED. */
46 /* */
47 /* INPUT */
48 /* */
49 /* hcd_ehci Pointer to EHCI controller */
50 /* ed Pointer to the ED */
51 /* phase Phase (for control transfers) */
52 /* pid PID to be used with this */
53 /* request (SETUP,IN,OUT) */
54 /* toggle Toggle value 0 or 1 */
55 /* buffer_address Buffer address for transfer */
56 /* buffer_length Buffer length */
57 /* transfer_request Pointer to transfer request */
58 /* */
59 /* OUTPUT */
60 /* */
61 /* Completion Status */
62 /* */
63 /* CALLS */
64 /* */
65 /* _ux_hcd_ehci_regular_td_obtain Obtain regular TD */
66 /* _ux_utility_physical_address Get physical address */
67 /* */
68 /* CALLED BY */
69 /* */
70 /* EHCI Controller Driver */
71 /* */
72 /* RELEASE HISTORY */
73 /* */
74 /* DATE NAME DESCRIPTION */
75 /* */
76 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
77 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
78 /* resulting in version 6.1 */
79 /* */
80 /**************************************************************************/
_ux_hcd_ehci_request_transfer_add(UX_HCD_EHCI * hcd_ehci,UX_EHCI_ED * ed,ULONG phase,ULONG pid,ULONG toggle,UCHAR * buffer_address,ULONG buffer_length,UX_TRANSFER * transfer_request)81 UINT _ux_hcd_ehci_request_transfer_add(UX_HCD_EHCI *hcd_ehci, UX_EHCI_ED *ed, ULONG phase, ULONG pid,
82 ULONG toggle, UCHAR * buffer_address, ULONG buffer_length, UX_TRANSFER *transfer_request)
83 {
84
85 UX_EHCI_TD *last_td;
86 UX_EHCI_TD *td;
87 UX_EHCI_LINK_POINTER lp;
88 UX_EHCI_POINTER bp;
89
90
91 /* Obtain a TD for this transaction. */
92 td = _ux_hcd_ehci_regular_td_obtain(hcd_ehci);
93 if (td == UX_NULL)
94 return(UX_NO_TD_AVAILABLE);
95
96 /* Store the transfer request associated with this TD. */
97 td -> ux_ehci_td_transfer_request = transfer_request;
98
99 /* Store the ED associated with this TD. */
100 td -> ux_ehci_td_ed = ed;
101
102 /* Mark the TD with the phase. */
103 td -> ux_ehci_td_phase |= phase;
104
105 /* Set the PID in the control DWORD of the TD. */
106 td -> ux_ehci_td_control = pid;
107
108 /* Set the buffer address if there is a data payload. */
109 bp.void_ptr = _ux_utility_physical_address(buffer_address);
110 td -> ux_ehci_td_bp0 = bp.void_ptr; /* with offset. */
111
112 /* Fill in the next pages addresses if required. */
113 bp.value &= UX_EHCI_PAGE_ALIGN;
114 td -> ux_ehci_td_bp1 = bp.u8_ptr + UX_EHCI_PAGE_SIZE;
115 td -> ux_ehci_td_bp2 = bp.u8_ptr + UX_EHCI_PAGE_SIZE * 2;
116 td -> ux_ehci_td_bp3 = bp.u8_ptr + UX_EHCI_PAGE_SIZE * 3;
117 td -> ux_ehci_td_bp4 = bp.u8_ptr + UX_EHCI_PAGE_SIZE * 4;
118
119 /* Set the length of the data transfer. We keep its original value. */
120 td -> ux_ehci_td_control |= buffer_length << UX_EHCI_TD_LG_LOC;
121 td -> ux_ehci_td_length = buffer_length;
122
123 /* Add the completion trigger, the default error count, the active bit. */
124 td -> ux_ehci_td_control |= UX_EHCI_TD_CERR | UX_EHCI_TD_ACTIVE;
125
126 /* Add the toggle value. This value is only used for control transfers. */
127 td -> ux_ehci_td_control |= toggle;
128
129 /* Recall the last TD hooked to the ED. If the value is NULL, this will be the
130 first TD and should be hooked to the ED itself.. */
131 last_td = ed -> ux_ehci_ed_last_td;
132
133 /* Do we hook this TD to the ED? */
134 if (last_td == UX_NULL)
135 {
136
137 /* The TD is hooked to the ED. We set the T bit so that the controller will
138 not transfer this TD on hook up but when all the TDs have been hooked.
139 We memorize this TD as the first TD as well. */
140 ed -> ux_ehci_ed_first_td = td;
141 lp.void_ptr = _ux_utility_physical_address(td);
142 lp.value |= UX_EHCI_TD_T;
143 ed -> ux_ehci_ed_queue_element = lp.td_ptr;
144 }
145 else
146 {
147
148 /* The TD is hooked to the end of the linked TDs. */
149 last_td -> ux_ehci_td_link_pointer = _ux_utility_physical_address(td);
150 }
151
152 /* Memorize the last TD hooked. */
153 ed -> ux_ehci_ed_last_td = td;
154
155 /* Return successful completion. */
156 return(UX_SUCCESS);
157 }
158
159