/* DISKAPI.C
 *
 * Autor:    Kai Uwe Rommel
 * Datum:    Thu 28-Dec-1989
 * Stand:    Tue 7-Aug-1990
 *
 * Compiler: MS C ab 5.10
 * System:   PC/MS-DOS ab 3.20
 *
 * Direct disk access library for OS/2 protected mode and MS-DOS.
 *
 * - API simulation for MS-DOS.
 */

#include <dos.h>

#include "diskacc.h"


#define RETRIES        3
#define DSTEP(x)       (* (char far *) (0x00400090L + (x)))
#define INC(ptr, x)    (ptr = (PVOID) ((PBYTE) ptr + x * 512))


#ifdef DOSBUG
static int dosbug;
#endif


extern int diskint(int service, int drive, int head, int track,
                   int sector, int nsects, PBYTE buffer);


static int test_sector(int drive, int side, int track, int sector)
{
  return (diskint(4, drive, side, track, sector, 1, NULL) == 0);
}


INT APIENTRY DskOpen(USHORT drive, PUSHORT sides,
                     PUSHORT tracks, PUSHORT sectors)
{
  int cnt, erg;

  if ( drive > 1 )
    return -1;

  diskint(0, drive, 0, 0, 0, 0, NULL);

  for ( cnt = 0; cnt < 3; cnt++ )
    if ( erg = test_sector(drive, 0, 0, 1) )
      break;

  if ( ! erg )
    return -1;

  for ( cnt = 8; cnt <= 10; cnt ++ )
    if ( test_sector(drive, 0, 0, cnt) )
      *sectors = cnt;
    else
      break;

  if ( *sectors == 10 )
    for ( cnt = 15; cnt <= 20; cnt ++ )
      if ( test_sector(drive, 0, 0, cnt) )
        *sectors = cnt;
      else
        break;

  *sides = test_sector(drive, 1, 0, 1) ? 2 : 1;

  if ( DSTEP(drive) & 0x20 )
    if ( !test_sector(drive, 0, 1, 1) )
    {
       DSTEP(drive) &= ~0x20;

       if ( !test_sector(drive, 0, 1, 1) )
          return -1;
    }

  *tracks = (DSTEP(drive) & 0x20) ? 40 : 80;

#ifdef DOSBUG
  if ( *sectors > 9 )
    dosbug = diskint(4, drive, 1, 0, 9, 2, NULL);
  else
    dosbug = 0; 
#endif

  return drive + 1;
}


VOID APIENTRY DskClose(USHORT handle)
{
  if ( (handle < 1) || (2 < handle) )
    return;

  diskint(0, handle - 1, 0, 0, 0, 0, NULL);
}


static int dmaborder(PVOID buf, USHORT nsects)
{
  unsigned long lo, hi;

  lo = ((long) FP_SEG(buf) << 4) + (long) FP_OFF(buf);
  hi = lo + nsects * 512L - 1;

  if ( (lo & 0xFFFF0000) == (hi & 0xFFFF0000) )
    return -1;

  return (int) (((hi & 0xFFFF0000) - lo) / 512L);
}


int diskint3r(int f, int drive, int head, int track,
              int sector, int nsects, PBYTE buf)
{
  int cnt, rc;

  for ( cnt = 0; cnt < RETRIES; cnt++ )
  {
#ifdef DOSBUG
    if ( dosbug && (sector < 10) && (sector + nsects > 10) )
    {              /* what an ugly bug in several DOS versions ... */
      rc  = diskint(f, drive, head, track, sector, 10 - sector, buf);
      rc += diskint(f, drive, head, track, 10, sector + nsects - 10,
                   buf + (10 - sector) * 512);
    }
    else
#endif
      rc = diskint(f, drive, head, track, sector, nsects, buf);

    if ( rc == 0 )
      return 0;
    else
      diskint(0, drive, 0, 0, 0, 0, NULL);
  }

  return -1;
}


INT APIENTRY DskRead(USHORT handle, USHORT side, USHORT  track,
                     USHORT sector, USHORT nsects, PVOID buf)
{
  char buffer[1024], *ptr;
  int dma, cnt;

  if ( (handle < 1) || (2 < handle) )
    return -1;

  if ( (dma = dmaborder(buf, nsects)) == -1 )
  {
    if ( diskint3r(2, handle - 1, side, track, sector, nsects, buf) )
      return -1;
  }
  else
  {
    ptr = (dmaborder(buffer, 1) == -1) ? buffer : buffer + 512;

    if ( dma > 0 )
    {
      if ( diskint3r(2, handle - 1, side, track, sector, dma, buf) )
        return -1;

      INC(buf, dma);
      sector += dma;
      nsects -= dma;
    }

    if ( diskint3r(2, handle - 1, side, track, sector, 1, ptr) )
      return -1;

    for ( cnt = 0; cnt < 512; cnt++ )
      ((PBYTE) buf)[cnt] = ptr[cnt];

    INC(buf, 1);
    sector++;
    nsects--;

    if ( nsects > 0 )
      if ( diskint3r(2, handle - 1, side, track, sector, nsects, buf) )
        return -1;
  }

  return 0;
}

 
INT APIENTRY DskWrite(USHORT handle, USHORT side, USHORT  track,
                      USHORT sector, USHORT nsects, PVOID buf)
{
  char buffer[1024], *ptr;
  int dma, cnt;

  if ( (handle < 1) || (2 < handle) )
    return -1;

  if ( (dma = dmaborder(buf, nsects)) == -1 )
  {
    if ( diskint3r(3, handle - 1, side, track, sector, nsects, buf) )
      return -1;
  }
  else
  {
    ptr = (dmaborder(buffer, 1) == -1) ? buffer : buffer + 512;

    if ( dma > 0 )
    {
      if ( diskint3r(3, handle - 1, side, track, sector, dma, buf) )
        return -1;

      INC(buf, dma);
      sector += dma;
      nsects -= dma;
    }

    for ( cnt = 0; cnt < 512; cnt++ )
      ptr[cnt] = ((PBYTE) buf)[cnt];

    if ( diskint3r(3, handle - 1, side, track, sector, 1, ptr) )
      return -1;

    INC(buf, 1);
    sector++;
    nsects--;

    if ( nsects > 0 )
      if ( diskint3r(3, handle - 1, side, track, sector, nsects, buf) )
        return -1;
  }

  return 0;
}

 
/* Ende DISKAPI.C */
