Search
lxdream.org :: lxdream/src/gdrom/gdrom.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/gdrom.c
changeset 1023:264e2fd90be8
prev837:4eae2ddccf9c
next1074:397d77b6e346
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@138
     1
/**
nkeynes@561
     2
 * $Id$
nkeynes@138
     3
 *
nkeynes@138
     4
 * GD-Rom  access functions.
nkeynes@138
     5
 *
nkeynes@138
     6
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@138
     7
 *
nkeynes@138
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@138
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@138
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@138
    11
 * (at your option) any later version.
nkeynes@138
    12
 *
nkeynes@138
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@138
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@138
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@138
    16
 * GNU General Public License for more details.
nkeynes@138
    17
 */
nkeynes@138
    18
nkeynes@138
    19
#include <stdio.h>
nkeynes@237
    20
#include <fcntl.h>
nkeynes@168
    21
#include <errno.h>
nkeynes@1023
    22
#include <ctype.h>
nkeynes@678
    23
#include <glib/gutils.h>
nkeynes@138
    24
#include "gdrom/ide.h"
nkeynes@138
    25
#include "gdrom/gdrom.h"
nkeynes@678
    26
#include "gdrom/gddriver.h"
nkeynes@143
    27
#include "gdrom/packet.h"
nkeynes@138
    28
#include "dream.h"
nkeynes@1023
    29
#include "bootstrap.h"
nkeynes@138
    30
nkeynes@342
    31
extern gdrom_disc_t gdrom_disc;
nkeynes@138
    32
nkeynes@678
    33
DEFINE_HOOK( gdrom_disc_change_hook, gdrom_disc_change_hook_t )
nkeynes@678
    34
nkeynes@759
    35
static void gdrom_fire_disc_changed( gdrom_disc_t disc )
nkeynes@678
    36
{
nkeynes@678
    37
    CALL_HOOKS( gdrom_disc_change_hook, disc, disc == NULL ? NULL : disc->name );
nkeynes@678
    38
}
nkeynes@678
    39
nkeynes@644
    40
char *gdrom_mode_names[] = { "Mode 0", "Mode 1", "Mode 2", "Mode 2 Form 1", "Mode 2 Form 2", "Audio", 
nkeynes@736
    41
        "Mode 2 semiraw", "XA Raw", "Non-XA Raw" };
nkeynes@644
    42
uint32_t gdrom_sector_size[] = { 0, 2048, 2336, 2048, 2324, 2352, 2336, 2352, 2352 };
nkeynes@138
    43
nkeynes@1023
    44
nkeynes@1023
    45
gdrom_device_t gdrom_device_new( const gchar *name, const gchar *dev_name )
nkeynes@138
    46
{
nkeynes@1023
    47
    struct gdrom_device *dev = g_malloc0( sizeof(struct gdrom_device) );
nkeynes@1023
    48
    dev->name = g_strdup(name);
nkeynes@1023
    49
    dev->device_name = g_strdup(dev_name);
nkeynes@1023
    50
    return dev;
nkeynes@1023
    51
}
nkeynes@168
    52
nkeynes@1023
    53
void gdrom_device_destroy( gdrom_device_t dev )
nkeynes@1023
    54
{
nkeynes@1023
    55
    if( dev->name != NULL ) {
nkeynes@1023
    56
        g_free( dev->name );
nkeynes@1023
    57
        dev->name = NULL;
nkeynes@709
    58
    }
nkeynes@1023
    59
    if( dev->device_name != NULL ) {
nkeynes@1023
    60
        g_free( dev->device_name );
nkeynes@1023
    61
        dev->device_name = NULL;
nkeynes@168
    62
    }
nkeynes@1023
    63
    g_free( dev );
nkeynes@138
    64
}
nkeynes@138
    65
nkeynes@138
    66
void gdrom_mount_disc( gdrom_disc_t disc ) 
nkeynes@138
    67
{
nkeynes@678
    68
    if( disc != gdrom_disc ) {
nkeynes@695
    69
        if( gdrom_disc != NULL ) {
nkeynes@1023
    70
            gdrom_disc->destroy(gdrom_disc,TRUE);
nkeynes@695
    71
        }
nkeynes@678
    72
        gdrom_disc = disc;
nkeynes@1023
    73
        gdrom_disc_read_title( disc );
nkeynes@678
    74
        gdrom_fire_disc_changed( disc );
nkeynes@678
    75
    }
nkeynes@138
    76
}
nkeynes@138
    77
