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 /**   Device Stack                                                        */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 #define UX_SOURCE_CODE
24 
25 
26 /* Include necessary system files.  */
27 
28 #include "ux_api.h"
29 #include "ux_device_stack.h"
30 
31 
32 #if defined(UX_DEVICE_STANDALONE)
33 
34 #define UX_DEVICE_STACK_TRANSFER_STATE_HALT_WAIT (UX_STATE_STACK_STEP + 0)
35 #define UX_DEVICE_STACK_TRANSFER_STATE_TRAN_WAIT (UX_STATE_STACK_STEP + 1)
36 
37 /**************************************************************************/
38 /*                                                                        */
39 /*  FUNCTION                                               RELEASE        */
40 /*                                                                        */
41 /*    _ux_device_stack_transfer_run                       PORTABLE C      */
42 /*                                                           6.1.10       */
43 /*  AUTHOR                                                                */
44 /*                                                                        */
45 /*    Chaoqiong Xiao, Microsoft Corporation                               */
46 /*                                                                        */
47 /*  DESCRIPTION                                                           */
48 /*                                                                        */
49 /*    This function performs a USB transaction. On entry the              */
50 /*    transfer request gives the endpoint pipe selected for this          */
51 /*    transaction and the parameters associated with the transfer         */
52 /*    (data payload, length of transaction).                              */
53 /*                                                                        */
54 /*    It's for standalone mode.                                           */
55 /*                                                                        */
56 /*  INPUT                                                                 */
57 /*                                                                        */
58 /*    transfer_request                      Pointer to transfer request   */
59 /*    slave_length                          Length returned by host       */
60 /*    host_length                           Length asked by host          */
61 /*                                                                        */
62 /*  OUTPUT                                                                */
63 /*                                                                        */
64 /*    State machine Status to check                                       */
65 /*    UX_STATE_NEXT                         Transfer done, to next state  */
66 /*    UX_STATE_EXIT                         Abnormal, to reset state      */
67 /*    (others)                              Keep running, waiting         */
68 /*                                                                        */
69 /*  CALLS                                                                 */
70 /*                                                                        */
71 /*    (ux_slave_dcd_function)               Slave DCD dispatch function   */
72 /*                                                                        */
73 /*  CALLED BY                                                             */
74 /*                                                                        */
75 /*    Application                                                         */
76 /*    Device Stack                                                        */
77 /*                                                                        */
78 /*  RELEASE HISTORY                                                       */
79 /*                                                                        */
80 /*    DATE              NAME                      DESCRIPTION             */
81 /*                                                                        */
82 /*  01-31-2022     Chaoqiong Xiao           Initial Version 6.1.10        */
83 /*                                                                        */
84 /**************************************************************************/
_ux_device_stack_transfer_run(UX_SLAVE_TRANSFER * transfer_request,ULONG slave_length,ULONG host_length)85 UINT  _ux_device_stack_transfer_run(UX_SLAVE_TRANSFER *transfer_request, ULONG slave_length, ULONG host_length)
86 {
87 
88 UX_SLAVE_DCD            *dcd;
89 UINT                    status;
90 UINT                    state;
91 UX_SLAVE_ENDPOINT       *endpoint;
92 ULONG                   device_state;
93 
94 
95     /* Do we have to skip this transfer?  */
96     if (transfer_request -> ux_slave_transfer_request_status_phase_ignore == UX_TRUE)
97     {
98         transfer_request -> ux_slave_transfer_request_completion_code = UX_SUCCESS;
99         transfer_request -> ux_slave_transfer_request_state = UX_STATE_NEXT;
100         return(UX_STATE_NEXT);
101     }
102 
103     /* Get the device state.  */
104     device_state =  _ux_system_slave -> ux_system_slave_device.ux_slave_device_state;
105 
106     /* We can only transfer when the device is ATTACHED, ADDRESSED OR CONFIGURED.  */
107     if (!(device_state == UX_DEVICE_ATTACHED) &&
108         !(device_state == UX_DEVICE_ADDRESSED) &&
109         !(device_state == UX_DEVICE_CONFIGURED))
110     {
111         transfer_request -> ux_slave_transfer_request_completion_code = UX_TRANSFER_NOT_READY;
112         transfer_request -> ux_slave_transfer_request_state = UX_STATE_RESET;
113         return(UX_STATE_EXIT);
114     }
115 
116     /* Get the pointer to the DCD.  */
117     dcd =  &_ux_system_slave -> ux_system_slave_dcd;
118 
119     /* Get the endpoint associated with this transaction.  */
120     endpoint =  transfer_request -> ux_slave_transfer_request_endpoint;
121 
122     /* Process states.  */
123     state = transfer_request -> ux_slave_transfer_request_state;
124     switch(state)
125     {
126     case UX_STATE_RESET:
127 
128         /* Prepare transfer parameters.  */
129 
130         /* If the endpoint is non Control, check the endpoint direction and set the data phase direction.  */
131         if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) != UX_CONTROL_ENDPOINT)
132         {
133 
134             /* Isolate the direction from the endpoint address.  */
135             if ((endpoint -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == UX_ENDPOINT_IN)
136                 transfer_request -> ux_slave_transfer_request_phase =  UX_TRANSFER_PHASE_DATA_OUT;
137             else
138                 transfer_request -> ux_slave_transfer_request_phase =  UX_TRANSFER_PHASE_DATA_IN;
139         }
140 
141         /* See if we need to force a zero length packet at the end of the transfer.
142            This happens on a DATA IN and when the host requested length is not met
143            and the last packet is on a boundary. If slave_length is zero, then it is
144            a explicit ZLP request, no need to force ZLP.  */
145         if ((transfer_request -> ux_slave_transfer_request_phase == UX_TRANSFER_PHASE_DATA_OUT) &&
146             (slave_length != 0) && (host_length != slave_length) &&
147             (slave_length % endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize) == 0)
148         {
149 
150             /* If so force Zero Length Packet.  */
151             transfer_request -> ux_slave_transfer_request_force_zlp =  UX_TRUE;
152         }
153         else
154         {
155 
156             /* Condition is not met, do not force a Zero Length Packet.  */
157             transfer_request -> ux_slave_transfer_request_force_zlp =  UX_FALSE;
158         }
159 
160         /* Reset the number of bytes sent/received.  */
161         transfer_request -> ux_slave_transfer_request_actual_length =  0;
162 
163         /* Determine how many bytes to send in this transaction.  We keep track of the original
164            length and have a working length.  */
165         transfer_request -> ux_slave_transfer_request_requested_length =    slave_length;
166         transfer_request -> ux_slave_transfer_request_in_transfer_length =  slave_length;
167 
168         /* Save the buffer pointer.  */
169         transfer_request -> ux_slave_transfer_request_current_data_pointer =
170                                 transfer_request -> ux_slave_transfer_request_data_pointer;
171 
172         /* Set the transfer to pending.  */
173         transfer_request -> ux_slave_transfer_request_status = UX_TRANSFER_STATUS_PENDING;
174 
175         /* Next state.  */
176         transfer_request -> ux_slave_transfer_request_state = UX_DEVICE_STACK_TRANSFER_STATE_HALT_WAIT;
177 
178         /* If trace is enabled, insert this event into the trace buffer.  */
179         UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_STACK_TRANSFER_REQUEST, transfer_request, 0, 0, 0, UX_TRACE_DEVICE_STACK_EVENTS, 0, 0)
180 
181         /* Fall through.  */
182     case UX_DEVICE_STACK_TRANSFER_STATE_HALT_WAIT:
183 
184         /* If the endpoint is non Control, check the endpoint direction and set the data phase direction.  */
185         if ((endpoint -> ux_slave_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) != UX_CONTROL_ENDPOINT)
186         {
187 
188             /* Return WAIT until halt cleared.  */
189             if (endpoint -> ux_slave_endpoint_state == UX_ENDPOINT_HALTED)
190                 return(UX_STATE_WAIT);
191 
192         }
193 
194         /* Next state.  */
195         transfer_request -> ux_slave_transfer_request_state = UX_DEVICE_STACK_TRANSFER_STATE_TRAN_WAIT;
196 
197         /* Start background transfer immediately.  */
198         /* Fall through.  */
199     case UX_DEVICE_STACK_TRANSFER_STATE_TRAN_WAIT:
200 
201         /* Call the DCD driver transfer function.   */
202         /* Transfer state is adjusted inside DCD driver.  */
203         status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_TRANSFER_RUN, transfer_request);
204 
205         /* Any error case or normal end: reset state for next transfer.  */
206         if (status < UX_STATE_WAIT)
207         {
208             UX_SLAVE_TRANSFER_STATE_RESET(transfer_request);
209         }
210         break;
211 
212     default: /* Error case, return EXIT.  */
213         transfer_request -> ux_slave_transfer_request_state = UX_STATE_RESET;
214         return(UX_STATE_EXIT);
215     }
216 
217     /* And return the status.  */
218     return(status);
219 }
220 #endif
221