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