* load as much as possible into silo
* get correct numbers for receive silo parameter timeout
* test with more than one unit
* optimize for efficient DMA and dynamically
* decide between silo and DMA mode
* Definition of the driver for the auto-configuration program.
int dmfprobe(), dmfattach(), dmfrint(), dmfxint();
struct uba_device
*dmfinfo
[NDMF
];
u_short dmfstd
[] = { 0 };
struct uba_driver dmfdriver
=
{ dmfprobe
, 0, dmfattach
, 0, dmfstd
, "dmf", dmfinfo
};
* In this driver, "dmf" (unqualified) refers to the async portion
* of the dmf32, "dmfc" to the combo portion, "dmfs" to the sync
* portion, "dmfl" to the lp portion, and "dmfd" to the dr portion.
short dmfccsr0
; /* combo csr 0 */
short dmfccsr1
; /* combo csr 1 */
short dmfcsr
; /* control-status register */
short dmflpr
; /* line parameter register */
short dmfrbuf
; /* receiver buffer (ro) */
u_short dmfirw
; /* indirect register word */
u_char dmfirc
[2]; /* " " bytes */
#define dmfrsp dmfrbuf /* receive silo parameter register (wo) */
#define dmftbuf dmfun.dmfirc[0] /* transmit buffer */
#define dmftsc dmfun.dmfirc[0] /* transmit silo count */
#define dmfrms dmfun.dmfirc[1] /* receive modem status */
#define dmflcr dmfun.dmfirc[0] /* line control register */
#define dmftms dmfun.dmfirc[1] /* transmit modem status */
#define dmftba dmfun.dmfirw /* transmit buffer address */
#define dmftcc dmfun.dmfirw /* transmit character count */
#define DMF_TI 0100000 /* transmit interrupt */
#define DMF_TIE 0040000 /* transmit interrupt enable */
#define DMF_NXM 0020000 /* non-existant memory */
#define DMF_LIN 0003400 /* transmit line number */
#define DMF_RI 0000200 /* receiver interrupt */
#define DMF_RIE 0000100 /* receiver interrupt enable */
#define DMF_CLR 0000040 /* master reset */
#define DMF_IAD 0000037 /* indirect address register */
#define DMFIR_TBUF 000 /* select tbuf indirect register */
#define DMFIR_LCR 010 /* select lcr indirect register */
#define DMFIR_TBA 020 /* select tba indirect register */
#define DMFIR_TCC 030 /* select tcc indirect register */
/* DEC manuals incorrectly say this bit causes generation of even parity. */
#define DMF_IE (DMF_TIE|DMF_RIE)
#define DMF_SILOCNT 32 /* size of DMF output silo (per line) */
#define DMF_DSC 0004000 /* data set change */
#define DMF_PE 0010000 /* parity error */
#define DMF_FE 0020000 /* framing error */
#define DMF_DO 0040000 /* data overrun */
#define DMF_USRR 0004 /* user modem signal (pin 25) */
#define DMF_SR 0010 /* secondary receive */
#define DMF_CTS 0020 /* clear to send */
#define DMF_CAR 0040 /* carrier detect */
#define DMF_RNG 0100 /* ring */
#define DMF_DSR 0200 /* data set ready */
#define DMF_USRW 0001 /* user modem signal (pin 18) */
#define DMF_DTR 0002 /* data terminal ready */
#define DMF_RATE 0004 /* data signal rate select */
#define DMF_ST 0010 /* secondary transmit */
#define DMF_RTS 0020 /* request to send */
#define DMF_BRK 0040 /* pseudo break bit */
#define DMF_PREEMPT 0200 /* preempt output */
/* flags for modem control */
#define DMF_ON (DMF_DTR|DMF_RTS)
#define DMF_MIE 0040 /* modem interrupt enable */
#define DMF_FLUSH 0020 /* flush transmit silo */
#define DMF_RBRK 0010 /* real break bit */
#define DMF_RE 0004 /* receive enable */
#define DMF_AUTOX 0002 /* auto XON/XOFF */
#define DMF_TE 0001 /* transmit enable */
#define DMFLCR_ENA (DMF_MIE|DMF_RE|DMF_TE)
/* bits in dm lsr, copied from dh.c */
#define DML_USR 0001000 /* usr modem sig, not a real DM bit */
#define DML_DSR 0000400 /* data set ready, not a real DM bit */
#define DML_RNG 0000200 /* ring */
#define DML_CAR 0000100 /* carrier detect */
#define DML_CTS 0000040 /* clear to send */
#define DML_SR 0000020 /* secondary receive */
#define DML_ST 0000010 /* secondary transmit */
#define DML_RTS 0000004 /* request to send */
#define DML_DTR 0000002 /* data terminal ready */
#define DML_LE 0000001 /* line enable */
* Local variables for the driver
{ 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 };
struct tty dmf_tty
[NDMF
*8];
int dmfact
; /* mask of active dmf's */
int dmfstart(), ttrstrt();
* The clist space is mapped by the driver onto each UNIBUS.
* The UBACVT macro converts a clist space address for unibus uban
* into an i/o space address for the DMA routine.
int dmf_ubinfo
[MAXNUBA
]; /* info about allocated unibus map */
static int cbase
[MAXNUBA
]; /* base address in unibus map */
#define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree))
* Routine for configuration to set dmf interrupt.
register int br
, cvec
; /* these are ``value-result'' */
register struct dmfdevice
*dmfaddr
= (struct dmfdevice
*)reg
;
br
= 0; cvec
= br
; br
= cvec
;
cvec
= (uba_hd
[numuba
].uh_lastiv
-= 4*8);
dmfaddr
->dmfccsr0
= cvec
>> 2;
/* NEED TO SAVE IT SOMEWHERE FOR OTHER DEVICES */
* Routine called to attach a dmf.
dmfsoftCAR
[ui
->ui_unit
] = ui
->ui_flags
;
* Open a DMF32 line, mapping the clist onto the uba if this
* is the first dmf on this uba. Turn on this dmf if this is
register struct dmfdevice
*addr
;
register struct uba_device
*ui
;
if (unit
>= NDMF
*8 || (ui
= dmfinfo
[dmf
])== 0 || ui
->ui_alive
== 0) {
if (tp
->t_state
&XCLUDE
&& u
.u_uid
!=0) {
addr
= (struct dmfdevice
*)ui
->ui_addr
;
tp
->t_addr
= (caddr_t
)addr
;
* While setting up state for this uba and this dmf,
* block uba resets which can clear the state.
if (dmf_ubinfo
[ui
->ui_ubanum
] == 0) {
dmf_ubinfo
[ui
->ui_ubanum
] =
uballoc(ui
->ui_ubanum
, (caddr_t
)cfree
,
nclist
*sizeof(struct cblock
), 0);
cbase
[ui
->ui_ubanum
] = dmf_ubinfo
[ui
->ui_ubanum
]&0x3ffff;
if ((dmfact
&(1<<dmf
)) == 0) {
addr
->dmfrsp
= 1; /* DON'T KNOW WHAT TO SET IT TO YET */
* If this is first open, initialze tty state to default.
if ((tp
->t_state
&ISOPEN
) == 0) {
tp
->t_flags
= ODDP
|EVENP
|ECHO
;
* Wait for carrier, then process line discipline specific open.
if ((dmfmctl(dev
, DMF_ON
, DMSET
) & (DMF_CAR
<<8)) ||
(dmfsoftCAR
[dmf
] & (1<<(unit
&07))))
while ((tp
->t_state
& CARR_ON
) == 0) {
sleep((caddr_t
)&tp
->t_rawq
, TTIPRI
);
(*linesw
[tp
->t_line
].l_open
)(dev
, tp
);
(*linesw
[tp
->t_line
].l_close
)(tp
);
dmfmctl(unit
, DMF_BRK
, DMBIC
);
if (tp
->t_state
&HUPCLS
|| (tp
->t_state
&ISOPEN
)==0)
dmfmctl(unit
, DMF_OFF
, DMSET
);
tp
= &dmf_tty
[minor(dev
)];
(*linesw
[tp
->t_line
].l_read
)(tp
);
tp
= &dmf_tty
[minor(dev
)];
(*linesw
[tp
->t_line
].l_write
)(tp
);
* DMF32 receiver interrupt.
register struct dmfdevice
*addr
;
register struct tty
*tp0
;
register struct uba_device
*ui
;
if (ui
== 0 || ui
->ui_alive
== 0)
addr
= (struct dmfdevice
*)ui
->ui_addr
;
* Loop fetching characters from the silo for this
* dmf until there are no more in the silo.
while ((c
= addr
->dmfrbuf
) < 0) {
addr
->dmfcsr
= DMF_IE
| DMFIR_TBUF
| ((c
>>8)&07);
if (addr
->dmfrms
& DMF_CAR
) {
if ((tp
->t_state
& CARR_ON
) == 0) {
wakeup((caddr_t
)&tp
->t_rawq
);
if (tp
->t_state
& CARR_ON
) {
gsignal(tp
->t_pgrp
, SIGHUP
);
gsignal(tp
->t_pgrp
, SIGCONT
);
addr
->dmfcsr
= DMF_IE
| DMFIR_LCR
|
flushtty(tp
, FREAD
|FWRITE
);
if ((tp
->t_state
&ISOPEN
)==0) {
if ((tp
->t_flags
&(EVENP
|ODDP
))==EVENP
|| (tp
->t_flags
&(EVENP
|ODDP
))==ODDP
)
if ((c
& DMF_DO
) && overrun
== 0) {
printf("dmf%d: silo overflow\n", dmf
);
* At framing error (break) generate
* a null (in raw mode, for getty), or a
* interrupt (in cooked/cbreak mode).
if (tp
->t_line
== NETLDISC
) {
(*linesw
[tp
->t_line
].l_rint
)(c
, tp
);
dmfioctl(dev
, cmd
, addr
, flag
)
register int unit
= minor(dev
);
register int dmf
= unit
>> 3;
register struct device
*dmfaddr
;
cmd
= (*linesw
[tp
->t_line
].l_ioctl
)(tp
, cmd
, addr
);
if (ttioctl(tp
, cmd
, addr
, flag
)) {
if (cmd
==TIOCSETP
|| cmd
==TIOCSETN
)
dmfmctl(dev
, DMF_BRK
, DMBIS
);
dmfmctl(dev
, DMF_BRK
, DMBIC
);
dmfmctl(dev
, DMF_DTR
|DMF_RTS
, DMBIS
);
dmfmctl(dev
, DMF_DTR
|DMF_RTS
, DMBIC
);
if (copyin(addr
, (caddr_t
) &temp
, sizeof(temp
)))
dmfmctl(dev
, dmtodmf(temp
), DMSET
);
if (copyin(addr
, (caddr_t
) &temp
, sizeof(temp
)))
dmfmctl(dev
, dmtodmf(temp
), DMBIS
);
if (copyin(addr
, (caddr_t
) &temp
, sizeof(temp
)))
dmfmctl(dev
, dmtodmf(temp
), DMBIC
);
temp
= dmftodm(dmfmctl(dev
, 0, DMGET
));
if (copyout((caddr_t
) &temp
, addr
, sizeof(temp
)))
if (bits
& DML_ST
) b
|= DMF_RATE
;
if (bits
& DML_RTS
) b
|= DMF_RTS
;
if (bits
& DML_USR
) b
|= DMF_USRW
;
b
= (bits
& 012) | ((bits
>> 7) & 0760) | DML_LE
;
if (bits
& DMF_USRR
) b
|= DML_USR
;
if (bits
& DMF_RTS
) b
|= DML_RTS
;
* Set parameters from open or stty into the DMF hardware
register struct dmfdevice
*addr
;
addr
= (struct dmfdevice
*)tp
->t_addr
;
* Block interrupts so parameters will be set
* before the line interrupts.
addr
->dmfcsr
= (unit
&07) | DMFIR_LCR
| DMF_IE
;
dmfmctl(unit
, DMF_OFF
, DMSET
);
lpar
= (dmf_speeds
[tp
->t_ospeed
]<<12) | (dmf_speeds
[tp
->t_ispeed
]<<8);
if ((tp
->t_ispeed
) == B134
)
else if ((tp
->t_flags
&RAW
) || (tp
->t_local
&LLITOUT
))
/* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */
if ((tp
->t_flags
&EVENP
) == 0)
if ((tp
->t_ospeed
) == B110
)
* DMF32 transmitter interrupt.
register struct dmfdevice
*addr
;
register struct uba_device
*ui
;
addr
= (struct dmfdevice
*)ui
->ui_addr
;
while ((t
= addr
->dmfcsr
) & DMF_TI
) {
unit
= dmf
*8 + ((t
>>8)&07);
printf("dmf%d: NXM line %d\n", dmf
, unit
&7);
/* SHOULD RESTART OR SOMETHING... */
addr
->dmfcsr
= DMFIR_TBUF
| DMF_IE
| (unit
&07);
* Do arithmetic in a short to make up
addr
->dmfcsr
= DMFIR_TBA
| DMF_IE
| (unit
&07);
UBACVT(tp
->t_outq
.c_cf
, ui
->ui_ubanum
);
ndflush(&tp
->t_outq
, (int)cntr
);
(*linesw
[tp
->t_line
].l_start
)(tp
);
* Start (restart) transmission on the given DMF32 line.
register struct dmfdevice
*addr
;
register int car
, dmf
, unit
, nch
;
addr
= (struct dmfdevice
*)tp
->t_addr
;
* Must hold interrupts in following code to prevent
* state of the tp from changing.
* If it's currently active, or delaying, no need to do anything.
if (tp
->t_state
&(TIMEOUT
|BUSY
|TTSTOP
))
* If there are still characters in the silo,
* just reenable the transmitter.
addr
->dmfcsr
= DMF_IE
| DMFIR_TBUF
| unit
;
addr
->dmfcsr
= DMF_IE
| DMFIR_LCR
| unit
;
* If there are sleepers, and output has drained below low
* water mark, wake up the sleepers.
if ((tp
->t_state
&ASLEEP
) && tp
->t_outq
.c_cc
<=TTLOWAT(tp
)) {
mcstart(tp
->t_chan
, (caddr_t
)&tp
->t_outq
);
wakeup((caddr_t
)&tp
->t_outq
);
* Now restart transmission unless the output queue is
if (tp
->t_outq
.c_cc
== 0)
if (tp
->t_flags
&RAW
|| tp
->t_local
&LLITOUT
)
nch
= ndqb(&tp
->t_outq
, 0);
nch
= ndqb(&tp
->t_outq
, 0200);
* If first thing on queue is a delay process it.
timeout(ttrstrt
, (caddr_t
)tp
, (nch
&0x7f)+6);
* If characters to transmit, restart transmission.
addr
->dmfcsr
= DMF_IE
| DMFIR_LCR
| unit
;
car
= UBACVT(tp
->t_outq
.c_cf
, dmfinfo
[dmf
]->ui_ubanum
);
addr
->dmfcsr
= DMF_IE
| DMFIR_TBA
| unit
;
addr
->dmftcc
= ((car
>>2)&0xc000) | nch
;
register char *cp
= tp
->t_outq
.c_cf
;
nch
= MIN(nch
, DMF_SILOCNT
);
addr
->dmfcsr
= DMF_IE
| DMFIR_LCR
| unit
;
addr
->dmfcsr
= DMF_IE
| DMFIR_TBUF
| unit
;
for (i
= 0; i
< nch
; i
++)
ndflush(&tp
->t_outq
, nch
);
* Stop output on a line, e.g. for ^S/^Q or output flush.
register struct dmfdevice
*addr
;
addr
= (struct dmfdevice
*)tp
->t_addr
;
* Block input/output interrupts while messing with state.
if (tp
->t_state
& BUSY
) {
* Device is transmitting; stop output
* by selecting the line and disabling
* the transmitter. If this is a flush
* request then flush the output silo,
* otherwise we will pick up where we
* left off by enabling the transmitter.
addr
->dmfcsr
= DMFIR_LCR
| (unit
&07) | DMF_IE
;
if ((tp
->t_state
&TTSTOP
)==0) {
addr
->dmflcr
|= DMF_FLUSH
;
register struct dmfdevice
*dmfaddr
;
register int unit
, mbits
, lcr
;
dmfaddr
= (struct dmfdevice
*)(dmf_tty
[unit
].t_addr
);
dmfaddr
->dmfcsr
= DMF_IE
| DMFIR_TBUF
| unit
;
mbits
= dmfaddr
->dmfrms
<< 8;
dmfaddr
->dmfcsr
= DMF_IE
| DMFIR_LCR
| unit
;
mbits
|= dmfaddr
->dmftms
;
dmfaddr
->dmftms
= mbits
&037;
* Reset state of driver if UBA reset was necessary.
* Reset the csr, lpr, and lcr registers on open lines, and
register struct uba_device
*ui
;
register struct dmfdevice
*addr
;
if (dmf_ubinfo
[uban
] == 0)
ubarelse(uban
, &dmf_ubinfo
[uban
]);
dmf_ubinfo
[uban
] = uballoc(uban
, (caddr_t
)cfree
,
nclist
*sizeof (struct cblock
), 0);
cbase
[uban
] = dmf_ubinfo
[uban
]&0x3ffff;
for (dmf
= 0; dmf
< NDMF
; dmf
++) {
if (ui
== 0 || ui
->ui_alive
== 0 || ui
->ui_ubanum
!= uban
)
addr
= (struct dmfdevice
*)ui
->ui_addr
;
for (i
= 0; i
< 8; i
++) {
if (tp
->t_state
& (ISOPEN
|WOPEN
)) {
dmfmctl(unit
, DMF_ON
, DMSET
);
/* stubs for interrupt routines for devices not yet supported */
dmfsrint() { printf("dmfsrint\n"); }
dmfsxint() { printf("dmfsxint\n"); }
dmfdaint() { printf("dmfdaint\n"); }
dmfdbint() { printf("dmfdbint\n"); }
dmflint() { printf("dmflint\n"); }