diff options
Diffstat (limited to 'libhw_cr/rp2040_include/libhw/w5500.h')
-rw-r--r-- | libhw_cr/rp2040_include/libhw/w5500.h | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/libhw_cr/rp2040_include/libhw/w5500.h b/libhw_cr/rp2040_include/libhw/w5500.h new file mode 100644 index 0000000..51effba --- /dev/null +++ b/libhw_cr/rp2040_include/libhw/w5500.h @@ -0,0 +1,114 @@ +/* libhw/w5500.h - <libhw/generic/net.h> implementation for the WIZnet W5500 chip + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBHW_W5500_H_ +#define _LIBHW_W5500_H_ + +#include <pico/binary_info.h> /* for bi_* */ + +#include <libcr_ipc/chan.h> +#include <libcr_ipc/mutex.h> +#include <libcr_ipc/sema.h> +#include <libmisc/private.h> + +#include <libhw/generic/net.h> +#include <libhw/generic/spi.h> + +CR_CHAN_DECLARE(_w5500_sockintr_ch, uint8_t) + +struct _w5500_socket { + BEGIN_PRIVATE(LIBHW_W5500_H) + /* const-after-init */ + uint8_t socknum; + + /* mutable */ + struct _w5500_socket *next_free; + enum { + W5500_MODE_NONE = 0, + W5500_MODE_TCP, + W5500_MODE_UDP, + } mode; + uint16_t port; /* MODE_{TCP,UDP} */ + uint64_t read_deadline_ns; /* MODE_{TCP,UDP} */ + cr_sema_t listen_sema; /* MODE_TCP */ + cr_sema_t read_sema; /* MODE_{TCP,UDP} */ + _w5500_sockintr_ch_t write_ch; /* MODE_{TCP,UDP} */ + bool list_open, read_open, write_open; /* MODE_TCP */ + + END_PRIVATE(LIBHW_W5500_H) +}; + +LO_IMPLEMENTATION_H(io_closer, struct _w5500_socket, w5500_tcplist) +LO_IMPLEMENTATION_H(net_stream_listener, struct _w5500_socket, w5500_tcplist) + +LO_IMPLEMENTATION_H(io_reader, struct _w5500_socket, w5500_tcp) +LO_IMPLEMENTATION_H(io_writer, struct _w5500_socket, w5500_tcp) +LO_IMPLEMENTATION_H(io_readwriter, struct _w5500_socket, w5500_tcp) +LO_IMPLEMENTATION_H(io_closer, struct _w5500_socket, w5500_tcp) +LO_IMPLEMENTATION_H(io_bidi_closer, struct _w5500_socket, w5500_tcp) +LO_IMPLEMENTATION_H(net_stream_conn, struct _w5500_socket, w5500_tcp) + +LO_IMPLEMENTATION_H(io_closer, struct _w5500_socket, w5500_udp) +LO_IMPLEMENTATION_H(net_packet_conn, struct _w5500_socket, w5500_udp) + +struct w5500 { + BEGIN_PRIVATE(LIBHW_W5500_H) + /* const-after-init */ + lo_interface spi spidev; + uint pin_intr; + uint pin_reset; + struct net_eth_addr hwaddr; + + /* mutable */ + uint16_t next_local_port; + struct _w5500_socket sockets[8]; + struct _w5500_socket *free; + cr_sema_t intr; + cr_mutex_t mu; + END_PRIVATE(LIBHW_W5500_H) +}; +LO_IMPLEMENTATION_H(net_iface, struct w5500, w5500_if) + +/** + * Initialize a WIZnet W5500 Ethernet-and-TCP/IP-offload chip. + * + * The W5500 has 3 lines of communication with the MCU: + * + * - An SPI-based RPC protocol: + * + mode: mode 0 or mode 3 + * + bit-order: MSB-first + * + clock frequency: 33.3MHz - 80MHz + * - An interrupt pin that it pulls low when an event happens (to let + * the MCU know that it should do an SPI RPC "get" to see what + * happened.) + * - A reset pin that the MCU can pull low to reset the W5500. + */ +#define w5500_init(self, name, spi, pin_intr, pin_reset, eth_addr) do { \ + bi_decl(bi_2pins_with_names(pin_intr, name" interrupt", \ + pin_reset, name" reset")); \ + _w5500_init(self, spi, pin_intr, pin_reset, eth_addr); \ + } while (0) +void _w5500_init(struct w5500 *self, + lo_interface spi spi, uint pin_intr, uint pin_reset, + struct net_eth_addr addr); + +/** + * Perform a hard reset on the chip (pull the reset line low). + * + * If you have any in-use sockets when you call this, you're going to + * have a bad time. + */ +void w5500_hard_reset(struct w5500 *self); + +/** + * Perform a soft reset on the chip (send the RST command). + * + * If you have any in-use sockets when you call this, you're going to + * have a bad time. + */ +void w5500_soft_reset(struct w5500 *self); + +#endif /* _LIBHW_W5500_H_ */ |