/**
***  IPDial     Script program for initializing a SLIP connection
***  Copyright  (C)   1994    Jochen Wiedmann
***
***  This program is free software; you can redistribute it and/or modify
***  it under the terms of the GNU General Public License as published by
***  the Free Software Foundation; either version 2 of the License, or
***  (at your option) any later version.
***
***  This program is distributed in the hope that it will be useful,
***  but WITHOUT ANY WARRANTY; without even the implied warranty of
***  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
***  GNU General Public License for more details.
***
***  You should have received a copy of the GNU General Public License
***  along with this program; if not, write to the Free Software
***  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
***
***
***
***  This file implements something like a device class. It's only
***  reason is the lack of a possibility to determine the real state
***  of an IORequest. (Sent? Inactive? Whatever else?)
***
***
***  Computer: Amiga 1200                       Compiler: Dice 3.01
***
***  Author:    Jochen Wiedmann
***             Am Eisteich 9
***             72555 Metzingen
***             Germany
***
***             Phone: (+0049) 7123 / 14881
***             Internet: jochen.wiedmann@zdv.uni-tuebingen.de
**/





/**
***  Include files
**/
#ifndef IPDIAL_H
#include "IPDial.h"
#endif
#include <exec/devices.h>
#include <exec/io.h>





/**
***  We use the structure below for device IO, because I don't see
***  any way to check an IORequest whether it must be aborted, before
***  using or deleting it.
**/
struct MyIORequest
{ ULONG Used;
  ULONG Signal;
  ULONG DeviceOpen;
  struct IORequest *Req;
};





/**
***  This is the WaitIO() equivalent.
**/
BYTE DeviceIOWait(APTR wreq)

{ struct MyIORequest *req = wreq;
  BYTE result;

  result = WaitIO(req->Req);
  req->Used = FALSE;
  return(result);
}





/**
***  This is the AbortIO() equivalent.
**/
VOID DeviceIOAbort(APTR areq)

{ struct MyIORequest *req = areq;

  if (req  &&  req->Used  &&  req->Req)
  { AbortIO(req->Req);
    DeviceIOWait(req);
  }
  /**
  ***  The following is needed for reasons I don't understand
  ***  really.
  **/
  SetSignal(0, req->Signal);
}





/**
***  This is the SendIO() equivalent.
**/
VOID DeviceIOSend(APTR sreq, UWORD Command)

{ struct MyIORequest *req = sreq;

  if (req->Used)
  { fprintf(stderr, "Internal error: IORequest in use.\n");
    exit(20);
  }
  req->Used = TRUE;
  req->Req->io_Command = Command;
  SendIO(req->Req);
}





/**
***  This is the DoIO() equivalent.
**/
BYTE DeviceIODo(APTR dreq, UWORD Command)

{ struct MyIORequest *req = dreq;

  if (req->Used)
  { fprintf(stderr, "Internal error: IORequest in use.\n");
    exit(20);
  }
  req->Req->io_Command = Command;
  return(DoIO(req->Req));
}





/**
***  This is the DeleteIORequest() equivalent.
**/
VOID DeviceIODelete(APTR dreq)

{ struct MyIORequest *req = dreq;

  if (req)
  { DeviceIOAbort(req);
    if (req->DeviceOpen)
    { CloseDevice(req->Req);
    }
    if (req->Req)
    { struct MsgPort *port = req->Req->io_Message.mn_ReplyPort;

      DeleteIORequest(req->Req);
      DeleteMsgPort(port);
    }
    free(req);
  }
}





/**
***  This is the CreateIORequest() equivalent.
**/
APTR DeviceIOCreate(ULONG Size)

{ struct MyIORequest *req;

  if ((req = malloc(sizeof(*req))))
  { struct MsgPort *port;

    req->Used = FALSE;
    req->DeviceOpen = FALSE;
    if ((port = CreateMsgPort()))
    { req->Signal = (1 << port->mp_SigBit);
      if ((req->Req = CreateIORequest(port, Size)))
      { return(req);
      }
      DeleteMsgPort(port);
    }
    free(req);
  }
  return(NULL);
}





/**
***  This is the OpenDevice() equivalent.
**/
BYTE DeviceIOOpen(STRPTR devname,
		  ULONG unit,
		  APTR oreq,
		  ULONG flags)

{ struct MyIORequest *req = oreq;
  BYTE error;

  if (req->DeviceOpen)
  { fprintf(stderr, "Internal error: Device already open.\n");
    exit(20);
  }
  if (!(error = OpenDevice(devname, unit, req->Req, flags)))
  { req->DeviceOpen = TRUE;
  }
  return(error);
}





/**
***  This function returns the IORequest attached to a struct
***  MyIORequest.
**/
struct IORequest *DeviceIOReq(APTR rreq)

{ return(((struct MyIORequest *)rreq)->Req);
}





/**
***  This function returns an IORequest's signal. (Not the
***  signal number.)
**/
ULONG DeviceIOSignal(APTR sreq)

{ return(((struct MyIORequest *) sreq)->Signal);
}
