use crate::{TagHeader, TagType};
use core::fmt;
use core::mem;
use multiboot2_common::{MaybeDynSized, Tag};
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, align(8))]
pub struct VBEInfoTag {
header: TagHeader,
mode: u16,
interface_segment: u16,
interface_offset: u16,
interface_length: u16,
control_info: VBEControlInfo,
mode_info: VBEModeInfo,
}
impl VBEInfoTag {
#[must_use]
pub fn new(
mode: u16,
interface_segment: u16,
interface_offset: u16,
interface_length: u16,
control_info: VBEControlInfo,
mode_info: VBEModeInfo,
) -> Self {
Self {
header: TagHeader::new(Self::ID, mem::size_of::<Self>().try_into().unwrap()),
mode,
interface_segment,
interface_offset,
interface_length,
control_info,
mode_info,
}
}
#[must_use]
pub const fn mode(&self) -> u16 {
self.mode
}
#[must_use]
pub const fn interface_segment(&self) -> u16 {
self.interface_segment
}
#[must_use]
pub const fn interface_offset(&self) -> u16 {
self.interface_offset
}
#[must_use]
pub const fn interface_length(&self) -> u16 {
self.interface_length
}
#[must_use]
pub const fn control_info(&self) -> VBEControlInfo {
self.control_info
}
#[must_use]
pub const fn mode_info(&self) -> VBEModeInfo {
self.mode_info
}
}
impl MaybeDynSized for VBEInfoTag {
type Header = TagHeader;
const BASE_SIZE: usize = mem::size_of::<Self>();
fn dst_len(_: &TagHeader) {}
}
impl Tag for VBEInfoTag {
type IDType = TagType;
const ID: TagType = TagType::Vbe;
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, packed)]
pub struct VBEControlInfo {
pub signature: [u8; 4],
pub version: u16,
pub oem_string_ptr: u32,
pub capabilities: VBECapabilities,
pub mode_list_ptr: u32,
pub total_memory: u16,
pub oem_software_revision: u16,
pub oem_vendor_name_ptr: u32,
pub oem_product_name_ptr: u32,
pub oem_product_revision_ptr: u32,
reserved: [u8; 222],
oem_data: [u8; 256],
}
impl fmt::Debug for VBEControlInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("VBEControlInfo")
.field("signature", &self.signature)
.field("version", &{ self.version })
.field("oem_string_ptr", &{ self.oem_string_ptr })
.field("capabilities", &{ self.capabilities })
.field("mode_list_ptr", &{ self.mode_list_ptr })
.field("total_memory", &{ self.total_memory })
.field("oem_software_revision", &{ self.oem_software_revision })
.field("oem_vendor_name_ptr", &{ self.oem_vendor_name_ptr })
.field("oem_product_name_ptr", &{ self.oem_product_name_ptr })
.field("oem_product_revision_ptr", &{
self.oem_product_revision_ptr
})
.finish()
}
}
impl Default for VBEControlInfo {
fn default() -> Self {
Self {
signature: Default::default(),
version: 0,
oem_string_ptr: 0,
capabilities: Default::default(),
mode_list_ptr: 0,
total_memory: 0,
oem_software_revision: 0,
oem_vendor_name_ptr: 0,
oem_product_name_ptr: 0,
oem_product_revision_ptr: 0,
reserved: [0; 222],
oem_data: [0; 256],
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, packed)]
pub struct VBEModeInfo {
pub mode_attributes: VBEModeAttributes,
pub window_a_attributes: VBEWindowAttributes,
pub window_b_attributes: VBEWindowAttributes,
pub window_granularity: u16,
pub window_size: u16,
pub window_a_segment: u16,
pub window_b_segment: u16,
pub window_function_ptr: u32,
pub pitch: u16,
pub resolution: (u16, u16),
pub character_size: (u8, u8),
pub number_of_planes: u8,
pub bpp: u8,
pub number_of_banks: u8,
pub memory_model: VBEMemoryModel,
pub bank_size: u8,
pub number_of_image_pages: u8,
reserved0: u8,
pub red_field: VBEField,
pub green_field: VBEField,
pub blue_field: VBEField,
pub reserved_field: VBEField,
pub direct_color_attributes: VBEDirectColorAttributes,
pub framebuffer_base_ptr: u32,
pub offscreen_memory_offset: u32,
pub offscreen_memory_size: u16,
reserved1: [u8; 206],
}
impl fmt::Debug for VBEModeInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("VBEModeInfo")
.field("mode_attributes", &{ self.mode_attributes })
.field("window_a_attributes", &self.window_a_attributes)
.field("window_b_attributes", &self.window_b_attributes)
.field("window_granularity", &{ self.window_granularity })
.field("window_size", &{ self.window_size })
.field("window_a_segment", &{ self.window_a_segment })
.field("window_b_segment", &{ self.window_b_segment })
.field("window_function_ptr", &{ self.window_function_ptr })
.field("pitch", &{ self.pitch })
.field("resolution", &{ self.resolution })
.field("character_size", &self.character_size)
.field("number_of_planes", &self.number_of_planes)
.field("bpp", &self.bpp)
.field("number_of_banks", &self.number_of_banks)
.field("memory_model", &self.memory_model)
.field("bank_size", &self.bank_size)
.field("number_of_image_pages", &self.number_of_image_pages)
.field("red_field", &self.red_field)
.field("green_field", &self.green_field)
.field("blue_field", &self.blue_field)
.field("reserved_field", &self.reserved_field)
.field("direct_color_attributes", &self.direct_color_attributes)
.field("framebuffer_base_ptr", &{ self.framebuffer_base_ptr })
.field("offscreen_memory_offset", &{ self.offscreen_memory_offset })
.field("offscreen_memory_size", &{ self.offscreen_memory_size })
.finish()
}
}
impl Default for VBEModeInfo {
fn default() -> Self {
Self {
mode_attributes: Default::default(),
window_a_attributes: Default::default(),
window_b_attributes: Default::default(),
window_granularity: 0,
window_size: 0,
window_a_segment: 0,
window_b_segment: 0,
window_function_ptr: 0,
pitch: 0,
resolution: (0, 0),
character_size: (0, 0),
number_of_planes: 0,
bpp: 0,
number_of_banks: 0,
memory_model: Default::default(),
bank_size: 0,
number_of_image_pages: 0,
reserved0: 0,
red_field: Default::default(),
green_field: Default::default(),
blue_field: Default::default(),
reserved_field: Default::default(),
direct_color_attributes: Default::default(),
framebuffer_base_ptr: 0,
offscreen_memory_offset: 0,
offscreen_memory_size: 0,
reserved1: [0; 206],
}
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, packed)]
pub struct VBEField {
pub size: u8,
pub position: u8,
}
bitflags! {
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct VBECapabilities: u32 {
const SWITCHABLE_DAC = 0x1;
const NOT_VGA_COMPATIBLE = 0x2;
const RAMDAC_FIX = 0x4;
}
}
bitflags! {
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct VBEModeAttributes: u16 {
const SUPPORTED = 0x1;
const TTY_SUPPORTED = 0x4;
const COLOR = 0x8;
const GRAPHICS = 0x10;
const NOT_VGA_COMPATIBLE = 0x20;
const NO_VGA_WINDOW = 0x40;
const LINEAR_FRAMEBUFFER = 0x80;
}
}
bitflags! {
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct VBEWindowAttributes: u8 {
const RELOCATABLE = 0x1;
const READABLE = 0x2;
const WRITEABLE = 0x4;
}
}
bitflags! {
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct VBEDirectColorAttributes: u8 {
const PROGRAMMABLE = 0x1;
const RESERVED_USABLE = 0x2;
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
#[allow(missing_docs)]
#[allow(clippy::upper_case_acronyms)]
pub enum VBEMemoryModel {
#[default]
Text = 0x00,
CGAGraphics = 0x01,
HerculesGraphics = 0x02,
Planar = 0x03,
PackedPixel = 0x04,
Unchained = 0x05,
DirectColor = 0x06,
YUV = 0x07,
}