* Copyright (c) 1982 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)dz.c 6.9 (Berkeley) %G%
* This driver mimics dh.c; see it for explanation of common code.
#include "../machine/pte.h"
* Driver information for auto-configuration stuff.
int dzprobe(), dzattach(), dzrint();
struct uba_device
*dzinfo
[NDZ
];
struct uba_driver dzdriver
=
{ dzprobe
, 0, dzattach
, 0, dzstd
, "dz", dzinfo
};
#define FASTTIMER (hz/30) /* rate to drain silos, when in use */
int dzstart(), dzxint(), dzdma();
struct tty dz_tty
[NDZLINE
];
int dz_cnt
= { NDZLINE
};
int dzsilos
; /* mask of dz's with silo in use */
int dzchars
[NDZ
]; /* recent input count */
int dzrate
[NDZ
]; /* smoothed input count */
int dztimerintvl
; /* time interval for dztimer */
int dzhighrate
= 100; /* silo on if dzchars > dzhighrate */
int dzlowrate
= 75; /* silo off if dzrate < dzlowrate */
#define dzwait(x) while (((x)->dzlcs & DZ_ACK) == 0)
* Software copy of dzbrk since it isn't readable
char dz_lnen
[NDZ
]; /* saved line enable bits for DZ32 */
* The dz11 doesn't interrupt on carrier transitions, so
* we have to use a timer to watch it.
char dz_timer
; /* timer started? */
* Pdma structures for fast output code
struct pdma dzpdma
[NDZLINE
];
{ 0,020,021,022,023,024,0,025,026,027,030,032,034,036,037,0 };
#define IFLAGS (EVENP|ODDP|ECHO)
#define IFLAGS (EVENP|ODDP)
register struct dzdevice
*dzaddr
= (struct dzdevice
*)reg
;
br
= 0; cvec
= br
; br
= cvec
;
dzrint(0); dzxint((struct tty
*)0);
dzaddr
->dzcsr
= DZ_TIE
|DZ_MSE
|DZ_32
;
if (dzaddr
->dzcsr
& DZ_32
)
dzaddr
->dztcr
= 1; /* enable any line */
dzaddr
->dzcsr
= DZ_CLR
|DZ_32
; /* reset everything */
if (cvec
&& cvec
!= 0x200)
return (sizeof (struct dzdevice
));
register struct uba_device
*ui
;
register struct pdma
*pdp
= &dzpdma
[ui
->ui_unit
*8];
register struct tty
*tp
= &dz_tty
[ui
->ui_unit
*8];
for (cntr
= 0; cntr
< 8; cntr
++) {
pdp
->p_addr
= (struct dzdevice
*)ui
->ui_addr
;
dzsoftCAR
[ui
->ui_unit
] = ui
->ui_flags
;
timeout(dzscan
, (caddr_t
)0, hz
);
dztimerintvl
= FASTTIMER
;
if (unit
>= dz_cnt
|| dzpdma
[unit
].p_addr
== 0)
tp
->t_addr
= (caddr_t
)&dzpdma
[unit
];
if ((tp
->t_state
& TS_ISOPEN
) == 0) {
tp
->t_ospeed
= tp
->t_ispeed
= ISPEED
;
/* tp->t_state |= TS_HUPCLS; */
} else if (tp
->t_state
&TS_XCLUDE
&& u
.u_uid
!= 0)
(void) dzmctl(dev
, DZ_ON
, DMSET
);
while ((tp
->t_state
& TS_CARR_ON
) == 0) {
sleep((caddr_t
)&tp
->t_rawq
, TTIPRI
);
return ((*linesw
[tp
->t_line
].l_open
)(dev
, tp
));
register struct dzdevice
*dzaddr
;
(*linesw
[tp
->t_line
].l_close
)(tp
);
dzaddr
= dzpdma
[unit
].p_addr
;
(void) dzmctl(dev
, DZ_BRK
, DMBIC
);
dzaddr
->dzbrk
= (dz_brk
[dz
] &= ~(1 << (unit
&07)));
if ((tp
->t_state
&(TS_HUPCLS
|TS_WOPEN
)) || (tp
->t_state
&TS_ISOPEN
) == 0)
(void) dzmctl(dev
, DZ_OFF
, DMSET
);
tp
= &dz_tty
[minor(dev
)];
return ((*linesw
[tp
->t_line
].l_read
)(tp
, uio
));
tp
= &dz_tty
[minor(dev
)];
return ((*linesw
[tp
->t_line
].l_write
)(tp
, uio
));
register struct dzdevice
*dzaddr
;
register struct tty
*tp0
;
if ((dzact
& (1<<dz
)) == 0)
dzaddr
= dzpdma
[unit
].p_addr
;
dzaddr
->dzcsr
&= ~(DZ_RIE
|DZ_MIE
); /* the manual says this song */
dzaddr
->dzcsr
|= DZ_RIE
|DZ_MIE
; /* and dance is necessary */
while (dzaddr
->dzcsr
& DZ_MSC
) { /* DZ32 modem change interrupt */
if (tp
>= &dz_tty
[dz_cnt
])
dzaddr
->dzlcs
= c
&7; /* get status of modem lines */
dzwait(dzaddr
); /* wait for them */
if (c
& DZ_CD
) /* carrier status change? */
if (dzaddr
->dzlcs
& DZ_CD
) { /* carrier up? */
if ((tp
->t_state
&TS_CARR_ON
) == 0) {
wakeup((caddr_t
)&tp
->t_rawq
);
tp
->t_state
|= TS_CARR_ON
;
} else { /* no carrier */
if (tp
->t_state
&TS_CARR_ON
) {
gsignal(tp
->t_pgrp
, SIGHUP
);
gsignal(tp
->t_pgrp
, SIGCONT
);
dzaddr
->dzlcs
= DZ_ACK
|(c
&7);
ttyflush(tp
, FREAD
|FWRITE
);
tp
->t_state
&= ~TS_CARR_ON
;
while ((c
= dzaddr
->dzrbuf
) < 0) { /* char present */
if (tp
>= &dz_tty
[dz_cnt
])
if ((tp
->t_state
& TS_ISOPEN
) == 0) {
wakeup((caddr_t
)&tp
->t_rawq
);
if ((tp
->t_state
&TS_WOPEN
) == 0)
if (c
&DZ_DO
&& overrun
== 0) {
log(LOG_WARNING
, "dz%d,%d: silo overflow\n", dz
, (c
>>8)&7);
if (((tp
->t_flags
& (EVENP
|ODDP
)) == EVENP
)
|| ((tp
->t_flags
& (EVENP
|ODDP
)) == ODDP
))
if (tp
->t_line
== NETLDISC
) {
(*linesw
[tp
->t_line
].l_rint
)(c
, tp
);
dzioctl(dev
, cmd
, data
, flag
)
register int unit
= minor(dev
);
register int dz
= unit
>> 3;
register struct dzdevice
*dzaddr
;
error
= (*linesw
[tp
->t_line
].l_ioctl
)(tp
, cmd
, data
, flag
);
error
= ttioctl(tp
, cmd
, data
, flag
);
if (cmd
== TIOCSETP
|| cmd
== TIOCSETN
|| cmd
== TIOCLBIS
||
cmd
== TIOCLBIC
|| cmd
== TIOCLSET
)
dzaddr
= ((struct pdma
*)(tp
->t_addr
))->p_addr
;
(void) dzmctl(dev
, DZ_BRK
, DMBIS
);
dzaddr
->dzbrk
= (dz_brk
[dz
] |= 1 << (unit
&07));
dzaddr
= ((struct pdma
*)(tp
->t_addr
))->p_addr
;
(void) dzmctl(dev
, DZ_BRK
, DMBIC
);
dzaddr
->dzbrk
= (dz_brk
[dz
] &= ~(1 << (unit
&07)));
(void) dzmctl(dev
, DZ_DTR
|DZ_RTS
, DMBIS
);
(void) dzmctl(dev
, DZ_DTR
|DZ_RTS
, DMBIC
);
(void) dzmctl(dev
, dmtodz(*(int *)data
), DMSET
);
(void) dzmctl(dev
, dmtodz(*(int *)data
), DMBIS
);
(void) dzmctl(dev
, dmtodz(*(int *)data
), DMBIC
);
*(int *)data
= dztodm(dzmctl(dev
, 0, DMGET
));
if (bits
& DML_ST
) b
|= DZ_ST
;
if (bits
& DML_RTS
) b
|= DZ_RTS
;
if (bits
& DML_DTR
) b
|= DZ_DTR
;
if (bits
& DML_LE
) b
|= DZ_LE
;
if (bits
& DZ_DSR
) b
|= DML_DSR
;
if (bits
& DZ_DTR
) b
|= DML_DTR
;
if (bits
& DZ_ST
) b
|= DML_ST
;
if (bits
& DZ_RTS
) b
|= DML_RTS
;
register struct dzdevice
*dzaddr
;
dzaddr
= dzpdma
[unit
].p_addr
;
if (dzsilos
& (1 << (unit
>> 3)))
dzaddr
->dzcsr
= DZ_IEN
| DZ_SAE
;
(void) dzmctl(unit
, DZ_OFF
, DMSET
); /* hang up line */
lpr
= (dz_speeds
[tp
->t_ispeed
]<<8) | (unit
& 07);
if (tp
->t_flags
& (RAW
|LITOUT
|PASS8
))
if ((tp
->t_flags
& EVENP
) == 0)
if (tp
->t_ispeed
== B110
)
register struct pdma
*dp
;
dp
= (struct pdma
*)tp
->t_addr
;
if (tp
->t_state
& TS_FLUSH
)
tp
->t_state
&= ~TS_FLUSH
;
ndflush(&tp
->t_outq
, dp
->p_mem
-tp
->t_outq
.c_cf
);
dp
->p_end
= dp
->p_mem
= tp
->t_outq
.c_cf
;
(*linesw
[tp
->t_line
].l_start
)(tp
);
dz
= minor(tp
->t_dev
) >> 3;
unit
= minor(tp
->t_dev
) & 7;
if (tp
->t_outq
.c_cc
== 0 || (tp
->t_state
&TS_BUSY
)==0)
if (dp
->p_addr
->dzcsr
& DZ_32
)
dp
->p_addr
->dzlnen
= (dz_lnen
[dz
] &= ~(1<<unit
));
dp
->p_addr
->dztcr
&= ~(1<<unit
);
register struct pdma
*dp
;
register struct dzdevice
*dzaddr
;
dp
= (struct pdma
*)tp
->t_addr
;
if (tp
->t_state
& (TS_TIMEOUT
|TS_BUSY
|TS_TTSTOP
))
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
;
if (tp
->t_outq
.c_cc
== 0)
if (tp
->t_flags
& (RAW
|LITOUT
))
cc
= ndqb(&tp
->t_outq
, 0);
cc
= ndqb(&tp
->t_outq
, 0200);
timeout(ttrstrt
, (caddr_t
)tp
, (cc
&0x7f) + 6);
tp
->t_state
|= TS_TIMEOUT
;
dp
->p_end
= dp
->p_mem
= tp
->t_outq
.c_cf
;
dz
= minor(tp
->t_dev
) >> 3;
unit
= minor(tp
->t_dev
) & 7;
if (dzaddr
->dzcsr
& DZ_32
)
dzaddr
->dzlnen
= (dz_lnen
[dz
] |= (1<<unit
));
dzaddr
->dztcr
|= (1<<unit
);
register struct pdma
*dp
;
dp
= (struct pdma
*)tp
->t_addr
;
if (tp
->t_state
& TS_BUSY
) {
if ((tp
->t_state
&TS_TTSTOP
)==0)
register struct dzdevice
*dzaddr
;
register int unit
, mbits
;
dzaddr
= dzpdma
[unit
].p_addr
;
if (dzaddr
->dzcsr
& DZ_32
) {
DELAY(100); /* IS 100 TOO MUCH? */
mbits
= (dzaddr
->dzdtr
& b
) ? DZ_DTR
: 0;
mbits
|= (dzaddr
->dzmsr
& b
) ? DZ_CD
: 0;
mbits
|= (dzaddr
->dztbuf
& b
) ? DZ_RI
: 0;
if (dzaddr
->dzcsr
& DZ_32
) {
mbits
|= DZ_ACK
|(unit
&7);
int dztransitions
, dzfasttimers
; /*DEBUG*/
register struct dzdevice
*dzaddr
;
int olddzsilos
= dzsilos
;
for (i
= 0; i
< dz_cnt
; i
++) {
dzaddr
= dzpdma
[i
].p_addr
;
else if (dzaddr
->dzcsr
& DZ_32
) {
car
= dzaddr
->dzlcs
& DZ_CD
;
if ((tp
->t_state
& TS_CARR_ON
) == 0) {
wakeup((caddr_t
)&tp
->t_rawq
);
tp
->t_state
|= TS_CARR_ON
;
if ((tp
->t_state
&TS_CARR_ON
) &&
(tp
->t_flags
&NOHANG
) == 0) {
if (tp
->t_state
&TS_ISOPEN
) {
gsignal(tp
->t_pgrp
, SIGHUP
);
gsignal(tp
->t_pgrp
, SIGCONT
);
ttyflush(tp
, FREAD
|FWRITE
);
tp
->t_state
&= ~TS_CARR_ON
;
for (i
= 0; i
< NDZ
; i
++) {
ave(dzrate
[i
], dzchars
[i
], 8);
if (dzchars
[i
] > dzhighrate
&& ((dzsilos
& (1 << i
)) == 0)) {
dzpdma
[i
<< 3].p_addr
->dzcsr
= DZ_IEN
| DZ_SAE
;
dztransitions
++; /*DEBUG*/
} else if ((dzsilos
& (1 << i
)) && (dzrate
[i
] < dzlowrate
)) {
dzpdma
[i
<< 3].p_addr
->dzcsr
= DZ_IEN
;
if (dzsilos
&& !olddzsilos
)
timeout(dztimer
, (caddr_t
)0, dztimerintvl
);
timeout(dzscan
, (caddr_t
)0, hz
);
dzfasttimers
++; /*DEBUG*/
for (dz
= 0; dz
< NDZ
; dz
++)
timeout(dztimer
, (caddr_t
) 0, dztimerintvl
);
* Reset state of driver if UBA reset was necessary.
* Reset parameters and restart transmission on open lines.
register struct uba_device
*ui
;
for (unit
= 0; unit
< NDZLINE
; unit
++) {
if (ui
== 0 || ui
->ui_ubanum
!= uban
|| ui
->ui_alive
== 0)
printf(" dz%d", unit
>>3);
if (tp
->t_state
& (TS_ISOPEN
|TS_WOPEN
)) {
(void) dzmctl(unit
, DZ_ON
, DMSET
);