/* * close routine. returns zero if successful, else error code */ int mbppclose(dev_t dev, int flag, int mode, struct lwp *l) { struct mbpp_softc *ms = device_lookup_private(&mbpp_cd, MAGMA_CARD(dev)); struct mbpp_port *mp = &ms->ms_port[MAGMA_PORT(dev)]; mp->mp_flags = 0; return(0); }
/* * Poll routine */ int mttypoll(dev_t dev, int events, struct lwp *l) { struct mtty_softc *ms = device_lookup_private(&mtty_cd, MAGMA_CARD(dev)); struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(dev)]; struct tty *tp = mp->mp_tty; return ((*tp->t_linesw->l_poll)(tp, events, l)); }
/* * Write routine */ int mttywrite(dev_t dev, struct uio *uio, int flags) { struct mtty_softc *ms = device_lookup_private(&mtty_cd, MAGMA_CARD(dev)); struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(dev)]; struct tty *tp = mp->mp_tty; return( (*tp->t_linesw->l_write)(tp, uio, flags) ); }
/* * open routine. returns zero if successful, else error code */ int mbppopen(dev_t dev, int flags, int mode, struct lwp *l) { int card = MAGMA_CARD(dev); int port = MAGMA_PORT(dev); struct mbpp_softc *ms; struct mbpp_port *mp; int s; if ((ms = device_lookup_private(&mbpp_cd, card)) == NULL || port >= ms->ms_nports ) return(ENXIO); mp = &ms->ms_port[port]; s = spltty(); if( ISSET(mp->mp_flags, MBPPF_OPEN) ) { splx(s); return(EBUSY); } SET(mp->mp_flags, MBPPF_OPEN); splx(s); /* set defaults */ mp->mp_burst = MBPP_BURST; mp->mp_timeout = mbpp_mstohz(MBPP_TIMEOUT); mp->mp_delay = mbpp_mstohz(MBPP_DELAY); /* init chips */ if( mp->mp_cd1400 ) { /* CD1400 */ struct cd1400 *cd = mp->mp_cd1400; /* set up CD1400 channel */ s = spltty(); cd1400_write_reg(cd, CD1400_CAR, 0); cd1400_write_ccr(cd, CD1400_CCR_CMDRESET); cd1400_write_reg(cd, CD1400_LIVR, (1<<3)); splx(s); } else { /* CD1190 */ mp->mp_flags = 0; return (ENXIO); } return (0); }
/* * ioctl routine */ int mbppioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) { struct mbpp_softc *ms = device_lookup_private(&mbpp_cd, MAGMA_CARD(dev)); struct mbpp_port *mp = &ms->ms_port[MAGMA_PORT(dev)]; struct mbpp_param *bp; int error = 0; int s; switch(cmd) { case MBPPIOCSPARAM: bp = (struct mbpp_param *)data; if( bp->bp_burst < MBPP_BURST_MIN || bp->bp_burst > MBPP_BURST_MAX || bp->bp_delay < MBPP_DELAY_MIN || bp->bp_delay > MBPP_DELAY_MIN ) { error = EINVAL; } else { mp->mp_burst = bp->bp_burst; mp->mp_timeout = mbpp_mstohz(bp->bp_timeout); mp->mp_delay = mbpp_mstohz(bp->bp_delay); } break; case MBPPIOCGPARAM: bp = (struct mbpp_param *)data; bp->bp_burst = mp->mp_burst; bp->bp_timeout = mbpp_hztoms(mp->mp_timeout); bp->bp_delay = mbpp_hztoms(mp->mp_delay); break; case MBPPIOCGSTAT: /* XXX make this more generic */ s = spltty(); cd1400_write_reg(mp->mp_cd1400, CD1400_CAR, 0); *(int *)data = cd1400_read_reg(mp->mp_cd1400, CD1400_PSVR); splx(s); break; default: error = ENOTTY; } return(error); }
/* * ioctl routine */ int mbppioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) { struct mbpp_softc *ms = mbpp_cd.cd_devs[MAGMA_CARD(dev)]; struct mbpp_port *mp = &ms->ms_port[MAGMA_PORT(dev)]; struct bpp_param *bp; int error = 0; int s; switch(cmd) { case BPPIOCSPARAM: bp = (struct bpp_param *)data; if (bp->bp_burst < BPP_BURST_MIN || bp->bp_burst > BPP_BURST_MAX || bp->bp_delay < BPP_DELAY_MIN || bp->bp_delay > BPP_DELAY_MIN) { error = EINVAL; } else { mp->mp_burst = bp->bp_burst; mp->mp_timeout = mbpp_mstohz(bp->bp_timeout); mp->mp_delay = mbpp_mstohz(bp->bp_delay); } break; case BPPIOCGPARAM: bp = (struct bpp_param *)data; bp->bp_burst = mp->mp_burst; bp->bp_timeout = mbpp_hztoms(mp->mp_timeout); bp->bp_delay = mbpp_hztoms(mp->mp_delay); break; case BPPIOCGSTAT: /* XXX make this more generic */ s = spltty(); CD1400_WRITE_REG(mp->mp_cd1400, CD1400_CAR, 0); *(int *)data = CD1400_READ_REG(mp->mp_cd1400, CD1400_PSVR); splx(s); break; default: error = ENOTTY; } return (error); }
/* * Stop output, e.g., for ^S or output flush. */ int mttystop(struct tty *tp, int flags) { struct mtty_softc *ms = mtty_cd.cd_devs[MAGMA_CARD(tp->t_dev)]; struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(tp->t_dev)]; int s; s = spltty(); if (ISSET(tp->t_state, TS_BUSY)) { if (!ISSET(tp->t_state, TS_TTSTOP)) SET(tp->t_state, TS_FLUSH); /* * the transmit interrupt routine will disable transmit when it * notices that MTTYF_STOP has been set. */ SET(mp->mp_flags, MTTYF_STOP); } splx(s); return (0); }
/* * Start output, after a stop. */ void mtty_start(struct tty *tp) { struct mtty_softc *ms = device_lookup_private(&mtty_cd, MAGMA_CARD(tp->t_dev)); struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(tp->t_dev)]; int s; s = spltty(); /* we only need to do something if we are not already busy * or delaying or stopped */ if( !ISSET(tp->t_state, TS_TTSTOP | TS_TIMEOUT | TS_BUSY) ) { if (ttypull(tp)) { mp->mp_txc = ndqb(&tp->t_outq, 0); mp->mp_txp = tp->t_outq.c_cf; SET(tp->t_state, TS_BUSY); cd1400_enable_transmitter(mp->mp_cd1400, mp->mp_channel); } } splx(s); }
/* * ioctl routine */ int mttyioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) { struct mtty_softc *ms = mtty_cd.cd_devs[MAGMA_CARD(dev)]; struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(dev)]; struct tty *tp = mp->mp_tty; int error; error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flags, p); if (error >= 0) return (error); error = ttioctl(tp, cmd, data, flags, p); if (error >= 0) return (error); error = 0; switch(cmd) { case TIOCSBRK: /* set break */ SET(mp->mp_flags, MTTYF_SET_BREAK); cd1400_enable_transmitter(mp->mp_cd1400, mp->mp_channel); break; case TIOCCBRK: /* clear break */ SET(mp->mp_flags, MTTYF_CLR_BREAK); cd1400_enable_transmitter(mp->mp_cd1400, mp->mp_channel); break; case TIOCSDTR: /* set DTR */ mtty_modem_control(mp, TIOCM_DTR, DMBIS); break; case TIOCCDTR: /* clear DTR */ mtty_modem_control(mp, TIOCM_DTR, DMBIC); break; case TIOCMSET: /* set modem lines */ mtty_modem_control(mp, *((int *)data), DMSET); break; case TIOCMBIS: /* bit set modem lines */ mtty_modem_control(mp, *((int *)data), DMBIS); break; case TIOCMBIC: /* bit clear modem lines */ mtty_modem_control(mp, *((int *)data), DMBIC); break; case TIOCMGET: /* get modem lines */ *((int *)data) = mtty_modem_control(mp, 0, DMGET); break; case TIOCGFLAGS: *((int *)data) = mp->mp_openflags; break; case TIOCSFLAGS: if (suser(p, 0)) error = EPERM; else mp->mp_openflags = *((int *)data) & (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF); break; default: error = ENOTTY; } return (error); }
/* * open routine. returns zero if successful, else error code */ int mttyopen(dev_t dev, int flags, int mode, struct proc *p) { int card = MAGMA_CARD(dev); int port = MAGMA_PORT(dev); struct mtty_softc *ms; struct mtty_port *mp; struct tty *tp; struct cd1400 *cd; int s; if (card >= mtty_cd.cd_ndevs || (ms = mtty_cd.cd_devs[card]) == NULL || port >= ms->ms_nports) return (ENXIO); /* device not configured */ mp = &ms->ms_port[port]; tp = mp->mp_tty; tp->t_dev = dev; if (!ISSET(tp->t_state, TS_ISOPEN)) { SET(tp->t_state, TS_WOPEN); /* set defaults */ ttychars(tp); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_cflag = TTYDEF_CFLAG; if (ISSET(mp->mp_openflags, TIOCFLAG_CLOCAL)) SET(tp->t_cflag, CLOCAL); if (ISSET(mp->mp_openflags, TIOCFLAG_CRTSCTS)) SET(tp->t_cflag, CRTSCTS); if (ISSET(mp->mp_openflags, TIOCFLAG_MDMBUF)) SET(tp->t_cflag, MDMBUF); tp->t_lflag = TTYDEF_LFLAG; tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; /* init ring buffer */ mp->mp_rput = mp->mp_rget = mp->mp_rbuf; s = spltty(); /* reset CD1400 channel */ cd = mp->mp_cd1400; CD1400_WRITE_REG(cd, CD1400_CAR, mp->mp_channel); cd1400_write_ccr(cd, CD1400_CCR_CMDRESET); /* encode the port number in top half of LIVR */ CD1400_WRITE_REG(cd, CD1400_LIVR, port << 4); /* sets parameters and raises DTR */ (void)mtty_param(tp, &tp->t_termios); /* set tty watermarks */ ttsetwater(tp); /* enable service requests */ CD1400_WRITE_REG(cd, CD1400_SRER, CD1400_SRER_RXDATA | CD1400_SRER_MDMCH); /* tell the tty about the carrier status */ if (ISSET(mp->mp_openflags, TIOCFLAG_SOFTCAR) || mp->mp_carrier) SET(tp->t_state, TS_CARR_ON); else CLR(tp->t_state, TS_CARR_ON); } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p, 0) != 0) { return (EBUSY); /* superuser can break exclusive access */ } else { s = spltty(); } /* wait for carrier if necessary */ if (!ISSET(flags, O_NONBLOCK)) { while (!ISSET(tp->t_cflag, CLOCAL) && !ISSET(tp->t_state, TS_CARR_ON)) { int error; SET(tp->t_state, TS_WOPEN); error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, "mttydcd", 0); if (error != 0) { splx(s); CLR(tp->t_state, TS_WOPEN); return (error); } } } splx(s); return ((*linesw[tp->t_line].l_open)(dev, tp, p)); }
int mbpp_rw(dev_t dev, struct uio *uio) { int card = MAGMA_CARD(dev); int port = MAGMA_PORT(dev); struct mbpp_softc *ms = mbpp_cd.cd_devs[card]; struct mbpp_port *mp = &ms->ms_port[port]; caddr_t buffer, ptr; int buflen, cnt, len; int s, error = 0; int gotdata = 0; if (uio->uio_resid == 0) return (0); buflen = min(uio->uio_resid, mp->mp_burst); buffer = malloc(buflen, M_DEVBUF, M_WAITOK); SET(mp->mp_flags, MBPPF_UIO); /* * start timeout, if needed */ if (mp->mp_timeout > 0) { SET(mp->mp_flags, MBPPF_TIMEOUT); timeout_add(&mp->mp_timeout_tmo, mp->mp_timeout); } len = cnt = 0; while (uio->uio_resid > 0) { len = min(buflen, uio->uio_resid); ptr = buffer; if (uio->uio_rw == UIO_WRITE) { error = uiomove(ptr, len, uio); if (error) break; } again: /* goto bad */ /* timed out? */ if (!ISSET(mp->mp_flags, MBPPF_UIO)) break; /* * perform the operation */ if (uio->uio_rw == UIO_WRITE) { cnt = mbpp_send(mp, ptr, len); } else { cnt = mbpp_recv(mp, ptr, len); } if (uio->uio_rw == UIO_READ) { if (cnt) { error = uiomove(ptr, cnt, uio); if (error) break; gotdata++; } else if (gotdata) /* consider us done */ break; } /* timed out? */ if (!ISSET(mp->mp_flags, MBPPF_UIO)) break; /* * poll delay? */ if (mp->mp_delay > 0) { s = spltty(); /* XXX */ SET(mp->mp_flags, MBPPF_DELAY); timeout_add(&mp->mp_start_tmo, mp->mp_delay); error = tsleep(mp, PCATCH | PZERO, "mbppdelay", 0); splx(s); if (error) break; } /* * don't call uiomove again until we used all the data we grabbed */ if (uio->uio_rw == UIO_WRITE && cnt != len) { ptr += cnt; len -= cnt; cnt = 0; goto again; } } /* * clear timeouts */ s = spltty(); /* XXX */ if (ISSET(mp->mp_flags, MBPPF_TIMEOUT)) { timeout_del(&mp->mp_timeout_tmo); CLR(mp->mp_flags, MBPPF_TIMEOUT); } if (ISSET(mp->mp_flags, MBPPF_DELAY)) { timeout_del(&mp->mp_start_tmo); CLR(mp->mp_flags, MBPPF_DELAY); } splx(s); /* * adjust for those chars that we uiomoved but never actually wrote */ if (uio->uio_rw == UIO_WRITE && cnt != len) { uio->uio_resid += (len - cnt); } free(buffer, M_DEVBUF); return (error); }
/* * Set tty parameters, returns error or 0 on success */ int mtty_param(struct tty *tp, struct termios *t) { struct mtty_softc *ms = mtty_cd.cd_devs[MAGMA_CARD(tp->t_dev)]; struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(tp->t_dev)]; struct cd1400 *cd = mp->mp_cd1400; int rbpr, tbpr, rcor, tcor; u_char mcor1 = 0, mcor2 = 0; int s, opt; if (t->c_ospeed && cd1400_compute_baud(t->c_ospeed, cd->cd_clock, &tcor, &tbpr)) return (EINVAL); if (t->c_ispeed && cd1400_compute_baud(t->c_ispeed, cd->cd_clock, &rcor, &rbpr)) return (EINVAL); s = spltty(); /* hang up the line if ospeed is zero, else raise DTR */ (void)mtty_modem_control(mp, TIOCM_DTR, (t->c_ospeed == 0 ? DMBIC : DMBIS)); /* select channel, done in mtty_modem_control() */ /* CD1400_WRITE_REG(cd, CD1400_CAR, mp->mp_channel); */ /* set transmit speed */ if (t->c_ospeed) { CD1400_WRITE_REG(cd, CD1400_TCOR, tcor); CD1400_WRITE_REG(cd, CD1400_TBPR, tbpr); } /* set receive speed */ if (t->c_ispeed) { CD1400_WRITE_REG(cd, CD1400_RCOR, rcor); CD1400_WRITE_REG(cd, CD1400_RBPR, rbpr); } /* enable transmitting and receiving on this channel */ opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN | CD1400_CCR_RCVEN; cd1400_write_ccr(cd, opt); /* set parity, data and stop bits */ opt = 0; if (ISSET(t->c_cflag, PARENB)) opt |= (ISSET(t->c_cflag, PARODD) ? CD1400_COR1_PARODD : CD1400_COR1_PARNORMAL); if (!ISSET(t->c_iflag, INPCK)) opt |= CD1400_COR1_NOINPCK; /* no parity checking */ if (ISSET(t->c_cflag, CSTOPB)) opt |= CD1400_COR1_STOP2; switch( t->c_cflag & CSIZE) { case CS5: opt |= CD1400_COR1_CS5; break; case CS6: opt |= CD1400_COR1_CS6; break; case CS7: opt |= CD1400_COR1_CS7; break; default: opt |= CD1400_COR1_CS8; break; } CD1400_WRITE_REG(cd, CD1400_COR1, opt); /* * enable Embedded Transmit Commands (for breaks) * use the CD1400 automatic CTS flow control if CRTSCTS is set */ opt = CD1400_COR2_ETC; if (ISSET(t->c_cflag, CRTSCTS)) opt |= CD1400_COR2_CCTS_OFLOW; CD1400_WRITE_REG(cd, CD1400_COR2, opt); CD1400_WRITE_REG(cd, CD1400_COR3, MTTY_RX_FIFO_THRESHOLD); cd1400_write_ccr(cd, CD1400_CCR_CMDCORCHG | CD1400_CCR_COR1 | CD1400_CCR_COR2 | CD1400_CCR_COR3); CD1400_WRITE_REG(cd, CD1400_COR4, CD1400_COR4_PFO_EXCEPTION); CD1400_WRITE_REG(cd, CD1400_COR5, 0); /* * if automatic RTS handshaking enabled, set DTR threshold * (RTS and DTR lines are switched, CD1400 thinks its DTR) */ if (ISSET(t->c_cflag, CRTSCTS)) mcor1 = MTTY_RX_DTR_THRESHOLD; /* set up `carrier detect' interrupts */ if (cd->cd_parmode) { SET(mcor1, CD1400_MCOR1_DSRzd); SET(mcor2, CD1400_MCOR2_DSRod); } else { SET(mcor1, CD1400_MCOR1_CDzd); SET(mcor2, CD1400_MCOR2_CDod); } CD1400_WRITE_REG(cd, CD1400_MCOR1, mcor1); CD1400_WRITE_REG(cd, CD1400_MCOR2, mcor2); /* receive timeout 2ms */ CD1400_WRITE_REG(cd, CD1400_RTPR, 2); splx(s); return (0); }
/* * open routine. returns zero if successful, else error code */ int mttyopen(dev_t dev, int flags, int mode, struct lwp *l) { int card = MAGMA_CARD(dev); int port = MAGMA_PORT(dev); struct mtty_softc *ms; struct mtty_port *mp; struct tty *tp; struct cd1400 *cd; int error, s; if ((ms = device_lookup_private(&mtty_cd, card)) == NULL || port >= ms->ms_nports ) return(ENXIO); /* device not configured */ mp = &ms->ms_port[port]; tp = mp->mp_tty; tp->t_dev = dev; if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) return (EBUSY); s = spltty(); if( !ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { /* set defaults */ ttychars(tp); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_cflag = TTYDEF_CFLAG; if( ISSET(mp->mp_openflags, TIOCFLAG_CLOCAL) ) SET(tp->t_cflag, CLOCAL); if( ISSET(mp->mp_openflags, TIOCFLAG_CRTSCTS) ) SET(tp->t_cflag, CRTSCTS); if( ISSET(mp->mp_openflags, TIOCFLAG_MDMBUF) ) SET(tp->t_cflag, MDMBUF); tp->t_lflag = TTYDEF_LFLAG; tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; /* init ring buffer */ mp->mp_rput = mp->mp_rget = mp->mp_rbuf; /* reset CD1400 channel */ cd = mp->mp_cd1400; cd1400_write_reg(cd, CD1400_CAR, mp->mp_channel); cd1400_write_ccr(cd, CD1400_CCR_CMDRESET); /* encode the port number in top half of LIVR */ cd1400_write_reg(cd, CD1400_LIVR, port << 4 ); /* sets parameters and raises DTR */ (void)mtty_param(tp, &tp->t_termios); /* set tty watermarks */ ttsetwater(tp); /* enable service requests */ cd1400_write_reg(cd, CD1400_SRER, CD1400_SRER_RXDATA | CD1400_SRER_MDMCH); /* tell the tty about the carrier status */ if( ISSET(mp->mp_openflags, TIOCFLAG_SOFTCAR) || mp->mp_carrier ) SET(tp->t_state, TS_CARR_ON); else CLR(tp->t_state, TS_CARR_ON); } splx(s); error = ttyopen(tp, MTTY_DIALOUT(dev), ISSET(flags, O_NONBLOCK)); if (error != 0) goto bad; error = (*tp->t_linesw->l_open)(dev, tp); if (error != 0) goto bad; bad: if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { /* * We failed to open the device, and nobody else had it opened. * Clean up the state as appropriate. */ /* XXX - do that here */ } return (error); }
/* * ioctl routine */ int mttyioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) { struct mtty_softc *ms = device_lookup_private(&mtty_cd, MAGMA_CARD(dev)); struct mtty_port *mp = &ms->ms_port[MAGMA_PORT(dev)]; struct tty *tp = mp->mp_tty; int error; error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flags, l); if( error != EPASSTHROUGH ) return(error); error = ttioctl(tp, cmd, data, flags, l); if( error != EPASSTHROUGH ) return(error); error = 0; switch(cmd) { case TIOCSBRK: /* set break */ SET(mp->mp_flags, MTTYF_SET_BREAK); cd1400_enable_transmitter(mp->mp_cd1400, mp->mp_channel); break; case TIOCCBRK: /* clear break */ SET(mp->mp_flags, MTTYF_CLR_BREAK); cd1400_enable_transmitter(mp->mp_cd1400, mp->mp_channel); break; case TIOCSDTR: /* set DTR */ mtty_modem_control(mp, TIOCM_DTR, DMBIS); break; case TIOCCDTR: /* clear DTR */ mtty_modem_control(mp, TIOCM_DTR, DMBIC); break; case TIOCMSET: /* set modem lines */ mtty_modem_control(mp, *((int *)data), DMSET); break; case TIOCMBIS: /* bit set modem lines */ mtty_modem_control(mp, *((int *)data), DMBIS); break; case TIOCMBIC: /* bit clear modem lines */ mtty_modem_control(mp, *((int *)data), DMBIC); break; case TIOCMGET: /* get modem lines */ *((int *)data) = mtty_modem_control(mp, 0, DMGET); break; case TIOCGFLAGS: *((int *)data) = mp->mp_openflags; break; case TIOCSFLAGS: if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_PRIVSET, tp)) error = EPERM; else mp->mp_openflags = *((int *)data) & (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF); break; default: error = EPASSTHROUGH; } return(error); }