Delete the toolchain builddir after building the toolchain.
[AROS.git] / workbench / devs / networks / rtl8029 / driver.c
blobfc919d10b8307b528724e53fc9e0541c02e1f3f0
1 /*
3 Prometheus NE2000 driver.
5 Copyright (C) 2001-2004 Matay
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 MA 02111-1307, USA.
23 /// includes and defines
25 #define __NOLIBBASE__
27 #include <proto/exec.h>
28 #include <proto/expansion.h>
29 #include <proto/utility.h>
30 #include <proto/dos.h>
31 #include <proto/prometheus.h>
32 #include <proto/timer.h>
33 #include <exec/libraries.h>
34 #include <exec/resident.h>
35 #include <exec/memory.h>
36 #include <exec/interrupts.h>
37 #include <exec/errors.h>
38 #include <devices/sana2.h>
39 #include <hardware/intbits.h>
40 #include <dos/dostags.h>
42 #include <string.h>
44 #include "rev.h"
45 #include "ne2000.h"
46 #include "endian.h"
47 #include "io.h"
49 #define OK 0
51 #define TX_BUFFER 0x40
52 #define RX_BUFFER 0x46
53 #define BUFFER_END 0x80
54 #define INTMASK (INT_RXPACKET | INT_TXPACKET | INT_TXERROR)
56 /* PCI card ID's */
58 #define PCI_VENDOR_REALTEK 0x10EC
59 #define PCI_DEVICE_RTL8029 0x8029
61 // Unit flags.
63 #define UF_CONFIGURED 0x01
64 #define UF_ONLINE 0x02
65 #define UF_PROMISCUOUS 0x04
67 // Macro for registerized parameters (used in some OS functions).
69 #ifndef REG
70 #if defined(__mc68000) && !defined(__AROS__)
71 #define _REG(A, B) B __asm(#A)
72 #define REG(A, B) _REG(A, B)
73 #else
74 #define REG(A, B) B
75 #endif
76 #endif
78 // Macro for declaring local libraries bases.
80 #define USE(a) struct Library * a = dd->dd_##a;
81 #define USE_U(a) struct Library * a = ud->ud_##a;
83 // Debug on/off switch (debug off if commented).
85 //#define PDEBUG 1
87 // Macros for debug messages.
89 #ifdef PDEBUG
90 #define USE_D(a) struct Library *##a = dd->dd_##a;
91 #define USE_UD(a) struct Library *##a = ud->ud_##a;
92 #define DBG(a) FPrintf(dd->debug, a "\n")
93 #define DBG_U(a) FPrintf(ud->debug, a "\n")
94 #define DBG_T(a) FPrintf(ud->tdebug, a "\n")
95 #define DBG1(a,b) FPrintf(dd->debug, a "\n",(LONG)b)
96 #define DBG1_U(a,b) FPrintf(ud->debug, a "\n",(LONG)b)
97 #define DBG1_T(a,b) FPrintf(ud->tdebug, a "\n",(LONG)b)
98 #define DBG2(a,b,c) FPrintf(dd->debug, a "\n",(LONG)b,(LONG)c)
99 #define DBG2_U(a,b,c) FPrintf(ud->debug, a "\n",(LONG)b,(LONG)c)
100 #define DBG2_T(a,b,c) FPrintf(ud->tdebug, a "\n",(LONG)b,(LONG)c)
101 #else
102 #define USE_D(a)
103 #define USE_UD(a)
104 #define DBG(a)
105 #define DBG_U(a)
106 #define DBG_T(a)
107 #define DBG1(a,b)
108 #define DBG1_U(a,b)
109 #define DBG1_T(a,b)
110 #define DBG2(a,b,c)
111 #define DBG2_U(a,b,c)
112 #define DBG2_T(a,b,c)
113 #endif
115 // New Style Device support
117 #define NSCMD_DEVICEQUERY 0x4000
119 struct NSDeviceQueryResult
121 ULONG DevQueryFormat; /* this is type 0 */
122 ULONG SizeAvailable; /* bytes available */
123 UWORD DeviceType; /* what the device does */
124 UWORD DeviceSubType; /* depends on the main type */
125 UWORD *SupportedCommands; /* 0 terminated list of cmd's */
128 #define NSDEVTYPE_SANA2 7 /* A >=SANA2R2 networking device */
131 /// device structures
133 struct DevData
135 struct Library dd_Lib;
136 APTR dd_SegList;
137 struct Library *dd_SysBase;
138 struct Library *dd_PrometheusBase;
139 struct Library *dd_UtilityBase;
140 struct Library *dd_DOSBase;
141 struct Library *dd_TimerBase;
142 struct UnitData *dd_Units[4];
143 struct timerequest dd_Treq;
146 #ifdef PDEBUG
147 BPTR debug;
148 UBYTE dpath[128];
149 #endif
152 struct UnitData
154 struct Message ud_Message;
155 IPTR ud_Hardware;
156 struct Library *ud_SysBase;
157 struct Library *ud_PrometheusBase;
158 struct Library *ud_DOSBase;
159 struct Library *ud_TimerBase;
160 struct Interrupt *ud_Interrupt;
161 struct Task *ud_Task;
162 struct MsgPort *ud_TaskPort;
163 struct MsgPort *ud_LifeTime;
164 struct MinList ud_RxQueue;
165 struct MinList ud_TxQueue;
166 struct IOSana2Req *ud_PendingWrite;
167 APTR ud_Board;
168 ULONG ud_OpenCnt;
169 ULONG ud_GoWriteMask;
170 UWORD ud_RxBuffer[768];
171 UBYTE ud_Name[24];
172 UBYTE ud_EtherAddress[6];
173 UBYTE ud_SoftAddress[6];
174 struct Sana2DeviceStats ud_DevStats;
175 UBYTE ud_Flags;
176 UBYTE ud_NextPage;
177 BYTE ud_GoWriteBit;
178 UBYTE pad;
179 #ifdef PDEBUG
180 BPTR debug;
181 BPTR tdebug;
182 #endif
185 struct BuffFunctions
187 BOOL (*bf_CopyTo)(REG(a0, APTR), REG(a1, APTR), REG(d0, ULONG));
188 BOOL (*bf_CopyFrom)(REG(a0, APTR), REG(a1, APTR), REG(d0, ULONG));
192 /// prototypes
194 LONG DevOpen(REG(a1, struct IOSana2Req *req), REG(d0, LONG unit),
195 REG(d1, LONG flags), REG(a6, struct DevData *dd));
196 APTR DevClose(REG(a1, struct IOSana2Req *req), REG(a6, struct DevData *dd));
197 APTR DevExpunge(REG(a6, struct DevData *dd));
198 LONG DevReserved(void);
199 void DevBeginIO(REG(a1, struct IOSana2Req *req),
200 REG(a6, struct DevData *dd));
201 ULONG DevAbortIO(REG(a1, struct IOSana2Req *req),
202 REG(a6, struct DevData *dd));
204 void IoDone(struct UnitData *ud, struct IOSana2Req *req, LONG err, LONG werr);
205 LONG OpenDeviceLibraries(struct DevData *dd);
206 void CloseDeviceLibraries(struct DevData *dd);
207 LONG PrepareCookie(struct IOSana2Req *req, struct DevData *dd);
208 LONG RunTask(struct DevData *dd, struct UnitData *ud);
209 void ClearGlobalStats(struct UnitData *ud);
210 struct UnitData *OpenUnit(struct DevData *dd, LONG unit, LONG flags);
211 struct UnitData *InitializeUnit(struct DevData *dd, LONG unit);
212 void CloseUnit(struct DevData *dd, struct UnitData *ud);
213 void ExpungeUnit(struct DevData *dd, struct UnitData *ud);
215 void CmdNSDQuery(struct UnitData *ud, struct IOStdReq *req);
216 void S2DeviceQuery(struct UnitData *ud, struct IOSana2Req *req);
217 void S2GetStationAddress(struct UnitData *ud, struct IOSana2Req *req);
218 void S2ConfigInterface(struct UnitData *ud, struct IOSana2Req *req);
219 void S2Online(struct UnitData *ud, struct IOSana2Req *req);
220 void S2Offline(struct UnitData *ud, struct IOSana2Req *req);
221 void S2GetGlobalStats(struct UnitData *ud, struct IOSana2Req *req);
223 void HardwareReset(struct UnitData *ud);
224 void HardwareInit (struct UnitData *ud);
225 IPTR FindHardware(struct DevData *dd, WORD unit, struct UnitData *ud);
226 void GoOnline (struct UnitData *ud);
227 void GoOffline(struct UnitData *ud);
228 void GetHwAddress(struct UnitData *ud);
229 void WriteHwAddress(struct UnitData *ud);
230 LONG PacketReceived(struct UnitData *ud);
231 LONG RingBufferNotEmpty(struct UnitData *ud);
233 struct IOSana2Req *SearchReadRequest(struct UnitData *ud,
234 struct MinList *queue, ULONG type);
235 void UnitTask(void);
238 /// tables and constants
240 extern struct Resident romtag;
241 const UBYTE IdString[] = DEV_IDSTRING;
243 const void *FuncTable[] =
245 DevOpen,
246 DevClose,
247 DevExpunge,
248 DevReserved,
249 DevBeginIO,
250 DevAbortIO,
251 (APTR)-1
254 UWORD NSDSupported[] =
256 CMD_READ,
257 CMD_WRITE,
258 CMD_FLUSH,
259 S2_DEVICEQUERY,
260 S2_GETSTATIONADDRESS,
261 S2_CONFIGINTERFACE,
262 S2_BROADCAST,
263 S2_GETGLOBALSTATS,
264 S2_ONLINE,
265 S2_OFFLINE,
266 NSCMD_DEVICEQUERY,
272 /// DevInit()
273 // Called when the device is loaded into memory. Makes system library, initializes Library structure, opens
274 // libraries used by the device. Returns device base or NULL if init failed.
276 struct DevData *DevInit(REG(d0, ULONG num), REG(a0, void *seglist),
277 REG(a6, struct Library *sysb))
279 struct DevData *dd;
280 struct Library *SysBase = sysb;
282 if (dd = (struct DevData*)MakeLibrary(FuncTable, NULL, NULL,
283 sizeof(struct DevData), 0))
285 dd->dd_Lib.lib_Node.ln_Type = NT_DEVICE;
286 dd->dd_Lib.lib_Node.ln_Name = (TEXT *)romtag.rt_Name;
287 dd->dd_Lib.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
288 dd->dd_Lib.lib_Version = DEV_VERSION;
289 dd->dd_Lib.lib_Revision = DEV_REVISION;
290 dd->dd_Lib.lib_IdString = (TEXT *)romtag.rt_IdString;
291 dd->dd_Lib.lib_OpenCnt = 0;
292 dd->dd_SegList = seglist;
293 dd->dd_SysBase = SysBase;
294 if (OpenDeviceLibraries(dd))
296 USE_D(DOSBase)
297 WORD i;
299 for (i = 0; i < 4; i++) dd->dd_Units[i] = NULL;
301 #ifdef PDEBUG
302 strcpy(dd->dpath, "KCON:0/17/400/300/prm-rtl8029.device (main)/AUTO/CLOSE/WAIT");
303 GetVar("PrometheusDebug", dd->dpath, 128, 0);
304 dd->debug = Open(dd->dpath, MODE_NEWFILE);
305 #endif
307 DBG1("Device initialized, base at $%08lx.", dd);
308 AddDevice((struct Device*)dd);
309 return dd;
311 CloseDeviceLibraries(dd);
313 return NULL;
317 /// DevOpen()
319 LONG DevOpen(REG(a1, struct IOSana2Req *req), REG(d0, LONG unit),
320 REG(d1, LONG flags), REG(a6, struct DevData *dd))
322 USE_D(DOSBase)
323 struct UnitData *ud;
325 DBG("DevOpen() called.");
326 dd->dd_Lib.lib_OpenCnt++; // expunge protection
328 if ((unit >= 0) && (unit <= 3))
330 if (ud = OpenUnit(dd, unit, flags))
332 req->ios2_Req.io_Error = 0;
333 req->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
334 req->ios2_Req.io_Device = (struct Device*)dd;
335 req->ios2_Req.io_Unit = (struct Unit*)ud;
336 if (PrepareCookie(req, dd))
338 dd->dd_Lib.lib_Flags &= ~LIBF_DELEXP;
339 DBG("DevOpen(): device opened successfully.");
340 return 0;
342 DBG("PrepareCookie() failed.");
343 CloseUnit(dd, ud);
346 req->ios2_Req.io_Error = IOERR_OPENFAIL;
347 req->ios2_Req.io_Device = (struct Device*)-1;
348 req->ios2_Req.io_Unit = (struct Unit*)-1;
349 dd->dd_Lib.lib_OpenCnt--; /* end of expunge protection */
350 return IOERR_OPENFAIL;
354 /// DevClose()
356 APTR DevClose(REG(a1, struct IOSana2Req *req), REG(a6, struct DevData *dd))
358 USE(SysBase)
359 USE_D(DOSBase)
361 CloseUnit(dd, (struct UnitData*)req->ios2_Req.io_Unit);
363 if (req->ios2_BufferManagement) FreeMem(req->ios2_BufferManagement,
364 sizeof(struct BuffFunctions));
366 if (--dd->dd_Lib.lib_OpenCnt == 0)
368 DBG("DevClose(): open counter reached 0.");
369 if (dd->dd_Lib.lib_Flags & LIBF_DELEXP) return (DevExpunge(dd));
371 return 0;
375 /// DevExpunge()
377 APTR DevExpunge(REG(a6, struct DevData *dd))
379 USE(SysBase)
380 USE_D(DOSBase)
381 APTR seglist;
383 if (dd->dd_Lib.lib_OpenCnt)
385 dd->dd_Lib.lib_Flags |= LIBF_DELEXP;
386 return 0;
388 Remove((struct Node*)dd);
389 CloseDeviceLibraries(dd);
390 seglist = dd->dd_SegList;
391 FreeMem((APTR)dd - dd->dd_Lib.lib_NegSize,
392 (IPTR)dd->dd_Lib.lib_PosSize + (IPTR)dd->dd_Lib.lib_NegSize);
393 DBG("DevExpunge(): expunged.");
394 return seglist;
398 /// DevReserved()
400 LONG DevReserved (void)
402 return 0;
406 /// DevBeginIo()
408 void DevBeginIO(REG(a1, struct IOSana2Req *req),
409 REG(a6, struct DevData *dd))
411 USE(SysBase)
412 USE_D(DOSBase)
413 struct UnitData *ud = (struct UnitData*)req->ios2_Req.io_Unit;
414 WORD i;
416 switch(req->ios2_Req.io_Command)
418 case NSCMD_DEVICEQUERY: CmdNSDQuery(ud, (struct IOStdReq*)req); break;
419 case S2_DEVICEQUERY: S2DeviceQuery(ud, req); break;
420 case S2_GETSTATIONADDRESS: S2GetStationAddress(ud, req); break;
421 case S2_CONFIGINTERFACE: S2ConfigInterface(ud, req); break;
422 case S2_ONLINE: S2Online(ud, req); break;
423 case S2_OFFLINE: S2Offline(ud, req); break;
424 case S2_GETGLOBALSTATS: S2GetGlobalStats(ud, req); break;
426 case CMD_READ:
427 DBG1("CMD_READ [$%08lx].", (LONG)req);
428 req->ios2_Req.io_Flags &= ~IOF_QUICK;
429 PutMsg(ud->ud_TaskPort, &req->ios2_Req.io_Message);
430 break;
432 case S2_BROADCAST:
433 for (i = 0; i < 6; i++) req->ios2_DstAddr[i] = 0xFF;
434 case CMD_WRITE:
435 DBG1("CMD_WRITE [$%08lx].", (LONG)req);
436 req->ios2_Req.io_Flags &= ~IOF_QUICK;
437 PutMsg(ud->ud_TaskPort, &req->ios2_Req.io_Message);
438 break;
440 case CMD_FLUSH:
441 DBG1("CMD_FLUSH [$%08lx].", (LONG)req);
442 req->ios2_Req.io_Flags &= ~IOF_QUICK;
443 PutMsg(ud->ud_TaskPort, &req->ios2_Req.io_Message);
444 break;
446 default:
447 DBG1("DevBeginIo(): unknown command code %ld.", req->ios2_Req.io_Command);
448 IoDone(ud, req, IOERR_NOCMD, S2WERR_GENERIC_ERROR);
449 break;
451 return;
455 /// DevAbortIo()
457 ULONG DevAbortIO(REG(a1, struct IOSana2Req *req),
458 REG(a6, struct DevData *dd))
460 USE(SysBase)
461 USE_D(DOSBase)
462 LONG ret = 0;
463 struct UnitData *ud = (struct UnitData*)req->ios2_Req.io_Unit;
464 struct MinList *list;
465 struct MinNode *node;
467 DBG1("DevAbortIo: aborting $%08lx.", req);
468 switch (req->ios2_Req.io_Command)
470 case CMD_READ:
471 list = &ud->ud_RxQueue;
472 break;
474 case CMD_WRITE:
475 case S2_BROADCAST:
476 list = &ud->ud_TxQueue;
477 break;
479 default:
480 list = NULL;
482 if (list)
484 Disable();
485 for (node = list->mlh_Head; node->mln_Succ; node = node->mln_Succ)
487 if (node == (struct MinNode*)req)
489 if (((struct Message*)node)->mn_Node.ln_Type != NT_REPLYMSG)
491 Remove((struct Node*)node);
492 req->ios2_Req.io_Error = IOERR_ABORTED;
493 ReplyMsg((struct Message*)node);
494 ret = 0;
498 Enable();
500 else ret = IOERR_NOCMD;
501 return ret;
506 // AUXILIARY FUNCTIONS
508 /// IoDone(struct UnitData *ud, struct IOSana2Req *req, LONG err, LONG werr)
509 // Function ends IORequest with given error codes. Requests with IOF_QUICK cleared will be ReplyMsg()-ed.
511 void IoDone(struct UnitData *ud, struct IOSana2Req *req, LONG err, LONG werr)
513 USE_U(SysBase)
515 req->ios2_Req.io_Error = err;
516 req->ios2_WireError = werr;
517 if (!(req->ios2_Req.io_Flags & IOF_QUICK))
518 ReplyMsg(&req->ios2_Req.io_Message);
519 return;
523 /// OpenDeviceLibraries(struct DevData *dd)
525 LONG OpenDeviceLibraries(struct DevData *dd)
527 USE(SysBase)
529 if (!(dd->dd_UtilityBase = OpenLibrary("utility.library", 39))) return FALSE;
530 if (!(dd->dd_PrometheusBase = OpenLibrary("prometheus.library", 2))) return FALSE;
531 if (!(dd->dd_DOSBase = OpenLibrary("dos.library", 38))) return FALSE;
532 if (OpenDevice ("timer.device", UNIT_VBLANK, (struct IORequest*)&dd->dd_Treq, 0) == 0)
534 dd->dd_TimerBase = (struct Library*)dd->dd_Treq.tr_node.io_Device;
537 return TRUE;
541 /// CloseDeviceLibraries(struct DevData *dd)
543 void CloseDeviceLibraries(struct DevData *dd)
545 USE(SysBase)
547 if (dd->dd_DOSBase) CloseLibrary(dd->dd_DOSBase);
548 if (dd->dd_PrometheusBase) CloseLibrary(dd->dd_PrometheusBase);
549 if (dd->dd_UtilityBase) CloseLibrary(dd->dd_UtilityBase);
550 if (dd->dd_TimerBase) CloseDevice ((struct IORequest*)&dd->dd_Treq);
554 /// PrepareCookie(struct IOSana2Req *req, struct DevData *dd)
556 LONG PrepareCookie(struct IOSana2Req *req, struct DevData *dd)
558 USE(SysBase)
559 USE(UtilityBase)
560 USE_D(DOSBase)
562 if (req->ios2_BufferManagement)
564 struct BuffFunctions *bfun;
566 if (bfun = AllocMem(sizeof(struct BuffFunctions), MEMF_ANY))
568 bfun->bf_CopyFrom = (APTR)GetTagData(S2_CopyFromBuff, (IPTR)NULL,
569 (struct TagItem*)req->ios2_BufferManagement);
570 bfun->bf_CopyTo = (APTR)GetTagData(S2_CopyToBuff, (IPTR)NULL,
571 (struct TagItem*)req->ios2_BufferManagement);
573 if (bfun->bf_CopyFrom && bfun->bf_CopyTo)
575 DBG1("CopyFrom [$%08lx].", bfun->bf_CopyFrom);
576 req->ios2_BufferManagement = bfun;
577 return TRUE;
579 else FreeMem(bfun, sizeof(struct BuffFunctions));
582 return FALSE;
586 /// RunTask(struct DevData *dd, struct UnitData *ud)
588 LONG RunTask(struct DevData *dd, struct UnitData *ud)
590 USE(SysBase)
591 USE(DOSBase)
592 const struct TagItem task_tags[] =
594 {NP_Entry, (IPTR)UnitTask},
595 {NP_Name, (IPTR)ud->ud_Name},
596 {NP_Priority, 6},
597 {TAG_END, 0}
600 DBG("RunTask() called.");
602 if(ud->ud_LifeTime = CreateMsgPort())
604 if (ud->ud_Task = (struct Task*)CreateNewProc(task_tags))
606 WORD i;
608 DBG1("Task [$%08lx] started.", ud->ud_Task);
609 for (i = 0; i < 50; i++)
611 if (!(ud->ud_TaskPort = FindPort(ud->ud_Name))) Delay(1);
612 else
614 DBG("Task port detected.");
615 ud->ud_Message.mn_Node.ln_Type = NT_MESSAGE;
616 ud->ud_Message.mn_Length = sizeof(struct UnitData);
617 ud->ud_Message.mn_ReplyPort = ud->ud_LifeTime;
618 PutMsg(ud->ud_TaskPort, &ud->ud_Message);
619 return TRUE;
624 return FALSE;
628 /// KillTask(struct DevData *dd, struct UnitData *ud)
630 void KillTask(struct DevData *dd, struct UnitData *ud)
632 USE(SysBase)
633 USE_D(DOSBase)
635 Signal(ud->ud_Task, SIGBREAKF_CTRL_C);
636 WaitPort(ud->ud_LifeTime);
637 GetMsg(ud->ud_LifeTime);
638 DeleteMsgPort(ud->ud_LifeTime);
639 DBG("Task dead.");
640 return;
644 /// ClearGlobalStats()
646 void ClearGlobalStats(struct UnitData *ud)
648 USE_U(TimerBase)
650 ud->ud_DevStats.PacketsReceived = 0;
651 ud->ud_DevStats.PacketsSent = 0;
652 GetSysTime(&ud->ud_DevStats.LastStart);
653 return;
657 /// OpenUnit()
659 struct UnitData *OpenUnit(struct DevData *dd, LONG unit, LONG flags)
661 USE_D(DOSBase)
662 struct UnitData *ud = dd->dd_Units[unit];
664 DBG("OpenUnit() called.");
666 /* Eliminate 'promiscuous without exclusive' flag combination. */
668 if ((flags & SANA2OPF_PROM) && !(flags & SANA2OPF_MINE)) return NULL;
670 /* Initialize unit if opened first time. */
672 if (!ud)
674 if (!(ud = InitializeUnit(dd, unit))) return NULL;
677 /* Check exclusive flag - reject if already opened by someone else. */
679 if ((flags & SANA2OPF_MINE) && ud->ud_OpenCnt) return NULL;
681 /* Set promiscuous flag if requested - we konw here MINE was requested too, and noone else has opened */
682 /* the unit. So we can just set it if requested. */
684 if (flags & SANA2OPF_PROM) ud->ud_Flags |= UF_PROMISCUOUS;
686 /* OK, increment open counter and exit with success. */
688 ud->ud_OpenCnt++;
689 DBG2("%s opened [%ld].", ud->ud_Name, ud->ud_OpenCnt);
690 return ud;
694 /// CloseUnit()
696 void CloseUnit(struct DevData *dd, struct UnitData *ud)
698 USE_D(DOSBase)
700 DBG1("%s closed.", ud->ud_Name);
701 if (!(--ud->ud_OpenCnt)) ExpungeUnit(dd, ud);
702 return;
706 /// InitializeUnit()
708 struct UnitData *InitializeUnit(struct DevData *dd, LONG unit)
710 USE(SysBase)
711 #ifdef PDEBUG
712 USE(DOSBase)
713 #endif
714 struct UnitData *ud;
715 WORD i;
717 DBG("InitializeUnit() called.");
718 if (ud = AllocMem(sizeof(struct UnitData), MEMF_PUBLIC | MEMF_CLEAR))
720 if (ud->ud_Hardware = FindHardware(dd, unit, ud))
722 #ifdef PDEBUG
723 ud->debug = dd->debug;
724 #endif
726 for (i = 5; i >= 0; i--)
728 ud->ud_SoftAddress[i] = 0x00;
729 ud->ud_EtherAddress[i] = 0x00;
731 ud->ud_SysBase = dd->dd_SysBase;
732 ud->ud_PrometheusBase = dd->dd_PrometheusBase;
733 ud->ud_DOSBase = dd->dd_DOSBase;
734 ud->ud_TimerBase = dd->dd_TimerBase;
735 strcpy(ud->ud_Name, "prm-rtl8029.device (x)");
736 ud->ud_Name[20] = '0' + unit;
737 ud->ud_RxQueue.mlh_Head = (struct MinNode*)&ud->ud_RxQueue.mlh_Tail;
738 ud->ud_RxQueue.mlh_Tail = NULL;
739 ud->ud_RxQueue.mlh_TailPred = (struct MinNode*)&ud->ud_RxQueue.mlh_Head;
740 ud->ud_TxQueue.mlh_Head = (struct MinNode*)&ud->ud_TxQueue.mlh_Tail;
741 ud->ud_TxQueue.mlh_Tail = NULL;
742 ud->ud_TxQueue.mlh_TailPred = (struct MinNode*)&ud->ud_TxQueue.mlh_Head;
743 ud->ud_NextPage = RX_BUFFER;
744 HardwareReset(ud);
745 HardwareInit(ud);
746 GetHwAddress(ud);
747 if (RunTask(dd, ud))
749 dd->dd_Units[unit] = ud;
750 DBG1("%s initialized.", (LONG)ud->ud_Name);
751 return ud;
755 ExpungeUnit(dd, ud);
756 return NULL;
760 /// ExpungeUnit()
762 void ExpungeUnit(struct DevData *dd, struct UnitData *ud)
764 USE(SysBase)
765 USE_D(DOSBase)
766 WORD unit;
768 if (ud)
770 unit = ud->ud_Name[20] - '0';
771 if (ud->ud_Flags & UF_ONLINE) GoOffline(ud);
772 if (ud->ud_Task) KillTask(dd, ud);
773 FreeMem(ud, sizeof(struct UnitData));
774 dd->dd_Units[unit] = NULL;
775 DBG1("%s expunged.", ud->ud_Name);
777 return;
782 // IMMEDIATE DEVICE COMMANDS
784 /// S2DeviceQuery()
786 void S2DeviceQuery(struct UnitData *ud, struct IOSana2Req *req)
788 USE_UD(DOSBase)
789 struct Sana2DeviceQuery *query = req->ios2_StatData;
791 DBG_U("S2_DEVICEQUERY.");
792 if (query)
794 if (query->SizeAvailable >= sizeof(struct Sana2DeviceQuery))
796 query->SizeSupplied = sizeof(struct Sana2DeviceQuery);
797 query->DevQueryFormat = 0;
798 query->DeviceLevel = 0;
799 query->AddrFieldSize = 48;
800 query->MTU = 1500;
801 query->BPS = 10000000;
802 query->HardwareType = S2WireType_Ethernet;
803 IoDone(ud, req, OK, OK);
805 else IoDone(ud, req, S2ERR_BAD_ARGUMENT, S2WERR_GENERIC_ERROR);
807 else IoDone(ud, req, S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
808 return;
812 /// S2GetStationAddress()
814 void S2GetStationAddress(struct UnitData *ud, struct IOSana2Req *req)
816 USE_U(SysBase)
817 USE_UD(DOSBase)
819 DBG_U("S2_GETSTATIONADDRESS.");
820 CopyMem(ud->ud_SoftAddress, req->ios2_SrcAddr, 6);
821 CopyMem(ud->ud_EtherAddress, req->ios2_DstAddr, 6);
822 IoDone(ud, req, OK, OK);
823 return;
827 /// S2Online()
829 void S2Online(struct UnitData *ud, struct IOSana2Req *req)
831 USE_UD(DOSBase)
833 DBG_U("S2_ONLINE.");
834 ClearGlobalStats(ud);
835 if (!(ud->ud_Flags & UF_ONLINE))
837 GoOnline(ud);
838 ud->ud_Flags |= UF_ONLINE;
839 IoDone(ud, req, OK, OK);
841 else IoDone(ud, req, S2ERR_BAD_STATE, S2WERR_UNIT_ONLINE);
842 return;
846 /// S2ConfigInterface()
848 BOOL address_has_all(UBYTE *addr, UBYTE num)
850 WORD i;
852 for (i = 5; i >= 0; i--)
854 if (addr[i] != num) return FALSE;
856 return TRUE;
860 void S2ConfigInterface(struct UnitData *ud, struct IOSana2Req *req)
862 USE_U(SysBase)
863 USE_UD(DOSBase)
865 DBG_U("S2_CONFIGINTERFACE.");
866 ClearGlobalStats(ud);
867 if (ud->ud_Flags & UF_CONFIGURED)
869 IoDone(ud, req, S2ERR_BAD_STATE, S2WERR_IS_CONFIGURED);
871 else if (address_has_all(req->ios2_SrcAddr, 0x00) ||
872 address_has_all(req->ios2_SrcAddr, 0xFF))
874 IoDone(ud, req, S2ERR_BAD_ADDRESS, S2WERR_SRC_ADDRESS);
876 else
878 HardwareInit(ud);
879 CopyMem(req->ios2_SrcAddr, ud->ud_SoftAddress, 6);
880 WriteHwAddress(ud);
881 if (!(ud->ud_Flags & UF_ONLINE))
883 GoOnline(ud);
884 ud->ud_Flags |= UF_ONLINE;
886 ud->ud_Flags |= UF_CONFIGURED;
887 IoDone(ud, req, OK, OK);
889 return;
893 /// S2Offline()
895 void S2Offline(struct UnitData *ud, struct IOSana2Req *req)
897 USE_UD(DOSBase)
899 DBG_U("S2_OFFLINE.");
900 if (ud->ud_Flags & UF_ONLINE)
902 GoOffline(ud);
903 ud->ud_Flags &= ~UF_ONLINE;
904 IoDone(ud, req, OK, OK);
906 else IoDone(ud, req, S2ERR_BAD_STATE, S2WERR_UNIT_OFFLINE);
907 return;
911 /// S2GetGlobalStats()
913 void S2GetGlobalStats(struct UnitData *ud, struct IOSana2Req *req)
915 USE_U(SysBase)
917 if (req->ios2_StatData)
919 CopyMem(&ud->ud_DevStats, req->ios2_StatData, sizeof(struct Sana2DeviceStats));
920 IoDone(ud, req, OK, OK);
922 else IoDone(ud, req, S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
926 /// CmdNSDQuery()
928 void CmdNSDQuery(struct UnitData *ud, struct IOStdReq *req)
930 USE_U(SysBase)
931 USE_UD(DOSBase)
932 struct NSDeviceQueryResult *qdata;
933 LONG error = OK;
935 DBG_U("NSCMD_DEVICEQUERY.");
936 if (req->io_Length >= sizeof(struct NSDeviceQueryResult))
938 if (qdata = (struct NSDeviceQueryResult*)req->io_Data)
940 if ((qdata->DevQueryFormat == 0) && (qdata->SizeAvailable == 0))
942 qdata->SizeAvailable = sizeof(struct NSDeviceQueryResult);
943 qdata->DeviceType = NSDEVTYPE_SANA2;
944 qdata->DeviceSubType = 0;
945 qdata->SupportedCommands = NSDSupported;
946 req->io_Actual = sizeof(struct NSDeviceQueryResult);
948 else error = IOERR_BADLENGTH;
950 else error = IOERR_BADADDRESS;
952 else error = IOERR_BADLENGTH;
954 /* I don't use IoDone() here, because it writes to ios2_WireError */
955 /* but this request can be simple IOStdReq one. */
957 req->io_Error = error;
958 if (!(req->io_Flags & IOF_QUICK)) ReplyMsg(&req->io_Message);
959 return;
964 // HARDWARE ACCESS FUNCTIONS
966 /// IntCode()
968 LONG IntCode(REG(a1, struct UnitData *ud))
970 USE_U(SysBase)
971 UBYTE intstatus;
972 struct IOSana2Req *req;
973 LONG my_int = 0;
975 while (intstatus = (BYTEIN(ud->ud_Hardware + NE2000_INT_STATUS)
976 & INTMASK))
978 if (intstatus & INT_TXERROR)
980 BYTEOUT(ud->ud_Hardware + NE2000_INT_STATUS, INT_TXERROR);
981 req = ud->ud_PendingWrite;
982 IoDone(ud, req, S2ERR_TX_FAILURE, S2WERR_TOO_MANY_RETIRES);
983 Signal(ud->ud_Task, ud->ud_GoWriteMask);
984 my_int = 1;
987 if (intstatus & INT_TXPACKET)
989 BYTEOUT(ud->ud_Hardware + NE2000_INT_STATUS, INT_TXPACKET);
990 req = ud->ud_PendingWrite;
991 ud->ud_DevStats.PacketsSent++;
992 IoDone(ud, req, OK, OK);
993 Signal(ud->ud_Task, ud->ud_GoWriteMask);
994 my_int = 1;
997 if (intstatus & INT_RXPACKET)
999 ULONG offset, len;
1000 UWORD mask = 0xFFFF;
1001 WORD i;
1003 while (RingBufferNotEmpty(ud))
1005 BYTEOUT(ud->ud_Hardware + NE2000_INT_STATUS, INT_RXPACKET);
1006 len = PacketReceived(ud);
1007 if (req = SearchReadRequest(ud, &ud->ud_RxQueue,
1008 BEWord(ud->ud_RxBuffer[6])))
1010 if (req->ios2_Req.io_Flags & SANA2IOF_RAW) offset = 0;
1011 else offset = 7;
1012 ((struct BuffFunctions*)req->ios2_BufferManagement)->
1013 bf_CopyTo(req->ios2_Data, &ud->ud_RxBuffer[offset],
1014 len - (offset << 1));
1015 CopyMem(&ud->ud_RxBuffer[0], req->ios2_DstAddr, 6);
1016 CopyMem(&ud->ud_RxBuffer[3], req->ios2_SrcAddr, 6);
1017 req->ios2_DataLength = len - (offset << 1);
1018 for (i = 2; i >= 0; i--) mask &= ud->ud_RxBuffer[i];
1019 if (mask == 0xFFFF)
1020 req->ios2_Req.io_Flags |= SANA2IOF_BCAST;
1021 ud->ud_DevStats.PacketsReceived++;
1022 IoDone(ud, req, OK, OK);
1025 my_int = 1;
1028 return my_int;
1032 /// InstallInterrupt()
1034 LONG InstallInterrupt(struct UnitData *ud)
1036 USE_U(SysBase)
1037 USE_U(PrometheusBase)
1038 struct Interrupt *intr;
1040 if (intr = AllocMem(sizeof(struct Interrupt), MEMF_PUBLIC | MEMF_CLEAR))
1042 intr->is_Node.ln_Type = NT_INTERRUPT;
1043 intr->is_Node.ln_Name = ud->ud_Name;
1044 intr->is_Data = ud;
1045 intr->is_Code = (APTR)IntCode;
1046 Prm_AddIntServer(ud->ud_Board, intr);
1047 ud->ud_Interrupt = intr;
1048 return TRUE;
1050 return FALSE;
1054 /// RemoveInterrupt()
1056 void RemoveInterrupt(struct UnitData *ud)
1058 USE_U(SysBase)
1059 USE_U(PrometheusBase)
1061 Prm_RemIntServer(ud->ud_Board, ud->ud_Interrupt);
1062 FreeMem(ud->ud_Interrupt, sizeof(struct Interrupt));
1063 return;
1067 /// FindHardware()
1069 IPTR FindHardware(struct DevData *dd, WORD unit, struct UnitData *ud)
1071 USE(PrometheusBase)
1072 WORD u = unit;
1073 APTR board = NULL;
1074 IPTR hwbase;
1076 while (u-- >= 0)
1078 board = Prm_FindBoardTags(board,
1079 PRM_Vendor, PCI_VENDOR_REALTEK,
1080 PRM_Device, PCI_DEVICE_RTL8029,
1081 TAG_END);
1082 if (!board) break;
1085 if (board)
1087 ud->ud_Board = board;
1088 Prm_GetBoardAttrsTags(board,
1089 PRM_MemoryAddr0, (IPTR)&hwbase,
1090 TAG_END);
1091 Prm_SetBoardAttrsTags(board,
1092 PRM_BoardOwner, (IPTR)dd,
1093 TAG_END);
1094 return hwbase;
1096 return 0;
1100 /// HardwareInit()
1102 void HardwareInit (struct UnitData *ud)
1104 IPTR hw = ud->ud_Hardware;
1106 BYTEOUT(hw + NE2000_COMMAND, 0x21);
1107 BYTEOUT(hw + NE2000_DATA_CONFIG,
1108 DTCFG_FIFO_8 | DTCFG_WIDE | DTCFG_LOOPSEL);
1109 BYTEOUT(hw + NE2000_DMA_COUNTER0, 0);
1110 BYTEOUT(hw + NE2000_DMA_COUNTER1, 0);
1111 BYTEOUT(hw + NE2000_TX_CONFIG, 0x02);
1112 BYTEOUT(hw + NE2000_PAGE_START, RX_BUFFER);
1113 BYTEOUT(hw + NE2000_PAGE_STOP, BUFFER_END);
1114 BYTEOUT(hw + NE2000_BOUNDARY, BUFFER_END - 1);
1115 BYTEOUT(hw + NE2000_INT_STATUS, 0xFF);
1116 BYTEOUT(hw + NE2000_INT_MASK, 0x00);
1117 BYTEOUT(hw + NE2000_COMMAND, 0x61);
1118 BYTEOUT(hw + NE2000_CURRENT_PAGE, RX_BUFFER);
1119 BYTEOUT(hw + NE2000_COMMAND, 0x21);
1120 return;
1124 /// HardwareReset()
1126 void HardwareReset (struct UnitData *ud)
1128 USE_U(DOSBase)
1129 IPTR hw = ud->ud_Hardware;
1130 UBYTE trash;
1132 WORDOUT(hw + NE2000_RESET_PORT, trash);
1133 Delay(1);
1134 trash = WORDIN(hw + NE2000_RESET_PORT);
1135 HardwareInit(ud);
1136 return;
1140 /// GoOnline()
1142 void GoOnline (struct UnitData *ud)
1144 IPTR hw = ud->ud_Hardware;
1146 HardwareReset(ud);
1147 WriteHwAddress(ud);
1148 InstallInterrupt(ud);
1149 BYTEOUT(hw + NE2000_COMMAND, 0x22);
1150 BYTEOUT(hw + NE2000_TX_CONFIG, 0x00);
1151 BYTEOUT(hw + NE2000_RX_CONFIG, RXCFG_BCAST | RXCFG_MCAST |
1152 ((ud->ud_Flags & UF_PROMISCUOUS) ? RXCFG_PROM : 0));
1153 BYTEOUT(hw + NE2000_INT_STATUS, 0xFF);
1154 BYTEOUT(hw + NE2000_INT_MASK, INTMASK);
1156 return;
1160 /// GoOffline()
1162 void GoOffline(struct UnitData *ud)
1164 IPTR hw = ud->ud_Hardware;
1166 BYTEOUT(hw + NE2000_COMMAND, 0x21);
1167 BYTEOUT(hw + NE2000_TX_CONFIG, 0x02);
1168 BYTEOUT(hw + NE2000_RX_CONFIG, 0x20);
1169 BYTEOUT(hw + NE2000_INT_STATUS, 0xFF);
1170 BYTEOUT(hw + NE2000_INT_MASK, 0);
1171 RemoveInterrupt(ud);
1172 return;
1176 /// BoardShutdown()
1178 void BoardShutdown(struct UnitData *ud)
1180 IPTR hw = ud->ud_Hardware;
1182 GoOffline(ud);
1183 BYTEOUT(hw + NE2000_INT_MASK, 0);
1184 BYTEOUT(hw + NE2000_INT_STATUS, 0xFF);
1185 return;
1189 /// GetPacketHeader()
1191 ULONG GetPacketHeader(IPTR ne, UBYTE page)
1193 ULONG hdr;
1195 BYTEOUT(ne + NE2000_DMA_COUNTER0, 4);
1196 BYTEOUT(ne + NE2000_DMA_COUNTER1, 0);
1197 BYTEOUT(ne + NE2000_DMA_START_ADDR0, 0);
1198 BYTEOUT(ne + NE2000_DMA_START_ADDR1, page);
1199 BYTEOUT(ne + NE2000_COMMAND,
1200 COMMAND_PAGE0 | COMMAND_START | COMMAND_READ);
1201 hdr = LEWORDIN(ne + NE2000_DMA_PORT);
1202 hdr |= LEWORDIN(ne + NE2000_DMA_PORT) << 16;
1203 return hdr;
1207 /// GetPacket()
1209 /*GetPacket(volatile struct Ne2000 *ne, UBYTE startpage, UWORD len, UWORD *buffer)*/
1210 VOID GetPacket(IPTR ne, UBYTE startpage, UWORD len, UWORD *buffer)
1212 UWORD count;
1214 BYTEOUT(ne + NE2000_DMA_COUNTER0, len & 0xFF);
1215 BYTEOUT(ne + NE2000_DMA_COUNTER1, len >> 8);
1216 BYTEOUT(ne + NE2000_DMA_START_ADDR0, 4);
1217 BYTEOUT(ne + NE2000_DMA_START_ADDR1, startpage);
1218 BYTEOUT(ne + NE2000_COMMAND, COMMAND_PAGE0 | COMMAND_START | COMMAND_READ);
1220 for (count = (len + 1) >> 1; count; count--)
1222 *buffer++ = WORDIN(ne + NE2000_DMA_PORT);
1224 return;
1228 /// PacketReceived()
1230 LONG PacketReceived(struct UnitData *ud)
1232 ULONG header, len;
1234 header = GetPacketHeader(ud->ud_Hardware, ud->ud_NextPage);
1235 len = header >> 16;
1236 GetPacket(ud->ud_Hardware, ud->ud_NextPage, len, (UWORD*)ud->ud_RxBuffer);
1237 BYTEOUT(ud->ud_Hardware + NE2000_BOUNDARY, ud->ud_NextPage);
1238 ud->ud_NextPage = (header >> 8) & 0xFF;
1239 BYTEOUT(ud->ud_Hardware + NE2000_INT_STATUS, INT_RXPACKET);
1240 return len;
1244 /// BufferOverflow()
1246 void BufferOverflow(struct UnitData *ud)
1248 struct Library *DOSBase = ud->ud_DOSBase;
1249 IPTR hw = ud->ud_Hardware;
1250 UBYTE txp, resent = FALSE, intstatus;
1252 txp = BYTEIN(hw + NE2000_COMMAND) & COMMAND_TXP;
1253 BYTEOUT(hw + NE2000_COMMAND, COMMAND_PAGE0 | COMMAND_ABORT | COMMAND_STOP);
1254 Delay(1);
1255 BYTEOUT(hw + NE2000_DMA_COUNTER0, 0);
1256 BYTEOUT(hw + NE2000_DMA_COUNTER1, 0);
1258 if (txp)
1260 intstatus = BYTEIN(hw + NE2000_INT_STATUS);
1261 if (!(intstatus & (INT_TXPACKET | INT_TXERROR))) resent = TRUE;
1264 BYTEOUT(hw + NE2000_TX_CONFIG, TXCFG_LOOP_INT);
1265 BYTEOUT(hw + NE2000_COMMAND,
1266 COMMAND_PAGE1 | COMMAND_ABORT | COMMAND_START);
1267 BYTEOUT(hw + NE2000_CURRENT_PAGE, RX_BUFFER);
1268 BYTEOUT(hw + NE2000_COMMAND,
1269 COMMAND_PAGE0 | COMMAND_ABORT | COMMAND_START);
1270 BYTEOUT(hw + NE2000_BOUNDARY, BUFFER_END - 1);
1271 ud->ud_NextPage = RX_BUFFER;
1273 BYTEOUT(hw + NE2000_TX_CONFIG, TXCFG_LOOP_NONE);
1274 if (resent) BYTEOUT(hw + NE2000_COMMAND, COMMAND_PAGE0 | COMMAND_START |
1275 COMMAND_ABORT | COMMAND_TXP);
1276 BYTEOUT(hw + NE2000_INT_STATUS, INT_OVERFLOW);
1278 return;
1282 /// SendPacket()
1284 void SendPacket(struct UnitData *ud, struct IOSana2Req *req)
1286 USE_U(SysBase)
1287 USE_UD(DOSBase)
1288 IPTR hw = ud->ud_Hardware;
1289 UBYTE ethbuffer[1536], *datapointer;
1290 UWORD *ethdata = (UWORD*)ethbuffer;
1291 ULONG data_len = req->ios2_DataLength;
1292 UWORD cycles;
1294 /* If not raw packets, fill in Dst, Src and Type fields of Ethernet frame. 'datapointer' is a variable */
1295 /* holding address of data to copy from network stack. If packet is raw, datapointer points to start */
1296 /* of ethbuffer, otherwise points to ef_Data field (first byte after Ethernet header. */
1298 if (!(req->ios2_Req.io_Flags & SANA2IOF_RAW))
1300 struct EthFrame *ef = (struct EthFrame*)ethbuffer;
1302 CopyMem(req->ios2_DstAddr, ef->ef_DestAddr, 6);
1303 CopyMem(ud->ud_EtherAddress, ef->ef_SrcAddr, 6);
1304 ef->ef_Type = MakeBEWord(req->ios2_PacketType);
1305 datapointer = ef->ef_Data;
1307 else datapointer = ethbuffer;
1309 /* Copy data from network stack using supplied CopyFrom() function. */
1311 ((struct BuffFunctions*)req->ios2_BufferManagement)->bf_CopyFrom(
1312 datapointer, req->ios2_Data, data_len);
1314 /* Now we need length of data to send to hardware. IORequest ios2_DataLength does not include header */
1315 /* length if packet is not RAW. So we should add it. */
1317 if (!(req->ios2_Req.io_Flags & SANA2IOF_RAW)) data_len += 14;
1319 /* Packet sent to Ethernet hardware should be at least 60 bytes long (4 bytes of CRC will be appended */
1320 /* by hardware giving 64 bytes). If our packet is shorter we should extend it with spaces. */
1322 while (data_len < 60) ethbuffer[data_len++] = ' ';
1324 /* Now the packet is ready to send it to NIC buffer. It is done by Remote Write DMA command. Firstly */
1325 /* write address and counter should be initialized, then command register. */
1327 Disable();
1328 BYTEOUT(hw + NE2000_DMA_COUNTER0, data_len & 0xFF);
1329 BYTEOUT(hw + NE2000_DMA_COUNTER1, data_len >> 8);
1330 BYTEOUT(hw + NE2000_DMA_START_ADDR0, 0);
1331 BYTEOUT(hw + NE2000_DMA_START_ADDR1, TX_BUFFER);
1332 BYTEOUT(hw + NE2000_COMMAND,
1333 COMMAND_PAGE0 | COMMAND_START | COMMAND_WRITE);
1335 /* Now we can send packet data to DMAPort word by word. */
1337 for (cycles = (data_len + 1) >> 1; cycles; cycles--)
1338 WORDOUT(hw + NE2000_DMA_PORT, *ethdata++);
1340 /* Send packet to the wire. Register setup first. */
1342 BYTEOUT(hw + NE2000_TX_PAGE_START, TX_BUFFER);
1343 BYTEOUT(hw + NE2000_TX_COUNTER0, data_len & 0xFF);
1344 BYTEOUT(hw + NE2000_TX_COUNTER1, data_len >> 8);
1346 /* Three, two, one, go! */
1348 BYTEOUT(hw + NE2000_COMMAND,
1349 COMMAND_PAGE0 | COMMAND_START | COMMAND_ABORT | COMMAND_TXP);
1350 Enable();
1352 /* OK. Packet was sent (successfully or not). Hardware will respond with TXPACKET or TXERROR interrupt */
1353 /* then we will be able to reply IORequest in the interrupt server. */
1355 DBG_T("Packet sent.");
1356 return;
1360 /// GetHwAddress()
1362 void GetHwAddress(struct UnitData *ud)
1364 USE_UD(DOSBase)
1365 IPTR hw = ud->ud_Hardware;
1366 WORD i;
1368 BYTEOUT(hw + NE2000_DMA_COUNTER0, 6);
1369 BYTEOUT(hw + NE2000_DMA_COUNTER1, 0);
1370 BYTEOUT(hw + NE2000_DMA_START_ADDR0, 0);
1371 BYTEOUT(hw + NE2000_DMA_START_ADDR1, 0);
1372 BYTEOUT(hw + NE2000_COMMAND, COMMAND_READ);
1373 for (i = 0; i < 6; i++)
1374 ud->ud_EtherAddress[i] = WORDIN(hw + NE2000_DMA_PORT);
1376 #ifdef PDEBUG
1377 DBG_U("\thardware address (read):");
1378 for (i = 0; i < 6; i++) DBG1_U("\t%02lx", ud->ud_EtherAddress[i]);
1379 #endif
1381 return;
1385 /// WriteHwAddress()
1387 void WriteHwAddress(struct UnitData *ud)
1389 USE_UD(DOSBase)
1390 IPTR hw = ud->ud_Hardware;
1391 WORD i;
1393 #ifdef PDEBUG
1394 DBG_U("\thardware address (write):");
1395 for (i = 0; i < 6; i++) DBG1_U("\t%02lx", ud->ud_SoftAddress[i]);
1396 #endif
1398 BYTEOUT(hw + NE2000_COMMAND,
1399 COMMAND_PAGE1 | COMMAND_ABORT | COMMAND_STOP);
1400 for (i = 0; i < 6; i++)
1402 BYTEOUT(hw + NE2000_PHYSICAL_ADDR0 + i, ud->ud_SoftAddress[i]);
1404 BYTEOUT(hw + NE2000_COMMAND,
1405 COMMAND_PAGE0 | COMMAND_ABORT | COMMAND_STOP);
1406 return;
1410 /// RingBufferNotEmpty()
1412 LONG RingBufferNotEmpty(struct UnitData *ud)
1414 UBYTE current;
1415 IPTR hw = ud->ud_Hardware;
1417 BYTEOUT(hw + NE2000_COMMAND,
1418 COMMAND_PAGE1 | COMMAND_ABORT | COMMAND_START);
1419 current = BYTEIN(hw + NE2000_CURRENT_PAGE);
1420 BYTEOUT(hw + NE2000_COMMAND,
1421 COMMAND_PAGE0 | COMMAND_ABORT | COMMAND_START);
1423 if (ud->ud_NextPage == current) return FALSE;
1424 else return TRUE;
1429 // SUBTASK CODE
1431 /// SearchReadRequest()
1433 struct IOSana2Req *SearchReadRequest(struct UnitData *ud,
1434 struct MinList *queue, ULONG type)
1436 struct Library *SysBase = ud->ud_SysBase;
1437 struct IOSana2Req *req, *found = NULL /*, *x*/ ;
1439 for (req = (struct IOSana2Req*)queue->mlh_Head;
1440 req->ios2_Req.io_Message.mn_Node.ln_Succ;
1441 req = (struct IOSana2Req*)req->ios2_Req.io_Message.mn_Node.ln_Succ)
1443 if (req->ios2_PacketType == type)
1445 Remove((struct Node*)req);
1446 found = req;
1447 break;
1450 return found;
1454 /// FlushQueues()
1456 void FlushQueues(struct UnitData *ud)
1458 USE_U(SysBase)
1459 USE_UD(DOSBase)
1460 struct IOSana2Req *xreq;
1462 for (;;)
1464 Disable();
1465 xreq = (struct IOSana2Req*)RemHead((struct List*)&ud->ud_RxQueue);
1466 Enable();
1467 if (!xreq) break;
1468 DBG1_T("<- READ [$08%lx] [F].", xreq);
1469 IoDone(ud, xreq, IOERR_ABORTED, S2WERR_GENERIC_ERROR);
1472 for (;;)
1474 Disable();
1475 xreq = (struct IOSana2Req*)RemHead((struct List*)&ud->ud_TxQueue);
1476 Enable();
1477 if (!xreq) break;
1478 DBG1_T("<- WRITE [$08%lx] [F].", xreq);
1479 IoDone(ud, xreq, IOERR_ABORTED, S2WERR_GENERIC_ERROR);
1481 return;
1485 /// MainLoop()
1487 void MainLoop(struct UnitData *ud, struct MsgPort *port)
1489 USE_U(SysBase)
1490 USE_UD(DOSBase)
1491 ULONG signals, sigmask;
1492 struct IOSana2Req *req;
1494 #ifdef PDEBUG
1495 UBYTE wname[60], *ptr;
1497 ptr = strcpy(wname, "CON:400/17/400/300/");
1498 ptr = strcpy(ptr, ud->ud_Name);
1499 strcpy(ptr,"/AUTO/CLOSE/WAIT");
1500 ud->tdebug = Open(wname, MODE_NEWFILE);
1501 #endif
1503 sigmask = 1 << port->mp_SigBit;
1504 for (;;)
1506 DBG_T("Waiting...");
1507 signals = Wait(SIGBREAKF_CTRL_C | sigmask | ud->ud_GoWriteMask);
1509 if (signals & ud->ud_GoWriteMask)
1511 DBG_T("GoWrite");
1512 Disable();
1513 req = (struct IOSana2Req*)RemHead((struct List*)&ud->ud_TxQueue);
1514 Enable();
1515 ud->ud_PendingWrite = req;
1516 if (req) SendPacket(ud, req);
1519 if (signals & SIGBREAKF_CTRL_C)
1521 DBG1_T("TASK: %s task killed.", ud->ud_Name);
1522 return;
1525 if (signals & sigmask)
1527 struct IOSana2Req *req;
1529 DBG_T("port");
1530 while (req = (struct IOSana2Req*)GetMsg(port))
1532 switch (req->ios2_Req.io_Command)
1534 case CMD_READ:
1535 DBG1_T("-> READ [$%08lx].", req);
1536 Disable();
1537 AddTail((struct List*)&ud->ud_RxQueue, (struct Node*)req);
1538 Enable();
1539 break;
1541 case S2_BROADCAST:
1542 case CMD_WRITE:
1543 DBG1_T("-> WRITE [$%08lx].", req);
1544 if (ud->ud_PendingWrite)
1546 Disable();
1547 AddTail((struct List*)&ud->ud_TxQueue, (struct Node*)req);
1548 Enable();
1550 else
1552 ud->ud_PendingWrite = req;
1553 SendPacket(ud, req);
1554 DBG_T("Packet sent 2.");
1556 break;
1558 case CMD_FLUSH:
1559 DBG1_T("-> FLUSH [$%08lx].", req);
1560 FlushQueues(ud);
1561 DBG1_T("<- FLUSH [$%08lx].", req);
1562 IoDone(ud, req, OK, OK);
1563 break;
1565 default:
1566 DBG2_T("-> Unknown ($%lx) [$%08lx].", req->ios2_Req.io_Command, req);
1574 /// UnitTask()
1576 void UnitTask(void)
1578 struct Library *SysBase = *(struct Library**)4;
1579 struct Task *task;
1580 struct MsgPort *port;
1581 struct UnitData *ud;
1583 #ifdef PDEBUG
1584 struct Library *DOSBase;
1585 #endif
1587 task = FindTask(NULL);
1588 if (port = CreateMsgPort())
1590 port->mp_Node.ln_Name = task->tc_Node.ln_Name;
1591 port->mp_Node.ln_Pri = 20;
1592 AddPort(port);
1593 WaitPort(port);
1594 RemPort(port);
1595 ud = (struct UnitData*)GetMsg(port);
1596 if ((ud->ud_GoWriteBit = AllocSignal(-1)) != -1)
1598 ud->ud_GoWriteMask = 1 << ud->ud_GoWriteBit;
1599 MainLoop(ud, port);
1600 FreeSignal(ud->ud_GoWriteBit);
1602 DeleteMsgPort(port);
1603 Forbid();
1604 ReplyMsg(&ud->ud_Message);
1606 return;