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