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 Sun Jan 31 18:35:06 2010 +1000 (12 years ago)
permissions -rw-r--r--
last change Refactor CDROM host support
- Completely separate GDROM hardware (in gdrom/gdrom.c) from generic CDROM
support (now in drivers/cdrom)
- Add concept of 'sector sources' that can be mixed and matched to create
cdrom discs (makes support of arbitrary disc types much simpler)
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 {
nkeynes@1023
   116
	    uint32_t track[99];
nkeynes@1023
   117
	    uint32_t first, last, leadout;
nkeynes@1023
   118
	};
nkeynes@1023
   119
	
nkeynes@1023
   120
    struct gdrom_toc *toc = (struct gdrom_toc *)buf;
nkeynes@1023
   121
    int i;
nkeynes@1023
   122
    
nkeynes@1097
   123
    CHECK_DISC();
nkeynes@1097
   124
    cdrom_disc_t disc = gdrom_drive.disc;
nkeynes@1023
   125
nkeynes@1023
   126
    for( i=0; i<disc->track_count; i++ ) {
nkeynes@1097
   127
        toc->track[i] = htonl( disc->track[i].lba+GDROM_LBA_OFFSET ) | disc->track[i].flags;
nkeynes@1023
   128
    }
nkeynes@1023
   129
    toc->first = 0x0100 | disc->track[0].flags;
nkeynes@1023
   130
    toc->last = (disc->track_count<<8) | disc->track[i-1].flags;
nkeynes@1097
   131
    toc->leadout = htonl(disc->leadout+GDROM_LBA_OFFSET) |
nkeynes@1023
   132
    disc->track[i-1].flags;
nkeynes@1023
   133
    for( ;i<99; i++ )
nkeynes@1023
   134
        toc->track[i] = 0xFFFFFFFF;
nkeynes@1023
   135
    return PKT_ERR_OK;
nkeynes@1023
   136
}
nkeynes@1023
   137
nkeynes@1097
   138
cdrom_error_t gdrom_read_session( int session, unsigned char *buf )
nkeynes@1023
   139
{
nkeynes@1097
   140
    cdrom_lba_t lba;
nkeynes@1097
   141
	CHECK_DISC();
nkeynes@1023
   142
	
nkeynes@1023
   143
    buf[0] = 0x01; /* Disc status? */
nkeynes@1023
   144
    buf[1] = 0;
nkeynes@1023
   145
nkeynes@1097
   146
nkeynes@1023
   147
    if( session == 0 ) {
nkeynes@1097
   148
        buf[2] = gdrom_drive.disc->session_count;
nkeynes@1097
   149
        lba = gdrom_drive.disc->leadout + GDROM_LBA_OFFSET;
nkeynes@1023
   150
    } else {
nkeynes@1097
   151
        cdrom_track_t track = cdrom_disc_get_session( gdrom_drive.disc, session );
nkeynes@1097
   152
        if( track == NULL )
nkeynes@1097
   153
            return CDROM_ERROR_BADFIELD;
nkeynes@1097
   154
nkeynes@1097
   155
        buf[2] = track->trackno;
nkeynes@1097
   156
        lba = track->lba + GDROM_LBA_OFFSET;
nkeynes@1023
   157
    }
nkeynes@1097
   158
    buf[3] = (lba >> 16) & 0xFF;
nkeynes@1097
   159
    buf[4] = (lba >> 8) & 0xFF;
nkeynes@1097
   160
    buf[5] = lba & 0xFF;
nkeynes@1097
   161
    return CDROM_ERROR_OK;
nkeynes@1023
   162
}
nkeynes@1023
   163
nkeynes@1097
   164
cdrom_error_t gdrom_read_short_status( cdrom_lba_t lba, unsigned char *buf )
nkeynes@1023
   165
{
nkeynes@1097
   166
    cdrom_lba_t real_lba = lba - GDROM_LBA_OFFSET;
nkeynes@1097
   167
	CHECK_DISC();
nkeynes@1023
   168
	
nkeynes@1097
   169
    cdrom_track_t track = cdrom_disc_get_track_by_lba( gdrom_drive.disc, real_lba );
nkeynes@1097
   170
    if( track == NULL ) {
nkeynes@1097
   171
        track = cdrom_disc_get_track( gdrom_drive.disc, 1 );
nkeynes@1097
   172
        if( track == NULL )
nkeynes@1097
   173
            return CDROM_ERROR_NODISC;
nkeynes@1023
   174
        lba = 150;
nkeynes@1023
   175
    }
nkeynes@1097
   176
    uint32_t offset = real_lba - track->lba;
nkeynes@1023
   177
	buf[0] = 0x00;
nkeynes@1023
   178
	buf[1] = 0x15; /* audio status ? */
nkeynes@1023
   179
    buf[2] = 0x00;
nkeynes@1023
   180
    buf[3] = 0x0E;
nkeynes@1023
   181
    buf[4] = track->flags;
nkeynes@1097
   182
    buf[5] = track->trackno;
nkeynes@1023
   183
    buf[6] = 0x01; /* ?? */
nkeynes@1023
   184
    buf[7] = (offset >> 16) & 0xFF;
nkeynes@1023
   185
    buf[8] = (offset >> 8) & 0xFF;
nkeynes@1023
   186
    buf[9] = offset & 0xFF;
nkeynes@1023
   187
    buf[10] = 0;
nkeynes@1023
   188
    buf[11] = (lba >> 16) & 0xFF;
nkeynes@1023
   189
    buf[12] = (lba >> 8) & 0xFF;
nkeynes@1023
   190
    buf[13] = lba & 0xFF;
nkeynes@1023
   191
    return PKT_ERR_OK;
nkeynes@1023
   192
}
nkeynes@1023
   193
