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(¶ms->data_pointer[0x16], (USHORT)first_sector_different_signatures_sig_values[first_sector_different_signatures_test_num][3]);
3997 ux_utility_long_put(¶ms->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(¬_ready_actions);
5050 ux_test_add_action_to_user_list(¬_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(¬_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, ¶ms);
5678 if (action.matched)
5679 {
5680 if (action.action_func)
5681 {
5682 action.action_func(&action, ¶ms);
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, ¶ms);
5708 if (action.matched && !action.do_after)
5709 {
5710 if (action.action_func)
5711 {
5712 action.action_func(&action, ¶ms);
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, ¶ms);
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, ¶ms);
5783 if (action.matched && !action.do_after)
5784 {
5785 if (action.action_func)
5786 {
5787 action.action_func(&action, ¶ms);
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, ¶ms);
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, ¶ms);
5845
5846 return(UX_SUCCESS);
5847 }
5848