From patchwork Mon Apr 14 13:18:04 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 14050409 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 80E502BEC5E; Mon, 14 Apr 2025 13:19:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744636785; cv=none; b=s3CjwhpwvTOWz8fTJ+skGnmXuIIy+aonOIahW753nzt39SRjN74g9XHwTqrtQPs3LOsewDLYKb1KuEKU/Fb/OhAA9f2NMMw0zub1Q4IWB1/q87tZgkG0A7DVpUoAMS1l5ywzISPdOib6LClKiKwtGr0S10XfRm6gyBPIHRswY5U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744636785; c=relaxed/simple; bh=p6KJzJV+pXbLRKuQeBLyBQEvfFDlkC0B4qSzr2zkf3M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZN2u6RWzREPxgVcX/7Ph0zBayQtEOTztiIa8YcNDzRL4WCSFBzCJFwNs/UJyGJnZK6kM78bUYpYOoROQGpziUxQQdtQzNBU5xzsqSD77ohuCzXHCdQBDP0s3vpQaUiJNfPfwNqG8OZS2XZtNbtlSBP0cLEQs2VIzlD2IS3yjoZE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=J9IhUpFl; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="J9IhUpFl" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 36AE3C4CEE2; Mon, 14 Apr 2025 13:19:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1744636784; bh=p6KJzJV+pXbLRKuQeBLyBQEvfFDlkC0B4qSzr2zkf3M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=J9IhUpFlIUclESt/bmXx/c7M7g619mc6EpAhrwit6CgBG3OOIJ+w7h2qLR/AUn44M QBQy/JAH951ZsNbWpmO7Be++1zI6Z2xKEnRY0QOf9uWu/zDK37v8KwRdF4qtVGi6CQ lq/1NYkRlpWRNHWGZHw1vzBHCXl+LXxIWToqFOJWvVzb2T72fp4E2MhYwNOAX/3Eki GKyLtr3NQJ+xiJYhmMPwvbrbC9kfmK8AWAMUEiesYFjtmC7cqmiKc5cB0mawTsosx9 aI8LeezmtMVL4i8f1tHKQXEWb1/DyxoViLOPp/p/V4vNt0QC/2Th0VdDNGw+rrmcIp Vh3I5Of5Fksfg== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, david.m.ertman@intel.com, ira.weiny@intel.com, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, airlied@gmail.com, acourbot@nvidia.com, jhubbard@nvidia.com Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v4 1/5] rust: types: add `Opaque::zeroed` Date: Mon, 14 Apr 2025 15:18:04 +0200 Message-ID: <20250414131934.28418-2-dakr@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250414131934.28418-1-dakr@kernel.org> References: <20250414131934.28418-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: rust-for-linux@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Analogous to `Opaque::uninit` add `Opaque::zeroed`, which sets the corresponding memory to zero. In contrast to `Opaque::uninit`, the corresponding value, depending on its type, may be initialized. Acked-by: Greg Kroah-Hartman Signed-off-by: Danilo Krummrich Reviewed-by: Alice Ryhl Acked-by: Miguel Ojeda --- rust/kernel/types.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 9d0471afc964..eee387727d1a 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -329,6 +329,14 @@ pub const fn uninit() -> Self { } } + /// Creates a new zeroed opaque value. + pub const fn zeroed() -> Self { + Self { + value: UnsafeCell::new(MaybeUninit::zeroed()), + _pin: PhantomPinned, + } + } + /// Create an opaque pin-initializer from the given pin-initializer. pub fn pin_init(slot: impl PinInit) -> impl PinInit { Self::ffi_init(|ptr: *mut T| { From patchwork Mon Apr 14 13:18:05 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 14050410 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7FACE29C34D; Mon, 14 Apr 2025 13:19:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744636789; cv=none; b=bwz5MZ1UuZY3XqLvQPrLVhVSO1NIoSFMGeoSih0b/jQgePCrak6RK+i0I9sNa/EEQ7h6GBTlSvnE9o4kew9gHIXqCMhtcXh5KsYN+rFgDxFnmFS3s6i8WFUlsk/EVRxs5LHOXeW2OBwdOM/U6BA4/FXfE59Frv7M+IpJITxNB/Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744636789; c=relaxed/simple; bh=EPgd6oqwzWETga6AF6P7FGJ1ioPGKiJ5Ogq5uR3snkI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cAzeIAOqQI2G9dbJbYxKqkNPv+CTf1JwaMvZwzze7zNSDKGQ0oaUL3Lffuf0YC/GggTO0rRAfyosnlKXlgY3UMuDdEv/BJy5xaSbOpQ81121IQeHkkA1VFr+ZdtFuUnC1tqRcYCNzRbq86eF0bnFNbrleiIe3A3dwm+5k4Eg2eo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=O4DtXnhl; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="O4DtXnhl" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5878BC4CEE9; Mon, 14 Apr 2025 13:19:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1744636789; bh=EPgd6oqwzWETga6AF6P7FGJ1ioPGKiJ5Ogq5uR3snkI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=O4DtXnhlcIg6ldfxtODrxm0/zY79lAAP0M7yBX/KCxknuJo40SzFdh9O0mg7VE8Xd 2Glgsm+2y8McR5hgnNZQos/nEHw4g/k+M0cumvEJq6bPl1yerTj/j3UIorE44h+Cur g5MMBNejYakO7qeV8JJVtcoaYVSEv29g60y1DlSDMLMYVCiG+Enhr3eolwbA8DDP/A rJ6Qv8Ns0dE5H6UMh4qIXC7vSyfsLdvysGDRl0Qg9SJD/fpnDC89ATk/YyTp/ZErCq dJfNNOlZK7gM+mT35N7HIPAP+oBZwhdYzgWDkK4DIk5AtuDa+uqrrz/sRaAyOHjzmx F+V3hBCKyDyXA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, david.m.ertman@intel.com, ira.weiny@intel.com, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, airlied@gmail.com, acourbot@nvidia.com, jhubbard@nvidia.com Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v4 2/5] rust: device: implement Device::parent() Date: Mon, 14 Apr 2025 15:18:05 +0200 Message-ID: <20250414131934.28418-3-dakr@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250414131934.28418-1-dakr@kernel.org> References: <20250414131934.28418-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: rust-for-linux@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Device::parent() returns a reference to the device' parent device, if any. Reviewed-by: Alice Ryhl Signed-off-by: Danilo Krummrich --- rust/kernel/device.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 585a3fcfeea3..911045e32c34 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -67,6 +67,25 @@ pub(crate) fn as_raw(&self) -> *mut bindings::device { self.0.get() } + /// Returns a reference to the parent device, if any. + #[expect(unused)] + pub(crate) fn parent(&self) -> Option<&Self> { + // SAFETY: + // - By the type invariant `self.as_raw()` is always valid. + // - The parent device is only ever set at device creation. + let parent = unsafe { (*self.as_raw()).parent }; + + if parent.is_null() { + None + } else { + // SAFETY: + // - Since `parent` is not NULL, it must be a valid pointer to a `struct device`. + // - `parent` is valid for the lifetime of `self`, since a `struct device` holds a + // reference count of its parent. + Some(unsafe { Self::as_ref(parent) }) + } + } + /// Convert a raw C `struct device` pointer to a `&'a Device`. /// /// # Safety From patchwork Mon Apr 14 13:18:06 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 14050411 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5C0B72BE7A8; Mon, 14 Apr 2025 13:19:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744636793; cv=none; b=PiTr0e1LlNfaqywxReokyuu674FTWFc7rBLL2N5eMoBEq5+ySLlCP9KZzr2r9k9OkzjPaZjYRXSYG5fcs90bAEcR0COeA9iRaDeofaTog4f69T1YdmN5sjsKFfBTvvK6rtOm4lPOVXI94Ravt5A7is39i3Z2LT1X0WEsg6sfylg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744636793; c=relaxed/simple; bh=UDI/AINJ2eSGkvDP2SFZPf6QNDNrXltQ02V5ZBvYLvI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SyngCADMklVfMRn6N5X1CGPseetj8ASUAmwnOoT6dYZ4agyzSUk3pWyTXf4KXe0/fdAQEU8KlJPHSz4GfCNWiNeGl6fYP1fQIlb9RZybVfqLqbwnfm8BkSziLdMrquelzBbVFo0zf7/prUaEGKzvk2LtjNFvDGFowM17SeqzYbs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AHn1qc33; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="AHn1qc33" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7A86BC4CEE2; Mon, 14 Apr 2025 13:19:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1744636793; bh=UDI/AINJ2eSGkvDP2SFZPf6QNDNrXltQ02V5ZBvYLvI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AHn1qc33BaFCwQETZnb5xvuBUTxZnnXiEUtTFbfetO2ji2+7aKxRasi+GRboscaR8 +rWqMad5hu8L2kQjU8TB5l0W5vi4t7JJsjwBLd1FYqGKzle2dU5buX7PDF6Z8nuWqx M/vZJWE27xGc5XBF0U5hbWvFssnf5vY05SwLyMykiOvPWM0Y9TQcp/Lcr/2iglEEhb dhWdHIE99Hj1hzZzABIeXbEccjVHpNE9tVmEuYBTVNnzBXj9bxh8zoaW2wOFlG5YFD 0ziYPRVKRLqWQskcYVEEEOrXDi0EJV4CYDMgGbhoBLP9l1OU3FDmC/bnop8+i5f2Al vCbswBpvSW13A== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, david.m.ertman@intel.com, ira.weiny@intel.com, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, airlied@gmail.com, acourbot@nvidia.com, jhubbard@nvidia.com Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v4 3/5] rust: auxiliary: add auxiliary device / driver abstractions Date: Mon, 14 Apr 2025 15:18:06 +0200 Message-ID: <20250414131934.28418-4-dakr@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250414131934.28418-1-dakr@kernel.org> References: <20250414131934.28418-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: rust-for-linux@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Implement the basic auxiliary abstractions required to implement a driver matching an auxiliary device. The design and implementation is analogous to PCI and platform and is based on the generic device / driver abstractions. Acked-by: Greg Kroah-Hartman Signed-off-by: Danilo Krummrich Reviewed-by: Alice Ryhl --- MAINTAINERS | 2 + rust/bindings/bindings_helper.h | 1 + rust/helpers/auxiliary.c | 23 +++ rust/helpers/helpers.c | 1 + rust/kernel/auxiliary.rs | 274 ++++++++++++++++++++++++++++++++ rust/kernel/device.rs | 1 - rust/kernel/lib.rs | 2 + 7 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 rust/helpers/auxiliary.c create mode 100644 rust/kernel/auxiliary.rs diff --git a/MAINTAINERS b/MAINTAINERS index 96b827049501..a7bc29ca37d4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3872,6 +3872,8 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git F: Documentation/driver-api/auxiliary_bus.rst F: drivers/base/auxiliary.c F: include/linux/auxiliary_bus.h +F: rust/kernel/auxiliary.rs +F: samples/rust/rust_driver_auxiliary.rs AUXILIARY DISPLAY DRIVERS M: Andy Shevchenko diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index ab37e1d35c70..8a2add69e5d6 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -7,6 +7,7 @@ */ #include +#include #include #include #include diff --git a/rust/helpers/auxiliary.c b/rust/helpers/auxiliary.c new file mode 100644 index 000000000000..0db3860d774e --- /dev/null +++ b/rust/helpers/auxiliary.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +void rust_helper_auxiliary_set_drvdata(struct auxiliary_device *adev, void *data) +{ + auxiliary_set_drvdata(adev, data); +} + +void *rust_helper_auxiliary_get_drvdata(struct auxiliary_device *adev) +{ + return auxiliary_get_drvdata(adev); +} + +void rust_helper_auxiliary_device_uninit(struct auxiliary_device *adev) +{ + return auxiliary_device_uninit(adev); +} + +void rust_helper_auxiliary_device_delete(struct auxiliary_device *adev) +{ + return auxiliary_device_delete(adev); +} diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index e1c21eba9b15..6b279279cb12 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -7,6 +7,7 @@ * Sorted alphabetically. */ +#include "auxiliary.c" #include "blk.c" #include "bug.c" #include "build_assert.c" diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs new file mode 100644 index 000000000000..75423737032a --- /dev/null +++ b/rust/kernel/auxiliary.rs @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Abstractions for the auxiliary bus. +//! +//! C header: [`include/linux/auxiliary_bus.h`](srctree/include/linux/auxiliary_bus.h) + +use crate::{ + bindings, device, + device_id::RawDeviceId, + driver, + error::{to_result, Result}, + prelude::*, + str::CStr, + types::{ForeignOwnable, Opaque}, + ThisModule, +}; +use core::{ + marker::PhantomData, + ptr::{addr_of_mut, NonNull}, +}; + +/// An adapter for the registration of auxiliary drivers. +pub struct Adapter(T); + +// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if +// a preceding call to `register` has been successful. +unsafe impl driver::RegistrationOps for Adapter { + type RegType = bindings::auxiliary_driver; + + unsafe fn register( + adrv: &Opaque, + name: &'static CStr, + module: &'static ThisModule, + ) -> Result { + // SAFETY: It's safe to set the fields of `struct auxiliary_driver` on initialization. + unsafe { + (*adrv.get()).name = name.as_char_ptr(); + (*adrv.get()).probe = Some(Self::probe_callback); + (*adrv.get()).remove = Some(Self::remove_callback); + (*adrv.get()).id_table = T::ID_TABLE.as_ptr(); + } + + // SAFETY: `adrv` is guaranteed to be a valid `RegType`. + to_result(unsafe { + bindings::__auxiliary_driver_register(adrv.get(), module.0, name.as_char_ptr()) + }) + } + + unsafe fn unregister(adrv: &Opaque) { + // SAFETY: `adrv` is guaranteed to be a valid `RegType`. + unsafe { bindings::auxiliary_driver_unregister(adrv.get()) } + } +} + +impl Adapter { + extern "C" fn probe_callback( + adev: *mut bindings::auxiliary_device, + id: *const bindings::auxiliary_device_id, + ) -> core::ffi::c_int { + // SAFETY: The auxiliary bus only ever calls the probe callback with a valid pointer to a + // `struct auxiliary_device`. + // + // INVARIANT: `adev` is valid for the duration of `probe_callback()`. + let adev = unsafe { &*adev.cast::>() }; + + // SAFETY: `DeviceId` is a `#[repr(transparent)` wrapper of `struct auxiliary_device_id` and + // does not add additional invariants, so it's safe to transmute. + let id = unsafe { &*id.cast::() }; + let info = T::ID_TABLE.info(id.index()); + + match T::probe(adev, info) { + Ok(data) => { + // Let the `struct auxiliary_device` own a reference of the driver's private data. + // SAFETY: By the type invariant `adev.as_raw` returns a valid pointer to a + // `struct auxiliary_device`. + unsafe { bindings::auxiliary_set_drvdata(adev.as_raw(), data.into_foreign()) }; + } + Err(err) => return Error::to_errno(err), + } + + 0 + } + + extern "C" fn remove_callback(adev: *mut bindings::auxiliary_device) { + // SAFETY: The auxiliary bus only ever calls the remove callback with a valid pointer to a + // `struct auxiliary_device`. + let ptr = unsafe { bindings::auxiliary_get_drvdata(adev) }; + + // SAFETY: `remove_callback` is only ever called after a successful call to + // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized + // `KBox` pointer created through `KBox::into_foreign`. + let _ = unsafe { KBox::::from_foreign(ptr) }; + } +} + +/// Declares a kernel module that exposes a single auxiliary driver. +#[macro_export] +macro_rules! module_auxiliary_driver { + ($($f:tt)*) => { + $crate::module_driver!(, $crate::auxiliary::Adapter, { $($f)* }); + }; +} + +/// Abstraction for `bindings::auxiliary_device_id`. +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct DeviceId(bindings::auxiliary_device_id); + +impl DeviceId { + /// Create a new [`DeviceId`] from name. + pub const fn new(modname: &'static CStr, name: &'static CStr) -> Self { + let name = name.as_bytes_with_nul(); + let modname = modname.as_bytes_with_nul(); + + // TODO: Replace with `bindings::auxiliary_device_id::default()` once stabilized for + // `const`. + // + // SAFETY: FFI type is valid to be zero-initialized. + let mut id: bindings::auxiliary_device_id = unsafe { core::mem::zeroed() }; + + let mut i = 0; + while i < modname.len() { + id.name[i] = modname[i]; + i += 1; + } + + // Reuse the space of the NULL terminator. + id.name[i - 1] = b'.'; + + let mut j = 0; + while j < name.len() { + id.name[i] = name[j]; + i += 1; + j += 1; + } + + Self(id) + } +} + +// SAFETY: +// * `DeviceId` is a `#[repr(transparent)` wrapper of `auxiliary_device_id` and does not add +// additional invariants, so it's safe to transmute to `RawType`. +// * `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field. +unsafe impl RawDeviceId for DeviceId { + type RawType = bindings::auxiliary_device_id; + + const DRIVER_DATA_OFFSET: usize = + core::mem::offset_of!(bindings::auxiliary_device_id, driver_data); + + fn index(&self) -> usize { + self.0.driver_data + } +} + +/// IdTable type for auxiliary drivers. +pub type IdTable = &'static dyn kernel::device_id::IdTable; + +/// Create a auxiliary `IdTable` with its alias for modpost. +#[macro_export] +macro_rules! auxiliary_device_table { + ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => { + const $table_name: $crate::device_id::IdArray< + $crate::auxiliary::DeviceId, + $id_info_type, + { $table_data.len() }, + > = $crate::device_id::IdArray::new($table_data); + + $crate::module_device_table!("auxiliary", $module_table_name, $table_name); + }; +} + +/// The auxiliary driver trait. +/// +/// Drivers must implement this trait in order to get an auxiliary driver registered. +pub trait Driver { + /// The type holding information about each device id supported by the driver. + /// + /// TODO: Use associated_type_defaults once stabilized: + /// + /// type IdInfo: 'static = (); + type IdInfo: 'static; + + /// The table of device ids supported by the driver. + const ID_TABLE: IdTable; + + /// Auxiliary driver probe. + /// + /// Called when an auxiliary device is matches a corresponding driver. + fn probe(dev: &Device, id_info: &Self::IdInfo) -> Result>>; +} + +/// The auxiliary device representation. +/// +/// This structure represents the Rust abstraction for a C `struct auxiliary_device`. The +/// implementation abstracts the usage of an already existing C `struct auxiliary_device` within +/// Rust code that we get passed from the C side. +/// +/// # Invariants +/// +/// A [`Device`] instance represents a valid `struct auxiliary_device` created by the C portion of +/// the kernel. +#[repr(transparent)] +pub struct Device( + Opaque, + PhantomData, +); + +impl Device { + fn as_raw(&self) -> *mut bindings::auxiliary_device { + self.0.get() + } + + /// Returns the auxiliary device' id. + pub fn id(&self) -> u32 { + // SAFETY: By the type invariant `self.as_raw()` is a valid pointer to a + // `struct auxiliary_device`. + unsafe { (*self.as_raw()).id } + } + + /// Returns a reference to the parent [`device::Device`], if any. + pub fn parent(&self) -> Option<&device::Device> { + let ptr: *const Self = self; + // CAST: `Device` types are transparent to each other. + let ptr: *const Device = ptr.cast(); + // SAFETY: `ptr` was derived from `&self`. + let this = unsafe { &*ptr }; + + this.as_ref().parent() + } +} + +// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic +// argument. +kernel::impl_device_context_deref!(unsafe { Device }); +kernel::impl_device_context_into_aref!(Device); + +// SAFETY: Instances of `Device` are always reference-counted. +unsafe impl crate::types::AlwaysRefCounted for Device { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. + unsafe { bindings::get_device(self.as_ref().as_raw()) }; + } + + unsafe fn dec_ref(obj: NonNull) { + // CAST: `Self` a transparent wrapper of `bindings::auxiliary_device`. + let adev: *mut bindings::auxiliary_device = obj.cast().as_ptr(); + + // SAFETY: By the type invariant of `Self`, `adev` is a pointer to a valid + // `struct auxiliary_device`. + let dev = unsafe { addr_of_mut!((*adev).dev) }; + + // SAFETY: The safety requirements guarantee that the refcount is non-zero. + unsafe { bindings::put_device(dev) } + } +} + +impl AsRef> for Device { + fn as_ref(&self) -> &device::Device { + // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid + // `struct auxiliary_device`. + let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; + + // SAFETY: `dev` points to a valid `struct device`. + unsafe { device::Device::as_ref(dev) } + } +} + +// SAFETY: A `Device` is always reference-counted and can be released from any thread. +unsafe impl Send for Device {} + +// SAFETY: `Device` can be shared among threads because all methods of `Device` +// (i.e. `Device) are thread safe. +unsafe impl Sync for Device {} diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 911045e32c34..bbd308b8c694 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -68,7 +68,6 @@ pub(crate) fn as_raw(&self) -> *mut bindings::device { } /// Returns a reference to the parent device, if any. - #[expect(unused)] pub(crate) fn parent(&self) -> Option<&Self> { // SAFETY: // - By the type invariant `self.as_raw()` is always valid. diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index de07aadd1ff5..55a8dfeece0b 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -38,6 +38,8 @@ pub use ffi; pub mod alloc; +#[cfg(CONFIG_AUXILIARY_BUS)] +pub mod auxiliary; #[cfg(CONFIG_BLOCK)] pub mod block; #[doc(hidden)] From patchwork Mon Apr 14 13:18:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 14050412 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D652E2E338C; Mon, 14 Apr 2025 13:19:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744636797; cv=none; b=CcTjSxQ0EWdJZ5E8SlnBTeAK6e3plMMa40MbGTOUFz1vynH+l2wFw4COAgHdhtyhuUaPZDGK2oNWmDyHUbahV9YVsNaTB+IsnQ+SaXYeXJBz7S3BNXf/QXrV5Gs93nmba0bCGfs0OGpHSUFfbxuYeMUx0Cn0esdNYXv3WtseJ0g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744636797; c=relaxed/simple; bh=eudGftji2a38VjloW6y+9kohBtajszdwKNZYkxBDrpo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RieE09rAnq+yT6O4LjBiy+QDBq7igCPPJEVXvZ4Q94oNdbp/vqCfSMG2lzXG0uLlMYIKCCDeo9upQ/HCwFuDdSnBMrIFl/PWD69nJH0po+OwXF3veVXbkwXq0tnKo4a3V/I7i4KPRxwGNwr3TPabvRLh8qKuDpmq7rYYhy/mhwI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Tn4kh1M7; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Tn4kh1M7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9D930C4CEEE; Mon, 14 Apr 2025 13:19:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1744636797; bh=eudGftji2a38VjloW6y+9kohBtajszdwKNZYkxBDrpo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Tn4kh1M7GkFkLB82iwGyhY091SBT8wobdjZlHQF4s12ERyjHL+2p9tt/O/rRRn207 jKqIeOTdnuge4X1EwHSh+TDXhg5hQv1t5KAiIB4mRsAh6/cSZ/bU5aubNV+c61X/qC SPZilLtVJW4kDPZ4A/px1ja3GV/XESip68sk5pQk0OxHze11cEDzWzLwNGvooxCS5n SYE+T1MqRtpjVHiSYGUJPV6ojWdDBRyVO0jctJvFjxSTuU5QiqB8eqnuteIlFbetO/ sGcK5RUVD86+YayrRXQ/kxD8aYWAcft/xRbCULIc+/LZdXtp4ajKMfRKc7LyS81K5h flnWRR6p6HQOw== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, david.m.ertman@intel.com, ira.weiny@intel.com, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, airlied@gmail.com, acourbot@nvidia.com, jhubbard@nvidia.com Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v4 4/5] rust: auxiliary: add auxiliary registration Date: Mon, 14 Apr 2025 15:18:07 +0200 Message-ID: <20250414131934.28418-5-dakr@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250414131934.28418-1-dakr@kernel.org> References: <20250414131934.28418-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: rust-for-linux@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Implement the `auxiliary::Registration` type, which provides an API to create and register new auxiliary devices in the system. Acked-by: Greg Kroah-Hartman Signed-off-by: Danilo Krummrich Reviewed-by: Alice Ryhl --- rust/kernel/auxiliary.rs | 88 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 75423737032a..b40d663b42eb 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -5,7 +5,7 @@ //! C header: [`include/linux/auxiliary_bus.h`](srctree/include/linux/auxiliary_bus.h) use crate::{ - bindings, device, + bindings, container_of, device, device_id::RawDeviceId, driver, error::{to_result, Result}, @@ -230,6 +230,18 @@ pub fn parent(&self) -> Option<&device::Device> { } } +impl Device { + extern "C" fn release(dev: *mut bindings::device) { + // SAFETY: By the type invariant `self.0.as_raw` is a pointer to the `struct device` + // embedded in `struct auxiliary_device`. + let adev = unsafe { container_of!(dev, bindings::auxiliary_device, dev) }.cast_mut(); + + // SAFETY: `adev` points to the memory that has been allocated in `Registration::new`, via + // `KBox::new(Opaque::::zeroed(), GFP_KERNEL)`. + let _ = unsafe { KBox::>::from_raw(adev.cast()) }; + } +} + // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic // argument. kernel::impl_device_context_deref!(unsafe { Device }); @@ -272,3 +284,77 @@ unsafe impl Send for Device {} // SAFETY: `Device` can be shared among threads because all methods of `Device` // (i.e. `Device) are thread safe. unsafe impl Sync for Device {} + +/// The registration of an auxiliary device. +/// +/// This type represents the registration of a [`struct auxiliary_device`]. When an instance of this +/// type is dropped, its respective auxiliary device will be unregistered from the system. +/// +/// # Invariants +/// +/// `self.0` always holds a valid pointer to an initialized and registered +/// [`struct auxiliary_device`]. +pub struct Registration(NonNull); + +impl Registration { + /// Create and register a new auxiliary device. + pub fn new(parent: &device::Device, name: &CStr, id: u32, modname: &CStr) -> Result { + let boxed = KBox::new(Opaque::::zeroed(), GFP_KERNEL)?; + let adev = boxed.get(); + + // SAFETY: It's safe to set the fields of `struct auxiliary_device` on initialization. + unsafe { + (*adev).dev.parent = parent.as_raw(); + (*adev).dev.release = Some(Device::release); + (*adev).name = name.as_char_ptr(); + (*adev).id = id; + } + + // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, + // which has not been initialized yet. + unsafe { bindings::auxiliary_device_init(adev) }; + + // Now that `adev` is initialized, leak the `Box`; the corresponding memory will be freed + // by `Device::release` when the last reference to the `struct auxiliary_device` is dropped. + let _ = KBox::into_raw(boxed); + + // SAFETY: + // - `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, which has + // been initialialized, + // - `modname.as_char_ptr()` is a NULL terminated string. + let ret = unsafe { bindings::__auxiliary_device_add(adev, modname.as_char_ptr()) }; + if ret != 0 { + // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct auxiliary_device`, + // which has been initialialized. + unsafe { bindings::auxiliary_device_uninit(adev) }; + + return Err(Error::from_errno(ret)); + } + + // SAFETY: `adev` is guaranteed to be non-null, since the `KBox` was allocated successfully. + // + // INVARIANT: The device will remain registered until `auxiliary_device_delete()` is called, + // which happens in `Self::drop()`. + Ok(Self(unsafe { NonNull::new_unchecked(adev) })) + } +} + +impl Drop for Registration { + fn drop(&mut self) { + // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered + // `struct auxiliary_device`. + unsafe { bindings::auxiliary_device_delete(self.0.as_ptr()) }; + + // This drops the reference we acquired through `auxiliary_device_init()`. + // + // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a valid registered + // `struct auxiliary_device`. + unsafe { bindings::auxiliary_device_uninit(self.0.as_ptr()) }; + } +} + +// SAFETY: A `Registration` of a `struct auxiliary_device` can be released from any thread. +unsafe impl Send for Registration {} + +// SAFETY: `Registration` does not expose any methods or fields that need synchronization. +unsafe impl Sync for Registration {} From patchwork Mon Apr 14 13:18:08 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 14050413 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9F1972E338C; Mon, 14 Apr 2025 13:20:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744636801; cv=none; b=jpgJnaV3c0JNA+ahY0YEdl5z6FFJRPfthc7VsUY7ueBOeZYu+cZLueiWoHaSktBMMR7gPk2bx9hEdYgd/Gx0kAq7CzjOGRjiKst3oWtlao5b7vzRB1dMpd9KQRec10J7yJidwjsWhewsDVwml8Zlb322ntvIeH56UUlJqMAzaQk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744636801; c=relaxed/simple; bh=aLWqfMc3LxAnj7N11OD12sfVIcutCmvYMivUM9e+DKY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cvhTzAPEHse21Vb7eL+sThNSwkyFVr3CH+P1qRQrgFl5mzNRtcG6x6gfGPseGxmbXONwhgQqcBT2FtEQlXQKOT+kAnV7aQtyrnZ+K/baD/g5+d1ahIyH0P5sbNlhAoGcVXn7PPjp2ffgJJbQGm6pHWNiIlhcvAYkhTF2rIc3py8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=I9wlSznv; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="I9wlSznv" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C1CCAC4CEE2; Mon, 14 Apr 2025 13:19:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1744636801; bh=aLWqfMc3LxAnj7N11OD12sfVIcutCmvYMivUM9e+DKY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=I9wlSznvqT6nfjJ8DmvqwLKbGW1cO8YlnfjbFTvr1Q3BbMbBPVRIAWUF/AWdpVAoW ZhszPDJhXuxxVIc9CUx+f2lo6TCSBKfi7Lkymbprvq3n4pGsZuVV0JHXkWUy4aDT5N eErxiW/Vow74UENyzOUEuXI5dx/ml1R2K3DrZtofKybtukh3UKnUesqEebQzTTJ+pn 5UumgFY4HRdZgCTRojGHxoS1nKcyqTFObaNGgmrZkpmzFpY+zh943FKjWbPy8Hnc8R PtJ6VGy8wi4Y4YS14GlgL0rWstT776SP15stHlWLtT1ZSpZnqyqxBK7jI6AxD0mYGm 0V3s4qNCAtYCg== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, david.m.ertman@intel.com, ira.weiny@intel.com, ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, airlied@gmail.com, acourbot@nvidia.com, jhubbard@nvidia.com Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v4 5/5] samples: rust: add Rust auxiliary driver sample Date: Mon, 14 Apr 2025 15:18:08 +0200 Message-ID: <20250414131934.28418-6-dakr@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250414131934.28418-1-dakr@kernel.org> References: <20250414131934.28418-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: rust-for-linux@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add a sample Rust auxiliary driver based on a PCI driver for QEMU's "pci-testdev" device. The PCI driver only registers an auxiliary device, in order to make the corresponding auxiliary driver probe. Acked-by: Greg Kroah-Hartman Signed-off-by: Danilo Krummrich --- MAINTAINERS | 1 + samples/rust/Kconfig | 12 +++ samples/rust/Makefile | 1 + samples/rust/rust_driver_auxiliary.rs | 122 ++++++++++++++++++++++++++ 4 files changed, 136 insertions(+) create mode 100644 samples/rust/rust_driver_auxiliary.rs diff --git a/MAINTAINERS b/MAINTAINERS index a7bc29ca37d4..23c6ca105471 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7246,6 +7246,7 @@ F: rust/kernel/devres.rs F: rust/kernel/driver.rs F: rust/kernel/faux.rs F: rust/kernel/platform.rs +F: samples/rust/rust_driver_auxiliary.rs F: samples/rust/rust_driver_platform.rs F: samples/rust/rust_driver_faux.rs diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index cad52b7120b5..43cb72d72631 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -82,6 +82,18 @@ config SAMPLE_RUST_DRIVER_FAUX If unsure, say N. +config SAMPLE_RUST_DRIVER_AUXILIARY + tristate "Auxiliary Driver" + depends on AUXILIARY_BUS + depends on PCI + help + This option builds the Rust auxiliary driver sample. + + To compile this as a module, choose M here: + the module will be called rust_driver_auxiliary. + + If unsure, say N. + config SAMPLE_RUST_HOSTPROGS bool "Host programs" help diff --git a/samples/rust/Makefile b/samples/rust/Makefile index c6a2479f7d9c..6a466afd2a21 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_SAMPLE_RUST_DMA) += rust_dma.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) += rust_driver_platform.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX) += rust_driver_faux.o +obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY) += rust_driver_auxiliary.o rust_print-y := rust_print_main.o rust_print_events.o diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs new file mode 100644 index 000000000000..8373c9a2337b --- /dev/null +++ b/samples/rust/rust_driver_auxiliary.rs @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust auxiliary driver sample (based on a PCI driver for QEMU's `pci-testdev`). +//! +//! To make this driver probe, QEMU must be run with `-device pci-testdev`. + +use kernel::{ + auxiliary, bindings, c_str, device::Core, driver, error::Error, pci, prelude::*, str::CStr, + InPlaceModule, +}; + +use pin_init::PinInit; + +const MODULE_NAME: &CStr = ::NAME; +const AUXILIARY_NAME: &CStr = c_str!("auxiliary"); + +struct AuxiliaryDriver; + +kernel::auxiliary_device_table!( + AUX_TABLE, + MODULE_AUX_TABLE, + ::IdInfo, + [(auxiliary::DeviceId::new(MODULE_NAME, AUXILIARY_NAME), ())] +); + +impl auxiliary::Driver for AuxiliaryDriver { + type IdInfo = (); + + const ID_TABLE: auxiliary::IdTable = &AUX_TABLE; + + fn probe(adev: &auxiliary::Device, _info: &Self::IdInfo) -> Result>> { + dev_info!( + adev.as_ref(), + "Probing auxiliary driver for auxiliary device with id={}\n", + adev.id() + ); + + ParentDriver::connect(adev)?; + + let this = KBox::new(Self, GFP_KERNEL)?; + + Ok(this.into()) + } +} + +struct ParentDriver { + _reg: [auxiliary::Registration; 2], +} + +kernel::pci_device_table!( + PCI_TABLE, + MODULE_PCI_TABLE, + ::IdInfo, + [( + pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, 0x5), + () + )] +); + +impl pci::Driver for ParentDriver { + type IdInfo = (); + + const ID_TABLE: pci::IdTable = &PCI_TABLE; + + fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> Result>> { + let this = KBox::new( + Self { + _reg: [ + auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 0, MODULE_NAME)?, + auxiliary::Registration::new(pdev.as_ref(), AUXILIARY_NAME, 1, MODULE_NAME)?, + ], + }, + GFP_KERNEL, + )?; + + Ok(this.into()) + } +} + +impl ParentDriver { + fn connect(adev: &auxiliary::Device) -> Result<()> { + if let Some(parent) = adev.parent() { + // Validate that we're the parent of the given auxiliary device. + let pdev: &pci::Device = parent.try_into()?; + + dev_info!( + adev.as_ref(), + "Connect auxiliary {} with parent: VendorID={:#x}, DeviceID={:#x}\n", + adev.id(), + pdev.vendor_id(), + pdev.device_id() + ); + } + + Ok(()) + } +} + +#[pin_data] +struct SampleModule { + #[pin] + _pci_driver: driver::Registration>, + #[pin] + _aux_driver: driver::Registration>, +} + +impl InPlaceModule for SampleModule { + fn init(module: &'static kernel::ThisModule) -> impl PinInit { + try_pin_init!(Self { + _pci_driver <- driver::Registration::new(MODULE_NAME, module), + _aux_driver <- driver::Registration::new(MODULE_NAME, module), + }) + } +} + +module! { + type: SampleModule, + name: "rust_driver_auxiliary", + author: "Danilo Krummrich", + description: "Rust auxiliary driver", + license: "GPL v2", +}