Search
lxdream.org :: lxdream/src/gdrom/gdimage.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/gdimage.c
changeset 644:ccae4bfa5f82
prev640:01b50fd48035
next669:ab344e42bca9
author nkeynes
date Sun Mar 02 11:38:08 2008 +0000 (14 years ago)
permissions -rw-r--r--
last change Bug #59: Add provisional support for all CD read modes (not validated)
file annotate diff log raw
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.3 @@ -16,10 +16,12 @@
1.4 * GNU General Public License for more details.
1.5 */
1.6
1.7 +#include <assert.h>
1.8 #include <netinet/in.h>
1.9
1.10 #include "gdrom/gdrom.h"
1.11 #include "gdrom/packet.h"
1.12 +#include "ecc.h"
1.13 #include "bootstrap.h"
1.14
1.15 static void gdrom_image_destroy( gdrom_disc_t disc );
1.16 @@ -30,10 +32,21 @@
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.19
1.20 +static uint8_t gdrom_default_sync[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
1.21 +
1.22 +#define SECTOR_HEADER_SIZE 16
1.23 +#define SECTOR_SUBHEADER_SIZE 8
1.24 +
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.27 +
1.28 +
1.29 +
1.30 struct cdrom_sector_header {
1.31 uint8_t sync[12];
1.32 uint8_t msf[3];
1.33 uint8_t mode;
1.34 + uint8_t subhead[8]; // Mode-2 XA sectors only
1.35 };
1.36
1.37 /**
1.38 @@ -58,7 +71,7 @@
1.39 if( image == NULL ) {
1.40 return NULL;
1.41 }
1.42 - image->disc_type = IDE_DISC_CDROM;
1.43 + image->disc_type = IDE_DISC_CDROMXA;
1.44 image->file = f;
1.45 gdrom_disc_t disc = (gdrom_disc_t)image;
1.46 gdrom_image_init(disc);
1.47 @@ -132,7 +145,7 @@
1.48 * Read a block from an image file, handling negative file offsets
1.49 * with 0-fill.
1.50 */
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.53 {
1.54 if( file_offset < 0 ) {
1.55 int size = -file_offset;
1.56 @@ -146,9 +159,88 @@
1.57 }
1.58 }
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.62 }
1.63
1.64 +static void gdrom_build_sector_header( unsigned char *buf, uint32_t lba,
1.65 + gdrom_track_mode_t sector_mode )
1.66 +{
1.67 + memcpy( buf, gdrom_default_sync, 12 );
1.68 + cd_build_address( buf, sector_mode, lba );
1.69 +}
1.70 +
1.71 +/**
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.76 + */
1.77 +static gboolean gdrom_is_compatible_read_mode( int track_mode, int read_mode )
1.78 +{
1.79 + switch( read_mode ) {
1.80 + case READ_CD_MODE_ANY:
1.81 + return TRUE;
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.92 + default:
1.93 + return FALSE;
1.94 + }
1.95 +}
1.96 +
1.97 +/**
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.100 + */
1.101 +static void gdrom_get_read_bounds( int sector_mode, int read_mode, int *start, int *size )
1.102 +{
1.103 + if( READ_CD_RAW(read_mode) ) {
1.104 + // whole sector
1.105 + *start = 0;
1.106 + *size = 2352;
1.107 + } else {
1.108 + *size = 0;
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.112 + }
1.113 +
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.118 + }
1.119 +
1.120 + if( READ_CD_HEADER(read_mode) ) {
1.121 + *size += SECTOR_HEADER_SIZE;
1.122 + *start = 0;
1.123 + }
1.124 +
1.125 + }
1.126 +}
1.127 +
1.128 +/**
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.131 + *
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.137 + *
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.142 + */
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.145 {
1.146 @@ -171,47 +263,109 @@
1.147 f = image->file;
1.148 }
1.149
1.150 -
1.151 -
1.152 - switch( mode ) {
1.153 - case 0x20: /* Actually, read anything, but for now... */
1.154 - case 0x24:
1.155 - case 0x28:
1.156 - read_len = 2048;
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.161 - break;
1.162 - case GDROM_MODE2:
1.163 - file_offset += 8; /* skip the subheader */
1.164 - gdrom_read_block( buf, file_offset, 2048, f );
1.165 - break;
1.166 - case GDROM_RAW:
1.167 - gdrom_read_block( (unsigned char *)(&secthead), file_offset, sizeof(secthead), f );
1.168 - switch( secthead.mode ) {
1.169 - case 1:
1.170 - file_offset += 16;
1.171 - break;
1.172 - case 2:
1.173 - file_offset += 24;
1.174 - break;
1.175 - default:
1.176 - return PKT_ERR_BADREADMODE;
1.177 - }
1.178 - gdrom_read_block( buf, file_offset, 2048, f );
1.179 - break;
1.180 - default:
1.181 - return PKT_ERR_BADREADMODE;
1.182 + /* First figure out what the real sector mode is for raw/semiraw sectors */
1.183 + int sector_mode;
1.184 + switch( track->mode ) {
1.185 + case GDROM_RAW_NONXA:
1.186 + gdrom_read_block( (unsigned char *)(&secthead), file_offset, sizeof(secthead), f );
1.187 + sector_mode = (secthead.mode == 1) ? GDROM_MODE1 : GDROM_MODE2_FORMLESS;
1.188 + break;
1.189 + case GDROM_RAW_XA:
1.190 + gdrom_read_block( (unsigned char *)(&secthead), file_offset, sizeof(secthead), f );
1.191 + if( secthead.mode == 1 ) {
1.192 + sector_mode = GDROM_MODE1;
1.193 + } else {
1.194 + sector_mode = ((secthead.subhead[2] & 0x20) == 0 ) ? GDROM_MODE2_FORM1 : GDROM_MODE2_FORM2;
1.195 }
1.196 break;
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.200 + break;
1.201 default:
1.202 + /* In the other cases, the track mode completely defines the sector mode */
1.203 + sector_mode = track->mode;
1.204 + break;
1.205 + }
1.206 +
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.210 }
1.211 -
1.212 +
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.215 + */
1.216 + int channels = READ_CD_CHANNELS(mode);
1.217 +
1.218 + if( channels == 0 ) {
1.219 + // legal, if weird
1.220 + *length = 0;
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.228 + }
1.229 +
1.230 + read_len = 0;
1.231 + int start, size;
1.232 + switch( track->mode ) {
1.233 + case GDROM_CDDA:
1.234 + // audio is nice and simple (assume perfect reads for now)
1.235 + *length = 2352;
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.242 + read_len = size;
1.243 + break;
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.250 + } else {
1.251 + start -= SECTOR_HEADER_SIZE;
1.252 + }
1.253 + gdrom_read_block( buf + read_len, file_offset+start, size, f );
1.254 + read_len += size;
1.255 + break;
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.261 + read_len = 2352;
1.262 + } else {
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.266 + }
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.272 + } else {
1.273 + *((uint32_t *)(buf+read_len)) = 0x00200000;
1.274 + *((uint32_t *)(buf+read_len+4)) = 0x00200000;
1.275 + }
1.276 + read_len += 8;
1.277 + }
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.281 + }
1.282 + }
1.283 + }
1.284 *length = read_len;
1.285 return PKT_ERR_OK;
1.286 -
1.287 }
1.288
1.289 static gdrom_error_t gdrom_image_read_toc( gdrom_disc_t disc, unsigned char *buf )
.