Search
lxdream.org :: lxdream/src/drivers/cd_mmc.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/cd_mmc.c
changeset 1023:264e2fd90be8
next1071:182cfe43c09e
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
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * SCSI/MMC device interface (depends on lower-level SCSI transport)
     5  *
     6  * Copyright (c) 2009 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 <string.h>
    20 #include "lxdream.h"
    21 #include "gettext.h"
    22 #include "gdrom/gddriver.h"
    23 #include "gdrom/packet.h"
    25 #define MAXTOCENTRIES 600  /* This is a fairly generous overestimate really */
    26 #define MAXTOCSIZE 4 + (MAXTOCENTRIES*11)
    27 #define MAX_SECTORS_PER_CALL 1
    29 #define MSFTOLBA( m,s,f ) (f + (s*CD_FRAMES_PER_SECOND) + (m*CD_FRAMES_PER_MINUTE))
    31 static void mmc_make_read_cd_cmd( char *cmd, uint32_t real_sector, int mode )
    32 {
    33     cmd[0] = 0xBE;
    34     cmd[1] = (mode & 0x0E) << 1;
    35     cmd[2] = (real_sector >> 24) & 0xFF;
    36     cmd[3] = (real_sector >> 16) & 0xFF;
    37     cmd[4] = (real_sector >> 8) & 0xFF;
    38     cmd[5] = real_sector & 0xFF;
    39     cmd[6] = 0;
    40     cmd[7] = 0;
    41     cmd[8] = 1;
    42     cmd[9] = 0;
    43     cmd[10]= 0;
    44     cmd[11]= 0;
    46     if( READ_CD_RAW(mode) ) {
    47         cmd[9] = 0xF0;
    48     } else {
    49         if( READ_CD_HEADER(mode) ) {
    50             cmd[9] = 0xA0;
    51         }
    52         if( READ_CD_SUBHEAD(mode) ) {
    53             cmd[9] |= 0x40;
    54         }
    55         if( READ_CD_DATA(mode) ) {
    56             cmd[9] |= 0x10;
    57         }
    58     }
    59 }
    61 /**
    62  * Parse the TOC (format 2) into the gdrom_disc structure
    63  */
    64 void mmc_parse_toc2( gdrom_disc_t disc, unsigned char *buf )
    65 {
    66     int max_track = 0;
    67     int last_track = -1;
    68     int leadout = -1;
    69     int len = (buf[0] << 8) | buf[1];
    70     int session_type = -1;
    71     int i;
    72     for( i = 4; i<len; i+=11 ) {
    73         int session = buf[i];
    74         int adr = buf[i+1] >> 4;
    75         int point = buf[i+3];
    76         if( adr == 0x01 && point > 0 && point < 100 ) {
    77             /* Track info */
    78             int trackno = point-1;
    79             if( point > max_track ) {
    80                 max_track = point;
    81             }
    82             disc->track[trackno].flags = (buf[i+1] & 0x0F) << 4;
    83             disc->track[trackno].session = session - 1;
    84             disc->track[trackno].lba = MSFTOLBA(buf[i+8],buf[i+9],buf[i+10]);
    85             if( disc->track[trackno].flags & TRACK_DATA ) {
    86                 disc->track[trackno].mode = GDROM_MODE1;
    87             } else {
    88                 disc->track[trackno].mode = GDROM_CDDA;
    89             }
    90             if( last_track != -1 ) {
    91                 disc->track[last_track].sector_count = disc->track[trackno].lba -
    92                 disc->track[last_track].lba;
    93             }
    94             last_track = trackno;
    95         } else switch( (adr << 8) | point ) {
    96         case 0x1A0: /* session info */
    97             if( buf[i+9] == 0x20 ) {
    98                 session_type = IDE_DISC_CDROMXA;
    99             } else {
   100                 session_type = IDE_DISC_CDROM;
   101             }
   102             disc->disc_type = session_type;
   103             break;
   104         case 0x1A2: /* leadout */
   105             leadout = MSFTOLBA(buf[i+8], buf[i+9], buf[i+10]);
   106             break;
   107         }
   108     }
   109     disc->track_count = max_track;
   111     if( leadout != -1 && last_track != -1 ) {
   112         disc->track[last_track].sector_count = leadout - disc->track[last_track].lba;
   113     }
   114 }
   117 /**
   118  * Construct a drive indentification string based on the response to the
   119  * INQUIRY command. On success, the disc display_name is updated with the
   120  * drive name, otherwise the display_name is unchanged.
   121  * @return PKT_ERR_OK on success, otherwise the host failure code.
   122  */
   123 static gdrom_error_t gdrom_scsi_identify_drive( gdrom_disc_t disc )
   124 {
   125     unsigned char ident[256];
   126     uint32_t identlen = 256;
   127     char cmd[12] = {0x12,0,0,0, 0xFF,0,0,0, 0,0,0,0};
   128     gdrom_error_t status = SCSI_TRANSPORT(disc)->packet_read( disc, cmd, ident, &identlen );
   129     if( status == PKT_ERR_OK ) {
   130         char vendorid[9];
   131         char productid[17];
   132         char productrev[5];
   133         memcpy( vendorid, ident+8, 8 ); vendorid[8] = 0;
   134         memcpy( productid, ident+16, 16 ); productid[16] = 0;
   135         memcpy( productrev, ident+32, 4 ); productrev[4] = 0;
   136        	g_free( (char *)disc->display_name );
   137         disc->display_name = g_strdup_printf( "%.8s %.16s %.4s", g_strstrip(vendorid), 
   138                   g_strstrip(productid), g_strstrip(productrev) );
   139     }
   140     return status;
   141 }
   144 static gdrom_error_t gdrom_scsi_read_sector( gdrom_disc_t disc, uint32_t sector,
   145                                         int mode, unsigned char *buf, uint32_t *length )
   146 {
   147     uint32_t real_sector = sector - GDROM_PREGAP;
   148     uint32_t sector_size = MAX_SECTOR_SIZE;
   149     char cmd[12];
   151     mmc_make_read_cd_cmd( cmd, real_sector, mode );
   153     gdrom_error_t status = SCSI_TRANSPORT(disc)->packet_read( disc, cmd, buf, &sector_size );
   154     if( status != 0 ) {
   155         return status;
   156     }
   157     /* FIXME */
   158     *length = 2048;
   159     return 0;
   160 }
   162 /**
   163  * Read the full table of contents into the disc from the device.
   164  */
   165 static gdrom_error_t gdrom_scsi_read_toc( gdrom_disc_t disc )
   166 {
   167     unsigned char buf[MAXTOCSIZE];
   168     uint32_t buflen = sizeof(buf);
   169     char cmd[12] = { 0x43, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
   171     cmd[7] = (sizeof(buf))>>8;
   172     cmd[8] = (sizeof(buf))&0xFF;
   173     memset( buf, 0, sizeof(buf) );
   174     gdrom_error_t status = SCSI_TRANSPORT(disc)->packet_read(disc, cmd, buf, &buflen );
   175     if( status == PKT_ERR_OK ) {
   176 	    mmc_parse_toc2( disc, buf );	
   177     } else {
   178     	if( status & 0xFF != 0x02 ) {
   179     	    /* Sense key 2 == Not Ready (ie temporary failure). Just ignore and
   180     	     * consider the drive empty for now, but warn about any other errors
   181     	     * we get. */
   182     	    WARN( _("Unable to read disc table of contents (error %04x)"), status );
   183     	}
   184     	disc->disc_type = IDE_DISC_NONE;
   185     }
   186     return status;
   187 }
   189 static gboolean gdrom_scsi_check_status( gdrom_disc_t disc )
   190 {
   191 	if( SCSI_TRANSPORT(disc)->media_changed(disc) ) {
   192 		gdrom_scsi_read_toc(disc);
   193 		return TRUE;
   194 	} else {
   195 		return FALSE;
   196 	}
   197 }
   199 static gdrom_error_t gdrom_scsi_play_audio( gdrom_disc_t disc, uint32_t lba, uint32_t endlba )
   200 {
   201     uint32_t real_sector = lba - GDROM_PREGAP;
   202     uint32_t length = endlba - lba;
   204     char cmd[12] = { 0xA5, 0,0,0, 0,0,0,0, 0,0,0,0 };
   205     cmd[2] = (real_sector >> 24) & 0xFF;
   206     cmd[3] = (real_sector >> 16) & 0xFF;
   207     cmd[4] = (real_sector >> 8) & 0xFF;
   208     cmd[5] = real_sector & 0xFF;
   209     cmd[6] = (length >> 24) & 0xFF;
   210     cmd[7] = (length >> 16) & 0xFF;
   211     cmd[8] = (length >> 8) & 0xFF;
   212     cmd[9] = length & 0xFF;
   214     return SCSI_TRANSPORT(disc)->packet_cmd( disc, cmd );
   215 }
   218 gdrom_error_t gdrom_scsi_stop_audio( gdrom_disc_t disc )
   219 {
   220     int fd = fileno(disc->file);
   221     uint32_t buflen = 0;
   222     char cmd[12] = {0x4E,0,0,0, 0,0,0,0, 0,0,0,0};
   224     return SCSI_TRANSPORT(disc)->packet_cmd( disc, cmd );
   225 }
   228 gdrom_disc_t gdrom_scsi_disc_new( const gchar *filename, FILE *f, gdrom_scsi_transport_t scsi )
   229 {
   230 	gdrom_disc_t disc = gdrom_disc_new(filename,f);
   231     if( disc != NULL ) {
   232 	    /* Initialize */
   233     	disc->impl_data = scsi;
   234     	disc->check_status = gdrom_scsi_check_status;
   235     	disc->read_sector = gdrom_scsi_read_sector;
   236     	disc->play_audio = gdrom_scsi_play_audio;
   237     	disc->run_time_slice = NULL;
   238     	gdrom_scsi_identify_drive(disc);
   239     	gdrom_scsi_read_toc(disc);
   240     }
   241     return disc;
   242 } 
.