diff options
Diffstat (limited to 'libhw_generic')
-rw-r--r-- | libhw_generic/CMakeLists.txt | 3 | ||||
-rw-r--r-- | libhw_generic/alarmclock.c | 9 | ||||
-rw-r--r-- | libhw_generic/include/libhw/generic/alarmclock.h | 70 | ||||
-rw-r--r-- | libhw_generic/include/libhw/generic/net.h | 188 | ||||
-rw-r--r-- | libhw_generic/include/libhw/generic/spi.h | 16 |
5 files changed, 129 insertions, 157 deletions
diff --git a/libhw_generic/CMakeLists.txt b/libhw_generic/CMakeLists.txt index 0356770..e38fbe9 100644 --- a/libhw_generic/CMakeLists.txt +++ b/libhw_generic/CMakeLists.txt @@ -1,12 +1,13 @@ # libhw_generic/CMakeLists.txt - UAPI device interfaces # -# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # 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 + libobj libcr ) diff --git a/libhw_generic/alarmclock.c b/libhw_generic/alarmclock.c index a16f2f6..7fd049e 100644 --- a/libhw_generic/alarmclock.c +++ b/libhw_generic/alarmclock.c @@ -1,24 +1,25 @@ /* libhw_generic/alarmclock.c - Device-independent <libhw/generic/alarmclock.h> utilities * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ #include <libcr/coroutine.h> -#include <libmisc/vcall.h> #include <libhw/generic/alarmclock.h> +lo_interface alarmclock bootclock = {0}; + static void alarmclock_sleep_intrhandler(void *_arg) { cid_t cid = *(cid_t *)_arg; cr_unpause_from_intrhandler(cid); } -void alarmclock_sleep_until_ns(implements_alarmclock *clock, uint64_t abstime_ns) { +void alarmclock_sleep_until_ns(lo_interface alarmclock clock, uint64_t abstime_ns) { bool saved = cr_save_and_disable_interrupts(); cid_t cid = cr_getcid(); struct alarmclock_trigger trigger; - VCALL(clock, add_trigger, &trigger, abstime_ns, alarmclock_sleep_intrhandler, &cid); + LO_CALL(clock, add_trigger, &trigger, abstime_ns, alarmclock_sleep_intrhandler, &cid); cr_pause_and_yield(); cr_restore_interrupts(saved); } diff --git a/libhw_generic/include/libhw/generic/alarmclock.h b/libhw_generic/include/libhw/generic/alarmclock.h index a9d816b..3817b4b 100644 --- a/libhw_generic/include/libhw/generic/alarmclock.h +++ b/libhw_generic/include/libhw/generic/alarmclock.h @@ -1,6 +1,6 @@ /* libhw/generic/alarmclock.h - Device-independent alarmclock definitions * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -11,7 +11,7 @@ #include <stdint.h> /* for uint{n}_t and UINT{n}_C */ #include <libmisc/private.h> -#include <libmisc/vcall.h> +#include <libobj/obj.h> /* Useful constants ***********************************************************/ @@ -35,59 +35,53 @@ struct alarmclock_trigger { /* 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); -}; +#define alarmclock_LO_IFACE \ + /** \ + * (2⁶⁴-1 nanoseconds is more than 500 years; there is little \ + * risk of this overflowing) \ + */ \ + LO_FUNC(uint64_t, get_time_ns) \ + \ + /** \ + * 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. \ + */ \ + LO_FUNC(bool, add_trigger, struct alarmclock_trigger *trigger, \ + uint64_t fire_at_ns, \ + void (*cb)(void *), \ + void *cb_arg) \ + \ + LO_FUNC(void, del_trigger, struct alarmclock_trigger *trigger) +LO_INTERFACE(alarmclock) /* Utilities ******************************************************************/ -void alarmclock_sleep_until_ns(implements_alarmclock *clock, uint64_t abstime_ns); +void alarmclock_sleep_until_ns(lo_interface 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_ns(lo_interface alarmclock clock, uint64_t delta_ns) { + alarmclock_sleep_until_ns(clock, LO_CALL(clock, get_time_ns) + delta_ns); } -static inline void alarmclock_sleep_for_us(implements_alarmclock *clock, uint64_t delta_us) { +static inline void alarmclock_sleep_for_us(lo_interface 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) { +static inline void alarmclock_sleep_for_ms(lo_interface 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) { +static inline void alarmclock_sleep_for_s(lo_interface alarmclock clock, uint64_t delta_s) { alarmclock_sleep_for_ns(clock, delta_s * NS_PER_S); } /* Globals ********************************************************************/ -extern implements_alarmclock *bootclock; +extern lo_interface alarmclock bootclock; #define sleep_until_ns(t) alarmclock_sleep_until_ns(bootclock, t) #define sleep_for_ns(t) alarmclock_sleep_for_ns(bootclock, t) diff --git a/libhw_generic/include/libhw/generic/net.h b/libhw_generic/include/libhw/generic/net.h index 0f9872e..c888735 100644 --- a/libhw_generic/include/libhw/generic/net.h +++ b/libhw_generic/include/libhw/generic/net.h @@ -1,6 +1,6 @@ /* libhw/generic/net.h - Device-independent network definitions * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -13,6 +13,8 @@ #include <stdint.h> /* for uint{n}_t} */ #include <sys/types.h> /* for ssize_t */ +#include <libobj/obj.h> + /* Errnos *********************************************************************/ #define NET_EOTHER 1 @@ -54,97 +56,81 @@ struct net_eth_addr { /* 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); -}; +lo_interface net_stream_conn; + +#define net_stream_listener_LO_IFACE \ + /** \ + * It is invalid to accept() a new connection if an existing \ + * connection is still open. \ + */ \ + LO_FUNC(lo_interface net_stream_conn, accept) \ + \ + /** \ + * The net_stream_conn returned from accept() may still be \ + * valid after the listener is closed. \ + * \ + * Return 0 on success, -errno on error. \ + */ \ + LO_FUNC(int, close) +LO_INTERFACE(net_stream_listener) + +#define net_stream_conn_LO_IFACE \ + /** \ + * Return bytes-read on success, 0 on EOF, -errno on error; a \ + * short read is *not* an error. \ + */ \ + LO_FUNC(ssize_t, read, 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) \ + */ \ + LO_FUNC(void, set_read_deadline, 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. \ + */ \ + LO_FUNC(ssize_t, write, void *buf, size_t count) \ + \ + /** \ + * Return 0 on success, -errno on error. \ + */ \ + LO_FUNC(int, close, bool rd, bool wr) +LO_INTERFACE(net_stream_conn) /* 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); -}; +#define net_packet_conn_LO_IFACE \ + LO_FUNC(ssize_t, sendto, \ + 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). \ + */ \ + LO_FUNC(ssize_t, recvfrom, \ + void *buf, size_t len, \ + struct net_ip4_addr *ret_node, uint16_t *ret_port) \ + \ + LO_FUNC(void, set_read_deadline, \ + uint64_t ns_since_boot) \ + \ + LO_FUNC(int, close) +LO_INTERFACE(net_packet_conn) /* Interfaces *****************************************************************/ @@ -154,20 +140,14 @@ struct net_iface_config { 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); -}; +#define net_iface_LO_IFACE \ + LO_FUNC(struct net_eth_addr , hwaddr ) \ + LO_FUNC(void , ifup , struct net_iface_config) \ + LO_FUNC(void , ifdown ) \ + \ + LO_FUNC(lo_interface net_stream_listener, tcp_listen, uint16_t local_port) \ + LO_FUNC(lo_interface net_stream_conn , tcp_dial , struct net_ip4_addr remote_node, uint16_t remote_port) \ + LO_FUNC(lo_interface net_packet_conn , udp_conn , uint16_t local_port) +LO_INTERFACE(net_iface) #endif /* _LIBHW_GENERIC_NET_H_ */ diff --git a/libhw_generic/include/libhw/generic/spi.h b/libhw_generic/include/libhw/generic/spi.h index 2207a2c..aeeca37 100644 --- a/libhw_generic/include/libhw/generic/spi.h +++ b/libhw_generic/include/libhw/generic/spi.h @@ -1,6 +1,6 @@ /* libhw/generic/spi.h - Device-independent SPI definitions * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -9,6 +9,8 @@ #include <stddef.h> /* for size_t */ +#include <libobj/obj.h> + 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) */ @@ -22,12 +24,6 @@ struct bidi_iovec { 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 @@ -40,8 +36,8 @@ typedef struct { * 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); -}; +#define spi_LO_IFACE \ + LO_FUNC(void, readwritev, const struct bidi_iovec *iov, int iovcnt) +LO_INTERFACE(spi) #endif /* _LIBHW_GENERIC_SPI_H_ */ |