Search
lxdream.org :: lxdream/src/drivers/cdrom/cd_mmc.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/cdrom/cd_mmc.c
changeset 1097:d4807997e450
prevsrc/drivers/cd_mmc.c@1071:182cfe43c09e
next1296:30ecee61f811
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)
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 <assert.h>
    20 #include <string.h>
    21 #include <glib/gstrfuncs.h>
    22 #include "lxdream.h"
    23 #include "gettext.h"
    24 #include "drivers/cdrom/cdimpl.h"
    26 #define MAXTOCENTRIES 600  /* This is a fairly generous overestimate really */
    27 #define MAXTOCSIZE 4 + (MAXTOCENTRIES*11)
    28 #define MAX_SECTORS_PER_CALL 1
    30 /**
    31  * Parse the TOC (format 2) into the cdrom_disc structure
    32  */
    33 void mmc_parse_toc2( cdrom_disc_t disc, unsigned char *buf )
    34 {
    35     int max_track = 0;
    36     int max_session = 0;
    37     int last_track = -1;
    38     int leadout = -1;
    39     int len = (buf[0] << 8) | buf[1];
    40     int session_type = -1;
    41     int i;
    42     for( i = 4; i<len; i+=11 ) {
    43         int session = buf[i];
    44         int adr = buf[i+1] >> 4;
    45         int point = buf[i+3];
    46         if( adr == 0x01 && point > 0 && point < 100 ) {
    47             /* Track info */
    48             int trackno = point-1;
    49             if( point > max_track ) {
    50                 max_track = point;
    51             }
    52             if( session > max_session ) {
    53                 max_session = session;
    54             }
    55             disc->track[trackno].trackno = point;
    56             disc->track[trackno].flags = (buf[i+1] & 0x0F) << 4;
    57             disc->track[trackno].sessionno = session;
    58             disc->track[trackno].lba = MSFTOLBA(buf[i+8],buf[i+9],buf[i+10]);
    59             last_track = trackno;
    60         } else switch( (adr << 8) | point ) {
    61         case 0x1A0: /* session info */
    62             if( buf[i+9] == 0x20 ) {
    63                 session_type = CDROM_DISC_XA;
    64             } else {
    65                 session_type = CDROM_DISC_NONXA;
    66             }
    67             disc->disc_type = session_type;
    68             break;
    69         case 0x1A2: /* leadout */
    70             disc->leadout = MSFTOLBA(buf[i+8], buf[i+9], buf[i+10]);
    71             break;
    72         }
    73     }
    74     disc->track_count = max_track;
    75     disc->session_count = max_session;
    76 }
    79 const char *mmc_parse_inquiry( unsigned char *buf )
    80 {
    81     char vendorid[9];
    82     char productid[17];
    83     char productrev[5];
    84     memcpy( vendorid, buf+8, 8 ); vendorid[8] = 0;
    85     memcpy( productid, buf+16, 16 ); productid[16] = 0;
    86     memcpy( productrev, buf+32, 4 ); productrev[4] = 0;
    87     return g_strdup_printf( "%.8s %.16s %.4s", g_strstrip(vendorid),
    88               g_strstrip(productid), g_strstrip(productrev) );
    89 }
    91 /**
    92  * Construct a drive indentification string based on the response to the
    93  * INQUIRY command. On success, returns the disc identification as a newly
    94  * allocated string, otherwise NULL.
    95  */
    96 const char *cdrom_disc_scsi_identify_drive( cdrom_disc_t disc )
    97 {
    98     unsigned char ident[256];
    99     uint32_t identlen = 256;
   100     char cmd[12] = {0x12,0,0,0, 0xFF,0,0,0, 0,0,0,0};
   101     cdrom_error_t status = SCSI_TRANSPORT(disc)->packet_read( disc, cmd, ident, &identlen );
   102     if( status == CDROM_ERROR_OK ) {
   103         return mmc_parse_inquiry(ident);
   104     }
   105     return NULL;
   106 }
   109 static cdrom_error_t cdrom_disc_scsi_read_sectors( sector_source_t source, cdrom_lba_t lba,
   110         cdrom_count_t count, cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
   111 {
   112     assert( IS_SECTOR_SOURCE_TYPE(source,DISC_SECTOR_SOURCE) );
   113     cdrom_disc_t disc = (cdrom_disc_t)source;
   114     uint32_t sector_size = CDROM_MAX_SECTOR_SIZE;
   115     char cmd[12];
   117     cmd[0] = 0xBE;
   118     cmd[1] = CDROM_READ_TYPE(mode);
   119     cmd[2] = (lba >> 24) & 0xFF;
   120     cmd[3] = (lba >> 16) & 0xFF;
   121     cmd[4] = (lba >> 8) & 0xFF;
   122     cmd[5] = lba & 0xFF;
   123     cmd[6] = (count>>16) & 0xFF;
   124     cmd[7] = (count>>8) & 0xFF;
   125     cmd[8] = count & 0xFF;
   126     cmd[9] = CDROM_READ_FIELDS(mode)>>8;
   127     cmd[10]= 0;
   128     cmd[11]= 0;
   130     cdrom_error_t status = SCSI_TRANSPORT(disc)->packet_read( disc, cmd, buf, &sector_size );
   131     if( status != 0 ) {
   132         return status;
   133     }
   134     /* FIXME */
   135     *length = 2048;
   136     return 0;
   137 }
   139 /**
   140  * Read the full table of contents into the disc from the device.
   141  */
   142 gboolean cdrom_disc_scsi_read_toc( cdrom_disc_t disc, ERROR *err )
   143 {
   144     unsigned char buf[MAXTOCSIZE];
   145     uint32_t buflen = sizeof(buf);
   146     char cmd[12] = { 0x43, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
   148     cmd[7] = (sizeof(buf))>>8;
   149     cmd[8] = (sizeof(buf))&0xFF;
   150     memset( buf, 0, sizeof(buf) );
   151     cdrom_error_t status = SCSI_TRANSPORT(disc)->packet_read(disc, cmd, buf, &buflen );
   152     if( status == CDROM_ERROR_OK ) {
   153 	    mmc_parse_toc2( disc, buf );
   154 	    return TRUE;
   155     } else {
   156     	if( (status & 0xFF) != 0x02 ) {
   157     	    /* Sense key 2 == Not Ready (ie temporary failure). Just ignore and
   158     	     * consider the drive empty for now, but warn about any other errors
   159     	     * we get. */
   160     	    WARN( _("Unable to read disc table of contents (error %04x)"), status );
   161     	}
   162     	cdrom_disc_clear_toc(disc);
   163     	return FALSE;
   164     }
   165 }
   167 static gboolean cdrom_disc_scsi_check_media( cdrom_disc_t disc )
   168 {
   169 	if( SCSI_TRANSPORT(disc)->media_changed(disc) ) {
   170 		cdrom_disc_scsi_read_toc(disc, NULL);
   171 		return TRUE;
   172 	} else {
   173 		return FALSE;
   174 	}
   175 }
   177 static cdrom_error_t cdrom_disc_scsi_play_audio( cdrom_disc_t disc, cdrom_lba_t lba, cdrom_count_t length )
   178 {
   179     char cmd[12] = { 0xA5, 0,0,0, 0,0,0,0, 0,0,0,0 };
   180     cmd[2] = (lba >> 24) & 0xFF;
   181     cmd[3] = (lba >> 16) & 0xFF;
   182     cmd[4] = (lba >> 8) & 0xFF;
   183     cmd[5] = lba & 0xFF;
   184     cmd[6] = (length >> 24) & 0xFF;
   185     cmd[7] = (length >> 16) & 0xFF;
   186     cmd[8] = (length >> 8) & 0xFF;
   187     cmd[9] = length & 0xFF;
   189     return SCSI_TRANSPORT(disc)->packet_cmd( disc, cmd );
   190 }
   193 static cdrom_error_t cdrom_disc_scsi_stop_audio( cdrom_disc_t disc )
   194 {
   195     uint32_t buflen = 0;
   196     char cmd[12] = {0x4E,0,0,0, 0,0,0,0, 0,0,0,0};
   198     return SCSI_TRANSPORT(disc)->packet_cmd( disc, cmd );
   199 }
   201 void cdrom_disc_scsi_init( cdrom_disc_t disc, cdrom_scsi_transport_t scsi )
   202 {
   203     disc->impl_data = scsi;
   204     disc->source.read_sectors = cdrom_disc_scsi_read_sectors;
   205     disc->read_toc = cdrom_disc_scsi_read_toc;
   206     disc->check_media = cdrom_disc_scsi_check_media;
   207     disc->play_audio = cdrom_disc_scsi_play_audio;
   208     disc->stop_audio = cdrom_disc_scsi_stop_audio;
   209 }
   211 cdrom_disc_t cdrom_disc_scsi_new( const char *filename, cdrom_scsi_transport_t scsi, ERROR *err )
   212 {
   213     cdrom_disc_t disc = cdrom_disc_new(filename, err);
   214     if( disc != NULL ) {
   215         /* Initialize */
   216         cdrom_disc_scsi_init( disc, scsi );
   217         cdrom_disc_read_toc(disc, err);
   218     }
   219     return disc;
   220 } 
   222 cdrom_disc_t cdrom_disc_scsi_new_file( FILE *f, const char *filename, cdrom_scsi_transport_t scsi, ERROR *err )
   223 {
   224     cdrom_disc_t disc = cdrom_disc_new(filename, err);
   225     if( disc != NULL ) {
   226         /* Initialize */
   227         disc->base_source = file_sector_source_new( f, SECTOR_UNKNOWN, 0, 0, TRUE );
   228         if( disc->base_source != NULL ) {
   229             sector_source_ref( disc->base_source );
   230             cdrom_disc_scsi_init( disc, scsi );
   231             cdrom_disc_read_toc(disc, err);
   232         } else {
   233             cdrom_disc_unref(disc);
   234             disc = NULL;
   235         }
   236     }
   237     return disc;
   238 }
.