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 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _ux_device_class_printer_control_request PORTABLE C */
36 /* 6.1.12 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function manages the requests sent by the host on the control */
44 /* endpoint with a CLASS or VENDOR SPECIFIC type. */
45 /* */
46 /* INPUT */
47 /* */
48 /* command Pointer to class command */
49 /* */
50 /* OUTPUT */
51 /* */
52 /* None */
53 /* */
54 /* CALLS */
55 /* */
56 /* (ux_device_class_printer_soft_reset) Notify a software reset */
57 /* _ux_device_class_printer_soft_reset Performs software reset */
58 /* _ux_device_stack_transfer_request Transfer request */
59 /* _ux_utility_short_get Get short value from buffer */
60 /* _ux_utility_short_get_big_endian Get big endian short value */
61 /* */
62 /* CALLED BY */
63 /* */
64 /* Device Printer Class */
65 /* */
66 /* RELEASE HISTORY */
67 /* */
68 /* DATE NAME DESCRIPTION */
69 /* */
70 /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */
71 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
72 /* fixed parameter/variable */
73 /* names conflict C++ keyword, */
74 /* resulting in version 6.1.12 */
75 /* */
76 /**************************************************************************/
_ux_device_class_printer_control_request(UX_SLAVE_CLASS_COMMAND * command)77 UINT _ux_device_class_printer_control_request(UX_SLAVE_CLASS_COMMAND *command)
78 {
79 UX_DEVICE_CLASS_PRINTER *printer;
80 UX_SLAVE_CLASS *printer_class;
81 UX_SLAVE_INTERFACE *printer_interface;
82 UX_SLAVE_TRANSFER *transfer_request;
83 UX_SLAVE_DEVICE *device;
84 ULONG request;
85 ULONG value;
86 ULONG request_length;
87 ULONG length;
88 UCHAR *buffer;
89 UCHAR index_low;
90 UCHAR *descriptor;
91 ULONG descriptor_length;
92 ULONG index;
93 UCHAR found;
94
95 /* Get the class container. */
96 printer_class = command -> ux_slave_class_command_class_ptr;
97
98 /* Get the class instance in the container. */
99 printer = (UX_DEVICE_CLASS_PRINTER *) printer_class -> ux_slave_class_instance;
100
101 /* Get the interface. */
102 printer_interface = printer_class -> ux_slave_class_interface;
103
104 /* Get the pointer to the device. */
105 device = &_ux_system_slave -> ux_system_slave_device;
106
107 /* Get the pointer to the transfer request associated with the control endpoint. */
108 transfer_request = &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request;
109
110 /* Extract all necessary fields of the request. */
111 request = *(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_REQUEST);
112
113 /* Extract all necessary fields of the value. */
114 value = _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_VALUE);
115 index_low = transfer_request -> ux_slave_transfer_request_setup[UX_SETUP_INDEX];
116
117 /* Pickup the request length. */
118 request_length = _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH);
119
120 /* Get buffer to fill. */
121 buffer = transfer_request -> ux_slave_transfer_request_data_pointer;
122
123 /* Here we proceed only the standard request we know of at the device level. */
124 switch (request)
125 {
126 case UX_DEVICE_CLASS_PRINTER_GET_DEVICE_ID:
127
128 /* Sanity check
129 - wValue == config index
130 - wIndex_high == interface (already checked before entry, index of
131 interface should equal to interface number)
132 - wIndex_low == alternate */
133 if (index_low != (UCHAR)printer_interface -> ux_slave_interface_descriptor.bAlternateSetting)
134 return(UX_ERROR);
135
136 /* Check config index. */
137 descriptor = _ux_system_slave -> ux_system_slave_device_framework;
138 length = _ux_system_slave->ux_system_slave_device_framework_length;
139 index = 0;
140 found = 0;
141 while(length)
142 {
143
144 /* By default use bLength @ 0. */
145 descriptor_length = descriptor[0];
146
147 /* Check bDescriptorType @ 1. */
148 switch(descriptor[1])
149 {
150 case UX_CONFIGURATION_DESCRIPTOR_ITEM:
151
152 /* It's configuration requested? */
153 if (index == value)
154 {
155
156 /* Check if bConfigurationValue @ 5 is as expected. */
157 if ((UCHAR)printer_class -> ux_slave_class_configuration_number != descriptor[5])
158 return(UX_ERROR);
159
160 /* Find the configuration. */
161 found = 1;
162 break;
163 }
164
165 /* Target to next configuration index. */
166 index ++;
167
168 /* Use wTotalLength @ 2. */
169 descriptor_length = _ux_utility_short_get(descriptor + 2);
170 break;
171
172 default:
173 break;
174 }
175
176 /* Break if found. */
177 if (found)
178 break;
179
180 /* Descriptor broken check. */
181 if (descriptor_length < 2 ||
182 descriptor_length > length)
183 {
184
185 /* Error trap! */
186 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
187 return(UX_DESCRIPTOR_CORRUPTED);
188 }
189
190 /* Next descriptor. */
191 descriptor += descriptor_length;
192 length -= descriptor_length;
193 }
194
195 /* Request parameter not expected if not found. */
196 if (!found)
197 return(UX_ERROR);
198
199 /* Length of data (first two bytes in big endian). */
200 length = _ux_utility_short_get_big_endian(printer ->
201 ux_device_class_printer_parameter.ux_device_class_printer_device_id);
202
203 /* Prepare device ID to send. */
204 if (length)
205 {
206
207 /* Sanity check. */
208 if (length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
209 {
210
211 /* Error trap! */
212 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_BUFFER_OVERFLOW);
213 return(UX_BUFFER_OVERFLOW);
214 }
215
216 /* Copy data. */
217 _ux_utility_memory_copy(buffer, printer ->
218 ux_device_class_printer_parameter.ux_device_class_printer_device_id,
219 length); /* Use case of memcpy is verified. */
220 }
221
222 /* Set the phase of the transfer to data out. */
223 transfer_request -> ux_slave_transfer_request_phase = UX_TRANSFER_PHASE_DATA_OUT;
224
225 /* Transfer. */
226 _ux_device_stack_transfer_request(transfer_request, length, request_length);
227 break ;
228
229 case UX_DEVICE_CLASS_PRINTER_GET_PORT_STATUS:
230
231 /* Sanity check. */
232 if (request_length < 1)
233 return(UX_ERROR);
234
235 /* Fill status byte. */
236 *buffer = (UCHAR)printer -> ux_device_class_printer_port_status;
237
238 /* Set the phase of the transfer to data out. */
239 transfer_request -> ux_slave_transfer_request_phase = UX_TRANSFER_PHASE_DATA_OUT;
240
241 /* Perform the data transfer. */
242 _ux_device_stack_transfer_request(transfer_request, 1, request_length);
243 break;
244
245 case UX_DEVICE_CLASS_PRINTER_SOFT_RESET:
246 _ux_device_class_printer_soft_reset(printer);
247
248 /* If there is a soft reset function call it. */
249 if (printer -> ux_device_class_printer_parameter.
250 ux_device_class_printer_soft_reset != UX_NULL)
251 {
252
253 /* Invoke the application callback. */
254 printer -> ux_device_class_printer_parameter.
255 ux_device_class_printer_soft_reset(printer);
256 }
257 break;
258
259 default:
260
261 /* Unknown function. It's not handled. */
262 return(UX_ERROR);
263 }
264
265 /* It's handled. */
266 return(UX_SUCCESS);
267 }
268