Example #1
0
int
mcd_get_parms(struct mcd_softc *sc)
{
	struct mcd_mbox mbx;
	daddr_t size;
	int error;

	/* Send volume info command. */
	mbx.cmd.opcode = MCD_CMDGETVOLINFO;
	mbx.cmd.length = 0;
	mbx.res.length = sizeof(mbx.res.data.volinfo);
	if ((error = mcd_send(sc, &mbx, 1)) != 0)
		return error;

	if (mbx.res.data.volinfo.trk_low == 0x00 &&
	    mbx.res.data.volinfo.trk_high == 0x00)
		return EINVAL;

	/* Volinfo is OK. */
	sc->volinfo = mbx.res.data.volinfo;
	sc->blksize = MCD_BLKSIZE_COOKED;
	size = msf2hsg(sc->volinfo.vol_msf, 0);
	sc->disksize = size * (MCD_BLKSIZE_COOKED / DEV_BSIZE);
	return 0;
}
Example #2
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;
}
Example #3
0
int
mcd_toc_header(struct mcd_softc *sc, struct ioc_toc_header *th)
{

	if (sc->debug)
		printf("%s: mcd_toc_header: reading toc header\n",
		    device_xname(sc->sc_dev));

	th->len = msf2hsg(sc->volinfo.vol_msf, 0);
	th->starting_track = bcd2bin(sc->volinfo.trk_low);
	th->ending_track = bcd2bin(sc->volinfo.trk_high);

	return 0;
}
Example #4
0
File: mcd.c Project: 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);
}
Example #5
0
File: mcd.c Project: MarginC/kame
static int
mcdsize(dev_t dev)
{
	struct mcd_softc *sc;
	int size;

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

	if (mcd_volinfo(sc) == 0) {
		sc->data.blksize = MCDBLK;
		size = msf2hsg(sc->data.volinfo.vol_msf, 0);
		sc->data.disksize = size * (MCDBLK/DEV_BSIZE);
		return (0);
	}
	return (-1);
}
Example #6
0
File: mcd.c Project: 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));
}
Example #7
0
File: mcd.c Project: 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));
}
Example #8
0
int mcd_audio_ioctl(struct cdrom_device_info * cdi, unsigned int cmd,
                      void * arg)
{
	int i, st;
	struct mcd_Toc qInfo;
	struct cdrom_ti *ti;
	struct cdrom_tochdr *tocHdr;
	struct cdrom_msf *msf;
	struct cdrom_subchnl *subchnl;
	struct cdrom_tocentry *entry;
	struct mcd_Toc *tocPtr;
	struct cdrom_volctrl *volctrl;

	st = statusCmd();
	if (st < 0)
		return -EIO;

	if (!tocUpToDate)
	{
		i = updateToc();
		if (i < 0) 
			return i;	/* error reading TOC */
	}

	switch (cmd)
	{
	case CDROMSTART:     /* Spin up the drive */
		/* Don't think we can do this.  Even if we could,
 		 * I think the drive times out and stops after a while
		 * anyway.  For now, ignore it.
		 */

		return 0;

	case CDROMSTOP:      /* Spin down the drive */
		outb(MCMD_STOP, MCDPORT(0));
		i = getMcdStatus(MCD_STATUS_DELAY);

		/* should we do anything if it fails? */

		audioStatus = CDROM_AUDIO_NO_STATUS;
		return 0;

	case CDROMPAUSE:     /* Pause the drive */
		if (audioStatus != CDROM_AUDIO_PLAY)
			return -EINVAL;

		outb(MCMD_STOP, MCDPORT(0));
		i = getMcdStatus(MCD_STATUS_DELAY);

		if (GetQChannelInfo(&qInfo) < 0)
		{
			/* didn't get q channel info */

			audioStatus = CDROM_AUDIO_NO_STATUS;
			return 0;
		}

		mcd_Play.start = qInfo.diskTime;	/* remember restart point */

		audioStatus = CDROM_AUDIO_PAUSED;
		return 0;

	case CDROMRESUME:    /* Play it again, Sam */
		if (audioStatus != CDROM_AUDIO_PAUSED)
			return -EINVAL;

		/* restart the drive at the saved position. */

		i = mcdPlay(&mcd_Play);
		if (i < 0)
		{
			audioStatus = CDROM_AUDIO_ERROR;
			return -EIO;
		}

		audioStatus = CDROM_AUDIO_PLAY;
		return 0;

	case CDROMPLAYTRKIND:     /* Play a track.  This currently ignores index. */

		ti=(struct cdrom_ti *) arg;

		if (ti->cdti_trk0 < DiskInfo.first
			|| ti->cdti_trk0 > DiskInfo.last
			|| ti->cdti_trk1 < ti->cdti_trk0)
		{
			return -EINVAL;
		}

		if (ti->cdti_trk1 > DiskInfo.last)
			ti->cdti_trk1 = DiskInfo.last;

		mcd_Play.start = Toc[ti->cdti_trk0].diskTime;
		mcd_Play.end = Toc[ti->cdti_trk1 + 1].diskTime;

#ifdef MCD_DEBUG
printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
	mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
	mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
#endif

		i = mcdPlay(&mcd_Play);
		if (i < 0)
		{
			audioStatus = CDROM_AUDIO_ERROR;
			return -EIO;
		}

		audioStatus = CDROM_AUDIO_PLAY;
		return 0;

	case CDROMPLAYMSF:   /* Play starting at the given MSF address. */

		if (audioStatus == CDROM_AUDIO_PLAY) {
		  outb(MCMD_STOP, MCDPORT(0));
		  i = getMcdStatus(MCD_STATUS_DELAY);
		  audioStatus = CDROM_AUDIO_NO_STATUS;
		}

		msf=(struct cdrom_msf *) arg;

		/* convert to bcd */

		bin2bcd(&msf->cdmsf_min0);
		bin2bcd(&msf->cdmsf_sec0);
		bin2bcd(&msf->cdmsf_frame0);
		bin2bcd(&msf->cdmsf_min1);
		bin2bcd(&msf->cdmsf_sec1);
		bin2bcd(&msf->cdmsf_frame1);

		mcd_Play.start.min = msf->cdmsf_min0;
		mcd_Play.start.sec = msf->cdmsf_sec0;
		mcd_Play.start.frame = msf->cdmsf_frame0;
		mcd_Play.end.min = msf->cdmsf_min1;
		mcd_Play.end.sec = msf->cdmsf_sec1;
		mcd_Play.end.frame = msf->cdmsf_frame1;

#ifdef MCD_DEBUG
printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
#endif

		i = mcdPlay(&mcd_Play);
		if (i < 0)
		{
			audioStatus = CDROM_AUDIO_ERROR;
			return -EIO;
		}

		audioStatus = CDROM_AUDIO_PLAY;
		return 0;

	case CDROMREADTOCHDR:        /* Read the table of contents header */
	        tocHdr=(struct cdrom_tochdr *) arg; 
		tocHdr->cdth_trk0 = DiskInfo.first;
		tocHdr->cdth_trk1 = DiskInfo.last;
		return 0;

	case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
		entry=(struct cdrom_tocentry *) arg;
		if (entry->cdte_track == CDROM_LEADOUT)
			tocPtr = &Toc[DiskInfo.last - DiskInfo.first + 1];

		else if (entry->cdte_track > DiskInfo.last
				|| entry->cdte_track < DiskInfo.first)
			return -EINVAL;

		else
			tocPtr = &Toc[entry->cdte_track];

		entry->cdte_adr = tocPtr -> ctrl_addr;
		entry->cdte_ctrl = tocPtr -> ctrl_addr >> 4;

		if (entry->cdte_format == CDROM_LBA)
			entry->cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);

		else if (entry->cdte_format == CDROM_MSF)
		{
			entry->cdte_addr.msf.minute = bcd2bin(tocPtr -> diskTime.min);
			entry->cdte_addr.msf.second = bcd2bin(tocPtr -> diskTime.sec);
			entry->cdte_addr.msf.frame = bcd2bin(tocPtr -> diskTime.frame);
		}

		else
			return -EINVAL;

		return 0;

	case CDROMSUBCHNL:   /* Get subchannel info */

                subchnl=(struct cdrom_subchnl *) arg;
		if (GetQChannelInfo(&qInfo) < 0)
			return -EIO;

		subchnl->cdsc_audiostatus = audioStatus;
		subchnl->cdsc_adr = qInfo.ctrl_addr;
		subchnl->cdsc_ctrl = qInfo.ctrl_addr >> 4;
		subchnl->cdsc_trk = bcd2bin(qInfo.track);
		subchnl->cdsc_ind = bcd2bin(qInfo.pointIndex);
		subchnl->cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
		subchnl->cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
		subchnl->cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame);
		subchnl->cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
		subchnl->cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
		subchnl->cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame);
		return(0);

	case CDROMVOLCTRL:   /* Volume control */
		volctrl=(struct cdrom_volctrl *) arg;
		outb(MCMD_SET_VOLUME, MCDPORT(0));
		outb(volctrl->channel0, MCDPORT(0));
		outb(255, MCDPORT(0));
		outb(volctrl->channel1, MCDPORT(0));
		outb(255, MCDPORT(0));

		i = getMcdStatus(MCD_STATUS_DELAY);
		if (i < 0)
			return -EIO;

		{
			char a, b, c, d;

			getValue(&a);
			getValue(&b);
			getValue(&c);
			getValue(&d);
		}

		return 0;

	default:
		return -EINVAL;
	}
}
Example #9
0
static int
mcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
          unsigned long arg)
{
    int i, st;
    struct mcd_Toc qInfo;
    struct cdrom_ti ti;
    struct cdrom_tochdr tocHdr;
    struct cdrom_msf msf;
    struct cdrom_tocentry entry;
    struct mcd_Toc *tocPtr;
    struct cdrom_subchnl subchnl;
    struct cdrom_volctrl volctrl;

    if (!ip)
        return -EINVAL;

    st = statusCmd();
    if (st < 0)
        return -EIO;

    if (!tocUpToDate)
    {
        i = updateToc();
        if (i < 0)
            /* [email protected]:
            We _can_ open the door even without a CD */
            if (cmd != CDROMEJECT)
                return i;	/* error reading TOC */
    }

    switch (cmd)
    {
    case CDROMSTART:     /* Spin up the drive */
        /* Don't think we can do this.  Even if we could,
         * I think the drive times out and stops after a while
         * anyway.  For now, ignore it.
         */

        return 0;

    case CDROMSTOP:      /* Spin down the drive */
        outb(MCMD_STOP, MCDPORT(0));
        i = getMcdStatus(MCD_STATUS_DELAY);

        /* should we do anything if it fails? */

        audioStatus = CDROM_AUDIO_NO_STATUS;
        return 0;

    case CDROMPAUSE:     /* Pause the drive */
        if (audioStatus != CDROM_AUDIO_PLAY)
            return -EINVAL;

        outb(MCMD_STOP, MCDPORT(0));
        i = getMcdStatus(MCD_STATUS_DELAY);

        if (GetQChannelInfo(&qInfo) < 0)
        {
            /* didn't get q channel info */

            audioStatus = CDROM_AUDIO_NO_STATUS;
            return 0;
        }

        mcd_Play.start = qInfo.diskTime;	/* remember restart point */

        audioStatus = CDROM_AUDIO_PAUSED;
        return 0;

    case CDROMRESUME:    /* Play it again, Sam */
        if (audioStatus != CDROM_AUDIO_PAUSED)
            return -EINVAL;

        /* restart the drive at the saved position. */

        i = mcdPlay(&mcd_Play);
        if (i < 0)
        {
            audioStatus = CDROM_AUDIO_ERROR;
            return -EIO;
        }

        audioStatus = CDROM_AUDIO_PLAY;
        return 0;

    case CDROMPLAYTRKIND:     /* Play a track.  This currently ignores index. */

        st = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
        if (st)
            return st;

        memcpy_fromfs(&ti, (void *) arg, sizeof ti);

        if (ti.cdti_trk0 < DiskInfo.first
                || ti.cdti_trk0 > DiskInfo.last
                || ti.cdti_trk1 < ti.cdti_trk0)
        {
            return -EINVAL;
        }

        if (ti.cdti_trk1 > DiskInfo.last)
            ti. cdti_trk1 = DiskInfo.last;

        mcd_Play.start = Toc[ti.cdti_trk0].diskTime;
        mcd_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;

#ifdef MCD_DEBUG
        printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
               mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
               mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
#endif

        i = mcdPlay(&mcd_Play);
        if (i < 0)
        {
            audioStatus = CDROM_AUDIO_ERROR;
            return -EIO;
        }

        audioStatus = CDROM_AUDIO_PLAY;
        return 0;

    case CDROMPLAYMSF:   /* Play starting at the given MSF address. */

        if (audioStatus == CDROM_AUDIO_PLAY) {
            outb(MCMD_STOP, MCDPORT(0));
            i = getMcdStatus(MCD_STATUS_DELAY);
            audioStatus = CDROM_AUDIO_NO_STATUS;
        }

        st = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
        if (st)
            return st;

        memcpy_fromfs(&msf, (void *) arg, sizeof msf);

        /* convert to bcd */

        bin2bcd(&msf.cdmsf_min0);
        bin2bcd(&msf.cdmsf_sec0);
        bin2bcd(&msf.cdmsf_frame0);
        bin2bcd(&msf.cdmsf_min1);
        bin2bcd(&msf.cdmsf_sec1);
        bin2bcd(&msf.cdmsf_frame1);

        mcd_Play.start.min = msf.cdmsf_min0;
        mcd_Play.start.sec = msf.cdmsf_sec0;
        mcd_Play.start.frame = msf.cdmsf_frame0;
        mcd_Play.end.min = msf.cdmsf_min1;
        mcd_Play.end.sec = msf.cdmsf_sec1;
        mcd_Play.end.frame = msf.cdmsf_frame1;

#ifdef MCD_DEBUG
        printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
               mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
               mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
#endif

        i = mcdPlay(&mcd_Play);
        if (i < 0)
        {
            audioStatus = CDROM_AUDIO_ERROR;
            return -EIO;
        }

        audioStatus = CDROM_AUDIO_PLAY;
        return 0;

    case CDROMREADTOCHDR:        /* Read the table of contents header */
        st = verify_area(VERIFY_WRITE, (void *) arg, sizeof tocHdr);
        if (st)
            return st;

        tocHdr.cdth_trk0 = DiskInfo.first;
        tocHdr.cdth_trk1 = DiskInfo.last;
        memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
        return 0;

    case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */

        st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
        if (st)
            return st;

        memcpy_fromfs(&entry, (void *) arg, sizeof entry);
        if (entry.cdte_track == CDROM_LEADOUT)
            /* XXX */
            tocPtr = &Toc[DiskInfo.last + 1];

        else if (entry.cdte_track > DiskInfo.last
                 || entry.cdte_track < DiskInfo.first)
            return -EINVAL;

        else
            tocPtr = &Toc[entry.cdte_track];

        entry.cdte_adr = tocPtr -> ctrl_addr;
        entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;

        if (entry.cdte_format == CDROM_LBA)
            entry.cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);

        else if (entry.cdte_format == CDROM_MSF)
        {
            entry.cdte_addr.msf.minute = bcd2bin(tocPtr -> diskTime.min);
            entry.cdte_addr.msf.second = bcd2bin(tocPtr -> diskTime.sec);
            entry.cdte_addr.msf.frame = bcd2bin(tocPtr -> diskTime.frame);
        }

        else
            return -EINVAL;

        memcpy_tofs((void *) arg, &entry, sizeof entry);
        return 0;

    case CDROMSUBCHNL:   /* Get subchannel info */

        st = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
        if (st)
            return st;

        memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);

        if (GetQChannelInfo(&qInfo) < 0)
            return -EIO;

        subchnl.cdsc_audiostatus = audioStatus;
        subchnl.cdsc_adr = qInfo.ctrl_addr;
        subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
        subchnl.cdsc_trk = bcd2bin(qInfo.track);
        subchnl.cdsc_ind = bcd2bin(qInfo.pointIndex);

        if (subchnl.cdsc_format == CDROM_LBA)
        {
            subchnl.cdsc_absaddr.lba = msf2hsg(&qInfo.diskTime);
            subchnl.cdsc_reladdr.lba = msf2hsg(&qInfo.trackTime);
        }

        else if (subchnl.cdsc_format == CDROM_MSF)
        {
            subchnl.cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
            subchnl.cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
            subchnl.cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame);

            subchnl.cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
            subchnl.cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
            subchnl.cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame);
        }

        else
            return -EINVAL;

        memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
        return 0;

    case CDROMVOLCTRL:   /* Volume control */
        st = verify_area(VERIFY_READ, (void *) arg, sizeof(volctrl));
        if (st)
            return st;

        memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
        outb(MCMD_SET_VOLUME, MCDPORT(0));
        outb(volctrl.channel0, MCDPORT(0));
        outb(255, MCDPORT(0));
        outb(volctrl.channel1, MCDPORT(0));
        outb(255, MCDPORT(0));

        i = getMcdStatus(MCD_STATUS_DELAY);
        if (i < 0)
            return -EIO;

        {
            char a, b, c, d;

            getValue(&a);
            getValue(&b);
            getValue(&c);
            getValue(&d);
        }

        return 0;

    case CDROMEJECT:
        /* all drives can at least stop! */
        if (audioStatus == CDROM_AUDIO_PLAY) {
            outb(MCMD_STOP, MCDPORT(0));
            i = getMcdStatus(MCD_STATUS_DELAY);
        }

        audioStatus = CDROM_AUDIO_NO_STATUS;

        outb(MCMD_EJECT, MCDPORT(0));
        /*
         * the status (i) shows failure on all but the FX drives.
         * But nothing we can do about that in software!
         * So just read the status and forget it. - Jon.
         */
        i = getMcdStatus(MCD_STATUS_DELAY);
        return 0;
    default:
        return -EINVAL;
    }
}
Example #10
0
int
mcd_read_subchannel(struct mcd_softc *sc, struct ioc_read_subchannel *ch, struct cd_sub_channel_info *info)
{
	int len = ch->data_len;
	union mcd_qchninfo q;
	daddr_t lba;
	int error;

	if (sc->debug)
		printf("%s: subchan: af=%d df=%d\n", device_xname(sc->sc_dev),
		    ch->address_format, ch->data_format);

	if (len > sizeof(*info) || len < sizeof(info->header))
		return EINVAL;
	if (ch->address_format != CD_MSF_FORMAT &&
	    ch->address_format != CD_LBA_FORMAT)
		return EINVAL;
	if (ch->data_format != CD_CURRENT_POSITION &&
	    ch->data_format != CD_MEDIA_CATALOG)
		return EINVAL;

	if ((error = mcd_getqchan(sc, &q, ch->data_format)) != 0)
		return error;

	info->header.audio_status = sc->audio_status;
	info->what.media_catalog.data_format = ch->data_format;

	switch (ch->data_format) {
	case CD_MEDIA_CATALOG:
		info->what.media_catalog.mc_valid = 1;
#if 0
		info->what.media_catalog.mc_number =
#endif
		break;

	case CD_CURRENT_POSITION:
		info->what.position.track_number = bcd2bin(q.current.trk_no);
		info->what.position.index_number = bcd2bin(q.current.idx_no);
		switch (ch->address_format) {
		case CD_MSF_FORMAT:
			info->what.position.reladdr.addr[0] = 0;
			info->what.position.reladdr.addr[1] = bcd2bin(q.current.relative_pos[0]);
			info->what.position.reladdr.addr[2] = bcd2bin(q.current.relative_pos[1]);
			info->what.position.reladdr.addr[3] = bcd2bin(q.current.relative_pos[2]);
			info->what.position.absaddr.addr[0] = 0;
			info->what.position.absaddr.addr[1] = bcd2bin(q.current.absolute_pos[0]);
			info->what.position.absaddr.addr[2] = bcd2bin(q.current.absolute_pos[1]);
			info->what.position.absaddr.addr[3] = bcd2bin(q.current.absolute_pos[2]);
			break;
		case CD_LBA_FORMAT:
			lba = msf2hsg(q.current.relative_pos, 1);
			/*
			 * Pre-gap has index number of 0, and decreasing MSF
			 * address.  Must be converted to negative LBA, per
			 * SCSI spec.
			 */
			if (info->what.position.index_number == 0x00)
				lba = -lba;
			info->what.position.reladdr.addr[0] = lba >> 24;
			info->what.position.reladdr.addr[1] = lba >> 16;
			info->what.position.reladdr.addr[2] = lba >> 8;
			info->what.position.reladdr.addr[3] = lba;
			lba = msf2hsg(q.current.absolute_pos, 0);
			info->what.position.absaddr.addr[0] = lba >> 24;
			info->what.position.absaddr.addr[1] = lba >> 16;
			info->what.position.absaddr.addr[2] = lba >> 8;
			info->what.position.absaddr.addr[3] = lba;
			break;
		}
		break;
	}

	return 0;
}