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

Native USB device-side composite-class layer. More...

#include <stdint.h>
#include "ra8_err.h"
#include "ra8_usb.h"
Include dependency graph for ra8_usb_composite.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ra8_usb_composite_class_t
 Caller-owned class-layer registration record. More...

Typedefs

typedef ra8_err_t(* ra8_usb_composite_init_fn_t) (void *ctx)
 Class-layer initialise hook.
typedef ra8_err_t(* ra8_usb_composite_setup_fn_t) (void *ctx, const ra8_usb_setup_t *setup)
 Class-layer SETUP-handler hook.
typedef ra8_err_t(* ra8_usb_composite_close_fn_t) (void *ctx)
 Class-layer teardown hook.

Enumerations

enum  ra8_usb_composite_limits_t : uint8_t {
  k_ra8_usb_composite_max_classes = 4U ,
  k_ra8_usb_composite_max_ifs = 16U
}
 Static ceilings for the composite registry. More...
enum  ra8_usb_composite_iad_t : uint8_t {
  k_ra8_usb_composite_class_misc = 0xEFU ,
  k_ra8_usb_composite_subclass_common = 0x02U ,
  k_ra8_usb_composite_protocol_iad = 0x01U ,
  k_ra8_usb_composite_descriptor_type_iad = 0x0BU
}
 Interface Association Descriptor (IAD) constants. More...

Functions

ra8_err_t ra8_usb_composite_init (ra8_usb_speed_t speed)
 Bring up the composite-class driver on a chosen USB controller.
ra8_err_t ra8_usb_composite_close (void)
 Tear down the composite-class driver and release the controller.
ra8_err_t ra8_usb_composite_register_class (const ra8_usb_composite_class_t *class_layer)
 Register a single class layer with the composite driver.
ra8_err_t ra8_usb_composite_set_descriptors (const uint8_t *device_desc, const uint8_t *config_desc)
 Cache caller-owned device + configuration descriptor pointers.
ra8_err_t ra8_usb_composite_step (void)
 Drive the composite dispatch state machine forward by one step.
ra8_err_t ra8_usb_composite_dispatch_setup (const ra8_usb_setup_t *setup, uint8_t *out_handler_class)
 Inject a SETUP packet directly into the dispatch logic.
ra8_err_t ra8_usb_composite_get_class_count (uint8_t *out_count)
 Read back the number of currently-registered class layers.
ra8_err_t ra8_usb_composite_get_device_descriptor (const uint8_t **out_desc)
 Read back the cached device descriptor pointer.
ra8_err_t ra8_usb_composite_get_config_descriptor (const uint8_t **out_desc)
 Read back the cached configuration descriptor pointer.

Detailed Description

Native USB device-side composite-class layer.

Mirrors FSP's r_usb_composite peripheral-mode composite-device driver. With this layer the EK-RA8D2 can present multiple USB function classes (CDC ACM serial, HID keyboard, MSC mass storage, ...) over a single physical connection so the host enumerates one USB device that exposes a serial port + a keyboard + a drive at the same time.

The composite layer is class-agnostic: it does not pull in ra8_usb_cdc.h, ra8_usb_phid.h, or ra8_usb_pmsc.h. Instead the application registers each class layer by passing a small function-pointer struct (ra8_usb_composite_class_t) at boot time; the composite layer walks the registered list whenever a SETUP packet arrives whose wIndex (interface number) lands in that class's owned IF range.

Lifecycle (mirrors ra8_usb_pmsc.h and ra8_usb_phid.h shape):

  1. ra8_usb_composite_init(speed) flips the controller to device mode for speed, clears the registered-class table, primes the dispatch state machine to IDLE, and leaves D+ pull-up off so the application can finalise its descriptor table before advertising on the bus.
  2. ra8_usb_composite_register_class(class_layer) is called once per attached class. Each call validates the requested IF range against already-registered ranges so two classes cannot claim the same interface number.
  3. ra8_usb_composite_set_descriptors(device, configuration) stores pointers to the caller-owned device + configuration descriptors. The caller is expected to have built a valid composite configuration descriptor including IADs (Interface Association Descriptors) for each multi-interface class.
  4. ra8_usb_composite_step() drives the dispatch state machine. When a SETUP packet arrives the layer walks the registered classes; the one whose [interface_number_first, +interface_number_count) range covers setup->w_index gets handle_setup called. Standard chapter-9 requests (GET_DESCRIPTOR, SET_ADDRESS, SET_CONFIGURATION) are handled by the composite layer itself before any class dispatch.
  5. ra8_usb_composite_close() invokes each registered class's close hook, drops the class table, and tears down the device-mode controller.

