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

Native USB host-side MSC (Mass Storage Class) class layer implementation. More...

#include "ra8_usb_hmsc.h"
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_hal_internal.h"
#include "ra8_log.h"
#include "ra8_time.h"
#include "ra8_usb.h"
#include "ra8_usb_hmsc_internal.h"
Include dependency graph for ra8_usb_hmsc.c:

Go to the source code of this file.

Enumerations

enum  ra8_usb_hmsc_cbw_offset_t : uint8_t {
  k_ra8_hmsc_cbw_off_signature = 0U ,
  k_ra8_hmsc_cbw_off_tag = 4U ,
  k_ra8_hmsc_cbw_off_data_length = 8U ,
  k_ra8_hmsc_cbw_off_flags = 12U ,
  k_ra8_hmsc_cbw_off_lun = 13U ,
  k_ra8_hmsc_cbw_off_cdb_length = 14U ,
  k_ra8_hmsc_cbw_off_cdb = 15U
}
 Byte offsets inside the 31-byte CBW header. More...
enum  ra8_usb_hmsc_csw_offset_t : uint8_t {
  k_ra8_hmsc_csw_off_signature = 0U ,
  k_ra8_hmsc_csw_off_tag = 4U ,
  k_ra8_hmsc_csw_off_residue = 8U ,
  k_ra8_hmsc_csw_off_status = 12U
}
 Byte offsets inside the 13-byte CSW. More...
enum  ra8_usb_hmsc_cbw_flag_t : uint8_t {
  k_ra8_hmsc_cbw_flag_data_out = 0x00U ,
  k_ra8_hmsc_cbw_flag_data_in = 0x80U
}
 bmCBWFlags direction bit values. More...
enum  ra8_usb_hmsc_signature_t : uint32_t {
  k_ra8_hmsc_cbw_signature = 0x43425355U ,
  k_ra8_hmsc_csw_signature = 0x53425355U
}
 BOT wrapper signatures (USB MSC BBB rev 1.0 sec 5). More...
enum  ra8_usb_hmsc_byte_shift_t : uint8_t {
  k_ra8_hmsc_shift_byte0 = 0U ,
  k_ra8_hmsc_shift_byte1 = 8U ,
  k_ra8_hmsc_shift_byte2 = 16U ,
  k_ra8_hmsc_shift_byte3 = 24U
}
 Per-byte left-shift constants for little-endian / big-endian serialisation. More...
enum  ra8_usb_hmsc_byte_mask_t : uint32_t { k_ra8_hmsc_byte_mask = 0xFFU }
 Byte mask for serialisation. More...
enum  ra8_usb_hmsc_cdb_offset_t : uint8_t {
  k_ra8_hmsc_cdb_off_opcode = 0U ,
  k_ra8_hmsc_cdb_off_lba_msb = 2U ,
  k_ra8_hmsc_cdb_off_lba_b1 = 3U ,
  k_ra8_hmsc_cdb_off_lba_b2 = 4U ,
  k_ra8_hmsc_cdb_off_lba_lsb = 5U ,
  k_ra8_hmsc_cdb_off_cnt_msb = 7U ,
  k_ra8_hmsc_cdb_off_cnt_lsb = 8U ,
  k_ra8_hmsc_cdb_off_inq_alloc = 4U
}
 SCSI CDB byte offsets used when assembling READ(10) / WRITE(10) / READ_CAPACITY(10) / INQUIRY blocks. More...
enum  ra8_usb_hmsc_lun_mask_t : uint8_t {
  k_ra8_hmsc_lun_field_mask = 0x0FU ,
  k_ra8_hmsc_cdb_field_mask = 0x1FU
}
 Field width masks for the bCBWLUN + bCBWCBLength bytes. More...
enum  ra8_usb_hmsc_initial_tag_t : uint32_t { k_ra8_hmsc_initial_tag = 1U }
 Starting value of the BOT dCBWTag counter. More...
enum  ra8_usb_hmsc_inquiry_field_t : uint8_t {
  k_ra8_hmsc_inq_qual_shift = 5U ,
  k_ra8_hmsc_inq_dev_type_mask = 0x1FU ,
  k_ra8_hmsc_inq_removable_shift = 7U ,
  k_ra8_hmsc_inq_removable_mask = 1U
}
 Bit-field shifts / masks inside the SCSI INQUIRY response byte 0 / byte 1 (SBC-4 sec 6.6). More...
enum  ra8_usb_hmsc_inquiry_offset_t : uint8_t {
  k_ra8_hmsc_inq_off_dev_type = 0U ,
  k_ra8_hmsc_inq_off_removable = 1U ,
  k_ra8_hmsc_inq_off_version = 2U ,
  k_ra8_hmsc_inq_off_vendor_id = 8U ,
  k_ra8_hmsc_inq_off_product_id = 16U ,
  k_ra8_hmsc_inq_off_product_rev = 32U
}
 Byte offsets inside the SBC-4 standard INQUIRY response. More...
enum  ra8_usb_hmsc_capacity_offset_t : uint8_t {
  k_ra8_hmsc_cap_off_last_lba = 0U ,
  k_ra8_hmsc_cap_off_blk_size = 4U
}
 Byte offsets inside the SCSI READ_CAPACITY(10) 8-byte response (SBC-4 sec 5.10). More...

Functions

static uint16_t internal_bulk_max_packet (ra8_usb_speed_t speed)
 Pick the bulk-endpoint max-packet ceiling for the negotiated speed.
static uint32_t internal_next_tag (void)
 Hand out the next BOT tag (monotonic uint32 counter).
static void internal_pack_u32_le (uint32_t value, uint8_t *dst)
static uint32_t internal_unpack_u32_le (const uint8_t *src)
static uint32_t internal_unpack_u32_be (const uint8_t *src)
 Assemble a 32-bit word from four big-endian bytes.
static void internal_zero_bytes (uint8_t *dst, uint16_t len)
 Zero len bytes at dst byte-by-byte.
static void internal_copy_bytes (uint8_t *dst, const uint8_t *src, uint16_t len)
ra8_err_t ra8_usb_hmsc_build_cbw (uint8_t target_lun, uint32_t data_transfer_length, bool data_in, const uint8_t *cdb, uint8_t cdb_len, uint8_t *out_cbw)
 Construct the 31-byte CBW header for the given SCSI command.
