how to SYNC to inhibit all partitions

This forum is for general developer support questions.
Post Reply
User avatar
javierdlr
Beta Tester
Beta Tester
Posts: 389
Joined: Sun Jun 19, 2011 11:13 pm
Location: Donostia (GUIPUZCOA) - Spain
Contact:

how to SYNC to inhibit all partitions

Post by javierdlr »

Can someone point me (enlight) where to look (website, code, sdk docs,...) to add to poweroff SYNC feature (like in reboot cmd.)?

TIA
User avatar
salass00
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 534
Joined: Sat Jun 18, 2011 4:12 pm
Location: Finland
Contact:

Re: how to SYNC to inhibit all partitions

Post by salass00 »

Essentially all you need to do is go through all the devices in the doslist and inhibit them.

The following code should do that:

Code: Select all

static void Sync(void) {
    const uint32 flags = LDF_READ|LDF_DEVICES;
    struct DeviceNode *dn;

    dn = IDOS->LockDosList(flags);
    while ((dn = (struct DeviceNode *)IDOS->NextDosEntry((struct DosList *)dn, flags))) {
        if (dn->dn_Port != NULL) {
            /* Skip RAM Disk */
            if (!strcmp((char *)BADDR(dn->dn_Name)+1, "RAM"))
                continue;

            /* 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? */
            IDOS->FlushVolumePort(dn->dn_Port); /* Requires dos.library V53.90 */

            /* Inhibit filesystem. */
            IDOS->InhibitPort(dn->dn_Port, TRUE); /* Requires dos.library V53.88 */
        }
    }
    IDOS->UnLockDosList(flags);
}
Depending on how safe you want to be you could check for a failure of InhibitPort() function. If it returns FALSE and IDOS->IoErr() !=ERROR_ACTION_NOT_KNOWN then that means that the device couldn't inhibit because there was an error. In such a case you could if you wanted to set a flag and then afterwards uninhibit all the devices and not do the poweroff.
User avatar
ZeroG
Posts: 124
Joined: Sat Jun 18, 2011 12:31 pm
Location: Germany

Re: how to SYNC to inhibit all partitions

Post by ZeroG »

Or he could just use C:Reboot SYNC...
Raziel

Re: how to SYNC to inhibit all partitions

Post by Raziel »

ZeroG wrote:Or he could just use C:Reboot SYNC...
He wants to poweroff, not reboot
User avatar
javierdlr
Beta Tester
Beta Tester
Posts: 389
Joined: Sun Jun 19, 2011 11:13 pm
Location: Donostia (GUIPUZCOA) - Spain
Contact:

Re: how to SYNC to inhibit all partitions

Post by javierdlr »

salass00 wrote:Essentially all you need to do is go through all the devices in the doslist and inhibit them.
..
Thx it works fine your code :-) just a question:
Why are you using 'struct DeviceNode *dn;' instead of 'struct DosList *dl;' looking in autodocs 'IDOS->LockDosList()' result "should" be a DosList structure. Or am I mixing things (or too complicated for a non programmer guy :-O )

Thx again.
Hidden Text - Click to Show :
/*
* poff: gcc -Wall -N poff.c -opoff
* (C) Copyright 2013
* Fredrik Wikstrom
*
* Based on U-boot code:
* (C) Copyright 2009-2011
* Max Tretene, ACube Systems Srl. [email protected].
*
* 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 like Reboot cmd (THX salas00 for Sync_code)
*/

#include <devices/timer.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/expansion.h>
#include <string.h>

#define CONFIG_SYS_FPGA_BASE 0xFF000000 // SAM460ex

struct MsgPort *timer_mp = NULL;
struct TimeRequest *timer_io = NULL;
struct Library *ExpansionBase = NULL;
struct ExpansionIFace *IExpansion = NULL;

const char *version={"\0$VER: poff 0.4 (31.05.2013)\r\n"};

struct RDArgs *rdargs;
STATIC struct{
LONG *WaitTime;
LONG SyncHDDs;
} Args;


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);
}


