ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_usb_pal.c
Go to the documentation of this file.
1
19
20#include "ra8_usb_pal.h"
21
22#include <stdint.h>
23
24#include "ra8_attributes.h"
25#include "ra8_check.h"
26#include "ra8_err.h"
27#include "ra8_log.h"
28#include "ra8_usb.h"
30
47bool priv_usb_pal_should_dispatch_event(const void* event_fn, uint16_t mask, uint16_t none_value)
48{
49 return (event_fn != nullptr) && (mask != none_value);
50}
51
67bool priv_usb_pal_ep_out_of_range(uint8_t ep_addr, uint8_t ep_max)
68{
69 return (ep_addr == 0U) || (ep_addr > ep_max);
70}
71
72static const char* s_tag = "USBPAL";
73
74/* =============================================================================
75 * Ring sizing
76 * =============================================================================
77 */
78
84
85/* =============================================================================
86 * Per-EP + per-PAL state
87 * =============================================================================
88 */
89
94typedef struct {
95 uint16_t len;
98
113
126
128
129/* =============================================================================
130 * Internal helpers
131 * =============================================================================
132 */
133
155static void internal_copy_bytes(uint8_t* dst, const uint8_t* src, uint16_t len)
156{
157 for (uint16_t i = 0U; i < len; ++i) {
158 dst[i] = src[i];
159 }
160}
161
179static void internal_reset_eps(void)
180{
181 for (uint16_t i = 0U; i < k_ra8_usb_pal_ep_table_len; ++i) {
182 ra8_usb_pal_ep_slot_t* slot = &s_state.eps[i];
183 slot->opened = false;
186 slot->max_packet = 0U;
187 slot->head = 0U;
188 slot->tail = 0U;
189 slot->count = 0U;
190 for (uint16_t j = 0U; j < k_ra8_usb_pal_ring_slots; ++j) {
191 slot->ring[j].len = 0U;
192 }
193 }
194}
195
219static uint16_t internal_translate(uint16_t usb_mask)
220{
221 if (usb_mask != 0U) {
223 }
225}
226
251static void internal_usb_event(void* ctx, ra8_usb_speed_t speed, uint16_t status_mask)
252{
253 (void)ctx;
254 if (!s_state.initialized) {
255 return;
256 }
257 if (speed != s_state.speed) {
258 return;
259 }
260 const uint16_t pal_mask = internal_translate(status_mask);
261 if (priv_usb_pal_should_dispatch_event((const void*)s_state.event_fn,
262 pal_mask,
263 (uint16_t)k_ra8_usb_pal_event_none)) {
264 s_state.event_fn(s_state.event_ctx, speed, pal_mask);
265 }
266}
267
268/* =============================================================================
269 * Public API
270 * =============================================================================
271 */
272
300{
301 if ((speed != k_ra8_usb_speed_fs) && (speed != k_ra8_usb_speed_hs)) {
303 }
304 const ra8_err_t usb_err = ra8_usb_device_init(speed);
305 if (usb_err != k_ra8_ok) {
306 ra8_log_error_val(s_tag, "ra8_usb_device_init failed", (uint32_t)usb_err);
308 }
309
310 s_state.speed = speed;
312 s_state.event_fn = nullptr;
313 s_state.event_ctx = nullptr;
314 s_state.initialized = true;
316
318
319 ra8_log_info(s_tag, "PAL ready");
320 return k_ra8_ok;
321}
322
345{
346 if (!s_state.initialized) {
348 }
349 (void)ra8_usb_device_attach(s_state.speed, false);
350 ra8_usb_attach_handler(s_state.speed, nullptr, nullptr);
351 const ra8_err_t err = ra8_usb_device_deinit(s_state.speed);
352 s_state.initialized = false;
353 s_state.event_fn = nullptr;
354 s_state.event_ctx = nullptr;
357 return err;
358}
359
382{
383 if (!s_state.initialized) {
385 }
386 /* `ra8_usb_device_attach` rejects only an invalid controller selector;
387 * successful initialization stored a validated selector in `s_state`. */
388 (void)ra8_usb_device_attach(s_state.speed, attached);
389 if (attached) {
391 } else {
393 }
394 return k_ra8_ok;
395}
396
398{
399 RA8_CHECK_NULL_PTR(out_state, s_tag, "get_state: out_state");
400 if (!s_state.initialized) {
402 }
403 *out_state = s_state.state;
404 return k_ra8_ok;
405}
406
437 uint16_t max_packet)
438{
439 /* USB descriptor bEndpointAddress encodes direction in bit 7
440 * (0x80 = IN). Strip it so callers can pass either the descriptor
441 * form (e.g. 0x83) or the bare endpoint number (e.g. 3). */
442 ep_addr = (uint8_t)(ep_addr & (uint8_t)k_ra8_usb_pal_ep_addr_mask);
443 if (!s_state.initialized) {
445 }
446 if (priv_usb_pal_ep_out_of_range(ep_addr, (uint8_t)k_ra8_usb_pal_ep_max)) {
448 }
449 if ((dir != k_ra8_usb_pal_ep_dir_out) && (dir != k_ra8_usb_pal_ep_dir_in)) {
451 }
452 if ((type > k_ra8_usb_pal_ep_type_intr) || (max_packet == 0U) ||
453 (max_packet > k_ra8_usb_pal_xfer_max)) {
455 }
456 ra8_usb_pal_ep_slot_t* slot = &s_state.eps[ep_addr];
457 slot->opened = true;
458 slot->dir = dir;
459 slot->type = type;
460 slot->max_packet = max_packet;
461 slot->head = 0U;
462 slot->tail = 0U;
463 slot->count = 0U;
464 for (uint16_t j = 0U; j < k_ra8_usb_pal_ring_slots; ++j) {
465 slot->ring[j].len = 0U;
466 }
467 return k_ra8_ok;
468}
469
498ra8_err_t ra8_usb_pal_ep_send(uint8_t ep_addr, const uint8_t* data, uint16_t len)
499{
500 /* Accept descriptor-shaped (0x80 | ep) and bare-number ep_addr. */
501 ep_addr = (uint8_t)(ep_addr & (uint8_t)k_ra8_usb_pal_ep_addr_mask);
502 if (!s_state.initialized) {
504 }
505 if (priv_usb_pal_ep_out_of_range(ep_addr, (uint8_t)k_ra8_usb_pal_ep_max)) {
507 }
508 if ((len > k_ra8_usb_pal_xfer_max) || ((data == nullptr) && (len != 0U))) {
509 return (data == nullptr) ? k_ra8_err_null_ptr : k_ra8_err_invalid_arg;
510 }
511 ra8_usb_pal_ep_slot_t* slot = &s_state.eps[ep_addr];
512 if (!slot->opened) {
514 }
515 if (len > slot->max_packet) {
517 }
518 if (slot->count >= k_ra8_usb_pal_ring_slots) {
519 return k_ra8_err_no_mem;
520 }
521 ra8_usb_pal_packet_t* pkt = &slot->ring[slot->tail];
522 if (len > 0U) {
523 internal_copy_bytes(pkt->data, data, len);
524 }
525 pkt->len = len;
526 slot->tail = (uint16_t)((slot->tail + 1U) % k_ra8_usb_pal_ring_slots);
527 ++slot->count;
528 if (s_state.event_fn != nullptr) {
529 s_state.event_fn(s_state.event_ctx, s_state.speed, k_ra8_usb_pal_event_ep_in);
530 }
531 return k_ra8_ok;
532}
533
563ra8_err_t ra8_usb_pal_ep_recv(uint8_t ep_addr, uint8_t* out_buf, uint16_t* inout_len)
564{
565 RA8_CHECK_NULL_PTR(out_buf, s_tag, "ep_recv: out_buf");
566 RA8_CHECK_NULL_PTR(inout_len, s_tag, "ep_recv: inout_len");
567 /* Accept descriptor-shaped (0x80 | ep) and bare-number ep_addr. */
568 ep_addr = (uint8_t)(ep_addr & (uint8_t)k_ra8_usb_pal_ep_addr_mask);
569 if (!s_state.initialized) {
571 }
572 if (priv_usb_pal_ep_out_of_range(ep_addr, (uint8_t)k_ra8_usb_pal_ep_max)) {
574 }
575 if (*inout_len == 0U) {
577 }
578 ra8_usb_pal_ep_slot_t* slot = &s_state.eps[ep_addr];
579 if (!slot->opened) {
581 }
582 if (slot->count == 0U) {
583 return k_ra8_err_no_data;
584 }
585 ra8_usb_pal_packet_t* pkt = &slot->ring[slot->head];
586 const uint16_t n = (pkt->len < *inout_len) ? pkt->len : *inout_len;
587 if (n > 0U) {
588 internal_copy_bytes(out_buf, pkt->data, n);
589 }
590 *inout_len = n;
591 pkt->len = 0U;
592 slot->head = (uint16_t)((slot->head + 1U) % k_ra8_usb_pal_ring_slots);
593 --slot->count;
594 return k_ra8_ok;
595}
596
621{
622 if (!s_state.initialized) {
624 }
625 s_state.event_fn = fn;
626 s_state.event_ctx = ctx;
627 return k_ra8_ok;
628}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_hw_init_failed
Hardware peripheral failed to initialise.
Definition ra8_err.h:290
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ k_ra8_err_no_data
No application data available (e.g.
Definition ra8_err.h:202
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_error_val(tag, message, value)
RA8 log error val.
Definition ra8_log.h:337
#define ra8_log_info(tag, message)
RA8 log info.
Definition ra8_log.h:364
static uint32_t s_state
Native USB controller driver public API (device + host modes).
ra8_err_t ra8_usb_device_init(ra8_usb_speed_t speed)
Bring up a USB controller in device mode.
ra8_err_t ra8_usb_device_deinit(ra8_usb_speed_t speed)
Tear down a USB controller and drop its MSTP reference.
ra8_err_t ra8_usb_device_attach(ra8_usb_speed_t speed, bool attached)
Raise / drop the D+ pull-up to advertise the device to the host.
void ra8_usb_attach_handler(ra8_usb_speed_t speed, ra8_usb_event_fn_t fn, void *ctx)
Install (or detach) the per-controller USB event handler.
Definition ra8_usb_irq.c:90
ra8_usb_speed_t
Selects which controller instance the call targets.
@ k_ra8_usb_speed_hs
High-Speed controller (USBHS @ 0x40351000).
@ k_ra8_usb_speed_fs
Full-Speed controller (USBFS @ 0x40250000).
ra8_usb_pal_ring_dim_t
Definition ra8_usb_pal.c:79
@ k_ra8_usb_pal_ep_table_len
Index 0..ep_max, 1-based EPs.
Definition ra8_usb_pal.c:80
@ k_ra8_usb_pal_pkt_max
Per-packet capacity.
Definition ra8_usb_pal.c:82
@ k_ra8_usb_pal_ring_slots
Per-EP queue depth.
Definition ra8_usb_pal.c:81
bool priv_usb_pal_ep_out_of_range(uint8_t ep_addr, uint8_t ep_max)
Pure ep-out-of-range predicate – see header for full contract.
Definition ra8_usb_pal.c:67
static void internal_usb_event(void *ctx, ra8_usb_speed_t speed, uint16_t status_mask)
ra8_usb event handler – translate + forward to the PAL callback.
ra8_err_t ra8_usb_pal_init(ra8_usb_speed_t speed)
Bring up the USB PAL singleton at the requested speed.
ra8_err_t ra8_usb_pal_attach(bool attached)
Drive the D+ pull-up to attach or detach the device.
static void internal_copy_bytes(uint8_t *dst, const uint8_t *src, uint16_t len)
Copy len bytes (string.h-free local memcpy substitute).
ra8_err_t ra8_usb_pal_ep_open(uint8_t ep_addr, ra8_usb_pal_ep_dir_t dir, ra8_usb_pal_ep_type_t type, uint16_t max_packet)
Open one endpoint and reserve a per-EP packet ring.
ra8_err_t ra8_usb_pal_get_state(ra8_usb_pal_state_t *out_state)
Read the current PAL state machine.
static uint16_t internal_translate(uint16_t usb_mask)
Translate ra8_usb status mask -> PAL event mask.
ra8_err_t ra8_usb_pal_ep_recv(uint8_t ep_addr, uint8_t *out_buf, uint16_t *inout_len)
Pull the next packet, if any, from an open OUT endpoint.
static void internal_reset_eps(void)
Reset every endpoint slot to empty / unopened.
ra8_err_t ra8_usb_pal_set_event_handler(ra8_usb_pal_event_fn_t fn, void *ctx)
Install a single event handler for bus and per-EP events.
ra8_err_t ra8_usb_pal_ep_send(uint8_t ep_addr, const uint8_t *data, uint16_t len)
Queue a packet for transmit on an open IN endpoint.
ra8_err_t ra8_usb_pal_deinit(void)
Tear down the USB PAL singleton.
bool priv_usb_pal_should_dispatch_event(const void *event_fn, uint16_t mask, uint16_t none_value)
Pure dispatch-event predicate – see header for full contract.
Definition ra8_usb_pal.c:47
USB device-mode Platform Abstraction Layer.
ra8_usb_pal_ep_dir_t
Endpoint direction.
@ k_ra8_usb_pal_ep_dir_out
Host -> device.
@ k_ra8_usb_pal_ep_dir_in
Device -> host.
@ k_ra8_usb_pal_ep_addr_mask
Strip USB-IN dir bit (bit 7) from ep_addr.
Definition ra8_usb_pal.h:93
@ k_ra8_usb_pal_xfer_max
Single-shot xfer cap.
Definition ra8_usb_pal.h:92
@ k_ra8_usb_pal_ep_max
Maximum endpoint number.
Definition ra8_usb_pal.h:88
ra8_usb_pal_ep_type_t
USB endpoint transfer type.
@ k_ra8_usb_pal_ep_type_control
RA8 USB pal ep type control.
@ k_ra8_usb_pal_ep_type_intr
RA8 USB pal ep type intr.
@ k_ra8_usb_pal_event_error
Controller error.
@ k_ra8_usb_pal_event_none
RA8 USB pal event none.
@ k_ra8_usb_pal_event_ep_in
IN endpoint complete.
void(* ra8_usb_pal_event_fn_t)(void *ctx, ra8_usb_speed_t speed, uint16_t event_mask)
Async event callback shape.
ra8_usb_pal_state_t
USB device state per chapter 9 of USB 2.0.
@ k_ra8_usb_pal_state_attached
D+ pull-up on, no reset.
@ k_ra8_usb_pal_state_detached
D+ pull-up off.
Test-access surface for ra8_usb_pal internal helpers (MC/DC).
Configuration + queue for one endpoint.
uint16_t count
In-flight packet count.
uint16_t head
Next slot to pop.
uint16_t max_packet
Stored max packet size.
ra8_usb_pal_packet_t ring[k_ra8_usb_pal_ring_slots]
Per-EP queue.
ra8_usb_pal_ep_type_t type
Stored transfer type.
uint16_t tail
Next slot to push.
ra8_usb_pal_ep_dir_t dir
Stored direction.
bool opened
True once ra8_usb_pal_ep_open fired.
One packet on a per-endpoint ring.
Definition ra8_usb_pal.c:94
uint16_t len
0 == empty slot.
Definition ra8_usb_pal.c:95
uint8_t data[k_ra8_usb_pal_pkt_max]
Packet payload bytes.
Definition ra8_usb_pal.c:96
Singleton PAL state.
ra8_usb_pal_event_fn_t event_fn
Stack-installed callback.
ra8_usb_speed_t speed
FS or HS, set at init.
bool initialized
True after ra8_usb_pal_init.
ra8_usb_pal_state_t state
Detached/attached/...
ra8_usb_pal_ep_slot_t eps[k_ra8_usb_pal_ep_table_len]
Per-EP state.
void * event_ctx
Callback context.