Пример #1
0
int
mcd_getresult(struct mcd_softc *sc, struct mcd_result *res)
{
	int i, x;

	if (sc->debug)
		printf("%s: mcd_getresult: %d", device_xname(sc->sc_dev),
		    res->length);

	if ((x = mcd_getreply(sc)) < 0) {
		if (sc->debug)
			printf(" timeout\n");
		else if (!sc->probe)
			printf("%s: timeout in getresult\n", device_xname(sc->sc_dev));
		return EIO;
	}
	if (sc->debug)
		printf(" %02x", (u_int)x);
	sc->status = x;
	mcd_setflags(sc);

	if ((sc->status & MCD_ST_CMDCHECK) != 0)
		return EINVAL;

	for (i = 0; i < res->length; i++) {
		if ((x = mcd_getreply(sc)) < 0) {
			if (sc->debug)
				printf(" timeout\n");
			else
				printf("%s: timeout in getresult\n", device_xname(sc->sc_dev));
			return EIO;
		}
		if (sc->debug)
			printf(" %02x", (u_int)x);
		res->data.raw.data[i] = x;
	}

	if (sc->debug)
		printf(" succeeded\n");

#ifdef MCDDEBUG
	delay(10);
	while ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, MCD_XFER) &
	    MCD_XF_STATUSUNAVAIL) == 0) {
		x = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MCD_STATUS);
		printf("%s: got extra byte %02x during getstatus\n",
		    device_xname(sc->sc_dev), (u_int)x);
		delay(10);
	}
#endif

	return 0;
}
Пример #2
0
Файл: mcd.c Проект: MarginC/kame
static int
mcd_getstat(struct mcd_softc *sc, int sflg)
{
	int	i;

	/* get the status */
	if (sflg)
		MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDGETSTAT);
	i = mcd_getreply(sc, DELAY_GETREPLY);
	if (i<0 || (i & MCD_ST_CMDCHECK)) {
		sc->data.curr_mode = MCD_MD_UNKNOWN;
		return (-1);
	}

	sc->data.status = i;

	if (mcd_setflags(sc) < 0)
		return (-2);
	return (sc->data.status);
}
Пример #3
0
Файл: mcd.c Проект: MarginC/kame
static void
mcd_doread(struct mcd_softc *sc, int state, struct mcd_mbx *mbxin)
{
	struct mcd_mbx *mbx;
	struct bio *bp;
	int rm, i, k;
	struct mcd_read2 rbuf;
	int blknum;
	caddr_t	addr;

	mbx = (state!=MCD_S_BEGIN) ? sc->ch_mbxsave : mbxin;
	bp = mbx->bp;

loop:
	switch (state) {
	case MCD_S_BEGIN:
		mbx = sc->ch_mbxsave = mbxin;

	case MCD_S_BEGIN1:
retry_status:
		/* get status */
		MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDGETSTAT);
		mbx->count = RDELAY_WAITSTAT;
		sc->ch_state = MCD_S_WAITSTAT;
		sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
		return;
	case MCD_S_WAITSTAT:
		sc->ch_state = MCD_S_WAITSTAT;
		untimeout(mcd_timeout,(caddr_t)sc, sc->ch);
		if (mbx->count-- >= 0) {
			if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) {
				sc->ch_state = MCD_S_WAITSTAT;
				timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
				return;
			}
			sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF;
			if (sc->data.status & MCD_ST_CMDCHECK)
				goto retry_status;
			if (mcd_setflags(sc) < 0)
				goto changed;
			MCD_TRACE("got WAITSTAT delay=%d\n",
				RDELAY_WAITSTAT-mbx->count);
			/* reject, if audio active */
			if (sc->data.status & MCDAUDIOBSY) {
				device_printf(sc->dev, "audio is active\n");
				goto readerr;
			}

retry_mode:
			/* to check for raw/cooked mode */
			if (sc->data.flags & MCDREADRAW) {
				rm = MCD_MD_RAW;
				mbx->sz = MCDRBLK;
			} else {
				rm = MCD_MD_COOKED;
				mbx->sz = sc->data.blksize;
			}

			if (rm == sc->data.curr_mode)
				goto modedone;

			mbx->count = RDELAY_WAITMODE;

			sc->data.curr_mode = MCD_MD_UNKNOWN;
			mbx->mode = rm;
			MCD_WRITE(sc, MCD_REG_COMMAND, MCD_CMDSETMODE);
			MCD_WRITE(sc, MCD_REG_COMMAND, rm);

			sc->ch_state = MCD_S_WAITMODE;
			sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
			return;
		} else {
			device_printf(sc->dev, "timeout getstatus\n");
			goto readerr;
		}

	case MCD_S_WAITMODE:
		sc->ch_state = MCD_S_WAITMODE;
		untimeout(mcd_timeout, (caddr_t)sc, sc->ch);
		if (mbx->count-- < 0) {
			device_printf(sc->dev, "timeout set mode\n");
			goto readerr;
		}
		if (MCD_READ(sc, MCD_FLAGS) & MFL_STATUS_NOT_AVAIL) {
			sc->ch_state = MCD_S_WAITMODE;
			sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100);
			return;
		}
		sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF;
		if (sc->data.status & MCD_ST_CMDCHECK) {
			sc->data.curr_mode = MCD_MD_UNKNOWN;
			goto retry_mode;
		}
		if (mcd_setflags(sc) < 0)
			goto changed;
		sc->data.curr_mode = mbx->mode;
		MCD_TRACE("got WAITMODE delay=%d\n",
			RDELAY_WAITMODE-mbx->count);
