Esempio n. 1
0
int
mcd_getqchan(struct mcd_softc *sc, union mcd_qchninfo *q, int qchn)
{
	struct mcd_mbox mbx;
	int error;

	if (qchn == CD_TRACK_INFO) {
		if ((error = mcd_setmode(sc, MCD_MD_TOC)) != 0)
			return error;
	} else {
		if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
			return error;
	}
	if (qchn == CD_MEDIA_CATALOG) {
		if ((error = mcd_setupc(sc, MCD_UPC_ENABLE)) != 0)
			return error;
	} else {
		if ((error = mcd_setupc(sc, MCD_UPC_DISABLE)) != 0)
			return error;
	}

	mbx.cmd.opcode = MCD_CMDGETQCHN;
	mbx.cmd.length = 0;
	mbx.res.length = sizeof(mbx.res.data.qchninfo);
	if ((error = mcd_send(sc, &mbx, 1)) != 0)
		return error;

	*q = mbx.res.data.qchninfo;
	return 0;
}
Esempio n. 2
0
File: mcd.c Progetto: MarginC/kame
static int
mcd_playtracks(struct mcd_softc *sc, struct ioc_play_track *pt)
{
	struct mcd_read2 pb;
	int a = pt->start_track;
	int z = pt->end_track;
	int rc, i;

	if ((rc = mcd_read_toc(sc)) != 0)
		return (rc);

	if (sc->data.debug)
		device_printf(sc->dev, "playtracks from %d:%d to %d:%d\n",
			a, pt->start_index, z, pt->end_index);

	if (   a < bcd2bin(sc->data.volinfo.trk_low)
	    || a > bcd2bin(sc->data.volinfo.trk_high)
	    || a > z
	    || z < bcd2bin(sc->data.volinfo.trk_low)
	    || z > bcd2bin(sc->data.volinfo.trk_high))
		return (EINVAL);

	for (i = 0; i < 3; i++) {
		pb.start_msf[i] = sc->data.toc[a].hd_pos_msf[i];
		pb.end_msf[i] = sc->data.toc[z+1].hd_pos_msf[i];
	}

	if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
		return (EIO);

	return mcd_play(sc, &pb);
}
Esempio n. 3
0
File: mcd.c Progetto: MarginC/kame
static int
mcd_playmsf(struct mcd_softc *sc, struct ioc_play_msf *p)
{
	struct mcd_read2 pb;

	if (sc->data.debug)
		device_printf(sc->dev, "playmsf: from %d:%d.%d to %d:%d.%d\n",
		    p->start_m, p->start_s, p->start_f,
		    p->end_m, p->end_s, p->end_f);

	if ((p->start_m * 60 * 75 + p->start_s * 75 + p->start_f) >=
	    (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f) ||
	    (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f) >
	    M_msf(sc->data.volinfo.vol_msf) * 60 * 75 +
	    S_msf(sc->data.volinfo.vol_msf) * 75 +
	    F_msf(sc->data.volinfo.vol_msf))
		return (EINVAL);

	pb.start_msf[0] = bin2bcd(p->start_m);
	pb.start_msf[1] = bin2bcd(p->start_s);
	pb.start_msf[2] = bin2bcd(p->start_f);
	pb.end_msf[0] = bin2bcd(p->end_m);
	pb.end_msf[1] = bin2bcd(p->end_s);
	pb.end_msf[2] = bin2bcd(p->end_f);

	if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
		return (EIO);

	return mcd_play(sc, &pb);
}
Esempio n. 4
0
int
mcdclose(dev_t dev, int flag, int fmt, struct lwp *l)
{
	struct mcd_softc *sc = device_lookup_private(&mcd_cd, MCDUNIT(dev));
	int part = MCDPART(dev);
	
	MCD_TRACE("close: partition=%d\n", part);

	mutex_enter(&sc->sc_lock);

	switch (fmt) {
	case S_IFCHR:
		sc->sc_dk.dk_copenmask &= ~(1 << part);
		break;
	case S_IFBLK:
		sc->sc_dk.dk_bopenmask &= ~(1 << part);
		break;
	}
	sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;

	if (sc->sc_dk.dk_openmask == 0) {
		/* XXXX Must wait for I/O to complete! */

#if 0
		(void) mcd_setmode(sc, MCD_MD_SLEEP);
#endif
		(void) mcd_setlock(sc, MCD_LK_UNLOCK);
	}

	mutex_exit(&sc->sc_lock);
	return 0;
}
Esempio n. 5
0
int
mcd_playblocks(struct mcd_softc *sc, struct ioc_play_blocks *p)
{
	struct mcd_mbox mbx;
	int error;

	if (sc->debug)
		printf("%s: playblocks: blkno %d length %d\n",
		    device_xname(sc->sc_dev), p->blk, p->len);

	if (p->blk > sc->disksize || p->len > sc->disksize ||
	    (p->blk + p->len) > sc->disksize)
		return 0;

	if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
		return error;

	mbx.cmd.opcode = MCD_CMDREADSINGLESPEED;
	mbx.cmd.length = sizeof(mbx.cmd.data.play);
	hsg2msf(p->blk, mbx.cmd.data.play.start_msf);
	hsg2msf(p->blk + p->len, mbx.cmd.data.play.end_msf);
	sc->lastpb = mbx.cmd;
	mbx.res.length = 0;
	return mcd_send(sc, &mbx, 1);
}
Esempio n. 6
0
int
mcd_playmsf(struct mcd_softc *sc, struct ioc_play_msf *p)
{
	struct mcd_mbox mbx;
	int error;

	if (sc->debug)
		printf("%s: playmsf: from %d:%d.%d to %d:%d.%d\n",
		    device_xname(sc->sc_dev),
		    p->start_m, p->start_s, p->start_f,
		    p->end_m, p->end_s, p->end_f);

	if ((p->start_m * 60 * 75 + p->start_s * 75 + p->start_f) >=
	    (p->end_m * 60 * 75 + p->end_s * 75 + p->end_f))
		return EINVAL;

	if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
		return error;

	mbx.cmd.opcode = MCD_CMDREADSINGLESPEED;
	mbx.cmd.length = sizeof(mbx.cmd.data.play);
	mbx.cmd.data.play.start_msf[0] = bin2bcd(p->start_m);
	mbx.cmd.data.play.start_msf[1] = bin2bcd(p->start_s);
	mbx.cmd.data.play.start_msf[2] = bin2bcd(p->start_f);
	mbx.cmd.data.play.end_msf[0] = bin2bcd(p->end_m);
	mbx.cmd.data.play.end_msf[1] = bin2bcd(p->end_s);
	mbx.cmd.data.play.end_msf[2] = bin2bcd(p->end_f);
	sc->lastpb = mbx.cmd;
	mbx.res.length = 0;
	return mcd_send(sc, &mbx, 1);
}
Esempio n. 7
0
int
mcd_playtracks(struct mcd_softc *sc, struct ioc_play_track *p)
{
	struct mcd_mbox mbx;
	int a = p->start_track;
	int z = p->end_track;
	int error;

	if (sc->debug)
		printf("%s: playtracks: from %d:%d to %d:%d\n",
		    device_xname(sc->sc_dev),
		    a, p->start_index, z, p->end_index);

	if (a < bcd2bin(sc->volinfo.trk_low) ||
	    a > bcd2bin(sc->volinfo.trk_high) ||
	    a > z ||
	    z < bcd2bin(sc->volinfo.trk_low) ||
	    z > bcd2bin(sc->volinfo.trk_high))
		return EINVAL;

	if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
		return error;

	mbx.cmd.opcode = MCD_CMDREADSINGLESPEED;
	mbx.cmd.length = sizeof(mbx.cmd.data.play);
	mbx.cmd.data.play.start_msf[0] = sc->toc[a].toc.absolute_pos[0];
	mbx.cmd.data.play.start_msf[1] = sc->toc[a].toc.absolute_pos[1];
	mbx.cmd.data.play.start_msf[2] = sc->toc[a].toc.absolute_pos[2];
	mbx.cmd.data.play.end_msf[0] = sc->toc[z+1].toc.absolute_pos[0];
	mbx.cmd.data.play.end_msf[1] = sc->toc[z+1].toc.absolute_pos[1];
	mbx.cmd.data.play.end_msf[2] = sc->toc[z+1].toc.absolute_pos[2];
	sc->lastpb = mbx.cmd;
	mbx.res.length = 0;
	return mcd_send(sc, &mbx, 1);
}
Esempio n. 8
0
int
mcd_read_toc(struct mcd_softc *sc)
{
	struct ioc_toc_header th;
	union mcd_qchninfo q;
	int error, trk, idx, retry;

	if ((error = mcd_toc_header(sc, &th)) != 0)
		return error;

	if ((error = mcd_stop(sc)) != 0)
		return error;

	if (sc->debug)
		printf("%s: read_toc: reading qchannel info\n",
		    device_xname(sc->sc_dev));

	for (trk = th.starting_track; trk <= th.ending_track; trk++)
		sc->toc[trk].toc.idx_no = 0x00;
	trk = th.ending_track - th.starting_track + 1;
	for (retry = 300; retry && trk > 0; retry--) {
		if (mcd_getqchan(sc, &q, CD_TRACK_INFO) != 0)
			break;
		if (q.toc.trk_no != 0x00 || q.toc.idx_no == 0x00)
			continue;
		idx = bcd2bin(q.toc.idx_no);
		if (idx < MCD_MAXTOCS &&
		    sc->toc[idx].toc.idx_no == 0x00) {
			sc->toc[idx] = q;
			trk--;
		}
	}

	/* Inform the drive that we're finished so it turns off the light. */
	if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
		return error;

	if (trk != 0)
		return EINVAL;

	/* Add a fake last+1 for mcd_playtracks(). */
	idx = th.ending_track + 1;
	sc->toc[idx].toc.control = sc->toc[idx-1].toc.control;
	sc->toc[idx].toc.addr_type = sc->toc[idx-1].toc.addr_type;
	sc->toc[idx].toc.trk_no = 0x00;
	sc->toc[idx].toc.idx_no = 0xaa;
	sc->toc[idx].toc.absolute_pos[0] = sc->volinfo.vol_msf[0];
	sc->toc[idx].toc.absolute_pos[1] = sc->volinfo.vol_msf[1];
	sc->toc[idx].toc.absolute_pos[2] = sc->volinfo.vol_msf[2];

	return 0;
}
Esempio n. 9
0
int
mcd_resume(struct mcd_softc *sc)
{
	struct mcd_mbox mbx;
	int error;

	if (sc->audio_status != CD_AS_PLAY_PAUSED)
		return EINVAL;

	if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
		return error;

	mbx.cmd = sc->lastpb;
	mbx.res.length = 0;
	return mcd_send(sc, &mbx, 1);
}
Esempio n. 10
0
File: mcd.c Progetto: MarginC/kame
static int
mcd_playblocks(struct mcd_softc *sc, struct ioc_play_blocks *p)
{
	struct mcd_read2 pb;

	if (sc->data.debug)
		device_printf(sc->dev, "playblocks: blkno %d length %d\n",
		    p->blk, p->len);

	if (p->blk > sc->data.disksize || p->len > sc->data.disksize ||
	    p->blk < 0 || p->len < 0 ||
	    (p->blk + p->len) > sc->data.disksize)
		return (EINVAL);

	hsg2msf(p->blk, pb.start_msf);
	hsg2msf(p->blk + p->len, pb.end_msf);

	if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
		return (EIO);

	return mcd_play(sc, &pb);
}
Esempio n. 11
0
File: mcd.c Progetto: MarginC/kame
static int
mcdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
{
	struct mcd_softc *sc;
	int retry,r;

	sc = (struct mcd_softc *)dev->si_drv1;

	if (mcd_getstat(sc, 1) == -1) /* detect disk change too */
		return (EIO);
MCD_TRACE("ioctl called 0x%lx\n", cmd);

	switch (cmd) {
	case CDIOCSETPATCH:
	case CDIOCGETVOL:
	case CDIOCSETVOL:
	case CDIOCSETMONO:
	case CDIOCSETSTERIO:
	case CDIOCSETMUTE:
	case CDIOCSETLEFT:
	case CDIOCSETRIGHT:
		return (EINVAL);
	case CDIOCEJECT:
		return mcd_eject(sc);
	case CDIOCSETDEBUG:
		sc->data.debug = 1;
		return (0);
	case CDIOCCLRDEBUG:
		sc->data.debug = 0;
		return (0);
	case CDIOCRESET:
		return mcd_hard_reset(sc);
	case CDIOCALLOW:
		return mcd_lock_door(sc, MCD_LK_UNLOCK);
	case CDIOCPREVENT:
		return mcd_lock_door(sc, MCD_LK_LOCK);
	case CDIOCCLOSE:
		return mcd_inject(sc);
	}

	if (!(sc->data.flags & MCDVALID)) {
		if (    (sc->data.status & (MCDDSKCHNG|MCDDOOROPEN))
		    || !(sc->data.status & MCDDSKIN))
			for (retry = 0; retry < DISK_SENSE_SECS * WAIT_FRAC; retry++) {
				(void) tsleep((caddr_t)sc, PSOCK | PCATCH, "mcdsn2", hz/WAIT_FRAC);
				if ((r = mcd_getstat(sc, 1)) == -1)
					return (EIO);
				if (r != -2)
					break;
			}
		if (   (sc->data.status & (MCDDOOROPEN|MCDDSKCHNG))
		    || !(sc->data.status & MCDDSKIN)
		    || mcdsize(dev) < 0
		   )
			return (ENXIO);
		sc->data.flags |= MCDVALID;
		sc->data.partflags |= MCDREADRAW;
		(void) mcd_lock_door(sc, MCD_LK_LOCK);
		if (!(sc->data.flags & MCDVALID))
			return (ENXIO);
	}

	switch (cmd) {
	case DIOCGMEDIASIZE:
		*(off_t *)addr = (off_t)sc->data.disksize * sc->data.blksize;
		return (0);
		break;
	case DIOCGSECTORSIZE:
		*(u_int *)addr = sc->data.blksize;
		return (0);
		break;

	case CDIOCPLAYTRACKS:
		return mcd_playtracks(sc, (struct ioc_play_track *) addr);
	case CDIOCPLAYBLOCKS:
		return mcd_playblocks(sc, (struct ioc_play_blocks *) addr);
	case CDIOCPLAYMSF:
		return mcd_playmsf(sc, (struct ioc_play_msf *) addr);
	case CDIOCREADSUBCHANNEL:
		return mcd_subchan(sc, (struct ioc_read_subchannel *) addr);
	case CDIOREADTOCHEADER:
		return mcd_toc_header(sc, (struct ioc_toc_header *) addr);
	case CDIOREADTOCENTRYS:
		return mcd_toc_entrys(sc, (struct ioc_read_toc_entry *) addr);
	case CDIOCRESUME:
		return mcd_resume(sc);
	case CDIOCPAUSE:
		return mcd_pause(sc);
	case CDIOCSTART:
		if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
			return (EIO);
		return (0);
	case CDIOCSTOP:
		return mcd_stop(sc);
	default:
		return (ENOTTY);
	}
	/*NOTREACHED*/
}
Esempio n. 12
0
File: mcd.c Progetto: MarginC/kame
static int
mcd_subchan(struct mcd_softc *sc, struct ioc_read_subchannel *sch)
{
	struct mcd_qchninfo q;
	struct cd_sub_channel_info data;
	int lba;

	if (sc->data.debug)
		device_printf(sc->dev, "subchan af=%d, df=%d\n",
			sch->address_format,
			sch->data_format);

	if (sch->address_format != CD_MSF_FORMAT &&
	    sch->address_format != CD_LBA_FORMAT)
		return (EINVAL);

	if (sch->data_format != CD_CURRENT_POSITION &&
	    sch->data_format != CD_MEDIA_CATALOG)
		return (EINVAL);

	if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
		return (EIO);

	if (mcd_getqchan(sc, &q) < 0)
		return (EIO);

	data.header.audio_status = sc->data.audio_status;
	data.what.position.data_format = sch->data_format;

	switch (sch->data_format) {
	case CD_MEDIA_CATALOG:
		data.what.media_catalog.mc_valid = 1;
		data.what.media_catalog.mc_number[0] = '\0';
		break;

	case CD_CURRENT_POSITION:
		data.what.position.control = q.control;
		data.what.position.addr_type = q.addr_type;
		data.what.position.track_number = bcd2bin(q.trk_no);
		data.what.position.index_number = bcd2bin(q.idx_no);
		switch (sch->address_format) {
		case CD_MSF_FORMAT:
			data.what.position.reladdr.msf.unused = 0;
			data.what.position.reladdr.msf.minute = bcd2bin(q.trk_size_msf[0]);
			data.what.position.reladdr.msf.second = bcd2bin(q.trk_size_msf[1]);
			data.what.position.reladdr.msf.frame = bcd2bin(q.trk_size_msf[2]);
			data.what.position.absaddr.msf.unused = 0;
			data.what.position.absaddr.msf.minute = bcd2bin(q.hd_pos_msf[0]);
			data.what.position.absaddr.msf.second = bcd2bin(q.hd_pos_msf[1]);
			data.what.position.absaddr.msf.frame = bcd2bin(q.hd_pos_msf[2]);
			break;
		case CD_LBA_FORMAT:
			lba = msf2hsg(q.trk_size_msf, 1);
			/*
			 * Pre-gap has index number of 0, and decreasing MSF
			 * address.  Must be converted to negative LBA, per
			 * SCSI spec.
			 */
			if (data.what.position.index_number == 0)
				lba = -lba;
			data.what.position.reladdr.lba = htonl(lba);
			data.what.position.absaddr.lba = htonl(msf2hsg(q.hd_pos_msf, 0));
			break;
		}
		break;
	}

	return copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len));
}
Esempio n. 13
0
File: mcd.c Progetto: MarginC/kame
static int
mcd_read_toc(struct mcd_softc *sc)
{
	struct ioc_toc_header th;
	struct mcd_qchninfo q;
	int rc, trk, idx, retry;

	/* Only read TOC if needed */
	if (sc->data.flags & MCDTOC)
		return (0);

	if (sc->data.debug)
		device_printf(sc->dev, "reading toc header\n");

	if ((rc = mcd_toc_header(sc, &th)) != 0)
		return (rc);

	if (mcd_send(sc, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0)
		return (EIO);

	if (mcd_setmode(sc, MCD_MD_TOC) != 0)
		return (EIO);

	if (sc->data.debug)
		device_printf(sc->dev, "get_toc reading qchannel info\n");

	for(trk=th.starting_track; trk<=th.ending_track; trk++)
		sc->data.toc[trk].idx_no = 0;
	trk = th.ending_track - th.starting_track + 1;
	for(retry=0; retry<600 && trk>0; retry++)
	{
		if (mcd_getqchan(sc, &q) < 0) break;
		idx = bcd2bin(q.idx_no);
		if (idx>=th.starting_track && idx<=th.ending_track && q.trk_no==0) {
			if (sc->data.toc[idx].idx_no == 0) {
				sc->data.toc[idx] = q;
				trk--;
			}
		}
	}

	if (mcd_setmode(sc, MCD_MD_COOKED) != 0)
		return (EIO);

	if (trk != 0)
		return (ENXIO);

	/* add a fake last+1 */
	idx = th.ending_track + 1;
	sc->data.toc[idx].control = sc->data.toc[idx-1].control;
	sc->data.toc[idx].addr_type = sc->data.toc[idx-1].addr_type;
	sc->data.toc[idx].trk_no = 0;
	sc->data.toc[idx].idx_no = MCD_LASTPLUS1;
	sc->data.toc[idx].hd_pos_msf[0] = sc->data.volinfo.vol_msf[0];
	sc->data.toc[idx].hd_pos_msf[1] = sc->data.volinfo.vol_msf[1];
	sc->data.toc[idx].hd_pos_msf[2] = sc->data.volinfo.vol_msf[2];

	if (sc->data.debug)
	{ int i;
	for (i = th.starting_track; i <= idx; i++)
		device_printf(sc->dev, "trk %d idx %d pos %d %d %d\n",
			i,
			sc->data.toc[i].idx_no > 0x99 ? sc->data.toc[i].idx_no :
			bcd2bin(sc->data.toc[i].idx_no),
			bcd2bin(sc->data.toc[i].hd_pos_msf[0]),
			bcd2bin(sc->data.toc[i].hd_pos_msf[1]),
			bcd2bin(sc->data.toc[i].hd_pos_msf[2]));
	}

	sc->data.flags |= MCDTOC;

	return (0);
}
Esempio n. 14
0
int
mcdopen(dev_t dev, int flag, int fmt, struct lwp *l)
{
	int error, part;
	struct mcd_softc *sc;

	sc = device_lookup_private(&mcd_cd, MCDUNIT(dev));
	if (sc == NULL)
		return ENXIO;

	mutex_enter(&sc->sc_lock);

	if (sc->sc_dk.dk_openmask != 0) {
		/*
		 * If any partition is open, but the disk has been invalidated,
		 * disallow further opens.
		 */
		if ((sc->flags & MCDF_LOADED) == 0) {
			error = EIO;
			goto bad3;
		}
	} else {
		/*
		 * Lock the drawer.  This will also notice any pending disk
		 * change or door open indicator and clear the MCDF_LOADED bit
		 * if necessary.
		 */
		(void) mcd_setlock(sc, MCD_LK_LOCK);

		if ((sc->flags & MCDF_LOADED) == 0) {
			/* Partially reset the state. */
			sc->lastmode = MCD_MD_UNKNOWN;
			sc->lastupc = MCD_UPC_UNKNOWN;

			sc->flags |= MCDF_LOADED;

			/* Set the mode, causing the disk to spin up. */
			if ((error = mcd_setmode(sc, MCD_MD_COOKED)) != 0)
				goto bad2;

			/* Load the physical device parameters. */
			if (mcd_get_parms(sc) != 0) {
				error = ENXIO;
				goto bad2;
			}

			/* Read the table of contents. */
			if ((error = mcd_read_toc(sc)) != 0)
				goto bad2;

			/* Fabricate a disk label. */
			mcdgetdisklabel(sc);
		}
	}

	part = MCDPART(dev);

	MCD_TRACE("open: partition=%d disksize=%ld blksize=%d\n", part,
	    sc->disksize, sc->blksize);

	/* Check that the partition exists. */
	if (part != RAW_PART &&
	    (part >= sc->sc_dk.dk_label->d_npartitions ||
	     sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
		error = ENXIO;
		goto bad;
	}

	/* Insure only one open at a time. */
	switch (fmt) {
	case S_IFCHR:
		sc->sc_dk.dk_copenmask |= (1 << part);
		break;
	case S_IFBLK:
		sc->sc_dk.dk_bopenmask |= (1 << part);
		break;
	}
	sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;

	mutex_exit(&sc->sc_lock);
	return 0;

bad2:
	sc->flags &= ~MCDF_LOADED;

bad:
	if (sc->sc_dk.dk_openmask == 0) {
#if 0
		(void) mcd_setmode(sc, MCD_MD_SLEEP);
#endif
		(void) mcd_setlock(sc, MCD_LK_UNLOCK);
	}

bad3:
	mutex_exit(&sc->sc_lock);
	return error;
}