home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 1
/
GoldFishApril1994_CD1.img
/
d1xx
/
d169
/
src
/
suplib
/
dio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-11-22
|
11KB
|
423 lines
/*
* 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);
}