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}