| 1 | |
| 2 |
|
| 3 | |
| 4 |
|
| 5 | use kernel::alloc::flags;
|
| 6 | use kernel::configfs;
|
| 7 | use kernel::configfs::configfs_attrs;
|
| 8 | use kernel::new_mutex;
|
| 9 | use kernel::page::PAGE_SIZE;
|
| 10 | use kernel::prelude::*;
|
| 11 | use kernel::sync::Mutex;
|
| 12 |
|
| 13 | module! {
|
| 14 | type: RustConfigfs,
|
| 15 | name: "rust_configfs",
|
| 16 | authors: ["Rust for Linux Contributors"],
|
| 17 | description: "Rust configfs sample",
|
| 18 | license: "GPL",
|
| 19 | }
|
| 20 |
|
| 21 | #[pin_data]
|
| 22 | struct RustConfigfs {
|
| 23 | #[pin]
|
| 24 | config: configfs::Subsystem<Configuration>,
|
| 25 | }
|
| 26 |
|
| 27 | #[pin_data]
|
| 28 | struct Configuration {
|
| 29 | message: &'static CStr,
|
| 30 | #[pin]
|
| 31 | bar: Mutex<(KBox<[u8; PAGE_SIZE]>, usize)>,
|
| 32 | }
|
| 33 |
|
| 34 | impl Configuration {
|
| 35 | fn new() -> impl PinInit<Self, Error> {
|
| 36 | try_pin_init!(Self {
|
| 37 | message: c"Hello World\n",
|
| 38 | bar <- new_mutex!((KBox::new([0; PAGE_SIZE], flags::GFP_KERNEL)?, 0)),
|
| 39 | })
|
| 40 | }
|
| 41 | }
|
| 42 |
|
| 43 | impl kernel::InPlaceModule for RustConfigfs {
|
| 44 | fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
|
| 45 | pr_info!("Rust configfs sample (init)\n");
|
| 46 |
|
| 47 | |
| 48 | |
| 49 | |
| 50 | |
| 51 | let item_type = configfs_attrs! {
|
| 52 | container: configfs::Subsystem<Configuration>,
|
| 53 | data: Configuration,
|
| 54 | child: Child,
|
| 55 | attributes: [
|
| 56 | message: 0,
|
| 57 | bar: 1,
|
| 58 | ],
|
| 59 | };
|
| 60 |
|
| 61 | try_pin_init!(Self {
|
| 62 | config <- configfs::Subsystem::new(
|
| 63 | c"rust_configfs", item_type, Configuration::new()
|
| 64 | ),
|
| 65 | })
|
| 66 | }
|
| 67 | }
|
| 68 |
|
| 69 | #[vtable]
|
| 70 | impl configfs::GroupOperations for Configuration {
|
| 71 | type Child = Child;
|
| 72 |
|
| 73 | fn make_group(&self, name: &CStr) -> Result<impl PinInit<configfs::Group<Child>, Error>> {
|
| 74 | |
| 75 | |
| 76 | |
| 77 | let tpe = configfs_attrs! {
|
| 78 | container: configfs::Group<Child>,
|
| 79 | data: Child,
|
| 80 | child: GrandChild,
|
| 81 | attributes: [
|
| 82 | baz: 0,
|
| 83 | ],
|
| 84 | };
|
| 85 |
|
| 86 | Ok(configfs::Group::new(name.try_into()?, tpe, Child::new()))
|
| 87 | }
|
| 88 | }
|
| 89 |
|
| 90 | #[vtable]
|
| 91 | impl configfs::AttributeOperations<0> for Configuration {
|
| 92 | type Data = Configuration;
|
| 93 |
|
| 94 | fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
|
| 95 | pr_info!("Show message\n");
|
| 96 | let data = container.message.to_bytes();
|
| 97 | page[0..data.len()].copy_from_slice(data);
|
| 98 | Ok(data.len())
|
| 99 | }
|
| 100 | }
|
| 101 |
|
| 102 | #[vtable]
|
| 103 | impl configfs::AttributeOperations<1> for Configuration {
|
| 104 | type Data = Configuration;
|
| 105 |
|
| 106 | fn show(container: &Configuration, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
|
| 107 | pr_info!("Show bar\n");
|
| 108 | let guard = container.bar.lock();
|
| 109 | let data = guard.0.as_slice();
|
| 110 | let len = guard.1;
|
| 111 | page[0..len].copy_from_slice(&data[0..len]);
|
| 112 | Ok(len)
|
| 113 | }
|
| 114 |
|
| 115 | fn store(container: &Configuration, page: &[u8]) -> Result {
|
| 116 | pr_info!("Store bar\n");
|
| 117 | let mut guard = container.bar.lock();
|
| 118 | guard.0[0..page.len()].copy_from_slice(page);
|
| 119 | guard.1 = page.len();
|
| 120 | Ok(())
|
| 121 | }
|
| 122 | }
|
| 123 |
|
| 124 | |
| 125 | #[pin_data]
|
| 126 | struct Child {}
|
| 127 |
|
| 128 | impl Child {
|
| 129 | fn new() -> impl PinInit<Self, Error> {
|
| 130 | try_pin_init!(Self {})
|
| 131 | }
|
| 132 | }
|
| 133 |
|
| 134 | #[vtable]
|
| 135 | impl configfs::GroupOperations for Child {
|
| 136 | type Child = GrandChild;
|
| 137 |
|
| 138 | fn make_group(&self, name: &CStr) -> Result<impl PinInit<configfs::Group<GrandChild>, Error>> {
|
| 139 | |
| 140 | |
| 141 | |
| 142 | |
| 143 | let tpe = configfs_attrs! {
|
| 144 | container: configfs::Group<GrandChild>,
|
| 145 | data: GrandChild,
|
| 146 | attributes: [
|
| 147 | gc: 0,
|
| 148 | ],
|
| 149 | };
|
| 150 |
|
| 151 | Ok(configfs::Group::new(
|
| 152 | name.try_into()?,
|
| 153 | tpe,
|
| 154 | GrandChild::new(),
|
| 155 | ))
|
| 156 | }
|
| 157 | }
|
| 158 |
|
| 159 | #[vtable]
|
| 160 | impl configfs::AttributeOperations<0> for Child {
|
| 161 | type Data = Child;
|
| 162 |
|
| 163 | fn show(_container: &Child, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
|
| 164 | pr_info!("Show baz\n");
|
| 165 | let data = c"Hello Baz\n".to_bytes();
|
| 166 | page[0..data.len()].copy_from_slice(data);
|
| 167 | Ok(data.len())
|
| 168 | }
|
| 169 | }
|
| 170 |
|
| 171 | |
| 172 | #[pin_data]
|
| 173 | struct GrandChild {}
|
| 174 |
|
| 175 | impl GrandChild {
|
| 176 | fn new() -> impl PinInit<Self, Error> {
|
| 177 | try_pin_init!(Self {})
|
| 178 | }
|
| 179 | }
|
| 180 |
|
| 181 | #[vtable]
|
| 182 | impl configfs::AttributeOperations<0> for GrandChild {
|
| 183 | type Data = GrandChild;
|
| 184 |
|
| 185 | fn show(_container: &GrandChild, page: &mut [u8; PAGE_SIZE]) -> Result<usize> {
|
| 186 | pr_info!("Show grand child\n");
|
| 187 | let data = c"Hello GC\n".to_bytes();
|
| 188 | page[0..data.len()].copy_from_slice(data);
|
| 189 | Ok(data.len())
|
| 190 | }
|
| 191 | }
|