revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / networks / rtl8029 / driver.c
blobfc00577fdb4739296b4d096510eab4a7a42224f3
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 #ifdef __AROS__
28 #include <aros/asmcall.h>
29 #include <aros/libcall.h>
30 #else
31 #define AROS_LIBFUNC_INIT
32 #define AROS_LIBFUNC_EXIT
33 #define AROS_INTFUNC_INIT
34 #define AROS_INTFUNC_EXIT
35 #endif
37 #include <proto/exec.h>
38 #include <proto/expansion.h>
39 #include <proto/utility.h>
40 #include <proto/dos.h>
41 #include <proto/prometheus.h>
42 #include <proto/timer.h>
43 #include <exec/libraries.h>
44 #include <exec/resident.h>
45 #include <exec/memory.h>
46 #include <exec/interrupts.h>
47 #include <exec/errors.h>
48 #include <devices/sana2.h>
49 #include <hardware/intbits.h>
50 #include <dos/dostags.h>
52 #include <string.h>
54 #include "rev.h"
55 #include "ne2000.h"
56 #include "endian.h"
57 #include "io.h"
59 #define OK 0
61 #define TX_BUFFER 0x40
62 #define RX_BUFFER 0x46
63 #define BUFFER_END 0x80
64 #define INTMASK (INT_RXPACKET | INT_TXPACKET | INT_TXERROR)
66 /* PCI card IDs */
68 #define PCI_VENDOR_REALTEK 0x10EC
69 #define PCI_DEVICE_RTL8029 0x8029
71 // Unit flags.
73 #define UF_CONFIGURED 0x01
74 #define UF_ONLINE 0x02
75 #define UF_PROMISCUOUS 0x04
77 // Macro for registerized parameters (used in some OS functions).
79 #ifndef REG
80 #if defined(__mc68000) && !defined(__AROS__)
81 #define _REG(A, B) B __asm(#A)
82 #define REG(A, B) _REG(A, B)
83 #else
84 #define REG(A, B) B
85 #endif
86 #endif
88 // Macro for declaring local libraries bases.
90 #define USE(a) struct Library * a = dd->dd_##a;
91 #define USE_U(a) struct Library * a = ud->ud_##a;
93 // Debug on/off switch (debug off if commented).
95 //#define PDEBUG 1
97 // Macros for debug messages.
99 #ifdef PDEBUG
100 #define USE_D(a) struct Library *##a = dd->dd_##a;
101 #define USE_UD(a) struct Library *##a = ud->ud_##a;
102 #define DBG(a) FPrintf(dd->debug, a "\n")
103 #define DBG_U(a) FPrintf(ud->debug, a "\n")
104 #define DBG_T(a) FPrintf(ud->tdebug, a "\n")
105 #define DBG1(a,b) FPrintf(dd->debug, a "\n",(LONG)b)
106 #define DBG1_U(a,b) FPrintf(ud->debug, a "\n",(LONG)b)
107 #define DBG1_T(a,b) FPrintf(ud->tdebug, a "\n",(LONG)b)
108 #define DBG2(a,b,c) FPrintf(dd->debug, a "\n",(LONG)b,(LONG)c)
109 #define DBG2_U(a,b,c) FPrintf(ud->debug, a "\n",(LONG)b,(LONG)c)
110 #define DBG2_T(a,b,c) FPrintf(ud->tdebug, a "\n",(LONG)b,(LONG)c)
111 #else
112 #define USE_D(a)
113 #define USE_UD(a)
114 #define DBG(a)
115 #define DBG_U(a)
116 #define DBG_T(a)
117 #define DBG1(a,b)
118 #define DBG1_U(a,b)
119 #define DBG1_T(a,b)
120 #define DBG2(a,b,c)
121 #define DBG2_U(a,b,c)
122 #define DBG2_T(a,b,c)
123 #endif
125 // New Style Device support
127 #define NSCMD_DEVICEQUERY 0x4000
129 struct NSDeviceQueryResult
131 ULONG DevQueryFormat; /* this is type 0 */
132 ULONG SizeAvailable; /* bytes available */
133 UWORD DeviceType; /* what the device does */
134 UWORD DeviceSubType; /* depends on the main type */
135 UWORD *SupportedCommands; /* 0 terminated list of cmd's */
138 #define NSDEVTYPE_SANA2 7 /* A >=SANA2R2 networking device */
141 /// device structures
143 struct DevData
145 struct Library dd_Lib;
146 APTR dd_SegList;
147 struct Library *dd_SysBase;
148 struct Library *dd_PrometheusBase;
149 struct Library *dd_UtilityBase;
150 struct Library *dd_DOSBase;
151 struct Library *dd_TimerBase;
152 struct UnitData *dd_Units[4];
153 struct timerequest dd_Treq;
156 #ifdef PDEBUG
157 BPTR debug;
158 UBYTE dpath[128];
159 #endif
162 struct UnitData
164 struct Message ud_Message;
165 IPTR ud_Hardware;
166 struct Library *ud_SysBase;
167 struct Library *ud_PrometheusBase;
168 struct Library *ud_DOSBase;
169 struct Library *ud_TimerBase;
170 struct Interrupt *ud_Interrupt;
171 struct Task *ud_Task;
172 struct MsgPort *ud_TaskPort;
173 struct MsgPort *ud_LifeTime;
174 struct MinList ud_RxQueue;
175 struct MinList ud_TxQueue;
176 struct IOSana2Req *ud_PendingWrite;
177 APTR ud_Board;
178 ULONG ud_OpenCnt;
179 ULONG ud_GoWriteMask;
180 UWORD ud_RxBuffer[768];
181 UBYTE ud_Name[24];
182 UBYTE ud_EtherAddress[6];
183 UBYTE ud_SoftAddress[6];
184 struct Sana2DeviceStats ud_DevStats;
185 UBYTE ud_Flags;
186 UBYTE ud_NextPage;
187 BYTE ud_GoWriteBit;
188 UBYTE pad;
189 #ifdef PDEBUG
190 BPTR debug;
191 BPTR tdebug;
192 #endif
195 struct BuffFunctions
197 BOOL (*bf_CopyTo)(REG(a0, APTR), REG(a1, APTR), REG(d0, ULONG));
198 BOOL (*bf_CopyFrom)(REG(a0, APTR), REG(a1, APTR), REG(d0, ULONG));
202 /// prototypes
204 #ifdef __AROS__
205 AROS_UFP3(struct DevData *, DevInit,
206 AROS_UFPA(IPTR, num, D0),
207 AROS_UFPA(APTR, seglist, A0),
208 AROS_UFPA(struct Library *, sysb, A6));
209 AROS_LD3(LONG, DevOpen,
210 AROS_LDA(struct IOSana2Req *, req, A1),
211 AROS_LDA(LONG, unit, D0),
212 AROS_LDA(ULONG, flags, D1),
213 struct DevData *, dd, 1, S2);
214 AROS_LD1(APTR, DevClose,
215 AROS_LDA(struct IOSana2Req *, req, A1),
216 struct DevData *, dd, 2, S2);
217 AROS_LD0(APTR, DevExpunge,
218 struct DevData *, dd, 3, S2);
219 AROS_LD0(APTR, DevReserved,
220 struct DevData *, dd, 4, S2);
221 AROS_LD1(VOID, DevBeginIO,
222 AROS_LDA(struct IOSana2Req *, req, A1),
223 struct DevData *, dd, 5, S2);
224 AROS_LD1(ULONG, DevAbortIO,
225 AROS_LDA(struct IOSana2Req *, req, A1),
226 struct DevData *, dd, 6, S2);
227 #else
228 LONG DevOpen(REG(a1, struct IOSana2Req *req), REG(d0, LONG unit),
229 REG(d1, LONG flags), REG(a6, struct DevData *dd));
230 APTR DevClose(REG(a1, struct IOSana2Req *req), REG(a6, struct DevData *dd));
231 APTR DevExpunge(REG(a6, struct DevData *dd));
232 LONG DevReserved(void);
233 void DevBeginIO(REG(a1, struct IOSana2Req *req),
234 REG(a6, struct DevData *dd));
235 ULONG DevAbortIO(REG(a1, struct IOSana2Req *req),
236 REG(a6, struct DevData *dd));
237 #endif
239 void IoDone(struct UnitData *ud, struct IOSana2Req *req, LONG err, LONG werr);
240 LONG OpenDeviceLibraries(struct DevData *dd);
241 void CloseDeviceLibraries(struct DevData *dd);
242 LONG PrepareCookie(struct IOSana2Req *req, struct DevData *dd);
243 LONG RunTask(struct DevData *dd, struct UnitData *ud);
244 void ClearGlobalStats(struct UnitData *ud);
245 struct UnitData *OpenUnit(struct DevData *dd, LONG unit, LONG flags);
246 struct UnitData *InitializeUnit(struct DevData *dd, LONG unit);
247 void CloseUnit(struct DevData *dd, struct UnitData *ud);
248 void ExpungeUnit(struct DevData *dd, struct UnitData *ud);
250 void CmdNSDQuery(struct UnitData *ud, struct IOStdReq *req);
251 void S2DeviceQuery(struct UnitData *ud, struct IOSana2Req *req);
252 void S2GetStationAddress(struct UnitData *ud, struct IOSana2Req *req);
253 void S2ConfigInterface(struct UnitData *ud, struct IOSana2Req *req);
254 void S2Online(struct UnitData *ud, struct IOSana2Req *req);
255 void S2Offline(struct UnitData *ud, struct IOSana2Req *req);
256 void S2GetGlobalStats(struct UnitData *ud, struct IOSana2Req *req);
258 void HardwareReset(struct UnitData *ud);
259 void HardwareInit (struct UnitData *ud);
260 IPTR FindHardware(struct DevData *dd, WORD unit, struct UnitData *ud);
261 void GoOnline (struct UnitData *ud);
262 void GoOffline(struct UnitData *ud);
263 void GetHwAddress(struct UnitData *ud);
264 void WriteHwAddress(struct UnitData *ud);
265 LONG PacketReceived(struct UnitData *ud);
266 LONG RingBufferNotEmpty(struct UnitData *ud);
268 struct IOSana2Req *SearchReadRequest(struct UnitData *ud,
269 struct MinList *queue, ULONG type);
270 void UnitTask(void);
272 #ifdef __AROS__
273 struct Library *sys_base;
274 #endif
277 /// tables and constants
279 extern struct Resident romtag;
280 const UBYTE IdString[] = DEV_IDSTRING;
282 const void *FuncTable[] =
284 #ifdef __AROS__
285 AROS_SLIB_ENTRY(DevOpen, S2, 1),
286 AROS_SLIB_ENTRY(DevClose, S2, 2),
287 AROS_SLIB_ENTRY(DevExpunge, S2, 3),
288 AROS_SLIB_ENTRY(DevReserved, S2, 4),
289 AROS_SLIB_ENTRY(DevBeginIO, S2, 5),
290 AROS_SLIB_ENTRY(DevAbortIO, S2, 6),
291 #else
292 DevOpen,
293 DevClose,
294 DevExpunge,
295 DevReserved,
296 DevBeginIO,
297 DevAbortIO,
298 #endif
299 (APTR)-1
302 UWORD NSDSupported[] =
304 CMD_READ,
305 CMD_WRITE,
306 CMD_FLUSH,
307 S2_DEVICEQUERY,
308 S2_GETSTATIONADDRESS,
309 S2_CONFIGINTERFACE,
310 S2_BROADCAST,
311 S2_GETGLOBALSTATS,
312 S2_ONLINE,
313 S2_OFFLINE,
314 NSCMD_DEVICEQUERY,
320 /// DevInit()
321 // Called when the device is loaded into memory. Makes system library, initializes Library structure, opens
322 // libraries used by the device. Returns device base or NULL if init failed.
324 #ifdef __AROS__
325 AROS_UFH3(struct DevData *, DevInit,
326 AROS_UFHA(IPTR, num, D0),
327 AROS_UFHA(APTR, seglist, A0),
328 AROS_UFHA(struct Library *, sysb, A6))
329 #else
330 struct DevData *DevInit(REG(d0, ULONG num), REG(a0, void *seglist),
331 REG(a6, struct Library *sysb))
332 #endif
334 AROS_USERFUNC_INIT
336 struct DevData *dd;
337 struct Library *SysBase = sysb;
339 if (dd = (struct DevData*)MakeLibrary(FuncTable, NULL, NULL,
340 sizeof(struct DevData), 0))
342 dd->dd_Lib.lib_Node.ln_Type = NT_DEVICE;
343 dd->dd_Lib.lib_Node.ln_Name = (TEXT *)romtag.rt_Name;
344 dd->dd_Lib.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
345 dd->dd_Lib.lib_Version = DEV_VERSION;
346 dd->dd_Lib.lib_Revision = DEV_REVISION;
347 dd->dd_Lib.lib_IdString = (TEXT *)romtag.rt_IdString;
348 dd->dd_Lib.lib_OpenCnt = 0;
349 dd->dd_SegList = seglist;
350 dd->dd_SysBase = SysBase;
351 if (OpenDeviceLibraries(dd))
353 USE_D(DOSBase)
354 WORD i;
356 for (i = 0; i < 4; i++) dd->dd_Units[i] = NULL;
358 #ifdef __AROS__
359 sys_base = SysBase;
360 #endif
362 #ifdef PDEBUG
363 strcpy(dd->dpath, "KCON:0/17/400/300/prm-rtl8029.device (main)/AUTO/CLOSE/WAIT");
364 GetVar("PrometheusDebug", dd->dpath, 128, 0);
365 dd->debug = Open(dd->dpath, MODE_NEWFILE);
366 #endif
368 DBG1("Device initialized, base at $%08lx.", dd);
369 AddDevice((struct Device*)dd);
370 return dd;
372 CloseDeviceLibraries(dd);
374 return NULL;
376 AROS_USERFUNC_EXIT
380 /// DevOpen()
382 #ifdef __AROS__
383 AROS_LH3(LONG, DevOpen,
384 AROS_LHA(struct IOSana2Req *, req, A1),
385 AROS_LHA(LONG, unit, D0),
386 AROS_LHA(ULONG, flags, D1),
387 struct DevData *, dd, 1, S2)
388 #else
389 LONG DevOpen(REG(a1, struct IOSana2Req *req), REG(d0, LONG unit),
390 REG(d1, LONG flags), REG(a6, struct DevData *dd))
391 #endif
393 AROS_LIBFUNC_INIT
395 USE_D(DOSBase)
396 struct UnitData *ud;
398 DBG("DevOpen() called.");
399 dd->dd_Lib.lib_OpenCnt++; // expunge protection
401 if ((unit >= 0) && (unit <= 3))
403 if (ud = OpenUnit(dd, unit, flags))
405 req->ios2_Req.io_Error = 0;
406 req->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
407 req->ios2_Req.io_Device = (struct Device*)dd;
408 req->ios2_Req.io_Unit = (struct Unit*)ud;
409 if (PrepareCookie(req, dd))
411 dd->dd_Lib.lib_Flags &= ~LIBF_DELEXP;
412 DBG("DevOpen(): device opened successfully.");
413 return 0;
415 DBG("PrepareCookie() failed.");
416 CloseUnit(dd, ud);
419 req->ios2_Req.io_Error = IOERR_OPENFAIL;
420 req->ios2_Req.io_Device = (struct Device*)-1;
421 req->ios2_Req.io_Unit = (struct Unit*)-1;
422 dd->dd_Lib.lib_OpenCnt--; /* end of expunge protection */
423 return IOERR_OPENFAIL;
425 AROS_LIBFUNC_EXIT
429 /// DevClose()
431 #ifdef __AROS__
432 AROS_LH1(APTR, DevClose,
433 AROS_LHA(struct IOSana2Req *, req, A1),
434 struct DevData *, dd, 2, S2)
435 #else
436 APTR DevClose(REG(a1, struct IOSana2Req *req), REG(a6, struct DevData *dd))
437 #endif
439 AROS_LIBFUNC_INIT
441 USE(SysBase)
442 USE_D(DOSBase)
444 CloseUnit(dd, (struct UnitData*)req->ios2_Req.io_Unit);
446 if (req->ios2_BufferManagement) FreeMem(req->ios2_BufferManagement,
447 sizeof(struct BuffFunctions));
449 if (--dd->dd_Lib.lib_OpenCnt == 0)
451 DBG("DevClose(): open counter reached 0.");
452 if (dd->dd_Lib.lib_Flags & LIBF_DELEXP)
453 #ifdef __AROS__
454 return AROS_LVO_CALL0(APTR, struct DevData *, dd, 2, );
455 #else
456 return (DevExpunge(dd));
457 #endif
459 return 0;
461 AROS_LIBFUNC_EXIT
465 /// DevExpunge()
467 #ifdef __AROS__
468 AROS_LH0(APTR, DevExpunge,
469 struct DevData *, dd, 3, S2)
470 #else
471 APTR DevExpunge(REG(a6, struct DevData *dd))
472 #endif
474 AROS_LIBFUNC_INIT
476 USE(SysBase)
477 USE_D(DOSBase)
478 APTR seglist;
480 if (dd->dd_Lib.lib_OpenCnt)
482 dd->dd_Lib.lib_Flags |= LIBF_DELEXP;
483 return 0;
485 Remove((struct Node*)dd);
486 CloseDeviceLibraries(dd);
487 seglist = dd->dd_SegList;
488 FreeMem((APTR)dd - dd->dd_Lib.lib_NegSize,
489 (IPTR)dd->dd_Lib.lib_PosSize + (IPTR)dd->dd_Lib.lib_NegSize);
490 DBG("DevExpunge(): expunged.");
491 return seglist;
493 AROS_LIBFUNC_EXIT
497 /// DevReserved()
499 #ifdef __AROS__
500 AROS_LH0(APTR, DevReserved,
501 struct DevData *, dd, 4, S2)
502 #else
503 LONG DevReserved (void)
504 #endif
506 AROS_LIBFUNC_INIT
508 return 0;
510 AROS_LIBFUNC_EXIT
514 /// DevBeginIo()
516 #ifdef __AROS__
517 AROS_LH1(VOID, DevBeginIO,
518 AROS_LHA(struct IOSana2Req *, req, A1),
519 struct DevData *, dd, 5, S2)
520 #else
521 void DevBeginIO(REG(a1, struct IOSana2Req *req),
522 REG(a6, struct DevData *dd))
523 #endif
525 AROS_LIBFUNC_INIT
527 USE(SysBase)
528 USE_D(DOSBase)
529 struct UnitData *ud = (struct UnitData*)req->ios2_Req.io_Unit;
530 WORD i;
532 switch(req->ios2_Req.io_Command)
534 case NSCMD_DEVICEQUERY: CmdNSDQuery(ud, (struct IOStdReq*)req); break;
535 case S2_DEVICEQUERY: S2DeviceQuery(ud, req); break;
536 case S2_GETSTATIONADDRESS: S2GetStationAddress(ud, req); break;
537 case S2_CONFIGINTERFACE: S2ConfigInterface(ud, req); break;
538 case S2_ONLINE: S2Online(ud, req); break;
539 case S2_OFFLINE: S2Offline(ud, req); break;
540 case S2_GETGLOBALSTATS: S2GetGlobalStats(ud, req); break;
542 case CMD_READ:
543 DBG1("CMD_READ [$%08lx].", (LONG)req);
544 req->ios2_Req.io_Flags &= ~IOF_QUICK;
545 PutMsg(ud->ud_TaskPort, &req->ios2_Req.io_Message);
546 break;
548 case S2_BROADCAST:
549 for (i = 0; i < 6; i++) req->ios2_DstAddr[i] = 0xFF;
550 case CMD_WRITE:
551 DBG1("CMD_WRITE [$%08lx].", (LONG)req);
552 req->ios2_Req.io_Flags &= ~IOF_QUICK;
553 PutMsg(ud->ud_TaskPort, &req->ios2_Req.io_Message);
554 break;
556 case CMD_FLUSH:
557 DBG1("CMD_FLUSH [$%08lx].", (LONG)req);
558 req->ios2_Req.io_Flags &= ~IOF_QUICK;
559 PutMsg(ud->ud_TaskPort, &req->ios2_Req.io_Message);
560 break;
562 default:
563 DBG1("DevBeginIo(): unknown command code %ld.", req->ios2_Req.io_Command);
564 IoDone(ud, req, IOERR_NOCMD, S2WERR_GENERIC_ERROR);
565 break;
567 return;
569 AROS_LIBFUNC_EXIT
573 /// DevAbortIO()
575 #ifdef __AROS__
576 AROS_LH1(ULONG, DevAbortIO,
577 AROS_LHA(struct IOSana2Req *, req, A1),
578 struct DevData *, dd, 6, S2)
579 #else
580 ULONG DevAbortIO(REG(a1, struct IOSana2Req *req),
581 REG(a6, struct DevData *dd))
582 #endif
584 AROS_LIBFUNC_INIT
586 USE(SysBase)
587 USE_D(DOSBase)
588 LONG ret = 0;
589 struct UnitData *ud = (struct UnitData*)req->ios2_Req.io_Unit;
590 struct MinList *list;
591 struct MinNode *node;
593 DBG1("DevAbortIo: aborting $%08lx.", req);
594 switch (req->ios2_Req.io_Command)
596 case CMD_READ:
597 list = &ud->ud_RxQueue;
598 break;
600 case CMD_WRITE:
601 case S2_BROADCAST:
602 list = &ud->ud_TxQueue;
603 break;
605 default:
606 list = NULL;
608 if (list)
610 Disable();
611 for (node = list->mlh_Head; node->mln_Succ; node = node->mln_Succ)
613 if (node == (struct MinNode*)req)
615 if (((struct Message*)node)->mn_Node.ln_Type != NT_REPLYMSG)
617 Remove((struct Node*)node);
618 req->ios2_Req.io_Error = IOERR_ABORTED;
619 ReplyMsg((struct Message*)node);
620 ret = 0;
624 Enable();
626 else ret = IOERR_NOCMD;
627 return ret;
629 AROS_LIBFUNC_EXIT
634 // AUXILIARY FUNCTIONS
636 /// IoDone(struct UnitData *ud, struct IOSana2Req *req, LONG err, LONG werr)
637 // Function ends IORequest with given error codes. Requests with IOF_QUICK cleared will be ReplyMsg()-ed.
639 void IoDone(struct UnitData *ud, struct IOSana2Req *req, LONG err, LONG werr)
641 USE_U(SysBase)
643 req->ios2_Req.io_Error = err;
644 req->ios2_WireError = werr;
645 if (!(req->ios2_Req.io_Flags & IOF_QUICK))
646 ReplyMsg(&req->ios2_Req.io_Message);
647 return;
651 /// OpenDeviceLibraries(struct DevData *dd)
653 LONG OpenDeviceLibraries(struct DevData *dd)
655 USE(SysBase)
657 if (!(dd->dd_UtilityBase = OpenLibrary("utility.library", 39))) return FALSE;
658 if (!(dd->dd_PrometheusBase = OpenLibrary("prometheus.library", 2))) return FALSE;
659 if (!(dd->dd_DOSBase = OpenLibrary("dos.library", 38))) return FALSE;
660 if (OpenDevice ("timer.device", UNIT_VBLANK, (struct IORequest*)&dd->dd_Treq, 0) == 0)
662 dd->dd_TimerBase = (struct Library*)dd->dd_Treq.tr_node.io_Device;
665 return TRUE;
669 /// CloseDeviceLibraries(struct DevData *dd)
671 void CloseDeviceLibraries(struct DevData *dd)
673 USE(SysBase)
675 if (dd->dd_DOSBase) CloseLibrary(dd->dd_DOSBase);
676 if (dd->dd_PrometheusBase) CloseLibrary(dd->dd_PrometheusBase);
677 if (dd->dd_UtilityBase) CloseLibrary(dd->dd_UtilityBase);
678 if (dd->dd_TimerBase) CloseDevice ((struct IORequest*)&dd->dd_Treq);
682 /// PrepareCookie(struct IOSana2Req *req, struct DevData *dd)
684 LONG PrepareCookie(struct IOSana2Req *req, struct DevData *dd)
686 USE(SysBase)
687 USE(UtilityBase)
688 USE_D(DOSBase)
690 if (req->ios2_BufferManagement)
692 struct BuffFunctions *bfun;
694 if (bfun = AllocMem(sizeof(struct BuffFunctions), MEMF_ANY))
696 bfun->bf_CopyFrom = (APTR)GetTagData(S2_CopyFromBuff, (IPTR)NULL,
697 (struct TagItem*)req->ios2_BufferManagement);
698 bfun->bf_CopyTo = (APTR)GetTagData(S2_CopyToBuff, (IPTR)NULL,
699 (struct TagItem*)req->ios2_BufferManagement);
701 if (bfun->bf_CopyFrom && bfun->bf_CopyTo)
703 DBG1("CopyFrom [$%08lx].", bfun->bf_CopyFrom);
704 req->ios2_BufferManagement = bfun;
705 return TRUE;
707 else FreeMem(bfun, sizeof(struct BuffFunctions));
710 return FALSE;
714 /// RunTask(struct DevData *dd, struct UnitData *ud)
716 LONG RunTask(struct DevData *dd, struct UnitData *ud)
718 USE(SysBase)
719 USE(DOSBase)
720 const struct TagItem task_tags[] =
722 {NP_Entry, (IPTR)UnitTask},
723 {NP_Name, (IPTR)ud->ud_Name},
724 {NP_Priority, 6},
725 {TAG_END, 0}
728 DBG("RunTask() called.");
730 if(ud->ud_LifeTime = CreateMsgPort())
732 if (ud->ud_Task = (struct Task*)CreateNewProc(task_tags))
734 WORD i;
736 DBG1("Task [$%08lx] started.", ud->ud_Task);
737 for (i = 0; i < 50; i++)
739 if (!(ud->ud_TaskPort = FindPort(ud->ud_Name))) Delay(1);
740 else
742 DBG("Task port detected.");
743 ud->ud_Message.mn_Node.ln_Type = NT_MESSAGE;
744 ud->ud_Message.mn_Length = sizeof(struct UnitData);
745 ud->ud_Message.mn_ReplyPort = ud->ud_LifeTime;
746 PutMsg(ud->ud_TaskPort, &ud->ud_Message);
747 return TRUE;
752 return FALSE;
756 /// KillTask(struct DevData *dd, struct UnitData *ud)
758 void KillTask(struct DevData *dd, struct UnitData *ud)
760 USE(SysBase)
761 USE_D(DOSBase)
763 Signal(ud->ud_Task, SIGBREAKF_CTRL_C);
764 WaitPort(ud->ud_LifeTime);
765 GetMsg(ud->ud_LifeTime);
766 DeleteMsgPort(ud->ud_LifeTime);
767 DBG("Task dead.");
768 return;
772 /// ClearGlobalStats()
774 void ClearGlobalStats(struct UnitData *ud)
776 USE_U(TimerBase)
778 ud->ud_DevStats.PacketsReceived = 0;
779 ud->ud_DevStats.PacketsSent = 0;
780 GetSysTime(&ud->ud_DevStats.LastStart);
781 return;
785 /// OpenUnit()
787 struct UnitData *OpenUnit(struct DevData *dd, LONG unit, LONG flags)
789 USE_D(DOSBase)
790 struct UnitData *ud = dd->dd_Units[unit];
792 DBG("OpenUnit() called.");
794 /* Eliminate 'promiscuous without exclusive' flag combination. */
796 if ((flags & SANA2OPF_PROM) && !(flags & SANA2OPF_MINE)) return NULL;
798 /* Initialize unit if opened first time. */
800 if (!ud)
802 if (!(ud = InitializeUnit(dd, unit))) return NULL;
805 /* Check exclusive flag - reject if already opened by someone else. */
807 if ((flags & SANA2OPF_MINE) && ud->ud_OpenCnt) return NULL;
809 /* Set promiscuous flag if requested - we konw here MINE was requested too, and noone else has opened */
810 /* the unit. So we can just set it if requested. */
812 if (flags & SANA2OPF_PROM) ud->ud_Flags |= UF_PROMISCUOUS;
814 /* OK, increment open counter and exit with success. */
816 ud->ud_OpenCnt++;
817 DBG2("%s opened [%ld].", ud->ud_Name, ud->ud_OpenCnt);
818 return ud;
822 /// CloseUnit()
824 void CloseUnit(struct DevData *dd, struct UnitData *ud)
826 USE_D(DOSBase)
828 DBG1("%s closed.", ud->ud_Name);
829 if (!(--ud->ud_OpenCnt)) ExpungeUnit(dd, ud);
830 return;
834 /// InitializeUnit()
836 struct UnitData *InitializeUnit(struct DevData *dd, LONG unit)
838 USE(SysBase)
839 #ifdef PDEBUG
840 USE(DOSBase)
841 #endif
842 struct UnitData *ud;
843 WORD i;
845 DBG("InitializeUnit() called.");
846 if (ud = AllocMem(sizeof(struct UnitData), MEMF_PUBLIC | MEMF_CLEAR))
848 if (ud->ud_Hardware = FindHardware(dd, unit, ud))
850 #ifdef PDEBUG
851 ud->debug = dd->debug;
852 #endif
854 for (i = 5; i >= 0; i--)
856 ud->ud_SoftAddress[i] = 0x00;
857 ud->ud_EtherAddress[i] = 0x00;
859 ud->ud_SysBase = dd->dd_SysBase;
860 ud->ud_PrometheusBase = dd->dd_PrometheusBase;
861 ud->ud_DOSBase = dd->dd_DOSBase;
862 ud->ud_TimerBase = dd->dd_TimerBase;
863 strcpy(ud->ud_Name, "prm-rtl8029.device (x)");
864 ud->ud_Name[20] = '0' + unit;
865 ud->ud_RxQueue.mlh_Head = (struct MinNode*)&ud->ud_RxQueue.mlh_Tail;
866 ud->ud_RxQueue.mlh_Tail = NULL;
867 ud->ud_RxQueue.mlh_TailPred = (struct MinNode*)&ud->ud_RxQueue.mlh_Head;
868 ud->ud_TxQueue.mlh_Head = (struct MinNode*)&ud->ud_TxQueue.mlh_Tail;
869 ud->ud_TxQueue.mlh_Tail = NULL;
870 ud->ud_TxQueue.mlh_TailPred = (struct MinNode*)&ud->ud_TxQueue.mlh_Head;
871 ud->ud_NextPage = RX_BUFFER;
872 HardwareReset(ud);
873 HardwareInit(ud);
874 GetHwAddress(ud);
875 if (RunTask(dd, ud))
877 dd->dd_Units[unit] = ud;
878 DBG1("%s initialized.", (LONG)ud->ud_Name);
879 return ud;
883 ExpungeUnit(dd, ud);
884 return NULL;
888 /// ExpungeUnit()
890 void ExpungeUnit(struct DevData *dd, struct UnitData *ud)
892 USE(SysBase)
893 USE_D(DOSBase)
894 WORD unit;
896 if (ud)
898 unit = ud->ud_Name[20] - '0';
899 if (ud->ud_Flags & UF_ONLINE) GoOffline(ud);
900 if (ud->ud_Task) KillTask(dd, ud);
901 FreeMem(ud, sizeof(struct UnitData));
902 dd->dd_Units[unit] = NULL;
903 DBG1("%s expunged.", ud->ud_Name);
905 return;
910 // IMMEDIATE DEVICE COMMANDS
912 /// S2DeviceQuery()
914 void S2DeviceQuery(struct UnitData *ud, struct IOSana2Req *req)
916 USE_UD(DOSBase)
917 struct Sana2DeviceQuery *query = req->ios2_StatData;
919 DBG_U("S2_DEVICEQUERY.");
920 if (query)
922 if (query->SizeAvailable >= sizeof(struct Sana2DeviceQuery))
924 query->SizeSupplied = sizeof(struct Sana2DeviceQuery);
925 query->DevQueryFormat = 0;
926 query->DeviceLevel = 0;
927 query->AddrFieldSize = 48;
928 query->MTU = 1500;
929 query->BPS = 10000000;
930 query->HardwareType = S2WireType_Ethernet;
931 IoDone(ud, req, OK, OK);
933 else IoDone(ud, req, S2ERR_BAD_ARGUMENT, S2WERR_GENERIC_ERROR);
935 else IoDone(ud, req, S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
936 return;
940 /// S2GetStationAddress()
942 void S2GetStationAddress(struct UnitData *ud, struct IOSana2Req *req)
944 USE_U(SysBase)
945 USE_UD(DOSBase)
947 DBG_U("S2_GETSTATIONADDRESS.");
948 CopyMem(ud->ud_SoftAddress, req->ios2_SrcAddr, 6);
949 CopyMem(ud->ud_EtherAddress, req->ios2_DstAddr, 6);
950 IoDone(ud, req, OK, OK);
951 return;
955 /// S2Online()
957 void S2Online(struct UnitData *ud, struct IOSana2Req *req)
959 USE_UD(DOSBase)
961 DBG_U("S2_ONLINE.");
962 ClearGlobalStats(ud);
963 if (!(ud->ud_Flags & UF_ONLINE))
965 GoOnline(ud);
966 ud->ud_Flags |= UF_ONLINE;
967 IoDone(ud, req, OK, OK);
969 else IoDone(ud, req, S2ERR_BAD_STATE, S2WERR_UNIT_ONLINE);
970 return;
974 /// S2ConfigInterface()
976 BOOL address_has_all(UBYTE *addr, UBYTE num)
978 WORD i;
980 for (i = 5; i >= 0; i--)
982 if (addr[i] != num) return FALSE;
984 return TRUE;
988 void S2ConfigInterface(struct UnitData *ud, struct IOSana2Req *req)
990 USE_U(SysBase)
991 USE_UD(DOSBase)
993 DBG_U("S2_CONFIGINTERFACE.");
994 ClearGlobalStats(ud);
995 if (ud->ud_Flags & UF_CONFIGURED)
997 IoDone(ud, req, S2ERR_BAD_STATE, S2WERR_IS_CONFIGURED);
999 else if (address_has_all(req->ios2_SrcAddr, 0x00) ||
1000 address_has_all(req->ios2_SrcAddr, 0xFF))
1002 IoDone(ud, req, S2ERR_BAD_ADDRESS, S2WERR_SRC_ADDRESS);
1004 else
1006 HardwareInit(ud);
1007 CopyMem(req->ios2_SrcAddr, ud->ud_SoftAddress, 6);
1008 WriteHwAddress(ud);
1009 if (!(ud->ud_Flags & UF_ONLINE))
1011 GoOnline(ud);
1012 ud->ud_Flags |= UF_ONLINE;
1014 ud->ud_Flags |= UF_CONFIGURED;
1015 IoDone(ud, req, OK, OK);
1017 return;
1021 /// S2Offline()
1023 void S2Offline(struct UnitData *ud, struct IOSana2Req *req)
1025 USE_UD(DOSBase)
1027 DBG_U("S2_OFFLINE.");
1028 if (ud->ud_Flags & UF_ONLINE)
1030 GoOffline(ud);
1031 ud->ud_Flags &= ~UF_ONLINE;
1032 IoDone(ud, req, OK, OK);
1034 else IoDone(ud, req, S2ERR_BAD_STATE, S2WERR_UNIT_OFFLINE);
1035 return;
1039 /// S2GetGlobalStats()
1041 void S2GetGlobalStats(struct UnitData *ud, struct IOSana2Req *req)
1043 USE_U(SysBase)
1045 if (req->ios2_StatData)
1047 CopyMem(&ud->ud_DevStats, req->ios2_StatData, sizeof(struct Sana2DeviceStats));
1048 IoDone(ud, req, OK, OK);
1050 else IoDone(ud, req, S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
1054 /// CmdNSDQuery()
1056 void CmdNSDQuery(struct UnitData *ud, struct IOStdReq *req)
1058 USE_U(SysBase)
1059 USE_UD(DOSBase)
1060 struct NSDeviceQueryResult *qdata;
1061 LONG error = OK;
1063 DBG_U("NSCMD_DEVICEQUERY.");
1064 if (req->io_Length >= sizeof(struct NSDeviceQueryResult))
1066 if (qdata = (struct NSDeviceQueryResult*)req->io_Data)
1068 if ((qdata->DevQueryFormat == 0) && (qdata->SizeAvailable == 0))
1070 qdata->SizeAvailable = sizeof(struct NSDeviceQueryResult);
1071 qdata->DeviceType = NSDEVTYPE_SANA2;
1072 qdata->DeviceSubType = 0;
1073 qdata->SupportedCommands = NSDSupported;
1074 req->io_Actual = sizeof(struct NSDeviceQueryResult);
1076 else error = IOERR_BADLENGTH;
1078 else error = IOERR_BADADDRESS;
1080 else error = IOERR_BADLENGTH;
1082 /* I don't use IoDone() here, because it writes to ios2_WireError */
1083 /* but this request can be simple IOStdReq one. */
1085 req->io_Error = error;
1086 if (!(req->io_Flags & IOF_QUICK)) ReplyMsg(&req->io_Message);
1087 return;
1092 // HARDWARE ACCESS FUNCTIONS
1094 /// IntCode()
1096 #ifdef __AROS__
1097 AROS_INTH1(IntCode, struct UnitData *, ud)
1098 #else
1099 LONG IntCode(REG(a1, struct UnitData *ud))
1100 #endif
1102 AROS_INTFUNC_INIT
1104 USE_U(SysBase)
1105 UBYTE intstatus;
1106 struct IOSana2Req *req;
1107 LONG my_int = 0;
1109 while (intstatus = (BYTEIN(ud->ud_Hardware + NE2000_INT_STATUS)
1110 & INTMASK))
1112 if (intstatus & INT_TXERROR)
1114 BYTEOUT(ud->ud_Hardware + NE2000_INT_STATUS, INT_TXERROR);
1115 req = ud->ud_PendingWrite;
1116 IoDone(ud, req, S2ERR_TX_FAILURE, S2WERR_TOO_MANY_RETIRES);
1117 Signal(ud->ud_Task, ud->ud_GoWriteMask);
1118 my_int = 1;
1121 if (intstatus & INT_TXPACKET)
1123 BYTEOUT(ud->ud_Hardware + NE2000_INT_STATUS, INT_TXPACKET);
1124 req = ud->ud_PendingWrite;
1125 ud->ud_DevStats.PacketsSent++;
1126 IoDone(ud, req, OK, OK);
1127 Signal(ud->ud_Task, ud->ud_GoWriteMask);
1128 my_int = 1;
1131 if (intstatus & INT_RXPACKET)
1133 ULONG offset, len;
1134 UWORD mask = 0xFFFF;
1135 WORD i;
1137 while (RingBufferNotEmpty(ud))
1139 BYTEOUT(ud->ud_Hardware + NE2000_INT_STATUS, INT_RXPACKET);
1140 len = PacketReceived(ud);
1141 if (req = SearchReadRequest(ud, &ud->ud_RxQueue,
1142 BEWord(ud->ud_RxBuffer[6])))
1144 if (req->ios2_Req.io_Flags & SANA2IOF_RAW) offset = 0;
1145 else offset = 7;
1146 #ifdef __AROS__
1147 AROS_UFC3(BOOL, ((struct BuffFunctions*)
1148 req->ios2_BufferManagement)->bf_CopyTo,
1149 AROS_UFCA(APTR, req->ios2_Data, A0),
1150 AROS_UFCA(APTR, &ud->ud_RxBuffer[offset], A1),
1151 AROS_UFCA(ULONG, len - (offset << 1), D0));
1152 #else
1153 ((struct BuffFunctions*)req->ios2_BufferManagement)->
1154 bf_CopyTo(req->ios2_Data, &ud->ud_RxBuffer[offset],
1155 len - (offset << 1));
1156 #endif
1157 CopyMem(&ud->ud_RxBuffer[0], req->ios2_DstAddr, 6);
1158 CopyMem(&ud->ud_RxBuffer[3], req->ios2_SrcAddr, 6);
1159 req->ios2_DataLength = len - (offset << 1);
1160 for (i = 2; i >= 0; i--) mask &= ud->ud_RxBuffer[i];
1161 if (mask == 0xFFFF)
1162 req->ios2_Req.io_Flags |= SANA2IOF_BCAST;
1163 ud->ud_DevStats.PacketsReceived++;
1164 IoDone(ud, req, OK, OK);
1167 my_int = 1;
1170 return my_int;
1172 AROS_INTFUNC_EXIT
1176 /// InstallInterrupt()
1178 LONG InstallInterrupt(struct UnitData *ud)
1180 USE_U(SysBase)
1181 USE_U(PrometheusBase)
1182 struct Interrupt *intr;
1184 if (intr = AllocMem(sizeof(struct Interrupt), MEMF_PUBLIC | MEMF_CLEAR))
1186 intr->is_Node.ln_Type = NT_INTERRUPT;
1187 intr->is_Node.ln_Name = ud->ud_Name;
1188 intr->is_Data = ud;
1189 intr->is_Code = (APTR)IntCode;
1190 Prm_AddIntServer(ud->ud_Board, intr);
1191 ud->ud_Interrupt = intr;
1192 return TRUE;
1194 return FALSE;
1198 /// RemoveInterrupt()
1200 void RemoveInterrupt(struct UnitData *ud)
1202 USE_U(SysBase)
1203 USE_U(PrometheusBase)
1205 Prm_RemIntServer(ud->ud_Board, ud->ud_Interrupt);
1206 FreeMem(ud->ud_Interrupt, sizeof(struct Interrupt));
1207 return;
1211 /// FindHardware()
1213 IPTR FindHardware(struct DevData *dd, WORD unit, struct UnitData *ud)
1215 USE(PrometheusBase)
1216 WORD u = unit;
1217 APTR board = NULL;
1218 IPTR hwbase;
1220 while (u-- >= 0)
1222 board = Prm_FindBoardTags(board,
1223 PRM_Vendor, PCI_VENDOR_REALTEK,
1224 PRM_Device, PCI_DEVICE_RTL8029,
1225 TAG_END);
1226 if (!board) break;
1229 if (board)
1231 ud->ud_Board = board;
1232 Prm_GetBoardAttrsTags(board,
1233 PRM_MemoryAddr0, (IPTR)&hwbase,
1234 TAG_END);
1235 Prm_SetBoardAttrsTags(board,
1236 PRM_BoardOwner, (IPTR)dd,
1237 TAG_END);
1238 return hwbase;
1240 return 0;
1244 /// HardwareInit()
1246 void HardwareInit (struct UnitData *ud)
1248 IPTR hw = ud->ud_Hardware;
1250 BYTEOUT(hw + NE2000_COMMAND, 0x21);
1251 BYTEOUT(hw + NE2000_DATA_CONFIG,
1252 DTCFG_FIFO_8 | DTCFG_WIDE | DTCFG_LOOPSEL);
1253 BYTEOUT(hw + NE2000_DMA_COUNTER0, 0);
1254 BYTEOUT(hw + NE2000_DMA_COUNTER1, 0);
1255 BYTEOUT(hw + NE2000_TX_CONFIG, 0x02);
1256 BYTEOUT(hw + NE2000_PAGE_START, RX_BUFFER);
1257 BYTEOUT(hw + NE2000_PAGE_STOP, BUFFER_END);
1258 BYTEOUT(hw + NE2000_BOUNDARY, BUFFER_END - 1);
1259 BYTEOUT(hw + NE2000_INT_STATUS, 0xFF);
1260 BYTEOUT(hw + NE2000_INT_MASK, 0x00);
1261 BYTEOUT(hw + NE2000_COMMAND, 0x61);
1262 BYTEOUT(hw + NE2000_CURRENT_PAGE, RX_BUFFER);
1263 BYTEOUT(hw + NE2000_COMMAND, 0x21);
1264 return;
1268 /// HardwareReset()
1270 void HardwareReset (struct UnitData *ud)
1272 USE_U(DOSBase)
1273 IPTR hw = ud->ud_Hardware;
1274 UBYTE trash;
1276 WORDOUT(hw + NE2000_RESET_PORT, trash);
1277 Delay(1);
1278 trash = WORDIN(hw + NE2000_RESET_PORT);
1279 HardwareInit(ud);
1280 return;
1284 /// GoOnline()
1286 void GoOnline (struct UnitData *ud)
1288 IPTR hw = ud->ud_Hardware;
1290 HardwareReset(ud);
1291 WriteHwAddress(ud);
1292 InstallInterrupt(ud);
1293 BYTEOUT(hw + NE2000_COMMAND, 0x22);
1294 BYTEOUT(hw + NE2000_TX_CONFIG, 0x00);
1295 BYTEOUT(hw + NE2000_RX_CONFIG, RXCFG_BCAST | RXCFG_MCAST |
1296 ((ud->ud_Flags & UF_PROMISCUOUS) ? RXCFG_PROM : 0));
1297 BYTEOUT(hw + NE2000_INT_STATUS, 0xFF);
1298 BYTEOUT(hw + NE2000_INT_MASK, INTMASK);
1300 return;
1304 /// GoOffline()
1306 void GoOffline(struct UnitData *ud)
1308 IPTR hw = ud->ud_Hardware;
1310 BYTEOUT(hw + NE2000_COMMAND, 0x21);
1311 BYTEOUT(hw + NE2000_TX_CONFIG, 0x02);
1312 BYTEOUT(hw + NE2000_RX_CONFIG, 0x20);
1313 BYTEOUT(hw + NE2000_INT_STATUS, 0xFF);
1314 BYTEOUT(hw + NE2000_INT_MASK, 0);
1315 RemoveInterrupt(ud);
1316 return;
1320 /// BoardShutdown()
1322 void BoardShutdown(struct UnitData *ud)
1324 IPTR hw = ud->ud_Hardware;
1326 GoOffline(ud);
1327 BYTEOUT(hw + NE2000_INT_MASK, 0);
1328 BYTEOUT(hw + NE2000_INT_STATUS, 0xFF);
1329 return;
1333 /// GetPacketHeader()
1335 ULONG GetPacketHeader(IPTR ne, UBYTE page)
1337 ULONG hdr;
1339 BYTEOUT(ne + NE2000_DMA_COUNTER0, 4);
1340 BYTEOUT(ne + NE2000_DMA_COUNTER1, 0);
1341 BYTEOUT(ne + NE2000_DMA_START_ADDR0, 0);
1342 BYTEOUT(ne + NE2000_DMA_START_ADDR1, page);
1343 BYTEOUT(ne + NE2000_COMMAND,
1344 COMMAND_PAGE0 | COMMAND_START | COMMAND_READ);
1345 hdr = LEWORDIN(ne + NE2000_DMA_PORT);
1346 hdr |= LEWORDIN(ne + NE2000_DMA_PORT) << 16;
1347 return hdr;
1351 /// GetPacket()
1353 /*GetPacket(volatile struct Ne2000 *ne, UBYTE startpage, UWORD len, UWORD *buffer)*/
1354 VOID GetPacket(IPTR ne, UBYTE startpage, UWORD len, UWORD *buffer)
1356 UWORD count;
1358 BYTEOUT(ne + NE2000_DMA_COUNTER0, len & 0xFF);
1359 BYTEOUT(ne + NE2000_DMA_COUNTER1, len >> 8);
1360 BYTEOUT(ne + NE2000_DMA_START_ADDR0, 4);
1361 BYTEOUT(ne + NE2000_DMA_START_ADDR1, startpage);
1362 BYTEOUT(ne + NE2000_COMMAND, COMMAND_PAGE0 | COMMAND_START | COMMAND_READ);
1364 for (count = (len + 1) >> 1; count; count--)
1366 *buffer++ = WORDIN(ne + NE2000_DMA_PORT);
1368 return;
1372 /// PacketReceived()
1374 LONG PacketReceived(struct UnitData *ud)
1376 ULONG header, len;
1378 header = GetPacketHeader(ud->ud_Hardware, ud->ud_NextPage);
1379 len = header >> 16;
1380 GetPacket(ud->ud_Hardware, ud->ud_NextPage, len, (UWORD*)ud->ud_RxBuffer);
1381 BYTEOUT(ud->ud_Hardware + NE2000_BOUNDARY, ud->ud_NextPage);
1382 ud->ud_NextPage = (header >> 8) & 0xFF;
1383 BYTEOUT(ud->ud_Hardware + NE2000_INT_STATUS, INT_RXPACKET);
1384 return len;
1388 /// BufferOverflow()
1390 void BufferOverflow(struct UnitData *ud)
1392 struct Library *DOSBase = ud->ud_DOSBase;
1393 IPTR hw = ud->ud_Hardware;
1394 UBYTE txp, resent = FALSE, intstatus;
1396 txp = BYTEIN(hw + NE2000_COMMAND) & COMMAND_TXP;
1397 BYTEOUT(hw + NE2000_COMMAND, COMMAND_PAGE0 | COMMAND_ABORT | COMMAND_STOP);
1398 Delay(1);
1399 BYTEOUT(hw + NE2000_DMA_COUNTER0, 0);
1400 BYTEOUT(hw + NE2000_DMA_COUNTER1, 0);
1402 if (txp)
1404 intstatus = BYTEIN(hw + NE2000_INT_STATUS);
1405 if (!(intstatus & (INT_TXPACKET | INT_TXERROR))) resent = TRUE;
1408 BYTEOUT(hw + NE2000_TX_CONFIG, TXCFG_LOOP_INT);
1409 BYTEOUT(hw + NE2000_COMMAND,
1410 COMMAND_PAGE1 | COMMAND_ABORT | COMMAND_START);
1411 BYTEOUT(hw + NE2000_CURRENT_PAGE, RX_BUFFER);
1412 BYTEOUT(hw + NE2000_COMMAND,
1413 COMMAND_PAGE0 | COMMAND_ABORT | COMMAND_START);
1414 BYTEOUT(hw + NE2000_BOUNDARY, BUFFER_END - 1);
1415 ud->ud_NextPage = RX_BUFFER;
1417 BYTEOUT(hw + NE2000_TX_CONFIG, TXCFG_LOOP_NONE);
1418 if (resent) BYTEOUT(hw + NE2000_COMMAND, COMMAND_PAGE0 | COMMAND_START |
1419 COMMAND_ABORT | COMMAND_TXP);
1420 BYTEOUT(hw + NE2000_INT_STATUS, INT_OVERFLOW);
1422 return;
1426 /// SendPacket()
1428 void SendPacket(struct UnitData *ud, struct IOSana2Req *req)
1430 USE_U(SysBase)
1431 USE_UD(DOSBase)
1432 IPTR hw = ud->ud_Hardware;
1433 UBYTE ethbuffer[1536], *datapointer;
1434 UWORD *ethdata = (UWORD*)ethbuffer;
1435 ULONG data_len = req->ios2_DataLength;
1436 UWORD cycles;
1438 /* If not raw packets, fill in Dst, Src and Type fields of Ethernet frame. 'datapointer' is a variable */
1439 /* holding address of data to copy from network stack. If packet is raw, datapointer points to start */
1440 /* of ethbuffer, otherwise points to ef_Data field (first byte after Ethernet header. */
1442 if (!(req->ios2_Req.io_Flags & SANA2IOF_RAW))
1444 struct EthFrame *ef = (struct EthFrame*)ethbuffer;
1446 CopyMem(req->ios2_DstAddr, ef->ef_DestAddr, 6);
1447 CopyMem(ud->ud_EtherAddress, ef->ef_SrcAddr, 6);
1448 ef->ef_Type = MakeBEWord(req->ios2_PacketType);
1449 datapointer = ef->ef_Data;
1451 else datapointer = ethbuffer;
1453 /* Copy data from network stack using supplied CopyFrom() function. */
1455 #ifdef __AROS__
1456 AROS_UFC3(BOOL, ((struct BuffFunctions*)
1457 req->ios2_BufferManagement)->bf_CopyFrom,
1458 AROS_UFCA(APTR, datapointer, A0),
1459 AROS_UFCA(APTR, req->ios2_Data, A1),
1460 AROS_UFCA(ULONG, data_len, D0));
1461 #else
1462 ((struct BuffFunctions*)req->ios2_BufferManagement)->bf_CopyFrom(
1463 datapointer, req->ios2_Data, data_len);
1464 #endif
1466 /* Now we need length of data to send to hardware. IORequest ios2_DataLength does not include header */
1467 /* length if packet is not RAW. So we should add it. */
1469 if (!(req->ios2_Req.io_Flags & SANA2IOF_RAW)) data_len += 14;
1471 /* Packet sent to Ethernet hardware should be at least 60 bytes long (4 bytes of CRC will be appended */
1472 /* by hardware giving 64 bytes). If our packet is shorter we should extend it with spaces. */
1474 while (data_len < 60) ethbuffer[data_len++] = ' ';
1476 /* Now the packet is ready to send it to NIC buffer. It is done by Remote Write DMA command. Firstly */
1477 /* write address and counter should be initialized, then command register. */
1479 Disable();
1480 BYTEOUT(hw + NE2000_DMA_COUNTER0, data_len & 0xFF);
1481 BYTEOUT(hw + NE2000_DMA_COUNTER1, data_len >> 8);
1482 BYTEOUT(hw + NE2000_DMA_START_ADDR0, 0);
1483 BYTEOUT(hw + NE2000_DMA_START_ADDR1, TX_BUFFER);
1484 BYTEOUT(hw + NE2000_COMMAND,
1485 COMMAND_PAGE0 | COMMAND_START | COMMAND_WRITE);
1487 /* Now we can send packet data to DMAPort word by word. */
1489 for (cycles = (data_len + 1) >> 1; cycles; cycles--)
1490 WORDOUT(hw + NE2000_DMA_PORT, *ethdata++);
1492 /* Send packet to the wire. Register setup first. */
1494 BYTEOUT(hw + NE2000_TX_PAGE_START, TX_BUFFER);
1495 BYTEOUT(hw + NE2000_TX_COUNTER0, data_len & 0xFF);
1496 BYTEOUT(hw + NE2000_TX_COUNTER1, data_len >> 8);
1498 /* Three, two, one, go! */
1500 BYTEOUT(hw + NE2000_COMMAND,
1501 COMMAND_PAGE0 | COMMAND_START | COMMAND_ABORT | COMMAND_TXP);
1502 Enable();
1504 /* OK. Packet was sent (successfully or not). Hardware will respond with TXPACKET or TXERROR interrupt */
1505 /* then we will be able to reply IORequest in the interrupt server. */
1507 DBG_T("Packet sent.");
1508 return;
1512 /// GetHwAddress()
1514 void GetHwAddress(struct UnitData *ud)
1516 USE_UD(DOSBase)
1517 IPTR hw = ud->ud_Hardware;
1518 WORD i;
1520 BYTEOUT(hw + NE2000_DMA_COUNTER0, 6);
1521 BYTEOUT(hw + NE2000_DMA_COUNTER1, 0);
1522 BYTEOUT(hw + NE2000_DMA_START_ADDR0, 0);
1523 BYTEOUT(hw + NE2000_DMA_START_ADDR1, 0);
1524 BYTEOUT(hw + NE2000_COMMAND, COMMAND_READ);
1525 for (i = 0; i < 6; i++)
1526 ud->ud_EtherAddress[i] = WORDIN(hw + NE2000_DMA_PORT);
1528 #ifdef PDEBUG
1529 DBG_U("\thardware address (read):");
1530 for (i = 0; i < 6; i++) DBG1_U("\t%02lx", ud->ud_EtherAddress[i]);
1531 #endif
1533 return;
1537 /// WriteHwAddress()
1539 void WriteHwAddress(struct UnitData *ud)
1541 USE_UD(DOSBase)
1542 IPTR hw = ud->ud_Hardware;
1543 WORD i;
1545 #ifdef PDEBUG
1546 DBG_U("\thardware address (write):");
1547 for (i = 0; i < 6; i++) DBG1_U("\t%02lx", ud->ud_SoftAddress[i]);
1548 #endif
1550 BYTEOUT(hw + NE2000_COMMAND,
1551 COMMAND_PAGE1 | COMMAND_ABORT | COMMAND_STOP);
1552 for (i = 0; i < 6; i++)
1554 BYTEOUT(hw + NE2000_PHYSICAL_ADDR0 + i, ud->ud_SoftAddress[i]);
1556 BYTEOUT(hw + NE2000_COMMAND,
1557 COMMAND_PAGE0 | COMMAND_ABORT | COMMAND_STOP);
1558 return;
1562 /// RingBufferNotEmpty()
1564 LONG RingBufferNotEmpty(struct UnitData *ud)
1566 UBYTE current;
1567 IPTR hw = ud->ud_Hardware;
1569 BYTEOUT(hw + NE2000_COMMAND,
1570 COMMAND_PAGE1 | COMMAND_ABORT | COMMAND_START);
1571 current = BYTEIN(hw + NE2000_CURRENT_PAGE);
1572 BYTEOUT(hw + NE2000_COMMAND,
1573 COMMAND_PAGE0 | COMMAND_ABORT | COMMAND_START);
1575 if (ud->ud_NextPage == current) return FALSE;
1576 else return TRUE;
1581 // SUBTASK CODE
1583 /// SearchReadRequest()
1585 struct IOSana2Req *SearchReadRequest(struct UnitData *ud,
1586 struct MinList *queue, ULONG type)
1588 struct Library *SysBase = ud->ud_SysBase;
1589 struct IOSana2Req *req, *found = NULL /*, *x*/ ;
1591 for (req = (struct IOSana2Req*)queue->mlh_Head;
1592 req->ios2_Req.io_Message.mn_Node.ln_Succ;
1593 req = (struct IOSana2Req*)req->ios2_Req.io_Message.mn_Node.ln_Succ)
1595 if (req->ios2_PacketType == type)
1597 Remove((struct Node*)req);
1598 found = req;
1599 break;
1602 return found;
1606 /// FlushQueues()
1608 void FlushQueues(struct UnitData *ud)
1610 USE_U(SysBase)
1611 USE_UD(DOSBase)
1612 struct IOSana2Req *xreq;
1614 for (;;)
1616 Disable();
1617 xreq = (struct IOSana2Req*)RemHead((struct List*)&ud->ud_RxQueue);
1618 Enable();
1619 if (!xreq) break;
1620 DBG1_T("<- READ [$08%lx] [F].", xreq);
1621 IoDone(ud, xreq, IOERR_ABORTED, S2WERR_GENERIC_ERROR);
1624 for (;;)
1626 Disable();
1627 xreq = (struct IOSana2Req*)RemHead((struct List*)&ud->ud_TxQueue);
1628 Enable();
1629 if (!xreq) break;
1630 DBG1_T("<- WRITE [$08%lx] [F].", xreq);
1631 IoDone(ud, xreq, IOERR_ABORTED, S2WERR_GENERIC_ERROR);
1633 return;
1637 /// MainLoop()
1639 void MainLoop(struct UnitData *ud, struct MsgPort *port)
1641 USE_U(SysBase)
1642 USE_UD(DOSBase)
1643 ULONG signals, sigmask;
1644 struct IOSana2Req *req;
1646 #ifdef PDEBUG
1647 UBYTE wname[60], *ptr;
1649 ptr = strcpy(wname, "CON:400/17/400/300/");
1650 ptr = strcpy(ptr, ud->ud_Name);
1651 strcpy(ptr,"/AUTO/CLOSE/WAIT");
1652 ud->tdebug = Open(wname, MODE_NEWFILE);
1653 #endif
1655 sigmask = 1 << port->mp_SigBit;
1656 for (;;)
1658 DBG_T("Waiting...");
1659 signals = Wait(SIGBREAKF_CTRL_C | sigmask | ud->ud_GoWriteMask);
1661 if (signals & ud->ud_GoWriteMask)
1663 DBG_T("GoWrite");
1664 Disable();
1665 req = (struct IOSana2Req*)RemHead((struct List*)&ud->ud_TxQueue);
1666 Enable();
1667 ud->ud_PendingWrite = req;
1668 if (req) SendPacket(ud, req);
1671 if (signals & SIGBREAKF_CTRL_C)
1673 DBG1_T("TASK: %s task killed.", ud->ud_Name);
1674 return;
1677 if (signals & sigmask)
1679 struct IOSana2Req *req;
1681 DBG_T("port");
1682 while (req = (struct IOSana2Req*)GetMsg(port))
1684 switch (req->ios2_Req.io_Command)
1686 case CMD_READ:
1687 DBG1_T("-> READ [$%08lx].", req);
1688 Disable();
1689 AddTail((struct List*)&ud->ud_RxQueue, (struct Node*)req);
1690 Enable();
1691 break;
1693 case S2_BROADCAST:
1694 case CMD_WRITE:
1695 DBG1_T("-> WRITE [$%08lx].", req);
1696 if (ud->ud_PendingWrite)
1698 Disable();
1699 AddTail((struct List*)&ud->ud_TxQueue, (struct Node*)req);
1700 Enable();
1702 else
1704 ud->ud_PendingWrite = req;
1705 SendPacket(ud, req);
1706 DBG_T("Packet sent 2.");
1708 break;
1710 case CMD_FLUSH:
1711 DBG1_T("-> FLUSH [$%08lx].", req);
1712 FlushQueues(ud);
1713 DBG1_T("<- FLUSH [$%08lx].", req);
1714 IoDone(ud, req, OK, OK);
1715 break;
1717 default:
1718 DBG2_T("-> Unknown ($%lx) [$%08lx].", req->ios2_Req.io_Command, req);
1726 /// UnitTask()
1728 void UnitTask(void)
1730 struct Library *SysBase;
1731 struct Task *task;
1732 struct MsgPort *port;
1733 struct UnitData *ud;
1735 #ifdef PDEBUG
1736 struct Library *DOSBase;
1737 #endif
1739 #ifdef __AROS__
1740 SysBase = sys_base;
1741 #else
1742 SysBase = *(struct Library**)4;
1743 #endif
1744 task = FindTask(NULL);
1745 if (port = CreateMsgPort())
1747 port->mp_Node.ln_Name = task->tc_Node.ln_Name;
1748 port->mp_Node.ln_Pri = 20;
1749 AddPort(port);
1750 WaitPort(port);
1751 RemPort(port);
1752 ud = (struct UnitData*)GetMsg(port);
1753 if ((ud->ud_GoWriteBit = AllocSignal(-1)) != -1)
1755 ud->ud_GoWriteMask = 1 << ud->ud_GoWriteBit;
1756 MainLoop(ud, port);
1757 FreeSignal(ud->ud_GoWriteBit);
1759 DeleteMsgPort(port);
1760 Forbid();
1761 ReplyMsg(&ud->ud_Message);
1763 return;