/**********************************************************************/
/*                                                                    */
/*          SupraDirect.c                                             */
/*                                                                    */
/*          For the Amiga                                             */
/*          Series II                                                 */
/*          Version 1.09                                              */
/*          January 5, 1990                                           */
/*                                                                    */
/*          SUPRA CORPORATION                                         */
/*          by Clark A. Stevens                                       */
/*                                                                    */
/*          (c) 1988,1989,1990                                        */
/*                                                                    */
/**********************************************************************/

/**********************************************************************/
/*                                                                    */
/*  Copyright 1988,89,90  Clark A. Stevens & Supra Corporation        */
/*                                                                    */
/*  All Rights Reserved                                               */
/*                                                                    */
/*  The files and information contained in this file may not be       */
/*  transmitted, transcribed, translated, or reproduced in any form.  */
/*                                                                    */
/**********************************************************************/

/**********************************************************************/
/*                                                                    */
/*                 DISCLAIMER                                         */
/*                                                                    */
/*  THE INFORMATION CONTAINED HEREIN IS SUBJECT TO CHANGE WITHOUT     */
/*  NOTICE AND IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,     */
/*  EITHER EXPRESS OR IMPLIED.  SUPRA MAKES NO REPRESENTATIONS AS TO  */
/*  THE ACCURACY, RELIABILITY, OR CURRENTNESS OF THIS INFORMATION,    */
/*  AND THE ENTIRE RISK AS TO THE USE OF THIS INFORMATION IS ASSUMED  */
/*  BY THE USER.                                                      */
/*                                                                    */
/**********************************************************************/

/**********************************************************************/
/*  A special note regarding this code.                               */
/*                                                                    */
/*  This code was written with tabs set to 4 on a screen running      */
/*  overscan.  If the format of the code looks weird to you, try      */
/*  those settings.                                                   */
/*                                                                    */
/*  This code is in an on going state of refinement.  As such, there  */
/*  are many features that aren't included yet, mostly because so     */
/*  far there hasn't been a need for them.  Currently, the most       */
/*  apparent place this code may be found lacking, is that it only    */
/*  supports one open device at a time.  However, a little            */
/*  reorganization could have this code working easily with handles.  */
/*                                                                    */
/*  This code uses printf for error messages and is written to be run */
/*  from the CLI environment.  Requesters should be substituted for   */
/*  programs running from Workbench.                                  */
/*                                                                    */
/*  This code was compiled using Manx 3.6a without any special        */
/*  compiler options and linked with the standard library ( -lc ).    */
/*  Lattice should also work worrying about integer size, as there    */
/*  are no int declarations in this code.                             */
/*                                                                    */
/*  Finally, note that this code does nothing, useful or otherwise.   */
/*  The user must supply main() and any other routines necessary to   */
/*  accomplish a worthwhile task.  The routines that follow can be    */
/*  used to get some of the grunt work done.                          */
/*                                                                    */
/**********************************************************************/

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/io.h>
#include <devices/scsidisk.h>

#ifdef LATTICE
#include <proto/exec.h>
#include <proto/expansion.h>
#endif

#include <stdio.h>

#ifdef AZTEC_C
#include <functions.h>
#endif

#include "SupraDirect.h"

struct  ScsiCmdBlock    sCMD = {0,0,0,0,0,0};
struct  SCSICmd         ScsiCmd;                /* Refer to scsidisk.h */
struct  MsgPort         *SupMntPort = NULL;
struct  IOStdReq        *Req = NULL;

LONG    NotOpenFlag = TRUE;

struct  ExpansionBase *ExpansionBase;



/*  Find and return product ID of a Supra interface, else return FALSE. */
LONG
GetProductNum()
{
    struct ConfigDev *cd = NULL;

    if(cd = FindConfigDev(cd, 1056L, IF_BYTESYNC))       /* Current A500 IF */
        return(IF_BYTESYNC);
    if(cd = FindConfigDev(cd, 1056L, IF_WORDSYNC))       /* Current A2000 I/F */
        return(IF_WORDSYNC);
    if(cd = FindConfigDev(cd, 1056L, IF_AB500))          /* 1st A500 autoboot I/F */
        return(IF_AB500);
    if(cd = FindConfigDev(cd, 1056L, IF_DMA))            /* original A2000 I/F */
        return(IF_DMA);
    if(cd = FindConfigDev(cd, 1056L, IF_A1_A5))          /* original A1000/A500 I/F */
        return(IF_A1_A5);
    return(FALSE);
}


/*  First, call this to see if we even need to bother with any of our other code. */
LONG
Get_IF_ID()
{
    LONG    product;
    ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library", 0L);
    if (ExpansionBase == NULL)
        return(50);
    product = GetProductNum();
    CloseLibrary(ExpansionBase);
    return(product);
}


/*  NOTE:  Current device driver does not support multiple Supra interfaces.  */
LONG
MakeUnit(scsi,lun)
SHORT    scsi,lun;
{
    return((ULONG)(lun * 10L) + scsi);
}


/*  This is a private routine!  It allows the OpenDevice flags to be changed    */
/*  after the device is up and running.  These flags will not be document,      */
/*  are subject to change, and private to the device driver.  In other words    */
/*  NEVER USE THIS FUNCTION.                                                    */
SHORT
SetDevFlag(flag)
LONG    flag;
{
    Req->io_Command = HD_SETDEVFLAG;
    Req->io_Length = flag;
    DoIO(Req);
    return((SHORT)Req->io_Error);
}


