1.1 --- a/src/gdrom/gdimage.c Thu Feb 21 06:12:00 2008 +0000
1.2 +++ b/src/gdrom/gdimage.c Sun Mar 02 11:38:08 2008 +0000
1.4 * GNU General Public License for more details.
1.8 #include <netinet/in.h>
1.10 #include "gdrom/gdrom.h"
1.11 #include "gdrom/packet.h"
1.13 #include "bootstrap.h"
1.15 static void gdrom_image_destroy( gdrom_disc_t disc );
1.17 static gdrom_error_t gdrom_image_read_position( gdrom_disc_t disc, uint32_t lba, unsigned char *buf );
1.18 static int gdrom_image_drive_status( gdrom_disc_t disc );
1.20 +static uint8_t gdrom_default_sync[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
1.22 +#define SECTOR_HEADER_SIZE 16
1.23 +#define SECTOR_SUBHEADER_SIZE 8
1.25 +/* Data offset (from start of raw sector) by sector mode */
1.26 +static int gdrom_data_offset[] = { 16, 16, 16, 24, 24, 0, 8, 0, 0 };
1.30 struct cdrom_sector_header {
1.34 + uint8_t subhead[8]; // Mode-2 XA sectors only
1.39 if( image == NULL ) {
1.42 - image->disc_type = IDE_DISC_CDROM;
1.43 + image->disc_type = IDE_DISC_CDROMXA;
1.45 gdrom_disc_t disc = (gdrom_disc_t)image;
1.46 gdrom_image_init(disc);
1.48 * Read a block from an image file, handling negative file offsets
1.51 -static void gdrom_read_block( unsigned char *buf, int file_offset, int length, FILE *f )
1.52 +static gboolean gdrom_read_block( unsigned char *buf, int file_offset, int length, FILE *f )
1.54 if( file_offset < 0 ) {
1.55 int size = -file_offset;
1.56 @@ -146,9 +159,88 @@
1.59 fseek( f, file_offset, SEEK_SET );
1.60 - fread( buf, length, 1, f );
1.61 + return fread( buf, length, 1, f ) == 1;
1.64 +static void gdrom_build_sector_header( unsigned char *buf, uint32_t lba,
1.65 + gdrom_track_mode_t sector_mode )
1.67 + memcpy( buf, gdrom_default_sync, 12 );
1.68 + cd_build_address( buf, sector_mode, lba );
1.72 + * Return TRUE if the given read mode + track modes are compatible,
1.73 + * otherwise FALSE.
1.74 + * @param track_mode one of the GDROM_MODE* constants
1.75 + * @param read_mode the READ_CD_MODE from the read request
1.77 +static gboolean gdrom_is_compatible_read_mode( int track_mode, int read_mode )
1.79 + switch( read_mode ) {
1.80 + case READ_CD_MODE_ANY:
1.82 + case READ_CD_MODE_CDDA:
1.83 + return track_mode == GDROM_CDDA;
1.84 + case READ_CD_MODE_1:
1.85 + return track_mode == GDROM_MODE1 || track_mode == GDROM_MODE2_FORM1;
1.86 + case READ_CD_MODE_2_FORM_1:
1.87 + return track_mode == GDROM_MODE1 || track_mode == GDROM_MODE2_FORM1;
1.88 + case READ_CD_MODE_2_FORM_2:
1.89 + return track_mode == GDROM_MODE2_FORM2;
1.90 + case READ_CD_MODE_2:
1.91 + return track_mode == GDROM_MODE2_FORMLESS;
1.98 + * Determine the start position in a raw sector, and the amount of data to read
1.99 + * in bytes, for a given combination of sector mode and read mode.
1.101 +static void gdrom_get_read_bounds( int sector_mode, int read_mode, int *start, int *size )
1.103 + if( READ_CD_RAW(read_mode) ) {
1.109 + if( READ_CD_DATA(read_mode) ) {
1.110 + *start = gdrom_data_offset[sector_mode];
1.111 + *size = gdrom_sector_size[sector_mode];
1.114 + if( READ_CD_SUBHEAD(read_mode) &&
1.115 + (sector_mode == GDROM_MODE2_FORM1 || sector_mode == GDROM_MODE2_FORM2) ) {
1.116 + *start = SECTOR_HEADER_SIZE;
1.117 + *size += SECTOR_SUBHEADER_SIZE;
1.120 + if( READ_CD_HEADER(read_mode) ) {
1.121 + *size += SECTOR_HEADER_SIZE;
1.129 + * Read a single sector from a disc image. If you thought this would be simple,
1.130 + * I have just one thing to say to you: Bwahahahahahahahah.
1.132 + * Once we've decided that there's a real sector at the requested lba, there's
1.133 + * really two things we need to care about:
1.134 + * 1. Is the sector mode compatible with the requested read mode
1.135 + * 2. Which parts of the sector do we need to return?
1.136 + * (header/subhead/data/raw sector)
1.138 + * Also note that the disc image may supply us with just the data (most common
1.139 + * case), or may have the full raw sector. In the former case we may need to
1.140 + * generate the missing data on the fly, for which we use libedc to compute the
1.141 + * data correction codes.
1.143 static gdrom_error_t gdrom_image_read_sector( gdrom_disc_t disc, uint32_t lba,
1.144 int mode, unsigned char *buf, uint32_t *length )
1.146 @@ -171,47 +263,109 @@
1.153 - case 0x20: /* Actually, read anything, but for now... */
1.157 - switch( track->mode ) {
1.158 - case GDROM_MODE1:
1.159 - case GDROM_MODE2_XA1:
1.160 - gdrom_read_block( buf, file_offset, track->sector_size, f );
1.162 - case GDROM_MODE2:
1.163 - file_offset += 8; /* skip the subheader */
1.164 - gdrom_read_block( buf, file_offset, 2048, f );
1.167 - gdrom_read_block( (unsigned char *)(§head), file_offset, sizeof(secthead), f );
1.168 - switch( secthead.mode ) {
1.170 - file_offset += 16;
1.173 - file_offset += 24;
1.176 - return PKT_ERR_BADREADMODE;
1.178 - gdrom_read_block( buf, file_offset, 2048, f );
1.181 - return PKT_ERR_BADREADMODE;
1.182 + /* First figure out what the real sector mode is for raw/semiraw sectors */
1.184 + switch( track->mode ) {
1.185 + case GDROM_RAW_NONXA:
1.186 + gdrom_read_block( (unsigned char *)(§head), file_offset, sizeof(secthead), f );
1.187 + sector_mode = (secthead.mode == 1) ? GDROM_MODE1 : GDROM_MODE2_FORMLESS;
1.189 + case GDROM_RAW_XA:
1.190 + gdrom_read_block( (unsigned char *)(§head), file_offset, sizeof(secthead), f );
1.191 + if( secthead.mode == 1 ) {
1.192 + sector_mode = GDROM_MODE1;
1.194 + sector_mode = ((secthead.subhead[2] & 0x20) == 0 ) ? GDROM_MODE2_FORM1 : GDROM_MODE2_FORM2;
1.197 + case GDROM_SEMIRAW_MODE2:
1.198 + gdrom_read_block( secthead.subhead, file_offset, 8, f );
1.199 + sector_mode = ((secthead.subhead[2] & 0x20) == 0 ) ? GDROM_MODE2_FORM1 : GDROM_MODE2_FORM2;
1.202 + /* In the other cases, the track mode completely defines the sector mode */
1.203 + sector_mode = track->mode;
1.207 + int mode_restrict = READ_CD_MODE(mode);
1.208 + if( !gdrom_is_compatible_read_mode(sector_mode, READ_CD_MODE(mode)) ) {
1.209 return PKT_ERR_BADREADMODE;
1.213 + /* Ok, we've got a valid sector, check what parts of the sector we need to
1.214 + * return - header | subhead | data | everything
1.216 + int channels = READ_CD_CHANNELS(mode);
1.218 + if( channels == 0 ) {
1.219 + // legal, if weird
1.221 + return PKT_ERR_OK;
1.222 + } else if( channels == 0xA0 &&
1.223 + (sector_mode == GDROM_MODE2_FORM1 || sector_mode == GDROM_MODE2_FORM2 )) {
1.224 + // caller requested a non-contiguous region
1.225 + return PKT_ERR_BADFIELD;
1.226 + } else if( READ_CD_RAW(channels) ) {
1.227 + channels = 0xF0; // implies everything
1.232 + switch( track->mode ) {
1.234 + // audio is nice and simple (assume perfect reads for now)
1.236 + gdrom_read_block( buf, file_offset, track->sector_size, f );
1.237 + return PKT_ERR_OK;
1.238 + case GDROM_RAW_XA:
1.239 + case GDROM_RAW_NONXA:
1.240 + gdrom_get_read_bounds( sector_mode, channels, &start, &size );
1.241 + gdrom_read_block( buf, file_offset+start, size, f );
1.244 + case GDROM_SEMIRAW_MODE2:
1.245 + gdrom_get_read_bounds( sector_mode, channels, &start, &size );
1.246 + if( READ_CD_HEADER(channels) ) {
1.247 + gdrom_build_sector_header( buf, lba, sector_mode );
1.248 + read_len += SECTOR_HEADER_SIZE;
1.249 + size -= SECTOR_HEADER_SIZE;
1.251 + start -= SECTOR_HEADER_SIZE;
1.253 + gdrom_read_block( buf + read_len, file_offset+start, size, f );
1.254 + read_len += size;
1.256 + default: // Data track w/ data only in file
1.257 + if( READ_CD_RAW(channels) ) {
1.258 + gdrom_read_block( buf + gdrom_data_offset[track->mode], file_offset,
1.259 + track->sector_size, f );
1.260 + do_encode_L2( buf, sector_mode, lba );
1.263 + if( READ_CD_HEADER(channels) ) {
1.264 + gdrom_build_sector_header( buf, lba, sector_mode );
1.265 + read_len += SECTOR_HEADER_SIZE;
1.267 + if( READ_CD_SUBHEAD(channels) &&
1.268 + (sector_mode == GDROM_MODE2_FORM1 || sector_mode == GDROM_MODE2_FORM2) ) {
1.269 + if( sector_mode == GDROM_MODE2_FORM1 ) {
1.270 + *((uint32_t *)(buf+read_len)) = 0;
1.271 + *((uint32_t *)(buf+read_len+4)) = 0;
1.273 + *((uint32_t *)(buf+read_len)) = 0x00200000;
1.274 + *((uint32_t *)(buf+read_len+4)) = 0x00200000;
1.278 + if( READ_CD_DATA(channels) ) {
1.279 + gdrom_read_block( buf+read_len, file_offset, track->sector_size, f );
1.280 + read_len += track->sector_size;
1.284 *length = read_len;
1.289 static gdrom_error_t gdrom_image_read_toc( gdrom_disc_t disc, unsigned char *buf )