1994-12-02 23:23:01 +00:00
|
|
|
/*
|
|
|
|
* Cronyx-Sigma adapter driver for FreeBSD.
|
|
|
|
* Supports PPP/HDLC protocol in synchronous mode,
|
|
|
|
* and asyncronous channels with full modem control.
|
|
|
|
*
|
|
|
|
* Copyright (C) 1994 Cronyx Ltd.
|
|
|
|
* Author: Serge Vakulenko, <vak@zebub.msk.su>
|
|
|
|
*
|
|
|
|
* This software is distributed with NO WARRANTIES, not even the implied
|
|
|
|
* warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
*
|
|
|
|
* Authors grant any other persons or organisations permission to use
|
|
|
|
* or modify this software as long as this message is kept with the software,
|
|
|
|
* all derivative works or modified versions.
|
|
|
|
*
|
1995-10-04 22:24:16 +00:00
|
|
|
* Version 1.9, Wed Oct 4 18:58:15 MSK 1995
|
1999-09-25 16:21:39 +00:00
|
|
|
*
|
|
|
|
* $FreeBSD$
|
|
|
|
*
|
1994-12-02 23:23:01 +00:00
|
|
|
*/
|
|
|
|
#undef DEBUG
|
|
|
|
|
|
|
|
#include "cx.h"
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
1994-12-04 08:51:58 +00:00
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
1997-03-23 03:37:54 +00:00
|
|
|
#include <sys/fcntl.h>
|
1994-12-02 23:23:01 +00:00
|
|
|
#include <sys/conf.h>
|
|
|
|
#include <sys/tty.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <net/if.h>
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
# if __FreeBSD__ < 2
|
1994-12-04 08:51:58 +00:00
|
|
|
# include <machine/pio.h>
|
1994-12-02 23:23:01 +00:00
|
|
|
# define RB_GETC(q) getc(q)
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
#ifdef __bsdi__
|
|
|
|
# include <sys/ttystats.h>
|
1994-12-04 08:51:58 +00:00
|
|
|
# include <machine/inline.h>
|
1994-12-02 23:23:01 +00:00
|
|
|
# define tsleep(tp,pri,msg,x) ((tp)->t_state |= TS_WOPEN,\
|
|
|
|
ttysleep (tp, (caddr_t)&tp->t_rawq, pri, msg, x))
|
|
|
|
#endif
|
|
|
|
#if !defined (__FreeBSD__) || __FreeBSD__ >= 2
|
|
|
|
# define t_out t_outq
|
|
|
|
# define RB_LEN(q) ((q).c_cc)
|
|
|
|
# define RB_GETC(q) getc(&q)
|
1995-10-07 20:07:18 +00:00
|
|
|
#ifndef TSA_CARR_ON /* FreeBSD 2.x before not long after 2.0.5 */
|
1994-12-02 23:23:01 +00:00
|
|
|
# define TSA_CARR_ON(tp) tp
|
|
|
|
# define TSA_OLOWAT(q) ((caddr_t)&(q)->t_out)
|
|
|
|
#endif
|
1995-10-07 20:07:18 +00:00
|
|
|
#endif
|
1994-12-02 23:23:01 +00:00
|
|
|
|
1994-12-04 08:51:58 +00:00
|
|
|
#include <machine/cronyx.h>
|
1994-12-02 23:23:01 +00:00
|
|
|
#include <i386/isa/cxreg.h>
|
|
|
|
|
1995-12-15 00:54:32 +00:00
|
|
|
/* XXX imported from if_cx.c. */
|
|
|
|
void cxswitch (cx_chan_t *c, cx_soft_opt_t new);
|
|
|
|
|
|
|
|
/* XXX exported. */
|
|
|
|
void cxmint (cx_chan_t *c);
|
|
|
|
int cxrinta (cx_chan_t *c);
|
|
|
|
void cxtinta (cx_chan_t *c);
|
|
|
|
timeout_t cxtimeout;
|
1995-12-10 21:08:11 +00:00
|
|
|
|
1994-12-02 23:23:01 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
# define print(s) printf s
|
|
|
|
#else
|
1995-10-04 22:24:16 +00:00
|
|
|
# define print(s) {/*void*/}
|
1994-12-02 23:23:01 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#define DMABUFSZ (6*256) /* buffer size */
|
|
|
|
#define BYTE *(unsigned char*)&
|
1999-05-08 07:02:41 +00:00
|
|
|
#define UNIT(u) (minor(u) & 077)
|
1994-12-02 23:23:01 +00:00
|
|
|
#define UNIT_CTL 077
|
|
|
|
|
|
|
|
extern cx_board_t cxboard [NCX]; /* adapter state structures */
|
|
|
|
extern cx_chan_t *cxchan [NCX*NCHAN]; /* unit to channel struct pointer */
|
|
|
|
#if __FreeBSD__ >= 2
|
1995-12-10 13:40:44 +00:00
|
|
|
static struct tty cx_tty [NCX*NCHAN]; /* tty data */
|
1995-12-08 11:19:42 +00:00
|
|
|
|
|
|
|
static d_open_t cxopen;
|
|
|
|
static d_close_t cxclose;
|
|
|
|
static d_ioctl_t cxioctl;
|
|
|
|
|
1998-08-23 08:26:42 +00:00
|
|
|
#define CDEV_MAJOR 42
|
|
|
|
/* Don't make this static, since if_cx.c uses it. */
|
1999-05-30 16:53:49 +00:00
|
|
|
struct cdevsw cx_cdevsw = {
|
|
|
|
/* open */ cxopen,
|
|
|
|
/* close */ cxclose,
|
1999-09-28 11:45:31 +00:00
|
|
|
/* read */ ttyread,
|
|
|
|
/* write */ ttywrite,
|
1999-05-30 16:53:49 +00:00
|
|
|
/* ioctl */ cxioctl,
|
1999-09-25 16:21:39 +00:00
|
|
|
/* poll */ ttypoll,
|
1999-05-30 16:53:49 +00:00
|
|
|
/* mmap */ nommap,
|
|
|
|
/* strategy */ nostrategy,
|
|
|
|
/* name */ "cx",
|
|
|
|
/* maj */ CDEV_MAJOR,
|
|
|
|
/* dump */ nodump,
|
|
|
|
/* psize */ nopsize,
|
2001-02-15 16:34:11 +00:00
|
|
|
/* flags */ D_TTY | D_KQFILTER,
|
|
|
|
/* kqfilter */ ttykqfilter,
|
1998-08-23 08:26:42 +00:00
|
|
|
};
|
1994-12-02 23:23:01 +00:00
|
|
|
#else
|
|
|
|
struct tty *cx_tty [NCX*NCHAN]; /* tty data */
|
|
|
|
#endif
|
|
|
|
|
1995-12-10 13:40:44 +00:00
|
|
|
static void cxoproc (struct tty *tp);
|
1999-09-25 16:21:39 +00:00
|
|
|
static void cxstop (struct tty *tp, int flag);
|
1995-12-10 13:40:44 +00:00
|
|
|
static int cxparam (struct tty *tp, struct termios *t);
|
1994-12-02 23:23:01 +00:00
|
|
|
|
2001-09-12 08:38:13 +00:00
|
|
|
int cxopen (dev_t dev, int flag, int mode, struct thread *td)
|
1994-12-02 23:23:01 +00:00
|
|
|
{
|
|
|
|
int unit = UNIT (dev);
|
|
|
|
cx_chan_t *c = cxchan[unit];
|
|
|
|
unsigned short port;
|
|
|
|
struct tty *tp;
|
|
|
|
int error = 0;
|
1995-05-30 08:16:23 +00:00
|
|
|
|
1994-12-02 23:23:01 +00:00
|
|
|
if (unit == UNIT_CTL) {
|
|
|
|
print (("cx: cxopen /dev/cronyx\n"));
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
if (unit >= NCX*NCHAN || !c || c->type==T_NONE)
|
|
|
|
return (ENXIO);
|
|
|
|
port = c->chip->port;
|
|
|
|
print (("cx%d.%d: cxopen unit=%d\n", c->board->num, c->num, unit));
|
|
|
|
if (c->mode != M_ASYNC)
|
|
|
|
return (EBUSY);
|
|
|
|
if (! c->ttyp) {
|
1995-10-04 22:24:16 +00:00
|
|
|
#ifdef __FreeBSD__
|
1994-12-02 23:23:01 +00:00
|
|
|
#if __FreeBSD__ >= 2
|
|
|
|
c->ttyp = &cx_tty[unit];
|
1995-10-04 22:24:16 +00:00
|
|
|
#else
|
|
|
|
c->ttyp = cx_tty[unit] = ttymalloc (cx_tty[unit]);
|
|
|
|
#endif
|
1994-12-02 23:23:01 +00:00
|
|
|
#else
|
|
|
|
MALLOC (cx_tty[unit], struct tty*, sizeof (struct tty), M_DEVBUF, M_WAITOK);
|
|
|
|
bzero (cx_tty[unit], sizeof (*cx_tty[unit]));
|
|
|
|
c->ttyp = cx_tty[unit];
|
|
|
|
#endif
|
1995-11-18 07:07:04 +00:00
|
|
|
c->ttyp->t_oproc = cxoproc;
|
1999-09-25 16:21:39 +00:00
|
|
|
c->ttyp->t_stop = cxstop;
|
1994-12-02 23:23:01 +00:00
|
|
|
c->ttyp->t_param = cxparam;
|
|
|
|
}
|
1999-09-25 16:21:39 +00:00
|
|
|
dev->si_tty = c->ttyp;
|
1994-12-02 23:23:01 +00:00
|
|
|
#ifdef __bsdi__
|
|
|
|
if (! c->ttydev) {
|
|
|
|
MALLOC (c->ttydev, struct ttydevice_tmp*,
|
|
|
|
sizeof (struct ttydevice_tmp), M_DEVBUF, M_WAITOK);
|
|
|
|
bzero (c->ttydev, sizeof (*c->ttydev));
|
|
|
|
strcpy (c->ttydev->tty_name, "cx");
|
|
|
|
c->ttydev->tty_unit = unit;
|
|
|
|
c->ttydev->tty_base = unit;
|
|
|
|
c->ttydev->tty_count = 1;
|
|
|
|
c->ttydev->tty_ttys = c->ttyp;
|
|
|
|
tty_attach (c->ttydev);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
tp = c->ttyp;
|
|
|
|
tp->t_dev = dev;
|
|
|
|
if ((tp->t_state & TS_ISOPEN) && (tp->t_state & TS_XCLUDE) &&
|
2002-04-01 21:31:13 +00:00
|
|
|
suser(td))
|
1994-12-02 23:23:01 +00:00
|
|
|
return (EBUSY);
|
|
|
|
if (! (tp->t_state & TS_ISOPEN)) {
|
|
|
|
ttychars (tp);
|
|
|
|
if (tp->t_ispeed == 0) {
|
|
|
|
#ifdef __bsdi__
|
|
|
|
tp->t_termios = deftermios;
|
|
|
|
#else
|
|
|
|
tp->t_iflag = 0;
|
|
|
|
tp->t_oflag = 0;
|
|
|
|
tp->t_lflag = 0;
|
|
|
|
tp->t_cflag = CREAD | CS8 | HUPCL;
|
|
|
|
tp->t_ispeed = c->rxbaud;
|
|
|
|
tp->t_ospeed = c->txbaud;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
cxparam (tp, &tp->t_termios);
|
|
|
|
ttsetwater (tp);
|
|
|
|
}
|
|
|
|
|
|
|
|
spltty ();
|
|
|
|
if (! (tp->t_state & TS_ISOPEN)) {
|
|
|
|
/*
|
|
|
|
* Compute optimal receiver buffer length.
|
|
|
|
* The best choice is rxbaud/400.
|
|
|
|
* Make it even, to avoid byte-wide DMA transfers.
|
|
|
|
* --------------------------
|
|
|
|
* Baud rate Buffer length
|
|
|
|
* --------------------------
|
|
|
|
* 300 4
|
|
|
|
* 1200 4
|
|
|
|
* 9600 24
|
|
|
|
* 19200 48
|
|
|
|
* 38400 96
|
|
|
|
* 57600 192
|
|
|
|
* 115200 288
|
|
|
|
* --------------------------
|
|
|
|
*/
|
|
|
|
int rbsz = (c->rxbaud + 800 - 1) / 800 * 2;
|
|
|
|
if (rbsz < 4)
|
|
|
|
rbsz = 4;
|
|
|
|
else if (rbsz > DMABUFSZ)
|
|
|
|
rbsz = DMABUFSZ;
|
|
|
|
|
|
|
|
/* Initialize channel, enable receiver. */
|
|
|
|
cx_cmd (port, CCR_INITCH | CCR_ENRX);
|
|
|
|
cx_cmd (port, CCR_INITCH | CCR_ENRX);
|
|
|
|
|
|
|
|
/* Start receiver. */
|
|
|
|
outw (ARBCNT(port), rbsz);
|
|
|
|
outw (BRBCNT(port), rbsz);
|
|
|
|
outw (ARBSTS(port), BSTS_OWN24);
|
|
|
|
outw (BRBSTS(port), BSTS_OWN24);
|
|
|
|
|
|
|
|
/* Enable interrupts. */
|
|
|
|
outb (IER(port), IER_RXD | IER_RET | IER_TXD | IER_MDM);
|
|
|
|
|
|
|
|
cx_chan_dtr (c, 1);
|
|
|
|
cx_chan_rts (c, 1);
|
|
|
|
}
|
|
|
|
if (cx_chan_cd (c))
|
1995-10-07 20:07:18 +00:00
|
|
|
(*linesw[tp->t_line].l_modem)(tp, 1);
|
1994-12-02 23:23:01 +00:00
|
|
|
if (! (flag & O_NONBLOCK)) {
|
|
|
|
/* Lock the channel against cxconfig while we are
|
|
|
|
* waiting for carrier. */
|
|
|
|
c->sopt.lock = 1;
|
|
|
|
while (!(tp->t_cflag & CLOCAL) && !(tp->t_state & TS_CARR_ON))
|
|
|
|
if ((error = tsleep (TSA_CARR_ON(tp), TTIPRI | PCATCH,
|
|
|
|
"cxdcd", 0)))
|
|
|
|
break;
|
|
|
|
c->sopt.lock = 0; /* Unlock the channel. */
|
|
|
|
}
|
|
|
|
print (("cx%d.%d: cxopen done csr=%b\n", c->board->num, c->num,
|
|
|
|
inb(CSR(c->chip->port)), CSRA_BITS));
|
|
|
|
spl0 ();
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
#if __FreeBSD__ >= 2
|
|
|
|
error = (*linesw[tp->t_line].l_open) (dev, tp);
|
|
|
|
#else
|
|
|
|
error = (*linesw[tp->t_line].l_open) (dev, tp, 0);
|
|
|
|
#endif
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2001-09-12 08:38:13 +00:00
|
|
|
int cxclose (dev_t dev, int flag, int mode, struct thread *td)
|
1994-12-02 23:23:01 +00:00
|
|
|
{
|
|
|
|
int unit = UNIT (dev);
|
|
|
|
cx_chan_t *c = cxchan[unit];
|
|
|
|
struct tty *tp;
|
|
|
|
int s;
|
1995-05-30 08:16:23 +00:00
|
|
|
|
1994-12-02 23:23:01 +00:00
|
|
|
if (unit == UNIT_CTL)
|
|
|
|
return (0);
|
|
|
|
tp = c->ttyp;
|
|
|
|
(*linesw[tp->t_line].l_close) (tp, flag);
|
|
|
|
|
|
|
|
/* Disable receiver.
|
|
|
|
* Transmitter continues sending the queued data. */
|
|
|
|
s = spltty ();
|
|
|
|
outb (CAR(c->chip->port), c->num & 3);
|
|
|
|
outb (IER(c->chip->port), IER_TXD | IER_MDM);
|
|
|
|
cx_cmd (c->chip->port, CCR_DISRX);
|
|
|
|
|
|
|
|
/* Clear DTR and RTS. */
|
|
|
|
if ((tp->t_cflag & HUPCL) || ! (tp->t_state & TS_ISOPEN)) {
|
|
|
|
cx_chan_dtr (c, 0);
|
|
|
|
cx_chan_rts (c, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Stop sending break. */
|
|
|
|
if (c->brk == BRK_SEND) {
|
|
|
|
c->brk = BRK_STOP;
|
|
|
|
if (! (tp->t_state & TS_BUSY))
|
|
|
|
cxoproc (tp);
|
|
|
|
}
|
|
|
|
splx (s);
|
|
|
|
ttyclose (tp);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2001-09-12 08:38:13 +00:00
|
|
|
int cxioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
1994-12-02 23:23:01 +00:00
|
|
|
{
|
|
|
|
int unit = UNIT (dev);
|
1995-10-04 22:24:16 +00:00
|
|
|
cx_chan_t *c, *m;
|
|
|
|
cx_stat_t *st;
|
1994-12-02 23:23:01 +00:00
|
|
|
struct tty *tp;
|
|
|
|
int error, s;
|
|
|
|
unsigned char msv;
|
1995-10-04 22:24:16 +00:00
|
|
|
struct ifnet *master;
|
1994-12-02 23:23:01 +00:00
|
|
|
|
|
|
|
if (unit == UNIT_CTL) {
|
|
|
|
/* Process an ioctl request on /dev/cronyx */
|
|
|
|
cx_options_t *o = (cx_options_t*) data;
|
|
|
|
|
|
|
|
if (o->board >= NCX || o->channel >= NCHAN)
|
|
|
|
return (EINVAL);
|
|
|
|
c = &cxboard[o->board].chan[o->channel];
|
|
|
|
if (c->type == T_NONE)
|
|
|
|
return (ENXIO);
|
|
|
|
switch (cmd) {
|
|
|
|
default:
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
case CXIOCSETMODE:
|
|
|
|
print (("cx%d.%d: CXIOCSETMODE\n", o->board, o->channel));
|
|
|
|
if (c->type == T_NONE)
|
|
|
|
return (EINVAL);
|
|
|
|
if (c->type == T_ASYNC && o->mode != M_ASYNC)
|
|
|
|
return (EINVAL);
|
|
|
|
if (o->mode == M_ASYNC)
|
|
|
|
switch (c->type) {
|
|
|
|
case T_SYNC_RS232:
|
|
|
|
case T_SYNC_V35:
|
|
|
|
case T_SYNC_RS449:
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
/* Somebody is waiting for carrier? */
|
|
|
|
if (c->sopt.lock)
|
|
|
|
return (EBUSY);
|
|
|
|
/* /dev/ttyXX is already opened by someone? */
|
|
|
|
if (c->mode == M_ASYNC && c->ttyp &&
|
|
|
|
(c->ttyp->t_state & TS_ISOPEN))
|
|
|
|
return (EBUSY);
|
|
|
|
/* Network interface is up? */
|
|
|
|
if (c->mode != M_ASYNC && (c->ifp->if_flags & IFF_UP))
|
|
|
|
return (EBUSY);
|
1995-10-04 22:24:16 +00:00
|
|
|
|
|
|
|
/* Find the master interface. */
|
|
|
|
master = *o->master ? ifunit (o->master) : c->ifp;
|
|
|
|
if (! master)
|
|
|
|
return (EINVAL);
|
|
|
|
m = cxchan[master->if_unit];
|
|
|
|
|
|
|
|
/* Leave the previous master queue. */
|
|
|
|
if (c->master != c->ifp) {
|
|
|
|
cx_chan_t *p = cxchan[c->master->if_unit];
|
|
|
|
|
|
|
|
for (; p; p=p->slaveq)
|
|
|
|
if (p->slaveq == c)
|
|
|
|
p->slaveq = c->slaveq;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set up new master. */
|
|
|
|
c->master = master;
|
|
|
|
c->slaveq = 0;
|
|
|
|
|
|
|
|
/* Join the new master queue. */
|
|
|
|
if (c->master != c->ifp) {
|
|
|
|
c->slaveq = m->slaveq;
|
|
|
|
m->slaveq = c;
|
|
|
|
}
|
|
|
|
|
1994-12-02 23:23:01 +00:00
|
|
|
c->mode = o->mode;
|
|
|
|
c->rxbaud = o->rxbaud;
|
|
|
|
c->txbaud = o->txbaud;
|
|
|
|
c->opt = o->opt;
|
|
|
|
c->aopt = o->aopt;
|
|
|
|
c->hopt = o->hopt;
|
|
|
|
c->bopt = o->bopt;
|
|
|
|
c->xopt = o->xopt;
|
|
|
|
switch (c->num) {
|
|
|
|
case 0: c->board->if0type = o->iftype; break;
|
|
|
|
case 8: c->board->if8type = o->iftype; break;
|
|
|
|
}
|
|
|
|
s = spltty ();
|
1995-10-04 22:24:16 +00:00
|
|
|
cxswitch (c, o->sopt);
|
1994-12-02 23:23:01 +00:00
|
|
|
cx_setup_chan (c);
|
|
|
|
outb (IER(c->chip->port), 0);
|
|
|
|
splx (s);
|
|
|
|
break;
|
|
|
|
|
1995-10-04 22:24:16 +00:00
|
|
|
case CXIOCGETSTAT:
|
|
|
|
st = (cx_stat_t*) data;
|
|
|
|
st->rintr = c->stat->rintr;
|
|
|
|
st->tintr = c->stat->tintr;
|
|
|
|
st->mintr = c->stat->mintr;
|
|
|
|
st->ibytes = c->stat->ibytes;
|
|
|
|
st->ipkts = c->stat->ipkts;
|
|
|
|
st->ierrs = c->stat->ierrs;
|
|
|
|
st->obytes = c->stat->obytes;
|
|
|
|
st->opkts = c->stat->opkts;
|
|
|
|
st->oerrs = c->stat->oerrs;
|
|
|
|
break;
|
|
|
|
|
1994-12-02 23:23:01 +00:00
|
|
|
case CXIOCGETMODE:
|
|
|
|
print (("cx%d.%d: CXIOCGETMODE\n", o->board, o->channel));
|
|
|
|
o->type = c->type;
|
|
|
|
o->mode = c->mode;
|
|
|
|
o->rxbaud = c->rxbaud;
|
|
|
|
o->txbaud = c->txbaud;
|
|
|
|
o->opt = c->opt;
|
|
|
|
o->aopt = c->aopt;
|
|
|
|
o->hopt = c->hopt;
|
|
|
|
o->bopt = c->bopt;
|
|
|
|
o->xopt = c->xopt;
|
|
|
|
o->sopt = c->sopt;
|
|
|
|
switch (c->num) {
|
|
|
|
case 0: o->iftype = c->board->if0type; break;
|
|
|
|
case 8: o->iftype = c->board->if8type; break;
|
|
|
|
}
|
1995-10-04 22:24:16 +00:00
|
|
|
if (c->master != c->ifp)
|
1998-12-04 22:54:57 +00:00
|
|
|
snprintf (o->master, sizeof(o->master),
|
|
|
|
"%s%d", c->master->if_name,
|
1995-10-04 22:24:16 +00:00
|
|
|
c->master->if_unit);
|
|
|
|
else
|
|
|
|
*o->master = 0;
|
1994-12-02 23:23:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
c = cxchan[unit];
|
|
|
|
tp = c->ttyp;
|
|
|
|
if (! tp)
|
|
|
|
return (EINVAL);
|
|
|
|
#if __FreeBSD__ >= 2
|
2001-09-12 08:38:13 +00:00
|
|
|
error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag, td);
|
1994-12-02 23:23:01 +00:00
|
|
|
#else
|
|
|
|
error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag);
|
|
|
|
#endif
|
1997-12-06 13:25:01 +00:00
|
|
|
if (error != ENOIOCTL)
|
1994-12-02 23:23:01 +00:00
|
|
|
return (error);
|
|
|
|
error = ttioctl (tp, cmd, data, flag);
|
1997-12-06 13:25:01 +00:00
|
|
|
if (error != ENOIOCTL)
|
1994-12-02 23:23:01 +00:00
|
|
|
return (error);
|
|
|
|
|
|
|
|
s = spltty ();
|
|
|
|
switch (cmd) {
|
|
|
|
default:
|
|
|
|
splx (s);
|
|
|
|
return (ENOTTY);
|
|
|
|
case TIOCSBRK: /* Start sending line break */
|
|
|
|
c->brk = BRK_SEND;
|
|
|
|
if (! (tp->t_state & TS_BUSY))
|
|
|
|
cxoproc (tp);
|
|
|
|
break;
|
|
|
|
case TIOCCBRK: /* Stop sending line break */
|
|
|
|
c->brk = BRK_STOP;
|
|
|
|
if (! (tp->t_state & TS_BUSY))
|
|
|
|
cxoproc (tp);
|
|
|
|
break;
|
|
|
|
case TIOCSDTR: /* Set DTR */
|
|
|
|
cx_chan_dtr (c, 1);
|
|
|
|
break;
|
|
|
|
case TIOCCDTR: /* Clear DTR */
|
|
|
|
cx_chan_dtr (c, 0);
|
|
|
|
break;
|
|
|
|
case TIOCMSET: /* Set DTR/RTS */
|
|
|
|
cx_chan_dtr (c, (*(int*)data & TIOCM_DTR) ? 1 : 0);
|
|
|
|
cx_chan_rts (c, (*(int*)data & TIOCM_RTS) ? 1 : 0);
|
|
|
|
break;
|
|
|
|
case TIOCMBIS: /* Add DTR/RTS */
|
|
|
|
if (*(int*)data & TIOCM_DTR) cx_chan_dtr (c, 1);
|
|
|
|
if (*(int*)data & TIOCM_RTS) cx_chan_rts (c, 1);
|
|
|
|
break;
|
|
|
|
case TIOCMBIC: /* Clear DTR/RTS */
|
|
|
|
if (*(int*)data & TIOCM_DTR) cx_chan_dtr (c, 0);
|
|
|
|
if (*(int*)data & TIOCM_RTS) cx_chan_rts (c, 0);
|
|
|
|
break;
|
|
|
|
case TIOCMGET: /* Get modem status */
|
|
|
|
msv = inb (MSVR(c->chip->port));
|
|
|
|
*(int*)data = TIOCM_LE; /* always enabled while open */
|
|
|
|
if (msv & MSV_DSR) *(int*)data |= TIOCM_DSR;
|
|
|
|
if (msv & MSV_CTS) *(int*)data |= TIOCM_CTS;
|
|
|
|
if (msv & MSV_CD) *(int*)data |= TIOCM_CD;
|
|
|
|
if (c->dtr) *(int*)data |= TIOCM_DTR;
|
|
|
|
if (c->rts) *(int*)data |= TIOCM_RTS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
splx (s);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill transmitter buffer with data.
|
|
|
|
*/
|
1995-12-10 13:40:44 +00:00
|
|
|
static void
|
|
|
|
cxout (cx_chan_t *c, char b)
|
1994-12-02 23:23:01 +00:00
|
|
|
{
|
|
|
|
unsigned char *buf, *p, sym;
|
|
|
|
unsigned short port = c->chip->port, len = 0, cnt_port, sts_port;
|
|
|
|
struct tty *tp = c->ttyp;
|
|
|
|
|
|
|
|
if (! tp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Choose the buffer. */
|
|
|
|
if (b == 'A') {
|
|
|
|
buf = c->atbuf;
|
|
|
|
cnt_port = ATBCNT(port);
|
|
|
|
sts_port = ATBSTS(port);
|
|
|
|
} else {
|
|
|
|
buf = c->btbuf;
|
|
|
|
cnt_port = BTBCNT(port);
|
|
|
|
sts_port = BTBSTS(port);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is it busy? */
|
|
|
|
if (inb (sts_port) & BSTS_OWN24) {
|
|
|
|
tp->t_state |= TS_BUSY;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (c->brk) {
|
|
|
|
case BRK_SEND:
|
|
|
|
*buf++ = 0; /* extended transmit command */
|
|
|
|
*buf++ = 0x81; /* send break */
|
|
|
|
*buf++ = 0; /* extended transmit command */
|
|
|
|
*buf++ = 0x82; /* insert delay */
|
|
|
|
*buf++ = 250; /* 1/4 of second */
|
|
|
|
*buf++ = 0; /* extended transmit command */
|
|
|
|
*buf++ = 0x82; /* insert delay */
|
|
|
|
*buf++ = 250; /* + 1/4 of second */
|
|
|
|
len = 8;
|
|
|
|
c->brk = BRK_IDLE;
|
|
|
|
break;
|
|
|
|
case BRK_STOP:
|
|
|
|
*buf++ = 0; /* extended transmit command */
|
|
|
|
*buf++ = 0x83; /* stop break */
|
|
|
|
len = 2;
|
|
|
|
c->brk = BRK_IDLE;
|
|
|
|
break;
|
|
|
|
case BRK_IDLE:
|
1995-10-04 22:24:16 +00:00
|
|
|
p = buf;
|
1994-12-02 23:23:01 +00:00
|
|
|
if (tp->t_iflag & IXOFF)
|
1995-10-04 22:24:16 +00:00
|
|
|
while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) {
|
1994-12-02 23:23:01 +00:00
|
|
|
sym = RB_GETC (tp->t_out);
|
|
|
|
/* Send XON/XOFF out of band. */
|
|
|
|
if (sym == tp->t_cc[VSTOP]) {
|
|
|
|
outb (STCR(port), STC_SNDSPC|STC_SSPC_2);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (sym == tp->t_cc[VSTART]) {
|
|
|
|
outb (STCR(port), STC_SNDSPC|STC_SSPC_1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* Duplicate NULLs in ETC mode. */
|
|
|
|
if (! sym)
|
|
|
|
*p++ = 0;
|
|
|
|
*p++ = sym;
|
|
|
|
}
|
|
|
|
else
|
1995-10-04 22:24:16 +00:00
|
|
|
while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) {
|
1994-12-02 23:23:01 +00:00
|
|
|
sym = RB_GETC (tp->t_out);
|
|
|
|
/* Duplicate NULLs in ETC mode. */
|
|
|
|
if (! sym)
|
|
|
|
*p++ = 0;
|
|
|
|
*p++ = sym;
|
|
|
|
}
|
|
|
|
len = p - buf;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Start transmitter. */
|
|
|
|
if (len) {
|
|
|
|
outw (cnt_port, len);
|
|
|
|
outb (sts_port, BSTS_INTR | BSTS_OWN24);
|
1995-10-04 22:24:16 +00:00
|
|
|
c->stat->obytes += len;
|
1994-12-02 23:23:01 +00:00
|
|
|
tp->t_state |= TS_BUSY;
|
|
|
|
print (("cx%d.%d: out %d bytes to %c\n",
|
|
|
|
c->board->num, c->num, len, b));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cxoproc (struct tty *tp)
|
|
|
|
{
|
|
|
|
int unit = UNIT (tp->t_dev);
|
|
|
|
cx_chan_t *c = cxchan[unit];
|
|
|
|
unsigned short port = c->chip->port;
|
|
|
|
int s = spltty ();
|
|
|
|
|
|
|
|
/* Set current channel number */
|
|
|
|
outb (CAR(port), c->num & 3);
|
|
|
|
|
|
|
|
if (! (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))) {
|
|
|
|
/* Start transmitter. */
|
|
|
|
if (! (inb (CSR(port)) & CSRA_TXEN))
|
|
|
|
cx_cmd (port, CCR_ENTX);
|
|
|
|
|
|
|
|
/* Determine the buffer order. */
|
|
|
|
if (inb (DMABSTS(port)) & DMABSTS_NTBUF) {
|
|
|
|
cxout (c, 'B');
|
|
|
|
cxout (c, 'A');
|
|
|
|
} else {
|
|
|
|
cxout (c, 'A');
|
|
|
|
cxout (c, 'B');
|
|
|
|
}
|
|
|
|
}
|
1995-10-07 20:07:18 +00:00
|
|
|
#ifndef TS_ASLEEP /* FreeBSD some time after 2.0.5 */
|
|
|
|
ttwwakeup(tp);
|
|
|
|
#else
|
1994-12-02 23:23:01 +00:00
|
|
|
if (RB_LEN (tp->t_out) <= tp->t_lowat) {
|
|
|
|
if (tp->t_state & TS_ASLEEP) {
|
|
|
|
tp->t_state &= ~TS_ASLEEP;
|
|
|
|
wakeup(TSA_OLOWAT(tp));
|
|
|
|
}
|
|
|
|
selwakeup(&tp->t_wsel);
|
|
|
|
}
|
1995-07-22 01:30:45 +00:00
|
|
|
#endif
|
1994-12-02 23:23:01 +00:00
|
|
|
splx (s);
|
|
|
|
}
|
|
|
|
|
1995-12-10 13:40:44 +00:00
|
|
|
static int
|
|
|
|
cxparam (struct tty *tp, struct termios *t)
|
1994-12-02 23:23:01 +00:00
|
|
|
{
|
|
|
|
int unit = UNIT (tp->t_dev);
|
|
|
|
cx_chan_t *c = cxchan[unit];
|
|
|
|
unsigned short port = c->chip->port;
|
|
|
|
int clock, period, s;
|
|
|
|
cx_cor1_async_t cor1;
|
1995-05-30 08:16:23 +00:00
|
|
|
|
1994-12-02 23:23:01 +00:00
|
|
|
if (t->c_ospeed == 0) {
|
|
|
|
/* Clear DTR and RTS. */
|
|
|
|
s = spltty ();
|
|
|
|
cx_chan_dtr (c, 0);
|
|
|
|
cx_chan_rts (c, 0);
|
|
|
|
splx (s);
|
|
|
|
print (("cx%d.%d: cxparam (hangup)\n", c->board->num, c->num));
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
print (("cx%d.%d: cxparam\n", c->board->num, c->num));
|
|
|
|
|
|
|
|
/* Check requested parameters. */
|
|
|
|
if (t->c_ospeed < 300 || t->c_ospeed > 256*1024)
|
|
|
|
return(EINVAL);
|
|
|
|
if (t->c_ispeed && (t->c_ispeed < 300 || t->c_ispeed > 256*1024))
|
|
|
|
return(EINVAL);
|
|
|
|
|
|
|
|
#ifdef __bsdi__
|
|
|
|
/* CLOCAL flag set -- wakeup everybody who waits for CD. */
|
|
|
|
/* FreeBSD does this themselves. */
|
|
|
|
if (! (tp->t_cflag & CLOCAL) && (t->c_cflag & CLOCAL))
|
|
|
|
wakeup ((caddr_t) &tp->t_rawq);
|
|
|
|
#endif
|
|
|
|
/* And copy them to tty and channel structures. */
|
|
|
|
c->rxbaud = tp->t_ispeed = t->c_ispeed;
|
|
|
|
c->txbaud = tp->t_ospeed = t->c_ospeed;
|
|
|
|
tp->t_cflag = t->c_cflag;
|
|
|
|
|
|
|
|
/* Set character length and parity mode. */
|
|
|
|
BYTE cor1 = 0;
|
|
|
|
switch (t->c_cflag & CSIZE) {
|
|
|
|
default:
|
|
|
|
case CS8: cor1.charlen = 7; break;
|
|
|
|
case CS7: cor1.charlen = 6; break;
|
|
|
|
case CS6: cor1.charlen = 5; break;
|
|
|
|
case CS5: cor1.charlen = 4; break;
|
|
|
|
}
|
|
|
|
if (t->c_cflag & PARENB) {
|
|
|
|
cor1.parmode = PARM_NORMAL;
|
|
|
|
cor1.ignpar = 0;
|
|
|
|
cor1.parity = (t->c_cflag & PARODD) ? PAR_ODD : PAR_EVEN;
|
|
|
|
} else {
|
|
|
|
cor1.parmode = PARM_NOPAR;
|
|
|
|
cor1.ignpar = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable/disable hardware CTS. */
|
|
|
|
c->aopt.cor2.ctsae = (t->c_cflag & CRTSCTS) ? 1 : 0;
|
|
|
|
/* Handle DSR as CTS. */
|
|
|
|
c->aopt.cor2.dsrae = (t->c_cflag & CRTSCTS) ? 1 : 0;
|
|
|
|
/* Enable extended transmit command mode.
|
|
|
|
* Unfortunately, there is no other method for sending break. */
|
|
|
|
c->aopt.cor2.etc = 1;
|
|
|
|
/* Enable/disable hardware XON/XOFF. */
|
|
|
|
c->aopt.cor2.ixon = (t->c_iflag & IXON) ? 1 : 0;
|
|
|
|
c->aopt.cor2.ixany = (t->c_iflag & IXANY) ? 1 : 0;
|
|
|
|
|
|
|
|
/* Set the number of stop bits. */
|
|
|
|
if (t->c_cflag & CSTOPB)
|
|
|
|
c->aopt.cor3.stopb = STOPB_2;
|
|
|
|
else
|
|
|
|
c->aopt.cor3.stopb = STOPB_1;
|
|
|
|
/* Disable/enable passing XON/XOFF chars to the host. */
|
|
|
|
c->aopt.cor3.scde = (t->c_iflag & IXON) ? 1 : 0;
|
|
|
|
c->aopt.cor3.flowct = (t->c_iflag & IXON) ? FLOWCC_NOTPASS : FLOWCC_PASS;
|
|
|
|
|
|
|
|
c->aopt.schr1 = t->c_cc[VSTART]; /* XON */
|
|
|
|
c->aopt.schr2 = t->c_cc[VSTOP]; /* XOFF */
|
|
|
|
|
|
|
|
/* Set current channel number. */
|
|
|
|
s = spltty ();
|
|
|
|
outb (CAR(port), c->num & 3);
|
|
|
|
|
|
|
|
/* Set up receiver clock values. */
|
|
|
|
cx_clock (c->chip->oscfreq, c->rxbaud, &clock, &period);
|
|
|
|
c->opt.rcor.clk = clock;
|
|
|
|
outb (RCOR(port), BYTE c->opt.rcor);
|
|
|
|
outb (RBPR(port), period);
|
|
|
|
|
|
|
|
/* Set up transmitter clock values. */
|
|
|
|
cx_clock (c->chip->oscfreq, c->txbaud, &clock, &period);
|
|
|
|
c->opt.tcor.clk = clock;
|
|
|
|
c->opt.tcor.ext1x = 0;
|
|
|
|
outb (TCOR(port), BYTE c->opt.tcor);
|
|
|
|
outb (TBPR(port), period);
|
|
|
|
|
|
|
|
outb (COR2(port), BYTE c->aopt.cor2);
|
|
|
|
outb (COR3(port), BYTE c->aopt.cor3);
|
|
|
|
outb (SCHR1(port), c->aopt.schr1);
|
|
|
|
outb (SCHR2(port), c->aopt.schr2);
|
|
|
|
|
|
|
|
if (BYTE c->aopt.cor1 != BYTE cor1) {
|
|
|
|
BYTE c->aopt.cor1 = BYTE cor1;
|
|
|
|
outb (COR1(port), BYTE c->aopt.cor1);
|
|
|
|
/* Any change to COR1 require reinitialization. */
|
|
|
|
/* Unfortunately, it may cause transmitter glitches... */
|
|
|
|
cx_cmd (port, CCR_INITCH);
|
|
|
|
}
|
|
|
|
splx (s);
|
|
|
|
return (0);
|
|
|
|
}
|
1995-02-28 00:21:11 +00:00
|
|
|
|
1994-12-02 23:23:01 +00:00
|
|
|
/*
|
|
|
|
* Stop output on a line
|
|
|
|
*/
|
|
|
|
void cxstop (struct tty *tp, int flag)
|
|
|
|
{
|
|
|
|
cx_chan_t *c = cxchan[UNIT(tp->t_dev)];
|
|
|
|
unsigned short port = c->chip->port;
|
|
|
|
int s = spltty ();
|
|
|
|
|
|
|
|
if (tp->t_state & TS_BUSY) {
|
|
|
|
print (("cx%d.%d: cxstop\n", c->board->num, c->num));
|
|
|
|
|
|
|
|
/* Set current channel number */
|
|
|
|
outb (CAR(port), c->num & 3);
|
|
|
|
|
|
|
|
/* Stop transmitter */
|
|
|
|
cx_cmd (port, CCR_DISTX);
|
|
|
|
}
|
|
|
|
splx (s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle receive interrupts, including receive errors and
|
|
|
|
* receive timeout interrupt.
|
|
|
|
*/
|
|
|
|
int cxrinta (cx_chan_t *c)
|
|
|
|
{
|
|
|
|
unsigned short port = c->chip->port;
|
|
|
|
unsigned short len = 0, risr = inw (RISR(port)), reoir = 0;
|
|
|
|
struct tty *tp = c->ttyp;
|
|
|
|
|
|
|
|
/* Compute optimal receiver buffer length. */
|
|
|
|
int rbsz = (c->rxbaud + 800 - 1) / 800 * 2;
|
|
|
|
if (rbsz < 4)
|
|
|
|
rbsz = 4;
|
|
|
|
else if (rbsz > DMABUFSZ)
|
|
|
|
rbsz = DMABUFSZ;
|
|
|
|
|
|
|
|
if (risr & RISA_TIMEOUT) {
|
|
|
|
unsigned long rcbadr = (unsigned short) inw (RCBADRL(port)) |
|
|
|
|
(long) inw (RCBADRU(port)) << 16;
|
|
|
|
unsigned char *buf = 0;
|
|
|
|
unsigned short cnt_port = 0, sts_port = 0;
|
|
|
|
if (rcbadr >= c->brphys && rcbadr < c->brphys+DMABUFSZ) {
|
|
|
|
buf = c->brbuf;
|
|
|
|
len = rcbadr - c->brphys;
|
|
|
|
cnt_port = BRBCNT(port);
|
|
|
|
sts_port = BRBSTS(port);
|
|
|
|
} else if (rcbadr >= c->arphys && rcbadr < c->arphys+DMABUFSZ) {
|
|
|
|
buf = c->arbuf;
|
|
|
|
len = rcbadr - c->arphys;
|
|
|
|
cnt_port = ARBCNT(port);
|
|
|
|
sts_port = ARBSTS(port);
|
|
|
|
} else
|
|
|
|
printf ("cx%d.%d: timeout: invalid buffer address\n",
|
|
|
|
c->board->num, c->num);
|
|
|
|
|
|
|
|
if (len) {
|
|
|
|
print (("cx%d.%d: async receive timeout (%d bytes), risr=%b, arbsts=%b, brbsts=%b\n",
|
|
|
|
c->board->num, c->num, len, risr, RISA_BITS,
|
|
|
|
inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS));
|
1995-10-04 22:24:16 +00:00
|
|
|
c->stat->ibytes += len;
|
1994-12-02 23:23:01 +00:00
|
|
|
if (tp && (tp->t_state & TS_ISOPEN)) {
|
|
|
|
int i;
|
1995-11-18 07:07:04 +00:00
|
|
|
int (*rint)(int, struct tty *) =
|
1994-12-02 23:23:01 +00:00
|
|
|
linesw[tp->t_line].l_rint;
|
|
|
|
|
|
|
|
for (i=0; i<len; ++i)
|
|
|
|
(*rint) (buf[i], tp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restart receiver. */
|
|
|
|
outw (cnt_port, rbsz);
|
|
|
|
outb (sts_port, BSTS_OWN24);
|
|
|
|
}
|
|
|
|
return (REOI_TERMBUFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
print (("cx%d.%d: async receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n",
|
|
|
|
c->board->num, c->num, risr, RISA_BITS,
|
|
|
|
inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS));
|
|
|
|
|
1995-10-04 22:24:16 +00:00
|
|
|
if (risr & RIS_BUSERR) {
|
1994-12-02 23:23:01 +00:00
|
|
|
printf ("cx%d.%d: receive bus error\n", c->board->num, c->num);
|
1995-10-04 22:24:16 +00:00
|
|
|
++c->stat->ierrs;
|
|
|
|
}
|
1995-03-29 21:26:37 +00:00
|
|
|
if (risr & (RIS_OVERRUN | RISA_PARERR | RISA_FRERR | RISA_BREAK)) {
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (risr & RISA_PARERR)
|
|
|
|
err |= TTY_PE;
|
|
|
|
if (risr & RISA_FRERR)
|
|
|
|
err |= TTY_FE;
|
1995-10-04 22:24:16 +00:00
|
|
|
#ifdef TTY_OE
|
|
|
|
if (risr & RIS_OVERRUN)
|
|
|
|
err |= TTY_OE;
|
|
|
|
#endif
|
|
|
|
#ifdef TTY_BI
|
1995-03-29 21:26:37 +00:00
|
|
|
if (risr & RISA_BREAK)
|
|
|
|
err |= TTY_BI;
|
1995-10-04 22:24:16 +00:00
|
|
|
#endif
|
1995-03-29 21:26:37 +00:00
|
|
|
print (("cx%d.%d: receive error %x\n", c->board->num, c->num, err));
|
1994-12-02 23:23:01 +00:00
|
|
|
if (tp && (tp->t_state & TS_ISOPEN))
|
1995-03-29 21:26:37 +00:00
|
|
|
(*linesw[tp->t_line].l_rint) (err, tp);
|
1995-10-04 22:24:16 +00:00
|
|
|
++c->stat->ierrs;
|
1994-12-02 23:23:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Discard exception characters. */
|
1998-12-13 22:29:32 +00:00
|
|
|
if ((risr & RISA_SCMASK) && tp && (tp->t_iflag & IXON))
|
1994-12-02 23:23:01 +00:00
|
|
|
reoir |= REOI_DISCEXC;
|
|
|
|
|
|
|
|
/* Handle received data. */
|
|
|
|
if ((risr & RIS_EOBUF) && tp && (tp->t_state & TS_ISOPEN)) {
|
1995-11-18 07:07:04 +00:00
|
|
|
int (*rint)(int, struct tty *) = linesw[tp->t_line].l_rint;
|
1994-12-02 23:23:01 +00:00
|
|
|
unsigned char *buf;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
len = (risr & RIS_BB) ? inw(BRBCNT(port)) : inw(ARBCNT(port));
|
|
|
|
|
|
|
|
print (("cx%d.%d: async: %d bytes received\n",
|
|
|
|
c->board->num, c->num, len));
|
1995-10-04 22:24:16 +00:00
|
|
|
c->stat->ibytes += len;
|
1994-12-02 23:23:01 +00:00
|
|
|
|
|
|
|
buf = (risr & RIS_BB) ? c->brbuf : c->arbuf;
|
|
|
|
for (i=0; i<len; ++i)
|
|
|
|
(*rint) (buf[i], tp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restart receiver. */
|
|
|
|
if (! (inb (ARBSTS(port)) & BSTS_OWN24)) {
|
|
|
|
outw (ARBCNT(port), rbsz);
|
|
|
|
outb (ARBSTS(port), BSTS_OWN24);
|
|
|
|
}
|
|
|
|
if (! (inb (BRBSTS(port)) & BSTS_OWN24)) {
|
|
|
|
outw (BRBCNT(port), rbsz);
|
|
|
|
outb (BRBSTS(port), BSTS_OWN24);
|
|
|
|
}
|
|
|
|
return (reoir);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle transmit interrupt.
|
|
|
|
*/
|
|
|
|
void cxtinta (cx_chan_t *c)
|
|
|
|
{
|
|
|
|
struct tty *tp = c->ttyp;
|
|
|
|
unsigned short port = c->chip->port;
|
|
|
|
unsigned char tisr = inb (TISR(port));
|
|
|
|
|
|
|
|
print (("cx%d.%d: async transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n",
|
|
|
|
c->board->num, c->num, tisr, TIS_BITS,
|
|
|
|
inb (ATBSTS(port)), BSTS_BITS, inb (BTBSTS(port)), BSTS_BITS));
|
|
|
|
|
1995-10-04 22:24:16 +00:00
|
|
|
if (tisr & TIS_BUSERR) {
|
1994-12-02 23:23:01 +00:00
|
|
|
printf ("cx%d.%d: transmit bus error\n",
|
|
|
|
c->board->num, c->num);
|
1995-10-04 22:24:16 +00:00
|
|
|
++c->stat->oerrs;
|
|
|
|
} else if (tisr & TIS_UNDERRUN) {
|
1994-12-02 23:23:01 +00:00
|
|
|
printf ("cx%d.%d: transmit underrun error\n",
|
|
|
|
c->board->num, c->num);
|
1995-10-04 22:24:16 +00:00
|
|
|
++c->stat->oerrs;
|
|
|
|
}
|
1994-12-02 23:23:01 +00:00
|
|
|
if (tp) {
|
|
|
|
tp->t_state &= ~(TS_BUSY | TS_FLUSH);
|
|
|
|
if (tp->t_line)
|
|
|
|
(*linesw[tp->t_line].l_start) (tp);
|
|
|
|
else
|
|
|
|
cxoproc (tp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle modem interrupt.
|
|
|
|
*/
|
|
|
|
void cxmint (cx_chan_t *c)
|
|
|
|
{
|
|
|
|
unsigned short port = c->chip->port;
|
|
|
|
unsigned char misr = inb (MISR(port));
|
|
|
|
unsigned char msvr = inb (MSVR(port));
|
|
|
|
struct tty *tp = c->ttyp;
|
|
|
|
|
|
|
|
if (c->mode != M_ASYNC) {
|
|
|
|
printf ("cx%d.%d: unexpected modem interrupt, misr=%b, msvr=%b\n",
|
|
|
|
c->board->num, c->num, misr, MIS_BITS, msvr, MSV_BITS);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
print (("cx%d.%d: modem interrupt, misr=%b, msvr=%b\n",
|
|
|
|
c->board->num, c->num, misr, MIS_BITS, msvr, MSV_BITS));
|
|
|
|
|
|
|
|
/* Ignore DSR events. */
|
|
|
|
/* Ignore RTC/CTS events, handled by hardware. */
|
|
|
|
/* Handle carrier detect/loss. */
|
|
|
|
if (tp && (misr & MIS_CCD))
|
|
|
|
(*linesw[tp->t_line].l_modem) (tp, (msvr & MSV_CD) != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Recover after lost transmit interrupts.
|
|
|
|
*/
|
1995-11-18 07:07:04 +00:00
|
|
|
void cxtimeout (void *a)
|
1994-12-02 23:23:01 +00:00
|
|
|
{
|
|
|
|
cx_board_t *b;
|
|
|
|
cx_chan_t *c;
|
|
|
|
struct tty *tp;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
for (b=cxboard; b<cxboard+NCX; ++b)
|
|
|
|
for (c=b->chan; c<b->chan+NCHAN; ++c) {
|
|
|
|
tp = c->ttyp;
|
|
|
|
if (c->type==T_NONE || c->mode!=M_ASYNC || !tp)
|
|
|
|
continue;
|
|
|
|
s = spltty ();
|
|
|
|
if (tp->t_state & TS_BUSY) {
|
|
|
|
tp->t_state &= ~TS_BUSY;
|
|
|
|
if (tp->t_line)
|
|
|
|
(*linesw[tp->t_line].l_start) (tp);
|
|
|
|
else
|
|
|
|
cxoproc (tp);
|
|
|
|
}
|
|
|
|
splx (s);
|
|
|
|
}
|
1995-11-18 07:07:04 +00:00
|
|
|
timeout (cxtimeout, 0, hz*5);
|
1994-12-02 23:23:01 +00:00
|
|
|
}
|
the second set of changes in a move towards getting devices to be
totally dynamic.
this is only the devices in i386/isa
I'll do more tomorrow.
they're completely masked by #ifdef JREMOD at this stage...
the eventual aim is that every driver will do a SYSINIT
at startup BEFORE the probes, which will effectively
link it into the devsw tables etc.
If I'd thought about it more I'd have put that in in this set (damn)
The ioconf lines generated by config will also end up in the
device's own scope as well, so ioconf.c will eventually be gutted
the SYSINIT call to the driver will include a phase where the
driver links it's ioconf line into a chain of such. when this phase is done
then the user can modify them with the boot: -c
config menu if he wants, just like now..
config will put the config lines out in the .h file
(e.g. in aha.h will be the addresses for the aha driver to look.)
as I said this is a very small first step..
the aim of THIS set of edits is to not have to edit conf.c at all when
adding a new device.. the tabe will be a simple skeleton..
when this is done, it will allow other changes to be made,
all teh time still having a fully working kernel tree,
but the logical outcome is the complete REMOVAL of the devsw tables.
By the end of this, linked in drivers will be exactly the same as
run-time loaded drivers, except they JUST HAPPEN to already be linked
and present at startup..
the SYSINIT calls will be the equivalent of the "init" call
made to a newly loaded driver in every respect.
For this edit,
each of the files has the following code inserted into it:
obviously, tailored to suit..
----------------------somewhere at the top:
#ifdef JREMOD
#include <sys/conf.h>
#define CDEV_MAJOR 13
#define BDEV_MAJOR 4
static void sd_devsw_install();
#endif /*JREMOD */
---------------------somewhere that's run during bootup: EVENTUALLY a SYSINIT
#ifdef JREMOD
sd_devsw_install();
#endif /*JREMOD*/
-----------------------at the bottom:
#ifdef JREMOD
struct bdevsw sd_bdevsw =
{ sdopen, sdclose, sdstrategy, sdioctl, /*4*/
sddump, sdsize, 0 };
struct cdevsw sd_cdevsw =
{ sdopen, sdclose, rawread, rawwrite, /*13*/
sdioctl, nostop, nullreset, nodevtotty,/* sd */
seltrue, nommap, sdstrategy };
static sd_devsw_installed = 0;
static void sd_devsw_install()
{
dev_t descript;
if( ! sd_devsw_installed ) {
descript = makedev(CDEV_MAJOR,0);
cdevsw_add(&descript,&sd_cdevsw,NULL);
#if defined(BDEV_MAJOR)
descript = makedev(BDEV_MAJOR,0);
bdevsw_add(&descript,&sd_bdevsw,NULL);
#endif /*BDEV_MAJOR*/
sd_devsw_installed = 1;
}
}
#endif /* JREMOD */
1995-11-28 09:42:06 +00:00
|
|
|
|
|
|
|
|
1995-12-08 11:19:42 +00:00
|
|
|
#if defined(__FreeBSD__) && (__FreeBSD__ > 1 )
|
1995-11-29 10:49:16 +00:00
|
|
|
static void cx_drvinit(void *unused)
|
the second set of changes in a move towards getting devices to be
totally dynamic.
this is only the devices in i386/isa
I'll do more tomorrow.
they're completely masked by #ifdef JREMOD at this stage...
the eventual aim is that every driver will do a SYSINIT
at startup BEFORE the probes, which will effectively
link it into the devsw tables etc.
If I'd thought about it more I'd have put that in in this set (damn)
The ioconf lines generated by config will also end up in the
device's own scope as well, so ioconf.c will eventually be gutted
the SYSINIT call to the driver will include a phase where the
driver links it's ioconf line into a chain of such. when this phase is done
then the user can modify them with the boot: -c
config menu if he wants, just like now..
config will put the config lines out in the .h file
(e.g. in aha.h will be the addresses for the aha driver to look.)
as I said this is a very small first step..
the aim of THIS set of edits is to not have to edit conf.c at all when
adding a new device.. the tabe will be a simple skeleton..
when this is done, it will allow other changes to be made,
all teh time still having a fully working kernel tree,
but the logical outcome is the complete REMOVAL of the devsw tables.
By the end of this, linked in drivers will be exactly the same as
run-time loaded drivers, except they JUST HAPPEN to already be linked
and present at startup..
the SYSINIT calls will be the equivalent of the "init" call
made to a newly loaded driver in every respect.
For this edit,
each of the files has the following code inserted into it:
obviously, tailored to suit..
----------------------somewhere at the top:
#ifdef JREMOD
#include <sys/conf.h>
#define CDEV_MAJOR 13
#define BDEV_MAJOR 4
static void sd_devsw_install();
#endif /*JREMOD */
---------------------somewhere that's run during bootup: EVENTUALLY a SYSINIT
#ifdef JREMOD
sd_devsw_install();
#endif /*JREMOD*/
-----------------------at the bottom:
#ifdef JREMOD
struct bdevsw sd_bdevsw =
{ sdopen, sdclose, sdstrategy, sdioctl, /*4*/
sddump, sdsize, 0 };
struct cdevsw sd_cdevsw =
{ sdopen, sdclose, rawread, rawwrite, /*13*/
sdioctl, nostop, nullreset, nodevtotty,/* sd */
seltrue, nommap, sdstrategy };
static sd_devsw_installed = 0;
static void sd_devsw_install()
{
dev_t descript;
if( ! sd_devsw_installed ) {
descript = makedev(CDEV_MAJOR,0);
cdevsw_add(&descript,&sd_cdevsw,NULL);
#if defined(BDEV_MAJOR)
descript = makedev(BDEV_MAJOR,0);
bdevsw_add(&descript,&sd_bdevsw,NULL);
#endif /*BDEV_MAJOR*/
sd_devsw_installed = 1;
}
}
#endif /* JREMOD */
1995-11-28 09:42:06 +00:00
|
|
|
{
|
1995-11-29 10:49:16 +00:00
|
|
|
|
1999-05-31 11:29:30 +00:00
|
|
|
cdevsw_add(&cx_cdevsw);
|
the second set of changes in a move towards getting devices to be
totally dynamic.
this is only the devices in i386/isa
I'll do more tomorrow.
they're completely masked by #ifdef JREMOD at this stage...
the eventual aim is that every driver will do a SYSINIT
at startup BEFORE the probes, which will effectively
link it into the devsw tables etc.
If I'd thought about it more I'd have put that in in this set (damn)
The ioconf lines generated by config will also end up in the
device's own scope as well, so ioconf.c will eventually be gutted
the SYSINIT call to the driver will include a phase where the
driver links it's ioconf line into a chain of such. when this phase is done
then the user can modify them with the boot: -c
config menu if he wants, just like now..
config will put the config lines out in the .h file
(e.g. in aha.h will be the addresses for the aha driver to look.)
as I said this is a very small first step..
the aim of THIS set of edits is to not have to edit conf.c at all when
adding a new device.. the tabe will be a simple skeleton..
when this is done, it will allow other changes to be made,
all teh time still having a fully working kernel tree,
but the logical outcome is the complete REMOVAL of the devsw tables.
By the end of this, linked in drivers will be exactly the same as
run-time loaded drivers, except they JUST HAPPEN to already be linked
and present at startup..
the SYSINIT calls will be the equivalent of the "init" call
made to a newly loaded driver in every respect.
For this edit,
each of the files has the following code inserted into it:
obviously, tailored to suit..
----------------------somewhere at the top:
#ifdef JREMOD
#include <sys/conf.h>
#define CDEV_MAJOR 13
#define BDEV_MAJOR 4
static void sd_devsw_install();
#endif /*JREMOD */
---------------------somewhere that's run during bootup: EVENTUALLY a SYSINIT
#ifdef JREMOD
sd_devsw_install();
#endif /*JREMOD*/
-----------------------at the bottom:
#ifdef JREMOD
struct bdevsw sd_bdevsw =
{ sdopen, sdclose, sdstrategy, sdioctl, /*4*/
sddump, sdsize, 0 };
struct cdevsw sd_cdevsw =
{ sdopen, sdclose, rawread, rawwrite, /*13*/
sdioctl, nostop, nullreset, nodevtotty,/* sd */
seltrue, nommap, sdstrategy };
static sd_devsw_installed = 0;
static void sd_devsw_install()
{
dev_t descript;
if( ! sd_devsw_installed ) {
descript = makedev(CDEV_MAJOR,0);
cdevsw_add(&descript,&sd_cdevsw,NULL);
#if defined(BDEV_MAJOR)
descript = makedev(BDEV_MAJOR,0);
bdevsw_add(&descript,&sd_bdevsw,NULL);
#endif /*BDEV_MAJOR*/
sd_devsw_installed = 1;
}
}
#endif /* JREMOD */
1995-11-28 09:42:06 +00:00
|
|
|
}
|
1995-11-29 10:49:16 +00:00
|
|
|
|
|
|
|
SYSINIT(cxdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cx_drvinit,NULL)
|
|
|
|
|
|
|
|
|
1995-12-08 11:19:42 +00:00
|
|
|
#endif
|