Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 31 Mar 1995 02:57:38 -0800 (PST)
From:      brian@mediacity.com (Brian Litzinger)
To:        freebsd-current@FreeBSD.org
Subject:   cyb2.0bf
Message-ID:  <m0rueOZ-000rccC@easynet.com>

next in thread | raw e-mail | index | archive | help
Following is a modified version of the cyb driver which includes:

    ttyinput speedups for raw input
    increased the fifo interrupt point a little
    updated to 2.1.0-Development scheme

Brian Litzinger
brian@easynet.com


# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	readme.src
#	cybreg.h
#	cl-cd1400.h
#	cyb.c
#
echo x - readme.src
sed 's/^X//' >readme.src << 'END-of-readme.src'
XCyclades Cyclom 8Y/8Yo/16Y driver for FreeBSD 2.1.0-Development
X
XBy Brian E. Litzinger  <brian@mpress.com>
X
XCopyright 1995 By Brian E. Litzinger
X
X--------------------------------------------------------------------
X
XYou must reverse the sense of RTS and DTR in the Cyclades manual!
X
XThis driver reverses their usage to correctly implement full duplex
Xhardware handshaking.
X
XWhich means, there is no DTR on the 8Y RJ12 connector.  The DTR pin
Xin the manual becomes RTS.  DTR does exist in the 16Y and the 8Yo.
X
XIn your i386/conf/LOCAL or whatever file you must add the following lines:
Xand you should make sure the fields match what you set on the board.
X
Xdevice cyb0 at isa? tty irq 15 iomem 0xd8000 iosiz 8192 vector cybintr
X
XAdd this near the end of i386/conf/files.i386:
X
Xi386/isa/cyb.c                  optional        cyb     device-driver
X
Xsomewhere in i386/i386/conf.c add:
X
X#include "cyb.h"
X#if NCYB > 0
Xd_open_t        cybopen;
Xd_close_t       cybclose;
Xd_ioctl_t       cybioctl;
Xd_rdwr_t        cybread, cybwrite;
Xd_select_t      cybselect;
Xd_stop_t        cybstop;
Xd_ttycv_t       cybdevtotty;
X#define cybreset        nxreset
X#define cybmmap         nxmmap
X#define cybstrategy     nxstrategy
X#else
X#define cybopen     (d_open_t *)enxio
X#define cybclose    (d_close_t *)enxio
X#define cybioctl    (d_ioctl_t *)enxio
X#define cybread     (d_rdwr_t *)enxio
X#define cybwrite    (d_rdwr_t *)enxio
X#define cybselect   (d_select_t *)enxio
X#define cybstop     (d_stop_t *)enxio
X#define cybdevtotty     nxdevtotty
X#define cybreset        nxreset
X#define cybmmap         nxmmap
X#define cybstrategy     nxstrategy
X#endif
X
Xthen in i386/i386/conf.c add to the cdevsw structure
X
X        { cybopen,      cybclose,       cybread,        cybwrite,       /*48*/
X	  cybioctl,     cybstop,        cybreset,       cybdevtotty, /* cyb */
X	  ttselect,     cybmmap,        cybstrategy },
X
XYou may want to replace the existing /*48*/ with this one, or you might
Xwant to put it in the local /*20*/ spot.
X
XLastly, put cyb.c, and the *.h files in i386/isa
X
XThen do a config and make depend and make and install and boot the new
Xkernel.
X
XYou should see the following in the boot text or from dmesg:
X
Xcy returned 46
Xcy returned 46
Xcy returned 46
Xcy returned 46
Xcyb at 0x0 irq 15 maddr 0xd0000 msize 8192
X ports 16
X
XAssuming you have 16Y so configured.
X
XNow go to the /dev directory and mknod the devices:
X
Xmknod ttyi0 c 48 0 0		# remember, major # may be different
Xmknod ttyi1 c 48 0 1
X...
X
XYou also need to set the permissions appropriately:
XFor bidir operations that would probably be: uucp:wheel
XFor normal ops that would probably be: root:?????
X
XBest of luck.  
X
XBrian Litzinger <brian@easynet.com>
XP.O. Box 82
XBoulder Creek, CA 95006
END-of-readme.src
echo x - cybreg.h
sed 's/^X//' >cybreg.h << 'END-of-cybreg.h'
X/*-
X * Copyright (c) 1994 By Brian E. Litzinger, All rights reserved.
X */
X
X/*
X * Definitions for Cyclades 8Y and 16Y Cyclom cards.
X */
X
X
X/*
X * Address mapping between Cirrus Logic CD1400 chip internal registers
X * and ISA port addresses:
X *
X */
X#define CY_ADDR(reg)	(reg)
X
X/* Input Byte from CL CD1400 register */
X#define rinb(base, reg)		(*((base)+CY_ADDR(reg)))
X
X/* Output Byte to CL CD1400 register */
X#define routb(base, reg, val)	(*((base)+CY_ADDR(reg))=val)
X
X#define CY_NPORT	16	/* decoder recognizes 16 addresses... */
X
X#define CD1400_MEMSIZE 0x400
X#define cy_RESET_16             0x1400                  /* cyclom-16y reset */
X#define cy_CLEAR_INTR           0x1800                  /* intr ack address */
X#define CYCLOM_CLOCK            25000000                /* baud rate clock */
X#define CD1400_CLOCK_25_1MS     0x31
X#define CD1400_NO_OF_CHANNELS   4
X#define CD1400_MAX_FIFO_SIZE    12
X
X
END-of-cybreg.h
echo x - cl-cd1400.h
sed 's/^X//' >cl-cd1400.h << 'END-of-cl-cd1400.h'
X/*-
X * Copyright (c) 1994 By Brian E. Litzinger, All rights reserved.
X */
X
X/*
X * Definitions for Cirrus Logic CL-CD1400 4-port async mux chip
X */
X
X#define CD1400_NCHAN	 4	/* Total number of channels */
X#define CD1400_TPC	16	/* Ticks per character */
X
X/*
X * Global Registers
X */
X#define CD1400_GFRCR            2*0x40  /* global firmware revision code */
X#define CD1400_CAR              2*0x68  /* channel access */
X#define CD1400_GCR              2*0x4b  /* global config  */
X#define CD1400_SVRR             2*0x67  /* service request */
X#define CD1400_RICR             2*0x44  /* receive intr channel */
X#define CD1400_TICR             2*0x45  /* transmit intr channel */
X#define CD1400_MICR             2*0x46  /* modem intr channel */
X#define CD1400_RIR              2*0x6B  /* receive interrupt status */
X#define CD1400_TIR              2*0x6A  /* transmit interrupt status */
X#define CD1400_MIR              2*0x69  /* modem interrupt status */
X#define CD1400_PPR              2*0x7e
X
X/*
X    Virtual Registers
X*/
X#define CD1400_RIVR             2*0x43  /* receive intr vector */
X#define CD1400_TIVR             2*0x42  /* transmit intr vector */
X#define CD1400_MIVR             2*0x41  /* modem intr vector */
X#define CD1400_LIVR             2*0x18  /* local intr vector */
X#define CD1400_TDR              2*0x63  /* tx data */
X#define CD1400_RDSR             2*0x62  /* rx data/status */
X#define CD1400_MISR             2*0x4c  /* modem intr status */
X#define CD1400_EOSRR            2*0x60  /* end of service request */
X
X
X
X/*
X * Channel Registers
X */
X#define CD1400_LIVR             2*0x18  /* local intr vector */
X#define CD1400_CCR              2*0x05  /* channel control */
X#define CD1400_SRER             2*0x06  /* service request enable */
X#define CD1400_COR1             2*0x08  /* channel option 1 */
X#define CD1400_COR2             2*0x09  /* channel option 2 */
X#define CD1400_COR3             2*0x0A  /* channel option 3 */
X#define CD1400_COR4             2*0x1E  /* channel option 4 */
X#define CD1400_COR5             2*0x1F  /* channel option 5 */
X#define CD1400_CCSR             2*0x0b  /* channel control status */
X#define CD1400_RDCR             2*0x0e  /* rx data count */
X#define CD1400_SCHR1            2*0x1A  /* special character 1 */
X#define CD1400_SCHR2            2*0x1B  /* special character 2 */
X#define CD1400_SCHR3            2*0x1C  /* special character 3 */
X#define CD1400_SCHR4            2*0x1D  /* special character 4 */
X#define CD1400_SCRL             2*0x22  /* special char range, low */
X#define CD1400_SCRH             2*0x23  /* special char range, high */
X#define CD1400_LNC              2*0x24  /* LNext character */
X#define CD1400_MCOR1            2*0x15  /* modem change 1 */
X#define CD1400_MCOR2            2*0x16  /* modem change 2 */
X#define CD1400_RTPR             2*0x21  /* receive timeout period */
X#define CD1400_MSVR1            2*0x6c  /* modem signals */
X#define CD1400_MSVR2            2*0x6d  /* modem signals */
X
X#define CD1400_RBPR             2*0x78  /* receive baud rate period */
X#define CD1400_RCOR             2*0x7C  /* receive clock option */
X#define CD1400_TBPR             2*0x72  /* transmit baud rate period */
X#define CD1400_TCOR             2*0x76  /* transmit clock option */
X
X/*
X * Channel Address Register
X */
X#define CAR_CHAN	0x7	/* Channel Number Mask */
X
X/*
X * Channel Command Register
X * (commands in groups can be OR-ed)
X */
X#define CCR_HARDRESET	0x81	/* Reset the chip */
X
X#define CCR_SOFTRESET	0x80	/* Soft Channel Reset */
X
X#define CCR_CORCHG1	0x42	/* Channel Option Register 1 Changed */
X#define CCR_CORCHG2	0x44	/* Channel Option Register 2 Changed */
X#define CCR_CORCHG3	0x48	/* Channel Option Register 3 Changed */
X
X#define CCR_SSCH1	0x21	/* Send Special Character 1 */
X
X#define CCR_SSCH2	0x22	/* Send Special Character 2 */
X
X#define CCR_SSCH3	0x23	/* Send Special Character 3 */
X
X#define CCR_SSCH4	0x24	/* Send Special Character 4 */
X
X#define CCR_TXEN	0x18	/* Enable Transmitter */
X#define CCR_RXEN	0x12	/* Enable Receiver */
X
X#define CCR_TXDIS	0x14	/* Diasable Transmitter */
X#define CCR_RXDIS	0x11	/* Diasable Receiver */
X
X/*
X * Channel Option Register 1
X */
X#define COR1_ODDP	0x80	/* Odd Parity */
X#define COR1_PARMODE	0x60	/* Parity Mode mask */
X#define  COR1_NOPAR	 0x0	 /* No Parity */
X#define  COR1_FORCEPAR	 0x20	 /* Force Parity */
X#define  COR1_NORMPAR	 0x40	 /* Normal Parity */
X#define COR1_IGNORE	0x10	/* Ignore Parity on RX */
X#define COR1_STOPBITS	0xc	/* Number of Stop Bits */
X#define  COR1_1SB	 0x0	 /* 1 Stop Bit */
X#define  COR1_15SB	 0x4	 /* 1.5 Stop Bits */
X#define  COR1_2SB	 0x8	 /* 2 Stop Bits */
X#define COR1_CHARLEN	0x3	/* Character Length */
X#define	 COR1_5BITS	 0x0	 /* 5 bits */
X#define	 COR1_6BITS	 0x1	 /* 6 bits */
X#define	 COR1_7BITS	 0x2	 /* 7 bits */
X#define	 COR1_8BITS	 0x3	 /* 8 bits */
X
X/*
X * Channel Option Register 2
X */
X#define COR2_IXM	0x80	/* Implied XON mode */
X#define COR2_TXIBE	0x40	/* Enable In-Band (XON/XOFF) Flow Control */
X#define COR2_ETC	0x20	/* Embedded Tx Commands Enable */
X#define COR2_LLM	0x10	/* Local Loopback Mode */
X#define COR2_RLM	0x8	/* Remote Loopback Mode */
X#define COR2_RTSAO	0x4	/* RTS Automatic Output Enable */
X#define COR2_CTSAE	0x2	/* CTS Automatic Enable */
X#define COR2_DSRAE	0x1	/* DSR Automatic Enable */
X
X/*
X * Channel Option Register 3
X */
X#define COR3_XONCH	0x80	/* XON is a pair of characters (spec. 1&3) */
X#define COR3_XOFFCH	0x40	/* XOFF is a pair of characters (2&4) */
X#define COR3_FCT	0x20	/* Flow-Control Transparency Mode */
X#define COR3_SCDE	0x10	/* Special Character Detection Enable */
X#define COR3_RXTH	0xf	/* RX FIFO Threshold value (1-12) */
X
X/*
X  Channel Option Register 4
X*/
X#define COR4_IGNCR   0x80
X#define COR4_ICRNL   0x40
X#define COR4_INLCR   0x20
X#define COR4_IGNBRK  0x10
X#define COR4_NBRKINT 0x08
X#define COR4_PFOEXCP 0x00
X#define COR4_PFOGOOD 0x01
X#define COR4_PFODISC 0x02
X#define COR4_PFONULL 0x03
X#define COR4_PFOMARK 0x04
X
X/*
X  Channel Option Register 5
X*/
X
X#define COR5_ISTRIP 0x80
X#define COR5_IEXTEN 0x40
X#define COR5_ONLCR  0x02
X#define COR5_OCRNL  0x01
X
X/*
X * Modem Change Option Register 1
X */
X#define MCOR1_DSRZD	0x80	/* Detect 0->1 transition of DSR */
X#define MCOR1_CTSZD	0x40	/* Detect 0->1 transition of CTS */
X#define MCOR1_RIZD	0x20	/* Detect 0->1 transition of RI */
X#define MCOR1_CDZD	0x10	/* Detect 0->1 transition of CD */
X#define MCOR1_DTRTH	0xf	/* Automatic DTR flow control Threshold (1-12)*/
X#define MCOR1_NODTRFC	0x0	/* Automatic DTR flow control disabled */
X
X/*
X * Modem Change Option Register 2
X */
X#define MCOR2_DSROD	0x80	/* Detect 1->0 transition of DSR */
X#define MCOR2_CTSOD	0x40	/* Detect 1->0 transition of CTS */
X#define MCOR2_RIOD	0x20	/* Detect 1->0 transition of RI */
X#define MCOR2_CDOD	0x10	/* Detect 1->0 transition of CD */
X
X/*
X * Modem Signal Value Registers
X */
X#define MSVR2_DSR	0x80	/* Current state of DSR input */
X#define MSVR2_CTS	0x40	/* Current state of CTS input */
X#define MSVR2_RI 	0x20	/* Current state of RI  input */
X#define MSVR2_CD	0x10	/* Current state of CD  input */
X#define MSVR2_DTR	0x02	/* Current state of DTR output */
X
X#define MSVR1_RTS	0x01	/* Current state of RTS output */
X
X/*
X * Escape characters
X */
X#define CD1400_C_ESC	0x0	/* Escape character */
X#define CD1400_C_SBRK	0x81	/* Start sending BREAK */
X#define CD1400_C_DELAY	0x82	/* Delay output */
X#define CD1400_C_EBRK	0x83	/* Stop sending BREAK */
X
X#define MISR_CDCHG 0x10
X
X
X#define CD1400_SVRR_RX  0x01
X#define CD1400_SVRR_TX  0x02
X#define CD1400_SVRR_MDM 0x04
X
X#define SRER_MDM  0x80
X#define SRER_RXD  0x10
X#define SRER_TXD  0x04
X#define SRER_NNDT 0x01
END-of-cl-cd1400.h
echo x - cyb.c
sed 's/^X//' >cyb.c << 'END-of-cyb.c'
X/*-
X * Copyright (c) 1995 By Brian E. Litzinger. All rights reserved.
X *
X * <brian@mpress.com>
X */
X
X/*
X
X*/
X/*
X * cyclades
X */
X
X#include "cyb.h"
X#if NCYB > 0
X/* #define CYDEBUG 1 */
X
X#include <sys/param.h>
X#include <sys/systm.h>
X#include <sys/ioctl.h>
X#include <sys/tty.h>
X#include <sys/proc.h>
X#include <sys/user.h>
X#include <sys/conf.h>
X#include <sys/file.h>
X#include <sys/uio.h>
X#include <sys/kernel.h>
X#include <sys/syslog.h>
X#include <sys/device.h>
X#include "sys/devconf.h"
X
X#include "machine/cpufunc.h"
X#include "machine/clock.h"
X
X#include "i386/isa/isa.h"
X#include "i386/isa/isa_device.h"
X#include "i386/isa/icu.h"
X
X#include "i386/isa/cybreg.h"
X#include "i386/isa/cl-cd1400.h"
X
X#define POLLSLICE 100 /*ms*/
X
X
X#define dprintf(x)	/* */
X#define UNIT(dev)	(((dev)>>5)&0x03)
X#define LINE(dev)	((dev)&0x1f)
X
X#define MAX_CHAN 16
X#define FastRawInput
X
X
Xstruct cybsoftc {
X	struct  tty cyb_tty[MAX_CHAN];  /* Per-channel tty structures */
X	short	cy_softdtr;		/* software copy of DTR */
X	short	cy_txint;		/* TX interrupt is in progress */
X	short   cy_inintr;		/* Interrupt in progess */
X	short   cy_pollactive;          /* Polling active */
X	caddr_t	cy_addr[MAX_CHAN];	/* base i/o address */
X	char	cy_init[MAX_CHAN];	/* line has been inited since reset */
X	char	cy_cmd[MAX_CHAN];	/* command bytes per channels */
X	char	cy_pendesc[MAX_CHAN];   /* pending escapes */
X	u_int	cy_orun[MAX_CHAN];	/* overruns */
X        unsigned char cy_srer[MAX_CHAN];
X        caddr_t cy_base;
X        int     cy_NbrCD1400s;
X        int     cy_NbrPorts;
X	struct  kern_devconf kdc; /* kernel configuration database info */
X} cybsoftc[NCYB];
X
X/*
X * cybmctl commands
X */
Xenum cybmctl_cmds { GET, SET, BIS, BIC };
X
Xint cybprobe __P((struct isa_device *));
Xint cybattach __P((struct isa_device *));
Xint cybopen __P((dev_t, int, int, struct proc *));
Xint cybclose __P((dev_t, int, int, struct proc *));
Xint cybread __P((dev_t, struct uio *, int));
Xint cybwrite __P((dev_t, struct uio *, int));
Xvoid cybintr __P((int));
Xvoid cybstart __P((struct tty *));
Xint cybioctl __P((dev_t, int, caddr_t, int, struct proc *));
Xstatic void cybchancmd __P((caddr_t, int));
Xint cybparam __P((struct tty *, struct termios *));
Xint cybselect __P((dev_t, int, struct proc *));
Xvoid cybstop __P((struct tty *, int));
Xstatic void cybcd1400init __P((int));
Xstatic int cybmctl __P((dev_t, enum cybmctl_cmds, int));
Xstatic int cybspeed __P((long, int *));
Xstatic void cybpoll();
X
Xstruct isa_driver cybdriver = { cybprobe, cybattach, "cyb" };
X
Xstatic struct kern_devconf kdc_tm_template = {
X        0, 0, 0,                /* filled in by dev_attach */
X        "cyb", 0, { MDDT_ISA, 0, "tty" },
X        isa_generic_externalize, 0, 0, ISA_EXTERNALLEN,
X        &kdc_isa0,              /* parent */
X        0,                      /* parentdata */
X        DC_UNCONFIGURED,
X        "Cyclades-BEL"          /* description */
X};
X 
X
Xstatic inline void
Xcyb_registerdev(struct isa_device *id, const char *descr)
X{
X        struct kern_devconf *kdc = &cybsoftc[id->id_unit].kdc;
X        char *longdescr;
X        *kdc = kdc_tm_template;
X        kdc->kdc_unit = id->id_unit;
X        kdc->kdc_parentdata = id;
X        kdc->kdc_description = descr;
X        dev_attach(kdc);
X}
X
X/*
X * Probe routine
X */
Xint
Xcybprobe(struct isa_device *isa_dev) {   
X    struct cybsoftc *sc = &cybsoftc[isa_dev->id_unit];
X 
X    int i,j;
X    caddr_t b;
X    int flags;
X    int ports;
X    int NbrCD1400s;
X    unsigned char version;
X
X
X    cyb_registerdev(isa_dev,"Cyclades-BEL");
X
X#define TEST_FOR_NbrCD1400s 4
X
X    NbrCD1400s = 0;
X
X    b = isa_dev->id_maddr;
X
X    (void) rinb(b,cy_RESET_16);
X    DELAY(500);
X
X    for (i=0; i<TEST_FOR_NbrCD1400s; i++) {
X        caddr_t base = b + i * CD1400_MEMSIZE;
X
X        /* wait for chip to become ready for new command */
X        for (j = 0; j < 500; j += 50) {
X            DELAY(50);  /* wait 50 us */
X            if (!rinb(base,CD1400_CCR)) {
X                break;
X            }
X        }
X
X        /* clear the GFRCR register */
X        routb(base,CD1400_GFRCR,0);
X
X        /* issue a reset command */
X        routb(base,CD1400_CCR,CCR_HARDRESET);
X
X        /* wait for the CD1400 to initialize itself */
X        for (j = 0; j < 10000; j += 50) {
X            DELAY(50);  /* wait 50 us */
X
X            /* retrieve firmware version */
X            version = rinb(base,CD1400_GFRCR);
X            if ((version&0xf0)==0x40)
X                break;
X        }
X
X        printf("cy returned %x\n",version);
X        /* anything in the 40-4f range is fine */
X        if ((version & 0xf0) == 0x40) {
X	    NbrCD1400s++;
X        } else {
X            break;
X	}
X    }
X    sc->cy_NbrCD1400s = NbrCD1400s;
X    return (NbrCD1400s>0);
X}
X
X/*
X * Attach routine
X */
Xint
Xcybattach(struct isa_device *isa_dev) {
X	register struct cybsoftc *sc = &cybsoftc[isa_dev->id_unit];
X	register caddr_t base;
X	caddr_t b;
X        int flags;
X        int i,j,k;
X
X
X        sc->cy_NbrPorts   = sc->cy_NbrCD1400s * 4;
X        printf(" ports %d",sc->cy_NbrPorts);
X
X
X	sc->cy_base = b = isa_dev->id_maddr;
X
X	for (i=0,k=0;i<sc->cy_NbrCD1400s;i++) {
X	    base = b + i * CD1400_MEMSIZE;
X	    routb(base, CD1400_PPR, CD1400_CLOCK_25_1MS);
X	    for (j=0;j<CD1400_NO_OF_CHANNELS;j++,k++) {
X		sc->cy_addr[k] = base;
X		/* cy_channel_init */
X		routb(base, CD1400_CAR, j&0x03);
X		cybchancmd(base,CCR_SOFTRESET);
X		routb(base, CD1400_LIVR, 0);
X	    }
X	}
X
X	routb(b,cy_CLEAR_INTR,0);	/* Clear interrupts */
X
X	/* Initialize interrupt/id structures */
X
X	bzero(&sc->cyb_tty,sizeof(struct tty)*MAX_CHAN);
X
X#if 0
X	strcpy(sc->cy_ttydev.tty_name, cycd.cd_name);
X	sc->cy_ttydev.tty_unit = sc->cy_dev.dv_unit;
X	sc->cy_ttydev.tty_base = sc->cy_dev.dv_unit * 16;
X	sc->cy_ttydev.tty_count = sc->cy_NbrPorts;
X	sc->cy_ttydev.tty_ttys = sc->cy_tty;
X	tty_attach(&sc->cy_ttydev);
X#endif
X	sc->cy_inintr = 0;
X	sc->cy_pollactive = 1;
X#ifdef cy_STATS
X        sc->cy_statclk = 1000;	/* 1000ms = 1 sec */
X#endif
X	timeout((timeout_func_t)cybpoll,(caddr_t)sc,POLLSLICE);
X	printf("\n");
X	return(1);
X}
X
X/*
X * Open line
X */
Xint
Xcybopen(dev, flag, mode, p)
X	dev_t dev;
X	int flag;
X	int mode;
X	struct proc *p;
X{
X	register struct tty *tp;
X	int s;
X	int error;
X	register caddr_t base;
X	int unit, chan;
X	struct cybsoftc *sc;
X
X	unit = UNIT(dev);
X	sc = &cybsoftc[unit];
X	if (sc == 0) {
X	    dprintf(("&cybsoftc[%d]=0 error\n",unit));
X	    return (ENXIO);
X	}
X 
X	chan = LINE(dev);
X	if (chan >= sc->cy_NbrPorts) {
X	    dprintf(("chan %d>NbrPorts",chan));
X	    return (ENXIO);
X	}
X	tp = &sc->cyb_tty[chan];
X	base = sc->cy_addr[chan];
X	dprintf(("cybopen: base %lx, chan %d\n",base,chan));
X	tp->t_oproc = cybstart;
X	tp->t_param = cybparam;
X	tp->t_dev = dev;
X	if ((tp->t_state & TS_ISOPEN) == 0) {
X		tp->t_state |= TS_WOPEN;
X		if (tp->t_ispeed == 0) {
X		    tp->t_iflag = 0;
X		    tp->t_oflag = 0;
X		    tp->t_cflag = TTYDEF_CFLAG;
X		    tp->t_lflag = 0;
X		    tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
X		}
X		cybparam(tp, &tp->t_termios);
X		ttsetwater(tp);
X	} else if ((tp->t_state & TS_XCLUDE) && p->p_ucred->cr_uid != 0)
X		return (EBUSY);
X
X	error = 0;
X	s = spltty();
X	(void) cybmctl(dev, SET, TIOCM_DTR|TIOCM_RTS);
X
X	routb(base, CD1400_CAR, chan&0x03);
X	if (rinb(base, CD1400_MSVR2) & MSVR2_CD) {
X		dprintf(("CD PRESENT\n"));
X		tp->t_state |= TS_CARR_ON;
X	}
X	if (!(flag & O_NONBLOCK)) {
X		while (!(tp->t_cflag & CLOCAL) && !(tp->t_state & TS_CARR_ON)) {
X			tp->t_state |= TS_WOPEN;
X			error = ttysleep(tp, (caddr_t)&tp->t_rawq,
X			    TTIPRI | PCATCH, ttopen, 0);
X			if (error) {
X				/*
X				 * Disable line and drop DTR.
X				 * Note, this is wrong if another open might
X				 * be in progress.
X				 */
X#if 1
X				/*cybchancmd(base, CCR_TXDIS | CCR_RXDIS);*/
X				sc->cy_init[chan] = 0;
X				(void) cybmctl(dev, SET, 0);
X#endif
X				break;
X			}
X		}
X	}
X	splx(s);
X	if (error == 0)
X		error = (*linesw[tp->t_line].l_open)(dev, tp);
X#ifdef cy_STATS
X	sc->stats_ints_xmit[chan] = 0;
X	sc->stats_ints_recv[chan] = 0;
X	sc->stats_ints_mdm [chan] = 0;
X#endif
X	return (error);
X}
X
X/*
X * Close line
X */
Xint
Xcybclose(dev, flag, mode, p)
X	dev_t dev;
X	int flag;
X	int mode;
X	struct proc *p;
X{
X	struct cybsoftc *sc = &cybsoftc[UNIT(dev)];
X	int chan = LINE(dev);
X	register struct tty *tp = &sc->cyb_tty[chan];
X	register caddr_t base = sc->cy_addr[chan];
X	int s;
X
X	dprintf(("cybclose: chan %d\n",chan));
X
X	s = spltty();
X	(*linesw[tp->t_line].l_close)(tp, flag);
X
X	/* Disable line */
X	routb(base, CD1400_CAR, chan&0x03);
X	cybchancmd(base, CCR_TXDIS | CCR_RXDIS);
X	sc->cy_init[chan] = 0;
X	routb(base, CD1400_SRER, sc->cy_srer[chan]=0);
X
X	/* Hang up */
X	if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) ||
X	    (tp->t_state & TS_ISOPEN) == 0)
X	    (void) cybmctl(dev, SET, 0);
X
X	ttyclose(tp);
X	splx(s);
X	if (sc->cy_orun[chan]) {
X		log(LOG_ERR, "cy%d line %d: %d overruns\n", UNIT(dev), chan,
X		    sc->cy_orun[chan]);
X		sc->cy_orun[chan] = 0;
X	}
X#ifdef cy_STATS
X	{
X		int i;
X		printf("cy%d:%d\n\t", UNIT(dev), LINE(dev));
X		for (i = 0; i < 3; i++)
X			printf("I%d=%x ", i, int_cnt[minor(dev)][i]);
X		for (i = 0; i < 2; i++)
X			printf("L%d=%x ", i, loops[UNIT(dev)][i]);
X		printf("\n");
X	}
X#endif
X	return (0);
X}
X
X/*
X * Read from line
X */
Xint
Xcybread(dev, uio, flag)
X	dev_t dev;
X	struct uio *uio;
X	int flag;
X{
X	struct cybsoftc *sc = &cybsoftc[UNIT(dev)];
X	struct tty *tp = &sc->cyb_tty[LINE(dev)];
X
X	dprintf(("cybread:\n"));
X	return ((*linesw[(u_char)tp->t_line].l_read)(tp, uio, flag));
X}
X
X/*
X * Write to line
X */
Xint
Xcybwrite(dev, uio, flag)
X	dev_t dev;
X	struct uio *uio;
X	int flag;
X{
X	struct cybsoftc *sc = &cybsoftc[UNIT(dev)];
X	struct tty *tp = &sc->cyb_tty[LINE(dev)];
X
X	dprintf(("cybwrite:\n"));
X	return ((*linesw[(u_char)tp->t_line].l_write)(tp, uio, flag));
X}
X
Xstruct tty *
Xcybdevtotty(dev_t dev)
X{
X	int chan;
X	struct cybsoftc *sc;
X	int unit;
X
X	/*
X	 * XXX UNIT() hacks on dev, should hack on minor(dev).
X	 */
X	unit = UNIT(dev);
X	/*
X	 * XXX minor bits aren't fully decoded.  This guarantees that
X	 * 0 <= unit < 0x20, so the following indexing is guaranteed valid.
X	 */
X	sc = &cybsoftc[unit];
X	/*
X	 * XXX sc is guaranteed != NULL now.  The following check will be
X	 * required when we resurrect dynamic allocation.
X	 */
X	if (sc == NULL)
X	    return (NULL);
X	chan = LINE(dev);
X	if (chan >= sc->cy_NbrPorts)
X	    return (NULL);
X	return (&sc->cyb_tty[chan]);
X}
X
X#ifdef wrong_for_FreeBSD_2_0_and_unused_for_FreeBSD_2_1
Xint
Xcybselect(dev, flag, p)
X	dev_t dev;
X	int flag;
X	struct proc *p;
X{
X	/* WARNING *** FreeBSD *** */
X	return (ttselect(dev, flag, p));
X}
X#endif
X
Xstatic void
Xcybpoll(sc)
X    struct cybsoftc *sc;
X{
X    register struct tty *tp;
X    register caddr_t base;
X    register int chan;
X    int s;
X
X    s = spltty();
X    if (sc->cy_inintr==0) {
X	for (chan=0;chan<sc->cy_NbrPorts;chan++) {
X	    tp   = &sc->cyb_tty[chan];
X
X	    if (tp->t_state&TS_BUSY /*&& (sc->cy_srer[chan]&SRER_TXD)==0*/) {
X		base = sc->cy_addr[chan];
X		dprintf(("prodding %d\n",chan));
X		routb(base, CD1400_CAR, chan&0x03);
X		routb(base, CD1400_SRER, sc->cy_srer[chan]=SRER_MDM|SRER_RXD|SRER_TXD);
X	    }
X	}
X    }
X#ifdef cy_STATS
X    sc->cy_statclk -= POLLSLICE;
X    if (sc->cy_statclk<=0) {
X
X       sc->cy_statclk = 1000;	/* 1000ms = 1 sec */
X    }
X#endif
X    splx(s);
X    if (sc->cy_pollactive)
X	timeout((timeout_func_t)cybpoll,(caddr_t)sc,POLLSLICE);
X}
X
X/*
X * Interrupt routine
X */
Xvoid
Xcybintr(int unit)
X{
X	struct cybsoftc *sc = &cybsoftc[0/*unit WARN *** */];
X	struct tty *tp;
X	int b, c;
X	unsigned cnt;
X	int chan;
X	caddr_t base;
X	int cd;
X	int domore;
X
X    sc->cy_inintr = 1;
X    dprintf(("cybintr:\n"));
X  more:
X    domore = 0;
X    for (cd=0;cd<sc->cy_NbrCD1400s;cd++) {
X	base = sc->cy_addr[cd*4]; 	/* WARNING */
X
X	dprintf(("*I%d*\n", unit));
X	if (base == 0) {
X		printf("cy%d: bogus interrupt\n", unit);
X		sc->cy_inintr = 0;
X	}
X
X	/* Read Board Status Register */
X	dprintf(("reading from %lx\n",(unsigned long)base));
X	while (b=rinb(base,CD1400_SVRR)) {
X	    domore = 1;
X	    /*
X	     * Need to add some code to allow return if this card is hogging
X	     */
X
X	    /* Receiver interrupt */
X	    if (b & CD1400_SVRR_RX) {
X		unsigned char save_rir = rinb(base,CD1400_RIR);
X		int           chan     = cd*CD1400_NO_OF_CHANNELS + (save_rir&0x03);
X		unsigned char save_car = rinb(base,CD1400_CAR);
X		routb(base,CD1400_CAR,save_rir);
X
X		tp = &sc->cyb_tty[chan];
X#ifdef cy_STATS
X		sc->stats_ints_recv[chan]++;
X#endif
X
X		switch(rinb(base,CD1400_RIVR)&0x07) {
X
X		    case 3:
X			/* Get the count of received characters */
X			cnt = rinb(base, CD1400_RDCR);
X
X			/* If the line wasn't opened, throw data into bit bucket */
X			if ((tp->t_state & TS_ISOPEN) == 0) {
X			    while (cnt--)
X				(void) rinb(base, CD1400_RDSR);
X			    goto rxout;
X			}
X
X#ifdef FastRawInput
X			if ((tp->t_line == 0) &&
X		    !(tp->t_iflag & (ICRNL|IMAXBEL|INLCR)) &&
X                    !(tp->t_lflag & (ECHO|ECHONL|ICANON|IEXTEN|ISIG|PENDIN))&&
X                    !(tp->t_state & (TS_CNTTB|TS_LNCH)) && cnt>0 ) {
X                            unsigned char buf[32]; /* *** WARNING *** */
X                            unsigned char *p = buf;
X                            int i = cnt;
X			    while (i--) {
X				*p++ = ((rinb(base, CD1400_RDSR))&0xff);
X			    }
X			    i = b_to_q(buf,cnt,&tp->t_rawq);
X                            ttwakeup(tp);
X    	    	    	} else 
X#endif
X                        {
X			    while (cnt--) {
X				c = ((rinb(base, CD1400_RDSR))&0xff);
X				(*linesw[tp->t_line].l_rint)(c, tp);
X			    }
X		 	}
X		    break;
X
X		    case 7:
X			(void) rinb(base,CD1400_RDSR); /* Get status */
X			(void) rinb(base,CD1400_RDSR); /* Get bad data */
X		    break;
X		}
X
X	      rxout:
X		routb(base,CD1400_RIR,save_rir&0x3f);
X		routb(base,CD1400_CAR,save_car);
X	    }
X
X
X
X	    /* TX interrupt? */
X	    if (b & CD1400_SVRR_TX) {
X		unsigned char save_tir = rinb(base,CD1400_TIR);
X		int           chan     = cd*CD1400_NO_OF_CHANNELS + (save_tir&0x03);
X		unsigned char save_car = rinb(base,CD1400_CAR);
X		routb(base,CD1400_CAR,save_tir);
X
X		tp = &sc->cyb_tty[chan];
X#ifdef cy_STATS
X		sc->stats_ints_xmit[chan]++;
X#endif
X
X		/* (Re-)start transmit */
X		if (tp->t_state & TS_FLUSH) {
X		    tp->t_state &= ~(TS_BUSY|TS_FLUSH);
X		    /* Disable TX interrupts */
X		    routb(base, CD1400_SRER, sc->cy_srer[chan]=SRER_MDM|SRER_RXD);
X		} else {
X		    tp->t_state &= ~TS_BUSY;
X		    sc->cy_txint = 1;
X		    (*linesw[tp->t_line].l_start)(tp);
X		    sc->cy_txint = 0;
X		    /* If nothing to send, disable TX interrupts */
X		    if ((tp->t_state&TS_BUSY) == 0)	
X			routb(base, CD1400_SRER, sc->cy_srer[chan]=SRER_MDM|SRER_RXD);
X
X		}
X		routb(base, CD1400_TIR,(save_tir & 0x3f));
X		routb(base, CD1400_CAR,save_car);
X
X	    }
X	    /* goto out */
X
X	    /* Modem Ctl interrupt? */
X	    if (b & CD1400_SVRR_MDM) {
X		unsigned char save_mir = rinb(base,CD1400_MIR);
X		int           chan = cd * CD1400_NO_OF_CHANNELS + (save_mir & 0x3);
X		unsigned char save_car = rinb(base,CD1400_CAR);
X		routb(base,CD1400_CAR,save_mir);
X
X		tp = &sc->cyb_tty[chan];
X#ifdef cy_STATS
X		sc->stats_ints_mdm[chan]++;
X#endif
X		
X		if ((rinb(base, CD1400_MISR) & MISR_CDCHG)) {
X			/* Get the value of CD */
X			if (rinb(base,CD1400_MSVR2) & MSVR2_CD)
X				(void) (*linesw[tp->t_line].l_modem)(tp, 1);	
X			else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
X			    (void) cybmctl(tp->t_dev, SET, 0);
X
X		   /* WARNING: May need to clear change bits here */
X		}
X		routb(base,CD1400_MIR,save_mir&0x3f);
X		routb(base,CD1400_CAR,save_car);
X
X	    }
X	}
X    }
X    if (domore) goto more;
X    sc->cy_inintr = 0;
X    routb(sc->cy_base, cy_CLEAR_INTR, 0);
X}
X
X/*
X * Start transmission
X */
Xvoid
Xcybstart(tp)
X	register struct tty *tp;
X{
X	register caddr_t base;
X	register c, count;
X	int s, chan;
X	register struct cybsoftc *sc;
X
X	dprintf(("cybstart:\n"));
X	/*
X	 * Check if there is work to do and we're able to do more.
X	 */
X	s = spltty();
X	if (tp->t_state & TS_BUSY 
X	    || (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
X#if 0					/* *** FreeBSD WARNING *** */
X	    && (tp->t_state & (TS_XON_PEND|TS_XOFF_PEND)) == 0)
X#endif
X	    ) {
X		dprintf(("leaving early\n"));
X		goto out;
X	}
X
X	if (tp->t_outq.c_cc <= tp->t_lowat) {
X		if (tp->t_state & TS_ASLEEP) {
X			tp->t_state &= ~TS_ASLEEP;
X			wakeup((caddr_t)&tp->t_outq);
X		}
X		selwakeup(&tp->t_wsel);
X	}
X
X	sc = &cybsoftc[UNIT(tp->t_dev)];
X	chan =  LINE(tp->t_dev);	/* *** WARNING *** */
X	base = sc->cy_addr[chan];
X
X	/*
X	 * If not in interrupt context, TDR is not available.
X	 * Simply enable TX interrupt if there is output to be done.
X	 */
X	if (sc->cy_txint == 0) {
X		if (tp->t_outq.c_cc ||
X		    /*tp->t_state & (TS_XON_PEND|TS_XOFF_PEND) ||  freeBSD WARN *** */
X		    sc->cy_cmd[chan] || sc->cy_pendesc[chan]) {
X			tp->t_state |= TS_BUSY;
X			routb(base, CD1400_CAR, chan&0x03);
X		        routb(base, CD1400_SRER, sc->cy_srer[chan]=SRER_MDM|SRER_RXD|SRER_TXD);
X		}
X		dprintf(("leaving with TXD ints enabled\n"));
X		goto out;
X	}
X
X	/*
X	 * Process pending commands
X	 */
X	count = CD1400_MAX_FIFO_SIZE;
X	if (c = sc->cy_cmd[chan]) {
X		sc->cy_cmd[chan] = 0;
X		routb(base, CD1400_TDR, CD1400_C_ESC);
X		routb(base, CD1400_TDR, c);
X		count -= 2;
X	}
X	if (sc->cy_pendesc[chan]) {
X		sc->cy_pendesc[chan] = 0;
X		routb(base, CD1400_TDR, CD1400_C_ESC);
X		count--;
X	}
X	
X
X#if 0	/* *** FreeBSD WARNING *** */
X	if (tp->t_state & (TS_XON_PEND|TS_XOFF_PEND)) {
X		if (tp->t_state & TS_XON_PEND) {
X			routb(base, CD1400_TDR, tp->t_cc[VSTART]);
X			tp->t_state &= ~TS_XON_PEND;
X		} else {
X			routb(base, CD1400_TDR, tp->t_cc[VSTOP]);
X			tp->t_state &= ~TS_XOFF_PEND;
X		}
X		if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
X			count = 0;
X		else
X			count--;
X	}
X#endif
X
X	/*
X	 * Run regular output queue
X	 */
X	while (tp->t_outq.c_cc && count--) {
X		c = getc(&tp->t_outq);
X		if (c == CD1400_C_ESC) {
X			if (count == 0)		/* oops */
X				sc->cy_pendesc[chan]++;
X			else {
X				routb(base, CD1400_TDR, CD1400_C_ESC);
X				count--;
X			}
X		}
X	        dprintf(("txd: %c (%x)\n",(c<0x20||c>0x7e)?' ':c,c));
X		routb(base, CD1400_TDR, c);
X	}
X        if (count<CD1400_MAX_FIFO_SIZE /*tp->t_outq.c_cc*/)
X	    tp->t_state |= TS_BUSY;
X
Xout:
X	splx(s);
X}
X
X/*
X * Ioctl routine
X */
Xint
Xcybioctl(dev, cmd, data, flag, p)
X	dev_t dev;
X	int cmd;
X	caddr_t data;
X	int flag;
X        struct proc *p;
X{
X	register struct cybsoftc *sc = &cybsoftc[UNIT(dev)];
X	register struct tty *tp = &sc->cyb_tty[LINE(dev)];
X	register int error;
X	int s;
X 
X	dprintf(("cybioctl:\n"));
X	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
X	if (error >= 0)
X		return (error);
X	error = ttioctl(tp, cmd, data, flag);
X	if (error >= 0)
X		return (error);
X
X	s = spltty();
X	switch (cmd) {
X	case TIOCSBRK:
X		/* Start sending BREAK */
X		sc->cy_cmd[LINE(tp->t_dev)] = CD1400_C_SBRK;
X		cybstart(tp);
X		break;
X
X	case TIOCCBRK:
X		/* Stop sending BREAK */
X		sc->cy_cmd[LINE(tp->t_dev)] = CD1400_C_EBRK;
X		cybstart(tp);
X		break;
X
X	case TIOCSDTR:			/* set DTR */
X		(void) cybmctl(dev, BIS, TIOCM_DTR);
X		break;
X
X	case TIOCCDTR:			/* clear DTR */
X		(void) cybmctl(dev, BIC, TIOCM_DTR);
X		break;
X
X	case TIOCMSET:
X		(void) cybmctl(dev, SET, * (int *) data);
X		break;
X
X	case TIOCMBIS:
X		(void) cybmctl(dev, BIS, * (int *) data);
X		break;
X
X	case TIOCMBIC:
X		(void) cybmctl(dev, BIC, * (int *) data);
X		break;
X
X	case TIOCMGET:
X		* (int *) data = cybmctl(dev, GET, 0);
X		break;
X
X	default:
X		splx(s);
X		return (ENOTTY);
X	}
X	splx(s);
X	return (0);
X}
X
Xstatic int cyb_fifothresh_lo = 9;	/* FIFO depth, half of FIFO, < 38.4k */
Xstatic int cyb_fifothresh_hi = 6;	/* FIFO depth, >= 38.4k */
X
Xstatic int cyb_doenable = 0;	/* should not be needed, defeats optimization if set */
X/*
X * Set parameters and enable the line
X */
Xint
Xcybparam(tp, t)
X	register struct tty *tp;
X	register struct termios *t;
X{
X	int s, chan;
X	register struct cybsoftc *sc;
X	register caddr_t base;
X	int iprescaler, oprescaler;
X	int ispeed, ospeed;
X	int cflag = t->c_cflag;
X	int iflag = t->c_iflag;
X	/*
X	    c is initialized to 0, eventhough it isn't necessary, to stop
X	    gnu gcc 2.6.2 from emitting a warning that it may be used
X	    uninitialized.
X	*/
X	register c = 0;
X
X	dprintf(("cybparam:\n"));
X	/* short-circuit the common case where there is no hardware change */
X
X	if (tp->t_cflag == t->c_cflag && tp->t_state&TS_ISOPEN &&
X	    tp->t_iflag == t->c_iflag &&
X	    tp->t_ispeed == t->c_ispeed && tp->t_ospeed == t->c_ospeed)
X	    	return (0);
X
X	if ((tp->t_cflag & CLOCAL) == 0 && t->c_cflag & CLOCAL)
X		wakeup((caddr_t) &tp->t_rawq);
X
X	tp->t_ispeed = t->c_ispeed;
X	tp->t_ospeed = t->c_ospeed;
X	tp->t_cflag = t->c_cflag;
X	tp->t_iflag = t->c_iflag;
X
X	/* Select line */
X	sc = &cybsoftc[UNIT(tp->t_dev)];
X	chan = LINE(tp->t_dev);
X	base = sc->cy_addr[chan];
X	s = spltty();
X	routb(base, CD1400_CAR, chan&0x03);
X
X	/* ospeed == 0 is for HANGUP */
X	if (tp->t_ospeed == 0) {
X		(void) cybmctl(tp->t_dev, SET, 0);
X		cybchancmd(base, CCR_TXDIS | CCR_RXDIS);
X		sc->cy_init[chan] = 0;
X		splx(s);
X		return (0);
X	}
X
X        if ((ospeed = cybspeed(t->c_ospeed, &oprescaler)) < 0) {
X            splx(s);
X            return(EINVAL);
X        }
X        routb(base,CD1400_TBPR,ospeed);
X        routb(base,CD1400_TCOR,oprescaler);
X
X        if ((ispeed = cybspeed(t->c_ispeed, &iprescaler)) < 0) {
X            splx(s);
X            return(EINVAL);
X        }
X        routb(base,CD1400_RBPR,ispeed);
X        routb(base,CD1400_RCOR,iprescaler);
X	
X	/* Load COR1 */
X	switch (tp->t_cflag & CSIZE) {
X	case CS5:
X		c = COR1_5BITS;
X		break;
X	case CS6:
X		c = COR1_6BITS;
X		break;
X	case CS7:
X		c = COR1_7BITS;
X		break;
X	case CS8:
X		c = COR1_8BITS;
X		break;
X	}
X#if 0
X	printf("%s ",tp->t_cflag & CSTOPB ? "CSTOPB":"!CSTOPB");
X	printf("%s ",tp->t_cflag & PARENB ? "PARENB":"!PARENB");
X	printf("%s ",tp->t_cflag & PARODD ? "PARODD":"!PARODD");
X	printf("%s ",tp->t_cflag & PARODD ? "PARODD":"!PARODD");
X#endif
X	if (tp->t_cflag & CSTOPB)
X		c |= COR1_2SB;
X	if (tp->t_cflag & PARENB) {
X		c |= COR1_NORMPAR;
X		if (tp->t_cflag & PARODD)
X			c |= COR1_ODDP;
X#if 0
X		if ((tp->t_iflag & INPCK) == 0)
X			c |= COR1_IGNORE;
X#endif
X	} else
X		c |= COR1_IGNORE;
X	routb(base, CD1400_COR1, c);
X	dprintf(("cor1=%x\n",c));
X
X	/* Load COR2 */
X	c = COR2_ETC;
X	if (tp->t_cflag & CCTS_OFLOW)
X		c |= COR2_CTSAE;
X#ifdef wrong
X	/*
X	 * COR2_RTSAO enables traditional RTS (high when there is something
X	 * to transmit), not RTR (high when ready to receive).
X	 */
X	if (tp->t_cflag & CRTS_IFLOW)
X		c |= COR2_RTSAO;
X#endif
X
X	/* there should be some logic to enable on-chip Xon/Xoff flow ctl */
X	routb(base, CD1400_COR2, c);
X	dprintf(("cor2=%x\n",c));
X
X	/* Load COR3 */
X	if (tp->t_ispeed >= 38400)
X		routb(base, CD1400_COR3, cyb_fifothresh_hi);	/* FIFO depth */
X	else
X		routb(base, CD1400_COR3, cyb_fifothresh_lo);	/* FIFO depth */
X	/* set the Receive Timeout Period to 20ms */
X	routb(base, CD1400_RTPR, 20);
X
X	/* Inform CD1400 engine about new values in COR registers */
X	cybchancmd(base, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
X	DELAY(500);
X	
X        /* Load COR4 */
X        c = 0;
X        if (iflag&IGNCR)
X	    c |= COR4_IGNCR;
X	if (iflag&IGNBRK)
X	    c |= COR4_IGNBRK;
X	if (!(iflag&BRKINT))
X	    c |= COR4_NBRKINT;
X	if (iflag&IGNPAR)
X	    c |= COR4_PFODISC;
X	else {
X	    if (iflag&PARMRK)
X		c |= COR4_PFOMARK;
X	    else
X		c |= COR4_PFONULL;
X	}
X	routb(base,CD1400_COR4,c);
X	dprintf(("cor4=%x\n",c));
X
X        /* Load COR5 */
X        c = 0;
X        if (iflag&ISTRIP)
X	    c |= COR5_ISTRIP;
X	if (t->c_iflag&IEXTEN)
X	    c |= COR5_IEXTEN;
X	routb(base,CD1400_COR5,c);
X	dprintf(("cor5=%x\n",c));
X
X
X        c = 0;
X	if (tp->t_cflag & CRTS_IFLOW)
X	    c |= 8;
X	routb(base, CD1400_MCOR1, MCOR1_CDZD|6);	/* WARNING */
X
X	dprintf(("cybparam:1\n"));
X	if (sc->cy_init[chan] == 0 || cyb_doenable) {
X		sc->cy_init[chan] = 1;
X		/* Load modem control parameters */
X		routb(base, CD1400_MCOR2, MCOR2_CDOD);
X
X		/* Finally enable transmitter and receiver */
X		cybchancmd(base, CCR_TXEN | CCR_RXEN);
X		routb(base, CD1400_SRER, sc->cy_srer[chan]=SRER_MDM|SRER_RXD); /* WARNING */
X		dprintf(("cybparam:2\n"));
X	}
X	splx(s);
X	dprintf(("cybparam:d\n"));
X	return (0);
X}
X
X/*
X * Write a command to the Channel Command Register,
X * making sure it is not busy before writing the command.
X * The channel must already have been selected.
X */
Xstatic void
Xcybchancmd(base, cmd)
X	caddr_t base;
X	int cmd;
X{
X	int i;
X
X	for (i = 0; i < 100; i++) {
X		if (rinb(base, CD1400_CCR) == 0)
X			goto ready;
X		DELAY(100);
X	}
X	printf("cy: ccr not ready\n");
Xready:
X	routb(base, CD1400_CCR, cmd);
X}
X
X/*
X * Stop output on a line
X */
X/*ARGSUSED*/
Xvoid
Xcybstop(tp, flag)
X	register struct tty *tp;
X	int flag;
X{
X	int s;
X
X	s = spltty();
X	if (tp->t_state & TS_BUSY) {
X		if ((tp->t_state & TS_TTSTOP) == 0)
X			tp->t_state |= TS_FLUSH;
X	}
X	splx(s);
X}
X
X/*
X * Modem control routine.
X */
Xstatic int
Xcybmctl(dev, cmd, bits)
X	dev_t dev;
X	enum cybmctl_cmds cmd;
X	int bits;
X{
X	register struct cybsoftc *sc = &cybsoftc[UNIT(dev)];
X	register line = LINE(dev);
X	register caddr_t base = sc->cy_addr[line];
X	register msvr;
X
X	dprintf(("cybmctl%x: cmd=%d bits=%x base=%lx\n",
X	         minor(dev), cmd, bits, (unsigned long)base));
X
X	routb(base, CD1400_CAR, line&0x03);
X
X	switch (cmd) {
X	case GET:
X		msvr = rinb(base, CD1400_MSVR2);
X		bits = TIOCM_LE;
X		if (msvr & MSVR2_DTR)
X			bits |= TIOCM_DTR;
X		if (msvr & MSVR2_CTS)
X			bits |= TIOCM_CTS;
X		if (msvr & MSVR2_DSR)
X			bits |= TIOCM_DSR;
X		if (msvr & MSVR2_CD)
X			bits |= TIOCM_CAR;
X		if (msvr & MSVR2_RI)
X			bits |= TIOCM_RI;
X		msvr = rinb(base, CD1400_MSVR1);
X		if (msvr & MSVR1_RTS)
X			bits |= TIOCM_RTS;
X		return (bits);
X
X	case SET:
X		if (bits&TIOCM_DTR) {
X		    sc->cy_softdtr |= 1 << line;
X		    routb(base, CD1400_MSVR1,MSVR1_RTS);
X		} else {
X		    sc->cy_softdtr &= ~(1 << line);
X		    routb(base, CD1400_MSVR1,0x00); /* lower RTS */
X		}
X		break;
X
X	case BIS:
X#if 0
X		if (bits & TIOCM_RTS)
X			routb(base, CD1400_MSVR2, MSVR2_RTS);
X#endif
X		if (bits & TIOCM_DTR) {
X		    sc->cy_softdtr |= 1 << line;
X		    routb(base, CD1400_MSVR1,MSVR1_RTS);
X		}
X		 
X		break;
X
X	case BIC:
X#if 0
X		if (bits & TIOCM_RTS)
X			routb(base, CD1400_MSVR, 0);
X#endif
X		if (bits & TIOCM_DTR) {
X		    sc->cy_softdtr &= ~(1 << line);
X		    routb(base, CD1400_MSVR1,0x00); /* lower RTS */
X		}
X		break;
X	}
X
X	/* Enable/disable receiver on open/close */
X	if (cmd == SET) {
X		routb(base, CD1400_CAR, line&0x03);
X		if (bits == 0) {
X		    cybchancmd(base, CCR_RXDIS);
X		} else {
X		    cybchancmd(base, CCR_RXEN);
X		}
X	}
X	return (0);
X}
X
Xstatic int
Xcybspeed(speed, prescaler_io)
X    long speed;
X    int *prescaler_io;
X{
X    int         actual;
X    int         error;
X    int         divider;
X    int         prescaler;
X    int         prescaler_unit;
X
X    if (speed == 0)
X        return 0;
X
X    if (speed < 0 || speed > 150000)
X        return -1;
X
X    /* determine which prescaler to use */
X    for (prescaler_unit = 4, prescaler = 2048; prescaler_unit;
X            prescaler_unit--, prescaler >>= 2) {
X        if (CYCLOM_CLOCK/prescaler/speed > 63)
X            break;
X    }
X
X    divider = (CYCLOM_CLOCK/prescaler*2/speed + 1)/2;   /* round off */
X    if (divider > 255)
X        divider = 255;
X    actual = CYCLOM_CLOCK/prescaler/divider;
X    error = ((actual-speed)*2000/speed +1)/2;   /* percentage */
X
X    /* 3.0% max error tolerance */
X    if (error < -30 || error > 30)
X        return -1;
X
X#if 0
X    printf("speed = %ld\n",speed);
X    printf("prescaler = %d (%d)\n", prescaler, prescaler_unit);
X    printf("divider = %d (%x)\n", divider, divider);
X    printf("actual = %d\n", actual);
X    printf("error = %d\n", error);
X#endif
X
X    *prescaler_io = prescaler_unit;
X    return divider;
X}
X#endif /* NCYB > 0 */
END-of-cyb.c
exit




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?m0rueOZ-000rccC>