Reference: USB 2.0 spec sec 9.6 "Standard USB Descriptor Definitions"; Interface Association Descriptor ECN ("USB Engineering Change Notice: Interface Association Descriptors", 2003-07-23).

Definition in file ra8_usb_composite.h.

Typedef Documentation

◆ ra8_usb_composite_close_fn_t

typedef ra8_err_t(* ra8_usb_composite_close_fn_t) (void *ctx)

Class-layer teardown hook.

Parameters
[in]ctxCaller-supplied context registered with the class.
Returns
ra8_err_t error code.

Definition at line 139 of file ra8_usb_composite.h.

◆ ra8_usb_composite_init_fn_t

typedef ra8_err_t(* ra8_usb_composite_init_fn_t) (void *ctx)

Class-layer initialise hook.

Parameters
[in]ctxCaller-supplied context registered with the class.
Returns
ra8_err_t error code propagated unchanged.

Definition at line 118 of file ra8_usb_composite.h.

◆ ra8_usb_composite_setup_fn_t

typedef ra8_err_t(* ra8_usb_composite_setup_fn_t) (void *ctx, const ra8_usb_setup_t *setup)

Class-layer SETUP-handler hook.

Parameters
[in]ctxCaller-supplied context registered with the class.
[in]setupDecoded 8-byte SETUP packet (USB 2.0 sec 9.3).
Returns
ra8_err_t error code. Non-zero stalls the control transfer.

Definition at line 129 of file ra8_usb_composite.h.

Enumeration Type Documentation

◆ ra8_usb_composite_iad_t

enum ra8_usb_composite_iad_t : uint8_t

Interface Association Descriptor (IAD) constants.

Per the USB 2.0 IAD ECN sec 9.X. The composite device descriptor advertises class = MISC (0xEF) / subclass = COMMON (0x02) / protocol = IAD (0x01) so the host knows to look for IADs in the configuration descriptor. Each IAD itself uses bDescriptorType 0x0B.

Enumerator
k_ra8_usb_composite_class_misc 

Miscellaneous class.

k_ra8_usb_composite_subclass_common 

Common subclass.

k_ra8_usb_composite_protocol_iad 

IAD protocol.

k_ra8_usb_composite_descriptor_type_iad 

bDescriptorType = IAD.

Definition at line 98 of file ra8_usb_composite.h.

◆ ra8_usb_composite_limits_t

Static ceilings for the composite registry.

The starter caps the number of registered classes at 4 (CDC + HID + MSC + a vendor-specific function is the largest realistic stack) and the maximum interface index at 16 to bound the collision-detection bitmap. These match the FSP reference templates shipped under r_usb_composite (.template files).

Enumerator
k_ra8_usb_composite_max_classes 

Registered class ceiling.

k_ra8_usb_composite_max_ifs 

Highest IF number tracked.

Definition at line 83 of file ra8_usb_composite.h.

Function Documentation

◆ ra8_usb_composite_close()

ra8_err_t ra8_usb_composite_close ( void )
nodiscard

Tear down the composite-class driver and release the controller.

Walks the registered class table and invokes each class's close callback in reverse-registration order. Then drops the cached class table and calls ra8_usb_device_deinit.

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_device_deinit ran; subsequent composite API calls return k_ra8_err_invalid_state.
Note
Not thread-safe.
Since
0.1.0

Definition at line 456 of file ra8_usb_composite.c.

References ra8_usb_composite_class_t::close, ra8_usb_composite_class_t::ctx, internal_clear_if_owners(), k_ra8_err_invalid_state, k_ra8_ok, ra8_log_error_val, ra8_usb_device_deinit(), s_state, and s_tag.

◆ ra8_usb_composite_dispatch_setup()

ra8_err_t ra8_usb_composite_dispatch_setup ( const ra8_usb_setup_t * setup,
uint8_t * out_handler_class )
nodiscard

Inject a SETUP packet directly into the dispatch logic.

Test / debug entry point. Production code receives SETUPs from the controller's USBREQ / USBVAL / USBINDX / USBLENG mirrors via ra8_usb_read_setup_if_valid; tests bypass the FIFO and feed an 8-byte decoded SETUP directly. Standard chapter-9 requests are answered internally; class / vendor requests are routed to the registered class whose IF range covers setup->w_index.

