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

Native USB device-side HID class layer implementation. More...

#include "ra8_usb_phid.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 dependency graph for ra8_usb_phid.c:

Go to the source code of this file.

Data Structures

struct  ra8_usb_phid_state_t
 Singleton shadow state for the device-HID function. More...

Enumerations

enum  ra8_usb_phid_setup_field_t : uint8_t {
  k_ra8_phid_bm_class_iface_in = 0xA1U ,
  k_ra8_phid_bm_class_iface_out = 0x21U ,
  k_ra8_phid_default_idle_rate = 0U ,
  k_ra8_phid_default_protocol = 1U ,
  k_ra8_phid_report_id_prepend_len = 1U
}
 Constants used to decode HID class-specific SETUPs. More...
enum  ra8_usb_phid_byte_shift_t : uint8_t {
  k_ra8_phid_shift_byte0 = 0U ,
  k_ra8_phid_shift_byte1 = 8U
}
 Per-byte shift constants for wValue decoding. More...
enum  ra8_usb_phid_byte_mask_t : uint16_t { k_ra8_phid_mask_byte = 0xFFU }
 Per-byte mask constants for wValue decoding. More...

Functions

static uint16_t internal_intr_max_packet (ra8_usb_speed_t speed)
 Pick the interrupt-max-packet ceiling matching the negotiated speed.
static void internal_configure_pipes (ra8_usb_speed_t speed)
 Configure the two HID interrupt pipes.
static void internal_reset_shadow (ra8_usb_speed_t speed)
 Reset shadow state to spec defaults.
static bool internal_is_known_class_request (uint8_t b_request)
 Recognise a HID class request code we shadow / forward.
static void internal_apply_class_setup (const ra8_usb_setup_t *setup)
 Apply SET_IDLE / SET_PROTOCOL to the local shadow.
ra8_err_t ra8_usb_phid_init (ra8_usb_speed_t speed)
 Bring up the device-HID function on a chosen USB controller.
ra8_err_t ra8_usb_phid_close (void)
 Tear down the device-HID function and release the controller.
ra8_err_t ra8_usb_phid_set_descriptors (const uint8_t *report_desc, uint16_t report_desc_len, const uint8_t *hid_desc, uint16_t hid_desc_len)
 Install the caller-supplied HID Report descriptor and HID class descriptor.
ra8_err_t ra8_usb_phid_send_report (uint8_t report_id, const uint8_t *payload, uint16_t len)
 Push a HID input report on the interrupt-IN endpoint.
ra8_err_t ra8_usb_phid_recv_report (uint8_t report_id, uint8_t *buf, uint16_t max_len, uint16_t *got_len)
 Drain a HID output report from the interrupt-OUT endpoint.
ra8_err_t ra8_usb_phid_attach_setup_handler (ra8_usb_phid_setup_fn_t setup_fn, void *ctx)
 Register the application's HID class-setup handler.
ra8_err_t ra8_usb_phid_handle_setup (const ra8_usb_setup_t *setup)
 Process a class-specific SETUP packet on EP0.
ra8_err_t ra8_usb_phid_get_idle (uint8_t *out_idle_rate)
 Read the most-recently negotiated idle rate.
ra8_err_t ra8_usb_phid_get_protocol (ra8_usb_phid_protocol_select_t *out_protocol)
 Read the most-recently negotiated protocol.

Variables

static const char * s_tag = "USBPHID"
static ra8_usb_phid_state_t s_state = {}

Detailed Description

Native USB device-side HID class layer implementation.

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

Glues the device-mode ra8_usb driver to a HID interface so the EK-RA8D2 enumerates as a USB keyboard, mouse, gamepad, or vendor-defined HID gadget. This file is the native peripheral-HID class layer; FSP's r_usb_phid_driver.c is reference material only, nothing is pulled in verbatim.

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

Behaviourally the class layer responds to host requests rather than initiating them: the host enumerates, walks GET_DESCRIPTOR(HID) and GET_DESCRIPTOR(Report) over EP0, may issue SET_IDLE / SET_PROTOCOL, and then keeps polling the interrupt-IN pipe for input reports.

Definition in file ra8_usb_phid.c.

Enumeration Type Documentation

◆ ra8_usb_phid_byte_mask_t

enum ra8_usb_phid_byte_mask_t : uint16_t

Per-byte mask constants for wValue decoding.

Enumerator
k_ra8_phid_mask_byte 

RA8 phid mask byte.

Definition at line 79 of file ra8_usb_phid.c.

◆ ra8_usb_phid_byte_shift_t

enum ra8_usb_phid_byte_shift_t : uint8_t

Per-byte shift constants for wValue decoding.

Enumerator
k_ra8_phid_shift_byte0 

RA8 phid shift byte0.

k_ra8_phid_shift_byte1 

RA8 phid shift byte1.

