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 /**   Device HID Class                                                    */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define UX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "ux_api.h"
28 #include "ux_device_class_hid.h"
29 #include "ux_device_stack.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_device_class_hid_descriptor_send                PORTABLE C      */
37 /*                                                           6.1.8        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function sends back the class descriptor required by the host. */
45 /*                                                                        */
46 /*  INPUT                                                                 */
47 /*                                                                        */
48 /*    descriptor_type                       Descriptor type               */
49 /*    descriptor_index                      Index of descriptor           */
50 /*    host_length                           Length requested by host      */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    Completion Status                                                   */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    (ux_slave_dcd_function)               DCD dispatch function         */
59 /*    _ux_device_stack_transfer_request     Process transfer request      */
60 /*    _ux_utility_memory_copy               Memory copy                   */
61 /*                                                                        */
62 /*  CALLED BY                                                             */
63 /*                                                                        */
64 /*    Application                                                         */
65 /*    Device Stack                                                        */
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 /*                                            verified memset and memcpy  */
74 /*                                            cases,                      */
75 /*                                            resulting in version 6.1    */
76 /*  08-02-2021     Chaoqiong Xiao           Modified comment(s),          */
77 /*                                            fixed HID descriptor search,*/
78 /*                                            resulting in version 6.1.8  */
79 /*                                                                        */
80 /**************************************************************************/
_ux_device_class_hid_descriptor_send(UX_SLAVE_CLASS_HID * hid,ULONG descriptor_type,ULONG request_index,ULONG host_length)81 UINT  _ux_device_class_hid_descriptor_send(UX_SLAVE_CLASS_HID *hid, ULONG descriptor_type,
82                                             ULONG request_index, ULONG host_length)
83 {
84 
85 UX_SLAVE_DCD                    *dcd;
86 UX_SLAVE_DEVICE                 *device;
87 UX_SLAVE_TRANSFER               *transfer_request;
88 UX_SLAVE_ENDPOINT               *endpoint;
89 UCHAR *                         device_framework;
90 UCHAR *                         device_framework_end;
91 ULONG                           descriptor_length;
92 UINT                            status =  UX_ERROR;
93 ULONG                           length;
94 UCHAR                           interface_number = 0xFF;
95 
96     UX_PARAMETER_NOT_USED(request_index);
97 
98     /* If trace is enabled, insert this event into the trace buffer.  */
99     UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_HID_DESCRIPTOR_SEND, hid, descriptor_type, request_index, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
100 
101     /* Get the pointer to the DCD.  */
102     dcd =  &_ux_system_slave -> ux_system_slave_dcd;
103 
104     /* Get the pointer to the device.  */
105     device =  &_ux_system_slave -> ux_system_slave_device;
106 
107     /* Get the control endpoint associated with the device.  */
108     endpoint =  &device -> ux_slave_device_control_endpoint;
109 
110     /* Get the pointer to the transfer request associated with the endpoint.  */
111     transfer_request =  &endpoint -> ux_slave_endpoint_transfer_request;
112 
113     /* Set the direction to OUT.  */
114     transfer_request -> ux_slave_transfer_request_phase =  UX_TRANSFER_PHASE_DATA_OUT;
115 
116     /* Shift the descriptor type in the low byte field.  */
117     descriptor_type =  (UCHAR) ((descriptor_type >> 8) & 0xff);
118 
119     /* What type of descriptor do we need to return?  */
120     switch (descriptor_type)
121     {
122 
123     case UX_DEVICE_CLASS_HID_DESCRIPTOR_HID:
124 
125         /* We should have a HID descriptor as part of the config descriptor.  */
126         device_framework =  _ux_system_slave -> ux_system_slave_device_framework;
127         device_framework_end = device_framework + _ux_system_slave -> ux_system_slave_device_framework_length;
128 
129         /* Parse the device framework and locate the HID descriptor.
130            There is only one HID descriptor.  */
131         while (device_framework < device_framework_end)
132         {
133 
134             /* Get the type of the current descriptor.  */
135             descriptor_type =  *(device_framework + 1);
136 
137             /* And its length.  */
138             descriptor_length =  (ULONG) *device_framework;
139 
140             /* Save interface number for later check.  */
141             if (descriptor_type == UX_INTERFACE_DESCRIPTOR_ITEM)
142                 interface_number = *(device_framework + 2);
143 
144             /* Check if this is a HID report descriptor.  */
145             if ((descriptor_type == UX_DEVICE_CLASS_HID_DESCRIPTOR_HID) &&
146                 (interface_number == (UCHAR)request_index))
147             {
148 
149                 /* Ensure the host does not demand a length beyond our descriptor (Windows does that)
150                    and do not return more than what is allowed.  */
151                 if (descriptor_length < host_length)
152                     length =  descriptor_length;
153                 else
154                     length =  host_length;
155 
156                 /* Check buffer length, since descriptor length may exceed buffer...  */
157                 if (length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
158                 {
159 
160                     /* Error trap. */
161                     _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
162 
163                     /* If trace is enabled, insert this event into the trace buffer.  */
164                     UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
165 
166                     /* Stall the endpoint.  */
167                     status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
168                     break;
169                 }
170 
171                 /* Copy the device descriptor into the transfer request memory.  */
172                 _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer,
173                                             device_framework, length); /* Use case of memcpy is verified. */
174 
175                 /* We can return the configuration descriptor.  */
176                 status =  _ux_device_stack_transfer_request(transfer_request, length, host_length);
177                 break;
178 
179             }
180 
181             /* Point to the next descriptor.  */
182             device_framework +=  descriptor_length;
183         }
184 
185         /* Stall the endpoint if not found or corrupt.  */
186         if (device_framework >= device_framework_end)
187             status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
188 
189         break;
190 
191     case UX_DEVICE_CLASS_HID_DESCRIPTOR_REPORT:
192 
193         /* Get the length of entire configuration descriptor.  */
194         descriptor_length =  hid -> ux_device_class_hid_report_length;
195 
196         /* Ensure the host does not demand a length beyond our descriptor (Windows does that)
197            and do not return more than what is allowed.  */
198         if (descriptor_length < host_length)
199             length =  descriptor_length;
200         else
201             length =  host_length;
202 
203         /* Check buffer length, since total descriptors length may exceed buffer...  */
204         if (length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
205         {
206 
207             /* Error trap. */
208             _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_MEMORY_INSUFFICIENT);
209 
210             /* If trace is enabled, insert this event into the trace buffer.  */
211             UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, hid, 0, 0, UX_TRACE_ERRORS, 0, 0)
212 
213             /* Stall the endpoint.  */
214             status =  dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
215             break;
216         }
217 
218         /* Copy the device descriptor into the transfer request memory.  */
219         _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer,
220                                     hid -> ux_device_class_hid_report_address, length); /* Use case of memcpy is verified. */
221 
222         /* We can return the report descriptor.  */
223         status =  _ux_device_stack_transfer_request(transfer_request, length, host_length);
224         break;
225 
226     case UX_DEVICE_CLASS_HID_DESCRIPTOR_PHYSICAL:
227 
228         /* Not treated for now.  Fall through and Stall endpoint.  */
229 
230     default:
231 
232         /* Stall the endpoint.  */
233         dcd -> ux_slave_dcd_function(dcd, UX_DCD_STALL_ENDPOINT, endpoint);
234         return(UX_ERROR);
235     }
236 
237     /* Return the status to the caller.  */
238     return(status);
239 }
240 
241