From af24671ebf9ab02955eda6af234d4dac351065ba Mon Sep 17 00:00:00 2001 From: xuchang-vivo <72209398@vivo.com> Date: Wed, 8 Jul 2026 10:32:21 +0800 Subject: [PATCH 01/13] add fb framework --- kernel/src/boot.rs | 11 +++--- kernel/tests/test_vfs.rs | 80 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/kernel/src/boot.rs b/kernel/src/boot.rs index a963289e..278ec733 100644 --- a/kernel/src/boot.rs +++ b/kernel/src/boot.rs @@ -115,6 +115,12 @@ extern "C" fn init() { // initialize virtio virtio::init_virtio(&fdt); } + + #[cfg(spi_core)] + crate::boards::init_spi_bus(); + #[cfg(i2c_core)] + crate::boards::init_i2c_bus(); + #[cfg(enable_vfs)] init_vfs(); @@ -129,11 +135,6 @@ extern "C" fn init() { net::net_manager::init(); } - #[cfg(spi_core)] - crate::boards::init_spi_bus(); - #[cfg(i2c_core)] - crate::boards::init_i2c_bus(); - // it's an bug in fact, but at now we use a workaround let newlib do the c++ runtime initialization #[cfg(not(target_board = "newlib_mps3_an547"))] run_init_array(); diff --git a/kernel/tests/test_vfs.rs b/kernel/tests/test_vfs.rs index 7c99658b..935a071b 100644 --- a/kernel/tests/test_vfs.rs +++ b/kernel/tests/test_vfs.rs @@ -78,6 +78,86 @@ fn test_uart() { ); } +#[test] +fn test_framebuffer_devfs_read_write_seek() { + let fd = open(c"/dev/fb0".as_ptr() as *const c_char, O_RDWR, 0); + assert!(fd >= 0, "[VFS Test framebuffer]: Failed to open /dev/fb0"); + + let test_data = [0x12, 0x34, 0x56, 0x78]; + let write_size = write(fd, test_data.as_ptr(), test_data.len()); + assert_eq!(write_size, test_data.len() as isize); + + let offset = lseek(fd, 0, SEEK_SET); + assert_eq!(offset, 0); + + let mut read_buf = [0; 4]; + let read_size = read(fd, read_buf.as_mut_ptr(), read_buf.len()); + assert_eq!(read_size, read_buf.len() as isize); + assert_eq!(read_buf, test_data); + + let end_offset = lseek(fd, 0, SEEK_END); + assert!(end_offset > 0); + + let close_result = close(fd); + assert_eq!(close_result, 0); +} + +#[test] +fn test_framebuffer_devfs_ioctls() { + let fd = open(c"/dev/fb0".as_ptr() as *const c_char, O_RDWR, 0); + assert!(fd >= 0, "[VFS Test framebuffer]: Failed to open /dev/fb0"); + + let mut fixed_info = unsafe { mem::zeroed::() }; + assert_eq!( + ioctl( + fd, + libc::FBIOGET_FSCREENINFO.into(), + (&mut fixed_info as *mut libc::fb_fix_screeninfo).cast::() + ), + 0 + ); + assert!(fixed_info.smem_len > 0); + assert!(fixed_info.line_length > 0); + + let mut variable_info = unsafe { mem::zeroed::() }; + assert_eq!( + ioctl( + fd, + libc::FBIOGET_VSCREENINFO.into(), + (&mut variable_info as *mut libc::fb_var_screeninfo).cast::() + ), + 0 + ); + assert!(variable_info.xres > 0); + assert!(variable_info.yres > 0); + assert!(variable_info.bits_per_pixel > 0); + + assert_eq!( + ioctl( + fd, + libc::FBIOPUT_VSCREENINFO.into(), + (&mut variable_info as *mut libc::fb_var_screeninfo).cast::() + ), + 0 + ); + + let mut unsupported_info = variable_info; + unsupported_info.bits_per_pixel += 1; + assert_eq!( + ioctl( + fd, + libc::FBIOPUT_VSCREENINFO.into(), + (&mut unsupported_info as *mut libc::fb_var_screeninfo).cast::() + ), + -libc::EINVAL + ); + + assert_eq!(ioctl(fd, 0xffff_ffff, core::ptr::null_mut()), -libc::EIO); + + let close_result = close(fd); + assert_eq!(close_result, 0); +} + #[test] fn test_read_and_write() { println!("[VFS Test Read/Write] Test the tmpfs mounted at /"); From 27e55e0c1f8f43f3e1f25c8a24f21b0c60a7b36a Mon Sep 17 00:00:00 2001 From: xuchang-vivo <72209398@vivo.com> Date: Thu, 9 Jul 2026 17:56:01 +0800 Subject: [PATCH 02/13] add st7789 driver moduler --- kconfig/config/seeed_xiao_esp32c3/debug/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig index 6e5739bf..508c0c4f 100644 --- a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig +++ b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig @@ -33,3 +33,4 @@ CONFIG_ENABLE_VFS=y CONFIG_ENABLE_NET=n CONFIG_PROCFS=n CONFIG_UNITTEST_THREAD_NUM=16 +CONFIG_LOG_LEVEL_DEBUG=y From 2232cac14ab4cf041105fea403681745bf3a1546 Mon Sep 17 00:00:00 2001 From: xuchang-vivo <72209398@vivo.com> Date: Mon, 13 Jul 2026 11:22:45 +0800 Subject: [PATCH 03/13] fix typo & fmt --- kconfig/config/seeed_xiao_esp32c3/debug/defconfig | 1 - kernel/tests/test_vfs.rs | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig index 508c0c4f..6e5739bf 100644 --- a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig +++ b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig @@ -33,4 +33,3 @@ CONFIG_ENABLE_VFS=y CONFIG_ENABLE_NET=n CONFIG_PROCFS=n CONFIG_UNITTEST_THREAD_NUM=16 -CONFIG_LOG_LEVEL_DEBUG=y diff --git a/kernel/tests/test_vfs.rs b/kernel/tests/test_vfs.rs index 935a071b..c42191ed 100644 --- a/kernel/tests/test_vfs.rs +++ b/kernel/tests/test_vfs.rs @@ -111,7 +111,7 @@ fn test_framebuffer_devfs_ioctls() { assert_eq!( ioctl( fd, - libc::FBIOGET_FSCREENINFO.into(), + libc::FBIOGET_FSCREENINFO, (&mut fixed_info as *mut libc::fb_fix_screeninfo).cast::() ), 0 @@ -123,7 +123,7 @@ fn test_framebuffer_devfs_ioctls() { assert_eq!( ioctl( fd, - libc::FBIOGET_VSCREENINFO.into(), + libc::FBIOGET_VSCREENINFO, (&mut variable_info as *mut libc::fb_var_screeninfo).cast::() ), 0 @@ -135,7 +135,7 @@ fn test_framebuffer_devfs_ioctls() { assert_eq!( ioctl( fd, - libc::FBIOPUT_VSCREENINFO.into(), + libc::FBIOPUT_VSCREENINFO, (&mut variable_info as *mut libc::fb_var_screeninfo).cast::() ), 0 @@ -146,7 +146,7 @@ fn test_framebuffer_devfs_ioctls() { assert_eq!( ioctl( fd, - libc::FBIOPUT_VSCREENINFO.into(), + libc::FBIOPUT_VSCREENINFO, (&mut unsupported_info as *mut libc::fb_var_screeninfo).cast::() ), -libc::EINVAL From fa4b32e7273b07ef3b63ab6b94204477a1fa45cb Mon Sep 17 00:00:00 2001 From: xuchang-vivo <72209398@vivo.com> Date: Mon, 13 Jul 2026 12:00:06 +0800 Subject: [PATCH 04/13] fix bug --- kernel/tests/test_vfs.rs | 80 ---------------------------------------- 1 file changed, 80 deletions(-) diff --git a/kernel/tests/test_vfs.rs b/kernel/tests/test_vfs.rs index c42191ed..7c99658b 100644 --- a/kernel/tests/test_vfs.rs +++ b/kernel/tests/test_vfs.rs @@ -78,86 +78,6 @@ fn test_uart() { ); } -#[test] -fn test_framebuffer_devfs_read_write_seek() { - let fd = open(c"/dev/fb0".as_ptr() as *const c_char, O_RDWR, 0); - assert!(fd >= 0, "[VFS Test framebuffer]: Failed to open /dev/fb0"); - - let test_data = [0x12, 0x34, 0x56, 0x78]; - let write_size = write(fd, test_data.as_ptr(), test_data.len()); - assert_eq!(write_size, test_data.len() as isize); - - let offset = lseek(fd, 0, SEEK_SET); - assert_eq!(offset, 0); - - let mut read_buf = [0; 4]; - let read_size = read(fd, read_buf.as_mut_ptr(), read_buf.len()); - assert_eq!(read_size, read_buf.len() as isize); - assert_eq!(read_buf, test_data); - - let end_offset = lseek(fd, 0, SEEK_END); - assert!(end_offset > 0); - - let close_result = close(fd); - assert_eq!(close_result, 0); -} - -#[test] -fn test_framebuffer_devfs_ioctls() { - let fd = open(c"/dev/fb0".as_ptr() as *const c_char, O_RDWR, 0); - assert!(fd >= 0, "[VFS Test framebuffer]: Failed to open /dev/fb0"); - - let mut fixed_info = unsafe { mem::zeroed::() }; - assert_eq!( - ioctl( - fd, - libc::FBIOGET_FSCREENINFO, - (&mut fixed_info as *mut libc::fb_fix_screeninfo).cast::() - ), - 0 - ); - assert!(fixed_info.smem_len > 0); - assert!(fixed_info.line_length > 0); - - let mut variable_info = unsafe { mem::zeroed::() }; - assert_eq!( - ioctl( - fd, - libc::FBIOGET_VSCREENINFO, - (&mut variable_info as *mut libc::fb_var_screeninfo).cast::() - ), - 0 - ); - assert!(variable_info.xres > 0); - assert!(variable_info.yres > 0); - assert!(variable_info.bits_per_pixel > 0); - - assert_eq!( - ioctl( - fd, - libc::FBIOPUT_VSCREENINFO, - (&mut variable_info as *mut libc::fb_var_screeninfo).cast::() - ), - 0 - ); - - let mut unsupported_info = variable_info; - unsupported_info.bits_per_pixel += 1; - assert_eq!( - ioctl( - fd, - libc::FBIOPUT_VSCREENINFO, - (&mut unsupported_info as *mut libc::fb_var_screeninfo).cast::() - ), - -libc::EINVAL - ); - - assert_eq!(ioctl(fd, 0xffff_ffff, core::ptr::null_mut()), -libc::EIO); - - let close_result = close(fd); - assert_eq!(close_result, 0); -} - #[test] fn test_read_and_write() { println!("[VFS Test Read/Write] Test the tmpfs mounted at /"); From a80a433ae479b1e18b6b5e79b51d0215914e5b06 Mon Sep 17 00:00:00 2001 From: xuchang-vivo <72209398@vivo.com> Date: Thu, 16 Jul 2026 16:03:03 +0800 Subject: [PATCH 05/13] add st7796 --- macro/BUILD.gn | 2 +- test_harness/BUILD.gn | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/macro/BUILD.gn b/macro/BUILD.gn index c6181342..614873ec 100644 --- a/macro/BUILD.gn +++ b/macro/BUILD.gn @@ -22,7 +22,7 @@ build_rust("blueos_macro") { deps = [] proc_macro_deps = [ "//external/vendor/proc-macro2-1.0.103:proc_macro2", - "//external/vendor/quote-1.0.41:quote", + "//external/vendor/quote-1.0.46:quote", "//external/vendor/syn-2.0.108:syn", ] features = [] diff --git a/test_harness/BUILD.gn b/test_harness/BUILD.gn index c57e7ac2..ddc0328d 100644 --- a/test_harness/BUILD.gn +++ b/test_harness/BUILD.gn @@ -24,7 +24,7 @@ build_rust("blueos_test_macro") { ] deps = [ "//external/vendor/proc-macro2-1.0.103:proc_macro2", - "//external/vendor/quote-1.0.41:quote", + "//external/vendor/quote-1.0.46:quote", "//external/vendor/syn-2.0.108:syn", ] } From a0314be9c906179eaabb337d078690217af025f6 Mon Sep 17 00:00:00 2001 From: xuchang-vivo <72209398@vivo.com> Date: Tue, 21 Jul 2026 15:08:56 +0800 Subject: [PATCH 06/13] add tc --- kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 53 ++++- kernel/src/drivers/input/ft6336u.rs | 207 ++++++++++++++++++++ kernel/src/drivers/input/mod.rs | 15 ++ kernel/src/drivers/mod.rs | 1 + 4 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 kernel/src/drivers/input/ft6336u.rs create mode 100644 kernel/src/drivers/input/mod.rs diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 1e897fbf..ead8fc5f 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -239,6 +239,20 @@ crate::define_bus! { } ), ), + ( + i2c_bus, + crate::devices::i2c_core::block_i2c::BlockI2c, + #[cfg(ft6336u)] + (ft6336u, crate::drivers::input::ft6336u::Ft6336uConfig, + crate::drivers::input::ft6336u::Ft6336uConfig:: { + rst: get_device!(touch_rst_pin), + } + ), + #[cfg(bme280)] + (bme280, crate::drivers::sensor::bme280::Bme280Config, + crate::drivers::sensor::bme280::Bme280Config::new(0x76) + ), + ), } pub(crate) fn init_spi_bus() { @@ -283,4 +297,41 @@ pub(crate) fn init_spi_bus() { } } -pub(crate) fn init_i2c_bus() {} +pub(crate) fn init_i2c_bus() { + use crate::{ + devices::{bus::Bus, i2c_core::block_i2c::BlockI2c}, + drivers::InitDriver, + }; + use alloc::sync::Arc; + + if let Ok(block_i2c) = BlockI2c::new(get_device!(i2c0)) { + let i2c_bus = Arc::new(Bus::new(block_i2c)); + for device in crate::boards::get_bus_devices!(i2c_bus) { + i2c_bus.register_device(device).unwrap(); + } + + #[cfg(ft6336u)] + if let Ok(driver) = + i2c_bus.probe_driver(&crate::drivers::input::ft6336u::Ft6336uDriverModule::< + blueos_driver::gpio::esp32_gpio::Esp32GpioOutputPin, + >::new()) + { + if let Err(error) = driver.init(&i2c_bus) { + log::warn!("Failed to initialize FT6336U driver: {}", error); + } + } else { + log::warn!("Failed to probe FT6336U driver"); + } + + #[cfg(bme280)] + if let Ok(driver) = i2c_bus.probe_driver(&crate::drivers::sensor::bme280::Bme280DriverModule) { + if let Err(error) = driver.init(&i2c_bus) { + log::warn!("Failed to initialize BME280 driver: {}", error); + } + } else { + log::warn!("Failed to probe BME280 driver"); + } + } else { + log::warn!("Failed to initialize ESP32-C3 I2C0 bus"); + } +} diff --git a/kernel/src/drivers/input/ft6336u.rs b/kernel/src/drivers/input/ft6336u.rs new file mode 100644 index 00000000..8915d17e --- /dev/null +++ b/kernel/src/drivers/input/ft6336u.rs @@ -0,0 +1,207 @@ +// Copyright (c) 2026 vivo Mobile Communication Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use blueos_driver::i2c::I2cConfig; +use embedded_io::ErrorKind; +use ft6336u_driver::{TouchData, TouchStatus, FT6336U}; + +use crate::{ + devices::{ + bus::{Bus, BusWrapper}, + gpio::{GeneralGpio, Level}, + i2c_core::block_i2c::BlockI2c, + Device, DeviceClass, DeviceData, DeviceId, DeviceManager, + }, + drivers::{DriverModule, InitDriver, Result as DriverResult}, + sync::{KernelDelay, SpinLock}, +}; +use alloc::{string::String, sync::Arc}; + +const FT6336U_CHIP_ID: u8 = 0x64; +const RESET_LOW_MS: u32 = 10; +const STARTUP_DELAY_MS: u32 = 300; +const CHIP_ID_RETRIES: usize = 5; +const CHIP_ID_RETRY_DELAY_MS: u32 = 50; +const FT6336U_DEVICE_NAME: &str = "ft6336u0"; +const FT6336U_DEVICE_MAJOR: usize = 240; +const FT6336U_DEVICE_MINOR: usize = 0; + +/// Binary report returned by `/dev/ft6336u0`. +/// +/// Layout (all 16-bit fields are little-endian): +/// - byte 0: format version (`1`) +/// - byte 1: active touch count (`0..=2`) +/// - bytes 2..=6: point 0 status, x, y +/// - bytes 7..=11: point 1 status, x, y +/// +/// Status values are `0 = released`, `1 = new touch`, `2 = continuing touch`. +pub const FT6336U_REPORT_SIZE: usize = 12; +const FT6336U_REPORT_VERSION: u8 = 1; + +pub struct Ft6336uDevice> { + touch: SpinLock>>>, +} + +impl> Ft6336uDevice { + fn new(touch: FT6336U>>) -> Self { + Self { + touch: SpinLock::new(touch), + } + } + + fn encode_report(data: TouchData, report: &mut [u8; FT6336U_REPORT_SIZE]) { + report[0] = FT6336U_REPORT_VERSION; + report[1] = data.touch_count.min(2); + + for (index, point) in data.points.iter().enumerate() { + let offset = 2 + index * 5; + report[offset] = match point.status { + TouchStatus::Release => 0, + TouchStatus::Touch => 1, + TouchStatus::Stream => 2, + }; + report[offset + 1..offset + 3].copy_from_slice(&point.x.to_le_bytes()); + report[offset + 3..offset + 5].copy_from_slice(&point.y.to_le_bytes()); + } + } +} + +impl> Device for Ft6336uDevice { + fn name(&self) -> String { + String::from(FT6336U_DEVICE_NAME) + } + + fn class(&self) -> DeviceClass { + DeviceClass::Char + } + + fn id(&self) -> DeviceId { + DeviceId::new(FT6336U_DEVICE_MAJOR, FT6336U_DEVICE_MINOR) + } + + fn read( + &self, + _pos: u64, + buf: &mut [u8], + _is_nonblocking: bool, + ) -> core::result::Result { + if buf.len() < FT6336U_REPORT_SIZE { + return Err(ErrorKind::InvalidInput); + } + + let data = self.touch.lock().scan().map_err(|error| { + log::warn!("Failed to scan FT6336U touch data: {:?}", error); + ErrorKind::Other + })?; + let mut report = [0u8; FT6336U_REPORT_SIZE]; + Self::encode_report(data, &mut report); + buf[..FT6336U_REPORT_SIZE].copy_from_slice(&report); + Ok(FT6336U_REPORT_SIZE) + } + + fn write( + &self, + _pos: u64, + _buf: &[u8], + _is_nonblocking: bool, + ) -> core::result::Result { + Err(ErrorKind::Unsupported) + } +} + +pub struct Ft6336uConfig { + pub rst: &'static G, +} + +impl, G: blueos_hal::gpio::OutputPin> InitDriver> + for Ft6336uConfig +{ + type Data = (); + fn init(self, bus: &Bus>) -> DriverResult { + use embedded_hal::{delay::DelayNs, digital::OutputPin}; + + let mut delay = KernelDelay; + let mut rst = GeneralGpio::new(self.rst, Some(Level::Low)); + delay.delay_ms(RESET_LOW_MS); + rst.set_high()?; + delay.delay_ms(STARTUP_DELAY_MS); + + let mut touch = FT6336U::new(bus.intf.clone()); + let mut last_chip_id = None; + for attempt in 0..CHIP_ID_RETRIES { + match touch.read_chip_id() { + Ok(FT6336U_CHIP_ID) => { + log::debug!("FT6336U chip ID: 0x{:X}", FT6336U_CHIP_ID); + let device = Arc::new(Ft6336uDevice::::new(touch)); + DeviceManager::get() + .register_device(String::from(FT6336U_DEVICE_NAME), device) + .map_err(|_| crate::error::code::EIO)?; + return Ok(()); + } + Ok(id) => last_chip_id = Some(id), + Err(error) if attempt + 1 == CHIP_ID_RETRIES => { + log::warn!("Failed to read FT6336U chip ID: {:?}", error); + } + Err(_) => {} + } + + if attempt + 1 < CHIP_ID_RETRIES { + delay.delay_ms(CHIP_ID_RETRY_DELAY_MS); + } + } + + log::warn!( + "Unexpected FT6336U chip ID: {:?}, library version: {:?}, firmware ID: {:?}, FocalTech ID: {:?}", + last_chip_id, + touch.read_library_version(), + touch.read_firmware_id(), + touch.read_focaltech_id(), + ); + Err(crate::error::code::EIO) + } +} + +pub struct Ft6336uDriverModule { + _marker: core::marker::PhantomData, +} + +impl Ft6336uDriverModule { + pub const fn new() -> Self { + Ft6336uDriverModule { + _marker: core::marker::PhantomData, + } + } +} + +impl, G: blueos_hal::gpio::OutputPin> + DriverModule> for Ft6336uDriverModule +{ + type Data = Ft6336uConfig; + fn probe(dev: &crate::devices::DeviceData) -> DriverResult { + match dev { + DeviceData::Native(native_dev) => { + if native_dev.is_attached() { + return Err(crate::error::code::ENODEV); + } + + if let Some(config) = native_dev.config::>() { + Ok(Ft6336uConfig:: { rst: config.rst }) + } else { + Err(crate::error::code::ENODEV) + } + } + _ => Err(crate::error::code::ENODEV), + } + } +} diff --git a/kernel/src/drivers/input/mod.rs b/kernel/src/drivers/input/mod.rs new file mode 100644 index 00000000..1415c222 --- /dev/null +++ b/kernel/src/drivers/input/mod.rs @@ -0,0 +1,15 @@ +// Copyright (c) 2026 vivo Mobile Communication Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod ft6336u; diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs index d14991be..a40e6dd8 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -17,6 +17,7 @@ use crate::devices::bus::{Bus, BusInterface}; pub(crate) mod ic; +pub(crate) mod input; pub(crate) mod lcd; pub(crate) mod msip; pub(crate) mod sensor; From d32ad74168c7c2f240e1ceda45bec9db30d4f99f Mon Sep 17 00:00:00 2001 From: xuchang-vivo <72209398@vivo.com> Date: Wed, 22 Jul 2026 17:34:12 +0800 Subject: [PATCH 07/13] add gpio --- .../config/seeed_xiao_esp32c3/debug/defconfig | 2 + kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 34 ++++- kernel/src/boot.rs | 2 + kernel/src/devices/gpio/mod.rs | 109 +++++++++++++- kernel/src/drivers/sensor/bme280.rs | 137 ++++++++++++++++-- kernel/src/vfs/path.rs | 9 +- 6 files changed, 276 insertions(+), 17 deletions(-) diff --git a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig index 6e5739bf..9f2a8137 100644 --- a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig +++ b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig @@ -33,3 +33,5 @@ CONFIG_ENABLE_VFS=y CONFIG_ENABLE_NET=n CONFIG_PROCFS=n CONFIG_UNITTEST_THREAD_NUM=16 + +CONFIG_LOG_LEVEL_DEBUG=y diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index ead8fc5f..2560a4db 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -119,6 +119,9 @@ const RTC_CNTL_WDTCONFIG0_REG: usize = RTC_CNTL_BASE + 0x90; const USB_SERIAL_JTAG_IRQ: Interrupt = Interrupt::new(26, USB_SERIAL_JTAG_INT_NUM); const SYSTIMER_TARGET0_IRQ: Interrupt = Interrupt::new(37, TARGET0_INT_NUM); +const LED_DEVICE_MAJOR: usize = 242; +const LED_B_DEVICE_MINOR: usize = 0; +const LED_R_DEVICE_MINOR: usize = 1; pub(crate) fn init() { assert!(!local_irq_enabled()); @@ -189,6 +192,10 @@ crate::define_peripheral! { blueos_driver::gpio::esp32_gpio::Esp32GpioOutputPin::new(21)), (lcd_cs, blueos_driver::gpio::esp32_gpio::Esp32GpioOutputPin, blueos_driver::gpio::esp32_gpio::Esp32GpioOutputPin::new(20)), + (led_b, blueos_driver::gpio::esp32_gpio::Esp32GpioOutputPin, + blueos_driver::gpio::esp32_gpio::Esp32GpioOutputPin::new(2)), + (led_r, blueos_driver::gpio::esp32_gpio::Esp32GpioOutputPin, + blueos_driver::gpio::esp32_gpio::Esp32GpioOutputPin::new(3)), } #[inline(always)] @@ -215,6 +222,8 @@ crate::define_pin_states!( (5, 1, false, true, false, 2, None, None, true, false), // lcd dc (4, 1, false, true, false, 2, None, None, true, false), // lcd rst (21, 1, false, true, false, 2, None, None, true, false), // touch rst + (2, 1, false, true, false, 2, None, None, true, false), // led blue + (3, 1, false, true, false, 2, None, None, true, false), // led red ); crate::define_bus! { @@ -324,7 +333,9 @@ pub(crate) fn init_i2c_bus() { } #[cfg(bme280)] - if let Ok(driver) = i2c_bus.probe_driver(&crate::drivers::sensor::bme280::Bme280DriverModule) { + if let Ok(driver) = + i2c_bus.probe_driver(&crate::drivers::sensor::bme280::Bme280DriverModule) + { if let Err(error) = driver.init(&i2c_bus) { log::warn!("Failed to initialize BME280 driver: {}", error); } @@ -335,3 +346,24 @@ pub(crate) fn init_i2c_bus() { log::warn!("Failed to initialize ESP32-C3 I2C0 bus"); } } + +pub(crate) fn init_gpio() { + crate::devices::gpio::GeneralGpio::new( + get_device!(led_b), + Some(crate::devices::gpio::Level::High), + ) + .register( + alloc::string::String::from("led_b"), + crate::devices::DeviceId::new(LED_DEVICE_MAJOR, LED_B_DEVICE_MINOR), + ) + .expect("Failed to register led_b"); + crate::devices::gpio::GeneralGpio::new( + get_device!(led_r), + Some(crate::devices::gpio::Level::High), + ) + .register( + alloc::string::String::from("led_r"), + crate::devices::DeviceId::new(LED_DEVICE_MAJOR, LED_R_DEVICE_MINOR), + ) + .expect("Failed to register led_r"); +} diff --git a/kernel/src/boot.rs b/kernel/src/boot.rs index 278ec733..c348cb9a 100644 --- a/kernel/src/boot.rs +++ b/kernel/src/boot.rs @@ -120,6 +120,8 @@ extern "C" fn init() { crate::boards::init_spi_bus(); #[cfg(i2c_core)] crate::boards::init_i2c_bus(); + #[cfg(gpio)] + crate::boards::init_gpio(); #[cfg(enable_vfs)] init_vfs(); diff --git a/kernel/src/devices/gpio/mod.rs b/kernel/src/devices/gpio/mod.rs index 42cdf1f1..b507ddb6 100644 --- a/kernel/src/devices/gpio/mod.rs +++ b/kernel/src/devices/gpio/mod.rs @@ -12,12 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::{ + devices::{Device, DeviceClass, DeviceId, DeviceManager}, + sync::SpinLock, +}; +use alloc::{string::String, sync::Arc}; +use embedded_io::ErrorKind; + pub struct GeneralGpio { inner: &'static T, + level: Option, } impl !Sync for GeneralGpio {} +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub(crate) enum Level { Low, High, @@ -25,19 +34,109 @@ pub(crate) enum Level { impl GeneralGpio { pub fn new(inner: &'static T, level: Option) -> Self { - let mut gpio = GeneralGpio { inner }; + let mut gpio = GeneralGpio { inner, level: None }; if let Some(level) = level { gpio.set_level(level).ok(); } gpio } + /// Register this GPIO as a character device. + /// + /// Reads return `0\n` or `1\n`; writes accept ASCII `0` or `1`, with + /// optional surrounding whitespace. + pub fn register(self, name: String, id: DeviceId) -> Result<(), ErrorKind> { + let device = Arc::new(GeneralGpioDevice::new(name.clone(), id, self)); + DeviceManager::get().register_device(name, device) + } + fn set_level(&mut self, level: Level) -> crate::drivers::Result<()> { match level { - Level::Low => self.inner.set_low().map_err(|_| crate::error::code::EIO), - Level::High => self.inner.set_high().map_err(|_| crate::error::code::EIO), + Level::Low => self.inner.set_low().map_err(|_| crate::error::code::EIO)?, + Level::High => self.inner.set_high().map_err(|_| crate::error::code::EIO)?, + }; + self.level = Some(level); + Ok(()) + } +} + +struct GeneralGpioDevice { + name: String, + id: DeviceId, + inner: &'static T, + level: SpinLock>, +} + +impl GeneralGpioDevice { + fn new(name: String, id: DeviceId, gpio: GeneralGpio) -> Self { + Self { + name, + id, + inner: gpio.inner, + level: SpinLock::new(gpio.level), } } + + fn set_level(&self, level: Level) -> Result<(), ErrorKind> { + let mut current_level = self.level.lock(); + match level { + Level::Low => self.inner.set_low().map_err(|_| ErrorKind::Other)?, + Level::High => self.inner.set_high().map_err(|_| ErrorKind::Other)?, + }; + *current_level = Some(level); + Ok(()) + } +} + +impl Device for GeneralGpioDevice { + fn name(&self) -> String { + self.name.clone() + } + + fn class(&self) -> DeviceClass { + DeviceClass::Char + } + + fn id(&self) -> DeviceId { + self.id + } + + fn read(&self, pos: u64, buf: &mut [u8], _is_nonblocking: bool) -> Result { + let level = (*self.level.lock()).ok_or(ErrorKind::Other)?; + let value = match level { + Level::Low => b"0\n", + Level::High => b"1\n", + }; + let pos = usize::try_from(pos).map_err(|_| ErrorKind::InvalidInput)?; + if pos >= value.len() { + return Ok(0); + } + + let len = buf.len().min(value.len() - pos); + buf[..len].copy_from_slice(&value[pos..pos + len]); + Ok(len) + } + + fn write(&self, _pos: u64, buf: &[u8], _is_nonblocking: bool) -> Result { + let mut values = buf + .iter() + .copied() + .filter(|byte| !byte.is_ascii_whitespace()); + let level = match values.next() { + Some(b'0') => Level::Low, + Some(b'1') => Level::High, + // Formatting helpers may send a trailing newline in a separate + // write. It has no GPIO value to apply, so accept it as a no-op. + None => return Ok(buf.len()), + _ => return Err(ErrorKind::InvalidInput), + }; + if values.next().is_some() { + return Err(ErrorKind::InvalidInput); + } + + self.set_level(level)?; + Ok(buf.len()) + } } #[cfg(use_embedded_hal_v1)] @@ -56,10 +155,10 @@ impl embedded_hal::digital::Error for crate::error::Error { #[cfg(use_embedded_hal_v1)] impl embedded_hal::digital::OutputPin for GeneralGpio { fn set_low(&mut self) -> Result<(), Self::Error> { - self.inner.set_low().map_err(|_| crate::error::code::EIO) + self.set_level(Level::Low) } fn set_high(&mut self) -> Result<(), Self::Error> { - self.inner.set_high().map_err(|_| crate::error::code::EIO) + self.set_level(Level::High) } } diff --git a/kernel/src/drivers/sensor/bme280.rs b/kernel/src/drivers/sensor/bme280.rs index 55325bbe..ef0e6ef3 100644 --- a/kernel/src/drivers/sensor/bme280.rs +++ b/kernel/src/drivers/sensor/bme280.rs @@ -14,23 +14,136 @@ use blueos_driver::i2c::I2cConfig; use blueos_hal::PlatPeri; -use blueos_infra::tinyarc::TinyArc; use bme280::i2c::BME280; +use embedded_hal::delay::DelayNs; +use embedded_io::ErrorKind; use crate::{ - devices::{bus::Bus, i2c_core::block_i2c::BlockI2c, DeviceData}, + devices::{ + bus::{Bus, BusWrapper}, + i2c_core::block_i2c::BlockI2c, + Device, DeviceClass, DeviceData, DeviceId, DeviceManager, + }, drivers::{DriverModule, InitDriver}, - sync::KernelDelay, + sync::{KernelDelay, SpinLock}, }; +use alloc::{string::String, sync::Arc}; + +const BME280_RESET_DELAY_MS: u32 = 2; +const BME280_SAFE_RESET_DELAY_MS: u32 = 10; +const BME280_DEVICE_NAME: &str = "bme2800"; +const BME280_DEVICE_MAJOR: usize = 241; +const BME280_DEVICE_MINOR: usize = 0; + +/// Binary measurement report returned by `/dev/bme2800`. +/// +/// Layout (all multi-byte fields are little-endian): +/// - byte 0: format version (`1`) +/// - bytes 1..=4: temperature in milli-degrees Celsius (`i32`) +/// - bytes 5..=8: pressure in pascals (`u32`) +/// - bytes 9..=12: relative humidity in thousandths of a percent (`u32`) +pub const BME280_REPORT_SIZE: usize = 13; +const BME280_REPORT_VERSION: u8 = 1; + +/// Extends the BME280 crate's nominal post-reset delay so the sensor has +/// enough time to copy its NVM calibration data before initialization reads it. +struct Bme280Delay(KernelDelay); + +impl DelayNs for Bme280Delay { + fn delay_ns(&mut self, ns: u32) { + self.0.delay_ns(ns); + } + + fn delay_ms(&mut self, ms: u32) { + let ms = if ms == BME280_RESET_DELAY_MS { + BME280_SAFE_RESET_DELAY_MS + } else { + ms + }; + self.0.delay_ms(ms); + } +} #[derive(Default)] pub struct Bme280Config { pub device_addr: u8, } -#[derive(Default)] -pub struct Bme280Driver { - device_addr: u8, +pub struct Bme280Device> { + sensor: SpinLock>>>, +} + +impl> Bme280Device { + fn new(sensor: BME280>>) -> Self { + Self { + sensor: SpinLock::new(sensor), + } + } + + fn encode_report( + temperature: f32, + pressure: f32, + humidity: f32, + report: &mut [u8; BME280_REPORT_SIZE], + ) { + let temperature_milli_celsius = (temperature * 1_000.0) as i32; + let pressure_pascals = pressure as u32; + let humidity_milli_percent = (humidity * 1_000.0) as u32; + + report[0] = BME280_REPORT_VERSION; + report[1..5].copy_from_slice(&temperature_milli_celsius.to_le_bytes()); + report[5..9].copy_from_slice(&pressure_pascals.to_le_bytes()); + report[9..13].copy_from_slice(&humidity_milli_percent.to_le_bytes()); + } +} + +impl> Device for Bme280Device { + fn name(&self) -> String { + String::from(BME280_DEVICE_NAME) + } + + fn class(&self) -> DeviceClass { + DeviceClass::Char + } + + fn id(&self) -> DeviceId { + DeviceId::new(BME280_DEVICE_MAJOR, BME280_DEVICE_MINOR) + } + + fn read( + &self, + _pos: u64, + buf: &mut [u8], + _is_nonblocking: bool, + ) -> core::result::Result { + if buf.len() < BME280_REPORT_SIZE { + return Err(ErrorKind::InvalidInput); + } + + let mut delay = Bme280Delay(KernelDelay); + let measurements = self.sensor.lock().measure(&mut delay).map_err(|error| { + log::warn!("Failed to measure BME280 data: {:?}", error); + ErrorKind::Other + })?; + let mut report = [0u8; BME280_REPORT_SIZE]; + Self::encode_report( + measurements.temperature, + measurements.pressure, + measurements.humidity, + &mut report, + ); + buf[..BME280_REPORT_SIZE].copy_from_slice(&report); + Ok(BME280_REPORT_SIZE) + } + + fn write( + &self, + _pos: u64, + _buf: &[u8], + _is_nonblocking: bool, + ) -> core::result::Result { + Err(ErrorKind::Unsupported) + } } impl Bme280Config { @@ -42,7 +155,7 @@ impl Bme280Config { impl> InitDriver> for Bme280Config { type Data = (); fn init(self, bus: &Bus>) -> crate::drivers::Result { - let mut delay = KernelDelay; + let mut delay = Bme280Delay(KernelDelay); let mut bme280 = match self.device_addr { 0x76 => BME280::new_primary(bus.intf.clone()), @@ -54,9 +167,15 @@ impl> InitDriver> for Bme280C .init(&mut delay) .map_err(|_| crate::error::code::EINVAL)?; + let device = Arc::new(Bme280Device::::new(bme280)); + DeviceManager::get() + .register_device(String::from(BME280_DEVICE_NAME), device) + .map_err(|_| crate::error::code::EIO)?; + log::info!( - "BME280 initialized successfully at address 0x{:X}", - self.device_addr + "BME280 initialized successfully at address 0x{:X} as /dev/{}", + self.device_addr, + BME280_DEVICE_NAME ); Ok(()) diff --git a/kernel/src/vfs/path.rs b/kernel/src/vfs/path.rs index ec6f2560..2a7e643f 100644 --- a/kernel/src/vfs/path.rs +++ b/kernel/src/vfs/path.rs @@ -122,8 +122,13 @@ pub fn open_path(path: &str, flags: i32, mode: mode_t) -> Result { } } }; - // resize to 0 if O_TRUNC is set - if open_flags.contains(OpenFlags::O_TRUNC) && access_mode.is_writable() { + // Linux applies O_TRUNC only to regular files. Device nodes and other + // special files ignore it, which allows shell redirection such as + // `echo 1 > /dev/led_b` to open a character device successfully. + if open_flags.contains(OpenFlags::O_TRUNC) + && access_mode.is_writable() + && dcache.type_().is_regular_file() + { dcache.inode().resize(0)?; } From 27f6eb93d31b62b478cd73b9cbbafad1531a3dd8 Mon Sep 17 00:00:00 2001 From: xuchang-vivo <72209398@vivo.com> Date: Wed, 29 Jul 2026 17:09:29 +0800 Subject: [PATCH 08/13] fix stack error --- kernel/src/boards/seeed_xiao_esp32c3/Kconfig | 26 ++++++++++++++++++-- kernel/src/boot.rs | 7 +++++- kernel/src/drivers/input/mod.rs | 1 + kernel/src/drivers/mod.rs | 1 + 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/kernel/src/boards/seeed_xiao_esp32c3/Kconfig b/kernel/src/boards/seeed_xiao_esp32c3/Kconfig index 0bc6e0a0..480c4de3 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/Kconfig +++ b/kernel/src/boards/seeed_xiao_esp32c3/Kconfig @@ -19,7 +19,27 @@ choice Set irq priority bits to 8. endchoice -choice +config LCD + bool "Enable LCD device" + default n + help + Enable LCD module + +config FT6336U + bool "Enable touch screen device" + default n + help + Enable touch screen + +config GPIO + bool "Enable gpio device" + default n + help + Enable gpio device + +if LCD + + choice prompt "LCD controller" default ST7789 @@ -32,7 +52,9 @@ choice bool "Enable LCD ST7796" help Enable the ST7796 LCD controller. -endchoice + endchoice + +endif config BME280 bool "BME280 Sensor" diff --git a/kernel/src/boot.rs b/kernel/src/boot.rs index c348cb9a..44af1d07 100644 --- a/kernel/src/boot.rs +++ b/kernel/src/boot.rs @@ -200,7 +200,12 @@ fn init_apps() { unsafe { let mut app = addr_of!(__bk_app_array_start); while app < addr_of!(__bk_app_array_end) { - thread::Builder::new(thread::Entry::C(*app)).start(); + let stack = + thread::Stack::from_size(blueos_kconfig::CONFIG_MAIN_THREAD_STACK_SIZE as usize) + .expect("Invalid main thread stack size"); + thread::Builder::new(thread::Entry::C(*app)) + .set_stack(stack) + .start(); app = app.offset(1); } } diff --git a/kernel/src/drivers/input/mod.rs b/kernel/src/drivers/input/mod.rs index 1415c222..ab19b5d4 100644 --- a/kernel/src/drivers/input/mod.rs +++ b/kernel/src/drivers/input/mod.rs @@ -12,4 +12,5 @@ // See the License for the specific language governing permissions and // limitations under the License. +#[cfg(touch_screen)] pub mod ft6336u; diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs index a40e6dd8..69c80503 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -18,6 +18,7 @@ use crate::devices::bus::{Bus, BusInterface}; pub(crate) mod ic; pub(crate) mod input; +#[cfg(lcd)] pub(crate) mod lcd; pub(crate) mod msip; pub(crate) mod sensor; From 0fe0dfd9d2baa0950a63be62c386b5a44be3df76 Mon Sep 17 00:00:00 2001 From: xuchang-vivo <72209398@vivo.com> Date: Thu, 30 Jul 2026 11:33:57 +0800 Subject: [PATCH 09/13] add gpio --- kconfig/config/seeed_xiao_esp32c3/debug/defconfig | 2 -- kernel/src/boot.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig index 9f2a8137..6e5739bf 100644 --- a/kconfig/config/seeed_xiao_esp32c3/debug/defconfig +++ b/kconfig/config/seeed_xiao_esp32c3/debug/defconfig @@ -33,5 +33,3 @@ CONFIG_ENABLE_VFS=y CONFIG_ENABLE_NET=n CONFIG_PROCFS=n CONFIG_UNITTEST_THREAD_NUM=16 - -CONFIG_LOG_LEVEL_DEBUG=y diff --git a/kernel/src/boot.rs b/kernel/src/boot.rs index 44af1d07..6c1a9f13 100644 --- a/kernel/src/boot.rs +++ b/kernel/src/boot.rs @@ -115,14 +115,12 @@ extern "C" fn init() { // initialize virtio virtio::init_virtio(&fdt); } - #[cfg(spi_core)] crate::boards::init_spi_bus(); #[cfg(i2c_core)] crate::boards::init_i2c_bus(); #[cfg(gpio)] crate::boards::init_gpio(); - #[cfg(enable_vfs)] init_vfs(); From 0e343cd79e46842747c9c28c6eb604c559cc88cc Mon Sep 17 00:00:00 2001 From: xuchang-vivo <72209398@vivo.com> Date: Fri, 31 Jul 2026 19:34:26 +0800 Subject: [PATCH 10/13] refactor spi core --- hal/src/lib.rs | 20 +----- kernel/src/boards/seeed_xiao_esp32c3/mod.rs | 2 + kernel/src/devices/bus/mod.rs | 7 +-- kernel/src/devices/framebuffer.rs | 49 ++++++++------- kernel/src/devices/gpio/mod.rs | 34 +++++++--- kernel/src/devices/i2c_core/block_i2c.rs | 24 ++----- kernel/src/devices/mod.rs | 15 +---- kernel/src/devices/spi_core/block_spi.rs | 70 ++------------------- kernel/src/devices/spi_core/mod.rs | 64 +++++++++++++++++++ kernel/src/drivers/lcd/mod.rs | 22 ++++--- kernel/src/drivers/lcd/st7789.rs | 2 + kernel/src/drivers/lcd/st7796.rs | 9 ++- 12 files changed, 152 insertions(+), 166 deletions(-) diff --git a/hal/src/lib.rs b/hal/src/lib.rs index 5e79d738..44a309d2 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -53,23 +53,9 @@ pub trait Configuration

{ /// Platform peripheral base trait /// -/// Defines the fundamental operations that all platform peripherals must implement. -/// This trait provides a unified interface for enabling and disabling peripheral devices -/// across different hardware platforms. -/// -/// All peripheral drivers should implement this trait to ensure consistent power -/// management and resource control capabilities. -/// -/// # Trait Bounds -/// -/// This trait requires implementations to be: -/// - `Sync` - Safe to share references between threads, Peripherals are often accessed from multiple contexts. -/// - `Send` - Safe to transfer ownership between threads, Peripherals always exists in system memory. -/// - `'static` - Lives for the entire duration of the program -/// -/// These bounds ensure that peripheral instances can be safely used in multi-threaded -/// environments and stored in static variables, which is common in embedded systems. -pub trait PlatPeri: Sync + Send + 'static { +/// Peripherals would be a global singleton, +/// and the HAL layer would provide a static reference to the peripheral. +pub trait PlatPeri: 'static { fn enable(&self) {} fn disable(&self) {} } diff --git a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs index 2560a4db..27eebb7d 100644 --- a/kernel/src/boards/seeed_xiao_esp32c3/mod.rs +++ b/kernel/src/boards/seeed_xiao_esp32c3/mod.rs @@ -235,6 +235,7 @@ crate::define_bus! { crate::drivers::lcd::st7789::St7789Config:: { rst: get_device!(rst_pin), dc: get_device!(dc_pin), + cs: Some(get_device!(lcd_cs)), } ), #[cfg(st7796)] @@ -242,6 +243,7 @@ crate::define_bus! { crate::drivers::lcd::st7796::St7796Config:: { rst: get_device!(rst_pin), dc: get_device!(dc_pin), + cs: Some(get_device!(lcd_cs)), orientation: mipidsi::options::Orientation::new() .rotate(mipidsi::options::Rotation::Deg0) .flip_horizontal(), diff --git a/kernel/src/devices/bus/mod.rs b/kernel/src/devices/bus/mod.rs index 6c74d190..2f3d64d0 100644 --- a/kernel/src/devices/bus/mod.rs +++ b/kernel/src/devices/bus/mod.rs @@ -33,12 +33,7 @@ pub struct Bus { unsafe impl Send for Bus {} unsafe impl Sync for Bus {} -pub trait BusInterface: Sync + Send + Sized { - type Region; - fn read_region(&self, region: Self::Region, buffer: &mut [u8]) -> crate::drivers::Result<()>; - - fn write_region(&self, region: Self::Region, data: &[u8]) -> crate::drivers::Result<()>; -} +pub trait BusInterface: Sized {} impl Bus { pub fn new(intf: B) -> Self { diff --git a/kernel/src/devices/framebuffer.rs b/kernel/src/devices/framebuffer.rs index 12044399..768f71f6 100644 --- a/kernel/src/devices/framebuffer.rs +++ b/kernel/src/devices/framebuffer.rs @@ -14,9 +14,9 @@ use crate::devices::{Device, DeviceClass, DeviceId, DeviceManager}; use alloc::{format, string::String, sync::Arc, vec, vec::Vec}; +use blueos_infra::tinyrwlock::RwLock; use embedded_io::ErrorKind; use libc::{FBIOGET_FSCREENINFO, FBIOGET_VSCREENINFO, FBIOPUT_VSCREENINFO}; -use spin::Mutex; /// Linux framebuffer character-device major number. pub const FRAMEBUFFER_MAJOR: usize = 29; @@ -171,7 +171,7 @@ unsafe fn store_user_variable_info( } /// Driver-facing framebuffer operations. -pub trait FramebufferOps: Send + Sync { +pub trait FramebufferOps { /// Return fixed framebuffer metadata. fn fixed_info(&self) -> Result; @@ -180,31 +180,34 @@ pub trait FramebufferOps: Send + Sync { /// Validate and apply a variable-info update, returning the effective state. fn set_variable_info( - &self, + &mut self, variable_info: &FramebufferVariableInfo, ) -> Result; /// Read framebuffer bytes starting at `offset`. - fn read_bytes(&self, offset: u64, buf: &mut [u8]) -> Result; + fn read_bytes(&mut self, offset: u64, buf: &mut [u8]) -> Result; /// Write framebuffer bytes starting at `offset`. - fn write_bytes(&self, offset: u64, buf: &[u8]) -> Result; + fn write_bytes(&mut self, offset: u64, buf: &[u8]) -> Result; /// Return the framebuffer byte length. fn byte_len(&self) -> Result; } /// Character-device wrapper for a framebuffer implementation. -pub struct FramebufferDevice { +pub struct FramebufferDevice { name: String, id: DeviceId, - ops: Arc, + ops: Arc>, } -impl FramebufferDevice { +unsafe impl Send for FramebufferDevice {} +unsafe impl Sync for FramebufferDevice {} + +impl FramebufferDevice { /// Create a framebuffer device named `fb{index}` with Linux framebuffer major `29`. #[must_use] - pub fn new(index: usize, ops: Arc) -> Self { + pub fn new(index: usize, ops: Arc>) -> Self { Self::with_id( format!("fb{index}"), DeviceId::new(FRAMEBUFFER_MAJOR, index), @@ -214,12 +217,12 @@ impl FramebufferDevice { /// Create a framebuffer device with an explicit name and device id. #[must_use] - pub fn with_id(name: String, id: DeviceId, ops: Arc) -> Self { + pub fn with_id(name: String, id: DeviceId, ops: Arc>) -> Self { Self { name, id, ops } } /// Register a framebuffer device named `fb{index}`. - pub fn register(index: usize, ops: Arc) -> Result<(), ErrorKind> { + pub fn register(index: usize, ops: Arc>) -> Result<(), ErrorKind> { Self::register_device(Arc::new(Self::new(index, ops))) } @@ -244,12 +247,12 @@ impl FramebufferDevice { /// Return fixed framebuffer metadata. pub fn fixed_info(&self) -> Result { - self.ops.fixed_info() + self.ops.read().fixed_info() } /// Return variable framebuffer metadata. pub fn variable_info(&self) -> Result { - self.ops.variable_info() + self.ops.read().variable_info() } /// Validate and apply a variable-info update, returning the effective state. @@ -257,11 +260,11 @@ impl FramebufferDevice { &self, variable_info: &FramebufferVariableInfo, ) -> Result { - self.ops.set_variable_info(variable_info) + self.ops.write().set_variable_info(variable_info) } } -impl Device for FramebufferDevice { +impl Device for FramebufferDevice { fn name(&self) -> String { self.name.clone() } @@ -279,7 +282,7 @@ impl Device for FramebufferDevice { return Ok(0); } - let byte_len = self.ops.byte_len()?; + let byte_len = self.ops.read().byte_len()?; if pos >= byte_len { return Ok(0); } @@ -287,7 +290,7 @@ impl Device for FramebufferDevice { let remaining = byte_len - pos; let read_len = usize::try_from(remaining).map_or(buf.len(), |remaining| remaining.min(buf.len())); - self.ops.read_bytes(pos, &mut buf[..read_len]) + self.ops.write().read_bytes(pos, &mut buf[..read_len]) } fn write(&self, pos: u64, buf: &[u8], _is_nonblocking: bool) -> Result { @@ -295,7 +298,7 @@ impl Device for FramebufferDevice { return Ok(0); } - let byte_len = self.ops.byte_len()?; + let byte_len = self.ops.read().byte_len()?; if pos >= byte_len { return Ok(0); } @@ -303,17 +306,17 @@ impl Device for FramebufferDevice { let remaining = byte_len - pos; let write_len = usize::try_from(remaining).map_or(buf.len(), |remaining| remaining.min(buf.len())); - self.ops.write_bytes(pos, &buf[..write_len]) + self.ops.write().write_bytes(pos, &buf[..write_len]) } fn ioctl(&self, request: u32, arg: usize) -> Result<(), ErrorKind> { match request { req if req == FBIOGET_FSCREENINFO => { - let fixed_info = self.ops.fixed_info()?; + let fixed_info = self.ops.read().fixed_info()?; unsafe { store_user_fixed_info(arg as *mut FramebufferFixedInfo, &fixed_info) } } req if req == FBIOGET_VSCREENINFO => { - let variable_info = self.ops.variable_info()?; + let variable_info = self.ops.read().variable_info()?; unsafe { store_user_variable_info(arg as *mut FramebufferVariableInfo, &variable_info) } @@ -321,7 +324,7 @@ impl Device for FramebufferDevice { req if req == FBIOPUT_VSCREENINFO => { let requested_info = unsafe { load_user_variable_info(arg as *const FramebufferVariableInfo)? }; - let effective_info = self.ops.set_variable_info(&requested_info)?; + let effective_info = self.ops.write().set_variable_info(&requested_info)?; unsafe { store_user_variable_info(arg as *mut FramebufferVariableInfo, &effective_info) } @@ -331,6 +334,6 @@ impl Device for FramebufferDevice { } fn capacity(&self) -> Result { - self.ops.byte_len() + self.ops.read().byte_len() } } diff --git a/kernel/src/devices/gpio/mod.rs b/kernel/src/devices/gpio/mod.rs index b507ddb6..2c6bafe7 100644 --- a/kernel/src/devices/gpio/mod.rs +++ b/kernel/src/devices/gpio/mod.rs @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +use core::cell::Cell; + use crate::{ devices::{Device, DeviceClass, DeviceId, DeviceManager}, sync::SpinLock, @@ -63,27 +65,39 @@ impl GeneralGpio { struct GeneralGpioDevice { name: String, id: DeviceId, - inner: &'static T, - level: SpinLock>, + inner: SpinLock<&'static T>, + level: Cell>, } +/// Safety: `GeneralGpioDevice` is safe to share between threads +/// because it uses a `SpinLock` to protect access to the +/// underlying GPIO pin, ensuring that only one thread can modify +/// the pin state at a time. The `level` field is a `Cell`, +/// which allows for interior mutability, but since it +/// is only accessed within the locked context, it does not +/// introduce data races. Therefore, it is safe to implement `Sync` +unsafe impl Sync for GeneralGpioDevice {} +unsafe impl Send for GeneralGpioDevice {} + impl GeneralGpioDevice { fn new(name: String, id: DeviceId, gpio: GeneralGpio) -> Self { Self { name, id, - inner: gpio.inner, - level: SpinLock::new(gpio.level), + inner: SpinLock::new(gpio.inner), + level: Cell::new(gpio.level), } } fn set_level(&self, level: Level) -> Result<(), ErrorKind> { - let mut current_level = self.level.lock(); + let l = self.inner.lock(); + let mut current_level = self.level.get(); match level { - Level::Low => self.inner.set_low().map_err(|_| ErrorKind::Other)?, - Level::High => self.inner.set_high().map_err(|_| ErrorKind::Other)?, + Level::Low => l.set_low().map_err(|_| ErrorKind::Other)?, + Level::High => l.set_high().map_err(|_| ErrorKind::Other)?, }; - *current_level = Some(level); + self.level.set(Some(level)); + drop(l); Ok(()) } } @@ -102,7 +116,8 @@ impl Device for GeneralGpioDevice { } fn read(&self, pos: u64, buf: &mut [u8], _is_nonblocking: bool) -> Result { - let level = (*self.level.lock()).ok_or(ErrorKind::Other)?; + let l = self.inner.lock(); + let level = self.level.get().ok_or(ErrorKind::Other)?; let value = match level { Level::Low => b"0\n", Level::High => b"1\n", @@ -114,6 +129,7 @@ impl Device for GeneralGpioDevice { let len = buf.len().min(value.len() - pos); buf[..len].copy_from_slice(&value[pos..pos + len]); + drop(l); Ok(len) } diff --git a/kernel/src/devices/i2c_core/block_i2c.rs b/kernel/src/devices/i2c_core/block_i2c.rs index 4ef4b366..2690d4b0 100644 --- a/kernel/src/devices/i2c_core/block_i2c.rs +++ b/kernel/src/devices/i2c_core/block_i2c.rs @@ -118,23 +118,7 @@ impl> BlockI2c { } } -impl> BusInterface for BlockI2c { - type Region = (bool, u8, bool); - - fn read_region(&self, region: Self::Region, buffer: &mut [u8]) -> crate::drivers::Result<()> { - let (first, address, last) = region; - self.read_bytes(address, buffer, first, last) - .map_err(|error| self.report_error("read", error))?; - Ok(()) - } - - fn write_region(&self, region: Self::Region, data: &[u8]) -> crate::drivers::Result<()> { - let (first, address, last) = region; - self.write_bytes(address, data, first, last) - .map_err(|error| self.report_error("write", error))?; - Ok(()) - } -} +impl> BusInterface for BlockI2c {} #[cfg(use_embedded_hal_v1)] impl> embedded_hal::i2c::ErrorType @@ -176,10 +160,12 @@ impl> embedded_hal::i2c::I2c for BusWrapp let last = operations.peek().is_none(); match operation { embedded_hal::i2c::Operation::Read(buf) => { - inner.read_region((first, address, last), buf)? + inner.read_bytes(address, buf, first, last) + .map_err(|error| inner.report_error("read", error))? } embedded_hal::i2c::Operation::Write(buf) => { - inner.write_region((first, address, last), buf)? + inner.write_bytes(address, buf, first, last) + .map_err(|error| inner.report_error("write", error))? } }; first = false; diff --git a/kernel/src/devices/mod.rs b/kernel/src/devices/mod.rs index c53272de..31f86773 100644 --- a/kernel/src/devices/mod.rs +++ b/kernel/src/devices/mod.rs @@ -423,20 +423,7 @@ mod tests { } struct DummyBus; - impl BusInterface for DummyBus { - type Region = u8; - fn read_region( - &self, - region: Self::Region, - buffer: &mut [u8], - ) -> crate::drivers::Result<()> { - Ok(()) - } - - fn write_region(&self, region: Self::Region, data: &[u8]) -> crate::drivers::Result<()> { - Ok(()) - } - } + impl BusInterface for DummyBus {} #[test] fn test_device_match() { diff --git a/kernel/src/devices/spi_core/block_spi.rs b/kernel/src/devices/spi_core/block_spi.rs index 772b86ce..f9e4ad9e 100644 --- a/kernel/src/devices/spi_core/block_spi.rs +++ b/kernel/src/devices/spi_core/block_spi.rs @@ -42,88 +42,28 @@ impl, G: blueos_hal::gpio::OutputPin> Blo self.cs.set_high().ok(); } - fn read(&mut self, words: &mut [u8]) -> Result<(), crate::error::Error> { + pub fn read(&mut self, words: &mut [u8]) -> Result<(), crate::error::Error> { self.inner.read(words).map_err(|_| crate::error::code::EIO) } - fn write(&mut self, words: &[u8]) -> Result<(), crate::error::Error> { + pub fn write(&mut self, words: &[u8]) -> Result<(), crate::error::Error> { self.inner.write(words).map_err(|_| crate::error::code::EIO) } - fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), crate::error::Error> { + pub fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), crate::error::Error> { self.inner .transfer(read, write) .map_err(|_| crate::error::code::EIO) } - fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), crate::error::Error> { + pub fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), crate::error::Error> { self.inner .write(words) .map_err(|_| crate::error::code::EIO)?; self.inner.read(words).map_err(|_| crate::error::code::EIO) } - - fn flush(&mut self) -> Result<(), crate::error::Error> { - Ok(()) - } } impl, G: blueos_hal::gpio::OutputPin> BusInterface for BlockSpi -{ - type Region = (); - - fn read_region(&self, region: Self::Region, buffer: &mut [u8]) -> crate::drivers::Result<()> { - todo!() - } - - fn write_region(&self, region: Self::Region, data: &[u8]) -> crate::drivers::Result<()> { - todo!() - } -} - -#[cfg(use_embedded_hal_v1)] -impl, G: blueos_hal::gpio::OutputPin> - embedded_hal::spi::ErrorType for BusWrapper> -{ - type Error = crate::error::Error; -} - -#[cfg(use_embedded_hal_v1)] -impl embedded_hal::spi::Error for crate::error::Error { - fn kind(&self) -> embedded_hal::spi::ErrorKind { - // FIXME: Map the error code to embedded_hal::spi::ErrorKind - embedded_hal::spi::ErrorKind::Other - } -} - -#[cfg(use_embedded_hal_v1)] -impl, G: blueos_hal::gpio::OutputPin> - embedded_hal::spi::SpiDevice for BusWrapper> -{ - fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> { - let mut inner = self.0.lock(); - inner.assert_cs(); - - let op_res = operations.iter_mut().try_for_each(|op| match op { - Operation::Read(buf) => inner.read(buf), - Operation::Write(buf) => inner.write(buf), - Operation::Transfer(read, write) => inner.transfer(read, write), - Operation::TransferInPlace(buf) => inner.transfer_in_place(buf), - Operation::DelayNs(ns) => { - use embedded_hal::delay::DelayNs; - inner.flush()?; - let mut kernel = KernelDelay; - kernel.delay_ns(*ns); - Ok(()) - } - }); - - let flush_res = inner.flush(); - inner.deassert_cs(); - op_res?; - flush_res?; - - Ok(()) - } -} +{} diff --git a/kernel/src/devices/spi_core/mod.rs b/kernel/src/devices/spi_core/mod.rs index 56d07130..12bb57ca 100644 --- a/kernel/src/devices/spi_core/mod.rs +++ b/kernel/src/devices/spi_core/mod.rs @@ -12,4 +12,68 @@ // See the License for the specific language governing permissions and // limitations under the License. +use blueos_driver::spi::SpiConfig; +use crate::devices::{bus::BusWrapper, spi_core::block_spi::BlockSpi}; +use embedded_hal::spi::Operation; +use crate::sync::KernelDelay; pub mod block_spi; + +pub struct ExclusiveSpiWithCs, G: blueos_hal::gpio::OutputPin> { + spi: BusWrapper>, + cs: &'static G, +} + +impl, G: blueos_hal::gpio::OutputPin> ExclusiveSpiWithCs { + pub fn new(spi: BusWrapper>, cs: &'static G) -> Self { + ExclusiveSpiWithCs { spi, cs } + } + + fn assert_cs(&self) { + self.cs.set_low().ok(); + } + + fn deassert_cs(&self) { + self.cs.set_high().ok(); + } +} + +#[cfg(use_embedded_hal_v1)] +impl embedded_hal::spi::Error for crate::error::Error { + fn kind(&self) -> embedded_hal::spi::ErrorKind { + // FIXME: Map the error code to embedded_hal::spi::ErrorKind + embedded_hal::spi::ErrorKind::Other + } +} + +#[cfg(use_embedded_hal_v1)] +impl, G: blueos_hal::gpio::OutputPin> + embedded_hal::spi::ErrorType for ExclusiveSpiWithCs +{ + type Error = crate::error::Error; +} + +#[cfg(use_embedded_hal_v1)] +impl, G: blueos_hal::gpio::OutputPin> + embedded_hal::spi::SpiDevice for ExclusiveSpiWithCs +{ + fn transaction(&mut self, operations: &mut [embedded_hal::spi::Operation<'_, u8>]) -> Result<(), Self::Error> { + let mut inner = self.spi.0.lock(); + self.assert_cs(); + + let op_res = operations.iter_mut().try_for_each(|op| match op { + Operation::Read(buf) => inner.read(buf), + Operation::Write(buf) => inner.write(buf), + Operation::Transfer(read, write) => inner.transfer(read, write), + Operation::TransferInPlace(buf) => inner.transfer_in_place(buf), + Operation::DelayNs(ns) => { + use embedded_hal::delay::DelayNs; + let mut kernel = KernelDelay; + kernel.delay_ns(*ns); + Ok(()) + } + }); + + self.deassert_cs(); + Ok(()) + } +} diff --git a/kernel/src/drivers/lcd/mod.rs b/kernel/src/drivers/lcd/mod.rs index 2faab8af..185204bf 100644 --- a/kernel/src/drivers/lcd/mod.rs +++ b/kernel/src/drivers/lcd/mod.rs @@ -19,7 +19,7 @@ use crate::devices::framebuffer::{ FramebufferVariableInfo, }; use alloc::sync::Arc; -use spin::Mutex; +use blueos_infra::tinyrwlock::RwLock; // FIXME: Only support 16-bit RGB565 format for now, need to support more formats in the future. const LCD_BITS_PER_PIXEL: u32 = 16; @@ -35,7 +35,7 @@ pub mod st7796; pub struct LcdFramebuffer { width: u32, height: u32, - display: Mutex, + display: T, } impl LcdFramebuffer { @@ -46,14 +46,16 @@ impl LcdFramebuffer { fn byte_len(&self) -> u32 { self.line_length() * self.height } +} +impl LcdFramebuffer { fn register_lcd(lcd: T, width: u32, height: u32) -> Result<(), embedded_io::ErrorKind> { static INDEX: AtomicUsize = AtomicUsize::new(0); - let fb = Arc::new(LcdFramebuffer:: { + let fb = Arc::new(RwLock::new(LcdFramebuffer:: { width, height, - display: Mutex::new(lcd), - }); + display: lcd, + })); FramebufferDevice::register(INDEX.load(core::sync::atomic::Ordering::Relaxed), fb)?; INDEX.fetch_add(1, core::sync::atomic::Ordering::SeqCst); Ok(()) @@ -105,17 +107,17 @@ impl FramebufferOps for LcdFramebuffer { } fn set_variable_info( - &self, + &mut self, variable_info: &crate::devices::framebuffer::FramebufferVariableInfo, ) -> Result { todo!() } - fn read_bytes(&self, offset: u64, buf: &mut [u8]) -> Result { + fn read_bytes(&mut self, offset: u64, buf: &mut [u8]) -> Result { todo!() } - fn write_bytes(&self, offset: u64, buf: &[u8]) -> Result { + fn write_bytes(&mut self, offset: u64, buf: &[u8]) -> Result { if offset % u64::from(LCD_BYTES_PER_PIXEL) != 0 || buf.len() % LCD_BYTES_PER_PIXEL as usize != 0 { @@ -125,7 +127,7 @@ impl FramebufferOps for LcdFramebuffer { let mut pixel_index = u32::try_from(offset / u64::from(LCD_BYTES_PER_PIXEL)) .map_err(|_| embedded_io::ErrorKind::InvalidInput)?; let mut written = 0; - let mut display = self.display.lock(); + let mut display = &mut self.display; while written < buf.len() { let row = pixel_index / self.width; @@ -178,6 +180,6 @@ fn lcd_error_to_io_error(error: LcdError) -> embedded_io::ErrorKind { } } -pub trait Lcd: Send + 'static { +pub trait Lcd { fn draw_area(&mut self, area: DrawArea, color: &[u8]) -> Result<(), LcdError>; } diff --git a/kernel/src/drivers/lcd/st7789.rs b/kernel/src/drivers/lcd/st7789.rs index a91ce0d3..9bc7699a 100644 --- a/kernel/src/drivers/lcd/st7789.rs +++ b/kernel/src/drivers/lcd/st7789.rs @@ -33,6 +33,7 @@ use mipidsi::{ pub struct St7789Config { pub rst: &'static G, pub dc: &'static G, + pub cs: Option<&'static G>, } static mut BUFFER: [u8; 512] = [0; 512]; @@ -91,6 +92,7 @@ impl, G: blueos_hal::gpio::OutputPin> Ok(St7789Config:: { rst: config.rst, dc: config.dc, + cs: config.cs, }) } else { Err(crate::error::code::ENODEV) diff --git a/kernel/src/drivers/lcd/st7796.rs b/kernel/src/drivers/lcd/st7796.rs index 045dbc3a..cbb93006 100644 --- a/kernel/src/drivers/lcd/st7796.rs +++ b/kernel/src/drivers/lcd/st7796.rs @@ -16,7 +16,7 @@ use crate::{ devices::{ bus::{Bus, BusWrapper}, gpio::{GeneralGpio, Level}, - spi_core::block_spi::BlockSpi, + spi_core::{block_spi::BlockSpi, ExclusiveSpiWithCs}, DeviceData, }, drivers::{DriverModule, InitDriver}, @@ -34,6 +34,7 @@ use mipidsi::{ pub struct St7796Config { pub rst: &'static G, pub dc: &'static G, + pub cs: Option<&'static G>, pub orientation: Orientation, } @@ -54,6 +55,7 @@ impl, G: blueos_hal::gpio::OutputPin> let orientation = self.orientation; let spi_device = bus.intf.clone(); + let spi_device = ExclusiveSpiWithCs::new(spi_device, self.cs.unwrap()); let di = SpiInterface::new(spi_device, dc, unsafe { &mut BUFFER }); let display = Builder::new(ST7796, di) .reset_pin(rst) @@ -98,6 +100,7 @@ impl, G: blueos_hal::gpio::OutputPin> Ok(St7796Config:: { rst: config.rst, dc: config.dc, + cs: config.cs, orientation: config.orientation, }) } else { @@ -111,10 +114,10 @@ impl, G: blueos_hal::gpio::OutputPin> impl< G1: blueos_hal::gpio::OutputPin, - G2: embedded_hal::digital::OutputPin + Send + 'static, + G2: embedded_hal::digital::OutputPin + 'static, T: blueos_hal::spi::Spi, > super::Lcd - for Display>, G2>, ST7796, GeneralGpio> + for Display, G2>, ST7796, GeneralGpio> { fn draw_area(&mut self, area: super::DrawArea, color: &[u8]) -> Result<(), super::LcdError> { let area_width = area From f73cb99ff29fb1ef46bc1dd40785d765838c2ca0 Mon Sep 17 00:00:00 2001 From: xuchang-vivo <72209398@vivo.com> Date: Mon, 10 Aug 2026 21:58:10 +0800 Subject: [PATCH 11/13] fix quote --- macro/BUILD.gn | 2 +- test_harness/BUILD.gn | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/macro/BUILD.gn b/macro/BUILD.gn index 614873ec..c6181342 100644 --- a/macro/BUILD.gn +++ b/macro/BUILD.gn @@ -22,7 +22,7 @@ build_rust("blueos_macro") { deps = [] proc_macro_deps = [ "//external/vendor/proc-macro2-1.0.103:proc_macro2", - "//external/vendor/quote-1.0.46:quote", + "//external/vendor/quote-1.0.41:quote", "//external/vendor/syn-2.0.108:syn", ] features = [] diff --git a/test_harness/BUILD.gn b/test_harness/BUILD.gn index ddc0328d..c57e7ac2 100644 --- a/test_harness/BUILD.gn +++ b/test_harness/BUILD.gn @@ -24,7 +24,7 @@ build_rust("blueos_test_macro") { ] deps = [ "//external/vendor/proc-macro2-1.0.103:proc_macro2", - "//external/vendor/quote-1.0.46:quote", + "//external/vendor/quote-1.0.41:quote", "//external/vendor/syn-2.0.108:syn", ] } From 1cf58fadd9c3614197c916e72ee6282bced802dc Mon Sep 17 00:00:00 2001 From: xuchang-vivo <72209398@vivo.com> Date: Mon, 10 Aug 2026 22:06:36 +0800 Subject: [PATCH 12/13] fix kconfig typo --- kernel/src/drivers/input/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/src/drivers/input/mod.rs b/kernel/src/drivers/input/mod.rs index ab19b5d4..78018b93 100644 --- a/kernel/src/drivers/input/mod.rs +++ b/kernel/src/drivers/input/mod.rs @@ -12,5 +12,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[cfg(touch_screen)] +#[cfg(ft6336u)] pub mod ft6336u; From e8d388ef90e7df4cc0f038df3873ed13be4c0cbc Mon Sep 17 00:00:00 2001 From: xuchang-vivo <72209398@vivo.com> Date: Tue, 11 Aug 2026 10:18:08 +0800 Subject: [PATCH 13/13] fix fmt --- hal/src/lib.rs | 2 +- kernel/src/devices/gpio/mod.rs | 12 +++++----- kernel/src/devices/i2c_core/block_i2c.rs | 14 +++++------- kernel/src/devices/spi_core/block_spi.rs | 3 ++- kernel/src/devices/spi_core/mod.rs | 28 ++++++++++++++++-------- 5 files changed, 34 insertions(+), 25 deletions(-) diff --git a/hal/src/lib.rs b/hal/src/lib.rs index 44a309d2..1a1123f0 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -53,7 +53,7 @@ pub trait Configuration

{ /// Platform peripheral base trait /// -/// Peripherals would be a global singleton, +/// Peripherals would be a global singleton, /// and the HAL layer would provide a static reference to the peripheral. pub trait PlatPeri: 'static { fn enable(&self) {} diff --git a/kernel/src/devices/gpio/mod.rs b/kernel/src/devices/gpio/mod.rs index 2c6bafe7..0b76b52c 100644 --- a/kernel/src/devices/gpio/mod.rs +++ b/kernel/src/devices/gpio/mod.rs @@ -69,12 +69,12 @@ struct GeneralGpioDevice { level: Cell>, } -/// Safety: `GeneralGpioDevice` is safe to share between threads -/// because it uses a `SpinLock` to protect access to the -/// underlying GPIO pin, ensuring that only one thread can modify -/// the pin state at a time. The `level` field is a `Cell`, -/// which allows for interior mutability, but since it -/// is only accessed within the locked context, it does not +/// Safety: `GeneralGpioDevice` is safe to share between threads +/// because it uses a `SpinLock` to protect access to the +/// underlying GPIO pin, ensuring that only one thread can modify +/// the pin state at a time. The `level` field is a `Cell`, +/// which allows for interior mutability, but since it +/// is only accessed within the locked context, it does not /// introduce data races. Therefore, it is safe to implement `Sync` unsafe impl Sync for GeneralGpioDevice {} unsafe impl Send for GeneralGpioDevice {} diff --git a/kernel/src/devices/i2c_core/block_i2c.rs b/kernel/src/devices/i2c_core/block_i2c.rs index 2690d4b0..d0b1479f 100644 --- a/kernel/src/devices/i2c_core/block_i2c.rs +++ b/kernel/src/devices/i2c_core/block_i2c.rs @@ -159,14 +159,12 @@ impl> embedded_hal::i2c::I2c for BusWrapp while let Some(operation) = operations.next() { let last = operations.peek().is_none(); match operation { - embedded_hal::i2c::Operation::Read(buf) => { - inner.read_bytes(address, buf, first, last) - .map_err(|error| inner.report_error("read", error))? - } - embedded_hal::i2c::Operation::Write(buf) => { - inner.write_bytes(address, buf, first, last) - .map_err(|error| inner.report_error("write", error))? - } + embedded_hal::i2c::Operation::Read(buf) => inner + .read_bytes(address, buf, first, last) + .map_err(|error| inner.report_error("read", error))?, + embedded_hal::i2c::Operation::Write(buf) => inner + .write_bytes(address, buf, first, last) + .map_err(|error| inner.report_error("write", error))?, }; first = false; } diff --git a/kernel/src/devices/spi_core/block_spi.rs b/kernel/src/devices/spi_core/block_spi.rs index f9e4ad9e..cdd0788a 100644 --- a/kernel/src/devices/spi_core/block_spi.rs +++ b/kernel/src/devices/spi_core/block_spi.rs @@ -66,4 +66,5 @@ impl, G: blueos_hal::gpio::OutputPin> Blo impl, G: blueos_hal::gpio::OutputPin> BusInterface for BlockSpi -{} +{ +} diff --git a/kernel/src/devices/spi_core/mod.rs b/kernel/src/devices/spi_core/mod.rs index 12bb57ca..eefc1375 100644 --- a/kernel/src/devices/spi_core/mod.rs +++ b/kernel/src/devices/spi_core/mod.rs @@ -12,18 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::{ + devices::{bus::BusWrapper, spi_core::block_spi::BlockSpi}, + sync::KernelDelay, +}; use blueos_driver::spi::SpiConfig; -use crate::devices::{bus::BusWrapper, spi_core::block_spi::BlockSpi}; use embedded_hal::spi::Operation; -use crate::sync::KernelDelay; pub mod block_spi; -pub struct ExclusiveSpiWithCs, G: blueos_hal::gpio::OutputPin> { +pub struct ExclusiveSpiWithCs< + T: blueos_hal::spi::Spi, + G: blueos_hal::gpio::OutputPin, +> { spi: BusWrapper>, cs: &'static G, } -impl, G: blueos_hal::gpio::OutputPin> ExclusiveSpiWithCs { +impl, G: blueos_hal::gpio::OutputPin> + ExclusiveSpiWithCs +{ pub fn new(spi: BusWrapper>, cs: &'static G) -> Self { ExclusiveSpiWithCs { spi, cs } } @@ -46,17 +53,20 @@ impl embedded_hal::spi::Error for crate::error::Error { } #[cfg(use_embedded_hal_v1)] -impl, G: blueos_hal::gpio::OutputPin> - embedded_hal::spi::ErrorType for ExclusiveSpiWithCs +impl, G: blueos_hal::gpio::OutputPin> + embedded_hal::spi::ErrorType for ExclusiveSpiWithCs { type Error = crate::error::Error; } #[cfg(use_embedded_hal_v1)] -impl, G: blueos_hal::gpio::OutputPin> - embedded_hal::spi::SpiDevice for ExclusiveSpiWithCs +impl, G: blueos_hal::gpio::OutputPin> + embedded_hal::spi::SpiDevice for ExclusiveSpiWithCs { - fn transaction(&mut self, operations: &mut [embedded_hal::spi::Operation<'_, u8>]) -> Result<(), Self::Error> { + fn transaction( + &mut self, + operations: &mut [embedded_hal::spi::Operation<'_, u8>], + ) -> Result<(), Self::Error> { let mut inner = self.spi.0.lock(); self.assert_cs();