/*\ |*| PLatform dependent code for accessing CDROM units. |*| For now, Linux and FreeBSD \*/ #ifndef CDROMBSD_H #define CDROMBSD_H #include #include #ifndef CD_FRAMESIZE_RAW #define CD_FRAMESIZE_RAW 2352 #endif /*\ |*| FreeBSD (?) specific code \*/ #define GET_LBA(entry) ((entry.addr.msf.minute * 60 \ + entry.addr.msf.second) * 75 \ + entry.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, CDRIOCREADSPEED, &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 ioc_toc_header ith; if (ioctl(cdfd, CDIOREADTOCHEADER, &ith) < 0) { cd->first_trk = 1; cd->last_trk = 0; return -1; } cd->first_trk = ith.starting_track; cd->last_trk = ith.ending_track; i = cd->last_trk + 2; while (--i >= cd->first_trk) { struct ioc_read_toc_single_entry rtse; rtse.track = i; rtse.address_format = CD_MSF_FORMAT; ioctl(cdfd, CDIOREADTOCENTRY, &rtse); cd->lba[i] = GET_LBA(rtse.entry); cd->data[i] = rtse.entry.control & 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. \*/ #if __FreeBSD_version >= 501106 static int cdrom_read_audio(int cdfd, int lba, char *buf, int btw) { int bsize = CD_FRAMESIZE_RAW; if (ioctl(cdfd, CDRIOCSETBLOCKSIZE, &bsize) == -1) return -errno; if (pread(cdfd, buf, btw*bsize, (lba - 150)*bsize) != btw*bsize) return 0; return btw; } #else // 4-STABLE static int cdrom_read_audio(int cdfd, int lba, char *buf, int btw) { int rtr = 3; do { struct ioc_read_audio ira; ira.buffer = buf; ira.nframes = btw; ira.address_format = CD_MSF_FORMAT; ira.address.msf.minute = lba / (75 * 60); ira.address.msf.second = (lba / 75) % 60; ira.address.msf.frame = lba % 75; if (ioctl(cdfd, CDIOCREADAUDIO, &ira) >= 0) return ira.nframes; } while (--rtr >= 0); return -1; } #endif // FreeBSD_version /*\ 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 ioc_play_msf imsf; imsf.start_m = from / (75 * 60); imsf.start_s = (from / 75) % 60; imsf.start_f = from % 75; imsf.end_m = to / (75 * 60); imsf.end_s = (to / 75) % 60; imsf.end_f = to % 75; return ioctl(cdfd, CDIOCPLAYMSF, &imsf); } /*\ Stop audio playback |*| return -1 on failure \*/ static int cdrom_stop(int cdfd) { /*\ CDIOCPAUSE: Rude hack, because stop takes so long. |*| It looks like it actually stops the disc spinning.. \*/ if (cdfd >= 0) return ioctl(cdfd, CDIOCPAUSE, 0); return 0; } /*\ Pause/resume audio playback |*| return -1 on failure \*/ static int cdrom_pause(int cdfd, short p) { return ioctl(cdfd, p ? CDIOCPAUSE : CDIOCRESUME); } /*\ 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 ioc_read_subchannel irs; struct cd_sub_channel_info cdsc; if (cd->cdfd < 0) return -1; irs.address_format = CD_MSF_FORMAT; irs.data_format = CD_CURRENT_POSITION; irs.data = &cdsc; if (ioctl(cd->cdfd, CDIOCREADSUBCHANNEL, &irs) < 0) return -2; f = ((irs.data->what.position.absaddr.msf.minute * 60 + irs.data->what.position.absaddr.msf.second) * 75 + irs.data->what.position.absaddr.msf.frame); if (f > end_lba) return -1; f -= cd->lba[cur_trk]; return (f * 40) / 3; } #endif /*\ CDROMBSD_H \*/