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 #if defined(UX_DEVICE_STANDALONE)
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_device_class_hid_tasks_run PORTABLE C */
37 /* 6.3.0 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function is the background task of the hid. */
45 /* */
46 /* It's for standalone mode. */
47 /* */
48 /* INPUT */
49 /* */
50 /* hid_class Address of hid class */
51 /* container */
52 /* */
53 /* OUTPUT */
54 /* */
55 /* State machine status */
56 /* UX_STATE_EXIT Device not configured */
57 /* UX_STATE_IDLE No interrupt transfer running */
58 /* UX_STATE_WAIT Interrupt IN transfer running */
59 /* */
60 /* CALLS */
61 /* */
62 /* _ux_device_class_hid_event_get Get HID event */
63 /* _ux_device_stack_transfer_run Run transfer state machine */
64 /* _ux_utility_memory_copy Copy memory */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* USBX Device Stack */
69 /* */
70 /* RELEASE HISTORY */
71 /* */
72 /* DATE NAME DESCRIPTION */
73 /* */
74 /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */
75 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
76 /* added zero copy support, */
77 /* resulting in version 6.3.0 */
78 /* */
79 /**************************************************************************/
_ux_device_class_hid_tasks_run(VOID * instance)80 UINT _ux_device_class_hid_tasks_run(VOID *instance)
81 {
82
83 UX_SLAVE_CLASS_HID *hid;
84 UX_SLAVE_DEVICE *device;
85 UX_DEVICE_CLASS_HID_EVENT *hid_event;
86 UX_SLAVE_TRANSFER *trans;
87 ULONG tick, elapsed;
88 UINT status;
89
90
91 /* Get HID instance. */
92 hid = (UX_SLAVE_CLASS_HID *) instance;
93
94 /* Get the pointer to the device. */
95 device = &_ux_system_slave -> ux_system_slave_device;
96
97 /* Check if the device is configured. */
98 if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
99 {
100 hid -> ux_device_class_hid_event_state = UX_STATE_EXIT;
101 return(UX_STATE_EXIT);
102 }
103
104 #if defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT)
105 if (hid -> ux_device_class_hid_receiver)
106 hid -> ux_device_class_hid_receiver -> ux_device_class_hid_receiver_tasks_run(hid);
107 #endif
108
109 /* Get access to current event instance. */
110 hid_event = &hid -> ux_device_class_hid_event;
111
112 /* Run HID state machine. */
113 switch(hid -> ux_device_class_hid_event_state)
114 {
115 case UX_STATE_EXIT:
116
117 /* There is nothing to do in this state. */
118 return (UX_STATE_EXIT);
119
120 case UX_STATE_RESET:
121
122 /* Start timeout waiting. */
123 hid -> ux_device_class_hid_event_wait_start = _ux_utility_time_get();
124 hid -> ux_device_class_hid_event_state = UX_STATE_IDLE;
125
126 /* Fall through. */
127 case UX_STATE_IDLE:
128
129 /* Check if there is event ready. */
130 status = _ux_device_class_hid_event_check(hid, &hid_event);
131
132 /* If there is no event, check idle rate. */
133 if (status != UX_SUCCESS)
134 {
135
136 /* Check idle rate setting. */
137 if (hid -> ux_device_class_hid_event_wait_timeout == UX_WAIT_FOREVER)
138 {
139
140 /* There is no background idle report, keep waiting. */
141 return(UX_STATE_IDLE);
142 }
143
144 /* Check wait timeout. */
145 tick = _ux_utility_time_get();
146 elapsed = _ux_utility_time_elapsed(hid -> ux_device_class_hid_event_wait_start, tick);
147 if (elapsed < hid -> ux_device_class_hid_event_wait_timeout)
148 {
149
150 /* Keep waiting. */
151 return(UX_STATE_IDLE);
152 }
153
154 /* Send the last event in buffer. */
155 }
156
157 /* Prepare the request to send event. */
158 trans = &hid -> ux_device_class_hid_interrupt_endpoint ->
159 ux_slave_endpoint_transfer_request;
160
161 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_HID_ZERO_COPY)
162
163 /* Directly use event buffer for transfer. */
164 trans -> ux_slave_transfer_request_data_pointer =
165 hid_event -> ux_device_class_hid_event_buffer;
166 #else
167
168 /* Copy event data to endpoint buffer. */
169 _ux_utility_memory_copy(trans -> ux_slave_transfer_request_data_pointer,
170 UX_DEVICE_CLASS_HID_EVENT_BUFFER(hid_event),
171 hid_event -> ux_device_class_hid_event_length); /* Use case of memcpy is verified. */
172 #endif
173
174 trans -> ux_slave_transfer_request_requested_length =
175 hid_event -> ux_device_class_hid_event_length;
176 UX_SLAVE_TRANSFER_STATE_RESET(trans);
177 hid -> ux_device_class_hid_event_state = UX_STATE_WAIT;
178
179 /* Fall through. */
180 case UX_STATE_WAIT:
181
182 /* Run transfer state machine. */
183 trans = &hid -> ux_device_class_hid_interrupt_endpoint ->
184 ux_slave_endpoint_transfer_request;
185 status = _ux_device_stack_transfer_run(trans,
186 hid_event -> ux_device_class_hid_event_length,
187 hid_event -> ux_device_class_hid_event_length);
188
189 /* Any error or success case. */
190 if (status <= UX_STATE_NEXT)
191 {
192
193 /* Event handled and the tail should be freed. */
194 _ux_device_class_hid_event_free(hid);
195
196 /* Next round. */
197 hid -> ux_device_class_hid_event_state = UX_STATE_RESET;
198 return(UX_STATE_IDLE);
199 }
200
201 /* Wait. */
202 return(UX_STATE_WAIT);
203
204 default:
205
206 /* Just go back to normal state. */
207 hid -> ux_device_class_hid_event_state = UX_STATE_RESET;
208 return(UX_STATE_IDLE);
209 }
210 }
211 #endif
212