revert between 56095 -> 55830 in arch
[AROS.git] / rom / usb / classes / davicometh / dm9601eth.class.c
blob3266e9c369bc19f18ef1010c54bc89b48352e712
1 /*
2 *----------------------------------------------------------------------------
3 * dm9601eth class for poseidon
4 *----------------------------------------------------------------------------
5 * By Chris Hodges <chrisly@platon42.de>
6 */
8 #include "debug.h"
10 #include "dm9601eth.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 dm9601eth.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! dm9601eth.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 /* \\\ */
119 * ***********************************************************************
120 * * Library functions *
121 * ***********************************************************************
124 struct AutoBindData
126 UWORD abd_VendID;
127 UWORD abd_ProdID;
130 struct AutoBindData ClassBinds[] =
132 { 0x07aa, 0x9601 }, /* Corega FEther USB-TXC */
133 { 0x0a46, 0x9601 }, /* Davicom USB-100 */
134 { 0x0a46, 0x6688 }, /* ZT6688 USB NIC */
135 { 0x0a46, 0x0268 }, /* ShanTou ST268 USB NIC */
136 { 0x0a46, 0x8515 }, /* ADMtek ADM8515 USB NIC */
137 { 0x0a47, 0x9601 }, /* Hirose USB-100 */
138 { 0x0fe6, 0x8101 }, /* DM9601 USB to Fast Ethernet Adapter */
139 { 0, 0 }
142 /* /// "usbAttemptDeviceBinding()" */
143 struct NepClassEth * usbAttemptDeviceBinding(struct NepEthBase *nh, struct PsdDevice *pd)
145 struct Library *ps;
146 struct AutoBindData *abd = ClassBinds;
147 IPTR prodid;
148 IPTR vendid;
150 KPRINTF(1, ("nepEthAttemptDeviceBinding(%08lx)\n", pd));
152 if((ps = OpenLibrary("poseidon.library", 4)))
154 psdGetAttrs(PGA_DEVICE, pd,
155 DA_VendorID, &vendid,
156 DA_ProductID, &prodid,
157 TAG_END);
158 CloseLibrary(ps);
159 while(abd->abd_VendID)
161 if((vendid == abd->abd_VendID) && (prodid == abd->abd_ProdID))
163 return(usbForceDeviceBinding(nh, pd));
165 abd++;
168 return(NULL);
170 /* \\\ */
172 /* /// "usbForceDeviceBinding()" */
173 struct NepClassEth * usbForceDeviceBinding(struct NepEthBase *nh, struct PsdDevice *pd)
175 struct Library *ps;
176 struct NepClassEth *ncp;
177 struct NepClassEth *tmpncp;
178 struct ClsDevCfg *cdc;
179 struct AutoBindData *abd = ClassBinds;
180 STRPTR devname;
181 STRPTR devidstr;
182 IPTR prodid;
183 IPTR vendid;
184 ULONG unitno;
185 BOOL unitfound;
186 UBYTE buf[64];
187 struct Task *tmptask;
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 while(abd->abd_VendID)
203 if((vendid == abd->abd_VendID) && (prodid == abd->abd_ProdID))
205 break;
207 abd++;
210 unitfound = FALSE;
211 unitno = (ULONG) -1;
212 ncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
213 while(ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
215 if(!strcmp(ncp->ncp_DevIDString, devidstr))
217 unitno = ncp->ncp_UnitNo;
218 unitfound = TRUE;
219 break;
221 ncp = (struct NepClassEth *) ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
223 if(!unitfound)
225 /* as units are freed in the expunge-vector, the memory is
226 outside the scope of the poseidon library */
227 if(!(ncp = AllocVec(sizeof(struct NepClassEth), MEMF_PUBLIC|MEMF_CLEAR)))
229 Permit();
230 CloseLibrary(ps);
231 return(NULL);
233 ncp->ncp_CDC = cdc = AllocVec(sizeof(struct ClsDevCfg), MEMF_PUBLIC|MEMF_CLEAR);
234 if(!cdc)
236 Permit();
237 FreeVec(ncp);
238 CloseLibrary(ps);
239 return(NULL);
241 /* IORequests may be queued even if the task is gone. */
242 ncp->ncp_UnitNo = (ULONG) -1;
243 NewList(&ncp->ncp_Unit.unit_MsgPort.mp_MsgList);
244 NewList(&ncp->ncp_OrphanQueue);
245 NewList(&ncp->ncp_WriteQueue);
246 NewList(&ncp->ncp_BufManList);
247 NewList(&ncp->ncp_EventList);
248 NewList(&ncp->ncp_TrackList);
249 NewList(&ncp->ncp_Multicasts);
250 strncpy(ncp->ncp_DevIDString, devidstr, 127);
251 AddTail(&nh->nh_Units, &ncp->ncp_Unit.unit_MsgPort.mp_Node);
253 ncp->ncp_ClsBase = nh;
254 ncp->ncp_Device = pd;
255 ncp->ncp_UnitProdID = prodid;
256 ncp->ncp_UnitVendorID = vendid;
258 nLoadBindingConfig(ncp);
260 /* Find next free unit number */
261 if(unitno == (ULONG) -1)
263 unitno = ncp->ncp_CDC->cdc_DefaultUnit;
264 tmpncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
265 while(tmpncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
267 if(tmpncp->ncp_UnitNo == unitno)
269 unitno++;
270 tmpncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
271 } else {
272 tmpncp = (struct NepClassEth *) tmpncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
276 ncp->ncp_UnitNo = unitno;
277 Permit();
279 psdSafeRawDoFmt(buf, 64, "dm9601eth.class<%08lx>", ncp);
280 ncp->ncp_ReadySignal = SIGB_SINGLE;
281 ncp->ncp_ReadySigTask = FindTask(NULL);
282 SetSignal(0, SIGF_SINGLE);
283 if((tmptask = psdSpawnSubTask(buf, nEthTask, ncp)))
285 psdBorrowLocksWait(tmptask, 1UL<<ncp->ncp_ReadySignal);
286 if(ncp->ncp_Task)
288 ncp->ncp_ReadySigTask = NULL;
289 //FreeSignal(ncp->ncp_ReadySignal);
290 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
291 "And Goliath trembled with fear over '%s' on %s unit %ld!",
292 devname, nh->nh_DevBase->np_Library.lib_Node.ln_Name,
293 ncp->ncp_UnitNo);
295 CloseLibrary(ps);
296 return(ncp);
299 ncp->ncp_ReadySigTask = NULL;
300 //FreeSignal(ncp->ncp_ReadySignal);
301 /* Get rid of unit structure */
302 /*Forbid();
303 Remove((struct Node *) ncp);
304 FreeVec(ncp->ncp_CDC);
305 FreeVec(ncp);
306 Permit();*/
307 CloseLibrary(ps);
309 return(NULL);
311 /* \\\ */
313 /* /// "usbReleaseDeviceBinding()" */
314 void usbReleaseDeviceBinding(struct NepEthBase *nh, struct NepClassEth *ncp)
316 struct Library *ps;
317 STRPTR devname;
318 KPRINTF(1, ("nepEthReleaseDeviceBinding(%08lx)\n", ncp));
320 if((ps = OpenLibrary("poseidon.library", 4)))
322 Forbid();
323 ncp->ncp_ReadySignal = SIGB_SINGLE;
324 ncp->ncp_ReadySigTask = FindTask(NULL);
325 if(ncp->ncp_Task)
327 Signal(ncp->ncp_Task, SIGBREAKF_CTRL_C);
329 Permit();
330 while(ncp->ncp_Task)
332 Wait(1L<<ncp->ncp_ReadySignal);
334 //FreeSignal(ncp->ncp_ReadySignal);
335 psdGetAttrs(PGA_DEVICE, ncp->ncp_Device, DA_ProductName, &devname, TAG_END);
336 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
337 "But finally Goliath crushed '%s'.",
338 devname);
339 /*psdFreeVec(ncp);*/
340 CloseLibrary(ps);
343 /* \\\ */
345 /* /// "usbGetAttrsA()" */
346 AROS_LH3(LONG, usbGetAttrsA,
347 AROS_LHA(ULONG, type, D0),
348 AROS_LHA(APTR, usbstruct, A0),
349 AROS_LHA(struct TagItem *, tags, A1),
350 LIBBASETYPEPTR, nh, 5, nep)
352 AROS_LIBFUNC_INIT
354 struct TagItem *ti;
355 LONG count = 0;
357 KPRINTF(1, ("nepEthGetAttrsA(%ld, %08lx, %08lx)\n", type, usbstruct, tags));
358 switch(type)
360 case UGA_CLASS:
361 if((ti = FindTagItem(UCCA_Priority, tags)))
363 *((SIPTR *) ti->ti_Data) = 0;
364 count++;
366 if((ti = FindTagItem(UCCA_Description, tags)))
368 *((STRPTR *) ti->ti_Data) = "Ethernet SANA driver for Davicom chipsets via dm9601eth.device";
369 count++;
371 if((ti = FindTagItem(UCCA_HasClassCfgGUI, tags)))
373 *((IPTR *) ti->ti_Data) = TRUE;
374 count++;
376 if((ti = FindTagItem(UCCA_HasBindingCfgGUI, tags)))
378 *((IPTR *) ti->ti_Data) = TRUE;
379 count++;
381 if((ti = FindTagItem(UCCA_AfterDOSRestart, tags)))
383 *((IPTR *) ti->ti_Data) = FALSE;
384 count++;
386 if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags)))
388 *((IPTR *) ti->ti_Data) = nh->nh_DummyNCP.ncp_UsingDefaultCfg;
389 count++;
391 break;
393 case UGA_BINDING:
394 if((ti = FindTagItem(UCBA_UsingDefaultCfg, tags)))
396 *((IPTR *) ti->ti_Data) = ((struct NepClassEth *) usbstruct)->ncp_UsingDefaultCfg;
397 count++;
399 break;
401 return(count);
402 AROS_LIBFUNC_EXIT
404 /* \\\ */
406 /* /// "usbSetAttrsA()" */
407 AROS_LH3(LONG, usbSetAttrsA,
408 AROS_LHA(ULONG, type, D0),
409 AROS_LHA(APTR, usbstruct, A0),
410 AROS_LHA(struct TagItem *, tags, A1),
411 LIBBASETYPEPTR, nh, 6, nep)
413 AROS_LIBFUNC_INIT
414 return(0);
415 AROS_LIBFUNC_EXIT
417 /* \\\ */
419 /* /// "usbDoMethodA()" */
420 AROS_LH2(IPTR, usbDoMethodA,
421 AROS_LHA(ULONG, methodid, D0),
422 AROS_LHA(IPTR *, methoddata, A1),
423 LIBBASETYPEPTR, nh, 7, nep)
425 AROS_LIBFUNC_INIT
427 struct NepClassEth *ncp;
429 KPRINTF(10, ("Do Method %ld\n", methodid));
430 switch(methodid)
432 case UCM_AttemptDeviceBinding:
433 return((IPTR) usbAttemptDeviceBinding(nh, (struct PsdDevice *) methoddata[0]));
435 case UCM_ForceDeviceBinding:
436 return((IPTR) usbForceDeviceBinding(nh, (struct PsdDevice *) methoddata[0]));
438 case UCM_ReleaseDeviceBinding:
439 usbReleaseDeviceBinding(nh, (struct NepClassEth *) methoddata[0]);
440 return(TRUE);
442 case UCM_OpenCfgWindow:
443 return(nOpenBindingCfgWindow(nh, &nh->nh_DummyNCP));
445 case UCM_OpenBindingCfgWindow:
446 return(nOpenBindingCfgWindow(nh, (struct NepClassEth *) methoddata[0]));
448 case UCM_ConfigChangedEvent:
449 nLoadClassConfig(nh);
450 Forbid();
451 ncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
452 while(ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
454 nLoadBindingConfig(ncp);
455 ncp = (struct NepClassEth *) ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
457 Permit();
458 return(TRUE);
460 default:
461 break;
463 return(0);
464 AROS_LIBFUNC_EXIT
466 /* \\\ */
468 /* /// "nLoadClassConfig()" */
469 BOOL nLoadClassConfig(struct NepEthBase *nh)
471 struct NepClassEth *ncp = &nh->nh_DummyNCP;
472 struct Library *ps;
473 struct ClsDevCfg *cdc;
474 struct PsdIFFContext *pic;
476 KPRINTF(10, ("Loading Class Config...\n"));
477 if(ncp->ncp_GUITask)
479 return(FALSE);
481 if(!(ps = OpenLibrary("poseidon.library", 4)))
483 return(FALSE);
486 Forbid();
487 /* Create default config */
488 cdc = ncp->ncp_CDC;
489 cdc->cdc_ChunkID = AROS_LONG2BE(MAKE_ID('D','M','9','6'));
490 cdc->cdc_Length = AROS_LONG2BE(sizeof(struct ClsDevCfg)-8);
491 cdc->cdc_DefaultUnit = 0;
492 cdc->cdc_MediaType = 0;
493 ncp->ncp_UsingDefaultCfg = TRUE;
494 /* try to load default config */
495 pic = psdGetClsCfg(libname);
496 if(pic)
498 cdc = psdGetCfgChunk(pic, AROS_LONG2BE(ncp->ncp_CDC->cdc_ChunkID));
499 if(cdc)
501 CopyMem(((UBYTE *) cdc) + 8, ((UBYTE *) ncp->ncp_CDC) + 8, min(AROS_LONG2BE(cdc->cdc_Length), AROS_LONG2BE(ncp->ncp_CDC->cdc_Length)));
502 psdFreeVec(cdc);
503 ncp->ncp_UsingDefaultCfg = FALSE;
506 Permit();
507 CloseLibrary(ps);
508 return(FALSE);
510 /* \\\ */
512 /* /// "nLoadBindingConfig()" */
513 BOOL nLoadBindingConfig(struct NepClassEth *ncp)
515 struct NepEthBase *nh = ncp->ncp_ClsBase;
516 struct Library *ps;
517 struct ClsDevCfg *cdc;
518 struct PsdIFFContext *pic;
520 KPRINTF(10, ("Loading Binding Config...\n"));
521 if(ncp->ncp_GUITask)
523 return(FALSE);
525 //nLoadClassConfig(nh);
526 *ncp->ncp_CDC = *nh->nh_DummyNCP.ncp_CDC;
527 ncp->ncp_UsingDefaultCfg = TRUE;
529 if(!(ps = OpenLibrary("poseidon.library", 4)))
531 return(FALSE);
534 Forbid();
535 /* Load config */
536 pic = psdGetUsbDevCfg(libname, ncp->ncp_DevIDString, NULL);
537 if(pic)
539 cdc = psdGetCfgChunk(pic, AROS_LONG2BE(ncp->ncp_CDC->cdc_ChunkID));
540 if(cdc)
542 CopyMem(((UBYTE *) cdc) + 8, ((UBYTE *) ncp->ncp_CDC) + 8, min(AROS_LONG2BE(cdc->cdc_Length), AROS_LONG2BE(ncp->ncp_CDC->cdc_Length)));
543 psdFreeVec(cdc);
544 ncp->ncp_UsingDefaultCfg = FALSE;
547 Permit();
548 CloseLibrary(ps);
549 return(FALSE);
551 /* \\\ */
553 /* /// "nOpenBindingCfgWindow()" */
554 LONG nOpenBindingCfgWindow(struct NepEthBase *nh, struct NepClassEth *ncp)
556 struct Library *ps;
557 KPRINTF(10, ("Opening GUI...\n"));
558 if(!(ps = OpenLibrary("poseidon.library", 4)))
560 return(FALSE);
562 Forbid();
563 if(!ncp->ncp_GUITask)
565 if((ncp->ncp_GUITask = psdSpawnSubTask(MOD_NAME_STRING " GUI", nGUITask, ncp)))
567 Permit();
568 CloseLibrary(ps);
569 return(TRUE);
572 Permit();
573 CloseLibrary(ps);
574 return(FALSE);
576 /* \\\ */
578 /**************************************************************************/
580 #undef ps
581 #define ps ncp->ncp_Base
583 static char *MediaTypeStrings[] = { "Auto negotiation", "10Base-T Half Duplex", "10Base-T Full Duplex", "100Base-TX Half Duplex", "100Base-TX Full Duplex", NULL };
585 /* /// "nEthTask()" */
586 AROS_UFH0(void, nEthTask)
588 AROS_USERFUNC_INIT
590 struct NepClassEth *ncp;
591 struct PsdPipe *pp;
592 ULONG sigmask;
593 ULONG sigs;
594 LONG ioerr;
595 UBYTE *pktptr;
596 ULONG pktlen;
597 UWORD cnt;
598 LONG lastioerr = 0;
599 ULONG errcount = 0;
600 #if 0
601 BOOL clearandretry;
602 #endif
604 struct IOSana2Req *ioreq;
606 if((ncp = nAllocEth()))
608 Forbid();
609 if(ncp->ncp_ReadySigTask)
611 Signal(ncp->ncp_ReadySigTask, 1L<<ncp->ncp_ReadySignal);
613 Permit();
615 /*if(nReadEEPROMMAC(ncp, ncp->ncp_ROMAddress))
617 if(!(ncp->ncp_StateFlags & DDF_CONFIGURED))
619 // don't overwrite previously configured MAC Address
620 CopyMem(ncp->ncp_ROMAddress, ncp->ncp_MacAddress, ETHER_ADDR_SIZE);
622 nWriteDMRegs(ncp, ncp->ncp_MacAddress, ETHER_ADDR_SIZE, DMREG_ETH_ID);
623 } else {*/
624 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
625 "Couldn't read EEPROM for MAC Address, using preset one.");*/
626 nReadDMRegs(ncp, ncp->ncp_ROMAddress, ETHER_ADDR_SIZE, DMREG_ETH_ID);
627 if(!(ncp->ncp_StateFlags & DDF_CONFIGURED))
629 // don't overwrite previously configured MAC Address
630 CopyMem(ncp->ncp_ROMAddress, ncp->ncp_MacAddress, ETHER_ADDR_SIZE);
631 } else {
632 nWriteDMRegs(ncp, ncp->ncp_MacAddress, ETHER_ADDR_SIZE, DMREG_ETH_ID);
635 KPRINTF(10, ("MAC Address in EEPROM %02lx:%02lx:%02lx:%02lx:%02lx:%02lx\n",
636 ncp->ncp_MacAddress[0],
637 ncp->ncp_MacAddress[1],
638 ncp->ncp_MacAddress[2],
639 ncp->ncp_MacAddress[3],
640 ncp->ncp_MacAddress[4],
641 ncp->ncp_MacAddress[5]));
643 //if((!(ncp->ncp_StateFlags & DDF_OFFLINE)))// && (ncp->ncp_StateFlags & DDF_CONFIGURED))
645 /* Record start time_of_day */
646 //GetSysTime(&ncp->ncp_DeviceStats.LastStart);
647 nSetOnline(ncp);
650 /* Main task */
651 sigmask = (1L<<ncp->ncp_Unit.unit_MsgPort.mp_SigBit)|(1L<<ncp->ncp_TaskMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C;
652 #if 0
653 clearandretry = TRUE;
654 #endif
657 // start transmitting read request if online...
658 if((ncp->ncp_StateFlags & DDF_ONLINE) && (ncp->ncp_ReadPending == NULL))
660 ncp->ncp_ReadPending = ncp->ncp_ReadBuffer[ncp->ncp_ReadBufNum];
661 psdSendPipe(ncp->ncp_EPInPipe, ncp->ncp_ReadPending, ETHER_MAX_LEN);
662 ncp->ncp_ReadBufNum ^= 1;
664 while((pp = (struct PsdPipe *) GetMsg(ncp->ncp_TaskMsgPort)))
666 KPRINTF(1, ("Pipe back %08lx\n", pp));
667 for(cnt = 0; cnt < 2; cnt++)
669 if(pp == ncp->ncp_EPOutPipe[cnt])
671 if((ioreq = ncp->ncp_WritePending[cnt]))
673 ioerr = psdGetPipeError(pp);
674 #if 0
675 if((ioerr == UHIOERR_STALL) && clearandretry)
677 clearandretry = FALSE;
678 psdPipeSetup(ncp->ncp_EP0Pipe, URTF_STANDARD|URTF_ENDPOINT,
679 USR_CLEAR_FEATURE, UFS_ENDPOINT_HALT, (ULONG) ncp->ncp_EPOutNum);
680 ioerr = psdDoPipe(ncp->ncp_EP0Pipe, NULL, 0);
681 if(ioerr)
683 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
684 "Clearing OUT-endpoint stall failed: %s (%ld)",
685 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
686 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_TX);
687 ioreq->ios2_DataLength = 0;
688 ioreq->ios2_Req.io_Error = S2ERR_TX_FAILURE;
689 ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
690 psdDelayMS(50);
692 ReplyMsg(ioreq);
693 ncp->ncp_WritePending[cnt] = NULL;
694 } else {
695 // retry
696 UBYTE *buf = ncp->ncp_WriteBuffer[cnt];
697 psdSendPipe(ncp->ncp_EPOutPipe[cnt], buf, (ULONG) (buf[0]|(buf[1]<<8)));
698 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Retrying...");
700 } else {
701 #endif
702 if(ioerr)
704 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
705 "Eth transmit failed: %s (%ld)",
706 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
708 /* Trigger any tx or generic error events */
709 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_TX);
711 /* Set error code and terminate the iorequest.
712 NOTE: Can't use RC_* or deverror() this is not
713 called from devBeginIO()!
715 ioreq->ios2_DataLength = 0;
716 ioreq->ios2_Req.io_Error = S2ERR_TX_FAILURE;
717 ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
718 psdDelayMS(50);
719 } else {
720 #if 0
721 clearandretry = TRUE;
722 #endif
724 ReplyMsg((struct Message *) ioreq);
725 ncp->ncp_WritePending[cnt] = NULL;
728 break;
731 if(pp == ncp->ncp_EPInPipe)
733 if((pktptr = ncp->ncp_ReadPending))
735 ioerr = psdGetPipeError(pp);
736 pktlen = psdGetPipeActual(pp);
737 KPRINTF(1, ("ReadBack with %ld bytes.\n", pktlen));
738 // interleave next packet reading ASAP.
739 if(ncp->ncp_StateFlags & DDF_ONLINE)
741 ncp->ncp_ReadPending = ncp->ncp_ReadBuffer[ncp->ncp_ReadBufNum];
742 psdSendPipe(ncp->ncp_EPInPipe, ncp->ncp_ReadPending, ETHER_MAX_LEN);
743 ncp->ncp_ReadBufNum ^= 1;
744 } else {
745 ncp->ncp_ReadPending = NULL;
747 if(ioerr)
749 if(lastioerr != ioerr)
751 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
752 "Eth receive failed: %s (%ld)",
753 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
754 errcount = 0;
755 } else {
756 errcount++;
757 if(errcount > 20)
759 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname,
760 "That's it, that device pissed me off long enough!");
761 Signal(ncp->ncp_Task, SIGBREAKF_CTRL_C);
764 lastioerr = ioerr;
765 psdDelayMS(50);
766 break;
767 } else {
768 lastioerr = 0;
769 KPRINTF(20, ("%ld\n", pktlen));
770 KPRINTF(1, ("Pkt %ld received\n", pktlen));
771 //DB(dumpmem(pktptr, pktlen));
772 nReadPacket(ncp, pktptr, pktlen);
778 while((ioreq = (struct IOSana2Req *) GetMsg(&ncp->ncp_Unit.unit_MsgPort)))
780 KPRINTF(5, ("command ioreq: 0x%08lx cmd: %lu len: %ld\n",
781 ioreq, ioreq->ios2_Req.io_Command, ioreq->ios2_DataLength));
782 switch(ioreq->ios2_Req.io_Command)
784 case S2_CONFIGINTERFACE:
785 nWriteDMRegs(ncp, ncp->ncp_MacAddress, ETHER_ADDR_SIZE, DMREG_ETH_ID);
786 /* Now configured */
787 ncp->ncp_StateFlags |= DDF_CONFIGURED;
788 if(!(ncp->ncp_StateFlags & DDF_ONLINE))
790 nSetOnline(ncp);
792 ReplyMsg((struct Message *) ioreq);
793 break;
795 case S2_ADDMULTICASTADDRESS:
796 case S2_DELMULTICASTADDRESS:
797 case S2_ADDMULTICASTADDRESSES:
798 case S2_DELMULTICASTADDRESSES:
800 ULONG rxcr = RX_ENABLE|RX_ALL_MULTICAST|RX_DISCARD_LONG|RX_DISCARD_CRC;
801 if(ncp->ncp_OpenFlags & SANA2OPF_PROM)
803 rxcr |= RX_PROMISCUOUS;
805 if(ncp->ncp_Multicasts.lh_Head->ln_Succ)
807 rxcr &= ~RX_ALL_MULTICAST;
808 nWriteDMRegs(ncp, ncp->ncp_MulticastArray, 8, DMREG_MCAST_ADDR);
810 nWriteDMReg(ncp, DMREG_RX_CTRL, rxcr);
812 ReplyMsg((struct Message *) ioreq);
813 break;
816 case S2_ONLINE:
817 nSetOnline(ncp);
818 ReplyMsg((struct Message *) ioreq);
819 break;
821 case S2_OFFLINE:
822 ioerr = nWriteDMReg(ncp, DMREG_RX_CTRL, 0x00);
824 nWritePhyWord(ncp, MII_BMCR, BMCR_PDOWN);
825 ReplyMsg((struct Message *) ioreq);
826 break;
828 default:
829 ioreq->ios2_Req.io_Error = IOERR_NOCMD;
830 ReplyMsg((struct Message *) ioreq);
831 break;
834 Forbid();
835 while((!ncp->ncp_WritePending[ncp->ncp_WriteBufNum]) && ncp->ncp_WriteQueue.lh_Head->ln_Succ)
837 ioreq = (struct IOSana2Req *) RemHead(&ncp->ncp_WriteQueue);
838 Permit();
839 nWritePacket(ncp, ioreq);
840 Forbid();
842 Permit();
843 sigs = Wait(sigmask);
844 } while(!(sigs & SIGBREAKF_CTRL_C));
846 Forbid();
847 /* Now remove all requests still pending *anywhere* */
848 //ncp->ncp_DenyRequests = TRUE;
849 /* Current transfers */
850 for(cnt = 0; cnt < 2; cnt++)
852 if((ioreq = ncp->ncp_WritePending[cnt]))
854 KPRINTF(1, ("Aborting pending write...\n"));
855 psdAbortPipe(ncp->ncp_EPOutPipe[cnt]);
856 psdWaitPipe(ncp->ncp_EPOutPipe[cnt]);
857 ioreq->ios2_Req.io_Error = IOERR_ABORTED;
858 ReplyMsg((struct Message *) ioreq);
859 ncp->ncp_WritePending[cnt] = NULL;
862 if(ncp->ncp_ReadPending)
864 KPRINTF(1, ("Aborting pending read...\n"));
865 psdAbortPipe(ncp->ncp_EPInPipe);
866 psdWaitPipe(ncp->ncp_EPInPipe);
867 ncp->ncp_ReadPending = NULL;
869 /* Command queue */
870 /*while(ioreq = (struct IOSana2Req *) GetMsg(&ncp->ncp_Unit.unit_MsgPort))
872 KPRINTF(1, ("Aborting pending requests...\n"));
873 ioreq->ios2_Req.io_Error = IOERR_ABORTED;
874 ReplyMsg((struct Message *) ioreq);
876 Permit();
878 nDoEvent(ncp, S2EVENT_OFFLINE);
880 KPRINTF(20, ("Going down the river!\n"));
881 nFreeEth(ncp);
884 AROS_USERFUNC_EXIT
886 /* \\\ */
888 /* /// "nAllocEth()" */
889 struct NepClassEth * nAllocEth(void)
891 struct Task *thistask;
892 struct NepClassEth *ncp;
894 thistask = FindTask(NULL);
897 ncp = thistask->tc_UserData;
898 if(!(ncp->ncp_Base = OpenLibrary("poseidon.library", 4)))
900 Alert(AG_OpenLib);
901 break;
904 ncp->ncp_Interface = psdFindInterface(ncp->ncp_Device, NULL,
905 TAG_END);
907 if(!ncp->ncp_Interface)
909 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "No interface?");
910 break;
913 ncp->ncp_EPIn = psdFindEndpoint(ncp->ncp_Interface, NULL,
914 EA_IsIn, TRUE,
915 EA_TransferType, USEAF_BULK,
916 TAG_END);
917 ncp->ncp_EPOut = psdFindEndpoint(ncp->ncp_Interface, NULL,
918 EA_IsIn, FALSE,
919 EA_TransferType, USEAF_BULK,
920 TAG_END);
921 if(!(ncp->ncp_EPIn && ncp->ncp_EPOut))
923 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "IN or OUT endpoint missing!");
924 break;
927 psdGetAttrs(PGA_ENDPOINT, ncp->ncp_EPOut,
928 EA_MaxPktSize, &ncp->ncp_EPOutMaxPktSize,
929 EA_EndpointNum, &ncp->ncp_EPOutNum,
930 TAG_END);
932 psdGetAttrs(PGA_ENDPOINT, ncp->ncp_EPIn,
933 EA_EndpointNum, &ncp->ncp_EPInNum,
934 TAG_END);
936 ncp->ncp_ReadPending = NULL;
937 ncp->ncp_WritePending[0] = NULL;
938 ncp->ncp_WritePending[1] = NULL;
939 if(!(ncp->ncp_ReadBuffer[0] = AllocVec(ETHER_MAX_LEN * 4, MEMF_PUBLIC|MEMF_CLEAR)))
941 KPRINTF(1, ("Out of memory for read buffer\n"));
942 break;
944 ncp->ncp_ReadBuffer[1] = ncp->ncp_ReadBuffer[0] + ETHER_MAX_LEN;
945 ncp->ncp_WriteBuffer[0] = ncp->ncp_ReadBuffer[1] + ETHER_MAX_LEN;
946 ncp->ncp_WriteBuffer[1] = ncp->ncp_WriteBuffer[0] + ETHER_MAX_LEN;
947 ncp->ncp_Unit.unit_MsgPort.mp_SigBit = AllocSignal(-1);
948 ncp->ncp_Unit.unit_MsgPort.mp_SigTask = thistask;
949 ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
950 ncp->ncp_Unit.unit_MsgPort.mp_Flags = PA_SIGNAL;
952 if((ncp->ncp_TaskMsgPort = CreateMsgPort()))
954 if((ncp->ncp_EP0Pipe = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, NULL)))
956 if((ncp->ncp_EPOutPipe[0] = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, ncp->ncp_EPOut)))
958 /* Turn off short packets */
959 psdSetAttrs(PGA_PIPE, ncp->ncp_EPOutPipe[0],
960 PPA_NoShortPackets, FALSE,
961 PPA_NakTimeout, TRUE,
962 PPA_NakTimeoutTime, 5000,
963 TAG_END);
964 if((ncp->ncp_EPOutPipe[1] = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, ncp->ncp_EPOut)))
966 /* Turn off short packets */
967 psdSetAttrs(PGA_PIPE, ncp->ncp_EPOutPipe[1],
968 PPA_NoShortPackets, FALSE,
969 PPA_NakTimeout, TRUE,
970 PPA_NakTimeoutTime, 5000,
971 TAG_END);
972 if((ncp->ncp_EPInPipe = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, ncp->ncp_EPIn)))
974 /* Turn off short packets */
975 psdSetAttrs(PGA_PIPE, ncp->ncp_EPInPipe,
976 PPA_NakTimeout, FALSE,
977 PPA_NakTimeoutTime, 5000,
978 PPA_AllowRuntPackets, TRUE,
979 TAG_END);
980 ncp->ncp_Task = thistask;
982 if(nInitDavicom(ncp))
984 return(ncp);
986 psdFreePipe(ncp->ncp_EPInPipe);
988 psdFreePipe(ncp->ncp_EPOutPipe[1]);
990 psdFreePipe(ncp->ncp_EPOutPipe[0]);
992 psdFreePipe(ncp->ncp_EP0Pipe);
994 DeleteMsgPort(ncp->ncp_TaskMsgPort);
996 FreeSignal((LONG) ncp->ncp_Unit.unit_MsgPort.mp_SigBit);
997 } while(FALSE);
998 if(ncp->ncp_ReadBuffer[0])
1000 FreeVec(ncp->ncp_ReadBuffer[0]);
1001 ncp->ncp_ReadBuffer[0] = NULL;
1003 CloseLibrary(ncp->ncp_Base);
1004 Forbid();
1005 ncp->ncp_Task = NULL;
1006 if(ncp->ncp_ReadySigTask)
1008 Signal(ncp->ncp_ReadySigTask, 1L<<ncp->ncp_ReadySignal);
1010 return(NULL);
1012 /* \\\ */
1014 /* /// "nFreeEth()" */
1015 void nFreeEth(struct NepClassEth *ncp)
1017 struct IOSana2Req *ioreq;
1018 Forbid();
1019 /* Disable the message port, messages may still be queued */
1020 ncp->ncp_Unit.unit_MsgPort.mp_SigTask = NULL;
1021 ncp->ncp_Unit.unit_MsgPort.mp_Flags = PA_IGNORE;
1022 FreeSignal((LONG) ncp->ncp_Unit.unit_MsgPort.mp_SigBit);
1023 // get rid of all messages that still have appeared here
1024 while((ioreq = (struct IOSana2Req *) GetMsg(&ncp->ncp_Unit.unit_MsgPort)))
1026 ioreq->ios2_Req.io_Error = IOERR_ABORTED;
1027 ReplyMsg((struct Message *) ioreq);
1029 Permit();
1031 psdFreePipe(ncp->ncp_EPInPipe);
1032 psdFreePipe(ncp->ncp_EPOutPipe[0]);
1033 psdFreePipe(ncp->ncp_EPOutPipe[1]);
1034 psdFreePipe(ncp->ncp_EP0Pipe);
1036 if(ncp->ncp_ReadBuffer[0])
1038 FreeVec(ncp->ncp_ReadBuffer[0]);
1039 ncp->ncp_ReadBuffer[0] = NULL;
1042 DeleteMsgPort(ncp->ncp_TaskMsgPort);
1043 CloseLibrary(ncp->ncp_Base);
1044 Forbid();
1045 ncp->ncp_Task = NULL;
1046 if(ncp->ncp_ReadySigTask)
1048 Signal(ncp->ncp_ReadySigTask, 1L<<ncp->ncp_ReadySignal);
1051 /* \\\ */
1053 /* /// "nReadDMReg()" */
1054 LONG nReadDMReg(struct NepClassEth *ncp, ULONG reg)
1056 UBYTE result;
1057 LONG ioerr;
1059 psdPipeSetup(ncp->ncp_EP0Pipe, URTF_IN|URTF_DEVICE|URTF_VENDOR, UDMR_GET_REGS, 0, reg);
1060 ioerr = psdDoPipe(ncp->ncp_EP0Pipe, &result, 1);
1061 if(ioerr)
1063 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1064 "Reading DM Reg %ld failed: %s (%ld)",
1065 reg,
1066 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1067 return(-1);
1069 KPRINTF(1, ("DM Reg(%ld)=%02lx (%ld)\n", reg, result, result));
1070 return(result);
1072 /* \\\ */
1074 /* /// "nReadDMRegs()" */
1075 LONG nReadDMRegs(struct NepClassEth *ncp, UBYTE *data, ULONG len, ULONG offset)
1077 LONG ioerr;
1079 psdPipeSetup(ncp->ncp_EP0Pipe, URTF_IN|URTF_DEVICE|URTF_VENDOR, UDMR_GET_REGS, 0, offset);
1080 ioerr = psdDoPipe(ncp->ncp_EP0Pipe, data, len);
1081 if(ioerr)
1083 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1084 "Reading DM Regs %ld-%ld failed: %s (%ld)",
1085 offset, offset+len-1,
1086 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1088 return(ioerr);
1090 /* \\\ */
1092 /* /// "nWriteDMReg()" */
1093 LONG nWriteDMReg(struct NepClassEth *ncp, ULONG reg, ULONG value)
1095 LONG ioerr;
1097 psdPipeSetup(ncp->ncp_EP0Pipe, URTF_OUT|URTF_DEVICE|URTF_VENDOR, UDMR_SET_REG, value, reg);
1098 ioerr = psdDoPipe(ncp->ncp_EP0Pipe, NULL, 0);
1099 if(ioerr)
1101 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1102 "Writing DM Reg %ld with 0x%02lx failed: %s (%ld)",
1103 reg, value,
1104 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1106 return(ioerr);
1108 /* \\\ */
1110 /* /// "nWriteDMRegs()" */
1111 LONG nWriteDMRegs(struct NepClassEth *ncp, UBYTE *data, ULONG len, ULONG offset)
1113 LONG ioerr;
1115 psdPipeSetup(ncp->ncp_EP0Pipe, URTF_OUT|URTF_DEVICE|URTF_VENDOR, UDMR_SET_REGS, 0, offset);
1116 ioerr = psdDoPipe(ncp->ncp_EP0Pipe, data, len);
1117 if(ioerr)
1119 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1120 "Writing DM Regs %ld-%ld failed: %s (%ld)",
1121 offset, offset+len-1,
1122 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1124 return(ioerr);
1126 /* \\\ */
1128 /* /// "nReadPhyWord()" */
1129 LONG nReadPhyWord(struct NepClassEth *ncp, ULONG phyreg)
1131 UBYTE phyword[2];
1132 UWORD timeout;
1133 LONG ioerr;
1134 LONG data;
1136 ioerr = nWriteDMReg(ncp, DMREG_PHY_ADDR, phyreg|0x40);
1137 if(ioerr)
1139 return(-1);
1141 ioerr = nWriteDMReg(ncp, DMREG_PHY_CTRL, PHY_READ|PHY_PHYSEL);
1142 if(ioerr)
1144 return(-1);
1146 psdDelayMS(1);
1148 timeout = 10;
1149 while(--timeout)
1151 data = nReadDMReg(ncp, DMREG_PHY_CTRL);
1152 if(data < 0)
1154 return(-1);
1156 if(!(data & PHY_BUSY))
1158 break;
1160 psdDelayMS(10);
1162 ioerr = nWriteDMReg(ncp, DMREG_PHY_CTRL, 0x00);
1163 if(ioerr)
1165 return(-1);
1167 if(!timeout)
1169 KPRINTF(20, ("Timeout waiting for PHY to respond (read reg %ld)!\n", phyreg));
1170 return(-1);
1172 ioerr = nReadDMRegs(ncp, phyword, 2, DMREG_PHY_DATA_LOW);
1173 if(ioerr)
1175 return(-1);
1177 return(phyword[0]|(phyword[1]<<8));
1179 /* \\\ */
1181 /* /// "nWritePhyWord()" */
1182 BOOL nWritePhyWord(struct NepClassEth *ncp, ULONG phyreg, ULONG value)
1184 UBYTE val[2];
1185 UWORD timeout;
1186 LONG ioerr;
1187 LONG data;
1189 val[0] = value;
1190 val[1] = value>>8;
1192 ioerr = nWriteDMRegs(ncp, val, 2, DMREG_PHY_DATA_LOW);
1193 if(ioerr)
1195 return(FALSE);
1197 ioerr = nWriteDMReg(ncp, DMREG_PHY_ADDR, phyreg|0x40);
1198 if(ioerr)
1200 return(FALSE);
1203 ioerr = nWriteDMReg(ncp, DMREG_PHY_CTRL, PHY_PHYSEL|PHY_WRITE);
1204 if(ioerr)
1206 return(FALSE);
1208 psdDelayMS(1);
1209 timeout = 10;
1210 while(--timeout)
1212 data = nReadDMReg(ncp, DMREG_PHY_CTRL);
1213 if(data < 0)
1215 return(FALSE);
1217 if(!(data & PHY_BUSY))
1219 break;
1221 psdDelayMS(10);
1223 ioerr = nWriteDMReg(ncp, DMREG_PHY_CTRL, 0x00);
1224 if(ioerr)
1226 return(FALSE);
1228 if(!timeout)
1230 KPRINTF(20, ("Timeout waiting for PHY to respond (write reg %ld=%04lx)!\n", phyreg, value));
1231 return(FALSE);
1233 return(TRUE);
1235 /* \\\ */
1237 /* /// "nInitDavicom()" */
1238 BOOL nInitDavicom(struct NepClassEth *ncp)
1240 LONG data;
1241 LONG ioerr;
1243 ioerr = nWriteDMReg(ncp, DMREG_NET_CTRL, 0x01);
1244 if(ioerr)
1246 return(FALSE);
1248 psdDelayMS(20);
1250 ioerr = nWriteDMReg(ncp, DMREG_GPR_CTRL, 0x01);
1251 if(ioerr)
1253 return(FALSE);
1255 ioerr = nWriteDMReg(ncp, DMREG_GPR_DATA, 0x00);
1256 if(ioerr)
1258 return(FALSE);
1261 data = nReadPhyWord(ncp, MII_BMSR);
1262 KPRINTF(10, ("Phy %04lx\n", data));
1263 if((data > 0) && (data != 0xffff) && (data & BMSR_MEDIA))
1265 return(TRUE);
1267 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Couldn't identify PHY!");
1268 return(FALSE);
1270 /* \\\ */
1272 /* /// "nSetOnline()" */
1273 void nSetOnline(struct NepClassEth *ncp)
1275 LONG data;
1276 ULONG bmcr;
1277 BOOL autoneg = FALSE;
1278 BOOL linkgood = FALSE;
1279 UWORD timeout = 60;
1280 ULONG rxcr;
1282 switch(ncp->ncp_CDC->cdc_MediaType)
1284 case MT_AUTO:
1285 KPRINTF(10, ("Autonegotiation!\n"));
1286 bmcr = BMCR_ANENABLE|BMCR_ANRESTART;
1287 autoneg = TRUE;
1288 break;
1290 case MT_10BASE_T_HALF_DUP:
1291 bmcr = 0;
1292 break;
1294 case MT_10BASE_T_FULL_DUP:
1295 bmcr = BMCR_FULLDPLX;
1296 break;
1298 case MT_100BASE_TX_HALF_DUP:
1299 bmcr = BMCR_SPEED100;
1300 break;
1302 case MT_100BASE_TX_FULL_DUP:
1303 default:
1304 bmcr = BMCR_SPEED100|BMCR_FULLDPLX;
1305 break;
1308 nWritePhyWord(ncp, MII_BMCR, bmcr);
1309 while(--timeout)
1311 psdDelayMS(50);
1312 data = nReadPhyWord(ncp, MII_BMSR);
1313 KPRINTF(10, ("Status: %04lx\n", data));
1314 if(data < 0)
1316 timeout = 0;
1317 break;
1320 linkgood = (data & BMSR_LSTATUS);
1321 if((!autoneg) && linkgood)
1323 // no need to wait for autonegotiation
1324 break;
1327 // complete?
1328 if(data & BMSR_ANEGCOMPLETE)
1330 break;
1334 if(autoneg)
1336 STRPTR negstr = NULL;
1337 if(timeout)
1339 KPRINTF(10, ("Auto neg successful!\n"));
1340 data = nReadPhyWord(ncp, MII_LPA);
1341 KPRINTF(10, ("Auto neg state %04lx\n", data));
1342 if(data < 0)
1344 timeout = 0;
1346 if(data & ADVERTISE_100FULL)
1348 // 100Base-TX Full Duplex
1349 negstr = MediaTypeStrings[MT_100BASE_TX_FULL_DUP];
1351 else if(data & ADVERTISE_100HALF)
1353 // 100Base-TX Half Duplex
1354 negstr = MediaTypeStrings[MT_100BASE_TX_HALF_DUP];
1356 else if(data & ADVERTISE_10FULL)
1358 // 10Base-T Full Duplex
1359 negstr = MediaTypeStrings[MT_10BASE_T_FULL_DUP];
1361 else if(data & ADVERTISE_10HALF)
1363 // 10Base-T Half Duplex
1364 negstr = MediaTypeStrings[MT_10BASE_T_HALF_DUP];
1365 } else {
1366 timeout = 0;
1369 if(!timeout)
1371 negstr = MediaTypeStrings[MT_100BASE_TX_FULL_DUP];
1372 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname, "Autonegotiation failed! Using %s instead.", negstr);
1373 nWritePhyWord(ncp, MII_BMCR, BMCR_SPEED100|BMCR_FULLDPLX);
1374 } else {
1375 psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Autonegotiation: Using %s.", negstr);
1378 if(!linkgood)
1380 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "No link, check the plug and cable.");
1383 rxcr = RX_ENABLE|RX_ALL_MULTICAST|RX_DISCARD_LONG|RX_DISCARD_CRC;
1384 nWriteDMRegs(ncp, ncp->ncp_MulticastArray, 8, DMREG_MCAST_ADDR);
1385 if(ncp->ncp_OpenFlags & SANA2OPF_PROM)
1387 rxcr |= RX_PROMISCUOUS;
1389 if(ncp->ncp_Multicasts.lh_Head->ln_Succ)
1391 rxcr &= ~RX_ALL_MULTICAST;
1392 nWriteDMRegs(ncp, ncp->ncp_MulticastArray, 8, DMREG_MCAST_ADDR);
1394 nWriteDMReg(ncp, DMREG_RX_CTRL, rxcr);
1396 data = nReadPhyWord(ncp, MII_TPISTATUS);
1397 nWritePhyWord(ncp, MII_TPISTATUS, data|4);
1399 /* Now online */
1400 ncp->ncp_StateFlags |= DDF_ONLINE;
1401 ncp->ncp_StateFlags &= ~DDF_OFFLINE;
1402 /* Trigger any ONLINE events */
1403 nDoEvent(ncp, S2EVENT_ONLINE);
1405 /* \\\ */
1407 /* /// "nDoEvent()" */
1408 void nDoEvent(struct NepClassEth *ncp, ULONG events)
1410 struct IOSana2Req *worknode, *nextnode;
1412 KPRINTF(1, ("DoEvent events: 0x%08lx\n", events));
1414 Forbid();
1415 /* Process pending S2_ONEVENT requests */
1416 worknode = (struct IOSana2Req *) ncp->ncp_EventList.lh_Head;
1417 while((nextnode = (struct IOSana2Req *) (((struct Node *) worknode)->ln_Succ)))
1419 if(worknode->ios2_WireError & events)
1421 Remove(&worknode->ios2_Req.io_Message.mn_Node);
1422 worknode->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
1423 KPRINTF(1, ("DoEvent: returned eventreq 0x%08lx\n", worknode));
1424 ReplyMsg(&worknode->ios2_Req.io_Message);
1426 worknode = nextnode;
1428 Permit();
1430 /* \\\ */
1432 /* /// "support routines" */
1433 static
1434 inline void *callcopy(void *routine,
1435 void *from,
1436 void *to,
1437 ULONG len)
1439 void * (*call) (APTR, APTR, ULONG) = routine;
1441 return (*call) (from, to, len);
1444 #define callfilter CallHookPkt
1445 /* \\\ */
1447 /* /// "nWritePacket()" */
1448 BOOL nWritePacket(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
1450 ULONG packettype;
1451 struct EtherPacketHeader *eph;
1452 UBYTE *copydest;
1453 UWORD writelen;
1454 struct BufMan *bufman;
1455 struct Sana2PacketTypeStats *stats;
1456 UBYTE *buf = ncp->ncp_WriteBuffer[ncp->ncp_WriteBufNum];
1458 packettype = ioreq->ios2_PacketType;
1459 // the first two bytes are the length
1460 eph = (struct EtherPacketHeader *) &buf[2];
1461 copydest = buf + 2;
1462 writelen = ioreq->ios2_DataLength;
1463 bufman = ioreq->ios2_BufferManagement;
1465 /* Not a raw packet? */
1466 if(!(ioreq->ios2_Req.io_Flags & SANA2IOF_RAW))
1468 UWORD cnt;
1469 KPRINTF(10, ("RAW WRITE!\n"));
1470 /* The ethernet header isn't included in the data */
1471 /* Build ethernet packet header */
1472 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
1474 eph->eph_Dest[cnt] = ioreq->ios2_DstAddr[cnt];
1475 eph->eph_Src[cnt] = ncp->ncp_MacAddress[cnt];
1477 eph->eph_Type = AROS_WORD2BE(packettype);
1479 /* Packet data is at txbuffer */
1480 copydest += sizeof(struct EtherPacketHeader);
1481 writelen += sizeof(struct EtherPacketHeader);
1484 //memset(buf + 2, 0x55, writelen);
1486 /* Dma not available, fallback to regular copy */
1487 if(callcopy(bufman->bm_CopyFromBuf, copydest, ioreq->ios2_Data, ioreq->ios2_DataLength) == NULL)
1489 KPRINTF(10, ("writepacket: copyfrom returned failure!\n"));
1491 /* Trigger any tx, buff or generic error events */
1492 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_TX|S2EVENT_BUFF);
1494 /* Set error code and terminate the iorequest.
1495 NOTE: Can't use RC_* or deverror() this is not
1496 called from devBeginIO()! */
1497 ioreq->ios2_DataLength = 0;
1498 ioreq->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
1499 ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
1500 return FALSE;
1503 if(!((writelen+2) & (ncp->ncp_EPOutMaxPktSize-1)))
1505 // adjust size to send one extra byte as zero packet termination doesn't seem to work with this adapter
1506 buf[writelen+2] = 0;
1507 KPRINTF(10, ("Zero Packet adjustment\n"));
1508 ++writelen;
1511 buf[0] = writelen;
1512 buf[1] = writelen>>8;
1514 writelen += 2;
1515 KPRINTF(10, ("PktOut[%ld] %ld\n", ncp->ncp_WriteBufNum, writelen));
1516 // unfortunately, it looks like the adapter does not correctly accept
1517 // zero length packets as end of transfer, so make the last packet a
1518 // one byte length one.
1519 if(!(writelen & (ncp->ncp_EPOutMaxPktSize-1)))
1521 writelen++;
1523 ncp->ncp_WritePending[ncp->ncp_WriteBufNum] = ioreq;
1524 psdSendPipe(ncp->ncp_EPOutPipe[ncp->ncp_WriteBufNum], buf, (ULONG) writelen);
1525 ncp->ncp_WriteBufNum ^= 1;
1528 if(AROS_BE2WORD(eph->eph_Type) < ETHERPKT_SIZE)
1530 KPRINTF(5, ("writepacket: %04lx%08lx > %04lx%08lx (IEEE802.3) len %lu, %lu bytes\n",
1531 *((UWORD *) eph->eph_Src), *((ULONG *) (eph->eph_Src + 2)),
1532 *((UWORD *) eph->eph_Dest), *((ULONG *) (eph->eph_Dest + 2)),
1533 AROS_BE2WORD(eph->eph_Type), writelen));
1534 } else {
1535 KPRINTF(5, ("writepacket: %04lx%08lx > %04lx%08lx type %lu, %lu bytes\n",
1536 *((UWORD *) eph->eph_Src), *((ULONG *) (eph->eph_Src + 2)),
1537 *((UWORD *) eph->eph_Dest), *((ULONG *) (eph->eph_Dest + 2)),
1538 AROS_BE2WORD(eph->eph_Type), writelen));
1540 //dumpmem(buf, (ULONG) writelen);
1543 /* Update statistics */
1544 stats = FindPacketTypeStats(ncp, packettype);
1545 if(stats)
1547 stats->PacketsSent++;
1548 stats->BytesSent += writelen;
1550 ncp->ncp_DeviceStats.PacketsSent++;
1552 return TRUE;
1554 /* \\\ */
1556 /* /// "nReadIOReq()" */
1557 UWORD nReadIOReq(struct NepClassEth *ncp, struct EtherPacketHeader *eph, UWORD datasize, struct IOSana2Req *ioreq, UWORD flags)
1559 LIBBASETYPEPTR nh = ncp->ncp_ClsBase;
1560 UBYTE *copyfrom;
1561 UWORD cnt;
1563 /* Handle RAW read */
1564 if(ioreq->ios2_Req.io_Flags & SANA2IOF_RAW)
1566 /* ShapeShifter won't work with `sizeof(struct etherpacket_hdr)'
1567 here. This is most likely because it wants the RAW ethernet
1568 packet checksum size (4) added to the packet size. */
1569 copyfrom = (UBYTE *) eph;
1570 datasize += sizeof(struct EtherPacketHeader) + 4;
1571 } else {
1572 copyfrom = (UBYTE *) (eph + 1);
1575 /* Build up the ios2 structure enough so we can call the packet filter. */
1576 ioreq->ios2_PacketType = AROS_BE2WORD(eph->eph_Type);
1577 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
1579 ioreq->ios2_SrcAddr[cnt] = eph->eph_Src[cnt];
1580 ioreq->ios2_DstAddr[cnt] = eph->eph_Dest[cnt];
1582 ioreq->ios2_DataLength = datasize;
1583 /* Call the packet filter, if available. */
1584 if((flags & PACKETFILTER) &&
1585 (((struct BufMan *) ioreq->ios2_BufferManagement)->bm_PacketFilter) &&
1586 (!callfilter(((struct BufMan *) ioreq->ios2_BufferManagement)->bm_PacketFilter,
1587 ioreq, copyfrom)))
1589 /* This packet got dropped! */
1590 KPRINTF(7, ("readioreq: packet type %lu for ioreq 0x%08lx dropped\n",
1591 AROS_BE2WORD(eph->eph_Type), ioreq));
1592 return flags;
1596 /* Ok, the packet didn't get dropped, set the BCAST and MCAST
1597 flags according to dstaddr. */
1599 /* Address == Multicast? */
1600 if(ioreq->ios2_DstAddr[0] & 1)
1602 /* Address == Broadcast? */
1603 const UBYTE bcast[ETHER_ADDR_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1604 if(memcmp(bcast, ioreq->ios2_DstAddr, ETHER_ADDR_SIZE) == 0)
1606 ioreq->ios2_Req.io_Flags |= SANA2IOF_BCAST;
1607 } else {
1608 ioreq->ios2_Req.io_Flags |= SANA2IOF_MCAST;
1612 /* Finally copy the packet data! */
1613 if(callcopy(((struct BufMan *) ioreq->ios2_BufferManagement)->bm_CopyToBuf,
1614 ioreq->ios2_Data, copyfrom, ioreq->ios2_DataLength))
1617 KPRINTF(5, ("readioreq: copytobuffed packet ior 0x%08lx, %04lx%08lx < %04lx%08lx, type %lu, %lu bytes, %s%s%s\n",
1618 ioreq,
1619 *((UWORD *) ioreq->ios2_DstAddr), *((ULONG *) (ioreq->ios2_DstAddr + 2)),
1620 *((UWORD *) ioreq->ios2_SrcAddr), *((ULONG *) (ioreq->ios2_SrcAddr + 2)),
1621 ioreq->ios2_PacketType, ioreq->ios2_DataLength,
1622 (ioreq->ios2_Req.io_Flags & SANA2IOF_RAW) ? "RAW " : "",
1623 (ioreq->ios2_Req.io_Flags & SANA2IOF_BCAST) ? "BCAST " : "",
1624 (ioreq->ios2_Req.io_Flags & SANA2IOF_MCAST) ? "MCAST " : ""));
1625 //dumpmem(copyfrom, ioreq->ios2_DataLength);
1628 /* Clear the dropped flag */
1629 flags &= ~DROPPED;
1630 } else {
1631 KPRINTF(10, ("readioreq: copyto returned failure!\n"));
1633 /* Trigger any rx, buff or generic error events */
1634 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_RX|S2EVENT_BUFF);
1636 /* Set error code.
1637 NOTE: Can't use RC_* or deverror() this is not called from devBeginIO()!
1639 ioreq->ios2_DataLength = 0;
1640 ioreq->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
1641 ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
1644 /* Pull the ioreq off the list & terminate it */
1645 Forbid();
1646 Remove((struct Node *) ioreq);
1647 Permit();
1648 ReplyMsg((struct Message *) ioreq);
1649 return flags;
1651 /* \\\ */
1653 /* /// "nReadPacket()" */
1654 BOOL nReadPacket(struct NepClassEth *ncp, UBYTE *pktptr, ULONG len)
1656 struct EtherPacketHeader *eph;
1657 struct BufMan *bufman;
1658 struct IOSana2Req *worknode, *nextnode;
1659 struct Sana2PacketTypeStats *stats;
1660 UWORD flags;
1661 UWORD datasize;
1662 UWORD status;
1663 UWORD pktlen;
1665 KPRINTF(10, ("PktIn [%ld] %ld\n", ncp->ncp_ReadBufNum, len));
1667 if(len < 4)
1669 ncp->ncp_DeviceStats.BadData++;
1670 return FALSE;
1672 status = *pktptr++;
1673 pktlen = *pktptr++;
1674 pktlen += (*pktptr++)<<8;
1675 if(status & 0xbf)
1677 KPRINTF(20, ("Error %02lx\n", status));
1678 if(status & 0x01)
1680 ncp->ncp_DeviceStats.Overruns++;
1681 } else {
1682 ncp->ncp_DeviceStats.BadData++;
1684 return FALSE;
1686 if(len != pktlen + 3)
1688 KPRINTF(20, ("Pktlen %ld != len %ld\n", pktlen + 3, len));
1689 return FALSE;
1691 pktlen -= 4;
1692 ncp->ncp_DeviceStats.PacketsReceived++;
1694 eph = (struct EtherPacketHeader *) pktptr;
1695 stats = FindPacketTypeStats(ncp, (ULONG) AROS_BE2WORD(eph->eph_Type));
1696 flags = DROPPED|PACKETFILTER;
1698 /* Calculate size of the actual data */
1699 datasize = pktlen - sizeof(struct EtherPacketHeader);
1701 /* Is the packet datasize valid? */
1702 if((pktlen >= ETHER_MIN_LEN) && (pktlen <= ETHER_MAX_LEN))
1704 /* Update the packet statistics */
1705 if(stats)
1707 stats->PacketsReceived++;
1708 stats->BytesReceived += datasize; /* NOTE: don't include headers */
1711 /* For each device user (bufman)
1712 NOTE: We absolutely *MUST* try to offer the packet to *all*
1713 different device users (SANA-II V2 spec requirement). */
1714 Forbid();
1715 bufman = (struct BufMan *) ncp->ncp_BufManList.lh_Head;
1716 while(((struct Node *) bufman)->ln_Succ)
1718 /* For each queued read request (ioreq) */
1719 worknode = (struct IOSana2Req *) bufman->bm_RXQueue.lh_Head;
1720 while((nextnode = (struct IOSana2Req *) (((struct Node *) worknode)->ln_Succ)))
1722 /* Check the packet type. Also handles 802.3 packets. */
1723 if((worknode->ios2_PacketType == AROS_BE2WORD(eph->eph_Type)) ||
1724 ((AROS_BE2WORD(eph->eph_Type) < ETHERPKT_SIZE) && (worknode->ios2_PacketType < ETHERPKT_SIZE)))
1726 flags = nReadIOReq(ncp, eph, datasize, worknode, flags);
1727 /* Break out - let other callers get the packet too */
1728 break;
1730 worknode = nextnode;
1732 bufman = (struct BufMan *) (((struct Node *) bufman)->ln_Succ);
1734 Permit();
1735 /* Now we've tried to give the packet to every CMD_READ caller.
1736 If DROPPED is set at this point no-one wanted this packet. */
1737 if(flags & DROPPED)
1739 /* So there were no outstanding CMD_READs or the packet wasn't
1740 accepted by any of them. Okay, check if we have any pending
1741 S2_READORPHAN ioreq in list and if we have return this packet
1742 with it. Note that packet filter must not be used for this
1743 time!
1745 NOTE: orphanlist is global, ie. only one caller will get the
1746 packet if multiple users have pending S2_READORPHANs.
1749 /* Process pending orphanread iorequs */
1750 Forbid();
1751 worknode = (struct IOSana2Req *) ncp->ncp_OrphanQueue.lh_Head;
1752 while((nextnode = (struct IOSana2Req *) (((struct Node *) worknode)->ln_Succ)))
1754 nReadIOReq(ncp, eph, datasize, worknode, 0);
1755 worknode = nextnode;
1757 Permit();
1758 } else {
1759 /* Packet not dropped - return ok */
1760 return TRUE;
1762 } else {
1763 KPRINTF(20, ("Pktlen %ld invalid!\n", pktlen));
1764 ncp->ncp_DeviceStats.BadData++;
1766 /* Update global dropped packet counter. */
1767 ncp->ncp_DeviceStats.UnknownTypesReceived++;
1769 /* Update dropped packet statistics. */
1770 if(stats)
1772 stats->PacketsDropped++;
1774 KPRINTF(9, ("readpacket: packet type %lu dropped\n", AROS_BE2WORD(eph->eph_Type)));
1776 /* Trigger any rx or generic error events */
1777 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_RX);
1778 return FALSE;
1780 /* \\\ */
1782 /**************************************************************************/
1784 /* /// "nGUITask()" */
1785 AROS_UFH0(void, nGUITask)
1787 AROS_USERFUNC_INIT
1789 struct Task *thistask;
1790 struct NepEthBase *nh;
1791 struct NepClassEth *ncp;
1792 struct PsdIFFContext *pic;
1794 thistask = FindTask(NULL);
1795 #undef ps
1796 #define ps ncp->ncp_PsdBase
1797 #undef IntuitionBase
1798 #define IntuitionBase ncp->ncp_IntBase
1799 #undef MUIMasterBase
1800 #define MUIMasterBase ncp->ncp_MUIBase
1802 ncp = thistask->tc_UserData;
1803 nh = ncp->ncp_ClsBase;
1805 ++nh->nh_Library.lib_OpenCnt;
1806 if(!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN)))
1808 KPRINTF(10, ("Couldn't open muimaster.library.\n"));
1809 nGUITaskCleanup(ncp);
1810 return;
1813 if(!(IntuitionBase = OpenLibrary("intuition.library", 39)))
1815 KPRINTF(10, ("Couldn't open intuition.library.\n"));
1816 nGUITaskCleanup(ncp);
1817 return;
1819 if(!(ps = OpenLibrary("poseidon.library", 4)))
1821 KPRINTF(10, ("Couldn't open poseidon.library.\n"));
1822 nGUITaskCleanup(ncp);
1823 return;
1826 ncp->ncp_App = ApplicationObject,
1827 MUIA_Application_Title , (IPTR)libname,
1828 MUIA_Application_Version , (IPTR)VERSION_STRING,
1829 MUIA_Application_Copyright , (IPTR)"©2006-2009 Harry Sintonen & Chris Hodges",
1830 MUIA_Application_Author , (IPTR)"Harry Sintonen <sintonen@iki.fi> & Chris Hodges <chrisly@platon42.de>",
1831 MUIA_Application_Description, (IPTR)"Settings for the dm9601eth.class",
1832 MUIA_Application_Base , (IPTR)"DM9601ETH",
1833 MUIA_Application_HelpFile , (IPTR)"HELP:Poseidon.guide",
1834 MUIA_Application_Menustrip , (IPTR)MenustripObject,
1835 Child, (IPTR)MenuObjectT((IPTR)"Project"),
1836 Child, (IPTR)(ncp->ncp_AboutMI = MenuitemObject,
1837 MUIA_Menuitem_Title, (IPTR)"About...",
1838 MUIA_Menuitem_Shortcut, (IPTR)"?",
1839 End),
1840 End,
1841 Child, (IPTR)MenuObjectT((IPTR)"Settings"),
1842 Child, (IPTR)(ncp->ncp_UseMI = MenuitemObject,
1843 MUIA_Menuitem_Title, (IPTR) "Save",
1844 MUIA_Menuitem_Shortcut, (IPTR) "S",
1845 End),
1846 Child, (IPTR)(ncp->ncp_SetDefaultMI = MenuitemObject,
1847 MUIA_Menuitem_Title, (IPTR) "Set as Default",
1848 MUIA_Menuitem_Shortcut, (IPTR) "D",
1849 End),
1850 Child, (IPTR)MenuitemObject,
1851 MUIA_Menuitem_Title, (IPTR)NM_BARLABEL,
1852 End,
1853 Child, (IPTR)(ncp->ncp_MUIPrefsMI = MenuitemObject,
1854 MUIA_Menuitem_Title, (IPTR) "MUI Settings",
1855 MUIA_Menuitem_Shortcut, (IPTR) "M",
1856 End),
1857 End,
1858 End,
1860 SubWindow, (IPTR)(ncp->ncp_MainWindow = WindowObject,
1861 MUIA_Window_ID , MAKE_ID('M','A','I','N'),
1862 MUIA_Window_Title, (IPTR)libname,
1863 MUIA_HelpNode, (IPTR)libname,
1865 WindowContents, (IPTR)VGroup,
1866 Child, (IPTR)ColGroup(2), GroupFrameT((IPTR)(ncp->ncp_Interface ? "Device Settings" : "Default Device Settings")),
1867 //Child, HSpace(0),
1868 Child, (IPTR)Label((IPTR) "Media Type:"),
1869 Child, (IPTR)(ncp->ncp_MediaTypeObj = CycleObject,
1870 MUIA_CycleChain, 1,
1871 MUIA_Cycle_Entries, (IPTR)MediaTypeStrings,
1872 MUIA_Cycle_Active, ncp->ncp_CDC->cdc_MediaType,
1873 End),
1874 Child, (IPTR)Label((IPTR) "Default " DEVNAME " Unit:"),
1875 Child, (IPTR)(ncp->ncp_UnitObj = StringObject,
1876 StringFrame,
1877 MUIA_CycleChain, 1,
1878 MUIA_String_AdvanceOnCR, TRUE,
1879 MUIA_String_Integer, ncp->ncp_CDC->cdc_DefaultUnit,
1880 MUIA_String_Accept, (IPTR)"0123456789",
1881 End),
1882 End,
1883 Child, (IPTR)VSpace(0),
1884 Child, (IPTR)HGroup,
1885 MUIA_Group_SameWidth, TRUE,
1886 Child, (IPTR)(ncp->ncp_UseObj = TextObject, ButtonFrame,
1887 MUIA_ShowMe, (IPTR)ncp->ncp_Interface,
1888 MUIA_Background, MUII_ButtonBack,
1889 MUIA_CycleChain, 1,
1890 MUIA_InputMode, MUIV_InputMode_RelVerify,
1891 MUIA_Text_Contents, (IPTR)"\33c Save ",
1892 End),
1893 Child, (IPTR)(ncp->ncp_SetDefaultObj = TextObject, ButtonFrame,
1894 MUIA_Background, MUII_ButtonBack,
1895 MUIA_CycleChain, 1,
1896 MUIA_InputMode, MUIV_InputMode_RelVerify,
1897 MUIA_Text_Contents, (IPTR)(ncp->ncp_Interface ? "\33c Save as Default " : "\33c Save Defaults "),
1898 End),
1899 Child, (IPTR)(ncp->ncp_CloseObj = TextObject, ButtonFrame,
1900 MUIA_Background, MUII_ButtonBack,
1901 MUIA_CycleChain, 1,
1902 MUIA_InputMode, MUIV_InputMode_RelVerify,
1903 MUIA_Text_Contents, (IPTR)("\33c Use "),
1904 End),
1905 End,
1906 End,
1907 End),
1908 End;
1910 if(!ncp->ncp_App)
1912 KPRINTF(10, ("Couldn't create application\n"));
1913 nGUITaskCleanup(ncp);
1914 return;
1917 DoMethod(ncp->ncp_MainWindow, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
1918 ncp->ncp_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
1919 DoMethod(ncp->ncp_UseObj, MUIM_Notify, MUIA_Pressed, FALSE,
1920 ncp->ncp_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG);
1921 DoMethod(ncp->ncp_SetDefaultObj, MUIM_Notify, MUIA_Pressed, FALSE,
1922 ncp->ncp_App, 2, MUIM_Application_ReturnID, ID_DEF_CONFIG);
1923 DoMethod(ncp->ncp_CloseObj, MUIM_Notify, MUIA_Pressed, FALSE,
1924 ncp->ncp_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
1926 DoMethod(ncp->ncp_AboutMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
1927 ncp->ncp_App, 2, MUIM_Application_ReturnID, ID_ABOUT);
1928 DoMethod(ncp->ncp_UseMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
1929 ncp->ncp_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG);
1930 DoMethod(ncp->ncp_SetDefaultMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
1931 ncp->ncp_App, 2, MUIM_Application_ReturnID, ID_DEF_CONFIG);
1932 DoMethod(ncp->ncp_MUIPrefsMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
1933 ncp->ncp_App, 2, MUIM_Application_OpenConfigWindow, 0);
1935 IPTR isopen = 0;
1936 IPTR iconify = 0;
1937 ULONG sigs;
1938 ULONG sigmask;
1939 LONG retid;
1941 get(ncp->ncp_App, MUIA_Application_Iconified, &iconify);
1942 set(ncp->ncp_MainWindow, MUIA_Window_Open, TRUE);
1943 get(ncp->ncp_MainWindow, MUIA_Window_Open, &isopen);
1944 if(!(isopen || iconify))
1946 nGUITaskCleanup(ncp);
1947 return;
1949 sigmask = 0;
1952 retid = DoMethod(ncp->ncp_App, MUIM_Application_NewInput, &sigs);
1953 switch(retid)
1955 case ID_DEF_CONFIG:
1956 case ID_STORE_CONFIG:
1957 case MUIV_Application_ReturnID_Quit:
1959 get(ncp->ncp_UnitObj, MUIA_String_Integer, &ncp->ncp_CDC->cdc_DefaultUnit);
1960 get(ncp->ncp_MediaTypeObj, MUIA_Cycle_Active, &ncp->ncp_CDC->cdc_MediaType);
1962 if(retid == ID_DEF_CONFIG)
1964 pic = psdGetClsCfg(libname);
1965 if(!pic)
1967 psdSetClsCfg(libname, NULL);
1968 pic = psdGetClsCfg(libname);
1970 if(pic)
1972 psdAddCfgEntry(pic, ncp->ncp_CDC);
1973 psdSaveCfgToDisk(NULL, FALSE);
1976 if(ncp->ncp_Interface)
1978 pic = psdGetUsbDevCfg(libname, ncp->ncp_DevIDString, NULL);
1979 if(!pic)
1981 psdSetUsbDevCfg(libname, ncp->ncp_DevIDString, NULL, NULL);
1982 pic = psdGetUsbDevCfg(libname, ncp->ncp_DevIDString, NULL);
1984 if(pic)
1986 if(psdAddCfgEntry(pic, ncp->ncp_CDC))
1988 if(retid != MUIV_Application_ReturnID_Quit)
1990 psdSaveCfgToDisk(NULL, FALSE);
1992 retid = MUIV_Application_ReturnID_Quit;
1995 } else {
1996 retid = MUIV_Application_ReturnID_Quit;
1998 break;
2001 case ID_ABOUT:
2002 MUI_RequestA(ncp->ncp_App, ncp->ncp_MainWindow, 0, NULL, "Phat!", VERSION_STRING, NULL);
2003 break;
2005 if(retid == MUIV_Application_ReturnID_Quit)
2007 break;
2009 if(sigs)
2011 sigs = Wait(sigs|sigmask|SIGBREAKF_CTRL_C);
2012 if(sigs & SIGBREAKF_CTRL_C)
2014 break;
2017 } while(TRUE);
2018 set(ncp->ncp_MainWindow, MUIA_Window_Open, FALSE);
2020 nGUITaskCleanup(ncp);
2022 AROS_USERFUNC_EXIT
2024 /* \\\ */
2026 /* /// "nGUITaskCleanup()" */
2027 void nGUITaskCleanup(struct NepClassEth *ncp)
2029 if(ncp->ncp_App)
2031 MUI_DisposeObject(ncp->ncp_App);
2032 ncp->ncp_App = NULL;
2034 if(MUIMasterBase)
2036 CloseLibrary(MUIMasterBase);
2037 MUIMasterBase = NULL;
2039 if(IntuitionBase)
2041 CloseLibrary(IntuitionBase);
2042 IntuitionBase = NULL;
2044 if(ps)
2046 CloseLibrary(ps);
2047 ps = NULL;
2049 Forbid();
2050 ncp->ncp_GUIBinding = NULL;
2051 ncp->ncp_GUITask = NULL;
2052 if(ncp->ncp_ReadySigTask)
2054 Signal(ncp->ncp_ReadySigTask, 1L<<ncp->ncp_ReadySignal);
2056 --ncp->ncp_ClsBase->nh_Library.lib_OpenCnt;
2058 /* \\\ */