Changes to add support for the PCI version of the Cyclades Cyclom-Y

serial adapter, and support for multiple Cyclom controllers.
This commit is contained in:
David Greenman 1996-10-13 01:09:24 +00:00
parent d2322fc6ac
commit 3010cd6550
9 changed files with 811 additions and 409 deletions

View File

@ -305,6 +305,7 @@ pccard/pccard.c optional crd
pccard/pcic.c optional pcic device-driver
pci/aic7870.c optional ahc device-driver
pci/bt9xx.c optional bt device-driver
pci/cy_pci.c optional cy device-driver
pci/if_de.c optional de device-driver
pci/if_ed_p.c optional ed device-driver
pci/if_fxp.c optional fxp device-driver

View File

@ -27,7 +27,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: cy.c,v 1.36 1996/10/04 10:33:08 davidg Exp $
* $Id: cy.c,v 1.37 1996/10/04 14:17:32 davidg Exp $
*/
#include "cy.h"
@ -141,7 +141,7 @@
/* We encode the cyclom unit number (cyu) in spare bits in the IVR's. */
#define CD1400_xIVR_CHAN_SHIFT 3
#define CD1400_xIVR_CHAN 0x0F /* XXX reduce to pack Cyclom-8Ys */
#define CD1400_xIVR_CHAN 0x1F /* XXX reduce to pack Cyclom-8Ys */
#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
#define RB_I_HIGH_WATER (TTYHOG - 2 * RS_IBUFSIZE)
@ -153,7 +153,8 @@
#define CONTROL_LOCK_STATE 0x40
#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
#define MINOR_TO_UNIT(mynor) ((mynor) & ~MINOR_MAGIC_MASK)
#define MINOR_TO_UNIT(mynor) (((mynor) >> 16) * CY_MAX_PORTS + \
(((mynor) & 0xff) & ~MINOR_MAGIC_MASK))
/*
* Input buffer watermarks.
@ -262,6 +263,7 @@ struct com_s {
cy_addr cy_iobase; /* base address of this port's cyclom */
cy_addr iobase; /* base address of this port's cd1400 */
int cy_align; /* index for register alignment */
struct tty *tp; /* cross reference */
@ -330,8 +332,10 @@ void siopoll __P((void));
#define siommap nommap
#define siostrategy nostrategy
int cyattach_common __P((cy_addr cy_iobase, int cy_align));
static int cy_units __P((cy_addr cy_iobase, int cy_align));
static int sioattach __P((struct isa_device *dev));
static void cd1400_channel_cmd __P((cy_addr iobase, int cmd));
static void cd1400_channel_cmd __P((cy_addr iobase, int cmd, int cy_align));
static timeout_t siodtrwakeup;
static void comhardclose __P((struct com_s *com));
#if 0
@ -399,6 +403,7 @@ static u_int cy_timeouts;
#endif
static int cy_nr_cd1400s[NCY];
static int cy_total_devices;
#undef RxFifoThreshold
static int volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2);
static int cy_chip_offset[] = {
@ -416,16 +421,9 @@ static int
sioprobe(dev)
struct isa_device *dev;
{
int cyu;
u_char firmware_version;
cy_addr iobase;
int unit;
iobase = (cy_addr)dev->id_maddr;
unit = dev->id_unit;
if ((u_int)unit >= NCY)
return (0);
cy_nr_cd1400s[unit] = 0;
/* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */
cy_inb(iobase, CY16_RESET); /* XXX? */
@ -435,22 +433,34 @@ sioprobe(dev)
cy_outb(iobase, CY_CLEAR_INTR, 0);
DELAY(500);
return (cy_units(iobase, 0) == 0 ? 0 : -1);
}
static int
cy_units(cy_iobase, cy_align)
cy_addr cy_iobase;
int cy_align;
{
cy_addr iobase;
int cyu;
for (cyu = 0; cyu < CY_MAX_CD1400s; ++cyu) {
int i;
u_char firmware_version;
iobase = (cy_addr) (dev->id_maddr + cy_chip_offset[cyu]);
iobase = cy_iobase + (cy_chip_offset[cyu] << cy_align);
/* wait for chip to become ready for new command */
for (i = 0; i < 10; i++) {
DELAY(50);
if (!cd_inb(iobase, CD1400_CCR))
if (!cd_inb(iobase, CD1400_CCR, cy_align))
break;
}
/* clear the GFRCR register */
cd_outb(iobase, CD1400_GFRCR, 0);
cd_outb(iobase, CD1400_GFRCR, cy_align, 0);
/* issue a reset command */
cd_outb(iobase, CD1400_CCR,
cd_outb(iobase, CD1400_CCR, cy_align,
CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);
/* wait for the CD1400 to initialize itself */
@ -458,7 +468,7 @@ sioprobe(dev)
DELAY(50);
/* retrieve firmware version */
firmware_version = cd_inb(iobase, CD1400_GFRCR);
firmware_version = cd_inb(iobase, CD1400_GFRCR, cy_align);
if ((firmware_version & 0xf0) == 0x40)
break;
}
@ -470,38 +480,60 @@ sioprobe(dev)
*/
if ((firmware_version & 0xf0) != 0x40)
break;
++cy_nr_cd1400s[unit];
}
return (cy_nr_cd1400s[unit] == 0 ? 0 : -1);
return (cyu);
}
static int
sioattach(isdp)
struct isa_device *isdp;
struct isa_device *isdp;
{
int cyu;
cy_addr cy_iobase;
dev_t dev;
cy_addr iobase;
int ncyu;
int unit;
int adapter;
unit = isdp->id_unit;
if ((u_int)unit >= NCY)
return (0);
ncyu = cy_nr_cd1400s[unit];
if (ncyu == 0)
adapter = cyattach_common((cy_addr) isdp->id_maddr, 0);
if (adapter < 0)
return (0);
/*
* XXX
* This kludge is to allow ISA/PCI device specifications in the
* kernel config file to be in any order.
*/
if (isdp->id_unit != adapter) {
printf("cy%d: attached as cy%d\n", isdp->id_unit, adapter);
isdp->id_unit = adapter; /* XXX */
}
isdp->id_ri_flags |= RI_FAST;
return (1);
}
cy_iobase = (cy_addr)isdp->id_maddr;
unit *= CY_MAX_PORTS;
int
cyattach_common(cy_iobase, cy_align)
cy_addr cy_iobase;
int cy_align;
{
int cyu, ncyu, unit, adapter;
dev_t dev;
cy_addr iobase;
adapter = cy_total_devices;
if ((u_int)adapter >= NCY) {
printf("cy%d: can't attach adapter: insufficient cy devices configured\n",
adapter);
return (-1);
}
ncyu = cy_units(cy_iobase, cy_align);
if (ncyu == 0)
return (-1);
cy_nr_cd1400s[adapter] = ncyu;
cy_total_devices++;
unit = adapter * CY_MAX_PORTS;
for (cyu = 0; cyu < ncyu; ++cyu) {
int cdu;
iobase = (cy_addr) (isdp->id_maddr + cy_chip_offset[cyu]);
iobase = (cy_addr) (cy_iobase + (cy_chip_offset[cyu] << cy_align));
/* Set up a receive timeout period of than 1+ ms. */
cd_outb(iobase, CD1400_PPR,
cd_outb(iobase, CD1400_PPR, cy_align,
howmany(CY_CLOCK / CD1400_PPR_PRESCALER, 1000));
for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; ++cdu, ++unit) {
@ -522,6 +554,7 @@ sioattach(isdp)
com->cy_iobase = cy_iobase;
com->iobase = iobase;
com->cy_align = cy_align;
/*
* We don't use all the flags from <sys/ttydefaults.h> since they
@ -574,9 +607,9 @@ sioattach(isdp)
}
/* ensure an edge for the next interrupt */
cy_outb(cy_iobase, CY_CLEAR_INTR, 0);
cd_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
return (1);
return (adapter);
}
static int
@ -664,8 +697,8 @@ open_top:
iobase = com->iobase;
/* reset this channel */
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd1400_channel_cmd(iobase, CD1400_CCR_CMDRESET);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
cd1400_channel_cmd(iobase, CD1400_CCR_CMDRESET, com->cy_align);
/*
* Resetting disables the transmitter and receiver as well as
@ -677,7 +710,7 @@ open_top:
com->channel_control = 0;
/* Encode per-board unit in LIVR for access in intr routines. */
cd_outb(iobase, CD1400_LIVR,
cd_outb(iobase, CD1400_LIVR, com->cy_align,
(unit & CD1400_xIVR_CHAN) << CD1400_xIVR_CHAN_SHIFT);
/*
@ -732,8 +765,8 @@ open_top:
(void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
disable_intr();
com->prev_modem_status = com->last_modem_status
= cd_inb(iobase, CD1400_MSVR2);
cd_outb(iobase, CD1400_SRER,
= cd_inb(iobase, CD1400_MSVR2, com->cy_align);
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable
= CD1400_SRER_MDMCH | CD1400_SRER_RXDATA);
enable_intr();
@ -827,7 +860,7 @@ comhardclose(com)
com->poll_output = FALSE;
#endif
com->do_timestamp = 0;
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
#if 0
outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
#endif
@ -837,7 +870,7 @@ comhardclose(com)
outb(iobase + com_ier, 0);
#else
disable_intr();
cd_outb(iobase, CD1400_SRER, com->intr_enable = 0);
cd_outb(iobase, CD1400_SRER, com->cy_align, com->intr_enable = 0);
enable_intr();
#endif
tp = com->tp;
@ -859,7 +892,7 @@ comhardclose(com)
com->channel_control = CD1400_CCR_CMDCHANCTL
| CD1400_CCR_XMTEN
| CD1400_CCR_RCVDIS;
cd1400_channel_cmd(iobase, com->channel_control);
cd1400_channel_cmd(iobase, com->channel_control, com->cy_align);
if (com->dtr_wait != 0) {
timeout(siodtrwakeup, com, com->dtr_wait);
@ -948,20 +981,19 @@ void
siointr(unit)
int unit;
{
int baseu;
cy_addr cy_iobase;
int cyu;
cy_addr iobase;
u_char status;
cy_addr cy_iobase, iobase;
int baseu, cyu, cy_align;
u_char status;
baseu = unit * CY_MAX_PORTS;
cy_iobase = com_addr(baseu)->cy_iobase;
cy_align = com_addr(baseu)->cy_align;
/* check each CD1400 in turn */
for (cyu = 0; cyu < cy_nr_cd1400s[unit]; ++cyu) {
iobase = (cy_addr) (cy_iobase + cy_chip_offset[cyu]);
iobase = (cy_addr) (cy_iobase + (cy_chip_offset[cyu] << cy_align));
/* poll to see if it has any work */
status = cd_inb(iobase, CD1400_SVRR);
status = cd_inb(iobase, CD1400_SVRR, cy_align);
if (status == 0)
continue;
#ifdef CyDebug
@ -981,13 +1013,13 @@ siointr(unit)
#endif
#ifdef PollMode
save_rir = cd_inb(iobase, CD1400_RIR);
save_car = cd_inb(iobase, CD1400_CAR);
save_rir = cd_inb(iobase, CD1400_RIR, cy_align);
save_car = cd_inb(iobase, CD1400_CAR, cy_align);
/* enter rx service */
cd_outb(iobase, CD1400_CAR, save_rir);
cd_outb(iobase, CD1400_CAR, cy_align, save_rir);
serv_type = cd_inb(iobase, CD1400_RIVR);
serv_type = cd_inb(iobase, CD1400_RIVR, cy_align);
com = com_addr(baseu
+ ((serv_type >> CD1400_xIVR_CHAN_SHIFT)
& CD1400_xIVR_CHAN));
@ -1002,9 +1034,9 @@ siointr(unit)
if (serv_type & CD1400_RIVR_EXCEPTION) {
++com->recv_exception;
line_status = cd_inb(iobase, CD1400_RDSR);
line_status = cd_inb(iobase, CD1400_RDSR, cy_align);
/* break/unnattached error bits or real input? */
recv_data = cd_inb(iobase, CD1400_RDSR);
recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
#ifndef SOFT_HOTCHAR
if (line_status & CD1400_RDSR_SPECIAL
&& com->hotchar != 0)
@ -1053,7 +1085,7 @@ siointr(unit)
outb(com->modem_ctl_port,
com->mcr_image &= ~MCR_RTS);
#else
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, cy_align,
com->mcr_image &= ~MCR_RTS);
#endif
if (line_status & LSR_OE)
@ -1063,7 +1095,7 @@ siointr(unit)
} else {
int ifree;
count = cd_inb(iobase, CD1400_RDCR);
count = cd_inb(iobase, CD1400_RDCR, cy_align);
com->bytes_in += count;
ioptr = com->iptr;
ifree = com->ibufend - ioptr;
@ -1075,7 +1107,7 @@ siointr(unit)
microtime(&com->timestamp);
do {
recv_data = cd_inb(iobase,
CD1400_RDSR);
CD1400_RDSR, cy_align);
#ifdef SOFT_HOTCHAR
if (com->hotchar != 0
&& recv_data
@ -1090,7 +1122,7 @@ siointr(unit)
com->delta_error_counts
[CE_INTERRUPT_BUF_OVERFLOW] += count;
do {
recv_data = cd_inb(iobase, CD1400_RDSR);
recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
#ifdef SOFT_HOTCHAR
if (com->hotchar != 0
&& recv_data == com->hotchar)
@ -1107,12 +1139,12 @@ siointr(unit)
outb(com->modem_ctl_port,
com->mcr_image &= ~MCR_RTS);
#else
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, cy_align,
com->mcr_image &= ~MCR_RTS);
#endif
com_events += count;
do {
recv_data = cd_inb(iobase, CD1400_RDSR);
recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
#ifdef SOFT_HOTCHAR
if (com->hotchar != 0
&& recv_data == com->hotchar)
@ -1129,12 +1161,12 @@ cont:
/* terminate service context */
#ifdef PollMode
cd_outb(iobase, CD1400_RIR,
cd_outb(iobase, CD1400_RIR, cy_align,
save_rir
& ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY));
cd_outb(iobase, CD1400_CAR, save_car);
cd_outb(iobase, CD1400_CAR, cy_align, save_car);
#else
cd_outb(iobase, CD1400_EOSRR, 0);
cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
#endif
}
if (status & CD1400_SVRR_MDMCH) {
@ -1148,11 +1180,11 @@ cont:
#endif
#ifdef PollMode
save_mir = cd_inb(iobase, CD1400_MIR);
save_car = cd_inb(iobase, CD1400_CAR);
save_mir = cd_inb(iobase, CD1400_MIR, cy_align);
save_car = cd_inb(iobase, CD1400_CAR, cy_align);
/* enter modem service */
cd_outb(iobase, CD1400_CAR, save_mir);
cd_outb(iobase, CD1400_CAR, cy_align, save_mir);
com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS
+ (save_mir & CD1400_MIR_CHAN));
@ -1165,7 +1197,7 @@ cont:
& CD1400_xIVR_CHAN));
#endif
++com->mdm;
modem_status = cd_inb(iobase, CD1400_MSVR2);
modem_status = cd_inb(iobase, CD1400_MSVR2, cy_align);
if (modem_status != com->last_modem_status) {
if (com->do_dcd_timestamp
&& !(com->last_modem_status & MSR_DCD)
@ -1194,13 +1226,13 @@ cont:
| CS_ODEVREADY)
&& !(com->intr_enable
& CD1400_SRER_TXRDY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, cy_align,
com->intr_enable
|= CD1400_SRER_TXRDY);
} else {
com->state &= ~CS_ODEVREADY;
if (com->intr_enable & CD1400_SRER_TXRDY)
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, cy_align,
com->intr_enable
&= ~CD1400_SRER_TXRDY);
}
@ -1210,12 +1242,12 @@ cont:
/* terminate service context */
#ifdef PollMode
cd_outb(iobase, CD1400_MIR,
cd_outb(iobase, CD1400_MIR, cy_align,
save_mir
& ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY));
cd_outb(iobase, CD1400_CAR, save_car);
cd_outb(iobase, CD1400_CAR, cy_align, save_car);
#else
cd_outb(iobase, CD1400_EOSRR, 0);
cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
#endif
}
if (status & CD1400_SVRR_TXRDY) {
@ -1228,11 +1260,11 @@ cont:
#endif
#ifdef PollMode
save_tir = cd_inb(iobase, CD1400_TIR);
save_car = cd_inb(iobase, CD1400_CAR);
save_tir = cd_inb(iobase, CD1400_TIR, cy_align);
save_car = cd_inb(iobase, CD1400_CAR, cy_align);
/* enter tx service */
cd_outb(iobase, CD1400_CAR, save_tir);
cd_outb(iobase, CD1400_CAR, cy_align, save_tir);
com = com_addr(baseu
+ cyu * CD1400_NO_OF_CHANNELS
+ (save_tir & CD1400_TIR_CHAN));
@ -1255,7 +1287,7 @@ cont:
ocount = CD1400_TX_FIFO_SIZE;
com->bytes_out += ocount;
do
cd_outb(iobase, CD1400_TDR, *ioptr++);
cd_outb(iobase, CD1400_TDR, cy_align, *ioptr++);
while (--ocount != 0);
com->obufq.l_head = ioptr;
if (ioptr >= com->obufq.l_tail) {
@ -1271,7 +1303,7 @@ cont:
} else {
/* output just completed */
com->state &= ~CS_BUSY;
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, cy_align,
com->intr_enable
&= ~CD1400_SRER_TXRDY);
}
@ -1285,18 +1317,18 @@ cont:
/* terminate service context */
#ifdef PollMode
cd_outb(iobase, CD1400_TIR,
cd_outb(iobase, CD1400_TIR, cy_align,
save_tir
& ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY));
cd_outb(iobase, CD1400_CAR, save_car);
cd_outb(iobase, CD1400_CAR, cy_align, save_car);
#else
cd_outb(iobase, CD1400_EOSRR, 0);
cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
#endif
}
}
/* ensure an edge for the next interrupt */
cy_outb(cy_iobase, CY_CLEAR_INTR, 0);
cd_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
schedsofttty();
}
@ -1406,7 +1438,7 @@ sioioctl(dev, cmd, data, flag, p)
splx(s);
return (error);
}
cd_outb(iobase, CD1400_CAR, MINOR_TO_UNIT(mynor) & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, MINOR_TO_UNIT(mynor) & CD1400_CAR_CHAN);
switch (cmd) {
#if 0
case TIOCSBRK:
@ -1544,9 +1576,9 @@ repeat:
com->mcr_image |= MCR_RTS);
#else
iobase = com->iobase,
cd_outb(iobase, CD1400_CAR,
cd_outb(iobase, CD1400_CAR, com->cy_align,
unit & CD1400_CAR_CHAN),
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, com->cy_align,
com->mcr_image |= MCR_RTS);
#endif
enable_intr();
@ -1669,19 +1701,19 @@ comparam(tp, t)
com = com_addr(unit);
iobase = com->iobase;
s = spltty();
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
if (odivisor == 0)
(void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */
else
(void)commctl(com, TIOCM_DTR, DMBIS);
if (idivisor != 0) {
cd_outb(iobase, CD1400_RBPR, idivisor);
cd_outb(iobase, CD1400_RCOR, iprescaler);
cd_outb(iobase, CD1400_RBPR, com->cy_align, idivisor);
cd_outb(iobase, CD1400_RCOR, com->cy_align, iprescaler);
}
if (odivisor != 0) {
cd_outb(iobase, CD1400_TBPR, odivisor);
cd_outb(iobase, CD1400_TCOR, oprescaler);
cd_outb(iobase, CD1400_TBPR, com->cy_align, odivisor);
cd_outb(iobase, CD1400_TCOR, com->cy_align, oprescaler);
}
/*
@ -1694,20 +1726,20 @@ comparam(tp, t)
| (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS);
if (opt != com->channel_control) {
com->channel_control = opt;
cd1400_channel_cmd(iobase, opt);
cd1400_channel_cmd(iobase, opt, com->cy_align);
}
#ifdef Smarts
/* set special chars */
/* XXX if one is _POSIX_VDISABLE, can't use some others */
if (t->c_cc[VSTOP] != _POSIX_VDISABLE)
cd_outb(iobase, CD1400_SCHR1, t->c_cc[VSTOP]);
cd_outb(iobase, CD1400_SCHR1, com->cy_align, t->c_cc[VSTOP]);
if (t->c_cc[VSTART] != _POSIX_VDISABLE)
cd_outb(iobase, CD1400_SCHR2, t->c_cc[VSTART]);
cd_outb(iobase, CD1400_SCHR2, com->cy_align, t->c_cc[VSTART]);
if (t->c_cc[VINTR] != _POSIX_VDISABLE)
cd_outb(iobase, CD1400_SCHR3, t->c_cc[VINTR]);
cd_outb(iobase, CD1400_SCHR3, com->cy_align, t->c_cc[VINTR]);
if (t->c_cc[VSUSP] != _POSIX_VDISABLE)
cd_outb(iobase, CD1400_SCHR4, t->c_cc[VSUSP]);
cd_outb(iobase, CD1400_SCHR4, com->cy_align, t->c_cc[VSUSP]);
#endif
/*
@ -1754,14 +1786,14 @@ comparam(tp, t)
cor_change = 0;
if (opt != com->cor[0]) {
cor_change |= CD1400_CCR_COR1;
cd_outb(iobase, CD1400_COR1, com->cor[0] = opt);
cd_outb(iobase, CD1400_COR1, com->cy_align, com->cor[0] = opt);
}
/*
* Set receive time-out period, normally to max(one char time, 5 ms).
*/
if (t->c_ispeed == 0)
itimeout = cd_inb(iobase, CD1400_RTPR);
itimeout = cd_inb(iobase, CD1400_RTPR, com->cy_align);
else {
itimeout = (1000 * bits + t->c_ispeed - 1) / t->c_ispeed;
#ifdef SOFT_HOTCHAR
@ -1777,7 +1809,7 @@ comparam(tp, t)
itimeout = t->c_cc[VTIME] * 10;
if (itimeout > 255)
itimeout = 255;
cd_outb(iobase, CD1400_RTPR, itimeout);
cd_outb(iobase, CD1400_RTPR, com->cy_align, itimeout);
/*
* set channel option register 2 -
@ -1796,7 +1828,7 @@ comparam(tp, t)
#endif
if (opt != com->cor[1]) {
cor_change |= CD1400_CCR_COR2;
cd_outb(iobase, CD1400_COR2, com->cor[1] = opt);
cd_outb(iobase, CD1400_COR2, com->cy_align, com->cor[1] = opt);
}
/*
@ -1814,12 +1846,12 @@ comparam(tp, t)
#endif
if (opt != com->cor[2]) {
cor_change |= CD1400_CCR_COR3;
cd_outb(iobase, CD1400_COR3, com->cor[2] = opt);
cd_outb(iobase, CD1400_COR3, com->cy_align, com->cor[2] = opt);
}
/* notify the CD1400 if COR1-3 have changed */
if (cor_change)
cd1400_channel_cmd(iobase, CD1400_CCR_CMDCORCHG | cor_change);
cd1400_channel_cmd(iobase, CD1400_CCR_CMDCORCHG | cor_change, com->cy_align);
/*
* set channel option register 4 -
@ -1858,7 +1890,7 @@ comparam(tp, t)
#else
opt |= CD1400_COR4_PFO_EXCEPTION;
#endif
cd_outb(iobase, CD1400_COR4, opt);
cd_outb(iobase, CD1400_COR4, com->cy_align, opt);
/*
* set channel option register 5 -
@ -1875,7 +1907,7 @@ comparam(tp, t)
if (t->c_oflag & OCRNL)
opt |= CD1400_COR5_OCRNL;
#endif
cd_outb(iobase, CD1400_COR5, opt);
cd_outb(iobase, CD1400_COR5, com->cy_align, opt);
/*
* XXX we probably alway want to track carrier changes, so that
@ -1892,7 +1924,7 @@ comparam(tp, t)
if (cflag & CCTS_OFLOW)
opt |= CD1400_MCOR1_CTSzd;
#endif
cd_outb(iobase, CD1400_MCOR1, opt);
cd_outb(iobase, CD1400_MCOR1, com->cy_align, opt);
/*
* set modem change option register 2
@ -1903,7 +1935,7 @@ comparam(tp, t)
if (cflag & CCTS_OFLOW)
opt |= CD1400_MCOR2_CTSod;
#endif
cd_outb(iobase, CD1400_MCOR2, opt);
cd_outb(iobase, CD1400_MCOR2, com->cy_align, opt);
/*
* XXX should have done this long ago, but there is too much state
@ -1946,11 +1978,11 @@ comparam(tp, t)
#endif
if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
if (!(com->intr_enable & CD1400_SRER_TXRDY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable |= CD1400_SRER_TXRDY);
} else {
if (com->intr_enable & CD1400_SRER_TXRDY)
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable &= ~CD1400_SRER_TXRDY);
}
@ -1982,17 +2014,17 @@ comstart(tp)
#endif
disable_intr();
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
if (tp->t_state & TS_TTSTOP) {
com->state &= ~CS_TTGO;
if (com->intr_enable & CD1400_SRER_TXRDY)
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable &= ~CD1400_SRER_TXRDY);
} else {
com->state |= CS_TTGO;
if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)
&& !(com->intr_enable & CD1400_SRER_TXRDY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable |= CD1400_SRER_TXRDY);
}
if (tp->t_state & TS_TBLOCK) {
@ -2000,7 +2032,7 @@ comstart(tp)
#if 0
outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
#else
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, com->cy_align,
com->mcr_image &= ~MCR_RTS);
#endif
} else {
@ -2013,7 +2045,7 @@ comstart(tp)
#if 0
outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
#else
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, com->cy_align,
com->mcr_image |= MCR_RTS);
#endif
}
@ -2048,7 +2080,7 @@ comstart(tp)
com->state |= CS_BUSY;
if (com->state >= (CS_BUSY | CS_TTGO
| CS_ODEVREADY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable
|= CD1400_SRER_TXRDY);
}
@ -2076,7 +2108,7 @@ comstart(tp)
com->state |= CS_BUSY;
if (com->state >= (CS_BUSY | CS_TTGO
| CS_ODEVREADY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable
|= CD1400_SRER_TXRDY);
}
@ -2182,18 +2214,18 @@ commctl(com, bits, how)
switch (how) {
case DMSET:
com->mcr_image = mcr;
cd_outb(iobase, CD1400_MSVR1, mcr);
cd_outb(iobase, CD1400_MSVR2, mcr);
cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
break;
case DMBIS:
com->mcr_image = mcr = com->mcr_image | mcr;
cd_outb(iobase, CD1400_MSVR1, mcr);
cd_outb(iobase, CD1400_MSVR2, mcr);
cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
break;
case DMBIC:
com->mcr_image = mcr = com->mcr_image & ~mcr;
cd_outb(iobase, CD1400_MSVR1, mcr);
cd_outb(iobase, CD1400_MSVR2, mcr);
cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
break;
}
enable_intr();
@ -2331,17 +2363,17 @@ disc_optim(tp, t, com)
com->hotchar = 0;
#ifndef SOFT_HOTCHAR
iobase = com->iobase;
cd_outb(iobase, CD1400_CAR, com->unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, com->unit & CD1400_CAR_CHAN);
opt = com->cor[2] & ~CD1400_COR3_SCD34;
if (com->hotchar != 0) {
cd_outb(iobase, CD1400_SCHR3, com->hotchar);
cd_outb(iobase, CD1400_SCHR4, com->hotchar);
cd_outb(iobase, CD1400_SCHR3, com->cy_align, com->hotchar);
cd_outb(iobase, CD1400_SCHR4, com->cy_align, com->hotchar);
opt |= CD1400_COR3_SCD34;
}
if (opt != com->cor[2]) {
cd_outb(iobase, CD1400_COR3, com->cor[2] = opt);
cd_outb(iobase, CD1400_COR3, com->cy_align, com->cor[2] = opt);
cd1400_channel_cmd(com->iobase,
CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3);
CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3, com->cy_align);
}
#endif
}
@ -2405,9 +2437,10 @@ comspeed(speed, prescaler_io)
}
static void
cd1400_channel_cmd(iobase, cmd)
cd1400_channel_cmd(iobase, cmd, cy_align)
cy_addr iobase;
int cmd;
int cy_align;
{
/* XXX hsu@clinet.fi: This is always more dependent on ISA bus speed,
as the card is probed every round? Replaced delaycount with 8k.
@ -2417,14 +2450,14 @@ cd1400_channel_cmd(iobase, cmd)
u_int maxwait = 5 * 8 * 1024; /* approx. 5 ms */
/* wait for processing of previous command to complete */
while (cd_inb(iobase, CD1400_CCR) && maxwait--)
while (cd_inb(iobase, CD1400_CCR, cy_align) && maxwait--)
;
if (!maxwait)
log(LOG_ERR, "cy: channel command timeout (%d loops) - arrgh\n",
5 * 8 * 1024);
cd_outb(iobase, CD1400_CCR, cmd);
cd_outb(iobase, CD1400_CCR, cy_align, cmd);
}
#ifdef CyDebug
@ -2448,7 +2481,7 @@ cystatus(unit)
iobase = com->iobase;
printf("\n");
printf("cd1400 base address:\\tt%p\n", iobase);
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
printf("saved channel_control:\t\t0x%02x\n", com->channel_control);
printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n",
com->cor[0], com->cor[1], com->cor[2]);

