Search
lxdream.org :: lxdream/src/drivers/cdrom/sector.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/cdrom/sector.c
changeset 1097:d4807997e450
next1099:566cdeb157ec
author nkeynes
date Sun Jan 31 18:35:06 2010 +1000 (12 years ago)
permissions -rw-r--r--
last change Refactor CDROM host support
- Completely separate GDROM hardware (in gdrom/gdrom.c) from generic CDROM
support (now in drivers/cdrom)
- Add concept of 'sector sources' that can be mixed and matched to create
cdrom discs (makes support of arbitrary disc types much simpler)
file annotate diff log raw
nkeynes@1097
     1
/**
nkeynes@1097
     2
 * $Id$
nkeynes@1097
     3
 *
nkeynes@1097
     4
 * low-level 'block device' for input to gdrom discs.
nkeynes@1097
     5
 *
nkeynes@1097
     6
 * Copyright (c) 2009 Nathan Keynes.
nkeynes@1097
     7
 *
nkeynes@1097
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@1097
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@1097
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@1097
    11
 * (at your option) any later version.
nkeynes@1097
    12
 *
nkeynes@1097
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@1097
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@1097
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@1097
    16
 * GNU General Public License for more details.
nkeynes@1097
    17
 */
nkeynes@1097
    18
nkeynes@1097
    19
#include <sys/stat.h>
nkeynes@1097
    20
#include <glib/gmem.h>
nkeynes@1097
    21
#include <assert.h>
nkeynes@1097
    22
#include <stdlib.h>
nkeynes@1097
    23
#include <stdio.h>
nkeynes@1097
    24
#include <string.h>
nkeynes@1097
    25
#include <unistd.h>
nkeynes@1097
    26
#include <fcntl.h>
nkeynes@1097
    27
nkeynes@1097
    28
#include "drivers/cdrom/sector.h"
nkeynes@1097
    29
#include "drivers/cdrom/cdrom.h"
nkeynes@1097
    30
#include "drivers/cdrom/ecc.h"
nkeynes@1097
    31
nkeynes@1097
    32
#define CHECK_READ(dev,lba,count) \
nkeynes@1097
    33
    if( !IS_SECTOR_SOURCE(dev) ) { \
nkeynes@1097
    34
        return CDROM_ERROR_NODISC; \
nkeynes@1097
    35
    } else if( (lba) >= (dev)->size || (lba+block_count) > (dev)->size ) { \
nkeynes@1097
    36
        return CDROM_ERROR_BADREAD; \
nkeynes@1097
    37
    }
nkeynes@1097
    38
nkeynes@1097
    39
/* Default read mode for each sector mode */
nkeynes@1097
    40
const uint32_t cdrom_sector_read_mode[] = { 0,
nkeynes@1097
    41
        CDROM_READ_CDDA|CDROM_READ_DATA, CDROM_READ_MODE1|CDROM_READ_DATA,
nkeynes@1097
    42
        CDROM_READ_MODE2|CDROM_READ_DATA, CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
nkeynes@1097
    43
        CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,
nkeynes@1097
    44
        CDROM_READ_MODE2|CDROM_READ_DATA|CDROM_READ_SUBHEADER|CDROM_READ_ECC,
nkeynes@1097
    45
        CDROM_READ_RAW, CDROM_READ_RAW };
nkeynes@1097
    46
nkeynes@1097
    47
/* Block size for each sector mode */
nkeynes@1097
    48
const uint32_t cdrom_sector_size[] = { 0, 2352, 2048, 2336, 2048, 2324, 2336, 2352, 2352 };
nkeynes@1097
    49
nkeynes@1097
    50
const char *cdrom_sector_mode_names[] = { "Unknown", "Audio", "Mode 1", "Mode 2", "Mode 2 Form 1", "Mode 2 Form 2",
nkeynes@1097
    51
        "Mode 2 semiraw", "XA Raw", "Non-XA Raw" };
nkeynes@1097
    52
nkeynes@1097
    53
nkeynes@1097
    54
/********************* Public functions *************************/
nkeynes@1097
    55
cdrom_error_t sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
nkeynes@1097
    56
{
nkeynes@1097
    57
    CHECK_READ(device,lba,block_count);
nkeynes@1097
    58
    return device->read_blocks(device, lba, block_count, buf);
nkeynes@1097
    59
}
nkeynes@1097
    60
nkeynes@1097
    61
cdrom_error_t sector_source_read_sectors( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,
nkeynes@1097
    62
                                          unsigned char *buf, size_t *length )
nkeynes@1097
    63
{
nkeynes@1097
    64
    CHECK_READ(device,lba,block_count);
nkeynes@1097
    65
    return device->read_sectors(device, lba, block_count, mode, buf, length);
nkeynes@1097
    66
}
nkeynes@1097
    67
