]> git.sesse.net Git - pistorm/commitdiff
Adapt a314eth to work on PiStorm + A314 emulation
authorbeeanyew <beeanyew@gmail.com>
Tue, 18 May 2021 11:33:06 +0000 (13:33 +0200)
committerbeeanyew <beeanyew@gmail.com>
Tue, 18 May 2021 11:33:06 +0000 (13:33 +0200)
Please don't ask me how this works, I have no idea.

15 files changed:
a314/files_pi/eth-config-pi/rc.local [new file with mode: 0644]
a314/files_pi/eth-config-pi/tap0 [new file with mode: 0644]
a314/software-amiga/a314eth.device
a314/software-amiga/eth-config-amiga/A314Eth [new file with mode: 0644]
a314/software-amiga/eth-config-amiga/name_resolution [new file with mode: 0644]
a314/software-amiga/eth-config-amiga/routes [new file with mode: 0644]
a314/software-amiga/ethernet_pistorm/README.md [new file with mode: 0644]
a314/software-amiga/ethernet_pistorm/build.bat [new file with mode: 0644]
a314/software-amiga/ethernet_pistorm/device.c [new file with mode: 0644]
a314/software-amiga/ethernet_pistorm/ethernet.py [new file with mode: 0644]
a314/software-amiga/ethernet_pistorm/romtag.asm [new file with mode: 0644]
a314/software-amiga/ethernet_pistorm/sana2.h [new file with mode: 0644]
a314/software-amiga/ethernet_pistorm/tagitem.h [new file with mode: 0644]
a314/software-amiga/remote-mouse [deleted file]
a314/software-amiga/remotewb [deleted file]

