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