rust: add 'firmware' field support to module! macro

This adds 'firmware' field support to module! macro, corresponds to
MODULE_FIRMWARE macro. You can specify the file names of binary
firmware that the kernel module requires. The information is embedded
in the modinfo section of the kernel module. For example, a tool to
build an initramfs uses this information to put the firmware files
into the initramfs image.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
Link: https://lore.kernel.org/r/20240501123548.51769-1-fujita.tomonori@gmail.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
FUJITA Tomonori 2024-05-01 21:35:48 +09:00 committed by Miguel Ojeda
parent 63249a070e
commit 549d3c2ffb
2 changed files with 48 additions and 2 deletions

View File

@ -56,6 +56,36 @@ use proc_macro::TokenStream;
/// } /// }
/// ``` /// ```
/// ///
/// ## Firmware
///
/// The following example shows how to declare a kernel module that needs
/// to load binary firmware files. You need to specify the file names of
/// the firmware in the `firmware` field. The information is embedded
/// in the `modinfo` section of the kernel module. For example, a tool to
/// build an initramfs uses this information to put the firmware files into
/// the initramfs image.
///
/// ```ignore
/// use kernel::prelude::*;
///
/// module!{
/// type: MyDeviceDriverModule,
/// name: "my_device_driver_module",
/// author: "Rust for Linux Contributors",
/// description: "My device driver requires firmware",
/// license: "GPL",
/// firmware: ["my_device_firmware1.bin", "my_device_firmware2.bin"],
/// }
///
/// struct MyDeviceDriverModule;
///
/// impl kernel::Module for MyDeviceDriverModule {
/// fn init() -> Result<Self> {
/// Ok(Self)
/// }
/// }
/// ```
///
/// # Supported argument types /// # Supported argument types
/// - `type`: type which implements the [`Module`] trait (required). /// - `type`: type which implements the [`Module`] trait (required).
/// - `name`: ASCII string literal of the name of the kernel module (required). /// - `name`: ASCII string literal of the name of the kernel module (required).
@ -63,6 +93,8 @@ use proc_macro::TokenStream;
/// - `description`: string literal of the description of the kernel module. /// - `description`: string literal of the description of the kernel module.
/// - `license`: ASCII string literal of the license of the kernel module (required). /// - `license`: ASCII string literal of the license of the kernel module (required).
/// - `alias`: array of ASCII string literals of the alias names of the kernel module. /// - `alias`: array of ASCII string literals of the alias names of the kernel module.
/// - `firmware`: array of ASCII string literals of the firmware files of
/// the kernel module.
#[proc_macro] #[proc_macro]
pub fn module(ts: TokenStream) -> TokenStream { pub fn module(ts: TokenStream) -> TokenStream {
module::module(ts) module::module(ts)

View File

@ -97,14 +97,22 @@ struct ModuleInfo {
author: Option<String>, author: Option<String>,
description: Option<String>, description: Option<String>,
alias: Option<Vec<String>>, alias: Option<Vec<String>>,
firmware: Option<Vec<String>>,
} }
impl ModuleInfo { impl ModuleInfo {
fn parse(it: &mut token_stream::IntoIter) -> Self { fn parse(it: &mut token_stream::IntoIter) -> Self {
let mut info = ModuleInfo::default(); let mut info = ModuleInfo::default();
const EXPECTED_KEYS: &[&str] = const EXPECTED_KEYS: &[&str] = &[
&["type", "name", "author", "description", "license", "alias"]; "type",
"name",
"author",
"description",
"license",
"alias",
"firmware",
];
const REQUIRED_KEYS: &[&str] = &["type", "name", "license"]; const REQUIRED_KEYS: &[&str] = &["type", "name", "license"];
let mut seen_keys = Vec::new(); let mut seen_keys = Vec::new();
@ -131,6 +139,7 @@ impl ModuleInfo {
"description" => info.description = Some(expect_string(it)), "description" => info.description = Some(expect_string(it)),
"license" => info.license = expect_string_ascii(it), "license" => info.license = expect_string_ascii(it),
"alias" => info.alias = Some(expect_string_array(it)), "alias" => info.alias = Some(expect_string_array(it)),
"firmware" => info.firmware = Some(expect_string_array(it)),
_ => panic!( _ => panic!(
"Unknown key \"{}\". Valid keys are: {:?}.", "Unknown key \"{}\". Valid keys are: {:?}.",
key, EXPECTED_KEYS key, EXPECTED_KEYS
@ -186,6 +195,11 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
modinfo.emit("alias", &alias); modinfo.emit("alias", &alias);
} }
} }
if let Some(firmware) = info.firmware {
for fw in firmware {
modinfo.emit("firmware", &fw);
}
}
// Built-in modules also export the `file` modinfo string. // Built-in modules also export the `file` modinfo string.
let file = let file =