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 /**   HID Class                                                           */
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_host_class_hid.h"
30 #include "ux_host_stack.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _ux_host_class_hid_descriptor_parse                 PORTABLE C      */
38 /*                                                           6.1.12       */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Chaoqiong Xiao, Microsoft Corporation                               */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function obtains the HID descriptor and parses it.             */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    hid                                   Pointer to HID class          */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    Completion Status                                                   */
54 /*                                                                        */
55 /*  CALLS                                                                 */
56 /*                                                                        */
57 /*    _ux_host_class_hid_report_descriptor_get                            */
58 /*                                          Get HID report descriptor     */
59 /*    _ux_host_stack_transfer_request       Process transfer request      */
60 /*    _ux_utility_descriptor_parse          Parse descriptor              */
61 /*    _ux_utility_memory_allocate           Allocate memory block         */
62 /*    _ux_utility_memory_free               Release memory block          */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    HID Class                                                           */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
73 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
74 /*                                            resulting in version 6.1    */
75 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
76 /*                                            used shared device config   */
77 /*                                            descriptor for enum scan,   */
78 /*                                            resulting in version 6.1.12 */
79 /*                                                                        */
80 /**************************************************************************/
_ux_host_class_hid_descriptor_parse(UX_HOST_CLASS_HID * hid)81 UINT  _ux_host_class_hid_descriptor_parse(UX_HOST_CLASS_HID *hid)
82 {
83 
84 UX_DEVICE                       *device;
85 UX_CONFIGURATION                *configuration;
86 UCHAR                           *descriptor;
87 UCHAR                           *start_descriptor;
88 UX_ENDPOINT                     *control_endpoint;
89 UX_TRANSFER                     *transfer_request;
90 UX_HID_DESCRIPTOR               hid_descriptor;
91 UX_INTERFACE_DESCRIPTOR         interface_descriptor;
92 UINT                            status;
93 ULONG                           total_configuration_length;
94 UINT                            descriptor_length;
95 UINT                            descriptor_type;
96 ULONG                           current_interface;
97 
98     /* Get device, current configuration.  */
99     device = hid -> ux_host_class_hid_device;
100     configuration = device -> ux_device_current_configuration;
101     total_configuration_length = configuration -> ux_configuration_descriptor.wTotalLength;
102 
103     /* Check if descriptor is previously saved.  */
104     if (device -> ux_device_packed_configuration != UX_NULL)
105     {
106         start_descriptor = device -> ux_device_packed_configuration;
107         descriptor = start_descriptor;
108         status = UX_SUCCESS;
109     }
110     else
111     {
112 
113         /* We need to get the default control endpoint transfer request pointer.  */
114         control_endpoint =  &device -> ux_device_control_endpoint;
115         transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
116 
117         /* Need to allocate memory for the descriptor. Since we do not know the size of the
118         descriptor, we first read the first bytes.  */
119         descriptor =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, total_configuration_length);
120         if (descriptor == UX_NULL)
121             return(UX_MEMORY_INSUFFICIENT);
122 
123         /* Memorize the descriptor start address.  */
124         start_descriptor =  descriptor;
125 
126         /* Create a transfer request for the GET_DESCRIPTOR request.  */
127         transfer_request -> ux_transfer_request_data_pointer =      descriptor;
128         transfer_request -> ux_transfer_request_requested_length =  total_configuration_length;
129         transfer_request -> ux_transfer_request_function =          UX_GET_DESCRIPTOR;
130         transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_DEVICE;
131         transfer_request -> ux_transfer_request_value =             UX_CONFIGURATION_DESCRIPTOR_ITEM << 8;
132         transfer_request -> ux_transfer_request_index =             0;
133 
134         /* Send request to HCD layer.  */
135         status =  _ux_host_stack_transfer_request(transfer_request);
136 
137         /* Check descriptor length.  */
138         if (transfer_request -> ux_transfer_request_actual_length != total_configuration_length)
139             status = UX_DESCRIPTOR_CORRUPTED;
140     }
141 
142     /* Reset the current interface to keep compiler warnings happy. */
143     current_interface = 0;
144 
145     /* Check for correct transfer and entire descriptor returned.  */
146     if (status == UX_SUCCESS)
147     {
148 
149         /* The HID descriptor is embedded within the configuration descriptor. We parse the
150             entire descriptor to locate the HID portion.  */
151         while (total_configuration_length)
152         {
153 
154             /* Gather the length and type of the descriptor.   */
155             descriptor_length =  *descriptor;
156             descriptor_type =    *(descriptor + 1);
157 
158             /* Make sure this descriptor has at least the minimum length.  */
159             if (descriptor_length < 3)
160             {
161 
162                 /* Error trap. */
163                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
164 
165                 /* If trace is enabled, insert this event into the trace buffer.  */
166                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
167 
168                 /* Error, release the memory and return an error.  */
169                 _ux_utility_memory_free(start_descriptor);
170 
171                 return(UX_DESCRIPTOR_CORRUPTED);
172             }
173 
174             /* Check the type for an interface descriptor.  */
175             if (descriptor_type == UX_INTERFACE_DESCRIPTOR_ITEM)
176             {
177 
178                 /* Parse the interface descriptor and make it machine independent.  */
179                 _ux_utility_descriptor_parse(descriptor,
180                             _ux_system_interface_descriptor_structure,
181                             UX_INTERFACE_DESCRIPTOR_ENTRIES,
182                             (UCHAR *) &interface_descriptor);
183 
184                 /* Memorize the interface we are scanning.  */
185                 current_interface = interface_descriptor.bInterfaceNumber;
186             }
187 
188             /* Check the type for an interface descriptor.  */
189             /* Check if the descriptor belongs to interface attached to this instance.  */
190             if (descriptor_type == UX_HOST_CLASS_HID_DESCRIPTOR)
191             {
192 
193                 /* Ensure this interface is the one we need to scan.  */
194                 if (current_interface == hid -> ux_host_class_hid_interface -> ux_interface_descriptor.bInterfaceNumber)
195                 {
196 
197                     /* Obtain the length of the HID descriptor. We need to make machine
198                         independent first.  */
199                     _ux_utility_descriptor_parse(descriptor, _ux_system_hid_descriptor_structure,
200                                                     UX_HID_DESCRIPTOR_ENTRIES, (UCHAR *) &hid_descriptor);
201 
202                     /* We have found the hid descriptor. Now we should get the HID report descriptor.  */
203                     status =  _ux_host_class_hid_report_descriptor_get(hid, hid_descriptor.wItemLength);
204 
205                     /* No release, the memory will be released after all interface scan done(enumeration done).  */
206                     device -> ux_device_packed_configuration = start_descriptor;
207 
208                     /* Return completion status.  */
209                     return(status);
210                 }
211             }
212 
213             /* Verify if the descriptor is still valid.  */
214             if (descriptor_length > total_configuration_length)
215             {
216 
217                 /* Error trap. */
218                 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
219 
220                 /* If trace is enabled, insert this event into the trace buffer.  */
221                 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
222 
223                 /* Release the memory.  */
224                 _ux_utility_memory_free(start_descriptor);
225 
226                 /* Return an error.  */
227                 return(UX_DESCRIPTOR_CORRUPTED);
228             }
229 
230             /* Jump to the next descriptor if we have not reached the end.  */
231             descriptor +=  descriptor_length;
232 
233             /* And adjust the length left to parse in the descriptor.  */
234             total_configuration_length -=  descriptor_length;
235         }
236     }
237 
238     /* Error trap. */
239     _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
240 
241     /* If trace is enabled, insert this event into the trace buffer.  */
242     UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, start_descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
243 
244     /* Free all used resources.  */
245     if (device -> ux_device_packed_configuration == UX_NULL)
246         _ux_utility_memory_free(start_descriptor);
247 
248     /* Return an error.  */
249     return(UX_DESCRIPTOR_CORRUPTED);
250 }
251 
252