From owner-freebsd-current Fri Mar 31 03:07:28 1995 Return-Path: current-owner Received: (from majordom@localhost) by freefall.cdrom.com (8.6.10/8.6.6) id DAA14004 for current-outgoing; Fri, 31 Mar 1995 03:07:28 -0800 Received: from easynet.com (easyr.easynet.net [198.67.38.6]) by freefall.cdrom.com (8.6.10/8.6.6) with SMTP id DAA13995 for ; Fri, 31 Mar 1995 03:07:24 -0800 Received: by easynet.com (Smail3.1.28.1 #7) id m0rueOZ-000rccC; Fri, 31 Mar 95 02:57 WET Message-Id: From: brian@mediacity.com (Brian Litzinger) Subject: cyb2.0bf To: freebsd-current@FreeBSD.org Date: Fri, 31 Mar 1995 02:57:38 -0800 (PST) X-Mailer: ELM [version 2.4 PL23] Content-Type: text Content-Length: 40769 Sender: current-owner@FreeBSD.org Precedence: bulk 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 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 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 * 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 X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include 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; icy_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;icy_NbrCD1400s;i++) { X base = b + i * CD1400_MEMSIZE; X routb(base, CD1400_PPR, CD1400_CLOCK_25_1MS); X for (j=0;jcy_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;chancy_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;cdcy_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 (countt_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