ra8_err_t ra8_usb_hmsc_decode_csw (const uint8_t *csw, uint32_t expected_tag, ra8_usb_hmsc_csw_status_t *out_status)
 Decode a 13-byte CSW.
ra8_err_t ra8_usb_hmsc_init (ra8_usb_speed_t speed)
 Bring up the host-MSC driver on a chosen USB controller.
ra8_err_t ra8_usb_hmsc_close (void)
 Tear down the host-MSC driver and release the controller.
ra8_err_t ra8_usb_hmsc_attach_callback (ra8_usb_hmsc_attach_fn_t on_attach, void *ctx)
 Register (or detach) the attach callback.
static ra8_err_t internal_check_ready (uint8_t target_lun)
static ra8_err_t internal_send_cbw (const uint8_t *cbw)
 Push a CBW out on the bulk-OUT pipe.
static ra8_err_t internal_recv_bytes (uint8_t *dst, uint16_t *inout_len)
 Pull bytes from the bulk-IN pipe (data + CSW phase).
static void internal_build_inquiry_cdb (uint8_t *cdb)
static void internal_build_read_capacity_cdb (uint8_t *cdb)
static void internal_build_rw10_cdb (uint8_t opcode, uint32_t lba, uint16_t block_count, uint8_t *cdb)
 Build a 10-byte CDB for SCSI READ(10) / WRITE(10).
static ra8_err_t internal_issue_cbw (uint8_t target_lun, uint32_t xfer_len, bool data_in, const uint8_t *cdb, uint8_t cdb_len, uint32_t *out_tag)
static ra8_err_t internal_read_csw (uint32_t expected_tag)
 Read and validate the 13-byte CSW that closes a BOT exchange.
static ra8_err_t internal_run_data_in (uint8_t target_lun, const uint8_t *cdb, uint8_t cdb_len, uint8_t *out_buf, uint16_t *inout_len)
static ra8_err_t internal_run_data_out (uint8_t target_lun, const uint8_t *cdb, uint8_t cdb_len, const uint8_t *in_buf, uint16_t push_len)
static void internal_decode_inquiry (const uint8_t *raw, ra8_usb_hmsc_inquiry_response_t *response)
 Decode a 36-byte SCSI standard INQUIRY response into the public struct.
ra8_err_t ra8_usb_hmsc_inquiry (uint8_t target_lun, ra8_usb_hmsc_inquiry_response_t *response)
 Issue a SCSI INQUIRY (opcode 0x12) over BBB.
ra8_err_t ra8_usb_hmsc_read_capacity (uint8_t target_lun, uint32_t *block_count, uint32_t *block_size)
 Issue a SCSI READ CAPACITY(10) (opcode 0x25) over BBB.
ra8_err_t ra8_usb_hmsc_read10 (uint8_t target_lun, uint32_t lba, uint16_t block_count, uint8_t *out_buf)
 Issue a SCSI READ(10) (opcode 0x28) over BBB.
ra8_err_t ra8_usb_hmsc_write10 (uint8_t target_lun, uint32_t lba, uint16_t block_count, const uint8_t *in_buf)
 Issue a SCSI WRITE(10) (opcode 0x2A) over BBB.

Variables

static const char * s_tag = "USBHMSC"
ra8_usb_hmsc_state_t g_usb_hmsc_state = {}
 Singleton host-MSC shadow state, shared across the ra8_usb_hmsc split.

Detailed Description

Native USB host-side MSC (Mass Storage Class) class layer implementation.

Tag
[Ring 3 / HAL] {World: NS}

Glues the host-mode bring-up paths in ra8_usb to a USB Mass Storage Class (Bulk-Only-Transport / BBB) peripheral attached on the EK-RA8D2's USB-host port. This file is the native host-MSC class layer; FSP's r_usb_hmsc_driver.c, r_usb_hstorage_driver.c, and r_usb_hmsc.c are reference material only – nothing is pulled in verbatim.

Mapping vs FSP (FSP function -> our entry point):

The starter does CPU-FIFO, single-device, no-hub. Enumeration is a single polled ladder (ra8_usb_hmsc_enumerate): wait for the D+ attach, hunt the (reset, address) combination the device answers on, then read descriptors / SET_CONFIGURATION / open the bulk pipes. Every chapter-9 SETUP goes through ra8_usb_host_setup_request.

BOT (Bulk-Only Transport) state machine – per command:

READY -> CBW_OUT (push 31-byte CBW) -> DATA (in or out, optional) -> CSW_IN (pull 13-byte CSW) -> READY

On CSW phase-error the spec mandates Reset Recovery; the starter surfaces that as k_ra8_err_hw_error and lets the caller decide what to do.

Definition in file ra8_usb_hmsc.c.

Enumeration Type Documentation

◆ ra8_usb_hmsc_byte_mask_t

enum ra8_usb_hmsc_byte_mask_t : uint32_t

Byte mask for serialisation.

Enumerator
k_ra8_hmsc_byte_mask 

Single-byte extraction mask.

Definition at line 136 of file ra8_usb_hmsc.c.

◆ ra8_usb_hmsc_byte_shift_t

enum ra8_usb_hmsc_byte_shift_t : uint8_t

Per-byte left-shift constants for little-endian / big-endian serialisation.

Enumerator
k_ra8_hmsc_shift_byte0 

RA8 hmsc shift byte0.

k_ra8_hmsc_shift_byte1 

RA8 hmsc shift byte1.

k_ra8_hmsc_shift_byte2 

RA8 hmsc shift byte2.

k_ra8_hmsc_shift_byte3 

RA8 hmsc shift byte3.

Definition at line 125 of file ra8_usb_hmsc.c.

◆ ra8_usb_hmsc_capacity_offset_t

Byte offsets inside the SCSI READ_CAPACITY(10) 8-byte response (SBC-4 sec 5.10).

Enumerator
k_ra8_hmsc_cap_off_last_lba 

Last valid LBA (big-endian).

k_ra8_hmsc_cap_off_blk_size 

