From 936fd0145896acbf55de496f036af55a01b80e82 Mon Sep 17 00:00:00 2001 From: "Luke T. Shumaker" Date: Fri, 15 Nov 2024 11:58:59 -0700 Subject: libhw_generic: Split into a separate library --- CMakeLists.txt | 1 + libhw/CMakeLists.txt | 14 +-- libhw/common_alarmclock.c | 21 ---- libhw/common_include/libhw/generic/alarmclock.h | 98 --------------- libhw/common_include/libhw/generic/net.h | 154 ----------------------- libhw/common_include/libhw/generic/spi.h | 47 ------- libhw_generic/CMakeLists.txt | 15 +++ libhw_generic/alarmclock.c | 21 ++++ libhw_generic/include/libhw/generic/alarmclock.h | 98 +++++++++++++++ libhw_generic/include/libhw/generic/net.h | 154 +++++++++++++++++++++++ libhw_generic/include/libhw/generic/spi.h | 47 +++++++ 11 files changed, 341 insertions(+), 329 deletions(-) delete mode 100644 libhw/common_alarmclock.c delete mode 100644 libhw/common_include/libhw/generic/alarmclock.h delete mode 100644 libhw/common_include/libhw/generic/net.h delete mode 100644 libhw/common_include/libhw/generic/spi.h create mode 100644 libhw_generic/CMakeLists.txt create mode 100644 libhw_generic/alarmclock.c create mode 100644 libhw_generic/include/libhw/generic/alarmclock.h create mode 100644 libhw_generic/include/libhw/generic/net.h create mode 100644 libhw_generic/include/libhw/generic/spi.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e42490..eef2617 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,6 +93,7 @@ endfunction() add_subdirectory(libmisc) add_subdirectory(libcr) add_subdirectory(libcr_ipc) +add_subdirectory(libhw_generic) add_subdirectory(libhw) add_subdirectory(libdhcp) add_subdirectory(libusb) diff --git a/libhw/CMakeLists.txt b/libhw/CMakeLists.txt index 3627641..d1767da 100644 --- a/libhw/CMakeLists.txt +++ b/libhw/CMakeLists.txt @@ -1,22 +1,18 @@ -# libhw/CMakeLists.txt - TODO +# libhw/CMakeLists.txt - Device drivers # # Copyright (C) 2024 Luke T. Shumaker # SPDX-License-Identifier: AGPL-3.0-or-later add_library(libhw INTERFACE) -target_include_directories(libhw SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/common_include) target_link_libraries(libhw INTERFACE - libcr - libcr_ipc - libmisc -) - -target_sources(libhw INTERFACE - common_alarmclock.c + libhw_generic ) if (PICO_PLATFORM STREQUAL "rp2040") target_include_directories(libhw SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/rp2040_include) + target_link_libraries(libhw INTERFACE + libcr_ipc + ) target_sources(libhw INTERFACE rp2040_hwtimer.c rp2040_hwspi.c diff --git a/libhw/common_alarmclock.c b/libhw/common_alarmclock.c deleted file mode 100644 index 9812d44..0000000 --- a/libhw/common_alarmclock.c +++ /dev/null @@ -1,21 +0,0 @@ -/* libhw/common_alarmclock.c - Device-independent utilities - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#include -#include - -#include - -static void alarmclock_sleep_intrhandler(void *_arg) { - cid_t *cid = _arg; - cr_unpause_from_intrhandler(*cid); -} - -void alarmclock_sleep_until_ns(implements_alarmclock *clock, uint64_t abstime_ns) { - cid_t cid = cr_getcid(); - struct alarmclock_trigger trigger; - VCALL(clock, add_trigger, &trigger, abstime_ns, alarmclock_sleep_intrhandler, &cid); -} diff --git a/libhw/common_include/libhw/generic/alarmclock.h b/libhw/common_include/libhw/generic/alarmclock.h deleted file mode 100644 index a9d816b..0000000 --- a/libhw/common_include/libhw/generic/alarmclock.h +++ /dev/null @@ -1,98 +0,0 @@ -/* libhw/generic/alarmclock.h - Device-independent alarmclock definitions - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#ifndef _LIBHW_GENERIC_ALARMCLOCK_H_ -#define _LIBHW_GENERIC_ALARMCLOCK_H_ - -#include /* for bool */ -#include /* for uint{n}_t and UINT{n}_C */ - -#include -#include - -/* Useful constants ***********************************************************/ - -#define NS_PER_S UINT64_C(1000000000) /* needs at least log₂(10⁹) ≈ 29.9 bits */ -#define US_PER_S UINT64_C(1000000) /* needs at least log₂(10⁶) ≈ 19.9 bits */ -#define MS_PER_S UINT64_C(1000) /* needs at least log₂(10³) ≈ 9.9 bits */ - -/* Structs ********************************************************************/ - -struct alarmclock_trigger; -struct alarmclock_trigger { - BEGIN_PRIVATE(LIBHW_GENERIC_ALARMCLOCK_H) - void *alarmclock; - struct alarmclock_trigger *prev, *next; - - uint64_t fire_at_ns; - void (*cb)(void *); - void *cb_arg; - END_PRIVATE(LIBHW_GENERIC_ALARMCLOCK_H) -}; - -/* Interface ******************************************************************/ - -struct alarmclock_vtable; - -typedef struct { - struct alarmclock_vtable *vtable; -} implements_alarmclock; - -struct alarmclock_vtable { - /** - * (2⁶⁴-1 nanoseconds is more than 500 years; there is little - * risk of this overflowing) - */ - uint64_t (*get_time_ns)(implements_alarmclock *self); - - /** - * Returns true on error. - * - * Implementations may return an error if fire_at_ns is more - * than UINT32_MAX µs (72 minutes) in the future. - * - * If fire_at_ns is in the past, then it will fire - * immediately. - */ - bool (*add_trigger)(implements_alarmclock *self, struct alarmclock_trigger *trigger, - uint64_t fire_at_ns, - void (*cb)(void *), - void *cb_arg); - - void (*del_trigger)(implements_alarmclock *self, struct alarmclock_trigger *trigger); -}; - -/* Utilities ******************************************************************/ - -void alarmclock_sleep_until_ns(implements_alarmclock *clock, uint64_t abstime_ns); - -static inline void alarmclock_sleep_for_ns(implements_alarmclock *clock, uint64_t delta_ns) { - alarmclock_sleep_until_ns(clock, VCALL(clock, get_time_ns) + delta_ns); -} - -static inline void alarmclock_sleep_for_us(implements_alarmclock *clock, uint64_t delta_us) { - alarmclock_sleep_for_ns(clock, delta_us * (NS_PER_S/US_PER_S)); -} - -static inline void alarmclock_sleep_for_ms(implements_alarmclock *clock, uint64_t delta_ms) { - alarmclock_sleep_for_ns(clock, delta_ms * (NS_PER_S/MS_PER_S)); -} - -static inline void alarmclock_sleep_for_s(implements_alarmclock *clock, uint64_t delta_s) { - alarmclock_sleep_for_ns(clock, delta_s * NS_PER_S); -} - -/* Globals ********************************************************************/ - -extern implements_alarmclock *bootclock; - -#define sleep_until_ns(t) alarmclock_sleep_until_ns(bootclock, t) -#define sleep_for_ns(t) alarmclock_sleep_for_ns(bootclock, t) -#define sleep_for_us(t) alarmclock_sleep_for_us(bootclock, t) -#define sleep_for_ms(t) alarmclock_sleep_for_ms(bootclock, t) -#define sleep_for_s(t) alarmclock_sleep_for_s(bootclock, t) - -#endif /* _LIBHW_GENERIC_ALARMCLOCK_H_ */ diff --git a/libhw/common_include/libhw/generic/net.h b/libhw/common_include/libhw/generic/net.h deleted file mode 100644 index def533c..0000000 --- a/libhw/common_include/libhw/generic/net.h +++ /dev/null @@ -1,154 +0,0 @@ -/* libhw/generic/net.h - Device-independent network definitions - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#ifndef _LIBHW_GENERIC_NET_H_ -#define _LIBHW_GENERIC_NET_H_ - -#include /* for bool */ -#include /* for size_t */ -#include /* for uint{n}_t} */ -#include /* for ssize_t */ - -/* Errnos *********************************************************************/ - -#define NET_EOTHER 1 -#define NET_ETIMEDOUT 2 -#define NET_ETHREAD 3 -#define NET_ECLOSED 4 -#define NET_EMSGSIZE 5 - -/* Address types **************************************************************/ - -struct net_ip4_addr { - unsigned char octets[4]; -}; - -static const struct net_ip4_addr net_ip4_addr_broadcast = {{255, 255, 255, 255}}; -static const struct net_ip4_addr net_ip4_addr_zero = {{0, 0, 0, 0}}; - -struct net_eth_addr { - unsigned char octets[6]; -}; - -/* Streams (e.g. TCP) *********************************************************/ - -struct net_stream_listener_vtable; -struct net_stream_conn_vtable; - -typedef struct { - struct net_stream_listener_vtable *vtable; -} implements_net_stream_listener; - -typedef struct { - struct net_stream_conn_vtable *vtable; -} implements_net_stream_conn; - -struct net_stream_listener_vtable { - /** - * It is invalid to accept() a new connection if an existing - * connection is still open. - */ - implements_net_stream_conn *(*accept)(implements_net_stream_listener *self); - - /** - * The net_stream_conn returned from accept() may still be - * valid after the listener is closed. - * - * Return 0 on success, -errno on error. - */ - int (*close)(implements_net_stream_listener *self); -}; - -struct net_stream_conn_vtable { - /** - * Return bytes-read on success, 0 on EOF, -errno on error; a - * short read is *not* an error. - */ - ssize_t (*read)(implements_net_stream_conn *self, - void *buf, size_t count); - - /** - * Set a timestamp after which calls to read() will return - * NET_ETIMEDOUT. The timestamp is in nanoseconds on the - * system monotonic clock, which is usually (on pico-sdk and - * on the Linux kernel) nanoseconds-since-boot. - * - * A zero value disables the deadline. - * - * (2⁶⁴-1 nanoseconds is more than 500 years; there is little - * risk of this overflowing) - */ - void (*set_read_deadline)(implements_net_stream_conn *self, - uint64_t ns_since_boot); - - /** - * Return `count` on success, -errno on error; a short write *is* an - * error. - * - * Writes are *not* guaranteed to be atomic (as this would be - * expensive to implement), so if you have concurrent writers then you - * should arrange for a mutex to protect the connection. - */ - ssize_t (*write)(implements_net_stream_conn *self, - void *buf, size_t count); - - /** - * Return 0 on success, -errno on error. - */ - int (*close)(implements_net_stream_conn *self, - bool rd, bool wr); -}; - -/* Packets (e.g. UDP) *********************************************************/ - -struct net_packet_conn_vtable; - -typedef struct { - struct net_packet_conn_vtable *vtable; -} implements_net_packet_conn; - -struct net_packet_conn_vtable { - ssize_t (*sendto )(implements_net_packet_conn *self, - void *buf, size_t len, - struct net_ip4_addr node, uint16_t port); - /** - * @return The full length of the message, which may be more - * than the given `len` (as if the Linux MSG_TRUNC flag were - * given). - */ - ssize_t (*recvfrom)(implements_net_packet_conn *self, - void *buf, size_t len, - struct net_ip4_addr *ret_node, uint16_t *ret_port); - void (*set_read_deadline)(implements_net_packet_conn *self, - uint64_t ns_since_boot); - int (*close )(implements_net_packet_conn *self); -}; - -/* Interfaces *****************************************************************/ - -struct net_iface_config { - struct net_ip4_addr addr; - struct net_ip4_addr gateway_addr; - struct net_ip4_addr subnet_mask; -}; - -struct net_iface_vtable; - -typedef struct { - struct net_iface_vtable *vtable; -} implements_net_iface; - -struct net_iface_vtable { - struct net_eth_addr (*hwaddr )(implements_net_iface *); - void (*ifup )(implements_net_iface *, struct net_iface_config); - void (*ifdown )(implements_net_iface *); - - implements_net_stream_listener *(*tcp_listen)(implements_net_iface *, uint16_t local_port); - implements_net_stream_conn *(*tcp_dial )(implements_net_iface *, struct net_ip4_addr remote_node, uint16_t remote_port); - implements_net_packet_conn *(*udp_conn )(implements_net_iface *, uint16_t local_port); -}; - -#endif /* _LIBHW_GENERIC_NET_H_ */ diff --git a/libhw/common_include/libhw/generic/spi.h b/libhw/common_include/libhw/generic/spi.h deleted file mode 100644 index 2207a2c..0000000 --- a/libhw/common_include/libhw/generic/spi.h +++ /dev/null @@ -1,47 +0,0 @@ -/* libhw/generic/spi.h - Device-independent SPI definitions - * - * Copyright (C) 2024 Luke T. Shumaker - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#ifndef _LIBHW_GENERIC_SPI_H_ -#define _LIBHW_GENERIC_SPI_H_ - -#include /* for size_t */ - -enum spi_mode { - SPI_MODE_0 = 0, /* clk_polarity=0 (idle low), clk_phase=0 (sample on rise) */ - SPI_MODE_1 = 1, /* clk_polarity=0 (idle low), clk_phase=1 (sample on fall) */ - SPI_MODE_2 = 2, /* clk_polarity=1 (idle high), clk_phase=0 (sample on rise) */ - SPI_MODE_3 = 3, /* clk_polarity=1 (idle high), clk_phase=1 (sample on fall) */ -}; - -struct bidi_iovec { - void *iov_read_dst; - void *iov_write_src; - size_t iov_len; -}; - -struct spi_vtable; - -typedef struct { - struct spi_vtable *vtable; -} implements_spi; - -/* This API assumes that an SPI frame is a multiple of 8-bits. - * - * It is my understanding that this is a common constraint of SPI - * hardware, and that the RP2040 is somewhat unusual in that it allows - * frames of any length 4-16 bits (we disconnect the CS pin from the - * PL022 SSP and manually GPIO it from the CPU in order to achieve - * longer frames). - * - * But, more relevantly: The W5500's protocol uses frames that are 4-N - * octets; so we have no need for an API that allows a - * non-multiple-of-8 number of bits. - */ -struct spi_vtable { - void (*readwritev)(implements_spi *, const struct bidi_iovec *iov, int iovcnt); -}; - -#endif /* _LIBHW_GENERIC_SPI_H_ */ diff --git a/libhw_generic/CMakeLists.txt b/libhw_generic/CMakeLists.txt new file mode 100644 index 0000000..9c88937 --- /dev/null +++ b/libhw_generic/CMakeLists.txt @@ -0,0 +1,15 @@ +# libhw_generic/CMakeLists.txt - UAPI device interfaces +# +# Copyright (C) 2024 Luke T. Shumaker +# SPDX-License-Identifier: AGPL-3.0-or-later + +add_library(libhw_generic INTERFACE) +target_include_directories(libhw_generic SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_link_libraries(libhw_generic INTERFACE + libmisc + libcr +) + +target_sources(libhw_generic INTERFACE + alarmclock.c +) diff --git a/libhw_generic/alarmclock.c b/libhw_generic/alarmclock.c new file mode 100644 index 0000000..d539496 --- /dev/null +++ b/libhw_generic/alarmclock.c @@ -0,0 +1,21 @@ +/* libhw_generic/alarmclock.c - Device-independent utilities + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include +#include + +#include + +static void alarmclock_sleep_intrhandler(void *_arg) { + cid_t *cid = _arg; + cr_unpause_from_intrhandler(*cid); +} + +void alarmclock_sleep_until_ns(implements_alarmclock *clock, uint64_t abstime_ns) { + cid_t cid = cr_getcid(); + struct alarmclock_trigger trigger; + VCALL(clock, add_trigger, &trigger, abstime_ns, alarmclock_sleep_intrhandler, &cid); +} diff --git a/libhw_generic/include/libhw/generic/alarmclock.h b/libhw_generic/include/libhw/generic/alarmclock.h new file mode 100644 index 0000000..a9d816b --- /dev/null +++ b/libhw_generic/include/libhw/generic/alarmclock.h @@ -0,0 +1,98 @@ +/* libhw/generic/alarmclock.h - Device-independent alarmclock definitions + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBHW_GENERIC_ALARMCLOCK_H_ +#define _LIBHW_GENERIC_ALARMCLOCK_H_ + +#include /* for bool */ +#include /* for uint{n}_t and UINT{n}_C */ + +#include +#include + +/* Useful constants ***********************************************************/ + +#define NS_PER_S UINT64_C(1000000000) /* needs at least log₂(10⁹) ≈ 29.9 bits */ +#define US_PER_S UINT64_C(1000000) /* needs at least log₂(10⁶) ≈ 19.9 bits */ +#define MS_PER_S UINT64_C(1000) /* needs at least log₂(10³) ≈ 9.9 bits */ + +/* Structs ********************************************************************/ + +struct alarmclock_trigger; +struct alarmclock_trigger { + BEGIN_PRIVATE(LIBHW_GENERIC_ALARMCLOCK_H) + void *alarmclock; + struct alarmclock_trigger *prev, *next; + + uint64_t fire_at_ns; + void (*cb)(void *); + void *cb_arg; + END_PRIVATE(LIBHW_GENERIC_ALARMCLOCK_H) +}; + +/* Interface ******************************************************************/ + +struct alarmclock_vtable; + +typedef struct { + struct alarmclock_vtable *vtable; +} implements_alarmclock; + +struct alarmclock_vtable { + /** + * (2⁶⁴-1 nanoseconds is more than 500 years; there is little + * risk of this overflowing) + */ + uint64_t (*get_time_ns)(implements_alarmclock *self); + + /** + * Returns true on error. + * + * Implementations may return an error if fire_at_ns is more + * than UINT32_MAX µs (72 minutes) in the future. + * + * If fire_at_ns is in the past, then it will fire + * immediately. + */ + bool (*add_trigger)(implements_alarmclock *self, struct alarmclock_trigger *trigger, + uint64_t fire_at_ns, + void (*cb)(void *), + void *cb_arg); + + void (*del_trigger)(implements_alarmclock *self, struct alarmclock_trigger *trigger); +}; + +/* Utilities ******************************************************************/ + +void alarmclock_sleep_until_ns(implements_alarmclock *clock, uint64_t abstime_ns); + +static inline void alarmclock_sleep_for_ns(implements_alarmclock *clock, uint64_t delta_ns) { + alarmclock_sleep_until_ns(clock, VCALL(clock, get_time_ns) + delta_ns); +} + +static inline void alarmclock_sleep_for_us(implements_alarmclock *clock, uint64_t delta_us) { + alarmclock_sleep_for_ns(clock, delta_us * (NS_PER_S/US_PER_S)); +} + +static inline void alarmclock_sleep_for_ms(implements_alarmclock *clock, uint64_t delta_ms) { + alarmclock_sleep_for_ns(clock, delta_ms * (NS_PER_S/MS_PER_S)); +} + +static inline void alarmclock_sleep_for_s(implements_alarmclock *clock, uint64_t delta_s) { + alarmclock_sleep_for_ns(clock, delta_s * NS_PER_S); +} + +/* Globals ********************************************************************/ + +extern implements_alarmclock *bootclock; + +#define sleep_until_ns(t) alarmclock_sleep_until_ns(bootclock, t) +#define sleep_for_ns(t) alarmclock_sleep_for_ns(bootclock, t) +#define sleep_for_us(t) alarmclock_sleep_for_us(bootclock, t) +#define sleep_for_ms(t) alarmclock_sleep_for_ms(bootclock, t) +#define sleep_for_s(t) alarmclock_sleep_for_s(bootclock, t) + +#endif /* _LIBHW_GENERIC_ALARMCLOCK_H_ */ diff --git a/libhw_generic/include/libhw/generic/net.h b/libhw_generic/include/libhw/generic/net.h new file mode 100644 index 0000000..def533c --- /dev/null +++ b/libhw_generic/include/libhw/generic/net.h @@ -0,0 +1,154 @@ +/* libhw/generic/net.h - Device-independent network definitions + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBHW_GENERIC_NET_H_ +#define _LIBHW_GENERIC_NET_H_ + +#include /* for bool */ +#include /* for size_t */ +#include /* for uint{n}_t} */ +#include /* for ssize_t */ + +/* Errnos *********************************************************************/ + +#define NET_EOTHER 1 +#define NET_ETIMEDOUT 2 +#define NET_ETHREAD 3 +#define NET_ECLOSED 4 +#define NET_EMSGSIZE 5 + +/* Address types **************************************************************/ + +struct net_ip4_addr { + unsigned char octets[4]; +}; + +static const struct net_ip4_addr net_ip4_addr_broadcast = {{255, 255, 255, 255}}; +static const struct net_ip4_addr net_ip4_addr_zero = {{0, 0, 0, 0}}; + +struct net_eth_addr { + unsigned char octets[6]; +}; + +/* Streams (e.g. TCP) *********************************************************/ + +struct net_stream_listener_vtable; +struct net_stream_conn_vtable; + +typedef struct { + struct net_stream_listener_vtable *vtable; +} implements_net_stream_listener; + +typedef struct { + struct net_stream_conn_vtable *vtable; +} implements_net_stream_conn; + +struct net_stream_listener_vtable { + /** + * It is invalid to accept() a new connection if an existing + * connection is still open. + */ + implements_net_stream_conn *(*accept)(implements_net_stream_listener *self); + + /** + * The net_stream_conn returned from accept() may still be + * valid after the listener is closed. + * + * Return 0 on success, -errno on error. + */ + int (*close)(implements_net_stream_listener *self); +}; + +struct net_stream_conn_vtable { + /** + * Return bytes-read on success, 0 on EOF, -errno on error; a + * short read is *not* an error. + */ + ssize_t (*read)(implements_net_stream_conn *self, + void *buf, size_t count); + + /** + * Set a timestamp after which calls to read() will return + * NET_ETIMEDOUT. The timestamp is in nanoseconds on the + * system monotonic clock, which is usually (on pico-sdk and + * on the Linux kernel) nanoseconds-since-boot. + * + * A zero value disables the deadline. + * + * (2⁶⁴-1 nanoseconds is more than 500 years; there is little + * risk of this overflowing) + */ + void (*set_read_deadline)(implements_net_stream_conn *self, + uint64_t ns_since_boot); + + /** + * Return `count` on success, -errno on error; a short write *is* an + * error. + * + * Writes are *not* guaranteed to be atomic (as this would be + * expensive to implement), so if you have concurrent writers then you + * should arrange for a mutex to protect the connection. + */ + ssize_t (*write)(implements_net_stream_conn *self, + void *buf, size_t count); + + /** + * Return 0 on success, -errno on error. + */ + int (*close)(implements_net_stream_conn *self, + bool rd, bool wr); +}; + +/* Packets (e.g. UDP) *********************************************************/ + +struct net_packet_conn_vtable; + +typedef struct { + struct net_packet_conn_vtable *vtable; +} implements_net_packet_conn; + +struct net_packet_conn_vtable { + ssize_t (*sendto )(implements_net_packet_conn *self, + void *buf, size_t len, + struct net_ip4_addr node, uint16_t port); + /** + * @return The full length of the message, which may be more + * than the given `len` (as if the Linux MSG_TRUNC flag were + * given). + */ + ssize_t (*recvfrom)(implements_net_packet_conn *self, + void *buf, size_t len, + struct net_ip4_addr *ret_node, uint16_t *ret_port); + void (*set_read_deadline)(implements_net_packet_conn *self, + uint64_t ns_since_boot); + int (*close )(implements_net_packet_conn *self); +}; + +/* Interfaces *****************************************************************/ + +struct net_iface_config { + struct net_ip4_addr addr; + struct net_ip4_addr gateway_addr; + struct net_ip4_addr subnet_mask; +}; + +struct net_iface_vtable; + +typedef struct { + struct net_iface_vtable *vtable; +} implements_net_iface; + +struct net_iface_vtable { + struct net_eth_addr (*hwaddr )(implements_net_iface *); + void (*ifup )(implements_net_iface *, struct net_iface_config); + void (*ifdown )(implements_net_iface *); + + implements_net_stream_listener *(*tcp_listen)(implements_net_iface *, uint16_t local_port); + implements_net_stream_conn *(*tcp_dial )(implements_net_iface *, struct net_ip4_addr remote_node, uint16_t remote_port); + implements_net_packet_conn *(*udp_conn )(implements_net_iface *, uint16_t local_port); +}; + +#endif /* _LIBHW_GENERIC_NET_H_ */ diff --git a/libhw_generic/include/libhw/generic/spi.h b/libhw_generic/include/libhw/generic/spi.h new file mode 100644 index 0000000..2207a2c --- /dev/null +++ b/libhw_generic/include/libhw/generic/spi.h @@ -0,0 +1,47 @@ +/* libhw/generic/spi.h - Device-independent SPI definitions + * + * Copyright (C) 2024 Luke T. Shumaker + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBHW_GENERIC_SPI_H_ +#define _LIBHW_GENERIC_SPI_H_ + +#include /* for size_t */ + +enum spi_mode { + SPI_MODE_0 = 0, /* clk_polarity=0 (idle low), clk_phase=0 (sample on rise) */ + SPI_MODE_1 = 1, /* clk_polarity=0 (idle low), clk_phase=1 (sample on fall) */ + SPI_MODE_2 = 2, /* clk_polarity=1 (idle high), clk_phase=0 (sample on rise) */ + SPI_MODE_3 = 3, /* clk_polarity=1 (idle high), clk_phase=1 (sample on fall) */ +}; + +struct bidi_iovec { + void *iov_read_dst; + void *iov_write_src; + size_t iov_len; +}; + +struct spi_vtable; + +typedef struct { + struct spi_vtable *vtable; +} implements_spi; + +/* This API assumes that an SPI frame is a multiple of 8-bits. + * + * It is my understanding that this is a common constraint of SPI + * hardware, and that the RP2040 is somewhat unusual in that it allows + * frames of any length 4-16 bits (we disconnect the CS pin from the + * PL022 SSP and manually GPIO it from the CPU in order to achieve + * longer frames). + * + * But, more relevantly: The W5500's protocol uses frames that are 4-N + * octets; so we have no need for an API that allows a + * non-multiple-of-8 number of bits. + */ +struct spi_vtable { + void (*readwritev)(implements_spi *, const struct bidi_iovec *iov, int iovcnt); +}; + +#endif /* _LIBHW_GENERIC_SPI_H_ */ -- cgit v1.2.3-2-g168b