@@ -115,3 +115,130 @@ unsafe impl Send for Firmware {}
115
115
// SAFETY: `Firmware` only holds a pointer to a C `struct firmware`, references to which are safe to
116
116
// be used from any thread.
117
117
unsafe impl Sync for Firmware { }
118
+
119
+ /// Builder for firmware module info.
120
+ ///
121
+ /// [`ModInfoBuilder`] is a helper component to flexibly compose firmware paths strings for the
122
+ /// .modinfo section in const context.
123
+ ///
124
+ /// Therefore the [`ModInfoBuilder`] provides the methods [`ModInfoBuilder::new_entry`] and
125
+ /// [`ModInfoBuilder::push`], where the latter is used to push path components and the former to
126
+ /// mark the beginning of a new path string.
127
+ ///
128
+ /// [`ModInfoBuilder`] is meant to be used in combination with `kernel::module_firmware!`.
129
+ ///
130
+ /// The const generic `N` as well as the `module_name` parameter of [`ModInfoBuilder::new`] is an
131
+ /// internal implementation detail and supplied through the above macro.
132
+ pub struct ModInfoBuilder < const N : usize > {
133
+ buf : [ u8 ; N ] ,
134
+ n : usize ,
135
+ module_name : & ' static CStr ,
136
+ }
137
+
138
+ impl < const N : usize > ModInfoBuilder < N > {
139
+ /// Create an empty builder instance.
140
+ pub const fn new ( module_name : & ' static CStr ) -> Self {
141
+ Self {
142
+ buf : [ 0 ; N ] ,
143
+ n : 0 ,
144
+ module_name,
145
+ }
146
+ }
147
+
148
+ const fn push_internal ( mut self , bytes : & [ u8 ] ) -> Self {
149
+ let mut j = 0 ;
150
+
151
+ if N == 0 {
152
+ self . n += bytes. len ( ) ;
153
+ return self ;
154
+ }
155
+
156
+ while j < bytes. len ( ) {
157
+ if self . n < N {
158
+ self . buf [ self . n ] = bytes[ j] ;
159
+ }
160
+ self . n += 1 ;
161
+ j += 1 ;
162
+ }
163
+ self
164
+ }
165
+
166
+ /// Push an additional path component.
167
+ ///
168
+ /// Append path components to the [`ModInfoBuilder`] instance. Paths need to be separated
169
+ /// with [`ModInfoBuilder::new_entry`].
170
+ ///
171
+ /// # Example
172
+ ///
173
+ /// ```
174
+ /// use kernel::firmware::ModInfoBuilder;
175
+ ///
176
+ /// # const DIR: &str = "vendor/chip/";
177
+ /// # const fn no_run<const N: usize>(builder: ModInfoBuilder<N>) {
178
+ /// let builder = builder.new_entry()
179
+ /// .push(DIR)
180
+ /// .push("foo.bin")
181
+ /// .new_entry()
182
+ /// .push(DIR)
183
+ /// .push("bar.bin");
184
+ /// # }
185
+ /// ```
186
+ pub const fn push ( self , s : & str ) -> Self {
187
+ // Check whether there has been an initial call to `next_entry()`.
188
+ if N != 0 && self . n == 0 {
189
+ crate :: build_error!( "Must call next_entry() before push()." ) ;
190
+ }
191
+
192
+ self . push_internal ( s. as_bytes ( ) )
193
+ }
194
+
195
+ const fn push_module_name ( self ) -> Self {
196
+ let mut this = self ;
197
+ let module_name = this. module_name ;
198
+
199
+ if !this. module_name . is_empty ( ) {
200
+ this = this. push_internal ( module_name. as_bytes_with_nul ( ) ) ;
201
+
202
+ if N != 0 {
203
+ // Re-use the space taken by the NULL terminator and swap it with the '.' separator.
204
+ this. buf [ this. n - 1 ] = b'.' ;
205
+ }
206
+ }
207
+
208
+ this
209
+ }
210
+
211
+ /// Prepare the [`ModInfoBuilder`] for the next entry.
212
+ ///
213
+ /// This method acts as a separator between module firmware path entries.
214
+ ///
215
+ /// Must be called before constructing a new entry with subsequent calls to
216
+ /// [`ModInfoBuilder::push`].
217
+ ///
218
+ /// See [`ModInfoBuilder::push`] for an example.
219
+ pub const fn new_entry ( self ) -> Self {
220
+ self . push_internal ( b"\0 " )
221
+ . push_module_name ( )
222
+ . push_internal ( b"firmware=" )
223
+ }
224
+
225
+ /// Build the byte array.
226
+ pub const fn build ( self ) -> [ u8 ; N ] {
227
+ // Add the final NULL terminator.
228
+ let this = self . push_internal ( b"\0 " ) ;
229
+
230
+ if this. n == N {
231
+ this. buf
232
+ } else {
233
+ crate :: build_error!( "Length mismatch." ) ;
234
+ }
235
+ }
236
+ }
237
+
238
+ impl ModInfoBuilder < 0 > {
239
+ /// Return the length of the byte array to build.
240
+ pub const fn build_length ( self ) -> usize {
241
+ // Compensate for the NULL terminator added by `build`.
242
+ self . n + 1
243
+ }
244
+ }
0 commit comments