View File

@ -27,7 +27,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: cy.c,v 1.36 1996/10/04 10:33:08 davidg Exp $
* $Id: cy.c,v 1.37 1996/10/04 14:17:32 davidg Exp $
*/
#include "cy.h"
@ -141,7 +141,7 @@
/* We encode the cyclom unit number (cyu) in spare bits in the IVR's. */
#define CD1400_xIVR_CHAN_SHIFT 3
#define CD1400_xIVR_CHAN 0x0F /* XXX reduce to pack Cyclom-8Ys */
#define CD1400_xIVR_CHAN 0x1F /* XXX reduce to pack Cyclom-8Ys */
#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
#define RB_I_HIGH_WATER (TTYHOG - 2 * RS_IBUFSIZE)
@ -153,7 +153,8 @@
#define CONTROL_LOCK_STATE 0x40
#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
#define MINOR_TO_UNIT(mynor) ((mynor) & ~MINOR_MAGIC_MASK)
#define MINOR_TO_UNIT(mynor) (((mynor) >> 16) * CY_MAX_PORTS + \
(((mynor) & 0xff) & ~MINOR_MAGIC_MASK))
/*
* Input buffer watermarks.
@ -262,6 +263,7 @@ struct com_s {
cy_addr cy_iobase; /* base address of this port's cyclom */
cy_addr iobase; /* base address of this port's cd1400 */
int cy_align; /* index for register alignment */
struct tty *tp; /* cross reference */
@ -330,8 +332,10 @@ void siopoll __P((void));
#define siommap nommap
#define siostrategy nostrategy
int cyattach_common __P((cy_addr cy_iobase, int cy_align));
static int cy_units __P((cy_addr cy_iobase, int cy_align));
static int sioattach __P((struct isa_device *dev));
static void cd1400_channel_cmd __P((cy_addr iobase, int cmd));
static void cd1400_channel_cmd __P((cy_addr iobase, int cmd, int cy_align));
static timeout_t siodtrwakeup;
static void comhardclose __P((struct com_s *com));
#if 0
@ -399,6 +403,7 @@ static u_int cy_timeouts;
#endif
static int cy_nr_cd1400s[NCY];
static int cy_total_devices;
#undef RxFifoThreshold
static int volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2);
static int cy_chip_offset[] = {
@ -416,16 +421,9 @@ static int
sioprobe(dev)
struct isa_device *dev;
{
int cyu;
u_char firmware_version;
cy_addr iobase;
int unit;
iobase = (cy_addr)dev->id_maddr;
unit = dev->id_unit;
if ((u_int)unit >= NCY)
return (0);
cy_nr_cd1400s[unit] = 0;
/* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */
cy_inb(iobase, CY16_RESET); /* XXX? */
@ -435,22 +433,34 @@ sioprobe(dev)
cy_outb(iobase, CY_CLEAR_INTR, 0);
DELAY(500);
return (cy_units(iobase, 0) == 0 ? 0 : -1);
}
static int
cy_units(cy_iobase, cy_align)
cy_addr cy_iobase;
int cy_align;
{
cy_addr iobase;
int cyu;
for (cyu = 0; cyu < CY_MAX_CD1400s; ++cyu) {
int i;
u_char firmware_version;
iobase = (cy_addr) (dev->id_maddr + cy_chip_offset[cyu]);
iobase = cy_iobase + (cy_chip_offset[cyu] << cy_align);
/* wait for chip to become ready for new command */
for (i = 0; i < 10; i++) {
DELAY(50);
if (!cd_inb(iobase, CD1400_CCR))
if (!cd_inb(iobase, CD1400_CCR, cy_align))
break;
}
/* clear the GFRCR register */
cd_outb(iobase, CD1400_GFRCR, 0);
cd_outb(iobase, CD1400_GFRCR, cy_align, 0);
/* issue a reset command */
cd_outb(iobase, CD1400_CCR,
cd_outb(iobase, CD1400_CCR, cy_align,
CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);
/* wait for the CD1400 to initialize itself */
@ -458,7 +468,7 @@ sioprobe(dev)
DELAY(50);
/* retrieve firmware version */
firmware_version = cd_inb(iobase, CD1400_GFRCR);
firmware_version = cd_inb(iobase, CD1400_GFRCR, cy_align);
if ((firmware_version & 0xf0) == 0x40)
break;
}
@ -470,38 +480,60 @@ sioprobe(dev)
*/
if ((firmware_version & 0xf0) != 0x40)
break;
++cy_nr_cd1400s[unit];
}
return (cy_nr_cd1400s[unit] == 0 ? 0 : -1);
return (cyu);
}
static int
sioattach(isdp)
struct isa_device *isdp;
struct isa_device *isdp;
{
int cyu;
cy_addr cy_iobase;
dev_t dev;
cy_addr iobase;
int ncyu;
int unit;
int adapter;
unit = isdp->id_unit;
if ((u_int)unit >= NCY)
return (0);
ncyu = cy_nr_cd1400s[unit];
if (ncyu == 0)
adapter = cyattach_common((cy_addr) isdp->id_maddr, 0);
if (adapter < 0)
return (0);
/*
* XXX
* This kludge is to allow ISA/PCI device specifications in the
* kernel config file to be in any order.
*/
if (isdp->id_unit != adapter) {
printf("cy%d: attached as cy%d\n", isdp->id_unit, adapter);
isdp->id_unit = adapter; /* XXX */
}
isdp->id_ri_flags |= RI_FAST;
return (1);
}
cy_iobase = (cy_addr)isdp->id_maddr;
unit *= CY_MAX_PORTS;
int
cyattach_common(cy_iobase, cy_align)
cy_addr cy_iobase;
int cy_align;
{
int cyu, ncyu, unit, adapter;
dev_t dev;
cy_addr iobase;
adapter = cy_total_devices;
if ((u_int)adapter >= NCY) {
printf("cy%d: can't attach adapter: insufficient cy devices configured\n",
adapter);
return (-1);
}
ncyu = cy_units(cy_iobase, cy_align);
if (ncyu == 0)
return (-1);
cy_nr_cd1400s[adapter] = ncyu;
cy_total_devices++;
unit = adapter * CY_MAX_PORTS;
for (cyu = 0; cyu < ncyu; ++cyu) {
int cdu;
iobase = (cy_addr) (isdp->id_maddr + cy_chip_offset[cyu]);
iobase = (cy_addr) (cy_iobase + (cy_chip_offset[cyu] << cy_align));
/* Set up a receive timeout period of than 1+ ms. */
cd_outb(iobase, CD1400_PPR,
cd_outb(iobase, CD1400_PPR, cy_align,
howmany(CY_CLOCK / CD1400_PPR_PRESCALER, 1000));
for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; ++cdu, ++unit) {
@ -522,6 +554,7 @@ sioattach(isdp)
com->cy_iobase = cy_iobase;
com->iobase = iobase;
com->cy_align = cy_align;
/*
* We don't use all the flags from <sys/ttydefaults.h> since they
@ -574,9 +607,9 @@ sioattach(isdp)
}
/* ensure an edge for the next interrupt */
cy_outb(cy_iobase, CY_CLEAR_INTR, 0);
cd_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
return (1);
return (adapter);
}
static int
@ -664,8 +697,8 @@ open_top:
iobase = com->iobase;
/* reset this channel */
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd1400_channel_cmd(iobase, CD1400_CCR_CMDRESET);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
cd1400_channel_cmd(iobase, CD1400_CCR_CMDRESET, com->cy_align);
/*
* Resetting disables the transmitter and receiver as well as
@ -677,7 +710,7 @@ open_top:
com->channel_control = 0;
/* Encode per-board unit in LIVR for access in intr routines. */
cd_outb(iobase, CD1400_LIVR,
cd_outb(iobase, CD1400_LIVR, com->cy_align,
(unit & CD1400_xIVR_CHAN) << CD1400_xIVR_CHAN_SHIFT);
/*
@ -732,8 +765,8 @@ open_top:
(void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
disable_intr();
com->prev_modem_status = com->last_modem_status
= cd_inb(iobase, CD1400_MSVR2);
cd_outb(iobase, CD1400_SRER,
= cd_inb(iobase, CD1400_MSVR2, com->cy_align);
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable
= CD1400_SRER_MDMCH | CD1400_SRER_RXDATA);
enable_intr();
@ -827,7 +860,7 @@ comhardclose(com)
com->poll_output = FALSE;
#endif
com->do_timestamp = 0;
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
#if 0
outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
#endif
@ -837,7 +870,7 @@ comhardclose(com)
outb(iobase + com_ier, 0);
#else
disable_intr();
cd_outb(iobase, CD1400_SRER, com->intr_enable = 0);
cd_outb(iobase, CD1400_SRER, com->cy_align, com->intr_enable = 0);
enable_intr();
#endif
tp = com->tp;
@ -859,7 +892,7 @@ comhardclose(com)
com->channel_control = CD1400_CCR_CMDCHANCTL
| CD1400_CCR_XMTEN
| CD1400_CCR_RCVDIS;
cd1400_channel_cmd(iobase, com->channel_control);
cd1400_channel_cmd(iobase, com->channel_control, com->cy_align);
if (com->dtr_wait != 0) {
timeout(siodtrwakeup, com, com->dtr_wait);
@ -948,20 +981,19 @@ void
siointr(unit)
int unit;
{
int baseu;
cy_addr cy_iobase;
int cyu;
cy_addr iobase;
u_char status;
cy_addr cy_iobase, iobase;
int baseu, cyu, cy_align;
u_char status;
baseu = unit * CY_MAX_PORTS;
cy_iobase = com_addr(baseu)->cy_iobase;
cy_align = com_addr(baseu)->cy_align;
/* check each CD1400 in turn */
for (cyu = 0; cyu < cy_nr_cd1400s[unit]; ++cyu) {
iobase = (cy_addr) (cy_iobase + cy_chip_offset[cyu]);
iobase = (cy_addr) (cy_iobase + (cy_chip_offset[cyu] << cy_align));
/* poll to see if it has any work */
status = cd_inb(iobase, CD1400_SVRR);
status = cd_inb(iobase, CD1400_SVRR, cy_align);
if (status == 0)
continue;
#ifdef CyDebug
@ -981,13 +1013,13 @@ siointr(unit)
#endif
#ifdef PollMode
save_rir = cd_inb(iobase, CD1400_RIR);
save_car = cd_inb(iobase, CD1400_CAR);
save_rir = cd_inb(iobase, CD1400_RIR, cy_align);
save_car = cd_inb(iobase, CD1400_CAR, cy_align);
/* enter rx service */
cd_outb(iobase, CD1400_CAR, save_rir);
cd_outb(iobase, CD1400_CAR, cy_align, save_rir);
serv_type = cd_inb(iobase, CD1400_RIVR);
serv_type = cd_inb(iobase, CD1400_RIVR, cy_align);
com = com_addr(baseu
+ ((serv_type >> CD1400_xIVR_CHAN_SHIFT)
& CD1400_xIVR_CHAN));
@ -1002,9 +1034,9 @@ siointr(unit)
if (serv_type & CD1400_RIVR_EXCEPTION) {
++com->recv_exception;
line_status = cd_inb(iobase, CD1400_RDSR);
line_status = cd_inb(iobase, CD1400_RDSR, cy_align);
/* break/unnattached error bits or real input? */
recv_data = cd_inb(iobase, CD1400_RDSR);
recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
#ifndef SOFT_HOTCHAR
if (line_status & CD1400_RDSR_SPECIAL
&& com->hotchar != 0)
@ -1053,7 +1085,7 @@ siointr(unit)
outb(com->modem_ctl_port,
com->mcr_image &= ~MCR_RTS);
#else
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, cy_align,
com->mcr_image &= ~MCR_RTS);
#endif
if (line_status & LSR_OE)
@ -1063,7 +1095,7 @@ siointr(unit)
} else {
int ifree;
count = cd_inb(iobase, CD1400_RDCR);
count = cd_inb(iobase, CD1400_RDCR, cy_align);
com->bytes_in += count;
ioptr = com->iptr;
ifree = com->ibufend - ioptr;
@ -1075,7 +1107,7 @@ siointr(unit)
microtime(&com->timestamp);
do {
recv_data = cd_inb(iobase,
CD1400_RDSR);
CD1400_RDSR, cy_align);
#ifdef SOFT_HOTCHAR
if (com->hotchar != 0
&& recv_data
@ -1090,7 +1122,7 @@ siointr(unit)
com->delta_error_counts
[CE_INTERRUPT_BUF_OVERFLOW] += count;
do {
recv_data = cd_inb(iobase, CD1400_RDSR);
recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
#ifdef SOFT_HOTCHAR
if (com->hotchar != 0
&& recv_data == com->hotchar)
@ -1107,12 +1139,12 @@ siointr(unit)
outb(com->modem_ctl_port,
com->mcr_image &= ~MCR_RTS);
#else
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, cy_align,
com->mcr_image &= ~MCR_RTS);
#endif
com_events += count;
do {
recv_data = cd_inb(iobase, CD1400_RDSR);
recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
#ifdef SOFT_HOTCHAR
if (com->hotchar != 0
&& recv_data == com->hotchar)
@ -1129,12 +1161,12 @@ cont:
/* terminate service context */
#ifdef PollMode
cd_outb(iobase, CD1400_RIR,
cd_outb(iobase, CD1400_RIR, cy_align,
save_rir
& ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY));
cd_outb(iobase, CD1400_CAR, save_car);
cd_outb(iobase, CD1400_CAR, cy_align, save_car);
#else
cd_outb(iobase, CD1400_EOSRR, 0);
cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
#endif
}
if (status & CD1400_SVRR_MDMCH) {
@ -1148,11 +1180,11 @@ cont:
#endif
#ifdef PollMode
save_mir = cd_inb(iobase, CD1400_MIR);
save_car = cd_inb(iobase, CD1400_CAR);
save_mir = cd_inb(iobase, CD1400_MIR, cy_align);
save_car = cd_inb(iobase, CD1400_CAR, cy_align);
/* enter modem service */
cd_outb(iobase, CD1400_CAR, save_mir);
cd_outb(iobase, CD1400_CAR, cy_align, save_mir);
com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS
+ (save_mir & CD1400_MIR_CHAN));
@ -1165,7 +1197,7 @@ cont:
& CD1400_xIVR_CHAN));
#endif
++com->mdm;
modem_status = cd_inb(iobase, CD1400_MSVR2);
modem_status = cd_inb(iobase, CD1400_MSVR2, cy_align);
if (modem_status != com->last_modem_status) {
if (com->do_dcd_timestamp
&& !(com->last_modem_status & MSR_DCD)
@ -1194,13 +1226,13 @@ cont:
| CS_ODEVREADY)
&& !(com->intr_enable
& CD1400_SRER_TXRDY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, cy_align,
com->intr_enable
|= CD1400_SRER_TXRDY);
} else {
com->state &= ~CS_ODEVREADY;
if (com->intr_enable & CD1400_SRER_TXRDY)
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, cy_align,
com->intr_enable
&= ~CD1400_SRER_TXRDY);
}
@ -1210,12 +1242,12 @@ cont:
/* terminate service context */
#ifdef PollMode
cd_outb(iobase, CD1400_MIR,
cd_outb(iobase, CD1400_MIR, cy_align,
save_mir
& ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY));
cd_outb(iobase, CD1400_CAR, save_car);
cd_outb(iobase, CD1400_CAR, cy_align, save_car);
#else
cd_outb(iobase, CD1400_EOSRR, 0);
cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
#endif
}
if (status & CD1400_SVRR_TXRDY) {
@ -1228,11 +1260,11 @@ cont:
#endif
#ifdef PollMode
save_tir = cd_inb(iobase, CD1400_TIR);
save_car = cd_inb(iobase, CD1400_CAR);
save_tir = cd_inb(iobase, CD1400_TIR, cy_align);
save_car = cd_inb(iobase, CD1400_CAR, cy_align);
/* enter tx service */
cd_outb(iobase, CD1400_CAR, save_tir);
cd_outb(iobase, CD1400_CAR, cy_align, save_tir);
com = com_addr(baseu
+ cyu * CD1400_NO_OF_CHANNELS
+ (save_tir & CD1400_TIR_CHAN));
@ -1255,7 +1287,7 @@ cont:
ocount = CD1400_TX_FIFO_SIZE;
com->bytes_out += ocount;
do
cd_outb(iobase, CD1400_TDR, *ioptr++);
cd_outb(iobase, CD1400_TDR, cy_align, *ioptr++);
while (--ocount != 0);
com->obufq.l_head = ioptr;
if (ioptr >= com->obufq.l_tail) {
@ -1271,7 +1303,7 @@ cont:
} else {
/* output just completed */
com->state &= ~CS_BUSY;
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, cy_align,
com->intr_enable
&= ~CD1400_SRER_TXRDY);
}
@ -1285,18 +1317,18 @@ cont:
/* terminate service context */
#ifdef PollMode
cd_outb(iobase, CD1400_TIR,
cd_outb(iobase, CD1400_TIR, cy_align,
save_tir
& ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY));
cd_outb(iobase, CD1400_CAR, save_car);
cd_outb(iobase, CD1400_CAR, cy_align, save_car);
#else
cd_outb(iobase, CD1400_EOSRR, 0);
cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
#endif
}
}
/* ensure an edge for the next interrupt */
cy_outb(cy_iobase, CY_CLEAR_INTR, 0);
cd_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
schedsofttty();
}
@ -1406,7 +1438,7 @@ sioioctl(dev, cmd, data, flag, p)
splx(s);
return (error);
}
cd_outb(iobase, CD1400_CAR, MINOR_TO_UNIT(mynor) & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, MINOR_TO_UNIT(mynor) & CD1400_CAR_CHAN);
switch (cmd) {
#if 0
case TIOCSBRK:
@ -1544,9 +1576,9 @@ repeat:
com->mcr_image |= MCR_RTS);
#else
iobase = com->iobase,
cd_outb(iobase, CD1400_CAR,
cd_outb(iobase, CD1400_CAR, com->cy_align,
unit & CD1400_CAR_CHAN),
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, com->cy_align,
com->mcr_image |= MCR_RTS);
#endif
enable_intr();
@ -1669,19 +1701,19 @@ comparam(tp, t)
com = com_addr(unit);
iobase = com->iobase;
s = spltty();
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
if (odivisor == 0)
(void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */
else
(void)commctl(com, TIOCM_DTR, DMBIS);
if (idivisor != 0) {
cd_outb(iobase, CD1400_RBPR, idivisor);
cd_outb(iobase, CD1400_RCOR, iprescaler);
cd_outb(iobase, CD1400_RBPR, com->cy_align, idivisor);
cd_outb(iobase, CD1400_RCOR, com->cy_align, iprescaler);
}
if (odivisor != 0) {
cd_outb(iobase, CD1400_TBPR, odivisor);
cd_outb(iobase, CD1400_TCOR, oprescaler);
cd_outb(iobase, CD1400_TBPR, com->cy_align, odivisor);
cd_outb(iobase, CD1400_TCOR, com->cy_align, oprescaler);
}
/*
@ -1694,20 +1726,20 @@ comparam(tp, t)
| (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS);
if (opt != com->channel_control) {
com->channel_control = opt;
cd1400_channel_cmd(iobase, opt);
cd1400_channel_cmd(iobase, opt, com->cy_align);
}
#ifdef Smarts
/* set special chars */
/* XXX if one is _POSIX_VDISABLE, can't use some others */
if (t->c_cc[VSTOP] != _POSIX_VDISABLE)
cd_outb(iobase, CD1400_SCHR1, t->c_cc[VSTOP]);
cd_outb(iobase, CD1400_SCHR1, com->cy_align, t->c_cc[VSTOP]);
if (t->c_cc[VSTART] != _POSIX_VDISABLE)
cd_outb(iobase, CD1400_SCHR2, t->c_cc[VSTART]);
cd_outb(iobase, CD1400_SCHR2, com->cy_align, t->c_cc[VSTART]);
if (t->c_cc[VINTR] != _POSIX_VDISABLE)
cd_outb(iobase, CD1400_SCHR3, t->c_cc[VINTR]);
cd_outb(iobase, CD1400_SCHR3, com->cy_align, t->c_cc[VINTR]);
if (t->c_cc[VSUSP] != _POSIX_VDISABLE)
cd_outb(iobase, CD1400_SCHR4, t->c_cc[VSUSP]);
cd_outb(iobase, CD1400_SCHR4, com->cy_align, t->c_cc[VSUSP]);
#endif
/*
@ -1754,14 +1786,14 @@ comparam(tp, t)
cor_change = 0;
if (opt != com->cor[0]) {
cor_change |= CD1400_CCR_COR1;
cd_outb(iobase, CD1400_COR1, com->cor[0] = opt);
cd_outb(iobase, CD1400_COR1, com->cy_align, com->cor[0] = opt);
}
/*
* Set receive time-out period, normally to max(one char time, 5 ms).
*/
if (t->c_ispeed == 0)
itimeout = cd_inb(iobase, CD1400_RTPR);
itimeout = cd_inb(iobase, CD1400_RTPR, com->cy_align);
else {
itimeout = (1000 * bits + t->c_ispeed - 1) / t->c_ispeed;
#ifdef SOFT_HOTCHAR
@ -1777,7 +1809,7 @@ comparam(tp, t)
itimeout = t->c_cc[VTIME] * 10;
if (itimeout > 255)
itimeout = 255;
cd_outb(iobase, CD1400_RTPR, itimeout);
cd_outb(iobase, CD1400_RTPR, com->cy_align, itimeout);
/*
* set channel option register 2 -
@ -1796,7 +1828,7 @@ comparam(tp, t)
#endif
if (opt != com->cor[1]) {
cor_change |= CD1400_CCR_COR2;
cd_outb(iobase, CD1400_COR2, com->cor[1] = opt);
cd_outb(iobase, CD1400_COR2, com->cy_align, com->cor[1] = opt);
}
/*
@ -1814,12 +1846,12 @@ comparam(tp, t)
#endif
if (opt != com->cor[2]) {
cor_change |= CD1400_CCR_COR3;
cd_outb(iobase, CD1400_COR3, com->cor[2] = opt);
cd_outb(iobase, CD1400_COR3, com->cy_align, com->cor[2] = opt);
}
/* notify the CD1400 if COR1-3 have changed */
if (cor_change)
cd1400_channel_cmd(iobase, CD1400_CCR_CMDCORCHG | cor_change);
cd1400_channel_cmd(iobase, CD1400_CCR_CMDCORCHG | cor_change, com->cy_align);
/*
* set channel option register 4 -
@ -1858,7 +1890,7 @@ comparam(tp, t)
#else
opt |= CD1400_COR4_PFO_EXCEPTION;
#endif
cd_outb(iobase, CD1400_COR4, opt);
cd_outb(iobase, CD1400_COR4, com->cy_align, opt);
/*
* set channel option register 5 -
@ -1875,7 +1907,7 @@ comparam(tp, t)
if (t->c_oflag & OCRNL)
opt |= CD1400_COR5_OCRNL;
#endif
cd_outb(iobase, CD1400_COR5, opt);
cd_outb(iobase, CD1400_COR5, com->cy_align, opt);
/*
* XXX we probably alway want to track carrier changes, so that
@ -1892,7 +1924,7 @@ comparam(tp, t)
if (cflag & CCTS_OFLOW)
opt |= CD1400_MCOR1_CTSzd;
#endif
cd_outb(iobase, CD1400_MCOR1, opt);
cd_outb(iobase, CD1400_MCOR1, com->cy_align, opt);
/*
* set modem change option register 2
@ -1903,7 +1935,7 @@ comparam(tp, t)
if (cflag & CCTS_OFLOW)
opt |= CD1400_MCOR2_CTSod;
#endif
cd_outb(iobase, CD1400_MCOR2, opt);
cd_outb(iobase, CD1400_MCOR2, com->cy_align, opt);
/*
* XXX should have done this long ago, but there is too much state
@ -1946,11 +1978,11 @@ comparam(tp, t)
#endif
if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
if (!(com->intr_enable & CD1400_SRER_TXRDY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable |= CD1400_SRER_TXRDY);
} else {
if (com->intr_enable & CD1400_SRER_TXRDY)
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable &= ~CD1400_SRER_TXRDY);
}
@ -1982,17 +2014,17 @@ comstart(tp)
#endif
disable_intr();
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
if (tp->t_state & TS_TTSTOP) {
com->state &= ~CS_TTGO;
if (com->intr_enable & CD1400_SRER_TXRDY)
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable &= ~CD1400_SRER_TXRDY);
} else {
com->state |= CS_TTGO;
if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)
&& !(com->intr_enable & CD1400_SRER_TXRDY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable |= CD1400_SRER_TXRDY);
}
if (tp->t_state & TS_TBLOCK) {
@ -2000,7 +2032,7 @@ comstart(tp)
#if 0
outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
#else
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, com->cy_align,
com->mcr_image &= ~MCR_RTS);
#endif
} else {
@ -2013,7 +2045,7 @@ comstart(tp)
#if 0
outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
#else
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, com->cy_align,
com->mcr_image |= MCR_RTS);
#endif
}
@ -2048,7 +2080,7 @@ comstart(tp)
com->state |= CS_BUSY;
if (com->state >= (CS_BUSY | CS_TTGO
| CS_ODEVREADY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable
|= CD1400_SRER_TXRDY);
}
@ -2076,7 +2108,7 @@ comstart(tp)
com->state |= CS_BUSY;
if (com->state >= (CS_BUSY | CS_TTGO
| CS_ODEVREADY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable
|= CD1400_SRER_TXRDY);
}
@ -2182,18 +2214,18 @@ commctl(com, bits, how)
switch (how) {
case DMSET:
com->mcr_image = mcr;
cd_outb(iobase, CD1400_MSVR1, mcr);
cd_outb(iobase, CD1400_MSVR2, mcr);
cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
break;
case DMBIS:
com->mcr_image = mcr = com->mcr_image | mcr;
cd_outb(iobase, CD1400_MSVR1, mcr);
cd_outb(iobase, CD1400_MSVR2, mcr);
cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
break;
case DMBIC:
com->mcr_image = mcr = com->mcr_image & ~mcr;
cd_outb(iobase, CD1400_MSVR1, mcr);
cd_outb(iobase, CD1400_MSVR2, mcr);
cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
break;
}
enable_intr();
@ -2331,17 +2363,17 @@ disc_optim(tp, t, com)
com->hotchar = 0;
#ifndef SOFT_HOTCHAR
iobase = com->iobase;
cd_outb(iobase, CD1400_CAR, com->unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, com->unit & CD1400_CAR_CHAN);
opt = com->cor[2] & ~CD1400_COR3_SCD34;
if (com->hotchar != 0) {
cd_outb(iobase, CD1400_SCHR3, com->hotchar);
cd_outb(iobase, CD1400_SCHR4, com->hotchar);
cd_outb(iobase, CD1400_SCHR3, com->cy_align, com->hotchar);
cd_outb(iobase, CD1400_SCHR4, com->cy_align, com->hotchar);
opt |= CD1400_COR3_SCD34;
}
if (opt != com->cor[2]) {
cd_outb(iobase, CD1400_COR3, com->cor[2] = opt);
cd_outb(iobase, CD1400_COR3, com->cy_align, com->cor[2] = opt);
cd1400_channel_cmd(com->iobase,
CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3);
CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3, com->cy_align);
}
#endif
}
@ -2405,9 +2437,10 @@ comspeed(speed, prescaler_io)
}
static void
cd1400_channel_cmd(iobase, cmd)
cd1400_channel_cmd(iobase, cmd, cy_align)
cy_addr iobase;
int cmd;
int cy_align;
{
/* XXX hsu@clinet.fi: This is always more dependent on ISA bus speed,
as the card is probed every round? Replaced delaycount with 8k.
@ -2417,14 +2450,14 @@ cd1400_channel_cmd(iobase, cmd)
u_int maxwait = 5 * 8 * 1024; /* approx. 5 ms */
/* wait for processing of previous command to complete */
while (cd_inb(iobase, CD1400_CCR) && maxwait--)
while (cd_inb(iobase, CD1400_CCR, cy_align) && maxwait--)
;
if (!maxwait)
log(LOG_ERR, "cy: channel command timeout (%d loops) - arrgh\n",
5 * 8 * 1024);
cd_outb(iobase, CD1400_CCR, cmd);
cd_outb(iobase, CD1400_CCR, cy_align, cmd);
}
#ifdef CyDebug
@ -2448,7 +2481,7 @@ cystatus(unit)
iobase = com->iobase;
printf("\n");
printf("cd1400 base address:\\tt%p\n", iobase);
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
printf("saved channel_control:\t\t0x%02x\n", com->channel_control);
printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n",
com->cor[0], com->cor[1], com->cor[2]);

