1 #include <stdio.h>
2 #include <stdint.h>
3 #include "fx_api.h"
4 #include "tx_api.h"
5 #include "ux_api.h"
6 #include "ux_hcd_sim_host.h"
7 #include "ux_system.h"
8 #include "ux_utility.h"
9 #include "tx_thread.h"
10 
11 #include "ux_device_stack.h"
12 #include "ux_device_class_storage.h"
13 #include "ux_host_class_storage.h"
14 #include "ux_dcd_sim_slave.h"
15 
16 #include "ux_test.h"
17 #include "ux_test_actions.h"
18 #include "ux_test_utility_sim.h"
19 #include "ux_test_hcd_sim_host.h"
20 #include "ux_test_dcd_sim_slave.h"
21 
22 typedef struct device_media_read_write_timeout_data
23 {
24     UX_TRANSFER *transfer_request;
25     ULONG       num_timeouts;
26 } DEVICE_MEDIA_READ_WRITE_TIMEOUT_DATA;
27 
28 #define _storage_media_is_mounted() (global_storage_media->ux_host_class_storage_media_status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED)
29 #if defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
30 FX_MEDIA    *_ux_host_class_storage_driver_media(INT i);
31 VOID        _ux_host_class_storage_driver_entry(FX_MEDIA *media);
32 VOID        _ux_host_class_storage_media_insert(UX_HOST_CLASS_STORAGE_MEDIA *storage_media, ULONG format_open);
33 VOID        _ux_host_class_storage_media_remove(UX_HOST_CLASS_STORAGE_MEDIA *storage_media);
34 INT         _ux_host_class_storage_media_index(UX_HOST_CLASS_STORAGE_MEDIA *storage_media);
35 FX_MEDIA    *_ux_host_class_storage_media_fx_media(UX_HOST_CLASS_STORAGE_MEDIA *storage_media);
36 UCHAR       *_ux_host_class_storage_media_fx_media_memory(UX_HOST_CLASS_STORAGE_MEDIA *storage_media);
37 #endif
38 
39 /* Define constants.  */
40 #define     UX_TEST_MULTIPLE_TRANSFERS_SECTOR_COUNT (2*UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE/UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT)
41 #define     UX_TEST_SLEEP_STORAGE_THREAD_RUN_ONCE   (3*UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME/2)
42 #define     UX_TEST_DEFAULT_SECTOR_SIZE             UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT
43 #define     UX_TEST_MAX_SECTOR_SIZE                 (2*UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT)
44 #define     UX_TEST_NUM_DIRECTORY_ENTRIES           512
45 #define     UX_DEMO_STACK_SIZE                      2048
46 #define     UX_DEMO_BUFFER_SIZE                     2048
47 #define     UX_DEMO_FILE_BUFFER_SIZE                UX_TEST_MAX_SECTOR_SIZE
48 #define     UX_DEMO_LARGE_FILE_BUFFER_SIZE          (2*UX_HOST_CLASS_STORAGE_MAX_TRANSFER_SIZE)
49 #define     UX_DEMO_RECEPTION_BLOCK_SIZE            64
50 #define     UX_DEMO_MEMORY_SIZE                     (256 * 1024)
51 #define     UX_DEMO_FILE_SIZE                       (4 * 1024)
52 #define     UX_RAM_DISK_SIZE                        (200 * 1024)
53 #define     UX_RAM_DISK_LAST_LBA                    ((UX_RAM_DISK_SIZE / global_sector_size) -1)
54 #define     BULK_IN                                 1
55 #define     BULK_OUT                                2
56 #define     PARTITION_TYPE_UNKNOWN                  0xff
57 #define     MEDIA_TYPE_UNKNOWN                      0xff
58 #define     PROTOCOL_UNKNOWN                        0xff
59 #define     SUB_CLASS_UNKNOWN                       0xff
60 #define     bInterfaceSubClass_POS                  0x21
61 #define     bInterfaceProtocol_POS                  0x22
62 #define     bNumEndpoints_FS_POS                    0x1f
63 #define     bNumEndpoints_HS_POS                    0x29
64 #define     Endpoint_bLength                        0
65 #define     Endpoint_bDescriptorType                1
66 #define     Endpoint_bEndpointAddress               2
67 #define     Endpoint_bmAttributes                   3
68 #define     Endpoint_wMaxPacketSize                 4
69 #define     Endpoint_bInterval                      6
70 
71 /* Define local/extern function prototypes.  */
72 static void                                 demo_thread_entry(ULONG);
73 static TX_THREAD                            tx_demo_thread_host_simulation;
74 static TX_THREAD                            tx_demo_thread_slave_simulation;
75 static void                                 ux_test_thread_host_simulation_entry(ULONG);
76 UINT                                        _ux_dcd_sim_slave_function(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter);
77 
78 
79 VOID                                        _fx_ram_driver(FX_MEDIA *media_ptr);
80 static UINT                                 default_device_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status);
81 static UINT                                 default_device_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status);
82 static UINT                                 default_device_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status);
83 static UINT                                 default_device_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status);
84 static UINT                                 ux_test_storage_file_co(FX_MEDIA *media, FX_FILE *file, UCHAR fail_on_error);
85 static UINT                                 ux_test_storage_file_cow(FX_MEDIA *media, FX_FILE *file, UCHAR *data_pointer, ULONG data_length, UCHAR fail_on_error);
86 static void                                 ux_test_storage_file_cd(FX_MEDIA *media, FX_FILE *file);
87 static void                                 ux_test_storage_file_cowcd(FX_MEDIA *media, FX_FILE *file, UCHAR *data_pointer, ULONG data_length);
88 
89 /* Define global data structures.  */
90 static UCHAR                                usbx_memory[UX_DEMO_MEMORY_SIZE + (UX_DEMO_STACK_SIZE * 2)];
91 static UCHAR                                global_buffer[UX_DEMO_LARGE_FILE_BUFFER_SIZE];
92 static UCHAR                                global_buffer_2x_slave_buffer_size[2*UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE];
93 static FX_MEDIA                             global_ram_disk;
94 static CHAR                                 global_ram_disk_memory[UX_RAM_DISK_SIZE];
95 static UCHAR                                global_ram_disk_working_buffer[UX_TEST_MAX_SECTOR_SIZE];
96 static UX_SLAVE_CLASS_STORAGE_PARAMETER     global_storage_parameter;
97 static UX_HOST_CLASS                        *global_host_storage_class;
98 static UX_HOST_CLASS_STORAGE_EXT            *global_host_class_ext;
99 static UX_HOST_CLASS_STORAGE                *global_storage;
100 static UX_HOST_CLASS_STORAGE                *global_storage_change_function;
101 static TX_THREAD                            *global_storage_thread;
102 static UX_HOST_CLASS_STORAGE_MEDIA          *global_storage_media;
103 static UX_HOST_CLASS_STORAGE_MEDIA          *global_storage_medias;
104 static FX_MEDIA                             *global_media;
105 static UX_HCD                               *global_hcd;
106 static UX_SLAVE_DCD                         *global_dcd;
107 static UX_DEVICE                            *global_host_device;
108 static UX_SLAVE_DEVICE                      *global_slave_device;
109 static UX_SLAVE_CLASS                       *global_slave_class_container;
110 static UX_SLAVE_CLASS_STORAGE               *global_slave_storage;
111 static UX_SLAVE_ENDPOINT                    *global_slave_storage_bulk_in;
112 static UX_SLAVE_ENDPOINT                    *global_slave_storage_bulk_out;
113 static TX_THREAD                            *global_slave_storage_thread;
114 static UX_SLAVE_CLASS_STORAGE               *global_persistent_slave_storage;
115 static TX_THREAD                            *global_enum_thread;
116 static ULONG                                global_sector_size = UX_TEST_DEFAULT_SECTOR_SIZE;
117 static ULONG                                global_memory_test_no_device_memory_free_amount;
118 static UCHAR                                global_is_storage_thread_locked_out;
119 
120 /* Common data we match. */
121 static UCHAR global_transfer_request_data_request_sense_data_phase[] =  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
122 static UCHAR global_cbw_data_unit_ready_test_sbc[20] =                  { 85, 83, 66, 67, 67, 66, 83, 85, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0 };
123 static UCHAR global_cbw_data_request_sense[26] =                        { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x12, 0x00, 0x00, 0x00, 0x80, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
124 static UCHAR global_cbw_data_format_capacity_get[] =                    { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0xfc, 0x00, 0x00, 0x00, 0x80, 0x00, 0x0a, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
125 static UCHAR global_cbw_data_first_sector_read[] =                      { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x0a, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
126 static UCHAR global_cbw_data_media_characteristics_get_sbc[20] =        { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12, 0x00, 0x00, 0x00, 0x24 };
127 static UCHAR global_cbw_data_media_capacity_get_sbc[25] =               { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x08, 0x00, 0x00, 0x00, 0x80, 0x00, 0x0a, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
128 
129 /* Opcode matching. */
130 static UCHAR global_cbw_opcode_read[] =                                 { 'U', 'S', 'B', 'C', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '(' };
131 static UCHAR global_cbw_opcode_match_mask[] =                           {  1,   1,   1,   1,   0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    1 };
132 
133 /* Common errors. */
134 static UX_TEST_ERROR_CALLBACK_ERROR global_transfer_stall_error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_TRANSFER_STALLED };
135 static UX_TEST_ERROR_CALLBACK_ERROR global_transfer_timeout_error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT };
136 
137 /* Test resources. */
138 static TX_SEMAPHORE global_test_semaphore;
139 static TX_TIMER     global_timer;
140 
141 static UCHAR device_framework_full_speed[] = {
142 
143     /* Device descriptor */
144         0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08,
145         0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
146         0x03, 0x01,
147 
148     /* Configuration descriptor */
149         0x09, 0x02, 0x45, 0x00, 0x01, 0x01, 0x00, 0xc0,
150         0x32,
151 
152     /* Interface descriptor */
153         0x09, 0x04, 0x00, 0x00, 0x03, 0x08, 0x06, 0x50,
154         0x00,
155 
156     /* Endpoint descriptor (Bulk In) */
157         0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00,
158 
159     /* Endpoint descriptor (Bulk Out) */
160         0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
161 
162     /* Endpoint descriptor (Interrupt In) */
163         0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x01,
164 
165     /* Interface descriptor */
166         0x09, 0x04, 0x00, 0x01, 0x03, 0x08, 0x06, 0x50,
167         0x00,
168 
169     /* Endpoint descriptor (Bulk In) */
170         0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00,
171 
172     /* Endpoint descriptor (Bulk Out) */
173         0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
174 
175     /* Endpoint descriptor (Interrupt In) */
176         0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x01,
177 
178     };
179 #define DEVICE_FRAMEWORK_LENGTH_FULL_SPEED ARRAY_COUNT(device_framework_full_speed)
180 
181 static UCHAR *bulk_in_endpoint_descriptor_fs =      &device_framework_full_speed[0x12 + 0x09 + 0x09];
182 static UCHAR *bulk_out_endpoint_descriptor_fs =     &device_framework_full_speed[0x12 + 0x09 + 0x09 + 0x07];
183 static UCHAR *interrupt_in_endpoint_descriptor_fs = &device_framework_full_speed[0x12 + 0x09 + 0x09 + 0x07 + 0x07];
184 
185 static UCHAR device_framework_high_speed[] = {
186 
187     /* Device descriptor */
188         0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
189         0x81, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02,
190         0x03, 0x01,
191 
192     /* Device qualifier descriptor */
193         0x0a, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40,
194         0x01, 0x00,
195 
196     /* Configuration descriptor */
197         0x09, 0x02, 0x45, 0x00, 0x01, 0x01, 0x00, 0xc0,
198         0x32,
199 
200     /* Interface descriptor */
201         0x09, 0x04, 0x00, 0x00, 0x03, 0x08, 0x06, 0x50,
202         0x00,
203 
204     /* Endpoint descriptor (Bulk In) */
205         0x07, 0x05, 0x81, 0x02, 0x00, 0x01, 0x00,
206 
207     /* Endpoint descriptor (Bulk Out) */
208         0x07, 0x05, 0x02, 0x02, 0x00, 0x01, 0x00,
209 
210     /* Endpoint descriptor (Interrupt In) */
211         0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x01,
212 
213     /* Interface descriptor */
214         0x09, 0x04, 0x00, 0x01, 0x03, 0x08, 0x06, 0x50,
215         0x00,
216 
217     /* Endpoint descriptor (Bulk In) */
218         0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00,
219 
220     /* Endpoint descriptor (Bulk Out) */
221         0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
222 
223     /* Endpoint descriptor (Interrupt In) */
224         0x07, 0x05, 0x83, 0x03, 0x40, 0x00, 0x01,
225 
226     };
227 #define DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED ARRAY_COUNT(device_framework_high_speed)
228 
229 static UCHAR *bulk_in_endpoint_descriptor_hs =      &device_framework_high_speed[0x12 + 0x0a + 0x09 + 0x09];
230 static UCHAR *bulk_out_endpoint_descriptor_hs =     &device_framework_high_speed[0x12 + 0x0a + 0x09 + 0x09 + 0x07];
231 static UCHAR *interrupt_in_endpoint_descriptor_hs = &device_framework_high_speed[0x12 + 0x0a + 0x09 + 0x09 + 0x07 + 0x07];
232 
233 
234     /* String Device Framework :
235      Byte 0 and 1 : Word containing the language ID : 0x0904 for US
236      Byte 2       : Byte containing the index of the descriptor
237      Byte 3       : Byte containing the length of the descriptor string
238     */
239 
240 #define STRING_FRAMEWORK_LENGTH 38
241 static UCHAR string_framework[] = {
242 
243     /* Manufacturer string descriptor : Index 1 */
244         0x09, 0x04, 0x01, 0x0c,
245         0x45, 0x78, 0x70, 0x72,0x65, 0x73, 0x20, 0x4c,
246         0x6f, 0x67, 0x69, 0x63,
247 
248     /* Product string descriptor : Index 2 */
249         0x09, 0x04, 0x02, 0x0a,
250         0x46, 0x6c, 0x61, 0x73, 0x68, 0x20, 0x44, 0x69,
251         0x73, 0x6b,
252 
253     /* Serial Number string descriptor : Index 3 */
254         0x09, 0x04, 0x03, 0x04,
255         0x30, 0x30, 0x30, 0x31
256     };
257 
258 
259     /* Multiple languages are supported on the device, to add
260        a language besides english, the unicode language code must
261        be appended to the language_id_framework array and the length
262        adjusted accordingly. */
263 #define LANGUAGE_ID_FRAMEWORK_LENGTH 2
264 static UCHAR language_id_framework[] = {
265 
266     /* English. */
267         0x09, 0x04
268     };
269 
270 
271 /* Define the ISR dispatch.  */
272 
273 extern VOID    (*test_isr_dispatch)(void);
274 
275 
276 /* Prototype for test control return.  */
277 
278 void  test_control_return(UINT status);
279 
280 
281 /* Define the ISR dispatch routine.  */
282 
test_isr(void)283 static void    test_isr(void)
284 {
285 
286     /* For further expansion of interrupt-level testing.  */
287 }
288 
289 /* OS wrappers. */
290 
ux_test_semaphore_get(TX_SEMAPHORE * sempahore,UINT wait_option)291 static void ux_test_semaphore_get(TX_SEMAPHORE *sempahore, UINT wait_option)
292 {
293 
294 UINT status;
295 
296 
297     status =  ux_utility_semaphore_get(sempahore, wait_option);
298     if (status != UX_SUCCESS)
299     {
300 
301         printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status);
302         test_control_return(1);
303     }
304 }
305 
306 /* General test resources. */
307 
lock_out_storage_thread()308 static void lock_out_storage_thread()
309 {
310 
311 UINT status;
312 
313 
314     status = ux_utility_semaphore_get(&global_storage -> ux_host_class_storage_semaphore,TX_WAIT_FOREVER);
315     if (status != UX_SUCCESS)
316     {
317 
318         printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status);
319         test_control_return(1);
320     }
321 
322     global_is_storage_thread_locked_out = 1;
323 }
324 
lock_in_storage_thread()325 static void lock_in_storage_thread()
326 {
327 
328 UINT status;
329 
330 
331     status = ux_utility_semaphore_put(&global_storage -> ux_host_class_storage_semaphore);
332     if (status != UX_SUCCESS)
333     {
334 
335         printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status);
336         test_control_return(1);
337     }
338 
339     global_is_storage_thread_locked_out = 0;
340 }
341 
ux_test_host_class_storage_media_read(UX_HOST_CLASS_STORAGE * storage,ULONG sector_start,ULONG sector_count,UCHAR * data_pointer)342 static UINT ux_test_host_class_storage_media_read(UX_HOST_CLASS_STORAGE *storage, ULONG sector_start, ULONG sector_count, UCHAR *data_pointer)
343 {
344 
345     UX_TEST_ASSERT(global_is_storage_thread_locked_out);
346     return(ux_host_class_storage_media_read(storage, sector_start, sector_count, data_pointer));
347 }
348 
ux_test_host_class_storage_media_write(UX_HOST_CLASS_STORAGE * storage,ULONG sector_start,ULONG sector_count,UCHAR * data_pointer)349 static UINT ux_test_host_class_storage_media_write(UX_HOST_CLASS_STORAGE *storage, ULONG sector_start, ULONG sector_count, UCHAR *data_pointer)
350 {
351 
352     UX_TEST_ASSERT(global_is_storage_thread_locked_out);
353     return(ux_host_class_storage_media_write(storage, sector_start, sector_count, data_pointer));
354 }
355 
356 /* Does a write - for times when you just want a write to trigger a CBW or something. */
do_any_write()357 static void do_any_write()
358 {
359 
360     lock_out_storage_thread();
361     ux_test_host_class_storage_media_write(global_storage, 10, 10, global_buffer);
362     lock_in_storage_thread();
363 }
364 
365 /* Storage thread needs to be locked out when this is called. */
366 UINT _ux_host_stack_endpoint_reset(UX_ENDPOINT *endpoint);
receive_device_csw()367 static void receive_device_csw()
368 {
369 
370 UX_TRANSFER *transfer_request;
371 
372 
373     UX_TEST_ASSERT(global_is_storage_thread_locked_out);
374 
375     if (global_slave_storage_bulk_in->ux_slave_endpoint_state == UX_ENDPOINT_HALTED)
376     {
377         _ux_host_stack_endpoint_reset(global_storage->ux_host_class_storage_bulk_in_endpoint);
378     }
379 
380     transfer_request =  &global_storage -> ux_host_class_storage_bulk_in_endpoint -> ux_endpoint_transfer_request;
381     transfer_request -> ux_transfer_request_data_pointer =      (UCHAR *) &global_storage -> ux_host_class_storage_csw;
382     transfer_request -> ux_transfer_request_requested_length =  UX_HOST_CLASS_STORAGE_CSW_LENGTH;
383     UX_TEST_CHECK_SUCCESS(ux_host_stack_transfer_request(transfer_request));
384     UX_TEST_CHECK_SUCCESS(ux_utility_semaphore_get(&transfer_request->ux_transfer_request_semaphore, TX_WAIT_FOREVER));
385 
386     /* Note: we want to do this _after_ because it's possible the device hasn't stalled the OUT endpoint before. */
387     if (global_slave_storage_bulk_out->ux_slave_endpoint_state == UX_ENDPOINT_HALTED)
388     {
389         _ux_host_stack_endpoint_reset(global_storage->ux_host_class_storage_bulk_out_endpoint);
390     }
391 }
392 
393 /* Sometimes we need to storage instance during enumeration and before our system host change function has been called. */
get_internal_host_storage_instance()394 static UX_HOST_CLASS_STORAGE *get_internal_host_storage_instance()
395 {
396     return _ux_system_host -> ux_system_host_class_array[0].ux_host_class_first_instance;
397 }
398 
399 /* Sometimes we need to storage instance during enumeration and before our system host change function has been called. */
get_internal_host_storage_medias()400 static UX_HOST_CLASS_STORAGE_MEDIA *get_internal_host_storage_medias()
401 {
402     return (_ux_system_host -> ux_system_host_class_array[0].ux_host_class_media);
403 }
404 
get_host_enum_thread()405 static TX_THREAD *get_host_enum_thread()
406 {
407     return &_ux_system_host->ux_system_host_enum_thread;
408 }
409 
ux_slave_class_storage_instance_activate(VOID * instance)410 static VOID ux_slave_class_storage_instance_activate(VOID *instance)
411 {
412 
413 UX_SLAVE_ENDPOINT *tmp;
414 
415 
416     global_slave_storage = (UX_SLAVE_CLASS_STORAGE *)instance;
417 
418     global_slave_storage_bulk_in = global_slave_storage->ux_slave_class_storage_interface->ux_slave_interface_first_endpoint;
419     global_slave_storage_bulk_out = global_slave_storage_bulk_in->ux_slave_endpoint_next_endpoint;
420     if ((global_slave_storage_bulk_in->ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_IN)
421     {
422 
423         tmp = global_slave_storage_bulk_in;
424         global_slave_storage_bulk_in = global_slave_storage_bulk_out;
425         global_slave_storage_bulk_out = tmp;
426     }
427 
428     /* As long as we don't unregister the storage class, this _should_ be fine! */
429     global_persistent_slave_storage = global_slave_storage;
430 }
431 
ux_slave_class_storage_instance_deactivate(VOID * instance)432 static VOID ux_slave_class_storage_instance_deactivate(VOID *instance)
433 {
434 
435     global_slave_storage = UX_NULL;
436     global_slave_storage_bulk_in = UX_NULL;
437     global_slave_storage_bulk_out = UX_NULL;
438 }
439 
ux_test_system_host_change_function(ULONG event,UX_HOST_CLASS * cls,VOID * inst)440 static UINT ux_test_system_host_change_function(ULONG event, UX_HOST_CLASS *cls, VOID *inst)
441 {
442 
443     switch(event)
444     {
445 
446         case UX_DEVICE_INSERTION:
447 
448             global_storage_change_function = inst;
449             break;
450 
451         case UX_DEVICE_REMOVAL:
452 
453             global_storage_change_function = UX_NULL;
454             break;
455 
456 #if defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
457         case UX_STORAGE_MEDIA_INSERTION:
458             /* keep using first media.  */
459             if (_ux_host_class_storage_media_index((UX_HOST_CLASS_STORAGE_MEDIA*)inst) == 0)
460             {
461                 _ux_host_class_storage_media_insert((UX_HOST_CLASS_STORAGE_MEDIA*)inst, 1);
462                 global_media = _ux_host_class_storage_media_fx_media((UX_HOST_CLASS_STORAGE_MEDIA*)inst);
463             }
464             break;
465 
466         case UX_STORAGE_MEDIA_REMOVAL:
467             if (_ux_host_class_storage_media_index((UX_HOST_CLASS_STORAGE_MEDIA*)inst) == 0)
468             {
469                 _ux_host_class_storage_media_remove((UX_HOST_CLASS_STORAGE_MEDIA*)inst);
470             }
471             break;
472 #endif
473 
474         default:
475             break;
476     }
477 
478     return 0;
479 }
480 
481 /* General worker thread resources. */
482 
483 typedef struct UX_TEST_WORKER_WORK
484 {
485     ULONG   input;
486     void    (*function)(ULONG);
487 } UX_TEST_WORKER_WORK;
488 
489 static UX_TEST_WORKER_WORK  *ux_test_worker_current_work;
490 static TX_SEMAPHORE         ux_test_worker_semaphore;
491 static TX_THREAD            ux_test_worker_thread;
492 static UCHAR                ux_test_worker_thread_stack[4096];
493 
ux_test_worker_add_work(UX_TEST_WORKER_WORK * work)494 static void ux_test_worker_add_work(UX_TEST_WORKER_WORK *work)
495 {
496 
497 UINT status;
498 
499 
500     /* There shouldn't be more than one work at a time. */
501     UX_TEST_ASSERT(ux_test_worker_semaphore.tx_semaphore_suspended_count == 1);
502 
503     ux_test_worker_current_work = work;
504 
505     status = ux_utility_semaphore_put(&ux_test_worker_semaphore);
506     if (status != UX_SUCCESS)
507     {
508 
509         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
510         test_control_return(1);
511     }
512 }
513 
ux_test_worker_thread_entry(ULONG input)514 static void ux_test_worker_thread_entry(ULONG input)
515 {
516 
517 UINT status;
518 
519 
520     while (1)
521     {
522 
523         /* Wait for some work. */
524         status = ux_utility_semaphore_get(&ux_test_worker_semaphore, TX_WAIT_FOREVER);
525         if (status != UX_SUCCESS)
526         {
527 
528             printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
529             test_control_return(1);
530         }
531 
532         /* Do the work. */
533         ux_test_worker_current_work->function(ux_test_worker_current_work->input);
534     }
535 }
536 
ux_test_worker_initialize()537 static void ux_test_worker_initialize()
538 {
539 
540 UINT status;
541 
542 
543     status = ux_utility_semaphore_create(&ux_test_worker_semaphore, "ux_test_worker_semaphore", 0);
544     if (status != UX_SUCCESS)
545     {
546 
547         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
548         test_control_return(1);
549     }
550 
551     status = ux_utility_thread_create(&ux_test_worker_thread, "ux_test_worker_thread", ux_test_worker_thread_entry, 0,
552                                       ux_test_worker_thread_stack, UX_DEMO_STACK_SIZE, 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
553     if (status != UX_SUCCESS)
554     {
555 
556         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
557         test_control_return(1);
558     }
559 }
560 
561 /* Simulate CBI resources. */
562 
563 UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter);
564 static TX_SEMAPHORE *cbi_interrupt_endpoint_transfer_semaphore;
565 static TX_SEMAPHORE cbi_transfer_request_csw_semaphore_host;
566 static UCHAR        *cbi_host_transfer_csw_data_pointer;
567 static UINT         global_cbi_fail_on_csw;
568 static UINT         global_cbi_actual_csw = UX_TRUE;
569 
ux_cbi_simulator_initialize()570 void ux_cbi_simulator_initialize()
571 {
572 
573 UINT status;
574 
575 
576     status = ux_utility_semaphore_create(&cbi_transfer_request_csw_semaphore_host, "transfer request csw semaphore device", 0);
577     if (status != UX_SUCCESS)
578     {
579 
580         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
581         test_control_return(1);
582     }
583 }
584 
get_host_bulk_endpoint(UCHAR get_bulk_out)585 static UX_ENDPOINT *get_host_bulk_endpoint(UCHAR get_bulk_out)
586 {
587 
588 UX_ENDPOINT *bulk_out;
589 UINT        direction = (get_bulk_out == UX_TRUE) ? UX_ENDPOINT_OUT : UX_ENDPOINT_IN;
590 
591 
592     bulk_out = global_host_device->ux_device_first_configuration->ux_configuration_first_interface->ux_interface_first_endpoint;
593     while (bulk_out)
594     {
595 
596         if ((bulk_out->ux_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) == direction &&
597            (bulk_out->ux_endpoint_descriptor.bmAttributes & UX_MASK_ENDPOINT_TYPE) == UX_BULK_ENDPOINT)
598         {
599             break;
600         }
601 
602         bulk_out = bulk_out->ux_endpoint_next_endpoint;
603     }
604     return bulk_out;
605 }
606 
get_host_bulk_out_endpoint()607 static UX_ENDPOINT *get_host_bulk_out_endpoint()
608 {
609     return get_host_bulk_endpoint(UX_TRUE);
610 }
611 
get_host_bulk_in_endpoint()612 static UX_ENDPOINT *get_host_bulk_in_endpoint()
613 {
614     return get_host_bulk_endpoint(UX_FALSE);
615 }
616 
_ux_hcd_sim_host_entry_bo_to_cbi(UX_HCD * hcd,UINT function,VOID * parameter)617 static UINT _ux_hcd_sim_host_entry_bo_to_cbi(UX_HCD *hcd, UINT function, VOID *parameter)
618 {
619 
620 UINT            status;
621 UINT            entry_status;
622 UX_TRANSFER     *transfer_request;
623 UX_ENDPOINT     *bulk_out;
624 UX_TRANSFER     *bulk_out_transfer_request;
625 UCHAR           *cbw;
626 UCHAR           *cb;
627 UINT            old_threshold;
628 
629 
630     if (function == UX_HCD_TRANSFER_REQUEST)
631     {
632 
633         transfer_request = parameter;
634 
635         /* Is this a CBW? */
636         if (transfer_request->ux_transfer_request_endpoint->ux_endpoint_descriptor.bmAttributes == 0x0 &&
637             transfer_request->ux_transfer_request_type == (UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE))
638         {
639 
640             /* Right now it's being sent on the control endpoint. Need to switch to bulk. */
641 
642             bulk_out = get_host_bulk_out_endpoint();
643             bulk_out_transfer_request = &bulk_out->ux_endpoint_transfer_request;
644 
645             /* Make the following check and assignment atomic. */
646             tx_thread_priority_change(tx_thread_identify(), 0, &old_threshold);
647 
648             /* We can only transfer when the device is ATTACHED, ADDRESSED OR CONFIGURED.  */
649             if ((global_host_device -> ux_device_state == UX_DEVICE_ATTACHED) || (global_host_device -> ux_device_state == UX_DEVICE_ADDRESSED)
650                     || (global_host_device -> ux_device_state == UX_DEVICE_CONFIGURED))
651 
652                 /* Set the pending transfer request.  */
653                 bulk_out_transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_STATUS_PENDING;
654 
655             tx_thread_priority_change(tx_thread_identify(), old_threshold, &old_threshold);
656 
657             if (bulk_out_transfer_request -> ux_transfer_request_completion_code != UX_TRANSFER_STATUS_PENDING)
658                 return(UX_TRANSFER_NOT_READY);
659 
660             /* Through the power of friendship, we know the CBW is located behind the UFI. */
661             cb = transfer_request->ux_transfer_request_data_pointer;
662             cbw = cb - UX_HOST_CLASS_STORAGE_CBW_CB;
663 
664             bulk_out_transfer_request->ux_transfer_request_data_pointer = cbw;
665             bulk_out_transfer_request->ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH;
666 
667             entry_status = _ux_hcd_sim_host_entry(hcd, function, bulk_out_transfer_request);
668             if (entry_status == UX_SUCCESS)
669             {
670 
671                 /* The caller expects this to be blocking since it's a control transfer, so wait for it to complete. */
672                 status = ux_utility_semaphore_get(&bulk_out_transfer_request->ux_transfer_request_semaphore, TX_WAIT_FOREVER);
673                 if (status != UX_SUCCESS)
674                 {
675 
676                     printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
677                     test_control_return(1);
678                 }
679             }
680 
681             transfer_request->ux_transfer_request_completion_code = bulk_out_transfer_request->ux_transfer_request_completion_code;
682             transfer_request->ux_transfer_request_status = bulk_out_transfer_request->ux_transfer_request_status;
683 
684             return entry_status;
685         }
686 
687         /* Is this a CSW (only thing that could be on the interrupt endpoint)? */
688         else if (transfer_request->ux_transfer_request_endpoint->ux_endpoint_descriptor.bmAttributes == 0x03)
689         {
690 
691             /* Make the following check and assignment atomic. */
692             tx_thread_priority_change(tx_thread_identify(), 0, &old_threshold);
693 
694             /* We can only transfer when the device is ATTACHED, ADDRESSED OR CONFIGURED.  */
695             if ((global_host_device -> ux_device_state == UX_DEVICE_ATTACHED) || (global_host_device -> ux_device_state == UX_DEVICE_ADDRESSED)
696                     || (global_host_device -> ux_device_state == UX_DEVICE_CONFIGURED))
697 
698                 /* Set the pending transfer request.  */
699                 transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_STATUS_PENDING;
700 
701             tx_thread_priority_change(tx_thread_identify(), old_threshold, &old_threshold);
702 
703             if (transfer_request -> ux_transfer_request_completion_code != UX_TRANSFER_STATUS_PENDING)
704                 return(UX_TRANSFER_NOT_READY);
705 
706             cbi_host_transfer_csw_data_pointer = transfer_request->ux_transfer_request_data_pointer;
707             cbi_interrupt_endpoint_transfer_semaphore = &transfer_request->ux_transfer_request_semaphore;
708 
709             if (global_cbi_actual_csw == UX_TRUE)
710             {
711 
712                 /* Tell device we've received csw request. */
713                 status = ux_utility_semaphore_put(&cbi_transfer_request_csw_semaphore_host);
714                 if (status != UX_SUCCESS)
715                 {
716 
717                     printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
718                     test_control_return(1);
719                 }
720 
721                 /* Wait for device to copy data. */
722                 status = ux_utility_semaphore_get(&transfer_request -> ux_transfer_request_semaphore, TX_WAIT_FOREVER);
723                 if (status != UX_SUCCESS)
724                 {
725 
726                     printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
727                     test_control_return(1);
728                 }
729 
730                 /* Release semaphore for caller. */
731                 status = ux_utility_semaphore_put(&transfer_request->ux_transfer_request_semaphore);
732                 if (status != UX_SUCCESS)
733                 {
734 
735                     printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
736                     test_control_return(1);
737                 }
738             }
739             else
740             {
741 
742                 global_cbi_actual_csw = UX_TRUE;
743             }
744 
745             transfer_request->ux_transfer_request_completion_code = UX_SUCCESS;
746             transfer_request->ux_transfer_request_status = UX_TRANSFER_STATUS_COMPLETED;
747 
748             if (global_cbi_fail_on_csw == UX_TRUE)
749             {
750 
751                 global_cbi_fail_on_csw = UX_FALSE;
752                 return(UX_ERROR);
753             }
754 
755             return UX_SUCCESS;
756         }
757     }
758 
759     return _ux_hcd_sim_host_entry(hcd, function, parameter);
760 }
761 
_ux_dcd_sim_slave_function_bo_to_cbi(UX_SLAVE_DCD * dcd,UINT function,VOID * parameter)762 static UINT _ux_dcd_sim_slave_function_bo_to_cbi(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter)
763 {
764 
765 UINT                status;
766 ULONG               mask;
767 UX_SLAVE_TRANSFER   *transfer_request;
768 
769 
770     if (function == UX_DCD_TRANSFER_REQUEST)
771     {
772 
773 #if 0
774         /* See matching #if block in host bo_to_cbi. */
775 #else
776         transfer_request = parameter;
777 
778         mask = ux_utility_long_get(&transfer_request->ux_slave_transfer_request_data_pointer[UX_SLAVE_CLASS_STORAGE_CSW_SIGNATURE]);
779 
780         /* Is this a CSW? */
781         if (mask == UX_SLAVE_CLASS_STORAGE_CSW_SIGNATURE_MASK)
782         {
783 
784             /* Wait for host to send CSW request. */
785             status = ux_utility_semaphore_get(&cbi_transfer_request_csw_semaphore_host, TX_WAIT_FOREVER);
786             if (status != UX_SUCCESS)
787             {
788 
789                 printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
790                 test_control_return(1);
791             }
792 
793             /* Copy CSW to host. */
794             ux_utility_memory_copy(cbi_host_transfer_csw_data_pointer,
795                 transfer_request->ux_slave_transfer_request_current_data_pointer, UX_SLAVE_CLASS_STORAGE_CSW_LENGTH);
796 
797             /* Tell host we've copied data */
798             status = ux_utility_semaphore_put(cbi_interrupt_endpoint_transfer_semaphore);
799             if (status != UX_SUCCESS)
800             {
801 
802                 printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
803                 test_control_return(1);
804             }
805 
806             transfer_request->ux_slave_transfer_request_completion_code = UX_SUCCESS;
807             transfer_request->ux_slave_transfer_request_status = UX_TRANSFER_STATUS_COMPLETED;
808 
809             return UX_SUCCESS;
810         }
811 #endif
812     }
813 
814     return _ux_dcd_sim_slave_function(dcd, function, parameter);
815 }
816 
817 /* Simulate CB resources. */
818 
819 UINT _ux_hcd_sim_host_entry(UX_HCD *hcd, UINT function, VOID *parameter);
_ux_hcd_sim_host_entry_bo_to_cb(UX_HCD * hcd,UINT function,VOID * parameter)820 static UINT _ux_hcd_sim_host_entry_bo_to_cb(UX_HCD *hcd, UINT function, VOID *parameter)
821 {
822 
823 UINT            status;
824 UINT            entry_status;
825 UX_TRANSFER     *transfer_request;
826 UX_ENDPOINT     *bulk_out;
827 UX_TRANSFER     *bulk_out_transfer_request;
828 UCHAR           *cbw;
829 UCHAR           *cb;
830 UINT            old_threshold;
831 
832 
833     if (function == UX_HCD_TRANSFER_REQUEST)
834     {
835 
836         transfer_request = parameter;
837 
838         /* Is this a CBW? */
839         if (transfer_request->ux_transfer_request_type == (UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE))
840         {
841 
842             /* Right now it's being sent on the control endpoint. Need to switch to bulk. */
843 
844             bulk_out = global_host_device->ux_device_first_configuration->ux_configuration_first_interface->ux_interface_first_endpoint->ux_endpoint_next_endpoint;
845             bulk_out_transfer_request = &bulk_out->ux_endpoint_transfer_request;
846 
847             /* Make the following check and assignment atomic. */
848             tx_thread_priority_change(tx_thread_identify(), 0, &old_threshold);
849 
850             /* We can only transfer when the device is ATTACHED, ADDRESSED OR CONFIGURED.  */
851             if ((global_host_device -> ux_device_state == UX_DEVICE_ATTACHED) || (global_host_device -> ux_device_state == UX_DEVICE_ADDRESSED)
852                     || (global_host_device -> ux_device_state == UX_DEVICE_CONFIGURED))
853 
854                 /* Set the pending transfer request.  */
855                 bulk_out_transfer_request -> ux_transfer_request_completion_code = UX_TRANSFER_STATUS_PENDING;
856 
857             tx_thread_priority_change(tx_thread_identify(), old_threshold, &old_threshold);
858 
859             if (transfer_request -> ux_transfer_request_completion_code != UX_TRANSFER_STATUS_PENDING)
860                 return(UX_TRANSFER_NOT_READY);
861 
862             /* Through the power of friendship, we know the CBW is located behind the UFI. */
863             cb = transfer_request->ux_transfer_request_data_pointer;
864             cbw = cb - UX_HOST_CLASS_STORAGE_CBW_CB;
865 
866             bulk_out_transfer_request->ux_transfer_request_data_pointer = cbw;
867             bulk_out_transfer_request->ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH;
868 
869             entry_status = _ux_hcd_sim_host_entry(hcd, function, bulk_out_transfer_request);
870 
871             if (entry_status == UX_SUCCESS)
872             {
873 
874                 /* The caller expects this to be blocking since it's a control transfer, so wait for it to complete. */
875                 status = ux_utility_semaphore_get(&bulk_out_transfer_request->ux_transfer_request_semaphore, TX_WAIT_FOREVER);
876                 if (status != UX_SUCCESS)
877                 {
878 
879                     printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
880                     test_control_return(1);
881                 }
882             }
883 
884             transfer_request->ux_transfer_request_completion_code = bulk_out_transfer_request->ux_transfer_request_completion_code;
885             transfer_request->ux_transfer_request_status = bulk_out_transfer_request->ux_transfer_request_status;
886 
887             return entry_status;
888         }
889     }
890 
891     return _ux_hcd_sim_host_entry(hcd, function, parameter);
892 }
893 
_ux_dcd_sim_slave_function_bo_to_cb(UX_SLAVE_DCD * dcd,UINT function,VOID * parameter)894 static UINT _ux_dcd_sim_slave_function_bo_to_cb(UX_SLAVE_DCD *dcd, UINT function, VOID *parameter)
895 {
896 
897 UX_SLAVE_TRANSFER   *transfer_request;
898 ULONG               mask;
899 
900 
901     if (function == UX_DCD_TRANSFER_REQUEST)
902     {
903 
904         transfer_request = parameter;
905 
906         mask = ux_utility_long_get(&transfer_request->ux_slave_transfer_request_data_pointer[UX_SLAVE_CLASS_STORAGE_CSW_SIGNATURE]);
907 
908         /* Is this a CSW? */
909         if (mask == UX_SLAVE_CLASS_STORAGE_CSW_SIGNATURE_MASK)
910         {
911 
912             /* Sike, that's the wrong number! */
913             /* Ignore cause there is no CSW in CB protocol. */
914 
915             transfer_request->ux_slave_transfer_request_completion_code = UX_SUCCESS;
916             transfer_request->ux_slave_transfer_request_status = UX_TRANSFER_STATUS_COMPLETED;
917 
918             return UX_SUCCESS;
919         }
920     }
921 
922     return _ux_dcd_sim_slave_function(dcd, function, parameter);
923 }
924 
format_ram_disk()925 static void format_ram_disk()
926 {
927 
928 UINT status;
929 
930 
931     /* We need to close media before formatting. */
932     status = fx_media_close(&global_ram_disk);
933     if (status != FX_SUCCESS)
934     {
935 
936         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
937         test_control_return(1);
938     }
939 
940     status =  fx_media_format(&global_ram_disk, _fx_ram_driver, global_ram_disk_memory, global_ram_disk_working_buffer, global_sector_size, "RAM DISK", 2, UX_TEST_NUM_DIRECTORY_ENTRIES, 0, UX_RAM_DISK_SIZE/global_sector_size, global_sector_size, 4, 1, 1);
941     if (status != FX_SUCCESS)
942     {
943 
944         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
945         test_control_return(1);
946     }
947 
948     status =  fx_media_open(&global_ram_disk, "RAM DISK", _fx_ram_driver, global_ram_disk_memory, global_ram_disk_working_buffer, sizeof(global_ram_disk_working_buffer));
949     if (status != FX_SUCCESS)
950     {
951 
952         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
953         test_control_return(1);
954     }
955 }
956 
957 /* Disconnection and connection functions. Note that these should be the only ways you disconnect and connect, for the
958    sake of 'funneling'. */
959 
960 /* This function should not be called from inside USBX because we wait for the deactivation to finish. If we have a
961    semaphore the deactivation routine requires, then we have deadlock.
962    Note that we format the ram disk during connection because global_sector_size uses changes after we call
963    disconnect(). */
disconnect_host_and_slave()964 static void disconnect_host_and_slave()
965 {
966 
967     ux_test_dcd_sim_slave_disconnect();
968     ux_test_hcd_sim_host_disconnect_no_wait();
969 
970     /* Wait for disconnect to finish. */
971     while (global_hcd->ux_hcd_nb_devices != 0)
972         tx_thread_sleep(10);
973 
974     /* Do a memory check. */
975 
976     /* Has the value not been initialized yet? */
977     if (global_memory_test_no_device_memory_free_amount == 0)
978         return;
979 
980     if (_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available != global_memory_test_no_device_memory_free_amount)
981     {
982 
983         printf("Error on line %d\n", __LINE__);
984         test_control_return(1);
985     }
986 }
987 
disconnect_host_and_slave_work_func(ULONG input)988 static void disconnect_host_and_slave_work_func(ULONG input)
989 {
990 
991     disconnect_host_and_slave();
992 }
993 
994 static UX_TEST_WORKER_WORK global_disconnect_host_and_slave_work = { 0, disconnect_host_and_slave_work_func };
disconnect_host_and_slave_action_func(UX_TEST_ACTION * action,VOID * _params)995 static void disconnect_host_and_slave_action_func(UX_TEST_ACTION *action, VOID *_params)
996 {
997 
998 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
999 
1000 
1001     ux_test_worker_add_work(&global_disconnect_host_and_slave_work);
1002 
1003     /* Allow enum thread to run. This is what we want to have happen, like, all of the time. */
1004     tx_thread_relinquish();
1005 }
1006 
1007 /* Note: This assumes the enum thread is already running AKA enum thread's semaphore
1008    was put() before. */
wait_for_enum_completion_and_get_global_storage_values()1009 static UINT wait_for_enum_completion_and_get_global_storage_values()
1010 {
1011 
1012 UINT status;
1013 
1014 
1015     /* Should already be running! */
1016     UX_TEST_ASSERT(_ux_system_host -> ux_system_host_enum_semaphore.tx_semaphore_suspended_count == 0);
1017 
1018     /* Wait for enum thread to complete. */
1019     while (_ux_system_host -> ux_system_host_enum_semaphore.tx_semaphore_suspended_count == 0)
1020         tx_thread_sleep(10);
1021 
1022     status = ux_host_stack_class_get(_ux_system_host_class_storage_name, &global_host_storage_class);
1023     UX_TEST_ASSERT(status == UX_SUCCESS);
1024 
1025     status = ux_host_stack_class_instance_get(global_host_storage_class, 0, (void **) &global_storage);
1026     if (status)
1027         return status;
1028 
1029     global_host_class_ext = global_host_storage_class -> ux_host_class_ext;
1030 
1031     if (global_storage -> ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_LIVE ||
1032         global_host_class_ext == UX_NULL ||
1033         global_host_storage_class -> ux_host_class_media == UX_NULL)
1034         return UX_ERROR;
1035 
1036     global_storage_medias = global_host_storage_class->ux_host_class_media;
1037     global_storage_media = &global_storage_medias[0];
1038 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
1039     global_media =  &global_storage_media->ux_host_class_storage_media;
1040 #endif
1041     global_storage_thread = &global_host_class_ext->ux_host_class_thread;
1042 
1043     return status;
1044 }
1045 
1046 /* Returns whether or not the enumeration succeeded. */
connect_host_and_slave()1047 static UINT connect_host_and_slave()
1048 {
1049 
1050 UINT status;
1051 
1052 
1053     /* The worker thread might be in the middle of waiting for the disconnect
1054        to complete. Don't confuse it! */
1055     while (ux_test_worker_semaphore.tx_semaphore_suspended_count == 0)
1056         tx_thread_sleep(10);
1057 
1058     /* During the basic test, although we delete the file, it seems to stay
1059        on the disk. Clear everything and reformat the disk (reformatting doesn't
1060        clear everything). */
1061     memset(global_ram_disk_memory, 0, sizeof(global_ram_disk_memory));
1062     format_ram_disk();
1063 
1064     ux_test_dcd_sim_slave_connect(UX_FULL_SPEED_DEVICE);
1065 
1066     /* No wait because wait_for_enum...() expects the enum thread to be running
1067        when it's called. */
1068     ux_test_hcd_sim_host_connect_no_wait(UX_FULL_SPEED_DEVICE);
1069 
1070     status = wait_for_enum_completion_and_get_global_storage_values();
1071 
1072     return status;
1073 }
1074 
switch_to_protocol(UCHAR protocol)1075 static void switch_to_protocol(UCHAR protocol)
1076 {
1077     switch (protocol)
1078     {
1079 
1080     case UX_HOST_CLASS_STORAGE_PROTOCOL_BO:
1081             device_framework_full_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_BO;
1082             device_framework_high_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_BO;
1083             device_framework_full_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_SCSI;
1084             device_framework_high_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_SCSI;
1085             global_hcd->ux_hcd_entry_function = _ux_test_hcd_sim_host_entry;
1086             global_dcd->ux_slave_dcd_function = _ux_test_dcd_sim_slave_function;
1087         break;
1088 
1089     case UX_HOST_CLASS_STORAGE_PROTOCOL_CBI:
1090             device_framework_full_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI;
1091             device_framework_high_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI;
1092             device_framework_full_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI;
1093             device_framework_high_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI;
1094             global_hcd->ux_hcd_entry_function = _ux_hcd_sim_host_entry_bo_to_cbi;
1095             global_dcd->ux_slave_dcd_function = _ux_dcd_sim_slave_function_bo_to_cbi;
1096         break;
1097 
1098     case UX_HOST_CLASS_STORAGE_PROTOCOL_CB:
1099             device_framework_full_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CB;
1100             device_framework_high_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CB;
1101             device_framework_full_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI;
1102             device_framework_high_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI;
1103             global_hcd->ux_hcd_entry_function = _ux_hcd_sim_host_entry_bo_to_cb;
1104             global_dcd->ux_slave_dcd_function = _ux_dcd_sim_slave_function_bo_to_cb;
1105         break;
1106     }
1107 }
1108 
1109 /* For restoring state for next test. */
reset_to_bo()1110 static void reset_to_bo()
1111 {
1112 
1113     disconnect_host_and_slave();
1114 
1115     global_sector_size = UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT;
1116 
1117     switch_to_protocol(UX_HOST_CLASS_STORAGE_PROTOCOL_BO);
1118 
1119     bulk_in_endpoint_descriptor_fs[Endpoint_bEndpointAddress] = 0x81;
1120     bulk_in_endpoint_descriptor_hs[Endpoint_bEndpointAddress] = 0x81;
1121     bulk_in_endpoint_descriptor_fs[Endpoint_bmAttributes] = 0x02;
1122     bulk_in_endpoint_descriptor_hs[Endpoint_bmAttributes] = 0x02;
1123 
1124     bulk_out_endpoint_descriptor_fs[Endpoint_bEndpointAddress] = 0x02;
1125     bulk_out_endpoint_descriptor_hs[Endpoint_bEndpointAddress] = 0x02;
1126     bulk_out_endpoint_descriptor_fs[Endpoint_bmAttributes] = 0x02;
1127     bulk_out_endpoint_descriptor_hs[Endpoint_bmAttributes] = 0x02;
1128 
1129     interrupt_in_endpoint_descriptor_fs[Endpoint_bEndpointAddress] = 0x83;
1130     interrupt_in_endpoint_descriptor_hs[Endpoint_bEndpointAddress] = 0x83;
1131     interrupt_in_endpoint_descriptor_fs[Endpoint_bmAttributes] = 0x03;
1132     interrupt_in_endpoint_descriptor_hs[Endpoint_bmAttributes] = 0x03;
1133 
1134     global_persistent_slave_storage->ux_slave_class_storage_number_lun = 1;
1135     global_persistent_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_type = UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK;
1136     global_persistent_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_removable_flag = 0x80;
1137     global_persistent_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_block_length = global_sector_size;
1138 
1139     connect_host_and_slave();
1140 }
1141 
1142 /* This function is called when the device tries to read/write to the device. We return an error so that transfer
1143    succeeds, but the CSW contains an error (this is for the multiple read retries test). */
fx_media_read_write_test_error_action_func(VOID * storage,ULONG lun,UCHAR * data_pointer,ULONG number_blocks,ULONG lba,ULONG * media_status)1144 static UINT fx_media_read_write_test_error_action_func(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status)
1145 {
1146 
1147     *media_status = (ULONG)-1;
1148     return UX_ERROR;
1149 }
1150 
1151 UX_TEST_SETUP global_setup_endpoint_reset_in1 =
1152 {
1153     UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_ENDPOINT,
1154     UX_CLEAR_FEATURE,
1155     UX_ENDPOINT_HALT,
1156     0x81
1157 };
1158 
1159 UX_TEST_SETUP global_setup_endpoint_reset_out2 =
1160 {
1161     UX_REQUEST_OUT | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_ENDPOINT,
1162     UX_CLEAR_FEATURE,
1163     UX_ENDPOINT_HALT,
1164     0x02
1165 };
1166 
1167 UX_TEST_SETUP global_setup_mass_storage_reset =
1168 {
1169     UX_REQUEST_OUT | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE,
1170     UX_HOST_CLASS_STORAGE_RESET,
1171     0,
1172     0
1173 };
1174 
1175 /* Action creation functions. */
1176 
ux_test_memory_allocate_all_memory_action_func(UX_TEST_ACTION * action,VOID * _params)1177 static void ux_test_memory_allocate_all_memory_action_func(UX_TEST_ACTION *action, VOID *_params)
1178 {
1179 
1180     ux_test_utility_sim_mem_allocate_until_align_flagged(0, 0, action->memory_cache_flag);
1181 }
1182 
create_disconnect_on_thread_preemption_change(TX_THREAD * thread_to_match,TX_THREAD * preemption_change_param_thread_ptr,UINT preemption_change_param_new_threshold)1183 static UX_TEST_ACTION create_disconnect_on_thread_preemption_change(TX_THREAD *thread_to_match, TX_THREAD *preemption_change_param_thread_ptr, UINT preemption_change_param_new_threshold)
1184 {
1185 
1186 UX_TEST_ACTION action = { 0 };
1187 
1188 
1189     action.usbx_function = UX_TEST_OVERRIDE_TX_THREAD_PREEMPTION_CHANGE;
1190     action.thread_ptr = preemption_change_param_thread_ptr;
1191     action.new_threshold = preemption_change_param_new_threshold;
1192     action.action_func = disconnect_host_and_slave_action_func;
1193     action.thread_to_match = thread_to_match;
1194     action.do_after = 1;
1195 
1196     return action;
1197 }
1198 
device_media_write_block_action_func(UX_TEST_ACTION * action,VOID * _params)1199 static VOID device_media_write_block_action_func(UX_TEST_ACTION *action, VOID *_params)
1200 {
1201 
1202 UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *params = (UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *)_params;
1203 
1204 
1205     /* 100% of the time, we're doing this block so we can hit a transfer timeout branch. The problem is that the
1206        timeouts can take a while, so we abort the waits prematurely from here since the test thread (and therefore host)
1207        are blocked. */
1208 
1209 DEVICE_MEDIA_READ_WRITE_TIMEOUT_DATA    *timeout_data = (DEVICE_MEDIA_READ_WRITE_TIMEOUT_DATA *)action->user_data;
1210 TX_SEMAPHORE                            *semaphore = &timeout_data->transfer_request->ux_transfer_request_semaphore;
1211 
1212 
1213     while (timeout_data->num_timeouts--)
1214     {
1215 
1216         /* Wait for host thread to wait on the semaphore. */
1217         while (semaphore->tx_semaphore_suspended_count == 0)
1218             tx_thread_sleep(10);
1219 
1220         UX_TEST_ASSERT(semaphore->tx_semaphore_suspension_list != UX_NULL);
1221 
1222         /* Now simulate a timeout. */
1223         UX_TEST_CHECK_SUCCESS(tx_thread_wait_abort(semaphore->tx_semaphore_suspension_list));
1224     }
1225 
1226     /* It's unrealistic for us the complete the write _right_ after the host timeouts. Therefore, we sleep a little
1227        longer. It's up to the user to unblock the CSW we do after.
1228        Note: I got this sleep value from ux_hcd_sim_host_transfer_abort.c: it's 10x the 1 ms it does. */
1229     ux_utility_delay_ms(10*1);
1230 }
1231 
create_device_media_write_block_action(DEVICE_MEDIA_READ_WRITE_TIMEOUT_DATA * timeout_data)1232 static UX_TEST_ACTION create_device_media_write_block_action(DEVICE_MEDIA_READ_WRITE_TIMEOUT_DATA *timeout_data)
1233 {
1234 
1235 UX_TEST_ACTION action = { 0 };
1236 
1237 
1238     action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_WRITE;
1239     action.ignore_params = 1;
1240     action.no_return = 0;
1241     action.status = UX_ERROR;
1242     action.action_func = device_media_write_block_action_func;
1243     action.user_data = (ALIGN_TYPE)timeout_data;
1244 
1245     return(action);
1246 }
1247 
device_media_read_write_media_status_error_action_func(UX_TEST_ACTION * action,VOID * _params)1248 static VOID device_media_read_write_media_status_error_action_func(UX_TEST_ACTION *action, VOID *_params)
1249 {
1250 
1251 UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *params = (UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *)_params;
1252 
1253 
1254     *params->media_status = ~0;
1255 }
1256 
device_media_status_error_action_func(UX_TEST_ACTION * action,VOID * _params)1257 static VOID device_media_status_error_action_func(UX_TEST_ACTION *action, VOID *_params)
1258 {
1259 
1260 UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS_PARAMS *params = (UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS_PARAMS *)_params;
1261 
1262 
1263     *params->media_status = ~0;
1264 }
1265 
create_device_media_read_fail_action()1266 static UX_TEST_ACTION create_device_media_read_fail_action()
1267 {
1268 
1269 UX_TEST_ACTION action = { 0 };
1270 
1271 
1272     action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ;
1273     action.ignore_params = 1;
1274     action.action_func = device_media_read_write_media_status_error_action_func;
1275     action.no_return = 0;
1276     action.status = UX_ERROR;
1277 
1278     return action;
1279 }
1280 
create_device_media_write_fail_action()1281 static UX_TEST_ACTION create_device_media_write_fail_action()
1282 {
1283 
1284 UX_TEST_ACTION action = { 0 };
1285 
1286 
1287     action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_WRITE;
1288     action.ignore_params = 1;
1289     action.action_func = device_media_read_write_media_status_error_action_func;
1290     action.no_return = 0;
1291     action.status = UX_ERROR;
1292 
1293     return action;
1294 }
1295 
configuration_reset_action_func(UX_TEST_ACTION * action,VOID * _params)1296 static void configuration_reset_action_func(UX_TEST_ACTION *action, VOID *_params)
1297 {
1298 
1299 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
1300 UINT                                status;
1301 
1302 
1303     status = ux_host_stack_device_configuration_reset(global_host_device);
1304     if (status != UX_SUCCESS)
1305     {
1306 
1307         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
1308         test_control_return(1);
1309     }
1310 }
1311 
create_disconnect_on_media_characteristics_get_action(TX_THREAD * thread_to_match)1312 static UX_TEST_ACTION create_disconnect_on_media_characteristics_get_action(TX_THREAD *thread_to_match)
1313 {
1314 
1315 UX_TEST_ACTION action = { 0 };
1316 
1317 
1318     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1319     action.function = UX_HCD_TRANSFER_REQUEST;
1320     action.req_data = global_cbw_data_media_characteristics_get_sbc;
1321     action.req_actual_len = sizeof(global_cbw_data_media_characteristics_get_sbc);
1322     action.action_func = disconnect_host_and_slave_action_func;
1323     action.thread_to_match = thread_to_match;
1324     action.no_return = 1;
1325 
1326     return action;
1327 }
1328 
create_format_capacity_get_match_action(TX_THREAD * thread_to_match)1329 static UX_TEST_ACTION create_format_capacity_get_match_action(TX_THREAD *thread_to_match)
1330 {
1331 
1332 UX_TEST_ACTION action = { 0 };
1333 
1334 
1335     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1336     action.function = UX_HCD_TRANSFER_REQUEST;
1337     action.req_action = UX_TEST_MATCH_REQ_LEN;
1338     action.req_requested_len = UX_HOST_CLASS_STORAGE_READ_FORMAT_RESPONSE_LENGTH;
1339     action.thread_to_match = thread_to_match;
1340     action.no_return = 1;
1341 
1342     return action;
1343 }
1344 
create_disconnect_on_transfer_data_match_action(TX_THREAD * thread_to_match,UCHAR * data,UINT data_size)1345 static UX_TEST_ACTION create_disconnect_on_transfer_data_match_action(TX_THREAD *thread_to_match, UCHAR *data, UINT data_size)
1346 {
1347 
1348 UX_TEST_ACTION action = { 0 };
1349 
1350 
1351     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1352     action.function = UX_HCD_TRANSFER_REQUEST;
1353     action.req_data = data;
1354     action.req_actual_len = data_size;
1355     action.action_func = disconnect_host_and_slave_action_func;
1356     action.thread_to_match = thread_to_match;
1357     action.no_return = 1;
1358 
1359     return action;
1360 }
1361 
create_allocate_all_memory_on_transfer_data_match_action(TX_THREAD * thread_to_match,ULONG memory_cache_flag,UCHAR * data,UINT data_size)1362 static UX_TEST_ACTION create_allocate_all_memory_on_transfer_data_match_action(TX_THREAD *thread_to_match, ULONG memory_cache_flag, UCHAR *data, UINT data_size)
1363 {
1364 
1365 UX_TEST_ACTION action = { 0 };
1366 
1367 
1368     action = create_disconnect_on_transfer_data_match_action(thread_to_match, data, data_size);
1369     action.memory_cache_flag = memory_cache_flag;
1370     action.action_func = ux_test_memory_allocate_all_memory_action_func;
1371     action.no_return = 1;
1372 
1373     return action;
1374 }
1375 
create_setup_match_action(TX_THREAD * thread_to_match,UX_TEST_SETUP * req_setup)1376 static UX_TEST_ACTION create_setup_match_action(TX_THREAD *thread_to_match, UX_TEST_SETUP *req_setup)
1377 {
1378 
1379 UX_TEST_ACTION action = { 0 };
1380 
1381 
1382     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1383     action.function = UX_HCD_TRANSFER_REQUEST;
1384     action.req_action = UX_TEST_SETUP_MATCH_REQ_V_I;
1385     action.req_setup = req_setup;
1386     action.thread_to_match = thread_to_match;
1387     action.no_return = 1;
1388 
1389     return action;
1390 }
1391 
create_mass_storage_reset_match_action(TX_THREAD * thread_to_match)1392 static UX_TEST_ACTION create_mass_storage_reset_match_action(TX_THREAD *thread_to_match)
1393 {
1394 
1395 UX_TEST_ACTION action = { 0 };
1396 
1397 
1398     action = create_setup_match_action(thread_to_match, &global_setup_mass_storage_reset);
1399 
1400     return action;
1401 }
1402 
create_disconnect_on_mass_storage_reset_match_action(TX_THREAD * thread_to_match)1403 static UX_TEST_ACTION create_disconnect_on_mass_storage_reset_match_action(TX_THREAD *thread_to_match)
1404 {
1405 
1406 UX_TEST_ACTION action = { 0 };
1407 
1408 
1409     action = create_setup_match_action(thread_to_match, &global_setup_mass_storage_reset);
1410     action.action_func = disconnect_host_and_slave_action_func;
1411 
1412     return action;
1413 }
1414 
create_error_match_action_from_error(UX_TEST_ERROR_CALLBACK_ERROR error)1415 static UX_TEST_ACTION create_error_match_action_from_error(UX_TEST_ERROR_CALLBACK_ERROR error)
1416 {
1417 
1418 UX_TEST_ACTION action = create_error_match_action(error.system_level, error.system_context, error.error_code);
1419 
1420 
1421     return action;
1422 }
1423 
create_memory_allocation_fail_error_match_action()1424 static UX_TEST_ACTION create_memory_allocation_fail_error_match_action()
1425 {
1426 
1427 UX_TEST_ACTION action = create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_UTILITY, UX_MEMORY_INSUFFICIENT);
1428 
1429 
1430     return action;
1431 }
1432 
1433 /* Note: do_after and do_before refer to when the action func is called relative to the HCD function. */
1434 /* This is to be used as an action func. It simply sets the completion code of a transfer to UX_ERROR */
async_transfer_completion_code_error_action_func_do_after(UX_TEST_ACTION * action,VOID * _params)1435 static void async_transfer_completion_code_error_action_func_do_after(UX_TEST_ACTION *action, VOID *_params)
1436 {
1437 
1438 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
1439 UINT                                status;
1440 UX_TRANSFER                         *transfer = params->parameter;
1441 
1442 
1443     status = ux_utility_semaphore_get(&transfer->ux_transfer_request_semaphore, TX_WAIT_FOREVER);
1444     if (status != UX_SUCCESS)
1445     {
1446 
1447         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
1448         test_control_return(1);
1449     }
1450 
1451     transfer->ux_transfer_request_completion_code = UX_ERROR;
1452 
1453     status = ux_utility_semaphore_put(&transfer->ux_transfer_request_semaphore);
1454     if (status != UX_SUCCESS)
1455     {
1456 
1457         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
1458         test_control_return(1);
1459     }
1460 }
1461 
1462 /* This changes the transfer completion code before the HCD is called. */
async_transfer_completion_code_success_action_func_do_before(UX_TEST_ACTION * action,VOID * _params)1463 static void async_transfer_completion_code_success_action_func_do_before(UX_TEST_ACTION *action, VOID *_params)
1464 {
1465 
1466 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
1467 UINT                                status;
1468 UX_TRANSFER                         *transfer_request = params->parameter;
1469 
1470 
1471     transfer_request->ux_transfer_request_completion_code = UX_SUCCESS;
1472 
1473     /* Since we're not calling the HCD, we don't wait for the transfer to complete via a sempahore_get(). However,
1474        the caller is still going to wait on the semaphore, so make sure we put() it. */
1475     status = ux_utility_semaphore_put(&transfer_request -> ux_transfer_request_semaphore);
1476     if (status != UX_SUCCESS)
1477     {
1478 
1479         printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status);
1480         test_control_return(1);
1481     }
1482 }
1483 
create_semaphore_get_match_action(TX_THREAD * thread,TX_SEMAPHORE * semaphore,ULONG semaphore_signal)1484 static UX_TEST_ACTION create_semaphore_get_match_action(TX_THREAD *thread, TX_SEMAPHORE *semaphore, ULONG semaphore_signal)
1485 {
1486 
1487 UX_TEST_ACTION action = { 0 };
1488 
1489 
1490     action.usbx_function = UX_TEST_OVERRIDE_TX_SEMAPHORE_GET;
1491     action.semaphore_ptr = semaphore;
1492     action.wait_option = semaphore_signal;
1493     action.thread_to_match = thread;
1494     action.no_return = 1;
1495 
1496     return action;
1497 }
1498 
create_semaphore_get_disconnect_action(TX_THREAD * thread,TX_SEMAPHORE * semaphore,ULONG semaphore_signal)1499 static UX_TEST_ACTION create_semaphore_get_disconnect_action(TX_THREAD *thread, TX_SEMAPHORE *semaphore, ULONG semaphore_signal)
1500 {
1501 
1502 UX_TEST_ACTION action = { 0 };
1503 
1504 
1505     action.usbx_function = UX_TEST_OVERRIDE_TX_SEMAPHORE_GET;
1506     action.semaphore_ptr = semaphore;
1507     action.wait_option = semaphore_signal;
1508     action.thread_to_match = thread;
1509     action.action_func = disconnect_host_and_slave_action_func;
1510     action.no_return = 1;
1511 
1512     return action;
1513 }
1514 
create_test_unit_ready_match_action(TX_THREAD * thread_to_match)1515 static UX_TEST_ACTION create_test_unit_ready_match_action(TX_THREAD *thread_to_match)
1516 {
1517 
1518 UX_TEST_ACTION action = { 0 };
1519 
1520 
1521     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1522     action.function = UX_HCD_TRANSFER_REQUEST;
1523     action.req_data = global_cbw_data_unit_ready_test_sbc;
1524     action.req_actual_len = sizeof(global_cbw_data_unit_ready_test_sbc);
1525     action.no_return = 1;
1526     action.thread_to_match = thread_to_match;
1527 
1528     return action;
1529 }
1530 
create_semaphore_get_fail_with_check_override_action(TX_THREAD * thread,TX_SEMAPHORE * semaphore,ULONG semaphore_signal,UCHAR (* check)())1531 static UX_TEST_ACTION create_semaphore_get_fail_with_check_override_action(TX_THREAD *thread, TX_SEMAPHORE *semaphore, ULONG semaphore_signal, UCHAR (*check)())
1532 {
1533 
1534 UX_TEST_ACTION action = { 0 };
1535 
1536 
1537     action.usbx_function = UX_TEST_OVERRIDE_TX_SEMAPHORE_GET;
1538     action.semaphore_ptr = semaphore;
1539     action.wait_option = semaphore_signal;
1540     action.thread_to_match = thread;
1541     action.check_func = check;
1542     action.no_return = 1;
1543 
1544     return action;
1545 }
1546 
async_transport_stall_test_action_func(UX_TEST_ACTION * action,VOID * _params)1547 static void async_transport_stall_test_action_func(UX_TEST_ACTION *action, VOID *_params)
1548 {
1549 
1550 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
1551 UINT                                status;
1552 UX_TRANSFER                         *transfer_request = params->parameter;
1553 
1554 
1555     transfer_request->ux_transfer_request_completion_code = UX_TRANSFER_STALLED;
1556 
1557     /* Caller is waiting for transfer completion. */
1558     status = ux_utility_semaphore_put(&transfer_request->ux_transfer_request_semaphore);
1559     if (status != UX_SUCCESS)
1560     {
1561 
1562         printf("Error on line %d\n", __LINE__);
1563         test_control_return(1);
1564     }
1565 }
1566 
create_request_sense_error_action_func(UX_TEST_ACTION * action,VOID * _params)1567 static void create_request_sense_error_action_func(UX_TEST_ACTION *action, VOID *_params)
1568 {
1569 
1570 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
1571 UINT                                status;
1572 UX_TRANSFER                         *transfer_request = params->parameter;
1573 
1574 
1575     /* Wait for transfer to complete. */
1576     status = ux_utility_semaphore_get(&transfer_request->ux_transfer_request_semaphore, TX_WAIT_FOREVER);
1577     if (status != UX_SUCCESS)
1578     {
1579 
1580         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
1581         test_control_return(1);
1582     }
1583 
1584     transfer_request->ux_transfer_request_data_pointer[UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_SENSE_KEY] = (UCHAR)action->user_data;
1585     transfer_request->ux_transfer_request_completion_code = UX_SUCCESS;
1586 
1587     /* Signal caller that transfer is complete. */
1588     status = ux_utility_semaphore_put(&transfer_request->ux_transfer_request_semaphore);
1589     if (status != UX_SUCCESS)
1590     {
1591 
1592         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
1593         test_control_return(1);
1594     }
1595 }
1596 
create_request_sense_error_action(TX_THREAD * thread_to_match,UINT request_sense_code)1597 static UX_TEST_ACTION create_request_sense_error_action(TX_THREAD *thread_to_match, UINT request_sense_code)
1598 {
1599 
1600 UX_TEST_ACTION action = { 0 };
1601 
1602 
1603     /* For making Request Sense contain error. */
1604     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1605     action.function = UX_HCD_TRANSFER_REQUEST;
1606     action.req_action = UX_TEST_MATCH_REQ_LEN;
1607     action.req_requested_len = UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RESPONSE_LENGTH;
1608     action.action_func = create_request_sense_error_action_func;
1609     action.do_after = 1;
1610     action.no_return = 1;
1611     action.thread_to_match = thread_to_match;
1612     action.user_data = request_sense_code;
1613 
1614     return action;
1615 }
1616 
1617 /* Action function for making the CSW contain an error. */
csw_error_action_func(UX_TEST_ACTION * action,VOID * _params)1618 static void csw_error_action_func(UX_TEST_ACTION *action, VOID *_params)
1619 {
1620 
1621 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
1622 UINT                                status;
1623 UX_TRANSFER                         *transfer_request = params->parameter;
1624 
1625 
1626     /* Wait for transfer to complete. */
1627     status = ux_utility_semaphore_get(&transfer_request->ux_transfer_request_semaphore, TX_WAIT_FOREVER);
1628     if (status != UX_SUCCESS)
1629     {
1630 
1631         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
1632         test_control_return(1);
1633     }
1634 
1635     transfer_request->ux_transfer_request_data_pointer[UX_HOST_CLASS_STORAGE_CSW_STATUS] = (UCHAR)action->user_data;
1636     transfer_request->ux_transfer_request_completion_code = UX_SUCCESS;
1637 
1638     /* Signal caller that transfer is complete. */
1639     status = ux_utility_semaphore_put(&transfer_request->ux_transfer_request_semaphore);
1640     if (status != UX_SUCCESS)
1641     {
1642 
1643         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
1644         test_control_return(1);
1645     }
1646 }
1647 
1648 /* Action function for skipping transfer. */
skip_transfer_action_func(UX_TEST_ACTION * action,VOID * _params)1649 static void skip_transfer_action_func(UX_TEST_ACTION *action, VOID *_params)
1650 {
1651 
1652 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
1653 UINT                                status;
1654 UX_TRANSFER                         *transfer_request = params->parameter;
1655 
1656 
1657     /* Caller is gonna wait! */
1658     status = ux_utility_semaphore_put(&transfer_request->ux_transfer_request_semaphore);
1659     if (status != UX_SUCCESS)
1660     {
1661 
1662         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
1663         test_control_return(1);
1664     }
1665 
1666     transfer_request->ux_transfer_request_completion_code = UX_SUCCESS;
1667 }
1668 
create_endpoint_reset_match_action(TX_THREAD * thread_to_match,UX_TEST_SETUP * setup)1669 static UX_TEST_ACTION create_endpoint_reset_match_action(TX_THREAD *thread_to_match, UX_TEST_SETUP *setup)
1670 {
1671 
1672 UX_TEST_ACTION action = { 0 };
1673 
1674 
1675     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1676     action.function = UX_HCD_TRANSFER_REQUEST;
1677     action.req_action = UX_TEST_SETUP_MATCH_REQ_V_I;
1678     action.no_return = 0; /* Host side tests, the actual request is not sent.  */
1679                           /* TODO: modify testing to make changes in device side.  */
1680     action.req_setup = setup;
1681     action.thread_to_match = thread_to_match;
1682 
1683     return action;
1684 }
1685 
1686 /* Sets the CSW status to the value specific ('error'). Note: the reason we add the thread to match is because of the
1687    pesky little background storage thread. */
create_csw_error_action(TX_THREAD * thread_to_match,UINT error)1688 static UX_TEST_ACTION create_csw_error_action(TX_THREAD *thread_to_match, UINT error)
1689 {
1690 
1691 UX_TEST_ACTION action = { 0 };
1692 
1693 
1694     /* For making CSW contain error. */
1695     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1696     action.function = UX_HCD_TRANSFER_REQUEST;
1697     action.req_action = UX_TEST_MATCH_REQ_LEN;
1698     action.req_requested_len = UX_HOST_CLASS_STORAGE_CSW_LENGTH;
1699     action.action_func = csw_error_action_func;
1700     action.do_after = 1;
1701     action.no_return = 1;
1702     action.thread_to_match = thread_to_match;
1703     action.user_data = error;
1704 
1705     return action;
1706 }
1707 
create_data_match_action(TX_THREAD * thread_to_match,UCHAR * data,ULONG data_length)1708 static UX_TEST_ACTION create_data_match_action(TX_THREAD *thread_to_match, UCHAR *data, ULONG data_length)
1709 {
1710 
1711 UX_TEST_ACTION action = { 0 };
1712 
1713 
1714     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1715     action.function = UX_HCD_TRANSFER_REQUEST;
1716     action.req_data = data;
1717     action.req_actual_len = data_length;
1718     action.thread_to_match = thread_to_match;
1719     action.no_return = 1;
1720 
1721     return action;
1722 }
1723 
create_csw_match_action(TX_THREAD * thread_to_match)1724 static UX_TEST_ACTION create_csw_match_action(TX_THREAD *thread_to_match)
1725 {
1726 
1727 UX_TEST_ACTION action = { 0 };
1728 
1729 
1730     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1731     action.function = UX_HCD_TRANSFER_REQUEST;
1732     action.req_action = UX_TEST_MATCH_REQ_LEN;
1733     action.req_requested_len = UX_HOST_CLASS_STORAGE_CSW_LENGTH;
1734     action.thread_to_match = thread_to_match;
1735     action.no_return = 1;
1736 
1737     return action;
1738 }
1739 
create_csw_skip_hcd_no_put_action(TX_THREAD * thread_to_match)1740 static UX_TEST_ACTION create_csw_skip_hcd_no_put_action(TX_THREAD *thread_to_match)
1741 {
1742 
1743 UX_TEST_ACTION action = { 0 };
1744 
1745 
1746     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1747     action.function = UX_HCD_TRANSFER_REQUEST;
1748     action.req_action = UX_TEST_MATCH_REQ_LEN;
1749     action.req_requested_len = UX_HOST_CLASS_STORAGE_CSW_LENGTH;
1750     action.thread_to_match = thread_to_match;
1751     action.no_return = 0;
1752     action.status = UX_SUCCESS;
1753 
1754     return action;
1755 }
1756 
create_csw_skip_hcd_action(TX_THREAD * thread_to_match)1757 static UX_TEST_ACTION create_csw_skip_hcd_action(TX_THREAD *thread_to_match)
1758 {
1759 
1760 UX_TEST_ACTION action = { 0 };
1761 
1762 
1763     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1764     action.function = UX_HCD_TRANSFER_REQUEST;
1765     action.req_action = UX_TEST_MATCH_REQ_LEN;
1766     action.req_requested_len = UX_HOST_CLASS_STORAGE_CSW_LENGTH;
1767     action.thread_to_match = thread_to_match;
1768     action.action_func = skip_transfer_action_func;
1769     action.no_return = 0;
1770     action.status = UX_SUCCESS;
1771 
1772     return action;
1773 }
1774 
create_transfer_requested_length_match_action(TX_THREAD * thread_to_match,ULONG length_to_match)1775 static UX_TEST_ACTION create_transfer_requested_length_match_action(TX_THREAD *thread_to_match, ULONG length_to_match)
1776 {
1777 
1778 UX_TEST_ACTION action = { 0 };
1779 
1780 
1781     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1782     action.function = UX_HCD_TRANSFER_REQUEST;
1783     action.req_action = UX_TEST_MATCH_REQ_LEN;
1784     action.req_requested_len = length_to_match;
1785     action.thread_to_match = thread_to_match;
1786     action.no_return = 1;
1787 
1788     return action;
1789 }
1790 
create_data_phase_sector_size_match_action(TX_THREAD * thread_to_match)1791 static UX_TEST_ACTION create_data_phase_sector_size_match_action(TX_THREAD *thread_to_match)
1792 {
1793 
1794 UX_TEST_ACTION action = { 0 };
1795 
1796 
1797     action = create_transfer_requested_length_match_action(thread_to_match, UX_TEST_DEFAULT_SECTOR_SIZE);
1798 
1799     return action;
1800 }
1801 
create_data_phase_sector_size_stall_action(TX_THREAD * thread_to_match)1802 static UX_TEST_ACTION create_data_phase_sector_size_stall_action(TX_THREAD *thread_to_match)
1803 {
1804 
1805 UX_TEST_ACTION action = { 0 };
1806 
1807 
1808     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1809     action = create_data_phase_sector_size_match_action(thread_to_match);
1810     action.action_func = async_transport_stall_test_action_func;
1811     action.do_after = 0;
1812     action.no_return = 0;
1813     action.status = UX_SUCCESS;
1814     action.thread_to_match = thread_to_match;
1815 
1816     return action;
1817 }
1818 
create_disconnect_on_sector_size_transfer_action(TX_THREAD * thread_to_match)1819 static UX_TEST_ACTION create_disconnect_on_sector_size_transfer_action(TX_THREAD *thread_to_match)
1820 {
1821 
1822 UX_TEST_ACTION action = { 0 };
1823 
1824 
1825     action = create_data_phase_sector_size_match_action(thread_to_match);
1826     action.action_func = disconnect_host_and_slave_action_func;
1827 
1828     return action;
1829 }
1830 
create_cbw_match_action(TX_THREAD * thread_to_match)1831 static UX_TEST_ACTION create_cbw_match_action(TX_THREAD *thread_to_match)
1832 {
1833 
1834 UX_TEST_ACTION action = { 0 };
1835 
1836 
1837     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1838     action.function = UX_HCD_TRANSFER_REQUEST;
1839     action.req_action = UX_TEST_MATCH_REQ_LEN;
1840     action.req_requested_len = UX_HOST_CLASS_STORAGE_CBW_LENGTH;
1841     action.thread_to_match = thread_to_match;
1842     action.no_return = 1;
1843 
1844     return action;
1845 }
1846 
create_timeout_on_cbw_action(TX_THREAD * thread_to_match)1847 static UX_TEST_ACTION create_timeout_on_cbw_action(TX_THREAD *thread_to_match)
1848 {
1849 
1850 UX_TEST_ACTION action = { 0 };
1851 
1852 
1853     /* We do this by just not sending the request to the device. */
1854 
1855     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1856     action.function = UX_HCD_TRANSFER_REQUEST;
1857     action.req_action = UX_TEST_MATCH_REQ_LEN;
1858     action.req_requested_len = UX_HOST_CLASS_STORAGE_CBW_LENGTH;
1859     action.thread_to_match = thread_to_match;
1860     action.no_return = 0;
1861 
1862     return action;
1863 }
1864 
create_timeout_on_transfer_action(TX_THREAD * thread_to_match)1865 static UX_TEST_ACTION create_timeout_on_transfer_action(TX_THREAD *thread_to_match)
1866 {
1867 
1868 UX_TEST_ACTION action = { 0 };
1869 
1870 
1871     /* We do this by just not sending the request to the device. */
1872 
1873     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1874     action.function = UX_HCD_TRANSFER_REQUEST;
1875     action.thread_to_match = thread_to_match;
1876     action.no_return = 0;
1877 
1878     return action;
1879 }
1880 
create_cbw_opcode_match_action(TX_THREAD * thread_to_match,UCHAR opcode)1881 static UX_TEST_ACTION create_cbw_opcode_match_action(TX_THREAD *thread_to_match, UCHAR opcode)
1882 {
1883 
1884 UX_TEST_ACTION action = { 0 };
1885 
1886 
1887     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1888     action.function = UX_HCD_TRANSFER_REQUEST;
1889     action.req_action = 0;
1890     /* Opcode is right after CBW. */
1891     action.req_actual_len = UX_HOST_CLASS_STORAGE_CBW_CB + 1;
1892     action.thread_to_match = thread_to_match;
1893     action.no_return = 1;
1894 
1895     action.req_data_match_mask = global_cbw_opcode_match_mask;
1896 
1897     switch (opcode)
1898     {
1899         case UX_HOST_CLASS_STORAGE_SCSI_READ16:
1900             action.req_data = global_cbw_opcode_read;
1901             break;
1902 
1903         default:
1904             UX_TEST_ASSERT(0);
1905     }
1906 
1907     return action;
1908 }
1909 
create_disconnect_on_requested_length_action(TX_THREAD * thread_to_match,UINT requested_length)1910 static  UX_TEST_ACTION create_disconnect_on_requested_length_action(TX_THREAD *thread_to_match, UINT requested_length)
1911 {
1912 
1913 UX_TEST_ACTION action = { 0 };
1914 
1915 
1916     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1917     action.function = UX_HCD_TRANSFER_REQUEST;
1918     action.req_action = UX_TEST_MATCH_REQ_LEN;
1919     action.req_requested_len = requested_length;
1920     action.action_func = disconnect_host_and_slave_action_func;
1921     action.thread_to_match = thread_to_match;
1922     action.no_return = 1;
1923 
1924     return action;
1925 }
1926 
create_config_reset_on_requested_length_action(TX_THREAD * thread_to_match,UINT requested_length)1927 static  UX_TEST_ACTION create_config_reset_on_requested_length_action(TX_THREAD *thread_to_match, UINT requested_length)
1928 {
1929 
1930 UX_TEST_ACTION action = { 0 };
1931 
1932 
1933     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1934     action.function = UX_HCD_TRANSFER_REQUEST;
1935     action.req_action = UX_TEST_MATCH_REQ_LEN;
1936     action.req_requested_len = requested_length;
1937     action.action_func = configuration_reset_action_func;
1938     action.thread_to_match = thread_to_match;
1939     action.no_return = 1;
1940 
1941     return action;
1942 }
1943 
create_cbw_disconnect_action(TX_THREAD * thread_to_match)1944 static UX_TEST_ACTION create_cbw_disconnect_action(TX_THREAD *thread_to_match)
1945 {
1946 
1947 UX_TEST_ACTION action = create_disconnect_on_requested_length_action(thread_to_match, UX_HOST_CLASS_STORAGE_CBW_LENGTH);
1948 
1949 
1950     return action;
1951 }
1952 
create_cbw_config_reset_action(TX_THREAD * thread_to_match)1953 static UX_TEST_ACTION create_cbw_config_reset_action(TX_THREAD *thread_to_match)
1954 {
1955 
1956 UX_TEST_ACTION action = create_config_reset_on_requested_length_action(thread_to_match, UX_HOST_CLASS_STORAGE_CBW_LENGTH);
1957 
1958 
1959     return action;
1960 }
1961 
create_csw_disconnect_action(TX_THREAD * thread_to_match)1962 static UX_TEST_ACTION create_csw_disconnect_action(TX_THREAD *thread_to_match)
1963 {
1964 
1965 UX_TEST_ACTION action = create_disconnect_on_requested_length_action(thread_to_match, UX_HOST_CLASS_STORAGE_CSW_LENGTH);
1966 
1967 
1968     return action;
1969 }
1970 
1971 /* This will match a CSW and call the supplied action function. */
create_csw_match_action_with_func(VOID (* entry_func_action)(UX_TEST_ACTION * action,VOID * params),TX_THREAD * thread_to_match)1972 static UX_TEST_ACTION create_csw_match_action_with_func(VOID (*entry_func_action)(UX_TEST_ACTION *action, VOID *params), TX_THREAD *thread_to_match)
1973 {
1974 
1975 UX_TEST_ACTION action = { 0 };
1976 
1977 
1978     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
1979     action.function = UX_HCD_TRANSFER_REQUEST;
1980     action.req_action = UX_TEST_MATCH_REQ_LEN;
1981     action.req_requested_len = UX_HOST_CLASS_STORAGE_CSW_LENGTH;
1982     action.action_func = entry_func_action;
1983     action.do_after = 1;
1984     action.thread_to_match = thread_to_match;
1985 
1986     return action;
1987 }
1988 
1989 /* Note: This should be a last resort.
1990 
1991    This will match a CSW and force the transfer completion to stall. Note that this returns before the HCD is called
1992    This because if the transfer makes it to the device, the device will send the CSW, host will see the stall, ask for
1993    another, but won't get it. */
create_csw_stall_action(TX_THREAD * thread_to_match)1994 static UX_TEST_ACTION create_csw_stall_action(TX_THREAD *thread_to_match)
1995 {
1996 
1997 UX_TEST_ACTION action = { 0 };
1998 
1999 
2000     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
2001     action.function = UX_HCD_TRANSFER_REQUEST;
2002     action.req_action = UX_TEST_MATCH_REQ_LEN;
2003     action.req_requested_len = UX_HOST_CLASS_STORAGE_CSW_LENGTH;
2004     action.action_func = async_transport_stall_test_action_func;
2005     action.do_after = 0;
2006     action.thread_to_match = thread_to_match;
2007 
2008     return action;
2009 }
2010 
create_cbw_stall_action(TX_THREAD * thread_to_match)2011 static UX_TEST_ACTION create_cbw_stall_action(TX_THREAD *thread_to_match)
2012 {
2013 
2014 UX_TEST_ACTION action = { 0 };
2015 
2016 
2017     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
2018     action.function = UX_HCD_TRANSFER_REQUEST;
2019     action.req_action = UX_TEST_MATCH_REQ_LEN;
2020     action.req_requested_len = UX_HOST_CLASS_STORAGE_CBW_LENGTH;
2021     action.action_func = async_transport_stall_test_action_func;
2022     action.do_after = 0;
2023     action.thread_to_match = thread_to_match;
2024 
2025     return action;
2026 }
2027 
create_device_media_status_fail_action()2028 static UX_TEST_ACTION create_device_media_status_fail_action()
2029 {
2030 
2031 UX_TEST_ACTION action = { 0 };
2032 
2033 
2034     action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS;
2035     action.ignore_params = 1;
2036     action.action_func = device_media_status_error_action_func;
2037     action.no_return = 0;
2038     action.status = UX_ERROR;
2039 
2040     return action;
2041 }
2042 
add_multiple_read_retries_fails_actions(UX_TEST_ACTION * user_list,TX_THREAD * thread_to_match)2043 static VOID add_multiple_read_retries_fails_actions(UX_TEST_ACTION *user_list, TX_THREAD *thread_to_match)
2044 {
2045 
2046 UINT    i;
2047 
2048 
2049     for (i = 0; i < UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RETRY; i++)
2050     {
2051         /* Remember, entire read has to succeed to storage -> ux_host_class_storage_data_phase_length is valid. */
2052 
2053         /* For safety, match the read CBW. */
2054         ux_test_add_action_to_user_list(user_list, create_cbw_opcode_match_action(thread_to_match, UX_HOST_CLASS_STORAGE_SCSI_READ16));
2055 
2056         /* We only send the request sense if the CSW contains an error.  */
2057         ux_test_add_action_to_user_list(user_list, create_csw_error_action(thread_to_match, UX_HOST_CLASS_STORAGE_CSW_FAILED));
2058 
2059         ux_test_add_action_to_user_list(user_list, create_request_sense_error_action(thread_to_match, UX_ERROR));
2060     }
2061 }
2062 
add_multiple_write_retries_fails_actions(UX_TEST_ACTION * user_list)2063 static VOID add_multiple_write_retries_fails_actions(UX_TEST_ACTION *user_list)
2064 {
2065 
2066 UINT    i;
2067 
2068 
2069     for (i = 0; i < UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RETRY; i++)
2070     {
2071         ux_test_add_action_to_user_list(user_list, create_device_media_write_fail_action());
2072         ux_test_add_action_to_user_list(user_list, create_error_match_action_from_error(global_transfer_stall_error));
2073     }
2074 }
2075 
add_multiple_status_retries_fails_actions(UX_TEST_ACTION * user_list)2076 static VOID add_multiple_status_retries_fails_actions(UX_TEST_ACTION *user_list)
2077 {
2078 
2079 UINT    i;
2080 
2081 
2082     for (i = 0; i < UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RETRY; i++)
2083     {
2084         ux_test_add_action_to_user_list(user_list, create_device_media_status_fail_action());
2085         ux_test_add_action_to_user_list(user_list, create_error_match_action_from_error(global_transfer_stall_error));
2086     }
2087 }
2088 
2089 /* Action creation functions END. */
2090 
2091 /* Action addition utilities. */
2092 
add_unit_ready_test_not_ready_actions(UX_TEST_ACTION * actions)2093 static void add_unit_ready_test_not_ready_actions(UX_TEST_ACTION *actions)
2094 {
2095 
2096     ux_test_add_action_to_user_list(actions, create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED));
2097     ux_test_add_action_to_user_list(actions, create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY));
2098 }
2099 
initialize_test_resources()2100 static void initialize_test_resources()
2101 {
2102 
2103 UINT status;
2104 
2105 #if defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
2106     /* Reset media IDs.  */
2107     for (int i = 0; i < UX_HOST_CLASS_STORAGE_MAX_MEDIA; i ++)
2108         _ux_host_class_storage_driver_media(i)->fx_media_id = 0;
2109 #endif
2110 
2111     status = ux_utility_semaphore_create(&global_test_semaphore, "test_semaphore", 0);
2112     if (status != UX_SUCCESS)
2113     {
2114 
2115         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2116         test_control_return(1);
2117     }
2118 
2119     ux_cbi_simulator_initialize();
2120     ux_test_worker_initialize();
2121 }
2122 
basic_read_write_test(FX_FILE * file)2123 static void basic_read_write_test(FX_FILE *file)
2124 {
2125 
2126 UINT    status;
2127 ULONG   total_length;
2128 UCHAR   buffer_pattern;
2129 ULONG   bytes_read;
2130 UINT    i;
2131 
2132 
2133     /* Set the file length.  */
2134     total_length = UX_DEMO_FILE_SIZE;
2135 
2136     /* Set pattern first letter.  */
2137     buffer_pattern = 'a';
2138 
2139     /* Seek to the beginning to copy over an existing file.  */
2140     status = fx_file_seek(file, 0);
2141     if (status != UX_SUCCESS)
2142     {
2143 
2144         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2145         test_control_return(1);
2146     }
2147 
2148     while (total_length !=0)
2149     {
2150 
2151         /* Set the buffer with pattern.  */
2152         ux_utility_memory_set(global_buffer, buffer_pattern, UX_DEMO_FILE_BUFFER_SIZE);
2153 
2154         /* Copy the file in blocks */
2155         status = fx_file_write(file, global_buffer, UX_DEMO_FILE_BUFFER_SIZE);
2156 
2157         /* Check if status OK.  */
2158         if (status != UX_SUCCESS)
2159         {
2160 
2161             printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2162             test_control_return(1);
2163         }
2164 
2165         /* Decrement the length remaining. */
2166         total_length -= UX_DEMO_FILE_BUFFER_SIZE;
2167 
2168         /* Next pattern.  */
2169         buffer_pattern++;
2170 
2171         /* Check pattern end.  */
2172         if (buffer_pattern > 'z')
2173 
2174             /* Back to beginning.  */
2175             buffer_pattern = 'a';
2176     }
2177 
2178     /* Seek to the beginning to read.  */
2179     status = fx_file_seek(file, 0);
2180     if (status != UX_SUCCESS)
2181     {
2182 
2183         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2184         test_control_return(1);
2185     }
2186 
2187     /* Set the file length.  */
2188     total_length = UX_DEMO_FILE_SIZE;
2189 
2190     /* Set pattern first letter.  */
2191     buffer_pattern = 'a';
2192 
2193     while(total_length !=0)
2194     {
2195 
2196         /* Read the file in blocks */
2197         status = fx_file_read(file, global_buffer, UX_DEMO_FILE_BUFFER_SIZE, &bytes_read);
2198 
2199         /* Check if status OK.  */
2200         if (status != UX_SUCCESS)
2201         {
2202 
2203             printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2204             test_control_return(1);
2205         }
2206 
2207         if (bytes_read != UX_DEMO_FILE_BUFFER_SIZE)
2208         {
2209 
2210             printf("Error on line %d\n", __LINE__);
2211             test_control_return(1);
2212         }
2213 
2214         /* Do compare. */
2215         for (i = 0; i < UX_DEMO_FILE_BUFFER_SIZE; i++)
2216         {
2217 
2218             if (global_buffer[i] != buffer_pattern)
2219             {
2220 
2221                 printf("Error on line %d\n", __LINE__);
2222                 test_control_return(1);
2223             }
2224         }
2225 
2226         /* Decrement the length remaining. */
2227         total_length -= UX_DEMO_FILE_BUFFER_SIZE;
2228 
2229         /* Next pattern.  */
2230         buffer_pattern++;
2231 
2232         /* Check pattern end.  */
2233         if (buffer_pattern > 'z')
2234 
2235             /* Back to beginning.  */
2236             buffer_pattern = 'a';
2237     }
2238 }
2239 
2240 /* Performs basic test including deletion, creation, open, writing, and reading.  */
basic_test_pre_existing_file(UINT iterations,char * message,FX_FILE * file)2241 static void basic_test_pre_existing_file(UINT iterations, char *message, FX_FILE *file)
2242 {
2243 
2244     if (message != UX_NULL)
2245     {
2246         stepinfo("%s", message);
2247     }
2248 
2249     while (iterations--)
2250         basic_read_write_test(file);
2251 }
2252 
2253 /* Performs basic test including deletion, creation, open, writing, and reading.  */
basic_test(FX_MEDIA * media,UINT iterations,char * message)2254 static void basic_test(FX_MEDIA *media, UINT iterations, char *message)
2255 {
2256 
2257 UINT                    status;
2258 FX_FILE                 file;
2259 
2260 
2261     if (message != UX_NULL)
2262     {
2263         stepinfo("%s", message);
2264     }
2265 
2266     while (iterations--)
2267     {
2268 
2269         /* Try to delete the non-existent target file.  */
2270         status =  fx_file_delete(media, "FILE.CPY");
2271         if (status != FX_NOT_FOUND)
2272         {
2273 
2274             printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2275             test_control_return(1);
2276         }
2277 
2278         /* Create and open file. */
2279         ux_test_storage_file_co(media, &file, UX_TRUE);
2280 
2281         basic_read_write_test(&file);
2282 
2283         /* Close and delete file. */
2284         ux_test_storage_file_cd(media, &file);
2285     }
2286 }
2287 
2288 /* This is for use in the tests array. */
basic_test_with_globals()2289 static void basic_test_with_globals()
2290 {
2291 
2292     stepinfo("basic_test_with_globals\n");
2293     basic_test(global_media, 1, UX_NULL);
2294 }
2295 
ux_test_device_class_storage_entry(UX_SLAVE_CLASS_COMMAND * command)2296 UINT ux_test_device_class_storage_entry(UX_SLAVE_CLASS_COMMAND *command)
2297 {
2298 
2299 UINT            status;
2300 ULONG           old_time_slice;
2301 UX_SLAVE_CLASS  *storage_class;
2302 TX_THREAD       *storage_thread;
2303 
2304 
2305     status = _ux_device_class_storage_entry(command);
2306 
2307     if (command -> ux_slave_class_command_request == UX_SLAVE_CLASS_COMMAND_INITIALIZE)
2308     {
2309 
2310         storage_class = command->ux_slave_class_command_class_ptr;
2311 
2312         /* Currently, the slave storage thread has no time slice. This is a problem
2313            in the following case:
2314             1) Device write to storage device fails
2315             2) Device stalls bulk OUT endpoint
2316             3) Device sends CSW, waits for transaction scheduler
2317             4) Host tries to receive CSW, waits for transaction scheduler
2318             5) Transaction scheduler completes transfer, resumes device
2319             6) Device storage thread loops forever (with no sleep) waiting for host
2320                to clear OUT endpoint, but host thread can't run because slave
2321                storage thread runs forever.
2322 
2323             This is valid behavior on the device's part since, obviously,
2324             the host isn't running on the same processor.
2325 
2326             The fix is to give the device storage thread a very large time slice;
2327             if it ever reaches the end of the time slice, it means it's waiting
2328             for the host to clear the stall. */
2329         storage_thread = &storage_class->ux_slave_class_thread;
2330         status = tx_thread_time_slice_change(storage_thread, 100, &old_time_slice);
2331         if (status != TX_SUCCESS)
2332         {
2333 
2334             printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2335             test_control_return(1);
2336         }
2337     }
2338 
2339     return(status);
2340 }
2341 
2342 /* Define what the initial system looks like.  */
2343 
2344 #ifdef CTEST
test_application_define(void * first_unused_memory)2345 void test_application_define(void *first_unused_memory)
2346 #else
2347 void usbx_storage_tests_application_define(void *first_unused_memory)
2348 #endif
2349 {
2350 
2351 UINT                            status;
2352 CHAR                            *stack_pointer;
2353 CHAR                            *memory_pointer;
2354 
2355 
2356     /* Inform user.  */
2357     printf("Running Storage Basic Functionality Test............................ ");
2358 #if !(UX_TEST_MULTI_IFC_ON) || !(UX_MAX_SLAVE_LUN > 1)
2359     printf("SKIP!");
2360     test_control_return(0);
2361     return;
2362 #endif
2363 
2364     stepinfo("\n");
2365 
2366     /* Initialize testing-related resources. */
2367     initialize_test_resources();
2368 
2369     /* Initialize FileX.  */
2370     fx_system_initialize();
2371 
2372     /* Initialize the free memory pointer */
2373     stack_pointer = (CHAR *) usbx_memory;
2374     memory_pointer = stack_pointer + (UX_DEMO_STACK_SIZE * 2);
2375 
2376     /* Initialize USBX. Memory */
2377     ux_system_initialize(memory_pointer, UX_DEMO_MEMORY_SIZE, UX_NULL,0);
2378 
2379     /* Reset ram disk memory.  */
2380     ux_utility_memory_set(global_ram_disk_memory, 0, UX_RAM_DISK_SIZE);
2381 
2382     /* The code below is required for installing the device portion of USBX.
2383        In this demo, DFU is possible and we have a call back for state change. */
2384     status = ux_device_stack_initialize(device_framework_high_speed, DEVICE_FRAMEWORK_LENGTH_HIGH_SPEED,
2385                                         device_framework_full_speed, DEVICE_FRAMEWORK_LENGTH_FULL_SPEED,
2386                                         string_framework, STRING_FRAMEWORK_LENGTH,
2387                                         language_id_framework, LANGUAGE_ID_FRAMEWORK_LENGTH, UX_NULL);
2388     if (status != UX_SUCCESS)
2389     {
2390 
2391         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2392         test_control_return(1);
2393     }
2394 
2395     /* Store the number of LUN in this device storage instance.  */
2396     global_storage_parameter.ux_slave_class_storage_parameter_number_lun = 1;
2397 
2398     /* Set the instance activate and deactivate callbacks. */
2399     global_storage_parameter.ux_slave_class_storage_instance_activate = ux_slave_class_storage_instance_activate;
2400     global_storage_parameter.ux_slave_class_storage_instance_deactivate = ux_slave_class_storage_instance_deactivate;
2401 
2402     /* Initialize the storage class parameters for reading/writing to the Flash Disk.  */
2403     global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba        =  UX_RAM_DISK_LAST_LBA;
2404     global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length    =  global_sector_size;
2405     /* Note: The multiple_and_different_lun_types_test tests the other two types (OPTICAL DISK and IOMEGA CLICK). */
2406     global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type            =  UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK;
2407     global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag  =  0x80;
2408     global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read            =  default_device_media_read;
2409     global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write           =  default_device_media_write;
2410 #ifdef BUGFIX /* USBX_200 */
2411     global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_flush           =  default_device_media_flush;
2412 #endif
2413     global_storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status          =  default_device_media_status;
2414 
2415     /* Initilize the device storage class. The class is connected with interface 0 on configuration 1. */
2416     status =  ux_device_stack_class_register(_ux_system_slave_class_storage_name, ux_test_device_class_storage_entry,
2417                                                 1, 0, (VOID *)&global_storage_parameter);
2418     if (status != UX_SUCCESS)
2419     {
2420 
2421         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2422         test_control_return(1);
2423     }
2424 
2425     /* Initialize the simulated device controller.  */
2426     status =  _ux_test_dcd_sim_slave_initialize();
2427 
2428     /* Check for error.  */
2429     if (status != UX_SUCCESS)
2430     {
2431 
2432         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2433         test_control_return(1);
2434     }
2435 
2436     global_dcd = &_ux_system_slave->ux_system_slave_dcd;
2437     global_slave_class_container = &_ux_system_slave->ux_system_slave_class_array[0];
2438     global_slave_device = &_ux_system_slave->ux_system_slave_device;
2439     global_slave_storage_thread = &global_slave_class_container->ux_slave_class_thread;
2440 
2441     /* The code below is required for installing the host portion of USBX */
2442     status =  ux_host_stack_initialize(ux_test_system_host_change_function);
2443 
2444     /* Check for error.  */
2445     if (status != UX_SUCCESS)
2446     {
2447 
2448         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2449         test_control_return(1);
2450     }
2451 
2452     global_host_device = &_ux_system_host->ux_system_host_device_array[0];
2453     global_enum_thread = &_ux_system_host->ux_system_host_enum_thread;
2454 
2455     /* Register the error callback. */
2456     ux_utility_error_callback_register(ux_test_error_callback);
2457 
2458     /* Register storage class.  */
2459     status =  ux_host_stack_class_register(_ux_system_host_class_storage_name, ux_host_class_storage_entry);
2460     if (status != UX_SUCCESS)
2461     {
2462 
2463         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2464         test_control_return(1);
2465     }
2466 
2467     /* Register all the USB host controllers available in this system */
2468     status =  ux_host_stack_hcd_register(_ux_system_host_hcd_simulator_name, _ux_test_hcd_sim_host_initialize,0,0);
2469 
2470     /* Check for error.  */
2471     if (status != UX_SUCCESS)
2472     {
2473 
2474         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2475         test_control_return(1);
2476     }
2477 
2478     global_hcd = &_ux_system_host->ux_system_host_hcd_array[0];
2479 
2480     /* Create the main host simulation thread.  */
2481     status =  tx_thread_create(&tx_demo_thread_host_simulation, "tx demo host simulation", ux_test_thread_host_simulation_entry, 0,
2482             stack_pointer, UX_DEMO_STACK_SIZE,
2483             20, 20, 1, TX_AUTO_START);
2484 
2485     /* Check for error.  */
2486     if (status != TX_SUCCESS)
2487     {
2488 
2489         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2490         test_control_return(1);
2491     }
2492 }
2493 
2494 /* CO: Create and Open */
ux_test_storage_file_co(FX_MEDIA * media,FX_FILE * file,UCHAR fail_on_error)2495 static UINT ux_test_storage_file_co(FX_MEDIA *media, FX_FILE *file, UCHAR fail_on_error)
2496 {
2497 
2498 UINT status;
2499 
2500 
2501     /* Create the file.  */
2502     status = fx_file_create(media, "FILE.CPY");
2503     if (fail_on_error == UX_TRUE && status != UX_SUCCESS)
2504     {
2505 
2506         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2507         test_control_return(1);
2508     }
2509 
2510     memset(file,0,sizeof(FX_FILE));
2511 
2512     /* Open file for copying.  */
2513     status = fx_file_open(media,file,"FILE.CPY",FX_OPEN_FOR_WRITE);
2514     if (fail_on_error == UX_TRUE && status != UX_SUCCESS)
2515     {
2516 
2517         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2518         test_control_return(1);
2519     }
2520 
2521     /* Seek to the beginning to copy over an existing file.  */
2522     status = fx_file_seek(file,0);
2523     if (fail_on_error == UX_TRUE && status != UX_SUCCESS)
2524     {
2525 
2526         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2527         test_control_return(1);
2528     }
2529 
2530     return status;
2531 }
2532 
2533 /* COW: Create, Open, and Write */
ux_test_storage_file_cow(FX_MEDIA * media,FX_FILE * file,UCHAR * data_pointer,ULONG data_length,UCHAR fail_on_error)2534 static UINT ux_test_storage_file_cow(FX_MEDIA *media, FX_FILE *file, UCHAR *data_pointer, ULONG data_length, UCHAR fail_on_error)
2535 {
2536 
2537 UINT status;
2538 
2539 
2540     status = ux_test_storage_file_co(media, file, fail_on_error);
2541     if (fail_on_error == UX_TRUE && status != UX_SUCCESS)
2542     {
2543 
2544         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2545         test_control_return(1);
2546     }
2547 
2548     status = fx_file_write(file, data_pointer, data_length);
2549     if (fail_on_error == UX_TRUE && status != UX_SUCCESS)
2550     {
2551 
2552         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2553         test_control_return(1);
2554     }
2555 
2556     /* Ensure it's actually written to. */
2557     UX_TEST_CHECK_SUCCESS(fx_media_flush(media));
2558 
2559     /* Most of the time, we want to do a read right after. */
2560     status = fx_file_seek(file, 0);
2561     if (fail_on_error == UX_TRUE && status != UX_SUCCESS)
2562     {
2563 
2564         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2565         test_control_return(1);
2566     }
2567 
2568     return status;
2569 }
2570 
ux_test_storage_file_cd(FX_MEDIA * media,FX_FILE * file)2571 static void ux_test_storage_file_cd(FX_MEDIA *media, FX_FILE *file)
2572 {
2573 
2574 UINT status;
2575 
2576 
2577     /* Close the file. */
2578     status = fx_file_close(file);
2579     if (status != UX_SUCCESS)
2580     {
2581 
2582         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2583         test_control_return(1);
2584     }
2585 
2586     /* Delete the target file.  */
2587     status = fx_file_delete(media, "FILE.CPY");
2588     if (status != UX_SUCCESS)
2589     {
2590 
2591         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2592         test_control_return(1);
2593     }
2594 }
2595 
ux_test_storage_file_cowcd(FX_MEDIA * media,FX_FILE * file,UCHAR * data_pointer,ULONG data_length)2596 static void ux_test_storage_file_cowcd(FX_MEDIA *media, FX_FILE *file, UCHAR *data_pointer, ULONG data_length)
2597 {
2598 
2599     ux_test_storage_file_cow(media, file, data_pointer, data_length, UX_TRUE);
2600     ux_test_storage_file_cd(media, file);
2601 }
2602 
2603 /* Device reset test resources. */
2604 
device_reset_test(UINT cb_length,UCHAR * message)2605 static void device_reset_test(UINT cb_length, UCHAR *message)
2606 {
2607 
2608 UCHAR                   transfer_request_data_unit_test_cbw[] = { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, cb_length, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
2609 UX_TEST_ACTION          actions[] = {
2610     create_cbw_match_action(tx_thread_identify()),
2611     create_csw_error_action(tx_thread_identify(), UX_HOST_CLASS_STORAGE_CSW_PHASE_ERROR),
2612     { 0 }
2613 };
2614 
2615 
2616     /* Test ux_host_class_storage_device_reset. */
2617     if (message)
2618     {
2619         stepinfo("%s", message);
2620     }
2621 
2622     /* Set our amazing action. */
2623     ux_test_set_main_action_list_from_array(actions);
2624 
2625     lock_out_storage_thread();
2626     UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, 1, global_buffer));
2627     lock_in_storage_thread();
2628 }
2629 
let_storage_thread_run()2630 static void let_storage_thread_run()
2631 {
2632 
2633     /* Get the semaphore so we can keep track of the storage thread. */
2634     lock_out_storage_thread();
2635 
2636     /* Wait for storage thread to wait on the semaphore. */
2637     while (global_storage->ux_host_class_storage_semaphore.tx_semaphore_suspended_count == 0)
2638         tx_thread_sleep(10);
2639 
2640     /* Now let storage thread run. */
2641     lock_in_storage_thread();
2642     tx_thread_sleep(100);
2643 
2644     /* TODO: match a 2 second sleep via test action engine (trademark)? */
2645 
2646     /* Wait for storage thread to complete a single cycle. We know it has when it does the 2 second sleep (hopefullly
2647        there aren't any other sleeps it does though...). */
2648     UINT global_storage_thread_state;
2649     do
2650     {
2651 
2652         tx_thread_sleep(10);
2653         UX_TEST_CHECK_SUCCESS(tx_thread_info_get(global_storage_thread, UX_NULL, &global_storage_thread_state, UX_NULL, UX_NULL, UX_NULL, UX_NULL, UX_NULL, UX_NULL));
2654     } while (global_storage_thread_state != TX_SLEEP);
2655 }
2656 
2657 /* Test unit ready test resourcs. */
2658 
turt_unit_attention_first_semaphore_get_fails_check_action_function()2659 UCHAR turt_unit_attention_first_semaphore_get_fails_check_action_function()
2660 {
2661 
2662     /* Have we closed the media yet? */
2663     return global_media->fx_media_id == 0 ? UX_TRUE : UX_FALSE;
2664 }
2665 
test_unit_ready_test()2666 static void test_unit_ready_test()
2667 {
2668 
2669 UINT                        i;
2670 UINT                        sense_code_values[] = { UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION };
2671 UX_HOST_CLASS_STORAGE_MEDIA *storage_media;
2672 UCHAR                       *stringies[] = { "UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY", "UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION" };
2673 UX_HOST_CLASS_STORAGE       *local_init_storage = global_storage;
2674 UX_TEST_ACTION              *action_item;
2675 
2676     UX_TEST_ACTION not_ready_actions[] = {
2677         create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED),
2678         create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY),
2679         { 0 }
2680     };
2681 
2682     UX_TEST_ACTION unit_attention_actions[] = {
2683         create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED),
2684         create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION),
2685         { 0 }
2686     };
2687 
2688     UX_TEST_ACTION not_ready_first_semaphore_get_disconnect_actions[] = {
2689         create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED),
2690         create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY),
2691         /* The first semaphore_get() will be from the fx_media_close to flush. */
2692         create_semaphore_get_match_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER),
2693         /* The second semaphore_get() will be from the fx_media_close to unittialize driver. */
2694         create_semaphore_get_match_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER),
2695         create_semaphore_get_disconnect_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER),
2696         { 0 }
2697     };
2698 
2699     UX_TEST_ACTION first_class_instance_semaphore_get_disconnect_actions[] = {
2700         create_semaphore_get_disconnect_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER),
2701         { 0 }
2702     };
2703 
2704     UX_TEST_ACTION unit_attention_unit_ready_test_disconnect_actions[] = {
2705         create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED),
2706         create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION),
2707         create_disconnect_on_transfer_data_match_action(global_storage_thread, global_cbw_data_unit_ready_test_sbc, sizeof(global_cbw_data_unit_ready_test_sbc)),
2708         { 0 }
2709     };
2710 
2711     UX_TEST_ACTION unit_attention_media_characteristics_get_disconnect_actions[] = {
2712         create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED),
2713         create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION),
2714         create_disconnect_on_media_characteristics_get_action(global_storage_thread),
2715         { 0 }
2716     };
2717 
2718     UX_TEST_ACTION unit_attention_unit_ready_test_request_sense_disconnect_actions[] = {
2719         create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED),
2720         create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION),
2721         create_disconnect_on_transfer_data_match_action(global_storage_thread, global_cbw_data_unit_ready_test_sbc, sizeof(global_cbw_data_unit_ready_test_sbc)),
2722         { 0 }
2723     };
2724 
2725     UX_TEST_ACTION unit_attention_format_capacity_get_fails_via_memory_alloc_failure_actions[] = {
2726         create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED),
2727         create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION),
2728         create_test_unit_ready_match_action(global_storage_thread),
2729         /* We do two format_capacity_get()s. Make the second one fail. */
2730         create_format_capacity_get_match_action(global_storage_thread),
2731         /* The only way format_capacity_get fails is via memory allocation failure. */
2732         create_allocate_all_memory_on_transfer_data_match_action(global_storage_thread, UX_CACHE_SAFE_MEMORY, global_cbw_data_media_capacity_get_sbc, sizeof(global_cbw_data_media_capacity_get_sbc)),
2733         create_memory_allocation_fail_error_match_action(global_storage_thread),
2734         { 0 }
2735     };
2736 
2737     UX_TEST_ACTION unit_attention_first_semaphore_get_disconnect_actions[] = {
2738         create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED),
2739         create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION),
2740         /* The first semaphore_get() will be from the fx_media_close to flush. */
2741         create_semaphore_get_match_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER),
2742         /* The second semaphore_get() will be from the fx_media_close to unittialize driver. */
2743         create_semaphore_get_match_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER),
2744         create_semaphore_get_disconnect_action(global_storage_thread, &global_storage->ux_host_class_storage_semaphore, UX_WAIT_FOREVER),
2745         { 0 }
2746     };
2747 
2748     UX_TEST_ACTION *all_actions[] = {
2749         unit_attention_format_capacity_get_fails_via_memory_alloc_failure_actions,
2750         unit_attention_first_semaphore_get_disconnect_actions,
2751         not_ready_first_semaphore_get_disconnect_actions,
2752         unit_attention_media_characteristics_get_disconnect_actions,
2753         first_class_instance_semaphore_get_disconnect_actions,
2754         not_ready_actions,
2755         unit_attention_actions,
2756         unit_attention_unit_ready_test_disconnect_actions,
2757         unit_attention_unit_ready_test_request_sense_disconnect_actions,
2758     };
2759 
2760 
2761     stepinfo("unit_ready_test_test\n");
2762 
2763     stepinfo("    single lun\n");
2764 
2765     for (i = 0; i < ARRAY_COUNT(all_actions); i++)
2766     {
2767 
2768         stepinfo("        doing %d\n", i);
2769 
2770         if (global_storage != local_init_storage)
2771         {
2772             action_item = all_actions[i];
2773             while(action_item->function != 0 || action_item->usbx_function != 0)
2774             {
2775                 if (action_item->semaphore_ptr == &local_init_storage->ux_host_class_storage_semaphore)
2776                 {
2777                     action_item->semaphore_ptr = &global_storage->ux_host_class_storage_semaphore;
2778                 }
2779                 action_item ++;
2780             }
2781         }
2782 
2783         ux_test_set_main_action_list_from_array(all_actions[i]);
2784 
2785         let_storage_thread_run();
2786 
2787         /* Ensure expected result and clean up. */
2788 
2789         if (all_actions[i] == not_ready_actions)
2790         {
2791 
2792             /* Make sure storage media is unmounted. */
2793             if (!!_storage_media_is_mounted())
2794             {
2795 
2796                 printf("Error on line %d\n", __LINE__);
2797                 test_control_return(1);
2798             }
2799         }
2800         else if (all_actions[i] == unit_attention_actions)
2801         {
2802 
2803             /* Make sure storage media is mounted. */
2804             if (!_storage_media_is_mounted())
2805             {
2806 
2807                 printf("Error on line %d\n", __LINE__);
2808                 test_control_return(1);
2809             }
2810 
2811             /* In thierry, we should've remounted the media, so run a basic test. */
2812             basic_test(global_media, 1, "            running basic test\n");
2813         }
2814         else if (all_actions[i] == unit_attention_first_semaphore_get_disconnect_actions ||
2815                  all_actions[i] == first_class_instance_semaphore_get_disconnect_actions ||
2816                  all_actions[i] == unit_attention_unit_ready_test_disconnect_actions ||
2817                  all_actions[i] == unit_attention_unit_ready_test_request_sense_disconnect_actions ||
2818                  all_actions[i] == unit_attention_media_characteristics_get_disconnect_actions ||
2819                  all_actions[i] == not_ready_first_semaphore_get_disconnect_actions)
2820         {
2821 
2822             /* Note: the disconnection method we use ensures disconnection is complete. */
2823 
2824             if (global_media->fx_media_id != 0)
2825             {
2826 
2827                 printf("Error on line %d\n", __LINE__);
2828                 test_control_return(1);
2829             }
2830 
2831             /* Setup for next test. */
2832             connect_host_and_slave();
2833         }
2834         else if (all_actions[i] == unit_attention_format_capacity_get_fails_via_memory_alloc_failure_actions)
2835         {
2836 
2837             UX_TEST_ASSERT(ux_test_check_actions_empty());
2838 
2839             if (global_media->fx_media_id != 0)
2840             {
2841 
2842                 printf("Error on line %d\n", __LINE__);
2843                 test_control_return(1);
2844             }
2845 
2846             /* This test consisted of a memory allocation failure. Free the memory. */
2847             ux_test_utility_sim_mem_free_all_flagged(UX_CACHE_SAFE_MEMORY);
2848 
2849             /* The media is in an unstable state. Reset. */
2850             disconnect_host_and_slave();
2851             connect_host_and_slave();
2852         }
2853         else
2854         {
2855 
2856             /* We should handle them individually. */
2857             printf("Error on line %d\n", __LINE__);
2858             test_control_return(1);
2859         }
2860 
2861         UX_TEST_ASSERT(ux_test_check_actions_empty());
2862     }
2863 
2864     /* For this test, there two LUNs and the second one reports the errors. */
2865     stepinfo("    Host receives NOT_READY and UNIT_ATTENTION sense keys from second LUN\n");
2866 
2867     /* Add another LUN. */
2868     global_persistent_slave_storage->ux_slave_class_storage_number_lun = 2;
2869     global_persistent_slave_storage->ux_slave_class_storage_lun[1] = global_persistent_slave_storage->ux_slave_class_storage_lun[0];
2870 
2871     for (i = 0;; i++)
2872     {
2873 
2874         stepinfo("        doing %s\n", stringies[i]);
2875 
2876         disconnect_host_and_slave();
2877         connect_host_and_slave();
2878 
2879         UX_TEST_ACTION multi_lun_not_ready_actions[] = {
2880             create_csw_match_action(global_storage_thread),
2881             create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED),
2882             create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY),
2883             { 0 }
2884         };
2885 
2886         UX_TEST_ACTION multi_lun_unit_attention_actions[] = {
2887             create_csw_match_action(global_storage_thread),
2888             create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED),
2889             create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION),
2890             { 0 }
2891         };
2892 
2893         UX_TEST_ACTION *multi_lun_actions[] = {
2894             multi_lun_not_ready_actions,
2895             multi_lun_unit_attention_actions,
2896         };
2897 
2898         ux_test_set_main_action_list_from_array(multi_lun_actions[i]);
2899 
2900         /* Let storage thread run at least once. */
2901         ux_utility_delay_ms(UX_TEST_SLEEP_STORAGE_THREAD_RUN_ONCE);
2902 
2903         /* First LUN should still be mounted. */
2904         storage_media = global_host_storage_class->ux_host_class_media;
2905         if (!_storage_media_is_mounted())
2906         {
2907 
2908             printf("Error on line %d\n", __LINE__);
2909             test_control_return(1);
2910         }
2911 
2912         storage_media++;
2913         if (multi_lun_actions[i] == multi_lun_not_ready_actions)
2914         {
2915 
2916             /* Make sure storage media is unmounted. */
2917             if (!_storage_media_is_mounted())
2918             {
2919 
2920                 printf("Error on line %d\n", __LINE__);
2921                 test_control_return(1);
2922             }
2923         }
2924         else if (multi_lun_actions[i] == multi_lun_unit_attention_actions)
2925         {
2926 
2927             /* Make sure storage media is mounted. */
2928             if (!_storage_media_is_mounted())
2929             {
2930 
2931                 printf("Error on line %d\n", __LINE__);
2932                 test_control_return(1);
2933             }
2934 
2935             /* In thierry, we should've remounted the media, so run a basic test */
2936             basic_test(global_media, 1, "    running basic test\n");
2937         }
2938 
2939         if (i == ARRAY_COUNT(multi_lun_actions) - 1)
2940         {
2941             break;
2942         }
2943     }
2944 }
2945 
2946 /* Abort media test resources. */
2947 
abort_media_test()2948 static void abort_media_test()
2949 {
2950 
2951 UINT    status;
2952 FX_FILE file;
2953 
2954 
2955     /* Test aborting the media. */
2956     stepinfo("Abort media test\n");
2957 
2958     /* Create file and write something. */
2959     ux_test_storage_file_cow(global_media, &file, global_buffer, 1, UX_TRUE);
2960 
2961     /* Abort media. Media must be reopened if it is to be used again. */
2962     status = fx_media_abort(global_media);
2963     if (status != FX_SUCCESS)
2964     {
2965 
2966         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2967         test_control_return(1);
2968     }
2969 
2970     /* Reopen media. */
2971 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
2972     status = fx_media_open(global_media, UX_HOST_CLASS_STORAGE_MEDIA_NAME, _ux_host_class_storage_driver_entry,
2973                            global_storage, global_storage_media->ux_host_class_storage_media_memory,
2974                            UX_HOST_CLASS_STORAGE_MEMORY_BUFFER_SIZE);
2975 #else
2976     status = fx_media_open(global_media, UX_HOST_CLASS_STORAGE_MEDIA_NAME, _ux_host_class_storage_driver_entry,
2977                            global_storage_media, _ux_host_class_storage_media_fx_media_memory(global_storage_media),
2978                            UX_HOST_CLASS_STORAGE_MEMORY_BUFFER_SIZE);
2979 #endif
2980     if (status != UX_SUCCESS)
2981     {
2982 
2983         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2984         test_control_return(1);
2985     }
2986 
2987     /* Delete the target file.  */
2988     status = fx_file_delete(global_media, "FILE.CPY");
2989     if (status != UX_SUCCESS)
2990     {
2991 
2992         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
2993         test_control_return(1);
2994     }
2995 
2996     /* Do basic test to ensure everything still works. */
2997     ux_test_storage_file_cowcd(global_media, &file, global_buffer, 1);
2998 }
2999 
3000 /* boot_sector_write_fail_test resources */
3001 
boot_sector_write_fail_test()3002 static void boot_sector_write_fail_test()
3003 {
3004 
3005 UINT    status;
3006 
3007 
3008     /* Test formatting the media. */
3009     stepinfo("boot_sector_write_fail_test\n");
3010 
3011     /* This test forces the boot write in ux_host_class_storage_driver_entry to fail. Writing to the boot sector occurs
3012        during fx_media_volume_set.
3013        Specific test case: ux_host_class_storage_driver_entry.c case FX_DRIVER_BOOT_WRITE */
3014     stepinfo("    fx_media_volume_set fails due to write error (also boot write fails test)\n");
3015 
3016     UX_TEST_ACTION actions = { 0 };
3017     add_multiple_read_retries_fails_actions(&actions, tx_thread_identify());
3018     ux_test_set_main_action_list_from_list(&actions);
3019 
3020     status =  fx_media_volume_set(global_media, "C");
3021     if (status == UX_SUCCESS)
3022     {
3023 
3024         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
3025         test_control_return(1);
3026     }
3027 
3028     stepinfo("    fx_media_volume_set succeeds\n");
3029 
3030     /* Do it again without the broken media write function. */
3031     status =  fx_media_volume_set(global_media, "C");
3032     if (status != UX_SUCCESS)
3033     {
3034 
3035         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
3036         test_control_return(1);
3037     }
3038 
3039     /* Do basic test to ensure everything still works. */
3040     basic_test(global_media, 1, "    basic testerino\n");
3041 }
3042 
3043 /* Flush media test resources. */
3044 
flush_media_test()3045 static void flush_media_test()
3046 {
3047 
3048 UINT    status;
3049 FX_FILE file;
3050 
3051 
3052     /* Test flushing the media. */
3053     stepinfo("Flush media test\n");
3054 
3055     /* Create, open, and write file. */
3056     ux_test_storage_file_cow(global_media, &file, global_buffer, 1, UX_TRUE);
3057 
3058     status = fx_media_flush(global_media);
3059     if (status != UX_SUCCESS)
3060     {
3061 
3062         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
3063         test_control_return(1);
3064     }
3065 
3066     /* Close and delete file */
3067     ux_test_storage_file_cd(global_media, &file);
3068 }
3069 
3070 /* Close media test resources. */
3071 
close_media_test()3072 static void close_media_test()
3073 {
3074 
3075 UINT status;
3076 
3077 
3078     /* Test closing the media. */
3079     stepinfo("Close media test\n");
3080 
3081     status = fx_media_close(global_media);
3082     if (status != FX_SUCCESS)
3083     {
3084 
3085         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
3086         test_control_return(1);
3087     }
3088 }
3089 
3090 /* Entry command test resources. */
3091 
entry_command_test()3092 static void entry_command_test()
3093 {
3094 
3095 UINT                    status;
3096 UX_HOST_CLASS_COMMAND   command;
3097 UX_TEST_ACTION          actions[] = {
3098     create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED),
3099     {0}
3100 };
3101 
3102 
3103     /* Test _ux_host_class_storage_entry unknown command */
3104     stepinfo("_ux_host_class_storage_entry unknown command\n");
3105 
3106     ux_test_set_main_action_list_from_array(actions);
3107 
3108     command.ux_host_class_command_request = 0xdeadbeef;
3109     status = ux_host_class_storage_entry(&command);
3110     if (status == UX_SUCCESS)
3111     {
3112 
3113         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
3114         test_control_return(1);
3115     }
3116 }
3117 
get_sector_start()3118 static UINT get_sector_start()
3119 {
3120 UINT sector_start = global_media->fx_media_driver_logical_sector
3121 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
3122          + global_storage_media->ux_host_class_storage_media_partition_start
3123 #endif
3124          ;
3125 
3126 
3127     return sector_start;
3128 }
3129 
ux_test_host_class_storage_media_read_write_basic_test(UINT iterations,char * message,UINT lun)3130 static void ux_test_host_class_storage_media_read_write_basic_test(UINT iterations, char *message, UINT lun)
3131 {
3132 
3133 UCHAR   buffer_pattern;
3134 UINT    sector_count;
3135 UINT    size;
3136 UINT    i;
3137 UINT    j;
3138 
3139 
3140     /* Basic ux_test_host_class_storage_media_write & ux_test_host_class_storage_media_write tests. */
3141     if (message != UX_NULL)
3142     {
3143         stepinfo("%s", message);
3144     }
3145 
3146     if (iterations > 2)
3147     {
3148 
3149         printf("Error on line %d\n", __LINE__);
3150         test_control_return(1);
3151     }
3152 
3153     buffer_pattern = 'G';
3154 
3155 #if 0
3156     for (i = 0; i < iterations; i++)
3157 #else
3158     for (i = 0; i < 1; i++)
3159 #endif
3160     {
3161 
3162         if (i == 0)
3163             size = UX_DEMO_FILE_BUFFER_SIZE;
3164         else
3165             size = UX_DEMO_LARGE_FILE_BUFFER_SIZE;
3166 
3167         sector_count = ((size - 1) + global_storage_media->ux_host_class_storage_media_sector_size) / global_storage_media->ux_host_class_storage_media_sector_size;
3168 
3169         if (i == 0)
3170         {
3171 
3172             /* Set buffer we're going to use to write. */
3173             ux_utility_memory_set(global_buffer, buffer_pattern, size);
3174         }
3175         else
3176         {
3177 
3178             /* Set one half. */
3179             ux_utility_memory_set(global_buffer, buffer_pattern, size / 2);
3180 
3181             /* Set the other half. */
3182             ux_utility_memory_set(global_buffer + size / 2, buffer_pattern + 1, size / 2);
3183         }
3184 
3185         lock_out_storage_thread();
3186         global_storage->ux_host_class_storage_lun = lun;
3187         ux_test_host_class_storage_media_write(global_storage,
3188             global_media->fx_media_driver_logical_sector
3189 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
3190              + global_storage_media->ux_host_class_storage_media_partition_start
3191 #endif
3192              ,
3193             sector_count, global_buffer);
3194         lock_in_storage_thread();
3195 
3196         /* Clear buffer to make sure read() really works. */
3197         ux_utility_memory_set(global_buffer, 0, UX_DEMO_FILE_BUFFER_SIZE);
3198 
3199         lock_out_storage_thread();
3200         global_storage->ux_host_class_storage_lun = lun;
3201         ux_test_host_class_storage_media_read(global_storage,
3202             global_media->fx_media_driver_logical_sector
3203 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
3204              + global_storage_media->ux_host_class_storage_media_partition_start
3205 #endif
3206              ,
3207             sector_count, global_buffer);
3208         lock_in_storage_thread();
3209 
3210         /* Check result of read(). */
3211         if (i == 0)
3212         {
3213 
3214             for (j = 0; j < size; j++)
3215             {
3216 
3217                 if (global_buffer[j] != buffer_pattern)
3218                 {
3219 
3220                     printf("Error on line %d\n", __LINE__);
3221                     test_control_return(1);
3222                 }
3223             }
3224         }
3225         else
3226         {
3227 
3228             for (j = 0; j < size / 2; j++)
3229             {
3230 
3231                 if ((global_buffer[j] != buffer_pattern) || (global_buffer[size / 2 + j] != (buffer_pattern + 1)))
3232                 {
3233 
3234                     printf("Error on line %d\n", __LINE__);
3235                     test_control_return(1);
3236                 }
3237             }
3238         }
3239     }
3240 }
3241 
3242 /* fx_media_write test resources */
3243 
3244 /* This is used to match our action with cbw transfer (CBW has a length field, we try to match it). */
3245 #define WRITE_SIZE (2*UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE)
3246 
fx_media_write_test()3247 static void fx_media_write_test()
3248 {
3249 
3250 UINT    status;
3251 FX_FILE file;
3252 
3253 
3254     stepinfo("Test fx_media_write API\n");
3255 
3256     /* Specific test case: in ux_host_class_storage_driver_entry, the media_write() fails. */
3257     stepinfo("    transfer fails\n");
3258 
3259     ux_test_storage_file_co(global_media, &file, UX_TRUE);
3260 
3261     UX_TEST_ACTION cbw_transfer_fail_actions[] = {
3262         create_cbw_disconnect_action(tx_thread_identify()),
3263         { 0 }
3264     };
3265     ux_test_set_main_action_list_from_array(cbw_transfer_fail_actions);
3266 
3267     status = fx_file_write(&file, global_buffer, WRITE_SIZE);
3268     if (status == FX_SUCCESS)
3269     {
3270 
3271         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
3272         test_control_return(1);
3273     }
3274 
3275     UX_TEST_ASSERT(ux_test_check_actions_empty());
3276     connect_host_and_slave();
3277 
3278     stepinfo("    data phase fails due to timeout\n");
3279 
3280     DEVICE_MEDIA_READ_WRITE_TIMEOUT_DATA timeout_data;
3281     timeout_data.num_timeouts = 1;
3282     timeout_data.transfer_request = &global_storage->ux_host_class_storage_bulk_out_endpoint->ux_endpoint_transfer_request;
3283 
3284     UX_TEST_ACTION data_phase_timeout_actions[] = {
3285         create_device_media_write_block_action(&timeout_data),
3286         create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT),
3287         { 0 }
3288     };
3289     ux_test_set_main_action_list_from_array(data_phase_timeout_actions);
3290 
3291     lock_out_storage_thread();
3292     UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, UX_TEST_MULTIPLE_TRANSFERS_SECTOR_COUNT, global_buffer));
3293     receive_device_csw();
3294     lock_in_storage_thread();
3295     UX_TEST_ASSERT(ux_test_check_actions_empty());
3296     basic_test(global_media, 1, "        basic test\n");
3297 
3298     /* Specific test case: while (media_retry-- != 0) fails in ux_test_host_class_storage_media_write */
3299     /* How: Having the device write fail, causing the device to stall the endpoint and send a CSW with error. */
3300     stepinfo("    multiple retries fails\n");
3301 
3302     ux_test_storage_file_co(global_media, &file, UX_TRUE);
3303 
3304     UX_TEST_ACTION actions = { 0 };
3305     add_multiple_write_retries_fails_actions(&actions);
3306     ux_test_set_main_action_list_from_list(&actions);
3307 
3308     status = fx_file_write(&file, global_buffer, WRITE_SIZE);
3309     if (status == FX_SUCCESS)
3310     {
3311 
3312         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
3313         test_control_return(1);
3314     }
3315 
3316     basic_test_pre_existing_file(1, "    running basic test\n", &file);
3317 
3318     UX_TEST_ASSERT(ux_test_check_actions_empty());
3319 }
3320 
3321 #undef WRITE_SIZE
3322 
3323 /* fx_media_read test resources */
3324 
boot_read_fails_action_check_function()3325 static UCHAR boot_read_fails_action_check_function()
3326 {
3327 
3328 UCHAR result;
3329 
3330 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
3331     /* Is this from FileX? */
3332     result = (get_internal_host_storage_medias()->ux_host_class_storage_media_memory != UX_NULL);
3333 #else
3334     result = UX_TRUE;
3335 #endif
3336     return result ? UX_TRUE : UX_FALSE;
3337 }
3338 
create_boot_read_from_filex_fails_action(TX_THREAD * thread_to_match)3339 static UX_TEST_ACTION create_boot_read_from_filex_fails_action(TX_THREAD *thread_to_match)
3340 {
3341 
3342 UX_TEST_ACTION action;
3343 
3344 
3345     action = create_device_media_read_fail_action(thread_to_match);
3346     action.check_func = boot_read_fails_action_check_function;
3347 
3348     return action;
3349 }
3350 
3351 /* BUG_ID_19 - tldr; original sim is broken, so this size only works with fixed sim. */
3352 #define READ_SIZE (2*UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE)
3353 
fx_media_read_test()3354 static void fx_media_read_test()
3355 {
3356 
3357 UINT                            status;
3358 UX_TEST_ERROR_CALLBACK_ERROR    transfer_stall_error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_TRANSFER_STALLED };
3359 FX_FILE                         file;
3360 ULONG                           actual_size;
3361 UX_HOST_CLASS_STORAGE_MEDIA     *storage_media;
3362 UINT                            i;
3363 
3364 
3365     stepinfo("Test fx_media_read API\n");
3366 
3367     stepinfo("    large read\n");
3368 
3369     /* Set first half of buffer to 'a', second half to 'b'. */
3370     ux_utility_memory_set(global_buffer_2x_slave_buffer_size, 'a', sizeof(global_buffer_2x_slave_buffer_size)/2);
3371     ux_utility_memory_set(global_buffer_2x_slave_buffer_size + sizeof(global_buffer_2x_slave_buffer_size)/2, 'b', sizeof(global_buffer_2x_slave_buffer_size)/2);
3372 
3373     /* We need to create a file and write to it, since there actually needs to be something to read. */
3374     ux_test_storage_file_cow(global_media, &file, global_buffer_2x_slave_buffer_size, READ_SIZE, UX_TRUE);
3375 
3376     status = fx_file_read(&file, global_buffer_2x_slave_buffer_size, READ_SIZE, &actual_size);
3377     if (status != FX_SUCCESS)
3378     {
3379 
3380         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
3381         test_control_return(1);
3382     }
3383 
3384     /* Ensure data is correct. */
3385     for (i = 0; i < sizeof(global_buffer_2x_slave_buffer_size)/2; i++)
3386     {
3387 
3388         if (global_buffer_2x_slave_buffer_size[i] != 'a' ||
3389             global_buffer_2x_slave_buffer_size[sizeof(global_buffer_2x_slave_buffer_size)/2 + i] != 'b')
3390         {
3391 
3392             printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
3393             test_control_return(1);
3394         }
3395     }
3396 
3397     /* Specific test case: in ux_host_class_storage_driver_entry, the media_read() fails. */
3398     stepinfo("    transfer fails\n");
3399 
3400     status = fx_file_seek(&file, 0);
3401     if (status != FX_SUCCESS)
3402     {
3403 
3404         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
3405         test_control_return(1);
3406     }
3407 
3408     UX_TEST_ACTION cbw_disconnect_actions[] = {
3409         create_cbw_disconnect_action(tx_thread_identify()),
3410         { 0 }
3411     };
3412     ux_test_set_main_action_list_from_array(cbw_disconnect_actions);
3413 
3414     UX_TEST_CHECK_NOT_SUCCESS(fx_file_read(&file, global_buffer_2x_slave_buffer_size, READ_SIZE, &actual_size));
3415     connect_host_and_slave();
3416 
3417 #if 0 /* NOBUGFIX: BUG_ID_25 */
3418     stepinfo("    multiple BO data phase transfers, first one fails\n");
3419 
3420     /* Action for making read fail. */
3421     read_fail_actions[0].is_valid = UX_TRUE;
3422     read_fail_actions[0].func = ux_test_host_class_storage_media_read_test_media_read_action_func;
3423 
3424     /* Set media read action. */
3425     set_device_media_read_actions(read_fail_actions);
3426 
3427     /* We should get one stall error. */
3428     ux_test_error_callback_add_error_to_ignore(stall_error);
3429 
3430     status = ux_test_media_read(storage, media->fx_media_driver_logical_sector +
3431                                  storage_media->ux_host_class_storage_media_partition_start,
3432                                  8, media->fx_media_driver_buffer, UX_FALSE);
3433     if (status == UX_SUCCESS)
3434     {
3435 
3436         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
3437         test_control_return(1);
3438     }
3439 #endif
3440 
3441     /* Specific test case: while (media_retry-- != 0) fails */
3442     /* Specific test case: if (*(cbw + UX_HOST_CLASS_STORAGE_CBW_FLAGS) == UX_HOST_CLASS_STORAGE_DATA_IN) in
3443        ux_host_class_transport_bo */
3444     /* Note: this one is a pain in the ass, since the sense code check is after
3445        the data phase length check. This means the data phase has to "succeed",
3446        but the sense code contains an error. Is this even possible? I think so:
3447        if the device has less data to send than the host requests, but pads out
3448        the data, then according to the spec (thirteen cases), the device will
3449        stall the endpoint, and most likely, the request sense will have an error. */
3450     stepinfo("    multiple retries fails\n");
3451 
3452     ux_test_storage_file_cow(global_media, &file, global_buffer, 512, UX_TRUE);
3453     UX_TEST_ACTION actions = { 0 };
3454     add_multiple_read_retries_fails_actions(&actions, tx_thread_identify());
3455     ux_test_set_main_action_list_from_list(&actions);
3456     UX_TEST_CHECK_NOT_SUCCESS(fx_file_read(&file, global_buffer, 512, &actual_size));
3457     UX_TEST_ASSERT(ux_test_check_actions_empty());
3458     basic_test_pre_existing_file(1, "    running basic test\n", &file);
3459 
3460 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX) /* Boot read is available only when FX_MEDIA is integrated.  */
3461     /* This test occurs during enumeration. The boot sector read needs to fail in the USBX storage driver for FileX.
3462        This means we can't just fail during the first boot sector read; we need to fail only when it's a boot sector
3463        read from FileX. How do we determine if it's from FileX? Before USBX calls fx_media_open() (which does the boot
3464        sector read), it initializes a UX_HOST_CLASS_STORAGE_MEDIA instance. We check if that instance is initialized
3465        and if it is, we know FileX is doing the read... The problem is that upon deinitialization, USBX doesn't clear
3466        reset the instance's members, so we do it ourselves.
3467 
3468        Specific test case: ux_host_class_storage_driver_entry.c case FX_DRIVER_BOOT_READ
3469                            and
3470                            / Ask FileX to mount the partition.  /
3471                            ux_host_class_storage_media_open.c fx_media_open fails
3472     */
3473     stepinfo("    boot read fails\n");
3474 
3475     disconnect_host_and_slave();
3476 
3477     /* Point the media structure to the first media in the container.  */
3478     storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) _ux_system_host -> ux_system_host_class_array[0].ux_host_class_media;
3479 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
3480     storage_media -> ux_host_class_storage_media_memory = UX_NULL;
3481 #endif
3482 
3483     for (i = 0; i < UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RETRY; i++)
3484     {
3485         ux_test_add_action_to_main_list(create_boot_read_from_filex_fails_action(tx_thread_identify()));
3486         ux_test_add_action_to_main_list(create_error_match_action_from_error(transfer_stall_error));
3487     }
3488 
3489     connect_host_and_slave();
3490 
3491     /* Since boot read should've failed, the storage instance shouldn't be valid. */
3492     if (global_media -> fx_media_id != 0)
3493     {
3494 
3495         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
3496         test_control_return(1);
3497     }
3498 #endif
3499 }
3500 
3501 /* first_sector_non_boot_test_ram_disk_memory test resources */
3502 
3503 static CHAR     first_sector_non_boot_test_ram_disk_memory[1*1024];
3504 
first_sector_non_boot_test_media_read_action_func(UX_TEST_ACTION * action,VOID * _params)3505 static VOID first_sector_non_boot_test_media_read_action_func(UX_TEST_ACTION *action, VOID *_params)
3506 {
3507 
3508 UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *params = (UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *)_params;
3509 
3510 
3511     while (params->number_blocks--)
3512     {
3513         ux_utility_memory_copy(params->data_pointer, first_sector_non_boot_test_ram_disk_memory + global_sector_size * params->lba, global_sector_size);
3514         params->lba++;
3515     }
3516 }
3517 
create_first_sector_non_boot_test_media_read_action()3518 static UX_TEST_ACTION create_first_sector_non_boot_test_media_read_action()
3519 {
3520 
3521 UX_TEST_ACTION action = { 0 };
3522 
3523 
3524     action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ;
3525     action.ignore_params = 1;
3526     action.no_return = 0;
3527     action.status = UX_SUCCESS;
3528     action.action_func = first_sector_non_boot_test_media_read_action_func;
3529 
3530     return action;
3531 }
3532 
3533 /* Tests the cases where the first sector is not the boot sector, but instead a partition table. */
first_sector_non_boot_test()3534 static void first_sector_non_boot_test()
3535 {
3536 
3537 UINT                    i;
3538 UX_SLAVE_CLASS_STORAGE  *device_storage;
3539 UCHAR                   *extended_partition;
3540 UCHAR                   *partition_table;
3541 UCHAR                   partition_types[] = {
3542     /* Extended partitions. */
3543     UX_HOST_CLASS_STORAGE_PARTITION_EXTENDED,
3544     UX_HOST_CLASS_STORAGE_PARTITION_EXTENDED_LBA_MAPPED,
3545 
3546     /* Regular partitions. */
3547     UX_HOST_CLASS_STORAGE_PARTITION_FAT_12,
3548     UX_HOST_CLASS_STORAGE_PARTITION_FAT_16,
3549     UX_HOST_CLASS_STORAGE_PARTITION_FAT_16L,
3550     UX_HOST_CLASS_STORAGE_PARTITION_FAT_16_LBA_MAPPED,
3551     UX_HOST_CLASS_STORAGE_PARTITION_FAT_32_1,
3552     UX_HOST_CLASS_STORAGE_PARTITION_FAT_32_2,
3553 
3554     /* Unknown partition. */
3555     0xff
3556 };
3557 UX_TEST_ACTION          first_sector_non_boot_test_extended_media_actions[] = {
3558     create_first_sector_non_boot_test_media_read_action(),
3559     create_first_sector_non_boot_test_media_read_action(),
3560     { 0 }
3561 };
3562 UX_TEST_ACTION          first_sector_non_boot_test_media_read_actions[] = {
3563     create_first_sector_non_boot_test_media_read_action(),
3564     { 0 }
3565 };
3566 
3567 
3568     stepinfo("first sector is not boot test\n");
3569 
3570     /* Get device storage instance. */
3571     device_storage = _ux_system_slave->ux_system_slave_class_array[0].ux_slave_class_instance;
3572 
3573     for (i = 0; i < ARRAY_COUNT(partition_types); i++)
3574     {
3575 
3576         stepinfo("    doing %d\n", i);
3577 
3578         disconnect_host_and_slave();
3579 
3580         /* Set disk. */
3581 
3582         partition_table = &first_sector_non_boot_test_ram_disk_memory[UX_HOST_CLASS_STORAGE_PARTITION_TABLE_START];
3583 
3584         /* Set partition signature. */
3585         ux_utility_short_put(first_sector_non_boot_test_ram_disk_memory + 510, UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE);
3586 
3587         /* Make sure there's no boot signature. */
3588         first_sector_non_boot_test_ram_disk_memory[0] = 0x00;
3589         first_sector_non_boot_test_ram_disk_memory[1] = 0x00;
3590         first_sector_non_boot_test_ram_disk_memory[2] = 0x00;
3591 
3592         /* Set the partition table entry type. */
3593         partition_table[UX_HOST_CLASS_STORAGE_PARTITION_TYPE] = partition_types[i];
3594 
3595         /* Is this an extended entry? An extended entry means it points to another partition table. */
3596         if (partition_types[i] == UX_HOST_CLASS_STORAGE_PARTITION_EXTENDED ||
3597             partition_types[i] == UX_HOST_CLASS_STORAGE_PARTITION_EXTENDED_LBA_MAPPED)
3598         {
3599 
3600             /* The extended partition is located one sector away. */
3601             partition_table[UX_HOST_CLASS_STORAGE_PARTITION_SECTORS_BEFORE] = 1;
3602 
3603             /* Set disk. */
3604 
3605             extended_partition = &first_sector_non_boot_test_ram_disk_memory[UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT];
3606             partition_table = &extended_partition[UX_HOST_CLASS_STORAGE_PARTITION_TABLE_START];
3607 
3608             /* Set partition signature. */
3609             ux_utility_short_put(extended_partition + 510, UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE);
3610 
3611             /* Make sure there's no boot signature. */
3612             extended_partition[0] = 0x00;
3613             extended_partition[1] = 0x00;
3614             extended_partition[2] = 0x00;
3615 
3616             /* Set the type to something non-extended so we don't recurse. */
3617             partition_table[UX_HOST_CLASS_STORAGE_PARTITION_TYPE] = UX_HOST_CLASS_STORAGE_PARTITION_FAT_12;
3618 
3619             /* We want subsequent boot sector reads to read the beginning of the ram disk (where FileX formatted it).
3620                We need to overflow to get the SECTORS_BEFORE to equal zero. */
3621             ux_utility_long_put(&partition_table[UX_HOST_CLASS_STORAGE_PARTITION_SECTORS_BEFORE], ~0);
3622 
3623             /* Set action for media read. Since it's an extended entry, it will read twice. */
3624             ux_test_set_main_action_list_from_array(first_sector_non_boot_test_extended_media_actions);
3625         }
3626         else
3627         {
3628 
3629             /* We want subsequent boot sector reads to read the beginning of the ram disk (where FileX formatted it). */
3630             partition_table[UX_HOST_CLASS_STORAGE_PARTITION_SECTORS_BEFORE] = 0;
3631 
3632             /* Set action for media read. */
3633             ux_test_set_main_action_list_from_array(first_sector_non_boot_test_media_read_actions);
3634         }
3635 
3636         /* Start enumeration. */
3637         connect_host_and_slave();
3638 
3639         if (partition_types[i] != PARTITION_TYPE_UNKNOWN)
3640         {
3641 
3642             if (global_storage == UX_NULL)
3643             {
3644 
3645                 printf("Error on line %d\n", __LINE__);
3646                 test_control_return(1);
3647             }
3648 
3649             basic_test(global_media, 1, "    running basic test\n");
3650         }
3651         /* Ensure unknown partition wasn't mounted. */
3652         else if (global_media->fx_media_id != 0)
3653         {
3654 
3655             printf("Error on line %d\n", __LINE__);
3656             test_control_return(1);
3657         }
3658     }
3659 
3660     /* Since during the last test the media was never opened, we need to disconnect and reconnect. */
3661     disconnect_host_and_slave();
3662     connect_host_and_slave();
3663 }
3664 
3665 /* multiple_and_different_lun_types_test resources */
3666 
3667 static UINT                         madltt_media_types[] = { UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK, UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK, UX_HOST_CLASS_STORAGE_MEDIA_CDROM, MEDIA_TYPE_UNKNOWN };
3668 static UX_TEST_ERROR_CALLBACK_ERROR dltt_media_not_supported_error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_MEDIA_NOT_SUPPORTED };
3669 static UCHAR                        dltt_unit_test_called_actions_data[UX_HOST_CLASS_STORAGE_MAX_MEDIA][sizeof(global_cbw_data_unit_ready_test_sbc)];
3670 static UX_TEST_ACTION               dltt_unit_test_called_actions[UX_HOST_CLASS_STORAGE_MAX_MEDIA + 1];
3671 
3672 /* This tests every possible permutation of LUN types within the allowable number of medias
3673    (UX_HOST_CLASS_STORAGE_MAX_MEDIA). We don't use the max LUNs because it's possible for us to run out of medias
3674    (USBX-93). */
dltt_test_every_lun_type_permutation(UINT luns_remaining)3675 static void dltt_test_every_lun_type_permutation(UINT luns_remaining)
3676 {
3677 
3678 UINT            lun_idx;
3679 UINT            media_idx;
3680 UINT            num_medias;
3681 UINT            expected_medias;
3682 UINT            expected_unit_ready_tests;
3683 UX_TEST_ACTION  media_not_supported_match_action = create_error_match_action_from_error(dltt_media_not_supported_error);
3684 
3685 
3686     if (luns_remaining > 0)
3687     {
3688 
3689         for (lun_idx = 0; lun_idx < ARRAY_COUNT(madltt_media_types); lun_idx++)
3690         {
3691 
3692             global_persistent_slave_storage->ux_slave_class_storage_lun[luns_remaining - 1].ux_slave_class_storage_media_type = madltt_media_types[lun_idx];
3693             global_persistent_slave_storage->ux_slave_class_storage_lun[luns_remaining - 1].ux_slave_class_storage_media_removable_flag = (lun_idx % 2) ? 0x80 : 0x00;
3694             dltt_test_every_lun_type_permutation(luns_remaining - 1);
3695         }
3696     }
3697     else
3698     {
3699 
3700         /* All the LUNs are set. Let's do it! */
3701 
3702         stepinfo("        disconnecting...\n");
3703 
3704         disconnect_host_and_slave();
3705 
3706         global_persistent_slave_storage->ux_slave_class_storage_number_lun = UX_HOST_CLASS_STORAGE_MAX_MEDIA;
3707 
3708         /* Initialize actions. */
3709         ux_utility_memory_set(dltt_unit_test_called_actions, 0, sizeof(dltt_unit_test_called_actions));
3710 
3711         /* Get the number of medias we expect the LUNs should have, and add errors to ignore. */
3712         expected_medias = 0;
3713         expected_unit_ready_tests = 0;
3714         for (lun_idx = 0; lun_idx < ARRAY_COUNT(global_persistent_slave_storage->ux_slave_class_storage_lun); lun_idx++)
3715         {
3716 
3717             if (global_persistent_slave_storage->ux_slave_class_storage_lun[lun_idx].ux_slave_class_storage_media_type == UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK ||
3718                 global_persistent_slave_storage->ux_slave_class_storage_lun[lun_idx].ux_slave_class_storage_media_type == UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK ||
3719                 global_persistent_slave_storage->ux_slave_class_storage_lun[lun_idx].ux_slave_class_storage_media_type == UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK)
3720             {
3721                 expected_medias++;
3722 
3723 #if 0 /* NOBUGFIX: USBX_100 */
3724                 if (global_persistent_slave_storage->ux_slave_class_storage_lun[lun_idx].ux_slave_class_storage_media_removable_flag == 0x80)
3725                 {
3726 
3727                     ux_utility_memory_copy(dltt_unit_test_called_actions_data[expected_unit_ready_tests], global_transfer_request_data_unit_test_sbc_cbw, sizeof(global_transfer_request_data_unit_test_sbc_cbw));
3728                     dltt_unit_test_called_actions_data[expected_unit_ready_tests][UX_HOST_CLASS_STORAGE_CBW_LUN] = lun_idx;
3729                     dltt_unit_test_called_actions[expected_unit_ready_tests].function = UX_HCD_TRANSFER_REQUEST;
3730                     dltt_unit_test_called_actions[expected_unit_ready_tests].req_actual_len = sizeof(global_transfer_request_data_unit_test_sbc_cbw);
3731                     dltt_unit_test_called_actions[expected_unit_ready_tests].no_return = 1;
3732                     dltt_unit_test_called_actions[expected_unit_ready_tests].req_data = dltt_unit_test_called_actions_data[expected_unit_ready_tests];
3733                     expected_unit_ready_tests++;
3734                 }
3735 #endif
3736             }
3737             else if (global_persistent_slave_storage->ux_slave_class_storage_lun[lun_idx].ux_slave_class_storage_media_type == MEDIA_TYPE_UNKNOWN)
3738             {
3739 
3740                 ux_test_add_action_to_main_list(media_not_supported_match_action);
3741             }
3742         }
3743 
3744         for (lun_idx = 0; lun_idx < UX_HOST_CLASS_STORAGE_MAX_MEDIA; lun_idx++)
3745             stepinfo( "            media type: %lu\n", global_persistent_slave_storage->ux_slave_class_storage_lun[lun_idx].ux_slave_class_storage_media_type);
3746 
3747         stepinfo("        connecting...\n");
3748         connect_host_and_slave();
3749 
3750         stepinfo("            waiting 2 seconds for storage thread to run...\n");
3751 
3752 #if 0 /* NOBUGFIX: USBX_100 */
3753         /* Add actions. */
3754         if (dltt_unit_test_called_actions[0].function != 0)
3755             ux_test_set_actions(dltt_unit_test_called_actions);
3756 #endif
3757 
3758         /* Let storage thread run least once. */
3759         ux_utility_delay_ms(UX_TEST_SLEEP_STORAGE_THREAD_RUN_ONCE);
3760 
3761 #if 0 /* NOBUGFIX USBX_100 */
3762         if (ux_test_actions_empty_check() != UX_TRUE)
3763         {
3764 
3765             printf("Error on line %d\n", __LINE__);
3766             test_control_return(1);
3767         }
3768 #endif
3769 
3770         /* Go through each LUN and run a test if applicable. */
3771         num_medias = 0;
3772         media_idx = 0;
3773         for (lun_idx = 0; lun_idx < UX_HOST_CLASS_STORAGE_MAX_MEDIA; lun_idx++)
3774         {
3775 
3776             if (global_storage->ux_host_class_storage_lun_types[lun_idx] == UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK ||
3777                 global_storage->ux_host_class_storage_lun_types[lun_idx] == UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK ||
3778                 global_storage->ux_host_class_storage_lun_types[lun_idx] == UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK)
3779             {
3780 
3781                 /* Only optical disks, fat disks, and iomega clicks have FX_MEDIAs instances, which is why we only
3782                    increment media_idx if the type is one of those two. */
3783                 basic_test(
3784 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
3785                     &global_storage_medias[media_idx++].ux_host_class_storage_media,
3786 #else
3787                     _ux_host_class_storage_media_fx_media(&global_storage_medias[media_idx++]),
3788 #endif
3789                     1, "            running basic test...\n");
3790 
3791                 /* We need to remove the file entirely for the next test. Usually disconnect_host_and_slave() does this
3792                    but we're not calling that in between basic_test() calls, now are we?...!...? */
3793                 format_ram_disk();
3794 
3795                 num_medias++;
3796             }
3797             else if (global_storage->ux_host_class_storage_lun_types[lun_idx] == UX_HOST_CLASS_STORAGE_MEDIA_CDROM)
3798             {
3799 
3800                 /* For CDROMs, we don't mount the partition, so we can't use FileX. Also, we have to manually set which
3801                    LUN we want USBX to write to. */
3802                 ux_test_host_class_storage_media_read_write_basic_test(1, "            running basic test...\n", lun_idx);
3803             }
3804             else// if(MEDIA_TYPE_UNKNOWN)
3805             {
3806                 /* Do nothing. */
3807             }
3808         }
3809 
3810         if (num_medias != expected_medias)
3811         {
3812 
3813             printf("Error on line %d\n", __LINE__);
3814             test_control_return(1);
3815         }
3816 
3817         if (ux_test_check_actions_empty() == UX_FALSE)
3818         {
3819 
3820             printf("Error on line %d\n", __LINE__);
3821             test_control_return(1);
3822         }
3823     }
3824 }
3825 
multiple_and_different_lun_types_test()3826 static void multiple_and_different_lun_types_test()
3827 {
3828 
3829 UINT            i;
3830 UX_TEST_ACTION  unknown_media_error_actions[] = {
3831     create_error_match_action_from_error(dltt_media_not_supported_error),
3832     { 0 }
3833 };
3834 
3835 
3836     /* Specific test cases: (storage -> ux_host_class_storage_removable_media == UX_HOST_CLASS_STORAGE_MEDIA_REMOVABLE)
3837        passes and fails in ux_host_class_storage_thread_entry.c */
3838 
3839     stepinfo("multiple_and_different_lun_types_test\n");
3840 
3841     stepinfo("    max lun test\n");
3842 
3843     for (i = 1; i < UX_HOST_CLASS_STORAGE_MAX_MEDIA; i++)
3844     {
3845         global_persistent_slave_storage->ux_slave_class_storage_lun[i] = global_persistent_slave_storage->ux_slave_class_storage_lun[0];
3846     }
3847 
3848     dltt_test_every_lun_type_permutation(UX_HOST_CLASS_STORAGE_MAX_MEDIA);
3849 
3850     /* Note: if there's a test after this, we should reset_to_bo(). */
3851     reset_to_bo();
3852 
3853     /* When we disconnect the slave, it sets the global device storage pointer to null. Save it! */
3854     global_persistent_slave_storage = global_slave_storage;
3855 }
3856 
3857 /* Transport failures cause device reset test resources. */
3858 
transport_failures_cause_device_reset_test()3859 static void transport_failures_cause_device_reset_test()
3860 {
3861 
3862     UX_TEST_ACTION actions[] = {
3863         /* This will cause the CSW to contain an error. */
3864         create_device_media_write_fail_action(),
3865         /* This is how we make the REQUEST SENSE fail. Every other option is completely ridiculous (i.e. transmission
3866            error, which never ever happens, and if they do happen, then the controller is broken). */
3867         create_disconnect_on_transfer_data_match_action(tx_thread_identify(), global_cbw_data_request_sense, sizeof(global_cbw_data_request_sense)),
3868         /* Since we disconnect, the request is never sent to the HCD, so we can't check it. */
3869         //create_mass_storage_reset_match_action(tx_thread_identify()),
3870         { 0 }
3871     };
3872 
3873 
3874     stepinfo("transport_failures_cause_device_reset_test\n");
3875 
3876     ux_test_set_main_action_list_from_array(actions);
3877 
3878     lock_out_storage_thread();
3879     UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, 1, global_buffer));
3880     lock_in_storage_thread();
3881 
3882     connect_host_and_slave();
3883 }
3884 
3885 /* Resources for failure of starting the UFI device test. */
3886 
ufi_start_fails_action_func(UX_TEST_ACTION * action,VOID * _params)3887 static void ufi_start_fails_action_func(UX_TEST_ACTION *action, VOID *_params)
3888 {
3889 
3890 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
3891 UX_TRANSFER                         *transfer_request = params->parameter;
3892 
3893 
3894     transfer_request->ux_transfer_request_completion_code = UX_ERROR;
3895 }
3896 
3897 /* Specific test case: _ux_host_class_storage_start_stop fails in _ux_host_class_storage_media_mount */
ufi_start_fails()3898 static void ufi_start_fails()
3899 {
3900 
3901 UCHAR             transfer_data_ufi_start_cb[] = { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
3902 UX_TEST_ACTION    actions[2] = { 0 };
3903 
3904 
3905     stepinfo("ufi_start_fails test\n");
3906 
3907     /* Action for making transfer of start command fail. */
3908     actions[0].usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
3909     actions[0].function = UX_HCD_TRANSFER_REQUEST;
3910     actions[0].action_func = ufi_start_fails_action_func;
3911     actions[0].req_data = transfer_data_ufi_start_cb;
3912     actions[0].req_actual_len = sizeof(transfer_data_ufi_start_cb);
3913     actions[0].no_return = 0;
3914     actions[0].status = UX_ERROR;
3915 
3916     disconnect_host_and_slave();
3917 
3918     /* Switch to CBI (only CBI requires start command). */
3919 
3920     device_framework_full_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI;
3921     device_framework_high_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI;
3922     device_framework_full_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI;
3923     device_framework_high_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI;
3924 
3925     global_hcd->ux_hcd_entry_function = _ux_hcd_sim_host_entry_bo_to_cbi;
3926     global_dcd->ux_slave_dcd_function = _ux_dcd_sim_slave_function_bo_to_cbi;
3927 
3928     /* Set actions */
3929     ux_test_set_main_action_list_from_array(actions);
3930 
3931     connect_host_and_slave();
3932 
3933     if (global_media->fx_media_id == FX_MEDIA_ID)
3934     {
3935 
3936         printf("Error on line %d\n", __LINE__);
3937         test_control_return(1);
3938     }
3939 }
3940 
3941 /* First sector read fails test resources. */
3942 
3943 /* Specific test case: case UX_HOST_CLASS_STORAGE_SENSE_ERROR: and default: in ux_host_class_storage_media_mount */
media_mount_first_sector_read_fails_test()3944 static void media_mount_first_sector_read_fails_test()
3945 {
3946 
3947 UINT errors[] = { UX_ERROR, UX_HOST_CLASS_STORAGE_SENSE_ERROR };
3948 
3949 
3950     stepinfo("media_mount_first_sector_read_fail test\n");
3951 
3952     /* How: Read keeps failing. Note: this assumes the very first read the one we're looking for. */
3953     stepinfo("    case UX_HOST_CLASS_STORAGE_SENSE_ERROR: \n");
3954 
3955     disconnect_host_and_slave();
3956     UX_TEST_ACTION actions = { 0 };
3957     add_multiple_read_retries_fails_actions(&actions, tx_thread_identify());
3958     ux_test_set_main_action_list_from_list(&actions);
3959     connect_host_and_slave();
3960 
3961     /* How: we disconnect during the read. */
3962     stepinfo("    default :\n");
3963 
3964     disconnect_host_and_slave();
3965     ux_test_add_action_to_main_list(create_disconnect_on_transfer_data_match_action(global_enum_thread, global_cbw_data_first_sector_read, sizeof(global_cbw_data_first_sector_read)));
3966     UX_TEST_ASSERT(connect_host_and_slave() != UX_SUCCESS);
3967 }
3968 
3969 /* First sector not partition test resources. */
3970 
3971 static UINT first_sector_different_signatures_test_num;
3972 static ULONG first_sector_different_signatures_sig_values[5][6] =
3973 {
3974        /* 510 */                                  /* 0 */   /* 2 */ /* 0x16 */  /* 0x24 */
3975     /* _ux_utility_short_get(sector_memory + 510) == UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE fails */
3976     { ~UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE, 0,        0,      0,          0,          UX_ERROR  },
3977     /* (*sector_memory == 0xe9) fails */
3978     {  UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE, 0xeb,     0x90,   0xff,       0,          UX_SUCCESS },
3979     /* *(sector_memory + 2) == 0x90 fails */
3980     {  UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE, 0xeb,     0,      0,          0,          UX_ERROR },
3981     /* _ux_utility_short_get(sector_memory + 0x16) != 0x0 fails and _ux_utility_long_get(sector_memory + 0x24) != 0x0 succeeds */
3982     {  UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE, 0xe9,     0,      0x00,       0xff,       UX_SUCCESS },
3983     /* _ux_utility_long_get(sector_memory + 0x24) != 0x0 fails */
3984     {  UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE, 0xe9,     0,      0x00,       0x00,       UX_ERROR },
3985 };
3986 
first_sector_different_signatures_action_func(UX_TEST_ACTION * action,VOID * _params)3987 static VOID first_sector_different_signatures_action_func(UX_TEST_ACTION *action, VOID *_params)
3988 {
3989 
3990 UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *params = (UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS *)_params;
3991 
3992 
3993     params->data_pointer[510] =                         (UCHAR) first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][0];
3994     params->data_pointer[0] =                           (UCHAR) first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][1];
3995     params->data_pointer[2] =                           (UCHAR) first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][2];
3996     ux_utility_short_put(&params->data_pointer[0x16],   (USHORT)first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][3]);
3997     ux_utility_long_put(&params->data_pointer[0x24],            first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][4]);
3998 }
3999 
create_first_sector_different_signature_action()4000 static UX_TEST_ACTION create_first_sector_different_signature_action()
4001 {
4002 
4003 UX_TEST_ACTION action = { 0 };
4004 
4005 
4006     action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ;
4007     action.action_func = first_sector_different_signatures_action_func;
4008     action.do_after = 1;
4009     action.no_return = 1;
4010     action.ignore_params = 1;
4011 
4012     return action;
4013 }
4014 
4015 /* Specific test case: if (_ux_utility_short_get(sector_memory + 510) == UX_HOST_CLASS_STORAGE_PARTITION_SIGNATURE) fails in ux_host_class_storage_media_mount */
first_sector_different_signatures_test()4016 static void first_sector_different_signatures_test()
4017 {
4018 
4019 UX_TEST_ACTION actions[] = {
4020     create_first_sector_different_signature_action(),
4021     { 0 }
4022 };
4023 
4024 
4025     stepinfo("first_sector_different_signatures\n");
4026 
4027     for (; first_sector_different_signatures_test_num < ARRAY_COUNT(first_sector_different_signatures_sig_values); first_sector_different_signatures_test_num++)
4028     {
4029 
4030         disconnect_host_and_slave();
4031         ux_test_set_main_action_list_from_array(actions);
4032         connect_host_and_slave();
4033 
4034         if ((first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][5] == UX_SUCCESS &&   global_media->fx_media_id != FX_MEDIA_ID) ||
4035             (first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][5] == UX_ERROR &&     global_media->fx_media_id == FX_MEDIA_ID))
4036         {
4037 
4038             printf("Error on line %d\n", __LINE__);
4039             test_control_return(1);
4040         }
4041 
4042         if (first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][5] == UX_SUCCESS)
4043             basic_test(global_media, 1, "    basic test\n");
4044     }
4045 }
4046 
4047 /* General disconnection test resources. */
4048 
disconnection_tests_transfer_action_func(UX_TEST_ACTION * action,VOID * parameter)4049 static VOID disconnection_tests_transfer_action_func(UX_TEST_ACTION *action, VOID *parameter)
4050 {
4051 
4052     disconnect_host_and_slave();
4053 }
4054 
disconnection_tests_transfer_with_relinquish_action_func(UX_TEST_ACTION * action,VOID * parameter)4055 static VOID disconnection_tests_transfer_with_relinquish_action_func(UX_TEST_ACTION *action, VOID *parameter)
4056 {
4057 
4058     ux_test_hcd_sim_host_disconnect_no_wait();
4059 
4060     /* Simulate time slice running out. */
4061     tx_thread_relinquish();
4062 }
4063 
4064 /* Storage class related device disconnect test resources. */
4065 
4066 static TX_SEMAPHORE transfer_initiated_semaphore;
4067 
device_disconnect_test_action_func(UX_TEST_ACTION * action,VOID * _params)4068 static VOID device_disconnect_test_action_func(UX_TEST_ACTION *action, VOID *_params)
4069 {
4070 
4071 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
4072 UINT                                status;
4073 
4074 
4075     /* Tell test thread to start disconnection. */
4076     status = ux_utility_semaphore_put(&transfer_initiated_semaphore);
4077     if (status != UX_SUCCESS)
4078     {
4079 
4080         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
4081         test_control_return(1);
4082     }
4083 }
4084 
4085 /* system_host_change_function_test resources */
4086 
system_host_change_function_test()4087 static void system_host_change_function_test()
4088 {
4089 
4090     stepinfo("system_host_change_function_test\n");
4091 
4092     disconnect_host_and_slave();
4093 
4094     /* Set change function to null. */
4095     _ux_system_host -> ux_system_host_change_function = UX_NULL;
4096 
4097     connect_host_and_slave();
4098 
4099     /* Since there's no change function registered, our instance should remain null. */
4100     if (global_storage_change_function != UX_NULL)
4101     {
4102 
4103         printf("Error on line %d, %p\n", __LINE__, global_storage_change_function);
4104         test_control_return(1);
4105     }
4106 
4107     /* Disconnect with null change function. */
4108     disconnect_host_and_slave();
4109 
4110     /* Restore change function. */
4111     _ux_system_host -> ux_system_host_change_function = ux_test_system_host_change_function;
4112 
4113     stepinfo("    connecting...\n");
4114 
4115     /* Connect with non-null change function. */
4116     connect_host_and_slave();
4117 
4118     /* Since our change function was restored, our storage function should've been invoked. */
4119     if (global_storage_change_function == UX_NULL)
4120     {
4121 
4122         printf("Error on line %d, %p\n", __LINE__, global_storage_change_function);
4123         test_control_return(1);
4124     }
4125 }
4126 
direct_calls_test()4127 static void direct_calls_test()
4128 {
4129 
4130 FX_MEDIA                        media;
4131 UX_TEST_ERROR_CALLBACK_ERROR    error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN };
4132 UX_TEST_ACTION                  actions[] = {
4133     create_error_match_action_from_error(error),
4134     { 0 }
4135 };
4136 
4137 
4138     stepinfo("direct calls test\n");
4139 
4140     /* These cases have no way of being triggered via normal circumstances, and therefore direct calls are required. An
4141        explanation should be provided with each.  */
4142 
4143     /* The FileX storage driver handles every request FileX sends to it. */
4144     stepinfo("    ux_host_class_storage_driver_entry unknown command\n");
4145 
4146     media.fx_media_driver_info = global_storage;
4147     media.fx_media_reserved_for_user = (ALIGN_TYPE)global_host_storage_class->ux_host_class_media;
4148 
4149     /* Set to unknown driver request. */
4150     media.fx_media_driver_request = 0xffffffff;
4151 
4152     _ux_host_class_storage_driver_entry(&media);
4153     if (media.fx_media_driver_status == FX_SUCCESS)
4154     {
4155 
4156         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)media.fx_media_driver_status);
4157         test_control_return(1);
4158     }
4159 
4160 #ifdef BUGFIX /* USBX_89 */
4161     /* Make interrupt in search fail by setting it's type to non-interrupt. */
4162     tmp = global_storage->ux_host_class_storage_interface->ux_interface_descriptor.bInterfaceProtocol;
4163     global_storage->ux_host_class_storage_interface->ux_interface_descriptor.bInterfaceProtocol = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI;
4164     global_storage->ux_host_class_storage_interface->ux_interface_first_endpoint->ux_endpoint_next_endpoint->ux_endpoint_next_endpoint->ux_endpoint_descriptor.bmAttributes = 0x00;
4165     ux_test_set_main_action_list_from_array(actions);
4166     status = _ux_host_class_storage_endpoints_get(global_storage);
4167     if (status == UX_SUCCESS)
4168     {
4169 
4170         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)media.fx_media_driver_status);
4171         test_control_return(1);
4172     }
4173     global_storage->ux_host_class_storage_interface->ux_interface_first_endpoint->ux_endpoint_next_endpoint->ux_endpoint_next_endpoint->ux_endpoint_descriptor.bmAttributes = UX_INTERRUPT_ENDPOINT;
4174     global_storage->ux_host_class_storage_interface->ux_interface_descriptor.bInterfaceProtocol = tmp;
4175 
4176     global_storage->ux_host_class_storage_interface->ux_interface_descriptor.bNumEndpoints = original_num_endpoints;
4177 #endif
4178 }
4179 
4180 #define ENDPOINT_TYPE_BULK          0x02
4181 #define ENDPOINT_TYPE_INTERRUPT     0x03
4182 
storage_endpoints_get_test()4183 static void storage_endpoints_get_test()
4184 {
4185 
4186 UINT  endpoint_addresses[] = { 0x81, 0x02 };
4187 UCHAR *first_endpoint_fs, *first_endpoint_hs;
4188 UCHAR *second_endpoint_fs, *second_endpoint_hs;
4189 UCHAR *third_endpoint_fs, *third_endpoint_hs;
4190 UX_TEST_ERROR_CALLBACK_ERROR error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_ENDPOINT_HANDLE_UNKNOWN };
4191 
4192 
4193     stepinfo("_ux_host_class_storage_endpoints_get\n");
4194 
4195     first_endpoint_fs = bulk_in_endpoint_descriptor_fs;
4196     first_endpoint_hs = bulk_in_endpoint_descriptor_hs;
4197     second_endpoint_fs = bulk_out_endpoint_descriptor_fs;
4198     second_endpoint_hs = bulk_out_endpoint_descriptor_hs;
4199     third_endpoint_fs = interrupt_in_endpoint_descriptor_hs;
4200     third_endpoint_hs = interrupt_in_endpoint_descriptor_fs;
4201 
4202     /* None of these should pass enumeration. It's impossible to hit the test cases without breaking everything (device
4203        assumes bulk endpoints are always first, and one of the test cases is that one of the endpoints before a bulk is
4204        non-bulk). */
4205 
4206     /** For bulk out: **/
4207 
4208     /* 1) An endpoint before bulk out must be IN. Set them all to IN. */
4209 
4210     disconnect_host_and_slave();
4211 
4212     first_endpoint_fs[Endpoint_bEndpointAddress] = 0x81;
4213     first_endpoint_hs[Endpoint_bEndpointAddress] = 0x81;
4214 
4215     second_endpoint_fs[Endpoint_bEndpointAddress] = 0x82;
4216     second_endpoint_hs[Endpoint_bEndpointAddress] = 0x82;
4217 
4218     third_endpoint_fs[Endpoint_bEndpointAddress] = 0x83;
4219     third_endpoint_hs[Endpoint_bEndpointAddress] = 0x83;
4220 
4221     /* Ignore error. */
4222     ux_test_add_action_to_main_list(create_error_match_action_from_error(error));
4223 
4224     connect_host_and_slave();
4225 
4226     if (global_media->fx_media_id != 0)
4227     {
4228 
4229         printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id);
4230         test_control_return(1);
4231     }
4232 
4233     /* 2) An endpoint before bulk out must be OUT and non-bulk. Set the first to OUT and non-bulk. The rest must be IN
4234        so it fails. */
4235 
4236     disconnect_host_and_slave();
4237 
4238     first_endpoint_fs[Endpoint_bEndpointAddress] = 0x01;
4239     first_endpoint_hs[Endpoint_bEndpointAddress] = 0x01;
4240     first_endpoint_fs[Endpoint_bmAttributes] = ENDPOINT_TYPE_INTERRUPT;
4241     first_endpoint_hs[Endpoint_bmAttributes] = ENDPOINT_TYPE_INTERRUPT;
4242     first_endpoint_fs[Endpoint_bInterval] = 0x01;
4243     first_endpoint_hs[Endpoint_bInterval] = 0x01;
4244 
4245     second_endpoint_fs[Endpoint_bEndpointAddress] = 0x82;
4246     second_endpoint_hs[Endpoint_bEndpointAddress] = 0x82;
4247 
4248     third_endpoint_fs[Endpoint_bEndpointAddress] = 0x83;
4249     third_endpoint_hs[Endpoint_bEndpointAddress] = 0x83;
4250 
4251     /* This third endpoint is Interrupt, but we must change since if we have multiple Interrupt endpoints, USBX breaks. */
4252     third_endpoint_fs[Endpoint_bmAttributes] = ENDPOINT_TYPE_BULK;
4253     third_endpoint_hs[Endpoint_bmAttributes] = ENDPOINT_TYPE_BULK;
4254 
4255     /* Ignore error. */
4256     ux_test_add_action_to_main_list(create_error_match_action_from_error(error));
4257 
4258     connect_host_and_slave();
4259 
4260     if (global_media->fx_media_id != 0)
4261     {
4262 
4263         printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id);
4264         test_control_return(1);
4265     }
4266 
4267     /** For bulk in (Note: in order to even search for bulk in, bulk out must be valid, so the first should be bulk
4268         out): **/
4269 
4270     /* 1) An endpoint before bulk in must be OUT. Set them all to out so it fails. */
4271 
4272     disconnect_host_and_slave();
4273 
4274     first_endpoint_fs[Endpoint_bEndpointAddress] = 0x01;
4275     first_endpoint_hs[Endpoint_bEndpointAddress] = 0x01;
4276     first_endpoint_fs[Endpoint_bmAttributes] = ENDPOINT_TYPE_BULK;
4277     first_endpoint_hs[Endpoint_bmAttributes] = ENDPOINT_TYPE_BULK;
4278 
4279     second_endpoint_fs[Endpoint_bEndpointAddress] = 0x02;
4280     second_endpoint_hs[Endpoint_bEndpointAddress] = 0x02;
4281 
4282     third_endpoint_fs[Endpoint_bEndpointAddress] = 0x03;
4283     third_endpoint_hs[Endpoint_bEndpointAddress] = 0x03;
4284 
4285     /* Ignore error. */
4286     ux_test_add_action_to_main_list(create_error_match_action_from_error(error));
4287 
4288     connect_host_and_slave();
4289 
4290     if (global_media->fx_media_id != 0)
4291     {
4292 
4293         printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id);
4294         test_control_return(1);
4295     }
4296 
4297     /* 2) An endpoint before bulk in must be IN and non-bulk. Set the second to IN and non-bulk. The rest must be OUT
4298        so it fails. */
4299 
4300     disconnect_host_and_slave();
4301 
4302     second_endpoint_fs[Endpoint_bEndpointAddress] = 0x82;
4303     second_endpoint_hs[Endpoint_bEndpointAddress] = 0x82;
4304     second_endpoint_fs[Endpoint_bmAttributes] = ENDPOINT_TYPE_INTERRUPT;
4305     second_endpoint_hs[Endpoint_bmAttributes] = ENDPOINT_TYPE_INTERRUPT;
4306     second_endpoint_fs[Endpoint_bInterval] = 0x01;
4307     second_endpoint_hs[Endpoint_bInterval] = 0x01;
4308 
4309     third_endpoint_fs[Endpoint_bEndpointAddress] = 0x03;
4310     third_endpoint_hs[Endpoint_bEndpointAddress] = 0x03;
4311 
4312     /* Ignore error. */
4313     ux_test_add_action_to_main_list(create_error_match_action_from_error(error));
4314 
4315     connect_host_and_slave();
4316 
4317     if (global_media->fx_media_id != 0)
4318     {
4319 
4320         printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id);
4321         test_control_return(1);
4322     }
4323 
4324 #ifdef BUGFIX
4325     /** For interrupt in: **/
4326 
4327     /* 1) CBI but no interrupt endpoint */
4328 
4329     disconnect_host_and_slave();
4330 
4331     device_framework_full_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI;
4332     device_framework_high_speed[bInterfaceProtocol_POS] = UX_HOST_CLASS_STORAGE_PROTOCOL_CBI;
4333     device_framework_full_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI;
4334     device_framework_high_speed[bInterfaceSubClass_POS] = UX_HOST_CLASS_STORAGE_SUBCLASS_UFI;
4335 
4336     first_endpoint_fs[Endpoint_bEndpointAddress] = 0x81;
4337     first_endpoint_hs[Endpoint_bEndpointAddress] = 0x81;
4338     first_endpoint_fs[Endpoint_bmAttributes] = 0x02;
4339     first_endpoint_hs[Endpoint_bmAttributes] = 0x02;
4340 
4341     second_endpoint_fs[Endpoint_bEndpointAddress] = 0x01;
4342     second_endpoint_hs[Endpoint_bEndpointAddress] = 0x01;
4343     second_endpoint_fs[Endpoint_bmAttributes] = 0x02;
4344     second_endpoint_hs[Endpoint_bmAttributes] = 0x02;
4345 
4346     third_endpoint_fs[Endpoint_bEndpointAddress] = 0x81;
4347     third_endpoint_hs[Endpoint_bEndpointAddress] = 0x81;
4348     third_endpoint_fs[Endpoint_bmAttributes] = 0x02;
4349     third_endpoint_hs[Endpoint_bmAttributes] = 0x02;
4350 
4351     connect_host_and_slave();
4352 
4353     if (global_media->fx_media_id != 0)
4354     {
4355 
4356         printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id);
4357         test_control_return(1);
4358     }
4359 #endif
4360 
4361     /* reset_to_bo() resets the endpoint addresses, so we don't have to. */
4362 }
4363 
4364 #undef ENDPOINT_TYPE_BULK
4365 #undef ENDPOINT_TYPE_INTERRUPT
4366 
4367 /* max_lun_get_test resources */
4368 
max_lun_get_test_action_func(UX_TEST_ACTION * action,VOID * _params)4369 static VOID max_lun_get_test_action_func(UX_TEST_ACTION *action, VOID *_params)
4370 {
4371 
4372 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
4373 UX_TRANSFER                         *transfer = params->parameter;
4374 
4375 
4376     /* Host expects a length of 1. Set it to not 1. */
4377     transfer->ux_transfer_request_actual_length = 0xdeadbeef;
4378 }
4379 
max_lun_get_test()4380 static void max_lun_get_test()
4381 {
4382 
4383 UX_TEST_SETUP     setup = { 0 };
4384 UX_TEST_ACTION    actions[2] = { 0 };
4385 
4386 
4387     /* We still expect USBX to mount the LUN because 1) max_lun_get always returns UX_SUCCESS 2) when it fails, the
4388        storage instance's max_lun count is 0 which means 1 LUN, so USBX continues as normal.
4389        Also, the real world example of when this would happen is the device not being ready yet, so it stalls the
4390        endpoint. */
4391 
4392     stepinfo("max_lun_get_test\n");
4393 
4394     stepinfo("    transfer_request fails\n");
4395 
4396     disconnect_host_and_slave();
4397 
4398     setup.ux_test_setup_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
4399     setup.ux_test_setup_request = UX_HOST_CLASS_STORAGE_GET_MAX_LUN;
4400 
4401     actions[0].usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
4402     actions[0].function = UX_HCD_TRANSFER_REQUEST;
4403     actions[0].req_setup = &setup;
4404     actions[0].req_action = UX_TEST_SETUP_MATCH_REQUEST;
4405     actions[0].no_return = 0;
4406     actions[0].status = UX_ERROR;
4407 
4408     ux_test_set_main_action_list_from_array(actions);
4409 
4410     connect_host_and_slave();
4411 
4412     if (global_media->fx_media_id == 0)
4413     {
4414 
4415         printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id);
4416         test_control_return(1);
4417     }
4418 
4419     stepinfo("    invalid actual length\n");
4420 
4421     disconnect_host_and_slave();
4422 
4423     setup.ux_test_setup_type = UX_REQUEST_IN | UX_REQUEST_TYPE_CLASS | UX_REQUEST_TARGET_INTERFACE;
4424     setup.ux_test_setup_request = UX_HOST_CLASS_STORAGE_GET_MAX_LUN;
4425 
4426     actions[0].usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
4427     actions[0].function = UX_HCD_TRANSFER_REQUEST;
4428     actions[0].req_setup = &setup;
4429     actions[0].req_action = UX_TEST_SETUP_MATCH_REQUEST;
4430     actions[0].no_return = 0;
4431     actions[0].action_func = max_lun_get_test_action_func;
4432     actions[0].status = UX_SUCCESS;
4433 
4434     ux_test_set_main_action_list_from_array(actions);
4435 
4436     connect_host_and_slave();
4437 
4438     if (global_media->fx_media_id == 0)
4439     {
4440 
4441         printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id);
4442         test_control_return(1);
4443     }
4444 }
4445 
4446 /* media_capacity_get_test resources */
4447 
media_capacity_get_test()4448 static void media_capacity_get_test()
4449 {
4450 
4451 UINT                            i;
4452 UX_TEST_ERROR_CALLBACK_ERROR    error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_HCD, UX_TRANSFER_STALLED };
4453 ULONG                           test_sector_size = 2*UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT;
4454 UX_TEST_ACTION                  actions[2] = { 0 };
4455 
4456 
4457     stepinfo("media_capacity_get_test\n");
4458 
4459     /* How: We do this by overriding the device's media_status function to return an error. Also, this assumes that
4460        media_capacity_get is the first BO transfer to the device. */
4461     stepinfo("    transport succeeds, error sense code, fails 10 times\n");
4462 
4463     disconnect_host_and_slave();
4464     for (i = 0; i < UX_HOST_CLASS_STORAGE_REQUEST_SENSE_RETRY; i++)
4465     {
4466         ux_test_add_action_to_main_list(create_data_match_action(global_enum_thread, global_cbw_data_media_capacity_get_sbc, sizeof(global_cbw_data_media_capacity_get_sbc)));
4467         ux_test_add_action_to_main_list(create_device_media_status_fail_action());
4468         ux_test_add_action_to_main_list(create_error_match_action_from_error(global_transfer_stall_error));
4469     }
4470     connect_host_and_slave();
4471 
4472     if (ux_test_check_actions_empty() == UX_FALSE)
4473     {
4474 
4475         printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id);
4476         test_control_return(1);
4477     }
4478 
4479     stepinfo("    non-default sector size\n");
4480 
4481     disconnect_host_and_slave();
4482 
4483     /* Change the sector size. */
4484     global_sector_size = test_sector_size;
4485 
4486     /* USBX has a default sector size, therefore in order to test this, we change the sector size to the non-default. */
4487     global_persistent_slave_storage -> ux_slave_class_storage_lun[0].ux_slave_class_storage_media_block_length = test_sector_size;
4488 
4489     connect_host_and_slave();
4490 
4491     /* Ensure media_capacity_get() received the correctomundo sector size. */
4492     if (global_storage -> ux_host_class_storage_sector_size != test_sector_size)
4493     {
4494 
4495         printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_storage -> ux_host_class_storage_sector_size);
4496         test_control_return(1);
4497     }
4498 
4499     basic_test(global_media, 1, "        basic_test\n");
4500 
4501     /* Set the sector size back to normal. */
4502     reset_to_bo();
4503 
4504     stepinfo("    transport fails\n");
4505 
4506     disconnect_host_and_slave();
4507 
4508     UX_TEST_ACTION media_capacity_get_cbw_disconnect_actions[] = {
4509         create_disconnect_on_transfer_data_match_action(global_enum_thread, global_cbw_data_media_capacity_get_sbc, sizeof(global_cbw_data_media_capacity_get_sbc)),
4510         create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT),
4511         { 0 }
4512     };
4513     ux_test_set_main_action_list_from_array(media_capacity_get_cbw_disconnect_actions);
4514     UX_TEST_ASSERT(connect_host_and_slave() != UX_SUCCESS);
4515 }
4516 
4517 /* media_characteristics_get_test resources */
4518 
media_characteristics_get_test()4519 static void media_characteristics_get_test()
4520 {
4521 
4522     stepinfo("media_characteristics_get_test\n");
4523 
4524     stepinfo("    correct characteristics received\n");
4525 
4526     disconnect_host_and_slave();
4527     global_persistent_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_removable_flag = 0x00;
4528     connect_host_and_slave();
4529 
4530     if (global_storage->ux_host_class_storage_lun_removable_media_flags[0] != 0x00)
4531     {
4532 
4533         printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id);
4534         test_control_return(1);
4535     }
4536 
4537     basic_test(global_media, 1, "    basic test\n");
4538 
4539     /* Reset removable flag. */
4540     reset_to_bo();
4541 
4542     stepinfo("    fail on transfer\n");
4543 
4544     disconnect_host_and_slave();
4545     UX_TEST_ACTION media_characteristics_get_disconnect_actions[] = {
4546         create_disconnect_on_transfer_data_match_action(global_enum_thread, global_cbw_data_media_characteristics_get_sbc, sizeof(global_cbw_data_media_characteristics_get_sbc)),
4547         create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT),
4548         { 0 }
4549     };
4550     ux_test_set_main_action_list_from_array(media_characteristics_get_disconnect_actions);;
4551     UX_TEST_ASSERT(connect_host_and_slave() != UX_SUCCESS);
4552 }
4553 
4554 /* ux_test_host_class_storage_media_read_test resources */
4555 
uhcsmrt_action_func(UX_TEST_ACTION * action,VOID * _params)4556 static void uhcsmrt_action_func(UX_TEST_ACTION *action, VOID *_params)
4557 {
4558 
4559 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
4560 UX_TRANSFER                         *transfer = params->parameter;
4561 
4562 
4563     /* Make it NOT correct. */
4564     global_storage -> ux_host_class_storage_data_phase_length = ~(global_storage -> ux_host_class_storage_data_phase_length);
4565 }
4566 
4567 /* ux_host_class_storage_request_sense_test resources */
4568 
ux_host_class_storage_request_sense_test()4569 static void ux_host_class_storage_request_sense_test()
4570 {
4571 
4572 UINT                         status;
4573 UX_TEST_ACTION     actions[3] = { 0 };
4574 
4575 
4576     stepinfo("ux_host_class_storage_request_sense_test\n");
4577 
4578     /* We accomplish this by forcing a REQUEST_SENSE command to fail via error in CSW. */
4579     stepinfo("    recursive REQUEST_SENSE command\n");
4580 
4581     lock_out_storage_thread();
4582 
4583     /* In order to get USBX to send the REQUEST_SENSE comand, a CSW must contain an error. Therefore, we need to error
4584        CSWs. */
4585     actions[0] = create_csw_error_action(tx_thread_identify(), UX_HOST_CLASS_STORAGE_CSW_FAILED);
4586     actions[1] = create_csw_error_action(tx_thread_identify(), UX_HOST_CLASS_STORAGE_CSW_FAILED);
4587     ux_test_set_main_action_list_from_array(actions);
4588 
4589     /* This should fail because the transport itself fails, not just the CSW. */
4590     status = ux_test_host_class_storage_media_read(global_storage, 10, 1, global_buffer);
4591     if (status == UX_SUCCESS)
4592     {
4593 
4594         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
4595         test_control_return(1);
4596     }
4597 
4598     lock_in_storage_thread();
4599 }
4600 
4601 /* ux_host_class_storage_start_stop_test resources */
4602 
uhcsst_action_func(UX_TEST_ACTION * action,VOID * _params)4603 static void uhcsst_action_func(UX_TEST_ACTION *action, VOID *_params)
4604 {
4605 
4606 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
4607 UX_TRANSFER                         *transfer = params->parameter;
4608 UX_HOST_CLASS_STORAGE               *storage = get_internal_host_storage_instance();
4609 
4610 
4611     storage->ux_host_class_storage_sense_code = 0xff;
4612 }
4613 
ux_host_class_storage_start_stop_test()4614 static void ux_host_class_storage_start_stop_test()
4615 {
4616 
4617 UCHAR                       cbw_data_start_stop[] = { 0x55, 0x53, 0x42, 0x43, 0x43, 0x42, 0x53, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
4618 UX_TEST_ACTION              actions[51] = { 0 };
4619 UINT                        i;
4620 
4621 
4622     /* The host sends the START_STOP command only to UFI devices during enumeration. */
4623     stepinfo("ux_host_class_storage_start_stop_test\n");
4624 
4625     /* We do this by detecting the CBW and setting to sense code to error. */
4626     stepinfo("    50 retries fail test\n");
4627 
4628     disconnect_host_and_slave();
4629 
4630     /* Set this to UFI. */
4631     switch_to_protocol(UX_HOST_CLASS_STORAGE_PROTOCOL_CBI);
4632 
4633     /* Match CBW and set the sense code to error. */
4634     actions[0].usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
4635     actions[0].function = UX_HCD_TRANSFER_REQUEST;
4636     actions[0].req_data = cbw_data_start_stop;
4637     actions[0].req_actual_len = sizeof(cbw_data_start_stop);
4638     actions[0].action_func = uhcsst_action_func;
4639     actions[0].no_return = 1;
4640 
4641     /* Host will try to send a REQUEST_SENSE command to device. Make sure it contains an error. */
4642     for (i = 1; i < (ARRAY_COUNT(actions) - 1); i++)
4643     {
4644         actions[i] = actions[0];
4645     }
4646 
4647     ux_test_set_main_action_list_from_array(actions);
4648 
4649     connect_host_and_slave();
4650 
4651     if (global_media->fx_media_id != 0)
4652     {
4653 
4654         printf("Error on line %d\n", __LINE__);
4655         test_control_return(1);
4656     }
4657 }
4658 
4659 /* ux_host_class_storage_transport_test resources */
4660 
4661 /* This tests transport, transport_bo, transport_cb, and transport_cbi. */
ux_host_class_storage_transport_test()4662 static void ux_host_class_storage_transport_test()
4663 {
4664 
4665 UX_TEST_ERROR_CALLBACK_ERROR    transfer_timeout_error = { UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT };
4666 
4667 
4668     stepinfo("ux_host_class_storage_transport_test\n");
4669 
4670     stepinfo("    CSW 2 timeouts\n");
4671 
4672     DEVICE_MEDIA_READ_WRITE_TIMEOUT_DATA timeout_data;
4673     timeout_data.transfer_request = &global_storage->ux_host_class_storage_bulk_in_endpoint->ux_endpoint_transfer_request;
4674     timeout_data.num_timeouts = 2;
4675 
4676     UX_TEST_ACTION csw_multiple_retries_fails[] = {
4677         create_device_media_write_block_action(&timeout_data),
4678         { 0 }
4679     };
4680     ux_test_set_main_action_list_from_array(csw_multiple_retries_fails);
4681 
4682     lock_out_storage_thread();
4683     UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, 1, global_buffer));
4684     receive_device_csw();
4685     lock_in_storage_thread();
4686     basic_test(global_media, 1, "        basic test\n");
4687 
4688     stepinfo("    CBW transfer fail\n");
4689 
4690     /* Set action for making CBW transfer fail. */
4691     UX_TEST_ACTION cbw_disconnect_actions[] = {
4692         create_cbw_disconnect_action(tx_thread_identify()),
4693         { 0 }
4694     };
4695     ux_test_set_main_action_list_from_array(cbw_disconnect_actions);
4696 
4697     lock_out_storage_thread();
4698     UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 0, 1, global_buffer));
4699     lock_in_storage_thread();
4700     connect_host_and_slave();
4701 
4702 #if 0 /* USBX_54 */
4703     stepinfo("    CBW stalls\n");
4704 
4705     actions[0] = create_cbw_stall_action(tx_thread_identify());
4706     ux_test_set_actions(actions);
4707 
4708     /* Do anything that triggers a CBW. */
4709     status = ux_test_media_write(global_storage, 0, 1, global_buffer, 0, UX_FALSE);
4710     if (status == UX_SUCCESS)
4711     {
4712 
4713         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
4714         test_control_return(1);
4715     }
4716 #endif
4717 
4718     /* Note: the device never sends a PHASE ERROR, since it's optional. Therefore, we do the next best thing. */
4719     stepinfo("    CSW status is Phase Error\n");
4720 
4721     /* Set action for making CSW contain Phase Error. */
4722     UX_TEST_ACTION csw_phase_error[] = {
4723         create_csw_error_action(tx_thread_identify(), UX_HOST_CLASS_STORAGE_CSW_PHASE_ERROR),
4724         create_endpoint_reset_match_action(tx_thread_identify(), &global_setup_endpoint_reset_out2),
4725         { 0 }
4726     };
4727     ux_test_set_main_action_list_from_array(csw_phase_error);
4728 
4729     lock_out_storage_thread();
4730     UX_TEST_CHECK_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, 1, global_buffer));
4731     lock_in_storage_thread();
4732     UX_TEST_ASSERT(ux_test_check_actions_empty());
4733 
4734     stepinfo("    CSW transfer fail\n");
4735 
4736     /* Set action for making CSW transfer fail. */
4737     UX_TEST_ACTION csw_disconnect_actions[] = {
4738         create_csw_disconnect_action(tx_thread_identify()),
4739         { 0 }
4740     };
4741     ux_test_set_main_action_list_from_array(csw_disconnect_actions);
4742 
4743     lock_out_storage_thread();
4744     UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, 1, global_buffer));
4745     lock_in_storage_thread();
4746     connect_host_and_slave();
4747 
4748     stepinfo("    CSW semaphore_get() fails due to disconnect\n");
4749 
4750     UX_TEST_ACTION csw_semaphore_get_disconnect_actions[] = {
4751         create_csw_match_action(tx_thread_identify()),
4752         create_semaphore_get_disconnect_action(tx_thread_identify(), &global_storage->ux_host_class_storage_bulk_in_endpoint->ux_endpoint_transfer_request.ux_transfer_request_semaphore, UX_HOST_CLASS_STORAGE_TRANSFER_TIMEOUT),
4753         { 0 }
4754     };
4755     ux_test_set_main_action_list_from_array(csw_semaphore_get_disconnect_actions);
4756 
4757     lock_out_storage_thread();
4758     UX_TEST_CHECK_NOT_SUCCESS(ux_test_host_class_storage_media_write(global_storage, 10, 1, global_buffer));
4759     lock_in_storage_thread();
4760     connect_host_and_slave();
4761 }
4762 
4763 /* thirteen_cases_test resources
4764    These tests ensure the host acts conformant to the USB MSC BO spec regarding the thirteen cases specified in section
4765    6.7. */
4766 
create_match_unit_test_ready_cbw(TX_THREAD * thread)4767 static UX_TEST_ACTION create_match_unit_test_ready_cbw(TX_THREAD *thread)
4768 {
4769 
4770 UX_TEST_ACTION  action = {0};
4771 
4772 
4773     /* Action for matching CBW of unit ready test. */
4774     action.usbx_function = UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY;
4775     action.function = UX_HCD_TRANSFER_REQUEST;
4776     action.req_data = global_cbw_data_unit_ready_test_sbc;
4777     action.req_actual_len = sizeof(global_cbw_data_unit_ready_test_sbc);
4778     action.no_return = 1;
4779     action.thread_to_match = thread;
4780 
4781     return action;
4782 }
4783 
4784 static UINT tcht_media_read_test_error_action_func_calls;
tcht_media_read_test_error_action_func(VOID * storage,ULONG lun,UCHAR * data_pointer,ULONG number_blocks,ULONG lba,ULONG * media_status)4785 static UINT tcht_media_read_test_error_action_func(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status)
4786 {
4787 
4788     if (!tcht_media_read_test_error_action_func_calls++)
4789     {
4790 
4791         *media_status = (ULONG)-1;
4792         return UX_ERROR;
4793     }
4794     else
4795         return default_device_media_read(storage, lun, data_pointer, number_blocks, lba, media_status);
4796 }
4797 
4798 static UINT tcht_media_write_test_error_action_func_calls;
tcht_media_write_test_error_action_func(VOID * storage,ULONG lun,UCHAR * data_pointer,ULONG number_blocks,ULONG lba,ULONG * media_status)4799 static UINT tcht_media_write_test_error_action_func(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status)
4800 {
4801 
4802     if (!tcht_media_write_test_error_action_func_calls++)
4803     {
4804 
4805         *media_status = (ULONG)-1;
4806         return UX_ERROR;
4807     }
4808     else
4809         return default_device_media_write(storage, lun, data_pointer, number_blocks, lba, media_status);
4810 }
4811 
stall_while_receiving_csw_test()4812 static void stall_while_receiving_csw_test()
4813 {
4814 
4815     /* Case: On a STALL condition receiving the CSW, then:
4816         -The host shall clear the Bulk-In pipe.
4817         -The host shall attempt to receive the CSW again.
4818 
4819         We "hardcode" it because there's no reason AFAIK to trigger this case. */
4820     stepinfo("stall_while_receiving_csw_test\n");
4821 
4822     UX_TEST_ACTION actions[] = {
4823         /* Action for matching CBW of unit ready test. */
4824         create_cbw_match_action(tx_thread_identify()),
4825         /* Force the CSW to stall. */
4826         create_csw_stall_action(tx_thread_identify()), /* Not actually stalled on device side.  */
4827         /* Match bulk-in endpoint reset. */
4828         create_endpoint_reset_match_action(tx_thread_identify(), &global_setup_endpoint_reset_in1),
4829         /* Match CSW. */
4830         create_csw_match_action(tx_thread_identify()),
4831         { 0 }
4832     };
4833 
4834     lock_out_storage_thread();
4835 
4836     ux_test_set_expedient(UX_TRUE);
4837     ux_test_set_main_action_list_from_array(actions);
4838     UX_TEST_CHECK_SUCCESS(ux_test_host_class_storage_media_read(global_storage, 10, sizeof(global_buffer_2x_slave_buffer_size)/UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT, global_buffer_2x_slave_buffer_size));
4839     ux_test_set_expedient(UX_FALSE);
4840 
4841     lock_in_storage_thread();
4842 
4843     /* Ensure we "attempt to receive the CSW again" and "clear the Bulk-In pipe" */
4844     if (ux_test_check_actions_empty() != UX_TRUE)
4845     {
4846 
4847         printf("Error on line %d\n", __LINE__);
4848         test_control_return(1);
4849     }
4850 }
4851 
csw_contains_phase_error_test()4852 static void csw_contains_phase_error_test()
4853 {
4854 
4855     stepinfo("csw_contains_phase_error_test\n");
4856 
4857     lock_out_storage_thread();
4858 
4859     UX_TEST_ACTION actions[] = {
4860         create_cbw_match_action(tx_thread_identify()),
4861         create_csw_error_action(tx_thread_identify(), UX_HOST_CLASS_STORAGE_CSW_PHASE_ERROR),
4862         create_mass_storage_reset_match_action(tx_thread_identify()),
4863         create_request_sense_error_action(tx_thread_identify(), 0xff),
4864         { 0 }
4865     };
4866     ux_test_set_main_action_list_from_array(actions);
4867 
4868     UX_TEST_CHECK_SUCCESS(ux_test_host_class_storage_media_read(global_storage, 10, sizeof(global_buffer_2x_slave_buffer_size)/UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT, global_buffer_2x_slave_buffer_size));
4869 
4870     lock_in_storage_thread();
4871 
4872     /* Ensure we "attempt to receive the CSW again" and "clear the Bulk-In pipe" */
4873     UX_TEST_ASSERT(ux_test_check_actions_empty());
4874 }
4875 
thirteen_cases_4_5_test_host()4876 static void thirteen_cases_4_5_test_host()
4877 {
4878 
4879 UINT              status;
4880 UX_TEST_ACTION    actions[] = {
4881     create_device_media_read_fail_action(),
4882     create_error_match_action_from_error(ux_error_hcd_transfer_stalled),
4883     create_endpoint_reset_match_action(tx_thread_identify(), &global_setup_endpoint_reset_in1),
4884     { 0 }
4885 };
4886 
4887 
4888     /* For case 4 and 5, the device should stall during data stage. This is what
4889        we do during this test. */
4890     stepinfo("thirteen_cases_4_5_test_host\n");
4891 
4892     lock_out_storage_thread();
4893 
4894     ux_test_set_main_action_list_from_array(actions);
4895 
4896     /* Make sure it requires multiple transfers (large data size). */
4897     status = ux_test_host_class_storage_media_read(global_storage, 10, sizeof(global_buffer_2x_slave_buffer_size)/UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT, global_buffer_2x_slave_buffer_size);
4898     if (status != UX_SUCCESS)
4899     {
4900 
4901         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
4902         test_control_return(1);
4903     }
4904 
4905     lock_in_storage_thread();
4906 
4907     if (global_media->fx_media_id == 0)
4908     {
4909 
4910         printf("Error on line %d, error code: 0x%lx\n", __LINE__, global_media->fx_media_id);
4911         test_control_return(1);
4912     }
4913 
4914     /* Ensure we "clear the Bulk-In pipe." */
4915     if (ux_test_check_actions_empty() != UX_TRUE)
4916     {
4917 
4918         printf("Error on line %d\n", __LINE__);
4919         test_control_return(1);
4920     }
4921 }
4922 
thirteen_cases_9_11_test_host()4923 static void thirteen_cases_9_11_test_host()
4924 {
4925 
4926 UINT                        status;
4927 UINT                        num_transfers;
4928 /* Note that we use the DEVICE's max buffer size because we need the device to process it (for example, if it's less than
4929    the host's and we use the host's, then it would be the same as only sending one transfer). */
4930 ULONG                       write_sector_counts[] = { UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE/UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT, UX_TEST_MULTIPLE_TRANSFERS_SECTOR_COUNT };
4931 
4932 /* We don't expect any errors since the device doesn't stall until after we've sent all our data, we don't actually
4933    detect the stall. Instead, we see that the CSW contains an error then clear the endpoint. */
4934 UX_TEST_ACTION              one_transfer_actions[] = {
4935     create_device_media_write_fail_action(),
4936     create_endpoint_reset_match_action(tx_thread_identify(), &global_setup_endpoint_reset_out2),
4937     { 0 }
4938 };
4939 
4940 /* This time, we will detect the stall in transport_bo.c. */
4941 UX_TEST_ACTION              two_transfers_actions[] = {
4942     create_device_media_write_fail_action(),
4943     create_error_match_action_from_error(ux_error_hcd_transfer_stalled),
4944     create_endpoint_reset_match_action(tx_thread_identify(), &global_setup_endpoint_reset_out2),
4945     { 0 }
4946 };
4947 
4948     /* For these cases, the device should stall the bulk out during the data
4949        phase. That is what we do during this test.
4950 
4951        We do this test twice for good measuer: one that requires one slave transfer,
4952        and one that requires two slave transfers. */
4953     stepinfo("thirteen_cases_9_11_test_host\n");
4954 
4955     for (num_transfers = 1; num_transfers < 3; num_transfers++)
4956     {
4957 
4958         stepinfo("    num_transfers: %d\n", num_transfers);
4959 
4960         if (num_transfers == 1)
4961         {
4962             ux_test_set_main_action_list_from_array(one_transfer_actions);
4963         }
4964         else if (num_transfers == 2)
4965         {
4966             ux_test_set_main_action_list_from_array(two_transfers_actions);
4967         }
4968 
4969         lock_out_storage_thread();
4970 
4971         /* Make sure it requires multiple transfers (large data size). */
4972         status = ux_test_host_class_storage_media_write(global_storage, 10, write_sector_counts[num_transfers - 1], global_buffer_2x_slave_buffer_size);
4973         if (status != UX_SUCCESS)
4974         {
4975 
4976             printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
4977             test_control_return(1);
4978         }
4979 
4980         /* Ensure we "clear the Bulk-Out pipe." Note that we actually do it twice, once in transport_bo() and once in
4981            transport(). See the note in transport() as to why this is indeed the case. */
4982         if (ux_test_check_actions_empty() != UX_TRUE)
4983         {
4984 
4985             printf("Error on line %d\n", __LINE__);
4986             test_control_return(1);
4987         }
4988 
4989         if (global_storage->ux_host_class_storage_bulk_out_endpoint->ux_endpoint_transfer_request.ux_transfer_request_semaphore.tx_semaphore_count != 0)
4990         {
4991 
4992             printf("Error on line %d\n", __LINE__);
4993             test_control_return(1);
4994         }
4995 
4996         lock_in_storage_thread();
4997     }
4998 }
4999 
5000 /* get_no_device_memory_free_amount resources. */
5001 
get_no_device_free_memory_amount_action_func(UX_TEST_ACTION * action,VOID * _params)5002 static void get_no_device_free_memory_amount_action_func(UX_TEST_ACTION *action, VOID *_params)
5003 {
5004 
5005 UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_OVERRIDE_UX_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
5006 ULONG                                           *no_device_memory_free_amount = (ULONG *)action->user_data;
5007 
5008 
5009     /* Log number of memory allocations right before storage class initialization. */
5010     *no_device_memory_free_amount = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available;
5011 }
5012 
5013 /* device_not_ready_during_enumeration_test resources */
5014 
device_not_ready_during_enumeration_test()5015 static void device_not_ready_during_enumeration_test()
5016 {
5017 
5018     stepinfo("device_not_ready_during_enumeration_test\n");
5019 
5020     disconnect_host_and_slave();
5021 
5022     UX_TEST_ACTION actions[] = {
5023         /* This causes the UNIT READY TEST in _ux_host_class_storage_media_mount to fail. */
5024         create_test_unit_ready_match_action(global_enum_thread),
5025         create_device_media_status_fail_action(),
5026         /* These two causes the UNIT READY TEST to receive the UNIT_ATTENTION sense key, which will mount us! */
5027         create_csw_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_CSW_FAILED),
5028         create_request_sense_error_action(global_storage_thread, UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION),
5029         { 0 }
5030     };
5031     ux_test_set_main_action_list_from_array(actions);
5032 
5033     connect_host_and_slave();
5034 
5035     /* Wait for storage thread to mount us. */
5036     while (!_storage_media_is_mounted())
5037         tx_thread_sleep(10);
5038 
5039     /* We should be successfully mounted. Run a basic test. */
5040     basic_test(global_media, 1, "    basic test\n");
5041 }
5042 
disconnect_during_storage_thread_unmounting_media_test()5043 static void disconnect_during_storage_thread_unmounting_media_test()
5044 {
5045 
5046     stepinfo("disconnect_during_storage_thread_unmounting_media_test\n");
5047 
5048     UX_TEST_ACTION not_ready_actions = { 0 };
5049     add_unit_ready_test_not_ready_actions(&not_ready_actions);
5050     ux_test_add_action_to_user_list(&not_ready_actions, create_disconnect_on_thread_preemption_change(global_storage_thread, global_storage_thread, UX_HOST_CLASS_STORAGE_THREAD_PRIORITY_CLASS));
5051     ux_test_set_main_action_list_from_list(&not_ready_actions);
5052     let_storage_thread_run();
5053 }
5054 
5055 #ifdef UX_TEST_RACE_CONDITION_TESTS_ON
5056 
5057 /* host_stack_simultaneous_control_transfer_test resources */
5058 
hssctt_thread2_entry(ULONG input)5059 static void hssctt_thread2_entry(ULONG input)
5060 {
5061 
5062 UINT            status;
5063 
5064 
5065     /** This is Thread2 **/
5066 
5067     /* ux_host_stack_interface_setting_select() with alternate setting 0. Should override Thread1's transfer. */
5068     status = ux_host_stack_interface_setting_select(global_host_device->ux_device_first_configuration->ux_configuration_first_interface);
5069     if (status != UX_SUCCESS)
5070     {
5071 
5072         printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status);
5073         test_control_return(1);
5074     }
5075 
5076     /* Resume Thread1. */
5077     status = ux_utility_semaphore_put(&global_test_semaphore);
5078     if (status != UX_SUCCESS)
5079     {
5080 
5081         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5082         test_control_return(1);
5083     }
5084 }
5085 
hssctt_action_func(UX_TEST_ACTION * action,VOID * _params)5086 static void hssctt_action_func(UX_TEST_ACTION *action, VOID *_params)
5087 {
5088 
5089 UX_TEST_HCD_SIM_HOST_ENTRY_PARAMS   *params = (UX_TEST_HCD_SIM_HOST_ENTRY_PARAMS *)_params;
5090 UINT                                status;
5091 UX_TEST_WORKER_WORK                 work;
5092 
5093 
5094     work.function = hssctt_thread2_entry;
5095 
5096     /* Remember we are being called from ux_host_stack_interface_set.c */
5097 
5098     /* Run Thread2 */
5099     ux_test_worker_add_work(&work);
5100 
5101     /* Wait for Thread2 to finish. */
5102     status = ux_utility_semaphore_get(&global_test_semaphore, TX_WAIT_FOREVER);
5103     if (status != UX_SUCCESS)
5104     {
5105 
5106         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5107         test_control_return(1);
5108     }
5109 }
5110 
host_stack_simultaneous_control_transfers_cause_override_test()5111 static void host_stack_simultaneous_control_transfers_cause_override_test()
5112 {
5113 
5114 UINT                    status;
5115 UX_INTERFACE            *interface_alternate_setting1;
5116 UX_TRANSFER             *transfer_request;
5117 UCHAR                   buffer;
5118 
5119 
5120     /* Proof of concept for USBX_77 */
5121 
5122     /* Here is a REALISTIC example of what could POSSIBLY happen:
5123 
5124         -Background storage thread does a UNIT_READY_TEST.
5125         -It fails on the device side, so device stalls endpoint.
5126         -Host just sees that it failed and tries to reset the device (via MSC command on _control endpoint)).
5127         -After setting up transfer request but _before_ calling ux_host_stack_transfer_request, storage thread gets
5128          preempted by ThreadA.
5129         -ThreadA decides it's time to select another interface setting or change the configuration (via
5130          _control endpoint_).
5131         -ThreadA _overrides_ storage thread's transfer request.
5132         -Once storage thread runs again, it wlil send the same request as ThreadA.
5133 
5134         Not only that, but the reverse could happen: storage thread overrides ThreadA's transfer!
5135 
5136        See? this test isn't a waste of time! */
5137 
5138     stepinfo("host_stack_simultaneous_control_transfer_test\n");
5139 
5140     UX_TEST_ACTION actions[2] = { 0 };
5141     actions[0]._usbx_function = UX_TEST_HOST_STACK_INTERFACE_SET;
5142     actions[0].bInterfaceNumber = 0;
5143     actions[0].bAlternateSetting = 1;
5144     actions[0].action_func = hssctt_action_func;
5145 
5146     /** This is Thread1. **/
5147 
5148     lock_out_storage_thread();
5149 
5150     /* The device stack calls the class to handle SET_INTERFACE requests. Problem is that device classes don't actually
5151        support it and throw an error. In case this is a bug, I've documented it as BUG_ID_48. */
5152     ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_FUNCTION_NOT_SUPPORTED));
5153 
5154     /* Set action so that right before transfer_request(), we get preempted by Thread2. */
5155     ux_test_set_main_action_list_from_array(actions);
5156 
5157     interface_alternate_setting1 = global_storage->ux_host_class_storage_interface->ux_interface_next_interface;
5158 
5159     /* Call ux_host_stack_interface_setting_select() with alternate setting 1. Should be the interface right after the
5160        current one. */
5161     /* When we resume, our transfer should've been overridden. */
5162     status = ux_host_stack_interface_setting_select(interface_alternate_setting1);
5163     if (status != UX_SUCCESS)
5164     {
5165 
5166         printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status);
5167         test_control_return(1);
5168     }
5169 
5170     /* Get the current alternate setting from the device (there's no API for this, we'll have to send the transfer
5171        manually). */
5172     transfer_request = &global_host_device->ux_device_control_endpoint.ux_endpoint_transfer_request;
5173     transfer_request -> ux_transfer_request_data_pointer =      &buffer;
5174     transfer_request -> ux_transfer_request_requested_length =  1;
5175     transfer_request -> ux_transfer_request_function =          UX_GET_INTERFACE;
5176     transfer_request -> ux_transfer_request_type =              UX_REQUEST_IN | UX_REQUEST_TYPE_STANDARD | UX_REQUEST_TARGET_INTERFACE;
5177     transfer_request -> ux_transfer_request_index =             0;
5178     status = ux_host_stack_transfer_request(transfer_request);
5179     if (status != UX_SUCCESS)
5180     {
5181 
5182         printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status);
5183         test_control_return(1);
5184     }
5185 
5186     if (buffer != 1)
5187     {
5188 
5189         printf("Error on line %d, error code: 0x%lx\n",__LINE__,(ULONG)status);
5190         test_control_return(1);
5191     }
5192 
5193     lock_in_storage_thread();
5194 }
5195 
5196 /* host_stack_simultaneous_control_transfers_cause_extra_sem_count_test resources */
5197 
hssctcesmt_do_configuration_reset_function(ULONG input)5198 static void hssctcesmt_do_configuration_reset_function(ULONG input)
5199 {
5200 
5201 UINT status;
5202 
5203 
5204     /* We just need to do A control transfer, doesn't matter which one. */
5205     status = ux_host_stack_device_configuration_reset(global_host_device);
5206     if (status != UX_SUCCESS)
5207     {
5208 
5209         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5210         test_control_return(1);
5211     }
5212 }
5213 
hssctcesmt_reactivate_hcd_timer(ULONG input)5214 static void hssctcesmt_reactivate_hcd_timer(ULONG input)
5215 {
5216 
5217 UINT            status;
5218 UX_HCD_SIM_HOST *hcd_sim_host = global_hcd -> ux_hcd_controller_hardware;
5219 
5220 
5221     /* Reactivate HCD timer. */
5222     status = tx_timer_activate(&hcd_sim_host -> ux_hcd_sim_host_timer);
5223     if (status != TX_SUCCESS)
5224     {
5225 
5226         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5227         test_control_return(1);
5228     }
5229 }
5230 
host_stack_simultaneous_control_transfers_cause_extra_sem_count_test()5231 static void host_stack_simultaneous_control_transfers_cause_extra_sem_count_test()
5232 {
5233 
5234 UINT                        status;
5235 UX_TEST_WORKER_WORK         work_transfer = { 0 };
5236 UX_HCD_SIM_HOST             *hcd_sim_host = global_hcd -> ux_hcd_controller_hardware;
5237 
5238 
5239     /* Proof of concept for USBX_78. */
5240 
5241     stepinfo("    simulataneous control transfers test\n");
5242 
5243     work_transfer.function = hssctcesmt_do_configuration_reset_function;
5244 
5245     /* Deactivate HCD timer. No transfers are processed during this time. */
5246     status = tx_timer_deactivate(&hcd_sim_host -> ux_hcd_sim_host_timer);
5247     if (status != TX_SUCCESS)
5248     {
5249 
5250         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5251         test_control_return(1);
5252     }
5253 
5254     /* Start our timer. */
5255     status = tx_timer_create(&global_timer, "timer", hssctcesmt_reactivate_hcd_timer, 0, 100, 0, TX_AUTO_ACTIVATE);
5256     if (status != TX_SUCCESS)
5257     {
5258 
5259         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5260         test_control_return(1);
5261     }
5262 
5263     /* Place work for doing transfer at the same we are in worker thread. */
5264     ux_test_worker_add_work(&work_transfer);
5265 
5266     /* Do our control transfer (remember that this is blocking). */
5267     hssctcesmt_do_configuration_reset_function(0);
5268 
5269     /* Our timer should reactivate HCD timer. */
5270 
5271     /* If there are no bugs, the device protection semaphore's count is 1 (but with bugs, it should be 2). */
5272     if (global_host_device->ux_device_protection_semaphore.tx_semaphore_count != 1)
5273     {
5274 
5275         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5276         test_control_return(1);
5277     }
5278 
5279     status = tx_timer_delete(&global_timer);
5280     if (status != TX_SUCCESS)
5281     {
5282 
5283         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5284         test_control_return(1);
5285     }
5286 }
5287 #endif
5288 
5289 /* synchronize_cache_test resources. */
5290 
5291 /* Opcodes.  */
5292 #define UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE 0x35
5293 
5294 /* Define Storage Class read format command constants.  */
5295 #define UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_OPERATION                       0
5296 #define UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS                           1
5297 #define UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_LBA                             2
5298 
5299 #define UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_NUMBER_OF_BLOCKS                7
5300 #define UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_COMMAND_LENGTH_SBC              10
5301 
5302 #define UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS_IMMED                     0x02
5303 
synchronize_cache_test()5304 static void synchronize_cache_test()
5305 {
5306 
5307 UCHAR   *cbw;
5308 UINT    number_of_blocks;
5309 UINT    i;
5310 
5311 
5312     stepinfo("synchronize cache test\n");
5313 
5314     /* For this test, the device will reply with an error in the CSW. This will
5315        cause us to send a REQUEST SENSE. We ensure the REQUEST SENSE is valid.  */
5316     stepinfo("    synchronize cache test - callback NULL\n");
5317 
5318     /* Set callback to NULL.  */
5319     global_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = 0;
5320 
5321     number_of_blocks = 0xffff;
5322 
5323     /* Initialize the CBW for this command.  */
5324     _ux_host_class_storage_cbw_initialize(global_storage, 0, 0, UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_COMMAND_LENGTH_SBC);
5325 
5326     /* Prepare the SYNCHRONIZE CACHE command block.  */
5327     cbw =  (UCHAR *) global_storage -> ux_host_class_storage_cbw;
5328     *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_OPERATION) =  UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE;
5329     _ux_utility_long_put_big_endian((cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_LBA), 0);
5330     _ux_utility_short_put_big_endian((cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_NUMBER_OF_BLOCKS), number_of_blocks);
5331 
5332     UX_TEST_CHECK_SUCCESS(_ux_host_class_storage_transport(global_storage, UX_NULL));
5333     UX_TEST_ASSERT(global_storage->ux_host_class_storage_cbw[UX_HOST_CLASS_STORAGE_CSW_STATUS] == UX_SUCCESS);
5334     UX_TEST_ASSERT(ux_test_check_actions_empty());
5335 
5336     /* Restore callback.  */
5337     global_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_flush = default_device_media_flush;
5338 
5339     stepinfo("    synchronize cache test - different LBAs and number of blocks\n");
5340 
5341     /* Try with different blocks and LBAs. */
5342     UINT lbas[] = {0, 1, 2, 3, 4, 5};
5343     USHORT number_blocks[] = {0xffff, 10, 9, 8, 7, 6};
5344     for (i = 0; i < ARRAY_COUNT(lbas); i++)
5345     {
5346 
5347         stepinfo("        synchronize cache test - different LBAs and number of blocks - %d\n", i);
5348 
5349         /* Initialize the CBW for this command.  */
5350         _ux_host_class_storage_cbw_initialize(global_storage, 0, 0, UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_COMMAND_LENGTH_SBC);
5351 
5352         /* Prepare the SYNCHRONIZE CACHE command block.  */
5353         cbw =  (UCHAR *) global_storage -> ux_host_class_storage_cbw;
5354         *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_OPERATION) =  UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE;
5355         _ux_utility_long_put_big_endian((cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_LBA), lbas[i]);
5356         _ux_utility_short_put_big_endian((cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_NUMBER_OF_BLOCKS), number_blocks[i]);
5357 
5358         /* Action for matching media flush to make sure device receives it. */
5359         UX_TEST_ACTION action = { 0 };
5360         action.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_FLUSH;
5361         action.lun = 0;
5362         action.lba = lbas[i];
5363         action.number_blocks = number_blocks[i];
5364         ux_test_add_action_to_main_list(action);
5365 
5366         UX_TEST_CHECK_SUCCESS(_ux_host_class_storage_transport(global_storage, UX_NULL));
5367         UX_TEST_ASSERT(global_storage->ux_host_class_storage_cbw[UX_HOST_CLASS_STORAGE_CSW_STATUS] == UX_SUCCESS);
5368         UX_TEST_ASSERT(ux_test_check_actions_empty());
5369     }
5370 
5371     stepinfo("    synchronize cache test - immediate bit set\n");
5372 
5373     number_of_blocks = 0xffff;
5374 
5375     /* Initialize the CBW for this command.  */
5376     _ux_host_class_storage_cbw_initialize(global_storage, 0, 0, UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_COMMAND_LENGTH_SBC);
5377 
5378     /* Prepare the SYNCHRONIZE CACHE command block.  */
5379     cbw =  (UCHAR *) global_storage -> ux_host_class_storage_cbw;
5380     *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_OPERATION) =  UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE;
5381     _ux_utility_long_put_big_endian((cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_LBA), 0);
5382     *(cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS) |=  UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_FLAGS_IMMED;
5383     _ux_utility_short_put_big_endian((cbw + UX_HOST_CLASS_STORAGE_CBW_CB + UX_HOST_CLASS_STORAGE_SYNCHRONIZE_CACHE_NUMBER_OF_BLOCKS), number_of_blocks);
5384 
5385     /* Action for matching media flush to make sure device receives it. */
5386     UX_TEST_ACTION action_immediate_bit_set = { 0 };
5387     action_immediate_bit_set.usbx_function = UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_FLUSH;
5388     action_immediate_bit_set.lun = 0;
5389     action_immediate_bit_set.lba = 0;
5390     action_immediate_bit_set.number_blocks = number_of_blocks;
5391     ux_test_add_action_to_main_list(action_immediate_bit_set);
5392 
5393     UX_TEST_CHECK_SUCCESS(_ux_host_class_storage_transport(global_storage, UX_NULL));
5394     UX_TEST_ASSERT(global_storage->ux_host_class_storage_cbw[UX_HOST_CLASS_STORAGE_CSW_STATUS] == UX_SUCCESS);
5395     UX_TEST_ASSERT(ux_test_check_actions_empty());
5396 
5397     basic_test(global_media, 1, "        running basic test\n");
5398 }
5399 
5400 /** This tests the case where the media is unremovable. **/
5401 
unremovable_media_test()5402 static void unremovable_media_test()
5403 {
5404 
5405     stepinfo("unremovable_media_test\n");
5406 
5407     ux_test_disconnect_slave_and_host_wait_for_enum_completion();
5408 
5409     /* Change the device's removable media flag to unremovable. */
5410     global_persistent_slave_storage->ux_slave_class_storage_lun[0].ux_slave_class_storage_media_removable_flag = 0x00;
5411 
5412     /* Now connect. */
5413     ux_test_connect_slave_and_host_wait_for_enum_completion();
5414 
5415     /* Wait for storage thread to run. */
5416     tx_thread_sleep(2*UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME);
5417 }
5418 
5419 /* transfer_timeout_test resources */
5420 
5421 static TX_THREAD ttt_asynchronous_transfer_thread;
5422 static UCHAR ttt_asynchronous_transfer_thread_stack[4096];
5423 
my_completion_function(UX_TRANSFER * transfer_request)5424 static void my_completion_function(UX_TRANSFER *transfer_request)
5425 {
5426 
5427     /* transfer_request_abort() will call this. */
5428     UX_TEST_ASSERT(transfer_request->ux_transfer_request_completion_code == UX_TRANSFER_STATUS_ABORT);
5429 }
5430 
ttt_asynchronous_transfer_thread_entry(ULONG input)5431 static VOID ttt_asynchronous_transfer_thread_entry(ULONG input)
5432 {
5433 
5434 UX_TRANSFER *transfer_request;
5435 
5436 
5437     UX_THREAD_EXTENSION_PTR_GET(transfer_request, UX_TRANSFER, input);
5438 
5439     /* Make sure the transfer never completes. */
5440     ux_test_add_action_to_main_list(create_timeout_on_transfer_action(tx_thread_identify()));
5441 
5442     transfer_request->ux_transfer_request_completion_function = my_completion_function;
5443     transfer_request->ux_transfer_request_data_pointer = global_buffer;
5444     transfer_request->ux_transfer_request_requested_length = UX_HOST_CLASS_STORAGE_CBW_LENGTH;
5445     UX_TEST_CHECK_SUCCESS(ux_host_stack_transfer_request(transfer_request));
5446     UX_TEST_ASSERT(ux_test_check_actions_empty());
5447 
5448     tx_thread_suspend(tx_thread_identify());
5449 }
5450 
transfer_timeout_test()5451 static void transfer_timeout_test()
5452 {
5453 
5454 UCHAR       original_expedient_value;
5455 UX_TRANSFER *transfer_request = &global_storage->ux_host_class_storage_bulk_in_endpoint->ux_endpoint_transfer_request;
5456 
5457 
5458     /* This is to test USBX-115. In summary, the bug is that if the thread timeouts
5459        waiting on a semaphore, then it usually calls transfer_abort(), but abort()
5460        does a semaphore_put() so there is extra count.  */
5461     stepinfo("transfer_timeout_test\n");
5462 
5463     /* Synchronous means no completion function is set. */
5464     stepinfo("    transfer_timeout_test - synchronous\n");
5465 
5466     /* Since we return from the transfer immediately, we need to turn on
5467        expedient mode.  */
5468     ux_test_turn_on_expedient(&original_expedient_value);
5469 
5470     /* Have the transfer timeout. */
5471     ux_test_add_action_to_main_list(create_timeout_on_cbw_action(tx_thread_identify()));
5472     ux_test_add_action_to_main_list(create_error_match_action(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_TIMEOUT));
5473 
5474     /* Do a transfer - the first transfer should be a CBW. */
5475     do_any_write();
5476     UX_TEST_ASSERT(ux_test_check_actions_empty());
5477 
5478     /* Check the bulk-out's transfer semaphore count. */
5479     UX_TEST_ASSERT(global_storage->ux_host_class_storage_bulk_out_endpoint->ux_endpoint_transfer_request.ux_transfer_request_semaphore.tx_semaphore_count == 0);
5480 
5481     /* Asynchronous means a completion function is set. */
5482     stepinfo("    transfer_timeout_test - asynchronous\n");
5483 
5484     /* We use the bulk out endpoint cause we have no others to use. */
5485     lock_out_storage_thread();
5486 
5487     UX_TEST_CHECK_SUCCESS(tx_thread_create(&ttt_asynchronous_transfer_thread, "ttt_asynchronous_transfer_thread",
5488                                            ttt_asynchronous_transfer_thread_entry, (ULONG)(ALIGN_TYPE)transfer_request,
5489                                            ttt_asynchronous_transfer_thread_stack, sizeof(ttt_asynchronous_transfer_thread_stack),
5490                                            20, 20, 10, TX_DONT_START));
5491     UX_THREAD_EXTENSION_PTR_SET(&ttt_asynchronous_transfer_thread, transfer_request);
5492     UX_TEST_CHECK_SUCCESS(tx_thread_resume(&ttt_asynchronous_transfer_thread));
5493 
5494     /* Wait for thread to do transfer. */
5495     int thread_state;
5496     do
5497     {
5498 
5499         UX_TEST_CHECK_SUCCESS(tx_thread_info_get(&ttt_asynchronous_transfer_thread, UX_NULL, &thread_state, UX_NULL, UX_NULL, UX_NULL, UX_NULL, UX_NULL, UX_NULL));
5500     } while(thread_state != TX_SUSPENDED);
5501 
5502     /* Now abort transfer. */
5503     UX_TEST_CHECK_SUCCESS(ux_host_stack_transfer_request_abort(transfer_request));
5504 
5505     /* Make sure the semaphore wasn't put(). */
5506     UX_TEST_ASSERT(transfer_request->ux_transfer_request_semaphore.tx_semaphore_count == 0);
5507 
5508     UX_TEST_CHECK_SUCCESS(tx_thread_terminate(&ttt_asynchronous_transfer_thread));
5509     UX_TEST_CHECK_SUCCESS(tx_thread_delete(&ttt_asynchronous_transfer_thread));
5510 
5511     lock_in_storage_thread();
5512 
5513     ux_test_set_expedient(original_expedient_value);
5514 }
5515 
ux_test_thread_host_simulation_entry(ULONG arg)5516 static void ux_test_thread_host_simulation_entry(ULONG arg)
5517 {
5518 
5519 UCHAR   original_expedient_value;
5520 UINT    status;
5521 ULONG   error_count = 0;
5522 UINT    i;
5523 void(*tests[])() =
5524 {
5525 
5526     transfer_timeout_test,
5527     unremovable_media_test,
5528     synchronize_cache_test,
5529     fx_media_read_test,
5530 
5531     thirteen_cases_4_5_test_host,
5532     thirteen_cases_9_11_test_host,
5533     stall_while_receiving_csw_test,
5534     csw_contains_phase_error_test,
5535     basic_test_with_globals,
5536     test_unit_ready_test,
5537 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
5538     first_sector_non_boot_test,
5539 #endif
5540     abort_media_test,
5541     flush_media_test,
5542     media_characteristics_get_test,
5543     storage_endpoints_get_test,
5544     system_host_change_function_test,
5545 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
5546     direct_calls_test,
5547     first_sector_different_signatures_test,
5548 #endif
5549     close_media_test,
5550     ux_host_class_storage_request_sense_test,
5551     transport_failures_cause_device_reset_test,
5552     entry_command_test,
5553     media_capacity_get_test,
5554 
5555 #ifdef UX_TEST_RACE_CONDITION_TESTS_ON
5556     disconnect_during_storage_thread_unmounting_media_test,
5557 #endif
5558 };
5559 
5560 
5561     ux_test_turn_off_expedient(&original_expedient_value);
5562 
5563     /* Format the ram drive. */
5564     status = fx_media_format(&global_ram_disk, _fx_ram_driver, global_ram_disk_memory, global_ram_disk_working_buffer, global_sector_size, "RAM DISK", 2, UX_TEST_NUM_DIRECTORY_ENTRIES, 0, UX_RAM_DISK_SIZE/global_sector_size, global_sector_size, 4, 1, 1);
5565     if (status != FX_SUCCESS)
5566     {
5567 
5568         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5569         test_control_return(1);
5570     }
5571 
5572     /* Open the ram_disk.  */
5573     status = fx_media_open(&global_ram_disk, "RAM DISK", _fx_ram_driver, global_ram_disk_memory, global_ram_disk_working_buffer, global_sector_size);
5574     if (status != FX_SUCCESS)
5575     {
5576 
5577         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5578         test_control_return(1);
5579     }
5580 
5581     UX_TEST_ASSERT(wait_for_enum_completion_and_get_global_storage_values() == UX_SUCCESS);
5582 
5583     /* Ensure slave activate callback was invoked. */
5584     if (global_slave_storage == UX_NULL)
5585     {
5586 
5587         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5588         test_control_return(1);
5589     }
5590 
5591     /* Get basic memory amount. */
5592     disconnect_host_and_slave();
5593     global_memory_test_no_device_memory_free_amount = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available;
5594     connect_host_and_slave();
5595 
5596     /* With basic memory amount, now do basic memory test. */
5597     disconnect_host_and_slave();
5598     connect_host_and_slave();
5599 
5600     for (i = 0; i < ARRAY_COUNT(tests); i++)
5601     {
5602 
5603         tests[i]();
5604 
5605         ux_test_free_user_list_actions();
5606 
5607         if (/* Left over actions? */
5608             ux_test_check_actions_empty() == UX_FALSE ||
5609             /* Invalid semaphore? */
5610             global_test_semaphore.tx_semaphore_count != 0 ||
5611             global_test_semaphore.tx_semaphore_suspended_count != 0)
5612         {
5613 
5614             /* Error! */
5615             printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5616             test_control_return(1);
5617         }
5618 
5619         /* Reset for next test. */
5620         reset_to_bo();
5621     }
5622 
5623     /* The storage thread runs every two seconds. Make sure it runs at least once so the device reset will occurr. */
5624     ux_utility_delay_ms(UX_TEST_SLEEP_STORAGE_THREAD_RUN_ONCE);
5625 
5626     /* Disconnect device and host. */
5627     stepinfo("Disconnect test\n");
5628 
5629     disconnect_host_and_slave();
5630 
5631     /* Let enum thread run. */
5632     tx_thread_sleep(50);
5633 
5634     /* Ensure system change callback was invoked. */
5635     if (global_storage_change_function != UX_NULL)
5636     {
5637 
5638         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5639         test_control_return(1);
5640     }
5641 
5642     /* Ensure slave deactivate callback was invoked. */
5643     if (global_slave_storage != UX_NULL)
5644     {
5645 
5646         printf("Error on line %d, error code: 0x%lx\n", __LINE__, (ULONG)status);
5647         test_control_return(1);
5648     }
5649 
5650     /* Start cleaning up. */
5651     stepinfo("clean up\n");
5652 
5653     /* And deinitialize the class.  */
5654     status =  ux_device_stack_class_unregister(_ux_system_slave_class_storage_name, ux_device_class_storage_entry);
5655 
5656     /* Deinitialize the device side of usbx.  */
5657     _ux_device_stack_uninitialize();
5658 
5659     /* And finally the usbx system resources.  */
5660     _ux_system_uninitialize();
5661 
5662     ux_test_set_expedient(original_expedient_value);
5663 
5664     /* Successful test.  */
5665     printf("SUCCESS!\n");
5666     test_control_return(0);
5667 }
5668 
5669 
default_device_media_status(VOID * storage,ULONG lun,ULONG media_id,ULONG * media_status)5670 static UINT default_device_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status)
5671 {
5672 
5673 UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS_PARAMS  params = { storage, lun, media_id, media_status };
5674 UX_TEST_ACTION                      action;
5675 
5676 
5677     action = ux_test_action_handler(UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_STATUS, &params);
5678     if (action.matched)
5679     {
5680         if (action.action_func)
5681         {
5682             action.action_func(&action, &params);
5683         }
5684 
5685         if (!action.no_return)
5686         {
5687             return action.status;
5688         }
5689     }
5690     else
5691     {
5692         *media_status = 0;
5693     }
5694 
5695     /* The ATA drive never fails. This is just for demo only !!!! */
5696     return(UX_SUCCESS);
5697 }
5698 
default_device_media_read(VOID * storage,ULONG lun,UCHAR * data_pointer,ULONG number_blocks,ULONG lba,ULONG * media_status)5699 static UINT default_device_media_read(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status)
5700 {
5701 
5702 UINT                                    status;
5703 UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS  params = { storage, lun, data_pointer, number_blocks, lba, media_status };
5704 UX_TEST_ACTION                          action;
5705 
5706 
5707     action = ux_test_action_handler(UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ, &params);
5708     if (action.matched && !action.do_after)
5709     {
5710         if (action.action_func)
5711         {
5712             action.action_func(&action, &params);
5713         }
5714 
5715         if (!action.no_return)
5716         {
5717             return action.status;
5718         }
5719     }
5720 
5721     if (lba == 0)
5722     {
5723 
5724         global_ram_disk.fx_media_driver_logical_sector = 0;
5725         global_ram_disk.fx_media_driver_sectors = 1;
5726         global_ram_disk.fx_media_driver_request = FX_DRIVER_BOOT_READ;
5727         global_ram_disk.fx_media_driver_buffer = data_pointer;
5728         _fx_ram_driver(&global_ram_disk);
5729         *(data_pointer) = 0xeb;
5730         *(data_pointer+1) = 0x3c;
5731         *(data_pointer+2) = 0x90;
5732         *(data_pointer+21) = 0xF8;
5733 
5734         *(data_pointer+24) = 0x01;
5735         *(data_pointer+26) = 0x10;
5736         *(data_pointer+28) = 0x01;
5737 
5738         *(data_pointer+510) = 0x55;
5739         *(data_pointer+511) = 0xaa;
5740         ux_utility_memory_copy(data_pointer+0x36, "FAT12", 5);
5741 
5742 
5743         status = global_ram_disk.fx_media_driver_status;
5744         UX_TEST_CHECK_SUCCESS(status);
5745     }
5746     else
5747     {
5748 
5749         while (number_blocks--)
5750         {
5751             status = fx_media_read(&global_ram_disk, lba, data_pointer);
5752             UX_TEST_CHECK_SUCCESS(status);
5753             data_pointer += global_sector_size;
5754             lba++;
5755         }
5756     }
5757 
5758     if (action.matched && action.do_after)
5759     {
5760         if (action.action_func)
5761         {
5762             action.action_func(&action, &params);
5763         }
5764 
5765         if (!action.no_return)
5766         {
5767             return action.status;
5768         }
5769     }
5770 
5771     return(status);
5772 }
5773 
default_device_media_write(VOID * storage,ULONG lun,UCHAR * data_pointer,ULONG number_blocks,ULONG lba,ULONG * media_status)5774 static UINT default_device_media_write(VOID *storage, ULONG lun, UCHAR * data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status)
5775 {
5776 
5777 UINT                                                status;
5778 UX_TEST_ACTION                                      action;
5779 UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS  params = { storage, lun, data_pointer, number_blocks, lba, media_status };
5780 
5781 
5782     action = ux_test_action_handler(UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_WRITE, &params);
5783     if (action.matched && !action.do_after)
5784     {
5785         if (action.action_func)
5786         {
5787             action.action_func(&action, &params);
5788         }
5789 
5790         if (!action.no_return)
5791         {
5792             return action.status;
5793         }
5794     }
5795 
5796     if(lba == 0)
5797     {
5798 
5799         global_ram_disk.fx_media_driver_logical_sector =  0;
5800         global_ram_disk.fx_media_driver_sectors =  1;
5801         global_ram_disk.fx_media_driver_request =  FX_DRIVER_BOOT_WRITE;
5802         global_ram_disk.fx_media_driver_buffer =  data_pointer;
5803         _fx_ram_driver(&global_ram_disk);
5804 
5805         status = global_ram_disk.fx_media_driver_status;
5806 
5807     }
5808     else
5809     {
5810 
5811         while(number_blocks--)
5812         {
5813 
5814             status =  fx_media_write(&global_ram_disk,lba,data_pointer);
5815             data_pointer+=global_sector_size;
5816             lba++;
5817         }
5818         return(status);
5819     }
5820 
5821     if (action.matched && action.do_after)
5822     {
5823         if (action.action_func)
5824         {
5825             action.action_func(&action, &params);
5826         }
5827 
5828         if (!action.no_return)
5829         {
5830             return action.status;
5831         }
5832     }
5833 
5834     return(status);
5835 }
5836 
5837 
default_device_media_flush(VOID * storage,ULONG lun,ULONG number_blocks,ULONG lba,ULONG * media_status)5838 static UINT default_device_media_flush(VOID *storage, ULONG lun, ULONG number_blocks, ULONG lba, ULONG *media_status)
5839 {
5840 
5841 UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_READ_WRITE_FLUSH_PARAMS    params = { storage, lun, UX_NULL, number_blocks, lba, media_status };
5842 
5843 
5844     ux_test_action_handler(UX_TEST_OVERRIDE_UX_DEVICE_MEDIA_FLUSH, &params);
5845 
5846     return(UX_SUCCESS);
5847 }
5848