1*1919Swnj /* tm.c 4.1 12/17/80 */ 2*1919Swnj 3*1919Swnj #include "../conf/tm.h" 4*1919Swnj #if NTM > 0 5*1919Swnj /* 6*1919Swnj * TM tape driver 7*1919Swnj */ 8*1919Swnj 9*1919Swnj #include "../h/param.h" 10*1919Swnj #include "../h/buf.h" 11*1919Swnj #include "../h/dir.h" 12*1919Swnj #include "../h/conf.h" 13*1919Swnj #include "../h/user.h" 14*1919Swnj #include "../h/file.h" 15*1919Swnj #include "../h/map.h" 16*1919Swnj #include "../h/pte.h" 17*1919Swnj #include "../h/uba.h" 18*1919Swnj #include "../h/mtio.h" 19*1919Swnj #include "../h/ioctl.h" 20*1919Swnj #include "../h/vm.h" 21*1919Swnj 22*1919Swnj struct device { 23*1919Swnj u_short tmer; 24*1919Swnj u_short tmcs; 25*1919Swnj short tmbc; 26*1919Swnj u_short tmba; 27*1919Swnj short tmdb; 28*1919Swnj short tmrd; 29*1919Swnj }; 30*1919Swnj 31*1919Swnj #define b_repcnt b_bcount 32*1919Swnj #define b_command b_resid 33*1919Swnj 34*1919Swnj struct buf tmtab; 35*1919Swnj struct buf ctmbuf; 36*1919Swnj struct buf rtmbuf; 37*1919Swnj 38*1919Swnj int tm_ubinfo; 39*1919Swnj 40*1919Swnj /* bits in minor device */ 41*1919Swnj #define T_NOREWIND 04 42*1919Swnj #define T_1600BPI 08 43*1919Swnj 44*1919Swnj #define INF (daddr_t)1000000L 45*1919Swnj 46*1919Swnj /* 47*1919Swnj * Really only handle one tape drive... if you have more than one, 48*1919Swnj * you can make all these arrays and change the obvious things, but 49*1919Swnj * it is not clear what happens when some drives are transferring while 50*1919Swnj * others rewind, so we don't pretend that this driver handles multiple 51*1919Swnj * tape drives. 52*1919Swnj */ 53*1919Swnj char t_openf; 54*1919Swnj daddr_t t_blkno; 55*1919Swnj char t_flags; 56*1919Swnj daddr_t t_nxrec; 57*1919Swnj u_short t_erreg; 58*1919Swnj u_short t_dsreg; 59*1919Swnj short t_resid; 60*1919Swnj 61*1919Swnj /* bits in tmcs */ 62*1919Swnj #define GO 01 63*1919Swnj #define OFFL 0 64*1919Swnj #define RCOM 02 65*1919Swnj #define WCOM 04 66*1919Swnj #define WEOF 06 67*1919Swnj #define SFORW 010 68*1919Swnj #define SREV 012 69*1919Swnj #define WIRG 014 70*1919Swnj #define REW 016 71*1919Swnj #define IENABLE 0100 72*1919Swnj #define CUR 0200 73*1919Swnj #define NOP IENABLE 74*1919Swnj #define DCLR 010000 75*1919Swnj #define D800 060000 76*1919Swnj #define ERROR 0100000 77*1919Swnj 78*1919Swnj /* bits in tmer */ 79*1919Swnj #define TUR 1 80*1919Swnj #define RWS 02 81*1919Swnj #define WRL 04 82*1919Swnj #define SDWN 010 83*1919Swnj #define BOT 040 84*1919Swnj #define SELR 0100 85*1919Swnj #define NXM 0200 86*1919Swnj #define TMBTE 0400 87*1919Swnj #define RLE 01000 88*1919Swnj #define EOT 02000 89*1919Swnj #define BGL 04000 90*1919Swnj #define PAE 010000 91*1919Swnj #define CRE 020000 92*1919Swnj #define EOF 040000 93*1919Swnj #define ILC 0100000 94*1919Swnj 95*1919Swnj #define HARD (ILC|EOT) 96*1919Swnj #define SOFT (CRE|PAE|BGL|RLE|TMBTE|NXM) 97*1919Swnj 98*1919Swnj #define SSEEK 1 /* seeking */ 99*1919Swnj #define SIO 2 /* doing seq i/o */ 100*1919Swnj #define SCOM 3 /* sending control command */ 101*1919Swnj 102*1919Swnj #define LASTIOW 1 /* last op was a write */ 103*1919Swnj #define WAITREW 2 /* someone is waiting for a rewind */ 104*1919Swnj 105*1919Swnj tmopen(dev, flag) 106*1919Swnj dev_t dev; 107*1919Swnj int flag; 108*1919Swnj { 109*1919Swnj register ds, unit; 110*1919Swnj 111*1919Swnj tmtab.b_flags |= B_TAPE; 112*1919Swnj unit = minor(dev)&03; 113*1919Swnj if (unit >= NTM || t_openf) { 114*1919Swnj u.u_error = ENXIO; /* out of range or open */ 115*1919Swnj return; 116*1919Swnj } 117*1919Swnj tcommand(dev, NOP, 1); 118*1919Swnj if ((t_erreg&SELR) == 0) { 119*1919Swnj u.u_error = EIO; /* offline */ 120*1919Swnj return; 121*1919Swnj } 122*1919Swnj t_openf = 1; 123*1919Swnj if (t_erreg&RWS) 124*1919Swnj tmwaitrws(dev); /* wait for rewind complete */ 125*1919Swnj while (t_erreg&SDWN) 126*1919Swnj tcommand(dev, NOP, 1); /* await settle down */ 127*1919Swnj if ((t_erreg&TUR)==0 || 128*1919Swnj ((flag&(FREAD|FWRITE)) == FWRITE && (t_erreg&WRL))) { 129*1919Swnj TMADDR->tmcs = DCLR|GO; 130*1919Swnj u.u_error = EIO; /* offline or write protect */ 131*1919Swnj } 132*1919Swnj if (u.u_error != 0) { 133*1919Swnj t_openf = 0; 134*1919Swnj return; 135*1919Swnj } 136*1919Swnj t_blkno = (daddr_t)0; 137*1919Swnj t_nxrec = INF; 138*1919Swnj t_flags = 0; 139*1919Swnj t_openf = 1; 140*1919Swnj } 141*1919Swnj 142*1919Swnj tmwaitrws(dev) 143*1919Swnj register dev; 144*1919Swnj { 145*1919Swnj 146*1919Swnj spl5(); 147*1919Swnj for (;;) { 148*1919Swnj tcommand(dev, NOP, 1); 149*1919Swnj if ((t_erreg&RWS) == 0) { 150*1919Swnj spl0(); /* rewind complete */ 151*1919Swnj return; 152*1919Swnj } 153*1919Swnj t_flags |= WAITREW; 154*1919Swnj sleep((caddr_t)&t_flags, PRIBIO); 155*1919Swnj } 156*1919Swnj } 157*1919Swnj 158*1919Swnj tmclose(dev, flag) 159*1919Swnj register dev_t dev; 160*1919Swnj register flag; 161*1919Swnj { 162*1919Swnj 163*1919Swnj if (flag == FWRITE || ((flag&FWRITE) && (t_flags&LASTIOW))) { 164*1919Swnj tcommand(dev, WEOF, 1); 165*1919Swnj tcommand(dev, WEOF, 1); 166*1919Swnj tcommand(dev, SREV, 1); 167*1919Swnj } 168*1919Swnj if ((minor(dev)&T_NOREWIND) == 0) 169*1919Swnj tcommand(dev, REW, 1); 170*1919Swnj t_openf = 0; 171*1919Swnj } 172*1919Swnj 173*1919Swnj tcommand(dev, com, count) 174*1919Swnj dev_t dev; 175*1919Swnj int com, count; 176*1919Swnj { 177*1919Swnj register struct buf *bp; 178*1919Swnj 179*1919Swnj bp = &ctmbuf; 180*1919Swnj (void) spl5(); 181*1919Swnj while (bp->b_flags&B_BUSY) { 182*1919Swnj bp->b_flags |= B_WANTED; 183*1919Swnj sleep((caddr_t)bp, PRIBIO); 184*1919Swnj } 185*1919Swnj bp->b_flags = B_BUSY|B_READ; 186*1919Swnj (void) spl0(); 187*1919Swnj bp->b_dev = dev; 188*1919Swnj bp->b_repcnt = -count; 189*1919Swnj bp->b_command = com; 190*1919Swnj bp->b_blkno = 0; 191*1919Swnj tmstrategy(bp); 192*1919Swnj iowait(bp); 193*1919Swnj if (bp->b_flags&B_WANTED) 194*1919Swnj wakeup((caddr_t)bp); 195*1919Swnj bp->b_flags &= B_ERROR; 196*1919Swnj } 197*1919Swnj 198*1919Swnj tmstrategy(bp) 199*1919Swnj register struct buf *bp; 200*1919Swnj { 201*1919Swnj register daddr_t *p; 202*1919Swnj 203*1919Swnj tcommand(bp->b_dev, NOP, 1); 204*1919Swnj if (t_erreg&RWS) 205*1919Swnj tmwaitrws(bp->b_dev); 206*1919Swnj if (bp != &ctmbuf) { 207*1919Swnj p = &t_nxrec; 208*1919Swnj if (dbtofsb(bp->b_blkno) > *p) { 209*1919Swnj bp->b_flags |= B_ERROR; 210*1919Swnj bp->b_error = ENXIO; /* past EOF */ 211*1919Swnj iodone(bp); 212*1919Swnj return; 213*1919Swnj } else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) { 214*1919Swnj bp->b_resid = bp->b_bcount; 215*1919Swnj clrbuf(bp); /* at EOF */ 216*1919Swnj iodone(bp); 217*1919Swnj return; 218*1919Swnj } else if ((bp->b_flags&B_READ) == 0) 219*1919Swnj *p = dbtofsb(bp->b_blkno) + 1; /* write sets EOF */ 220*1919Swnj } 221*1919Swnj bp->av_forw = NULL; 222*1919Swnj (void) spl5(); 223*1919Swnj if (tmtab.b_actf == NULL) 224*1919Swnj tmtab.b_actf = bp; 225*1919Swnj else 226*1919Swnj tmtab.b_actl->av_forw = bp; 227*1919Swnj tmtab.b_actl = bp; 228*1919Swnj if (tmtab.b_active == 0) 229*1919Swnj tmstart(); 230*1919Swnj (void) spl0(); 231*1919Swnj } 232*1919Swnj 233*1919Swnj tmstart() 234*1919Swnj { 235*1919Swnj register struct buf *bp; 236*1919Swnj register cmd; 237*1919Swnj register daddr_t blkno; 238*1919Swnj 239*1919Swnj loop: 240*1919Swnj if ((bp = tmtab.b_actf) == 0) 241*1919Swnj return; 242*1919Swnj t_dsreg = TMADDR->tmcs; 243*1919Swnj t_erreg = TMADDR->tmer; 244*1919Swnj t_resid = TMADDR->tmbc; 245*1919Swnj t_flags &= ~LASTIOW; 246*1919Swnj if (t_openf < 0 || (TMADDR->tmcs&CUR) == 0) { 247*1919Swnj /* t_openf = -1; ??? */ 248*1919Swnj bp->b_flags |= B_ERROR; /* hard error'ed or !SELR */ 249*1919Swnj goto next; 250*1919Swnj } 251*1919Swnj cmd = IENABLE | GO; 252*1919Swnj if ((minor(bp->b_dev) & T_1600BPI) == 0) 253*1919Swnj cmd |= D800; 254*1919Swnj if (bp == &ctmbuf) { 255*1919Swnj if (bp->b_command == NOP) 256*1919Swnj goto next; /* just get status */ 257*1919Swnj else { 258*1919Swnj cmd |= bp->b_command; 259*1919Swnj tmtab.b_active = SCOM; 260*1919Swnj if (bp->b_command == SFORW || bp->b_command == SREV) 261*1919Swnj TMADDR->tmbc = bp->b_repcnt; 262*1919Swnj TMADDR->tmcs = cmd; 263*1919Swnj return; 264*1919Swnj } 265*1919Swnj } 266*1919Swnj if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) { 267*1919Swnj TMADDR->tmbc = -bp->b_bcount; 268*1919Swnj if (tm_ubinfo == 0) 269*1919Swnj tm_ubinfo = ubasetup(bp,1); 270*1919Swnj if ((bp->b_flags&B_READ) == 0) { 271*1919Swnj if (tmtab.b_errcnt) 272*1919Swnj cmd |= WIRG; 273*1919Swnj else 274*1919Swnj cmd |= WCOM; 275*1919Swnj } else 276*1919Swnj cmd |= RCOM; 277*1919Swnj cmd |= (tm_ubinfo >> 12) & 0x30; 278*1919Swnj tmtab.b_active = SIO; 279*1919Swnj TMADDR->tmba = tm_ubinfo; 280*1919Swnj TMADDR->tmcs = cmd; 281*1919Swnj return; 282*1919Swnj } 283*1919Swnj tmtab.b_active = SSEEK; 284*1919Swnj if (blkno < dbtofsb(bp->b_blkno)) { 285*1919Swnj cmd |= SFORW; 286*1919Swnj TMADDR->tmbc = blkno - dbtofsb(bp->b_blkno); 287*1919Swnj } else { 288*1919Swnj cmd |= SREV; 289*1919Swnj TMADDR->tmbc = dbtofsb(bp->b_blkno) - blkno; 290*1919Swnj } 291*1919Swnj TMADDR->tmcs = cmd; 292*1919Swnj return; 293*1919Swnj 294*1919Swnj next: 295*1919Swnj if (tm_ubinfo != 0) { 296*1919Swnj ubafree(tm_ubinfo); 297*1919Swnj tm_ubinfo = 0; 298*1919Swnj } 299*1919Swnj tmtab.b_actf = bp->av_forw; 300*1919Swnj iodone(bp); 301*1919Swnj goto loop; 302*1919Swnj } 303*1919Swnj 304*1919Swnj tmintr() 305*1919Swnj { 306*1919Swnj register struct buf *bp; 307*1919Swnj register state; 308*1919Swnj 309*1919Swnj if (t_flags&WAITREW && (TMADDR->tmer&RWS) == 0) { 310*1919Swnj t_flags &= ~WAITREW; 311*1919Swnj wakeup((caddr_t)&t_flags); 312*1919Swnj } 313*1919Swnj if ((bp = tmtab.b_actf) == NULL) 314*1919Swnj return; 315*1919Swnj t_dsreg = TMADDR->tmcs; 316*1919Swnj TMADDR->tmcs = IENABLE; 317*1919Swnj t_erreg = TMADDR->tmer; 318*1919Swnj t_resid = TMADDR->tmbc; 319*1919Swnj if ((bp->b_flags & B_READ) == 0) 320*1919Swnj t_flags |= LASTIOW; 321*1919Swnj state = tmtab.b_active; 322*1919Swnj tmtab.b_active = 0; 323*1919Swnj if (TMADDR->tmcs&ERROR) { 324*1919Swnj while(TMADDR->tmer & SDWN) 325*1919Swnj ; /* await settle down */ 326*1919Swnj if (TMADDR->tmer&EOF) { 327*1919Swnj tmseteof(bp); /* set blkno and nxrec */ 328*1919Swnj state = SCOM; 329*1919Swnj TMADDR->tmbc = -bp->b_bcount; 330*1919Swnj goto errout; 331*1919Swnj } 332*1919Swnj if ((bp->b_flags&B_READ) && (TMADDR->tmer&(HARD|SOFT)) == RLE) 333*1919Swnj goto out; 334*1919Swnj if ((TMADDR->tmer&HARD)==0 && state==SIO) { 335*1919Swnj if (++tmtab.b_errcnt < 3) { 336*1919Swnj if((TMADDR->tmer&SOFT) == NXM) 337*1919Swnj printf("TM UBA late error\n"); 338*1919Swnj else 339*1919Swnj t_blkno++; 340*1919Swnj if (tm_ubinfo) { 341*1919Swnj ubafree(tm_ubinfo); 342*1919Swnj tm_ubinfo = 0; 343*1919Swnj } 344*1919Swnj tmstart(); 345*1919Swnj return; 346*1919Swnj } 347*1919Swnj } else if (t_openf>0 && bp != &rtmbuf) 348*1919Swnj t_openf = -1; 349*1919Swnj deverror(bp, t_erreg, 0); 350*1919Swnj bp->b_flags |= B_ERROR; 351*1919Swnj state = SIO; 352*1919Swnj } 353*1919Swnj out: 354*1919Swnj switch (state) { 355*1919Swnj 356*1919Swnj case SIO: 357*1919Swnj t_blkno++; 358*1919Swnj /* fall into ... */ 359*1919Swnj 360*1919Swnj case SCOM: 361*1919Swnj if (bp == &ctmbuf) { 362*1919Swnj switch (bp->b_command) { 363*1919Swnj case SFORW: 364*1919Swnj t_blkno -= bp->b_repcnt; 365*1919Swnj break; 366*1919Swnj 367*1919Swnj case SREV: 368*1919Swnj t_blkno += bp->b_repcnt; 369*1919Swnj break; 370*1919Swnj 371*1919Swnj default: 372*1919Swnj if (++bp->b_repcnt < 0) { 373*1919Swnj tmstart(); /* continue */ 374*1919Swnj return; 375*1919Swnj } 376*1919Swnj } 377*1919Swnj } 378*1919Swnj errout: 379*1919Swnj tmtab.b_errcnt = 0; 380*1919Swnj tmtab.b_actf = bp->av_forw; 381*1919Swnj bp->b_resid = -TMADDR->tmbc; 382*1919Swnj if (tm_ubinfo != 0) { 383*1919Swnj ubafree(tm_ubinfo); 384*1919Swnj tm_ubinfo = 0; 385*1919Swnj } 386*1919Swnj iodone(bp); 387*1919Swnj break; 388*1919Swnj 389*1919Swnj case SSEEK: 390*1919Swnj t_blkno = dbtofsb(bp->b_blkno); 391*1919Swnj break; 392*1919Swnj 393*1919Swnj default: 394*1919Swnj return; 395*1919Swnj } 396*1919Swnj tmstart(); 397*1919Swnj } 398*1919Swnj 399*1919Swnj tmseteof(bp) 400*1919Swnj register struct buf *bp; 401*1919Swnj { 402*1919Swnj 403*1919Swnj if (bp == &ctmbuf) { 404*1919Swnj if (t_blkno > dbtofsb(bp->b_blkno)) { 405*1919Swnj /* reversing */ 406*1919Swnj t_nxrec = dbtofsb(bp->b_blkno) - TMADDR->tmbc; 407*1919Swnj t_blkno = t_nxrec; 408*1919Swnj } else { 409*1919Swnj /* spacing forward */ 410*1919Swnj t_blkno = dbtofsb(bp->b_blkno) + TMADDR->tmbc; 411*1919Swnj t_nxrec = t_blkno - 1; 412*1919Swnj } 413*1919Swnj return; 414*1919Swnj } 415*1919Swnj /* eof on read */ 416*1919Swnj t_nxrec = dbtofsb(bp->b_blkno); 417*1919Swnj } 418*1919Swnj 419*1919Swnj tmread(dev) 420*1919Swnj { 421*1919Swnj 422*1919Swnj tmphys(dev); 423*1919Swnj physio(tmstrategy, &rtmbuf, dev, B_READ, minphys); 424*1919Swnj } 425*1919Swnj 426*1919Swnj tmwrite(dev) 427*1919Swnj { 428*1919Swnj 429*1919Swnj tmphys(dev); 430*1919Swnj physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys); 431*1919Swnj } 432*1919Swnj 433*1919Swnj tmphys(dev) 434*1919Swnj { 435*1919Swnj register daddr_t a; 436*1919Swnj 437*1919Swnj a = dbtofsb(u.u_offset >> 9); 438*1919Swnj t_blkno = a; 439*1919Swnj t_nxrec = a + 1; 440*1919Swnj } 441*1919Swnj 442*1919Swnj /*ARGSUSED*/ 443*1919Swnj tmioctl(dev, cmd, addr, flag) 444*1919Swnj caddr_t addr; 445*1919Swnj dev_t dev; 446*1919Swnj { 447*1919Swnj register callcount; 448*1919Swnj int fcount; 449*1919Swnj struct mtop mtop; 450*1919Swnj struct mtget mtget; 451*1919Swnj /* we depend of the values and order of the MT codes here */ 452*1919Swnj static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL}; 453*1919Swnj 454*1919Swnj switch(cmd) { 455*1919Swnj case MTIOCTOP: /* tape operation */ 456*1919Swnj if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { 457*1919Swnj u.u_error = EFAULT; 458*1919Swnj return; 459*1919Swnj } 460*1919Swnj switch(mtop.mt_op) { 461*1919Swnj case MTWEOF: case MTFSF: case MTBSF: 462*1919Swnj callcount = mtop.mt_count; 463*1919Swnj fcount = INF; 464*1919Swnj break; 465*1919Swnj case MTFSR: case MTBSR: 466*1919Swnj callcount = 1; 467*1919Swnj fcount = mtop.mt_count; 468*1919Swnj break; 469*1919Swnj case MTREW: case MTOFFL: 470*1919Swnj callcount = 1; 471*1919Swnj fcount = 1; 472*1919Swnj break; 473*1919Swnj default: 474*1919Swnj u.u_error = ENXIO; 475*1919Swnj return; 476*1919Swnj } 477*1919Swnj if (callcount <= 0 || fcount <= 0) 478*1919Swnj u.u_error = ENXIO; 479*1919Swnj else while (--callcount >= 0) { 480*1919Swnj tcommand(dev, tmops[mtop.mt_op], fcount); 481*1919Swnj if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) && 482*1919Swnj ctmbuf.b_resid) { 483*1919Swnj u.u_error = EIO; 484*1919Swnj break; 485*1919Swnj } 486*1919Swnj if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT) 487*1919Swnj break; 488*1919Swnj } 489*1919Swnj geterror(&ctmbuf); 490*1919Swnj return; 491*1919Swnj case MTIOCGET: 492*1919Swnj mtget.mt_dsreg = t_dsreg; 493*1919Swnj mtget.mt_erreg = t_erreg; 494*1919Swnj mtget.mt_resid = t_resid; 495*1919Swnj if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) 496*1919Swnj u.u_error = EFAULT; 497*1919Swnj return; 498*1919Swnj default: 499*1919Swnj u.u_error = ENXIO; 500*1919Swnj } 501*1919Swnj } 502*1919Swnj 503*1919Swnj #define DBSIZE 20 504*1919Swnj 505*1919Swnj twall(start, num) 506*1919Swnj int start, num; 507*1919Swnj { 508*1919Swnj #if VAX==780 509*1919Swnj register struct uba_regs *up = (struct uba_regs *)PHYSUBA0; 510*1919Swnj #endif 511*1919Swnj int blk; 512*1919Swnj 513*1919Swnj TMPHYS->tmcs = DCLR | GO; 514*1919Swnj #if VAX==780 515*1919Swnj up->uba_cr = ADINIT; 516*1919Swnj up->uba_cr = IFS|BRIE|USEFIE|SUEFIE; 517*1919Swnj while ((up->uba_cnfgr & UBIC) == 0) 518*1919Swnj ; 519*1919Swnj #endif 520*1919Swnj while (num > 0) { 521*1919Swnj blk = num > DBSIZE ? DBSIZE : num; 522*1919Swnj tmdwrite(start, blk); 523*1919Swnj start += blk; 524*1919Swnj num -= blk; 525*1919Swnj } 526*1919Swnj } 527*1919Swnj 528*1919Swnj tmdwrite(buf, num) 529*1919Swnj register buf, num; 530*1919Swnj { 531*1919Swnj register int *io, npf; 532*1919Swnj tmwait(); 533*1919Swnj /* Flush buffered data path 0 */ 534*1919Swnj ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] = 0; 535*1919Swnj ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] = BNE; 536*1919Swnj /* Map unibus address 0 to section of interest */ 537*1919Swnj io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map; 538*1919Swnj npf = num+1; 539*1919Swnj while(--npf != 0) 540*1919Swnj *io++ = (int)(buf++ | (1<<21) | MRV); 541*1919Swnj *io = 0; 542*1919Swnj TMPHYS->tmbc = -(num*NBPG); 543*1919Swnj TMPHYS->tmba = 0; 544*1919Swnj TMPHYS->tmcs = WCOM | GO | D800; 545*1919Swnj } 546*1919Swnj 547*1919Swnj tmwait() 548*1919Swnj { 549*1919Swnj register short s; 550*1919Swnj 551*1919Swnj do 552*1919Swnj s = TMPHYS->tmcs; 553*1919Swnj while ((s & CUR) == 0); 554*1919Swnj } 555*1919Swnj 556*1919Swnj tmrewind() 557*1919Swnj { 558*1919Swnj 559*1919Swnj tmwait(); 560*1919Swnj TMPHYS->tmcs = REW | GO; 561*1919Swnj } 562*1919Swnj 563*1919Swnj tmeof() 564*1919Swnj { 565*1919Swnj 566*1919Swnj tmwait(); 567*1919Swnj TMPHYS->tmcs = WEOF | GO | D800; 568*1919Swnj } 569*1919Swnj #endif 570