nkeynes@433
    78
gboolean gdrom_mount_image( const gchar *filename )
nkeynes@138
    79
{
nkeynes@138
    80
    gdrom_disc_t disc = gdrom_image_open(filename);
nkeynes@695
    81
    if( disc != NULL ) {         
nkeynes@678
    82
        gdrom_mount_disc( disc );
nkeynes@678
    83
        return TRUE;
nkeynes@433
    84
    }
nkeynes@433
    85
    return FALSE;
nkeynes@138
    86
}
nkeynes@138
    87
nkeynes@138
    88
void gdrom_unmount_disc( ) 
nkeynes@138
    89
{
nkeynes@138
    90
    if( gdrom_disc != NULL ) {
nkeynes@1023
    91
        gdrom_disc->destroy(gdrom_disc, TRUE);
nkeynes@678
    92
        gdrom_fire_disc_changed(NULL);
nkeynes@691
    93
        gdrom_disc = NULL;
nkeynes@138
    94
    }
nkeynes@138
    95
}
nkeynes@138
    96
nkeynes@464
    97
gdrom_disc_t gdrom_get_current_disc()
nkeynes@464
    98
{
nkeynes@464
    99
    return gdrom_disc;
nkeynes@464
   100
}
nkeynes@613
   101
nkeynes@678
   102
const gchar *gdrom_get_current_disc_name()
nkeynes@678
   103
{
nkeynes@678
   104
    if( gdrom_disc == NULL ) {
nkeynes@678
   105
        return NULL;
nkeynes@678
   106
    } else {
nkeynes@678
   107
        return gdrom_disc->name;
nkeynes@678
   108
    }
nkeynes@678
   109
}
nkeynes@678
   110
nkeynes@837
   111
const gchar *gdrom_get_current_disc_title()
nkeynes@837
   112
{
nkeynes@837
   113
    if( gdrom_disc == NULL || gdrom_disc->title[0] == '\0' ) {
nkeynes@837
   114
        return NULL;
nkeynes@837
   115
    } else {
nkeynes@837
   116
        return gdrom_disc->title;
nkeynes@837
   117
    }
nkeynes@837
   118
}
nkeynes@837
   119
nkeynes@1023
   120
int gdrom_disc_get_track_by_lba( gdrom_disc_t disc, uint32_t lba )
nkeynes@613
   121
{
nkeynes@1023
   122
    int i;	
nkeynes@1023
   123
    for( i=0; i<disc->track_count; i++ ) {
nkeynes@1023
   124
        if( disc->track[i].lba <= lba && 
nkeynes@1023
   125
                lba < (disc->track[i].lba + disc->track[i].sector_count) ) {
nkeynes@1023
   126
            return i+1;
nkeynes@1023
   127
        }
nkeynes@1023
   128
    }
nkeynes@1023
   129
    return -1;
nkeynes@613
   130
}
nkeynes@837
   131
nkeynes@1023
   132
#define CHECK_DISC(disc) do { \
nkeynes@1023
   133
	    if( disc == NULL ) { return PKT_ERR_NODISC; } \
nkeynes@1023
   134
	    disc->check_status(disc); \
nkeynes@1023
   135
	    if( disc->disc_type == IDE_DISC_NONE ) { return PKT_ERR_NODISC; } \
nkeynes@1023
   136
    } while(0)
nkeynes@1023
   137
nkeynes@1023
   138
gdrom_error_t gdrom_disc_check_media( gdrom_disc_t disc )
nkeynes@1023
   139
{
nkeynes@1023
   140
	CHECK_DISC(disc);
nkeynes@1023
   141
	return PKT_ERR_OK;
nkeynes@1023
   142
}
nkeynes@1023
   143
nkeynes@1023
   144
