1 // SPDX-License-Identifier: MIT
3 #include <exec/resident.h>
4 #include <exec/errors.h>
5 #include <exec/memory.h>
6 #include <exec/lists.h>
7 #include <exec/alerts.h>
8 #include <exec/tasks.h>
10 #include <exec/execbase.h>
11 #include <exec/interrupts.h>
12 #include <hardware/intbits.h>
14 #include <libraries/expansion.h>
16 #include <devices/trackdisk.h>
17 #include <devices/timer.h>
18 #include <devices/scsidisk.h>
20 #include <dos/filehandler.h>
21 #include <dos/dostags.h>
23 #include <proto/exec.h>
24 #include <proto/disk.h>
25 #include <proto/expansion.h>
26 #include <proto/utility.h>
27 #include <proto/dos.h>
29 #include <utility/tagitem.h>
31 //#include <clib/exec_protos.h>
32 #include <clib/alib_protos.h>
33 //#include <clib/debug_protos.h>
35 #include "../pi-net-enums.h"
42 #define XSTR(s) STR(s)
44 #define DEVICE_NAME "pi-net.device"
45 #define DEVICE_DATE "(14 May 2021)"
46 #define DEVICE_ID_STRING "Pi-NET " XSTR(DEVICE_VERSION) "." XSTR(DEVICE_REVISION) " " DEVICE_DATE
47 #define DEVICE_VERSION 43
48 #define DEVICE_REVISION 10
49 #define DEVICE_PRIORITY 0
53 struct Device* pi_dev;
58 struct List read_list;
59 struct SignalSemaphore read_list_sem;
62 struct ExecBase* SysBase = NULL;
63 uint8_t *saved_seg_list;
66 #define WRITESHORT(cmd, val) *(unsigned short *)((unsigned long)(PINET_OFFSET + cmd)) = val;
67 #define WRITELONG(cmd, val) *(unsigned long *)((unsigned long)(PINET_OFFSET + cmd)) = val;
68 #define WRITEBYTE(cmd, val) *(unsigned char *)((unsigned long)(PINET_OFFSET + cmd)) = val;
70 #define READBYTE(cmd, var) var = *(volatile unsigned char *)(PINET_OFFSET + cmd);
71 #define READSHORT(cmd, var) var = *(volatile unsigned short *)(PINET_OFFSET + cmd);
72 #define READLONG(cmd, var) var = *(volatile unsigned long *)(PINET_OFFSET + cmd);
74 int __attribute__((no_reorder)) _start()
80 " dc.w "XSTR(RTC_MATCHWORD)" \n"
83 " dc.b "XSTR(RTF_AUTOINIT)" \n"
84 " dc.b "XSTR(DEVICE_VERSION)" \n"
85 " dc.b "XSTR(NT_DEVICE)" \n"
86 " dc.b "XSTR(DEVICE_PRIORITY)" \n"
87 " dc.l _device_name \n"
88 " dc.l _device_id_string \n"
89 " dc.l _auto_init_tables \n"
91 char device_name[] = DEVICE_NAME;
92 char device_id_string[] = DEVICE_ID_STRING;
94 typedef struct BufferManagement
96 struct MinNode bm_Node;
97 BOOL (*bm_CopyFromBuffer)(void* a __asm("a0"), void* b __asm("a1"), long c __asm("d0"));
98 BOOL (*bm_CopyToBuffer)(void* a __asm("a0"), void* b __asm("a1"), long c __asm("d0"));
101 struct pinet_base *dev_base = NULL;
107 static struct Library __attribute__((used)) *init_device(struct Device* dev) {
113 if (ok || i || p) { }
115 SysBase = *(struct ExecBase **)4L;
117 kprintf("Initializing net device.\n");
119 dev_base = AllocMem(sizeof(struct pinet_base), MEMF_PUBLIC | MEMF_CLEAR);
120 dev_base->pi_dev = dev;
122 kprintf("Grabbing MAC.\n");
123 for (int i = 0; i < 6; i++) {
124 READBYTE((PINET_CMD_MAC + i), dev_base->MAC[i]);
126 kprintf("Grabbing IP.\n");
127 for (int i = 0; i < 4; i++) {
128 READBYTE((PINET_CMD_IP + i), dev_base->IP[i]);
131 return (struct Library *)dev;
134 static uint8_t* __attribute__((used)) expunge(void) {
135 kprintf("Cleaning up.\n");
136 FreeMem(dev_base, sizeof(struct pinet_base));
140 static void __attribute__((used)) open(struct IORequest *io, uint32_t num, uint32_t flags) {
141 struct IOSana2Req *ioreq = (struct IOSana2Req *)io;
142 int32_t ok = 0, ret = IOERR_OPENFAIL;
143 struct BufferManagement *bm;
145 kprintf("Opening net device %ld.\n", num);
146 dev_base->unit.unit_OpenCnt++;
151 if (num == 0 && dev_base->unit.unit_OpenCnt == 1) {
152 //kprintf("Trying to alloc buffer management.\n");
153 //if ((bm = (struct BufferManagement*)AllocVec(sizeof(struct BufferManagement), MEMF_CLEAR | MEMF_PUBLIC))) {
154 //kprintf("Setting up buffer copy funcs (1).\n");
155 //bm->bm_CopyToBuffer = (BOOL *)GetTagData(S2_CopyToBuff, 0, (struct TagItem *)ioreq->ios2_BufferManagement);
156 //kprintf("Setting up buffer copy funcs (2).\n");
157 //bm->bm_CopyFromBuffer = (BOOL *)GetTagData(S2_CopyFromBuff, 0, (struct TagItem *)ioreq->ios2_BufferManagement);
159 kprintf("Doing more things.\n");
160 ioreq->ios2_BufferManagement = NULL;//(VOID *)bm;
161 ioreq->ios2_Req.io_Error = 0;
162 ioreq->ios2_Req.io_Unit = (struct Unit *)&dev_base->unit;
163 ioreq->ios2_Req.io_Device = (struct Device *)dev_base->pi_dev;
165 kprintf("New list.\n");
167 NewList(&dev_base->read_list);
168 InitSemaphore(&dev_base->read_list_sem);
175 if (ret == IOERR_OPENFAIL) {
176 kprintf("Failed to open device. Already open?\n");
179 kprintf("Device opened, yay.\n");
181 ioreq->ios2_Req.io_Error = ret;
182 ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
184 kprintf("Opened device, return code: %ld\n", ret);
187 static uint8_t* __attribute__((used)) close(struct IORequest *io) {
191 uint32_t pinet_read_frame(struct IOSana2Req *ioreq) {
195 void pinet_write_frame(struct IOSana2Req *ioreq) {
199 static void __attribute__((used)) begin_io(struct IORequest *io) {
200 struct IOSana2Req *ioreq = (struct IOSana2Req *)io;
201 ULONG unit = (ULONG)ioreq->ios2_Req.io_Unit;
204 ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
205 ioreq->ios2_Req.io_Error = S2ERR_NO_ERROR;
206 ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
208 //D(("BeginIO command %ld unit %ld\n",(LONG)ioreq->ios2_Req.io_Command,unit));
213 switch( ioreq->ios2_Req.io_Command ) {
216 if (pinet_read_frame(ioreq) != 0) {
217 ioreq->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
218 ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
223 kprintf("Broadcast\n");
224 if (ioreq->ios2_DstAddr) {
225 for (int i = 0; i < ADDRFIELDSIZE; i++) {
226 ioreq->ios2_DstAddr[i] = 0xFF;
229 kprintf("Invalid ios2_DstAddr\n");
234 pinet_write_frame(ioreq);
239 ioreq->ios2_Req.io_Flags &= ~SANA2IOF_QUICK;
244 case S2_CONFIGINTERFACE: /* forward request */
247 case S2_GETSTATIONADDRESS:
248 for (int i = 0; i < ADDRFIELDSIZE; i++) {
249 ioreq->ios2_SrcAddr[i] = dev_base->MAC[i];
250 ioreq->ios2_DstAddr[i] = dev_base->MAC[i];
253 case S2_DEVICEQUERY: {
254 struct Sana2DeviceQuery *devquery;
256 devquery = ioreq->ios2_StatData;
257 devquery->DevQueryFormat = 0;
258 devquery->DeviceLevel = 0;
260 if (devquery->SizeAvailable >= 18)
261 devquery->AddrFieldSize = ADDRFIELDSIZE * 8;
262 if (devquery->SizeAvailable >= 22)
263 devquery->MTU = 1500;
264 if (devquery->SizeAvailable >= 26)
265 devquery->BPS = 1000 * 1000 * 100;
266 if (devquery->SizeAvailable >= 30)
267 devquery->HardwareType = S2WireType_Ethernet;
269 devquery->SizeSupplied = (devquery->SizeAvailable < 30) ? devquery->SizeAvailable : 30;
272 case S2_GETSPECIALSTATS: {
273 struct Sana2SpecialStatHeader *s2ssh = (struct Sana2SpecialStatHeader *)ioreq->ios2_StatData;
274 s2ssh->RecordCountSupplied = 0;
278 uint8_t cmd = ioreq->ios2_Req.io_Command;
280 kprintf("Unknown/unhandled IO command %lx\n", cmd);
281 ioreq->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
282 ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
288 if (!(ioreq->ios2_Req.io_Flags & SANA2IOF_QUICK)) {
289 ReplyMsg((struct Message *)ioreq);
291 ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
296 static uint32_t __attribute__((used)) abort_io(struct IORequest* ioreq) {
297 struct IOSana2Req* ios2 = (struct IOSana2Req*)ioreq;
299 if (!ioreq) return IOERR_NOCMD;
300 ioreq->io_Error = IOERR_ABORTED;
301 ios2->ios2_WireError = 0;
303 return IOERR_ABORTED;
306 static uint32_t device_vectors[] = {
316 const uint32_t auto_init_tables[4] = {
317 sizeof(struct Library),
318 (uint32_t)device_vectors,
320 (uint32_t)init_device