ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
usb_selftest_hs_host_msc.c File Reference

Device-side FAT16 synthesis + USBX storage media callbacks. More...

#include <stdint.h>
#include <string.h>
#include "usb_selftest_hs_host_steps.h"
#include "ra8_board_ek_ra8d2.h"
#include "tx_api.h"
#include "ux_api.h"
#include "ux_device_class_storage.h"
Include dependency graph for usb_selftest_hs_host_msc.c:

Go to the source code of this file.

Functions

static void selftest_put16 (UCHAR *dst, uint16_t value)
 Write a 16-bit value little-endian into a byte buffer.
static void selftest_put32 (UCHAR *dst, uint32_t value)
 Write a 32-bit value little-endian into a byte buffer.
static void selftest_fat_fill_boot (UCHAR *out)
 Synthesize the FAT16 boot sector (MS FAT spec 1.03 sec 3.1).
static void selftest_fat_fill_fat (uint32_t fat_sector, UCHAR *out)
 Synthesize one FAT16 sector of the cluster chain.
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.
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.
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).
UINT selftest_msc_status (VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status)
 Storage media-status callback.

Variables

static const UCHAR s_fat_oem_name [8] = {'R', 'A', '8', 'D', '2', 'F', 'W', ' '}
 Boot-sector OEM name (8 bytes, space padded).
static const UCHAR s_fat_volume_label [11] = {'R', 'A', '8', 'D', '2', ' ', 'M', 'R', 'A', 'M', ' '}
 Volume label, 11 bytes space padded (also the root entry).
static const UCHAR s_fat_fs_type [8] = {'F', 'A', 'T', '1', '6', ' ', ' ', ' '}
 Filesystem-type tag, 8 bytes space padded.
static const UCHAR s_fat_file_name [11] = {'M', 'R', 'A', 'M', ' ', ' ', ' ', ' ', 'B', 'I', 'N'}
 8.3 directory name of the exposed file: "MRAM.BIN".
static volatile uint32_t s_dbg_read_calls
 Device-side media_read invocations.

Detailed Description

Device-side FAT16 synthesis + USBX storage media callbacks.

Tag
[Ring 6 / APP] {World: S}

The device half of the USB self-loop config A app: it synthesizes a read-only FAT16 volume over the 1 MiB MRAM window at 0x02000000 (one file MRAM.BIN) and exposes it through the three USBX storage media callbacks (read / write / status). main.c registers those callbacks with the USBX storage class in selftest_msc_class_register; the FAT synthesis helpers below are private to this translation unit.

Split out of main.c verbatim to keep every translation unit under the 1000-line file-size cap; see usb_selftest_hs_host_steps.h for the shared constants and the callback contract.

Author
Brighton Sikarskie
Date
2026-06-12
Since
0.1.0

Definition in file usb_selftest_hs_host_msc.c.

Function Documentation

◆ selftest_fat_fill_boot()

void selftest_fat_fill_boot ( UCHAR * out)
static

Synthesize the FAT16 boot sector (MS FAT spec 1.03 sec 3.1).

BPB for the padded 4146-sector volume plus the 0x55AA signature; geometry constants in selftest_fat_geom_t.

Parameters
[out]outZeroed 512-byte sector buffer.
Precondition
out is zeroed.
Geometry constants describe a valid FAT16 volume.
Postcondition
out holds the BPB + 0x55AA signature.
No other state changes.
Note
Pure function.
Since
0.1.0

Definition at line 118 of file usb_selftest_hs_host_msc.c.

References k_boot_drive_num, k_boot_ext_sig, k_boot_jmp0, k_boot_jmp1, k_boot_jmp2, k_boot_media, k_boot_num_heads, k_boot_sec_per_trk, k_boot_sig_hi, k_boot_sig_hi_off, k_boot_sig_lo, k_boot_sig_lo_off, k_boot_volume_id, k_bpb_off_bootsig, k_bpb_off_bps, k_bpb_off_drvnum, k_bpb_off_fatsz16, k_bpb_off_fstype, k_bpb_off_heads, k_bpb_off_jmp, k_bpb_off_label, k_bpb_off_media, k_bpb_off_nfats, k_bpb_off_oem, k_bpb_off_rootent, k_bpb_off_rsvd, k_bpb_off_spc, k_bpb_off_spt, k_bpb_off_totsec16, k_bpb_off_volid, k_fat_fat_sectors, k_fat_num_fats, k_fat_reserved_sectors, k_fat_root_entries, k_fat_total_sectors, k_selftest_block_size, memcpy(), s_fat_fs_type, s_fat_oem_name, s_fat_volume_label, selftest_put16(), and selftest_put32().

Referenced by selftest_fat_fill_sector().

◆ selftest_fat_fill_fat()

void selftest_fat_fill_fat ( uint32_t fat_sector,
UCHAR * out )
static

Synthesize one FAT16 sector of the cluster chain.

MRAM.BIN occupies clusters 2..2049 as one sequential chain (entry c -> c + 1, last entry -> end-of-chain). Entries 0/1 carry the media descriptor per the FAT spec; everything past the chain reads as free (0x0000).