static BOOL openlibs(void) {
if( (ExpansionBase = IExec->OpenLibrary("expansion.library", 53)) != NULL )
if( (IExpansion = (struct ExpansionIFace *) IExec->GetInterface((struct Library *) ExpansionBase, "main", 1, NULL)) != NULL)
return(TRUE);

return(FALSE);
}


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;
struct DeviceNode *dn;

dn = IDOS->LockDosList(flags);
while( (dn = (struct DeviceNode *)IDOS->NextDosEntry((struct DosList *)dn, flags)) )
{
if (dn->dn_Port != NULL)
{
if(!strcmp((char *)BADDR(dn->dn_Name)+1, "RAM")) /* Skip RAM Disk */
continue;
/* 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(dn->dn_Port); /* Requires dos.library V53.90 */
IDOS->InhibitPort(dn->dn_Port, TRUE); /* Requires dos.library V53.88 */
}
}
IDOS->UnLockDosList(flags);
}


static inline void out_be16(void *p, uint16 v) {
volatile uint16 *reg = p;
__asm volatile ("sync");
*reg = v;
__asm volatile ("sync; isync");
}


int main(void) {
uint16 fpga_val;
uint32 msec=0, cpum;

if(openlibs() == FALSE) //something went wrong, but what?
{
if(IExpansion)
{
IDOS->PutErrStr("POFF: Failed to open ExpansionIFace.\n");
IExec->DropInterface( (struct Interface *) IExpansion);
}
if(ExpansionBase)
{
IDOS->PutErrStr("POFF: Failed to open 'expansion.library' +V53\n" );
IExec->CloseLibrary( (struct Library *) ExpansionBase);
}
return(RETURN_FAIL);
}

if(opentimer() == FALSE)
{
IDOS->PutErrStr("POFF: Failed to open 'timer.device'.\n");
IExec->DropInterface( (struct Interface *) IExpansion);
IExec->CloseLibrary( (struct Library *) ExpansionBase);
return(RETURN_FAIL);
}

// IExec->GetCPUInfoTags(GCIT_Model, &cpum, TAG_DONE); // get cpu model
IExpansion->GetMachineInfoTags(GMIT_Machine, &cpum, TAG_DONE); // get machine model

rdargs = IDOS->ReadArgs("WAIT/N,SYNC/S",(LONG *)&Args,NULL);
if(rdargs != NULL)
{
if(Args.WaitTime) msec=(*Args.WaitTime)*1000;

if(Args.SyncHDDs)
{
IDOS->Printf("POFF: Trying to shut down all file system devices...\n");
Sync();
}

if(cpum==MACHINETYPE_X1000) // see 'case MACHINETYPE_X1000:'
{
if(msec>4000) msec-=4000;
else msec=0;
}
}

// IDOS->Printf("your machine=%lu; wait=%lumsec\n",cpum,msec);
// cpum=0; // "trick" to not poweroff while testing
IDOS->Printf("Going to poweroff your machine...\n");
if(msec) wait_ms(msec);
IDOS->FreeArgs(rdargs);

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;
// IExec->Wait(SIGBREAKF_CTRL_C);
*((uint8 *)(0xf5000007)) = 0;
break;

default:
IDOS->PutErrStr("Oops, machine not supported.\n");
break;
}

IExec->FreeSysObject(ASOT_IOREQUEST, timer_io);
IExec->FreeSysObject(ASOT_PORT, timer_mp);
IExec->DropInterface( (struct Interface *) IExpansion);
IExec->CloseLibrary( (struct Library *) ExpansionBase);

return(RETURN_OK);
}
User avatar
salass00
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 534
Joined: Sat Jun 18, 2011 4:12 pm
Location: Finland
Contact:

Re: how to SYNC to inhibit all partitions

Post by salass00 »

