home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 3 / Meeting_Pearls_III.iso / Pearls / disk / Misc / dd / dev.c < prev    next >
C/C++ Source or Header  |  1992-06-02  |  12KB  |  413 lines

  1. /*
  2.  * dev.c - device manipulation functions
  3.  *
  4.  * Bruno Costa - 30 Nov 91 - 2 Jun 92
  5.  */
  6.  
  7. #include <exec/types.h>
  8. #include <exec/memory.h>
  9. #include <exec/errors.h>
  10. #include <devices/trackdisk.h>
  11. #include <dos/dos.h>
  12. #include <dos/filehandler.h>
  13. #include <dos/dosextens.h>
  14. #include <clib/exec_protos.h>
  15. #include <clib/dos_protos.h>
  16. #include <pragmas/exec_pragmas.h>
  17. #include <pragmas/dos_pragmas.h>
  18. #include <string.h>
  19. #include "dossupport.h"
  20. #include "dev.h"
  21.  
  22. extern struct Library *DOSBase;
  23. extern struct Library *SysBase;
  24.  
  25. extern int quiet;
  26.  
  27. static int blocksize = 512;
  28. static int sectorsize = 512;
  29. static unsigned char *sectorbuf = NULL;
  30.  
  31.  
  32. int devblocksize (void)
  33. {
  34.  return blocksize;
  35. }
  36.  
  37.  
  38. int devsectorsize (void)
  39. {
  40.  return sectorsize;
  41. }
  42.  
  43.  
  44. void Motor (struct IOExtTD *disk, int onoff)
  45. {
  46.   disk->iotd_Req.io_Length = onoff;
  47.   disk->iotd_Req.io_Command = TD_MOTOR;
  48.   DoIO ((struct IORequest *) disk);
  49. }
  50.  
  51.  
  52. int secread (struct IOExtTD *disk, long int offset)
  53. {
  54.  disk->iotd_Req.io_Length = sectorsize;
  55.  disk->iotd_Req.io_Data = (APTR) sectorbuf;
  56.  disk->iotd_Req.io_Command = CMD_READ;
  57.  disk->iotd_Req.io_Offset = (ULONG) (offset * sectorsize);
  58.  DoIO ((struct IORequest *) disk);
  59.  
  60.  return (disk->iotd_Req.io_Error == 0);
  61. }
  62.  
  63.  
  64. int secwrite (struct IOExtTD *disk, long int offset)
  65. {
  66.  disk->iotd_Req.io_Length = sectorsize;
  67.  disk->iotd_Req.io_Data = (APTR) sectorbuf;
  68.  disk->iotd_Req.io_Command = CMD_WRITE;
  69.  disk->iotd_Req.io_Offset = (ULONG) (offset * sectorsize);
  70.  DoIO ((struct IORequest *) disk);
  71.  
  72.  return (disk->iotd_Req.io_Error == 0);
  73. }
  74.  
  75.  
  76. int devread (struct IOExtTD *diskreq, BPTR f, long int skip, long int count)
  77. {
  78.  int secskip = skip / sectorsize;
  79.  int byteskip = skip - (secskip * sectorsize);
  80.  int seccount = (count + byteskip + sectorsize - 1) / sectorsize;
  81.  int bytecount = (seccount * sectorsize) - count - byteskip;
  82.  int sec;
  83.  
  84.  for (sec = 0; sec < seccount; sec++)
  85.  {
  86.    if (CheckSignal (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D))
  87.      return RETURN_FAIL;
  88.  
  89.    if (!secread (diskreq, secskip + sec))
  90.      return (diskreq->iotd_Req.io_Error);
  91.  
  92.    if (seccount == 1)
  93.    {
  94.      if (Write (f, sectorbuf + byteskip, sectorsize - byteskip - bytecount) != sectorsize - byteskip - bytecount)
  95.        return IoErr ();
  96.    }
  97.    else if (sec == 0)
  98.    {
  99.      if (Write (f, sectorbuf + byteskip, sectorsize - byteskip) != sectorsize - byteskip)
  100.        return IoErr ();
  101.    }
  102.    else if (sec == seccount - 1)
  103.    {
  104.      if (Write (f, sectorbuf, sectorsize - bytecount) != sectorsize - bytecount)
  105.        return IoErr ();
  106.    }
  107.    else
  108.    {
  109.      if (Write (f, sectorbuf, sectorsize) != sectorsize)
  110.        return IoErr ();
  111.    }
  112.  
  113.    if (!quiet)
  114.    {
  115.      Printf (" %ld/%ld\r", sec + 1, seccount);
  116.      Flush (Output ());
  117.    }
  118.  }
  119.  return 0;
  120. }
  121.  
  122.  
  123. int devwrite (BPTR f, struct IOExtTD *diskreq, long int skip, long int count)
  124. {
  125.  /*
  126.   *   devwrite() is a bit more complicated than devread() because partially
  127.   * skipped sectors should not be zeroed -- these sectors have to be read
  128.   * first, then partially filled with data from the file and then at last
  129.   * written to the device. The secskip/byteskip/seccount/bytecount
  130.   * calculations are probably the same as in devread().
  131.   */
  132.  int secskip = skip / sectorsize;
  133.  int byteskip = skip - (secskip * sectorsize);
  134.  int seccount = (count + byteskip + sectorsize - 1) / sectorsize;
  135.  int bytecount = (seccount * sectorsize) - count - byteskip;
  136.  int sec;
  137.  
  138.  for (sec = 0; sec < seccount; sec++)
  139.  {
  140.    if (CheckSignal (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D))
  141.      return RETURN_FAIL;
  142.  
  143.    if (seccount == 1)
  144.    {
  145.      if (!secread (diskreq, secskip + sec))
  146.        return (diskreq->iotd_Req.io_Error);
  147.  
  148.      if (Read (f, sectorbuf + byteskip, sectorsize - byteskip - bytecount) != sectorsize - byteskip - bytecount)
  149.        return IoErr ();
  150.    }
  151.    else if (sec == 0)
  152.    {
  153.      if (!secread (diskreq, secskip + sec))
  154.        return (diskreq->iotd_Req.io_Error);
  155.  
  156.      if (Read (f, sectorbuf + byteskip, sectorsize - byteskip) != sectorsize - byteskip)
  157.        return IoErr ();
  158.    }
  159.    else if (sec == seccount - 1)
  160.    {
  161.      if (!secread (diskreq, secskip + sec))
  162.        return (diskreq->iotd_Req.io_Error);
  163.  
  164.      if (Read (f, sectorbuf, sectorsize - bytecount) != sectorsize - bytecount)
  165.        return IoErr ();
  166.    }
  167.    else
  168.    {
  169.      if (Read (f, sectorbuf, sectorsize) != sectorsize)
  170.        return IoErr ();
  171.    }
  172.  
  173.    if (!secwrite (diskreq, secskip + sec))
  174.      return (diskreq->iotd_Req.io_Error);
  175.  
  176.    if (!quiet)
  177.    {
  178.      Printf (" %ld/%ld\r", sec + 1, seccount);
  179.      Flush (Output ());
  180.    }
  181.  }
  182.  return 0;
  183. }
  184.  
  185.  
  186. #define NDEVTYPES 10
  187. #define devtype(code) (((code) < NDEVTYPES) ? devtypetable[code] : "Unknown")
  188.  
  189. void devinfo (char *dosname, char *execname,
  190.               struct FileSysStartupMsg *fss, struct DosEnvec *de,
  191.               struct Device *dev, struct DriveGeometry *geo)
  192. {
  193.  static char *devtypetable[NDEVTYPES] = {
  194.    "Direct Access",
  195.    "Sequential Access",
  196.    "Printer",
  197.    "Processor",
  198.    "Worm",
  199.    "CD-ROM",
  200.    "Scanner",
  201.    "Optical Disk",
  202.    "Medium Changer",
  203.    "Communication"
  204.  };
  205.  static struct {int offset; char *format;} table[] = {
  206.    {DE_BOOTPRI,        "           Boot Priority: %ld\n"},
  207.    {DE_DOSTYPE,        "              Filesystem: 0x%lx\n"},
  208.    {DE_SIZEBLOCK,    "              Block size: %ld longwords\n"},
  209.    {DE_SECSPERBLK,    "       Sectors per Block: %ld\n"},
  210.    {DE_BLKSPERTRACK,    "        Blocks per track: %ld\n"},
  211.    {DE_NUMHEADS,    "         Number of heads: %ld\n"},
  212.    {DE_INTERLEAVE,    "              Interleave: %ld\n"},
  213.    {DE_LOWCYL,        "       Starting cylinder: %ld\n"},
  214.    {DE_UPPERCYL,    "         Ending cylinder: %ld\n"},
  215.    {DE_RESERVEDBLKS,    "Blocks reserved at start: %ld\n"},
  216.    {DE_PREFAC,        "  Blocks reserved at end: %ld\n"},
  217.    {DE_BOOTBLOCKS,    "   Number of Boot Blocks: %ld\n"},
  218.    {DE_NUMBUFFERS,    "       Number of buffers: %ld\n"},
  219.    {DE_BUFMEMTYPE,    " Memory Type for Buffers: 0x%lx\n"},
  220.    {DE_MAXTRANSFER,    "   Max bytes transferred: %ld\n"},
  221.    {DE_MASK,        "            Address Mask: 0x%lx\n"},
  222.    {DE_BAUD,        "               Baud rate: %ld\n"},
  223.    {DE_CONTROL,        "            Control Word: 0x%lx\n"},
  224.    {-1,    ""}
  225.  };
  226.  int i;
  227.  
  228.  Printf ("AmigaDOS information on device `%s':\n", dosname);
  229.  for (i = 0; table[i].offset > 0; i++)
  230.    if (table[i].offset <= de->de_TableSize)
  231.      Printf (table[i].format, ((ULONG *)de)[table[i].offset]);
  232.  
  233.  Printf ("\nExec information on device `%s' (unit %ld with flags 0x%lx):\n",
  234.           execname, fss->fssm_Unit, fss->fssm_Flags);
  235.  Printf ("          Device Version: %ld\n", dev->dd_Library.lib_Version);
  236.  Printf ("         Device Revision: %ld\n", dev->dd_Library.lib_Revision);
  237.  Printf ("        Device Driver ID: %s\n",
  238.          dev->dd_Library.lib_IdString ? dev->dd_Library.lib_IdString : "(empty)");
  239.  
  240.  if (!geo)
  241.    Printf ("        (Further information not available)\n");
  242.  else
  243.  {
  244.    Printf ("             Sector Size: %ld\n", geo->dg_SectorSize);
  245.    Printf ("           Total Sectors: %ld\n", geo->dg_TotalSectors);
  246.    Printf ("               Cylinders: %ld\n", geo->dg_Cylinders);
  247.    Printf ("         Number of Heads: %ld\n", geo->dg_Heads);
  248.    Printf ("       Sectors per Track: %ld\n", geo->dg_TrackSectors);
  249.    Printf (" Memory Type for Buffers: 0x%lx\n", geo->dg_BufMemType);
  250.    Printf ("              DeviceType: %s\n", devtype (geo->dg_DeviceType));
  251.    Printf ("                   Flags: 0x%lx", geo->dg_Flags);
  252.    Printf ("%s\n", (geo->dg_Flags & DGF_REMOVABLE) ? " (removable)" : "");
  253.  }
  254. }
  255.  
  256.  
  257. struct IOExtTD *opendev (char *devname, int justinfo)
  258. {
  259.  struct MsgPort *port;
  260.  struct DosList *dlist;
  261.  struct DosEnvec de;        /* drive geometry as seen by DOS */
  262.  struct FileSysStartupMsg fss;
  263.  char *execdev = NULL;
  264.  char save;
  265.  char *savepos;
  266.  
  267.  savepos = strchr (devname, ':');
  268.  if (!savepos)
  269.    return NULL;
  270.  
  271.  save = *savepos;        /* remove ':' */
  272.  *savepos = '\0';
  273.  
  274.  dlist = LockDosList (LDF_DEVICES | LDF_READ);
  275.  if (dlist)
  276.  {
  277.    struct DeviceNode *dosdev;
  278.    dosdev = (struct DeviceNode *) FindDosEntry (dlist, devname, LDF_DEVICES);
  279.    if (dosdev)
  280.    {
  281.      fss = *((struct FileSysStartupMsg *) BADDR (dosdev->dn_Startup));
  282.      de = *((struct DosEnvec *) BADDR (fss.fssm_Environ));
  283.      execdev = cstr (fss.fssm_Device);
  284.    }
  285.    UnLockDosList (LDF_DEVICES | LDF_READ);
  286.  }
  287.  
  288.  *savepos = save;        /* restore ':' */
  289.  
  290.  if (!execdev)
  291.    return NULL;
  292.  
  293.  if (port = CreateMsgPort ())
  294.  {
  295.    struct IOExtTD *diskreq;
  296.    diskreq = (struct IOExtTD *) CreateIORequest (port, sizeof (struct IOExtTD));
  297.    if (diskreq)
  298.    {
  299.      if (!OpenDevice (execdev, fss.fssm_Unit, (struct IORequest *) diskreq,
  300.                       fss.fssm_Flags))
  301.      {
  302.        ULONG memtype;
  303.        struct DriveGeometry geo;    /* drive geometry */
  304.  
  305.        diskreq->iotd_Req.io_Length = sizeof (geo);
  306.        diskreq->iotd_Req.io_Data = (APTR) &geo;
  307.        diskreq->iotd_Req.io_Command = TD_GETGEOMETRY;
  308.        diskreq->iotd_Req.io_Offset = 0;
  309.        DoIO ((struct IORequest *) diskreq);
  310.  
  311.        if (diskreq->iotd_Req.io_Error)        /* TD_GETGEOMETRY not supported */
  312.        {
  313.          memtype = de.de_BufMemType;
  314.          blocksize = de.de_SizeBlock << 2;    /* convert to bytes */
  315.          if (de.de_SectorPerBlock == 0)
  316.            sectorsize = blocksize;
  317.          else
  318.            sectorsize = blocksize / de.de_SectorPerBlock;
  319.        }
  320.        else
  321.        {
  322.          memtype = geo.dg_BufMemType;
  323.          blocksize = de.de_SizeBlock << 2;    /* convert to bytes */
  324.          sectorsize = geo.dg_SectorSize;
  325.        }
  326.  
  327.        if (justinfo)
  328.          if (diskreq->iotd_Req.io_Error)
  329.            devinfo (devname, execdev, &fss, &de, diskreq->iotd_Req.io_Device, NULL);
  330.          else
  331.            devinfo (devname, execdev, &fss, &de, diskreq->iotd_Req.io_Device, &geo);
  332.        else
  333.        {
  334.          /***
  335.           ***  KLUDGE!   (is this really needed?)
  336.           ***/
  337.          if (strcmp (execdev, "trackdisk.device") == 0)
  338.            memtype = MEMF_CHIP;
  339.  
  340.          sectorbuf = AllocMem (sectorsize, memtype);
  341.          if (sectorbuf)
  342.          {
  343.            Inhibit (devname, TRUE);
  344.            Motor (diskreq, ON);
  345.            return diskreq;
  346.          }
  347.        }
  348.        CloseDevice ((struct IORequest *) diskreq);
  349.      }
  350.      DeleteIORequest ((struct IORequest *) diskreq);
  351.    }
  352.    DeleteMsgPort (port);
  353.  }
  354.  
  355.  return NULL;
  356. }
  357.  
  358.  
  359. void closedev (char *devname, struct IOExtTD *diskreq)
  360. {
  361.  if (diskreq && devname)
  362.  {
  363.    struct IORequest *ioreq = (struct IORequest *) diskreq;
  364.  
  365.    if (sectorbuf)
  366.      FreeMem (sectorbuf, sectorsize);
  367.    Motor (diskreq, OFF);
  368.    Inhibit (devname, FALSE);
  369.    CloseDevice (ioreq);
  370.    DeleteMsgPort (ioreq->io_Message.mn_ReplyPort);
  371.    DeleteIORequest (ioreq);
  372.  }
  373. }
  374.  
  375.  
  376. int deverror (long err)
  377. {
  378.  static struct {int code; char *msg;} table[] = {
  379.    {IOERR_OPENFAIL,    "could not open device/unit"},
  380.    {IOERR_NOCMD,    "command not supported"},
  381.    {IOERR_BADLENGTH,    "invalid lenght"},
  382.    {IOERR_BADADDRESS,    "invalid address"},
  383.    {IOERR_UNITBUSY,    "unit in use"},
  384.    {IOERR_SELFTEST,    "hardware failed self-test"},
  385.    {TDERR_NotSpecified,    "unspecified error"},
  386.    {TDERR_NoSecHdr,    "couldn't find sector"},
  387.    {TDERR_BadSecPreamble,    "bad sector preamble"},
  388.    {TDERR_BadSecID,    "bad sector ID"},
  389.    {TDERR_BadHdrSum,    "incorrect header checksum"},
  390.    {TDERR_BadSecSum,    "incorrect sector checksum"},
  391.    {TDERR_TooFewSecs,    "couldn't find enough sectors"},
  392.    {TDERR_BadSecHdr,    "bad sector header"},
  393.    {TDERR_WriteProt,    "disk is write-protected"},
  394.    {TDERR_DiskChanged,    "no disk in drive"},
  395.    {TDERR_SeekError,    "seek error"},
  396.    {TDERR_NoMem,    "out of memory"},
  397.    {TDERR_BadUnitNum,    "bad unit number"},
  398.    {TDERR_BadDriveType,    "bad drive type"},
  399.    {TDERR_DriveInUse,    "drive in use"},
  400.    {0,    ""}
  401.  };
  402.  int i;
  403.  
  404.  for (i = 0; table[i].code; i++)
  405.    if (err == table[i].code)
  406.    {
  407.      Printf ("dd: %s\n", table[i].msg);
  408.      return TRUE;
  409.    }
  410.  
  411.  return FALSE;
  412. }
  413.