Definition at line 70 of file ra8_usb_phid.c.

◆ ra8_usb_phid_setup_field_t

Constants used to decode HID class-specific SETUPs.

Per USB HID 1.11 sec 7.2 "Class-Specific Requests" the standard interface-recipient class envelope uses:

  • bmRequestType = 0x21 (H2D | Class | Interface)
  • bmRequestType = 0xA1 (D2H | Class | Interface)
Enumerator
k_ra8_phid_bm_class_iface_in 

Class | Iface | In.

k_ra8_phid_bm_class_iface_out 

Class | Iface | Out.

k_ra8_phid_default_idle_rate 

Spec default idle.

k_ra8_phid_default_protocol 

Spec default = report.

k_ra8_phid_report_id_prepend_len 

Report ID byte.

Definition at line 58 of file ra8_usb_phid.c.

Function Documentation

◆ internal_apply_class_setup()

void internal_apply_class_setup ( const ra8_usb_setup_t * setup)
static

Apply SET_IDLE / SET_PROTOCOL to the local shadow.

wValue.high carries the duration for SET_IDLE; wValue carries 0 (boot) or 1 (report) for SET_PROTOCOL.

Parameters
[in]setupSee implementation.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 243 of file ra8_usb_phid.c.

References ra8_usb_setup_t::b_request, k_ra8_phid_mask_byte, k_ra8_phid_proto_boot, k_ra8_phid_proto_report, k_ra8_phid_req_set_idle, k_ra8_phid_req_set_protocol, k_ra8_phid_shift_byte1, s_state, and ra8_usb_setup_t::w_value.

Referenced by ra8_usb_phid_handle_setup().

◆ internal_configure_pipes()

void internal_configure_pipes ( ra8_usb_speed_t speed)
static

Configure the two HID interrupt pipes.

See implementation.

Parameters
[in]speedSee implementation.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 157 of file ra8_usb_phid.c.

References internal_intr_max_packet(), k_ra8_phid_ep_intr_in_addr, k_ra8_phid_ep_intr_out_addr, k_ra8_phid_pipe_intr_in, k_ra8_phid_pipe_intr_out, k_ra8_usb_ep_dir_in, k_ra8_usb_ep_dir_out, k_ra8_usb_ep_type_intr, and ra8_usb_configure_endpoint().

◆ internal_intr_max_packet()

uint16_t internal_intr_max_packet ( ra8_usb_speed_t speed)
static

Pick the interrupt-max-packet ceiling matching the negotiated speed.

See implementation.

Parameters
[in]speedSee implementation.
Returns
The interrupt-endpoint maximum packet size in bytes for speed.
Return values
k_ra8_phid_intr_max_packet_hsspeed is k_ra8_usb_speed_hs.
k_ra8_phid_intr_max_packet_defaultAny other speed.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 138 of file ra8_usb_phid.c.

References k_ra8_phid_intr_max_packet_default, k_ra8_phid_intr_max_packet_hs, and k_ra8_usb_speed_hs.

Referenced by internal_configure_pipes(), and internal_reset_shadow().

◆ internal_is_known_class_request()

bool internal_is_known_class_request ( uint8_t b_request)
static

Recognise a HID class request code we shadow / forward.

See implementation.

Parameters
[in]b_requestSee implementation.
Returns
Result code.
Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 221 of file ra8_usb_phid.c.

References k_ra8_phid_req_get_idle, k_ra8_phid_req_get_protocol, k_ra8_phid_req_get_report, k_ra8_phid_req_set_idle, k_ra8_phid_req_set_protocol, and k_ra8_phid_req_set_report.

Referenced by ra8_usb_phid_handle_setup().

◆ internal_reset_shadow()

void internal_reset_shadow ( ra8_usb_speed_t speed)
static

Reset shadow state to spec defaults.

See implementation.

Parameters
[in]speedSee implementation.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 190 of file ra8_usb_phid.c.

References internal_intr_max_packet(), k_ra8_phid_default_idle_rate, k_ra8_phid_ep_intr_in_addr, k_ra8_phid_ep_intr_out_addr, k_ra8_phid_proto_report, and s_state.

Referenced by ra8_usb_phid_init().

◆ ra8_usb_phid_attach_setup_handler()

ra8_err_t ra8_usb_phid_attach_setup_handler ( ra8_usb_phid_setup_fn_t setup_fn,
void * ctx )
nodiscard

Register the application's HID class-setup handler.

The class layer drains the SETUP envelope from the controller, then forwards it to the registered handler if its bmRequestType indicates a class-recipient-interface request and its bRequest is one of GET_REPORT / SET_REPORT / GET_IDLE / SET_IDLE / GET_PROTOCOL / SET_PROTOCOL. Pass NULL for setup_fn to detach.

