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; }
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; }
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; }
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); }
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); }
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)); }
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)); }
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; } }
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; } }
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; }