home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * DIO.C
- *
- * (C)Copyright 1987 by Matthew Dillon, All rights reserved
- * Freely distributable. Donations Welcome. This is NOT shareware,
- * This is NOT public domain.
- *
- * Matthew Dillon
- * 891 Regal Rd.
- * Berkeley, Ca. 94708
- *
- * EXEC device driver IO support routines... makes everything easy.
- *
- * dfd = dio_open(name, unit, flags, req/NULL)
- *
- * open an IO device. Note: in some cases you might have to provide
- * a request structure with some fields initialized (example, the
- * console device requires certain fields to be initialized). For
- * instance, if openning the SERIAL.DEVICE, you would want to give
- * an IOExtSer structure which is completely blank execept for the
- * io_SerFlags field.
- *
- * The request structure's message and reply ports need not be
- * initialized. The request structure is no longer needed after
- * the dio_open().
- *
- * NULL = error, else descriptor (a pointer) returned.
- *
- *
- * dio_close(dfd)
- *
- * close an IO device. Any pending asyncronous requests are
- * AbortIO()'d and then Wait'ed on for completion.
- *
- *
- * dio_closegrp(dfd)
- *
- * close EVERY DIO DESCRIPTOR ASSOCIATED WITH THE dio_open() call
- * that was the parent for this descriptor. That is, you can get
- * a descriptor using dio_open(), dio_dup() it a couple of times,
- * then use dio_closegrp() on any ONE of the resulting descriptors
- * to close ALL of them.
- *
- *
- * dio_ddl(dfd,bool)
- *
- * Disable BUF and LEN fields in dio_ctl[_to].. dummy parameters
- * must still be passed, but they are not loaded into the io_Data
- * and io_Length fields of the io request. This is for devices
- * like the AUDIO.DEVICE which has io_Data/io_Length in non-standard
- * places.
- *
- * dio_cact(dfd,bool)
- *
- * If an error occurs (io_Error field), the io_Actual field is usually
- * not modified by the device driver, and thus contains garbage. To
- * provide a cleaner interface, you can have DIO_CTL() and DIO_CTL_TO()
- * calls automatically pre-clear this field so if an io_Error does
- * occur, the field is a definate 0 instead of garbage.
- *
- * In most cases you will want to do this. An exception is the
- * TIMER.DEVICE, which uses the io_Actual field for part of the
- * timeout structure.
- *
- * This flags the particular dio descriptor to do the pre-clear, and
- * any new descriptors obtained by DIO_DUP()ing this one will also
- * have the pre-clear flag set.
- *
- *
- * dio_dup(dfd)
- *
- * Returns a new channel descriptor referencing the same device.
- * The new descriptor has it's own signal and IO request structure.
- * For instance, if you openned the serial device, you might want
- * to dup the descriptor so you can use one channel to pend an
- * asyncronous read, and the other channel to write out to the device
- * and do other things without disturbing the asyncronous read.
- *
- *
- * sig = dio_signal(dfd)
- *
- * get the signal number (0..31) used for a DIO descriptor.
- * This allows you to Wait() for asyncronous requests. Note that
- * if your Wait() returns, you should double check using dio_isdone()
- *
- * dio_flags(dfd, or, ~and)
- *
- * Modify the io_Flags field in the request, ORing it with the OR
- * mask, and ANDing it with ~AND mask. E.G., the AUDIO.DEVICE requires
- * some flags be put in io_Flags.
- *
- * req = dio_ctl_to(dfd, command, buf, len, to)
- *
- * Same as DIO_CTL() below, but (A) is always syncronous, and
- * (B) will attempt to AbortIO()+WaitIO() the request if the
- * timeout occurs before the IO completes.
- *
- * the 'to' argument is in microseconds.
- *
- * If timeout occurs before request completes, and DIO aborts the
- * request, some devices do not have the io_Actual field set
- * properly.
- *
- * req = dio_ctl(dfd, command, buf, len)
- *
- * DIO_CTL() is the basis for the entire library. It works as follows:
- *
- * (1) If the channel isn't clear (there is an asyncronous IO request
- * still pending), DIO_CTL() waits for it to complete
- *
- * (2) If the command is 0, simply return a pointer to the io
- * request structure.
- *
- * (3) If the DIO_CACT() flag is TRUE, the io_Actual field of the
- * request is cleared.
- *
- * (4) Set the io_Data field to 'buf', and io_Length field to 'len'
- * If the command is positive, use DoIO(). If the command
- * negative, take it's absolute value and then do a SendIO().
- * (The command is placed in the io_Command field, of course).
- *
- * (5) return the IO request structure
- *
- *
- * bool= dio_isdone(dfd)
- *
- * return 1 if current channel is clear (done processing), else 0.
- * e.g. if you did, say, an asyncronous read, and dio_isdone() returns
- * true, you can now use the data buffer returned and look at the
- * io_Actual field.
- *
- * You need not do a dio_wait() after dio_isdone() returns 1.
- *
- *
- * req = dio_wait(dfd)
- *
- * Wait on the current channel for the request to complete and
- * then return the request structure. (nop if channel is clear)
- *
- *
- * req = dio_abort(dfd)
- *
- * Abort the request on the current channel (nop if channel is
- * clear). Sends an AbortIO() if the channel is active and then
- * WaitIO()'s the request.
- *
- *
- * MACROS: SEE DIO.H
- *
- */
-
- #include <exec/types.h>
- #include <exec/io.h>
- #include <exec/memory.h>
- #include <exec/ports.h>
- #include <devices/timer.h>
- #include <local/xmisc.h>
-
- #define MPC (MEMF_CLEAR|MEMF_PUBLIC)
- #define CPORT ior.ior.io_Message.mn_ReplyPort
- #define MAXREQSIZE 128 /* big enough to hold all Amiga iorequests */
-
- typedef struct IORequest IOR;
- typedef struct IOStdReq STD;
- typedef struct MsgPort PORT;
-
- typedef struct {
- STD ior;
- char filler[MAXREQSIZE-sizeof(STD)];
- } MAXIOR;
-
- typedef struct {
- struct _CHAN *list;
- short refs;
- } DIO;
-
- typedef struct _CHAN {
- MAXIOR ior;
- DIO *base;
- XLIST link; /* doubly linked list */
- STD timer;
- char notclear;
- char cact; /* automatic io_Actual field clear */
- char ddl;
- UBYTE flagmask;
- } CHAN;
-
- extern CHAN *dio_ctl(), *dio_ctl_to(), *dio_wait(), *dio_abort();
- extern PORT *CreatePort();
- extern char *AllocMem();
-
- CHAN *
- dio_open(name, unit, flags, req)
- char *name;
- MAXIOR *req; /* not really this big */
- {
- register CHAN *chan;
- register DIO *dio;
- register PORT *port;
- int ret;
-
- dio = (DIO *)AllocMem(sizeof(DIO), MPC); if (!dio) goto fail3;
- chan= (CHAN *)AllocMem(sizeof(CHAN), MPC); if (!chan) goto fail2;
- if (req)
- chan->ior = *req;
- chan->CPORT = CreatePort(NULL,0); if (!chan->CPORT) goto fail1;
- chan->ior.ior.io_Message.mn_Node.ln_Type = NT_MESSAGE;
- chan->base = dio;
- chan->flagmask = 0xF0;
- dio->refs = 1;
- if (OpenDevice(name, unit, &chan->ior, flags)) {
- DeletePort(chan->CPORT);
- fail1: FreeMem(chan, sizeof(CHAN));
- fail2: FreeMem(dio, sizeof(DIO));
- fail3: return(NULL);
- }
- llink(&dio->list, &chan->link);
- chan->ior.ior.io_Flags = 0;
- return(chan);
- }
-
- void
- dio_dfm(chan,mask)
- CHAN *chan;
- {
- chan->flagmask = mask;
- }
-
- void
- dio_ddl(chan,n)
- CHAN *chan;
- {
- chan->ddl = n;
- }
-
- void
- dio_cact(chan,n)
- CHAN *chan;
- {
- chan->cact = n;
- }
-
- void
- dio_close(chan)
- register CHAN *chan;
- {
- dio_abort(chan);
- lunlink(&chan->link);
- if (--chan->base->refs == 0) {
- FreeMem(chan->base, sizeof(DIO));
- CloseDevice(&chan->ior);
- }
- if (chan->timer.io_Message.mn_ReplyPort)
- CloseDevice(&chan->timer);
- DeletePort(chan->CPORT);
- FreeMem(chan, sizeof(CHAN));
- }
-
- void
- dio_closegroup(chan)
- register CHAN *chan;
- {
- register CHAN *nextc;
-
- for (chan = chan->base->list; chan; chan = nextc) {
- chan = (CHAN *)((char *)chan - ((char *)&chan->link - (char *)chan));
- nextc = (CHAN *)chan->link.next;
- dio_close(chan);
- }
- }
-
-
- CHAN *
- dio_dup(chan)
- register CHAN *chan;
- {
- register CHAN *nc;
-
- if (chan) {
- nc = (CHAN *)AllocMem(sizeof(CHAN), MPC); if (!nc) goto fail2;
- nc->ior = chan->ior;
- nc->base = chan->base;
- nc->CPORT = CreatePort(NULL,0); if (!nc->CPORT) goto fail1;
- nc->ior.ior.io_Flags = NULL;
- nc->cact = chan->cact;
- nc->ddl = chan->ddl;
- nc->flagmask = chan->flagmask;
- ++nc->base->refs;
- llink(&nc->base->list, &nc->link);
- return(nc);
- fail1: FreeMem(nc, sizeof(CHAN));
- }
- fail2:
- return(NULL);
- }
-
- dio_signal(chan)
- CHAN *chan;
- {
- return(chan->CPORT->mp_SigBit);
- }
-
- dio_flags(chan,or,and)
- long chan;
- {
- IOR *ior = (void *)chan;
-
- ior->io_Flags = (ior->io_Flags | or) & ~and;
- }
-
-
- CHAN *
- dio_ctl_to(chan, com, buf, len, to)
- register CHAN *chan;
- char *buf;
- {
- register long mask;
-
- if (chan->timer.io_Message.mn_ReplyPort == NULL) {
- chan->timer.io_Message.mn_ReplyPort = chan->CPORT;
- chan->timer.io_Message.mn_Node.ln_Type = NT_MESSAGE;
- if (OpenDevice("timer.device", UNIT_VBLANK, &chan->timer, 0)) {
- puts("Panic: DIO_CTL_TO: No timer.device");
- }
- chan->timer.io_Command = TR_ADDREQUEST;
- }
- mask = 1 << chan->CPORT->mp_SigBit;
- dio_ctl(chan, (com>0)?-com:com, buf, len); /* SendIO the request */
- chan->timer.io_Actual = to / 1000000;
- chan->timer.io_Length = to % 1000000; /* setup timer */
- chan->timer.io_Flags = 0;
- BeginIO(&chan->timer); /* start timer running */
- while (Wait(mask)) { /* Wait for something */
- if (CheckIO(chan)) /* request done */
- break;
- if (CheckIO(&chan->timer)) { /* timeout? */
- dio_abort(chan);
- break;
- }
- }
- AbortIO(&chan->timer); /* kill the timer */
- WaitIO(&chan->timer); /* remove from rp */
- return(chan); /* return ior */
- }
-
-
- CHAN *
- dio_ctl(chan, com, buf, len)
- register CHAN *chan;
- char *buf;
- {
- if (chan->notclear) { /* wait previous req to finish */
- WaitIO(chan);
- chan->notclear = 0;
- }
- if (com) {
- if (chan->cact)
- chan->ior.ior.io_Actual = 0; /* initialize io_Actual to 0*/
- chan->ior.ior.io_Error = 0; /* initialize error to 0 */
- if (!chan->ddl) {
- chan->ior.ior.io_Data = (APTR)buf; /* buffer */
- chan->ior.ior.io_Length = len; /* length */
- }
- if (com < 0) { /* asyncronous IO */
- chan->ior.ior.io_Command = -com;
- chan->notclear = 1;
- chan->ior.ior.io_Flags &= chan->flagmask;
- BeginIO(chan);
- } else { /* syncronous IO */
- chan->ior.ior.io_Command = com;
- chan->ior.ior.io_Flags = (chan->ior.ior.io_Flags & chan->flagmask) | IOF_QUICK;
- BeginIO(chan);
- if (!(chan->ior.ior.io_Flags & IOF_QUICK))
- WaitIO(chan);
- }
- }
- return(chan);
- }
-
-
- CHAN *
- dio_isdone(chan)
- register CHAN *chan;
- {
- if (chan->notclear) { /* if not clear */
- if (CheckIO(chan)) { /* if done */
- WaitIO(chan); /* clear */
- chan->notclear = 0;
- return(chan); /* done */
- }
- return(NULL); /* notdone */
- }
- return(chan); /* done */
- }
-
-
- CHAN *
- dio_wait(chan)
- register CHAN *chan;
- {
- if (chan->notclear) {
- WaitIO(chan); /* wait and remove from rp */
- chan->notclear = 0;
- }
- return(chan);
- }
-
-
- CHAN *
- dio_abort(chan)
- register CHAN *chan;
- {
- if (chan->notclear) {
- AbortIO(chan); /* Abort it */
- WaitIO(chan); /* wait and remove from rp */
- chan->notclear = 0;
- }
- return(chan);
- }
-
-
-