Parameters
[in]setup_fnApplication's handler. NULL detaches.
[in]ctxContext pointer threaded back into setup_fn.
Returns
ra8_err_t error code.
Return values
k_ra8_okHandler installed.
k_ra8_err_invalid_stateDriver not initialized.
Precondition
ra8_usb_phid_init succeeded.
Postcondition
On the next class SETUP, setup_fn(ctx, &setup) fires.
Note
Not thread-safe.
Since
0.1.0

Definition at line 403 of file ra8_usb_phid.c.

References k_ra8_err_invalid_state, k_ra8_ok, and s_state.

◆ ra8_usb_phid_close()

ra8_err_t ra8_usb_phid_close ( void )
nodiscard

Tear down the device-HID function 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_device_deinit ran; D+ pull-up dropped; subsequent device-HID API calls return k_ra8_err_invalid_state.
Note
Not thread-safe.
Since
0.1.0

Definition at line 294 of file ra8_usb_phid.c.

References k_ra8_err_invalid_state, ra8_usb_device_attach(), ra8_usb_device_deinit(), and s_state.

◆ ra8_usb_phid_get_idle()

ra8_err_t ra8_usb_phid_get_idle ( uint8_t * out_idle_rate)
nodiscard

Read the most-recently negotiated idle rate.

Parameters
[out]out_idle_rateReceives the 4 ms-tick idle rate (0 = "report only on change").
Returns
ra8_err_t error code.
Return values
k_ra8_okValue copied.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrout_idle_rate was NULL.
Precondition
out_idle_rate non-NULL.
Postcondition
No internal state mutated.
Note
Not thread-safe.
Since
0.1.0

Definition at line 449 of file ra8_usb_phid.c.

References k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, s_state, and s_tag.

◆ ra8_usb_phid_get_protocol()

ra8_err_t ra8_usb_phid_get_protocol ( ra8_usb_phid_protocol_select_t * out_protocol)
nodiscard

Read the most-recently negotiated protocol.

Parameters
[out]out_protocolReceives the protocol selector.
Returns
ra8_err_t error code.
Return values
k_ra8_okValue copied.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrout_protocol was NULL.
Precondition
out_protocol non-NULL.
Postcondition
No internal state mutated.
Note
Not thread-safe.
Since
0.1.0

Definition at line 459 of file ra8_usb_phid.c.

References k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, s_state, and s_tag.

◆ ra8_usb_phid_handle_setup()

ra8_err_t ra8_usb_phid_handle_setup ( const ra8_usb_setup_t * setup)
nodiscard

Process a class-specific SETUP packet on EP0.

Switches on b_request and (a) updates the local idle-rate / protocol shadow for SET_IDLE / SET_PROTOCOL, then (b) forwards the SETUP to the registered application handler if any. Standard (non-class) SETUPs are rejected with k_ra8_err_not_supported so the caller can fall back to its own standard-request handler.

Parameters
[in]setupThe SETUP packet returned by ra8_usb_read_setup_if_valid.
Returns
ra8_err_t error code.
Return values
k_ra8_okSETUP handled (status stage queued internally).
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrsetup was NULL.
k_ra8_err_not_supportedbRequest is not a HID class request this layer cares about.
Precondition
ra8_usb_phid_init succeeded.
Postcondition
Idle-rate / protocol shadow updated as appropriate.
Note
Call from the CTRT ISR path of ra8_usb.
Since
0.1.0

Definition at line 418 of file ra8_usb_phid.c.

References ra8_usb_setup_t::b_request, ra8_usb_setup_t::bm_request_type, internal_apply_class_setup(), internal_is_known_class_request(), k_ra8_err_invalid_state, k_ra8_err_not_supported, k_ra8_ok, k_ra8_phid_bm_class_iface_in, k_ra8_phid_bm_class_iface_out, RA8_CHECK_NULL_PTR, ra8_usb_control_response(), s_state, and s_tag.

◆ ra8_usb_phid_init()

ra8_err_t ra8_usb_phid_init ( ra8_usb_speed_t speed)
nodiscard

Bring up the device-HID function on a chosen USB controller.

Initialises the underlying ra8_usb driver in DEVICE mode for speed, configures PIPE6 (interrupt IN) and PIPE7 (interrupt OUT), resets the idle-rate / protocol shadow to spec defaults (idle_rate = 0 = "report only on change", protocol = report), and leaves the D+ pull-up dropped. The caller raises it via ra8_usb_device_attach once descriptors are set.

Parameters
[in]speedWhich USB controller (FS or HS).
Returns
ra8_err_t error code.
Return values
k_ra8_okDevice-HID ready.
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
Internal state machine armed; descriptor pointers cleared.
Pipe6 / pipe7 configured at the speed's default packet size.
Note
Not thread-safe.
See also
ra8_usb_phid_set_descriptors
ra8_usb_phid_close
Since
0.1.0

Definition at line 275 of file ra8_usb_phid.c.

References internal_configure_pipes(), internal_reset_shadow(), k_ra8_err_hw_init_failed, k_ra8_err_invalid_arg, k_ra8_ok, 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_phid_recv_report()

ra8_err_t ra8_usb_phid_recv_report ( uint8_t report_id,
uint8_t * buf,
uint16_t max_len,
uint16_t * got_len )
nodiscard

Drain a HID output report from the interrupt-OUT endpoint.

Pulls bytes off PIPE7 (interrupt OUT) into buf. Some HID gadgets (notably keyboards announcing LED state) instead deliver output reports via SET_REPORT on EP0; that path is handled by the caller-installed setup callback.

Parameters
[in]report_idReport ID (informational; not consumed here).
[out]bufReceive buffer.
[in]max_lenCapacity of buf, > 0.
[out]got_lenReceives the number of bytes actually placed.
Returns
ra8_err_t error code.
Return values
k_ra8_okBytes drained; *got_len reflects the count.
k_ra8_err_no_dataPipe was empty.
k_ra8_err_null_ptrbuf or got_len was NULL.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_invalid_argmax_len == 0.
Precondition
ra8_usb_phid_init succeeded.
buf non-NULL, got_len non-NULL.
Postcondition
On success *got_len reflects the actual byte count.
Note
Not thread-safe.
Since
0.1.0

Definition at line 372 of file ra8_usb_phid.c.

References k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_ok, k_ra8_phid_pipe_intr_out, RA8_CHECK_NULL_PTR, ra8_usb_queue_out(), s_state, and s_tag.

◆ ra8_usb_phid_send_report()

ra8_err_t ra8_usb_phid_send_report ( uint8_t report_id,
const uint8_t * payload,
uint16_t len )
nodiscard

Push a HID input report on the interrupt-IN endpoint.

If report_id == 0 the device uses a single unnamed report and the payload goes straight onto PIPE6. If report_id != 0 the byte is prepended to the payload as the spec requires (USB HID 1.11 sec 8 "Report Protocol"). The caller is responsible for not exceeding the configured pipe max-packet.

Parameters
[in]report_idHID report ID (0 if device uses a single report).
[in]payloadReport payload.
[in]lenPayload length.
Returns
ra8_err_t error code.
Return values
k_ra8_okBytes queued onto interrupt-IN.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrpayload was NULL with len > 0.
k_ra8_err_invalid_arglen zero with report_id == 0, or too large for the pipe max-packet.
Precondition
ra8_usb_phid_init succeeded.
payload non-NULL when len > 0.
Postcondition
len (or len + 1 if report_id != 0) bytes sit on PIPE6.
Note
Not thread-safe.
Since
0.1.0

Definition at line 339 of file ra8_usb_phid.c.

References k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_err_null_ptr, k_ra8_phid_pipe_intr_in, k_ra8_phid_report_id_prepend_len, RA8_RETURN_ON_ERROR, ra8_usb_queue_in(), s_state, and s_tag.

◆ ra8_usb_phid_set_descriptors()

ra8_err_t ra8_usb_phid_set_descriptors ( const uint8_t * report_desc,
uint16_t report_desc_len,
const uint8_t * hid_desc,
uint16_t hid_desc_len )
nodiscard

Install the caller-supplied HID Report descriptor and HID class descriptor.

The class layer keeps just a pointer + length pair for each descriptor; the application owns the storage. When the host issues GET_DESCRIPTOR(Report) on the HID interface, the class layer hands the buffered Report descriptor to the EP0 data stage. When the host issues GET_DESCRIPTOR(HID), the same is done for the HID class descriptor.

Parameters
[in]report_descPointer to the caller-owned Report descriptor.
[in]report_desc_lenByte length of report_desc.
[in]hid_descPointer to the caller-owned HID class descriptor.
[in]hid_desc_lenByte length of hid_desc.
Returns
ra8_err_t error code.
Return values
k_ra8_okPointers + lengths stored.
k_ra8_err_invalid_stateDriver not initialized.
k_ra8_err_null_ptrEither pointer was NULL.
k_ra8_err_invalid_argEither length was 0.
Precondition
ra8_usb_phid_init succeeded.
Both pointers non-NULL, both lengths > 0.
Postcondition
Subsequent GET_DESCRIPTOR(Report) / GET_DESCRIPTOR(HID) requests serve the supplied buffers.
Note
Not thread-safe.
Since
0.1.0

Definition at line 314 of file ra8_usb_phid.c.

References k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, s_state, and s_tag.

Variable Documentation

◆ s_state

ra8_usb_phid_state_t s_state = {}
static

Definition at line 114 of file ra8_usb_phid.c.

◆ s_tag

const char* s_tag = "USBPHID"
static

Definition at line 42 of file ra8_usb_phid.c.