diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-03-02 13:30:05 -0700 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-03-02 13:30:05 -0700 |
commit | 255baf6db201dcdf8da017d55c577622f217a888 (patch) | |
tree | 905a389bc9fdf072cbdf7e9f21b2b936881eb620 /libhw_generic | |
parent | 188ac62a0c0f5519f5d45519fa7d224cb25305c6 (diff) | |
parent | 5a84ba2361cecade0343b88f696b6a63454cc3c6 (diff) |
Merge branch 'lukeshu/iov'
Diffstat (limited to 'libhw_generic')
-rw-r--r-- | libhw_generic/include/libhw/generic/io.h | 94 | ||||
-rw-r--r-- | libhw_generic/include/libhw/generic/net.h | 112 | ||||
-rw-r--r-- | libhw_generic/include/libhw/generic/spi.h | 10 |
3 files changed, 143 insertions, 73 deletions
diff --git a/libhw_generic/include/libhw/generic/io.h b/libhw_generic/include/libhw/generic/io.h new file mode 100644 index 0000000..a7f7378 --- /dev/null +++ b/libhw_generic/include/libhw/generic/io.h @@ -0,0 +1,94 @@ +/* libhw/generic/io.h - Device-independent I/O definitions + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBHW_GENERIC_IO_H_ +#define _LIBHW_GENERIC_IO_H_ + +#include <stddef.h> /* for size_t */ +#include <sys/types.h> /* for ssize_t */ + +#include <libobj/obj.h> + +/* structs ********************************************************************/ + +#if __unix__ +#include <sys/uio.h> +#else +struct iovec { + void *iov_base; + size_t iov_len; +}; +#endif + +struct duplex_iovec { + void *iov_read_dst; + void *iov_write_src; + size_t iov_len; +}; + +/* basic interfaces ***********************************************************/ + +/** + * Return bytes-read on success, 0 on EOF, -errno on error; a short + * read is *not* an error. + */ +#define io_reader_LO_IFACE \ + LO_FUNC(ssize_t, readv, const struct iovec *iov, int iovcnt) +LO_INTERFACE(io_reader) +#define io_readv(r, iov, iovcnt) LO_CALL(r, readv, iov, iovcnt) +#define io_read(r, buf, count) LO_CALL(r, readv, &((struct iovec){.iov_base = buf, .iov_len = count}), 1) + +/** + * Return `count` on success, -errno on error; a short write *is* an + * error. + * + * Writes are *not* guaranteed to be atomic, so if you have concurrent + * writers then you should arrange for a mutex to protect the writer. + */ +#define io_writer_LO_IFACE \ + LO_FUNC(ssize_t, writev, const struct iovec *iov, int iovcnt) +LO_INTERFACE(io_writer) +#define io_writev(w, iov, iovcnt) LO_CALL(w, writev, iov, iovcnt) +#define io_write(w, buf, count) LO_CALL(w, writev, &((struct iovec){.iov_base = buf, .iov_len = count}), 1) + +/** + * Return 0 on success, -errno on error. + */ +#define io_closer_LO_IFACE \ + LO_FUNC(int, close) +LO_INTERFACE(io_closer) +#define io_close(c) LO_CALL(c, close) + +/** + * All methods return 0 on success, -errno on error. + */ +#define io_bidi_closer_LO_IFACE \ + LO_NEST(io_closer) \ + LO_FUNC(int, close_read) \ + LO_FUNC(int, close_write) +LO_INTERFACE(io_bidi_closer) +#define io_close_read(c) LO_CALL(c, close_read) +#define io_close_write(c) LO_CALL(c, close_write) + +/** + * Return bytes-read and bytes-written on success, -errno on error; a + * short read/write *is* an error. + */ +#define io_duplex_readwriter_LO_IFACE \ + LO_FUNC(void, readwritev, const struct duplex_iovec *iov, int iovcnt) +LO_INTERFACE(io_duplex_readwriter) + +#define io_readwritev(rw, iov, iovcnt) \ + LO_CALL(rw, readwritev, iov, iovcnt) + +/* aggregate interfaces *******************************************************/ + +#define io_readwriter_LO_IFACE \ + LO_NEST(io_reader) \ + LO_NEST(io_writer) +LO_INTERFACE(io_readwriter) + +#endif /* _LIBHW_GENERIC_IO_H_ */ diff --git a/libhw_generic/include/libhw/generic/net.h b/libhw_generic/include/libhw/generic/net.h index 8d81573..2703b26 100644 --- a/libhw_generic/include/libhw/generic/net.h +++ b/libhw_generic/include/libhw/generic/net.h @@ -13,16 +13,7 @@ #include <stdint.h> /* for uint{n}_t} */ #include <sys/types.h> /* for ssize_t */ -#if __unix__ -#include <sys/uio.h> -#else -struct iovec { - void *iov_base; - size_t iov_len; -}; -#endif - -#include <libobj/obj.h> +#include <libhw/generic/io.h> /* Errnos *********************************************************************/ @@ -77,68 +68,59 @@ lo_interface net_stream_conn; /** \ * 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_NEST(io_closer) 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) +#define net_stream_conn_LO_IFACE \ + LO_NEST(io_readwriter) \ + LO_NEST(io_bidi_closer) \ + \ + /** \ + * 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) LO_INTERFACE(net_stream_conn) /* Packets (e.g. UDP) *********************************************************/ -#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) +#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) \ + \ + /** \ + * Set a timestamp after which calls to recvfrom() 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_recv_deadline, \ + uint64_t ns_since_boot) \ + \ + LO_NEST(io_closer) LO_INTERFACE(net_packet_conn) /* Interfaces *****************************************************************/ diff --git a/libhw_generic/include/libhw/generic/spi.h b/libhw_generic/include/libhw/generic/spi.h index aeeca37..a4dbcae 100644 --- a/libhw_generic/include/libhw/generic/spi.h +++ b/libhw_generic/include/libhw/generic/spi.h @@ -9,7 +9,7 @@ #include <stddef.h> /* for size_t */ -#include <libobj/obj.h> +#include <libhw/generic/io.h> enum spi_mode { SPI_MODE_0 = 0, /* clk_polarity=0 (idle low), clk_phase=0 (sample on rise) */ @@ -18,12 +18,6 @@ enum spi_mode { 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; -}; - /* 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 @@ -37,7 +31,7 @@ struct bidi_iovec { * non-multiple-of-8 number of bits. */ #define spi_LO_IFACE \ - LO_FUNC(void, readwritev, const struct bidi_iovec *iov, int iovcnt) + LO_NEST(io_duplex_readwriter) LO_INTERFACE(spi) #endif /* _LIBHW_GENERIC_SPI_H_ */ |