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