Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: pwm: Add complete abstraction layer

Introduce a comprehensive abstraction layer for the PWM subsystem to
enable writing drivers in Rust.

Because `Device`, `Chip`, and `PwmOps` all refer to each other, they
form a single, indivisible unit with circular dependencies. They are
introduced together in this single commit to create a complete,
compilable abstraction layer.

The main components are:
- Data Wrappers: Safe, idiomatic wrappers for core C types like
`pwm_device`, and `pwm_chip`.

- PwmOps Trait: An interface that drivers can implement to provide
their hardware-specific logic, mirroring the C `pwm_ops` interface.

- FFI VTable and Adapter: A bridge to connect the high-level PwmOps trait
to the C kernel's pwm_ops vtable.

- Allocation and Lifetime Management: A high-level `Chip::new()`
API to safely allocate a chip and a `Registration` guard that integrates
with `devres` to manage the chip's registration with the PWM core.
An `AlwaysRefCounted` implementation and a custom release handler
prevent memory leaks by managing the chip's lifetime and freeing
driver data correctly.

Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Reviewed-by: Elle Rhumsaa <elle@weathered-steel.dev>
Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com>
Link: https://patch.msgid.link/20251016-rust-next-pwm-working-fan-for-sending-v16-3-a5df2405d2bd@samsung.com
Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>

authored by

Michal Wilczynski and committed by
Uwe Kleine-König
d8046cd5 7b3dce81

