/* DISKACC2.C
 *
 * Autor:    Kai Uwe Rommel
 * Datum:    Thu 28-Dec-1989
 * Stand:    Wed 22-Jul-1992
 *
 * Compiler: 32-bit OS/2
 * System:   OS/2 ab 2.0
 *
 * Direct disk access library for OS/2 2.0 protected mode.
 */


#define INCL_DOSDEVICES
#define INCL_DOSDEVIOCTL
#define INCL_NOPM
#include <os2.h>
#include <string.h>
#include <ctype.h>

#include "diskacc.h"


#define PHYSICAL     0x1000
#define CATEGORY(x)  (((x) & PHYSICAL) ? IOCTL_PHYSICALDISK : IOCTL_DISK)
#define HANDLE(x)    ((x) & ~PHYSICAL)


#pragma pack(1)

typedef struct
{
  BYTE   bCommand;
  USHORT usHead;
  USHORT usCylinder;
  USHORT usFirstSector;
  USHORT cSectors;
  struct
  {
    USHORT usSectorNumber;
    USHORT usSectorSize;
  }
  TrackTable[64];
}
TRACK;


ULONG DosDevIOCtl32(PVOID pData, ULONG cbData, PVOID pParms, ULONG cbParms,
		    ULONG usFunction, HFILE hDevice)
{
  ULONG ulParmLengthInOut = cbParms, ulDataLengthInOut = cbData;
  return DosDevIOCtl(HANDLE(hDevice), CATEGORY(hDevice), usFunction,
		     pParms, cbParms, &ulParmLengthInOut, 
		     pData, cbData, &ulDataLengthInOut);
}


static int test_sector(int handle, int side, int track, int sector)
{
  char buffer[1024];
  TRACK trk;

  trk.bCommand      = 0;
  trk.usHead        = side;
  trk.usCylinder    = track;
  trk.usFirstSector = 0;
  trk.cSectors      = 1;

  trk.TrackTable[0].usSectorNumber = sector;
  trk.TrackTable[0].usSectorSize   = 512;

  return (DosDevIOCtl32(buffer, sizeof(buffer), &trk, sizeof(trk), 
                        DSK_READTRACK, handle) == 0);
}


int DskOpen(char *drv, int logfmt, 
	    unsigned *sides, unsigned *tracks, unsigned *sectors)
{
  BIOSPARAMETERBLOCK bpb;
  HFILE handle;
  USHORT physical;
  ULONG action;
  BYTE cmd = logfmt;

  if ( isalpha(drv[0]) && drv[1] == ':' && drv[2] == 0 )
  {
    if ( DosOpen(drv, &handle, &action, 0L, FILE_NORMAL, FILE_OPEN,
		 OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR |
		 OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE, 0L) != 0 )
      return -1;
  }
  else if ( drv[0] == '$' && isdigit(drv[1]) && drv[2] == ':' && drv[3] == 0 )
  {
    if ( DosPhysicalDisk(INFO_GETIOCTLHANDLE, &physical, sizeof(physical), 
			 drv + 1, strlen(drv + 1)) != 0 )
      return -1;
    handle = physical | PHYSICAL;
  }
  else
    return -1;

  if ( DosDevIOCtl32(&bpb, sizeof(bpb), &cmd, sizeof(cmd), 
		     DSK_GETDEVICEPARAMS, handle) != 0 
       || DosDevIOCtl32(0L, 0, &cmd, sizeof(cmd), DSK_LOCKDRIVE, handle) != 0 )
  {
    if ( handle & PHYSICAL )
      DosPhysicalDisk(INFO_FREEIOCTLHANDLE, NULL, 0, 
		      &physical, sizeof(physical));
    else
      DosClose(handle);
    return -1;
  }

  *sectors = bpb.usSectorsPerTrack;
  /* *tracks  = bpb.cCylinders; */     /* work around possible bug */
  *tracks  = bpb.cSectors / (bpb.cHeads * bpb.usSectorsPerTrack);
  *sides   = bpb.cHeads;

  if ( *sectors >= 15 )
    if ( !test_sector(handle, 0, 0, 15) )
    {
      if ( *sectors == 15 )
        *tracks = 40;

      *sectors = 9;
    }

  return handle;
}


int DskClose(int handle)
{
  BYTE cmd = 0;
  USHORT physical = handle & ~PHYSICAL;

  DosDevIOCtl32(0L, 0, &cmd, sizeof(cmd), DSK_UNLOCKDRIVE, handle);

  if ( handle & PHYSICAL )
    return DosPhysicalDisk(INFO_FREEIOCTLHANDLE, NULL, 0, 
			   &physical, sizeof(physical));
  else
    return DosClose(handle);
}


int DskRead(int handle, unsigned side, unsigned  track,
            unsigned sector, unsigned nsects, void *buf)
{
  TRACK trk;
  unsigned cnt;

  trk.bCommand      = 0;
  trk.usHead        = side;
  trk.usCylinder    = track;
  trk.usFirstSector = 0;
  trk.cSectors      = nsects;

  for ( cnt = 0; cnt < nsects; cnt++ )
  {
    trk.TrackTable[cnt].usSectorNumber = sector + cnt;
    trk.TrackTable[cnt].usSectorSize   = 512;
  }

  return DosDevIOCtl32(buf, nsects * 512, &trk, sizeof(trk), 
                       DSK_READTRACK, handle);
}

 
int DskWrite(int handle, unsigned side, unsigned  track,
             unsigned sector, unsigned nsects, void *buf)
{
  TRACK trk;
  unsigned cnt;

  trk.bCommand      = 0;
  trk.usHead        = side;
  trk.usCylinder    = track;
  trk.usFirstSector = 0;
  trk.cSectors      = nsects;

  for ( cnt = 0; cnt < nsects; cnt++ )
  {
    trk.TrackTable[cnt].usSectorNumber = sector + cnt;
    trk.TrackTable[cnt].usSectorSize   = 512;
  }

  return DosDevIOCtl32(buf, nsects * 512, &trk, sizeof(trk), 
                       DSK_WRITETRACK, handle);
}

 
/* Ende DISKACC2.C */
