📄 pcxx.c
字号:
bd = &boards[crd]; outb(FEPRST, bd->port); pcxxdelay(1); for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) { if(i > 100) { printk("PC/Xx: Board not found at port 0x%x! Check switch settings.\n", bd->port); bd->status = DISABLED; break; }#ifdef MODULE schedule();#endif pcxxdelay(10); } if(bd->status == DISABLED) continue; v = inb(bd->port); if((v & 0x1) == 0x1) { if((v & 0x30) == 0) { /* PC/Xi 64K card */ memory_seg = 0xf000; memory_size = 0x10000; } if((v & 0x30) == 0x10) { /* PC/Xi 128K card */ memory_seg = 0xe000; memory_size = 0x20000; } if((v & 0x30) == 0x20) { /* PC/Xi 256K card */ memory_seg = 0xc000; memory_size = 0x40000; } if((v & 0x30) == 0x30) { /* PC/Xi 512K card */ memory_seg = 0x8000; memory_size = 0x80000; } bd->type = PCXI; } else { if((v & 0x1) == 0x1) { bd->status = DISABLED; /* PC/Xm unsupported card */ printk("PC/Xx: PC/Xm at 0x%x not supported!!\n", bd->port); continue; } else { if(v & 0xC0) { topwin = 0x1f00L; outb((((ulong)bd->membase>>8) & 0xe0) | 0x10, bd->port+2); outb(((ulong)bd->membase>>16) & 0xff, bd->port+3); bd->type = PCXEVE; /* PC/Xe 8K card */ } else { bd->type = PCXE; /* PC/Xe 64K card */ } memory_seg = 0xf000; 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 *)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 > 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) continue; memwinon(bd,0); *(ulong *)(memaddr + botwin) = 0xa55a3cc3; *(ulong *)(memaddr + topwin) = 0x5aa5c33c; if(*(ulong *)(memaddr + botwin) != 0xa55a3cc3 || *(ulong *)(memaddr + topwin) != 0x5aa5c33c) { printk("PC/Xx: Failed memory test at %lx for %s at port %x, check switch settings.\n", bd->membase, board_desc[bd->type], bd->port); bd->status = DISABLED; continue; } if (verbose) printk(" done.\n"); for(i=0; i < 16; i++) { memaddr[MISCGLOBAL+i] = 0; } 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); 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; } if (verbose) { printk("."); if (i % 50 == 0) printk("\n"); }#ifdef MODULE schedule();#endif pcxxdelay(50); } 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; } if(bd->type == PCXEVE) { bios = memaddr + (BIOSCODE & 0x1fff); memwinon(bd,0xff); memcpy(bios, pcxx_bios, pcxx_nbios); outb(FEPCLR, bd->port); memwinon(bd,0); for(i=0; i <= 1000; i++) { if(*(ushort *)((ulong)memaddr + MISCGLOBAL) == *(ushort *)"GD" ) { goto load_fep; } if (verbose) { printk("."); if (i % 50 == 0) printk("\n"); }#ifdef MODULE schedule();#endif pcxxdelay(10); } printk("\nPC/Xx: BIOS download failed on the %s at 0x%x!\n", board_desc[bd->type], bd->port); bd->status = DISABLED; continue; }load_fep: fepos = memaddr + FEPCODE; 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; *(ushort *)((ulong)memaddr + MBOX + 6) = FEPCODESEG; *(ushort *)((ulong)memaddr + MBOX + 8) = 0; *(ushort *)((ulong)memaddr + MBOX + 10) = pcxx_ncook; outb(FEPMEM|FEPINT, bd->port); outb(FEPMEM, bd->port); for(i=0; *(ushort *)((ulong)memaddr + MBOX); i++) { if(i > 2000) { printk("PC/Xx: Command failed for the %s at 0x%x!\n", board_desc[bd->type], bd->port); 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; *(ushort *)(memaddr + MBOX + 4) = 0x4L; outb(FEPINT, bd->port); outb(FEPCLR, bd->port); memwinon(bd, 0); 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"); bc = (volatile struct board_chan *)((ulong)memaddr + CHANSTRUCT); gd = (volatile struct global_data *)((ulong)memaddr + GLOBAL); if((bd->type == PCXEVE) && (*(ushort *)((ulong)memaddr+NPORT) < 3)) shrinkmem = 1; request_region(bd->port, 4, "PC/Xx"); for(i=0; i < bd->numports; i++, ch++, bc++) { if(((ushort *)((ulong)memaddr + PORTBASE))[i] == 0) { ch->brdchan = 0; continue; } ch->brdchan = bc; ch->mailbox = gd; ch->tqueue.routine = do_softint; ch->tqueue.data = ch; ch->board = &boards[crd];#ifdef DEFAULT_HW_FLOW ch->digiext.digi_flags = RTSPACE|CTSPACE;#endif if(boards[crd].altpin) { ch->dsr = CD; ch->dcd = DSR; ch->digiext.digi_flags |= DIGI_ALTPIN; } else { ch->dcd = CD; ch->dsr = DSR; } ch->magic = PCXX_MAGIC; ch->boardnum = crd; ch->channelnum = i; ch->dev = bd->first_minor + i; ch->tty = 0; if(shrinkmem) { fepcmd(ch, SETBUFFER, 32, 0, 0, 0); shrinkmem = 0; } if(bd->type != PCXEVE) { ch->txptr = memaddr+((bc->tseg-memory_seg) << 4); ch->rxptr = memaddr+((bc->rseg-memory_seg) << 4); ch->txwin = ch->rxwin = 0; } else { ch->txptr = memaddr+(((bc->tseg-memory_seg) << 4) & 0x1fff); ch->txwin = FEPWIN | ((bc->tseg-memory_seg) >> 9); ch->rxptr = memaddr+(((bc->rseg-memory_seg) << 4) & 0x1fff); ch->rxwin = FEPWIN | ((bc->rseg-memory_seg) >>9 ); } 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); fepcmd(ch, SRXHWATER, 3 * ch->rxbufsize/4, 0, 10, 0); bc->edelay = 100; bc->idata = 1; ch->startc = bc->startc; ch->stopc = bc->stopc; ch->startca = bc->startca; ch->stopca = bc->stopca; ch->fepcflag = 0; ch->fepiflag = 0; ch->fepoflag = 0; ch->fepstartc = 0; ch->fepstopc = 0; ch->fepstartca = 0; ch->fepstopca = 0; ch->close_delay = 50; ch->count = 0; ch->blocked_open = 0; ch->callout_termios = pcxe_callout.init_termios; ch->normal_termios = pcxe_driver.init_termios; ch->open_wait = 0; ch->close_wait = 0; ch->asyncflags = 0; } 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)) panic("Couldn't register PC/Xe driver"); if(tty_register_driver(&pcxe_callout)) panic("Couldn't register PC/Xe callout"); /* * Start up the poller to check for events on all enabled boards */ timer_active |= 1 << DIGI_TIMER; if (verbose) printk(KERN_NOTICE "PC/Xx: Driver with %d card(s) ready.\n", enabled_cards); return 0;}static void pcxxpoll(void){ unsigned long flags; int crd; volatile unsigned int head, tail; struct channel *ch; struct board_info *bd; save_flags(flags); cli(); for(crd=0; crd < numcards; crd++) { bd = &boards[crd]; ch = digi_channels+bd->first_minor; if(bd->status == DISABLED) continue; assertmemoff(ch); globalwinon(ch); head = ch->mailbox->ein; tail = ch->mailbox->eout; if(head != tail) doevent(crd); memoff(ch); } timer_table[DIGI_TIMER].fn = pcxxpoll; timer_table[DIGI_TIMER].expires = jiffies + HZ/25; timer_active |= 1 << DIGI_TIMER; restore_flags(flags);}static void doevent(int crd){ volatile struct board_info *bd; static struct tty_struct *tty; volatile struct board_chan *bc; volatile unchar *eventbuf; volatile unsigned int head; volatile unsigned int tail; struct channel *ch; struct channel *chan0; int channel, event, mstat, lstat; bd = &boards[crd]; chan0 = digi_channels+bd->first_minor; pcxxassert(chan0 < digi_channels+nbdevs, "ch out of range"); assertgwinon(chan0); while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) { assertgwinon(chan0); eventbuf = (volatile unchar *)phys_to_virt(bd->membase + tail + ISTART); channel = eventbuf[0]; event = eventbuf[1]; mstat = eventbuf[2]; lstat = eventbuf[3]; ch=chan0+channel; if ((unsigned)channel >= bd->numports || !ch) { printk("physmem=%lx, tail=%x, head=%x\n", bd->membase, tail, head); printk("doevent(%x) channel %x, event %x, mstat %x, lstat %x\n", crd, (unsigned)channel, event, (unsigned)mstat, lstat); if(channel >= bd->numports) ch = chan0; bc = ch->brdchan; goto next; } if ((bc = ch->brdchan) == NULL) goto next; if (event & DATA_IND) { receive_data(ch); assertgwinon(ch); } if (event & MODEMCHG_IND) { ch->imodem = mstat; if (ch->asyncflags & (ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE)) { if (ch->asyncflags & ASYNC_CHECK_CD) { if (mstat & ch->dcd) { wake_up_interruptible(&ch->open_wait); } else { pcxe_sched_event(ch, PCXE_EVENT_HANGUP); } } } } tty = ch->tty; if (tty) { if (event & BREAK_IND) { tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_BREAK; *tty->flip.char_buf_ptr++ = 0;#if 0 if (ch->asyncflags & ASYNC_SAK) do_SAK(tty);#endif tty_schedule_flip(tty); } if (event & LOWTX_IND) { if (ch->statusflags & LOWWAIT) { ch->statusflags &= ~LOWWAIT; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); } } if (event & EMPTYTX_IND) { ch->statusflags &= ~TXBUSY; if (ch->statusflags & EMPTYWAIT) { ch->statusflags &= ~EMPTYWAIT; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); } } } next: globalwinon(ch); if(!bc) printk("bc == NULL in doevent!\n"); else bc->idata = 1; chan0->mailbox->eout = (tail+4) & (IMAX-ISTART-4); globalwinon(chan0); }}/* * pcxxdelay - delays a specified number of milliseconds */static void pcxxdelay(int msec){ while(msec-- > 0) __delay(loops_per_sec/1000);}static void fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds, int bytecmd){ unchar *memaddr; unsigned int head, tail; long count; int n; if(ch->board->status == DISABLED) return; assertgwinon(ch); memaddr = (unchar *)phys_to_virt(ch->board->membase); head = ch->mailbox->cin; if(head >= (CMAX-CSTART) || (head & 03)) { printk("line %d: Out of range, cmd=%x, head=%x\n", __LINE__, cmd, head); return; } if(bytecmd) { *(unchar *)(memaddr+head+CSTART+0) = cmd; *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor; *(unchar *)(memaddr+head+CSTART+2) = word_or_byte; *(unchar *)(memaddr+head+CSTART+3) = byte2; } else { *(unchar *)(memaddr+head+CSTART+0) = cmd; *(unchar *)(memaddr+head+CSTART+1) = ch->dev - ch->board->first_minor; *(ushort*)(memaddr+head+CSTART+2) = word_or_byte; } head = (head+4) & (CMAX-CSTART-4); ch->mailbox->cin = head; count = FEPTIMEOUT; while(1) { count--; if(count == 0) { printk("Fep not responding in fepcmd()\n"); return; } head = ch->mailbox->cin; tail = ch->mailbox->cout; n = (head-tail) & (CMAX-CSTART-4); if(n <= ncmds * (sizeof(short)*4)) break; /* Seems not to be good here: schedule(); */ }}static unsigned termios2digi_c(struct channel *ch, unsigned cflag){ unsigned res = 0;#ifdef SPEED_HACK /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */ if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200; if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;#endif if (cflag & CBAUDEX) { ch->digiext.digi_flags |= DIGI_FAST; res |= FEP_HUPCL; /* This gets strange but if we don't do this we will get 78600 * instead of 115200. 57600 is mapped to 50 baud yielding 57600 in * FAST mode. 115200 is mapped to 75. We need to map it to 110 to * do 115K */ if (cflag & B115200) res|=1; } else ch->digiext.digi_flags &= ~DIGI_FAST; res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE | CLOCAL); return res;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -