filename | src/drivers/cdrom/sector.c |
changeset | 1097:d4807997e450 |
next | 1099:566cdeb157ec |
author | nkeynes |
date | Sun Jan 31 18:35:06 2010 +1000 (14 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 |
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00001.2 +++ b/src/drivers/cdrom/sector.c Sun Jan 31 18:35:06 2010 +10001.3 @@ -0,0 +1,581 @@1.4 +/**1.5 + * $Id$1.6 + *1.7 + * low-level 'block device' for input to gdrom discs.1.8 + *1.9 + * Copyright (c) 2009 Nathan Keynes.1.10 + *1.11 + * This program is free software; you can redistribute it and/or modify1.12 + * it under the terms of the GNU General Public License as published by1.13 + * the Free Software Foundation; either version 2 of the License, or1.14 + * (at your option) any later version.1.15 + *1.16 + * This program is distributed in the hope that it will be useful,1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1.19 + * GNU General Public License for more details.1.20 + */1.21 +1.22 +#include <sys/stat.h>1.23 +#include <glib/gmem.h>1.24 +#include <assert.h>1.25 +#include <stdlib.h>1.26 +#include <stdio.h>1.27 +#include <string.h>1.28 +#include <unistd.h>1.29 +#include <fcntl.h>1.30 +1.31 +#include "drivers/cdrom/sector.h"1.32 +#include "drivers/cdrom/cdrom.h"1.33 +#include "drivers/cdrom/ecc.h"1.34 +1.35 +#define CHECK_READ(dev,lba,count) \1.36 + if( !IS_SECTOR_SOURCE(dev) ) { \1.37 + return CDROM_ERROR_NODISC; \1.38 + } else if( (lba) >= (dev)->size || (lba+block_count) > (dev)->size ) { \1.39 + return CDROM_ERROR_BADREAD; \1.40 + }1.41 +1.42 +/* Default read mode for each sector mode */1.43 +const uint32_t cdrom_sector_read_mode[] = { 0,1.44 + CDROM_READ_CDDA|CDROM_READ_DATA, CDROM_READ_MODE1|CDROM_READ_DATA,1.45 + CDROM_READ_MODE2|CDROM_READ_DATA, CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,1.46 + CDROM_READ_MODE2_FORM1|CDROM_READ_DATA,1.47 + CDROM_READ_MODE2|CDROM_READ_DATA|CDROM_READ_SUBHEADER|CDROM_READ_ECC,1.48 + CDROM_READ_RAW, CDROM_READ_RAW };1.49 +1.50 +/* Block size for each sector mode */1.51 +const uint32_t cdrom_sector_size[] = { 0, 2352, 2048, 2336, 2048, 2324, 2336, 2352, 2352 };1.52 +1.53 +const char *cdrom_sector_mode_names[] = { "Unknown", "Audio", "Mode 1", "Mode 2", "Mode 2 Form 1", "Mode 2 Form 2",1.54 + "Mode 2 semiraw", "XA Raw", "Non-XA Raw" };1.55 +1.56 +1.57 +/********************* Public functions *************************/1.58 +cdrom_error_t sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )1.59 +{1.60 + CHECK_READ(device,lba,block_count);1.61 + return device->read_blocks(device, lba, block_count, buf);1.62 +}1.63 +1.64 +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,1.65 + unsigned char *buf, size_t *length )1.66 +{1.67 + CHECK_READ(device,lba,block_count);1.68 + return device->read_sectors(device, lba, block_count, mode, buf, length);1.69 +}1.70 +1.71 +void sector_source_ref( sector_source_t device )1.72 +{1.73 + assert( IS_SECTOR_SOURCE(device) );1.74 + device->ref_count++;1.75 +}1.76 +1.77 +void sector_source_unref( sector_source_t device )1.78 +{1.79 + if( device == NULL )1.80 + return;1.81 + assert( IS_SECTOR_SOURCE(device) );1.82 + if( device->ref_count > 0 )1.83 + device->ref_count--;1.84 + if( device->ref_count == 0 )1.85 + device->destroy(device);1.86 +}1.87 +1.88 +void sector_source_release( sector_source_t device )1.89 +{1.90 + assert( IS_SECTOR_SOURCE(device) );1.91 + if( device->ref_count == 0 )1.92 + device->destroy(device);1.93 +}1.94 +1.95 +/************************** Sector mangling ***************************/1.96 +/*1.97 + * Private functions used to pack/unpack sectors, determine mode, and1.98 + * evaluate sector reads.1.99 + */1.100 +1.101 +/** Basic data sector header structure */1.102 +struct cdrom_sector_header {1.103 + uint8_t sync[12];1.104 + uint8_t msf[3];1.105 + uint8_t mode;1.106 + uint8_t subhead[8]; // Mode-2 XA sectors only1.107 +};1.108 +1.109 +static const uint8_t cdrom_sync_data[12] = { 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0 };1.110 +1.111 +/* Field combinations that are legal for mode 1 or mode 2 (formless) reads */1.112 +static const uint8_t legal_nonxa_fields[] =1.113 +{ TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,1.114 + TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,1.115 + TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE,1.116 + FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };1.117 +1.118 +/* Field combinations that are legal for mode 2 form 1 or form 2 reads */1.119 +static const uint8_t legal_xa_fields[] =1.120 +{ TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,1.121 + TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE,1.122 + TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,1.123 + FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE };1.124 +1.125 +/**1.126 + * Position per sector mode of each of the fields1.127 + * sync, header, subheader, data, ecc.1.128 + *1.129 + */1.130 +static const uint32_t sector_field_positions[][6] = {1.131 + { 0, 0, 0, 0, 0, 0 }, /* Unknown */1.132 + { 0, 0, 0, 0, 2352, 2352 }, /* CDDA */1.133 + { 0, 12, 16, 16, 2064, 2352 }, /* Mode 1 */1.134 + { 0, 12, 16, 16, 2352, 2352 }, /* Mode 2 formless */1.135 + { 0, 12, 16, 24, 2072, 2352 }, /* Mode 2 form 1 */1.136 + { 0, 12, 16, 24, 2352, 2352 }}; /* Mode 2 form 2 */1.137 +1.138 +1.139 +1.140 +/**1.141 + * Return CDROM_ERROR_OK if the given read mode + sector modes are compatible,1.142 + * otherwise either CDROM_ERROR_BADREADMODE or CDROM_ERROR_BADFIELD. Raw sector modes1.143 + * will return BADREADMODE, as it's impossible to tell.1.144 + *1.145 + * @param track_mode one of the CDROM_MODE* constants1.146 + * @param read_mode the full read mode1.147 + */1.148 +static cdrom_error_t is_legal_read( sector_mode_t sector_mode, cdrom_read_mode_t read_mode )1.149 +{1.150 + int read_sector_type = CDROM_READ_TYPE(read_mode);1.151 + int read_sector_fields = CDROM_READ_FIELDS(read_mode);1.152 +1.153 + /* Check the sector type is consistent */1.154 + switch( read_sector_type ) {1.155 + case CDROM_READ_ANY: break;1.156 + case CDROM_READ_CDDA:1.157 + if( sector_mode != SECTOR_CDDA )1.158 + return CDROM_ERROR_BADREADMODE;1.159 + break;1.160 + case CDROM_READ_MODE1:1.161 + case CDROM_READ_MODE2_FORM1:1.162 + if( sector_mode != SECTOR_MODE1 && sector_mode != SECTOR_MODE2_FORM1 )1.163 + return CDROM_ERROR_BADREADMODE;1.164 + break;1.165 + case CDROM_READ_MODE2_FORM2:1.166 + if( sector_mode != SECTOR_MODE2_FORM2 )1.167 + return CDROM_ERROR_BADREADMODE;1.168 + break;1.169 + case CDROM_READ_MODE2:1.170 + if( sector_mode != SECTOR_MODE2_FORMLESS )1.171 + return CDROM_ERROR_BADREADMODE;1.172 + break;1.173 + default: /* Illegal read mode */1.174 + return CDROM_ERROR_BADFIELD;1.175 + }1.176 +1.177 + /* Check the fields requested are sane per MMC (non-contiguous regions prohibited) */1.178 + switch( sector_mode ) {1.179 + case SECTOR_CDDA:1.180 + return CDROM_ERROR_OK; /* Everything is OK */1.181 + case SECTOR_MODE2_FORM1:1.182 + case SECTOR_MODE2_FORM2:1.183 + if( !legal_xa_fields[read_sector_fields>>11] )1.184 + return CDROM_ERROR_BADFIELD;1.185 + else1.186 + return CDROM_ERROR_OK;1.187 + case SECTOR_MODE1:1.188 + case SECTOR_MODE2_FORMLESS:1.189 + if( !legal_nonxa_fields[read_sector_fields>>11] )1.190 + return CDROM_ERROR_BADFIELD;1.191 + else1.192 + return CDROM_ERROR_OK;1.193 + default:1.194 + return CDROM_ERROR_BADFIELD;1.195 + }1.196 +}1.197 +1.198 +static sector_mode_t identify_sector( sector_mode_t raw_mode, unsigned char *buf )1.199 +{1.200 + struct cdrom_sector_header *header = (struct cdrom_sector_header *)buf;1.201 +1.202 + switch( raw_mode ) {1.203 + case SECTOR_SEMIRAW_MODE2: /* XA sectors */1.204 + case SECTOR_RAW_XA:1.205 + switch( header->mode ) {1.206 + case 1: return SECTOR_MODE1;1.207 + case 2: return ((header->subhead[2] & 0x20) == 0 ) ? SECTOR_MODE2_FORM1 : SECTOR_MODE2_FORM2;1.208 + default: return SECTOR_UNKNOWN;1.209 + }1.210 + case SECTOR_RAW_NONXA:1.211 + switch( header->mode ) {1.212 + case 1: return SECTOR_MODE1;1.213 + case 2: return SECTOR_MODE2_FORMLESS;1.214 + default: return SECTOR_UNKNOWN;1.215 + }1.216 + default:1.217 + return raw_mode;1.218 + }1.219 +}1.220 +1.221 +/**1.222 + * Read a single raw sector from the device. Generate sync, ECC/EDC data etc where1.223 + * necessary.1.224 + */1.225 +static cdrom_error_t read_raw_sector( sector_source_t device, cdrom_lba_t lba, unsigned char *buf )1.226 +{1.227 + cdrom_error_t err;1.228 +1.229 + switch( device->mode ) {1.230 + case SECTOR_RAW_XA:1.231 + case SECTOR_RAW_NONXA:1.232 + return device->read_blocks(device, lba, 1, buf);1.233 + case SECTOR_SEMIRAW_MODE2:1.234 + memcpy( buf, cdrom_sync_data, 12 );1.235 + cd_build_address(buf, SECTOR_MODE2_FORMLESS, lba);1.236 + return device->read_blocks(device, lba, 1, &buf[16]);1.237 + case SECTOR_MODE1:1.238 + case SECTOR_MODE2_FORMLESS:1.239 + err = device->read_blocks(device, lba, 1, &buf[16]);1.240 + if( err == CDROM_ERROR_OK ) {1.241 + do_encode_L2( buf, device->mode, lba );1.242 + }1.243 + return err;1.244 + case SECTOR_MODE2_FORM1:1.245 + *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0;1.246 + err = device->read_blocks(device, lba, 1, &buf[24]);1.247 + if( err == CDROM_ERROR_OK ) {1.248 + do_encode_L2( buf, device->mode, lba );1.249 + }1.250 + return err;1.251 + case SECTOR_MODE2_FORM2:1.252 + *((uint32_t *)(buf+16)) = *((uint32_t *)(buf+20)) = 0x00200000;1.253 + err = device->read_blocks(device, lba, 1, &buf[24]);1.254 + if( err == CDROM_ERROR_OK ) {1.255 + do_encode_L2( buf, device->mode, lba );1.256 + }1.257 + return err;1.258 + default:1.259 + abort();1.260 + }1.261 +}1.262 +1.263 +static cdrom_error_t extract_sector_fields( unsigned char *raw_sector, sector_mode_t mode, int fields, unsigned char *buf, size_t *length )1.264 +{1.265 + int start=-1,end=0;1.266 + int i;1.267 +1.268 + for( i=0; i<5; i++ ) {1.269 + if( fields & (0x8000>>i) ) {1.270 + if( start == -1 )1.271 + start = sector_field_positions[mode][i];1.272 + else if( end != sector_field_positions[mode][i] )1.273 + return CDROM_ERROR_BADFIELD;1.274 + end = sector_field_positions[mode][i+1];1.275 + }1.276 + }1.277 + if( start == -1 ) {1.278 + *length = 0;1.279 + } else {1.280 + memcpy( buf, &raw_sector[start], end-start );1.281 + *length = end-start;1.282 + }1.283 + return CDROM_ERROR_OK;1.284 +}1.285 +1.286 +cdrom_error_t sector_extract_from_raw( unsigned char *raw_sector, cdrom_read_mode_t mode, unsigned char *buf, size_t *length )1.287 +{1.288 + sector_mode_t sector_mode = identify_sector( SECTOR_RAW_XA, raw_sector );1.289 + if( sector_mode == SECTOR_UNKNOWN )1.290 + return CDROM_ERROR_BADREAD;1.291 + cdrom_error_t status = is_legal_read( sector_mode, mode );1.292 + if( status != CDROM_ERROR_OK )1.293 + return status;1.294 + return extract_sector_fields( raw_sector, sector_mode, CDROM_READ_FIELDS(mode), buf, length );1.295 +}1.296 +1.297 +/**1.298 + * This is horribly complicated by the need to handle mapping between all possible1.299 + * sector modes + read modes, but fortunately most sources can just supply1.300 + * a single block type and not care about the details here.1.301 + */1.302 +cdrom_error_t default_sector_source_read_sectors( sector_source_t device,1.303 + cdrom_lba_t lba, cdrom_count_t block_count, cdrom_read_mode_t mode,1.304 + unsigned char *buf, size_t *length )1.305 +{1.306 + unsigned char tmp[CDROM_MAX_SECTOR_SIZE];1.307 + int read_sector_type = CDROM_READ_TYPE(mode);1.308 + int read_sector_fields = CDROM_READ_FIELDS(mode);1.309 + int i;1.310 + size_t len = 0;1.311 + cdrom_error_t err;1.312 +1.313 + CHECK_READ(device, lba, count);1.314 +1.315 + switch(device->mode) {1.316 + case SECTOR_CDDA:1.317 + if( read_sector_type != CDROM_READ_ANY && read_sector_type != CDROM_READ_CDDA )1.318 + return CDROM_ERROR_BADREADMODE;1.319 + if( read_sector_fields != 0 ) {1.320 + len = block_count * CDROM_MAX_SECTOR_SIZE;1.321 + device->read_blocks( device, lba, block_count, buf );1.322 + }1.323 + break;1.324 + case SECTOR_RAW_XA:1.325 + case SECTOR_RAW_NONXA:1.326 + case SECTOR_SEMIRAW_MODE2:1.327 + /* We (may) have to break the raw sector up into requested fields.1.328 + * Process sectors one at a time1.329 + */1.330 + for( i=0; i<block_count; i++ ) {1.331 + size_t tmplen;1.332 + err = read_raw_sector( device, lba+i, tmp );1.333 + if( err != CDROM_ERROR_OK )1.334 + return err;1.335 + err = sector_extract_from_raw( tmp, mode, &buf[len], &tmplen );1.336 + if( err != CDROM_ERROR_OK )1.337 + return err;1.338 + len += tmplen;1.339 + }1.340 + break;1.341 + default: /* Data-only blocks */1.342 + err = is_legal_read( device->mode, mode );1.343 + if( err != CDROM_ERROR_OK )1.344 + return err;1.345 + if( read_sector_fields == 0 ) { /* Read nothing */1.346 + *length = 0;1.347 + return CDROM_ERROR_OK;1.348 + } else if( read_sector_fields == CDROM_READ_DATA ) {1.349 + /* Data-only */1.350 + *length = block_count * CDROM_SECTOR_SIZE(device->mode);1.351 + return device->read_blocks( device, lba, block_count, buf );1.352 + } else if( read_sector_fields == CDROM_READ_RAW ) {1.353 + for( i=0; i<block_count; i++ ) {1.354 + err = read_raw_sector( device, lba+i, &buf[2352*i] );1.355 + if( err != CDROM_ERROR_OK )1.356 + return err;1.357 + }1.358 + len = block_count * CDROM_MAX_SECTOR_SIZE;1.359 + } else {1.360 + for( i=0; i<block_count; i++ ) {1.361 + size_t tmplen;1.362 + err = read_raw_sector( device, lba+i, tmp );1.363 + if( err != CDROM_ERROR_OK )1.364 + return err;1.365 + err = extract_sector_fields( tmp, device->mode, read_sector_fields, &buf[len], &tmplen );1.366 + if( err != CDROM_ERROR_OK )1.367 + return err;1.368 + len += tmplen;1.369 + }1.370 + }1.371 + }1.372 + *length = len;1.373 + return CDROM_ERROR_OK;1.374 +1.375 +}1.376 +1.377 +/************************ Base implementation *************************/1.378 +1.379 +/**1.380 + * Default destroy implementation - clears the tag and frees memory.1.381 + */1.382 +void default_sector_source_destroy( sector_source_t device )1.383 +{1.384 + assert( device != NULL && device->ref_count == 0 );1.385 + device->tag = 0;1.386 + g_free( device );1.387 +}1.388 +1.389 +sector_source_t sector_source_init( sector_source_t device, sector_source_type_t type, sector_mode_t mode, cdrom_count_t size,1.390 + sector_source_read_fn_t readfn, sector_source_destroy_fn_t destroyfn )1.391 +{1.392 + device->tag = SECTOR_SOURCE_TAG;1.393 + device->ref_count = 0;1.394 + device->type = type;1.395 + device->mode = mode;1.396 + device->size = size;1.397 + device->read_blocks = readfn;1.398 + device->read_sectors = default_sector_source_read_sectors;1.399 + if( destroyfn == NULL )1.400 + device->destroy = default_sector_source_destroy;1.401 + else1.402 + device->destroy = destroyfn;1.403 + return device;1.404 +}1.405 +1.406 +/************************ Null device implementation *************************/1.407 +cdrom_error_t null_sector_source_read( sector_source_t device, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )1.408 +{1.409 + memset( buf, 0, block_count*CDROM_SECTOR_SIZE(device->mode) );1.410 + return CDROM_ERROR_OK;1.411 +}1.412 +1.413 +sector_source_t null_sector_source_new( sector_mode_t mode, cdrom_count_t size )1.414 +{1.415 + return sector_source_init( g_malloc(sizeof(struct sector_source)), NULL_SECTOR_SOURCE, mode, size,1.416 + null_sector_source_read, default_sector_source_destroy );1.417 +}1.418 +1.419 +/************************ File device implementation *************************/1.420 +typedef struct file_sector_source {1.421 + struct sector_source dev;1.422 + FILE *file;1.423 + uint32_t offset; /* offset in file where source begins */1.424 + sector_source_t ref; /* Parent source reference */1.425 + gboolean closeOnDestroy;1.426 +} *file_sector_source_t;1.427 +1.428 +void file_sector_source_destroy( sector_source_t dev )1.429 +{1.430 + assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );1.431 + file_sector_source_t fdev = (file_sector_source_t)dev;1.432 +1.433 + if( fdev->closeOnDestroy && fdev->file != NULL ) {1.434 + fclose( fdev->file );1.435 + }1.436 + sector_source_unref( fdev->ref );1.437 + fdev->file = NULL;1.438 + default_sector_source_destroy(dev);1.439 +}1.440 +1.441 +cdrom_error_t file_sector_source_read( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t block_count, unsigned char *buf )1.442 +{1.443 + assert( IS_SECTOR_SOURCE_TYPE(dev,FILE_SECTOR_SOURCE) );1.444 + file_sector_source_t fdev = (file_sector_source_t)dev;1.445 +1.446 + uint32_t off = fdev->offset + lba * CDROM_SECTOR_SIZE(dev->mode);1.447 + uint32_t size = block_count * CDROM_SECTOR_SIZE(dev->mode);1.448 + fseek( fdev->file, off, SEEK_SET );1.449 +1.450 + size_t len = fread( buf, 1, size, fdev->file );1.451 + if( len == -1 ) {1.452 + return CDROM_ERROR_READERROR;1.453 + } else if( len < size ) {1.454 + /* zero-fill */1.455 + memset( buf + len, 0, size-len );1.456 + }1.457 + return CDROM_ERROR_OK;1.458 +}1.459 +1.460 +sector_source_t file_sector_source_new( FILE *f, sector_mode_t mode, uint32_t offset,1.461 + cdrom_count_t sector_count, gboolean closeOnDestroy )1.462 +{1.463 + if( sector_count == FILE_SECTOR_FULL_FILE ) {1.464 + unsigned int sector_size = CDROM_SECTOR_SIZE(mode);1.465 + if( sector_size == 0 )1.466 + sector_size = 2048;1.467 + struct stat st;1.468 +1.469 + if( f == NULL || fstat( fileno(f), &st ) != 0 ) {1.470 + /* can't stat file? */1.471 + return NULL;1.472 + }1.473 +1.474 + sector_count = (st.st_size + sector_size-1) / sector_size;1.475 + }1.476 +1.477 + file_sector_source_t dev = g_malloc(sizeof(struct file_sector_source));1.478 + dev->file = f;1.479 + dev->offset = offset;1.480 + dev->closeOnDestroy = closeOnDestroy;1.481 + dev->ref = NULL;1.482 + return sector_source_init( &dev->dev, FILE_SECTOR_SOURCE, mode, sector_count, file_sector_source_read, file_sector_source_destroy );1.483 +}1.484 +1.485 +sector_source_t file_sector_source_new_full( FILE *f, sector_mode_t mode, gboolean closeOnDestroy )1.486 +{1.487 + return file_sector_source_new( f, mode, 0, FILE_SECTOR_FULL_FILE, closeOnDestroy );1.488 +}1.489 +1.490 +sector_source_t file_sector_source_new_filename( const gchar *filename, sector_mode_t mode, uint32_t offset,1.491 + cdrom_count_t sector_count )1.492 +{1.493 + int fd = open( filename, O_RDONLY|O_NONBLOCK );1.494 + if( fd == -1 ) {1.495 + return NULL;1.496 + }1.497 + FILE *f = fdopen( fd , "ro" );1.498 + if( f == NULL ) {1.499 + close(fd);1.500 + return NULL;1.501 + } else {1.502 + return file_sector_source_new( f, mode, offset, sector_count, TRUE );1.503 + }1.504 +}1.505 +1.506 +sector_source_t file_sector_source_new_source( sector_source_t ref, sector_mode_t mode, uint32_t offset,1.507 + cdrom_count_t sector_count )1.508 +{1.509 + assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );1.510 + file_sector_source_t fref = (file_sector_source_t)ref;1.511 +1.512 + sector_source_t source = file_sector_source_new( fref->file, mode, offset, sector_count, FALSE );1.513 + ((file_sector_source_t)source)->ref = ref;1.514 + sector_source_ref(ref);1.515 + return source;1.516 +}1.517 +1.518 +FILE *file_sector_source_get_file( sector_source_t ref )1.519 +{1.520 + assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );1.521 + file_sector_source_t fref = (file_sector_source_t)ref;1.522 + return fref->file;1.523 +}1.524 +1.525 +int file_sector_source_get_fd( sector_source_t ref )1.526 +{1.527 + return fileno(file_sector_source_get_file(ref));1.528 +}1.529 +1.530 +void file_sector_source_set_close_on_destroy( sector_source_t ref, gboolean closeOnDestroy )1.531 +{1.532 + assert( IS_SECTOR_SOURCE_TYPE(ref,FILE_SECTOR_SOURCE) );1.533 + file_sector_source_t fref = (file_sector_source_t)ref;1.534 + fref->closeOnDestroy = closeOnDestroy;1.535 +}1.536 +1.537 +/************************ Track device implementation *************************/1.538 +typedef struct track_sector_source {1.539 + struct sector_source dev;1.540 + cdrom_disc_t disc;1.541 + uint32_t start_lba;1.542 +} *track_sector_source_t;1.543 +1.544 +cdrom_error_t track_sector_source_read_blocks( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,1.545 + unsigned char *out )1.546 +{1.547 + size_t length;1.548 + assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );1.549 + assert( dev->mode != SECTOR_UNKNOWN );1.550 + track_sector_source_t tdev = (track_sector_source_t)dev;1.551 + return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, CDROM_SECTOR_READ_MODE(dev->mode), out, &length );1.552 +}1.553 +1.554 +cdrom_error_t track_sector_source_read_sectors( sector_source_t dev, cdrom_lba_t lba, cdrom_count_t count,1.555 + cdrom_read_mode_t mode, unsigned char *out, size_t *length )1.556 +{1.557 + assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );1.558 + track_sector_source_t tdev = (track_sector_source_t)dev;1.559 +1.560 + return cdrom_disc_read_sectors( tdev->disc, lba + tdev->start_lba, count, mode, out, length );1.561 +}1.562 +1.563 +void track_sector_source_destroy( sector_source_t dev )1.564 +{1.565 + assert( IS_SECTOR_SOURCE_TYPE(dev,TRACK_SECTOR_SOURCE) );1.566 + track_sector_source_t tdev = (track_sector_source_t)dev;1.567 + sector_source_unref( &tdev->disc->source );1.568 + default_sector_source_destroy(dev);1.569 +}1.570 +1.571 +sector_source_t track_sector_source_new( cdrom_disc_t disc, sector_mode_t mode, cdrom_lba_t lba, cdrom_count_t count )1.572 +{1.573 + if( disc == NULL ) {1.574 + return NULL;1.575 + }1.576 + track_sector_source_t dev = g_malloc(sizeof(struct track_sector_source));1.577 + dev->disc = disc;1.578 + dev->start_lba = lba;1.579 + sector_source_init( &dev->dev, TRACK_SECTOR_SOURCE, mode, count,1.580 + track_sector_source_read_blocks, track_sector_source_destroy );1.581 + dev->dev.read_sectors = track_sector_source_read_sectors;1.582 + sector_source_ref( &disc->source );1.583 + return &dev->dev;1.584 +}
.