From nobody Sat Jul 25 16:45:12 2026 Received: from mout01.posteo.de (mout01.posteo.de [185.67.36.65]) (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 DB4D23CD8B0 for ; Wed, 15 Jul 2026 21:00:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.67.36.65 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784149225; cv=none; b=Cbr/oKhoCqdlq70MJQgQg5WYBGf0RIjgZs2NGbcVeHHqp2nqQDlDFJLY4N8GaJ5GFqs1LLO7lnSZpj8dTIFwnQX09OTlkjd5gfTcxAt90VbaEmdgNKkCx7ALEGjnvWP9Y9iu0a8CvWxsOSoRNo19OwN5e76p9eOu99xlDeDkR48= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784149225; c=relaxed/simple; bh=D6RhNjNLBSYc0HBQYBKZ5j0krt32LvrSvmqs4/tg0RI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=B9pooUkKoncKE6xuwQsmcHrLiA5+hFzDX4zgtmhuSf8q28D4waB5T/N2PXig5fpTQ4jhJd9jzdL399BjuERdj3V5NktbHN+OMahmHZBz7QI2462AtS1m7i824DfoqOupV4jOYKIarvz8WJLvb7Bm9M8V5iYaeZFj+gTDDLfMnAU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=posteo.de; spf=pass smtp.mailfrom=posteo.de; dkim=pass (2048-bit key) header.d=posteo.de header.i=@posteo.de header.b=X3NfdUqA; arc=none smtp.client-ip=185.67.36.65 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=posteo.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=posteo.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=posteo.de header.i=@posteo.de header.b="X3NfdUqA" Received: from submission (posteo.de [185.67.36.169]) by mout01.posteo.de (Postfix) with ESMTPS id E937524002E for ; Wed, 15 Jul 2026 23:00:18 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.de; s=1984.8680eb; t=1784149218; bh=AlSagtTfd5zrOC53Nr8UT4OK8IVljQeJaR5AeKGNHXM=; h=From:Date:Subject:MIME-Version:Content-Type: Content-Transfer-Encoding:Message-Id:To:Cc:Autocrypt:OpenPGP:From; b=X3NfdUqAkOu1s/B1FMwNFXwOSqCy4ED7f+77ZMmJEeWjs/dj/kJqJFh8RYSPNSn3s tpCOIyq/1tQk+HM9/fq8OBysAQkLu1jm0RikRXbJUHlsr/7lfYS7mO9zTOX1l4SlOI 6Q+o4xl+P3dXpxQWVsvOqYeZL86g0PzYWbfmWKQ1SCJWyiPNMIx6PkXs29r//cN/rO HfA0L7ayvG31nFVflHHpjlzZ6l89slPxDer2HTbG78VV2jZgAuNY6KKuU87QAxheKh CcuJjBqNm+Cz+YdTIzNkKF2q76/BsjWMi8Y5F0H/lbEKLZSNOOnRwQasmoHBd4Krud GTvLIllfsmRcQ== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4h0pTp25xrz6twb; Wed, 15 Jul 2026 23:00:14 +0200 (CEST) From: Markus Probst Date: Wed, 15 Jul 2026 21:00:17 +0000 Subject: [PATCH v14 1/3] rust: add basic serial device bus abstractions Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260715-rust_serdev-v14-1-b4ed5c93606f@posteo.de> References: <20260715-rust_serdev-v14-0-b4ed5c93606f@posteo.de> In-Reply-To: <20260715-rust_serdev-v14-0-b4ed5c93606f@posteo.de> To: Rob Herring , Greg Kroah-Hartman , Jiri Slaby , Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Kari Argillander , "Rafael J. Wysocki" , Viresh Kumar , Boqun Feng , David Airlie , Simona Vetter , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Boqun Feng Cc: linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-pm@vger.kernel.org, driver-core@lists.linux.dev, dri-devel@lists.freedesktop.org, Markus Probst X-Developer-Signature: v=1; a=openpgp-sha256; l=26741; i=markus.probst@posteo.de; h=from:subject:message-id; bh=D6RhNjNLBSYc0HBQYBKZ5j0krt32LvrSvmqs4/tg0RI=; b=owEBiQJ2/ZANAwAIATR2H/jnrUPSAcsmYgBqV/TaTwFfBIWxFksbjK7FNVf4tI/AZV6Anh3u7 1hsCxka05qJAk8EAAEIADkWIQSCdBjE9KxY53IwxHM0dh/4561D0gUCalf02hsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQNHYf+OetQ9IbkxAAt4eQr691DhpktD46q6AWAWd6sjBYmaa v23UBbfmR0GX+KdSOu5gYWoVoAJbviRTMNj7hhxfkNPKGTWmXpzRxevFxVj18tupPXatD10PyMZ abUy91kmJ/+038c918KjtGhfxRZZa7OIQnAbBLR88Q4DRdd2YeG2HhKCMluEoYz49mZcH3d3RAm oi2hPKDftyFcX1xKQOehZv2Xr70OjE/6ZqhSmrDHzZJxjdIGLhLF89roPmLc3O5ufMGBO64MHnB QVg1PrJaDH1LHP30LSWzL5TMfZ9Nsm7gR6RZ6r0nH11uVTeL7DmxAReVas2Vp3BY1PI9wiHmnEy eRjnV24yd1LvUUkf4md5bWgfekO72RfRzlHuWyt/Yd7YJLe+u3zPXoCZrUMrxTI3fTrYu4VF/Bs 93k3lqcP+L/3l2eCetRHb6E055xipcHE63i8Jii8T3dPYmyVbNJaW7KIY9IzJNDBnlTJJifL4pW fJTpbUGS5LPePgVbRONOy/89esE4ZaLL5YUCHXcvOCMjblkjyV23BsgZNiz+LPzv27+68GRsCwK Wdc0dlfvD2eJdiTMbmNBKxZSwVtApia+91U0S9QVPY6GMZekZZ+OS8o4otL7XRaEN+c40lHvRHY OscvMHp5+sXJokW1mus99g8gzasjHi+HSartRoMVFXftO0OiI4yk= X-Developer-Key: i=markus.probst@posteo.de; a=openpgp; fpr=827418C4F4AC58E77230C47334761FF8E7AD43D2 Autocrypt: addr=markus.probst@posteo.de; prefer-encrypt=mutual; keydata=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 aBeNN4ijKZchBXHPgVx+YtWRHfcm4l8= OpenPGP: url=https://posteo.de/keys/markus.probst@posteo.de.asc; preference=encrypt Implement the basic serial device bus abstractions required to write a serial device bus device driver with or without the need for initial device data. This includes the following data structures: The `serdev::Driver` trait represents the interface to the driver. The `serdev::Device` abstraction represents a `struct serdev_device`. In order to provide the Serdev specific parts to a generic `driver::Registration` the `driver::RegistrationOps` trait is implemented by `serdev::Adapter`. Signed-off-by: Markus Probst Reviewed-by: Markus Probst --- MAINTAINERS | 2 + drivers/tty/serdev/Kconfig | 7 + rust/bindings/bindings_helper.h | 1 + rust/helpers/helpers.c | 1 + rust/helpers/serdev.c | 22 ++ rust/kernel/lib.rs | 2 + rust/kernel/serdev.rs | 599 ++++++++++++++++++++++++++++++++++++= ++++ 7 files changed, 634 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 806bd2d80d15..cd735d227892 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24568,6 +24568,8 @@ S: Maintained F: Documentation/devicetree/bindings/serial/serial.yaml F: drivers/tty/serdev/ F: include/linux/serdev.h +F: rust/helpers/serdev.c +F: rust/kernel/serdev.rs =20 SERIAL IR RECEIVER M: Sean Young diff --git a/drivers/tty/serdev/Kconfig b/drivers/tty/serdev/Kconfig index 46ae732bfc68..e6dfe949ad01 100644 --- a/drivers/tty/serdev/Kconfig +++ b/drivers/tty/serdev/Kconfig @@ -9,6 +9,13 @@ menuconfig SERIAL_DEV_BUS =20 Note that you typically also want to enable TTY port controller support. =20 +config RUST_SERIAL_DEV_BUS_ABSTRACTIONS + bool "Rust Serial device bus abstractions" + depends on RUST + select SERIAL_DEV_BUS + help + This enables the Rust abstraction for the serial device bus API. + if SERIAL_DEV_BUS =20 config SERIAL_DEV_CTRL_TTYPORT diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 1124785e210b..fe7c505da236 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -85,6 +85,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 998e31052e66..6921a5ecb78a 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -87,6 +87,7 @@ #include "regulator.c" #include "scatterlist.c" #include "security.c" +#include "serdev.c" #include "signal.c" #include "slab.c" #include "spinlock.c" diff --git a/rust/helpers/serdev.c b/rust/helpers/serdev.c new file mode 100644 index 000000000000..c52b78ca3fc7 --- /dev/null +++ b/rust/helpers/serdev.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +__rust_helper +void rust_helper_serdev_device_driver_unregister(struct serdev_device_driv= er *sdrv) +{ + serdev_device_driver_unregister(sdrv); +} + +__rust_helper +void rust_helper_serdev_device_put(struct serdev_device *serdev) +{ + serdev_device_put(serdev); +} + +__rust_helper +void rust_helper_serdev_device_set_client_ops(struct serdev_device *serdev, + const struct serdev_device_ops *ops) +{ + serdev_device_set_client_ops(serdev, ops); +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 9512af7156df..d5ca17336739 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -119,6 +119,8 @@ pub mod scatterlist; pub mod security; pub mod seq_file; +#[cfg(CONFIG_RUST_SERIAL_DEV_BUS_ABSTRACTIONS)] +pub mod serdev; pub mod sizes; #[cfg(CONFIG_SOC_BUS)] pub mod soc; diff --git a/rust/kernel/serdev.rs b/rust/kernel/serdev.rs new file mode 100644 index 000000000000..0ffcef1849d2 --- /dev/null +++ b/rust/kernel/serdev.rs @@ -0,0 +1,599 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Abstractions for the serial device bus. +//! +//! C header: [`include/linux/serdev.h`](srctree/include/linux/serdev.h) + +use crate::{ + acpi, + device, + driver, + error::{ + from_result, + to_result, + VTABLE_DEFAULT_ERROR, // + }, + new_mutex, + of, + prelude::*, + sync::{ + aref::AlwaysRefCounted, + Mutex, // + }, + time::{ + msecs_to_jiffies, + Jiffies, + Msecs, // + }, + types::{ + Opaque, + ScopeGuard, // + }, // +}; + +use core::{ + cell::UnsafeCell, + marker::PhantomData, + mem::{offset_of, MaybeUninit}, + num::NonZero, + ptr::NonNull, // +}; + +/// Parity bit to use with a serial device. +#[repr(u32)] +pub enum Parity { + /// No parity bit. + None =3D bindings::serdev_parity_SERDEV_PARITY_NONE, + /// Even partiy. + Even =3D bindings::serdev_parity_SERDEV_PARITY_EVEN, + /// Odd parity. + Odd =3D bindings::serdev_parity_SERDEV_PARITY_ODD, +} + +/// Timeout in Jiffies. +pub enum Timeout { + /// Wait for a specific amount of [`Jiffies`]. + Jiffies(NonZero), + /// Wait for a specific amount of [`Msecs`]. + Milliseconds(NonZero), + /// Wait as long as possible. + /// + /// This is equivalent to [`kernel::task::MAX_SCHEDULE_TIMEOUT`]. + Max, +} + +impl Timeout { + fn into_jiffies(self) -> isize { + match self { + Self::Jiffies(value) =3D> value.get().try_into().unwrap_or_def= ault(), + Self::Milliseconds(value) =3D> { + msecs_to_jiffies(value.get()).try_into().unwrap_or_default= () + } + Self::Max =3D> 0, + } + } +} + +/// An adapter for the registration of serial device bus device drivers. +pub struct Adapter(T); + +// SAFETY: +// - `bindings::serdev_device_driver` is a C type declared as `repr(C)`. +// - `PrivateData<'bound, T>` is the type of the driver's device private d= ata. +// - `struct serdev_device_driver` embeds a `struct device_driver`. +// - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. +unsafe impl driver::DriverLayout for Adapter { + type DriverType =3D bindings::serdev_device_driver; + type DriverData<'bound> =3D PrivateData<'bound, T>; + const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); +} + +// SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if +// a preceding call to `register` has been successful. +unsafe impl driver::RegistrationOps for Adapter { + unsafe fn register( + sdrv: &Opaque, + name: &'static CStr, + module: &'static ThisModule, + ) -> Result { + let of_table =3D match T::OF_ID_TABLE { + Some(table) =3D> table.as_ptr(), + None =3D> core::ptr::null(), + }; + + let acpi_table =3D match T::ACPI_ID_TABLE { + Some(table) =3D> table.as_ptr(), + None =3D> core::ptr::null(), + }; + + // SAFETY: It's safe to set the fields of `struct serdev_device_dr= iver` on initialization. + unsafe { + (*sdrv.get()).driver.name =3D name.as_char_ptr(); + (*sdrv.get()).probe =3D Some(Self::probe_callback); + (*sdrv.get()).remove =3D Some(Self::remove_callback); + (*sdrv.get()).driver.of_match_table =3D of_table; + (*sdrv.get()).driver.acpi_match_table =3D acpi_table; + } + + // SAFETY: `sdrv` is guaranteed to be a valid `DriverType`. + to_result(unsafe { bindings::__serdev_device_driver_register(sdrv.= get(), module.0) }) + } + + unsafe fn unregister(sdrv: &Opaque) { + // SAFETY: `sdrv` is guaranteed to be a valid `DriverType`. + unsafe { bindings::serdev_device_driver_unregister(sdrv.get()) }; + } +} + +#[doc(hidden)] +#[pin_data(PinnedDrop)] +pub struct PrivateData<'bound, T: Driver> { + sdev: &'bound Device, + #[pin] + driver: UnsafeCell>>, + open: UnsafeCell, + #[pin] + active: Mutex, +} + +#[pinned_drop] +impl PinnedDrop for PrivateData<'_, T> { + fn drop(self: Pin<&mut Self>) { + let mut active =3D self.active.lock(); + if *active { + // SAFETY: + // - We have exclusive access to `self.driver`. + // - `self.driver` is guaranteed to be initialized. + unsafe { (*self.driver.get()).assume_init_drop() }; + *active =3D false; + } + drop(active); + + // SAFETY: We have exclusive access to `self.open`. + if unsafe { *self.open.get() } { + // SAFETY: `self.sdev.as_raw()` is guaranteed to be a pointer = to a valid + // `struct serdev_device`. + unsafe { bindings::serdev_device_close(self.sdev.as_raw()) }; + } + } +} + +impl Adapter { + const OPS: &'static bindings::serdev_device_ops =3D &bindings::serdev_= device_ops { + receive_buf: if T::HAS_RECEIVE { + Some(Self::receive_buf_callback) + } else { + None + }, + write_wakeup: Some(bindings::serdev_device_write_wakeup), + }; + + extern "C" fn probe_callback(sdev: *mut bindings::serdev_device) -> ke= rnel::ffi::c_int { + // SAFETY: The serial device bus only ever calls the probe callbac= k with a valid pointer to + // a `struct serdev_device`. + // + // INVARIANT: `sdev` is valid for the duration of `probe_callback(= )`. + let sdev =3D unsafe { &*sdev.cast::>>() }; + let info =3D ::id_info(sdev.as_ref()); + + from_result(|| { + sdev.as_ref().set_drvdata(try_pin_init!(PrivateData:: { + sdev: &**sdev, + driver: MaybeUninit::>::zeroed().into(), + open: false.into(), + active <- new_mutex!(false), + }))?; + // SAFETY: We just set drvdata to `PrivateData<'_, T>`. + let private_data =3D unsafe { sdev.as_ref().drvdata_borrow::>() }; + let private_data =3D ScopeGuard::new_with_data(private_data, |= _| { + // SAFETY: We just set drvdata to `PrivateData<'_, T>`. + drop(unsafe { sdev.as_ref().drvdata_obtain::>() }); + }); + let mut active =3D private_data.active.lock(); + + // SAFETY: `sdev.as_raw()` is guaranteed to be a valid pointer= to `serdev_device`. + unsafe { bindings::serdev_device_set_client_ops(sdev.as_raw(),= Self::OPS) }; + + // SAFETY: The serial device bus only ever calls the probe cal= lback with a valid pointer + // to a `serdev_device`. + to_result(unsafe { bindings::serdev_device_open(sdev.as_raw())= })?; + + // SAFETY: We have exclusive access to `private_data.open`. + unsafe { *private_data.open.get() =3D true }; + + let data =3D T::probe(sdev, info); + + // SAFETY: We have exclusive access to `private_data.driver`. + let driver =3D unsafe { &mut *private_data.driver.get() }; + // SAFETY: + // - `driver.as_mut_ptr()` is a valid pointer to uninitialized= data. + // - `private_data.driver` is pinned. + let result =3D unsafe { data.__pinned_init(driver.as_mut_ptr()= ) }; + + *active =3D result.is_ok(); + + drop(active); + + result.map(|()| { + private_data.dismiss(); + 0 + }) + }) + } + + extern "C" fn remove_callback(sdev: *mut bindings::serdev_device) { + // SAFETY: The serial device bus only ever calls the remove callba= ck with a valid pointer + // to a `struct serdev_device`. + // + // INVARIANT: `sdev` is valid for the duration of `remove_callback= ()`. + let sdev =3D unsafe { &*sdev.cast::>>() }; + + // SAFETY: `remove_callback` is only ever called after a successfu= l call to + // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called + // and stored a `Pin>>`. + let private_data =3D unsafe { sdev.as_ref().drvdata_borrow::>() }; + + // SAFETY: No one has exclusive access to `private_data.driver`. + let data =3D unsafe { &*private_data.driver.get() }; + // SAFETY: + // - `private_data.driver` is pinned. + // - `remove_callback` is only ever called after a successful call= to `probe_callback`, + // hence it's guaranteed that `private_data.driver` was initiali= zed. + let data_pinned =3D unsafe { Pin::new_unchecked(data.assume_init_r= ef()) }; + + T::unbind(sdev, data_pinned); + } + + extern "C" fn receive_buf_callback( + sdev: *mut bindings::serdev_device, + buf: *const u8, + length: usize, + ) -> usize { + // SAFETY: The serial device bus only ever calls the receive buf c= allback with a valid + // pointer to a `struct serdev_device`. + // + // INVARIANT: `sdev` is valid for the duration of `receive_buf_cal= lback()`. + let sdev =3D unsafe { &*sdev.cast::>= () }; + + // SAFETY: `receive_buf_callback` is only ever called after a succ= essful call to + // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called + // and stored a `Pin>>`. + let private_data =3D unsafe { sdev.as_ref().drvdata_borrow::>() }; + let active =3D private_data.active.lock(); + + if !*active { + return length; + } + + // SAFETY: No one has exclusive access to `private_data.driver`. + let data =3D unsafe { &*private_data.driver.get() }; + // SAFETY: + // - `private_data.driver` is pinned. + // - `receive_buf_callback` is only ever called after a successful= call to `probe_callback`, + // hence it's guaranteed that `private_data.driver` was initiali= zed. + let data_pinned =3D unsafe { Pin::new_unchecked(data.assume_init_r= ef()) }; + + // SAFETY: `buf` is guaranteed to be non-null and has the size of = `length`. + let buf =3D unsafe { core::slice::from_raw_parts(buf, length) }; + + T::receive(sdev, data_pinned, buf) + } +} + +impl driver::Adapter for Adapter { + type IdInfo =3D T::IdInfo; + + fn of_id_table() -> Option> { + T::OF_ID_TABLE + } + + fn acpi_id_table() -> Option> { + T::ACPI_ID_TABLE + } +} + +/// Declares a kernel module that exposes a single serial device bus devic= e driver. +/// +/// # Examples +/// +/// ```ignore +/// kernel::module_serdev_device_driver! { +/// type: MyDriver, +/// name: "Module name", +/// authors: ["Author name"], +/// description: "Description", +/// license: "GPL v2", +/// } +/// ``` +#[macro_export] +macro_rules! module_serdev_device_driver { + ($($f:tt)*) =3D> { + $crate::module_driver!(, $crate::serdev::Adapter, { $($f)* }= ); + }; +} + +/// The serial device bus device driver trait. +/// +/// Drivers must implement this trait in order to get a serial device bus = device driver registered. +/// +/// # Examples +/// +///``` +/// # use kernel::{ +/// acpi, +/// bindings, +/// device::{ +/// Bound, +/// Core, // +/// }, +/// of, +/// serdev, // +/// }; +/// +/// struct MyDriver; +/// +/// kernel::of_device_table!( +/// OF_TABLE, +/// MODULE_OF_TABLE, +/// ::IdInfo, +/// [ +/// (of::DeviceId::new(c"test,device"), ()) +/// ] +/// ); +/// +/// kernel::acpi_device_table!( +/// ACPI_TABLE, +/// MODULE_ACPI_TABLE, +/// ::IdInfo, +/// [ +/// (acpi::DeviceId::new(c"LNUXBEEF"), ()) +/// ] +/// ); +/// +/// #[vtable] +/// impl serdev::Driver for MyDriver { +/// type IdInfo =3D (); +/// type Data<'bound> =3D Self; +/// const OF_ID_TABLE: Option> =3D Some(&OF_= TABLE); +/// const ACPI_ID_TABLE: Option> =3D Some(= &ACPI_TABLE); +/// +/// fn probe<'bound>( +/// sdev: &'bound serdev::Device>, +/// _id_info: Option<&'bound Self::IdInfo>, +/// ) -> impl PinInit, Error> + 'bound { +/// sdev.set_baudrate(115200); +/// sdev.write_all(b"Hello\n", serdev::Timeout::Max)?; +/// Ok(MyDriver) +/// } +/// } +///``` +#[vtable] +pub trait Driver { + /// The type holding driver private data about each device id supporte= d by the driver. + // TODO: Use associated_type_defaults once stabilized: + // + // ``` + // type IdInfo: 'static =3D (); + // ``` + type IdInfo: 'static; + + /// The type of the driver's bus device private data. + type Data<'bound>: Send + Sync + 'bound; + + /// The table of OF device ids supported by the driver. + const OF_ID_TABLE: Option> =3D None; + + /// The table of ACPI device ids supported by the driver. + const ACPI_ID_TABLE: Option> =3D None; + + /// Serial device bus device driver probe. + /// + /// Called when a new serial device bus device is added or discovered. + /// Implementers should attempt to initialize the device here. + fn probe<'bound>( + sdev: &'bound Device>, + id_info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit, Error> + 'bound; + + /// Serial device bus device driver unbind. + /// + /// Called when a [`Device`] is unbound from its bound [`Driver`]. Imp= lementing this callback + /// is optional. + /// + /// This callback serves as a place for drivers to perform teardown op= erations that require a + /// `&Device` or `&Device` reference. For instance. + /// + /// Otherwise, release operations for driver resources should be perfo= rmed in `Drop`. + fn unbind<'bound>(sdev: &'bound Device>, this: Pin<&S= elf::Data<'bound>>) { + let _ =3D (sdev, this); + } + + /// Serial device bus device data receive callback. + /// + /// Called when data got received from device. + /// + /// Returns the number of bytes accepted. + fn receive<'bound>( + sdev: &'bound Device, + this: Pin<&Self::Data<'bound>>, + data: &[u8], + ) -> usize { + let _ =3D (sdev, this, data); + build_error!(VTABLE_DEFAULT_ERROR) + } +} + +/// The serial device bus device representation. +/// +/// This structure represents the Rust abstraction for a C `struct serdev_= device`. The +/// implementation abstracts the usage of an already existing C `struct se= rdev_device` within Rust +/// code that we get passed from the C side. +/// +/// # Invariants +/// +/// A [`Device`] instance represents a valid `struct serdev_device` create= d by the C portion of +/// the kernel. +#[repr(transparent)] +pub struct Device( + Opaque, + PhantomData, +); + +impl Device { + fn as_raw(&self) -> *mut bindings::serdev_device { + self.0.get() + } +} + +impl Device { + /// Set the baudrate in bits per second. + /// + /// Common baudrates are 115200, 9600, 19200, 57600, 4800. + /// + /// Use [`Device::write_flush`] before calling this if you have writte= n data prior to this call. + pub fn set_baudrate(&self, speed: u32) -> Result<(), u32> { + // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a vali= d `serdev_device`. + let ret =3D unsafe { bindings::serdev_device_set_baudrate(self.as_= raw(), speed) }; + if ret =3D=3D speed { + Ok(()) + } else { + Err(ret) + } + } + + /// Set if flow control should be enabled. + /// + /// Use [`Device::write_flush`] before calling this if you have writte= n data prior to this call. + pub fn set_flow_control(&self, enable: bool) { + // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a vali= d `serdev_device`. + unsafe { bindings::serdev_device_set_flow_control(self.as_raw(), e= nable) }; + } + + /// Set parity to use. + /// + /// Use [`Device::write_flush`] before calling this if you have writte= n data prior to this call. + pub fn set_parity(&self, parity: Parity) -> Result { + // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a vali= d `serdev_device`. + to_result(unsafe { bindings::serdev_device_set_parity(self.as_raw(= ), parity as u32) }) + } + + /// Write data to the serial device until the controller has accepted = all the data or has + /// been interrupted by a timeout or signal. + /// + /// Note that any accepted data has only been buffered by the controll= er. Use + /// [`Device::wait_until_sent`] to make sure the controller write buff= er has actually been + /// emptied. + /// + /// Returns the number of bytes written (less than `data.len()` if int= errupted). + /// [`kernel::error::code::ETIMEDOUT`] or [`kernel::error::code::EREST= ARTSYS`] if interrupted + /// before any bytes were written. + pub fn write_all(&self, data: &[u8], timeout: Timeout) -> Result { + if data.len() > i32::MAX as usize { + return Err(EINVAL); + } + + // SAFETY: + // - `self.as_raw()` is guaranteed to be a pointer to a valid `ser= dev_device`. + // - `data.as_ptr()` is guaranteed to be a valid array pointer wit= h the size of + // `data.len()`. + let ret =3D unsafe { + bindings::serdev_device_write( + self.as_raw(), + data.as_ptr(), + data.len(), + timeout.into_jiffies(), + ) + }; + // CAST: negative return values are guaranteed to be between `-MAX= _ERRNO` and `-1`, + // which always fit into a `i32`. + to_result(ret as i32).map(|()| ret.unsigned_abs()) + } + + /// Write data to the serial device. + /// + /// If you want to write until the controller has accepted all the dat= a, use + /// [`Device::write_all`]. + /// + /// Note that any accepted data has only been buffered by the controll= er. Use + /// [ Device::wait_until_sent`] to make sure the controller write buff= er has actually been + /// emptied. + /// + /// Returns the number of bytes written (less than `data.len()` if not= enough room in the + /// write buffer). + pub fn write(&self, data: &[u8]) -> Result { + if data.len() > i32::MAX as usize { + return Err(EINVAL); + } + + // SAFETY: + // - `self.as_raw()` is guaranteed to be a pointer to a valid `ser= dev_device`. + // - `data.as_ptr()` is guaranteed to be a valid array pointer wit= h the size of + // `data.len()`. + let ret =3D + unsafe { bindings::serdev_device_write_buf(self.as_raw(), data= .as_ptr(), data.len()) }; + + to_result(ret as i32).map(|()| ret.unsigned_abs()) + } + + /// Send data to the serial device immediately. + /// + /// Note that this doesn't guarantee that the data has been transmitte= d. + /// Use [`Device::wait_until_sent`] for this purpose. + pub fn write_flush(&self) { + // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a vali= d `serdev_device`. + unsafe { bindings::serdev_device_write_flush(self.as_raw()) }; + } + + /// Wait for the data to be sent. + /// + /// After this function, the write buffer of the controller should be = empty. + pub fn wait_until_sent(&self, timeout: Timeout) { + // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a vali= d `serdev_device`. + unsafe { bindings::serdev_device_wait_until_sent(self.as_raw(), ti= meout.into_jiffies()) }; + } +} + +// SAFETY: `serdev::Device` is a transparent wrapper of `struct serdev_dev= ice`. +// The offset is guaranteed to point to a valid device field inside `serde= v::Device`. +unsafe impl device::AsBusDevice for Devic= e { + const OFFSET: usize =3D offset_of!(bindings::serdev_device, dev); +} + +// 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 AlwaysRefCounted for Device { + fn inc_ref(&self) { + self.as_ref().inc_ref(); + } + + unsafe fn dec_ref(obj: NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is = non-zero. + unsafe { bindings::serdev_device_put(obj.cast().as_ptr()) } + } +} + +impl AsRef> for Device { + fn as_ref(&self) -> &device::Device { + // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a p= ointer to a valid + // `struct serdev_device`. + let dev =3D unsafe { &raw mut (*self.as_raw()).dev }; + + // SAFETY: `dev` points to a valid `struct device`. + unsafe { device::Device::from_raw(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 `De= vice` +// (i.e. `Device) are thread safe. +unsafe impl Sync for Device {} + +// SAFETY: Same as `Device` -- the underlying `struct serdev_devic= e` is the same; +// `Bound` is a zero-sized type-state marker that does not affect thread s= afety. +unsafe impl Sync for Device {} --=20 2.54.0 From nobody Sat Jul 25 16:45:12 2026 Received: from mout02.posteo.de (mout02.posteo.de [185.67.36.66]) (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 B7EAB3CAA41 for ; Wed, 15 Jul 2026 21:00:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.67.36.66 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784149224; cv=none; b=GlvdPHtrNyk0hdIkAqjAHVDtnnTAwwn/IHCruvl3L5lb6Ic9Fg2/Y0m6VV64rwEvQlL2EDp3VplTg4Ylte4ViB2i/kqw0eq/IMx7520EA/aSgmppFUzrwnstZGztOC/kMxw/OhUDiEYMCpL3gOuFQhP3UAW1Ht6Lk8LoVkoxhGc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784149224; c=relaxed/simple; bh=QWIn30TMvT1lmgc9+8mNgqULSX/wvgFHQj1GFajrCx4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=LOlQBqmvz1WaddVez3K+/KpnJw3f462Bq9LHZE+PV4jPrEIbH1al2JyjYWbwETAiQRw7ltRNYFsLmExyxLzbw+YTYp1JYKb/kBDH/5ZiF4Loxcnxhw87U7DM8jwvE5o/TCpJaFMmfRsSdmOWsGkaVNnNW3PyBfJYkuYzsX/ZNVw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=posteo.de; spf=pass smtp.mailfrom=posteo.de; dkim=pass (2048-bit key) header.d=posteo.de header.i=@posteo.de header.b=C4BZQgb2; arc=none smtp.client-ip=185.67.36.66 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=posteo.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=posteo.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=posteo.de header.i=@posteo.de header.b="C4BZQgb2" Received: from submission (posteo.de [185.67.36.169]) by mout02.posteo.de (Postfix) with ESMTPS id ABA5B240106 for ; Wed, 15 Jul 2026 23:00:20 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.de; s=1984.8680eb; t=1784149220; bh=q4s4EmOrWKz90kwhMtLK3K0YPhABFNhnfpVflHhZGjo=; h=From:Date:Subject:MIME-Version:Content-Type: Content-Transfer-Encoding:Message-Id:To:Cc:Autocrypt:OpenPGP:From; b=C4BZQgb2AlDVu1WK98L1YuVrdWUQh8IjcCkwsLQPDNFUFio7ywxJXjyu+evNu1CfD gBr2Lru6yApc4/bwq5XUuSsyzSwNv2IoNkCUXJBa5CdRIyjLfKwwqMhPAze5c3G5G8 eQuw/PeNJ+nwQeS/+y1Y+blMLZd/t2fybVs72+1a4VtZQcMsuPtUbd5Y200Dpxp/Pp HitcX963NQLhIJmcXj47/zHWMBw76KVomAQrKMnU2HRzFknxxXG6hnRUSOHKmlzfxG tHSj+QFfzfY0B4j0MUqzo/RCJK+2Xqffxlzn6+Z46bOg7k3xzO3/TsyDg7GlF+tP7i n8lhE10yBaaGw== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4h0pTs4w96z6tyw; Wed, 15 Jul 2026 23:00:17 +0200 (CEST) From: Markus Probst Date: Wed, 15 Jul 2026 21:00:19 +0000 Subject: [PATCH v14 2/3] samples: rust: add Rust serial device bus sample device driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260715-rust_serdev-v14-2-b4ed5c93606f@posteo.de> References: <20260715-rust_serdev-v14-0-b4ed5c93606f@posteo.de> In-Reply-To: <20260715-rust_serdev-v14-0-b4ed5c93606f@posteo.de> To: Rob Herring , Greg Kroah-Hartman , Jiri Slaby , Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Kari Argillander , "Rafael J. Wysocki" , Viresh Kumar , Boqun Feng , David Airlie , Simona Vetter , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Boqun Feng Cc: linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-pm@vger.kernel.org, driver-core@lists.linux.dev, dri-devel@lists.freedesktop.org, Markus Probst X-Developer-Signature: v=1; a=openpgp-sha256; l=4721; i=markus.probst@posteo.de; h=from:subject:message-id; bh=QWIn30TMvT1lmgc9+8mNgqULSX/wvgFHQj1GFajrCx4=; b=owEBiQJ2/ZANAwAIATR2H/jnrUPSAcsmYgBqV/TaGISuazZ3R7ZPF7BvabaRkxUF7G4hzD98N 7MJ8BOdz7GJAk8EAAEIADkWIQSCdBjE9KxY53IwxHM0dh/4561D0gUCalf02hsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQNHYf+OetQ9LxCA/7BQm05hIs9AUl9tTsAVJMRiH+GwJ10Yl /SlsR3HGuo3GKCRkhbjOPX/YtbJwAYZ836aISmxhmyZ+Kw04J4gpSK4ubD1ypR/f9HOjdkjKmZe qoDNQWR/ruPC0U2xy1/nugoTAG/piJwwpTJdrBX0IUrhETu8S/k4uuV7DZegPC6BY+2zifpFg/4 92cXPZ5Rm7+8r2ZomYNLztna6UJ3TOCOn4vYSeZJihUjhA/0tBgAKl/nUUYb36shOJvy0YxjaoR yWGyCzRufr7wWugJokkS1tt7VfzOUZwJ6xnBQpNjQYuAHqZXMdj8IhInPYA1H0ZGGY9/iT/cLZ/ Niwj4KBC7du3ZXoAT9yYfVlLVw3XQkxndg9yT/a8N0g0uJyUfzNcW9HWdkAV3qjXL8Pmv0/ZVVv f8IvGp4p75MZLqtbEUBDwZ+0u7BDG5K1K7j16pTF/gDPUKhDvi79r2/OyWfPeWiUZCIS7wrdqRH YSNMZ3F5lRYxnNxPKREjiKXDATnWUvvdPS0+28BJhvPUFLABXIPZZWPuN8UFI3I04Q6YvzvFrkW ElEgH6lFhQxnPXsAjBgdALRp2L6euibXyNVcdKIdg0HK6T4jFqFEZTijmCUh3SJ4+ORDqo/ZCLO Y5AZpam4A/hG+IWhwSnV5jG2Swdxo7QHsUHXrqCjm8PiE+DERdqU= X-Developer-Key: i=markus.probst@posteo.de; a=openpgp; fpr=827418C4F4AC58E77230C47334761FF8E7AD43D2 Autocrypt: addr=markus.probst@posteo.de; prefer-encrypt=mutual; keydata=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 aBeNN4ijKZchBXHPgVx+YtWRHfcm4l8= OpenPGP: url=https://posteo.de/keys/markus.probst@posteo.de.asc; preference=encrypt Add a sample Rust serial device bus device driver illustrating the usage of the serial device bus abstractions. This drivers probes through either a match of device / driver name or a match within the OF ID table. Signed-off-by: Markus Probst Reviewed-by: Markus Probst --- MAINTAINERS | 1 + samples/rust/Kconfig | 11 +++++ samples/rust/Makefile | 1 + samples/rust/rust_driver_serdev.rs | 90 ++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 103 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index cd735d227892..7d32aa7f42a4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24570,6 +24570,7 @@ F: drivers/tty/serdev/ F: include/linux/serdev.h F: rust/helpers/serdev.c F: rust/kernel/serdev.rs +F: samples/rust/rust_driver_serdev.rs =20 SERIAL IR RECEIVER M: Sean Young diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index c49ab9106345..31d62533ef25 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -161,6 +161,17 @@ config SAMPLE_RUST_DRIVER_AUXILIARY =20 If unsure, say N. =20 +config SAMPLE_RUST_DRIVER_SERDEV + tristate "Serial Device Bus Device Driver" + select RUST_SERIAL_DEV_BUS_ABSTRACTIONS + help + This option builds the Rust serial device bus driver sample. + + To compile this as a module, choose M here: + the module will be called rust_driver_serdev. + + If unsure, say N. + config SAMPLE_RUST_SOC tristate "SoC Driver" select SOC_BUS diff --git a/samples/rust/Makefile b/samples/rust/Makefile index 6c0aaa58cccc..b986b681cde5 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) +=3D rust_drive= r_platform.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_USB) +=3D rust_driver_usb.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX) +=3D rust_driver_faux.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY) +=3D rust_driver_auxiliary.o +obj-$(CONFIG_SAMPLE_RUST_DRIVER_SERDEV) +=3D rust_driver_serdev.o obj-$(CONFIG_SAMPLE_RUST_CONFIGFS) +=3D rust_configfs.o obj-$(CONFIG_SAMPLE_RUST_SOC) +=3D rust_soc.o =20 diff --git a/samples/rust/rust_driver_serdev.rs b/samples/rust/rust_driver_= serdev.rs new file mode 100644 index 000000000000..a12b1412db30 --- /dev/null +++ b/samples/rust/rust_driver_serdev.rs @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust Serial device bus device driver sample. + +use kernel::{ + acpi, + device::{ + Bound, + Core, // + }, + of, + prelude::*, + serdev, + sync::aref::ARef, // +}; + +struct SampleDriver { + sdev: ARef, +} + +kernel::of_device_table!( + OF_TABLE, + MODULE_OF_TABLE, + ::IdInfo, + [(of::DeviceId::new(c"test,rust_driver_serdev"), ())] +); + +kernel::acpi_device_table!( + ACPI_TABLE, + MODULE_ACPI_TABLE, + ::IdInfo, + [(acpi::DeviceId::new(c"LNUXBEEF"), ())] +); + +#[vtable] +impl serdev::Driver for SampleDriver { + type IdInfo =3D (); + type Data<'bound> =3D Self; + const OF_ID_TABLE: Option> =3D Some(&OF_TABL= E); + const ACPI_ID_TABLE: Option> =3D Some(&ACP= I_TABLE); + + fn probe<'bound>( + sdev: &'bound serdev::Device>, + _info: Option<&'bound Self::IdInfo>, + ) -> impl PinInit + 'bound { + let dev =3D sdev.as_ref(); + + dev_dbg!(dev, "Probe Rust Serial device bus device driver sample.\= n"); + + if sdev + .set_baudrate( + dev.fwnode() + .and_then(|fwnode| fwnode.property_read(c"baudrate").o= ptional()) + .unwrap_or(115200), + ) + .is_err() + { + return Err(EINVAL); + } + sdev.set_flow_control(false); + sdev.set_parity(serdev::Parity::None)?; + + Ok(Self { sdev: sdev.into() }) + } + + fn receive<'bound>( + sdev: &'bound serdev::Device, + _this: Pin<&Self>, + data: &[u8], + ) -> usize { + sdev.write(data).unwrap_or_default() as usize + } +} + +impl Drop for SampleDriver { + fn drop(&mut self) { + dev_dbg!( + self.sdev.as_ref(), + "Remove Rust Serial device bus device driver sample.\n" + ); + } +} + +kernel::module_serdev_device_driver! { + type: SampleDriver, + name: "rust_driver_serdev", + authors: ["Markus Probst"], + description: "Rust Serial device bus device driver", + license: "GPL v2", +} --=20 2.54.0 From nobody Sat Jul 25 16:45:12 2026 Received: from mout02.posteo.de (mout02.posteo.de [185.67.36.66]) (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 8813C3CBE8B for ; Wed, 15 Jul 2026 21:00:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.67.36.66 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784149233; cv=none; b=Jw16DwRZwwQZ/BGTD1tdsMYgWErwipvooeon/xgcZGbsZt4l4vIUNxf1F4TM5rB5F7UN1P7yzPCn9R7PeQ04nadjvPOv4oxhPGRU+VNZgcRZ2xhf+LEqJIkXzsHAw2EkNYsY30iULMMavJjMeI1kbpZT3rweB3QHa/LuUKhK+G8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784149233; c=relaxed/simple; bh=DxSzaBqP43XW94Qp7LgDYVOU3VZcdc/fcMrcCLNmLR8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=iiUCX3uzkXTl5mmcKysOQTbedp43iZ+ypQtkWNkK5X5COGtcsn/jhqBUBuo0GnImzLnQ7emtz9HjZ0uohMvVMECnWjcsvqus5amrkpz4oV4fYvSYPp4DfEDpQV7oeZdXQ9rhP6Zwx+jnqvylCfaBxyj57tPkCktzwV7heF131/0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=posteo.de; spf=pass smtp.mailfrom=posteo.de; dkim=pass (2048-bit key) header.d=posteo.de header.i=@posteo.de header.b=BADVBTDg; arc=none smtp.client-ip=185.67.36.66 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=posteo.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=posteo.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=posteo.de header.i=@posteo.de header.b="BADVBTDg" Received: from submission (posteo.de [185.67.36.169]) by mout02.posteo.de (Postfix) with ESMTPS id 658B9240104 for ; Wed, 15 Jul 2026 23:00:22 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posteo.de; s=1984.8680eb; t=1784149222; bh=/AgXW+UnQB7fSeYuKQh0PV4Eb/oe8ytZXjtjkC3mhq8=; h=From:Date:Subject:MIME-Version:Content-Type: Content-Transfer-Encoding:Message-Id:To:Cc:Autocrypt:OpenPGP:From; b=BADVBTDgewazNL1nsC3vSMFYQPkHyfre/3yeTMyOKuR0y9Q+q20qcb8hU8gZ/gaLi U6sr/bWZEe4N1ncMa40S/dYJZRk2kZmrHFAbHNCxp/LtZ2EtIvTwyrTMaROM87JjQi wU46kBzkz3NNxSYVbeyw7CR1onWVVIusjQjQ5uzwbKip+N4ihv5qEysNYiBPXOBleb 0Lk7Uwq8uvkkswgE562BeNi95ClCOi5jzC2xVfWa47rlvxSjj4iwh8sLEzwN+AtEq8 iqiJd2MeaRbjAuTXml3nQrQMExHelHBhVZ0B6pjrjbXr0S4UIdmHnr7mdfeRMaY4zN aVKc1r6v70s6w== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4h0pTv3lXvz6v1f; Wed, 15 Jul 2026 23:00:19 +0200 (CEST) From: Markus Probst Date: Wed, 15 Jul 2026 21:00:21 +0000 Subject: [PATCH v14 3/3] MAINTAINERS: serdev: Add self for serdev Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260715-rust_serdev-v14-3-b4ed5c93606f@posteo.de> References: <20260715-rust_serdev-v14-0-b4ed5c93606f@posteo.de> In-Reply-To: <20260715-rust_serdev-v14-0-b4ed5c93606f@posteo.de> To: Rob Herring , Greg Kroah-Hartman , Jiri Slaby , Miguel Ojeda , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Kari Argillander , "Rafael J. Wysocki" , Viresh Kumar , Boqun Feng , David Airlie , Simona Vetter , Daniel Almeida , Tamir Duberstein , Alexandre Courbot , =?utf-8?q?Onur_=C3=96zkan?= , Boqun Feng Cc: linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-pm@vger.kernel.org, driver-core@lists.linux.dev, dri-devel@lists.freedesktop.org, Markus Probst X-Developer-Signature: v=1; a=openpgp-sha256; l=885; i=markus.probst@posteo.de; h=from:subject:message-id; bh=DxSzaBqP43XW94Qp7LgDYVOU3VZcdc/fcMrcCLNmLR8=; b=owEBiQJ2/ZANAwAIATR2H/jnrUPSAcsmYgBqV/TaEizSEAQrXECK7KXxIPyUFdUuahJJi2ycq CSBoDrAOpyJAk8EAAEIADkWIQSCdBjE9KxY53IwxHM0dh/4561D0gUCalf02hsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQNHYf+OetQ9LuDw//Tb4jPFKMlcHv5AfHhqTI4Qqj4y1npzF C7KcIJr4aoWlf/4c+BDdB3Z8DD5D5G5HwxlMuAuESGRNdxH1gAS6WrGyyZhshu98dIGEBtgHKXh 0x7KgqApN74s4R3jKeO5vcxWZ5HCmuma5c2wbWwZ0oSBoD3NEK0T3LWxMnA6CwZZ+iohfuTOYND 0clnMav0SwwRJdcRleM4Il+T2t6hIN7utW3DSD1TNZBBuAPpArergzFgakY/fksmpiXqf+D6ttW AQFNdwbV64li+6cTCdaWSCryANTiDWRt2O2NP680NRo9QY7XX6z/Z4hZR04UVPpPE6EsWdUQlEz NzSXufv2jQ8cdCDnv0ovqIzx2882ddPItjSrdFJga5aRFoWBywivRbd+fUnfKlMthgIHPTPaPB0 1DOrkwmdTb047Rjscm7Kj/PCySWpW39dTJ+1z1CVZLaCgqXR1V5OZAzAZXt3cLcaOYQ7A+G4VFH zNMhW0DFB6jFS8vgsVkWw4dRWBLjn6V5AsVoTNCKK/sC8N7UtVtC7u8JOfokvqgd0R+tOOI7nci cQ+J7Vnf94R8rT2A/03m25a5ii9jqIvJ7d6HweUQt4y1MrD33Xob9tVI+IL9utdkcAkLLxhsbXy rWJoiREY62nf+bCoFI2OXfd2YJbiJ9slizmERdoCACysHzrB8TII= X-Developer-Key: i=markus.probst@posteo.de; a=openpgp; fpr=827418C4F4AC58E77230C47334761FF8E7AD43D2 Autocrypt: addr=markus.probst@posteo.de; prefer-encrypt=mutual; keydata=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 aBeNN4ijKZchBXHPgVx+YtWRHfcm4l8= OpenPGP: url=https://posteo.de/keys/markus.probst@posteo.de.asc; preference=encrypt Rob mentioned he needs to find someone else to maintain serdev. Link: https://lore.kernel.org/rust-for-linux/20260430195858.GA1650658-robh@= kernel.org/ Link: https://lore.kernel.org/rust-for-linux/da85ceb81f51079d4a8248a1ffde6a= 27d2ef24ad.camel@posteo.de/ Acked-by: Rob Herring (Arm) Signed-off-by: Markus Probst Reviewed-by: Markus Probst --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7d32aa7f42a4..d092042fed31 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -24562,7 +24562,7 @@ F: drivers/iio/chemical/sps30_i2c.c F: drivers/iio/chemical/sps30_serial.c =20 SERIAL DEVICE BUS -M: Rob Herring +M: Markus Probst L: linux-serial@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/serial/serial.yaml --=20 2.54.0