Block length (big-endian).

Definition at line 209 of file ra8_usb_hmsc.c.

◆ ra8_usb_hmsc_cbw_flag_t

enum ra8_usb_hmsc_cbw_flag_t : uint8_t

bmCBWFlags direction bit values.

Enumerator
k_ra8_hmsc_cbw_flag_data_out 

Host -> device.

k_ra8_hmsc_cbw_flag_data_in 

Device -> host.

Definition at line 103 of file ra8_usb_hmsc.c.

◆ ra8_usb_hmsc_cbw_offset_t

enum ra8_usb_hmsc_cbw_offset_t : uint8_t

Byte offsets inside the 31-byte CBW header.

See USB MSC BBB rev 1.0 sec 5.1 Table 5.1 "Command Block Wrapper".

Enumerator
k_ra8_hmsc_cbw_off_signature 

dCBWSignature [4].

k_ra8_hmsc_cbw_off_tag 

dCBWTag [4].

k_ra8_hmsc_cbw_off_data_length 

dCBWDataTransferLen.

k_ra8_hmsc_cbw_off_flags 

bmCBWFlags.

k_ra8_hmsc_cbw_off_lun 

bCBWLUN (low nib).

k_ra8_hmsc_cbw_off_cdb_length 

bCBWCBLength (low 5).

k_ra8_hmsc_cbw_off_cdb 

CBWCB [16].

Definition at line 75 of file ra8_usb_hmsc.c.

◆ ra8_usb_hmsc_cdb_offset_t

enum ra8_usb_hmsc_cdb_offset_t : uint8_t

SCSI CDB byte offsets used when assembling READ(10) / WRITE(10) / READ_CAPACITY(10) / INQUIRY blocks.

Enumerator
k_ra8_hmsc_cdb_off_opcode 

Operation Code.

k_ra8_hmsc_cdb_off_lba_msb 

READ(10): LBA byte 3.

k_ra8_hmsc_cdb_off_lba_b1 

READ(10): LBA byte 2.

k_ra8_hmsc_cdb_off_lba_b2 

READ(10): LBA byte 1.

k_ra8_hmsc_cdb_off_lba_lsb 

READ(10): LBA byte 0.

k_ra8_hmsc_cdb_off_cnt_msb 

READ(10): count high.

k_ra8_hmsc_cdb_off_cnt_lsb 

READ(10): count low.

k_ra8_hmsc_cdb_off_inq_alloc 

INQUIRY allocation len.

Definition at line 145 of file ra8_usb_hmsc.c.

◆ ra8_usb_hmsc_csw_offset_t

enum ra8_usb_hmsc_csw_offset_t : uint8_t

Byte offsets inside the 13-byte CSW.

See USB MSC BBB rev 1.0 sec 5.2 Table 5.2 "Command Status Wrapper".

Enumerator
k_ra8_hmsc_csw_off_signature 

dCSWSignature [4].

k_ra8_hmsc_csw_off_tag 

dCSWTag [4].

k_ra8_hmsc_csw_off_residue 

dCSWDataResidue.

k_ra8_hmsc_csw_off_status 

bCSWStatus.

Definition at line 92 of file ra8_usb_hmsc.c.

◆ ra8_usb_hmsc_initial_tag_t

enum ra8_usb_hmsc_initial_tag_t : uint32_t

Starting value of the BOT dCBWTag counter.

Enumerator
k_ra8_hmsc_initial_tag 

First tag handed out post-init.

Definition at line 172 of file ra8_usb_hmsc.c.

◆ ra8_usb_hmsc_inquiry_field_t

Bit-field shifts / masks inside the SCSI INQUIRY response byte 0 / byte 1 (SBC-4 sec 6.6).

Byte 0 high 3 bits = peripheral qualifier; low 5 bits = peripheral device type. Byte 1 bit 7 = removable.

Enumerator
k_ra8_hmsc_inq_qual_shift 

Byte 0 [7:5] qualifier.

k_ra8_hmsc_inq_dev_type_mask 

Byte 0 [4:0] dev type.

k_ra8_hmsc_inq_removable_shift 

Byte 1 [7] removable bit.

k_ra8_hmsc_inq_removable_mask 

1-bit removable flag.

Definition at line 184 of file ra8_usb_hmsc.c.

◆ ra8_usb_hmsc_inquiry_offset_t

Byte offsets inside the SBC-4 standard INQUIRY response.

Enumerator
k_ra8_hmsc_inq_off_dev_type 

Byte 0 (qual+devtype).

k_ra8_hmsc_inq_off_removable 

Byte 1 (removable).

k_ra8_hmsc_inq_off_version 

Byte 2 (SPC version).

k_ra8_hmsc_inq_off_vendor_id 

T10 Vendor ID start.

k_ra8_hmsc_inq_off_product_id 

Product ID start.

k_ra8_hmsc_inq_off_product_rev 

Product revision.

Definition at line 195 of file ra8_usb_hmsc.c.

◆ ra8_usb_hmsc_lun_mask_t

enum ra8_usb_hmsc_lun_mask_t : uint8_t

Field width masks for the bCBWLUN + bCBWCBLength bytes.

See USB MSC BBB rev 1.0 sec 5.1 Table 5.1: bCBWLUN occupies the low 4 bits; bCBWCBLength occupies the low 5 bits.

Enumerator
k_ra8_hmsc_lun_field_mask 

Low 4 bits of bCBWLUN.

k_ra8_hmsc_cdb_field_mask 

Low 5 bits of bCBWCBLen.

Definition at line 163 of file ra8_usb_hmsc.c.

◆ ra8_usb_hmsc_signature_t

enum ra8_usb_hmsc_signature_t : uint32_t

BOT wrapper signatures (USB MSC BBB rev 1.0 sec 5).

Stored on-wire little-endian. dCBWSignature 'USBC' is 0x43425355; dCSWSignature 'USBS' is 0x53425355.

Enumerator
k_ra8_hmsc_cbw_signature 

'USBC' little-endian.

k_ra8_hmsc_csw_signature 

'USBS' little-endian.

Definition at line 115 of file ra8_usb_hmsc.c.

Function Documentation

