|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 8381 (0x20bd)
Types: TextFile
Notes: UNIX file
Names: »tp.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦2d53db1df⟧ UNIX Filesystem
└─⟦this⟧ »frankh/src/ieee/tp.c«
└─⟦this⟧ »frankh/src/tape_drive/tp.c«
/*
*
*
*
*/
#define FMTCMD 3 /* for tpioctl */
#define FDFORMAT 0x181
#include <coherent.h>
#include <buf.h>
#include <con.h>
#include <sched.h>
#include <stat.h>
#include <uproc.h>
#include <errno.h>
#include <ioport.h>
int tpload();
int tpuload();
int tpopen();
int tpread();
int tpwrite();
int tpblock();
int tpintr();
int tpioctl();
int nulldev();
int nonedev();
char *pfix(); /* map phys addr to a char * */
daddr_t tpbno(); /* returns actual block offset */
CON tpcon = {
DFBLK|DFCHR, /* Flags */
11, /* Major index */
tpopen, /* Open */
nulldev, /* Close */
tpblock, /* Block */
tpread, /* Read */
tpwrite, /* Write */
tpioctl, /* Ioctl */
nulldev, /* Powerfail */
nulldev, /* Timeout */
tpload, /* Load */
tpuload /* Unload */
};
/*
* QIC-02 command lines
*/
#define ONL 0x01 /* 8036 #0 PB0 */
#define REQ 0x02 /* 8036 #0 PB1 */
#define RST 0x04 /* 8036 #0 PB2 */
#define XFR 0x04 /* 8036 #1 PB2 */
#define ACK 0x08 /* 8036 #1 PB3 */
#define RDY 0x01 /* 8036 #1 PC0 */
#define EXC 0x01 /* 8036 #0 PC0 */
#define DIR 0x02 /* 8036 #1 PB1 */
/*
* QIC-02 commands
*/
#define SEL0 0x01 /* select drive 0 */
#define SELL0 0x11 /* select & lock drive 0 */
#define BOT 0x21 /* rewind drive to BOT */
#define ERASE 0x22 /* erase ENTIRE tape! */
#define RETEN 0x24 /* retension tape */
#define WRITE 0x40 /* write on the tape */
#define WRITEFM 0x60 /* write file mark */
#define READ 0x80 /* begin tape read */
#define READFM 0xA0 /* look for file mark */
#define STATUS 0xC0 /* read status command */
#define MAXBUF 256
#define TPVEC 0x80 /* base of tp interrupt vector */
#define NDRIVES 1 /* max 1 tape drive */
#define bool int
#define TRUE (0 == 0)
#define FALSE (0 != 0)
/*
* minor device layout
* bits 7-4: physical drive number
* bits 3-0: pseudo-drive number (partition) within the physical drive
*/
#define drive(mdev) ((mdev) >> 4) /* get drive # */
#define pseudo(mdev) ((mdev) & 0xF) /* get partition # */
struct {
unsigned int padd; /* port address */
unsigned int pdata; /* port data */
} savport[] = {
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0, 0
};
/*
* Printer database.
*/
typedef struct lpinfo {
int lpcol; /* Current horizontal position */
int lpnbuf; /* # of bytes in buffer */
char *lpin; /* Input pointer */
char *lpout; /* Output pointer */
char lpflag; /* Flags */
char lpbuf[MAXBUF]; /* Buffer */
} LP;
extern LP *lp;
/* lpflag bits */
#define LPOPEN 0x01 /* Printer is open */
/*
* housekeeping
*/
typedef struct tpunit {
bool tpu_active; /* drive/controller busy */
bool tpu_dma_aligned;/* dma address is 512 aligned */
struct tpunit *tpu_forw; /* next drive in controller chain */
struct tpunit *tpu_back; /* last drive */
BUF *tpu_actf; /* next BUF in drive chain */
paddr_t tpu_paddr; /* physical address of buffer */
} WDU;
WDU tputab[NDRIVES]; /* drive headers */
BUF tpbuf; /* BUF structure */
/*
* set up the driver.
*
*/
tpload()
{
register int i;
printf("tpload: load driver\n");
/* if (lp->lpflag) if lp is open, don't try this!
return(-1);
lp->lpflag = LPOPEN; mark busy! */
svp(0, PBDPP);
svp(1, PBDD);
svp(2, PBD);
svp(3, PBDPP | CIO1);
svp(4, PBDD | CIO1);
svp(5, PBD | CIO1);
svp(6, PCDPP | CIO1);
svp(7, PCDD | CIO1);
svp(8, 0);
/* setivec(WDVEC, tpintr); */
}
svp(pos, add)
int pos;
unsigned int add;
{
savport[pos].padd = add;
if (add)
savport[pos].pdata = inb(add);
else
savport[pos].pdata = 0;
}
tpuload()
{
register int cnt = 0;
printf("tpuload: unload driver\n");
/* lp->lpflag = 0; */
while(savport[cnt].padd) {
outb(savport[cnt].padd, savport[cnt].pdata);
++cnt;
}
}
/*
* Open routine. Check that the minor # is in range.
*
*/
tpopen(dev, mode)
dev_t dev;
{
register unsigned int d; /* drive # */
d = drive(minor(dev));
printf("tpopen: d = %d\n", d);
if (d >= NDRIVES)
u.u_error = ENXIO;
if (!selectl()) /* select & lock cart. */
u.u_error = EIO;
if (!bot()) /* rewind */
u.u_error = EIO;
}
/*
* perform a RAW read operation
*/
tpread(dev, iop)
dev_t dev;
IO *iop;
{
printf("tpread: begin\n");
ioreq(&tpbuf, iop, dev, BREAD, BFIOC|BFBLK|BFRAW);
}
/*
* perform a RAW read operation
*/
tpwrite(dev, iop)
dev_t dev;
IO *iop;
{
printf("tpwrite: begin\n");
ioreq(&tpbuf, iop, dev, BWRITE, BFIOC|BFBLK|BFRAW);
}
/*
* block I/O routine.
*/
tpblock(bp)
register BUF *bp;
{
register unsigned int d; /* drive # */
register unsigned int pd; /* partition # */
register daddr_t bno; /* block # */
register int s, fh; /* saved machine status */
bool tpstart();
d = drive(minor(bp->b_dev));
pd = pseudo(minor(bp->b_dev));
bno = bp->b_bno;
/* printf("tpblock: d=%d, pd=%d, bno=%d enter\n", d, pd, (int)bno);
tpbufdump(bp); */
if (d >= NDRIVES) {
bp->b_flag |= BFERR;
bdone(bp);
return;
}
s = sphi();
while (!(fh = tpstart(bp)))
;
spl(s);
/* printf("*buf = %s\n", bp->b_vaddr); */
}
/*
* Do the actual tape read/write.
*
*/
bool
tpstart(bp)
register BUF *bp;
{
register unsigned int d, pd, cmd;
int dma_error = FALSE;
/* printf("tpstart: begin\n"); */
if (bp->b_flag&BFRAW) {
printf("tp: RAW I/O not supported\n");
bp->b_flag |= BFERR;
bdone(bp);
}
printf("tpstart: block = %u req = %x\n", (int)bp->b_bno, bp->b_req);
/* tpbufdump(bp);
printf("*buf = %s\n", bp->b_vaddr); */
d = drive(minor(bp->b_dev));
pd = pseudo(minor(bp->b_dev));
if (bp->b_req == FMTCMD)
return tpformat(bp);
/*
* the actual block write of bp should
* be done here
*/
if ((int)bp->b_bno == 0) {
cmd = ((bp->b_req == BREAD) ? READ : WRITE);
command(cmd);
}
return (tpintr(bp));
}
/*
* got an interrupt from the controller - see if it was a valid I/O
* completion or an error.
*/
tpintr(bp)
register BUF *bp;
{
register unsigned int d;
/* printf("tpintr: begin\n"); */
d = drive(minor(bp->b_dev));
if ( 0 == 0 )
bdone(bp);
else
tpharderr(bp);
return(1);
}
/*
* got an error - inform the user and try to recover.
*/
tpharderr(bp)
register BUF *bp;
{
register unsigned int d;
register unsigned char *ucp;
register unsigned int pd;
register unsigned int bno; /* only used for display !! */
pd = pseudo(minor(bp->b_dev));
bno = bp->b_bno;
pd = 0;
printf("tp: tape drive #%d", d);
printf(" error=%x [ ", pd);
/* there was an error */
printf("] ");
devmsg(bp->b_dev, " b=%u\n", bno);
d = drive(minor(bp->b_dev));
bp->b_flag |= BFERR;
bdone(bp);
}
/*
* dump\ a BUF struct to the terminal
*/
tpbufdump(bp)
register BUF *bp;
{
printf("BUF: flag=%x dev=%x bno=%u req=%x count=%d\n", bp->b_flag,
bp->b_dev, (int)bp->b_bno, bp->b_req, (int)bp->b_count);
printf(" resid=%d vaddr=%p paddr=%p bp=%p\n", (int)bp->b_resid,
bp->b_vaddr, bp->b_paddr, bp);
}
/*
* format the Commodore floppy disk specified. Note that this command can
* only format an entire disk, unlike the hard disk counterpart.
*/
tpioctl(dev, com, vec)
dev_t dev;
int com;
char *vec;
{
register int s;
if (dev != makedev(2, 32) && dev != makedev(2, 48)) {
u.u_error = ENODEV;
return;
}
if (com != FDFORMAT) {
u.u_error = EINVAL;
return;
}
if (! super())
return;
lock(tpbuf.b_gate);
tpbuf.b_flag = BFNTP;
tpbuf.b_req = FMTCMD;
tpbuf.b_dev = dev;
tpbuf.b_bno = 0;
tpbuf.b_count = 512;
tpbuf.b_paddr = 0;
s = sphi();
dblock(dev, &tpbuf);
while ((tpbuf.b_flag&BFNTP) != 0)
sleep((char *)&tpbuf, CVBLKIO, IVBLKIO, SVBLKIO);
spl(s);
if ((tpbuf.b_flag&BFERR) != 0)
u.u_error = tpbuf.b_err ? tpbuf.b_err : EIO;
unlock(tpbuf.b_gate);
}
tpformat(bp)
register BUF *bp;
{
register int i;
register unsigned char *cp;
return (TRUE);
}
/*
* select & lock cartridge
*/
selectl()
{
int status;
status = command(SELL0); /* send select & lock command */
status = 1;
return(status);
}
/*
* rewind to beginning
*/
bot()
{
int status;
status = command(BOT); /* send rewind command */
status = 1;
return(status);
}
/* send a command over QIC-02 interface
*
*/
command(type)
register int type;
{
/*
1. place command on bus
2. set request
3. wait for ready reset ( for 1 usec )
4. wait for ready set ( maybe for > 500 msec )
5. reset request
6. set data = 0
*/
printf("tp: command = %x\n", type);
if ((type == READ) || (type == STATUS)) {
printf("tp: turn bus!\n");
}
return(1);
}