Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / usb / classes / ethwrap / ethwrap.class.c
blob5771b8b6d6ddfecae63d809c9bac874ba338bac1
1 /*
2 *----------------------------------------------------------------------------
3 * ethwrap class for poseidon
4 *----------------------------------------------------------------------------
5 * By Chris Hodges <chrisly@platon42.de>
6 */
8 #include "debug.h"
10 #include "ethwrap.class.h"
12 /* /// "Lib Stuff" */
13 static const STRPTR libname = MOD_NAME_STRING;
15 static
16 const APTR DevFuncTable[] =
18 &AROS_SLIB_ENTRY(devOpen, dev, 1),
19 &AROS_SLIB_ENTRY(devClose, dev, 2),
20 &AROS_SLIB_ENTRY(devExpunge, dev, 3),
21 &AROS_SLIB_ENTRY(devReserved, dev, 4),
22 &AROS_SLIB_ENTRY(devBeginIO, dev, 5),
23 &AROS_SLIB_ENTRY(devAbortIO, dev, 6),
24 (APTR) -1,
27 static int libInit(LIBBASETYPEPTR nh)
29 struct NepClassEth *ncp;
30 struct NepEthBase *ret = NULL;
32 KPRINTF(10, ("libInit nh: 0x%08lx SysBase: 0x%08lx\n", nh, SysBase));
34 nh->nh_UtilityBase = OpenLibrary("utility.library", 39);
36 #define UtilityBase nh->nh_UtilityBase
38 if(UtilityBase)
40 NewList(&nh->nh_Units);
42 if((nh->nh_DevBase = (struct NepEthDevBase *) MakeLibrary((APTR) DevFuncTable, NULL, (APTR) devInit,
43 sizeof(struct NepEthDevBase), NULL)))
45 ncp = &nh->nh_DummyNCP;
46 ncp->ncp_ClsBase = nh;
47 ncp->ncp_Interface = NULL;
48 ncp->ncp_CDC = AllocVec(sizeof(struct ClsDevCfg), MEMF_PUBLIC|MEMF_CLEAR);
49 if(ncp->ncp_CDC)
51 nh->nh_DevBase->np_ClsBase = nh;
52 Forbid();
53 AddDevice((struct Device *) nh->nh_DevBase);
54 nh->nh_DevBase->np_Library.lib_OpenCnt++;
55 Permit();
56 ret = nh;
58 } else {
59 KPRINTF(20, ("failed to create usbparallel.device\n"));
61 if(!ret)
63 CloseLibrary(UtilityBase);
65 } else {
66 KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n"));
69 KPRINTF(10, ("libInit: Ok\n"));
70 return(ret ? TRUE : FALSE);
73 static int libOpen(LIBBASETYPEPTR nh)
75 KPRINTF(10, ("libOpen nh: 0x%08lx\n", nh));
76 nLoadClassConfig(nh);
77 return(TRUE);
80 static int libExpunge(LIBBASETYPEPTR nh)
82 struct NepClassEth *ncp;
84 KPRINTF(10, ("libExpunge nh: 0x%08lx\n", nh));
86 if(nh->nh_DevBase->np_Library.lib_OpenCnt == 1)
88 KPRINTF(1, ("libExpunge: closelibrary utilitybase 0x%08lx\n",
89 UtilityBase));
90 CloseLibrary((struct Library *) UtilityBase);
92 ncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
93 while(ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
95 Remove((struct Node *) ncp);
96 FreeVec(ncp->ncp_CDC);
97 FreeVec(ncp);
98 ncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
101 nh->nh_DevBase->np_Library.lib_OpenCnt--;
102 RemDevice((struct Device *) nh->nh_DevBase);
104 KPRINTF(5, ("libExpunge: Unloading done! ethwrap.class expunged!\n\n"));
105 } else {
106 KPRINTF(5, ("libExpunge: Could not expunge, LIBF_DELEXP set!\n"));
107 return(FALSE);
110 return(TRUE);
113 ADD2INITLIB(libInit, 0)
114 ADD2OPENLIB(libOpen, 0)
115 ADD2EXPUNGELIB(libExpunge, 0)
116 /* \\\ */
120 * ***********************************************************************
121 * * Library functions *
122 * ***********************************************************************
125 struct AutoBindData
127 UWORD abd_VendID;
128 UWORD abd_ProdID;
131 struct AutoBindData ClassBinds[] =
133 { 0x0402, 0x5632 }, // ALi defaults
134 { 0x050d, 0x0004 }, // Belkin
135 { 0x050f, 0x0190 }, // KC-190
136 { 0x0525, 0x2888 }, // EPSON USB client
137 { 0x0525, 0x9901 }, // Advance USBNET (eTEK)
138 { 0x0547, 0x2720 }, // AnchorChips defaults
139 { 0x0547, 0x2727 }, // Xircom PGUNET
140 { 0x056c, 0x8100 }, // eTEK
141 { 0, 0 }
144 /* /// "usbAttemptDeviceBinding()" */
145 struct NepClassEth * usbAttemptDeviceBinding(struct NepEthBase *nh, struct PsdDevice *pd)
147 struct Library *ps;
148 struct AutoBindData *abd = ClassBinds;
149 IPTR prodid;
150 IPTR vendid;
152 KPRINTF(1, ("nepEthAttemptDeviceBinding(%08lx)\n", pd));
154 if((ps = OpenLibrary("poseidon.library", 4)))
156 psdGetAttrs(PGA_DEVICE, pd,
157 DA_VendorID, &vendid,
158 DA_ProductID, &prodid,
159 TAG_END);
160 CloseLibrary(ps);
161 while(abd->abd_VendID)
163 if((vendid == abd->abd_VendID) && (prodid == abd->abd_ProdID))
165 return(usbForceDeviceBinding(nh, pd));
167 abd++;
170 return(NULL);
172 /* \\\ */
174 /* /// "usbForceDeviceBinding()" */
175 struct NepClassEth * usbForceDeviceBinding(struct NepEthBase *nh, struct PsdDevice *pd)
177 struct Library *ps;
178 struct NepClassEth *ncp;
179 struct NepClassEth *tmpncp;
180 struct ClsDevCfg *cdc;
181 STRPTR devname;
182 STRPTR devidstr;
183 IPTR prodid;
184 IPTR vendid;
185 ULONG unitno;
186 BOOL unitfound;
187 UBYTE buf[64];
189 KPRINTF(1, ("nepEthForceDeviceBinding(%08lx)\n", pd));
191 if((ps = OpenLibrary("poseidon.library", 4)))
193 psdGetAttrs(PGA_DEVICE, pd,
194 DA_ProductID, &prodid,
195 DA_VendorID, &vendid,
196 DA_ProductName, &devname,
197 DA_IDString, &devidstr,
198 TAG_END);
199 Forbid();
201 unitfound = FALSE;
202 unitno = (ULONG) -1;
203 ncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
204 while(ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
206 if(!strcmp(ncp->ncp_DevIDString, devidstr))
208 unitno = ncp->ncp_UnitNo;
209 unitfound = TRUE;
210 break;
212 ncp = (struct NepClassEth *) ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
214 if(!unitfound)
216 /* as units are freed in the expunge-vector, the memory is
217 outside the scope of the poseidon library */
218 if(!(ncp = AllocVec(sizeof(struct NepClassEth), MEMF_PUBLIC|MEMF_CLEAR)))
220 Permit();
221 CloseLibrary(ps);
222 return(NULL);
224 ncp->ncp_CDC = cdc = AllocVec(sizeof(struct ClsDevCfg), MEMF_PUBLIC|MEMF_CLEAR);
225 if(!cdc)
227 Permit();
228 FreeVec(ncp);
229 CloseLibrary(ps);
230 return(NULL);
232 /* IORequests may be queued even if the task is gone. */
233 ncp->ncp_UnitNo = (ULONG) -1;
234 NewList(&ncp->ncp_Unit.unit_MsgPort.mp_MsgList);
235 NewList(&ncp->ncp_OrphanQueue);
236 NewList(&ncp->ncp_WriteQueue);
237 NewList(&ncp->ncp_BufManList);
238 NewList(&ncp->ncp_EventList);
239 NewList(&ncp->ncp_TrackList);
240 NewList(&ncp->ncp_Multicasts);
241 strncpy(ncp->ncp_DevIDString, devidstr, 127);
242 AddTail(&nh->nh_Units, &ncp->ncp_Unit.unit_MsgPort.mp_Node);
244 ncp->ncp_ClsBase = nh;
245 ncp->ncp_Device = pd;
246 ncp->ncp_UnitProdID = prodid;
247 ncp->ncp_UnitVendorID = vendid;
249 nLoadBindingConfig(ncp);
251 /* Find next free unit number */
252 if(unitno == (ULONG) -1)
254 unitno = ncp->ncp_CDC->cdc_DefaultUnit;
255 tmpncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
256 while(tmpncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
258 if(tmpncp->ncp_UnitNo == unitno)
260 unitno++;
261 tmpncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
262 } else {
263 tmpncp = (struct NepClassEth *) tmpncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
267 ncp->ncp_UnitNo = unitno;
268 Permit();
270 psdSafeRawDoFmt(buf, 64, "ethwrap.class<%08lx>", ncp);
271 ncp->ncp_ReadySignal = SIGB_SINGLE;
272 ncp->ncp_ReadySigTask = FindTask(NULL);
273 SetSignal(0, SIGF_SINGLE);
274 if(psdSpawnSubTask(buf, nEthTask, ncp))
276 Wait(1L<<ncp->ncp_ReadySignal);
277 if(ncp->ncp_Task)
279 ncp->ncp_ReadySigTask = NULL;
280 //FreeSignal(ncp->ncp_ReadySignal);
281 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
282 "Mr. Data linked '%s' to %s unit %ld!",
283 devname, nh->nh_DevBase->np_Library.lib_Node.ln_Name,
284 ncp->ncp_UnitNo);
286 CloseLibrary(ps);
287 return(ncp);
290 ncp->ncp_ReadySigTask = NULL;
291 //FreeSignal(ncp->ncp_ReadySignal);
292 /* Get rid of unit structure */
293 /*Forbid();
294 Remove((struct Node *) ncp);
295 FreeVec(ncp->ncp_CDC);
296 FreeVec(ncp);
297 Permit();*/
298 CloseLibrary(ps);
300 return(NULL);
302 /* \\\ */
304 /* /// "usbReleaseDeviceBinding()" */
305 void usbReleaseDeviceBinding(struct NepEthBase *nh, struct NepClassEth *ncp)
307 struct Library *ps;
308 STRPTR devname;
309 KPRINTF(1, ("nepEthReleaseDeviceBinding(%08lx)\n", ncp));
311 if((ps = OpenLibrary("poseidon.library", 4)))
313 Forbid();
314 ncp->ncp_ReadySignal = SIGB_SINGLE;
315 ncp->ncp_ReadySigTask = FindTask(NULL);
316 if(ncp->ncp_Task)
318 Signal(ncp->ncp_Task, SIGBREAKF_CTRL_C);
320 Permit();
321 while(ncp->ncp_Task)
323 Wait(1L<<ncp->ncp_ReadySignal);
325 //FreeSignal(ncp->ncp_ReadySignal);
326 psdGetAttrs(PGA_DEVICE, ncp->ncp_Device, DA_ProductName, &devname, TAG_END);
327 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
328 "Shrinkwrapped and wasted '%s'.",
329 devname);
330 /*psdFreeVec(ncp);*/
331 CloseLibrary(ps);
334 /* \\\ */
336 /* /// "usbGetAttrsA()" */
337 AROS_LH3(LONG, usbGetAttrsA,
338 AROS_LHA(ULONG, type, D0),
339 AROS_LHA(APTR, usbstruct, A0),
340 AROS_LHA(struct TagItem *, tags, A1),
341 LIBBASETYPEPTR, nh, 5, nep)
343 AROS_LIBFUNC_INIT
345 struct TagItem *ti;
346 LONG count = 0;
348 KPRINTF(1, ("nepEthGetAttrsA(%ld, %08lx, %08lx)\n", type, usbstruct, tags));
349 switch(type)
351 case UGA_CLASS:
352 if((ti = FindTagItem(UCCA_Priority, tags)))
354 *((SIPTR *) ti->ti_Data) = -100;
355 count++;
357 if((ti = FindTagItem(UCCA_Description, tags)))
359 *((STRPTR *) ti->ti_Data) = "Ethernet SANA wrapper for simple devices via usbethwrap.device";
360 count++;
362 if((ti = FindTagItem(UCCA_HasClassCfgGUI, tags)))
364 *((IPTR *) ti->ti_Data) = TRUE;
365 count++;
367 if((ti = FindTagItem(UCCA_HasBindingCfgGUI, tags)))
369 *((IPTR *) ti->ti_Data) = TRUE;
370 count++;
372 if((ti = FindTagItem(UCCA_AfterDOSRestart, tags)))
374 *((IPTR *) ti->ti_Data) = FALSE;
375 count++;
377 if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags)))
379 *((IPTR *) ti->ti_Data) = nh->nh_DummyNCP.ncp_UsingDefaultCfg;
380 count++;
382 break;
384 case UGA_BINDING:
385 if((ti = FindTagItem(UCBA_UsingDefaultCfg, tags)))
387 *((IPTR *) ti->ti_Data) = ((struct NepClassEth *) usbstruct)->ncp_UsingDefaultCfg;
388 count++;
390 break;
392 return(count);
393 AROS_LIBFUNC_EXIT
395 /* \\\ */
397 /* /// "usbSetAttrsA()" */
398 AROS_LH3(LONG, usbSetAttrsA,
399 AROS_LHA(ULONG, type, D0),
400 AROS_LHA(APTR, usbstruct, A0),
401 AROS_LHA(struct TagItem *, tags, A1),
402 LIBBASETYPEPTR, nh, 6, nep)
404 AROS_LIBFUNC_INIT
405 return(0);
406 AROS_LIBFUNC_EXIT
408 /* \\\ */
410 /* /// "usbDoMethodA()" */
411 AROS_LH2(IPTR, usbDoMethodA,
412 AROS_LHA(ULONG, methodid, D0),
413 AROS_LHA(IPTR *, methoddata, A1),
414 LIBBASETYPEPTR, nh, 7, nep)
416 AROS_LIBFUNC_INIT
418 struct NepClassEth *ncp;
420 KPRINTF(10, ("Do Method %ld\n", methodid));
421 switch(methodid)
423 case UCM_AttemptDeviceBinding:
424 return((IPTR) usbAttemptDeviceBinding(nh, (struct PsdDevice *) methoddata[0]));
426 case UCM_ForceDeviceBinding:
427 return((IPTR) usbForceDeviceBinding(nh, (struct PsdDevice *) methoddata[0]));
429 case UCM_ReleaseDeviceBinding:
430 usbReleaseDeviceBinding(nh, (struct NepClassEth *) methoddata[0]);
431 return(TRUE);
433 case UCM_OpenCfgWindow:
434 return(nOpenBindingCfgWindow(nh, &nh->nh_DummyNCP));
436 case UCM_OpenBindingCfgWindow:
437 return(nOpenBindingCfgWindow(nh, (struct NepClassEth *) methoddata[0]));
439 case UCM_ConfigChangedEvent:
440 nLoadClassConfig(nh);
441 Forbid();
442 ncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
443 while(ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
445 nLoadBindingConfig(ncp);
446 ncp = (struct NepClassEth *) ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
448 Permit();
449 return(TRUE);
451 default:
452 break;
454 return(0);
455 AROS_LIBFUNC_EXIT
457 /* \\\ */
459 /* /// "nLoadClassConfig()" */
460 BOOL nLoadClassConfig(struct NepEthBase *nh)
462 struct NepClassEth *ncp = &nh->nh_DummyNCP;
463 struct Library *ps;
464 struct ClsDevCfg *cdc;
465 struct PsdIFFContext *pic;
467 KPRINTF(10, ("Loading Class Config...\n"));
468 if(ncp->ncp_GUITask)
470 return(FALSE);
472 if(!(ps = OpenLibrary("poseidon.library", 4)))
474 return(FALSE);
477 Forbid();
478 /* Create default config */
479 cdc = ncp->ncp_CDC;
480 cdc->cdc_ChunkID = AROS_LONG2BE(MAKE_ID('E','T','H','W'));
481 cdc->cdc_Length = AROS_LONG2BE(sizeof(struct ClsDevCfg)-8);
482 cdc->cdc_DefaultUnit = 0;
483 cdc->cdc_MACAddress[0] = 0x00;
484 cdc->cdc_MACAddress[1] = 0xff;
485 cdc->cdc_MACAddress[2] = 0xff;
486 cdc->cdc_MACAddress[3] = ((IPTR) cdc)>>20;
487 cdc->cdc_MACAddress[4] = ((IPTR) cdc)>>12;
488 cdc->cdc_MACAddress[5] = ((IPTR) cdc)>>4;
489 ncp->ncp_UsingDefaultCfg = TRUE;
490 /* try to load default config */
491 pic = psdGetClsCfg(libname);
492 if(pic)
494 cdc = psdGetCfgChunk(pic, AROS_LONG2BE(ncp->ncp_CDC->cdc_ChunkID));
495 if(cdc)
497 CopyMem(((UBYTE *) cdc) + 8, ((UBYTE *) ncp->ncp_CDC) + 8, min(AROS_LONG2BE(cdc->cdc_Length), AROS_LONG2BE(ncp->ncp_CDC->cdc_Length)));
498 psdFreeVec(cdc);
499 ncp->ncp_UsingDefaultCfg = FALSE;
502 Permit();
503 CloseLibrary(ps);
504 return(FALSE);
506 /* \\\ */
508 /* /// "nLoadBindingConfig()" */
509 BOOL nLoadBindingConfig(struct NepClassEth *ncp)
511 struct NepEthBase *nh = ncp->ncp_ClsBase;
512 struct Library *ps;
513 struct ClsDevCfg *cdc;
514 struct PsdIFFContext *pic;
516 KPRINTF(10, ("Loading Binding Config...\n"));
517 if(ncp->ncp_GUITask)
519 return(FALSE);
521 //nLoadClassConfig(nh);
522 *ncp->ncp_CDC = *nh->nh_DummyNCP.ncp_CDC;
523 ncp->ncp_UsingDefaultCfg = TRUE;
525 if(!(ps = OpenLibrary("poseidon.library", 4)))
527 return(FALSE);
530 Forbid();
531 /* Load config */
532 pic = psdGetUsbDevCfg(libname, ncp->ncp_DevIDString, NULL);
533 if(pic)
535 cdc = psdGetCfgChunk(pic, AROS_LONG2BE(ncp->ncp_CDC->cdc_ChunkID));
536 if(cdc)
538 CopyMem(((UBYTE *) cdc) + 8, ((UBYTE *) ncp->ncp_CDC) + 8, min(AROS_LONG2BE(cdc->cdc_Length), AROS_LONG2BE(ncp->ncp_CDC->cdc_Length)));
539 psdFreeVec(cdc);
540 ncp->ncp_UsingDefaultCfg = FALSE;
543 Permit();
544 CloseLibrary(ps);
545 return(FALSE);
547 /* \\\ */
549 /* /// "nOpenBindingCfgWindow()" */
550 LONG nOpenBindingCfgWindow(struct NepEthBase *nh, struct NepClassEth *ncp)
552 struct Library *ps;
553 KPRINTF(10, ("Opening GUI...\n"));
554 if(!(ps = OpenLibrary("poseidon.library", 4)))
556 return(FALSE);
558 Forbid();
559 if(!ncp->ncp_GUITask)
561 if((ncp->ncp_GUITask = psdSpawnSubTask(MOD_NAME_STRING " GUI", nGUITask, ncp)))
563 Permit();
564 CloseLibrary(ps);
565 return(TRUE);
568 Permit();
569 CloseLibrary(ps);
570 return(FALSE);
572 /* \\\ */
574 /**************************************************************************/
576 #undef ps
577 #define ps ncp->ncp_Base
579 /* /// "nEthTask()" */
580 AROS_UFH0(void, nEthTask)
582 AROS_USERFUNC_INIT
584 struct NepClassEth *ncp;
585 struct PsdPipe *pp;
586 ULONG sigmask;
587 ULONG sigs;
588 LONG ioerr;
589 UBYTE *pktptr;
590 ULONG pktlen;
591 UWORD cnt;
592 LONG lastioerr = 0;
593 ULONG errcount = 0;
595 struct IOSana2Req *ioreq;
597 if((ncp = nAllocEth()))
599 Forbid();
600 if(ncp->ncp_ReadySigTask)
602 Signal(ncp->ncp_ReadySigTask, 1L<<ncp->ncp_ReadySignal);
604 Permit();
606 if(!(ncp->ncp_StateFlags & DDF_CONFIGURED))
608 // don't overwrite previously configured MAC Address
609 CopyMem(ncp->ncp_CDC->cdc_MACAddress, ncp->ncp_MacAddress, ETHER_ADDR_SIZE);
612 //if((!(ncp->ncp_StateFlags & DDF_OFFLINE)))// && (ncp->ncp_StateFlags & DDF_CONFIGURED))
614 /* Record start time_of_day */
615 //GetSysTime(&ncp->ncp_DeviceStats.LastStart);
616 /* Now online */
617 ncp->ncp_StateFlags |= DDF_ONLINE;
618 ncp->ncp_StateFlags &= ~DDF_OFFLINE;
619 /* Trigger any ONLINE events */
620 nDoEvent(ncp, S2EVENT_ONLINE);
623 /* Main task */
624 sigmask = (1L<<ncp->ncp_Unit.unit_MsgPort.mp_SigBit)|(1L<<ncp->ncp_TaskMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C;
627 // start transmitting read request if online...
628 if((ncp->ncp_StateFlags & DDF_ONLINE) && (ncp->ncp_ReadPending == NULL))
630 ncp->ncp_ReadPending = ncp->ncp_ReadBuffer[ncp->ncp_ReadBufNum];
631 psdSendPipe(ncp->ncp_EPInPipe, ncp->ncp_ReadPending, ETHER_MAX_LEN);
632 ncp->ncp_ReadBufNum ^= 1;
634 while((pp = (struct PsdPipe *) GetMsg(ncp->ncp_TaskMsgPort)))
636 KPRINTF(1, ("Pipe back %08lx\n", pp));
637 for(cnt = 0; cnt < 2; cnt++)
639 if(pp == ncp->ncp_EPOutPipe[cnt])
641 if((ioreq = ncp->ncp_WritePending[cnt]))
643 ioerr = psdGetPipeError(pp);
644 if(ioerr)
646 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
647 "Eth transmit failed: %s (%ld)",
648 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
650 /* Trigger any tx or generic error events */
651 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_TX);
653 /* Set error code and terminate the iorequest.
654 NOTE: Can't use RC_* or deverror() this is not
655 called from devBeginIO()!
657 ioreq->ios2_DataLength = 0;
658 ioreq->ios2_Req.io_Error = S2ERR_TX_FAILURE;
659 ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
660 psdDelayMS(50);
662 ReplyMsg((struct Message *) ioreq);
663 ncp->ncp_WritePending[cnt] = NULL;
665 break;
668 if(pp == ncp->ncp_EPInPipe)
670 if((pktptr = ncp->ncp_ReadPending))
672 ioerr = psdGetPipeError(pp);
673 pktlen = psdGetPipeActual(pp);
674 KPRINTF(1, ("ReadBack with %ld bytes.\n", pktlen));
675 // interleave next packet reading ASAP.
676 if(ncp->ncp_StateFlags & DDF_ONLINE)
678 ncp->ncp_ReadPending = ncp->ncp_ReadBuffer[ncp->ncp_ReadBufNum];
679 psdSendPipe(ncp->ncp_EPInPipe, ncp->ncp_ReadPending, ETHER_MAX_LEN);
680 ncp->ncp_ReadBufNum ^= 1;
681 } else {
682 ncp->ncp_ReadPending = NULL;
684 if(ioerr)
686 if(lastioerr != ioerr)
688 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
689 "Eth receive failed: %s (%ld)",
690 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
691 errcount = 0;
692 } else {
693 errcount++;
694 if(errcount > 20)
696 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname,
697 "That's it, that device pissed me off long enough!");
698 Signal(ncp->ncp_Task, SIGBREAKF_CTRL_C);
701 lastioerr = ioerr;
702 psdDelayMS(50);
703 break;
704 } else {
705 KPRINTF(1, ("Pkt %ld received\n", pktlen));
706 DB(dumpmem(pktptr, pktlen));
707 nReadPacket(ncp, pktptr, pktlen);
713 Forbid();
714 while((!ncp->ncp_WritePending[ncp->ncp_WriteBufNum]) && ncp->ncp_WriteQueue.lh_Head->ln_Succ)
716 ioreq = (struct IOSana2Req *) RemHead(&ncp->ncp_WriteQueue);
717 Permit();
718 nWritePacket(ncp, ioreq);
719 Forbid();
721 Permit();
722 sigs = Wait(sigmask);
723 } while(!(sigs & SIGBREAKF_CTRL_C));
725 Forbid();
726 /* Now remove all requests still pending *anywhere* */
727 //ncp->ncp_DenyRequests = TRUE;
728 /* Current transfers */
729 for(cnt = 0; cnt < 2; cnt++)
731 if((ioreq = ncp->ncp_WritePending[cnt]))
733 KPRINTF(1, ("Aborting pending write...\n"));
734 psdAbortPipe(ncp->ncp_EPOutPipe[cnt]);
735 psdWaitPipe(ncp->ncp_EPOutPipe[cnt]);
736 ioreq->ios2_Req.io_Error = IOERR_ABORTED;
737 ReplyMsg((struct Message *) ioreq);
738 ncp->ncp_WritePending[cnt] = NULL;
741 if(ncp->ncp_ReadPending)
743 KPRINTF(1, ("Aborting pending read...\n"));
744 psdAbortPipe(ncp->ncp_EPInPipe);
745 psdWaitPipe(ncp->ncp_EPInPipe);
746 ncp->ncp_ReadPending = NULL;
748 Permit();
750 nDoEvent(ncp, S2EVENT_OFFLINE);
752 KPRINTF(20, ("Going down the river!\n"));
753 nFreeEth(ncp);
756 AROS_USERFUNC_EXIT
758 /* \\\ */
760 /* /// "nAllocEth()" */
761 struct NepClassEth * nAllocEth(void)
763 struct Task *thistask;
764 struct NepClassEth *ncp;
766 thistask = FindTask(NULL);
769 ncp = thistask->tc_UserData;
770 if(!(ncp->ncp_Base = OpenLibrary("poseidon.library", 4)))
772 Alert(AG_OpenLib);
773 break;
776 ncp->ncp_Interface = psdFindInterface(ncp->ncp_Device, NULL,
777 TAG_END);
779 if(!ncp->ncp_Interface)
781 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "No interface?");
782 break;
785 ncp->ncp_EPIn = psdFindEndpoint(ncp->ncp_Interface, NULL,
786 EA_IsIn, TRUE,
787 EA_TransferType, USEAF_BULK,
788 TAG_END);
789 ncp->ncp_EPOut = psdFindEndpoint(ncp->ncp_Interface, NULL,
790 EA_IsIn, FALSE,
791 EA_TransferType, USEAF_BULK,
792 TAG_END);
793 if(!(ncp->ncp_EPIn && ncp->ncp_EPOut))
795 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "IN or OUT endpoint missing!");
796 break;
799 ncp->ncp_ReadPending = NULL;
800 ncp->ncp_WritePending[0] = NULL;
801 ncp->ncp_WritePending[1] = NULL;
802 if(!(ncp->ncp_ReadBuffer[0] = AllocVec(ETHER_MAX_LEN * 4, MEMF_PUBLIC|MEMF_CLEAR)))
804 KPRINTF(1, ("Out of memory for read buffer\n"));
805 break;
807 ncp->ncp_ReadBuffer[1] = ncp->ncp_ReadBuffer[0] + ETHER_MAX_LEN;
808 ncp->ncp_WriteBuffer[0] = ncp->ncp_ReadBuffer[1] + ETHER_MAX_LEN;
809 ncp->ncp_WriteBuffer[1] = ncp->ncp_WriteBuffer[0] + ETHER_MAX_LEN;
810 ncp->ncp_Unit.unit_MsgPort.mp_SigBit = AllocSignal(-1);
811 ncp->ncp_Unit.unit_MsgPort.mp_SigTask = thistask;
812 ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
813 ncp->ncp_Unit.unit_MsgPort.mp_Flags = PA_SIGNAL;
815 if((ncp->ncp_TaskMsgPort = CreateMsgPort()))
817 if((ncp->ncp_EP0Pipe = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, NULL)))
819 if((ncp->ncp_EPOutPipe[0] = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, ncp->ncp_EPOut)))
821 /* Turn off short packets */
822 psdSetAttrs(PGA_PIPE, ncp->ncp_EPOutPipe[0],
823 PPA_NoShortPackets, FALSE,
824 PPA_NakTimeout, TRUE,
825 PPA_NakTimeoutTime, 5000,
826 TAG_END);
827 if((ncp->ncp_EPOutPipe[1] = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, ncp->ncp_EPOut)))
829 /* Turn off short packets */
830 psdSetAttrs(PGA_PIPE, ncp->ncp_EPOutPipe[1],
831 PPA_NoShortPackets, FALSE,
832 PPA_NakTimeout, TRUE,
833 PPA_NakTimeoutTime, 5000,
834 TAG_END);
835 if((ncp->ncp_EPInPipe = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, ncp->ncp_EPIn)))
837 /* Turn off short packets */
838 psdSetAttrs(PGA_PIPE, ncp->ncp_EPInPipe,
839 PPA_NakTimeout, FALSE,
840 PPA_NakTimeoutTime, 5000,
841 PPA_AllowRuntPackets, TRUE,
842 TAG_END);
843 ncp->ncp_Task = thistask;
845 return(ncp);
847 psdFreePipe(ncp->ncp_EPOutPipe[1]);
849 psdFreePipe(ncp->ncp_EPOutPipe[0]);
851 psdFreePipe(ncp->ncp_EP0Pipe);
853 DeleteMsgPort(ncp->ncp_TaskMsgPort);
855 FreeSignal((LONG) ncp->ncp_Unit.unit_MsgPort.mp_SigBit);
856 } while(FALSE);
857 if(ncp->ncp_ReadBuffer[0])
859 FreeVec(ncp->ncp_ReadBuffer[0]);
860 ncp->ncp_ReadBuffer[0] = NULL;
862 CloseLibrary(ncp->ncp_Base);
863 Forbid();
864 ncp->ncp_Task = NULL;
865 if(ncp->ncp_ReadySigTask)
867 Signal(ncp->ncp_ReadySigTask, 1L<<ncp->ncp_ReadySignal);
869 return(NULL);
871 /* \\\ */
873 /* /// "nFreeEth()" */
874 void nFreeEth(struct NepClassEth *ncp)
876 struct IOSana2Req *ioreq;
877 Forbid();
878 /* Disable the message port, messages may still be queued */
879 ncp->ncp_Unit.unit_MsgPort.mp_SigTask = NULL;
880 ncp->ncp_Unit.unit_MsgPort.mp_Flags = PA_IGNORE;
881 FreeSignal((LONG) ncp->ncp_Unit.unit_MsgPort.mp_SigBit);
882 // get rid of all messages that still have appeared here
883 while((ioreq = (struct IOSana2Req *) GetMsg(&ncp->ncp_Unit.unit_MsgPort)))
885 ioreq->ios2_Req.io_Error = IOERR_ABORTED;
886 ReplyMsg((struct Message *) ioreq);
888 Permit();
890 psdFreePipe(ncp->ncp_EPInPipe);
891 psdFreePipe(ncp->ncp_EPOutPipe[0]);
892 psdFreePipe(ncp->ncp_EPOutPipe[1]);
893 psdFreePipe(ncp->ncp_EP0Pipe);
895 if(ncp->ncp_ReadBuffer[0])
897 FreeVec(ncp->ncp_ReadBuffer[0]);
898 ncp->ncp_ReadBuffer[0] = NULL;
901 DeleteMsgPort(ncp->ncp_TaskMsgPort);
902 CloseLibrary(ncp->ncp_Base);
903 Forbid();
904 ncp->ncp_Task = NULL;
905 if(ncp->ncp_ReadySigTask)
907 Signal(ncp->ncp_ReadySigTask, 1L<<ncp->ncp_ReadySignal);
910 /* \\\ */
912 /* /// "nDoEvent()" */
913 void nDoEvent(struct NepClassEth *ncp, ULONG events)
915 struct IOSana2Req *worknode, *nextnode;
917 KPRINTF(1, ("DoEvent events: 0x%08lx\n", events));
919 Forbid();
920 /* Process pending S2_ONEVENT requests */
921 worknode = (struct IOSana2Req *) ncp->ncp_EventList.lh_Head;
922 while((nextnode = (struct IOSana2Req *) (((struct Node *) worknode)->ln_Succ)))
924 if(worknode->ios2_WireError & events)
926 Remove(&worknode->ios2_Req.io_Message.mn_Node);
927 worknode->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
928 KPRINTF(1, ("DoEvent: returned eventreq 0x%08lx\n", worknode));
929 ReplyMsg(&worknode->ios2_Req.io_Message);
931 worknode = nextnode;
933 Permit();
935 /* \\\ */
937 /* /// "support routines" */
938 static
939 inline void *callcopy(void *routine,
940 void *from,
941 void *to,
942 ULONG len)
944 void * (*call) (APTR, APTR, ULONG) = routine;
946 return (*call) (from, to, len);
949 #define callfilter CallHookPkt
950 /* \\\ */
952 /* /// "nWritePacket()" */
953 BOOL nWritePacket(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
955 ULONG packettype;
956 struct EtherPacketHeader *eph;
957 UBYTE *copydest;
958 UWORD writelen;
959 struct BufMan *bufman;
960 struct Sana2PacketTypeStats *stats;
961 UBYTE *buf = ncp->ncp_WriteBuffer[ncp->ncp_WriteBufNum];
963 packettype = ioreq->ios2_PacketType;
964 // the first two bytes are the length
965 eph = (struct EtherPacketHeader *) buf;
966 copydest = buf;
967 writelen = ioreq->ios2_DataLength;
968 bufman = ioreq->ios2_BufferManagement;
970 /* Not a raw packet? */
971 if(!(ioreq->ios2_Req.io_Flags & SANA2IOF_RAW))
973 UWORD cnt;
974 KPRINTF(10, ("RAW WRITE!\n"));
975 /* The ethernet header isn't included in the data */
976 /* Build ethernet packet header */
977 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
979 eph->eph_Dest[cnt] = ioreq->ios2_DstAddr[cnt];
980 eph->eph_Src[cnt] = ncp->ncp_MacAddress[cnt];
982 eph->eph_Type = AROS_BE2WORD(packettype);
984 /* Packet data is at txbuffer */
985 copydest += sizeof(struct EtherPacketHeader);
986 writelen += sizeof(struct EtherPacketHeader);
989 /* Dma not available, fallback to regular copy */
990 if(callcopy(bufman->bm_CopyFromBuf, copydest, ioreq->ios2_Data, ioreq->ios2_DataLength) == NULL)
992 KPRINTF(10, ("writepacket: copyfrom returned failure!\n"));
994 /* Trigger any tx, buff or generic error events */
995 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_TX|S2EVENT_BUFF);
997 /* Set error code and terminate the iorequest.
998 NOTE: Can't use RC_* or deverror() this is not
999 called from devBeginIO()! */
1000 ioreq->ios2_DataLength = 0;
1001 ioreq->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
1002 ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
1003 return FALSE;
1006 KPRINTF(20, ("PktOut[%ld] %ld\n", ncp->ncp_WriteBufNum, writelen));
1008 ncp->ncp_WritePending[ncp->ncp_WriteBufNum] = ioreq;
1009 psdSendPipe(ncp->ncp_EPOutPipe[ncp->ncp_WriteBufNum], buf, (ULONG) writelen);
1010 ncp->ncp_WriteBufNum ^= 1;
1013 if(AROS_BE2WORD(eph->eph_Type) < 1500)
1015 KPRINTF(5, ("writepacket: %04lx%08lx > %04lx%08lx (IEEE802.3) len %lu, %lu bytes\n",
1016 *((UWORD *) eph->eph_Src), *((ULONG *) (eph->eph_Src + 2)),
1017 *((UWORD *) eph->eph_Dest), *((ULONG *) (eph->eph_Dest + 2)),
1018 AROS_BE2WORD(eph->eph_Type), writelen));
1019 } else {
1020 KPRINTF(5, ("writepacket: %04lx%08lx > %04lx%08lx type %lu, %lu bytes\n",
1021 *((UWORD *) eph->eph_Src), *((ULONG *) (eph->eph_Src + 2)),
1022 *((UWORD *) eph->eph_Dest), *((ULONG *) (eph->eph_Dest + 2)),
1023 AROS_BE2WORD(eph->eph_Type), writelen));
1025 //dumpmem(buf, (ULONG) writelen);
1028 /* Update statistics */
1029 stats = FindPacketTypeStats(ncp, packettype);
1030 if(stats)
1032 stats->PacketsSent++;
1033 stats->BytesSent += writelen;
1035 ncp->ncp_DeviceStats.PacketsSent++;
1037 return TRUE;
1039 /* \\\ */
1041 /* /// "nReadIOReq()" */
1042 UWORD nReadIOReq(struct NepClassEth *ncp, struct EtherPacketHeader *eph, UWORD datasize, struct IOSana2Req *ioreq, UWORD flags)
1044 LIBBASETYPEPTR nh = ncp->ncp_ClsBase;
1045 UBYTE *copyfrom;
1046 UWORD cnt;
1048 /* Handle RAW read */
1049 if(ioreq->ios2_Req.io_Flags & SANA2IOF_RAW)
1051 /* ShapeShifter won't work with `sizeof(struct etherpacket_hdr)'
1052 here. This is most likely because it want the RAW ethernet
1053 packet checksum size (4) added to the packet size. */
1054 copyfrom = (UBYTE *) eph;
1055 datasize += sizeof(struct EtherPacketHeader) + 4;
1056 } else {
1057 copyfrom = (UBYTE *) (eph + 1);
1060 /* Build up the ios2 structure enough so we can call the packet filter. */
1061 ioreq->ios2_PacketType = AROS_BE2WORD(eph->eph_Type);
1062 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
1064 ioreq->ios2_SrcAddr[cnt] = eph->eph_Src[cnt];
1065 ioreq->ios2_DstAddr[cnt] = eph->eph_Dest[cnt];
1067 ioreq->ios2_DataLength = datasize;
1068 /* Call the packet filter, if available. */
1069 if((flags & PACKETFILTER) &&
1070 (((struct BufMan *) ioreq->ios2_BufferManagement)->bm_PacketFilter) &&
1071 (!callfilter(((struct BufMan *) ioreq->ios2_BufferManagement)->bm_PacketFilter,
1072 ioreq, copyfrom)))
1074 /* This packet got dropped! */
1075 KPRINTF(7, ("readioreq: packet type %lu for ioreq 0x%08lx dropped\n",
1076 AROS_BE2WORD(eph->eph_Type), ioreq));
1077 return flags;
1081 /* Ok, the packet didn't get dropped, set the BCAST and MCAST
1082 flags according to dstaddr. */
1084 /* Address == Multicast? */
1085 if(ioreq->ios2_DstAddr[0] & 1)
1087 /* Address == Broadcast? */
1088 static const UBYTE bcast[ETHER_ADDR_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1089 if(memcmp(bcast, ioreq->ios2_DstAddr, ETHER_ADDR_SIZE) == 0)
1091 ioreq->ios2_Req.io_Flags |= SANA2IOF_BCAST;
1092 } else {
1093 ioreq->ios2_Req.io_Flags |= SANA2IOF_MCAST;
1097 /* Finally copy the packet data! */
1098 if(callcopy(((struct BufMan *) ioreq->ios2_BufferManagement)->bm_CopyToBuf,
1099 ioreq->ios2_Data, copyfrom, ioreq->ios2_DataLength))
1102 KPRINTF(5, ("readioreq: copytobuffed packet ior 0x%08lx, %04lx%08lx < %04lx%08lx, type %lu, %lu bytes, %s%s%s\n",
1103 ioreq,
1104 *((UWORD *) ioreq->ios2_DstAddr), *((ULONG *) (ioreq->ios2_DstAddr + 2)),
1105 *((UWORD *) ioreq->ios2_SrcAddr), *((ULONG *) (ioreq->ios2_SrcAddr + 2)),
1106 ioreq->ios2_PacketType, ioreq->ios2_DataLength,
1107 (ioreq->ios2_Req.io_Flags & SANA2IOF_RAW) ? "RAW " : "",
1108 (ioreq->ios2_Req.io_Flags & SANA2IOF_BCAST) ? "BCAST " : "",
1109 (ioreq->ios2_Req.io_Flags & SANA2IOF_MCAST) ? "MCAST " : ""));
1110 //dumpmem(copyfrom, ioreq->ios2_DataLength);
1113 /* Clear the dropped flag */
1114 flags &= ~DROPPED;
1115 } else {
1116 KPRINTF(10, ("readioreq: copyto returned failure!\n"));
1118 /* Trigger any rx, buff or generic error events */
1119 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_RX|S2EVENT_BUFF);
1121 /* Set error code.
1122 NOTE: Can't use RC_* or deverror() this is not called from devBeginIO()!
1124 ioreq->ios2_DataLength = 0;
1125 ioreq->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
1126 ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
1129 /* Pull the ioreq off the list & terminate it */
1130 Forbid();
1131 Remove((struct Node *) ioreq);
1132 Permit();
1133 ReplyMsg((struct Message *) ioreq);
1134 return flags;
1136 /* \\\ */
1138 /* /// "nReadPacket()" */
1139 BOOL nReadPacket(struct NepClassEth *ncp, UBYTE *pktptr, ULONG pktlen)
1141 struct EtherPacketHeader *eph;
1142 struct BufMan *bufman;
1143 struct IOSana2Req *worknode, *nextnode;
1144 struct Sana2PacketTypeStats *stats;
1145 UWORD flags;
1146 UWORD datasize;
1148 KPRINTF(20, ("PktIn [%ld] %ld\n", ncp->ncp_ReadBufNum, pktlen));
1150 if(pktlen < 14)
1152 ncp->ncp_DeviceStats.BadData++;
1153 return FALSE;
1155 ncp->ncp_DeviceStats.PacketsReceived++;
1157 eph = (struct EtherPacketHeader *) pktptr;
1158 stats = FindPacketTypeStats(ncp, (ULONG) AROS_BE2WORD(eph->eph_Type));
1159 flags = DROPPED|PACKETFILTER;
1161 /* Calculate size of the actual data */
1162 datasize = pktlen - sizeof(struct EtherPacketHeader);
1164 /* Is the packet datasize valid? */
1165 if(pktlen <= ETHER_MAX_LEN)
1167 /* Update the packet statistics */
1168 if(stats)
1170 stats->PacketsReceived++;
1171 stats->BytesReceived += datasize; /* NOTE: don't include headers */
1174 /* For each device user (bufman)
1175 NOTE: We absolutely *MUST* try to offer the packet to *all*
1176 different device users (SANA-II V2 spec requirement). */
1177 Forbid();
1178 bufman = (struct BufMan *) ncp->ncp_BufManList.lh_Head;
1179 while(((struct Node *) bufman)->ln_Succ)
1181 /* For each queued read request (ioreq) */
1182 worknode = (struct IOSana2Req *) bufman->bm_RXQueue.lh_Head;
1183 while((nextnode = (struct IOSana2Req *) (((struct Node *) worknode)->ln_Succ)))
1185 /* Check the packet type. Also handles 802.3 packets. */
1186 if((worknode->ios2_PacketType == AROS_BE2WORD(eph->eph_Type)) ||
1187 ((AROS_BE2WORD(eph->eph_Type) < 1500) && (worknode->ios2_PacketType < 1500)))
1189 flags = nReadIOReq(ncp, eph, datasize, worknode, flags);
1190 /* Break out - let other callers get the packet too */
1191 break;
1193 worknode = nextnode;
1195 bufman = (struct BufMan *) (((struct Node *) bufman)->ln_Succ);
1197 Permit();
1198 /* Now we've tried to give the packet to every CMD_READ caller.
1199 If DROPPED is set at this point no-one wanted this packet. */
1200 if(flags & DROPPED)
1202 /* So there were no outstanding CMD_READs or the packet wasn't
1203 accepted by any of them. Okay, check if we have any pending
1204 S2_READORPHAN ioreq in list and if we have return this packet
1205 with it. Note that packet filter must not be used for this
1206 time!
1208 NOTE: orphanlist is global, ie. only one caller will get the
1209 packet if multiple users have pending S2_READORPHANs.
1212 /* Process pending orphanread iorequs */
1213 Forbid();
1214 worknode = (struct IOSana2Req *) ncp->ncp_OrphanQueue.lh_Head;
1215 while((nextnode = (struct IOSana2Req *) (((struct Node *) worknode)->ln_Succ)))
1217 nReadIOReq(ncp, eph, datasize, worknode, 0);
1218 worknode = nextnode;
1220 Permit();
1221 } else {
1222 /* Packet not dropped - return ok */
1223 return TRUE;
1225 } else {
1226 KPRINTF(20, ("Pktlen %ld invalid!\n", pktlen));
1227 ncp->ncp_DeviceStats.BadData++;
1229 /* Update global dropped packet counter. */
1230 ncp->ncp_DeviceStats.UnknownTypesReceived++;
1232 /* Update dropped packet statistics. */
1233 if(stats)
1235 stats->PacketsDropped++;
1237 KPRINTF(9, ("readpacket: packet type %lu dropped\n", AROS_BE2WORD(eph->eph_Type)));
1239 /* Trigger any rx or generic error events */
1240 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_RX);
1241 return FALSE;
1243 /* \\\ */
1245 /**************************************************************************/
1247 /* /// "nGetMACAddress()" */
1248 void nGetMACAddress(UBYTE *macaddr, CONST_STRPTR tmpstr)
1250 ULONG macbyte = 0;
1251 UBYTE ch;
1252 UWORD cnt = 0;
1254 while((ch = *tmpstr++))
1256 if((ch >= '0') && (ch <= '9'))
1258 macbyte <<= 4;
1259 macbyte += ch - '0';
1261 else if((ch >= 'a') && (ch <= 'f'))
1263 macbyte <<= 4;
1264 macbyte += ch - 'a' + 10;
1266 else if((ch >= 'A') && (ch <= 'F'))
1268 macbyte <<= 4;
1269 macbyte += ch - 'A' + 10;
1271 else if(ch == ':')
1273 if(cnt == 5)
1275 break;
1277 macaddr[cnt] = macbyte;
1278 macbyte = 0;
1279 cnt++;
1282 macaddr[cnt] = macbyte;
1284 /* \\\ */
1286 /* /// "nGUITask()" */
1287 AROS_UFH0(void, nGUITask)
1289 AROS_USERFUNC_INIT
1291 struct Task *thistask;
1292 struct NepEthBase *nh;
1293 struct NepClassEth *ncp;
1294 struct PsdIFFContext *pic;
1295 UBYTE macaddr[20];
1297 thistask = FindTask(NULL);
1298 #undef ps
1299 #define ps ncp->ncp_PsdBase
1300 #undef IntuitionBase
1301 #define IntuitionBase ncp->ncp_IntBase
1302 #undef MUIMasterBase
1303 #define MUIMasterBase ncp->ncp_MUIBase
1305 ncp = thistask->tc_UserData;
1306 nh = ncp->ncp_ClsBase;
1308 ++nh->nh_Library.lib_OpenCnt;
1309 if(!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN)))
1311 KPRINTF(10, ("Couldn't open muimaster.library.\n"));
1312 nGUITaskCleanup(ncp);
1313 return;
1316 if(!(IntuitionBase = OpenLibrary("intuition.library", 39)))
1318 KPRINTF(10, ("Couldn't open intuition.library.\n"));
1319 nGUITaskCleanup(ncp);
1320 return;
1322 if(!(ps = OpenLibrary("poseidon.library", 4)))
1324 KPRINTF(10, ("Couldn't open poseidon.library.\n"));
1325 nGUITaskCleanup(ncp);
1326 return;
1329 psdSafeRawDoFmt(macaddr, 20, "%02lx:%02lx:%02lx:%02lx:%02lx:%02lx",
1330 ncp->ncp_CDC->cdc_MACAddress[0],
1331 ncp->ncp_CDC->cdc_MACAddress[1],
1332 ncp->ncp_CDC->cdc_MACAddress[2],
1333 ncp->ncp_CDC->cdc_MACAddress[3],
1334 ncp->ncp_CDC->cdc_MACAddress[4],
1335 ncp->ncp_CDC->cdc_MACAddress[5]);
1337 ncp->ncp_App = ApplicationObject,
1338 MUIA_Application_Title , (IPTR)libname,
1339 MUIA_Application_Version , (IPTR)VERSION_STRING,
1340 MUIA_Application_Copyright , (IPTR)"©2006-2007 Harry Sintonen & Chris Hodges",
1341 MUIA_Application_Author , (IPTR)"Harry Sintonen <sintonen@iki.fi> & Chris Hodges <chrisly@platon42.de>",
1342 MUIA_Application_Description, (IPTR)"Settings for the ethwrap.class",
1343 MUIA_Application_Base , (IPTR)"ETHWRAP",
1344 MUIA_Application_HelpFile , (IPTR)"HELP:Poseidon.guide",
1345 MUIA_Application_Menustrip , (IPTR)MenustripObject,
1346 Child, (IPTR)MenuObjectT((IPTR)"Project"),
1347 Child, (IPTR)(ncp->ncp_AboutMI = MenuitemObject,
1348 MUIA_Menuitem_Title, (IPTR)"About...",
1349 MUIA_Menuitem_Shortcut, (IPTR)"?",
1350 End),
1351 End,
1352 Child, (IPTR)MenuObjectT((IPTR)"Settings"),
1353 Child, (IPTR)(ncp->ncp_UseMI = MenuitemObject,
1354 MUIA_Menuitem_Title, (IPTR)"Save",
1355 MUIA_Menuitem_Shortcut, (IPTR)"S",
1356 End),
1357 Child, (IPTR)(ncp->ncp_SetDefaultMI = MenuitemObject,
1358 MUIA_Menuitem_Title, (IPTR)"Set as Default",
1359 MUIA_Menuitem_Shortcut, (IPTR)"D",
1360 End),
1361 Child, (IPTR)MenuitemObject,
1362 MUIA_Menuitem_Title, (IPTR)NM_BARLABEL,
1363 End,
1364 Child, (IPTR)(ncp->ncp_MUIPrefsMI = MenuitemObject,
1365 MUIA_Menuitem_Title, (IPTR)"MUI Settings",
1366 MUIA_Menuitem_Shortcut, (IPTR)"M",
1367 End),
1368 End,
1369 End,
1371 SubWindow, (IPTR)(ncp->ncp_MainWindow = WindowObject,
1372 MUIA_Window_ID , MAKE_ID('M','A','I','N'),
1373 MUIA_Window_Title, (IPTR)libname,
1374 MUIA_HelpNode, (IPTR)libname,
1376 WindowContents, (IPTR)VGroup,
1377 Child, (IPTR)ColGroup(2), GroupFrameT(ncp->ncp_Interface ? "Device Settings" : "Default Device Settings"),
1378 //Child, HSpace(0),
1379 Child, (IPTR)Label((IPTR) "Default MAC Address:"),
1380 Child, (IPTR)(ncp->ncp_MACAddressObj = StringObject,
1381 StringFrame,
1382 MUIA_CycleChain, 1,
1383 MUIA_String_AdvanceOnCR, TRUE,
1384 MUIA_String_Contents, (IPTR)macaddr,
1385 MUIA_String_MaxLen, 18,
1386 MUIA_String_Accept, (IPTR)"0123456789abcdefABCDEF:",
1387 End),
1388 Child, (IPTR)Label((IPTR) "Default " DEVNAME " Unit:"),
1389 Child, (IPTR)(ncp->ncp_UnitObj = StringObject,
1390 StringFrame,
1391 MUIA_CycleChain, 1,
1392 MUIA_String_AdvanceOnCR, TRUE,
1393 MUIA_String_Integer, ncp->ncp_CDC->cdc_DefaultUnit,
1394 MUIA_String_Accept, (IPTR)"0123456789",
1395 End),
1396 End,
1397 Child, (IPTR)VSpace(0),
1398 Child, (IPTR)HGroup,
1399 MUIA_Group_SameWidth, TRUE,
1400 Child, (IPTR)(ncp->ncp_UseObj = TextObject, ButtonFrame,
1401 MUIA_ShowMe, (IPTR)ncp->ncp_Interface,
1402 MUIA_Background, MUII_ButtonBack,
1403 MUIA_CycleChain, 1,
1404 MUIA_InputMode, MUIV_InputMode_RelVerify,
1405 MUIA_Text_Contents, (IPTR)"\33c Save ",
1406 End),
1407 Child, (IPTR)(ncp->ncp_SetDefaultObj = TextObject, ButtonFrame,
1408 MUIA_Background, MUII_ButtonBack,
1409 MUIA_CycleChain, 1,
1410 MUIA_InputMode, MUIV_InputMode_RelVerify,
1411 MUIA_Text_Contents, (IPTR)(ncp->ncp_Interface ? "\33c Save as Default " : "\33c Save Defaults "),
1412 End),
1413 Child, (IPTR)(ncp->ncp_CloseObj = TextObject, ButtonFrame,
1414 MUIA_Background, MUII_ButtonBack,
1415 MUIA_CycleChain, 1,
1416 MUIA_InputMode, MUIV_InputMode_RelVerify,
1417 MUIA_Text_Contents, (IPTR)"\33c Use ",
1418 End),
1419 End,
1420 End,
1421 End),
1422 End;
1424 if(!ncp->ncp_App)
1426 KPRINTF(10, ("Couldn't create application\n"));
1427 nGUITaskCleanup(ncp);
1428 return;
1431 DoMethod(ncp->ncp_MainWindow, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
1432 ncp->ncp_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
1433 DoMethod(ncp->ncp_UseObj, MUIM_Notify, MUIA_Pressed, FALSE,
1434 ncp->ncp_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG);
1435 DoMethod(ncp->ncp_SetDefaultObj, MUIM_Notify, MUIA_Pressed, FALSE,
1436 ncp->ncp_App, 2, MUIM_Application_ReturnID, ID_DEF_CONFIG);
1437 DoMethod(ncp->ncp_CloseObj, MUIM_Notify, MUIA_Pressed, FALSE,
1438 ncp->ncp_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
1440 DoMethod(ncp->ncp_AboutMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
1441 ncp->ncp_App, 2, MUIM_Application_ReturnID, ID_ABOUT);
1442 DoMethod(ncp->ncp_UseMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
1443 ncp->ncp_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG);
1444 DoMethod(ncp->ncp_SetDefaultMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
1445 ncp->ncp_App, 2, MUIM_Application_ReturnID, ID_DEF_CONFIG);
1446 DoMethod(ncp->ncp_MUIPrefsMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
1447 ncp->ncp_App, 2, MUIM_Application_OpenConfigWindow, 0);
1449 IPTR isopen = 0;
1450 IPTR iconify = 0;
1451 ULONG sigs;
1452 ULONG sigmask;
1453 LONG retid;
1455 get(ncp->ncp_App, MUIA_Application_Iconified, &iconify);
1456 set(ncp->ncp_MainWindow, MUIA_Window_Open, TRUE);
1457 get(ncp->ncp_MainWindow, MUIA_Window_Open, &isopen);
1458 if(!(isopen || iconify))
1460 nGUITaskCleanup(ncp);
1461 return;
1463 sigmask = 0;
1466 retid = DoMethod(ncp->ncp_App, MUIM_Application_NewInput, &sigs);
1467 switch(retid)
1469 case ID_DEF_CONFIG:
1470 case ID_STORE_CONFIG:
1471 case MUIV_Application_ReturnID_Quit:
1473 CONST_STRPTR tmpstr = "";
1474 get(ncp->ncp_UnitObj, MUIA_String_Integer, &ncp->ncp_CDC->cdc_DefaultUnit);
1475 get(ncp->ncp_MACAddressObj, MUIA_String_Contents, &tmpstr);
1477 nGetMACAddress(ncp->ncp_CDC->cdc_MACAddress, tmpstr);
1479 if(retid == ID_DEF_CONFIG)
1481 pic = psdGetClsCfg(libname);
1482 if(!pic)
1484 psdSetClsCfg(libname, NULL);
1485 pic = psdGetClsCfg(libname);
1487 if(pic)
1489 psdAddCfgEntry(pic, ncp->ncp_CDC);
1490 psdSaveCfgToDisk(NULL, FALSE);
1493 if(ncp->ncp_Interface)
1495 pic = psdGetUsbDevCfg(libname, ncp->ncp_DevIDString, NULL);
1496 if(!pic)
1498 psdSetUsbDevCfg(libname, ncp->ncp_DevIDString, NULL, NULL);
1499 pic = psdGetUsbDevCfg(libname, ncp->ncp_DevIDString, NULL);
1501 if(pic)
1503 if(psdAddCfgEntry(pic, ncp->ncp_CDC))
1505 if(retid != MUIV_Application_ReturnID_Quit)
1507 psdSaveCfgToDisk(NULL, FALSE);
1509 retid = MUIV_Application_ReturnID_Quit;
1512 } else {
1513 retid = MUIV_Application_ReturnID_Quit;
1515 break;
1518 case ID_ABOUT:
1519 MUI_RequestA(ncp->ncp_App, ncp->ncp_MainWindow, 0, NULL, "Phat!", VERSION_STRING, NULL);
1520 break;
1522 if(retid == MUIV_Application_ReturnID_Quit)
1524 break;
1526 if(sigs)
1528 sigs = Wait(sigs|sigmask|SIGBREAKF_CTRL_C);
1529 if(sigs & SIGBREAKF_CTRL_C)
1531 break;
1534 } while(TRUE);
1535 set(ncp->ncp_MainWindow, MUIA_Window_Open, FALSE);
1537 nGUITaskCleanup(ncp);
1539 AROS_USERFUNC_EXIT
1541 /* \\\ */
1543 /* /// "nGUITaskCleanup()" */
1544 void nGUITaskCleanup(struct NepClassEth *ncp)
1546 if(ncp->ncp_App)
1548 MUI_DisposeObject(ncp->ncp_App);
1549 ncp->ncp_App = NULL;
1551 if(MUIMasterBase)
1553 CloseLibrary(MUIMasterBase);
1554 MUIMasterBase = NULL;
1556 if(IntuitionBase)
1558 CloseLibrary(IntuitionBase);
1559 IntuitionBase = NULL;
1561 if(ps)
1563 CloseLibrary(ps);
1564 ps = NULL;
1566 Forbid();
1567 ncp->ncp_GUIBinding = NULL;
1568 ncp->ncp_GUITask = NULL;
1569 if(ncp->ncp_ReadySigTask)
1571 Signal(ncp->ncp_ReadySigTask, 1L<<ncp->ncp_ReadySignal);
1573 --ncp->ncp_ClsBase->nh_Library.lib_OpenCnt;
1575 /* \\\ */