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 /** 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 #if defined(UX_DEVICE_CLASS_HID_INTERRUPT_OUT_SUPPORT) && !defined(UX_DEVICE_STANDALONE)
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_device_class_hid_receiver_thread PORTABLE C */
38 /* 6.1.11 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function is the thread of the hid interrupt OUT endpoint */
46 /* */
47 /* INPUT */
48 /* */
49 /* hid_class Address of hid class */
50 /* container */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* None */
55 /* */
56 /* CALLS */
57 /* */
58 /* _ux_utility_event_flags_get Get event flags */
59 /* _ux_device_class_hid_event_get Get HID event */
60 /* _ux_device_stack_transfer_request Request transfer */
61 /* _ux_utility_memory_copy Copy memory */
62 /* _ux_utility_thread_suspend Suspend thread */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* ThreadX */
67 /* */
68 /* RELEASE HISTORY */
69 /* */
70 /* DATE NAME DESCRIPTION */
71 /* */
72 /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */
73 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
74 /* added receiver callback, */
75 /* resulting in version 6.1.11 */
76 /* */
77 /**************************************************************************/
_ux_device_class_hid_receiver_thread(ULONG hid_instance)78 VOID _ux_device_class_hid_receiver_thread(ULONG hid_instance)
79 {
80
81 UX_SLAVE_CLASS_HID *hid;
82 UX_SLAVE_DEVICE *device;
83 UX_DEVICE_CLASS_HID_RECEIVER *receiver;
84 UX_DEVICE_CLASS_HID_RECEIVED_EVENT *pos;
85 UCHAR *next_pos;
86 UX_SLAVE_TRANSFER *transfer;
87 UINT status;
88 UCHAR *buffer;
89 ULONG temp;
90
91
92 /* Cast properly the hid instance. */
93 UX_THREAD_EXTENSION_PTR_GET(hid, UX_SLAVE_CLASS_HID, hid_instance)
94
95 /* Get the pointer to the device. */
96 device = &_ux_system_slave -> ux_system_slave_device;
97
98 /* Get receiver instance. */
99 receiver = hid -> ux_device_class_hid_receiver;
100
101 /* This thread runs forever but can be suspended or resumed. */
102 while(1)
103 {
104
105 /* Check device state. */
106 if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
107 {
108
109 /* We need to suspend ourselves. We will be resumed by the device enumeration module. */
110 _ux_utility_thread_suspend(&receiver -> ux_device_class_hid_receiver_thread);
111 continue;
112 }
113
114 /* Check if there is buffer available. */
115 pos = receiver -> ux_device_class_hid_receiver_event_save_pos;
116 if (pos -> ux_device_class_hid_received_event_length != 0)
117 {
118
119 /* Wait before check again. */
120 status = _ux_utility_event_flags_get(
121 &hid -> ux_device_class_hid_event_flags_group,
122 UX_DEVICE_CLASS_HID_RECEIVER_RESTART,
123 UX_OR_CLEAR, &temp, 100);
124 if (status != UX_SUCCESS)
125 {
126
127 /* Keep checking before a good state. */
128 continue;
129 }
130 }
131
132 /* Event buffer available, issue request to get data. */
133 transfer = &hid -> ux_device_class_hid_read_endpoint -> ux_slave_endpoint_transfer_request;
134
135 /* Protect read. */
136 _ux_device_mutex_on(&hid -> ux_device_class_hid_read_mutex);
137
138 /* Issue the transfer request. */
139 status = _ux_device_stack_transfer_request(transfer,
140 receiver -> ux_device_class_hid_receiver_event_buffer_size,
141 receiver -> ux_device_class_hid_receiver_event_buffer_size);
142
143 /* Check status and ignore ZLPs. */
144 if ((status != UX_SUCCESS) ||
145 (transfer -> ux_slave_transfer_request_actual_length == 0))
146 {
147 _ux_device_mutex_off(&hid -> ux_device_class_hid_read_mutex);
148 continue;
149 }
150
151 /* Save received event data and length. */
152 buffer = (UCHAR *)&pos -> ux_device_class_hid_received_event_data;
153 temp = transfer -> ux_slave_transfer_request_actual_length;
154 _ux_utility_memory_copy(buffer,
155 transfer -> ux_slave_transfer_request_data_pointer,
156 temp); /* Use case of memcpy is verified. */
157
158 /* Unprotect read. */
159 _ux_device_mutex_off(&hid -> ux_device_class_hid_read_mutex);
160
161 /* Advance the save position. */
162 next_pos = (UCHAR *)pos + receiver -> ux_device_class_hid_receiver_event_buffer_size + sizeof(ULONG);
163 if (next_pos >= (UCHAR *)receiver -> ux_device_class_hid_receiver_events_end)
164 next_pos = (UCHAR *)receiver -> ux_device_class_hid_receiver_events;
165 receiver -> ux_device_class_hid_receiver_event_save_pos = (UX_DEVICE_CLASS_HID_RECEIVED_EVENT *)next_pos;
166
167 /* Save received data length (it's valid now). */
168 pos -> ux_device_class_hid_received_event_length = temp;
169
170 /* Notify application that a event is received. */
171 if (receiver -> ux_device_class_hid_receiver_event_callback)
172 receiver -> ux_device_class_hid_receiver_event_callback(hid);
173 }
174 }
175 #endif
176