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