1*45553Sbill #include "wt.h" 2*45553Sbill #if NWT > 0 3*45553Sbill /* 4*45553Sbill * Mach Operating System 5*45553Sbill * Copyright (c) 1989 Carnegie-Mellon University 6*45553Sbill * All rights reserved. The CMU software License Agreement specifies 7*45553Sbill * the terms and conditions for use and redistribution. 8*45553Sbill * @(#)wt.c 1.1 (Berkeley) 11/08/90 9*45553Sbill */ 10*45553Sbill /* 11*45553Sbill * HISTORY 12*45553Sbill * $Log: wt.c,v $ 13*45553Sbill * Revision 2.2.1.3 90/01/08 13:29:38 rvb 14*45553Sbill * Add Intel copyright. 15*45553Sbill * [90/01/08 rvb] 16*45553Sbill * 17*45553Sbill * Revision 2.2.1.2 89/12/21 18:00:09 rvb 18*45553Sbill * Change WTPRI to make the streamer tape read/write 19*45553Sbill * interruptible. [lin] 20*45553Sbill * 21*45553Sbill * Revision 2.2.1.1 89/11/10 09:49:49 rvb 22*45553Sbill * ORC likes their streamer port at 0x288. 23*45553Sbill * [89/11/08 rvb] 24*45553Sbill * 25*45553Sbill * Revision 2.2 89/09/25 12:33:02 rvb 26*45553Sbill * Driver was provided by Intel 9/18/89. 27*45553Sbill * [89/09/23 rvb] 28*45553Sbill * 29*45553Sbill */ 30*45553Sbill 31*45553Sbill /* 32*45553Sbill * 33*45553Sbill * Copyright 1988, 1989 by Intel Corporation 34*45553Sbill * 35*45553Sbill * Support Bell Tech QIC-02 and WANGTEK QIC-36 or QIC-02 36*45553Sbill */ 37*45553Sbill 38*45553Sbill #include <sys/errno.h> 39*45553Sbill #include <sys/signal.h> 40*45553Sbill #include <sys/types.h> 41*45553Sbill #include <sys/param.h> 42*45553Sbill #include <sys/buf.h> 43*45553Sbill #include <sys/dir.h> 44*45553Sbill #include <sys/user.h> 45*45553Sbill #include <sys/file.h> 46*45553Sbill #include <sys/proc.h> 47*45553Sbill #include <machine/isa/wtreg.h> 48*45553Sbill 49*45553Sbill #ifdef ORC 50*45553Sbill unsigned wtport = 0x288; /* base I/O port of controller */ 51*45553Sbill #else ORC 52*45553Sbill unsigned wtport = 0x300; /* base I/O port of controller */ 53*45553Sbill #endif ORC 54*45553Sbill /* standard = 0x300 */ 55*45553Sbill /* alternate = 0x338 */ 56*45553Sbill 57*45553Sbill unsigned wtchan = 1; /* DMA channel number */ 58*45553Sbill /* stardard = 1 */ 59*45553Sbill /* hardware permits 1, 2 or 3. */ 60*45553Sbill /* (Avoid DMA 2: used by disks) */ 61*45553Sbill 62*45553Sbill int first_wtopen_ever = 1; 63*45553Sbill 64*45553Sbill 65*45553Sbill #define ERROR 1 /* return from tape routines */ 66*45553Sbill #define SUCCESS 0 /* return from tape routines */ 67*45553Sbill 68*45553Sbill int wci = 0; 69*45553Sbill int exflag = 0; 70*45553Sbill int bytes = 0; 71*45553Sbill 72*45553Sbill static unsigned char eqdma = 0x8; 73*45553Sbill static unsigned char pagereg = 0x83; 74*45553Sbill static unsigned char dmareg = 2; 75*45553Sbill static unsigned char dma_write = 0x49; 76*45553Sbill static unsigned char dma_read = 0x45; 77*45553Sbill static unsigned char dma_done = 2; 78*45553Sbill static unsigned char mode = 0; 79*45553Sbill static unsigned char mbits; /* map bits into each other */ 80*45553Sbill static long bufptr; 81*45553Sbill static unsigned numbytes; 82*45553Sbill /* 83*45553Sbill _wci dw 0 ; interrupt chain finished normally 84*45553Sbill _exflag dw 0 ; exception variable 85*45553Sbill _bytes dw 0 ; current bytes 86*45553Sbill 87*45553Sbill eqdma db 8h ; enable dma command: ch1,ch2=8h, ch3=10h 88*45553Sbill pagereg db 83h ; ch1=83h, ch2=81h, ch3=82h 89*45553Sbill dmareg db 2 ; ch1=2, ch2=4, ch3=6 90*45553Sbill dma_write db 49h ; write dma command: 48h+_wtchan 91*45553Sbill dma_read db 45h ; read dma command: 44h+_wtchan 92*45553Sbill dma_done db 2 ; dma done flag: 1<<_wtchan 93*45553Sbill mode db 0 ; dma operation mode 94*45553Sbill lbufptr dw 0 ; buffer pointer to data buffers, low word 95*45553Sbill hbufptr dw 0 ; buffer pointer to data buffers, high word 96*45553Sbill numbytes dw 0 ; number of bytes to read or write (new) 97*45553Sbill */ 98*45553Sbill 99*45553Sbill #define PAGESIZ 4096 100*45553Sbill #define HZ 60 101*45553Sbill 102*45553Sbill /* tape controller ports */ 103*45553Sbill #define STATPORT wtport 104*45553Sbill #define CTLPORT STATPORT 105*45553Sbill #define CMDPORT (wtport+1) 106*45553Sbill #define DATAPORT CMDPORT 107*45553Sbill 108*45553Sbill /* defines for reading out status from wangtek tape controller */ 109*45553Sbill #define READY 0x01 /* ready bit define */ 110*45553Sbill #define EXCEP 0x02 /* exception bit define */ 111*45553Sbill #define STAT (READY|EXCEP) 112*45553Sbill #define RESETMASK 0x7 113*45553Sbill #define RESETVAL (RESETMASK & ~EXCEP) 114*45553Sbill 115*45553Sbill /* tape controller control bits (CTLPORT) */ 116*45553Sbill #define ONLINE 0x01 117*45553Sbill #define RESET 0x02 118*45553Sbill #define REQUEST 0x04 /* request command */ 119*45553Sbill #define CMDOFF 0xC0 120*45553Sbill 121*45553Sbill /* QIC-02 commands (CMDPORT) */ 122*45553Sbill #define RDDATA 0x80 /* read data */ 123*45553Sbill #define READFM 0xA0 /* read file mark */ 124*45553Sbill #define WRTDATA 0x40 /* write data */ 125*45553Sbill #define WRITEFM 0x60 /* write file mark */ 126*45553Sbill #define RDSTAT 0xC0 /* read status command */ 127*45553Sbill #define REWIND 0x21 /* rewind command (position+bot) */ 128*45553Sbill 129*45553Sbill /* 8237 DMA controller regs */ 130*45553Sbill #define STATUSREG 0x8 131*45553Sbill #define MASKREG 0xA 132*45553Sbill #define MODEREG 0xB 133*45553Sbill #define CLEARFF 0xC 134*45553Sbill 135*45553Sbill /* streamer tape block size */ 136*45553Sbill #define BLKSIZE 512 137*45553Sbill 138*45553Sbill /* Tape characteristics */ 139*45553Sbill #define NBPS 512 /* 512-byte blocks */ 140*45553Sbill #define ERROR 1 /* return from tape routines */ 141*45553Sbill #define SUCCESS 0 /* return from tape routines */ 142*45553Sbill 143*45553Sbill /* Minor devs */ 144*45553Sbill #define TP_REWCLOSE(d) ((minor(d)&04) == 0) /* Rewind tape on close if read/write */ 145*45553Sbill #define TP_DENS(dev) ((minor(dev) >> 3) & 03) /* set density */ 146*45553Sbill #define TPHOG(d) 0 /* use Hogproc during tape I/O */ 147*45553Sbill 148*45553Sbill /* defines for wtflags */ 149*45553Sbill #define TPINUSE 0x0001 /* tape is already open */ 150*45553Sbill #define TPREAD 0x0002 /* tape is only open for reading */ 151*45553Sbill #define TPWRITE 0x0004 /* tape is only open for writing */ 152*45553Sbill #define TPSTART 0x0008 /* tape must be rewound and reset */ 153*45553Sbill #define TPDEAD 0x0010 /* tape drive does not work or driver error */ 154*45553Sbill #define TPSESS 0x0020 /* no more reads or writes allowed in session */ 155*45553Sbill /* for example, when tape has to be changed */ 156*45553Sbill #define TPSTOP 0x0040 /* Stop command outstanding */ 157*45553Sbill #define TPREW 0x0080 /* Rewind command outstanding, see wtdsl2() */ 158*45553Sbill #define TPVOL 0x0100 /* Read file mark, or hit end of tape */ 159*45553Sbill #define TPWO 0x0200 /* write command outstanding */ 160*45553Sbill #define TPRO 0x0400 /* read command outstanding */ 161*45553Sbill #define TPWANY 0x0800 /* write command requested */ 162*45553Sbill #define TPRANY 0x1000 /* read command requested */ 163*45553Sbill #define TPWP 0x2000 /* write protect error seen */ 164*45553Sbill 165*45553Sbill unsigned int wtflags = TPSTART; /* state of tape drive */ 166*45553Sbill 167*45553Sbill struct buf rwtbuf; /* header for raw i/o */ 168*45553Sbill struct proc *myproc; /* process which opened tape driver */ 169*45553Sbill 170*45553Sbill char wtimeron; /* wtimer() active flag */ 171*45553Sbill char wtio; /* dma (i/o) active flag */ 172*45553Sbill char isrlock; /* isr() flag */ 173*45553Sbill 174*45553Sbill struct proc * Hogproc; /* no Hogproc on Microport */ 175*45553Sbill #define ftoseg(x) ((unsigned) (x >> 16)) 176*45553Sbill #define seterror(err) u.u_error = err 177*45553Sbill 178*45553Sbill struct wtstatus { 179*45553Sbill ushort wt_err; /* code for error encountered */ 180*45553Sbill ushort wt_ercnt; /* number of error blocks */ 181*45553Sbill ushort wt_urcnt; /* number of underruns */ 182*45553Sbill } wterror; 183*45553Sbill 184*45553Sbill /* defines for wtstatus.wt_err */ 185*45553Sbill #define TP_POR 0x100 /* Power on/reset occurred */ 186*45553Sbill #define TP_RES1 0x200 /* Reserved for end of media */ 187*45553Sbill #define TP_RES2 0x400 /* Reserved for bus parity */ 188*45553Sbill #define TP_BOM 0x800 /* Beginning of media */ 189*45553Sbill #define TP_MBD 0x1000 /* Marginal block detected */ 190*45553Sbill #define TP_NDT 0x2000 /* No data detected */ 191*45553Sbill #define TP_ILL 0x4000 /* Illegal command */ 192*45553Sbill #define TP_ST1 0x8000 /* Status byte 1 bits */ 193*45553Sbill #define TP_FIL 0x01 /* File mark detected */ 194*45553Sbill #define TP_BNL 0x02 /* Bad block not located */ 195*45553Sbill #define TP_UDA 0x04 /* Unrecoverable data error */ 196*45553Sbill #define TP_EOM 0x08 /* End of media */ 197*45553Sbill #define TP_WRP 0x10 /* Write protected cartridge */ 198*45553Sbill #define TP_USL 0x20 /* Unselected drive */ 199*45553Sbill #define TP_CNI 0x40 /* Cartridge not in place */ 200*45553Sbill #define TP_ST0 0x80 /* Status byte 0 bits */ 201*45553Sbill 202*45553Sbill /* Grounds for reporting I/O error to user */ 203*45553Sbill #define TP_ERR0 (TP_BNL|TP_UDA|TP_WRP|TP_CNI|TP_FIL|TP_EOM|TP_USL) 204*45553Sbill #define TP_ERR1 (TP_MBD|TP_NDT|TP_ILL) 205*45553Sbill /* TP_ILL should never happen! */ 206*45553Sbill /* 207*45553Sbill #define TP_ERR0 0x7f 208*45553Sbill #define TP_ERR1 0x7700 209*45553Sbill */ 210*45553Sbill 211*45553Sbill /* defines for reading out status from wangtek tape controller */ 212*45553Sbill #define READY 0x01 /* ready bit define */ 213*45553Sbill #define EXCEP 0x02 /* exception bit define */ 214*45553Sbill 215*45553Sbill /* sleep priority */ 216*45553Sbill #define WTPRI (PZERO+10) 217*45553Sbill 218*45553Sbill char pagebuf[NBPS]; /* buffer of size NBPS */ 219*45553Sbill unsigned long pageaddr; /* physical addr of pagebuf */ 220*45553Sbill /* pageaddr is used with DMA controller */ 221*45553Sbill time_t Hogtime; /* lbolt when Hog timer started */ 222*45553Sbill extern time_t lbolt; 223*45553Sbill 224*45553Sbill #define debug printf 225*45553Sbill 226*45553Sbill /* 227*45553Sbill * Strategy routine. 228*45553Sbill * 229*45553Sbill * Arguments: 230*45553Sbill * Pointer to buffer structure 231*45553Sbill * Function: 232*45553Sbill * Start transfer. 233*45553Sbill * 234*45553Sbill * It would be nice to have this multiple-threaded. 235*45553Sbill * There is a version of dump from Berkeley that works with multiple processes 236*45553Sbill * trading off with disk & tape I/O. 237*45553Sbill */ 238*45553Sbill 239*45553Sbill int 240*45553Sbill wtstrategy(bp) 241*45553Sbill register struct buf *bp; 242*45553Sbill { 243*45553Sbill unsigned ucnt1, ucnt2, finished; 244*45553Sbill unsigned long adr1, adr2; 245*45553Sbill 246*45553Sbill adr1 = kvtop(bp->b_un.b_addr); 247*45553Sbill #ifdef DEBUG 248*45553Sbill debug("bpaddr %x\n", adr1); 249*45553Sbill #endif 250*45553Sbill ucnt1 = bp->b_bcount; 251*45553Sbill ucnt2 = 0; 252*45553Sbill adr2 = 0; 253*45553Sbill #ifdef DEBUG 254*45553Sbill debug("WTstart: adr1 %lx cnt %x\n", adr1, ucnt1); 255*45553Sbill #endif 256*45553Sbill if (ftoseg(adr1) != ftoseg(adr1 + (unsigned) ucnt1 - 1)) 257*45553Sbill { 258*45553Sbill adr2 = (adr1 & 0xffff0000L) + 0x10000L; 259*45553Sbill ucnt2 = (adr1 + ucnt1) - adr2; 260*45553Sbill ucnt1 -= ucnt2; 261*45553Sbill } 262*45553Sbill /* at file marks and end of tape, we just return '0 bytes available' */ 263*45553Sbill if (wtflags & TPVOL) { 264*45553Sbill bp->b_resid = bp->b_bcount; 265*45553Sbill goto xit; 266*45553Sbill } 267*45553Sbill if ((Hogproc == (struct proc *) 0) && TPHOG(bp->b_dev)) 268*45553Sbill { 269*45553Sbill #ifdef DEBUG 270*45553Sbill printf("setting Hogproc\n"); 271*45553Sbill #endif 272*45553Sbill Hogtime = 0; 273*45553Sbill Hogproc = myproc; 274*45553Sbill } 275*45553Sbill if (bp->b_flags & B_READ) { 276*45553Sbill int bad = 0; 277*45553Sbill 278*45553Sbill /* For now, we assume that all data will be copied out */ 279*45553Sbill /* If read command outstanding, just skip down */ 280*45553Sbill if (!(wtflags & TPRO)) { 281*45553Sbill if (ERROR == wtsense(TP_WRP)) /* clear status */ 282*45553Sbill goto errxit; 283*45553Sbill #ifdef DEBUG 284*45553Sbill debug("WTread: Start read\n"); 285*45553Sbill #endif 286*45553Sbill if (!(wtflags & TPREAD) || (wtflags & TPWANY) || 287*45553Sbill (rstart() == ERROR)) { 288*45553Sbill #ifdef DEBUG 289*45553Sbill debug("Tpstart: read init error\n"); /* */ 290*45553Sbill #endif 291*45553Sbill goto errxit; 292*45553Sbill } 293*45553Sbill wtflags |= TPRO|TPRANY; 294*45553Sbill } 295*45553Sbill 296*45553Sbill finished = 0; 297*45553Sbill /* Take a deep breath */ 298*45553Sbill if (ucnt1) { 299*45553Sbill if ((rtape(adr1, ucnt1) == ERROR) && 300*45553Sbill (wtsense(TP_WRP) == ERROR)) 301*45553Sbill goto endio; 302*45553Sbill /* wait for it */ 303*45553Sbill bad = pollrdy(); 304*45553Sbill finished = bytes; 305*45553Sbill if (bad) 306*45553Sbill goto endio; 307*45553Sbill } 308*45553Sbill /* if a second I/O region, start it */ 309*45553Sbill if (ucnt2) { 310*45553Sbill if ((rtape(adr2, ucnt2) == ERROR) && 311*45553Sbill (wtsense(TP_WRP) == ERROR)) 312*45553Sbill ucnt2 = 0; /* don't poll for me */ 313*45553Sbill } 314*45553Sbill 315*45553Sbill /* if second i/o pending wait for it */ 316*45553Sbill if (ucnt2) { 317*45553Sbill pollrdy(); 318*45553Sbill /* whether pollrdy is ok or not */ 319*45553Sbill finished += bytes; 320*45553Sbill } 321*45553Sbill } else { 322*45553Sbill if (wtflags & TPWP) /* write protected */ 323*45553Sbill goto errxit; 324*45553Sbill 325*45553Sbill /* If write command outstanding, just skip down */ 326*45553Sbill if (!(wtflags & TPWO)) { 327*45553Sbill if (ERROR == wtsense(0)) /* clear status */ 328*45553Sbill { 329*45553Sbill #ifdef DEBUG 330*45553Sbill debug("TPstart: sense 0\n"); 331*45553Sbill #endif 332*45553Sbill goto errxit; 333*45553Sbill } 334*45553Sbill if (!(wtflags & TPWRITE) || (wtflags & TPRANY) || 335*45553Sbill (wstart() == ERROR)) { 336*45553Sbill #ifdef DEBUG 337*45553Sbill debug("Tpstart: write init error\n"); /* */ 338*45553Sbill #endif 339*45553Sbill wtsense(0); 340*45553Sbill 341*45553Sbill errxit: bp->b_flags |= B_ERROR; 342*45553Sbill bp->b_resid = bp->b_bcount; 343*45553Sbill goto xit; 344*45553Sbill } 345*45553Sbill wtflags |= TPWO|TPWANY; 346*45553Sbill } 347*45553Sbill 348*45553Sbill /* and hold your nose */ 349*45553Sbill if (ucnt1 && ((wtape(adr1, ucnt1) == ERROR) 350*45553Sbill && (wtsense(0) == ERROR))) 351*45553Sbill finished = bytes; 352*45553Sbill 353*45553Sbill else if (ucnt2 && 354*45553Sbill (((ucnt1 && pollrdy()) || 355*45553Sbill (wtape(adr2, ucnt2) == ERROR)) && 356*45553Sbill (wtsense(0) == ERROR))) 357*45553Sbill finished = ucnt1 + NBPS + bytes; 358*45553Sbill /* All writes and/or copyins were fine! */ 359*45553Sbill else 360*45553Sbill finished = bp->b_bcount; 361*45553Sbill pollrdy(); 362*45553Sbill } 363*45553Sbill 364*45553Sbill endio: 365*45553Sbill wterror.wt_err = 0; 366*45553Sbill if (exflag && wtsense((bp->b_flags & B_READ) ? TP_WRP : 0)) { 367*45553Sbill if ((wterror.wt_err & TP_ST0) 368*45553Sbill && (wterror.wt_err & (TP_FIL|TP_EOM))) { 369*45553Sbill #ifdef DEBUG 370*45553Sbill debug("WTsta: Hit end of tape\n"); /* */ 371*45553Sbill #endif 372*45553Sbill wtflags |= TPVOL; 373*45553Sbill if (wterror.wt_err & TP_FIL) { 374*45553Sbill if (wtflags & TPRO) 375*45553Sbill /* interrupter is bogus */ 376*45553Sbill rstart(); /* restart read command */ 377*45553Sbill else 378*45553Sbill wtflags &= ~TPWO; 379*45553Sbill finished += NBPS; 380*45553Sbill } 381*45553Sbill /* Reading file marks or writing end of tape return 0 bytes */ 382*45553Sbill } else { 383*45553Sbill bp->b_flags |= B_ERROR; 384*45553Sbill wtflags &= ~(TPWO|TPRO); 385*45553Sbill } 386*45553Sbill } 387*45553Sbill 388*45553Sbill bp->b_resid = bp->b_bcount - finished; 389*45553Sbill xit: 390*45553Sbill biodone(bp); 391*45553Sbill if (wtimeron) 392*45553Sbill Hogtime = lbolt; 393*45553Sbill else if (Hogproc == myproc) 394*45553Sbill Hogproc = (struct proc *) 0; 395*45553Sbill } 396*45553Sbill 397*45553Sbill /* 398*45553Sbill * simulate an interrupt periodically while I/O is going 399*45553Sbill * this is necessary in case interrupts get eaten due to 400*45553Sbill * multiple devices on a single IRQ line 401*45553Sbill */ 402*45553Sbill wtimer() 403*45553Sbill { 404*45553Sbill /* If I/O going and not in isr(), simulate interrupt 405*45553Sbill * If no I/O for at least 1 second, stop being a Hog 406*45553Sbill * If I/O done and not a Hog, turn off wtimer() 407*45553Sbill */ 408*45553Sbill if (wtio && !isrlock) 409*45553Sbill isr(); 410*45553Sbill 411*45553Sbill if ((Hogproc == myproc) && Hogtime && (lbolt-Hogtime > HZ)) 412*45553Sbill Hogproc = (struct proc *) 0; 413*45553Sbill 414*45553Sbill if (wtio || (Hogproc == myproc)) 415*45553Sbill timeout(wtimer, (caddr_t) 0, HZ); 416*45553Sbill else 417*45553Sbill wtimeron = 0; 418*45553Sbill } 419*45553Sbill 420*45553Sbill 421*45553Sbill wtrawio(bp) 422*45553Sbill struct buf *bp; 423*45553Sbill { 424*45553Sbill wtstrategy(bp); 425*45553Sbill biowait(bp); 426*45553Sbill return(0); 427*45553Sbill } 428*45553Sbill 429*45553Sbill wt_minphys(bp) 430*45553Sbill struct buf *bp; 431*45553Sbill { 432*45553Sbill if (bp->b_bcount > PAGESIZ) 433*45553Sbill bp->b_bcount = PAGESIZ; 434*45553Sbill } 435*45553Sbill 436*45553Sbill /* 437*45553Sbill * raw read routine 438*45553Sbill */ 439*45553Sbill wtread(dev, uio) 440*45553Sbill struct uio *uio; 441*45553Sbill { 442*45553Sbill if (wtflags & TPSESS) { 443*45553Sbill seterror(EIO); 444*45553Sbill return(EIO); 445*45553Sbill } 446*45553Sbill physio(wtrawio, &rwtbuf, dev, B_READ, wt_minphys, uio); 447*45553Sbill return(0); 448*45553Sbill } 449*45553Sbill 450*45553Sbill /* 451*45553Sbill * raw write routine 452*45553Sbill */ 453*45553Sbill wtwrite(dev, uio) 454*45553Sbill struct uio *uio; 455*45553Sbill { 456*45553Sbill if (wtflags & TPSESS) { 457*45553Sbill seterror(EIO); 458*45553Sbill return(EIO); 459*45553Sbill } 460*45553Sbill physio(wtrawio, &rwtbuf, dev, B_WRITE, wt_minphys, uio); 461*45553Sbill return(0); 462*45553Sbill } 463*45553Sbill 464*45553Sbill 465*45553Sbill 466*45553Sbill /* 467*45553Sbill * ioctl routine 468*45553Sbill * for user level QIC commands only 469*45553Sbill */ 470*45553Sbill wtioctl(dev, cmd, arg, mode) 471*45553Sbill int dev, cmd; 472*45553Sbill unsigned long arg; 473*45553Sbill int mode; 474*45553Sbill { 475*45553Sbill if (cmd == WTQICMD) 476*45553Sbill { 477*45553Sbill if ((qicmd((int)arg) == ERROR) || (rdyexc(HZ) == ERROR)) 478*45553Sbill { 479*45553Sbill wtsense(0); 480*45553Sbill seterror(EIO); 481*45553Sbill } 482*45553Sbill return; 483*45553Sbill } 484*45553Sbill seterror(EINVAL); 485*45553Sbill } 486*45553Sbill 487*45553Sbill /* 488*45553Sbill * open routine 489*45553Sbill * called on every device open 490*45553Sbill */ 491*45553Sbill wtopen(dev, flag) 492*45553Sbill int dev, flag; 493*45553Sbill { 494*45553Sbill if (first_wtopen_ever) { 495*45553Sbill wtinit(); 496*45553Sbill first_wtopen_ever = 0; 497*45553Sbill } 498*45553Sbill #ifdef DEBUG 499*45553Sbill printf("wtopen ...\n"); 500*45553Sbill #endif 501*45553Sbill if (!pageaddr) { 502*45553Sbill nodev(); 503*45553Sbill return(ENXIO); 504*45553Sbill } 505*45553Sbill if (wtflags & (TPINUSE)) { 506*45553Sbill seterror(ENXIO); 507*45553Sbill return(ENXIO); 508*45553Sbill } 509*45553Sbill if (wtflags & (TPDEAD)) { 510*45553Sbill seterror(EIO); 511*45553Sbill return(EIO); 512*45553Sbill } 513*45553Sbill /* If a rewind from the last session is going on, wait */ 514*45553Sbill while(wtflags & TPREW) { 515*45553Sbill #ifdef DEBUG 516*45553Sbill debug("Waiting for rew to finish\n"); 517*45553Sbill #endif 518*45553Sbill delay(1000000); /* delay one second */ 519*45553Sbill } 520*45553Sbill /* Only do reset and select when tape light is off, and tape is rewound. 521*45553Sbill * This allows multiple volumes. */ 522*45553Sbill if (wtflags & TPSTART) { 523*45553Sbill if (t_reset() != SUCCESS) { 524*45553Sbill nodev(); 525*45553Sbill return(ENXIO); 526*45553Sbill } 527*45553Sbill #ifdef DEBUG 528*45553Sbill debug("reset done. calling wtsense\n"); 529*45553Sbill #endif 530*45553Sbill if (wtsense(TP_WRP) == ERROR) { 531*45553Sbill seterror(EIO); 532*45553Sbill return (EIO); 533*45553Sbill } 534*45553Sbill #ifdef DEBUG 535*45553Sbill debug("wtsense done\n"); 536*45553Sbill #endif 537*45553Sbill wtflags &= ~TPSTART; 538*45553Sbill } 539*45553Sbill 540*45553Sbill wtflags = TPINUSE; 541*45553Sbill if (flag & FREAD) 542*45553Sbill wtflags |= TPREAD; 543*45553Sbill if (flag & FWRITE) 544*45553Sbill wtflags |= TPWRITE; 545*45553Sbill rwtbuf.b_flags = 0; 546*45553Sbill myproc = u.u_procp; /* for comparison */ 547*45553Sbill switch(TP_DENS(dev)) { 548*45553Sbill case 0: 549*45553Sbill cmds(0x28); 550*45553Sbill break; 551*45553Sbill case 1: 552*45553Sbill cmds(0x29); 553*45553Sbill break; 554*45553Sbill case 2: 555*45553Sbill cmds(0x27); 556*45553Sbill break; 557*45553Sbill case 3: 558*45553Sbill cmds(0x24); 559*45553Sbill } 560*45553Sbill return(0); 561*45553Sbill } 562*45553Sbill 563*45553Sbill /* 564*45553Sbill * close routine 565*45553Sbill * called on last device close 566*45553Sbill * If not rewind-on-close, leave read or write command intact. 567*45553Sbill */ 568*45553Sbill wtclose(dev) 569*45553Sbill { 570*45553Sbill int wtdsl2(); 571*45553Sbill 572*45553Sbill #ifdef DEBUG 573*45553Sbill debug("WTclose:\n"); 574*45553Sbill #endif 575*45553Sbill if (Hogproc == myproc) 576*45553Sbill Hogproc = (struct proc *) 0; 577*45553Sbill if (!exflag && (wtflags & TPWANY) && !(wtflags & (TPSESS|TPDEAD))) { 578*45553Sbill if (!(wtflags & TPWO)) 579*45553Sbill wstart(); 580*45553Sbill #ifdef DEBUG 581*45553Sbill debug("WT: Writing file mark\n"); 582*45553Sbill #endif 583*45553Sbill wmark(); /* write file mark */ 584*45553Sbill #ifdef DEBUG 585*45553Sbill debug("WT: Wrote file mark, going to wait\n"); 586*45553Sbill #endif 587*45553Sbill if (rdyexc(HZ/10) == ERROR) { 588*45553Sbill wtsense(0); 589*45553Sbill } 590*45553Sbill } 591*45553Sbill if (TP_REWCLOSE(dev) || (wtflags & (TPSESS|TPDEAD))) { 592*45553Sbill /* rewind tape to beginning of tape, deselect tape, and make a note */ 593*45553Sbill /* don't wait until rewind, though */ 594*45553Sbill /* Ending read or write causes rewind to happen, if no error, 595*45553Sbill * and READY and EXCEPTION stay up until it finishes */ 596*45553Sbill if (wtflags & (TPRO|TPWO)) 597*45553Sbill { 598*45553Sbill #ifdef DEBUG 599*45553Sbill debug("End read or write\n"); 600*45553Sbill #endif 601*45553Sbill rdyexc(HZ/10); 602*45553Sbill ioend(); 603*45553Sbill wtflags &= ~(TPRO|TPWO); 604*45553Sbill } 605*45553Sbill else wtwind(); 606*45553Sbill wtflags |= TPSTART | TPREW; 607*45553Sbill timeout(wtdsl2, 0, HZ); 608*45553Sbill } 609*45553Sbill else if (!(wtflags & (TPVOL|TPWANY))) 610*45553Sbill { 611*45553Sbill /* space forward to after next file mark no writing done */ 612*45553Sbill /* This allows skipping data without reading it.*/ 613*45553Sbill #ifdef DEBUG 614*45553Sbill debug("Reading past file mark\n"); 615*45553Sbill #endif 616*45553Sbill if (!(wtflags & TPRO)) 617*45553Sbill rstart(); 618*45553Sbill rmark(); 619*45553Sbill if (rdyexc(HZ/10)) 620*45553Sbill { 621*45553Sbill wtsense(TP_WRP); 622*45553Sbill } 623*45553Sbill } 624*45553Sbill wtflags &= TPREW|TPDEAD|TPSTART|TPRO|TPWO; 625*45553Sbill return(0); 626*45553Sbill } 627*45553Sbill 628*45553Sbill /* return ERROR if user I/O request should receive an I/O error code */ 629*45553Sbill 630*45553Sbill wtsense(ignor) 631*45553Sbill { 632*45553Sbill wtflags &= ~(TPRO|TPWO); 633*45553Sbill #ifdef DEBUGx 634*45553Sbill debug("WTsense: start "); 635*45553Sbill #endif 636*45553Sbill if (rdstatus(&wterror) == ERROR) 637*45553Sbill { 638*45553Sbill #ifdef DEBUG 639*45553Sbill debug("WTsense: Can't read status\n"); 640*45553Sbill #endif 641*45553Sbill return(ERROR); 642*45553Sbill } 643*45553Sbill #ifdef DEBUG 644*45553Sbill if (wterror.wt_err & (TP_ST0|TP_ST1)) 645*45553Sbill { 646*45553Sbill debug("Tperror: status %x error %d underruns %d\n", 647*45553Sbill wterror.wt_err, wterror.wt_ercnt, wterror.wt_urcnt); 648*45553Sbill } 649*45553Sbill else 650*45553Sbill debug("done. no error\n"); 651*45553Sbill #endif 652*45553Sbill wterror.wt_err &= ~ignor; /* ignore certain errors */ 653*45553Sbill reperr(wterror.wt_err); 654*45553Sbill if (((wterror.wt_err & TP_ST0) && (wterror.wt_err & TP_ERR0)) || 655*45553Sbill ((wterror.wt_err & TP_ST1) && (wterror.wt_err & TP_ERR1))) 656*45553Sbill return ERROR; 657*45553Sbill 658*45553Sbill return SUCCESS; 659*45553Sbill } 660*45553Sbill 661*45553Sbill /* lifted from tdriver.c from Wangtek */ 662*45553Sbill reperr(srb0) 663*45553Sbill int srb0; 664*45553Sbill { 665*45553Sbill int s0 = srb0 & (TP_ERR0|TP_ERR1); /* find out which exception to report */ 666*45553Sbill 667*45553Sbill if (s0) { 668*45553Sbill if (s0 & TP_USL) 669*45553Sbill sterr("Drive not online"); 670*45553Sbill else if (s0 & TP_CNI) 671*45553Sbill sterr("No cartridge"); 672*45553Sbill else if ((s0 & TP_WRP) && !(wtflags & TPWP)) 673*45553Sbill { 674*45553Sbill sterr("Tape is write protected"); 675*45553Sbill wtflags |= TPWP; 676*45553Sbill } 677*45553Sbill /* 678*45553Sbill if (s0 & TP_FIL) 679*45553Sbill sterr("Filemark detected"); 680*45553Sbill */ 681*45553Sbill else if (s0 & TP_BNL) 682*45553Sbill sterr("Block in error not located"); 683*45553Sbill else if (s0 & TP_UDA) 684*45553Sbill sterr("Unrecoverable data error"); 685*45553Sbill /* 686*45553Sbill else if (s0 & TP_EOM) 687*45553Sbill sterr("End of tape"); 688*45553Sbill */ 689*45553Sbill else if (s0 & TP_NDT) 690*45553Sbill sterr("No data detected"); 691*45553Sbill /* 692*45553Sbill if (s0 & TP_POR) 693*45553Sbill sterr("Reset occured"); 694*45553Sbill */ 695*45553Sbill else if (s0 & TP_BOM) 696*45553Sbill sterr("Beginning of tape"); 697*45553Sbill else if (s0 & TP_ILL) 698*45553Sbill sterr("Illegal command"); 699*45553Sbill } 700*45553Sbill } 701*45553Sbill 702*45553Sbill sterr(errstr) 703*45553Sbill char *errstr; 704*45553Sbill { 705*45553Sbill printf("Streamer: %s\n", errstr); 706*45553Sbill } 707*45553Sbill 708*45553Sbill /* Wait until rewind finishes, and deselect drive */ 709*45553Sbill wtdsl2() { 710*45553Sbill int stat; 711*45553Sbill 712*45553Sbill stat = inb(wtport) & (READY|EXCEP); 713*45553Sbill #ifdef DEBUG 714*45553Sbill debug("Timeout: Waiting for rewind to finish: stat %x\n", stat); 715*45553Sbill #endif 716*45553Sbill switch (stat) { 717*45553Sbill /* They're active low, ya'know */ 718*45553Sbill case READY|EXCEP: 719*45553Sbill timeout(wtdsl2, (caddr_t) 0, HZ); 720*45553Sbill return; 721*45553Sbill case EXCEP: 722*45553Sbill wtflags &= ~TPREW; 723*45553Sbill return; 724*45553Sbill case READY: 725*45553Sbill case 0: 726*45553Sbill wtflags &= ~TPREW; 727*45553Sbill sterr("Rewind failed"); 728*45553Sbill wtsense(TP_WRP); 729*45553Sbill return; 730*45553Sbill } 731*45553Sbill } 732*45553Sbill 733*45553Sbill wtwind() { 734*45553Sbill #ifdef DEBUG 735*45553Sbill debug("WT: About to rewind\n"); 736*45553Sbill #endif 737*45553Sbill rwind(); /* actually start rewind */ 738*45553Sbill } 739*45553Sbill 740*45553Sbill wtintr(vec) { 741*45553Sbill if (wtflags & (TPWO|TPRO)) 742*45553Sbill { 743*45553Sbill isrlock = 1; 744*45553Sbill if (wtio) isr(); 745*45553Sbill isrlock = 0; 746*45553Sbill } 747*45553Sbill } 748*45553Sbill 749*45553Sbill wtinit() { 750*45553Sbill if (wtchan < 1 || wtchan > 3) 751*45553Sbill { 752*45553Sbill sterr("Bad DMA channel, cannot init driver"); 753*45553Sbill return; 754*45553Sbill } 755*45553Sbill wtlinit(); /* init assembly language variables */ 756*45553Sbill pageset(); 757*45553Sbill } 758*45553Sbill 759*45553Sbill rdyexc(ticks) 760*45553Sbill { 761*45553Sbill int s; 762*45553Sbill #ifdef DEBUG 763*45553Sbill int os = 0xffff; /* force printout first time */ 764*45553Sbill #endif 765*45553Sbill for (;;) { /* loop until ready or exception */ 766*45553Sbill s=(inb(wtport) & 0xff); /* read the status register */ 767*45553Sbill #ifdef DEBUG 768*45553Sbill if (os != s) { 769*45553Sbill debug("Status reg = %x\n", s); /* */ 770*45553Sbill os = s; 771*45553Sbill } 772*45553Sbill #endif 773*45553Sbill if (!(s & EXCEP)) /* check if exception have occured */ 774*45553Sbill break; 775*45553Sbill if (!(s & READY)) /* check if controller is ready */ 776*45553Sbill break; 777*45553Sbill s = splbio(); 778*45553Sbill delay((ticks/HZ)*1000000); /* */ 779*45553Sbill splx(s); 780*45553Sbill } 781*45553Sbill #ifdef DEBUG 782*45553Sbill debug("Status reg = %x on return\n", s); /* */ 783*45553Sbill #endif 784*45553Sbill return((s & EXCEP)?SUCCESS:ERROR); /* return exception if it occured */ 785*45553Sbill } 786*45553Sbill 787*45553Sbill pollrdy() 788*45553Sbill { 789*45553Sbill int sps; 790*45553Sbill #ifdef DEBUG 791*45553Sbill debug("Pollrdy\n"); 792*45553Sbill #endif 793*45553Sbill sps = splbio(); 794*45553Sbill while (wtio) 795*45553Sbill sleep(&wci, WTPRI); 796*45553Sbill splx(sps); 797*45553Sbill #ifdef DEBUG 798*45553Sbill debug("Finish poll, wci %d exflag %d\n", wci, exflag); 799*45553Sbill #endif 800*45553Sbill return exflag; 801*45553Sbill } 802*45553Sbill 803*45553Sbill wtdma() /* start up i/o operation, called from dma() in wtlib1.s */ 804*45553Sbill { 805*45553Sbill wtio = 1; 806*45553Sbill if (!wtimeron) 807*45553Sbill { 808*45553Sbill wtimeron = 1; 809*45553Sbill timeout(wtimer, (caddr_t) 0, HZ/2); 810*45553Sbill } 811*45553Sbill } 812*45553Sbill 813*45553Sbill wtwake() /* end i/o operation, called from isr() in wtlib1.s */ 814*45553Sbill { 815*45553Sbill wtio = 0; 816*45553Sbill wakeup(&wci); 817*45553Sbill } 818*45553Sbill 819*45553Sbill pageset() 820*45553Sbill { 821*45553Sbill unsigned long pp; 822*45553Sbill 823*45553Sbill pp = (unsigned long) pagebuf; 824*45553Sbill pageaddr = kvtop(pp); 825*45553Sbill #ifdef DEBUG 826*45553Sbill debug("pageset: addr %lx\n", pageaddr); 827*45553Sbill #endif 828*45553Sbill } 829*45553Sbill 830*45553Sbill 831*45553Sbill 832*45553Sbill #define near 833*45553Sbill 834*45553Sbill static near 835*45553Sbill sendcmd() 836*45553Sbill { 837*45553Sbill /* desired command in global mbits */ 838*45553Sbill 839*45553Sbill outb(CTLPORT, mbits | REQUEST); /* set request */ 840*45553Sbill while (inb(STATPORT) & READY); /* wait for ready */ 841*45553Sbill outb(CTLPORT, mbits & ~REQUEST); /* reset request */ 842*45553Sbill while ((inb(STATPORT) & READY) == 0); /* wait for not ready */ 843*45553Sbill } 844*45553Sbill 845*45553Sbill static near /* execute command */ 846*45553Sbill cmds(cmd) 847*45553Sbill { 848*45553Sbill register s; 849*45553Sbill 850*45553Sbill do s = inb(STATPORT); 851*45553Sbill while ((s & STAT) == STAT); /* wait for ready */ 852*45553Sbill 853*45553Sbill if ((s & EXCEP) == 0) /* if exception */ 854*45553Sbill return ERROR; /* error */ 855*45553Sbill 856*45553Sbill outb(CMDPORT, cmd); /* output the command */ 857*45553Sbill 858*45553Sbill outb(CTLPORT, mbits=ONLINE); /* set & send ONLINE */ 859*45553Sbill sendcmd(); 860*45553Sbill 861*45553Sbill return SUCCESS; 862*45553Sbill } 863*45553Sbill 864*45553Sbill qicmd(cmd) 865*45553Sbill { 866*45553Sbill return cmds(cmd); 867*45553Sbill } 868*45553Sbill 869*45553Sbill rstart() 870*45553Sbill { 871*45553Sbill return cmds(RDDATA); 872*45553Sbill } 873*45553Sbill 874*45553Sbill rmark() 875*45553Sbill { 876*45553Sbill return cmds(READFM); 877*45553Sbill } 878*45553Sbill 879*45553Sbill wstart() 880*45553Sbill { 881*45553Sbill return cmds(WRTDATA); 882*45553Sbill } 883*45553Sbill 884*45553Sbill ioend() 885*45553Sbill { 886*45553Sbill register s; 887*45553Sbill register rval = SUCCESS; 888*45553Sbill 889*45553Sbill do s = inb(STATPORT); 890*45553Sbill while ((s & STAT) == STAT); /* wait for ready */ 891*45553Sbill 892*45553Sbill if ((s & EXCEP) == 0) /* if exception */ 893*45553Sbill rval = ERROR; /* error */ 894*45553Sbill 895*45553Sbill mbits &= ~ONLINE; 896*45553Sbill outb(CTLPORT, mbits); /* reset ONLINE */ 897*45553Sbill outb(MASKREG, wtchan+4); /* turn off dma */ 898*45553Sbill outb(CLEARFF, 0); /* reset direction flag */ 899*45553Sbill 900*45553Sbill return rval; 901*45553Sbill } 902*45553Sbill 903*45553Sbill wmark() 904*45553Sbill { 905*45553Sbill register s; 906*45553Sbill 907*45553Sbill if (cmds(WRITEFM) == ERROR) 908*45553Sbill return ERROR; 909*45553Sbill 910*45553Sbill do s = inb(STATPORT); 911*45553Sbill while ((s & STAT) == STAT); /* wait for ready */ 912*45553Sbill 913*45553Sbill if ((s & EXCEP) == 0) /* if exception */ 914*45553Sbill return ERROR; /* error */ 915*45553Sbill 916*45553Sbill return SUCCESS; 917*45553Sbill } 918*45553Sbill 919*45553Sbill rwind() 920*45553Sbill { 921*45553Sbill register s; 922*45553Sbill 923*45553Sbill mbits = CMDOFF; 924*45553Sbill 925*45553Sbill do s = inb(STATPORT); 926*45553Sbill while ((s & STAT) == STAT); /* wait for ready */ 927*45553Sbill 928*45553Sbill outb(CMDPORT, REWIND); 929*45553Sbill sendcmd(); 930*45553Sbill 931*45553Sbill return SUCCESS; 932*45553Sbill } 933*45553Sbill 934*45553Sbill rdstatus(stp) 935*45553Sbill char *stp; /* pointer to 6 byte buffer */ 936*45553Sbill { 937*45553Sbill register s; 938*45553Sbill int n; 939*45553Sbill 940*45553Sbill do s = inb(STATPORT); 941*45553Sbill while ((s & STAT) == STAT); /* wait for ready or exception */ 942*45553Sbill 943*45553Sbill outb(CMDPORT, RDSTAT); 944*45553Sbill sendcmd(); /* send read status command */ 945*45553Sbill 946*45553Sbill for (n=0; n<6; n++) 947*45553Sbill { 948*45553Sbill #ifdef DEBUGx 949*45553Sbill debug("rdstatus: waiting, byte %d\n", n); 950*45553Sbill #endif 951*45553Sbill do s = inb(STATPORT); 952*45553Sbill while ((s & STAT) == STAT); /* wait for ready */ 953*45553Sbill #ifdef DEBUGx 954*45553Sbill debug("rdstatus: done\n"); 955*45553Sbill #endif 956*45553Sbill if ((s & EXCEP) == 0) /* if exception */ 957*45553Sbill return ERROR; /* error */ 958*45553Sbill 959*45553Sbill *stp++ = inb(DATAPORT); /* read status byte */ 960*45553Sbill 961*45553Sbill outb(CTLPORT, mbits | REQUEST); /* set request */ 962*45553Sbill #ifdef DEBUGx 963*45553Sbill debug("rdstatus: waiting after request, byte %d\n", n); 964*45553Sbill #endif 965*45553Sbill while ((inb(STATPORT)&READY) == 0); /* wait for not ready */ 966*45553Sbill for (s=100; s>0; s--); /* wait an additional time */ 967*45553Sbill 968*45553Sbill outb(CTLPORT, mbits & ~REQUEST);/* unset request */ 969*45553Sbill #ifdef DEBUGx 970*45553Sbill debug("rdstatus: done\n"); 971*45553Sbill #endif 972*45553Sbill } 973*45553Sbill return SUCCESS; 974*45553Sbill } 975*45553Sbill 976*45553Sbill t_reset() 977*45553Sbill { 978*45553Sbill register i; 979*45553Sbill mbits |= RESET; 980*45553Sbill outb(CTLPORT, mbits); /* send reset */ 981*45553Sbill delay(20); 982*45553Sbill mbits &= ~RESET; 983*45553Sbill outb(CTLPORT, mbits); /* turn off reset */ 984*45553Sbill if ((inb(STATPORT) & RESETMASK) == RESETVAL) 985*45553Sbill return SUCCESS; 986*45553Sbill return ERROR; 987*45553Sbill } 988*45553Sbill 989*45553Sbill static 990*45553Sbill dma() 991*45553Sbill { 992*45553Sbill int x=splbio(); 993*45553Sbill wtdma(); 994*45553Sbill outb(CLEARFF, 0); 995*45553Sbill outb(MODEREG, mode); /* set dma mode */ 996*45553Sbill outb(dmareg, bufptr & 0xFF); 997*45553Sbill outb(dmareg, (bufptr>>8) & 0xFF); 998*45553Sbill outb(pagereg, (bufptr>>16) & 0xFF); 999*45553Sbill outb(dmareg+1, (BLKSIZE-1) & 0xFF); 1000*45553Sbill outb(dmareg+1, (BLKSIZE-1) >> 8); 1001*45553Sbill outb(wtport, eqdma+ONLINE); 1002*45553Sbill outb(MASKREG, wtchan); /* enable command to 8237, start dma */ 1003*45553Sbill splx(x); 1004*45553Sbill } 1005*45553Sbill 1006*45553Sbill static near 1007*45553Sbill wtstart(buf, cnt) 1008*45553Sbill long buf; 1009*45553Sbill int cnt; 1010*45553Sbill { 1011*45553Sbill register s; 1012*45553Sbill 1013*45553Sbill bufptr = buf; /* init statics */ 1014*45553Sbill numbytes = cnt; 1015*45553Sbill wci = 0; /* init flags */ 1016*45553Sbill exflag = 0; 1017*45553Sbill bytes = 0; /* init counter */ 1018*45553Sbill 1019*45553Sbill do s = inb(STATPORT) & STAT; 1020*45553Sbill while (s == STAT); /* wait for ready or error */ 1021*45553Sbill 1022*45553Sbill if (s & EXCEP) /* no error */ 1023*45553Sbill { 1024*45553Sbill dma(); 1025*45553Sbill return SUCCESS; 1026*45553Sbill } 1027*45553Sbill return ERROR; /* error */ 1028*45553Sbill } 1029*45553Sbill 1030*45553Sbill rtape(buf, cnt) 1031*45553Sbill long buf; /* physical address */ 1032*45553Sbill int cnt; /* number of bytes */ 1033*45553Sbill { 1034*45553Sbill mode = dma_read; 1035*45553Sbill return wtstart(buf,cnt); 1036*45553Sbill } 1037*45553Sbill 1038*45553Sbill wtape(buf, cnt) 1039*45553Sbill long buf; /* physical address */ 1040*45553Sbill int cnt; /* number of bytes */ 1041*45553Sbill { 1042*45553Sbill mode = dma_write; 1043*45553Sbill return wtstart(buf,cnt); 1044*45553Sbill } 1045*45553Sbill 1046*45553Sbill isr() 1047*45553Sbill { 1048*45553Sbill int stat = inb(wtport); 1049*45553Sbill if (!(stat & EXCEP)) /* exception during I/O */ 1050*45553Sbill { 1051*45553Sbill if (bytes + BLKSIZE >= numbytes) wci = 1; 1052*45553Sbill exflag = 1; 1053*45553Sbill goto isrwake; 1054*45553Sbill } 1055*45553Sbill if ((stat & READY) || !(inb(STATUSREG) & dma_done)) 1056*45553Sbill return; 1057*45553Sbill exflag = 0; 1058*45553Sbill outb(wtport, ONLINE); 1059*45553Sbill bytes += BLKSIZE; 1060*45553Sbill if (bytes >= numbytes) /* normal completion of I/O */ 1061*45553Sbill { 1062*45553Sbill wci = 1; 1063*45553Sbill isrwake: 1064*45553Sbill outb(MASKREG, 4+wtchan); /* turn off dma */ 1065*45553Sbill wtwake(); /* wake up user level */ 1066*45553Sbill } 1067*45553Sbill else 1068*45553Sbill { /* continue I/O */ 1069*45553Sbill bufptr += BLKSIZE; 1070*45553Sbill dma(); 1071*45553Sbill } 1072*45553Sbill } 1073*45553Sbill 1074*45553Sbill wtlinit() 1075*45553Sbill { 1076*45553Sbill switch (wtchan) { 1077*45553Sbill case 1: 1078*45553Sbill return; 1079*45553Sbill case 2: 1080*45553Sbill pagereg = 0x81; 1081*45553Sbill dma_done = 4; 1082*45553Sbill break; 1083*45553Sbill case 3: 1084*45553Sbill eqdma = 0x10; 1085*45553Sbill pagereg = 0x82; 1086*45553Sbill dma_done = 8; 1087*45553Sbill break; 1088*45553Sbill } 1089*45553Sbill dma_write = wtchan+0x48; 1090*45553Sbill dma_read = wtchan+0x44; 1091*45553Sbill dmareg = wtchan+wtchan; 1092*45553Sbill } 1093*45553Sbill 1094*45553Sbill /* 1095*45553Sbill * delay i microseconds 1096*45553Sbill */ 1097*45553Sbill delay(i) 1098*45553Sbill register int i; 1099*45553Sbill { 1100*45553Sbill while (i-- > 0) 1101*45553Sbill DELAY(1000); 1102*45553Sbill } 1103*45553Sbill 1104*45553Sbill wtsize() 1105*45553Sbill { 1106*45553Sbill } 1107*45553Sbill 1108*45553Sbill wtdump() 1109*45553Sbill { 1110*45553Sbill } 1111*45553Sbill 1112*45553Sbill #include "machine/isa/device.h" 1113*45553Sbill #include "machine/isa/icu.h" 1114*45553Sbill 1115*45553Sbill int wtprobe(), wtattach(); 1116*45553Sbill struct isa_driver wtdriver = { 1117*45553Sbill wtprobe, wtattach, "wt", 1118*45553Sbill }; 1119*45553Sbill 1120*45553Sbill wtprobe(dvp) 1121*45553Sbill struct isa_device *dvp; 1122*45553Sbill { 1123*45553Sbill int val,i,s; 1124*45553Sbill 1125*45553Sbill #ifdef lint 1126*45553Sbill wtintr(0); 1127*45553Sbill #endif 1128*45553Sbill 1129*45553Sbill wtport = dvp->id_iobase; 1130*45553Sbill if(t_reset() != SUCCESS) return(0); 1131*45553Sbill return(1); 1132*45553Sbill } 1133*45553Sbill 1134*45553Sbill wtattach() { } 1135*45553Sbill 1136*45553Sbill #endif NWT 1137