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