1 // Copyright 2008 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #pragma once
6 
7 #include <atomic>
8 #include <thread>
9 #include <vector>
10 
11 #ifdef _WIN32
12 #include <Windows.h>
13 #endif
14 
15 #include <SFML/Network.hpp>
16 
17 #include "Common/Flag.h"
18 #include "Core/HW/EXI/EXI_Device.h"
19 
20 class PointerWrap;
21 
22 namespace ExpansionInterface
23 {
24 // Network Control Register A
25 enum NCRA
26 {
27   NCRA_RESET = 0x01,  // RESET
28   NCRA_ST0 = 0x02,    // Start transmit command/status
29   NCRA_ST1 = 0x04,    // "
30   NCRA_SR = 0x08      // Start Receive
31 };
32 
33 // Network Control Register B
34 enum NCRB
35 {
36   NCRB_PR = 0x01,     // Promiscuous Mode
37   NCRB_CA = 0x02,     // Capture Effect Mode
38   NCRB_PM = 0x04,     // Pass Multicast
39   NCRB_PB = 0x08,     // Pass Bad Frame
40   NCRB_AB = 0x10,     // Accept Broadcast
41   NCRB_HBD = 0x20,    // reserved
42   NCRB_RXINTC = 0xC0  // Receive Interrupt Counter (mask)
43 };
44 
45 // Interrupt Mask Register
46 // Interrupt Register
47 enum Interrupts
48 {
49   INT_FRAG = 0x01,      // Fragment Counter
50   INT_R = 0x02,         // Receive
51   INT_T = 0x04,         // Transmit
52   INT_R_ERR = 0x08,     // Receive Error
53   INT_T_ERR = 0x10,     // Transmit Error
54   INT_FIFO_ERR = 0x20,  // FIFO Error
55   INT_BUS_ERR = 0x40,   // BUS Error
56   INT_RBF = 0x80        // RX Buffer Full
57 };
58 
59 // NWAY Configuration Register
60 enum NWAYC
61 {
62   NWAYC_FD = 0x01,        // Full Duplex Mode
63   NWAYC_PS100_10 = 0x02,  // Port Select 100/10
64   NWAYC_ANE = 0x04,       // Autonegotiate enable
65 
66   // Autonegotiation status bits...
67 
68   NWAYC_NTTEST = 0x40,  // Reserved
69   NWAYC_LTE = 0x80      // Link Test Enable
70 };
71 
72 enum NWAYS
73 {
74   NWAYS_LS10 = 0x01,
75   NWAYS_LS100 = 0x02,
76   NWAYS_LPNWAY = 0x04,
77   NWAYS_ANCLPT = 0x08,
78   NWAYS_100TXF = 0x10,
79   NWAYS_100TXH = 0x20,
80   NWAYS_10TXF = 0x40,
81   NWAYS_10TXH = 0x80
82 };
83 
84 enum MISC1
85 {
86   MISC1_BURSTDMA = 0x01,
87   MISC1_DISLDMA = 0x02,
88   MISC1_TPF = 0x04,
89   MISC1_TPH = 0x08,
90   MISC1_TXF = 0x10,
91   MISC1_TXH = 0x20,
92   MISC1_TXFIFORST = 0x40,
93   MISC1_RXFIFORST = 0x80
94 };
95 
96 enum MISC2
97 {
98   MISC2_HBRLEN0 = 0x01,
99   MISC2_HBRLEN1 = 0x02,
100   MISC2_RUNTSIZE = 0x04,
101   MISC2_DREQBCTRL = 0x08,
102   MISC2_RINTSEL = 0x10,
103   MISC2_ITPSEL = 0x20,
104   MISC2_A11A8EN = 0x40,
105   MISC2_AUTORCVR = 0x80
106 };
107 
108 enum
109 {
110   BBA_NCRA = 0x00,
111   BBA_NCRB = 0x01,
112 
113   BBA_LTPS = 0x04,
114   BBA_LRPS = 0x05,
115 
116   BBA_IMR = 0x08,
117   BBA_IR = 0x09,
118 
119   BBA_BP = 0x0a,
120   BBA_TLBP = 0x0c,
121   BBA_TWP = 0x0e,
122   BBA_IOB = 0x10,
123   BBA_TRP = 0x12,
124   BBA_RWP = 0x16,
125   BBA_RRP = 0x18,
126   BBA_RHBP = 0x1a,
127 
128   BBA_RXINTT = 0x14,
129 
130   BBA_NAFR_PAR0 = 0x20,
131   BBA_NAFR_PAR1 = 0x21,
132   BBA_NAFR_PAR2 = 0x22,
133   BBA_NAFR_PAR3 = 0x23,
134   BBA_NAFR_PAR4 = 0x24,
135   BBA_NAFR_PAR5 = 0x25,
136   BBA_NAFR_MAR0 = 0x26,
137   BBA_NAFR_MAR1 = 0x27,
138   BBA_NAFR_MAR2 = 0x28,
139   BBA_NAFR_MAR3 = 0x29,
140   BBA_NAFR_MAR4 = 0x2a,
141   BBA_NAFR_MAR5 = 0x2b,
142   BBA_NAFR_MAR6 = 0x2c,
143   BBA_NAFR_MAR7 = 0x2d,
144 
145   BBA_NWAYC = 0x30,
146   BBA_NWAYS = 0x31,
147 
148   BBA_GCA = 0x32,
149 
150   BBA_MISC = 0x3d,
151 
152   BBA_TXFIFOCNT = 0x3e,
153   BBA_WRTXFIFOD = 0x48,
154 
155   BBA_MISC2 = 0x50,
156 
157   BBA_SI_ACTRL = 0x5c,
158   BBA_SI_STATUS = 0x5d,
159   BBA_SI_ACTRL2 = 0x60
160 };
161 
162 enum
163 {
164   BBA_NUM_PAGES = 0x10,
165   BBA_PAGE_SIZE = 0x100,
166   BBA_MEM_SIZE = BBA_NUM_PAGES * BBA_PAGE_SIZE,
167   BBA_TXFIFO_SIZE = 1518
168 };
169 
170 enum
171 {
172   EXI_DEVTYPE_ETHER = 0x04020200
173 };
174 
175 enum SendStatus
176 {
177   DESC_CC0 = 0x01,
178   DESC_CC1 = 0x02,
179   DESC_CC2 = 0x04,
180   DESC_CC3 = 0x08,
181   DESC_CRSLOST = 0x10,
182   DESC_UF = 0x20,
183   DESC_OWC = 0x40,
184   DESC_OWN = 0x80
185 };
186 
187 enum RecvStatus
188 {
189   DESC_BF = 0x01,
190   DESC_CRC = 0x02,
191   DESC_FAE = 0x04,
192   DESC_FO = 0x08,
193   DESC_RW = 0x10,
194   DESC_MF = 0x20,
195   DESC_RF = 0x40,
196   DESC_RERR = 0x80
197 };
198 
199 #define BBA_RECV_SIZE 0x800
200 
201 enum class BBADeviceType
202 {
203   TAP,
204   XLINK,
205 };
206 
207 class CEXIETHERNET : public IEXIDevice
208 {
209 public:
210   explicit CEXIETHERNET(BBADeviceType type);
211   virtual ~CEXIETHERNET();
212   void SetCS(int cs) override;
213   bool IsPresent() const override;
214   bool IsInterruptSet() override;
215   void ImmWrite(u32 data, u32 size) override;
216   u32 ImmRead(u32 size) override;
217   void DMAWrite(u32 addr, u32 size) override;
218   void DMARead(u32 addr, u32 size) override;
219   void DoState(PointerWrap& p) override;
220 
221 private:
222   struct
223   {
224     enum
225     {
226       READ,
227       WRITE
228     } direction;
229 
230     enum
231     {
232       EXI,
233       MX
234     } region;
235 
236     u16 address;
237     bool valid;
238   } transfer = {};
239 
240   enum
241   {
242     EXI_ID,
243     REVISION_ID,
244     INTERRUPT_MASK,
245     INTERRUPT,
246     DEVICE_ID,
247     ACSTART,
248     HASH_READ = 8,
249     HASH_WRITE,
250     HASH_STATUS = 0xb,
251     RESET = 0xf
252   };
253 
254   // exi regs
255   struct EXIStatus
256   {
257     enum
258     {
259       TRANSFER = 0x80
260     };
261 
262     u8 revision_id = 0;  // 0xf0
263     u8 interrupt_mask = 0;
264     u8 interrupt = 0;
265     u16 device_id = 0xD107;
266     u8 acstart = 0x4E;
267     u32 hash_challenge = 0;
268     u32 hash_response = 0;
269     u8 hash_status = 0;
270   } exi_status;
271 
272   struct Descriptor
273   {
274     u32 word;
275 
setDescriptor276     inline void set(u32 const next_page, u32 const packet_length, u32 const status)
277     {
278       word = 0;
279       word |= (status & 0xff) << 24;
280       word |= (packet_length & 0xfff) << 12;
281       word |= next_page & 0xfff;
282     }
283   };
284 
page_ptr(int const index)285   inline u16 page_ptr(int const index) const
286   {
287     return ((u16)mBbaMem[index + 1] << 8) | mBbaMem[index];
288   }
289 
ptr_from_page_ptr(int const index)290   inline u8* ptr_from_page_ptr(int const index) const { return &mBbaMem[page_ptr(index) << 8]; }
291   bool IsMXCommand(u32 const data);
292   bool IsWriteCommand(u32 const data);
293   const char* GetRegisterName() const;
294   void MXHardReset();
295   void MXCommandHandler(u32 data, u32 size);
296   void DirectFIFOWrite(const u8* data, u32 size);
297   void SendFromDirectFIFO();
298   void SendFromPacketBuffer();
299   void SendComplete();
300   u8 HashIndex(const u8* dest_eth_addr);
301   bool RecvMACFilter();
302   void inc_rwp();
303   bool RecvHandlePacket();
304 
305   std::unique_ptr<u8[]> mBbaMem;
306   std::unique_ptr<u8[]> tx_fifo;
307 
308   class NetworkInterface
309   {
310   protected:
311     CEXIETHERNET* m_eth_ref = nullptr;
NetworkInterface(CEXIETHERNET * eth_ref)312     explicit NetworkInterface(CEXIETHERNET* eth_ref) : m_eth_ref{eth_ref} {}
313 
314   public:
Activate()315     virtual bool Activate() { return false; }
Deactivate()316     virtual void Deactivate() {}
IsActivated()317     virtual bool IsActivated() { return false; }
SendFrame(const u8 * frame,u32 size)318     virtual bool SendFrame(const u8* frame, u32 size) { return false; }
RecvInit()319     virtual bool RecvInit() { return false; }
RecvStart()320     virtual void RecvStart() {}
RecvStop()321     virtual void RecvStop() {}
322 
323     virtual ~NetworkInterface() = default;
324   };
325 
326   class TAPNetworkInterface : public NetworkInterface
327   {
328   public:
TAPNetworkInterface(CEXIETHERNET * eth_ref)329     explicit TAPNetworkInterface(CEXIETHERNET* eth_ref) : NetworkInterface(eth_ref) {}
330 
331   public:
332     bool Activate() override;
333     void Deactivate() override;
334     bool IsActivated() override;
335     bool SendFrame(const u8* frame, u32 size) override;
336     bool RecvInit() override;
337     void RecvStart() override;
338     void RecvStop() override;
339 
340   private:
341 #if defined(WIN32) || defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||          \
342     defined(__OpenBSD__)
343     std::thread readThread;
344     Common::Flag readEnabled;
345     Common::Flag readThreadShutdown;
346     static void ReadThreadHandler(TAPNetworkInterface* self);
347 #endif
348 #if defined(_WIN32)
349     HANDLE mHAdapter = INVALID_HANDLE_VALUE;
350     OVERLAPPED mReadOverlapped = {};
351     OVERLAPPED mWriteOverlapped = {};
352     std::vector<u8> mWriteBuffer;
353     bool mWritePending = false;
354 #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
355     int fd = -1;
356 #endif
357   };
358 
359   class XLinkNetworkInterface : public NetworkInterface
360   {
361   public:
XLinkNetworkInterface(CEXIETHERNET * eth_ref,std::string dest_ip,int dest_port,std::string identifier,bool chat_osd_enabled)362     XLinkNetworkInterface(CEXIETHERNET* eth_ref, std::string dest_ip, int dest_port,
363                           std::string identifier, bool chat_osd_enabled)
364         : NetworkInterface(eth_ref), m_dest_ip(std::move(dest_ip)), m_dest_port(dest_port),
365           m_client_identifier(identifier), m_chat_osd_enabled(chat_osd_enabled)
366     {
367     }
368 
369   public:
370     bool Activate() override;
371     void Deactivate() override;
372     bool IsActivated() override;
373     bool SendFrame(const u8* frame, u32 size) override;
374     bool RecvInit() override;
375     void RecvStart() override;
376     void RecvStop() override;
377 
378   private:
379     std::string m_dest_ip;
380     int m_dest_port;
381     std::string m_client_identifier;
382     bool m_chat_osd_enabled;
383     bool m_bba_link_up = false;
384     bool m_bba_failure_notified = false;
385 #if defined(WIN32) || defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||          \
386     defined(__OpenBSD__)
387     sf::UdpSocket m_sf_socket;
388     sf::IpAddress m_sf_recipient_ip;
389     char m_in_frame[9004];
390     char m_out_frame[9004];
391     std::thread m_read_thread;
392     Common::Flag m_read_enabled;
393     Common::Flag m_read_thread_shutdown;
394     static void ReadThreadHandler(XLinkNetworkInterface* self);
395 #endif
396   };
397 
398   std::unique_ptr<NetworkInterface> m_network_interface;
399 
400   std::unique_ptr<u8[]> mRecvBuffer;
401   u32 mRecvBufferLength = 0;
402 };
403 }  // namespace ExpansionInterface
404