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 static inline
34 #else
35 VOID _ux_host_class_printer_name_parse(UX_HOST_CLASS_PRINTER *printer, UCHAR *descriptor_buffer, ULONG descriptor_length);
36 #endif
_ux_host_class_printer_name_parse(UX_HOST_CLASS_PRINTER * printer,UCHAR * descriptor_buffer,ULONG descriptor_length)37 VOID _ux_host_class_printer_name_parse(UX_HOST_CLASS_PRINTER *printer, UCHAR *descriptor_buffer, ULONG descriptor_length)
38 {
39 ULONG           length;
40 UCHAR *         printer_name_buffer;
41 UCHAR *         printer_name;
42 UINT            printer_name_length;
43 
44     /* Cannot use descriptor buffer, so copy it to 1284 buffer.  */
45     printer_name_buffer =  descriptor_buffer;
46 
47     /* Retrieve the printer name which is a USHORT at the beginning of the returned buffer.  */
48     length =  (USHORT)_ux_utility_short_get_big_endian(printer_name_buffer);
49     if (length < descriptor_length)
50         descriptor_length = length;
51 
52     /* Point the name buffer after the length.  */
53     printer_name_buffer +=  2;
54 
55     /* Parse the name for a tag which is in the form DES: or DESCRIPTOR:  */
56     while (descriptor_length != 0)
57     {
58 
59         if (descriptor_length > 12)
60         {
61 
62             /* Compare the current pointer position with the DESCRIPTOR: tag.  */
63             if (_ux_utility_memory_compare(printer_name_buffer, UX_HOST_CLASS_PRINTER_TAG_DESCRIPTION, 12) == UX_SUCCESS)
64             {
65 
66                 printer_name_buffer +=  12;
67                 descriptor_length =  (USHORT)(descriptor_length - 12);
68                 break;
69             }
70         }
71 
72         if (descriptor_length > 4)
73         {
74 
75             /* Compare the current pointer position with the DES: tag.  */
76             if (_ux_utility_memory_compare(printer_name_buffer, UX_HOST_CLASS_PRINTER_TAG_DES, 4) == UX_SUCCESS)
77             {
78 
79                 printer_name_buffer +=  4;
80                 descriptor_length = (USHORT)(descriptor_length - 4);
81                 break;
82             }
83         }
84 
85         /* And reduce the remaining length by 1.  */
86         descriptor_length--;
87 
88         /* Increment the descriptor pointer.  */
89         printer_name_buffer++;
90     }
91 
92     /* If the length remaining is 0, we have not found the descriptor tag we wanted.  */
93     if (descriptor_length == 0)
94     {
95 
96         /* Use the generic USB printer name.  */
97         _ux_utility_memory_copy(printer -> ux_host_class_printer_name, UX_HOST_CLASS_PRINTER_GENERIC_NAME, 11); /* Use case of memcpy is verified. */
98     }
99     else
100     {
101 
102         /* We have found a tag and the name is right after delimited by ; or a 0.  */
103         printer_name =  printer -> ux_host_class_printer_name;
104         printer_name_length =  UX_HOST_CLASS_PRINTER_NAME_LENGTH;
105 
106         /* Parse the name and only copy the name until the max length is reached
107             or the delimiter is reached.  */
108         while ((descriptor_length--) && (printer_name_length--))
109         {
110 
111             /* Check for the delimiter.  */
112             if((*printer_name_buffer == 0) || (*printer_name_buffer == ';'))
113                 break;
114             else
115                 /* Copy the name of the printer to the printer instance character
116                     by character.  */
117                 *printer_name++ =  *printer_name_buffer++;
118         }
119     }
120 }
121 
122 /**************************************************************************/
123 /*                                                                        */
124 /*  FUNCTION                                               RELEASE        */
125 /*                                                                        */
126 /*    _ux_host_class_printer_name_get                     PORTABLE C      */
127 /*                                                           6.3.0        */
128 /*  AUTHOR                                                                */
129 /*                                                                        */
130 /*    Chaoqiong Xiao, Microsoft Corporation                               */
131 /*                                                                        */
132 /*  DESCRIPTION                                                           */
133 /*                                                                        */
134 /*    This function obtains the printer name. The name is used by the     */
135 /*    application layer to identify the printer and loads its handler.    */
136 /*                                                                        */
137 /*  INPUT                                                                 */
138 /*                                                                        */
139 /*    printer                               Pointer to printer class      */
140 /*                                                                        */
141 /*  OUTPUT                                                                */
142 /*                                                                        */
143 /*    Completion Status                                                   */
144 /*                                                                        */
145 /*  CALLS                                                                 */
146 /*                                                                        */
147 /*    _ux_host_stack_transfer_request       Process transfer request      */
148 /*    _ux_utility_memory_allocate           Allocate memory block         */
149 /*    _ux_utility_memory_compare            Compare memory block          */
150 /*    _ux_utility_memory_copy               Copy memory block             */
151 /*    _ux_utility_memory_free               Free memory block             */
152 /*    _ux_utility_short_get_big_endian      Get 16-bit value              */
153 /*                                                                        */
154 /*  CALLED BY                                                             */
155 /*                                                                        */
156 /*    Printer Class                                                       */
157 /*                                                                        */
158 /*  RELEASE HISTORY                                                       */
159 /*                                                                        */
160 /*    DATE              NAME                      DESCRIPTION             */
161 /*                                                                        */
162 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
163 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
164 /*                                            verified memset and memcpy  */
165 /*                                            cases,                      */
166 /*                                            resulting in version 6.1    */
167 /*  02-02-2021     Chaoqiong Xiao           Modified comment(s),          */
168 /*                                            supported interface other   */
169 /*                                            than number zero,           */
170 /*                                            resulting in version 6.1.4  */
171 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
172 /*                                            added standalone support,   */
173 /*                                            resulting in version 6.1.10 */
174 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
175 /*                                            fixed parameter/variable    */
176 /*                                            names conflict C++ keyword, */
177 /*                                            resulting in version 6.1.12 */
178 /*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
179 /*                                            fixed compile warnings,     */
180 /*                                            resulting in version 6.3.0  */
181 /*                                                                        */
182 /**************************************************************************/
_ux_host_class_printer_name_get(UX_HOST_CLASS_PRINTER * printer)183 UINT  _ux_host_class_printer_name_get(UX_HOST_CLASS_PRINTER *printer)
184 {
185 
186 UCHAR *         descriptor_buffer;
187 UX_INTERFACE    *interface_ptr;
188 UX_ENDPOINT     *control_endpoint;
189 UX_TRANSFER     *transfer_request;
190 #if !defined(UX_HOST_STANDALONE)
191 UINT            status;
192 #endif
193 
194     /* If trace is enabled, insert this event into the trace buffer.  */
195     UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_PRINTER_NAME_GET, printer, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
196 
197     /* We need to get the default control endpoint transfer request pointer.  */
198     control_endpoint =  &printer -> ux_host_class_printer_device -> ux_device_control_endpoint;
199     transfer_request =  &control_endpoint -> ux_endpoint_transfer_request;
200 
201     /* Need to allocate memory for the 1284 descriptor.  */
202     descriptor_buffer =  _ux_utility_memory_allocate(UX_SAFE_ALIGN, UX_CACHE_SAFE_MEMORY, UX_HOST_CLASS_PRINTER_DESCRIPTOR_LENGTH);
203     if(descriptor_buffer == UX_NULL)
204         return(UX_MEMORY_INSUFFICIENT);
205 
206     /* Need interface for wIndex.  */
207     interface_ptr = printer -> ux_host_class_printer_interface;
208 
209     /* Create a transfer request for the GET_DEVICE_ID request.  */
210     transfer_request -> ux_transfer_request_data_pointer =      descriptor_buffer;
211     transfer_request -> ux_transfer_request_requested_length =  UX_HOST_CLASS_PRINTER_DESCRIPTOR_LENGTH;
212     transfer_request -> ux_transfer_request_function =          UX_HOST_CLASS_PRINTER_GET_DEVICE_ID;
213     transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
214     transfer_request -> ux_transfer_request_value =             0; /* Do not support multiple configuration for now.  */
215     transfer_request -> ux_transfer_request_index =             ((UINT)interface_ptr -> ux_interface_descriptor.bInterfaceNumber  << 8) |
216                                                                 (interface_ptr -> ux_interface_descriptor.bAlternateSetting     );
217 
218 #if defined(UX_HOST_STANDALONE)
219     printer -> ux_host_class_printer_allocated = descriptor_buffer;
220     UX_TRANSFER_STATE_RESET(transfer_request);
221     return(UX_SUCCESS);
222 #else
223 
224     /* Send request to HCD layer.  */
225     status =  _ux_host_stack_transfer_request(transfer_request);
226 
227     /* Check for correct transfer. We do not check for entire length as it may vary.  */
228     if(status == UX_SUCCESS)
229     {
230 
231         _ux_host_class_printer_name_parse(printer, descriptor_buffer,
232                                     UX_HOST_CLASS_PRINTER_DESCRIPTOR_LENGTH);
233     }
234 
235     /* Free all used resources.  */
236     _ux_utility_memory_free(descriptor_buffer);
237 
238     /* Return completion status.  */
239     return(status);
240 
241 #endif
242 }
243 
244 /**************************************************************************/
245 /*                                                                        */
246 /*  FUNCTION                                               RELEASE        */
247 /*                                                                        */
248 /*    _uxe_host_class_printer_name_get                    PORTABLE C      */
249 /*                                                           6.3.0        */
250 /*  AUTHOR                                                                */
251 /*                                                                        */
252 /*    Yajun Xia, Microsoft Corporation                                    */
253 /*                                                                        */
254 /*  DESCRIPTION                                                           */
255 /*                                                                        */
256 /*    This function checks errors in printer name get function call.      */
257 /*                                                                        */
258 /*  INPUT                                                                 */
259 /*                                                                        */
260 /*    printer                               Pointer to printer class      */
261 /*                                                                        */
262 /*  OUTPUT                                                                */
263 /*                                                                        */
264 /*    Completion Status                                                   */
265 /*                                                                        */
266 /*  CALLS                                                                 */
267 /*                                                                        */
268 /*    _ux_host_class_printer_name_get       Obtains the printer name      */
269 /*                                                                        */
270 /*  CALLED BY                                                             */
271 /*                                                                        */
272 /*    Application                                                         */
273 /*                                                                        */
274 /*  RELEASE HISTORY                                                       */
275 /*                                                                        */
276 /*    DATE              NAME                      DESCRIPTION             */
277 /*                                                                        */
278 /*  10-31-2023        Yajun xia             Initial Version 6.3.0         */
279 /*                                                                        */
280 /**************************************************************************/
_uxe_host_class_printer_name_get(UX_HOST_CLASS_PRINTER * printer)281 UINT  _uxe_host_class_printer_name_get(UX_HOST_CLASS_PRINTER *printer)
282 {
283 
284     /* Sanity checks.  */
285     if (printer == UX_NULL)
286         return(UX_INVALID_PARAMETER);
287 
288     return(_ux_host_class_printer_name_get(printer));
289 }