diff --git a/a314/files_pi/eth-config-pi/rc.local b/a314/files_pi/eth-config-pi/rc.local
new file mode 100644 (file)
index 0000000..f7581f3
--- /dev/null
@@ -0,0 +1,3 @@
+iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE  
+iptables -A FORWARD -i wlan0 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT  
+iptables -A FORWARD -i tap0 -o wlan0 -j ACCEPT
diff --git a/a314/files_pi/eth-config-pi/tap0 b/a314/files_pi/eth-config-pi/tap0
new file mode 100644 (file)
index 0000000..372406d
--- /dev/null
@@ -0,0 +1,9 @@
+auto tap0
+
+iface tap0 inet static
+       address 192.168.2.1
+       netmask 255.255.255.0
+       broadcast 192.168.2.255
+       pre-up ip tuntap add tap0 mode tap user pi group pi
+       up ip link set dev tap0 up
+       post-down ip link del dev tap0
index 4781e69bf94b0ce82ce7cf82ab8c1922bc0be6c8..6a8fb8883cb69e4d90a88af8a4c6d4fdff72b095 100644 (file)
Binary files a/a314/software-amiga/a314eth.device and b/a314/software-amiga/a314eth.device differ
diff --git a/a314/software-amiga/eth-config-amiga/A314Eth b/a314/software-amiga/eth-config-amiga/A314Eth
new file mode 100644 (file)
index 0000000..e6d385e
--- /dev/null
@@ -0,0 +1,3 @@
+device=a314eth.device
+address=192.168.2.2
+netmask=255.255.255.0
diff --git a/a314/software-amiga/eth-config-amiga/name_resolution b/a314/software-amiga/eth-config-amiga/name_resolution
new file mode 100644 (file)
index 0000000..cae093a
--- /dev/null
@@ -0,0 +1 @@
+nameserver 8.8.8.8
diff --git a/a314/software-amiga/eth-config-amiga/routes b/a314/software-amiga/eth-config-amiga/routes
new file mode 100644 (file)
index 0000000..2a3655d
--- /dev/null
@@ -0,0 +1 @@
+default 192.168.2.1
diff --git a/a314/software-amiga/ethernet_pistorm/README.md b/a314/software-amiga/ethernet_pistorm/README.md
new file mode 100644 (file)
index 0000000..59af112
--- /dev/null
@@ -0,0 +1,34 @@
+# a314eth.device - SANA-II driver for A314
+
+**NOTE: This readme is the default A314 Ethernet driver readme, and some of these things don't apply to the PiStorm A314 emulation adapted binary.**
+This SANA-II driver works by copying Ethernet frames back and forth between the Amiga and a virtual ethernet interface (tap0) on the Raspberry Pi. The Pi will, when configured properly, do network address translation (NAT) and route packets from the Amiga to the Internet.
+
+## Configuring the Raspberry Pi
+
+- Install pytun: `sudo pip3 install python-pytun`.
+- Copy `ethernet.py` to `/opt/a314/ethernet.py`.
+- Update `/etc/opt/a314/a314d.conf` with a line that starts `ethernet.py` on demand.
+  - In order for `a314d` to pick up the changes in `a314d.conf` you'll have to restart `a314d`, either by `sudo systemctl restart a314d` or by rebooting the Pi.
+- Copy `pi-config/tap0` to `/etc/network/interfaces.d/tap0`. This file creates a tap device with ip address 192.168.2.1 when the Raspberry Pi is booted up.
+- Add the lines in `pi-config/rc.local` to the bottom of `/etc/rc.local` just before `exit 0`. This create iptables rules that forwards packets from the `tap0` interface to the `wlan0` interface.
+  - Please note that if the Pi is connected using wired ethernet then `wlan0` should be changed to `eth0`.
+
+The first four steps are performed by `sudo make install`. The last step you have to do manually.
+
+## Configuring the Amiga
+
+This has only been tested with the Roadshow TCP/IP stack, and these instructions are written for Roadshow. The instructions won't describe how to install Roadshow.
+
+- Build the `a314eth.device` binary, for example using the `rpi_docker_build.sh` script.
+- Copy `bin/a314eth.device` to `DEVS:`.
+- Copy `amiga-config/A314Eth` to `DEVS:NetInterfaces/A314Eth`.
+- Copy `amiga-config/routes` to `DEVS:Internet/routes`.
+- Copy `amiga-config/name_resolution` to `DEVS:Internet/name_resolution`.
+  - You should change the nameserver to a DNS server that works on your network.
+  - Note that there may be settings in the above two files (`routes` and `name_resolution`) that you wish to keep, so look through the changes you are about to make first.
+
+Reboot the Amiga and with some luck you should be able to access the Internet from your Amiga.
+
+## Important note:
+
+After `ethernet.py` starts it waits for 15 seconds before it starts forwarding Ethernet frames. Without this waiting there is something that doesn't work properly (I don't know why this is). So when the Amiga boots for the first time after power off you'll have to wait up to 15 seconds before the Amiga can reach the Internet.
diff --git a/a314/software-amiga/ethernet_pistorm/build.bat b/a314/software-amiga/ethernet_pistorm/build.bat
new file mode 100644 (file)
index 0000000..63af202
--- /dev/null
@@ -0,0 +1 @@
+vc romtag.asm device.c -O3 -nostdlib -o ../a314eth.device -lamiga
diff --git a/a314/software-amiga/ethernet_pistorm/device.c b/a314/software-amiga/ethernet_pistorm/device.c
new file mode 100644 (file)
index 0000000..01f7731
--- /dev/null
@@ -0,0 +1,766 @@
+/*
+ * Copyright (c) 2020-2021 Niklas Ekström
+ *
+ * Thanks to Christian Vogelgsang and Mike Sterling for inspiration gained from their SANA-II drivers:
+ * - https://github.com/cnvogelg/plipbox
+ * - https://github.com/mikestir/k1208-drivers
+ */
+
+#include <exec/types.h>
+#include <exec/execbase.h>
+#include <exec/devices.h>
+#include <exec/errors.h>
+#include <exec/ports.h>
+#include <libraries/dos.h>
+#include <proto/exec.h>
+#include <proto/dos.h>
+
+#include <string.h>
+
+#include <clib/alib_protos.h>
+
+#include "../../a314device/a314.h"
+#include "../../a314device/proto_a314.h"
+#include "sana2.h"
+
+// Defines.
+
+#define DEVICE_NAME            "a314eth.device"
+#define SERVICE_NAME           "ethernet"
+
+#define TASK_PRIO              10
+
+#define MACADDR_SIZE           6
+#define NIC_BPS                        10000000
+
+#define ETH_MTU                        1500
+#define RAW_MTU                        1518
+
+#define READ_FRAME_REQ         1
+#define WRITE_FRAME_REQ                2
+#define READ_FRAME_RES         3
+#define WRITE_FRAME_RES                4
+
+#define ET_RBUF_CNT            2
+#define ET_WBUF_CNT            2
+#define ET_BUF_CNT             (ET_RBUF_CNT + ET_WBUF_CNT)
+
+// Typedefs.
+
+typedef BOOL (*buf_copy_func_t)(__reg("a0") void *dst, __reg("a1") void *src, __reg("d0") LONG size);
+
+// Structs.
+
+#pragma pack(push, 1)
+struct EthHdr
+{
+       unsigned char eh_Dst[MACADDR_SIZE];
+       unsigned char eh_Src[MACADDR_SIZE];
+       unsigned short eh_Type;
+};
+#pragma pack(pop)
+
+#pragma pack(push, 1)
+struct ServiceMsg
+{
+       ULONG sm_Address;
+       UWORD sm_Length;
+       UWORD sm_Kind;
+};
+#pragma pack(pop)
+
+struct BufDesc
+{
+       struct MinNode bd_Node;
+       void *bd_Buffer;
+       int bd_Length;
+};
+
+// Constants.
+
+const char device_name[] = DEVICE_NAME;
+const char id_string[] = DEVICE_NAME " 1.0 (20 July 2020)";
+
+static const char service_name[] = SERVICE_NAME;
+static const char a314_device_name[] = A314_NAME;
+
+static const unsigned char macaddr[MACADDR_SIZE] = { 0x40, 0x61, 0x33, 0x31, 0x34, 0x65 };
+
+// Global variables.
+
+BPTR saved_seg_list;
+struct ExecBase *SysBase;
+struct DosLibrary *DOSBase;
+struct Library *A314Base;
+
+buf_copy_func_t copyfrom;
+buf_copy_func_t copyto;
+
+volatile struct List ut_rbuf_list;
+volatile struct List ut_wbuf_list;
+
+struct BufDesc et_bufs[ET_BUF_CNT];
+
+struct List et_rbuf_free_list;
+struct List et_rbuf_pending_list;
+struct List et_rbuf_has_data_list;
+
+struct List et_wbuf_free_list;
+struct List et_wbuf_pending_list;
+
+LONG a314_socket;
+short last_req_kind;
+
+struct MsgPort a314_mp;
+
+struct A314_IORequest read_ior;
+struct A314_IORequest write_ior;
+struct A314_IORequest reset_ior;
+
+BOOL pending_a314_read;
+BOOL pending_a314_write;
+BOOL pending_a314_reset;
+
+struct ServiceMsg a314_read_buf;
+struct ServiceMsg a314_write_buf;
+
+volatile ULONG sana2_sigmask;
+volatile ULONG shutdown_sigmask;
+
+volatile struct Task *init_task;
+
+struct Process *device_process;
+volatile int device_start_error;
+
+// External declarations.
+
+extern void device_process_seglist();
+
+// Procedures.
+
+static struct Library *init_device(__reg("a6") struct ExecBase *sys_base, __reg("a0") BPTR seg_list, __reg("d0") struct Library *dev)
+{
+       saved_seg_list = seg_list;
+
+       dev->lib_Node.ln_Type = NT_DEVICE;
+       dev->lib_Node.ln_Name = (char *)device_name;
+       dev->lib_Flags = LIBF_SUMUSED | LIBF_CHANGED;
+       dev->lib_Version = 1;
+       dev->lib_Revision = 0;
+       dev->lib_IdString = (APTR)id_string;
+
+       SysBase = *(struct ExecBase **)4;
+       DOSBase = (struct DosLibrary *)OpenLibrary(DOSNAME, 0);
+
+       return dev;
+}
+
+static BPTR expunge(__reg("a6") struct Library *dev)
+{
+       if (dev->lib_OpenCnt)
+       {
+               dev->lib_Flags |= LIBF_DELEXP;
+               return 0;
+       }
+
+       // Shady way of waiting for device process to terminate before unloading.
+       Delay(10);
+
+       CloseLibrary((struct Library *)DOSBase);
+
+       Remove(&dev->lib_Node);
+       FreeMem((char *)dev - dev->lib_NegSize, dev->lib_NegSize + dev->lib_PosSize);
+       return saved_seg_list;
+}
+
+static void send_a314_cmd(struct A314_IORequest *ior, UWORD cmd, char *buffer, int length)
+{
+       ior->a314_Request.io_Command = cmd;
+       ior->a314_Request.io_Error = 0;
+       ior->a314_Socket = a314_socket;
+       ior->a314_Buffer = buffer;
+       ior->a314_Length = length;
+       SendIO((struct IORequest *)ior);
+}
+
+static void do_a314_cmd(struct A314_IORequest *ior, UWORD cmd, char *buffer, int length)
+{
+       ior->a314_Request.io_Command = cmd;
+       ior->a314_Request.io_Error = 0;
+       ior->a314_Socket = a314_socket;
+       ior->a314_Buffer = buffer;
+       ior->a314_Length = length;
+       DoIO((struct IORequest *)ior);
+}
+
+static void copy_from_bd_and_reply(struct IOSana2Req *ios2, struct BufDesc *bd)
+{
+       struct EthHdr *eh = bd->bd_Buffer;
+
+       if (ios2->ios2_Req.io_Flags & SANA2IOF_RAW)
+       {
+               ios2->ios2_DataLength = bd->bd_Length;
+               copyto(ios2->ios2_Data, bd->bd_Buffer, ios2->ios2_DataLength);
+               ios2->ios2_Req.io_Flags = SANA2IOF_RAW;
+       }
+       else
+       {
+               ios2->ios2_DataLength = bd->bd_Length - sizeof(struct EthHdr);
+               copyto(ios2->ios2_Data, &eh[1], ios2->ios2_DataLength);
+               ios2->ios2_Req.io_Flags = 0;
+       }
+
+       memcpy(ios2->ios2_SrcAddr, eh->eh_Src, MACADDR_SIZE);
+       memcpy(ios2->ios2_DstAddr, eh->eh_Dst, MACADDR_SIZE);
+
+       BOOL bcast = TRUE;
+       for (int i = 0; i < MACADDR_SIZE; i++)
+       {
+               if (eh->eh_Dst[i] != 0xff)
+               {
+                       bcast = FALSE;
+                       break;
+               }
+       }
+
+       if (bcast)
+               ios2->ios2_Req.io_Flags |= SANA2IOF_BCAST;
+
+       ios2->ios2_PacketType = eh->eh_Type;
+
+       ios2->ios2_Req.io_Error = 0;
+       ReplyMsg(&ios2->ios2_Req.io_Message);
+}
+
+static void copy_to_bd_and_reply(struct BufDesc *bd, struct IOSana2Req *ios2)
+{
+       struct EthHdr *eh = bd->bd_Buffer;
+
+       if (ios2->ios2_Req.io_Flags & SANA2IOF_RAW)
+       {
+               copyfrom(bd->bd_Buffer, ios2->ios2_Data, ios2->ios2_DataLength);
+               bd->bd_Length = ios2->ios2_DataLength;
+       }
+       else
+       {
+               eh->eh_Type = ios2->ios2_PacketType;
+               memcpy(eh->eh_Src, macaddr, sizeof(macaddr));
+               memcpy(eh->eh_Dst, ios2->ios2_DstAddr, MACADDR_SIZE);
+               copyfrom(&eh[1], ios2->ios2_Data, ios2->ios2_DataLength);
+               bd->bd_Length = ios2->ios2_DataLength + sizeof(struct EthHdr);
+       }
+
+       ios2->ios2_Req.io_Error = 0;
+       ReplyMsg(&ios2->ios2_Req.io_Message);
+}
+
+static void handle_a314_reply(struct A314_IORequest *ior)
+{
+       if (ior == &write_ior)
+       {
+               pending_a314_write = FALSE;
+
+               if (ior->a314_Request.io_Error == A314_WRITE_OK)
+               {
+                       // Start new write later.
+               }
+               else // A314_WRITE_RESET
+               {
+                       // TODO: Handle. What if pi-side is shutting down.
+               }
+       }
+       else if (ior == &read_ior)
+       {
+               pending_a314_read = FALSE;
+
+               if (ior->a314_Request.io_Error == A314_READ_OK)
+               {
+                       if (a314_read_buf.sm_Kind == WRITE_FRAME_RES)
+                       {
+                               struct BufDesc *bd = (struct BufDesc *)RemHead(&et_wbuf_pending_list);
+                               AddTail(&et_wbuf_free_list, (struct Node *)bd);
+                       }
+                       else // READ_FRAME_RES
+                       {
+                               struct BufDesc *bd = (struct BufDesc *)RemHead(&et_rbuf_pending_list);
+                               bd->bd_Length = a314_read_buf.sm_Length;
+                               AddTail(&et_rbuf_has_data_list, (struct Node *)bd);
+                       }
+
+                       send_a314_cmd(&read_ior, A314_READ, (void *)&a314_read_buf, sizeof(a314_read_buf));
+                       pending_a314_read = TRUE;
+               }
+               else // A314_READ_RESET
+               {
+                       // TODO: Handle. What if pi-side is shutting down.
+               }
+       }
+       else if (ior == &reset_ior)
+       {
+               pending_a314_reset = FALSE;
+       }
+}
+
+static struct IOSana2Req *remove_matching_rbuf(ULONG type)
+{
+       struct Node *node = ut_rbuf_list.lh_Head;
+       while (node->ln_Succ)
+       {
+               struct IOSana2Req *ios2 = (struct IOSana2Req *)node;
+               if (ios2->ios2_PacketType == type)
+               {
+                       Remove(node);
+                       return ios2;
+               }
+               node = node->ln_Succ;
+       }
+       return NULL;
+}
+
+static void complete_read_reqs()
+{
+       struct Node *node = et_rbuf_has_data_list.lh_Head;
+       if (!node->ln_Succ)
+               return;
+
+       Forbid();
+       while (node->ln_Succ)
+       {
+               struct BufDesc *bd = (struct BufDesc *)node;
+               struct EthHdr *eh = (struct EthHdr *)bd->bd_Buffer;
+
+               node = node->ln_Succ;
+
+               struct IOSana2Req *ios2 = remove_matching_rbuf(eh->eh_Type);
+               if (ios2)
+               {
+                       copy_from_bd_and_reply(ios2, bd);
+
+                       Remove((struct Node *)bd);
+                       AddTail(&et_rbuf_free_list, (struct Node *)bd);
+               }
+       }
+       Permit();
+}
+
+static void maybe_write_req()
+{
+       if (pending_a314_write)
+               return;
+
+       BOOL free_et_wbuf = et_wbuf_free_list.lh_Head->ln_Succ != NULL;
+       BOOL idle_et_rbuf = et_rbuf_free_list.lh_Head->ln_Succ != NULL;
+
+       Forbid();
+
+       BOOL waiting_ut_wbuf = ut_wbuf_list.lh_Head->ln_Succ != NULL;
+
+       BOOL want_wbuf = free_et_wbuf && waiting_ut_wbuf;
+       BOOL want_rbuf = idle_et_rbuf;
+
+       if (!want_rbuf && !want_wbuf)
+       {
+               Permit();
+               return;
+       }
+
+       short next_req_kind = 0;
+
+       if (last_req_kind == WRITE_FRAME_REQ)
+               next_req_kind = want_rbuf ? READ_FRAME_REQ : WRITE_FRAME_REQ;
+       else
+               next_req_kind = want_wbuf ? WRITE_FRAME_REQ : READ_FRAME_REQ;
+
+       struct IOSana2Req *ios2 = NULL;
+       if (next_req_kind == WRITE_FRAME_REQ)
+               ios2 = (struct IOSana2Req*)RemHead((struct List *)&ut_wbuf_list);
+
+       Permit();
+
+       struct BufDesc *bd;
+
+       if (next_req_kind == READ_FRAME_REQ)
+       {
+               bd = (struct BufDesc *)RemHead(&et_rbuf_free_list);
+               bd->bd_Length = RAW_MTU;
+               AddTail(&et_rbuf_pending_list, (struct Node *)&bd->bd_Node);
+       }
+       else // WRITE_FRAME_REQ
+       {
+               bd = (struct BufDesc *)RemHead(&et_wbuf_free_list);
+               copy_to_bd_and_reply(bd, ios2);
+               AddTail(&et_wbuf_pending_list, (struct Node *)bd);
+       }
+
+       a314_write_buf.sm_Address = TranslateAddressA314(bd->bd_Buffer);
+       a314_write_buf.sm_Length = bd->bd_Length;
+       a314_write_buf.sm_Kind = next_req_kind;
+
+       send_a314_cmd(&write_ior, A314_WRITE, (void *)&a314_write_buf, sizeof(a314_write_buf));
+       pending_a314_write = TRUE;
+
+       last_req_kind = next_req_kind;
+}
+
+void device_process_run()
+{
+       ULONG sana2_signal = AllocSignal(-1);
+       sana2_sigmask = 1UL << sana2_signal;
+
+       ULONG shutdown_signal = AllocSignal(-1);
+       shutdown_sigmask = 1UL << shutdown_signal;
+
+       a314_mp.mp_SigBit = AllocSignal(-1);
+       a314_mp.mp_SigTask = FindTask(NULL);
+
+       do_a314_cmd(&reset_ior, A314_CONNECT, (char *)service_name, strlen(service_name));
+       device_start_error = reset_ior.a314_Request.io_Error == A314_CONNECT_OK ? 0 : -1;
+
+       Signal((struct Task *)init_task, SIGF_SINGLE);
+
+       if (device_start_error)
+               return;
+
+       ULONG a314_sigmask = 1UL << a314_mp.mp_SigBit;
+
+       send_a314_cmd(&read_ior, A314_READ, (void *)&a314_read_buf, sizeof(a314_read_buf));
+       pending_a314_read = TRUE;
+
+       BOOL shutting_down = FALSE;
+
+       while (TRUE)
+       {
+               complete_read_reqs();
+               maybe_write_req();
+
+               if (shutting_down && !pending_a314_read && !pending_a314_write && !pending_a314_reset)
+                       break;
+
+               ULONG sigs = Wait(a314_sigmask | sana2_sigmask | shutdown_sigmask);
+
+               if ((sigs & shutdown_sigmask) && !shutting_down)
+               {
+                       send_a314_cmd(&reset_ior, A314_RESET, NULL, 0);
+                       pending_a314_reset = TRUE;
+                       shutting_down = TRUE;
+               }
+
+               if (sigs & a314_sigmask)
+               {
+                       struct A314_IORequest *ior;
+                       while ((ior = (struct A314_IORequest *)GetMsg(&a314_mp)))
+                               handle_a314_reply(ior);
+               }
+       }
+
+       Signal((struct Task *)init_task, SIGF_SINGLE);
+}
+
+static struct TagItem *FindTagItem(Tag tagVal, struct TagItem *tagList)
+{
+       struct TagItem *ti = tagList;
+       while (ti && ti->ti_Tag != tagVal)
+       {
+               switch (ti->ti_Tag)
+               {
+               case TAG_DONE:
+                       return NULL;
+               case TAG_MORE:
+                       ti = (struct TagItem *)ti->ti_Data;
+                       break;
+               case TAG_SKIP:
+                       ti += ti->ti_Data + 1;
+                       break;
+               case TAG_IGNORE:
+               default:
+                       ti++;
+                       break;
+               }
+       }
+       return ti;
+}
+
+static ULONG GetTagData(Tag tagVal, ULONG defaultData, struct TagItem *tagList)
+{
+       struct TagItem *ti = FindTagItem(tagVal, tagList);
+       return ti ? ti->ti_Data : defaultData;
+}
+
+static void open(__reg("a6") struct Library *dev, __reg("a1") struct IOSana2Req *ios2, __reg("d0") ULONG unitnum, __reg("d1") ULONG flags)
+{
+       ios2->ios2_Req.io_Error = IOERR_OPENFAIL;
+       ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
+
+       if (unitnum != 0 || dev->lib_OpenCnt)
+               return;
+
+       dev->lib_OpenCnt++;
+
+       copyfrom = (buf_copy_func_t)GetTagData(S2_CopyFromBuff, 0, (struct TagItem *)ios2->ios2_BufferManagement);
+       copyto = (buf_copy_func_t)GetTagData(S2_CopyToBuff, 0, (struct TagItem *)ios2->ios2_BufferManagement);
+       ios2->ios2_BufferManagement = (void *)0xdeadbeefUL;
+
+       memset(&a314_mp, 0, sizeof(a314_mp));
+       a314_mp.mp_Node.ln_Pri = 0;
+       a314_mp.mp_Node.ln_Type = NT_MSGPORT;
+       a314_mp.mp_Node.ln_Name = (char *)device_name;
+       a314_mp.mp_Flags = PA_SIGNAL;
+       NewList(&a314_mp.mp_MsgList);
+
+       memset(&write_ior, 0, sizeof(write_ior));
+       write_ior.a314_Request.io_Message.mn_ReplyPort = &a314_mp;
+       write_ior.a314_Request.io_Message.mn_Length = sizeof(write_ior);
+       write_ior.a314_Request.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
+
+       A314Base = NULL;
+       if (OpenDevice((char *)a314_device_name, 0, (struct IORequest *)&write_ior, 0))
+               goto error;
+
+       A314Base = &(write_ior.a314_Request.io_Device->dd_Library);
+
+       memcpy(&read_ior, &write_ior, sizeof(read_ior));
+       memcpy(&reset_ior, &write_ior, sizeof(reset_ior));
+
+       struct DateStamp ds;
+       DateStamp(&ds);
+       a314_socket = (ds.ds_Minute * 60 * TICKS_PER_SECOND) + ds.ds_Tick;
+
+       last_req_kind = WRITE_FRAME_REQ;
+
+       NewList((struct List *)&ut_rbuf_list);
+       NewList((struct List *)&ut_wbuf_list);
+
+       NewList(&et_rbuf_free_list);
+       NewList(&et_rbuf_pending_list);
+       NewList(&et_rbuf_has_data_list);
+
+       NewList(&et_wbuf_free_list);
+       NewList(&et_wbuf_pending_list);
+
+       for (int i = 0; i < ET_BUF_CNT; i++)
+               memset(&et_bufs[i], 0, sizeof(struct BufDesc));
+
+       for (int i = 0; i < ET_BUF_CNT; i++)
+       {
+               struct BufDesc *bd = &et_bufs[i];
+
+               bd->bd_Buffer = AllocMem(RAW_MTU, MEMF_FAST);
+               if (!bd->bd_Buffer)
+                       goto error;
+
+               if (i < ET_RBUF_CNT)
+                       AddTail(&et_rbuf_free_list, (struct Node*)&bd->bd_Node);
+               else
+                       AddTail(&et_wbuf_free_list, (struct Node*)&bd->bd_Node);
+       }
+
+       init_task = FindTask(NULL);
+
+       struct MsgPort *device_mp = CreateProc((char *)device_name, TASK_PRIO, ((ULONG)device_process_seglist) >> 2, 2048);
+       if (!device_mp)
+               goto error;
+
+       device_process = (struct Process *)((char *)device_mp - sizeof(struct Task));
+
+       Wait(SIGF_SINGLE);
+
+       if (device_start_error)
+               goto error;
+
+       ios2->ios2_Req.io_Error = 0;
+       return;
+
+error:
+       for (int i = ET_BUF_CNT - 1; i >= 0; i--)
+               if (et_bufs[i].bd_Buffer)
+                       FreeMem(et_bufs[i].bd_Buffer, RAW_MTU);
+
+       if (A314Base)
+       {
+               CloseDevice((struct IORequest *)&write_ior);
+               A314Base = NULL;
+       }
+
+       dev->lib_OpenCnt--;
+}
+
+static BPTR close(__reg("a6") struct Library *dev, __reg("a1") struct IOSana2Req *ios2)
+{
+       init_task = FindTask(NULL);
+       Signal(&device_process->pr_Task, shutdown_sigmask);
+       Wait(SIGF_SINGLE);
+
+       for (int i = ET_BUF_CNT - 1; i >= 0; i--)
+               FreeMem(et_bufs[i].bd_Buffer, RAW_MTU);
+
+       CloseDevice((struct IORequest *)&write_ior);
+       A314Base = NULL;
+
+       ios2->ios2_Req.io_Device = NULL;
+       ios2->ios2_Req.io_Unit = NULL;
+
+       dev->lib_OpenCnt--;
+
+       if (dev->lib_OpenCnt == 0 && (dev->lib_Flags & LIBF_DELEXP))
+               return expunge(dev);
+
+       return 0;
+}
+
+static void device_query(struct IOSana2Req *req)
+{
+       struct Sana2DeviceQuery *query;
+
+       query = req->ios2_StatData;
+       query->DevQueryFormat = 0;
+       query->DeviceLevel = 0;
+
+       if (query->SizeAvailable >= 18)
+               query->AddrFieldSize = MACADDR_SIZE * 8;
+
+       if (query->SizeAvailable >= 22)
+               query->MTU = ETH_MTU;
+
+       if (query->SizeAvailable >= 26)
+               query->BPS = NIC_BPS;
+
+       if (query->SizeAvailable >= 30)
+               query->HardwareType = S2WireType_Ethernet;
+
+       query->SizeSupplied = query->SizeAvailable < 30 ? query->SizeAvailable : 30;
+}
+
+static void begin_io(__reg("a6") struct Library *dev, __reg("a1") struct IOSana2Req *ios2)
+{
+       ios2->ios2_Req.io_Error = S2ERR_NO_ERROR;
+       ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
+
+       switch (ios2->ios2_Req.io_Command)
+       {
+       case CMD_READ:
+               if (!ios2->ios2_BufferManagement)
+               {
+                       ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
+                       ios2->ios2_WireError = S2WERR_BUFF_ERROR;
+                       break;
+               }
+
+               Forbid();
+               AddTail((struct List *)&ut_rbuf_list, &ios2->ios2_Req.io_Message.mn_Node);
+               Permit();
+
+               ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
+               ios2 = NULL;
+
+               Signal(&device_process->pr_Task, sana2_sigmask);
+               break;
+
+       case S2_BROADCAST:
+               memset(ios2->ios2_DstAddr, 0xff, MACADDR_SIZE);
+               /* Fall through */
+
+       case CMD_WRITE:
+               if (((ios2->ios2_Req.io_Flags & SANA2IOF_RAW) != 0 && ios2->ios2_DataLength > RAW_MTU) ||
+                       ((ios2->ios2_Req.io_Flags & SANA2IOF_RAW) == 0 && ios2->ios2_DataLength > ETH_MTU))
+               {
+                       ios2->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED;
+                       break;
+               }
+
+               if (!ios2->ios2_BufferManagement)
+               {
+                       ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
+                       ios2->ios2_WireError = S2WERR_BUFF_ERROR;
+                       break;
+               }
+
+               Forbid();
+               AddTail((struct List *)&ut_wbuf_list, &ios2->ios2_Req.io_Message.mn_Node);
+               Permit();
+
+               ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
+               ios2 = NULL;
+
+               Signal(&device_process->pr_Task, sana2_sigmask);
+               break;
+
+       case S2_ONLINE:
+       case S2_OFFLINE:
+       case S2_CONFIGINTERFACE:
+               break;
+       case S2_GETSTATIONADDRESS:
+               memcpy(ios2->ios2_SrcAddr, macaddr, sizeof(macaddr));
+               memcpy(ios2->ios2_DstAddr, macaddr, sizeof(macaddr));
+               break;
+       case S2_DEVICEQUERY:
+               device_query(ios2);
+               break;
+
+       case S2_ONEVENT:
+       case S2_TRACKTYPE:
+       case S2_UNTRACKTYPE:
+       case S2_GETTYPESTATS:
+       case S2_READORPHAN:
+       case S2_GETGLOBALSTATS:
+       case S2_GETSPECIALSTATS:
+               break;
+
+       default:
+               ios2->ios2_Req.io_Error = IOERR_NOCMD;
+               ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
+               break;
+       }
+
+       if (ios2)
+       {
+               if (ios2->ios2_Req.io_Flags & SANA2IOF_QUICK)
+                       ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
+               else
+                       ReplyMsg(&ios2->ios2_Req.io_Message);
+       }
+}
+
+static void remove_from_list(struct List *list, struct Node *node)
+{
+       for (struct Node *n = list->lh_Head; n->ln_Succ; n = n->ln_Succ)
+       {
+               if (n == node)
+               {
+                       Remove(n);
+                       return;
+               }
+       }
+}
+
+static ULONG abort_io(__reg("a6") struct Library *dev, __reg("a1") struct IOSana2Req *ios2)
+{
+       Forbid();
+       remove_from_list((struct List *)&ut_rbuf_list, &ios2->ios2_Req.io_Message.mn_Node);
+       remove_from_list((struct List *)&ut_wbuf_list, &ios2->ios2_Req.io_Message.mn_Node);
+       Permit();
+
+       ios2->ios2_Req.io_Error = IOERR_ABORTED;
+       ios2->ios2_WireError = 0;
+       ReplyMsg(&ios2->ios2_Req.io_Message);
+
+       return 0;
+}
+
+static ULONG device_vectors[] =
+{
+       (ULONG)open,
+       (ULONG)close,
+       (ULONG)expunge,
+       0,
+       (ULONG)begin_io,
+       (ULONG)abort_io,
+       -1,
+};
+
+ULONG auto_init_tables[] =
+{
+       sizeof(struct Library),
+       (ULONG)device_vectors,
+       0,
+       (ULONG)init_device,
+};
diff --git a/a314/software-amiga/ethernet_pistorm/ethernet.py b/a314/software-amiga/ethernet_pistorm/ethernet.py
new file mode 100644 (file)
index 0000000..028875f
--- /dev/null
@@ -0,0 +1,264 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2020 Niklas Ekström
+
+import logging
+import os
+import pytun
+import select
+import socket
+import struct
+import sys
+import time
+
+logging.basicConfig(format = '%(levelname)s, %(asctime)s, %(name)s, line %(lineno)d: %(message)s')
+logger = logging.getLogger(__name__)
+logger.setLevel(logging.INFO)
+
+MSG_REGISTER_REQ        = 1
+MSG_REGISTER_RES        = 2
+MSG_DEREGISTER_REQ      = 3
+MSG_DEREGISTER_RES      = 4
+MSG_READ_MEM_REQ        = 5
+MSG_READ_MEM_RES        = 6
+MSG_WRITE_MEM_REQ       = 7
+MSG_WRITE_MEM_RES       = 8
+MSG_CONNECT             = 9
+MSG_CONNECT_RESPONSE    = 10
+MSG_DATA                = 11
+MSG_EOS                 = 12
+MSG_RESET               = 13
+
+def wait_for_msg():
+    header = b''
+    while len(header) < 9:
+        data = drv.recv(9 - len(header))
+        if not data:
+            logger.error('Connection to a314d was closed, terminating.')
+            exit(-1)
+        header += data
+    (plen, stream_id, ptype) = struct.unpack('=IIB', header)
+    payload = b''
+    while len(payload) < plen:
+        data = drv.recv(plen - len(payload))
+        if not data:
+            logger.error('Connection to a314d was closed, terminating.')
+            exit(-1)
+        payload += data
+    return (stream_id, ptype, payload)
+
+def send_register_req(name):
+    m = struct.pack('=IIB', len(name), 0, MSG_REGISTER_REQ) + name
+    drv.sendall(m)
+
+def send_read_mem_req(address, length):
+    m = struct.pack('=IIBII', 8, 0, MSG_READ_MEM_REQ, address, length)
+    drv.sendall(m)
+
+def read_mem(address, length):
+    send_read_mem_req(address, length)
+    _, ptype, payload = wait_for_msg()
+    if ptype != MSG_READ_MEM_RES:
+        logger.error('Expected MSG_READ_MEM_RES but got %s. Shutting down.', ptype)
+        exit(-1)
+    return payload
+
+def send_write_mem_req(address, data):
+    m = struct.pack('=IIBI', 4 + len(data), 0, MSG_WRITE_MEM_REQ, address) + data
+    drv.sendall(m)
+
+def write_mem(address, data):
+    send_write_mem_req(address, data)
+    _, ptype, _ = wait_for_msg()
+    if ptype != MSG_WRITE_MEM_RES:
+        logger.error('Expected MSG_WRITE_MEM_RES but got %s. Shutting down.', ptype)
+        exit(-1)
+
+def send_connect_response(stream_id, result):
+    m = struct.pack('=IIBB', 1, stream_id, MSG_CONNECT_RESPONSE, result)
+    drv.sendall(m)
+
+def send_data(stream_id, data):
+    m = struct.pack('=IIB', len(data), stream_id, MSG_DATA) + data
+    drv.sendall(m)
+
+def send_eos(stream_id):
+    m = struct.pack('=IIB', 0, stream_id, MSG_EOS)
+    drv.sendall(m)
+
+def send_reset(stream_id):
+    m = struct.pack('=IIB', 0, stream_id, MSG_RESET)
+    drv.sendall(m)
+
+### A314 communication routines above. Actual driver below.
+
+current_stream_id = None
+done = False
+rbuf = b''
+
+DEV_NAME = 'tap0'
+SERVICE_NAME = b'ethernet'
+
+READ_FRAME_REQ = 1
+WRITE_FRAME_REQ = 2
+READ_FRAME_RES = 3
+WRITE_FRAME_RES = 4
+
+mem_read_queue = []
+mem_write_queue = []
+
+# Can buffer as many frames as fit in memory.
+# Maybe should have a limit on the number of buffers?
+waiting_read_reqs = []
+buffered_frames = []
+
+DROP_START_SECS = 15.0
+
+def process_tap_frame(frame):
+    if current_stream_id is None:
+        return
+
+    global drop_start
+    if drop_start:
+        if time.time() < start_time + DROP_START_SECS:
+            return
+        drop_start = False
+
+    if waiting_read_reqs:
+        stream_id, address, length = waiting_read_reqs.pop(0)
+
+        if length < len(frame):
+            logger.error('Fatal error, read frame from TAP larger than buffer')
+
+        mem_write_queue.append((stream_id, address, len(frame)))
+        send_write_mem_req(address, frame)
+    else:
+        buffered_frames.append(frame)
+
+def process_stream_data(stream_id, data):
+    address, length, kind = struct.unpack('>IHH', data)
+    if kind == WRITE_FRAME_REQ:
+        mem_read_queue.append((stream_id, address, length))
+        send_read_mem_req(address, length)
+    elif kind == READ_FRAME_REQ:
+        if buffered_frames:
+            frame = buffered_frames.pop(0)
+
+            if length < len(frame):
+                logger.error('Fatal error, read frame from TAP larger than buffer')
+
+            mem_write_queue.append((stream_id, address, len(frame)))
+            send_write_mem_req(address, frame)
+        else:
+            waiting_read_reqs.append((stream_id, address, length))
+
+def process_read_mem_res(frame):
+    tap.write(frame)
+
+    stream_id, address, length = mem_read_queue.pop(0)
+    if stream_id == current_stream_id:
+        send_data(stream_id, struct.pack('>IHH', address, length, WRITE_FRAME_RES))
+
+def process_write_mem_res():
+    stream_id, address, length = mem_write_queue.pop(0)
+    if stream_id == current_stream_id:
+        send_data(stream_id, struct.pack('>IHH', address, length, READ_FRAME_RES))
+
+def process_drv_msg(stream_id, ptype, payload):
+    global current_stream_id
+
+    if ptype == MSG_CONNECT:
+        if payload == SERVICE_NAME and current_stream_id is None:
+            logger.info('Amiga connected')
+            current_stream_id = stream_id
+            send_connect_response(stream_id, 0)
+        else:
+            send_connect_response(stream_id, 3)
+    elif ptype == MSG_READ_MEM_RES:
+        process_read_mem_res(payload)
+    elif ptype == MSG_WRITE_MEM_RES:
+        process_write_mem_res()
+    elif current_stream_id == stream_id:
+        if ptype == MSG_DATA:
+            process_stream_data(stream_id, payload)
+        elif ptype == MSG_EOS:
+            # EOS is not used.
+            pass
+        elif ptype == MSG_RESET:
+            current_stream_id = None
+            waiting_read_reqs.clear()
+            buffered_frames.clear()
+            logger.info('Amiga disconnected')
+
+try:
+    idx = sys.argv.index('-ondemand')
+except ValueError:
+    idx = -1
+
+if idx != -1:
+    fd = int(sys.argv[idx + 1])
+    drv = socket.socket(fileno=fd)
+else:
+    drv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    drv.connect(('localhost', 7110))
+    drv.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+
+    send_register_req(SERVICE_NAME)
+    _, _, payload = wait_for_msg()
+    if payload[0] != 1:
+        logger.error('Unable to register ethernet with driver, shutting down')
+        drv.close()
+        done = True
+
+if not done:
+    try:
+        tap = pytun.TunTapDevice(name=DEV_NAME, flags=pytun.IFF_TAP | pytun.IFF_NO_PI)
+    except:
+        logger.error('Unable to open tap device at ' + DEV_NAME)
+        done = True
+
+    start_time = time.time()
+    drop_start = True
+        
+if not done:
+    logger.info('Ethernet service is running')
+
+while not done:
+    try:
+        rl, _, _ = select.select([drv, tap], [], [], 10.0)
+    except KeyboardInterrupt:
+        rl = []
+        if current_stream_id is not None:
+            send_reset(current_stream_id)
+        drv.close()
+        done = True
+
+    if drv in rl:
+        buf = drv.recv(1600)
+        if not buf:
+            if current_stream_id is not None:
+                send_reset(current_stream_id)
+            drv.close()
+            done = True
+        else:
+            rbuf += buf
+            while True:
+                if len(rbuf) < 9:
+                    break
+
+                (plen, stream_id, ptype) = struct.unpack('=IIB', rbuf[:9])
+                if len(rbuf) < 9 + plen:
+                    break
+
+                payload = rbuf[9:9+plen]
+                rbuf = rbuf[9+plen:]
+
+                process_drv_msg(stream_id, ptype, payload)
+
+    if tap in rl:
+        frame = tap.read(1600)
+        process_tap_frame(frame)
+
+tap.close()
+logger.info('Ethernet service stopped')
diff --git a/a314/software-amiga/ethernet_pistorm/romtag.asm b/a314/software-amiga/ethernet_pistorm/romtag.asm
new file mode 100644 (file)
index 0000000..0b8b52b
--- /dev/null
@@ -0,0 +1,33 @@
+       XDEF    _device_process_seglist
+       XREF    _device_process_run
+
+RTC_MATCHWORD: equ     $4afc
+RTF_AUTOINIT:  equ     (1<<7)
+NT_DEVICE:     equ     3
+VERSION:       equ     1
+PRIORITY:      equ     0
+
+               section code,code
+
+               moveq   #-1,d0
+               rts
+
+romtag:
+               dc.w    RTC_MATCHWORD
+               dc.l    romtag
+               dc.l    endcode
+               dc.b    RTF_AUTOINIT
+               dc.b    VERSION
+               dc.b    NT_DEVICE
+               dc.b    PRIORITY
+               dc.l    _device_name
+               dc.l    _id_string
+               dc.l    _auto_init_tables
+endcode:
+
+               cnop    0,4
+
+               dc.l    16
+_device_process_seglist:
+               dc.l    0
+               jmp     _device_process_run
diff --git a/a314/software-amiga/ethernet_pistorm/sana2.h b/a314/software-amiga/ethernet_pistorm/sana2.h
new file mode 100644 (file)
index 0000000..645a0cd
--- /dev/null
@@ -0,0 +1,261 @@
+#ifndef SANA2_SANA2DEVICE_H
+#define SANA2_SANA2DEVICE_H 1
+/*
+**      $Filename: devices/sana2.h $
+**      $Revision: 4.1 $
+**      $Date: 1994/10/03 20:55:10 $
+**
+**      Structure definitions for SANA-II devices.
+**
+**      (C) Copyright 1991 Commodore-Amiga Inc.
+**              All Rights Reserved
+*/
+
+
+#ifndef EXEC_TYPES_H
+#include <exec/types.h>
+#endif
+
+#ifndef EXEC_PORTS_H
+#include <exec/ports.h>
+#endif
+
+#ifndef EXEC_IO_H
+#include <exec/io.h>
+#endif
+
+#ifndef EXEC_ERRORS_H
+#include <exec/errors.h>
+#endif
+
+#ifndef DEVICES_TIMER_H
+#include <devices/timer.h>
+#endif
+
+#ifndef UTILITY_TAGITEM_H
+#include "tagitem.h"
+#endif
+
+
+#define SANA2_MAX_ADDR_BITS     (128)
+#define SANA2_MAX_ADDR_BYTES    ((SANA2_MAX_ADDR_BITS+7)/8)
+
+struct IOSana2Req
+{
+        struct IORequest ios2_Req;
+        ULONG ios2_WireError;           /* wire type specific error     */
+        ULONG ios2_PacketType;          /* packet type                  */
+        UBYTE ios2_SrcAddr[SANA2_MAX_ADDR_BYTES];       /* source addr  */
+        UBYTE ios2_DstAddr[SANA2_MAX_ADDR_BYTES];       /* dest address */
+        ULONG ios2_DataLength;          /* length of packet data        */
+        VOID *ios2_Data;                /* packet data                  */
+        VOID *ios2_StatData;            /* statistics data pointer      */
+        VOID *ios2_BufferManagement;    /* see SANA-II OpenDevice adoc  */
+};
+
+
+/*
+** defines for the io_Flags field
+*/
+#define SANA2IOB_RAW    (7)             /* raw packet IO requested      */
+#define SANA2IOF_RAW    (1<<SANA2IOB_RAW)
+
+#define SANA2IOB_BCAST  (6)             /* broadcast packet (received)  */
+#define SANA2IOF_BCAST  (1<<SANA2IOB_BCAST)
+
+#define SANA2IOB_MCAST  (5)             /* multicast packet (received)  */
+#define SANA2IOF_MCAST  (1<<SANA2IOB_MCAST)
+
+#define SANA2IOB_QUICK  (IOB_QUICK)     /* quick IO requested (0)       */
+#define SANA2IOF_QUICK  (IOF_QUICK)
+
+
+/*
+** defines for OpenDevice() flags
+*/
+#define SANA2OPB_MINE   (0)             /* exclusive access requested   */
+#define SANA2OPF_MINE   (1<<SANA2OPB_MINE)
+
+#define SANA2OPB_PROM   (1)             /* promiscuous mode requested   */
+#define SANA2OPF_PROM   (1<<SANA2OPB_PROM)
+
+
+/*
+** defines for OpenDevice() tags
+*/
+#define S2_Dummy        (TAG_USER + 0xB0000)
+
+#define S2_CopyToBuff   (S2_Dummy + 1)
+#define S2_CopyFromBuff (S2_Dummy + 2)
+#define S2_PacketFilter (S2_Dummy + 3)
+
+struct Sana2DeviceQuery
+{
+/*
+** Standard information
+*/
+        ULONG   SizeAvailable;          /* bytes available              */
+        ULONG   SizeSupplied;           /* bytes supplied               */
+        ULONG   DevQueryFormat;         /* this is type 0               */
+        ULONG   DeviceLevel;            /* this document is level 0     */
+/*
+** Common information
+*/
+        UWORD   AddrFieldSize;          /* address size in bits         */
+        ULONG   MTU;                    /* maximum packet data size     */
+        ULONG   BPS;                    /* line rate (bits/sec)         */
+        ULONG   HardwareType;           /* what the wire is             */
+/*
+** Format specific information
+*/
+};
+
+
+/*
+** defined Hardware types
+**
+**  If your hardware type isn't listed below contact CATS to get a new
+**  type number added for your hardware.
+*/
+#define S2WireType_Ethernet             1
+#define S2WireType_IEEE802              6
+#define S2WireType_Arcnet               7
+#define S2WireType_LocalTalk            11
+#define S2WireType_DyLAN                12
+
+#define S2WireType_AmokNet              200    /* Amiga Floppy Port hardware */
+
+#define S2WireType_Liana               202     /* Villate Tronic parallel port hw */
+
+#define S2WireType_PPP                  253
+#define S2WireType_SLIP                 254
+#define S2WireType_CSLIP                255    /* Compressed SLIP */
+
+#define S2WireType_PLIP                        420     /* SLIP over a parallel port */
+
+struct Sana2PacketTypeStats
+{
+        ULONG PacketsSent;              /* transmitted count            */
+        ULONG PacketsReceived;          /* received count               */
+        ULONG BytesSent;                /* bytes transmitted count      */
+        ULONG BytesReceived;            /* bytes received count         */
+        ULONG PacketsDropped;           /* packets dropped count        */
+};
+
+
+struct Sana2SpecialStatRecord
+{
+        ULONG Type;                     /* statistic identifier         */
+        ULONG Count;                    /* the statistic                */
+        char *String;                   /* statistic name               */
+};
+
+
+struct Sana2SpecialStatHeader
+{
+        ULONG RecordCountMax;           /* room available               */
+        ULONG RecordCountSupplied;      /* number supplied              */
+        /* struct Sana2SpecialStatRecord[RecordCountMax]; */
+};
+
+
+struct Sana2DeviceStats
+{
+        ULONG PacketsReceived;          /* received count               */
+        ULONG PacketsSent;              /* transmitted count            */
+        ULONG BadData;                  /* bad packets received         */
+        ULONG Overruns;                 /* hardware miss count          */
+        ULONG Unused;                   /* Unused field                 */
+        ULONG UnknownTypesReceived;     /* orphan count                 */
+        ULONG Reconfigurations;         /* network reconfigurations     */
+        struct timeval LastStart;       /* time of last online          */
+};
+
+
+/*
+** Device Commands
+*/
+#define S2_START                (CMD_NONSTD)
+
+#define S2_DEVICEQUERY          (S2_START+ 0)
+#define S2_GETSTATIONADDRESS    (S2_START+ 1)
+#define S2_CONFIGINTERFACE      (S2_START+ 2)
+#define S2_ADDMULTICASTADDRESS  (S2_START+ 5)
+#define S2_DELMULTICASTADDRESS  (S2_START+ 6)
+#define S2_MULTICAST            (S2_START+ 7)
+#define S2_BROADCAST            (S2_START+ 8)
+#define S2_TRACKTYPE            (S2_START+ 9)
+#define S2_UNTRACKTYPE          (S2_START+10)
+#define S2_GETTYPESTATS         (S2_START+11)
+#define S2_GETSPECIALSTATS      (S2_START+12)
+#define S2_GETGLOBALSTATS       (S2_START+13)
+#define S2_ONEVENT              (S2_START+14)
+#define S2_READORPHAN           (S2_START+15)
+#define S2_ONLINE               (S2_START+16)
+#define S2_OFFLINE              (S2_START+17)
+
+#define S2_END                  (S2_START+18)
+
+
+/*
+** defined errors for io_Error  (see also <exec/errors.h>)
+*/
+#define S2ERR_NO_ERROR          0       /* peachy-keen                  */
+#define S2ERR_NO_RESOURCES      1       /* resource allocation failure  */
+#define S2ERR_BAD_ARGUMENT      3       /* garbage somewhere            */
+#define S2ERR_BAD_STATE         4       /* inappropriate state          */
+#define S2ERR_BAD_ADDRESS       5       /* who?                         */
+#define S2ERR_MTU_EXCEEDED      6       /* too much to chew             */
+#define S2ERR_NOT_SUPPORTED     8       /* hardware can't support cmd   */
+#define S2ERR_SOFTWARE          9       /* software error detected      */
+#define S2ERR_OUTOFSERVICE      10      /* driver is OFFLINE            */
+#define S2ERR_TX_FAILURE        11      /* Transmission attempt failed  */
+/*
+** From <exec/errors.h>
+**
+**      IOERR_OPENFAIL   (-1) * device/unit failed to open *
+**      IOERR_ABORTED    (-2) * request terminated early [after AbortIO()] *
+**      IOERR_NOCMD      (-3) * command not supported by device *
+**      IOERR_BADLENGTH  (-4) * not a valid length (usually IO_LENGTH) *
+**      IOERR_BADADDRESS (-5) * invalid address (misaligned or bad range) *
+**      IOERR_UNITBUSY   (-6) * device opens ok, but requested unit is busy *
+**      IOERR_SELFTEST   (-7) * hardware failed self-test *
+*/
+
+/*
+** defined errors for ios2_WireError
+*/
+#define S2WERR_GENERIC_ERROR    0       /* no specific info available   */
+#define S2WERR_NOT_CONFIGURED   1       /* unit not configured          */
+#define S2WERR_UNIT_ONLINE      2       /* unit is currently online     */
+#define S2WERR_UNIT_OFFLINE     3       /* unit is currently offline    */
+#define S2WERR_ALREADY_TRACKED  4       /* protocol already tracked     */
+#define S2WERR_NOT_TRACKED      5       /* protocol not tracked         */
+#define S2WERR_BUFF_ERROR       6       /* buff mgt func returned error */
+#define S2WERR_SRC_ADDRESS      7       /* source address problem       */
+#define S2WERR_DST_ADDRESS      8       /* destination address problem  */
+#define S2WERR_BAD_BROADCAST    9       /* broadcast address problem    */
+#define S2WERR_BAD_MULTICAST    10      /* multicast address problem    */
+#define S2WERR_MULTICAST_FULL   11      /* multicast address list full  */
+#define S2WERR_BAD_EVENT        12      /* unsupported event class      */
+#define S2WERR_BAD_STATDATA     13      /* statdata failed sanity check */
+#define S2WERR_IS_CONFIGURED    15      /* attempt to config twice      */
+#define S2WERR_NULL_POINTER     16      /* null pointer detected        */
+#define S2WERR_TOO_MANY_RETIRES 17      /* tx failed - too many retries */
+#define S2WERR_RCVREL_HDW_ERR   18      /* Driver fixable HW error      */
+
+
+/*
+** defined events
+*/
+#define S2EVENT_ERROR           (1L<<0) /* error catch all              */
+#define S2EVENT_TX              (1L<<1) /* transmitter error catch all  */
+#define S2EVENT_RX              (1L<<2) /* receiver error catch all     */
+#define S2EVENT_ONLINE          (1L<<3) /* unit is in service           */
+#define S2EVENT_OFFLINE         (1L<<4) /* unit is not in service       */
+#define S2EVENT_BUFF            (1L<<5) /* buff mgt function error      */
+#define S2EVENT_HARDWARE        (1L<<6) /* hardware error catch all     */
+#define S2EVENT_SOFTWARE        (1L<<7) /* software error catch all     */
+
+
+#endif  /* SANA2_SANA2DEVICE_H */
diff --git a/a314/software-amiga/ethernet_pistorm/tagitem.h b/a314/software-amiga/ethernet_pistorm/tagitem.h
new file mode 100644 (file)
index 0000000..15e05cc
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef UTILITY_TAGITEM_H
+#define UTILITY_TAGITEM_H
+/*
+**     $VER: tagitem.h 40.1 (19.7.1993)
+**     Includes Release 45.1
+**
+**     Extended specification mechanism
+**
+**     (C) Copyright 1989-2001 Amiga, Inc.
+**     All Rights Reserved
+*/
+
+/*****************************************************************************/
+
+
+#ifndef EXEC_TYPES_H
+#include <exec/types.h>
+#endif
+
+
+/*****************************************************************************/
+
+
+/* Tags are a general mechanism of extensible data arrays for parameter
+ * specification and property inquiry. In practice, tags are used in arrays,
+ * or chain of arrays.
+ *
+ */
+
+typedef ULONG Tag;
+
+struct TagItem
+{
+    Tag          ti_Tag;       /* identifies the type of data */
+    ULONG ti_Data;     /* type-specific data          */
+};
+
+/* constants for Tag.ti_Tag, control tag values */
+#define TAG_DONE   (0L)          /* terminates array of TagItems. ti_Data unused */
+#define TAG_END           (0L)   /* synonym for TAG_DONE                         */
+#define        TAG_IGNORE (1L)   /* ignore this item, not end of array           */
+#define        TAG_MORE   (2L)   /* ti_Data is pointer to another array of TagItems
+                          * note that this tag terminates the current array
+                          */
+#define        TAG_SKIP   (3L)   /* skip this and the next ti_Data items         */
+
+/* differentiates user tags from control tags */
+#define TAG_USER   ((ULONG)(1L<<31))
+
+/* If the TAG_USER bit is set in a tag number, it tells utility.library that
+ * the tag is not a control tag (like TAG_DONE, TAG_IGNORE, TAG_MORE) and is
+ * instead an application tag. "USER" means a client of utility.library in
+ * general, including system code like Intuition or ASL, it has nothing to do
+ * with user code.
+ */
+
+
+/*****************************************************************************/
+
+
+/* Tag filter logic specifiers for use with FilterTagItems() */
+#define TAGFILTER_AND 0                /* exclude everything but filter hits   */
+#define TAGFILTER_NOT 1                /* exclude only filter hits             */
+
+
+/*****************************************************************************/
+
+
+/* Mapping types for use with MapTags() */
+#define MAP_REMOVE_NOT_FOUND 0 /* remove tags that aren't in mapList */
+#define MAP_KEEP_NOT_FOUND   1 /* keep tags that aren't in mapList   */
+
+
+/*****************************************************************************/
+
+
+#endif /* UTILITY_TAGITEM_H */
diff --git a/a314/software-amiga/remote-mouse b/a314/software-amiga/remote-mouse
deleted file mode 100644 (file)
index 773f05e..0000000
Binary files a/a314/software-amiga/remote-mouse and /dev/null differ
diff --git a/a314/software-amiga/remotewb b/a314/software-amiga/remotewb
deleted file mode 100644 (file)
index 9a12a4c..0000000
Binary files a/a314/software-amiga/remotewb and /dev/null differ