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 /**   OHCI 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_ohci.h"
30 #include "ux_host_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_hcd_ohci_request_control_transfer               PORTABLE C      */
38 /*                                                           6.1.10       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*     This function performs a control transfer from a transfer request. */
46 /*     The USB control transfer is in 3 phases (setup, data, status).     */
47 /*     This function will chain all phases of the control sequence before */
48 /*     setting the OHCI endpoint as a candidate for transfer.             */
49 /*                                                                        */
50 /*     The maximum aggregated size of a data payload in OHCI is 4K. We    */
51 /*     are assuming that this size will be sufficient to contain the      */
52 /*     control packet.                                                    */
53 /*                                                                        */
54 /*  INPUT                                                                 */
55 /*                                                                        */
56 /*    hcd_ohci                              Pointer to OHCI controller    */
57 /*    transfer_request                      Pointer to transfer request   */
58 /*                                                                        */
59 /*  OUTPUT                                                                */
60 /*                                                                        */
61 /*    Completion Status                                                   */
62 /*                                                                        */
63 /*  CALLS                                                                 */
64 /*                                                                        */
65 /*    _ux_hcd_ohci_register_read            Read OHCI register            */
66 /*    _ux_hcd_ohci_register_write           Write OHCI register           */
67 /*    _ux_hcd_ohci_regular_td_obtain        Get regular TD                */
68 /*    _ux_host_stack_transfer_request_abort Abort transfer request        */
69 /*    _ux_utility_memory_allocate           Allocate memory block         */
70 /*    _ux_utility_memory_free               Release memory block          */
71 /*    _ux_utility_physical_address          Get physical address          */
72 /*    _ux_host_semaphore_get                Get semaphore                 */
73 /*    _ux_utility_short_put                 Write 16-bit value            */
74 /*    _ux_utility_virtual_address           Get virtual address           */
75 /*                                                                        */
76 /*  CALLED BY                                                             */
77 /*                                                                        */
78 /*    OHCI Controller Driver                                              */
79 /*                                                                        */
80 /*  RELEASE HISTORY                                                       */
81 /*                                                                        */
82 /*    DATE              NAME                      DESCRIPTION             */
83 /*                                                                        */
84 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
85 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
86 /*                                            prefixed UX to MS_TO_TICK,  */
87 /*                                            resulting in version 6.1    */
88 /*  11-09-2020     Chaoqiong Xiao           Modified comment(s),          */
89 /*                                            fixed compile warnings,     */
90 /*                                            resulting in version 6.1.2  */
91 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
92 /*                                            refined macros names,       */
93 /*                                            resulting in version 6.1.10 */
94 /*                                                                        */
95 /**************************************************************************/
_ux_hcd_ohci_request_control_transfer(UX_HCD_OHCI * hcd_ohci,UX_TRANSFER * transfer_request)96 UINT  _ux_hcd_ohci_request_control_transfer(UX_HCD_OHCI *hcd_ohci, UX_TRANSFER *transfer_request)
97 {
98 
99 UX_DEVICE       *device;
100 UX_ENDPOINT     *endpoint;
101 UCHAR *         setup_request;
102 UX_OHCI_ED      *ed;
103 UX_OHCI_TD      *setup_td;
104 UX_OHCI_TD      *chain_td;
105 UX_OHCI_TD      *data_td;
106 UX_OHCI_TD      *tail_td;
107 UX_OHCI_TD      *status_td;
108 ULONG           ohci_register;
109 UINT            status;
110 
111 
112     /* Get the pointer to the Endpoint and the Device.  */
113     endpoint =  (UX_ENDPOINT *) transfer_request -> ux_transfer_request_endpoint;
114     device =    endpoint -> ux_endpoint_device;
115 
116     /* Now get the physical ED attached to this endpoint.  */
117     ed =  endpoint -> ux_endpoint_ed;
118 
119     /* Build the SETUP packet (phase 1 of the control transfer).  */
120     setup_request =  _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, UX_SETUP_SIZE);
121     if (setup_request == UX_NULL)
122         return(UX_MEMORY_INSUFFICIENT);
123 
124     *setup_request =                            (UCHAR)transfer_request -> ux_transfer_request_function;
125     *(setup_request + UX_SETUP_REQUEST_TYPE) =  (UCHAR)transfer_request -> ux_transfer_request_type;
126     *(setup_request + UX_SETUP_REQUEST) =       (UCHAR)transfer_request -> ux_transfer_request_function;
127     _ux_utility_short_put(setup_request + UX_SETUP_VALUE, (USHORT)transfer_request -> ux_transfer_request_value);
128     _ux_utility_short_put(setup_request + UX_SETUP_INDEX, (USHORT)transfer_request -> ux_transfer_request_index);
129     _ux_utility_short_put(setup_request + UX_SETUP_LENGTH, (USHORT) transfer_request -> ux_transfer_request_requested_length);
130 
131     /* Set the ED address and MPS values since they may have changed.
132        The ED direction will be set from the TD.  */
133     ed -> ux_ohci_ed_dw0 =  device -> ux_device_address |  ((ULONG) endpoint -> ux_endpoint_descriptor.bEndpointAddress << 7) |
134                                                            ((ULONG) endpoint -> ux_endpoint_descriptor.wMaxPacketSize << 16);
135 
136     /* Refresh the speed.  */
137     if (device -> ux_device_speed == UX_LOW_SPEED_DEVICE)
138         ed -> ux_ohci_ed_dw0 |=  UX_OHCI_ED_LOW_SPEED;
139 
140     /* Use the TD pointer by ed -> tail for our setup TD and chain from this one on.  */
141     setup_td =  _ux_utility_virtual_address(ed -> ux_ohci_ed_tail_td);
142     setup_td -> ux_ohci_td_dw0 =  UX_OHCI_TD_DEFAULT_DW0 | UX_OHCI_TD_DATA0 | UX_OHCI_TD_R;
143     setup_td -> ux_ohci_td_cbp =  _ux_utility_physical_address(setup_request);
144     setup_td -> ux_ohci_td_be =   setup_td -> ux_ohci_td_cbp + UX_SETUP_SIZE - 1;
145     chain_td =  setup_td;
146 
147     /* Attach the endpoint and transfer request to the TD.  */
148     setup_td -> ux_ohci_td_transfer_request =  transfer_request;
149     setup_td -> ux_ohci_td_ed =  ed;
150 
151     /* Mark the TD with the SETUP phase.  */
152     setup_td -> ux_ohci_td_status |=  UX_OHCI_TD_SETUP_PHASE;
153 
154     /* Check if there is a data phase, if not jump to status phase.  */
155     data_td =  UX_NULL;
156     if (transfer_request -> ux_transfer_request_requested_length != 0)
157     {
158 
159         data_td =  _ux_hcd_ohci_regular_td_obtain(hcd_ohci);
160         if (data_td == UX_NULL)
161         {
162 
163             _ux_utility_memory_free(setup_request);
164             return(UX_NO_TD_AVAILABLE);
165         }
166 
167         /* Attach the endpoint and transfer request to the TD.  */
168         data_td -> ux_ohci_td_transfer_request =  transfer_request;
169         data_td -> ux_ohci_td_ed =  ed;
170 
171         /* Mark the TD with the DATA phase.  */
172         data_td -> ux_ohci_td_status |=  UX_OHCI_TD_DATA_PHASE;
173 
174         /* Program the control bits of the TD.  */
175         if ((transfer_request -> ux_transfer_request_type & UX_REQUEST_DIRECTION) == UX_REQUEST_IN)
176 
177             data_td -> ux_ohci_td_dw0 =  UX_OHCI_TD_DEFAULT_DW0 | UX_OHCI_TD_IN | UX_OHCI_TD_DATA1 | UX_OHCI_TD_R;
178         else
179 
180             data_td -> ux_ohci_td_dw0 =  UX_OHCI_TD_DEFAULT_DW0 | UX_OHCI_TD_OUT | UX_OHCI_TD_DATA1 | UX_OHCI_TD_R;
181 
182         /* Attach the CBP and BE values to the TD.  */
183         data_td -> ux_ohci_td_cbp =  _ux_utility_physical_address(transfer_request -> ux_transfer_request_data_pointer);
184         data_td -> ux_ohci_td_be =   data_td -> ux_ohci_td_cbp + transfer_request -> ux_transfer_request_requested_length - 1;
185 
186         /* Update the length of the transfer for this TD.  */
187         data_td -> ux_ohci_td_length =  transfer_request -> ux_transfer_request_requested_length;
188 
189         /* Chain the TD.  */
190         chain_td -> ux_ohci_td_next_td =  _ux_utility_physical_address(data_td);
191         chain_td =  data_td;
192     }
193 
194     /* Now, program the status phase.  */
195     status_td =  _ux_hcd_ohci_regular_td_obtain(hcd_ohci);
196     if (status_td == UX_NULL)
197     {
198 
199         _ux_utility_memory_free(setup_request);
200         if (data_td != UX_NULL)
201             data_td -> ux_ohci_td_status =  UX_UNUSED;
202         return(UX_NO_TD_AVAILABLE);
203     }
204 
205     /* Attach the endpoint and transfer request to the TD.  */
206     status_td -> ux_ohci_td_transfer_request =  transfer_request;
207     status_td -> ux_ohci_td_ed =  ed;
208 
209     /* Mark the TD with the STATUS phase.  */
210     status_td -> ux_ohci_td_status |=  UX_OHCI_TD_STATUS_PHASE;
211 
212     /* The direction of the status phase is IN if data phase is OUT and
213        vice versa.  */
214     if ((transfer_request -> ux_transfer_request_type & UX_REQUEST_DIRECTION) == UX_REQUEST_IN)
215 
216         status_td -> ux_ohci_td_dw0 =  UX_OHCI_TD_DEFAULT_DW0 | UX_OHCI_TD_OUT | UX_OHCI_TD_DATA1;
217     else
218 
219         status_td -> ux_ohci_td_dw0 =  UX_OHCI_TD_DEFAULT_DW0 | UX_OHCI_TD_IN | UX_OHCI_TD_DATA1;
220 
221     /* No data payload for the status phase.  */
222     status_td -> ux_ohci_td_cbp =  0;
223     status_td -> ux_ohci_td_be =  0;
224 
225     /* Hook the status phase to the previous TD.  */
226     chain_td -> ux_ohci_td_next_td =  _ux_utility_physical_address(status_td);
227 
228     /* Since we have consumed out tail TD for the setup packet, we must get another
229        one and hook it to the ED's tail.  */
230     tail_td =  _ux_hcd_ohci_regular_td_obtain(hcd_ohci);
231     if (tail_td == UX_NULL)
232     {
233 
234         _ux_utility_memory_free(setup_request);
235         if (data_td != UX_NULL)
236             data_td -> ux_ohci_td_status =  UX_UNUSED;
237         status_td -> ux_ohci_td_status =  UX_UNUSED;
238         return(UX_NO_TD_AVAILABLE);
239     }
240 
241     /* Hook the new TD to the status TD.  */
242     status_td -> ux_ohci_td_next_td =  _ux_utility_physical_address(tail_td);
243 
244     /* At this stage, the Head and Tail in the ED are still the same and
245        the OHCI controller will skip this ED until we have hooked the new
246        tail TD.  */
247     ed -> ux_ohci_ed_tail_td =  _ux_utility_physical_address(tail_td);
248 
249     /* Now, we must tell the OHCI controller that there is something in the
250        control queue.  */
251     ohci_register =  _ux_hcd_ohci_register_read(hcd_ohci, OHCI_HC_COMMAND_STATUS);
252     ohci_register |=  OHCI_HC_CS_CLF;
253     _ux_hcd_ohci_register_write(hcd_ohci, OHCI_HC_COMMAND_STATUS, ohci_register);
254 
255    /* Wait for the completion of the transfer request.  */
256     status =  _ux_host_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, UX_MS_TO_TICK(UX_CONTROL_TRANSFER_TIMEOUT));
257 
258     /* If the semaphore did not succeed we probably have a time out.  */
259     if (status != UX_SUCCESS)
260     {
261 
262         /* All transfers pending need to abort. There may have been a partial transfer. */
263         _ux_host_stack_transfer_request_abort(transfer_request);
264 
265         /* There was an error, return to the caller.  */
266         transfer_request -> ux_transfer_request_completion_code =  UX_TRANSFER_TIMEOUT;
267 
268         /* Error trap. */
269         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_TRANSFER_TIMEOUT);
270 
271         /* If trace is enabled, insert this event into the trace buffer.  */
272         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_TRANSFER_TIMEOUT, transfer_request, 0, 0, UX_TRACE_ERRORS, 0, 0)
273 
274     }
275 
276     /* Free the resources.  */
277     _ux_utility_memory_free(setup_request);
278 
279     /* Return the completion status.  */
280     return(transfer_request -> ux_transfer_request_completion_code);
281 }
282 
283