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 Printer 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_printer.h"
28 #include "ux_device_stack.h"
29
30
31 #if defined(UX_DEVICE_STANDALONE)
32
33
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _ux_device_class_printer_read_run PORTABLE C */
39 /* 6.2.0 */
40 /* AUTHOR */
41 /* */
42 /* Yajun Xia, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function reads from the Printer class. */
47 /* */
48 /* It's for standalone mode. */
49 /* */
50 /* INPUT */
51 /* */
52 /* printer Address of printer class */
53 /* instance */
54 /* buffer Pointer to buffer to save */
55 /* received data */
56 /* requested_length Length of bytes to read */
57 /* actual_length Pointer to save number of */
58 /* bytes read */
59 /* */
60 /* OUTPUT */
61 /* */
62 /* State machine Status to check */
63 /* UX_STATE_NEXT Transfer done, to next state */
64 /* UX_STATE_EXIT Abnormal, to reset state */
65 /* (others) Keep running, waiting */
66 /* */
67 /* CALLS */
68 /* */
69 /* _ux_device_stack_transfer_run Transfer request */
70 /* _ux_utility_memory_copy Copy memory */
71 /* */
72 /* CALLED BY */
73 /* */
74 /* Application */
75 /* */
76 /* RELEASE HISTORY */
77 /* */
78 /* DATE NAME DESCRIPTION */
79 /* */
80 /* 10-31-2022 Yajun xia Initial Version 6.2.0 */
81 /* */
82 /**************************************************************************/
_ux_device_class_printer_read_run(UX_DEVICE_CLASS_PRINTER * printer,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)83 UINT _ux_device_class_printer_read_run(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
84 ULONG requested_length, ULONG *actual_length)
85 {
86
87 UX_SLAVE_ENDPOINT *endpoint;
88 UX_SLAVE_DEVICE *device;
89 UX_SLAVE_TRANSFER *transfer_request;
90 ULONG max_transfer_length;
91 UINT status = UX_SUCCESS;
92
93 /* If trace is enabled, insert this event into the trace buffer. */
94 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_PRINTER_READ, printer, buffer, requested_length, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
95
96 /* Get the pointer to the device. */
97 device = &_ux_system_slave -> ux_system_slave_device;
98
99 /* As long as the device is in the CONFIGURED state. */
100 if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
101 {
102
103 /* Error trap. */
104 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN);
105
106 /* If trace is enabled, insert this event into the trace buffer. */
107 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_CONFIGURATION_HANDLE_UNKNOWN, device, 0, 0, UX_TRACE_ERRORS, 0, 0)
108
109 /* Cannot proceed with command, the interface is down. */
110 printer -> ux_device_class_printer_read_state = UX_STATE_RESET;
111 printer -> ux_device_class_printer_read_status = UX_CONFIGURATION_HANDLE_UNKNOWN;
112
113 return(UX_STATE_EXIT);
114 }
115
116 /* Locate the endpoint. */
117 endpoint = printer -> ux_device_class_printer_endpoint_out;
118
119 /* All Printer reading are on the endpoint OUT, from the host. */
120 transfer_request = &endpoint -> ux_slave_endpoint_transfer_request;
121
122 #if (UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1) && defined(UX_DEVICE_CLASS_PRINTER_ZERO_COPY)
123
124 /* Run the transfer state machine. */
125 if (printer -> ux_device_class_printer_read_state == UX_STATE_RESET)
126 {
127
128 /* If trace is enabled, insert this event into the trace buffer. */
129 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_PRINTER_READ, printer, buffer, requested_length, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
130
131 printer -> ux_device_class_printer_read_state = UX_DEVICE_CLASS_PRINTER_READ_START;
132 printer -> ux_device_class_printer_read_status = UX_TRANSFER_NO_ANSWER;
133 transfer_request -> ux_slave_transfer_request_data_pointer = buffer;
134 UX_SLAVE_TRANSFER_STATE_RESET(transfer_request);
135 }
136
137 /* Issue the transfer request. */
138 max_transfer_length = requested_length;
139 status = _ux_device_stack_transfer_run(transfer_request, max_transfer_length, max_transfer_length);
140
141 /* Error case. */
142 if (status < UX_STATE_NEXT)
143 {
144
145 printer -> ux_device_class_printer_read_state = UX_STATE_RESET;
146 printer -> ux_device_class_printer_read_status =
147 transfer_request -> ux_slave_transfer_request_completion_code;
148 return(UX_STATE_ERROR);
149 }
150
151 /* Success case. */
152 if (status == UX_STATE_NEXT)
153 {
154
155 /* Last transfer status. */
156 printer -> ux_device_class_printer_read_status =
157 transfer_request -> ux_slave_transfer_request_completion_code;
158
159 /* Update actual length. */
160 *actual_length = transfer_request -> ux_slave_transfer_request_actual_length;
161
162 /* It's done. */
163 printer -> ux_device_class_printer_read_state = UX_STATE_RESET;
164 }
165
166 return(status);
167 #else
168
169 /* Handle state cases. */
170 switch(printer -> ux_device_class_printer_read_state)
171 {
172 case UX_STATE_RESET:
173
174 /* If trace is enabled, insert this event into the trace buffer. */
175 UX_TRACE_IN_LINE_INSERT(UX_TRACE_DEVICE_CLASS_PRINTER_READ, printer, buffer, requested_length, 0, UX_TRACE_DEVICE_CLASS_EVENTS, 0, 0)
176
177 printer -> ux_device_class_printer_read_state = UX_DEVICE_CLASS_PRINTER_READ_START;
178 printer -> ux_device_class_printer_read_status = UX_TRANSFER_NO_ANSWER;
179 printer -> ux_device_class_printer_read_buffer = buffer;
180 printer -> ux_device_class_printer_read_requested_length = requested_length;
181 printer -> ux_device_class_printer_read_actual_length = 0;
182
183 /* Fall through. */
184 case UX_DEVICE_CLASS_PRINTER_READ_START:
185
186 /* Get remaining transfer length. */
187 requested_length = printer -> ux_device_class_printer_read_requested_length -
188 printer -> ux_device_class_printer_read_actual_length;
189
190 /* There is nothing remaining, it's done. */
191 if (requested_length == 0)
192 {
193 *actual_length = printer -> ux_device_class_printer_read_actual_length;
194 printer -> ux_device_class_printer_read_state = UX_STATE_RESET;
195 printer -> ux_device_class_printer_read_status = UX_SUCCESS;
196 return(UX_STATE_NEXT);
197 }
198
199 printer -> ux_device_class_printer_read_transfer_length = requested_length;
200
201 /* Next state. */
202 printer -> ux_device_class_printer_read_state = UX_DEVICE_CLASS_PRINTER_READ_WAIT;
203 UX_SLAVE_TRANSFER_STATE_RESET(transfer_request);
204
205 /* Fall through. */
206 case UX_DEVICE_CLASS_PRINTER_READ_WAIT:
207
208 /* Get a full packet each time */
209 max_transfer_length = endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize;
210
211 /* Run the transfer state machine. */
212 status = _ux_device_stack_transfer_run(transfer_request,
213 max_transfer_length,
214 max_transfer_length);
215
216 /* Error case. */
217 if (status < UX_STATE_NEXT)
218 {
219 printer -> ux_device_class_printer_read_state = UX_STATE_RESET;
220 printer -> ux_device_class_printer_read_status =
221 transfer_request -> ux_slave_transfer_request_completion_code;
222 return(UX_STATE_ERROR);
223 }
224
225 /* Success case. */
226 if (status == UX_STATE_NEXT)
227 {
228 /* Check overflow */
229 if (printer -> ux_device_class_printer_read_transfer_length <
230 transfer_request -> ux_slave_transfer_request_actual_length)
231 {
232 printer -> ux_device_class_printer_read_state = UX_STATE_ERROR;
233 printer -> ux_device_class_printer_read_status = UX_TRANSFER_BUFFER_OVERFLOW;
234 return(UX_STATE_ERROR);
235 }
236
237 /* We need to copy the buffer locally. */
238 _ux_utility_memory_copy(printer -> ux_device_class_printer_read_buffer,
239 transfer_request -> ux_slave_transfer_request_data_pointer,
240 transfer_request -> ux_slave_transfer_request_actual_length); /* Use case of memcpy is verified. */
241
242 /* Next buffer address. */
243 printer -> ux_device_class_printer_read_buffer +=
244 transfer_request -> ux_slave_transfer_request_actual_length;
245
246 /* Set the length actually received. */
247 printer -> ux_device_class_printer_read_actual_length +=
248 transfer_request -> ux_slave_transfer_request_actual_length;
249
250 /* Last transfer status. */
251 printer -> ux_device_class_printer_read_status =
252 transfer_request -> ux_slave_transfer_request_completion_code;
253
254 /* Update actual length. */
255 *actual_length = printer -> ux_device_class_printer_read_actual_length;
256
257 /* Check short packet. */
258 if (transfer_request -> ux_slave_transfer_request_actual_length <
259 transfer_request -> ux_slave_transfer_request_requested_length)
260 {
261
262 /* It's done. */
263 printer -> ux_device_class_printer_read_state = UX_STATE_RESET;
264 return(UX_STATE_NEXT);
265 }
266
267 /* Next state. */
268 printer -> ux_device_class_printer_read_state = UX_DEVICE_CLASS_PRINTER_READ_START;
269 }
270
271 /* Keep waiting. */
272 return(UX_STATE_WAIT);
273
274 default: /* Error. */
275 printer -> ux_device_class_printer_read_state = UX_STATE_RESET;
276 printer -> ux_device_class_printer_read_status = UX_INVALID_STATE;
277 break;
278 }
279 #endif
280
281 /* Error cases. */
282 return(UX_STATE_EXIT);
283 }
284
285 /**************************************************************************/
286 /* */
287 /* FUNCTION RELEASE */
288 /* */
289 /* _uxe_device_class_printer_read_run PORTABLE C */
290 /* 6.3.0 */
291 /* AUTHOR */
292 /* */
293 /* Yajun Xia, Microsoft Corporation */
294 /* */
295 /* DESCRIPTION */
296 /* */
297 /* This function checks errors in printer read function call. */
298 /* */
299 /* It's for standalone mode. */
300 /* */
301 /* INPUT */
302 /* */
303 /* printer Address of printer class */
304 /* instance */
305 /* buffer Pointer to buffer to save */
306 /* received data */
307 /* requested_length Length of bytes to read */
308 /* actual_length Pointer to save number of */
309 /* bytes read */
310 /* */
311 /* OUTPUT */
312 /* */
313 /* State machine Status to check */
314 /* UX_STATE_NEXT Transfer done, to next state */
315 /* UX_STATE_EXIT Abnormal, to reset state */
316 /* UX_STATE_ERROR Error occurred */
317 /* (others) Keep running, waiting */
318 /* */
319 /* CALLS */
320 /* */
321 /* _ux_device_class_printer_read_run Printer class read process */
322 /* */
323 /* CALLED BY */
324 /* */
325 /* Application */
326 /* */
327 /* RELEASE HISTORY */
328 /* */
329 /* DATE NAME DESCRIPTION */
330 /* */
331 /* 10-31-2023 Yajun xia Initial Version 6.3.0 */
332 /* */
333 /**************************************************************************/
_uxe_device_class_printer_read_run(UX_DEVICE_CLASS_PRINTER * printer,UCHAR * buffer,ULONG requested_length,ULONG * actual_length)334 UINT _uxe_device_class_printer_read_run(UX_DEVICE_CLASS_PRINTER *printer, UCHAR *buffer,
335 ULONG requested_length, ULONG *actual_length)
336 {
337
338 /* Sanity checks. */
339 if ((printer == UX_NULL) || ((buffer == UX_NULL) && (requested_length > 0)) || (actual_length == UX_NULL))
340 {
341 return (UX_STATE_ERROR);
342 }
343
344 return(_ux_device_class_printer_read_run(printer, buffer, requested_length, actual_length));
345 }
346
347 #endif
348