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

Native USB host-side MSC (Mass Storage Class) polled enumeration ladder. More...

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

Go to the source code of this file.

Enumerations

enum  ra8_usb_hmsc_enum_tune_t : uint32_t {
  k_ra8_hmsc_vbus_settle_ms = 200U ,
  k_ra8_hmsc_attach_to_ms = 2000U ,
  k_ra8_hmsc_debounce_ms = 500U ,
  k_ra8_hmsc_reset_hold_ms = 50U ,
  k_ra8_hmsc_recovery_ms = 20U ,
  k_ra8_hmsc_addr_settle_ms = 5U ,
  k_ra8_hmsc_enum_tries = 8U ,
  k_ra8_hmsc_no_reset_tries = 4U ,
  k_ra8_hmsc_addr_alt_mask = 0x03U ,
  k_ra8_hmsc_cfg_buf_len = 128U ,
  k_ra8_hmsc_attach_spin_limit = 50000000UL
}
 Timing / retry tunables for the polled enumeration ladder. More...
enum  ra8_usb_hmsc_walk_off_t : uint8_t {
  k_ra8_hmsc_off_dlen = 0U ,
  k_ra8_hmsc_off_dtype = 1U ,
  k_ra8_hmsc_off_iface_num = 2U ,
  k_ra8_hmsc_off_iface_class = 5U ,
  k_ra8_hmsc_off_iface_sub = 6U ,
  k_ra8_hmsc_off_iface_proto = 7U ,
  k_ra8_hmsc_off_ep_addr = 2U ,
  k_ra8_hmsc_off_ep_attr = 3U ,
  k_ra8_hmsc_off_ep_mps = 4U ,
  k_ra8_hmsc_off_cfg_total = 2U ,
  k_ra8_hmsc_off_cfg_value = 5U ,
  k_ra8_hmsc_off_dev_vid = 8U ,
  k_ra8_hmsc_off_dev_pid = 10U ,
  k_ra8_hmsc_ep_dir_in_bit = 0x80U ,
  k_ra8_hmsc_ep_num_mask = 0x0FU ,
  k_ra8_hmsc_ep_attr_mask = 0x03U ,
  k_ra8_hmsc_ep_attr_bulk = 0x02U ,
  k_ra8_hmsc_byte_bits = 8U
}
 Descriptor-walk byte offsets and identity codes. More...

Functions

static ra8_err_t internal_enum_read_dev_desc (uint8_t *desc)
 Read the 18-byte device descriptor over the polled control engine.
static ra8_err_t internal_enum_hunt (uint8_t *desc, uint8_t *out_addr)
 Wait for a device to attach, then hunt for its address.
static ra8_err_t internal_enum_assign_addr (uint8_t *dev_addr)
 Move the device to address 1 when it answered at the default.
static void internal_enum_note_endpoint (const uint8_t *d)
 Record one bulk endpoint descriptor into the device snapshot.
static bool internal_enum_iface_is_msc (const uint8_t *d)
 Test whether an interface descriptor is MSC SCSI Bulk-Only.
static ra8_err_t internal_enum_walk_cfg (const uint8_t *cfg, uint16_t len)
 Walk a configuration blob for the MSC interface + bulk endpoints.
static ra8_err_t internal_enum_read_config (uint8_t *out_cfg_value)
 Read + parse the configuration descriptor set.
static ra8_err_t internal_enum_configure (uint8_t dev_addr, uint8_t cfg_value)
 SET_CONFIGURATION, best-effort GET_MAX_LUN, and pipe setup.
static void internal_enum_fill_ids (const uint8_t *desc)
 Unpack VID/PID from a device descriptor into the snapshot.
static void internal_enum_publish (uint8_t dev_addr, ra8_usb_hmsc_device_t *out_device)
 Publish a completed enumeration: snapshot, callback, out-copy.
static ra8_err_t internal_enum_ladder (uint8_t *out_addr)
 Run the enumeration ladder: hunt, address, configure, pipes.
ra8_err_t ra8_usb_hmsc_enumerate (ra8_usb_hmsc_device_t *out_device)
 Implementation of ra8_usb_hmsc_enumerate().