◆ internal_build_inquiry_cdb()

void internal_build_inquiry_cdb ( uint8_t * cdb)
static

◆ internal_build_read_capacity_cdb()

void internal_build_read_capacity_cdb ( uint8_t * cdb)
static

◆ internal_build_rw10_cdb()

void internal_build_rw10_cdb ( uint8_t opcode,
uint32_t lba,
uint16_t block_count,
uint8_t * cdb )
static

Build a 10-byte CDB for SCSI READ(10) / WRITE(10).

See SBC-4 sec 5.7 (READ(10)) and 5.20 (WRITE(10)). LBA is big-endian on the wire.

Parameters
[in]opcodeSee declaration: uint8_t opcode.
[in]lbaSee declaration: uint32_t lba.
[in]block_countSee declaration: uint16_t block_count.
[out]cdbSee declaration: uint8_t* cdb.
Precondition
Module/state preconditions hold (see function body).
Module/state preconditions hold (see function body).
Postcondition
Documented side effects are visible on success.
Documented side effects are visible on success.
Note
Internal helper. Not thread-safe; caller provides synchronisation.
Since
0.1.0

Definition at line 605 of file ra8_usb_hmsc.c.

References internal_zero_bytes(), k_ra8_hmsc_byte_mask, k_ra8_hmsc_cdb10_len, k_ra8_hmsc_cdb_off_cnt_lsb, k_ra8_hmsc_cdb_off_cnt_msb, k_ra8_hmsc_cdb_off_lba_b1, k_ra8_hmsc_cdb_off_lba_b2, k_ra8_hmsc_cdb_off_lba_lsb, k_ra8_hmsc_cdb_off_lba_msb, k_ra8_hmsc_cdb_off_opcode, k_ra8_hmsc_shift_byte0, k_ra8_hmsc_shift_byte1, k_ra8_hmsc_shift_byte2, and k_ra8_hmsc_shift_byte3.

Referenced by ra8_usb_hmsc_read10(), and ra8_usb_hmsc_write10().

◆ internal_bulk_max_packet()

uint16_t internal_bulk_max_packet ( ra8_usb_speed_t speed)
static

Pick the bulk-endpoint max-packet ceiling for the negotiated speed.

Returns the USB-spec bulk maximum packet size for the active bus speed: 512 bytes at High-Speed, 64 bytes at Full-Speed. Used by the data-OUT chunk loop as a fallback ceiling when the enumerated endpoint wMaxPacketSize is unknown (left zero by enumeration).

Parameters
[in]speedNegotiated controller bus speed (k_ra8_usb_speed_fs or k_ra8_usb_speed_hs).
Returns
Bulk maximum packet size in bytes.
Return values
k_ra8_hmsc_bulk_max_packet_hs512 bytes when speed is k_ra8_usb_speed_hs.
k_ra8_hmsc_bulk_max_packet_fs64 bytes for any other speed (Full-Speed).
Precondition
speed holds a valid ra8_usb_speed_t value.
The bulk pipe is enumerated so the returned ceiling is meaningful.
Postcondition
The returned value is one of the two spec-defined bulk sizes.
No module state is modified (pure function).
Note
Internal helper. Not thread-safe; caller provides synchronisation.
Since
0.1.0

Definition at line 252 of file ra8_usb_hmsc.c.

References k_ra8_hmsc_bulk_max_packet_fs, k_ra8_hmsc_bulk_max_packet_hs, and k_ra8_usb_speed_hs.

Referenced by internal_run_data_out().

◆ internal_check_ready()

◆ internal_copy_bytes()

void internal_copy_bytes ( uint8_t * dst,
const uint8_t * src,
uint16_t len )
static

Definition at line 357 of file ra8_usb_hmsc.c.

Referenced by internal_decode_inquiry(), and ra8_usb_hmsc_build_cbw().

◆ internal_decode_inquiry()

void internal_decode_inquiry ( const uint8_t * raw,
ra8_usb_hmsc_inquiry_response_t * response )
static

Decode a 36-byte SCSI standard INQUIRY response into the public struct.

Zero-initializes response, then extracts the peripheral qualifier and device type from byte 0, the removable-media bit from byte 1, and the SCSI version byte, and copies the ASCII vendor-id (8 B), product-id (16 B) and product-revision (4 B) fields from their fixed SPC/SBC offsets in the raw buffer.

Parameters
[in]rawPointer to at least k_ra8_hmsc_inquiry_resp_len (36) bytes of standard INQUIRY data.
[out]responseDestination struct populated with the decoded fields.
Precondition
raw is non-NULL and points to >= 36 readable bytes.
response is non-NULL and writable.
Postcondition
response is fully overwritten (leading zero-fill then decoded fields).
The vendor/product/revision ASCII fields are copied verbatim and are not NUL-terminated by this routine.
Note
Internal helper. Not thread-safe; caller provides synchronisation.
Since
0.1.0

Definition at line 754 of file ra8_usb_hmsc.c.

References internal_copy_bytes(), internal_zero_bytes(), k_ra8_hmsc_inq_dev_type_mask, k_ra8_hmsc_inq_off_dev_type, k_ra8_hmsc_inq_off_product_id, k_ra8_hmsc_inq_off_product_rev, k_ra8_hmsc_inq_off_removable, k_ra8_hmsc_inq_off_vendor_id, k_ra8_hmsc_inq_off_version, k_ra8_hmsc_inq_qual_shift, k_ra8_hmsc_inq_removable_mask, k_ra8_hmsc_inq_removable_shift, ra8_usb_hmsc_inquiry_response_t::peripheral_device_type, ra8_usb_hmsc_inquiry_response_t::peripheral_qualifier, ra8_usb_hmsc_inquiry_response_t::product_id, ra8_usb_hmsc_inquiry_response_t::product_revision, ra8_usb_hmsc_inquiry_response_t::removable, ra8_usb_hmsc_inquiry_response_t::vendor_id, and ra8_usb_hmsc_inquiry_response_t::version.

Referenced by ra8_usb_hmsc_inquiry().

◆ internal_issue_cbw()

ra8_err_t internal_issue_cbw ( uint8_t target_lun,
uint32_t xfer_len,
bool data_in,
const uint8_t * cdb,
uint8_t cdb_len,
uint32_t * out_tag )
static

