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