ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ux_dcd_ra8_usb_ep.c
Go to the documentation of this file.
1
20
21#define UX_SOURCE_CODE
22
23#include <stdint.h>
24#include <string.h>
25
26#include "ra8_check.h"
27#include "ra8_elc_regs.h"
28#include "ra8_isr.h"
29#include "ra8_log.h"
30#include "ra8_usb_regs.h"
31#include "tx_api.h"
32#include "ux_api.h"
33#include "ux_dcd_ra8_usb.h"
35#include "ux_device_stack.h"
36#include "ux_system.h"
37#include "ux_utility.h"
38
64RA8_INTERNAL static void internal_endpoint_arm_out_pid(uint8_t pipe, uint8_t ep_addr)
65{
66 if ((ep_addr & (uint8_t)k_ra8_usb_ep_addr_dir_in_bit) != 0U) {
67 return; /* IN pipe -- queue_in / internal_submit_pipe own the PID */
68 }
69 /* Fresh OUT-pipe config: drop any orphan packet held from a prior
70 * configuration so it cannot be misdelivered to a new transfer. */
71 g_orphan_len = 0U;
72 bool auto_echo_pipe = false;
73 if (g_dcd_auto_echo_enable != 0U) {
74 if (pipe == g_dcd_auto_echo_out_pipe) {
75 auto_echo_pipe = true;
76 }
77 }
78 /* HUM Ch 36.2.27 "PIPEnCTR : PIPE n Control Register" p 2005 */
79 if (auto_echo_pipe) {
80 (void)ra8_usb_rearm_out_pipe(g_dcd.speed, pipe);
81 } else {
82 (void)ra8_usb_park_out_pipe(g_dcd.speed, pipe);
83 }
84}
85
100RA8_INTERNAL static unsigned int internal_endpoint_create(struct UX_SLAVE_ENDPOINT_STRUCT* ep)
101{
102 g_diag.ep_create_calls++;
103 if (ep == nullptr) {
104 return UX_ERROR;
105 }
106 const uint8_t ep_addr = (uint8_t)ep->ux_slave_endpoint_descriptor.bEndpointAddress;
107 const uint8_t pipe = priv_ep_to_pipe(ep_addr);
108 if (pipe == 0U || pipe >= (uint8_t)k_ux_dcd_ra8_usb_max_pipes) {
109 /* DCP is configured by ra8_usb_device_init; class layer should
110 * not call CREATE_ENDPOINT for EP0. */
111 return UX_SUCCESS;
112 }
113
114 ra8_usb_ep_dir_t dir = ((ep_addr & (uint8_t)k_ra8_usb_ep_addr_dir_in_bit) != 0U)
118 switch ((uint8_t)ep->ux_slave_endpoint_descriptor.bmAttributes & 0x03U) {
119 case 0x02U:
121 break;
122 case 0x03U:
124 break;
125 case 0x01U:
127 break;
128 default:
129 return UX_ERROR;
130 }
131
133 pipe,
134 (uint8_t)(ep_addr & (uint8_t)k_ra8_usb_ep_addr_num_mask),
135 dir,
136 type,
137 (uint16_t)ep->ux_slave_endpoint_descriptor.wMaxPacketSize) !=
138 k_ra8_ok) {
139 g_diag.ep_create_fail++;
140 return UX_ERROR;
141 }
142 g_dcd.pipes[pipe].ep_addr = ep_addr;
143 g_dcd.pipes[pipe].dir_in =
144 (uint8_t)((ep_addr & (uint8_t)k_ra8_usb_ep_addr_dir_in_bit) != 0U ? 1U : 0U);
145 g_dcd.pipes[pipe].max_pkt = (uint16_t)ep->ux_slave_endpoint_descriptor.wMaxPacketSize;
146 internal_endpoint_arm_out_pid(pipe, ep_addr);
147 return UX_SUCCESS;
148}
149
169RA8_INTERNAL static unsigned int internal_endpoint_stall(struct UX_SLAVE_ENDPOINT_STRUCT* ep)
170{
171 if (ep == nullptr) {
172 return UX_ERROR;
173 }
174 const uint8_t pipe = priv_ep_to_pipe((uint8_t)ep->ux_slave_endpoint_descriptor.bEndpointAddress);
175 if (pipe >= (uint8_t)k_ux_dcd_ra8_usb_max_pipes) {
176 return UX_ERROR;
177 }
178 return (ra8_usb_stall_endpoint(g_dcd.speed, pipe) == k_ra8_ok) ? UX_SUCCESS : UX_ERROR;
179}
180
181/* -------------------------------------------------------------------------- */
182/* USBX entry-point: the ux_slave_dcd_function trampoline */
183/* -------------------------------------------------------------------------- */
184
208RA8_INTERNAL static unsigned int internal_endpoint_destroy(struct UX_SLAVE_ENDPOINT_STRUCT* ep)
209{
210 if (ep == nullptr) {
211 return UX_ERROR;
212 }
213 const uint8_t pipe = priv_ep_to_pipe((uint8_t)ep->ux_slave_endpoint_descriptor.bEndpointAddress);
214 if (pipe < (uint8_t)k_ux_dcd_ra8_usb_max_pipes) {
215 g_dcd.pipes[pipe].xfer = nullptr;
216 }
217 return UX_SUCCESS;
218}
219
238RA8_INTERNAL static void internal_count_change_state(unsigned long state)
239{
240 if (state == (unsigned long)UX_DEVICE_ATTACHED) {
241 g_diag.chg_state_attached++;
242 }
243 if (state == (unsigned long)UX_DEVICE_CONFIGURED) {
244 g_diag.chg_state_configured++;
245 }
246}
247
248unsigned int
281_ux_dcd_ra8_usb_function(struct UX_SLAVE_DCD_STRUCT* dcd, unsigned int function, void* parameter)
282{
283 (void)dcd;
285 return UX_CONTROLLER_UNKNOWN;
286 }
287
288 switch (function) {
289 case UX_DCD_TRANSFER_REQUEST:
290 return priv_transfer_request((UX_SLAVE_TRANSFER*)parameter);
291
292 case UX_DCD_TRANSFER_ABORT:
293 /* Best effort: NAK the pipe by re-running endpoint configure. */
294 return UX_SUCCESS;
295
296 case UX_DCD_CREATE_ENDPOINT:
297 return internal_endpoint_create((UX_SLAVE_ENDPOINT*)parameter);
298
299 case UX_DCD_DESTROY_ENDPOINT:
300 return internal_endpoint_destroy((UX_SLAVE_ENDPOINT*)parameter);
301
302 case UX_DCD_RESET_ENDPOINT:
303 /* ra8_usb has no per-pipe reset that's exposed -- the class
304 * layer's expected sequence is destroy + create. We accept
305 * this as a no-op. */
306 return UX_SUCCESS;
307
308 case UX_DCD_STALL_ENDPOINT:
309 return internal_endpoint_stall((UX_SLAVE_ENDPOINT*)parameter);
310
311 case UX_DCD_SET_DEVICE_ADDRESS:
312 /* No-op: the SIE auto-responds to SET_ADDRESS (HUM Ch 37.3 p 2147)
313 * -- writing USBADDR from firmware fights the auto-latch and
314 * stalls enumeration. */
315 return UX_SUCCESS;
316
317 case UX_DCD_GET_FRAME_NUMBER:
318 if (parameter != nullptr) {
319 *(unsigned long*)parameter = 0UL; /* ra8_usb does not surface FRMNUM. */
320 }
321 return UX_SUCCESS;
322
323 case UX_DCD_CHANGE_STATE:
324 internal_count_change_state((unsigned long)parameter);
325 g_dcd.state = ((unsigned long)parameter != 0UL) ? k_ux_dcd_ra8_usb_state_active
327 return UX_SUCCESS;
328
329 case UX_DCD_ENDPOINT_STATUS:
330 return UX_SUCCESS;
331
332 case UX_DCD_ISR_PENDING:
333 return UX_SUCCESS;
334
335 default:
336 return UX_FUNCTION_NOT_SUPPORTED;
337 }
338}
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
Event Link Controller (ELC) register layout for the Renesas RA8D2.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
NVIC + ICU IELSR allocator.
Lightweight Logging Interface for ra8-firmware.
ra8_err_t ra8_usb_park_out_pipe(ra8_usb_speed_t speed, uint8_t pipe_num)
Park an OUT pipe at PID=NAK so an idle pipe stays quiescent.
ra8_usb_ep_type_t
Transfer type for a non-control endpoint.
@ k_ra8_usb_ep_type_bulk
Bulk transfer.
@ k_ra8_usb_ep_type_iso
Isochronous transfer.
@ k_ra8_usb_ep_type_intr
Interrupt transfer.
ra8_err_t ra8_usb_stall_endpoint(ra8_usb_speed_t speed, uint8_t pipe_num)
Stall a configured endpoint.
ra8_err_t ra8_usb_rearm_out_pipe(ra8_usb_speed_t speed, uint8_t pipe_num)
Re-arm an OUT pipe that the controller has parked at PID=NAK.
ra8_err_t ra8_usb_configure_endpoint(ra8_usb_speed_t speed, uint8_t pipe_num, uint8_t ep_addr, ra8_usb_ep_dir_t dir, ra8_usb_ep_type_t type, uint16_t max_packet)
Configure a non-control PIPE for IN or OUT bulk / interrupt / iso transfers.
ra8_usb_ep_dir_t
Endpoint direction.
@ k_ra8_usb_ep_dir_in
Device -> host.
@ k_ra8_usb_ep_dir_out
Host -> device.
USB Full-Speed + High-Speed controller layout for the Renesas RA8D2.
USBX device-controller-driver (DCD) bridge to ra8_usb.
@ k_ux_dcd_ra8_usb_max_pipes
DCP + 9 PIPE entries (HUM 36.1).
@ k_ux_dcd_ra8_usb_state_ready
Bridge installed; bus idle.
@ k_ux_dcd_ra8_usb_state_active
Class-layer transfers active.
@ k_ux_dcd_ra8_usb_state_uninit
Bridge not yet initialized.
static unsigned int internal_endpoint_create(struct UX_SLAVE_ENDPOINT_STRUCT *ep)
Translate a USBX endpoint create request into ra8_usb call.
static void internal_endpoint_arm_out_pid(uint8_t pipe, uint8_t ep_addr)
Set the power-on PID of a freshly created non-control pipe.
static unsigned int internal_endpoint_stall(struct UX_SLAVE_ENDPOINT_STRUCT *ep)
Endpoint stall.
static void internal_count_change_state(unsigned long state)
Count UX_DCD_CHANGE_STATE notifications by target state.
unsigned int _ux_dcd_ra8_usb_function(struct UX_SLAVE_DCD_STRUCT *dcd, unsigned int function, void *parameter)
USBX device-side DCD function dispatcher.
static unsigned int internal_endpoint_destroy(struct UX_SLAVE_ENDPOINT_STRUCT *ep)
Drop the bridge's per-pipe transfer stash for a destroyed endpoint.
USBX device-controller-driver bridge to ra8_usb – per-module cross-translation-unit contract.
uint8_t priv_ep_to_pipe(uint8_t ep_addr)
Map a USB EP number (1..9) into the PIPE table index.
volatile uint32_t g_dcd_auto_echo_enable
Non-zero once ISR-side auto-echo is armed.
uint8_t g_dcd_auto_echo_out_pipe
Pipe drained by the in-ISR auto-echo path.
uint16_t g_orphan_len
Held orphan byte count; 0 = empty.
ra8_usb_dcd_t g_dcd
The single bridge instance, defined in ux_dcd_ra8_usb.c.
ra8_usb_dcd_diag_t g_diag
Bridge diagnostic counter block, defined in ux_dcd_ra8_usb.c.
@ k_ra8_usb_ep_addr_dir_in_bit
Direction bit set => IN endpoint.
@ k_ra8_usb_ep_addr_num_mask
Endpoint-number field (bits 3:0).
unsigned int priv_transfer_request(struct UX_SLAVE_TRANSFER_STRUCT *tr)
USBX UX_DCD_TRANSFER_REQUEST dispatcher entry point.