/*
 * Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan@pm.me>
 *
 * SPDX-License-Identifier: MPL-2.0
 */

pub mod class;
pub mod device;
pub mod vendors;

// MassStorage_IDE (0x0101)
pub mod ide;

use alloc::sync::Arc;
pub use class::*;
pub use device::*;
use lazy_static::lazy_static;
use spin::Mutex;
use x86_64::structures::paging::{Mapper, Size4KiB};

use crate::arch::memory::BootInfoFrameAllocator;

// MassStorage_IDE (0x0101)
use self::ide::PciIde;

lazy_static! {
    pub static ref PCI_DEVICES: Mutex<Vec<Arc<Mutex<PciDevice>>>> = Default::default();
}

#[non_exhaustive]
pub enum PciDevice {
    Ide(PciIde),
    // Variant so that we aren't about irrefutable if-let patterns
    // FIXME: remove as soon as we have other variants
    _0,
}

/// Enumerate PCI devices and run initialisation routines on ones we support
pub fn init(mapper: &mut impl Mapper<Size4KiB>, frame_allocator: &mut BootInfoFrameAllocator) {
    for bus in 0..=255 {
        for device in 0..32 {
            if let Some(device_info) = device::check_device(bus, device) {
                trace!("{device_info}");
                match device_info.device_id {
                    // FIXME: Unknown class
                    S3_TRIO64V2 => {}

                    // MassStorage_IDE (0x0101)
                    ide_controller if device_info.full_class == PciFullClass::MassStorage_IDE => {
                        if !matches!(ide_controller, INTEL_PIIX3_IDE | INTEL_PIIX4_IDE) {
                            // not one of our tested IDE controllers, but
                            // we shouldn't have any problems
                            warn!("Unsupported PCI IDE controller device {device} on bus {bus}")
                        }

                        let mut ide = PciIde::new(bus, device).unwrap();
                        ide.allocate_dma_frame(mapper, frame_allocator).unwrap();
                        let mut devices = PCI_DEVICES.lock();
                        devices.push(Arc::new(Mutex::new(PciDevice::Ide(ide))));
                    }

                    // Display_VGA (0x0300)
                    VMWARE_SVGA2 => {}
                    _ => {
                        trace!("Unknown PCI device {device} on bus {bus}")
                    }
                }
            }
        }
    }
}
