ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
usb_selftest_device.c
Go to the documentation of this file.
1
17
18#include "usb_selftest_device.h"
19
20#include <stdint.h>
21#include <string.h>
22
23#include "ra8_board_ek_ra8d2.h"
24#include "ra8_err.h"
25#include "ra8_usb.h"
26#include "usb_selftest_common.h"
27
28#ifndef RA8_OFF_TARGET
29#include "tx_api.h"
30#include "ux_api.h"
31#include "ux_dcd_ra8_usb.h"
32#include "ux_device_class_storage.h"
33#include "ux_device_stack.h"
34
35/* -------------------------------------------------------------------------- */
36/* Device state: USBX pool, SCSI/FAT identity strings, J-Link probe */
37/* -------------------------------------------------------------------------- */
38
40
41/* SCSI INQUIRY strings -- 8 / 16 / 4 byte fields per SBC-3. */
42static UCHAR s_msc_vendor_id[] = "RA8D2 ";
43static UCHAR s_msc_product_id[] = "SELFTEST MRAM RO";
44static UCHAR s_msc_product_rev[] = "0001";
45
47static const UCHAR s_fat_oem_name[8] = {'R', 'A', '8', 'D', '2', 'F', 'W', ' '};
48
50static const UCHAR s_fat_volume_label[11] = {'R', 'A', '8', 'D', '2', ' ', 'M', 'R', 'A', 'M', ' '};
51
53static const UCHAR s_fat_fs_type[8] = {'F', 'A', 'T', '1', '6', ' ', ' ', ' '};
54
56static const UCHAR s_fat_file_name[11] = {'M', 'R', 'A', 'M', ' ', ' ', ' ', ' ', 'B', 'I', 'N'};
57
58/* -------------------------------------------------------------------------- */
59/* J-Link probes */
60/* -------------------------------------------------------------------------- */
61
63static volatile uint32_t s_dbg_read_calls;
64
65/* -------------------------------------------------------------------------- */
66/* USB descriptors (DEVICE + CONFIG + MSC interface + endpoints) */
67/* -------------------------------------------------------------------------- */
68
69/* Single-interface MSC config: bulk-only transport, SCSI command set.
70 * EP1 IN + EP2 OUT, 64-byte MPS. PID 0x000E marks the self-test
71 * identity apart from the Mac-facing usb_msc_mram (0x000C). */
72static UCHAR s_device_framework_fs[] = {
73 /* Device descriptor (USB 2.0 sec 9.6.1) -- 18 bytes. */
74 0x12U,
75 0x01U,
76 0x00U,
77 0x02U,
78 0x00U, /* class = per-interface */
79 0x00U,
80 0x00U,
81 0x40U,
82 0x09U,
83 0x12U,
84 0x0EU, /* PID = 0x000E (pid.codes test). */
85 0x00U,
86 0x00U,
87 0x01U,
88 0x01U,
89 0x02U,
90 0x03U,
91 0x01U,
92 /* Configuration descriptor (32 bytes total). */
93 0x09U,
94 0x02U,
95 0x20U,
96 0x00U,
97 0x01U,
98 0x01U,
99 0x00U,
100 0x80U,
101 0x32U,
102 /* Interface descriptor -- MSC, SCSI, BBB. */
103 0x09U,
104 0x04U,
105 0x00U,
106 0x00U,
107 0x02U,
108 0x08U,
109 0x06U,
110 0x50U,
111 0x00U,
112 /* Bulk-IN endpoint (EP1 IN, 64-byte MPS). */
113 0x07U,
114 0x05U,
115 0x81U,
116 0x02U,
117 0x40U,
118 0x00U,
119 0x00U,
120 /* Bulk-OUT endpoint (EP2 OUT, 64-byte MPS). */
121 0x07U,
122 0x05U,
123 0x02U,
124 0x02U,
125 0x40U,
126 0x00U,
127 0x00U,
128};
129
137static UCHAR s_string_framework[] = {
138 /* idx 1: "Brighton Sikarskie". */
139 0x09U,
140 0x04U,
141 0x01U,
142 0x12U,
143 'B',
144 'r',
145 'i',
146 'g',
147 'h',
148 't',
149 'o',
150 'n',
151 ' ',
152 'S',
153 'i',
154 'k',
155 'a',
156 'r',
157 's',
158 'k',
159 'i',
160 'e',
161 /* idx 2: "RA8D2 SELFTEST". */
162 0x09U,
163 0x04U,
164 0x02U,
165 0x0EU,
166 'R',
167 'A',
168 '8',
169 'D',
170 '2',
171 ' ',
172 'S',
173 'E',
174 'L',
175 'F',
176 'T',
177 'E',
178 'S',
179 'T',
180 /* idx 3: serial. */
181 0x09U,
182 0x04U,
183 0x03U,
184 0x08U,
185 '0',
186 '0',
187 '0',
188 '0',
189 '0',
190 '0',
191 '0',
192 '4',
193};
194
195/* USBX LANGID descriptor 0x0409 (English-US), little-endian byte pair. */
196typedef enum : uint8_t {
200
207
208/* -------------------------------------------------------------------------- */
209/* FAT16 synthesis (identical layout to usb_msc_mram) */
210/* -------------------------------------------------------------------------- */
211
228static void selftest_put16(UCHAR* dst, uint16_t value)
229{
230 dst[0] = (UCHAR)(value & (uint16_t)k_byte_mask);
231 dst[1] = (UCHAR)((value >> (uint16_t)k_byte_shift) & (uint16_t)k_byte_mask);
232}
233
250static void selftest_put32(UCHAR* dst, uint32_t value)
251{
252 selftest_put16(dst, (uint16_t)(value & (uint32_t)k_word_mask));
253 selftest_put16(dst + 2U, (uint16_t)(value >> (uint32_t)k_word_shift));
254}
255
272static void selftest_fat_fill_boot(UCHAR* out)
273{
274 out[k_bpb_off_jmp] = (UCHAR)k_boot_jmp0;
275 out[k_bpb_off_jmp + 1U] = (UCHAR)k_boot_jmp1;
276 out[k_bpb_off_jmp + 2U] = (UCHAR)k_boot_jmp2;
277 (void)memcpy(&out[k_bpb_off_oem], s_fat_oem_name, sizeof(s_fat_oem_name));
279 out[k_bpb_off_spc] = 1U;
281 out[k_bpb_off_nfats] = (UCHAR)k_fat_num_fats;
284 out[k_bpb_off_media] = (UCHAR)k_boot_media;
289 out[k_bpb_off_bootsig] = (UCHAR)k_boot_ext_sig;
292 (void)memcpy(&out[k_bpb_off_fstype], s_fat_fs_type, sizeof(s_fat_fs_type));
293 out[k_boot_sig_lo_off] = (UCHAR)k_boot_sig_lo;
294 out[k_boot_sig_hi_off] = (UCHAR)k_boot_sig_hi;
295}
296
316static void selftest_fat_fill_fat(uint32_t fat_sector, UCHAR* out)
317{
318 const uint32_t first_entry = fat_sector * (uint32_t)k_fat_entries_per_sec;
319 for (uint32_t j = 0U; j < (uint32_t)k_fat_entries_per_sec; j++) {
320 const uint32_t entry = first_entry + j;
321 uint16_t value = 0U;
322 if (entry == 0U) {
323 value = (uint16_t)k_fat_entry0;
324 } else if (entry == 1U) {
325 value = (uint16_t)k_fat_eoc;
326 } else if (entry < (uint32_t)k_fat_last_mram_clus) {
327 value = (uint16_t)(entry + 1U);
328 } else if (entry == (uint32_t)k_fat_last_mram_clus) {
329 value = (uint16_t)k_fat_eoc;
330 } else {
331 value = 0U;
332 }
333 selftest_put16(&out[j * 2U], value);
334 }
335}
336
355static void selftest_fat_fill_root(uint32_t root_sector, UCHAR* out)
356{
357 if (root_sector != 0U) {
358 return;
359 }
360 /* Entry 0: volume label. */
361 (void)memcpy(&out[0], s_fat_volume_label, (size_t)k_dir_name_bytes);
362 out[k_dir_off_attr] = (UCHAR)k_dir_attr_volume;
363 /* Entry 1: MRAM.BIN, read-only, cluster 2, 1 MiB. */
364 UCHAR* entry = &out[k_dir_entry_bytes];
365 (void)memcpy(entry, s_fat_file_name, (size_t)k_dir_name_bytes);
366 entry[k_dir_off_attr] = (UCHAR)k_dir_attr_read_only;
368 selftest_put32(&entry[k_dir_off_size], (uint32_t)k_mram_bytes);
369}
370
390static void selftest_fat_fill_sector(uint32_t lba, UCHAR* out)
391{
392 (void)memset(out, 0, (size_t)k_selftest_block_size);
393 if (lba == 0U) {
395 return;
396 }
397 if (lba < (uint32_t)k_fat_root_lba) {
398 selftest_fat_fill_fat(lba - (uint32_t)k_fat_fat_lba, out);
399 return;
400 }
401 if (lba < (uint32_t)k_fat_data_lba) {
402 selftest_fat_fill_root(lba - (uint32_t)k_fat_root_lba, out);
403 return;
404 }
405 const uint32_t cluster = (lba - (uint32_t)k_fat_data_lba) + (uint32_t)k_fat_first_cluster;
406 if (cluster <= (uint32_t)k_fat_last_mram_clus) {
407 const uint32_t offset =
408 (cluster - (uint32_t)k_fat_first_cluster) * (uint32_t)k_selftest_block_size;
409 const UCHAR* mram = (const UCHAR*)(uintptr_t)((uint32_t)k_mram_base_addr + offset);
410 (void)memcpy(out, mram, (size_t)k_selftest_block_size);
411 }
412}
413
414/* -------------------------------------------------------------------------- */
415/* Storage class media callbacks (read / write / status) */
416/* -------------------------------------------------------------------------- */
417
447static UINT selftest_msc_read(VOID* storage,
448 ULONG lun,
449 UCHAR* data_pointer,
450 ULONG number_blocks,
451 ULONG lba,
452 ULONG* media_status)
453{
454 (void)storage;
455 (void)lun;
457 if ((lba + number_blocks) > (ULONG)k_fat_total_sectors) {
458 *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(k_scsi_sense_illegal_request,
461 return UX_ERROR;
462 }
463 for (ULONG i = 0UL; i < number_blocks; i++) {
464 selftest_fat_fill_sector((uint32_t)(lba + i), &data_pointer[i * (ULONG)k_selftest_block_size]);
465 }
466 *media_status = 0UL;
468 return UX_SUCCESS;
469}
470
496static UINT selftest_msc_write(VOID* storage,
497 ULONG lun,
498 UCHAR* data_pointer,
499 ULONG number_blocks,
500 ULONG lba,
501 ULONG* media_status)
502{
503 (void)storage;
504 (void)lun;
505 (void)data_pointer;
506 (void)number_blocks;
507 (void)lba;
508 *media_status = UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(k_scsi_sense_data_protect,
511 return UX_ERROR;
512}
513
535static UINT selftest_msc_status(VOID* storage, ULONG lun, ULONG media_id, ULONG* media_status)
536{
537 (void)storage;
538 (void)lun;
539 (void)media_id;
540 *media_status = 0UL;
541 return UX_SUCCESS;
542}
543
544/* -------------------------------------------------------------------------- */
545/* Threads */
546/* -------------------------------------------------------------------------- */
547
566{
567 if (_ux_system_initialize(s_usbx_pool, k_selftest_usbx_pool_bytes, UX_NULL, 0) != UX_SUCCESS) {
568 return UX_ERROR;
569 }
570 return _ux_device_stack_initialize((UCHAR*)UX_NULL,
571 0,
573 sizeof(s_device_framework_fs),
575 sizeof(s_string_framework),
578 UX_NULL);
579}
580
599{
600 UX_SLAVE_CLASS_STORAGE_PARAMETER msc_params;
601 (void)memset(&msc_params, 0, sizeof(msc_params));
602 msc_params.ux_slave_class_storage_parameter_number_lun = 1UL;
603 msc_params.ux_slave_class_storage_parameter_vendor_id = s_msc_vendor_id;
604 msc_params.ux_slave_class_storage_parameter_product_id = s_msc_product_id;
605 msc_params.ux_slave_class_storage_parameter_product_rev = s_msc_product_rev;
606
607 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_last_lba =
609 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_block_length =
611 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_type =
612 UX_SLAVE_CLASS_STORAGE_MEDIA_FAT_DISK;
613 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_removable_flag =
614 UX_SLAVE_CLASS_STORAGE_MEDIA_IS_REMOVABLE;
615 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read_only_flag =
616 UX_TRUE;
617 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read =
619 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write =
621 msc_params.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status =
623
624 static UCHAR s_class_name[] = "ux_slave_class_storage";
625
626 return _ux_device_stack_class_register(s_class_name,
627 _ux_device_class_storage_entry,
628 1,
629 0,
630 &msc_params);
631}
632
651{
652 (void)arg;
653
654 if (selftest_usbx_stack_up() != UX_SUCCESS) {
655 return;
656 }
657 if (selftest_msc_class_register() != UX_SUCCESS) {
658 return;
659 }
661 return;
662 }
664 return;
665 }
666
667 /* Idle. USBX runs the SCSI/BBB state machine on its own threads. */
668 while (1) {
670 }
671}
672
673#endif /* !RA8_OFF_TARGET */
static UCHAR s_msc_product_id[]
Definition main.c:197
static UCHAR s_string_framework[]
USBX string descriptor table (vendor / product / serial).
Definition main.c:299
@ k_scsi_ascq_none
ASCQ: none.
Definition main.c:147
@ k_scsi_asc_write_protected
ASC: WRITE PROTECTED.
Definition main.c:149
@ k_scsi_sense_illegal_request
Sense key: ILLEGAL REQUEST.
Definition main.c:145
@ k_scsi_sense_data_protect
Sense key: DATA PROTECT.
Definition main.c:148
@ k_scsi_asc_lba_out_of_range
ASC: LBA out of range.
Definition main.c:146
static UCHAR s_usbx_pool[k_wlun_usbx_pool_bytes]
USBX memory pool (USBX uses tx_byte_pool internally).
Definition main.c:193
usb_langid_byte_t
Definition main.c:358
@ k_usb_langid_en_us_lo
LANGID 0x0409 low byte.
Definition main.c:359
@ k_usb_langid_en_us_hi
LANGID 0x0409 high byte.
Definition main.c:360
static UCHAR s_device_framework_fs[]
Definition main.c:234
static UCHAR s_msc_product_rev[]
Definition main.c:198
static UCHAR s_language_id_framework[]
USBX language-id table – US English.
Definition main.c:368
static volatile uint32_t s_dbg_read_calls
Device-side media_read invocations.
Definition main.c:213
static UCHAR s_msc_vendor_id[]
Definition main.c:196
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_led_toggle(ra8_board_led_id_t led)
Toggle led's output state.
@ k_ra8_board_led1
LED1, BLUE, P600 (jumper E27).
Error Code Definitions for ra8-firmware.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
@ k_dir_off_attr
MS FAT spec sec 6 "DIR_Attr".
@ k_byte_mask
Byte mask.
@ k_word_mask
Word mask.
Native USB controller driver public API (device + host modes).
ra8_err_t ra8_usb_device_attach(ra8_usb_speed_t speed, bool attached)
Raise / drop the D+ pull-up to advertise the device to the host.
@ k_ra8_usb_speed_fs
Full-Speed controller (USBFS @ 0x40250000).
unsigned int UINT
ThreadX-compatible unsigned int (host stub).
#define tx_thread_sleep
unsigned long ULONG
ThreadX-compatible unsigned long (host stub).
static const UCHAR s_fat_oem_name[8]
Boot-sector OEM name (8 bytes, space padded).
static const UCHAR s_fat_fs_type[8]
Filesystem-type tag, 8 bytes space padded.
static const UCHAR s_fat_volume_label[11]
Volume label, 11 bytes space padded (also the root entry).
@ k_boot_sig_hi_off
Signature high-byte offset.
@ k_boot_jmp0
Short JMP opcode.
@ k_boot_num_heads
Geometry filler.
@ k_boot_sig_lo_off
Signature low-byte offset.
@ k_boot_sig_hi
Boot signature high byte.
@ k_boot_jmp1
JMP displacement.
@ k_boot_sig_lo
Boot signature low byte.
@ k_boot_media
Fixed-disk media byte.
@ k_boot_sec_per_trk
Geometry filler.
@ k_boot_ext_sig
Extended boot signature.
@ k_boot_drive_num
BIOS drive number.
@ k_boot_jmp2
NOP.
@ k_boot_volume_id
Arbitrary volume serial.
static const UCHAR s_fat_file_name[11]
8.3 directory name of the exposed file: "MRAM.BIN".
@ k_word_shift
Bits per half-word.
UINT selftest_msc_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status)
Storage media-status callback.
@ k_fat_root_entries
Root directory entries.
@ k_fat_eoc
End-of-chain marker.
@ k_fat_data_lba
First data sector (cluster 2).
@ k_fat_root_lba
First root-directory sector.
@ k_fat_fat_sectors
FAT16 size for 4098 entries.
@ k_fat_fat_lba
First FAT sector.
@ k_fat_first_cluster
FAT data area starts at cluster 2.
@ k_fat_entry0
FAT[0]: media F8 + filler.
@ k_fat_reserved_sectors
Boot sector only.
@ k_fat_entries_per_sec
FAT16 entries per 512-byte sector.
@ k_fat_total_sectors
1 + 17 + 32 + 4096.
@ k_fat_last_mram_clus
Last cluster of MRAM.BIN.
@ k_fat_num_fats
Single FAT copy.
UINT selftest_msc_read(VOID *storage, ULONG lun, UCHAR *data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status)
Storage media-read callback: synthesize sectors over MRAM.
@ k_dir_entry_bytes
Directory entry size.
@ k_bpb_off_spt
Sectors per track.
@ k_bpb_off_label
Volume label (11 bytes).
@ k_dir_attr_volume
Volume-label attribute.
@ k_bpb_off_media
Media descriptor.
@ k_bpb_off_bps
Bytes per sector.
@ k_dir_off_size
File size (32-bit LE).
@ k_bpb_off_jmp
Jump instruction.
@ k_bpb_off_heads
Head count.
@ k_bpb_off_oem
OEM name (8 bytes).
@ k_bpb_off_volid
Volume serial (4 bytes).
@ k_bpb_off_bootsig
Extended boot signature.
@ k_bpb_off_fatsz16
Sectors per FAT.
@ k_bpb_off_rsvd
Reserved sector count.
@ k_bpb_off_drvnum
Drive number.
@ k_bpb_off_fstype
Filesystem type (8 bytes).
@ k_bpb_off_rootent
Root entry count.
@ k_dir_name_bytes
8.3 name field length.
@ k_byte_shift
Bits per byte for LE packing.
@ k_dir_off_cluster_lo
First cluster (low word).
@ k_bpb_off_nfats
Number of FATs.
@ k_bpb_off_spc
Sectors per cluster.
@ k_bpb_off_totsec16
Total sectors (16-bit).
@ k_dir_attr_read_only
Read-only attribute.
@ k_mram_bytes
1 MiB window size.
@ k_mram_base_addr
MRAM code window base address.
UINT selftest_msc_write(VOID *storage, ULONG lun, UCHAR *data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status)
Storage media-write callback: always rejects (write-protected).
@ k_selftest_block_size
SCSI logical block size (bytes).
@ k_selftest_idle_ticks
Parked-loop back-off (ticks).
@ k_selftest_usbx_pool_bytes
USBX memory pool (bytes).
Shared constants for the usb_selftest_soak translation units.
static void selftest_put16(UCHAR *dst, uint16_t value)
Write a 16-bit value little-endian into a byte buffer.
VOID selftest_device_worker(ULONG arg)
Device-side worker: bring the FS device stack up, then park.
static void selftest_fat_fill_root(uint32_t root_sector, UCHAR *out)
Synthesize one root-directory sector.
static void selftest_fat_fill_sector(uint32_t lba, UCHAR *out)
Synthesize one 512-byte sector of the read-only volume.
static UINT selftest_msc_read(VOID *storage, ULONG lun, UCHAR *data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status)
Storage media-read callback: synthesize sectors over MRAM.
static void selftest_fat_fill_boot(UCHAR *out)
Synthesize the FAT16 boot sector (MS FAT spec 1.03 sec 3.1).
static UINT selftest_msc_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status)
Storage media-status callback.
static UINT selftest_usbx_stack_up(void)
Brings USBX system + FS device stack up.
static void selftest_fat_fill_fat(uint32_t fat_sector, UCHAR *out)
Synthesize one FAT16 sector of the cluster chain.
static void selftest_put32(UCHAR *dst, uint32_t value)
Write a 32-bit value little-endian into a byte buffer.
static UINT selftest_msc_write(VOID *storage, ULONG lun, UCHAR *data_pointer, ULONG number_blocks, ULONG lba, ULONG *media_status)
Storage media-write callback: always rejects (write-protected).
static UINT selftest_msc_class_register(void)
Registers the Mass-Storage class with the read-only MRAM LUN.
Device-side worker entry of the soak self-test.
USBX device-controller-driver (DCD) bridge to ra8_usb.
ra8_err_t ux_dcd_ra8_usb_initialize(ra8_usb_speed_t speed)
Register the ra8_usb bridge as the active USBX DCD.