@@ -116,6 +116,95 @@ unsafe impl Send for Firmware {}
116116// be used from any thread.
117117unsafe impl Sync for Firmware { }
118118
119+ /// Create firmware .modinfo entries.
120+ ///
121+ /// This macro is the counterpart of the C macro `MODULE_FIRMWARE()`, but instead of taking a
122+ /// simple string literals, which is already covered by the `firmware` field of
123+ /// [`crate::prelude::module!`], it allows the caller to pass a builder type, based on the
124+ /// [`ModInfoBuilder`], which can create the firmware modinfo strings in a more flexible way.
125+ ///
126+ /// Drivers should extend the [`ModInfoBuilder`] with their own driver specific builder type.
127+ ///
128+ /// The `builder` argument must be a type which implements the following function.
129+ ///
130+ /// `const fn create(module_name: &'static CStr) -> ModInfoBuilder`
131+ ///
132+ /// `create` should pass the `module_name` to the [`ModInfoBuilder`] and, with the help of
133+ /// it construct the corresponding firmware modinfo.
134+ ///
135+ /// Typically, such contracts would be enforced by a trait, however traits do not (yet) support
136+ /// const functions.
137+ ///
138+ /// # Example
139+ ///
140+ /// ```
141+ /// # mod module_firmware_test {
142+ /// # use kernel::firmware;
143+ /// # use kernel::prelude::*;
144+ /// #
145+ /// # struct MyModule;
146+ /// #
147+ /// # impl kernel::Module for MyModule {
148+ /// # fn init(_module: &'static ThisModule) -> Result<Self> {
149+ /// # Ok(Self)
150+ /// # }
151+ /// # }
152+ /// #
153+ /// #
154+ /// struct Builder<const N: usize>;
155+ ///
156+ /// impl<const N: usize> Builder<N> {
157+ /// const DIR: &'static str = "vendor/chip/";
158+ /// const FILES: [&'static str; 3] = [ "foo", "bar", "baz" ];
159+ ///
160+ /// const fn create(module_name: &'static kernel::str::CStr) -> firmware::ModInfoBuilder<N> {
161+ /// let mut builder = firmware::ModInfoBuilder::new(module_name);
162+ ///
163+ /// let mut i = 0;
164+ /// while i < Self::FILES.len() {
165+ /// builder = builder.new_entry()
166+ /// .push(Self::DIR)
167+ /// .push(Self::FILES[i])
168+ /// .push(".bin");
169+ ///
170+ /// i += 1;
171+ /// }
172+ ///
173+ /// builder
174+ /// }
175+ /// }
176+ ///
177+ /// module! {
178+ /// type: MyModule,
179+ /// name: "module_firmware_test",
180+ /// author: "Rust for Linux",
181+ /// description: "module_firmware! test module",
182+ /// license: "GPL",
183+ /// }
184+ ///
185+ /// kernel::module_firmware!(Builder);
186+ /// # }
187+ /// ```
188+ #[ macro_export]
189+ macro_rules! module_firmware {
190+ // The argument is the builder type without the const generic, since it's deferred from within
191+ // this macro. Hence, we can neither use `expr` nor `ty`.
192+ ( $( $builder: tt) * ) => {
193+ const _: ( ) = {
194+ const __MODULE_FIRMWARE_PREFIX: & ' static $crate:: str :: CStr = if cfg!( MODULE ) {
195+ $crate:: c_str!( "" )
196+ } else {
197+ <LocalModule as $crate:: ModuleMetadata >:: NAME
198+ } ;
199+
200+ #[ link_section = ".modinfo" ]
201+ #[ used]
202+ static __MODULE_FIRMWARE: [ u8 ; $( $builder) * :: create( __MODULE_FIRMWARE_PREFIX)
203+ . build_length( ) ] = $( $builder) * :: create( __MODULE_FIRMWARE_PREFIX) . build( ) ;
204+ } ;
205+ } ;
206+ }
207+
119208/// Builder for firmware module info.
120209///
121210/// [`ModInfoBuilder`] is a helper component to flexibly compose firmware paths strings for the
@@ -125,7 +214,7 @@ unsafe impl Sync for Firmware {}
125214/// [`ModInfoBuilder::push`], where the latter is used to push path components and the former to
126215/// mark the beginning of a new path string.
127216///
128- /// [`ModInfoBuilder`] is meant to be used in combination with `kernel::module_firmware!`.
217+ /// [`ModInfoBuilder`] is meant to be used in combination with [ `kernel::module_firmware!`] .
129218///
130219/// The const generic `N` as well as the `module_name` parameter of [`ModInfoBuilder::new`] is an
131220/// internal implementation detail and supplied through the above macro.
0 commit comments