-
Notifications
You must be signed in to change notification settings - Fork 1
Add data support 0 4 1 #34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7f39407
983a759
50d70b2
195af49
a5dfafc
ea38302
ddf44f5
33fb7df
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| /// Sector read mode for the READ CD (0xBE) command. | ||
| /// | ||
| /// Controls CDB byte 1 (Expected Sector Type) and byte 9 (Main Channel Selection) | ||
| /// to read different sector formats from the same READ CD command. | ||
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| pub enum SectorReadMode { | ||
| /// Audio: 2352 bytes/sector, raw PCM. | ||
| /// CDB byte 1 = 0x00 (any type), byte 9 = 0x10 (user data). | ||
| Audio, | ||
| /// Data cooked: 2048 bytes/sector, user data only (no sync/header/EDC/ECC). | ||
| /// CDB byte 1 = 0x04 (Mode 1), byte 9 = 0x10 (user data). | ||
| DataCooked, | ||
| /// Data raw: 2352 bytes/sector with sync + header + user data + EDC/ECC. | ||
| /// CDB byte 1 = 0x04 (Mode 1), byte 9 = 0xF8 (sync + header + user data + EDC/ECC). | ||
| DataRaw, | ||
| } | ||
|
|
||
| impl SectorReadMode { | ||
| /// Bytes per sector for this read mode. | ||
| pub fn sector_size(&self) -> usize { | ||
| match self { | ||
| SectorReadMode::Audio => 2352, | ||
| SectorReadMode::DataCooked => 2048, | ||
| SectorReadMode::DataRaw => 2352, | ||
| } | ||
| } | ||
|
|
||
| /// CDB byte 1: Expected Sector Type field (bits 5-2). | ||
| pub fn cdb_byte1(&self) -> u8 { | ||
| match self { | ||
| SectorReadMode::Audio => 0x00, | ||
| SectorReadMode::DataCooked => 0x04, | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I found the spec: ref, and in the reference they say:
So the mode 1 should be |
||
| SectorReadMode::DataRaw => 0x04, | ||
| } | ||
| } | ||
|
|
||
| /// CDB byte 9: Main Channel Selection bits. | ||
| pub fn cdb_byte9(&self) -> u8 { | ||
| match self { | ||
| SectorReadMode::Audio => 0x10, | ||
| SectorReadMode::DataCooked => 0x10, | ||
| SectorReadMode::DataRaw => 0xF8, | ||
| } | ||
| } | ||
|
|
||
| /// Maximum sectors per single `READ CD` command. | ||
| /// | ||
| /// This is the sole chunker for the blocking `read_track` / | ||
| /// `read_data_sectors` paths, which hand a whole track (tens of thousands | ||
| /// of sectors) straight to the read loop; the streaming API already limits | ||
| /// itself via `TrackStreamConfig::sectors_per_chunk`. The cap is not about | ||
| /// OS pass-through limits (modern SG_IO/SPTI handle far larger transfers) | ||
| /// but about optical-drive firmware and USB-bridge reliability: large | ||
| /// multi-sector `READ CD` requests are flaky across the zoo of drives. The | ||
| /// values keep each transfer around 64 KiB, matching the conventional | ||
| /// ~27-sector chunk used by cdparanoia/libcdio. | ||
| pub(crate) fn max_sectors_per_xfer(&self) -> u32 { | ||
| match self.sector_size() { | ||
| 2048 => 32, // 32 * 2048 = 64 KiB | ||
| _ => 27, // 27 * 2352 ≈ 62 KiB | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,60 @@ | ||
| #include "shim_common.h" | ||
|
|
||
| bool read_cd_audio(uint32_t lba, uint32_t sectors, uint8_t **outBuf, uint32_t *outLen, CdScsiError *outErr) { | ||
| // Map our SectorReadMode discriminant to the macOS CD sector area/type and the | ||
| // resulting bytes-per-sector. Keeping the mapping here (rather than in Rust) | ||
| // means the IOKit constants only ever appear where their header is imported. | ||
| // | ||
| // 0 = Audio -> user area, CDDA, 2352 B/sector | ||
| // 1 = DataCooked -> user area, Mode 1, 2048 B/sector | ||
| // 2 = DataRaw -> sync+header+user+aux, Mode 1, 2352 B/sector | ||
| static bool sector_layout_for_mode(uint32_t mode_id, | ||
| CDSectorArea *outArea, | ||
| CDSectorType *outType, | ||
| uint32_t *outSectorSize) { | ||
| switch (mode_id) { | ||
| case 0: | ||
| *outArea = kCDSectorAreaUser; | ||
| *outType = kCDSectorTypeCDDA; | ||
| *outSectorSize = 2352; | ||
| return true; | ||
| case 1: | ||
| *outArea = kCDSectorAreaUser; | ||
| *outType = kCDSectorTypeMode1; | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can see in the docs: ref -- this value is |
||
| *outSectorSize = 2048; | ||
| return true; | ||
| case 2: | ||
| *outArea = (CDSectorArea)(kCDSectorAreaSync | kCDSectorAreaHeader | | ||
| kCDSectorAreaUser | kCDSectorAreaAuxiliary); | ||
| *outType = kCDSectorTypeMode1; | ||
| *outSectorSize = 2352; | ||
| return true; | ||
| default: | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| bool read_cd_sectors(uint32_t lba, uint32_t sectors, uint32_t mode_id, | ||
| uint8_t **outBuf, uint32_t *outLen, CdScsiError *outErr) { | ||
| *outBuf = NULL; | ||
| *outLen = 0; | ||
| if (outErr) { | ||
| memset(outErr, 0, sizeof(CdScsiError)); | ||
| } | ||
|
|
||
| const uint32_t SECTOR_SZ = 2352; | ||
| CDSectorArea sectorArea; | ||
| CDSectorType sectorType; | ||
| uint32_t sectorSize; | ||
| if (!sector_layout_for_mode(mode_id, §orArea, §orType, §orSize)) { | ||
| fprintf(stderr, "[READ] unknown sector mode %u\n", mode_id); | ||
| goto fail; | ||
| } | ||
|
|
||
| if (sectors == 0) { | ||
| fprintf(stderr, "[READ] sectors == 0\n"); | ||
| goto fail; | ||
| } | ||
|
|
||
| uint64_t totalBytes64 = (uint64_t)SECTOR_SZ * (uint64_t)sectors; | ||
| uint64_t totalBytes64 = (uint64_t)sectorSize * (uint64_t)sectors; | ||
| if (totalBytes64 > UINT32_MAX) { | ||
| fprintf(stderr, "[READ] requested size too large\n"); | ||
| goto fail; | ||
|
|
@@ -34,9 +75,9 @@ bool read_cd_audio(uint32_t lba, uint32_t sectors, uint8_t **outBuf, uint32_t *o | |
| } | ||
|
|
||
| dk_cd_read_t read = {0}; | ||
| read.offset = (uint64_t)lba * (uint64_t)SECTOR_SZ; | ||
| read.sectorArea = kCDSectorAreaUser; | ||
| read.sectorType = kCDSectorTypeCDDA; | ||
| read.offset = (uint64_t)lba * (uint64_t)sectorSize; | ||
| read.sectorArea = sectorArea; | ||
| read.sectorType = sectorType; | ||
| read.bufferLength = totalBytes; | ||
| read.buffer = dst; | ||
|
|
||
|
|
||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
small correction: They live in bits 4-2