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