Skip to content

Commit 8944c92

Browse files
committed
CD-ROM: Parity and CRC checking support, System Shock 2 now works with a directly mounted .CUE image as well.
1 parent 362528d commit 8944c92

6 files changed

Lines changed: 10557 additions & 8 deletions

File tree

src/cdrom/cdrom.c

Lines changed: 99 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -292,17 +292,101 @@ msf_to_bcd(int *m, int *s, int *f)
292292
*f = bin2bcd(*f);
293293
}
294294

295+
void
296+
cdrom_compute_ecc_block(cdrom_t *dev, uint8_t *parity, const uint8_t *data,
297+
uint32_t major_count, uint32_t minor_count,
298+
uint32_t major_mult, uint32_t minor_inc)
299+
{
300+
uint32_t size = major_count * minor_count;
301+
302+
for (uint32_t major = 0; major < major_count; ++major) {
303+
uint32_t index = (major >> 1) * major_mult + (major & 1);
304+
305+
uint8_t ecc_a = 0;
306+
uint8_t ecc_b = 0;
307+
308+
for (uint32_t minor = 0; minor < minor_count; ++minor) {
309+
uint8_t temp = data[index];
310+
311+
index += minor_inc;
312+
313+
if (index >= size)
314+
index -= size;
315+
316+
ecc_a ^= temp;
317+
ecc_b ^= temp;
318+
ecc_a = dev->_F_LUT[ecc_a];
319+
}
320+
321+
parity[major] = dev->_B_LUT[dev->_F_LUT[ecc_a] ^ ecc_b];
322+
parity[major + major_count] = parity[major] ^ ecc_b;
323+
}
324+
}
325+
326+
extern void
327+
cdrom_generate_ecc_data(cdrom_t *dev, const uint8_t *data)
328+
{
329+
/* Compute ECC P code. */
330+
cdrom_compute_ecc_block(dev, dev->p_parity, data, 86, 24, 2, 86);
331+
332+
/* Compute ECC Q code. */
333+
cdrom_compute_ecc_block(dev, dev->q_parity, data, 52, 43, 86, 88);
334+
}
335+
295336
static int
296-
read_data(cdrom_t *dev, const uint32_t lba)
337+
cdrom_is_sector_good(cdrom_t *dev, const uint8_t *b, const uint8_t mode2, const uint8_t form)
297338
{
298-
int ret = 1;
339+
int ret = 1;
340+
341+
if (mode2 && (form == 1)) {
342+
const uint32_t crc = cdrom_crc32(0xffffffff, b, 2072) ^ 0xffffffff;
343+
344+
ret = ret && (crc == (*(uint32_t *) &(b[2072])));
345+
} else if (!mode2) {
346+
const uint32_t crc = cdrom_crc32(0xffffffff, b, 2064) ^ 0xffffffff;
347+
348+
ret = ret && (crc == (*(uint32_t *) &(b[2064])));
349+
}
350+
351+
cdrom_generate_ecc_data(dev, &(b[12]));
352+
353+
ret = ret && !memcmp(dev->p_parity, &(b[2076]), 172);
354+
ret = ret && !memcmp(dev->q_parity, &(b[2248]), 104);
355+
356+
return ret;
357+
}
358+
359+
static int
360+
read_data(cdrom_t *dev, const uint32_t lba, int check)
361+
{
362+
int ret = 1;
363+
int form = 0;
299364

300365
if (dev->cached_sector != lba) {
301366
dev->cached_sector = lba;
302367

303368
ret = dev->ops->read_sector(dev->local,
304369
dev->raw_buffer[dev->cur_buf ^ 1], lba);
305370

371+
if ((ret > 0) && check) {
372+
if (dev->mode2) {
373+
if (dev->raw_buffer[dev->cur_buf ^ 1][0x000f] == 0x01)
374+
/*
375+
Use Mode 1, since evidently specification-violating
376+
discs exist.
377+
*/
378+
dev->mode2 = 0;
379+
else if (dev->raw_buffer[dev->cur_buf ^ 1][0x0012] ==
380+
dev->raw_buffer[dev->cur_buf ^ 1][0x0016])
381+
form = ((dev->raw_buffer[dev->cur_buf ^ 1][0x0012] &
382+
0x20) >> 5) + 1;
383+
} else if (dev->raw_buffer[dev->cur_buf ^ 1][0x000f] == 0x02)
384+
dev->mode2 = 1;
385+
386+
if (!cdrom_is_sector_good(dev, dev->raw_buffer[dev->cur_buf ^ 1], dev->mode2, form))
387+
ret = -1;
388+
}
389+
306390
if (ret <= 0) {
307391
memset(dev->raw_buffer[dev->cur_buf ^ 1], 0x00, 2448);
308392
dev->cached_sector = -1;
@@ -322,7 +406,7 @@ cdrom_get_subchannel(cdrom_t *dev, const uint32_t lba,
322406
if (lba != dev->cached_sector)
323407
dev->cached_sector = -1;
324408

325-
(void) read_data(dev, lba);
409+
(void) read_data(dev, lba, 0);
326410

327411
for (int i = 0; i < 12; i++)
328412
for (int j = 0; j < 8; j++)
@@ -679,7 +763,7 @@ track_type_is_valid(UNUSED(const cdrom_t *dev), const int type, const int flags,
679763
static int
680764
read_audio(cdrom_t *dev, const uint32_t lba, uint8_t *b)
681765
{
682-
const int ret = read_data(dev, lba);
766+
const int ret = read_data(dev, lba, 0);
683767

684768
memcpy(b, dev->raw_buffer[dev->cur_buf], 2352);
685769

@@ -2379,6 +2463,8 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int
23792463
if (dm != CD_TRACK_NORMAL)
23802464
mode2 = 1;
23812465

2466+
dev->mode2 = mode2;
2467+
23822468
memset(dev->extra_buffer, 0, 296);
23832469

23842470
if ((cdrom_sector_flags & 0xf8) == 0x08) {
@@ -2405,7 +2491,7 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int
24052491
else
24062492
ret = read_audio(dev, lba, temp_b);
24072493
} else {
2408-
ret = read_data(dev, lba);
2494+
ret = read_data(dev, lba, 1);
24092495

24102496
/* Return with error if we had one. */
24112497
if (ret > 0) {
@@ -2800,7 +2886,7 @@ cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer)
28002886
}
28012887

28022888
if (track->adr_ctl & 0x04) {
2803-
ret = read_data(dev, start);
2889+
ret = read_data(dev, start, 0);
28042890
mode = dev->raw_buffer[dev->cur_buf][3];
28052891
}
28062892
} else if (track->point != 0xa2)
@@ -2829,9 +2915,9 @@ uint8_t
28292915
cdrom_get_current_mode(cdrom_t *dev)
28302916
{
28312917
if (dev->cached_sector == -1)
2832-
(void) read_data(dev, dev->seek_pos);
2918+
(void) read_data(dev, dev->seek_pos, 0);
28332919
else
2834-
(void) read_data(dev, dev->cached_sector);
2920+
(void) read_data(dev, dev->cached_sector, 0);
28352921

28362922
return dev->raw_buffer[dev->cur_buf][3];
28372923
}
@@ -3011,6 +3097,11 @@ cdrom_hard_reset(void)
30113097

30123098
cdrom_load(dev, dev->image_path, 0);
30133099
}
3100+
3101+
for (uint32_t j = 0; j < _LUT_SIZE; ++j) {
3102+
dev->_F_LUT[j] = (j << 1) ^ (j & 0x80 ? 0x11d : 0);
3103+
dev->_B_LUT[j ^ dev->_F_LUT[j]] = j;
3104+
}
30143105
}
30153106
}
30163107

src/cdrom/cdrom_image.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,6 +2237,7 @@ image_read_sector(const void *local, uint8_t *buffer,
22372237
const uint32_t sector)
22382238
{
22392239
const cd_image_t *img = (const cd_image_t *) local;
2240+
cdrom_t *dev = (cdrom_t *) img->dev;
22402241
int m = 0;
22412242
int s = 0;
22422243
int f = 0;
@@ -2245,6 +2246,7 @@ image_read_sector(const void *local, uint8_t *buffer,
22452246
int track;
22462247
int index;
22472248
uint8_t q[16] = { 0x00 };
2249+
uint8_t *buf = buffer;
22482250

22492251
if (sector == 0xffffffff)
22502252
lba = img->dev->seek_pos;
@@ -2304,6 +2306,33 @@ image_read_sector(const void *local, uint8_t *buffer,
23042306
/* Index is not in the file, no read to fail here. */
23052307
ret = 1;
23062308

2309+
if ((ret > 0) && (trk->attr & 0x04) && ((idx->type < INDEX_NORMAL) || !track_is_raw)) {
2310+
uint32_t crc;
2311+
2312+
if ((trk->mode == 2) && (trk->form == 1))
2313+
crc = cdrom_crc32(0xffffffff, buf, 2072) ^ 0xffffffff;
2314+
else
2315+
crc = cdrom_crc32(0xffffffff, buf, 2064) ^ 0xffffffff;
2316+
2317+
memcpy(&(buf[2064]), &crc, 4);
2318+
2319+
#if 0
2320+
/* Compute ECC P code. */
2321+
cdrom_compute_ecc_block(dev, dev->p_parity, &(buf[12]), 86, 24, 2, 86);
2322+
memcpy(&(buf[2076]), dev->p_parity, 172);
2323+
2324+
/* Compute ECC Q code. */
2325+
cdrom_compute_ecc_block(dev, dev->q_parity, &(buf[12]), 52, 43, 86, 88);
2326+
memcpy(&(buf[2248]), dev->q_parity, 104);
2327+
#else
2328+
/* Compute ECC P code. */
2329+
cdrom_compute_ecc_block(dev, &(buf[2076]), &(buf[12]), 86, 24, 2, 86);
2330+
2331+
/* Compute ECC Q code. */
2332+
cdrom_compute_ecc_block(dev, &(buf[2248]), &(buf[12]), 52, 43, 86, 88);
2333+
#endif
2334+
}
2335+
23072336
if ((ret > 0) && ((idx->type < INDEX_NORMAL) || (trk->subch_type != 0x08))) {
23082337
buffer -= offset;
23092338

src/include/86box/cdrom.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@
6969

7070
#define CD_FPS 75
7171

72+
#define _LUT_SIZE 0x100
73+
7274
#define FRAMES_TO_MSF(f, M, S, F) \
7375
{ \
7476
uint64_t value = f; \
@@ -351,6 +353,13 @@ typedef struct cdrom {
351353

352354
/* Only used on Windows hosts for disc change notifications. */
353355
uint8_t host_letter;
356+
uint8_t mode2;
357+
358+
uint8_t _F_LUT[_LUT_SIZE];
359+
uint8_t _B_LUT[_LUT_SIZE];
360+
361+
uint8_t p_parity[172];
362+
uint8_t q_parity[104];
354363
} cdrom_t;
355364

356365
extern cdrom_t cdrom[CDROM_NUM];
@@ -448,6 +457,12 @@ extern int cdrom_is_empty(const uint8_t id);
448457
extern void cdrom_eject(const uint8_t id);
449458
extern void cdrom_reload(const uint8_t id);
450459

460+
extern void cdrom_compute_ecc_block(cdrom_t *dev, uint8_t *parity, const uint8_t *data,
461+
uint32_t major_count, uint32_t minor_count,
462+
uint32_t major_mult, uint32_t minor_inc);
463+
extern unsigned long cdrom_crc32(unsigned long crc, const unsigned char *buf,
464+
size_t len);
465+
451466
extern int cdrom_assigned_letters;
452467

453468
#ifdef __cplusplus

src/utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
add_library(utils OBJECT
1919
cJSON.c
2020
crc.c
21+
crc32.c
2122
fifo.c
2223
fifo8.c
2324
ini.c

0 commit comments

Comments
 (0)