Search
lxdream.org :: lxdream/src/gdrom/gdimage.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/gdimage.c
changeset 1023:264e2fd90be8
prev840:c6a778c228a6
next1030:864417a57662
author nkeynes
date Mon Jun 08 04:12:21 2009 +0000 (13 years ago)
permissions -rw-r--r--
last change General cleanup of the GD-rom subsystem
- merge gdrom_image_t and gdrom_disc_t
- Abstract MMC devices using a lower-level scsi transport
- OSX: only look at the whole disc device, and ignore partitions
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@1023
    24
#include <sys/stat.h>
nkeynes@1023
    25
#include <fcntl.h>
nkeynes@422
    26
#include <netinet/in.h>
nkeynes@422
    27
nkeynes@678
    28
#include "gdrom/gddriver.h"
nkeynes@342
    29
#include "gdrom/packet.h"
nkeynes@644
    30
#include "ecc.h"
nkeynes@342
    31
nkeynes@1023
    32
static gboolean gdrom_null_check_status( gdrom_disc_t disc );
nkeynes@342
    33
static gdrom_error_t gdrom_image_read_sector( gdrom_disc_t disc, uint32_t lba, int mode, 
nkeynes@736
    34
                                              unsigned char *buf, uint32_t *readlength );
nkeynes@342
    35
nkeynes@644
    36
