filename | src/gdrom/gdrom.c |
changeset | 1109:700c5ab26a63 |
prev | 1101:78e762cec843 |
next | 1296:30ecee61f811 |
author | nkeynes |
date | Fri Oct 29 07:52:45 2010 +1000 (13 years ago) |
permissions | -rw-r--r-- |
last change | Fix triangle extraction when the tile entry is a triangle but the polygon is actually a strip (lead to extracting too many triangles) |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * GD-Rom access functions.
5 *
6 * Copyright (c) 2005 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 <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <ctype.h>
25 #include <glib/gutils.h>
26 #include <netinet/in.h>
27 #include "gdrom/ide.h"
28 #include "gdrom/gdrom.h"
29 #include "gdrom/packet.h"
30 #include "bootstrap.h"
31 #include "loader.h"
32 #include "drivers/cdrom/cdrom.h"
34 #define GDROM_LBA_OFFSET 150
36 DEFINE_HOOK( gdrom_disc_change_hook, gdrom_disc_change_hook_t )
38 static void gdrom_fire_disc_changed( cdrom_disc_t disc )
39 {
40 CALL_HOOKS( gdrom_disc_change_hook, disc, disc == NULL ? NULL : disc->name );
41 }
43 gboolean gdrom_disc_read_title( cdrom_disc_t disc, char *title, size_t titlelen );
45 struct gdrom_drive {
46 cdrom_disc_t disc;
47 int boot_track;
48 char title[129];
49 } gdrom_drive;
51 void gdrom_mount_disc( cdrom_disc_t disc )
52 {
53 if( disc != gdrom_drive.disc ) {
54 cdrom_disc_unref(gdrom_drive.disc);
55 gdrom_drive.disc = disc;
56 cdrom_disc_ref(disc);
57 gdrom_disc_read_title( disc, gdrom_drive.title, sizeof(gdrom_drive.title) );
58 gdrom_fire_disc_changed( disc );
59 }
60 }
62 gboolean gdrom_mount_image( const gchar *filename, ERROR *err )
63 {
64 cdrom_disc_t disc = cdrom_disc_open(filename, err);
65 if( disc == NULL && err->code == LX_ERR_FILE_UNKNOWN ) {
66 disc = cdrom_wrap_magic( CDROM_DISC_XA, filename, err );
67 }
68 if( disc != NULL ) {
69 gdrom_mount_disc( disc );
70 return TRUE;
71 }
72 return FALSE;
73 }
75 void gdrom_unmount_disc( )
76 {
77 if( gdrom_drive.disc != NULL ) {
78 cdrom_disc_unref(gdrom_drive.disc);
79 gdrom_fire_disc_changed(NULL);
80 gdrom_drive.disc = NULL;
81 }
82 }
84 cdrom_disc_t gdrom_get_current_disc()
85 {
86 return gdrom_drive.disc;
87 }
89 const gchar *gdrom_get_current_disc_name()
90 {
91 if( gdrom_drive.disc == NULL ) {
92 return NULL;
93 } else {
94 return gdrom_drive.disc->name;
95 }
96 }
98 const gchar *gdrom_get_current_disc_title()
99 {
100 if( gdrom_drive.disc == NULL || gdrom_drive.title[0] == '\0' ) {
101 return NULL;
102 } else {
103 return gdrom_drive.title;
104 }
105 }
107 #define CHECK_DISC() do { \
108 if( gdrom_drive.disc == NULL || gdrom_drive.disc->disc_type == CDROM_DISC_NONE ) { return CDROM_ERROR_NODISC; } \
109 } while(0)
111 cdrom_error_t gdrom_check_media( )
112 {
113 CHECK_DISC();
114 return CDROM_ERROR_OK;
115 }
117 cdrom_error_t gdrom_read_toc( unsigned char *buf )
118 {
119 struct gdrom_toc *toc = (struct gdrom_toc *)buf;
120 int i;
122 CHECK_DISC();
123 cdrom_disc_t disc = gdrom_drive.disc;
125 for( i=0; i<disc->track_count; i++ ) {
126 toc->track[i] = htonl( disc->track[i].lba+GDROM_LBA_OFFSET ) | disc->track[i].flags;
127 }
128 toc->first = 0x0100 | disc->track[0].flags;
129 toc->last = (disc->track_count<<8) | disc->track[i-1].flags;
130 toc->leadout = htonl(disc->leadout+GDROM_LBA_OFFSET) |
131 disc->track[i-1].flags;
132 for( ;i<99; i++ )
133 toc->track[i] = 0xFFFFFFFF;
134 return PKT_ERR_OK;
135 }
137 cdrom_error_t gdrom_read_session( int session, unsigned char *buf )
138 {
139 cdrom_lba_t lba;
140 CHECK_DISC();
142 buf[0] = 0x01; /* Disc status? */
143 buf[1] = 0;
146 if( session == 0 ) {
147 buf[2] = gdrom_drive.disc->session_count;
148 lba = gdrom_drive.disc->leadout + GDROM_LBA_OFFSET;
149 } else {
150 cdrom_track_t track = cdrom_disc_get_session( gdrom_drive.disc, session );
151 if( track == NULL )
152 return CDROM_ERROR_BADFIELD;
154 buf[2] = track->trackno;
155 lba = track->lba + GDROM_LBA_OFFSET;
156 }
157 buf[3] = (lba >> 16) & 0xFF;
158 buf[4] = (lba >> 8) & 0xFF;
159 buf[5] = lba & 0xFF;
160 return CDROM_ERROR_OK;
161 }
163 cdrom_error_t gdrom_read_short_status( cdrom_lba_t lba, unsigned char *buf )
164 {
165 cdrom_lba_t real_lba = lba - GDROM_LBA_OFFSET;
166 CHECK_DISC();
168 cdrom_track_t track = cdrom_disc_get_track_by_lba( gdrom_drive.disc, real_lba );
169 if( track == NULL ) {
170 track = cdrom_disc_get_track( gdrom_drive.disc, 1 );
171 if( track == NULL )
172 return CDROM_ERROR_NODISC;
173 lba = 150;
174 }
175 uint32_t offset = real_lba - track->lba;
176 buf[0] = 0x00;
177 buf[1] = 0x15; /* audio status ? */
178 buf[2] = 0x00;
179 buf[3] = 0x0E;
180 buf[4] = track->flags;
181 buf[5] = track->trackno;
182 buf[6] = 0x01; /* ?? */
183 buf[7] = (offset >> 16) & 0xFF;
184 buf[8] = (offset >> 8) & 0xFF;
185 buf[9] = offset & 0xFF;
186 buf[10] = 0;
187 buf[11] = (lba >> 16) & 0xFF;
188 buf[12] = (lba >> 8) & 0xFF;
189 buf[13] = lba & 0xFF;
190 return PKT_ERR_OK;
191 }
193 int gdrom_get_drive_status( )
194 {
195 if( gdrom_drive.disc == NULL ) {
196 return CDROM_DISC_NONE;
197 }
199 if( cdrom_disc_check_media(gdrom_drive.disc) == CDROM_DISC_NONE ) {
200 return CDROM_DISC_NONE;
201 } else {
202 return gdrom_drive.disc->disc_type | IDE_DISC_READY;
203 }
204 }
206 cdrom_error_t gdrom_play_audio( cdrom_lba_t lba, cdrom_count_t count )
207 {
208 CHECK_DISC();
209 if( gdrom_drive.disc->play_audio ) {
210 return gdrom_drive.disc->play_audio( gdrom_drive.disc, lba - GDROM_LBA_OFFSET, count );
211 }
212 return CDROM_ERROR_BADFIELD;
213 }
215 /* Parse CD read */
216 #define READ_CD_MODE(x) ((x)&0x0E)
217 #define READ_CD_MODE_ANY 0x00
218 #define READ_CD_MODE_CDDA 0x02
219 #define READ_CD_MODE_1 0x04
220 #define READ_CD_MODE_2 0x06
221 #define READ_CD_MODE_2_FORM_1 0x08
222 #define READ_CD_MODE_2_FORM_2 0x0A
224 #define READ_CD_CHANNELS(x) ((x)&0xF0)
225 #define READ_CD_HEADER(x) ((x)&0x80)
226 #define READ_CD_SUBHEAD(x) ((x)&0x40)
227 #define READ_CD_DATA(x) ((x)&0x20)
228 #define READ_CD_RAW(x) ((x)&0x10)
231 cdrom_error_t gdrom_read_cd( cdrom_lba_t lba, cdrom_count_t count,
232 unsigned mode, unsigned char *buf, size_t *length )
233 {
234 cdrom_lba_t real_lba = lba - 150;
235 cdrom_read_mode_t real_mode = 0;
237 CHECK_DISC();
239 /* Translate GDROM read mode into standard MMC read mode */
240 if( READ_CD_RAW(mode) ) {
241 real_mode = CDROM_READ_RAW;
242 } else {
243 if( READ_CD_HEADER(mode) ) {
244 real_mode = CDROM_READ_HEADER|CDROM_READ_SYNC;
245 }
246 if( READ_CD_SUBHEAD(mode) ) {
247 real_mode |= CDROM_READ_SUBHEADER;
248 }
249 if( READ_CD_DATA(mode) ) {
250 real_mode |= CDROM_READ_DATA;
251 }
252 }
254 if( READ_CD_MODE(mode) == 0x0C )
255 real_mode |= CDROM_READ_MODE2;
256 else
257 real_mode |= (READ_CD_MODE(mode)<<1);
259 return cdrom_disc_read_sectors( gdrom_drive.disc, real_lba, count, real_mode, buf, length );
260 }
262 void gdrom_run_slice( uint32_t nanosecs )
263 {
265 }
268 cdrom_track_t gdrom_disc_get_boot_track( cdrom_disc_t disc ) {
269 int i, boot_track = -1;
270 if( disc != NULL && disc->track_count > 0 ) {
271 int last_session = disc->track[disc->track_count-1].sessionno;
272 if( last_session == 1 )
273 return NULL;
274 for( i=disc->track_count-1; i>=0 && disc->track[i].sessionno == last_session; i-- ) {
275 if( disc->track[i].flags & TRACK_FLAG_DATA ) {
276 boot_track = i;
277 }
278 }
279 }
280 return &disc->track[boot_track];
281 }
283 /**
284 * Check the disc for a useable DC bootstrap, and update the disc
285 * with the title accordingly. Otherwise set the title to the empty string.
286 * @return TRUE if we found a bootstrap, otherwise FALSE.
287 */
288 gboolean gdrom_disc_read_title( cdrom_disc_t disc, char *title, size_t titlelen ) {
289 cdrom_track_t boot_track = gdrom_disc_get_boot_track(disc);
290 int i;
291 if( boot_track != NULL ) {
292 unsigned char boot_sector[CDROM_MAX_SECTOR_SIZE];
293 size_t length = sizeof(boot_sector);
294 if( cdrom_disc_read_sectors( disc, boot_track->lba, 1, CDROM_READ_DATA|CDROM_READ_MODE2_FORM1,
295 boot_sector, &length ) == CDROM_ERROR_OK ) {
296 if( memcmp( boot_sector, "SEGA SEGAKATANA SEGA ENTERPRISES", 32) == 0 ) {
297 /* Got magic */
298 dc_bootstrap_head_t bootstrap = (dc_bootstrap_head_t)boot_sector;
299 for( i=128; i>0; i-- ) {
300 if( !isspace(bootstrap->product_name[i-1]) )
301 break;
302 }
303 if( i >= titlelen )
304 i = (titlelen-1);
305 memcpy( title, bootstrap->product_name, i );
306 title[i] = '\0';
307 }
308 bootstrap_dump(boot_sector, FALSE);
309 return TRUE;
310 }
311 }
312 title[0] = '\0';
313 return FALSE;
314 }
.