patch-2.0.11 linux/drivers/char/pcxx.c
Next file: linux/drivers/isdn/pcbit/edss1.c
Previous file: linux/drivers/char/pcwd.c
Back to the patch index
Back to the overall index
- Lines: 376
- Date:
Thu Aug 1 15:40:32 1996
- Orig file:
v2.0.10/linux/drivers/char/pcxx.c
- Orig date:
Sun May 19 15:24:50 1996
diff -u --recursive --new-file v2.0.10/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c
@@ -30,8 +30,13 @@
* variable handling, instead of using the old pcxxconfig.h
* 1.5.6 April 16, 1996 Christoph Lameter: Pointer cleanup, macro cleanup.
* Call out devices changed to /dev/cudxx.
+ * 1.5.7 July 22, 1996 Martin Mares: CLOCAL fix, pcxe_table clearing.
+ * David Nugent: Bug in pcxe_open.
+ * Brian J. Murrell: Modem Control fixes, Majors correctly assigned
*
*/
+#undef MODULE
+/* Module code is broken right now. Don't enable this unless you want to fix it */
#undef SPEED_HACK
/* If you define SPEED_HACK then you get the following Baudrate translation
@@ -41,6 +46,7 @@
some distributions like Slackware 3.0 don't like these high baudrates.
*/
+#include <linux/module.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/errno.h>
@@ -59,18 +65,24 @@
#include <linux/tty_driver.h>
#include <linux/malloc.h>
#include <linux/string.h>
+
+#ifndef MODULE
+
+/* is* routines not available in modules
+** the need for this should go away when probing is done. :-)
+** brian@ilinx.com
+*/
+
#include <linux/ctype.h>
+#endif
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <asm/bitops.h>
-#define VERSION "1.5.6"
-static char *banner = "Digiboard PC/X{i,e,eve} driver v1.5.6. Christoph Lameter <clameter@fuller.edu>.";
-
-/*#define DEFAULT_HW_FLOW 1 */
-/*#define DEBUG_IOCTL */
+#define VERSION "1.5.7"
+static char *banner = "Digiboard PC/X{i,e,eve} driver v1.5.7";
#include "digi.h"
#include "fep.h"
@@ -145,6 +157,62 @@
#define TZ_BUFSZ 4096
+/* function definitions */
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+
+/*
+ * Loadable module initialization stuff.
+ */
+
+int init_module()
+{
+
+ return pcxe_init();
+
+}
+
+/*****************************************************************************/
+
+void cleanup_module()
+{
+
+ unsigned long flags;
+ int crd, i;
+ int e1, e2;
+ struct board_info *bd;
+ struct channel *ch;
+
+ printk(KERN_INFO "Unloading PC/Xx: version %s\n", VERSION);
+
+ save_flags(flags);
+ cli();
+ timer_active &= ~(1 << DIGI_TIMER);
+ timer_table[DIGI_TIMER].fn = NULL;
+ timer_table[DIGI_TIMER].expires = 0;
+
+ if ((e1 = tty_unregister_driver(&pcxe_driver)))
+ printk("SERIAL: failed to unregister serial driver (%d)\n", e1);
+ if ((e2 = tty_unregister_driver(&pcxe_callout)))
+ printk("SERIAL: failed to unregister callout driver (%d)\n",e2);
+
+ for(crd=0; crd < numcards; crd++) {
+ bd = &boards[crd];
+ ch = digi_channels+bd->first_minor;
+ for(i=0; i < bd->numports; i++, ch++) {
+ kfree(ch->tmp_buf);
+ }
+ release_region(bd->port, 4);
+ }
+ kfree(digi_channels);
+ kfree(pcxe_termios_locked);
+ kfree(pcxe_termios);
+ kfree(pcxe_table);
+ restore_flags(flags);
+}
+#endif
+
static inline struct channel *chan(register struct tty_struct *tty)
{
if (tty) {
@@ -289,7 +357,6 @@
}
-/* static ???why static??? */
int pcxe_open(struct tty_struct *tty, struct file * filp)
{
volatile struct board_chan *bc;
@@ -309,7 +376,7 @@
for(boardnum=0;boardnum<numcards;boardnum++)
if ((line >= boards[boardnum].first_minor) &&
- (line <= boards[boardnum].first_minor + boards[boardnum].numports))
+ (line < boards[boardnum].first_minor + boards[boardnum].numports))
break;
if(boardnum >= numcards || boards[boardnum].status == DISABLED ||
@@ -325,6 +392,8 @@
return(-ENODEV);
}
+ /* flag the kernel that there is somebody using this guy */
+ MOD_INC_USE_COUNT;
/*
* If the device is in the middle of being closed, then block
* until it's done, and then try again.
@@ -393,6 +462,13 @@
return -EBUSY;
}
else {
+ /* this has to be set in order for the "block until
+ * CD" code to work correctly. i'm not sure under
+ * what circumstances asyncflags should be set to
+ * ASYNC_NORMAL_ACTIVE though
+ * brian@ilinx.com
+ */
+ ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0)
return retval;
}
@@ -460,11 +536,26 @@
cli();
if(tty_hung_up_p(filp)) {
+ /* flag that somebody is done with this module */
+ MOD_DEC_USE_COUNT;
restore_flags(flags);
return;
}
+ /* this check is in serial.c, it won't hurt to do it here too */
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("pcxe_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count);
+ info->count = 1;
+ }
if (info->count-- > 1) {
restore_flags(flags);
+ MOD_DEC_USE_COUNT;
return;
}
if (info->count < 0) {
@@ -495,6 +586,13 @@
tty->closing = 0;
info->event = 0;
info->tty = NULL;
+#ifndef MODULE
+/* ldiscs[] is not available in a MODULE
+** worth noting that while I'm not sure what this hunk of code is supposed
+** to do, it is not present in the serial.c driver. Hmmm. If you know,
+** please send me a note. brian@ilinx.com
+** Dont know either what this is supposed to do clameter@waterf.org.
+*/
if(tty->ldisc.num != ldiscs[N_TTY].num) {
if(tty->ldisc.close)
(tty->ldisc.close)(tty);
@@ -503,6 +601,7 @@
if(tty->ldisc.open)
(tty->ldisc.open)(tty);
}
+#endif
if(info->blocked_open) {
if(info->close_delay) {
current->state = TASK_INTERRUPTIBLE;
@@ -514,6 +613,7 @@
info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|
ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&info->close_wait);
+ MOD_DEC_USE_COUNT;
restore_flags(flags);
}
}
@@ -562,9 +662,12 @@
cli();
globalwinon(ch);
head = bc->tin & (size - 1);
- tail = bc->tout;
- if (tail != bc->tout)
- tail = bc->tout;
+ /* It seems to be necessary to make sure that the value is stable here somehow
+ This is a rather odd pice of code here. */
+ do
+ { tail = bc->tout;
+ } while (tail != bc->tout);
+
tail &= (size - 1);
stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
count = MIN(stlen, count);
@@ -882,6 +985,11 @@
case 4:
t2 = str;
+#ifndef MODULE
+/* is* routines not available in modules
+** the need for this should go away when probing is done. :-)
+** brian@ilinx.com
+*/
while (isdigit(*t2))
t2++;
@@ -890,12 +998,18 @@
printk("PC/Xx: Invalid port count %s\n", str);
return;
}
+#endif
board.numports = simple_strtoul(str, NULL, 0);
last = i;
break;
case 5:
+#ifndef MODULE
+/* is* routines not available in modules
+** the need for this should go away when probing is done. :-)
+** brian@ilinx.com
+*/
t2 = str;
while (isxdigit(*t2))
t2++;
@@ -905,12 +1019,18 @@
printk("PC/Xx: Invalid port count %s\n", str);
return;
}
+#endif
board.port = simple_strtoul(str, NULL, 16);
last = i;
break;
case 6:
+#ifndef MODULE
+/* is* routines not available in modules
+** the need for this should go away when probing is done. :-)
+** brian@ilinx.com
+*/
t2 = str;
while (isxdigit(*t2))
t2++;
@@ -920,6 +1040,7 @@
printk("PC/Xx: Invalid memory base %s\n", str);
return;
}
+#endif
board.membase = simple_strtoul(str, NULL, 16);
last = i;
@@ -958,10 +1079,6 @@
int pcxe_init(void)
{
-#if 0
- ulong save_loops_per_sec;
-#endif
-
ulong flags, memory_seg=0, memory_size;
int lowwater, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
unchar *fepos, *memaddr, *bios, v;
@@ -998,6 +1115,7 @@
pcxe_table = kmalloc(sizeof(struct tty_struct *) * nbdevs, GFP_KERNEL);
if (!pcxe_table)
panic("Unable to allocate pcxe_table struct");
+ memset(pcxe_table, 0, sizeof(struct tty_struct *) * nbdevs);
pcxe_termios = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL);
if (!pcxe_termios)
@@ -1007,7 +1125,6 @@
if (!pcxe_termios_locked)
panic("Unable to allocate pcxe_termios_locked struct");
-
init_bh(DIGI_BH,do_pcxe_bh);
enable_bh(DIGI_BH);
@@ -1016,7 +1133,7 @@
memset(&pcxe_driver, 0, sizeof(struct tty_driver));
pcxe_driver.magic = TTY_DRIVER_MAGIC;
- pcxe_driver.name = "cud";
+ pcxe_driver.name = "ttyD";
pcxe_driver.major = DIGI_MAJOR;
pcxe_driver.minor_start = 0;
@@ -1025,7 +1142,7 @@
pcxe_driver.type = TTY_DRIVER_TYPE_SERIAL;
pcxe_driver.subtype = SERIAL_TYPE_NORMAL;
pcxe_driver.init_termios = tty_std_termios;
- pcxe_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
+ pcxe_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
pcxe_driver.flags = TTY_DRIVER_REAL_RAW;
pcxe_driver.refcount = &pcxe_refcount;
@@ -1050,22 +1167,10 @@
pcxe_driver.hangup = pcxe_hangup;
pcxe_callout = pcxe_driver;
- pcxe_callout.name = "ttyD";
+ pcxe_callout.name = "cud";
pcxe_callout.major = DIGICU_MAJOR;
pcxe_callout.subtype = SERIAL_TYPE_CALLOUT;
- pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
-
-#if 0
-
-/* strangely enough, this is FALSE */
-
- /*
- * loops_per_sec hasn't been set at this point :-(, so fake it out...
- * I set it so that I can use the __delay() function.
- */
- save_loops_per_sec = loops_per_sec;
- loops_per_sec = 13L*500000L;
-#endif
+ pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
save_flags(flags);
cli();
@@ -1346,6 +1451,10 @@
ch->normal_termios = pcxe_driver.init_termios;
ch->open_wait = 0;
ch->close_wait = 0;
+ /* zero out flags as it is unassigned at this point
+ * brian@ilinx.com
+ */
+ ch->asyncflags = 0;
}
printk("PC/Xx: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n",
@@ -1610,7 +1719,7 @@
if (cflag & B115200) res|=1;
}
else ch->digiext.digi_flags &= ~DIGI_FAST;
- res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE);
+ res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE | CLOCAL);
return res;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov