patch-2.1.74 linux/drivers/char/stallion.c
Next file: linux/drivers/net/hamradio/scc.c
Previous file: linux/drivers/char/istallion.c
Back to the patch index
Back to the overall index
- Lines: 2521
- Date:
Fri Dec 19 12:30:54 1997
- Orig file:
v2.1.73/linux/drivers/char/stallion.c
- Orig date:
Wed Dec 10 11:12:43 1997
diff -u --recursive --new-file v2.1.73/linux/drivers/char/stallion.c linux/drivers/char/stallion.c
@@ -66,6 +66,8 @@
#define BRD_ECH 21
#define BRD_ECHMC 22
#define BRD_ECHPCI 26
+#define BRD_ECH64PCI 27
+#define BRD_EASYIOPCI 28
/*
* Define a configuration structure to hold the board configuration.
@@ -101,34 +103,11 @@
int irqtype;
} stlconf_t;
-/*static stlconf_t stl_brdconf[] = {
- { BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },
-};*/
-
-#ifdef MODULE
-static char *brdtype[STL_MAXBRDS] = {"\0", };
-static int io[STL_MAXBRDS] = { 0, };
-static int secio[STL_MAXBRDS] = { 0, };
-static int irq[STL_MAXBRDS] = { 0, };
-
-MODULE_PARM(brdtype, "1-" __MODULE_STRING(STL_MAXBRDS) "s");
-MODULE_PARM(io, "1-" __MODULE_STRING(STL_MAXBRDS) "i");
-MODULE_PARM(secio, "1-" __MODULE_STRING(STL_MAXBRDS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(STL_MAXBRDS) "i");
-
-static stlconf_t stl_brdconf[STL_MAXBRDS];
-static int stl_nrbrds = 0;
-
-#else
static stlconf_t stl_brdconf[] = {
{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },
- { BRD_EASYIO, 0x2a8, 0, 0, 10, 0 },
- { BRD_EASYIO, 0x2b0, 0, 0, 10, 0 },
- { BRD_ECH, 0x2a0, 0x240, 0, 10, 0 },
};
static int stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t);
-#endif
/*****************************************************************************/
@@ -162,8 +141,9 @@
* Define our local driver identity first. Set up stuff to deal with
* all the local structures required by a serial tty driver.
*/
-static char *stl_drvname = "Stallion Multiport Serial Driver";
-static char *stl_drvversion = "5.3.4";
+static char *stl_drvtitle = "Stallion Multiport Serial Driver";
+static char *stl_drvname = "stallion";
+static char *stl_drvversion = "5.4.1";
static char *stl_serialname = "ttyE";
static char *stl_calloutname = "cue";
@@ -272,6 +252,8 @@
(char *) NULL,
(char *) NULL,
"EC8/32-PCI",
+ "EC8/64-PCI",
+ "EasyIO-PCI",
};
/*****************************************************************************/
@@ -320,12 +302,6 @@
#define ECH_ADDR2MASK 0x1e0
/*
- * Define real Stallion PCI vemdor and device ID.
- */
-#define PCI_VENDOR_ID_STALLION 0x124d
-#define PCI_DEVICE_ID_ECHPCI832 0x0000
-
-/*
* Define the vector mapping bits for the programmable interrupt board
* hardware. These bits encode the interrupt for the board to use - it
* is software selectable (except the EIO-8M).
@@ -354,9 +330,47 @@
outb((stl_brds[(brdnr)]->ioctrlval | ECH_BRDDISABLE), \
stl_brds[(brdnr)]->ioctrl);
-#define STL_MAXBAUD 921600
-#define STL_BAUDBASE 115200
-#define STL_CLOSEDELAY 50
+#define STL_CD1400MAXBAUD 230400
+#define STL_SC26198MAXBAUD 460800
+
+#define STL_BAUDBASE 115200
+#define STL_CLOSEDELAY (5 * HZ / 10)
+
+/*****************************************************************************/
+
+/*
+ * Define the Stallion PCI vendor and device IDs.
+ */
+#ifndef PCI_VENDOR_ID_STALLION
+#define PCI_VENDOR_ID_STALLION 0x124d
+#endif
+#ifndef PCI_DEVICE_ID_ECHPCI832
+#define PCI_DEVICE_ID_ECHPCI832 0x0000
+#endif
+#ifndef PCI_DEVICE_ID_ECHPCI864
+#define PCI_DEVICE_ID_ECHPCI864 0x0002
+#endif
+#ifndef PCI_DEVICE_ID_EIOPCI
+#define PCI_DEVICE_ID_EIOPCI 0x0003
+#endif
+
+/*
+ * Define structure to hold all Stallion PCI boards.
+ */
+typedef struct stlpcibrd {
+ unsigned short vendid;
+ unsigned short devid;
+ int brdtype;
+} stlpcibrd_t;
+
+static stlpcibrd_t stl_pcibrds[] = {
+ { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI864, BRD_ECH64PCI },
+ { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_EIOPCI, BRD_EASYIOPCI },
+ { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832, BRD_ECHPCI },
+ { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, BRD_ECHPCI },
+};
+
+static int stl_nrpcibrds = sizeof(stl_pcibrds) / sizeof(stlpcibrd_t);
/*****************************************************************************/
@@ -409,15 +423,19 @@
static void stl_stop(struct tty_struct *tty);
static void stl_start(struct tty_struct *tty);
static void stl_flushbuffer(struct tty_struct *tty);
+static void stl_breakctl(struct tty_struct *tty, int state);
+static void stl_waituntilsent(struct tty_struct *tty, int timeout);
+static void stl_sendxchar(struct tty_struct *tty, char ch);
static void stl_hangup(struct tty_struct *tty);
+static int stl_memopen(struct inode *ip, struct file *fp);
+static int stl_memclose(struct inode *ip, struct file *fp);
static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
+static int stl_portinfo(stlport_t *portp, int portnr, char *pos);
+static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data);
-static inline int stl_initbrds(void);
-static inline int stl_initeio(stlbrd_t *brdp);
-static inline int stl_initech(stlbrd_t *brdp);
static int stl_brdinit(stlbrd_t *brdp);
static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp);
-static int stl_mapirq(int irq);
+static int stl_mapirq(int irq, char *name);
static void stl_getserial(stlport_t *portp, struct serial_struct *sp);
static int stl_setserial(stlport_t *portp, struct serial_struct *sp);
static int stl_getbrdstats(combrd_t *bp);
@@ -432,12 +450,18 @@
static void stl_echatintr(stlbrd_t *brdp);
static void stl_echmcaintr(stlbrd_t *brdp);
static void stl_echpciintr(stlbrd_t *brdp);
+static void stl_echpci64intr(stlbrd_t *brdp);
static void stl_offintr(void *private);
static void *stl_memalloc(int len);
static stlport_t *stl_getport(int brdnr, int panelnr, int portnr);
+static inline int stl_initbrds(void);
+static inline int stl_initeio(stlbrd_t *brdp);
+static inline int stl_initech(stlbrd_t *brdp);
+
#ifdef CONFIG_PCI
-static inline int stl_findpcibrds(void);
+static inline int stl_findpcibrds(void);
+static inline int stl_initpcibrd(int brdtype, unsigned char busnr, unsigned char devnr);
#endif
/*
@@ -455,15 +479,19 @@
static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx);
static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx);
static void stl_cd1400disableintrs(stlport_t *portp);
-static void stl_cd1400sendbreak(stlport_t *portp, long len);
+static void stl_cd1400sendbreak(stlport_t *portp, int len);
static void stl_cd1400flowctrl(stlport_t *portp, int state);
+static void stl_cd1400sendflow(stlport_t *portp, int state);
static void stl_cd1400flush(stlport_t *portp);
+static int stl_cd1400datastate(stlport_t *portp);
static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase);
static void stl_cd1400echintr(stlpanel_t *panelp, unsigned int iobase);
static void stl_cd1400txisr(stlpanel_t *panelp, int ioaddr);
static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr);
static void stl_cd1400mdmisr(stlpanel_t *panelp, int ioaddr);
+static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr);
+
/*
* SC26198 uart specific handling functions.
*/
@@ -479,9 +507,12 @@
static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx);
static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx);
static void stl_sc26198disableintrs(stlport_t *portp);
-static void stl_sc26198sendbreak(stlport_t *portp, long len);
+static void stl_sc26198sendbreak(stlport_t *portp, int len);
static void stl_sc26198flowctrl(stlport_t *portp, int state);
+static void stl_sc26198sendflow(stlport_t *portp, int state);
static void stl_sc26198flush(stlport_t *portp);
+static int stl_sc26198datastate(stlport_t *portp);
+static void stl_sc26198wait(stlport_t *portp);
static void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty);
static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase);
static void stl_sc26198txisr(stlport_t *port);
@@ -504,9 +535,11 @@
void (*enablerxtx)(stlport_t *portp, int rx, int tx);
void (*startrxtx)(stlport_t *portp, int rx, int tx);
void (*disableintrs)(stlport_t *portp);
- void (*sendbreak)(stlport_t *portp, long len);
+ void (*sendbreak)(stlport_t *portp, int len);
void (*flowctrl)(stlport_t *portp, int state);
+ void (*sendflow)(stlport_t *portp, int state);
void (*flush)(stlport_t *portp);
+ int (*datastate)(stlport_t *portp);
void (*intr)(stlpanel_t *panelp, unsigned int iobase);
} uart_t;
@@ -523,7 +556,9 @@
#define stl_disableintrs (* ((uart_t *) portp->uartp)->disableintrs)
#define stl_sendbreak (* ((uart_t *) portp->uartp)->sendbreak)
#define stl_flowctrl (* ((uart_t *) portp->uartp)->flowctrl)
+#define stl_sendflow (* ((uart_t *) portp->uartp)->sendflow)
#define stl_flush (* ((uart_t *) portp->uartp)->flush)
+#define stl_datastate (* ((uart_t *) portp->uartp)->datastate)
/*****************************************************************************/
@@ -541,7 +576,9 @@
stl_cd1400disableintrs,
stl_cd1400sendbreak,
stl_cd1400flowctrl,
+ stl_cd1400sendflow,
stl_cd1400flush,
+ stl_cd1400datastate,
stl_cd1400eiointr
};
@@ -585,7 +622,9 @@
stl_sc26198disableintrs,
stl_sc26198sendbreak,
stl_sc26198flowctrl,
+ stl_sc26198sendflow,
stl_sc26198flush,
+ stl_sc26198datastate,
stl_sc26198intr
};
@@ -626,8 +665,8 @@
NULL,
stl_memioctl,
NULL,
- NULL,
- NULL,
+ stl_memopen,
+ stl_memclose,
NULL
};
@@ -639,22 +678,9 @@
* Loadable module initialization stuff.
*/
-struct board_type_elem
-{
- int type_id;
- char *name;
-};
-
-struct board_type_elem board_types[] = {
- { BRD_EASYIO, "easyio" },
- { BRD_ECH, "ech" },
- { BRD_ECHMC, "echmc" },
- { BRD_ECHPCI, "echpci" } };
-
int init_module()
{
unsigned long flags;
- int i, j, num_board_types;
#if DEBUG
printk("init_module()\n");
@@ -662,25 +688,6 @@
save_flags(flags);
cli();
-
- num_board_types = sizeof(board_types) / sizeof(struct board_type_elem);
- for (i = 0; (i < STL_MAXBRDS && io[i]); i++)
- {
- stl_brdconf[stl_nrbrds].brdtype = 0;
- for (j = 0; j < num_board_types; j++)
- if(strcmp(board_types[j].name, brdtype[i]) == 0)
- stl_brdconf[stl_nrbrds].brdtype = board_types[j].type_id;
- if(stl_brdconf[stl_nrbrds].brdtype != 0)
- {
- stl_brdconf[stl_nrbrds].ioaddr1 = io[i];
- stl_brdconf[stl_nrbrds].ioaddr2 = secio[i];
- stl_brdconf[stl_nrbrds].memaddr = 0;
- stl_brdconf[stl_nrbrds].irq = irq[i];
- stl_brdconf[stl_nrbrds].irqtype = 0;
- stl_nrbrds++;
- }
- }
-
stl_init();
restore_flags(flags);
@@ -701,7 +708,8 @@
printk("cleanup_module()\n");
#endif
- printk(KERN_INFO "Unloading %s: version %s\n", stl_drvname, stl_drvversion);
+ printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle,
+ stl_drvversion);
save_flags(flags);
cli();
@@ -715,12 +723,14 @@
i = tty_unregister_driver(&stl_serial);
j = tty_unregister_driver(&stl_callout);
if (i || j) {
- printk("STALLION: failed to un-register tty driver, errno=%d,%d\n", -i, -j);
+ printk("STALLION: failed to un-register tty driver, "
+ "errno=%d,%d\n", -i, -j);
restore_flags(flags);
return;
}
if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
- printk("STALLION: failed to un-register serial memory device, errno=%d\n", -i);
+ printk("STALLION: failed to un-register serial memory device, "
+ "errno=%d\n", -i);
if (stl_tmpwritebuf != (char *) NULL)
kfree_s(stl_tmpwritebuf, STL_TXBUFSIZE);
@@ -729,33 +739,24 @@
brdp = stl_brds[i];
for (j = 0; (j < STL_MAXPANELS); j++) {
panelp = brdp->panels[j];
- if (panelp != (stlpanel_t *) NULL) {
- for (k = 0; (k < STL_PORTSPERPANEL); k++) {
- portp = panelp->ports[k];
- if (portp != (stlport_t *) NULL) {
- if (portp->tty != (struct tty_struct *) NULL)
- stl_hangup(portp->tty);
- if (portp->tx.buf != (char *) NULL)
- kfree_s(portp->tx.buf, STL_TXBUFSIZE);
- kfree_s(portp, sizeof(stlport_t));
- }
- }
- kfree_s(panelp, sizeof(stlpanel_t));
+ if (panelp == (stlpanel_t *) NULL)
+ continue;
+ for (k = 0; (k < STL_PORTSPERPANEL); k++) {
+ portp = panelp->ports[k];
+ if (portp == (stlport_t *) NULL)
+ continue;
+ if (portp->tty != (struct tty_struct *) NULL)
+ stl_hangup(portp->tty);
+ if (portp->tx.buf != (char *) NULL)
+ kfree_s(portp->tx.buf, STL_TXBUFSIZE);
+ kfree_s(portp, sizeof(stlport_t));
}
-
+ kfree_s(panelp, sizeof(stlpanel_t));
}
- if (brdp->brdtype == BRD_ECH) {
- release_region(brdp->ioaddr1, 2);
- release_region(brdp->ioaddr2, 32);
- } else if (brdp->brdtype == BRD_ECHPCI) {
- release_region(brdp->ioaddr1, 4);
- release_region(brdp->ioaddr2, 8);
- } else if (brdp->brdtype == BRD_ECHMC) {
- release_region(brdp->ioaddr1, 64);
- } else if (brdp->brdtype == BRD_EASYIO) {
- release_region(brdp->ioaddr1, 8);
- }
+ release_region(brdp->ioaddr1, brdp->iosize1);
+ if (brdp->iosize2 > 0)
+ release_region(brdp->ioaddr2, brdp->iosize2);
kfree_s(brdp, sizeof(stlbrd_t));
stl_brds[i] = (stlbrd_t *) NULL;
@@ -790,7 +791,8 @@
int brdnr, panelnr, portnr, rc;
#if DEBUG
- printk("stl_open(tty=%x,filp=%x): device=%x\n", (int) tty, (int) filp, tty->device);
+ printk("stl_open(tty=%x,filp=%x): device=%x\n", (int) tty,
+ (int) filp, tty->device);
#endif
minordev = MINOR(tty->device);
@@ -817,6 +819,8 @@
if (portp == (stlport_t *) NULL)
return(-ENODEV);
+ MOD_INC_USE_COUNT;
+
/*
* On the first open of the device setup the port hardware, and
* initialize the per port data structure.
@@ -865,10 +869,10 @@
return(-EBUSY);
if (portp->flags & ASYNC_CALLOUT_ACTIVE) {
if ((portp->flags & ASYNC_SESSION_LOCKOUT) &&
- (portp->session != current->session))
+ (portp->session != current->session))
return(-EBUSY);
if ((portp->flags & ASYNC_PGRP_LOCKOUT) &&
- (portp->pgrp != current->pgrp))
+ (portp->pgrp != current->pgrp))
return(-EBUSY);
}
portp->flags |= ASYNC_CALLOUT_ACTIVE;
@@ -878,10 +882,7 @@
return(-EBUSY);
} else {
if ((rc = stl_waitcarrier(portp, filp)) != 0)
- {
- MOD_INC_USE_COUNT;
return(rc);
- }
}
portp->flags |= ASYNC_NORMAL_ACTIVE;
}
@@ -896,7 +897,6 @@
portp->session = current->session;
portp->pgrp = current->pgrp;
- MOD_INC_USE_COUNT;
return(0);
}
@@ -930,13 +930,14 @@
save_flags(flags);
cli();
portp->openwaitcnt++;
- if (portp->refcount > 0)
+ if (! tty_hung_up_p(filp))
portp->refcount--;
for (;;) {
if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0)
stl_setsignals(portp, 1, 1);
- if (tty_hung_up_p(filp) || ((portp->flags & ASYNC_INITIALIZED) == 0)) {
+ if (tty_hung_up_p(filp) ||
+ ((portp->flags & ASYNC_INITIALIZED) == 0)) {
if (portp->flags & ASYNC_HUP_NOTIFY)
rc = -EBUSY;
else
@@ -944,8 +945,8 @@
break;
}
if (((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) &&
- ((portp->flags & ASYNC_CLOSING) == 0) &&
- (doclocal || (portp->sigs & TIOCM_CD))) {
+ ((portp->flags & ASYNC_CLOSING) == 0) &&
+ (doclocal || (portp->sigs & TIOCM_CD))) {
break;
}
if (signal_pending(current)) {
@@ -981,11 +982,14 @@
save_flags(flags);
cli();
if (tty_hung_up_p(filp)) {
+ MOD_DEC_USE_COUNT;
restore_flags(flags);
return;
}
- MOD_DEC_USE_COUNT;
+ if ((tty->count == 1) && (portp->refcount != 1))
+ portp->refcount = 1;
if (portp->refcount-- > 1) {
+ MOD_DEC_USE_COUNT;
restore_flags(flags);
return;
}
@@ -1000,14 +1004,14 @@
/*
* May want to wait for any data to drain before closing. The BUSY
- * flag keeps track of whether we are still sending or not - it allows
- * for the FIFO in the cd1400.
+ * flag keeps track of whether we are still sending or not - it is
+ * very accurate for the cd1400, not quite so for the sc26198.
+ * (The sc26198 has no "end-of-data" interrupt only empty FIFO)
*/
tty->closing = 1;
- if (test_bit(ASYI_TXBUSY, &portp->istate)) {
- if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, portp->closing_wait);
- }
+ if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, portp->closing_wait);
+ stl_waituntilsent(tty, (HZ / 2));
portp->flags &= ~ASYNC_INITIALIZED;
stl_disableintrs(portp);
@@ -1027,7 +1031,6 @@
(tty->ldisc.flush_buffer)(tty);
tty->closing = 0;
- tty->driver_data = (void *) NULL;
portp->tty = (struct tty_struct *) NULL;
if (portp->openwaitcnt) {
@@ -1036,8 +1039,10 @@
wake_up_interruptible(&portp->open_wait);
}
- portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+ portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE |
+ ASYNC_CLOSING);
wake_up_interruptible(&portp->close_wait);
+ MOD_DEC_USE_COUNT;
restore_flags(flags);
}
@@ -1058,6 +1063,7 @@
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + len;
schedule();
+ current->state = TASK_RUNNING;
}
}
@@ -1077,10 +1083,12 @@
char *head, *tail;
#if DEBUG
- printk("stl_write(tty=%x,from_user=%d,buf=%x,count=%d)\n", (int) tty, from_user, (int) buf, count);
+ printk("stl_write(tty=%x,from_user=%d,buf=%x,count=%d)\n",
+ (int) tty, from_user, (int) buf, count);
#endif
- if ((tty == (struct tty_struct *) NULL) || (stl_tmpwritebuf == (char *) NULL))
+ if ((tty == (struct tty_struct *) NULL) ||
+ (stl_tmpwritebuf == (char *) NULL))
return(0);
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
@@ -1202,7 +1210,8 @@
return;
#if 0
- if (tty->stopped || tty->hw_stopped || (portp->tx.head == portp->tx.tail))
+ if (tty->stopped || tty->hw_stopped ||
+ (portp->tx.head == portp->tx.tail))
return;
#endif
stl_startrxtx(portp, -1, 1);
@@ -1327,12 +1336,14 @@
copy_from_user(&sio, sp, sizeof(struct serial_struct));
if (!suser()) {
if ((sio.baud_base != portp->baud_base) ||
- (sio.close_delay != portp->close_delay) ||
- ((sio.flags & ~ASYNC_USR_MASK) != (portp->flags & ~ASYNC_USR_MASK)))
+ (sio.close_delay != portp->close_delay) ||
+ ((sio.flags & ~ASYNC_USR_MASK) !=
+ (portp->flags & ~ASYNC_USR_MASK)))
return(-EPERM);
}
- portp->flags = (portp->flags & ~ASYNC_USR_MASK) | (sio.flags & ASYNC_USR_MASK);
+ portp->flags = (portp->flags & ~ASYNC_USR_MASK) |
+ (sio.flags & ASYNC_USR_MASK);
portp->baud_base = sio.baud_base;
portp->close_delay = sio.close_delay;
portp->closing_wait = sio.closing_wait;
@@ -1350,7 +1361,8 @@
int rc;
#if DEBUG
- printk("stl_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n", (int) tty, (int) file, cmd, (int) arg);
+ printk("stl_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n",
+ (int) tty, (int) file, cmd, (int) arg);
#endif
if (tty == (struct tty_struct *) NULL)
@@ -1360,7 +1372,7 @@
return(-ENODEV);
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) {
+ (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) {
if (tty->flags & (1 << TTY_IO_ERROR))
return(-EIO);
}
@@ -1368,67 +1380,68 @@
rc = 0;
switch (cmd) {
- case TCSBRK:
- if ((rc = tty_check_change(tty)) == 0) {
- tty_wait_until_sent(tty, 0);
- if (! arg)
- stl_sendbreak(portp, 250);
- }
- break;
- case TCSBRKP:
- if ((rc = tty_check_change(tty)) == 0) {
- tty_wait_until_sent(tty, 0);
- stl_sendbreak(portp, (arg ? (arg * 100) : 250));
- }
- break;
case TIOCGSOFTCAR:
rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned int *) arg);
+ (unsigned int *) arg);
break;
case TIOCSSOFTCAR:
- if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) {
+ if ((rc = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(int))) == 0) {
get_user(ival, (unsigned int *) arg);
- tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (ival ? CLOCAL : 0);
+ tty->termios->c_cflag =
+ (tty->termios->c_cflag & ~CLOCAL) |
+ (ival ? CLOCAL : 0);
}
break;
case TIOCMGET:
- if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) == 0) {
+ if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(unsigned int))) == 0) {
ival = stl_getsignals(portp);
put_user(ival, (unsigned int *) arg);
}
break;
case TIOCMBIS:
- if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) {
+ if ((rc = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(unsigned int))) == 0) {
get_user(ival, (unsigned int *) arg);
- stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : -1), ((ival & TIOCM_RTS) ? 1 : -1));
+ stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : -1),
+ ((ival & TIOCM_RTS) ? 1 : -1));
}
break;
case TIOCMBIC:
- if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) {
+ if ((rc = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(unsigned int))) == 0) {
get_user(ival, (unsigned int *) arg);
- stl_setsignals(portp, ((ival & TIOCM_DTR) ? 0 : -1), ((ival & TIOCM_RTS) ? 0 : -1));
+ stl_setsignals(portp, ((ival & TIOCM_DTR) ? 0 : -1),
+ ((ival & TIOCM_RTS) ? 0 : -1));
}
break;
case TIOCMSET:
- if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) {
+ if ((rc = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(unsigned int))) == 0) {
get_user(ival, (unsigned int *) arg);
- stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : 0), ((ival & TIOCM_RTS) ? 1 : 0));
+ stl_setsignals(portp, ((ival & TIOCM_DTR) ? 1 : 0),
+ ((ival & TIOCM_RTS) ? 1 : 0));
}
break;
case TIOCGSERIAL:
- if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) == 0)
+ if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct serial_struct))) == 0)
stl_getserial(portp, (struct serial_struct *) arg);
break;
case TIOCSSERIAL:
- if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(struct serial_struct))) == 0)
+ if ((rc = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(struct serial_struct))) == 0)
rc = stl_setserial(portp, (struct serial_struct *) arg);
break;
case COM_GETPORTSTATS:
- if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+ if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(comstats_t))) == 0)
rc = stl_getportstats(portp, (comstats_t *) arg);
break;
case COM_CLRPORTSTATS:
- if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
+ if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(comstats_t))) == 0)
rc = stl_clrportstats(portp, (comstats_t *) arg);
break;
case TIOCSERCONFIG:
@@ -1464,11 +1477,13 @@
return;
tiosp = tty->termios;
- if ((tiosp->c_cflag == old->c_cflag) && (tiosp->c_iflag == old->c_iflag))
+ if ((tiosp->c_cflag == old->c_cflag) &&
+ (tiosp->c_iflag == old->c_iflag))
return;
stl_setport(portp, tiosp);
- stl_setsignals(portp, ((tiosp->c_cflag & (CBAUD & ~CBAUDEX)) ? 1 : 0), -1);
+ stl_setsignals(portp, ((tiosp->c_cflag & (CBAUD & ~CBAUDEX)) ? 1 : 0),
+ -1);
if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0)) {
tty->hw_stopped = 0;
stl_start(tty);
@@ -1603,7 +1618,6 @@
portp->tx.head = (char *) NULL;
portp->tx.tail = (char *) NULL;
}
- tty->driver_data = (void *) NULL;
portp->tty = (struct tty_struct *) NULL;
portp->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
portp->refcount = 0;
@@ -1628,12 +1642,219 @@
stl_flush(portp);
wake_up_interruptible(&tty->write_wait);
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
}
/*****************************************************************************/
+static void stl_breakctl(struct tty_struct *tty, int state)
+{
+ stlport_t *portp;
+
+#if DEBUG
+ printk("stl_breakctl(tty=%x,state=%d)\n", (int) tty, state);
+#endif
+
+ if (tty == (struct tty_struct *) NULL)
+ return;
+ portp = tty->driver_data;
+ if (portp == (stlport_t *) NULL)
+ return;
+
+ stl_sendbreak(portp, ((state == -1) ? 1 : 2));
+}
+
+/*****************************************************************************/
+
+static void stl_waituntilsent(struct tty_struct *tty, int timeout)
+{
+ stlport_t *portp;
+ unsigned long tend;
+
+#if DEBUG
+ printk("stl_waituntilsent(tty=%x,timeout=%d)\n", (int) tty, timeout);
+#endif
+
+ if (tty == (struct tty_struct *) NULL)
+ return;
+ portp = tty->driver_data;
+ if (portp == (stlport_t *) NULL)
+ return;
+
+ if (timeout == 0)
+ timeout = HZ;
+ tend = jiffies + timeout;
+
+ while (stl_datastate(portp)) {
+ if (signal_pending(current))
+ break;
+ stl_delay(2);
+ if (jiffies >= tend)
+ break;
+ }
+}
+
+/*****************************************************************************/
+
+static void stl_sendxchar(struct tty_struct *tty, char ch)
+{
+ stlport_t *portp;
+
+#if DEBUG
+ printk("stl_sendxchar(tty=%x,ch=%x)\n", (int) tty, ch);
+#endif
+
+ if (tty == (struct tty_struct *) NULL)
+ return;
+ portp = tty->driver_data;
+ if (portp == (stlport_t *) NULL)
+ return;
+
+ if (ch == STOP_CHAR(tty))
+ stl_sendflow(portp, 0);
+ else if (ch == START_CHAR(tty))
+ stl_sendflow(portp, 1);
+ else
+ stl_putchar(tty, ch);
+}
+
+/*****************************************************************************/
+
+#define MAXLINE 80
+
+/*
+ * Format info for a specified port. The line is deliberately limited
+ * to 80 characters. (If it is too long it will be truncated, if too
+ * short then padded with spaces).
+ */
+
+static int stl_portinfo(stlport_t *portp, int portnr, char *pos)
+{
+ char *sp;
+ int sigs, cnt;
+
+ sp = pos;
+ sp += sprintf(sp, "%d: uart:%s tx:%d rx:%d",
+ portnr, (portp->hwid == 1) ? "SC26198" : "CD1400",
+ (int) portp->stats.txtotal, (int) portp->stats.rxtotal);
+
+ if (portp->stats.rxframing)
+ sp += sprintf(sp, " fe:%d", (int) portp->stats.rxframing);
+ if (portp->stats.rxparity)
+ sp += sprintf(sp, " pe:%d", (int) portp->stats.rxparity);
+ if (portp->stats.rxbreaks)
+ sp += sprintf(sp, " brk:%d", (int) portp->stats.rxbreaks);
+ if (portp->stats.rxoverrun)
+ sp += sprintf(sp, " oe:%d", (int) portp->stats.rxoverrun);
+
+ sigs = stl_getsignals(portp);
+ cnt = sprintf(sp, "%s%s%s%s%s ",
+ (sigs & TIOCM_RTS) ? "|RTS" : "",
+ (sigs & TIOCM_CTS) ? "|CTS" : "",
+ (sigs & TIOCM_DTR) ? "|DTR" : "",
+ (sigs & TIOCM_CD) ? "|DCD" : "",
+ (sigs & TIOCM_DSR) ? "|DSR" : "");
+ *sp = ' ';
+ sp += cnt;
+
+ for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++)
+ *sp++ = ' ';
+ if (cnt >= MAXLINE)
+ pos[(MAXLINE - 2)] = '+';
+ pos[(MAXLINE - 1)] = '\n';
+
+ return(MAXLINE);
+}
+
+/*****************************************************************************/
+
+/*
+ * Port info, read from the /proc file system.
+ */
+
+static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ stlbrd_t *brdp;
+ stlpanel_t *panelp;
+ stlport_t *portp;
+ int brdnr, panelnr, portnr, totalport;
+ int curoff, maxoff;
+ char *pos;
+
+#if DEBUG
+ printk("stl_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x,"
+ "data=%x\n", (int) page, (int) start, (int) off, count,
+ (int) eof, (int) data);
+#endif
+
+ pos = page;
+ totalport = 0;
+ curoff = 0;
+
+ if (off == 0) {
+ pos += sprintf(pos, "%s: version %s", stl_drvtitle,
+ stl_drvversion);
+ while (pos < (page + MAXLINE - 1))
+ *pos++ = ' ';
+ *pos++ = '\n';
+ }
+ curoff = MAXLINE;
+
+/*
+ * We scan through for each board, panel and port. The offset is
+ * calculated on the fly, and irrelevant ports are skipped.
+ */
+ for (brdnr = 0; (brdnr < stl_nrbrds); brdnr++) {
+ brdp = stl_brds[brdnr];
+ if (brdp == (stlbrd_t *) NULL)
+ continue;
+ if (brdp->state == 0)
+ continue;
+
+ maxoff = curoff + (brdp->nrports * MAXLINE);
+ if (off >= maxoff) {
+ curoff = maxoff;
+ continue;
+ }
+
+ totalport = brdnr * STL_MAXPORTS;
+ for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) {
+ panelp = brdp->panels[panelnr];
+ if (panelp == (stlpanel_t *) NULL)
+ continue;
+
+ maxoff = curoff + (panelp->nrports * MAXLINE);
+ if (off >= maxoff) {
+ curoff = maxoff;
+ totalport += panelp->nrports;
+ continue;
+ }
+
+ for (portnr = 0; (portnr < panelp->nrports); portnr++,
+ totalport++) {
+ portp = panelp->ports[portnr];
+ if (portp == (stlport_t *) NULL)
+ continue;
+ if (off >= (curoff += MAXLINE))
+ continue;
+ if ((pos - page + MAXLINE) > count)
+ goto stl_readdone;
+ pos += stl_portinfo(portp, totalport, pos);
+ }
+ }
+ }
+
+ *eof = 1;
+
+stl_readdone:
+ *start = page;
+ return(pos - page);
+}
+
+/*****************************************************************************/
+
/*
* All board interrupts are vectored through here first. This code then
* calls off to the approrpriate board interrupt handlers.
@@ -1755,6 +1976,29 @@
/*****************************************************************************/
/*
+ * Interrupt service routine for ECH-8/64-PCI board types.
+ */
+
+static void stl_echpci64intr(stlbrd_t *brdp)
+{
+ stlpanel_t *panelp;
+ unsigned int ioaddr;
+ int bnknr;
+
+ while (inb(brdp->ioctrl) & 0x1) {
+ for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) {
+ ioaddr = brdp->bnkstataddr[bnknr];
+ if (inb(ioaddr) & ECH_PNLINTRPEND) {
+ panelp = brdp->bnk2panel[bnknr];
+ (* panelp->isr)(panelp, (ioaddr & 0xfffc));
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+/*
* Service an off-level request for some channel.
*/
@@ -1777,7 +2021,8 @@
return;
if (test_bit(ASYI_TXLOW, &portp->istate)) {
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
wake_up_interruptible(&tty->write_wait);
}
@@ -1790,7 +2035,7 @@
if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) {
if (portp->flags & ASYNC_CHECK_CD) {
if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) &&
- (portp->flags & ASYNC_CALLOUT_NOHUP))) {
+ (portp->flags & ASYNC_CALLOUT_NOHUP))) {
tty_hangup(tty);
}
}
@@ -1806,12 +2051,12 @@
* interrupt across multiple boards.
*/
-__initfunc(static int stl_mapirq(int irq))
+__initfunc(static int stl_mapirq(int irq, char *name))
{
int rc, i;
#if DEBUG
- printk("stl_mapirq(irq=%d)\n", irq);
+ printk("stl_mapirq(irq=%d,name=%s)\n", irq, name);
#endif
rc = 0;
@@ -1820,8 +2065,9 @@
break;
}
if (i >= stl_numintrs) {
- if (request_irq(irq, stl_intr, SA_INTERRUPT, stl_drvname, NULL) != 0) {
- printk("STALLION: failed to register interrupt routine for irq=%d\n", irq);
+ if (request_irq(irq, stl_intr, SA_INTERRUPT, name, NULL) != 0) {
+ printk("STALLION: failed to register interrupt "
+ "routine for %s irq=%d\n", name, irq);
rc = -ENODEV;
} else {
stl_gotintrs[stl_numintrs++] = irq;
@@ -1854,7 +2100,8 @@
for (i = 0; (i < panelp->nrports); i++) {
portp = (stlport_t *) stl_memalloc(sizeof(stlport_t));
if (portp == (stlport_t *) NULL) {
- printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlport_t));
+ printk("STALLION: failed to allocate memory "
+ "(size=%d)\n", sizeof(stlport_t));
break;
}
memset(portp, 0, sizeof(stlport_t));
@@ -1892,19 +2139,54 @@
{
stlpanel_t *panelp;
unsigned int status;
+ char *name;
int rc;
#if DEBUG
printk("stl_initeio(brdp=%x)\n", (int) brdp);
#endif
- if (check_region(brdp->ioaddr1, 8)) {
- printk("STALLION: Warning, unit %d I/O address %x conflicts with another device\n",
- brdp->brdnr, brdp->ioaddr1);
- }
-
brdp->ioctrl = brdp->ioaddr1 + 1;
brdp->iostatus = brdp->ioaddr1 + 2;
+
+/*
+ * Handle board specific stuff now. The real difference is PCI
+ * or not PCI.
+ */
+ if (brdp->brdtype == BRD_EASYIOPCI) {
+ brdp->iosize1 = 0x80;
+ brdp->iosize2 = 0x80;
+ name = "serial(EIO-PCI)";
+ outb(0x41, (brdp->ioaddr2 + 0x4c));
+ } else {
+ brdp->iosize1 = 8;
+ name = "serial(EIO)";
+ if ((brdp->irq < 0) || (brdp->irq > 15) ||
+ (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
+ printk("STALLION: invalid irq=%d for brd=%d\n",
+ brdp->irq, brdp->brdnr);
+ return(-EINVAL);
+ }
+ outb((stl_vecmap[brdp->irq] |
+ ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)),
+ brdp->ioctrl);
+ }
+
+ if (check_region(brdp->ioaddr1, brdp->iosize1)) {
+ printk("STALLION: Warning, unit %d I/O address %x conflicts "
+ "with another device\n", brdp->brdnr, brdp->ioaddr1);
+ }
+ if (brdp->iosize2 > 0) {
+ if (check_region(brdp->ioaddr2, brdp->iosize2)) {
+ printk("STALLION: Warning, unit %d I/O address %x "
+ "conflicts with another device\n",
+ brdp->brdnr, brdp->ioaddr2);
+ }
+ }
+
+/*
+ * Everything looks OK, so lets go ahead and probe for the hardware.
+ */
brdp->clk = CD1400_CLK;
brdp->isr = stl_eiointr;
@@ -1940,23 +2222,18 @@
return(-ENODEV);
}
- request_region(brdp->ioaddr1, 8, "serial(EIO)");
-
/*
- * Check that the supplied IRQ is good and then use it to setup the
- * programmable interrupt bits on EIO board. Also set the edge/level
- * triggered interrupt bit.
+ * We have verfied that the board is actually present, so now we
+ * can complete the setup.
*/
- if ((brdp->irq < 0) || (brdp->irq > 15) ||
- (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
- printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr);
- return(-EINVAL);
- }
- outb((stl_vecmap[brdp->irq] | ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE)), brdp->ioctrl);
+ request_region(brdp->ioaddr1, brdp->iosize1, name);
+ if (brdp->iosize2 > 0)
+ request_region(brdp->ioaddr2, brdp->iosize2, name);
panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t));
if (panelp == (stlpanel_t *) NULL) {
- printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlpanel_t));
+ printk("STALLION: failed to allocate memory (size=%d)\n",
+ sizeof(stlpanel_t));
return(-ENOMEM);
}
memset(panelp, 0, sizeof(stlpanel_t));
@@ -1979,7 +2256,7 @@
brdp->nrpanels = 1;
brdp->state |= BRD_FOUND;
brdp->hwid = status;
- rc = stl_mapirq(brdp->irq);
+ rc = stl_mapirq(brdp->irq, name);
return(rc);
}
@@ -1990,11 +2267,12 @@
* dealing with all types of ECH board.
*/
-static inline int stl_initech(stlbrd_t *brdp)
+static int inline stl_initech(stlbrd_t *brdp)
{
stlpanel_t *panelp;
unsigned int status, nxtid, ioaddr, conflict;
int panelnr, banknr, i;
+ char *name;
#if DEBUG
printk("stl_initech(brdp=%x)\n", (int) brdp);
@@ -2008,69 +2286,101 @@
* bit between the different board types. So we need to handle each
* separately. Also do a check that the supplied IRQ is good.
*/
- if (brdp->brdtype == BRD_ECH) {
+ switch (brdp->brdtype) {
+
+ case BRD_ECH:
brdp->isr = stl_echatintr;
brdp->ioctrl = brdp->ioaddr1 + 1;
brdp->iostatus = brdp->ioaddr1 + 1;
status = inb(brdp->iostatus);
if ((status & ECH_IDBITMASK) != ECH_ID)
return(-ENODEV);
-
if ((brdp->irq < 0) || (brdp->irq > 15) ||
- (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
- printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr);
+ (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
+ printk("STALLION: invalid irq=%d for brd=%d\n",
+ brdp->irq, brdp->brdnr);
return(-EINVAL);
}
status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1);
status |= (stl_vecmap[brdp->irq] << 1);
outb((status | ECH_BRDRESET), brdp->ioaddr1);
- brdp->ioctrlval = ECH_INTENABLE | ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE);
- outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
- conflict = check_region(brdp->ioaddr1, 2) ? brdp->ioaddr1 : 0;
- if (conflict == 0)
- conflict = check_region(brdp->ioaddr2, 32) ? brdp->ioaddr2 : 0;
- request_region(brdp->ioaddr1, 2, "serial(EC8/32)");
- request_region(brdp->ioaddr2, 32, "serial(EC8/32-secondary)");
+ brdp->ioctrlval = ECH_INTENABLE |
+ ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE);
+ for (i = 0; (i < 10); i++)
+ outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl);
+ brdp->iosize1 = 2;
+ brdp->iosize2 = 32;
+ name = "serial(EC8/32)";
outb(status, brdp->ioaddr1);
- } else if (brdp->brdtype == BRD_ECHMC) {
+ break;
+
+ case BRD_ECHMC:
brdp->isr = stl_echmcaintr;
brdp->ioctrl = brdp->ioaddr1 + 0x20;
brdp->iostatus = brdp->ioctrl;
status = inb(brdp->iostatus);
if ((status & ECH_IDBITMASK) != ECH_ID)
return(-ENODEV);
-
if ((brdp->irq < 0) || (brdp->irq > 15) ||
- (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
- printk("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, brdp->brdnr);
+ (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) {
+ printk("STALLION: invalid irq=%d for brd=%d\n",
+ brdp->irq, brdp->brdnr);
return(-EINVAL);
}
outb(ECHMC_BRDRESET, brdp->ioctrl);
outb(ECHMC_INTENABLE, brdp->ioctrl);
- conflict = check_region(brdp->ioaddr1, 64) ? brdp->ioaddr1 : 0;
- request_region(brdp->ioaddr1, 64, "serial(EC8/32-MC)");
- } else if (brdp->brdtype == BRD_ECHPCI) {
+ brdp->iosize1 = 64;
+ name = "serial(EC8/32-MC)";
+ break;
+
+ case BRD_ECHPCI:
brdp->isr = stl_echpciintr;
brdp->ioctrl = brdp->ioaddr1 + 2;
- conflict = check_region(brdp->ioaddr1, 4) ? brdp->ioaddr1 : 0;
- if (conflict == 0)
- conflict = check_region(brdp->ioaddr2, 8) ? brdp->ioaddr2 : 0;
- request_region(brdp->ioaddr1, 4, "serial(EC8/32-PCI)");
- request_region(brdp->ioaddr2, 8, "serial(EC8/32-PCI-secondary)");
+ brdp->iosize1 = 4;
+ brdp->iosize2 = 8;
+ name = "serial(EC8/32-PCI)";
+ break;
+
+ case BRD_ECH64PCI:
+ brdp->isr = stl_echpci64intr;
+ brdp->ioctrl = brdp->ioaddr2 + 0x40;
+ outb(0x43, (brdp->ioaddr1 + 0x4c));
+ brdp->iosize1 = 0x80;
+ brdp->iosize2 = 0x80;
+ name = "serial(EC8/64-PCI)";
+ break;
+
+ default:
+ printk("STALLION: unknown board type=%d\n", brdp->brdtype);
+ return(-EINVAL);
+ break;
}
+/*
+ * Check boards for possible IO address conflicts. We won't actually
+ * do anything about it here, just issue a warning...
+ */
+ conflict = check_region(brdp->ioaddr1, brdp->iosize1) ?
+ brdp->ioaddr1 : 0;
+ if ((conflict == 0) && (brdp->iosize2 > 0))
+ conflict = check_region(brdp->ioaddr2, brdp->iosize2) ?
+ brdp->ioaddr2 : 0;
if (conflict) {
- printk("STALLION: Warning, unit %d I/O address %x conflicts with another device\n",
- brdp->brdnr, conflict);
+ printk("STALLION: Warning, unit %d I/O address %x conflicts "
+ "with another device\n", brdp->brdnr, conflict);
}
- brdp->clk = CD1400_CLK;
- brdp->hwid = status;
+ request_region(brdp->ioaddr1, brdp->iosize1, name);
+ if (brdp->iosize2 > 0)
+ request_region(brdp->ioaddr2, brdp->iosize2, name);
/*
* Scan through the secondary io address space looking for panels.
* As we find'em allocate and initialize panel structures for each.
*/
+ brdp->clk = CD1400_CLK;
+ brdp->hwid = status;
+
ioaddr = brdp->ioaddr2;
banknr = 0;
panelnr = 0;
@@ -2086,7 +2396,8 @@
break;
panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t));
if (panelp == (stlpanel_t *) NULL) {
- printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlpanel_t));
+ printk("STALLION: failed to allocate memory "
+ "(size=%d)\n", sizeof(stlpanel_t));
break;
}
memset(panelp, 0, sizeof(stlpanel_t));
@@ -2107,7 +2418,8 @@
panelp->nrports = 16;
brdp->bnk2panel[banknr] = panelp;
brdp->bnkpageaddr[banknr] = nxtid;
- brdp->bnkstataddr[banknr++] = ioaddr + 4 + ECH_PNLSTATUS;
+ brdp->bnkstataddr[banknr++] = ioaddr + 4 +
+ ECH_PNLSTATUS;
} else {
panelp->nrports = 8;
}
@@ -2121,7 +2433,8 @@
ioaddr += EREG_BANKSIZE;
brdp->bnk2panel[banknr] = panelp;
brdp->bnkpageaddr[banknr] = ++nxtid;
- brdp->bnkstataddr[banknr++] = ioaddr + ECH_PNLSTATUS;
+ brdp->bnkstataddr[banknr++] = ioaddr +
+ ECH_PNLSTATUS;
} else {
panelp->nrports = 8;
panelp->ackmask = 0xc0;
@@ -2132,7 +2445,8 @@
ioaddr += EREG_BANKSIZE;
brdp->nrports += panelp->nrports;
brdp->panels[panelnr++] = panelp;
- if (ioaddr >= (brdp->ioaddr2 + 0x20))
+ if ((brdp->brdtype != BRD_ECHPCI) &&
+ (ioaddr >= (brdp->ioaddr2 + brdp->iosize2)))
break;
}
@@ -2142,7 +2456,7 @@
outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl);
brdp->state |= BRD_FOUND;
- i = stl_mapirq(brdp->irq);
+ i = stl_mapirq(brdp->irq, name);
return(i);
}
@@ -2165,21 +2479,26 @@
switch (brdp->brdtype) {
case BRD_EASYIO:
+ case BRD_EASYIOPCI:
stl_initeio(brdp);
break;
case BRD_ECH:
case BRD_ECHMC:
case BRD_ECHPCI:
+ case BRD_ECH64PCI:
stl_initech(brdp);
break;
default:
- printk("STALLION: unit=%d is unknown board type=%d\n", brdp->brdnr, brdp->brdtype);
+ printk("STALLION: unit=%d is unknown board type=%d\n",
+ brdp->brdnr, brdp->brdtype);
return(ENODEV);
}
stl_brds[brdp->brdnr] = brdp;
if ((brdp->state & BRD_FOUND) == 0) {
- printk("STALLION: %s board not found, unit=%d io=%x irq=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq);
+ printk("STALLION: %s board not found, unit=%d io=%x irq=%d\n",
+ stl_brdnames[brdp->brdtype], brdp->brdnr,
+ brdp->ioaddr1, brdp->irq);
return(ENODEV);
}
@@ -2187,90 +2506,160 @@
if (brdp->panels[i] != (stlpanel_t *) NULL)
stl_initports(brdp, brdp->panels[i]);
- printk("STALLION: %s found, unit=%d io=%x irq=%d nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype], brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels, brdp->nrports);
+ printk("STALLION: %s found, unit=%d io=%x irq=%d "
+ "nrpanels=%d nrports=%d\n", stl_brdnames[brdp->brdtype],
+ brdp->brdnr, brdp->ioaddr1, brdp->irq, brdp->nrpanels,
+ brdp->nrports);
return(0);
}
/*****************************************************************************/
+#ifdef CONFIG_PCI
+
/*
- * Find any ECH-PCI boards that might be installed. Initialize each
+ * We have a Stallion board. Allocate a board structure and
+ * initialize it. Read its IO and IRQ resources from PCI
+ * configuration space.
+ */
+
+static inline int stl_initpcibrd(int brdtype, unsigned char busnr, unsigned char devnr)
+{
+ unsigned int bar[4];
+ stlbrd_t *brdp;
+ int i, rc;
+ unsigned char irq;
+
+#if DEBUG
+ printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n",
+ brdtype, busnr, devnr);
+#endif
+
+ brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
+ if (brdp == (stlbrd_t *) NULL) {
+ printk("STALLION: failed to allocate memory (size=%d)\n",
+ sizeof(stlbrd_t));
+ return(-ENOMEM);
+ }
+
+ memset(brdp, 0, sizeof(stlbrd_t));
+ brdp->magic = STL_BOARDMAGIC;
+ brdp->brdnr = stl_nrbrds++;
+ brdp->brdtype = brdtype;
+
+/*
+ * Read in all the BAR registers from this board. Different Stallion
+ * boards use these in different ways, so we just read in the whole
+ * lot and then figure out what is what later.
+ */
+ for (i = 0; (i < 4); i++) {
+ rc = pcibios_read_config_dword(busnr, devnr,
+ (PCI_BASE_ADDRESS_0 + (i * 0x4)), &bar[i]);
+ if (rc) {
+ printk("STALLION: failed to read BAR register %d "
+ "from PCI board, errno=%x\n", i, rc);
+ return(0);
+ }
+ }
+
+ rc = pcibios_read_config_byte(busnr, devnr, PCI_INTERRUPT_LINE, &irq);
+ if (rc) {
+ printk("STALLION: failed to read INTERRUPT register "
+ "from PCI board, errno=%x\n", rc);
+ return(0);
+ }
+
+#if DEBUG
+ printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__,
+ bar[0], bar[1], bar[2], bar[3], irq);
+#endif
+
+/*
+ * We have all resources from the board, so lets setup the actual
+ * board structure now.
+ */
+ switch (brdtype) {
+ case BRD_ECHPCI:
+ brdp->ioaddr2 = (bar[0] & PCI_BASE_ADDRESS_IO_MASK);
+ brdp->ioaddr1 = (bar[1] & PCI_BASE_ADDRESS_IO_MASK);
+ break;
+ case BRD_ECH64PCI:
+ brdp->ioaddr2 = (bar[2] & PCI_BASE_ADDRESS_IO_MASK);
+ brdp->ioaddr1 = (bar[1] & PCI_BASE_ADDRESS_IO_MASK);
+ break;
+ case BRD_EASYIOPCI:
+ brdp->ioaddr1 = (bar[2] & PCI_BASE_ADDRESS_IO_MASK);
+ brdp->ioaddr2 = (bar[1] & PCI_BASE_ADDRESS_IO_MASK);
+ break;
+ default:
+ printk("STALLION: unknown PCI board type=%d\n", brdtype);
+ break;
+ }
+
+ brdp->irq = irq;
+ stl_brdinit(brdp);
+
+ return(0);
+}
+
+
+/*****************************************************************************/
+
+/*
+ * Find all Stallion PCI boards that might be installed. Initialize each
* one as it is found.
*/
-#ifdef CONFIG_PCI
static inline int stl_findpcibrds()
{
- stlbrd_t *brdp;
- unsigned char busnr, devnr, irq;
+ unsigned char busnr, devnr;
unsigned short class;
- unsigned int ioaddr;
- int i, rc;
+ int i, rc, brdtypnr;
#if DEBUG
printk("stl_findpcibrds()\n");
#endif
- if (pcibios_present()) {
- for (i = 0; (i < STL_MAXBRDS); i++) {
- if (pcibios_find_device(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECHPCI832, i, &busnr, &devnr))
- if (pcibios_find_device(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, i, &busnr, &devnr))
- break;
+ if (! pcibios_present())
+ return(0);
+
+ for (i = 0; (i < stl_nrpcibrds); i++) {
+ for (brdtypnr = 0; ; brdtypnr++) {
+
+ rc = pcibios_find_device(stl_pcibrds[i].vendid,
+ stl_pcibrds[i].devid, brdtypnr, &busnr, &devnr);
+ if (rc)
+ break;
/*
- * Found a device on the PCI bus that has our vendor and
- * device ID. Need to check now that it is really us.
+ * Check that we can handle more boards...
*/
- if ((rc = pcibios_read_config_word(busnr, devnr, PCI_CLASS_DEVICE, &class))) {
- printk("STALLION: failed to read class type from PCI board, errno=%x\n", rc);
- continue;
- }
- if (class == PCI_CLASS_STORAGE_IDE)
- continue;
-
if (stl_nrbrds >= STL_MAXBRDS) {
- printk("STALLION: too many boards found, maximum supported %d\n", STL_MAXBRDS);
+ printk("STALLION: too many boards found, "
+ "maximum supported %d\n", STL_MAXBRDS);
+ i = stl_nrpcibrds;
break;
}
/*
- * We have a Stallion board. Allocate a board structure
- * and initialize it. Read its IO and IRQ resources
- * from conf space.
- */
- brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
- if (brdp == (stlbrd_t *) NULL) {
- printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlbrd_t));
- return(-ENOMEM);
- }
- memset(brdp, 0, sizeof(stlbrd_t));
- brdp->magic = STL_BOARDMAGIC;
- brdp->brdnr = stl_nrbrds++;
- brdp->brdtype = BRD_ECHPCI;
-
- if ((rc = pcibios_read_config_dword(busnr, devnr, PCI_BASE_ADDRESS_0, &ioaddr))) {
- printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc);
- continue;
- }
- brdp->ioaddr2 = (ioaddr & PCI_BASE_ADDRESS_IO_MASK);
-
- if ((rc = pcibios_read_config_dword(busnr, devnr, PCI_BASE_ADDRESS_1, &ioaddr))) {
- printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc);
+ * Found a device on the PCI bus that has our vendor and
+ * device ID. Need to check now that it is really us.
+ */
+ rc = pcibios_read_config_word(busnr, devnr,
+ PCI_CLASS_DEVICE, &class);
+ if (rc) {
+ printk("STALLION: failed to read class type "
+ "from PCI board, errno=%x\n", rc);
continue;
}
- brdp->ioaddr1 = (ioaddr & PCI_BASE_ADDRESS_IO_MASK);
-#if DEBUG
- printk("%s(%d): BAR0=%x BAR1=%x\n", __FILE__, __LINE__, brdp->ioaddr2, brdp->ioaddr1);
-#endif
-
- if ((rc = pcibios_read_config_byte(busnr, devnr, PCI_INTERRUPT_LINE, &irq))) {
- printk("STALLION: failed to read BAR register from PCI board, errno=%x\n", rc);
+ if (class == PCI_CLASS_STORAGE_IDE)
continue;
- }
- brdp->irq = irq;
- stl_brdinit(brdp);
+ rc = stl_initpcibrd(stl_pcibrds[i].brdtype, busnr,
+ devnr);
+ if (rc)
+ return(rc);
}
}
@@ -2297,12 +2686,11 @@
printk("stl_initbrds()\n");
#endif
-#ifndef MODULE
if (stl_nrbrds > STL_MAXBRDS) {
- printk("STALLION: too many boards in configuration table, truncating to %d\n", STL_MAXBRDS);
+ printk("STALLION: too many boards in configuration table, "
+ "truncating to %d\n", STL_MAXBRDS);
stl_nrbrds = STL_MAXBRDS;
}
-#endif
/*
* Firstly scan the list of static boards configured. Allocate
@@ -2312,7 +2700,8 @@
confp = &stl_brdconf[i];
brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
if (brdp == (stlbrd_t *) NULL) {
- printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlbrd_t));
+ printk("STALLION: failed to allocate memory "
+ "(size=%d)\n", sizeof(stlbrd_t));
return(-ENOMEM);
}
memset(brdp, 0, sizeof(stlbrd_t));
@@ -2419,7 +2808,8 @@
if (portp == (stlport_t *) NULL) {
copy_from_user(&stl_comstats, cp, sizeof(comstats_t));
- portp = stl_getport(stl_comstats.brd, stl_comstats.panel, stl_comstats.port);
+ portp = stl_getport(stl_comstats.brd, stl_comstats.panel,
+ stl_comstats.port);
if (portp == (stlport_t *) NULL)
return(-ENODEV);
}
@@ -2453,7 +2843,8 @@
head = portp->tx.head;
tail = portp->tx.tail;
- portp->stats.txbuffered = ((head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)));
+ portp->stats.txbuffered = ((head >= tail) ? (head - tail) :
+ (STL_TXBUFSIZE - (tail - head)));
portp->stats.signals = (unsigned long) stl_getsignals(portp);
@@ -2471,7 +2862,8 @@
{
if (portp == (stlport_t *) NULL) {
copy_from_user(&stl_comstats, cp, sizeof(comstats_t));
- portp = stl_getport(stl_comstats.brd, stl_comstats.panel, stl_comstats.port);
+ portp = stl_getport(stl_comstats.brd, stl_comstats.panel,
+ stl_comstats.port);
if (portp == (stlport_t *) NULL)
return(-ENODEV);
}
@@ -2526,6 +2918,27 @@
/*****************************************************************************/
/*
+ * Memory device open code. Need to keep track of opens and close
+ * for module handling.
+ */
+
+static int stl_memopen(struct inode *ip, struct file *fp)
+{
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+/*****************************************************************************/
+
+static int stl_memclose(struct inode *ip, struct file *fp)
+{
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+/*****************************************************************************/
+
+/*
* The "staliomem" device is also required to do some special operations
* on the board and/or ports. In this driver it is mostly used for stats
* collection.
@@ -2536,7 +2949,8 @@
int brdnr, rc;
#if DEBUG
- printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip, (int) fp, cmd, (int) arg);
+ printk("stl_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n", (int) ip,
+ (int) fp, cmd, (int) arg);
#endif
brdnr = MINOR(ip->i_rdev);
@@ -2546,23 +2960,30 @@
switch (cmd) {
case COM_GETPORTSTATS:
- if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
- rc = stl_getportstats((stlport_t *) NULL, (comstats_t *) arg);
+ if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(comstats_t))) == 0)
+ rc = stl_getportstats((stlport_t *) NULL,
+ (comstats_t *) arg);
break;
case COM_CLRPORTSTATS:
- if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0)
- rc = stl_clrportstats((stlport_t *) NULL, (comstats_t *) arg);
+ if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(comstats_t))) == 0)
+ rc = stl_clrportstats((stlport_t *) NULL,
+ (comstats_t *) arg);
break;
case COM_GETBRDSTATS:
- if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(combrd_t))) == 0)
+ if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(combrd_t))) == 0)
rc = stl_getbrdstats((combrd_t *) arg);
break;
case COM_READPORT:
- if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(stlport_t))) == 0)
+ if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(stlport_t))) == 0)
rc = stl_getportstruct(arg);
break;
case COM_READBOARD:
- if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(stlbrd_t))) == 0)
+ if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(stlbrd_t))) == 0)
rc = stl_getbrdstruct(arg);
break;
default:
@@ -2577,7 +2998,7 @@
__initfunc(int stl_init(void))
{
- printk(KERN_INFO "%s: version %s\n", stl_drvname, stl_drvversion);
+ printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
stl_initbrds();
@@ -2586,7 +3007,8 @@
*/
stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE);
if (stl_tmpwritebuf == (char *) NULL)
- printk("STALLION: failed to allocate memory (size=%d)\n", STL_TXBUFSIZE);
+ printk("STALLION: failed to allocate memory (size=%d)\n",
+ STL_TXBUFSIZE);
/*
* Set up a character driver for per board stuff. This is mainly used
@@ -2601,6 +3023,7 @@
*/
memset(&stl_serial, 0, sizeof(struct tty_driver));
stl_serial.magic = TTY_DRIVER_MAGIC;
+ stl_serial.driver_name = stl_drvname;
stl_serial.name = stl_serialname;
stl_serial.major = STL_SERIALMAJOR;
stl_serial.minor_start = 0;
@@ -2629,11 +3052,16 @@
stl_serial.start = stl_start;
stl_serial.hangup = stl_hangup;
stl_serial.flush_buffer = stl_flushbuffer;
+ stl_serial.break_ctl = stl_breakctl;
+ stl_serial.wait_until_sent = stl_waituntilsent;
+ stl_serial.send_xchar = stl_sendxchar;
+ stl_serial.read_proc = stl_readproc;
stl_callout = stl_serial;
stl_callout.name = stl_calloutname;
stl_callout.major = STL_CALLOUTMAJOR;
stl_callout.subtype = STL_DRVTYPCALLOUT;
+ stl_callout.read_proc = 0;
if (tty_register_driver(&stl_serial))
printk("STALLION: failed to register serial driver\n");
@@ -2719,7 +3147,9 @@
break;
}
if ((j >= CCR_MAXWAIT) || (gfrcr < 0x40) || (gfrcr > 0x60)) {
- printk("STALLION: cd1400 not responding, brd=%d panel=%d chip=%d\n", panelp->brdnr, panelp->panelnr, i);
+ printk("STALLION: cd1400 not responding, "
+ "brd=%d panel=%d chip=%d\n",
+ panelp->brdnr, panelp->panelnr, i);
continue;
}
chipmask |= (0x1 << i);
@@ -2744,7 +3174,8 @@
(int) brdp, (int) panelp, (int) portp);
#endif
- if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || (portp == (stlport_t *) NULL))
+ if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) ||
+ (portp == (stlport_t *) NULL))
return;
portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) ||
@@ -2776,7 +3207,8 @@
}
}
- printk("STALLION: cd1400 device not responding, port=%d panel=%d brd=%d\n", portp->portnr, portp->panelnr, portp->brdnr);
+ printk("STALLION: cd1400 not responding, port=%d panel=%d brd=%d\n",
+ portp->portnr, portp->panelnr, portp->brdnr);
}
/*****************************************************************************/
@@ -2887,7 +3319,7 @@
baudrate = tiosp->c_cflag & CBAUD;
if (baudrate & CBAUDEX) {
baudrate &= ~CBAUDEX;
- if ((baudrate < 1) || (baudrate > 2))
+ if ((baudrate < 1) || (baudrate > 4))
tiosp->c_cflag &= ~CBAUDEX;
else
baudrate += 15;
@@ -2898,11 +3330,15 @@
baudrate = 57600;
else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
baudrate = 115200;
+ else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ baudrate = 230400;
+ else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ baudrate = 460800;
else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
baudrate = (portp->baud_base / portp->custom_divisor);
}
- if (baudrate > STL_MAXBAUD)
- baudrate = STL_MAXBAUD;
+ if (baudrate > STL_CD1400MAXBAUD)
+ baudrate = STL_CD1400MAXBAUD;
if (baudrate > 0) {
for (clk = 0; (clk < CD1400_NUMCLKS); clk++) {
@@ -2949,11 +3385,16 @@
*/
#if DEBUG
- printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", portp->portnr, portp->panelnr, portp->brdnr);
- printk(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n", cor1, cor2, cor3, cor4, cor5);
- printk(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n", mcor1, mcor2, rtpr, sreron, sreroff);
+ printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n",
+ portp->portnr, portp->panelnr, portp->brdnr);
+ printk(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n",
+ cor1, cor2, cor3, cor4, cor5);
+ printk(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n",
+ mcor1, mcor2, rtpr, sreron, sreroff);
printk(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div);
- printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
+ printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n",
+ tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP],
+ tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
#endif
save_flags(flags);
@@ -3009,7 +3450,8 @@
unsigned long flags;
#if DEBUG
- printk("stl_cd1400setsignals(portp=%x,dtr=%d,rts=%d)\n", (int) portp, dtr, rts);
+ printk("stl_cd1400setsignals(portp=%x,dtr=%d,rts=%d)\n",
+ (int) portp, dtr, rts);
#endif
msvr1 = 0;
@@ -3059,10 +3501,14 @@
sigs = 0;
sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0;
sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0;
- sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0;
- sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0;
sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0;
sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0;
+#if 0
+ sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0;
+ sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0;
+#else
+ sigs |= TIOCM_DSR;
+#endif
return(sigs);
}
@@ -3078,7 +3524,8 @@
unsigned long flags;
#if DEBUG
- printk("stl_cd1400enablerxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, rx, tx);
+ printk("stl_cd1400enablerxtx(portp=%x,rx=%d,tx=%d)\n",
+ (int) portp, rx, tx);
#endif
ccr = 0;
@@ -3114,8 +3561,8 @@
unsigned long flags;
#if DEBUG
- printk("stl_cd1400startrxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp,
- rx, tx);
+ printk("stl_cd1400startrxtx(portp=%x,rx=%d,tx=%d)\n",
+ (int) portp, rx, tx);
#endif
sreron = 0;
@@ -3135,7 +3582,8 @@
cli();
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
- stl_cd1400setreg(portp, SRER, ((stl_cd1400getreg(portp, SRER) & ~sreroff) | sreron));
+ stl_cd1400setreg(portp, SRER,
+ ((stl_cd1400getreg(portp, SRER) & ~sreroff) | sreron));
BRDDISABLE(portp->brdnr);
if (tx > 0)
set_bit(ASYI_TXBUSY, &portp->istate);
@@ -3166,24 +3614,25 @@
/*****************************************************************************/
-static void stl_cd1400sendbreak(stlport_t *portp, long len)
+static void stl_cd1400sendbreak(stlport_t *portp, int len)
{
unsigned long flags;
#if DEBUG
- printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, (int) len);
+ printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len);
#endif
save_flags(flags);
cli();
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
- stl_cd1400setreg(portp, COR2, (stl_cd1400getreg(portp, COR2) | COR2_ETC));
- stl_cd1400setreg(portp, SRER, ((stl_cd1400getreg(portp, SRER) & ~SRER_TXDATA) | SRER_TXEMPTY));
+ stl_cd1400setreg(portp, SRER,
+ ((stl_cd1400getreg(portp, SRER) & ~SRER_TXDATA) |
+ SRER_TXEMPTY));
BRDDISABLE(portp->brdnr);
- len = len / 5;
- portp->brklen = (len > 255) ? 255 : len;
- portp->stats.txbreaks++;
+ portp->brklen = len;
+ if (len == 1)
+ portp->stats.txbreaks++;
restore_flags(flags);
}
@@ -3227,7 +3676,9 @@
* set the RTS line by hand.
*/
if (tty->termios->c_cflag & CRTSCTS) {
- stl_cd1400setreg(portp, MCOR1, (stl_cd1400getreg(portp, MCOR1) | FIFO_RTSTHRESHOLD));
+ stl_cd1400setreg(portp, MCOR1,
+ (stl_cd1400getreg(portp, MCOR1) |
+ FIFO_RTSTHRESHOLD));
stl_cd1400setreg(portp, MSVR2, MSVR2_RTS);
portp->stats.rxrtson++;
}
@@ -3239,7 +3690,8 @@
stl_cd1400ccrwait(portp);
}
if (tty->termios->c_cflag & CRTSCTS) {
- stl_cd1400setreg(portp, MCOR1, (stl_cd1400getreg(portp, MCOR1) & 0xf0));
+ stl_cd1400setreg(portp, MCOR1,
+ (stl_cd1400getreg(portp, MCOR1) & 0xf0));
stl_cd1400setreg(portp, MSVR2, 0);
portp->stats.rxrtsoff++;
}
@@ -3251,6 +3703,46 @@
/*****************************************************************************/
+/*
+ * Send a flow control character...
+ */
+
+static void stl_cd1400sendflow(stlport_t *portp, int state)
+{
+ struct tty_struct *tty;
+ unsigned long flags;
+
+#if DEBUG
+ printk("stl_cd1400sendflow(portp=%x,state=%x)\n", (int) portp, state);
+#endif
+
+ if (portp == (stlport_t *) NULL)
+ return;
+ tty = portp->tty;
+ if (tty == (struct tty_struct *) NULL)
+ return;
+
+ save_flags(flags);
+ cli();
+ BRDENABLE(portp->brdnr, portp->pagenr);
+ stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
+ if (state) {
+ stl_cd1400ccrwait(portp);
+ stl_cd1400setreg(portp, CCR, CCR_SENDSCHR1);
+ portp->stats.rxxon++;
+ stl_cd1400ccrwait(portp);
+ } else {
+ stl_cd1400ccrwait(portp);
+ stl_cd1400setreg(portp, CCR, CCR_SENDSCHR2);
+ portp->stats.rxxoff++;
+ stl_cd1400ccrwait(portp);
+ }
+ BRDDISABLE(portp->brdnr);
+ restore_flags(flags);
+}
+
+/*****************************************************************************/
+
static void stl_cd1400flush(stlport_t *portp)
{
unsigned long flags;
@@ -3277,6 +3769,27 @@
/*****************************************************************************/
/*
+ * Return the current state of data flow on this port. This is only
+ * really interresting when determining if data has fully completed
+ * transmission or not... This is easy for the cd1400, it accurately
+ * maintains the busy port flag.
+ */
+
+static int stl_cd1400datastate(stlport_t *portp)
+{
+#if DEBUG
+ printk("stl_cd1400datastate(portp=%x)\n", (int) portp);
+#endif
+
+ if (portp == (stlport_t *) NULL)
+ return(0);
+
+ return(test_bit(ASYI_TXBUSY, &portp->istate) ? 1 : 0);
+}
+
+/*****************************************************************************/
+
+/*
* Interrupt service routine for cd1400 EasyIO boards.
*/
@@ -3285,7 +3798,8 @@
unsigned char svrtype;
#if DEBUG
- printk("stl_cd1400eiointr(panelp=%x,iobase=%x)\n", (int) panelp, iobase);
+ printk("stl_cd1400eiointr(panelp=%x,iobase=%x)\n",
+ (int) panelp, iobase);
#endif
outb(SVRR, iobase);
@@ -3297,13 +3811,12 @@
if (svrtype & SVRR_RX)
stl_cd1400rxisr(panelp, iobase);
- if (svrtype & SVRR_TX)
+ else if (svrtype & SVRR_TX)
stl_cd1400txisr(panelp, iobase);
- if (svrtype & SVRR_MDM)
+ else if (svrtype & SVRR_MDM)
stl_cd1400mdmisr(panelp, iobase);
}
-
/*****************************************************************************/
/*
@@ -3315,7 +3828,8 @@
unsigned char svrtype;
#if DEBUG
- printk("stl_cd1400echintr(panelp=%x,iobase=%x)\n", (int) panelp, iobase);
+ printk("stl_cd1400echintr(panelp=%x,iobase=%x)\n", (int) panelp,
+ iobase);
#endif
outb(SVRR, iobase);
@@ -3324,12 +3838,48 @@
svrtype |= inb(iobase + EREG_DATA);
if (svrtype & SVRR_RX)
stl_cd1400rxisr(panelp, iobase);
- if (svrtype & SVRR_TX)
+ else if (svrtype & SVRR_TX)
stl_cd1400txisr(panelp, iobase);
- if (svrtype & SVRR_MDM)
+ else if (svrtype & SVRR_MDM)
stl_cd1400mdmisr(panelp, iobase);
}
+
+/*****************************************************************************/
+
+/*
+ * Unfortunately we need to handle breaks in the TX data stream, since
+ * this is the only way to generate them on the cd1400.
+ */
+
+static inline int stl_cd1400breakisr(stlport_t *portp, int ioaddr)
+{
+ if (portp->brklen == 1) {
+ outb((COR2 + portp->uartaddr), ioaddr);
+ outb((inb(ioaddr + EREG_DATA) | COR2_ETC),
+ (ioaddr + EREG_DATA));
+ outb((TDR + portp->uartaddr), ioaddr);
+ outb(ETC_CMD, (ioaddr + EREG_DATA));
+ outb(ETC_STARTBREAK, (ioaddr + EREG_DATA));
+ outb((SRER + portp->uartaddr), ioaddr);
+ outb((inb(ioaddr + EREG_DATA) & ~(SRER_TXDATA | SRER_TXEMPTY)),
+ (ioaddr + EREG_DATA));
+ return(1);
+ } else if (portp->brklen > 1) {
+ outb((TDR + portp->uartaddr), ioaddr);
+ outb(ETC_CMD, (ioaddr + EREG_DATA));
+ outb(ETC_STOPBREAK, (ioaddr + EREG_DATA));
+ portp->brklen = -1;
+ return(1);
+ } else {
+ outb((COR2 + portp->uartaddr), ioaddr);
+ outb((inb(ioaddr + EREG_DATA) & ~COR2_ETC),
+ (ioaddr + EREG_DATA));
+ portp->brklen = 0;
+ }
+ return(0);
+}
+
/*****************************************************************************/
/*
@@ -3356,7 +3906,8 @@
#endif
ioack = inb(ioaddr + EREG_TXACK);
- if (((ioack & panelp->ackmask) != 0) || ((ioack & ACK_TYPMASK) != ACK_TYPTX)) {
+ if (((ioack & panelp->ackmask) != 0) ||
+ ((ioack & ACK_TYPMASK) != ACK_TYPTX)) {
printk("STALLION: bad TX interrupt ack value=%x\n", ioack);
return;
}
@@ -3367,29 +3918,15 @@
* this is the only way to generate them on the cd1400. Do it now if
* a break is to be sent.
*/
- if (portp->brklen != 0) {
- if (portp->brklen > 0) {
- outb((TDR + portp->uartaddr), ioaddr);
- outb(ETC_CMD, (ioaddr + EREG_DATA));
- outb(ETC_STARTBREAK, (ioaddr + EREG_DATA));
- outb(ETC_CMD, (ioaddr + EREG_DATA));
- outb(ETC_DELAY, (ioaddr + EREG_DATA));
- outb(portp->brklen, (ioaddr + EREG_DATA));
- outb(ETC_CMD, (ioaddr + EREG_DATA));
- outb(ETC_STOPBREAK, (ioaddr + EREG_DATA));
- portp->brklen = -1;
+ if (portp->brklen != 0)
+ if (stl_cd1400breakisr(portp, ioaddr))
goto stl_txalldone;
- } else {
- outb((COR2 + portp->uartaddr), ioaddr);
- outb((inb(ioaddr + EREG_DATA) & ~COR2_ETC), (ioaddr + EREG_DATA));
- portp->brklen = 0;
- }
- }
head = portp->tx.head;
tail = portp->tx.tail;
len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head));
- if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
+ if ((len == 0) || ((len < STL_TXBUFLOW) &&
+ (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
set_bit(ASYI_TXLOW, &portp->istate);
queue_task(&portp->tqueue, &tq_scheduler);
}
@@ -3461,8 +3998,9 @@
if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) {
outb((RDCR + portp->uartaddr), ioaddr);
len = inb(ioaddr + EREG_DATA);
- if ((tty == (struct tty_struct *) NULL) || (tty->flip.char_buf_ptr == (char *) NULL) ||
- ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
+ if ((tty == (struct tty_struct *) NULL) ||
+ (tty->flip.char_buf_ptr == (char *) NULL) ||
+ ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
outb((RDSR + portp->uartaddr), ioaddr);
insb((ioaddr + EREG_DATA), &stl_unwanted[0], len);
portp->stats.rxlost += len;
@@ -3499,16 +4037,15 @@
portp->stats.txxoff++;
goto stl_rxalldone;
}
- if ((tty != (struct tty_struct *) NULL) && ((portp->rxignoremsk & status) == 0)) {
+ if ((tty != (struct tty_struct *) NULL) &&
+ ((portp->rxignoremsk & status) == 0)) {
if (portp->rxmarkmsk & status) {
if (status & ST_BREAK) {
status = TTY_BREAK;
-#ifndef MODULE
if (portp->flags & ASYNC_SAK) {
do_SAK(tty);
BRDENABLE(portp->brdnr, portp->pagenr);
}
-#endif
} else if (status & ST_PARITY) {
status = TTY_PARITY;
} else if (status & ST_FRAMING) {
@@ -3559,7 +4096,8 @@
#endif
ioack = inb(ioaddr + EREG_MDACK);
- if (((ioack & panelp->ackmask) != 0) || ((ioack & ACK_TYPMASK) != ACK_TYPMDM)) {
+ if (((ioack & panelp->ackmask) != 0) ||
+ ((ioack & ACK_TYPMASK) != ACK_TYPMDM)) {
printk("STALLION: bad MODEM interrupt ack value=%x\n", ioack);
return;
}
@@ -3643,7 +4181,8 @@
int nrchips, ioaddr;
#if DEBUG
- printk("stl_sc26198panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp);
+ printk("stl_sc26198panelinit(brdp=%x,panelp=%x)\n",
+ (int) brdp, (int) panelp);
#endif
BRDENABLE(panelp->brdnr, panelp->pagenr);
@@ -3662,7 +4201,9 @@
outb(CR_RESETALL, (ioaddr + XP_DATA));
outb(TSTR, (ioaddr + XP_ADDR));
if (inb(ioaddr + XP_DATA) != 0) {
- printk("STALLION: sc26198 not responding, brd=%d panel=%d chip=%d\n", panelp->brdnr, panelp->panelnr, i);
+ printk("STALLION: sc26198 not responding, "
+ "brd=%d panel=%d chip=%d\n",
+ panelp->brdnr, panelp->panelnr, i);
continue;
}
chipmask |= (0x1 << i);
@@ -3689,7 +4230,8 @@
(int) brdp, (int) panelp, (int) portp);
#endif
- if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) || (portp == (stlport_t *) NULL))
+ if ((brdp == (stlbrd_t *) NULL) || (panelp == (stlpanel_t *) NULL) ||
+ (portp == (stlport_t *) NULL))
return;
portp->ioaddr = panelp->iobase + ((portp->portnr < 8) ? 0 : 4);
@@ -3735,7 +4277,8 @@
*/
portp->rxignoremsk = 0;
if (tiosp->c_iflag & IGNPAR)
- portp->rxignoremsk |= (SR_RXPARITY | SR_RXFRAMING | SR_RXOVERRUN);
+ portp->rxignoremsk |= (SR_RXPARITY | SR_RXFRAMING |
+ SR_RXOVERRUN);
if (tiosp->c_iflag & IGNBRK)
portp->rxignoremsk |= SR_RXBREAK;
@@ -3795,7 +4338,7 @@
baudrate = tiosp->c_cflag & CBAUD;
if (baudrate & CBAUDEX) {
baudrate &= ~CBAUDEX;
- if ((baudrate < 1) || (baudrate > 5))
+ if ((baudrate < 1) || (baudrate > 4))
tiosp->c_cflag &= ~CBAUDEX;
else
baudrate += 15;
@@ -3806,11 +4349,15 @@
baudrate = 57600;
else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
baudrate = 115200;
+ else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ baudrate = 230400;
+ else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ baudrate = 460800;
else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
baudrate = (portp->baud_base / portp->custom_divisor);
}
- if (baudrate > STL_MAXBAUD)
- baudrate = STL_MAXBAUD;
+ if (baudrate > STL_SC26198MAXBAUD)
+ baudrate = STL_SC26198MAXBAUD;
if (baudrate > 0) {
for (clk = 0; (clk < SC26198_NRBAUDS); clk++) {
@@ -3856,10 +4403,13 @@
*/
#if DEBUG
- printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", portp->portnr, portp->panelnr, portp->brdnr);
+ printk("SETPORT: portnr=%d panelnr=%d brdnr=%d\n",
+ portp->portnr, portp->panelnr, portp->brdnr);
printk(" mr0=%x mr1=%x mr2=%x clk=%x\n", mr0, mr1, mr2, clk);
printk(" iopr=%x imron=%x imroff=%x\n", iopr, imron, imroff);
- printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n", tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
+ printk(" schr1=%x schr2=%x schr3=%x schr4=%x\n",
+ tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP],
+ tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
#endif
save_flags(flags);
@@ -3905,7 +4455,8 @@
unsigned long flags;
#if DEBUG
- printk("stl_sc26198setsignals(portp=%x,dtr=%d,rts=%d)\n", (int) portp, dtr, rts);
+ printk("stl_sc26198setsignals(portp=%x,dtr=%d,rts=%d)\n",
+ (int) portp, dtr, rts);
#endif
iopioron = 0;
@@ -3956,6 +4507,7 @@
sigs |= (ipr & IPR_CTS) ? 0 : TIOCM_CTS;
sigs |= (ipr & IPR_DTR) ? 0: TIOCM_DTR;
sigs |= (ipr & IPR_RTS) ? 0: TIOCM_RTS;
+ sigs |= TIOCM_DSR;
return(sigs);
}
@@ -3971,7 +4523,8 @@
unsigned long flags;
#if DEBUG
- printk("stl_sc26198enablerxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, rx, tx);
+ printk("stl_sc26198enablerxtx(portp=%x,rx=%d,tx=%d)\n",
+ (int) portp, rx, tx);
#endif
ccr = portp->crenable;
@@ -4005,8 +4558,8 @@
unsigned long flags;
#if DEBUG
- printk("stl_sc26198startrxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp,
- rx, tx);
+ printk("stl_sc26198startrxtx(portp=%x,rx=%d,tx=%d)\n",
+ (int) portp, rx, tx);
#endif
imr = portp->imr;
@@ -4055,28 +4608,23 @@
/*****************************************************************************/
-static void stl_sc26198sendbreak(stlport_t *portp, long len)
+static void stl_sc26198sendbreak(stlport_t *portp, int len)
{
unsigned long flags;
#if DEBUG
- printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, (int) len);
+ printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len);
#endif
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + (len / (1000 / HZ));
-
save_flags(flags);
cli();
BRDENABLE(portp->brdnr, portp->pagenr);
- stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK);
- BRDDISABLE(portp->brdnr);
- portp->stats.txbreaks++;
-
- schedule();
-
- BRDENABLE(portp->brdnr, portp->pagenr);
- stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK);
+ if (len == 1) {
+ stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK);
+ portp->stats.txbreaks++;
+ } else {
+ stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK);
+ }
BRDDISABLE(portp->brdnr);
restore_flags(flags);
}
@@ -4114,6 +4662,7 @@
stl_sc26198setreg(portp, SCCR, CR_TXSENDXON);
mr0 |= MR0_SWFRX;
portp->stats.rxxon++;
+ stl_sc26198wait(portp);
stl_sc26198setreg(portp, MR0, mr0);
}
/*
@@ -4136,6 +4685,7 @@
stl_sc26198setreg(portp, SCCR, CR_TXSENDXOFF);
mr0 &= ~MR0_SWFRX;
portp->stats.rxxoff++;
+ stl_sc26198wait(portp);
stl_sc26198setreg(portp, MR0, mr0);
}
if (tty->termios->c_cflag & CRTSCTS) {
@@ -4153,6 +4703,52 @@
/*****************************************************************************/
+/*
+ * Send a flow control character.
+ */
+
+static void stl_sc26198sendflow(stlport_t *portp, int state)
+{
+ struct tty_struct *tty;
+ unsigned long flags;
+ unsigned char mr0;
+
+#if DEBUG
+ printk("stl_sc26198sendflow(portp=%x,state=%x)\n", (int) portp, state);
+#endif
+
+ if (portp == (stlport_t *) NULL)
+ return;
+ tty = portp->tty;
+ if (tty == (struct tty_struct *) NULL)
+ return;
+
+ save_flags(flags);
+ cli();
+ BRDENABLE(portp->brdnr, portp->pagenr);
+ if (state) {
+ mr0 = stl_sc26198getreg(portp, MR0);
+ stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX));
+ stl_sc26198setreg(portp, SCCR, CR_TXSENDXON);
+ mr0 |= MR0_SWFRX;
+ portp->stats.rxxon++;
+ stl_sc26198wait(portp);
+ stl_sc26198setreg(portp, MR0, mr0);
+ } else {
+ mr0 = stl_sc26198getreg(portp, MR0);
+ stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX));
+ stl_sc26198setreg(portp, SCCR, CR_TXSENDXOFF);
+ mr0 &= ~MR0_SWFRX;
+ portp->stats.rxxoff++;
+ stl_sc26198wait(portp);
+ stl_sc26198setreg(portp, MR0, mr0);
+ }
+ BRDDISABLE(portp->brdnr);
+ restore_flags(flags);
+}
+
+/*****************************************************************************/
+
static void stl_sc26198flush(stlport_t *portp)
{
unsigned long flags;
@@ -4177,10 +4773,67 @@
/*****************************************************************************/
/*
+ * Return the current state of data flow on this port. This is only
+ * really interresting when determining if data has fully completed
+ * transmission or not... The sc26198 interrupt scheme cannot
+ * determine when all data has actually drained, so we need to
+ * check the port statusy register to be sure.
+ */
+
+static int stl_sc26198datastate(stlport_t *portp)
+{
+ unsigned long flags;
+ unsigned char sr;
+
+#if DEBUG
+ printk("stl_sc26198datastate(portp=%x)\n", (int) portp);
+#endif
+
+ if (portp == (stlport_t *) NULL)
+ return(0);
+ if (test_bit(ASYI_TXBUSY, &portp->istate))
+ return(1);
+
+ save_flags(flags);
+ cli();
+ BRDENABLE(portp->brdnr, portp->pagenr);
+ sr = stl_sc26198getreg(portp, SR);
+ BRDDISABLE(portp->brdnr);
+ restore_flags(flags);
+
+ return((sr & SR_TXEMPTY) ? 0 : 1);
+}
+
+/*****************************************************************************/
+
+/*
+ * Delay for a small amount of time, to give the sc26198 a chance
+ * to process a command...
+ */
+
+static void stl_sc26198wait(stlport_t *portp)
+{
+ int i;
+
+#if DEBUG
+ printk("stl_sc26198wait(portp=%x)\n", (int) portp);
+#endif
+
+ if (portp == (stlport_t *) NULL)
+ return;
+
+ for (i = 0; (i < 20); i++)
+ stl_sc26198getglobreg(portp, TSTR);
+}
+
+/*****************************************************************************/
+
+/*
* If we are TX flow controlled and in IXANY mode then we may
* need to unflow control here. We gotta do this because of the
* automatic flow control modes of the sc26198.
*/
+
static inline void stl_sc26198txunflow(stlport_t *portp, struct tty_struct *tty)
{
unsigned char mr0;
@@ -4188,6 +4841,7 @@
mr0 = stl_sc26198getreg(portp, MR0);
stl_sc26198setreg(portp, MR0, (mr0 & ~MR0_SWFRXTX));
stl_sc26198setreg(portp, SCCR, CR_HOSTXON);
+ stl_sc26198wait(portp);
stl_sc26198setreg(portp, MR0, mr0);
clear_bit(ASYI_TXFLOWED, &portp->istate);
}
@@ -4247,7 +4901,8 @@
head = portp->tx.head;
tail = portp->tx.tail;
len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head));
- if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
+ if ((len == 0) || ((len < STL_TXBUFLOW) &&
+ (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
set_bit(ASYI_TXLOW, &portp->istate);
queue_task(&portp->tqueue, &tq_scheduler);
}
@@ -4340,8 +4995,8 @@
*/
if (test_bit(ASYI_TXFLOWED, &portp->istate)) {
if ((tty != (struct tty_struct *) NULL) &&
- (tty->termios != (struct termios *) NULL) &&
- (tty->termios->c_iflag & IXANY)) {
+ (tty->termios != (struct termios *) NULL) &&
+ (tty->termios->c_iflag & IXANY)) {
stl_sc26198txunflow(portp, tty);
}
}
@@ -4371,16 +5026,14 @@
portp->stats.rxbreaks++;
if ((tty != (struct tty_struct *) NULL) &&
- ((portp->rxignoremsk & status) == 0)) {
+ ((portp->rxignoremsk & status) == 0)) {
if (portp->rxmarkmsk & status) {
if (status & SR_RXBREAK) {
status = TTY_BREAK;
-#ifndef MODULE
if (portp->flags & ASYNC_SAK) {
do_SAK(tty);
BRDENABLE(portp->brdnr, portp->pagenr);
}
-#endif
} else if (status & SR_RXPARITY) {
status = TTY_PARITY;
} else if (status & SR_RXFRAMING) {
@@ -4487,7 +5140,6 @@
stl_sc26198rxbadchars(portp);
break;
default:
- /*printk("%s(%d): unknown other intr cir=%x, iack=%x!\n", __FILE__, __LINE__, cir, iack);*/
break;
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov