static int mcd_tray_move(struct cdrom_device_info * cdi, int position) { int i; if (position) { /* Eject */ /* 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; } else return -EINVAL; }
int GetQChannelInfo(struct mcd_Toc *qp) { unsigned char notUsed; int retry; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { outb(MCMD_GET_Q_CHANNEL, MCDPORT(0)); if (getMcdStatus(MCD_STATUS_DELAY) != -1) break; } if (retry >= MCD_RETRY_ATTEMPTS) return -1; if (getValue(&qp -> ctrl_addr) < 0) return -1; if (getValue(&qp -> track) < 0) return -1; if (getValue(&qp -> pointIndex) < 0) return -1; if (getValue(&qp -> trackTime.min) < 0) return -1; if (getValue(&qp -> trackTime.sec) < 0) return -1; if (getValue(&qp -> trackTime.frame) < 0) return -1; if (getValue(¬Used) < 0) return -1; if (getValue(&qp -> diskTime.min) < 0) return -1; if (getValue(&qp -> diskTime.sec) < 0) return -1; if (getValue(&qp -> diskTime.frame) < 0) return -1; return 0; }
static int mcdPlay(struct mcd_Play_msf *arg) { int retry, st = -1; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { sendMcdCmd(MCMD_PLAY_READ, arg); st = getMcdStatus(2 * MCD_STATUS_DELAY); if (st != -1) break; } return st; }
static int statusCmd(void) { int st = -1, retry; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { /* send get-status cmd */ outb(MCMD_GET_STATUS, MCDPORT(0)); st = getMcdStatus(MCD_STATUS_DELAY); if (st != -1) break; } return st; }
static int GetDiskInfo(void) { int retry; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { outb(MCMD_GET_DISK_INFO, MCDPORT(0)); if (getMcdStatus(MCD_STATUS_DELAY) != -1) break; } if (retry >= MCD_RETRY_ATTEMPTS) return -1; if (getValue(&DiskInfo.first) < 0) return -1; if (getValue(&DiskInfo.last) < 0) return -1; DiskInfo.first = bcd2bin(DiskInfo.first); DiskInfo.last = bcd2bin(DiskInfo.last); #ifdef MCD_DEBUG printk ("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n", DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min, DiskInfo.diskLength.sec, DiskInfo.diskLength.frame, DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec, DiskInfo.firstTrack.frame); #endif if (getValue(&DiskInfo.diskLength.min) < 0) return -1; if (getValue(&DiskInfo.diskLength.sec) < 0) return -1; if (getValue(&DiskInfo.diskLength.frame) < 0) return -1; if (getValue(&DiskInfo.firstTrack.min) < 0) return -1; if (getValue(&DiskInfo.firstTrack.sec) < 0) return -1; if (getValue(&DiskInfo.firstTrack.frame) < 0) return -1; return 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; } }
static int GetToc() { int i, px; int limit; int retry; struct mcd_Toc qInfo; for (i = 0; i < MAX_TRACKS; i++) Toc[i].pointIndex = 0; i = DiskInfo.last + 3; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { outb(MCMD_STOP, MCDPORT(0)); if (getMcdStatus(MCD_STATUS_DELAY) != -1) break; } if (retry >= MCD_RETRY_ATTEMPTS) return -1; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { outb(MCMD_SET_MODE, MCDPORT(0)); outb(0x05, MCDPORT(0)); /* mode: toc */ mcd_mode = 0x05; if (getMcdStatus(MCD_STATUS_DELAY) != -1) break; } if (retry >= MCD_RETRY_ATTEMPTS) return -1; for (limit = 300; limit > 0; limit--) { if (GetQChannelInfo(&qInfo) < 0) break; px = bcd2bin(qInfo.pointIndex); if (px > 0 && px < MAX_TRACKS && qInfo.track == 0) if (Toc[px].pointIndex == 0) { Toc[px] = qInfo; i--; } if (i <= 0) break; } Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { outb(MCMD_SET_MODE, MCDPORT(0)); outb(0x01, MCDPORT(0)); mcd_mode = 1; if (getMcdStatus(MCD_STATUS_DELAY) != -1) break; } #ifdef MCD_DEBUG for (i = 1; i <= DiskInfo.last; i++) printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n", i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex, Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame, Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame); for (i = 100; i < 103; i++) printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n", i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex, Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame, Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame); #endif return limit > 0 ? 0 : -1; }
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; } }