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 1298:d0eb2307b847
prev1296:30ecee61f811
author nkeynes
date Wed Feb 04 08:38:23 2015 +1000 (5 years ago)
permissions -rw-r--r--
last change Fix assorted compile warnings reported by Clang
file annotate diff log raw
nkeynes@1023
     1
/**
nkeynes@1023
     2
 * $Id$
nkeynes@1023
     3
 *
nkeynes@1023
     4
 * SCSI/MMC device interface (depends on lower-level SCSI transport)
nkeynes@1023
     5
 *
nkeynes@1023
     6
 * Copyright (c) 2009 Nathan Keynes.
nkeynes@1023
     7
 *
nkeynes@1023
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@1023
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@1023
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@1023
    11
 * (at your option) any later version.
nkeynes@1023
    12
 *
nkeynes@1023
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@1023
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@1023
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@1023
    16
 * GNU General Public License for more details.
nkeynes@1023
    17
 */
nkeynes@1023
    18
nkeynes@1097
    19
#include <assert.h>
nkeynes@1023
    20
#include <string.h>
nkeynes@1296
    21
#include <glib.h>
nkeynes@1023
    22
#include "lxdream.h"
nkeynes@1023
    23
#include "gettext.h"
nkeynes@1097
    24
#include "drivers/cdrom/cdimpl.h"
nkeynes@1023
    25
nkeynes@1023
    26
#define MAXTOCENTRIES 600  /* This is a fairly generous overestimate really */
nkeynes@1023
    27
#define MAXTOCSIZE 4 + (MAXTOCENTRIES*11)
nkeynes@1023
    28
#define MAX_SECTORS_PER_CALL 1
nkeynes@1023
    29
nkeynes@1023
    30
/**
nkeynes@1097
    31
 * Parse the TOC (format 2) into the cdrom_disc structure
nkeynes@1023
    32
 */
nkeynes@1097
    33
void mmc_parse_toc2( cdrom_disc_t disc, unsigned char *buf )
nkeynes@1023
    34
{
nkeynes@1023
    35
    int max_track = 0;
nkeynes@1097
    36
    int max_session = 0;
nkeynes@1023
    37
    int last_track = -1;
nkeynes@1023
    38
    int len = (buf[0] << 8) | buf[1];
nkeynes@1023
    39
    int session_type = -1;
nkeynes@1023
    40
    int i;
nkeynes@1023
    41
    for( i = 4; i<len; i+=11 ) {
nkeynes@1023
    42
        int session = buf[i];
nkeynes@1023
    43
        int adr = buf[i+1] >> 4;
nkeynes@1023
    44
        int point = buf[i+3];
nkeynes@1023
    45
        if( adr == 0x01 && point > 0 && point < 100 ) {
nkeynes@1023
    46
            /* Track info */
nkeynes@1023
    47
            int trackno = point-1;
nkeynes@1023
    48
            if( point > max_track ) {
nkeynes@1023
    49
                max_track = point;
nkeynes@1023
    50
            }
nkeynes@1097
    51
            if( session > max_session ) {
nkeynes@1097
    52
                max_session = session;
nkeynes@1097
    53
            }
nkeynes@1097
    54
            disc->track[trackno].trackno = point;
nkeynes@1023
    55
            disc->track[trackno].flags = (buf[i+1] & 0x0F) << 4;
nkeynes@1097
    56
            disc->track[trackno].sessionno = session;
nkeynes@1023
    57
            disc->track[trackno].lba = MSFTOLBA(buf[i+8],buf[i+9],buf[i+10]);
nkeynes@1023
    58
            last_track = trackno;
nkeynes@1023
    59
        } else switch( (adr << 8) | point ) {
nkeynes@1023
    60
        case 0x1A0: /* session info */
nkeynes@1023
    61
            if( buf[i+9] == 0x20 ) {
nkeynes@1097
    62
                session_type = CDROM_DISC_XA;
nkeynes@1023
    63
            } else {
nkeynes@1097
    64
                session_type = CDROM_DISC_NONXA;
nkeynes@1023
    65
            }
nkeynes@1023
    66
            disc->disc_type = session_type;
nkeynes@1023
    67
            break;
nkeynes@1023
    68
        case 0x1A2: /* leadout */
nkeynes@1097
    69
            disc->leadout = MSFTOLBA(buf[i+8], buf[i+9], buf[i+10]);
nkeynes@1023
    70
            break;
nkeynes@1023
    71
        }
nkeynes@1023
    72
    }
nkeynes@1023
    73
    disc->track_count = max_track;
nkeynes@1097
    74
    disc->session_count = max_session;
nkeynes@1023
    75
}
nkeynes@1023
    76
