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

#include <proto/exec.h>

#include <stdio.h>
#include <string.h>
#include <signal.h>

#include <scanner.h>
#include "scsi.h"

#define BUFSIZE 256

struct IOStdReq* SCSIReq;       /* a standard IORequest structure */
struct SCSICmd   Cmd;           /* where the actual SCSI command goes */
UBYTE  Sense[20];               /* buffer for request sense data */


int openScannerDevice(char* dname,int unit)
{
  struct MsgPort *Port;

  if( Port = CreateMsgPort() )
  {
    if( SCSIReq = (struct IOStdReq*)CreateIORequest(Port,sizeof(struct IOStdReq)) )
    {
      if( OpenDevice( dname, unit, (struct IORequest *)SCSIReq, 0) )
      {
        DeleteIORequest(SCSIReq);
        DeleteMsgPort(Port);
        SCSIReq = NULL;
      }
    }
    else
      DeleteMsgPort(Port);
  }
  
  return( SCSIReq != NULL);
}

void closeScannerDevice(void)
{
  if( SCSIReq )
  {
    struct MsgPort *Port;

    Port = SCSIReq->io_Message.mn_ReplyPort;
    CloseDevice( (struct IORequest *)SCSIReq );
    DeleteIORequest(SCSIReq);
    DeleteMsgPort(Port);
    SCSIReq = NULL;
  }
}

/*-------------------------------------------------------------------------*/
/* int sendCommand()                                                       */
/* Assembles the command packet to be sent to the SCSI device from the     */
/* specified SCSI command and data, writes it, and reads the reply. If a   */
/* reply size and buffer is specified, the reply data is copied into that  */
/* buffer.                                                                 */
/* The sense data is copied to scsi_sensebuffer.                           */
/* Return: RET_SUCCESS if successful, RET_FAIL if errors occured.          */
/*-------------------------------------------------------------------------*/
int sendCommand(unsigned char *scsi_cmd,int cmd_len,
                unsigned char *scsi_data,  int data_size,
                unsigned char *scsi_reply, int reply_size)
{

  SCSIReq->io_Length  = sizeof(struct SCSICmd);
  SCSIReq->io_Data    = (APTR)&Cmd;
  SCSIReq->io_Command = HD_SCSICMD;        /* the command we are sending   */

  if( scsi_data )
  {
    Cmd.scsi_Data = (UWORD *)scsi_data;          /* The data to write      */
    Cmd.scsi_Length = (data_size+1)&0xFFFFFFFE;  /* How much we will write */
    Cmd.scsi_Flags = SCSIF_AUTOSENSE|SCSIF_WRITE; 
  }
  else if( scsi_reply )
  {
    Cmd.scsi_Data = (UWORD *)scsi_reply;         /* Read buffer             */
    Cmd.scsi_Length = (reply_size+1)&0xFFFFFFFE; /* How much we will accept */
    Cmd.scsi_Flags = SCSIF_AUTOSENSE|SCSIF_READ; 
  }                                        
  else
  {
    Cmd.scsi_Data = NULL;                /* where we put mode sense data */
    Cmd.scsi_Length = 0;                 /* how much we will accept      */
    Cmd.scsi_Flags = SCSIF_AUTOSENSE; 
  }                                      /* set expected data direction  */
  Cmd.scsi_SenseData =(UBYTE *)Sense;    /* where sense data will go     */
  Cmd.scsi_SenseLength = 16;             /* how much we will accept      */
  Cmd.scsi_SenseActual = 0;              /* how much has been received   */
  Cmd.scsi_Status = 0;

  Cmd.scsi_Command = scsi_cmd;           /* issuing a MODE_SENSE command */
  Cmd.scsi_CmdLength = cmd_len;          /* length of the command        */
  DoIO( (struct IORequest *)SCSIReq );   /* send it to the device driver */

  if( Cmd.scsi_Status )
  {
    switch( Sense[0] )
    {
      case 0x00:  // ????
        return SCAN_ERR_READY;
      case 0x81:  // Command or data error
      case 0x83:  // Operation error (illegal parameter values)
        return SCAN_ERR_PARAMETER;
      case 0x82:  // Hardware error
        return SCAN_ERR_HARDWARE;
      default:    // Other communication error
        return SCAN_ERR_COMMUNICATION;
    }
  }
  else
    return 0;
}