Variables

static const char * s_tag = "USBHMSC"

Detailed Description

Native USB host-side MSC (Mass Storage Class) polled enumeration ladder.

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

Sibling translation unit of ra8_usb_hmsc.c, split out purely to satisfy the per-file size cap. Holds the hardware-proven polled enumeration ladder (ra8_usb_hmsc_enumerate) and its internal_enum_* helpers: wait for the D+ attach, hunt the (reset, address) combination the device answers on, assign address 1, read + parse the configuration descriptor set, run SET_CONFIGURATION / GET_MAX_LUN, program the bulk pipes, and fire the attach callback. Every chapter-9 SETUP goes through ra8_usb_host_setup_request.

The singleton shadow state (g_usb_hmsc_state) lives in ra8_usb_hmsc.c and is shared with this TU through ra8_hal_internal.h.

Since
0.1.0

Definition in file ra8_usb_hmsc_enum.c.

Enumeration Type Documentation

◆ ra8_usb_hmsc_enum_tune_t

enum ra8_usb_hmsc_enum_tune_t : uint32_t

Timing / retry tunables for the polled enumeration ladder.

Enumerator
k_ra8_hmsc_vbus_settle_ms 

Supply settle before probing.

k_ra8_hmsc_attach_to_ms 

Wait for the D+ pull-up.

k_ra8_hmsc_debounce_ms 

Post-attach debounce (>=100 ms).

k_ra8_hmsc_reset_hold_ms 

USB bus-reset hold (>=10 ms).

k_ra8_hmsc_recovery_ms 

Post-reset recovery (TRSTRCY).

k_ra8_hmsc_addr_settle_ms 

Post-SET_ADDRESS recovery.

k_ra8_hmsc_enum_tries 

(reset?

, addr) hunt attempts.

k_ra8_hmsc_no_reset_tries 

Attempts before using bus reset.

k_ra8_hmsc_addr_alt_mask 

Alternate addr 0..3 per attempt.

k_ra8_hmsc_cfg_buf_len 

Full-configuration read buffer.

k_ra8_hmsc_attach_spin_limit 

P10 iteration bound on the attach wait: the loop is primarily ms-bounded via ra8_time_ms, but if the tick is frozen (fake builds, SysTick masked) the spin cap guarantees termination.

Definition at line 49 of file ra8_usb_hmsc_enum.c.

◆ ra8_usb_hmsc_walk_off_t

enum ra8_usb_hmsc_walk_off_t : uint8_t

Descriptor-walk byte offsets and identity codes.

Enumerator
k_ra8_hmsc_off_dlen 

Any descriptor: bLength.

k_ra8_hmsc_off_dtype 

Any descriptor: bDescriptorType.

k_ra8_hmsc_off_iface_num 

Interface: bInterfaceNumber.

k_ra8_hmsc_off_iface_class 

Interface: bInterfaceClass.

k_ra8_hmsc_off_iface_sub 

Interface: bInterfaceSubClass.

k_ra8_hmsc_off_iface_proto 

Interface: bInterfaceProtocol.

k_ra8_hmsc_off_ep_addr 

Endpoint: bEndpointAddress.

k_ra8_hmsc_off_ep_attr 

Endpoint: bmAttributes.

k_ra8_hmsc_off_ep_mps 

Endpoint: wMaxPacketSize LSB.

k_ra8_hmsc_off_cfg_total 

Configuration: wTotalLength LSB.

k_ra8_hmsc_off_cfg_value 

Configuration: bConfigValue.

k_ra8_hmsc_off_dev_vid 

Device: idVendor LSB.

k_ra8_hmsc_off_dev_pid 

Device: idProduct LSB.

k_ra8_hmsc_ep_dir_in_bit 

bEndpointAddress direction bit.

k_ra8_hmsc_ep_num_mask 

bEndpointAddress number field.

k_ra8_hmsc_ep_attr_mask 

bmAttributes transfer-type mask.

k_ra8_hmsc_ep_attr_bulk 

bmAttributes: bulk transfer.

k_ra8_hmsc_byte_bits 

Bit width of one byte.

Definition at line 70 of file ra8_usb_hmsc_enum.c.

