summaryrefslogtreecommitdiff
path: root/rust/kernel/firmware.rs
blob: 8c54096a6737f41f81e3d4c258b6aa247ddf029e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// SPDX-License-Identifier: GPL-2.0

//! Firmware load
//!
//! C header: [`include/linux/firmware.h`](../../../../include/linux/firmware.h")

use crate::{
    bindings,
    error::Error,
    error::Result,
    device::{RawDevice},
    str::CStr,
    types::Opaque,
};

/// Pointer to a C firmware struct
pub struct Firmware {
    pub fw: Opaque<*const bindings::firmware>,
    fw_size: usize,
}

impl Firmware {
    /// Create a new firmware instance.
    pub const fn new() -> Self {
        Self {
            fw: Opaque::uninit(),
            fw_size: 0,
        }
    }

    pub fn request(&mut self, name: &CStr, dev: &dyn RawDevice) -> Result {
        let ret = unsafe { bindings::request_firmware(self.fw.get(),
                                                      name.as_char_ptr(), dev.raw_device()) };
        if ret != 0 {
            return Err(Error::from_errno(ret));
        }
        self.fw_size = unsafe { (*(*self.fw.get())).size };
        Ok(())
    }

    pub fn request_nowarn(&mut self, name: &CStr, dev: &dyn RawDevice) -> Result {
        let ret = unsafe { bindings::firmware_request_nowarn(self.fw.get(),
                                                             name.as_char_ptr(), dev.raw_device()) };
        if ret != 0 {
            return Err(Error::from_errno(ret));
        }
        self.fw_size = unsafe { (*(*self.fw.get())).size };
        Ok(())
    }

    pub fn size(&self) -> usize {
        self.fw_size
    }
}

impl Drop for Firmware {
    fn drop(&mut self) {
        unsafe {bindings::release_firmware(*self.fw.get())};
    }
}