nkeynes@1097
   194
int gdrom_get_drive_status( )
nkeynes@1023
   195
{
nkeynes@1097
   196
	if( gdrom_drive.disc == NULL ) {
nkeynes@1097
   197
		return CDROM_DISC_NONE;
nkeynes@1023
   198
	}
nkeynes@1023
   199
	
nkeynes@1097
   200
    if( cdrom_disc_check_media(gdrom_drive.disc) == CDROM_DISC_NONE ) {
nkeynes@1097
   201
        return CDROM_DISC_NONE;
nkeynes@1023
   202
    } else {
nkeynes@1097
   203
        return gdrom_drive.disc->disc_type | IDE_DISC_READY;
nkeynes@1023
   204
    }
nkeynes@1023
   205
}
nkeynes@1023
   206
nkeynes@1097
   207
cdrom_error_t gdrom_play_audio( cdrom_lba_t lba, cdrom_count_t count )
nkeynes@1097
   208
{
nkeynes@1097
   209
    CHECK_DISC();
nkeynes@1097
   210
    if( gdrom_drive.disc->play_audio ) {
nkeynes@1097
   211
        return gdrom_drive.disc->play_audio( gdrom_drive.disc, lba - GDROM_LBA_OFFSET, count );
nkeynes@1097
   212
    }
nkeynes@1097
   213
    return CDROM_ERROR_BADFIELD;
nkeynes@1097
   214
}
nkeynes@1097
   215
nkeynes@1097
   216
/* Parse CD read */
nkeynes@1097
   217
#define READ_CD_MODE(x)    ((x)&0x0E)
nkeynes@1097
   218
#define READ_CD_MODE_ANY   0x00
nkeynes@1097
   219
#define READ_CD_MODE_CDDA  0x02
nkeynes@1097
   220
#define READ_CD_MODE_1     0x04
nkeynes@1097
   221
#define READ_CD_MODE_2     0x06
nkeynes@1097
   222
#define READ_CD_MODE_2_FORM_1 0x08
nkeynes@1097
   223
#define READ_CD_MODE_2_FORM_2 0x0A
nkeynes@1097
   224
nkeynes@1097
   225
#define READ_CD_CHANNELS(x) ((x)&0xF0)
nkeynes@1097
   226
#define READ_CD_HEADER(x)  ((x)&0x80)
nkeynes@1097
   227
#define READ_CD_SUBHEAD(x) ((x)&0x40)
nkeynes@1097
   228
#define READ_CD_DATA(x)    ((x)&0x20)
nkeynes@1097
   229
#define READ_CD_RAW(x)     ((x)&0x10)
nkeynes@1097
   230
nkeynes@1097
   231
nkeynes@1097
   232
cdrom_error_t gdrom_read_cd( cdrom_lba_t lba, cdrom_count_t count,
nkeynes@1097
   233
                             unsigned mode, unsigned char *buf, size_t *length )