modedone:
		/* for first block */
		mbx->nblk = (bp->bio_bcount + (mbx->sz-1)) / mbx->sz;
		mbx->skip = 0;

nextblock:
		blknum 	= (bp->bio_blkno / (mbx->sz/DEV_BSIZE))
			+ mbx->skip/mbx->sz;

		MCD_TRACE("mcd_doread: read blknum=%d for bp=%p\n",
			blknum, bp);

		/* build parameter block */
		hsg2msf(blknum,rbuf.start_msf);
retry_read:
		/* send the read command */
		critical_enter();
		MCD_WRITE(sc, MCD_REG_COMMAND, sc->data.read_command);
		MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[0]);
		MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[1]);
		MCD_WRITE(sc, MCD_REG_COMMAND, rbuf.start_msf[2]);
		MCD_WRITE(sc, MCD_REG_COMMAND, 0);
		MCD_WRITE(sc, MCD_REG_COMMAND, 0);
		MCD_WRITE(sc, MCD_REG_COMMAND, 1);
		critical_exit();

		/* Spin briefly (<= 2ms) to avoid missing next block */
		for (i = 0; i < 20; i++) {
			k = MCD_READ(sc, MCD_FLAGS);
			if (!(k & MFL_DATA_NOT_AVAIL))
				goto got_it;
			DELAY(100);
		}

		mbx->count = RDELAY_WAITREAD;
		sc->ch_state = MCD_S_WAITREAD;
		sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
		return;
	case MCD_S_WAITREAD:
		sc->ch_state = MCD_S_WAITREAD;
		untimeout(mcd_timeout, (caddr_t)sc, sc->ch);
		if (mbx->count-- > 0) {
			k = MCD_READ(sc, MCD_FLAGS);
			if (!(k & MFL_DATA_NOT_AVAIL)) { /* XXX */
				MCD_TRACE("got data delay=%d\n",
					RDELAY_WAITREAD-mbx->count);
			got_it:
				/* data is ready */
				addr	= bp->bio_data + mbx->skip;

				MCD_WRITE(sc, MCD_REG_CTL2,0x04);	/* XXX */
				for (i=0; i<mbx->sz; i++)
					*addr++ = MCD_READ(sc, MCD_REG_RDATA);
				MCD_WRITE(sc, MCD_REG_CTL2,0x0c);	/* XXX */

				k = MCD_READ(sc, MCD_FLAGS);
				/* If we still have some junk, read it too */
				if (!(k & MFL_DATA_NOT_AVAIL)) {
					MCD_WRITE(sc, MCD_REG_CTL2, 0x04);       /* XXX */
					(void)MCD_READ(sc, MCD_REG_RDATA);
					(void)MCD_READ(sc, MCD_REG_RDATA);
					MCD_WRITE(sc, MCD_REG_CTL2, 0x0c);       /* XXX */
				}

				if (--mbx->nblk > 0) {
					mbx->skip += mbx->sz;
					goto nextblock;
				}

				/* return buffer */
				bp->bio_resid = 0;
				biodone(bp);

				sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW);
				mcd_start(sc);
				return;
			}
			if (!(k & MFL_STATUS_NOT_AVAIL)) {
				sc->data.status = MCD_READ(sc, MCD_REG_STATUS) & 0xFF;
				if (sc->data.status & MCD_ST_CMDCHECK)
					goto retry_read;
				if (mcd_setflags(sc) < 0)
					goto changed;
			}
			sc->ch_state = MCD_S_WAITREAD;
			sc->ch = timeout(mcd_timeout, (caddr_t)sc, hz/100); /* XXX */
			return;
		} else {
			device_printf(sc->dev, "timeout read data\n");
			goto readerr;
		}
	}

