kernel/library/std/
print.rs

1//! # Print Macros and UART Handling
2//!
3//! This module provides functionality for formatted printing through a UART device.
4//! It defines the core printing macros (`print!` and `println!`) used throughout the kernel,
5//! along with the necessary infrastructure to handle UART output.
6//!
7//! ## Examples
8//!
9//! ```
10//! println!("Hello, world!");
11//! println!("Value: {}", 42);
12//! print!("No newline here");
13//! ```
14//!
15//! ## Implementation Details
16//!
17//! The module initializes a UART writer lazily when first used and provides the
18//! core implementation of the `Write` trait for the UART device. It automatically
19//! handles CR+LF conversion for newlines.
20
21/// Implements core printing functionality by writing formatted text to the UART.
22/// This function is called by the `print!` macro and handles lazy initialization
23/// of the UART writer if it doesn't exist.
24///
25/// # Arguments
26///
27/// * `args` - Formatted arguments to print
28///
29/// # Note
30///
31/// This function is not meant to be called directly. Use the `print!` or
32/// `println!` macros instead.
33///
34/// Wraps a UART device to implement the `core::fmt::Write` trait.
35///
36/// This allows the UART to be used with the standard formatting macros.
37use core::fmt;
38use core::fmt::Write;
39
40use crate::device::char::CharDevice;
41use crate::device::manager::DeviceManager;
42use crate::device::{DeviceCapability, DeviceType};
43use crate::early_println;
44
45#[macro_export]
46macro_rules! print {
47    ($($arg:tt)*) => ($crate::library::std::print::_print(format_args!($($arg)*)));
48}
49
50#[macro_export]
51macro_rules! println {
52    ($fmt:expr) => ($crate::print!(concat!($fmt, "\n")));
53    ($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*));
54}
55
56pub fn _print(args: fmt::Arguments) {
57    let manager = DeviceManager::get_manager();
58
59    // Helper: write to a specific CharDevice implementation
60    struct CharDeviceWriter<'a>(&'a dyn CharDevice);
61    impl<'a> fmt::Write for CharDeviceWriter<'a> {
62        fn write_str(&mut self, s: &str) -> fmt::Result {
63            for byte in s.bytes() {
64                if self.0.write_byte(byte).is_err() {
65                    return Err(fmt::Error);
66                }
67            }
68            Ok(())
69        }
70    }
71
72    // 1) Prefer devices that advertise Serial capability (raw UART-like)
73    let count = manager.get_devices_count();
74    for id in 1..=count {
75        if let Some(dev) = manager.get_device(id) {
76            if dev.device_type() == DeviceType::Char
77                && dev.capabilities().contains(&DeviceCapability::Serial)
78                && dev.name() != "null"
79            {
80                if let Some(char_dev) = dev.as_char_device() {
81                    let mut writer = CharDeviceWriter(char_dev);
82                    if writer.write_fmt(args).is_ok() {
83                        return;
84                    }
85                }
86            }
87        }
88    }
89
90    // 2) Otherwise choose any Char device that is NOT TTY-capable and NOT the null sink
91    for id in 1..=count {
92        if let Some(dev) = manager.get_device(id) {
93            if dev.device_type() == DeviceType::Char
94                && !dev.capabilities().contains(&DeviceCapability::Tty)
95            {
96                if let Some(char_dev) = dev.as_char_device() {
97                    let mut writer = CharDeviceWriter(char_dev);
98                    if writer.write_fmt(args).is_ok() {
99                        return;
100                    }
101                }
102            }
103        }
104    }
105
106    // Final fallback: early console
107    early_println!("[print] No usable character device found; using early console");
108}