nkeynes@1023
    77
nkeynes@1097
    78
const char *mmc_parse_inquiry( unsigned char *buf )
nkeynes@1097
    79
{
nkeynes@1097
    80
    char vendorid[9];
nkeynes@1097
    81
    char productid[17];
nkeynes@1097
    82
    char productrev[5];
nkeynes@1097
    83
    memcpy( vendorid, buf+8, 8 ); vendorid[8] = 0;
nkeynes@1097
    84
    memcpy( productid, buf+16, 16 ); productid[16] = 0;
nkeynes@1097
    85
    memcpy( productrev, buf+32, 4 ); productrev[4] = 0;
nkeynes@1097
    86
    return g_strdup_printf( "%.8s %.16s %.4s", g_strstrip(vendorid),
nkeynes@1097
    87
              g_strstrip(productid), g_strstrip(productrev) );
nkeynes@1097
    88
}
nkeynes@1097
    89
nkeynes@1023
    90
/**
nkeynes@1023
    91
 * Construct a drive indentification string based on the response to the
nkeynes@1097
    92
 * INQUIRY command. On success, returns the disc identification as a newly
nkeynes@1097
    93
 * allocated string, otherwise NULL.
nkeynes@1023
    94
 */
nkeynes@1097
    95
const char *cdrom_disc_scsi_identify_drive( cdrom_disc_t disc )
nkeynes@1023
    96
{
nkeynes@1023
    97
    unsigned char ident[256];
nkeynes@1023
    98
    uint32_t identlen = 256;
nkeynes@1023
    99
    char cmd[12] = {0x12,0,0,0, 0xFF,0,0,0, 0,0,0,0};
nkeynes@1097
   100
    cdrom_error_t status = SCSI_TRANSPORT(disc)->packet_read( disc, cmd, ident, &identlen );
nkeynes@1097
   101
    if( status == CDROM_ERROR_OK ) {
nkeynes@1097
   102
        return mmc_parse_inquiry(ident);
nkeynes@1023
   103
    }
nkeynes@1097
   104
    return NULL;
nkeynes@1023
   105
}
nkeynes@1023
   106
nkeynes@1023
   107
nkeynes@1097
   108
