/* libhw/w5500.h - implementation for the WIZnet W5500 chip * * Copyright (C) 2024-2025 Luke T. Shumaker * SPDX-License-Identifier: AGPL-3.0-or-later */ #ifndef _LIBHW_W5500_H_ #define _LIBHW_W5500_H_ #include /* for bi_* */ #include #include #include #include #include #include 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_ */