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

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

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

Go to the source code of this file.

Enumerations

enum  scsi_sense_code_t : uint8_t {
  k_scsi_sense_illegal_request = 0x05U ,
  k_scsi_asc_lba_out_of_range = 0x21U ,
  k_scsi_ascq_none = 0x00U
}
enum  scsi_wp_sense_t : uint8_t {
  k_scsi_sense_data_protect = 0x07U ,
  k_scsi_asc_write_protected = 0x27U
}
 SCSI sense triple for a write to the protected medium. More...
enum  selftest_fat_boot_t : uint32_t {
  k_boot_jmp0 = 0xEBU ,
  k_boot_jmp1 = 0x3CU ,
  k_boot_jmp2 = 0x90U ,
  k_boot_media = 0xF8U ,
  k_boot_sec_per_trk = 32U ,
  k_boot_num_heads = 16U ,
  k_boot_drive_num = 0x80U ,
  k_boot_ext_sig = 0x29U ,
  k_boot_volume_id = 0x52A8D20AU ,
  k_boot_sig_lo = 0x55U ,
  k_boot_sig_hi = 0xAAU ,
  k_boot_sig_lo_off = 510U ,
  k_boot_sig_hi_off = 511U
}
 Boot-sector field values (MS FAT spec 1.03 sec 3.1). More...
enum  selftest_word_pack_t : uint32_t {
  k_word_shift = 16U ,
  k_word_mask = 0xFFFFU
}
 32-bit little-endian split constants. More...

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}

Device-side step routines split out of the usb_host_msc_browse self-loop app's main.c to keep every translation unit under the file-size cap. This TU synthesizes the read-only FAT16 volume the fake peripheral exposes (boot sector / FAT chain / root directory / data region over the 1 MiB MRAM window) and implements the three USBX storage media callbacks (read / write / status) that main.c's class-register helper wires into the single LUN. The host-side browse/verify ladder and all bring-up code remain in main.c.

The whole TU is compiled only in the on-target firmware build, mirroring the original placement inside main.c's #ifndef RA8_OFF_TARGET block.

Author
Brighton Sikarskie
Date
2026-06-25
Since
0.1.0

Definition in file usb_host_msc_browse_steps.c.

Enumeration Type Documentation

◆ scsi_sense_code_t

enum scsi_sense_code_t : uint8_t
Enumerator
k_scsi_sense_illegal_request 

Sense key: ILLEGAL REQUEST.

k_scsi_asc_lba_out_of_range 

ASC: LBA out of range.

k_scsi_ascq_none 

ASCQ: none.

Definition at line 40 of file usb_host_msc_browse_steps.c.

◆ scsi_wp_sense_t

enum scsi_wp_sense_t : uint8_t

SCSI sense triple for a write to the protected medium.

Enumerator
k_scsi_sense_data_protect 

Sense key: DATA PROTECT.

k_scsi_asc_write_protected 

ASC: WRITE PROTECTED.

Definition at line 47 of file usb_host_msc_browse_steps.c.

◆ selftest_fat_boot_t

enum selftest_fat_boot_t : uint32_t

Boot-sector field values (MS FAT spec 1.03 sec 3.1).

Enumerator
k_boot_jmp0 

Short JMP opcode.

k_boot_jmp1 

JMP displacement.

k_boot_jmp2 

NOP.

k_boot_media 

Fixed-disk media byte.

k_boot_sec_per_trk 

Geometry filler.

k_boot_num_heads 

Geometry filler.

k_boot_drive_num 

BIOS drive number.

k_boot_ext_sig 

Extended boot signature.

k_boot_volume_id 

Arbitrary volume serial.

k_boot_sig_lo 

Boot signature low byte.

k_boot_sig_hi 

Boot signature high byte.

k_boot_sig_lo_off 

Signature low-byte offset.

k_boot_sig_hi_off 

Signature high-byte offset.

Definition at line 56 of file usb_host_msc_browse_steps.c.

◆ selftest_word_pack_t

enum selftest_word_pack_t : uint32_t

32-bit little-endian split constants.

Enumerator
k_word_shift 

Bits per half-word.

k_word_mask 

Low half-word mask.

Definition at line 76 of file usb_host_msc_browse_steps.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 160 of file usb_host_msc_browse_steps.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 204 of file usb_host_msc_browse_steps.c.

References k_fat_entries_per_sec, k_fat_entry0, k_fat_eoc, k_fat_first_cluster, 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 241 of file usb_host_msc_browse_steps.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 276 of file usb_host_msc_browse_steps.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

Definition at line 304 of file usb_host_msc_browse_steps.c.

◆ 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 347 of file usb_host_msc_browse_steps.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 328 of file usb_host_msc_browse_steps.c.

◆ 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 116 of file usb_host_msc_browse_steps.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 138 of file usb_host_msc_browse_steps.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 94 of file usb_host_msc_browse_steps.c.

◆ s_fat_file_name

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

◆ s_fat_fs_type

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

◆ s_fat_oem_name

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

◆ s_fat_volume_label

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