home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_progs / prog_c / suplib.lzh / SUPLIB / SRC / DIO.C < prev    next >
C/C++ Source or Header  |  1991-08-16  |  11KB  |  437 lines

  1.  
  2. /*
  3.  *  DIO.C
  4.  *
  5.  *  (C)Copyright 1987 by Matthew Dillon, All rights reserved
  6.  *  Freely distributable.  Donations Welcome.  This is NOT shareware,
  7.  *  This is NOT public domain.
  8.  *
  9.  *    Matthew Dillon
  10.  *    891 Regal Rd.
  11.  *    Berkeley, Ca. 94708
  12.  *
  13.  *  EXEC device driver IO support routines... makes everything easy.
  14.  *
  15.  *  dfd = dio_open(name, unit, flags, req/NULL)
  16.  *
  17.  *    open an IO device.  Note: in some cases you might have to provide
  18.  *    a request structure with some fields initialized (example, the
  19.  *    console device requires certain fields to be initialized).  For
  20.  *    instance, if openning the SERIAL.DEVICE, you would want to give
  21.  *    an IOExtSer structure which is completely blank execept for the
  22.  *    io_SerFlags field.
  23.  *
  24.  *    The request structure's message and reply ports need not be
  25.  *    initialized.  The request structure is no longer needed after
  26.  *    the dio_open().
  27.  *
  28.  *    NULL = error, else descriptor (a pointer) returned.
  29.  *
  30.  *
  31.  *  dio_close(dfd)
  32.  *
  33.  *    close an IO device.  Any pending asyncronous requests are
  34.  *    AbortIO()'d and then Wait'ed on for completion.
  35.  *
  36.  *
  37.  *  dio_closegrp(dfd)
  38.  *
  39.  *    close EVERY DIO DESCRIPTOR ASSOCIATED WITH THE dio_open() call
  40.  *    that was the parent for this descriptor.  That is, you can get
  41.  *    a descriptor using dio_open(), dio_dup() it a couple of times,
  42.  *    then use dio_closegrp() on any ONE of the resulting descriptors
  43.  *    to close ALL of them.
  44.  *
  45.  *
  46.  *  dio_ddl(dfd,bool)
  47.  *
  48.  *    Disable BUF and LEN fields in dio_ctl[_to].. dummy parameters
  49.  *    must still be passed, but they are not loaded into the io_Data
  50.  *    and io_Length fields of the io request.  This is for devices
  51.  *    like the AUDIO.DEVICE which has io_Data/io_Length in non-standard
  52.  *    places.
  53.  *
  54.  *  dio_cact(dfd,bool)
  55.  *
  56.  *    If an error occurs (io_Error field), the io_Actual field is usually
  57.  *    not modified by the device driver, and thus contains garbage.  To
  58.  *    provide a cleaner interface, you can have DIO_CTL() and DIO_CTL_TO()
  59.  *    calls automatically pre-clear this field so if an io_Error does
  60.  *    occur, the field is a definate 0 instead of garbage.
  61.  *
  62.  *    In most cases you will want to do this.  An exception is the
  63.  *    TIMER.DEVICE, which uses the io_Actual field for part of the
  64.  *    timeout structure.
  65.  *
  66.  *    This flags the particular dio descriptor to do the pre-clear, and
  67.  *    any new descriptors obtained by DIO_DUP()ing this one will also
  68.  *    have the pre-clear flag set.
  69.  *
  70.  *
  71.  *  dio_dup(dfd)
  72.  *
  73.  *    Returns a new channel descriptor referencing the same device.
  74.  *    The new descriptor has it's own signal and IO request structure.
  75.  *    For instance, if you openned the serial device, you might want
  76.  *    to dup the descriptor so you can use one channel to pend an
  77.  *    asyncronous read, and the other channel to write out to the device
  78.  *    and do other things without disturbing the asyncronous read.
  79.  *
  80.  *
  81.  *  sig = dio_signal(dfd)
  82.  *
  83.  *    get the signal number (0..31) used for a DIO descriptor.
  84.  *    This allows you to Wait() for asyncronous requests.  Note that
  85.  *    if your Wait() returns, you should double check using dio_isdone()
  86.  *
  87.  *      dio_flags(dfd, or, ~and)
  88.  *
  89.  *    Modify the io_Flags field in the request, ORing it with the OR
  90.  *    mask, and ANDing it with ~AND mask.  E.G., the AUDIO.DEVICE requires
  91.  *    some flags be put in io_Flags.
  92.  *
  93.  *  req = dio_ctl_to(dfd, command, buf, len, to)
  94.  *
  95.  *    Same as DIO_CTL() below, but (A) is always syncronous, and
  96.  *    (B) will attempt to AbortIO()+WaitIO() the request if the
  97.  *    timeout occurs before the IO completes.
  98.  *
  99.  *    the 'to' argument is in microseconds.
  100.  *
  101.  *    If timeout occurs before request completes, and DIO aborts the
  102.  *    request, some devices do not have the io_Actual field set
  103.  *    properly.
  104.  *
  105.  *  req = dio_ctl(dfd, command, buf, len)
  106.  *
  107.  *    DIO_CTL() is the basis for the entire library.  It works as follows:
  108.  *
  109.  *    (1) If the channel isn't clear (there is an asyncronous IO request
  110.  *        still pending), DIO_CTL() waits for it to complete
  111.  *
  112.  *    (2) If the command is 0, simply return a pointer to the io
  113.  *        request structure.
  114.  *
  115.  *    (3) If the DIO_CACT() flag is TRUE, the io_Actual field of the
  116.  *        request is cleared.
  117.  *
  118.  *    (4) Set the io_Data field to 'buf', and io_Length field to 'len'
  119.  *        If the command is positive, use DoIO().  If the command
  120.  *        negative, take it's absolute value and then do a SendIO().
  121.  *        (The command is placed in the io_Command field, of course).
  122.  *
  123.  *    (5) return the IO request structure
  124.  *
  125.  *
  126.  *  bool= dio_isdone(dfd)
  127.  *
  128.  *    return 1 if current channel is clear (done processing), else 0.
  129.  *    e.g. if you did, say, an asyncronous read, and dio_isdone() returns
  130.  *    true, you can now use the data buffer returned and look at the
  131.  *    io_Actual field.
  132.  *
  133.  *    You need not do a dio_wait() after dio_isdone() returns 1.
  134.  *
  135.  *
  136.  *  req = dio_wait(dfd)
  137.  *
  138.  *    Wait on the current channel for the request to complete and
  139.  *    then return the request structure. (nop if channel is clear)
  140.  *
  141.  *
  142.  *  req = dio_abort(dfd)
  143.  *
  144.  *    Abort the request on the current channel (nop if channel is
  145.  *    clear).  Sends an AbortIO() if the channel is active and then
  146.  *    WaitIO()'s the request.
  147.  *
  148.  *
  149.  *  MACROS: SEE DIO.H
  150.  *
  151.  */
  152.  
  153. #include <local/typedefs.h>
  154. #include <local/xmisc.h>
  155.  
  156. #define MPC        (MEMF_CLEAR|MEMF_PUBLIC)
  157. #define CPORT        ior.ior.io_Message.mn_ReplyPort
  158. #define MAXREQSIZE  128     /* big enough to hold all Amiga iorequests */
  159.  
  160. typedef struct IORequest IOR;
  161. typedef struct IOStdReq  STD;
  162.  
  163. typedef struct {
  164.     STD ior;
  165.     char filler[MAXREQSIZE-sizeof(STD)];
  166. } MAXIOR;
  167.  
  168. typedef struct {
  169.     struct _CHAN *list;
  170.     short refs;
  171. } DIO;
  172.  
  173. typedef struct _CHAN {
  174.     MAXIOR  ior;
  175.     DIO     *base;
  176.     XLIST   link;    /* doubly linked list */
  177.     STD     timer;
  178.     char    notclear;
  179.     char    cact;    /* automatic io_Actual field clear  */
  180.     char    ddl;
  181.     UBYTE   flagmask;
  182. } CHAN;
  183.  
  184. void *
  185. dio_open(name, unit, flags, _req)
  186. char *name;
  187. long unit, flags;
  188. void *_req;
  189. {
  190.     MAXIOR *req = _req;
  191.     register CHAN *chan;
  192.     register DIO *dio;
  193.  
  194.     dio = (DIO *)AllocMem(sizeof(DIO), MPC);    if (!dio)   goto fail3;
  195.     chan= (CHAN *)AllocMem(sizeof(CHAN), MPC);  if (!chan)   goto fail2;
  196.     if (req)
  197.     chan->ior = *req;
  198.     chan->CPORT = CreatePort(NULL,0);           if (!chan->CPORT) goto fail1;
  199.     chan->ior.ior.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  200.     chan->base = dio;
  201.     chan->flagmask = 0xF0;
  202.     dio->refs = 1;
  203.     if (OpenDevice(name, unit, (IOSTD *)&chan->ior, flags)) {
  204.     DeletePort(chan->CPORT);
  205. fail1:    FreeMem(chan, sizeof(CHAN));
  206. fail2:    FreeMem(dio, sizeof(DIO));
  207. fail3:    return(NULL);
  208.     }
  209.     llink((XLIST **)&dio->list, &chan->link);
  210.     chan->ior.ior.io_Flags = 0;
  211.     return((void *)chan);
  212. }
  213.  
  214. void
  215. dio_dfm(_chan,mask)
  216. void *_chan;
  217. long mask;
  218. {
  219.     CHAN *chan = _chan;
  220.     chan->flagmask = mask;
  221. }
  222.  
  223. void
  224. dio_ddl(_chan,n)
  225. void *_chan;
  226. long n;
  227. {
  228.     CHAN *chan = _chan;
  229.     chan->ddl = n;
  230. }
  231.  
  232. void
  233. dio_cact(_chan,n)
  234. void *_chan;
  235. long n;
  236. {
  237.     CHAN *chan = _chan;
  238.     chan->cact = n;
  239. }
  240.  
  241. void
  242. dio_close(_chan)
  243. void *_chan;
  244. {
  245.     CHAN *chan = _chan;
  246.     dio_abort(chan);
  247.     lunlink(&chan->link);
  248.     if (--chan->base->refs == 0) {
  249.     FreeMem(chan->base, sizeof(DIO));
  250.     CloseDevice((IOSTD *)&chan->ior);
  251.     }
  252.     if (chan->timer.io_Message.mn_ReplyPort)
  253.     CloseDevice((IOSTD *)&chan->timer);
  254.     DeletePort(chan->CPORT);
  255.     FreeMem(chan, sizeof(CHAN));
  256. }
  257.  
  258. void
  259. dio_closegroup(_chan)
  260. void *_chan;
  261. {
  262.     CHAN *chan = _chan;
  263.     register CHAN *nextc;
  264.  
  265.     for (chan = chan->base->list; chan; chan = nextc) {
  266.     chan = (CHAN *)((char *)chan - ((char *)&chan->link - (char *)chan));
  267.     nextc = (CHAN *)chan->link.next;
  268.     dio_close(chan);
  269.     }
  270. }
  271.  
  272. void *
  273. dio_dup(_chan)
  274. void *_chan;
  275. {
  276.     CHAN *chan = _chan;
  277.     CHAN *nc;
  278.  
  279.     if (chan) {
  280.     nc = (CHAN *)AllocMem(sizeof(CHAN), MPC);   if (!nc) goto fail2;
  281.     nc->ior = chan->ior;
  282.     nc->base = chan->base;
  283.     nc->CPORT = CreatePort(NULL,0);         if (!nc->CPORT) goto fail1;
  284.     nc->ior.ior.io_Flags = NULL;
  285.     nc->cact = chan->cact;
  286.     nc->ddl = chan->ddl;
  287.     nc->flagmask = chan->flagmask;
  288.     ++nc->base->refs;
  289.     llink((XLIST **)&nc->base->list, &nc->link);
  290.     return((void *)nc);
  291. fail1:    FreeMem(nc, sizeof(CHAN));
  292.     }
  293. fail2:
  294.     return(NULL);
  295. }
  296.  
  297. int
  298. dio_signal(_chan)
  299. void *_chan;
  300. {
  301.     CHAN *chan = _chan;
  302.     return((int)chan->CPORT->mp_SigBit);
  303. }
  304.  
  305. void
  306. dio_flags(_chan,or,and)
  307. void *_chan;
  308. long or;
  309. long and;
  310. {
  311.     CHAN *chan = _chan;
  312.     IOR *ior = (void *)chan;
  313.  
  314.     ior->io_Flags = (ior->io_Flags | or) & ~and;
  315. }
  316.  
  317.  
  318. void *
  319. dio_ctl_to(_chan, com, buf, len, to)
  320. void *_chan;
  321. long com;
  322. char *buf;
  323. long len, to;
  324. {
  325.     CHAN *chan = _chan;
  326.     register long mask;
  327.  
  328.     if (chan->timer.io_Message.mn_ReplyPort == NULL) {
  329.     chan->timer.io_Message.mn_ReplyPort = chan->CPORT;
  330.     chan->timer.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  331.     if (OpenDevice("timer.device", UNIT_VBLANK, &chan->timer, 0))
  332.         Alert((long)0x44494F20,(char *)1);
  333.     chan->timer.io_Command = TR_ADDREQUEST;
  334.     }
  335.     mask = 1 << chan->CPORT->mp_SigBit;
  336.     dio_ctl(chan, (com>0)?-com:com, buf, len);  /* SendIO the request */
  337.     chan->timer.io_Actual = to / 1000000;
  338.     chan->timer.io_Length = to % 1000000;    /* setup timer          */
  339.     chan->timer.io_Flags = 0;
  340.     BeginIO(&chan->timer);          /* start timer running  */
  341.     while (Wait(mask)) {            /* Wait for something   */
  342.     if (CheckIO((IOSTD *)chan))          /* request done         */
  343.         break;
  344.     if (CheckIO((IOSTD *)&chan->timer)) {    /* timeout?           */
  345.         dio_abort(chan);
  346.         break;
  347.     }
  348.     }
  349.     AbortIO((IOSTD *)&chan->timer);          /*  kill the timer  */
  350.     WaitIO((IOSTD *)&chan->timer);           /*  remove from rp  */
  351.     return((void *)chan);           /*  return ior  */
  352. }
  353.  
  354.  
  355. void *
  356. dio_ctl(_chan, com, buf, len)
  357. void *_chan;
  358. long com;
  359. char *buf;
  360. long len;
  361. {
  362.     CHAN *chan = _chan;
  363.  
  364.     if (chan->notclear) {   /* wait previous req to finish */
  365.     WaitIO((IOSTD *)chan);
  366.     chan->notclear = 0;
  367.     }
  368.     if (com) {
  369.     if (chan->cact)
  370.         chan->ior.ior.io_Actual = 0;    /* initialize io_Actual to 0*/
  371.     chan->ior.ior.io_Error = 0;        /* initialize error to 0 */
  372.     if (!chan->ddl) {
  373.         chan->ior.ior.io_Data = (APTR)buf;  /* buffer   */
  374.         chan->ior.ior.io_Length = len;    /* length   */
  375.     }
  376.     if (com < 0) {                      /* asyncronous IO  */
  377.         chan->ior.ior.io_Command = -com;
  378.         chan->notclear = 1;
  379.         chan->ior.ior.io_Flags &= chan->flagmask;
  380.         BeginIO((IOSTD *)chan);
  381.     } else {                /* syncronous IO  */
  382.         chan->ior.ior.io_Command = com;
  383.         chan->ior.ior.io_Flags = (chan->ior.ior.io_Flags & chan->flagmask) | IOF_QUICK;
  384.         BeginIO((IOSTD *)chan);
  385.         if (!(chan->ior.ior.io_Flags & IOF_QUICK))
  386.         WaitIO((IOSTD *)chan);
  387.     }
  388.     }
  389.     return((void *)chan);
  390. }
  391.  
  392.  
  393. void *
  394. dio_isdone(_chan)
  395. void *_chan;
  396. {
  397.     CHAN *chan = _chan;
  398.     if (chan->notclear) {       /* if not clear */
  399.     if (CheckIO((IOSTD *)chan)) {    /* if done      */
  400.         WaitIO((IOSTD *)chan);       /* clear        */
  401.         chan->notclear = 0;
  402.         return((void *)chan);     /* done         */
  403.     }
  404.     return(NULL);           /* notdone      */
  405.     }
  406.     return((void *)chan);               /* done         */
  407. }
  408.  
  409.  
  410. void *
  411. dio_wait(_chan)
  412. void *_chan;
  413. {
  414.     CHAN *chan = _chan;
  415.     if (chan->notclear) {
  416.     WaitIO((IOSTD *)chan);           /* wait and remove from rp */
  417.     chan->notclear = 0;
  418.     }
  419.     return((void *)chan);
  420. }
  421.  
  422.  
  423. void *
  424. dio_abort(_chan)
  425. void *_chan;
  426. {
  427.     CHAN *chan = _chan;
  428.     if (chan->notclear) {
  429.     AbortIO((IOSTD *)chan);          /* Abort it   */
  430.     WaitIO((IOSTD *)chan);           /* wait and remove from rp */
  431.     chan->notclear = 0;
  432.     }
  433.     return((void *)chan);
  434. }
  435.  
  436.  
  437.