* Copyright (c) 1988 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* @(#)dr.c 7.9 (Berkeley) 12/16/90
* DRV11-W DMA interface driver.
#include "../include/mtpr.h"
#include "../include/pte.h"
#include "../vba/vbavar.h"
#include "../vba/drreg.h"
struct vba_device
*drinfo
[NDR
];
struct dr_aux dr_aux
[NDR
];
int drprobe(), drintr(), drattach(), drtimo(), drrwtimo();
extern struct vba_device
*drinfo
[];
static long drstd
[] = { 0 };
struct vba_driver drdriver
=
{ drprobe
, 0, drattach
, 0, drstd
, "rs", drinfo
};
#define RSUNIT(dev) (minor(dev) & 7)
/* -------- Per-unit data -------- */
extern struct dr_aux dr_aux
[];
register int br
, cvec
; /* must be r12, r11 */
br
= 0; cvec
= br
; br
= cvec
;
dr
= (struct rsdevice
*)reg
;
dr
->dr_intvect
= --vi
->ui_hd
->vh_lastiv
;
printf("dprobe: Set interrupt vector %lx and init\n",dr
->dr_intvec
);
/* generate interrupt here for autoconfig */
dr
->dr_cstat
= MCLR
; /* init board and device */
printf("drprobe: Initial status %lx\n", dr
->dr_cstat
);
br
= 0x18, cvec
= dr
->dr_intvect
; /* XXX */
return (sizeof (struct rsdevice
)); /* DR11 exist */
register struct dr_aux
*rsd
;
rsd
= &dr_aux
[ui
->ui_unit
];
rsd
->dr_flags
= DR_PRES
; /* This dr11 is present */
rsd
->dr_addr
= (struct rsdevice
*)ui
->ui_addr
; /* Save addr of this dr11 */
register int unit
= RSUNIT(dev
);
register struct rsdevice
*dr
;
register struct dr_aux
*rsd
;
if (drinfo
[unit
] == 0 || !drinfo
[unit
]->ui_alive
)
if (rsd
->dr_flags
& DR_OPEN
) {
printf("\ndropen: dr11 unit %ld already open",unit
);
return (ENXIO
); /* DR11 already open */
rsd
->dr_flags
|= DR_OPEN
; /* Mark it OPEN */
rsd
->dr_istat
= 0; /* Clear status of previous interrupt */
rsd
->rtimoticks
= hz
; /* Set read no stall timout to 1 sec */
rsd
->wtimoticks
= hz
*60; /* Set write no stall timout to 1 min */
dr
->dr_cstat
= DR_ZERO
; /* Clear function & latches */
dr
->dr_pulse
= (RDMA
| RATN
); /* clear leftover attn & e-o-r flags */
drtimo(dev
); /* start the self kicker */
register int unit
= RSUNIT(dev
);
register struct dr_aux
*dra
;
register struct rsdevice
*rs
;
if ((dra
->dr_flags
& DR_OPEN
) == 0) {
printf("\ndrclose: DR11 device %ld not open",unit
);
dra
->dr_flags
&= ~(DR_OPEN
|DR_ACTV
);
if (dra
->dr_buf
.b_flags
& B_BUSY
) {
dra
->dr_buf
.b_flags
&= ~B_BUSY
;
wakeup((caddr_t
)&dra
->dr_buf
.b_flags
);
/* drread() works exactly like drwrite() except that the
B_READ flag is used when physio() is called
{ register struct dr_aux
*dra
;
register int unit
= RSUNIT(dev
);
if (uio
->uio_iov
->iov_len
<= 0 || /* Negative count */
uio
->uio_iov
->iov_len
& 1 || /* odd count */
(int)uio
->uio_iov
->iov_base
& 1) /* odd destination address */
printf("\ndrread: (len:%ld)(base:%lx)",
uio
->uio_iov
->iov_len
,(int)uio
->uio_iov
->iov_base
);
dra
= &dr_aux
[RSUNIT(dev
)];
if (dra
->dr_flags
& DR_NORSTALL
) {
* We are in no stall mode, start the timer,
* raise IPL so nothing can stop us once the
timeout(drrwtimo
, (caddr_t
)((dra
->currenttimo
<<8) | unit
),
err
= physio(drstrategy
, bp
, dev
,B_READ
, drminphys
, uio
);
dra
->currenttimo
++; /* Update current timeout number */
if (dra
->dr_flags
& DR_TMDM
)
dra
->dr_flags
&= ~DR_TMDM
; /* Clear timeout flag */
return (physio(drstrategy
, bp
, dev
,B_READ
, drminphys
, uio
));
{ register struct dr_aux
*dra
;
register int unit
= RSUNIT(dev
);
if (uio
->uio_iov
->iov_len
<= 0 || uio
->uio_iov
->iov_len
& 1 ||
(int)uio
->uio_iov
->iov_base
& 1)
printf("\ndrwrite: (len:%ld)(base:%lx)",
uio
->uio_iov
->iov_len
,(int)uio
->uio_iov
->iov_base
);
dra
= &dr_aux
[RSUNIT(dev
)];
if (dra
->dr_flags
& DR_NOWSTALL
) {
* We are in no stall mode, start the timer,
* raise IPL so nothing can stop us once the
timeout(drrwtimo
,(caddr_t
)((dra
->currenttimo
<<8) | unit
),
err
= physio (drstrategy
, bp
, dev
,B_WRITE
, drminphys
, uio
);
dra
->currenttimo
++; /* Update current timeout number */
if (dra
->dr_flags
& DR_TMDM
)
dra
->dr_flags
&= ~DR_TMDM
; /* Clear timeout flag */
return (physio(drstrategy
, bp
, dev
,B_WRITE
, drminphys
, uio
));
* Routine used by calling program to issue commands to dr11 driver and
* through it to the device.
* It is also used to read status from the device and driver and to wait
* for attention interrupts.
* Status is returned in an 8 elements unsigned short integer array, the
* first two elements of the array are also used to pass arguments to
* The function bits to be written to the dr11 are included in the cmd
* argument. Even if they are not being written to the dr11 in a particular
* drioctl() call, they will update the copy of cmd that is stored in the
* driver. When drstrategy() is called, this updated copy is used if a
* deferred function bit write has been specified. The "side effect" of
* calls to the drioctl() requires that the last call prior to a read or
* write has an appropriate copy of the function bits in cmd if they are
* to be used in drstrategy().
* When used as command value, the contents of data[0] is the command
register int unit
= RSUNIT(dev
);
register struct dr_aux
*dra
;
register struct rsdevice
*rsaddr
= RSADDR(unit
);
printf("\ndrioctl: (dev:%lx)(cmd:%lx)(data:%lx)(data[0]:%lx)",
dra
->dr_cmd
= 0; /* Fresh copy; clear all previous flags */
case DRWAIT
: /* Wait for attention interrupt */
printf("\ndrioctl: wait for attention interrupt");
* If the attention flag in dr_flags is set, it probably
* means that an attention has arrived by the time a
* previous DMA end-of-range interrupt was serviced. If
* ATRX is set, we will return with out sleeping, since
* we have received an attention since the last call to
* wait on attention. This may not be appropriate for
if ((dra
->dr_flags
& DR_ATRX
) == 0) {
dra
->dr_flags
|= DR_ATWT
; /* Set waiting flag */
* Enable interrupt; use pulse reg.
* so function bits are not changed
error
= tsleep((caddr_t
)&dra
->dr_cmd
, DRPRI
| PCATCH
,
case DRPIOW
: /* Write to p-i/o register */
rsaddr
->dr_data
= data
[0];
case DRPACL
: /* Send pulse to device */
case DRDACL
: /* Defer alco pulse until go */
case DRPCYL
: /* Set cycle with next go */
case DRDFCN
: /* Update function with next go */
case DRRATN
: /* Reset attention flag */
case DRRDMA
: /* Reset DMA e-o-r flag */
case DRSFCN
: /* Set function bits */
temp
= data
[0] & DR_FMSK
;
* This has a very important side effect -- It clears
* the interrupt enable flag. That is fine for this driver,
* but if it is desired to leave interrupt enable at all
* times, it will be necessary to read the status register
* first to get IENB, or carry a software flag that indicates
* whether interrupts are set, and or this into the control
* register value being written.
case DRRPER
: /* Clear parity flag */
case DRSETRSTALL
: /* Set read stall mode. */
dra
->dr_flags
&= (~DR_NORSTALL
);
case DRSETNORSTALL
: /* Set no stall read mode. */
dra
->dr_flags
|= DR_NORSTALL
;
case DRGETRSTALL
: /* Returns true if in read stall mode */
data
[0] = (dra
->dr_flags
& DR_NORSTALL
)? 0 : 1;
case DRSETRTIMEOUT
: /* Set read stall timeout (1/10 secs) */
dra
->rtimoticks
= (data
[0] * hz
)/10;
case DRGETRTIMEOUT
: /* Return read stall timeout */
data
[0] = ((dra
->rtimoticks
)*10)/hz
;
case DRSETWSTALL
: /* Set write stall mode. */
dra
->dr_flags
&= (~DR_NOWSTALL
);
case DRSETNOWSTALL
: /* Set write stall mode. */
dra
->dr_flags
|= DR_NOWSTALL
;
case DRGETWSTALL
: /* Return true if in write stall mode */
data
[0] = (dra
->dr_flags
& DR_NOWSTALL
)? 0 : 1;
case DRSETWTIMEOUT
: /* Set write stall timeout (1/10's) */
dra
->wtimoticks
= (data
[0] * hz
)/10;
case DRGETWTIMEOUT
: /* Return write stall timeout */
data
[0] = ((dra
->wtimoticks
)*10)/hz
;
case DRWRITEREADY
: /* Return true if can write data */
data
[0] = (rsaddr
->dr_cstat
& STTA
)? 1 : 0;
case DRREADREADY
: /* Return true if data to be read */
data
[0] = (rsaddr
->dr_cstat
& STTB
)? 1 : 0;
case DRBUSY
: /* Return true if device busy */
* Internally this is the DR11-W
* STAT C bit, but there is a bug in the Omega 500/FIFO
* interface board that it cannot drive this signal low
* for certain DR11-W ctlr such as the Ikon. We use the
* REDY signal of the CSR on the Ikon DR11-W instead.
data
[0] = (rsaddr
->dr_cstat
& STTC
)? 1 : 0;
data
[0] = ((rsaddr
->dr_cstat
& REDY
)? 0 : 1);
case DRRESET
: /* Reset device */
/* Reset DMA ATN RPER flag */
rsaddr
->dr_pulse
= (MCLR
|RDMA
|RATN
|RPER
);
while ((rsaddr
->dr_cstat
& REDY
) == 0 && error
== 0)
error
= tsleep((caddr_t
)dra
, DRPRI
| PCATCH
, devio
, 0);
case DR11STAT
: { /* Copy back dr11 status to user */
register struct dr11io
*dr
= (struct dr11io
*)data
;
dr
->arg
[0] = dra
->dr_flags
;
dr
->arg
[1] = rsaddr
->dr_cstat
;
dr
->arg
[2] = dra
->dr_istat
; /* Status at last interrupt */
dr
->arg
[3] = rsaddr
->dr_data
; /* P-i/o input data */
status
= (u_short
)((rsaddr
->dr_addmod
<< 8) & 0xff00);
dr
->arg
[4] = status
| (u_short
)(rsaddr
->dr_intvect
& 0xff);
dr
->arg
[5] = rsaddr
->dr_range
;
dr
->arg
[6] = rsaddr
->dr_rahi
;
dr
->arg
[7] = rsaddr
->dr_ralo
;
case DR11LOOP
: /* Perform loopback test */
* NB: MUST HAVE LOOPBACK CABLE ATTACHED --
* Test results are printed on system console
if (error
= suser(u
.u_cred
, &u
.u_acflag
))
dr11loop(rsaddr
, dra
, unit
);
printf("**** (data[0]:%lx)",data
[0]);
u_short tstpat
[DMATBL
] = { 0xAAAA, 0x5555};
* Perform loopback test -- MUST HAVE LOOPBACK CABLE ATTACHED
* Test results are printed on system console
register long result
, ix
;
dr
->dr_cstat
= MCLR
; /* Clear board & device, disable intr */
printf("\n\t ----- DR11 unit %ld loopback test -----", unit
);
printf("\n\t Program I/O ...");
for (ix
=0;ix
<NPAT
;ix
++) {
dr
->dr_data
= tstpat
[ix
]; /* Write to Data out register */
result
= dr
->dr_data
& 0xFFFF; /* Read it back */
if (result
!= tstpat
[ix
]) {
printf("Failed, expected : %lx --- actual : %lx",
printf("OK\n\t Functions & Status Bits ...");
dr
->dr_cstat
= (FCN1
| FCN3
);
result
= dr
->dr_cstat
& 0xffff; /* Read them back */
if ((result
& (STTC
| STTA
)) != (STTC
|STTA
)) {
printf("Failed, expected : %lx --- actual : %lx, ISR:%lx",
(STTA
|STTC
), (result
& (STTA
|STTC
)), result
);
result
= dr
->dr_cstat
& 0xffff; /* Read them back */
if ((result
& STTB
) != STTB
) {
printf("Failed, expected : %lx --- actual : %lx, ISR:%lx",
STTB
, (result
& STTB
), result
);
printf("OK\n\t DMA output ...");
/* Initialize DMA data buffer */
for (ix
=0; ix
<DMATBL
; ix
++)
tstpat
[ix
] = 0xCCCC + ix
;
tstpat
[DMATBL
-1] = 0xCCCC; /* Last word output */
addr
= (long)vtoph((struct proc
*)0, (unsigned)tstpat
);
dr
->dr_walo
= (addr
>> 1) & 0xffff;
dr
->dr_wahi
= (addr
>> 17) & 0x7fff;
/* Set DMA range count: (number of words - 1) */
dr
->dr_range
= DMATBL
- 1;
/* Set address modifier code to be used for DMA access to memory */
dr
->dr_addmod
= DRADDMOD
;
* Clear dmaf and attf to assure a clean dma start, also disable
dr
->dr_pulse
= RDMA
|RATN
|RMSK
; /* Use pulse register */
dr
->dr_cstat
= GO
|CYCL
; /* GO...... */
/* Wait for DMA complete; REDY and DMAF are true in ISR */
while ((result
=(dr
->dr_cstat
& (REDY
|DMAF
))) != (REDY
|DMAF
)) {
printf("\n\tWait for DMA complete...ISR : %lx", result
);
printf("\n\t DMA output fails...timeout!!, ISR:%lx",
result
= dr
->dr_data
& 0xffff; /* Read last word output */
printf("\n\t Fails, expected : %lx --- actual : %lx",
printf("OK\n\t DMA input ...");
dr
->dr_data
= 0x1111; /* DMA input data */
addr
= (long)vtoph((struct proc
*)0, (unsigned)tstpat
);
dr
->dr_walo
= (addr
>> 1) & 0xffff;
dr
->dr_wahi
= (addr
>> 17) & 0x7fff;
dr
->dr_range
= DMATBL
- 1;
dr
->dr_addmod
= (char)DRADDMOD
;
dr
->dr_cstat
= FCN1
; /* Set FCN1 in ICR to DMA in*/
if ((dra
->dr_flags
& DR_LOOPTST
) == 0) {
dr
->dr_pulse
= RDMA
|RATN
|RMSK
|CYCL
|GO
;
/* Wait for DMA complete; REDY and DMAF are true in ISR */
while ((result
=(dr
->dr_cstat
& (REDY
|DMAF
))) != (REDY
|DMAF
)) {
printf("\n\tWait for DMA to complete...ISR:%lx",result
);
printf("\n\t DMA input timeout!!, ISR:%lx",
/* Enable DMA e-o-r interrupt */
dr
->dr_pulse
= IENB
|RDMA
|RATN
|CYCL
|GO
;
/* Wait for DMA complete; DR_LOOPTST is false in dra->dr_flags*/
while (dra
->dr_flags
& DR_LOOPTST
) {
result
= dr
->dr_cstat
& 0xffff;
printf("\n\tWait for DMA e-o-r intr...ISR:%lx", result
);
printf("\n\t DMA e-o-r timeout!!, ISR:%lx",
dra
->dr_flags
&= ~DR_LOOPTST
;
dra
->dr_flags
|= DR_LOOPTST
;
mtpr(P1DC
, tstpat
); /* Purge cache */
mtpr(P1DC
, 0x3ff+tstpat
);
for (ix
=0; ix
<DMATBL
; ix
++) {
if (tstpat
[ix
] != 0x1111) {
printf("\n\t Fails, ix:%d, expected:%x --- actual:%x",
if ((dra
->dr_flags
& DR_LOOPTST
) == 0) {
dra
->dr_flags
|= DR_LOOPTST
;
printf(" OK..\n\tDMA end of range interrupt...");
printf(" OK..\n\tAttention interrupt....");
dr
->dr_pulse
= IENB
|RDMA
;
/* Wait for ATTN interrupt; DR_LOOPTST is false in dra->dr_flags*/
while (dra
->dr_flags
& DR_LOOPTST
) {
result
= dr
->dr_cstat
& 0xffff;
printf("\n\tWait for Attention intr...ISR:%lx",result
);
printf("\n\t Attention interrupt timeout!!, ISR:%lx",
dra
->dr_flags
&= ~DR_LOOPTST
;
dra
->dr_flags
&= ~DR_LOOPTST
;
printf(" OK..\n\tDone...");
/* Reset state on Unibus reset */
* An interrupt is caused either by an error,
* base address overflow, or transfer complete
register struct dr_aux
*dra
= &dr_aux
[dr11
];
register struct rsdevice
*rsaddr
= RSADDR(dr11
);
status
= rsaddr
->dr_cstat
& 0xffff; /* get board status register */
printf("\ndrintr: dr11 status : %lx",status
& 0xffff);
if (dra
->dr_flags
& DR_LOOPTST
) { /* doing loopback test */
dra
->dr_flags
&= ~DR_LOOPTST
;
* Make sure this is not a stray interrupt; at least one of dmaf or attf
* must be set. Note that if the dr11 interrupt enable latch is reset
* during a hardware interrupt ack sequence, and by the we get to this
* point in the interrupt code it will be 0. This is done to give the
* programmer some control over how the two more-or-less independent
* interrupt sources on the board are handled.
* If the attention flag is set when drstrategy() is called to start a
* dma read or write an interrupt will be generated as soon as the
* strategy routine enables interrupts for dma end-of-range. This will
* cause execution of the interrupt routine (not necessarily bad) and
* will cause the interrupt enable mask to be reset (very bad since the
* dma end-of-range condition will not be able to generate an interrupt
* when it occurs) causing the dma operation to time-out (even though
* the dma transfer will be done successfully) or hang the process if a
* software time-out capability is not implemented. One way to avoid
* this situation is to check for a pending attention interrupt (attf
* set) by calling drioctl() before doing a read or a write. For the
* time being this driver will solve the problem by clearing the attf
* flag in the status register before enabling interrupts in
* **** The IKON 10084 for which this driver is written will set both
* attf and dmaf if dma is terminated by an attention pulse. This will
* cause a wakeup(&dr_aux), which will be ignored since it is not being
* waited on, and an iodone(bp) which is the desired action. Some other
* dr11 emulators, in particular the IKON 10077 for the Multibus, donot
* dmaf in this case. This may require some addtional code in the inter-
* rupt routine to ensure that en iodone(bp) is issued when dma is term-
if ((status
& (ATTF
| DMAF
)) == 0) {
printf("dr%d: stray interrupt, status=%x", dr11
, status
);
if (status
& DMAF
) { /* End-of-range interrupt */
dra
->dr_flags
|= DR_DMAX
;
printf("\ndrintr: e-o-r interrupt,cstat:%lx,dr_flags:%lx",
status
&0xffff, dra
->dr_flags
& DR_ACTV
);
if ((dra
->dr_flags
& DR_ACTV
) == 0) {
/* We are not doing DMA !! */
if (dra
->dr_op
== DR_READ
)
mtpr(P1DC
, bp
->b_un
.b_addr
);
dra
->dr_bycnt
-= bp
->b_bcount
;
bp
->b_un
.b_addr
+= bp
->b_bcount
;
bp
->b_bcount
= (dra
->dr_bycnt
> NBPG
) ? NBPG
:
drstart(rsaddr
, dra
, bp
);
dra
->dr_flags
&= ~DR_ACTV
;
wakeup((caddr_t
)dra
); /* Wakeup waiting in drwait() */
rsaddr
->dr_pulse
= (RPER
|RDMA
|RATN
); /* reset dma e-o-r flag */
* Now test for attention interrupt -- It may be set in addition to
* the dma e-o-r interrupt. If we get one we will issue a wakeup to
* the drioctl() routine which is presumable waiting for one.
* The program may have to monitor the attention interrupt received
* flag in addition to doing waits for the interrupt. Futhermore,
* interrupts are not enabled unless dma is in progress or drioctl()
* has been called to wait for attention -- this may produce some
* strange results if attf is set on the dr11 when a read or a write
* is initiated, since that will enables interrupts.
* **** The appropriate code for this interrupt routine will probably
* be rather application dependent.
dra
->dr_flags
|= DR_ATRX
;
dra
->dr_flags
&= ~DR_ATWT
;
rsaddr
->dr_cstat
= RATN
; /* reset attention flag */
* Some applications which use attention to terminate
* dma may also want to issue an iodone() here to
wakeup((caddr_t
)&dra
->dr_cmd
);
if (bp
->b_bcount
> 65536)
* This routine performs the device unique operations on the DR11W
* it is passed as an argument to and invoked by physio
int unit
= RSUNIT(bp
->b_dev
);
register struct rsdevice
*rsaddr
= RSADDR(unit
);
register struct dr_aux
*dra
= &dr_aux
[unit
];
if ((dra
->dr_flags
& DR_OPEN
) == 0) { /* Device not open */
while (dra
->dr_flags
& DR_ACTV
)
/* Device is active; should never be in here... */
(void) tsleep((caddr_t
)&dra
->dr_flags
, DRPRI
, devio
, 0);
drva(dra
, bp
->b_proc
, bp
->b_un
.b_addr
, bp
->b_bcount
);
dra
->dr_oba
= bp
->b_un
.b_addr
; /* Save original addr, count */
dra
->dr_obc
= bp
->b_bcount
;
dra
->dr_bycnt
= bp
->b_bcount
; /* Save xfer count used by drintr() */
if ((((long)bp
->b_un
.b_addr
& 0x3fffffff) >> PGSHIFT
) !=
((((long)bp
->b_un
.b_addr
& 0x3fffffff) + bp
->b_bcount
) >> PGSHIFT
))
bp
->b_bcount
= NBPG
- (((long)bp
->b_un
.b_addr
) & PGOFSET
);
dra
->dr_flags
|= DR_ACTV
; /* Mark active (use in intr handler) */
caddr
= (char *)dra
->dr_oba
;
if (dra
->dr_op
== DR_READ
)
printf("\nAfter read: (%lx)(%lx)",
caddr
[0]&0xff, caddr
[1]&0xff);
dra
->dr_flags
&= ~DR_ACTV
; /* Clear active flag */
bp
->b_un
.b_addr
= dra
->dr_oba
; /* Restore original addr, count */
bp
->b_bcount
= dra
->dr_obc
;
/* Mark buffer B_DONE,so physstrat() in ml/machdep.c won't sleep */
wakeup((caddr_t
)&dra
->dr_flags
);
* Return to the calling program (physio()). Physio() will sleep
* until awaken by a call to iodone() in the interupt handler --
* which will be called by the dispatcher when it receives dma
* end-of-range interrupt.
register struct rsdevice
*rs
;
register struct dr_aux
*dr
;
while (dr
->dr_flags
& DR_ACTV
)
(void) tsleep((caddr_t
)dr
, DRPRI
, devio
, 0);
if (dr
->dr_flags
& DR_TMDM
) { /* DMA timed out */
dr
->dr_flags
&= ~DR_TMDM
;
if (rs
->dr_cstat
& (PERR
|BERR
|TERR
)) {
dr
->dr_actf
->b_flags
|= B_ERROR
;
dr
->dr_flags
&= ~DR_DMAX
;
* The lower 8-bit of tinfo is the minor device number, the
* remaining higher 8-bit is the current timout number
register long unit
= tinfo
& 0xff;
register struct dr_aux
*dr
= &dr_aux
[unit
];
register struct rsdevice
*rs
= dr
->dr_addr
;
* If this is not the timeout that drwrite/drread is waiting
* for then we should just go away
if ((tinfo
&~ 0xff) != (dr
->currenttimo
<< 8))
/* Mark the device timed out */
dr
->dr_flags
&= ~DR_ACTV
;
rs
->dr_pulse
= RMSK
; /* Inihibit interrupt */
rs
->dr_pulse
= (RPER
|RDMA
|RATN
|IENB
); /* Clear DMA logic */
* Some applications will not issue a master after dma timeout,
* since doing so sends an INIT H pulse to the external device,
* which may produce undesirable side-effects.
/* Wake up process waiting in drwait() and flag the error */
dr
->dr_actf
->b_flags
|= B_ERROR
;
wakeup((caddr_t
)dr
->dr_cmd
);
* Kick the driver every second
register int unit
= RSUNIT(dev
);
register struct dr_aux
*dr
;
if (dr
->dr_flags
& DR_OPEN
)
timeout(drtimo
, (caddr_t
)dev
, hz
);
wakeup((caddr_t
)dr
); /* Wakeup any process waiting for interrupt */
register long first
, last
, np
;
first
= ((long)(vtoph(p
, (unsigned)va
))) >> 10;
last
= ((long)(vtoph(p
, (unsigned)va
+bcnt
))) >> 10;
printf("\ndrva: (op:%ld)(first:%ld)(last:%ld)(np:%ld)(cnt:%ld)",
dra
->dr_op
,first
,last
,np
,bcnt
);
register struct rsdevice
*rsaddr
;
register struct dr_aux
*dra
;
if (dra
->dr_op
== DR_READ
&& (DR11
& 8)) {
char *caddr
= (char *)bp
->b_un
.b_addr
;
printf("\ndrstart: READ, bcnt:%ld",bp
->b_bcount
);
printf(",(%lx)(%lx)",caddr
[0]&0xff,caddr
[1]&0xff);
/* we are doing raw IO, bp->b_un.b_addr is user's address */
addr
= (long)vtoph(bp
->b_proc
, (unsigned)bp
->b_un
.b_addr
);
* Set DMA address into DR11 interace registers: DR11 requires that
* the address be right shifted 1 bit position before it is written
* to the board (The board will left shift it one bit position before
* it places the address on the bus
rsaddr
->dr_walo
= (addr
>> 1) & 0xffff;
rsaddr
->dr_wahi
= (addr
>> 17) & 0x7fff;
/* Set DMA range count: (number of words - 1) */
rsaddr
->dr_range
= (bp
->b_bcount
>> 1) - 1;
/* Set address modifier code to be used for DMA access to memory */
rsaddr
->dr_addmod
= DRADDMOD
;
* Now determine whether this is a read or a write. ***** This is
* probably only usefull for link mode operation, since dr11 doesnot
* controll the direction of data transfer. The C1 control input
* controls whether the hardware is doing a read or a write. In link
* mode this is controlled by function 1 latch (looped back by the
* cable) and could be set the program. In the general case, the dr11
* doesnot know in advance what the direction of transfer is - although
* the program and protocol logic probably is
"\ndrstrat: about to GO..,dr_cmd:%lx,drstat:%lx,drcnt:%ld,cdata:%lx,OP:%ld",
dra
->dr_cmd
, rsaddr
->dr_cstat
, rsaddr
->dr_range
,
rsaddr
->dr_data
, dra
->dr_op
);
* Update function latches may have been done already by drioctl() if
if (dra
->dr_cmd
& DR_DFCN
) { /* deferred function write */
dra
->dr_cmd
&= ~DR_DFCN
; /* Clear request */
go
= dra
->dr_cmd
& DR_FMSK
; /* mask out fcn bits */
rsaddr
->dr_cstat
= go
; /* Write it to the board */
/* Clear dmaf and attf to assure a clean dma start */
rsaddr
->dr_pulse
= RATN
|RDMA
|RPER
;
rsaddr
->dr_cstat
= IENB
|GO
|CYCL
|dra
->dr_op
; /* GO...... */
* Now check for software cycle request -- usually
* by transmitter in link mode.
if (dra
->dr_cmd
& DR_PCYL
) {
dra
->dr_cmd
&= ~DR_PCYL
; /* Clear request */
rsaddr
->dr_pulse
= CYCL
; /* Use pulse register again */
* Now check for deferred ACLO FCNT2 pulse request -- usually to tell
* the transmitter (via its attention) that we have enabled dma.
if (dra
->dr_cmd
& DR_DACL
) {
dra
->dr_cmd
&= ~DR_DACL
; /* Clear request */
rsaddr
->dr_pulse
= FCN2
; /* Use pulse register again */