145553Sbill #include "wt.h" 245553Sbill #if NWT > 0 345553Sbill /* 445553Sbill * Mach Operating System 545553Sbill * Copyright (c) 1989 Carnegie-Mellon University 645553Sbill * All rights reserved. The CMU software License Agreement specifies 745553Sbill * the terms and conditions for use and redistribution. 8*49573Swilliam * @(#)wt.c 1.4 (Berkeley) 1/18/91 945553Sbill */ 1045553Sbill /* 1145553Sbill * HISTORY 1245553Sbill * $Log: wt.c,v $ 1345553Sbill * Revision 2.2.1.3 90/01/08 13:29:38 rvb 1445553Sbill * Add Intel copyright. 1545553Sbill * [90/01/08 rvb] 1645553Sbill * 1745553Sbill * Revision 2.2.1.2 89/12/21 18:00:09 rvb 1845553Sbill * Change WTPRI to make the streamer tape read/write 1945553Sbill * interruptible. [lin] 2045553Sbill * 2145553Sbill * Revision 2.2.1.1 89/11/10 09:49:49 rvb 2245553Sbill * ORC likes their streamer port at 0x288. 2345553Sbill * [89/11/08 rvb] 2445553Sbill * 2545553Sbill * Revision 2.2 89/09/25 12:33:02 rvb 2645553Sbill * Driver was provided by Intel 9/18/89. 2745553Sbill * [89/09/23 rvb] 2845553Sbill * 2945553Sbill */ 3045553Sbill 3145553Sbill /* 3245553Sbill * 3345553Sbill * Copyright 1988, 1989 by Intel Corporation 3445553Sbill * 3545553Sbill * Support Bell Tech QIC-02 and WANGTEK QIC-36 or QIC-02 3645553Sbill */ 3745553Sbill 38*49573Swilliam /*#include <sys/errno.h> 3945553Sbill #include <sys/signal.h> 40*49573Swilliam #include <sys/types.h>*/ 41*49573Swilliam #include "sys/param.h" 42*49573Swilliam #include "sys/buf.h" 43*49573Swilliam #include "sys/file.h" 44*49573Swilliam #include "sys/proc.h" 45*49573Swilliam #include "sys/user.h" 46*49573Swilliam #include "i386/isa/wtreg.h" 4745553Sbill 4845553Sbill #ifdef ORC 4945553Sbill unsigned wtport = 0x288; /* base I/O port of controller */ 5045553Sbill #else ORC 5145553Sbill unsigned wtport = 0x300; /* base I/O port of controller */ 5245553Sbill #endif ORC 5345553Sbill /* standard = 0x300 */ 5445553Sbill /* alternate = 0x338 */ 5545553Sbill 5645553Sbill unsigned wtchan = 1; /* DMA channel number */ 5745553Sbill /* stardard = 1 */ 5845553Sbill /* hardware permits 1, 2 or 3. */ 5945553Sbill /* (Avoid DMA 2: used by disks) */ 6045553Sbill 6145553Sbill int first_wtopen_ever = 1; 6245553Sbill 6345553Sbill 6445553Sbill #define ERROR 1 /* return from tape routines */ 6545553Sbill #define SUCCESS 0 /* return from tape routines */ 6645553Sbill 6745553Sbill int wci = 0; 6845553Sbill int exflag = 0; 6945553Sbill int bytes = 0; 7045553Sbill 7145553Sbill static unsigned char eqdma = 0x8; 7245553Sbill static unsigned char pagereg = 0x83; 7345553Sbill static unsigned char dmareg = 2; 7445553Sbill static unsigned char dma_write = 0x49; 7545553Sbill static unsigned char dma_read = 0x45; 7645553Sbill static unsigned char dma_done = 2; 7745553Sbill static unsigned char mode = 0; 7845553Sbill static unsigned char mbits; /* map bits into each other */ 7945553Sbill static long bufptr; 8045553Sbill static unsigned numbytes; 8145553Sbill /* 8245553Sbill _wci dw 0 ; interrupt chain finished normally 8345553Sbill _exflag dw 0 ; exception variable 8445553Sbill _bytes dw 0 ; current bytes 8545553Sbill 8645553Sbill eqdma db 8h ; enable dma command: ch1,ch2=8h, ch3=10h 8745553Sbill pagereg db 83h ; ch1=83h, ch2=81h, ch3=82h 8845553Sbill dmareg db 2 ; ch1=2, ch2=4, ch3=6 8945553Sbill dma_write db 49h ; write dma command: 48h+_wtchan 9045553Sbill dma_read db 45h ; read dma command: 44h+_wtchan 9145553Sbill dma_done db 2 ; dma done flag: 1<<_wtchan 9245553Sbill mode db 0 ; dma operation mode 9345553Sbill lbufptr dw 0 ; buffer pointer to data buffers, low word 9445553Sbill hbufptr dw 0 ; buffer pointer to data buffers, high word 9545553Sbill numbytes dw 0 ; number of bytes to read or write (new) 9645553Sbill */ 9745553Sbill 9845553Sbill #define PAGESIZ 4096 9945553Sbill #define HZ 60 10045553Sbill 10145553Sbill /* tape controller ports */ 10245553Sbill #define STATPORT wtport 10345553Sbill #define CTLPORT STATPORT 10445553Sbill #define CMDPORT (wtport+1) 10545553Sbill #define DATAPORT CMDPORT 10645553Sbill 10745553Sbill /* defines for reading out status from wangtek tape controller */ 10845553Sbill #define READY 0x01 /* ready bit define */ 10945553Sbill #define EXCEP 0x02 /* exception bit define */ 11045553Sbill #define STAT (READY|EXCEP) 11145553Sbill #define RESETMASK 0x7 11245553Sbill #define RESETVAL (RESETMASK & ~EXCEP) 11345553Sbill 11445553Sbill /* tape controller control bits (CTLPORT) */ 11545553Sbill #define ONLINE 0x01 11645553Sbill #define RESET 0x02 11745553Sbill #define REQUEST 0x04 /* request command */ 11845553Sbill #define CMDOFF 0xC0 11945553Sbill 12045553Sbill /* QIC-02 commands (CMDPORT) */ 12145553Sbill #define RDDATA 0x80 /* read data */ 12245553Sbill #define READFM 0xA0 /* read file mark */ 12345553Sbill #define WRTDATA 0x40 /* write data */ 12445553Sbill #define WRITEFM 0x60 /* write file mark */ 12545553Sbill #define RDSTAT 0xC0 /* read status command */ 12645553Sbill #define REWIND 0x21 /* rewind command (position+bot) */ 12745553Sbill 12845553Sbill /* 8237 DMA controller regs */ 12945553Sbill #define STATUSREG 0x8 13045553Sbill #define MASKREG 0xA 13145553Sbill #define MODEREG 0xB 13245553Sbill #define CLEARFF 0xC 13345553Sbill 13445553Sbill /* streamer tape block size */ 13545553Sbill #define BLKSIZE 512 13645553Sbill 13745553Sbill /* Tape characteristics */ 13845553Sbill #define NBPS 512 /* 512-byte blocks */ 13945553Sbill #define ERROR 1 /* return from tape routines */ 14045553Sbill #define SUCCESS 0 /* return from tape routines */ 14145553Sbill 14245553Sbill /* Minor devs */ 14345553Sbill #define TP_REWCLOSE(d) ((minor(d)&04) == 0) /* Rewind tape on close if read/write */ 14445553Sbill #define TP_DENS(dev) ((minor(dev) >> 3) & 03) /* set density */ 14545553Sbill #define TPHOG(d) 0 /* use Hogproc during tape I/O */ 14645553Sbill 14745553Sbill /* defines for wtflags */ 14845553Sbill #define TPINUSE 0x0001 /* tape is already open */ 14945553Sbill #define TPREAD 0x0002 /* tape is only open for reading */ 15045553Sbill #define TPWRITE 0x0004 /* tape is only open for writing */ 15145553Sbill #define TPSTART 0x0008 /* tape must be rewound and reset */ 15245553Sbill #define TPDEAD 0x0010 /* tape drive does not work or driver error */ 15345553Sbill #define TPSESS 0x0020 /* no more reads or writes allowed in session */ 15445553Sbill /* for example, when tape has to be changed */ 15545553Sbill #define TPSTOP 0x0040 /* Stop command outstanding */ 15645553Sbill #define TPREW 0x0080 /* Rewind command outstanding, see wtdsl2() */ 15745553Sbill #define TPVOL 0x0100 /* Read file mark, or hit end of tape */ 15845553Sbill #define TPWO 0x0200 /* write command outstanding */ 15945553Sbill #define TPRO 0x0400 /* read command outstanding */ 16045553Sbill #define TPWANY 0x0800 /* write command requested */ 16145553Sbill #define TPRANY 0x1000 /* read command requested */ 16245553Sbill #define TPWP 0x2000 /* write protect error seen */ 16345553Sbill 16445553Sbill unsigned int wtflags = TPSTART; /* state of tape drive */ 16545553Sbill 16645553Sbill struct buf rwtbuf; /* header for raw i/o */ 16745553Sbill struct proc *myproc; /* process which opened tape driver */ 16845553Sbill 16945553Sbill char wtimeron; /* wtimer() active flag */ 17045553Sbill char wtio; /* dma (i/o) active flag */ 17145553Sbill char isrlock; /* isr() flag */ 17245553Sbill 17345553Sbill struct proc * Hogproc; /* no Hogproc on Microport */ 17445553Sbill #define ftoseg(x) ((unsigned) (x >> 16)) 17545553Sbill 17645553Sbill struct wtstatus { 17745553Sbill ushort wt_err; /* code for error encountered */ 17845553Sbill ushort wt_ercnt; /* number of error blocks */ 17945553Sbill ushort wt_urcnt; /* number of underruns */ 18045553Sbill } wterror; 18145553Sbill 18245553Sbill /* defines for wtstatus.wt_err */ 18345553Sbill #define TP_POR 0x100 /* Power on/reset occurred */ 18445553Sbill #define TP_RES1 0x200 /* Reserved for end of media */ 18545553Sbill #define TP_RES2 0x400 /* Reserved for bus parity */ 18645553Sbill #define TP_BOM 0x800 /* Beginning of media */ 18745553Sbill #define TP_MBD 0x1000 /* Marginal block detected */ 18845553Sbill #define TP_NDT 0x2000 /* No data detected */ 18945553Sbill #define TP_ILL 0x4000 /* Illegal command */ 19045553Sbill #define TP_ST1 0x8000 /* Status byte 1 bits */ 19145553Sbill #define TP_FIL 0x01 /* File mark detected */ 19245553Sbill #define TP_BNL 0x02 /* Bad block not located */ 19345553Sbill #define TP_UDA 0x04 /* Unrecoverable data error */ 19445553Sbill #define TP_EOM 0x08 /* End of media */ 19545553Sbill #define TP_WRP 0x10 /* Write protected cartridge */ 19645553Sbill #define TP_USL 0x20 /* Unselected drive */ 19745553Sbill #define TP_CNI 0x40 /* Cartridge not in place */ 19845553Sbill #define TP_ST0 0x80 /* Status byte 0 bits */ 19945553Sbill 20045553Sbill /* Grounds for reporting I/O error to user */ 20145553Sbill #define TP_ERR0 (TP_BNL|TP_UDA|TP_WRP|TP_CNI|TP_FIL|TP_EOM|TP_USL) 20245553Sbill #define TP_ERR1 (TP_MBD|TP_NDT|TP_ILL) 20345553Sbill /* TP_ILL should never happen! */ 20445553Sbill /* 20545553Sbill #define TP_ERR0 0x7f 20645553Sbill #define TP_ERR1 0x7700 20745553Sbill */ 20845553Sbill 20945553Sbill /* defines for reading out status from wangtek tape controller */ 21045553Sbill #define READY 0x01 /* ready bit define */ 21145553Sbill #define EXCEP 0x02 /* exception bit define */ 21245553Sbill 21345553Sbill /* sleep priority */ 21445553Sbill #define WTPRI (PZERO+10) 21545553Sbill 21645553Sbill char pagebuf[NBPS]; /* buffer of size NBPS */ 21745553Sbill unsigned long pageaddr; /* physical addr of pagebuf */ 21845553Sbill /* pageaddr is used with DMA controller */ 21945553Sbill time_t Hogtime; /* lbolt when Hog timer started */ 22045553Sbill extern time_t lbolt; 22145553Sbill 22245553Sbill #define debug printf 22345553Sbill 22445553Sbill /* 22545553Sbill * Strategy routine. 22645553Sbill * 22745553Sbill * Arguments: 22845553Sbill * Pointer to buffer structure 22945553Sbill * Function: 23045553Sbill * Start transfer. 23145553Sbill * 23245553Sbill * It would be nice to have this multiple-threaded. 23345553Sbill * There is a version of dump from Berkeley that works with multiple processes 23445553Sbill * trading off with disk & tape I/O. 23545553Sbill */ 23645553Sbill 23745553Sbill int 23845553Sbill wtstrategy(bp) 23945553Sbill register struct buf *bp; 24045553Sbill { 24145553Sbill unsigned ucnt1, ucnt2, finished; 24245553Sbill unsigned long adr1, adr2; 243*49573Swilliam int bad; 24445553Sbill 24545553Sbill adr1 = kvtop(bp->b_un.b_addr); 24645553Sbill #ifdef DEBUG 24745553Sbill debug("bpaddr %x\n", adr1); 24845553Sbill #endif 24945553Sbill ucnt1 = bp->b_bcount; 25045553Sbill ucnt2 = 0; 25145553Sbill adr2 = 0; 25245553Sbill #ifdef DEBUG 25345553Sbill debug("WTstart: adr1 %lx cnt %x\n", adr1, ucnt1); 25445553Sbill #endif 25545553Sbill if (ftoseg(adr1) != ftoseg(adr1 + (unsigned) ucnt1 - 1)) 25645553Sbill { 25745553Sbill adr2 = (adr1 & 0xffff0000L) + 0x10000L; 25845553Sbill ucnt2 = (adr1 + ucnt1) - adr2; 25945553Sbill ucnt1 -= ucnt2; 26045553Sbill } 26145553Sbill /* at file marks and end of tape, we just return '0 bytes available' */ 26245553Sbill if (wtflags & TPVOL) { 26345553Sbill bp->b_resid = bp->b_bcount; 26445553Sbill goto xit; 26545553Sbill } 26645553Sbill if ((Hogproc == (struct proc *) 0) && TPHOG(bp->b_dev)) 26745553Sbill { 26845553Sbill #ifdef DEBUG 26945553Sbill printf("setting Hogproc\n"); 27045553Sbill #endif 27145553Sbill Hogtime = 0; 27245553Sbill Hogproc = myproc; 27345553Sbill } 27445553Sbill if (bp->b_flags & B_READ) { 275*49573Swilliam bad = 0; 27645553Sbill 27745553Sbill /* For now, we assume that all data will be copied out */ 27845553Sbill /* If read command outstanding, just skip down */ 27945553Sbill if (!(wtflags & TPRO)) { 28045553Sbill if (ERROR == wtsense(TP_WRP)) /* clear status */ 28145553Sbill goto errxit; 28245553Sbill #ifdef DEBUG 28345553Sbill debug("WTread: Start read\n"); 28445553Sbill #endif 28545553Sbill if (!(wtflags & TPREAD) || (wtflags & TPWANY) || 28645553Sbill (rstart() == ERROR)) { 28745553Sbill #ifdef DEBUG 28845553Sbill debug("Tpstart: read init error\n"); /* */ 28945553Sbill #endif 29045553Sbill goto errxit; 29145553Sbill } 29245553Sbill wtflags |= TPRO|TPRANY; 29345553Sbill } 29445553Sbill 29545553Sbill finished = 0; 29645553Sbill /* Take a deep breath */ 29745553Sbill if (ucnt1) { 29845553Sbill if ((rtape(adr1, ucnt1) == ERROR) && 29945553Sbill (wtsense(TP_WRP) == ERROR)) 30045553Sbill goto endio; 30145553Sbill /* wait for it */ 30245553Sbill bad = pollrdy(); 30345553Sbill finished = bytes; 30445553Sbill if (bad) 30545553Sbill goto endio; 30645553Sbill } 30745553Sbill /* if a second I/O region, start it */ 30845553Sbill if (ucnt2) { 30945553Sbill if ((rtape(adr2, ucnt2) == ERROR) && 31045553Sbill (wtsense(TP_WRP) == ERROR)) 31145553Sbill ucnt2 = 0; /* don't poll for me */ 31245553Sbill } 31345553Sbill 31445553Sbill /* if second i/o pending wait for it */ 31545553Sbill if (ucnt2) { 31645553Sbill pollrdy(); 31745553Sbill /* whether pollrdy is ok or not */ 31845553Sbill finished += bytes; 31945553Sbill } 32045553Sbill } else { 32145553Sbill if (wtflags & TPWP) /* write protected */ 32245553Sbill goto errxit; 32345553Sbill 32445553Sbill /* If write command outstanding, just skip down */ 32545553Sbill if (!(wtflags & TPWO)) { 32645553Sbill if (ERROR == wtsense(0)) /* clear status */ 32745553Sbill { 32845553Sbill #ifdef DEBUG 32945553Sbill debug("TPstart: sense 0\n"); 33045553Sbill #endif 33145553Sbill goto errxit; 33245553Sbill } 33345553Sbill if (!(wtflags & TPWRITE) || (wtflags & TPRANY) || 33445553Sbill (wstart() == ERROR)) { 33545553Sbill #ifdef DEBUG 33645553Sbill debug("Tpstart: write init error\n"); /* */ 33745553Sbill #endif 33845553Sbill wtsense(0); 33945553Sbill 34045553Sbill errxit: bp->b_flags |= B_ERROR; 34145553Sbill bp->b_resid = bp->b_bcount; 34245553Sbill goto xit; 34345553Sbill } 34445553Sbill wtflags |= TPWO|TPWANY; 34545553Sbill } 34645553Sbill 34745553Sbill /* and hold your nose */ 34845553Sbill if (ucnt1 && ((wtape(adr1, ucnt1) == ERROR) 34945553Sbill && (wtsense(0) == ERROR))) 35045553Sbill finished = bytes; 35145553Sbill 35245553Sbill else if (ucnt2 && 35345553Sbill (((ucnt1 && pollrdy()) || 35445553Sbill (wtape(adr2, ucnt2) == ERROR)) && 35545553Sbill (wtsense(0) == ERROR))) 35645553Sbill finished = ucnt1 + NBPS + bytes; 35745553Sbill /* All writes and/or copyins were fine! */ 35845553Sbill else 35945553Sbill finished = bp->b_bcount; 360*49573Swilliam bad = pollrdy(); 36145553Sbill } 36245553Sbill 36345553Sbill endio: 364*49573Swilliam if(bad == EIO) bad = 0; 36545553Sbill wterror.wt_err = 0; 36645553Sbill if (exflag && wtsense((bp->b_flags & B_READ) ? TP_WRP : 0)) { 36745553Sbill if ((wterror.wt_err & TP_ST0) 36845553Sbill && (wterror.wt_err & (TP_FIL|TP_EOM))) { 36945553Sbill #ifdef DEBUG 37045553Sbill debug("WTsta: Hit end of tape\n"); /* */ 37145553Sbill #endif 37245553Sbill wtflags |= TPVOL; 37345553Sbill if (wterror.wt_err & TP_FIL) { 37445553Sbill if (wtflags & TPRO) 37545553Sbill /* interrupter is bogus */ 37645553Sbill rstart(); /* restart read command */ 37745553Sbill else 37845553Sbill wtflags &= ~TPWO; 37945553Sbill finished += NBPS; 38045553Sbill } 38145553Sbill /* Reading file marks or writing end of tape return 0 bytes */ 38245553Sbill } else { 38345553Sbill bp->b_flags |= B_ERROR; 38445553Sbill wtflags &= ~(TPWO|TPRO); 38545553Sbill } 38645553Sbill } 38745553Sbill 388*49573Swilliam if(bad) { 389*49573Swilliam bp->b_flags |= B_ERROR; 390*49573Swilliam bp->b_error = bad; 391*49573Swilliam } 39245553Sbill bp->b_resid = bp->b_bcount - finished; 39345553Sbill xit: 39445553Sbill biodone(bp); 39545553Sbill if (wtimeron) 39645553Sbill Hogtime = lbolt; 39745553Sbill else if (Hogproc == myproc) 39845553Sbill Hogproc = (struct proc *) 0; 39945553Sbill } 40045553Sbill 40145553Sbill /* 40245553Sbill * simulate an interrupt periodically while I/O is going 40345553Sbill * this is necessary in case interrupts get eaten due to 40445553Sbill * multiple devices on a single IRQ line 40545553Sbill */ 40645553Sbill wtimer() 40745553Sbill { 40845553Sbill /* If I/O going and not in isr(), simulate interrupt 40945553Sbill * If no I/O for at least 1 second, stop being a Hog 41045553Sbill * If I/O done and not a Hog, turn off wtimer() 41145553Sbill */ 41245553Sbill if (wtio && !isrlock) 41345553Sbill isr(); 41445553Sbill 41545553Sbill if ((Hogproc == myproc) && Hogtime && (lbolt-Hogtime > HZ)) 41645553Sbill Hogproc = (struct proc *) 0; 41745553Sbill 41845553Sbill if (wtio || (Hogproc == myproc)) 41945553Sbill timeout(wtimer, (caddr_t) 0, HZ); 42045553Sbill else 42145553Sbill wtimeron = 0; 42245553Sbill } 42345553Sbill 42445553Sbill 42545553Sbill wtrawio(bp) 42645553Sbill struct buf *bp; 42745553Sbill { 42845553Sbill wtstrategy(bp); 42945553Sbill biowait(bp); 43045553Sbill return(0); 43145553Sbill } 43245553Sbill 43345553Sbill wt_minphys(bp) 43445553Sbill struct buf *bp; 43545553Sbill { 43645553Sbill if (bp->b_bcount > PAGESIZ) 43745553Sbill bp->b_bcount = PAGESIZ; 43845553Sbill } 43945553Sbill 44045553Sbill /* 44145553Sbill * raw read routine 44245553Sbill */ 44345553Sbill wtread(dev, uio) 44445553Sbill struct uio *uio; 44545553Sbill { 44645553Sbill if (wtflags & TPSESS) { 44745553Sbill return(EIO); 44845553Sbill } 44945553Sbill physio(wtrawio, &rwtbuf, dev, B_READ, wt_minphys, uio); 45045553Sbill return(0); 45145553Sbill } 45245553Sbill 45345553Sbill /* 45445553Sbill * raw write routine 45545553Sbill */ 45645553Sbill wtwrite(dev, uio) 45745553Sbill struct uio *uio; 45845553Sbill { 45945553Sbill if (wtflags & TPSESS) { 46045553Sbill return(EIO); 46145553Sbill } 46245553Sbill physio(wtrawio, &rwtbuf, dev, B_WRITE, wt_minphys, uio); 46345553Sbill return(0); 46445553Sbill } 46545553Sbill 46645553Sbill 46745553Sbill 46845553Sbill /* 46945553Sbill * ioctl routine 47045553Sbill * for user level QIC commands only 47145553Sbill */ 47245553Sbill wtioctl(dev, cmd, arg, mode) 47345553Sbill int dev, cmd; 47445553Sbill unsigned long arg; 47545553Sbill int mode; 47645553Sbill { 47745553Sbill if (cmd == WTQICMD) 47845553Sbill { 47945553Sbill if ((qicmd((int)arg) == ERROR) || (rdyexc(HZ) == ERROR)) 48045553Sbill { 48145553Sbill wtsense(0); 482*49573Swilliam return(EIO); 48345553Sbill } 484*49573Swilliam return(0); 48545553Sbill } 486*49573Swilliam return(EINVAL); 48745553Sbill } 48845553Sbill 48945553Sbill /* 49045553Sbill * open routine 49145553Sbill * called on every device open 49245553Sbill */ 49345553Sbill wtopen(dev, flag) 49445553Sbill int dev, flag; 49545553Sbill { 49645553Sbill if (first_wtopen_ever) { 49745553Sbill wtinit(); 49845553Sbill first_wtopen_ever = 0; 49945553Sbill } 50045553Sbill #ifdef DEBUG 50145553Sbill printf("wtopen ...\n"); 50245553Sbill #endif 50345553Sbill if (!pageaddr) { 50445553Sbill return(ENXIO); 50545553Sbill } 50645553Sbill if (wtflags & (TPINUSE)) { 50745553Sbill return(ENXIO); 50845553Sbill } 50945553Sbill if (wtflags & (TPDEAD)) { 51045553Sbill return(EIO); 51145553Sbill } 51245553Sbill /* If a rewind from the last session is going on, wait */ 51345553Sbill while(wtflags & TPREW) { 51445553Sbill #ifdef DEBUG 51545553Sbill debug("Waiting for rew to finish\n"); 51645553Sbill #endif 51745553Sbill delay(1000000); /* delay one second */ 51845553Sbill } 51945553Sbill /* Only do reset and select when tape light is off, and tape is rewound. 52045553Sbill * This allows multiple volumes. */ 52145553Sbill if (wtflags & TPSTART) { 52245553Sbill if (t_reset() != SUCCESS) { 52345553Sbill return(ENXIO); 52445553Sbill } 52545553Sbill #ifdef DEBUG 52645553Sbill debug("reset done. calling wtsense\n"); 52745553Sbill #endif 52845553Sbill if (wtsense(TP_WRP) == ERROR) { 52945553Sbill return (EIO); 53045553Sbill } 53145553Sbill #ifdef DEBUG 53245553Sbill debug("wtsense done\n"); 53345553Sbill #endif 53445553Sbill wtflags &= ~TPSTART; 53545553Sbill } 53645553Sbill 53745553Sbill wtflags = TPINUSE; 53845553Sbill if (flag & FREAD) 53945553Sbill wtflags |= TPREAD; 54045553Sbill if (flag & FWRITE) 54145553Sbill wtflags |= TPWRITE; 54245553Sbill rwtbuf.b_flags = 0; 543*49573Swilliam myproc = curproc; /* for comparison */ 54445553Sbill switch(TP_DENS(dev)) { 54545553Sbill case 0: 54645553Sbill cmds(0x28); 54745553Sbill break; 54845553Sbill case 1: 54945553Sbill cmds(0x29); 55045553Sbill break; 55145553Sbill case 2: 55245553Sbill cmds(0x27); 55345553Sbill break; 55445553Sbill case 3: 55545553Sbill cmds(0x24); 55645553Sbill } 55745553Sbill return(0); 55845553Sbill } 55945553Sbill 56045553Sbill /* 56145553Sbill * close routine 56245553Sbill * called on last device close 56345553Sbill * If not rewind-on-close, leave read or write command intact. 56445553Sbill */ 56545553Sbill wtclose(dev) 56645553Sbill { 56745553Sbill int wtdsl2(); 56845553Sbill 56945553Sbill #ifdef DEBUG 57045553Sbill debug("WTclose:\n"); 57145553Sbill #endif 57245553Sbill if (Hogproc == myproc) 57345553Sbill Hogproc = (struct proc *) 0; 57445553Sbill if (!exflag && (wtflags & TPWANY) && !(wtflags & (TPSESS|TPDEAD))) { 57545553Sbill if (!(wtflags & TPWO)) 57645553Sbill wstart(); 57745553Sbill #ifdef DEBUG 57845553Sbill debug("WT: Writing file mark\n"); 57945553Sbill #endif 58045553Sbill wmark(); /* write file mark */ 58145553Sbill #ifdef DEBUG 58245553Sbill debug("WT: Wrote file mark, going to wait\n"); 58345553Sbill #endif 58445553Sbill if (rdyexc(HZ/10) == ERROR) { 58545553Sbill wtsense(0); 58645553Sbill } 58745553Sbill } 58845553Sbill if (TP_REWCLOSE(dev) || (wtflags & (TPSESS|TPDEAD))) { 58945553Sbill /* rewind tape to beginning of tape, deselect tape, and make a note */ 59045553Sbill /* don't wait until rewind, though */ 59145553Sbill /* Ending read or write causes rewind to happen, if no error, 59245553Sbill * and READY and EXCEPTION stay up until it finishes */ 59345553Sbill if (wtflags & (TPRO|TPWO)) 59445553Sbill { 59545553Sbill #ifdef DEBUG 59645553Sbill debug("End read or write\n"); 59745553Sbill #endif 59845553Sbill rdyexc(HZ/10); 59945553Sbill ioend(); 60045553Sbill wtflags &= ~(TPRO|TPWO); 60145553Sbill } 60245553Sbill else wtwind(); 60345553Sbill wtflags |= TPSTART | TPREW; 60445553Sbill timeout(wtdsl2, 0, HZ); 60545553Sbill } 60645553Sbill else if (!(wtflags & (TPVOL|TPWANY))) 60745553Sbill { 60845553Sbill /* space forward to after next file mark no writing done */ 60945553Sbill /* This allows skipping data without reading it.*/ 61045553Sbill #ifdef DEBUG 61145553Sbill debug("Reading past file mark\n"); 61245553Sbill #endif 61345553Sbill if (!(wtflags & TPRO)) 61445553Sbill rstart(); 61545553Sbill rmark(); 61645553Sbill if (rdyexc(HZ/10)) 61745553Sbill { 61845553Sbill wtsense(TP_WRP); 61945553Sbill } 62045553Sbill } 62145553Sbill wtflags &= TPREW|TPDEAD|TPSTART|TPRO|TPWO; 62245553Sbill return(0); 62345553Sbill } 62445553Sbill 62545553Sbill /* return ERROR if user I/O request should receive an I/O error code */ 62645553Sbill 62745553Sbill wtsense(ignor) 62845553Sbill { 62945553Sbill wtflags &= ~(TPRO|TPWO); 63045553Sbill #ifdef DEBUGx 63145553Sbill debug("WTsense: start "); 63245553Sbill #endif 63345553Sbill if (rdstatus(&wterror) == ERROR) 63445553Sbill { 63545553Sbill #ifdef DEBUG 63645553Sbill debug("WTsense: Can't read status\n"); 63745553Sbill #endif 63845553Sbill return(ERROR); 63945553Sbill } 64045553Sbill #ifdef DEBUG 64145553Sbill if (wterror.wt_err & (TP_ST0|TP_ST1)) 64245553Sbill { 64345553Sbill debug("Tperror: status %x error %d underruns %d\n", 64445553Sbill wterror.wt_err, wterror.wt_ercnt, wterror.wt_urcnt); 64545553Sbill } 64645553Sbill else 64745553Sbill debug("done. no error\n"); 64845553Sbill #endif 64945553Sbill wterror.wt_err &= ~ignor; /* ignore certain errors */ 65045553Sbill reperr(wterror.wt_err); 65145553Sbill if (((wterror.wt_err & TP_ST0) && (wterror.wt_err & TP_ERR0)) || 65245553Sbill ((wterror.wt_err & TP_ST1) && (wterror.wt_err & TP_ERR1))) 65345553Sbill return ERROR; 65445553Sbill 65545553Sbill return SUCCESS; 65645553Sbill } 65745553Sbill 65845553Sbill /* lifted from tdriver.c from Wangtek */ 65945553Sbill reperr(srb0) 66045553Sbill int srb0; 66145553Sbill { 66245553Sbill int s0 = srb0 & (TP_ERR0|TP_ERR1); /* find out which exception to report */ 66345553Sbill 66445553Sbill if (s0) { 66545553Sbill if (s0 & TP_USL) 66645553Sbill sterr("Drive not online"); 66745553Sbill else if (s0 & TP_CNI) 66845553Sbill sterr("No cartridge"); 66945553Sbill else if ((s0 & TP_WRP) && !(wtflags & TPWP)) 67045553Sbill { 67145553Sbill sterr("Tape is write protected"); 67245553Sbill wtflags |= TPWP; 67345553Sbill } 67445553Sbill /* 67545553Sbill if (s0 & TP_FIL) 67645553Sbill sterr("Filemark detected"); 67745553Sbill */ 67845553Sbill else if (s0 & TP_BNL) 67945553Sbill sterr("Block in error not located"); 68045553Sbill else if (s0 & TP_UDA) 68145553Sbill sterr("Unrecoverable data error"); 68245553Sbill /* 68345553Sbill else if (s0 & TP_EOM) 68445553Sbill sterr("End of tape"); 68545553Sbill */ 68645553Sbill else if (s0 & TP_NDT) 68745553Sbill sterr("No data detected"); 68845553Sbill /* 68945553Sbill if (s0 & TP_POR) 69045553Sbill sterr("Reset occured"); 69145553Sbill */ 69245553Sbill else if (s0 & TP_BOM) 69345553Sbill sterr("Beginning of tape"); 69445553Sbill else if (s0 & TP_ILL) 69545553Sbill sterr("Illegal command"); 69645553Sbill } 69745553Sbill } 69845553Sbill 69945553Sbill sterr(errstr) 70045553Sbill char *errstr; 70145553Sbill { 70245553Sbill printf("Streamer: %s\n", errstr); 70345553Sbill } 70445553Sbill 70545553Sbill /* Wait until rewind finishes, and deselect drive */ 70645553Sbill wtdsl2() { 70745553Sbill int stat; 70845553Sbill 70945553Sbill stat = inb(wtport) & (READY|EXCEP); 71045553Sbill #ifdef DEBUG 71145553Sbill debug("Timeout: Waiting for rewind to finish: stat %x\n", stat); 71245553Sbill #endif 71345553Sbill switch (stat) { 71445553Sbill /* They're active low, ya'know */ 71545553Sbill case READY|EXCEP: 71645553Sbill timeout(wtdsl2, (caddr_t) 0, HZ); 71745553Sbill return; 71845553Sbill case EXCEP: 71945553Sbill wtflags &= ~TPREW; 72045553Sbill return; 72145553Sbill case READY: 72245553Sbill case 0: 72345553Sbill wtflags &= ~TPREW; 72445553Sbill sterr("Rewind failed"); 72545553Sbill wtsense(TP_WRP); 72645553Sbill return; 72745553Sbill } 72845553Sbill } 72945553Sbill 73045553Sbill wtwind() { 73145553Sbill #ifdef DEBUG 73245553Sbill debug("WT: About to rewind\n"); 73345553Sbill #endif 73445553Sbill rwind(); /* actually start rewind */ 73545553Sbill } 73645553Sbill 737*49573Swilliam wtintr(unit) { 73845553Sbill if (wtflags & (TPWO|TPRO)) 73945553Sbill { 74045553Sbill isrlock = 1; 74145553Sbill if (wtio) isr(); 74245553Sbill isrlock = 0; 74345553Sbill } 74445553Sbill } 74545553Sbill 74645553Sbill wtinit() { 74745553Sbill if (wtchan < 1 || wtchan > 3) 74845553Sbill { 74945553Sbill sterr("Bad DMA channel, cannot init driver"); 75045553Sbill return; 75145553Sbill } 75245553Sbill wtlinit(); /* init assembly language variables */ 75345553Sbill pageset(); 75445553Sbill } 75545553Sbill 75645553Sbill rdyexc(ticks) 75745553Sbill { 75845553Sbill int s; 75945553Sbill #ifdef DEBUG 76045553Sbill int os = 0xffff; /* force printout first time */ 76145553Sbill #endif 76245553Sbill for (;;) { /* loop until ready or exception */ 76345553Sbill s=(inb(wtport) & 0xff); /* read the status register */ 76445553Sbill #ifdef DEBUG 76545553Sbill if (os != s) { 76645553Sbill debug("Status reg = %x\n", s); /* */ 76745553Sbill os = s; 76845553Sbill } 76945553Sbill #endif 77045553Sbill if (!(s & EXCEP)) /* check if exception have occured */ 77145553Sbill break; 77245553Sbill if (!(s & READY)) /* check if controller is ready */ 77345553Sbill break; 77445553Sbill s = splbio(); 77545553Sbill delay((ticks/HZ)*1000000); /* */ 77645553Sbill splx(s); 77745553Sbill } 77845553Sbill #ifdef DEBUG 77945553Sbill debug("Status reg = %x on return\n", s); /* */ 78045553Sbill #endif 78145553Sbill return((s & EXCEP)?SUCCESS:ERROR); /* return exception if it occured */ 78245553Sbill } 78345553Sbill 78445553Sbill pollrdy() 78545553Sbill { 78645553Sbill int sps; 78745553Sbill #ifdef DEBUG 78845553Sbill debug("Pollrdy\n"); 78945553Sbill #endif 79045553Sbill sps = splbio(); 791*49573Swilliam while (wtio) { 792*49573Swilliam int error; 793*49573Swilliam 794*49573Swilliam if (error = tsleep((caddr_t)&wci, WTPRI | PCATCH, 795*49573Swilliam "wtpoll", 0)) { 796*49573Swilliam splx(sps); 797*49573Swilliam return(error); 798*49573Swilliam } 799*49573Swilliam } 80045553Sbill splx(sps); 80145553Sbill #ifdef DEBUG 80245553Sbill debug("Finish poll, wci %d exflag %d\n", wci, exflag); 80345553Sbill #endif 804*49573Swilliam return (EIO); 80545553Sbill } 80645553Sbill 80745553Sbill wtdma() /* start up i/o operation, called from dma() in wtlib1.s */ 80845553Sbill { 80945553Sbill wtio = 1; 81045553Sbill if (!wtimeron) 81145553Sbill { 81245553Sbill wtimeron = 1; 81345553Sbill timeout(wtimer, (caddr_t) 0, HZ/2); 81445553Sbill } 81545553Sbill } 81645553Sbill 81745553Sbill wtwake() /* end i/o operation, called from isr() in wtlib1.s */ 81845553Sbill { 81945553Sbill wtio = 0; 82045553Sbill wakeup(&wci); 82145553Sbill } 82245553Sbill 82345553Sbill pageset() 82445553Sbill { 82545553Sbill unsigned long pp; 82645553Sbill 82745553Sbill pp = (unsigned long) pagebuf; 82845553Sbill pageaddr = kvtop(pp); 82945553Sbill #ifdef DEBUG 83045553Sbill debug("pageset: addr %lx\n", pageaddr); 83145553Sbill #endif 83245553Sbill } 83345553Sbill 83445553Sbill 83545553Sbill 83645553Sbill #define near 83745553Sbill 83845553Sbill static near 83945553Sbill sendcmd() 84045553Sbill { 84145553Sbill /* desired command in global mbits */ 84245553Sbill 84345553Sbill outb(CTLPORT, mbits | REQUEST); /* set request */ 84445553Sbill while (inb(STATPORT) & READY); /* wait for ready */ 84545553Sbill outb(CTLPORT, mbits & ~REQUEST); /* reset request */ 84645553Sbill while ((inb(STATPORT) & READY) == 0); /* wait for not ready */ 84745553Sbill } 84845553Sbill 84945553Sbill static near /* execute command */ 85045553Sbill cmds(cmd) 85145553Sbill { 85245553Sbill register s; 85345553Sbill 85445553Sbill do s = inb(STATPORT); 85545553Sbill while ((s & STAT) == STAT); /* wait for ready */ 85645553Sbill 85745553Sbill if ((s & EXCEP) == 0) /* if exception */ 85845553Sbill return ERROR; /* error */ 85945553Sbill 86045553Sbill outb(CMDPORT, cmd); /* output the command */ 86145553Sbill 86245553Sbill outb(CTLPORT, mbits=ONLINE); /* set & send ONLINE */ 86345553Sbill sendcmd(); 86445553Sbill 86545553Sbill return SUCCESS; 86645553Sbill } 86745553Sbill 86845553Sbill qicmd(cmd) 86945553Sbill { 87045553Sbill return cmds(cmd); 87145553Sbill } 87245553Sbill 87345553Sbill rstart() 87445553Sbill { 87545553Sbill return cmds(RDDATA); 87645553Sbill } 87745553Sbill 87845553Sbill rmark() 87945553Sbill { 88045553Sbill return cmds(READFM); 88145553Sbill } 88245553Sbill 88345553Sbill wstart() 88445553Sbill { 88545553Sbill return cmds(WRTDATA); 88645553Sbill } 88745553Sbill 88845553Sbill ioend() 88945553Sbill { 89045553Sbill register s; 89145553Sbill register rval = SUCCESS; 89245553Sbill 89345553Sbill do s = inb(STATPORT); 89445553Sbill while ((s & STAT) == STAT); /* wait for ready */ 89545553Sbill 89645553Sbill if ((s & EXCEP) == 0) /* if exception */ 89745553Sbill rval = ERROR; /* error */ 89845553Sbill 89945553Sbill mbits &= ~ONLINE; 90045553Sbill outb(CTLPORT, mbits); /* reset ONLINE */ 90145553Sbill outb(MASKREG, wtchan+4); /* turn off dma */ 90245553Sbill outb(CLEARFF, 0); /* reset direction flag */ 90345553Sbill 90445553Sbill return rval; 90545553Sbill } 90645553Sbill 90745553Sbill wmark() 90845553Sbill { 90945553Sbill register s; 91045553Sbill 91145553Sbill if (cmds(WRITEFM) == ERROR) 91245553Sbill return ERROR; 91345553Sbill 91445553Sbill do s = inb(STATPORT); 91545553Sbill while ((s & STAT) == STAT); /* wait for ready */ 91645553Sbill 91745553Sbill if ((s & EXCEP) == 0) /* if exception */ 91845553Sbill return ERROR; /* error */ 91945553Sbill 92045553Sbill return SUCCESS; 92145553Sbill } 92245553Sbill 92345553Sbill rwind() 92445553Sbill { 92545553Sbill register s; 92645553Sbill 92745553Sbill mbits = CMDOFF; 92845553Sbill 92945553Sbill do s = inb(STATPORT); 93045553Sbill while ((s & STAT) == STAT); /* wait for ready */ 93145553Sbill 93245553Sbill outb(CMDPORT, REWIND); 93345553Sbill sendcmd(); 93445553Sbill 93545553Sbill return SUCCESS; 93645553Sbill } 93745553Sbill 93845553Sbill rdstatus(stp) 93945553Sbill char *stp; /* pointer to 6 byte buffer */ 94045553Sbill { 94145553Sbill register s; 94245553Sbill int n; 94345553Sbill 94445553Sbill do s = inb(STATPORT); 94545553Sbill while ((s & STAT) == STAT); /* wait for ready or exception */ 94645553Sbill 94745553Sbill outb(CMDPORT, RDSTAT); 94845553Sbill sendcmd(); /* send read status command */ 94945553Sbill 95045553Sbill for (n=0; n<6; n++) 95145553Sbill { 95245553Sbill #ifdef DEBUGx 95345553Sbill debug("rdstatus: waiting, byte %d\n", n); 95445553Sbill #endif 95545553Sbill do s = inb(STATPORT); 95645553Sbill while ((s & STAT) == STAT); /* wait for ready */ 95745553Sbill #ifdef DEBUGx 95845553Sbill debug("rdstatus: done\n"); 95945553Sbill #endif 96045553Sbill if ((s & EXCEP) == 0) /* if exception */ 96145553Sbill return ERROR; /* error */ 96245553Sbill 96345553Sbill *stp++ = inb(DATAPORT); /* read status byte */ 96445553Sbill 96545553Sbill outb(CTLPORT, mbits | REQUEST); /* set request */ 96645553Sbill #ifdef DEBUGx 96745553Sbill debug("rdstatus: waiting after request, byte %d\n", n); 96845553Sbill #endif 96945553Sbill while ((inb(STATPORT)&READY) == 0); /* wait for not ready */ 97045553Sbill for (s=100; s>0; s--); /* wait an additional time */ 97145553Sbill 97245553Sbill outb(CTLPORT, mbits & ~REQUEST);/* unset request */ 97345553Sbill #ifdef DEBUGx 97445553Sbill debug("rdstatus: done\n"); 97545553Sbill #endif 97645553Sbill } 97745553Sbill return SUCCESS; 97845553Sbill } 97945553Sbill 98045553Sbill t_reset() 98145553Sbill { 98245553Sbill register i; 98345553Sbill mbits |= RESET; 98445553Sbill outb(CTLPORT, mbits); /* send reset */ 98545553Sbill delay(20); 98645553Sbill mbits &= ~RESET; 98745553Sbill outb(CTLPORT, mbits); /* turn off reset */ 98845553Sbill if ((inb(STATPORT) & RESETMASK) == RESETVAL) 98945553Sbill return SUCCESS; 99045553Sbill return ERROR; 99145553Sbill } 99245553Sbill 99345553Sbill static 99445553Sbill dma() 99545553Sbill { 99645553Sbill int x=splbio(); 99745553Sbill wtdma(); 99845553Sbill outb(CLEARFF, 0); 99945553Sbill outb(MODEREG, mode); /* set dma mode */ 100045553Sbill outb(dmareg, bufptr & 0xFF); 100145553Sbill outb(dmareg, (bufptr>>8) & 0xFF); 100245553Sbill outb(pagereg, (bufptr>>16) & 0xFF); 100345553Sbill outb(dmareg+1, (BLKSIZE-1) & 0xFF); 100445553Sbill outb(dmareg+1, (BLKSIZE-1) >> 8); 100545553Sbill outb(wtport, eqdma+ONLINE); 100645553Sbill outb(MASKREG, wtchan); /* enable command to 8237, start dma */ 100745553Sbill splx(x); 100845553Sbill } 100945553Sbill 101045553Sbill static near 101145553Sbill wtstart(buf, cnt) 101245553Sbill long buf; 101345553Sbill int cnt; 101445553Sbill { 101545553Sbill register s; 101645553Sbill 101745553Sbill bufptr = buf; /* init statics */ 101845553Sbill numbytes = cnt; 101945553Sbill wci = 0; /* init flags */ 102045553Sbill exflag = 0; 102145553Sbill bytes = 0; /* init counter */ 102245553Sbill 102345553Sbill do s = inb(STATPORT) & STAT; 102445553Sbill while (s == STAT); /* wait for ready or error */ 102545553Sbill 102645553Sbill if (s & EXCEP) /* no error */ 102745553Sbill { 102845553Sbill dma(); 102945553Sbill return SUCCESS; 103045553Sbill } 103145553Sbill return ERROR; /* error */ 103245553Sbill } 103345553Sbill 103445553Sbill rtape(buf, cnt) 103545553Sbill long buf; /* physical address */ 103645553Sbill int cnt; /* number of bytes */ 103745553Sbill { 103845553Sbill mode = dma_read; 103945553Sbill return wtstart(buf,cnt); 104045553Sbill } 104145553Sbill 104245553Sbill wtape(buf, cnt) 104345553Sbill long buf; /* physical address */ 104445553Sbill int cnt; /* number of bytes */ 104545553Sbill { 104645553Sbill mode = dma_write; 104745553Sbill return wtstart(buf,cnt); 104845553Sbill } 104945553Sbill 105045553Sbill isr() 105145553Sbill { 105245553Sbill int stat = inb(wtport); 105345553Sbill if (!(stat & EXCEP)) /* exception during I/O */ 105445553Sbill { 105545553Sbill if (bytes + BLKSIZE >= numbytes) wci = 1; 105645553Sbill exflag = 1; 105745553Sbill goto isrwake; 105845553Sbill } 105945553Sbill if ((stat & READY) || !(inb(STATUSREG) & dma_done)) 106045553Sbill return; 106145553Sbill exflag = 0; 106245553Sbill outb(wtport, ONLINE); 106345553Sbill bytes += BLKSIZE; 106445553Sbill if (bytes >= numbytes) /* normal completion of I/O */ 106545553Sbill { 106645553Sbill wci = 1; 106745553Sbill isrwake: 106845553Sbill outb(MASKREG, 4+wtchan); /* turn off dma */ 106945553Sbill wtwake(); /* wake up user level */ 107045553Sbill } 107145553Sbill else 107245553Sbill { /* continue I/O */ 107345553Sbill bufptr += BLKSIZE; 107445553Sbill dma(); 107545553Sbill } 107645553Sbill } 107745553Sbill 107845553Sbill wtlinit() 107945553Sbill { 108045553Sbill switch (wtchan) { 108145553Sbill case 1: 108245553Sbill return; 108345553Sbill case 2: 108445553Sbill pagereg = 0x81; 108545553Sbill dma_done = 4; 108645553Sbill break; 108745553Sbill case 3: 108845553Sbill eqdma = 0x10; 108945553Sbill pagereg = 0x82; 109045553Sbill dma_done = 8; 109145553Sbill break; 109245553Sbill } 109345553Sbill dma_write = wtchan+0x48; 109445553Sbill dma_read = wtchan+0x44; 109545553Sbill dmareg = wtchan+wtchan; 109645553Sbill } 109745553Sbill 109845553Sbill /* 109945553Sbill * delay i microseconds 110045553Sbill */ 110145553Sbill delay(i) 110245553Sbill register int i; 110345553Sbill { 110445553Sbill while (i-- > 0) 110545553Sbill DELAY(1000); 110645553Sbill } 110745553Sbill 110845553Sbill wtsize() 110945553Sbill { 111045553Sbill } 111145553Sbill 111245553Sbill wtdump() 111345553Sbill { 111445553Sbill } 111545553Sbill 1116*49573Swilliam #include "i386/isa/isa_device.h" 1117*49573Swilliam #include "i386/isa/icu.h" 111845553Sbill 111945553Sbill int wtprobe(), wtattach(); 112045553Sbill struct isa_driver wtdriver = { 112145553Sbill wtprobe, wtattach, "wt", 112245553Sbill }; 112345553Sbill 112445553Sbill wtprobe(dvp) 112545553Sbill struct isa_device *dvp; 112645553Sbill { 112745553Sbill int val,i,s; 112845553Sbill 112945553Sbill #ifdef lint 113045553Sbill wtintr(0); 113145553Sbill #endif 113245553Sbill 113345553Sbill wtport = dvp->id_iobase; 113445553Sbill if(t_reset() != SUCCESS) return(0); 113545553Sbill return(1); 113645553Sbill } 113745553Sbill 113845553Sbill wtattach() { } 113945553Sbill 114045553Sbill #endif NWT 1141