Parameters
[in]setupPointer to the 8-byte decoded SETUP packet.
[out]out_handler_classOn success, receives the index of the class that handled the request, or k_ra8_usb_composite_max_classes if the composite layer answered (i.e. standard request).
Returns
ra8_err_t error code.
Return values
k_ra8_okSETUP dispatched.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrsetup or out_handler_class was NULL.
k_ra8_err_not_foundClass request whose wIndex does not fall in any registered class's IF range.
Precondition
Both pointers non-NULL.
Postcondition
On k_ra8_ok for a class request, the matching class's handle_setup callback was invoked exactly once.
Note
Not thread-safe.
Since
0.1.0

Definition at line 583 of file ra8_usb_composite.c.

References ra8_usb_setup_t::bm_request_type, internal_handle_standard(), internal_require_init(), internal_route_class(), k_ra8_err_not_found, k_ra8_ok, k_ra8_usb_composite_handler_self, k_ra8_usb_composite_req_type_mask, k_ra8_usb_composite_req_type_standard, RA8_CHECK_NULL_PTR, s_state, and s_tag.

◆ ra8_usb_composite_get_class_count()

ra8_err_t ra8_usb_composite_get_class_count ( uint8_t * out_count)
nodiscard

Read back the number of currently-registered class layers.

Parameters
[out]out_countReceives the registered class count.
Returns
ra8_err_t error code.
Return values
k_ra8_okCount returned.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrout_count was NULL.
Precondition
out_count non-NULL.
Postcondition
No state mutated.
Note
Not thread-safe.
Since
0.1.0

Definition at line 614 of file ra8_usb_composite.c.

References internal_require_init(), k_ra8_ok, RA8_CHECK_NULL_PTR, s_state, and s_tag.

◆ ra8_usb_composite_get_config_descriptor()

ra8_err_t ra8_usb_composite_get_config_descriptor ( const uint8_t ** out_desc)
nodiscard

Read back the cached configuration descriptor pointer.

Parameters
[out]out_descReceives the cached configuration descriptor pointer (or NULL if set_descriptors never ran).
Returns
ra8_err_t error code.
Return values
k_ra8_okPointer returned.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrout_desc was NULL.
Precondition
out_desc non-NULL.
Postcondition
No state mutated.
Note
Not thread-safe.
Since
0.1.0

Definition at line 636 of file ra8_usb_composite.c.

References internal_require_init(), k_ra8_ok, RA8_CHECK_NULL_PTR, s_state, and s_tag.

◆ ra8_usb_composite_get_device_descriptor()

ra8_err_t ra8_usb_composite_get_device_descriptor ( const uint8_t ** out_desc)
nodiscard

Read back the cached device descriptor pointer.

Parameters
[out]out_descReceives the cached device descriptor pointer (or NULL if set_descriptors never ran).
Returns
ra8_err_t error code.
Return values
k_ra8_okPointer returned.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrout_desc was NULL.
Precondition
out_desc non-NULL.
Postcondition
No state mutated.
Note
Not thread-safe.
Since
0.1.0

Definition at line 625 of file ra8_usb_composite.c.

References internal_require_init(), k_ra8_ok, RA8_CHECK_NULL_PTR, s_state, and s_tag.

◆ ra8_usb_composite_init()

ra8_err_t ra8_usb_composite_init ( ra8_usb_speed_t speed)
nodiscard

Bring up the composite-class driver on a chosen USB controller.

Initialises the underlying ra8_usb driver in DEVICE mode for speed, zeroes the registered-class table, primes the dispatch state machine to IDLE, and clears the cached descriptor pointers. D+ pull-up is left off so the application can publish the configuration descriptor before the host enumerates it.

Parameters
[in]speedWhich USB controller (FS or HS).
Returns
ra8_err_t error code.
Return values
k_ra8_okComposite ready, awaiting register_class.
k_ra8_err_invalid_argspeed out of range.
k_ra8_err_hw_init_failedUnderlying ra8_usb_device_init failed.
Precondition
Single-threaded init context.
ra8_mstp_init and ra8_pwr_init already ran.
Postcondition
ra8_usb_device_init succeeded for speed.
Internal class registry empty; descriptors NULL.
Note
Not thread-safe.
See also
ra8_usb_composite_register_class
ra8_usb_composite_set_descriptors
ra8_usb_composite_close
Since
0.1.0

Definition at line 429 of file ra8_usb_composite.c.

References internal_clear_if_owners(), k_ra8_err_hw_init_failed, k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_usb_composite_handler_self, k_ra8_usb_composite_max_classes, k_ra8_usb_composite_state_idle, k_ra8_usb_speed_fs, k_ra8_usb_speed_hs, ra8_log_error_val, ra8_log_info_val, ra8_usb_device_init(), s_state, and s_tag.

