* Copyright (c) 1988 University of Utah.
* Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* 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
* from: $Hdr: dcm.c 1.26 91/01/21$
* @(#)dcm.c 7.14 (Berkeley) 6/27/91
#include "../hp300/isr.h"
#ifndef DEFAULT_BAUD_RATE
#define DEFAULT_BAUD_RATE 9600
int dcmprobe(), dcmstart(), dcmintr(), dcmparam();
struct driver dcmdriver
= {
#define NDCMLINE (NDCM*4)
struct tty dcm_tty
[NDCMLINE
];
struct modemreg
*dcm_modem
[NDCMLINE
];
char mcndlast
[NDCMLINE
]; /* XXX last modem status for line */
struct dcmdevice
*dcm_addr
[NDCM
];
struct speedtab dcmspeedtab
[] = {
/* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */
#define DCM_USPERCH(s) (10000000 / (s))
* Per board interrupt scheme. 16.7ms is the polling interrupt rate
* (16.7ms is about 550 baud, 38.4k is 72 chars in 16.7ms).
int dcmistype
= -1; /* -1 == dynamic, 0 == timer, 1 == perchar */
int dcminterval
= 5; /* interval (secs) between checks */
int dis_perchar
; /* non-zero if interrupting per char */
long dis_time
; /* last time examined */
int dis_intr
; /* recv interrupts during last interval */
int dis_char
; /* characters read during last interval */
int dcmconsole
= DCMCONSOLE
;
int dcmdefaultrate
= DEFAULT_BAUD_RATE
;
extern struct tty
*constty
;
#include "machine/remote-sl.h"
extern int kgdb_debug_init
;
#define DDB_OPENCLOSE 0x100
long xints
; /* # of xmit ints */
long xchars
; /* # of xmit chars */
long xempty
; /* times outq is empty in dcmstart */
long xrestarts
; /* times completed while xmitting */
long rints
; /* # of recv ints */
long rchars
; /* # of recv chars */
long xsilo
[DCMXBSIZE
+2]; /* times this many chars xmit on one int */
long rsilo
[DCMRBSIZE
+2]; /* times this many chars read on one int */
#define BOARD(x) (((x) >> 2) & 0x3f)
#define PORT(x) ((x) & 3)
#define MKUNIT(b,p) (((b) << 2) | (p))
* Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux,
* the distribution panel uses "HP DCE" conventions. If requested via
* the device flags, we swap the inputs to something closer to normal DCE,
* allowing a straight-through cable to a DTE or a reversed cable
* to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected;
* this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect
* DSR or make RTS work, though). The following gives the full
* details of a cable from this mux panel to a modem:
* CTS 4 5 CTS (only needed for CCTS_OFLOW)
* "DSR" 9 6 DSR (unneeded)
* "SR" 23 4 RTS (often not needed)
#define FLAG_STDDCE 0x10 /* map inputs if this bit is set in flags */
#define hp2dce_in(ibits) (iconv[(ibits) & 0xf])
static char iconv
[16] = {
0, MI_DM
, MI_CTS
, MI_CTS
|MI_DM
,
MI_CD
, MI_CD
|MI_DM
, MI_CD
|MI_CTS
, MI_CD
|MI_CTS
|MI_DM
,
MI_RI
, MI_RI
|MI_DM
, MI_RI
|MI_CTS
, MI_RI
|MI_CTS
|MI_DM
,
MI_RI
|MI_CD
, MI_RI
|MI_CD
|MI_DM
, MI_RI
|MI_CD
|MI_CTS
,
register struct hp_device
*hd
;
register struct dcmdevice
*dcm
;
int s
, brd
, isconsole
, mbits
;
dcm
= (struct dcmdevice
*)hd
->hp_addr
;
if ((dcm
->dcm_rsid
& 0x1f) != DCMID
)
isconsole
= (brd
== BOARD(dcmconsole
));
* XXX selected console device (CONSUNIT) as determined by
* dcmcnprobe does not agree with logical numbering imposed
* by the config file (i.e. lowest address DCM is not unit
* CONSUNIT). Don't recognize this card.
if (isconsole
&& dcm
!= dcm_addr
[BOARD(dcmconsole
)])
* Empirically derived self-test magic
DELAY(50000); /* 5000 is not long enough */
while ((dcm
->dcm_ic
& IC_IR
) == 0)
DELAY(50000) /* XXX why is this needed ???? */
while ((dcm
->dcm_iir
& IIR_SELFT
) == 0)
DELAY(50000) /* XXX why is this needed ???? */
if (dcm
->dcm_stcon
!= ST_OK
) {
printf("dcm%d: self test failed: %x\n",
hd
->hp_ipl
= DCMIPL(dcm
->dcm_ic
);
dcmsoftCAR
[brd
] = hd
->hp_flags
;
dcmisr
[brd
].isr_ipl
= hd
->hp_ipl
;
dcmisr
[brd
].isr_arg
= brd
;
dcmisr
[brd
].isr_intr
= dcmintr
;
if (major(kgdb_dev
) == dcmmajor
&& BOARD(kgdb_dev
) == brd
) {
if (dcmconsole
== UNIT(kgdb_dev
))
kgdb_dev
= NODEV
; /* can't debug over console port */
* The following could potentially be replaced
* by the corresponding code in dcmcnprobe.
(void) dcminit(kgdb_dev
, kgdb_rate
);
printf("dcm%d: ", UNIT(kgdb_dev
));
printf("dcm%d: kgdb enabled\n", UNIT(kgdb_dev
));
/* end could be replaced */
if (dcmistype
== DIS_TIMER
)
dcmsetischeme(brd
, DIS_RESET
|DIS_TIMER
);
dcmsetischeme(brd
, DIS_RESET
|DIS_PERCHAR
);
/* load pointers to modem control */
dcm_modem
[MKUNIT(brd
, 0)] = &dcm
->dcm_modem0
;
dcm_modem
[MKUNIT(brd
, 1)] = &dcm
->dcm_modem1
;
dcm_modem
[MKUNIT(brd
, 2)] = &dcm
->dcm_modem2
;
dcm_modem
[MKUNIT(brd
, 3)] = &dcm
->dcm_modem3
;
/* set DCD (modem) and CTS (flow control) on all ports */
if (dcmsoftCAR
[brd
] & FLAG_STDDCE
)
mbits
= hp2dce_in(MI_CD
|MI_CTS
);
dcm_modem
[MKUNIT(brd
, i
)]->mdmmsk
= mbits
;
dcm
->dcm_ic
= IC_IE
; /* turn all interrupts on */
* Need to reset baud rate, etc. of next print so reset dcmconsole.
* Also make sure console is always "hardwired"
dcmsoftCAR
[brd
] |= (1 << PORT(dcmconsole
));
dcmopen(dev_t dev
, int flag
, int mode
, struct proc
*p
)
dcmopen(dev
, flag
, mode
, p
)
if (unit
>= NDCMLINE
|| (dcm_active
& (1 << brd
)) == 0)
if ((tp
->t_state
& TS_ISOPEN
) == 0) {
tp
->t_iflag
= TTYDEF_IFLAG
;
tp
->t_oflag
= TTYDEF_OFLAG
;
tp
->t_cflag
= TTYDEF_CFLAG
;
tp
->t_lflag
= TTYDEF_LFLAG
;
tp
->t_ispeed
= tp
->t_ospeed
= TTYDEF_SPEED
;
(void) dcmparam(tp
, &tp
->t_termios
);
} else if (tp
->t_state
&TS_XCLUDE
&& p
->p_ucred
->cr_uid
!= 0)
if (dcmsoftCAR
[brd
] & FLAG_STDDCE
)
mbits
|= MO_SR
; /* pin 23, could be used as RTS */
(void) dcmmctl(dev
, mbits
, DMSET
); /* enable port */
if ((dcmsoftCAR
[brd
] & (1 << PORT(unit
))) ||
(dcmmctl(dev
, MO_OFF
, DMGET
) & MI_CD
))
tp
->t_state
|= TS_CARR_ON
;
if (dcmdebug
& DDB_MODEM
)
printf("dcm%d: dcmopen port %d softcarr %c\n",
brd
, unit
, (tp
->t_state
& TS_CARR_ON
) ? '1' : '0');
while ((flag
&O_NONBLOCK
) == 0 && (tp
->t_cflag
&CLOCAL
) == 0 &&
(tp
->t_state
& TS_CARR_ON
) == 0) {
if (error
= ttysleep(tp
, (caddr_t
)&tp
->t_rawq
, TTIPRI
| PCATCH
,
if (dcmdebug
& DDB_OPENCLOSE
)
printf("dcmopen: u %x st %x fl %x\n",
unit
, tp
->t_state
, tp
->t_flags
);
error
= (*linesw
[tp
->t_line
].l_open
)(dev
, tp
);
dcmclose(dev
, flag
, mode
, p
)
(*linesw
[tp
->t_line
].l_close
)(tp
, flag
);
if (tp
->t_cflag
&HUPCL
|| tp
->t_state
&TS_WOPEN
||
(tp
->t_state
&TS_ISOPEN
) == 0)
(void) dcmmctl(dev
, MO_OFF
, DMSET
);
if (dcmdebug
& DDB_OPENCLOSE
)
printf("dcmclose: u %x st %x fl %x\n",
unit
, tp
->t_state
, tp
->t_flags
);
tp
= &dcm_tty
[UNIT(dev
)];
return ((*linesw
[tp
->t_line
].l_read
)(tp
, uio
, flag
));
* XXX we disallow virtual consoles if the physical console is
* a serial port. This is in case there is a display attached that
* is not the console. In that situation we don't need/want the X
* server taking over the console.
if (constty
&& unit
== dcmconsole
)
return ((*linesw
[tp
->t_line
].l_write
)(tp
, uio
, flag
));
register struct dcmdevice
*dcm
= dcm_addr
[brd
];
register struct dcmischeme
*dis
;
register int unit
= MKUNIT(brd
, 0);
int pcnd
[4], mcode
, mcnd
[4];
* Do all guarded register accesses right off to minimize
if ((dcm
->dcm_ic
& IC_IR
) == 0) {
for (i
= 0; i
< 4; i
++) {
pcnd
[i
] = dcm
->dcm_icrtab
[i
].dcm_data
;
dcm
->dcm_icrtab
[i
].dcm_data
= 0;
code
= dcm_modem
[unit
+i
]->mdmin
;
if (dcmsoftCAR
[brd
] & FLAG_STDDCE
)
code
= dcm
->dcm_iir
& IIR_MASK
;
dcm
->dcm_iir
= 0; /* XXX doc claims read clears interrupt?! */
mcode
= dcm
->dcm_modemintr
;
if (dcmdebug
& DDB_INTR
) {
printf("dcmintr(%d): iir %x pc %x/%x/%x/%x ",
brd
, code
, pcnd
[0], pcnd
[1], pcnd
[2], pcnd
[3]);
printf("miir %x mc %x/%x/%x/%x\n",
mcode
, mcnd
[0], mcnd
[1], mcnd
[2], mcnd
[3]);
dcmpint(unit
+0, pcnd
[0], dcm
);
dcmpint(unit
+1, pcnd
[1], dcm
);
dcmpint(unit
+2, pcnd
[2], dcm
);
dcmpint(unit
+3, pcnd
[3], dcm
);
if (mcode
== 0 || mcode
& 0x1) /* mcode==0 -> 98642 board */
dcmmint(unit
+0, mcnd
[0], dcm
);
dcmmint(unit
+1, mcnd
[1], dcm
);
dcmmint(unit
+2, mcnd
[2], dcm
);
dcmmint(unit
+3, mcnd
[3], dcm
);
* Chalk up a receiver interrupt if the timer running or one of
* the ports reports a special character interrupt.
if ((code
& IIR_TIMEO
) ||
((pcnd
[0]|pcnd
[1]|pcnd
[2]|pcnd
[3]) & IT_SPEC
))
* See if it is time to check/change the interrupt rate.
(i
= time
.tv_sec
- dis
->dis_time
) >= dcminterval
) {
* If currently per-character and averaged over 70 interrupts
* per-second (66 is threshold of 600 baud) in last interval,
* XXX decay counts ala load average to avoid spikes?
if (dis
->dis_perchar
&& dis
->dis_intr
> 70 * i
)
dcmsetischeme(brd
, DIS_TIMER
);
* If currently using timer and had more interrupts than
* received characters in the last interval, switch back
* to per-character. Note that after changing to per-char
* we must process any characters already in the queue
* since they may have arrived before the bitmap was setup.
else if (!dis
->dis_perchar
&& dis
->dis_intr
> dis
->dis_char
) {
dcmsetischeme(brd
, DIS_PERCHAR
);
dis
->dis_intr
= dis
->dis_char
= 0;
dis
->dis_time
= time
.tv_sec
;
* Port interrupt. Can be two things:
* First, it might be a special character (exception interrupt);
* Second, it may be a buffer empty (transmit interrupt);
struct tty
*tp
= &dcm_tty
[unit
];
dcmreadbuf(unit
, dcm
, tp
);
register struct dcmdevice
*dcm
;
for (i
= 0; i
< 4; i
++, tp
++, unit
++)
dcmreadbuf(unit
, dcm
, tp
);
dcmreadbuf(unit
, dcm
, tp
)
register struct dcmdevice
*dcm
;
register struct dcmpreg
*pp
= dcm_preg(dcm
, port
);
register struct dcmrfifo
*fifo
;
struct dcmstats
*dsp
= &dcmstats
[BOARD(unit
)];
if ((tp
->t_state
& TS_ISOPEN
) == 0) {
if ((makedev(dcmmajor
, unit
) == kgdb_dev
) &&
(head
= pp
->r_head
& RX_MASK
) != (pp
->r_tail
& RX_MASK
) &&
dcm
->dcm_rfifos
[3-port
][head
>>1].data_char
== FRAME_END
) {
pp
->r_head
= (head
+ 2) & RX_MASK
;
kgdb_connect(0); /* trap into kgdb */
pp
->r_head
= pp
->r_tail
& RX_MASK
;
head
= pp
->r_head
& RX_MASK
;
fifo
= &dcm
->dcm_rfifos
[3-port
][head
>>1];
* XXX upper bound on how many chars we will take in one swallow?
while (head
!= (pp
->r_tail
& RX_MASK
)) {
* Get character/status and update head pointer as fast
* as possible to make room for more characters.
head
= (head
+ 2) & RX_MASK
;
fifo
= head
? fifo
+1 : &dcm
->dcm_rfifos
[3-port
][0];
if (dcmdebug
& DDB_INPUT
)
printf("dcmreadbuf(%d): c%x('%c') s%x f%x h%x t%x\n",
unit
, c
&0xFF, c
, stat
&0xFF,
tp
->t_flags
, head
, pp
->r_tail
);
* Check for and handle errors
if (dcmdebug
& (DDB_INPUT
|DDB_SIOERR
))
printf("dcmreadbuf(%d): err: c%x('%c') s%x\n",
if (stat
& (RD_BD
| RD_FE
))
"dcm%d: silo overflow\n", unit
);
"dcm%d: uart overflow\n", unit
);
(*linesw
[tp
->t_line
].l_rint
)(c
, tp
);
dcmischeme
[BOARD(unit
)].dis_char
+= nch
;
dsp
->rsilo
[DCMRBSIZE
+1]++;
if (tp
->t_state
& TS_FLUSH
)
tp
->t_state
&= ~TS_FLUSH
;
(*linesw
[tp
->t_line
].l_start
)(tp
);
register struct dcmdevice
*dcm
;
if (dcmdebug
& DDB_MODEM
)
printf("dcmmint: port %d mcnd %x mcndlast %x\n",
unit
, mcnd
, mcndlast
[unit
]);
delta
= mcnd
^ mcndlast
[unit
];
if ((delta
& MI_CTS
) && (tp
->t_state
& TS_ISOPEN
) &&
(tp
->t_flags
& CCTS_OFLOW
)) {
tp
->t_state
&= ~TS_TTSTOP
;
tp
->t_state
|= TS_TTSTOP
; /* inline dcmstop */
(void)(*linesw
[tp
->t_line
].l_modem
)(tp
, 1);
else if ((dcmsoftCAR
[BOARD(unit
)] & (1 << PORT(unit
))) == 0 &&
(*linesw
[tp
->t_line
].l_modem
)(tp
, 0) == 0) {
dcm_modem
[unit
]->mdmout
= MO_OFF
;
dcm
->dcm_modemchng
|= 1<<(unit
& 3);
DELAY(10); /* time to change lines */
dcmioctl(dev
, cmd
, data
, flag
)
register int unit
= UNIT(dev
);
register struct dcmdevice
*dcm
;
if (dcmdebug
& DDB_IOCTL
)
printf("dcmioctl: unit %d cmd %x data %x flag %x\n",
error
= (*linesw
[tp
->t_line
].l_ioctl
)(tp
, cmd
, data
, flag
);
error
= ttioctl(tp
, cmd
, data
, flag
);
dcm
= dcm_addr
[BOARD(unit
)];
* Wait for transmitter buffer to empty
while (dcm
->dcm_thead
[port
].ptr
!= dcm
->dcm_ttail
[port
].ptr
)
DELAY(DCM_USPERCH(tp
->t_ospeed
));
dcm
->dcm_cmdtab
[port
].dcm_data
|= CT_BRK
;
dcm
->dcm_cr
|= (1 << port
); /* start break */
dcm
->dcm_cmdtab
[port
].dcm_data
|= CT_BRK
;
dcm
->dcm_cr
|= (1 << port
); /* end break */
(void) dcmmctl(dev
, MO_ON
, DMBIS
);
(void) dcmmctl(dev
, MO_ON
, DMBIC
);
(void) dcmmctl(dev
, *(int *)data
, DMSET
);
(void) dcmmctl(dev
, *(int *)data
, DMBIS
);
(void) dcmmctl(dev
, *(int *)data
, DMBIC
);
*(int *)data
= dcmmctl(dev
, 0, DMGET
);
register struct termios
*t
;
register struct dcmdevice
*dcm
;
register int port
, mode
, cflag
= t
->c_cflag
;
int ospeed
= ttspeedtab(t
->c_ospeed
, dcmspeedtab
);
/* check requested parameters */
if (ospeed
< 0 || (t
->c_ispeed
&& t
->c_ispeed
!= t
->c_ospeed
))
tp
->t_ispeed
= t
->c_ispeed
;
tp
->t_ospeed
= t
->c_ospeed
;
(void) dcmmctl(UNIT(tp
->t_dev
), MO_OFF
, DMSET
);
if (dcmdebug
& DDB_PARAM
)
printf("dcmparam(%d): cflag %x mode %x speed %d uperch %d\n",
UNIT(tp
->t_dev
), cflag
, mode
, tp
->t_ospeed
,
DCM_USPERCH(tp
->t_ospeed
));
dcm
= dcm_addr
[BOARD(tp
->t_dev
)];
* Wait for transmitter buffer to empty.
while (dcm
->dcm_thead
[port
].ptr
!= dcm
->dcm_ttail
[port
].ptr
)
DELAY(DCM_USPERCH(tp
->t_ospeed
));
* Make changes known to hardware.
dcm
->dcm_data
[port
].dcm_baud
= ospeed
;
dcm
->dcm_data
[port
].dcm_conf
= mode
;
dcm
->dcm_cmdtab
[port
].dcm_data
|= CT_CON
;
dcm
->dcm_cr
|= (1 << port
);
* Delay for config change to take place. Weighted by baud.
DELAY(16 * DCM_USPERCH(tp
->t_ospeed
));
register struct dcmdevice
*dcm
;
register struct dcmpreg
*pp
;
register struct dcmtfifo
*fifo
;
register unsigned tail
, next
;
struct dcmstats
*dsp
= &dcmstats
[BOARD(tp
->t_dev
)];
if (dcmdebug
& DDB_OUTPUT
)
printf("dcmstart(%d): state %x flags %x outcc %d\n",
UNIT(tp
->t_dev
), tp
->t_state
, tp
->t_flags
,
if (tp
->t_state
& (TS_TIMEOUT
|TS_BUSY
|TS_TTSTOP
))
if (tp
->t_outq
.c_cc
<= tp
->t_lowat
) {
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) {
dcm
= dcm_addr
[BOARD(tp
->t_dev
)];
pp
= dcm_preg(dcm
, port
);
tail
= pp
->t_tail
& TX_MASK
;
next
= (tail
+ 1) & TX_MASK
;
head
= pp
->t_head
& TX_MASK
;
fifo
= &dcm
->dcm_tfifos
[3-port
][tail
];
nch
= q_to_b(&tp
->t_outq
, buf
, (head
- next
) & TX_MASK
);
if (dcmdebug
& DDB_OUTPUT
)
printf("\thead %x tail %x nch %d\n", head
, tail
, nch
);
* Loop transmitting all the characters we can.
for (bp
= buf
; --nch
>= 0; bp
++) {
* If this is the first character,
* get the hardware moving right now.
dcm
->dcm_cmdtab
[port
].dcm_data
|= CT_TX
;
dcm
->dcm_cr
|= (1 << port
);
fifo
= tail
? fifo
+1 : &dcm
->dcm_tfifos
[3-port
][0];
next
= (next
+ 1) & TX_MASK
;
* Head changed while we were loading the buffer,
* go back and load some more if we can.
if (tp
->t_outq
.c_cc
&& head
!= (pp
->t_head
& TX_MASK
)) {
head
= pp
->t_head
& TX_MASK
;
* Kick it one last time in case it finished while we were
* loading the last bunch.
dcm
->dcm_cmdtab
[port
].dcm_data
|= CT_TX
;
dcm
->dcm_cr
|= (1 << port
);
printf("dcmstart(%d): head %x tail %x outqcc %d\n",
UNIT(tp
->t_dev
), head
, tail
, tp
->t_outq
.c_cc
);
dsp
->xsilo
[DCMXBSIZE
+1]++;
if (tp
->t_state
& TS_BUSY
) {
/* XXX is there some way to safely stop transmission? */
if ((tp
->t_state
&TS_TTSTOP
) == 0)
register struct dcmdevice
*dcm
;
int s
, unit
, brd
, hit
= 0;
if (dcmdebug
& DDB_MODEM
)
printf("dcmmctl(%d) unit %d bits 0x%x how %x\n",
BOARD(unit
), unit
, bits
, how
);
dcm_modem
[unit
]->mdmout
= bits
;
dcm_modem
[unit
]->mdmout
|= bits
;
dcm_modem
[unit
]->mdmout
&= ~bits
;
bits
= dcm_modem
[unit
]->mdmin
;
if (dcmsoftCAR
[brd
] & FLAG_STDDCE
)
dcm
->dcm_modemchng
|= 1<<(unit
& 3);
DELAY(10); /* delay until done */
* Set board to either interrupt per-character or at a fixed interval.
dcmsetischeme(brd
, flags
)
register struct dcmdevice
*dcm
= dcm_addr
[brd
];
register struct dcmischeme
*dis
= &dcmischeme
[brd
];
int perchar
= flags
& DIS_PERCHAR
;
if (dcmdebug
& DDB_INTSCHM
)
printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n",
brd
, perchar
, dis
->dis_perchar
,
dis
->dis_intr
, dis
->dis_char
);
if ((flags
& DIS_RESET
) == 0 && perchar
== dis
->dis_perchar
) {
printf("dcmsetischeme(%d): redundent request %d\n",
* If perchar is non-zero, we enable interrupts on all characters
* otherwise we disable perchar interrupts and use periodic
dis
->dis_perchar
= perchar
;
mask
= perchar
? 0xf : 0x0;
for (i
= 0; i
< 256; i
++)
dcm
->dcm_bmap
[i
].data_data
= mask
;
* Don't slow down tandem mode, interrupt on flow control
* chars for any port on the board.
register struct tty
*tp
= &dcm_tty
[MKUNIT(brd
, 0)];
for (i
= 0; i
< 4; i
++, tp
++) {
if ((c
= tp
->t_cc
[VSTART
]) != _POSIX_VDISABLE
)
dcm
->dcm_bmap
[c
].data_data
|= (1 << i
);
if ((c
= tp
->t_cc
[VSTOP
]) != _POSIX_VDISABLE
)
dcm
->dcm_bmap
[c
].data_data
|= (1 << i
);
* Board starts with timer disabled so if first call is to
* set perchar mode then we don't want to toggle the timer.
if (flags
== (DIS_RESET
|DIS_PERCHAR
))
* Toggle card 16.7ms interrupts (we first make sure that card
* has cleared the bit so it will see the toggle).
while (dcm
->dcm_cr
& CR_TIMER
)
* Following are all routines needed for DCM to act as console
#include "../hp300/cons.h"
register struct hp_hw
*hw
;
/* locate the major number */
for (dcmmajor
= 0; dcmmajor
< nchrdev
; dcmmajor
++)
if (cdevsw
[dcmmajor
].d_open
== dcmopen
)
* Implicitly assigns the lowest select code DCM card found to be
* logical unit 0 (actually CONUNIT). If your config file does
* anything different, you're screwed.
for (hw
= sc_table
; hw
->hw_type
; hw
++)
if (HW_ISDEV(hw
, D_COMMDCM
) && !badaddr((short *)hw
->hw_kva
))
if (!HW_ISDEV(hw
, D_COMMDCM
)) {
dcm_addr
[BOARD(CONUNIT
)] = (struct dcmdevice
*)hw
->hw_kva
;
/* initialize required fields */
cp
->cn_dev
= makedev(dcmmajor
, unit
);
cp
->cn_tp
= &dcm_tty
[unit
];
switch (dcm_addr
[BOARD(unit
)]->dcm_rsid
) {
* If dcmconsole is initialized, raise our priority.
if (dcmconsole
== UNIT(unit
))
* This doesn't currently work, at least not with ite consoles;
* the console hasn't been initialized yet.
if (major(kgdb_dev
) == dcmmajor
&& BOARD(kgdb_dev
) == BOARD(unit
)) {
(void) dcminit(kgdb_dev
, kgdb_rate
);
* We assume that console is ready for us...
* this assumes that a dca or ite console
* has been selected already and will init
printf("dcm%d: ", UNIT(kgdb_dev
));
dcminit(cp
->cn_dev
, dcmdefaultrate
);
dcmconsole
= UNIT(cp
->cn_dev
);
register struct dcmdevice
*dcm
= dcm_addr
[BOARD(dev
)];
mode
= LC_8BITS
| LC_1STOP
;
* Wait for transmitter buffer to empty.
while (dcm
->dcm_thead
[port
].ptr
!= dcm
->dcm_ttail
[port
].ptr
)
DELAY(DCM_USPERCH(rate
));
* Make changes known to hardware.
dcm
->dcm_data
[port
].dcm_baud
= ttspeedtab(rate
, dcmspeedtab
);
dcm
->dcm_data
[port
].dcm_conf
= mode
;
dcm
->dcm_cmdtab
[port
].dcm_data
|= CT_CON
;
dcm
->dcm_cr
|= (1 << port
);
* Delay for config change to take place. Weighted by baud.
DELAY(16 * DCM_USPERCH(rate
));
register struct dcmdevice
*dcm
= dcm_addr
[BOARD(dev
)];
register struct dcmrfifo
*fifo
;
register struct dcmpreg
*pp
;
pp
= dcm_preg(dcm
, port
);
head
= pp
->r_head
& RX_MASK
;
fifo
= &dcm
->dcm_rfifos
[3-port
][head
>>1];
while (head
== (pp
->r_tail
& RX_MASK
))
* If board interrupts are enabled, just let our received char
* interrupt through in case some other port on the board was
* busy. Otherwise we must clear the interrupt.
if ((dcm
->dcm_ic
& IC_IE
) == 0)
pp
->r_head
= (head
+ 2) & RX_MASK
;
* Console kernel output character routine.
register struct dcmdevice
*dcm
= dcm_addr
[BOARD(dev
)];
register struct dcmpreg
*pp
;
pp
= dcm_preg(dcm
, port
);
(void) dcminit(dev
, dcmdefaultrate
);
tail
= pp
->t_tail
& TX_MASK
;
while (tail
!= (pp
->t_head
& TX_MASK
))
dcm
->dcm_tfifos
[3-port
][tail
].data_char
= c
;
pp
->t_tail
= tail
= (tail
+ 1) & TX_MASK
;
dcm
->dcm_cmdtab
[port
].dcm_data
|= CT_TX
;
dcm
->dcm_cr
|= (1 << port
);
while (tail
!= (pp
->t_head
& TX_MASK
))
* If board interrupts are enabled, just let our completion
* interrupt through in case some other port on the board
* was busy. Otherwise we must clear the interrupt.
if ((dcm
->dcm_ic
& IC_IE
) == 0) {