nkeynes@1097
   234
{
nkeynes@1097
   235
    cdrom_lba_t real_lba = lba - 150;
nkeynes@1097
   236
    cdrom_read_mode_t real_mode = 0;
nkeynes@1097
   237
nkeynes@1097
   238
    CHECK_DISC();
nkeynes@1097
   239
nkeynes@1097
   240
    /* Translate GDROM read mode into standard MMC read mode */
nkeynes@1097
   241
    if( READ_CD_RAW(mode) ) {
nkeynes@1097
   242
        real_mode = CDROM_READ_RAW;
nkeynes@1097
   243
    } else {
nkeynes@1097
   244
        if( READ_CD_HEADER(mode) ) {
nkeynes@1097
   245
            real_mode = CDROM_READ_HEADER|CDROM_READ_SYNC;
nkeynes@1097
   246
        }
nkeynes@1097
   247
        if( READ_CD_SUBHEAD(mode) ) {
nkeynes@1097
   248
            real_mode |= CDROM_READ_SUBHEADER;
nkeynes@1097
   249
        }
nkeynes@1097
   250
        if( READ_CD_DATA(mode) ) {
nkeynes@1097
   251
            real_mode |= CDROM_READ_DATA;
nkeynes@1097
   252
        }
nkeynes@1097
   253
    }
nkeynes@1097
   254
nkeynes@1097
   255
    if( READ_CD_MODE(mode) == 0x0C )
nkeynes@1097
   256
        real_mode |= CDROM_READ_MODE2;
nkeynes@1097
   257
    else
nkeynes@1097
   258
        real_mode |= (READ_CD_MODE(mode)<<1);
nkeynes@1097
   259
nkeynes@1097
   260
    return cdrom_disc_read_sectors( gdrom_drive.disc, real_lba, count, real_mode, buf, length );
nkeynes@1097
   261
}
nkeynes@1097
   262
nkeynes@1097
   263
void gdrom_run_slice( uint32_t nanosecs )
nkeynes@1097
   264
{
nkeynes@1097
   265
nkeynes@1097
   266
}
nkeynes@1097
   267
nkeynes@1097
   268
nkeynes@1097
   269
cdrom_track_t gdrom_disc_get_boot_track( cdrom_disc_t disc ) {
nkeynes@1097
   270
    int i, boot_track = -1;
nkeynes@1097
   271
    if( disc != NULL && disc->track_count > 0 ) {
nkeynes@1097
   272
        int last_session = disc->track[disc->track_count-1].sessionno;
nkeynes@1097
   273
        if( last_session == 1 )
nkeynes@1097
   274
            return NULL;
nkeynes@1097
   275
        for( i=disc->track_count-1; i>=0 && disc->track[i].sessionno == last_session; i-- ) {
nkeynes@1097
   276
            if( disc->track[i].flags & TRACK_FLAG_DATA ) {
nkeynes@1097
   277
                boot_track = i;
nkeynes@1097
   278
            }
nkeynes@1097
   279
        }
nkeynes@1097
   280
    }
nkeynes@1097
   281
    return &disc->track[boot_track];
nkeynes@1097
   282
}
nkeynes@1097
   283
nkeynes@1023
   284
/**
nkeynes@1023
   285
 * Check the disc for a useable DC bootstrap, and update the disc
nkeynes@1097
   286
 * with the title accordingly. Otherwise set the title to the empty string.
nkeynes@1023
   287
 * @return TRUE if we found a bootstrap, otherwise FALSE.
nkeynes@1023
   288
 */
nkeynes@1097
   289
gboolean gdrom_disc_read_title( cdrom_disc_t disc, char *title, size_t titlelen ) {
nkeynes@1097
   290
    cdrom_track_t boot_track = gdrom_disc_get_boot_track(disc);
nkeynes@1097
   291
    int i;
nkeynes@1097
   292
    if( boot_track != NULL ) {
nkeynes@1097
   293
        unsigned char boot_sector[CDROM_MAX_SECTOR_SIZE];
nkeynes@1097
   294
        size_t length = sizeof(boot_sector);
nkeynes@1097
   295
        if( cdrom_disc_read_sectors( disc, boot_track->lba, 1, CDROM_READ_DATA|CDROM_READ_MODE2_FORM1,
nkeynes@1097
   296
                boot_sector, &length ) == CDROM_ERROR_OK ) {
nkeynes@1097
   297
            if( memcmp( boot_sector, "SEGA SEGAKATANA SEGA ENTERPRISES", 32) == 0 ) {
nkeynes@1097
   298
                /* Got magic */
nkeynes@1097
   299
                dc_bootstrap_head_t bootstrap = (dc_bootstrap_head_t)boot_sector;
nkeynes@1097
   300
                for( i=128; i>0; i-- ) {
nkeynes@1097
   301
                    if( !isspace(bootstrap->product_name[i-1]) )
nkeynes@1097
   302
                        break;
nkeynes@1097
   303
                }
nkeynes@1097
   304
                if( i >= titlelen )
nkeynes@1097
   305
                    i = (titlelen-1);
nkeynes@1097
   306
                memcpy( title, bootstrap->product_name, i );
nkeynes@1097
   307
                title[i] = '\0';
nkeynes@1023
   308
            }
nkeynes@1097
   309
            bootstrap_dump(boot_sector, FALSE);
nkeynes@1097
   310
            return TRUE;
nkeynes@1023
   311
        }
nkeynes@1023
   312
    }
nkeynes@1097
   313
    title[0] = '\0';
nkeynes@1023
   314
    return FALSE;
nkeynes@1023
   315
}
nkeynes@1097
   316
.