nkeynes@1097
    68
void sector_source_ref( sector_source_t device )
nkeynes@1097
    69
{
nkeynes@1097
    70
    assert( IS_SECTOR_SOURCE(device) );
nkeynes@1097
    71
    device->ref_count++;
nkeynes@1097
    72
}
nkeynes@1097
    73
nkeynes@1097
    74
void sector_source_unref( sector_source_t device )
nkeynes@1097
    75
{
nkeynes@1097
    76
    if( device == NULL )
nkeynes@1097
    77
        return;
nkeynes@1097
    78
    assert( IS_SECTOR_SOURCE(device) );
nkeynes@1097
    79
    if( device->ref_count > 0 )
nkeynes@1097
    80
        device->ref_count--;
nkeynes@1097
    81
    if( device->ref_count == 0 )
nkeynes@1097
    82
        device->destroy(device);
nkeynes@1097
    83
}
nkeynes@1097
    84
nkeynes@1097
    85
void sector_source_release( sector_source_t device )
nkeynes@1097
    86
{
nkeynes@1097
    87
    assert( IS_SECTOR_SOURCE(device) );
nkeynes@1097
    88
    if( device->ref_count == 0 )
nkeynes@1097
    89
        device->destroy(device);
nkeynes@1097
    90
}
nkeynes@1097
    91
nkeynes@1097
    92
/************************** Sector mangling ***************************/
nkeynes@1097
    93
/*
nkeynes@1097
    94
 * Private functions used to pack/unpack sectors, determine mode, and
nkeynes@1097
    95
 * evaluate sector reads.
nkeynes@1097
    96
 */
nkeynes@1097
    97
nkeynes@1097
    98
/** Basic data sector header structure */
nkeynes@1097
    99
struct cdrom_sector_header {
nkeynes@1097
   100
    uint8_t sync[12];
nkeynes@1097
   101
    uint8_t msf[3];
nkeynes@1097
   102
    uint8_t mode;
nkeynes@1097
   103
    uint8_t subhead[8]; // Mode-2 XA sectors only
nkeynes@1097
   104
};
nkeynes@1097
   105
nkeynes@1097
   106
static const uint8_t cdrom_sync_data[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };
nkeynes@1097
   107
nkeynes@1097
   108
/* Field combinations that are legal for mode 1 or mode 2 (formless) reads */
nkeynes@1097
   109
