~ubuntu-branches/debian/experimental/mednafen/experimental

« back to all changes in this revision

Viewing changes to src/cdrom/CDAccess_Physical.cpp

  • Committer: Package Import Robot
  • Author(s): Stephen Kitt
  • Date: 2012-01-31 07:21:35 UTC
  • mfrom: (1.2.8)
  • Revision ID: package-import@ubuntu.com-20120131072135-es3dj12y00xcnrsk
Tags: 0.9.19-1
* New upstream WIP version.
* Update copyright information.
* Refresh use-system-tremor.patch and remove psx-big-endian-only.patch.
* Add spelling-fixes.patch based on Lintian's recommendations.
* Build-depend on debhelper 9 or later and remove corresponding Lintian
  override.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#define EXTERNAL_LIBCDIO_CONFIG_H 1
 
19
 
 
20
#include "../mednafen.h"
 
21
#include "../general.h"
 
22
 
 
23
#include "CDAccess.h"
 
24
#include "CDAccess_Physical.h"
 
25
 
 
26
#include <time.h>
 
27
 
 
28
#include <cdio/cdio.h>
 
29
#include <cdio/mmc.h>
 
30
 
 
31
#if LIBCDIO_VERSION_NUM >= 83
 
32
#include <cdio/mmc_cmds.h>
 
33
#endif
 
34
 
 
35
using namespace CDUtility;
 
36
 
 
37
void CDAccess_Physical::DetermineFeatures(void)
 
38
{
 
39
 uint8 buf[256];
 
40
 
 
41
 mmc_cdb_t cdb = {{0, }};
 
42
 
 
43
 CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SENSE_10);
 
44
 
 
45
 memset(buf, 0, sizeof(buf));
 
46
 
 
47
 cdb.field[2] = 0x2A;
 
48
 
 
49
 cdb.field[7] = sizeof(buf) >> 8;
 
50
 cdb.field[8] = sizeof(buf) & 0xFF;
 
51
 
 
52
 if(mmc_run_cmd ((CdIo *)p_cdio, MMC_TIMEOUT_DEFAULT,
 
53
                    &cdb,
 
54
                    SCSI_MMC_DATA_READ,
 
55
                    sizeof(buf),
 
56
                    buf))
 
57
 {
 
58
  throw(MDFN_Error(0, _("MMC [MODE SENSE 10] command failed.")));
 
59
 }
 
60
 else
 
61
 {
 
62
  const uint8 *pd = &buf[8];
 
63
 
 
64
  if(pd[0] != 0x2A || pd[1] < 0x14)
 
65
  {
 
66
   throw(MDFN_Error(0, _("MMC [MODE SENSE 10] command returned bogus data for mode page 0x2A.")));
 
67
  }
 
68
 
 
69
  if(!(pd[4] & 0x10))
 
70
  {
 
71
   throw(MDFN_Error(0, _("Drive does not support reading Mode 2 Form 1 sectors.")));
 
72
  }
 
73
 
 
74
  if(!(pd[4] & 0x20))
 
75
  {
 
76
   throw(MDFN_Error(0, _("Drive does not support reading Mode 2 Form 2 sectors.")));
 
77
  }
 
78
 
 
79
  if(!(pd[5] & 0x01))
 
80
  {
 
81
   throw(MDFN_Error(0, _("Reading CD-DA sectors via \"READ CD\" is not supported.")));
 
82
  }
 
83
 
 
84
  if(!(pd[5] & 0x02))
 
85
  {
 
86
   throw(MDFN_Error(0, _("Read CD-DA sectors via \"READ CD\" are not positionally-accurate.")));
 
87
  }
 
88
 
 
89
  if(!(pd[5] & 0x04))
 
90
  {
 
91
   throw(MDFN_Error(0, _("Reading raw subchannel data via \"READ CD\" is not supported.")));
 
92
  }
 
93
 }
 
94
}
 
95
 
 
96
void CDAccess_Physical::PreventAllowMediumRemoval(bool prevent)
 
97
{
 
98
#if 0
 
99
 mmc_cdb_t cdb = {{0, }};
 
100
 uint8 buf[8];
 
101
 
 
102
 cdb.field[0] = 0x1E;
 
103
 cdb.field[1] = 0x00;
 
104
 cdb.field[2] = 0x00;
 
105
 cdb.field[3] = 0x00;
 
106
 cdb.field[4] = 0x00; //prevent;
 
107
 cdb.field[5] = 0x00;
 
108
 
 
109
 printf("%d\n", mmc_run_cmd_len (p_cdio, MMC_TIMEOUT_DEFAULT,
 
110
                      &cdb, 6,
 
111
                      SCSI_MMC_DATA_READ, 0, buf));
 
112
 assert(0);
 
113
#endif
 
114
}
 
115
 
 
116
void CDAccess_Physical::ReadPhysDiscInfo(unsigned retry)
 