/*  This routine actually gets the work done by calling DoIO */
SHORT
sc_direct(buffer,len,cmd,cnt,rw)
VOID    *buffer;
ULONG   len;
struct  ScsiCmdBlock    *cmd;
UWORD   cnt;
UBYTE   rw;
{
    ScsiCmd.scsi_Data = buffer;
    ScsiCmd.scsi_Length = len;
    ScsiCmd.scsi_Command = (UBYTE *)cmd;
    ScsiCmd.scsi_CmdLength = cnt;
    ScsiCmd.scsi_Flags = rw?SCSIF_READ:SCSIF_WRITE;

    Req->io_Command = HD_SCSICMD;
    Req->io_Data = (APTR)&ScsiCmd;
    Req->io_Length = (ULONG)sizeof(struct SCSICmd);
    DoIO(Req);
    return((SHORT)Req->io_Error);
}


VOID
StandardScsiArgs(sec,length,unit)
LONG sec,unit;
UBYTE length;
{
    sCMD.scb_addrHi = ((unit%100)/10) << 5 | sec >> 16;
    sCMD.scb_addrMd = sec >> 8; 
    sCMD.scb_addrLo = sec; 
    sCMD.scb_argmnt = length;            /* length in sectors, in this case */
    sCMD.scb_vendor = 0;
}


/* mode read */
SHORT
sc_mdread(command,data,length,unit)
LONG    command;
VOID    *data;
SHORT   length;
LONG    unit;
{
    sCMD.scb_command = SCSI_MODE_RD;
    StandardScsiArgs(command,(UBYTE)length,unit);

    return(sc_direct(data,(LONG)length,&sCMD,6,SCSIF_READ));

}


/* gets scsi controller id (inquiry) */
SHORT
sc_idread(data,length,unit)
VOID    *data;
SHORT   length;
LONG    unit;
{
    sCMD.scb_command = SCSI_ID_RD;
    StandardScsiArgs(0L,(UBYTE)length,unit);

    return(sc_direct(data,(LONG)length,&sCMD,6,SCSIF_READ));

}


/* ask if the drive is ready */
SHORT
sc_ready(unit)
LONG    unit;
{
    SHORT   stat;

    sCMD.scb_command = SCSI_READY;             /* Build Command Block */
    sCMD.scb_addrHi = ((unit%100)/10) << 5;    /* lun << 5 */
    sCMD.scb_addrMd = 0; 
    sCMD.scb_addrLo = 0; 
    sCMD.scb_argmnt = 0;
    sCMD.scb_vendor = 0;

    if(stat = sc_direct(NULL,NULL,&sCMD,6,SCSIF_READ))
        stat = sc_direct(NULL,NULL,&sCMD,6,SCSIF_READ);
    return(stat);
}


/*  sc_read -- does the I/O for specified sector(s) and the related data.   */
SHORT
sc_read(sec,data,length,unit)
LONG sec,unit;
VOID *data;
UBYTE length;
{
    sCMD.scb_command = SCSI_READ;
    StandardScsiArgs(sec,length,unit);
    return(sc_direct(data,(LONG)(length*512L),&sCMD,6,SCSIF_READ));
}


/*  sc_write -- does the I/O for specified sector(s) and the related data.  */
SHORT
sc_write(sec,data,length,unit)
LONG  sec,unit;
VOID  *data;
UBYTE length;
{
    sCMD.scb_command = SCSI_WRITE;
    StandardScsiArgs(sec,length,unit);
    return(sc_direct(data,(LONG)(length*512L),&sCMD,6,SCSIF_WRITE));
}


/*  Second, call this routine to make sure that the supradirect.device    */
/*  is available.  This routine is more reliable than doing a lock on     */
/*  devs:supradirect.device because that file is not needed if the user   */
/*  has autobooted.                                                       */
BOOL
FindDirect()
{
    BOOL   stat = FALSE;

    SupMntPort = (struct MsgPort *)CreatePort("Supra_Preme_Port",0L);
    if(SupMntPort)  {
        Req = (struct IOStdReq *)CreateStdIO(SupMntPort);
        if(Req)  {
            if(!OpenDevice("supradirect.device",0L,Req,0L))  {
                CloseDevice(Req);
                stat = TRUE;
            }
            else  {
                printf("ERROR:  Unable to open 'supradirect.device'.\n");
                printf("        Please make sure 'supradirect.device' is in the\n");
                printf("        current devs: directory and try again.\n\n");
            }
            DeleteStdIO(Req);
        }
        DeletePort(SupMntPort);
    }
    return(stat);
}


/*  Call this routine to open a specific unit.  Should eventually return a handle. */
BOOL
InitDirect(unit)
LONG    unit;
{
    SupMntPort = (struct MsgPort *)CreatePort("Supra_Direct",0L);
    if(!SupMntPort)
        printf("ERROR:  Unit %ld could not create port.\n",unit);
    else  {
        Req = (struct IOStdReq *)CreateStdIO(SupMntPort);
        if(!Req)
            printf("ERROR:  Unit %ld could not create standard i/o request.\n",unit);
        else  {
            NotOpenFlag = OpenDevice("supradirect.device",unit,Req,0L);
            if(NotOpenFlag)
                printf("ERROR:  Unit %ld could not open supradirect.device.\n",unit);
            else
                return(TRUE);
        }
    }
    return(FALSE);
}


/*  Call this function when done with device.  Eventually, this function   */
/*  should be passed a handle for the unit.  The unit argument is not      */
/*  presently used.                                                        */
VOID
CleanupDirect(unit)
LONG    unit;
{
    if(NotOpenFlag == FALSE)  {
        CloseDevice(Req);
        NotOpenFlag = TRUE;
    }
    if(Req)  {
        DeleteStdIO(Req);
        Req = NULL;
    }
    if(SupMntPort)  {
        DeletePort(SupMntPort);
        SupMntPort = NULL;
    }
}


