From: Tristan de Cacqueray <tristan@midirus.com>
To: Takashi Iwai <tiwai@suse.de>, Miguel Ojeda <ojeda@kernel.org>
Cc: linux-sound@vger.kernel.org, rust-for-linux@vger.kernel.org,
linux-kernel@vger.kernel.org,
Tristan de Cacqueray <tristan@midirus.com>
Subject: [PATCH RFC 1/3] rust: snd: Add initial snd_card binding
Date: Sun, 11 Oct 2026 13:02:17 +0000 [thread overview]
Message-ID: <20261011-rust-snd-v1-1-7974ecdcd345@midirus.com> (raw)
In-Reply-To: <20261011-rust-snd-v1-0-7974ecdcd345@midirus.com>
Add minimal abstraction to create a snd_card in Rust.
Signed-off-by: Tristan de Cacqueray <tristan@midirus.com>
---
rust/bindings/bindings_helper.h | 1 +
rust/kernel/lib.rs | 2 ++
rust/kernel/snd.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
samples/rust/Kconfig | 11 +++++++++++
samples/rust/Makefile | 1 +
samples/rust/rust_midi_device.rs | 41 +++++++++++++++++++++++++++++++++++++++++
6 files changed, 145 insertions(+)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index c706dda5b5ca..c624f073db04 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -97,6 +97,7 @@
#include <linux/xarray.h>
#include <net/genetlink.h>
#include <net/netlink.h>
+#include <sound/core.h>
#include <trace/events/rust_sample.h>
/*
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 7225abc64084..974b3e5ce7ac 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -130,6 +130,8 @@
#[cfg(CONFIG_RUST_SERIAL_DEV_BUS_ABSTRACTIONS)]
pub mod serdev;
pub mod sizes;
+#[cfg(CONFIG_SND)]
+pub mod snd;
#[cfg(CONFIG_SOC_BUS)]
pub mod soc;
#[doc(hidden)]
diff --git a/rust/kernel/snd.rs b/rust/kernel/snd.rs
new file mode 100644
index 000000000000..aaffe942b360
--- /dev/null
+++ b/rust/kernel/snd.rs
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: Copyright (C) 2026 Tristan de Cacqueray
+
+//! Abstractions for the snd subsystem.
+//!
+//! This module provides bindings for working with ALSA in kernel modules.
+//!
+//! C header: [`include/sound/core.h`](srctree/include/sound/core.h)
+
+use kernel::{
+ bindings,
+ device::Device,
+ error::{Result},
+ prelude::*,
+};
+
+/// A sound card instance.
+pub struct SoundCard {
+ ptr: *mut bindings::snd_card,
+}
+
+impl SoundCard {
+ /// Creates a new sound card bound to a device lifecycle
+ pub fn new(dev: &Device, id: &CStr, module: &'static kernel::ThisModule) -> Result<Self> {
+ let mut card_ptr: *mut bindings::snd_card = core::ptr::null_mut();
+
+ // SAFETY: C helper copies the arguments.
+ let ret = unsafe {
+ bindings::snd_devm_card_new(
+ dev.as_raw(),
+ -1,
+ id.as_char_ptr(),
+ module.as_ptr(),
+ 0,
+ &mut card_ptr,
+ )
+ };
+
+ if ret < 0 {
+ return Err(Error::from_errno(ret));
+ }
+
+ Ok(Self { ptr: card_ptr })
+ }
+
+ /// Sets the driver field of the sound card.
+ pub fn set_driver(&mut self, name: &CStr) -> Result<()> {
+ // SAFETY: `self.ptr` is valid and points to an initialized `snd_card`.
+ let card = unsafe { &mut *self.ptr };
+ copy_to_c_buf(&mut card.driver, name)
+ }
+
+ /// Sets the shortname field of the sound card.
+ pub fn set_shortname(&mut self, name: &CStr) -> Result<()> {
+ // SAFETY: `self.ptr` is valid and points to an initialized `snd_card`.
+ let card = unsafe { &mut *self.ptr };
+ copy_to_c_buf(&mut card.shortname, name)
+ }
+
+ /// Triggers registration of the card components to the user-space ALSA layers
+ pub fn register(self) -> Result<RegisteredSoundCard> {
+ // SAFETY: `self.ptr` is valid and points to an initialized `snd_card`.
+ let ret = unsafe { bindings::snd_card_register(self.ptr) };
+ if ret < 0 {
+ return Err(Error::from_errno(ret));
+ }
+ Ok(RegisteredSoundCard { _inner: self })
+ }
+}
+
+/// Helper to copy `src` (including its NUL) into the fixed-size C buffer `dest`.
+/// Returns `EINVAL` if `src` does not fit.
+fn copy_to_c_buf(dest: &mut [ffi::c_char], src: &CStr) -> Result<()> {
+ let bytes = src.to_bytes_with_nul();
+ if bytes.len() > dest.len() {
+ return Err(EINVAL);
+ }
+ let (used, rest) = dest.split_at_mut(bytes.len());
+ for (d, &b) in used.iter_mut().zip(bytes) {
+ *d = b as ffi::c_char;
+ }
+ rest.fill(0);
+ Ok(())
+}
+
+/// A sound card that is already registered.
+pub struct RegisteredSoundCard {
+ _inner: SoundCard,
+}
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
index 31d62533ef25..1cf8cf18cd2d 100644
--- a/samples/rust/Kconfig
+++ b/samples/rust/Kconfig
@@ -31,6 +31,17 @@ config SAMPLE_RUST_MINIMAL
If unsure, say N.
+config SAMPLE_RUST_MIDI_DEVICE
+ tristate "MIDI device"
+ depends on SND_RAWMIDI
+ help
+ This option builds the Rust MIDI device.
+
+ To compile this as a module, choose M here:
+ the module will be called rust_midi_device.
+
+ If unsure, say N.
+
config SAMPLE_RUST_MISC_DEVICE
tristate "Misc device"
help
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
index b986b681cde5..170b7e3e5590 100644
--- a/samples/rust/Makefile
+++ b/samples/rust/Makefile
@@ -2,6 +2,7 @@
ccflags-y += -I$(src) # needed for trace events
obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o
+obj-$(CONFIG_SAMPLE_RUST_MIDI_DEVICE) += rust_midi_device.o
obj-$(CONFIG_SAMPLE_RUST_MISC_DEVICE) += rust_misc_device.o
obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o
obj-$(CONFIG_SAMPLE_RUST_DEBUGFS) += rust_debugfs.o
diff --git a/samples/rust/rust_midi_device.rs b/samples/rust/rust_midi_device.rs
new file mode 100644
index 000000000000..5561a0437b59
--- /dev/null
+++ b/samples/rust/rust_midi_device.rs
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust MIDI minimal sample.
+
+use kernel::{
+ faux,
+ prelude::*,
+ snd,
+};
+
+impl kernel::Module for RustMidiDeviceModule {
+ fn init(_module: &'static ThisModule) -> Result<Self> {
+ pr_debug!("Initializing sound card\n");
+ let reg = faux::Registration::new(c"rust-midi-device", None)?;
+ let fdev = reg.as_ref();
+ let mut card = snd::SoundCard::new(
+ fdev.as_ref(),
+ c"RustMIDI",
+ kernel::module::this_module::<RustMidiDeviceModule>(),
+ )?;
+ card.set_driver(c"rust-midi")?;
+ card.set_shortname(c"RustMIDI")?;
+
+ // Register the sndcard to ALSA.
+ card.register()?;
+
+ Ok(Self { _reg: reg })
+ }
+}
+
+struct RustMidiDeviceModule {
+ _reg: faux::Registration,
+}
+
+module! {
+ type: RustMidiDeviceModule,
+ name: "rust_midi_device",
+ authors: ["Rust for Linux Contributors"],
+ description: "Rust MIDI device sample",
+ license: "GPL",
+}
--
2.56.0
next prev parent reply other threads:[~2026-10-11 13:02 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-11 13:02 [PATCH RFC 0/3] rust: snd: Introduce experimental ALSA rawmidi abstractions Tristan de Cacqueray
2026-10-11 13:02 ` Tristan de Cacqueray [this message]
2026-10-11 13:02 ` [PATCH RFC 2/3] rust: snd: Add snd_rawmidi binding Tristan de Cacqueray
2026-10-11 13:02 ` [PATCH RFC 3/3] rust: snd: Add active rawmidi_substream helper Tristan de Cacqueray
2026-10-12 12:23 ` [PATCH RFC 0/3] rust: snd: Introduce experimental ALSA rawmidi abstractions Takashi Iwai
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=20261011-rust-snd-v1-1-7974ecdcd345@midirus.com \
--to=tristan@midirus.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tiwai@suse.de \
/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
all inboxes | Powered by JetHome®