home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frostbyte's 1980s DOS Shareware Collection
/
floppyshareware.zip
/
floppyshareware
/
DOOG
/
CTASK.ZIP
/
TSKPRT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-12-21
|
11KB
|
399 lines
/*
--- Version 2.0 89-12-13 17:40 ---
TSKPRT.C - CTask - Printer interface routines.
Public Domain Software written by
Thomas Wagner
Patschkauer Weg 31
D-1000 Berlin 33
West Germany
The algorithm for waiting when the printer is busy has been changed
in version 1.2. In the previous versions, a timed delay was used after
a certain number of times through the loop. Depending on the kind of
printer, and the system speed, this could lead to extremely slow
output. Now a busy waiting loop with scheduling is employed. This
change will not likely hamper system performance significantly, but
can speed up printer output processing.
Also new in version 1.2 is the stack switch module, tskprti.asm. The
interrupt routine is now called through an "envelope" that first
switches to a local stack.
*/
#include "tsk.h"
#include "prt.h"
#define STKSZ 256 /* Printer Task stack size */
/*
The following values may need some tuning for optimum performance.
*/
/*
MAX_WAIT_xx: Maximum number of times through the loop when waiting
for the printer to get ready.
*/
#define MAX_WAIT_INT 30 /* For interrupt output */
#define MAX_WAIT_POLL 30 /* For polling output */
#define INT_TIMEOUT 2L /* Timeout for ACK interrupt wait */
typedef void (interrupt far * intprocptr)(void);
#define inta00 0x20 /* 8259 interrupt controller control-port */
#define inta01 0x21 /* 8259 interrupt controller mask-port */
#define rdserv 0x0b /* read service register control value */
#define eoi 0x20 /* end of interrupt signal for 8259 */
#define data 0x00
#define status 0x01
#define control 0x02
#define STROBE 0x01
#define IRQENA 0x10
#define dflt_control (INIT | SELECT)
/*
To add support for other LPT-Ports, define
- Port base
- IRQ-Bit (optional)
- Interrupt vector (optional)
here, add the necessary data to the pr_port_descr array, and, if irq
was specified, define the corresponding interrupt function by
duplicating prtint0, replacing the index into the prt_data array.
*/
#define PORTS 3 /* Number of defined ports */
#define lpt1_base 0x3bc /* LPT1 port base (mono card) */
#define lpt2_base 0x378 /* LPT2 port base (IBM printer adapter) */
#define lpt3_base 0x278 /* LPT3 port base (secondary parallel) */
#define lpt1_irq 0x80 /* IRQ-Bit for LPT1 */
#define lpt2_irq 0x80 /* IRQ-Bit for LPT2 (same as LPT1) */
#define lpt3_irq 0x20 /* IRQ-Bit for LPT3 */
#define lpt1_vect 0x0f /* Interrupt vector for LPT1 */
#define lpt2_vect 0x0f /* Interrupt vector for LPT2 */
#define lpt3_vect 0x0d /* Interrupt vector for LPT3 */
typedef struct {
intprocptr proc;
int base;
byte irq;
byte vector;
} port_data;
extern void interrupt far tskprt_int0 (void);
extern void interrupt far tskprt_int1 (void);
extern void interrupt far tskprt_int2 (void);
port_data pr_port_descr [PORTS] = {
{ tskprt_int0, lpt1_base, lpt1_irq, lpt1_vect },
{ tskprt_int1, lpt2_base, lpt2_irq, lpt2_vect },
{ tskprt_int2, lpt3_base, lpt3_irq, lpt3_vect }
};
/*-------------------------------------------------------------------------*/
typedef struct {
farptr savvect; /* Interrupt vector save location */
int port_base; /* Port base I/O address */
byte irqbit; /* IRQ-Bit for this port */
byte civect; /* Interrupt Vector for this port */
byte wait_xmit; /* Transmit delayed */
byte xmit_pending; /* Transmit in progress */
byte polling; /* Use polling if on */
byte ccontrol; /* Current control reg */
pipe xmit_pipe; /* Transmit pipe */
flag pready; /* Printer ready flag */
tcb pr_task; /* Printer task */
byte pr_stack [STKSZ]; /* Printer task stack */
} prt_datarec;
typedef prt_datarec *prtptr;
local prt_datarec prt_data [PORTS];
local int prt_installed [PORTS] = { 0 };
extern funcptr prt_remove_func;
/*-------------------------------------------------------------------------*/
void near tsk_prt_int (int port)
{
prtptr prt = &prt_data [port];
/* Turn off int */
prt->ccontrol &= ~IRQENA;
tsk_outp (prt->port_base + control, prt->ccontrol);
/* Signal print char complete */
set_flag (&prt->pready);
}
/*-------------------------------------------------------------------------*/
local void near pr_toggle_strobe (int port_base, byte ctl)
{
tsk_outp (port_base + control, ctl | STROBE);
tsk_nop ();
tsk_outp (port_base + control, ctl);
}
local int near pr_ready (int port_base)
{
return (tsk_inp (port_base + status) & (BUSY | ACK | PEND | SELIN | ERROR))
== (BUSY | ACK | SELIN | ERROR);
}
local void near pr_output_poll (prtptr prt, byte ch)
{
int wait_count;
int port_base;
port_base = prt->port_base;
while (!pr_ready (port_base))
{
for (wait_count = 0; wait_count < MAX_WAIT_POLL; wait_count++)
if (pr_ready (port_base))
break;
if (!pr_ready (port_base))
yield ();
}
tsk_outp (port_base + data, ch);
pr_toggle_strobe (port_base, prt->ccontrol);
}
local void near pr_output_int (prtptr prt, byte ch)
{
int wait_count;
int port_base;
port_base = prt->port_base;
while (!pr_ready (port_base))
{
for (wait_count = 0; wait_count < MAX_WAIT_INT; wait_count++)
if (pr_ready (port_base))
break;
if (!pr_ready (port_base))
yield ();
}
clear_flag (&prt->pready);
tsk_outp (port_base + data, ch);
pr_toggle_strobe (port_base, prt->ccontrol | IRQENA);
for (wait_count = 0; wait_count < MAX_WAIT_INT; wait_count++)
if (check_flag (&prt->pready))
return;
if (wait_flag_set (&prt->pready, INT_TIMEOUT) < 0)
tsk_outp (prt->port_base + control, prt->ccontrol &= ~IRQENA);
}
local void far pr_task (prtptr prt)
{
int ch;
while (1)
{
ch = read_pipe (&prt->xmit_pipe, 0L);
if (prt->polling)
pr_output_poll (prt, (byte)ch);
else
pr_output_int (prt, (byte)ch);
}
}
/*-------------------------------------------------------------------------*/
int far prt_install (int port, byte polling, word prior,
farptr xmitbuf, word xmitsize)
{
prtptr prt;
int pbase;
intprocptr far *intptr;
#if (TSK_NAMEPAR)
static char name [] = "PRTn";
name [3] = (char)(port & 0x7f) + '0';
#endif
if (port & 0x80)
{
port &= 0x7f;
if (port > 4)
return -1;
pbase = *((wordptr)(MK_FP (0x40, port * 2 + 8)));
if (!pbase)
return -1;
for (port = 0; port < PORTS; port++)
if (pr_port_descr [port].base == pbase)
break;
}
if (port < 0 || port >= PORTS || !xmitsize || prt_installed [port])
return -1;
prt = &prt_data [port];
if (create_pipe (&prt->xmit_pipe, xmitbuf, xmitsize
#if (TSK_NAMEPAR)
, name
#endif
) == NULL)
return -1;
create_flag (&prt->pready
#if (TSK_NAMEPAR)
, name
#endif
);
create_task (&prt->pr_task, pr_task, prt->pr_stack, STKSZ, prior, prt
#if (TSK_NAMEPAR)
, name
#endif
);
pbase = prt->port_base = pr_port_descr [port].base;
prt->civect = pr_port_descr [port].vector;
prt->irqbit = pr_port_descr [port].irq;
prt->ccontrol = dflt_control;
prt->wait_xmit = prt->xmit_pending = 0;
if (!prt->irqbit)
polling = 1;
prt->polling = polling;
tsk_outp (pbase + control, dflt_control);
if (!polling)
{
intptr = (intprocptr far *)MK_FP (0, prt->civect * 4);
tsk_cli ();
prt->savvect = *intptr;
*intptr = pr_port_descr [port].proc;
tsk_sti ();
tsk_outp (inta01, tsk_inp (inta01) & ~prt->irqbit);
}
prt_installed [port] = 1;
prt_remove_func = prt_remove_all;
start_task (&prt->pr_task);
return port;
}
void far prt_remove (int port)
{
prtptr prt;
intprocptr far *intptr;
if ((port & 0xfff0) || !prt_installed [port])
return;
prt = &prt_data [port];
tsk_outp (prt->port_base + control, prt->ccontrol & ~IRQENA);
if (!prt->polling)
{
tsk_outp (inta01, tsk_inp (inta01) | prt->irqbit);
intptr = (intprocptr far *)MK_FP (0, prt->civect * 4);
tsk_cli ();
*intptr = prt->savvect;
tsk_sti ();
}
kill_task (&prt->pr_task);
delete_pipe (&prt->xmit_pipe);
delete_flag (&prt->pready);
prt_installed [port] = 0;
}
void far prt_remove_all (void)
{
int i;
for (i = 0; i < PORTS; i++)
if (prt_installed [i])
prt_remove (i);
}
/*-------------------------------------------------------------------------*/
void far prt_change_control (int port, byte ctl)
{
prtptr prt;
CRITICAL;
if ((port & 0xfff0) || !prt_installed [port])
return;
prt = &prt_data [port];
C_ENTER;
prt->ccontrol = (prt->ccontrol & ~(AUTOFEED | INIT | SELECT))
| (ctl & (AUTOFEED | INIT | SELECT));
C_LEAVE;
tsk_outp (prt->port_base + control, prt->ccontrol);
}
int far prt_write (int port, byte ch, dword timeout)
{
if ((port & 0xfff0) || !prt_installed [port])
return -1;
return write_pipe (&prt_data [port].xmit_pipe, ch, timeout);
}
int far prt_status (int port)
{
if ((port & 0xfff0) || !prt_installed [port])
return -1;
return tsk_inp (prt_data [port].port_base + status);
}
int far prt_complete (int port)
{
if ((port & 0xfff0) || !prt_installed [port])
return -1;
return (check_pipe (&prt_data [port].xmit_pipe) == -1);
}
int far prt_wait_complete (int port, dword timeout)
{
if ((port & 0xfff0) || !prt_installed [port])
return -1;
return wait_pipe_empty (&prt_data [port].xmit_pipe, timeout);
}
void far prt_flush (int port)
{
if ((port & 0xfff0) || !prt_installed [port])
return;
flush_pipe (&prt_data [port].xmit_pipe);
}