Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions libcdio-rs/src/mmc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ use std::{

pub use get_config::*;
pub use get_event_status::*;
pub use inquiry::*;
pub use read_disc_info::*;
pub use read_subchannel::*;
pub use test_unit_ready::*;
pub use read_toc::*;

mod get_config;
mod get_event_status;
mod inquiry;
mod read_disc_info;
mod read_subchannel;
mod test_unit_ready;
Expand Down Expand Up @@ -365,6 +367,7 @@ pub enum OsError {
enum MmcCommand {
#[allow(unused)]
GetConfiguration = 0x46,
Inquiry = 0x12,
TestUnitReady = 0x00,
ReadDiscInfo = 0x51,
ReadToc = 0x43,
Expand Down
132 changes: 132 additions & 0 deletions libcdio-rs/src/mmc/inquiry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright (C) 2026 Shiva Kiran Koninty <shiva@skran.xyz>
//
// This file is part of libcdio-rs.
//
// libcdio-rs is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// libcdio-rs is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with libcdio-rs. If not, see <https://www.gnu.org/licenses/>.

//! Routines based on MMC `INQUIRY`.

use displaydoc::Display;
use thiserror::Error;
use tracing::debug;

use crate::{
Mmc,
mmc::{Cdb, MmcCommand, MmcDirection, MmcError},
};

/// Routines based on MMC `INQUIRY`.
impl Mmc {
/// Get the hardware identifiers (Product, Vendor and Revision).
pub fn hardware_identifiers(&self) -> Result<HardwareIdentifiers, GetHardwareIdentifersError> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn hardware_identifiers(&self) -> Result<HardwareIdentifiers, GetHardwareIdentifersError> {
pub fn hardware_identifiers(&self) -> Result<HardwareIdentifiers, GetHardwareIdentifiersError> {

let buf = self.inquiry(InquiryKind::Standard)?;
let response_data_format = buf[RESPONSE_DATA_FMT_POS] & 0b1111;
if response_data_format != RESPONSE_DATA_FMT_MMC {
return Err(MmcInquiryError::InvalidResponse(format!(
"unsupported non-standard INQUIRY response format, got response data format of {}",
response_data_format,
))
.into());
}
let vendor = String::from_utf8_lossy(&buf[VENDOR_ID_START_POS..=VENDOR_ID_END_POS])
.trim()
.to_string();
let product = String::from_utf8_lossy(&buf[PRODUCT_ID_START_POS..=PRODUCT_ID_END_POS])
.trim()
.to_string();
let revision = String::from_utf8_lossy(&buf[REVISION_START_POS..=REVISION_END_POS])
.trim()
.to_string();

return Ok(HardwareIdentifiers {
product,
vendor,
revision,
});

const RESPONSE_DATA_FMT_POS: usize = 3;
const RESPONSE_DATA_FMT_MMC: u8 = 2;
const VENDOR_ID_START_POS: usize = 8;
const VENDOR_ID_END_POS: usize = 15;
const PRODUCT_ID_START_POS: usize = 16;
const PRODUCT_ID_END_POS: usize = 31;
const REVISION_START_POS: usize = 32;
const REVISION_END_POS: usize = 35;
}

@rocky rocky Jul 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What, if any, are the implications of having this appear after the return statement as opposed to at the start of the function or before the return?

To verify that this information is correct. I went to a MMC-5 PDF that then directed me to a SPC3 PDF https://www.t10.org/ftp/t10/document.08/08-309r1.pdf where I found

Image

What can we do to make it more transparent and easier for someone to be able to verify this kind of information?


fn inquiry(&self, kind: InquiryKind) -> Result<Vec<u8>, MmcInquiryError> {
let mut buf = vec![0; ALLOC_LEN];
let mut cdb = Cdb::default();
cdb[0] = MmcCommand::Inquiry as u8;
if let InquiryKind::VitalProductData { page_code } = kind {
cdb[1] = EVPD_SET;
cdb[2] = page_code;
}
cdb[3..=4].copy_from_slice(&(buf.len() as u16).to_be_bytes());

self.run_command(Some(MmcDirection::Read), buf.as_mut_slice(), cdb)?;
debug!(?buf, len = buf.len());

return Ok(buf);

const ALLOC_LEN: usize = 255;
const EVPD_SET: u8 = 1;
}
}

/// could not get hardware identifers

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// could not get hardware identifers
/// could not get hardware identifiers

#[derive(Debug, Display, Error)]
pub struct GetHardwareIdentifersError {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub struct GetHardwareIdentifersError {
pub struct GetHardwareIdentifiersError {

#[from]
pub source: MmcInquiryError,
}

/// error from an `INQUIRY` command.
#[derive(Debug, Display, Error)]
pub enum MmcInquiryError {
/// operating system returned an error
Os(#[from] MmcError),

/// invalid response from mmc command: {0}
InvalidResponse(String),
}

#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
/// Basic hardware identifiers
pub struct HardwareIdentifiers {
pub product: String,
pub vendor: String,
pub revision: String,
}

#[allow(unused)]
#[derive(Clone, Copy, Debug)]
enum InquiryKind {
Standard,
VitalProductData { page_code: u8 },
}

#[cfg(test)]
mod tests {
use tracing::info;

use super::*;

#[test_log::test(test)]
#[ignore = "requires a drive with mmc"]
fn hardware_identifers() {
let hardware_identifiers = Mmc::new().unwrap().hardware_identifiers().unwrap();
info!(?hardware_identifiers);
}
}