Search
lxdream.org :: lxdream/src/gdrom/gdrom.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/gdrom.c
changeset 1074:397d77b6e346
prev1023:264e2fd90be8
next1097:d4807997e450
author nkeynes
date Wed Oct 07 17:53:56 2009 +1000 (14 years ago)
permissions -rw-r--r--
last change Create a host attachment for the SCIF serial port. By default, uses /dev/console
Add general fd listening to netutil, and rename to ioutil
Add SCIF update on port read/write - fixes KOS timing problems but needs to
be redone properly.
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 <fcntl.h>
    21 #include <errno.h>
    22 #include <ctype.h>
    23 #include <glib/gutils.h>
    24 #include <netinet/in.h>
    25 #include "gdrom/ide.h"
    26 #include "gdrom/gdrom.h"
    27 #include "gdrom/gddriver.h"
    28 #include "gdrom/packet.h"
    29 #include "dream.h"
    30 #include "bootstrap.h"
    32 extern gdrom_disc_t gdrom_disc;
    34 DEFINE_HOOK( gdrom_disc_change_hook, gdrom_disc_change_hook_t )
    36 static void gdrom_fire_disc_changed( gdrom_disc_t disc )
    37 {
    38     CALL_HOOKS( gdrom_disc_change_hook, disc, disc == NULL ? NULL : disc->name );
    39 }
    41 char *gdrom_mode_names[] = { "Mode 0", "Mode 1", "Mode 2", "Mode 2 Form 1", "Mode 2 Form 2", "Audio", 
    42         "Mode 2 semiraw", "XA Raw", "Non-XA Raw" };
    43 uint32_t gdrom_sector_size[] = { 0, 2048, 2336, 2048, 2324, 2352, 2336, 2352, 2352 };
    46 gdrom_device_t gdrom_device_new( const gchar *name, const gchar *dev_name )
    47 {
    48     struct gdrom_device *dev = g_malloc0( sizeof(struct gdrom_device) );
    49     dev->name = g_strdup(name);
    50     dev->device_name = g_strdup(dev_name);
    51     return dev;
    52 }
    54 void gdrom_device_destroy( gdrom_device_t dev )
    55 {
    56     if( dev->name != NULL ) {
    57         g_free( dev->name );
    58         dev->name = NULL;
    59     }
    60     if( dev->device_name != NULL ) {
    61         g_free( dev->device_name );
    62         dev->device_name = NULL;
    63     }
    64     g_free( dev );
    65 }
    67 void gdrom_mount_disc( gdrom_disc_t disc ) 
    68 {
    69     if( disc != gdrom_disc ) {
    70         if( gdrom_disc != NULL ) {
    71             gdrom_disc->destroy(gdrom_disc,TRUE);
    72         }
    73         gdrom_disc = disc;
    74         gdrom_disc_read_title( disc );
    75         gdrom_fire_disc_changed( disc );
    76     }
    77 }
    79 gboolean gdrom_mount_image( const gchar *filename )
    80 {
    81     gdrom_disc_t disc = gdrom_image_open(filename);
    82     if( disc != NULL ) {         
    83         gdrom_mount_disc( disc );
    84         return TRUE;
    85     }
    86     return FALSE;
    87 }
    89 void gdrom_unmount_disc( ) 
    90 {
    91     if( gdrom_disc != NULL ) {
    92         gdrom_disc->destroy(gdrom_disc, TRUE);
    93         gdrom_fire_disc_changed(NULL);
    94         gdrom_disc = NULL;
    95     }
    96 }
    98 gdrom_disc_t gdrom_get_current_disc()
    99 {
   100     return gdrom_disc;
   101 }
   103 const gchar *gdrom_get_current_disc_name()
   104 {
   105     if( gdrom_disc == NULL ) {
   106         return NULL;
   107     } else {
   108         return gdrom_disc->name;
   109     }
   110 }
   112 const gchar *gdrom_get_current_disc_title()
   113 {
   114     if( gdrom_disc == NULL || gdrom_disc->title[0] == '\0' ) {
   115         return NULL;
   116     } else {
   117         return gdrom_disc->title;
   118     }
   119 }
   121 int gdrom_disc_get_track_by_lba( gdrom_disc_t disc, uint32_t lba )
   122 {
   123     int i;	
   124     for( i=0; i<disc->track_count; i++ ) {
   125         if( disc->track[i].lba <= lba && 
   126                 lba < (disc->track[i].lba + disc->track[i].sector_count) ) {
   127             return i+1;
   128         }
   129     }
   130     return -1;
   131 }
   133 #define CHECK_DISC(disc) do { \
   134 	    if( disc == NULL ) { return PKT_ERR_NODISC; } \
   135 	    disc->check_status(disc); \
   136 	    if( disc->disc_type == IDE_DISC_NONE ) { return PKT_ERR_NODISC; } \
   137     } while(0)
   139 gdrom_error_t gdrom_disc_check_media( gdrom_disc_t disc )
   140 {
   141 	CHECK_DISC(disc);
   142 	return PKT_ERR_OK;
   143 }
   145 gdrom_error_t gdrom_disc_get_toc( gdrom_disc_t disc, unsigned char *buf ) 
   146 {
   147 	struct gdrom_toc {
   148 	    uint32_t track[99];
   149 	    uint32_t first, last, leadout;
   150 	};
   152     struct gdrom_toc *toc = (struct gdrom_toc *)buf;
   153     int i;
   155     CHECK_DISC(disc);
   157     for( i=0; i<disc->track_count; i++ ) {
   158         toc->track[i] = htonl( disc->track[i].lba ) | disc->track[i].flags;
   159     }
   160     toc->first = 0x0100 | disc->track[0].flags;
   161     toc->last = (disc->track_count<<8) | disc->track[i-1].flags;
   162     toc->leadout = htonl(disc->track[i-1].lba + disc->track[i-1].sector_count) |
   163     disc->track[i-1].flags;
   164     for( ;i<99; i++ )
   165         toc->track[i] = 0xFFFFFFFF;
   166     return PKT_ERR_OK;
   167 }
   169 gdrom_error_t gdrom_disc_get_session_info( gdrom_disc_t disc, int session, unsigned char *buf )
   170 {
   171 	CHECK_DISC(disc);
   173     struct gdrom_track *last_track = &disc->track[disc->track_count-1];
   174     unsigned int end_of_disc = last_track->lba + last_track->sector_count;
   175     int i;
   176     buf[0] = 0x01; /* Disc status? */
   177     buf[1] = 0;
   179     if( session == 0 ) {
   180         buf[2] = last_track->session+1; /* last session */
   181         buf[3] = (end_of_disc >> 16) & 0xFF;
   182         buf[4] = (end_of_disc >> 8) & 0xFF;
   183         buf[5] = end_of_disc & 0xFF;
   184         return PKT_ERR_OK;
   185     } else {
   186         session--;
   187         for( i=0; i<disc->track_count; i++ ) {
   188             if( disc->track[i].session == session ) {
   189                 buf[2] = i+1; /* first track of session */
   190                 buf[3] = (disc->track[i].lba >> 16) & 0xFF;
   191                 buf[4] = (disc->track[i].lba >> 8) & 0xFF;
   192                 buf[5] = disc->track[i].lba & 0xFF;
   193                 return PKT_ERR_OK;
   194             }
   195         }
   196         return PKT_ERR_BADFIELD; /* No such session */
   197     }
   198 }
   200 gdrom_error_t gdrom_disc_get_short_status( gdrom_disc_t disc, uint32_t lba, unsigned char *buf )
   201 {
   202 	CHECK_DISC(disc);
   204     int track_no = gdrom_disc_get_track_by_lba( disc, lba );
   205     if( track_no == -1 ) {
   206         track_no = 1;
   207         lba = 150;
   208     }
   209     struct gdrom_track *track = &disc->track[track_no-1];
   210     uint32_t offset = lba - track->lba;
   211 	buf[0] = 0x00;
   212 	buf[1] = 0x15; /* audio status ? */
   213     buf[2] = 0x00;
   214     buf[3] = 0x0E;
   215     buf[4] = track->flags;
   216     buf[5] = track_no;
   217     buf[6] = 0x01; /* ?? */
   218     buf[7] = (offset >> 16) & 0xFF;
   219     buf[8] = (offset >> 8) & 0xFF;
   220     buf[9] = offset & 0xFF;
   221     buf[10] = 0;
   222     buf[11] = (lba >> 16) & 0xFF;
   223     buf[12] = (lba >> 8) & 0xFF;
   224     buf[13] = lba & 0xFF;
   225     return PKT_ERR_OK;
   226 }
   228 int gdrom_disc_get_drive_status( gdrom_disc_t disc ) 
   229 {
   230 	if( disc == NULL ) {
   231 		return IDE_DISC_NONE;
   232 	}
   234 	disc->check_status(disc);
   235     if( disc->disc_type == IDE_DISC_NONE ) {
   236         return IDE_DISC_NONE;
   237     } else {
   238         return disc->disc_type | IDE_DISC_READY;
   239     }
   240 }
   242 /**
   243  * Check the disc for a useable DC bootstrap, and update the disc
   244  * with the title accordingly.
   245  * @return TRUE if we found a bootstrap, otherwise FALSE.
   246  */
   247 gboolean gdrom_disc_read_title( gdrom_disc_t disc ) {
   248     if( disc->track_count > 0 ) {
   249         /* Find the first data track of the last session */
   250         int last_session = disc->track[disc->track_count-1].session;
   251         int i, boot_track = -1;
   252         for( i=disc->track_count-1; i>=0 && disc->track[i].session == last_session; i-- ) {
   253             if( disc->track[i].flags & TRACK_DATA ) {
   254                 boot_track = i;
   255             }
   256         }
   257         if( boot_track != -1 ) {
   258             unsigned char boot_sector[MAX_SECTOR_SIZE];
   259             uint32_t length = sizeof(boot_sector);
   260             if( disc->read_sector( disc, disc->track[boot_track].lba, 0x28,
   261                     boot_sector, &length ) == PKT_ERR_OK ) {
   262                 if( memcmp( boot_sector, "SEGA SEGAKATANA SEGA ENTERPRISES", 32) == 0 ) {
   263                     /* Got magic */
   264                     memcpy( disc->title, boot_sector+128, 128 );
   265                     for( i=127; i>=0; i-- ) {
   266                         if( !isspace(disc->title[i]) ) 
   267                             break;
   268                     }
   269                     disc->title[i+1] = '\0';
   270                 }
   271                 bootstrap_dump(boot_sector, FALSE);
   272                 return TRUE;
   273             }
   274         }
   275     }
   276     return FALSE;
   277 }
.