Function Documentation

◆ internal_enum_assign_addr()

ra8_err_t internal_enum_assign_addr ( uint8_t * dev_addr)
static

Move the device to address 1 when it answered at the default.

SET_CONFIGURATION is only legal from the Address state (sticks STALL it at the default address), so assign address 1, honour the set-address recovery, and retarget the DCP. Skipped when the hunt already found the device addressed.

Parameters
[in,out]dev_addrIn: hunt result. Out: the operating address.
Returns
First failing step's error, or k_ra8_ok.
Return values
k_ra8_okThe DCP targets the operating address.
Precondition
internal_enum_hunt succeeded.
The bus is active (UACT on).
Postcondition
*dev_addr is non-zero on success.
Later transfers carry tokens to the new address.
Note
Blocking (one polled control transfer + settle).
Since
0.1.0

Definition at line 206 of file ra8_usb_hmsc_enum.c.

References g_usb_hmsc_state, k_ra8_hmsc_addr_settle_ms, k_ra8_hmsc_assigned_address, k_ra8_hmsc_bm_std_dev_out, k_ra8_hmsc_breq_set_address, k_ra8_ok, ra8_delay_ms(), RA8_RETURN_ON_ERROR, ra8_usb_host_control_xfer(), ra8_usb_host_set_target(), and s_tag.

Referenced by internal_enum_ladder().

◆ internal_enum_configure()

ra8_err_t internal_enum_configure ( uint8_t dev_addr,
uint8_t cfg_value )
static

SET_CONFIGURATION, best-effort GET_MAX_LUN, and pipe setup.

Activates the parsed configuration (strict status), issues the class GET_MAX_LUN (devices may STALL it, which legally means LUN 0, so failures default to 0), then programs the bulk pipes against the snapshot endpoints at dev_addr.

Parameters
[in]dev_addrAddress the device answers at.
[in]cfg_valuebConfigurationValue to activate.
Returns
First failing step's error, or k_ra8_ok.
Return values
k_ra8_okThe device is configured and both pipes are ready.
Precondition
internal_enum_read_config filled the snapshot.
The DCP targets dev_addr.
Postcondition
The bulk pipes are configured (DATA0, parked NAK).
g_usb_hmsc_state.device.max_lun is filled (0 on GET_MAX_LUN failure).
Note
Blocking (polled control transfers).
Since
0.1.0

Definition at line 417 of file ra8_usb_hmsc_enum.c.

References g_usb_hmsc_state, k_ra8_hmsc_bm_class_iface_in, k_ra8_hmsc_bm_std_dev_out, k_ra8_hmsc_breq_set_config, k_ra8_hmsc_get_max_lun_len, k_ra8_hmsc_pipe_bulk_in, k_ra8_hmsc_pipe_bulk_out, k_ra8_hmsc_req_get_max_lun, k_ra8_ok, RA8_RETURN_ON_ERROR, ra8_usb_host_control_xfer(), ra8_usb_host_pipe_setup(), and s_tag.

Referenced by internal_enum_ladder().

◆ internal_enum_fill_ids()

void internal_enum_fill_ids ( const uint8_t * desc)
static

Unpack VID/PID from a device descriptor into the snapshot.

Little-endian 16-bit fields at idVendor/idProduct.

Parameters
[in]descDevice descriptor bytes (18 valid bytes).
Precondition
desc is non-NULL and holds a device descriptor.
The snapshot was reset for this enumeration pass.
Postcondition
g_usb_hmsc_state.device.vendor_id / .product_id are filled.
desc is unmodified.
Note
Pure helper for ra8_usb_hmsc_enumerate.
Since
0.1.0

Definition at line 477 of file ra8_usb_hmsc_enum.c.

References g_usb_hmsc_state, k_ra8_hmsc_byte_bits, k_ra8_hmsc_off_dev_pid, and k_ra8_hmsc_off_dev_vid.

Referenced by internal_enum_ladder().

◆ internal_enum_hunt()

ra8_err_t internal_enum_hunt ( uint8_t * desc,
uint8_t * out_addr )
static

Wait for a device to attach, then hunt for its address.

