Search
lxdream.org :: lxdream/src/drivers/cdrom/cd_mmc.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/cdrom/cd_mmc.c
changeset 1097:d4807997e450
prev1071: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)
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/drivers/cdrom/cd_mmc.c Sun Jan 31 18:35:06 2010 +1000
1.3 @@ -0,0 +1,238 @@
1.4 +/**
1.5 + * $Id$
1.6 + *
1.7 + * SCSI/MMC device interface (depends on lower-level SCSI transport)
1.8 + *
1.9 + * Copyright (c) 2009 Nathan Keynes.
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify
1.12 + * it under the terms of the GNU General Public License as published by
1.13 + * the Free Software Foundation; either version 2 of the License, or
1.14 + * (at your option) any later version.
1.15 + *
1.16 + * This program is distributed in the hope that it will be useful,
1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 + * GNU General Public License for more details.
1.20 + */
1.21 +
1.22 +#include <assert.h>
1.23 +#include <string.h>
1.24 +#include <glib/gstrfuncs.h>
1.25 +#include "lxdream.h"
1.26 +#include "gettext.h"
1.27 +#include "drivers/cdrom/cdimpl.h"
1.28 +
1.29 +#define MAXTOCENTRIES 600 /* This is a fairly generous overestimate really */
1.30 +#define MAXTOCSIZE 4 + (MAXTOCENTRIES*11)
1.31 +#define MAX_SECTORS_PER_CALL 1
1.32 +
1.33 +/**
1.34 + * Parse the TOC (format 2) into the cdrom_disc structure
1.35 + */
1.36 +void mmc_parse_toc2( cdrom_disc_t disc, unsigned char *buf )
1.37 +{
1.38 + int max_track = 0;
1.39 + int max_session = 0;
1.40 + int last_track = -1;
1.41 + int leadout = -1;
1.42 + int len = (buf[0] << 8) | buf[1];
1.43 + int session_type = -1;
1.44 + int i;
1.45 + for( i = 4; i<len; i+=11 ) {
1.46 + int session = buf[i];
1.47 + int adr = buf[i+1] >> 4;
1.48 + int point = buf[i+3];
1.49 + if( adr == 0x01 && point > 0 && point < 100 ) {
1.50 + /* Track info */
1.51 + int trackno = point-1;
1.52 + if( point > max_track ) {
1.53 + max_track = point;
1.54 + }
1.55 + if( session > max_session ) {
1.56 + max_session = session;
1.57 + }
1.58 + disc->track[trackno].trackno = point;
1.59 + disc->track[trackno].flags = (buf[i+1] & 0x0F) << 4;
1.60 + disc->track[trackno].sessionno = session;
1.61 + disc->track[trackno].lba = MSFTOLBA(buf[i+8],buf[i+9],buf[i+10]);
1.62 + last_track = trackno;
1.63 + } else switch( (adr << 8) | point ) {
1.64 + case 0x1A0: /* session info */
1.65 + if( buf[i+9] == 0x20 ) {
1.66 + session_type = CDROM_DISC_XA;
1.67 + } else {
1.68 + session_type = CDROM_DISC_NONXA;
1.69 + }
1.70 + disc->disc_type = session_type;
1.71 + break;
1.72 + case 0x1A2: /* leadout */
1.73 + disc->leadout = MSFTOLBA(buf[i+8], buf[i+9], buf[i+10]);
1.74 + break;
1.75 + }
1.76 + }
1.77 + disc->track_count = max_track;
1.78 + disc->session_count = max_session;
1.79 +}
1.80 +
1.81 +
1.82 +const char *mmc_parse_inquiry( unsigned char *buf )
1.83 +{
1.84 + char vendorid[9];
1.85 + char productid[17];
1.86 + char productrev[5];
1.87 + memcpy( vendorid, buf+8, 8 ); vendorid[8] = 0;
1.88 + memcpy( productid, buf+16, 16 ); productid[16] = 0;
1.89 + memcpy( productrev, buf+32, 4 ); productrev[4] = 0;
1.90 + return g_strdup_printf( "%.8s %.16s %.4s", g_strstrip(vendorid),
1.91 + g_strstrip(productid), g_strstrip(productrev) );
1.92 +}
1.93 +
1.94 +/**
1.95 + * Construct a drive indentification string based on the response to the
1.96 + * INQUIRY command. On success, returns the disc identification as a newly
1.97 + * allocated string, otherwise NULL.
1.98 + */
1.99 +const char *cdrom_disc_scsi_identify_drive( cdrom_disc_t disc )
1.100 +{
1.101 + unsigned char ident[256];
1.102 + uint32_t identlen = 256;
1.103 + char cmd[12] = {0x12,0,0,0, 0xFF,0,0,0, 0,0,0,0};
1.104 + cdrom_error_t status = SCSI_TRANSPORT(disc)->packet_read( disc, cmd, ident, &identlen );
1.105 + if( status == CDROM_ERROR_OK ) {
1.106 + return mmc_parse_inquiry(ident);
1.107 + }
1.108 + return NULL;
1.109 +}
1.110 +
1.111 +
1.112 +static cdrom_error_t cdrom_disc_scsi_read_sectors( sector_source_t source, cdrom_lba_t lba,
1.113 + cdrom_count_t count, cdrom_read_mode_t mode, unsigned char *buf, size_t *length )
1.114 +{
1.115 + assert( IS_SECTOR_SOURCE_TYPE(source,DISC_SECTOR_SOURCE) );
1.116 + cdrom_disc_t disc = (cdrom_disc_t)source;
1.117 + uint32_t sector_size = CDROM_MAX_SECTOR_SIZE;
1.118 + char cmd[12];
1.119 +
1.120 + cmd[0] = 0xBE;
1.121 + cmd[1] = CDROM_READ_TYPE(mode);
1.122 + cmd[2] = (lba >> 24) & 0xFF;
1.123 + cmd[3] = (lba >> 16) & 0xFF;
1.124 + cmd[4] = (lba >> 8) & 0xFF;
1.125 + cmd[5] = lba & 0xFF;
1.126 + cmd[6] = (count>>16) & 0xFF;
1.127 + cmd[7] = (count>>8) & 0xFF;
1.128 + cmd[8] = count & 0xFF;
1.129 + cmd[9] = CDROM_READ_FIELDS(mode)>>8;
1.130 + cmd[10]= 0;
1.131 + cmd[11]= 0;
1.132 +
1.133 + cdrom_error_t status = SCSI_TRANSPORT(disc)->packet_read( disc, cmd, buf, &sector_size );
1.134 + if( status != 0 ) {
1.135 + return status;
1.136 + }
1.137 + /* FIXME */
1.138 + *length = 2048;
1.139 + return 0;
1.140 +}
1.141 +
1.142 +/**
1.143 + * Read the full table of contents into the disc from the device.
1.144 + */
1.145 +gboolean cdrom_disc_scsi_read_toc( cdrom_disc_t disc, ERROR *err )
1.146 +{
1.147 + unsigned char buf[MAXTOCSIZE];
1.148 + uint32_t buflen = sizeof(buf);
1.149 + char cmd[12] = { 0x43, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1.150 +
1.151 + cmd[7] = (sizeof(buf))>>8;
1.152 + cmd[8] = (sizeof(buf))&0xFF;
1.153 + memset( buf, 0, sizeof(buf) );
1.154 + cdrom_error_t status = SCSI_TRANSPORT(disc)->packet_read(disc, cmd, buf, &buflen );
1.155 + if( status == CDROM_ERROR_OK ) {
1.156 + mmc_parse_toc2( disc, buf );
1.157 + return TRUE;
1.158 + } else {
1.159 + if( (status & 0xFF) != 0x02 ) {
1.160 + /* Sense key 2 == Not Ready (ie temporary failure). Just ignore and
1.161 + * consider the drive empty for now, but warn about any other errors
1.162 + * we get. */
1.163 + WARN( _("Unable to read disc table of contents (error %04x)"), status );
1.164 + }
1.165 + cdrom_disc_clear_toc(disc);
1.166 + return FALSE;
1.167 + }
1.168 +}
1.169 +
1.170 +static gboolean cdrom_disc_scsi_check_media( cdrom_disc_t disc )
1.171 +{
1.172 + if( SCSI_TRANSPORT(disc)->media_changed(disc) ) {
1.173 + cdrom_disc_scsi_read_toc(disc, NULL);
1.174 + return TRUE;
1.175 + } else {
1.176 + return FALSE;
1.177 + }
1.178 +}
1.179 +
1.180 +static cdrom_error_t cdrom_disc_scsi_play_audio( cdrom_disc_t disc, cdrom_lba_t lba, cdrom_count_t length )
1.181 +{
1.182 + char cmd[12] = { 0xA5, 0,0,0, 0,0,0,0, 0,0,0,0 };
1.183 + cmd[2] = (lba >> 24) & 0xFF;
1.184 + cmd[3] = (lba >> 16) & 0xFF;
1.185 + cmd[4] = (lba >> 8) & 0xFF;
1.186 + cmd[5] = lba & 0xFF;
1.187 + cmd[6] = (length >> 24) & 0xFF;
1.188 + cmd[7] = (length >> 16) & 0xFF;
1.189 + cmd[8] = (length >> 8) & 0xFF;
1.190 + cmd[9] = length & 0xFF;
1.191 +
1.192 + return SCSI_TRANSPORT(disc)->packet_cmd( disc, cmd );
1.193 +}
1.194 +
1.195 +
1.196 +static cdrom_error_t cdrom_disc_scsi_stop_audio( cdrom_disc_t disc )
1.197 +{
1.198 + uint32_t buflen = 0;
1.199 + char cmd[12] = {0x4E,0,0,0, 0,0,0,0, 0,0,0,0};
1.200 +
1.201 + return SCSI_TRANSPORT(disc)->packet_cmd( disc, cmd );
1.202 +}
1.203 +
1.204 +void cdrom_disc_scsi_init( cdrom_disc_t disc, cdrom_scsi_transport_t scsi )
1.205 +{
1.206 + disc->impl_data = scsi;
1.207 + disc->source.read_sectors = cdrom_disc_scsi_read_sectors;
1.208 + disc->read_toc = cdrom_disc_scsi_read_toc;
1.209 + disc->check_media = cdrom_disc_scsi_check_media;
1.210 + disc->play_audio = cdrom_disc_scsi_play_audio;
1.211 + disc->stop_audio = cdrom_disc_scsi_stop_audio;
1.212 +}
1.213 +
1.214 +cdrom_disc_t cdrom_disc_scsi_new( const char *filename, cdrom_scsi_transport_t scsi, ERROR *err )
1.215 +{
1.216 + cdrom_disc_t disc = cdrom_disc_new(filename, err);
1.217 + if( disc != NULL ) {
1.218 + /* Initialize */
1.219 + cdrom_disc_scsi_init( disc, scsi );
1.220 + cdrom_disc_read_toc(disc, err);
1.221 + }
1.222 + return disc;
1.223 +}
1.224 +
1.225 +cdrom_disc_t cdrom_disc_scsi_new_file( FILE *f, const char *filename, cdrom_scsi_transport_t scsi, ERROR *err )
1.226 +{
1.227 + cdrom_disc_t disc = cdrom_disc_new(filename, err);
1.228 + if( disc != NULL ) {
1.229 + /* Initialize */
1.230 + disc->base_source = file_sector_source_new( f, SECTOR_UNKNOWN, 0, 0, TRUE );
1.231 + if( disc->base_source != NULL ) {
1.232 + sector_source_ref( disc->base_source );
1.233 + cdrom_disc_scsi_init( disc, scsi );
1.234 + cdrom_disc_read_toc(disc, err);
1.235 + } else {
1.236 + cdrom_disc_unref(disc);
1.237 + disc = NULL;
1.238 + }
1.239 + }
1.240 + return disc;
1.241 +}
.