Parameters
[in]fat_sectorIndex of the FAT sector (0-based).
[out]outZeroed 512-byte sector buffer.
Precondition
out is zeroed.
fat_sector is below k_fat_fat_sectors.
Postcondition
out holds 256 little-endian FAT16 entries.
No other state changes.
Note
Pure function.
Since
0.1.0

Definition at line 162 of file usb_selftest_hs_host_msc.c.

References k_fat_entries_per_sec, k_fat_entry0, k_fat_eoc, k_fat_last_mram_clus, and selftest_put16().

Referenced by selftest_fat_fill_sector().

◆ selftest_fat_fill_root()

void selftest_fat_fill_root ( uint32_t root_sector,
UCHAR * out )
static

Synthesize one root-directory sector.

Sector 0 of the root carries two entries: the volume label and the read-only MRAM.BIN file (start cluster 2, size 1 MiB). Every other root sector is empty.

Parameters
[in]root_sectorIndex of the root sector (0-based).
[out]outZeroed 512-byte sector buffer.
Precondition
out is zeroed.
root_sector is below k_fat_root_sectors.
Postcondition
out holds the directory entries for that sector.
No other state changes.
Note
Pure function.
Since
0.1.0

Definition at line 201 of file usb_selftest_hs_host_msc.c.

References k_dir_attr_read_only, k_dir_attr_volume, k_dir_entry_bytes, k_dir_name_bytes, k_dir_off_attr, k_dir_off_cluster_lo, k_dir_off_size, k_fat_first_cluster, k_mram_bytes, memcpy(), s_fat_file_name, s_fat_volume_label, selftest_put16(), and selftest_put32().

Referenced by selftest_fat_fill_sector().

◆ selftest_fat_fill_sector()

void selftest_fat_fill_sector ( uint32_t lba,
UCHAR * out )
static

Synthesize one 512-byte sector of the read-only volume.

Dispatches on the LBA: boot sector, FAT, root directory, or data region. Data sectors inside the MRAM.BIN chain are copied straight out of the 1 MiB MRAM window; padding clusters past the chain read as zeros.

Parameters
[in]lbaLogical block address inside the volume.
[out]out512-byte destination buffer.
Precondition
lba is below k_fat_total_sectors (caller-checked).
out has 512 writable bytes.
Postcondition
out holds the synthesized sector content.
No other state changes.
Note
Reads chip MRAM directly; no caching.
Since
0.1.0

Definition at line 236 of file usb_selftest_hs_host_msc.c.

References k_fat_data_lba, k_fat_fat_lba, k_fat_first_cluster, k_fat_last_mram_clus, k_fat_root_lba, k_mram_base_addr, k_selftest_block_size, memcpy(), memset(), selftest_fat_fill_boot(), selftest_fat_fill_fat(), and selftest_fat_fill_root().

Referenced by selftest_msc_read().

◆ selftest_msc_read()

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.

Bound checks the request against the volume, then fills each block via the FAT16 synthesizer. LED1 toggles per call so the self-loop traffic is visible on the board.

Parameters
[in,out]storageUSBX storage class instance (unused).
[in]lunLogical unit number (must be 0).
[out]data_pointerUSBX-owned destination buffer.
[in]number_blocksNumber of 512-byte blocks to produce.
[in]lbaStarting LBA.
[out]media_statusFilled with sense status word.
Returns
UX_SUCCESS if the request fits the volume; otherwise UX_ERROR with media_status set to ILLEGAL REQUEST.
Return values
UX_SUCCESSRead completed.
UX_ERROROut-of-range LBA / count.
Precondition
data_pointer and media_status are non-NULL (USBX guarantee).
lun is 0 (single-LUN device).
Postcondition
Either number_blocks * 512 bytes were synthesized or media_status is non-zero.
The device-side read-call probe advanced.
Note
Called from the USBX storage class thread.
Since
0.1.0

Bound checks the request against the volume, then fills each block via selftest_fat_fill_sector. LED1 toggles per call so the self-loop traffic is visible on the board.

Parameters
[in,out]storageUSBX storage class instance (unused).
[in]lunLogical unit number (must be 0).
[out]data_pointerUSBX-owned destination buffer.
[in]number_blocksNumber of 512-byte blocks to produce.
[in]lbaStarting LBA.
[out]media_statusFilled with sense status word.
Returns
UX_SUCCESS if the request fits the volume; otherwise UX_ERROR with media_status set to ILLEGAL REQUEST.
Return values
UX_SUCCESSRead completed.
UX_ERROROut-of-range LBA / count.
Precondition
data_pointer and media_status are non-NULL (USBX guarantee).
lun is 0 (single-LUN device).
Postcondition
Either number_blocks * 512 bytes were synthesized or media_status is non-zero.
s_dbg_read_calls advanced.
Note
Called from the USBX storage class thread.
Since
0.1.0

Definition at line 264 of file usb_selftest_hs_host_msc.c.