Waits for the D+ pull-up (LNST leaves SE0) plus the spec debounce, then tries each (reset?, address) combination: four gentle attempts at addresses 0..3 without touching the bus, then four more with a full bus reset (which also returns a previously addressed device to address 0). The first combination whose device-descriptor read returns all 18 bytes wins.

Parameters
[out]descReceives the winning 18-byte device descriptor.
[out]out_addrReceives the address the device answered at.
Returns
Hunt outcome.
Return values
k_ra8_okThe device answered.
k_ra8_err_hw_timeoutNothing attached / nothing answered.
Precondition
ra8_usb_hmsc_init ran (host mode up, VBUS supplied).
ra8_time_init has run (the ladder uses millisecond delays).
Postcondition
On success the DCP targets *out_addr with UACT on.
On failure the bus state is whatever the last attempt left.
Note
Blocking; worst case a few seconds.
Since
0.1.0

Definition at line 154 of file ra8_usb_hmsc_enum.c.

References g_usb_hmsc_state, internal_enum_read_dev_desc(), k_ra8_err_hw_timeout, k_ra8_hmsc_addr_alt_mask, k_ra8_hmsc_attach_spin_limit, k_ra8_hmsc_attach_to_ms, k_ra8_hmsc_debounce_ms, k_ra8_hmsc_enum_tries, k_ra8_hmsc_no_reset_tries, k_ra8_hmsc_recovery_ms, k_ra8_hmsc_reset_hold_ms, k_ra8_hmsc_vbus_settle_ms, k_ra8_ok, ra8_delay_ms(), ra8_time_ms(), ra8_usb_host_bus_reset(), ra8_usb_host_line_state(), ra8_usb_host_set_target(), and ra8_usb_host_set_uact().

Referenced by internal_enum_ladder().

◆ internal_enum_iface_is_msc()

bool internal_enum_iface_is_msc ( const uint8_t * d)
static

Test whether an interface descriptor is MSC SCSI Bulk-Only.

Matches class 0x08 (mass storage), subclass 0x06 (SCSI transparent), protocol 0x50 (Bulk-Only Transport) – the trio every consumer thumb drive reports.

Parameters
[in]dInterface descriptor bytes (9 valid bytes).
Returns
true when the interface is MSC SCSI BOT.
Return values
falseAny of the three class fields differs.
Precondition
d is non-NULL and points at an interface descriptor.
The descriptor passed the walker's length check.
Postcondition
No state changes.
d is unmodified.
Note
Pure helper for internal_enum_walk_cfg.
Since
0.1.0

Definition at line 283 of file ra8_usb_hmsc_enum.c.

References k_ra8_hmsc_class_msc, k_ra8_hmsc_off_iface_class, k_ra8_hmsc_off_iface_proto, k_ra8_hmsc_off_iface_sub, k_ra8_hmsc_protocol_bbb, and k_ra8_hmsc_subclass_scsi.

Referenced by internal_enum_walk_cfg().

◆ internal_enum_ladder()

ra8_err_t internal_enum_ladder ( uint8_t * out_addr)
static

Run the enumeration ladder: hunt, address, configure, pipes.

Waits for the attach, hunts the (reset, address) combination the device answers on, unpacks VID/PID, assigns address 1, parses + activates the configuration, and programs the bulk pipes.

Parameters
[out]out_addrReceives the address the device answers at.
Returns
First failing step's error, or k_ra8_ok.
Return values
k_ra8_okThe device is configured and both pipes are ready.
Precondition
ra8_usb_hmsc_init succeeded and VBUS reaches the device.
The snapshot was reset for this enumeration pass.
Postcondition
On success the snapshot carries IDs, endpoints, and max-LUN.
On failure the controller may need a fresh attach cycle.
Note
Helper for ra8_usb_hmsc_enumerate (statement-count split).
Since
0.1.0

Definition at line 533 of file ra8_usb_hmsc_enum.c.

References internal_enum_assign_addr(), internal_enum_configure(), internal_enum_fill_ids(), internal_enum_hunt(), internal_enum_read_config(), k_ra8_hmsc_dev_desc_len, k_ra8_ok, RA8_RETURN_ON_ERROR, and s_tag.

