|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Native USB device-side MSC (Mass Storage Class) class layer implementation. More...
#include "ra8_usb_pmsc.h"#include <stdint.h>#include "ra8_attributes.h"#include "ra8_check.h"#include "ra8_err.h"#include "ra8_log.h"#include "ra8_usb.h"#include "ra8_usb_pmsc_internal.h"Go to the source code of this file.
Functions | |
| static uint16_t | internal_bulk_max_packet (ra8_usb_speed_t speed) |
| Pick the bulk-max-packet ceiling matching the negotiated speed. | |
| static void | internal_configure_pipes (void) |
| Configure the two device-MSC bulk pipes against the local endpoints. | |
| static void | internal_pack_u32_le (uint32_t value, uint8_t *dst) |
| Pack a uint32 into 4 little-endian bytes. | |
| static uint32_t | internal_unpack_u32_le (const uint8_t *src) |
| Unpack a uint32 from 4 little-endian bytes. | |
| void | priv_zero_bytes (uint8_t *dst, uint32_t len) |
| Zero len bytes at dst byte-by-byte. | |
| static void | internal_copy_bytes (uint8_t *dst, const uint8_t *src, uint32_t len) |
| Copy len bytes from src to dst byte-by-byte. | |
| ra8_err_t | ra8_usb_pmsc_feed_cbw (const uint8_t *cbw) |
| Inject a CBW directly into the BOT state machine. | |
| static ra8_err_t | internal_dispatch_scsi (uint8_t *data_buf, uint32_t data_buf_capacity, uint32_t *data_len, ra8_usb_pmsc_csw_status_t *csw_status) |
| Dispatch the cached CDB to the right SCSI handler. | |
| static ra8_err_t | internal_dispatch_preconditions (uint32_t data_buf_capacity) |
| Validate dispatch_command preconditions (driver state + bot phase + buffer capacity). | |
| static void | internal_dispatch_advance_state (uint32_t data_len) |
| Advance BOT state after a successful CDB dispatch. | |
| ra8_err_t | ra8_usb_pmsc_dispatch_command (uint8_t *data_buf, uint32_t data_buf_capacity, uint32_t *data_len, ra8_usb_pmsc_csw_status_t *csw_status) |
| Run the SCSI command currently parked in the BOT state. | |
| ra8_err_t | ra8_usb_pmsc_build_csw (ra8_usb_pmsc_csw_status_t csw_status, uint32_t residue, uint8_t *out_csw) |
| Build the 13-byte CSW for the in-flight command. | |
| ra8_err_t | ra8_usb_pmsc_step (void) |
| Drive the BOT (Bulk-Only Transport) state machine forward by one step. | |
| ra8_err_t | ra8_usb_pmsc_attach_storage (const ra8_usb_pmsc_storage_t *storage) |
| Bind a caller-owned storage backend to the device-MSC class. | |
| ra8_err_t | ra8_usb_pmsc_init (ra8_usb_speed_t speed) |
| Bring up the device-MSC driver on a chosen USB controller. | |
| ra8_err_t | ra8_usb_pmsc_close (void) |
| Tear down the device-MSC driver and release the controller. | |
Variables | |
| static const char * | s_tag = "USBPMSC" |
| ra8_usb_pmsc_state_data_t | g_usb_pmsc_state = {} |
| Singleton shadow state shared by both device-MSC TUs. | |
Native USB device-side MSC (Mass Storage Class) class layer implementation.
Glues the device-mode bring-up paths in ra8_usb to a USB Mass Storage Class (Bulk-Only-Transport / BBB) function so the EK-RA8D2 appears as a USB drive on the host side. This file is the native device-MSC class layer; FSP's r_usb_pmsc_driver.c, r_usb_pmsc.c, and r_media_driver_api.c are reference material only – no FSP source is pulled in verbatim.
Mapping vs FSP (FSP function -> our entry point):
The starter is single-LUN, single-instance. Get-Max-LUN returns 0; Mass Storage Reset rewinds the state machine to IDLE.
BOT (Bulk-Only Transport) state machine – per command:
IDLE -> CBW_RX (pull 31-byte CBW) -> CDB_DECODE -> DATA_TX (push read data) | DATA_RX (pull write data) -> CSW_TX (push 13-byte CSW) -> IDLE
On invalid CBW signature the spec mandates phase-error CSW, which the starter emits by transitioning straight to CSW_TX with status k_ra8_pmsc_csw_status_phase_error.
Definition in file ra8_usb_pmsc.c.
| enum ra8_usb_pmsc_cbw_flag_t : uint8_t |
bmCBWFlags direction bit values.
| Enumerator | |
|---|---|
| k_ra8_pmsc_cbw_flag_data_out | Host -> device. |
| k_ra8_pmsc_cbw_flag_data_in | Device -> host. |
Definition at line 97 of file ra8_usb_pmsc.c.
| enum ra8_usb_pmsc_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".
Definition at line 69 of file ra8_usb_pmsc.c.
| enum ra8_usb_pmsc_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_pmsc_csw_off_signature | dCSWSignature [4]. |
| k_ra8_pmsc_csw_off_tag | dCSWTag [4]. |
| k_ra8_pmsc_csw_off_residue | dCSWDataResidue. |
| k_ra8_pmsc_csw_off_status | bCSWStatus. |
Definition at line 86 of file ra8_usb_pmsc.c.
| enum ra8_usb_pmsc_initial_tag_t : uint32_t |
Initial value of the cached BOT dCBWTag.
| Enumerator | |
|---|---|
| k_ra8_pmsc_initial_tag | Reset value. |
Definition at line 118 of file ra8_usb_pmsc.c.
| enum ra8_usb_pmsc_lun_mask_t : uint8_t |
Field-width masks for 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_pmsc_lun_field_mask | Low 4 bits of bCBWLUN. |
| k_ra8_pmsc_cdb_field_mask | Low 5 bits of bCBWCBLen. |
Definition at line 129 of file ra8_usb_pmsc.c.
| enum ra8_usb_pmsc_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_pmsc_cbw_signature | 'USBC' little-endian. |
| k_ra8_pmsc_csw_signature | 'USBS' little-endian. |
Definition at line 109 of file ra8_usb_pmsc.c.
|
static |
Pick the bulk-max-packet ceiling matching the negotiated speed.
See implementation.
| [in] | speed | See implementation. |
speed. | k_ra8_pmsc_bulk_max_packet_hs | speed is k_ra8_usb_speed_hs. |
| k_ra8_pmsc_bulk_max_packet_fs | Any other speed. |
Definition at line 163 of file ra8_usb_pmsc.c.
References k_ra8_pmsc_bulk_max_packet_fs, k_ra8_pmsc_bulk_max_packet_hs, and k_ra8_usb_speed_hs.
Referenced by internal_configure_pipes().
|
static |
Configure the two device-MSC bulk pipes against the local endpoints.
Mirrors FSP's usb_pstd_pipe_table writes condensed for the MSC case. PIPE3 = bulk-IN, PIPE4 = bulk-OUT, matching the host-MSC layer for symmetry.
Definition at line 185 of file ra8_usb_pmsc.c.
References g_usb_pmsc_state, internal_bulk_max_packet(), k_ra8_pmsc_ep_bulk_in, k_ra8_pmsc_ep_bulk_out, k_ra8_pmsc_pipe_bulk_in, k_ra8_pmsc_pipe_bulk_out, k_ra8_usb_ep_dir_in, k_ra8_usb_ep_dir_out, k_ra8_usb_ep_type_bulk, and ra8_usb_configure_endpoint().
Referenced by ra8_usb_pmsc_init().
|
static |
Copy len bytes from src to dst byte-by-byte.
See implementation.
| [in] | dst | See implementation. |
| [in] | src | See implementation. |
| [in] | len | See implementation. |
Definition at line 272 of file ra8_usb_pmsc.c.
Referenced by ra8_usb_pmsc_feed_cbw().
|
static |
Advance BOT state after a successful CDB dispatch.
See implementation.
| [in] | data_len | See implementation. |
Definition at line 418 of file ra8_usb_pmsc.c.
References g_usb_pmsc_state, k_ra8_pmsc_state_csw_tx, k_ra8_pmsc_state_data_rx, and k_ra8_pmsc_state_data_tx.
Referenced by ra8_usb_pmsc_dispatch_command().
|
static |
Validate dispatch_command preconditions (driver state + bot phase + buffer capacity).
See implementation.
| [in] | data_buf_capacity | See implementation. |
| k_ra8_ok | Operation succeeded. |
Definition at line 388 of file ra8_usb_pmsc.c.
References g_usb_pmsc_state, k_ra8_err_invalid_size, k_ra8_err_invalid_state, k_ra8_ok, and k_ra8_pmsc_state_cdb_decode.
Referenced by ra8_usb_pmsc_dispatch_command().
|
static |
Dispatch the cached CDB to the right SCSI handler.
Helper for ra8_usb_pmsc_dispatch_command. Returns k_ra8_ok and a populated *data_len on a supported opcode; sets *csw_status to failed on an unsupported opcode and leaves *data_len zero.
| [in] | data_buf | See implementation. |
| [in] | data_buf_capacity | See implementation. |
| [in] | data_len | See implementation. |
| [in] | csw_status | See implementation. |
| k_ra8_ok | Operation succeeded. |
Definition at line 343 of file ra8_usb_pmsc.c.
References g_usb_pmsc_state, k_ra8_ok, k_ra8_pmsc_cdb_off_opcode, k_ra8_pmsc_csw_status_failed, k_ra8_pmsc_scsi_inquiry, k_ra8_pmsc_scsi_mode_sense_6, k_ra8_pmsc_scsi_read_10, k_ra8_pmsc_scsi_read_capacity_10, k_ra8_pmsc_scsi_request_sense, k_ra8_pmsc_scsi_test_unit_ready, k_ra8_pmsc_scsi_write_10, priv_handle_inquiry(), priv_handle_mode_sense(), priv_handle_read10(), priv_handle_read_capacity(), priv_handle_request_sense(), and priv_handle_write10().
Referenced by ra8_usb_pmsc_dispatch_command().
|
static |
Pack a uint32 into 4 little-endian bytes.
See implementation.
| [in] | value | See implementation. |
| [in] | dst | See implementation. |
Definition at line 219 of file ra8_usb_pmsc.c.
References k_ra8_pmsc_byte_mask, k_ra8_pmsc_shift_byte0, k_ra8_pmsc_shift_byte1, k_ra8_pmsc_shift_byte2, and k_ra8_pmsc_shift_byte3.
Referenced by ra8_usb_pmsc_build_csw().
|
static |
Unpack a uint32 from 4 little-endian bytes.
See implementation.
| [in] | src | See implementation. |
| k_ra8_ok | Operation succeeded. |
Definition at line 242 of file ra8_usb_pmsc.c.
References k_ra8_pmsc_shift_byte0, k_ra8_pmsc_shift_byte1, k_ra8_pmsc_shift_byte2, and k_ra8_pmsc_shift_byte3.
Referenced by ra8_usb_pmsc_feed_cbw().
| void priv_zero_bytes | ( | uint8_t * | dst, |
| uint32_t | len ) |
Zero len bytes at dst byte-by-byte.
Avoids memset so the project's clang-tidy clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling gate stays clean. Defined in ra8_usb_pmsc.c, shared with the SCSI handler TU.
| [out] | dst | Destination buffer (non-null, at least len bytes). |
| [in] | len | Byte count to clear. |
Definition at line 250 of file ra8_usb_pmsc.c.
Referenced by priv_handle_inquiry(), priv_handle_mode_sense(), priv_handle_read_capacity(), priv_handle_request_sense(), ra8_usb_pmsc_build_csw(), and ra8_usb_pmsc_init().
|
nodiscard |
Bind a caller-owned storage backend to the device-MSC class.
The four function pointers in storage are validated for NULL and the struct is copied into internal state. After this call the BOT state machine can answer SCSI commands the host issues.
| [in] | storage | Storage backend snapshot. Copied by value. |
| k_ra8_ok | Backend installed. |
| k_ra8_err_invalid_state | Driver not initialized. |
| k_ra8_err_null_ptr | storage was NULL or any callback was NULL. |
Definition at line 515 of file ra8_usb_pmsc.c.
References g_usb_pmsc_state, ra8_usb_pmsc_storage_t::get_capacity, ra8_usb_pmsc_storage_t::get_inquiry, k_ra8_err_invalid_state, k_ra8_ok, k_ra8_pmsc_state_idle, RA8_CHECK_NULL_PTR, ra8_log_info, ra8_usb_pmsc_storage_t::read_block, s_tag, and ra8_usb_pmsc_storage_t::write_block.
|
nodiscard |
Build the 13-byte CSW for the in-flight command.
Test / debug entry point. Production code calls this internally during the CSW_TX phase. The CSW is laid out per USB MSC BBB rev 1.0 sec 5.2: dCSWSignature='USBS', dCSWTag echoed from the CBW, dCSWDataResidue computed from the CBW dCBWDataTransferLength minus the actual byte count produced, bCSWStatus from csw_status.
| [in] | csw_status | Status byte to embed in the CSW. |
| [in] | residue | Bytes that were NOT transferred (CBW expected minus actual). |
| [out] | out_csw | Receives the 13-byte CSW buffer. |
| k_ra8_ok | CSW constructed. |
| k_ra8_err_null_ptr | out_csw was NULL. |
| k_ra8_err_invalid_state | Driver not initialized, or no CBW currently in-flight. |
Definition at line 454 of file ra8_usb_pmsc.c.
References g_usb_pmsc_state, internal_pack_u32_le(), k_ra8_err_invalid_state, k_ra8_ok, k_ra8_pmsc_csw_len, k_ra8_pmsc_csw_off_residue, k_ra8_pmsc_csw_off_signature, k_ra8_pmsc_csw_off_status, k_ra8_pmsc_csw_off_tag, k_ra8_pmsc_csw_signature, k_ra8_pmsc_state_idle, priv_zero_bytes(), RA8_CHECK_NULL_PTR, and s_tag.
|
nodiscard |
Tear down the device-MSC driver and release the controller.
| k_ra8_ok | Released. |
| k_ra8_err_invalid_state | Driver was never initialized. |
Definition at line 568 of file ra8_usb_pmsc.c.
References g_usb_pmsc_state, k_ra8_err_invalid_state, k_ra8_pmsc_state_idle, ra8_usb_device_attach(), and ra8_usb_device_deinit().
|
nodiscard |
Run the SCSI command currently parked in the BOT state.
Test / debug entry point. After ra8_usb_pmsc_feed_cbw accepts a CBW, this routine invokes the storage backend (if any) and stages the data-phase output buffer / pulls the CSW status byte. On unsupported opcodes the CSW status is set to k_ra8_pmsc_csw_status_failed.
| [out] | data_buf | Buffer that receives the data-IN payload (or provides the data-OUT payload). Caller sized to at least data_buf_capacity bytes. |
| [in] | data_buf_capacity | Capacity of data_buf in bytes. |
| [out] | data_len | Receives the actual data byte count produced / consumed. |
| [out] | csw_status | Receives the CSW status byte the device will emit at the end of the transaction. |
| k_ra8_ok | Command dispatched (the CSW status byte may still be k_ra8_pmsc_csw_status_failed). |
| k_ra8_err_null_ptr | Any output pointer was NULL. |
| k_ra8_err_invalid_state | Driver not initialized, storage not attached, or no CBW currently in-flight. |
| k_ra8_err_invalid_size | data_buf_capacity was 0. |
Definition at line 429 of file ra8_usb_pmsc.c.
References internal_dispatch_advance_state(), internal_dispatch_preconditions(), internal_dispatch_scsi(), k_ra8_ok, k_ra8_pmsc_csw_status_failed, k_ra8_pmsc_csw_status_passed, RA8_CHECK_NULL_PTR, and s_tag.
|
nodiscard |
Inject a CBW directly into the BOT state machine.
Test / debug entry point. Production code receives CBWs from the bulk-OUT pipe; tests bypass the FIFO and feed the 31-byte buffer directly. Returns k_ra8_err_invalid_arg on signature mismatch (USB MSC BBB rev 1.0 sec 6.2.1 "Valid CBW").
| [in] | cbw | Pointer to a 31-byte CBW. |
| k_ra8_ok | CBW accepted; state machine now in CDB_DECODE. |
| k_ra8_err_null_ptr | cbw was NULL. |
| k_ra8_err_invalid_state | Driver not initialized, or storage not attached. |
| k_ra8_err_invalid_arg | Signature mismatch (CBW invalid). In this case the BOT machine transitions to a phase-error CSW_TX as required by USB MSC BBB rev 1.0 sec 6.6.1 "CBW Not Valid". |
Definition at line 284 of file ra8_usb_pmsc.c.
References g_usb_pmsc_state, internal_copy_bytes(), internal_unpack_u32_le(), k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_ok, k_ra8_pmsc_cbw_flag_data_in, k_ra8_pmsc_cbw_off_cdb, k_ra8_pmsc_cbw_off_cdb_length, k_ra8_pmsc_cbw_off_data_length, k_ra8_pmsc_cbw_off_flags, k_ra8_pmsc_cbw_off_lun, k_ra8_pmsc_cbw_off_signature, k_ra8_pmsc_cbw_off_tag, k_ra8_pmsc_cbw_signature, k_ra8_pmsc_cdb_field_mask, k_ra8_pmsc_cdb_max_len, k_ra8_pmsc_lun_field_mask, k_ra8_pmsc_state_cdb_decode, k_ra8_pmsc_state_csw_tx, RA8_CHECK_NULL_PTR, and s_tag.
|
nodiscard |
Bring up the device-MSC driver on a chosen USB controller.
Initialises the underlying ra8_usb driver in DEVICE mode for speed, configures the bulk-IN / bulk-OUT pipes (PIPE3 / PIPE4) with the speed-appropriate maximum packet size, primes the BOT state machine to the IDLE state, and zeroes the BOT command tag counter. D+ pull-up is left off so the application can publish the configuration descriptor before the host enumerates it.
| [in] | speed | Which USB controller (FS or HS). |
| k_ra8_ok | Device-MSC ready, awaiting attach_storage. |
| k_ra8_err_invalid_arg | speed out of range. |
| k_ra8_err_hw_init_failed | Underlying ra8_usb_device_init failed. |
Definition at line 538 of file ra8_usb_pmsc.c.
References g_usb_pmsc_state, internal_configure_pipes(), k_ra8_err_hw_init_failed, k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_pmsc_cdb_max_len, k_ra8_pmsc_initial_tag, k_ra8_pmsc_state_idle, k_ra8_usb_speed_fs, k_ra8_usb_speed_hs, priv_zero_bytes(), ra8_log_error_val, ra8_log_info_val, ra8_usb_device_init(), and s_tag.
|
nodiscard |
Drive the BOT (Bulk-Only Transport) state machine forward by one step.
Production code calls this from the bulk-OUT completion ISR. The state machine cycles through:
Each call advances by exactly one phase; the caller pumps the state machine until it idles back to CBW reception.
| k_ra8_ok | Step advanced. |
| k_ra8_err_invalid_state | Driver not initialized, or storage not attached. |
Definition at line 470 of file ra8_usb_pmsc.c.
References g_usb_pmsc_state, k_ra8_err_invalid_state, k_ra8_ok, k_ra8_pmsc_state_cbw_rx, k_ra8_pmsc_state_cdb_decode, k_ra8_pmsc_state_csw_tx, k_ra8_pmsc_state_data_rx, k_ra8_pmsc_state_data_tx, and k_ra8_pmsc_state_idle.
| ra8_usb_pmsc_state_data_t g_usb_pmsc_state = {} |
Singleton shadow state shared by both device-MSC TUs.
Defined in ra8_usb_pmsc.c; the SCSI handler TU reads the cached CDB and storage backend through this extern declaration.
Definition at line 139 of file ra8_usb_pmsc.c.
Referenced by internal_configure_pipes(), internal_dispatch_advance_state(), internal_dispatch_preconditions(), internal_dispatch_scsi(), priv_handle_inquiry(), priv_handle_read10(), priv_handle_read_capacity(), priv_handle_write10(), ra8_usb_pmsc_attach_storage(), ra8_usb_pmsc_build_csw(), ra8_usb_pmsc_close(), ra8_usb_pmsc_feed_cbw(), ra8_usb_pmsc_init(), and ra8_usb_pmsc_step().
|
static |
Definition at line 55 of file ra8_usb_pmsc.c.