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,
23 /// includes and defines
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>
51 #define TX_BUFFER 0x40
52 #define RX_BUFFER 0x46
53 #define BUFFER_END 0x80
54 #define INTMASK (INT_RXPACKET | INT_TXPACKET | INT_TXERROR)
58 #define PCI_VENDOR_REALTEK 0x10EC
59 #define PCI_DEVICE_RTL8029 0x8029
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).
70 #if defined(__mc68000) && !defined(__AROS__)
71 #define _REG(A, B) B __asm(#A)
72 #define REG(A, B) _REG(A, B)
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).
87 // Macros for debug messages.
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)
111 #define DBG2_U(a,b,c)
112 #define DBG2_T(a,b,c)
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
135 struct Library dd_Lib
;
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
;
154 struct Message ud_Message
;
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
;
169 ULONG ud_GoWriteMask
;
170 UWORD ud_RxBuffer
[768];
172 UBYTE ud_EtherAddress
[6];
173 UBYTE ud_SoftAddress
[6];
174 struct Sana2DeviceStats ud_DevStats
;
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
));
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
);
238 /// tables and constants
240 extern struct Resident romtag
;
241 const UBYTE IdString
[] = DEV_IDSTRING
;
243 const void *FuncTable
[] =
254 UWORD NSDSupported
[] =
260 S2_GETSTATIONADDRESS
,
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
))
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
))
299 for (i
= 0; i
< 4; i
++) dd
->dd_Units
[i
] = NULL
;
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
);
307 DBG1("Device initialized, base at $%08lx.", dd
);
308 AddDevice((struct Device
*)dd
);
311 CloseDeviceLibraries(dd
);
319 LONG
DevOpen(REG(a1
, struct IOSana2Req
*req
), REG(d0
, LONG unit
),
320 REG(d1
, LONG flags
), REG(a6
, struct DevData
*dd
))
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.");
342 DBG("PrepareCookie() failed.");
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
;
356 APTR
DevClose(REG(a1
, struct IOSana2Req
*req
), REG(a6
, struct DevData
*dd
))
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
));
377 APTR
DevExpunge(REG(a6
, struct DevData
*dd
))
383 if (dd
->dd_Lib
.lib_OpenCnt
)
385 dd
->dd_Lib
.lib_Flags
|= LIBF_DELEXP
;
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.");
400 LONG
DevReserved (void)
408 void DevBeginIO(REG(a1
, struct IOSana2Req
*req
),
409 REG(a6
, struct DevData
*dd
))
413 struct UnitData
*ud
= (struct UnitData
*)req
->ios2_Req
.io_Unit
;
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;
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
);
433 for (i
= 0; i
< 6; i
++) req
->ios2_DstAddr
[i
] = 0xFF;
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
);
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
);
447 DBG1("DevBeginIo(): unknown command code %ld.", req
->ios2_Req
.io_Command
);
448 IoDone(ud
, req
, IOERR_NOCMD
, S2WERR_GENERIC_ERROR
);
457 ULONG
DevAbortIO(REG(a1
, struct IOSana2Req
*req
),
458 REG(a6
, struct DevData
*dd
))
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
)
471 list
= &ud
->ud_RxQueue
;
476 list
= &ud
->ud_TxQueue
;
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
);
500 else ret
= IOERR_NOCMD
;
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
)
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
);
523 /// OpenDeviceLibraries(struct DevData *dd)
525 LONG
OpenDeviceLibraries(struct DevData
*dd
)
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
;
541 /// CloseDeviceLibraries(struct DevData *dd)
543 void CloseDeviceLibraries(struct DevData
*dd
)
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
)
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
;
579 else FreeMem(bfun
, sizeof(struct BuffFunctions
));
586 /// RunTask(struct DevData *dd, struct UnitData *ud)
588 LONG
RunTask(struct DevData
*dd
, struct UnitData
*ud
)
592 const struct TagItem task_tags
[] =
594 {NP_Entry
, (IPTR
)UnitTask
},
595 {NP_Name
, (IPTR
)ud
->ud_Name
},
600 DBG("RunTask() called.");
602 if(ud
->ud_LifeTime
= CreateMsgPort())
604 if (ud
->ud_Task
= (struct Task
*)CreateNewProc(task_tags
))
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);
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
);
628 /// KillTask(struct DevData *dd, struct UnitData *ud)
630 void KillTask(struct DevData
*dd
, struct UnitData
*ud
)
635 Signal(ud
->ud_Task
, SIGBREAKF_CTRL_C
);
636 WaitPort(ud
->ud_LifeTime
);
637 GetMsg(ud
->ud_LifeTime
);
638 DeleteMsgPort(ud
->ud_LifeTime
);
644 /// ClearGlobalStats()
646 void ClearGlobalStats(struct UnitData
*ud
)
650 ud
->ud_DevStats
.PacketsReceived
= 0;
651 ud
->ud_DevStats
.PacketsSent
= 0;
652 GetSysTime(&ud
->ud_DevStats
.LastStart
);
659 struct UnitData
*OpenUnit(struct DevData
*dd
, LONG unit
, LONG flags
)
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. */
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. */
689 DBG2("%s opened [%ld].", ud
->ud_Name
, ud
->ud_OpenCnt
);
696 void CloseUnit(struct DevData
*dd
, struct UnitData
*ud
)
700 DBG1("%s closed.", ud
->ud_Name
);
701 if (!(--ud
->ud_OpenCnt
)) ExpungeUnit(dd
, ud
);
708 struct UnitData
*InitializeUnit(struct DevData
*dd
, LONG unit
)
717 DBG("InitializeUnit() called.");
718 if (ud
= AllocMem(sizeof(struct UnitData
), MEMF_PUBLIC
| MEMF_CLEAR
))
720 if (ud
->ud_Hardware
= FindHardware(dd
, unit
, ud
))
723 ud
->debug
= dd
->debug
;
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
;
749 dd
->dd_Units
[unit
] = ud
;
750 DBG1("%s initialized.", (LONG
)ud
->ud_Name
);
762 void ExpungeUnit(struct DevData
*dd
, struct UnitData
*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
);
782 // IMMEDIATE DEVICE COMMANDS
786 void S2DeviceQuery(struct UnitData
*ud
, struct IOSana2Req
*req
)
789 struct Sana2DeviceQuery
*query
= req
->ios2_StatData
;
791 DBG_U("S2_DEVICEQUERY.");
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;
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
);
812 /// S2GetStationAddress()
814 void S2GetStationAddress(struct UnitData
*ud
, struct IOSana2Req
*req
)
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
);
829 void S2Online(struct UnitData
*ud
, struct IOSana2Req
*req
)
834 ClearGlobalStats(ud
);
835 if (!(ud
->ud_Flags
& UF_ONLINE
))
838 ud
->ud_Flags
|= UF_ONLINE
;
839 IoDone(ud
, req
, OK
, OK
);
841 else IoDone(ud
, req
, S2ERR_BAD_STATE
, S2WERR_UNIT_ONLINE
);
846 /// S2ConfigInterface()
848 BOOL
address_has_all(UBYTE
*addr
, UBYTE num
)
852 for (i
= 5; i
>= 0; i
--)
854 if (addr
[i
] != num
) return FALSE
;
860 void S2ConfigInterface(struct UnitData
*ud
, struct IOSana2Req
*req
)
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
);
879 CopyMem(req
->ios2_SrcAddr
, ud
->ud_SoftAddress
, 6);
881 if (!(ud
->ud_Flags
& UF_ONLINE
))
884 ud
->ud_Flags
|= UF_ONLINE
;
886 ud
->ud_Flags
|= UF_CONFIGURED
;
887 IoDone(ud
, req
, OK
, OK
);
895 void S2Offline(struct UnitData
*ud
, struct IOSana2Req
*req
)
899 DBG_U("S2_OFFLINE.");
900 if (ud
->ud_Flags
& UF_ONLINE
)
903 ud
->ud_Flags
&= ~UF_ONLINE
;
904 IoDone(ud
, req
, OK
, OK
);
906 else IoDone(ud
, req
, S2ERR_BAD_STATE
, S2WERR_UNIT_OFFLINE
);
911 /// S2GetGlobalStats()
913 void S2GetGlobalStats(struct UnitData
*ud
, struct IOSana2Req
*req
)
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
);
928 void CmdNSDQuery(struct UnitData
*ud
, struct IOStdReq
*req
)
932 struct NSDeviceQueryResult
*qdata
;
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
);
964 // HARDWARE ACCESS FUNCTIONS
968 LONG
IntCode(REG(a1
, struct UnitData
*ud
))
972 struct IOSana2Req
*req
;
975 while (intstatus
= (BYTEIN(ud
->ud_Hardware
+ NE2000_INT_STATUS
)
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
);
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
);
997 if (intstatus
& INT_RXPACKET
)
1000 UWORD mask
= 0xFFFF;
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;
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
];
1020 req
->ios2_Req
.io_Flags
|= SANA2IOF_BCAST
;
1021 ud
->ud_DevStats
.PacketsReceived
++;
1022 IoDone(ud
, req
, OK
, OK
);
1032 /// InstallInterrupt()
1034 LONG
InstallInterrupt(struct UnitData
*ud
)
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
;
1045 intr
->is_Code
= (APTR
)IntCode
;
1046 Prm_AddIntServer(ud
->ud_Board
, intr
);
1047 ud
->ud_Interrupt
= intr
;
1054 /// RemoveInterrupt()
1056 void RemoveInterrupt(struct UnitData
*ud
)
1059 USE_U(PrometheusBase
)
1061 Prm_RemIntServer(ud
->ud_Board
, ud
->ud_Interrupt
);
1062 FreeMem(ud
->ud_Interrupt
, sizeof(struct Interrupt
));
1069 IPTR
FindHardware(struct DevData
*dd
, WORD unit
, struct UnitData
*ud
)
1078 board
= Prm_FindBoardTags(board
,
1079 PRM_Vendor
, PCI_VENDOR_REALTEK
,
1080 PRM_Device
, PCI_DEVICE_RTL8029
,
1087 ud
->ud_Board
= board
;
1088 Prm_GetBoardAttrsTags(board
,
1089 PRM_MemoryAddr0
, (IPTR
)&hwbase
,
1091 Prm_SetBoardAttrsTags(board
,
1092 PRM_BoardOwner
, (IPTR
)dd
,
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);
1126 void HardwareReset (struct UnitData
*ud
)
1129 IPTR hw
= ud
->ud_Hardware
;
1132 WORDOUT(hw
+ NE2000_RESET_PORT
, trash
);
1134 trash
= WORDIN(hw
+ NE2000_RESET_PORT
);
1142 void GoOnline (struct UnitData
*ud
)
1144 IPTR hw
= ud
->ud_Hardware
;
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
);
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
);
1178 void BoardShutdown(struct UnitData
*ud
)
1180 IPTR hw
= ud
->ud_Hardware
;
1183 BYTEOUT(hw
+ NE2000_INT_MASK
, 0);
1184 BYTEOUT(hw
+ NE2000_INT_STATUS
, 0xFF);
1189 /// GetPacketHeader()
1191 ULONG
GetPacketHeader(IPTR ne
, UBYTE page
)
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;
1209 /*GetPacket(volatile struct Ne2000 *ne, UBYTE startpage, UWORD len, UWORD *buffer)*/
1210 VOID
GetPacket(IPTR ne
, UBYTE startpage
, UWORD len
, UWORD
*buffer
)
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
);
1228 /// PacketReceived()
1230 LONG
PacketReceived(struct UnitData
*ud
)
1234 header
= GetPacketHeader(ud
->ud_Hardware
, ud
->ud_NextPage
);
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
);
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
);
1255 BYTEOUT(hw
+ NE2000_DMA_COUNTER0
, 0);
1256 BYTEOUT(hw
+ NE2000_DMA_COUNTER1
, 0);
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
);
1284 void SendPacket(struct UnitData
*ud
, struct IOSana2Req
*req
)
1288 IPTR hw
= ud
->ud_Hardware
;
1289 UBYTE ethbuffer
[1536], *datapointer
;
1290 UWORD
*ethdata
= (UWORD
*)ethbuffer
;
1291 ULONG data_len
= req
->ios2_DataLength
;
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. */
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
);
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.");
1362 void GetHwAddress(struct UnitData
*ud
)
1365 IPTR hw
= ud
->ud_Hardware
;
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
);
1377 DBG_U("\thardware address (read):");
1378 for (i
= 0; i
< 6; i
++) DBG1_U("\t%02lx", ud
->ud_EtherAddress
[i
]);
1385 /// WriteHwAddress()
1387 void WriteHwAddress(struct UnitData
*ud
)
1390 IPTR hw
= ud
->ud_Hardware
;
1394 DBG_U("\thardware address (write):");
1395 for (i
= 0; i
< 6; i
++) DBG1_U("\t%02lx", ud
->ud_SoftAddress
[i
]);
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
);
1410 /// RingBufferNotEmpty()
1412 LONG
RingBufferNotEmpty(struct UnitData
*ud
)
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
;
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
);
1456 void FlushQueues(struct UnitData
*ud
)
1460 struct IOSana2Req
*xreq
;
1465 xreq
= (struct IOSana2Req
*)RemHead((struct List
*)&ud
->ud_RxQueue
);
1468 DBG1_T("<- READ [$08%lx] [F].", xreq
);
1469 IoDone(ud
, xreq
, IOERR_ABORTED
, S2WERR_GENERIC_ERROR
);
1475 xreq
= (struct IOSana2Req
*)RemHead((struct List
*)&ud
->ud_TxQueue
);
1478 DBG1_T("<- WRITE [$08%lx] [F].", xreq
);
1479 IoDone(ud
, xreq
, IOERR_ABORTED
, S2WERR_GENERIC_ERROR
);
1487 void MainLoop(struct UnitData
*ud
, struct MsgPort
*port
)
1491 ULONG signals
, sigmask
;
1492 struct IOSana2Req
*req
;
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
);
1503 sigmask
= 1 << port
->mp_SigBit
;
1506 DBG_T("Waiting...");
1507 signals
= Wait(SIGBREAKF_CTRL_C
| sigmask
| ud
->ud_GoWriteMask
);
1509 if (signals
& ud
->ud_GoWriteMask
)
1513 req
= (struct IOSana2Req
*)RemHead((struct List
*)&ud
->ud_TxQueue
);
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
);
1525 if (signals
& sigmask
)
1527 struct IOSana2Req
*req
;
1530 while (req
= (struct IOSana2Req
*)GetMsg(port
))
1532 switch (req
->ios2_Req
.io_Command
)
1535 DBG1_T("-> READ [$%08lx].", req
);
1537 AddTail((struct List
*)&ud
->ud_RxQueue
, (struct Node
*)req
);
1543 DBG1_T("-> WRITE [$%08lx].", req
);
1544 if (ud
->ud_PendingWrite
)
1547 AddTail((struct List
*)&ud
->ud_TxQueue
, (struct Node
*)req
);
1552 ud
->ud_PendingWrite
= req
;
1553 SendPacket(ud
, req
);
1554 DBG_T("Packet sent 2.");
1559 DBG1_T("-> FLUSH [$%08lx].", req
);
1561 DBG1_T("<- FLUSH [$%08lx].", req
);
1562 IoDone(ud
, req
, OK
, OK
);
1566 DBG2_T("-> Unknown ($%lx) [$%08lx].", req
->ios2_Req
.io_Command
, req
);
1578 struct Library
*SysBase
= *(struct Library
**)4;
1580 struct MsgPort
*port
;
1581 struct UnitData
*ud
;
1584 struct Library
*DOSBase
;
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;
1595 ud
= (struct UnitData
*)GetMsg(port
);
1596 if ((ud
->ud_GoWriteBit
= AllocSignal(-1)) != -1)
1598 ud
->ud_GoWriteMask
= 1 << ud
->ud_GoWriteBit
;
1600 FreeSignal(ud
->ud_GoWriteBit
);
1602 DeleteMsgPort(port
);
1604 ReplyMsg(&ud
->ud_Message
);