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