filename | src/gdrom/gdrom.c |
changeset | 1074:397d77b6e346 |
prev | 1023:264e2fd90be8 |
next | 1097:d4807997e450 |
author | nkeynes |
date | Wed Oct 07 17:53:56 2009 +1000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Create a host attachment for the SCIF serial port. By default, uses /dev/console Add general fd listening to netutil, and rename to ioutil Add SCIF update on port read/write - fixes KOS timing problems but needs to be redone properly. |
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 <fcntl.h>
21 #include <errno.h>
22 #include <ctype.h>
23 #include <glib/gutils.h>
24 #include <netinet/in.h>
25 #include "gdrom/ide.h"
26 #include "gdrom/gdrom.h"
27 #include "gdrom/gddriver.h"
28 #include "gdrom/packet.h"
29 #include "dream.h"
30 #include "bootstrap.h"
32 extern gdrom_disc_t gdrom_disc;
34 DEFINE_HOOK( gdrom_disc_change_hook, gdrom_disc_change_hook_t )
36 static void gdrom_fire_disc_changed( gdrom_disc_t disc )
37 {
38 CALL_HOOKS( gdrom_disc_change_hook, disc, disc == NULL ? NULL : disc->name );
39 }
41 char *gdrom_mode_names[] = { "Mode 0", "Mode 1", "Mode 2", "Mode 2 Form 1", "Mode 2 Form 2", "Audio",
42 "Mode 2 semiraw", "XA Raw", "Non-XA Raw" };
43 uint32_t gdrom_sector_size[] = { 0, 2048, 2336, 2048, 2324, 2352, 2336, 2352, 2352 };
46 gdrom_device_t gdrom_device_new( const gchar *name, const gchar *dev_name )
47 {
48 struct gdrom_device *dev = g_malloc0( sizeof(struct gdrom_device) );
49 dev->name = g_strdup(name);
50 dev->device_name = g_strdup(dev_name);
51 return dev;
52 }
54 void gdrom_device_destroy( gdrom_device_t dev )
55 {
56 if( dev->name != NULL ) {
57 g_free( dev->name );
58 dev->name = NULL;
59 }
60 if( dev->device_name != NULL ) {
61 g_free( dev->device_name );
62 dev->device_name = NULL;
63 }
64 g_free( dev );
65 }
67 void gdrom_mount_disc( gdrom_disc_t disc )
68 {
69 if( disc != gdrom_disc ) {
70 if( gdrom_disc != NULL ) {
71 gdrom_disc->destroy(gdrom_disc,TRUE);
72 }
73 gdrom_disc = disc;
74 gdrom_disc_read_title( disc );
75 gdrom_fire_disc_changed( disc );
76 }
77 }
79 gboolean gdrom_mount_image( const gchar *filename )
80 {
81 gdrom_disc_t disc = gdrom_image_open(filename);
82 if( disc != NULL ) {
83 gdrom_mount_disc( disc );
84 return TRUE;
85 }
86 return FALSE;
87 }
89 void gdrom_unmount_disc( )
90 {
91 if( gdrom_disc != NULL ) {
92 gdrom_disc->destroy(gdrom_disc, TRUE);
93 gdrom_fire_disc_changed(NULL);
94 gdrom_disc = NULL;
95 }
96 }
98 gdrom_disc_t gdrom_get_current_disc()
99 {
100 return gdrom_disc;
101 }
103 const gchar *gdrom_get_current_disc_name()
104 {
105 if( gdrom_disc == NULL ) {
106 return NULL;
107 } else {
108 return gdrom_disc->name;
109 }
110 }
112 const gchar *gdrom_get_current_disc_title()
113 {
114 if( gdrom_disc == NULL || gdrom_disc->title[0] == '\0' ) {
115 return NULL;
116 } else {
117 return gdrom_disc->title;
118 }
119 }
121 int gdrom_disc_get_track_by_lba( gdrom_disc_t disc, uint32_t lba )
122 {
123 int i;
124 for( i=0; i<disc->track_count; i++ ) {
125 if( disc->track[i].lba <= lba &&
126 lba < (disc->track[i].lba + disc->track[i].sector_count) ) {
127 return i+1;
128 }
129 }
130 return -1;
131 }
133 #define CHECK_DISC(disc) do { \
134 if( disc == NULL ) { return PKT_ERR_NODISC; } \
135 disc->check_status(disc); \
136 if( disc->disc_type == IDE_DISC_NONE ) { return PKT_ERR_NODISC; } \
137 } while(0)
139 gdrom_error_t gdrom_disc_check_media( gdrom_disc_t disc )
140 {
141 CHECK_DISC(disc);
142 return PKT_ERR_OK;
143 }
145 gdrom_error_t gdrom_disc_get_toc( gdrom_disc_t disc, unsigned char *buf )
146 {
147 struct gdrom_toc {
148 uint32_t track[99];
149 uint32_t first, last, leadout;
150 };
152 struct gdrom_toc *toc = (struct gdrom_toc *)buf;
153 int i;
155 CHECK_DISC(disc);
157 for( i=0; i<disc->track_count; i++ ) {
158 toc->track[i] = htonl( disc->track[i].lba ) | disc->track[i].flags;
159 }
160 toc->first = 0x0100 | disc->track[0].flags;
161 toc->last = (disc->track_count<<8) | disc->track[i-1].flags;
162 toc->leadout = htonl(disc->track[i-1].lba + disc->track[i-1].sector_count) |
163 disc->track[i-1].flags;
164 for( ;i<99; i++ )
165 toc->track[i] = 0xFFFFFFFF;
166 return PKT_ERR_OK;
167 }
169 gdrom_error_t gdrom_disc_get_session_info( gdrom_disc_t disc, int session, unsigned char *buf )
170 {
171 CHECK_DISC(disc);
173 struct gdrom_track *last_track = &disc->track[disc->track_count-1];
174 unsigned int end_of_disc = last_track->lba + last_track->sector_count;
175 int i;
176 buf[0] = 0x01; /* Disc status? */
177 buf[1] = 0;
179 if( session == 0 ) {
180 buf[2] = last_track->session+1; /* last session */
181 buf[3] = (end_of_disc >> 16) & 0xFF;
182 buf[4] = (end_of_disc >> 8) & 0xFF;
183 buf[5] = end_of_disc & 0xFF;
184 return PKT_ERR_OK;
185 } else {
186 session--;
187 for( i=0; i<disc->track_count; i++ ) {
188 if( disc->track[i].session == session ) {
189 buf[2] = i+1; /* first track of session */
190 buf[3] = (disc->track[i].lba >> 16) & 0xFF;
191 buf[4] = (disc->track[i].lba >> 8) & 0xFF;
192 buf[5] = disc->track[i].lba & 0xFF;
193 return PKT_ERR_OK;
194 }
195 }
196 return PKT_ERR_BADFIELD; /* No such session */
197 }
198 }
200 gdrom_error_t gdrom_disc_get_short_status( gdrom_disc_t disc, uint32_t lba, unsigned char *buf )
201 {
202 CHECK_DISC(disc);
204 int track_no = gdrom_disc_get_track_by_lba( disc, lba );
205 if( track_no == -1 ) {
206 track_no = 1;
207 lba = 150;
208 }
209 struct gdrom_track *track = &disc->track[track_no-1];
210 uint32_t offset = lba - track->lba;
211 buf[0] = 0x00;
212 buf[1] = 0x15; /* audio status ? */
213 buf[2] = 0x00;
214 buf[3] = 0x0E;
215 buf[4] = track->flags;
216 buf[5] = track_no;
217 buf[6] = 0x01; /* ?? */
218 buf[7] = (offset >> 16) & 0xFF;
219 buf[8] = (offset >> 8) & 0xFF;
220 buf[9] = offset & 0xFF;
221 buf[10] = 0;
222 buf[11] = (lba >> 16) & 0xFF;
223 buf[12] = (lba >> 8) & 0xFF;
224 buf[13] = lba & 0xFF;
225 return PKT_ERR_OK;
226 }
228 int gdrom_disc_get_drive_status( gdrom_disc_t disc )
229 {
230 if( disc == NULL ) {
231 return IDE_DISC_NONE;
232 }
234 disc->check_status(disc);
235 if( disc->disc_type == IDE_DISC_NONE ) {
236 return IDE_DISC_NONE;
237 } else {
238 return disc->disc_type | IDE_DISC_READY;
239 }
240 }
242 /**
243 * Check the disc for a useable DC bootstrap, and update the disc
244 * with the title accordingly.
245 * @return TRUE if we found a bootstrap, otherwise FALSE.
246 */
247 gboolean gdrom_disc_read_title( gdrom_disc_t disc ) {
248 if( disc->track_count > 0 ) {
249 /* Find the first data track of the last session */
250 int last_session = disc->track[disc->track_count-1].session;
251 int i, boot_track = -1;
252 for( i=disc->track_count-1; i>=0 && disc->track[i].session == last_session; i-- ) {
253 if( disc->track[i].flags & TRACK_DATA ) {
254 boot_track = i;
255 }
256 }
257 if( boot_track != -1 ) {
258 unsigned char boot_sector[MAX_SECTOR_SIZE];
259 uint32_t length = sizeof(boot_sector);
260 if( disc->read_sector( disc, disc->track[boot_track].lba, 0x28,
261 boot_sector, &length ) == PKT_ERR_OK ) {
262 if( memcmp( boot_sector, "SEGA SEGAKATANA SEGA ENTERPRISES", 32) == 0 ) {
263 /* Got magic */
264 memcpy( disc->title, boot_sector+128, 128 );
265 for( i=127; i>=0; i-- ) {
266 if( !isspace(disc->title[i]) )
267 break;
268 }
269 disc->title[i+1] = '\0';
270 }
271 bootstrap_dump(boot_sector, FALSE);
272 return TRUE;
273 }
274 }
275 }
276 return FALSE;
277 }
.