// plays cdda audio // sector: // byte 0 - minute // byte 1 - second // byte 2 - frame // does NOT uses bcd format long CDRplay(unsigned char *sector) { long ret; if (!IsCdHandleOpen()) return 0; // If play was called with the same time as the previous call, // don't restart it. Of course, if play is called with a different // track, stop playing the current stream. if (playing) { if (msf_to_lba(sector[0], sector[1], sector[2]) == initial_time) return 0; else CDRstop(); } initial_time = msf_to_lba(sector[0], sector[1], sector[2]); if (ReadMode == THREADED) pthread_mutex_lock(&mut); ret = PlayCDDA(sector); if (ReadMode == THREADED) pthread_mutex_unlock(&mut); if (ret == 0) { playing = 1; return 0; } return -1; }
void *CdrThread(void *arg) { unsigned char curTime[3]; int i; for (;;) { pthread_mutex_lock(&mut); locked = 1; pthread_cond_wait(&cond, &mut); if (stopth == 2) pthread_exit(NULL); // refill the buffer cacheaddr = msf_to_lba(cr.msf.cdmsf_min0, cr.msf.cdmsf_sec0, cr.msf.cdmsf_frame0); memcpy(curTime, &cr.msf, 3); PRINTF("start thc %d:%d:%d\n", curTime[0], curTime[1], curTime[2]); for (i = 0; i < CacheSize; i++) { cdcache[i].cr.msf.cdmsf_min0 = curTime[0]; cdcache[i].cr.msf.cdmsf_sec0 = curTime[1]; cdcache[i].cr.msf.cdmsf_frame0 = curTime[2]; PRINTF("reading %d:%d:%d\n", curTime[0], curTime[1], curTime[2]); cdcache[i].ret = ReadSector((crdata *)&cdcache[i].cr); if (cdcache[i].ret == -1) break; PRINTF("readed %x:%x:%x\n", cdcache[i].cr.buf[12], cdcache[i].cr.buf[13], cdcache[i].cr.buf[14]); cdcache[i].msf[0] = curTime[0]; cdcache[i].msf[1] = curTime[1]; cdcache[i].msf[2] = curTime[2]; curTime[2]++; if (curTime[2] == 75) { curTime[2] = 0; curTime[1]++; if (curTime[1] == 60) { curTime[1] = 0; curTime[0]++; } } if (stopth) break; } pthread_mutex_unlock(&mut); } return NULL; }
static void dump_full_table_of_contents(uchar* data, uint16 dataLength) { cdrom_table_of_contents_header* header = (cdrom_table_of_contents_header*)data; cdrom_full_table_of_contents_entry* entries = (cdrom_full_table_of_contents_entry*)(data + 4); int headerLength = B_BENDIAN_TO_HOST_INT16(header->length); if (dataLength < headerLength) { TRACE(("dump_full_table_of_contents: warning, data buffer not large " "enough (%d < %d)\n", dataLength, headerLength)); headerLength = dataLength; } TRACE(("%s: table of contents dump:\n", kModuleDebugName)); TRACE(("--------------------------------------------------\n")); TRACE(("header:\n")); TRACE((" length = %d\n", headerLength)); TRACE((" first = %d\n", header->first)); TRACE((" last = %d\n", header->last)); int count = (headerLength - 2) / sizeof(cdrom_full_table_of_contents_entry); TRACE(("\n")); TRACE(("entry count = %d\n", count)); for (int i = 0; i < count; i++) { TRACE(("\n")); TRACE(("entry #%d:\n", i)); TRACE((" session = %d\n", entries[i].session)); TRACE((" adr = %d\n", entries[i].adr)); TRACE((" control = %d (%s track, copy %s)\n", entries[i].control, (entries[i].control & kControlDataTrack ? "data" : "audio"), (entries[i].control & kControlCopyPermitted ? "permitted" : "prohibited"))); TRACE((" tno = %d\n", entries[i].tno)); TRACE((" point = %d (0x%.2x)\n", entries[i].point, entries[i].point)); TRACE((" minutes = %d\n", entries[i].minutes)); TRACE((" frames = %d\n", entries[i].seconds)); TRACE((" seconds = %d\n", entries[i].frames)); TRACE((" zero = %d\n", entries[i].zero)); TRACE((" pminutes = %d\n", entries[i].pminutes)); TRACE((" pseconds = %d\n", entries[i].pseconds)); TRACE((" pframes = %d\n", entries[i].pframes)); TRACE((" lba = %lld\n", msf_to_lba(make_msf_address(entries[i].pminutes, entries[i].pseconds, entries[i].pframes)))); } TRACE(("--------------------------------------------------\n")); }
bool mcd_isa_device::read_sector(bool first) { if((m_irq & IRQ_DATACOMP) && !first) m_isa->irq5_w(ASSERT_LINE); if(!m_readcount) { m_isa->drq5_w(CLEAR_LINE); m_data = false; return false; } uint32_t lba = msf_to_lba(m_readmsf); cdrom_read_data(m_cdrom_handle, lba - 150, m_buf, m_mode & 0x40 ? CD_TRACK_MODE1_RAW : CD_TRACK_MODE1); if(m_mode & 0x40) { //correct the header m_buf[12] = dec_2_bcd((m_readmsf >> 16) & 0xff); m_buf[13] = dec_2_bcd((m_readmsf >> 8) & 0xff); }
// threaded reading (with cache) long ReadThreaded() { int addr = msf_to_lba(cr.msf.cdmsf_min0, cr.msf.cdmsf_sec0, cr.msf.cdmsf_frame0); int i; if (addr >= cacheaddr && addr < (cacheaddr + CacheSize) && cacheaddr != -1) { i = addr - cacheaddr; PRINTF("found %d\n", (addr - cacheaddr)); cdbuffer = cdcache[i].cr.buf + 12; while (cdcache[i].msf[0] != cr.msf.cdmsf_min0 || cdcache[i].msf[1] != cr.msf.cdmsf_sec0 || cdcache[i].msf[2] != cr.msf.cdmsf_frame0) { if (locked == 1) { if (cdcache[i].ret == 0) break; return -1; } usleep(5000); } PRINTF("%d:%d:%d, %p, %p\n", cdcache[i].msf[0], cdcache[i].msf[1], cdcache[i].msf[2], cdbuffer, cdcache); found = 1; return 0; } else found = 0; if (locked == 0) { stopth = 1; while (locked == 0) { usleep(5000); } stopth = 0; } // not found in cache locked = 0; pthread_mutex_lock(&mut); pthread_cond_signal(&cond); pthread_mutex_unlock(&mut); return 0; }
/*! \brief Reads through the given table of contents data and creates an unsorted, unverified (i.e. non-error-checked) list of sessions and tracks. */ status_t Disc::_ParseTableOfContents(cdrom_full_table_of_contents_entry entries[], uint32 count) { DEBUG_INIT_ETC("Disc", ("entries: %p, count: %ld", entries, count)); for (uint32 i = 0; i < count; i++) { // Find or create the appropriate session uint8 sessionIndex = entries[i].session; session* session = (struct session*)fSessionList->Find(sessionIndex); if (session == NULL) { session = new struct session(sessionIndex); if (session == NULL) return B_NO_MEMORY; fSessionList->Add(session); } uint8 point = entries[i].point; switch (point) { // first track hint case 0xA0: if (!session->first_track_hint_is_set()) { int8 firstTrackHint = entries[i].pminutes; if (1 <= firstTrackHint && firstTrackHint <= 99) { session->first_track_hint = firstTrackHint; } else { WARN(("%s: warning: illegal first track hint %d found " "for session %d\n", kModuleDebugName, firstTrackHint, sessionIndex)); } } else { WARN(("%s: warning: duplicated first track hint values " "found for session %d; using first value " "encountered: %d", kModuleDebugName, sessionIndex, session->first_track_hint)); } break; // last track hint case 0xA1: if (!session->last_track_hint_is_set()) { int8 lastTrackHint = entries[i].pminutes; if (1 <= lastTrackHint && lastTrackHint <= 99) { session->last_track_hint = lastTrackHint; } else { WARN(("%s: warning: illegal last track hint %d found " "for session %d\n", kModuleDebugName, lastTrackHint, sessionIndex)); } } else { WARN(("%s: warning: duplicate last track hint values found " "for session %d; using first value encountered: %d", kModuleDebugName, sessionIndex, session->last_track_hint)); } break; // end of session address case 0xA2: if (!session->end_lba_is_set()) { off_t endLBA = msf_to_lba(make_msf_address( entries[i].pminutes, entries[i].pseconds, entries[i].pframes)); if (endLBA > 0) { session->end_lba = endLBA; // We also grab the session's control and adr values // from this entry session->control = entries[i].control; session->adr = entries[i].adr; } else { WARN(("%s: warning: illegal end lba %lld found for " "session %d\n", kModuleDebugName, endLBA, sessionIndex)); } } else { WARN(("%s: warning: duplicate end lba values found for " "session %d; using first value encountered: %lld", kModuleDebugName, sessionIndex, session->end_lba)); } break; // Valid, but uninteresting, points case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xC0: case 0xC1: break; default: // Anything else had better be a valid track number, // or it's an invalid point if (1 <= point && point <= 99) { // Create and add the track. We'll weed out any duplicates // later. uint8 trackIndex = point; off_t startLBA = msf_to_lba(make_msf_address( entries[i].pminutes, entries[i].pseconds, entries[i].pframes)); // The control and adr values grabbed here are only used // later on to signal a warning if they don't match the // corresponding values of the parent session. track* track = new(std::nothrow) struct track(trackIndex, startLBA, entries[i].control, entries[i].adr); if (track == NULL) return B_NO_MEMORY; session->track_list.Add(track); } else { WARN(("%s: warning: illegal point 0x%2x found in table of " "contents\n", kModuleDebugName, entries[i].point)); } break; } } return B_OK; }
int cueify_device_read_track_indices(cueify_device *d, cueify_indices *i, uint8_t track) { cueify_device_private *dev = (cueify_device_private *)d; cueify_indices_private *indices = (cueify_indices_private *)i; cueify_full_toc_private toc; if (cueify_device_read_full_toc_unportable(dev, &toc) != CUEIFY_OK) { return CUEIFY_ERR_INTERNAL; } if ((track >= toc.first_track_number && track <= toc.last_track_number) || track == CUEIFY_LEAD_OUT_TRACK) { /* First, see if there appears to be more than one index. */ cueify_msf_t msf; cueify_position_t pos; int lba, first_lba, left_lba, right_lba, last_lba; int index; first_lba = left_lba = msf_to_lba(toc.tracks[track].offset); if (track == toc.sessions[toc.tracks[track].session].last_track_number) { last_lba = right_lba = msf_to_lba(toc.sessions[toc.tracks[track].session].leadout); } else { last_lba = right_lba = msf_to_lba(toc.tracks[track + 1].offset); } /* Get the index of the penultimate second of the track. */ lba = last_lba - 1; if (lba < left_lba) { lba = (left_lba + last_lba) / 2; } /* And the MSF of the first. */ lba_to_msf(first_lba, &msf); if (cueify_device_read_position_unportable( dev, track, lba, &pos) != CUEIFY_OK) { return CUEIFY_ERR_INTERNAL; } if (pos.track == track && pos.index != 1) { indices->num_indices = pos.index; indices->has_pregap = 0; indices->indices = calloc(indices->num_indices, sizeof(cueify_msf_t)); if (indices->indices == NULL) { return CUEIFY_ERR_INTERNAL; } indices->indices[0] = msf; } else if (pos.track == track + 1) { indices->num_indices = 2; indices->has_pregap = 1; indices->indices = calloc(indices->num_indices, sizeof(cueify_msf_t)); if (indices->indices == NULL) { return CUEIFY_ERR_INTERNAL; } indices->indices[0] = msf; /* Detect the pre-gap. */ while (left_lba != right_lba) { lba = (left_lba + right_lba) / 2; if (cueify_device_read_position_unportable( dev, track, lba, &pos) != CUEIFY_OK) { free(indices->indices); indices->indices = NULL; return CUEIFY_ERR_INTERNAL; } if (pos.track == track) { /* Choose the right half. */ left_lba = lba + 1; } else { /* Choose the left half. */ right_lba = lba; } } /* Found the start address. */ lba_to_msf(left_lba, &msf); indices->indices[1] = msf; /* Reset the right and left sides. */ last_lba = right_lba = lba; left_lba = first_lba; /* And calculate the TRUE index count. */ lba = last_lba - 1; if (lba < left_lba) { lba = (left_lba + last_lba) / 2; } if (cueify_device_read_position_unportable( dev, track, lba, &pos) != CUEIFY_OK) { free(indices->indices); indices->indices = NULL; return CUEIFY_ERR_INTERNAL; } if (pos.track == track && pos.index != 1) { indices->num_indices = pos.index + 1; indices->indices = realloc(indices->indices, indices->num_indices * sizeof(cueify_msf_t)); if (indices->indices == NULL) { return CUEIFY_ERR_INTERNAL; } /* TODO: Test me. */ /* Copy the pre-gap indices over. */ memcpy(&(indices->indices[indices->num_indices]), &(indices->indices[1]), sizeof(cueify_msf_t)); } else { /* That's it. */ return CUEIFY_OK; } } else { indices->num_indices = 1; indices->has_pregap = 0; indices->indices = calloc(1, sizeof(cueify_msf_t)); if (indices->indices == NULL) { return 0; } indices->indices[0] = msf; return CUEIFY_OK; } for (index = 1; index < indices->num_indices; index++) { /* Detect the given index by binary search. */ while (left_lba != right_lba) { lba = (left_lba + right_lba) / 2; if (cueify_device_read_position_unportable( dev, track, lba, &pos) != CUEIFY_OK) { free(indices->indices); indices->indices = NULL; return CUEIFY_ERR_INTERNAL; } if (pos.index >= index + 1) { /* Choose the left half. */ right_lba = lba; } else { /* Choose the right half. */ left_lba = lba + 1; } } /* Found the start address. */ lba_to_msf(left_lba, &msf); indices->indices[index] = msf; /* Reset the right side. */ right_lba = last_lba; } return CUEIFY_OK; } else { return CUEIFY_ERR_INTERNAL; } } /* cueify_device_read_track_indices */
cdrom_ioctl(int fd, u_long cmd, void *arg) { int ret; cgc_t cgc; switch (cmd) { case CDROMREADRAW: case CDROMREADMODE1: case CDROMREADMODE2: { struct cdrom_msf *msf; int blocksize = 0, format = 0, lba; switch (cmd) { case CDROMREADRAW: blocksize = CD_FRAMESIZE_RAW; break; case CDROMREADMODE1: blocksize = CD_FRAMESIZE; format = 2; break; case CDROMREADMODE2: blocksize = CD_FRAMESIZE_RAW0; break; } msf = (struct cdrom_msf *)arg; lba = msf_to_lba(msf->cdmsf_min0,msf->cdmsf_sec0, msf->cdmsf_frame0); ret = EINVAL; if (lba < 0) break; cgc_init(&cgc, arg, blocksize, SUC_READ); ret = cdrom_read_block(fd, &cgc, lba, 1, format, blocksize); if (ret) { /* * SCSI-II devices are not required to support CMD_READ_CD (which specifies * the blocksize to read) so try switching the block size with a mode select, * doing the normal read sector command and then changing the sector size back * to 2048. * * If the program dies before changing the blocksize back sdopen() * in the kernel will fail opens with a message that looks something like: * * "sr1: blksize 2336 not multiple of 512: cannot use" * * At that point the drive has to be power cycled (or reset in some other way). */ if (ret = cdrom_blocksize(fd, blocksize)) break; ret = cdrom_read_cd(fd, &cgc, lba, blocksize, 1); ret |= cdrom_blocksize(fd, 2048); } break; } case CDROMREADTOCHDR: { struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; u_char buffer[12]; cgc_init(&cgc, buffer, sizeof (buffer), SUC_READ); cgc.cdb[0] = CMD_READ_TOC_PMA_ATIP; cgc.cdb[1] = 0x2; /* MSF */ cgc.cdb[8] = 12; /* LSB of length */ ret = scsi_cmd(fd, &cgc); if (!ret) { tochdr->cdth_trk0 = buffer[2]; tochdr->cdth_trk1 = buffer[3]; } break; } case CDROMREADTOCENTRY: { struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg; u_char buffer[12]; cgc_init(&cgc, buffer, sizeof (buffer), SUC_READ); cgc.cdb[0] = CMD_READ_TOC_PMA_ATIP; cgc.cdb[1] = (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0; cgc.cdb[6] = tocentry->cdte_track; cgc.cdb[8] = 12; /* LSB of length */ ret = scsi_cmd(fd, &cgc); if (ret) break; tocentry->cdte_ctrl = buffer[5] & 0xf; tocentry->cdte_adr = buffer[5] >> 4; tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0; if (tocentry->cdte_format == CDROM_MSF) { tocentry->cdte_addr.msf.minute = buffer[9]; tocentry->cdte_addr.msf.second = buffer[10]; tocentry->cdte_addr.msf.frame = buffer[11]; } else tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8) + buffer[10]) << 8) + buffer[11]; break; } case CDROMEJECT: /* NO-OP for now */ ret = cdrom_tray_move(fd, 1); break; case CDROMCLOSETRAY: ret = cdrom_tray_move(fd, 0); break; /* * This sucks but emulates the expected behaviour. Instead of the return * value being the actual status a success/fail indicator should have been * returned and the 3rd arg to the ioctl should have been an 'int *' to update * with the actual status. Both the drive and disc status ioctl calls are * similarily braindamaged. */ case CDROM_DRIVE_STATUS: return(CDS_NO_INFO); /* XXX */ case CDROM_DISC_STATUS: { tracktype tracks; int cnt; cdrom_count_tracks(fd, &tracks); if (tracks.error) return(tracks.error); if (tracks.audio > 0) { cnt = tracks.data + tracks.cdi + tracks.xa; if (cnt == 0) return(CDS_AUDIO); else return(CDS_MIXED); } if (tracks.cdi) return(CDS_XA_2_2); if (tracks.xa) return(CDS_XA_2_1); if (tracks.data) return(CDS_DATA_1); return(CDS_NO_INFO); } } errno = ret; return(ret ? -1 : 0); }