/*\ |*| PLatform dependent code for accessing CDROM units. |*| For now, Linux and FreeBSD \*/ #ifndef CDROMLINUX_H #define CDROMLINUX_H /*\ |*| Linux specific code \*/ #define GET_LBA(entry) ((entry.cdte_format == CDROM_LBA) ? \ entry.cdte_addr.lba : \ ((entry.cdte_addr.msf.minute * 60 + \ entry.cdte_addr.msf.second) * 75 + \ entry.cdte_addr.msf.frame)) /*\ |*| Open cdrom device |*| Return -1 on error. \*/ static int cdrom_open(const char *device, int *flags) { int fd; fd = open(device, O_RDONLY|O_NONBLOCK); if (fd < 0) return -1; if (!(*flags & FLAG_FAIL_SPD) && (ioctl(fd, CDROM_SELECT_SPEED, cd_cfg.cdrom_speed) < 0)) { if (errno == ENOTTY) { close(fd); return -1; } *flags |= FLAG_FAIL_SPD; } return fd; } /*\ |*| Close cdrom device |*| Return -1 on error. \*/ static int cdrom_close(int cdfd) { return close(cdfd); } /*\ Read the toc into: |*| cd->first_trk .. cd->last_trk |*| cd->lba[..], cd->data[..] |*| |*| Return -1 on error. \*/ static int cdrom_read_toc(struct cd_struct *cd, int cdfd) { int i; struct cdrom_tochdr toc_hdr; struct cdrom_tocentry entry; if (ioctl(cdfd, CDROMREADTOCHDR, &toc_hdr) < 0) { cd->first_trk = 1; cd->last_trk = 0; return -1; } cd->first_trk = toc_hdr.cdth_trk0; cd->last_trk = toc_hdr.cdth_trk1; i = cd->last_trk + 1; entry.cdte_track = CDROM_LEADOUT; entry.cdte_format = CDROM_MSF; ioctl(cdfd, CDROMREADTOCENTRY, &entry); cd->lba[i] = GET_LBA(entry); cd->data[i] = entry.cdte_ctrl & 4; while (--i >= cd->first_trk) { entry.cdte_track = i; entry.cdte_format = CDROM_MSF; ioctl(cdfd, CDROMREADTOCENTRY, &entry); cd->lba[i] = GET_LBA(entry); cd->data[i] = entry.cdte_ctrl & 4; } return 0; } /*\ Read btw frames of audio data into buf, |*| from device cdfd, at position lba |*| Return number of successfully read frames, -1 on error. \*/ static int cdrom_read_audio(int cdfd, int lba, char *buf, int btw) { int rtr = 3; do { struct cdrom_read_audio cdra; cdra.buf = buf; cdra.nframes = btw; cdra.addr.msf.minute = lba / (75 * 60); cdra.addr.msf.second = (lba / 75) % 60; cdra.addr.msf.frame = lba % 75; cdra.addr_format = CDROM_MSF; if (ioctl(cdfd, CDROMREADAUDIO, &cdra) >= 0) return cdra.nframes; } while (--rtr >= 0); return -1; } /*\ Play audio from lba address from, to lba address to |*| return -1 on failure \*/ static int cdrom_play_lba(int cdfd, int from, int to) { struct cdrom_msf cmsf; cmsf.cdmsf_min0 = from / (75 * 60); cmsf.cdmsf_sec0 = (from / 75) % 60; cmsf.cdmsf_frame0 = from % 75; cmsf.cdmsf_min1 = to / (75 * 60); cmsf.cdmsf_sec1 = (to / 75) % 60; cmsf.cdmsf_frame1 = to % 75; return ioctl(cdfd, CDROMPLAYMSF, &cmsf); } /*\ Stop audio playback |*| return -1 on failure \*/ static int cdrom_stop(int cdfd) { /*\ CDROMPAUSE: Rude hack, because stop takes so long. |*| It looks like it actually stops the disc spinning.. \*/ if (cdfd >= 0) return ioctl(cdfd, CDROMPAUSE, 0); return 0; } /*\ Pause/resume audio playback |*| return -1 on failure \*/ static int cdrom_pause(int cdfd, short p) { return ioctl(cdfd, p ? CDROMPAUSE : CDROMRESUME); } /*\ Get currently playing relative time |*| return -1 on failure |*| (Closes cdfd if not playing) \*/ static gint32 cdrom_get_time(struct cd_struct *cd) { gint32 f; struct cdrom_subchnl cdsc; if (cd->cdfd < 0) return -1; cdsc.cdsc_format = CDROM_MSF; if (ioctl(cd->cdfd, CDROMSUBCHNL, &cdsc) < 0) return -2; if (cdsc.cdsc_audiostatus == CDROM_AUDIO_ERROR) return -2; if (cdsc.cdsc_audiostatus == CDROM_AUDIO_COMPLETED) return -1; f = ((cdsc.cdsc_absaddr.msf.minute * 60 + cdsc.cdsc_absaddr.msf.second) * 75 + cdsc.cdsc_absaddr.msf.frame); if (f > (end_lba - 20)) return -1; f -= cd->lba[cur_trk]; if (f < 0) f = 0; return (f * 40) / 3; } #endif /*\ CDROMLINUX_H \*/