summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-01-08 11:33:08 +0700
committerhathach <[email protected]>2026-01-08 12:34:13 +0700
commit07416f704f1a55b286d5c9b082e6f1e3e51ce9b0 (patch)
tree205577ffeee30dbafbe3d1f8c35ac79e24b565c6 /src
parentf0a3d448347047c9df62518fbd641502b2d55333 (diff)
minor clean up
Diffstat (limited to 'src')
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c68
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c31
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c26
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.h34
4 files changed, 77 insertions, 82 deletions
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index 5c21590c4..952245cb1 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -71,18 +71,17 @@ TU_ATTR_ALWAYS_INLINE static inline hw_endpoint_t *hw_endpoint_get_by_addr(uint8
// main processing for dcd_edpt_iso_activate
static void hw_endpoint_init(hw_endpoint_t *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
- const uint8_t epnum = tu_edpt_number(ep_addr);
-
ep->ep_addr = ep_addr;
ep->next_pid = 0u;
ep->wMaxPacketSize = wMaxPacketSize;
ep->transfer_type = transfer_type;
// Clear existing buffer control state
- io_rw_32 *buf_ctrl_reg = hwep_buf_ctrl_reg_device(ep);
+ io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
*buf_ctrl_reg = 0;
// allocated hw buffer
+ const uint8_t epnum = tu_edpt_number(ep_addr);
if (epnum == 0) {
// Buffer offset is fixed (also double buffered)
ep->hw_data_buf = (uint8_t*) &usb_dpram->ep0_buf_a[0];
@@ -104,16 +103,9 @@ static void hw_endpoint_init(hw_endpoint_t *ep, uint8_t ep_addr, uint16_t wMaxPa
}
}
-// Init, allocate buffer and enable endpoint
-static void hw_endpoint_open(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
- const uint8_t epnum = tu_edpt_number(ep_addr);
- const tusb_dir_t dir = tu_edpt_dir(ep_addr);
- hw_endpoint_t *ep = hw_endpoint_get(epnum, dir);
-
- hw_endpoint_init(ep, ep_addr, wMaxPacketSize, transfer_type);
-
- // Set endpoint control register to enable (EP0 has no endpoint control register)
+static void hw_endpoint_enable(hw_endpoint_t *ep, uint8_t transfer_type) {
io_rw_32 *ctrl_reg = hwep_ctrl_reg_device(ep);
+ // Set endpoint control register to enable (EP0 has no endpoint control register)
if (ctrl_reg != NULL) {
const uint32_t ctrl_value =
EP_CTRL_ENABLE_BITS | ((uint32_t)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->hw_data_buf);
@@ -121,14 +113,24 @@ static void hw_endpoint_open(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t t
}
}
+// Init and enable endpoint
+static void hw_endpoint_open(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
+ const uint8_t epnum = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ hw_endpoint_t *ep = hw_endpoint_get(epnum, dir);
+
+ hw_endpoint_init(ep, ep_addr, wMaxPacketSize, transfer_type);
+ hw_endpoint_enable(ep, transfer_type);
+}
+
static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) {
// Abort any pending transfer
- // Due to Errata RP2040-E2: ABORT flag is only applicable for B2 and later (unusable for B0, B1).
- // Which means we are not guaranteed to safely abort pending transfer on B0 and B1.
const uint8_t dir = (uint8_t)tu_edpt_dir(ep->ep_addr);
- const uint8_t epnum = tu_edpt_number(ep->ep_addr);
+ const uint8_t epnum = tu_edpt_number(ep->ep_addr);
const uint32_t abort_mask = TU_BIT((epnum << 1) | (dir ? 0 : 1));
+ // Due to Errata RP2040-E2: ABORT flag is only applicable for B2 and later (unusable for B0, B1).
+ // Which means we are not guaranteed to safely abort pending transfer on B0 and B1.
if (rp2040_chip_version() >= 2) {
usb_hw_set->abort = abort_mask;
while ((usb_hw->abort_done & abort_mask) != abort_mask) {}
@@ -139,8 +141,8 @@ static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) {
buf_ctrl |= USB_BUF_CTRL_DATA1_PID;
}
- io_rw_32 *buf_ctrl_reg = hwep_buf_ctrl_reg_device(ep);
- hwep_buf_ctrl_set(buf_ctrl_reg, buf_ctrl);
+ io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
+ hwbuf_ctrl_set(buf_ctrl_reg, buf_ctrl);
hw_endpoint_reset_transfer(ep);
if (rp2040_chip_version() >= 2) {
@@ -265,15 +267,12 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
#if FORCE_VBUS_DETECT == 0
// Since we force VBUS detect On, device will always think it is connected and
// couldn't distinguish between disconnect and suspend
- if (status & USB_INTS_DEV_CONN_DIS_BITS)
- {
+ if (status & USB_INTS_DEV_CONN_DIS_BITS) {
handled |= USB_INTS_DEV_CONN_DIS_BITS;
- if ( usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS )
- {
+ if (usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS) {
// Connected: nothing to do
- }else
- {
+ } else {
// Disconnected
dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
}
@@ -295,8 +294,10 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
// Only run enumeration workaround if pull up is enabled
- if (usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS) rp2040_usb_device_enumeration_fix();
-#endif
+ if (usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS) {
+ rp2040_usb_device_enumeration_fix();
+ }
+ #endif
}
/* Note from pico datasheet 4.1.2.6.4 (v1.2)
@@ -458,7 +459,6 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* req
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
(void) rhport;
const uint8_t xfer_type = desc_edpt->bmAttributes.xfer;
- TU_VERIFY(xfer_type != TUSB_XFER_ISOCHRONOUS);
hw_endpoint_open(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), xfer_type);
return true;
}
@@ -485,13 +485,7 @@ bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *ep_desc)
}
ep->wMaxPacketSize = ep_desc->wMaxPacketSize;
- // Set control register to enable endpoint
- io_rw_32 *ctrl_reg = hwep_ctrl_reg_device(ep);
- if (ctrl_reg != NULL) {
- const uint32_t ctrl_value = EP_CTRL_ENABLE_BITS | ((uint32_t)TUSB_XFER_ISOCHRONOUS << EP_CTRL_BUFFER_TYPE_LSB) |
- hw_data_offset(ep->hw_data_buf);
- *ctrl_reg = ctrl_value;
- }
+ hw_endpoint_enable(ep, TUSB_XFER_ISOCHRONOUS);
return true;
}
@@ -522,8 +516,8 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
}
// stall and clear current pending buffer, may need to use EP_ABORT
- io_rw_32 *buf_ctrl_reg = hwep_buf_ctrl_reg_device(ep);
- hwep_buf_ctrl_set(buf_ctrl_reg, USB_BUF_CTRL_STALL);
+ io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
+ hwbuf_ctrl_set(buf_ctrl_reg, USB_BUF_CTRL_STALL);
}
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
@@ -534,8 +528,8 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
// clear stall also reset toggle to DATA0, ready for next transfer
ep->next_pid = 0;
- io_rw_32 *buf_ctrl_reg = hwep_buf_ctrl_reg_device(ep);
- hwep_buf_ctrl_clear_mask(buf_ctrl_reg, USB_BUF_CTRL_STALL);
+ io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
+ hwbuf_ctrl_clear_mask(buf_ctrl_reg, USB_BUF_CTRL_STALL);
}
}
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index 2e5f0fe1f..c4eba0d5f 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -62,22 +62,23 @@ enum {
USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS
};
-static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr)
-{
+static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr) {
uint8_t num = tu_edpt_number(ep_addr);
- if ( num == 0 ) return &epx;
+ if (num == 0) {
+ return &epx;
+ }
- for ( uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++ )
- {
+ for (uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++) {
struct hw_endpoint *ep = &ep_pool[i];
- if ( ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr) ) return ep;
+ if (ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr)) {
+ return ep;
+ }
}
return NULL;
}
-TU_ATTR_ALWAYS_INLINE static inline uint8_t dev_speed(void)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint8_t dev_speed(void) {
return (usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS) >> USB_SIE_STATUS_SPEED_LSB;
}
@@ -98,8 +99,7 @@ static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_
hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true);
}
-static void __tusb_irq_path_func(_handle_buff_status_bit)(uint bit, struct hw_endpoint *ep)
-{
+static void __tusb_irq_path_func(_handle_buff_status_bit)(uint bit, struct hw_endpoint *ep) {
usb_hw_clear->buf_status = bit;
// EP may have been stalled?
assert(ep->active);
@@ -357,8 +357,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
// Finally, enable interrupt that endpoint
usb_hw_set->int_ep_ctrl = 1 << (ep->interrupt_num + 1);
- // If it's an interrupt endpoint we need to set up the buffer control
- // register
+ // If it's an interrupt endpoint we need to set up the buffer control register
}
}
@@ -456,8 +455,8 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
// reset epx if it is currently active with unplugged device
if (epx.configured && epx.active && epx.dev_addr == dev_addr) {
epx.configured = false;
- *hwep_ctrl_reg_host(&epx) = 0;
- *hwep_buf_ctrl_reg_host(&epx) = 0;
+ *hwep_ctrl_reg_host(&epx) = 0;
+ *hwbuf_ctrl_reg_host(&epx) = 0;
hw_endpoint_reset_transfer(&epx);
}
@@ -472,8 +471,8 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
// unconfigure the endpoint
ep->configured = false;
- *hwep_ctrl_reg_host(ep) = 0;
- *hwep_buf_ctrl_reg_host(ep) = 0;
+ *hwep_ctrl_reg_host(ep) = 0;
+ *hwbuf_ctrl_reg_host(ep) = 0;
hw_endpoint_reset_transfer(ep);
}
}
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index 5258b9705..798129e0c 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -88,7 +88,7 @@ void __tusb_irq_path_func(hw_endpoint_reset_transfer)(struct hw_endpoint* ep) {
ep->user_buf = 0;
}
-void __tusb_irq_path_func(hwep_buf_ctrl_update)(io_rw_32 *buf_ctrl_reg, uint32_t and_mask, uint32_t or_mask) {
+void __tusb_irq_path_func(hwbuf_ctrl_update)(io_rw_32 *buf_ctrl_reg, uint32_t and_mask, uint32_t or_mask) {
const bool is_host = rp2usb_is_host_mode();
uint32_t value = 0;
uint32_t buf_ctrl = *buf_ctrl_reg;
@@ -101,7 +101,7 @@ void __tusb_irq_path_func(hwep_buf_ctrl_update)(io_rw_32 *buf_ctrl_reg, uint32_t
value |= or_mask;
if (or_mask & USB_BUF_CTRL_AVAIL) {
if (buf_ctrl & USB_BUF_CTRL_AVAIL) {
- panic("buf_ctrl @%lX already available", (uintptr_t)buf_ctrl_reg);
+ panic("buf_ctrl @ 0x%lX already available", (uintptr_t)buf_ctrl_reg);
}
*buf_ctrl_reg = value & ~USB_BUF_CTRL_AVAIL;
@@ -162,15 +162,15 @@ void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint* ep)
#if CFG_TUH_ENABLED
const bool is_host = rp2usb_is_host_mode();
if (is_host) {
- buf_ctrl_reg = hwep_buf_ctrl_reg_host(ep);
- ep_ctrl_reg = hwep_ctrl_reg_host(ep);
- is_rx = (dir == TUSB_DIR_IN);
+ buf_ctrl_reg = hwbuf_ctrl_reg_host(ep);
+ ep_ctrl_reg = hwep_ctrl_reg_host(ep);
+ is_rx = (dir == TUSB_DIR_IN);
} else
#endif
{
- buf_ctrl_reg = hwep_buf_ctrl_reg_device(ep);
- ep_ctrl_reg = hwep_ctrl_reg_device(ep);
- is_rx = (dir == TUSB_DIR_OUT);
+ buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
+ ep_ctrl_reg = hwep_ctrl_reg_device(ep);
+ is_rx = (dir == TUSB_DIR_OUT);
}
// always compute and start with buffer 0
@@ -209,7 +209,7 @@ void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint* ep)
// Finally, write to buffer_control which will trigger the transfer
// the next time the controller polls this dpram address
- hwep_buf_ctrl_set(buf_ctrl_reg, buf_ctrl);
+ hwbuf_ctrl_set(buf_ctrl_reg, buf_ctrl);
}
void hw_endpoint_xfer_start(struct hw_endpoint* ep, uint8_t* buffer, uint16_t total_len) {
@@ -287,13 +287,13 @@ static void __tusb_irq_path_func(hwep_xfer_sync)(hw_endpoint_t *ep) {
#if CFG_TUH_ENABLED
const bool is_host = rp2usb_is_host_mode();
if (is_host) {
- buf_ctrl_reg = hwep_buf_ctrl_reg_host(ep);
+ buf_ctrl_reg = hwbuf_ctrl_reg_host(ep);
ep_ctrl_reg = hwep_ctrl_reg_host(ep);
is_rx = (dir == TUSB_DIR_IN);
} else
#endif
{
- buf_ctrl_reg = hwep_buf_ctrl_reg_device(ep);
+ buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
ep_ctrl_reg = hwep_ctrl_reg_device(ep);
is_rx = (dir == TUSB_DIR_OUT);
}
@@ -327,8 +327,8 @@ static void __tusb_irq_path_func(hwep_xfer_sync)(hw_endpoint_t *ep) {
ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
- io_rw_32 *buf_ctrl_reg = is_host ? hwep_buf_ctrl_reg_host(ep) : hwep_buf_ctrl_reg_device(ep);
- hwep_buf_ctrl_set(buf_ctrl_reg, 0);
+ io_rw_32 *buf_ctrl_reg = is_host ? hwbuf_ctrl_reg_host(ep) : hwbuf_ctrl_reg_device(ep);
+ hwbuf_ctrl_set(buf_ctrl_reg, 0);
usb_hw->abort &= ~TU_BIT(ep_id);
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h
index e9fed73de..368bb6509 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.h
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h
@@ -1,10 +1,6 @@
#ifndef RP2040_COMMON_H_
#define RP2040_COMMON_H_
-#if defined(RP2040_USB_HOST_MODE) && defined(RP2040_USB_DEVICE_MODE)
-#error TinyUSB device and host mode not supported at the same time
-#endif
-
#include "common/tusb_common.h"
#include "pico.h"
@@ -13,6 +9,10 @@
#include "hardware/resets.h"
#include "hardware/timer.h"
+#if defined(RP2040_USB_HOST_MODE) && defined(RP2040_USB_DEVICE_MODE)
+ #error TinyUSB device and host mode not supported at the same time
+#endif
+
#if defined(PICO_RP2040_USB_DEVICE_ENUMERATION_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX)
#define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX PICO_RP2040_USB_DEVICE_ENUMERATION_FIX
#endif
@@ -36,6 +36,9 @@
#define __tusb_irq_path_func(x) x
#endif
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
#define usb_hw_set ((usb_hw_t *) hw_set_alias_untyped(usb_hw))
#define usb_hw_clear ((usb_hw_t *) hw_clear_alias_untyped(usb_hw))
@@ -56,9 +59,9 @@ typedef struct hw_endpoint
uint16_t wMaxPacketSize;
uint8_t *hw_data_buf; // Buffer pointer in usb dpram
- uint8_t *user_buf; // User buffer in main memory
// Current transfer information
+ uint8_t *user_buf; // User buffer in main memory
uint16_t remaining_len;
uint16_t xferred_len;
@@ -108,7 +111,7 @@ TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwep_ctrl_reg_device(struct hw_end
return (dir == TUSB_DIR_IN) ? &usb_dpram->ep_ctrl[epnum - 1].in : &usb_dpram->ep_ctrl[epnum - 1].out;
}
-TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwep_buf_ctrl_reg_device(struct hw_endpoint *ep) {
+TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwbuf_ctrl_reg_device(struct hw_endpoint *ep) {
const uint8_t epnum = tu_edpt_number(ep->ep_addr);
const uint8_t dir = (uint8_t)tu_edpt_dir(ep->ep_addr);
return (dir == TUSB_DIR_IN) ? &usb_dpram->ep_buf_ctrl[epnum].in : &usb_dpram->ep_buf_ctrl[epnum].out;
@@ -123,30 +126,29 @@ TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwep_ctrl_reg_host(struct hw_endpo
return &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl;
}
-TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwep_buf_ctrl_reg_host(struct hw_endpoint *ep) {
- if (ep->transfer_type == TUSB_XFER_CONTROL) {
+TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwbuf_ctrl_reg_host(struct hw_endpoint *ep) {
+ if (tu_edpt_number(ep->ep_addr) == 0) {
return &usbh_dpram->epx_buf_ctrl;
}
return &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl;
}
#endif
-
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
-void hwep_buf_ctrl_update(io_rw_32 *buf_ctrl_reg, uint32_t and_mask, uint32_t or_mask);
+void hwbuf_ctrl_update(io_rw_32 *buf_ctrl_reg, uint32_t and_mask, uint32_t or_mask);
-TU_ATTR_ALWAYS_INLINE static inline void hwep_buf_ctrl_set(io_rw_32 *buf_ctrl_reg, uint32_t value) {
- hwep_buf_ctrl_update(buf_ctrl_reg, 0, value);
+TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_set(io_rw_32 *buf_ctrl_reg, uint32_t value) {
+ hwbuf_ctrl_update(buf_ctrl_reg, 0, value);
}
-TU_ATTR_ALWAYS_INLINE static inline void hwep_buf_ctrl_set_mask(io_rw_32 *buf_ctrl_reg, uint32_t value) {
- hwep_buf_ctrl_update(buf_ctrl_reg, ~value, value);
+TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_set_mask(io_rw_32 *buf_ctrl_reg, uint32_t value) {
+ hwbuf_ctrl_update(buf_ctrl_reg, ~value, value);
}
-TU_ATTR_ALWAYS_INLINE static inline void hwep_buf_ctrl_clear_mask(io_rw_32 *buf_ctrl_reg, uint32_t value) {
- hwep_buf_ctrl_update(buf_ctrl_reg, ~value, 0);
+TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_clear_mask(io_rw_32 *buf_ctrl_reg, uint32_t value) {
+ hwbuf_ctrl_update(buf_ctrl_reg, ~value, 0);
}
static inline uintptr_t hw_data_offset(uint8_t *buf) {