Commit | Line | Data |
---|---|---|
9d61b7ff | 1 | /* dr.c 1.6 86/12/15 */ |
20340301 SL |
2 | |
3 | #include "dr.h" | |
4 | #if NDR > 0 | |
9d61b7ff SL |
5 | /* |
6 | * DRV11-W DMA interface driver. | |
7 | * | |
b5d0006f | 8 | * UNTESTED WITH 4.3 |
20340301 | 9 | */ |
20340301 SL |
10 | #include "../machine/mtpr.h" |
11 | #include "../machine/pte.h" | |
12 | ||
13 | #include "param.h" | |
14 | #include "conf.h" | |
15 | #include "dir.h" | |
16 | #include "user.h" | |
17 | #include "proc.h" | |
18 | #include "map.h" | |
19 | #include "ioctl.h" | |
20 | #include "buf.h" | |
21 | #include "vm.h" | |
22 | #include "uio.h" | |
9d61b7ff | 23 | #include "kernel.h" |
20340301 SL |
24 | |
25 | #include "../tahoevba/vbavar.h" | |
26 | #include "../tahoevba/drreg.h" | |
27 | ||
28 | #define YES 1 | |
29 | #define NO 0 | |
30 | ||
31 | struct vba_device *drinfo[NDR]; | |
32 | struct dr_aux dr_aux[NDR]; | |
33 | ||
20340301 | 34 | unsigned drminphys(); |
9d61b7ff SL |
35 | int drprobe(), drintr(), drattach(), drtimo(), drrwtimo(); |
36 | int drstrategy(); | |
37 | extern struct vba_device *drinfo[]; | |
38 | static long drstd[] = { 0 }; | |
20340301 | 39 | struct vba_driver drdriver = |
9d61b7ff | 40 | { drprobe, 0, drattach, 0, drstd, "rs", drinfo }; |
20340301 SL |
41 | |
42 | #define RSUNIT(dev) (minor(dev) & 7) | |
43 | #define SPL_UP spl5 | |
44 | ||
45 | /* -------- Per-unit data -------- */ | |
46 | ||
47 | extern struct dr_aux dr_aux[]; | |
48 | ||
20340301 | 49 | #ifdef DR_DEBUG |
9d61b7ff | 50 | long DR11 = 0; |
20340301 SL |
51 | #endif |
52 | ||
53 | drprobe(reg, vi) | |
9d61b7ff SL |
54 | caddr_t reg; |
55 | struct vba_device *vi; | |
20340301 | 56 | { |
9d61b7ff SL |
57 | register int br, cvec; /* must be r12, r11 */ |
58 | struct rsdevice *dr; | |
20340301 | 59 | |
9d61b7ff SL |
60 | #ifdef lint |
61 | br = 0; cvec = br; br = cvec; | |
62 | drintr(0); | |
20340301 | 63 | #endif |
9d61b7ff SL |
64 | if (badaddr(reg, 2)) |
65 | return (0); | |
66 | dr = (struct rsdevice *)reg; | |
67 | dr->dr_intvect = --vi->ui_hd->vh_lastiv; | |
20340301 | 68 | #ifdef DR_DEBUG |
9d61b7ff | 69 | printf("dprobe: Set interrupt vector %lx and init\n",dr->dr_intvec); |
20340301 | 70 | #endif |
9d61b7ff SL |
71 | /* generate interrupt here for autoconfig */ |
72 | dr->dr_cstat = MCLR; /* init board and device */ | |
20340301 | 73 | #ifdef DR_DEBUG |
9d61b7ff | 74 | printf("drprobe: Initial status %lx\n", dr->dr_cstat); |
20340301 | 75 | #endif |
9d61b7ff SL |
76 | br = 0x18, cvec = dr->dr_intvect; /* XXX */ |
77 | return (sizeof (struct rsdevice)); /* DR11 exist */ | |
20340301 SL |
78 | } |
79 | ||
80 | /* ARGSUSED */ | |
81 | drattach(ui) | |
9d61b7ff | 82 | struct vba_device *ui; |
20340301 | 83 | { |
9d61b7ff SL |
84 | register struct dr_aux *rsd; |
85 | ||
86 | rsd = &dr_aux[ui->ui_unit]; | |
87 | rsd->dr_flags = DR_PRES; /* This dr11 is present */ | |
88 | rsd->dr_addr = (struct rsdevice *)ui->ui_addr; /* Save addr of this dr11 */ | |
89 | rsd->dr_istat = 0; | |
90 | rsd->dr_bycnt = 0; | |
91 | rsd->dr_cmd = 0; | |
92 | rsd->currenttimo = 0; | |
20340301 SL |
93 | } |
94 | ||
9d61b7ff SL |
95 | /*ARGSUSED*/ |
96 | dropen(dev, flag) | |
97 | dev_t dev; | |
98 | int flag; | |
20340301 | 99 | { |
9d61b7ff SL |
100 | register int unit = RSUNIT(dev); |
101 | register struct rsdevice *dr; | |
102 | register struct dr_aux *rsd; | |
103 | ||
104 | if (drinfo[unit] == 0 || !drinfo[unit]->ui_alive) | |
105 | return (ENXIO); | |
106 | dr = RSADDR(unit); | |
107 | rsd = &dr_aux[unit]; | |
108 | if (rsd->dr_flags & DR_OPEN) { | |
20340301 | 109 | #ifdef DR_DEBUG |
9d61b7ff | 110 | printf("\ndropen: dr11 unit %ld already open",unit); |
20340301 | 111 | #endif |
9d61b7ff SL |
112 | return (ENXIO); /* DR11 already open */ |
113 | } | |
114 | rsd->dr_flags |= DR_OPEN; /* Mark it OPEN */ | |
115 | rsd->dr_istat = 0; /* Clear status of previous interrupt */ | |
116 | rsd->rtimoticks = hz; /* Set read no stall timout to 1 sec */ | |
117 | rsd->wtimoticks = hz*60; /* Set write no stall timout to 1 min */ | |
118 | dr->dr_cstat = DR_ZERO; /* Clear function & latches */ | |
119 | dr->dr_pulse = (RDMA | RATN); /* clear leftover attn & e-o-r flags */ | |
120 | drtimo(dev); /* start the self kicker */ | |
121 | return (0); | |
20340301 SL |
122 | } |
123 | ||
124 | drclose (dev) | |
9d61b7ff | 125 | dev_t dev; |
20340301 | 126 | { |
9d61b7ff SL |
127 | register int unit = RSUNIT(dev); |
128 | register struct dr_aux *dra; | |
129 | register struct rsdevice *rs; | |
130 | register short s; | |
20340301 | 131 | |
9d61b7ff SL |
132 | dra = &dr_aux[unit]; |
133 | if ((dra->dr_flags & DR_OPEN) == 0) { | |
20340301 | 134 | #ifdef DR_DEBUG |
9d61b7ff | 135 | printf("\ndrclose: DR11 device %ld not open",unit); |
20340301 | 136 | #endif |
9d61b7ff SL |
137 | return; |
138 | } | |
139 | dra->dr_flags &= ~(DR_OPEN|DR_ACTV); | |
140 | rs = dra->dr_addr; | |
141 | s = SPL_UP(); | |
142 | rs->dr_cstat = DR_ZERO; | |
143 | if (dra->dr_buf.b_flags & B_BUSY) { | |
144 | dra->dr_buf.b_flags &= ~B_BUSY; | |
145 | wakeup((caddr_t)&dra->dr_buf.b_flags); | |
146 | } | |
147 | splx(s); | |
20340301 SL |
148 | } |
149 | ||
150 | ||
151 | /* drread() works exactly like drwrite() except that the | |
152 | B_READ flag is used when physio() is called | |
153 | */ | |
154 | drread (dev, uio) | |
9d61b7ff SL |
155 | dev_t dev; |
156 | struct uio *uio; | |
20340301 SL |
157 | { register struct dr_aux *dra; |
158 | register struct buf *bp; | |
9d61b7ff SL |
159 | register int spl, err; |
160 | register int unit = RSUNIT(dev); | |
20340301 | 161 | |
9d61b7ff SL |
162 | if (uio->uio_iov->iov_len <= 0 || /* Negative count */ |
163 | uio->uio_iov->iov_len & 1 || /* odd count */ | |
164 | (int)uio->uio_iov->iov_base & 1) /* odd destination address */ | |
165 | return (EINVAL); | |
20340301 | 166 | #ifdef DR_DEBUG |
9d61b7ff SL |
167 | if (DR11 & 8) |
168 | printf("\ndrread: (len:%ld)(base:%lx)", | |
169 | uio->uio_iov->iov_len,(int)uio->uio_iov->iov_base); | |
20340301 | 170 | #endif |
9d61b7ff SL |
171 | dra = &dr_aux[RSUNIT(dev)]; |
172 | dra->dr_op = DR_READ; | |
173 | bp = &dra->dr_buf; | |
174 | bp->b_resid = 0; | |
175 | if (dra->dr_flags & DR_NORSTALL) { | |
176 | /* | |
177 | * We are in no stall mode, start the timer, | |
178 | * raise IPL so nothing can stop us once the | |
179 | * timer's running | |
180 | */ | |
181 | spl = SPL_UP(); | |
182 | timeout(drrwtimo, (caddr_t)((dra->currenttimo<<8) | unit), | |
183 | (int)dra->rtimoticks); | |
184 | err = physio(drstrategy, bp, dev,B_READ, drminphys, uio); | |
185 | splx(spl); | |
186 | if (err) | |
187 | return (err); | |
188 | dra->currenttimo++; /* Update current timeout number */ | |
189 | /* Did we timeout */ | |
190 | if (dra->dr_flags & DR_TMDM) { | |
191 | dra->dr_flags &= ~DR_TMDM; /* Clear timeout flag */ | |
192 | u.u_error = 0; /* Made the error ourself, ignore it */ | |
193 | } | |
194 | return (err); | |
20340301 | 195 | } |
9d61b7ff | 196 | return (physio(drstrategy, bp, dev,B_READ, drminphys, uio)); |
20340301 SL |
197 | } |
198 | ||
9d61b7ff SL |
199 | drwrite(dev, uio) |
200 | dev_t dev; | |
201 | struct uio *uio; | |
20340301 SL |
202 | { register struct dr_aux *dra; |
203 | register struct buf *bp; | |
9d61b7ff SL |
204 | register int unit = RSUNIT(dev); |
205 | int spl, err; | |
20340301 | 206 | |
9d61b7ff SL |
207 | if (uio->uio_iov->iov_len <= 0 || uio->uio_iov->iov_len & 1 || |
208 | (int)uio->uio_iov->iov_base & 1) | |
209 | return (EINVAL); | |
20340301 | 210 | #ifdef DR_DEBUG |
9d61b7ff SL |
211 | if (DR11 & 4) |
212 | printf("\ndrwrite: (len:%ld)(base:%lx)", | |
213 | uio->uio_iov->iov_len,(int)uio->uio_iov->iov_base); | |
20340301 | 214 | #endif |
9d61b7ff SL |
215 | dra = &dr_aux[RSUNIT(dev)]; |
216 | dra->dr_op = DR_WRITE; | |
217 | bp = &dra->dr_buf; | |
218 | bp->b_resid = 0; | |
219 | if (dra->dr_flags & DR_NOWSTALL) { | |
220 | /* | |
221 | * We are in no stall mode, start the timer, | |
222 | * raise IPL so nothing can stop us once the | |
223 | * timer's running | |
224 | */ | |
225 | spl = SPL_UP(); | |
226 | timeout(drrwtimo,(caddr_t)((dra->currenttimo<<8) | unit), | |
227 | (int)dra->wtimoticks); | |
228 | err = physio (drstrategy, bp, dev,B_WRITE, drminphys, uio); | |
229 | splx(spl); | |
230 | if (err) | |
231 | return (err); | |
232 | dra->currenttimo++; /* Update current timeout number */ | |
233 | /* Did we timeout */ | |
234 | if (dra->dr_flags & DR_TMDM) { | |
235 | dra->dr_flags &= ~DR_TMDM; /* Clear timeout flag */ | |
236 | u.u_error = 0; /* Made the error ourself, ignore it */ | |
237 | } | |
238 | return (err); | |
20340301 | 239 | } |
9d61b7ff | 240 | return (physio(drstrategy, bp, dev,B_WRITE, drminphys, uio)); |
20340301 SL |
241 | } |
242 | ||
9d61b7ff SL |
243 | /* |
244 | * Routine used by calling program to issue commands to dr11 driver and | |
245 | * through it to the device. | |
246 | * It is also used to read status from the device and driver and to wait | |
247 | * for attention interrupts. | |
248 | * Status is returned in an 8 elements unsigned short integer array, the | |
249 | * first two elements of the array are also used to pass arguments to | |
250 | * drioctl() if required. | |
251 | * The function bits to be written to the dr11 are included in the cmd | |
252 | * argument. Even if they are not being written to the dr11 in a particular | |
253 | * drioctl() call, they will update the copy of cmd that is stored in the | |
254 | * driver. When drstrategy() is called, this updated copy is used if a | |
255 | * deferred function bit write has been specified. The "side effect" of | |
256 | * calls to the drioctl() requires that the last call prior to a read or | |
257 | * write has an appropriate copy of the function bits in cmd if they are | |
258 | * to be used in drstrategy(). | |
259 | * When used as command value, the contents of data[0] is the command | |
260 | * parameter. | |
261 | */ | |
262 | drioctl(dev, cmd, data) | |
263 | dev_t dev; | |
264 | int cmd; | |
265 | long *data; | |
20340301 | 266 | { |
9d61b7ff SL |
267 | register int unit = RSUNIT(dev); |
268 | register struct dr_aux *dra; | |
269 | register struct rsdevice *rsaddr = RSADDR(unit); | |
270 | int s; | |
271 | u_short status; | |
272 | long temp; | |
273 | ||
274 | #ifdef DR_DEBUG | |
275 | if (DR11 & 0x10) | |
276 | printf("\ndrioctl: (dev:%lx)(cmd:%lx)(data:%lx)(data[0]:%lx)", | |
277 | dev,cmd,data,data[0]); | |
278 | #endif | |
279 | dra = &dr_aux[unit]; | |
280 | dra->dr_cmd = 0; /* Fresh copy; clear all previous flags */ | |
281 | switch (cmd) { | |
20340301 | 282 | |
9d61b7ff | 283 | case DRWAIT: /* Wait for attention interrupt */ |
20340301 | 284 | #ifdef DR_DEBUG |
9d61b7ff | 285 | printf("\ndrioctl: wait for attention interrupt"); |
20340301 | 286 | #endif |
9d61b7ff SL |
287 | s = SPL_UP(); |
288 | /* | |
289 | * If the attention flag in dr_flags is set, it probably | |
290 | * means that an attention has arrived by the time a | |
291 | * previous DMA end-of-range interrupt was serviced. If | |
292 | * ATRX is set, we will return with out sleeping, since | |
293 | * we have received an attention since the last call to | |
294 | * wait on attention. This may not be appropriate for | |
295 | * some applications. | |
296 | */ | |
297 | if ((dra->dr_flags & DR_ATRX) == 0) { | |
298 | dra->dr_flags |= DR_ATWT; /* Set waiting flag */ | |
299 | /* | |
300 | * Enable interrupt; use pulse reg. | |
301 | * so function bits are not changed | |
302 | */ | |
303 | rsaddr->dr_pulse = IENB; | |
304 | sleep((caddr_t)&dra->dr_cmd, DRPRI); | |
305 | } | |
306 | splx(s); | |
307 | break; | |
308 | ||
309 | case DRPIOW: /* Write to p-i/o register */ | |
310 | rsaddr->dr_data = data[0]; | |
311 | break; | |
312 | ||
313 | case DRPACL: /* Send pulse to device */ | |
314 | rsaddr->dr_pulse = FCN2; | |
315 | break; | |
316 | ||
317 | case DRDACL: /* Defer alco pulse until go */ | |
318 | dra->dr_cmd |= DR_DACL; | |
319 | break; | |
320 | ||
321 | case DRPCYL: /* Set cycle with next go */ | |
322 | dra->dr_cmd |= DR_PCYL; | |
323 | break; | |
324 | ||
325 | case DRDFCN: /* Update function with next go */ | |
326 | dra->dr_cmd |= DR_DFCN; | |
327 | break; | |
328 | ||
329 | case DRRATN: /* Reset attention flag */ | |
330 | rsaddr->dr_pulse = RATN; | |
331 | break; | |
332 | ||
333 | case DRRDMA: /* Reset DMA e-o-r flag */ | |
334 | rsaddr->dr_pulse = RDMA; | |
335 | break; | |
336 | ||
337 | case DRSFCN: /* Set function bits */ | |
338 | temp = data[0] & DR_FMSK; | |
339 | /* | |
340 | * This has a very important side effect -- It clears | |
341 | * the interrupt enable flag. That is fine for this driver, | |
342 | * but if it is desired to leave interrupt enable at all | |
343 | * times, it will be necessary to read the status register | |
344 | * first to get IENB, or carry a software flag that indicates | |
345 | * whether interrupts are set, and or this into the control | |
346 | * register value being written. | |
347 | */ | |
348 | rsaddr->dr_cstat = temp; | |
349 | break; | |
350 | ||
351 | case DRRPER: /* Clear parity flag */ | |
352 | rsaddr->dr_pulse = RPER; | |
353 | break; | |
354 | ||
355 | case DRSETRSTALL: /* Set read stall mode. */ | |
356 | dra->dr_flags &= (~DR_NORSTALL); | |
357 | break; | |
358 | ||
359 | case DRSETNORSTALL: /* Set no stall read mode. */ | |
360 | dra->dr_flags |= DR_NORSTALL; | |
361 | break; | |
362 | ||
363 | case DRGETRSTALL: /* Returns true if in read stall mode */ | |
364 | data[0] = (dra->dr_flags & DR_NORSTALL)? 0 : 1; | |
365 | break; | |
366 | ||
367 | case DRSETRTIMEOUT: /* Set read stall timeout (1/10 secs) */ | |
368 | if (data[0] < 1) { | |
369 | u.u_error = EINVAL; | |
370 | temp = 1; | |
371 | } | |
372 | dra->rtimoticks = (data[0] * hz )/10; | |
373 | break; | |
20340301 | 374 | |
9d61b7ff SL |
375 | case DRGETRTIMEOUT: /* Return read stall timeout */ |
376 | data[0] = ((dra->rtimoticks)*10)/hz; | |
377 | break; | |
20340301 | 378 | |
9d61b7ff SL |
379 | case DRSETWSTALL: /* Set write stall mode. */ |
380 | dra->dr_flags &= (~DR_NOWSTALL); | |
381 | break; | |
20340301 | 382 | |
9d61b7ff SL |
383 | case DRSETNOWSTALL: /* Set write stall mode. */ |
384 | dra->dr_flags |= DR_NOWSTALL; | |
385 | break; | |
386 | ||
387 | case DRGETWSTALL: /* Return true if in write stall mode */ | |
388 | data[0] = (dra->dr_flags & DR_NOWSTALL)? 0 : 1; | |
389 | break; | |
390 | ||
391 | case DRSETWTIMEOUT: /* Set write stall timeout (1/10's) */ | |
392 | if (data[0] < 1) { | |
393 | u.u_error = EINVAL; | |
394 | temp = 1; | |
395 | } | |
396 | dra->wtimoticks = (data[0] * hz )/10; | |
397 | break; | |
398 | ||
399 | case DRGETWTIMEOUT: /* Return write stall timeout */ | |
400 | data[0] = ((dra->wtimoticks)*10)/hz; | |
401 | break; | |
402 | ||
403 | case DRWRITEREADY: /* Return true if can write data */ | |
404 | data[0] = (rsaddr->dr_cstat & STTA)? 1 : 0; | |
405 | break; | |
406 | ||
407 | case DRREADREADY: /* Return true if data to be read */ | |
408 | data[0] = (rsaddr->dr_cstat & STTB)? 1 : 0; | |
409 | break; | |
410 | ||
411 | case DRBUSY: /* Return true if device busy */ | |
412 | /* | |
413 | * Internally this is the DR11-W | |
414 | * STAT C bit, but there is a bug in the Omega 500/FIFO | |
415 | * interface board that it cannot drive this signal low | |
416 | * for certain DR11-W ctlr such as the Ikon. We use the | |
417 | * REDY signal of the CSR on the Ikon DR11-W instead. | |
418 | */ | |
419 | #ifdef notdef | |
420 | data[0] = (rsaddr->dr_cstat & STTC)? 1 : 0; | |
421 | #else | |
422 | data[0] = ((rsaddr->dr_cstat & REDY)? 0 : 1); | |
20340301 | 423 | #endif |
9d61b7ff SL |
424 | break; |
425 | ||
426 | case DRRESET: /* Reset device */ | |
427 | /* Reset DMA ATN RPER flag */ | |
428 | rsaddr->dr_pulse = (MCLR|RDMA|RATN|RPER); | |
429 | DELAY(0x1f000); | |
430 | while ((rsaddr->dr_cstat & REDY) == 0) | |
431 | sleep((caddr_t)dra, DRPRI); /* Wakeup by drtimo() */ | |
432 | dra->dr_istat = 0; | |
433 | dra->dr_cmd = 0; | |
434 | dra->currenttimo = 0; | |
435 | break; | |
436 | ||
437 | case DR11STAT: { /* Copy back dr11 status to user */ | |
438 | register struct dr11io *dr = (struct dr11io *)data; | |
439 | dr->arg[0] = dra->dr_flags; | |
440 | dr->arg[1] = rsaddr->dr_cstat; | |
441 | dr->arg[2] = dra->dr_istat; /* Status at last interrupt */ | |
442 | dr->arg[3] = rsaddr->dr_data; /* P-i/o input data */ | |
443 | status = (u_short)((rsaddr->dr_addmod << 8) & 0xff00); | |
444 | dr->arg[4] = status | (u_short)(rsaddr->dr_intvect & 0xff); | |
445 | dr->arg[5] = rsaddr->dr_range; | |
446 | dr->arg[6] = rsaddr->dr_rahi; | |
447 | dr->arg[7] = rsaddr->dr_ralo; | |
448 | break; | |
20340301 | 449 | } |
9d61b7ff SL |
450 | case DR11LOOP: /* Perform loopback test */ |
451 | /* | |
452 | * NB: MUST HAVE LOOPBACK CABLE ATTACHED -- | |
453 | * Test results are printed on system console | |
454 | */ | |
455 | if (suser()) | |
456 | dr11loop(rsaddr, dra, unit); | |
457 | break; | |
458 | ||
459 | default: | |
460 | return (EINVAL); | |
20340301 | 461 | } |
20340301 | 462 | #ifdef DR_DEBUG |
9d61b7ff SL |
463 | if (DR11 & 0x10) |
464 | printf("**** (data[0]:%lx)",data[0]); | |
20340301 | 465 | #endif |
9d61b7ff | 466 | return (0); |
20340301 SL |
467 | } |
468 | ||
9d61b7ff SL |
469 | #define NPAT 2 |
470 | #define DMATBL 20 | |
471 | u_short tstpat[DMATBL] = { 0xAAAA, 0x5555}; | |
472 | long DMAin = 0; | |
aa4f73e3 | 473 | |
9d61b7ff SL |
474 | /* |
475 | * Perform loopback test -- MUST HAVE LOOPBACK CABLE ATTACHED | |
476 | * Test results are printed on system console | |
477 | */ | |
478 | dr11loop(dr, dra, unit) | |
479 | struct rsdevice *dr; | |
480 | struct dr_aux *dra; | |
481 | int unit; | |
482 | { | |
483 | register long result, ix; | |
484 | long addr, wait; | |
aa4f73e3 SL |
485 | |
486 | dr->dr_cstat = MCLR; /* Clear board & device, disable intr */ | |
9d61b7ff | 487 | printf("\n\t ----- DR11 unit %ld loopback test -----", unit); |
aa4f73e3 SL |
488 | printf("\n\t Program I/O ..."); |
489 | for (ix=0;ix<NPAT;ix++) { | |
490 | dr->dr_data = tstpat[ix]; /* Write to Data out register */ | |
9d61b7ff | 491 | result = dr->dr_data & 0xFFFF; /* Read it back */ |
aa4f73e3 SL |
492 | if (result != tstpat[ix]) { |
493 | printf("Failed, expected : %lx --- actual : %lx", | |
9d61b7ff | 494 | tstpat[ix], result); |
aa4f73e3 SL |
495 | return; |
496 | } | |
497 | } | |
aa4f73e3 SL |
498 | printf("OK\n\t Functions & Status Bits ..."); |
499 | dr->dr_cstat = (FCN1 | FCN3); | |
500 | result = dr->dr_cstat & 0xffff; /* Read them back */ | |
501 | if ((result & (STTC | STTA)) != (STTC |STTA)) { | |
502 | printf("Failed, expected : %lx --- actual : %lx, ISR:%lx", | |
9d61b7ff | 503 | (STTA|STTC), (result & (STTA|STTC)), result); |
aa4f73e3 SL |
504 | return; |
505 | } | |
506 | dr->dr_cstat = FCN2; | |
507 | result = dr->dr_cstat & 0xffff; /* Read them back */ | |
508 | if ((result & STTB) != STTB) { | |
509 | printf("Failed, expected : %lx --- actual : %lx, ISR:%lx", | |
9d61b7ff | 510 | STTB, (result & STTB), result); |
aa4f73e3 SL |
511 | return; |
512 | } | |
aa4f73e3 | 513 | printf("OK\n\t DMA output ..."); |
9d61b7ff SL |
514 | if (DMAin) |
515 | goto dmain; | |
aa4f73e3 | 516 | /* Initialize DMA data buffer */ |
9d61b7ff SL |
517 | for (ix=0; ix<DMATBL; ix++) |
518 | tstpat[ix] = 0xCCCC + ix; | |
aa4f73e3 | 519 | tstpat[DMATBL-1] = 0xCCCC; /* Last word output */ |
aa4f73e3 | 520 | /* Setup normal DMA */ |
9d61b7ff SL |
521 | addr = (long)vtoph((struct proc *)0, (unsigned)tstpat); |
522 | dr->dr_walo = (addr >> 1) & 0xffff; | |
523 | dr->dr_wahi = (addr >> 17) & 0x7fff; | |
524 | /* Set DMA range count: (number of words - 1) */ | |
525 | dr->dr_range = DMATBL - 1; | |
526 | /* Set address modifier code to be used for DMA access to memory */ | |
527 | dr->dr_addmod = DRADDMOD; | |
528 | ||
529 | /* | |
530 | * Clear dmaf and attf to assure a clean dma start, also disable | |
531 | * attention interrupt | |
532 | */ | |
533 | dr->dr_pulse = RDMA|RATN|RMSK; /* Use pulse register */ | |
534 | dr->dr_cstat = GO|CYCL; /* GO...... */ | |
aa4f73e3 SL |
535 | |
536 | /* Wait for DMA complete; REDY and DMAF are true in ISR */ | |
537 | wait = 0; | |
9d61b7ff SL |
538 | while ((result=(dr->dr_cstat & (REDY|DMAF))) != (REDY|DMAF)) { |
539 | printf("\n\tWait for DMA complete...ISR : %lx", result); | |
aa4f73e3 SL |
540 | if (++wait > 5) { |
541 | printf("\n\t DMA output fails...timeout!!, ISR:%lx", | |
542 | result); | |
543 | return; | |
544 | } | |
545 | } | |
aa4f73e3 SL |
546 | result = dr->dr_data & 0xffff; /* Read last word output */ |
547 | if (result != 0xCCCC) { | |
548 | printf("\n\t Fails, expected : %lx --- actual : %lx", | |
9d61b7ff | 549 | 0xCCCC, result); |
aa4f73e3 SL |
550 | return; |
551 | } | |
aa4f73e3 | 552 | printf("OK\n\t DMA input ..."); |
aa4f73e3 SL |
553 | dmain: |
554 | dr->dr_data = 0x1111; /* DMA input data */ | |
555 | /* Setup normal DMA */ | |
9d61b7ff SL |
556 | addr = (long)vtoph((struct proc *)0, (unsigned)tstpat); |
557 | dr->dr_walo = (addr >> 1) & 0xffff; | |
558 | dr->dr_wahi = (addr >> 17) & 0x7fff; | |
559 | dr->dr_range = DMATBL - 1; | |
560 | dr->dr_addmod = (char)DRADDMOD; | |
561 | dr->dr_cstat = FCN1; /* Set FCN1 in ICR to DMA in*/ | |
562 | if ((dra->dr_flags & DR_LOOPTST) == 0) { | |
aa4f73e3 | 563 | /* Use pulse reg */ |
9d61b7ff | 564 | dr->dr_pulse = RDMA|RATN|RMSK|CYCL|GO; |
aa4f73e3 SL |
565 | /* Wait for DMA complete; REDY and DMAF are true in ISR */ |
566 | wait = 0; | |
9d61b7ff | 567 | while ((result=(dr->dr_cstat & (REDY|DMAF))) != (REDY|DMAF)) { |
aa4f73e3 SL |
568 | printf("\n\tWait for DMA to complete...ISR:%lx",result); |
569 | if (++wait > 5) { | |
570 | printf("\n\t DMA input timeout!!, ISR:%lx", | |
571 | result); | |
572 | return; | |
573 | } | |
574 | } | |
9d61b7ff | 575 | } else { |
aa4f73e3 | 576 | /* Enable DMA e-o-r interrupt */ |
9d61b7ff | 577 | dr->dr_pulse = IENB|RDMA|RATN|CYCL|GO; |
aa4f73e3 SL |
578 | /* Wait for DMA complete; DR_LOOPTST is false in dra->dr_flags*/ |
579 | wait = 0; | |
580 | while (dra->dr_flags & DR_LOOPTST) { | |
581 | result = dr->dr_cstat & 0xffff; | |
9d61b7ff | 582 | printf("\n\tWait for DMA e-o-r intr...ISR:%lx", result); |
aa4f73e3 SL |
583 | if (++wait > 7) { |
584 | printf("\n\t DMA e-o-r timeout!!, ISR:%lx", | |
585 | result); | |
586 | dra->dr_flags &= ~DR_LOOPTST; | |
587 | return; | |
588 | } | |
589 | } | |
590 | dra->dr_flags |= DR_LOOPTST; | |
591 | } | |
9d61b7ff SL |
592 | mtpr(P1DC, tstpat); /* Purge cache */ |
593 | mtpr(P1DC, 0x3ff+tstpat); | |
594 | for (ix=0; ix<DMATBL; ix++) { | |
aa4f73e3 | 595 | if (tstpat[ix] != 0x1111) { |
9d61b7ff SL |
596 | printf("\n\t Fails, ix:%d, expected:%x --- actual:%x", |
597 | ix, 0x1111, tstpat[ix]); | |
aa4f73e3 SL |
598 | return; |
599 | } | |
600 | } | |
9d61b7ff | 601 | if ((dra->dr_flags & DR_LOOPTST) == 0) { |
aa4f73e3 SL |
602 | dra->dr_flags |= DR_LOOPTST; |
603 | printf(" OK..\n\tDMA end of range interrupt..."); | |
604 | goto dmain; | |
605 | } | |
aa4f73e3 | 606 | printf(" OK..\n\tAttention interrupt...."); |
9d61b7ff SL |
607 | dr->dr_pulse = IENB|RDMA; |
608 | dr->dr_pulse = FCN2; | |
aa4f73e3 SL |
609 | /* Wait for ATTN interrupt; DR_LOOPTST is false in dra->dr_flags*/ |
610 | wait = 0; | |
611 | while (dra->dr_flags & DR_LOOPTST) { | |
612 | result = dr->dr_cstat & 0xffff; | |
613 | printf("\n\tWait for Attention intr...ISR:%lx",result); | |
614 | if (++wait > 7) { | |
615 | printf("\n\t Attention interrupt timeout!!, ISR:%lx", | |
616 | result); | |
617 | dra->dr_flags &= ~DR_LOOPTST; | |
618 | return; | |
619 | } | |
620 | } | |
621 | dra->dr_flags &= ~DR_LOOPTST; | |
622 | printf(" OK..\n\tDone..."); | |
623 | } | |
624 | ||
20340301 | 625 | /* Reset state on Unibus reset */ |
9d61b7ff | 626 | /*ARGSUSED*/ |
20340301 | 627 | drreset(uban) |
9d61b7ff | 628 | int uban; |
20340301 | 629 | { |
9d61b7ff | 630 | |
20340301 SL |
631 | } |
632 | ||
633 | /* | |
634 | * An interrupt is caused either by an error, | |
635 | * base address overflow, or transfer complete | |
636 | */ | |
9d61b7ff SL |
637 | drintr(dr11) |
638 | int dr11; | |
20340301 | 639 | { |
9d61b7ff SL |
640 | register struct dr_aux *dra = &dr_aux[dr11]; |
641 | register struct rsdevice *rsaddr = RSADDR(dr11); | |
642 | register struct buf *bp; | |
643 | register short status; | |
20340301 | 644 | |
9d61b7ff SL |
645 | status = rsaddr->dr_cstat & 0xffff; /* get board status register */ |
646 | dra->dr_istat = status; | |
20340301 | 647 | #ifdef DR_DEBUG |
9d61b7ff SL |
648 | if (DR11 & 2) |
649 | printf("\ndrintr: dr11 status : %lx",status & 0xffff); | |
20340301 | 650 | #endif |
9d61b7ff SL |
651 | if (dra->dr_flags & DR_LOOPTST) { /* doing loopback test */ |
652 | dra->dr_flags &= ~DR_LOOPTST; | |
653 | return; | |
654 | } | |
655 | /* | |
656 | * Make sure this is not a stray interrupt; at least one of dmaf or attf | |
657 | * must be set. Note that if the dr11 interrupt enable latch is reset | |
658 | * during a hardware interrupt ack sequence, and by the we get to this | |
659 | * point in the interrupt code it will be 0. This is done to give the | |
660 | * programmer some control over how the two more-or-less independent | |
661 | * interrupt sources on the board are handled. | |
662 | * If the attention flag is set when drstrategy() is called to start a | |
663 | * dma read or write an interrupt will be generated as soon as the | |
664 | * strategy routine enables interrupts for dma end-of-range. This will | |
665 | * cause execution of the interrupt routine (not necessarily bad) and | |
666 | * will cause the interrupt enable mask to be reset (very bad since the | |
667 | * dma end-of-range condition will not be able to generate an interrupt | |
668 | * when it occurs) causing the dma operation to time-out (even though | |
669 | * the dma transfer will be done successfully) or hang the process if a | |
670 | * software time-out capability is not implemented. One way to avoid | |
671 | * this situation is to check for a pending attention interrupt (attf | |
672 | * set) by calling drioctl() before doing a read or a write. For the | |
673 | * time being this driver will solve the problem by clearing the attf | |
674 | * flag in the status register before enabling interrupts in | |
675 | * drstrategy(). | |
676 | * | |
677 | * **** The IKON 10084 for which this driver is written will set both | |
678 | * attf and dmaf if dma is terminated by an attention pulse. This will | |
679 | * cause a wakeup(&dr_aux), which will be ignored since it is not being | |
680 | * waited on, and an iodone(bp) which is the desired action. Some other | |
681 | * dr11 emulators, in particular the IKON 10077 for the Multibus, donot | |
682 | * dmaf in this case. This may require some addtional code in the inter- | |
683 | * rupt routine to ensure that en iodone(bp) is issued when dma is term- | |
684 | * inated by attention. | |
685 | */ | |
686 | bp = dra->dr_actf; | |
687 | if ((status & (ATTF | DMAF)) == 0) { | |
688 | printf("dr%d: stray interrupt, status=%x", dr11, status); | |
689 | return; | |
690 | } | |
691 | if (status & DMAF) { /* End-of-range interrupt */ | |
692 | dra->dr_flags |= DR_DMAX; | |
20340301 SL |
693 | |
694 | #ifdef DR_DEBUG | |
9d61b7ff SL |
695 | if (DR11 & 2) |
696 | printf("\ndrintr: e-o-r interrupt,cstat:%lx,dr_flags:%lx", | |
697 | status&0xffff, dra->dr_flags & DR_ACTV); | |
20340301 | 698 | #endif |
9d61b7ff SL |
699 | if ((dra->dr_flags & DR_ACTV) == 0) { |
700 | /* We are not doing DMA !! */ | |
701 | bp->b_flags |= B_ERROR; | |
702 | } else { | |
703 | if (dra->dr_op == DR_READ) | |
704 | mtpr(P1DC, bp->b_un.b_addr); | |
705 | dra->dr_bycnt -= bp->b_bcount; | |
706 | if (dra->dr_bycnt >0) { | |
707 | bp->b_un.b_addr += bp->b_bcount; | |
708 | bp->b_bcount = (dra->dr_bycnt > NBPG) ? NBPG: | |
20340301 | 709 | dra->dr_bycnt; |
9d61b7ff SL |
710 | drstart(rsaddr, dra, bp); |
711 | return; | |
712 | } | |
20340301 | 713 | } |
9d61b7ff SL |
714 | dra->dr_flags &= ~DR_ACTV; |
715 | wakeup((caddr_t)dra); /* Wakeup waiting in drwait() */ | |
716 | rsaddr->dr_pulse = (RPER|RDMA|RATN); /* reset dma e-o-r flag */ | |
717 | } | |
718 | /* | |
719 | * Now test for attention interrupt -- It may be set in addition to | |
720 | * the dma e-o-r interrupt. If we get one we will issue a wakeup to | |
721 | * the drioctl() routine which is presumable waiting for one. | |
722 | * The program may have to monitor the attention interrupt received | |
723 | * flag in addition to doing waits for the interrupt. Futhermore, | |
724 | * interrupts are not enabled unless dma is in progress or drioctl() | |
725 | * has been called to wait for attention -- this may produce some | |
726 | * strange results if attf is set on the dr11 when a read or a write | |
727 | * is initiated, since that will enables interrupts. | |
728 | * **** The appropriate code for this interrupt routine will probably | |
729 | * be rather application dependent. | |
730 | */ | |
731 | if (status & ATTF) { | |
732 | dra->dr_flags |= DR_ATRX; | |
733 | dra->dr_flags &= ~DR_ATWT; | |
734 | rsaddr->dr_cstat = RATN; /* reset attention flag */ | |
735 | /* | |
736 | * Some applications which use attention to terminate | |
737 | * dma may also want to issue an iodone() here to | |
738 | * wakeup physio(). | |
739 | */ | |
740 | wakeup((caddr_t)&dra->dr_cmd); | |
20340301 | 741 | } |
20340301 SL |
742 | } |
743 | ||
744 | unsigned | |
745 | drminphys(bp) | |
9d61b7ff | 746 | struct buf *bp; |
20340301 | 747 | { |
9d61b7ff SL |
748 | |
749 | if (bp->b_bcount > 65536) | |
750 | bp->b_bcount = 65536; | |
20340301 SL |
751 | } |
752 | ||
753 | /* | |
9d61b7ff SL |
754 | * This routine performs the device unique operations on the DR11W |
755 | * it is passed as an argument to and invoked by physio | |
20340301 SL |
756 | */ |
757 | drstrategy (bp) | |
9d61b7ff | 758 | register struct buf *bp; |
20340301 | 759 | { |
9d61b7ff SL |
760 | register int s; |
761 | int unit = RSUNIT(bp->b_dev); | |
762 | register struct rsdevice *rsaddr = RSADDR(unit); | |
763 | register struct dr_aux *dra = &dr_aux[unit]; | |
764 | register int ok; | |
20340301 | 765 | #ifdef DR_DEBUG |
9d61b7ff SL |
766 | register char *caddr; |
767 | long drva(); | |
20340301 SL |
768 | #endif |
769 | ||
9d61b7ff SL |
770 | if ((dra->dr_flags & DR_OPEN) == 0) { /* Device not open */ |
771 | bp->b_error = ENXIO; | |
772 | bp->b_flags |= B_ERROR; | |
773 | iodone (bp); | |
774 | return; | |
775 | } | |
776 | while (dra->dr_flags & DR_ACTV) | |
777 | /* Device is active; should never be in here... */ | |
778 | sleep((caddr_t)&dra->dr_flags,DRPRI); | |
779 | dra->dr_actf = bp; | |
20340301 | 780 | #ifdef DR_DEBUG |
9d61b7ff | 781 | drva(dra, bp->b_proc, bp->b_un.b_addr, bp->b_bcount); |
20340301 | 782 | #endif |
9d61b7ff SL |
783 | dra->dr_oba = bp->b_un.b_addr; /* Save original addr, count */ |
784 | dra->dr_obc = bp->b_bcount; | |
785 | dra->dr_bycnt = bp->b_bcount; /* Save xfer count used by drintr() */ | |
786 | if ((((long)bp->b_un.b_addr & 0x3fffffff) >> PGSHIFT) != | |
787 | ((((long)bp->b_un.b_addr & 0x3fffffff) + bp->b_bcount) >> PGSHIFT)) | |
788 | bp->b_bcount = NBPG - (((long)bp->b_un.b_addr) & PGOFSET); | |
789 | dra->dr_flags |= DR_ACTV; /* Mark active (use in intr handler) */ | |
790 | s = SPL_UP(); | |
791 | drstart(rsaddr,dra,bp); | |
792 | splx(s); | |
793 | ok = drwait(rsaddr,dra); | |
20340301 | 794 | #ifdef DR_DEBUG |
9d61b7ff SL |
795 | if (DR11 & 0x40) { |
796 | caddr = (char *)dra->dr_oba; | |
797 | if (dra->dr_op == DR_READ) | |
798 | printf("\nAfter read: (%lx)(%lx)", | |
799 | caddr[0]&0xff, caddr[1]&0xff); | |
800 | } | |
20340301 | 801 | #endif |
9d61b7ff SL |
802 | dra->dr_flags &= ~DR_ACTV; /* Clear active flag */ |
803 | bp->b_un.b_addr = dra->dr_oba; /* Restore original addr, count */ | |
804 | bp->b_bcount = dra->dr_obc; | |
805 | if (!ok) | |
806 | bp->b_flags |= B_ERROR; | |
807 | /* Mark buffer B_DONE,so physstrat() in ml/machdep.c won't sleep */ | |
808 | iodone(bp); | |
809 | wakeup((caddr_t)&dra->dr_flags); | |
810 | /* | |
811 | * Return to the calling program (physio()). Physio() will sleep | |
812 | * until awaken by a call to iodone() in the interupt handler -- | |
813 | * which will be called by the dispatcher when it receives dma | |
814 | * end-of-range interrupt. | |
815 | */ | |
20340301 SL |
816 | } |
817 | ||
9d61b7ff SL |
818 | drwait(rs, dr) |
819 | register struct rsdevice *rs; | |
820 | register struct dr_aux *dr; | |
20340301 | 821 | { |
9d61b7ff | 822 | int s; |
20340301 SL |
823 | |
824 | s = SPL_UP(); | |
9d61b7ff SL |
825 | while (dr->dr_flags & DR_ACTV) |
826 | sleep((caddr_t)dr, DRPRI); | |
20340301 | 827 | splx(s); |
9d61b7ff | 828 | if (dr->dr_flags & DR_TMDM) { /* DMA timed out */ |
20340301 | 829 | dr->dr_flags &= ~DR_TMDM; |
9d61b7ff | 830 | return (0); |
20340301 | 831 | } |
9d61b7ff SL |
832 | if (rs->dr_cstat & (PERR|BERR|TERR)) { |
833 | dr->dr_actf->b_flags |= B_ERROR; | |
834 | return (0); | |
20340301 SL |
835 | } |
836 | dr->dr_flags &= ~DR_DMAX; | |
9d61b7ff | 837 | return (1); |
20340301 SL |
838 | } |
839 | ||
20340301 | 840 | /* |
9d61b7ff SL |
841 | * |
842 | * The lower 8-bit of tinfo is the minor device number, the | |
843 | * remaining higher 8-bit is the current timout number | |
844 | */ | |
845 | drrwtimo(tinfo) | |
846 | register u_long tinfo; | |
847 | { | |
848 | register long unit = tinfo & 0xff; | |
20340301 SL |
849 | register struct dr_aux *dr = &dr_aux[unit]; |
850 | register struct rsdevice *rs = dr->dr_addr; | |
851 | ||
9d61b7ff SL |
852 | /* |
853 | * If this is not the timeout that drwrite/drread is waiting | |
854 | * for then we should just go away | |
855 | */ | |
856 | if ((tinfo &~ 0xff) != (dr->currenttimo << 8)) | |
857 | return; | |
20340301 SL |
858 | /* Mark the device timed out */ |
859 | dr->dr_flags |= DR_TMDM; | |
860 | dr->dr_flags &= ~DR_ACTV; | |
861 | rs->dr_pulse = RMSK; /* Inihibit interrupt */ | |
862 | rs->dr_pulse = (RPER|RDMA|RATN|IENB); /* Clear DMA logic */ | |
9d61b7ff SL |
863 | /* |
864 | * Some applications will not issue a master after dma timeout, | |
865 | * since doing so sends an INIT H pulse to the external device, | |
866 | * which may produce undesirable side-effects. | |
867 | */ | |
20340301 | 868 | /* Wake up process waiting in drwait() and flag the error */ |
9d61b7ff | 869 | dr->dr_actf->b_flags |= B_ERROR; |
20340301 SL |
870 | wakeup((caddr_t)dr->dr_cmd); |
871 | } | |
872 | ||
20340301 | 873 | /* |
9d61b7ff SL |
874 | * Kick the driver every second |
875 | */ | |
20340301 | 876 | drtimo(dev) |
9d61b7ff | 877 | dev_t dev; |
20340301 | 878 | { |
9d61b7ff | 879 | register int unit = RSUNIT(dev); |
20340301 SL |
880 | register struct dr_aux *dr; |
881 | ||
9d61b7ff | 882 | dr = &dr_aux[unit]; |
20340301 | 883 | if (dr->dr_flags & DR_OPEN) |
9d61b7ff | 884 | timeout(drtimo, (caddr_t)dev, hz); |
20340301 SL |
885 | wakeup((caddr_t)dr); /* Wakeup any process waiting for interrupt */ |
886 | } | |
887 | ||
20340301 | 888 | #ifdef DR_DEBUG |
9d61b7ff SL |
889 | drva(dra, p, va, bcnt) |
890 | struct dr_aux *dra; | |
891 | struct proc *p; | |
892 | char *va; | |
893 | long bcnt; | |
894 | { | |
895 | register long first, last , np; | |
20340301 SL |
896 | |
897 | if (DR11 & 0x20) { | |
9d61b7ff SL |
898 | first = ((long)(vtoph(p, (unsigned)va))) >> 10; |
899 | last = ((long)(vtoph(p, (unsigned)va+bcnt))) >> 10; | |
20340301 SL |
900 | np = bcnt / 0x3ff; |
901 | printf("\ndrva: (op:%ld)(first:%ld)(last:%ld)(np:%ld)(cnt:%ld)", | |
902 | dra->dr_op,first,last,np,bcnt); | |
903 | } | |
904 | } | |
905 | #endif | |
906 | ||
9d61b7ff SL |
907 | drstart(rsaddr, dra, bp) |
908 | register struct rsdevice *rsaddr; | |
909 | register struct dr_aux *dra; | |
910 | register struct buf *bp; | |
911 | { | |
912 | register long addr; | |
913 | u_short go; | |
20340301 SL |
914 | |
915 | #ifdef DR_DEBUG | |
9d61b7ff SL |
916 | if (dra->dr_op == DR_READ && (DR11 & 8)) { |
917 | char *caddr = (char *)bp->b_un.b_addr; | |
20340301 | 918 | printf("\ndrstart: READ, bcnt:%ld",bp->b_bcount); |
20340301 SL |
919 | printf(",(%lx)(%lx)",caddr[0]&0xff,caddr[1]&0xff); |
920 | } | |
921 | #endif | |
9d61b7ff SL |
922 | /* we are doing raw IO, bp->b_un.b_addr is user's address */ |
923 | addr = (long)vtoph(bp->b_proc, (unsigned)bp->b_un.b_addr); | |
924 | /* | |
925 | * Set DMA address into DR11 interace registers: DR11 requires that | |
926 | * the address be right shifted 1 bit position before it is written | |
927 | * to the board (The board will left shift it one bit position before | |
928 | * it places the address on the bus | |
929 | */ | |
930 | rsaddr->dr_walo = (addr >> 1) & 0xffff; | |
931 | rsaddr->dr_wahi = (addr >> 17) & 0x7fff; | |
932 | /* Set DMA range count: (number of words - 1) */ | |
933 | rsaddr->dr_range = (bp->b_bcount >> 1) - 1; | |
934 | /* Set address modifier code to be used for DMA access to memory */ | |
935 | rsaddr->dr_addmod = DRADDMOD; | |
936 | /* | |
937 | * Now determine whether this is a read or a write. ***** This is | |
938 | * probably only usefull for link mode operation, since dr11 doesnot | |
939 | * controll the direction of data transfer. The C1 control input | |
940 | * controls whether the hardware is doing a read or a write. In link | |
941 | * mode this is controlled by function 1 latch (looped back by the | |
942 | * cable) and could be set the program. In the general case, the dr11 | |
943 | * doesnot know in advance what the direction of transfer is - although | |
944 | * the program and protocol logic probably is | |
945 | */ | |
20340301 | 946 | #ifdef DR_DEBUG |
9d61b7ff SL |
947 | if (DR11 & 1) |
948 | printf( | |
949 | "\ndrstrat: about to GO..,dr_cmd:%lx,drstat:%lx,drcnt:%ld,cdata:%lx,OP:%ld", | |
950 | dra->dr_cmd, rsaddr->dr_cstat, rsaddr->dr_range, | |
951 | rsaddr->dr_data, dra->dr_op); | |
20340301 | 952 | #endif |
9d61b7ff SL |
953 | /* |
954 | * Update function latches may have been done already by drioctl() if | |
955 | * request from drioctl() | |
956 | */ | |
957 | if (dra->dr_cmd & DR_DFCN) { /* deferred function write */ | |
958 | dra->dr_cmd &= ~DR_DFCN; /* Clear request */ | |
959 | go = dra->dr_cmd & DR_FMSK; /* mask out fcn bits */ | |
960 | rsaddr->dr_cstat = go; /* Write it to the board */ | |
961 | } | |
962 | /* Clear dmaf and attf to assure a clean dma start */ | |
963 | rsaddr->dr_pulse = RATN|RDMA|RPER; | |
964 | rsaddr->dr_cstat = IENB|GO|CYCL|dra->dr_op; /* GO...... */ | |
965 | /* | |
966 | * Now check for software cycle request -- usually | |
967 | * by transmitter in link mode. | |
968 | */ | |
969 | if (dra->dr_cmd & DR_PCYL) { | |
970 | dra->dr_cmd &= ~DR_PCYL; /* Clear request */ | |
971 | rsaddr->dr_pulse = CYCL; /* Use pulse register again */ | |
972 | } | |
973 | /* | |
974 | * Now check for deferred ACLO FCNT2 pulse request -- usually to tell | |
975 | * the transmitter (via its attention) that we have enabled dma. | |
976 | */ | |
977 | if (dra->dr_cmd & DR_DACL) { | |
978 | dra->dr_cmd &= ~DR_DACL; /* Clear request */ | |
979 | rsaddr->dr_pulse = FCN2; /* Use pulse register again */ | |
980 | } | |
20340301 | 981 | } |
20340301 | 982 | #endif NDR |