filename | src/gdrom/gdimage.c |
changeset | 1071:182cfe43c09e |
prev | 1030:864417a57662 |
author | nkeynes |
date | Tue Dec 15 08:46:37 2009 +1000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Add side-by-side x86+sh4 disassembly output Print SH4 state information and disassembly of the current block when crashing. Fix delay slot instruction in conditional branch not being marked as a delay-slot instruction in the branch-not-taken path. Rename REG_* defines in cpu.h to avoid conflict with translation defs |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * GD-Rom image-file common functions.
5 *
6 * Copyright (c) 2005 Nathan Keynes.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
19 #include <assert.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <netinet/in.h>
28 #include "gdrom/gddriver.h"
29 #include "gdrom/packet.h"
30 #include "ecc.h"
32 static gboolean gdrom_null_check_status( gdrom_disc_t disc );
33 static gdrom_error_t gdrom_image_read_sector( gdrom_disc_t disc, uint32_t lba, int mode,
34 unsigned char *buf, uint32_t *readlength );
36 static uint8_t gdrom_default_sync[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
38 #define SECTOR_HEADER_SIZE 16
39 #define SECTOR_SUBHEADER_SIZE 8
41 /* Data offset (from start of raw sector) by sector mode */
42 static int gdrom_data_offset[] = { 16, 16, 16, 24, 24, 0, 8, 0, 0 };
44 gdrom_image_class_t gdrom_image_classes[] = { &cdrom_device_class,
45 &nrg_image_class,
46 &cdi_image_class,
47 &gdi_image_class,
48 NULL };
50 struct cdrom_sector_header {
51 uint8_t sync[12];
52 uint8_t msf[3];
53 uint8_t mode;
54 uint8_t subhead[8]; // Mode-2 XA sectors only
55 };
57 gdrom_disc_t gdrom_disc_new( const gchar *filename, FILE *f )
58 {
59 gdrom_disc_t disc = (gdrom_disc_t)g_malloc0(sizeof(struct gdrom_disc));
60 if( disc == NULL ) {
61 return NULL;
62 }
63 disc->disc_type = IDE_DISC_NONE;
64 disc->file = f;
65 if( filename == NULL ) {
66 disc->name = NULL;
67 } else {
68 disc->name = g_strdup(filename);
69 }
71 disc->check_status = gdrom_null_check_status;
72 disc->destroy = gdrom_disc_destroy;
73 return disc;
74 }
76 void gdrom_disc_destroy( gdrom_disc_t disc, gboolean close_fh )
77 {
78 int i;
79 FILE *lastfile = NULL;
80 if( disc->file != NULL ) {
81 if( close_fh ) {
82 fclose(disc->file);
83 }
84 disc->file = NULL;
85 }
86 for( i=0; i<disc->track_count; i++ ) {
87 if( disc->track[i].file != NULL && disc->track[i].file != lastfile ) {
88 lastfile = disc->track[i].file;
89 /* Track files (if any) are closed regardless of the value of close_fh */
90 fclose(lastfile);
91 disc->track[i].file = NULL;
92 }
93 }
94 if( disc->name != NULL ) {
95 g_free( (gpointer)disc->name );
96 disc->name = NULL;
97 }
98 if( disc->display_name != NULL ) {
99 g_free( (gpointer)disc->name );
100 disc->display_name = NULL;
101 }
102 free( disc );
103 }
105 /**
106 * Construct a new gdrom_disc_t and initalize the vtable to the gdrom image
107 * default functions.
108 */
109 gdrom_disc_t gdrom_image_new( const gchar *filename, FILE *f )
110 {
111 gdrom_disc_t disc = gdrom_disc_new( filename, f );
112 if( disc != NULL ) {
113 disc->read_sector = gdrom_image_read_sector;
114 disc->play_audio = NULL; /* not supported yet */
115 disc->run_time_slice = NULL; /* not needed */
116 }
117 return disc;
118 }
121 gdrom_disc_t gdrom_image_open( const gchar *inFilename )
122 {
123 const gchar *filename = inFilename;
124 const gchar *ext = strrchr(filename, '.');
125 gdrom_disc_t disc = NULL;
126 int fd;
127 FILE *f;
128 int i;
129 gdrom_image_class_t extclz = NULL;
131 // Check for a url-style filename.
132 char *lizard_lips = strstr( filename, "://" );
133 if( lizard_lips != NULL ) {
134 gchar *path = lizard_lips + 3;
135 int method_len = (lizard_lips-filename);
136 gchar method[method_len + 1];
137 memcpy( method, filename, method_len );
138 method[method_len] = '\0';
140 if( strcasecmp( method, "file" ) == 0 ) {
141 filename = path;
142 } else if( strcasecmp( method, "dvd" ) == 0 ||
143 strcasecmp( method, "cd" ) == 0 ||
144 strcasecmp( method, "cdrom" ) ) {
145 return cdrom_open_device( method, path );
146 } else {
147 ERROR( "Unrecognized URL method '%s' in filename '%s'", method, filename );
148 return NULL;
149 }
150 }
152 fd = open( filename, O_RDONLY | O_NONBLOCK );
153 if( fd == -1 ) {
154 return NULL;
155 }
157 f = fdopen(fd, "ro");
160 /* try extensions */
161 if( ext != NULL ) {
162 ext++; /* Skip the '.' */
163 for( i=0; gdrom_image_classes[i] != NULL; i++ ) {
164 if( gdrom_image_classes[i]->extension != NULL &&
165 strcasecmp( gdrom_image_classes[i]->extension, ext ) == 0 ) {
166 extclz = gdrom_image_classes[i];
167 if( extclz->is_valid_file(f) ) {
168 disc = extclz->open_image_file(filename, f);
169 if( disc != NULL )
170 return disc;
171 }
172 break;
173 }
174 }
175 }
177 /* Okay, fall back to magic */
178 gboolean recognized = FALSE;
179 for( i=0; gdrom_image_classes[i] != NULL; i++ ) {
180 if( gdrom_image_classes[i] != extclz &&
181 gdrom_image_classes[i]->is_valid_file(f) ) {
182 recognized = TRUE;
183 disc = gdrom_image_classes[i]->open_image_file(filename, f);
184 if( disc != NULL )
185 return disc;
186 }
187 }
189 fclose(f);
190 return NULL;
191 }
193 /**
194 * Read a block from an image file, handling negative file offsets
195 * with 0-fill.
196 */
197 static gboolean gdrom_read_block( unsigned char *buf, int file_offset, int length, FILE *f )
198 {
199 if( file_offset < 0 ) {
200 int size = -file_offset;
201 if( size >= length ) {
202 memset( buf, 0, length );
203 return TRUE;
204 } else {
205 memset( buf, 0, size );
206 file_offset = 0;
207 length -= size;
208 }
209 }
210 fseek( f, file_offset, SEEK_SET );
211 return fread( buf, length, 1, f ) == 1;
212 }
214 static void gdrom_build_sector_header( unsigned char *buf, uint32_t lba,
215 gdrom_track_mode_t sector_mode )
216 {
217 memcpy( buf, gdrom_default_sync, 12 );
218 cd_build_address( buf, sector_mode, lba );
219 }
221 /**
222 * Return TRUE if the given read mode + track modes are compatible,
223 * otherwise FALSE.
224 * @param track_mode one of the GDROM_MODE* constants
225 * @param read_mode the READ_CD_MODE from the read request
226 */
227 static gboolean gdrom_is_compatible_read_mode( int track_mode, int read_mode )
228 {
229 switch( read_mode ) {
230 case READ_CD_MODE_ANY:
231 return TRUE;
232 case READ_CD_MODE_CDDA:
233 return track_mode == GDROM_CDDA;
234 case READ_CD_MODE_1:
235 return track_mode == GDROM_MODE1 || track_mode == GDROM_MODE2_FORM1;
236 case READ_CD_MODE_2_FORM_1:
237 return track_mode == GDROM_MODE1 || track_mode == GDROM_MODE2_FORM1;
238 case READ_CD_MODE_2_FORM_2:
239 return track_mode == GDROM_MODE2_FORM2;
240 case READ_CD_MODE_2:
241 return track_mode == GDROM_MODE2_FORMLESS;
242 default:
243 return FALSE;
244 }
245 }
247 void gdrom_set_disc_type( gdrom_disc_t disc )
248 {
249 int type = IDE_DISC_NONE, i;
250 for( i=0; i<disc->track_count; i++ ) {
251 if( disc->track[i].mode == GDROM_CDDA ) {
252 if( type == IDE_DISC_NONE )
253 type = IDE_DISC_AUDIO;
254 } else if( disc->track[i].mode == GDROM_MODE1 || disc->track[i].mode == GDROM_RAW_NONXA ) {
255 if( type != IDE_DISC_CDROMXA )
256 type = IDE_DISC_CDROM;
257 } else {
258 type = IDE_DISC_CDROMXA;
259 break;
260 }
261 }
262 disc->disc_type = type;
263 }
265 /**
266 * Determine the start position in a raw sector, and the amount of data to read
267 * in bytes, for a given combination of sector mode and read mode.
268 */
269 static void gdrom_get_read_bounds( int sector_mode, int read_mode, int *start, int *size )
270 {
271 if( READ_CD_RAW(read_mode) ) {
272 // whole sector
273 *start = 0;
274 *size = 2352;
275 } else {
276 *size = 0;
277 if( READ_CD_DATA(read_mode) ) {
278 *start = gdrom_data_offset[sector_mode];
279 *size = gdrom_sector_size[sector_mode];
280 }
282 if( READ_CD_SUBHEAD(read_mode) &&
283 (sector_mode == GDROM_MODE2_FORM1 || sector_mode == GDROM_MODE2_FORM2) ) {
284 *start = SECTOR_HEADER_SIZE;
285 *size += SECTOR_SUBHEADER_SIZE;
286 }
288 if( READ_CD_HEADER(read_mode) ) {
289 *size += SECTOR_HEADER_SIZE;
290 *start = 0;
291 }
293 }
294 }
296 void gdrom_extract_raw_data_sector( char *sector_data, int channels, unsigned char *buf, uint32_t *length )
297 {
298 int sector_mode;
299 int start, size;
300 struct cdrom_sector_header *secthead = (struct cdrom_sector_header *)sector_data;
301 if( secthead->mode == 1 ) {
302 sector_mode = GDROM_MODE1;
303 } else {
304 sector_mode = ((secthead->subhead[2] & 0x20) == 0 ) ? GDROM_MODE2_FORM1 : GDROM_MODE2_FORM2;
305 }
306 gdrom_get_read_bounds( sector_mode, channels, &start, &size );
308 memcpy( buf, sector_data+start, size );
309 *length = size;
310 }
312 /**
313 * Default check media status that does nothing and always returns
314 * false (unchanged).
315 */
316 static gboolean gdrom_null_check_status( gdrom_disc_t disc )
317 {
318 return FALSE;
319 }
321 /**
322 * Read a single sector from a disc image. If you thought this would be simple,
323 * I have just one thing to say to you: Bwahahahahahahahah.
324 *
325 * Once we've decided that there's a real sector at the requested lba, there's
326 * really two things we need to care about:
327 * 1. Is the sector mode compatible with the requested read mode
328 * 2. Which parts of the sector do we need to return?
329 * (header/subhead/data/raw sector)
330 *
331 * Also note that the disc image may supply us with just the data (most common
332 * case), or may have the full raw sector. In the former case we may need to
333 * generate the missing data on the fly, for which we use libedc to compute the
334 * data correction codes.
335 */
336 static gdrom_error_t gdrom_image_read_sector( gdrom_disc_t disc, uint32_t lba,
337 int mode, unsigned char *buf, uint32_t *length )
338 {
339 struct cdrom_sector_header secthead;
340 int file_offset, read_len, track_no;
342 FILE *f;
344 track_no = gdrom_disc_get_track_by_lba( disc, lba );
345 if( track_no == -1 ) {
346 return PKT_ERR_BADREAD;
347 }
348 struct gdrom_track *track = &disc->track[track_no-1];
349 file_offset = track->offset + track->sector_size * (lba - track->lba);
350 read_len = track->sector_size;
351 if( track->file != NULL ) {
352 f = track->file;
353 } else {
354 f = disc->file;
355 }
357 /* First figure out what the real sector mode is for raw/semiraw sectors */
358 int sector_mode;
359 switch( track->mode ) {
360 case GDROM_RAW_NONXA:
361 gdrom_read_block( (unsigned char *)(§head), file_offset, sizeof(secthead), f );
362 sector_mode = (secthead.mode == 1) ? GDROM_MODE1 : GDROM_MODE2_FORMLESS;
363 break;
364 case GDROM_RAW_XA:
365 gdrom_read_block( (unsigned char *)(§head), file_offset, sizeof(secthead), f );
366 if( secthead.mode == 1 ) {
367 sector_mode = GDROM_MODE1;
368 } else {
369 sector_mode = ((secthead.subhead[2] & 0x20) == 0 ) ? GDROM_MODE2_FORM1 : GDROM_MODE2_FORM2;
370 }
371 break;
372 case GDROM_SEMIRAW_MODE2:
373 gdrom_read_block( secthead.subhead, file_offset, 8, f );
374 sector_mode = ((secthead.subhead[2] & 0x20) == 0 ) ? GDROM_MODE2_FORM1 : GDROM_MODE2_FORM2;
375 break;
376 default:
377 /* In the other cases, the track mode completely defines the sector mode */
378 sector_mode = track->mode;
379 break;
380 }
382 if( !gdrom_is_compatible_read_mode(sector_mode, READ_CD_MODE(mode)) ) {
383 return PKT_ERR_BADREADMODE;
384 }
386 /* Ok, we've got a valid sector, check what parts of the sector we need to
387 * return - header | subhead | data | everything
388 */
389 int channels = READ_CD_CHANNELS(mode);
391 if( channels == 0 ) {
392 // legal, if weird
393 *length = 0;
394 return PKT_ERR_OK;
395 } else if( channels == 0xA0 &&
396 (sector_mode == GDROM_MODE2_FORM1 || sector_mode == GDROM_MODE2_FORM2 )) {
397 // caller requested a non-contiguous region
398 return PKT_ERR_BADFIELD;
399 } else if( READ_CD_RAW(channels) ) {
400 channels = 0xF0; // implies everything
401 }
403 read_len = 0;
404 int start, size;
405 switch( track->mode ) {
406 case GDROM_CDDA:
407 // audio is nice and simple (assume perfect reads for now)
408 *length = 2352;
409 gdrom_read_block( buf, file_offset, track->sector_size, f );
410 return PKT_ERR_OK;
411 case GDROM_RAW_XA:
412 case GDROM_RAW_NONXA:
413 gdrom_get_read_bounds( sector_mode, channels, &start, &size );
414 gdrom_read_block( buf, file_offset+start, size, f );
415 read_len = size;
416 break;
417 case GDROM_SEMIRAW_MODE2:
418 gdrom_get_read_bounds( sector_mode, channels, &start, &size );
419 if( READ_CD_HEADER(channels) ) {
420 gdrom_build_sector_header( buf, lba, sector_mode );
421 read_len += SECTOR_HEADER_SIZE;
422 size -= SECTOR_HEADER_SIZE;
423 } else {
424 start -= SECTOR_HEADER_SIZE;
425 }
426 gdrom_read_block( buf + read_len, file_offset+start, size, f );
427 read_len += size;
428 break;
429 default: // Data track w/ data only in file
430 if( READ_CD_RAW(channels) ) {
431 gdrom_read_block( buf + gdrom_data_offset[track->mode], file_offset,
432 track->sector_size, f );
433 do_encode_L2( buf, sector_mode, lba );
434 read_len = 2352;
435 } else {
436 if( READ_CD_HEADER(channels) ) {
437 gdrom_build_sector_header( buf, lba, sector_mode );
438 read_len += SECTOR_HEADER_SIZE;
439 }
440 if( READ_CD_SUBHEAD(channels) &&
441 (sector_mode == GDROM_MODE2_FORM1 || sector_mode == GDROM_MODE2_FORM2) ) {
442 if( sector_mode == GDROM_MODE2_FORM1 ) {
443 *((uint32_t *)(buf+read_len)) = 0;
444 *((uint32_t *)(buf+read_len+4)) = 0;
445 } else {
446 *((uint32_t *)(buf+read_len)) = 0x00200000;
447 *((uint32_t *)(buf+read_len+4)) = 0x00200000;
448 }
449 read_len += 8;
450 }
451 if( READ_CD_DATA(channels) ) {
452 gdrom_read_block( buf+read_len, file_offset, track->sector_size, f );
453 read_len += track->sector_size;
454 }
455 }
456 }
457 *length = read_len;
458 return PKT_ERR_OK;
459 }
.