inky_frame/
fs.rs

1// Permission is hereby granted, free of charge, to any person obtaining a copy
2// of this software and associated documentation files (the "Software"), to deal
3// in the Software without restriction, including without limitation the rights
4// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5// copies of the Software, and to permit persons to whom the Software is
6// furnished to do so, subject to the following conditions:
7//
8// The above copyright notice and this permission notice shall be included in
9// all copies or substantial portions of the Software.
10//
11// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17// SOFTWARE.
18//
19
20#![no_implicit_prelude]
21
22extern crate core;
23extern crate rpsp;
24
25mod block;
26mod device;
27mod volume;
28
29use core::cell::UnsafeCell;
30use core::marker::Sync;
31use core::mem::forget;
32use core::ops::{Deref, DerefMut, Drop};
33use core::ptr::NonNull;
34
35use rpsp::locks::{Spinlock28, Spinlock29, Spinlock30};
36
37pub use self::block::*;
38pub use self::device::*;
39pub use self::volume::*;
40
41// Shared References are annoying, but this is the best way to handle this as
42// the Pico does not operate properly when creating large objects.
43//
44// The Cache object allows for keeping a couple Blocks and a LFN that can be
45// locked individually for usage.
46//
47// The 'lfn' is only used for Directory search functions, 'block_a' is used for
48// small File read/writes. This may be kept locked when a File is converted to
49// a Reader and will be released when the Reader is dropped. 'block_b' is only
50// used for the Directory search cache.
51static CACHE: Cache = Cache::new();
52
53pub struct BlockPtr(NonNull<Block>);
54
55struct CacheInner {
56    lfn:     LongName,
57    block_a: Block,
58    block_b: Block,
59}
60struct Cache(UnsafeCell<CacheInner>);
61struct LongNamePtr(NonNull<LongName>);
62
63impl Cache {
64    #[inline(always)]
65    const fn new() -> Cache {
66        Cache(UnsafeCell::new(CacheInner {
67            lfn:     LongName::empty(),
68            block_a: Block::new(),
69            block_b: Block::new(),
70        }))
71    }
72
73    #[inline(always)]
74    fn lfn() -> LongNamePtr {
75        let c = Spinlock30::claim();
76        forget(c);
77        LongNamePtr(unsafe { NonNull::new_unchecked(&mut (&mut *CACHE.0.get()).lfn) })
78    }
79    #[inline(always)]
80    fn block_a() -> BlockPtr {
81        let c = Spinlock29::claim();
82        forget(c);
83        BlockPtr(unsafe { NonNull::new_unchecked(&mut (&mut *CACHE.0.get()).block_a) })
84    }
85    #[inline(always)]
86    fn block_b() -> BlockPtr {
87        let c = Spinlock28::claim();
88        forget(c);
89        BlockPtr(unsafe { NonNull::new_unchecked(&mut (&mut *CACHE.0.get()).block_b) })
90    }
91
92    #[inline(always)]
93    unsafe fn block_a_nolock() -> BlockPtr {
94        BlockPtr(unsafe { NonNull::new_unchecked(&mut (&mut *CACHE.0.get()).block_a) })
95    }
96}
97
98impl Drop for BlockPtr {
99    #[inline(always)]
100    fn drop(&mut self) {
101        if unsafe { self.0.as_ref() }.as_ptr() == unsafe { (*CACHE.0.get()).block_a.as_ptr() } {
102            unsafe { Spinlock29::free() }
103        } else {
104            unsafe { Spinlock28::free() }
105        }
106    }
107}
108impl Deref for BlockPtr {
109    type Target = Block;
110
111    #[inline(always)]
112    fn deref(&self) -> &Block {
113        unsafe { self.0.as_ref() }
114    }
115}
116impl DerefMut for BlockPtr {
117    #[inline(always)]
118    fn deref_mut(&mut self) -> &mut Block {
119        unsafe { &mut *self.0.as_ptr() }
120    }
121}
122
123impl Drop for LongNamePtr {
124    #[inline(always)]
125    fn drop(&mut self) {
126        unsafe { Spinlock30::free() }
127    }
128}
129impl Deref for LongNamePtr {
130    type Target = LongName;
131
132    #[inline(always)]
133    fn deref(&self) -> &LongName {
134        unsafe { self.0.as_ref() }
135    }
136}
137impl DerefMut for LongNamePtr {
138    #[inline(always)]
139    fn deref_mut(&mut self) -> &mut LongName {
140        unsafe { &mut *self.0.as_ptr() }
141    }
142}
143
144unsafe impl Sync for Cache {}