| @@ -74,22 +74,19 @@ impl<'a> IoRequest<'a> { · 73 unmodified lines |
| 74 | /// // | 74 | /// // |
| 75 | /// // No runtime checks will apply when reading and writing. | 75 | /// // No runtime checks will apply when reading and writing. |
| 76 | /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; | 76 | /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; |
| 77 | /// let iomem = request.iomap_sized::<42>(); | 77 | /// let iomem = request.iomap_sized::<42>()?; |
| 78 | /// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?; | | |
| 79 | /// | | |
| 80 | /// let io = iomem.access(pdev.as_ref())?; | | |
| 81 | /// | 78 | /// |
| 82 | /// // Read and write a 32-bit value at `offset`. | 79 | /// // Read and write a 32-bit value at `offset`. |
| 83 | /// let data = io.read32(offset); | 80 | /// let data = iomem.read32(offset); |
| 84 | /// | 81 | /// |
| 85 | /// io.write32(data, offset); | 82 | /// iomem.write32(data, offset); |
| 86 | /// | 83 | /// |
| 87 | /// # Ok(SampleDriver) | 84 | /// # Ok(SampleDriver) |
| 88 | /// } | 85 | /// } |
| 89 | /// } | 86 | /// } |
| 90 | /// ``` | 87 | /// ``` |
| 91 | pub fn iomap_sized<const SIZE: usize>(self) -> impl PinInit<Devres<IoMem<SIZE>>, Error> + 'a { | 88 | pub fn iomap_sized<const SIZE: usize>(self) -> Result<IoMem<'a, SIZE>> { |
| 92 | IoMem::new(self) | 89 | IoMem::ioremap(self.device, self.resource) |
| 93 | } | 90 | } |
| 94 | | 91 | |
| 95 | /// Same as [`Self::iomap_sized`] but with exclusive access to the | 92 | /// Same as [`Self::iomap_sized`] but with exclusive access to the |
| @@ -98,10 +95,8 @@ impl<'a> IoRequest<'a> { · 2 unmodified lines |
| 98 | /// This uses the [`ioremap()`] C API. | 95 | /// This uses the [`ioremap()`] C API. |
| 99 | /// | 96 | /// |
| 100 | /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device | 97 | /// [`ioremap()`]: https://docs.kernel.org/driver-api/device-io.html#getting-access-to-the-device |
| 101 | pub fn iomap_exclusive_sized<const SIZE: usize>( | 98 | pub fn iomap_exclusive_sized<const SIZE: usize>(self) -> Result<ExclusiveIoMem<'a, SIZE>> { |
| 102 | self, | 99 | ExclusiveIoMem::ioremap(self.device, self.resource) |
| 103 | ) -> impl PinInit<Devres<ExclusiveIoMem<SIZE>>, Error> + 'a { | | |
| 104 | ExclusiveIoMem::new(self) | | |
| 105 | } | 100 | } |
| 106 | | 101 | |
| 107 | /// Maps an [`IoRequest`] where the size is not known at compile time, | 102 | /// Maps an [`IoRequest`] where the size is not known at compile time, |
| @@ -140,27 +135,24 @@ impl<'a> IoRequest<'a> { · 32 unmodified lines |
| 140 | /// // family of functions should be used, leading to runtime checks on every | 135 | /// // family of functions should be used, leading to runtime checks on every |
| 141 | /// // access. | 136 | /// // access. |
| 142 | /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; | 137 | /// let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; |
| 143 | /// let iomem = request.iomap(); | 138 | /// let iomem = request.iomap()?; |
| 144 | /// let iomem = KBox::pin_init(iomem, GFP_KERNEL)?; | | |
| 145 | /// | | |
| 146 | /// let io = iomem.access(pdev.as_ref())?; | | |
| 147 | /// | 139 | /// |
| 148 | /// let data = io.try_read32(offset)?; | 140 | /// let data = iomem.try_read32(offset)?; |
| 149 | /// | 141 | /// |
| 150 | /// io.try_write32(data, offset)?; | 142 | /// iomem.try_write32(data, offset)?; |
| 151 | /// | 143 | /// |
| 152 | /// # Ok(SampleDriver) | 144 | /// # Ok(SampleDriver) |
| 153 | /// } | 145 | /// } |
| 154 | /// } | 146 | /// } |
| 155 | /// ``` | 147 | /// ``` |
| 156 | pub fn iomap(self) -> impl PinInit<Devres<IoMem<0>>, Error> + 'a { | 148 | pub fn iomap(self) -> Result<IoMem<'a>> { |
| 157 | Self::iomap_sized::<0>(self) | 149 | self.iomap_sized::<0>() |
| 158 | } | 150 | } |
| 159 | | 151 | |
| 160 | /// Same as [`Self::iomap`] but with exclusive access to the underlying | 152 | /// Same as [`Self::iomap`] but with exclusive access to the underlying |
| 161 | /// region. | 153 | /// region. |
| 162 | pub fn iomap_exclusive(self) -> impl PinInit<Devres<ExclusiveIoMem<0>>, Error> + 'a { | 154 | pub fn iomap_exclusive(self) -> Result<ExclusiveIoMem<'a, 0>> { |
| 163 | Self::iomap_exclusive_sized::<0>(self) | 155 | self.iomap_exclusive_sized::<0>() |
| 164 | } | 156 | } |
| 165 | } | 157 | } |
| 166 | | 158 | |
| @@ -169,9 +161,9 @@ impl<'a> IoRequest<'a> { · 2 unmodified lines |
| 169 | /// # Invariants | 161 | /// # Invariants |
| 170 | /// | 162 | /// |
| 171 | /// - [`ExclusiveIoMem`] has exclusive access to the underlying [`IoMem`]. | 163 | /// - [`ExclusiveIoMem`] has exclusive access to the underlying [`IoMem`]. |
| 172 | pub struct ExclusiveIoMem<const SIZE: usize> { | 164 | pub struct ExclusiveIoMem<'a, const SIZE: usize> { |
| 173 | /// The underlying `IoMem` instance. | 165 | /// The underlying `IoMem` instance. |
| 174 | iomem: IoMem<SIZE>, | 166 | iomem: IoMem<'a, SIZE>, |
| 175 | | 167 | |
| 176 | /// The region abstraction. This represents exclusive access to the | 168 | /// The region abstraction. This represents exclusive access to the |
| 177 | /// range represented by the underlying `iomem`. | 169 | /// range represented by the underlying `iomem`. |
| @@ -180,9 +172,9 @@ pub struct ExclusiveIoMem<const SIZE: usize> { · 2 unmodified lines |
| 180 | _region: Region, | 172 | _region: Region, |
| 181 | } | 173 | } |
| 182 | | 174 | |
| 183 | impl<const SIZE: usize> ExclusiveIoMem<SIZE> { | 175 | impl<'a, const SIZE: usize> ExclusiveIoMem<'a, SIZE> { |
| 184 | /// Creates a new `ExclusiveIoMem` instance. | 176 | /// Creates a new `ExclusiveIoMem` instance. |
| 185 | fn ioremap(resource: &Resource) -> Result<Self> { | 177 | fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> { |
| 186 | let start = resource.start(); | 178 | let start = resource.start(); |
| 187 | let size = resource.size(); | 179 | let size = resource.size(); |
| 188 | let name = resource.name().unwrap_or_default(); | 180 | let name = resource.name().unwrap_or_default(); |
| @@ -196,26 +188,29 @@ impl<const SIZE: usize> ExclusiveIoMem<SIZE> { · 7 unmodified lines |
| 196 | ) | 188 | ) |
| 197 | .ok_or(EBUSY)?; | 189 | .ok_or(EBUSY)?; |
| 198 | | 190 | |
| 199 | let iomem = IoMem::ioremap(resource)?; | 191 | let iomem = IoMem::ioremap(dev, resource)?; |
| 200 | | 192 | |
| 201 | let iomem = ExclusiveIoMem { | 193 | Ok(ExclusiveIoMem { |
| 202 | iomem, | 194 | iomem, |
| 203 | _region: region, | 195 | _region: region, |
| 204 | }; | 196 | }) |
| 205 | | | |
| 206 | Ok(iomem) | | |
| 207 | } | 197 | } |
| 208 | | 198 | |
| 209 | /// Creates a new `ExclusiveIoMem` instance from a previously acquired [`IoRequest`]. | 199 | /// Consume the `ExclusiveIoMem` and register it as a device-managed resource. |
| 210 | pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a { | 200 | /// |
| 211 | let dev = io_request.device; | 201 | /// The returned `Devres<ExclusiveIoMem<'static, SIZE>>` can outlive the original lifetime |
| 212 | let res = io_request.resource; | 202 | /// `'a`. Access to the I/O memory is revoked when the device is unbound. |
| 213 | | 203 | pub fn into_devres(self) -> Result<Devres<ExclusiveIoMem<'static, SIZE>>> { |
| 214 | Devres::new(dev, Self::ioremap(res)) | 204 | // SAFETY: Casting to `'static` is sound because `Devres` guarantees the |
| | 205 | // `ExclusiveIoMem` does not actually outlive the device -- access is revoked and the |
| | 206 | // resource is released when the device is unbound. |
| | 207 | let iomem: ExclusiveIoMem<'static, SIZE> = unsafe { core::mem::transmute(self) }; |
| | 208 | let dev = iomem.iomem.dev; |
| | 209 | Devres::new(dev, iomem) |
| 215 | } | 210 | } |
| 216 | } | 211 | } |
| 217 | | 212 | |
| 218 | impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> { | 213 | impl<const SIZE: usize> Deref for ExclusiveIoMem<'_, SIZE> { |
| 219 | type Target = Mmio<SIZE>; | 214 | type Target = Mmio<SIZE>; |
| 220 | | 215 | |
| 221 | fn deref(&self) -> &Self::Target { | 216 | fn deref(&self) -> &Self::Target { |
| @@ -232,12 +227,13 @@ impl<const SIZE: usize> Deref for ExclusiveIoMem<SIZE> { · 10 unmodified lines |
| 232 | /// | 227 | /// |
| 233 | /// [`IoMem`] always holds an [`MmioRaw`] instance that holds a valid pointer to the | 228 | /// [`IoMem`] always holds an [`MmioRaw`] instance that holds a valid pointer to the |
| 234 | /// start of the I/O memory mapped region. | 229 | /// start of the I/O memory mapped region. |
| 235 | pub struct IoMem<const SIZE: usize = 0> { | 230 | pub struct IoMem<'a, const SIZE: usize = 0> { |
| | 231 | dev: &'a Device<Bound>, |
| 236 | io: MmioRaw<SIZE>, | 232 | io: MmioRaw<SIZE>, |
| 237 | } | 233 | } |
| 238 | | 234 | |
| 239 | impl<const SIZE: usize> IoMem<SIZE> { | 235 | impl<'a, const SIZE: usize> IoMem<'a, SIZE> { |
| 240 | fn ioremap(resource: &Resource) -> Result<Self> { | 236 | fn ioremap(dev: &'a Device<Bound>, resource: &Resource) -> Result<Self> { |
| 241 | // Note: Some ioremap() implementations use types that depend on the CPU | 237 | // Note: Some ioremap() implementations use types that depend on the CPU |
| 242 | // word width rather than the bus address width. | 238 | // word width rather than the bus address width. |
| 243 | // | 239 | // |
| @@ -269,28 +265,33 @@ impl<const SIZE: usize> IoMem<SIZE> { · 25 unmodified lines |
| 269 | } | 265 | } |
| 270 | | 266 | |
| 271 | let io = MmioRaw::new(addr as usize, size)?; | 267 | let io = MmioRaw::new(addr as usize, size)?; |
| 272 | let io = IoMem { io }; | | |
| 273 | | 268 | |
| 274 | Ok(io) | 269 | Ok(IoMem { dev, io }) |
| 275 | } | 270 | } |
| 276 | | 271 | |
| 277 | /// Creates a new `IoMem` instance from a previously acquired [`IoRequest`]. | 272 | /// Consume the `IoMem` and register it as a device-managed resource. |
| 278 | pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> + 'a { | 273 | /// |
| 279 | let dev = io_request.device; | 274 | /// The returned `Devres<IoMem<'static, SIZE>>` can outlive the original |
| 280 | let res = io_request.resource; | 275 | /// lifetime `'a`. Access to the I/O memory is revoked when the device |
| 281 | | 276 | /// is unbound. |
| 282 | Devres::new(dev, Self::ioremap(res)) | 277 | pub fn into_devres(self) -> Result<Devres<IoMem<'static, SIZE>>> { |
| | 278 | // SAFETY: Casting to `'static` is sound because `Devres` guarantees the `IoMem` does not |
| | 279 | // actually outlive the device -- access is revoked and the resource is released when the |
| | 280 | // device is unbound. |
| | 281 | let iomem: IoMem<'static, SIZE> = unsafe { core::mem::transmute(self) }; |
| | 282 | let dev = iomem.dev; |
| | 283 | Devres::new(dev, iomem) |
| 283 | } | 284 | } |
| 284 | } | 285 | } |
| 285 | | 286 | |
| 286 | impl<const SIZE: usize> Drop for IoMem<SIZE> { | 287 | impl<const SIZE: usize> Drop for IoMem<'_, SIZE> { |
| 287 | fn drop(&mut self) { | 288 | fn drop(&mut self) { |
| 288 | // SAFETY: Safe as by the invariant of `Io`. | 289 | // SAFETY: Safe as by the invariant of `Io`. |
| 289 | unsafe { bindings::iounmap(self.io.addr() as *mut c_void) } | 290 | unsafe { bindings::iounmap(self.io.addr() as *mut c_void) } |
| 290 | } | 291 | } |
| 291 | } | 292 | } |
| 292 | | 293 | |
| 293 | impl<const SIZE: usize> Deref for IoMem<SIZE> { | 294 | impl<const SIZE: usize> Deref for IoMem<'_, SIZE> { |
| 294 | type Target = Mmio<SIZE>; | 295 | type Target = Mmio<SIZE>; |
| 295 | | 296 | |
| 296 | fn deref(&self) -> &Self::Target { | 297 | fn deref(&self) -> &Self::Target { |