+662 -2
+662 -2
rust/kernel/pwm.rs
··· 8 8 9 9 use crate::{ 10 10 bindings, 11 + container_of, 12 + device::{self, Bound}, 13 + devres, 14 + error::{self, to_result}, 11 15 prelude::*, 12 - types::Opaque, 16 + types::{ARef, AlwaysRefCounted, Opaque}, 13 17 }; 14 - use core::convert::TryFrom; 18 + use core::{convert::TryFrom, marker::PhantomData, ptr::NonNull}; 15 19 16 20 /// PWM polarity. Mirrors [`enum pwm_polarity`](srctree/include/linux/pwm.h). 17 21 #[derive(Copy, Clone, Debug, PartialEq, Eq)] ··· 102 98 /// Returns `true` if the PWM signal is enabled. 103 99 pub fn enabled(&self) -> bool { 104 100 self.0.enabled 101 + } 102 + } 103 + 104 + /// Describes the outcome of a `round_waveform` operation. 105 + #[derive(Debug, Clone, Copy, PartialEq, Eq)] 106 + pub enum RoundingOutcome { 107 + /// The requested waveform was achievable exactly or by rounding values down. 108 + ExactOrRoundedDown, 109 + 110 + /// The requested waveform could only be achieved by rounding up. 111 + RoundedUp, 112 + } 113 + 114 + /// Wrapper for a PWM device [`struct pwm_device`](srctree/include/linux/pwm.h). 115 + #[repr(transparent)] 116 + pub struct Device(Opaque<bindings::pwm_device>); 117 + 118 + impl Device { 119 + /// Creates a reference to a [`Device`] from a valid C pointer. 120 + /// 121 + /// # Safety 122 + /// 123 + /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the 124 + /// returned [`Device`] reference. 125 + pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::pwm_device) -> &'a Self { 126 + // SAFETY: The safety requirements guarantee the validity of the dereference, while the 127 + // `Device` type being transparent makes the cast ok. 128 + unsafe { &*ptr.cast::<Self>() } 129 + } 130 + 131 + /// Returns a raw pointer to the underlying `pwm_device`. 132 + fn as_raw(&self) -> *mut bindings::pwm_device { 133 + self.0.get() 134 + } 135 + 136 + /// Gets the hardware PWM index for this device within its chip. 137 + pub fn hwpwm(&self) -> u32 { 138 + // SAFETY: `self.as_raw()` provides a valid pointer for `self`'s lifetime. 139 + unsafe { (*self.as_raw()).hwpwm } 140 + } 141 + 142 + /// Gets a reference to the parent `Chip` that this device belongs to. 143 + pub fn chip<T: PwmOps>(&self) -> &Chip<T> { 144 + // SAFETY: `self.as_raw()` provides a valid pointer. (*self.as_raw()).chip 145 + // is assumed to be a valid pointer to `pwm_chip` managed by the kernel. 146 + // Chip::from_raw's safety conditions must be met. 147 + unsafe { Chip::<T>::from_raw((*self.as_raw()).chip) } 148 + } 149 + 150 + /// Gets the label for this PWM device, if any. 151 + pub fn label(&self) -> Option<&CStr> { 152 + // SAFETY: self.as_raw() provides a valid pointer. 153 + let label_ptr = unsafe { (*self.as_raw()).label }; 154 + if label_ptr.is_null() { 155 + return None 156 + } 157 + 158 + // SAFETY: label_ptr is non-null and points to a C string 159 + // managed by the kernel, valid for the lifetime of the PWM device. 160 + Some(unsafe { CStr::from_char_ptr(label_ptr) }) 161 + } 162 + 163 + /// Gets a copy of the current state of this PWM device. 164 + pub fn state(&self) -> State { 165 + // SAFETY: `self.as_raw()` gives a valid pointer. `(*self.as_raw()).state` 166 + // is a valid `pwm_state` struct. `State::from_c` copies this data. 167 + State::from_c(unsafe { (*self.as_raw()).state }) 168 + } 169 + 170 + /// Sets the PWM waveform configuration and enables the PWM signal. 171 + pub fn set_waveform(&self, wf: &Waveform, exact: bool) -> Result { 172 + let c_wf = bindings::pwm_waveform::from(*wf); 173 + 174 + // SAFETY: `self.as_raw()` provides a valid `*mut pwm_device` pointer. 175 + // `&c_wf` is a valid pointer to a `pwm_waveform` struct. The C function 176 + // handles all necessary internal locking. 177 + let ret = unsafe { bindings::pwm_set_waveform_might_sleep(self.as_raw(), &c_wf, exact) }; 178 + to_result(ret) 179 + } 180 + 181 + /// Queries the hardware for the configuration it would apply for a given 182 + /// request. 183 + pub fn round_waveform(&self, wf: &mut Waveform) -> Result<RoundingOutcome> { 184 + let mut c_wf = bindings::pwm_waveform::from(*wf); 185 + 186 + // SAFETY: `self.as_raw()` provides a valid `*mut pwm_device` pointer. 187 + // `&mut c_wf` is a valid pointer to a mutable `pwm_waveform` struct that 188 + // the C function will update. 189 + let ret = unsafe { bindings::pwm_round_waveform_might_sleep(self.as_raw(), &mut c_wf) }; 190 + 191 + to_result(ret)?; 192 + 193 + *wf = Waveform::from(c_wf); 194 + 195 + if ret == 1 { 196 + Ok(RoundingOutcome::RoundedUp) 197 + } else { 198 + Ok(RoundingOutcome::ExactOrRoundedDown) 199 + } 200 + } 201 + 202 + /// Reads the current waveform configuration directly from the hardware. 203 + pub fn get_waveform(&self) -> Result<Waveform> { 204 + let mut c_wf = bindings::pwm_waveform::default(); 205 + 206 + // SAFETY: `self.as_raw()` is a valid pointer. We provide a valid pointer 207 + // to a stack-allocated `pwm_waveform` struct for the kernel to fill. 208 + let ret = unsafe { bindings::pwm_get_waveform_might_sleep(self.as_raw(), &mut c_wf) }; 209 + 210 + to_result(ret)?; 211 + 212 + Ok(Waveform::from(c_wf)) 213 + } 214 + } 215 + 216 + /// The result of a `round_waveform_tohw` operation. 217 + #[derive(Debug, Clone, Copy, PartialEq, Eq)] 218 + pub struct RoundedWaveform<WfHw> { 219 + /// A status code, 0 for success or 1 if values were rounded up. 220 + pub status: c_int, 221 + /// The driver-specific hardware representation of the waveform. 222 + pub hardware_waveform: WfHw, 223 + } 224 + 225 + /// Trait defining the operations for a PWM driver. 226 + pub trait PwmOps: 'static + Sized { 227 + /// The driver-specific hardware representation of a waveform. 228 + /// 229 + /// This type must be [`Copy`], [`Default`], and fit within `PWM_WFHWSIZE`. 230 + type WfHw: Copy + Default; 231 + 232 + /// Optional hook for when a PWM device is requested. 233 + fn request( 234 + _chip: &Chip<Self>, 235 + _pwm: &Device, 236 + _parent_dev: &device::Device<Bound>, 237 + ) -> Result { 238 + Ok(()) 239 + } 240 + 241 + /// Optional hook for capturing a PWM signal. 242 + fn capture( 243 + _chip: &Chip<Self>, 244 + _pwm: &Device, 245 + _result: &mut bindings::pwm_capture, 246 + _timeout: usize, 247 + _parent_dev: &device::Device<Bound>, 248 + ) -> Result { 249 + Err(ENOTSUPP) 250 + } 251 + 252 + /// Convert a generic waveform to the hardware-specific representation. 253 + /// This is typically a pure calculation and does not perform I/O. 254 + fn round_waveform_tohw( 255 + _chip: &Chip<Self>, 256 + _pwm: &Device, 257 + _wf: &Waveform, 258 + ) -> Result<RoundedWaveform<Self::WfHw>> { 259 + Err(ENOTSUPP) 260 + } 261 + 262 + /// Convert a hardware-specific representation back to a generic waveform. 263 + /// This is typically a pure calculation and does not perform I/O. 264 + fn round_waveform_fromhw( 265 + _chip: &Chip<Self>, 266 + _pwm: &Device, 267 + _wfhw: &Self::WfHw, 268 + _wf: &mut Waveform, 269 + ) -> Result { 270 + Err(ENOTSUPP) 271 + } 272 + 273 + /// Read the current hardware configuration into the hardware-specific representation. 274 + fn read_waveform( 275 + _chip: &Chip<Self>, 276 + _pwm: &Device, 277 + _parent_dev: &device::Device<Bound>, 278 + ) -> Result<Self::WfHw> { 279 + Err(ENOTSUPP) 280 + } 281 + 282 + /// Write a hardware-specific waveform configuration to the hardware. 283 + fn write_waveform( 284 + _chip: &Chip<Self>, 285 + _pwm: &Device, 286 + _wfhw: &Self::WfHw, 287 + _parent_dev: &device::Device<Bound>, 288 + ) -> Result { 289 + Err(ENOTSUPP) 290 + } 291 + } 292 + 293 + /// Bridges Rust `PwmOps` to the C `pwm_ops` vtable. 294 + struct Adapter<T: PwmOps> { 295 + _p: PhantomData<T>, 296 + } 297 + 298 + impl<T: PwmOps> Adapter<T> { 299 + const VTABLE: PwmOpsVTable = create_pwm_ops::<T>(); 300 + 301 + /// # Safety 302 + /// 303 + /// `wfhw_ptr` must be valid for writes of `size_of::<T::WfHw>()` bytes. 304 + unsafe fn serialize_wfhw(wfhw: &T::WfHw, wfhw_ptr: *mut c_void) -> Result { 305 + let size = core::mem::size_of::<T::WfHw>(); 306 + 307 + build_assert!(size <= bindings::PWM_WFHWSIZE as usize); 308 + 309 + // SAFETY: The caller ensures `wfhw_ptr` is valid for `size` bytes. 310 + unsafe { 311 + core::ptr::copy_nonoverlapping( 312 + core::ptr::from_ref::<T::WfHw>(wfhw).cast::<u8>(), 313 + wfhw_ptr.cast::<u8>(), 314 + size, 315 + ); 316 + } 317 + 318 + Ok(()) 319 + } 320 + 321 + /// # Safety 322 + /// 323 + /// `wfhw_ptr` must be valid for reads of `size_of::<T::WfHw>()` bytes. 324 + unsafe fn deserialize_wfhw(wfhw_ptr: *const c_void) -> Result<T::WfHw> { 325 + let size = core::mem::size_of::<T::WfHw>(); 326 + 327 + build_assert!(size <= bindings::PWM_WFHWSIZE as usize); 328 + 329 + let mut wfhw = T::WfHw::default(); 330 + // SAFETY: The caller ensures `wfhw_ptr` is valid for `size` bytes. 331 + unsafe { 332 + core::ptr::copy_nonoverlapping( 333 + wfhw_ptr.cast::<u8>(), 334 + core::ptr::from_mut::<T::WfHw>(&mut wfhw).cast::<u8>(), 335 + size, 336 + ); 337 + } 338 + 339 + Ok(wfhw) 340 + } 341 + 342 + /// # Safety 343 + /// 344 + /// `dev` must be a valid pointer to a `bindings::device` embedded within a 345 + /// `bindings::pwm_chip`. This function is called by the device core when the 346 + /// last reference to the device is dropped. 347 + unsafe extern "C" fn release_callback(dev: *mut bindings::device) { 348 + // SAFETY: The function's contract guarantees that `dev` points to a `device` 349 + // field embedded within a valid `pwm_chip`. `container_of!` can therefore 350 + // safely calculate the address of the containing struct. 351 + let c_chip_ptr = unsafe { container_of!(dev, bindings::pwm_chip, dev) }; 352 + 353 + // SAFETY: `c_chip_ptr` is a valid pointer to a `pwm_chip` as established 354 + // above. Calling this FFI function is safe. 355 + let drvdata_ptr = unsafe { bindings::pwmchip_get_drvdata(c_chip_ptr) }; 356 + 357 + // SAFETY: The driver data was initialized in `new`. We run its destructor here. 358 + unsafe { core::ptr::drop_in_place(drvdata_ptr.cast::<T>()) }; 359 + 360 + // Now, call the original release function to free the `pwm_chip` itself. 361 + // SAFETY: `dev` is the valid pointer passed into this callback, which is 362 + // the expected argument for `pwmchip_release`. 363 + unsafe { bindings::pwmchip_release(dev); } 364 + } 365 + 366 + /// # Safety 367 + /// 368 + /// Pointers from C must be valid. 369 + unsafe extern "C" fn request_callback( 370 + chip_ptr: *mut bindings::pwm_chip, 371 + pwm_ptr: *mut bindings::pwm_device, 372 + ) -> c_int { 373 + // SAFETY: PWM core guarentees `chip_ptr` and `pwm_ptr` are valid pointers. 374 + let (chip, pwm) = unsafe { (Chip::<T>::from_raw(chip_ptr), Device::from_raw(pwm_ptr)) }; 375 + 376 + // SAFETY: The PWM core guarantees the parent device exists and is bound during callbacks. 377 + let bound_parent = unsafe { chip.bound_parent_device() }; 378 + match T::request(chip, pwm, bound_parent) { 379 + Ok(()) => 0, 380 + Err(e) => e.to_errno(), 381 + } 382 + } 383 + 384 + /// # Safety 385 + /// 386 + /// Pointers from C must be valid. 387 + unsafe extern "C" fn capture_callback( 388 + chip_ptr: *mut bindings::pwm_chip, 389 + pwm_ptr: *mut bindings::pwm_device, 390 + res: *mut bindings::pwm_capture, 391 + timeout: usize, 392 + ) -> c_int { 393 + // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid 394 + // pointers. 395 + let (chip, pwm, result) = unsafe { 396 + ( 397 + Chip::<T>::from_raw(chip_ptr), 398 + Device::from_raw(pwm_ptr), 399 + &mut *res, 400 + ) 401 + }; 402 + 403 + // SAFETY: The PWM core guarantees the parent device exists and is bound during callbacks. 404 + let bound_parent = unsafe { chip.bound_parent_device() }; 405 + match T::capture(chip, pwm, result, timeout, bound_parent) { 406 + Ok(()) => 0, 407 + Err(e) => e.to_errno(), 408 + } 409 + } 410 + 411 + /// # Safety 412 + /// 413 + /// Pointers from C must be valid. 414 + unsafe extern "C" fn round_waveform_tohw_callback( 415 + chip_ptr: *mut bindings::pwm_chip, 416 + pwm_ptr: *mut bindings::pwm_device, 417 + wf_ptr: *const bindings::pwm_waveform, 418 + wfhw_ptr: *mut c_void, 419 + ) -> c_int { 420 + // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid 421 + // pointers. 422 + let (chip, pwm, wf) = unsafe { 423 + ( 424 + Chip::<T>::from_raw(chip_ptr), 425 + Device::from_raw(pwm_ptr), 426 + Waveform::from(*wf_ptr), 427 + ) 428 + }; 429 + match T::round_waveform_tohw(chip, pwm, &wf) { 430 + Ok(rounded) => { 431 + // SAFETY: `wfhw_ptr` is valid per this function's safety contract. 432 + if unsafe { Self::serialize_wfhw(&rounded.hardware_waveform, wfhw_ptr) }.is_err() { 433 + return EINVAL.to_errno(); 434 + } 435 + rounded.status 436 + } 437 + Err(e) => e.to_errno(), 438 + } 439 + } 440 + 441 + /// # Safety 442 + /// 443 + /// Pointers from C must be valid. 444 + unsafe extern "C" fn round_waveform_fromhw_callback( 445 + chip_ptr: *mut bindings::pwm_chip, 446 + pwm_ptr: *mut bindings::pwm_device, 447 + wfhw_ptr: *const c_void, 448 + wf_ptr: *mut bindings::pwm_waveform, 449 + ) -> c_int { 450 + // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid 451 + // pointers. 452 + let (chip, pwm) = unsafe { (Chip::<T>::from_raw(chip_ptr), Device::from_raw(pwm_ptr)) }; 453 + // SAFETY: `deserialize_wfhw`'s safety contract is met by this function's contract. 454 + let wfhw = match unsafe { Self::deserialize_wfhw(wfhw_ptr) } { 455 + Ok(v) => v, 456 + Err(e) => return e.to_errno(), 457 + }; 458 + 459 + let mut rust_wf = Waveform::default(); 460 + match T::round_waveform_fromhw(chip, pwm, &wfhw, &mut rust_wf) { 461 + Ok(()) => { 462 + // SAFETY: `wf_ptr` is guaranteed valid by the C caller. 463 + unsafe { 464 + *wf_ptr = rust_wf.into(); 465 + }; 466 + 0 467 + } 468 + Err(e) => e.to_errno(), 469 + } 470 + } 471 + 472 + /// # Safety 473 + /// 474 + /// Pointers from C must be valid. 475 + unsafe extern "C" fn read_waveform_callback( 476 + chip_ptr: *mut bindings::pwm_chip, 477 + pwm_ptr: *mut bindings::pwm_device, 478 + wfhw_ptr: *mut c_void, 479 + ) -> c_int { 480 + // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid 481 + // pointers. 482 + let (chip, pwm) = unsafe { (Chip::<T>::from_raw(chip_ptr), Device::from_raw(pwm_ptr)) }; 483 + 484 + // SAFETY: The PWM core guarantees the parent device exists and is bound during callbacks. 485 + let bound_parent = unsafe { chip.bound_parent_device() }; 486 + match T::read_waveform(chip, pwm, bound_parent) { 487 + // SAFETY: `wfhw_ptr` is valid per this function's safety contract. 488 + Ok(wfhw) => match unsafe { Self::serialize_wfhw(&wfhw, wfhw_ptr) } { 489 + Ok(()) => 0, 490 + Err(e) => e.to_errno(), 491 + }, 492 + Err(e) => e.to_errno(), 493 + } 494 + } 495 + 496 + /// # Safety 497 + /// 498 + /// Pointers from C must be valid. 499 + unsafe extern "C" fn write_waveform_callback( 500 + chip_ptr: *mut bindings::pwm_chip, 501 + pwm_ptr: *mut bindings::pwm_device, 502 + wfhw_ptr: *const c_void, 503 + ) -> c_int { 504 + // SAFETY: Relies on the function's contract that `chip_ptr` and `pwm_ptr` are valid 505 + // pointers. 506 + let (chip, pwm) = unsafe { (Chip::<T>::from_raw(chip_ptr), Device::from_raw(pwm_ptr)) }; 507 + 508 + // SAFETY: The PWM core guarantees the parent device exists and is bound during callbacks. 509 + let bound_parent = unsafe { chip.bound_parent_device() }; 510 + 511 + // SAFETY: `wfhw_ptr` is valid per this function's safety contract. 512 + let wfhw = match unsafe { Self::deserialize_wfhw(wfhw_ptr) } { 513 + Ok(v) => v, 514 + Err(e) => return e.to_errno(), 515 + }; 516 + match T::write_waveform(chip, pwm, &wfhw, bound_parent) { 517 + Ok(()) => 0, 518 + Err(e) => e.to_errno(), 519 + } 520 + } 521 + } 522 + 523 + /// VTable structure wrapper for PWM operations. 524 + /// Mirrors [`struct pwm_ops`](srctree/include/linux/pwm.h). 525 + #[repr(transparent)] 526 + pub struct PwmOpsVTable(bindings::pwm_ops); 527 + 528 + // SAFETY: PwmOpsVTable is Send. The vtable contains only function pointers 529 + // and a size, which are simple data types that can be safely moved across 530 + // threads. The thread-safety of calling these functions is handled by the 531 + // kernel's locking mechanisms. 532 + unsafe impl Send for PwmOpsVTable {} 533 + 534 + // SAFETY: PwmOpsVTable is Sync. The vtable is immutable after it is created, 535 + // so it can be safely referenced and accessed concurrently by multiple threads 536 + // e.g. to read the function pointers. 537 + unsafe impl Sync for PwmOpsVTable {} 538 + 539 + impl PwmOpsVTable { 540 + /// Returns a raw pointer to the underlying `pwm_ops` struct. 541 + pub(crate) fn as_raw(&self) -> *const bindings::pwm_ops { 542 + &self.0 543 + } 544 + } 545 + 546 + /// Creates a PWM operations vtable for a type `T` that implements `PwmOps`. 547 + /// 548 + /// This is used to bridge Rust trait implementations to the C `struct pwm_ops` 549 + /// expected by the kernel. 550 + pub const fn create_pwm_ops<T: PwmOps>() -> PwmOpsVTable { 551 + // SAFETY: `core::mem::zeroed()` is unsafe. For `pwm_ops`, all fields are 552 + // `Option<extern "C" fn(...)>` or data, so a zeroed pattern (None/0) is valid initially. 553 + let mut ops: bindings::pwm_ops = unsafe { core::mem::zeroed() }; 554 + 555 + ops.request = Some(Adapter::<T>::request_callback); 556 + ops.capture = Some(Adapter::<T>::capture_callback); 557 + 558 + ops.round_waveform_tohw = Some(Adapter::<T>::round_waveform_tohw_callback); 559 + ops.round_waveform_fromhw = Some(Adapter::<T>::round_waveform_fromhw_callback); 560 + ops.read_waveform = Some(Adapter::<T>::read_waveform_callback); 561 + ops.write_waveform = Some(Adapter::<T>::write_waveform_callback); 562 + ops.sizeof_wfhw = core::mem::size_of::<T::WfHw>(); 563 + 564 + PwmOpsVTable(ops) 565 + } 566 + 567 + /// Wrapper for a PWM chip/controller ([`struct pwm_chip`](srctree/include/linux/pwm.h)). 568 + #[repr(transparent)] 569 + pub struct Chip<T: PwmOps>(Opaque<bindings::pwm_chip>, PhantomData<T>); 570 + 571 + impl<T: PwmOps> Chip<T> { 572 + /// Creates a reference to a [`Chip`] from a valid pointer. 573 + /// 574 + /// # Safety 575 + /// 576 + /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the 577 + /// returned [`Chip`] reference. 578 + pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::pwm_chip) -> &'a Self { 579 + // SAFETY: The safety requirements guarantee the validity of the dereference, while the 580 + // `Chip` type being transparent makes the cast ok. 581 + unsafe { &*ptr.cast::<Self>() } 582 + } 583 + 584 + /// Returns a raw pointer to the underlying `pwm_chip`. 585 + pub(crate) fn as_raw(&self) -> *mut bindings::pwm_chip { 586 + self.0.get() 587 + } 588 + 589 + /// Gets the number of PWM channels (hardware PWMs) on this chip. 590 + pub fn num_channels(&self) -> u32 { 591 + // SAFETY: `self.as_raw()` provides a valid pointer for `self`'s lifetime. 592 + unsafe { (*self.as_raw()).npwm } 593 + } 594 + 595 + /// Returns `true` if the chip supports atomic operations for configuration. 596 + pub fn is_atomic(&self) -> bool { 597 + // SAFETY: `self.as_raw()` provides a valid pointer for `self`'s lifetime. 598 + unsafe { (*self.as_raw()).atomic } 599 + } 600 + 601 + /// Returns a reference to the embedded `struct device` abstraction. 602 + pub fn device(&self) -> &device::Device { 603 + // SAFETY: 604 + // - `self.as_raw()` provides a valid pointer to `bindings::pwm_chip`. 605 + // - The `dev` field is an instance of `bindings::device` embedded 606 + // within `pwm_chip`. 607 + // - Taking a pointer to this embedded field is valid. 608 + // - `device::Device` is `#[repr(transparent)]`. 609 + // - The lifetime of the returned reference is tied to `self`. 610 + unsafe { device::Device::from_raw(&raw mut (*self.as_raw()).dev) } 611 + } 612 + 613 + /// Gets the typed driver specific data associated with this chip's embedded device. 614 + pub fn drvdata(&self) -> &T { 615 + // SAFETY: `pwmchip_get_drvdata` returns the pointer to the private data area, 616 + // which we know holds our `T`. The pointer is valid for the lifetime of `self`. 617 + unsafe { &*bindings::pwmchip_get_drvdata(self.as_raw()).cast::<T>() } 618 + } 619 + 620 + /// Returns a reference to the parent device of this PWM chip's device. 621 + /// 622 + /// # Safety 623 + /// 624 + /// The caller must guarantee that the parent device exists and is bound. 625 + /// This is guaranteed by the PWM core during `PwmOps` callbacks. 626 + unsafe fn bound_parent_device(&self) -> &device::Device<Bound> { 627 + // SAFETY: Per the function's safety contract, the parent device exists. 628 + let parent = unsafe { self.device().parent().unwrap_unchecked() }; 629 + 630 + // SAFETY: Per the function's safety contract, the parent device is bound. 631 + // This is guaranteed by the PWM core during `PwmOps` callbacks. 632 + unsafe { parent.as_bound() } 633 + } 634 + 635 + /// Allocates and wraps a PWM chip using `bindings::pwmchip_alloc`. 636 + /// 637 + /// Returns an [`ARef<Chip>`] managing the chip's lifetime via refcounting 638 + /// on its embedded `struct device`. 639 + pub fn new( 640 + parent_dev: &device::Device, 641 + num_channels: u32, 642 + data: impl pin_init::PinInit<T, Error>, 643 + ) -> Result<ARef<Self>> { 644 + let sizeof_priv = core::mem::size_of::<T>(); 645 + // SAFETY: `pwmchip_alloc` allocates memory for the C struct and our private data. 646 + let c_chip_ptr_raw = unsafe { 647 + bindings::pwmchip_alloc(parent_dev.as_raw(), num_channels, sizeof_priv) 648 + }; 649 + 650 + let c_chip_ptr: *mut bindings::pwm_chip = error::from_err_ptr(c_chip_ptr_raw)?; 651 + 652 + // SAFETY: The `drvdata` pointer is the start of the private area, which is where 653 + // we will construct our `T` object. 654 + let drvdata_ptr = unsafe { bindings::pwmchip_get_drvdata(c_chip_ptr) }; 655 + 656 + // SAFETY: We construct the `T` object in-place in the allocated private memory. 657 + unsafe { data.__pinned_init(drvdata_ptr.cast())? }; 658 + 659 + // SAFETY: `c_chip_ptr` points to a valid chip. 660 + unsafe { (*c_chip_ptr).dev.release = Some(Adapter::<T>::release_callback); } 661 + 662 + // SAFETY: `c_chip_ptr` points to a valid chip. 663 + // The `Adapter`'s `VTABLE` has a 'static lifetime, so the pointer 664 + // returned by `as_raw()` is always valid. 665 + unsafe { (*c_chip_ptr).ops = Adapter::<T>::VTABLE.as_raw(); } 666 + 667 + // Cast the `*mut bindings::pwm_chip` to `*mut Chip`. This is valid because 668 + // `Chip` is `repr(transparent)` over `Opaque<bindings::pwm_chip>`, and 669 + // `Opaque<T>` is `repr(transparent)` over `T`. 670 + let chip_ptr_as_self = c_chip_ptr.cast::<Self>(); 671 + 672 + // SAFETY: `chip_ptr_as_self` points to a valid `Chip` (layout-compatible with 673 + // `bindings::pwm_chip`) whose embedded device has refcount 1. 674 + // `ARef::from_raw` takes this pointer and manages it via `AlwaysRefCounted`. 675 + Ok(unsafe { ARef::from_raw(NonNull::new_unchecked(chip_ptr_as_self)) }) 676 + } 677 + } 678 + 679 + // SAFETY: Implements refcounting for `Chip` using the embedded `struct device`. 680 + unsafe impl<T: PwmOps> AlwaysRefCounted for Chip<T> { 681 + #[inline] 682 + fn inc_ref(&self) { 683 + // SAFETY: `self.0.get()` points to a valid `pwm_chip` because `self` exists. 684 + // The embedded `dev` is valid. `get_device` increments its refcount. 685 + unsafe { bindings::get_device(&raw mut (*self.0.get()).dev); } 686 + } 687 + 688 + #[inline] 689 + unsafe fn dec_ref(obj: NonNull<Chip<T>>) { 690 + let c_chip_ptr = obj.cast::<bindings::pwm_chip>().as_ptr(); 691 + 692 + // SAFETY: `obj` is a valid pointer to a `Chip` (and thus `bindings::pwm_chip`) 693 + // with a non-zero refcount. `put_device` handles decrement and final release. 694 + unsafe { bindings::put_device(&raw mut (*c_chip_ptr).dev); } 695 + } 696 + } 697 + 698 + // SAFETY: `Chip` is a wrapper around `*mut bindings::pwm_chip`. The underlying C 699 + // structure's state is managed and synchronized by the kernel's device model 700 + // and PWM core locking mechanisms. Therefore, it is safe to move the `Chip` 701 + // wrapper (and the pointer it contains) across threads. 702 + unsafe impl<T: PwmOps + Send> Send for Chip<T> {} 703 + 704 + // SAFETY: It is safe for multiple threads to have shared access (`&Chip`) because 705 + // the `Chip` data is immutable from the Rust side without holding the appropriate 706 + // kernel locks, which the C core is responsible for. Any interior mutability is 707 + // handled and synchronized by the C kernel code. 708 + unsafe impl<T: PwmOps + Sync> Sync for Chip<T> {} 709 + 710 + /// A resource guard that ensures `pwmchip_remove` is called on drop. 711 + /// 712 + /// This struct is intended to be managed by the `devres` framework by transferring its ownership 713 + /// via [`Devres::register`]. This ties the lifetime of the PWM chip registration 714 + /// to the lifetime of the underlying device. 715 + pub struct Registration<T: PwmOps> { 716 + chip: ARef<Chip<T>>, 717 + } 718 + 719 + impl<T: 'static + PwmOps + Send + Sync> Registration<T> { 720 + /// Registers a PWM chip with the PWM subsystem. 721 + /// 722 + /// Transfers its ownership to the `devres` framework, which ties its lifetime 723 + /// to the parent device. 724 + /// On unbind of the parent device, the `devres` entry will be dropped, automatically 725 + /// calling `pwmchip_remove`. This function should be called from the driver's `probe`. 726 + pub fn register( 727 + dev: &device::Device<Bound>, 728 + chip: ARef<Chip<T>>, 729 + ) -> Result { 730 + let chip_parent = chip.device().parent().ok_or(EINVAL)?; 731 + if dev.as_raw() != chip_parent.as_raw() { 732 + return Err(EINVAL); 733 + } 734 + 735 + let c_chip_ptr = chip.as_raw(); 736 + 737 + // SAFETY: `c_chip_ptr` points to a valid chip with its ops initialized. 738 + // `__pwmchip_add` is the C function to register the chip with the PWM core. 739 + unsafe { 740 + to_result(bindings::__pwmchip_add(c_chip_ptr, core::ptr::null_mut()))?; 741 + } 742 + 743 + let registration = Registration { chip }; 744 + 745 + devres::register(dev, registration, GFP_KERNEL) 746 + } 747 + } 748 + 749 + impl<T: PwmOps> Drop for Registration<T> { 750 + fn drop(&mut self) { 751 + let chip_raw = self.chip.as_raw(); 752 + 753 + // SAFETY: `chip_raw` points to a chip that was successfully registered. 754 + // `bindings::pwmchip_remove` is the correct C function to unregister it. 755 + // This `drop` implementation is called automatically by `devres` on driver unbind. 756 + unsafe { bindings::pwmchip_remove(chip_raw); } 105 757 } 106 758 }