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 /**   Host Stack                                                          */
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_host_stack.h"
29 
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _ux_host_stack_device_descriptor_read               PORTABLE C      */
36 /*                                                           6.1.10       */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Chaoqiong Xiao, Microsoft Corporation                               */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function reads the device descriptor.                          */
44 /*                                                                        */
45 /*  INPUT                                                                 */
46 /*                                                                        */
47 /*    device                                Pointer to device             */
48 /*                                                                        */
49 /*  OUTPUT                                                                */
50 /*                                                                        */
51 /*    Completion Status                                                   */
52 /*                                                                        */
53 /*  CALLS                                                                 */
54 /*                                                                        */
55 /*    _ux_host_stack_transfer_request       Process transfer request      */
56 /*    _ux_utility_descriptor_parse          Parse descriptor              */
57 /*    _ux_utility_memory_allocate           Allocate memory block         */
58 /*    _ux_utility_memory_free               Free memory block             */
59 /*                                                                        */
60 /*  CALLED BY                                                             */
61 /*                                                                        */
62 /*    USBX Components                                                     */
63 /*                                                                        */
64 /*  RELEASE HISTORY                                                       */
65 /*                                                                        */
66 /*    DATE              NAME                      DESCRIPTION             */
67 /*                                                                        */
68 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
69 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
70 /*                                            resulting in version 6.1    */
71 /*  10-15-2021     Chaoqiong Xiao           Modified comment(s),          */
72 /*                                            added bMaxPacketSize0 check,*/
73 /*                                            resulting in version 6.1.9  */
74 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
75 /*                                            added standalone support,   */
76 /*                                            added class code checking,  */
77 /*                                            resulting in version 6.1.10 */
78 /*                                                                        */
79 /**************************************************************************/
_ux_host_stack_device_descriptor_read(UX_DEVICE * device)80 UINT  _ux_host_stack_device_descriptor_read(UX_DEVICE *device)
81 {
82 
83 UX_TRANSFER     *transfer_request;
84 UINT            status;
85 UCHAR *         descriptor;
86 UX_ENDPOINT     *control_endpoint;
87 
88     /* If trace is enabled, insert this event into the trace buffer.  */
89     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_STACK_DEVICE_DESCRIPTOR_READ, device, 0, 0, 0, UX_TRACE_HOST_STACK_EVENTS, 0, 0)
90 
91     /* Retrieve the pointer to the control endpoint.  */
92     control_endpoint =  &device -> ux_device_control_endpoint;
93     transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
94 
95     /* Need to allocate memory for the descriptor.  */
96     descriptor =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_DEVICE_DESCRIPTOR_LENGTH);
97     if (descriptor == UX_NULL)
98         return(UX_MEMORY_INSUFFICIENT);
99 
100     /* Create a transfer_request for the GET_DESCRIPTOR request. The first transfer_request asks
101        for the first 8 bytes only. This way we will know the real MaxPacketSize
102        value for the control endpoint.  */
103     transfer_request -> ux_transfer_request_data_pointer =      descriptor;
104     transfer_request -> ux_transfer_request_requested_length =  8;
105     transfer_request -> ux_transfer_request_function =          UX_GET_DESCRIPTOR;
106     transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
107     transfer_request -> ux_transfer_request_value =             UX_DEVICE_DESCRIPTOR_ITEM << 8;
108     transfer_request -> ux_transfer_request_index =             0;
109 
110 #if defined(UX_HOST_STANDALONE)
111     device -> ux_device_enum_trans = transfer_request;
112     status = UX_SUCCESS;
113     return(status);
114 #else
115 
116     /* Send request to HCD layer.  */
117     status =  _ux_host_stack_transfer_request(transfer_request);
118 
119     /* Check for correct transfer and entire descriptor returned.  */
120     if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == 8))
121     {
122 
123         /* Parse the device descriptor and create the local descriptor.  */
124         _ux_utility_descriptor_parse(descriptor, _ux_system_device_descriptor_structure, UX_DEVICE_DESCRIPTOR_ENTRIES,
125                                                                                 (UCHAR *) &device -> ux_device_descriptor);
126     }
127     else
128     {
129 
130         /* Free all used resources.  */
131         _ux_utility_memory_free(descriptor);
132 
133         /* Return completion status.  */
134         return(status);
135     }
136 
137     /* Validate the bMaxPacketSize0.  */
138     if (device -> ux_device_descriptor.bMaxPacketSize0 != 8 &&
139         device -> ux_device_descriptor.bMaxPacketSize0 != 16 &&
140         device -> ux_device_descriptor.bMaxPacketSize0 != 32 &&
141         device -> ux_device_descriptor.bMaxPacketSize0 != 64)
142     {
143         _ux_utility_memory_free(descriptor);
144         return(UX_DESCRIPTOR_CORRUPTED);
145     }
146 
147 #if defined(UX_HOST_DEVICE_CLASS_CODE_VALIDATION_ENABLE)
148 
149     /* Validate the USB-IF bDeviceClass class code.  */
150     switch(device -> ux_device_descriptor.bDeviceClass)
151     {
152     case 0x00: /* Fall through.  */
153     case 0x02: /* Fall through.  */
154     case 0x09: /* Fall through.  */
155     case 0x11: /* Fall through.  */
156     case 0xDC: /* Fall through.  */
157     case 0xEF: /* Fall through.  */
158     case 0xFF:
159         break;
160     default:
161 
162         /* Invalid device class code.  */
163         _ux_utility_memory_free(descriptor);
164         return(UX_DESCRIPTOR_CORRUPTED);
165     }
166 #endif
167 
168     /* Update the max packet size value for the endpoint.  */
169     control_endpoint -> ux_endpoint_descriptor.wMaxPacketSize =  device -> ux_device_descriptor.bMaxPacketSize0;
170 
171     /* Create a transfer_request for the GET_DESCRIPTOR request. This time, we have the complete length */
172     transfer_request -> ux_transfer_request_data_pointer =      descriptor;
173     transfer_request -> ux_transfer_request_requested_length =  UX_DEVICE_DESCRIPTOR_LENGTH;
174     transfer_request -> ux_transfer_request_function =          UX_GET_DESCRIPTOR;
175     transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
176     transfer_request -> ux_transfer_request_value =             UX_DEVICE_DESCRIPTOR_ITEM << 8;
177     transfer_request -> ux_transfer_request_index =             0;
178     transfer_request -> ux_transfer_request_packet_length =     device -> ux_device_descriptor.bMaxPacketSize0;
179 
180     /* Send request to HCD layer.  */
181     status =  _ux_host_stack_transfer_request(transfer_request);
182 
183     /* Check for correct transfer and entire descriptor returned.  */
184     if ((status == UX_SUCCESS) && (transfer_request -> ux_transfer_request_actual_length == UX_DEVICE_DESCRIPTOR_LENGTH))
185     {
186 
187         /* Parse the device descriptor and create the local descriptor.  */
188         _ux_utility_descriptor_parse(descriptor, _ux_system_device_descriptor_structure, UX_DEVICE_DESCRIPTOR_ENTRIES,
189                                                                     (UCHAR *) &device -> ux_device_descriptor);
190     }
191     else
192     {
193 
194         /* Error trap. */
195         _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_ENUMERATOR, UX_DESCRIPTOR_CORRUPTED);
196 
197         /* If trace is enabled, insert this event into the trace buffer.  */
198         UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
199 
200         /* The device descriptor does not contain the right amount of data. Maybe corruption.  */
201         status =  UX_DESCRIPTOR_CORRUPTED;
202     }
203 
204     /* Free all used resources.  */
205     _ux_utility_memory_free(descriptor);
206 
207     /* Return completion status.  */
208     return(status);
209 #endif
210 }
211 
212