1 /******************************************************************************/
2 /* Mednafen - Multi-system Emulator */
3 /******************************************************************************/
4 /* CDInterface.cpp:
5 ** Copyright (C) 2009-2018 Mednafen Team
6 **
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software Foundation, Inc.,
19 ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #include <mednafen/mednafen.h>
23 #include <mednafen/cdrom/CDInterface.h>
24 #include "CDInterface_MT.h"
25 #include "CDInterface_ST.h"
26 #include "CDAccess.h"
27
28 namespace Mednafen
29 {
30
31 using namespace CDUtility;
32
CDInterface()33 CDInterface::CDInterface() : UnrecoverableError(false)
34 {
35
36
37 }
38
~CDInterface()39 CDInterface::~CDInterface()
40 {
41
42
43 }
44
NonDeterministic_CheckSectorReady(int32 lba)45 bool CDInterface::NonDeterministic_CheckSectorReady(int32 lba)
46 {
47 return true;
48 }
49
ReadSectors(uint8 * buf,int32 lba,uint32 sector_count)50 uint8 CDInterface::ReadSectors(uint8* buf, int32 lba, uint32 sector_count)
51 {
52 uint8 ret = 0;
53
54 if(UnrecoverableError)
55 return 0;
56
57 while(sector_count--)
58 {
59 uint8 rawbuf[2352 + 96];
60 uint8 mode;
61
62 if(!ReadRawSector(rawbuf, lba))
63 {
64 printf("ReadRawSector() failed in CDInterface::ReadSectors() for LBA=%d.\n", lba);
65 return 0;
66 }
67
68 mode = rawbuf[12 + 3];
69 if(mode != 0x1 && mode != 0x2)
70 return 0;
71
72 // Error if mode 2 form 2.
73 if(mode == 0x2 && (rawbuf[12 + 6] & 0x20))
74 return 0;
75
76 if(!edc_lec_check_and_correct(rawbuf, mode == 2))
77 return false;
78
79 memcpy(buf, rawbuf + ((mode == 2) ? 24 : 16), 2048);
80 ret = ret ? ret : mode;
81
82 lba++;
83 buf += 2048;
84 }
85
86 return ret;
87 }
88
89
90 class CDInterface_Stream_Thing : public Stream
91 {
92 public:
93
94 CDInterface_Stream_Thing(CDInterface *cdintf_arg, uint32 lba_arg, uint32 sector_count_arg);
95 ~CDInterface_Stream_Thing();
96
97 virtual uint64 attributes(void) override;
98
99 virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) override;
100 virtual void write(const void *data, uint64 count) override;
101 virtual void truncate(uint64 length) override;
102
103 virtual void seek(int64 offset, int whence) override;
104 virtual uint64 tell(void) override;
105 virtual uint64 size(void) override;
106 virtual void flush(void) override;
107 virtual void close(void) override;
108
109 private:
110 CDInterface *cdintf;
111 const uint32 start_lba;
112 const uint32 sector_count;
113 int64 position;
114 };
115
CDInterface_Stream_Thing(CDInterface * cdintf_arg,uint32 start_lba_arg,uint32 sector_count_arg)116 CDInterface_Stream_Thing::CDInterface_Stream_Thing(CDInterface *cdintf_arg, uint32 start_lba_arg, uint32 sector_count_arg) : cdintf(cdintf_arg), start_lba(start_lba_arg), sector_count(sector_count_arg)
117 {
118
119 }
120
~CDInterface_Stream_Thing()121 CDInterface_Stream_Thing::~CDInterface_Stream_Thing()
122 {
123
124 }
125
attributes(void)126 uint64 CDInterface_Stream_Thing::attributes(void)
127 {
128 return(ATTRIBUTE_READABLE | ATTRIBUTE_SEEKABLE);
129 }
130
read(void * data,uint64 count,bool error_on_eos)131 uint64 CDInterface_Stream_Thing::read(void *data, uint64 count, bool error_on_eos)
132 {
133 if(count > (((uint64)sector_count * 2048) - position))
134 {
135 if(error_on_eos)
136 {
137 throw MDFN_Error(0, "EOF");
138 }
139
140 count = ((uint64)sector_count * 2048) - position;
141 }
142
143 if(!count)
144 return(0);
145
146 for(uint64 rp = position; rp < (position + count); rp = (rp &~ 2047) + 2048)
147 {
148 uint8 buf[2048];
149
150 if(!cdintf->ReadSectors(buf, start_lba + (rp / 2048), 1))
151 {
152 throw MDFN_Error(ErrnoHolder(EIO));
153 }
154
155 //::printf("Meow: %08llx -- %08llx\n", count, (rp - position) + std::min<uint64>(2048 - (rp & 2047), count - (rp - position)));
156 memcpy((uint8*)data + (rp - position), buf + (rp & 2047), std::min<uint64>(2048 - (rp & 2047), count - (rp - position)));
157 }
158
159 position += count;
160
161 return count;
162 }
163
write(const void * data,uint64 count)164 void CDInterface_Stream_Thing::write(const void *data, uint64 count)
165 {
166 throw MDFN_Error(ErrnoHolder(EBADF));
167 }
168
truncate(uint64 length)169 void CDInterface_Stream_Thing::truncate(uint64 length)
170 {
171 throw MDFN_Error(ErrnoHolder(EBADF));
172 }
173
seek(int64 offset,int whence)174 void CDInterface_Stream_Thing::seek(int64 offset, int whence)
175 {
176 int64 new_position;
177
178 switch(whence)
179 {
180 default:
181 throw MDFN_Error(ErrnoHolder(EINVAL));
182 break;
183
184 case SEEK_SET:
185 new_position = offset;
186 break;
187
188 case SEEK_CUR:
189 new_position = position + offset;
190 break;
191
192 case SEEK_END:
193 new_position = ((int64)sector_count * 2048) + offset;
194 break;
195 }
196
197 if(new_position < 0 || new_position > ((int64)sector_count * 2048))
198 throw MDFN_Error(ErrnoHolder(EINVAL));
199
200 position = new_position;
201 }
202
tell(void)203 uint64 CDInterface_Stream_Thing::tell(void)
204 {
205 return position;
206 }
207
size(void)208 uint64 CDInterface_Stream_Thing::size(void)
209 {
210 return(sector_count * 2048);
211 }
212
flush(void)213 void CDInterface_Stream_Thing::flush(void)
214 {
215
216 }
217
close(void)218 void CDInterface_Stream_Thing::close(void)
219 {
220
221 }
222
223
MakeStream(int32 lba,uint32 sector_count)224 Stream *CDInterface::MakeStream(int32 lba, uint32 sector_count)
225 {
226 return new CDInterface_Stream_Thing(this, lba, sector_count);
227 }
228
229
Open(VirtualFS * vfs,const std::string & path,bool image_memcache,const uint64 affinity)230 CDInterface* CDInterface::Open(VirtualFS* vfs, const std::string& path, bool image_memcache, const uint64 affinity)
231 {
232 std::unique_ptr<CDAccess> cda(CDAccess_Open(vfs, path, image_memcache));
233
234 //
235 // Don't use multithreaded reader if we're using a custom VirtualFS implementation, to avoid
236 // thread safety nightmares.
237 //
238 if(image_memcache || (vfs != &NVFS))
239 return new CDInterface_ST(std::move(cda));
240 else
241 return new CDInterface_MT(std::move(cda), affinity);
242 }
243
244 }
245