117
{
 
118
 mmc_cdb_t cdb = {{0, }};
 
119
 uint8 toc_buffer[8192];
 
120
 int64 start_time = time(NULL);
 
121
 int cdio_rc;
 
122
 
 
123
 cdb.field[0] = 0x43;   // Read TOC
 
124
 cdb.field[1] = 0x00;
 
125
 cdb.field[2] = 0x00;   // Format 0000b
 
126
 cdb.field[3] = 0x00;
 
127
 cdb.field[4] = 0x00;
 
128
 cdb.field[5] = 0x00;
 
129
 cdb.field[6] = 0x01;   // Track number
 
130
 cdb.field[7] = sizeof(toc_buffer) >> 8;
 
131
 cdb.field[8] = sizeof(toc_buffer) & 0xFF;
 
132
 cdb.field[9] = 0x00;
 
133
 
 
134
 memset(toc_buffer, 0, sizeof(toc_buffer));
 
135
 
 
136
 while((cdio_rc = mmc_run_cmd ((CdIo *)p_cdio, MMC_TIMEOUT_DEFAULT,
 
137
                      &cdb,
 
138
                      SCSI_MMC_DATA_READ,
 
139
                      sizeof(toc_buffer),
 
140
                      toc_buffer)))
 
141
 {
 
142
  if(!retry || time(NULL) >= (start_time + retry))
 
143
  {
 
144
   throw(MDFN_Error(0, _("Error reading disc TOC.")));
 
145
  }
 
146
 }
 
147
 
 
148
 PhysTOC.Clear();
 
149
 
 
150
 PhysTOC.first_track = toc_buffer[2];
 
151
 PhysTOC.last_track = toc_buffer[3];
 
152
 
 
153
 if(PhysTOC.first_track < 1 || PhysTOC.first_track > 99)
 
154
 {
 
155
  throw(MDFN_Error(0, _("Invalid first track: %d\n"), PhysTOC.first_track));
 
156
 }
 
157
 
 
158
 if(PhysTOC.last_track > 99 || PhysTOC.last_track < PhysTOC.first_track)
 
159
 {
 
160
  throw(MDFN_Error(0, _("Invalid last track: %d\n"), PhysTOC.last_track));
 
161
 }
 
162
 
 
163
 int32 len_counter = MDFN_de16msb(&toc_buffer[0]) - 2;
 
164
 uint8 *tbi = &toc_buffer[4];
 
165
 
 
166
 assert(len_counter >= 0);
 
167
 assert((len_counter & 7) == 0);
 
168
 
 
169
 while(len_counter)
 
170
 {
 
171
  uint8 adr = tbi[1] >> 4;
 
172
  uint8 control = tbi[1] & 0xF;
 
173
  uint8 tnum = tbi[2];
 
174
  uint32 lba = MDFN_de32msb(&tbi[4]);
 
175
 
 
176
  if(tnum == 0xAA)
 
177
  {
 
178
   PhysTOC.tracks[100].adr = adr;
 
179
   PhysTOC.tracks[100].control = control;
 
180
   PhysTOC.tracks[100].lba = lba;
 
181
  }
 
182
  else if(tnum >= PhysTOC.first_track && tnum <= PhysTOC.last_track)
 
183
  {
 
184
   PhysTOC.tracks[tnum].adr = adr;
 
185
   PhysTOC.tracks[tnum].control = control;
 
186
   PhysTOC.tracks[tnum].lba = lba;
 
187
  }
 
188
 
 
189
  tbi += 8;
 
190
  len_counter -= 8;
 
191
 }
 
192
 
 
193
 // Convenience leadout track duplication.
 
194
 if(PhysTOC.last_track < 99)
 
195
  PhysTOC.tracks[PhysTOC.last_track + 1] = PhysTOC.tracks[100];
 
196
}
 
197
 
 
198
void CDAccess_Physical::Read_TOC(TOC *toc)
 
199
{
 
200
 *toc = PhysTOC;
 
201
}
 
202
 
 
203
void CDAccess_Physical::Read_Raw_Sector(uint8 *buf, int32 lba)
 
204
{
 
205
 mmc_cdb_t cdb = {{0, }};
 
206
 int cdio_rc;
 
207
 
 
208
 CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_CD);
 
209
 CDIO_MMC_SET_READ_TYPE    (cdb.field, CDIO_MMC_READ_TYPE_ANY);
 
210
 CDIO_MMC_SET_READ_LBA     (cdb.field, lba);
 
211
 CDIO_MMC_SET_READ_LENGTH24(cdb.field, 1);
 
212
 
 
213
 if(SkipSectorRead[(lba >> 3) & 0xFFFF] & (1 << (lba & 7)))
 
214
 {
 
215
  printf("Read(skipped): %d\n", lba);
 
216
  memset(buf, 0, 2352);
 
217
 
 
218
  cdb.field[9] = 0x00;
 
219
  cdb.field[10] = 0x01;
 
220
 
 
221
  if((cdio_rc = mmc_run_cmd ((CdIo *)p_cdio, MMC_TIMEOUT_DEFAULT,
 
222
                      &cdb,
 
223
                      SCSI_MMC_DATA_READ,
 
224
                      96,
 
225
                      buf + 2352)))
 
226
  {
 
227
   throw(MDFN_Error(0, _("MMC Read Error; libcdio return code %d"), cdio_rc));
 
228
  }
 
229
 }
 
