From: Mike Lothian <mike@fireburn.co.uk>
To: rust-for-linux@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Danilo Krummrich" <dakr@kernel.org>,
"Lyude Paul" <lyude@redhat.com>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
linux-kernel@vger.kernel.org,
"Mike Lothian" <mike@fireburn.co.uk>
Subject: [RFC PATCH v2 11/18] rust: platform: add runtime platform device creation
Date: Fri, 3 Jul 2026 04:00:58 +0100 [thread overview]
Message-ID: <20260703030123.2814-12-mike@fireburn.co.uk> (raw)
In-Reply-To: <20260703030123.2814-1-mike@fireburn.co.uk>
The platform abstraction can register a driver (platform::Driver) but not create
a device for it to bind to. Virtual drivers that spawn their own devices -- for
instance DisplayLink's evdi, which creates one platform device per virtual
display card from a sysfs attribute or at module load -- need the provider side.
Add platform::RegisteredDevice, a thin owner around
platform_device_register_full() whose Drop calls platform_device_unregister()
(which unbinds any bound driver first), plus DEVID_AUTO/DEVID_NONE constants and
a name/id/parent/dma_mask constructor. The non-generic methods are #[inline] so
out-of-tree modules can use them without an exported symbol.
Signed-off-by: Mike Lothian <mike@fireburn.co.uk>
Assisted-by: Claude:claude-opus-4-8 [Claude-Code]
---
rust/kernel/platform.rs | 77 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 9b362e0495d3..4c2ded2e264f 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -571,3 +571,80 @@ unsafe impl Sync for Device {}
// SAFETY: Same as `Device<Normal>` -- the underlying `struct platform_device` is the same;
// `Bound` is a zero-sized type-state marker that does not affect thread safety.
unsafe impl Sync for Device<device::Bound> {}
+
+/// Auto-assign a platform device instance id (`PLATFORM_DEVID_AUTO`).
+pub const DEVID_AUTO: i32 = bindings::PLATFORM_DEVID_AUTO;
+/// Create a platform device with no instance id (`PLATFORM_DEVID_NONE`).
+pub const DEVID_NONE: i32 = bindings::PLATFORM_DEVID_NONE;
+
+/// An owned platform device created and registered at runtime.
+///
+/// This is the *provider* side of the platform bus: whereas [`Driver`] binds to devices the bus
+/// hands it, [`RegisteredDevice`] *creates* a `struct platform_device` and adds it to the bus,
+/// which then binds any matching [`Driver`] (calling its `probe`). Virtual drivers such as
+/// DisplayLink's `evdi` use this to spawn their DRM card devices on demand (from a sysfs `add`
+/// attribute or at module init).
+///
+/// [`RegisteredDevice::new`] wraps `platform_device_register_full()`; dropping the handle calls
+/// `platform_device_unregister()`, which unbinds the bound driver and releases the device.
+pub struct RegisteredDevice {
+ pdev: NonNull<bindings::platform_device>,
+}
+
+// SAFETY: `platform_device_register_full()`/`platform_device_unregister()` are internally
+// synchronized by the driver core and safe to call from any thread; the handle only unregisters.
+unsafe impl Send for RegisteredDevice {}
+// SAFETY: See `Send`; `&RegisteredDevice` exposes only the thread-safe `Device<Normal>`.
+unsafe impl Sync for RegisteredDevice {}
+
+impl RegisteredDevice {
+ /// Create and register a new platform device.
+ ///
+ /// `name` is the platform device name, which the platform bus also uses to match a [`Driver`].
+ /// `id` is the instance id: [`DEVID_AUTO`] to auto-assign a unique one, [`DEVID_NONE`] for an
+ /// unnumbered device, or a fixed non-negative value. If `parent` is given, the new device is
+ /// created as its child. `dma_mask` requests a coherent DMA mask of that many bits (pass `0`
+ /// to leave the platform default).
+ #[inline]
+ pub fn new(
+ name: &CStr,
+ id: i32,
+ parent: Option<&device::Device>,
+ dma_mask: u64,
+ ) -> Result<Self> {
+ let info = bindings::platform_device_info {
+ parent: parent.map_or(core::ptr::null_mut(), |p| p.as_raw()),
+ name: name.as_char_ptr(),
+ id,
+ dma_mask,
+ ..Default::default()
+ };
+
+ // SAFETY: `info` is fully initialized (all remaining fields zeroed) and only borrowed for
+ // the duration of the call, which copies out the fields it needs.
+ let pdev = unsafe { bindings::platform_device_register_full(&info) };
+ let pdev = crate::error::from_err_ptr(pdev)?;
+
+ Ok(Self {
+ // A successful `platform_device_register_full()` returns a valid, non-null pointer.
+ pdev: NonNull::new(pdev).ok_or(ENOMEM)?,
+ })
+ }
+
+ /// Return a reference to the created platform [`Device`].
+ #[inline]
+ pub fn device(&self) -> &Device {
+ // SAFETY: `self.pdev` points to a valid, registered `struct platform_device` owned by
+ // `self`; `Device` is a transparent wrapper over `struct platform_device`.
+ unsafe { &*self.pdev.as_ptr().cast::<Device>() }
+ }
+}
+
+impl Drop for RegisteredDevice {
+ #[inline]
+ fn drop(&mut self) {
+ // SAFETY: `self.pdev` was returned by `platform_device_register_full()` and has not been
+ // unregistered yet; this consumes that registration exactly once.
+ unsafe { bindings::platform_device_unregister(self.pdev.as_ptr()) };
+ }
+}
--
2.55.0
next prev parent reply other threads:[~2026-07-03 3:02 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-17 15:02 [RFC PATCH 0/5] rust: drm: minimal KMS bindings, EDID read, rotation, HDCP defs Mike Lothian
2026-06-17 15:02 ` [RFC PATCH 1/4] rust: drm: add minimal KMS bindings for simple-display-pipe drivers Mike Lothian
2026-06-17 15:02 ` [RFC PATCH 2/4] rust: drm: expose drm_edid.h for reading connector EDID Mike Lothian
2026-06-17 15:02 ` [RFC PATCH 3/4] rust: drm: expose drm::Device::as_raw() Mike Lothian
2026-06-17 15:02 ` [RFC PATCH 4/4] rust: drm: expose drm_blend.h and the atomic new-CRTC-state accessor Mike Lothian
2026-06-17 15:11 ` [RFC PATCH 0/5] rust: drm: minimal KMS bindings, EDID read, rotation, HDCP defs Miguel Ojeda
2026-06-17 15:29 ` Mike Lothian
2026-07-03 3:00 ` [RFC PATCH v2 00/18] rust: drm: safe KMS mode-object layer + evdi bindings Mike Lothian
2026-07-03 3:00 ` [RFC PATCH v2 01/18] rust: drm: kms: forward-port the safe mode-object layer onto the typestate device Mike Lothian
2026-07-07 21:46 ` lyude
2026-07-07 22:21 ` lyude
2026-07-03 3:00 ` [RFC PATCH v2 02/18] rust: drm: kms: adapt the port to current drm-next Mike Lothian
2026-07-03 3:00 ` [RFC PATCH v2 03/18] rust: drm: kms: break the Driver* trait well-formedness cycle Mike Lothian
2026-07-03 3:00 ` [RFC PATCH v2 04/18] rust: drm: kms: build the kernel crate clean under -Znext-solver Mike Lothian
2026-07-03 3:00 ` [RFC PATCH v2 05/18] rust: drm: expose <drm/display/drm_hdcp.h> HDCP 2.2 message definitions Mike Lothian
2026-07-03 3:00 ` [RFC PATCH v2 06/18] rust: drm: kms: add a Framebuffer::vmap() guard Mike Lothian
2026-07-07 21:51 ` lyude
2026-07-03 3:00 ` [RFC PATCH v2 07/18] rust: drm: kms: add safe accessors for common state and connector modes Mike Lothian
2026-07-03 3:00 ` [RFC PATCH v2 08/18] rust: drm: tyr: add the Kms associated type Mike Lothian
2026-07-03 3:00 ` [RFC PATCH v2 09/18] rust: drm: add drm_event delivery Mike Lothian
2026-07-03 3:00 ` [RFC PATCH v2 10/18] rust: drm: allow drivers to declare ioctls from their own uAPI module Mike Lothian
2026-07-03 3:00 ` Mike Lothian [this message]
2026-07-03 3:00 ` [RFC PATCH v2 12/18] rust: drm: framebuffer: add geometry accessors, refcounting and a byte-slice vmap Mike Lothian
2026-07-03 3:01 ` [RFC PATCH v2 13/18] rust: i2c: add adapter-provider (bus controller) registration Mike Lothian
2026-07-03 3:01 ` [RFC PATCH v2 14/18] rust: add sysfs device attribute groups Mike Lothian
2026-07-03 3:01 ` [RFC PATCH v2 15/18] rust: drm: support hardware cursor planes with sleepable event delivery Mike Lothian
2026-07-03 3:01 ` [RFC PATCH v2 16/18] rust: drm: add CRTC gamma LUT and plane rotation property bindings Mike Lothian
2026-07-03 3:01 ` [RFC PATCH v2 17/18] rust: drm: kms: add connector detect() and mode_valid() hooks Mike Lothian
2026-07-03 3:01 ` [RFC PATCH v2 18/18] rust: drm: kms: add plane damage-clip accessors Mike Lothian
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260703030123.2814-12-mike@fireburn.co.uk \
--to=mike@fireburn.co.uk \
--cc=a.hindborg@kernel.org \
--cc=airlied@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=lyude@redhat.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=tmgross@umich.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox