📄 dgb.c
字号:
default: printf("dgb%d: wrong IRQ mask 0x%x\n",dev->id_unit,dev->id_irq); sc->status=DISABLED; return 0; }#endif outb(sc->port+2,t & 0xFF); outb(sc->port+3,t>>8); } else if(sc->type==PCXE) { t=(((u_long)sc->pmem>>8) & 0xFFE0) /* disable windowing */; outb(sc->port+2,t & 0xFF); outb(sc->port+3,t>>8); } if(sc->type==PCXI || sc->type==PCXE) { outb(sc->port, FEPRST|FEPMEM); DELAY(1); for(i=0; (inb(sc->port) & FEPMASK) != (FEPRST|FEPMEM) ; i++) { if(i>10000) { printf("dgb%d: 2nd reset failed\n",dev->id_unit); sc->status=DISABLED; hidewin(sc); return 0; } DELAY(1); } DPRINT3(DB_INFO,"dgb%d: got memory after %d us\n",unit,i); } mem=sc->vmem; /* very short memory test */ addr=setinitwin(sc,BOTWIN); *(u_long *)(mem+addr) = 0xA55A3CC3; if(*(u_long *)(mem+addr)!=0xA55A3CC3) { printf("dgb%d: 1st memory test failed\n",dev->id_unit); sc->status=DISABLED; hidewin(sc); return 0; } addr=setinitwin(sc,TOPWIN); *(u_long *)(mem+addr) = 0x5AA5C33C; if(*(u_long *)(mem+addr)!=0x5AA5C33C) { printf("dgb%d: 2nd memory test failed\n",dev->id_unit); sc->status=DISABLED; hidewin(sc); return 0; } addr=setinitwin(sc,BIOSCODE+((0xF000-sc->mem_seg)<<4)); *(u_long *)(mem+addr) = 0x5AA5C33C; if(*(u_long *)(mem+addr)!=0x5AA5C33C) { printf("dgb%d: 3rd (BIOS) memory test failed\n",dev->id_unit); } addr=setinitwin(sc,MISCGLOBAL); for(i=0; i<16; i++) { mem[addr+i]=0; } if(sc->type==PCXI || sc->type==PCXE) { addr=BIOSCODE+((0xF000-sc->mem_seg)<<4); DPRINT3(DB_INFO,"dgb%d: BIOS local address=0x%x\n",unit,addr); ptr= mem+addr; for(i=0; i<pcxx_nbios; i++, ptr++) *ptr = pcxx_bios[i]; ptr= mem+addr; nfails=0; for(i=0; i<pcxx_nbios; i++, ptr++) if( *ptr != pcxx_bios[i] ) { DPRINT5(DB_EXCEPT,"dgb%d: wrong code in BIOS at addr 0x%x : \0x%x instead of 0x%x\n", unit, ptr-(mem+addr), *ptr, pcxx_bios[i] ); if(++nfails>=5) { printf("dgb%d: 4th memory test (BIOS load) fails\n",unit); break; } } outb(sc->port,FEPMEM); for(i=0; (inb(sc->port) & FEPMASK) != FEPMEM ; i++) { if(i>10000) { printf("dgb%d: BIOS start failed\n",dev->id_unit); sc->status=DISABLED; hidewin(sc); return 0; } DELAY(1); } DPRINT3(DB_INFO,"dgb%d: reset dropped after %d us\n",unit,i); for(i=0; i<200000; i++) { if( *((ushort *)(mem+MISCGLOBAL)) == *((ushort *)"GD") ) goto load_fep; DELAY(1); } printf("dgb%d: BIOS download failed\n",dev->id_unit); DPRINT4(DB_EXCEPT,"dgb%d: code=0x%x must be 0x%x\n", dev->id_unit, *((ushort *)(mem+MISCGLOBAL)), *((ushort *)"GD")); sc->status=DISABLED; hidewin(sc); return 0; } if(sc->type==PCXEVE) { /* set window 7 */ outb(sc->port+1,0xFF); ptr= mem+(BIOSCODE & 0x1FFF); for(i=0; i<pcxx_nbios; i++) *ptr++ = pcxx_bios[i]; ptr= mem+(BIOSCODE & 0x1FFF); nfails=0; for(i=0; i<pcxx_nbios; i++, ptr++) if( *ptr != pcxx_bios[i] ) { DPRINT5(DB_EXCEPT,"dgb%d: wrong code in BIOS at addr 0x%x : \0x%x instead of 0x%x\n", unit, ptr-(mem+addr), *ptr, pcxx_bios[i] ); if(++nfails>=5) { printf("dgb%d: 4th memory test (BIOS load) fails\n",unit); break; } } outb(sc->port,FEPCLR); setwin(sc,0); for(i=0; (inb(sc->port) & FEPMASK) != FEPCLR ; i++) { if(i>10000) { printf("dgb%d: BIOS start failed\n",dev->id_unit); sc->status=DISABLED; hidewin(sc); return 0; } DELAY(1); } DPRINT3(DB_INFO,"dgb%d: reset dropped after %d us\n",unit,i); addr=setwin(sc,MISCGLOBAL); for(i=0; i<200000; i++) { if(*(ushort *)(mem+addr)== *(ushort *)"GD") goto load_fep; DELAY(1); } printf("dgb%d: BIOS download failed\n",dev->id_unit); DPRINT5(DB_EXCEPT,"dgb%d: Error#(0x%x,0x%x) code=0x%x\n", dev->id_unit, *(ushort *)(mem+0xC12), *(ushort *)(mem+0xC14), *(ushort *)(mem+MISCGLOBAL)); sc->status=DISABLED; hidewin(sc); return 0; }load_fep: DPRINT2(DB_INFO,"dgb%d: BIOS loaded\n",dev->id_unit); addr=setwin(sc,FEPCODE); ptr= mem+addr; for(i=0; i<pcxx_ncook; i++) *ptr++ = pcxx_cook[i]; addr=setwin(sc,MBOX); *(ushort *)(mem+addr+ 0)=2; *(ushort *)(mem+addr+ 2)=sc->mem_seg+FEPCODESEG; *(ushort *)(mem+addr+ 4)=0; *(ushort *)(mem+addr+ 6)=FEPCODESEG; *(ushort *)(mem+addr+ 8)=0; *(ushort *)(mem+addr+10)=pcxx_ncook; outb(sc->port,FEPMEM|FEPINT); /* send interrupt to BIOS */ outb(sc->port,FEPMEM); for(i=0; *(ushort *)(mem+addr)!=0; i++) { if(i>200000) { printf("dgb%d: FEP code download failed\n",unit); DPRINT3(DB_EXCEPT,"dgb%d: code=0x%x must be 0\n", unit, *(ushort *)(mem+addr)); sc->status=DISABLED; hidewin(sc); return 0; } } DPRINT2(DB_INFO,"dgb%d: FEP code loaded\n",unit); *(ushort *)(mem+setwin(sc,FEPSTAT))=0; addr=setwin(sc,MBOX); *(ushort *)(mem+addr+0)=1; *(ushort *)(mem+addr+2)=FEPCODESEG; *(ushort *)(mem+addr+4)=0x4; outb(sc->port,FEPINT); /* send interrupt to BIOS */ outb(sc->port,FEPCLR); addr=setwin(sc,FEPSTAT); for(i=0; *(ushort *)(mem+addr)!= *(ushort *)"OS"; i++) { if(i>200000) { printf("dgb%d: FEP/OS start failed\n",dev->id_unit); sc->status=DISABLED; hidewin(sc); return 0; } } DPRINT2(DB_INFO,"dgb%d: FEP/OS started\n",dev->id_unit); sc->numports= *(ushort *)(mem+setwin(sc,NPORT)); printf("dgb%d: %d ports\n",unit,sc->numports); if(sc->numports > MAX_DGB_PORTS) { printf("dgb%d: too many ports\n",unit); sc->status=DISABLED; hidewin(sc); return 0; } if(nports+sc->numports>NDGBPORTS) { printf("dgb%d: only %d ports are usable\n", unit, NDGBPORTS-nports); sc->numports=NDGBPORTS-nports; } /* allocate port and tty structures */ sc->ports=&dgb_ports[nports]; sc->ttys=&dgb_tty[nports]; nports+=sc->numports; addr=setwin(sc,PORTBASE); pstat=(ushort *)(mem+addr); for(i=0; i<sc->numports && pstat[i]; i++) if(pstat[i]) sc->ports[i].status=ENABLED; else { sc->ports[i].status=DISABLED; printf("dgb%d: port%d is broken\n", unit, i); } /* We should now init per-port structures */ bc=(volatile struct board_chan *)(mem + CHANSTRUCT); sc->mailbox=(volatile struct global_data *)(mem + FEP_GLOBAL); if(sc->numports<3) shrinkmem=1; else shrinkmem=0; for(i=0; i<sc->numports; i++, bc++) { port= &sc->ports[i]; port->tty=&sc->ttys[i]; port->unit=unit; port->brdchan=bc; if(sc->altpin) { port->dsr=CD; port->dcd=DSR; } else { port->dcd=CD; port->dsr=DSR; } port->pnum=i; if(shrinkmem) { DPRINT2(DB_INFO,"dgb%d: shrinking memory\n",unit); fepcmd(port, SETBUFFER, 32, 0, 0, 0); shrinkmem=0; } if(sc->type!=PCXEVE) { port->txptr=mem+((bc->tseg-sc->mem_seg)<<4); port->rxptr=mem+((bc->rseg-sc->mem_seg)<<4); port->txwin=port->rxwin=0; } else { port->txptr=mem+( ((bc->tseg-sc->mem_seg)<<4) & 0x1FFF ); port->rxptr=mem+( ((bc->rseg-sc->mem_seg)<<4) & 0x1FFF ); port->txwin=FEPWIN | ((bc->tseg-sc->mem_seg)>>9); port->rxwin=FEPWIN | ((bc->rseg-sc->mem_seg)>>9); } port->txbufhead=0; port->rxbufhead=0; port->txbufsize=bc->tmax+1; port->rxbufsize=bc->rmax+1; lowwater= (port->txbufsize>=2000) ? 1024 : (port->txbufsize/2); setwin(sc,0); fepcmd(port, STXLWATER, lowwater, 0, 10, 0); fepcmd(port, SRXLWATER, port->rxbufsize/4, 0, 10, 0); fepcmd(port, SRXHWATER, 3*port->rxbufsize/4, 0, 10, 0); bc->edelay=100; bc->idata=1; port->startc=bc->startc; port->startca=bc->startca; port->stopc=bc->stopc; port->stopca=bc->stopca; /*port->close_delay=50;*/ port->close_delay=3 * hz; port->do_timestamp=0; port->do_dcd_timestamp=0; /* * We don't use all the flags from <sys/ttydefaults.h> since they * are only relevant for logins. It's important to have echo off * initially so that the line doesn't start blathering before the * echo flag can be turned off. */ port->it_in.c_iflag = TTYDEF_IFLAG; port->it_in.c_oflag = TTYDEF_OFLAG; port->it_in.c_cflag = TTYDEF_CFLAG; port->it_in.c_lflag = TTYDEF_LFLAG; termioschars(&port->it_in); port->it_in.c_ispeed = port->it_in.c_ospeed = dgbdefaultrate; port->it_out = port->it_in;#ifdef DEVFS/*XXX*/ /* fix the minor numbers */ port->devfs_token.tty = devfs_add_devswf(&dgb_cdevsw, (unit*32)+i,/*mytical number*/ DV_CHR, 0, 0, 0600, "dgb%d.%d", unit, i); port->devfs_token.tty = devfs_add_devswf(&dgb_cdevsw, (unit*32)+i+64,/*mytical number*/ DV_CHR, 0, 0, 0600, "idgb%d.%d", unit, i); port->devfs_token.tty = devfs_add_devswf(&dgb_cdevsw, (unit*32)+i+128,/*mytical number*/ DV_CHR, 0, 0, 0600, "ldgb%d.%d", unit, i); port->devfs_token.tty = devfs_add_devswf(&dgb_cdevsw, (unit*32)+i+192,/*mytical number*/ DV_CHR, 0, 0, 0600, "dgbcua%d.%d", unit, i);#endif } hidewin(sc); /* register the polling function */ timeout(dgbpoll, (void *)unit, hz/POLLSPERSEC); return 1;}/* ARGSUSED */static intdgbopen(dev, flag, mode, p) dev_t dev; int flag; int mode; struct proc *p;{ struct dgb_softc *sc; struct tty *tp; int unit; int mynor; int pnum; struct dgb_p *port; int s,cs; int error; volatile struct board_chan *bc; error=0; mynor=minor(dev); unit=MINOR_TO_UNIT(mynor); pnum=MINOR_TO_PORT(mynor); if(unit >= NDGB) { DPRINT2(DB_EXCEPT,"dgb%d: try to open a nonexisting card\n",unit); return ENXIO; } sc=&dgb_softc[unit]; if(sc->status!=ENABLED) { DPRINT2(DB_EXCEPT,"dgb%d: try to open a disabled card\n",unit); return ENXIO; } if(pnum>=sc->numports) { DPRINT3(DB_EXCEPT,"dgb%d: try to open non-existing port %d\n",unit,pnum); return ENXIO; } if(mynor & CONTROL_MASK) return 0; tp=&sc->ttys[pnum]; port=&sc->ports[pnum]; bc=port->brdchan;open_top: s=spltty(); while(port->closing) { error=tsleep(&port->closing, TTOPRI|PCATCH, "dgocl", 0); if(error) { DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgocl) error=%d\n",unit,pnum,error); goto out; } } if (tp->t_state & TS_ISOPEN) { /* * The device is open, so everything has been initialized. * Handle conflicts. */ if (mynor & CALLOUT_MASK) { if (!port->active_out) { error = EBUSY; DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error); goto out; } } else { if (port->active_out) { if (flag & O_NONBLOCK) { error = EBUSY; DPRINT4(DB_OPEN,"dgb%d: port%d: BUSY error=%d\n",unit,pnum,error); goto out; } error = tsleep(&port->active_out, TTIPRI | PCATCH, "dgbi", 0); if (error != 0) { DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgbi) error=%d\n", unit,pnum,error); goto out; } splx(s); goto open_top; } } if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { error = EBUSY; goto out; } } else { /* * The device isn't open, so there are no conflicts. * Initialize it. Initialization is done twice in many * cases: to preempt sleeping callin opens if we are * callout, and to complete a callin open after DCD rises. */ tp->t_oproc=dgbstart; tp->t_param=dgbparam; tp->t_dev=dev; tp->t_termios= (mynor & CALLOUT_MASK) ? port->it_out : port->it_in; cs=splclock(); setwin(sc,0); port->imodem=bc->mstat; bc->rout=bc->rin; /* clear input queue */ bc->idata=1;#ifdef PRINT_BUFSIZE printf("dgb buffers tx=%x:%x rx=%x:%x\n",bc->tseg,bc->tmax,bc->rseg,bc->rmax);#endif hidewin(sc); splx(cs); port->wopeners++; error=dgbparam(tp, &tp->t_termios); port->wopeners--; if(error!=0) { DPRINT4(DB_OPEN,"dgb%d: port%d: dgbparam error=%d\n",unit,pnum,error); goto out; } ttsetwater(tp); /* handle fake DCD for callout devices */ /* and initial DCD */ if( (port->imodem & port->dcd) || mynor & CALLOUT_MASK ) linesw[tp->t_line].l_modem(tp,1); } /* * Wait for DCD if necessary. */ if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK) && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { ++port->wopeners; error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "dgdcd", 0); --port->wopeners; if (error != 0) { DPRINT4(DB_OPEN,"dgb%d: port%d: tsleep(dgdcd) error=%d\n",unit,pnum,error); goto out; } splx(s); goto open_top; } error = linesw[tp->t_line].l_open(dev, tp); disc_optim(tp,&tp->t_termios); DPRINT4(DB_OPEN,"dgb%d: port%d: l_open error=%d\n",unit,pnum,error); if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK) port->active_out = TRUE; port->used=1; /* If any port is open (i.e. the open() call is completed for it) * the device is busy */out: disc_optim(tp,&tp->t_termios); splx(s); if( !(tp->t_state & TS_ISOPEN) && port->wopeners==0 ) dgbhardclose(port); DPRINT4(DB_OPEN,"dgb%d: port%d: open() returns %d\n",unit,pnum,error); return error;}/*ARGSUSED*/static intdgbclose(dev, flag, mode, p) dev_t dev; int flag; int mode; struct proc *p;{ int mynor; struct tty *tp; int unit, pnum; struct dgb_softc *sc; struct dgb_p *port; int s; int i; mynor=minor(dev); if(mynor & CONTROL_MASK) return 0; unit=MINOR_TO_UNIT(mynor); pnum=MINOR_TO_PORT(mynor); sc=&dgb_softc[unit]; tp=&sc->ttys[pnum]; port=sc->ports+pnum; DPRINT3(DB_CLOSE,"dgb%d: port%d: closing\n",unit,pnum);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -