@@ -9,6 +9,7 @@ use crate::{
99 device_id:: RawDeviceId ,
1010 driver,
1111 error:: { to_result, Result } ,
12+ io_mem:: * ,
1213 of,
1314 prelude:: * ,
1415 str:: CStr ,
@@ -186,7 +187,10 @@ pub trait Driver {
186187/// `Device` holds a valid reference of `ARef<device::Device>` whose underlying `struct device` is a
187188/// member of a `struct platform_device`.
188189#[ derive( Clone ) ]
189- pub struct Device ( ARef < device:: Device > ) ;
190+ pub struct Device {
191+ dev : ARef < device:: Device > ,
192+ used_resource : u64 ,
193+ }
190194
191195impl Device {
192196 /// Convert a raw kernel device into a `Device`
@@ -196,22 +200,73 @@ impl Device {
196200 /// `dev` must be an `Aref<device::Device>` whose underlying `bindings::device` is a member of a
197201 /// `bindings::platform_device`.
198202 unsafe fn from_dev ( dev : ARef < device:: Device > ) -> Self {
199- Self ( dev)
203+ Self ( dev, 0 )
200204 }
201205
202206 fn as_dev ( & self ) -> & device:: Device {
203- & self . 0
207+ & self . dev
204208 }
205209
206210 fn as_raw ( & self ) -> * mut bindings:: platform_device {
207211 // SAFETY: By the type invariant `self.0.as_raw` is a pointer to the `struct device`
208212 // embedded in `struct platform_device`.
209- unsafe { container_of ! ( self . 0 . as_raw( ) , bindings:: platform_device, dev) } . cast_mut ( )
213+ unsafe { container_of ! ( self . dev. as_raw( ) , bindings:: platform_device, dev) } . cast_mut ( )
214+ }
215+
216+ /// Gets a system resources of a platform device.
217+ pub fn get_resource ( & mut self , rtype : IoResource , num : usize ) -> Result < Resource > {
218+ // SAFETY: `self.ptr` is valid by the type invariant.
219+ let res = unsafe { bindings:: platform_get_resource ( self . ptr , rtype as _ , num as _ ) } ;
220+ if res. is_null ( ) {
221+ return Err ( EINVAL ) ;
222+ }
223+
224+ // Get the position of the found resource in the array.
225+ // SAFETY:
226+ // - `self.ptr` is valid by the type invariant.
227+ // - `res` is a displaced pointer to one of the array's elements,
228+ // and `resource` is its base pointer.
229+ let index = unsafe { res. offset_from ( ( * self . ptr ) . resource ) } as usize ;
230+
231+ // Make sure that the index does not exceed the 64-bit mask.
232+ assert ! ( index < 64 ) ;
233+
234+ if self . used_resource >> index & 1 == 1 {
235+ return Err ( EBUSY ) ;
236+ }
237+ self . used_resource |= 1 << index;
238+
239+ // SAFETY: The pointer `res` is returned from `bindings::platform_get_resource`
240+ // above and checked if it is not a NULL.
241+ unsafe { Resource :: new ( ( * res) . start , ( * res) . end ) } . ok_or ( EINVAL )
242+ }
243+
244+ /// Ioremaps resources of a platform device.
245+ ///
246+ /// # Safety
247+ ///
248+ /// Callers must ensure that either (a) the resulting interface cannot be used to initiate DMA
249+ /// operations, or (b) that DMA operations initiated via the returned interface use DMA handles
250+ /// allocated through the `dma` module.
251+ pub unsafe fn ioremap_resource < const SIZE : usize > (
252+ & mut self ,
253+ index : usize ,
254+ ) -> Result < IoMem < SIZE > > {
255+ let mask = self . used_resource ;
256+ let res = self . get_resource ( IoResource :: Mem , index) ?;
257+
258+ // SAFETY: Valid by the safety contract.
259+ let iomem = unsafe { IoMem :: < SIZE > :: try_new ( res) } ;
260+ // If remapping fails, the given resource won't be used, so restore the old mask.
261+ if iomem. is_err ( ) {
262+ self . used_resource = mask;
263+ }
264+ iomem
210265 }
211266}
212267
213268impl AsRef < device:: Device > for Device {
214269 fn as_ref ( & self ) -> & device:: Device {
215- & self . 0
270+ & self . dev
216271 }
217272}
0 commit comments