#ifndef __MDFN_CDROM_CDUTILITY_H1#define __MDFN_CDROM_CDUTILITY_H23#include <string.h>45namespace CDUtility6{7// Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions.8// It will also be called automatically if needed for the first time a function in this namespace that requires9// the initialization function to be called is called, for potential10// usage in constructors of statically-declared objects.11void CDUtility_Init(void);1213// Quick definitions here:14//15// ABA - Absolute block address, synonymous to absolute MSF16// aba = (m_a * 60 * 75) + (s_a * 75) + f_a17//18// LBA - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors)19// lba = aba - 150202122enum23{24ADR_NOQINFO = 0x00,25ADR_CURPOS = 0x01,26ADR_MCN = 0x02,27ADR_ISRC = 0x0328};293031struct TOC_Track32{33uint8 adr;34uint8 control;35uint32 lba;36};3738// SubQ control field flags.39enum40{41SUBQ_CTRLF_PRE = 0x01, // With 50/15us pre-emphasis.42SUBQ_CTRLF_DCP = 0x02, // Digital copy permitted.43SUBQ_CTRLF_DATA = 0x04, // Data track.44SUBQ_CTRLF_4CH = 0x08, // 4-channel CD-DA.45};4647enum48{49DISC_TYPE_CDDA_OR_M1 = 0x00,50DISC_TYPE_CD_I = 0x10,51DISC_TYPE_CD_XA = 0x2052};5354struct TOC55{56INLINE TOC()57{58Clear();59}6061INLINE void Clear(void)62{63first_track = last_track = 0;64disc_type = 0;6566memset(tracks, 0, sizeof(tracks)); // FIXME if we change TOC_Track to non-POD type.67}6869INLINE int FindTrackByLBA(uint32 LBA)70{71for(int32 track = first_track; track <= (last_track + 1); track++)72{73if(track == (last_track + 1))74{75if(LBA < tracks[100].lba)76return(track - 1);77}78else79{80if(LBA < tracks[track].lba)81return(track - 1);82}83}84return(0);85}8687uint8 first_track;88uint8 last_track;89uint8 disc_type;90TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track.91// Also, for convenience, tracks[last_track + 1] will always refer92// to the leadout track(even if last_track < 99, IE the leadout track details are duplicated).93};9495//96// Address conversion functions.97//98static INLINE uint32 AMSF_to_ABA(int32 m_a, int32 s_a, int32 f_a)99{100return(f_a + 75 * s_a + 75 * 60 * m_a);101}102103static INLINE void ABA_to_AMSF(uint32 aba, uint8 *m_a, uint8 *s_a, uint8 *f_a)104{105*m_a = aba / 75 / 60;106*s_a = (aba - *m_a * 75 * 60) / 75;107*f_a = aba - (*m_a * 75 * 60) - (*s_a * 75);108}109110static INLINE int32 ABA_to_LBA(uint32 aba)111{112return(aba - 150);113}114115static INLINE uint32 LBA_to_ABA(int32 lba)116{117return(lba + 150);118}119120static INLINE int32 AMSF_to_LBA(uint8 m_a, uint8 s_a, uint8 f_a)121{122return(ABA_to_LBA(AMSF_to_ABA(m_a, s_a, f_a)));123}124125static INLINE void LBA_to_AMSF(int32 lba, uint8 *m_a, uint8 *s_a, uint8 *f_a)126{127ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a);128}129130//131// BCD conversion functions132//133static INLINE bool BCD_is_valid(uint8 bcd_number)134{135if((bcd_number & 0xF0) >= 0xA0)136return(false);137138if((bcd_number & 0x0F) >= 0x0A)139return(false);140141return(true);142}143144static INLINE uint8 BCD_to_U8(uint8 bcd_number)145{146return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) );147}148149static INLINE uint8 U8_to_BCD(uint8 num)150{151return( ((num / 10) << 4) + (num % 10) );152}153154// Check EDC and L-EC data of a mode 1 or mode 2 form 1 sector, and correct bit errors if any exist.155// Returns "true" if errors weren't detected, or they were corrected succesfully.156// Returns "false" if errors couldn't be corrected.157// sector_data should contain 2352 bytes of raw sector data.158bool edc_lec_check_and_correct(uint8 *sector_data, bool xa);159160// Returns false on checksum mismatch, true on match.161bool subq_check_checksum(const uint8 *subq_buf);162163// Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position164// in subq_buf.165void subq_generate_checksum(uint8 *subq_buf);166167// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.168void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf);169170// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.171void subpw_interleave(const uint8 *in_buf, uint8 *out_buf);172173}174175#endif176177178