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