capsules_core/virtualizers/
virtual_flash.rs
1use core::cell::Cell;
34
35use kernel::collections::list::{List, ListLink, ListNode};
36use kernel::hil;
37use kernel::utilities::cells::{OptionalCell, TakeCell};
38use kernel::ErrorCode;
39
40pub struct MuxFlash<'a, F: hil::flash::Flash + 'static> {
47 flash: &'a F,
48 users: List<'a, FlashUser<'a, F>>,
49 inflight: OptionalCell<&'a FlashUser<'a, F>>,
50}
51
52impl<F: hil::flash::Flash> hil::flash::Client<F> for MuxFlash<'_, F> {
53 fn read_complete(
54 &self,
55 pagebuffer: &'static mut F::Page,
56 result: Result<(), hil::flash::Error>,
57 ) {
58 self.inflight.take().map(move |user| {
59 user.read_complete(pagebuffer, result);
60 });
61 self.do_next_op();
62 }
63
64 fn write_complete(
65 &self,
66 pagebuffer: &'static mut F::Page,
67 result: Result<(), hil::flash::Error>,
68 ) {
69 self.inflight.take().map(move |user| {
70 user.write_complete(pagebuffer, result);
71 });
72 self.do_next_op();
73 }
74
75 fn erase_complete(&self, result: Result<(), hil::flash::Error>) {
76 self.inflight.take().map(move |user| {
77 user.erase_complete(result);
78 });
79 self.do_next_op();
80 }
81}
82
83impl<'a, F: hil::flash::Flash> MuxFlash<'a, F> {
84 pub const fn new(flash: &'a F) -> MuxFlash<'a, F> {
85 MuxFlash {
86 flash,
87 users: List::new(),
88 inflight: OptionalCell::empty(),
89 }
90 }
91
92 fn do_next_op(&self) {
95 if self.inflight.is_none() {
96 let mnode = self
97 .users
98 .iter()
99 .find(|node| node.operation.get() != Op::Idle);
100 mnode.map(|node| {
101 node.buffer.take().map_or_else(
102 || {
103 match node.operation.get() {
105 Op::Erase(page_number) => {
106 let _ = self.flash.erase_page(page_number);
107 }
108 _ => {}
109 }
110 },
111 |buf| {
112 match node.operation.get() {
113 Op::Write(page_number) => {
114 if let Err((_, buf)) = self.flash.write_page(page_number, buf) {
115 node.buffer.replace(buf);
116 }
117 }
118 Op::Read(page_number) => {
119 if let Err((_, buf)) = self.flash.read_page(page_number, buf) {
120 node.buffer.replace(buf);
121 }
122 }
123 Op::Erase(page_number) => {
124 let _ = self.flash.erase_page(page_number);
125 }
126 Op::Idle => {} }
128 },
129 );
130 node.operation.set(Op::Idle);
131 self.inflight.set(node);
132 });
133 }
134 }
135}
136
137#[derive(Copy, Clone, PartialEq)]
138enum Op {
139 Idle,
140 Write(usize),
141 Read(usize),
142 Erase(usize),
143}
144
145pub struct FlashUser<'a, F: hil::flash::Flash + 'static> {
152 mux: &'a MuxFlash<'a, F>,
153 buffer: TakeCell<'static, F::Page>,
154 operation: Cell<Op>,
155 next: ListLink<'a, FlashUser<'a, F>>,
156 client: OptionalCell<&'a dyn hil::flash::Client<FlashUser<'a, F>>>,
157}
158
159impl<'a, F: hil::flash::Flash> FlashUser<'a, F> {
160 pub fn new(mux: &'a MuxFlash<'a, F>) -> FlashUser<'a, F> {
161 FlashUser {
162 mux,
163 buffer: TakeCell::empty(),
164 operation: Cell::new(Op::Idle),
165 next: ListLink::empty(),
166 client: OptionalCell::empty(),
167 }
168 }
169}
170
171impl<'a, F: hil::flash::Flash, C: hil::flash::Client<Self>> hil::flash::HasClient<'a, C>
172 for FlashUser<'a, F>
173{
174 fn set_client(&'a self, client: &'a C) {
175 self.mux.users.push_head(self);
176 self.client.set(client);
177 }
178}
179
180impl<F: hil::flash::Flash> hil::flash::Client<F> for FlashUser<'_, F> {
181 fn read_complete(
182 &self,
183 pagebuffer: &'static mut F::Page,
184 result: Result<(), hil::flash::Error>,
185 ) {
186 self.client.map(move |client| {
187 client.read_complete(pagebuffer, result);
188 });
189 }
190
191 fn write_complete(
192 &self,
193 pagebuffer: &'static mut F::Page,
194 result: Result<(), hil::flash::Error>,
195 ) {
196 self.client.map(move |client| {
197 client.write_complete(pagebuffer, result);
198 });
199 }
200
201 fn erase_complete(&self, result: Result<(), hil::flash::Error>) {
202 self.client.map(move |client| {
203 client.erase_complete(result);
204 });
205 }
206}
207
208impl<'a, F: hil::flash::Flash> ListNode<'a, FlashUser<'a, F>> for FlashUser<'a, F> {
209 fn next(&'a self) -> &'a ListLink<'a, FlashUser<'a, F>> {
210 &self.next
211 }
212}
213
214impl<F: hil::flash::Flash> hil::flash::Flash for FlashUser<'_, F> {
215 type Page = F::Page;
216
217 fn read_page(
218 &self,
219 page_number: usize,
220 buf: &'static mut Self::Page,
221 ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
222 self.buffer.replace(buf);
223 self.operation.set(Op::Read(page_number));
224 self.mux.do_next_op();
225 Ok(())
226 }
227
228 fn write_page(
229 &self,
230 page_number: usize,
231 buf: &'static mut Self::Page,
232 ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
233 self.buffer.replace(buf);
234 self.operation.set(Op::Write(page_number));
235 self.mux.do_next_op();
236 Ok(())
237 }
238
239 fn erase_page(&self, page_number: usize) -> Result<(), ErrorCode> {
240 self.operation.set(Op::Erase(page_number));
241 self.mux.do_next_op();
242 Ok(())
243 }
244}