230
 else
 
231
 {
 
232
  cdb.field[9] = 0xF8;
 
233
  cdb.field[10] = 0x01;
 
234
 
 
235
  if((cdio_rc = mmc_run_cmd ((CdIo *)p_cdio, MMC_TIMEOUT_DEFAULT,
 
236
                      &cdb,
 
237
                      SCSI_MMC_DATA_READ,
 
238
                      2352 + 96,
 
239
                      buf)))
 
240
  {
 
241
   throw(MDFN_Error(0, _("MMC Read Error; libcdio return code %d"), cdio_rc));
 
242
  }
 
243
 }
 
244
}
 
245
 
 
246
CDAccess_Physical::CDAccess_Physical(const char *path)
 
247
{
 
248
 char **devices = NULL;
 
249
 char **parseit = NULL;
 
250
 
 
251
 p_cdio = NULL;
 
252
 
 
253
 cdio_init();
 
254
 
 
255
//
 
256
//
 
257
//
 
258
 try
 
259
 {
 
260
  devices = cdio_get_devices(DRIVER_DEVICE);
 
261
  parseit = devices;
 
262
  if(parseit)
 
263
  {
 
264
   MDFN_printf(_("Connected physical devices:\n"));
 
265
   MDFN_indent(1);
 
266
   while(*parseit)
 
267
   {
 
268
    MDFN_printf("%s\n", *parseit);
 
269
    parseit++;
 
270
   }
 
271
   MDFN_indent(-1);
 
272
  }
 
273
 
 
274
  if(!parseit || parseit == devices)
 
275
  {
 
276
   throw(MDFN_Error(0, _("No CDROM drives detected(or no disc present).")));
 
277
  }
 
278
 
 
279
  if(devices)
 
280
  {
 
281
   cdio_free_device_list(devices);
 
282
   devices = NULL;
 
283
  }
 
284
 
 
285
  p_cdio = cdio_open_cd(path); //, DRIVER_UNKNOWN); //NULL, DRIVER_UNKNOWN);
 
286
  if(!p_cdio) 
 
287
  {
 
288
   throw(MDFN_Error(0, _("Unknown error opening physical CD")));
 
289
  }
 
290
 
 
291
  //PreventAllowMediumRemoval(true);
 
292
  ReadPhysDiscInfo(0);
 
293
 
 
294
  //
 
295
  // Determine how we can read this CD.
 
296
  //
 
297
  DetermineFeatures();
 
298
 
 
299
  memset(SkipSectorRead, 0, sizeof(SkipSectorRead));
 
300
 }
 
301
 catch(std::exception &e)
 
302
 {
 
303
  if(devices)
 
304
   cdio_free_device_list(devices);
 
305
 
 
306
  if(p_cdio)
 
307
   cdio_destroy((CdIo *)p_cdio);
 
308
 
 
309
  throw;
 
310
 }
 
311
}
 
312
 
 
313
CDAccess_Physical::~CDAccess_Physical()
 
314
{
 
315
 cdio_destroy((CdIo *)p_cdio);
 
316
}
 
317
 
 
318
bool CDAccess_Physical::Is_Physical(void)
 
319
{
 
320
 return(true);
 
321
}
 
322
 
 
323
void CDAccess_Physical::Eject(bool eject_status)
 
324
{
 
325
 int cdio_rc;
 
326
 
 
327
#if LIBCDIO_VERSION_NUM >= 83
 
328
 if((cdio_rc = mmc_start_stop_unit((CdIo *)p_cdio, eject_status, false, 0, 0)) != 0)
 
329
 {
 
330
  if(cdio_rc != DRIVER_OP_UNSUPPORTED)  // Don't error out if it's just an unsupported operation.
 
331
   throw(MDFN_Error(0, _("Error ejecting medium;; libcdio return code %d"), cdio_rc));
 
332
 }
 
333
#else
 
334
 if((cdio_rc = mmc_start_stop_media((CdIo *)p_cdio, eject_status, false, 0)) != 0)
 
335
 {
 
336
  if(cdio_rc != DRIVER_OP_UNSUPPORTED)  // Don't error out if it's just an unsupported operation.
 
337
   throw(MDFN_Error(0, _("Error ejecting medium;; libcdio return code %d"), cdio_rc));
 
338
 }
 
339
#endif
 
340
 
 
341
 if(!eject_status)
 
342
 {
 
343
  try
 
344
  {
 
345
   ReadPhysDiscInfo(10);
 
346
  }
 
347
  catch(std::exception &e)
 
348
  {
 
349
#if LIBCDIO_VERSION_NUM >= 83
 
350
   mmc_start_stop_unit((CdIo *)p_cdio, true, false, 0, 0);      // Eject disc, if possible.
 
351
#else
 
352
   mmc_start_stop_media((CdIo *)p_cdio, true, false, 0);        // Eject disc, if possible.
 
353
#endif
 
354
   throw;
 
355
  }
 
356
 }
 
357
}
 
358