1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** USBX Component */
17 /** */
18 /** Pictbridge Application */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23
24 /* Include necessary system files. */
25
26 #define UX_SOURCE_CODE
27
28 #include "ux_api.h"
29 #include "ux_pictbridge.h"
30 #include "ux_host_class_pima.h"
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _ux_pictbridge_dpshost_start PORTABLE C */
38 /* 6.1.12 */
39 /* AUTHOR */
40 /* */
41 /* Chaoqiong Xiao, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function starts the DPS host (usually a printer). */
46 /* */
47 /* INPUT */
48 /* */
49 /* pima Pima instance associated */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* Completion Status */
54 /* */
55 /* CALLS */
56 /* */
57 /* */
58 /* CALLED BY */
59 /* */
60 /* user application */
61 /* */
62 /* RELEASE HISTORY */
63 /* */
64 /* DATE NAME DESCRIPTION */
65 /* */
66 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
67 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
68 /* used UX prefix to refer to */
69 /* TX symbols instead of using */
70 /* them directly, */
71 /* resulting in version 6.1 */
72 /* 04-25-2022 Yajun Xia Modified comment(s), */
73 /* internal clean up, */
74 /* resulting in version 6.1.11 */
75 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
76 /* fixed string length check, */
77 /* fixed possible overflow, */
78 /* used define instead of num, */
79 /* used macros for RTOS calls, */
80 /* resulting in version 6.1.12 */
81 /* */
82 /**************************************************************************/
_ux_pictbridge_dpshost_start(UX_PICTBRIDGE * pictbridge,UX_HOST_CLASS_PIMA * pima)83 UINT _ux_pictbridge_dpshost_start(UX_PICTBRIDGE *pictbridge, UX_HOST_CLASS_PIMA *pima)
84 {
85 UINT status;
86 ULONG object_index;
87 UCHAR string_discovery_name[UX_PICTBRIDGE_MAX_FILE_NAME_SIZE + 1]; /* +1 for null-terminator */
88 UX_HOST_CLASS_PIMA_OBJECT *pima_object;
89 UX_HOST_CLASS_PIMA_SESSION *pima_session;
90 UINT length, length1;
91
92 /* Store the pima instance in the pictbridge container. */
93 pictbridge -> ux_pictbridge_pima = (VOID *) pima;
94
95 /* We need to allocate memory for the pima structures contained in the pictbridge instance : Storage. */
96 pictbridge -> ux_pictbridge_storage = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_PIMA_STORAGE));
97
98 /* Check the completion status. */
99 if (pictbridge -> ux_pictbridge_storage == UX_NULL)
100 return(UX_MEMORY_INSUFFICIENT);
101
102 /* Initialize status to success for things going on. */
103 status = UX_SUCCESS;
104
105 /* We need to allocate memory for the pima structures contained in the pictbridge instance : host object. */
106 pictbridge -> ux_pictbridge_object_host = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_PIMA_OBJECT));
107
108 /* Get the address of the object container. */
109 pima_object = (UX_HOST_CLASS_PIMA_OBJECT *) pictbridge -> ux_pictbridge_object_host;
110
111 /* Check the completion status. */
112 if (pictbridge -> ux_pictbridge_object_host == UX_NULL)
113 status = (UX_MEMORY_INSUFFICIENT);
114 else
115 {
116
117 /* Allocate some memory for the script object. */
118 pima_object -> ux_host_class_pima_object_buffer = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_CACHE_SAFE_MEMORY, UX_PICTBRIDGE_MAX_PIMA_OBJECT_BUFFER);
119 if (pima_object -> ux_host_class_pima_object_buffer == UX_NULL)
120 status = (UX_MEMORY_INSUFFICIENT);
121 }
122
123 /* We need to allocate memory for the pima structures contained in the pictbridge instance : session. */
124 if (status == UX_SUCCESS)
125 {
126 pictbridge -> ux_pictbridge_session = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_PIMA_SESSION));
127
128 /* Check the completion status. */
129 if (pictbridge -> ux_pictbridge_session == UX_NULL)
130 status = (UX_MEMORY_INSUFFICIENT);
131 }
132
133 /* Go on if no error. */
134 if (status == UX_SUCCESS)
135 {
136
137 /* We need to allocate memory for the pima structures contained in the pictbridge instance : device. */
138 pictbridge -> ux_pictbridge_device = _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, sizeof(UX_HOST_CLASS_PIMA_DEVICE));
139
140 /* Check the completion status. */
141 if (pictbridge -> ux_pictbridge_device == UX_NULL)
142 status = (UX_MEMORY_INSUFFICIENT);
143 }
144
145 /* Go on if no error. */
146 if (status == UX_SUCCESS)
147 {
148
149 /* Store the Pictbridge instance in the pima application. This is used for the Pima callback
150 into the Pictbridge (or other application) layer. */
151 pima -> ux_host_class_pima_application = (VOID *) pictbridge;
152
153 /* State machine for the dpshost is idle. */
154 pictbridge -> ux_pictbridge_host_client_state_machine = UX_PICTBRIDGE_STATE_MACHINE_IDLE;
155
156 /* Create the semaphore to wake up the thread. */
157 status = _ux_system_semaphore_create(&pictbridge -> ux_pictbridge_notification_semaphore, "ux_pictbridge_notification_semaphore", 0);
158 if (status != UX_SUCCESS)
159 status = (UX_SEMAPHORE_ERROR);
160 }
161
162 /* Go on if no error. */
163 if (status == UX_SUCCESS)
164 {
165
166 /* Allocate a Thread stack. */
167 pictbridge -> ux_pictbridge_thread_stack =
168 _ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, UX_PICTBRIDGE_THREAD_STACK_SIZE);
169
170 /* Check the completion status. */
171 if (pictbridge -> ux_pictbridge_thread_stack == UX_NULL)
172 status = (UX_MEMORY_INSUFFICIENT);
173 }
174
175 /* Go on if no error. */
176 if (status == UX_SUCCESS)
177 {
178
179 /* Create the pictbridge class thread. */
180 status = _ux_system_thread_create(&pictbridge -> ux_pictbridge_thread,
181 "ux_pictbridge_thread", _ux_pictbridge_dpshost_thread,
182 (ULONG)(ALIGN_TYPE) pictbridge,
183 pictbridge -> ux_pictbridge_thread_stack,
184 UX_PICTBRIDGE_THREAD_STACK_SIZE,
185 UX_PICTBRIDGE_THREAD_PRIORITY_CLASS,
186 UX_PICTBRIDGE_THREAD_PRIORITY_CLASS,
187 UX_NO_TIME_SLICE, UX_AUTO_START);
188
189 /* Check the completion status. */
190 if (status != UX_SUCCESS)
191 status = (UX_THREAD_ERROR);
192
193 UX_THREAD_EXTENSION_PTR_SET(&(pictbridge -> ux_pictbridge_thread), pictbridge)
194 }
195
196 /* Free up resources if there is error. */
197 if (status != UX_SUCCESS)
198 {
199
200 /* Check and free pictbridge -> ux_pictbridge_thread. */
201 if (_ux_system_thread_created(&pictbridge -> ux_pictbridge_thread))
202 _ux_system_thread_delete(&pictbridge -> ux_pictbridge_thread);
203
204 /* Check and free pictbridge -> ux_pictbridge_thread_stack. */
205 if (pictbridge -> ux_pictbridge_thread_stack)
206 _ux_utility_memory_free(pictbridge -> ux_pictbridge_thread_stack);
207
208 /* Check and free pictbridge -> ux_pictbridge_notification_semaphore. */
209 if (_ux_system_semaphore_created(&pictbridge -> ux_pictbridge_notification_semaphore))
210 _ux_system_semaphore_delete(&pictbridge -> ux_pictbridge_notification_semaphore);
211
212 /* Check and free pictbridge -> ux_pictbridge_device. */
213 if (pictbridge -> ux_pictbridge_device)
214 _ux_utility_memory_free(pictbridge -> ux_pictbridge_device);
215
216 /* Check and free pictbridge -> ux_pictbridge_session. */
217 if (pictbridge -> ux_pictbridge_session)
218 _ux_utility_memory_free(pictbridge -> ux_pictbridge_session);
219
220 /* Check and free pictbridge -> ux_pictbridge_object_host (pima_object). */
221 if (pima_object)
222 {
223 if (pima_object -> ux_host_class_pima_object_buffer)
224 _ux_utility_memory_free(pima_object -> ux_host_class_pima_object_buffer);
225 _ux_utility_memory_free(pima_object);
226 }
227
228 /* Free pictbridge -> ux_pictbridge_storage. */
229 _ux_utility_memory_free(pictbridge -> ux_pictbridge_storage);
230
231 return(status);
232 }
233
234 /* Save the session in a properly casted format. */
235 pima_session = (UX_HOST_CLASS_PIMA_SESSION *)pictbridge->ux_pictbridge_session;
236
237 /* Initialize the pictbridge state machine to request expected. */
238 pictbridge -> ux_pictbridge_request_response = UX_PICTBRIDGE_REQUEST;
239
240 /* Initialize the head and tail of the notification round robin buffers.
241 At first, the head and tail are pointing to the beginning of the array. */
242 pictbridge -> ux_pictbridge_event_array_head = pictbridge -> ux_pictbridge_event_array;
243 pictbridge -> ux_pictbridge_event_array_tail = pictbridge -> ux_pictbridge_event_array;
244 pictbridge -> ux_pictbridge_event_array_end = pictbridge -> ux_pictbridge_event_array + UX_PICTBRIDGE_MAX_EVENT_NUMBER;
245
246 /* Get the device info . */
247 status = _ux_host_class_pima_device_info_get(pima, (UX_HOST_CLASS_PIMA_DEVICE *)pictbridge -> ux_pictbridge_device);
248 if (status != UX_SUCCESS)
249 return(UX_PICTBRIDGE_ERROR_GENERAL_ERROR);
250
251 /* Set a callback for the pima session notification. */
252 pima_session -> ux_host_class_pima_session_event_callback = _ux_pictbridge_dpshost_notification_callback;
253
254 /* Open a pima session. */
255 status = _ux_host_class_pima_session_open(pima, pima_session);
256 if (status != UX_SUCCESS)
257 return(UX_PICTBRIDGE_ERROR_SESSION_NOT_OPEN);
258
259 /* Get the number of storage IDs. */
260 status = _ux_host_class_pima_storage_ids_get(pima, pima_session,
261 pictbridge -> ux_pictbridge_storage_ids,
262 UX_PICTBRIDGE_MAX_NUMBER_STORAGE_IDS);
263 if (status != UX_SUCCESS)
264 {
265 /* Close the pima session. */
266 _ux_host_class_pima_session_close(pima, pima_session);
267
268 return(UX_PICTBRIDGE_ERROR_STORE_NOT_AVAILABLE);
269 }
270
271 /* Get the first storage ID info container. */
272 status = _ux_host_class_pima_storage_info_get(pima, pima_session,
273 pictbridge -> ux_pictbridge_storage_ids[0],
274 (UX_HOST_CLASS_PIMA_STORAGE *)pictbridge -> ux_pictbridge_storage);
275 if (status != UX_SUCCESS)
276 {
277 /* Close the pima session. */
278 _ux_host_class_pima_session_close(pictbridge -> ux_pictbridge_pima, pima_session);
279
280 return(UX_PICTBRIDGE_ERROR_STORE_NOT_AVAILABLE);
281 }
282
283 /* Get the number of objects on the container. */
284 status = _ux_host_class_pima_num_objects_get(pima, pima_session,
285 UX_PICTBRIDGE_ALL_CONTAINERS, UX_PICTBRIDGE_OBJECT_SCRIPT);
286 if (status != UX_SUCCESS)
287 {
288 /* Close the pima session. */
289 _ux_host_class_pima_session_close(pima, pima_session);
290
291 return(UX_PICTBRIDGE_ERROR_STORE_NOT_AVAILABLE);
292 }
293
294 /* Get the array of objects handles on the container. */
295 if (pima_session -> ux_host_class_pima_session_nb_objects > UX_PICTBRIDGE_MAX_NUMBER_OBJECT_HANDLES)
296 length = UX_PICTBRIDGE_MAX_NUMBER_OBJECT_HANDLES;
297 else
298 length = pima_session -> ux_host_class_pima_session_nb_objects;
299 status = _ux_host_class_pima_object_handles_get(pima, pima_session,
300 pictbridge -> ux_pictbridge_object_handles_array,
301 length,
302 UX_PICTBRIDGE_ALL_CONTAINERS, UX_PICTBRIDGE_OBJECT_SCRIPT, 0);
303 if (status != UX_SUCCESS)
304 {
305 /* Close the pima session. */
306 _ux_host_class_pima_session_close(pima, pima_session);
307
308 return(UX_PICTBRIDGE_ERROR_STORE_NOT_AVAILABLE);
309 }
310
311 /* We search for an object that is a picture or a script. */
312 object_index = 0;
313 while (object_index < pima_session -> ux_host_class_pima_session_nb_objects)
314 {
315
316 /* Get the object info structure. */
317 status = _ux_host_class_pima_object_info_get(pima, pima_session,
318 pictbridge -> ux_pictbridge_object_handles_array[object_index], pima_object);
319 if (status != UX_SUCCESS)
320 {
321 /* Close the pima session. */
322 _ux_host_class_pima_session_close(pima, pima_session);
323
324 return(UX_PICTBRIDGE_ERROR_INVALID_OBJECT_HANDLE );
325 }
326
327 /* Check if this is a script. */
328 if (pima_object -> ux_host_class_pima_object_format == UX_HOST_CLASS_PIMA_OFC_SCRIPT)
329 {
330
331 /* Yes this is a script. We need to search for the DDISCVRY.DPS file name.
332 Get the file name length (with null-terminator). */
333 length1 = (UINT)(*pima_object -> ux_host_class_pima_object_filename);
334
335 /* Now, compare it to the DDISCVRY.DPS file name. Check length first (excluding null-terminator). */
336 if (length1 <= UX_PICTBRIDGE_MAX_FILE_NAME_SIZE)
337 {
338
339 /* Invalidate length, on error it's untouched. */
340 length = UX_PICTBRIDGE_MAX_FILE_NAME_SIZE + 1;
341 _ux_utility_string_length_check(_ux_pictbridge_ddiscovery_name, &length, UX_PICTBRIDGE_MAX_FILE_NAME_SIZE);
342 if ((length + 1) == length1)
343 {
344
345 /* Get the file name in a ascii format (with null-terminator). */
346 _ux_utility_unicode_to_string(pima_object -> ux_host_class_pima_object_filename, string_discovery_name);
347
348 /* So far, the length of name of the files are the same.
349 Compare names now (since length is same just compare without null-terminator). */
350 if (_ux_utility_memory_compare(_ux_pictbridge_ddiscovery_name, string_discovery_name,
351 length) == UX_SUCCESS)
352 {
353
354 /* We have found a script with the DDISCVRY.DPS file name. Prepare a reply with a HDISCVRY. DPS name.
355 We use the same object container. Just change the name of the file. */
356 _ux_utility_string_to_unicode(_ux_pictbridge_hdiscovery_name, pima_object -> ux_host_class_pima_object_filename);
357
358 /* Send the script info. */
359 status = _ux_host_class_pima_object_info_send(pima, pima_session, 0,0,
360 pima_object);
361
362 /* Check the status of this operation. */
363 if (status != UX_SUCCESS)
364 {
365
366 /* Close the pima session. */
367 _ux_host_class_pima_session_close(pima, pima_session);
368
369 return(UX_PICTBRIDGE_ERROR_INVALID_OBJECT_HANDLE);
370 }
371 else
372
373 /* We return to the application with a success status. We leave the session opened. */
374 return(UX_SUCCESS);
375
376 }
377
378 }
379 }
380 }
381
382 /* Next object index. */
383 object_index++;
384
385 }
386
387 /* We come here when we have not found any script or the script does not have the DDISCVRY.DPS file. Close the pima session. */
388 _ux_host_class_pima_session_close(pima, pima_session);
389 return(UX_PICTBRIDGE_ERROR_NO_DISCOVERY_SCRIPT);
390 }
391
392