summaryrefslogtreecommitdiff
path: root/i386/i386at/com.c
diff options
context:
space:
mode:
authorThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
committerThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
commitf07a4c844da9f0ecae5bbee1ab94be56505f26f7 (patch)
tree12b07c7e578fc1a5f53dbfde2632408491ff2a70 /i386/i386at/com.c
Initial source
Diffstat (limited to 'i386/i386at/com.c')
-rw-r--r--i386/i386at/com.c891
1 files changed, 891 insertions, 0 deletions
diff --git a/i386/i386at/com.c b/i386/i386at/com.c
new file mode 100644
index 0000000..113387f
--- /dev/null
+++ b/i386/i386at/com.c
@@ -0,0 +1,891 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1994,1993,1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <com.h>
+#if NCOM > 0
+
+#include <mach/std_types.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <device/conf.h>
+#include <device/errno.h>
+#include <device/tty.h>
+#include <device/io_req.h>
+
+#include <i386/ipl.h>
+#include <i386/pio.h>
+#include <i386/machspl.h>
+#include <chips/busses.h>
+#include <i386at/comreg.h>
+
+#include <rc.h>
+#include <cons.h>
+
+extern void timeout(), ttrstrt();
+
+int comprobe(), comintr(), comstart(), commctl();
+void comattach();
+static void comparam();
+int comstop(), comgetstat(), comsetstat();
+
+static vm_offset_t com_std[NCOM] = { 0 };
+struct bus_device *cominfo[NCOM];
+struct bus_driver comdriver = {
+ comprobe, 0, comattach, 0, com_std, "com", cominfo, 0, 0, 0};
+
+struct tty com_tty[NCOM];
+int commodem[NCOM];
+int comcarrier[NCOM] = {0, 0,};
+boolean_t comfifo[NCOM];
+boolean_t comtimer_active;
+int comtimer_state[NCOM];
+
+#if RCLINE >= 0
+#define RCBAUD B9600
+static struct bus_device *comcndev;
+int comcnprobe(struct consdev *cp);
+int comcninit(struct consdev *cp);
+int comcngetc(dev_t dev, int wait);
+int comcnputc(dev_t dev, int c);
+#endif
+
+#ifndef PORTSELECTOR
+#define ISPEED B9600
+#define IFLAGS (EVENP|ODDP|ECHO|CRMOD)
+#else
+#define ISPEED B4800
+#define IFLAGS (EVENP|ODDP)
+#endif
+
+u_short divisorreg[] = {
+ 0, 2304, 1536, 1047, /* 0, 50, 75, 110*/
+ 857, 768, 576, 384, 192, /* 134.5, 150, 200, 300, 600*/
+ 96, 64, 48, /* 1200, 1800, 2000, 2400 */
+ 24, 12, /* 3600, 4800, 7200, 9600 */
+ 6, 3, 2}; /* 19200, 38400, 56000 */
+
+
+/*
+ *
+ * Probes are called during kernel boot: return 1 to mean that
+ * the relevant device is present today.
+ *
+ */
+int
+comprobe_general(struct bus_device *dev, int noisy)
+{
+ u_short addr = dev->address;
+ int unit = dev->unit;
+ int oldctl, oldmsb;
+ char *type = "8250";
+ int i;
+
+ if ((unit < 0) || (unit > NCOM)) {
+ printf("com %d out of range\n", unit);
+ return(0);
+ }
+ oldctl = inb(LINE_CTL(addr)); /* Save old value of LINE_CTL */
+ oldmsb = inb(BAUD_MSB(addr)); /* Save old value of BAUD_MSB */
+ outb(LINE_CTL(addr), 0); /* Select INTR_ENAB */
+ outb(BAUD_MSB(addr), 0);
+ if (inb(BAUD_MSB(addr)) != 0)
+ {
+ outb(LINE_CTL(addr), oldctl);
+ outb(BAUD_MSB(addr), oldmsb);
+ return 0;
+ }
+ outb(LINE_CTL(addr), iDLAB); /* Select BAUD_MSB */
+ outb(BAUD_MSB(addr), 255);
+ if (inb(BAUD_MSB(addr)) != 255)
+ {
+ outb(LINE_CTL(addr), oldctl);
+ outb(BAUD_MSB(addr), oldmsb);
+ return 0;
+ }
+ outb(LINE_CTL(addr), 0); /* Select INTR_ENAB */
+ if (inb(BAUD_MSB(addr)) != 0) /* Check that it has kept its value*/
+ {
+ outb(LINE_CTL(addr), oldctl);
+ outb(BAUD_MSB(addr), oldmsb);
+ return 0;
+ }
+
+ /* Com port found, now check what chip it has */
+
+ for(i = 0; i < 256; i++) /* Is there Scratch register */
+ {
+ outb(SCR(addr), i);
+ if (inb(SCR(addr)) != i)
+ break;
+ }
+ if (i == 256)
+ { /* Yes == 450 or 460 */
+ outb(SCR(addr), 0);
+ type = "82450 or 16450";
+ outb(FIFO_CTL(addr), iFIFOENA | iFIFO14CH); /* Enable fifo */
+ if ((inb(FIFO_CTL(addr)) & iFIFO14CH) != 0)
+ { /* Was it successfull */
+ /* if both bits are not set then broken xx550 */
+ if ((inb(FIFO_CTL(addr)) & iFIFO14CH) == iFIFO14CH)
+ {
+ type = "82550 or 16550";
+ comfifo[unit] = TRUE;
+ }
+ else
+ {
+ type = "82550 or 16550 with non-working FIFO";
+ }
+ outb(INTR_ID(addr), 0x00); /* Disable fifos */
+ }
+ }
+ if (noisy)
+ printf("com%d: %s chip.\n", unit, type);
+ return 1;
+}
+
+/*
+ * Probe routine for use during kernel startup when it is probing
+ * all of bus_device_init
+ */
+int
+comprobe(int port, struct bus_device *dev)
+{
+ return comprobe_general(dev, /*noisy*/ 1);
+}
+
+#if RCLINE >= 0
+/*
+ * Probe routine for use by the console
+ */
+int
+comcnprobe(struct consdev *cp)
+{
+ struct bus_device *b;
+ int maj, unit, pri;
+
+ maj = 0;
+ unit = -1;
+ pri = CN_DEAD;
+
+ for (b = bus_device_init; b->driver; b++)
+ if (strcmp(b->name, "com") == 0
+ && b->unit == RCLINE
+ && comprobe_general(b, /*quiet*/ 0))
+ {
+ /* Found one */
+ comcndev = b;
+ unit = b->unit;
+ pri = CN_REMOTE;
+ break;
+ }
+
+ cp->cn_dev = makedev(maj, unit);
+ cp->cn_pri = pri;
+}
+#endif
+
+
+/*
+ *
+ * Device Attach's are called during kernel boot, but only if the matching
+ * device Probe returned a 1.
+ *
+ */
+void
+comattach(struct bus_device *dev)
+{
+ u_char unit = dev->unit;
+ u_short addr = dev->address;
+
+ take_dev_irq(dev);
+ printf(", port = %x, spl = %d, pic = %d. (DOS COM%d)",
+ dev->address, dev->sysdep, dev->sysdep1, unit+1);
+
+/* comcarrier[unit] = addr->flags;*/
+ commodem[unit] = 0;
+
+ outb(INTR_ENAB(addr), 0);
+ outb(MODEM_CTL(addr), 0);
+ while (!(inb(INTR_ID(addr))&1)) {
+ (void) inb(LINE_STAT (addr)); /* reset overrun error etc */
+ (void) inb(TXRX (addr)); /* reset data-ready */
+ (void) inb(MODEM_STAT(addr)); /* reset modem status reg */
+ }
+}
+
+#if RCLINE >= 0
+/*
+ * Attach/init routine for console. This isn't called by
+ * configure_bus_device which sets the alive, adaptor, and minfo
+ * fields of the bus_device struct (comattach is), therefore we do
+ * that by hand.
+ */
+int
+comcninit(struct consdev *cp)
+{
+ u_char unit = comcndev->unit;
+ u_short addr = comcndev->address;
+
+ take_dev_irq(comcndev);
+
+ comcndev->alive = 1;
+ comcndev->adaptor = 0;
+ cominfo[minor(cp->cn_dev)] = comcndev;
+
+ outb(LINE_CTL(addr), iDLAB);
+ outb(BAUD_LSB(addr), divisorreg[RCBAUD] & 0xff);
+ outb(BAUD_MSB(addr), divisorreg[RCBAUD] >>8);
+ outb(LINE_CTL(addr), i7BITS|iPEN);
+ outb(INTR_ENAB(addr), 0);
+ outb(MODEM_CTL(addr), iDTR|iRTS|iOUT2);
+
+ {
+ char msg[128];
+ volatile unsigned char *p = (volatile unsigned char *)0xb8000;
+ int i;
+
+ sprintf(msg, " **** using COM port %d for console ****",
+ unit+1);
+ for (i = 0; msg[i]; i++) {
+ p[2*i] = msg[i];
+ p[2*i+1] = (0<<7) /* blink */
+ | (0x0<<4) /* bg */
+ | (1<<3) /* hi-intensity */
+ | 0x4; /* fg */
+ }
+ }
+
+}
+#endif
+
+/*
+ * Probe for COM<dev> after autoconfiguration.
+ * Used to handle PCMCIA modems, which may appear
+ * at any time.
+ */
+boolean_t com_reprobe(
+ int unit)
+{
+ struct bus_device *device;
+
+ /*
+ * Look for COM device <unit> in the device
+ * initialization list. It must not be alive
+ * (otherwise we would have opened it already).
+ */
+ for (device = bus_device_init; device->driver; device++) {
+ if (device->driver == &comdriver && device->unit == unit &&
+ !device->alive && device->ctlr == (char)-1)
+ {
+ /*
+ * Found an entry for com port <unit>.
+ * Probe it.
+ */
+ if (configure_bus_device(device->name,
+ device->address,
+ device->phys_address,
+ 0,
+ "atbus"))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+io_return_t comopen(
+ int dev,
+ int flag,
+ io_req_t ior)
+{
+ int unit = minor(dev);
+ u_short addr;
+ struct bus_device *isai;
+ struct tty *tp;
+ spl_t s;
+ io_return_t result;
+
+ if (unit >= NCOM)
+ return ENXIO; /* no such device */
+ if ((isai = cominfo[unit]) == 0 || isai->alive == 0) {
+ /*
+ * Try to probe it again
+ */
+ if (!com_reprobe(unit))
+ return ENXIO;
+ }
+ tp = &com_tty[unit];
+
+ if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0) {
+ ttychars(tp);
+ tp->t_addr = (char *)isai->address;
+ tp->t_dev = dev;
+ tp->t_oproc = comstart;
+ tp->t_stop = comstop;
+ tp->t_mctl = commctl;
+ tp->t_getstat = comgetstat;
+ tp->t_setstat = comsetstat;
+#ifndef PORTSELECTOR
+ if (tp->t_ispeed == 0) {
+#else
+ tp->t_state |= TS_HUPCLS;
+#endif /* PORTSELECTOR */
+ tp->t_ispeed = ISPEED;
+ tp->t_ospeed = ISPEED;
+ tp->t_flags = IFLAGS;
+ tp->t_state &= ~TS_BUSY;
+#ifndef PORTSELECTOR
+ }
+#endif /* PORTSELECTOR */
+ }
+/*rvb tp->t_state |= TS_WOPEN; */
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ comparam(unit);
+ addr = (int)tp->t_addr;
+
+ s = spltty();
+ if (!comcarrier[unit]) /* not originating */
+ tp->t_state |= TS_CARR_ON;
+ else {
+ int modem_stat = inb(MODEM_STAT(addr));
+ if (modem_stat & iRLSD)
+ tp->t_state |= TS_CARR_ON;
+ else
+ tp->t_state &= ~TS_CARR_ON;
+ fix_modem_state(unit, modem_stat);
+ }
+ splx(s);
+
+ result = char_open(dev, tp, flag, ior);
+
+ if (!comtimer_active) {
+ comtimer_active = TRUE;
+ comtimer();
+ }
+
+ s = spltty();
+ while(!(inb(INTR_ID(addr))&1)) { /* while pending interrupts */
+ (void) inb(LINE_STAT (addr)); /* reset overrun error */
+ (void) inb(TXRX (addr)); /* reset data-ready */
+ (void) inb(MODEM_STAT(addr)); /* reset modem status */
+ }
+ splx(s);
+ return result;
+}
+
+io_return_t comclose(dev, flag)
+int dev;
+int flag;
+{
+ struct tty *tp = &com_tty[minor(dev)];
+ u_short addr = (int)tp->t_addr;
+
+ ttyclose(tp);
+ if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) {
+ outb(INTR_ENAB(addr), 0);
+ outb(MODEM_CTL(addr), 0);
+ tp->t_state &= ~TS_BUSY;
+ commodem[minor(dev)] = 0;
+ if (comfifo[minor(dev)] != 0)
+ outb(INTR_ID(addr), 0x00); /* Disable fifos */
+ }
+ return 0;
+}
+
+io_return_t comread(dev, ior)
+int dev;
+io_req_t ior;
+{
+ return char_read(&com_tty[minor(dev)], ior);
+}
+
+io_return_t comwrite(dev, ior)
+int dev;
+io_req_t ior;
+{
+ return char_write(&com_tty[minor(dev)], ior);
+}
+
+io_return_t comportdeath(dev, port)
+dev_t dev;
+mach_port_t port;
+{
+ return (tty_portdeath(&com_tty[minor(dev)], port));
+}
+
+io_return_t
+comgetstat(dev, flavor, data, count)
+dev_t dev;
+int flavor;
+int *data; /* pointer to OUT array */
+unsigned int *count; /* out */
+{
+ io_return_t result = D_SUCCESS;
+ int unit = minor(dev);
+
+ switch (flavor) {
+ case TTY_MODEM:
+ fix_modem_state(unit, inb(MODEM_STAT(cominfo[unit]->address)));
+ *data = commodem[unit];
+ *count = 1;
+ break;
+ default:
+ result = tty_get_status(&com_tty[unit], flavor, data, count);
+ break;
+ }
+ return (result);
+}
+
+io_return_t
+comsetstat(dev, flavor, data, count)
+dev_t dev;
+int flavor;
+int * data;
+unsigned int count;
+{
+ io_return_t result = D_SUCCESS;
+ int unit = minor(dev);
+ struct tty *tp = &com_tty[unit];
+
+ switch (flavor) {
+ case TTY_SET_BREAK:
+ commctl(tp, TM_BRK, DMBIS);
+ break;
+ case TTY_CLEAR_BREAK:
+ commctl(tp, TM_BRK, DMBIC);
+ break;
+ case TTY_MODEM:
+ commctl(tp, *data, DMSET);
+ break;
+ default:
+ result = tty_set_status(&com_tty[unit], flavor, data, count);
+ if (result == D_SUCCESS && flavor == TTY_STATUS)
+ comparam(unit);
+ return (result);
+ }
+ return (D_SUCCESS);
+}
+
+comintr(unit)
+int unit;
+{
+ register struct tty *tp = &com_tty[unit];
+ u_short addr = cominfo[unit]->address;
+ static char comoverrun = 0;
+ char c, line, intr_id;
+ int line_stat;
+
+ while (! ((intr_id=(inb(INTR_ID(addr))&MASKi)) & 1))
+ switch (intr_id) {
+ case MODi:
+ /* modem change */
+ commodem_intr(unit, inb(MODEM_STAT(addr)));
+ break;
+
+ case TRAi:
+ comtimer_state[unit] = 0;
+ tp->t_state &= ~(TS_BUSY|TS_FLUSH);
+ tt_write_wakeup(tp);
+ (void) comstart(tp);
+ break;
+ case RECi:
+ case CTIi: /* Character timeout indication */
+ if (tp->t_state&TS_ISOPEN) {
+ while ((line = inb(LINE_STAT(addr))) & iDR) {
+ c = inb(TXRX(addr));
+ ttyinput(c, tp);
+ }
+ } else
+ tt_open_wakeup(tp);
+ break;
+ case LINi:
+ line_stat = inb(LINE_STAT(addr));
+
+ if ((line_stat & iPE) &&
+ ((tp->t_flags&(EVENP|ODDP)) == EVENP ||
+ (tp->t_flags&(EVENP|ODDP)) == ODDP)) {
+ /* parity error */;
+ } else if (line&iOR && !comoverrun) {
+ printf("com%d: overrun\n", unit);
+ comoverrun = 1;
+ } else if (line_stat & (iFE | iBRKINTR)) {
+ /* framing error or break */
+ ttyinput(tp->t_breakc, tp);
+ }
+ break;
+ }
+}
+
+static void
+comparam(unit)
+register int unit;
+{
+ struct tty *tp = &com_tty[unit];
+ u_short addr = (int)tp->t_addr;
+ spl_t s = spltty();
+ int mode;
+
+ if (tp->t_ispeed == B0) {
+ tp->t_state |= TS_HUPCLS;
+ outb(MODEM_CTL(addr), iOUT2);
+ commodem[unit] = 0;
+ splx(s);
+ return;
+ }
+
+ /* Do input buffering */
+ if (tp->t_ispeed >= B300)
+ tp->t_state |= TS_MIN;
+
+ outb(LINE_CTL(addr), iDLAB);
+ outb(BAUD_LSB(addr), divisorreg[tp->t_ispeed] & 0xff);
+ outb(BAUD_MSB(addr), divisorreg[tp->t_ispeed] >> 8);
+
+ if (tp->t_flags & (RAW|LITOUT|PASS8))
+ mode = i8BITS;
+ else
+ mode = i7BITS | iPEN;
+ if (tp->t_flags & EVENP)
+ mode |= iEPS;
+ if (tp->t_ispeed == B110)
+ /*
+ * 110 baud uses two stop bits -
+ * all other speeds use one
+ */
+ mode |= iSTB;
+
+ outb(LINE_CTL(addr), mode);
+
+ outb(INTR_ENAB(addr), iTX_ENAB|iRX_ENAB|iMODEM_ENAB|iERROR_ENAB);
+ if (comfifo[unit])
+ outb(FIFO_CTL(addr), iFIFOENA|iFIFO14CH);
+ outb(MODEM_CTL(addr), iDTR|iRTS|iOUT2);
+ commodem[unit] |= (TM_DTR|TM_RTS);
+ splx(s);
+}
+
+comparm(int unit, int baud, int intr, int mode, int modem)
+{
+ u_short addr = (u_short)(cominfo[unit]->address);
+ spl_t s = spltty();
+
+ if (unit != 0 && unit != 1) {
+ printf("comparm(unit, baud, mode, intr, modem)\n");
+ splx(s);
+ return;
+ }
+ outb(LINE_CTL(addr), iDLAB);
+ outb(BAUD_LSB(addr), divisorreg[baud] & 0xff);
+ outb(BAUD_MSB(addr), divisorreg[baud] >> 8);
+ outb(LINE_CTL(addr), mode);
+ outb(INTR_ENAB(addr), intr);
+ outb(MODEM_CTL(addr), modem);
+ splx(s);
+}
+
+int comst_1, comst_2, comst_3, comst_4, comst_5 = 14;
+
+int
+comstart(tp)
+struct tty *tp;
+{
+ char nch;
+ int i;
+
+ if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP|TS_BUSY)) {
+comst_1++;
+ return(0);
+ }
+ if ((!queue_empty(&tp->t_delayed_write)) &&
+ (tp->t_outq.c_cc <= TTLOWAT(tp))) {
+comst_2++;
+ tt_write_wakeup(tp);
+ }
+ if (!tp->t_outq.c_cc) {
+comst_3++;
+ return(0);
+ }
+
+#if 0
+ i = (comfifo[minor(tp->t_dev)]) ? /*14*/comst_5 : 1;
+
+ tp->t_state |= TS_BUSY;
+ while (i-- > 0) {
+ nch = getc(&tp->t_outq);
+ if (nch == -1) break;
+ if ((nch & 0200) && ((tp->t_flags & LITOUT) == 0)) {
+ timeout(ttrstrt, (char *)tp, (nch & 0x7f) + 6);
+ tp->t_state |= TS_TIMEOUT;
+comst_4++;
+ return(0);
+ }
+ outb(TXRX((int)tp->t_addr), nch);
+ }
+#else
+ nch = getc(&tp->t_outq);
+ if ((nch & 0200) && ((tp->t_flags & LITOUT) == 0)) {
+ timeout(ttrstrt, (char *)tp, (nch & 0x7f) + 6);
+ tp->t_state |= TS_TIMEOUT;
+comst_4++;
+ return(0);
+ }
+ outb(TXRX((int)tp->t_addr), nch);
+ tp->t_state |= TS_BUSY;
+#endif
+ return(0);
+}
+
+/* Check for stuck xmitters */
+int comtimer_interval = 5;
+
+comtimer()
+{
+ spl_t s = spltty();
+ struct tty *tp = com_tty;
+ int i, nch;
+
+ for (i = 0; i < NCOM; i++, tp++) {
+ if ((tp->t_state & TS_ISOPEN) == 0)
+ continue;
+ if (!tp->t_outq.c_cc)
+ continue;
+ if (++comtimer_state[i] < 2)
+ continue;
+ /* Its stuck */
+printf("Tty %x was stuck\n", tp);
+ nch = getc(&tp->t_outq);
+ outb(TXRX((int)tp->t_addr), nch);
+ }
+
+ splx(s);
+ timeout(comtimer, 0, comtimer_interval*hz);
+}
+
+/*
+ * Set receive modem state from modem status register.
+ */
+fix_modem_state(unit, modem_stat)
+int unit, modem_stat;
+{
+ int stat = 0;
+
+ if (modem_stat & iCTS)
+ stat |= TM_CTS; /* clear to send */
+ if (modem_stat & iDSR)
+ stat |= TM_DSR; /* data set ready */
+ if (modem_stat & iRI)
+ stat |= TM_RNG; /* ring indicator */
+ if (modem_stat & iRLSD)
+ stat |= TM_CAR; /* carrier? */
+
+ commodem[unit] = (commodem[unit] & ~(TM_CTS|TM_DSR|TM_RNG|TM_CAR))
+ | stat;
+}
+
+/*
+ * Modem change (input signals)
+ */
+commodem_intr(
+ int unit,
+ int stat)
+{
+ int changed;
+
+ changed = commodem[unit];
+ fix_modem_state(unit, stat);
+ stat = commodem[unit];
+
+ /* Assumption: if the other party can handle
+ modem signals then it should handle all
+ the necessary ones. Else fix the cable. */
+
+ changed ^= stat; /* what changed ? */
+
+ if (changed & TM_CTS)
+ tty_cts( &com_tty[unit], stat & TM_CTS );
+
+#if 0
+ if (changed & TM_CAR)
+ ttymodem( &com_tty[unit], stat & TM_CAR );
+#endif
+
+}
+
+/*
+ * Set/get modem bits
+ */
+commctl(
+ register struct tty *tp,
+ int bits,
+ int how)
+{
+ spl_t s;
+ int unit;
+ vm_offset_t dev_addr;
+ register int b;
+
+ unit = minor(tp->t_dev);
+
+ if (bits == TM_HUP) { /* close line (internal) */
+ bits = TM_DTR | TM_RTS;
+ how = DMBIC;
+ }
+
+ if (how == DMGET) return commodem[unit];
+
+ dev_addr = cominfo[unit]->address;
+
+ s = spltty();
+
+ switch (how) {
+ case DMSET:
+ b = bits; break;
+ case DMBIS:
+ b = commodem[unit] | bits; break;
+ case DMBIC:
+ b = commodem[unit] & ~bits; break;
+ }
+ commodem[unit] = b;
+
+ if (bits & TM_BRK) {
+ if (b & TM_BRK) {
+ outb(LINE_CTL(dev_addr), inb(LINE_CTL(dev_addr)) | iSETBREAK);
+ } else {
+ outb(LINE_CTL(dev_addr), inb(LINE_CTL(dev_addr)) & ~iSETBREAK);
+ }
+ }
+
+#if 0
+ /* do I need to do something on this ? */
+ if (bits & TM_LE) { /* line enable */
+ }
+#endif
+#if 0
+ /* Unsupported */
+ if (bits & TM_ST) { /* secondary transmit */
+ }
+ if (bits & TM_SR) { /* secondary receive */
+ }
+#endif
+ if (bits & (TM_DTR|TM_RTS)) { /* data terminal ready, request to send */
+ how = iOUT2;
+ if (b & TM_DTR) how |= iDTR;
+ if (b & TM_RTS) how |= iRTS;
+ outb(MODEM_CTL(dev_addr), how);
+ }
+
+ splx(s);
+
+ /* the rest are inputs */
+ return commodem[unit];
+}
+
+comstop(tp, flags)
+register struct tty *tp;
+int flags;
+{
+ if ((tp->t_state & TS_BUSY) && (tp->t_state & TS_TTSTOP) == 0)
+ tp->t_state |= TS_FLUSH;
+}
+
+/*
+ *
+ * Code to be called from debugger.
+ *
+ */
+void compr_addr(addr)
+{
+ /* The two line_stat prints may show different values, since
+ * touching some of the registers constitutes changing them.
+ */
+ printf("LINE_STAT(%x) %x\n",
+ LINE_STAT(addr), inb(LINE_STAT(addr)));
+
+ printf("TXRX(%x) %x, INTR_ENAB(%x) %x, INTR_ID(%x) %x, LINE_CTL(%x) %x,\n\
+MODEM_CTL(%x) %x, LINE_STAT(%x) %x, MODEM_STAT(%x) %x\n",
+ TXRX(addr), inb(TXRX(addr)),
+ INTR_ENAB(addr), inb(INTR_ENAB(addr)),
+ INTR_ID(addr), inb(INTR_ID(addr)),
+ LINE_CTL(addr), inb(LINE_CTL(addr)),
+ MODEM_CTL(addr), inb(MODEM_CTL(addr)),
+ LINE_STAT(addr), inb(LINE_STAT(addr)),
+ MODEM_STAT(addr),inb(MODEM_STAT(addr)));
+}
+
+int compr(unit)
+{
+ compr_addr(cominfo[unit]->address);
+ return(0);
+}
+
+int
+comgetc(int unit)
+{
+ u_short addr = (u_short)(cominfo[unit]->address);
+ spl_t s = spltty();
+ int c;
+
+ while((inb(LINE_STAT(addr)) & iDR) == 0) ;
+
+ c = inb(TXRX(addr));
+ splx(s);
+ return c;
+}
+
+#if RCLINE >= 0
+/*
+ * Routines for the console
+ */
+int
+comcnputc(dev_t dev, int c)
+{
+ u_short addr = (u_short)(cominfo[minor(dev)]->address);
+
+ /* Wait for transmitter to empty */
+ while((inb(LINE_STAT(addr)) & iTHRE) == 0)
+ continue;
+
+ /* send the char */
+ if (c == '\n')
+ comcnputc(dev, '\r');
+ outb(addr, c);
+}
+
+int
+comcngetc(dev_t dev, int wait)
+{
+ u_short addr = (u_short)(cominfo[minor(dev)]->address);
+ int c;
+
+ while((inb(LINE_STAT(addr)) & iDR) == 0)
+ if (! wait)
+ return 0;
+
+ c = inb(TXRX(addr));
+ return c & 0x7f;
+}
+#endif /* RCLINE */
+
+#endif /* NCOM */