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