Referenced by ra8_usb_hmsc_enumerate().

◆ internal_enum_note_endpoint()

void internal_enum_note_endpoint ( const uint8_t * d)
static

Record one bulk endpoint descriptor into the device snapshot.

Filters for bmAttributes == bulk and slots the endpoint into the IN or OUT position (first match wins) with its wMaxPacketSize.

Parameters
[in]dPointer to an endpoint descriptor.
Precondition
d points at a descriptor with bDescriptorType ENDPOINT.
The unfilled g_usb_hmsc_state.device endpoint slots are zero.
Postcondition
A matching bulk endpoint is recorded once.
Non-bulk endpoints leave the snapshot untouched.
Note
Pure helper for the config-descriptor walk.
Since
0.1.0

Definition at line 242 of file ra8_usb_hmsc_enum.c.

References g_usb_hmsc_state, k_ra8_hmsc_byte_bits, k_ra8_hmsc_ep_attr_bulk, k_ra8_hmsc_ep_attr_mask, k_ra8_hmsc_ep_dir_in_bit, k_ra8_hmsc_ep_num_mask, k_ra8_hmsc_off_ep_addr, k_ra8_hmsc_off_ep_attr, and k_ra8_hmsc_off_ep_mps.

Referenced by internal_enum_walk_cfg().

◆ internal_enum_publish()

void internal_enum_publish ( uint8_t dev_addr,
ra8_usb_hmsc_device_t * out_device )
static

Publish a completed enumeration: snapshot, callback, out-copy.

Stores the address, flips the attached flag, fires the registered attach callback, and copies the snapshot to the caller.

Parameters
[in]dev_addrAddress the device answers at.
[out]out_deviceCaller's snapshot copy (may be NULL).
Precondition
The bulk pipes are configured and SCSI calls may follow.
The snapshot carries VID/PID, endpoints, and max-LUN.
Postcondition
g_usb_hmsc_state.attached is true; the callback (if any) has fired.
*out_device holds the snapshot when out_device is non-NULL.
Note
Helper for ra8_usb_hmsc_enumerate.
Since
0.1.0

Definition at line 503 of file ra8_usb_hmsc_enum.c.

References g_usb_hmsc_state.

Referenced by ra8_usb_hmsc_enumerate().

◆ internal_enum_read_config()

ra8_err_t internal_enum_read_config ( uint8_t * out_cfg_value)
static

Read + parse the configuration descriptor set.

Reads the 9-byte header for wTotalLength + bConfigurationValue, re-reads the full set (clamped to the local buffer), and walks it for the MSC interface and bulk endpoints.

Parameters
[out]out_cfg_valueReceives bConfigurationValue.
Returns
First failing step's error, or k_ra8_ok.
Return values
k_ra8_okThe device snapshot carries the MSC endpoints.
Precondition
The device is addressed and answering control reads.
out_cfg_value is non-NULL.
Postcondition
On success the snapshot endpoints + interface are filled.
*out_cfg_value holds the value SET_CONFIGURATION needs.
Note
Blocking (two polled control reads).
Since
0.1.0

Definition at line 367 of file ra8_usb_hmsc_enum.c.

References g_usb_hmsc_state, internal_enum_walk_cfg(), k_ra8_hmsc_bm_std_dev_in, k_ra8_hmsc_breq_get_descriptor, k_ra8_hmsc_byte_bits, k_ra8_hmsc_cfg_buf_len, k_ra8_hmsc_cfg_desc_len, k_ra8_hmsc_desc_configuration, k_ra8_hmsc_off_cfg_total, k_ra8_hmsc_off_cfg_value, RA8_RETURN_ON_ERROR, ra8_usb_host_control_xfer(), s_tag, and ra8_usb_setup_t::w_length.

Referenced by internal_enum_ladder().

◆ internal_enum_read_dev_desc()

ra8_err_t internal_enum_read_dev_desc ( uint8_t * desc)
static

Read the 18-byte device descriptor over the polled control engine.

GET_DESCRIPTOR(DEVICE) at whatever address the DCP currently targets; requires the full 18 bytes back.