static const uint8_t legal_nonxa_fields[] =
nkeynes@1097
   110
{ TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
nkeynes@1097
   111
  TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
nkeynes@1097
   112
  TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE,
nkeynes@1097
   113
  FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
nkeynes@1097
   114
nkeynes@1097
   115
/* Field combinations that are legal for mode 2 form 1 or form 2 reads */
nkeynes@1097
   116
static const uint8_t legal_xa_fields[] =
nkeynes@1097
   117
{ TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,
nkeynes@1097
   118
  TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,
nkeynes@1097
   119
  TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,
nkeynes@1097
   120
  FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };
nkeynes@1097
   121
nkeynes@1097
   122
/**
nkeynes@1097
   123
 * Position per sector mode of each of the fields
nkeynes@1097
   124
 *   sync, header, subheader, data, ecc.
nkeynes@1097
   125
 *
nkeynes@1097
   126
 */
nkeynes@1097
   127
static const uint32_t sector_field_positions[][6] = {
nkeynes@1097
   128
        { 0, 0, 0, 0, 0, 0 },    /* Unknown */
nkeynes@1097
   129
        { 0, 0, 0, 0, 2352, 2352 }, /* CDDA */
nkeynes@1097
   130
        { 0, 12, 16, 16, 2064, 2352 }, /* Mode 1 */
nkeynes@1097
   131
        { 0, 12, 16, 16, 2352, 2352 }, /* Mode 2 formless */
nkeynes@1097
   132
        { 0, 12, 16, 24, 2072, 2352 }, /* Mode 2 form 1 */
nkeynes@1097
   133
        { 0, 12, 16, 24, 2352, 2352 }}; /* Mode 2 form 2 */
nkeynes@1097
   134
nkeynes@1097
   135
nkeynes@1097
   136
nkeynes@1097
   137
/**
nkeynes@1097
   138
 * Return CDROM_ERROR_OK if the given read mode + sector modes are compatible,
nkeynes@1097
   139
 * otherwise either CDROM_ERROR_BADREADMODE or CDROM_ERROR_BADFIELD. Raw sector modes
nkeynes@1097
   140
 * will return BADREADMODE, as it's impossible to tell.
nkeynes@1097
   141
 *
nkeynes@1097
   142
 * @param track_mode one of the CDROM_MODE* constants
nkeynes@1097
   143
 * @param read_mode the full read mode
nkeynes@1097
   144
 */
nkeynes@1097
   145
static cdrom_error_t is_legal_read( sector_mode_t sector_mode, cdrom_read_mode_t read_mode )
nkeynes@1097
   146
{
nkeynes@1097
   147
    int read_sector_type = CDROM_READ_TYPE(read_mode);
nkeynes@1097
   148
    int read_sector_fields = CDROM_READ_FIELDS(read_mode);
nkeynes@1097
   149
nkeynes@1097
   150
    /* Check the sector type is consistent */
nkeynes@1097
   151
    switch( read_sector_type ) {
nkeynes@1097
   152
    case CDROM_READ_ANY: break;
nkeynes@1097
   153
    case CDROM_READ_CDDA:
nkeynes@1097
   154
        if( sector_mode != SECTOR_CDDA )
nkeynes@1097
   155
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   156
        break;
nkeynes@1097
   157
    case CDROM_READ_MODE1:
nkeynes@1097
   158
    case CDROM_READ_MODE2_FORM1:
nkeynes@1097
   159
        if( sector_mode != SECTOR_MODE1 && sector_mode != SECTOR_MODE2_FORM1 )
nkeynes@1097
   160
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   161
        break;
nkeynes@1097
   162
    case CDROM_READ_MODE2_FORM2:
nkeynes@1097
   163
        if( sector_mode != SECTOR_MODE2_FORM2 )
nkeynes@1097
   164
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   165
        break;
nkeynes@1097
   166
    case CDROM_READ_MODE2:
nkeynes@1097
   167
        if( sector_mode != SECTOR_MODE2_FORMLESS )
nkeynes@1097
   168
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   169
        break;
nkeynes@1097
   170
    default: /* Illegal read mode */
nkeynes@1097
   171
        return CDROM_ERROR_BADFIELD;
nkeynes@1097
   172
    }
nkeynes@1097
   173
nkeynes@1097
   174
    /* Check the fields requested are sane per MMC (non-contiguous regions prohibited) */
nkeynes@1097
   175
    switch( sector_mode ) {
nkeynes@1097
   176
    case SECTOR_CDDA:
nkeynes@1097
   177
        return CDROM_ERROR_OK; /* Everything is OK */
nkeynes@1097
   178
    case SECTOR_MODE2_FORM1:
nkeynes@1097
   179
    case SECTOR_MODE2_FORM2:
nkeynes@1097
   180
        if( !legal_xa_fields[read_sector_fields>>11] )
nkeynes@1097
   181
            return CDROM_ERROR_BADFIELD;
nkeynes@1097
   182
        else
nkeynes@1097
   183
            return CDROM_ERROR_OK;
nkeynes@1097
   184
    case SECTOR_MODE1:
nkeynes@1097
   185
    case SECTOR_MODE2_FORMLESS:
nkeynes@1097
   186
        if( !legal_nonxa_fields[read_sector_fields>>11] )
nkeynes@1097
   187
            return CDROM_ERROR_BADFIELD;
nkeynes@1097
   188
        else
nkeynes@1097
   189
            return CDROM_ERROR_OK;
nkeynes@1097
   190
    default:
nkeynes@1097
   191
        return CDROM_ERROR_BADFIELD;
nkeynes@1097
   192
    }
nkeynes@1097
   193
}
nkeynes@1097
   194
nkeynes@1097
   195
static sector_mode_t identify_sector( sector_mode_t raw_mode, unsigned char *buf )
nkeynes@1097
   196
{
nkeynes@1097
   197
    struct cdrom_sector_header *header = (struct cdrom_sector_header *)buf;
nkeynes@1097
   198
nkeynes@1097
   199
    switch( raw_mode ) {
nkeynes@1097
   200
    case SECTOR_SEMIRAW_MODE2: /* XA sectors */
nkeynes@1097
   201
    case SECTOR_RAW_XA:
nkeynes@1097
   202
        switch( header->mode ) {
nkeynes@1097
   203
        case 1: return SECTOR_MODE1;
nkeynes@1097
   204
        case 2: return ((header->subhead[2] & 0x20) == 0 ) ? SECTOR_MODE2_FORM1 : SECTOR_MODE2_FORM2;
nkeynes@1097
   205
        default: return SECTOR_UNKNOWN;
nkeynes@1097
   206
        }
nkeynes@1097
   207
    case SECTOR_RAW_NONXA:
nkeynes@1097
   208
        switch( header->mode ) {
nkeynes@1097
   209
        case 1: return SECTOR_MODE1;
nkeynes@1097
   210
        case 2: return SECTOR_MODE2_FORMLESS;
nkeynes@1097
   211
        default: return SECTOR_UNKNOWN;
nkeynes@1097
   212
        }
nkeynes@1097
   213
    default:
nkeynes@1097
   214
        return raw_mode;
nkeynes@1097
   215
    }
nkeynes@1097
   216
}
nkeynes@1097
   217
nkeynes@1097
   218
/**
nkeynes@1097
   219
 * Read a single raw sector from the device. Generate sync, ECC/EDC data etc where
nkeynes@1097
   220
 * necessary.
nkeynes@1097
   221
 */
nkeynes@1097
   222
static cdrom_error_t read_raw_sector( sector_source_t device, cdrom_lba_t lba, unsigned char *buf )
nkeynes@1097
   223
{
nkeynes@1097
   224
    cdrom_error_t err;
nkeynes@1097
   225
nkeynes@1097
   226
    switch( device->mode ) {
nkeynes@1097
   227
    case SECTOR_RAW_XA:
nkeynes@1097
   228
    case SECTOR_RAW_NONXA:
nkeynes@1097
   229
        return device->read_blocks(device, lba, 1, buf);
nkeynes@1097
   230
    case SECTOR_SEMIRAW_MODE2:
nkeynes@1097
   231
        memcpy( buf, cdrom_sync_data, 12 );
nkeynes@1097
   232
        cd_build_address(buf, SECTOR_MODE2_FORMLESS, lba);
nkeynes@1097
   233
        return device->read_blocks(device, lba, 1, &buf[16]);
nkeynes@1097
   234
    case SECTOR_MODE1:
nkeynes@1097
   235
    case SECTOR_MODE2_FORMLESS:
nkeynes@1097
   236
        err = device->read_blocks(device, lba, 1, &buf[16]);
nkeynes@1097
   237
        if( err == CDROM_ERROR_OK ) {
nkeynes@1097
   238
            do_encode_L2( buf, device->mode, lba );
nkeynes@1097
   239
        }
nkeynes@1097
   240
        return err;
nkeynes@1097
   241
    case SECTOR_MODE2_FORM1:
nkeynes@1097
   242
        *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0;
nkeynes@1097
   243
        err = device->read_blocks(device, lba, 1, &buf[24]);
nkeynes@1097
   244
        if( err == CDROM_ERROR_OK ) {
nkeynes@1097
   245
            do_encode_L2( buf, device->mode, lba );
nkeynes@1097
   246
        }
nkeynes@1097
   247
        return err;
nkeynes@1097
   248
    case SECTOR_MODE2_FORM2:
nkeynes@1097
   249
        *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0x00200000;
nkeynes@1097
   250
        err = device->read_blocks(device, lba, 1, &buf[24]);
nkeynes@1097
   251
        if( err == CDROM_ERROR_OK ) {
nkeynes@1097
   252
            do_encode_L2( buf, device->mode, lba );
nkeynes@1097
   253
        }
nkeynes@1097
   254
        return err;
nkeynes@1097
   255
    default:
nkeynes@1097
   256
        abort();
nkeynes@1097
   257
    }
nkeynes@1097
   258
}
nkeynes@1097
   259
nkeynes@1097
   260
static cdrom_error_t extract_sector_fields( unsigned char *raw_sector, sector_mode_t mode, int fields, unsigned char *buf, size_t *length )
nkeynes@1097
   261
{
nkeynes@1097
   262
    int start=-1,end=0;
nkeynes@1097
   263
    int i;
nkeynes@1097
   264
nkeynes@1097
   265
    for( i=0; i<5; i++ ) {
nkeynes@1097
   266
        if( fields & (0x8000>>i) ) {
nkeynes@1097
   267
            if( start == -1 )
nkeynes@1097
   268
                start = sector_field_positions[mode][i];
nkeynes@1097
   269
            else if( end != sector_field_positions[mode][i] )
nkeynes@1097
   270
                return CDROM_ERROR_BADFIELD;
nkeynes@1097
   271
            end = sector_field_positions[mode][i+1];
nkeynes@1097
   272
        }
nkeynes@1097
   273
    }
nkeynes@1097
   274
    if( start == -1 ) {
nkeynes@1097
   275
        *length = 0;
nkeynes@1097
   276
    } else {
nkeynes@1097
   277
        memcpy( buf, &raw_sector[start], end-start );
nkeynes@1097
   278
        *length = end-start;
nkeynes@1097
   279
    }
nkeynes@1097
   280
    return CDROM_ERROR_OK;
nkeynes@1097
   281
}
nkeynes@1097
   282
nkeynes@1097
   283
cdrom_error_t sector_extract_from_raw( unsigned char *raw_sector, cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
nkeynes@1097
   284
{
nkeynes@1097
   285
    sector_mode_t sector_mode = identify_sector( SECTOR_RAW_XA, raw_sector );
nkeynes@1097
   286
    if( sector_mode == SECTOR_UNKNOWN )
nkeynes@1097
   287
        return CDROM_ERROR_BADREAD;
nkeynes@1097
   288
    cdrom_error_t status = is_legal_read( sector_mode, mode );
nkeynes@1097
   289
    if( status != CDROM_ERROR_OK )
nkeynes@1097
   290
        return status;
nkeynes@1097
   291
    return extract_sector_fields( raw_sector, sector_mode, CDROM_READ_FIELDS(mode), buf, length );
nkeynes@1097
   292
}
nkeynes@1097
   293
nkeynes@1097
   294
/**
nkeynes@1097
   295
 * This is horribly complicated by the need to handle mapping between all possible
nkeynes@1097
   296
 * sector modes + read modes, but fortunately most sources can just supply
nkeynes@1097
   297
 * a single block type and not care about the details here.
nkeynes@1097
   298
 */
nkeynes@1097
   299
cdrom_error_t default_sector_source_read_sectors( sector_source_t device,
nkeynes@1097
   300
        cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,
nkeynes@1097
   301
        unsigned char *buf, size_t *length )
nkeynes@1097
   302
{
nkeynes@1097
   303
    unsigned char tmp[CDROM_MAX_SECTOR_SIZE];
nkeynes@1097
   304
    int read_sector_type = CDROM_READ_TYPE(mode);
nkeynes@1097
   305
    int read_sector_fields = CDROM_READ_FIELDS(mode);
nkeynes@1097
   306
    int i;
nkeynes@1097
   307
    size_t len = 0;
nkeynes@1097
   308
    cdrom_error_t err;
nkeynes@1097
   309
nkeynes@1097
   310
    CHECK_READ(device, lba, count);
nkeynes@1097
   311
nkeynes@1097
   312
    switch(device->mode) {
nkeynes@1097
   313
    case SECTOR_CDDA:
nkeynes@1097
   314
        if( read_sector_type != CDROM_READ_ANY && read_sector_type != CDROM_READ_CDDA )
nkeynes@1097
   315
            return CDROM_ERROR_BADREADMODE;
nkeynes@1097
   316
        if( read_sector_fields != 0 ) {
nkeynes@1097
   317
            len = block_count * CDROM_MAX_SECTOR_SIZE;
nkeynes@1097
   318
            device->read_blocks( device, lba, block_count, buf );
nkeynes@1097
   319
        }
nkeynes@1097
   320
        break;
nkeynes@1097
   321
    case SECTOR_RAW_XA:
nkeynes@1097
   322
    case SECTOR_RAW_NONXA:
nkeynes@1097
   323
    case SECTOR_SEMIRAW_MODE2:
nkeynes@1097
   324
        /* We (may) have to break the raw sector up into requested fields.
nkeynes@1097
   325
         * Process sectors one at a time
nkeynes@1097
   326
         */
nkeynes@1097
   327
        for( i=0; i<block_count; i++ ) {
nkeynes@1097
   328
            size_t tmplen;
nkeynes@1097
   329
            err = read_raw_sector( device, lba+i, tmp );
nkeynes@1097
   330
            if( err != CDROM_ERROR_OK )
nkeynes@1097
   331
                return err;
nkeynes@1097
   332
            err = sector_extract_from_raw( tmp, mode, &buf[len], &tmplen );
nkeynes@1097
   333
            if( err != CDROM_ERROR_OK )
nkeynes@1097
   334
                return err;
nkeynes@1097
   335
            len += tmplen;
nkeynes@1097
   336
        }
nkeynes@1097
   337
        break;
nkeynes@1097
   338
    default: /* Data-only blocks */
nkeynes@1097
   339
        err = is_legal_read( device->mode, mode );
nkeynes@1097
   340
        if( err != CDROM_ERROR_OK )
nkeynes@1097
   341
            return err;
nkeynes@1097
   342
        if( read_sector_fields == 0 ) { /* Read nothing */
nkeynes@1097
   343
            *length = 0;
nkeynes@1097
   344
            return CDROM_ERROR_OK;
nkeynes@1097
   345
        } else if( read_sector_fields == CDROM_READ_DATA ) {
nkeynes@1097
   346
            /* Data-only */
nkeynes@1097
   347
            *length = block_count * CDROM_SECTOR_SIZE(device->mode);
nkeynes@1097
   348
            return device->read_blocks( device, lba, block_count, buf );
nkeynes@1097
   349
        } else if( read_sector_fields == CDROM_READ_RAW ) {
nkeynes@1097
   350
            for( i=0; i<block_count; i++ ) {
nkeynes@1097
   351
                err = read_raw_sector( device, lba+i, &buf[2352*i] );
nkeynes@1097
   352
                if( err != CDROM_ERROR_OK )
nkeynes@1097
   353
                    return err;
nkeynes@1097
   354
            }
nkeynes@1097
   355
            len = block_count * CDROM_MAX_SECTOR_SIZE;
nkeynes@1097
   356
        } else {
nkeynes@1097
   357
            for( i=0; i<block_count; i++ ) {
nkeynes@1097
   358
                size_t tmplen;
nkeynes@1097
   359
                err = read_raw_sector( device, lba+i, tmp );
nkeynes@1097
   360
                if( err != CDROM_ERROR_OK )
nkeynes@1097
   361
                    return err;
nkeynes@1097
   362
                err = extract_sector_fields( tmp, device->mode, read_sector_fields, &buf[len], &tmplen );
nkeynes@1097
   363
                if( err != CDROM_ERROR_OK )
nkeynes@1097
   364
                    return err;
nkeynes@1097
   365
                len += tmplen;
nkeynes@1097
   366
            }
nkeynes@1097
   367
        }
nkeynes@1097
   368
    }
nkeynes@1097
   369
    *length = len;
nkeynes@1097
   370
    return CDROM_ERROR_OK;
nkeynes@1097
   371
nkeynes@1097
   372
}
nkeynes@1097
   373
nkeynes@1097
   374
/************************ Base implementation *************************/
nkeynes@1097
   375
nkeynes@1097
   376
/**
nkeynes@1097
   377
 * Default destroy implementation - clears the tag and frees memory.
nkeynes@1097
   378
 */
nkeynes@1097
   379
void default_sector_source_destroy( sector_source_t device )
nkeynes@1097
   380
{
nkeynes@1097
   381
    assert( device != NULL && device->ref_count == 0 );
nkeynes@1097
   382
    device->tag = 0;
nkeynes@1097
   383
    g_free( device );
nkeynes@1097
   384
}
nkeynes@1097
   385
nkeynes@1097
   386
sector_source_t sector_source_init( sector_source_t device, sector_source_type_t type, sector_mode_t mode, cdrom_count_t size,
nkeynes@1097
   387
                        sector_source_read_fn_t readfn, sector_source_destroy_fn_t destroyfn )
nkeynes@1097
   388
{
nkeynes@1097
   389
    device->tag = SECTOR_SOURCE_TAG;
nkeynes@1097
   390
    device->ref_count = 0;
nkeynes@1097
   391
    device->type = type;
nkeynes@1097
   392
    device->mode = mode;
nkeynes@1097
   393
    device->size = size;
nkeynes@1097
   394
    device->read_blocks = readfn;
nkeynes@1097
   395
    device->read_sectors = default_sector_source_read_sectors;
nkeynes@1097
   396
    if( destroyfn == NULL )
nkeynes@1097
   397
        device->destroy = default_sector_source_destroy;
nkeynes@1097
   398
    else
nkeynes@1097
   399
        device->destroy = destroyfn;
nkeynes@1097
   400
    return device;
nkeynes@1097
   401
}
nkeynes@1097
   402
nkeynes@1097
   403
/************************ Null device implementation *************************/
nkeynes@1097
   404
cdrom_error_t null_sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
nkeynes@1097
   405
{
nkeynes@1097
   406
    memset( buf, 0,  block_count*CDROM_SECTOR_SIZE(device->mode) );
nkeynes@1097
   407
    return CDROM_ERROR_OK;
nkeynes@1097
   408
}
nkeynes@1097
   409
nkeynes@1097
   410
sector_source_t null_sector_source_new( sector_mode_t mode, cdrom_count_t size )
nkeynes@1097
   411
{
nkeynes@1097
   412
    return sector_source_init( g_malloc(sizeof(struct sector_source)), NULL_SECTOR_SOURCE, mode, size,
nkeynes@1097
   413
            null_sector_source_read, default_sector_source_destroy );
nkeynes@1097
   414
}
nkeynes@1097
   415
nkeynes@1097
   416
/************************ File device implementation *************************/
nkeynes@1097
   417
typedef struct file_sector_source {
nkeynes@1097
   418
    struct sector_source dev;
nkeynes@1097
   419
    FILE *file;
nkeynes@1097
   420
    uint32_t offset; /* offset in file where source begins */
nkeynes@1097
   421
    sector_source_t ref; /* Parent source reference */
nkeynes@1097
   422
    gboolean closeOnDestroy;
nkeynes@1097
   423
} *file_sector_source_t;
nkeynes@1097
   424
nkeynes@1097
   425
void file_sector_source_destroy( sector_source_t dev )
nkeynes@1097
   426
{
nkeynes@1097
   427
    assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
nkeynes@1097
   428
    file_sector_source_t fdev = (file_sector_source_t)dev;
nkeynes@1097
   429
nkeynes@1097
   430
    if( fdev->closeOnDestroy && fdev->file != NULL ) {
nkeynes@1097
   431
        fclose( fdev->file );
nkeynes@1097
   432
    }
nkeynes@1097
   433
    sector_source_unref( fdev->ref );
nkeynes@1097
   434
    fdev->file = NULL;
nkeynes@1097
   435
    default_sector_source_destroy(dev);
nkeynes@1097
   436
}
nkeynes@1097
   437
nkeynes@1097
   438
cdrom_error_t file_sector_source_read( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )
nkeynes@1097
   439
{
nkeynes@1097
   440
    assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );
nkeynes@1097
   441
    file_sector_source_t fdev = (file_sector_source_t)dev;
nkeynes@1097
   442
nkeynes@1097
   443
    uint32_t off = fdev->offset + lba * CDROM_SECTOR_SIZE(dev->mode);
nkeynes@1097
   444
    uint32_t size = block_count * CDROM_SECTOR_SIZE(dev->mode);
nkeynes@1097
   445
    fseek( fdev->file, off, SEEK_SET );
nkeynes@1097
   446
nkeynes@1097
   447
    size_t len = fread( buf, 1, size, fdev->file );
nkeynes@1097
   448
    if( len == -1 ) {
nkeynes@1097
   449
        return CDROM_ERROR_READERROR;
nkeynes@1097
   450
    } else if( len < size ) {
nkeynes@1097
   451
        /* zero-fill */
nkeynes@1097
   452
        memset( buf + len, 0, size-len );
nkeynes@1097
   453
    }
nkeynes@1097
   454
    return CDROM_ERROR_OK;
nkeynes@1097
   455
}
nkeynes@1097
   456
nkeynes@1097
   457
sector_source_t file_sector_source_new( FILE *f, sector_mode_t mode, uint32_t offset,
nkeynes@1097
   458
                                        cdrom_count_t sector_count, gboolean closeOnDestroy )
nkeynes@1097
   459
{
nkeynes@1097
   460
    if( sector_count == FILE_SECTOR_FULL_FILE ) {
nkeynes@1097
   461
        unsigned int sector_size = CDROM_SECTOR_SIZE(mode);
nkeynes@1097
   462
        if( sector_size == 0 )
nkeynes@1097
   463
            sector_size = 2048;
nkeynes@1097
   464
        struct stat st;
nkeynes@1097
   465
nkeynes@1097
   466
        if( f == NULL || fstat( fileno(f), &st ) != 0 ) {
nkeynes@1097
   467
            /* can't stat file? */
nkeynes@1097
   468
            return NULL;
nkeynes@1097
   469
        }
nkeynes@1097
   470
nkeynes@1097
   471
        sector_count = (st.st_size + sector_size-1) / sector_size;
nkeynes@1097
   472
    }
nkeynes@1097
   473
nkeynes@1097
   474
    file_sector_source_t dev = g_malloc(sizeof(struct file_sector_source));
nkeynes@1097
   475
    dev->file = f;
nkeynes@1097
   476
    dev->offset = offset;
nkeynes@1097
   477
    dev->closeOnDestroy = closeOnDestroy;
nkeynes@1097
   478
    dev->ref = NULL;
nkeynes@1097
   479
    return sector_source_init( &dev->dev, FILE_SECTOR_SOURCE, mode,  sector_count, file_sector_source_read, file_sector_source_destroy );
nkeynes@1097
   480
}
nkeynes@1097
   481
nkeynes@1097
   482
sector_source_t file_sector_source_new_full( FILE *f, sector_mode_t mode, gboolean closeOnDestroy )
nkeynes@1097
   483
{
nkeynes@1097
   484
    return file_sector_source_new( f, mode, 0, FILE_SECTOR_FULL_FILE, closeOnDestroy );
nkeynes@1097
   485
}
nkeynes@1097
   486
nkeynes@1097
   487
sector_source_t file_sector_source_new_filename( const gchar *filename, sector_mode_t mode, uint32_t offset,
nkeynes@1097
   488
                                                 cdrom_count_t sector_count )
nkeynes@1097
   489
{
nkeynes@1097
   490
    int fd = open( filename, O_RDONLY|O_NONBLOCK );
nkeynes@1097
   491
    if( fd == -1 ) {
nkeynes@1097
   492
        return NULL;
nkeynes@1097
   493
    }
nkeynes@1097
   494
    FILE *f = fdopen( fd , "ro" );
nkeynes@1097
   495
    if( f == NULL ) {
nkeynes@1097
   496
        close(fd);
nkeynes@1097
   497
        return NULL;
nkeynes@1097
   498
    } else {
nkeynes@1097
   499
        return file_sector_source_new( f, mode, offset, sector_count, TRUE );
nkeynes@1097
   500
    }
nkeynes@1097
   501
}
nkeynes@1097
   502
nkeynes@1097
   503
sector_source_t file_sector_source_new_source( sector_source_t ref, sector_mode_t mode, uint32_t offset,
nkeynes@1097
   504
                                               cdrom_count_t sector_count )
nkeynes@1097
   505
{
nkeynes@1097
   506
    assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
nkeynes@1097
   507
    file_sector_source_t fref = (file_sector_source_t)ref;
nkeynes@1097
   508
nkeynes@1097
   509
    sector_source_t source = file_sector_source_new( fref->file, mode, offset, sector_count, FALSE );
nkeynes@1097
   510
    ((file_sector_source_t)source)->ref = ref;
nkeynes@1097
   511
    sector_source_ref(ref);
nkeynes@1097
   512
    return source;
nkeynes@1097
   513
}
nkeynes@1097
   514
nkeynes@1097
   515
FILE *file_sector_source_get_file( sector_source_t ref )
nkeynes@1097
   516
{
nkeynes@1097
   517
    assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
nkeynes@1097
   518
    file_sector_source_t fref = (file_sector_source_t)ref;
nkeynes@1097
   519
    return fref->file;
nkeynes@1097
   520
}
nkeynes@1097
   521
nkeynes@1097
   522
int file_sector_source_get_fd( sector_source_t ref )
nkeynes@1097
   523
{
nkeynes@1097
   524
    return fileno(file_sector_source_get_file(ref));
nkeynes@1097
   525
}
nkeynes@1097
   526
nkeynes@1097
   527
void file_sector_source_set_close_on_destroy( sector_source_t ref, gboolean closeOnDestroy )
nkeynes@1097
   528
{
nkeynes@1097
   529
    assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );
nkeynes@1097
   530
    file_sector_source_t fref = (file_sector_source_t)ref;
nkeynes@1097
   531
    fref->closeOnDestroy = closeOnDestroy;
nkeynes@1097
   532
}
nkeynes@1097
   533
nkeynes@1097
   534
/************************ Track device implementation *************************/
nkeynes@1097
   535
typedef struct track_sector_source {
nkeynes@1097
   536
    struct sector_source dev;
nkeynes@1097
   537
    cdrom_disc_t disc;
nkeynes@1097
   538
    uint32_t start_lba;
nkeynes@1097
   539
} *track_sector_source_t;
nkeynes@1097
   540
nkeynes@1097
   541
cdrom_error_t track_sector_source_read_blocks( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
nkeynes@1097
   542
                                               unsigned char *out )
nkeynes@1097
   543
{
nkeynes@1097
   544
    size_t length;
nkeynes@1097
   545
    assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
nkeynes@1097
   546
    assert( dev->mode != SECTOR_UNKNOWN );
nkeynes@1097
   547
    track_sector_source_t tdev = (track_sector_source_t)dev;
nkeynes@1097
   548
    return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, CDROM_SECTOR_READ_MODE(dev->mode), out, &length );
nkeynes@1097
   549
}
nkeynes@1097
   550
nkeynes@1097
   551
cdrom_error_t track_sector_source_read_sectors( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,
nkeynes@1097
   552
                                                cdrom_read_mode_t mode, unsigned char *out, size_t *length )
nkeynes@1097
   553
{
nkeynes@1097
   554
    assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
nkeynes@1097
   555
    track_sector_source_t tdev = (track_sector_source_t)dev;
nkeynes@1097
   556
nkeynes@1097
   557
    return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, mode, out, length );
nkeynes@1097
   558
}
nkeynes@1097
   559
nkeynes@1097
   560
void track_sector_source_destroy( sector_source_t dev )
nkeynes@1097
   561
{
nkeynes@1097
   562
    assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );
nkeynes@1097
   563
    track_sector_source_t tdev = (track_sector_source_t)dev;
nkeynes@1097
   564
    sector_source_unref( &tdev->disc->source );
nkeynes@1097
   565
    default_sector_source_destroy(dev);
nkeynes@1097
   566
}
nkeynes@1097
   567
nkeynes@1097
   568
sector_source_t track_sector_source_new( cdrom_disc_t disc, sector_mode_t mode, cdrom_lba_t lba, cdrom_count_t count )
nkeynes@1097
   569
{
nkeynes@1097
   570
    if( disc == NULL ) {
nkeynes@1097
   571
        return NULL;
nkeynes@1097
   572
    }
nkeynes@1097
   573
    track_sector_source_t dev = g_malloc(sizeof(struct track_sector_source));
nkeynes@1097
   574
    dev->disc = disc;
nkeynes@1097
   575
    dev->start_lba = lba;
nkeynes@1097
   576
    sector_source_init( &dev->dev, TRACK_SECTOR_SOURCE, mode, count,
nkeynes@1097
   577
                        track_sector_source_read_blocks, track_sector_source_destroy );
nkeynes@1097
   578
    dev->dev.read_sectors = track_sector_source_read_sectors;
nkeynes@1097
   579
    sector_source_ref( &disc->source );
nkeynes@1097
   580
    return &dev->dev;
nkeynes@1097
   581
}
.