static int mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti) { struct s_subqcode *p; struct cdrom_msf msf; if (-1 == mcdx_readtoc(stuffp)) return -1; if (ti) p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first]; else p = &stuffp->start; msf.cdmsf_min0 = p->dt.minute; msf.cdmsf_sec0 = p->dt.second; msf.cdmsf_frame0 = p->dt.frame; if (ti) { p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1]; stuffp->stop = *p; } else p = &stuffp->stop; msf.cdmsf_min1 = p->dt.minute; msf.cdmsf_sec1 = p->dt.second; msf.cdmsf_frame1 = p->dt.frame; return mcdx_playmsf(stuffp, &msf); }
static int mcdx_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) { struct s_drive_stuff *stuffp = cdi->handle; if (!stuffp->present) return -ENXIO; if (stuffp->xxx) { if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) { stuffp->lastsector = -1; } else { stuffp->lastsector = (CD_FRAMESIZE / 512) * msf2log(&stuffp->di.msf_leadout) - 1; } if (stuffp->toc) { kfree(stuffp->toc); stuffp->toc = NULL; if (-1 == mcdx_readtoc(stuffp)) return -1; } stuffp->xxx = 0; } switch (cmd) { case CDROMSTART:{ xtrace(IOCTL, "ioctl() START\n"); /* Spin up the drive. Don't think we can do this. * For now, ignore it. */ return 0; } case CDROMSTOP:{ xtrace(IOCTL, "ioctl() STOP\n"); stuffp->audiostatus = CDROM_AUDIO_INVALID; if (-1 == mcdx_stop(stuffp, 1)) return -EIO; return 0; } case CDROMPLAYTRKIND:{ struct cdrom_ti *ti = (struct cdrom_ti *) arg; xtrace(IOCTL, "ioctl() PLAYTRKIND\n"); if ((ti->cdti_trk0 < stuffp->di.n_first) || (ti->cdti_trk0 > stuffp->di.n_last) || (ti->cdti_trk1 < stuffp->di.n_first)) return -EINVAL; if (ti->cdti_trk1 > stuffp->di.n_last) ti->cdti_trk1 = stuffp->di.n_last; xtrace(PLAYTRK, "ioctl() track %d to %d\n", ti->cdti_trk0, ti->cdti_trk1); return mcdx_playtrk(stuffp, ti); } case CDROMPLAYMSF:{ struct cdrom_msf *msf = (struct cdrom_msf *) arg; xtrace(IOCTL, "ioctl() PLAYMSF\n"); if ((stuffp->audiostatus == CDROM_AUDIO_PLAY) && (-1 == mcdx_hold(stuffp, 1))) return -EIO; msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0); msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0); msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0); msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1); msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1); msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1); stuffp->stop.dt.minute = msf->cdmsf_min1; stuffp->stop.dt.second = msf->cdmsf_sec1; stuffp->stop.dt.frame = msf->cdmsf_frame1; return mcdx_playmsf(stuffp, msf); } case CDROMRESUME:{ xtrace(IOCTL, "ioctl() RESUME\n"); return mcdx_playtrk(stuffp, NULL); } case CDROMREADTOCENTRY:{ struct cdrom_tocentry *entry = (struct cdrom_tocentry *) arg; struct s_subqcode *tp = NULL; xtrace(IOCTL, "ioctl() READTOCENTRY\n"); if (-1 == mcdx_readtoc(stuffp)) return -1; if (entry->cdte_track == CDROM_LEADOUT) tp = &stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1]; else if (entry->cdte_track > stuffp->di.n_last || entry->cdte_track < stuffp->di.n_first) return -EINVAL; else tp = &stuffp->toc[entry->cdte_track - stuffp->di.n_first]; if (NULL == tp) return -EIO; entry->cdte_adr = tp->control; entry->cdte_ctrl = tp->control >> 4; /* Always return stuff in MSF, and let the Uniform cdrom driver worry about what the user actually wants */ entry->cdte_addr.msf.minute = bcd2uint(tp->dt.minute); entry->cdte_addr.msf.second = bcd2uint(tp->dt.second); entry->cdte_addr.msf.frame = bcd2uint(tp->dt.frame); return 0; } case CDROMSUBCHNL:{ struct cdrom_subchnl *sub = (struct cdrom_subchnl *) arg; struct s_subqcode q; xtrace(IOCTL, "ioctl() SUBCHNL\n"); if (-1 == mcdx_requestsubqcode(stuffp, &q, 2)) return -EIO; xtrace(SUBCHNL, "audiostatus: %x\n", stuffp->audiostatus); sub->cdsc_audiostatus = stuffp->audiostatus; sub->cdsc_adr = q.control; sub->cdsc_ctrl = q.control >> 4; sub->cdsc_trk = bcd2uint(q.tno); sub->cdsc_ind = bcd2uint(q.index); xtrace(SUBCHNL, "trk %d, ind %d\n", sub->cdsc_trk, sub->cdsc_ind); /* Always return stuff in MSF, and let the Uniform cdrom driver worry about what the user actually wants */ sub->cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute); sub->cdsc_absaddr.msf.second = bcd2uint(q.dt.second); sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame); sub->cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute); sub->cdsc_reladdr.msf.second = bcd2uint(q.tt.second); sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame); xtrace(SUBCHNL, "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n", sub->cdsc_absaddr.msf.minute, sub->cdsc_absaddr.msf.second, sub->cdsc_absaddr.msf.frame, sub->cdsc_reladdr.msf.minute, sub->cdsc_reladdr.msf.second, sub->cdsc_reladdr.msf.frame); return 0; } case CDROMREADTOCHDR:{ struct cdrom_tochdr *toc = (struct cdrom_tochdr *) arg; xtrace(IOCTL, "ioctl() READTOCHDR\n"); toc->cdth_trk0 = stuffp->di.n_first; toc->cdth_trk1 = stuffp->di.n_last; xtrace(TOCHDR, "ioctl() track0 = %d, track1 = %d\n", stuffp->di.n_first, stuffp->di.n_last); return 0; } case CDROMPAUSE:{ xtrace(IOCTL, "ioctl() PAUSE\n"); if (stuffp->audiostatus != CDROM_AUDIO_PLAY) return -EINVAL; if (-1 == mcdx_stop(stuffp, 1)) return -EIO; stuffp->audiostatus = CDROM_AUDIO_PAUSED; if (-1 == mcdx_requestsubqcode(stuffp, &stuffp->start, 1)) return -EIO; return 0; } case CDROMMULTISESSION:{ struct cdrom_multisession *ms = (struct cdrom_multisession *) arg; xtrace(IOCTL, "ioctl() MULTISESSION\n"); /* Always return stuff in LBA, and let the Uniform cdrom driver worry about what the user actually wants */ ms->addr.lba = msf2log(&stuffp->multi.msf_last); ms->xa_flag = !!stuffp->multi.multi; xtrace(MS, "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n", ms->xa_flag, ms->addr.lba, stuffp->multi.msf_last.minute, stuffp->multi.msf_last.second, stuffp->multi.msf_last.frame); return 0; } case CDROMEJECT:{ xtrace(IOCTL, "ioctl() EJECT\n"); if (stuffp->users > 1) return -EBUSY; return (mcdx_tray_move(cdi, 1)); } case CDROMCLOSETRAY:{ xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n"); return (mcdx_tray_move(cdi, 0)); } case CDROMVOLCTRL:{ struct cdrom_volctrl *volctrl = (struct cdrom_volctrl *) arg; xtrace(IOCTL, "ioctl() VOLCTRL\n"); #if 0 /* not tested! */ /* adjust for the weirdness of workman (md) */ /* can't test it (hs) */ volctrl.channel2 = volctrl.channel1; volctrl.channel1 = volctrl.channel3 = 0x00; #endif return mcdx_setattentuator(stuffp, volctrl, 2); } default: return -EINVAL; } }