Commit | Line | Data |
---|---|---|
f86df66c | 1 | /* va.c 3.5 %G% */ |
20cc8b5b BJ |
2 | |
3 | #ifdef ERNIE | |
4 | #include "../h/param.h" | |
5 | #include "../h/dir.h" | |
6 | #include "../h/user.h" | |
7 | #include "../h/buf.h" | |
8 | #include "../h/systm.h" | |
9 | #include "../h/map.h" | |
10 | #include "../h/pte.h" | |
11 | #include "../h/uba.h" | |
12 | #include "../h/vcmd.h" | |
13 | ||
14 | /* | |
15 | * Benson-Varian matrix printer/plotter. Device "va", for "varian". | |
16 | * dma interface driver | |
17 | */ | |
18 | int vabdp = 1; /* Used with ubasetup. */ | |
19 | ||
20 | unsigned minvaph(); /* Maximum amount transferred by physio. */ | |
21 | ||
22 | #define VAPRI (PZERO-1) | |
23 | ||
24 | struct varegs { /* Unibus registers provided by va. */ | |
25 | unsigned short vabufaddr; /* DMA buffer address. */ | |
26 | short vawcount; /* Negative of number of 16-bit | |
27 | words to transfer by DMA. */ | |
28 | union { | |
29 | short vacsrword; /* csr addressed as a word (for R). */ | |
30 | struct { | |
31 | char Vacsrlo; | |
32 | char Vacsrhi; /* High byte (command bytes go here). */ | |
33 | } vacsrbytes; /* csr addressed as bytes (for W). */ | |
34 | } vacsr; /* Control/Status Register (csr). */ | |
35 | short vadata; | |
36 | }; | |
37 | ||
38 | #define vacsrhi vacsr.vacsrbytes.Vacsrhi | |
39 | #define vacsrlo vacsr.vacsrbytes.Vacsrlo | |
40 | #define VAADDR ((struct varegs *)(UBA0_DEV + 0164000)) | |
41 | ||
42 | /* vacsr.vacsrword bits: */ | |
43 | #define ERROR 0100000 /* R Some error has occurred */ | |
44 | #define NPRTIMO 01000 /* R DMA timeout error */ | |
45 | #define NOTREADY 0400 /* R Something besides NPRTIMO */ | |
46 | #define DONE 0200 /* R */ | |
47 | #define IENABLE 0100 /* R/W Interrupt enable */ | |
48 | #define SUPPLIESLOW 04 /* R */ | |
49 | #define BOTOFFORM 02 /* R */ | |
50 | #define BYTEREVERSE 01 /* R/W Reverse byte order in words */ | |
51 | ||
52 | /* Command bytes sent to vacsrhi */ | |
53 | #define VAPLOT 0340 | |
54 | #define VAPRINT 0100 | |
55 | #define VAPRINTPLOT 0160 | |
56 | #define VAAUTOSTEP 0244 | |
57 | /* The following commands are not used in this driver: */ | |
58 | #define VANOAUTOSTEP 0045 | |
59 | #define VAFORMFEED 0263 | |
60 | #define VASLEW 0265 | |
61 | #define VASTEP 0064 | |
62 | ||
63 | struct { | |
64 | char va_is_open; | |
65 | char va_busy; | |
66 | int va_state; /* State: bits are commands in vcmd.h. */ | |
67 | int va_wcount; | |
68 | int va_bufp; | |
69 | } vainfo; | |
70 | int va_ubinfo; | |
71 | ||
72 | struct buf rvabuf; /* Used by physio for a buffer. */ | |
73 | ||
74 | vaopen() | |
75 | { | |
76 | ||
77 | if (vainfo.va_is_open) { /* Can't open if it's already open. */ | |
78 | u.u_error = ENXIO; | |
79 | return; | |
80 | } | |
81 | vainfo.va_is_open = 1; /* NOW it's open! */ | |
82 | VAADDR->vawcount = 0; /* Clear residual errors */ | |
83 | vainfo.va_wcount = 0; /* No DMA to do now. */ | |
84 | vainfo.va_state = 0; | |
85 | VAADDR->vacsrlo = IENABLE; | |
86 | /* Enable interrupts. */ | |
87 | vatimo(); | |
88 | ||
89 | vacmd(VPRINT); /* Start in print mode. */ | |
90 | if (u.u_error) | |
91 | vaclose(); | |
92 | } | |
93 | ||
94 | vastrategy(bp) | |
95 | register struct buf *bp; | |
96 | { | |
97 | register int e; | |
98 | ||
81263dba | 99 | (void) spl4(); |
20cc8b5b BJ |
100 | while (vainfo.va_busy) /* Wait till not busy. */ |
101 | sleep((caddr_t)&vainfo, VAPRI); | |
102 | vainfo.va_busy = 1; /* Grab it. */ | |
81263dba | 103 | (void) spl0(); |
20cc8b5b BJ |
104 | |
105 | va_ubinfo = ubasetup(bp, vabdp); /* Set up uba mapper. */ | |
106 | vainfo.va_bufp = va_ubinfo & 0x3ffff; | |
107 | ||
81263dba | 108 | (void) spl4(); |
20cc8b5b BJ |
109 | if (e = vaerror(DONE)) |
110 | goto brkout; | |
111 | vainfo.va_wcount = -(bp->b_bcount/2); | |
112 | /* va uses a word count, | |
113 | so user had better supply an even number of bytes. */ | |
114 | vastart(); | |
115 | e = vaerror(DONE); /* Wait for DMA to complete. */ | |
116 | vainfo.va_wcount = 0; /* Reset state info. */ | |
117 | vainfo.va_bufp = 0; | |
118 | ||
119 | /* After printing a line of characters, VPRINTPLOT mode essentially | |
120 | reverts to VPLOT mode, plotting things until a new mode is set. | |
121 | This change is indicated by sending a VAAUTOSTEP command to | |
122 | the va. We also change va_state to reflect this effective | |
123 | mode change. | |
124 | */ | |
125 | if (vainfo.va_state & VPRINTPLOT) { | |
126 | vainfo.va_state = (vainfo.va_state & ~VPRINTPLOT) | VPLOT; | |
127 | VAADDR->vacsrhi = VAAUTOSTEP; | |
128 | e |= vaerror(DONE); | |
129 | } | |
81263dba | 130 | (void) spl0(); |
20cc8b5b BJ |
131 | brkout: |
132 | ubafree(va_ubinfo), va_ubinfo = 0; | |
133 | vainfo.va_busy = 0; | |
134 | iodone(bp); | |
135 | if (e) | |
136 | u.u_error = EIO; | |
137 | wakeup((caddr_t)&vainfo); | |
138 | } | |
139 | ||
140 | int vablock = 16384; | |
141 | ||
142 | unsigned | |
143 | minvaph(bp) | |
144 | struct buf *bp; | |
145 | { | |
146 | if (bp->b_bcount > vablock) | |
147 | bp->b_bcount = vablock; | |
148 | } | |
149 | ||
150 | /*ARGSUSED*/ | |
151 | vawrite(dev) | |
152 | { | |
153 | physio(vastrategy, &rvabuf, dev, B_WRITE, minvaph); | |
154 | } | |
155 | ||
156 | /* | |
157 | * Vaerror waits until bit or ERROR gets set, then returns non-zero if | |
158 | * if it was ERROR that was set. | |
159 | */ | |
160 | vaerror(bit) | |
161 | { | |
162 | register int e; | |
163 | ||
164 | while ((e = VAADDR->vacsr.vacsrword & (bit|ERROR)) == 0) | |
165 | sleep((caddr_t)&vainfo, VAPRI); | |
166 | return (e & ERROR); | |
167 | } | |
168 | ||
169 | /* vastart starts up the DMA by setting the buffer pointer and the word count. */ | |
170 | vastart() | |
171 | { | |
172 | if (vainfo.va_wcount) { | |
173 | VAADDR->vabufaddr = vainfo.va_bufp; | |
174 | VAADDR->vawcount = vainfo.va_wcount; | |
175 | return; | |
176 | } | |
177 | } | |
178 | ||
179 | /*ARGSUSED*/ | |
180 | vaioctl(dev, cmd, addr, flag) | |
181 | register caddr_t addr; | |
182 | { | |
183 | register int vcmd; | |
184 | ||
185 | switch (cmd) { | |
186 | ||
187 | case VGETSTATE: | |
81263dba | 188 | (void) suword(addr, vainfo.va_state); |
20cc8b5b BJ |
189 | return; |
190 | ||
191 | case VSETSTATE: | |
192 | vcmd = fuword(addr); | |
193 | if (vcmd == -1) { | |
194 | u.u_error = EFAULT; | |
195 | return; | |
196 | } | |
197 | vacmd(vcmd); | |
198 | return; | |
199 | ||
200 | default: | |
201 | u.u_error = ENOTTY; /* Not a legal ioctl cmd. */ | |
202 | return; | |
203 | } | |
204 | } | |
205 | ||
206 | /* vacmd sends a command code to the va, and waits for it to complete. | |
207 | If an error occurs, u.u_error is set to EIO. | |
208 | vacmd also updates vainfo.va_state. | |
209 | */ | |
210 | ||
211 | vacmd(vcmd) | |
212 | { | |
81263dba BJ |
213 | (void) spl4(); |
214 | (void) vaerror(DONE); /* Wait for va to be ready. */ | |
20cc8b5b BJ |
215 | switch (vcmd) { |
216 | ||
217 | case VPLOT: | |
218 | /* Must turn on plot AND autostep modes. */ | |
219 | VAADDR->vacsrhi = VAPLOT; | |
220 | if (vaerror(DONE)) | |
221 | u.u_error = EIO; | |
222 | VAADDR->vacsrhi = VAAUTOSTEP; | |
223 | break; | |
224 | ||
225 | case VPRINT: | |
226 | VAADDR->vacsrhi = VAPRINT; | |
227 | break; | |
228 | ||
229 | case VPRINTPLOT: | |
230 | VAADDR->vacsrhi = VAPRINTPLOT; | |
231 | break; | |
232 | } | |
233 | vainfo.va_state = | |
234 | (vainfo.va_state & ~(VPLOT | VPRINT | VPRINTPLOT)) | vcmd; | |
235 | ||
236 | if (vaerror(DONE)) /* Wait for command to complete. */ | |
237 | u.u_error = EIO; | |
81263dba | 238 | (void) spl0(); |
20cc8b5b BJ |
239 | } |
240 | ||
241 | vatimo() | |
242 | { | |
243 | if (vainfo.va_is_open) | |
244 | timeout(vatimo, (caddr_t)0, HZ/10); | |
245 | vaintr(0); | |
246 | } | |
247 | ||
248 | /*ARGSUSED*/ | |
249 | vaintr(dev) | |
250 | { | |
251 | wakeup((caddr_t)&vainfo); | |
252 | } | |
253 | ||
254 | vaclose() | |
255 | { | |
256 | ||
257 | vainfo.va_is_open = 0; | |
258 | vainfo.va_busy = 0; | |
259 | vainfo.va_state = 0; | |
260 | vainfo.va_wcount = 0; | |
261 | vainfo.va_bufp = 0; | |
262 | VAADDR->vacsrlo = 0; | |
263 | } | |
264 | #endif |