diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 8e5d4ab4e75e6e..860e19200fb898 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -84,13 +84,15 @@ dtb-$(CONFIG_ARCH_BCM2835) += \ bcm2835-rpi-a-plus.dtb \ bcm2835-rpi-cm1-io1.dtb \ bcm2836-rpi-2-b.dtb \ + bcm2836-rpi-2-b-rust.dtb \ bcm2837-rpi-3-a-plus.dtb \ bcm2837-rpi-3-b.dtb \ bcm2837-rpi-3-b-plus.dtb \ bcm2837-rpi-cm3-io3.dtb \ bcm2711-rpi-4-b.dtb \ bcm2835-rpi-zero.dtb \ - bcm2835-rpi-zero-w.dtb + bcm2835-rpi-zero-w.dtb \ + bcm2835-rpi-zero-w-rust.dtb dtb-$(CONFIG_ARCH_BCM_5301X) += \ bcm4708-asus-rt-ac56u.dtb \ bcm4708-asus-rt-ac68u.dtb \ diff --git a/arch/arm/boot/dts/bcm2835-rpi-zero-w-rust.dts b/arch/arm/boot/dts/bcm2835-rpi-zero-w-rust.dts new file mode 100644 index 00000000000000..18298115c1f5ce --- /dev/null +++ b/arch/arm/boot/dts/bcm2835-rpi-zero-w-rust.dts @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017 Stefan Wahren + */ + +/dts-v1/; +#include "bcm2835.dtsi" +#include "bcm2835-rpi.dtsi" +#include "bcm283x-rpi-usb-otg.dtsi" + +/ { + compatible = "raspberrypi,model-zero-w", "brcm,bcm2835"; + model = "Raspberry Pi Zero W"; + + bcm2835-rng-rust { + compatible = "brcm,bcm2835-rng"; + status = "okay"; + }; + + memory@0 { + device_type = "memory"; + reg = <0 0x20000000>; + }; + + chosen { + /* 8250 auxiliary UART instead of pl011 */ + stdout-path = "serial1:115200n8"; + }; + + leds { + act { + gpios = <&gpio 47 GPIO_ACTIVE_LOW>; + }; + }; + + wifi_pwrseq: wifi-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio 41 GPIO_ACTIVE_LOW>; + }; +}; + +&gpio { + /* + * This is based on the official GPU firmware DT blob. + * + * Legend: + * "NC" = not connected (no rail from the SoC) + * "FOO" = GPIO line named "FOO" on the schematic + * "FOO_N" = GPIO line named "FOO" on schematic, active low + */ + gpio-line-names = "ID_SDA", + "ID_SCL", + "SDA1", + "SCL1", + "GPIO_GCLK", + "GPIO5", + "GPIO6", + "SPI_CE1_N", + "SPI_CE0_N", + "SPI_MISO", + "SPI_MOSI", + "SPI_SCLK", + "GPIO12", + "GPIO13", + /* Serial port */ + "TXD0", + "RXD0", + "GPIO16", + "GPIO17", + "GPIO18", + "GPIO19", + "GPIO20", + "GPIO21", + "GPIO22", + "GPIO23", + "GPIO24", + "GPIO25", + "GPIO26", + "GPIO27", + "SDA0", + "SCL0", + "NC", /* GPIO30 */ + "NC", /* GPIO31 */ + "NC", /* GPIO32 */ + "NC", /* GPIO33 */ + "NC", /* GPIO34 */ + "NC", /* GPIO35 */ + "NC", /* GPIO36 */ + "NC", /* GPIO37 */ + "NC", /* GPIO38 */ + "NC", /* GPIO39 */ + "CAM_GPIO1", /* GPIO40 */ + "WL_ON", /* GPIO41 */ + "NC", /* GPIO42 */ + "WIFI_CLK", /* GPIO43 */ + "CAM_GPIO0", /* GPIO44 */ + "BT_ON", /* GPIO45 */ + "HDMI_HPD_N", + "STATUS_LED_N", + /* Used by SD Card */ + "SD_CLK_R", + "SD_CMD_R", + "SD_DATA0_R", + "SD_DATA1_R", + "SD_DATA2_R", + "SD_DATA3_R"; + + pinctrl-0 = <&gpioout &alt0>; +}; + +&hdmi { + hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; +}; + +&sdhci { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_gpio34 &gpclk2_gpio43>; + bus-width = <4>; + mmc-pwrseq = <&wifi_pwrseq>; + non-removable; + status = "okay"; + + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + }; +}; + +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; + bus-width = <4>; + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_gpio32 &uart0_ctsrts_gpio30>; + status = "okay"; + + bluetooth { + compatible = "brcm,bcm43438-bt"; + max-speed = <2000000>; + shutdown-gpios = <&gpio 45 GPIO_ACTIVE_HIGH>; + }; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_gpio14>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b-rust.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b-rust.dts new file mode 100644 index 00000000000000..1e3340097ec761 --- /dev/null +++ b/arch/arm/boot/dts/bcm2836-rpi-2-b-rust.dts @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +#include "bcm2836.dtsi" +#include "bcm2836-rpi.dtsi" +#include "bcm283x-rpi-smsc9514.dtsi" +#include "bcm283x-rpi-usb-host.dtsi" + +/ { + compatible = "raspberrypi,2-model-b", "brcm,bcm2836"; + model = "Raspberry Pi 2 Model B"; + + memory@0 { + device_type = "memory"; + reg = <0 0x40000000>; + }; + + bcm2835-rng-rust { + compatible = "brcm,bcm2835-rng"; + status = "okay"; + }; + + leds { + act { + gpios = <&gpio 47 GPIO_ACTIVE_HIGH>; + }; + + pwr { + label = "PWR"; + gpios = <&gpio 35 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + linux,default-trigger = "default-on"; + }; + }; +}; + +&gpio { + /* + * Taken from rpi_SCH_2b_1p2_reduced.pdf and + * the official GPU firmware DT blob. + * + * Legend: + * "NC" = not connected (no rail from the SoC) + * "FOO" = GPIO line named "FOO" on the schematic + * "FOO_N" = GPIO line named "FOO" on schematic, active low + */ + gpio-line-names = "ID_SDA", + "ID_SCL", + "SDA1", + "SCL1", + "GPIO_GCLK", + "GPIO5", + "GPIO6", + "SPI_CE1_N", + "SPI_CE0_N", + "SPI_MISO", + "SPI_MOSI", + "SPI_SCLK", + "GPIO12", + "GPIO13", + /* Serial port */ + "TXD0", + "RXD0", + "GPIO16", + "GPIO17", + "GPIO18", + "GPIO19", + "GPIO20", + "GPIO21", + "GPIO22", + "GPIO23", + "GPIO24", + "GPIO25", + "GPIO26", + "GPIO27", + "SDA0", + "SCL0", + "", /* GPIO30 */ + "LAN_RUN", + "CAM_GPIO1", + "", /* GPIO33 */ + "", /* GPIO34 */ + "PWR_LOW_N", + "", /* GPIO36 */ + "", /* GPIO37 */ + "USB_LIMIT", + "", /* GPIO39 */ + "PWM0_OUT", + "CAM_GPIO0", + "SMPS_SCL", + "SMPS_SDA", + "ETHCLK", + "PWM1_OUT", + "HDMI_HPD_N", + "STATUS_LED", + /* Used by SD Card */ + "SD_CLK_R", + "SD_CMD_R", + "SD_DATA0_R", + "SD_DATA1_R", + "SD_DATA2_R", + "SD_DATA3_R"; + + pinctrl-0 = <&gpioout &alt0 &i2s_alt0>; + + /* I2S interface */ + i2s_alt0: i2s_alt0 { + brcm,pins = <18 19 20 21>; + brcm,function = ; + }; +}; + +&hdmi { + hpd-gpios = <&gpio 46 GPIO_ACTIVE_LOW>; + power-domains = <&power RPI_POWER_DOMAIN_HDMI>; + status = "okay"; +}; + +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio45>; + status = "okay"; +}; + +&sdhost { + pinctrl-names = "default"; + pinctrl-0 = <&sdhost_gpio48>; + bus-width = <4>; + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_gpio14>; + status = "okay"; +}; diff --git a/arch/arm/configs/bcm2835_rust_defconfig b/arch/arm/configs/bcm2835_rust_defconfig new file mode 100644 index 00000000000000..eb7952baf2f071 --- /dev/null +++ b/arch/arm/configs/bcm2835_rust_defconfig @@ -0,0 +1,200 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_CFS_BANDWIDTH=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_NAMESPACES=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_RUST=y +CONFIG_ARCH_MULTI_V6=y +CONFIG_ARCH_BCM=y +CONFIG_ARCH_BCM2835=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPUFREQ_DT=y +CONFIG_ARM_RASPBERRYPI_CPUFREQ=y +CONFIG_VFP=y +# CONFIG_SUSPEND is not set +CONFIG_PM=y +CONFIG_RASPBERRYPI_FIRMWARE=y +CONFIG_JUMP_LABEL=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_KSM=y +CONFIG_CLEANCACHE=y +CONFIG_CMA=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NETFILTER=y +CONFIG_BT=y +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_BCM=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_NETDEVICES=y +CONFIG_BCMGENET=y +CONFIG_USB_LAN78XX=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_BRCMFMAC=m +CONFIG_ZD1211RW=y +CONFIG_INPUT_EVDEV=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_BCM2835AUX=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_DEV_BUS=y +CONFIG_TTY_PRINTK=y +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_BCM2835 is not set +CONFIG_HW_RANDOM_BCM2835_RUST=y +CONFIG_HW_RANDOM_IPROC_RNG200=m +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_BCM2835=y +CONFIG_SPI=y +CONFIG_SPI_BCM2835=y +CONFIG_SPI_BCM2835AUX=y +CONFIG_GPIO_SYSFS=y +CONFIG_SENSORS_RASPBERRYPI_HWMON=m +CONFIG_THERMAL=y +CONFIG_BCM2711_THERMAL=y +CONFIG_BCM2835_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_BCM2835_WDT=y +CONFIG_MFD_SYSCON=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_GPIO=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_DRM=y +CONFIG_DRM_VC4=y +CONFIG_FB_SIMPLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_BCM2835_SOC_I2S=y +CONFIG_USB=y +CONFIG_USB_OTG=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC2=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_GADGET=y +CONFIG_USB_ETH=m +CONFIG_USB_ETH_EEM=y +CONFIG_USB_G_SERIAL=m +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_IPROC=y +CONFIG_MMC_BCM2835=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_LEDS_TRIGGER_TRANSIENT=y +CONFIG_LEDS_TRIGGER_CAMERA=y +CONFIG_DMADEVICES=y +CONFIG_DMA_BCM2835=y +CONFIG_STAGING=y +CONFIG_SND_BCM2835=m +CONFIG_VIDEO_BCM2835=m +CONFIG_CLK_RASPBERRYPI=y +CONFIG_MAILBOX=y +CONFIG_BCM2835_MBOX=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_RASPBERRYPI_POWER=y +CONFIG_PWM=y +CONFIG_PWM_BCM2835=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_FANOTIFY=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_NFSD=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +CONFIG_DMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=32 +CONFIG_PRINTK_TIME=y +CONFIG_BOOT_PRINTK_DELAY=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_FS=y +CONFIG_KGDB=y +CONFIG_KGDB_KDB=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +CONFIG_SCHED_TRACER=y +CONFIG_SAMPLES=y +CONFIG_SAMPLES_RUST=y +CONFIG_SAMPLE_RUST_MINIMAL=m +CONFIG_SAMPLE_RUST_PRINT=m +CONFIG_SAMPLE_RUST_MODULE_PARAMETERS=m +CONFIG_SAMPLE_RUST_SYNC=m +CONFIG_SAMPLE_RUST_CHRDEV=m +CONFIG_SAMPLE_RUST_MISCDEV=m +CONFIG_SAMPLE_RUST_STACK_PROBING=m +CONFIG_SAMPLE_RUST_SEMAPHORE=m +CONFIG_SAMPLE_RUST_SEMAPHORE_C=m +CONFIG_SAMPLE_RUST_RANDOM=m +CONFIG_STRICT_DEVMEM=y +CONFIG_TEST_KSTRTOX=y diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 1fe006f3f12fab..50a516ce0b4f49 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -98,6 +98,19 @@ config HW_RANDOM_BCM2835 If unsure, say Y. +config HW_RANDOM_BCM2835_RUST + tristate "Rust implementation of Broadcom BCM2835 Random Number Generator" + depends on HAS_RUST && ARCH_BCM2835 + help + This driver provides alternative Rust-based kernel-side support + for the Random Number Generator hardware found on the Broadcom + BCM2835 SoC. + + To compile this driver as a module, choose M here: the + module will be called bcm2835_rng_rust + + If unsure, say N. + config HW_RANDOM_IPROC_RNG200 tristate "Broadcom iProc/STB RNG200 support" depends on ARCH_BCM_IPROC || ARCH_BCM2835 || ARCH_BRCMSTB diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 8933fada74f2fb..3e14586f2b3f29 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o +obj-$(CONFIG_HW_RANDOM_BCM2835_RUST) += bcm2835_rng_rust.o obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o obj-$(CONFIG_HW_RANDOM_ST) += st-rng.o obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o diff --git a/drivers/char/hw_random/bcm2835_rng_rust.rs b/drivers/char/hw_random/bcm2835_rng_rust.rs new file mode 100644 index 00000000000000..0a89dc0ba87828 --- /dev/null +++ b/drivers/char/hw_random/bcm2835_rng_rust.rs @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Broadcom BCM2835 Random Number Generator support. + +#![no_std] +#![feature(allocator_api, global_asm)] + +use alloc::boxed::Box; +use core::pin::Pin; +use kernel::prelude::*; +use kernel::{cstr, platdev}; + +module! { + type: RngModule, + name: b"bcm2835_rng_rust", + author: b"Rust for Linux Contributors", + description: b"BCM2835 Random Number Generator (RNG) driver", + license: b"GPL v2", +} + +struct RngModule { + _pdev: Pin>, +} + +impl KernelModule for RngModule { + fn init() -> Result { + let pdev = platdev::Registration::new_pinned(cstr!("bcm2835-rng-rust"), &THIS_MODULE)?; + + Ok(RngModule { _pdev: pdev }) + } +} diff --git a/rust/kernel/bindings_helper.h b/rust/kernel/bindings_helper.h index ec052e54350fd9..b66a326fc48ae8 100644 --- a/rust/kernel/bindings_helper.h +++ b/rust/kernel/bindings_helper.h @@ -13,6 +13,7 @@ #include #include #include +#include // `bindgen` gets confused at certain things const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL; diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index da488d67776ae2..0989ea601314dc 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -62,6 +62,7 @@ pub mod sysctl; pub mod io_buffer; pub mod iov_iter; +pub mod platdev; mod types; pub mod user_ptr; diff --git a/rust/kernel/platdev.rs b/rust/kernel/platdev.rs new file mode 100644 index 00000000000000..7cf35657227426 --- /dev/null +++ b/rust/kernel/platdev.rs @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Platform devices. +//! +//! Also called `platdev`, `pdev`. +//! +//! C header: [`include/linux/platform_device.h`](../../../../include/linux/platform_device.h) + +use crate::{ + bindings, c_types, + error::{Error, Result}, + pr_info, CStr, +}; +use alloc::boxed::Box; +use core::{marker::PhantomPinned, pin::Pin}; + +/// A registration of a platform device. +#[derive(Default)] +pub struct Registration { + registered: bool, + pdrv: bindings::platform_driver, + _pin: PhantomPinned, +} + +// SAFETY: `Registration` does not expose any of its state across threads +// (it is fine for multiple threads to have a shared reference to it). +unsafe impl Sync for Registration {} + +extern "C" fn probe_callback(_pdev: *mut bindings::platform_device) -> c_types::c_int { + pr_info!("Rust platform_device probed\n"); + 0 +} + +extern "C" fn remove_callback(_pdev: *mut bindings::platform_device) -> c_types::c_int { + pr_info!("Rust platform_device removed\n"); + 0 +} + +impl Registration { + fn register( + self: Pin<&mut Self>, + name: CStr<'static>, + module: &'static crate::ThisModule, + ) -> Result { + // SAFETY: We must ensure that we never move out of `this`. + let this = unsafe { self.get_unchecked_mut() }; + if this.registered { + // Already registered. + return Err(Error::EINVAL); + } + this.pdrv.driver.name = name.as_ptr() as *const c_types::c_char; + this.pdrv.probe = Some(probe_callback); + this.pdrv.remove = Some(remove_callback); + // SAFETY: + // - `this.pdrv` lives at least until the call to `platform_driver_unregister()` returns. + // - `name` pointer has static lifetime. + // - `module.0` lives at least as long as the module. + // - `probe()` and `remove()` are static functions. + let ret = unsafe { bindings::__platform_driver_register(&mut this.pdrv, module.0) }; + if ret < 0 { + return Err(Error::from_kernel_errno(ret)); + } + this.registered = true; + Ok(()) + } + + /// Registers a platform device. + /// + /// Returns a pinned heap-allocated representation of the registration. + pub fn new_pinned( + name: CStr<'static>, + module: &'static crate::ThisModule, + ) -> Result>> { + let mut r = Pin::from(Box::try_new(Self::default())?); + r.as_mut().register(name, module)?; + Ok(r) + } +} + +impl Drop for Registration { + fn drop(&mut self) { + if self.registered { + // SAFETY: if `registered` is true, then `self.pdev` was registered + // previously, which means `platform_driver_unregister` is always + // safe to call. + unsafe { bindings::platform_driver_unregister(&mut self.pdrv) } + } + } +}