1 #ifndef __MDFN_CDROM_CDUTILITY_H
2 #define __MDFN_CDROM_CDUTILITY_H
3 
4 #include <stdint.h>
5 #include <string.h>
6 
7 #include <boolean.h>
8 #include <retro_inline.h>
9 
10 #ifdef __cplusplus
11 extern "C" {
12 #endif
13 
14 enum
15 {
16    ADR_NOQINFO = 0x00,
17    ADR_CURPOS  = 0x01,
18    ADR_MCN     = 0x02,
19    ADR_ISRC    = 0x03
20 };
21 
22 struct TOC_Track
23 {
24    uint8_t adr;
25    uint8_t control;
26    uint32_t lba;
27   bool valid;	/* valid/present; oh CD-i... */
28 };
29 
30 // SubQ control field flags.
31 enum
32 {
33    SUBQ_CTRLF_PRE  = 0x01,	// With 50/15us pre-emphasis.
34    SUBQ_CTRLF_DCP  = 0x02,	// Digital copy permitted.
35    SUBQ_CTRLF_DATA = 0x04,	// Data track.
36    SUBQ_CTRLF_4CH  = 0x08	// 4-channel CD-DA.
37 };
38 
39 enum
40 {
41    DISC_TYPE_CDDA_OR_M1 = 0x00,
42    DISC_TYPE_CD_I       = 0x10,
43    DISC_TYPE_CD_XA      = 0x20
44 };
45 
46 struct TOC
47 {
48    uint8_t first_track;
49    uint8_t last_track;
50    uint8_t disc_type;
51    struct TOC_Track tracks[100 + 1];
52 };
53 
54 // Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions.
55 // It will also be called automatically if needed for the first time a function in this namespace that requires
56 // the initialization function to be called is called, for potential
57 // usage in constructors of statically-declared objects.
58 void CDUtility_Init(void);
59 
60 // Quick definitions here:
61 //
62 // ABA - Absolute block address, synonymous to absolute MSF
63 //  aba = (m_a * 60 * 75) + (s_a * 75) + f_a
64 //
65 // LBA - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors)
66 //  lba = aba - 150
67 
TOC_Clear(struct TOC * toc)68 static INLINE void TOC_Clear(struct TOC *toc)
69 {
70    if (!toc)
71       return;
72 
73    toc->first_track = 0;
74    toc->last_track  = 0;
75    toc->disc_type   = 0;
76 
77    memset(toc->tracks, 0, sizeof(toc->tracks));
78 }
79 
TOC_FindTrackByLBA(struct TOC * toc,uint32_t LBA)80 static INLINE int TOC_FindTrackByLBA(struct TOC *toc, uint32_t LBA)
81 {
82    int32_t track;
83 
84    for(track = toc->first_track; track <= (toc->last_track + 1); track++)
85    {
86       if(track == (toc->last_track + 1))
87       {
88          if(LBA < toc->tracks[100].lba)
89             return(track - 1);
90       }
91       else
92       {
93          if(LBA < toc->tracks[track].lba)
94             return(track - 1);
95       }
96    }
97 
98    return 0;
99 }
100 
101 // Address conversion functions.
AMSF_to_ABA(int32_t m_a,int32_t s_a,int32_t f_a)102 static INLINE uint32_t AMSF_to_ABA(int32_t m_a, int32_t s_a, int32_t f_a)
103 {
104    return(f_a + 75 * s_a + 75 * 60 * m_a);
105 }
106 
ABA_to_AMSF(uint32_t aba,uint8_t * m_a,uint8_t * s_a,uint8_t * f_a)107 static INLINE void ABA_to_AMSF(uint32_t aba, uint8_t *m_a, uint8_t *s_a, uint8_t *f_a)
108 {
109    *m_a = aba / 75 / 60;
110    *s_a = (aba - *m_a * 75 * 60) / 75;
111    *f_a = aba - (*m_a * 75 * 60) - (*s_a * 75);
112 }
113 
ABA_to_LBA(uint32_t aba)114 static INLINE int32_t ABA_to_LBA(uint32_t aba)
115 {
116    return(aba - 150);
117 }
118 
LBA_to_ABA(int32_t lba)119 static INLINE uint32_t LBA_to_ABA(int32_t lba)
120 {
121    return(lba + 150);
122 }
123 
AMSF_to_LBA(uint8_t m_a,uint8_t s_a,uint8_t f_a)124 static INLINE int32_t AMSF_to_LBA(uint8_t m_a, uint8_t s_a, uint8_t f_a)
125 {
126    return(ABA_to_LBA(AMSF_to_ABA(m_a, s_a, f_a)));
127 }
128 
LBA_to_AMSF(int32_t lba,uint8_t * m_a,uint8_t * s_a,uint8_t * f_a)129 static INLINE void LBA_to_AMSF(int32_t lba, uint8_t *m_a, uint8_t *s_a, uint8_t *f_a)
130 {
131    ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a);
132 }
133 
134 //
135 // BCD conversion functions
136 //
BCD_is_valid(uint8_t bcd_number)137 static INLINE bool BCD_is_valid(uint8_t bcd_number)
138 {
139    if((bcd_number & 0xF0) >= 0xA0)
140       return(false);
141 
142    if((bcd_number & 0x0F) >= 0x0A)
143       return(false);
144 
145    return(true);
146 }
147 
BCD_to_U8(uint8_t bcd_number)148 static INLINE uint8_t BCD_to_U8(uint8_t bcd_number)
149 {
150    return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) );
151 }
152 
U8_to_BCD(uint8_t num)153 static INLINE uint8_t U8_to_BCD(uint8_t num)
154 {
155    return( ((num / 10) << 4) + (num % 10) );
156 }
157 
158 // should always perform the conversion, even if the bcd number is invalid.
BCD_to_U8_check(uint8_t bcd_number,uint8_t * out_number)159 static INLINE bool BCD_to_U8_check(uint8_t bcd_number, uint8_t *out_number)
160 {
161    *out_number = BCD_to_U8(bcd_number);
162 
163    if(!BCD_is_valid(bcd_number))
164       return(false);
165 
166    return(true);
167 }
168 
169 //
170 // Sector data encoding functions(to full 2352 bytes raw sector).
171 //
172 //  sector_data must be able to contain at least 2352 bytes.
173 void encode_mode0_sector(uint32_t aba, uint8_t *sector_data);
174 void encode_mode1_sector(uint32_t aba, uint8_t *sector_data);	// 2048 bytes of user data at offset 16
175 void encode_mode2_sector(uint32_t aba, uint8_t *sector_data);	// 2336 bytes of user data at offset 16
176 void encode_mode2_form1_sector(uint32_t aba, uint8_t *sector_data);	// 2048+8 bytes of user data at offset 16
177 void encode_mode2_form2_sector(uint32_t aba, uint8_t *sector_data);	// 2324+8 bytes of user data at offset 16
178 
179 
180 // out_buf must be able to contain 2352+96 bytes.
181 // "mode" is only used if(toc.tracks[100].control & 0x4)
182 void synth_leadout_sector_lba(uint8_t mode, const struct TOC *toc, const int32_t lba, uint8_t* out_buf);
183 
184 //
185 // User data error detection and correction
186 //
187 
188 // Check EDC of a mode 1 or mode 2 form 1 sector.
189 //  Returns "true" if checksum is ok(matches).
190 //  Returns "false" if checksum mismatch.
191 //  sector_data should contain 2352 bytes of raw sector data.
192 bool edc_check(const uint8_t *sector_data, bool xa);
193 
194 // Check EDC and L-EC data of a mode 1 or mode 2 form 1 sector, and correct bit errors if any exist.
195 //  Returns "true" if errors weren't detected, or they were corrected succesfully.
196 //  Returns "false" if errors couldn't be corrected.
197 //  sector_data should contain 2352 bytes of raw sector data.
198 bool edc_lec_check_and_correct(uint8_t *sector_data, bool xa);
199 
200 //
201 // Subchannel(Q in particular) functions
202 //
203 
204 // Returns false on checksum mismatch, true on match.
205 bool subq_check_checksum(const uint8_t *subq_buf);
206 
207 // Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position
208 // in subq_buf.
209 void subq_generate_checksum(uint8_t *subq_buf);
210 
211 // Deinterleaves 12 bytes of subchannel Q data from 96 bytes of interleaved subchannel PW data.
212 void subq_deinterleave(const uint8_t *subpw_buf, uint8_t *subq_buf);
213 
214 // Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
215 void subpw_deinterleave(const uint8_t *in_buf, uint8_t *out_buf);
216 
217 // Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
218 void subpw_interleave(const uint8_t *in_buf, uint8_t *out_buf);
219 
220 // Extrapolates Q subchannel current position data from subq_input, with frame/sector delta position_delta, and writes to subq_output.
221 // Only valid for ADR_CURPOS.
222 // subq_input must pass subq_check_checksum().
223 // TODO
224 //void subq_extrapolate(const uint8_t *subq_input, int32_t position_delta, uint8_t *subq_output);
225 
226 // (De)Scrambles data sector.
227 void scrambleize_data_sector(uint8_t *sector_data);
228 
229 #ifdef __cplusplus
230 }
231 #endif
232 
233 #endif
234