Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / usb / classes / dfu / dfu.class.c
blob11d6c0d3a4e6b3ae88c9d17499025ba61582aa29
1 /*
2 *----------------------------------------------------------------------------
3 * dfu class for poseidon
4 *----------------------------------------------------------------------------
5 * By Chris Hodges <chrisly@platon42.de>
6 */
8 #include "debug.h"
10 #include "dfu.class.h"
12 /* /// "Lib Stuff" */
13 static const STRPTR libname = MOD_NAME_STRING;
15 static int libInit(LIBBASETYPEPTR nh)
17 struct NepDFUBase *ret = NULL;
19 KPRINTF(10, ("libInit nh: 0x%08lx SysBase: 0x%08lx\n", nh, SysBase));
21 nh->nh_UtilityBase = OpenLibrary("utility.library", 39);
23 #define UtilityBase nh->nh_UtilityBase
25 if(UtilityBase)
27 ret = nh;
28 } else {
29 KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n"));
32 KPRINTF(10, ("libInit: Ok\n"));
33 return(ret ? TRUE : FALSE);
36 static int libExpunge(LIBBASETYPEPTR nh)
38 KPRINTF(10, ("libExpunge nh: 0x%08lx\n", nh));
39 CloseLibrary((struct Library *) UtilityBase);
40 return(TRUE);
43 ADD2INITLIB(libInit, 0)
44 ADD2EXPUNGELIB(libExpunge, 0)
45 /* \\\ */
48 * ***********************************************************************
49 * * Library functions *
50 * ***********************************************************************
53 /* /// "usbAttemptInterfaceBinding()" */
54 struct NepClassDFU * usbAttemptInterfaceBinding(struct NepDFUBase *nh, struct PsdInterface *pif)
56 struct Library *ps;
57 IPTR ifclass;
58 IPTR subclass;
59 IPTR proto;
61 KPRINTF(1, ("nepDFUAttemptInterfaceBinding(%08lx)\n", pif));
62 if((ps = OpenLibrary("poseidon.library", 4)))
64 psdGetAttrs(PGA_INTERFACE, pif,
65 IFA_Class, &ifclass,
66 IFA_SubClass, &subclass,
67 IFA_Protocol, &proto,
68 TAG_DONE);
69 CloseLibrary(ps);
71 if((ifclass == FWUPGRADE_CLASSCODE) && (subclass == FWUPGRADE_STD_SUBCLASS))
73 return(usbForceInterfaceBinding(nh, pif));
76 return(NULL);
78 /* \\\ */
80 /* /// "usbForceInterfaceBinding()" */
81 struct NepClassDFU * usbForceInterfaceBinding(struct NepDFUBase *nh, struct PsdInterface *pif)
83 struct Library *ps;
84 struct NepClassDFU *nch;
85 struct PsdConfig *pc;
86 struct PsdDevice *pd;
87 struct PsdDevice *hubpd;
88 struct PsdDescriptor *pdd;
89 IPTR hubport;
90 STRPTR devname;
91 STRPTR ifidstr;
92 STRPTR devidstr;
93 IPTR ifnum;
94 IPTR devclass;
95 IPTR prodid;
96 IPTR ifproto;
97 struct UsbDFUDesc *dfudesc = NULL;
99 KPRINTF(1, ("nepDFUForceInterfaceBinding(%08lx)\n", pif));
100 if((ps = OpenLibrary("poseidon.library", 4)))
102 psdGetAttrs(PGA_INTERFACE, pif,
103 IFA_Config, &pc,
104 IFA_IDString, &ifidstr,
105 IFA_InterfaceNum, &ifnum,
106 IFA_Protocol, &ifproto,
107 TAG_DONE);
108 psdGetAttrs(PGA_CONFIG, pc,
109 CA_Device, &pd,
110 TAG_END);
111 psdGetAttrs(PGA_DEVICE, pd,
112 DA_ProductName, &devname,
113 DA_Class, &devclass,
114 DA_ProductID, &prodid,
115 DA_IDString, &devidstr,
116 DA_HubDevice, &hubpd,
117 DA_AtHubPortNumber, &hubport,
118 TAG_END);
119 pdd = psdFindDescriptor(pd, NULL,
120 DDA_DescriptorType, UDT_DFU,
121 DDA_Interface, pif,
122 TAG_END);
123 if(pdd)
125 if((nch = psdAllocVec(sizeof(struct NepClassDFU))))
127 nch->nch_ClsBase = nh;
128 nch->nch_Device = pd;
129 nch->nch_Hub = hubpd;
130 nch->nch_HubPort = hubport;
131 nch->nch_Interface = pif;
132 nch->nch_DevIDString = devidstr;
133 nch->nch_IfIDString = ifidstr;
134 nch->nch_IfNum = ifnum;
136 psdGetAttrs(PGA_DESCRIPTOR, pdd,
137 DDA_DescriptorData, &dfudesc,
138 TAG_END);
139 nch->nch_WillDetach = dfudesc->bmAttributes & UDDAF_WILL_DETACH;
140 nch->nch_CanUpgrade = dfudesc->bmAttributes & UDDAF_DOWNLOADABLE;
141 nch->nch_CanRetrieve = dfudesc->bmAttributes & UDDAF_UPLOADABLE;
142 nch->nch_NoManifestReset = dfudesc->bmAttributes & UDDAF_NO_MANIFEST_RST;
144 nch->nch_DetachTimeOut = dfudesc->wDetachTimeOut0|(dfudesc->wDetachTimeOut1<<8);
145 nch->nch_TransferSize = dfudesc->wTransferSize0|(dfudesc->wTransferSize1<<8);
147 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
148 "Firmware %s available for '%s' (through config GUI)!",
149 ((nch->nch_CanUpgrade && nch->nch_CanRetrieve) ? "Download/Upgrade" :
150 (nch->nch_CanRetrieve ? "Download" :
151 (nch->nch_CanUpgrade ? "Upgrade" : "Cage"))),
152 devname);
153 // auto open window
154 if((prodid == 0xffff) || (devclass == FWUPGRADE_CLASSCODE) || (ifproto == FWUPGRADE_PROTO_DFU))
156 nOpenBindingCfgWindow(nh, nch);
158 CloseLibrary(ps);
159 return(nch);
161 } else {
162 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname,
163 "Could not find DFU functional descriptor for '%s'!",
164 devname);
166 CloseLibrary(ps);
168 return(NULL);
171 /* \\\ */
173 /* /// "usbReleaseInterfaceBinding()" */
174 void usbReleaseInterfaceBinding(struct NepDFUBase *nh, struct NepClassDFU *nch)
176 struct Library *ps;
177 struct PsdConfig *pc;
178 struct PsdDevice *pd;
179 STRPTR devname;
181 KPRINTF(1, ("nepDFUReleaseInterfaceBinding(%08lx)\n", nch));
182 if((ps = OpenLibrary("poseidon.library", 4)))
184 Forbid();
185 nch->nch_ReadySignal = SIGB_SINGLE;
186 nch->nch_ReadySigTask = FindTask(NULL);
187 if(nch->nch_GUITask)
189 Signal(nch->nch_GUITask, SIGBREAKF_CTRL_C);
191 Permit();
192 while(nch->nch_GUITask)
194 Wait(1L<<nch->nch_ReadySignal);
197 //FreeSignal(nch->nch_ReadySignal);
198 psdGetAttrs(PGA_INTERFACE, nch->nch_Interface, IFA_Config, &pc, TAG_END);
199 psdGetAttrs(PGA_CONFIG, pc, CA_Device, &pd, TAG_END);
200 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
201 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
202 "Lost firm grip on '%s'!",
203 devname);
204 psdFreeVec(nch);
205 CloseLibrary(ps);
208 /* \\\ */
210 /* /// "usbGetAttrsA()" */
211 AROS_LH3(LONG, usbGetAttrsA,
212 AROS_LHA(ULONG, type, D0),
213 AROS_LHA(APTR, usbstruct, A0),
214 AROS_LHA(struct TagItem *, tags, A1),
215 LIBBASETYPEPTR, nh, 5, nep)
217 AROS_LIBFUNC_INIT
219 struct TagItem *ti;
220 LONG count = 0;
222 KPRINTF(1, ("nepDFUGetAttrsA(%ld, %08lx, %08lx)\n", type, usbstruct, tags));
223 switch(type)
225 case UGA_CLASS:
226 if((ti = FindTagItem(UCCA_Priority, tags)))
228 *((SIPTR *) ti->ti_Data) = -100;
229 count++;
231 if((ti = FindTagItem(UCCA_Description, tags)))
233 *((STRPTR *) ti->ti_Data) = "Firmware Upgrading/Downloading";
234 count++;
236 if((ti = FindTagItem(UCCA_HasClassCfgGUI, tags)))
238 *((IPTR *) ti->ti_Data) = FALSE;
239 count++;
241 if((ti = FindTagItem(UCCA_HasBindingCfgGUI, tags)))
243 *((IPTR *) ti->ti_Data) = TRUE;
244 count++;
246 if((ti = FindTagItem(UCCA_AfterDOSRestart, tags)))
248 *((IPTR *) ti->ti_Data) = FALSE;
249 count++;
251 if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags)))
253 *((IPTR *) ti->ti_Data) = TRUE;
254 count++;
256 break;
258 case UGA_BINDING:
259 if((ti = FindTagItem(UCBA_UsingDefaultCfg, tags)))
261 *((IPTR *) ti->ti_Data) = TRUE;
262 count++;
264 break;
266 return(count);
267 AROS_LIBFUNC_EXIT
269 /* \\\ */
271 /* /// "usbSetAttrsA()" */
272 AROS_LH3(LONG, usbSetAttrsA,
273 AROS_LHA(ULONG, type, D0),
274 AROS_LHA(APTR, usbstruct, A0),
275 AROS_LHA(struct TagItem *, tags, A1),
276 LIBBASETYPEPTR, nh, 6, nep)
278 AROS_LIBFUNC_INIT
279 return(0);
280 AROS_LIBFUNC_EXIT
282 /* \\\ */
284 /* /// "usbDoMethodA()" */
285 AROS_LH2(IPTR, usbDoMethodA,
286 AROS_LHA(ULONG, methodid, D0),
287 AROS_LHA(IPTR *, methoddata, A1),
288 LIBBASETYPEPTR, nh, 7, nep)
290 AROS_LIBFUNC_INIT
292 KPRINTF(10, ("Do Method %ld\n", methodid));
293 switch(methodid)
295 case UCM_AttemptInterfaceBinding:
296 return((IPTR) usbAttemptInterfaceBinding(nh, (struct PsdInterface *) methoddata[0]));
298 case UCM_ForceInterfaceBinding:
299 return((IPTR) usbForceInterfaceBinding(nh, (struct PsdInterface *) methoddata[0]));
301 case UCM_ReleaseInterfaceBinding:
302 usbReleaseInterfaceBinding(nh, (struct NepClassDFU *) methoddata[0]);
303 return(TRUE);
305 case UCM_OpenCfgWindow:
306 return(FALSE);
308 case UCM_OpenBindingCfgWindow:
309 return(nOpenBindingCfgWindow(nh, (struct NepClassDFU *) methoddata[0]));
311 case UCM_ConfigChangedEvent:
312 return(FALSE);
314 default:
315 break;
317 return(0);
318 AROS_LIBFUNC_EXIT
320 /* \\\ */
322 /* /// "nOpenBindingCfgWindow()" */
323 LONG nOpenBindingCfgWindow(struct NepDFUBase *nh, struct NepClassDFU *nch)
325 struct Library *ps;
326 KPRINTF(10, ("Opening GUI...\n"));
327 if(!(ps = OpenLibrary("poseidon.library", 4)))
329 return(FALSE);
331 Forbid();
332 if(!nch->nch_GUITask)
334 if((nch->nch_GUITask = psdSpawnSubTask(MOD_NAME_STRING " GUI", nGUITask, nch)))
336 Permit();
337 CloseLibrary(ps);
338 return(TRUE);
341 Permit();
342 CloseLibrary(ps);
343 return(FALSE);
345 /* \\\ */
347 /**************************************************************************/
349 #undef ps
351 const STRPTR DFUErrors[] =
353 "No error condition is present.",
354 "File is not targeted for use by this device.",
355 "File is for this device but fails some vendor-specific verification test.",
356 "Device is unable to write memory.",
357 "Memory erase function failed.",
358 "Memory erase check failed.",
359 "Program memory function failed.",
360 "Programmed memory failed verification.",
361 "Cannot program memory due to received address that is out of range.",
362 "Received DFU_DNLOAD with wLength = 0, but device does not think it has all of the data yet.",
363 "Device's firmware is corrupt. It cannot return to run-time (non-DFU) operations.",
364 "iString indicates a vendor-specific error.",
365 "Device detected unexpected USB reset signaling.",
366 "Device detected unexpected power on reset.",
367 "Something went wrong, but the device does not know what it was.",
368 "Device stalled an unexpected request."
371 const STRPTR DFUStates[] =
373 "Device is running its normal application.",
374 "Transition from normal to DFU mode.",
375 "Device is operating in the DFU mode.",
376 "Device has received a block, waiting for GetStatus.",
377 "Device is programming a block into its memories.",
378 "Device is processing a download operation.",
379 "Device has received the final block of firmware.",
380 "Device is in the Manifestation phase.",
381 "Device is waiting for reset.",
382 "Device is processing an upload operation.",
383 "An error has occurred."
386 /* /// "nGUITask()" */
387 AROS_UFH0(void, nGUITask)
389 AROS_USERFUNC_INIT
391 struct Task *thistask;
392 struct NepDFUBase *nh;
393 struct NepClassDFU *nch;
394 BOOL initokay = FALSE;
395 STRPTR infomsg;
397 thistask = FindTask(NULL);
398 #undef ps
399 #define ps nch->nch_PsdBase
400 #undef IntuitionBase
401 #define IntuitionBase nch->nch_IntBase
402 #undef MUIMasterBase
403 #define MUIMasterBase nch->nch_MUIBase
404 #undef DOSBase
405 #define DOSBase nch->nch_DOSBase
407 nch = thistask->tc_UserData;
408 nh = nch->nch_ClsBase;
410 ++nh->nh_Library.lib_OpenCnt;
413 if(!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN)))
415 KPRINTF(10, ("Couldn't open muimaster.library.\n"));
416 break;
419 if(!(IntuitionBase = OpenLibrary("intuition.library", 39)))
421 KPRINTF(10, ("Couldn't open intuition.library.\n"));
422 break;
424 if(!(DOSBase = OpenLibrary("dos.library", 39)))
426 KPRINTF(10, ("Couldn't open dos.library.\n"));
427 break;
429 if(!(ps = OpenLibrary("poseidon.library", 4)))
431 KPRINTF(10, ("Couldn't open poseidon.library.\n"));
432 break;
434 if(!(nch->nch_TaskMsgPort = CreateMsgPort()))
436 break;
438 if(!(nch->nch_EP0Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, NULL)))
440 break;
442 psdSetAttrs(PGA_PIPE, nch->nch_EP0Pipe,
443 PPA_NakTimeout, TRUE,
444 PPA_NakTimeoutTime, 15000,
445 TAG_END);
447 if(!(nch->nch_Buffer = psdAllocVec(nch->nch_TransferSize)))
449 break;
451 initokay = TRUE;
452 } while(FALSE);
453 if(!initokay)
455 nGUITaskCleanup(nch);
456 return;
459 /* obtain status */
460 infomsg = nGetStatus(nch);
462 nch->nch_App = ApplicationObject,
463 MUIA_Application_Title , (IPTR)libname,
464 MUIA_Application_Version , (IPTR)VERSION_STRING,
465 MUIA_Application_Copyright , (IPTR)"©2005-2009 Chris Hodges",
466 MUIA_Application_Author , (IPTR)"Chris Hodges <chrisly@platon42.de>",
467 MUIA_Application_Description, (IPTR)"Settings for the dfu.class",
468 MUIA_Application_Base , (IPTR)"DFU",
469 MUIA_Application_HelpFile , (IPTR)"HELP:Poseidon.guide",
470 MUIA_Application_Menustrip , (IPTR)MenustripObject,
471 Child, (IPTR)MenuObjectT((IPTR)"Project"),
472 Child, (IPTR)(nch->nch_AboutMI = MenuitemObject,
473 MUIA_Menuitem_Title, (IPTR)"About...",
474 MUIA_Menuitem_Shortcut, (IPTR)"?",
475 End),
476 End,
477 Child, (IPTR)MenuObjectT((IPTR)"Settings"),
478 Child, (IPTR)(nch->nch_MUIPrefsMI = MenuitemObject,
479 MUIA_Menuitem_Title, (IPTR)"MUI Settings",
480 MUIA_Menuitem_Shortcut, (IPTR)"M",
481 End),
482 End,
483 End,
485 SubWindow, (IPTR)(nch->nch_MainWindow = WindowObject,
486 MUIA_Window_ID , MAKE_ID('M','A','I','N'),
487 MUIA_Window_Title, (IPTR)libname,
488 MUIA_HelpNode, (IPTR)libname,
490 WindowContents, (IPTR)VGroup,
491 Child, (IPTR)VGroup, GroupFrameT((IPTR)"Firmware Upgrade/Download"),
492 Child, (IPTR)HGroup,
493 MUIA_ShowMe, nch->nch_DFUStatus.bState >= STATE_DFU_IDLE,
494 Child, (IPTR)Label((IPTR) "Firmware file:"),
495 Child, (IPTR)PopaslObject,
496 MUIA_Popstring_String, (IPTR)(nch->nch_FWFileObj = StringObject,
497 StringFrame,
498 MUIA_CycleChain, 1,
499 MUIA_String_AdvanceOnCR, TRUE,
500 MUIA_String_MaxLen, 256,
501 End),
502 MUIA_Popstring_Button, (IPTR)PopButton(MUII_PopFile),
503 ASLFR_TitleText, (IPTR)"Select a firmware binary file...",
504 ASLFR_InitialPattern, (IPTR)"#?.dfu",
505 ASLFR_DoPatterns, TRUE,
506 End,
507 End,
508 Child, (IPTR)(nch->nch_GaugeObj = GaugeObject,
509 MUIA_Frame, MUIV_Frame_ReadList,
510 MUIA_Gauge_Horiz, TRUE,
511 MUIA_Gauge_InfoText, (IPTR)infomsg,
512 MUIA_Gauge_Current, 0,
513 MUIA_Gauge_Max, 100,
514 End),
515 Child, (IPTR)HGroup,
516 MUIA_Group_SameWidth, TRUE,
517 Child, (IPTR)(nch->nch_DetachObj = TextObject, ButtonFrame,
518 MUIA_ShowMe, !nch->nch_DFUStatus.bState,
519 MUIA_Background, MUII_ButtonBack,
520 MUIA_CycleChain, 1,
521 MUIA_InputMode, MUIV_InputMode_RelVerify,
522 MUIA_Text_Contents, (IPTR)"\33c Enter DFU Mode ",
523 End),
524 Child, (IPTR)(nch->nch_DownloadObj = TextObject, ButtonFrame,
525 MUIA_ShowMe, nch->nch_DFUStatus.bState >= STATE_DFU_IDLE,
526 MUIA_Disabled, !nch->nch_CanRetrieve,
527 MUIA_Background, MUII_ButtonBack,
528 MUIA_CycleChain, 1,
529 MUIA_InputMode, MUIV_InputMode_RelVerify,
530 MUIA_Text_Contents, (IPTR)"\33c Download (Read) ",
531 End),
532 Child, (IPTR)(nch->nch_UploadObj = TextObject, ButtonFrame,
533 MUIA_ShowMe, nch->nch_DFUStatus.bState >= STATE_DFU_IDLE,
534 MUIA_Disabled, !nch->nch_CanUpgrade,
535 MUIA_Background, MUII_ButtonBack,
536 MUIA_CycleChain, 1,
537 MUIA_InputMode, MUIV_InputMode_RelVerify,
538 MUIA_Text_Contents, (IPTR)"\33c Upgrade (Write) ",
539 End),
540 End,
541 End,
542 Child, (IPTR)VSpace(0),
543 Child, (IPTR)(nch->nch_CloseObj = TextObject, ButtonFrame,
544 MUIA_Background, MUII_ButtonBack,
545 MUIA_CycleChain, 1,
546 MUIA_InputMode, MUIV_InputMode_RelVerify,
547 MUIA_Text_Contents, (IPTR)"\33c Close ",
548 End),
549 End,
550 End),
551 End;
553 if(!nch->nch_App)
555 KPRINTF(10, ("Couldn't create application\n"));
556 nGUITaskCleanup(nch);
557 return;
560 DoMethod(nch->nch_MainWindow, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
561 nch->nch_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
562 DoMethod(nch->nch_DetachObj, MUIM_Notify, MUIA_Pressed, FALSE,
563 nch->nch_App, 2, MUIM_Application_ReturnID, ID_DETACH);
564 DoMethod(nch->nch_DownloadObj, MUIM_Notify, MUIA_Pressed, FALSE,
565 nch->nch_App, 2, MUIM_Application_ReturnID, ID_DOWNLOAD);
566 DoMethod(nch->nch_UploadObj, MUIM_Notify, MUIA_Pressed, FALSE,
567 nch->nch_App, 2, MUIM_Application_ReturnID, ID_UPLOAD);
568 DoMethod(nch->nch_CloseObj, MUIM_Notify, MUIA_Pressed, FALSE,
569 nch->nch_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
571 DoMethod(nch->nch_AboutMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
572 nch->nch_App, 2, MUIM_Application_ReturnID, ID_ABOUT);
573 DoMethod(nch->nch_MUIPrefsMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
574 nch->nch_App, 2, MUIM_Application_OpenConfigWindow, 0);
576 IPTR isopen = 0;
577 IPTR iconify = 0;
578 ULONG sigs;
579 ULONG sigmask;
580 LONG retid;
582 get(nch->nch_App, MUIA_Application_Iconified, &iconify);
583 set(nch->nch_MainWindow, MUIA_Window_Open, TRUE);
584 get(nch->nch_MainWindow, MUIA_Window_Open, &isopen);
585 if(!(isopen || iconify))
587 nGUITaskCleanup(nch);
588 return;
590 sigmask = 0;
593 retid = DoMethod(nch->nch_App, MUIM_Application_NewInput, &sigs);
594 switch(retid)
596 case ID_DOWNLOAD:
597 nFWDownload(nch);
598 break;
600 case ID_UPLOAD:
601 nFWUpload(nch);
602 break;
604 case ID_DETACH:
605 nDetach(nch);
606 break;
608 case ID_ABOUT:
609 MUI_RequestA(nch->nch_App, nch->nch_MainWindow, 0, NULL, "Blimey!", VERSION_STRING, NULL);
610 break;
612 if(retid == MUIV_Application_ReturnID_Quit)
614 break;
616 if(sigs)
618 sigs = Wait(sigs | sigmask | SIGBREAKF_CTRL_C);
619 if(sigs & SIGBREAKF_CTRL_C)
621 break;
624 } while(TRUE);
625 set(nch->nch_MainWindow, MUIA_Window_Open, FALSE);
627 nGUITaskCleanup(nch);
629 AROS_USERFUNC_EXIT
631 /* \\\ */
633 /* /// "nDetach()" */
634 void nDetach(struct NepClassDFU *nch)
636 ULONG delay = (nch->nch_DetachTimeOut < 2000) ? nch->nch_DetachTimeOut : 2000;
637 LONG ioerr;
639 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_INTERFACE,
640 UDFUR_DETACH, delay, nch->nch_IfNum);
641 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
642 if(ioerr)
644 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
645 "Detaching failed: %s (%ld)",
646 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
647 return;
649 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, nGetStatus(nch));
650 if(!nch->nch_WillDetach)
652 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
653 "Sending USB Reset to device...");
655 psdDelayMS(delay>>1);
656 psdDoHubMethod(nch->nch_Device, UCM_HubPowerCyclePort, nch->nch_Hub, nch->nch_HubPort);
657 } else {
658 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
659 "Waiting for device to detach automatically...");
662 /* \\\ */
664 /* /// "nFWDownload()" */
665 void nFWDownload(struct NepClassDFU *nch)
667 UWORD blocknum = 0;
668 CONST_STRPTR file = "";
669 LONG ioerr;
670 ULONG len;
672 get(nch->nch_FWFileObj, MUIA_String_Contents, &file);
673 if(!*file)
675 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, "Give filename for writing!");
676 return;
678 if((nch->nch_InOutFile = Open(file, MODE_NEWFILE)))
680 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, "Starting download...");
683 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_INTERFACE,
684 UDFUR_UPLOAD, (ULONG) blocknum, nch->nch_IfNum);
685 ioerr = psdDoPipe(nch->nch_EP0Pipe, nch->nch_Buffer, nch->nch_TransferSize);
686 len = psdGetPipeActual(nch->nch_EP0Pipe);
687 if((!ioerr) || (ioerr == UHIOERR_RUNTPACKET))
689 /*psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
690 "%ld bytes", len);*/
691 Write(nch->nch_InOutFile, nch->nch_Buffer, len);
692 } else {
693 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
694 "Download at block %ld failed: %s (%ld), %ld read",
695 blocknum,
696 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr, len);
698 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, nGetStatus(nch));
699 break;
701 blocknum++;
702 set(nch->nch_GaugeObj, MUIA_Gauge_Current, blocknum % 100);
703 } while(!ioerr);
704 set(nch->nch_GaugeObj, MUIA_Gauge_Current, 0);
705 if(ioerr == UHIOERR_RUNTPACKET)
707 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, "Finished downloading.");
709 Close(nch->nch_InOutFile);
710 } else {
711 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, "Error opening file!");
714 /* \\\ */
716 /* /// "nFWUpload()" */
717 void nFWUpload(struct NepClassDFU *nch)
719 UWORD blocknum = 0;
720 CONST_STRPTR file = "";
721 LONG ioerr;
722 LONG len;
723 LONG totallen;
724 LONG pos = 0;
725 LONG choice;
726 STRPTR infomsg;
727 ULONG delay;
729 get(nch->nch_FWFileObj, MUIA_String_Contents, &file);
730 if(!*file)
732 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, "Give firmware file!");
733 return;
735 if((nch->nch_InOutFile = Open(file, MODE_OLDFILE)))
737 Seek(nch->nch_InOutFile, 0, OFFSET_END);
738 totallen = Seek(nch->nch_InOutFile, 0, OFFSET_BEGINNING);
739 choice = MUI_Request(nch->nch_App, nch->nch_MainWindow, 0, NULL, "Continue|Cancel",
740 "Are you sure you want to reflash the firmware of this device?\n\n"
741 "\33bDO NOT REMOVE THE DEVICE OR REBOOT DURING THIS PROCESS!\33n\n"
742 "This might render the device useless!\n", NULL);
743 if(choice == 1)
745 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, "Starting upload...");
746 set(nch->nch_GaugeObj, MUIA_Gauge_Max, totallen);
749 KPRINTF(1, ("Reading %ld/%ld: %ld...\n", pos, totallen, nch->nch_TransferSize));
750 len = Read(nch->nch_InOutFile, nch->nch_Buffer, nch->nch_TransferSize);
751 if(len < 0)
753 len = 0;
755 pos += len;
756 set(nch->nch_GaugeObj, MUIA_Gauge_Current, pos);
757 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_INTERFACE,
758 UDFUR_DNLOAD, (ULONG) blocknum, nch->nch_IfNum);
759 KPRINTF(1, ("Sending %ld\n", len));
760 ioerr = psdDoPipe(nch->nch_EP0Pipe, nch->nch_Buffer, len);
761 KPRINTF(1, ("IOErr = %ld\n", ioerr));
762 if(ioerr)
764 infomsg = nGetStatus(nch);
765 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, infomsg);
766 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
767 "Upload at block %ld failed: %s (%ld), %s",
768 blocknum,
769 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr, infomsg);
770 break;
771 } else {
772 infomsg = nGetStatus(nch);
773 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, infomsg);
774 if(nch->nch_DFUStatus.bState == STATE_DFU_ERROR)
776 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
777 "Upload at block %ld failed: %s",
778 blocknum,
779 infomsg);
780 break;
781 } else {
782 delay = nch->nch_DFUStatus.bwPollTimeout0|(nch->nch_DFUStatus.bwPollTimeout1<<8)|(nch->nch_DFUStatus.bwPollTimeout2<<16);
783 KPRINTF(1, ("Delaying %ldms\n", delay));
784 //psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Delaying %ldms", delay);
785 psdDelayMS(delay);
788 blocknum++;
789 } while((!ioerr) && len);
790 KPRINTF(1, ("Done\n"));
791 set(nch->nch_GaugeObj, MUIA_Gauge_Current, 0);
792 set(nch->nch_GaugeObj, MUIA_Gauge_Max, 100);
794 if(!len)
796 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, "Finished uploading, manifesting.");
797 if(nch->nch_NoManifestReset)
799 psdDelayMS(5000);
800 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, nGetStatus(nch));
801 } else {
802 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
803 "Sending USB Reset to device in 5 seconds...");
805 psdDelayMS(5000);
806 //psdDoHubMethod(nch->nch_Device, UCM_HubPowerCyclePort, nch->nch_Hub, nch->nch_HubPort);
807 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, nGetStatus(nch));
810 } else {
811 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, "Upgrade aborted by user.");
813 Close(nch->nch_InOutFile);
814 } else {
815 set(nch->nch_GaugeObj, MUIA_Gauge_InfoText, "Error opening file!");
818 /* \\\ */
820 /* /// "nGetStatus()" */
821 STRPTR nGetStatus(struct NepClassDFU *nch)
823 STRPTR infomsg;
824 LONG ioerr;
826 KPRINTF(1, ("GetStatus\n"));
827 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_INTERFACE,
828 UDFUR_GETSTATUS, 0, nch->nch_IfNum);
829 ioerr = psdDoPipe(nch->nch_EP0Pipe, &nch->nch_DFUStatus, sizeof(nch->nch_DFUStatus));
830 if(ioerr)
832 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
833 "UDFUR_GETSTATUS failed: %s (%ld)",
834 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
835 nch->nch_DFUStatus.bState = STATE_DFU_ERROR;
836 nch->nch_DFUStatus.bStatus = STATUS_ERR_UNKNOWN;
837 } else {
838 KPRINTF(1, ("State %ld, Status %ld\n", nch->nch_DFUStatus.bState, nch->nch_DFUStatus.bStatus));
839 if(nch->nch_DFUStatus.bState > STATE_DFU_ERROR)
841 nch->nch_DFUStatus.bState = STATE_DFU_ERROR;
843 if(nch->nch_DFUStatus.bStatus > STATUS_ERR_STALLEDPKT)
845 nch->nch_DFUStatus.bStatus = STATUS_ERR_UNKNOWN;
848 if(nch->nch_DFUStatus.bState == STATE_DFU_ERROR)
850 infomsg = DFUErrors[nch->nch_DFUStatus.bStatus];
851 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_INTERFACE,
852 UDFUR_CLRSTATUS, 0, nch->nch_IfNum);
853 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
854 if(ioerr)
856 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
857 "UDFUR_CLRSTATUS failed: %s (%ld)",
858 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
860 } else {
861 infomsg = DFUStates[nch->nch_DFUStatus.bState];
863 return(infomsg);
865 /* \\\ */
867 /* /// "nGUITaskCleanup()" */
868 void nGUITaskCleanup(struct NepClassDFU *nch)
870 if(nch->nch_App)
872 MUI_DisposeObject(nch->nch_App);
873 nch->nch_App = NULL;
875 if(nch->nch_Buffer)
877 psdFreeVec(nch->nch_Buffer);
878 nch->nch_Buffer = NULL;
880 if(nch->nch_EP0Pipe)
882 psdFreePipe(nch->nch_EP0Pipe);
883 nch->nch_EP0Pipe = NULL;
885 if(nch->nch_TaskMsgPort)
887 DeleteMsgPort(nch->nch_TaskMsgPort);
888 nch->nch_TaskMsgPort = NULL;
890 if(MUIMasterBase)
892 CloseLibrary(MUIMasterBase);
893 MUIMasterBase = NULL;
895 if(DOSBase)
897 CloseLibrary(DOSBase);
898 DOSBase = NULL;
900 if(IntuitionBase)
902 CloseLibrary(IntuitionBase);
903 IntuitionBase = NULL;
905 if(ps)
907 CloseLibrary(ps);
908 ps = NULL;
910 Forbid();
911 nch->nch_GUIBinding = NULL;
912 nch->nch_GUITask = NULL;
913 if(nch->nch_ReadySigTask)
915 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
917 --nch->nch_ClsBase->nh_Library.lib_OpenCnt;
919 /* \\\ */