◆ internal_next_tag()

uint32_t internal_next_tag ( void )
static

Hand out the next BOT tag (monotonic uint32 counter).

Mirrors FSP's g_usb_hmsc_csw_tag_no increment in r_usb_hmsc_driver.c. The starter never wraps in a single test run; production should detect wrap-around but a 32-bit counter lasts long enough that this is not urgent.

Returns
ra8_err_t outcome (or scalar return value).
Return values
k_ra8_okOperation completed successfully.
otherNon-zero error code from the underlying operation.
Precondition
Module/state preconditions hold (see function body).
Module/state preconditions hold (see function body).
Postcondition
Documented side effects are visible on success.
Documented side effects are visible on success.
Note
Internal helper. Not thread-safe; caller provides synchronisation.
Since
0.1.0

Definition at line 276 of file ra8_usb_hmsc.c.

References g_usb_hmsc_state.

Referenced by ra8_usb_hmsc_build_cbw().

◆ internal_pack_u32_le()

void internal_pack_u32_le ( uint32_t value,
uint8_t * dst )
static

◆ internal_read_csw()

ra8_err_t internal_read_csw ( uint32_t expected_tag)
static

Read and validate the 13-byte CSW that closes a BOT exchange.

Pulls the CSW from the bulk-IN pipe, requires the full 13 bytes, validates the signature + tag echo via ra8_usb_hmsc_decode_csw, and maps any non-PASSED status to k_ra8_err_hw_error.

Parameters
[in]expected_tagdCBWTag of the CBW that opened the exchange.
Returns
Exchange outcome.
Return values
k_ra8_okCSW signature/tag matched and status PASSED.
k_ra8_err_hw_errorShort CSW, bad signature/tag, or FAILED status.
Precondition
The CBW (and any data stage) for this exchange completed.
The bulk pipes are configured (ra8_usb_hmsc_enumerate).
Postcondition
The exchange is closed; the device is ready for the next CBW.
No state is modified on success.
Note
Blocking (one bounded bulk-IN wait).
Since
0.1.0

Definition at line 658 of file ra8_usb_hmsc.c.

References internal_recv_bytes(), k_ra8_err_hw_error, k_ra8_hmsc_csw_len, k_ra8_hmsc_csw_status_passed, k_ra8_hmsc_csw_status_phase_error, k_ra8_ok, RA8_RETURN_ON_ERROR, ra8_usb_hmsc_decode_csw(), and s_tag.

Referenced by internal_run_data_in(), and internal_run_data_out().

◆ internal_recv_bytes()

ra8_err_t internal_recv_bytes ( uint8_t * dst,
uint16_t * inout_len )
static

Pull bytes from the bulk-IN pipe (data + CSW phase).

inout_len is initialized to capacity by the caller and receives the actual byte count on return.

Parameters
[out]dstSee declaration: uint8_t* dst.
[out]inout_lenSee declaration: uint16_t* inout_len.
Returns
ra8_err_t outcome (or scalar return value).
Return values
k_ra8_okOperation completed successfully.
otherNon-zero error code from the underlying operation.
Precondition
Module/state preconditions hold (see function body).
Module/state preconditions hold (see function body).
Postcondition
Documented side effects are visible on success.
Documented side effects are visible on success.
Note
Internal helper. Not thread-safe; caller provides synchronisation.
Since
0.1.0

Definition at line 564 of file ra8_usb_hmsc.c.

References g_usb_hmsc_state, k_ra8_hmsc_pipe_bulk_in, and ra8_usb_host_bulk_in().

Referenced by internal_read_csw(), and internal_run_data_in().

◆ internal_run_data_in()

ra8_err_t internal_run_data_in ( uint8_t target_lun,
const uint8_t * cdb,
uint8_t cdb_len,
uint8_t * out_buf,
uint16_t * inout_len )
static

◆ internal_run_data_out()

ra8_err_t internal_run_data_out ( uint8_t target_lun,
const uint8_t * cdb,
uint8_t cdb_len,
const uint8_t * in_buf,
uint16_t push_len )
static

◆ internal_send_cbw()

ra8_err_t internal_send_cbw ( const uint8_t * cbw)
static

Push a CBW out on the bulk-OUT pipe.

The starter ignores the low-level transfer status that ra8_usb_queue_in returns – the CSW phase is what the caller checks. Production should propagate transfer errors here.

Parameters
[in]cbwSee declaration: const uint8_t* cbw.
Returns
ra8_err_t outcome (or scalar return value).
Return values
k_ra8_okOperation completed successfully.
otherNon-zero error code from the underlying operation.
Precondition
Module/state preconditions hold (see function body).
Module/state preconditions hold (see function body).
Postcondition
Documented side effects are visible on success.
Documented side effects are visible on success.
Note
Internal helper. Not thread-safe; caller provides synchronisation.
Since
0.1.0

Definition at line 538 of file ra8_usb_hmsc.c.

References g_usb_hmsc_state, k_ra8_hmsc_cbw_len, k_ra8_hmsc_pipe_bulk_out, and ra8_usb_host_bulk_out().

Referenced by internal_issue_cbw().

◆ internal_unpack_u32_be()

uint32_t internal_unpack_u32_be ( const uint8_t * src)
static

Assemble a 32-bit word from four big-endian bytes.

Reads src[0..3] most-significant-byte-first (the SCSI/BOT on-wire byte order) and packs them into a host-order uint32_t. Used to decode the READ_CAPACITY(10) block-count and block-size fields.

Parameters
[in]srcPointer to at least 4 readable bytes in big-endian order.
Returns
The reconstructed 32-bit value, where src[0] supplies bits 31..24.
Return values
0All four source bytes are zero.
otherThe big-endian value (src[0]<<24)|(src[1]<<16)|(src[2]<<8)|src[3].
Precondition
src is non-NULL and points to >= 4 readable bytes.
The four bytes are laid out most-significant-first.
Postcondition
The returned value equals the big-endian interpretation of the bytes.
No module state is modified (pure function).
Note
Internal helper. Not thread-safe; caller provides synchronisation.
Since
0.1.0

