/* * compile poff: gcc poff.c -N -Wall -oPOff -lauto * (C) Copyright 2013 * Fredrik Wikstrom original code. Updated by Javier de las Rivas * * Based on U-boot code: * (C) Copyright 2009-2011 * Max Tretene, ACube Systems Srl. mtretene@acube-systems.com. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * version 0.1 (2013.05.23): added SECONDS argument * version 0.2 (2013.05.25): included A1-X1000 from OS4Depot poweroff by Alex Carmona * version 0.3 (2013.05.25): using IExpansion->GetMachineInfoTags instead of IExec->GetCPUInfoTags * version 0.4 (2013.05.31): added SYNC alike Reboot cmd (THX salas00 for Sync_code) * version 0.5 (2013.06.09): fixed the X1000 poweroff case (THX Guillaume 'bzzd10h' Boesel) * version 0.6 (2013.06.11): WB/Icon support; Refactored code; ASK tooltype ;-) * version 1.1 (2013.06.15): [internal] added catalog/locale support; Refactored code * version 1.2 (2013.06.18): changed ASK req; added 'LAST CHANCE' ReAction window; cleaned-up code * version 1.3 (2013.06.20): now checks for SAM460/X1000 (hide POWEROFF,..); removed FreeDiskObject() duplicated * version 1.4 (2013.06.28): do not SYNC read only devices */ #define ALL_REACTION_CLASSES #include <reaction/reaction.h> #include <reaction/reaction_macros.h> #include <proto/intuition.h> #include <proto/exec.h> #include <proto/dos.h> #include <proto/expansion.h> #include <proto/icon.h> #include <proto/requester.h> #include <proto/locale.h> #include <stdio.h> #include <stdlib.h> #include "poff_rev.h" #define CATCOMP_NUMBERS #define CATCOMP_BLOCK #define CATCOMP_CODE #include "poff_strings.h" #define CONFIG_SYS_FPGA_BASE 0xFF000000 // SAM460ex const char version[] = VERSTAG; struct MsgPort *timer_mp = NULL; struct TimeRequest *timer_io = NULL; struct Library *ExpansionBase = NULL; struct ExpansionIFace *IExpansion = NULL; struct Library *IconBase = NULL; struct IconIFace *IIcon = NULL; struct Library *LocaleBase = NULL; struct LocaleIFace *ILocale = NULL; enum{GID_GAUGE=0, GID_QUIT, GID_LAST}; enum{WID_MAIN=0, WID_LAST}; enum{OID_MAIN=0, OID_LAST}; struct Window *windows[WID_LAST]; struct Gadget *gadgets[GID_LAST]; Object *objects[OID_LAST]; struct RDArgs *rdargs; CONST_STRPTR argTemplate = "WAIT/N,SYNC/S"; STATIC struct{ LONG *WaitTime; LONG SyncHDDs; } Args; struct LocaleInfo li; char msgbuffer[200]; // for use in localized strings static BOOL opentimer(void) { timer_mp = IExec->AllocSysObject(ASOT_PORT, NULL); timer_io = IExec->AllocSysObjectTags(ASOT_IOREQUEST, ASOIOR_Size, sizeof(struct TimeRequest), ASOIOR_ReplyPort, timer_mp, TAG_END); if(timer_io != NULL) { if(IExec->OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *)timer_io, 0) == IOERR_SUCCESS) return(TRUE); IExec->FreeSysObject(ASOT_IOREQUEST, timer_io); } IExec->FreeSysObject(ASOT_PORT, timer_mp); return(FALSE); } BOOL openlibs(void) { if( (ExpansionBase = IExec->OpenLibrary("expansion.library", 53)) == NULL) { snprintf(msgbuffer, sizeof(msgbuffer), GetString(&li, MSG_FAIL_OPEN_LIB),"expansion.library",53); IDOS->PutErrStr(msgbuffer); return(FALSE); } if( (IExpansion = (struct ExpansionIFace *)IExec->GetInterface((struct Library *)ExpansionBase, "main", 1, NULL)) == NULL) { snprintf(msgbuffer, sizeof(msgbuffer), GetString(&li, MSG_FAIL_OPEN_IFACE),"ExpansionIFace"); IDOS->PutErrStr(msgbuffer); return(FALSE); } if( (IconBase = IExec->OpenLibrary("icon.library", 53)) == NULL) { snprintf(msgbuffer, sizeof(msgbuffer), GetString(&li, MSG_FAIL_OPEN_LIB),"icon.library",53); IDOS->PutErrStr(msgbuffer); return(FALSE); } if( (IIcon = (struct IconIFace *)IExec->GetInterface(IconBase, "main", 1, NULL)) == NULL) { snprintf(msgbuffer, sizeof(msgbuffer), GetString(&li, MSG_FAIL_OPEN_IFACE),"IconIFace"); IDOS->PutErrStr(msgbuffer); return(FALSE); } if(!ButtonBase || !FuelGaugeBase || !WindowBase || !LayoutBase) { snprintf(msgbuffer, sizeof(msgbuffer), GetString(&li, MSG_FAIL_OPEN_IFACE),"ReAction"); IDOS->PutErrStr(msgbuffer); return(FALSE); } return(TRUE); } void closelibs(void) { if(ILocale) { ILocale->CloseCatalog(li.li_Catalog); IExec->DropInterface( (struct Interface *)ILocale ); } if(LocaleBase) IExec->CloseLibrary( (struct Library *)LocaleBase ); if(IExpansion) IExec->DropInterface( (struct Interface *)IExpansion ); if(ExpansionBase) IExec->CloseLibrary( (struct Library *)ExpansionBase ); if(IIcon) IExec->DropInterface( (struct Interface *)IIcon ); if(IconBase) IExec->CloseLibrary( (struct Library *)IconBase ); } static void wait_ms(uint32 ms) { timer_io->Request.io_Command = TR_ADDREQUEST; timer_io->Time.Seconds = ms / 1000; timer_io->Time.Microseconds = (ms % 1000) * 1000; IExec->DoIO( (struct IORequest *)timer_io ); } /* static void Sync(void) { const uint32 flags = LDF_READ|LDF_DEVICES; int32 result; struct DeviceNode *dn; struct InfoData id; dn = (struct DeviceNode *)IDOS->LockDosList(flags); while( (dn = (struct DeviceNode *)IDOS->NextDosEntry( (struct DosList *)dn, flags)) ) { if(dn->dn_Port != NULL) { if( !ILocale->StrnCmp(NULL, (char *)BADDR(dn->dn_Name)+1, "RAM", -1, SC_ASCII) ) continue; // Skip RAM Disk if( !ILocale->StrnCmp(NULL, (char *)BADDR(dn->dn_Name)+1, "TEXTCLIP", -1, SC_ASCII) ) continue; // Skip TEXTCLIP if( (result = IDOS->GetDiskInfoTags(GDI_MsgPortInput, dn->dn_Port, GDI_InfoData, &id, TAG_END) )) { if(id.id_DiskState == ID_DISKSTATE_WRITE_PROTECTED) continue; // Skip read only devices // Cause filesystem to flush all pending writes. // Inhibit should do this as well but might be useful for old // filesystems that don't support Inhibit to use Flush result = IDOS->FlushVolumePort(dn->dn_Port); // Requires dos.library V53.90 result = IDOS->InhibitPort(dn->dn_Port, TRUE); // Requires dos.library V53.88 } } } IDOS->UnLockDosList(flags); } */ static void Sync(void) { struct Node *nd = NULL; struct InfoData id; struct DevProc *dp = NULL; struct List *list = IDOS->AllocDosObjectTags(DOS_VOLUMELIST, ADO_Type, LDF_VOLUMES, ADO_AddColon, TRUE, TAG_END); if(list) { for( nd = IExec->GetHead(list); nd; nd = IExec->GetSucc(nd) ) { dp = IDOS->GetDeviceProc(nd->ln_Name, NULL); // IDOS->Printf("%s (0x%lX)\n",nd->ln_Name,dp->dvp_Port); if( !ILocale->StrnCmp(NULL, nd->ln_Name, "RAM Disk:", -1, SC_ASCII) ) continue; // skip RAM Disk if( (IDOS->GetDiskInfoTags(GDI_MsgPortInput, dp->dvp_Port, GDI_InfoData, &id, TAG_END)) ) { if(id.id_DiskState == ID_DISKSTATE_WRITE_PROTECTED) continue; // skip read only devices // Cause filesystem to flush all pending writes. Inhibit should do this as well but // might be useful for old filesystems that don't support Inhibit to use Flush. IDOS->FlushVolumePort(dp->dvp_Port); // Requires dos.library V53.90 IDOS->InhibitPort(dp->dvp_Port, TRUE); // Requires dos.library V53.88 } } IDOS->FreeDeviceProc(dp); IDOS->FreeDosObject(DOS_VOLUMELIST,list); } } static inline void out_be16(void *p, uint16 v) { volatile uint16 *reg = p; __asm volatile ("sync"); *reg = v; __asm volatile ("sync; isync"); } int main(int argc, char **argv) { uint16 fpga_val, result=3, answer=0; // default values/options uint32 cpum; int32 sec=0; STRPTR TTarg = NULL; BOOL syncON = FALSE; char reqtext[200], reqbtns[100], fuelgtext[10]; Object *requester; struct WBStartup *WBenchMsg = NULL; struct DiskObject *dobj = NULL; li.li_Catalog = NULL; if( (LocaleBase = IExec->OpenLibrary("locale.library", 53)) && (ILocale = (struct LocaleIFace *)IExec->GetInterface(LocaleBase, "main", 1, NULL)) ) { li.li_ILocale = ILocale; li.li_Catalog = ILocale->OpenCatalog(NULL, "poff.catalog", OC_BuiltInLanguage, "english", OC_PreferExternal, TRUE, TAG_END); } else IDOS->PutErrStr("POFF: Failed to use catalog system. Using built-in strings.\n"); if(openlibs() == FALSE) { closelibs(); return(RETURN_FAIL); } if(opentimer() == FALSE) { snprintf(msgbuffer, sizeof(msgbuffer), GetString(&li, MSG_FAIL_OPEN_IFACE),"timer.device"); IDOS->PutErrStr(msgbuffer); closelibs(); return(RETURN_FAIL); } // IExec->GetCPUInfoTags(GCIT_Model, &cpum, TAG_DONE); // get cpu model IExpansion->GetMachineInfoTags(GMIT_Machine, &cpum, TAG_DONE); // get machine model if(argc == 0) WBenchMsg = (struct WBStartup *)argv; if(WBenchMsg) { // IDOS->Printf("started from WB\n"); // get disk object dobj = IIcon->GetDiskObjectNew("PROGDIR:poff"); if(dobj) { // check for "WAIT" tooltype TTarg = IIcon->FindToolType(dobj->do_ToolTypes, "WAIT"); if(TTarg) sec=atoi(TTarg); // check for "SYNC" tooltype TTarg = IIcon->FindToolType(dobj->do_ToolTypes, "SYNC"); if(TTarg) { syncON = TRUE; snprintf(reqtext, sizeof(reqtext), GetString(&li, MSG_REQ_ASK01B),sec,GetString(&li, MSG_REQ_ASK02B) ); } else snprintf(reqtext, sizeof(reqtext), GetString(&li, MSG_REQ_ASK01B),sec,""); // hide POWEROFF button if no SAM460/X1000 if(cpum==MACHINETYPE_X1000 || cpum==MACHINETYPE_SAM460) snprintf(reqbtns, sizeof(reqbtns), GetString(&li, MSG_GAD_BUTTONS) ); else snprintf(reqbtns, sizeof(reqbtns), GetString(&li, MSG_GAD_BUTTONS2) ); // check for "ASK" tooltype TTarg = IIcon->FindToolType(dobj->do_ToolTypes, "ASK"); if(TTarg) { requester = IIntuition->NewObject(NULL, "requester.class", REQ_Image, REQIMAGE_WARNING, REQ_TitleText, VERS" ("DATE")", REQ_BodyText, reqtext, REQ_GadgetText, reqbtns, TAG_DONE); result = IIntuition->IDoMethod(requester, RM_OPENREQ, NULL, NULL, NULL); IIntuition->DisposeObject(requester); if(result == 0) // user choosed CANCEL, end properly { IIcon->FreeDiskObject(dobj); IExec->FreeSysObject(ASOT_IOREQUEST, timer_io); IExec->FreeSysObject(ASOT_PORT, timer_mp); closelibs(); return(RETURN_OK); } } // end if(TTarg) "ASK" // put the correct word (poweroff|reboot) in the 'LAST CHANCE' requester if(result == 3) // poweroff choosed (only SAM460/X1000) snprintf(reqtext, sizeof(reqtext), GetString(&li, MSG_REQ_ABORT_TXT),GetString(&li, MSG_REQ_ABORT_POWEROFF),sec); else // reboot choosed snprintf(reqtext, sizeof(reqtext), GetString(&li, MSG_REQ_ABORT_TXT),GetString(&li, MSG_REQ_ABORT_REBOOT),sec); } // end if(dobj) // free disk object structure & memory IIcon->FreeDiskObject(dobj); } // end if(WBenchMsg) else // commandline usage { if(cpum!=MACHINETYPE_X1000 && cpum!=MACHINETYPE_SAM460) // No SAM460/X1000? End properly { IDOS->PutErrStr(GetString(&li, MSG_NOT_SUPPORTED) ); IExec->FreeSysObject(ASOT_IOREQUEST, timer_io); IExec->FreeSysObject(ASOT_PORT, timer_mp); closelibs(); return(RETURN_WARN); } rdargs = IDOS->ReadArgs(argTemplate, (LONG *)&Args, NULL); if(rdargs != NULL) { if(Args.WaitTime) sec=(*Args.WaitTime); if(Args.SyncHDDs) syncON = TRUE; } IDOS->FreeArgs(rdargs); } /* Create the window object. */ objects[OID_MAIN] = WindowObject, WA_Title, VERS" ("DATE")", WA_Activate, TRUE, // WA_DepthGadget, TRUE, WA_DragBar, TRUE, WA_StayTop, TRUE, WINDOW_Position, WPOS_CENTERMOUSE, // WPOS_CENTERSCREEN WINDOW_ParentGroup, VGroupObject, LAYOUT_AddChild, gadgets[GID_GAUGE] = (struct Gadget *)FuelGaugeObject, GA_ID, GID_GAUGE, // GA_Text, fuelgtext, FUELGAUGE_Justification, FGJ_CENTER, FUELGAUGE_Min, 0, FUELGAUGE_Max, sec, FUELGAUGE_Level, sec, FUELGAUGE_Percent, FALSE, FUELGAUGE_TickSize, 0, FUELGAUGE_Ticks, 0, FuelGaugeEnd, LAYOUT_AddImage, LabelObject, LABEL_Text, reqtext, LABEL_Justification, LJ_CENTER, LabelEnd, LAYOUT_AddChild, gadgets[GID_QUIT] = (struct Gadget *)ButtonObject, GA_ID, GID_QUIT, GA_RelVerify, TRUE, GA_Text,GetString(&li, MSG_REQ_ABORT_BUTTON), ButtonEnd, EndGroup, EndWindow; // IDOS->Printf("your machine=%lu; wait=%lumsec\n",cpum,sec); // cpum=0; // "trick" to not poweroff while testing if(!WBenchMsg) IDOS->Printf( GetString(&li, MSG_CLI_POWEROFF) ); // hide it if in WB/icon mode while(sec) { if(WBenchMsg) { /* Object creation sucessful? */ if(objects[OID_MAIN]) { /* Open the window. */ if( (windows[WID_MAIN] = (struct Window *)RA_OpenWindow(objects[OID_MAIN])) ) { ULONG result2, done=FALSE; UWORD code; /* Input Event Loop */ sec++; // to show 0 on fuelgauge's countdown while(!done && sec) { sprintf(fuelgtext, "%ld",--sec); IIntuition->SetGadgetAttrs(gadgets[GID_GAUGE], windows[WID_MAIN], NULL, GA_Text, fuelgtext, FUELGAUGE_Level, sec, TAG_DONE); wait_ms(1000); while( (result2 = RA_HandleInput(objects[OID_MAIN], &code)) != WMHI_LASTMSG ) { if( (result2 & WMHI_CLASSMASK) == WMHI_GADGETUP && (result2 & WMHI_GADGETMASK) == GID_QUIT ) done = answer = TRUE; } // end while( (result = RA.. } // end while(!done && sec) } // end if(windows[WID_MAIN].. } //end if(objects[OID_MAIN]) // Disposing of the window object will also close the window if it is // already opened, and it will dispose of the layout object attached to it. // IIntuition->DisposeObject(objects[OID_MAIN]); // answer=TRUE; // "trick" to exit while testing if(answer) // user choosed ABORT 'LAST CHANCE', end properly { IIntuition->DisposeObject(objects[OID_MAIN]); IExec->FreeSysObject(ASOT_IOREQUEST, timer_io); IExec->FreeSysObject(ASOT_PORT, timer_mp); closelibs(); return(RETURN_OK); } IIntuition->SetGadgetAttrs(gadgets[GID_QUIT], // 'LAST CHANCE' still visible, but disabling button windows[WID_MAIN], NULL, GA_Disabled, TRUE, TAG_DONE); } //end if(WBenchMsg) else { IDOS->Printf(GetString(&li, MSG_CLI_POWEROFF2),sec); wait_ms(1000); sec--; IDOS->Printf(GetString(&li, MSG_CLI_POWEROFF2),sec); // shows 0 in countdown } } //end while(sec) if(syncON) { if(!WBenchMsg) IDOS->Printf( GetString(&li, MSG_SYNC) ); // hide it if in WB/icon mode Sync(); } // result of first ASK req: SoftReboot=1 HardReboot=2 PowerOff=3 if(result == 1) IExec->ColdReboot(); if(result == 2) IExec->IceColdReboot(); switch(cpum) { case MACHINETYPE_SAM460: // SAM460ex fpga_val = 0x000f; out_be16((void *)CONFIG_SYS_FPGA_BASE + 0x2E, fpga_val); wait_ms(300); fpga_val = 0x0000; out_be16((void *)CONFIG_SYS_FPGA_BASE + 0x2E, fpga_val); wait_ms(300); fpga_val = 0x000f; out_be16((void *)CONFIG_SYS_FPGA_BASE + 0x2E, fpga_val); wait_ms(300); fpga_val = 0x0010; out_be16((void *)CONFIG_SYS_FPGA_BASE + 0x2E, fpga_val); while(1); break; case MACHINETYPE_X1000: // A1-X1000 takes 4 secs internaly to poweroff *((uint8 *)(0xf5000007)) = 1; while(1); // IExec->Wait(SIGBREAKF_CTRL_C); // user can abort poweroff with CTRL+C // *((uint8 *)(0xf5000007)) = 0; break; default: IDOS->PutErrStr( GetString(&li, MSG_NOT_SUPPORTED) ); break; } if(objects[OID_MAIN]) IIntuition->DisposeObject(objects[OID_MAIN]); IExec->FreeSysObject(ASOT_IOREQUEST, timer_io); IExec->FreeSysObject(ASOT_PORT, timer_mp); closelibs(); return(RETURN_OK); }