◆ ra8_usb_composite_register_class()

ra8_err_t ra8_usb_composite_register_class ( const ra8_usb_composite_class_t * class_layer)
nodiscard

Register a single class layer with the composite driver.

Validates the supplied class-layer record:

  • All three function pointers (init, handle_setup, close) must be non-NULL.
  • interface_number_count must be >= 1.
  • interface_number_first + interface_number_count must not exceed k_ra8_usb_composite_max_ifs.
  • The [first, first+count) IF range must not overlap any previously-registered class's range (collision detection).

On success the record is copied into internal state and the class's init callback is invoked. Composition order is the order of register_class calls.

Parameters
[in]class_layerClass-layer snapshot. Copied by value.
Returns
ra8_err_t error code.
Return values
k_ra8_okClass registered, init invoked.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrclass_layer was NULL or any of its callbacks was NULL.
k_ra8_err_invalid_arginterface_number_count was 0 or the requested IF range overflows the IF ceiling.
k_ra8_err_existsIF range overlaps a previously-registered class.
k_ra8_err_no_memClass table is full (already at k_ra8_usb_composite_max_classes).
Precondition
ra8_usb_composite_init has run.
All three callbacks non-NULL.
Postcondition
Class slot count incremented; class's init callback invoked.
Note
Not thread-safe.
Since
0.1.0

Definition at line 492 of file ra8_usb_composite.c.

References ra8_usb_composite_class_t::ctx, ra8_usb_composite_class_t::init, internal_check_collision(), internal_mark_ownership(), internal_require_init(), internal_validate_class(), k_ra8_err_no_mem, k_ra8_ok, k_ra8_usb_composite_max_classes, ra8_log_error_val, ra8_log_info_val, s_state, and s_tag.

◆ ra8_usb_composite_set_descriptors()

ra8_err_t ra8_usb_composite_set_descriptors ( const uint8_t * device_desc,
const uint8_t * config_desc )
nodiscard

Cache caller-owned device + configuration descriptor pointers.

The composite layer does not allocate descriptors itself; the application builds them (typically as static const uint8_t[]) and passes pointers in. The device_desc is the 18-byte standard device descriptor (USB 2.0 sec 9.6.1); the config_desc is the variable- length composite configuration descriptor that includes one IAD per multi-interface class (USB IAD ECN sec 9.X).

Parameters
[in]device_descPointer to the device descriptor.
[in]config_descPointer to the configuration descriptor.
Returns
ra8_err_t error code.
Return values
k_ra8_okDescriptors cached.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrEither pointer was NULL.
Precondition
ra8_usb_composite_init has run.
Both descriptors point to caller-owned memory that lives for the device's session.
Postcondition
ra8_usb_composite_get_device_descriptor / ra8_usb_composite_get_config_descriptor return the supplied pointers.
Note
Not thread-safe.
Since
0.1.0

Definition at line 532 of file ra8_usb_composite.c.

References internal_require_init(), k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_log_info, s_state, and s_tag.

◆ ra8_usb_composite_step()

ra8_err_t ra8_usb_composite_step ( void )
nodiscard

Drive the composite dispatch state machine forward by one step.

Production code calls this from the EP0 / control-transfer completion ISR. Each call advances the state machine by one phase:

  • IDLE: wait for the next SETUP packet.
  • SETUP_RX: a SETUP arrived; classify it (standard / class / vendor) using bm_request_type and route accordingly.
  • STD_DISPATCH: standard chapter-9 requests (GET_DESCRIPTOR, SET_ADDRESS, SET_CONFIGURATION) handled here.
  • CLASS_DISPATCH: class / vendor requests routed to the registered class whose IF range covers setup->w_index.
  • DONE: transfer staged; next step idles back to SETUP_RX.
Returns
ra8_err_t error code.
Return values
k_ra8_okStep advanced.
k_ra8_err_invalid_stateDriver not initialized.
Precondition
ra8_usb_composite_init has run.
Postcondition
Internal state machine advances by one phase.
Note
Not thread-safe.
Since
0.1.0

Definition at line 552 of file ra8_usb_composite.c.

References internal_require_init(), k_ra8_ok, k_ra8_usb_composite_state_class_dispatch, k_ra8_usb_composite_state_done, k_ra8_usb_composite_state_idle, k_ra8_usb_composite_state_setup_rx, k_ra8_usb_composite_state_std_dispatch, and s_state.