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