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