|
|
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: 9095 (0x2387)
Types: TextFile
Notes: UNIX file
Names: »ieee.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦2d53db1df⟧ UNIX Filesystem
└─⟦this⟧ »frankh/src/ieee/ieee.c«
/*
*
*
*
*/
#define FMTCMD 3 /* for ieioctl */
#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 ieload();
int ieuload();
int ieopen();
int ieread();
int iewrite();
int ieblock();
int ieintr();
int ieioctl();
int nulldev();
int nonedev();
char *pfix(); /* map phys addr to a char * */
daddr_t iebno(); /* returns actual block offset */
CON iecon = {
DFBLK|DFCHR, /* Flags */
11, /* Major index */
ieopen, /* Open */
nulldev, /* Close */
ieblock, /* Block */
ieread, /* Read */
iewrite, /* Write */
ieioctl, /* Ioctl */
nulldev, /* Powerfail */
nulldev, /* Timeout */
ieload, /* Load */
ieuload /* 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 IEEEVEC 0x80 /* base of ie 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; /* Ouieut pointer */
char lpflag; /* Flags */
char lpbuf[MAXBUF]; /* Buffer */
} LP;
extern LP *lp;
/* lpflag bits */
#define LPOPEN 0x01 /* Printer is open */
/*
* housekeeping
*/
typedef struct ieunit {
bool ieu_active; /* drive/controller busy */
bool ieu_dma_aligned;/* dma address is 512 aligned */
struct ieunit *ieu_forw; /* next drive in controller chain */
struct ieunit *ieu_back; /* last drive */
BUF *ieu_actf; /* next BUF in drive chain */
paddr_t ieu_paddr; /* physical address of buffer */
} WDU;
WDU ieutab[NDRIVES]; /* drive headers */
BUF iebuf; /* BUF structure */
/*
* set up the driver.
*
*/
ieload()
{
register int i;
printf("ieload: 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(IEEEVEC, ieintr); */
outb(MICR | CIO1, inb(MICR | CIO1) & 0x7F);
outb(MCCR | CIO1, inb(MCCR | CIO1) | 0x94);
printf("Interrupts off\n");
outb(PADPP | CIO1, 0);
outb(PADD | CIO1, 0xFF);
printf("Port A set\n");
outb(PBDPP | CIO1, inb(PBDPP | CIO1) & 0xFC);
outb(PBDD | CIO1, inb(PBDD | CIO1) | 0xFC);
printf("Port B set\n");
outb(PCD | CIO1, inb(PCD | CIO1) & 0x08);
outb(PCDPP | CIO1, inb(PCDPP | CIO1) & 0x08);
outb(PCDD | CIO1, inb(PCDD | CIO1) & 0x08);
outb(PCD | CIO1, inb(PCD | CIO1) & 0x08);
printf("Port C set\n");
outb(PCD | CIO1, (inb(PCD | CIO1) | 0x01) & 0x0F);
printf("IFC = 1\n");
for ( i = 0; i < 100; ++i)
;
printf("done sleep\n");
outb(PCD | CIO1, inb(PCD| CIO1) & 0x0E);
printf("IFC = 0\n");
}
svp(pos, add)
int pos;
unsigned int add;
{
savport[pos].padd = add;
if (add)
savport[pos].pdata = inb(add);
else
savport[pos].pdata = 0;
}
ieuload()
{
register int cnt = 0;
printf("ieuload: 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.
*
*/
ieopen(dev, mode)
dev_t dev;
{
register unsigned int d; /* drive # */
d = drive(minor(dev));
printf("ieopen: 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
*/
ieread(dev, iop)
dev_t dev;
IO *iop;
{
printf("ieread: begin\n");
ioreq(&iebuf, iop, dev, BREAD, BFIOC|BFBLK|BFRAW);
}
/*
* perform a RAW read operation
*/
iewrite(dev, iop)
dev_t dev;
IO *iop;
{
printf("iewrite: begin\n");
ioreq(&iebuf, iop, dev, BWRITE, BFIOC|BFBLK|BFRAW);
}
/*
* block I/O routine.
*/
ieblock(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 iestart();
d = drive(minor(bp->b_dev));
pd = pseudo(minor(bp->b_dev));
bno = bp->b_bno;
/* printf("ieblock: d=%d, pd=%d, bno=%d enter\n", d, pd, (int)bno);
iebufdump(bp); */
if (d >= NDRIVES) {
bp->b_flag |= BFERR;
bdone(bp);
return;
}
s = sphi();
while (!(fh = iestart(bp)))
;
spl(s);
/* printf("*buf = %s\n", bp->b_vaddr); */
}
/*
* Do the actual tape read/write.
*
*/
bool
iestart(bp)
register BUF *bp;
{
register unsigned int d, pd, cmd;
int dma_error = FALSE;
/* printf("iestart: begin\n"); */
if (bp->b_flag&BFRAW) {
printf("ie: RAW I/O not supported\n");
bp->b_flag |= BFERR;
bdone(bp);
}
printf("iestart: block = %u req = %x\n", (int)bp->b_bno, bp->b_req);
/* iebufdump(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 ieformat(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 (ieintr(bp));
}
/*
* got an interrupt from the controller - see if it was a valid I/O
* completion or an error.
*/
ieintr(bp)
register BUF *bp;
{
register unsigned int d;
/* printf("ieintr: begin\n"); */
d = drive(minor(bp->b_dev));
if ( 0 == 0 )
bdone(bp);
else
ieharderr(bp);
return(1);
}
/*
* got an error - inform the user and try to recover.
*/
ieharderr(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("ie: 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
*/
iebufdump(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.
*/
ieioctl(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(iebuf.b_gate);
iebuf.b_flag = BFNTP;
iebuf.b_req = FMTCMD;
iebuf.b_dev = dev;
iebuf.b_bno = 0;
iebuf.b_count = 512;
iebuf.b_paddr = 0;
s = sphi();
dblock(dev, &iebuf);
while ((iebuf.b_flag&BFNTP) != 0)
sleep((char *)&iebuf, CVBLKIO, IVBLKIO, SVBLKIO);
spl(s);
if ((iebuf.b_flag&BFERR) != 0)
u.u_error = iebuf.b_err ? iebuf.b_err : EIO;
unlock(iebuf.b_gate);
}
ieformat(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("ie: command = %x\n", type);
if ((type == READ) || (type == STATUS)) {
printf("ie: turn bus!\n");
}
return(1);
}