Search
lxdream.org :: lxdream/src/gdrom/gdimage.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/gdimage.c
changeset 678:35eb00945316
prev669:ab344e42bca9
next709:18c39a8e504c
author nkeynes
date Sat Jun 14 11:54:15 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Change colour params to float
Convert background processing over to scene structure (fixes some depth issues as well)
Add color unclamp when supported
file annotate diff log raw
nkeynes@342
     1
/**
nkeynes@561
     2
 * $Id$
nkeynes@342
     3
 *
nkeynes@342
     4
 * GD-Rom image-file common functions. 
nkeynes@342
     5
 *
nkeynes@342
     6
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@342
     7
 *
nkeynes@342
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@342
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@342
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@342
    11
 * (at your option) any later version.
nkeynes@342
    12
 *
nkeynes@342
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@342
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@342
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@342
    16
 * GNU General Public License for more details.
nkeynes@342
    17
 */
nkeynes@342
    18
nkeynes@644
    19
#include <assert.h>
nkeynes@422
    20
#include <netinet/in.h>
nkeynes@422
    21
nkeynes@678
    22
#include "gdrom/gddriver.h"
nkeynes@342
    23
#include "gdrom/packet.h"
nkeynes@644
    24
#include "ecc.h"
nkeynes@422
    25
#include "bootstrap.h"
nkeynes@342
    26
nkeynes@342
    27
static void gdrom_image_destroy( gdrom_disc_t disc );
nkeynes@342
    28
static gdrom_error_t gdrom_image_read_sector( gdrom_disc_t disc, uint32_t lba, int mode, 
nkeynes@422
    29
					      unsigned char *buf, uint32_t *readlength );
nkeynes@422
    30
static gdrom_error_t gdrom_image_read_toc( gdrom_disc_t disc, unsigned char *buf );
nkeynes@422
    31
static gdrom_error_t gdrom_image_read_session( gdrom_disc_t disc, int session, unsigned char *buf );
nkeynes@422
    32
static gdrom_error_t gdrom_image_read_position( gdrom_disc_t disc, uint32_t lba, unsigned char *buf );
nkeynes@342
    33
static int gdrom_image_drive_status( gdrom_disc_t disc );
nkeynes@342
    34
nkeynes@644
    35
