Search
lxdream.org :: lxdream/src/gdrom/gdrom.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/gdrom.c
changeset 1097:d4807997e450
prev1074:397d77b6e346
next1101:78e762cec843
author nkeynes
date Mon Feb 15 17:27:14 2010 +1000 (14 years ago)
permissions -rw-r--r--
last change Hook up the fake bios boot
Use fakebios if invoked with -b, or if there's no boot rom loaded
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * GD-Rom  access functions.
     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 <stdio.h>
    20 #include <stdlib.h>
    21 #include <string.h>
    22 #include <fcntl.h>
    23 #include <errno.h>
    24 #include <ctype.h>
    25 #include <glib/gutils.h>
    26 #include <netinet/in.h>
    27 #include "gdrom/ide.h"
    28 #include "gdrom/gdrom.h"
    29 #include "gdrom/packet.h"
    30 #include "bootstrap.h"
    31 #include "drivers/cdrom/cdrom.h"
    33 #define GDROM_LBA_OFFSET 150
    35 DEFINE_HOOK( gdrom_disc_change_hook, gdrom_disc_change_hook_t )
    37 static void gdrom_fire_disc_changed( cdrom_disc_t disc )
    38 {
    39     CALL_HOOKS( gdrom_disc_change_hook, disc, disc == NULL ? NULL : disc->name );
    40 }
    42 gboolean gdrom_disc_read_title( cdrom_disc_t disc, char *title, size_t titlelen );
    44 struct gdrom_drive {
    45     cdrom_disc_t disc;
    46     int boot_track;
    47     char title[129];
    48 } gdrom_drive;
    50 void gdrom_mount_disc( cdrom_disc_t disc )
    51 {
    52     if( disc != gdrom_drive.disc ) {
    53         cdrom_disc_unref(gdrom_drive.disc);
    54         gdrom_drive.disc = disc;
    55         cdrom_disc_ref(disc);
    56         gdrom_disc_read_title( disc, gdrom_drive.title, sizeof(gdrom_drive.title) );
    57         gdrom_fire_disc_changed( disc );
    58     }
    59 }
    61 gboolean gdrom_mount_image( const gchar *filename )
    62 {
    63     cdrom_disc_t disc = cdrom_disc_open(filename, NULL);
    64     if( disc != NULL ) {         
    65         gdrom_mount_disc( disc );
    66         return TRUE;
    67     }
    68     return FALSE;
    69 }
    71 void gdrom_unmount_disc( ) 
    72 {
    73     if( gdrom_drive.disc != NULL ) {
    74         cdrom_disc_unref(gdrom_drive.disc);
    75         gdrom_fire_disc_changed(NULL);
    76         gdrom_drive.disc = NULL;
    77     }
    78 }
    80 cdrom_disc_t gdrom_get_current_disc()
    81 {
    82     return gdrom_drive.disc;
    83 }
    85 const gchar *gdrom_get_current_disc_name()
    86 {
    87     if( gdrom_drive.disc == NULL ) {
    88         return NULL;
    89     } else {
    90         return gdrom_drive.disc->name;
    91     }
    92 }
    94 const gchar *gdrom_get_current_disc_title()
    95 {
    96     if( gdrom_drive.disc == NULL || gdrom_drive.title[0] == '\0' ) {
    97         return NULL;
    98     } else {
    99         return gdrom_drive.title;
   100     }
   101 }
   103 #define CHECK_DISC() do { \
   104 	    if( gdrom_drive.disc == NULL || gdrom_drive.disc->disc_type == CDROM_DISC_NONE ) { return CDROM_ERROR_NODISC; } \
   105     } while(0)
   107 cdrom_error_t gdrom_check_media( )
   108 {
   109 	CHECK_DISC();
   110 	return CDROM_ERROR_OK;
   111 }
   113 cdrom_error_t gdrom_read_toc( unsigned char *buf )
   114 {
   115 	struct gdrom_toc {
   116 	    uint32_t track[99];
   117 	    uint32_t first, last, leadout;
   118 	};
   120     struct gdrom_toc *toc = (struct gdrom_toc *)buf;
   121     int i;
   123     CHECK_DISC();
   124     cdrom_disc_t disc = gdrom_drive.disc;
   126     for( i=0; i<disc->track_count; i++ ) {
   127         toc->track[i] = htonl( disc->track[i].lba+GDROM_LBA_OFFSET ) | disc->track[i].flags;
   128     }
   129     toc->first = 0x0100 | disc->track[0].flags;
   130     toc->last = (disc->track_count<<8) | disc->track[i-1].flags;
   131     toc->leadout = htonl(disc->leadout+GDROM_LBA_OFFSET) |
   132     disc->track[i-1].flags;
   133     for( ;i<99; i++ )
   134         toc->track[i] = 0xFFFFFFFF;
   135     return PKT_ERR_OK;
   136 }
   138 cdrom_error_t gdrom_read_session( int session, unsigned char *buf )
   139 {
   140     cdrom_lba_t lba;
   141 	CHECK_DISC();
   143     buf[0] = 0x01; /* Disc status? */
   144     buf[1] = 0;
   147     if( session == 0 ) {
   148         buf[2] = gdrom_drive.disc->session_count;
   149         lba = gdrom_drive.disc->leadout + GDROM_LBA_OFFSET;
   150     } else {
   151         cdrom_track_t track = cdrom_disc_get_session( gdrom_drive.disc, session );
   152         if( track == NULL )
   153             return CDROM_ERROR_BADFIELD;
   155         buf[2] = track->trackno;
   156         lba = track->lba + GDROM_LBA_OFFSET;
   157     }
   158     buf[3] = (lba >> 16) & 0xFF;
   159     buf[4] = (lba >> 8) & 0xFF;
   160     buf[5] = lba & 0xFF;
   161     return CDROM_ERROR_OK;
   162 }
   164 cdrom_error_t gdrom_read_short_status( cdrom_lba_t lba, unsigned char *buf )
   165 {
   166     cdrom_lba_t real_lba = lba - GDROM_LBA_OFFSET;
   167 	CHECK_DISC();
   169     cdrom_track_t track = cdrom_disc_get_track_by_lba( gdrom_drive.disc, real_lba );
   170     if( track == NULL ) {
   171         track = cdrom_disc_get_track( gdrom_drive.disc, 1 );
   172         if( track == NULL )
   173             return CDROM_ERROR_NODISC;
   174         lba = 150;
   175     }
   176     uint32_t offset = real_lba - track->lba;
   177 	buf[0] = 0x00;
   178 	buf[1] = 0x15; /* audio status ? */
   179     buf[2] = 0x00;
   180     buf[3] = 0x0E;
   181     buf[4] = track->flags;
   182     buf[5] = track->trackno;
   183     buf[6] = 0x01; /* ?? */
   184     buf[7] = (offset >> 16) & 0xFF;
   185     buf[8] = (offset >> 8) & 0xFF;
   186     buf[9] = offset & 0xFF;
   187     buf[10] = 0;
   188     buf[11] = (lba >> 16) & 0xFF;
   189     buf[12] = (lba >> 8) & 0xFF;
   190     buf[13] = lba & 0xFF;
   191     return PKT_ERR_OK;
   192 }
   194 int gdrom_get_drive_status( )
   195 {
   196 	if( gdrom_drive.disc == NULL ) {
   197 		return CDROM_DISC_NONE;
   198 	}
   200     if( cdrom_disc_check_media(gdrom_drive.disc) == CDROM_DISC_NONE ) {
   201         return CDROM_DISC_NONE;
   202     } else {
   203         return gdrom_drive.disc->disc_type | IDE_DISC_READY;
   204     }
   205 }
   207 cdrom_error_t gdrom_play_audio( cdrom_lba_t lba, cdrom_count_t count )
   208 {
   209     CHECK_DISC();
   210     if( gdrom_drive.disc->play_audio ) {
   211         return gdrom_drive.disc->play_audio( gdrom_drive.disc, lba - GDROM_LBA_OFFSET, count );
   212     }
   213     return CDROM_ERROR_BADFIELD;
   214 }
   216 /* Parse CD read */
   217 #define READ_CD_MODE(x)    ((x)&0x0E)
   218 #define READ_CD_MODE_ANY   0x00
   219 #define READ_CD_MODE_CDDA  0x02
   220 #define READ_CD_MODE_1     0x04
   221 #define READ_CD_MODE_2     0x06
   222 #define READ_CD_MODE_2_FORM_1 0x08
   223 #define READ_CD_MODE_2_FORM_2 0x0A
   225 #define READ_CD_CHANNELS(x) ((x)&0xF0)
   226 #define READ_CD_HEADER(x)  ((x)&0x80)
   227 #define READ_CD_SUBHEAD(x) ((x)&0x40)
   228 #define READ_CD_DATA(x)    ((x)&0x20)
   229 #define READ_CD_RAW(x)     ((x)&0x10)
   232 cdrom_error_t gdrom_read_cd( cdrom_lba_t lba, cdrom_count_t count,
   233                              unsigned mode, unsigned char *buf, size_t *length )
   234 {
   235     cdrom_lba_t real_lba = lba - 150;
   236     cdrom_read_mode_t real_mode = 0;
   238     CHECK_DISC();
   240     /* Translate GDROM read mode into standard MMC read mode */
   241     if( READ_CD_RAW(mode) ) {
   242         real_mode = CDROM_READ_RAW;
   243     } else {
   244         if( READ_CD_HEADER(mode) ) {
   245             real_mode = CDROM_READ_HEADER|CDROM_READ_SYNC;
   246         }
   247         if( READ_CD_SUBHEAD(mode) ) {
   248             real_mode |= CDROM_READ_SUBHEADER;
   249         }
   250         if( READ_CD_DATA(mode) ) {
   251             real_mode |= CDROM_READ_DATA;
   252         }
   253     }
   255     if( READ_CD_MODE(mode) == 0x0C )
   256         real_mode |= CDROM_READ_MODE2;
   257     else
   258         real_mode |= (READ_CD_MODE(mode)<<1);
   260     return cdrom_disc_read_sectors( gdrom_drive.disc, real_lba, count, real_mode, buf, length );
   261 }
   263 void gdrom_run_slice( uint32_t nanosecs )
   264 {
   266 }
   269 cdrom_track_t gdrom_disc_get_boot_track( cdrom_disc_t disc ) {
   270     int i, boot_track = -1;
   271     if( disc != NULL && disc->track_count > 0 ) {
   272         int last_session = disc->track[disc->track_count-1].sessionno;
   273         if( last_session == 1 )
   274             return NULL;
   275         for( i=disc->track_count-1; i>=0 && disc->track[i].sessionno == last_session; i-- ) {
   276             if( disc->track[i].flags & TRACK_FLAG_DATA ) {
   277                 boot_track = i;
   278             }
   279         }
   280     }
   281     return &disc->track[boot_track];
   282 }
   284 /**
   285  * Check the disc for a useable DC bootstrap, and update the disc
   286  * with the title accordingly. Otherwise set the title to the empty string.
   287  * @return TRUE if we found a bootstrap, otherwise FALSE.
   288  */
   289 gboolean gdrom_disc_read_title( cdrom_disc_t disc, char *title, size_t titlelen ) {
   290     cdrom_track_t boot_track = gdrom_disc_get_boot_track(disc);
   291     int i;
   292     if( boot_track != NULL ) {
   293         unsigned char boot_sector[CDROM_MAX_SECTOR_SIZE];
   294         size_t length = sizeof(boot_sector);
   295         if( cdrom_disc_read_sectors( disc, boot_track->lba, 1, CDROM_READ_DATA|CDROM_READ_MODE2_FORM1,
   296                 boot_sector, &length ) == CDROM_ERROR_OK ) {
   297             if( memcmp( boot_sector, "SEGA SEGAKATANA SEGA ENTERPRISES", 32) == 0 ) {
   298                 /* Got magic */
   299                 dc_bootstrap_head_t bootstrap = (dc_bootstrap_head_t)boot_sector;
   300                 for( i=128; i>0; i-- ) {
   301                     if( !isspace(bootstrap->product_name[i-1]) )
   302                         break;
   303                 }
   304                 if( i >= titlelen )
   305                     i = (titlelen-1);
   306                 memcpy( title, bootstrap->product_name, i );
   307                 title[i] = '\0';
   308             }
   309             bootstrap_dump(boot_sector, FALSE);
   310             return TRUE;
   311         }
   312     }
   313     title[0] = '\0';
   314     return FALSE;
   315 }
.