filename | src/drivers/cdrom/cd_mmc.c |
changeset | 1097:d4807997e450 |
prev | 1071:182cfe43c09e |
next | 1296:30ecee61f811 |
author | nkeynes |
date | Thu Feb 23 14:59:58 2012 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | mem_stream_class should be static (to avoid potential conflicts with the real one) |
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, §or_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 }
.