Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / usb / classes / ethwrap / dev.c
blob2583b3031416eaab09a4ecd69e31384230c7dc89
1 /* dev.c - usbethwrap.device by Chris Hodges
2 */
4 #include "debug.h"
6 #include "ethwrap.class.h"
8 AROS_UFH3(DEVBASETYPEPTR, devInit,
9 AROS_UFHA(DEVBASETYPEPTR, base, D0),
10 AROS_UFHA(BPTR, seglist, A0),
11 AROS_UFHA(struct ExecBase *, SysBase, A6))
13 AROS_USERFUNC_INIT
15 KPRINTF(10, ("devInit base: 0x%08lx seglist: 0x%08lx SysBase: 0x%08lx\n",
16 base, seglist, SysBase));
18 base->np_Library.lib_Node.ln_Type = NT_DEVICE;
19 base->np_Library.lib_Node.ln_Name = DEVNAME;
20 base->np_Library.lib_Flags = LIBF_SUMUSED|LIBF_CHANGED;
21 base->np_Library.lib_Version = VERSION_NUMBER;
22 base->np_Library.lib_Revision = REVISION_NUMBER;
23 base->np_Library.lib_IdString = VERSION_STRING;
25 /* Store segment */
26 base->np_SegList = seglist;
28 if((base->np_UtilityBase = OpenLibrary("utility.library", 0)))
30 KPRINTF(10, ("devInit: Ok\n"));
31 KPRINTF(10, ("devInit: openCnt = %ld\n", base->np_Library.lib_OpenCnt));
32 return(base);
34 else
36 return(NULL);
38 return(base);
40 AROS_USERFUNC_EXIT
43 #undef UtilityBase
44 #define UtilityBase base->np_UtilityBase
46 AROS_LH3(DEVBASETYPEPTR, devOpen,
47 AROS_LHA(struct IOSana2Req *, ioreq, A1),
48 AROS_LHA(ULONG, unit, D0),
49 AROS_LHA(ULONG, flags, D1),
50 DEVBASETYPEPTR, base, 1, dev)
52 AROS_LIBFUNC_INIT
54 struct NepClassEth *ncp;
55 struct TagItem *taglist;
57 KPRINTF(10, ("devOpen ioreq: 0x%08lx unit: %ld flags: 0x%08lx base: 0x%08lx\n",
58 ioreq, unit, flags, base));
60 ++base->np_Library.lib_OpenCnt;
61 base->np_Library.lib_Flags &= ~LIBF_DELEXP;
63 KPRINTF(10, ("devOpen: openCnt = %ld\n", base->np_Library.lib_OpenCnt));
64 /* Damn f*cking programs which leave this field to zero! */
65 if(ioreq->ios2_Req.io_Message.mn_Length && (ioreq->ios2_Req.io_Message.mn_Length < sizeof(struct IOSana2Req)))
67 KPRINTF(20, ("devOpen: invalid MN_LENGTH (%ld < %ld)!\n",
68 ioreq->ios2_Req.io_Message.mn_Length, sizeof(struct IOSana2Req)));
70 ioreq->ios2_Req.io_Error = IOERR_BADLENGTH;
71 } else {
72 /* Default to open failure. */
73 ioreq->ios2_Req.io_Error = IOERR_OPENFAIL;
75 ioreq->ios2_Req.io_Unit = NULL;
76 ncp = (struct NepClassEth *) base->np_ClsBase->nh_Units.lh_Head;
77 while(ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
79 if(ncp->ncp_UnitNo == unit)
81 if(ncp->ncp_OpenFlags & SANA2OPF_MINE)
83 ioreq->ios2_Req.io_Error = IOERR_UNITBUSY;
84 } else {
85 ioreq->ios2_Req.io_Unit = (struct Unit *) ncp;
87 break;
89 ncp = (struct NepClassEth *) ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
92 if(!ioreq->ios2_Req.io_Unit)
94 ioreq->ios2_Req.io_Error = IOERR_OPENFAIL;
95 KPRINTF(20, ("devOpen: could not open unit!\n"));
96 } else {
97 ncp->ncp_OpenFlags |= flags;
99 /* Got taglist? (don't fail if not available!) */
100 taglist = (struct TagItem *) ioreq->ios2_BufferManagement;
101 if(taglist)
103 struct BufMan *bufman;
105 bufman = (struct BufMan *) AllocVec(sizeof(struct BufMan), MEMF_CLEAR|MEMF_PUBLIC);
106 if(bufman)
108 /* Get copyfrom routines */
109 bufman->bm_CopyFromBuf = (APTR) GetTagData(S2_CopyFromBuff, (IPTR) NULL, taglist);
110 bufman->bm_CopyToBuf = (APTR) GetTagData(S2_CopyToBuff, (IPTR) NULL, taglist);
112 /* This is new SANA-II V2 addition */
113 bufman->bm_PacketFilter = (APTR) GetTagData(S2_PacketFilter, (IPTR) NULL, taglist);
115 /* These are new SANA-II V3 addition */
116 bufman->bm_DMACopyFromBuf32 = (APTR) GetTagData(S2_DMACopyFromBuff32, (IPTR) NULL, taglist);
117 bufman->bm_DMACopyToBuf32 = (APTR) GetTagData(S2_DMACopyToBuff32, (IPTR) NULL, taglist);
119 /* Init the list for CMD_READ requests */
120 NewList((struct List *) &bufman->bm_RXQueue);
122 /* Add the new bufman to global bufmanlist */
123 KPRINTF(5, ("Open_Unit: added bufman at 0x%08lx\n", bufman));
124 Forbid();
125 AddHead((struct List *) &ncp->ncp_BufManList, (struct Node *) bufman);
126 Permit();
128 ioreq->ios2_BufferManagement = bufman;
130 KPRINTF(5, ("Open_Unit:\n"
131 "copyfrombuf: 0x%08lx copytobuf: 0x%08lx packetfilter: 0x%08lx\n"
132 "dmacopyfrombuf32: 0x%08lx dmacopytobuf32: 0x%08lx\n",
133 bufman->bm_CopyFromBuf, bufman->bm_CopyToBuf, bufman->bm_PacketFilter,
134 bufman->bm_DMACopyFromBuf32, bufman->bm_DMACopyToBuf32));
136 /* Opended ok! */
137 ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
138 ioreq->ios2_Req.io_Error = 0;
139 ioreq->ios2_Req.io_Unit->unit_OpenCnt++;
141 /* Allow queuing */
142 //ncp->ncp_DenyRequests = FALSE;
144 return base;
148 ioreq->ios2_Req.io_Unit = (APTR) -1;
149 ioreq->ios2_Req.io_Device = (APTR) -1;
150 base->np_Library.lib_OpenCnt--;
152 return(NULL);
154 AROS_LIBFUNC_EXIT
158 AROS_LH1(BPTR, devClose,
159 AROS_LHA(struct IOSana2Req *, ioreq, A1),
160 DEVBASETYPEPTR, base, 2, dev)
162 AROS_LIBFUNC_INIT
164 BPTR ret;
165 struct NepClassEth *ncp = (struct NepClassEth *) ioreq->ios2_Req.io_Unit;
166 struct BufMan *bufman;
168 KPRINTF(10, ("devClose ioreq: 0x%08lx base: 0x%08lx\n", ioreq, base));
170 ret = BNULL;
171 /* Allow queuing */
172 //ncp->ncp_DenyRequests = TRUE;
174 ncp->ncp_Unit.unit_OpenCnt--;
175 if(ncp->ncp_Unit.unit_OpenCnt == 1)
177 ncp->ncp_OpenFlags = 0; // clear all flags, if all units are closed
180 ioreq->ios2_Req.io_Unit = (APTR) -1;
181 ioreq->ios2_Req.io_Device = (APTR) -1;
183 bufman = ioreq->ios2_BufferManagement;
184 if(bufman)
186 KPRINTF(5, ("Close_Unit: remove bufman at 0x%08lx\n", bufman));
187 ioreq->ios2_BufferManagement = NULL;
189 Forbid();
190 Remove((struct Node *) bufman);
191 Permit();
192 FreeVec(bufman);
195 if(--base->np_Library.lib_OpenCnt == 0)
197 if(base->np_Library.lib_Flags & LIBF_DELEXP)
199 KPRINTF(5, ("devClose: calling expunge...\n"));
200 ret = AROS_LC1(BPTR, devExpunge,
201 AROS_LCA(DEVBASETYPEPTR, base, D0),
202 DEVBASETYPEPTR, base, 3, dev);
206 KPRINTF(5, ("devClose: lib_OpenCnt = %ld\n", base->np_Library.lib_OpenCnt));
208 return(ret);
210 AROS_LIBFUNC_EXIT
214 AROS_LH1(BPTR, devExpunge,
215 AROS_LHA(DEVBASETYPEPTR, extralh, D0),
216 DEVBASETYPEPTR, base, 3, dev)
218 AROS_LIBFUNC_INIT
220 BPTR ret;
222 KPRINTF(10, ("devExpunge base: 0x%08lx\n", base));
224 ret = BNULL;
226 if(base->np_Library.lib_OpenCnt == 0)
228 KPRINTF(5, ("devExpunge: Unloading...\n"));
230 CloseLibrary(base->np_UtilityBase);
232 ret = base->np_SegList;
234 KPRINTF(5, ("devExpunge: removing device node 0x%08lx\n",
235 &base->np_Library.lib_Node));
236 Remove(&base->np_Library.lib_Node);
238 KPRINTF(5, ("devExpunge: FreeMem()...\n"));
239 FreeMem((char *) base - base->np_Library.lib_NegSize,
240 (ULONG) (base->np_Library.lib_NegSize + base->np_Library.lib_PosSize));
242 KPRINTF(5, ("devExpunge: Unloading done! " DEVNAME " expunged!\n\n"));
244 return(ret);
246 else
248 KPRINTF(5, ("devExpunge: Could not expunge, LIBF_DELEXP set!\n"));
249 base->np_Library.lib_Flags |= LIBF_DELEXP;
252 return(BNULL);
254 AROS_LIBFUNC_EXIT
257 AROS_LH0(DEVBASETYPEPTR, devReserved,
258 DEVBASETYPEPTR, base, 4, dev)
260 AROS_LIBFUNC_INIT
261 return NULL;
262 AROS_LIBFUNC_EXIT
267 *======================================================================
268 * cmdRead(ioreq, base)
269 *======================================================================
271 * This is the device CMD_READ routine.
273 * First it check if nic is in proper state and if user passed arguments
274 * are valid. If everything is ok, the request is linked to queue of
275 * pending read requests.
277 * The request is replied only when packet matching it's ios2_PacketType
278 * arrive, or if user abort the request with AbortIO().
282 WORD cmdRead(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
284 struct BufMan *bufman;
285 KPRINTF(1, ("CMD_READ ioreq: 0x%08lx type: %lu\n", ioreq, ioreq->ios2_PacketType));
287 /* Configured? */
288 if(!(ncp->ncp_StateFlags & DDF_CONFIGURED))
290 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_CONFIGURED);
293 /* Online? */
294 if(!(ncp->ncp_StateFlags & DDF_ONLINE))
296 return deverror(S2ERR_OUTOFSERVICE, S2WERR_UNIT_OFFLINE);
299 /* Valid bufman? Got copytobuf routine? */
300 bufman = ioreq->ios2_BufferManagement;
301 if((!bufman) || (!bufman->bm_CopyToBuf))
303 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
306 /* Must be queued */
307 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
309 /* Add to this ioreq's bufman rxqueue */
310 Forbid();
311 AddTail((struct List *) &bufman->bm_RXQueue, (struct Node *) ioreq);
312 Permit();
313 /* Don't reply the ioreq, it's pending
315 return RC_DONTREPLY;
320 *======================================================================
321 * cmdWrite(ioreq, base)
322 *======================================================================
324 * This is the device CMD_WRITE routine.
326 * First it check if nic is in proper state and if user passed arguments
327 * are valid. If everything is ok, the request is linked to queue of
328 * pending write requests.
330 * The request is replied as soon as the write has been processed or if
331 * user abort the request with AbortIO().
335 WORD cmdWrite(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
337 struct BufMan *bufman;
338 int size;
340 KPRINTF(1, ("CMD_WRITE ioreq: 0x%08lx type: %lu len: %lu\n",
341 ioreq, ioreq->ios2_PacketType, ioreq->ios2_DataLength));
343 /* Configured? */
344 if(!(ncp->ncp_StateFlags & DDF_CONFIGURED))
346 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_CONFIGURED);
349 /* Online? */
350 if(!(ncp->ncp_StateFlags & DDF_ONLINE))
352 return deverror(S2ERR_OUTOFSERVICE, S2WERR_UNIT_OFFLINE);
355 /* Valid bufman? got copyfrombuf routine? */
356 bufman = ioreq->ios2_BufferManagement;
357 if((!bufman) || (!bufman->bm_CopyFromBuf))
359 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
362 /* Check packet size */
363 size = (ioreq->ios2_Req.io_Flags & SANA2IOF_RAW) ? RAWPKT_SIZE : ETHERPKT_SIZE;
364 if(ioreq->ios2_DataLength > size)
366 /* Trigger any tx or generic error events */
367 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_TX);
368 return deverror(S2ERR_MTU_EXCEEDED, S2WERR_GENERIC_ERROR);
371 /* Must be queued */
372 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
373 Forbid();
374 AddTail(&ncp->ncp_WriteQueue, &ioreq->ios2_Req.io_Message.mn_Node);
375 if(ncp->ncp_Unit.unit_MsgPort.mp_SigTask)
377 Signal(ncp->ncp_Unit.unit_MsgPort.mp_SigTask, 1L<<(ncp->ncp_Unit.unit_MsgPort.mp_SigBit));
379 Permit();
380 /* Don't reply the ioreq, it's pending */
381 return RC_DONTREPLY;
386 *======================================================================
387 * cmdFlush(ioreq, base)
388 *======================================================================
390 * This is the device CMD_FLUSH routine.
392 * This routine abort all pending read, write and event requests.
396 WORD cmdFlush(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
398 struct BufMan *bufman;
400 KPRINTF(1, ("CMD_FLUSH ioreq: 0x%08lx\n", ioreq));
402 bufman = ioreq->ios2_BufferManagement;
403 if(bufman)
405 Forbid();
406 AbortRW(ncp, bufman, deverror(IOERR_ABORTED, S2WERR_GENERIC_ERROR));
407 AbortList(ncp, &ncp->ncp_EventList, bufman, deverror(IOERR_ABORTED, S2WERR_GENERIC_ERROR));
408 Permit();
411 /* Return success */
412 return RC_OK;
417 *======================================================================
418 * cmdDeviceQuery(ioreq, base)
419 *======================================================================
421 * This is the device S2_DEVICEQUERY routine.
423 * This routine return various parameters for this network interface.
427 static
428 const struct Sana2DeviceQuery DeviceQueryBlock[] =
431 sizeof(struct Sana2DeviceQuery), sizeof(struct Sana2DeviceQuery),
432 0, 0,
433 ETHER_ADDR_SIZE * 8,
434 ETHERPKT_SIZE,
435 10000000,
436 S2WireType_Ethernet
441 WORD cmdDeviceQuery(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
443 struct Sana2DeviceQuery *query;
445 KPRINTF(1, ("S2_DEVICEQUERY ioreq: 0x%08lx\n", ioreq));
447 /* NULL ptr? */
448 query = (struct Sana2DeviceQuery *) ioreq->ios2_StatData;
449 if(!query)
451 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
454 /* Enough space to store the info ? */
455 if(query->SizeAvailable < sizeof(struct Sana2DeviceQuery))
457 KPRINTF(1, ("S2_DEVICEQUERY: too small buffer supplied! (%lu / %lu)\n",
458 query->SizeAvailable, sizeof(struct Sana2DeviceQuery)));
460 query->SizeSupplied = 0;
461 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_BAD_STATDATA);
464 CopyMem(&((struct Sana2DeviceQuery *) DeviceQueryBlock)->SizeSupplied, &query->SizeSupplied, sizeof(struct Sana2DeviceQuery) - sizeof(ULONG));
466 /* Return success */
467 return RC_OK;
471 *======================================================================
472 * cmdGetStationAddress(ioreq, base)
473 *======================================================================
475 * This is the device S2_GETSTATIONADDRESS routine.
477 * This routine return current and default interface hardware addresses.
481 WORD cmdGetStationAddress(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
483 UWORD cnt;
485 KPRINTF(1, ("S2_GETSTATIONADDRESS ioreq: 0x%08lx\n", ioreq));
487 /* Source address = current station address
488 Dest address = default station address
490 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
492 ioreq->ios2_SrcAddr[cnt] = ncp->ncp_MacAddress[cnt];
493 ioreq->ios2_DstAddr[cnt] = ncp->ncp_ROMAddress[cnt];
496 /* Clear the rest */
497 for(; cnt < SANA2_MAX_ADDR_BYTES; cnt++)
499 ioreq->ios2_SrcAddr[cnt] = 0;
500 ioreq->ios2_DstAddr[cnt] = 0;
503 /* Return success */
504 return(RC_OK);
507 WORD cmdConfigInterface(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
509 UWORD cnt;
511 KPRINTF(1, ("S2_CONFIGINTERFACE ioreq: 0x%08lx\n", ioreq));
513 /* This stuff must be atomic */
514 Forbid();
515 if(ncp->ncp_StateFlags & DDF_CONFIGURED)
517 Permit();
518 /* Error, already configured */
519 return deverror(S2ERR_BAD_STATE, S2WERR_IS_CONFIGURED);
522 /* Check for valid address */
523 if(ioreq->ios2_SrcAddr[0] & 0x80)
525 Permit();
526 return deverror(S2ERR_BAD_ADDRESS, S2WERR_SRC_ADDRESS);
529 /* Copy the address */
530 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
532 ncp->ncp_MacAddress[cnt] = ioreq->ios2_SrcAddr[cnt];
535 ncp->ncp_StateFlags |= DDF_CONFIGURED;
536 if(ncp->ncp_Unit.unit_MsgPort.mp_SigTask)
538 Signal(ncp->ncp_Unit.unit_MsgPort.mp_SigTask, 1L<<(ncp->ncp_Unit.unit_MsgPort.mp_SigBit));
540 Permit();
541 return(RC_OK);
544 WORD cmdAddMulticastAddress(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
547 KPRINTF(1, ("S2_ADDMULTICASTADDRESS 0x%08lx%04lx\n",
548 ((ULONG *) ioreq->ios2_SrcAddr)[0], ((UWORD *) ioreq->ios2_SrcAddr)[2]));
550 return AddMCastRange(ncp, ioreq, ioreq->ios2_SrcAddr, ioreq->ios2_SrcAddr);
553 WORD cmdDelMulticastAddress(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
555 KPRINTF(1, ("S2_DELMULTICASTADDRESS 0x%08lx%04lx\n",
556 ((ULONG *) ioreq->ios2_SrcAddr)[0], ((UWORD *) ioreq->ios2_SrcAddr)[2]));
558 return DelMCastRange(ncp, ioreq, ioreq->ios2_SrcAddr, ioreq->ios2_SrcAddr);
561 WORD cmdAddMulticastAddresses(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
563 KPRINTF(1, ("S2_ADDMULTICASTADDRESSES 0x%08lx%04lx - 0x%08lx%04lx\n",
564 ((ULONG *) ioreq->ios2_SrcAddr)[0], ((UWORD *) ioreq->ios2_SrcAddr)[2],
565 ((ULONG *) ioreq->ios2_DstAddr)[0], ((UWORD *) ioreq->ios2_DstAddr)[2]));
567 return AddMCastRange(ncp, ioreq, ioreq->ios2_SrcAddr, ioreq->ios2_DstAddr);
570 WORD cmdDelMulticastAddresses(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
572 KPRINTF(1, ("S2_DELMULTICASTADDRESSES 0x%08lx%04lx - 0x%08lx%04lx\n",
573 ((ULONG *) ioreq->ios2_SrcAddr)[0], ((UWORD *) ioreq->ios2_SrcAddr)[2],
574 ((ULONG *) ioreq->ios2_DstAddr)[0], ((UWORD *) ioreq->ios2_DstAddr)[2]));
576 return DelMCastRange(ncp, ioreq, ioreq->ios2_SrcAddr, ioreq->ios2_DstAddr);
579 #define mcmp(a,b) (memcmp(a,b,ETHER_ADDR_SIZE)==0)
581 WORD AddMCastRange(struct NepClassEth *ncp, struct IOSana2Req *ioreq, UBYTE *lower, UBYTE *upper)
583 struct MulticastAddressRange *mar;
584 WORD cnt;
586 /* Valid multicast addresses? */
587 if(((lower[0] & 1) == 0) || ((upper[0] & 1) == 0))
589 return deverror(S2ERR_BAD_ADDRESS, S2WERR_BAD_MULTICAST);
592 /* Lock access to list */
593 Forbid();
595 /* Find matching node */
596 mar = (struct MulticastAddressRange *) ncp->ncp_Multicasts.lh_Head;
597 while(mar->mar_Node.ln_Succ)
599 if(mcmp(lower, mar->mar_LowerAddr) &&
600 mcmp(upper, mar->mar_UpperAddr))
602 break;
604 mar = (struct MulticastAddressRange *) mar->mar_Node.ln_Succ;
607 if(!mar->mar_Node.ln_Succ)
609 /* Add new node */
610 mar = AllocVec(sizeof(struct MulticastAddressRange), MEMF_CLEAR|MEMF_PUBLIC);
611 if(!mar)
613 Permit();
614 return deverror(S2ERR_NO_RESOURCES, S2WERR_GENERIC_ERROR);
616 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
618 mar->mar_LowerAddr[cnt] = *lower++;
619 mar->mar_UpperAddr[cnt] = *upper++;
621 mar->mar_UseCount = 1;
622 AddTail(&ncp->ncp_Multicasts, (struct Node *) mar);
624 Permit();
626 return RC_OK;
628 mar->mar_UseCount++;
629 Permit();
631 /* Return success */
632 return RC_OK;
635 WORD DelMCastRange(struct NepClassEth *ncp, struct IOSana2Req *ioreq, UBYTE *lower, UBYTE *upper)
637 struct MulticastAddressRange *mar;
639 /* Lock access to list */
640 Forbid();
642 /* Find matching node */
643 mar = (struct MulticastAddressRange *) ncp->ncp_Multicasts.lh_Head;
644 while(mar->mar_Node.ln_Succ)
646 if(mcmp(lower, mar->mar_LowerAddr) &&
647 mcmp(upper, mar->mar_UpperAddr))
649 if(!--mar->mar_UseCount)
651 Remove((struct Node *) mar);
652 Permit();
653 FreeVec(mar);
655 return RC_OK;
657 Permit();
658 return RC_OK;
660 mar = (struct MulticastAddressRange *) mar->mar_Node.ln_Succ;
662 Permit();
664 /* Return with failure */
665 return deverror(S2ERR_BAD_STATE, S2WERR_BAD_MULTICAST);
668 WORD cmdMulticast(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
670 KPRINTF(1, ("S2_MULTICAST ioreq: 0x%08lx to: 0x%08lx%04lx\n",
671 ioreq,
672 ((ULONG *) ioreq->ios2_DstAddr)[0], ((UWORD *) ioreq->ios2_DstAddr)[2]));
674 /* Is dest a multicast address? */
675 if(ioreq->ios2_DstAddr[0] & 1)
677 return cmdWrite(ncp, ioreq);
680 /* Trigger any tx or generic error events */
681 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_TX);
683 /* Wasn't a multicast addr */
684 return deverror(S2ERR_BAD_ADDRESS, S2WERR_BAD_MULTICAST);
687 WORD cmdBroadcast(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
689 UWORD cnt;
690 KPRINTF(1, ("S2_BROADCAST ioreq: 0x%08lx\n", ioreq));
692 /* Dest address = broadcast */
693 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
695 ioreq->ios2_DstAddr[cnt] = 0xff;
697 return cmdWrite(ncp, ioreq);
701 WORD cmdTrackType(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
703 struct PacketTypeStats *pts;
705 KPRINTF(1, ("S2_TRACKTYPE ioreq: 0x%08lx type: %lu\n",
706 ioreq, ioreq->ios2_PacketType));
708 Forbid();
709 /* Find matching node */
710 pts = (struct PacketTypeStats *) ncp->ncp_TrackList.lh_Head;
711 while(pts->pts_Node.ln_Succ)
713 /* Our packet type? */
714 if(pts->pts_PacketType == ioreq->ios2_PacketType)
716 Permit();
717 return deverror(S2ERR_BAD_STATE, S2WERR_ALREADY_TRACKED);
719 pts = (struct PacketTypeStats *) pts->pts_Node.ln_Succ;
722 /* Alloc tracking node */
723 pts = (struct PacketTypeStats *) AllocVec(sizeof(struct PacketTypeStats), MEMF_CLEAR|MEMF_PUBLIC);
724 if(!pts)
726 return deverror(S2ERR_NO_RESOURCES, S2WERR_NOT_TRACKED);
728 /* Set up tracking node */
729 pts->pts_PacketType = ioreq->ios2_PacketType;
731 /* Add the new node to tracklist */
732 AddTail((struct List *) &ncp->ncp_TrackList, (struct Node *) pts);
733 // caching
734 if(pts->pts_PacketType == 2048)
736 ncp->ncp_TypeStats2048 = &pts->pts_Stats;
738 else if(pts->pts_PacketType == 2054)
740 ncp->ncp_TypeStats2054 = &pts->pts_Stats;
742 Permit();
744 /* Return success */
745 return RC_OK;
749 WORD cmdUntrackType(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
751 struct PacketTypeStats *pts;
752 KPRINTF(1, ("S2_UNTRACKTYPE ioreq: 0x%08lx type: %lu\n",
753 ioreq, ioreq->ios2_PacketType));
755 Forbid();
756 /* Find matching node */
757 pts = (struct PacketTypeStats *) ncp->ncp_TrackList.lh_Head;
758 while(pts->pts_Node.ln_Succ)
760 /* Our packet type? */
761 if(pts->pts_PacketType == ioreq->ios2_PacketType)
763 Remove(&pts->pts_Node);
764 // caching
765 if(pts->pts_PacketType == 2048)
767 ncp->ncp_TypeStats2048 = NULL;
769 else if(pts->pts_PacketType == 2054)
771 ncp->ncp_TypeStats2054 = NULL;
773 Permit();
774 FreeVec(pts);
775 return RC_OK;
778 pts = (struct PacketTypeStats *) pts->pts_Node.ln_Succ;
780 Permit();
781 /* Return failure */
782 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_TRACKED);
786 WORD cmdGetTypeStats(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
788 struct Sana2PacketTypeStats *tostats;
789 struct Sana2PacketTypeStats *fromstats;
791 KPRINTF(1, ("S2_GETTYPESTATS ioreq: 0x%08lx type: %lu\n",
792 ioreq, ioreq->ios2_PacketType));
794 /* NULL ptr? */
795 tostats = (struct Sana2PacketTypeStats *) ioreq->ios2_StatData;
796 if(!tostats)
798 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
801 Forbid();
802 fromstats = FindPacketTypeStats(ncp, ioreq->ios2_PacketType);
803 if(fromstats)
805 /* Copy the stats */
806 CopyMem(fromstats, tostats, sizeof(struct Sana2PacketTypeStats));
807 Permit();
809 /* Return success */
810 return RC_OK;
812 Permit();
814 /* Return error */
815 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_TRACKED);
819 WORD cmdGetSpecialStats(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
821 struct Sana2SpecialStatHeader *stats;
822 struct Sana2SpecialStatRecord *record;
823 ULONG maxcount;
825 KPRINTF(1, ("S2_GETSPECIALSTATS ioreq: 0x%08lx\n", ioreq));
827 /* NULL ptr? */
828 stats = (struct Sana2SpecialStatHeader *) ioreq->ios2_StatData;
829 if(!stats)
831 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
834 stats->RecordCountSupplied = 0;
835 maxcount = stats->RecordCountMax;
836 record = (struct Sana2SpecialStatRecord *) (stats + 1);
838 if(maxcount--)
840 stats->RecordCountSupplied++;
842 record->Type = S2SS_ETHERNET_BADMULTICAST;
843 record->Count = ncp->ncp_BadMulticasts;
844 record->String = "bad multicasts";
845 record++;
847 if(maxcount--)
849 stats->RecordCountSupplied++;
851 record->Type = S2SS_ETHERNET_RETRIES;
852 record->Count = ncp->ncp_Retries;
853 record->String = "retries";
854 //record++;
858 /* Return success */
859 return RC_OK;
863 WORD cmdGetGlobalStats(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
865 struct Sana2DeviceStats *stats;
867 KPRINTF(1, ("S2_GETGLOBALSTATS ioreq: 0x%08lx\n", ioreq));
869 /* NULL ptr? */
870 stats = (struct Sana2DeviceStats *) ioreq->ios2_StatData;
871 if(!stats)
873 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
876 CopyMem(&ncp->ncp_DeviceStats, stats, sizeof(struct Sana2DeviceStats));
878 /* Return success */
879 return RC_OK;
883 #define KNOWN_EVENTS (S2EVENT_ERROR | \
884 S2EVENT_TX | \
885 S2EVENT_RX | \
886 S2EVENT_ONLINE | \
887 S2EVENT_OFFLINE | \
888 S2EVENT_BUFF | \
889 S2EVENT_HARDWARE)
891 WORD cmdOnEvent(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
893 KPRINTF(1, ("S2_ONEVENT ioreq: 0x%08lx mask: 0x%08lx\n", ioreq,
894 ioreq->ios2_WireError));
896 /* Do we know the requested events? */
897 if(ioreq->ios2_WireError & (~KNOWN_EVENTS))
899 return deverror(S2ERR_NOT_SUPPORTED, S2WERR_BAD_EVENT);
902 /* If online return S2EVENT_ONLINE immediately
903 If offline return S2EVENT_OFFLINE immediately. */
904 if(ncp->ncp_StateFlags & DDF_ONLINE)
906 if(ioreq->ios2_WireError & S2EVENT_ONLINE)
908 ioreq->ios2_WireError = S2EVENT_ONLINE;
910 /* Return success */
911 return RC_OK;
913 } else {
914 if(ioreq->ios2_WireError & S2EVENT_OFFLINE)
916 ioreq->ios2_WireError = S2EVENT_OFFLINE;
918 /* Return success */
919 return RC_OK;
923 /* Must be queued */
924 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
926 /* Queue the ioreq */
927 Forbid();
928 AddTail((struct List *) &ncp->ncp_EventList, (struct Node *) ioreq);
929 Permit();
931 /* Don't reply the ioreq, it's pending */
932 return RC_DONTREPLY;
936 WORD cmdReadOrphan(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
938 struct BufMan *bufman;
940 KPRINTF(1, ("S2_READORPHAN ioreq: 0x%08lx type: %lu\n", ioreq,
941 ioreq->ios2_PacketType));
943 /* Configured? */
944 if(!(ncp->ncp_StateFlags & DDF_CONFIGURED))
946 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_CONFIGURED);
949 /* Online? */
950 if(!(ncp->ncp_StateFlags & DDF_ONLINE))
952 return deverror(S2ERR_OUTOFSERVICE, S2WERR_UNIT_OFFLINE);
955 /* Valid bufman? got copytobuf routine? */
956 bufman = ioreq->ios2_BufferManagement;
957 if((!bufman) || (!bufman->bm_CopyToBuf))
959 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
962 /* Must be queued */
963 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
965 /* Queue the ioreq */
966 Forbid();
967 AddTail((struct List *) &ncp->ncp_OrphanQueue, (struct Node *) ioreq);
968 Permit();
970 /* Don't reply the ioreq, it's pending */
971 return RC_DONTREPLY;
975 WORD cmdOnline(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
977 KPRINTF(1, ("S2_ONLINE ioreq: 0x%08lx\n", ioreq));
979 Forbid();
980 /* Already online? */
981 if(!(ncp->ncp_StateFlags & DDF_ONLINE))
983 /* Configured? */
984 if(!(ncp->ncp_StateFlags & DDF_CONFIGURED))
986 Permit();
987 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_CONFIGURED);
990 /* Mark no longer offline */
991 ncp->ncp_StateFlags &= ~DDF_OFFLINE;
993 /* Mark being online */
994 ncp->ncp_StateFlags |= DDF_ONLINE;
995 if(ncp->ncp_Unit.unit_MsgPort.mp_SigTask)
997 Signal(ncp->ncp_Unit.unit_MsgPort.mp_SigTask, 1L<<(ncp->ncp_Unit.unit_MsgPort.mp_SigBit));
999 Permit();
1001 /* Trigger any ONLINE events */
1002 nDoEvent(ncp, S2EVENT_ONLINE);
1004 return RC_OK;
1007 Permit();
1008 /* Return success */
1009 return RC_OK;
1013 WORD cmdOffline(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
1016 KPRINTF(1, ("S2_OFFLINE ioreq: 0x%08lx\n", ioreq));
1018 Forbid();
1019 /* Mark being offline */
1020 ncp->ncp_StateFlags |= DDF_OFFLINE;
1022 /* Already offline? */
1023 if(ncp->ncp_StateFlags & DDF_ONLINE)
1025 /* Mark no longer online */
1026 ncp->ncp_StateFlags &= ~DDF_ONLINE;
1027 if(ncp->ncp_Unit.unit_MsgPort.mp_SigTask)
1029 Signal(ncp->ncp_Unit.unit_MsgPort.mp_SigTask, 1L<<(ncp->ncp_Unit.unit_MsgPort.mp_SigBit));
1031 Permit();
1033 /* *DO NOT* abort pending read & write requests.
1034 Miami dies a horrible death if this is enabled!
1036 if(ioreq->ios2_BufferManagement)
1038 AbortRW(ncp, ioreq->ios2_BufferManagement, deverror(S2ERR_OUTOFSERVICE, S2WERR_UNIT_OFFLINE));
1041 /* Trigger any OFFLINE events */
1042 nDoEvent(ncp, S2EVENT_OFFLINE);
1044 /* Don't reply the ioreq, it's pending */
1045 return RC_OK;
1047 Permit();
1049 /* Return success */
1050 return RC_OK;
1054 AROS_LH1(void, devBeginIO,
1055 AROS_LHA(struct IOSana2Req *, ioreq, A1),
1056 DEVBASETYPEPTR, base, 5, dev)
1058 AROS_LIBFUNC_INIT
1060 struct NepClassEth *ncp = (struct NepClassEth *) ioreq->ios2_Req.io_Unit;
1061 WORD ret = IOERR_NOCMD;
1063 KPRINTF(1, ("devBeginIO ioreq: 0x%08lx base: 0x%08lx cmd: %lu\n", ioreq, base, ioreq->ios2_Req.io_Command));
1065 ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
1066 ioreq->ios2_Req.io_Error = 0;
1068 if(ioreq->ios2_Req.io_Command < NSCMD_DEVICEQUERY)
1070 switch(ioreq->ios2_Req.io_Command)
1072 case CMD_READ:
1073 ret = cmdRead(ncp, ioreq);
1074 break;
1076 case CMD_FLUSH:
1077 ret = cmdFlush(ncp, ioreq);
1078 break;
1080 case CMD_WRITE:
1081 ret = cmdWrite(ncp, ioreq);
1082 break;
1084 case S2_GETSTATIONADDRESS:
1085 ret = cmdGetStationAddress(ncp, ioreq);
1086 break;
1088 case S2_DEVICEQUERY:
1089 ret = cmdDeviceQuery(ncp, ioreq);
1090 break;
1092 case S2_CONFIGINTERFACE:
1093 ret = cmdConfigInterface(ncp, ioreq);
1094 break;
1096 case S2_ADDMULTICASTADDRESS:
1097 ret = cmdAddMulticastAddress(ncp, ioreq);
1098 break;
1100 case S2_DELMULTICASTADDRESS:
1101 ret = cmdDelMulticastAddress(ncp, ioreq);
1102 break;
1104 case S2_MULTICAST:
1105 ret = cmdMulticast(ncp, ioreq);
1106 break;
1108 case S2_BROADCAST:
1109 ret = cmdBroadcast(ncp, ioreq);
1110 break;
1112 case S2_TRACKTYPE:
1113 ret = cmdTrackType(ncp, ioreq);
1114 break;
1116 case S2_UNTRACKTYPE:
1117 ret = cmdUntrackType(ncp, ioreq);
1118 break;
1120 case S2_GETTYPESTATS:
1121 ret = cmdGetTypeStats(ncp, ioreq);
1122 break;
1124 case S2_GETSPECIALSTATS:
1125 ret = cmdGetSpecialStats(ncp, ioreq);
1126 break;
1128 case S2_GETGLOBALSTATS:
1129 ret = cmdGetGlobalStats(ncp, ioreq);
1130 break;
1132 case S2_ONEVENT:
1133 ret = cmdOnEvent(ncp, ioreq);
1134 break;
1136 case S2_READORPHAN:
1137 ret = cmdReadOrphan(ncp, ioreq);
1138 break;
1140 case S2_ONLINE:
1141 ret = cmdOnline(ncp, ioreq);
1142 break;
1144 case S2_OFFLINE:
1145 ret = cmdOffline(ncp, ioreq);
1146 break;
1148 default:
1149 ret = IOERR_NOCMD;
1150 break;
1152 } else {
1153 switch(ioreq->ios2_Req.io_Command)
1155 case NSCMD_DEVICEQUERY:
1156 ret = cmdNSDeviceQuery(ncp, (struct IOStdReq *) ioreq);
1157 break;
1159 case S2_ADDMULTICASTADDRESSES:
1160 ret = cmdAddMulticastAddresses(ncp, ioreq);
1161 break;
1163 case S2_DELMULTICASTADDRESSES:
1164 ret = cmdDelMulticastAddresses(ncp, ioreq);
1165 break;
1167 default:
1168 ret = IOERR_NOCMD;
1169 break;
1173 if(ret != RC_DONTREPLY)
1175 KPRINTF(1, ("TermIO\n"));
1176 if (ret != RC_OK)
1178 /* Set error codes */
1179 ioreq->ios2_Req.io_Error = ret & 0xff;
1181 /* Terminate the iorequest */
1182 TermIO(ncp, ioreq);
1185 AROS_LIBFUNC_EXIT
1188 AROS_LH1(LONG, devAbortIO,
1189 AROS_LHA(struct IOSana2Req *, ioreq, A1),
1190 DEVBASETYPEPTR, base, 6, dev)
1192 AROS_LIBFUNC_INIT
1194 struct NepClassEth *ncp = (struct NepClassEth *) ioreq->ios2_Req.io_Unit;
1195 struct BufMan *worknode, *nextnode;
1197 KPRINTF(5, ("devAbortIO ioreq: 0x%08lx\n", ioreq));
1199 /* Is it pending? */
1200 Forbid();
1201 if(ioreq->ios2_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE)
1204 switch (ioreq->ios2_Req.io_Command)
1206 case CMD_READ:
1207 /* Check all nodes in dd_bufmanlist until we succeed to abort or run out of nodes. */
1208 worknode = (struct BufMan *) ncp->ncp_BufManList.lh_Head;
1209 while((nextnode = (struct BufMan *) (((struct Node *) worknode)->ln_Succ)))
1211 if(AbortReq(ncp, &worknode->bm_RXQueue, ioreq) == S2ERR_NO_ERROR)
1213 /* Success, break out */
1214 break;
1216 worknode = nextnode;
1218 break;
1220 case S2_READORPHAN:
1221 AbortReq(ncp, &ncp->ncp_OrphanQueue, ioreq);
1222 break;
1224 case CMD_WRITE:
1225 case S2_MULTICAST:
1226 case S2_BROADCAST:
1227 AbortReq(ncp, &ncp->ncp_WriteQueue, ioreq);
1228 break;
1230 // these commands may dispatch their ioreq to the USB task; catch from the message port
1231 case S2_ONLINE:
1232 case S2_OFFLINE:
1233 case S2_CONFIGINTERFACE:
1234 case S2_ADDMULTICASTADDRESS:
1235 case S2_DELMULTICASTADDRESS:
1236 case S2_ADDMULTICASTADDRESSES:
1237 case S2_DELMULTICASTADDRESSES:
1238 AbortReq(ncp, &ncp->ncp_Unit.unit_MsgPort.mp_MsgList, ioreq);
1239 break;
1241 case S2_ONEVENT:
1242 AbortReq(ncp, &ncp->ncp_EventList, ioreq);
1243 break;
1245 default:
1246 KPRINTF(1, ("devAbortIO: not READ, READORPHAN, WRITE, MULTICAST, BROADCAST or ONEVENT\n"));
1247 break;
1250 Permit();
1251 return(-1);
1253 AROS_LIBFUNC_EXIT
1256 /* NSD stuff
1259 static
1260 const UWORD NSDSupported[] =
1262 CMD_FLUSH, CMD_READ, CMD_WRITE,
1263 S2_DEVICEQUERY,
1264 S2_GETSTATIONADDRESS,
1265 S2_CONFIGINTERFACE,
1266 S2_ADDMULTICASTADDRESS, S2_DELMULTICASTADDRESS,
1267 S2_MULTICAST, S2_BROADCAST,
1268 S2_TRACKTYPE, S2_UNTRACKTYPE,
1269 S2_GETTYPESTATS, S2_GETSPECIALSTATS, S2_GETGLOBALSTATS,
1270 S2_ONEVENT,
1271 S2_READORPHAN,
1272 S2_ONLINE, S2_OFFLINE,
1273 NSCMD_DEVICEQUERY,
1274 S2_ADDMULTICASTADDRESSES, S2_DELMULTICASTADDRESSES,
1278 WORD cmdNSDeviceQuery(struct NepClassEth *ncp, struct IOStdReq *ioreq)
1280 struct my_NSDeviceQueryResult *query;
1282 query = (struct my_NSDeviceQueryResult *) ioreq->io_Data;
1284 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%08lx query: 0x%08lx\n", ioreq, query));
1286 /* NULL ptr?
1287 Enough data?
1288 Valid request?
1290 if((!query) ||
1291 (ioreq->io_Length < sizeof(struct my_NSDeviceQueryResult)) ||
1292 (query->DevQueryFormat != 0) ||
1293 (query->SizeAvailable != 0))
1295 /* Return error. This is special handling, since iorequest is only
1296 guaranteed to be sizeof(struct IOStdReq). If we'd let our
1297 devBeginIO dispatcher return the error, it would trash some
1298 memory past end of the iorequest (ios2_WireError field).
1300 ioreq->io_Error = IOERR_NOCMD;
1301 TermIO(ncp, (struct IOSana2Req *) ioreq);
1303 /* Don't reply, we already did.
1305 return RC_DONTREPLY;
1308 ioreq->io_Actual = query->SizeAvailable
1309 = sizeof(struct my_NSDeviceQueryResult);
1310 query->DeviceType = NSDEVTYPE_SANA2;
1311 query->DeviceSubType = 0;
1312 query->SupportedCommands = NSDSupported;
1314 /* Return success (note that this will NOT poke ios2_WireError).
1316 return RC_OK;
1320 *======================================================================
1321 * AbortReq(list, ioreq, base)
1322 *======================================================================
1324 * Locate an IO request in a linked list and abort it if found.
1328 LONG AbortReq(struct NepClassEth *ncp, struct List *list, struct IOSana2Req *ioreq)
1330 struct Node *node;
1332 for(node = list->lh_Head; node->ln_Succ; node = node->ln_Succ)
1334 if(node == (struct Node *) ioreq)
1336 //KPRINTF(1, ("AbortReq: aborted 0x%08lx\n", ioreq));
1338 Remove(&ioreq->ios2_Req.io_Message.mn_Node);
1339 ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
1340 ioreq->ios2_Req.io_Error = IOERR_ABORTED;
1341 ReplyMsg(&ioreq->ios2_Req.io_Message);
1343 return S2ERR_NO_ERROR;
1347 return S2ERR_BAD_STATE;
1353 *===========================================================
1354 * TermIO(ioreq, base)
1355 *===========================================================
1357 * Return completed ioreq to sender.
1361 void TermIO(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
1363 ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_FREEMSG;
1365 /* If not quick I/O, reply the message
1367 if(!(ioreq->ios2_Req.io_Flags & IOF_QUICK))
1369 ReplyMsg(&ioreq->ios2_Req.io_Message);
1374 *======================================================================
1375 * AbortList(list, bufman, error, base)
1376 *======================================================================
1378 * Aborts all pending ioreqs in given list with io_Error & ios2_WireError
1379 * set.
1381 * error is deverror() macro packed error number.
1385 void AbortList(struct NepClassEth *ncp, struct List *list, struct BufMan *bufman, WORD error)
1387 struct IOSana2Req *ioreq, *nextioreq;
1389 if(bufman)
1391 for(ioreq = (struct IOSana2Req *) list->lh_Head;
1392 (nextioreq = (struct IOSana2Req *) ioreq->ios2_Req.io_Message.mn_Node.ln_Succ);
1393 ioreq = nextioreq)
1395 if(ioreq->ios2_BufferManagement == bufman)
1397 Remove(&ioreq->ios2_Req.io_Message.mn_Node);
1398 /*ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;*/
1399 ioreq->ios2_Req.io_Error = error & 0xff;
1400 ioreq->ios2_WireError = error >> 8;
1401 ReplyMsg(&ioreq->ios2_Req.io_Message);
1405 else
1407 while((ioreq = (struct IOSana2Req *) RemHead(list)))
1409 /* ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;*/
1410 ioreq->ios2_Req.io_Error = error & 0xff;
1411 ioreq->ios2_WireError = error >> 8;
1412 ReplyMsg(&ioreq->ios2_Req.io_Message);
1419 *======================================================================
1420 * AbortRW(bufman, error, base)
1421 *======================================================================
1423 * Aborts all pending reads and writes with io_Error & ios2_WireError
1424 * set.
1426 * error is deverror() macro packed error number.
1430 void AbortRW(struct NepClassEth *ncp, struct BufMan *bufman, WORD error)
1432 AbortList(ncp, &bufman->bm_RXQueue, NULL, error);
1433 AbortList(ncp, &ncp->ncp_OrphanQueue, bufman, error);
1434 AbortList(ncp, &ncp->ncp_WriteQueue, bufman, error);
1437 struct Sana2PacketTypeStats * FindPacketTypeStats(struct NepClassEth *ncp, ULONG packettype)
1439 struct PacketTypeStats *pts;
1441 switch(packettype)
1443 case 2048:
1444 return ncp->ncp_TypeStats2048;
1445 break;
1447 case 2054:
1448 return ncp->ncp_TypeStats2054;
1449 break;
1451 default:
1452 /* Find matching node - slowly */
1453 pts = (struct PacketTypeStats *) ncp->ncp_TrackList.lh_Head;
1454 while(pts->pts_Node.ln_Succ)
1456 /* Our packet type? */
1457 if(pts->pts_PacketType == packettype)
1459 return &pts->pts_Stats;
1461 pts = (struct PacketTypeStats *) pts->pts_Node.ln_Succ;
1463 break;
1466 return NULL;