2 * Copyright (c) 2020-2021 Niklas Ekström
4 * Thanks to Christian Vogelgsang and Mike Sterling for inspiration gained from their SANA-II drivers:
5 * - https://github.com/cnvogelg/plipbox
6 * - https://github.com/mikestir/k1208-drivers
9 #include <exec/resident.h>
10 #include <exec/errors.h>
11 #include <exec/memory.h>
12 #include <exec/lists.h>
13 #include <exec/alerts.h>
14 #include <exec/devices.h>
15 #include <exec/types.h>
16 #include <exec/tasks.h>
18 #include <exec/execbase.h>
19 #include <exec/ports.h>
21 #include <libraries/expansion.h>
22 #include <libraries/dos.h>
24 #include <devices/trackdisk.h>
25 #include <devices/timer.h>
26 #include <devices/scsidisk.h>
28 #include <dos/filehandler.h>
30 #include <proto/disk.h>
31 #include <proto/expansion.h>
32 #include <proto/exec.h>
33 #include <proto/dos.h>
37 #include <clib/alib_protos.h>
39 #include "../../a314device/a314.h"
40 #include "../../a314device/proto_a314.h"
50 #define XSTR(s) STR(s)
52 #define DEVICE_NAME "a314eth.device"
53 #define DEVICE_DATE "(19 May 2021)"
54 #define SERVICE_NAME "ethernet"
55 #define DEVICE_ID_STRING "A314Eth " XSTR(DEVICE_VERSION) "." XSTR(DEVICE_REVISION) " " DEVICE_DATE
56 #define DEVICE_VERSION 42
57 #define DEVICE_REVISION 2
58 #define DEVICE_PRIORITY 0
61 #define DEVICE_NAME "a314eth.device"
62 #define SERVICE_NAME "ethernet"
66 #define MACADDR_SIZE 6
67 #define NIC_BPS 10000000
72 #define READ_FRAME_REQ 1
73 #define WRITE_FRAME_REQ 2
74 #define READ_FRAME_RES 3
75 #define WRITE_FRAME_RES 4
79 #define ET_BUF_CNT (ET_RBUF_CNT + ET_WBUF_CNT)
81 int __attribute__((no_reorder)) _start()
87 " dc.w "XSTR(RTC_MATCHWORD)" \n"
90 " dc.b "XSTR(RTF_AUTOINIT)" \n"
91 " dc.b "XSTR(DEVICE_VERSION)" \n"
92 " dc.b "XSTR(NT_DEVICE)" \n"
93 " dc.b "XSTR(DEVICE_PRIORITY)" \n"
94 " dc.l _device_name \n"
95 " dc.l _device_id_string \n"
96 " dc.l _auto_init_tables \n"
100 "_device_process_seglist:\n"
102 " jmp _device_process_run\n");
104 char device_name[] = DEVICE_NAME;
105 char device_id_string[] = DEVICE_ID_STRING;
109 typedef BOOL (*buf_copy_func_t)(void *dst asm("a0"), void *src asm("a1"), LONG size asm("d0"));
113 #pragma pack(push, 1)
116 unsigned char eh_Dst[MACADDR_SIZE];
117 unsigned char eh_Src[MACADDR_SIZE];
118 unsigned short eh_Type;
122 #pragma pack(push, 1)
133 struct MinNode bd_Node;
140 static const char service_name[] = SERVICE_NAME;
141 static const char a314_device_name[] = A314_NAME;
143 static const unsigned char macaddr[MACADDR_SIZE] = { 0x40, 0x61, 0x33, 0x31, 0x34, 0x65 };
148 struct ExecBase *SysBase;
149 struct DosLibrary *DOSBase;
150 struct Library *A314Base;
152 buf_copy_func_t copyfrom;
153 buf_copy_func_t copyto;
155 volatile struct List ut_rbuf_list;
156 volatile struct List ut_wbuf_list;
158 struct BufDesc et_bufs[ET_BUF_CNT];
160 struct List et_rbuf_free_list;
161 struct List et_rbuf_pending_list;
162 struct List et_rbuf_has_data_list;
164 struct List et_wbuf_free_list;
165 struct List et_wbuf_pending_list;
170 struct MsgPort a314_mp;
172 struct A314_IORequest read_ior;
173 struct A314_IORequest write_ior;
174 struct A314_IORequest reset_ior;
176 BOOL pending_a314_read;
177 BOOL pending_a314_write;
178 BOOL pending_a314_reset;
180 struct ServiceMsg a314_read_buf;
181 struct ServiceMsg a314_write_buf;
183 volatile ULONG sana2_sigmask;
184 volatile ULONG shutdown_sigmask;
186 volatile struct Task *init_task;
188 struct Process *device_process;
189 volatile int device_start_error;
190 void device_process_run();
192 // External declarations.
194 extern void device_process_seglist();
198 static struct Library __attribute__((used)) *init_device(uint8_t *seg_list asm("a0"), struct Library *dev asm("d0"))
200 saved_seg_list = (BPTR)seg_list;
202 dev->lib_Node.ln_Type = NT_DEVICE;
203 dev->lib_Node.ln_Name = (char *)device_name;
204 dev->lib_Flags = LIBF_SUMUSED | LIBF_CHANGED;
205 dev->lib_Version = 1;
206 dev->lib_Revision = 0;
207 dev->lib_IdString = (APTR)device_id_string;
209 SysBase = *(struct ExecBase **)4;
210 DOSBase = (struct DosLibrary *)OpenLibrary((STRPTR)DOSNAME, 0);
215 static uint8_t* __attribute__((used)) expunge(struct Library *dev asm("a6"))
217 if (dev->lib_OpenCnt)
219 dev->lib_Flags |= LIBF_DELEXP;
223 // Shady way of waiting for device process to terminate before unloading.
226 CloseLibrary((struct Library *)DOSBase);
228 Remove(&dev->lib_Node);
229 FreeMem((char *)dev - dev->lib_NegSize, dev->lib_NegSize + dev->lib_PosSize);
230 return (uint8_t *)saved_seg_list;
233 static void send_a314_cmd(struct A314_IORequest *ior, UWORD cmd, char *buffer, int length)
235 ior->a314_Request.io_Command = cmd;
236 ior->a314_Request.io_Error = 0;
237 ior->a314_Socket = a314_socket;
238 ior->a314_Buffer = (STRPTR)buffer;
239 ior->a314_Length = length;
240 SendIO((struct IORequest *)ior);
243 static void do_a314_cmd(struct A314_IORequest *ior, UWORD cmd, char *buffer, int length)
245 ior->a314_Request.io_Command = cmd;
246 ior->a314_Request.io_Error = 0;
247 ior->a314_Socket = a314_socket;
248 ior->a314_Buffer = (STRPTR)buffer;
249 ior->a314_Length = length;
250 DoIO((struct IORequest *)ior);
253 static void copy_from_bd_and_reply(struct IOSana2Req *ios2, struct BufDesc *bd)
255 struct EthHdr *eh = bd->bd_Buffer;
257 if (ios2->ios2_Req.io_Flags & SANA2IOF_RAW)
259 ios2->ios2_DataLength = bd->bd_Length;
260 copyto(ios2->ios2_Data, bd->bd_Buffer, ios2->ios2_DataLength);
261 ios2->ios2_Req.io_Flags = SANA2IOF_RAW;
265 ios2->ios2_DataLength = bd->bd_Length - sizeof(struct EthHdr);
266 copyto(ios2->ios2_Data, &eh[1], ios2->ios2_DataLength);
267 ios2->ios2_Req.io_Flags = 0;
270 memcpy(ios2->ios2_SrcAddr, eh->eh_Src, MACADDR_SIZE);
271 memcpy(ios2->ios2_DstAddr, eh->eh_Dst, MACADDR_SIZE);
274 for (int i = 0; i < MACADDR_SIZE; i++)
276 if (eh->eh_Dst[i] != 0xff)
284 ios2->ios2_Req.io_Flags |= SANA2IOF_BCAST;
286 ios2->ios2_PacketType = eh->eh_Type;
288 ios2->ios2_Req.io_Error = 0;
289 ReplyMsg(&ios2->ios2_Req.io_Message);
292 static void copy_to_bd_and_reply(struct BufDesc *bd, struct IOSana2Req *ios2)
294 struct EthHdr *eh = bd->bd_Buffer;
296 if (ios2->ios2_Req.io_Flags & SANA2IOF_RAW)
298 copyfrom(bd->bd_Buffer, ios2->ios2_Data, ios2->ios2_DataLength);
299 bd->bd_Length = ios2->ios2_DataLength;
303 eh->eh_Type = ios2->ios2_PacketType;
304 memcpy(eh->eh_Src, macaddr, sizeof(macaddr));
305 memcpy(eh->eh_Dst, ios2->ios2_DstAddr, MACADDR_SIZE);
306 copyfrom(&eh[1], ios2->ios2_Data, ios2->ios2_DataLength);
307 bd->bd_Length = ios2->ios2_DataLength + sizeof(struct EthHdr);
310 ios2->ios2_Req.io_Error = 0;
311 ReplyMsg(&ios2->ios2_Req.io_Message);
314 static void handle_a314_reply(struct A314_IORequest *ior)
316 if (ior == &write_ior)
318 pending_a314_write = FALSE;
320 if (ior->a314_Request.io_Error == A314_WRITE_OK)
322 // Start new write later.
324 else // A314_WRITE_RESET
326 // TODO: Handle. What if pi-side is shutting down.
329 else if (ior == &read_ior)
331 pending_a314_read = FALSE;
333 if (ior->a314_Request.io_Error == A314_READ_OK)
335 if (a314_read_buf.sm_Kind == WRITE_FRAME_RES)
337 struct BufDesc *bd = (struct BufDesc *)RemHead(&et_wbuf_pending_list);
338 AddTail(&et_wbuf_free_list, (struct Node *)bd);
340 else // READ_FRAME_RES
342 struct BufDesc *bd = (struct BufDesc *)RemHead(&et_rbuf_pending_list);
343 bd->bd_Length = a314_read_buf.sm_Length;
344 AddTail(&et_rbuf_has_data_list, (struct Node *)bd);
347 send_a314_cmd(&read_ior, A314_READ, (void *)&a314_read_buf, sizeof(a314_read_buf));
348 pending_a314_read = TRUE;
350 else // A314_READ_RESET
352 // TODO: Handle. What if pi-side is shutting down.
355 else if (ior == &reset_ior)
357 pending_a314_reset = FALSE;
361 static struct IOSana2Req *remove_matching_rbuf(ULONG type)
363 struct Node *node = ut_rbuf_list.lh_Head;
364 while (node->ln_Succ)
366 struct IOSana2Req *ios2 = (struct IOSana2Req *)node;
367 if (ios2->ios2_PacketType == type)
372 node = node->ln_Succ;
377 static void complete_read_reqs()
379 struct Node *node = et_rbuf_has_data_list.lh_Head;
384 while (node->ln_Succ)
386 struct BufDesc *bd = (struct BufDesc *)node;
387 struct EthHdr *eh = (struct EthHdr *)bd->bd_Buffer;
389 node = node->ln_Succ;
391 struct IOSana2Req *ios2 = remove_matching_rbuf(eh->eh_Type);
394 copy_from_bd_and_reply(ios2, bd);
396 Remove((struct Node *)bd);
397 AddTail(&et_rbuf_free_list, (struct Node *)bd);
403 static void maybe_write_req()
405 if (pending_a314_write)
408 BOOL free_et_wbuf = et_wbuf_free_list.lh_Head->ln_Succ != NULL;
409 BOOL idle_et_rbuf = et_rbuf_free_list.lh_Head->ln_Succ != NULL;
413 BOOL waiting_ut_wbuf = ut_wbuf_list.lh_Head->ln_Succ != NULL;
415 BOOL want_wbuf = free_et_wbuf && waiting_ut_wbuf;
416 BOOL want_rbuf = idle_et_rbuf;
418 if (!want_rbuf && !want_wbuf)
424 short next_req_kind = 0;
426 if (last_req_kind == WRITE_FRAME_REQ)
427 next_req_kind = want_rbuf ? READ_FRAME_REQ : WRITE_FRAME_REQ;
429 next_req_kind = want_wbuf ? WRITE_FRAME_REQ : READ_FRAME_REQ;
431 struct IOSana2Req *ios2 = NULL;
432 if (next_req_kind == WRITE_FRAME_REQ)
433 ios2 = (struct IOSana2Req*)RemHead((struct List *)&ut_wbuf_list);
439 if (next_req_kind == READ_FRAME_REQ)
441 bd = (struct BufDesc *)RemHead(&et_rbuf_free_list);
442 bd->bd_Length = RAW_MTU;
443 AddTail(&et_rbuf_pending_list, (struct Node *)&bd->bd_Node);
445 else // WRITE_FRAME_REQ
447 bd = (struct BufDesc *)RemHead(&et_wbuf_free_list);
448 copy_to_bd_and_reply(bd, ios2);
449 AddTail(&et_wbuf_pending_list, (struct Node *)bd);
452 a314_write_buf.sm_Address = TranslateAddressA314(bd->bd_Buffer);
453 a314_write_buf.sm_Length = bd->bd_Length;
454 a314_write_buf.sm_Kind = next_req_kind;
456 send_a314_cmd(&write_ior, A314_WRITE, (void *)&a314_write_buf, sizeof(a314_write_buf));
457 pending_a314_write = TRUE;
459 last_req_kind = next_req_kind;
462 void device_process_run()
464 ULONG sana2_signal = AllocSignal(-1);
465 sana2_sigmask = 1UL << sana2_signal;
467 ULONG shutdown_signal = AllocSignal(-1);
468 shutdown_sigmask = 1UL << shutdown_signal;
470 a314_mp.mp_SigBit = AllocSignal(-1);
471 a314_mp.mp_SigTask = FindTask(NULL);
473 do_a314_cmd(&reset_ior, A314_CONNECT, (char *)service_name, strlen(service_name));
474 device_start_error = reset_ior.a314_Request.io_Error == A314_CONNECT_OK ? 0 : -1;
476 Signal((struct Task *)init_task, SIGF_SINGLE);
478 if (device_start_error)
481 ULONG a314_sigmask = 1UL << a314_mp.mp_SigBit;
483 send_a314_cmd(&read_ior, A314_READ, (void *)&a314_read_buf, sizeof(a314_read_buf));
484 pending_a314_read = TRUE;
486 BOOL shutting_down = FALSE;
490 complete_read_reqs();
493 if (shutting_down && !pending_a314_read && !pending_a314_write && !pending_a314_reset)
496 ULONG sigs = Wait(a314_sigmask | sana2_sigmask | shutdown_sigmask);
498 if ((sigs & shutdown_sigmask) && !shutting_down)
500 send_a314_cmd(&reset_ior, A314_RESET, NULL, 0);
501 pending_a314_reset = TRUE;
502 shutting_down = TRUE;
505 if (sigs & a314_sigmask)
507 struct A314_IORequest *ior;
508 while ((ior = (struct A314_IORequest *)GetMsg(&a314_mp)))
509 handle_a314_reply(ior);
513 Signal((struct Task *)init_task, SIGF_SINGLE);
516 static struct TagItem *FindTagItem(Tag tagVal, struct TagItem *tagList)
518 struct TagItem *ti = tagList;
519 while (ti && ti->ti_Tag != tagVal)
526 ti = (struct TagItem *)ti->ti_Data;
529 ti += ti->ti_Data + 1;
540 static ULONG GetTagData(Tag tagVal, ULONG defaultData, struct TagItem *tagList)
542 struct TagItem *ti = FindTagItem(tagVal, tagList);
543 return ti ? ti->ti_Data : defaultData;
546 static void __attribute__((used)) open(struct Library *dev asm("a6"), struct IOSana2Req *ios2 asm("a1"), uint32_t unitnum asm("d0"), uint32_t flags asm("d1"))
548 kprintf("We opening this shit.\n");
549 ios2->ios2_Req.io_Error = IOERR_OPENFAIL;
550 ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
552 if (unitnum != 0 || dev->lib_OpenCnt)
557 kprintf("Try the copyfrom crap.\n");
558 copyfrom = (buf_copy_func_t)GetTagData(S2_CopyFromBuff, 0, (struct TagItem *)ios2->ios2_BufferManagement);
559 copyto = (buf_copy_func_t)GetTagData(S2_CopyToBuff, 0, (struct TagItem *)ios2->ios2_BufferManagement);
560 ios2->ios2_BufferManagement = (void *)0xdeadbeefUL;
562 kprintf("Memsetting some shit.\n");
563 memset(&a314_mp, 0, sizeof(a314_mp));
564 a314_mp.mp_Node.ln_Pri = 0;
565 a314_mp.mp_Node.ln_Type = NT_MSGPORT;
566 a314_mp.mp_Node.ln_Name = (char *)device_name;
567 a314_mp.mp_Flags = PA_SIGNAL;
568 NewList(&a314_mp.mp_MsgList);
570 kprintf("Memsetting more shit.\n");
571 memset(&write_ior, 0, sizeof(write_ior));
572 write_ior.a314_Request.io_Message.mn_ReplyPort = &a314_mp;
573 write_ior.a314_Request.io_Message.mn_Length = sizeof(write_ior);
574 write_ior.a314_Request.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
576 kprintf("Opendevice.\n");
578 if (OpenDevice((STRPTR)a314_device_name, 0, (struct IORequest *)&write_ior, 0))
581 A314Base = &(write_ior.a314_Request.io_Device->dd_Library);
583 kprintf("Copy memory.\n");
584 memcpy(&read_ior, &write_ior, sizeof(read_ior));
585 memcpy(&reset_ior, &write_ior, sizeof(reset_ior));
587 kprintf("Making datestamps.\n");
590 a314_socket = (ds.ds_Minute * 60 * TICKS_PER_SECOND) + ds.ds_Tick;
592 last_req_kind = WRITE_FRAME_REQ;
594 kprintf("Making lists.\n");
595 NewList((struct List *)&ut_rbuf_list);
596 NewList((struct List *)&ut_wbuf_list);
598 NewList(&et_rbuf_free_list);
599 NewList(&et_rbuf_pending_list);
600 NewList(&et_rbuf_has_data_list);
602 NewList(&et_wbuf_free_list);
603 NewList(&et_wbuf_pending_list);
605 kprintf("Memzero buffers.\n");
606 for (int i = 0; i < ET_BUF_CNT; i++)
607 memset(&et_bufs[i], 0, sizeof(struct BufDesc));
609 kprintf("Add tails.\n");
610 for (int i = 0; i < ET_BUF_CNT; i++)
612 struct BufDesc *bd = &et_bufs[i];
614 bd->bd_Buffer = AllocMem(RAW_MTU, MEMF_FAST);
619 AddTail(&et_rbuf_free_list, (struct Node*)&bd->bd_Node);
621 AddTail(&et_wbuf_free_list, (struct Node*)&bd->bd_Node);
624 kprintf("Find task.\n");
625 init_task = FindTask(NULL);
627 kprintf("Do msgport.\n");
628 struct MsgPort *device_mp = CreateProc((STRPTR)device_name, TASK_PRIO, ((ULONG)&device_process_seglist) >> 2, 2048);
632 kprintf("Process thing.\n");
633 device_process = (struct Process *)((char *)device_mp - sizeof(struct Task));
637 kprintf("Waitedf.\n");
639 if (device_start_error) {
640 kprintf("Device start error.\n");
644 kprintf("Everything ok?\n");
645 ios2->ios2_Req.io_Error = 0;
649 kprintf("Error small farts.\n");
650 for (int i = ET_BUF_CNT - 1; i >= 0; i--)
651 if (et_bufs[i].bd_Buffer)
652 FreeMem(et_bufs[i].bd_Buffer, RAW_MTU);
656 CloseDevice((struct IORequest *)&write_ior);
663 static uint8_t* __attribute__((used)) close(struct Library *dev asm("a6"), struct IOSana2Req *ios2 asm("a1"))
666 init_task = FindTask(NULL);
667 Signal(&device_process->pr_Task, shutdown_sigmask);
670 for (int i = ET_BUF_CNT - 1; i >= 0; i--)
671 FreeMem(et_bufs[i].bd_Buffer, RAW_MTU);
673 CloseDevice((struct IORequest *)&write_ior);
676 ios2->ios2_Req.io_Device = NULL;
677 ios2->ios2_Req.io_Unit = NULL;
681 if (dev->lib_OpenCnt == 0 && (dev->lib_Flags & LIBF_DELEXP))
687 static void device_query(struct IOSana2Req *req)
689 struct Sana2DeviceQuery *query;
691 query = req->ios2_StatData;
692 query->DevQueryFormat = 0;
693 query->DeviceLevel = 0;
695 if (query->SizeAvailable >= 18)
696 query->AddrFieldSize = MACADDR_SIZE * 8;
698 if (query->SizeAvailable >= 22)
699 query->MTU = ETH_MTU;
701 if (query->SizeAvailable >= 26)
702 query->BPS = NIC_BPS;
704 if (query->SizeAvailable >= 30)
705 query->HardwareType = S2WireType_Ethernet;
707 query->SizeSupplied = query->SizeAvailable < 30 ? query->SizeAvailable : 30;
710 static void __attribute__((used)) begin_io(struct Library *dev asm("a6"), struct IOSana2Req *ios2 asm("a1"))
712 kprintf("BeginIO.\n");
713 ios2->ios2_Req.io_Error = S2ERR_NO_ERROR;
714 ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
716 switch (ios2->ios2_Req.io_Command)
719 if (!ios2->ios2_BufferManagement)
721 ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
722 ios2->ios2_WireError = S2WERR_BUFF_ERROR;
727 AddTail((struct List *)&ut_rbuf_list, &ios2->ios2_Req.io_Message.mn_Node);
730 ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
733 Signal(&device_process->pr_Task, sana2_sigmask);
737 memset(ios2->ios2_DstAddr, 0xff, MACADDR_SIZE);
741 if (((ios2->ios2_Req.io_Flags & SANA2IOF_RAW) != 0 && ios2->ios2_DataLength > RAW_MTU) ||
742 ((ios2->ios2_Req.io_Flags & SANA2IOF_RAW) == 0 && ios2->ios2_DataLength > ETH_MTU))
744 ios2->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED;
748 if (!ios2->ios2_BufferManagement)
750 ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
751 ios2->ios2_WireError = S2WERR_BUFF_ERROR;
756 AddTail((struct List *)&ut_wbuf_list, &ios2->ios2_Req.io_Message.mn_Node);
759 ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
762 Signal(&device_process->pr_Task, sana2_sigmask);
767 case S2_CONFIGINTERFACE:
769 case S2_GETSTATIONADDRESS:
770 memcpy(ios2->ios2_SrcAddr, macaddr, sizeof(macaddr));
771 memcpy(ios2->ios2_DstAddr, macaddr, sizeof(macaddr));
780 case S2_GETTYPESTATS:
782 case S2_GETGLOBALSTATS:
783 case S2_GETSPECIALSTATS:
787 ios2->ios2_Req.io_Error = IOERR_NOCMD;
788 ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
794 if (ios2->ios2_Req.io_Flags & SANA2IOF_QUICK)
795 ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
797 ReplyMsg(&ios2->ios2_Req.io_Message);
801 static void remove_from_list(struct List *list, struct Node *node)
803 for (struct Node *n = list->lh_Head; n->ln_Succ; n = n->ln_Succ)
813 static uint32_t __attribute__((used)) abort_io(struct Library *dev asm("a6"), struct IOSana2Req *ios2 asm("a1"))
815 kprintf("AbortIO.\n");
817 remove_from_list((struct List *)&ut_rbuf_list, &ios2->ios2_Req.io_Message.mn_Node);
818 remove_from_list((struct List *)&ut_wbuf_list, &ios2->ios2_Req.io_Message.mn_Node);
821 ios2->ios2_Req.io_Error = IOERR_ABORTED;
822 ios2->ios2_WireError = 0;
823 ReplyMsg(&ios2->ios2_Req.io_Message);
828 static ULONG device_vectors[] =
839 ULONG auto_init_tables[] =
841 sizeof(struct Library),
842 (ULONG)device_vectors,