diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
commit | 19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch) | |
tree | 40b1cb534496a7f1ca0f5c314a523c69f1fee464 /drivers/char/pcxx.c | |
parent | 7206675c40394c78a90e74812bbdbf8cf3cca1be (diff) |
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'drivers/char/pcxx.c')
-rw-r--r-- | drivers/char/pcxx.c | 339 |
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(); */ } } |