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 /** Printer Class */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 /* Include necessary system files. */
24
25 #define UX_SOURCE_CODE
26
27 #include "ux_api.h"
28 #include "ux_host_class_printer.h"
29 #include "ux_host_stack.h"
30
31
32 #if defined(UX_HOST_STANDALONE)
33 #define UX_HOST_CLASS_PRINTER_ENUM_START (UX_STATE_WAIT)
34 #define UX_HOST_CLASS_PRINTER_ENUM_IDLE (UX_STATE_IDLE)
35
36 #define UX_HOST_CLASS_PRINTER_ENUM_NAME_GET (UX_STATE_STACK_STEP + 0)
37 #define UX_HOST_CLASS_PRINTER_ENUM_NAME_PARSE (UX_STATE_STACK_STEP + 1)
38 #define UX_HOST_CLASS_PRINTER_ENUM_TRANSFER (UX_STATE_STACK_STEP + 2)
39 #define UX_HOST_CLASS_PRINTER_ENUM_DONE (UX_STATE_STACK_STEP + 3)
40
41 extern VOID _ux_host_class_printer_name_parse(UX_HOST_CLASS_PRINTER *printer,
42 UCHAR *descriptor_buffer, ULONG descriptor_length);
43
44 static inline UINT _ux_host_class_printer_activate_wait(UX_HOST_CLASS_COMMAND *command);
45 #endif
46
47 /**************************************************************************/
48 /* */
49 /* FUNCTION RELEASE */
50 /* */
51 /* _ux_host_class_printer_entry PORTABLE C */
52 /* 6.1.12 */
53 /* AUTHOR */
54 /* */
55 /* Chaoqiong Xiao, Microsoft Corporation */
56 /* */
57 /* DESCRIPTION */
58 /* */
59 /* This function is the entry point of the printer class. It will be */
60 /* called by the USBX stack enumeration module when there is a new */
61 /* printer on the bus or when the USB printer is removed. */
62 /* */
63 /* INPUT */
64 /* */
65 /* command Printer class command */
66 /* */
67 /* OUTPUT */
68 /* */
69 /* Completion Status */
70 /* */
71 /* CALLS */
72 /* */
73 /* _ux_host_class_printer_activate Activate printer class */
74 /* _ux_host_class_printer_deactivate Deactivate printer class */
75 /* */
76 /* CALLED BY */
77 /* */
78 /* Printer Class */
79 /* */
80 /* RELEASE HISTORY */
81 /* */
82 /* DATE NAME DESCRIPTION */
83 /* */
84 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
85 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
86 /* resulting in version 6.1 */
87 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
88 /* added standalone support, */
89 /* resulting in version 6.1.10 */
90 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
91 /* removed compile warning, */
92 /* fixed parameter/variable */
93 /* names conflict C++ keyword, */
94 /* resulting in version 6.1.12 */
95 /* */
96 /**************************************************************************/
_ux_host_class_printer_entry(UX_HOST_CLASS_COMMAND * command)97 UINT _ux_host_class_printer_entry(UX_HOST_CLASS_COMMAND *command)
98 {
99
100 UINT status;
101
102
103 /* The command request will tell us we need to do here, either a enumeration
104 query, an activation or a deactivation. */
105 switch (command -> ux_host_class_command_request)
106 {
107
108 case UX_HOST_CLASS_COMMAND_QUERY:
109
110 /* The query command is used to let the stack enumeration process know if we want to own
111 this device or not. */
112 if((command -> ux_host_class_command_usage == UX_HOST_CLASS_COMMAND_USAGE_CSP) &&
113 (command -> ux_host_class_command_class == UX_HOST_CLASS_PRINTER_CLASS))
114 return(UX_SUCCESS);
115 else
116 return(UX_NO_CLASS_MATCH);
117
118 case UX_HOST_CLASS_COMMAND_ACTIVATE:
119
120 /* The activate command is used when the device inserted has found a parent and
121 is ready to complete the enumeration. */
122 status = _ux_host_class_printer_activate(command);
123 return(status);
124
125 #if defined(UX_HOST_STANDALONE)
126 case UX_HOST_CLASS_COMMAND_ACTIVATE_WAIT:
127 status = _ux_host_class_printer_activate_wait(command);
128 return(status);
129 #endif
130
131 case UX_HOST_CLASS_COMMAND_DEACTIVATE:
132
133 /* The deactivate command is used when the device has been extracted either
134 directly or when its parents has been extracted. */
135 status = _ux_host_class_printer_deactivate(command);
136 return(status);
137
138 default:
139
140 /* If trace is enabled, insert this event into the trace buffer. */
141 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_FUNCTION_NOT_SUPPORTED, 0, 0, 0, UX_TRACE_ERRORS, 0, 0)
142
143 return(UX_FUNCTION_NOT_SUPPORTED);
144 }
145 }
146
147 #if defined(UX_HOST_STANDALONE)
_ux_host_class_printer_activate_wait(UX_HOST_CLASS_COMMAND * command)148 static inline UINT _ux_host_class_printer_activate_wait(UX_HOST_CLASS_COMMAND *command)
149 {
150 UX_INTERFACE *interface_ptr;
151 UX_HOST_CLASS_PRINTER *printer;
152 UX_ENDPOINT *control_endpoint;
153 UX_TRANSFER *transfer;
154 UINT status;
155
156 /* Get the instance for this class. */
157 interface_ptr = (UX_INTERFACE *)command -> ux_host_class_command_container;
158
159 /* Sanity check. */
160 if (interface_ptr == UX_NULL)
161 return(UX_STATE_EXIT);
162
163 printer = (UX_HOST_CLASS_PRINTER *) interface_ptr -> ux_interface_class_instance;
164
165 /* Sanity check. */
166 if (printer == UX_NULL)
167 return(UX_STATE_EXIT);
168
169 switch(printer -> ux_host_class_printer_enum_state)
170 {
171 case UX_HOST_CLASS_PRINTER_ENUM_START:
172 status = _ux_host_class_printer_endpoints_get(printer);
173 if (status != UX_SUCCESS)
174 {
175 printer -> ux_host_class_printer_status = status;
176 printer -> ux_host_class_printer_enum_state =
177 UX_HOST_CLASS_PRINTER_ENUM_DONE;
178 return(UX_STATE_WAIT);
179 }
180
181 /* Fall through. */
182 case UX_HOST_CLASS_PRINTER_ENUM_NAME_GET:
183 status = _ux_host_class_printer_name_get(printer);
184 if (status != UX_SUCCESS)
185 {
186 printer -> ux_host_class_printer_status = status;
187 printer -> ux_host_class_printer_enum_state =
188 UX_HOST_CLASS_PRINTER_ENUM_DONE;
189 return(UX_STATE_WAIT);
190 }
191
192 /* Next: transfer -> parse name. */
193 printer -> ux_host_class_printer_enum_state =
194 UX_HOST_CLASS_PRINTER_ENUM_TRANSFER;
195 printer -> ux_host_class_printer_next_state =
196 UX_HOST_CLASS_PRINTER_ENUM_NAME_PARSE;
197
198 /* Fall through. */
199 case UX_HOST_CLASS_PRINTER_ENUM_TRANSFER:
200
201 /* We need to get the default control endpoint transfer request pointer. */
202 control_endpoint = &printer -> ux_host_class_printer_device -> ux_device_control_endpoint;
203 transfer = &control_endpoint -> ux_endpoint_transfer_request;
204
205 status = _ux_host_stack_transfer_run(transfer);
206
207 /* Transfer finished any way. */
208 if (status < UX_STATE_WAIT)
209 {
210
211 /* Error. */
212 if (transfer -> ux_transfer_request_completion_code != UX_SUCCESS)
213 {
214 printer -> ux_host_class_printer_status = status;
215 printer -> ux_host_class_printer_enum_state =
216 UX_HOST_CLASS_PRINTER_ENUM_DONE;
217 return(UX_STATE_WAIT);
218 }
219
220 /* Next state. */
221 printer -> ux_host_class_printer_enum_state =
222 printer -> ux_host_class_printer_next_state;
223
224 return(UX_STATE_WAIT);
225 }
226
227 /* Wait transfer. */
228 return(UX_STATE_WAIT);
229
230 case UX_HOST_CLASS_PRINTER_ENUM_NAME_PARSE:
231
232 /* We need to get the default control endpoint transfer request pointer. */
233 control_endpoint = &printer -> ux_host_class_printer_device -> ux_device_control_endpoint;
234 transfer = &control_endpoint -> ux_endpoint_transfer_request;
235
236 _ux_host_class_printer_name_parse(printer,
237 transfer -> ux_transfer_request_data_pointer,
238 transfer -> ux_transfer_request_actual_length);
239
240 /* Fall through. */
241 case UX_HOST_CLASS_PRINTER_ENUM_DONE:
242
243 /* Free allocated resources. */
244 if (printer -> ux_host_class_printer_allocated)
245 {
246 _ux_utility_memory_free(printer -> ux_host_class_printer_allocated);
247 printer -> ux_host_class_printer_allocated = UX_NULL;
248 }
249
250 /* Check status. */
251 if (printer -> ux_host_class_printer_status != UX_SUCCESS)
252 {
253
254 /* On error, free resources. */
255 _ux_host_stack_class_instance_destroy(
256 printer -> ux_host_class_printer_class, (VOID *) printer);
257 interface_ptr -> ux_interface_class_instance = UX_NULL;
258 _ux_utility_memory_free(printer);
259 return(UX_STATE_ERROR);
260 }
261
262 /* Success. */
263
264 /* Mark the printer as live now. */
265 printer -> ux_host_class_printer_state = UX_HOST_CLASS_INSTANCE_LIVE;
266
267 /* If all is fine and the device is mounted, we may need to inform the application
268 if a function has been programmed in the system structure. */
269 if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
270 {
271
272 /* Call system change function. */
273 _ux_system_host -> ux_system_host_change_function(UX_DEVICE_INSERTION, printer -> ux_host_class_printer_class, (VOID *) printer);
274 }
275
276 /* If trace is enabled, insert this event into the trace buffer. */
277 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_PRINTER_ACTIVATE, printer, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
278
279 /* If trace is enabled, register this object. */
280 UX_TRACE_OBJECT_REGISTER(UX_TRACE_HOST_OBJECT_TYPE_INTERFACE, printer, 0, 0, 0)
281
282 /* Return success. */
283 printer -> ux_host_class_printer_enum_state = UX_STATE_IDLE;
284 return(UX_STATE_NEXT);
285
286 default: /* reset, idle, error ... */
287 break;
288 }
289
290 /* Just next phase. */
291 return(UX_STATE_NEXT);
292 }
293 #endif
294