summaryrefslogtreecommitdiffstats
path: root/drivers/char/pcxx.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
committer <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
commit19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch)
tree40b1cb534496a7f1ca0f5c314a523c69f1fee464 /drivers/char/pcxx.c
parent7206675c40394c78a90e74812bbdbf8cf3cca1be (diff)
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'drivers/char/pcxx.c')
-rw-r--r--drivers/char/pcxx.c339
1 files changed, 242 insertions, 97 deletions
diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c
index b3f3af024..c09c7dbbe 100644
--- a/drivers/char/pcxx.c
+++ b/drivers/char/pcxx.c
@@ -33,10 +33,14 @@
* 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
+ * 1.6.1 April 6, 1997 Bernhard Kaindl: fixed virtual memory access for 2.1
+ * i386-kernels and use on other archtitectures, Allowing use
+ * as module, added module parameters, added switch to enable
+ * verbose messages to assist user during card configuration.
+ * Currently only tested on a PC/Xi card, but should work on Xe
+ * and Xeve also.
*
*/
-#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
@@ -65,15 +69,10 @@
#include <linux/tty_driver.h>
#include <linux/malloc.h>
#include <linux/string.h>
+#include <linux/init.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>
+#include <linux/ctype.h> /* We only need it for parsing the "digi="-line */
#endif
#include <asm/system.h>
@@ -81,8 +80,7 @@
#include <asm/uaccess.h>
#include <asm/bitops.h>
-#define VERSION "1.5.7"
-static char *banner = "Digiboard PC/X{i,e,eve} driver v1.5.7";
+#define VERSION "1.6.1"
#include "digi.h"
#include "fep.h"
@@ -90,11 +88,45 @@ static char *banner = "Digiboard PC/X{i,e,eve} driver v1.5.7";
#include "digi_fep.h"
#include "digi_bios.h"
-/* Define one default setting if no digi= config line is used.
- * Default is ALTPIN = ON, PC/16E, 16 ports, I/O 200h Memory 0D0000h
+/*
+ * Define one default setting if no digi= config line is used.
+ * Default is altpin = disabled, 16 ports, I/O 200h, Memory 0D0000h
*/
-static struct board_info boards[MAX_DIGI_BOARDS] = { { ENABLED, 0, ON, 16, 0x200, 0xd0000,0 } };
+static struct board_info boards[MAX_DIGI_BOARDS] = { {
+/* Board is enabled */ ENABLED,
+/* Type is auto-detected */ 0,
+/* altping is disabled */ DISABLED,
+/* number of ports = 16 */ 16,
+/* io address is 0x200 */ 0x200,
+/* card memory at 0xd0000 */ 0xd0000,
+/* first minor device no. */ 0
+} };
+static int verbose = 0;
+static int debug = 0;
+
+#ifdef MODULE
+/* Variables for insmod */
+static int io[] = {0, 0, 0, 0};
+static int membase[] = {0, 0, 0, 0};
+static int memsize[] = {0, 0, 0, 0};
+static int altpin[] = {0, 0, 0, 0};
+static int numports[] = {0, 0, 0, 0};
+
+# if (LINUX_VERSION_CODE > 0x020111)
+MODULE_AUTHOR("Bernhard Kaindl");
+MODULE_DESCRIPTION("Digiboard PC/X{i,e,eve} driver");
+MODULE_PARM(verbose, "i");
+MODULE_PARM(debug, "i");
+MODULE_PARM(io, "1-4i");
+MODULE_PARM(membase, "1-4i");
+MODULE_PARM(memsize, "1-4i");
+MODULE_PARM(altpin, "1-4i");
+MODULE_PARM(numports, "1-4i");
+# endif
+
+#endif MODULE
+
static int numcards = 1;
static int nbdevs = 0;
@@ -159,19 +191,14 @@ static inline void assertmemoff(struct channel *ch);
/* function definitions */
#ifdef MODULE
-int init_module(void);
-void cleanup_module(void);
/*
- * Loadable module initialization stuff.
+ * pcxe_init() is our init_module():
*/
+#define pcxe_init init_module
-int init_module()
-{
-
- return pcxe_init();
+void cleanup_module(void);
-}
/*****************************************************************************/
@@ -184,13 +211,14 @@ void cleanup_module()
struct board_info *bd;
struct channel *ch;
- printk(KERN_INFO "Unloading PC/Xx: version %s\n", VERSION);
+ printk(KERN_NOTICE "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;
+ remove_bh(DIGI_BH);
if ((e1 = tty_unregister_driver(&pcxe_driver)))
printk("SERIAL: failed to unregister serial driver (%d)\n", e1);
@@ -287,7 +315,7 @@ static inline void assertmemoff(struct channel *ch)
static inline void pcxe_sched_event(struct channel *info, int event)
{
info->event |= 1 << event;
- queue_task_irq_off(&info->tqueue, &tq_pcxx);
+ queue_task(&info->tqueue, &tq_pcxx);
mark_bh(DIGI_BH);
}
@@ -861,12 +889,12 @@ static void pcxe_flush_chars(struct tty_struct *tty)
}
}
-/* Flag if lilo configuration option is used. If so the
- * default settings are removed
- */
-
-static int liloconfig=0;
+#ifndef MODULE
+/*
+ * Driver setup function when linked into the kernel to optionally parse multible
+ * "digi="-lines and initialize the driver at boot time. No probing.
+ */
void pcxx_setup(char *str, int *ints)
{
@@ -875,11 +903,7 @@ void pcxx_setup(char *str, int *ints)
char *temp, *t2;
unsigned len;
-#if 0
- if (!numcards)
- memset(&boards, 0, sizeof(boards));
-#endif
- if (liloconfig==0) { liloconfig=1;numcards=0; }
+ numcards=0;
memset(&board, 0, sizeof(board));
@@ -921,7 +945,6 @@ void pcxx_setup(char *str, int *ints)
return;
}
-
while (str && *str)
{
/* find the next comma or terminator */
@@ -985,11 +1008,6 @@ void pcxx_setup(char *str, int *ints)
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++;
@@ -998,39 +1016,27 @@ void pcxx_setup(char *str, int *ints)
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++;
if (*t2)
{
- printk("PC/Xx: Invalid port count %s\n", str);
+ printk("PC/Xx: Invalid io port address %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++;
@@ -1040,7 +1046,6 @@ void pcxx_setup(char *str, int *ints)
printk("PC/Xx: Invalid memory base %s\n", str);
return;
}
-#endif
board.membase = simple_strtoul(str, NULL, 16);
last = i;
@@ -1075,33 +1080,97 @@ void pcxx_setup(char *str, int *ints)
/* yeha! string parameter was successful! */
numcards++;
}
+#endif
-
-int pcxe_init(void)
+/*
+ * function to initialize the driver with the given parameters, which are either
+ * the default values from this file or the parameters given at boot.
+ */
+__initfunc(int pcxe_init(void))
{
- ulong flags, memory_seg=0, memory_size;
- int lowwater, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
+ ulong memory_seg=0, memory_size=0;
+ int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;
unchar *fepos, *memaddr, *bios, v;
volatile struct global_data *gd;
- struct board_info *bd;
volatile struct board_chan *bc;
+ struct board_info *bd;
struct channel *ch;
- printk("%s\n", banner);
+ printk(KERN_NOTICE "Digiboard PC/X{i,e,eve} driver v%s\n", VERSION);
+
+#ifdef MODULE
+ for (i = 0; i < 4; i++) {
+ if (io[i]) {
+ numcards = 0;
+ break;
+ }
+ }
+ if (numcards == 0) {
+ int first_minor = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (io[i] == 0) {
+ boards[i].port = 0;
+ boards[i].status = DISABLED;
+ }
+ else {
+ boards[i].port = (ushort)io[i];
+ boards[i].status = ENABLED;
+ boards[i].first_minor = first_minor;
+ numcards=i+1;
+ }
+ if (membase[i])
+ boards[i].membase = (ulong)membase[i];
+ else
+ boards[i].membase = 0xD0000;
+
+ if (memsize[i])
+ boards[i].memsize = (ulong)(memsize[i] * 1024);
+ else
+ boards[i].memsize = 0;
+
+ if (altpin[i])
+ boards[i].altpin = ON;
+ else
+ boards[i].altpin = OFF;
+
+ if (numports[i])
+ boards[i].numports = (ushort)numports[i];
+ else
+ boards[i].numports = 16;
+
+ first_minor += boards[i].numports;
+ }
+ }
+#endif
if (numcards <= 0)
{
- printk("PC/Xx: No cards configured, exiting.\n");
- return(0);
+ printk("PC/Xx: No cards configured, driver not active.\n");
+ return -EIO;
}
+#if 1
+ if (debug)
+ for (i = 0; i < numcards; i++) {
+ printk("Card %d:status=%d, port=0x%x, membase=0x%lx, memsize=0x%lx, altpin=%d, numports=%d, first_minor=%d\n",
+ i+1,
+ boards[i].status,
+ boards[i].port,
+ boards[i].membase,
+ boards[i].memsize,
+ boards[i].altpin,
+ boards[i].numports,
+ boards[i].first_minor);
+ }
+#endif
for (i=0;i<numcards;i++)
nbdevs += boards[i].numports;
if (nbdevs <= 0)
{
- printk("PC/Xx: No devices activated, exiting.\n");
- return(0);
+ printk("PC/Xx: No devices activated, driver not active.\n");
+ return -EIO;
}
/*
@@ -1111,6 +1180,7 @@ int pcxe_init(void)
digi_channels = kmalloc(sizeof(struct channel) * nbdevs, GFP_KERNEL);
if (!digi_channels)
panic("Unable to allocate digi_channel struct");
+ memset(digi_channels, 0, sizeof(struct channel) * nbdevs);
pcxe_table = kmalloc(sizeof(struct tty_struct *) * nbdevs, GFP_KERNEL);
if (!pcxe_table)
@@ -1174,22 +1244,22 @@ int pcxe_init(void)
pcxe_callout.subtype = SERIAL_TYPE_CALLOUT;
pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- save_flags(flags);
- cli();
-
for(crd=0; crd < numcards; crd++) {
bd = &boards[crd];
outb(FEPRST, bd->port);
pcxxdelay(1);
for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {
- if(i > 1000) {
+ if(i > 100) {
printk("PC/Xx: Board not found at port 0x%x! Check switch settings.\n",
bd->port);
bd->status = DISABLED;
break;
}
- pcxxdelay(1);
+#ifdef MODULE
+ schedule();
+#endif
+ pcxxdelay(10);
}
if(bd->status == DISABLED)
continue;
@@ -1236,18 +1306,38 @@ int pcxe_init(void)
memory_size = 0x10000;
}
}
+ if (verbose)
+ printk("Configuring card %d as a %s %ldK card. io=0x%x, mem=%lx-%lx\n",
+ crd+1, board_desc[bd->type], memory_size/1024,
+ bd->port,bd->membase,bd->membase+memory_size-1);
+
+ if (boards[crd].memsize == 0)
+ boards[crd].memsize = memory_size;
+ else
+ if (boards[crd].memsize != memory_size) {
+ printk("PC/Xx: memory size mismatch:supplied=%lx(%ldK) probed=%ld(%ldK)\n",
+ boards[crd].memsize, boards[crd].memsize / 1024,
+ memory_size, memory_size / 1024);
+ continue;
+ }
- memaddr = (unchar *) bd->membase;
+ memaddr = (unchar *)phys_to_virt(bd->membase);
+
+ if (verbose)
+ printk("Resetting board and testing memory access:");
outb(FEPRST|FEPMEM, bd->port);
for(i=0; (inb(bd->port) & FEPMASK) != (FEPRST|FEPMEM); i++) {
- if(i > 10000) {
- printk("PC/Xx: %s not resetting at port 0x%x! Check switch settings.\n",
+ if(i > 1000) {
+ printk("\nPC/Xx: %s not resetting at port 0x%x! Check switch settings.\n",
board_desc[bd->type], bd->port);
bd->status = DISABLED;
break;
}
+#ifdef MODULE
+ schedule();
+#endif
pcxxdelay(1);
}
if(bd->status == DISABLED)
@@ -1264,6 +1354,8 @@ int pcxe_init(void)
bd->status = DISABLED;
continue;
}
+ if (verbose)
+ printk(" done.\n");
for(i=0; i < 16; i++) {
memaddr[MISCGLOBAL+i] = 0;
@@ -1272,19 +1364,36 @@ int pcxe_init(void)
if(bd->type == PCXI || bd->type == PCXE) {
bios = memaddr + BIOSCODE + ((0xf000 - memory_seg) << 4);
+ if (verbose)
+ printk("Downloading BIOS to 0x%lx:", virt_to_phys(bios));
+
memcpy(bios, pcxx_bios, pcxx_nbios);
+ if (verbose)
+ printk(" done.\n");
+
outb(FEPMEM, bd->port);
- for(i=0; i <= 10000; i++) {
+ if (verbose)
+ printk("Waiting for BIOS to become ready");
+
+ for(i=1; i <= 30; i++) {
if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
goto load_fep;
}
- pcxxdelay(1);
+ if (verbose) {
+ printk(".");
+ if (i % 50 == 0)
+ printk("\n");
+ }
+#ifdef MODULE
+ schedule();
+#endif
+ pcxxdelay(50);
}
- printk("PC/Xx: BIOS download failed on the %s at 0x%x!\n",
- board_desc[bd->type], bd->port);
+ printk("\nPC/Xx: BIOS download failed for board at 0x%x(addr=%lx-%lx)!\n",
+ bd->port, bd->membase, bd->membase+bd->memsize);
bd->status = DISABLED;
continue;
}
@@ -1298,14 +1407,22 @@ int pcxe_init(void)
outb(FEPCLR, bd->port);
memwinon(bd,0);
- for(i=0; i <= 10000; i++) {
+ for(i=0; i <= 1000; i++) {
if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) {
goto load_fep;
}
- pcxxdelay(1);
+ if (verbose) {
+ printk(".");
+ if (i % 50 == 0)
+ printk("\n");
+ }
+#ifdef MODULE
+ schedule();
+#endif
+ pcxxdelay(10);
}
- printk("PC/Xx: BIOS download failed on the %s at 0x%x!\n",
+ printk("\nPC/Xx: BIOS download failed on the %s at 0x%x!\n",
board_desc[bd->type], bd->port);
bd->status = DISABLED;
continue;
@@ -1316,10 +1433,16 @@ load_fep:
if(bd->type == PCXEVE)
fepos = memaddr + (FEPCODE & 0x1fff);
+ if (verbose)
+ printk(" ok.\nDownloading FEP/OS to 0x%lx:", virt_to_phys(fepos));
+
memwinon(bd, (FEPCODE >> 13));
memcpy(fepos, pcxx_cook, pcxx_ncook);
memwinon(bd, 0);
+ if (verbose)
+ printk(" done.\n");
+
*(ushort *)((ulong)memaddr + MBOX + 0) = 2;
*(ushort *)((ulong)memaddr + MBOX + 2) = memory_seg + FEPCODESEG;
*(ushort *)((ulong)memaddr + MBOX + 4) = 0;
@@ -1337,12 +1460,18 @@ load_fep:
bd->status = DISABLED;
break;
}
+#ifdef MODULE
+ schedule();
+#endif
pcxxdelay(1);
}
if(bd->status == DISABLED)
continue;
+ if (verbose)
+ printk("Waiting for FEP/OS to become ready");
+
*(ushort *)(memaddr + FEPSTAT) = 0;
*(ushort *)(memaddr + MBOX + 0) = 1;
*(ushort *)(memaddr + MBOX + 2) = FEPCODESEG;
@@ -1352,18 +1481,29 @@ load_fep:
outb(FEPCLR, bd->port);
memwinon(bd, 0);
- for(i=0; *(ushort *)((ulong)memaddr + FEPSTAT) != *(ushort *)"OS"; i++) {
- if(i > 10000) {
- printk("PC/Xx: FEP/OS download failed on the %s at 0x%x!\n",
+ for(i=1; *(ushort *)((ulong)memaddr + FEPSTAT) != *(ushort *)"OS"; i++) {
+ if(i > 1000) {
+ printk("\nPC/Xx: FEP/OS download failed on the %s at 0x%x!\n",
board_desc[bd->type], bd->port);
bd->status = DISABLED;
break;
}
+ if (verbose) {
+ printk(".");
+ if (i % 50 == 0)
+ printk("\n%5d",i/50);
+ }
+#ifdef MODULE
+ schedule();
+#endif
pcxxdelay(1);
}
if(bd->status == DISABLED)
continue;
+ if (verbose)
+ printk(" ok.\n");
+
ch = digi_channels+bd->first_minor;
pcxxassert(ch < digi_channels+nbdevs, "ch out of range");
@@ -1422,9 +1562,7 @@ load_fep:
ch->txbufsize = bc->tmax + 1;
ch->rxbufsize = bc->rmax + 1;
-
ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
-
lowwater = ch->txbufsize >= 2000 ? 1024 : ch->txbufsize/2;
fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
fepcmd(ch, SRXLWATER, ch->rxbufsize/4, 0, 10, 0);
@@ -1453,17 +1591,25 @@ load_fep:
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",
- board_desc[bd->type], board_mem[bd->type], bd->port,
- bd->membase, bd->numports);
+ if (verbose)
+ printk("Card No. %d ready: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n",
+ crd+1, board_desc[bd->type], board_mem[bd->type], bd->port,
+ bd->membase, bd->numports);
+ else
+ printk("PC/Xx: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n",
+ board_desc[bd->type], board_mem[bd->type], bd->port,
+ bd->membase, bd->numports);
memwinoff(bd, 0);
+ enabled_cards++;
+ }
+
+ if (enabled_cards <= 0) {
+ printk(KERN_NOTICE "PC/Xx: No cards enabled, no driver.\n");
+ return -EIO;
}
if(tty_register_driver(&pcxe_driver))
@@ -1472,15 +1618,13 @@ load_fep:
if(tty_register_driver(&pcxe_callout))
panic("Couldn't register PC/Xe callout");
-#if 0
- loops_per_sec = save_loops_per_sec; /* reset it to what it should be */
-#endif
-
/*
* Start up the poller to check for events on all enabled boards
*/
timer_active |= 1 << DIGI_TIMER;
- restore_flags(flags);
+
+ if (verbose)
+ printk(KERN_NOTICE "PC/Xx: Driver with %d card(s) ready.\n", enabled_cards);
return 0;
}
@@ -1545,7 +1689,7 @@ static void doevent(int crd)
while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) {
assertgwinon(chan0);
- eventbuf = (volatile unchar *)bd->membase + tail + ISTART;
+ eventbuf = (volatile unchar *)phys_to_virt(bd->membase + tail + ISTART);
channel = eventbuf[0];
event = eventbuf[1];
mstat = eventbuf[2];
@@ -1656,7 +1800,7 @@ fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,
assertgwinon(ch);
- memaddr = (unchar *)ch->board->membase;
+ memaddr = (unchar *)phys_to_virt(ch->board->membase);
head = ch->mailbox->cin;
if(head >= (CMAX-CSTART) || (head & 03)) {
@@ -1697,6 +1841,7 @@ fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,
if(n <= ncmds * (sizeof(short)*4))
break;
+ /* Seems not to be good here: schedule(); */
}
}