ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ux_hcd_ra8_usb.c
Go to the documentation of this file.
1
18
19#define UX_SOURCE_CODE
20
21#include "ux_hcd_ra8_usb.h"
22
23#include <stdint.h>
24#include <string.h>
25
26#include "ra8_attributes.h"
27#include "ra8_check.h"
28#include "ra8_log.h"
29#include "ux_api.h"
30
31static const char* const s_tag = "ux_hcd_ra8_usb";
32
37typedef struct {
40 struct UX_HCD_STRUCT* owner;
42
50 .speed = k_ra8_usb_speed_fs,
51 .owner = nullptr,
52};
53
66
75typedef enum : uint8_t {
78
83typedef enum : uint8_t {
86
87/* -------------------------------------------------------------------------- */
88/* Internal helpers */
89/* -------------------------------------------------------------------------- */
90
110RA8_INTERNAL static uint8_t internal_ep_to_pipe(uint8_t ep_addr)
111{
112 const uint8_t ep = ep_addr & (uint8_t)k_ra8_usb_hcd_ep_addr_num_mask;
113 if (ep == 0U) {
114 return 0U;
115 }
116 if (ep < (uint8_t)k_ra8_usb_hcd_pipe_count) {
117 return ep;
118 }
119 return (uint8_t)k_ra8_usb_hcd_pipe_count;
120}
121
141RA8_INTERNAL static unsigned int internal_endpoint_create(struct UX_ENDPOINT_STRUCT* ep)
142{
143 if (ep == nullptr) {
144 return UX_ERROR;
145 }
146 const uint8_t ep_addr = (uint8_t)ep->ux_endpoint_descriptor.bEndpointAddress;
147 const uint8_t pipe = internal_ep_to_pipe(ep_addr);
148 if (pipe == 0U) {
149 /* DCP is configured during host_init. */
150 return UX_SUCCESS;
151 }
152 if (pipe >= (uint8_t)k_ra8_usb_hcd_pipe_count) {
153 return UX_SUCCESS;
154 }
155
156 ra8_usb_ep_dir_t dir = ((ep_addr & (uint8_t)k_ra8_usb_hcd_ep_addr_dir_in_bit) != 0U)
159
161 switch ((uint8_t)ep->ux_endpoint_descriptor.bmAttributes & 0x03U) {
162 case 0x02U:
164 break;
165 case 0x03U:
167 break;
168 case 0x01U:
170 break;
171 default:
172 return UX_ERROR;
173 }
174
175 return (ra8_usb_configure_endpoint(s_hcd.speed,
176 pipe,
177 (uint8_t)(ep_addr & (uint8_t)k_ra8_usb_hcd_ep_addr_num_mask),
178 dir,
179 type,
180 (uint16_t)ep->ux_endpoint_descriptor.wMaxPacketSize) ==
181 k_ra8_ok)
182 ? UX_SUCCESS
183 : UX_ERROR;
184}
185
212RA8_INTERNAL static unsigned int internal_control_xfer(struct UX_TRANSFER_STRUCT* tr)
213{
214 ra8_usb_setup_t setup = {
215 .bm_request_type = (uint8_t)tr->ux_transfer_request_function,
216 .b_request = (uint8_t)tr->ux_transfer_request_type,
217 .w_value = (uint16_t)tr->ux_transfer_request_value,
218 .w_index = (uint16_t)tr->ux_transfer_request_index,
219 .w_length = (uint16_t)tr->ux_transfer_request_requested_length,
220 };
221 if (ra8_usb_host_setup_request(s_hcd.speed, &setup) != k_ra8_ok) {
222 return UX_TRANSFER_ERROR;
223 }
224 if (tr->ux_transfer_request_requested_length != 0U &&
225 tr->ux_transfer_request_data_pointer != nullptr) {
226 uint16_t len = (uint16_t)tr->ux_transfer_request_requested_length;
227 if ((setup.bm_request_type & (uint8_t)k_ra8_usb_hcd_ep_addr_dir_in_bit) != 0U) {
228 if (ra8_usb_queue_out(s_hcd.speed, 0U, tr->ux_transfer_request_data_pointer, &len, true) !=
229 k_ra8_ok) {
230 return UX_TRANSFER_ERROR;
231 }
232 tr->ux_transfer_request_actual_length = len;
233 } else {
234 if (ra8_usb_queue_in(s_hcd.speed, 0U, tr->ux_transfer_request_data_pointer, len) !=
235 k_ra8_ok) {
236 return UX_TRANSFER_ERROR;
237 }
238 tr->ux_transfer_request_actual_length = len;
239 }
240 }
241 return UX_SUCCESS;
242}
243
268RA8_INTERNAL static unsigned int
269internal_bulk_xfer(struct UX_TRANSFER_STRUCT* tr, uint8_t ep_addr, uint8_t pipe)
270{
271 if ((ep_addr & (uint8_t)k_ra8_usb_hcd_ep_addr_dir_in_bit) != 0U) {
272 uint16_t len = (uint16_t)tr->ux_transfer_request_requested_length;
273 if (ra8_usb_queue_out(s_hcd.speed, pipe, tr->ux_transfer_request_data_pointer, &len, true) !=
274 k_ra8_ok) {
275 return UX_TRANSFER_ERROR;
276 }
277 tr->ux_transfer_request_actual_length = len;
278 } else {
279 const uint16_t len = (uint16_t)tr->ux_transfer_request_requested_length;
280 if (ra8_usb_queue_in(s_hcd.speed, pipe, tr->ux_transfer_request_data_pointer, len) !=
281 k_ra8_ok) {
282 return UX_TRANSFER_ERROR;
283 }
284 tr->ux_transfer_request_actual_length = len;
285 }
286 return UX_SUCCESS;
287}
288
308RA8_INTERNAL static unsigned int internal_transfer_request(struct UX_TRANSFER_STRUCT* tr)
309{
310 if (tr == nullptr || tr->ux_transfer_request_endpoint == nullptr) {
311 return UX_TRANSFER_ERROR;
312 }
313 UX_ENDPOINT* ep = tr->ux_transfer_request_endpoint;
314 const uint8_t ep_addr = (uint8_t)ep->ux_endpoint_descriptor.bEndpointAddress;
315 const uint8_t pipe = internal_ep_to_pipe(ep_addr);
316
317 if (pipe == 0U) {
318 return internal_control_xfer(tr);
319 }
320 if (pipe >= (uint8_t)k_ra8_usb_hcd_pipe_count) {
321 return UX_TRANSFER_ERROR;
322 }
323 return internal_bulk_xfer(tr, ep_addr, pipe);
324}
325
326/* -------------------------------------------------------------------------- */
327/* Dispatcher */
328/* -------------------------------------------------------------------------- */
329
351RA8_INTERNAL static unsigned int internal_port_reset(void)
352{
353 if (ra8_usb_host_bus_reset(s_hcd.speed, true) != k_ra8_ok) {
354 return UX_ERROR;
355 }
356 if (ra8_usb_host_bus_reset(s_hcd.speed, false) != k_ra8_ok) {
357 return UX_ERROR;
358 }
359 return UX_SUCCESS;
360}
361
384RA8_INTERNAL static unsigned int internal_port_set_enabled(bool enable)
385{
386 if (ra8_usb_host_set_uact(s_hcd.speed, enable) != k_ra8_ok) {
387 return UX_ERROR;
388 }
390 return UX_SUCCESS;
391}
392
426unsigned int
427_ux_hcd_ra8_usb_function(struct UX_HCD_STRUCT* hcd, unsigned int function, void* parameter)
428{
429 (void)hcd;
431 return UX_CONTROLLER_UNKNOWN;
432 }
433
434 switch (function) {
435 case UX_HCD_CREATE_ENDPOINT:
436 return internal_endpoint_create((UX_ENDPOINT*)parameter);
437
438 case UX_HCD_DESTROY_ENDPOINT:
439 case UX_HCD_RESET_ENDPOINT:
440 return UX_SUCCESS;
441
442 case UX_HCD_TRANSFER_REQUEST:
443 return internal_transfer_request((UX_TRANSFER*)parameter);
444
445 case UX_HCD_TRANSFER_ABORT:
446 return UX_SUCCESS;
447
448 case UX_HCD_RESET_PORT:
449 return internal_port_reset();
450
451 case UX_HCD_ENABLE_PORT:
452 return internal_port_set_enabled(true);
453
454 case UX_HCD_DISABLE_PORT:
455 case UX_HCD_POWER_DOWN_PORT:
456 return internal_port_set_enabled(false);
457
458 case UX_HCD_POWER_ON_PORT:
459 return UX_SUCCESS;
460
461 case UX_HCD_GET_PORT_STATUS:
462 case UX_HCD_GET_FRAME_NUMBER:
463 if (parameter != nullptr) {
464 *(unsigned long*)parameter = 0UL;
465 }
466 return UX_SUCCESS;
467
468 case UX_HCD_PROCESS_DONE_QUEUE:
469 case UX_HCD_DISABLE_CONTROLLER:
470 case UX_HCD_UNINITIALIZE:
471 return UX_SUCCESS;
472
473 default:
474 return UX_FUNCTION_NOT_SUPPORTED;
475 }
476}
477
478/* -------------------------------------------------------------------------- */
479/* Lifecycle */
480/* -------------------------------------------------------------------------- */
481
502{
503 if ((uint8_t)speed > (uint8_t)k_ra8_usb_speed_hs) {
505 }
506 RA8_RETURN_ON_ERROR(ra8_usb_host_init(speed), s_tag, "ra8_usb_host_init");
507
508 if (_ux_system_host == UX_NULL || _ux_system_host->ux_system_host_hcd_array == UX_NULL) {
510 }
511
512 /* Pick the first free HCD slot. UX_MAX_HCD defaults to 1 in
513 * ux_port.h; we walk up to UX_SYSTEM_HOST_MAX_HCD_GET() entries. */
514 UX_HCD* slot = _ux_system_host->ux_system_host_hcd_array;
515 const UINT max_hcds = UX_SYSTEM_HOST_MAX_HCD_GET();
516 for (UINT i = 0; i < max_hcds; i++) {
517 if (slot->ux_hcd_status == UX_HCD_STATUS_UNUSED) {
518 break;
519 }
520 slot++;
521 }
522 slot->ux_hcd_status = UX_HCD_STATUS_OPERATIONAL;
523 slot->ux_hcd_controller_type = (UINT)k_ra8_usb_hcd_controller_id;
524 slot->ux_hcd_nb_root_hubs = 1U;
525 slot->ux_hcd_entry_function = _ux_hcd_ra8_usb_function;
526 slot->ux_hcd_controller_hardware = (void*)&s_hcd;
527
528 s_hcd.owner = slot;
529 s_hcd.speed = speed;
531
532 ra8_log_info(s_tag, "HCD bridge installed");
533 return k_ra8_ok;
534}
535
554{
557 }
558 (void)ra8_usb_host_set_uact(s_hcd.speed, false);
559 (void)ra8_usb_host_deinit(s_hcd.speed);
560 if (s_hcd.owner != nullptr) {
561 s_hcd.owner->ux_hcd_status = UX_HCD_STATUS_HALTED;
562 s_hcd.owner->ux_hcd_entry_function = nullptr;
563 }
565 s_hcd.owner = nullptr;
566 return k_ra8_ok;
567}
568
587{
588 return s_hcd.state;
589}
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_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
@ 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
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_info(tag, message)
RA8 log info.
Definition ra8_log.h:364
ra8_err_t ra8_usb_queue_out(ra8_usb_speed_t speed, uint8_t pipe_num, uint8_t *out_buf, uint16_t *inout_len, bool rearm)
Drain an OUT transfer (host -> device) from pipe_num.
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_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.
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_err_t ra8_usb_queue_in(ra8_usb_speed_t speed, uint8_t pipe_num, const uint8_t *data, uint16_t len)
Queue an IN transfer (device -> host) on pipe_num.
ra8_err_t ra8_usb_host_bus_reset(ra8_usb_speed_t speed, bool assert_reset)
Drive (or release) the bus reset line.
ra8_err_t ra8_usb_host_init(ra8_usb_speed_t speed)
Bring up a USB controller in HOST mode.
ra8_err_t ra8_usb_host_deinit(ra8_usb_speed_t speed)
Tear down a host-mode controller and drop its MSTP reference.
ra8_err_t ra8_usb_host_setup_request(ra8_usb_speed_t speed, const ra8_usb_setup_t *setup)
Issue a SETUP packet through the DCP (host -> peripheral).
ra8_err_t ra8_usb_host_set_uact(ra8_usb_speed_t speed, bool enable)
Enable / disable SOF (Start-of-Frame) generation on the bus.
unsigned int UINT
ThreadX-compatible unsigned int (host stub).
Bridge-singleton state.
struct UX_HCD_STRUCT * owner
Back-pointer into USBX.
ra8_usb_hcd_state_t state
Bridge run-state.
ra8_usb_speed_t speed
Controller this drives.
Decoded 8-byte USB SETUP packet.
uint8_t bm_request_type
Request direction / type / recipient.
static unsigned int internal_endpoint_create(struct UX_ENDPOINT_STRUCT *ep)
Endpoint create.
ra8_err_t ux_hcd_ra8_usb_initialize(ra8_usb_speed_t speed)
Ux hcd ra usb initialize.
static unsigned int internal_control_xfer(struct UX_TRANSFER_STRUCT *tr)
Drive the EP0 control transfer SETUP + optional data stage.
unsigned int _ux_hcd_ra8_usb_function(struct UX_HCD_STRUCT *hcd, unsigned int function, void *parameter)
USBX host-side HCD function dispatcher.
ra8_usb_hcd_ctrl_id_t
Private USBX controller-type id reported by this HCD bridge.
@ k_ra8_usb_hcd_controller_id
RA-USB private controller id.
static ra8_usb_hcd_t s_hcd
Bridge instance.
static unsigned int internal_transfer_request(struct UX_TRANSFER_STRUCT *tr)
Transfer request.
static unsigned int internal_bulk_xfer(struct UX_TRANSFER_STRUCT *tr, uint8_t ep_addr, uint8_t pipe)
Drive a bulk / interrupt transfer on a non-EP0 pipe.
ra8_err_t ux_hcd_ra8_usb_uninitialize(void)
Ux hcd ra usb uninitialize.
ra8_usb_hcd_pipe_t
Pipe-index bounds for the host bridge.
@ k_ra8_usb_hcd_pipe_count
Valid pipes 0..9; 10 == out-of-range.
ra8_usb_hcd_ep_addr_field_t
Bit fields of a USB endpoint address (bEndpointAddress).
@ k_ra8_usb_hcd_ep_addr_dir_in_bit
Direction bit set => IN.
@ k_ra8_usb_hcd_ep_addr_num_mask
Endpoint-number field (bits 3:0).
ra8_usb_hcd_state_t ux_hcd_ra8_usb_state(void)
Ux hcd ra usb state.
static uint8_t internal_ep_to_pipe(uint8_t ep_addr)
Ep to pipe.
static unsigned int internal_port_set_enabled(bool enable)
Enable or disable the root-hub port via DVSTCTR0.UACT.
static unsigned int internal_port_reset(void)
Pulse the root-hub port reset (assert then deassert).
USBX host-controller-driver (HCD) bridge to ra8_usb.
unsigned int _ux_hcd_ra8_usb_function(struct UX_HCD_STRUCT *hcd, unsigned int function, void *parameter)
ux hcd ra usb function.
ra8_usb_hcd_state_t
Run-state of the HCD bridge.
@ k_ux_hcd_ra8_usb_state_uninit
Bridge not yet initialized.
@ k_ux_hcd_ra8_usb_state_ready
Bridge installed; bus idle.
@ k_ux_hcd_ra8_usb_state_active
SOF generation enabled.