poseidon: Fix a number of BPTR issues
[AROS.git] / rom / usb / classes / moschipeth / dev.c
blobd987d481318334cf6ca8db9f87177af5de10ba3f
1 /* dev.c - usbmoschipeth.device by Chris Hodges
2 */
4 #include "debug.h"
6 #include "moschipeth.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 /* Copy the address (reverse direction) */
519 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
521 ioreq->ios2_SrcAddr[cnt] = ncp->ncp_MacAddress[cnt];
523 /* Error, already configured */
524 return deverror(S2ERR_BAD_STATE, S2WERR_IS_CONFIGURED);
527 /* Check for valid address */
528 if(ioreq->ios2_SrcAddr[0] & 0x80)
530 Permit();
531 return deverror(S2ERR_BAD_ADDRESS, S2WERR_SRC_ADDRESS);
534 /* Copy the address */
535 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
537 ncp->ncp_MacAddress[cnt] = ioreq->ios2_SrcAddr[cnt];
540 /* Must be queued */
541 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
542 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
543 Permit();
544 /* Don't reply the ioreq, it's pending */
545 return RC_DONTREPLY;
549 WORD cmdAddMulticastAddress(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
552 KPRINTF(1, ("S2_ADDMULTICASTADDRESS 0x%08lx%04lx\n",
553 ((ULONG *) ioreq->ios2_SrcAddr)[0], ((UWORD *) ioreq->ios2_SrcAddr)[2]));
555 return AddMCastRange(ncp, ioreq, ioreq->ios2_SrcAddr, ioreq->ios2_SrcAddr);
558 WORD cmdDelMulticastAddress(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
560 KPRINTF(1, ("S2_DELMULTICASTADDRESS 0x%08lx%04lx\n",
561 ((ULONG *) ioreq->ios2_SrcAddr)[0], ((UWORD *) ioreq->ios2_SrcAddr)[2]));
563 return DelMCastRange(ncp, ioreq, ioreq->ios2_SrcAddr, ioreq->ios2_SrcAddr);
566 WORD cmdAddMulticastAddresses(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
568 KPRINTF(1, ("S2_ADDMULTICASTADDRESSES 0x%08lx%04lx - 0x%08lx%04lx\n",
569 ((ULONG *) ioreq->ios2_SrcAddr)[0], ((UWORD *) ioreq->ios2_SrcAddr)[2],
570 ((ULONG *) ioreq->ios2_DstAddr)[0], ((UWORD *) ioreq->ios2_DstAddr)[2]));
572 return AddMCastRange(ncp, ioreq, ioreq->ios2_SrcAddr, ioreq->ios2_DstAddr);
575 WORD cmdDelMulticastAddresses(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
577 KPRINTF(1, ("S2_DELMULTICASTADDRESSES 0x%08lx%04lx - 0x%08lx%04lx\n",
578 ((ULONG *) ioreq->ios2_SrcAddr)[0], ((UWORD *) ioreq->ios2_SrcAddr)[2],
579 ((ULONG *) ioreq->ios2_DstAddr)[0], ((UWORD *) ioreq->ios2_DstAddr)[2]));
581 return DelMCastRange(ncp, ioreq, ioreq->ios2_SrcAddr, ioreq->ios2_DstAddr);
584 #define mcmp(a,b) (memcmp(a,b,ETHER_ADDR_SIZE)==0)
586 WORD AddMCastRange(struct NepClassEth *ncp, struct IOSana2Req *ioreq, UBYTE *lower, UBYTE *upper)
588 struct MulticastAddressRange *mar;
589 WORD cnt;
591 /* Valid multicast addresses? */
592 if(((lower[0] & 1) == 0) || ((upper[0] & 1) == 0))
594 return deverror(S2ERR_BAD_ADDRESS, S2WERR_BAD_MULTICAST);
597 /* Lock access to list */
598 Forbid();
600 /* Find matching node */
601 mar = (struct MulticastAddressRange *) ncp->ncp_Multicasts.lh_Head;
602 while(mar->mar_Node.ln_Succ)
604 if(mcmp(lower, mar->mar_LowerAddr) &&
605 mcmp(upper, mar->mar_UpperAddr))
607 break;
609 mar = (struct MulticastAddressRange *) mar->mar_Node.ln_Succ;
612 if(!mar->mar_Node.ln_Succ)
614 /* Add new node */
615 mar = AllocVec(sizeof(struct MulticastAddressRange), MEMF_CLEAR|MEMF_PUBLIC);
616 if(!mar)
618 Permit();
619 return deverror(S2ERR_NO_RESOURCES, S2WERR_GENERIC_ERROR);
621 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
623 mar->mar_LowerAddr[cnt] = *lower++;
624 mar->mar_UpperAddr[cnt] = *upper++;
626 mar->mar_UseCount = 1;
627 AddTail(&ncp->ncp_Multicasts, (struct Node *) mar);
629 Permit();
631 UpdateMulticastHash(ncp);
633 /* Must be queued */
634 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
635 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
637 /* Don't reply the ioreq, it's pending */
638 return RC_DONTREPLY;
640 mar->mar_UseCount++;
641 Permit();
643 /* Return success */
644 return RC_OK;
647 WORD DelMCastRange(struct NepClassEth *ncp, struct IOSana2Req *ioreq, UBYTE *lower, UBYTE *upper)
649 struct MulticastAddressRange *mar;
651 /* Lock access to list */
652 Forbid();
654 /* Find matching node */
655 mar = (struct MulticastAddressRange *) ncp->ncp_Multicasts.lh_Head;
656 while(mar->mar_Node.ln_Succ)
658 if(mcmp(lower, mar->mar_LowerAddr) &&
659 mcmp(upper, mar->mar_UpperAddr))
661 if(!--mar->mar_UseCount)
663 Remove((struct Node *) mar);
664 Permit();
665 FreeVec(mar);
667 UpdateMulticastHash(ncp);
668 /* Must be queued */
669 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
670 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
672 /* Don't reply the ioreq, it's pending */
673 return RC_DONTREPLY;
675 Permit();
676 return RC_OK;
678 mar = (struct MulticastAddressRange *) mar->mar_Node.ln_Succ;
680 Permit();
682 /* Return with failure */
683 return deverror(S2ERR_BAD_STATE, S2WERR_BAD_MULTICAST);
687 *===========================================================================
688 * Calculate 32 bit crc
689 *===========================================================================
691 * - for each bit: if (crcbit=1 XOR databit=1) then crc=(crc XOR polynomial).
692 * - polynomial is correct when data bits range 0-x, crc bits range 31-0.
693 * - crc wraps at 32 bits.
695 * crc = calc_crc(addr)
697 #define CRC_SEED -1
698 #define CRC_MASK 0x04c11db7U
700 ULONG ether_crc(LONG length, UBYTE *data)
702 register LONG crc;
704 crc = CRC_SEED;
706 while(--length >= 0)
708 register UBYTE c;
709 register UBYTE bit;
711 c = *data++;
713 for(bit = 0; bit < 8; bit++, c >>= 1)
715 crc = (crc << 1) ^ (((crc < 0) ^ (c & 1)) ? CRC_MASK : 0);
719 return (ULONG) crc;
723 *================================================================
724 * Update Multicasts
725 *================================================================
727 * calculate multicast hash table and send it to nic
730 * as of 1.2beta4 multicasts can be a address range, also single
731 * addresses are defined with lower = upper.
733 * multicasts list must be locked!
735 *==============================================================
736 * hash multicast address
737 *==============================================================
738 * The nic does not compare multicast addresses directly, but
739 * instead uses a bitfield of 64 bits - each bit corresponds
740 * to a 6 bit hash code for the multicast address. If the bit
741 * is set then any multicast address that matches the hash code
742 * will be accepted.
744 * The hash code is generated by taking the upper 6 bits of the
745 * 32 bit crc of the multicast address.
748 void UpdateMulticastHash(struct NepClassEth *ncp)
750 struct MulticastAddressRange *mar;
751 UBYTE addr[ETHER_ADDR_SIZE];
753 KPRINTF(1, ("nic_update_multicasts\n"));
755 /* Is promiscuous mode? */
756 if(ncp->ncp_OpenFlags & SANA2OPF_PROM)
758 /* "Promiscuous Physical." ... "In addition, the multicast hashing
759 array must be set to all 1's so that all multicast addresses are
760 accepted." */
761 memset(ncp->ncp_MulticastArray, 0xff, sizeof(ncp->ncp_MulticastArray));
762 } else {
763 /* Clear all multicast bits */
764 memset(ncp->ncp_MulticastArray, 0x00, sizeof(ncp->ncp_MulticastArray));
765 mar = (struct MulticastAddressRange *) ncp->ncp_Multicasts.lh_Head;
766 while(mar->mar_Node.ln_Succ)
768 memcpy(addr, mar->mar_LowerAddr, ETHER_ADDR_SIZE);
771 UBYTE hash;
772 hash = ether_crc(ETHER_ADDR_SIZE, addr) >> 26;
773 ncp->ncp_MulticastArray[hash>>3] |= 1<<(hash & 7);
774 if(mcmp(addr, mar->mar_UpperAddr))
776 break;
778 if(!++addr[5])
779 if (!++addr[4])
780 if (!++addr[3])
781 if (!++addr[2])
782 if (!++addr[1])
783 ++addr[0];
784 } while(TRUE);
785 mar = (struct MulticastAddressRange *) mar->mar_Node.ln_Succ;
790 WORD cmdMulticast(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
792 KPRINTF(1, ("S2_MULTICAST ioreq: 0x%08lx to: 0x%08lx%04lx\n",
793 ioreq,
794 ((ULONG *) ioreq->ios2_DstAddr)[0], ((UWORD *) ioreq->ios2_DstAddr)[2]));
796 /* Is dest a multicast address? */
797 if(ioreq->ios2_DstAddr[0] & 1)
799 return cmdWrite(ncp, ioreq);
802 /* Trigger any tx or generic error events */
803 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_TX);
805 /* Wasn't a multicast addr */
806 return deverror(S2ERR_BAD_ADDRESS, S2WERR_BAD_MULTICAST);
809 WORD cmdBroadcast(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
811 UWORD cnt;
812 KPRINTF(1, ("S2_BROADCAST ioreq: 0x%08lx\n", ioreq));
814 /* Dest address = broadcast */
815 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
817 ioreq->ios2_DstAddr[cnt] = 0xff;
819 return cmdWrite(ncp, ioreq);
823 WORD cmdTrackType(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
825 struct PacketTypeStats *pts;
827 KPRINTF(1, ("S2_TRACKTYPE ioreq: 0x%08lx type: %lu\n",
828 ioreq, ioreq->ios2_PacketType));
830 Forbid();
831 /* Find matching node */
832 pts = (struct PacketTypeStats *) ncp->ncp_TrackList.lh_Head;
833 while(pts->pts_Node.ln_Succ)
835 /* Our packet type? */
836 if(pts->pts_PacketType == ioreq->ios2_PacketType)
838 Permit();
839 return deverror(S2ERR_BAD_STATE, S2WERR_ALREADY_TRACKED);
841 pts = (struct PacketTypeStats *) pts->pts_Node.ln_Succ;
844 /* Alloc tracking node */
845 pts = (struct PacketTypeStats *) AllocVec(sizeof(struct PacketTypeStats), MEMF_CLEAR|MEMF_PUBLIC);
846 if(!pts)
848 return deverror(S2ERR_NO_RESOURCES, S2WERR_NOT_TRACKED);
850 /* Set up tracking node */
851 pts->pts_PacketType = ioreq->ios2_PacketType;
853 /* Add the new node to tracklist */
854 AddTail((struct List *) &ncp->ncp_TrackList, (struct Node *) pts);
855 // caching
856 if(pts->pts_PacketType == 2048)
858 ncp->ncp_TypeStats2048 = &pts->pts_Stats;
860 else if(pts->pts_PacketType == 2054)
862 ncp->ncp_TypeStats2054 = &pts->pts_Stats;
864 Permit();
866 /* Return success */
867 return RC_OK;
871 WORD cmdUntrackType(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
873 struct PacketTypeStats *pts;
874 KPRINTF(1, ("S2_UNTRACKTYPE ioreq: 0x%08lx type: %lu\n",
875 ioreq, ioreq->ios2_PacketType));
877 Forbid();
878 /* Find matching node */
879 pts = (struct PacketTypeStats *) ncp->ncp_TrackList.lh_Head;
880 while(pts->pts_Node.ln_Succ)
882 /* Our packet type? */
883 if(pts->pts_PacketType == ioreq->ios2_PacketType)
885 Remove(&pts->pts_Node);
886 // caching
887 if(pts->pts_PacketType == 2048)
889 ncp->ncp_TypeStats2048 = NULL;
891 else if(pts->pts_PacketType == 2054)
893 ncp->ncp_TypeStats2054 = NULL;
895 Permit();
896 FreeVec(pts);
897 return RC_OK;
900 pts = (struct PacketTypeStats *) pts->pts_Node.ln_Succ;
902 Permit();
903 /* Return failure */
904 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_TRACKED);
908 WORD cmdGetTypeStats(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
910 struct Sana2PacketTypeStats *tostats;
911 struct Sana2PacketTypeStats *fromstats;
913 KPRINTF(1, ("S2_GETTYPESTATS ioreq: 0x%08lx type: %lu\n",
914 ioreq, ioreq->ios2_PacketType));
916 /* NULL ptr? */
917 tostats = (struct Sana2PacketTypeStats *) ioreq->ios2_StatData;
918 if(!tostats)
920 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
923 Forbid();
924 fromstats = FindPacketTypeStats(ncp, ioreq->ios2_PacketType);
925 if(fromstats)
927 /* Copy the stats */
928 CopyMem(fromstats, tostats, sizeof(struct Sana2PacketTypeStats));
929 Permit();
931 /* Return success */
932 return RC_OK;
934 Permit();
936 /* Return error */
937 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_TRACKED);
941 WORD cmdGetSpecialStats(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
943 struct Sana2SpecialStatHeader *stats;
944 struct Sana2SpecialStatRecord *record;
945 ULONG maxcount;
947 KPRINTF(1, ("S2_GETSPECIALSTATS ioreq: 0x%08lx\n", ioreq));
949 /* NULL ptr? */
950 stats = (struct Sana2SpecialStatHeader *) ioreq->ios2_StatData;
951 if(!stats)
953 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
956 stats->RecordCountSupplied = 0;
957 maxcount = stats->RecordCountMax;
958 record = (struct Sana2SpecialStatRecord *) (stats + 1);
960 if(maxcount--)
962 stats->RecordCountSupplied++;
964 record->Type = S2SS_ETHERNET_BADMULTICAST;
965 record->Count = ncp->ncp_BadMulticasts;
966 record->String = "bad multicasts";
967 record++;
969 if(maxcount--)
971 stats->RecordCountSupplied++;
973 record->Type = S2SS_ETHERNET_RETRIES;
974 record->Count = ncp->ncp_Retries;
975 record->String = "retries";
976 //record++;
980 /* Return success */
981 return RC_OK;
985 WORD cmdGetGlobalStats(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
987 struct Sana2DeviceStats *stats;
989 KPRINTF(1, ("S2_GETGLOBALSTATS ioreq: 0x%08lx\n", ioreq));
991 /* NULL ptr? */
992 stats = (struct Sana2DeviceStats *) ioreq->ios2_StatData;
993 if(!stats)
995 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
998 CopyMem(&ncp->ncp_DeviceStats, stats, sizeof(struct Sana2DeviceStats));
1000 /* Return success */
1001 return RC_OK;
1005 #define KNOWN_EVENTS (S2EVENT_ERROR | \
1006 S2EVENT_TX | \
1007 S2EVENT_RX | \
1008 S2EVENT_ONLINE | \
1009 S2EVENT_OFFLINE | \
1010 S2EVENT_BUFF | \
1011 S2EVENT_HARDWARE)
1013 WORD cmdOnEvent(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
1015 KPRINTF(1, ("S2_ONEVENT ioreq: 0x%08lx mask: 0x%08lx\n", ioreq,
1016 ioreq->ios2_WireError));
1018 /* Do we know the requested events? */
1019 if(ioreq->ios2_WireError & (~KNOWN_EVENTS))
1021 return deverror(S2ERR_NOT_SUPPORTED, S2WERR_BAD_EVENT);
1024 /* If online return S2EVENT_ONLINE immediately
1025 If offline return S2EVENT_OFFLINE immediately. */
1026 if(ncp->ncp_StateFlags & DDF_ONLINE)
1028 if(ioreq->ios2_WireError & S2EVENT_ONLINE)
1030 ioreq->ios2_WireError = S2EVENT_ONLINE;
1032 /* Return success */
1033 return RC_OK;
1035 } else {
1036 if(ioreq->ios2_WireError & S2EVENT_OFFLINE)
1038 ioreq->ios2_WireError = S2EVENT_OFFLINE;
1040 /* Return success */
1041 return RC_OK;
1045 /* Must be queued */
1046 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
1048 /* Queue the ioreq */
1049 Forbid();
1050 AddTail((struct List *) &ncp->ncp_EventList, (struct Node *) ioreq);
1051 Permit();
1053 /* Don't reply the ioreq, it's pending */
1054 return RC_DONTREPLY;
1058 WORD cmdReadOrphan(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
1060 struct BufMan *bufman;
1062 KPRINTF(1, ("S2_READORPHAN ioreq: 0x%08lx type: %lu\n", ioreq,
1063 ioreq->ios2_PacketType));
1065 /* Configured? */
1066 if(!(ncp->ncp_StateFlags & DDF_CONFIGURED))
1068 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_CONFIGURED);
1071 /* Online? */
1072 if(!(ncp->ncp_StateFlags & DDF_ONLINE))
1074 return deverror(S2ERR_OUTOFSERVICE, S2WERR_UNIT_OFFLINE);
1077 /* Valid bufman? got copytobuf routine? */
1078 bufman = ioreq->ios2_BufferManagement;
1079 if((!bufman) || (!bufman->bm_CopyToBuf))
1081 return deverror(S2ERR_BAD_ARGUMENT, S2WERR_NULL_POINTER);
1084 /* Must be queued */
1085 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
1087 /* Queue the ioreq */
1088 Forbid();
1089 AddTail((struct List *) &ncp->ncp_OrphanQueue, (struct Node *) ioreq);
1090 Permit();
1092 /* Don't reply the ioreq, it's pending */
1093 return RC_DONTREPLY;
1097 WORD cmdOnline(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
1099 KPRINTF(1, ("S2_ONLINE ioreq: 0x%08lx\n", ioreq));
1101 Forbid();
1102 /* Already online? */
1103 if(!(ncp->ncp_StateFlags & DDF_ONLINE))
1105 /* Configured? */
1106 if(!(ncp->ncp_StateFlags & DDF_CONFIGURED))
1108 Permit();
1109 return deverror(S2ERR_BAD_STATE, S2WERR_NOT_CONFIGURED);
1112 /* Mark no longer offline */
1113 ncp->ncp_StateFlags &= ~DDF_OFFLINE;
1115 /* Must be queued */
1116 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
1117 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
1118 Permit();
1120 /* Don't reply the ioreq, it's pending */
1121 return RC_DONTREPLY;
1124 Permit();
1125 /* Return success */
1126 return RC_OK;
1130 WORD cmdOffline(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
1133 KPRINTF(1, ("S2_OFFLINE ioreq: 0x%08lx\n", ioreq));
1135 Forbid();
1136 /* Mark being offline */
1137 ncp->ncp_StateFlags |= DDF_OFFLINE;
1139 /* Already offline? */
1140 if(ncp->ncp_StateFlags & DDF_ONLINE)
1142 /* Mark no longer online */
1143 ncp->ncp_StateFlags &= ~DDF_ONLINE;
1145 /* *DO NOT* abort pending read & write requests.
1146 Miami dies a horrible death if this is enabled!
1148 if(ioreq->ios2_BufferManagement)
1150 AbortRW(ncp, ioreq->ios2_BufferManagement, deverror(S2ERR_OUTOFSERVICE, S2WERR_UNIT_OFFLINE));
1153 /* Trigger any OFFLINE events */
1154 nDoEvent(ncp, S2EVENT_OFFLINE);
1156 /* Must be queued */
1157 ioreq->ios2_Req.io_Flags &= ~IOF_QUICK;
1158 PutMsg(&ncp->ncp_Unit.unit_MsgPort, (struct Message *) ioreq);
1159 Permit();
1160 /* Don't reply the ioreq, it's pending */
1161 return RC_DONTREPLY;
1163 Permit();
1165 /* Return success */
1166 return RC_OK;
1170 AROS_LH1(void, devBeginIO,
1171 AROS_LHA(struct IOSana2Req *, ioreq, A1),
1172 DEVBASETYPEPTR, base, 5, dev)
1174 AROS_LIBFUNC_INIT
1176 struct NepClassEth *ncp = (struct NepClassEth *) ioreq->ios2_Req.io_Unit;
1177 WORD ret = IOERR_NOCMD;
1179 KPRINTF(1, ("devBeginIO ioreq: 0x%08lx base: 0x%08lx cmd: %lu\n", ioreq, base, ioreq->ios2_Req.io_Command));
1181 ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
1182 ioreq->ios2_Req.io_Error = 0;
1184 if(ioreq->ios2_Req.io_Command < NSCMD_DEVICEQUERY)
1186 switch(ioreq->ios2_Req.io_Command)
1188 case CMD_READ:
1189 ret = cmdRead(ncp, ioreq);
1190 break;
1192 case CMD_FLUSH:
1193 ret = cmdFlush(ncp, ioreq);
1194 break;
1196 case CMD_WRITE:
1197 ret = cmdWrite(ncp, ioreq);
1198 break;
1200 case S2_GETSTATIONADDRESS:
1201 ret = cmdGetStationAddress(ncp, ioreq);
1202 break;
1204 case S2_DEVICEQUERY:
1205 ret = cmdDeviceQuery(ncp, ioreq);
1206 break;
1208 case S2_CONFIGINTERFACE:
1209 ret = cmdConfigInterface(ncp, ioreq);
1210 break;
1212 case S2_ADDMULTICASTADDRESS:
1213 ret = cmdAddMulticastAddress(ncp, ioreq);
1214 break;
1216 case S2_DELMULTICASTADDRESS:
1217 ret = cmdDelMulticastAddress(ncp, ioreq);
1218 break;
1220 case S2_MULTICAST:
1221 ret = cmdMulticast(ncp, ioreq);
1222 break;
1224 case S2_BROADCAST:
1225 ret = cmdBroadcast(ncp, ioreq);
1226 break;
1228 case S2_TRACKTYPE:
1229 ret = cmdTrackType(ncp, ioreq);
1230 break;
1232 case S2_UNTRACKTYPE:
1233 ret = cmdUntrackType(ncp, ioreq);
1234 break;
1236 case S2_GETTYPESTATS:
1237 ret = cmdGetTypeStats(ncp, ioreq);
1238 break;
1240 case S2_GETSPECIALSTATS:
1241 ret = cmdGetSpecialStats(ncp, ioreq);
1242 break;
1244 case S2_GETGLOBALSTATS:
1245 ret = cmdGetGlobalStats(ncp, ioreq);
1246 break;
1248 case S2_ONEVENT:
1249 ret = cmdOnEvent(ncp, ioreq);
1250 break;
1252 case S2_READORPHAN:
1253 ret = cmdReadOrphan(ncp, ioreq);
1254 break;
1256 case S2_ONLINE:
1257 ret = cmdOnline(ncp, ioreq);
1258 break;
1260 case S2_OFFLINE:
1261 ret = cmdOffline(ncp, ioreq);
1262 break;
1264 default:
1265 ret = IOERR_NOCMD;
1266 break;
1268 } else {
1269 switch(ioreq->ios2_Req.io_Command)
1271 case NSCMD_DEVICEQUERY:
1272 ret = cmdNSDeviceQuery(ncp, (struct IOStdReq *) ioreq);
1273 break;
1275 case S2_ADDMULTICASTADDRESSES:
1276 ret = cmdAddMulticastAddresses(ncp, ioreq);
1277 break;
1279 case S2_DELMULTICASTADDRESSES:
1280 ret = cmdDelMulticastAddresses(ncp, ioreq);
1281 break;
1283 default:
1284 ret = IOERR_NOCMD;
1285 break;
1289 if(ret != RC_DONTREPLY)
1291 KPRINTF(1, ("TermIO\n"));
1292 if (ret != RC_OK)
1294 /* Set error codes */
1295 ioreq->ios2_Req.io_Error = ret & 0xff;
1296 ioreq->ios2_WireError = ret>>8;
1298 /* Terminate the iorequest */
1299 TermIO(ncp, ioreq);
1302 AROS_LIBFUNC_EXIT
1305 AROS_LH1(LONG, devAbortIO,
1306 AROS_LHA(struct IOSana2Req *, ioreq, A1),
1307 DEVBASETYPEPTR, base, 6, dev)
1309 AROS_LIBFUNC_INIT
1311 struct NepClassEth *ncp = (struct NepClassEth *) ioreq->ios2_Req.io_Unit;
1312 struct BufMan *worknode, *nextnode;
1314 KPRINTF(5, ("devAbortIO ioreq: 0x%08lx\n", ioreq));
1316 /* Is it pending? */
1317 Forbid();
1318 if(ioreq->ios2_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE)
1321 switch (ioreq->ios2_Req.io_Command)
1323 case CMD_READ:
1324 /* Check all nodes in dd_bufmanlist until we succeed to abort or run out of nodes. */
1325 worknode = (struct BufMan *) ncp->ncp_BufManList.lh_Head;
1326 while((nextnode = (struct BufMan *) (((struct Node *) worknode)->ln_Succ)))
1328 if(AbortReq(ncp, &worknode->bm_RXQueue, ioreq) == S2ERR_NO_ERROR)
1330 /* Success, break out */
1331 break;
1333 worknode = nextnode;
1335 break;
1337 case S2_READORPHAN:
1338 AbortReq(ncp, &ncp->ncp_OrphanQueue, ioreq);
1339 break;
1341 case CMD_WRITE:
1342 case S2_MULTICAST:
1343 case S2_BROADCAST:
1344 AbortReq(ncp, &ncp->ncp_WriteQueue, ioreq);
1345 break;
1347 // these commands may dispatch their ioreq to the USB task; catch from the message port
1348 case S2_ONLINE:
1349 case S2_OFFLINE:
1350 case S2_CONFIGINTERFACE:
1351 case S2_ADDMULTICASTADDRESS:
1352 case S2_DELMULTICASTADDRESS:
1353 case S2_ADDMULTICASTADDRESSES:
1354 case S2_DELMULTICASTADDRESSES:
1355 AbortReq(ncp, &ncp->ncp_Unit.unit_MsgPort.mp_MsgList, ioreq);
1356 break;
1358 case S2_ONEVENT:
1359 AbortReq(ncp, &ncp->ncp_EventList, ioreq);
1360 break;
1362 default:
1363 KPRINTF(1, ("devAbortIO: not READ, READORPHAN, WRITE, MULTICAST, BROADCAST or ONEVENT\n"));
1364 break;
1367 Permit();
1368 return(-1);
1370 AROS_LIBFUNC_EXIT
1373 /* NSD stuff
1376 static
1377 const UWORD NSDSupported[] =
1379 CMD_FLUSH, CMD_READ, CMD_WRITE,
1380 S2_DEVICEQUERY,
1381 S2_GETSTATIONADDRESS,
1382 S2_CONFIGINTERFACE,
1383 S2_ADDMULTICASTADDRESS, S2_DELMULTICASTADDRESS,
1384 S2_MULTICAST, S2_BROADCAST,
1385 S2_TRACKTYPE, S2_UNTRACKTYPE,
1386 S2_GETTYPESTATS, S2_GETSPECIALSTATS, S2_GETGLOBALSTATS,
1387 S2_ONEVENT,
1388 S2_READORPHAN,
1389 S2_ONLINE, S2_OFFLINE,
1390 NSCMD_DEVICEQUERY,
1391 S2_ADDMULTICASTADDRESSES, S2_DELMULTICASTADDRESSES,
1395 WORD cmdNSDeviceQuery(struct NepClassEth *ncp, struct IOStdReq *ioreq)
1397 struct my_NSDeviceQueryResult *query;
1399 query = (struct my_NSDeviceQueryResult *) ioreq->io_Data;
1401 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%08lx query: 0x%08lx\n", ioreq, query));
1403 /* NULL ptr?
1404 Enough data?
1405 Valid request?
1407 if((!query) ||
1408 (ioreq->io_Length < sizeof(struct my_NSDeviceQueryResult)) ||
1409 (query->DevQueryFormat != 0) ||
1410 (query->SizeAvailable != 0))
1412 /* Return error. This is special handling, since iorequest is only
1413 guaranteed to be sizeof(struct IOStdReq). If we'd let our
1414 devBeginIO dispatcher return the error, it would trash some
1415 memory past end of the iorequest (ios2_WireError field).
1417 ioreq->io_Error = IOERR_NOCMD;
1418 TermIO(ncp, (struct IOSana2Req *) ioreq);
1420 /* Don't reply, we already did.
1422 return RC_DONTREPLY;
1425 ioreq->io_Actual = query->SizeAvailable
1426 = sizeof(struct my_NSDeviceQueryResult);
1427 query->DeviceType = NSDEVTYPE_SANA2;
1428 query->DeviceSubType = 0;
1429 query->SupportedCommands = NSDSupported;
1431 /* Return success (note that this will NOT poke ios2_WireError).
1433 return RC_OK;
1437 *======================================================================
1438 * AbortReq(list, ioreq, base)
1439 *======================================================================
1441 * Locate an IO request in a linked list and abort it if found.
1445 LONG AbortReq(struct NepClassEth *ncp, struct List *list, struct IOSana2Req *ioreq)
1447 struct Node *node;
1449 for(node = list->lh_Head; node->ln_Succ; node = node->ln_Succ)
1451 if(node == (struct Node *) ioreq)
1453 //KPRINTF(1, ("AbortReq: aborted 0x%08lx\n", ioreq));
1455 Remove(&ioreq->ios2_Req.io_Message.mn_Node);
1456 ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
1457 ioreq->ios2_Req.io_Error = IOERR_ABORTED;
1458 ReplyMsg(&ioreq->ios2_Req.io_Message);
1460 return S2ERR_NO_ERROR;
1464 return S2ERR_BAD_STATE;
1470 *===========================================================
1471 * TermIO(ioreq, base)
1472 *===========================================================
1474 * Return completed ioreq to sender.
1478 void TermIO(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
1480 ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_FREEMSG;
1482 /* If not quick I/O, reply the message
1484 if(!(ioreq->ios2_Req.io_Flags & IOF_QUICK))
1486 ReplyMsg(&ioreq->ios2_Req.io_Message);
1491 *======================================================================
1492 * AbortList(list, bufman, error, base)
1493 *======================================================================
1495 * Aborts all pending ioreqs in given list with io_Error & ios2_WireError
1496 * set.
1498 * error is deverror() macro packed error number.
1502 void AbortList(struct NepClassEth *ncp, struct List *list, struct BufMan *bufman, WORD error)
1504 struct IOSana2Req *ioreq, *nextioreq;
1506 if(bufman)
1508 for(ioreq = (struct IOSana2Req *) list->lh_Head;
1509 (nextioreq = (struct IOSana2Req *) ioreq->ios2_Req.io_Message.mn_Node.ln_Succ);
1510 ioreq = nextioreq)
1512 if(ioreq->ios2_BufferManagement == bufman)
1514 Remove(&ioreq->ios2_Req.io_Message.mn_Node);
1515 /*ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;*/
1516 ioreq->ios2_Req.io_Error = error & 0xff;
1517 ioreq->ios2_WireError = error >> 8;
1518 ReplyMsg(&ioreq->ios2_Req.io_Message);
1522 else
1524 while((ioreq = (struct IOSana2Req *) RemHead(list)))
1526 /* ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;*/
1527 ioreq->ios2_Req.io_Error = error & 0xff;
1528 ioreq->ios2_WireError = error >> 8;
1529 ReplyMsg(&ioreq->ios2_Req.io_Message);
1536 *======================================================================
1537 * AbortRW(bufman, error, base)
1538 *======================================================================
1540 * Aborts all pending reads and writes with io_Error & ios2_WireError
1541 * set.
1543 * error is deverror() macro packed error number.
1547 void AbortRW(struct NepClassEth *ncp, struct BufMan *bufman, WORD error)
1549 AbortList(ncp, &bufman->bm_RXQueue, NULL, error);
1550 AbortList(ncp, &ncp->ncp_OrphanQueue, bufman, error);
1551 AbortList(ncp, &ncp->ncp_WriteQueue, bufman, error);
1554 struct Sana2PacketTypeStats * FindPacketTypeStats(struct NepClassEth *ncp, ULONG packettype)
1556 struct PacketTypeStats *pts;
1558 switch(packettype)
1560 case 2048:
1561 return ncp->ncp_TypeStats2048;
1562 break;
1564 case 2054:
1565 return ncp->ncp_TypeStats2054;
1566 break;
1568 default:
1569 /* Find matching node - slowly */
1570 pts = (struct PacketTypeStats *) ncp->ncp_TrackList.lh_Head;
1571 while(pts->pts_Node.ln_Succ)
1573 /* Our packet type? */
1574 if(pts->pts_PacketType == packettype)
1576 return &pts->pts_Stats;
1578 pts = (struct PacketTypeStats *) pts->pts_Node.ln_Succ;
1580 break;
1583 return NULL;