Definition at line 323 of file ra8_usb_hmsc.c.

References k_ra8_hmsc_shift_byte0, k_ra8_hmsc_shift_byte1, k_ra8_hmsc_shift_byte2, and k_ra8_hmsc_shift_byte3.

Referenced by ra8_usb_hmsc_read_capacity().

◆ internal_unpack_u32_le()

uint32_t internal_unpack_u32_le ( const uint8_t * src)
static

◆ internal_zero_bytes()

void internal_zero_bytes ( uint8_t * dst,
uint16_t len )
static

Zero len bytes at dst byte-by-byte.

Avoids memset so the project's clang-tidy clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling gate stays clean. The starter never zeros buffers > 64 bytes so the loop overhead is negligible.

Parameters
[out]dstSee declaration: uint8_t* dst.
[in]lenSee declaration: uint16_t len.
Precondition
Module/state preconditions hold (see function body).
Module/state preconditions hold (see function body).
Postcondition
Documented side effects are visible on success.
Documented side effects are visible on success.
Note
Internal helper. Not thread-safe; caller provides synchronisation.
Since
0.1.0

Definition at line 348 of file ra8_usb_hmsc.c.

Referenced by internal_build_inquiry_cdb(), internal_build_read_capacity_cdb(), internal_build_rw10_cdb(), internal_decode_inquiry(), and ra8_usb_hmsc_build_cbw().

◆ ra8_usb_hmsc_attach_callback()

ra8_err_t ra8_usb_hmsc_attach_callback ( ra8_usb_hmsc_attach_fn_t on_attach,
void * ctx )
nodiscard

Register (or detach) the attach callback.

The supplied callback fires exactly once per attach event, after the descriptor walk identifies an MSC interface (class=0x08 / subclass=0x06 SCSI / protocol=0x50 BBB) and the Get-Max-LUN class request lands. Pass NULL to detach.

Parameters
[in]on_attachCallback. NULL detaches.
[in]ctxContext pointer threaded back into on_attach.
Returns
ra8_err_t error code.
Return values
k_ra8_okCallback installed.
k_ra8_err_invalid_stateDriver was never initialized.
Precondition
ra8_usb_hmsc_init has run.
Postcondition
On a subsequent attach, on_attach(ctx, &device) fires once.
Note
Not thread-safe.
Since
0.1.0

Definition at line 489 of file ra8_usb_hmsc.c.

References g_usb_hmsc_state, k_ra8_err_invalid_state, and k_ra8_ok.

◆ ra8_usb_hmsc_build_cbw()

ra8_err_t ra8_usb_hmsc_build_cbw ( uint8_t target_lun,
uint32_t data_transfer_length,
bool data_in,
const uint8_t * cdb,
uint8_t cdb_len,
uint8_t * out_cbw )
nodiscard

Construct the 31-byte CBW header for the given SCSI command.

Test / debug entry point. Production code uses this internally; the unit-test build calls it directly to prove the CBW layout (signature 'USBC', tag, dCBWDataTransferLength, bmCBWFlags direction bit, LUN, CDB length, CDB bytes) matches USB MSC BBB rev 1.0 sec 5.1.

Parameters
[in]target_lunLogical unit (0..15).
[in]data_transfer_lengthdCBWDataTransferLength field.
[in]data_intrue for IN (device-to-host), false for OUT.
[in]cdb6 / 10 / 12-byte SCSI Command Descriptor Block.
[in]cdb_lenLength of the CDB in bytes (1..16).
[out]out_cbwReceives the 31-byte CBW header.
Returns
ra8_err_t error code.
Return values
k_ra8_okCBW constructed.
k_ra8_err_null_ptrcdb or out_cbw was NULL.
k_ra8_err_invalid_argcdb_len out of range or target_lun out of range.
Precondition
cdb, out_cbw non-NULL.
Postcondition
out_cbw[0..3] == 0x55, 0x53, 0x42, 0x43 (CBW signature 'USBC', little-endian on wire).
out_cbw[14] == cdb_len.
Note
Not thread-safe; bumps the internal BOT tag counter.
Since
0.1.0

Definition at line 369 of file ra8_usb_hmsc.c.

References internal_copy_bytes(), internal_next_tag(), internal_pack_u32_le(), internal_zero_bytes(), k_ra8_err_invalid_arg, k_ra8_hmsc_cbw_flag_data_in, k_ra8_hmsc_cbw_flag_data_out, k_ra8_hmsc_cbw_len, k_ra8_hmsc_cbw_off_cdb, k_ra8_hmsc_cbw_off_cdb_length, k_ra8_hmsc_cbw_off_data_length, k_ra8_hmsc_cbw_off_flags, k_ra8_hmsc_cbw_off_lun, k_ra8_hmsc_cbw_off_signature, k_ra8_hmsc_cbw_off_tag, k_ra8_hmsc_cbw_signature, k_ra8_hmsc_cdb_field_mask, k_ra8_hmsc_cdb_max_len, k_ra8_hmsc_lun_field_mask, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by internal_issue_cbw().

◆ ra8_usb_hmsc_close()

ra8_err_t ra8_usb_hmsc_close ( void )
nodiscard

Tear down the host-MSC driver and release the controller.

Returns
ra8_err_t error code.
Return values
k_ra8_okReleased.
k_ra8_err_invalid_stateDriver was never initialized.
Precondition
Single-threaded shutdown context.
Postcondition
ra8_usb_host_deinit ran; SOF generation halted; bus power dropped; subsequent host-MSC API calls return k_ra8_err_invalid_state.
Note
Not thread-safe.
Since
0.1.0

Definition at line 469 of file ra8_usb_hmsc.c.

References g_usb_hmsc_state, k_ra8_err_invalid_state, ra8_usb_host_deinit(), and ra8_usb_host_set_uact().

Referenced by fileops_run_ladder(), microsd_host_enumerate(), microsd_host_pass(), mlun_host_enumerate(), mlun_host_pass(), ospirw_host_enumerate(), ospirw_host_pass(), selftest_host_enumerate(), selftest_host_enumerate(), selftest_host_enumerate(), selftest_host_enumerate(), selftest_host_enumerate(), selftest_host_pass(), selftest_host_pass(), wlun_host_enumerate(), and wlun_host_pass().

