Exemplo n.º 1
0
int
mcd_toc_entries(struct mcd_softc *sc, struct ioc_read_toc_entry *te, struct cd_toc_entry *entries, int *count)
{
	int len = te->data_len;
	struct ioc_toc_header header;
	u_char trk;
	daddr_t lba;
	int error, n;

	if (len < sizeof(struct cd_toc_entry))
		return EINVAL;
	if (te->address_format != CD_MSF_FORMAT &&
	    te->address_format != CD_LBA_FORMAT)
		return EINVAL;

	/* Copy the TOC header. */
	if ((error = mcd_toc_header(sc, &header)) != 0)
		return error;

	/* Verify starting track. */
	trk = te->starting_track;
	if (trk == 0x00)
		trk = header.starting_track;
	else if (trk == 0xaa)
		trk = header.ending_track + 1;
	else if (trk < header.starting_track ||
		 trk > header.ending_track + 1)
		return EINVAL;

	/* Copy the TOC data. */
	for (n = 0; trk <= header.ending_track + 1; n++, trk++) {
		if (n * sizeof entries[0] > len)
			break;
		if (sc->toc[trk].toc.idx_no == 0x00)
			continue;
		entries[n].control = sc->toc[trk].toc.control;
		entries[n].addr_type = sc->toc[trk].toc.addr_type;
		entries[n].track = bcd2bin(sc->toc[trk].toc.idx_no);
		switch (te->address_format) {
		case CD_MSF_FORMAT:
			entries[n].addr.addr[0] = 0;
			entries[n].addr.addr[1] = bcd2bin(sc->toc[trk].toc.absolute_pos[0]);
			entries[n].addr.addr[2] = bcd2bin(sc->toc[trk].toc.absolute_pos[1]);
			entries[n].addr.addr[3] = bcd2bin(sc->toc[trk].toc.absolute_pos[2]);
			break;
		case CD_LBA_FORMAT:
			lba = msf2hsg(sc->toc[trk].toc.absolute_pos, 0);
			entries[n].addr.addr[0] = lba >> 24;
			entries[n].addr.addr[1] = lba >> 16;
			entries[n].addr.addr[2] = lba >> 8;
			entries[n].addr.addr[3] = lba;
			break;
		}
	}

	*count = n;
	return 0;
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
0
Arquivo: mcd.c Projeto: MarginC/kame
static int
mcd_toc_entry(struct mcd_softc *sc, struct ioc_read_toc_single_entry *te)
{
	struct ioc_toc_header th;
	int rc, trk;

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

	/* Copy the toc header */
	if ((rc = mcd_toc_header(sc, &th)) != 0)
		return (rc);

	/* verify starting track */
	trk = te->track;
	if (trk == 0)
		trk = th.starting_track;
	else if (trk == MCD_LASTPLUS1)
		trk = th.ending_track + 1;
	else if (trk < th.starting_track || trk > th.ending_track + 1)
		return (EINVAL);

	/* Make sure we have a valid toc */
	if ((rc=mcd_read_toc(sc)) != 0)
		return (rc);

	/* Copy the TOC data. */
	if (sc->data.toc[trk].idx_no == 0)
		return (EIO);

	te->entry.control = sc->data.toc[trk].control;
	te->entry.addr_type = sc->data.toc[trk].addr_type;
	te->entry.track =
		sc->data.toc[trk].idx_no > 0x99 ? sc->data.toc[trk].idx_no :
		bcd2bin(sc->data.toc[trk].idx_no);
	switch (te->address_format) {
	case CD_MSF_FORMAT:
		te->entry.addr.msf.unused = 0;
		te->entry.addr.msf.minute = bcd2bin(sc->data.toc[trk].hd_pos_msf[0]);
		te->entry.addr.msf.second = bcd2bin(sc->data.toc[trk].hd_pos_msf[1]);
		te->entry.addr.msf.frame = bcd2bin(sc->data.toc[trk].hd_pos_msf[2]);
		break;
	case CD_LBA_FORMAT:
		te->entry.addr.lba = htonl(msf2hsg(sc->data.toc[trk].hd_pos_msf, 0));
		break;
	}
	return (0);
}
Exemplo n.º 4
0
Arquivo: mcd.c Projeto: 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*/
}
Exemplo n.º 5
0
Arquivo: mcd.c Projeto: MarginC/kame
static int
mcd_toc_entrys(struct mcd_softc *sc, struct ioc_read_toc_entry *te)
{
	struct cd_toc_entry entries[MCD_MAXTOCS];
	struct ioc_toc_header th;
	int rc, n, trk, len;

	if (   te->data_len < sizeof(entries[0])
	    || (te->data_len % sizeof(entries[0])) != 0
	    || (te->address_format != CD_MSF_FORMAT
	        && te->address_format != CD_LBA_FORMAT)
	   )
		return (EINVAL);

	/* Copy the toc header */
	if ((rc = mcd_toc_header(sc, &th)) != 0)
		return (rc);

	/* verify starting track */
	trk = te->starting_track;
	if (trk == 0)
		trk = th.starting_track;
	else if (trk == MCD_LASTPLUS1)
		trk = th.ending_track + 1;
	else if (trk < th.starting_track || trk > th.ending_track + 1)
		return (EINVAL);

	len = ((th.ending_track + 1 - trk) + 1) *
		sizeof(entries[0]);
	if (te->data_len < len)
		len = te->data_len;
	if (len > sizeof(entries))
		return (EINVAL);

	/* Make sure we have a valid toc */
	if ((rc=mcd_read_toc(sc)) != 0)
		return (rc);

	/* Copy the TOC data. */
	for (n = 0; len > 0 && trk <= th.ending_track + 1; trk++) {
		if (sc->data.toc[trk].idx_no == 0)
			continue;
		entries[n].control = sc->data.toc[trk].control;
		entries[n].addr_type = sc->data.toc[trk].addr_type;
		entries[n].track =
			sc->data.toc[trk].idx_no > 0x99 ? sc->data.toc[trk].idx_no :
			bcd2bin(sc->data.toc[trk].idx_no);
		switch (te->address_format) {
		case CD_MSF_FORMAT:
			entries[n].addr.msf.unused = 0;
			entries[n].addr.msf.minute = bcd2bin(sc->data.toc[trk].hd_pos_msf[0]);
			entries[n].addr.msf.second = bcd2bin(sc->data.toc[trk].hd_pos_msf[1]);
			entries[n].addr.msf.frame = bcd2bin(sc->data.toc[trk].hd_pos_msf[2]);
			break;
		case CD_LBA_FORMAT:
			entries[n].addr.lba = htonl(msf2hsg(sc->data.toc[trk].hd_pos_msf, 0));
			break;
		}
		len -= sizeof(struct cd_toc_entry);
		n++;
	}

	/* copy the data back */
	return copyout(entries, te->data, n * sizeof(struct cd_toc_entry));
}
Exemplo n.º 6
0
Arquivo: mcd.c Projeto: 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);
}
Exemplo n.º 7
0
int
mcdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
{
	struct mcd_softc *sc = device_lookup_private(&mcd_cd, MCDUNIT(dev));
	int error;
	int part;
#ifdef __HAVE_OLD_DISKLABEL
	struct disklabel newlabel;
#endif
	
	MCD_TRACE("ioctl: cmd=0x%lx\n", cmd);

	if ((sc->flags & MCDF_LOADED) == 0)
		return EIO;

	error = disk_ioctl(&sc->sc_dk, dev, cmd, addr, flag, l);
	if (error != EPASSTHROUGH)
		return error;

	part = MCDPART(dev);
	switch (cmd) {
	case DIOCWDINFO:
	case DIOCSDINFO:
#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCWDINFO:
	case ODIOCSDINFO:
#endif
	{
		struct disklabel *lp;

		if ((flag & FWRITE) == 0)
			return EBADF;

#ifdef __HAVE_OLD_DISKLABEL
		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
			memset(&newlabel, 0, sizeof newlabel);
			memcpy(&newlabel, addr, sizeof (struct olddisklabel));
			lp = &newlabel;
		} else
#endif
		lp = addr;

		mutex_enter(&sc->sc_lock);
		sc->flags |= MCDF_LABELLING;

		error = setdisklabel(sc->sc_dk.dk_label,
		    lp, /*sc->sc_dk.dk_openmask : */0,
		    sc->sc_dk.dk_cpulabel);
		if (error == 0) {
		}

		sc->flags &= ~MCDF_LABELLING;
		mutex_exit(&sc->sc_lock);
		return error;
	}

	case DIOCWLABEL:
		return EBADF;

	case DIOCGDEFLABEL:
		mcdgetdefaultlabel(sc, addr);
		return 0;

#ifdef __HAVE_OLD_DISKLABEL
	case ODIOCGDEFLABEL:
		mcdgetdefaultlabel(sc, &newlabel);
		if (newlabel.d_npartitions > OLDMAXPARTITIONS)
			return ENOTTY;
		memcpy(addr, &newlabel, sizeof (struct olddisklabel));
		return 0;
#endif

	case CDIOCPLAYTRACKS:
		return mcd_playtracks(sc, addr);
	case CDIOCPLAYMSF:
		return mcd_playmsf(sc, addr);
	case CDIOCPLAYBLOCKS:
		return mcd_playblocks(sc, addr);
	case CDIOCREADSUBCHANNEL: {
		struct cd_sub_channel_info info;
		error = mcd_read_subchannel(sc, addr, &info);
		if (error != 0) {
			struct ioc_read_subchannel *ch = addr;
			error = copyout(&info, ch->data, ch->data_len);
		}
		return error;
	}
	case CDIOCREADSUBCHANNEL_BUF:
		return mcd_read_subchannel(sc, addr,
		    &((struct ioc_read_subchannel_buf *)addr)->info);
	case CDIOREADTOCHEADER:
		return mcd_toc_header(sc, addr);
	case CDIOREADTOCENTRYS: {
		struct cd_toc_entry entries[MCD_MAXTOCS];
		struct ioc_read_toc_entry *te = addr;
		int count;
		if (te->data_len > sizeof entries)
			return EINVAL;
		error = mcd_toc_entries(sc, te, entries, &count);
		if (error == 0)
			/* Copy the data back. */
			error = copyout(entries, te->data, min(te->data_len,
					count * sizeof(struct cd_toc_entry)));
		return error;
	}
	case CDIOREADTOCENTRIES_BUF: {
		struct ioc_read_toc_entry_buf *te = addr;
		int count;
		if (te->req.data_len > sizeof te->entry)
			return EINVAL;
		return mcd_toc_entries(sc, &te->req, te->entry, &count);
	}
	case CDIOCSETPATCH:
	case CDIOCGETVOL:
	case CDIOCSETVOL:
	case CDIOCSETMONO:
	case CDIOCSETSTEREO:
	case CDIOCSETMUTE:
	case CDIOCSETLEFT:
	case CDIOCSETRIGHT:
		return EINVAL;
	case CDIOCRESUME:
		return mcd_resume(sc);
	case CDIOCPAUSE:
		return mcd_pause(sc);
	case CDIOCSTART:
		return EINVAL;
	case CDIOCSTOP:
		return mcd_stop(sc);
	case DIOCEJECT:
		if (*(int *)addr == 0) {
			/*
			 * Don't force eject: check that we are the only
			 * partition open. If so, unlock it.
			 */
			if ((sc->sc_dk.dk_openmask & ~(1 << part)) == 0 &&
			    sc->sc_dk.dk_bopenmask + sc->sc_dk.dk_copenmask ==
			    sc->sc_dk.dk_openmask) {
				error = mcd_setlock(sc, MCD_LK_UNLOCK);
				if (error)
					return (error);
			} else {
				return (EBUSY);
			}
		}
		/* FALLTHROUGH */
	case CDIOCEJECT: /* FALLTHROUGH */
	case ODIOCEJECT:
		return mcd_eject(sc);
	case CDIOCALLOW:
		return mcd_setlock(sc, MCD_LK_UNLOCK);
	case CDIOCPREVENT:
		return mcd_setlock(sc, MCD_LK_LOCK);
	case DIOCLOCK:
		return mcd_setlock(sc,
		    (*(int *)addr) ? MCD_LK_LOCK : MCD_LK_UNLOCK);
	case CDIOCSETDEBUG:
		sc->debug = 1;
		return 0;
	case CDIOCCLRDEBUG:
		sc->debug = 0;
		return 0;
	case CDIOCRESET:
		return mcd_hard_reset(sc);

	default:
		return ENOTTY;
	}

#ifdef DIAGNOSTIC
	panic("mcdioctl: impossible");
#endif
}