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