aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/libpsxcd/psxcd.c
blob: 5be9eec4c7790c70c41bbe85ed0d41c38ff4ab4d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
#include <stdio.h>
#include "psxcd.h"

extern volatile char _cd_ack_wait;
extern volatile unsigned char _cd_last_int;
extern volatile unsigned char _cd_last_mode;
extern volatile unsigned char _cd_status;
extern volatile CdlCB _cd_callback_int1_data;
volatile unsigned char *_cd_result_ptr;

extern volatile char _cd_media_changed;

void _cd_init(void);
void _cd_control(unsigned char com, unsigned char *param, int plen);
void _cd_wait_ack(void);
void _cd_wait(void);

int CdInit(int mode)
{
	// Sets up CD-ROM hardware and low-level subsystem
	_cd_init();
	
	// So CD ISO file system component will update the ISO descriptor
	_cd_media_changed = 1;
	
	// Issue commands to initialize the CD-ROM hardware
	CdControl(CdlNop, 0, 0);
	CdControl(CdlInit, 0, 0);
	
	if( CdSync(0, 0) != CdlDiskError )
	{
		CdControl(CdlDemute, 0, 0);
		printf("psxcd: Init Ok!\n");
	}
	else
	{
		printf("psxcd: Error initializing. Bad disc/drive or no disc inserted.\n");
	}
	
	return 1;
}

int CdControl(unsigned char com, unsigned char *param, unsigned char *result)
{	
	// Don't issue command if ack is not received yet
	if( _cd_ack_wait )
	{
		return 0;
	}
	
	_cd_result_ptr = result;
	
	CdControlF(com, param);
	_cd_wait_ack();
	
	return 1;
}

int CdControlB(unsigned char com, unsigned char *param, unsigned char *result)
{
	if( !CdControl(com, param, result) )
	{
		return 0;
	}
	
	CdSync(0, 0);
	return 1;
}

int CdControlF(unsigned char com, unsigned char *param)
{
	int param_len=0;
	
	// Command specific parameters
	switch(com)
	{
		case CdlSetloc:
			param_len = 3;
			break;
		case CdlPlay:
			if( param )
			{
				param_len = 1;
			}
			break;
		case CdlSetfilter:
			param_len = 2;
			break;
		case CdlSetmode:
			param_len = 1;
			break;
		case CdlSetsession:
			param_len = 1;
			break;
		case CdlTest:
			param_len = 1;
			break;
		case CdlGetTD:
			param_len = 1;
	}
	
	// Issue Setloc if parameters are specified on CdlReadN and CdlReadS
	if( ( com == CdlReadN ) || ( com == CdlReadS ) )
	{
		if( param )
		{
			_cd_control(CdlSetloc, param, 3);
		}
	}
	
	// Issue CD command
	_cd_control(com, param, param_len);
	
	return 1;
}

int CdSync(int mode, unsigned char *result)
{
	int cdirq;
	
	if( mode )
	{
		if( result )
		{
			*result = _cd_status;
		}
		
		cdirq = _cd_last_int;
		if( cdirq == CdlAcknowledge )
		{
			cdirq = CdlComplete;
		}
		return cdirq;
	}
	
	_cd_wait();
	
	if( result )
	{
		*result = _cd_status;
	}
	
	cdirq = _cd_last_int;
	if( cdirq == CdlAcknowledge )
	{
		cdirq = CdlComplete;
	}
	
	return cdirq;
}

int CdGetToc(CdlLOC *toc)
{
	u_char track_info[8];
	int i,tracks;
	
	// Get number of tracks
	if( !CdControl(CdlGetTN, 0, track_info) )
	{
		return 0;
	}
	
	if( CdSync(1, 0) != CdlComplete )
	{
		return 0;
	}
	
	tracks = 1+(btoi(track_info[2])-btoi(track_info[1]));
	
	// Get track positions
	for(i=0; i<tracks; i++)
	{
		int t = itob(1+i);
		if( !CdControl(CdlGetTD, (u_char*)&t, (u_char*)&toc[i]) )
		{
			return 0;
		}
		if( CdSync(1, 0) != CdlComplete )
		{
			return 0;
		}
		toc[i].sector = 0;
		toc[i].track = 1+i;
	}
	
	return tracks;
}

CdlLOC *CdIntToPos(int i, CdlLOC *p) {

	i += 150;
	
	p->minute = itob((i/75)/60);
	p->second = itob((i/75)%60);
	p->sector = itob(i%75);

	return p;
	
}

int CdPosToInt(CdlLOC *p)
{	
	return ((75*(btoi(p->minute)*60))+(75*btoi(p->second))+btoi(p->sector))-150;
}

int CdStatus(void)
{	
	return _cd_status;	
}

int CdMode(void)
{
	return _cd_last_mode;
}


// CD data read routines
volatile int _cd_sector_count = 0;
volatile unsigned int *_cd_read_addr;
volatile unsigned char _cd_read_result[8];
volatile unsigned int _cd_read_oldcb;
volatile unsigned int _cd_read_sector_sz;
volatile CdlCB _cd_read_cb;

// Sector callback
static void _CdReadReadyCallback(int status, unsigned char *result)
{
	if( status == CdlDataReady )
	{
		// Fetch sector from CD controller
		CdGetSector((void*)_cd_read_addr, _cd_read_sector_sz);
		
		// Increment destination address
		_cd_read_addr += _cd_read_sector_sz>>2;
	
		// Subtract sector count
		_cd_sector_count--;
	}
	
	// End reading with pause command when sector count reaches zero
	// or when an error occurs
	if( ( _cd_sector_count <= 0 ) || ( status == CdlDiskError ) )
	{
		// Stop reading
		_cd_control(CdlPause, 0, 0);
		
		// Revert previous ready callback
		_cd_callback_int1_data = (CdlCB)_cd_read_oldcb;
		
		// Execute read completion callback
		if( _cd_read_cb )
		{
			_cd_read_cb(status, result);
		}
	}
}

int CdRead(int sectors, unsigned int *buf, int mode)
{
	// Set sectors to read count
	_cd_sector_count = sectors;
	_cd_read_addr = buf;
	
	// Determine sector based on mode flags
	if( mode & CdlModeSize0 )
	{
		_cd_read_sector_sz = 2328;
	}
	else if( mode & CdlModeSize1 )
	{
		_cd_read_sector_sz = 2340;
	}
	else
	{
		_cd_read_sector_sz = 2048;
	}
	
	// Set readt callback
	_cd_read_oldcb = CdReadyCallback(_CdReadReadyCallback);
	
	// Set specified mode
	CdControl(CdlSetmode, (unsigned char*)&mode, 0);
	
	// Begin reading sectors
	CdControl(CdlReadN, 0, (unsigned char*)_cd_read_result);
	
	return 0;
}

int CdReadSync(int mode, unsigned char *result)
{
	if( mode )
	{
		if( CdSync(1, 0) == CdlDiskError )
		{
			return -1;
		}
		return _cd_sector_count;
	}
	
	while(_cd_sector_count > 0);
	if( CdSync(0, result) != CdlComplete )
	{
		return -1;
	}
	
	return 0;
}

unsigned int CdReadCallback(CdlCB func)
{
	unsigned int old_func;
	
	old_func = (unsigned int)_cd_read_cb;
	
	_cd_read_cb = func;
	
	return old_func;
}