示例#1
0
int
mbpp_recv(struct mbpp_port *mp, caddr_t ptr, int len)
{
    int s;
    struct cd1400 *cd = mp->mp_cd1400;

    /* set up io information */
    mp->mp_ptr = ptr;
    mp->mp_cnt = len;

    /* start receiving */
    s = spltty();
    if (cd) {
        int rcor, rbpr;

        CD1400_WRITE_REG(cd, CD1400_CAR, 0);

        /* input strobe at 100kbaud (10microseconds) */
        cd1400_compute_baud(100000, cd->cd_clock, &rcor, &rbpr);
        CD1400_WRITE_REG(cd, CD1400_RCOR, rcor);
        CD1400_WRITE_REG(cd, CD1400_RBPR, rbpr);

        /* rx threshold */
        CD1400_WRITE_REG(cd, CD1400_COR3, MBPP_RX_FIFO_THRESHOLD);
        cd1400_write_ccr(cd, CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3);

        /* enable channel */
        cd1400_write_ccr(cd, CD1400_CCR_CMDCHANCTL | CD1400_CCR_RCVEN);
        CD1400_WRITE_REG(cd, CD1400_SRER, CD1400_SRER_RXDATA);
    }

    /* ZZzzz... */
    tsleep(mp, PCATCH | PZERO, "mbpp_recv", 0);

    /* stop receiving */
    if (cd) {
        CD1400_WRITE_REG(cd, CD1400_CAR, 0);

        /* disable receiving */
        CD1400_WRITE_REG(cd, CD1400_SRER, 0);
        cd1400_write_ccr(cd, CD1400_CCR_CMDCHANCTL | CD1400_CCR_RCVDIS);
    }
    splx(s);

    /* return number of chars received */
    return (len - mp->mp_cnt);
}
示例#2
0
int
mbpp_send(struct mbpp_port *mp, caddr_t ptr, int len)
{
    int s;
    struct cd1400 *cd = mp->mp_cd1400;

    /* set up io information */
    mp->mp_ptr = ptr;
    mp->mp_cnt = len;

    /* start transmitting */
    s = spltty();
    if (cd) {
        CD1400_WRITE_REG(cd, CD1400_CAR, 0);

        /* output strobe width ~1microsecond */
        CD1400_WRITE_REG(cd, CD1400_TBPR, 10);

        /* enable channel */
        cd1400_write_ccr(cd, CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN);
        CD1400_WRITE_REG(cd, CD1400_SRER, CD1400_SRER_TXRDY);
    }

    /* ZZzzz... */
    tsleep(mp, PCATCH | PZERO, "mbpp_send", 0);

    /* stop transmitting */
    if (cd) {
        CD1400_WRITE_REG(cd, CD1400_CAR, 0);

        /* disable transmitter */
        CD1400_WRITE_REG(cd, CD1400_SRER, 0);
        cd1400_write_ccr(cd, CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTDIS);

        /* flush fifo */
        cd1400_write_ccr(cd, CD1400_CCR_CMDRESET | CD1400_CCR_FTF);
    }
    splx(s);

    /* return number of chars sent */
    return (len - mp->mp_cnt);
}
示例#3
0
/*
 * 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);
}
示例#4
0
/*
 * 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));
}
示例#5
0
void
magma_attach(struct device *parent, struct device *dev, void *aux)
{
    struct sbus_attach_args *sa = aux;
    struct magma_softc *sc = (struct magma_softc *)dev;
    const struct magma_board_info *card;
    char magma_prom[40], *clockstr;
    int chip, cd_clock;

    getpropstringA(sa->sa_node, "magma_prom", magma_prom);
    for (card = supported_cards; card->mb_name != NULL; card++) {
        if (strcmp(sa->sa_name, card->mb_sbusname) != 0)
            continue;
        if (strcmp(magma_prom, card->mb_name) == 0)
            break;
    }
    if (card->mb_name == NULL) {
        printf(": %s (unsupported)\n", magma_prom);
        return;
    }

    sc->sc_bustag = sa->sa_bustag;

    clockstr = getpropstring(sa->sa_node, "clock");
    if (strlen(clockstr) == 0)
        cd_clock = 25;
    else {
        cd_clock = 0;
        while (*clockstr != '\0')
            cd_clock = cd_clock * 10 + *clockstr++ - '0';
    }

    if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
                     sa->sa_reg[0].sbr_offset, sa->sa_reg[0].sbr_size,
                     0, 0, &sc->sc_iohandle) != 0) {
        printf(": can't map registers\n");
        return;
    }

    if (sa->sa_nintr < 1) {
        printf(": can't find interrupt\n");
        return;
    }
    sc->sc_ih = bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_TTY, 0,
                                   magma_hard, sc, dev->dv_xname);
    if (sc->sc_ih == NULL) {
        printf(": couldn't establish interrupt, pri %d\n",
               INTLEV(sa->sa_pri));
        bus_space_unmap(sc->sc_bustag, sc->sc_iohandle,
                        sa->sa_reg[0].sbr_size);
        return;
    }

    sc->sc_sih = softintr_establish(IPL_TTY, magma_soft, sc);
    if (sc->sc_sih == NULL) {
        printf(": can't get soft intr\n");
        bus_space_unmap(sc->sc_bustag, sc->sc_iohandle,
                        sa->sa_reg[0].sbr_size);
        return;
    }

    printf(": %s\n", card->mb_realname);

    sc->ms_board = card;
    sc->ms_ncd1400 = card->mb_ncd1400;
    sc->ms_ncd1190 = card->mb_ncd1190;

    /* the SVCACK* lines are daisychained */
    if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle,
                            card->mb_svcackr, 1, &sc->sc_svcackrh)) {
        printf(": failed to map svcackr\n");
        return;
    }
    if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle,
                            card->mb_svcackt, 1, &sc->sc_svcackth)) {
        printf(": failed to map svcackt\n");
        return;
    }
    if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle,
                            card->mb_svcackm, 1, &sc->sc_svcackmh)) {
        printf(": failed to map svcackm\n");
        return;
    }

    /* init the cd1400 chips */
    for (chip = 0 ; chip < card->mb_ncd1400 ; chip++) {
        struct cd1400 *cd = &sc->ms_cd1400[chip];

        cd->cd_clock = cd_clock;

        if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle,
                                card->mb_cd1400[chip], CD1400_REGMAPSIZE, &cd->cd_regh)) {
            printf(": failed to map cd1400 regs\n");
            return;
        }
        cd->cd_regt = sc->sc_bustag;

        /* getpropstring(sa->sa_node, "chiprev"); */
        /* seemingly the Magma drivers just ignore the propstring */
        cd->cd_chiprev = CD1400_READ_REG(cd, CD1400_GFRCR);

        dprintf(("%s attach CD1400 %d addr 0x%x rev %x clock %dMHz\n",
                 sc->ms_dev.dv_xname, chip, cd->cd_reg,
                 cd->cd_chiprev, cd->cd_clock));

        /* clear GFRCR */
        CD1400_WRITE_REG(cd, CD1400_GFRCR, 0x00);

        /* reset whole chip */
        cd1400_write_ccr(cd,
                         CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);

        /* wait for revision code to be restored */
        while (CD1400_READ_REG(cd, CD1400_GFRCR) != cd->cd_chiprev)
            ;

        /* set the Prescaler Period Register to tick at 1ms */
        CD1400_WRITE_REG(cd, CD1400_PPR,
                         ((cd->cd_clock * 1000000 / CD1400_PPR_PRESCALER + 500)
                          / 1000));

        /*
         * The LC2+1Sp card is the only card that doesn't have a
         * CD1190 for the parallel port, but uses channel 0 of the
         * CD1400, so we make a note of it for later and set up the
         * CD1400 for parallel mode operation.
         */
        if (card->mb_npar && card->mb_ncd1190 == 0) {
            CD1400_WRITE_REG(cd, CD1400_GCR, CD1400_GCR_PARALLEL);
            cd->cd_parmode = 1;
        }
    }

    /* init the cd1190 chips */
    for (chip = 0 ; chip < card->mb_ncd1190 ; chip++) {
        struct cd1190 *cd = &sc->ms_cd1190[chip];

        if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle,
                                card->mb_cd1190[chip], CD1190_REGMAPSIZE, &cd->cd_regh)) {
            printf(": failed to map cd1190 regs\n");
            return;
        }
        cd->cd_regt = sc->sc_bustag;
        dprintf(("%s attach CD1190 %d addr 0x%x (failed)\n",
                 sc->ms_dev.dv_xname, chip, cd->cd_reg));
        /* XXX don't know anything about these chips yet */
    }

    /* configure the children */
    (void)config_found(dev, mtty_match, NULL);
    (void)config_found(dev, mbpp_match, NULL);
}
示例#6
0
/*
 * 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);
}
示例#7
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);
}
示例#8
0
void
magma_attach(device_t parent, device_t self, void *aux)
{
	struct sbus_attach_args *sa = aux;
	struct magma_softc *sc = device_private(self);
	struct magma_board_info *card;
	bus_space_handle_t bh;
	char *magma_prom, *clockstr;
	int cd_clock;
	int node, chip;

	sc->ms_dev = self;
	node = sa->sa_node;

	/*
	 * Find the card model.
	 * Older models all have sbus node name `MAGMA_Sp' (see
	 * `supported_cards[]' above), and must be distinguished
	 * by the `magma_prom' property.
	 */
	magma_prom = prom_getpropstring(node, "magma_prom");

	for (card = supported_cards; card->mb_name != NULL; card++) {
		if (strcmp(sa->sa_name, card->mb_sbusname) != 0)
			/* Sbus node name doesn't match */
			continue;
		if (strcmp(magma_prom, card->mb_name) == 0)
			/* Model name match */
			break;
	}

	if( card->mb_name == NULL ) {
		printf(": %s (unsupported)\n", magma_prom);
		return;
	}

	dprintf((" addr %p", sc));
	printf(": %s\n", card->mb_realname);

	sc->ms_board = card;
	sc->ms_ncd1400 = card->mb_ncd1400;
	sc->ms_ncd1190 = card->mb_ncd1190;

	if (sbus_bus_map(sa->sa_bustag,
			 sa->sa_slot, sa->sa_offset, sa->sa_size,
			 BUS_SPACE_MAP_LINEAR, &bh) != 0) {
		aprint_error("%s @ sbus: cannot map registers\n",
			device_xname(self));
		return;
	}

	/* the SVCACK* lines are daisychained */
	sc->ms_svcackr = (char *)bus_space_vaddr(sa->sa_bustag, bh)
		+ card->mb_svcackr;
	sc->ms_svcackt = (char *)bus_space_vaddr(sa->sa_bustag, bh)
		+ card->mb_svcackt;
	sc->ms_svcackm = (char *)bus_space_vaddr(sa->sa_bustag, bh)
		+ card->mb_svcackm;

	/*
	 * Find the clock speed; it's the same for all CD1400 chips
	 * on the board.
	 */
	clockstr = prom_getpropstring(node, "clock");
	if (*clockstr == '\0')
		/* Default to 25MHz */
		cd_clock = 25;
	else {
		cd_clock = 0;
		while (*clockstr != '\0')
			cd_clock = (cd_clock * 10) + (*clockstr++ - '0');
	}

	/* init the cd1400 chips */
	for( chip = 0 ; chip < card->mb_ncd1400 ; chip++ ) {
		struct cd1400 *cd = &sc->ms_cd1400[chip];

		cd->cd_clock = cd_clock;
		cd->cd_reg = (char *)bus_space_vaddr(sa->sa_bustag, bh) +
		    card->mb_cd1400[chip];

		/* prom_getpropstring(node, "chiprev"); */
		/* seemingly the Magma drivers just ignore the propstring */
		cd->cd_chiprev = cd1400_read_reg(cd, CD1400_GFRCR);

		dprintf(("%s attach CD1400 %d addr %p rev %x clock %dMHz\n",
			device_xname(sc->ms_dev), chip,
			cd->cd_reg, cd->cd_chiprev, cd->cd_clock));

		/* clear GFRCR */
		cd1400_write_reg(cd, CD1400_GFRCR, 0x00);

		/* reset whole chip */
		cd1400_write_ccr(cd, CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);

		/* wait for revision code to be restored */
		while( cd1400_read_reg(cd, CD1400_GFRCR) != cd->cd_chiprev )
		        ;

		/* set the Prescaler Period Register to tick at 1ms */
		cd1400_write_reg(cd, CD1400_PPR,
			((cd->cd_clock * 1000000 / CD1400_PPR_PRESCALER + 500) / 1000));

		/* The LC2+1Sp card is the only card that doesn't have
		 * a CD1190 for the parallel port, but uses channel 0 of
		 * the CD1400, so we make a note of it for later and set up
		 * the CD1400 for parallel mode operation.
		 */
		if( card->mb_npar && card->mb_ncd1190 == 0 ) {
			cd1400_write_reg(cd, CD1400_GCR, CD1400_GCR_PARALLEL);
			cd->cd_parmode = 1;
		}
	}

	/* init the cd1190 chips */
	for( chip = 0 ; chip < card->mb_ncd1190 ; chip++ ) {
		struct cd1190 *cd = &sc->ms_cd1190[chip];

		cd->cd_reg = (char *)bus_space_vaddr(sa->sa_bustag, bh) +
		    card->mb_cd1190[chip];

		/* XXX don't know anything about these chips yet */
		printf("%s: CD1190 %d addr %p (unsupported)\n",
			device_xname(self), chip, cd->cd_reg);
	}

	/* configure the children */
	(void)config_found(self, mtty_match, NULL);
	(void)config_found(self, mbpp_match, NULL);

	/*
	 * Establish the interrupt handlers.
	 */
	if (sa->sa_nintr == 0)
		return;		/* No interrupts to service!? */

	(void)bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_SERIAL,
				 magma_hard, sc);
	sc->ms_sicookie = softint_establish(SOFTINT_SERIAL, magma_soft, sc);
	if (sc->ms_sicookie == NULL) {
		aprint_normal("\n");
		aprint_error_dev(sc->ms_dev, "cannot establish soft int handler\n");
		return;
	}
	evcnt_attach_dynamic(&sc->ms_intrcnt, EVCNT_TYPE_INTR, NULL,
	    device_xname(sc->ms_dev), "intr");
}