132
sys/dev/cy/cy_pci.c Normal file
View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 1996, David Greenman
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
*/
/*
* Cyclades Y PCI serial interface driver
*/
#include <pci.h>
#if NPCI > 0
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <pci/pcivar.h>
#include <pci/cy_pcireg.h>
static char *cy_probe __P((pcici_t, pcidi_t));
static void cy_attach __P((pcici_t, int));
extern int cyattach_common(void *, int); /* Not exactly correct */
extern void cyintr(int);
static u_long cy_count;
static struct pci_device cy_device = {
"cy",
cy_probe,
cy_attach,
&cy_count,
NULL
};
DATA_SET(pcidevice_set, cy_device);
static char *
cy_probe(config_id, device_id)
pcici_t config_id;
pcidi_t device_id;
{
if ((device_id & 0xffff) == CY_VENDORID_CYCLADES &&
((device_id >> 16) == CY_DEVICEID_CYCLOM_Y_1 ||
(device_id >> 16) == CY_DEVICEID_CYCLOM_Y_2))
return ("Cyclades Cyclom-Y Serial Adapter");
return NULL;
}
static void
cy_attach(config_id, unit)
pcici_t config_id;
int unit;
{
vm_offset_t paddr;
void *vaddr;
u_int32_t ioport;
int adapter;
ioport = (u_int32_t) pci_conf_read(config_id, CY_PCI_BASE_ADDR1) & ~0x3;
paddr = pci_conf_read(config_id, CY_PCI_BASE_ADDR2) & ~0xf;
#if 0
if (!pci_map_mem(config_id, CY_PCI_BASE_ADDR2, &vaddr, &paddr)) {
printf("cy%d: couldn't map shared memory\n", unit);
return;
};
#endif
vaddr = pmap_mapdev(paddr, 0x4000);
adapter = cyattach_common(vaddr, 1);
if (adapter < 0) {
/*
* No ports found. Release resources and punt.
*/
printf("cy%d: no ports found!", unit);
goto fail;
}
/*
* Allocate our interrupt.
* XXX Using the ISA interrupt handler directly is a bit of a violation
* since it doesn't actually take the same argument. For PCI, the
* argument is a void * token, but for ISA it is a unit. Since
* there is no overlap in PCI/ISA unit numbers for this driver, and
* since the ISA driver must handle the interrupt anyway, we use
* the unit number as the token even for PCI.
*/
if (!pci_map_int(config_id, (pci_inthand_t *)cyintr, (void *)adapter, &tty_imask)) {
printf("cy%d: couldn't map interrupt\n", unit);
goto fail;
}
/*
* Enable the "local" interrupt input to generate a
* PCI interrupt.
*/
outw(ioport + CY_PLX_ICS, inw(CY_PLX_ICS) |
CY_PLX_ICS_IENABLE | CY_PLX_ICS_LOCAL_IENABLE);
return;
fail:
/* XXX should release any allocated virtual memory */
return;
}
#endif /* NPCI > 0 */

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: cyreg.h,v 1.1 1995/07/05 12:15:51 bde Exp $
* $Id: cyreg.h,v 1.2 1996/10/04 10:33:13 davidg Exp $
*/
/*
@ -36,22 +36,21 @@
#define CY8_SVCACKR 0x100
#define CY8_SVCACKT 0x200
#define CY8_SVCACKM 0x300
#define CY_CD1400_MEMSIZE 0x400
#define CY16_RESET 0x1400
#define CY_CLEAR_INTR 0x1800 /* intr ack address */
#define CY16_RESET 0x0a00
#define CY_CLEAR_INTR 0x0c00 /* intr ack address */
#define CY_MAX_CD1400s 8 /* for Cyclom-32Y */
#define CY_CLOCK 25000000 /* baud rate clock */
#ifdef CyDebug
#define cd_inb(iobase, reg) (++cd_inbs, *((iobase) + 2 * (reg)))
#define cd_inb(iobase, reg, cy_align) (++cd_inbs, *((iobase) + ((reg)*2 << (cy_align))))
#define cy_inb(iobase, reg) (++cy_inbs, *((iobase) + (reg)))
#define cd_outb(iobase, reg, val) (++cd_outbs, (void)(*((iobase) + 2 * (reg)) = (val)))
#define cd_outb(iobase, reg, cy_align, val) (++cd_outbs, (void)(*((iobase) + ((reg)*2 << (cy_align))) = (val)))
#define cy_outb(iobase, reg, val) (++cy_outbs, (void)(*((iobase) + (reg)) = (val)))
#else
#define cd_inb(iobase, reg) (*((iobase) + 2 * (reg)))
#define cd_inb(iobase, reg, cy_align) (*((iobase) + ((reg)*2 << (cy_align))))
#define cy_inb(iobase, reg) (*((iobase) + (reg)))
#define cd_outb(iobase, reg, val) ((void)(*((iobase) + 2 * (reg)) = (val)))
#define cd_outb(iobase, reg, cy_align, val) ((void)(*((iobase) + ((reg)*2 << (cy_align))) = (val)))
#define cy_outb(iobase, reg, val) ((void)(*((iobase) + (reg)) = (val)))
#endif

View File

@ -27,7 +27,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: cy.c,v 1.36 1996/10/04 10:33:08 davidg Exp $
* $Id: cy.c,v 1.37 1996/10/04 14:17:32 davidg Exp $
*/
#include "cy.h"
@ -141,7 +141,7 @@
/* We encode the cyclom unit number (cyu) in spare bits in the IVR's. */
#define CD1400_xIVR_CHAN_SHIFT 3
#define CD1400_xIVR_CHAN 0x0F /* XXX reduce to pack Cyclom-8Ys */
#define CD1400_xIVR_CHAN 0x1F /* XXX reduce to pack Cyclom-8Ys */
#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
#define RB_I_HIGH_WATER (TTYHOG - 2 * RS_IBUFSIZE)
@ -153,7 +153,8 @@
#define CONTROL_LOCK_STATE 0x40
#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
#define MINOR_TO_UNIT(mynor) ((mynor) & ~MINOR_MAGIC_MASK)
#define MINOR_TO_UNIT(mynor) (((mynor) >> 16) * CY_MAX_PORTS + \
(((mynor) & 0xff) & ~MINOR_MAGIC_MASK))
/*
* Input buffer watermarks.
@ -262,6 +263,7 @@ struct com_s {
cy_addr cy_iobase; /* base address of this port's cyclom */
cy_addr iobase; /* base address of this port's cd1400 */
int cy_align; /* index for register alignment */
struct tty *tp; /* cross reference */
@ -330,8 +332,10 @@ void siopoll __P((void));
#define siommap nommap
#define siostrategy nostrategy
int cyattach_common __P((cy_addr cy_iobase, int cy_align));
static int cy_units __P((cy_addr cy_iobase, int cy_align));
static int sioattach __P((struct isa_device *dev));
static void cd1400_channel_cmd __P((cy_addr iobase, int cmd));
static void cd1400_channel_cmd __P((cy_addr iobase, int cmd, int cy_align));
static timeout_t siodtrwakeup;
static void comhardclose __P((struct com_s *com));
#if 0
@ -399,6 +403,7 @@ static u_int cy_timeouts;
#endif
static int cy_nr_cd1400s[NCY];
static int cy_total_devices;
#undef RxFifoThreshold
static int volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2);
static int cy_chip_offset[] = {
@ -416,16 +421,9 @@ static int
sioprobe(dev)
struct isa_device *dev;
{
int cyu;
u_char firmware_version;
cy_addr iobase;
int unit;
iobase = (cy_addr)dev->id_maddr;
unit = dev->id_unit;
if ((u_int)unit >= NCY)
return (0);
cy_nr_cd1400s[unit] = 0;
/* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */
cy_inb(iobase, CY16_RESET); /* XXX? */
@ -435,22 +433,34 @@ sioprobe(dev)
cy_outb(iobase, CY_CLEAR_INTR, 0);
DELAY(500);
return (cy_units(iobase, 0) == 0 ? 0 : -1);
}
static int
cy_units(cy_iobase, cy_align)
cy_addr cy_iobase;
int cy_align;
{
cy_addr iobase;
int cyu;
for (cyu = 0; cyu < CY_MAX_CD1400s; ++cyu) {
int i;
u_char firmware_version;
iobase = (cy_addr) (dev->id_maddr + cy_chip_offset[cyu]);
iobase = cy_iobase + (cy_chip_offset[cyu] << cy_align);
/* wait for chip to become ready for new command */
for (i = 0; i < 10; i++) {
DELAY(50);
if (!cd_inb(iobase, CD1400_CCR))
if (!cd_inb(iobase, CD1400_CCR, cy_align))
break;
}
/* clear the GFRCR register */
cd_outb(iobase, CD1400_GFRCR, 0);
cd_outb(iobase, CD1400_GFRCR, cy_align, 0);
/* issue a reset command */
cd_outb(iobase, CD1400_CCR,
cd_outb(iobase, CD1400_CCR, cy_align,
CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);
/* wait for the CD1400 to initialize itself */
@ -458,7 +468,7 @@ sioprobe(dev)
DELAY(50);
/* retrieve firmware version */
firmware_version = cd_inb(iobase, CD1400_GFRCR);
firmware_version = cd_inb(iobase, CD1400_GFRCR, cy_align);
if ((firmware_version & 0xf0) == 0x40)
break;
}
@ -470,38 +480,60 @@ sioprobe(dev)
*/
if ((firmware_version & 0xf0) != 0x40)
break;
++cy_nr_cd1400s[unit];
}
return (cy_nr_cd1400s[unit] == 0 ? 0 : -1);
return (cyu);
}
static int
sioattach(isdp)
struct isa_device *isdp;
struct isa_device *isdp;
{
int cyu;
cy_addr cy_iobase;
dev_t dev;
cy_addr iobase;
int ncyu;
int unit;
int adapter;
unit = isdp->id_unit;
if ((u_int)unit >= NCY)
return (0);
ncyu = cy_nr_cd1400s[unit];
if (ncyu == 0)
adapter = cyattach_common((cy_addr) isdp->id_maddr, 0);
if (adapter < 0)
return (0);
/*
* XXX
* This kludge is to allow ISA/PCI device specifications in the
* kernel config file to be in any order.
*/
if (isdp->id_unit != adapter) {
printf("cy%d: attached as cy%d\n", isdp->id_unit, adapter);
isdp->id_unit = adapter; /* XXX */
}
isdp->id_ri_flags |= RI_FAST;
return (1);
}
cy_iobase = (cy_addr)isdp->id_maddr;
unit *= CY_MAX_PORTS;
int
cyattach_common(cy_iobase, cy_align)
cy_addr cy_iobase;
int cy_align;
{
int cyu, ncyu, unit, adapter;
dev_t dev;
cy_addr iobase;
adapter = cy_total_devices;
if ((u_int)adapter >= NCY) {
printf("cy%d: can't attach adapter: insufficient cy devices configured\n",
adapter);
return (-1);
}
ncyu = cy_units(cy_iobase, cy_align);
if (ncyu == 0)
return (-1);
cy_nr_cd1400s[adapter] = ncyu;
cy_total_devices++;
unit = adapter * CY_MAX_PORTS;
for (cyu = 0; cyu < ncyu; ++cyu) {
int cdu;
iobase = (cy_addr) (isdp->id_maddr + cy_chip_offset[cyu]);
iobase = (cy_addr) (cy_iobase + (cy_chip_offset[cyu] << cy_align));
/* Set up a receive timeout period of than 1+ ms. */
cd_outb(iobase, CD1400_PPR,
cd_outb(iobase, CD1400_PPR, cy_align,
howmany(CY_CLOCK / CD1400_PPR_PRESCALER, 1000));
for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; ++cdu, ++unit) {
@ -522,6 +554,7 @@ sioattach(isdp)
com->cy_iobase = cy_iobase;
com->iobase = iobase;
com->cy_align = cy_align;
/*
* We don't use all the flags from <sys/ttydefaults.h> since they
@ -574,9 +607,9 @@ sioattach(isdp)
}
/* ensure an edge for the next interrupt */
cy_outb(cy_iobase, CY_CLEAR_INTR, 0);
cd_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
return (1);
return (adapter);
}
static int
@ -664,8 +697,8 @@ open_top:
iobase = com->iobase;
/* reset this channel */
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd1400_channel_cmd(iobase, CD1400_CCR_CMDRESET);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
cd1400_channel_cmd(iobase, CD1400_CCR_CMDRESET, com->cy_align);
/*
* Resetting disables the transmitter and receiver as well as
@ -677,7 +710,7 @@ open_top:
com->channel_control = 0;
/* Encode per-board unit in LIVR for access in intr routines. */
cd_outb(iobase, CD1400_LIVR,
cd_outb(iobase, CD1400_LIVR, com->cy_align,
(unit & CD1400_xIVR_CHAN) << CD1400_xIVR_CHAN_SHIFT);
/*
@ -732,8 +765,8 @@ open_top:
(void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
disable_intr();
com->prev_modem_status = com->last_modem_status
= cd_inb(iobase, CD1400_MSVR2);
cd_outb(iobase, CD1400_SRER,
= cd_inb(iobase, CD1400_MSVR2, com->cy_align);
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable
= CD1400_SRER_MDMCH | CD1400_SRER_RXDATA);
enable_intr();
@ -827,7 +860,7 @@ comhardclose(com)
com->poll_output = FALSE;
#endif
com->do_timestamp = 0;
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
#if 0
outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
#endif
@ -837,7 +870,7 @@ comhardclose(com)
outb(iobase + com_ier, 0);
#else
disable_intr();
cd_outb(iobase, CD1400_SRER, com->intr_enable = 0);
cd_outb(iobase, CD1400_SRER, com->cy_align, com->intr_enable = 0);
enable_intr();
#endif
tp = com->tp;
@ -859,7 +892,7 @@ comhardclose(com)
com->channel_control = CD1400_CCR_CMDCHANCTL
| CD1400_CCR_XMTEN
| CD1400_CCR_RCVDIS;
cd1400_channel_cmd(iobase, com->channel_control);
cd1400_channel_cmd(iobase, com->channel_control, com->cy_align);
if (com->dtr_wait != 0) {
timeout(siodtrwakeup, com, com->dtr_wait);
@ -948,20 +981,19 @@ void
siointr(unit)
int unit;
{
int baseu;
cy_addr cy_iobase;
int cyu;
cy_addr iobase;
u_char status;
cy_addr cy_iobase, iobase;
int baseu, cyu, cy_align;
u_char status;
baseu = unit * CY_MAX_PORTS;
cy_iobase = com_addr(baseu)->cy_iobase;
cy_align = com_addr(baseu)->cy_align;
/* check each CD1400 in turn */
for (cyu = 0; cyu < cy_nr_cd1400s[unit]; ++cyu) {
iobase = (cy_addr) (cy_iobase + cy_chip_offset[cyu]);
iobase = (cy_addr) (cy_iobase + (cy_chip_offset[cyu] << cy_align));
/* poll to see if it has any work */
status = cd_inb(iobase, CD1400_SVRR);
status = cd_inb(iobase, CD1400_SVRR, cy_align);
if (status == 0)
continue;
#ifdef CyDebug
@ -981,13 +1013,13 @@ siointr(unit)
#endif
#ifdef PollMode
save_rir = cd_inb(iobase, CD1400_RIR);
save_car = cd_inb(iobase, CD1400_CAR);
save_rir = cd_inb(iobase, CD1400_RIR, cy_align);
save_car = cd_inb(iobase, CD1400_CAR, cy_align);
/* enter rx service */
cd_outb(iobase, CD1400_CAR, save_rir);
cd_outb(iobase, CD1400_CAR, cy_align, save_rir);
serv_type = cd_inb(iobase, CD1400_RIVR);
serv_type = cd_inb(iobase, CD1400_RIVR, cy_align);
com = com_addr(baseu
+ ((serv_type >> CD1400_xIVR_CHAN_SHIFT)
& CD1400_xIVR_CHAN));
@ -1002,9 +1034,9 @@ siointr(unit)
if (serv_type & CD1400_RIVR_EXCEPTION) {
++com->recv_exception;
line_status = cd_inb(iobase, CD1400_RDSR);
line_status = cd_inb(iobase, CD1400_RDSR, cy_align);
/* break/unnattached error bits or real input? */
recv_data = cd_inb(iobase, CD1400_RDSR);
recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
#ifndef SOFT_HOTCHAR
if (line_status & CD1400_RDSR_SPECIAL
&& com->hotchar != 0)
@ -1053,7 +1085,7 @@ siointr(unit)
outb(com->modem_ctl_port,
com->mcr_image &= ~MCR_RTS);
#else
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, cy_align,
com->mcr_image &= ~MCR_RTS);
#endif
if (line_status & LSR_OE)
@ -1063,7 +1095,7 @@ siointr(unit)
} else {
int ifree;
count = cd_inb(iobase, CD1400_RDCR);
count = cd_inb(iobase, CD1400_RDCR, cy_align);
com->bytes_in += count;
ioptr = com->iptr;
ifree = com->ibufend - ioptr;
@ -1075,7 +1107,7 @@ siointr(unit)
microtime(&com->timestamp);
do {
recv_data = cd_inb(iobase,
CD1400_RDSR);
CD1400_RDSR, cy_align);
#ifdef SOFT_HOTCHAR
if (com->hotchar != 0
&& recv_data
@ -1090,7 +1122,7 @@ siointr(unit)
com->delta_error_counts
[CE_INTERRUPT_BUF_OVERFLOW] += count;
do {
recv_data = cd_inb(iobase, CD1400_RDSR);
recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
#ifdef SOFT_HOTCHAR
if (com->hotchar != 0
&& recv_data == com->hotchar)
@ -1107,12 +1139,12 @@ siointr(unit)
outb(com->modem_ctl_port,
com->mcr_image &= ~MCR_RTS);
#else
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, cy_align,
com->mcr_image &= ~MCR_RTS);
#endif
com_events += count;
do {
recv_data = cd_inb(iobase, CD1400_RDSR);
recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
#ifdef SOFT_HOTCHAR
if (com->hotchar != 0
&& recv_data == com->hotchar)
@ -1129,12 +1161,12 @@ cont:
/* terminate service context */
#ifdef PollMode
cd_outb(iobase, CD1400_RIR,
cd_outb(iobase, CD1400_RIR, cy_align,
save_rir
& ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY));
cd_outb(iobase, CD1400_CAR, save_car);
cd_outb(iobase, CD1400_CAR, cy_align, save_car);
#else
cd_outb(iobase, CD1400_EOSRR, 0);
cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
#endif
}
if (status & CD1400_SVRR_MDMCH) {
@ -1148,11 +1180,11 @@ cont:
#endif
#ifdef PollMode
save_mir = cd_inb(iobase, CD1400_MIR);
save_car = cd_inb(iobase, CD1400_CAR);
save_mir = cd_inb(iobase, CD1400_MIR, cy_align);
save_car = cd_inb(iobase, CD1400_CAR, cy_align);
/* enter modem service */
cd_outb(iobase, CD1400_CAR, save_mir);
cd_outb(iobase, CD1400_CAR, cy_align, save_mir);
com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS
+ (save_mir & CD1400_MIR_CHAN));
@ -1165,7 +1197,7 @@ cont:
& CD1400_xIVR_CHAN));
#endif
++com->mdm;
modem_status = cd_inb(iobase, CD1400_MSVR2);
modem_status = cd_inb(iobase, CD1400_MSVR2, cy_align);
if (modem_status != com->last_modem_status) {
if (com->do_dcd_timestamp
&& !(com->last_modem_status & MSR_DCD)
@ -1194,13 +1226,13 @@ cont:
| CS_ODEVREADY)
&& !(com->intr_enable
& CD1400_SRER_TXRDY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, cy_align,
com->intr_enable
|= CD1400_SRER_TXRDY);
} else {
com->state &= ~CS_ODEVREADY;
if (com->intr_enable & CD1400_SRER_TXRDY)
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, cy_align,
com->intr_enable
&= ~CD1400_SRER_TXRDY);
}
@ -1210,12 +1242,12 @@ cont:
/* terminate service context */
#ifdef PollMode
cd_outb(iobase, CD1400_MIR,
cd_outb(iobase, CD1400_MIR, cy_align,
save_mir
& ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY));
cd_outb(iobase, CD1400_CAR, save_car);
cd_outb(iobase, CD1400_CAR, cy_align, save_car);
#else
cd_outb(iobase, CD1400_EOSRR, 0);
cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
#endif
}
if (status & CD1400_SVRR_TXRDY) {
@ -1228,11 +1260,11 @@ cont:
#endif
#ifdef PollMode
save_tir = cd_inb(iobase, CD1400_TIR);
save_car = cd_inb(iobase, CD1400_CAR);
save_tir = cd_inb(iobase, CD1400_TIR, cy_align);
save_car = cd_inb(iobase, CD1400_CAR, cy_align);
/* enter tx service */
cd_outb(iobase, CD1400_CAR, save_tir);
cd_outb(iobase, CD1400_CAR, cy_align, save_tir);
com = com_addr(baseu
+ cyu * CD1400_NO_OF_CHANNELS
+ (save_tir & CD1400_TIR_CHAN));
@ -1255,7 +1287,7 @@ cont:
ocount = CD1400_TX_FIFO_SIZE;
com->bytes_out += ocount;
do
cd_outb(iobase, CD1400_TDR, *ioptr++);
cd_outb(iobase, CD1400_TDR, cy_align, *ioptr++);
while (--ocount != 0);
com->obufq.l_head = ioptr;
if (ioptr >= com->obufq.l_tail) {
@ -1271,7 +1303,7 @@ cont:
} else {
/* output just completed */
com->state &= ~CS_BUSY;
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, cy_align,
com->intr_enable
&= ~CD1400_SRER_TXRDY);
}
@ -1285,18 +1317,18 @@ cont:
/* terminate service context */
#ifdef PollMode
cd_outb(iobase, CD1400_TIR,
cd_outb(iobase, CD1400_TIR, cy_align,
save_tir
& ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY));
cd_outb(iobase, CD1400_CAR, save_car);
cd_outb(iobase, CD1400_CAR, cy_align, save_car);
#else
cd_outb(iobase, CD1400_EOSRR, 0);
cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
#endif
}
}
/* ensure an edge for the next interrupt */
cy_outb(cy_iobase, CY_CLEAR_INTR, 0);
cd_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
schedsofttty();
}
@ -1406,7 +1438,7 @@ sioioctl(dev, cmd, data, flag, p)
splx(s);
return (error);
}
cd_outb(iobase, CD1400_CAR, MINOR_TO_UNIT(mynor) & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, MINOR_TO_UNIT(mynor) & CD1400_CAR_CHAN);
switch (cmd) {
#if 0
case TIOCSBRK:
@ -1544,9 +1576,9 @@ repeat:
com->mcr_image |= MCR_RTS);
#else
iobase = com->iobase,
cd_outb(iobase, CD1400_CAR,
cd_outb(iobase, CD1400_CAR, com->cy_align,
unit & CD1400_CAR_CHAN),
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, com->cy_align,
com->mcr_image |= MCR_RTS);
#endif
enable_intr();
@ -1669,19 +1701,19 @@ comparam(tp, t)
com = com_addr(unit);
iobase = com->iobase;
s = spltty();
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
if (odivisor == 0)
(void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */
else
(void)commctl(com, TIOCM_DTR, DMBIS);
if (idivisor != 0) {
cd_outb(iobase, CD1400_RBPR, idivisor);
cd_outb(iobase, CD1400_RCOR, iprescaler);
cd_outb(iobase, CD1400_RBPR, com->cy_align, idivisor);
cd_outb(iobase, CD1400_RCOR, com->cy_align, iprescaler);
}
if (odivisor != 0) {
cd_outb(iobase, CD1400_TBPR, odivisor);
cd_outb(iobase, CD1400_TCOR, oprescaler);
cd_outb(iobase, CD1400_TBPR, com->cy_align, odivisor);
cd_outb(iobase, CD1400_TCOR, com->cy_align, oprescaler);
}
/*
@ -1694,20 +1726,20 @@ comparam(tp, t)
| (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS);
if (opt != com->channel_control) {
com->channel_control = opt;
cd1400_channel_cmd(iobase, opt);
cd1400_channel_cmd(iobase, opt, com->cy_align);
}
#ifdef Smarts
/* set special chars */
/* XXX if one is _POSIX_VDISABLE, can't use some others */
if (t->c_cc[VSTOP] != _POSIX_VDISABLE)
cd_outb(iobase, CD1400_SCHR1, t->c_cc[VSTOP]);
cd_outb(iobase, CD1400_SCHR1, com->cy_align, t->c_cc[VSTOP]);
if (t->c_cc[VSTART] != _POSIX_VDISABLE)
cd_outb(iobase, CD1400_SCHR2, t->c_cc[VSTART]);
cd_outb(iobase, CD1400_SCHR2, com->cy_align, t->c_cc[VSTART]);
if (t->c_cc[VINTR] != _POSIX_VDISABLE)
cd_outb(iobase, CD1400_SCHR3, t->c_cc[VINTR]);
cd_outb(iobase, CD1400_SCHR3, com->cy_align, t->c_cc[VINTR]);
if (t->c_cc[VSUSP] != _POSIX_VDISABLE)
cd_outb(iobase, CD1400_SCHR4, t->c_cc[VSUSP]);
cd_outb(iobase, CD1400_SCHR4, com->cy_align, t->c_cc[VSUSP]);
#endif
/*
@ -1754,14 +1786,14 @@ comparam(tp, t)
cor_change = 0;
if (opt != com->cor[0]) {
cor_change |= CD1400_CCR_COR1;
cd_outb(iobase, CD1400_COR1, com->cor[0] = opt);
cd_outb(iobase, CD1400_COR1, com->cy_align, com->cor[0] = opt);
}
/*
* Set receive time-out period, normally to max(one char time, 5 ms).
*/
if (t->c_ispeed == 0)
itimeout = cd_inb(iobase, CD1400_RTPR);
itimeout = cd_inb(iobase, CD1400_RTPR, com->cy_align);
else {
itimeout = (1000 * bits + t->c_ispeed - 1) / t->c_ispeed;
#ifdef SOFT_HOTCHAR
@ -1777,7 +1809,7 @@ comparam(tp, t)
itimeout = t->c_cc[VTIME] * 10;
if (itimeout > 255)
itimeout = 255;
cd_outb(iobase, CD1400_RTPR, itimeout);
cd_outb(iobase, CD1400_RTPR, com->cy_align, itimeout);
/*
* set channel option register 2 -
@ -1796,7 +1828,7 @@ comparam(tp, t)
#endif
if (opt != com->cor[1]) {
cor_change |= CD1400_CCR_COR2;
cd_outb(iobase, CD1400_COR2, com->cor[1] = opt);
cd_outb(iobase, CD1400_COR2, com->cy_align, com->cor[1] = opt);
}
/*
@ -1814,12 +1846,12 @@ comparam(tp, t)
#endif
if (opt != com->cor[2]) {
cor_change |= CD1400_CCR_COR3;
cd_outb(iobase, CD1400_COR3, com->cor[2] = opt);
cd_outb(iobase, CD1400_COR3, com->cy_align, com->cor[2] = opt);
}
/* notify the CD1400 if COR1-3 have changed */
if (cor_change)
cd1400_channel_cmd(iobase, CD1400_CCR_CMDCORCHG | cor_change);
cd1400_channel_cmd(iobase, CD1400_CCR_CMDCORCHG | cor_change, com->cy_align);
/*
* set channel option register 4 -
@ -1858,7 +1890,7 @@ comparam(tp, t)
#else
opt |= CD1400_COR4_PFO_EXCEPTION;
#endif
cd_outb(iobase, CD1400_COR4, opt);
cd_outb(iobase, CD1400_COR4, com->cy_align, opt);
/*
* set channel option register 5 -
@ -1875,7 +1907,7 @@ comparam(tp, t)
if (t->c_oflag & OCRNL)
opt |= CD1400_COR5_OCRNL;
#endif
cd_outb(iobase, CD1400_COR5, opt);
cd_outb(iobase, CD1400_COR5, com->cy_align, opt);
/*
* XXX we probably alway want to track carrier changes, so that
@ -1892,7 +1924,7 @@ comparam(tp, t)
if (cflag & CCTS_OFLOW)
opt |= CD1400_MCOR1_CTSzd;
#endif
cd_outb(iobase, CD1400_MCOR1, opt);
cd_outb(iobase, CD1400_MCOR1, com->cy_align, opt);
/*
* set modem change option register 2
@ -1903,7 +1935,7 @@ comparam(tp, t)
if (cflag & CCTS_OFLOW)
opt |= CD1400_MCOR2_CTSod;
#endif
cd_outb(iobase, CD1400_MCOR2, opt);
cd_outb(iobase, CD1400_MCOR2, com->cy_align, opt);
/*
* XXX should have done this long ago, but there is too much state
@ -1946,11 +1978,11 @@ comparam(tp, t)
#endif
if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
if (!(com->intr_enable & CD1400_SRER_TXRDY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable |= CD1400_SRER_TXRDY);
} else {
if (com->intr_enable & CD1400_SRER_TXRDY)
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable &= ~CD1400_SRER_TXRDY);
}
@ -1982,17 +2014,17 @@ comstart(tp)
#endif
disable_intr();
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
if (tp->t_state & TS_TTSTOP) {
com->state &= ~CS_TTGO;
if (com->intr_enable & CD1400_SRER_TXRDY)
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable &= ~CD1400_SRER_TXRDY);
} else {
com->state |= CS_TTGO;
if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)
&& !(com->intr_enable & CD1400_SRER_TXRDY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable |= CD1400_SRER_TXRDY);
}
if (tp->t_state & TS_TBLOCK) {
@ -2000,7 +2032,7 @@ comstart(tp)
#if 0
outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
#else
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, com->cy_align,
com->mcr_image &= ~MCR_RTS);
#endif
} else {
@ -2013,7 +2045,7 @@ comstart(tp)
#if 0
outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
#else
cd_outb(iobase, CD1400_MSVR1,
cd_outb(iobase, CD1400_MSVR1, com->cy_align,
com->mcr_image |= MCR_RTS);
#endif
}
@ -2048,7 +2080,7 @@ comstart(tp)
com->state |= CS_BUSY;
if (com->state >= (CS_BUSY | CS_TTGO
| CS_ODEVREADY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable
|= CD1400_SRER_TXRDY);
}
@ -2076,7 +2108,7 @@ comstart(tp)
com->state |= CS_BUSY;
if (com->state >= (CS_BUSY | CS_TTGO
| CS_ODEVREADY))
cd_outb(iobase, CD1400_SRER,
cd_outb(iobase, CD1400_SRER, com->cy_align,
com->intr_enable
|= CD1400_SRER_TXRDY);
}
@ -2182,18 +2214,18 @@ commctl(com, bits, how)
switch (how) {
case DMSET:
com->mcr_image = mcr;
cd_outb(iobase, CD1400_MSVR1, mcr);
cd_outb(iobase, CD1400_MSVR2, mcr);
cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
break;
case DMBIS:
com->mcr_image = mcr = com->mcr_image | mcr;
cd_outb(iobase, CD1400_MSVR1, mcr);
cd_outb(iobase, CD1400_MSVR2, mcr);
cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
break;
case DMBIC:
com->mcr_image = mcr = com->mcr_image & ~mcr;
cd_outb(iobase, CD1400_MSVR1, mcr);
cd_outb(iobase, CD1400_MSVR2, mcr);
cd_outb(iobase, CD1400_MSVR1, com->cy_align, mcr);
cd_outb(iobase, CD1400_MSVR2, com->cy_align, mcr);
break;
}
enable_intr();
@ -2331,17 +2363,17 @@ disc_optim(tp, t, com)
com->hotchar = 0;
#ifndef SOFT_HOTCHAR
iobase = com->iobase;
cd_outb(iobase, CD1400_CAR, com->unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, com->unit & CD1400_CAR_CHAN);
opt = com->cor[2] & ~CD1400_COR3_SCD34;
if (com->hotchar != 0) {
cd_outb(iobase, CD1400_SCHR3, com->hotchar);
cd_outb(iobase, CD1400_SCHR4, com->hotchar);
cd_outb(iobase, CD1400_SCHR3, com->cy_align, com->hotchar);
cd_outb(iobase, CD1400_SCHR4, com->cy_align, com->hotchar);
opt |= CD1400_COR3_SCD34;
}
if (opt != com->cor[2]) {
cd_outb(iobase, CD1400_COR3, com->cor[2] = opt);
cd_outb(iobase, CD1400_COR3, com->cy_align, com->cor[2] = opt);
cd1400_channel_cmd(com->iobase,
CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3);
CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3, com->cy_align);
}
#endif
}
@ -2405,9 +2437,10 @@ comspeed(speed, prescaler_io)
}
static void
cd1400_channel_cmd(iobase, cmd)
cd1400_channel_cmd(iobase, cmd, cy_align)
cy_addr iobase;
int cmd;
int cy_align;
{
/* XXX hsu@clinet.fi: This is always more dependent on ISA bus speed,
as the card is probed every round? Replaced delaycount with 8k.
@ -2417,14 +2450,14 @@ cd1400_channel_cmd(iobase, cmd)
u_int maxwait = 5 * 8 * 1024; /* approx. 5 ms */
/* wait for processing of previous command to complete */
while (cd_inb(iobase, CD1400_CCR) && maxwait--)
while (cd_inb(iobase, CD1400_CCR, cy_align) && maxwait--)
;
if (!maxwait)
log(LOG_ERR, "cy: channel command timeout (%d loops) - arrgh\n",
5 * 8 * 1024);
cd_outb(iobase, CD1400_CCR, cmd);
cd_outb(iobase, CD1400_CCR, cy_align, cmd);
}
#ifdef CyDebug
@ -2448,7 +2481,7 @@ cystatus(unit)
iobase = com->iobase;
printf("\n");
printf("cd1400 base address:\\tt%p\n", iobase);
cd_outb(iobase, CD1400_CAR, unit & CD1400_CAR_CHAN);
cd_outb(iobase, CD1400_CAR, com->cy_align, unit & CD1400_CAR_CHAN);
printf("saved channel_control:\t\t0x%02x\n", com->channel_control);
printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n",
com->cor[0], com->cor[1], com->cor[2]);

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: cyreg.h,v 1.1 1995/07/05 12:15:51 bde Exp $
* $Id: cyreg.h,v 1.2 1996/10/04 10:33:13 davidg Exp $
*/
/*
@ -36,22 +36,21 @@
#define CY8_SVCACKR 0x100
#define CY8_SVCACKT 0x200
#define CY8_SVCACKM 0x300
#define CY_CD1400_MEMSIZE 0x400
#define CY16_RESET 0x1400
#define CY_CLEAR_INTR 0x1800 /* intr ack address */
#define CY16_RESET 0x0a00
#define CY_CLEAR_INTR 0x0c00 /* intr ack address */
#define CY_MAX_CD1400s 8 /* for Cyclom-32Y */
#define CY_CLOCK 25000000 /* baud rate clock */
#ifdef CyDebug
#define cd_inb(iobase, reg) (++cd_inbs, *((iobase) + 2 * (reg)))
#define cd_inb(iobase, reg, cy_align) (++cd_inbs, *((iobase) + ((reg)*2 << (cy_align))))
#define cy_inb(iobase, reg) (++cy_inbs, *((iobase) + (reg)))
#define cd_outb(iobase, reg, val) (++cd_outbs, (void)(*((iobase) + 2 * (reg)) = (val)))
#define cd_outb(iobase, reg, cy_align, val) (++cd_outbs, (void)(*((iobase) + ((reg)*2 << (cy_align))) = (val)))
#define cy_outb(iobase, reg, val) (++cy_outbs, (void)(*((iobase) + (reg)) = (val)))
#else
#define cd_inb(iobase, reg) (*((iobase) + 2 * (reg)))
#define cd_inb(iobase, reg, cy_align) (*((iobase) + ((reg)*2 << (cy_align))))
#define cy_inb(iobase, reg) (*((iobase) + (reg)))
#define cd_outb(iobase, reg, val) ((void)(*((iobase) + 2 * (reg)) = (val)))
#define cd_outb(iobase, reg, cy_align, val) ((void)(*((iobase) + ((reg)*2 << (cy_align))) = (val)))
#define cy_outb(iobase, reg, val) ((void)(*((iobase) + (reg)) = (val)))
#endif

132
sys/pci/cy_pci.c Normal file
View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 1996, David Greenman
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
*/
/*
* Cyclades Y PCI serial interface driver
*/
#include <pci.h>
#if NPCI > 0
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <pci/pcivar.h>
#include <pci/cy_pcireg.h>
static char *cy_probe __P((pcici_t, pcidi_t));
static void cy_attach __P((pcici_t, int));
extern int cyattach_common(void *, int); /* Not exactly correct */
extern void cyintr(int);
static u_long cy_count;
static struct pci_device cy_device = {
"cy",
cy_probe,
cy_attach,
&cy_count,
NULL
};
DATA_SET(pcidevice_set, cy_device);
static char *
cy_probe(config_id, device_id)
pcici_t config_id;
pcidi_t device_id;
{
if ((device_id & 0xffff) == CY_VENDORID_CYCLADES &&
((device_id >> 16) == CY_DEVICEID_CYCLOM_Y_1 ||
(device_id >> 16) == CY_DEVICEID_CYCLOM_Y_2))
return ("Cyclades Cyclom-Y Serial Adapter");
return NULL;
}
static void
cy_attach(config_id, unit)
pcici_t config_id;
int unit;
{
vm_offset_t paddr;
void *vaddr;
u_int32_t ioport;
int adapter;
ioport = (u_int32_t) pci_conf_read(config_id, CY_PCI_BASE_ADDR1) & ~0x3;
paddr = pci_conf_read(config_id, CY_PCI_BASE_ADDR2) & ~0xf;
#if 0
if (!pci_map_mem(config_id, CY_PCI_BASE_ADDR2, &vaddr, &paddr)) {
printf("cy%d: couldn't map shared memory\n", unit);
return;
};
#endif
vaddr = pmap_mapdev(paddr, 0x4000);
adapter = cyattach_common(vaddr, 1);
if (adapter < 0) {
/*
* No ports found. Release resources and punt.
*/
printf("cy%d: no ports found!", unit);
goto fail;
}
/*
* Allocate our interrupt.
* XXX Using the ISA interrupt handler directly is a bit of a violation
* since it doesn't actually take the same argument. For PCI, the
* argument is a void * token, but for ISA it is a unit. Since
* there is no overlap in PCI/ISA unit numbers for this driver, and
* since the ISA driver must handle the interrupt anyway, we use
* the unit number as the token even for PCI.
*/
if (!pci_map_int(config_id, (pci_inthand_t *)cyintr, (void *)adapter, &tty_imask)) {
printf("cy%d: couldn't map interrupt\n", unit);
goto fail;
}
/*
* Enable the "local" interrupt input to generate a
* PCI interrupt.
*/
outw(ioport + CY_PLX_ICS, inw(CY_PLX_ICS) |
CY_PLX_ICS_IENABLE | CY_PLX_ICS_LOCAL_IENABLE);
return;
fail:
/* XXX should release any allocated virtual memory */
return;
}
#endif /* NPCI > 0 */

40
sys/pci/cy_pcireg.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 1996, David Greenman
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
*/
#define CY_VENDORID_CYCLADES 0x120e
#define CY_DEVICEID_CYCLOM_Y_1 0x100
#define CY_DEVICEID_CYCLOM_Y_2 0x101
#define CY_PCI_BASE_ADDR0 0x10
#define CY_PCI_BASE_ADDR1 0x14
#define CY_PCI_BASE_ADDR2 0x18
#define CY_PLX_ICS 0x68
#define CY_PLX_ICS_IENABLE 0x100
#define CY_PLX_ICS_LOCAL_IENABLE 0x800