#include "../machine/pte.h"
#include "../vaxuba/ubareg.h"
#include "../vaxuba/ubavar.h"
#include "../vaxuba/dhreg.h"
#include "../vaxuba/dmreg.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
};
#define IFLAGS (EVENP|ODDP|ECHO)
#define IFLAGS (EVENP|ODDP)
* 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.
return ((*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
);
register struct tty
*tp
= &dh11
[minor(dev
)];
return ((*linesw
[tp
->t_line
].l_read
)(tp
, uio
));
register struct tty
*tp
= &dh11
[minor(dev
)];
return ((*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 int unit
= minor(dev
);
error
= (*linesw
[tp
->t_line
].l_ioctl
)(tp
, cmd
, data
, flag
);
error
= 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
|LITOUT
))
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
|LITOUT
))
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)
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 &&
(tp
->t_flags
& MDMBUF
)) {
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_flags
& NOHANG
) == 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
;