home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1999 mARCH
/
PCWK3A99.iso
/
Archiwiz
/
Tar320
/
SOURCES.ZIP
/
STREAMER.C
< prev
next >
Wrap
Text File
|
1994-12-23
|
21KB
|
717 lines
#ifdef __TURBOC__
#include <dos.h>
#include <errno.h>
#include <string.h>
#include "pctimer.h"
#define timer pctimer
#include "qic02.h"
/*****************************************************\
* Quarter-Inch-Cartridge no. 02 standart error list *
\*****************************************************/
static char *err[] = {
"udefined error",
"Ok",
"reset in progress", /* hardware status */
"end of recorded media",
"bus parity error",
"beginning of media",
"marginal block detected",
"no data detected",
"illegal command",
"timeout expired", /* software flag */
"file mark detected",
"block not located",
"unrecoverable data error",
"end of medium",
"write protected",
"device fault",
"cartridge not in place",
"drive busy", /* software error codes */
"device not opened",
"device already opened",
};
char **qic02_errlist = err+1;
int qic02_nerr = sizeof(err)/sizeof(*err) - 1;
/****************************************************\
* Quarter-Inch-Cartridge no. 02 standart interface *
\****************************************************/
extern unsigned long timer(void);
extern unsigned long suspend_value(unsigned);
extern void suspend(unsigned long);
extern void interrupt cthandle();
extern long ptr2abs(void far *);
static unsigned long wait03us, wait25ms;
#define CT_OPENED 0x08
#define CT_CHECKED 0x10
#define CT_EVENT 0x20
#define CT_PROTECT 0x40
#define MASK_BOARD 0x7f
#define SKIP_RESET 0x80
/* Calculate number of ticks by 300 ms units */
#define TIMEOUT(x) (int)((3*119318L*(x) + 65535L) / 65536L)
#define MINTIME TIMEOUT(1)
#define MAXTIME TIMEOUT(1000)
#define WAITIME TIMEOUT(10)
#define HALT_CPU /*__emit__(0xf4)*/
#define dim(x) (sizeof(x)/sizeof(*(x)))
#define NTRY 3
#define Q2_READBIT 0x80
#define DMA_WRDEV 8
#define DMA_RDDEV 4
static struct _ct_define {
char ct_name[8];
WORD valid_base, off_control, off_data, off_launch, off_clear;
BYTE mask_reset, val_reset;
BYTE mask_event, not_event;
BYTE mask_ready, not_ready;
BYTE mask_excep, not_excep;
BYTE mask_dma, done_dma;
BYTE mask_xfer, no_xfer;
BYTE set_reset, set_request, set_online;
BYTE ienable, denable, dma_valid, rundma[8];
} *ct_current = (struct _ct_define *)0;
static struct _ct_define sc499 = {
"archive",
0x3f8, 1, 0, 2, 3,
0xf0, 0x50,
0x80, 0x80,
0x40, 0x40,
0x20, 0x20,
0x10, 0x10,
0x08, 0x00,
0x80, 0x40, 0,
0x20, 0x10, 0x0A, { 0, 0, 0, 0, 0, 0, 0, 0 },
};
static struct _ct_define sc409a = {
"everex",
0x3ff, 0, 1, UNUSED, UNUSED,
7, 5,
0, 0,
1, 1,
2, 2,
0, 0,
4, 4,
2, 4, 1,
0x40, 0, 0x0E, { 0, 8, 8, 8, 0, 0, 0, 0 },
};
static struct _ct_define wangtek = {
"wangtek",
0x3ff, 0, 1, UNUSED, UNUSED,
7, 5,
0, 0,
1, 1,
2, 2,
0, 0,
4, 4,
2, 4, 1,
0, 0, 0x0E, { 0, 8, 8, 16, 0, 0, 0, 0 },
};
static struct _ct_define *ct_list[] = {
&sc499, &sc409a, &wangtek
};
struct _ct_pic {
WORD base;
BYTE ack, chain;
void interrupt (*old)();
int number; BYTE save;
} ct_pic;
struct _ct_dma {
WORD page, address, counter;
WORD mask, mode, clear;
BYTE read, write;
} ct_dma;
BYTE lastcmd = UNUSED;
WORD ct_error;
volatile struct _ct_psw {
BYTE flags;
BYTE input;
} ct_psw;
struct _ct_control {
WORD control, data, launch, clear;
BYTE mask_reset, val_reset;
BYTE mask_event, not_event;
BYTE mask_ready, not_ready;
BYTE mask_excep, not_excep;
BYTE mask_state, inv_state;
BYTE mask_xfer, no_xfer;
BYTE mask_dma, done_dma;
BYTE do_reset, request, online;
BYTE int_enable, done_enable, dma_enable;
} ct_set;
static WORD ct_error;
static BYTE statbuf[6];
#define ctlport (ct_set.control)
#define cmdport (ct_set.data)
#define statport (ct_set.control)
#define dataport (ct_set.data)
#define DMAGO (ct_set.launch)
#define DMACL (ct_set.clear)
#define MASK_RESET ct_set.mask_reset
#define VAL_RESET ct_set.val_reset
#define MASK_READY ct_set.mask_ready
#define NOT_READY ct_set.not_ready
#define MASK_EXCEP ct_set.mask_excep
#define NOT_EXCEP ct_set.not_excep
#define MASK_STATE ct_set.mask_state
#define INV_STATE ct_set.inv_state
#define DIRC ct_set.mask_xfer
#define XOFF ct_set.no_xfer
#define ON ct_set.online
#define REQ ct_set.request
#define RESET ct_set.do_reset
#define EI ct_set.int_enable
#define ED ct_set.done_enable
#define DMA ct_set.dma_enable
#define INP ct_psw.input
#define DMA_MAIN ct_dma.mask
#define WAIT_READY(t)\
for ((t)=timer(); ((INP=inportb(statport))&MASK_READY)==NOT_READY;)\
{ if (timer()-(t) > MINTIME) goto error; }
#define WAIT_BUSY(t)\
for ((t)=timer(); ((INP=inportb(statport))&MASK_READY)!=NOT_READY;)\
{ if (timer()-(t) > MINTIME) goto error; }
static int ct_iobyte(int c, unsigned char *p, unsigned length, unsigned tout)
{
register i;
register long t, t0;
#if 0
/* read-only now */ if (!(c & Q2_READBIT)) goto error;
#endif
ct_psw.flags &= ~CT_CHECKED;
outportb(cmdport, lastcmd=c);
outportb(ctlport, REQ);
WAIT_READY(t);
outportb(ctlport, ON); /* Clear request */
WAIT_BUSY(t);
t0 = timer();
i = c & Q2_READBIT ? XOFF : XOFF^DIRC;
while (((INP=inportb(statport)) & DIRC) == i) {
if (timer()-t0 > tout) goto error;
}
for (i=0; i<length; i++) {
WAIT_READY(t);
if (c & Q2_READBIT) {
p[i] = inportb(dataport);
} else {
outportb(dataport, p[i]);
}
outportb(ctlport, REQ);
suspend(wait03us);
WAIT_BUSY(t);
outportb(ctlport, ON);
}
return i;
error:
ct_error = Q2E_DEAD;
ct_psw.flags |= CT_CHECKED;
errno = EFAULT;
return -1;
}
static int ct_test(void)
{
register n;
register long t;
for (t=timer(); ((INP=inportb(statport))&MASK_STATE)==INV_STATE;) {
if (timer()-t > MINTIME) {
ct_error = Q2E_BUSY; goto end;
}
HALT_CPU;
}
for (n=NTRY; n; n--) {
if (ct_iobyte(Q2_RDSTAT, statbuf, 6, TIMEOUT(10)) == 6) {
ct_error = (statbuf[0] & Q2_ERRFLAG) ?
(statbuf[0] & Q2_ERRMASK) << 8 : 0;
if (statbuf[1] & Q2_ERRFLAG) ct_error |= statbuf[1] & Q2_ERRMASK;
break;
}
}
end:
ct_psw.flags |= CT_CHECKED;
return ct_error;
}
static int ct_wait(BYTE mask, BYTE val, unsigned long t0, unsigned tout)
{
while (((INP=inportb(statport)) & mask) == val) {
if ((INP & MASK_EXCEP) != NOT_EXCEP) return ct_test();
if (timer()-t0 > tout) {
ct_psw.flags |= CT_CHECKED;
return ct_error = (INP&MASK_READY)==NOT_READY ? Q2E_BUSY : Q2E_DEAD;
}
HALT_CPU;
}
return 0;
}
static int ct_reset(void)
{
register long t;
outportb(ctlport, ct_set.do_reset);
suspend(wait25ms);
outportb(DMACL != UNUSED ? DMACL : ctlport, ON);
t = timer();
while ((((INP=inportb(statport)) & MASK_RESET) != VAL_RESET)) {
if (timer()-t > MINTIME) goto error; HALT_CPU;
}
while (!(ct_test() & Q2E_POR)) {
if (timer()-t > MAXTIME) goto error; HALT_CPU;
}
while (ct_test() & Q2E_POR) {
if (timer()-t > MAXTIME) goto error; HALT_CPU;
}
while ((INP=inportb(statport) & MASK_STATE) == INV_STATE) {
if (timer()-t > MAXTIME) goto error; HALT_CPU;
}
return 0;
error:
return -1;
}
int ct_errbit(register unsigned m)
{
register n = 0;
if (m) {
if (m & Q2E_DEAD) m &= Q2E_DEAD;
else if (m & Q2E_HARD) m &= Q2E_HARD;
for (n=16; n && !(m & 0x8000); --n, m<<=1);
}
return n;
}
static void ct_end(void)
{
if (!(ct_psw.flags & CT_OPENED)) {
errno = EFAULT;
} else {
if (ct_pic.base != UNUSED) {
setvect(ct_pic.number, ct_pic.old);
if (ct_pic.save & (1 << (ct_pic.ack & 7)))
outportb(ct_pic.base+1, ct_pic.save);
}
ct_psw.flags = 0;
}
}
static void ct_pause(void)
{
register long t; for (t=timer(); timer()-t <= MINTIME;) HALT_CPU;
}
static int ct_begin(register struct init_data *d, int board_type)
{
register WORD i;
static BYTE page_tab[] = {0x87,0x83,0x81,0x82,0x8f,0x8b,0x89,0x8A};
static BYTE addr_tab[] = { 0, 2, 4, 6, 0xC0,0xC4,0xC8,0xCC};
static BYTE cntr_tab[] = { 1, 3, 5, 7, 0xC2,0xC6,0xCA,0xCE};
register j; register long t;
if ((i = board_type & MASK_BOARD) >= dim(ct_list)) {
errno = ENODEV; return CTE_FAULT;
} else {
ct_current = ct_list[i];
}
i = d->base_address;
if (i & ~(ct_current->valid_base)) {
errno = EINVDAT; return CTE_FAULT;
} else {
ct_set.control = i + ct_current->off_control;
ct_set.data = i + ct_current->off_data;
DMAGO = ct_current->off_launch == UNUSED ?
UNUSED : i + ct_current->off_launch;
DMACL = ct_current->off_clear == UNUSED ?
UNUSED : i + ct_current->off_clear;
ct_set.mask_reset = ct_current->mask_reset;
ct_set.val_reset = ct_current->val_reset;
ct_set.mask_event = ct_current->mask_event;
ct_set.not_event = ct_current->not_event;
ct_set.mask_ready = ct_current->mask_ready;
ct_set.not_ready = ct_current->not_ready;
ct_set.mask_excep = ct_current->mask_excep;
ct_set.not_excep = ct_current->not_excep;
ct_set.mask_state = ct_set.mask_ready | ct_set.mask_excep;
ct_set.inv_state = ct_set.not_ready | ct_set.not_excep;
ct_set.mask_xfer = ct_current->mask_xfer;
ct_set.no_xfer = ct_current->no_xfer;
ct_set.mask_dma = ct_current->mask_dma;
ct_set.done_dma = ct_current->done_dma;
ct_set.online = ct_current->set_online;
ct_set.request = ct_current->set_request | ct_set.online;
ct_set.do_reset = ct_current->set_reset;
}
i = d->dma_number;
if (i == UNUSED) {
ct_dma.page = ct_dma.address = ct_dma.counter = UNUSED;
ct_dma.mask = ct_dma.mode = ct_dma.clear = UNUSED;
ct_set.dma_enable = 0;
} else if (i & ~7 || !((ct_current->dma_valid >> i) & 1)) {
errno = EINVDAT; return CTE_FAULT;
} else {
ct_set.dma_enable = ct_current->rundma[i];
ct_dma.page = page_tab[i];
ct_dma.address = addr_tab[i];
ct_dma.counter = cntr_tab[i];
if (i & ~3) {/* slave device */
ct_dma.mask = 0xd4;
ct_dma.mode = 0xd6;
ct_dma.clear = 0xd8;
} else {/* primary device */
ct_dma.mask = 0xA;
ct_dma.mode = 0xB;
ct_dma.clear = 0xC;
}
i &= 3;
/* single mode, address increment, no auto-init */
ct_dma.write = 0x40 | DMA_WRDEV | i;
ct_dma.read = 0x40 | DMA_RDDEV | i;
}
i = d->irq_number;
if (i == UNUSED) {
ct_pic.number = ct_pic.base = UNUSED;
ct_set.int_enable = ct_set.done_enable = 0;
} else if (i & ~15) {
errno = EINVDAT; return CTE_FAULT;
} else {
ct_set.int_enable = ct_current->ienable;
ct_set.done_enable = ct_current->denable ?
ct_current->denable : ct_current->ienable;
if (i & ~7) {/* slave controller */
ct_pic.number = i + 0x68;
ct_pic.base = 0xA0;
} else {/* primary controller */
ct_pic.number = i + 8;
ct_pic.base = 0x20;
}
i &= 7;
ct_pic.old = getvect(ct_pic.number);
ct_pic.ack = 0x60 | i; /* specific EOI */
ct_pic.save = inportb(ct_pic.base + 1);
ct_pic.chain = ct_pic.old && ~(ct_pic.save >> i) & 1;
}
wait03us = suspend_value(3);
wait25ms = suspend_value(25000);
if ((board_type & SKIP_RESET) == 0) {
if (ct_reset()) return (errno = EFAULT, CTE_DEAD);
}
if (ct_pic.base != UNUSED) {
setvect(ct_pic.number, cthandle);
if ((i = 1 << (ct_pic.ack & 7)) & ct_pic.save)
outportb(ct_pic.base+1, ~i & ct_pic.save);
}
ct_error = 0; ct_psw.flags |= CT_OPENED;
for (t=timer(), j=0;;) {
i = ct_test();
if (i & Q2E_WRP) ct_psw.flags |= CT_PROTECT;
if (!(i & ~(Q2E_BOM|Q2E_FIL|Q2E_WRP))) return 0;
if (timer()-t > MAXTIME) break;
if (!(i & Q2E_POR) && ++j >= NTRY) break;
ct_pause();
}
ct_end(); errno = EFAULT; return ct_errbit(i);
}
static int ct_issue(int c)
{
register unsigned long tick;
if (ct_wait(MASK_STATE,INV_STATE,timer(),MINTIME) & Q2E_STOP) goto end;
ct_psw.flags &= ~CT_CHECKED;
outportb(cmdport, lastcmd=c);
outportb(ctlport, REQ);
if (ct_wait(MASK_READY,NOT_READY,timer(),MINTIME) & Q2E_HARD) goto end;
ct_psw.flags &= ~CT_EVENT;
INP = (INP & ~ct_set.mask_event) | ct_set.not_event;
outportb(ctlport, ON|EI); /* Clear request, interrupt enable */
WAIT_BUSY(tick);
return 0;
error:
ct_error = Q2E_DEAD;
ct_psw.flags |= CT_CHECKED;
end:
return ct_errbit(ct_error);
}
static int ct_complete(void)
{
register long t;
for (t=timer();;) {
if (((INP=inportb(statport)) & MASK_STATE)!=INV_STATE) break;
if (timer()-t > MAXTIME) return (ct_error = Q2E_DEAD, CTE_DEAD);
HALT_CPU;
}
return 0;
}
static int ct_iodma(int c, void *buf, unsigned length)
{
register unsigned k;
register unsigned inp;
register long t, t0;
long address;
address = ptr2abs(buf);
if (DMA_MAIN & 0xf0) {
/* Secondary DMA requires word alignment */
if (address & 1 || length & 1) return (errno = EINVMEM, CTE_FAULT);
address >>= 1;
length >>= 1;
}
length -= 1;
/* Check for writing across DMA page */
if (((address+length) ^ address) & ~0xffffL)
return (errno = EINVMEM, CTE_FAULT);
t0 = timer();
if (lastcmd!=c) {
if (DMACL != UNUSED) outportb(DMACL, 0);
/********** Issue a command **********/
outportb(cmdport, lastcmd=c);
outportb(ctlport, REQ);
if (ct_wait(MASK_READY, NOT_READY,
(c & Q2_READBIT ? timer() : t0),
(c & Q2_READBIT ? MINTIME : MAXTIME)) & Q2E_HARD)
goto error;
outportb(ctlport, ON|ED|DMA);
WAIT_BUSY(t);
}
/* Clear status */
ct_psw.flags &= ~(CT_EVENT|CT_CHECKED);
INP = (INP & ~ct_set.mask_event) | ct_set.not_event;
/********** Initialise DMA **********/
outportb(ct_dma.mask, 4|(ct_dma.read & 3));
outportb(ct_dma.mode, c & Q2_READBIT ? ct_dma.read : ct_dma.write);
outportb(ct_dma.page, (WORD)(address >> 16));
if (DMA_MAIN & 0xf0) {/* secondary controller */
outport(ct_dma.address, (WORD)address);
outport(ct_dma.counter, length);
} else {
disable();
outportb(ct_dma.clear, 0);
outportb(ct_dma.address, (WORD)address);
outportb(ct_dma.address, (WORD)address>>8);
outportb(ct_dma.counter, length);
outportb(ct_dma.counter, length>>8);
enable();
}
if (c & Q2_READBIT) {
if (ct_wait(DIRC,XOFF,t0,MAXTIME) & Q2E_HARD) goto error;
}
if (DMAGO != UNUSED) outportb(DMAGO, 0);
outportb(ct_dma.mask, (ct_dma.read & 3));
/* Wait for the end of operation */
for (;;) {
INP = inp = inportb(statport);
if ((INP & MASK_EXCEP) != NOT_EXCEP) {
if (ct_test() & Q2E_HARD) goto error;
break;
}
if (ct_set.mask_dma) {
if ((INP & ct_set.mask_dma) == ct_set.done_dma) break;
} else {
if ((INP & MASK_READY) != NOT_READY) break;
}
if (timer()-t0 > MAXTIME) goto error;
HALT_CPU;
}
/********** Get number of bytes transferred **********/
if (DMA_MAIN & 0xf0) {/* secondary controller */
k = inport(ct_dma.counter);
k = (length - k) << 1;
} else {
disable();
outportb(ct_dma.clear, 0);
k = inportb(ct_dma.counter);
k |= inportb(ct_dma.counter) << 8;
enable();
k = length - k;
}
if (!(c & Q2_READBIT) &&
(inp & MASK_READY) == NOT_READY && (INP & MASK_READY) == NOT_READY) {
(void)ct_wait(MASK_READY,NOT_READY,t0,MAXTIME);
}
return k;
/********** Error occured **********/
error:
if (DMACL != UNUSED) outportb(DMACL, 0);
return (errno = EFAULT, CTE_FAULT);
}
static int ct_inout(int c, void *buf, unsigned length)
{
if (ct_wait(MASK_READY,NOT_READY,timer(),
(c & Q2_READBIT ? MAXTIME : WAITIME)) & Q2E_STOP)
return -1;
return DMA_MAIN == UNUSED ?
ct_iobyte(c, buf, length, MAXTIME) :
ct_iodma(c, buf, length);
}
int streamer(register int op, void *ptr, int arg)
{
register i;
register long t;
op |= 'z'^'Z';
if (op == '?') {
for (op=dim(ct_list); --op >= 0;) {
if (stricmp(ct_list[op]->ct_name, ptr) == 0) goto end;
}
goto end;
} else if (op == 'o') {/* open device */
op = ct_psw.flags & CT_OPENED ?
(errno=EFAULT, CTE_OPENED) :
ct_begin((struct init_data *)ptr, arg);
goto end;
}
if (!(ct_psw.flags & CT_OPENED)) return (errno=EFAULT, CTE_CLOSED);
switch (op) {
case 'c': /* end - close device */
ct_end();
op = 0;
break;
case 't': /* read status */
op = ct_errbit(ct_psw.flags&CT_CHECKED ? ct_error : ct_test());
if (ptr) {
((struct qic02_word_status *)ptr)->status = ct_error;
((struct qic02_word_status *)ptr)->error_cnt =
(statbuf[2] << 8) | statbuf[3];
((struct qic02_word_status *)ptr)->underrun_cnt =
(statbuf[4] << 8) | statbuf[5];
}
ct_psw.flags &= ~CT_CHECKED;
break;
case 'd': /* "drop online" - write FM and rewind */
if (ct_current == &wangtek) {
if (ct_wait(MASK_STATE,INV_STATE,timer(),MINTIME) & Q2E_STOP) {
op = ct_errbit(ct_error); break;
}
ct_psw.flags &= ~CT_CHECKED;
lastcmd = 0; /* dummy */
outportb(ctlport, 0); /* drop online */
for (t=timer(); timer()-t <= MAXTIME;) {
if (((INP=inportb(statport))&MASK_STATE)!=INV_STATE) break;
HALT_CPU;
}
ct_test();
if (ct_error & Q2E_HARD) goto test_rewind;
if (ct_error & Q2E_BOM) { op = 0; break; }
} else if (!(ct_psw.flags & CT_PROTECT)) {
/* write file mark */
if (ct_issue(Q2_WRMARK)!=0 || ct_complete()!=0) {
ct_test(); op = -1; break;
}
}
case 'n': /* rewind */
for (op=0, i=0;;) {
if (ct_issue(Q2_REWIND) == 0) {
for (t=timer(); timer()-t <= MAXTIME;) {
if (((INP=inportb(statport))&MASK_STATE)!=INV_STATE) break;
HALT_CPU;
}
ct_test();
if (ct_error & Q2E_HARD) break;
if (ct_error & Q2E_BOM) goto end;
}
if (++i >= NTRY) break;
if (ct_reset()) {
ct_error = Q2E_DEAD; break;
}
}
test_rewind:
op = ct_error & ~Q2E_WRP;
op = op ? ct_errbit(op) : CTE_FAULT;
break;
case 'i': /* issue a command */
arg &= 255;
if (arg == Q2_RDDATA || arg == Q2_WRDATA || arg == Q2_RDSTAT) {
errno = EINVAL; op = CTE_FAULT;
} else {
ct_psw.flags &= ~CT_CHECKED;
if ((op = ct_issue(arg)) == 0) op = ct_complete();
}
break;
case 'f': /* forward space file(s) */
for (op=0; op<arg; op++) {
ct_issue(Q2_RDMARK); if (ct_complete() != 0) break;
}
if (op != arg) ct_test();
break;
case 'r': /* read */
if ((op = ct_inout(Q2_RDDATA, ptr, arg)) != arg) {
if (!(ct_psw.flags & CT_CHECKED)) ct_test();
if (ct_error & Q2E_FIL && !(ct_error & Q2E_HARD)) {
/* file mark detected */ op = 0;
}
}
break;
case 'w': /* write */
if (ct_psw.flags & CT_PROTECT) {
ct_psw.flags |= CT_CHECKED;
ct_error = Q2E_WRP;
op = CTE_FAULT;
break;
}
if (!arg) {
/* write file mark */
if (ct_issue(Q2_WRMARK)!=0 || ct_complete()!=0) {
ct_test();
op = -1;
}
} else {
op = ct_inout(Q2_WRDATA, ptr, arg);
}
break;
default:
errno = EINVFNC;
op = CTE_FAULT;
}
end:
return op;
}
#endif