readerr:
	if (mbx->retry-- > 0) {
		device_printf(sc->dev, "retrying\n");
		state = MCD_S_BEGIN1;
		goto loop;
	}
harderr:
	/* invalidate the buffer */
	bp->bio_flags |= BIO_ERROR;
	bp->bio_resid = bp->bio_bcount;
	biodone(bp);

	sc->data.flags &= ~(MCDMBXBSY|MCDREADRAW);
	mcd_start(sc);
	return;

changed:
	device_printf(sc->dev, "media changed\n");
	goto harderr;

#ifdef NOTDEF
	device_printf(sc->dev, "unit timeout, resetting\n");
	MCD_WRITE(sc, MCD_REG_RESET, MCD_CMDRESET);
	DELAY(300000);
	(void)mcd_getstat(sc, 1);
	(void)mcd_getstat(sc, 1);
	/*sc->data.status &= ~MCDDSKCHNG; */
	sc->data.debug = 1; /* preventive set debug mode */

#endif

}
Пример #4
0
/*
 * State machine to process read requests.
 * Initialize with MCD_S_BEGIN: calculate sizes, and set mode
 * MCD_S_WAITMODE: waits for status reply from set mode, set read command
 * MCD_S_WAITREAD: wait for read ready, read data.
 */
int
mcdintr(void *arg)
{
	struct mcd_softc *sc = arg;
	struct mcd_mbx *mbx = &sc->mbx;
	struct buf *bp = mbx->bp;
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;

	int i;
	u_char x;
	bcd_t msf[3];

	switch (mbx->state) {
	case MCD_S_IDLE:
		return 0;

	case MCD_S_BEGIN:
	tryagain:
		if (mbx->mode == sc->lastmode)
			goto firstblock;

		sc->lastmode = MCD_MD_UNKNOWN;
		bus_space_write_1(iot, ioh, MCD_COMMAND, MCD_CMDSETMODE);
		bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->mode);

		mbx->count = RDELAY_WAITMODE;
		mbx->state = MCD_S_WAITMODE;

	case MCD_S_WAITMODE:
		callout_stop(&sc->sc_pintr_ch);
		for (i = 20; i; i--) {
			x = bus_space_read_1(iot, ioh, MCD_XFER);
			if ((x & MCD_XF_STATUSUNAVAIL) == 0)
				break;
			delay(50);
		}
		if (i == 0)
			goto hold;
		sc->status = bus_space_read_1(iot, ioh, MCD_STATUS);
		mcd_setflags(sc);
		if ((sc->flags & MCDF_LOADED) == 0)
			goto changed;
		MCD_TRACE("doread: got WAITMODE delay=%d\n",
		    RDELAY_WAITMODE - mbx->count);

		sc->lastmode = mbx->mode;

	firstblock:
		MCD_TRACE("doread: read blkno=%d for bp=0x%p\n", 
		    (int) mbx->blkno, bp);

		/* Build parameter block. */
		hsg2msf(mbx->blkno, msf);

		/* Send the read command. */
		bus_space_write_1(iot, ioh, MCD_COMMAND, sc->readcmd);
		bus_space_write_1(iot, ioh, MCD_COMMAND, msf[0]);
		bus_space_write_1(iot, ioh, MCD_COMMAND, msf[1]);
		bus_space_write_1(iot, ioh, MCD_COMMAND, msf[2]);
		bus_space_write_1(iot, ioh, MCD_COMMAND, 0);
		bus_space_write_1(iot, ioh, MCD_COMMAND, 0);
		bus_space_write_1(iot, ioh, MCD_COMMAND, mbx->nblk);

		mbx->count = RDELAY_WAITREAD;
		mbx->state = MCD_S_WAITREAD;

	case MCD_S_WAITREAD:
		callout_stop(&sc->sc_pintr_ch);
	nextblock:
	loop:
		for (i = 20; i; i--) {
			x = bus_space_read_1(iot, ioh, MCD_XFER);
			if ((x & MCD_XF_DATAUNAVAIL) == 0)
				goto gotblock;
			if ((x & MCD_XF_STATUSUNAVAIL) == 0)
				break;
			delay(50);
		}
		if (i == 0)
			goto hold;
		sc->status = bus_space_read_1(iot, ioh, MCD_STATUS);
		mcd_setflags(sc);
		if ((sc->flags & MCDF_LOADED) == 0)
			goto changed;
#if 0
		printf("%s: got status byte %02x during read\n",
		    device_xname(sc->sc_dev), (u_int)sc->status);
#endif
		goto loop;

	gotblock:
		MCD_TRACE("doread: got data delay=%d\n",
		    RDELAY_WAITREAD - mbx->count);

		/* Data is ready. */
		bus_space_write_1(iot, ioh, MCD_CTL2, 0x04);	/* XXX */
		bus_space_read_multi_1(iot, ioh, MCD_RDATA,
		    (char *)bp->b_data + mbx->skip, mbx->sz);
		bus_space_write_1(iot, ioh, MCD_CTL2, 0x0c);	/* XXX */
		mbx->blkno += 1;
		mbx->skip += mbx->sz;
		if (--mbx->nblk > 0)
			goto nextblock;

		mbx->state = MCD_S_IDLE;

		/* Return buffer. */
		bp->b_resid = 0;
		disk_unbusy(&sc->sc_dk, bp->b_bcount, (bp->b_flags & B_READ));
		biodone(bp);

		mcdstart(sc);
		return 1;

	hold:
		if (mbx->count-- < 0) {
			printf("%s: timeout in state %d",
			    device_xname(sc->sc_dev), mbx->state);
			goto readerr;
		}

#if 0
		printf("%s: sleep in state %d\n", device_xname(sc->sc_dev),
		    mbx->state);
#endif
		callout_reset(&sc->sc_pintr_ch, hz / 100,
		    mcd_pseudointr, sc);
		return -1;
	}

readerr:
	if (mbx->retry-- > 0) {
		printf("; retrying\n");
		goto tryagain;
	} else
		printf("; giving up\n");

changed:
	/* Invalidate the buffer. */
	bp->b_error = EIO;
	bp->b_resid = bp->b_bcount - mbx->skip;
	disk_unbusy(&sc->sc_dk, (bp->b_bcount - bp->b_resid),
	    (bp->b_flags & B_READ));
	biodone(bp);

	mcdstart(sc);
	return -1;

#ifdef notyet
	printf("%s: unit timeout; resetting\n", device_xname(sc->sc_dev));
	bus_space_write_1(iot, ioh, MCD_RESET, MCD_CMDRESET);
	delay(300000);
	(void) mcd_getstat(sc, 1);
	(void) mcd_getstat(sc, 1);
	/*sc->status &= ~MCD_ST_DSKCHNG; */
	sc->debug = 1; /* preventive set debug mode */
#endif
}