1 /* Mednafen - Multi-system Emulator
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17 
18 #include "../mednafen.h"
19 #include <string.h>
20 #include <sys/types.h>
21 #include "cdromif.h"
22 #include "CDAccess.h"
23 #include "../general.h"
24 
25 #include <algorithm>
26 
27 enum
28 {
29  // Status/Error messages
30  CDIF_MSG_DONE = 0,		// Read -> emu. args: No args.
31  CDIF_MSG_INFO,			// Read -> emu. args: str_message
32  CDIF_MSG_FATAL_ERROR,		// Read -> emu. args: *TODO ARGS*
33 
34  //
35  // Command messages.
36  //
37  CDIF_MSG_DIEDIEDIE,		// Emu -> read
38 
39  CDIF_MSG_READ_SECTOR,		/* Emu -> read
40 					args[0] = lba
41 				*/
42 
43  CDIF_MSG_EJECT,		// Emu -> read, args[0]; 0=insert, 1=eject
44 };
45 
46 class CDIF_Message
47 {
48  public:
49 
50  CDIF_Message();
51  CDIF_Message(unsigned int message_, uint32 arg0 = 0, uint32 arg1 = 0, uint32 arg2 = 0, uint32 arg3 = 0);
52  CDIF_Message(unsigned int message_, const std::string &str);
53  ~CDIF_Message();
54 
55  unsigned int message;
56  uint32 args[4];
57  void *parg;
58  std::string str_message;
59 };
60 
61 typedef struct
62 {
63  bool valid;
64  bool error;
65  uint32 lba;
66  uint8 data[2352 + 96];
67 } CDIF_Sector_Buffer;
68 
69 // TODO: prohibit copy constructor
70 class CDIF_ST : public CDIF
71 {
72  public:
73 
74  CDIF_ST(CDAccess *cda);
75  virtual ~CDIF_ST();
76 
77  virtual void HintReadSector(uint32 lba);
78  virtual bool ReadRawSector(uint8 *buf, uint32 lba);
79  virtual bool Eject(bool eject_status);
80 
81  private:
82  CDAccess *disc_cdaccess;
83 };
84 
CDIF()85 CDIF::CDIF() : UnrecoverableError(false), is_phys_cache(false), DiscEjected(false)
86 {
87 
88 }
89 
~CDIF()90 CDIF::~CDIF()
91 {
92 
93 }
94 
95 
CDIF_Message()96 CDIF_Message::CDIF_Message()
97 {
98  message = 0;
99 
100  memset(args, 0, sizeof(args));
101 }
102 
CDIF_Message(unsigned int message_,uint32 arg0,uint32 arg1,uint32 arg2,uint32 arg3)103 CDIF_Message::CDIF_Message(unsigned int message_, uint32 arg0, uint32 arg1, uint32 arg2, uint32 arg3)
104 {
105  message = message_;
106  args[0] = arg0;
107  args[1] = arg1;
108  args[2] = arg2;
109  args[3] = arg3;
110 }
111 
CDIF_Message(unsigned int message_,const std::string & str)112 CDIF_Message::CDIF_Message(unsigned int message_, const std::string &str)
113 {
114  message = message_;
115  str_message = str;
116 }
117 
~CDIF_Message()118 CDIF_Message::~CDIF_Message()
119 {
120 
121 }
122 
ValidateRawSector(uint8 * buf)123 bool CDIF::ValidateRawSector(uint8 *buf)
124 {
125  int mode = buf[12 + 3];
126 
127  if(mode != 0x1 && mode != 0x2)
128   return(false);
129 
130  if(!edc_lec_check_and_correct(buf, mode == 2))
131   return(false);
132 
133  return(true);
134 }
135 
ReadSector(uint8 * pBuf,uint32 lba,uint32 nSectors)136 int CDIF::ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors)
137 {
138  int ret = 0;
139 
140  if(UnrecoverableError)
141   return(false);
142 
143  while(nSectors--)
144  {
145   uint8 tmpbuf[2352 + 96];
146 
147   if(!ReadRawSector(tmpbuf, lba))
148   {
149    puts("CDIF Raw Read error");
150    return(FALSE);
151   }
152 
153   if(!ValidateRawSector(tmpbuf))
154   {
155    MDFN_DispMessage(_("Uncorrectable data at sector %d"), lba);
156    MDFN_PrintError(_("Uncorrectable data at sector %d"), lba);
157    return(false);
158   }
159 
160   const int mode = tmpbuf[12 + 3];
161 
162   if(!ret)
163    ret = mode;
164 
165   if(mode == 1)
166   {
167    memcpy(pBuf, &tmpbuf[12 + 4], 2048);
168   }
169   else if(mode == 2)
170   {
171    memcpy(pBuf, &tmpbuf[12 + 4 + 8], 2048);
172   }
173   else
174   {
175    printf("CDIF_ReadSector() invalid sector type at LBA=%u\n", (unsigned int)lba);
176    return(false);
177   }
178 
179   pBuf += 2048;
180   lba++;
181  }
182 
183  return(ret);
184 }
185 
186 // Single-threaded implementation follows.
187 
CDIF_ST(CDAccess * cda)188 CDIF_ST::CDIF_ST(CDAccess *cda) : disc_cdaccess(cda)
189 {
190  //puts("***WARNING USING SINGLE-THREADED CD READER***");
191 
192  is_phys_cache = false;
193  UnrecoverableError = false;
194  DiscEjected = false;
195 
196  disc_cdaccess->Read_TOC(&disc_toc);
197 
198  if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track)
199  {
200   throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track));
201  }
202 }
203 
~CDIF_ST()204 CDIF_ST::~CDIF_ST()
205 {
206  if(disc_cdaccess)
207  {
208   delete disc_cdaccess;
209   disc_cdaccess = NULL;
210  }
211 }
212 
HintReadSector(uint32 lba)213 void CDIF_ST::HintReadSector(uint32 lba)
214 {
215  // TODO: disc_cdaccess seek hint? (probably not, would require asynchronousitycamel)
216 }
217 
ReadRawSector(uint8 * buf,uint32 lba)218 bool CDIF_ST::ReadRawSector(uint8 *buf, uint32 lba)
219 {
220  if(UnrecoverableError)
221  {
222   memset(buf, 0, 2352 + 96);
223   return(false);
224  }
225 
226  try
227  {
228   disc_cdaccess->Read_Raw_Sector(buf, lba);
229  }
230  catch(std::exception &e)
231  {
232   MDFN_PrintError(_("Sector %u read error: %s"), lba, e.what());
233   memset(buf, 0, 2352 + 96);
234   return(false);
235  }
236 
237  return(true);
238 }
239 
Eject(bool eject_status)240 bool CDIF_ST::Eject(bool eject_status)
241 {
242  if(UnrecoverableError)
243   return(false);
244 
245  try
246  {
247   int32 old_de = DiscEjected;
248 
249   DiscEjected = eject_status;
250 
251   if(old_de != DiscEjected)
252   {
253    disc_cdaccess->Eject(eject_status);
254 
255    if(!eject_status)     // Re-read the TOC
256    {
257     disc_cdaccess->Read_TOC(&disc_toc);
258 
259     if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track)
260     {
261      throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track));
262     }
263    }
264   }
265  }
266  catch(std::exception &e)
267  {
268   MDFN_PrintError("%s", e.what());
269   return(false);
270  }
271 
272  return(true);
273 }
274 
CDIF_Open(const char * path,const bool is_device,bool image_memcache)275 CDIF *CDIF_Open(const char *path, const bool is_device, bool image_memcache)
276 {
277    CDAccess *cda = cdaccess_open_image(path, image_memcache);
278 
279    return new CDIF_ST(cda);
280 }
281