static uint8_t gdrom_default_sync[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
nkeynes@644
    37
nkeynes@644
    38
#define SECTOR_HEADER_SIZE 16
nkeynes@644
    39
#define SECTOR_SUBHEADER_SIZE 8
nkeynes@644
    40
nkeynes@644
    41
/* Data offset (from start of raw sector) by sector mode */
nkeynes@644
    42
static int gdrom_data_offset[] = { 16, 16, 16, 24, 24, 0, 8, 0, 0 };
nkeynes@644
    43
nkeynes@1023
    44
gdrom_image_class_t gdrom_image_classes[] = { &cdrom_device_class, 
nkeynes@1023
    45
        &nrg_image_class, 
nkeynes@1023
    46
        &cdi_image_class, 
nkeynes@1023
    47
        &gdi_image_class, 
nkeynes@1023
    48
        NULL };
nkeynes@644
    49
nkeynes@498
    50
struct cdrom_sector_header {
nkeynes@498
    51
    uint8_t sync[12];
nkeynes@498
    52
    uint8_t msf[3];
nkeynes@498
    53
    uint8_t mode;
nkeynes@644
    54
    uint8_t subhead[8]; // Mode-2 XA sectors only
nkeynes@498
    55
};
nkeynes@342
    56
nkeynes@1023
    57
gdrom_disc_t gdrom_disc_new( const gchar *filename, FILE *f )
nkeynes@342
    58
{
nkeynes@1023
    59
    gdrom_disc_t disc = (gdrom_disc_t)g_malloc0(sizeof(struct gdrom_disc));
nkeynes@1023
    60
    if( disc == NULL ) {
nkeynes@736
    61
        return NULL;
nkeynes@342
    62
    }
nkeynes@1023
    63
    disc->disc_type = IDE_DISC_NONE;
nkeynes@1023
    64
    disc->file = f;
nkeynes@464
    65
    if( filename == NULL ) {
nkeynes@736
    66
        disc->name = NULL;
nkeynes@464
    67
    } else {
nkeynes@736
    68
        disc->name = g_strdup(filename);
nkeynes@464
    69
    }
nkeynes@464
    70
nkeynes@1023
    71
	disc->check_status = gdrom_null_check_status;
nkeynes@1023
    72
	disc->destroy = gdrom_disc_destroy;
nkeynes@342
    73
    return disc;
nkeynes@342
    74
}
nkeynes@342
    75
nkeynes@1023
    76
void gdrom_disc_destroy( gdrom_disc_t disc, gboolean close_fh )
nkeynes@342
    77
{
nkeynes@492
    78
    int i;
nkeynes@492
    79
    FILE *lastfile = NULL;
nkeynes@1023
    80
    if( disc->file != NULL ) {
nkeynes@1023
    81
    	if( close_fh ) {
nkeynes@1023
    82
        	fclose(disc->file);
nkeynes@1023
    83
    	}
nkeynes@1023
    84
        disc->file = NULL;
nkeynes@342
    85
    }
nkeynes@1023
    86
    for( i=0; i<disc->track_count; i++ ) {
nkeynes@1023
    87
        if( disc->track[i].file != NULL && disc->track[i].file != lastfile ) {
nkeynes@1023
    88
            lastfile = disc->track[i].file;
nkeynes@1023
    89
            /* Track files (if any) are closed regardless of the value of close_fh */
nkeynes@736
    90
            fclose(lastfile);
nkeynes@1023
    91
            disc->track[i].file = NULL;
nkeynes@736
    92
        }
nkeynes@492
    93
    }
nkeynes@464
    94
    if( disc->name != NULL ) {
nkeynes@736
    95
        g_free( (gpointer)disc->name );
nkeynes@736
    96
        disc->name = NULL;
nkeynes@464
    97
    }
nkeynes@1023
    98
    if( disc->display_name != NULL ) {
nkeynes@1023
    99
    	g_free( (gpointer)disc->name );
nkeynes@1023
   100
    	disc->display_name = NULL;
nkeynes@468
   101
    }
nkeynes@468
   102
    free( disc );
nkeynes@468
   103
}
nkeynes@468
   104
nkeynes@1023
   105
/**
nkeynes@1023
   106
 * Construct a new gdrom_disc_t and initalize the vtable to the gdrom image
nkeynes@1023
   107
 * default functions.
nkeynes@1023
   108
 */
nkeynes@1023
   109
gdrom_disc_t gdrom_image_new( const gchar *filename, FILE *f )
nkeynes@342
   110
{
nkeynes@1023
   111
	gdrom_disc_t disc = gdrom_disc_new( filename, f );
nkeynes@1023
   112
	if( disc != NULL ) {
nkeynes@1023
   113
	    disc->read_sector = gdrom_image_read_sector;
nkeynes@1023
   114
	    disc->play_audio = NULL; /* not supported yet */
nkeynes@1023
   115
	    disc->run_time_slice = NULL; /* not needed */
nkeynes@1023
   116
	}
nkeynes@1023
   117
}
nkeynes@1023
   118
nkeynes@1023
   119
nkeynes@1023
   120
gdrom_disc_t gdrom_image_open( const gchar *inFilename )
nkeynes@1023
   121
{
nkeynes@1023
   122
    const gchar *filename = inFilename;
nkeynes@1023
   123
    const gchar *ext = strrchr(filename, '.');
nkeynes@1023
   124
    gdrom_disc_t disc = NULL;
nkeynes@1023
   125
    int fd;
nkeynes@1023
   126
    FILE *f;
nkeynes@342
   127
    int i;
nkeynes@1023
   128
    gdrom_image_class_t extclz = NULL;
nkeynes@1023
   129
nkeynes@1023
   130
    // Check for a url-style filename.
nkeynes@1023
   131
    char *lizard_lips = strstr( filename, "://" );
nkeynes@1023
   132
    if( lizard_lips != NULL ) {
nkeynes@1023
   133
        gchar *path = lizard_lips + 3;
nkeynes@1023
   134
        int method_len = (lizard_lips-filename);
nkeynes@1023
   135
        gchar method[method_len + 1];
nkeynes@1023
   136
        memcpy( method, filename, method_len );
nkeynes@1023
   137
        method[method_len] = '\0';
nkeynes@1023
   138
nkeynes@1023
   139
        if( strcasecmp( method, "file" ) == 0 ) {
nkeynes@1023
   140
            filename = path;
nkeynes@1023
   141
        } else if( strcasecmp( method, "dvd" ) == 0 ||
nkeynes@1023
   142
                strcasecmp( method, "cd" ) == 0 ||
nkeynes@1023
   143
                strcasecmp( method, "cdrom" ) ) {
nkeynes@1023
   144
            return cdrom_open_device( method, path );
nkeynes@1023
   145
        } else {
nkeynes@1023
   146
            ERROR( "Unrecognized URL method '%s' in filename '%s'", method, filename );
nkeynes@1023
   147
            return NULL;
nkeynes@736
   148
        }
nkeynes@342
   149
    }
nkeynes@1023
   150
nkeynes@1023
   151
    fd = open( filename, O_RDONLY | O_NONBLOCK );
nkeynes@1023
   152
    if( fd == -1 ) {
nkeynes@1023
   153
        return NULL;
nkeynes@1023
   154
    }
nkeynes@1023
   155
nkeynes@1023
   156
    f = fdopen(fd, "ro");
nkeynes@1023
   157
nkeynes@1023
   158
nkeynes@1023
   159
    /* try extensions */
nkeynes@1023
   160
    if( ext != NULL ) {
nkeynes@1023
   161
        ext++; /* Skip the '.' */
nkeynes@1023
   162
        for( i=0; gdrom_image_classes[i] != NULL; i++ ) {
nkeynes@1023
   163
            if( gdrom_image_classes[i]->extension != NULL &&
nkeynes@1023
   164
                    strcasecmp( gdrom_image_classes[i]->extension, ext ) == 0 ) {
nkeynes@1023
   165
                extclz = gdrom_image_classes[i];
nkeynes@1023
   166
                if( extclz->is_valid_file(f) ) {
nkeynes@1023
   167
                    disc = extclz->open_image_file(filename, f);
nkeynes@1023
   168
                    if( disc != NULL )
nkeynes@1023
   169
                        return disc;
nkeynes@1023
   170
                }
nkeynes@1023
   171
                break;
nkeynes@1023
   172
            }
nkeynes@1023
   173
        }
nkeynes@1023
   174
    }
nkeynes@1023
   175
nkeynes@1023
   176
    /* Okay, fall back to magic */
nkeynes@1023
   177
    gboolean recognized = FALSE;
nkeynes@1023
   178
    for( i=0; gdrom_image_classes[i] != NULL; i++ ) {
nkeynes@1023
   179
        if( gdrom_image_classes[i] != extclz &&
nkeynes@1023
   180
                gdrom_image_classes[i]->is_valid_file(f) ) {
nkeynes@1023
   181
            recognized = TRUE;
nkeynes@1023
   182
            disc = gdrom_image_classes[i]->open_image_file(filename, f);
nkeynes@1023
   183
            if( disc != NULL )
nkeynes@1023
   184
                return disc;
nkeynes@1023
   185
        }
nkeynes@1023
   186
    }
nkeynes@1023
   187
nkeynes@1023
   188
    fclose(f);
nkeynes@1023
   189
    return NULL;
nkeynes@342
   190
}
nkeynes@342
   191
nkeynes@492
   192
/**
nkeynes@492
   193
 * Read a block from an image file, handling negative file offsets
nkeynes@492
   194
 * with 0-fill.
nkeynes@492
   195
 */
nkeynes@644
   196
static gboolean gdrom_read_block( unsigned char *buf, int file_offset, int length, FILE *f )
nkeynes@492
   197
{
nkeynes@492
   198
    if( file_offset < 0 ) {
nkeynes@736
   199
        int size = -file_offset;
nkeynes@736
   200
        if( size >= length ) {
nkeynes@736
   201
            memset( buf, 0, length );
nkeynes@736
   202
            return TRUE;
nkeynes@736
   203
        } else {
nkeynes@736
   204
            memset( buf, 0, size );
nkeynes@736
   205
            file_offset = 0;
nkeynes@736
   206
            length -= size;
nkeynes@736
   207
        }
nkeynes@492
   208
    }
nkeynes@492
   209
    fseek( f, file_offset, SEEK_SET );
nkeynes@644
   210
    return fread( buf, length, 1, f ) == 1;
nkeynes@492
   211
}
nkeynes@492
   212
nkeynes@644
   213
static void gdrom_build_sector_header( unsigned char *buf, uint32_t lba, 
nkeynes@736
   214
                                       gdrom_track_mode_t sector_mode )
nkeynes@644
   215
{
nkeynes@644
   216
    memcpy( buf, gdrom_default_sync, 12 );
nkeynes@644
   217
    cd_build_address( buf, sector_mode, lba );
nkeynes@644
   218
}
nkeynes@644
   219
nkeynes@644
   220
/**
nkeynes@644
   221
 * Return TRUE if the given read mode + track modes are compatible,
nkeynes@644
   222
 * otherwise FALSE.
nkeynes@644
   223
 * @param track_mode one of the GDROM_MODE* constants
nkeynes@644
   224
 * @param read_mode the READ_CD_MODE from the read request
nkeynes@644
   225
 */
nkeynes@644
   226
static gboolean gdrom_is_compatible_read_mode( int track_mode, int read_mode )
nkeynes@644
   227
{
nkeynes@644
   228
    switch( read_mode ) {
nkeynes@644
   229
    case READ_CD_MODE_ANY:
nkeynes@736
   230
        return TRUE;
nkeynes@644
   231
    case READ_CD_MODE_CDDA:
nkeynes@736
   232
        return track_mode == GDROM_CDDA;
nkeynes@644
   233
    case READ_CD_MODE_1:
nkeynes@736
   234
        return track_mode == GDROM_MODE1 || track_mode == GDROM_MODE2_FORM1;
nkeynes@644
   235
    case READ_CD_MODE_2_FORM_1:
nkeynes@736
   236
        return track_mode == GDROM_MODE1 || track_mode == GDROM_MODE2_FORM1;
nkeynes@644
   237
    case READ_CD_MODE_2_FORM_2:
nkeynes@736
   238
        return track_mode == GDROM_MODE2_FORM2;
nkeynes@644
   239
    case READ_CD_MODE_2:
nkeynes@736
   240
        return track_mode == GDROM_MODE2_FORMLESS;
nkeynes@644
   241
    default:
nkeynes@736
   242
        return FALSE;
nkeynes@644
   243
    }
nkeynes@644
   244
}
nkeynes@644
   245
nkeynes@644
   246
/**
nkeynes@644
   247
 * Determine the start position in a raw sector, and the amount of data to read
nkeynes@644
   248
 * in bytes, for a given combination of sector mode and read mode.
nkeynes@644
   249
 */ 
nkeynes@644
   250
static void gdrom_get_read_bounds( int sector_mode, int read_mode, int *start, int *size )
nkeynes@644
   251
{
nkeynes@644
   252
    if( READ_CD_RAW(read_mode) ) {
nkeynes@736
   253
        // whole sector
nkeynes@736
   254
        *start = 0;
nkeynes@736
   255
        *size = 2352;
nkeynes@644
   256
    } else {
nkeynes@736
   257
        *size = 0;
nkeynes@736
   258
        if( READ_CD_DATA(read_mode) ) {
nkeynes@736
   259
            *start = gdrom_data_offset[sector_mode];
nkeynes@736
   260
            *size = gdrom_sector_size[sector_mode];
nkeynes@736
   261
        }
nkeynes@644
   262
nkeynes@736
   263
        if( READ_CD_SUBHEAD(read_mode) && 
nkeynes@736
   264
                (sector_mode == GDROM_MODE2_FORM1 || sector_mode == GDROM_MODE2_FORM2) ) {
nkeynes@736
   265
            *start = SECTOR_HEADER_SIZE;
nkeynes@736
   266
            *size += SECTOR_SUBHEADER_SIZE;
nkeynes@736
   267
        }
nkeynes@644
   268
nkeynes@736
   269
        if( READ_CD_HEADER(read_mode) ) {
nkeynes@736
   270
            *size += SECTOR_HEADER_SIZE;
nkeynes@736
   271
            *start = 0;
nkeynes@736
   272
        }
nkeynes@644
   273
nkeynes@644
   274
    }
nkeynes@644
   275
}
nkeynes@644
   276
nkeynes@782
   277
void gdrom_extract_raw_data_sector( char *sector_data, int channels, unsigned char *buf, uint32_t *length )
nkeynes@782
   278
{
nkeynes@782
   279
    int sector_mode;
nkeynes@782
   280
    int start, size;
nkeynes@782
   281
    struct cdrom_sector_header *secthead = (struct cdrom_sector_header *)sector_data;
nkeynes@782
   282
    if( secthead->mode == 1 ) {
nkeynes@782
   283
        sector_mode = GDROM_MODE1;
nkeynes@782
   284
    } else {
nkeynes@782
   285
        sector_mode = ((secthead->subhead[2] & 0x20) == 0 ) ? GDROM_MODE2_FORM1 : GDROM_MODE2_FORM2;
nkeynes@782
   286
    }
nkeynes@782
   287
    gdrom_get_read_bounds( sector_mode, channels, &start, &size );
nkeynes@782
   288
    
nkeynes@782
   289
    memcpy( buf, sector_data+start, size );
nkeynes@782
   290
    *length = size;
nkeynes@782
   291
}
nkeynes@782
   292
nkeynes@644
   293
/**
nkeynes@1023
   294
 * Default check media status that does nothing and always returns
nkeynes@1023
   295
 * false (unchanged).
nkeynes@1023
   296
 */
nkeynes@1023
   297
static gboolean gdrom_null_check_status( gdrom_disc_t disc )
nkeynes@1023
   298
{
nkeynes@1023
   299
	return FALSE;
nkeynes@1023
   300
}
nkeynes@1023
   301
nkeynes@1023
   302
/**
nkeynes@644
   303
 * Read a single sector from a disc image. If you thought this would be simple, 
nkeynes@644
   304
 * I have just one thing to say to you: Bwahahahahahahahah.
nkeynes@644
   305
 *
nkeynes@644
   306
 * Once we've decided that there's a real sector at the requested lba, there's 
nkeynes@644
   307
 * really two things we need to care about:
nkeynes@644
   308
 *   1. Is the sector mode compatible with the requested read mode
nkeynes@644
   309
 *   2. Which parts of the sector do we need to return? 
nkeynes@644
   310
 *      (header/subhead/data/raw sector)
nkeynes@644
   311
 *
nkeynes@644
   312
 * Also note that the disc image may supply us with just the data (most common 
nkeynes@644
   313
 * case), or may have the full raw sector. In the former case we may need to 
nkeynes@644
   314
 * generate the missing data on the fly, for which we use libedc to compute the
nkeynes@644
   315
 * data correction codes.
nkeynes@644
   316
 */
nkeynes@342
   317
static gdrom_error_t gdrom_image_read_sector( gdrom_disc_t disc, uint32_t lba,
nkeynes@736
   318
                                              int mode, unsigned char *buf, uint32_t *length )
nkeynes@342
   319
{
nkeynes@498
   320
    struct cdrom_sector_header secthead;
nkeynes@422
   321
    int file_offset, read_len, track_no;
nkeynes@498
   322
nkeynes@492
   323
    FILE *f;
nkeynes@342
   324
nkeynes@1023
   325
    track_no = gdrom_disc_get_track_by_lba( disc, lba );
nkeynes@342
   326
    if( track_no == -1 ) {
nkeynes@736
   327
        return PKT_ERR_BADREAD;
nkeynes@342
   328
    }
nkeynes@1023
   329
    struct gdrom_track *track = &disc->track[track_no-1];
nkeynes@342
   330
    file_offset = track->offset + track->sector_size * (lba - track->lba);
nkeynes@342
   331
    read_len = track->sector_size;
nkeynes@492
   332
    if( track->file != NULL ) {
nkeynes@736
   333
        f = track->file;
nkeynes@492
   334
    } else {
nkeynes@1023
   335
        f = disc->file;
nkeynes@492
   336
    }
nkeynes@492
   337
nkeynes@644
   338
    /* First figure out what the real sector mode is for raw/semiraw sectors */
nkeynes@644
   339
    int sector_mode;
nkeynes@644
   340
    switch( track->mode ) {
nkeynes@644
   341
    case GDROM_RAW_NONXA:
nkeynes@736
   342
        gdrom_read_block( (unsigned char *)(&secthead), file_offset, sizeof(secthead), f );
nkeynes@736
   343
        sector_mode = (secthead.mode == 1) ? GDROM_MODE1 : GDROM_MODE2_FORMLESS;
nkeynes@736
   344
        break;
nkeynes@644
   345
    case GDROM_RAW_XA:
nkeynes@736
   346
        gdrom_read_block( (unsigned char *)(&secthead), file_offset, sizeof(secthead), f );
nkeynes@736
   347
        if( secthead.mode == 1 ) {
nkeynes@736
   348
            sector_mode = GDROM_MODE1;
nkeynes@736
   349
        } else {
nkeynes@736
   350
            sector_mode = ((secthead.subhead[2] & 0x20) == 0 ) ? GDROM_MODE2_FORM1 : GDROM_MODE2_FORM2;
nkeynes@736
   351
        }
nkeynes@736
   352
        break;
nkeynes@644
   353
    case GDROM_SEMIRAW_MODE2:
nkeynes@736
   354
        gdrom_read_block( secthead.subhead, file_offset, 8, f );
nkeynes@736
   355
        sector_mode = ((secthead.subhead[2] & 0x20) == 0 ) ? GDROM_MODE2_FORM1 : GDROM_MODE2_FORM2;
nkeynes@736
   356
        break;
nkeynes@342
   357
    default:
nkeynes@736
   358
        /* In the other cases, the track mode completely defines the sector mode */
nkeynes@736
   359
        sector_mode = track->mode;
nkeynes@736
   360
        break;
nkeynes@644
   361
    }
nkeynes@644
   362
nkeynes@644
   363
    if( !gdrom_is_compatible_read_mode(sector_mode, READ_CD_MODE(mode)) ) {
nkeynes@736
   364
        return PKT_ERR_BADREADMODE;
nkeynes@342
   365
    }
nkeynes@644
   366
nkeynes@644
   367
    /* Ok, we've got a valid sector, check what parts of the sector we need to
nkeynes@644
   368
     * return - header | subhead | data | everything
nkeynes@644
   369
     */
nkeynes@644
   370
    int channels = READ_CD_CHANNELS(mode);
nkeynes@644
   371
nkeynes@644
   372
    if( channels == 0 ) {
nkeynes@736
   373
        // legal, if weird
nkeynes@736
   374
        *length = 0;
nkeynes@736
   375
        return PKT_ERR_OK;
nkeynes@644
   376
    } else if( channels == 0xA0 && 
nkeynes@736
   377
            (sector_mode == GDROM_MODE2_FORM1 || sector_mode == GDROM_MODE2_FORM2 )) {
nkeynes@736
   378
        // caller requested a non-contiguous region
nkeynes@736
   379
        return PKT_ERR_BADFIELD;
nkeynes@644
   380
    } else if( READ_CD_RAW(channels) ) {
nkeynes@736
   381
        channels = 0xF0; // implies everything
nkeynes@644
   382
    }
nkeynes@644
   383
nkeynes@644
   384
    read_len = 0;
nkeynes@644
   385
    int start, size;
nkeynes@644
   386
    switch( track->mode ) {
nkeynes@644
   387
    case GDROM_CDDA:
nkeynes@736
   388
        // audio is nice and simple (assume perfect reads for now)
nkeynes@736
   389
        *length = 2352;
nkeynes@736
   390
        gdrom_read_block( buf, file_offset, track->sector_size, f );
nkeynes@736
   391
        return PKT_ERR_OK;
nkeynes@644
   392
    case GDROM_RAW_XA:
nkeynes@644
   393
    case GDROM_RAW_NONXA:
nkeynes@736
   394
        gdrom_get_read_bounds( sector_mode, channels, &start, &size );
nkeynes@736
   395
        gdrom_read_block( buf, file_offset+start, size, f );
nkeynes@736
   396
        read_len = size;
nkeynes@736
   397
        break;
nkeynes@644
   398
    case GDROM_SEMIRAW_MODE2:
nkeynes@736
   399
        gdrom_get_read_bounds( sector_mode, channels, &start, &size );
nkeynes@736
   400
        if( READ_CD_HEADER(channels) ) {
nkeynes@736
   401
            gdrom_build_sector_header( buf, lba, sector_mode );
nkeynes@736
   402
            read_len += SECTOR_HEADER_SIZE;
nkeynes@736
   403
            size -= SECTOR_HEADER_SIZE;
nkeynes@736
   404
        } else {
nkeynes@736
   405
            start -= SECTOR_HEADER_SIZE;
nkeynes@736
   406
        }
nkeynes@736
   407
        gdrom_read_block( buf + read_len, file_offset+start, size, f );
nkeynes@736
   408
        read_len += size;
nkeynes@736
   409
        break;
nkeynes@644
   410
    default: // Data track w/ data only in file
nkeynes@736
   411
        if( READ_CD_RAW(channels) ) {
nkeynes@736
   412
            gdrom_read_block( buf + gdrom_data_offset[track->mode], file_offset, 
nkeynes@736
   413
                    track->sector_size, f );
nkeynes@736
   414
            do_encode_L2( buf, sector_mode, lba );
nkeynes@736
   415
            read_len = 2352;
nkeynes@736
   416
        } else {
nkeynes@736
   417
            if( READ_CD_HEADER(channels) ) {
nkeynes@736
   418
                gdrom_build_sector_header( buf, lba, sector_mode );
nkeynes@736
   419
                read_len += SECTOR_HEADER_SIZE;
nkeynes@736
   420
            }
nkeynes@736
   421
            if( READ_CD_SUBHEAD(channels) && 
nkeynes@736
   422
                    (sector_mode == GDROM_MODE2_FORM1 || sector_mode == GDROM_MODE2_FORM2) ) {
nkeynes@736
   423
                if( sector_mode == GDROM_MODE2_FORM1 ) {
nkeynes@736
   424
                    *((uint32_t *)(buf+read_len)) = 0;
nkeynes@736
   425
                    *((uint32_t *)(buf+read_len+4)) = 0;
nkeynes@736
   426
                } else {
nkeynes@736
   427
                    *((uint32_t *)(buf+read_len)) = 0x00200000;
nkeynes@736
   428
                    *((uint32_t *)(buf+read_len+4)) = 0x00200000;
nkeynes@736
   429
                }
nkeynes@736
   430
                read_len += 8;
nkeynes@736
   431
            }
nkeynes@736
   432
            if( READ_CD_DATA(channels) ) {
nkeynes@736
   433
                gdrom_read_block( buf+read_len, file_offset, track->sector_size, f );
nkeynes@736
   434
                read_len += track->sector_size;
nkeynes@736
   435
            }
nkeynes@736
   436
        }
nkeynes@644
   437
    }
nkeynes@342
   438
    *length = read_len;
nkeynes@342
   439
    return PKT_ERR_OK;
nkeynes@342
   440
}
nkeynes@342
   441
.