home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / DOOG / CTASK.ZIP / TSKPRT.C < prev    next >
C/C++ Source or Header  |  1989-12-21  |  11KB  |  399 lines

  1. /*
  2.     --- Version 2.0 89-12-13 17:40 ---
  3.  
  4.    TSKPRT.C - CTask - Printer interface routines.
  5.  
  6.    Public Domain Software written by
  7.       Thomas Wagner
  8.       Patschkauer Weg 31
  9.       D-1000 Berlin 33
  10.       West Germany
  11.  
  12.    The algorithm for waiting when the printer is busy has been changed
  13.    in version 1.2. In the previous versions, a timed delay was used after
  14.    a certain number of times through the loop. Depending on the kind of
  15.    printer, and the system speed, this could lead to extremely slow
  16.    output. Now a busy waiting loop with scheduling is employed. This
  17.    change will not likely hamper system performance significantly, but
  18.    can speed up printer output processing.
  19.  
  20.    Also new in version 1.2 is the stack switch module, tskprti.asm. The
  21.    interrupt routine is now called through an "envelope" that first
  22.    switches to a local stack.
  23. */
  24.  
  25.  
  26. #include "tsk.h"
  27. #include "prt.h"
  28.  
  29. #define STKSZ     256   /* Printer Task stack size */
  30.  
  31. /*
  32.    The following values may need some tuning for optimum performance.
  33. */
  34. /* 
  35.    MAX_WAIT_xx: Maximum number of times through the loop when waiting
  36.                 for the printer to get ready.
  37. */
  38.  
  39. #define MAX_WAIT_INT    30 /* For interrupt output */
  40. #define MAX_WAIT_POLL   30 /* For polling output */
  41.  
  42. #define INT_TIMEOUT  2L  /* Timeout for ACK interrupt wait */
  43.  
  44.  
  45. typedef void (interrupt far * intprocptr)(void);
  46.  
  47. #define inta00    0x20   /* 8259 interrupt controller control-port */
  48. #define inta01    0x21   /* 8259 interrupt controller mask-port */
  49.  
  50. #define rdserv    0x0b   /* read service register control value */
  51. #define eoi       0x20   /* end of interrupt signal for 8259 */
  52.  
  53. #define data      0x00
  54. #define status    0x01
  55. #define control   0x02
  56.  
  57. #define STROBE    0x01
  58. #define IRQENA    0x10
  59.  
  60. #define dflt_control    (INIT | SELECT)
  61.  
  62.  
  63. /*
  64.    To add support for other LPT-Ports, define
  65.       - Port base
  66.       - IRQ-Bit (optional)
  67.       - Interrupt vector (optional)
  68.    here, add the necessary data to the pr_port_descr array, and, if irq
  69.    was specified, define the corresponding interrupt function by 
  70.    duplicating prtint0, replacing the index into the prt_data array.
  71. */
  72.  
  73. #define PORTS  3              /* Number of defined ports */
  74.  
  75. #define lpt1_base    0x3bc    /* LPT1 port base (mono card) */
  76. #define lpt2_base    0x378    /* LPT2 port base (IBM printer adapter) */
  77. #define lpt3_base    0x278    /* LPT3 port base (secondary parallel) */
  78.  
  79. #define lpt1_irq     0x80     /* IRQ-Bit for LPT1 */
  80. #define lpt2_irq     0x80     /* IRQ-Bit for LPT2 (same as LPT1) */
  81. #define lpt3_irq     0x20     /* IRQ-Bit for LPT3 */
  82.  
  83. #define lpt1_vect    0x0f     /* Interrupt vector for LPT1 */
  84. #define lpt2_vect    0x0f     /* Interrupt vector for LPT2 */
  85. #define lpt3_vect    0x0d     /* Interrupt vector for LPT3 */
  86.  
  87. typedef struct {
  88.                intprocptr  proc;
  89.                int         base;
  90.                byte        irq;
  91.                byte        vector;
  92.                } port_data;
  93.  
  94. extern void interrupt far tskprt_int0 (void);
  95. extern void interrupt far tskprt_int1 (void);
  96. extern void interrupt far tskprt_int2 (void);
  97.  
  98. port_data pr_port_descr [PORTS] = {
  99.                              { tskprt_int0, lpt1_base, lpt1_irq, lpt1_vect },
  100.                              { tskprt_int1, lpt2_base, lpt2_irq, lpt2_vect },
  101.                              { tskprt_int2, lpt3_base, lpt3_irq, lpt3_vect }
  102.                                   };
  103.  
  104. /*-------------------------------------------------------------------------*/
  105.  
  106. typedef struct {
  107.                farptr   savvect;       /* Interrupt vector save location */
  108.                int      port_base;     /* Port base I/O address */
  109.                byte     irqbit;        /* IRQ-Bit for this port */
  110.                byte     civect;        /* Interrupt Vector for this port */
  111.                byte     wait_xmit;     /* Transmit delayed */
  112.                byte     xmit_pending;  /* Transmit in progress */
  113.                byte     polling;       /* Use polling if on */
  114.                     byte        ccontrol;        /* Current control reg */
  115.                pipe     xmit_pipe;     /* Transmit pipe */
  116.                flag     pready;        /* Printer ready flag */
  117.                tcb      pr_task;       /* Printer task */
  118.                byte     pr_stack [STKSZ]; /* Printer task stack */
  119.                } prt_datarec;
  120.  
  121. typedef prt_datarec *prtptr;
  122.  
  123. local prt_datarec prt_data [PORTS];
  124. local int prt_installed [PORTS] = { 0 };
  125.  
  126. extern funcptr prt_remove_func;
  127.  
  128. /*-------------------------------------------------------------------------*/
  129.  
  130.  
  131. void near tsk_prt_int (int port)
  132. {
  133.    prtptr prt = &prt_data [port];
  134.  
  135.    /* Turn off int */
  136.    prt->ccontrol &= ~IRQENA;
  137.    tsk_outp (prt->port_base + control, prt->ccontrol);
  138.  
  139.    /* Signal print char complete */
  140.    set_flag (&prt->pready);
  141. }
  142.  
  143.  
  144. /*-------------------------------------------------------------------------*/
  145.  
  146.  
  147. local void near pr_toggle_strobe (int port_base, byte ctl)
  148. {
  149.    tsk_outp (port_base + control, ctl | STROBE);
  150.    tsk_nop ();
  151.    tsk_outp (port_base + control, ctl);
  152. }
  153.  
  154. local int near pr_ready (int port_base)
  155. {
  156.    return (tsk_inp (port_base + status) & (BUSY | ACK | PEND | SELIN | ERROR))
  157.           == (BUSY | ACK | SELIN | ERROR);
  158. }
  159.  
  160.  
  161. local void near pr_output_poll (prtptr prt, byte ch)
  162. {
  163.    int wait_count;
  164.    int port_base;
  165.  
  166.    port_base = prt->port_base;
  167.    while (!pr_ready (port_base))
  168.       {
  169.       for (wait_count = 0; wait_count < MAX_WAIT_POLL; wait_count++)
  170.          if (pr_ready (port_base))
  171.             break;
  172.       if (!pr_ready (port_base))
  173.          yield ();
  174.       }
  175.    tsk_outp (port_base + data, ch);
  176.    pr_toggle_strobe (port_base, prt->ccontrol);
  177. }
  178.  
  179.  
  180. local void near pr_output_int (prtptr prt, byte ch)
  181. {
  182.    int wait_count;
  183.    int port_base;
  184.  
  185.    port_base = prt->port_base;
  186.    while (!pr_ready (port_base))
  187.       {
  188.       for (wait_count = 0; wait_count < MAX_WAIT_INT; wait_count++)
  189.          if (pr_ready (port_base))
  190.             break;
  191.       if (!pr_ready (port_base))
  192.          yield ();
  193.       }
  194.  
  195.    clear_flag (&prt->pready);
  196.  
  197.    tsk_outp (port_base + data, ch);
  198.    pr_toggle_strobe (port_base, prt->ccontrol | IRQENA);
  199.  
  200.    for (wait_count = 0; wait_count < MAX_WAIT_INT; wait_count++)
  201.       if (check_flag (&prt->pready))
  202.          return;
  203.  
  204.    if (wait_flag_set (&prt->pready, INT_TIMEOUT) < 0)
  205.       tsk_outp (prt->port_base + control, prt->ccontrol &= ~IRQENA);
  206. }
  207.  
  208.  
  209. local void far pr_task (prtptr prt)
  210. {
  211.    int ch;
  212.  
  213.    while (1)
  214.       {
  215.       ch = read_pipe (&prt->xmit_pipe, 0L);
  216.       if (prt->polling)
  217.          pr_output_poll (prt, (byte)ch);
  218.       else
  219.          pr_output_int (prt, (byte)ch);
  220.       }
  221. }
  222.  
  223. /*-------------------------------------------------------------------------*/
  224.  
  225. int far prt_install (int port, byte polling, word prior,
  226.                      farptr xmitbuf, word xmitsize)
  227. {
  228.    prtptr prt;
  229.    int pbase;
  230.    intprocptr far *intptr;
  231. #if (TSK_NAMEPAR)
  232.    static char name [] = "PRTn";
  233.  
  234.    name [3] = (char)(port & 0x7f) + '0';
  235. #endif
  236.  
  237.    if (port & 0x80)
  238.       {
  239.       port &= 0x7f;
  240.       if (port > 4)
  241.          return -1; 
  242.       pbase = *((wordptr)(MK_FP (0x40, port * 2 + 8)));
  243.       if (!pbase)
  244.          return -1;
  245.  
  246.       for (port = 0; port < PORTS; port++)
  247.          if (pr_port_descr [port].base == pbase)
  248.             break;
  249.       }
  250.  
  251.    if (port < 0 || port >= PORTS || !xmitsize || prt_installed [port])
  252.       return -1;
  253.  
  254.    prt = &prt_data [port];
  255.  
  256.    if (create_pipe (&prt->xmit_pipe, xmitbuf, xmitsize
  257. #if (TSK_NAMEPAR)
  258.                    , name
  259. #endif
  260.                    ) == NULL)
  261.       return -1;
  262.  
  263.    create_flag (&prt->pready
  264. #if (TSK_NAMEPAR)
  265.                 , name
  266. #endif
  267.                 );
  268.  
  269.    create_task (&prt->pr_task, pr_task, prt->pr_stack, STKSZ, prior, prt
  270. #if (TSK_NAMEPAR)
  271.                 , name
  272. #endif
  273.                 );
  274.  
  275.    pbase = prt->port_base = pr_port_descr [port].base;
  276.    prt->civect = pr_port_descr [port].vector;
  277.    prt->irqbit = pr_port_descr [port].irq;
  278.    prt->ccontrol = dflt_control;
  279.    prt->wait_xmit = prt->xmit_pending = 0;
  280.  
  281.    if (!prt->irqbit)
  282.       polling = 1;
  283.  
  284.    prt->polling = polling;
  285.  
  286.    tsk_outp (pbase + control, dflt_control);
  287.    if (!polling)
  288.       {
  289.       intptr = (intprocptr far *)MK_FP (0, prt->civect * 4);
  290.       tsk_cli ();
  291.       prt->savvect = *intptr;
  292.       *intptr = pr_port_descr [port].proc;
  293.       tsk_sti ();
  294.       tsk_outp (inta01, tsk_inp (inta01) & ~prt->irqbit);
  295.       }
  296.  
  297.    prt_installed [port] = 1;
  298.    prt_remove_func = prt_remove_all;
  299.    start_task (&prt->pr_task);
  300.  
  301.     return port;
  302.    }
  303.  
  304.  
  305. void far prt_remove (int port)
  306.    {
  307.    prtptr prt;
  308.    intprocptr far *intptr;
  309.  
  310.    if ((port & 0xfff0) || !prt_installed [port])
  311.       return;
  312.    prt = &prt_data [port];
  313.  
  314.    tsk_outp (prt->port_base + control, prt->ccontrol & ~IRQENA);
  315.  
  316.    if (!prt->polling)
  317.       {
  318.       tsk_outp (inta01, tsk_inp (inta01) | prt->irqbit);
  319.       intptr = (intprocptr far *)MK_FP (0, prt->civect * 4);
  320.       tsk_cli ();
  321.       *intptr = prt->savvect;
  322.       tsk_sti ();
  323.       }
  324.    kill_task (&prt->pr_task);
  325.    delete_pipe (&prt->xmit_pipe);
  326.    delete_flag (&prt->pready);
  327.  
  328.    prt_installed [port] = 0;
  329.    }
  330.  
  331.  
  332. void far prt_remove_all (void)
  333. {
  334.    int i;
  335.  
  336.    for (i = 0; i < PORTS; i++)
  337.       if (prt_installed [i])
  338.          prt_remove (i);
  339. }
  340.  
  341.  
  342. /*-------------------------------------------------------------------------*/
  343.  
  344.  
  345. void far prt_change_control (int port, byte ctl)
  346. {
  347.    prtptr prt;
  348.    CRITICAL;
  349.  
  350.    if ((port & 0xfff0) || !prt_installed [port])
  351.       return;
  352.    prt = &prt_data [port];
  353.    C_ENTER;
  354.    prt->ccontrol = (prt->ccontrol & ~(AUTOFEED | INIT | SELECT))
  355.                    | (ctl & (AUTOFEED | INIT | SELECT));
  356.    C_LEAVE;
  357.    tsk_outp (prt->port_base + control, prt->ccontrol);
  358. }
  359.  
  360.  
  361. int far prt_write (int port, byte ch, dword timeout)
  362. {
  363.    if ((port & 0xfff0) || !prt_installed [port])
  364.       return -1;
  365.    return write_pipe (&prt_data [port].xmit_pipe, ch, timeout);
  366. }
  367.  
  368.  
  369. int far prt_status (int port)
  370. {
  371.    if ((port & 0xfff0) || !prt_installed [port])
  372.       return -1;
  373.    return tsk_inp (prt_data [port].port_base + status);
  374. }
  375.  
  376.  
  377. int far prt_complete (int port)
  378. {
  379.    if ((port & 0xfff0) || !prt_installed [port])
  380.       return -1;
  381.    return (check_pipe (&prt_data [port].xmit_pipe) == -1);
  382. }
  383.  
  384.  
  385. int far prt_wait_complete (int port, dword timeout)
  386. {
  387.    if ((port & 0xfff0) || !prt_installed [port])
  388.       return -1;
  389.    return wait_pipe_empty (&prt_data [port].xmit_pipe, timeout);
  390. }
  391.  
  392. void far prt_flush (int port)
  393. {
  394.    if ((port & 0xfff0) || !prt_installed [port])
  395.       return;
  396.    flush_pipe (&prt_data [port].xmit_pipe);
  397. }
  398.  
  399.