[net.micro.amiga] C support routines for devices ... make things easy.

dillon@CORY.BERKELEY.EDU (Matt Dillon) (05/22/86)

	I've gotten sick and tired of the number of things one must do to
open a device, so I wrote the following routines.  With one call, and
no previous initialization, allocation, or other assorted crap, you can
get one or two io-request structures for any device.

	Well, it isn't quite that easy... you still need to #include the
correct files to get the structure definitions, but.....

	In any case, it's made my life a lot easier.  I'm interested in
feedback.  I've included a huge comment to try to explain how it works.
Once you understand, it's a surprisingly simple call.

				Enjoy,

				-Matt


/*
 * IO.C           (should be compiled w/ 32-bit ints)
 *
 *			Matthew Dillon,   Completely Public Domain (you
 * don't even have to include these comments or anything.  Gee.)
 *
 * I/O support for devices.
 *  io_open()        - Generalized OpenDevice() which does everything for
 *                     you.
 *
 *  io_close()       - Generalized CloseDevice().  Should only be used
 *                     with io_open()'d devices.
 *
 *  long
 *  io_open(device_name, unit, flags, &rreq, &wwreq, req_size, spec1, spec2)
 *
 *    char *device_name          -the device name (ex: "serial.device")
 *    int   unit                 -unit #
 *    int   flags                -OpenDevice flags
 *    struct IOxxxxxx *rreq      -address of pointer (will be filled in)
 *    struct IOxxxxxx *wreq      -address of pointer (will be filled in)
 *    int   req_size             -size of above structures
 *    long  spec1,spec2          -special arguments for preinitialization
 *                                 (depends on the device your openning)
 *
 *    EXAMPLE:
 *    ----------------------
 *    typedef struct IOExtSer SIO;
 *
 *    #define SERFLAGS (SERF_XDISABLED | SERF_SHARED)
 *    SIO *srr, *swr;
 *    long mask;
 *
 *    mask = io_open("serial.device",0,0,&srr,&swr,sizeof(SIO),SERFLAGS,0);
 *		      .
 *		do stuff w/ srr and swr.
 *		      .
 *    io_close(srr, swr, sizeof(SIO));
 *
 *    ----------------------
 *
 *    The structure for rreq and wreq depend on the device you are openning.
 *    You must be sure to specify the correct size.
 *
 *    Some devices, such as the serial device, require certain fields inside
 *    their IO structures to be initialized before the OpenDevice().  Since
 *    io_open() Allocates these structures for you, these extra parameters
 *    must be passed to io_open() via SPEC1 and SPEC2 in the arguments list
 *    as outlined below:
 *                     SPEC1              SPEC2
 *    console.device   window pointer     window structure size
 *    parallel.device  parallel flags     0
 *    serial.device    serial flags       0
 *    **ALL OTHERS**   0                  0
 *
 *    note on audio device:  You must ADCMD_ALLOCATE and ADCMD_FREE
 *    manually.
 *
 *    You also pass io_open() the address of two pointers (e.g. **x).  These
 *    will be filled in by io_open() to result in a READ and WRITE request
 *    structure, each with it's own reply port, and with it's io_Command
 *    fields initialized to CMD_READ and CMD_WRITE, respectively.  You may
 *    specify a NULL for the **WRITE request structure instead of a
 *    **wreq.  This will result in only a READ request structure being
 *    set up.
 *
 *    You do not have to use the structures for only CMD_READ and CMD_WRITE,
 *    of course, you can use them for any io command.
 *
 *    a signal MASK with one bit set is returned.  This is the signal bit
 *    for the read-request structure (if rreq was NULL, then it is the
 *    signal for the write-request structure).  an example mask:
 *     00000000001000000000000000000000 in binary.
 *
 *    0 is returned if the open fails.
 *
 *
 *  io_close(rreq, wreq, size)
 *
 *       specify NULL for the wreq if it doesn't exist (e.g. you passed a
 *       NULL for it in the io_open() ).
 */

#include <exec/types.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <devices/serial.h>
#include <devices/parallel.h>

#define FAIL(ifzero) if (!ifzero) goto fail

typedef struct IORequest IOR;
typedef struct IOStdReq  STD;
typedef struct MsgPort   PORT;

extern char *AllocMem();
extern PORT *CreatePort();

long
io_open(name, unit, od_arg, prr, pww, size, special1, special2)
char *name;
IOR **prr, **pww;
long special1, special2;
{
   PORT  *rport, *wport;
   IOR   *rreq, *wreq;
   int ret;

   rreq  = wreq  = NULL;
   rport = wport = NULL;

   rport = CreatePort(NULL,0);                              FAIL(rport);
   rreq = (IOR *)AllocMem(size, MEMF_PUBLIC|MEMF_CLEAR);    FAIL(rreq);
   if (pww) {
      wport = CreatePort(NULL,0);                           FAIL(wport);
      wreq = (IOR *)AllocMem(size, MEMF_PUBLIC|MEMF_CLEAR); FAIL(wreq);
   }

   if (special1) {
      if (scmp(name, SERIALNAME))
         ((struct IOExtSer *)rreq)->io_SerFlags = special1;
      if (scmp(name, PARALLELNAME))
         ((struct IOExtPar *)rreq)->io_ParFlags = special1;
      if (scmp(name, "console.device")) {
         ((STD *)rreq)->io_Data  = (APTR)special1;
         ((STD *)rreq)->io_Length= special2;
      }
   }

   rreq->io_Message.mn_ReplyPort = rport;
   ret = OpenDevice(name, unit, rreq, od_arg);           FAIL(!ret);

   if (pww) {
      *wreq = *rreq;                         /* structure assignment   */
      wreq->io_Message.mn_ReplyPort = wport;
      wreq->io_Command = CMD_WRITE;
      *pww = wreq;
   }
   rreq->io_Command = CMD_READ;
   *prr = rreq;

   return (1 << rport->mp_SigBit);           /* return read sig bit    */
fail:
   if (rport)  DeletePort(rport);
   if (wport)  DeletePort(wport);
   if (rreq)   FreeMem(rreq, size);
   if (wreq)   FreeMem(wreq, size);
   return (0);
}


io_close(rreq, wreq, size)
IOR *rreq, *wreq;
{
   if (rreq) {
      CloseDevice(rreq);
      if (rreq->io_Message.mn_ReplyPort)
         DeletePort(rreq->io_Message.mn_ReplyPort);
      FreeMem (rreq, size);
   }
   if (wreq) {
      if (wreq->io_Message.mn_ReplyPort)
         DeletePort(wreq->io_Message.mn_ReplyPort);
      FreeMem (wreq, size);
   }
}


scmp(s1, s2)
register char *s1, *s2;
{
   while (*s1 == *s2) {
      if ((*s1 | *s2) == 0)
         return (1);
      ++s1; ++s2;
   }
   return (0);
}