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 Sun Jun 22 04:01:27 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Commit work-in-progress CoreAudio driver
(along with various changes to the audio subsystem)
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
.