1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** USBX Component */
16 /** */
17 /** EHCI Controller Driver */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 /* Include necessary system files. */
24
25 #define UX_SOURCE_CODE
26
27 #include "ux_api.h"
28 #include "ux_hcd_ehci.h"
29 #include "ux_host_stack.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_hcd_ehci_request_bulk_transfer PORTABLE C */
37 /* 6.1 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function performs a bulk transfer request. A bulk transfer */
45 /* can be larger than the size of the EHCI buffer so it may be */
46 /* required to chain multiple tds to accommodate this request. A bulk */
47 /* transfer is non blocking, so we return before the request is */
48 /* completed. */
49 /* */
50 /* INPUT */
51 /* */
52 /* hcd_ehci Pointer to EHCI controller */
53 /* transfer_request Pointer to transfer request */
54 /* */
55 /* OUTPUT */
56 /* */
57 /* Completion Status */
58 /* */
59 /* CALLS */
60 /* */
61 /* _ux_hcd_ehci_request_transfer_add Add transfer to ED */
62 /* */
63 /* CALLED BY */
64 /* */
65 /* EHCI Controller Driver */
66 /* */
67 /* RELEASE HISTORY */
68 /* */
69 /* DATE NAME DESCRIPTION */
70 /* */
71 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
72 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
73 /* resulting in version 6.1 */
74 /* */
75 /**************************************************************************/
_ux_hcd_ehci_request_bulk_transfer(UX_HCD_EHCI * hcd_ehci,UX_TRANSFER * transfer_request)76 UINT _ux_hcd_ehci_request_bulk_transfer(UX_HCD_EHCI *hcd_ehci, UX_TRANSFER *transfer_request)
77 {
78
79 UX_ENDPOINT *endpoint;
80 UX_EHCI_ED *ed;
81 ULONG transfer_request_payload_length;
82 ULONG bulk_packet_payload_length;
83 UCHAR * data_pointer;
84 ULONG pid;
85 ULONG td_component;
86 UINT status;
87 ULONG zlp_flag;
88
89
90 /* Get the pointer to the Endpoint. */
91 endpoint = (UX_ENDPOINT *) transfer_request -> ux_transfer_request_endpoint;
92
93 /* Now get the physical ED attached to this endpoint. */
94 ed = endpoint -> ux_endpoint_ed;
95
96 /* The overlay parameters should be reset now. */
97 ed -> ux_ehci_ed_current_td = UX_NULL;
98 ed -> ux_ehci_ed_queue_element = (UX_EHCI_TD *)UX_EHCI_TD_T;
99 ed -> ux_ehci_ed_alternate_td = (UX_EHCI_TD *)UX_EHCI_TD_T;
100 ed -> ux_ehci_ed_state &= UX_EHCI_QH_TOGGLE;
101 ed -> ux_ehci_ed_bp0 = UX_NULL;
102 ed -> ux_ehci_ed_bp0 = UX_NULL;
103 ed -> ux_ehci_ed_bp1 = UX_NULL;
104 ed -> ux_ehci_ed_bp2 = UX_NULL;
105 ed -> ux_ehci_ed_bp3 = UX_NULL;
106 ed -> ux_ehci_ed_bp4 = UX_NULL;
107
108 /* It may take more than one TD if the transfer_request length is more than the
109 maximum length for an EHCI TD (this is irrelevant of the MaxPacketSize value
110 in the endpoint descriptor). EHCI data payload has a maximum size of 16K. */
111 transfer_request_payload_length = transfer_request -> ux_transfer_request_requested_length;
112 data_pointer = transfer_request -> ux_transfer_request_data_pointer;
113
114 /* Check for ZLP condition. */
115 if (transfer_request_payload_length == 0)
116
117 /* We have a zlp condition. */
118 zlp_flag = UX_TRUE;
119 else
120
121 /* We do not have a zlp. */
122 zlp_flag = UX_FALSE;
123
124 /* Build all necessary TDs. */
125 while ((transfer_request_payload_length != 0) || zlp_flag == UX_TRUE)
126 {
127
128 /* Reset ZLP now. */
129 zlp_flag = UX_FALSE;
130
131 /* Check if we are exceeding the max payload. */
132 if (transfer_request_payload_length > UX_EHCI_MAX_PAYLOAD)
133 bulk_packet_payload_length = UX_EHCI_MAX_PAYLOAD;
134 else
135 bulk_packet_payload_length = transfer_request_payload_length;
136
137 /* Add this transfer request to the ED. */
138 if ((transfer_request -> ux_transfer_request_type&UX_REQUEST_DIRECTION) == UX_REQUEST_IN)
139 pid = UX_EHCI_PID_IN;
140 else
141 pid = UX_EHCI_PID_OUT;
142
143 status = _ux_hcd_ehci_request_transfer_add(hcd_ehci, ed, 0, pid, 0,
144 data_pointer, bulk_packet_payload_length, transfer_request);
145
146 if (status != UX_SUCCESS)
147 return(status);
148
149 /* Adjust the data payload length and the data payload pointer. */
150 transfer_request_payload_length -= bulk_packet_payload_length;
151 data_pointer += bulk_packet_payload_length;
152 }
153
154 /* Set the IOC bit in the last TD. */
155 ed -> ux_ehci_ed_last_td -> ux_ehci_td_control |= UX_EHCI_TD_IOC;
156
157 /* Ensure the IOC bit is set before activating the TD. This is necessary
158 for some processors that perform writes out of order as an optimization. */
159 UX_DATA_MEMORY_BARRIER
160
161 /* Activate the first TD linked to the ED. */
162 td_component = (ULONG) ed -> ux_ehci_ed_queue_element;
163 td_component &= ~UX_EHCI_TD_T;
164 ed -> ux_ehci_ed_queue_element = (UX_EHCI_TD *) td_component;
165
166 /* Return successful completion. */
167 return(UX_SUCCESS);
168 }
169
170