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 void subpw_synth_leadout_lba(const struct TOC *toc, const int32_t lba, uint8_t* SubPWBuf);
230
231 #ifdef __cplusplus
232 }
233 #endif
234
235 #endif
236