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 }