1 |
/* |
2 |
* PearPC |
3 |
* cd.cc |
4 |
* |
5 |
* Copyright (C) 2003 Sebastian Biallas (sb@biallas.net) |
6 |
* |
7 |
* This program is free software; you can redistribute it and/or modify |
8 |
* it under the terms of the GNU General Public License version 2 as |
9 |
* published by the Free Software Foundation. |
10 |
* |
11 |
* This program is distributed in the hope that it will be useful, |
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
* GNU General Public License for more details. |
15 |
* |
16 |
* You should have received a copy of the GNU General Public License |
17 |
* along with this program; if not, write to the Free Software |
18 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 |
*/ |
20 |
|
21 |
#include <cstdio> |
22 |
#include <cstring> |
23 |
#include "errno.h" |
24 |
|
25 |
#include "debug/tracers.h" |
26 |
#include "tools/data.h" |
27 |
#include "cd.h" |
28 |
#include "scsicmds.h" |
29 |
|
30 |
#define MM_DEVICE_PROFILE_CDROM 0x0008 // .242 |
31 |
#define MM_DEVICE_PROFILE_DVDROM 0x0010 // d.375 |
32 |
|
33 |
#define MM_DEVICE_FEATURE_PROFILE 0x0000 |
34 |
#define MM_DEVICE_FEATURE_CORE 0x0001 |
35 |
#define MM_DEVICE_FEATURE_MORPHING 0x0002 |
36 |
#define MM_DEVICE_FEATURE_REMOVABLE 0x0003 |
37 |
#define MM_DEVICE_FEATURE_RANDOM_READ 0x0010 |
38 |
#define MM_DEVICE_FEATURE_CD_READ 0x001e |
39 |
#define MM_DEVICE_FEATURE_DVD_READ 0x001f |
40 |
#define MM_DEVICE_FEATURE_INC_WRITE 0x0021 // .192 |
41 |
#define MM_DEVICE_FEATURE_xx 0x002d |
42 |
#define MM_DEVICE_FEATURE_xx2 0x002e |
43 |
#define MM_DEVICE_FEATURE_POWER 0x0100 |
44 |
#define MM_DEVICE_FEATURE_CD_AUDIO 0x0103 // .224 |
45 |
#define MM_DEVICE_FEATURE_TIMEOUT 0x0105 |
46 |
#define MM_DEVICE_FEATURE_DVD_CSS 0x0106 // .228 |
47 |
#define MM_DEVICE_FEATURE_RT_STREAM 0x0107 |
48 |
|
49 |
|
50 |
CDROMDevice::CDROMDevice(const char *name) |
51 |
: IDEDevice(name) |
52 |
{ |
53 |
mFeatures = new AVLTree(true); |
54 |
mProfiles = new AVLTree(true); |
55 |
addProfile(MM_DEVICE_PROFILE_DVDROM); |
56 |
curProfile = MM_DEVICE_PROFILE_DVDROM; |
57 |
// Profile DVDROM implies these features: |
58 |
addFeature(MM_DEVICE_FEATURE_PROFILE); |
59 |
addFeature(MM_DEVICE_FEATURE_CORE); |
60 |
addFeature(MM_DEVICE_FEATURE_MORPHING); |
61 |
addFeature(MM_DEVICE_FEATURE_REMOVABLE); |
62 |
addFeature(MM_DEVICE_FEATURE_RANDOM_READ); |
63 |
addFeature(MM_DEVICE_FEATURE_CD_READ); |
64 |
addFeature(MM_DEVICE_FEATURE_DVD_READ); |
65 |
addFeature(MM_DEVICE_FEATURE_POWER); |
66 |
addFeature(MM_DEVICE_FEATURE_TIMEOUT); |
67 |
addFeature(MM_DEVICE_FEATURE_RT_STREAM); |
68 |
|
69 |
mReady = false; |
70 |
mLocked = false; |
71 |
is_dvd = false; |
72 |
} |
73 |
|
74 |
CDROMDevice::~CDROMDevice() |
75 |
{ |
76 |
delete mFeatures; |
77 |
delete mProfiles; |
78 |
} |
79 |
|
80 |
bool CDROMDevice::isReady() |
81 |
{ |
82 |
return mReady; |
83 |
} |
84 |
|
85 |
bool CDROMDevice::setReady(bool aReady) |
86 |
{ |
87 |
if (isLocked()) return false; |
88 |
mReady = aReady; |
89 |
return true; |
90 |
} |
91 |
|
92 |
bool CDROMDevice::isLocked() |
93 |
{ |
94 |
return mLocked; |
95 |
} |
96 |
|
97 |
bool CDROMDevice::setLock(bool aLocked) |
98 |
{ |
99 |
if (!isReady()) return false; |
100 |
mLocked = aLocked; |
101 |
return true; |
102 |
} |
103 |
|
104 |
bool CDROMDevice::toggleLock() |
105 |
{ |
106 |
return setLock(!isLocked()); |
107 |
} |
108 |
|
109 |
void CDROMDevice::MSFfromLBA(MSF &msf, LBA lba) |
110 |
{ |
111 |
lba += 150; |
112 |
msf.m = lba / 4500; |
113 |
msf.s = (lba % 4500) / 75; |
114 |
msf.f = lba % 75; |
115 |
} |
116 |
|
117 |
void CDROMDevice::LBAfromMSF(LBA &lba, MSF msf) |
118 |
{ |
119 |
lba = (((msf.m*60) + msf.s) * 75) + msf.f - 150; |
120 |
} |
121 |
|
122 |
bool CDROMDevice::validLBA(LBA lba) |
123 |
{ |
124 |
return true; |
125 |
} |
126 |
|
127 |
uint CDROMDevice::getBlockSize() |
128 |
{ |
129 |
return 2048; |
130 |
} |
131 |
|
132 |
uint CDROMDevice::getBlockCount() |
133 |
{ |
134 |
return getCapacity(); |
135 |
} |
136 |
|
137 |
int CDROMDevice::getConfig(byte *buf, int aLen, byte RT, int first) |
138 |
{ |
139 |
// .284 |
140 |
byte header[] = { |
141 |
0x00, 0x00, 0x00, 0x00, // length, filled later |
142 |
0x00, 0x00, // res |
143 |
curProfile >> 8, curProfile, |
144 |
}; |
145 |
int len = sizeof header - 4; |
146 |
switch (RT) { |
147 |
case 0x00: |
148 |
// return all |
149 |
foreach(UInt, f, *mFeatures, { |
150 |
int v = f->value; |
151 |
if (v >= first) |
152 |
len += getFeature(buf+len, aLen-len, v); |
153 |
}); |
154 |
break; |
155 |
case 0x01: |
156 |
// return all with current bit |
157 |
foreach(UInt, f, *mFeatures, { |
158 |
int v = f->value; |
159 |
if (v >= first /* FIXME: && (current bit) */) |
160 |
len += getFeature(buf+len, aLen-len, v); |
161 |
}); |
162 |
break; |
163 |
case 0x02: |
164 |
// return specific |
165 |
len += getFeature(buf+len, aLen-len, first); |
166 |
break; |
167 |
default: |
168 |
IO_IDE_ERR("unknown RT in CDROMDevice::getConfig()\n"); |
169 |
return -1; |
170 |
} |
171 |
header[0] = len >> 24; header[1] = len >> 16; header[2] = len >> 8; header[3] = len; |
172 |
put(buf, aLen, header, sizeof header); |
173 |
return len; |
174 |
} |
175 |
|
176 |
int CDROMDevice::modeSense(byte *buf, int aLen, int pc, int page) |
177 |
{ |
178 |
return 0; |
179 |
} |
180 |
|
181 |
void CDROMDevice::addFeature(int feature) |
182 |
{ |
183 |
mFeatures->insert(new UInt(feature)); |
184 |
} |
185 |
|
186 |
void CDROMDevice::addProfile(int profile) |
187 |
{ |
188 |
mProfiles->insert(new UInt(profile)); |
189 |
} |
190 |
|
191 |
int CDROMDevice::getFeature(byte *buf, int aLen, int feature) |
192 |
{ |
193 |
if (aLen <= 0) return 0; |
194 |
switch (feature) { |
195 |
case MM_DEVICE_FEATURE_PROFILE: { |
196 |
int count = mProfiles->count(); |
197 |
byte list[count*4]; |
198 |
int idx = 0; |
199 |
// FIXME: foreachbwd ?? |
200 |
foreach(UInt, p, *mProfiles, { |
201 |
int v = p->value; |
202 |
list[idx++] = v>>8; |
203 |
list[idx++] = v; |
204 |
list[idx++] = (v == curProfile) ? 0x01 : 0x00; |
205 |
list[idx++] = 0x00; |
206 |
}); |
207 |
return createFeature(buf, aLen, MM_DEVICE_FEATURE_PROFILE, 0, true, true, list, count*4); |
208 |
} |
209 |
case MM_DEVICE_FEATURE_CORE: { |
210 |
byte core[] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00}; // 02=ATAPI, DBEvent=0 |
211 |
return createFeature(buf, aLen, MM_DEVICE_FEATURE_CORE, 0, true, true, core, sizeof core); |
212 |
} |
213 |
case MM_DEVICE_FEATURE_MORPHING: { |
214 |
byte morph[] = {0x00, 0x00, 0x00, 0x00}; // 1. ASYNC=0 (ATAPI) |
215 |
return createFeature(buf, aLen, MM_DEVICE_FEATURE_MORPHING, 1, true, true, morph, sizeof morph); |
216 |
} |
217 |
case MM_DEVICE_FEATURE_REMOVABLE: { |
218 |
byte remove[] = {0x19, 0x00, 0x00, 0x00}; // Tray-Type-Loading, Eject=1, Jmpr=0, LockAllow=1 |
219 |
return createFeature(buf, aLen, MM_DEVICE_FEATURE_REMOVABLE, 0, true, true, remove, sizeof remove); |
220 |
} |
221 |
case MM_DEVICE_FEATURE_RANDOM_READ: { |
222 |
byte randomread[] = { |
223 |
0x00, 0x00, 0x08, 0x00, // Logical Block Size |
224 |
0x00, 0x10, // Blocking |
225 |
0x00, |
226 |
0x00, // PP=0 |
227 |
}; |
228 |
// FIXME: persistent, current? |
229 |
return createFeature(buf, aLen, MM_DEVICE_FEATURE_RANDOM_READ, 0, true, true, randomread, sizeof randomread); |
230 |
} |
231 |
case MM_DEVICE_FEATURE_CD_READ: { |
232 |
byte cdread[] = {0x00, 0x00, 0x00, 0x00}; // DAP=0, C2=0, CD-Text=0 |
233 |
// FIXME: persistent, current? |
234 |
return createFeature(buf, aLen, MM_DEVICE_FEATURE_CD_READ, 2, true, true, cdread, sizeof cdread); |
235 |
} |
236 |
case MM_DEVICE_FEATURE_DVD_READ: { |
237 |
byte dvdread[] = {0x00, 0x00, 0x00, 0x00}; //MULTI110=0, Dual-R=0 |
238 |
|
239 |
// FIXME: persistent, current? |
240 |
return createFeature(buf, aLen, MM_DEVICE_FEATURE_DVD_READ, 2, true, true, dvdread, sizeof dvdread); |
241 |
} |
242 |
case MM_DEVICE_FEATURE_POWER: |
243 |
// FIXME: persistent, current? |
244 |
return createFeature(buf, aLen, MM_DEVICE_FEATURE_POWER, 0, true, true, NULL, 0); |
245 |
case MM_DEVICE_FEATURE_TIMEOUT: { |
246 |
byte timeout[] = {0x00, 0x00, 0x00, 0x00}; // Group 3=0 |
247 |
return createFeature(buf, aLen, MM_DEVICE_FEATURE_TIMEOUT, 0, true, true, timeout, sizeof timeout); |
248 |
} |
249 |
case MM_DEVICE_FEATURE_RT_STREAM: { |
250 |
byte rt_stream[] = { 0x00, 0x00, 0x00, 0x00 }; // RBCD=0 SCS=0 MP2A=0 WSPD=0 SW=0 |
251 |
|
252 |
return createFeature(buf, aLen, MM_DEVICE_FEATURE_RT_STREAM, 0, true, true, rt_stream, sizeof rt_stream); |
253 |
} |
254 |
default: |
255 |
// return size==0 for unimplemented / unsupported features |
256 |
return 0; |
257 |
} |
258 |
} |
259 |
|
260 |
int CDROMDevice::createFeature(byte *buf, int len, int feature, int version, bool pp, bool cur, byte *add, int size) |
261 |
{ |
262 |
byte header[] = { |
263 |
feature>>8, feature, |
264 |
version<<2|(pp?0x2:0)|(cur?0x1:0), |
265 |
size, |
266 |
}; |
267 |
int l = put(buf, len, header, sizeof header); |
268 |
return l+put(buf+l, len-l, add, size); |
269 |
} |
270 |
|
271 |
int CDROMDevice::put(byte *buf, int aLen, byte *src, int size) |
272 |
{ |
273 |
int len = 0; |
274 |
while (size > 0) { |
275 |
if (aLen > 0) { |
276 |
*(buf++) = *(src++); |
277 |
} else { |
278 |
len += size; |
279 |
break; |
280 |
} |
281 |
size--; |
282 |
aLen--; |
283 |
len++; |
284 |
|
285 |
} |
286 |
return len; |
287 |
} |
288 |
|
289 |
int CDROMDevice::writeBlock(byte *buf) |
290 |
{ |
291 |
IO_IDE_ERR("attempt to write to CDROM\n"); |
292 |
return 0; |
293 |
} |
294 |
|
295 |
int CDROMDevice::readDVDStructure(byte *buf, int len, uint8 subcommand, uint32 address, uint8 layer, uint8 format, uint8 AGID, uint8 control) |
296 |
{ |
297 |
uint32 capacity = getCapacity(); |
298 |
|
299 |
if (!is_dvd) { |
300 |
return 0; |
301 |
} |
302 |
|
303 |
if (subcommand == 0x0000) { |
304 |
switch (format) { |
305 |
case 0x00: //Physical format information |
306 |
buf[0] = 0; |
307 |
buf[1] = 21; |
308 |
|
309 |
buf[2] = 0x00; // reserved |
310 |
buf[3] = 0x00; // reserved |
311 |
|
312 |
buf[4] = 0x01; //DVD-ROM + Version 1.0x |
313 |
buf[5] = 0x0f; //120mm + No max rate specified |
314 |
buf[6] = 0x00; //1 layer + PTP + embossed data |
315 |
buf[7] = 0x00; //0.267um/bit + 0.74um/track |
316 |
|
317 |
buf[8] = 0x00; //pad |
318 |
buf[9] = 0x03; //start of physical data |
319 |
buf[10] = 0x00; //start of physical data |
320 |
buf[11] = 0x00; //start of physical data |
321 |
|
322 |
buf[12] = 0x00; //pad |
323 |
buf[13] = capacity >> 16; //end of physical data |
324 |
buf[14] = capacity >> 8; //end of physical data |
325 |
buf[15] = capacity; //end of physical data |
326 |
|
327 |
buf[16] = 0x00; //pad |
328 |
buf[17] = 0x00; //end sector number in layer 0 |
329 |
buf[18] = 0x00; //end sector number in layer 0 |
330 |
buf[19] = 0x00; //end sector number in layer 0 |
331 |
|
332 |
buf[20] = 0x00; //BCA + reserved |
333 |
|
334 |
// 21-n : defined as reserved for DVD-ROMs |
335 |
|
336 |
return 21; |
337 |
|
338 |
case 0x01: // Copyright Information |
339 |
buf[0] = 0; |
340 |
buf[1] = 8; |
341 |
|
342 |
buf[2] = 0; |
343 |
buf[3] = 0; |
344 |
|
345 |
buf[4] = 0x00; // no copyright information |
346 |
buf[5] = 0x00; // all regions allowed |
347 |
buf[6] = 0x00; // reserved |
348 |
buf[7] = 0x00; // reserved |
349 |
|
350 |
return 8; |
351 |
|
352 |
default: |
353 |
ht_printf("readDVDStructure with Unsupported Format (%i)\n", format); |
354 |
return 0; |
355 |
} |
356 |
} else { |
357 |
ht_printf("readDVDStructure on Unsupported Media (%i)\n", subcommand); |
358 |
return 0; |
359 |
} |
360 |
} |
361 |
|
362 |
void CDROMDevice::activateDVD(bool onoff) |
363 |
{ |
364 |
is_dvd = onoff; |
365 |
} |
366 |
|
367 |
bool CDROMDevice::isDVD(void) |
368 |
{ |
369 |
return is_dvd; |
370 |
} |
371 |
|
372 |
// ----------------------------- File based CDROM device ------------------------------------ |
373 |
|
374 |
/* |
375 |
* |
376 |
*/ |
377 |
CDROMDeviceFile::CDROMDeviceFile(const char *name) |
378 |
: CDROMDevice(name) |
379 |
{ |
380 |
mFile = NULL; |
381 |
} |
382 |
|
383 |
CDROMDeviceFile::~CDROMDeviceFile() |
384 |
{ |
385 |
if (mFile) sys_fclose(mFile); |
386 |
} |
387 |
|
388 |
uint32 CDROMDeviceFile::getCapacity() |
389 |
{ |
390 |
return mCapacity; |
391 |
} |
392 |
|
393 |
bool CDROMDeviceFile::seek(uint64 blockno) |
394 |
{ |
395 |
curLBA = blockno; |
396 |
sys_fseek(mFile, (uint64)blockno * 2048); |
397 |
return true; |
398 |
} |
399 |
|
400 |
void CDROMDeviceFile::flush() |
401 |
{ |
402 |
sys_flush(mFile); |
403 |
} |
404 |
|
405 |
int CDROMDeviceFile::readBlock(byte *buf) |
406 |
{ |
407 |
if (mMode & IDE_ATAPI_TRANSFER_HDR_SYNC) { |
408 |
// .95 |
409 |
byte sync[]={0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0}; |
410 |
memcpy(buf, sync, 12); |
411 |
buf+=12; |
412 |
} |
413 |
if (mMode & IDE_ATAPI_TRANSFER_HDR_SECTOR) { |
414 |
// .95 |
415 |
MSF msf; |
416 |
MSFfromLBA(msf, curLBA); |
417 |
*(buf++) = msf.m; |
418 |
*(buf++) = msf.s; |
419 |
*(buf++) = msf.f; |
420 |
*(buf++) = 0x01; // mode 1 data |
421 |
} |
422 |
if (mMode & IDE_ATAPI_TRANSFER_DATA) { |
423 |
sys_fread(mFile, buf, 2048); |
424 |
buf += 2048; |
425 |
} |
426 |
if (mMode & IDE_ATAPI_TRANSFER_ECC) { |
427 |
// .96 |
428 |
// blablablablabla ;) |
429 |
memset(buf, 0, 288); |
430 |
} |
431 |
curLBA++; |
432 |
return 0; |
433 |
} |
434 |
|
435 |
bool CDROMDeviceFile::promSeek(uint64 pos) |
436 |
{ |
437 |
return sys_fseek(mFile, pos) == 0; |
438 |
} |
439 |
|
440 |
uint CDROMDeviceFile::promRead(byte *buf, uint size) |
441 |
{ |
442 |
return sys_fread(mFile, buf, size); |
443 |
} |
444 |
|
445 |
bool CDROMDeviceFile::changeDataSource(const char *file) |
446 |
{ |
447 |
if (mFile) sys_fclose(mFile); |
448 |
mFile = sys_fopen(file, SYS_OPEN_READ); |
449 |
if (!mFile) { |
450 |
char buf[256]; |
451 |
ht_snprintf(buf, sizeof buf, "%s: could not open file (%s)", file, strerror(errno)); |
452 |
setError(buf); |
453 |
return false; |
454 |
} |
455 |
sys_fseek(mFile, 0, SYS_SEEK_END); |
456 |
FileOfs fsize = sys_ftell(mFile); |
457 |
mCapacity = fsize / 2048 + !!(fsize % 2048); |
458 |
|
459 |
if (!is_dvd && (mCapacity > 1151850)) { |
460 |
/* In case the image just can't be a CD-ROM */ |
461 |
this->activateDVD(true); |
462 |
} |
463 |
|
464 |
return true; |
465 |
} |
466 |
|
467 |
int CDROMDeviceFile::readTOC(byte *buf, bool msf, uint8 starttrack, int len, int format) |
468 |
{ |
469 |
switch (format) { |
470 |
case 0: { |
471 |
// .415 |
472 |
// start_track == track |
473 |
byte sector[12] = { |
474 |
0, |
475 |
10, |
476 |
|
477 |
1, // first track |
478 |
1, // last track |
479 |
0x00, // res |
480 |
0x16, // .408 (Data track, copy allowed :) ) |
481 |
1, // track number |
482 |
0x00, // res |
483 |
0x00, // LBA |
484 |
0x00, |
485 |
0x00, |
486 |
0x00, // LBA |
487 |
}; |
488 |
if (msf) { |
489 |
MSF m; |
490 |
MSFfromLBA(m, 0); |
491 |
sector[8] = 0x00; |
492 |
sector[9] = m.m; |
493 |
sector[10] = m.s; |
494 |
sector[11] = m.f; |
495 |
} |
496 |
return put(buf, len, sector, sizeof sector); |
497 |
} |
498 |
case 1: { |
499 |
// .418 Multisession information |
500 |
// start_track == 0 |
501 |
byte sector[12] = { |
502 |
0, |
503 |
10, |
504 |
|
505 |
1, // first session |
506 |
1, // last session |
507 |
0x00, // res |
508 |
0x16, // .408 (Data track, copy allowed :) ) |
509 |
1, // first track number in last complete session |
510 |
0x00, // res |
511 |
0x00, // LBA |
512 |
0x00, |
513 |
0x00, |
514 |
0x00, // LBA |
515 |
}; |
516 |
if (msf) { |
517 |
MSF m; |
518 |
MSFfromLBA(m, 0); |
519 |
sector[8] = 0x00; |
520 |
sector[9] = m.m; |
521 |
sector[10] = m.s; |
522 |
sector[11] = m.f; |
523 |
} |
524 |
return put(buf, len, sector, sizeof sector); |
525 |
} |
526 |
case 2: { |
527 |
// .420 Raw TOC |
528 |
// start_track == session number |
529 |
|
530 |
MSF msf_cap, msf_zero; |
531 |
// FIXME: only when (msf)? |
532 |
MSFfromLBA(msf_cap, getCapacity()); |
533 |
MSFfromLBA(msf_zero, 0); |
534 |
|
535 |
byte sector[48] = { |
536 |
0, |
537 |
sizeof sector - 2, |
538 |
1, // first session |
539 |
1, // last session |
540 |
|
541 |
// points a0-af tracks b0-bf |
542 |
|
543 |
1, // session number |
544 |
0x16, // .408 (Data track, copy allowed :) ) |
545 |
0, // track number |
546 |
0xa0, // point (lead-in) |
547 |
0x00, // min |
548 |
0x00, // sec |
549 |
0x00, // frame |
550 |
0x00, // zero |
551 |
0x01, // first track |
552 |
0x00, // disk type |
553 |
0x00, // |
554 |
|
555 |
1, // session number |
556 |
0x16, // .408 (Data track, copy allowed :) ) |
557 |
0, // track number |
558 |
0xa1, // point |
559 |
0x00, // min |
560 |
0x00, // sec |
561 |
0x00, // frame |
562 |
0x00, // zero |
563 |
0x01, // last track |
564 |
0x00, // |
565 |
0x00, // |
566 |
|
567 |
1, // session number |
568 |
0x16, // .408 (Data track, copy allowed :) ) |
569 |
0, // track number |
570 |
0xa2, // point (lead-out) |
571 |
0x00, // min |
572 |
0x00, // sec |
573 |
0x00, // frame |
574 |
0x00, // zero |
575 |
msf_cap.m, // start |
576 |
msf_cap.s, // of |
577 |
msf_cap.f, // leadout |
578 |
|
579 |
1, // session number |
580 |
0x16, // .408 (Data track, copy allowed :) ) |
581 |
0, // track number |
582 |
1, // point (real track) |
583 |
0x00, // min |
584 |
0x00, // sec |
585 |
0x00, // frame |
586 |
0x00, // zero |
587 |
msf_zero.m, // start |
588 |
msf_zero.s, // of |
589 |
msf_zero.f, // track |
590 |
}; |
591 |
return put(buf, len, sector, sizeof sector); |
592 |
} |
593 |
case 3: |
594 |
// PMA |
595 |
case 4: |
596 |
// ATIP |
597 |
case 5: |
598 |
// CDTEXT |
599 |
default: { |
600 |
IO_IDE_WARN("read toc: format %d not supported.\n", format); |
601 |
byte sector[2] = {0, 0}; |
602 |
return put(buf, len, sector, sizeof sector); |
603 |
} |
604 |
} |
605 |
} |
606 |
|
607 |
void CDROMDeviceFile::eject() |
608 |
{ |
609 |
} |
610 |
|
611 |
|
612 |
//---------------------- SCSI based CDROM drive ----------------------- |
613 |
|
614 |
#define CD_FRAMESIZE 2048 |
615 |
|
616 |
// For me values up to 32 worked, 0 disables caching |
617 |
#define SCSI_BUFFER_SECTORS 32 |
618 |
|
619 |
|
620 |
/// @author Alexander Stockinger |
621 |
/// @date 07/17/2004 |
622 |
/// @param name The name of the CDROM device |
623 |
CDROMDeviceSCSI::CDROMDeviceSCSI(const char *name) |
624 |
:CDROMDevice(name) |
625 |
{ |
626 |
buffer_size = SCSI_BUFFER_SECTORS; |
627 |
buffer_base = (LBA) - SCSI_BUFFER_SECTORS; |
628 |
data_buffer = NULL; |
629 |
// Alloc read ahead buffer |
630 |
if (buffer_size) |
631 |
data_buffer = new byte[buffer_size * CD_FRAMESIZE]; |
632 |
|
633 |
} |
634 |
|
635 |
/// @author Alexander Stockinger |
636 |
/// @date 07/17/2004 |
637 |
CDROMDeviceSCSI::~CDROMDeviceSCSI() |
638 |
{ |
639 |
delete[]data_buffer; |
640 |
} |
641 |
|
642 |
/// @author Alexander Stockinger |
643 |
/// @date 07/17/2004 |
644 |
/// @return true if drive is ready, else false |
645 |
bool CDROMDeviceSCSI::isReady() |
646 |
{ |
647 |
byte params[8] = {0, 0, 0, 0, 0, 0, 0, 0}; |
648 |
byte res = SCSI_ExecCmd(SCSI_UNITREADY, SCSI_CMD_DIR_OUT, params); |
649 |
mReady = res == SCSI_STATUS_GOOD; |
650 |
return mReady; |
651 |
} |
652 |
|
653 |
/// @author Alexander Stockinger |
654 |
/// @date 07/17/2004 |
655 |
/// @param lock true for locking the tray, false for unlocking |
656 |
/// @return true on successful execution, else false |
657 |
bool CDROMDeviceSCSI::setLock(bool lock) |
658 |
{ |
659 |
bool ret = CDROMDevice::setLock(lock); |
660 |
if (ret) { |
661 |
byte params[8] = {0, 0, 0, 0, 0, 0, 0, 0}; |
662 |
params[3] = lock ? SCSI_TRAYLOCK_LOCKED : SCSI_TRAYLOCK_UNLOCKED; |
663 |
ret = SCSI_ExecCmd(SCSI_TRAYLOCK, SCSI_CMD_DIR_OUT, params) == SCSI_STATUS_GOOD; |
664 |
} |
665 |
return ret; |
666 |
} |
667 |
|
668 |
/// @author Alexander Stockinger |
669 |
/// @date 07/17/2004 |
670 |
/// @return The number of sectors on the inserted media |
671 |
uint32 CDROMDeviceSCSI::getCapacity() |
672 |
{ |
673 |
if (!isReady()) { |
674 |
IO_IDE_ERR("CDROMDeviceSCSI::getCapacity() failed: not ready.\n"); |
675 |
} else { |
676 |
byte buf[8]; |
677 |
|
678 |
byte params[8] = {0, 0, 0, 0, 0, 0, 0, 0}; |
679 |
byte res = SCSI_ExecCmd(SCSI_READCDCAP, SCSI_CMD_DIR_IN, params, buf, 8); |
680 |
if (res != SCSI_STATUS_GOOD) return 0; |
681 |
|
682 |
return (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + buf[3]; |
683 |
} |
684 |
} |
685 |
|
686 |
/// @author Alexander Stockinger |
687 |
/// @date 07/17/2004 |
688 |
/// @param blockno The sector to seek to |
689 |
/// @return true on successful execution, else false |
690 |
bool CDROMDeviceSCSI::seek(uint64 blockno) |
691 |
{ |
692 |
curLBA = blockno; |
693 |
return true; |
694 |
} |
695 |
|
696 |
/// @author Alexander Stockinger |
697 |
/// @date 07/17/2004 |
698 |
void CDROMDeviceSCSI::flush() |
699 |
{ |
700 |
} |
701 |
|
702 |
/// @author Alexander Stockinger |
703 |
/// @date 07/17/2004 |
704 |
/// @param sector The sector to read |
705 |
/// @param buf The buffer to read into (size is expected to be CD_FRAMESIZE bytes) |
706 |
/// @return true on successful execution, else false |
707 |
bool CDROMDeviceSCSI::readBufferedData(byte *buf, uint sector) |
708 |
{ |
709 |
if (buffer_size) { |
710 |
// If we have the requested data buffered, return it |
711 |
int buffer_delta = (int) sector - (int) buffer_base; |
712 |
if (buffer_delta >= 0 && buffer_delta < (int) buffer_size) { |
713 |
uint offset = CD_FRAMESIZE * buffer_delta; |
714 |
memcpy(buf, data_buffer + offset, CD_FRAMESIZE); |
715 |
return true; |
716 |
} |
717 |
|
718 |
// If not, buffer some more and return the requested one |
719 |
buffer_base = sector; |
720 |
bool ret = SCSI_ReadSectors(sector, data_buffer, CD_FRAMESIZE * buffer_size, buffer_size); |
721 |
memcpy(buf, data_buffer, CD_FRAMESIZE); |
722 |
return ret; |
723 |
} else |
724 |
return SCSI_ReadSectors(sector, buf, CD_FRAMESIZE, 1); |
725 |
} |
726 |
|
727 |
/// @author Alexander Stockinger |
728 |
/// @date 07/17/2004 |
729 |
/// @param buf The buffer to read into (size is expected to be CD_FRAMESIZE bytes) |
730 |
/// @return Always 0 at the moment |
731 |
int CDROMDeviceSCSI::readBlock(byte *buf) |
732 |
{ |
733 |
if (mMode & IDE_ATAPI_TRANSFER_HDR_SYNC) { |
734 |
// .95 |
735 |
byte sync[] = {0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0}; |
736 |
memcpy(buf, sync, 12); |
737 |
buf += 12; |
738 |
} |
739 |
if (mMode & IDE_ATAPI_TRANSFER_HDR_SECTOR) { |
740 |
// .95 |
741 |
MSF msf; |
742 |
MSFfromLBA(msf, curLBA); |
743 |
*(buf++) = msf.m; |
744 |
*(buf++) = msf.s; |
745 |
*(buf++) = msf.f; |
746 |
*(buf++) = 0x01; // mode 1 data |
747 |
} |
748 |
if (mMode & IDE_ATAPI_TRANSFER_DATA) { |
749 |
//bool ret = ASPI_ReadSector(a, t, l, curLBA, buf, CD_FRAMESIZE); |
750 |
bool ret = readBufferedData(buf, curLBA); |
751 |
if (!ret) |
752 |
IO_IDE_WARN("Error reading from SCSI CD drive (sector %d)\n", curLBA); |
753 |
buf += CD_FRAMESIZE; |
754 |
} |
755 |
if (mMode & IDE_ATAPI_TRANSFER_ECC) { |
756 |
// .96 |
757 |
// blablablablabla ;) |
758 |
memset(buf, 0, 288); |
759 |
} |
760 |
curLBA++; |
761 |
return 0; |
762 |
} |
763 |
|
764 |
|
765 |
/** |
766 |
* @param buffer result buffer |
767 |
* @param msf if true use MSF encoding otherwise LBA |
768 |
* @param starttrack start track |
769 |
* @param len maximum length of buffer |
770 |
* @param format see CDROMDeviceFile::readTOC |
771 |
*/ |
772 |
int CDROMDeviceSCSI::readTOC(byte *buf, bool msf, uint8 starttrack, int len, int format) |
773 |
{ |
774 |
byte params[9] = { |
775 |
msf ? 2 : 0, |
776 |
0, |
777 |
0, |
778 |
0, |
779 |
0, |
780 |
starttrack, |
781 |
len >> 8, |
782 |
len >> 0, |
783 |
format << 6, |
784 |
}; |
785 |
if (SCSI_ExecCmd(SCSI_READ_TOC, SCSI_CMD_DIR_IN, |
786 |
params, buf, len) == SCSI_STATUS_GOOD) { |
787 |
ht_printf("readtoc: %d\n", (buf[0] << 8) | (buf[1] << 0)); |
788 |
return (buf[0] << 8) | (buf[1] << 0); |
789 |
} else { |
790 |
ht_printf("readtoc failed\n"); |
791 |
return 0; |
792 |
} |
793 |
} |
794 |
|
795 |
int CDROMDeviceSCSI::getConfig(byte *buf, int len, byte RT, int first) |
796 |
{ |
797 |
static byte rt[] = { |
798 |
0x00, 0x01, 0x02, 0x03, 0x43, 0x6f, 0x6e, 0x74, |
799 |
0x61, 0x69, 0x6e, 0x73, 0x00, 0x50, 0x00, 0x45, |
800 |
0x00, 0x41, 0x00, 0x52, 0x00, 0x50, 0x00, 0x43, |
801 |
0x20, 0x43, 0x6f, 0x64, 0x65, 0x2e, 0x20, 0x50, |
802 |
0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, |
803 |
0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, |
804 |
0x74, 0x20, 0x28, 0x43, 0x29, 0x20, 0x53, 0x65, |
805 |
0x62, 0x61, 0x73, 0x74, 0x69, 0x61, 0x6e, 0x20, |
806 |
0x42, 0x69, 0x61, 0x6c, 0x6c, 0x61, 0x73, 0x20, |
807 |
0x32, 0x30, 0x30, 0x34, 0x00, 0x46, 0x00, 0x00 |
808 |
}; |
809 |
|
810 |
byte params[9] = { |
811 |
rt[RT], |
812 |
first >> 8, |
813 |
first >> 0, |
814 |
0, |
815 |
0, |
816 |
0, |
817 |
len >> 8, |
818 |
len >> 0, |
819 |
0, |
820 |
}; |
821 |
if (SCSI_ExecCmd(rt[(4<<4)+13], SCSI_CMD_DIR_IN, |
822 |
params, buf, len) == SCSI_STATUS_GOOD) { |
823 |
uint32 reslen = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0) + 4; |
824 |
return reslen; |
825 |
} else { |
826 |
ht_printf("getconfig failed\n"); |
827 |
return 0; |
828 |
} |
829 |
} |
830 |
|
831 |
int CDROMDeviceSCSI::readDVDStructure(byte *buf, int len, uint8 subcommand, uint32 address, uint8 layer, uint8 format, uint8 AGID, uint8 control) |
832 |
{ |
833 |
byte params[11] = { |
834 |
subcommand, |
835 |
address >> 24, |
836 |
address >> 16, |
837 |
address >> 8, |
838 |
address >> 0, |
839 |
layer, |
840 |
format, |
841 |
len >> 8, |
842 |
len >> 0, |
843 |
AGID << 6, |
844 |
control, |
845 |
}; |
846 |
if (SCSI_ExecCmd(0xad, SCSI_CMD_DIR_IN, |
847 |
params, buf, len) == SCSI_STATUS_GOOD) { |
848 |
uint32 reslen = (buf[0] << 8) | (buf[1] << 0) + 2; |
849 |
return reslen; |
850 |
} else { |
851 |
ht_printf("readDVDStructure failed\n"); |
852 |
return 0; |
853 |
} |
854 |
} |
855 |
|
856 |
/// @author Alexander Stockinger |
857 |
/// @date 07/17/2004 |
858 |
void CDROMDeviceSCSI::eject() |
859 |
{ |
860 |
if (!isLocked()) { |
861 |
byte params[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; |
862 |
params[3] = true ? SCSI_EJECTTRAY_UNLOAD : SCSI_EJECTTRAY_LOAD; |
863 |
SCSI_ExecCmd(SCSI_EJECTTRAY, SCSI_CMD_DIR_OUT, params); |
864 |
buffer_base = (LBA) - buffer_size; |
865 |
} |
866 |
} |
867 |
|
868 |
/// @date 07/17/2004 |
869 |
/// @param pos The new seek position (byte address) |
870 |
/// @return true on successful execution, else false |
871 |
bool CDROMDeviceSCSI::promSeek(uint64 pos) |
872 |
{ |
873 |
prompos = pos; |
874 |
return true; |
875 |
} |
876 |
|
877 |
/// @author Alexander Stockinger |
878 |
/// @date 07/17/2004 |
879 |
/// @param buf The buffer to read into (expected to be at least count bytes) |
880 |
/// @param pos The first byte to read |
881 |
/// @param count The number of bytes to read |
882 |
/// @return The number of bytes actually read |
883 |
uint CDROMDeviceSCSI::readData(byte *buf, uint64 pos, uint count) |
884 |
{ |
885 |
uint res = 0; |
886 |
while (count) { |
887 |
uint sector = pos / CD_FRAMESIZE; |
888 |
uint offset = pos % CD_FRAMESIZE; |
889 |
uint read = CD_FRAMESIZE - offset; |
890 |
read = MIN(read, count); |
891 |
|
892 |
byte buffer[CD_FRAMESIZE]; |
893 |
bool ret = readBufferedData(buffer, sector); |
894 |
if (!ret) return res; |
895 |
|
896 |
memcpy(buf, buffer + offset, read); |
897 |
|
898 |
count -= read; |
899 |
res += read; |
900 |
buf += read; |
901 |
pos += read; |
902 |
} |
903 |
return res; |
904 |
} |
905 |
|
906 |
/// @author Alexander Stockinger |
907 |
/// @date 07/17/2004 |
908 |
/// @param buf The buffer to read into (expected to be at least size bytes) |
909 |
/// @param size The number of bytes to read |
910 |
/// @return The number of bytes read |
911 |
uint CDROMDeviceSCSI::promRead(byte *buf, uint size) |
912 |
{ |
913 |
if (!isReady()) { |
914 |
IO_IDE_WARN("CDROMDeviceSCSI::promRead(): not ready.\n"); |
915 |
return 0; |
916 |
} |
917 |
return readData(buf, prompos, size); |
918 |
} |
919 |
|
920 |
/// @author Alexander Stockinger |
921 |
/// @date 07/17/2004 |
922 |
/// @param start The first sector to read |
923 |
/// @param buffer The data buffer to read into |
924 |
/// @param buffer_bytes The size of the data buffer in bytes |
925 |
/// @param sectors The number of consecutive sectors to read |
926 |
/// @return true on successful execution, else false |
927 |
bool CDROMDeviceSCSI::SCSI_ReadSectors(uint32 start, byte *buffer, |
928 |
uint buffer_bytes, |
929 |
uint sectors) |
930 |
{ |
931 |
byte params[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; |
932 |
|
933 |
params[1] = (byte) (start >> 24); |
934 |
params[2] = (byte) (start >> 16); |
935 |
params[3] = (byte) (start >> 8); |
936 |
params[4] = (byte) (start >> 0); |
937 |
|
938 |
params[6] = sectors >> 8; // Number of sectors to read |
939 |
params[7] = sectors; // Number of sectors to read |
940 |
|
941 |
byte ret = SCSI_ExecCmd(SCSI_READ10, SCSI_CMD_DIR_IN, params, buffer, buffer_bytes); |
942 |
return ret == SCSI_STATUS_GOOD; |
943 |
} |