gdrom_error_t gdrom_disc_get_toc( gdrom_disc_t disc, unsigned char *buf ) 
nkeynes@1023
   145
{
nkeynes@1023
   146
	struct gdrom_toc {
nkeynes@1023
   147
	    uint32_t track[99];
nkeynes@1023
   148
	    uint32_t first, last, leadout;
nkeynes@1023
   149
	};
nkeynes@1023
   150
	
nkeynes@1023
   151
    struct gdrom_toc *toc = (struct gdrom_toc *)buf;
nkeynes@1023
   152
    int i;
nkeynes@1023
   153
    
nkeynes@1023
   154
    CHECK_DISC(disc);
nkeynes@1023
   155
nkeynes@1023
   156
    for( i=0; i<disc->track_count; i++ ) {
nkeynes@1023
   157
        toc->track[i] = htonl( disc->track[i].lba ) | disc->track[i].flags;
nkeynes@1023
   158
    }
nkeynes@1023
   159
    toc->first = 0x0100 | disc->track[0].flags;
nkeynes@1023
   160
    toc->last = (disc->track_count<<8) | disc->track[i-1].flags;
nkeynes@1023
   161
    toc->leadout = htonl(disc->track[i-1].lba + disc->track[i-1].sector_count) |
nkeynes@1023
   162
    disc->track[i-1].flags;
nkeynes@1023
   163
    for( ;i<99; i++ )
nkeynes@1023
   164
        toc->track[i] = 0xFFFFFFFF;
nkeynes@1023
   165
    return PKT_ERR_OK;
nkeynes@1023
   166
}
nkeynes@1023
   167
nkeynes@1023
   168
gdrom_error_t gdrom_disc_get_session_info( gdrom_disc_t disc, int session, unsigned char *buf )
nkeynes@1023
   169
{
nkeynes@1023
   170
	CHECK_DISC(disc);
nkeynes@1023
   171
	
nkeynes@1023
   172
    struct gdrom_track *last_track = &disc->track[disc->track_count-1];
nkeynes@1023
   173
    unsigned int end_of_disc = last_track->lba + last_track->sector_count;
nkeynes@1023
   174
    int i;
nkeynes@1023
   175
    buf[0] = 0x01; /* Disc status? */
nkeynes@1023
   176
    buf[1] = 0;
nkeynes@1023
   177
nkeynes@1023
   178
    if( session == 0 ) {
nkeynes@1023
   179
        buf[2] = last_track->session+1; /* last session */
nkeynes@1023
   180
        buf[3] = (end_of_disc >> 16) & 0xFF;
nkeynes@1023
   181
        buf[4] = (end_of_disc >> 8) & 0xFF;
nkeynes@1023
   182
        buf[5] = end_of_disc & 0xFF;
nkeynes@1023
   183
        return PKT_ERR_OK;
nkeynes@1023
   184
    } else {
nkeynes@1023
   185
        session--;
nkeynes@1023
   186
        for( i=0; i<disc->track_count; i++ ) {
nkeynes@1023
   187
            if( disc->track[i].session == session ) {
nkeynes@1023
   188
                buf[2] = i+1; /* first track of session */
nkeynes@1023
   189
                buf[3] = (disc->track[i].lba >> 16) & 0xFF;
nkeynes@1023
   190
                buf[4] = (disc->track[i].lba >> 8) & 0xFF;
nkeynes@1023
   191
                buf[5] = disc->track[i].lba & 0xFF;
nkeynes@1023
   192
                return PKT_ERR_OK;
nkeynes@1023
   193
            }
nkeynes@1023
   194
        }
nkeynes@1023
   195
        return PKT_ERR_BADFIELD; /* No such session */
nkeynes@1023
   196
    }
nkeynes@1023
   197
}
nkeynes@1023
   198
nkeynes@1023
   199
gdrom_error_t gdrom_disc_get_short_status( gdrom_disc_t disc, uint32_t lba, unsigned char *buf )
nkeynes@1023
   200
{
nkeynes@1023
   201
	CHECK_DISC(disc);
nkeynes@1023
   202
	
nkeynes@1023
   203
    int track_no = gdrom_disc_get_track_by_lba( disc, lba );
nkeynes@1023
   204
    if( track_no == -1 ) {
nkeynes@1023
   205
        track_no = 1;
nkeynes@1023
   206
        lba = 150;
nkeynes@1023
   207
    }
nkeynes@1023
   208
    struct gdrom_track *track = &disc->track[track_no-1];
nkeynes@1023
   209
    uint32_t offset = lba - track->lba;
nkeynes@1023
   210
	buf[0] = 0x00;
nkeynes@1023
   211
	buf[1] = 0x15; /* audio status ? */
nkeynes@1023
   212
    buf[2] = 0x00;
nkeynes@1023
   213
    buf[3] = 0x0E;
nkeynes@1023
   214
    buf[4] = track->flags;
nkeynes@1023
   215
    buf[5] = track_no;
nkeynes@1023
   216
    buf[6] = 0x01; /* ?? */
nkeynes@1023
   217
    buf[7] = (offset >> 16) & 0xFF;
nkeynes@1023
   218
    buf[8] = (offset >> 8) & 0xFF;
nkeynes@1023
   219
    buf[9] = offset & 0xFF;
nkeynes@1023
   220
    buf[10] = 0;
nkeynes@1023
   221
    buf[11] = (lba >> 16) & 0xFF;
nkeynes@1023
   222
    buf[12] = (lba >> 8) & 0xFF;
nkeynes@1023
   223
    buf[13] = lba & 0xFF;
nkeynes@1023
   224
    return PKT_ERR_OK;
nkeynes@1023
   225
}
nkeynes@1023
   226
nkeynes@1023
   227
int gdrom_disc_get_drive_status( gdrom_disc_t disc ) 
nkeynes@1023
   228
{
nkeynes@1023
   229
	if( disc == NULL ) {
nkeynes@1023
   230
		return IDE_DISC_NONE;
nkeynes@1023
   231
	}
nkeynes@1023
   232
	
nkeynes@1023
   233
	disc->check_status(disc);
nkeynes@1023
   234
    if( disc->disc_type == IDE_DISC_NONE ) {
nkeynes@1023
   235
        return IDE_DISC_NONE;
nkeynes@1023
   236
    } else {
nkeynes@1023
   237
        return disc->disc_type | IDE_DISC_READY;
nkeynes@1023
   238
    }
nkeynes@1023
   239
}
nkeynes@1023
   240
nkeynes@1023
   241
/**
nkeynes@1023
   242
 * Check the disc for a useable DC bootstrap, and update the disc
nkeynes@1023
   243
 * with the title accordingly.
nkeynes@1023
   244
 * @return TRUE if we found a bootstrap, otherwise FALSE.
nkeynes@1023
   245
 */
nkeynes@1023
   246
gboolean gdrom_disc_read_title( gdrom_disc_t disc ) {
nkeynes@1023
   247
    if( disc->track_count > 0 ) {
nkeynes@1023
   248
        /* Find the first data track of the last session */
nkeynes@1023
   249
        int last_session = disc->track[disc->track_count-1].session;
nkeynes@1023
   250
        int i, boot_track = -1;
nkeynes@1023
   251
        for( i=disc->track_count-1; i>=0 && disc->track[i].session == last_session; i-- ) {
nkeynes@1023
   252
            if( disc->track[i].flags & TRACK_DATA ) {
nkeynes@1023
   253
                boot_track = i;
nkeynes@1023
   254
            }
nkeynes@1023
   255
        }
nkeynes@1023
   256
        if( boot_track != -1 ) {
nkeynes@1023
   257
            unsigned char boot_sector[MAX_SECTOR_SIZE];
nkeynes@1023
   258
            uint32_t length = sizeof(boot_sector);
nkeynes@1023
   259
            if( disc->read_sector( disc, disc->track[boot_track].lba, 0x28,
nkeynes@1023
   260
                    boot_sector, &length ) == PKT_ERR_OK ) {
nkeynes@1023
   261
                if( memcmp( boot_sector, "SEGA SEGAKATANA SEGA ENTERPRISES", 32) == 0 ) {
nkeynes@1023
   262
                    /* Got magic */
nkeynes@1023
   263
                    memcpy( disc->title, boot_sector+128, 128 );
nkeynes@1023
   264
                    for( i=127; i>=0; i-- ) {
nkeynes@1023
   265
                        if( !isspace(disc->title[i]) ) 
nkeynes@1023
   266
                            break;
nkeynes@1023
   267
                    }
nkeynes@1023
   268
                    disc->title[i+1] = '\0';
nkeynes@1023
   269
                }
nkeynes@1023
   270
                bootstrap_dump(boot_sector, FALSE);
nkeynes@1023
   271
                return TRUE;
nkeynes@1023
   272
            }
nkeynes@1023
   273
        }
nkeynes@1023
   274
    }
nkeynes@1023
   275
    return FALSE;
nkeynes@1023
   276
}
.