📄 si.c
字号:
} sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport, M_DEVBUF, M_NOWAIT); if (sc->sc_ports == 0) {mem_fail: printf("si%d: fail to malloc memory for port structs\n", unit); return 0; } bzero(sc->sc_ports, sizeof(struct si_port) * nport); sc->sc_nport = nport; /* * allocate tty structures for ports */ tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT); if (tp == 0) goto mem_fail; bzero(tp, sizeof(*tp) * nport); si_tty = tp; /* mark the device state as attached */ si_kdc[unit].kdc_state = DC_BUSY; /* * Scan round the ports again, this time initialising. */ pp = sc->sc_ports; nmodule = 0; modp = (struct si_module *)(maddr + 0x80); uart_type = 0; for (;;) { switch (modp->sm_type & (~MMASK)) { case M232: case M422: nmodule++; nport = (modp->sm_type & MMASK); ccbp = (struct si_channel *)((char *)modp+0x100); if (uart_type == 0) uart_type = ccbp->type; for (x = 0; x < nport; x++, pp++, ccbp++) { pp->sp_ccb = ccbp; /* save the address */ pp->sp_tty = tp++; pp->sp_pend = IDLE_CLOSE; pp->sp_state = 0; /* internal flag */ pp->sp_dtr_wait = 3 * hz; pp->sp_iin.c_iflag = si_default_iflag; pp->sp_iin.c_oflag = si_default_oflag; pp->sp_iin.c_cflag = si_default_cflag; pp->sp_iin.c_lflag = si_default_lflag; termioschars(&pp->sp_iin); pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed = si_default_rate; pp->sp_iout = pp->sp_iin; } break; default: break; } if (modp->sm_next == 0) { printf("si%d: card: %s, ports: %d, modules: %d (type: %d)\n", unit, sc->sc_typename, sc->sc_nport, nmodule, uart_type); break; } modp = (struct si_module *) (maddr + (unsigned)(modp->sm_next & 0x7fff)); } if (done_chartimes == 0) { for (spt = chartimes ; spt->sp_speed != -1; spt++) { if ((spt->sp_code /= hz) == 0) spt->sp_code = 1; } done_chartimes = 1; } return (1);}struct isa_driver sidriver = { siprobe, siattach, "si" };intsiopen(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p;{ int oldspl, error; int card, port; register struct si_softc *sc; register struct tty *tp; volatile struct si_channel *ccbp; struct si_port *pp; int mynor = minor(dev); /* quickly let in /dev/si_control */ if (IS_CONTROLDEV(mynor)) { if (error = suser(p->p_ucred, &p->p_acflag)) return(error); return(0); } card = SI_CARD(mynor); if (card >= NSI) return (ENXIO); sc = &si_softc[card]; if (sc->sc_type == SIEMPTY) { DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n", card, sc->sc_typename)); return(ENXIO); } port = SI_PORT(mynor); if (port >= sc->sc_nport) { DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n", card, sc->sc_nport)); return(ENXIO); }#ifdef POLL /* * We've now got a device, so start the poller. */ if (init_finished == 0) { timeout(si_poll, (caddr_t)0L, POLL_INTERVAL); init_finished = 1; }#endif /* initial/lock device */ if (IS_STATE(mynor)) { return(0); } pp = sc->sc_ports + port; tp = pp->sp_tty; /* the "real" tty */ ccbp = pp->sp_ccb; /* Find control block */ DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n", dev, flag, mode, p)); oldspl = spltty(); /* Keep others out */ error = 0;open_top: while (pp->sp_state & SS_DTR_OFF) { error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0); if (error != 0) goto out; } if (tp->t_state & TS_ISOPEN) { /* * The device is open, so everything has been initialised. * handle conflicts. */ if (IS_CALLOUT(mynor)) { if (!pp->sp_active_out) { error = EBUSY; goto out; } } else { if (pp->sp_active_out) { if (flag & O_NONBLOCK) { error = EBUSY; goto out; } error = tsleep(&pp->sp_active_out, TTIPRI|PCATCH, "sibi", 0); if (error != 0) goto out; goto open_top; } } if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { DPRINT((pp, DBG_OPEN|DBG_FAIL, "already open and EXCLUSIVE set\n")); error = EBUSY; goto out; } } else { /* * The device isn't open, so there are no conflicts. * Initialize it. Avoid sleep... :-) */ DPRINT((pp, DBG_OPEN, "first open\n")); tp->t_oproc = si_start; tp->t_param = siparam; tp->t_dev = dev; tp->t_termios = mynor & SI_CALLOUT_MASK ? pp->sp_iout : pp->sp_iin; (void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS); ++pp->sp_wopeners; /* in case of sleep in siparam */ error = siparam(tp, &tp->t_termios); --pp->sp_wopeners; if (error != 0) goto out; /* XXX: we should goto_top if siparam slept */ ttsetwater(tp); /* set initial DCD state */ pp->sp_last_hi_ip = ccbp->hi_ip; if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) { (*linesw[tp->t_line].l_modem)(tp, 1); } } /* whoops! we beat the close! */ if (pp->sp_state & SS_CLOSING) { /* try and stop it from proceeding to bash the hardware */ pp->sp_state &= ~SS_CLOSING; } /* * Wait for DCD if necessary */ if (!(tp->t_state & TS_CARR_ON) && !IS_CALLOUT(mynor) && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { ++pp->sp_wopeners; DPRINT((pp, DBG_OPEN, "sleeping for carrier\n")); error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0); --pp->sp_wopeners; if (error != 0) goto out; goto open_top; } error = (*linesw[tp->t_line].l_open)(dev, tp); si_disc_optim(tp, &tp->t_termios, pp); if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor)) pp->sp_active_out = TRUE; pp->sp_state |= SS_OPEN; /* made it! */out: splx(oldspl); DPRINT((pp, DBG_OPEN, "leaving siopen\n")); if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0) sihardclose(pp); return(error);}intsiclose(dev, flag, mode, p) dev_t dev; int flag, mode; struct proc *p;{ register struct si_port *pp; register struct tty *tp; int oldspl; int error = 0; int mynor = minor(dev); if (IS_SPECIAL(mynor)) return(0); oldspl = spltty(); pp = MINOR2PP(mynor); tp = pp->sp_tty; DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n", dev, flag, mode, p, pp->sp_state)); /* did we sleep and loose a race? */ if (pp->sp_state & SS_CLOSING) { /* error = ESOMETING? */ goto out; } /* begin race detection.. */ pp->sp_state |= SS_CLOSING; si_write_enable(pp, 0); /* block writes for ttywait() */ /* THIS MAY SLEEP IN TTYWAIT!!! */ (*linesw[tp->t_line].l_close)(tp, flag); si_write_enable(pp, 1); /* did we sleep and somebody started another open? */ if (!(pp->sp_state & SS_CLOSING)) { /* error = ESOMETING? */ goto out; } /* ok. we are now still on the right track.. nuke the hardware */ if (pp->sp_state & SS_LSTART) { untimeout((timeout_func_t)si_lstart, (caddr_t)pp); pp->sp_state &= ~SS_LSTART; } sistop(tp, FREAD | FWRITE); sihardclose(pp); ttyclose(tp); pp->sp_state &= ~SS_OPEN;out: DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n")); splx(oldspl); return(error);}static voidsihardclose(pp) struct si_port *pp;{ int oldspl; struct tty *tp; volatile struct si_channel *ccbp; oldspl = spltty(); tp = pp->sp_tty; ccbp = pp->sp_ccb; /* Find control block */ if (tp->t_cflag & HUPCL || !pp->sp_active_out && !(ccbp->hi_ip & IP_DCD) && !(pp->sp_iin.c_cflag && CLOCAL) || !(tp->t_state & TS_ISOPEN)) { (void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS); (void) si_command(pp, FCLOSE, SI_NOWAIT); if (pp->sp_dtr_wait != 0) { timeout(sidtrwakeup, pp, pp->sp_dtr_wait); pp->sp_state |= SS_DTR_OFF; } } pp->sp_active_out = FALSE; wakeup((caddr_t)&pp->sp_active_out); wakeup(TSA_CARR_ON(tp)); splx(oldspl);}/* * called at splsoftclock()... */static voidsidtrwakeup(chan) void *chan;{ struct si_port *pp; int oldspl; oldspl = spltty(); pp = (struct si_port *)chan; pp->sp_state &= ~SS_DTR_OFF; wakeup(&pp->sp_dtr_wait); splx(oldspl);}/* * User level stuff - read and write */intsiread(dev, uio, flag) register dev_t dev; struct uio *uio; int flag;{ register struct tty *tp; int mynor = minor(dev); if (IS_SPECIAL(mynor)) { DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n")); return(ENODEV); } tp = MINOR2TP(mynor); DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ, "siread(%x,%x,%x)\n", dev, uio, flag)); return ((*linesw[tp->t_line].l_read)(tp, uio, flag));}intsiwrite(dev, uio, flag) dev_t dev; struct uio *uio; int flag;{ register struct si_port *pp; register struct tty *tp; int error = 0; int mynor = minor(dev); int oldspl; if (IS_SPECIAL(mynor)) { DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n")); return(ENODEV); } pp = MINOR2PP(mynor); tp = pp->sp_tty; DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag)); oldspl = spltty(); /* * If writes are currently blocked, wait on the "real" tty */ while (pp->sp_state & SS_BLOCKWRITE) { pp->sp_state |= SS_WAITWRITE; DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n")); if (error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH, "siwrite", 0)) goto out; } error = (*linesw[tp->t_line].l_write)(tp, uio, flag);out: splx(oldspl); return (error);}struct tty *sidevtotty(dev_t dev){ struct si_port *pp; int mynor = minor(dev); struct si_softc *sc = &si_softc[SI_CARD(mynor)]; if (IS_SPECIAL(mynor)) return(NULL); if (SI_PORT(mynor) >= sc->sc_nport) return(NULL); pp = MINOR2PP(mynor); return (pp->sp_tty);}intsiioctl(dev, cmd, data, flag, p) dev_t dev; int cmd; caddr_t data; int flag; struct proc *p;{ struct si_port *pp; register struct tty *tp; int error; int mynor = minor(dev); int oldspl; int blocked = 0;#if defined(COMPAT_43) int oldcmd; struct termios term;#endif if (IS_SI_IOCTL(cmd)) return(si_Sioctl(dev, cmd, data, flag, p)); pp = MINOR2PP(mynor); tp = pp->sp_tty; DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%x,%x,%x)\n", dev, cmd, data, flag)); if (IS_STATE(mynor)) { struct termios *ct; switch (mynor & SI_STATE_MASK) { case SI_INIT_STATE_MASK: ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin; break; case SI_LOCK_STATE_MASK: ct = IS_CALLOUT(mynor) ? &pp->sp_lout : &pp->sp_lin; break; default: return (ENODEV); } switch (cmd) { case TIOCSETA: error = suser(p->p_ucred, &p->p_acflag); if (error != 0) return (error); *ct = *(struct termios *)data; return (0); case TIOCGETA: *(struct termios *)data = *ct; return (0); case TIOCGETD: *(int *)data = TTYDISC; return (0); case TIOCGWINSZ: bzero(data, sizeof(struct winsize)); return (0); default: return (ENOTTY); } } /* * Do the old-style ioctl compat routines... */#if defined(COMPAT_43) term = tp->t_termios; oldcmd = cmd; error = ttsetcompat(tp, &cmd, data, &term); if (error != 0) return (error); if (cmd != oldcmd) data = (caddr_t)&term;#endif /* * Do the initial / lock state business */ if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { int cc; struct termios *dt = (struct termios *)data; struct termios *lt = mynor & SI_CALLOUT_MASK ? &pp->sp_lout : &pp->sp_lin; dt->c_iflag = (tp->t_iflag & lt->c_iflag) | (dt->c_iflag & ~lt->c_iflag); dt->c_oflag = (tp->t_oflag & lt->c_oflag) | (dt->c_oflag & ~lt->c_oflag); dt->c_cflag = (tp->t_cflag & lt->c_cflag) | (dt->c_cflag & ~lt->c_cflag); dt->c_lflag = (tp->t_lflag & lt->c_lflag) | (dt->c_lflag & ~lt->c_lflag); for (cc = 0; cc < NCCS; ++cc) if (lt->c_cc[cc] != 0) dt->c_cc[cc] = tp->t_cc[cc]; if (lt->c_ispeed != 0) dt->c_ispeed = tp->t_ispeed; if (lt->c_ospeed != 0) dt->c_ospeed = tp->t_ospeed; } /* * Block user-level writes to give the ttywait() * a chance to completely drain for commands * that require the port to be in a quiescent state. */ switch (cmd) { case TIOCSETAW: case TIOCSETAF: case TIOCDRAIN: case TIOCSETP: blocked++; /* block writes for ttywait() and siparam() */ si_write_enable(pp, 0); } error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); if (error >= 0) goto out; oldspl = spltty(); error = ttioctl(tp, cmd, data, flag); si_disc_optim(tp, &tp->t_termios, pp); if (error >= 0) goto outspl; switch (cmd) { case TIOCSBRK: si_command(pp, SBREAK, SI_WAIT); break; case TIOCCBRK: si_command(pp, EBREAK, SI_WAIT); break; case TIOCSDTR:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -