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