Search
lxdream.org :: lxdream/src/gdrom/cdi.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/cdi.c
changeset 759:f16975739abc
prev736:a02d1475ccfd
next999:3d19e3597d9b
author nkeynes
date Wed Nov 05 10:05:08 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Fix (extremely boneheaded) failure to convert pc to physical address before
storing in the translation cache (in other words, the translation cache was
effectively disabled for MMU code). MMU code is now about 3 times faster...
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * CDI CD-image file support
     5  *
     6  * Copyright (c) 2005 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    19 #include <stdlib.h>
    20 #include <stdio.h>
    21 #include <stdint.h>
    22 #include <string.h>
    23 #include <fcntl.h>
    24 #include <errno.h>
    25 #include <sys/stat.h>
    26 #include "gdrom/gddriver.h"
    28 #define CDI_V2_ID 0x80000004
    29 #define CDI_V3_ID 0x80000005
    30 #define CDI_V35_ID 0x80000006
    33 static gboolean cdi_image_is_valid( FILE *f );
    34 static gdrom_disc_t cdi_image_open( const gchar *filename, FILE *f );
    36 struct gdrom_image_class cdi_image_class = { "DiscJuggler", "cdi", 
    37         cdi_image_is_valid, cdi_image_open };
    39 static const char TRACK_START_MARKER[20] = { 0,0,1,0,0,0,255,255,255,255,
    40         0,0,1,0,0,0,255,255,255,255 };
    41 static const char EXT_MARKER[9] = {0,255,255,255,255,255,255,255,255 };
    43 struct cdi_trailer {
    44     uint32_t cdi_version;
    45     uint32_t header_offset;
    46 };
    48 struct cdi_track_data {
    49     uint32_t pregap_length;
    50     uint32_t length;
    51     char unknown2[6];
    52     uint32_t mode;
    53     char unknown3[0x0c];
    54     uint32_t start_lba;
    55     uint32_t total_length;
    56     char unknown4[0x10];
    57     uint32_t sector_size;
    58     char unknown5[0x1D];
    59 } __attribute__((packed));
    61 gboolean cdi_image_is_valid( FILE *f )
    62 {
    63     int len;
    64     struct cdi_trailer trail;
    66     fseek( f, -8, SEEK_END );
    67     len = ftell(f)+8;
    68     fread( &trail, sizeof(trail), 1, f );
    69     if( trail.header_offset >= len ||
    70             trail.header_offset == 0 )
    71         return FALSE;
    72     return trail.cdi_version == CDI_V2_ID || trail.cdi_version == CDI_V3_ID ||
    73     trail.cdi_version == CDI_V35_ID;
    74 }
    76 gdrom_disc_t cdi_image_open( const gchar *filename, FILE *f )
    77 {
    78     gdrom_disc_t disc = NULL;
    79     gdrom_image_t image;
    80     int i,j;
    81     uint16_t session_count;
    82     uint16_t track_count;
    83     int total_tracks = 0;
    84     int posn = 0;
    85     long len;
    86     struct cdi_trailer trail;
    87     char marker[20];
    89     fseek( f, -8, SEEK_END );
    90     len = ftell(f)+8;
    91     fread( &trail, sizeof(trail), 1, f );
    92     if( trail.header_offset >= len ||
    93             trail.header_offset == 0 )
    94         return NULL;
    96     if( trail.cdi_version != CDI_V2_ID && trail.cdi_version != CDI_V3_ID &&
    97             trail.cdi_version != CDI_V35_ID ) {
    98         return NULL;
    99     }
   101     if( trail.cdi_version == CDI_V35_ID ) {
   102         fseek( f, -trail.header_offset, SEEK_END );
   103     } else {
   104         fseek( f, trail.header_offset, SEEK_SET );
   105     }
   106     fread( &session_count, sizeof(session_count), 1, f );
   108     disc = gdrom_image_new(filename, f);
   109     if( disc == NULL ) {
   110         ERROR("Unable to allocate memory!");
   111         return NULL;
   112     }
   113     image = (gdrom_image_t)disc;
   115     for( i=0; i< session_count; i++ ) {        
   116         fread( &track_count, sizeof(track_count), 1, f );
   117         if( track_count + total_tracks > 99 ) {
   118             ERROR( "Invalid number of tracks, bad cdi image\n" );
   119             gdrom_image_destroy_no_close(disc);
   120             return NULL;
   121         }
   122         for( j=0; j<track_count; j++ ) {
   123             struct cdi_track_data trk;
   124             uint32_t new_fmt = 0;
   125             uint8_t fnamelen = 0;
   126             fread( &new_fmt, sizeof(new_fmt), 1, f );
   127             if( new_fmt != 0 ) { /* Additional data 3.00.780+ ?? */
   128                 fseek( f, 8, SEEK_CUR ); /* Skip */
   129             }
   130             fread( marker, 20, 1, f );
   131             if( memcmp( marker, TRACK_START_MARKER, 20) != 0 ) {
   132                 ERROR( "Track start marker not found, error reading cdi image\n" );
   133                 gdrom_image_destroy_no_close(disc);
   134                 return NULL;
   135             }
   136             fseek( f, 4, SEEK_CUR );
   137             fread( &fnamelen, 1, 1, f );
   138             fseek( f, (int)fnamelen, SEEK_CUR ); /* skip over the filename */
   139             fseek( f, 19, SEEK_CUR );
   140             fread( &new_fmt, sizeof(new_fmt), 1, f );
   141             if( new_fmt == 0x80000000 ) {
   142                 fseek( f, 10, SEEK_CUR );
   143             } else {
   144                 fseek( f, 2, SEEK_CUR );
   145             }
   146             fread( &trk, sizeof(trk), 1, f );
   147             image->track[total_tracks].session = i;
   148             image->track[total_tracks].lba = trk.start_lba + 150;
   149             image->track[total_tracks].sector_count = trk.length;
   150             switch( trk.mode ) {
   151             case 0:
   152                 image->track[total_tracks].mode = GDROM_CDDA;
   153                 image->track[total_tracks].sector_size = 2352;
   154                 image->track[total_tracks].flags = 0x01;
   155                 if( trk.sector_size != 2 ) {
   156                     ERROR( "Invalid combination of mode %d with size %d", trk.mode, trk.sector_size );
   157                     gdrom_image_destroy_no_close(disc);
   158                     return NULL;
   159                 }
   160                 break;
   161             case 1:
   162                 image->track[total_tracks].mode = GDROM_MODE1;
   163                 image->track[total_tracks].sector_size = 2048;
   164                 image->track[total_tracks].flags = 0x41;
   165                 if( trk.sector_size != 0 ) {
   166                     ERROR( "Invalid combination of mode %d with size %d", trk.mode, trk.sector_size );
   167                     gdrom_image_destroy_no_close(disc);
   168                     return NULL;
   169                 }
   170                 break;
   171             case 2:
   172                 image->track[total_tracks].flags = 0x41;
   173                 switch( trk.sector_size ) {
   174                 case 0:
   175                     image->track[total_tracks].mode = GDROM_MODE2_FORM1;
   176                     image->track[total_tracks].sector_size = 2048;
   177                     break;
   178                 case 1:
   179                     image->track[total_tracks].mode = GDROM_SEMIRAW_MODE2;
   180                     image->track[total_tracks].sector_size = 2336;
   181                     break;
   182                 case 2:
   183                 default:
   184                     ERROR( "Invalid combination of mode %d with size %d", trk.mode, trk.sector_size );
   185                     gdrom_image_destroy_no_close(disc);
   186                     return NULL;
   187                 }
   188                 break;
   189                 default:
   190                     ERROR( "Unsupported track mode %d", trk.mode );
   191                     gdrom_image_destroy_no_close(disc);
   192                     return NULL;
   193             }
   194             image->track[total_tracks].offset = posn + 
   195             trk.pregap_length * image->track[total_tracks].sector_size ;
   196             posn += trk.total_length * image->track[total_tracks].sector_size;
   197             total_tracks++;
   198             fread( marker, 1, 9, f );
   199             if( memcmp( marker, EXT_MARKER, 9 ) == 0 ) {
   200                 fseek( f, 79, SEEK_CUR );
   201             } else {
   202                 fseek( f, -9, SEEK_CUR );
   203             }
   204         }
   205         fseek( f, 12, SEEK_CUR );
   206     }
   207     image->track_count = total_tracks;
   208     return disc;
   209 }
.