| 1 | |
| 2 |
|
| 3 | use std::ffi::CString;
|
| 4 |
|
| 5 | use proc_macro2::{
|
| 6 | Literal,
|
| 7 | TokenStream, |
| 8 | };
|
| 9 | use quote::{
|
| 10 | format_ident,
|
| 11 | quote, |
| 12 | };
|
| 13 | use syn::{
|
| 14 | braced,
|
| 15 | bracketed,
|
| 16 | ext::IdentExt,
|
| 17 | parse::{
|
| 18 | Parse,
|
| 19 | ParseStream, |
| 20 | },
|
| 21 | parse_quote,
|
| 22 | punctuated::Punctuated,
|
| 23 | Error,
|
| 24 | Expr,
|
| 25 | Ident,
|
| 26 | LitStr,
|
| 27 | Path,
|
| 28 | Result,
|
| 29 | Token,
|
| 30 | Type, |
| 31 | };
|
| 32 |
|
| 33 | use crate::helpers::*;
|
| 34 |
|
| 35 | struct ModInfoBuilder<'a> {
|
| 36 | module: &'a str,
|
| 37 | counter: usize,
|
| 38 | ts: TokenStream,
|
| 39 | param_ts: TokenStream,
|
| 40 | }
|
| 41 |
|
| 42 | impl<'a> ModInfoBuilder<'a> {
|
| 43 | fn new(module: &'a str) -> Self {
|
| 44 | ModInfoBuilder {
|
| 45 | module,
|
| 46 | counter: 0,
|
| 47 | ts: TokenStream::new(),
|
| 48 | param_ts: TokenStream::new(),
|
| 49 | }
|
| 50 | }
|
| 51 |
|
| 52 | fn emit_base(&mut self, field: &str, content: &str, builtin: bool, param: bool) {
|
| 53 | let string = if builtin {
|
| 54 | |
| 55 | format!("{module}.{field}={content}\0", module = self.module)
|
| 56 | } else {
|
| 57 | |
| 58 | format!("{field}={content}\0")
|
| 59 | };
|
| 60 | let length = string.len();
|
| 61 | let string = Literal::byte_string(string.as_bytes());
|
| 62 | let cfg = if builtin {
|
| 63 | quote!(#[cfg(not(MODULE))])
|
| 64 | } else {
|
| 65 | quote!(#[cfg(MODULE)])
|
| 66 | };
|
| 67 |
|
| 68 | let counter = format_ident!(
|
| 69 | "__{module}_{counter}",
|
| 70 | module = self.module.to_uppercase(),
|
| 71 | counter = self.counter
|
| 72 | );
|
| 73 | let item = quote! {
|
| 74 | #cfg
|
| 75 | #[cfg_attr(not(target_os = "macos"), link_section = ".modinfo")]
|
| 76 | #[used(compiler)]
|
| 77 | pub static #counter: [u8; #length] = *#string;
|
| 78 | };
|
| 79 |
|
| 80 | if param {
|
| 81 | self.param_ts.extend(item);
|
| 82 | } else {
|
| 83 | self.ts.extend(item);
|
| 84 | }
|
| 85 |
|
| 86 | self.counter += 1;
|
| 87 | }
|
| 88 |
|
| 89 | fn emit_only_builtin(&mut self, field: &str, content: &str, param: bool) {
|
| 90 | self.emit_base(field, content, true, param)
|
| 91 | }
|
| 92 |
|
| 93 | fn emit_only_loadable(&mut self, field: &str, content: &str, param: bool) {
|
| 94 | self.emit_base(field, content, false, param)
|
| 95 | }
|
| 96 |
|
| 97 | fn emit(&mut self, field: &str, content: &str) {
|
| 98 | self.emit_internal(field, content, false);
|
| 99 | }
|
| 100 |
|
| 101 | fn emit_internal(&mut self, field: &str, content: &str, param: bool) {
|
| 102 | self.emit_only_builtin(field, content, param);
|
| 103 | self.emit_only_loadable(field, content, param);
|
| 104 | }
|
| 105 |
|
| 106 | fn emit_param(&mut self, field: &str, param: &str, content: &str) {
|
| 107 | let content = format!("{param}:{content}");
|
| 108 | self.emit_internal(field, &content, true);
|
| 109 | }
|
| 110 |
|
| 111 | fn emit_params(&mut self, info: &ModuleInfo) {
|
| 112 | let Some(params) = &info.params else {
|
| 113 | return;
|
| 114 | };
|
| 115 |
|
| 116 | for param in params {
|
| 117 | let param_name_str = param.name.to_string();
|
| 118 | let param_type_str = param.ptype.to_string();
|
| 119 |
|
| 120 | let ops = param_ops_path(¶m_type_str);
|
| 121 |
|
| 122 | |
| 123 | |
| 124 | self.emit_param("parmtype", ¶m_name_str, ¶m_type_str);
|
| 125 | self.emit_param("parm", ¶m_name_str, ¶m.description.value());
|
| 126 |
|
| 127 | let static_name = format_ident!("__{}_{}_struct", self.module, param.name);
|
| 128 | let param_name_cstr =
|
| 129 | CString::new(param_name_str).expect("name contains NUL-terminator");
|
| 130 | let param_name_cstr_with_module =
|
| 131 | CString::new(format!("{}.{}", self.module, param.name))
|
| 132 | .expect("name contains NUL-terminator");
|
| 133 |
|
| 134 | let param_name = ¶m.name;
|
| 135 | let param_type = ¶m.ptype;
|
| 136 | let param_default = ¶m.default;
|
| 137 |
|
| 138 | self.param_ts.extend(quote! {
|
| 139 | #[allow(non_upper_case_globals)]
|
| 140 | pub(crate) static #param_name:
|
| 141 | ::kernel::module_param::ModuleParamAccess<#param_type> =
|
| 142 | ::kernel::module_param::ModuleParamAccess::new(#param_default);
|
| 143 |
|
| 144 | const _: () = {
|
| 145 | #[allow(non_upper_case_globals)]
|
| 146 | #[link_section = "__param"]
|
| 147 | #[used(compiler)]
|
| 148 | static #static_name:
|
| 149 | ::kernel::module_param::KernelParam =
|
| 150 | ::kernel::module_param::KernelParam::new(
|
| 151 | ::kernel::bindings::kernel_param {
|
| 152 | name: kernel::str::as_char_ptr_in_const_context(
|
| 153 | if ::core::cfg!(MODULE) {
|
| 154 | #param_name_cstr
|
| 155 | } else {
|
| 156 | #param_name_cstr_with_module
|
| 157 | }
|
| 158 | ),
|
| 159 | |
| 160 | |
| 161 | #[cfg(MODULE)]
|
| 162 | mod_: unsafe {
|
| 163 | core::ptr::from_ref(&::kernel::bindings::__this_module)
|
| 164 | .cast_mut()
|
| 165 | },
|
| 166 | #[cfg(not(MODULE))]
|
| 167 | mod_: ::core::ptr::null_mut(),
|
| 168 | ops: core::ptr::from_ref(&#ops),
|
| 169 | perm: 0, |
| 170 | level: -1,
|
| 171 | flags: 0,
|
| 172 | __bindgen_anon_1: ::kernel::bindings::kernel_param__bindgen_ty_1 {
|
| 173 | arg: #param_name.as_void_ptr()
|
| 174 | },
|
| 175 | }
|
| 176 | );
|
| 177 | };
|
| 178 | });
|
| 179 | }
|
| 180 | }
|
| 181 | }
|
| 182 |
|
| 183 | fn param_ops_path(param_type: &str) -> Path {
|
| 184 | match param_type {
|
| 185 | "i8" => parse_quote!(::kernel::module_param::PARAM_OPS_I8),
|
| 186 | "u8" => parse_quote!(::kernel::module_param::PARAM_OPS_U8),
|
| 187 | "i16" => parse_quote!(::kernel::module_param::PARAM_OPS_I16),
|
| 188 | "u16" => parse_quote!(::kernel::module_param::PARAM_OPS_U16),
|
| 189 | "i32" => parse_quote!(::kernel::module_param::PARAM_OPS_I32),
|
| 190 | "u32" => parse_quote!(::kernel::module_param::PARAM_OPS_U32),
|
| 191 | "i64" => parse_quote!(::kernel::module_param::PARAM_OPS_I64),
|
| 192 | "u64" => parse_quote!(::kernel::module_param::PARAM_OPS_U64),
|
| 193 | "isize" => parse_quote!(::kernel::module_param::PARAM_OPS_ISIZE),
|
| 194 | "usize" => parse_quote!(::kernel::module_param::PARAM_OPS_USIZE),
|
| 195 | "bool" => parse_quote!(::kernel::module_param::PARAM_OPS_BOOL),
|
| 196 | t => panic!("Unsupported parameter type {}", t),
|
| 197 | }
|
| 198 | }
|
| 199 |
|
| 200 | |
| 201 | |
| 202 | |
| 203 | |
| 204 | |
| 205 | |
| 206 | |
| 207 | |
| 208 | |
| 209 | |
| 210 | |
| 211 | |
| 212 | |
| 213 | |
| 214 | |
| 215 | |
| 216 | |
| 217 | |
| 218 | |
| 219 | |
| 220 | |
| 221 | |
| 222 | |
| 223 | |
| 224 | |
| 225 | |
| 226 | |
| 227 | macro_rules! parse_ordered_fields {
|
| 228 | (@gen
|
| 229 | [$input:expr]
|
| 230 | [$([$name:ident; $key:ident; $parser:expr])*]
|
| 231 | [$([$req_name:ident; $req_key:ident])*]
|
| 232 | ) => {
|
| 233 | $(let mut $name = None;)*
|
| 234 |
|
| 235 | const EXPECTED_KEYS: &[&str] = &[$(stringify!($key),)*];
|
| 236 | const REQUIRED_KEYS: &[&str] = &[$(stringify!($req_key),)*];
|
| 237 |
|
| 238 | let span = $input.span();
|
| 239 | let mut seen_keys = Vec::new();
|
| 240 |
|
| 241 | while !$input.is_empty() {
|
| 242 | let key = $input.call(Ident::parse_any)?;
|
| 243 |
|
| 244 | if seen_keys.contains(&key) {
|
| 245 | Err(Error::new_spanned(
|
| 246 | &key,
|
| 247 | format!(r#"duplicated key "{key}". Keys can only be specified once."#),
|
| 248 | ))?
|
| 249 | }
|
| 250 |
|
| 251 | $input.parse::<Token![:]>()?;
|
| 252 |
|
| 253 | match &*key.to_string() {
|
| 254 | $(
|
| 255 | stringify!($key) => $name = Some($parser),
|
| 256 | )*
|
| 257 | _ => {
|
| 258 | Err(Error::new_spanned(
|
| 259 | &key,
|
| 260 | format!(r#"unknown key "{key}". Valid keys are: {EXPECTED_KEYS:?}."#),
|
| 261 | ))?
|
| 262 | }
|
| 263 | }
|
| 264 |
|
| 265 | $input.parse::<Token![,]>()?;
|
| 266 | seen_keys.push(key);
|
| 267 | }
|
| 268 |
|
| 269 | for key in REQUIRED_KEYS {
|
| 270 | if !seen_keys.iter().any(|e| e == key) {
|
| 271 | Err(Error::new(span, format!(r#"missing required key "{key}""#)))?
|
| 272 | }
|
| 273 | }
|
| 274 |
|
| 275 | let mut ordered_keys: Vec<&str> = Vec::new();
|
| 276 | for key in EXPECTED_KEYS {
|
| 277 | if seen_keys.iter().any(|e| e == key) {
|
| 278 | ordered_keys.push(key);
|
| 279 | }
|
| 280 | }
|
| 281 |
|
| 282 | if seen_keys != ordered_keys {
|
| 283 | Err(Error::new(
|
| 284 | span,
|
| 285 | format!(r#"keys are not ordered as expected. Order them like: {ordered_keys:?}."#),
|
| 286 | ))?
|
| 287 | }
|
| 288 |
|
| 289 | $(let $req_name = $req_name.expect("required field");)*
|
| 290 | };
|
| 291 |
|
| 292 | |
| 293 | (@gen
|
| 294 | [$input:expr] [$($tok:tt)*] [$($req:tt)*]
|
| 295 | $key:ident as $name:ident [required] => $parser:expr,
|
| 296 | $($rest:tt)*
|
| 297 | ) => {
|
| 298 | parse_ordered_fields!(
|
| 299 | @gen [$input] [$($tok)* [$name; $key; $parser]] [$($req)* [$name; $key]] $($rest)*
|
| 300 | )
|
| 301 | };
|
| 302 | (@gen
|
| 303 | [$input:expr] [$($tok:tt)*] [$($req:tt)*]
|
| 304 | $name:ident [required] => $parser:expr,
|
| 305 | $($rest:tt)*
|
| 306 | ) => {
|
| 307 | parse_ordered_fields!(
|
| 308 | @gen [$input] [$($tok)* [$name; $name; $parser]] [$($req)* [$name; $name]] $($rest)*
|
| 309 | )
|
| 310 | };
|
| 311 |
|
| 312 | |
| 313 | (@gen
|
| 314 | [$input:expr] [$($tok:tt)*] [$($req:tt)*]
|
| 315 | $key:ident as $name:ident => $parser:expr,
|
| 316 | $($rest:tt)*
|
| 317 | ) => {
|
| 318 | parse_ordered_fields!(
|
| 319 | @gen [$input] [$($tok)* [$name; $key; $parser]] [$($req)*] $($rest)*
|
| 320 | )
|
| 321 | };
|
| 322 | (@gen
|
| 323 | [$input:expr] [$($tok:tt)*] [$($req:tt)*]
|
| 324 | $name:ident => $parser:expr,
|
| 325 | $($rest:tt)*
|
| 326 | ) => {
|
| 327 | parse_ordered_fields!(
|
| 328 | @gen [$input] [$($tok)* [$name; $name; $parser]] [$($req)*] $($rest)*
|
| 329 | )
|
| 330 | };
|
| 331 |
|
| 332 | (from $input:expr; $($tok:tt)*) => {
|
| 333 | parse_ordered_fields!(@gen [$input] [] [] $($tok)*)
|
| 334 | }
|
| 335 | }
|
| 336 |
|
| 337 | struct Parameter {
|
| 338 | name: Ident,
|
| 339 | ptype: Ident,
|
| 340 | default: Expr,
|
| 341 | description: LitStr,
|
| 342 | }
|
| 343 |
|
| 344 | impl Parse for Parameter {
|
| 345 | fn parse(input: ParseStream<'_>) -> Result<Self> {
|
| 346 | let name = input.parse()?;
|
| 347 | input.parse::<Token![:]>()?;
|
| 348 | let ptype = input.parse()?;
|
| 349 |
|
| 350 | let fields;
|
| 351 | braced!(fields in input);
|
| 352 |
|
| 353 | parse_ordered_fields! {
|
| 354 | from fields;
|
| 355 | default [required] => fields.parse()?,
|
| 356 | description [required] => fields.parse()?,
|
| 357 | }
|
| 358 |
|
| 359 | Ok(Self {
|
| 360 | name,
|
| 361 | ptype,
|
| 362 | default,
|
| 363 | description,
|
| 364 | })
|
| 365 | }
|
| 366 | }
|
| 367 |
|
| 368 | pub(crate) struct ModuleInfo {
|
| 369 | type_: Type,
|
| 370 | license: AsciiLitStr,
|
| 371 | name: AsciiLitStr,
|
| 372 | authors: Option<Punctuated<AsciiLitStr, Token![,]>>,
|
| 373 | description: Option<LitStr>,
|
| 374 | alias: Option<Punctuated<AsciiLitStr, Token![,]>>,
|
| 375 | firmware: Option<Punctuated<AsciiLitStr, Token![,]>>,
|
| 376 | imports_ns: Option<Punctuated<AsciiLitStr, Token![,]>>,
|
| 377 | params: Option<Punctuated<Parameter, Token![,]>>,
|
| 378 | }
|
| 379 |
|
| 380 | impl Parse for ModuleInfo {
|
| 381 | fn parse(input: ParseStream<'_>) -> Result<Self> {
|
| 382 | parse_ordered_fields!(
|
| 383 | from input;
|
| 384 | type as type_ [required] => input.parse()?,
|
| 385 | name [required] => input.parse()?,
|
| 386 | authors => {
|
| 387 | let list;
|
| 388 | bracketed!(list in input);
|
| 389 | Punctuated::parse_terminated(&list)?
|
| 390 | },
|
| 391 | description => input.parse()?,
|
| 392 | license [required] => input.parse()?,
|
| 393 | alias => {
|
| 394 | let list;
|
| 395 | bracketed!(list in input);
|
| 396 | Punctuated::parse_terminated(&list)?
|
| 397 | },
|
| 398 | firmware => {
|
| 399 | let list;
|
| 400 | bracketed!(list in input);
|
| 401 | Punctuated::parse_terminated(&list)?
|
| 402 | },
|
| 403 | imports_ns => {
|
| 404 | let list;
|
| 405 | bracketed!(list in input);
|
| 406 | Punctuated::parse_terminated(&list)?
|
| 407 | },
|
| 408 | params => {
|
| 409 | let list;
|
| 410 | braced!(list in input);
|
| 411 | Punctuated::parse_terminated(&list)?
|
| 412 | },
|
| 413 | );
|
| 414 |
|
| 415 | Ok(ModuleInfo {
|
| 416 | type_,
|
| 417 | license,
|
| 418 | name,
|
| 419 | authors,
|
| 420 | description,
|
| 421 | alias,
|
| 422 | firmware,
|
| 423 | imports_ns,
|
| 424 | params,
|
| 425 | })
|
| 426 | }
|
| 427 | }
|
| 428 |
|
| 429 | pub(crate) fn module(info: ModuleInfo) -> Result<TokenStream> {
|
| 430 | let ModuleInfo {
|
| 431 | type_,
|
| 432 | license,
|
| 433 | name,
|
| 434 | authors,
|
| 435 | description,
|
| 436 | alias,
|
| 437 | firmware,
|
| 438 | imports_ns,
|
| 439 | params: _,
|
| 440 | } = &info;
|
| 441 |
|
| 442 | |
| 443 | let ident = name.value().replace('-', "_");
|
| 444 | let mut modinfo = ModInfoBuilder::new(ident.as_ref());
|
| 445 | if let Some(authors) = authors {
|
| 446 | for author in authors {
|
| 447 | modinfo.emit("author", &author.value());
|
| 448 | }
|
| 449 | }
|
| 450 | if let Some(description) = description {
|
| 451 | modinfo.emit("description", &description.value());
|
| 452 | }
|
| 453 | modinfo.emit("license", &license.value());
|
| 454 | if let Some(aliases) = alias {
|
| 455 | for alias in aliases {
|
| 456 | modinfo.emit("alias", &alias.value());
|
| 457 | }
|
| 458 | }
|
| 459 | if let Some(firmware) = firmware {
|
| 460 | for fw in firmware {
|
| 461 | modinfo.emit("firmware", &fw.value());
|
| 462 | }
|
| 463 | }
|
| 464 | if let Some(imports) = imports_ns {
|
| 465 | for ns in imports {
|
| 466 | modinfo.emit("import_ns", &ns.value());
|
| 467 | }
|
| 468 | }
|
| 469 |
|
| 470 | |
| 471 | let file =
|
| 472 | std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable");
|
| 473 | modinfo.emit_only_builtin("file", &file, false);
|
| 474 |
|
| 475 | modinfo.emit_params(&info);
|
| 476 |
|
| 477 | let modinfo_ts = modinfo.ts;
|
| 478 | let params_ts = modinfo.param_ts;
|
| 479 |
|
| 480 | let ident_init = format_ident!("__{ident}_init");
|
| 481 | let ident_exit = format_ident!("__{ident}_exit");
|
| 482 | let ident_initcall = format_ident!("__{ident}_initcall");
|
| 483 | let initcall_section = ".initcall6.init";
|
| 484 |
|
| 485 | let global_asm = format!(
|
| 486 | r#".section "{initcall_section}", "a"
|
| 487 | __{ident}_initcall:
|
| 488 | .long __{ident}_init - .
|
| 489 | .previous
|
| 490 | "#
|
| 491 | );
|
| 492 |
|
| 493 | let name_cstr = CString::new(name.value()).expect("name contains NUL-terminator");
|
| 494 |
|
| 495 | Ok(quote! {
|
| 496 | |
| 497 | |
| 498 | |
| 499 | const __LOG_PREFIX: &[u8] = #name_cstr.to_bytes_with_nul();
|
| 500 |
|
| 501 | |
| 502 | |
| 503 | type LocalModule = #type_;
|
| 504 |
|
| 505 | impl ::kernel::ModuleMetadata for #type_ {
|
| 506 | const NAME: &'static ::kernel::str::CStr = #name_cstr;
|
| 507 |
|
| 508 | #[cfg(MODULE)]
|
| 509 | const THIS_MODULE: ::kernel::ThisModule = {
|
| 510 | extern "C" {
|
| 511 | static __this_module: ::kernel::types::Opaque<::kernel::bindings::module>;
|
| 512 | }
|
| 513 |
|
| 514 | |
| 515 | |
| 516 | unsafe { ::kernel::ThisModule::from_ptr(__this_module.get()) }
|
| 517 | };
|
| 518 |
|
| 519 | #[cfg(not(MODULE))]
|
| 520 | const THIS_MODULE: ::kernel::ThisModule = unsafe {
|
| 521 | ::kernel::ThisModule::from_ptr(::core::ptr::null_mut())
|
| 522 | };
|
| 523 | }
|
| 524 |
|
| 525 | |
| 526 | #[doc(hidden)]
|
| 527 | mod __module_init {
|
| 528 | mod __module_init {
|
| 529 | use pin_init::PinInit;
|
| 530 |
|
| 531 | |
| 532 | |
| 533 | |
| 534 | |
| 535 | #[cfg(MODULE)]
|
| 536 | #[used(compiler)]
|
| 537 | static __IS_RUST_MODULE: () = ();
|
| 538 |
|
| 539 | static mut __MOD: ::core::mem::MaybeUninit<super::super::LocalModule> =
|
| 540 | ::core::mem::MaybeUninit::uninit();
|
| 541 |
|
| 542 | |
| 543 | |
| 544 | |
| 545 | |
| 546 | |
| 547 | #[cfg(MODULE)]
|
| 548 | #[no_mangle]
|
| 549 | #[link_section = ".init.text"]
|
| 550 | pub unsafe extern "C" fn init_module() -> ::kernel::ffi::c_int {
|
| 551 | |
| 552 | |
| 553 | |
| 554 | unsafe { __init() }
|
| 555 | }
|
| 556 |
|
| 557 | #[cfg(MODULE)]
|
| 558 | #[used(compiler)]
|
| 559 | #[link_section = ".init.data"]
|
| 560 | static __UNIQUE_ID___addressable_init_module: unsafe extern "C" fn() -> i32 =
|
| 561 | init_module;
|
| 562 |
|
| 563 | #[cfg(MODULE)]
|
| 564 | #[no_mangle]
|
| 565 | #[link_section = ".exit.text"]
|
| 566 | pub extern "C" fn cleanup_module() {
|
| 567 | |
| 568 | |
| 569 | |
| 570 | |
| 571 | |
| 572 | |
| 573 | unsafe { __exit() }
|
| 574 | }
|
| 575 |
|
| 576 | #[cfg(MODULE)]
|
| 577 | #[used(compiler)]
|
| 578 | #[link_section = ".exit.data"]
|
| 579 | static __UNIQUE_ID___addressable_cleanup_module: extern "C" fn() = cleanup_module;
|
| 580 |
|
| 581 | |
| 582 | |
| 583 | #[cfg(not(MODULE))]
|
| 584 | #[cfg(not(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS))]
|
| 585 | #[link_section = #initcall_section]
|
| 586 | #[used(compiler)]
|
| 587 | pub static #ident_initcall: extern "C" fn() ->
|
| 588 | ::kernel::ffi::c_int = #ident_init;
|
| 589 |
|
| 590 | #[cfg(not(MODULE))]
|
| 591 | #[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)]
|
| 592 | ::core::arch::global_asm!(#global_asm);
|
| 593 |
|
| 594 | #[cfg(not(MODULE))]
|
| 595 | #[no_mangle]
|
| 596 | pub extern "C" fn #ident_init() -> ::kernel::ffi::c_int {
|
| 597 | |
| 598 | |
| 599 | |
| 600 | unsafe { __init() }
|
| 601 | }
|
| 602 |
|
| 603 | #[cfg(not(MODULE))]
|
| 604 | #[no_mangle]
|
| 605 | pub extern "C" fn #ident_exit() {
|
| 606 | |
| 607 | |
| 608 | |
| 609 | |
| 610 | |
| 611 | |
| 612 | unsafe { __exit() }
|
| 613 | }
|
| 614 |
|
| 615 | |
| 616 | |
| 617 | |
| 618 | unsafe fn __init() -> ::kernel::ffi::c_int {
|
| 619 | let initer = <super::super::LocalModule as ::kernel::InPlaceModule>::init(
|
| 620 | ::kernel::module::this_module::<super::super::LocalModule>()
|
| 621 | );
|
| 622 | |
| 623 | |
| 624 | |
| 625 | match unsafe { ::pin_init::raw_try_init(__MOD.as_mut_ptr(), initer) } {
|
| 626 | Ok(m) => 0,
|
| 627 | Err(e) => e.to_errno(),
|
| 628 | }
|
| 629 | }
|
| 630 |
|
| 631 | |
| 632 | |
| 633 | |
| 634 | |
| 635 | |
| 636 | unsafe fn __exit() {
|
| 637 | |
| 638 | |
| 639 | |
| 640 | unsafe {
|
| 641 | |
| 642 | __MOD.assume_init_drop();
|
| 643 | }
|
| 644 | }
|
| 645 |
|
| 646 | #modinfo_ts
|
| 647 | }
|
| 648 | }
|
| 649 |
|
| 650 | mod module_parameters {
|
| 651 | #params_ts
|
| 652 | }
|
| 653 | })
|
| 654 | }
|