◆ ra8_usb_hmsc_decode_csw()

ra8_err_t ra8_usb_hmsc_decode_csw ( const uint8_t * csw,
uint32_t expected_tag,
ra8_usb_hmsc_csw_status_t * out_status )
nodiscard

Decode a 13-byte CSW.

Test / debug entry point. Validates the signature ('USBS'), the tag echo, and returns the decoded status byte.

Parameters
[in]cswPointer to the 13-byte CSW buffer.
[in]expected_tagdCBWTag from the CBW that initiated the transfer.
[out]out_statusDecoded CSW status byte.
Returns
ra8_err_t error code.
Return values
k_ra8_okSignature + tag match; *out_status valid.
k_ra8_err_null_ptrEither pointer was NULL.
k_ra8_err_invalid_argSignature mismatch or tag mismatch.
Precondition
csw, out_status non-NULL.
Postcondition
On success *out_status is one of k_ra8_hmsc_csw_status_passed, ..._failed, ..._phase_error.
Note
Not thread-safe.
Since
0.1.0

Definition at line 414 of file ra8_usb_hmsc.c.

References internal_unpack_u32_le(), k_ra8_err_invalid_arg, k_ra8_hmsc_csw_off_signature, k_ra8_hmsc_csw_off_status, k_ra8_hmsc_csw_off_tag, k_ra8_hmsc_csw_signature, k_ra8_hmsc_csw_status_failed, k_ra8_hmsc_csw_status_passed, k_ra8_hmsc_csw_status_phase_error, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by internal_read_csw().

◆ ra8_usb_hmsc_init()

ra8_err_t ra8_usb_hmsc_init ( ra8_usb_speed_t speed)
nodiscard

Bring up the host-MSC driver on a chosen USB controller.

Initialises the underlying ra8_usb driver in HOST mode for speed, primes the BOT tag counter, leaves the bus in the "wait for attach" state (UACT cleared), and arms the internal enumeration step machine.

Parameters
[in]speedWhich USB controller (FS or HS).
Returns
ra8_err_t error code.
Return values
k_ra8_okHost-MSC ready, awaiting attach.
k_ra8_err_invalid_argspeed out of range.
k_ra8_err_hw_init_failedUnderlying ra8_usb_host_init failed.
Precondition
Single-threaded init context.
ra8_mstp_init and ra8_pwr_init already ran.
Postcondition
ra8_usb_host_init succeeded for speed.
Internal step machine armed; attach callback has not fired.
Note
Not thread-safe.
See also
ra8_usb_hmsc_attach_callback
ra8_usb_hmsc_close
Since
0.1.0

Definition at line 446 of file ra8_usb_hmsc.c.

References g_usb_hmsc_state, k_ra8_err_hw_init_failed, k_ra8_err_invalid_arg, k_ra8_hmsc_initial_tag, k_ra8_ok, k_ra8_usb_speed_fs, k_ra8_usb_speed_hs, ra8_log_error_val, ra8_log_info_val, ra8_usb_host_init(), and s_tag.

Referenced by fileops_run_ladder(), microsd_host_pass(), mlun_host_pass(), ospirw_host_pass(), selftest_host_enumerate(), selftest_host_enumerate(), selftest_host_enumerate(), selftest_host_enumerate(), selftest_host_enumerate(), and wlun_host_pass().

◆ ra8_usb_hmsc_inquiry()

ra8_err_t ra8_usb_hmsc_inquiry ( uint8_t target_lun,
ra8_usb_hmsc_inquiry_response_t * response )
nodiscard

Issue a SCSI INQUIRY (opcode 0x12) over BBB.

Builds a 6-byte SCSI CDB, wraps it in a 31-byte CBW (signature 'USBC' / 0x43425355), pushes CBW on bulk-OUT, drains the 36-byte response on bulk-IN, then drains the 13-byte CSW (signature 'USBS' / 0x53425355). On success *response is filled in.

Parameters
[in]target_lunLogical unit (0..max_lun).
[out]responseDecoded INQUIRY response.
Returns
ra8_err_t error code.
Return values
k_ra8_okINQUIRY succeeded.
k_ra8_err_null_ptrresponse was NULL.
k_ra8_err_invalid_stateDriver not initialized, or no device attached.
k_ra8_err_invalid_argtarget_lun out of range.
k_ra8_err_hw_errorBBB transfer failed (CSW status != 0).
Precondition
ra8_usb_hmsc_init succeeded.
Attach callback already fired.
Postcondition
On success, *response reflects the device's INQUIRY data.
Note
Not thread-safe.
Since
0.1.0

Definition at line 780 of file ra8_usb_hmsc.c.

References internal_build_inquiry_cdb(), internal_check_ready(), internal_decode_inquiry(), internal_run_data_in(), k_ra8_hmsc_cdb6_len, k_ra8_hmsc_cdb_max_len, k_ra8_hmsc_inquiry_resp_len, k_ra8_ok, RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, and s_tag.

◆ ra8_usb_hmsc_read10()

ra8_err_t ra8_usb_hmsc_read10 ( uint8_t target_lun,
uint32_t lba,
uint16_t block_count,
uint8_t * out_buf )
nodiscard

Issue a SCSI READ(10) (opcode 0x28) over BBB.

Reads block_count contiguous blocks starting at lba into out_buf. Caller is responsible for sizing out_buf to at least block_count * block_size bytes (use the value returned by ra8_usb_hmsc_read_capacity).

Parameters
[in]target_lunLogical unit (0..max_lun).
[in]lbaStarting logical block address.
[in]block_countNumber of blocks to read (1..65535).
[out]out_bufDestination buffer, sized appropriately.
Returns
ra8_err_t error code.
Return values
k_ra8_okRead complete.
k_ra8_err_null_ptrout_buf was NULL.
k_ra8_err_invalid_stateDriver not initialized, or no device attached.
k_ra8_err_invalid_argArgument out of range (zero block count, bogus LUN).
k_ra8_err_hw_errorBBB transfer failed.
Precondition
ra8_usb_hmsc_init succeeded.
Attach callback already fired.
Postcondition
On success, out_buf holds the read data.
Note
Not thread-safe.
Since
0.1.0

