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