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 /** USBX Component */
15 /** */
16 /** Device HID Class */
17 /** */
18 /**************************************************************************/
19 /**************************************************************************/
20
21 #define UX_SOURCE_CODE
22
23
24 /* Include necessary system files. */
25
26 #include "ux_api.h"
27 #include "ux_device_class_hid.h"
28 #include "ux_device_stack.h"
29
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _ux_device_class_hid_control_request PORTABLE C */
36 /* 6.1.12 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function manages the based sent by the host on the control */
44 /* endpoints with a CLASS or VENDOR SPECIFIC type. */
45 /* */
46 /* INPUT */
47 /* */
48 /* hid Pointer to hid class */
49 /* */
50 /* OUTPUT */
51 /* */
52 /* None */
53 /* */
54 /* CALLS */
55 /* */
56 /* _ux_device_stack_transfer_request Transfer request */
57 /* _ux_device_class_hid_report_get Process Get_Report request */
58 /* _ux_device_class_hid_report_set Process Set_Report request */
59 /* _ux_device_class_hid_descriptor_send Send requested descriptor */
60 /* */
61 /* CALLED BY */
62 /* */
63 /* HID Class */
64 /* */
65 /* RELEASE HISTORY */
66 /* */
67 /* DATE NAME DESCRIPTION */
68 /* */
69 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
70 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
71 /* prefixed UX to MS_TO_TICK, */
72 /* used UX prefix to refer to */
73 /* TX symbols instead of using */
74 /* them directly, */
75 /* resulting in version 6.1 */
76 /* 11-09-2020 Chaoqiong Xiao Modified comment(s), */
77 /* fixed compile warnings 64b, */
78 /* resulting in version 6.1.2 */
79 /* 12-31-2020 Chaoqiong Xiao Modified comment(s), */
80 /* added Get/Set Protocol */
81 /* request support, */
82 /* resulting in version 6.1.3 */
83 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
84 /* added standalone support, */
85 /* resulting in version 6.1.10 */
86 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
87 /* resulting in version 6.1.11 */
88 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
89 /* fixed parameter/variable */
90 /* names conflict C++ keyword, */
91 /* resulting in version 6.1.12 */
92 /* */
93 /**************************************************************************/
_ux_device_class_hid_control_request(UX_SLAVE_CLASS_COMMAND * command)94 UINT _ux_device_class_hid_control_request(UX_SLAVE_CLASS_COMMAND *command)
95 {
96
97 UX_SLAVE_TRANSFER *transfer_request;
98 UX_SLAVE_DEVICE *device;
99 UX_SLAVE_CLASS *class_ptr;
100 ULONG request;
101 ULONG request_value;
102 ULONG request_index;
103 ULONG request_length;
104 ULONG descriptor_type;
105 UCHAR duration;
106 UX_SLAVE_CLASS_HID *hid;
107
108 /* Get the pointer to the device. */
109 device = &_ux_system_slave -> ux_system_slave_device;
110
111 /* Get the pointer to the transfer request associated with the control endpoint. */
112 transfer_request = &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request;
113
114 /* Extract all necessary fields of the request. */
115 request = *(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_REQUEST);
116 request_value = _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_VALUE);
117 request_index = _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_INDEX);
118 request_length = _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH);
119
120 /* Duration - upper byte of wValue. */
121 duration = *(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_VALUE + 1);
122
123 /* Get the class container. */
124 class_ptr = command -> ux_slave_class_command_class_ptr;
125
126 /* Get the storage instance from this class container. */
127 hid = (UX_SLAVE_CLASS_HID *) class_ptr -> ux_slave_class_instance;
128
129 /* Here we proceed only the standard request we know of at the device level. */
130 switch (request)
131 {
132
133 case UX_DEVICE_CLASS_HID_COMMAND_GET_REPORT:
134
135 /* Send the requested report to the host. */
136 _ux_device_class_hid_report_get(hid, request_value, request_index, request_length);
137 break;
138
139 case UX_DEVICE_CLASS_HID_COMMAND_SET_REPORT:
140
141 /* Extract the descriptor type. */
142 descriptor_type = (request_value & 0xff00) >> 8;
143
144 /* Get the requested report from the host. */
145 _ux_device_class_hid_report_set(hid, descriptor_type, request_index, request_length);
146 break;
147
148 case UX_GET_DESCRIPTOR:
149
150 /* Send the requested descriptor to the host. */
151 _ux_device_class_hid_descriptor_send(hid, request_value, request_index, request_length);
152 break;
153
154 case UX_DEVICE_CLASS_HID_COMMAND_GET_IDLE:
155 case UX_DEVICE_CLASS_HID_COMMAND_SET_IDLE:
156
157 /* Ignore Report ID for now. */
158
159 if (request == UX_DEVICE_CLASS_HID_COMMAND_GET_IDLE)
160 {
161
162 /* Send the idle rate. */
163 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR)hid -> ux_device_class_hid_event_idle_rate;
164 _ux_device_stack_transfer_request(transfer_request, 1, request_length);
165 }
166 else
167 {
168
169 /* Accept the idle rate if it changes. */
170 if ((UCHAR)hid -> ux_device_class_hid_event_idle_rate != duration)
171 {
172
173 hid -> ux_device_class_hid_event_idle_rate = duration;
174 if (duration == 0)
175 {
176
177 /* No need to repeat last report, no timeout. */
178 hid -> ux_device_class_hid_event_wait_timeout = UX_WAIT_FOREVER;
179 }
180 else
181 {
182
183 /* Calculate the timeout value. Weighted as 4ms. */
184 hid -> ux_device_class_hid_event_wait_timeout = (ULONG)UX_MS_TO_TICK((ULONG)duration << 2u);
185
186 /* Be sure to have a timeout that is not zero. */
187 if (hid -> ux_device_class_hid_event_wait_timeout == 0)
188 hid -> ux_device_class_hid_event_wait_timeout ++;
189
190 #if defined(UX_DEVICE_STANDALONE)
191
192 /* Restart event checking if no transfer in progress. */
193 if (hid -> ux_device_class_hid_event_state != UX_STATE_WAIT)
194 hid -> ux_device_class_hid_event_state = UX_STATE_RESET;
195 #else
196
197 /* Set an event to wake up the interrupt thread. */
198 _ux_device_event_flags_set(&hid -> ux_device_class_hid_event_flags_group, UX_DEVICE_CLASS_HID_NEW_IDLE_RATE, UX_OR);
199 #endif
200 }
201 }
202 }
203 break;
204
205 case UX_DEVICE_CLASS_HID_COMMAND_GET_PROTOCOL:
206
207 /* Send the protocol. */
208 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR)hid -> ux_device_class_hid_protocol;
209 _ux_device_stack_transfer_request(transfer_request, 1, request_length);
210 break;
211
212 case UX_DEVICE_CLASS_HID_COMMAND_SET_PROTOCOL:
213
214 /* Accept the protocol. */
215 hid -> ux_device_class_hid_protocol = request_value;
216 break;
217
218 default:
219
220 /* Unknown function. It's not handled. */
221 return(UX_ERROR);
222 }
223
224 /* It's handled. */
225 return(UX_SUCCESS);
226 }
227
228