DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦b57b0ab75⟧ TextFile

    Length: 8381 (0x20bd)
    Types: TextFile
    Notes: UNIX file
    Names: »tp.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦2d53db1df⟧ UNIX V7 Filesystem
        └─ ⟦this⟧ »frankh/src/ieee/tp.c« 
        └─ ⟦this⟧ »frankh/src/tape_drive/tp.c« 

TextFile

/*
 * 
 *
 *
 */

#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);
}