static uint8_t gdrom_default_sync[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
nkeynes@644
    36
nkeynes@644
    37
#define SECTOR_HEADER_SIZE 16
nkeynes@644
    38
#define SECTOR_SUBHEADER_SIZE 8
nkeynes@644
    39
nkeynes@644
    40
/* Data offset (from start of raw sector) by sector mode */
nkeynes@644
    41
static int gdrom_data_offset[] = { 16, 16, 16, 24, 24, 0, 8, 0, 0 };
nkeynes@644
    42
nkeynes@644
    43
nkeynes@644
    44
nkeynes@498
    45
struct cdrom_sector_header {
nkeynes@498
    46
    uint8_t sync[12];
nkeynes@498
    47
    uint8_t msf[3];
nkeynes@498
    48
    uint8_t mode;
nkeynes@644
    49
    uint8_t subhead[8]; // Mode-2 XA sectors only
nkeynes@498
    50
};
nkeynes@342
    51
nkeynes@342
    52
/**
nkeynes@342
    53
 * Initialize a gdrom_disc structure with the gdrom_image_* methods
nkeynes@342
    54
 */
nkeynes@342
    55
void gdrom_image_init( gdrom_disc_t disc )
nkeynes@342
    56
{
nkeynes@342
    57
    memset( disc, 0, sizeof(struct gdrom_disc) ); /* safety */
nkeynes@342
    58
    disc->read_sector = gdrom_image_read_sector;
nkeynes@342
    59
    disc->read_toc = gdrom_image_read_toc;
nkeynes@342
    60
    disc->read_session = gdrom_image_read_session;
nkeynes@342
    61
    disc->read_position = gdrom_image_read_position;
nkeynes@342
    62
    disc->drive_status = gdrom_image_drive_status;
nkeynes@342
    63
    disc->play_audio = NULL; /* not supported yet */
nkeynes@342
    64
    disc->run_time_slice = NULL; /* not needed */
nkeynes@342
    65
    disc->close = gdrom_image_destroy;
nkeynes@342
    66
}
nkeynes@342
    67
nkeynes@464
    68
gdrom_disc_t gdrom_image_new( const gchar *filename, FILE *f )
nkeynes@342
    69
{
nkeynes@342
    70
    gdrom_image_t image = (gdrom_image_t)calloc(sizeof(struct gdrom_image), 1);
nkeynes@342
    71
    if( image == NULL ) {
nkeynes@342
    72
	return NULL;
nkeynes@342
    73
    }
nkeynes@644
    74
    image->disc_type = IDE_DISC_CDROMXA;
nkeynes@342
    75
    image->file = f;
nkeynes@342
    76
    gdrom_disc_t disc = (gdrom_disc_t)image;
nkeynes@342
    77
    gdrom_image_init(disc);
nkeynes@464
    78
    if( filename == NULL ) {
nkeynes@464
    79
	disc->name = NULL;
nkeynes@464
    80
    } else {
nkeynes@464
    81
	disc->name = g_strdup(filename);
nkeynes@464
    82
    }
nkeynes@464
    83
nkeynes@342
    84
    return disc;
nkeynes@342
    85
}
nkeynes@342
    86
nkeynes@342
    87
static void gdrom_image_destroy( gdrom_disc_t disc )
nkeynes@342
    88
{
nkeynes@492
    89
    int i;
nkeynes@492
    90
    FILE *lastfile = NULL;
nkeynes@342
    91
    gdrom_image_t img = (gdrom_image_t)disc;
nkeynes@342
    92
    if( img->file != NULL ) {
nkeynes@342
    93
	fclose(img->file);
nkeynes@342
    94
	img->file = NULL;
nkeynes@342
    95
    }
nkeynes@492
    96
    for( i=0; i<img->track_count; i++ ) {
nkeynes@492
    97
	if( img->track[i].file != NULL && img->track[i].file != lastfile ) {
nkeynes@492
    98
	    lastfile = img->track[i].file;
nkeynes@492
    99
	    fclose(lastfile);
nkeynes@492
   100
	    img->track[i].file = NULL;
nkeynes@492
   101
	}
nkeynes@492
   102
    }
nkeynes@464
   103
    if( disc->name != NULL ) {
nkeynes@480
   104
	g_free( (gpointer)disc->name );
nkeynes@464
   105
	disc->name = NULL;
nkeynes@464
   106
    }
nkeynes@342
   107
    free( disc );
nkeynes@342
   108
}
nkeynes@342
   109
nkeynes@468
   110
void gdrom_image_destroy_no_close( gdrom_disc_t disc )
nkeynes@468
   111
{
nkeynes@492
   112
    int i;
nkeynes@492
   113
    FILE *lastfile = NULL;
nkeynes@468
   114
    gdrom_image_t img = (gdrom_image_t)disc;
nkeynes@468
   115
    if( img->file != NULL ) {
nkeynes@468
   116
	img->file = NULL;
nkeynes@468
   117
    }
nkeynes@492
   118
    for( i=0; i<img->track_count; i++ ) {
nkeynes@492
   119
	if( img->track[i].file != NULL && img->track[i].file != lastfile ) {
nkeynes@492
   120
	    lastfile = img->track[i].file;
nkeynes@492
   121
	    fclose(lastfile);
nkeynes@492
   122
	    img->track[i].file = NULL;
nkeynes@492
   123
	}
nkeynes@492
   124
    }
nkeynes@468
   125
    if( disc->name != NULL ) {
nkeynes@480
   126
	g_free( (gpointer)disc->name );
nkeynes@468
   127
	disc->name = NULL;
nkeynes@468
   128
    }
nkeynes@468
   129
    free( disc );
nkeynes@468
   130
}
nkeynes@468
   131
nkeynes@342
   132
static int gdrom_image_get_track_by_lba( gdrom_image_t image, uint32_t lba )
nkeynes@342
   133
{
nkeynes@342
   134
    int i;
nkeynes@342
   135
    for( i=0; i<image->track_count; i++ ) {
nkeynes@342
   136
	if( image->track[i].lba <= lba && 
nkeynes@342
   137
	    lba < (image->track[i].lba + image->track[i].sector_count) ) {
nkeynes@342
   138
	    return i+1;
nkeynes@342
   139
	}
nkeynes@342
   140
    }
nkeynes@342
   141
    return -1;
nkeynes@342
   142
}
nkeynes@342
   143
nkeynes@492
   144
/**
nkeynes@492
   145
 * Read a block from an image file, handling negative file offsets
nkeynes@492
   146
 * with 0-fill.
nkeynes@492
   147
 */
nkeynes@644
   148
static gboolean gdrom_read_block( unsigned char *buf, int file_offset, int length, FILE *f )
nkeynes@492
   149
{
nkeynes@492
   150
    if( file_offset < 0 ) {
nkeynes@492
   151
	int size = -file_offset;
nkeynes@492
   152
	if( size >= length ) {
nkeynes@492
   153
	    memset( buf, 0, length );
nkeynes@669
   154
	    return TRUE;
nkeynes@492
   155
	} else {
nkeynes@492
   156
	    memset( buf, 0, size );
nkeynes@492
   157
	    file_offset = 0;
nkeynes@492
   158
	    length -= size;
nkeynes@492
   159
	}
nkeynes@492
   160
    }
nkeynes@492
   161
    fseek( f, file_offset, SEEK_SET );
nkeynes@644
   162
    return fread( buf, length, 1, f ) == 1;
nkeynes@492
   163
}
nkeynes@492
   164
nkeynes@644
   165
static void gdrom_build_sector_header( unsigned char *buf, uint32_t lba, 
nkeynes@644
   166
				       gdrom_track_mode_t sector_mode )
nkeynes@644
   167
{
nkeynes@644
   168
    memcpy( buf, gdrom_default_sync, 12 );
nkeynes@644
   169
    cd_build_address( buf, sector_mode, lba );
nkeynes@644
   170
}
nkeynes@644
   171
nkeynes@644
   172
/**
nkeynes@644
   173
 * Return TRUE if the given read mode + track modes are compatible,
nkeynes@644
   174
 * otherwise FALSE.
nkeynes@644
   175
 * @param track_mode one of the GDROM_MODE* constants
nkeynes@644
   176
 * @param read_mode the READ_CD_MODE from the read request
nkeynes@644
   177
 */
nkeynes@644
   178
static gboolean gdrom_is_compatible_read_mode( int track_mode, int read_mode )
nkeynes@644
   179
{
nkeynes@644
   180
    switch( read_mode ) {
nkeynes@644
   181
    case READ_CD_MODE_ANY:
nkeynes@644
   182
	return TRUE;
nkeynes@644
   183
    case READ_CD_MODE_CDDA:
nkeynes@644
   184
	return track_mode == GDROM_CDDA;
nkeynes@644
   185
    case READ_CD_MODE_1:
nkeynes@644
   186
	return track_mode == GDROM_MODE1 || track_mode == GDROM_MODE2_FORM1;
nkeynes@644
   187
    case READ_CD_MODE_2_FORM_1:
nkeynes@644
   188
	return track_mode == GDROM_MODE1 || track_mode == GDROM_MODE2_FORM1;
nkeynes@644
   189
    case READ_CD_MODE_2_FORM_2:
nkeynes@644
   190
	return track_mode == GDROM_MODE2_FORM2;
nkeynes@644
   191
    case READ_CD_MODE_2:
nkeynes@644
   192
	return track_mode == GDROM_MODE2_FORMLESS;
nkeynes@644
   193
    default:
nkeynes@644
   194
	return FALSE;
nkeynes@644
   195
    }
nkeynes@644
   196
}
nkeynes@644
   197
nkeynes@644
   198
/**
nkeynes@644
   199
 * Determine the start position in a raw sector, and the amount of data to read
nkeynes@644
   200
 * in bytes, for a given combination of sector mode and read mode.
nkeynes@644
   201
 */ 
nkeynes@644
   202
static void gdrom_get_read_bounds( int sector_mode, int read_mode, int *start, int *size )
nkeynes@644
   203
{
nkeynes@644
   204
    if( READ_CD_RAW(read_mode) ) {
nkeynes@644
   205
	// whole sector
nkeynes@644
   206
	*start = 0;
nkeynes@644
   207
	*size = 2352;
nkeynes@644
   208
    } else {
nkeynes@644
   209
	*size = 0;
nkeynes@644
   210
	if( READ_CD_DATA(read_mode) ) {
nkeynes@644
   211
	    *start = gdrom_data_offset[sector_mode];
nkeynes@644
   212
	    *size = gdrom_sector_size[sector_mode];
nkeynes@644
   213
	}
nkeynes@644
   214
nkeynes@644
   215
	if( READ_CD_SUBHEAD(read_mode) && 
nkeynes@644
   216
	    (sector_mode == GDROM_MODE2_FORM1 || sector_mode == GDROM_MODE2_FORM2) ) {
nkeynes@644
   217
	    *start = SECTOR_HEADER_SIZE;
nkeynes@644
   218
	    *size += SECTOR_SUBHEADER_SIZE;
nkeynes@644
   219
	}
nkeynes@644
   220
nkeynes@644
   221
	if( READ_CD_HEADER(read_mode) ) {
nkeynes@644
   222
	    *size += SECTOR_HEADER_SIZE;
nkeynes@644
   223
	    *start = 0;
nkeynes@644
   224
	}
nkeynes@644
   225
nkeynes@644
   226
    }
nkeynes@644
   227
}
nkeynes@644
   228
nkeynes@644
   229
/**
nkeynes@644
   230
 * Read a single sector from a disc image. If you thought this would be simple, 
nkeynes@644
   231
 * I have just one thing to say to you: Bwahahahahahahahah.
nkeynes@644
   232
 *
nkeynes@644
   233
 * Once we've decided that there's a real sector at the requested lba, there's 
nkeynes@644
   234
 * really two things we need to care about:
nkeynes@644
   235
 *   1. Is the sector mode compatible with the requested read mode
nkeynes@644
   236
 *   2. Which parts of the sector do we need to return? 
nkeynes@644
   237
 *      (header/subhead/data/raw sector)
nkeynes@644
   238
 *
nkeynes@644
   239
 * Also note that the disc image may supply us with just the data (most common 
nkeynes@644
   240
 * case), or may have the full raw sector. In the former case we may need to 
nkeynes@644
   241
 * generate the missing data on the fly, for which we use libedc to compute the
nkeynes@644
   242
 * data correction codes.
nkeynes@644
   243
 */
nkeynes@342
   244
static gdrom_error_t gdrom_image_read_sector( gdrom_disc_t disc, uint32_t lba,
nkeynes@422
   245
					      int mode, unsigned char *buf, uint32_t *length )
nkeynes@342
   246
{
nkeynes@342
   247
    gdrom_image_t image = (gdrom_image_t)disc;
nkeynes@498
   248
    struct cdrom_sector_header secthead;
nkeynes@422
   249
    int file_offset, read_len, track_no;
nkeynes@498
   250
nkeynes@492
   251
    FILE *f;
nkeynes@342
   252
nkeynes@342
   253
    track_no = gdrom_image_get_track_by_lba( image, lba );
nkeynes@342
   254
    if( track_no == -1 ) {
nkeynes@342
   255
	return PKT_ERR_BADREAD;
nkeynes@342
   256
    }
nkeynes@342
   257
    struct gdrom_track *track = &image->track[track_no-1];
nkeynes@342
   258
    file_offset = track->offset + track->sector_size * (lba - track->lba);
nkeynes@342
   259
    read_len = track->sector_size;
nkeynes@492
   260
    if( track->file != NULL ) {
nkeynes@492
   261
	f = track->file;
nkeynes@492
   262
    } else {
nkeynes@492
   263
	f = image->file;
nkeynes@492
   264
    }
nkeynes@492
   265
nkeynes@644
   266
    /* First figure out what the real sector mode is for raw/semiraw sectors */
nkeynes@644
   267
    int sector_mode;
nkeynes@644
   268
    switch( track->mode ) {
nkeynes@644
   269
    case GDROM_RAW_NONXA:
nkeynes@644
   270
	gdrom_read_block( (unsigned char *)(&secthead), file_offset, sizeof(secthead), f );
nkeynes@644
   271
	sector_mode = (secthead.mode == 1) ? GDROM_MODE1 : GDROM_MODE2_FORMLESS;
nkeynes@644
   272
	break;
nkeynes@644
   273
    case GDROM_RAW_XA:
nkeynes@644
   274
	gdrom_read_block( (unsigned char *)(&secthead), file_offset, sizeof(secthead), f );
nkeynes@644
   275
	if( secthead.mode == 1 ) {
nkeynes@644
   276
	    sector_mode = GDROM_MODE1;
nkeynes@644
   277
	} else {
nkeynes@644
   278
	    sector_mode = ((secthead.subhead[2] & 0x20) == 0 ) ? GDROM_MODE2_FORM1 : GDROM_MODE2_FORM2;
nkeynes@342
   279
	}
nkeynes@342
   280
	break;
nkeynes@644
   281
    case GDROM_SEMIRAW_MODE2:
nkeynes@644
   282
	gdrom_read_block( secthead.subhead, file_offset, 8, f );
nkeynes@644
   283
	sector_mode = ((secthead.subhead[2] & 0x20) == 0 ) ? GDROM_MODE2_FORM1 : GDROM_MODE2_FORM2;
nkeynes@644
   284
	break;
nkeynes@342
   285
    default:
nkeynes@644
   286
	/* In the other cases, the track mode completely defines the sector mode */
nkeynes@644
   287
	sector_mode = track->mode;
nkeynes@644
   288
	break;
nkeynes@644
   289
    }
nkeynes@644
   290
nkeynes@644
   291
    if( !gdrom_is_compatible_read_mode(sector_mode, READ_CD_MODE(mode)) ) {
nkeynes@342
   292
	return PKT_ERR_BADREADMODE;
nkeynes@342
   293
    }
nkeynes@644
   294
nkeynes@644
   295
    /* Ok, we've got a valid sector, check what parts of the sector we need to
nkeynes@644
   296
     * return - header | subhead | data | everything
nkeynes@644
   297
     */
nkeynes@644
   298
    int channels = READ_CD_CHANNELS(mode);
nkeynes@644
   299
nkeynes@644
   300
    if( channels == 0 ) {
nkeynes@644
   301
	// legal, if weird
nkeynes@644
   302
	*length = 0;
nkeynes@644
   303
	return PKT_ERR_OK;
nkeynes@644
   304
    } else if( channels == 0xA0 && 
nkeynes@644
   305
	(sector_mode == GDROM_MODE2_FORM1 || sector_mode == GDROM_MODE2_FORM2 )) {
nkeynes@644
   306
	// caller requested a non-contiguous region
nkeynes@644
   307
	return PKT_ERR_BADFIELD;
nkeynes@644
   308
    } else if( READ_CD_RAW(channels) ) {
nkeynes@644
   309
	channels = 0xF0; // implies everything
nkeynes@644
   310
    }
nkeynes@644
   311
nkeynes@644
   312
    read_len = 0;
nkeynes@644
   313
    int start, size;
nkeynes@644
   314
    switch( track->mode ) {
nkeynes@644
   315
    case GDROM_CDDA:
nkeynes@644
   316
	// audio is nice and simple (assume perfect reads for now)
nkeynes@644
   317
	*length = 2352;
nkeynes@644
   318
	gdrom_read_block( buf, file_offset, track->sector_size, f );
nkeynes@644
   319
	return PKT_ERR_OK;
nkeynes@644
   320
    case GDROM_RAW_XA:
nkeynes@644
   321
    case GDROM_RAW_NONXA:
nkeynes@644
   322
	gdrom_get_read_bounds( sector_mode, channels, &start, &size );
nkeynes@644
   323
	gdrom_read_block( buf, file_offset+start, size, f );
nkeynes@644
   324
	read_len = size;
nkeynes@644
   325
	break;
nkeynes@644
   326
    case GDROM_SEMIRAW_MODE2:
nkeynes@644
   327
	gdrom_get_read_bounds( sector_mode, channels, &start, &size );
nkeynes@644
   328
	if( READ_CD_HEADER(channels) ) {
nkeynes@644
   329
	    gdrom_build_sector_header( buf, lba, sector_mode );
nkeynes@644
   330
	    read_len += SECTOR_HEADER_SIZE;
nkeynes@644
   331
	    size -= SECTOR_HEADER_SIZE;
nkeynes@644
   332
	} else {
nkeynes@644
   333
	    start -= SECTOR_HEADER_SIZE;
nkeynes@644
   334
	}
nkeynes@644
   335
	gdrom_read_block( buf + read_len, file_offset+start, size, f );
nkeynes@644
   336
	read_len += size;
nkeynes@644
   337
	break;
nkeynes@644
   338
    default: // Data track w/ data only in file
nkeynes@644
   339
	if( READ_CD_RAW(channels) ) {
nkeynes@644
   340
	    gdrom_read_block( buf + gdrom_data_offset[track->mode], file_offset, 
nkeynes@644
   341
			      track->sector_size, f );
nkeynes@644
   342
	    do_encode_L2( buf, sector_mode, lba );
nkeynes@644
   343
	    read_len = 2352;
nkeynes@644
   344
	} else {
nkeynes@644
   345
	    if( READ_CD_HEADER(channels) ) {
nkeynes@644
   346
		gdrom_build_sector_header( buf, lba, sector_mode );
nkeynes@644
   347
		read_len += SECTOR_HEADER_SIZE;
nkeynes@644
   348
	    }
nkeynes@644
   349
	    if( READ_CD_SUBHEAD(channels) && 
nkeynes@644
   350
		(sector_mode == GDROM_MODE2_FORM1 || sector_mode == GDROM_MODE2_FORM2) ) {
nkeynes@644
   351
		if( sector_mode == GDROM_MODE2_FORM1 ) {
nkeynes@644
   352
		    *((uint32_t *)(buf+read_len)) = 0;
nkeynes@644
   353
		    *((uint32_t *)(buf+read_len+4)) = 0;
nkeynes@644
   354
		} else {
nkeynes@644
   355
		    *((uint32_t *)(buf+read_len)) = 0x00200000;
nkeynes@644
   356
		    *((uint32_t *)(buf+read_len+4)) = 0x00200000;
nkeynes@644
   357
		}
nkeynes@644
   358
		read_len += 8;
nkeynes@644
   359
	    }
nkeynes@644
   360
	    if( READ_CD_DATA(channels) ) {
nkeynes@644
   361
		gdrom_read_block( buf+read_len, file_offset, track->sector_size, f );
nkeynes@644
   362
		read_len += track->sector_size;
nkeynes@644
   363
	    }
nkeynes@644
   364
	}
nkeynes@644
   365
    }
nkeynes@342
   366
    *length = read_len;
nkeynes@342
   367
    return PKT_ERR_OK;
nkeynes@342
   368
}
nkeynes@342
   369
nkeynes@422
   370
static gdrom_error_t gdrom_image_read_toc( gdrom_disc_t disc, unsigned char *buf ) 
nkeynes@342
   371
{
nkeynes@342
   372
    gdrom_image_t image = (gdrom_image_t)disc;
nkeynes@342
   373
    struct gdrom_toc *toc = (struct gdrom_toc *)buf;
nkeynes@342
   374
    int i;
nkeynes@342
   375
nkeynes@342
   376
    for( i=0; i<image->track_count; i++ ) {
nkeynes@342
   377
	toc->track[i] = htonl( image->track[i].lba ) | image->track[i].flags;
nkeynes@342
   378
    }
nkeynes@342
   379
    toc->first = 0x0100 | image->track[0].flags;
nkeynes@342
   380
    toc->last = (image->track_count<<8) | image->track[i-1].flags;
nkeynes@342
   381
    toc->leadout = htonl(image->track[i-1].lba + image->track[i-1].sector_count) |
nkeynes@342
   382
	image->track[i-1].flags;
nkeynes@342
   383
    for( ;i<99; i++ )
nkeynes@342
   384
	toc->track[i] = 0xFFFFFFFF;
nkeynes@342
   385
    return PKT_ERR_OK;
nkeynes@342
   386
}
nkeynes@342
   387
nkeynes@422
   388
static gdrom_error_t gdrom_image_read_session( gdrom_disc_t disc, int session, unsigned char *buf )
nkeynes@342
   389
{
nkeynes@342
   390
    gdrom_image_t image = (gdrom_image_t)disc;
nkeynes@342
   391
    struct gdrom_track *last_track = &image->track[image->track_count-1];
nkeynes@342
   392
    unsigned int end_of_disc = last_track->lba + last_track->sector_count;
nkeynes@342
   393
    int i;
nkeynes@342
   394
    buf[0] = 0x01; /* Disc status? */
nkeynes@342
   395
    buf[1] = 0;
nkeynes@342
   396
nkeynes@342
   397
    if( session == 0 ) {
nkeynes@342
   398
	buf[2] = last_track->session+1; /* last session */
nkeynes@342
   399
	buf[3] = (end_of_disc >> 16) & 0xFF;
nkeynes@342
   400
	buf[4] = (end_of_disc >> 8) & 0xFF;
nkeynes@342
   401
	buf[5] = end_of_disc & 0xFF;
nkeynes@342
   402
	return PKT_ERR_OK;
nkeynes@342
   403
    } else {
nkeynes@342
   404
	session--;
nkeynes@342
   405
	for( i=0; i<image->track_count; i++ ) {
nkeynes@342
   406
	    if( image->track[i].session == session ) {
nkeynes@342
   407
		buf[2] = i+1; /* first track of session */
nkeynes@342
   408
		buf[3] = (image->track[i].lba >> 16) & 0xFF;
nkeynes@342
   409
		buf[4] = (image->track[i].lba >> 8) & 0xFF;
nkeynes@342
   410
		buf[5] = image->track[i].lba & 0xFF;
nkeynes@342
   411
		return PKT_ERR_OK;
nkeynes@342
   412
	    }
nkeynes@342
   413
	}
nkeynes@342
   414
	return PKT_ERR_BADFIELD; /* No such session */
nkeynes@342
   415
    }
nkeynes@342
   416
}
nkeynes@342
   417
nkeynes@422
   418
static gdrom_error_t gdrom_image_read_position( gdrom_disc_t disc, uint32_t lba, unsigned char *buf )
nkeynes@342
   419
{
nkeynes@342
   420
    gdrom_image_t image = (gdrom_image_t)disc;
nkeynes@342
   421
    int track_no = gdrom_image_get_track_by_lba( image, lba );
nkeynes@342
   422
    if( track_no == -1 ) {
nkeynes@342
   423
	track_no = 1;
nkeynes@342
   424
	lba = 150;
nkeynes@342
   425
    }
nkeynes@342
   426
    struct gdrom_track *track = &image->track[track_no-1];
nkeynes@342
   427
    uint32_t offset = lba - track->lba;
nkeynes@342
   428
    buf[4] = track->flags;
nkeynes@342
   429
    buf[5] = track_no;
nkeynes@342
   430
    buf[6] = 0x01; /* ?? */
nkeynes@342
   431
    buf[7] = (offset >> 16) & 0xFF;
nkeynes@342
   432
    buf[8] = (offset >> 8) & 0xFF;
nkeynes@342
   433
    buf[9] = offset & 0xFF;
nkeynes@342
   434
    buf[10] = 0;
nkeynes@342
   435
    buf[11] = (lba >> 16) & 0xFF;
nkeynes@342
   436
    buf[12] = (lba >> 8) & 0xFF;
nkeynes@342
   437
    buf[13] = lba & 0xFF;
nkeynes@422
   438
    return PKT_ERR_OK;
nkeynes@342
   439
}
nkeynes@342
   440
nkeynes@342
   441
static int gdrom_image_drive_status( gdrom_disc_t disc ) 
nkeynes@342
   442
{
nkeynes@342
   443
    gdrom_image_t image = (gdrom_image_t)disc;
nkeynes@342
   444
    return image->disc_type | IDE_DISC_READY;
nkeynes@342
   445
}
nkeynes@342
   446
nkeynes@342
   447
void gdrom_image_dump_info( gdrom_disc_t d ) {
nkeynes@342
   448
    gdrom_image_t disc = (gdrom_image_t)d;
nkeynes@342
   449
    int i;
nkeynes@342
   450
    int last_session = disc->track[disc->track_count-1].session;
nkeynes@342
   451
    gboolean is_bootable = FALSE;
nkeynes@342
   452
nkeynes@342
   453
    INFO( "Disc ID: %s, %d tracks in %d sessions", disc->mcn, disc->track_count, 
nkeynes@342
   454
	  disc->track[disc->track_count-1].session + 1 );
nkeynes@342
   455
    if( last_session > 0 ) {
nkeynes@342
   456
	/* Boot track is the first data track of the last session, provided that it 
nkeynes@342
   457
	 * cannot be a single-session disc.
nkeynes@342
   458
	 */
nkeynes@342
   459
	int boot_track = -1;
nkeynes@342
   460
	for( i=disc->track_count-1; i>=0 && disc->track[i].session == last_session; i-- ) {
nkeynes@342
   461
	    if( disc->track[i].flags & TRACK_DATA ) {
nkeynes@342
   462
		boot_track = i;
nkeynes@342
   463
	    }
nkeynes@342
   464
	}
nkeynes@342
   465
	if( boot_track != -1 ) {
nkeynes@422
   466
	    unsigned char boot_sector[MAX_SECTOR_SIZE];
nkeynes@342
   467
	    uint32_t length = sizeof(boot_sector);
nkeynes@342
   468
	    if( d->read_sector( d, disc->track[boot_track].lba, 0x28,
nkeynes@342
   469
				   boot_sector, &length ) == PKT_ERR_OK ) {
nkeynes@342
   470
		bootstrap_dump(boot_sector, FALSE);
nkeynes@342
   471
		is_bootable = TRUE;
nkeynes@342
   472
	    }
nkeynes@342
   473
	}
nkeynes@342
   474
    }
nkeynes@342
   475
    if( !is_bootable ) {
nkeynes@342
   476
	WARN( "Disc does not appear to be bootable" );
nkeynes@342
   477
    }
nkeynes@342
   478
}
nkeynes@342
   479
.