Parameters
[out]descReceives the descriptor (18 bytes).
Returns
Read outcome.
Return values
k_ra8_okAll 18 bytes arrived.
k_ra8_err_hw_errorA short descriptor came back.
Precondition
The bus is reset and UACT is on.
desc holds at least 18 bytes.
Postcondition
desc carries the device descriptor on success.
No state is modified.
Note
Blocking (polled control transfer).
Since
0.1.0

Definition at line 109 of file ra8_usb_hmsc_enum.c.

References g_usb_hmsc_state, k_ra8_err_hw_error, k_ra8_hmsc_bm_std_dev_in, k_ra8_hmsc_breq_get_descriptor, k_ra8_hmsc_byte_bits, k_ra8_hmsc_desc_device, k_ra8_hmsc_dev_desc_len, k_ra8_ok, RA8_RETURN_ON_ERROR, ra8_usb_host_control_xfer(), and s_tag.

Referenced by internal_enum_hunt().

◆ internal_enum_walk_cfg()

ra8_err_t internal_enum_walk_cfg ( const uint8_t * cfg,
uint16_t len )
static

Walk a configuration blob for the MSC interface + bulk endpoints.

Strides descriptor-by-descriptor; an interface descriptor with class 0x08 / subclass 0x06 / protocol 0x50 opens the MSC scope, and the bulk endpoints inside it populate the device snapshot.

Parameters
[in]cfgConfiguration descriptor bytes.
[in]lenValid byte count in cfg.
Returns
Walk outcome.
Return values
k_ra8_okBoth bulk endpoints were found.
k_ra8_err_hw_errorNo MSC bulk endpoint pair in the blob.
Precondition
cfg is non-NULL with len valid bytes.
The device snapshot endpoint slots start zeroed.
Postcondition
On k_ra8_ok the snapshot carries eps, max packets, and iface.
cfg is unmodified.
Note
Pure helper for internal_enum_read_config.
Since
0.1.0

Definition at line 317 of file ra8_usb_hmsc_enum.c.

References g_usb_hmsc_state, internal_enum_iface_is_msc(), internal_enum_note_endpoint(), k_ra8_err_hw_error, k_ra8_hmsc_desc_endpoint, k_ra8_hmsc_desc_interface, k_ra8_hmsc_off_dlen, k_ra8_hmsc_off_dtype, k_ra8_hmsc_off_iface_num, and k_ra8_ok.

Referenced by internal_enum_read_config().

◆ ra8_usb_hmsc_enumerate()

ra8_err_t ra8_usb_hmsc_enumerate ( ra8_usb_hmsc_device_t * out_device)
nodiscard

Implementation of ra8_usb_hmsc_enumerate().

Enumerate the attached MSC device end to end (polled).

See the public header for the documented contract; runs the hardware-proven polled ladder: attach wait, (reset, address) hunt, address assignment, configuration parse + activate, GET_MAX_LUN, bulk pipe setup, then fires the attach callback.

Parameters
[out]out_deviceSee header (may be NULL).
Returns
Result code.
Return values
k_ra8_okDevice enumerated; SCSI calls may follow.
Precondition
ra8_usb_hmsc_init succeeded and VBUS reaches the device.
ra8_time_init has run.
Postcondition
On success g_usb_hmsc_state.attached is true and the snapshot is filled.
The registered attach callback (if any) has fired.
Note
Blocking; bounded by the ladder timeouts.
Since
0.1.0

Definition at line 566 of file ra8_usb_hmsc_enum.c.

References g_usb_hmsc_state, internal_enum_ladder(), internal_enum_publish(), k_ra8_err_invalid_state, and k_ra8_ok.

Referenced by fileops_run_ladder(), microsd_host_enumerate(), mlun_host_enumerate(), ospirw_host_enumerate(), selftest_host_enumerate(), selftest_host_enumerate(), selftest_host_enumerate(), selftest_host_enumerate(), selftest_host_enumerate(), and wlun_host_enumerate().

Variable Documentation

◆ s_tag

const char* s_tag = "USBHMSC"
static

Definition at line 38 of file ra8_usb_hmsc_enum.c.