1 /*
2 * OpenBOR - http://www.LavaLit.com
3 * -----------------------------------------------------------------------
4 * Licensed under the BSD license, see LICENSE in OpenBOR root for details.
5 *
6 * Copyright (c) 2004 - 2011 OpenBOR Team
7 */
8
9 /////////////////////////////////////////////////////////////////////////////
10
11 #include "dcport.h"
12
13 #include "bios.h"
14 #include "gdrom.h"
15
16 /////////////////////////////////////////////////////////////////////////////
17
18 #define CMD_PIOREAD 16
19 #define CMD_DMAREAD 17
20 #define CMD_GETTOC 18
21 #define CMD_GETTOC2 19
22 #define CMD_PLAY 20
23 #define CMD_PLAY2 21
24 #define CMD_PAUSE 22
25 #define CMD_RELEASE 23
26 #define CMD_INIT 24
27 #define CMD_SEEK 27
28 #define CMD_READ 28
29 #define CMD_STOP 33
30 #define CMD_GETSCD 34
31 #define CMD_GETSES 35
32
33 #define GDROM_STATUS_FAILED (-1)
34 #define GDROM_STATUS_BUSY (0)
35 #define GDROM_STATUS_PAUSED (1)
36 #define GDROM_STATUS_STANDBY (2)
37 #define GDROM_STATUS_PLAYING (3)
38 #define GDROM_STATUS_SEEKING (4)
39 #define GDROM_STATUS_SCANNING (5)
40 #define GDROM_STATUS_LIDOPEN (6)
41 #define GDROM_STATUS_NODISC (7)
42
43 static struct {
44 unsigned entry[99];
45 unsigned first, last;
46 unsigned dunno;
47 } gdrom_toc;
48
49 // Split TOC->entry into its components
50 #define GDROM_TOC_LBA(n) ((n)&0x00FFFFFF)
51 #define GDROM_TOC_ADR(n) (((n)>>24)&0xF)
52 #define GDROM_TOC_CTRL(n) (((n)>>28)&0xF)
53 // Use TOC_TRACK() to convert TOC->first and TOC->last entry to track #
54 #define GDROM_TOC_TRACK(n) (((n)>>16)&0xFF)
55
56 /////////////////////////////////////////////////////////////////////////////
57
58 #define MAXREAD (8)
59 static char gdrom_readbuffer[(2048*MAXREAD)+32];
60 #define GDROM_READBUFFER_P2 ((char*)((((int)gdrom_readbuffer)|0xA000001F)+1))
61
62 /////////////////////////////////////////////////////////////////////////////
63
64 static int currently_executing_read_lba = -1;
65 static int currently_executing_read_size = 0;
66 static char *currently_executing_read_dest = NULL;
67 static int currently_executing_read_q = 0;
68 static int currently_executing_read_retries = 0;
69 //static int currently_executing_read_reinit = 0;
70
71 /////////////////////////////////////////////////////////////////////////////
72
gdrom_queue_current_read(void)73 static void gdrom_queue_current_read(void) {
74 int param[4];
75 int s = currently_executing_read_size;
76 if(s > MAXREAD) s = MAXREAD;
77 param[0] = currently_executing_read_lba;
78 param[1] = s;
79 param[2] = (int)GDROM_READBUFFER_P2;
80 param[3] = 0; // dunno
81 // currently_executing_read_q = bios_gdGdcReqCmd(CMD_PIOREAD, param);
82 currently_executing_read_q = bios_gdGdcReqCmd(CMD_DMAREAD, param);
83 }
84
85 /////////////////////////////////////////////////////////////////////////////
86 //
87 // Returns nonzero if busy
88 //
gdrom_poll(void)89 int gdrom_poll(void) {
90 int param[4];
91 int r, s;
92 bios_gdGdcExecServer();
93 if(currently_executing_read_lba < 0) return 0;
94 param[0] = 0; param[1] = 0; param[2] = 0; param[3] = 0;
95 r = bios_gdGdcGetCmdStat(currently_executing_read_q, param);
96 if(r == 1) return 1;
97
98 // retry needed
99 if(r != 2) {
100 //printf("gdrom retry needed(r=%d, lba=%d, size=%d)\n",r,currently_executing_read_lba,currently_executing_read_size);
101 currently_executing_read_retries++;
102 gdrom_queue_current_read();
103 return 1;
104 }
105
106 // last read op was a success
107 currently_executing_read_retries = 0;
108
109 // done with one piece
110 s = currently_executing_read_size;
111 if(s > MAXREAD) s = MAXREAD;
112 memcpy(
113 currently_executing_read_dest,
114 GDROM_READBUFFER_P2,
115 2048*s
116 );
117 currently_executing_read_lba += s;
118 currently_executing_read_size -= s;
119 currently_executing_read_dest += 2048*s;
120 // done?
121 if(currently_executing_read_size <= 0) {
122 currently_executing_read_lba = -1;
123 return 0;
124 }
125
126 // otherwise queue up the next piece
127 gdrom_queue_current_read();
128 return 1;
129 }
130
131 /////////////////////////////////////////////////////////////////////////////
132 //
133 // Blocks until the prior read is done (you can ensure it won't block if you
134 // check gdrom_poll yourself), and then queues up a new read
135 //
136 // Danger: you do not want to try doing this on out-of-range sectors
137 //
gdrom_readsectors(void * dest,int lba,int num)138 void gdrom_readsectors(void *dest, int lba, int num) {
139 while(gdrom_poll());
140 //printf("gdrom_readsectors(dest,lba=%d,num=%d)\n",lba,num);
141
142 currently_executing_read_dest = dest;
143 currently_executing_read_lba = lba;
144 currently_executing_read_size = num;
145 gdrom_queue_current_read();
146 }
147
148 /////////////////////////////////////////////////////////////////////////////
149 //
150 // quick and dirty blocking read
151 //
quickblockread(int lba,int num)152 static int quickblockread(int lba, int num) {
153 int i, j;
154 int param[4];
155 param[0] = lba;
156 param[1] = num;
157 param[2] = (int)GDROM_READBUFFER_P2;
158 param[3] = 0;
159 i = bios_gdGdcReqCmd(CMD_PIOREAD, param);
160 for(;;) {
161 bios_gdGdcExecServer();
162 param[0] = 0; param[1] = 0; param[2] = 0; param[3] = 0;
163 j = bios_gdGdcGetCmdStat(i, param);
164 if(j != 1) break;
165 }
166 return j;
167 }
168
169 /////////////////////////////////////////////////////////////////////////////
170 //
171 // Initialize gdrom system
172 // returns the starting LBA of the main data track
173 //
gdrom_init(void)174 int gdrom_init(void) {
175 int param[4];
176 int i, j;
177 int first, last, track;
178 int probable_lba = -1;
179 int probable2_lba = -1;
180 int definite_lba = -1;
181
182 // Reactivate GD-ROM drive
183 *((volatile int*)0xA05F74E4) = 0x001FFFFF;
184 for(i = 0; i<(0x200000/4); i++) {
185 j += ((volatile int*)0xA0000000)[i];
186 }
187
188 // Reset GD system functions
189 bios_gdGdcInitSystem();
190
191 // Try to initialize the disc
192 tryinit:
193
194 i = bios_gdGdcReqCmd(CMD_INIT, NULL);
195 for(;;) {
196 bios_gdGdcExecServer();
197 param[0] = 0; param[1] = 0; param[2] = 0; param[3] = 0;
198 j = bios_gdGdcGetCmdStat(i, param);
199 if(j != 1) break;
200 }
201 if(j != 2) goto tryinit;
202
203 // Set the read mode
204 param[0] = 0; // 0 = set, 1 = get
205 param[1] = 8192; // ?
206 param[2] = 0; // autodetect read mode
207 param[3] = 2048; // sector size
208 if(bios_gdGdcChangeDataType(param) < 0) goto tryinit;
209
210 // Try to read the TOC
211 param[0] = 0; // session
212 param[1] = (int)(&gdrom_toc); // toc
213 i = bios_gdGdcReqCmd(CMD_GETTOC2, param);
214 for(;;) {
215 bios_gdGdcExecServer();
216 param[0] = 0; param[1] = 0; param[2] = 0; param[3] = 0;
217 j = bios_gdGdcGetCmdStat(i, param);
218 if(j != 1) break;
219 }
220 if(j != 2) goto tryinit;
221
222 first = GDROM_TOC_TRACK(gdrom_toc.first);
223 last = GDROM_TOC_TRACK(gdrom_toc.last);
224 if(first < 1 || last > 99 || first > last) {
225 // corrupt toc data, maybe
226 goto tryinit;
227 }
228 for(track = last; track >= first; track--) {
229 if(GDROM_TOC_CTRL(gdrom_toc.entry[track-1]) & 4) {
230 int lba = GDROM_TOC_LBA(gdrom_toc.entry[track-1]);
231 if(probable_lba < 0) probable_lba = lba;
232 // // try to read the boot sector
233 // if(quickblockread(lba, 1) != 2) continue;
234 // // look for "SEGA" in the boot sector
235 // if(memcmp(GDROM_READBUFFER_P2, "SEGA", 4)) continue;
236 // if(probable2_lba < 0) probable2_lba = lba;
237 // try to read the first sector after the boot sector
238 if(quickblockread(lba+16, 1) != 2) continue;
239 // look for "CD001"
240 if(memcmp(GDROM_READBUFFER_P2+1, "CD001", 5)) continue;
241 // success!
242 definite_lba = lba;
243 break;
244 }
245 }
246
247 // now return either a definite or a probable lba
248 if(definite_lba >= 0) return definite_lba;
249 if(probable2_lba >= 0) return probable2_lba;
250 if(probable_lba >= 0) return probable_lba;
251
252 // and if we don't have any of those, we're really screwed, oh well
253 // we could try running through tryinit again, but that would probably be
254 // fruitless
255 return -1;
256 }
257
258 /////////////////////////////////////////////////////////////////////////////
259