References k_fat_total_sectors, k_ra8_board_led1, k_scsi_asc_lba_out_of_range, k_scsi_ascq_none, k_scsi_sense_illegal_request, k_selftest_block_size, ra8_board_led_toggle(), s_dbg_read_calls, and selftest_fat_fill_sector().

◆ selftest_msc_status()

UINT selftest_msc_status ( VOID * storage,
ULONG lun,
ULONG media_id,
ULONG * media_status )

Storage media-status callback.

Always reports media-present.

The synthesized volume cannot go away; status is constant 0.

Parameters
[in,out]storageUSBX storage class instance (unused).
[in]lunLogical unit number (unused).
[in]media_idMedia id (unused).
[out]media_statusFilled with 0 (no fault).
Returns
Always UX_SUCCESS.
Return values
UX_SUCCESSMedia is present and ready.
Precondition
media_status is non-NULL (USBX guarantee).
The class instance is live.
Postcondition
*media_status is 0.
No other state changes.
Note
Synthesized volume; never reports media-not-present.
Since
0.1.0

Definition at line 306 of file usb_selftest_hs_host_msc.c.

◆ selftest_msc_write()

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).

The host side of this very app probes exactly this rejection (WRITE(10) must fail with DATA PROTECT and the transport must keep working afterwards).

Parameters
[in,out]storageUSBX storage class instance (unused).
[in]lunLogical unit number (unused).
[in]data_pointerUSBX-owned source buffer (unused).
[in]number_blocksNumber of blocks the host tried (unused).
[in]lbaStarting LBA (unused).
[out]media_statusFilled with DATA PROTECT sense.
Returns
Always UX_ERROR.
Return values
UX_ERRORThe medium is write-protected.
Precondition
media_status is non-NULL (USBX guarantee).
The LUN also reports write-protected via MODE SENSE.
Postcondition
*media_status carries the DATA PROTECT sense triple.
The MRAM window is untouched.
Note
Hosts honouring the MODE SENSE WP bit never call this.
Since
0.1.0

Definition at line 288 of file usb_selftest_hs_host_msc.c.

References k_scsi_asc_write_protected, k_scsi_ascq_none, and k_scsi_sense_data_protect.

◆ selftest_put16()

void selftest_put16 ( UCHAR * dst,
uint16_t value )
static

Write a 16-bit value little-endian into a byte buffer.

Low byte first, high byte second, per the FAT on-disk layout.

Parameters
[out]dstDestination (2 bytes).
[in]valueValue to store.
Precondition
dst has 2 writable bytes.
None beyond the buffer contract.
Postcondition
dst[0] holds the low byte, dst[1] the high byte.
No other state changes.
Note
Pure function.
Since
0.1.0

Definition at line 74 of file usb_selftest_hs_host_msc.c.

References k_byte_mask, and k_byte_shift.

Referenced by selftest_fat_fill_boot(), selftest_fat_fill_fat(), selftest_fat_fill_root(), and selftest_put32().

◆ selftest_put32()

void selftest_put32 ( UCHAR * dst,
uint32_t value )
static

Write a 32-bit value little-endian into a byte buffer.

Two selftest_put16 halves, low half-word first.

Parameters
[out]dstDestination (4 bytes).
[in]valueValue to store.
Precondition
dst has 4 writable bytes.
None beyond the buffer contract.
Postcondition
dst holds the four little-endian bytes of value.
No other state changes.
Note
Pure function.
Since
0.1.0

Definition at line 96 of file usb_selftest_hs_host_msc.c.

References k_word_mask, k_word_shift, and selftest_put16().

Referenced by selftest_fat_fill_boot(), and selftest_fat_fill_root().

Variable Documentation

◆ s_dbg_read_calls

volatile uint32_t s_dbg_read_calls
static

Device-side media_read invocations.

Definition at line 52 of file usb_selftest_hs_host_msc.c.

◆ s_fat_file_name

const UCHAR s_fat_file_name[11] = {'M', 'R', 'A', 'M', ' ', ' ', ' ', ' ', 'B', 'I', 'N'}
static

8.3 directory name of the exposed file: "MRAM.BIN".

Definition at line 49 of file usb_selftest_hs_host_msc.c.

◆ s_fat_fs_type

const UCHAR s_fat_fs_type[8] = {'F', 'A', 'T', '1', '6', ' ', ' ', ' '}
static

Filesystem-type tag, 8 bytes space padded.

Definition at line 46 of file usb_selftest_hs_host_msc.c.

◆ s_fat_oem_name

const UCHAR s_fat_oem_name[8] = {'R', 'A', '8', 'D', '2', 'F', 'W', ' '}
static

Boot-sector OEM name (8 bytes, space padded).

Definition at line 40 of file usb_selftest_hs_host_msc.c.

◆ s_fat_volume_label

const UCHAR s_fat_volume_label[11] = {'R', 'A', '8', 'D', '2', ' ', 'M', 'R', 'A', 'M', ' '}
static

Volume label, 11 bytes space padded (also the root entry).

Definition at line 43 of file usb_selftest_hs_host_msc.c.