7
7
//! C header: [`include/linux/platform_device.h`](../../../../include/linux/platform_device.h)
8
8
9
9
use crate :: {
10
- bindings, c_types,
10
+ bindings, bit , c_types,
11
11
device:: { self , RawDevice } ,
12
12
driver,
13
- error:: { from_kernel_result, Result } ,
13
+ error:: { code:: * , from_kernel_result} ,
14
+ io_mem:: { IoMem , IoResource , Resource } ,
14
15
of,
15
16
str:: CStr ,
16
17
to_result,
17
18
types:: PointerWrapper ,
18
- ThisModule ,
19
+ Result , ThisModule ,
19
20
} ;
20
21
21
22
/// A registration of a platform driver.
@@ -161,6 +162,7 @@ pub trait Driver {
161
162
/// The field `ptr` is non-null and valid for the lifetime of the object.
162
163
pub struct Device {
163
164
ptr : * mut bindings:: platform_device ,
165
+ used_resource : u64 ,
164
166
}
165
167
166
168
impl Device {
@@ -172,14 +174,68 @@ impl Device {
172
174
/// instance.
173
175
unsafe fn from_ptr ( ptr : * mut bindings:: platform_device ) -> Self {
174
176
// INVARIANT: The safety requirements of the function ensure the lifetime invariant.
175
- Self { ptr }
177
+ Self {
178
+ ptr,
179
+ used_resource : 0 ,
180
+ }
176
181
}
177
182
178
183
/// Returns id of the platform device.
179
184
pub fn id ( & self ) -> i32 {
180
185
// SAFETY: By the type invariants, we know that `self.ptr` is non-null and valid.
181
186
unsafe { ( * self . ptr ) . id }
182
187
}
188
+
189
+ /// Gets a system resources of a platform device.
190
+ pub fn get_resource ( & mut self , rtype : IoResource , num : usize ) -> Result < Resource > {
191
+ // SAFETY: `self.ptr` is valid by the type invariant.
192
+ let res = unsafe { bindings:: platform_get_resource ( self . ptr , rtype as _ , num as _ ) } ;
193
+ if res. is_null ( ) {
194
+ return Err ( EINVAL ) ;
195
+ }
196
+
197
+ // Get the position of the found resource in the array.
198
+ // SAFETY:
199
+ // - `self.ptr` is valid by the type invariant.
200
+ // - `res` is a displaced pointer to one of the array's elements,
201
+ // and `resource` is its base pointer.
202
+ let index = unsafe { res. offset_from ( ( * self . ptr ) . resource ) } as usize ;
203
+
204
+ // Make sure that the index does not exceed the 64-bit mask.
205
+ assert ! ( index < 64 ) ;
206
+
207
+ if self . used_resource >> index & bit ( 0 ) == 1 {
208
+ return Err ( EBUSY ) ;
209
+ }
210
+ self . used_resource |= bit ( index) ;
211
+
212
+ // SAFETY: The pointer `res` is returned from `bindings::platform_get_resource`
213
+ // above and checked if it is not a NULL.
214
+ unsafe { Resource :: new ( ( * res) . start , ( * res) . end ) } . ok_or ( EINVAL )
215
+ }
216
+
217
+ /// Ioremaps resources of a platform device.
218
+ ///
219
+ /// # Safety
220
+ ///
221
+ /// Callers must ensure that either (a) the resulting interface cannot be used to initiate DMA
222
+ /// operations, or (b) that DMA operations initiated via the returned interface use DMA handles
223
+ /// allocated through the `dma` module.
224
+ pub unsafe fn ioremap_resource < const SIZE : usize > (
225
+ & mut self ,
226
+ index : usize ,
227
+ ) -> Result < IoMem < SIZE > > {
228
+ let mask = self . used_resource ;
229
+ let res = self . get_resource ( IoResource :: Mem , index) ?;
230
+
231
+ // SAFETY: Valid by the safety contract.
232
+ let iomem = unsafe { IoMem :: < SIZE > :: try_new ( res) } ;
233
+ // If remapping fails, the given resource won't be used, so restore the old mask.
234
+ if iomem. is_err ( ) {
235
+ self . used_resource = mask;
236
+ }
237
+ iomem
238
+ }
183
239
}
184
240
185
241
// SAFETY: The device returned by `raw_device` is the raw platform device.
0 commit comments