#include <exec/types.h>
#include <exec/io.h>
#include <exec/execbase.h>
#include <libraries/dos.h>
#include <devices/scsidisk.h>

struct   MsgPort        *MyPort;
struct   IOStdReq       *Req;
struct   SCSICmd        SCSIinfo;
UBYTE    CDB[10];
UBYTE    stuff[80];
BPTR     wdw;
int      WB;

extern   struct ExecBase *AbsExecBase;

char  *AvoidNames[] = {
   "audio.device",         /* System devices we want to skip */
   "clipboard.device",
   "console.device",
   "gameport.device",
   "input.device",
   "keyboard.device",
   "parallel.device",
   "printer.device",
   "ramdrive.device",
   "serial.device",
   "timer.device",
   "trackdisk.device",

   "bootdisk.device",      /* Other devices that we don't want */
   "modem0.device",
   "modem1.device",
   "modem2.device",
   "modem3.device",

   "!"                     /* End of list */
};

void main(argc,argv)
int   argc;
char  **argv;
{
   struct   Node *DevNode;
   char     DevName[80];
   int      i,count=0;

   if (argc==0) {       /* Workbench support -- only works w/Lattice 3.03 */
      wdw = Open("CON:0/0/640/200/SCSI test",MODE_NEWFILE);
      if (wdw == NULL) Cleanup(0);
      WB = 1;
   }
   else {
      wdw = Output();
   }

   fprintf(wdw,"\nSCSI-direct test application: SCSI device lister\n");
   fprintf(wdw,"Written by Marty Flickinger\n");
   fprintf(wdw,"Copyright © 1990 Xetec, Inc.\n");

   MyPort = (struct MsgPort *)CreatePort("CDROM_test",0);
   if (!MyPort) Cleanup("Couldn't make port");
   Req = (struct IOStdReq *)CreateStdIO(MyPort);
   if (!Req) Cleanup("Couldn't make IO");

/*   Forbid(); */
   DevNode = AbsExecBase->DeviceList.lh_Head;
   while (DevNode->ln_Succ) {
      strcpy(DevName,DevNode->ln_Name);

      for (i=0;;i++) {
         if (AvoidNames[i][0] == '!') {
            ListDevice(DevName);
            count++;
            break;
         }
         if (!strcmp(AvoidNames[i],DevName))
            break;
      }
      DevNode = DevNode->ln_Succ;
   }
/*   Permit(); */

   if (count==0)
      fprintf(wdw,"\nDidn't find a SCSI hard disk driver\n");

   Cleanup("Done");
}


Cleanup(msg)
char  *msg;
{
   if (wdw)
      fprintf(wdw,"%ls\n",msg);

   if (Req)       DeleteStdIO(Req);
   if (MyPort)    DeletePort(MyPort);
   if ((WB)&&(wdw)) {
      Delay(300);
      Close(wdw);
   }
}


int ListDevice(devname)
char  *devname;
{
   int   stat,unit,act,ver,rev,known=0;
   int   OpenFlag = 1;
   char  *id;

   fprintf(wdw,"\n--- Using \"%ls\" ---\n",devname);

   for (unit=0;unit<7;unit++) {
      fprintf(wdw,"Unit #%ld: ",unit);
      OpenFlag = OpenDevice(devname,unit,Req,0);
      if (!OpenFlag) {
         if (!known) {
            ver = ((struct Library *)Req->io_Device)->lib_Version;
            rev = ((struct Library *)Req->io_Device)->lib_Revision;
            id =  (char *)((struct Library *)Req->io_Device)->lib_IdString;
            known++;
         }
         CDB[0] = 18;      /* Construct an "inquiry" command desc. block */
         CDB[4] = 40;
         CDB[1] = CDB[2] = CDB[3] = CDB[5] = 0;

         SCSIinfo.scsi_Data = (UWORD *)stuff;   /* Where I want the results */
         SCSIinfo.scsi_Length = 40;             /* Max data to return */
         SCSIinfo.scsi_Command = (UBYTE *)&CDB; /* Pointer to my command */
         SCSIinfo.scsi_CmdLength = 6;           /* It's 6 long */
         SCSIinfo.scsi_Flags = SCSIF_READ;      /* Direction = read */

         Req->io_Command = 28;                  /* SCSI direct command */
         Req->io_Data = (APTR)&SCSIinfo;        /* Give custom info */
         Req->io_Length = sizeof(struct SCSICmd);
         DoIO(Req);                             /* Do it! */
         stat = Req->io_Error;
         CloseDevice(Req);

         if (stat==HFERR_SelTimeout)
            fprintf(wdw,"No device\n");
         else if (stat==HFERR_BadStatus)
            fprintf(wdw,"Doesn't support SCSI direct command (28)\n");
         else if (stat)
            fprintf(wdw,"Unknown error\n");
         else {
            act = Req->io_Actual;
            if (act<16)
               act = SCSIinfo.scsi_Actual;

            if (act>15)
               DoString("",&stuff[8],8);
            if (act>31)
               DoString("  ",&stuff[16],16);
            if (act>35)
               DoString("   Rev:",&stuff[32],4);
            fprintf(wdw,"\n");
         }
      }
      else {
         fprintf(wdw,"No unit\n");
      }
   }
   if (known)
      fprintf(wdw,"Device version %ld.%ld --- %ls\n",ver,rev,id);
}


DoString(pre,msg,len)
char  *pre,*msg;
int   len;
{
   char  scratch[80];

   fprintf(wdw,pre);
   strncpy(scratch,msg,len);
   scratch[len] = 0;
   fprintf(wdw,scratch);
}
