📄 mcd.c
字号:
if (mcd_get_status(0) != -1 &&
!(McdStatus & DISK_ERROR)) break;
}
if (i == MCD_RETRIES) return EIO; /* Operation failed */
return OK; /* Operation succeeded */
}
/*=========================================================================*
* mcd_send_command *
*=========================================================================*/
PRIVATE int mcd_send_command(command)
int command; /* command to send */
{
int i;
for (i = 0; i < MCD_RETRIES; i++)
{
out_byte(MCD_DATA_PORT, command); /* send command */
if (mcd_get_status(0) != -1 &&
!(McdStatus & DISK_ERROR)) break;
}
if (i == MCD_RETRIES) return EIO; /* operation failed */
return OK;
}
/*=========================================================================*
* mcd_init *
*=========================================================================*/
PRIVATE int mcd_init()
{
/* Initialize the drive and get the version bytes, this is done only
once when the system gets up. We can't use mcd_ready because
the clock task is not available yet.
*/
u8_t version[3];
int i;
u32_t n;
struct milli_state ms;
/* Reset the flag port and remove all pending data, if we do
* not do this properly the drive won't cooperate.
*/
out_byte(MCD_FLAG_PORT, 0x00);
for (n = 0; n < 1000000; n++)
(void) in_byte(MCD_FLAG_PORT);
/* Now see if the drive will report its status */
if (mcd_get_status(1) == -1)
{
/* Too bad, drive will not listen */
printf("%s: init failed, no Mitsumi cdrom present\n", mcd_name());
return -1;
}
/* Find out drive version */
out_byte(MCD_DATA_PORT, MCD_GET_VERSION);
milli_start(&ms);
for (i = 0; i < 3; i++)
{
while (in_byte(MCD_FLAG_PORT) & MCD_BUSY)
{
if (milli_elapsed(&ms) >= 1000)
{
printf("%s: can't get version of Mitsumi cdrom\n", mcd_name());
return -1;
}
}
version[i] = in_byte(MCD_DATA_PORT);
}
if (version[1] == 'D')
printf("%s: Mitsumi FX001D CD-ROM\n", mcd_name());
else
printf("%s: Mitsumi CD-ROM version %02x%02x%02x\n", mcd_name(),
version[0], version[1], version[2]);
/* Newer drive models need this */
if (version[1] >= 4) out_byte(MCD_CONTROL_PORT, MCD_PICKLE);
/* Register interrupt vector and enable interrupt
* currently the interrupt is not used because
* the controller isn't set up to do dma. XXX
*/
put_irq_handler(mcd_irq, c_handler);
enable_irq(mcd_irq);
mcd_avail = 1;
return OK;
}
/*=========================================================================*
* c_handler *
*=========================================================================*/
PRIVATE int c_handler(irq)
int irq; /* irq number */
{
/* The interrupt handler, I never got an interrupt but its here just
* in case...
*/
/* Send interrupt message to cdrom task */
#if XXX
#if __minix_vmd
interrupt(mcd_tasknr);
#else
interrupt(CDROM);
#endif
#endif
return 1;
}
/*=========================================================================*
* mcd_play_mss *
*=========================================================================*/
PRIVATE int mcd_play_mss(mss)
struct cd_play_mss mss; /* from where to play minute:second.sector */
{
/* Command the drive to start playing at min:sec.sector */
int i;
#if MCD_DEBUG >= 1
printf("Play_mss: begin: %02d:%02d.%02d end: %02d:%02d.%02d\n",
mss.begin_mss[MINUTES], mss.begin_mss[SECONDS],
mss.begin_mss[SECTOR], mss.end_mss[MINUTES],
mss.end_mss[SECONDS], mss.end_mss[SECTOR]);
#endif
for (i=0; i < MCD_RETRIES; i++) /* Try it more than once */
{
lock(); /* No interrupts when we issue this command */
/* Send command with paramters to drive */
out_byte(MCD_DATA_PORT, MCD_READ_FROM_TO);
out_byte(MCD_DATA_PORT, bin2bcd(mss.begin_mss[MINUTES]));
out_byte(MCD_DATA_PORT, bin2bcd(mss.begin_mss[SECONDS]));
out_byte(MCD_DATA_PORT, bin2bcd(mss.begin_mss[SECTOR]));
out_byte(MCD_DATA_PORT, bin2bcd(mss.end_mss[MINUTES]));
out_byte(MCD_DATA_PORT, bin2bcd(mss.end_mss[SECONDS]));
out_byte(MCD_DATA_PORT, bin2bcd(mss.end_mss[SECTOR]));
unlock(); /* Enable interrupts again */
mcd_get_status(0); /* See if all went well */
if (McdStatus & AUDIO_PLAYING) break; /* Ok, we're playing */
}
if (i == MCD_RETRIES) return EIO; /* Command failed */
/* keep in mind where we going in case of a future resume */
PlayMss.end_mss[MINUTES] = mss.end_mss[MINUTES];
PlayMss.end_mss[SECONDS] = mss.end_mss[SECONDS];
PlayMss.end_mss[SECTOR] = mss.end_mss[SECTOR];
McdStatus &= ~(AUDIO_PAUSED);
return(OK);
}
/*=========================================================================*
* mcd_play_tracks *
*=========================================================================*/
PRIVATE int mcd_play_tracks(tracks)
struct cd_play_track tracks; /* which tracks to play */
{
/* Command the drive to play tracks */
int i, err;
struct cd_play_mss mss;
#if MCD_DEBUG >= 1
printf("Play tracks: begin: %02d end: %02d\n",
tracks.begin_track, tracks.end_track);
#endif
/* First read the table of contents */
if ((err = mcd_read_toc()) != OK) return err;
/* Check if parameters are valid */
if (tracks.begin_track < DiskInfo.first_track ||
tracks.end_track > DiskInfo.last_track ||
tracks.begin_track > tracks.end_track)
return EINVAL;
/* Convert the track numbers to min:sec.sector */
for (i=0; i<3; i++)
{
mss.begin_mss[i] = Toc[tracks.begin_track].position_mss[i];
mss.end_mss[i] = Toc[tracks.end_track+1].position_mss[i];
}
return(mcd_play_mss(mss)); /* Start playing */
}
/*=========================================================================*
* mcd_get_disk_info *
*=========================================================================*/
PRIVATE int mcd_get_disk_info()
{
/* Get disk info */
int i, err;
if (McdStatus & INFO_UPTODATE) return OK; /* No need to read info again */
/* Issue the get volume info command */
if ((err = mcd_send_command(MCD_GET_VOL_INFO)) != OK) return err;
/* Fill global DiskInfo */
for (i=0; i < sizeof(DiskInfo); i++)
{
if ((err = mcd_get_reply((u8_t *)(&DiskInfo) + i, REPLY_DELAY)) !=OK)
return err;
bcd2bin((u8_t *)(&DiskInfo) + i);
}
#if MCD_DEBUG >= 1
printf("Mitsumi disk info: first: %d last: %d first %02d:%02d.%02d length: %02d:%02d.%02d\n",
DiskInfo.first_track,
DiskInfo.last_track,
DiskInfo.first_track_mss[MINUTES],
DiskInfo.first_track_mss[SECONDS],
DiskInfo.first_track_mss[SECTOR],
DiskInfo.disk_length_mss[MINUTES],
DiskInfo.disk_length_mss[SECONDS],
DiskInfo.disk_length_mss[SECTOR]);
#endif
/* Update global status info */
McdStatus |= INFO_UPTODATE; /* toc header has been read */
McdStatus &= ~TOC_UPTODATE; /* toc has not been read yet */
return OK;
}
/*=========================================================================*
* mcd_read_q_channel *
*=========================================================================*/
PRIVATE int mcd_read_q_channel(qc)
struct cd_toc_entry *qc; /* struct to return q-channel info in */
{
/* Read the qchannel info, if we we're already playing this returns
* the relative position and the absolute position of where we are
* in min:sec.sector. If we're not playing, this returns an entry
* from the table of contents
*/
int i, err;
/* Issue the command */
if ((err = mcd_send_command(MCD_GET_Q_CHANNEL)) != OK) return err;
/* Read the info */
for (i=0; i < sizeof(struct cd_toc_entry); i++)
{
/* Return error on timeout */
if ((err = mcd_get_reply((u8_t *)qc + i, REPLY_DELAY)) != OK)
return err;
bcd2bin((u8_t *)qc + i); /* Convert value to binary */
}
#if MCD_DEBUG >= 2
printf("qchannel info: ctl_addr: %d track: %d index: %d length %02d:%02d.%02d pos: %02d:%02d.%02d\n",
qc->control_address,
qc->track_nr,
qc->index_nr,
qc->track_time_mss[MINUTES],
qc->track_time_mss[SECONDS],
qc->track_time_mss[SECTOR],
qc->position_mss[MINUTES],
qc->position_mss[SECONDS],
qc->position_mss[SECTOR]);
#endif
return OK; /* All done */
}
/*=========================================================================*
* mcd_read_toc *
*=========================================================================*/
PRIVATE int mcd_read_toc()
{
/* Read the table of contents (TOC) */
struct cd_toc_entry q_info;
int current_track, current_index;
int err,i;
if (McdStatus & TOC_UPTODATE) return OK; /* No need to read toc again */
/* Clear toc table */
for (i = 0; i < MAX_TRACKS; i++) Toc[i].index_nr = 0;
/* Read disk info */
if ((err = mcd_get_disk_info()) != OK) return err;
/* Calculate track to start with */
current_track = DiskInfo.last_track - DiskInfo.first_track + 1;
/* Set read toc mode */
if ((err = mcd_set_mode(MCD_TOC)) != OK) return err;
/* Read the complete TOC, on every read-q-channel command we get a random
* TOC entry depending on how far we are in the q-channel, collect entries
* as long as we don't have the complete TOC. There's a limit of 600 here,
* if we don't have the complete TOC after 600 reads we quit with an error
*/
for (i = 0; (i < 600 && current_track > 0); i++)
{
/* Try to read a TOC entry */
if ((err = mcd_read_q_channel(&q_info)) != OK) break;
/* Is this a valid track number and didn't we have it yet ? */
current_index = q_info.index_nr;
if (current_index >= DiskInfo.first_track &&
current_index <= DiskInfo.last_track &&
q_info.track_nr == 0)
{
/* Copy entry into toc table */
if (Toc[current_index].index_nr == 0)
{
Toc[current_index].control_address = q_info.control_address;
Toc[current_index].track_nr = current_index;
Toc[current_index].index_nr = 1;
Toc[current_index].track_time_mss[MINUTES] = q_info.track_time_mss[MINUTES];
Toc[current_index].track_time_mss[SECONDS] = q_info.track_time_mss[SECONDS];
Toc[current_index].track_time_mss[SECTOR] = q_info.track_time_mss[SECTOR];
Toc[current_index].position_mss[MINUTES] = q_info.position_mss[MINUTES];
Toc[current_index].position_mss[SECONDS] = q_info.position_mss[SECONDS];
Toc[current_index].position_mss[SECTOR] = q_info.position_mss[SECTOR];
current_track--;
}
}
}
if (err) return err; /* Do we have all toc entries? */
/* Fill in lead out */
current_index = DiskInfo.last_track + 1;
Toc[current_index].control_address =
Toc[current_index-1].control_address;
Toc[current_index].track_nr = 0;
Toc[current_index].index_nr = LEAD_OUT;
Toc[current_index].position_mss[MINUTES] = DiskInfo.disk_length_mss[MINUTES];
Toc[current_index].position_mss[SECONDS] = DiskInfo.disk_length_mss[SECONDS];
Toc[current_index].position_mss[SECTOR] = DiskInfo.disk_length_mss[SECTOR];
/* Return to cooked mode */
if ((err = mcd_set_mode(MCD_COOKED)) != OK) return err;
/* Update global status */
McdStatus |= TOC_UPTODATE;
#if MCD_DEBUG >= 1
for (i = DiskInfo.first_track; i <= current_index; i++)
{
printf("Mitsumi toc %d: trk %d index %d time %02d:%02d.%02d pos: %02d:%02d.%02d\n",
i,
Toc[i].track_nr,
Toc[i].index_nr,
Toc[i].track_time_mss[MINUTES],
Toc[i].track_time_mss[SECONDS],
Toc[i].track_time_mss[SECTOR],
Toc[i].position_mss[MINUTES],
Toc[i].position_mss[SECONDS],
Toc[i].position_mss[SECTOR]);
}
#endif
return OK;
}
/*=========================================================================*
* mcd_stop *
*=========================================================================*/
PRIVATE int mcd_stop()
{
int err;
if ((err = mcd_send_command(MCD_STOP)) != OK ) return err;
McdStatus &= ~(AUDIO_PAUSED);
return OK;
}
/*=========================================================================*
* mcd_eject *
*=========================================================================*/
PRIVATE int mcd_eject()
{
int err;
if ((err = mcd_send_command(MCD_EJECT)) != OK) return err;
return OK;
}
/*=========================================================================*
* mcd_pause *
*=========================================================================*/
PRIVATE int mcd_pause()
{
int err;
struct cd_toc_entry qc;
/* We can only pause when we are playing audio */
if (!(McdStatus & AUDIO_PLAYING)) return EINVAL;
/* Look where we are */
if ((err = mcd_read_q_channel(&qc)) != OK) return err;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -