#include "../vaxuba/ubareg.h"
#include "../vaxuba/ubavar.h"
* Definition of the driver for the auto-configuration program.
* There is one definition for the dh and one for the dm.
int dhprobe(), dhattach(), dhrint(), dhxint();
struct uba_device
*dhinfo
[NDH
];
struct uba_driver dhdriver
=
{ dhprobe
, 0, dhattach
, 0, dhstd
, "dh", dhinfo
};
int dmprobe(), dmattach(), dmintr();
struct uba_device
*dminfo
[NDH
];
struct uba_driver dmdriver
=
{ dmprobe
, 0, dmattach
, 0, dmstd
, "dm", dminfo
};
short dhcsr
; /* control-status register */
char dhcsrl
; /* low byte for line select */
short dhrcr
; /* receive character register */
short dhlpr
; /* line parameter register */
u_short dhcar
; /* current address register */
short dhbcr
; /* byte count register */
u_short dhbar
; /* buffer active register */
short dhbreak
; /* break control register */
short dhsilo
; /* silo status register */
#define IFLAGS (EVENP|ODDP|ECHO)
#define IFLAGS (EVENP|ODDP)
#define DH_TI 0100000 /* transmit interrupt */
#define DH_SI 0040000 /* storage interrupt */
#define DH_TIE 0020000 /* transmit interrupt enable */
#define DH_SIE 0010000 /* storage interrupt enable */
#define DH_MC 0004000 /* master clear */
#define DH_NXM 0002000 /* non-existant memory */
#define DH_MM 0001000 /* maintenance mode */
#define DH_CNI 0000400 /* clear non-existant memory interrupt */
#define DH_RI 0000200 /* receiver interrupt */
#define DH_RIE 0000100 /* receiver interrupt enable */
/* DEC manuals incorrectly say this bit causes generation of even parity. */
#define DH_IE (DH_TIE|DH_SIE|DH_RIE)
#define DH_PE 0010000 /* parity error */
#define DH_FE 0020000 /* framing error */
#define DH_DO 0040000 /* data overrun */
short dmcsr
; /* control status register */
short dmlstat
; /* line status register */
#define DM_RF 0100000 /* ring flag */
#define DM_CF 0040000 /* carrier flag */
#define DM_CTS 0020000 /* clear to send */
#define DM_SRF 0010000 /* secondary receive flag */
#define DM_CS 0004000 /* clear scan */
#define DM_CM 0002000 /* clear multiplexor */
#define DM_MM 0001000 /* maintenance mode */
#define DM_STP 0000400 /* step */
#define DM_DONE 0000200 /* scanner is done */
#define DM_IE 0000100 /* interrupt enable */
#define DM_SE 0000040 /* scan enable */
#define DM_BUSY 0000020 /* scan busy */
#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 */
#define DML_ON (DML_DTR|DML_RTS|DML_LE)
* Local variables for the driver
short dhsar
[NDH
]; /* software copy of last bar */
int dhact
; /* mask of active dh's */
int dhstart(), 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 dh_ubinfo
[MAXNUBA
]; /* info about allocated unibus map */
int cbase
[MAXNUBA
]; /* base address in unibus map */
#define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree))
* Routine for configuration to force a dh to interrupt.
* Set to transmit at 9600 baud, and cause a transmitter interrupt.
register int br
, cvec
; /* these are ``value-result'' */
register struct dhdevice
*dhaddr
= (struct dhdevice
*)reg
;
br
= 0; cvec
= br
; br
= cvec
;
if (ndh11
== 0) ndh11
= 1;
dhaddr
->un
.dhcsr
= DH_RIE
|DH_MM
|DH_RI
;
dhaddr
->un
.dhcsr
&= ~DH_RI
;
dhaddr
->un
.dhcsr
= DH_TIE
;
dhaddr
->dhlpr
= (B9600
<< 10) | (B9600
<< 6) | BITS7
|PENABLE
;
DELAY(100000); /* wait 1/10'th of a sec for interrupt */
if (cvec
&& cvec
!= 0x200)
cvec
-= 4; /* transmit -> receive */
return (sizeof (struct dhdevice
));
* Routine called to attach a dh.
dhsoftCAR
[ui
->ui_unit
] = ui
->ui_flags
;
* Configuration routine to cause a dm to interrupt.
register int br
, vec
; /* value-result */
register struct dmdevice
*dmaddr
= (struct dmdevice
*)reg
;
br
= 0; vec
= br
; br
= vec
;
dmaddr
->dmcsr
= DM_DONE
|DM_IE
;
/* no local state to set up */
* Open a DH11 line, mapping the clist onto the uba if this
* is the first dh on this uba. Turn on this dh if this is
* the first use of it. Also do a dmopen to wait for carrier.
register struct dhdevice
*addr
;
register struct uba_device
*ui
;
if (unit
>= NDH
*16 || (ui
= dhinfo
[dh
])== 0 || ui
->ui_alive
== 0) {
if (tp
->t_state
&TS_XCLUDE
&& u
.u_uid
!=0) {
addr
= (struct dhdevice
*)ui
->ui_addr
;
tp
->t_addr
= (caddr_t
)addr
;
* While setting up state for this uba and this dh,
* block uba resets which can clear the state.
if (dh_ubinfo
[ui
->ui_ubanum
] == 0) {
/* 512+ is a kludge to try to get around a hardware problem */
dh_ubinfo
[ui
->ui_ubanum
] =
uballoc(ui
->ui_ubanum
, (caddr_t
)cfree
,
512+nclist
*sizeof(struct cblock
), 0);
cbase
[ui
->ui_ubanum
] = dh_ubinfo
[ui
->ui_ubanum
]&0x3ffff;
if ((dhact
&(1<<dh
)) == 0) {
* If this is first open, initialze tty state to default.
if ((tp
->t_state
&TS_ISOPEN
) == 0) {
* Wait for carrier, then process line discipline specific open.
(*linesw
[tp
->t_line
].l_open
)(dev
, tp
);
* Close a DH11 line, turning off the DM11.
(*linesw
[tp
->t_line
].l_close
)(tp
);
((struct dhdevice
*)(tp
->t_addr
))->dhbreak
&= ~(1<<(unit
&017));
if (tp
->t_state
&TS_HUPCLS
|| (tp
->t_state
&TS_ISOPEN
)==0)
dmctl(unit
, DML_OFF
, DMSET
);
return ((*linesw
[tp
->t_line
].l_read
)(tp
, uio
));
(*linesw
[tp
->t_line
].l_write
)(tp
, uio
);
* DH11 receiver interrupt.
register struct dhdevice
*addr
;
register struct tty
*tp0
;
register struct uba_device
*ui
;
if (ui
== 0 || ui
->ui_alive
== 0)
addr
= (struct dhdevice
*)ui
->ui_addr
;
* Loop fetching characters from the silo for this
* dh until there are no more in the silo.
while ((c
= addr
->dhrcr
) < 0) {
if ((tp
->t_state
&TS_ISOPEN
)==0) {
if ((tp
->t_state
&(TS_ISOPEN
|TS_WOPEN
))==0) {
if ((tp
->t_flags
&(EVENP
|ODDP
))==EVENP
|| (tp
->t_flags
&(EVENP
|ODDP
))==ODDP
)
if ((c
& DH_DO
) && overrun
== 0) {
printf("dh%d: silo overflow\n", dh
);
* 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
);
dhioctl(dev
, cmd
, data
, flag
)
register unit
= minor(dev
);
cmd
= (*linesw
[tp
->t_line
].l_ioctl
)(tp
, cmd
, data
, flag
);
if (ttioctl(tp
, cmd
, data
, flag
)) {
if (cmd
== TIOCSETP
|| cmd
== TIOCSETN
)
((struct dhdevice
*)(tp
->t_addr
))->dhbreak
|= 1<<(unit
&017);
((struct dhdevice
*)(tp
->t_addr
))->dhbreak
&= ~(1<<(unit
&017));
dmctl(unit
, DML_DTR
|DML_RTS
, DMBIS
);
dmctl(unit
, DML_DTR
|DML_RTS
, DMBIC
);
* Set parameters from open or stty into the DH hardware
register struct dhdevice
*addr
;
addr
= (struct dhdevice
*)tp
->t_addr
;
* Block interrupts so parameters will be set
* before the line interrupts.
addr
->un
.dhcsrl
= (unit
&0xf) | DH_IE
;
tp
->t_state
|= TS_HUPCLS
;
dmctl(unit
, DML_OFF
, DMSET
);
lpar
= ((tp
->t_ospeed
)<<10) | ((tp
->t_ispeed
)<<6);
if ((tp
->t_ispeed
) == B134
)
lpar
|= BITS6
|PENABLE
|HDUPLX
;
else if ((tp
->t_flags
&RAW
) || (tp
->t_local
&LLITOUT
))
if ((tp
->t_flags
&EVENP
) == 0)
if ((tp
->t_ospeed
) == B110
)
* DH11 transmitter interrupt.
* Restart each line which used to be active but has
* terminated transmission since the last interrupt.
register struct dhdevice
*addr
;
short ttybit
, bar
, *sbar
;
register struct uba_device
*ui
;
addr
= (struct dhdevice
*)ui
->ui_addr
;
if (addr
->un
.dhcsr
& DH_NXM
) {
addr
->un
.dhcsr
|= DH_CNI
;
printf("dh%d: NXM\n", dh
);
bar
= *sbar
& ~addr
->dhbar
;
unit
= dh
* 16; ttybit
= 1;
addr
->un
.dhcsr
&= (short)~DH_TI
;
for (; bar
; unit
++, ttybit
<<= 1) {
if (tp
->t_state
&TS_FLUSH
)
tp
->t_state
&= ~TS_FLUSH
;
addr
->un
.dhcsrl
= (unit
&017)|DH_IE
;
* Do arithmetic in a short to make up
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 DH11 line.
register struct dhdevice
*addr
;
register int car
, dh
, unit
, nch
;
addr
= (struct dhdevice
*)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
&(TS_TIMEOUT
|TS_BUSY
|TS_TTSTOP
))
* If there are sleepers, and output has drained below low
* water mark, wake up the sleepers.
if (tp
->t_outq
.c_cc
<=TTLOWAT(tp
)) {
if (tp
->t_state
&TS_ASLEEP
) {
tp
->t_state
&= ~TS_ASLEEP
;
wakeup((caddr_t
)&tp
->t_outq
);
selwakeup(tp
->t_wsel
, tp
->t_state
& TS_WCOLL
);
tp
->t_state
&= ~TS_WCOLL
;
* 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);
tp
->t_state
|= TS_TIMEOUT
;
* If characters to transmit, restart transmission.
car
= UBACVT(tp
->t_outq
.c_cf
, dhinfo
[dh
]->ui_ubanum
);
addr
->un
.dhcsrl
= unit
|((car
>>12)&0x30)|DH_IE
;
* The following nonsense with short word
* is to make sure the dhbar |= word below
* is done with an interlocking bisw2 instruction.
{ short word
= 1 << unit
;
* Stop output on a line, e.g. for ^S/^Q or output flush.
register struct dhdevice
*addr
;
addr
= (struct dhdevice
*)tp
->t_addr
;
* Block input/output interrupts while messing with state.
if (tp
->t_state
& TS_BUSY
) {
* Device is transmitting; stop output
* by selecting the line and setting the byte
* count to -1. We will clean up later
* by examining the address where the dh stopped.
addr
->un
.dhcsrl
= (unit
&017) | DH_IE
;
if ((tp
->t_state
&TS_TTSTOP
)==0)
* Reset state of driver if UBA reset was necessary.
* Reset the csrl and lpr registers on open lines, and
register struct uba_device
*ui
;
if (dh_ubinfo
[uban
] == 0)
ubarelse(uban
, &dh_ubinfo
[uban
]);
dh_ubinfo
[uban
] = uballoc(uban
, (caddr_t
)cfree
,
512+nclist
*sizeof (struct cblock
), 0);
cbase
[uban
] = dh_ubinfo
[uban
]&0x3ffff;
for (dh
= 0; dh
< NDH
; dh
++) {
if (ui
== 0 || ui
->ui_alive
== 0 || ui
->ui_ubanum
!= uban
)
((struct dhdevice
*)ui
->ui_addr
)->un
.dhcsr
|= DH_IE
;
((struct dhdevice
*)ui
->ui_addr
)->dhsilo
= 16;
for (i
= 0; i
< 16; i
++) {
if (tp
->t_state
& (TS_ISOPEN
|TS_WOPEN
)) {
dmctl(unit
, DML_ON
, DMSET
);
* At software clock interrupt time or after a UNIBUS reset
* empty all the dh silos.
for (dh
= 0; dh
< NDH
; dh
++)
* Turn on the line associated with dh dev.
register struct dmdevice
*addr
;
register struct uba_device
*ui
;
if (dm
>= NDH
|| (ui
= dminfo
[dm
]) == 0 || ui
->ui_alive
== 0 ||
(dhsoftCAR
[dm
]&(1<<unit
))) {
tp
->t_state
|= TS_CARR_ON
;
addr
= (struct dmdevice
*)ui
->ui_addr
;
while (addr
->dmcsr
& DM_BUSY
)
if (addr
->dmlstat
&DML_CAR
)
tp
->t_state
|= TS_CARR_ON
;
addr
->dmcsr
= DM_IE
|DM_SE
;
while ((tp
->t_state
&TS_CARR_ON
)==0)
sleep((caddr_t
)&tp
->t_rawq
, TTIPRI
);
* Dump control bits into the DM registers.
register struct uba_device
*ui
;
register struct dmdevice
*addr
;
if ((ui
= dminfo
[dm
]) == 0 || ui
->ui_alive
== 0)
addr
= (struct dmdevice
*)ui
->ui_addr
;
while (addr
->dmcsr
& DM_BUSY
)
addr
->dmcsr
= unit
& 0xf;
addr
->dmcsr
= DM_IE
|DM_SE
;
* DM11 interrupt; deal with carrier transitions.
register struct uba_device
*ui
;
register struct dmdevice
*addr
;
addr
= (struct dmdevice
*)ui
->ui_addr
;
if (addr
->dmcsr
&DM_DONE
) {
tp
= &dh11
[(dm
<<4)+(addr
->dmcsr
&0xf)];
wakeup((caddr_t
)&tp
->t_rawq
);
if ((tp
->t_state
&TS_WOPEN
)==0 &&
if (addr
->dmlstat
& DML_CAR
) {
tp
->t_state
&= ~TS_TTSTOP
;
} else if ((tp
->t_state
&TS_TTSTOP
) == 0) {
tp
->t_state
|= TS_TTSTOP
;
} else if ((addr
->dmlstat
&DML_CAR
)==0) {
if ((tp
->t_state
&TS_WOPEN
)==0 &&
(tp
->t_local
&LNOHANG
)==0) {
gsignal(tp
->t_pgrp
, SIGHUP
);
gsignal(tp
->t_pgrp
, SIGCONT
);
flushtty(tp
, FREAD
|FWRITE
);
tp
->t_state
&= ~TS_CARR_ON
;
tp
->t_state
|= TS_CARR_ON
;
addr
->dmcsr
= DM_IE
|DM_SE
;