Definition at line 827 of file ra8_usb_hmsc.c.

References internal_build_rw10_cdb(), internal_check_ready(), internal_run_data_in(), k_ra8_err_invalid_arg, k_ra8_hmsc_block_size_default, k_ra8_hmsc_cdb10_len, k_ra8_hmsc_cdb_max_len, k_ra8_hmsc_scsi_read_10, k_ra8_ok, RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, and s_tag.

Referenced by internal_usbmsc_read(), microsd_verify_one(), mlun_verify_one(), ospirw_verify_one(), selftest_browse_root(), selftest_verify_mram_raw(), selftest_verify_mram_raw(), selftest_verify_mram_raw(), selftest_verify_mram_raw(), selftest_verify_ospi_raw(), and wlun_verify_one().

◆ ra8_usb_hmsc_read_capacity()

ra8_err_t ra8_usb_hmsc_read_capacity ( uint8_t target_lun,
uint32_t * block_count,
uint32_t * block_size )
nodiscard

Issue a SCSI READ CAPACITY(10) (opcode 0x25) over BBB.

Reads the device's logical block count and block size. The 8-byte response holds the LAST valid LBA (block count - 1) and the block size, both big-endian on the wire; this function decodes both and adds 1 to the LBA so *block_count is the inclusive total.

Parameters
[in]target_lunLogical unit (0..max_lun).
[out]block_countTotal number of blocks on the LUN.
[out]block_sizeBlock size in bytes (typically 512).
Returns
ra8_err_t error code.
Return values
k_ra8_okCapacity read.
k_ra8_err_null_ptrEither pointer was NULL.
k_ra8_err_invalid_stateDriver not initialized, or no device attached.
k_ra8_err_invalid_argtarget_lun out of range.
k_ra8_err_hw_errorBBB transfer failed.
Precondition
ra8_usb_hmsc_init succeeded.
Attach callback already fired.
Postcondition
On success, both outputs are non-zero.
Note
Not thread-safe.
Since
0.1.0

Definition at line 799 of file ra8_usb_hmsc.c.

References internal_build_read_capacity_cdb(), internal_check_ready(), internal_run_data_in(), internal_unpack_u32_be(), k_ra8_hmsc_block_size_default, k_ra8_hmsc_cap_off_blk_size, k_ra8_hmsc_cap_off_last_lba, k_ra8_hmsc_cdb10_len, k_ra8_hmsc_cdb_max_len, k_ra8_hmsc_read_capacity_resp_len, k_ra8_ok, RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, and s_tag.

Referenced by internal_usbmsc_get_caps(), microsd_verify_one(), mlun_verify_one(), ospirw_verify_one(), and wlun_verify_one().

◆ ra8_usb_hmsc_write10()

ra8_err_t ra8_usb_hmsc_write10 ( uint8_t target_lun,
uint32_t lba,
uint16_t block_count,
const uint8_t * in_buf )
nodiscard

Issue a SCSI WRITE(10) (opcode 0x2A) over BBB.

Writes block_count contiguous blocks starting at lba from in_buf. Caller is responsible for sizing in_buf to at least block_count * block_size bytes.

Parameters
[in]target_lunLogical unit (0..max_lun).
[in]lbaStarting logical block address.
[in]block_countNumber of blocks to write (1..65535).
[in]in_bufSource buffer, sized appropriately.
Returns
ra8_err_t error code.
Return values
k_ra8_okWrite complete.
k_ra8_err_null_ptrin_buf was NULL.
k_ra8_err_invalid_stateDriver not initialized, or no device attached.
k_ra8_err_invalid_argArgument out of range.
k_ra8_err_hw_errorBBB transfer failed.
Precondition
ra8_usb_hmsc_init succeeded.
Attach callback already fired.
Postcondition
On success the device has accepted all block_count blocks.
Note
Not thread-safe.
Since
0.1.0

Definition at line 851 of file ra8_usb_hmsc.c.

References internal_build_rw10_cdb(), internal_check_ready(), internal_run_data_out(), k_ra8_err_invalid_arg, k_ra8_hmsc_block_size_default, k_ra8_hmsc_cdb10_len, k_ra8_hmsc_cdb_max_len, k_ra8_hmsc_scsi_write_10, k_ra8_ok, RA8_CHECK_NULL_PTR, RA8_RETURN_ON_ERROR, and s_tag.

Referenced by internal_usbmsc_write(), ospirw_write_disk(), selftest_write_protect_probe(), selftest_write_protect_probe(), selftest_write_protect_probe(), selftest_write_protect_probe(), selftest_write_protect_probe(), and wlun_write_disk().

Variable Documentation

◆ g_usb_hmsc_state

ra8_usb_hmsc_state_t g_usb_hmsc_state = {}

Singleton host-MSC shadow state, shared across the ra8_usb_hmsc split.

Single definition lives in ra8_usb_hmsc.c; ra8_usb_hmsc_enum.c reads and writes the same object through this extern declaration. The mutable state (attach flags, negotiated speed, device snapshot, BOT tag counter) must remain one object so the enumeration ladder and the command path agree on the attached device.

Note
Module-private to libs/ra8_hal/src; not part of the public surface.
Warning
Not thread-safe; callers must serialise concurrent access.
Since
0.1.0

Definition at line 222 of file ra8_usb_hmsc.c.

Referenced by internal_check_ready(), internal_enum_assign_addr(), internal_enum_configure(), internal_enum_fill_ids(), internal_enum_hunt(), internal_enum_note_endpoint(), internal_enum_publish(), internal_enum_read_config(), internal_enum_read_dev_desc(), internal_enum_walk_cfg(), internal_next_tag(), internal_recv_bytes(), internal_run_data_out(), internal_send_cbw(), ra8_usb_hmsc_attach_callback(), ra8_usb_hmsc_close(), ra8_usb_hmsc_enumerate(), and ra8_usb_hmsc_init().

◆ s_tag

const char* s_tag = "USBHMSC"
static

Definition at line 61 of file ra8_usb_hmsc.c.