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