#![no_std]
#![warn(missing_docs)]
include!(concat!(env!("OUT_DIR"), "/pci_ids.cg.rs"));
pub struct Vendors;
impl Vendors {
pub fn iter() -> impl Iterator<Item = &'static Vendor> {
VENDORS.values()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Vendor {
id: u16,
name: &'static str,
devices: &'static [Device],
}
impl Vendor {
pub fn id(&self) -> u16 {
self.id
}
pub fn name(&self) -> &'static str {
self.name
}
pub fn devices(&self) -> impl Iterator<Item = &'static Device> {
self.devices.iter()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Device {
vendor_id: u16,
id: u16,
name: &'static str,
subsystems: &'static [SubSystem],
}
impl Device {
pub fn from_vid_pid(vid: u16, pid: u16) -> Option<&'static Device> {
let vendor = Vendor::from_id(vid);
vendor.and_then(|v| v.devices().find(|d| d.id == pid))
}
pub fn vendor(&self) -> &'static Vendor {
VENDORS.get(&self.vendor_id).unwrap()
}
pub fn as_vid_pid(&self) -> (u16, u16) {
(self.vendor_id, self.id)
}
pub fn id(&self) -> u16 {
self.id
}
pub fn name(&self) -> &'static str {
self.name
}
pub fn subsystems(&self) -> impl Iterator<Item = &'static SubSystem> {
self.subsystems.iter()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SubSystem {
subvendor: u16,
subdevice: u16,
name: &'static str,
}
impl SubSystem {
pub fn subvendor(&self) -> u16 {
self.subvendor
}
pub fn subdevice(&self) -> u16 {
self.subdevice
}
pub fn name(&self) -> &'static str {
self.name
}
}
pub struct Classes;
impl Classes {
pub fn iter() -> impl Iterator<Item = &'static Class> {
CLASSES.values()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Class {
id: u8,
name: &'static str,
subclasses: &'static [Subclass],
}
impl Class {
pub fn id(&self) -> u8 {
self.id
}
pub fn name(&self) -> &'static str {
self.name
}
pub fn subclasses(&self) -> impl Iterator<Item = &'static Subclass> {
self.subclasses.iter()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Subclass {
class_id: u8,
id: u8,
name: &'static str,
prog_ifs: &'static [ProgIf],
}
impl Subclass {
pub fn from_cid_sid(cid: u8, sid: u8) -> Option<&'static Self> {
let class = Class::from_id(cid);
class.and_then(|c| c.subclasses().find(|s| s.id == sid))
}
pub fn class(&self) -> &'static Class {
CLASSES.get(&self.class_id).unwrap()
}
pub fn as_cid_sid(&self) -> (u8, u8) {
(self.class_id, self.id)
}
pub fn id(&self) -> u8 {
self.id
}
pub fn name(&self) -> &'static str {
self.name
}
pub fn prog_ifs(&self) -> impl Iterator<Item = &'static ProgIf> {
self.prog_ifs.iter()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ProgIf {
id: u8,
name: &'static str,
}
impl ProgIf {
pub fn id(&self) -> u8 {
self.id
}
pub fn name(&self) -> &'static str {
self.name
}
}
pub trait FromId<T> {
fn from_id(id: T) -> Option<&'static Self>;
}
impl FromId<u16> for Vendor {
fn from_id(id: u16) -> Option<&'static Self> {
VENDORS.get(&id)
}
}
impl FromId<u8> for Class {
fn from_id(id: u8) -> Option<&'static Self> {
CLASSES.get(&id)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vendor_from_id() {
let vendor = Vendor::from_id(0x14c3).unwrap();
assert_eq!(vendor.name(), "MEDIATEK Corp.");
assert_eq!(vendor.id(), 0x14c3);
}
#[test]
fn test_vendor_devices() {
let vendor = Vendor::from_id(0x17cb).unwrap();
for device in vendor.devices() {
assert_eq!(device.vendor(), vendor);
assert!(!device.name().is_empty());
}
}
#[test]
fn test_device_from_vid_pid() {
let device = Device::from_vid_pid(0x16ae, 0x000a).unwrap();
assert_eq!(device.name(), "SafeXcel 1841");
let (vid, pid) = device.as_vid_pid();
assert_eq!(vid, device.vendor().id());
assert_eq!(pid, device.id());
let device2 = Device::from_vid_pid(vid, pid).unwrap();
assert_eq!(device, device2);
}
#[test]
fn test_class_from_id() {
let class = Class::from_id(0x08).unwrap();
assert_eq!(class.name(), "Generic system peripheral");
assert_eq!(class.id(), 0x08);
}
#[test]
fn test_class_subclasses() {
let class = Class::from_id(0x01).unwrap();
for subclass in class.subclasses() {
assert_eq!(subclass.class(), class);
assert!(!subclass.name().is_empty());
}
}
#[test]
fn test_subclass_from_cid_sid() {
let subclass = Subclass::from_cid_sid(0x07, 0x00).unwrap();
assert_eq!(subclass.name(), "Serial controller");
let (cid, sid) = subclass.as_cid_sid();
assert_eq!(cid, subclass.class().id());
assert_eq!(sid, subclass.id());
let subclass2 = Subclass::from_cid_sid(cid, sid).unwrap();
assert_eq!(subclass, subclass2);
}
}