static cdrom_error_t cdrom_disc_scsi_read_sectors( sector_source_t source, cdrom_lba_t lba,
nkeynes@1097
   109
        cdrom_count_t count, cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
nkeynes@1023
   110
{
nkeynes@1097
   111
    assert( IS_SECTOR_SOURCE_TYPE(source,DISC_SECTOR_SOURCE) );
nkeynes@1097
   112
    cdrom_disc_t disc = (cdrom_disc_t)source;
nkeynes@1097
   113
    uint32_t sector_size = CDROM_MAX_SECTOR_SIZE;
nkeynes@1023
   114
    char cmd[12];
nkeynes@1023
   115
nkeynes@1097
   116
    cmd[0] = 0xBE;
nkeynes@1097
   117
    cmd[1] = CDROM_READ_TYPE(mode);
nkeynes@1097
   118
    cmd[2] = (lba >> 24) & 0xFF;
nkeynes@1097
   119
    cmd[3] = (lba >> 16) & 0xFF;
nkeynes@1097
   120
    cmd[4] = (lba >> 8) & 0xFF;
nkeynes@1097
   121
    cmd[5] = lba & 0xFF;
nkeynes@1097
   122
    cmd[6] = (count>>16) & 0xFF;
nkeynes@1097
   123
    cmd[7] = (count>>8) & 0xFF;
nkeynes@1097
   124
    cmd[8] = count & 0xFF;
nkeynes@1097
   125
    cmd[9] = CDROM_READ_FIELDS(mode)>>8;
nkeynes@1097
   126
    cmd[10]= 0;
nkeynes@1097
   127
    cmd[11]= 0;
nkeynes@1023
   128
nkeynes@1097
   129
    cdrom_error_t status = SCSI_TRANSPORT(disc)->packet_read( disc, cmd, buf, &sector_size );
nkeynes@1023
   130
    if( status != 0 ) {
nkeynes@1023
   131
        return status;
nkeynes@1023
   132
    }
nkeynes@1023
   133
    /* FIXME */
nkeynes@1023
   134
    *length = 2048;
nkeynes@1023
   135
    return 0;
nkeynes@1023
   136
}
nkeynes@1023
   137
nkeynes@1023
   138
/**
nkeynes@1023
   139
 * Read the full table of contents into the disc from the device.
nkeynes@1023
   140
 */
nkeynes@1097
   141
gboolean cdrom_disc_scsi_read_toc( cdrom_disc_t disc, ERROR *err )
nkeynes@1023
   142
{
nkeynes@1023
   143
    unsigned char buf[MAXTOCSIZE];
nkeynes@1023
   144
    uint32_t buflen = sizeof(buf);
nkeynes@1023
   145
    char cmd[12] = { 0x43, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
nkeynes@1023
   146
nkeynes@1023
   147
    cmd[7] = (sizeof(buf))>>8;
nkeynes@1023
   148
    cmd[8] = (sizeof(buf))&0xFF;
nkeynes@1023
   149
    memset( buf, 0, sizeof(buf) );
nkeynes@1097
   150
    cdrom_error_t status = SCSI_TRANSPORT(disc)->packet_read(disc, cmd, buf, &buflen );
nkeynes@1097
   151
    if( status == CDROM_ERROR_OK ) {
nkeynes@1097
   152
	    mmc_parse_toc2( disc, buf );
nkeynes@1097
   153
	    return TRUE;
nkeynes@1023
   154
    } else {
nkeynes@1071
   155
    	if( (status & 0xFF) != 0x02 ) {
nkeynes@1023
   156
    	    /* Sense key 2 == Not Ready (ie temporary failure). Just ignore and
nkeynes@1023
   157
    	     * consider the drive empty for now, but warn about any other errors
nkeynes@1023
   158
    	     * we get. */
nkeynes@1023
   159
    	    WARN( _("Unable to read disc table of contents (error %04x)"), status );
nkeynes@1023
   160
    	}
nkeynes@1097
   161
    	cdrom_disc_clear_toc(disc);
nkeynes@1097
   162
    	return FALSE;
nkeynes@1023
   163
    }
nkeynes@1023
   164
}
nkeynes@1023
   165
nkeynes@1097
   166
static gboolean cdrom_disc_scsi_check_media( cdrom_disc_t disc )
nkeynes@1023
   167
{
nkeynes@1023
   168
	if( SCSI_TRANSPORT(disc)->media_changed(disc) ) {
nkeynes@1097
   169
		cdrom_disc_scsi_read_toc(disc, NULL);
nkeynes@1023
   170
		return TRUE;
nkeynes@1023
   171
	} else {
nkeynes@1023
   172
		return FALSE;
nkeynes@1023
   173
	}
nkeynes@1023
   174
}
nkeynes@1023
   175
nkeynes@1097
   176
static cdrom_error_t cdrom_disc_scsi_play_audio( cdrom_disc_t disc, cdrom_lba_t lba, cdrom_count_t length )
nkeynes@1023
   177
{
nkeynes@1023
   178
    char cmd[12] = { 0xA5, 0,0,0, 0,0,0,0, 0,0,0,0 };
nkeynes@1097
   179
    cmd[2] = (lba >> 24) & 0xFF;
nkeynes@1097
   180
    cmd[3] = (lba >> 16) & 0xFF;
nkeynes@1097
   181
    cmd[4] = (lba >> 8) & 0xFF;
nkeynes@1097
   182
    cmd[5] = lba & 0xFF;
nkeynes@1023
   183
    cmd[6] = (length >> 24) & 0xFF;
nkeynes@1023
   184
    cmd[7] = (length >> 16) & 0xFF;
nkeynes@1023
   185
    cmd[8] = (length >> 8) & 0xFF;
nkeynes@1023
   186
    cmd[9] = length & 0xFF;
nkeynes@1023
   187
nkeynes@1023
   188
    return SCSI_TRANSPORT(disc)->packet_cmd( disc, cmd );
nkeynes@1023
   189
}
nkeynes@1023
   190
nkeynes@1023
   191
nkeynes@1097
   192
static cdrom_error_t cdrom_disc_scsi_stop_audio( cdrom_disc_t disc )
nkeynes@1023
   193
{
nkeynes@1023
   194
    char cmd[12] = {0x4E,0,0,0, 0,0,0,0, 0,0,0,0};
nkeynes@1023
   195
    
nkeynes@1023
   196
    return SCSI_TRANSPORT(disc)->packet_cmd( disc, cmd );
nkeynes@1023
   197
}
nkeynes@1023
   198
nkeynes@1097
   199
void cdrom_disc_scsi_init( cdrom_disc_t disc, cdrom_scsi_transport_t scsi )
nkeynes@1097
   200
{
nkeynes@1097
   201
    disc->impl_data = scsi;
nkeynes@1097
   202
    disc->source.read_sectors = cdrom_disc_scsi_read_sectors;
nkeynes@1097
   203
    disc->read_toc = cdrom_disc_scsi_read_toc;
nkeynes@1097
   204
    disc->check_media = cdrom_disc_scsi_check_media;
nkeynes@1097
   205
    disc->play_audio = cdrom_disc_scsi_play_audio;
nkeynes@1097
   206
    disc->stop_audio = cdrom_disc_scsi_stop_audio;
nkeynes@1097
   207
}
nkeynes@1023
   208
nkeynes@1097
   209
cdrom_disc_t cdrom_disc_scsi_new( const char *filename, cdrom_scsi_transport_t scsi, ERROR *err )
nkeynes@1023
   210
{
nkeynes@1097
   211
    cdrom_disc_t disc = cdrom_disc_new(filename, err);
nkeynes@1023
   212
    if( disc != NULL ) {
nkeynes@1097
   213
        /* Initialize */
nkeynes@1097
   214
        cdrom_disc_scsi_init( disc, scsi );
nkeynes@1097
   215
        cdrom_disc_read_toc(disc, err);
nkeynes@1023
   216
    }
nkeynes@1023
   217
    return disc;
nkeynes@1071
   218
} 
nkeynes@1097
   219
nkeynes@1097
   220
cdrom_disc_t cdrom_disc_scsi_new_file( FILE *f, const char *filename, cdrom_scsi_transport_t scsi, ERROR *err )
nkeynes@1097
   221
{
nkeynes@1097
   222
    cdrom_disc_t disc = cdrom_disc_new(filename, err);
nkeynes@1097
   223
    if( disc != NULL ) {
nkeynes@1097
   224
        /* Initialize */
nkeynes@1097
   225
        disc->base_source = file_sector_source_new( f, SECTOR_UNKNOWN, 0, 0, TRUE );
nkeynes@1097
   226
        if( disc->base_source != NULL ) {
nkeynes@1097
   227
            sector_source_ref( disc->base_source );
nkeynes@1097
   228
            cdrom_disc_scsi_init( disc, scsi );
nkeynes@1097
   229
            cdrom_disc_read_toc(disc, err);
nkeynes@1097
   230
        } else {
nkeynes@1097
   231
            cdrom_disc_unref(disc);
nkeynes@1097
   232
            disc = NULL;
nkeynes@1097
   233
        }
nkeynes@1097
   234
    }
nkeynes@1097
   235
    return disc;
nkeynes@1097
   236
}
.