Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / usb / classes / pegasuseth / dev.c
blob5b0657787a9e3e8e1261136886acffd726d57cf5
1 /* dev.c - usbpegasus.device by Chris Hodges
2 */
4 #include "debug.h"
6 #include "pegasus.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 /* Must be queued */
536 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
537 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
538 Permit();
539 /* Don't reply the ioreq, it's pending */
540 return RC_DONTREPLY;
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 UpdateMulticastHash(ncp);
628 /* Must be queued */
629 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
630 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
632 /* Don't reply the ioreq, it's pending */
633 return RC_DONTREPLY;
635 mar->mar_UseCount++;
636 Permit();
638 /* Return success */
639 return RC_OK;
642 WORD DelMCastRange(struct NepClassEth *ncp, struct IOSana2Req *ioreq, UBYTE *lower, UBYTE *upper)
644 struct MulticastAddressRange *mar;
646 /* Lock access to list */
647 Forbid();
649 /* Find matching node */
650 mar = (struct MulticastAddressRange *) ncp->ncp_Multicasts.lh_Head;
651 while(mar->mar_Node.ln_Succ)
653 if(mcmp(lower, mar->mar_LowerAddr) &&
654 mcmp(upper, mar->mar_UpperAddr))
656 if(!--mar->mar_UseCount)
658 Remove((struct Node *) mar);
659 Permit();
660 FreeVec(mar);
662 UpdateMulticastHash(ncp);
663 /* Must be queued */
664 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
665 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
667 /* Don't reply the ioreq, it's pending */
668 return RC_DONTREPLY;
670 Permit();
671 return RC_OK;
673 mar = (struct MulticastAddressRange *) mar->mar_Node.ln_Succ;
675 Permit();
677 /* Return with failure */
678 return deverror(S2ERR_BAD_STATE, S2WERR_BAD_MULTICAST);
682 *===========================================================================
683 * Calculate 32 bit crc
684 *===========================================================================
686 * - for each bit: if (crcbit=1 XOR databit=1) then crc=(crc XOR polynomial).
687 * - polynomial is correct when data bits range 0-x, crc bits range 31-0.
688 * - crc wraps at 32 bits.
690 * crc = calc_crc(addr)
692 #define CRC_SEED -1
693 #define CRC_MASK 0x04c11db7U
695 ULONG ether_crc(LONG length, UBYTE *data)
697 register LONG crc;
699 crc = CRC_SEED;
701 while(--length >= 0)
703 register UBYTE c;
704 register UBYTE bit;
706 c = *data++;
708 for(bit = 0; bit < 8; bit++, c >>= 1)
710 crc = (crc << 1) ^ (((crc < 0) ^ (c & 1)) ? CRC_MASK : 0);
714 return (ULONG) crc;
718 *================================================================
719 * Update Multicasts
720 *================================================================
722 * calculate multicast hash table and send it to nic
725 * as of 1.2beta4 multicasts can be a address range, also single
726 * addresses are defined with lower = upper.
728 * multicasts list must be locked!
730 *==============================================================
731 * hash multicast address
732 *==============================================================
733 * The nic does not compare multicast addresses directly, but
734 * instead uses a bitfield of 64 bits - each bit corresponds
735 * to a 6 bit hash code for the multicast address. If the bit
736 * is set then any multicast address that matches the hash code
737 * will be accepted.
739 * The hash code is generated by taking the upper 6 bits of the
740 * 32 bit crc of the multicast address.
743 void UpdateMulticastHash(struct NepClassEth *ncp)
745 struct MulticastAddressRange *mar;
746 UBYTE addr[ETHER_ADDR_SIZE];
748 KPRINTF(1, ("nic_update_multicasts\n"));
750 /* Is promiscuous mode? */
751 if(ncp->ncp_OpenFlags & SANA2OPF_PROM)
753 /* "Promiscuous Physical." ... "In addition, the multicast hashing
754 array must be set to all 1's so that all multicast addresses are
755 accepted." */
756 memset(ncp->ncp_MulticastArray, 0xff, sizeof(ncp->ncp_MulticastArray));
757 } else {
758 /* Clear all multicast bits */
759 memset(ncp->ncp_MulticastArray, 0x00, sizeof(ncp->ncp_MulticastArray));
760 mar = (struct MulticastAddressRange *) ncp->ncp_Multicasts.lh_Head;
761 while(mar->mar_Node.ln_Succ)
763 memcpy(addr, mar->mar_LowerAddr, ETHER_ADDR_SIZE);
766 UBYTE hash;
767 hash = ether_crc(ETHER_ADDR_SIZE, addr) >> 26;
768 ncp->ncp_MulticastArray[hash>>3] |= 1<<(hash & 7);
769 if(mcmp(addr, mar->mar_UpperAddr))
771 break;
773 if(!++addr[5])
774 if(!++addr[4])
775 if(!++addr[3])
776 if(!++addr[2])
777 if(!++addr[1])
778 ++addr[0];
779 } while(TRUE);
780 mar = (struct MulticastAddressRange *) mar->mar_Node.ln_Succ;
785 WORD cmdMulticast(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
787 KPRINTF(1, ("S2_MULTICAST ioreq: 0x%08lx to: 0x%08lx%04lx\n",
788 ioreq,
789 ((ULONG *) ioreq->ios2_DstAddr)[0], ((UWORD *) ioreq->ios2_DstAddr)[2]));
791 /* Is dest a multicast address? */
792 if(ioreq->ios2_DstAddr[0] & 1)
794 return cmdWrite(ncp, ioreq);
797 /* Trigger any tx or generic error events */
798 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_TX);
800 /* Wasn't a multicast addr */
801 return deverror(S2ERR_BAD_ADDRESS, S2WERR_BAD_MULTICAST);
804 WORD cmdBroadcast(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
806 UWORD cnt;
807 KPRINTF(1, ("S2_BROADCAST ioreq: 0x%08lx\n", ioreq));
809 /* Dest address = broadcast */
810 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
812 ioreq->ios2_DstAddr[cnt] = 0xff;
814 return cmdWrite(ncp, ioreq);
818 WORD cmdTrackType(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
820 struct PacketTypeStats *pts;
822 KPRINTF(1, ("S2_TRACKTYPE ioreq: 0x%08lx type: %lu\n",
823 ioreq, ioreq->ios2_PacketType));
825 Forbid();
826 /* Find matching node */
827 pts = (struct PacketTypeStats *) ncp->ncp_TrackList.lh_Head;
828 while(pts->pts_Node.ln_Succ)
830 /* Our packet type? */
831 if(pts->pts_PacketType == ioreq->ios2_PacketType)
833 Permit();
834 return deverror(S2ERR_BAD_STATE, S2WERR_ALREADY_TRACKED);
836 pts = (struct PacketTypeStats *) pts->pts_Node.ln_Succ;
839 /* Alloc tracking node */
840 pts = (struct PacketTypeStats *) AllocVec(sizeof(struct PacketTypeStats), MEMF_CLEAR|MEMF_PUBLIC);
841 if(!pts)
843 return deverror(S2ERR_NO_RESOURCES, S2WERR_NOT_TRACKED);
845 /* Set up tracking node */
846 pts->pts_PacketType = ioreq->ios2_PacketType;
848 /* Add the new node to tracklist */
849 AddTail((struct List *) &ncp->ncp_TrackList, (struct Node *) pts);
850 // caching
851 if(pts->pts_PacketType == 2048)
853 ncp->ncp_TypeStats2048 = &pts->pts_Stats;
855 else if(pts->pts_PacketType == 2054)
857 ncp->ncp_TypeStats2054 = &pts->pts_Stats;
859 Permit();
861 /* Return success */
862 return RC_OK;
866 WORD cmdUntrackType(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
868 struct PacketTypeStats *pts;
869 KPRINTF(1, ("S2_UNTRACKTYPE ioreq: 0x%08lx type: %lu\n",
870 ioreq, ioreq->ios2_PacketType));
872 Forbid();
873 /* Find matching node */
874 pts = (struct PacketTypeStats *) ncp->ncp_TrackList.lh_Head;
875 while(pts->pts_Node.ln_Succ)
877 /* Our packet type? */
878 if(pts->pts_PacketType == ioreq->ios2_PacketType)
880 Remove(&pts->pts_Node);
881 // caching
882 if(pts->pts_PacketType == 2048)
884 ncp->ncp_TypeStats2048 = NULL;
886 else if(pts->pts_PacketType == 2054)
888 ncp->ncp_TypeStats2054 = NULL;
890 Permit();
891 FreeVec(pts);
892 return RC_OK;
895 pts = (struct PacketTypeStats *) pts->pts_Node.ln_Succ;
897 Permit();
898 /* Return failure */
899 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_TRACKED);
903 WORD cmdGetTypeStats(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
905 struct Sana2PacketTypeStats *tostats;
906 struct Sana2PacketTypeStats *fromstats;
908 KPRINTF(1, ("S2_GETTYPESTATS ioreq: 0x%08lx type: %lu\n",
909 ioreq, ioreq->ios2_PacketType));
911 /* NULL ptr? */
912 tostats = (struct Sana2PacketTypeStats *) ioreq->ios2_StatData;
913 if(!tostats)
915 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
918 Forbid();
919 fromstats = FindPacketTypeStats(ncp, ioreq->ios2_PacketType);
920 if(fromstats)
922 /* Copy the stats */
923 CopyMem(fromstats, tostats, sizeof(struct Sana2PacketTypeStats));
924 Permit();
926 /* Return success */
927 return RC_OK;
929 Permit();
931 /* Return error */
932 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_TRACKED);
936 WORD cmdGetSpecialStats(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
938 struct Sana2SpecialStatHeader *stats;
939 struct Sana2SpecialStatRecord *record;
940 ULONG maxcount;
942 KPRINTF(1, ("S2_GETSPECIALSTATS ioreq: 0x%08lx\n", ioreq));
944 /* NULL ptr? */
945 stats = (struct Sana2SpecialStatHeader *) ioreq->ios2_StatData;
946 if(!stats)
948 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
951 stats->RecordCountSupplied = 0;
952 maxcount = stats->RecordCountMax;
953 record = (struct Sana2SpecialStatRecord *) (stats + 1);
955 if(maxcount--)
957 stats->RecordCountSupplied++;
959 record->Type = S2SS_ETHERNET_BADMULTICAST;
960 record->Count = ncp->ncp_BadMulticasts;
961 record->String = "bad multicasts";
962 record++;
964 if(maxcount--)
966 stats->RecordCountSupplied++;
968 record->Type = S2SS_ETHERNET_RETRIES;
969 record->Count = ncp->ncp_Retries;
970 record->String = "retries";
971 //record++;
975 /* Return success */
976 return RC_OK;
980 WORD cmdGetGlobalStats(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
982 struct Sana2DeviceStats *stats;
984 KPRINTF(1, ("S2_GETGLOBALSTATS ioreq: 0x%08lx\n", ioreq));
986 /* NULL ptr? */
987 stats = (struct Sana2DeviceStats *) ioreq->ios2_StatData;
988 if(!stats)
990 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
993 CopyMem(&ncp->ncp_DeviceStats, stats, sizeof(struct Sana2DeviceStats));
995 /* Return success */
996 return RC_OK;
1000 #define KNOWN_EVENTS (S2EVENT_ERROR | \
1001 S2EVENT_TX | \
1002 S2EVENT_RX | \
1003 S2EVENT_ONLINE | \
1004 S2EVENT_OFFLINE | \
1005 S2EVENT_BUFF | \
1006 S2EVENT_HARDWARE)
1008 WORD cmdOnEvent(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
1010 KPRINTF(1, ("S2_ONEVENT ioreq: 0x%08lx mask: 0x%08lx\n", ioreq,
1011 ioreq->ios2_WireError));
1013 /* Do we know the requested events? */
1014 if(ioreq->ios2_WireError & (~KNOWN_EVENTS))
1016 return deverror(S2ERR_NOT_SUPPORTED, S2WERR_BAD_EVENT);
1019 /* If online return S2EVENT_ONLINE immediately
1020 If offline return S2EVENT_OFFLINE immediately. */
1021 if(ncp->ncp_StateFlags & DDF_ONLINE)
1023 if(ioreq->ios2_WireError & S2EVENT_ONLINE)
1025 ioreq->ios2_WireError = S2EVENT_ONLINE;
1027 /* Return success */
1028 return RC_OK;
1030 } else {
1031 if(ioreq->ios2_WireError & S2EVENT_OFFLINE)
1033 ioreq->ios2_WireError = S2EVENT_OFFLINE;
1035 /* Return success */
1036 return RC_OK;
1040 /* Must be queued */
1041 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
1043 /* Queue the ioreq */
1044 Forbid();
1045 AddTail((struct List *) &ncp->ncp_EventList, (struct Node *) ioreq);
1046 Permit();
1048 /* Don't reply the ioreq, it's pending */
1049 return RC_DONTREPLY;
1053 WORD cmdReadOrphan(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
1055 struct BufMan *bufman;
1057 KPRINTF(1, ("S2_READORPHAN ioreq: 0x%08lx type: %lu\n", ioreq,
1058 ioreq->ios2_PacketType));
1060 /* Configured? */
1061 if(!(ncp->ncp_StateFlags & DDF_CONFIGURED))
1063 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_CONFIGURED);
1066 /* Online? */
1067 if(!(ncp->ncp_StateFlags & DDF_ONLINE))
1069 return deverror(S2ERR_OUTOFSERVICE, S2WERR_UNIT_OFFLINE);
1072 /* Valid bufman? got copytobuf routine? */
1073 bufman = ioreq->ios2_BufferManagement;
1074 if((!bufman) || (!bufman->bm_CopyToBuf))
1076 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
1079 /* Must be queued */
1080 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
1082 /* Queue the ioreq */
1083 Forbid();
1084 AddTail((struct List *) &ncp->ncp_OrphanQueue, (struct Node *) ioreq);
1085 Permit();
1087 /* Don't reply the ioreq, it's pending */
1088 return RC_DONTREPLY;
1092 WORD cmdOnline(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
1094 KPRINTF(1, ("S2_ONLINE ioreq: 0x%08lx\n", ioreq));
1096 Forbid();
1097 /* Already online? */
1098 if(!(ncp->ncp_StateFlags & DDF_ONLINE))
1100 /* Configured? */
1101 if(!(ncp->ncp_StateFlags & DDF_CONFIGURED))
1103 Permit();
1104 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_CONFIGURED);
1107 /* Mark no longer offline */
1108 ncp->ncp_StateFlags &= ~DDF_OFFLINE;
1110 /* Must be queued */
1111 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
1112 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
1113 Permit();
1115 /* Don't reply the ioreq, it's pending */
1116 return RC_DONTREPLY;
1119 Permit();
1120 /* Return success */
1121 return RC_OK;
1125 WORD cmdOffline(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
1128 KPRINTF(1, ("S2_OFFLINE ioreq: 0x%08lx\n", ioreq));
1130 Forbid();
1131 /* Mark being offline */
1132 ncp->ncp_StateFlags |= DDF_OFFLINE;
1134 /* Already offline? */
1135 if(ncp->ncp_StateFlags & DDF_ONLINE)
1137 /* Mark no longer online */
1138 ncp->ncp_StateFlags &= ~DDF_ONLINE;
1140 /* *DO NOT* abort pending read & write requests.
1141 Miami dies a horrible death if this is enabled!
1143 if(ioreq->ios2_BufferManagement)
1145 AbortRW(ncp, ioreq->ios2_BufferManagement, deverror(S2ERR_OUTOFSERVICE, S2WERR_UNIT_OFFLINE));
1148 /* Trigger any OFFLINE events */
1149 nDoEvent(ncp, S2EVENT_OFFLINE);
1151 /* Must be queued */
1152 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
1153 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
1154 Permit();
1155 /* Don't reply the ioreq, it's pending */
1156 return RC_DONTREPLY;
1158 Permit();
1160 /* Return success */
1161 return RC_OK;
1165 AROS_LH1(void, devBeginIO,
1166 AROS_LHA(struct IOSana2Req *, ioreq, A1),
1167 DEVBASETYPEPTR, base, 5, dev)
1169 AROS_LIBFUNC_INIT
1171 struct NepClassEth *ncp = (struct NepClassEth *) ioreq->ios2_Req.io_Unit;
1172 WORD ret = IOERR_NOCMD;
1174 KPRINTF(1, ("devBeginIO ioreq: 0x%08lx base: 0x%08lx cmd: %lu\n", ioreq, base, ioreq->ios2_Req.io_Command));
1176 ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
1177 ioreq->ios2_Req.io_Error = 0;
1179 if(ioreq->ios2_Req.io_Command < NSCMD_DEVICEQUERY)
1181 switch(ioreq->ios2_Req.io_Command)
1183 case CMD_READ:
1184 ret = cmdRead(ncp, ioreq);
1185 break;
1187 case CMD_FLUSH:
1188 ret = cmdFlush(ncp, ioreq);
1189 break;
1191 case CMD_WRITE:
1192 ret = cmdWrite(ncp, ioreq);
1193 break;
1195 case S2_GETSTATIONADDRESS:
1196 ret = cmdGetStationAddress(ncp, ioreq);
1197 break;
1199 case S2_DEVICEQUERY:
1200 ret = cmdDeviceQuery(ncp, ioreq);
1201 break;
1203 case S2_CONFIGINTERFACE:
1204 ret = cmdConfigInterface(ncp, ioreq);
1205 break;
1207 case S2_ADDMULTICASTADDRESS:
1208 ret = cmdAddMulticastAddress(ncp, ioreq);
1209 break;
1211 case S2_DELMULTICASTADDRESS:
1212 ret = cmdDelMulticastAddress(ncp, ioreq);
1213 break;
1215 case S2_MULTICAST:
1216 ret = cmdMulticast(ncp, ioreq);
1217 break;
1219 case S2_BROADCAST:
1220 ret = cmdBroadcast(ncp, ioreq);
1221 break;
1223 case S2_TRACKTYPE:
1224 ret = cmdTrackType(ncp, ioreq);
1225 break;
1227 case S2_UNTRACKTYPE:
1228 ret = cmdUntrackType(ncp, ioreq);
1229 break;
1231 case S2_GETTYPESTATS:
1232 ret = cmdGetTypeStats(ncp, ioreq);
1233 break;
1235 case S2_GETSPECIALSTATS:
1236 ret = cmdGetSpecialStats(ncp, ioreq);
1237 break;
1239 case S2_GETGLOBALSTATS:
1240 ret = cmdGetGlobalStats(ncp, ioreq);
1241 break;
1243 case S2_ONEVENT:
1244 ret = cmdOnEvent(ncp, ioreq);
1245 break;
1247 case S2_READORPHAN:
1248 ret = cmdReadOrphan(ncp, ioreq);
1249 break;
1251 case S2_ONLINE:
1252 ret = cmdOnline(ncp, ioreq);
1253 break;
1255 case S2_OFFLINE:
1256 ret = cmdOffline(ncp, ioreq);
1257 break;
1259 default:
1260 ret = IOERR_NOCMD;
1261 break;
1263 } else {
1264 switch(ioreq->ios2_Req.io_Command)
1266 case NSCMD_DEVICEQUERY:
1267 ret = cmdNSDeviceQuery(ncp, (struct IOStdReq *) ioreq);
1268 break;
1270 case S2_ADDMULTICASTADDRESSES:
1271 ret = cmdAddMulticastAddresses(ncp, ioreq);
1272 break;
1274 case S2_DELMULTICASTADDRESSES:
1275 ret = cmdDelMulticastAddresses(ncp, ioreq);
1276 break;
1278 default:
1279 ret = IOERR_NOCMD;
1280 break;
1284 if(ret != RC_DONTREPLY)
1286 KPRINTF(1, ("TermIO\n"));
1287 if (ret != RC_OK)
1289 /* Set error codes */
1290 ioreq->ios2_Req.io_Error = ret & 0xff;
1292 /* Terminate the iorequest */
1293 TermIO(ncp, ioreq);
1296 AROS_LIBFUNC_EXIT
1299 AROS_LH1(LONG, devAbortIO,
1300 AROS_LHA(struct IOSana2Req *, ioreq, A1),
1301 DEVBASETYPEPTR, base, 6, dev)
1303 AROS_LIBFUNC_INIT
1305 struct NepClassEth *ncp = (struct NepClassEth *) ioreq->ios2_Req.io_Unit;
1306 struct BufMan *worknode, *nextnode;
1308 KPRINTF(5, ("devAbortIO ioreq: 0x%08lx\n", ioreq));
1310 /* Is it pending? */
1311 Forbid();
1312 if(ioreq->ios2_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE)
1315 switch (ioreq->ios2_Req.io_Command)
1317 case CMD_READ:
1318 /* Check all nodes in dd_bufmanlist until we succeed to abort or run out of nodes. */
1319 worknode = (struct BufMan *) ncp->ncp_BufManList.lh_Head;
1320 while((nextnode = (struct BufMan *) (((struct Node *) worknode)->ln_Succ)))
1322 if(AbortReq(ncp, &worknode->bm_RXQueue, ioreq) == S2ERR_NO_ERROR)
1324 /* Success, break out */
1325 break;
1327 worknode = nextnode;
1329 break;
1331 case S2_READORPHAN:
1332 AbortReq(ncp, &ncp->ncp_OrphanQueue, ioreq);
1333 break;
1335 case CMD_WRITE:
1336 case S2_MULTICAST:
1337 case S2_BROADCAST:
1338 AbortReq(ncp, &ncp->ncp_WriteQueue, ioreq);
1339 break;
1341 // these commands may dispatch their ioreq to the USB task; catch from the message port
1342 case S2_ONLINE:
1343 case S2_OFFLINE:
1344 case S2_CONFIGINTERFACE:
1345 case S2_ADDMULTICASTADDRESS:
1346 case S2_DELMULTICASTADDRESS:
1347 case S2_ADDMULTICASTADDRESSES:
1348 case S2_DELMULTICASTADDRESSES:
1349 AbortReq(ncp, &ncp->ncp_Unit.unit_MsgPort.mp_MsgList, ioreq);
1350 break;
1352 case S2_ONEVENT:
1353 AbortReq(ncp, &ncp->ncp_EventList, ioreq);
1354 break;
1356 default:
1357 KPRINTF(1, ("devAbortIO: not READ, READORPHAN, WRITE, MULTICAST, BROADCAST or ONEVENT\n"));
1358 break;
1361 Permit();
1362 return(-1);
1364 AROS_LIBFUNC_EXIT
1367 /* NSD stuff
1370 static
1371 const UWORD NSDSupported[] =
1373 CMD_FLUSH, CMD_READ, CMD_WRITE,
1374 S2_DEVICEQUERY,
1375 S2_GETSTATIONADDRESS,
1376 S2_CONFIGINTERFACE,
1377 S2_ADDMULTICASTADDRESS, S2_DELMULTICASTADDRESS,
1378 S2_MULTICAST, S2_BROADCAST,
1379 S2_TRACKTYPE, S2_UNTRACKTYPE,
1380 S2_GETTYPESTATS, S2_GETSPECIALSTATS, S2_GETGLOBALSTATS,
1381 S2_ONEVENT,
1382 S2_READORPHAN,
1383 S2_ONLINE, S2_OFFLINE,
1384 NSCMD_DEVICEQUERY,
1385 S2_ADDMULTICASTADDRESSES, S2_DELMULTICASTADDRESSES,
1389 WORD cmdNSDeviceQuery(struct NepClassEth *ncp, struct IOStdReq *ioreq)
1391 struct my_NSDeviceQueryResult *query;
1393 query = (struct my_NSDeviceQueryResult *) ioreq->io_Data;
1395 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%08lx query: 0x%08lx\n", ioreq, query));
1397 /* NULL ptr?
1398 Enough data?
1399 Valid request?
1401 if((!query) ||
1402 (ioreq->io_Length < sizeof(struct my_NSDeviceQueryResult)) ||
1403 (query->DevQueryFormat != 0) ||
1404 (query->SizeAvailable != 0))
1406 /* Return error. This is special handling, since iorequest is only
1407 guaranteed to be sizeof(struct IOStdReq). If we'd let our
1408 devBeginIO dispatcher return the error, it would trash some
1409 memory past end of the iorequest (ios2_WireError field).
1411 ioreq->io_Error = IOERR_NOCMD;
1412 TermIO(ncp, (struct IOSana2Req *) ioreq);
1414 /* Don't reply, we already did.
1416 return RC_DONTREPLY;
1419 ioreq->io_Actual = query->SizeAvailable
1420 = sizeof(struct my_NSDeviceQueryResult);
1421 query->DeviceType = NSDEVTYPE_SANA2;
1422 query->DeviceSubType = 0;
1423 query->SupportedCommands = NSDSupported;
1425 /* Return success (note that this will NOT poke ios2_WireError).
1427 return RC_OK;
1431 *======================================================================
1432 * AbortReq(list, ioreq, base)
1433 *======================================================================
1435 * Locate an IO request in a linked list and abort it if found.
1439 LONG AbortReq(struct NepClassEth *ncp, struct List *list, struct IOSana2Req *ioreq)
1441 struct Node *node;
1443 for(node = list->lh_Head; node->ln_Succ; node = node->ln_Succ)
1445 if(node == (struct Node *) ioreq)
1447 //KPRINTF(1, ("AbortReq: aborted 0x%08lx\n", ioreq));
1449 Remove(&ioreq->ios2_Req.io_Message.mn_Node);
1450 ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
1451 ioreq->ios2_Req.io_Error = IOERR_ABORTED;
1452 ReplyMsg(&ioreq->ios2_Req.io_Message);
1454 return S2ERR_NO_ERROR;
1458 return S2ERR_BAD_STATE;
1464 *===========================================================
1465 * TermIO(ioreq, base)
1466 *===========================================================
1468 * Return completed ioreq to sender.
1472 void TermIO(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
1474 ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_FREEMSG;
1476 /* If not quick I/O, reply the message
1478 if(!(ioreq->ios2_Req.io_Flags & IOF_QUICK))
1480 ReplyMsg(&ioreq->ios2_Req.io_Message);
1485 *======================================================================
1486 * AbortList(list, bufman, error, base)
1487 *======================================================================
1489 * Aborts all pending ioreqs in given list with io_Error & ios2_WireError
1490 * set.
1492 * error is deverror() macro packed error number.
1496 void AbortList(struct NepClassEth *ncp, struct List *list, struct BufMan *bufman, WORD error)
1498 struct IOSana2Req *ioreq, *nextioreq;
1500 if(bufman)
1502 for(ioreq = (struct IOSana2Req *) list->lh_Head;
1503 (nextioreq = (struct IOSana2Req *) ioreq->ios2_Req.io_Message.mn_Node.ln_Succ);
1504 ioreq = nextioreq)
1506 if(ioreq->ios2_BufferManagement == bufman)
1508 Remove(&ioreq->ios2_Req.io_Message.mn_Node);
1509 /*ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;*/
1510 ioreq->ios2_Req.io_Error = error & 0xff;
1511 ioreq->ios2_WireError = error >> 8;
1512 ReplyMsg(&ioreq->ios2_Req.io_Message);
1516 else
1518 while((ioreq = (struct IOSana2Req *) RemHead(list)))
1520 /* ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;*/
1521 ioreq->ios2_Req.io_Error = error & 0xff;
1522 ioreq->ios2_WireError = error >> 8;
1523 ReplyMsg(&ioreq->ios2_Req.io_Message);
1530 *======================================================================
1531 * AbortRW(bufman, error, base)
1532 *======================================================================
1534 * Aborts all pending reads and writes with io_Error & ios2_WireError
1535 * set.
1537 * error is deverror() macro packed error number.
1541 void AbortRW(struct NepClassEth *ncp, struct BufMan *bufman, WORD error)
1543 AbortList(ncp, &bufman->bm_RXQueue, NULL, error);
1544 AbortList(ncp, &ncp->ncp_OrphanQueue, bufman, error);
1545 AbortList(ncp, &ncp->ncp_WriteQueue, bufman, error);
1548 struct Sana2PacketTypeStats * FindPacketTypeStats(struct NepClassEth *ncp, ULONG packettype)
1550 struct PacketTypeStats *pts;
1552 switch(packettype)
1554 case 2048:
1555 return ncp->ncp_TypeStats2048;
1556 break;
1558 case 2054:
1559 return ncp->ncp_TypeStats2054;
1560 break;
1562 default:
1563 /* Find matching node - slowly */
1564 pts = (struct PacketTypeStats *) ncp->ncp_TrackList.lh_Head;
1565 while(pts->pts_Node.ln_Succ)
1567 /* Our packet type? */
1568 if(pts->pts_PacketType == packettype)
1570 return &pts->pts_Stats;
1572 pts = (struct PacketTypeStats *) pts->pts_Node.ln_Succ;
1574 break;
1577 return NULL;