* Copyright (c) 1988 Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)mp.c 7.12 (Berkeley) %G%
* Multi Protocol Communications Controller (MPCC).
* Asynchronous Terminal Protocol Support.
#include "machine/mtpr.h"
#include "../tahoevba/vbavar.h"
#include "../tahoevba/mpreg.h"
#define MPPORT(n) ((n) & 0xf)
#define MPUNIT(n) ((n) >> 4)
* Driver information for auto-configuration stuff.
int mpprobe(), mpattach(), mpintr();
struct vba_device
*mpinfo
[NMP
];
struct vba_driver mpdriver
=
{ mpprobe
, 0, mpattach
, 0, mpstd
, "mp", mpinfo
};
struct mpevent
*mpparam2();
struct mpevent
*mp_getevent();
* The following structure is needed to deal with mpcc's convoluted
* method for locating it's mblok structures (hold your stomach).
* When an mpcc is reset at boot time it searches host memory
* looking for a string that says ``ThIs Is MpCc''. The mpcc
* then reads the structure to locate the pointer to it's mblok
* structure (you can wretch now).
char s
[12]; /* `ThIs Is MpCc'' */
struct mblok
*mbloks
[NMP
]; /* can support at most 16 mpcc's */
} mpbogus
= { 'T','h','I','s',' ','I','s',' ','M','p','C','c' };
* Software state per unit.
u_int ms_ivec
; /* interrupt vector */
u_int ms_softCAR
; /* software carrier for async */
struct mblok
*ms_mb
; /* mpcc status area */
struct vb_buf ms_buf
; /* vba resources for ms_mb */
struct hxmtl ms_hxl
[MPMAXPORT
];/* host transmit list */
struct asyncparam ms_async
[MPMAXPORT
][MPINSET
];/* async structs */
char ms_cbuf
[MPMAXPORT
][MPOUTSET
][CBSIZE
];/* input character buffers */
9600, M9600
, /* baud rate = 9600 */
4800, M4800
, /* baud rate = 4800 */
2400, M2400
, /* baud rate = 2400 */
1800, M1800
, /* baud rate = 1800 */
1200, M1200
, /* baud rate = 1200 */
600, M600
, /* baud rate = 600 */
300, M300
, /* baud rate = 300 */
200, M200
, /* baud rate = 200 */
150, M150
, /* baud rate = 150 */
134, M134_5
, /* baud rate = 134.5 */
110, M110
, /* baud rate = 110 */
75, M75
, /* baud rate = 75 */
50, M50
, /* baud rate = 50 */
0, M0
, /* baud rate = 0 */
2000, M2000
, /* baud rate = 2000 */
3600, M3600
, /* baud rate = 3600 */
7200, M7200
, /* baud rate = 7200 */
19200, M19200
, /* baud rate = 19,200 */
24000, M24000
, /* baud rate = 24,000 */
28400, M28400
, /* baud rate = 28,400 */
37800, M37800
, /* baud rate = 37,800 */
40300, M40300
, /* baud rate = 40,300 */
48000, M48000
, /* baud rate = 48,000 */
52000, M52000
, /* baud rate = 52,000 */
56800, M56800
, /* baud rate = 56,800 */
EXTA
, MEXTA
, /* baud rate = Ext A */
EXTB
, MEXTB
, /* baud rate = Ext B */
struct tty mp_tty
[NMP
*MPCHUNK
];
register struct mpsoftc
*ms
;
br
= 0; cvec
= br
; br
= cvec
;
ms
= &mp_softc
[vi
->ui_unit
];
* Allocate page tables and mblok
* structure (mblok in non-cached memory).
if (vbainit(&ms
->ms_buf
, sizeof (struct mblok
), VB_32BIT
) == 0) {
printf("mp%d: vbainit failed\n", vi
->ui_unit
);
ms
->ms_mb
= (struct mblok
*)ms
->ms_buf
.vb_rawbuf
;
ms
->ms_ivec
= MPINTRBASE
+ 2*vi
->ui_unit
; /* XXX */
br
= 0x14, cvec
= ms
->ms_ivec
; /* XXX */
register struct vba_device
*vi
;
register struct mpsoftc
*ms
= &mp_softc
[vi
->ui_unit
];
ms
->ms_softCAR
= vi
->ui_flags
;
* Setup pointer to mblok, initialize bogus
* status block used by mpcc to locate the pointer
* and then poke the mpcc to get it to search host
* memory to find mblok pointer.
mpbogus
.mbloks
[vi
->ui_unit
] = (struct mblok
*)ms
->ms_buf
.vb_physbuf
;
*(short *)vi
->ui_addr
= 0x100; /* magic */
register struct mpsoftc
*ms
;
int error
, s
, port
, unit
, mpu
;
if (mpu
>= NMP
|| (vi
= mpinfo
[mpu
]) == 0 || vi
->ui_alive
== 0)
if (tp
->t_state
& TS_XCLUDE
&& u
.u_uid
!= 0)
if (ms
->ms_mb
->mb_proto
[port
] != MPPROTO_ASYNC
||
ms
->ms_mb
->mb_status
!= MP_OPOPEN
)
mp
= &ms
->ms_mb
->mb_port
[port
]; /* host mpcc struct */
* serialize open and close events
while ((mp
->mp_flags
& MP_PROGRESS
) || ((tp
->t_state
& TS_WOPEN
) &&
!(mode
&O_NONBLOCK
) && !(tp
->t_cflag
&CLOCAL
)))
if (error
= tsleep((caddr_t
)&tp
->t_canq
, TTIPRI
| PCATCH
,
tp
->t_addr
= (caddr_t
)ms
;
if ((tp
->t_state
& TS_ISOPEN
) == 0) {
tp
->t_ispeed
= TTYDEF_SPEED
;
tp
->t_ospeed
= TTYDEF_SPEED
;
tp
->t_iflag
= TTYDEF_IFLAG
;
tp
->t_oflag
= TTYDEF_OFLAG
;
tp
->t_lflag
= TTYDEF_LFLAG
;
tp
->t_cflag
= TTYDEF_CFLAG
;
* Initialize port state: init MPCC interface
* structures for port and setup modem control.
error
= mpportinit(ms
, mp
, port
);
ev
= mpparam2(tp
, &tp
->t_termios
);
mp
->mp_flags
|= MP_PROGRESS
;
mpcmd(ev
, EVCMD_OPEN
, 0, ms
->ms_mb
, port
);
while (mp
->mp_proto
!= MPPROTO_ASYNC
)
if (error
= tsleep((caddr_t
)&tp
->t_canq
,
TTIPRI
| PCATCH
, ttopen
, 0))
mp
->mp_flags
&= ~MP_PROGRESS
;
while ((mode
&O_NONBLOCK
) == 0 && (tp
->t_cflag
&CLOCAL
) == 0 &&
(tp
->t_state
& TS_CARR_ON
) == 0) {
if ((error
= tsleep((caddr_t
)&tp
->t_rawq
, TTIPRI
| PCATCH
,
* a mpclose() might have disabled port. if so restart
if (mp
->mp_proto
!= MPPROTO_ASYNC
)
error
= (*linesw
[tp
->t_line
].l_open
)(dev
,tp
);
* wakeup those processes waiting for the open to complete
wakeup((caddr_t
)&tp
->t_canq
);
tp
->t_state
&= ~TS_WOPEN
;
register struct mpport
*mp
;
register struct mpevent
*ev
;
int s
, port
, unit
, error
= 0;
mb
= mp_softc
[MPUNIT(unit
)].ms_mb
;
if (mp
->mp_flags
& MP_PROGRESS
) {
if (mp
->mp_flags
& MP_REMBSY
) {
mp
->mp_flags
&= ~MP_REMBSY
;
while (mp
->mp_flags
& MP_PROGRESS
)
if (error
= tsleep((caddr_t
)&tp
->t_canq
,
TTIPRI
| PCATCH
, ttclos
, 0)) {
mp
->mp_flags
|= MP_PROGRESS
;
(*linesw
[tp
->t_line
].l_close
)(tp
);
ev
= mp_getevent(mp
, unit
, 1);
mp
->mp_flags
&= ~MP_PROGRESS
;
if (tp
->t_state
& TS_HUPCLS
|| (tp
->t_state
& TS_ISOPEN
) == 0)
mpcmd(ev
, EVCMD_CLOSE
, 0, mb
, port
);
if (mp
->mp_flags
& MP_REMBSY
)
while (mp
->mp_flags
& MP_PROGRESS
&& error
== 0)
error
= tsleep((caddr_t
)&tp
->t_canq
, TTIPRI
| PCATCH
,
* Read from an mpcc port.
tp
= &mp_tty
[minor(dev
)];
return ((*linesw
[tp
->t_line
].l_read
)(tp
, uio
, flag
));
tp
= &mp_tty
[minor(dev
)];
return ((*linesw
[tp
->t_line
].l_write
)(tp
, uio
, flag
));
mpioctl(dev
, cmd
, data
, flag
)
register struct mpsoftc
*ms
;
register struct mpport
*mp
;
register struct mpevent
*ev
;
int s
, port
, error
, unit
;
ms
= &mp_softc
[MPUNIT(unit
)];
if (mp
->mp_proto
!= MPPROTO_ASYNC
)
error
= (*linesw
[tp
->t_line
].l_ioctl
)(tp
, cmd
, data
, flag
);
error
= ttioctl(tp
, cmd
, data
, flag
);
case TIOCSBRK
: /* send break */
case TIOCCBRK
: /* clear break */
while (mp
->mp_flags
& MP_IOCTL
) {
if (error
= tsleep((caddr_t
)&tp
->t_canq
,
TTIPRI
| PCATCH
, ttyout
, 0)) {
if (mp
->mp_proto
!= MPPROTO_ASYNC
) {
ev
= mp_getevent(mp
, unit
, 0);
mp
->mp_flags
|= MP_IOCTL
;
(cmd
== TIOCSBRK
? A_BRKON
: A_BRKOFF
), mb
, port
);
case TIOCSDTR
: /* set dtr control line */
case TIOCCDTR
: /* clear dtr control line */
register struct mpevent
*ev
;
int unit
= minor(tp
->t_dev
);
struct mpsoftc
*ms
= &mp_softc
[MPUNIT(unit
)];
struct mblok
*mb
= ms
->ms_mb
;
mpcmd(ev
, EVCMD_IOCTL
, A_CHGALL
, mb
, MPPORT(unit
));
register struct mpevent
*ev
;
register struct mpport
*mp
;
int unit
= minor(tp
->t_dev
);
register struct asyncparam
*asp
;
ms
= &mp_softc
[MPUNIT(unit
)];
ev
= mp_getevent(mp
, unit
, 0); /* XXX */
speedcode
= ttspeedtab(t
->c_ospeed
, mpspeedtab
);
if (ev
== 0 || speedcode
< 0) {
printf("mp mpunit %d port %d param2 failed ev: %x speed %d, wanted %d\n",
MPUNIT(unit
), port
, ev
, speedcode
, t
->c_ospeed
);
asp
= &ms
->ms_async
[port
][mp
->mp_on
?mp
->mp_on
-1:MPINSET
-1];
asp
->ap_xon
= t
->c_cc
[VSTART
];
asp
->ap_xoff
= t
->c_cc
[VSTOP
];
if (!(t
->c_iflag
&IXON
) || (asp
->ap_xon
== _POSIX_VDISABLE
) ||
(asp
->ap_xoff
== _POSIX_VDISABLE
))
asp
->ap_xany
= ((t
->c_iflag
& IXANY
) ? MPA_ENA
: MPA_DIS
);
if (t
->t_cflag
&CSIZE
) == CS8
) {
asp
->ap_parity
= MPPAR_NONE
;
if ((t
->c_flags
& (EVENP
|ODDP
)) == ODDP
) /* XXX */
asp
->ap_parity
= MPPAR_ODD
;
asp
->ap_parity
= MPPAR_EVEN
;
asp
->ap_loop
= MPA_DIS
; /* disable loopback */
asp
->ap_rtimer
= A_RCVTIM
; /* default receive timer */
tp
->t_state
|= TS_HUPCLS
;
setm(&asp
->ap_modem
, 0, DROP
);
seti(&asp
->ap_intena
, A_DCD
);
if (t
->c_ospeed
== EXTA
|| t
->c_ospeed
== EXTB
)
asp
->ap_baud
= speedcode
;
if (1 || ms
->ms_softCAR
& (1<<port
)) /* XXX HARDWIRE FOR NOW */
setm(&asp
->ap_modem
, A_DTR
, ASSERT
);
setm(&asp
->ap_modem
, A_DTR
, AUTO
);
seti(&asp
->ap_intena
, A_DCD
);
register struct mpevent
*ev
;
register struct mpport
*mp
;
int port
, unit
, xcnt
, n
, s
, i
;
ms
= &mp_softc
[MPUNIT(unit
)];
for (i
= 0; i
< MPXMIT
; i
++) {
if (tp
->t_state
& (TS_TIMEOUT
|TS_BUSY
|TS_TTSTOP
))
if (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 we're not currently busy outputting,
* and there is data to be output, set up
* port transmit structure to send to mpcc.
if (1) /* || tp->t_flags & (RAW|LITOUT)) XXX FIX */
timeout(ttrstrt
, (caddr_t
)tp
, (n
&0177)+6);
tp
->t_state
|= TS_TIMEOUT
;
hxp
->dblock
[i
] = (caddr_t
)kvtophys(outq
.c_cf
);
xcnt
++; /* count of xmts to send */
* If data to send, poke mpcc.
ev
= mp_getevent(mp
, unit
, 0);
tp
->t_state
&= ~(TS_BUSY
|TS_TIMEOUT
);
mpcmd(ev
, EVCMD_WRITE
, 0, mb
, MPPORT(unit
));
* Advance cc bytes from q but don't free memory.
register struct clist
*q
;
register struct cblock
*bp
;
while (cc
>0 && q
->c_cc
) {
bp
= (struct cblock
*)((int)q
->c_cf
& ~CROUND
);
if ((int)bp
== (((int)q
->c_cl
-1) & ~CROUND
)) {
end
= (char *)((int)bp
+ sizeof (struct cblock
));
q
->c_cf
= bp
->c_next
->c_info
;
q
->c_cf
= q
->c_cl
= NULL
;
* Stop output on a line, e.g. for ^S/^Q or output flush.
register struct mpport
*mp
;
register struct mpevent
*ev
;
int unit
= minor(tp
->t_dev
);
if (tp
->t_state
& TS_BUSY
) {
if ((tp
->t_state
& TS_TTSTOP
) == 0) {
mb
= mp_softc
[MPUNIT(unit
)].ms_mb
;
ev
= mp_getevent(mp
, unit
, 0);
mpcmd(ev
, EVCMD_WRITE
, A_FLUSH
, mb
, port
);
* Initialize an async port's MPCC state.
register struct mpsoftc
*ms
;
register struct mpport
*mp
;
register struct mpevent
*ev
;
mp
->mp_on
= mp
->mp_off
= 0;
for (i
= 0; ev
< &mp
->mp_recvq
[MPINSET
]; ev
++, i
++) {
ev
->ev_status
= EVSTATUS_FREE
;
ev
->ev_un
.hxl
= (struct hxmtl
*) kvtophys(&ms
->ms_hxl
[port
]);
ev
->ev_params
= (caddr_t
) kvtophys(&ms
->ms_async
[port
][i
]);
for (i
= 0; ev
< &mp
->mp_sendq
[MPOUTSET
]; ev
++, i
++) {
/* init so that L2 can't send any events */
/* to host until open has completed */
ev
->ev_status
= EVSTATUS_FREE
;
ptr
= (caddr_t
) &ms
->ms_cbuf
[port
][i
][0];
ev
->ev_un
.rcvblk
= (u_char
*)kvtophys(ptr
);
ev
->ev_params
= (caddr_t
) kvtophys(ptr
);
* Send an event to an mpcc.
mpcmd(ev
, cmd
, flags
, mb
, port
)
register struct mpevent
*ev
;
/* move host values to inbound entry */
/* show event ready for mpcc */
ev
->ev_status
= EVSTATUS_GO
;
* Return the next available event entry for the indicated port.
mp_getevent(mp
, unit
, cls_req
)
register struct mpport
*mp
;
register struct mpevent
*ev
;
ev
= &mp
->mp_recvq
[mp
->mp_on
];
if (ev
->ev_status
!= EVSTATUS_FREE
)
* If not a close request, verify one extra
* event is available for closing the port.
if ((i
= mp
->mp_on
+ 1) >= MPINSET
)
if (mp
->mp_recvq
[i
].ev_status
!= EVSTATUS_FREE
)
/* init inbound fields marking this entry as busy */
ev
->ev_status
= EVSTATUS_BUSY
;
/* adjust pointer to next available inbound entry */
adjptr(mp
->mp_on
, MPINSET
);
log(LOG_ERR
, "mp%d: port%d, out of events\n",
MPUNIT(unit
), MPPORT(unit
));
return ((struct mpevent
*)0);
struct mpsoftc
*ms
= &mp_softc
[MPUNIT(unit
)];
register struct mpport
*mp
;
register struct asyncparam
*asp
;
mp
= &ms
->ms_mb
->mb_port
[port
];
asp
= &ms
->ms_async
[port
][mp
->mp_on
?mp
->mp_on
-1:MPINSET
-1];
if (1 || ms
->ms_softCAR
& (1 << port
))/* XXX HARDWIRE FOR NOW */
setm(&asp
->ap_modem
, A_DTR
, ASSERT
);
setm(&asp
->ap_modem
, A_DTR
, AUTO
);
seti(&asp
->ap_intena
, A_DCD
);
setm(&asp
->ap_modem
, 0, DROP
);
seti(&asp
->ap_intena
, 0);
* Set up the modem control structure according to mask.
* Each set bit in the mask means assert the corresponding
* modem control line, otherwise, it will be dropped.
* RTS is special since it can either be asserted, dropped
* or put in auto mode for auto modem control.
register struct mdmctl
*mc
;
mc
->mc_rngdsr
= (mask
& A_RNGDSR
) ? ASSERT
: DROP
;
mc
->mc_rate
= (mask
& A_RATE
) ? ASSERT
: DROP
;
mc
->mc_dcd
= (mask
& A_DCD
) ? ASSERT
: DROP
;
mc
->mc_sectx
= (mask
& A_SECTX
) ? ASSERT
: DROP
;
mc
->mc_cts
= (mask
& A_CTS
) ? ASSERT
: DROP
;
mc
->mc_secrx
= (mask
& A_SECRX
) ? ASSERT
: DROP
;
mc
->mc_dtr
= (mask
& A_DTR
) ? ASSERT
: DROP
;
* Set up the status change enable field from mask.
* When a signal is enabled in this structure and
* and a change in state on a corresponding modem
* control line occurs, a status change event will
* be delivered to the host.
register struct mdmctl
*mc
;
mc
->mc_rngdsr
= (mask
& A_RNGDSR
) ? MDM_ON
: MDM_OFF
;
mc
->mc_rate
= (mask
& A_RATE
) ? MDM_ON
: MDM_OFF
;
mc
->mc_dcd
= (mask
& A_DCD
) ? MDM_ON
: MDM_OFF
;
mc
->mc_sectx
= (mask
& A_SECTX
) ? MDM_ON
: MDM_OFF
;
mc
->mc_cts
= (mask
& A_CTS
) ? MDM_ON
: MDM_OFF
;
mc
->mc_secrx
= (mask
& A_SECRX
) ? MDM_ON
: MDM_OFF
;
mc
->mc_dtr
= (mask
& A_DTR
) ? MDM_ON
: MDM_OFF
;
mc
->mc_rts
= (mask
& A_RTS
) ? MDM_ON
: MDM_OFF
;
register struct mpport
*mp
;
if (mp
->mp_proto
== MPPROTO_ASYNC
) {
mp
->mp_flags
= MP_REMBSY
;
/* signal loss of carrier and close */
tp
= &mp_tty
[mb
->mb_unit
*MPCHUNK
+port
];
ttyflush(tp
, FREAD
|FWRITE
);
(void) (*linesw
[tp
->t_line
].l_modem
)(tp
, 0);
register struct mblok
*mb
;
register struct mpport
*mp
;
register struct mpevent
*ev
;
for (i
= mp
->mp_off
; i
!= mp
->mp_on
; i
= (i
+1 % MPINSET
)) {
ev
->ev_status
= EVSTATUS_DONE
;
list
[0] = port
, list
[1] = MPPORT_EOL
;
/* Clear async for port */
mp
->mp_proto
= MPPROTO_UNUSED
;
mp_tty
[unit
*MPCHUNK
+ port
].t_state
= 0;
for (ev
= &mp
->mp_sendq
[0]; ev
< &mp
->mp_sendq
[MPOUTSET
]; ev
++) {
ev
->ev_status
= EVSTATUS_FREE
;
for (ev
= &mp
->mp_recvq
[0]; ev
< &mp
->mp_recvq
[MPINSET
]; ev
++) {
ev
->ev_status
= EVSTATUS_FREE
;
* MPCC interrupt handler.
register struct mblok
*mb
;
register struct his
*his
;
mb
= mp_softc
[mpcc
].ms_mb
;
printf("mp%d: stray interrupt\n", mpcc
);
his
->semaphore
&= ~MPSEMA_AVAILABLE
;
* Check for events to be processed.
if (his
->proto
[MPPROTO_ASYNC
].outbdone
[0] != MPPORT_EOL
)
mprintr(mpcc
, his
->proto
[MPPROTO_ASYNC
].outbdone
);
if (his
->proto
[MPPROTO_ASYNC
].inbdone
[0] != MPPORT_EOL
)
mpxintr(mpcc
, his
->proto
[MPPROTO_ASYNC
].inbdone
);
if (mb
->mb_harderr
|| mb
->mb_softerr
)
his
->semaphore
|= MPSEMA_AVAILABLE
;
* Handler for processing completion of transmitted events.
register struct mpport
*mp
;
register struct mpevent
*ev
;
register struct mblok
*mb
;
register struct asyncparam
*ap
;
# define nextevent(mp) &mp->mp_recvq[mp->mp_off]
mb
= mp_softc
[unit
].ms_mb
;
for (j
= 0; j
< MPMAXPORT
&& ((port
= *list
++) != MPPORT_EOL
); j
++) {
* Process each completed entry in the inbound queue.
tp
= &mp_tty
[unit
*MPCHUNK
+ port
];
for (; ev
->ev_status
& EVSTATUS_DONE
; ev
= nextevent(mp
)) {
ap
= &ms
->ms_async
[port
][mp
->mp_off
];
mppurge((caddr_t
)ap
, (int)sizeof (*ap
));
* Open completion, start all reads and
* assert modem status information.
for (i
= 0; i
< MPOUTSET
; i
++)
mp
->mp_sendq
[i
].ev_status
= EVSTATUS_GO
;
(*linesw
[tp
->t_line
].l_modem
)
(tp
, ap
->ap_modem
.mc_dcd
== ASSERT
);
adjptr(mp
->mp_off
, MPINSET
);
mp
->mp_proto
= MPPROTO_ASYNC
; /* XXX */
wakeup((caddr_t
)&tp
->t_canq
);
* Close completion, flush all pending
* transmissions, free resources, and
* cleanup mpcc port state.
for (i
= 0; i
< MPOUTSET
; i
++) {
mp
->mp_sendq
[i
].ev_status
=
mp
->mp_sendq
[i
].ev_un
.rcvblk
= 0;
mp
->mp_sendq
[i
].ev_params
= 0;
adjptr(mp
->mp_off
, MPINSET
);
tp
->t_state
&= ~(TS_CARR_ON
|TS_BUSY
|TS_FLUSH
);
mp
->mp_on
= mp
->mp_off
= mp
->mp_nextrcv
= 0;
mp
->mp_flags
&= ~MP_PROGRESS
;
mp
->mp_proto
= MPPROTO_UNUSED
;
wakeup((caddr_t
)&tp
->t_canq
);
adjptr(mp
->mp_off
, MPINSET
);
mp
->mp_flags
&= ~MP_IOCTL
;
wakeup((caddr_t
)&tp
->t_canq
);
* Transmission completed, update tty
* state and restart output.
if (ev
->ev_opts
!= A_FLUSH
) {
if (tp
->t_state
& TS_FLUSH
)
tp
->t_state
&= ~TS_FLUSH
;
for (n
=0;n
< ev
->ev_count
; n
++)
ndflush(&tp
->t_outq
, cc
);
case A_SIZERR
: /*# error in xmt data size */
mplog(unit
, port
, A_XSIZE
, 0);
case A_NXBERR
: /*# no more xmt evt buffers */
mplog(unit
, port
, A_NOXBUF
, 0);
adjptr(mp
->mp_off
, MPINSET
);
mplog(unit
, port
, A_INVCMD
, (int)ev
->ev_cmd
);
adjptr(mp
->mp_off
, MPINSET
);
register struct mpevent
*ev
;
/* re-init all values in this entry */
/* show this entry is available for use */
ev
->ev_status
= EVSTATUS_FREE
;
* Handler for processing received events.
register struct mpport
*mp
;
register struct mpevent
*ev
;
mb
= mp_softc
[unit
].ms_mb
;
for (i
= 0; i
< MPMAXPORT
&& (port
= *list
++) != MPPORT_EOL
; i
++) {
tp
= &mp_tty
[unit
*MPCHUNK
+ port
];
ev
= &mp
->mp_sendq
[mp
->mp_nextrcv
];
while (ev
->ev_status
& EVSTATUS_DONE
) {
* Status change, look for carrier changes.
(*linesw
[tp
->t_line
].l_modem
)(tp
, 1);
wakeup((caddr_t
)&tp
->t_canq
);
(*linesw
[tp
->t_line
].l_modem
)(tp
, 0);
wakeup((caddr_t
)&tp
->t_canq
);
"out of receive events", 0);
"unexpect status command",
if ((tp
->t_state
& TS_ISOPEN
) == 0) {
wakeup((caddr_t
)&tp
->t_rawq
);
if ((cc
= ev
->ev_count
) == 0)
cp
= ms
->ms_cbuf
[port
][mp
->mp_nextrcv
];
* A null character is inserted,
* potentially when a break or framing
* error occurs. If we're not in raw
* mode, substitute the interrupt
(ev
->ev_error
== BRKASRT
||
ev
->ev_error
== FRAMERR
))
if ((tp
->t_flags
&RAW
) == 0)
(*linesw
[tp
->t_line
].l_rint
)(*cp
++, tp
);
/* setup for next read */
ptr
= (caddr_t
)&mp_softc
[unit
].ms_cbuf
[port
][mp
->mp_nextrcv
][0];
ev
->ev_un
.rcvblk
= (u_char
*)kvtophys(ptr
);
ev
->ev_params
= (caddr_t
) kvtophys(ptr
);
/* Normal (good) rcv data do not
* report the following they are
rcverr
= "overrun error";
rcverr
= "overflow error";
rcverr
= "undefined rcv error";
mplog(unit
, port
, rcverr
,
mplog(unit
, port
, "unexpected command",
ev
->ev_status
= EVSTATUS_GO
; /* start next read */
adjptr(mp
->mp_nextrcv
, MPOUTSET
);
ev
= &mp
->mp_sendq
[mp
->mp_nextrcv
];
* Log an mpcc diagnostic.
mplog(unit
, port
, cp
, flags
)
log(LOG_ERR
, "mp%d: port%d, %s (%d)\n",
log(LOG_ERR
, "mp%d: port%d, %s\n", unit
, port
, cp
);
register struct mblok
*mb
;
mb
->mb_mpintclk
= (caddr_t
)0;
*(u_short
*)mpinfo
[mb
->mb_unit
]->ui_addr
= 2;
register struct mblok
*mb
;
mb
->mb_intr
[port
] |= MPSEMA_WORK
;
if (++mb
->mb_mpintcnt
== MPHOSTINT
) {
*(u_short
*)mpinfo
[mb
->mb_unit
]->ui_addr
= 2;
untimeout(mptimeint
, (caddr_t
)mb
);
if (mb
->mb_mpintclk
== 0) {
timeout(mptimeint
, (caddr_t
)mb
, 4);
mb
->mb_mpintclk
= (caddr_t
)1;
static char *mpherrmsg
[] = {
"Bus error", /* MPBUSERR */
"Address error", /* ADDRERR */
"Undefined ecc interrupt", /* UNDECC */
"Undefined interrupt", /* UNDINT */
"Power failure occurred", /* PWRFL */
"Stray transmit done interrupt", /* NOXENTRY */
"Two fast timers on one port", /* TWOFTMRS */
"Interrupt queue full", /* INTQFULL */
"Interrupt queue ack error", /* INTQERR */
"Uncorrectable dma parity error", /* CBPERR */
"32 port ACAP failed power up", /* ACPDEAD */
#define NHERRS (sizeof (mpherrmsg) / sizeof (mpherrmsg[0]))
register struct mblok
*mb
;
switch (mb
->mb_softerr
) {
case DMAPERR
: /* dma parity error */
cp
= "local memory ecc error";
log(LOG_ERR
, "mp%d: soft error, %s", unit
, cp
);
if (mb
->mb_harderr
< NHERRS
)
cp
= mpherrmsg
[mb
->mb_harderr
];
log(LOG_ERR
, "mp%d: hard error, %s", unit
, cp
);
if (mb
->mb_status
== MP_OPOPEN
) {
for (i
= 0; i
< MPMAXPORT
; i
++) {
mb
->mb_proto
[i
] = MPPROTO_UNUSED
;
for (; cc
>= 0; addr
+= NBPG
, cc
-= NBPG
)
* MPCC Download Pseudo-device.
char mpdlbuf
[MPDLBUFSIZE
];
int mpdlbusy
; /* interlock on download buffer */
if (mpu
>= NMP
|| (vi
= mpinfo
[mpu
]) == 0 || vi
->ui_alive
== 0)
register struct mpsoftc
*ms
= &mp_softc
[MPUNIT(minor(dev
))];
register struct mpdl
*dl
;
if (ms
->ms_mb
== 0 || ms
->ms_mb
->mb_status
!= MP_DLOPEN
)
dl
->mpdl_count
= uio
->uio_iov
->iov_len
;
dl
->mpdl_data
= (caddr_t
) kvtophys(mpdlbuf
);
if (error
= uiomove(mpdlbuf
, (int)dl
->mpdl_count
, uio
))
uio
->uio_resid
-= dl
->mpdl_count
; /* set up return from write */
dl
->mpdl_cmd
= MPDLCMD_NORMAL
;
register struct mblok
*mb
= mp_softc
[MPUNIT(minor(dev
))].ms_mb
;
if (mb
== 0 || mb
->mb_status
!= MP_DLDONE
) {
if (mpbogus
.mb
== mpbogus
.mbloks
[MPUNIT(minor(dev
))])
mb
->mb_status
= MP_OPOPEN
;
/* set to dead, for board handshake */
mb
->mb_hostint
.imok
= MPIMOK_DEAD
;
mpdlioctl(dev
, cmd
, data
, flag
)
register struct mblok
*mb
;
register struct mpdl
*dl
;
int unit
, error
= 0, s
, i
;
mb
= mp_softc
[unit
=MPUNIT(minor(dev
))].ms_mb
;
bcopy(data
, (caddr_t
)mb
->mb_proto
, sizeof (mb
->mb_proto
));
bcopy(data
, (caddr_t
)&mb
->mb_hiport
, 2*(sizeof(mb
->mb_hiport
)));
dl
->mpdl_cmd
= MPIOENDDL
&IOCPARM_MASK
;
mb
->mb_status
= MP_DLDONE
;
dl
->mpdl_cmd
= MPIOENDCODE
&IOCPARM_MASK
;
bcopy(data
, mpdlbuf
, sizeof (struct abdcf
));
dl
->mpdl_data
= (caddr_t
) kvtophys(mpdlbuf
);
dl
->mpdl_count
= sizeof (struct abdcf
);
dl
->mpdl_cmd
= MPIOASYNCNF
&IOCPARM_MASK
;
if (error
= tsleep((caddr_t
)&mpdlbusy
,
(PZERO
+1) | PCATCH
, devioc
, 0))
/* initialize the downloading interface */
mpbogus
.mb
= mpbogus
.mbloks
[unit
];
dl
->mpdl_status
= EVSTATUS_FREE
;
dl
->mpdl_data
= (char *) 0;
mb
->mb_ivec
= mp_softc
[unit
].ms_ivec
+1; /* download vector */
mb
->mb_status
= MP_DLPEND
;
mb
->mb_diagswitch
[0] = 'A';
mb
->mb_diagswitch
[1] = 'P';
*(u_short
*)mpinfo
[unit
]->ui_addr
= 2;
error
= tsleep((caddr_t
)&mb
->mb_status
, (PZERO
+1) | PCATCH
,
if (error
== EWOULDBLOCK
)
bzero((caddr_t
)mb
->mb_port
, sizeof (mb
->mb_port
));
*(u_short
*)mpinfo
[unit
]->ui_addr
= 0x100;
if (mb
->mb_status
== MP_DLOPEN
|| mb
->mb_status
== MP_DLDONE
) {
dl
->mpdl_status
= EVSTATUS_FREE
;
wakeup((caddr_t
)&dl
->mpdl_status
);
for (i
= 0; i
< MPMAXPORT
; i
++) {
if (mb
->mb_harderr
|| mb
->mb_softerr
)
mb
->mb_proto
[i
] = MPPROTO_UNUSED
;
register struct mblok
*mb
= mp_softc
[unit
].ms_mb
;
register struct his
*his
;
mb
->mb_status
= MP_DLDONE
;
mb
->mb_ivec
= mp_softc
[unit
].ms_ivec
;
/* Init host interface structure */
his
->semaphore
= MPSEMA_AVAILABLE
;
for (i
= 0; i
< NMPPROTO
; i
++)
for (j
= 0; j
< MPMAXPORT
; j
++) {
his
->proto
[i
].inbdone
[j
] = MPPORT_EOL
;
his
->proto
[i
].outbdone
[j
] = MPPORT_EOL
;
register struct mblok
*mb
;
register struct mpdl
*dl
;
mb
= mp_softc
[mpcc
].ms_mb
;
printf("mp%d: stray download interrupt\n", mpcc
);
if (dl
->mpdl_status
!= EVSTATUS_DONE
)
dl
->mpdl_status
= EVSTATUS_FREE
;
wakeup((caddr_t
)&dl
->mpdl_status
);
mb
->mb_status
= MP_DLOPEN
;
wakeup((caddr_t
)&mb
->mb_status
);
mb
->mb_nointcnt
= 0; /* reset no interrupt count */
mb
->mb_hostint
.imok
= MPIMOK_DEAD
;
mb
->mb_imokclk
= (caddr_t
)1;
log(LOG_ERR
, "mp%d: mpdlintr, status %x\n",
* Wait for a transfer to complete or a timeout to occur.
register struct mpdl
*dl
;
dl
->mpdl_status
= EVSTATUS_GO
;
while (dl
->mpdl_status
!= EVSTATUS_FREE
) {
error
= tsleep((caddr_t
)&dl
->mpdl_status
, (PZERO
+1) | PCATCH
,
if (mpdlerr
== MP_DLERROR
)