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/types.h>
10 #include <exec/execbase.h>
11 #include <exec/devices.h>
12 #include <exec/errors.h>
13 #include <exec/ports.h>
14 #include <libraries/dos.h>
15 #include <proto/exec.h>
16 #include <proto/dos.h>
20 #include <clib/alib_protos.h>
22 #include "../../a314device/a314.h"
23 #include "../../a314device/proto_a314.h"
28 #define DEVICE_NAME "a314eth.device"
29 #define SERVICE_NAME "ethernet"
33 #define MACADDR_SIZE 6
34 #define NIC_BPS 10000000
39 #define READ_FRAME_REQ 1
40 #define WRITE_FRAME_REQ 2
41 #define READ_FRAME_RES 3
42 #define WRITE_FRAME_RES 4
46 #define ET_BUF_CNT (ET_RBUF_CNT + ET_WBUF_CNT)
50 typedef BOOL (*buf_copy_func_t)(__reg("a0") void *dst, __reg("a1") void *src, __reg("d0") LONG size);
57 unsigned char eh_Dst[MACADDR_SIZE];
58 unsigned char eh_Src[MACADDR_SIZE];
59 unsigned short eh_Type;
74 struct MinNode bd_Node;
81 const char device_name[] = DEVICE_NAME;
82 const char id_string[] = DEVICE_NAME " 1.0 (20 July 2020)";
84 static const char service_name[] = SERVICE_NAME;
85 static const char a314_device_name[] = A314_NAME;
87 static const unsigned char macaddr[MACADDR_SIZE] = { 0x40, 0x61, 0x33, 0x31, 0x34, 0x65 };
92 struct ExecBase *SysBase;
93 struct DosLibrary *DOSBase;
94 struct Library *A314Base;
96 buf_copy_func_t copyfrom;
97 buf_copy_func_t copyto;
99 volatile struct List ut_rbuf_list;
100 volatile struct List ut_wbuf_list;
102 struct BufDesc et_bufs[ET_BUF_CNT];
104 struct List et_rbuf_free_list;
105 struct List et_rbuf_pending_list;
106 struct List et_rbuf_has_data_list;
108 struct List et_wbuf_free_list;
109 struct List et_wbuf_pending_list;
114 struct MsgPort a314_mp;
116 struct A314_IORequest read_ior;
117 struct A314_IORequest write_ior;
118 struct A314_IORequest reset_ior;
120 BOOL pending_a314_read;
121 BOOL pending_a314_write;
122 BOOL pending_a314_reset;
124 struct ServiceMsg a314_read_buf;
125 struct ServiceMsg a314_write_buf;
127 volatile ULONG sana2_sigmask;
128 volatile ULONG shutdown_sigmask;
130 volatile struct Task *init_task;
132 struct Process *device_process;
133 volatile int device_start_error;
135 // External declarations.
137 extern void device_process_seglist();
141 static struct Library *init_device(__reg("a6") struct ExecBase *sys_base, __reg("a0") BPTR seg_list, __reg("d0") struct Library *dev)
143 saved_seg_list = seg_list;
145 dev->lib_Node.ln_Type = NT_DEVICE;
146 dev->lib_Node.ln_Name = (char *)device_name;
147 dev->lib_Flags = LIBF_SUMUSED | LIBF_CHANGED;
148 dev->lib_Version = 1;
149 dev->lib_Revision = 0;
150 dev->lib_IdString = (APTR)id_string;
152 SysBase = *(struct ExecBase **)4;
153 DOSBase = (struct DosLibrary *)OpenLibrary(DOSNAME, 0);
158 static BPTR expunge(__reg("a6") struct Library *dev)
160 if (dev->lib_OpenCnt)
162 dev->lib_Flags |= LIBF_DELEXP;
166 // Shady way of waiting for device process to terminate before unloading.
169 CloseLibrary((struct Library *)DOSBase);
171 Remove(&dev->lib_Node);
172 FreeMem((char *)dev - dev->lib_NegSize, dev->lib_NegSize + dev->lib_PosSize);
173 return saved_seg_list;
176 static void send_a314_cmd(struct A314_IORequest *ior, UWORD cmd, char *buffer, int length)
178 ior->a314_Request.io_Command = cmd;
179 ior->a314_Request.io_Error = 0;
180 ior->a314_Socket = a314_socket;
181 ior->a314_Buffer = buffer;
182 ior->a314_Length = length;
183 SendIO((struct IORequest *)ior);
186 static void do_a314_cmd(struct A314_IORequest *ior, UWORD cmd, char *buffer, int length)
188 ior->a314_Request.io_Command = cmd;
189 ior->a314_Request.io_Error = 0;
190 ior->a314_Socket = a314_socket;
191 ior->a314_Buffer = buffer;
192 ior->a314_Length = length;
193 DoIO((struct IORequest *)ior);
196 static void copy_from_bd_and_reply(struct IOSana2Req *ios2, struct BufDesc *bd)
198 struct EthHdr *eh = bd->bd_Buffer;
200 if (ios2->ios2_Req.io_Flags & SANA2IOF_RAW)
202 ios2->ios2_DataLength = bd->bd_Length;
203 copyto(ios2->ios2_Data, bd->bd_Buffer, ios2->ios2_DataLength);
204 ios2->ios2_Req.io_Flags = SANA2IOF_RAW;
208 ios2->ios2_DataLength = bd->bd_Length - sizeof(struct EthHdr);
209 copyto(ios2->ios2_Data, &eh[1], ios2->ios2_DataLength);
210 ios2->ios2_Req.io_Flags = 0;
213 memcpy(ios2->ios2_SrcAddr, eh->eh_Src, MACADDR_SIZE);
214 memcpy(ios2->ios2_DstAddr, eh->eh_Dst, MACADDR_SIZE);
217 for (int i = 0; i < MACADDR_SIZE; i++)
219 if (eh->eh_Dst[i] != 0xff)
227 ios2->ios2_Req.io_Flags |= SANA2IOF_BCAST;
229 ios2->ios2_PacketType = eh->eh_Type;
231 ios2->ios2_Req.io_Error = 0;
232 ReplyMsg(&ios2->ios2_Req.io_Message);
235 static void copy_to_bd_and_reply(struct BufDesc *bd, struct IOSana2Req *ios2)
237 struct EthHdr *eh = bd->bd_Buffer;
239 if (ios2->ios2_Req.io_Flags & SANA2IOF_RAW)
241 copyfrom(bd->bd_Buffer, ios2->ios2_Data, ios2->ios2_DataLength);
242 bd->bd_Length = ios2->ios2_DataLength;
246 eh->eh_Type = ios2->ios2_PacketType;
247 memcpy(eh->eh_Src, macaddr, sizeof(macaddr));
248 memcpy(eh->eh_Dst, ios2->ios2_DstAddr, MACADDR_SIZE);
249 copyfrom(&eh[1], ios2->ios2_Data, ios2->ios2_DataLength);
250 bd->bd_Length = ios2->ios2_DataLength + sizeof(struct EthHdr);
253 ios2->ios2_Req.io_Error = 0;
254 ReplyMsg(&ios2->ios2_Req.io_Message);
257 static void handle_a314_reply(struct A314_IORequest *ior)
259 if (ior == &write_ior)
261 pending_a314_write = FALSE;
263 if (ior->a314_Request.io_Error == A314_WRITE_OK)
265 // Start new write later.
267 else // A314_WRITE_RESET
269 // TODO: Handle. What if pi-side is shutting down.
272 else if (ior == &read_ior)
274 pending_a314_read = FALSE;
276 if (ior->a314_Request.io_Error == A314_READ_OK)
278 if (a314_read_buf.sm_Kind == WRITE_FRAME_RES)
280 struct BufDesc *bd = (struct BufDesc *)RemHead(&et_wbuf_pending_list);
281 AddTail(&et_wbuf_free_list, (struct Node *)bd);
283 else // READ_FRAME_RES
285 struct BufDesc *bd = (struct BufDesc *)RemHead(&et_rbuf_pending_list);
286 bd->bd_Length = a314_read_buf.sm_Length;
287 AddTail(&et_rbuf_has_data_list, (struct Node *)bd);
290 send_a314_cmd(&read_ior, A314_READ, (void *)&a314_read_buf, sizeof(a314_read_buf));
291 pending_a314_read = TRUE;
293 else // A314_READ_RESET
295 // TODO: Handle. What if pi-side is shutting down.
298 else if (ior == &reset_ior)
300 pending_a314_reset = FALSE;
304 static struct IOSana2Req *remove_matching_rbuf(ULONG type)
306 struct Node *node = ut_rbuf_list.lh_Head;
307 while (node->ln_Succ)
309 struct IOSana2Req *ios2 = (struct IOSana2Req *)node;
310 if (ios2->ios2_PacketType == type)
315 node = node->ln_Succ;
320 static void complete_read_reqs()
322 struct Node *node = et_rbuf_has_data_list.lh_Head;
327 while (node->ln_Succ)
329 struct BufDesc *bd = (struct BufDesc *)node;
330 struct EthHdr *eh = (struct EthHdr *)bd->bd_Buffer;
332 node = node->ln_Succ;
334 struct IOSana2Req *ios2 = remove_matching_rbuf(eh->eh_Type);
337 copy_from_bd_and_reply(ios2, bd);
339 Remove((struct Node *)bd);
340 AddTail(&et_rbuf_free_list, (struct Node *)bd);
346 static void maybe_write_req()
348 if (pending_a314_write)
351 BOOL free_et_wbuf = et_wbuf_free_list.lh_Head->ln_Succ != NULL;
352 BOOL idle_et_rbuf = et_rbuf_free_list.lh_Head->ln_Succ != NULL;
356 BOOL waiting_ut_wbuf = ut_wbuf_list.lh_Head->ln_Succ != NULL;
358 BOOL want_wbuf = free_et_wbuf && waiting_ut_wbuf;
359 BOOL want_rbuf = idle_et_rbuf;
361 if (!want_rbuf && !want_wbuf)
367 short next_req_kind = 0;
369 if (last_req_kind == WRITE_FRAME_REQ)
370 next_req_kind = want_rbuf ? READ_FRAME_REQ : WRITE_FRAME_REQ;
372 next_req_kind = want_wbuf ? WRITE_FRAME_REQ : READ_FRAME_REQ;
374 struct IOSana2Req *ios2 = NULL;
375 if (next_req_kind == WRITE_FRAME_REQ)
376 ios2 = (struct IOSana2Req*)RemHead((struct List *)&ut_wbuf_list);
382 if (next_req_kind == READ_FRAME_REQ)
384 bd = (struct BufDesc *)RemHead(&et_rbuf_free_list);
385 bd->bd_Length = RAW_MTU;
386 AddTail(&et_rbuf_pending_list, (struct Node *)&bd->bd_Node);
388 else // WRITE_FRAME_REQ
390 bd = (struct BufDesc *)RemHead(&et_wbuf_free_list);
391 copy_to_bd_and_reply(bd, ios2);
392 AddTail(&et_wbuf_pending_list, (struct Node *)bd);
395 a314_write_buf.sm_Address = TranslateAddressA314(bd->bd_Buffer);
396 a314_write_buf.sm_Length = bd->bd_Length;
397 a314_write_buf.sm_Kind = next_req_kind;
399 send_a314_cmd(&write_ior, A314_WRITE, (void *)&a314_write_buf, sizeof(a314_write_buf));
400 pending_a314_write = TRUE;
402 last_req_kind = next_req_kind;
405 void device_process_run()
407 ULONG sana2_signal = AllocSignal(-1);
408 sana2_sigmask = 1UL << sana2_signal;
410 ULONG shutdown_signal = AllocSignal(-1);
411 shutdown_sigmask = 1UL << shutdown_signal;
413 a314_mp.mp_SigBit = AllocSignal(-1);
414 a314_mp.mp_SigTask = FindTask(NULL);
416 do_a314_cmd(&reset_ior, A314_CONNECT, (char *)service_name, strlen(service_name));
417 device_start_error = reset_ior.a314_Request.io_Error == A314_CONNECT_OK ? 0 : -1;
419 Signal((struct Task *)init_task, SIGF_SINGLE);
421 if (device_start_error)
424 ULONG a314_sigmask = 1UL << a314_mp.mp_SigBit;
426 send_a314_cmd(&read_ior, A314_READ, (void *)&a314_read_buf, sizeof(a314_read_buf));
427 pending_a314_read = TRUE;
429 BOOL shutting_down = FALSE;
433 complete_read_reqs();
436 if (shutting_down && !pending_a314_read && !pending_a314_write && !pending_a314_reset)
439 ULONG sigs = Wait(a314_sigmask | sana2_sigmask | shutdown_sigmask);
441 if ((sigs & shutdown_sigmask) && !shutting_down)
443 send_a314_cmd(&reset_ior, A314_RESET, NULL, 0);
444 pending_a314_reset = TRUE;
445 shutting_down = TRUE;
448 if (sigs & a314_sigmask)
450 struct A314_IORequest *ior;
451 while ((ior = (struct A314_IORequest *)GetMsg(&a314_mp)))
452 handle_a314_reply(ior);
456 Signal((struct Task *)init_task, SIGF_SINGLE);
459 static struct TagItem *FindTagItem(Tag tagVal, struct TagItem *tagList)
461 struct TagItem *ti = tagList;
462 while (ti && ti->ti_Tag != tagVal)
469 ti = (struct TagItem *)ti->ti_Data;
472 ti += ti->ti_Data + 1;
483 static ULONG GetTagData(Tag tagVal, ULONG defaultData, struct TagItem *tagList)
485 struct TagItem *ti = FindTagItem(tagVal, tagList);
486 return ti ? ti->ti_Data : defaultData;
489 static void open(__reg("a6") struct Library *dev, __reg("a1") struct IOSana2Req *ios2, __reg("d0") ULONG unitnum, __reg("d1") ULONG flags)
491 ios2->ios2_Req.io_Error = IOERR_OPENFAIL;
492 ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
494 if (unitnum != 0 || dev->lib_OpenCnt)
499 copyfrom = (buf_copy_func_t)GetTagData(S2_CopyFromBuff, 0, (struct TagItem *)ios2->ios2_BufferManagement);
500 copyto = (buf_copy_func_t)GetTagData(S2_CopyToBuff, 0, (struct TagItem *)ios2->ios2_BufferManagement);
501 ios2->ios2_BufferManagement = (void *)0xdeadbeefUL;
503 memset(&a314_mp, 0, sizeof(a314_mp));
504 a314_mp.mp_Node.ln_Pri = 0;
505 a314_mp.mp_Node.ln_Type = NT_MSGPORT;
506 a314_mp.mp_Node.ln_Name = (char *)device_name;
507 a314_mp.mp_Flags = PA_SIGNAL;
508 NewList(&a314_mp.mp_MsgList);
510 memset(&write_ior, 0, sizeof(write_ior));
511 write_ior.a314_Request.io_Message.mn_ReplyPort = &a314_mp;
512 write_ior.a314_Request.io_Message.mn_Length = sizeof(write_ior);
513 write_ior.a314_Request.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
516 if (OpenDevice((char *)a314_device_name, 0, (struct IORequest *)&write_ior, 0))
519 A314Base = &(write_ior.a314_Request.io_Device->dd_Library);
521 memcpy(&read_ior, &write_ior, sizeof(read_ior));
522 memcpy(&reset_ior, &write_ior, sizeof(reset_ior));
526 a314_socket = (ds.ds_Minute * 60 * TICKS_PER_SECOND) + ds.ds_Tick;
528 last_req_kind = WRITE_FRAME_REQ;
530 NewList((struct List *)&ut_rbuf_list);
531 NewList((struct List *)&ut_wbuf_list);
533 NewList(&et_rbuf_free_list);
534 NewList(&et_rbuf_pending_list);
535 NewList(&et_rbuf_has_data_list);
537 NewList(&et_wbuf_free_list);
538 NewList(&et_wbuf_pending_list);
540 for (int i = 0; i < ET_BUF_CNT; i++)
541 memset(&et_bufs[i], 0, sizeof(struct BufDesc));
543 for (int i = 0; i < ET_BUF_CNT; i++)
545 struct BufDesc *bd = &et_bufs[i];
547 bd->bd_Buffer = AllocMem(RAW_MTU, MEMF_FAST);
552 AddTail(&et_rbuf_free_list, (struct Node*)&bd->bd_Node);
554 AddTail(&et_wbuf_free_list, (struct Node*)&bd->bd_Node);
557 init_task = FindTask(NULL);
559 struct MsgPort *device_mp = CreateProc((char *)device_name, TASK_PRIO, ((ULONG)device_process_seglist) >> 2, 2048);
563 device_process = (struct Process *)((char *)device_mp - sizeof(struct Task));
567 if (device_start_error)
570 ios2->ios2_Req.io_Error = 0;
574 for (int i = ET_BUF_CNT - 1; i >= 0; i--)
575 if (et_bufs[i].bd_Buffer)
576 FreeMem(et_bufs[i].bd_Buffer, RAW_MTU);
580 CloseDevice((struct IORequest *)&write_ior);
587 static BPTR close(__reg("a6") struct Library *dev, __reg("a1") struct IOSana2Req *ios2)
589 init_task = FindTask(NULL);
590 Signal(&device_process->pr_Task, shutdown_sigmask);
593 for (int i = ET_BUF_CNT - 1; i >= 0; i--)
594 FreeMem(et_bufs[i].bd_Buffer, RAW_MTU);
596 CloseDevice((struct IORequest *)&write_ior);
599 ios2->ios2_Req.io_Device = NULL;
600 ios2->ios2_Req.io_Unit = NULL;
604 if (dev->lib_OpenCnt == 0 && (dev->lib_Flags & LIBF_DELEXP))
610 static void device_query(struct IOSana2Req *req)
612 struct Sana2DeviceQuery *query;
614 query = req->ios2_StatData;
615 query->DevQueryFormat = 0;
616 query->DeviceLevel = 0;
618 if (query->SizeAvailable >= 18)
619 query->AddrFieldSize = MACADDR_SIZE * 8;
621 if (query->SizeAvailable >= 22)
622 query->MTU = ETH_MTU;
624 if (query->SizeAvailable >= 26)
625 query->BPS = NIC_BPS;
627 if (query->SizeAvailable >= 30)
628 query->HardwareType = S2WireType_Ethernet;
630 query->SizeSupplied = query->SizeAvailable < 30 ? query->SizeAvailable : 30;
633 static void begin_io(__reg("a6") struct Library *dev, __reg("a1") struct IOSana2Req *ios2)
635 ios2->ios2_Req.io_Error = S2ERR_NO_ERROR;
636 ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
638 switch (ios2->ios2_Req.io_Command)
641 if (!ios2->ios2_BufferManagement)
643 ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
644 ios2->ios2_WireError = S2WERR_BUFF_ERROR;
649 AddTail((struct List *)&ut_rbuf_list, &ios2->ios2_Req.io_Message.mn_Node);
652 ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
655 Signal(&device_process->pr_Task, sana2_sigmask);
659 memset(ios2->ios2_DstAddr, 0xff, MACADDR_SIZE);
663 if (((ios2->ios2_Req.io_Flags & SANA2IOF_RAW) != 0 && ios2->ios2_DataLength > RAW_MTU) ||
664 ((ios2->ios2_Req.io_Flags & SANA2IOF_RAW) == 0 && ios2->ios2_DataLength > ETH_MTU))
666 ios2->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED;
670 if (!ios2->ios2_BufferManagement)
672 ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
673 ios2->ios2_WireError = S2WERR_BUFF_ERROR;
678 AddTail((struct List *)&ut_wbuf_list, &ios2->ios2_Req.io_Message.mn_Node);
681 ios2->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
684 Signal(&device_process->pr_Task, sana2_sigmask);
689 case S2_CONFIGINTERFACE:
691 case S2_GETSTATIONADDRESS:
692 memcpy(ios2->ios2_SrcAddr, macaddr, sizeof(macaddr));
693 memcpy(ios2->ios2_DstAddr, macaddr, sizeof(macaddr));
702 case S2_GETTYPESTATS:
704 case S2_GETGLOBALSTATS:
705 case S2_GETSPECIALSTATS:
709 ios2->ios2_Req.io_Error = IOERR_NOCMD;
710 ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
716 if (ios2->ios2_Req.io_Flags & SANA2IOF_QUICK)
717 ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
719 ReplyMsg(&ios2->ios2_Req.io_Message);
723 static void remove_from_list(struct List *list, struct Node *node)
725 for (struct Node *n = list->lh_Head; n->ln_Succ; n = n->ln_Succ)
735 static ULONG abort_io(__reg("a6") struct Library *dev, __reg("a1") struct IOSana2Req *ios2)
738 remove_from_list((struct List *)&ut_rbuf_list, &ios2->ios2_Req.io_Message.mn_Node);
739 remove_from_list((struct List *)&ut_wbuf_list, &ios2->ios2_Req.io_Message.mn_Node);
742 ios2->ios2_Req.io_Error = IOERR_ABORTED;
743 ios2->ios2_WireError = 0;
744 ReplyMsg(&ios2->ios2_Req.io_Message);
749 static ULONG device_vectors[] =
760 ULONG auto_init_tables[] =
762 sizeof(struct Library),
763 (ULONG)device_vectors,