javierdlr wrote: Thx it works fine your code :-) just a question:
Why are you using 'struct DeviceNode *dn;' instead of 'struct DosList *dl;' looking in autodocs 'IDOS->LockDosList()' result "should" be a DosList structure. Or am I mixing things (or too complicated for a non programmer guy :-O )
The DeviceNode struct is a specialised version of the DosList structure which applies only when the type field of the DosList is DLT_DEVICE. There are also others like VolumeNode for DLT_VOLUME and AssignNode for DLT_ASSIGN. The DosList structure just combines all of these into one structure using a union for the type specific fields.

You can also check out the comments on the structures in <dos/dosextens.h> as they explain this too.
User avatar
javierdlr
Beta Tester
Beta Tester
Posts: 389
Joined: Sun Jun 19, 2011 11:13 pm
Location: Donostia (GUIPUZCOA) - Spain
Contact:

Re: how to SYNC to inhibit all partitions

Post by javierdlr »

Hi, now using this code to SYNC, suing AllocDosObjectTags now:

Code: Select all

static void Sync(void) {
 int32 result;
 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);
    if( !ILocale->StrnCmp(NULL, nd->ln_Name, "RAM Disk:", -1, SC_ASCII) ) continue; // Skip RAM Disk

    result = IDOS->GetDiskInfoTags(GDI_StringNameInput, nd->ln_Name,
                               GDI_InfoData, &id,
                               TAG_END);
    if(result)
    {
     if(id.id_DiskState == ID_DISKSTATE_WRITE_PROTECTED) continue;
     // 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);
 }
}
Tried a couple of times and seems to work fine, any "difference"/"better" to use AllocDosObject() instead of previous (see first reply http://forum.hyperion-entertainment.biz ... 983#p20462) one?
Could I get a problem, 'cos now I strncmp 'RAM Disk:' instead of 'RAM:', maybe someone renamed 'RAM Disk:' to 'RAMDisk:' or alike.
TIA
User avatar
colinw
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 218
Joined: Mon Aug 15, 2011 10:20 am
Location: Brisbane, QLD. Australia.

Re: how to SYNC to inhibit all partitions

Post by colinw »

javierdlr wrote:Hi, now using this code to SYNC, suing AllocDosObjectTags now:
Tried a couple of times and seems to work fine, any "difference"/"better" to use AllocDosObject() instead of previous one.
Could I get a problem, 'cos now I strncmp 'RAM Disk:' instead of 'RAM:', maybe someone renamed 'RAM Disk:' to 'RAMDisk:' or alike.
TIA
Drop the ram disk test entirely, it's pointless, RAM will inhibit like all the others, so there's absolutely no point in doing that.
Also, drop the GetDiskInfo() test, it's also pointless, a write protected volume will still inhibit just fine.

You MUST test the result from GetDeviceProc(), it can return NULL.

You are doing it correctly using AllocDosObject() but be aware of the ADO_Type, LDF_VOLUMES all have DOS devices,
but not all LDF_DEVICES have filesystem volumes.

For what you are doing, LDF_VOLUMES is more correct because you probably are not interested in trying to kill things
like ENV: URL: TEXTCLIP: PIPE: APPDIR: etc....

Also, use IDOS->IsFileSystemPort( dp->dvp_Port ) as the final test for whether you should flush and inhibit this volume.
User avatar
javierdlr
Beta Tester
Beta Tester
Posts: 389
Joined: Sun Jun 19, 2011 11:13 pm
Location: Donostia (GUIPUZCOA) - Spain
Contact:

Re: how to SYNC to inhibit all partitions

Post by javierdlr »

THX Collin will change code and test it ASAP. THX again.
User avatar
colinw
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 218
Joined: Mon Aug 15, 2011 10:20 am
Location: Brisbane, QLD. Australia.

Re: how to SYNC to inhibit all partitions

Post by colinw »

By the way, I only just noticed...

FreeDeviceproc() must be called for each GetDeviceProc(), INSIDE the volume list loop.
As it is shown above, it's returning the deviceproc for each volume and just orphaning the devproc memory,
except for the last one when it falls out of the loop and calls FreeDeviceProc().
Post Reply