更新rtt成功
This commit is contained in:
parent
3847fcb4e0
commit
c431b61900
152
.config
152
.config
@ -4,10 +4,126 @@ CONFIG_BOARD_STM32F407_SPARK=y
|
||||
#
|
||||
# RT-Thread Kernel
|
||||
#
|
||||
|
||||
#
|
||||
# klibc options
|
||||
#
|
||||
|
||||
#
|
||||
# rt_vsnprintf options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_LIBC_VSNPRINTF is not set
|
||||
CONFIG_RT_KLIBC_USING_VSNPRINTF_LONGLONG=y
|
||||
CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD=y
|
||||
CONFIG_RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS=y
|
||||
CONFIG_RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS=y
|
||||
CONFIG_RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER=y
|
||||
CONFIG_RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER=y
|
||||
# CONFIG_RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS is not set
|
||||
CONFIG_RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE=32
|
||||
CONFIG_RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE=32
|
||||
CONFIG_RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION=6
|
||||
CONFIG_RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL=9
|
||||
CONFIG_RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS=4
|
||||
# end of rt_vsnprintf options
|
||||
|
||||
#
|
||||
# rt_vsscanf options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_LIBC_VSSCANF is not set
|
||||
# end of rt_vsscanf options
|
||||
|
||||
#
|
||||
# rt_memset options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_USER_MEMSET is not set
|
||||
# CONFIG_RT_KLIBC_USING_LIBC_MEMSET is not set
|
||||
# CONFIG_RT_KLIBC_USING_TINY_MEMSET is not set
|
||||
# end of rt_memset options
|
||||
|
||||
#
|
||||
# rt_memcpy options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_USER_MEMCPY is not set
|
||||
# CONFIG_RT_KLIBC_USING_LIBC_MEMCPY is not set
|
||||
# CONFIG_RT_KLIBC_USING_TINY_MEMCPY is not set
|
||||
# end of rt_memcpy options
|
||||
|
||||
#
|
||||
# rt_memmove options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_USER_MEMMOVE is not set
|
||||
# CONFIG_RT_KLIBC_USING_LIBC_MEMMOVE is not set
|
||||
# end of rt_memmove options
|
||||
|
||||
#
|
||||
# rt_memcmp options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_USER_MEMCMP is not set
|
||||
# CONFIG_RT_KLIBC_USING_LIBC_MEMCMP is not set
|
||||
# end of rt_memcmp options
|
||||
|
||||
#
|
||||
# rt_strstr options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_USER_STRSTR is not set
|
||||
# CONFIG_RT_KLIBC_USING_LIBC_STRSTR is not set
|
||||
# end of rt_strstr options
|
||||
|
||||
#
|
||||
# rt_strcasecmp options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_USER_STRCASECMP is not set
|
||||
# end of rt_strcasecmp options
|
||||
|
||||
#
|
||||
# rt_strncpy options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_USER_STRNCPY is not set
|
||||
# CONFIG_RT_KLIBC_USING_LIBC_STRNCPY is not set
|
||||
# end of rt_strncpy options
|
||||
|
||||
#
|
||||
# rt_strcpy options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_USER_STRCPY is not set
|
||||
# CONFIG_RT_KLIBC_USING_LIBC_STRCPY is not set
|
||||
# end of rt_strcpy options
|
||||
|
||||
#
|
||||
# rt_strncmp options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_USER_STRNCMP is not set
|
||||
# CONFIG_RT_KLIBC_USING_LIBC_STRNCMP is not set
|
||||
# end of rt_strncmp options
|
||||
|
||||
#
|
||||
# rt_strcmp options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_USER_STRCMP is not set
|
||||
# CONFIG_RT_KLIBC_USING_LIBC_STRCMP is not set
|
||||
# end of rt_strcmp options
|
||||
|
||||
#
|
||||
# rt_strlen options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_USER_STRLEN is not set
|
||||
# CONFIG_RT_KLIBC_USING_LIBC_STRLEN is not set
|
||||
# end of rt_strlen options
|
||||
|
||||
#
|
||||
# rt_strnlen options
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_USER_STRNLEN is not set
|
||||
# end of rt_strnlen options
|
||||
|
||||
# CONFIG_RT_UTEST_TC_USING_KLIBC is not set
|
||||
# end of klibc options
|
||||
|
||||
CONFIG_RT_NAME_MAX=8
|
||||
# CONFIG_RT_USING_ARCH_DATA_TYPE is not set
|
||||
# CONFIG_RT_USING_SMART is not set
|
||||
# CONFIG_RT_USING_NANO is not set
|
||||
# CONFIG_RT_USING_SMART is not set
|
||||
# CONFIG_RT_USING_AMP is not set
|
||||
# CONFIG_RT_USING_SMP is not set
|
||||
CONFIG_RT_CPUS_NR=1
|
||||
@ -17,6 +133,7 @@ CONFIG_RT_THREAD_PRIORITY_32=y
|
||||
# CONFIG_RT_THREAD_PRIORITY_256 is not set
|
||||
CONFIG_RT_THREAD_PRIORITY_MAX=32
|
||||
CONFIG_RT_TICK_PER_SECOND=1000
|
||||
CONFIG_RT_USING_OVERFLOW_CHECK=y
|
||||
CONFIG_RT_USING_HOOK=y
|
||||
CONFIG_RT_HOOK_USING_FUNC_PTR=y
|
||||
# CONFIG_RT_USING_HOOKLIST is not set
|
||||
@ -30,25 +147,17 @@ CONFIG_RT_TIMER_THREAD_STACK_SIZE=512
|
||||
# CONFIG_RT_USING_CPU_USAGE_TRACER is not set
|
||||
|
||||
#
|
||||
# kservice optimization
|
||||
# kservice options
|
||||
#
|
||||
# CONFIG_RT_USING_TINY_FFS is not set
|
||||
# end of kservice optimization
|
||||
|
||||
#
|
||||
# klibc optimization
|
||||
#
|
||||
# CONFIG_RT_KLIBC_USING_STDLIB is not set
|
||||
# CONFIG_RT_KLIBC_USING_TINY_SIZE is not set
|
||||
# CONFIG_RT_KLIBC_USING_PRINTF_LONGLONG is not set
|
||||
# end of klibc optimization
|
||||
# end of kservice options
|
||||
|
||||
CONFIG_RT_USING_DEBUG=y
|
||||
CONFIG_RT_DEBUGING_ASSERT=y
|
||||
CONFIG_RT_DEBUGING_COLOR=y
|
||||
CONFIG_RT_DEBUGING_CONTEXT=y
|
||||
# CONFIG_RT_DEBUGING_AUTO_INIT is not set
|
||||
CONFIG_RT_USING_OVERFLOW_CHECK=y
|
||||
# CONFIG_RT_USING_CI_ACTION is not set
|
||||
|
||||
#
|
||||
# Inter-Thread communication
|
||||
@ -83,7 +192,6 @@ CONFIG_RT_USING_DEVICE=y
|
||||
# CONFIG_RT_USING_DEVICE_OPS is not set
|
||||
# CONFIG_RT_USING_INTERRUPT_INFO is not set
|
||||
# CONFIG_RT_USING_THREADSAFE_PRINTF is not set
|
||||
# CONFIG_RT_USING_SCHED_THREAD_CTX is not set
|
||||
CONFIG_RT_USING_CONSOLE=y
|
||||
CONFIG_RT_CONSOLEBUF_SIZE=128
|
||||
CONFIG_RT_CONSOLE_DEVICE_NAME="uart1"
|
||||
@ -172,8 +280,7 @@ CONFIG_RT_USING_DFS_ROMFS=y
|
||||
# end of DFS: device virtual file system
|
||||
|
||||
CONFIG_RT_USING_FAL=y
|
||||
CONFIG_FAL_DEBUG_CONFIG=y
|
||||
CONFIG_FAL_DEBUG=1
|
||||
CONFIG_FAL_USING_DEBUG=y
|
||||
CONFIG_FAL_PART_HAS_TABLE_CFG=y
|
||||
CONFIG_FAL_USING_SFUD_PORT=y
|
||||
CONFIG_FAL_USING_NOR_FLASH_DEV_NAME="norflash0"
|
||||
@ -193,6 +300,7 @@ CONFIG_RT_USING_SERIAL_V1=y
|
||||
# CONFIG_RT_USING_SERIAL_V2 is not set
|
||||
CONFIG_RT_SERIAL_USING_DMA=y
|
||||
CONFIG_RT_SERIAL_RB_BUFSZ=64
|
||||
# CONFIG_RT_USING_SERIAL_BYPASS is not set
|
||||
# CONFIG_RT_USING_CAN is not set
|
||||
# CONFIG_RT_USING_CPUTIME is not set
|
||||
CONFIG_RT_USING_I2C=y
|
||||
@ -201,6 +309,7 @@ CONFIG_RT_USING_I2C_BITOPS=y
|
||||
# CONFIG_RT_I2C_BITOPS_DEBUG is not set
|
||||
# CONFIG_RT_USING_SOFT_I2C is not set
|
||||
# CONFIG_RT_USING_PHY is not set
|
||||
# CONFIG_RT_USING_PHY_V2 is not set
|
||||
CONFIG_RT_USING_ADC=y
|
||||
# CONFIG_RT_USING_DAC is not set
|
||||
# CONFIG_RT_USING_NULL is not set
|
||||
@ -222,6 +331,7 @@ CONFIG_RT_MMCSD_STACK_SIZE=1024
|
||||
CONFIG_RT_MMCSD_THREAD_PREORITY=22
|
||||
CONFIG_RT_MMCSD_MAX_PARTITION=16
|
||||
# CONFIG_RT_SDIO_DEBUG is not set
|
||||
# CONFIG_RT_USING_SDHCI is not set
|
||||
CONFIG_RT_USING_SPI=y
|
||||
# CONFIG_RT_USING_SPI_BITOPS is not set
|
||||
# CONFIG_RT_USING_QSPI is not set
|
||||
@ -270,6 +380,15 @@ CONFIG_RT_WLAN_WORKQUEUE_THREAD_NAME="wlan"
|
||||
CONFIG_RT_WLAN_WORKQUEUE_THREAD_SIZE=2048
|
||||
CONFIG_RT_WLAN_WORKQUEUE_THREAD_PRIO=15
|
||||
# CONFIG_RT_WLAN_DEBUG is not set
|
||||
CONFIG_RT_USING_BLK=y
|
||||
|
||||
#
|
||||
# Partition Types
|
||||
#
|
||||
CONFIG_RT_BLK_PARTITION_DFS=y
|
||||
CONFIG_RT_BLK_PARTITION_EFI=y
|
||||
# end of Partition Types
|
||||
|
||||
# CONFIG_RT_USING_VIRTIO is not set
|
||||
CONFIG_RT_USING_PIN=y
|
||||
# CONFIG_RT_USING_KTIME is not set
|
||||
@ -355,6 +474,7 @@ CONFIG_NETDEV_USING_IFCONFIG=y
|
||||
CONFIG_NETDEV_USING_PING=y
|
||||
CONFIG_NETDEV_USING_NETSTAT=y
|
||||
CONFIG_NETDEV_USING_AUTO_DEFAULT=y
|
||||
# CONFIG_NETDEV_USING_LINK_STATUS_CALLBACK is not set
|
||||
# CONFIG_NETDEV_USING_IPV6 is not set
|
||||
CONFIG_NETDEV_IPV4=1
|
||||
CONFIG_NETDEV_IPV6=0
|
||||
@ -418,6 +538,7 @@ CONFIG_LWIP_NETIF_LOOPBACK=0
|
||||
# CONFIG_RT_LWIP_USING_HW_CHECKSUM is not set
|
||||
CONFIG_RT_LWIP_USING_PING=y
|
||||
# CONFIG_LWIP_USING_DHCPD is not set
|
||||
# CONFIG_RT_LWIP_ENABLE_USER_HOOKS is not set
|
||||
# CONFIG_RT_LWIP_DEBUG is not set
|
||||
CONFIG_RT_USING_AT=y
|
||||
CONFIG_AT_DEBUG=y
|
||||
@ -955,6 +1076,7 @@ CONFIG_PKG_PERF_COUNTER_PATH="/packages/system/perf_counter"
|
||||
CONFIG_PKG_USING_PERF_COUNTER_V2241=y
|
||||
# CONFIG_PKG_USING_PERF_COUNTER_LATEST_VERSION is not set
|
||||
CONFIG_PKG_PERF_COUNTER_VER="v2.2.4.1"
|
||||
CONFIG_FAL_DEBUG_CONFIG=y
|
||||
# CONFIG_PKG_USING_FILEX is not set
|
||||
# CONFIG_PKG_USING_LEVELX is not set
|
||||
# CONFIG_PKG_USING_FLASHDB is not set
|
||||
|
486
.vscode/c_cpp_properties.json
vendored
486
.vscode/c_cpp_properties.json
vendored
@ -4,12 +4,379 @@
|
||||
"name": "rt-thread",
|
||||
"defines": [
|
||||
"RT_USING_LIBC",
|
||||
"RT_USING_NEWLIBC",
|
||||
"STM32F407xx",
|
||||
"USE_HAL_DRIVER",
|
||||
"_POSIX_C_SOURCE=1",
|
||||
"__RTTHREAD__",
|
||||
"__perf_counter_printf__=rt_kprintf"
|
||||
"__STDC_LIMIT_MACROS",
|
||||
"__CLK_TCK=RT_TICK_PER_SECOND",
|
||||
"STM32F407xx",
|
||||
"RT_USING_ARMLIBC",
|
||||
"__alignof__(x)=",
|
||||
"__asm(x)=",
|
||||
"__asm__(x)=",
|
||||
"__forceinline=",
|
||||
"__restrict=",
|
||||
"__volatile__=",
|
||||
"__inline=",
|
||||
"__inline__=",
|
||||
"__declspec(x)=",
|
||||
"__attribute__(x)=",
|
||||
"__nonnull__(x)=",
|
||||
"__unaligned=",
|
||||
"__promise(x)=",
|
||||
"__irq=",
|
||||
"__swi=",
|
||||
"__weak=",
|
||||
"__register=",
|
||||
"__pure=",
|
||||
"__value_in_regs=",
|
||||
"__breakpoint(x)=",
|
||||
"__current_pc()=0U",
|
||||
"__current_sp()=0U",
|
||||
"__disable_fiq()=",
|
||||
"__disable_irq()=",
|
||||
"__enable_fiq()=",
|
||||
"__enable_irq()=",
|
||||
"__force_stores()=",
|
||||
"__memory_changed()=",
|
||||
"__schedule_barrier()=",
|
||||
"__semihost(x,y)=0",
|
||||
"__vfp_status(x,y)=0",
|
||||
"__builtin_arm_nop()=",
|
||||
"__builtin_arm_wfi()=",
|
||||
"__builtin_arm_wfe()=",
|
||||
"__builtin_arm_sev()=",
|
||||
"__builtin_arm_sevl()=",
|
||||
"__builtin_arm_yield()=",
|
||||
"__builtin_arm_isb(x)=",
|
||||
"__builtin_arm_dsb(x)=",
|
||||
"__builtin_arm_dmb(x)=",
|
||||
"__builtin_bswap32(x)=0U",
|
||||
"__builtin_bswap16(x)=0U",
|
||||
"__builtin_arm_rbit(x)=0U",
|
||||
"__builtin_clz(x)=0U",
|
||||
"__builtin_arm_ldrex(x)=0U",
|
||||
"__builtin_arm_strex(x,y)=0U",
|
||||
"__builtin_arm_clrex()=",
|
||||
"__builtin_arm_ssat(x,y)=0U",
|
||||
"__builtin_arm_usat(x,y)=0U",
|
||||
"__builtin_arm_ldaex(x)=0U",
|
||||
"__builtin_arm_stlex(x,y)=0U",
|
||||
"_ILP32=1",
|
||||
"_USE_STATIC_INLINE=1",
|
||||
"__APCS_32__=1",
|
||||
"__ARMCC_VERSION=6070001",
|
||||
"__ARMCOMPILER_VERSION=6070001",
|
||||
"__ARMEL__=1",
|
||||
"__ARM_32BIT_STATE=1",
|
||||
"__ARM_ACLE=200",
|
||||
"__ARM_ARCH=4",
|
||||
"__ARM_ARCH_4T__=1",
|
||||
"__ARM_ARCH_ISA_ARM=1",
|
||||
"__ARM_ARCH_ISA_THUMB=1",
|
||||
"__ARM_EABI__=1",
|
||||
"__ARM_FP16_ARGS=1",
|
||||
"__ARM_FP16_FORMAT_IEEE=1",
|
||||
"__ARM_NO_IMAGINARY_TYPE=1",
|
||||
"__ARM_PCS=1",
|
||||
"__ARM_PROMISE=__builtin_assume",
|
||||
"__ARM_SIZEOF_MINIMAL_ENUM=4",
|
||||
"__ARM_SIZEOF_WCHAR_T=4",
|
||||
"__ARM_TARGET_COPROC=1",
|
||||
"__ARM_TARGET_COPROC_V4=1",
|
||||
"__ATOMIC_ACQUIRE=2",
|
||||
"__ATOMIC_ACQ_REL=4",
|
||||
"__ATOMIC_CONSUME=1",
|
||||
"__ATOMIC_RELAXED=0",
|
||||
"__ATOMIC_RELEASE=3",
|
||||
"__ATOMIC_SEQ_CST=5",
|
||||
"__BIGGEST_ALIGNMENT__=8",
|
||||
"__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__",
|
||||
"__CHAR16_TYPE__=unsigned short",
|
||||
"__CHAR32_TYPE__=unsigned int",
|
||||
"__CHAR_BIT__=8",
|
||||
"__CHAR_UNSIGNED__=1",
|
||||
"__CONSTANT_CFSTRINGS__=1",
|
||||
"__DBL_DECIMAL_DIG__=17",
|
||||
"__DBL_DENORM_MIN__=4.9406564584124654e-324",
|
||||
"__DBL_DIG__=15",
|
||||
"__DBL_EPSILON__=2.2204460492503131e-16",
|
||||
"__DBL_HAS_DENORM__=1",
|
||||
"__DBL_HAS_INFINITY__=1",
|
||||
"__DBL_HAS_QUIET_NAN__=1",
|
||||
"__DBL_MANT_DIG__=53",
|
||||
"__DBL_MAX_10_EXP__=308",
|
||||
"__DBL_MAX_EXP__=1024",
|
||||
"__DBL_MAX__=1.7976931348623157e+308",
|
||||
"__DBL_MIN_10_EXP__=(-307)",
|
||||
"__DBL_MIN_EXP__=(-1021)",
|
||||
"__DBL_MIN__=2.2250738585072014e-308",
|
||||
"__DECIMAL_DIG__=__LDBL_DECIMAL_DIG__",
|
||||
"__ELF__=1",
|
||||
"__ESCAPE__=",
|
||||
"__FINITE_MATH_ONLY__=1",
|
||||
"__FLT_DECIMAL_DIG__=9",
|
||||
"__FLT_DENORM_MIN__=1.40129846e-45F",
|
||||
"__FLT_DIG__=6",
|
||||
"__FLT_EPSILON__=1.19209290e-7F",
|
||||
"__FLT_EVAL_METHOD__=0",
|
||||
"__FLT_HAS_DENORM__=1",
|
||||
"__FLT_HAS_INFINITY__=1",
|
||||
"__FLT_HAS_QUIET_NAN__=1",
|
||||
"__FLT_MANT_DIG__=24",
|
||||
"__FLT_MAX_10_EXP__=38",
|
||||
"__FLT_MAX_EXP__=128",
|
||||
"__FLT_MAX__=3.40282347e+38F",
|
||||
"__FLT_MIN_10_EXP__=(-37)",
|
||||
"__FLT_MIN_EXP__=(-125)",
|
||||
"__FLT_MIN__=1.17549435e-38F",
|
||||
"__FLT_RADIX__=2",
|
||||
"__GCC_ATOMIC_BOOL_LOCK_FREE=1",
|
||||
"__GCC_ATOMIC_CHAR16_T_LOCK_FREE=1",
|
||||
"__GCC_ATOMIC_CHAR32_T_LOCK_FREE=1",
|
||||
"__GCC_ATOMIC_CHAR_LOCK_FREE=1",
|
||||
"__GCC_ATOMIC_INT_LOCK_FREE=1",
|
||||
"__GCC_ATOMIC_LLONG_LOCK_FREE=1",
|
||||
"__GCC_ATOMIC_LONG_LOCK_FREE=1",
|
||||
"__GCC_ATOMIC_POINTER_LOCK_FREE=1",
|
||||
"__GCC_ATOMIC_SHORT_LOCK_FREE=1",
|
||||
"__GCC_ATOMIC_TEST_AND_SET_TRUEVAL=1",
|
||||
"__GCC_ATOMIC_WCHAR_T_LOCK_FREE=1",
|
||||
"__GNUC_MINOR__=2",
|
||||
"__GNUC_PATCHLEVEL__=1",
|
||||
"__GNUC_STDC_INLINE__=1",
|
||||
"__GNUC__=4",
|
||||
"__GXX_ABI_VERSION=1002",
|
||||
"__ILP32__=1",
|
||||
"__INT16_C_SUFFIX__=",
|
||||
"__INT16_FMTd__=\"hd\"",
|
||||
"__INT16_FMTi__=\"hi\"",
|
||||
"__INT16_MAX__=32767",
|
||||
"__INT16_TYPE__=short",
|
||||
"__INT32_C_SUFFIX__=",
|
||||
"__INT32_FMTd__=\"d\"",
|
||||
"__INT32_FMTi__=\"i\"",
|
||||
"__INT32_MAX__=2147483647",
|
||||
"__INT32_TYPE__=int",
|
||||
"__INT64_C_SUFFIX__=LL",
|
||||
"__INT64_FMTd__=\"lld\"",
|
||||
"__INT64_FMTi__=\"lli\"",
|
||||
"__INT64_MAX__=9223372036854775807LL",
|
||||
"__INT64_TYPE__=long long int",
|
||||
"__INT8_C_SUFFIX__=",
|
||||
"__INT8_FMTd__=\"hhd\"",
|
||||
"__INT8_FMTi__=\"hhi\"",
|
||||
"__INT8_MAX__=127",
|
||||
"__INT8_TYPE__=signed char",
|
||||
"__INTMAX_C_SUFFIX__=LL",
|
||||
"__INTMAX_FMTd__=\"lld\"",
|
||||
"__INTMAX_FMTi__=\"lli\"",
|
||||
"__INTMAX_MAX__=9223372036854775807LL",
|
||||
"__INTMAX_TYPE__=long long int",
|
||||
"__INTMAX_WIDTH__=64",
|
||||
"__INTPTR_FMTd__=\"ld\"",
|
||||
"__INTPTR_FMTi__=\"li\"",
|
||||
"__INTPTR_MAX__=2147483647L",
|
||||
"__INTPTR_TYPE__=long int",
|
||||
"__INTPTR_WIDTH__=32",
|
||||
"__INT_FAST16_FMTd__=\"hd\"",
|
||||
"__INT_FAST16_FMTi__=\"hi\"",
|
||||
"__INT_FAST16_MAX__=32767",
|
||||
"__INT_FAST16_TYPE__=short",
|
||||
"__INT_FAST32_FMTd__=\"d\"",
|
||||
"__INT_FAST32_FMTi__=\"i\"",
|
||||
"__INT_FAST32_MAX__=2147483647",
|
||||
"__INT_FAST32_TYPE__=int",
|
||||
"__INT_FAST64_FMTd__=\"lld\"",
|
||||
"__INT_FAST64_FMTi__=\"lli\"",
|
||||
"__INT_FAST64_MAX__=9223372036854775807LL",
|
||||
"__INT_FAST64_TYPE__=long long int",
|
||||
"__INT_FAST8_FMTd__=\"hhd\"",
|
||||
"__INT_FAST8_FMTi__=\"hhi\"",
|
||||
"__INT_FAST8_MAX__=127",
|
||||
"__INT_FAST8_TYPE__=signed char",
|
||||
"__INT_LEAST16_FMTd__=\"hd\"",
|
||||
"__INT_LEAST16_FMTi__=\"hi\"",
|
||||
"__INT_LEAST16_MAX__=32767",
|
||||
"__INT_LEAST16_TYPE__=short",
|
||||
"__INT_LEAST32_FMTd__=\"d\"",
|
||||
"__INT_LEAST32_FMTi__=\"i\"",
|
||||
"__INT_LEAST32_MAX__=2147483647",
|
||||
"__INT_LEAST32_TYPE__=int",
|
||||
"__INT_LEAST64_FMTd__=\"lld\"",
|
||||
"__INT_LEAST64_FMTi__=\"lli\"",
|
||||
"__INT_LEAST64_MAX__=9223372036854775807LL",
|
||||
"__INT_LEAST64_TYPE__=long long int",
|
||||
"__INT_LEAST8_FMTd__=\"hhd\"",
|
||||
"__INT_LEAST8_FMTi__=\"hhi\"",
|
||||
"__INT_LEAST8_MAX__=127",
|
||||
"__INT_LEAST8_TYPE__=signed char",
|
||||
"__INT_MAX__=2147483647",
|
||||
"__I__=1.0if",
|
||||
"__LDBL_DECIMAL_DIG__=17",
|
||||
"__LDBL_DENORM_MIN__=4.9406564584124654e-324L",
|
||||
"__LDBL_DIG__=15",
|
||||
"__LDBL_EPSILON__=2.2204460492503131e-16L",
|
||||
"__LDBL_HAS_DENORM__=1",
|
||||
"__LDBL_HAS_INFINITY__=1",
|
||||
"__LDBL_HAS_QUIET_NAN__=1",
|
||||
"__LDBL_MANT_DIG__=53",
|
||||
"__LDBL_MAX_10_EXP__=308",
|
||||
"__LDBL_MAX_EXP__=1024",
|
||||
"__LDBL_MAX__=1.7976931348623157e+308L",
|
||||
"__LDBL_MIN_10_EXP__=(-307)",
|
||||
"__LDBL_MIN_EXP__=(-1021)",
|
||||
"__LDBL_MIN__=2.2250738585072014e-308L",
|
||||
"__LITTLE_ENDIAN__=1",
|
||||
"__LONG_LONG_MAX__=9223372036854775807LL",
|
||||
"__LONG_MAX__=2147483647L",
|
||||
"__NO_INLINE__=1",
|
||||
"__OBJC_BOOL_IS_BOOL=0",
|
||||
"__ORDER_BIG_ENDIAN__=4321",
|
||||
"__ORDER_LITTLE_ENDIAN__=1234",
|
||||
"__ORDER_PDP_ENDIAN__=3412",
|
||||
"__POINTER_WIDTH__=32",
|
||||
"__PRAGMA_REDEFINE_EXTNAME=1",
|
||||
"__PTRDIFF_FMTd__=\"d\"",
|
||||
"__PTRDIFF_FMTi__=\"i\"",
|
||||
"__PTRDIFF_MAX__=2147483647",
|
||||
"__PTRDIFF_TYPE__=int",
|
||||
"__PTRDIFF_WIDTH__=32",
|
||||
"__REGISTER_PREFIX__=",
|
||||
"__SCHAR_MAX__=127",
|
||||
"__SHRT_MAX__=32767",
|
||||
"__SIG_ATOMIC_MAX__=2147483647",
|
||||
"__SIG_ATOMIC_WIDTH__=32",
|
||||
"__SIZEOF_DOUBLE__=8",
|
||||
"__SIZEOF_FLOAT__=4",
|
||||
"__SIZEOF_INT__=4",
|
||||
"__SIZEOF_LONG_DOUBLE__=8",
|
||||
"__SIZEOF_LONG_LONG__=8",
|
||||
"__SIZEOF_LONG__=4",
|
||||
"__SIZEOF_POINTER__=4",
|
||||
"__SIZEOF_PTRDIFF_T__=4",
|
||||
"__SIZEOF_SHORT__=2",
|
||||
"__SIZEOF_SIZE_T__=4",
|
||||
"__SIZEOF_WCHAR_T__=4",
|
||||
"__SIZEOF_WINT_T__=4",
|
||||
"__SIZE_FMTX__=\"X\"",
|
||||
"__SIZE_FMTo__=\"o\"",
|
||||
"__SIZE_FMTu__=\"u\"",
|
||||
"__SIZE_FMTx__=\"x\"",
|
||||
"__SIZE_MAX__=4294967295U",
|
||||
"__SIZE_TYPE__=unsigned int",
|
||||
"__SIZE_WIDTH__=32",
|
||||
"__STDC_HOSTED__=1",
|
||||
"__STDC_UTF_16__=1",
|
||||
"__STDC_UTF_32__=1",
|
||||
"__STDC_VERSION__=201112L",
|
||||
"__STDC__=1",
|
||||
"__UINT16_C_SUFFIX__=",
|
||||
"__UINT16_FMTX__=\"hX\"",
|
||||
"__UINT16_FMTo__=\"ho\"",
|
||||
"__UINT16_FMTu__=\"hu\"",
|
||||
"__UINT16_FMTx__=\"hx\"",
|
||||
"__UINT16_MAX__=65535",
|
||||
"__UINT16_TYPE__=unsigned short",
|
||||
"__UINT32_C_SUFFIX__=U",
|
||||
"__UINT32_FMTX__=\"X\"",
|
||||
"__UINT32_FMTo__=\"o\"",
|
||||
"__UINT32_FMTu__=\"u\"",
|
||||
"__UINT32_FMTx__=\"x\"",
|
||||
"__UINT32_MAX__=4294967295U",
|
||||
"__UINT32_TYPE__=unsigned int",
|
||||
"__UINT64_C_SUFFIX__=ULL",
|
||||
"__UINT64_FMTX__=\"llX\"",
|
||||
"__UINT64_FMTo__=\"llo\"",
|
||||
"__UINT64_FMTu__=\"llu\"",
|
||||
"__UINT64_FMTx__=\"llx\"",
|
||||
"__UINT64_MAX__=18446744073709551615ULL",
|
||||
"__UINT64_TYPE__=long long unsigned int",
|
||||
"__UINT8_C_SUFFIX__=",
|
||||
"__UINT8_FMTX__=\"hhX\"",
|
||||
"__UINT8_FMTo__=\"hho\"",
|
||||
"__UINT8_FMTu__=\"hhu\"",
|
||||
"__UINT8_FMTx__=\"hhx\"",
|
||||
"__UINT8_MAX__=255",
|
||||
"__UINT8_TYPE__=unsigned char",
|
||||
"__UINTMAX_C_SUFFIX__=ULL",
|
||||
"__UINTMAX_FMTX__=\"llX\"",
|
||||
"__UINTMAX_FMTo__=\"llo\"",
|
||||
"__UINTMAX_FMTu__=\"llu\"",
|
||||
"__UINTMAX_FMTx__=\"llx\"",
|
||||
"__UINTMAX_MAX__=18446744073709551615ULL",
|
||||
"__UINTMAX_TYPE__=long long unsigned int",
|
||||
"__UINTMAX_WIDTH__=64",
|
||||
"__UINTPTR_FMTX__=\"lX\"",
|
||||
"__UINTPTR_FMTo__=\"lo\"",
|
||||
"__UINTPTR_FMTu__=\"lu\"",
|
||||
"__UINTPTR_FMTx__=\"lx\"",
|
||||
"__UINTPTR_MAX__=4294967295UL",
|
||||
"__UINTPTR_TYPE__=long unsigned int",
|
||||
"__UINTPTR_WIDTH__=32",
|
||||
"__UINT_FAST16_FMTX__=\"hX\"",
|
||||
"__UINT_FAST16_FMTo__=\"ho\"",
|
||||
"__UINT_FAST16_FMTu__=\"hu\"",
|
||||
"__UINT_FAST16_FMTx__=\"hx\"",
|
||||
"__UINT_FAST16_MAX__=65535",
|
||||
"__UINT_FAST16_TYPE__=unsigned short",
|
||||
"__UINT_FAST32_FMTX__=\"X\"",
|
||||
"__UINT_FAST32_FMTo__=\"o\"",
|
||||
"__UINT_FAST32_FMTu__=\"u\"",
|
||||
"__UINT_FAST32_FMTx__=\"x\"",
|
||||
"__UINT_FAST32_MAX__=4294967295U",
|
||||
"__UINT_FAST32_TYPE__=unsigned int",
|
||||
"__UINT_FAST64_FMTX__=\"llX\"",
|
||||
"__UINT_FAST64_FMTo__=\"llo\"",
|
||||
"__UINT_FAST64_FMTu__=\"llu\"",
|
||||
"__UINT_FAST64_FMTx__=\"llx\"",
|
||||
"__UINT_FAST64_MAX__=18446744073709551615ULL",
|
||||
"__UINT_FAST64_TYPE__=long long unsigned int",
|
||||
"__UINT_FAST8_FMTX__=\"hhX\"",
|
||||
"__UINT_FAST8_FMTo__=\"hho\"",
|
||||
"__UINT_FAST8_FMTu__=\"hhu\"",
|
||||
"__UINT_FAST8_FMTx__=\"hhx\"",
|
||||
"__UINT_FAST8_MAX__=255",
|
||||
"__UINT_FAST8_TYPE__=unsigned char",
|
||||
"__UINT_LEAST16_FMTX__=\"hX\"",
|
||||
"__UINT_LEAST16_FMTo__=\"ho\"",
|
||||
"__UINT_LEAST16_FMTu__=\"hu\"",
|
||||
"__UINT_LEAST16_FMTx__=\"hx\"",
|
||||
"__UINT_LEAST16_MAX__=65535",
|
||||
"__UINT_LEAST16_TYPE__=unsigned short",
|
||||
"__UINT_LEAST32_FMTX__=\"X\"",
|
||||
"__UINT_LEAST32_FMTo__=\"o\"",
|
||||
"__UINT_LEAST32_FMTu__=\"u\"",
|
||||
"__UINT_LEAST32_FMTx__=\"x\"",
|
||||
"__UINT_LEAST32_MAX__=4294967295U",
|
||||
"__UINT_LEAST32_TYPE__=unsigned int",
|
||||
"__UINT_LEAST64_FMTX__=\"llX\"",
|
||||
"__UINT_LEAST64_FMTo__=\"llo\"",
|
||||
"__UINT_LEAST64_FMTu__=\"llu\"",
|
||||
"__UINT_LEAST64_FMTx__=\"llx\"",
|
||||
"__UINT_LEAST64_MAX__=18446744073709551615ULL",
|
||||
"__UINT_LEAST64_TYPE__=long long unsigned int",
|
||||
"__UINT_LEAST8_FMTX__=\"hhX\"",
|
||||
"__UINT_LEAST8_FMTo__=\"hho\"",
|
||||
"__UINT_LEAST8_FMTu__=\"hhu\"",
|
||||
"__UINT_LEAST8_FMTx__=\"hhx\"",
|
||||
"__UINT_LEAST8_MAX__=255",
|
||||
"__UINT_LEAST8_TYPE__=unsigned char",
|
||||
"__USER_LABEL_PREFIX__=",
|
||||
"__VERSION__=\"4.2.1 Compatible Clang 5.0.0 \"",
|
||||
"__WCHAR_MAX__=4294967295U",
|
||||
"__WCHAR_TYPE__=unsigned int",
|
||||
"__WCHAR_UNSIGNED__=1",
|
||||
"__WCHAR_WIDTH__=32",
|
||||
"__WINT_TYPE__=int",
|
||||
"__WINT_WIDTH__=32",
|
||||
"__arm=1",
|
||||
"__arm__=1",
|
||||
"__clang__=1",
|
||||
"__clang_major__=5",
|
||||
"__clang_minor__=0",
|
||||
"__clang_patchlevel__=0",
|
||||
"__clang_version__=\"5.0.0 \"",
|
||||
"__llvm__=1"
|
||||
],
|
||||
"intelliSenseMode": "gcc-arm",
|
||||
"compilerPath": "d:/DevTools/env2/tools/gnu_gcc/arm_gcc/mingw/bin/arm-none-eabi-gcc",
|
||||
@ -19,78 +386,45 @@
|
||||
"build/compile_commands.json"
|
||||
],
|
||||
"includePath": [
|
||||
"packages\\aht10-latest\\inc",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\infra",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\mqtt\\impl",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\mqtt",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\client",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\server",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_sign",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\wrappers",
|
||||
"packages\\ap3216c-latest",
|
||||
"applications",
|
||||
"my_pro",
|
||||
"rt-thread\\components\\net\\at\\include",
|
||||
"packages\\cJSON-v1.7.17",
|
||||
"rt-thread\\components\\libc\\compilers\\common\\include",
|
||||
"rt-thread\\components\\libc\\compilers\\newlib",
|
||||
"rt-thread\\components\\libc\\cplusplus",
|
||||
"rt-thread\\components\\drivers\\include",
|
||||
"rt-thread\\components\\drivers\\spi",
|
||||
"rt-thread\\components\\drivers\\spi\\sfud\\inc",
|
||||
"rt-thread\\components\\drivers\\wlan",
|
||||
"board",
|
||||
"board\\CubeMX_Config\\Inc",
|
||||
"board\\ports",
|
||||
"board\\ports\\fal",
|
||||
"board\\ports\\lcd",
|
||||
"board\\ports\\led_matrix",
|
||||
"libraries\\HAL_Drivers\\drivers",
|
||||
"libraries\\HAL_Drivers\\drivers\\config",
|
||||
"libraries\\HAL_Drivers\\drivers\\drv_flash",
|
||||
"libraries\\HAL_Drivers",
|
||||
"libraries\\HAL_Drivers\\CMSIS\\Include",
|
||||
"rt-thread\\components\\fal\\inc",
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\include",
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\filesystems\\devfs",
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\filesystems\\elmfat",
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\filesystems\\romfs",
|
||||
"rt-thread\\components\\finsh",
|
||||
"packages\\FlexibleButton-v1.0.0",
|
||||
"packages\\icm20608-latest",
|
||||
"packages\\infrared-v0.1.1\\inc",
|
||||
".",
|
||||
"rt-thread\\include",
|
||||
"packages\\kernel_samples-latest\\en",
|
||||
"rt-thread\\components\\legacy",
|
||||
"rt-thread\\components\\legacy\\dfs",
|
||||
"rt-thread\\libcpu\\arm\\common",
|
||||
"rt-thread\\libcpu\\arm\\cortex-m4",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Inc",
|
||||
"libraries\\STM32F4xx_HAL\\CMSIS\\Device\\ST\\STM32F4xx\\Include",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\include",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\include\\ipv4",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\include\\netif",
|
||||
"rt-thread\\components\\net\\lwip\\port",
|
||||
"packages\\netutils-latest\\ntp",
|
||||
"packages\\perf_counter-v2.2.4.1",
|
||||
"rt-thread\\components\\libc\\posix\\io\\epoll",
|
||||
"rt-thread\\components\\libc\\posix\\io\\eventfd",
|
||||
"rt-thread\\components\\libc\\posix\\io\\poll",
|
||||
"rt-thread\\components\\libc\\posix\\ipc",
|
||||
"board\\ports\\rs485",
|
||||
"rt-thread\\components\\legacy\\usb\\usbdevice",
|
||||
"packages\\rw007-v2.1.0",
|
||||
"packages\\rw007-v2.1.0\\inc",
|
||||
"rt-thread\\components\\net\\netdev\\include",
|
||||
"rt-thread\\components\\net\\sal\\include",
|
||||
"rt-thread\\components\\net\\sal\\include\\socket",
|
||||
"rt-thread\\components\\net\\sal\\impl",
|
||||
"rt-thread\\components\\net\\sal\\include\\dfs_net",
|
||||
"rt-thread\\components\\net\\sal\\include\\socket\\sys_socket",
|
||||
"rt-thread\\components\\utilities\\ulog",
|
||||
"packages\\vconsole-latest"
|
||||
"d:\\components\\drivers\\include",
|
||||
"d:\\Develop\\libraries\\HAL_Drivers\\drivers\\config",
|
||||
"d:\\Develop\\libraries\\HAL_Drivers\\drivers",
|
||||
"d:\\components\\libc\\posix\\io\\eventfd",
|
||||
"d:\\Develop\\SumProject\\board",
|
||||
"d:\\Develop\\SumProject\\board\\CubeMX_Config\\Inc",
|
||||
"d:\\libcpu\\arm\\common",
|
||||
"d:\\components\\libc\\posix\\ipc",
|
||||
"d:\\Develop\\libraries\\HAL_Drivers\\CMSIS\\Include",
|
||||
"d:\\Develop\\SumProject\\board\\ports",
|
||||
"d:\\Develop\\libraries\\HAL_Drivers",
|
||||
"d:\\components\\libc\\compilers\\common\\include",
|
||||
"d:\\libcpu\\arm\\cortex-m4",
|
||||
"d:\\components\\libc\\posix\\io\\poll",
|
||||
"d:\\Develop\\SumProject",
|
||||
"d:\\components\\libc\\posix\\io\\epoll",
|
||||
"d:\\components\\finsh",
|
||||
"d:\\Develop\\libraries\\STM32F4xx_HAL\\CMSIS\\Device\\ST\\STM32F4xx\\Include",
|
||||
"d:\\Develop\\libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Inc",
|
||||
"d:\\components\\libc\\compilers\\common\\extension",
|
||||
"d:\\components\\libc\\compilers\\common\\extension\\fcntl\\octal",
|
||||
"d:\\Develop\\SumProject\\applications",
|
||||
"d:\\include",
|
||||
"D:\\Keil5\\ARM\\ARMCLANG\\include",
|
||||
"D:\\Keil5\\ARM\\ARMCLANG\\include\\libcxx",
|
||||
"d:\\components\\libc\\compilers\\armlibc",
|
||||
"d:\\components\\libc\\compilers\\common",
|
||||
"d:\\components\\drivers\\core",
|
||||
"d:\\components\\drivers\\i2c",
|
||||
"d:\\components\\drivers\\ipc",
|
||||
"d:\\components\\drivers\\misc",
|
||||
"d:\\components\\drivers\\pin",
|
||||
"d:\\components\\drivers\\serial",
|
||||
"d:\\Develop\\libraries\\STM32F4xx_HAL\\CMSIS\\Device\\ST\\STM32F4xx\\Source\\Templates\\arm",
|
||||
"d:\\Develop\\SumProject\\board\\CubeMX_Config\\Src",
|
||||
"d:\\src",
|
||||
"d:\\src\\klibc",
|
||||
"d:\\Develop\\libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src",
|
||||
"d:\\Develop\\libraries\\STM32F4xx_HAL\\CMSIS\\Device\\ST\\STM32F4xx\\Source\\Templates"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
519
.vscode/project.json
vendored
Normal file
519
.vscode/project.json
vendored
Normal file
@ -0,0 +1,519 @@
|
||||
{
|
||||
"RT-Thread": "D:\\Develop\\SumProject\\rt-thread",
|
||||
"Groups": [
|
||||
{
|
||||
"name": "aht10",
|
||||
"path": "packages\\aht10-latest",
|
||||
"files": [
|
||||
"packages\\aht10-latest\\src\\aht10.c",
|
||||
"packages\\aht10-latest\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ali-iotkit",
|
||||
"path": "packages\\ali-iotkit-v3.0.2",
|
||||
"files": [
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\mqtt\\impl\\MQTTSerializePublish.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\infra\\infra_compat.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\dm_ota.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\dm_fota.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\dm_ipc.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\infra\\infra_log.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\ports\\rtthread\\HAL_TCP_rtthread.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\mqtt\\impl\\MQTTDeserializePublish.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_sign\\dev_sign_mqtt.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\infra\\infra_prt_nwk_payload.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\mqtt\\impl\\MQTTConnectClient.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\iotx_cm.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\client\\dm_client.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\ports\\wrapper.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\dm_log_report.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\ports\\rtthread\\HAL_UDP_rtthread.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\impl_linkkit.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\mqtt\\impl\\MQTTPacket.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\ports\\rtthread\\HAL_OS_rtthread.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\infra\\infra_report.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\dm_message_cache.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\mqtt\\impl\\iotx_mqtt_client.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\infra\\infra_cjson.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\mqtt\\mqtt_api.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\infra\\infra_net.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\dm_manager.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\mqtt\\impl\\MQTTSubscribeClient.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\infra\\infra_defs.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\infra\\infra_string.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\dm_cota.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\dm_opt.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\iotx_cm_mqtt.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\client\\dm_client_adapter.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\dm_message.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\dm_utils.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\dm_api.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\infra\\infra_timer.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\dev_model\\dm_msg_process.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\mqtt\\impl\\MQTTUnsubscribeClient.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\iotkit-embedded\\src\\infra\\infra_sha256.c",
|
||||
"packages\\ali-iotkit-v3.0.2\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ap3216c",
|
||||
"path": "packages\\ap3216c-latest",
|
||||
"files": [
|
||||
"packages\\ap3216c-latest\\ap3216c.c",
|
||||
"packages\\ap3216c-latest\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Applications",
|
||||
"path": "applications",
|
||||
"files": [
|
||||
"applications\\app_lcd.c",
|
||||
"applications\\init.c",
|
||||
"applications\\main.c",
|
||||
"applications\\sim.c",
|
||||
"my_pro\\AHT10.c",
|
||||
"my_pro\\icm_20608_sample.c",
|
||||
"my_pro\\indicator_led.c",
|
||||
"my_pro\\my_func.c",
|
||||
"my_pro\\myinfrared.c",
|
||||
"my_pro\\myproject.c",
|
||||
"my_pro\\mysnake.c",
|
||||
"my_pro\\mytest.c",
|
||||
"my_pro\\pin_irq_example.c",
|
||||
"my_pro\\test_drv_example.c",
|
||||
"applications\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "AT",
|
||||
"path": "rt-thread\\components\\net\\at",
|
||||
"files": [
|
||||
"rt-thread\\components\\net\\at\\src\\at_cli.c",
|
||||
"rt-thread\\components\\net\\at\\src\\at_client.c",
|
||||
"rt-thread\\components\\net\\at\\src\\at_utils.c",
|
||||
"rt-thread\\components\\net\\at\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cJSON",
|
||||
"path": "packages\\cJSON-v1.7.17",
|
||||
"files": [
|
||||
"packages\\cJSON-v1.7.17\\cJSON_Utils.c",
|
||||
"packages\\cJSON-v1.7.17\\cJSON.c",
|
||||
"packages\\cJSON-v1.7.17\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Compiler",
|
||||
"path": "rt-thread\\components\\libc\\compilers\\common",
|
||||
"files": [
|
||||
"rt-thread\\components\\libc\\compilers\\common\\cctype.c",
|
||||
"rt-thread\\components\\libc\\compilers\\common\\cstdlib.c",
|
||||
"rt-thread\\components\\libc\\compilers\\common\\cstring.c",
|
||||
"rt-thread\\components\\libc\\compilers\\common\\ctime.c",
|
||||
"rt-thread\\components\\libc\\compilers\\common\\cunistd.c",
|
||||
"rt-thread\\components\\libc\\compilers\\common\\cwchar.c",
|
||||
"rt-thread\\components\\libc\\compilers\\newlib\\syscalls.c",
|
||||
"rt-thread\\components\\libc\\compilers\\common\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CPP",
|
||||
"path": "rt-thread\\components\\libc\\cplusplus",
|
||||
"files": [
|
||||
"rt-thread\\components\\libc\\cplusplus\\cxx_crt_init.c",
|
||||
"rt-thread\\components\\libc\\cplusplus\\cxx_crt.cpp",
|
||||
"rt-thread\\components\\libc\\cplusplus\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DeviceDrivers",
|
||||
"path": "rt-thread\\components\\drivers\\block",
|
||||
"files": [
|
||||
"rt-thread\\components\\drivers\\block\\blk.c",
|
||||
"rt-thread\\components\\drivers\\block\\blk_dev.c",
|
||||
"rt-thread\\components\\drivers\\block\\blk_dfs.c",
|
||||
"rt-thread\\components\\drivers\\block\\blk_partition.c",
|
||||
"rt-thread\\components\\drivers\\block\\partitions\\dfs.c",
|
||||
"rt-thread\\components\\drivers\\block\\partitions\\efi.c",
|
||||
"rt-thread\\components\\drivers\\core\\device.c",
|
||||
"rt-thread\\components\\drivers\\hwtimer\\hwtimer.c",
|
||||
"rt-thread\\components\\drivers\\i2c\\dev_i2c_bit_ops.c",
|
||||
"rt-thread\\components\\drivers\\i2c\\dev_i2c_core.c",
|
||||
"rt-thread\\components\\drivers\\i2c\\dev_i2c_dev.c",
|
||||
"rt-thread\\components\\drivers\\ipc\\completion_comm.c",
|
||||
"rt-thread\\components\\drivers\\ipc\\completion_up.c",
|
||||
"rt-thread\\components\\drivers\\ipc\\condvar.c",
|
||||
"rt-thread\\components\\drivers\\ipc\\dataqueue.c",
|
||||
"rt-thread\\components\\drivers\\ipc\\pipe.c",
|
||||
"rt-thread\\components\\drivers\\ipc\\ringblk_buf.c",
|
||||
"rt-thread\\components\\drivers\\ipc\\ringbuffer.c",
|
||||
"rt-thread\\components\\drivers\\ipc\\waitqueue.c",
|
||||
"rt-thread\\components\\drivers\\ipc\\workqueue.c",
|
||||
"rt-thread\\components\\drivers\\misc\\adc.c",
|
||||
"rt-thread\\components\\drivers\\misc\\rt_drv_pwm.c",
|
||||
"rt-thread\\components\\drivers\\pin\\dev_pin.c",
|
||||
"rt-thread\\components\\drivers\\rtc\\dev_rtc.c",
|
||||
"rt-thread\\components\\drivers\\rtc\\dev_soft_rtc.c",
|
||||
"rt-thread\\components\\drivers\\sdio\\dev_block.c",
|
||||
"rt-thread\\components\\drivers\\sdio\\dev_mmc.c",
|
||||
"rt-thread\\components\\drivers\\sdio\\dev_mmcsd_core.c",
|
||||
"rt-thread\\components\\drivers\\sdio\\dev_sd.c",
|
||||
"rt-thread\\components\\drivers\\sdio\\dev_sdio.c",
|
||||
"rt-thread\\components\\drivers\\sensor\\v1\\sensor.c",
|
||||
"rt-thread\\components\\drivers\\sensor\\v1\\sensor_cmd.c",
|
||||
"rt-thread\\components\\drivers\\serial\\dev_serial.c",
|
||||
"rt-thread\\components\\drivers\\spi\\dev_spi.c",
|
||||
"rt-thread\\components\\drivers\\spi\\dev_spi_core.c",
|
||||
"rt-thread\\components\\drivers\\spi\\dev_spi_flash_sfud.c",
|
||||
"rt-thread\\components\\drivers\\spi\\sfud\\src\\sfud.c",
|
||||
"rt-thread\\components\\drivers\\spi\\sfud\\src\\sfud_sfdp.c",
|
||||
"rt-thread\\components\\drivers\\wlan\\dev_wlan.c",
|
||||
"rt-thread\\components\\drivers\\wlan\\dev_wlan_cfg.c",
|
||||
"rt-thread\\components\\drivers\\wlan\\dev_wlan_cmd.c",
|
||||
"rt-thread\\components\\drivers\\wlan\\dev_wlan_lwip.c",
|
||||
"rt-thread\\components\\drivers\\wlan\\dev_wlan_mgnt.c",
|
||||
"rt-thread\\components\\drivers\\wlan\\dev_wlan_prot.c",
|
||||
"rt-thread\\components\\drivers\\wlan\\dev_wlan_workqueue.c",
|
||||
"rt-thread\\components\\drivers\\block\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Drivers",
|
||||
"path": "board",
|
||||
"files": [
|
||||
"board\\CubeMX_Config\\Src\\stm32f4xx_hal_msp.c",
|
||||
"board\\board.c",
|
||||
"board\\ports\\drv_filesystem.c",
|
||||
"board\\ports\\fal\\fal_spi_flash_sfud_port.c",
|
||||
"board\\ports\\lcd\\drv_lcd.c",
|
||||
"board\\ports\\led_matrix\\drv_matrix_led.c",
|
||||
"board\\ports\\spi_flash_init.c",
|
||||
"board\\startup_stm32f407xx.s",
|
||||
"libraries\\HAL_Drivers\\drivers\\drv_adc.c",
|
||||
"libraries\\HAL_Drivers\\drivers\\drv_flash\\drv_flash_f4.c",
|
||||
"libraries\\HAL_Drivers\\drivers\\drv_gpio.c",
|
||||
"libraries\\HAL_Drivers\\drivers\\drv_pwm.c",
|
||||
"libraries\\HAL_Drivers\\drivers\\drv_sdio.c",
|
||||
"libraries\\HAL_Drivers\\drivers\\drv_soft_i2c.c",
|
||||
"libraries\\HAL_Drivers\\drivers\\drv_spi.c",
|
||||
"libraries\\HAL_Drivers\\drivers\\drv_test.c",
|
||||
"libraries\\HAL_Drivers\\drivers\\drv_tim.c",
|
||||
"libraries\\HAL_Drivers\\drivers\\drv_usart.c",
|
||||
"libraries\\HAL_Drivers\\drivers\\drv_usbd.c",
|
||||
"libraries\\HAL_Drivers\\drv_common.c",
|
||||
"board\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Fal",
|
||||
"path": "rt-thread\\components\\fal",
|
||||
"files": [
|
||||
"rt-thread\\components\\fal\\src\\fal.c",
|
||||
"rt-thread\\components\\fal\\src\\fal_partition.c",
|
||||
"rt-thread\\components\\fal\\samples\\porting\\fal_flash_sfud_port.c",
|
||||
"rt-thread\\components\\fal\\src\\fal_flash.c",
|
||||
"rt-thread\\components\\fal\\src\\fal_rtt.c",
|
||||
"rt-thread\\components\\fal\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Filesystem",
|
||||
"path": "rt-thread\\components\\dfs\\dfs_v1",
|
||||
"files": [
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\filesystems\\devfs\\devfs.c",
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\filesystems\\elmfat\\dfs_elm.c",
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\filesystems\\elmfat\\ff.c",
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\filesystems\\elmfat\\ffunicode.c",
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\filesystems\\romfs\\dfs_romfs.c",
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\src\\dfs.c",
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\src\\dfs_file.c",
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\src\\dfs_fs.c",
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\src\\dfs_posix.c",
|
||||
"rt-thread\\components\\dfs\\dfs_v1\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Finsh",
|
||||
"path": "rt-thread\\components\\finsh",
|
||||
"files": [
|
||||
"rt-thread\\components\\finsh\\msh_parse.c",
|
||||
"rt-thread\\components\\finsh\\msh.c",
|
||||
"rt-thread\\components\\finsh\\msh_file.c",
|
||||
"rt-thread\\components\\finsh\\cmd.c",
|
||||
"rt-thread\\components\\finsh\\shell.c",
|
||||
"rt-thread\\components\\finsh\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "flex_button",
|
||||
"path": "packages\\FlexibleButton-v1.0.0",
|
||||
"files": [
|
||||
"packages\\FlexibleButton-v1.0.0\\flexible_button.c",
|
||||
"packages\\FlexibleButton-v1.0.0\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "icm20608",
|
||||
"path": "packages\\icm20608-latest",
|
||||
"files": [
|
||||
"packages\\icm20608-latest\\icm20608.c",
|
||||
"packages\\icm20608-latest\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Infrared_frame",
|
||||
"path": "packages\\infrared-v0.1.1",
|
||||
"files": [
|
||||
"packages\\infrared-v0.1.1\\src\\drv_infrared.c",
|
||||
"packages\\infrared-v0.1.1\\src\\infrared.c",
|
||||
"packages\\infrared-v0.1.1\\src\\nec_decoder.c",
|
||||
"packages\\infrared-v0.1.1\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Kernel",
|
||||
"path": ".",
|
||||
"files": [
|
||||
"rt-thread\\src\\clock.c",
|
||||
"rt-thread\\src\\components.c",
|
||||
"rt-thread\\src\\cpu_up.c",
|
||||
"rt-thread\\src\\defunct.c",
|
||||
"rt-thread\\src\\idle.c",
|
||||
"rt-thread\\src\\ipc.c",
|
||||
"rt-thread\\src\\irq.c",
|
||||
"rt-thread\\src\\kservice.c",
|
||||
"rt-thread\\src\\mem.c",
|
||||
"rt-thread\\src\\mempool.c",
|
||||
"rt-thread\\src\\object.c",
|
||||
"rt-thread\\src\\scheduler_comm.c",
|
||||
"rt-thread\\src\\scheduler_up.c",
|
||||
"rt-thread\\src\\thread.c",
|
||||
"rt-thread\\src\\timer.c",
|
||||
".\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "kernel-samples",
|
||||
"path": "packages\\kernel_samples-latest\\en",
|
||||
"files": [
|
||||
"packages\\kernel_samples-latest\\en\\semaphore_sample.c",
|
||||
"packages\\kernel_samples-latest\\en\\mailbox_sample.c",
|
||||
"packages\\kernel_samples-latest\\en\\msgq_sample.c",
|
||||
"packages\\kernel_samples-latest\\en\\thread_sample.c",
|
||||
"packages\\kernel_samples-latest\\en\\event_sample.c",
|
||||
"packages\\kernel_samples-latest\\en\\mutex_sample.c",
|
||||
"packages\\kernel_samples-latest\\en\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "klibc",
|
||||
"path": "rt-thread\\src\\klibc",
|
||||
"files": [
|
||||
"rt-thread\\src\\klibc\\rt_vsscanf.c",
|
||||
"rt-thread\\src\\klibc\\rt_vsnprintf_std.c",
|
||||
"rt-thread\\src\\klibc\\kerrno.c",
|
||||
"rt-thread\\src\\klibc\\kstdio.c",
|
||||
"rt-thread\\src\\klibc\\kstring.c",
|
||||
"rt-thread\\src\\klibc\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Legacy",
|
||||
"path": "rt-thread\\components\\legacy",
|
||||
"files": [
|
||||
"rt-thread\\components\\legacy\\ipc\\workqueue_legacy.c",
|
||||
"rt-thread\\components\\legacy\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "libcpu",
|
||||
"path": "rt-thread\\libcpu\\arm\\common",
|
||||
"files": [
|
||||
"rt-thread\\libcpu\\arm\\common\\atomic_arm.c",
|
||||
"rt-thread\\libcpu\\arm\\common\\div0.c",
|
||||
"rt-thread\\libcpu\\arm\\common\\showmem.c",
|
||||
"rt-thread\\libcpu\\arm\\cortex-m4\\context_gcc.S",
|
||||
"rt-thread\\libcpu\\arm\\cortex-m4\\cpuport.c",
|
||||
"rt-thread\\libcpu\\arm\\common\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Libraries",
|
||||
"path": "libraries\\STM32F4xx_HAL",
|
||||
"files": [
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_ll_usb.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_ll_fmc.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_sram.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_ll_sdmmc.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_i2c.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_rcc.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_hcd.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_tim.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_usart.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_dma.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_adc.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_rtc_ex.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_i2c_ex.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_flash_ramfunc.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_gpio.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_dma_ex.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_rcc_ex.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_rtc.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_pccard.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_cec.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_crc.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_pwr.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_sd.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_pcd.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_flash_ex.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_cortex.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_ll_fsmc.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_flash.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_adc_ex.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_pwr_ex.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_pcd_ex.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_cryp_ex.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_uart.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_qspi.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_tim_ex.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_spi.c",
|
||||
"libraries\\STM32F4xx_HAL\\CMSIS\\Device\\ST\\STM32F4xx\\Source\\Templates\\system_stm32f4xx.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_lptim.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_rng.c",
|
||||
"libraries\\STM32F4xx_HAL\\STM32F4xx_HAL_Driver\\Src\\stm32f4xx_hal_cryp.c",
|
||||
"libraries\\STM32F4xx_HAL\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "lwIP",
|
||||
"path": "rt-thread\\components\\net\\lwip\\lwip-2.0.3",
|
||||
"files": [
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\api\\api_lib.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\api\\api_msg.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\api\\err.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\api\\netbuf.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\api\\netdb.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\api\\netifapi.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\api\\sockets.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\api\\tcpip.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\apps\\ping\\ping.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\def.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\dns.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\inet_chksum.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\init.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\ip.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\ipv4\\autoip.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\ipv4\\dhcp.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\ipv4\\etharp.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\ipv4\\icmp.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\ipv4\\igmp.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\ipv4\\ip4.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\ipv4\\ip4_addr.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\ipv4\\ip4_frag.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\memp.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\netif.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\pbuf.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\raw.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\stats.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\sys.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\tcp.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\tcp_in.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\tcp_out.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\timeouts.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\core\\udp.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\netif\\ethernet.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\src\\netif\\lowpan6.c",
|
||||
"rt-thread\\components\\net\\lwip\\port\\ethernetif.c",
|
||||
"rt-thread\\components\\net\\lwip\\port\\sys_arch.c",
|
||||
"rt-thread\\components\\net\\lwip\\lwip-2.0.3\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NetUtils",
|
||||
"path": "packages\\netutils-latest\\ntp",
|
||||
"files": [
|
||||
"packages\\netutils-latest\\ntp\\ntp.c",
|
||||
"packages\\netutils-latest\\ntp\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "perf_counter",
|
||||
"path": "packages\\perf_counter-v2.2.4.1",
|
||||
"files": [
|
||||
"packages\\perf_counter-v2.2.4.1\\os\\perf_os_patch_rt_thread.c",
|
||||
"packages\\perf_counter-v2.2.4.1\\perf_counter.c",
|
||||
"packages\\perf_counter-v2.2.4.1\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "POSIX",
|
||||
"path": "rt-thread\\components\\libc\\posix\\io\\epoll",
|
||||
"files": [
|
||||
"rt-thread\\components\\libc\\posix\\io\\poll\\poll.c",
|
||||
"rt-thread\\components\\libc\\posix\\io\\poll\\select.c",
|
||||
"rt-thread\\components\\libc\\posix\\io\\epoll\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "RS485_port",
|
||||
"path": "board\\ports\\rs485",
|
||||
"files": [
|
||||
"board\\ports\\rs485\\drv_rs485.c",
|
||||
"board\\ports\\rs485\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "rt_usbd",
|
||||
"path": "rt-thread\\components\\legacy\\usb\\usbdevice",
|
||||
"files": [
|
||||
"rt-thread\\components\\legacy\\usb\\usbdevice\\core\\usbdevice.c",
|
||||
"rt-thread\\components\\legacy\\usb\\usbdevice\\class\\cdc_vcom.c",
|
||||
"rt-thread\\components\\legacy\\usb\\usbdevice\\core\\usbdevice_core.c",
|
||||
"rt-thread\\components\\legacy\\usb\\usbdevice\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "rw007",
|
||||
"path": "packages\\rw007-v2.1.0",
|
||||
"files": [
|
||||
"packages\\rw007-v2.1.0\\src\\spi_wifi_rw007.c",
|
||||
"packages\\rw007-v2.1.0\\example\\rw007_stm32_port.c",
|
||||
"packages\\rw007-v2.1.0\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SAL",
|
||||
"path": "rt-thread\\components\\net\\netdev",
|
||||
"files": [
|
||||
"rt-thread\\components\\net\\netdev\\src\\netdev.c",
|
||||
"rt-thread\\components\\net\\netdev\\src\\netdev_ipaddr.c",
|
||||
"rt-thread\\components\\net\\sal\\dfs_net\\dfs_net.c",
|
||||
"rt-thread\\components\\net\\sal\\impl\\af_inet_lwip.c",
|
||||
"rt-thread\\components\\net\\sal\\socket\\net_netdb.c",
|
||||
"rt-thread\\components\\net\\sal\\socket\\net_sockets.c",
|
||||
"rt-thread\\components\\net\\sal\\src\\sal_socket.c",
|
||||
"rt-thread\\components\\net\\netdev\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Utilities",
|
||||
"path": "rt-thread\\components\\utilities\\ulog",
|
||||
"files": [
|
||||
"rt-thread\\components\\utilities\\ulog\\backend\\console_be.c",
|
||||
"rt-thread\\components\\utilities\\ulog\\ulog.c",
|
||||
"rt-thread\\components\\utilities\\ulog\\SConscript"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "vconsole",
|
||||
"path": "packages\\vconsole-latest",
|
||||
"files": [
|
||||
"packages\\vconsole-latest\\vconsole.c",
|
||||
"packages\\vconsole-latest\\SConscript"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
#include "sim.h"
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include <wlan_mgnt.h>
|
||||
#include <wlan_cfg.h>
|
||||
#include <wlan_prot.h>
|
||||
#include <dev_wlan_mgnt.h>
|
||||
#include <dev_wlan_cfg.h>
|
||||
#include <dev_wlan_prot.h>
|
||||
#include <ap3216c.h>
|
||||
#include "my_func.h"
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include <sfud.h>
|
||||
|
||||
#ifdef RT_USING_SFUD
|
||||
#include <spi_flash_sfud.h>
|
||||
#include <dev_spi_flash_sfud.h>
|
||||
#endif
|
||||
|
||||
static int init(void);
|
||||
|
@ -9,8 +9,8 @@
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "spi_flash.h"
|
||||
#include "spi_flash_sfud.h"
|
||||
#include "dev_spi_flash.h"
|
||||
#include "dev_spi_flash_sfud.h"
|
||||
#include <drv_spi.h>
|
||||
#include <drv_gpio.h>
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
#ifdef BSP_USING_PWM
|
||||
#include "drv_config.h"
|
||||
#include "drv_tim.h"
|
||||
#include <drivers/rt_drv_pwm.h>
|
||||
#include <drivers/dev_pwm.h>
|
||||
|
||||
//#define DRV_DEBUG
|
||||
#define LOG_TAG "drv.pwm"
|
||||
|
@ -17,8 +17,8 @@
|
||||
#include <drv_common.h>
|
||||
#include "drv_dma.h"
|
||||
#include <string.h>
|
||||
#include <drivers/mmcsd_core.h>
|
||||
#include <drivers/sdio.h>
|
||||
#include <drivers/dev_mmcsd_core.h>
|
||||
#include <drivers/dev_sdio.h>
|
||||
|
||||
#if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4)
|
||||
#define SDCARD_INSTANCE_TYPE SDIO_TypeDef
|
||||
|
@ -11,7 +11,8 @@
|
||||
[](https://gitter.im/RT-Thread/rt-thread?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://github.com/RT-Thread/rt-thread/pulls)
|
||||
[](https://github.com/RT-Thread/rt-thread/pulls)
|
||||
|
||||
[](https://github.com/RT-Thread/rt-thread/actions/workflows/bsp_buildings.yml)
|
||||
<a href="https://hellogithub.com/repository/5816fc3c1e714d109631ceb377538ca9" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=5816fc3c1e714d109631ceb377538ca9&claim_uid=kVCe5FXIMGAjJfy" alt="Featured|HelloGitHub" style="width: 100px; height: 20px;" width="250" height="54" /></a>
|
||||
# RT-Thread
|
||||
|
||||
RT-Thread was born in 2006, it is an open source, neutral, and community-based real-time operating system (RTOS).
|
||||
|
@ -162,20 +162,32 @@ endif
|
||||
bool "Using devfs for device objects"
|
||||
default y
|
||||
|
||||
config RT_USING_DFS_ROMFS
|
||||
if RT_USING_DFS_V1
|
||||
config RT_USING_DFS_ISO9660
|
||||
bool "Using ISO9660 filesystem"
|
||||
depends on RT_USING_MEMHEAP
|
||||
default n
|
||||
endif
|
||||
|
||||
menuconfig RT_USING_DFS_ROMFS
|
||||
bool "Enable ReadOnly file system on flash"
|
||||
default n
|
||||
|
||||
config RT_USING_DFS_ROMFS_USER_ROOT
|
||||
bool "Use user's romfs root"
|
||||
depends on RT_USING_DFS_ROMFS
|
||||
default n
|
||||
if RT_USING_DFS_ROMFS
|
||||
config RT_USING_DFS_ROMFS_USER_ROOT
|
||||
bool "Use user's romfs root"
|
||||
depends on RT_USING_DFS_V1
|
||||
default n
|
||||
endif
|
||||
|
||||
if RT_USING_SMART
|
||||
config RT_USING_DFS_PTYFS
|
||||
bool "Using Pseudo-Teletype Filesystem (UNIX98 PTY)"
|
||||
depends on RT_USING_DFS_DEVFS
|
||||
default y
|
||||
config RT_USING_DFS_PROCFS
|
||||
bool "Enable proc file system"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_USING_DFS_CROMFS
|
||||
|
@ -1,4 +1,6 @@
|
||||
from building import *
|
||||
from gcc import *
|
||||
import rtconfig
|
||||
import os
|
||||
|
||||
# The set of source files associated with this SConscript file.
|
||||
@ -6,6 +8,7 @@ src = []
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd + "/include"]
|
||||
group = []
|
||||
LOCAL_CFLAGS = ''
|
||||
|
||||
if GetDepend('RT_USING_DFS') and not GetDepend('RT_USING_DFS_V2'):
|
||||
src = ['src/dfs.c', 'src/dfs_file.c', 'src/dfs_fs.c']
|
||||
@ -13,7 +16,12 @@ if GetDepend('RT_USING_DFS') and not GetDepend('RT_USING_DFS_V2'):
|
||||
if GetDepend('DFS_USING_POSIX'):
|
||||
src += ['src/dfs_posix.c']
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS'], CPPPATH = CPPPATH)
|
||||
if rtconfig.PLATFORM in GetGCCLikePLATFORM():
|
||||
LOCAL_CFLAGS += ' -std=c99'
|
||||
elif rtconfig.PLATFORM in ['armcc']:
|
||||
LOCAL_CFLAGS += ' --c99'
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS'], CPPPATH = CPPPATH, LOCAL_CFLAGS = LOCAL_CFLAGS)
|
||||
|
||||
# search in the file system implementation
|
||||
list = os.listdir(cwd)
|
||||
|
@ -0,0 +1,11 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_ISO9660'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
@ -0,0 +1,698 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtservice.h>
|
||||
|
||||
#define DBG_TAG "dfs.iso9660"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "dfs_iso9660.h"
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <dfs_file.h>
|
||||
#include <posix/string.h>
|
||||
#include <drivers/misc.h>
|
||||
#include <drivers/byteorder.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#define ISO9660_FSTYPE_DIR 0040000
|
||||
#define ISO9660_FSTYPE_REG 0100000
|
||||
#define ISO9660_FSTYPE_SYMLINK 0120000
|
||||
#define ISO9660_FSTYPE_MASK 0170000
|
||||
|
||||
#define ISO9660_BLKSZ 2048
|
||||
|
||||
#define ISO9660_VOLDESC_BOOT 0
|
||||
#define ISO9660_VOLDESC_PRIMARY 1
|
||||
#define ISO9660_VOLDESC_SUPP 2
|
||||
#define ISO9660_VOLDESC_PART 3
|
||||
#define ISO9660_VOLDESC_END 255
|
||||
|
||||
rt_packed(struct iso9660_voldesc
|
||||
{
|
||||
rt_uint8_t type;
|
||||
rt_uint8_t magic[5];
|
||||
rt_uint8_t version;
|
||||
});
|
||||
|
||||
rt_packed(struct iso9660_date2
|
||||
{
|
||||
rt_uint8_t year;
|
||||
rt_uint8_t month;
|
||||
rt_uint8_t day;
|
||||
rt_uint8_t hour;
|
||||
rt_uint8_t minute;
|
||||
rt_uint8_t second;
|
||||
rt_uint8_t offset;
|
||||
});
|
||||
|
||||
/* Directory entry */
|
||||
rt_packed(struct iso9660_dir
|
||||
{
|
||||
rt_uint8_t len;
|
||||
rt_uint8_t ext_sectors;
|
||||
rt_le32_t first_sector;
|
||||
rt_le32_t first_sector_be;
|
||||
rt_le32_t size;
|
||||
rt_le32_t size_be;
|
||||
struct iso9660_date2 mtime;
|
||||
#define FLAG_TYPE_PLAIN 0
|
||||
#define FLAG_TYPE_DIR 2
|
||||
#define FLAG_TYPE 3
|
||||
#define FLAG_MORE_EXTENTS 0x80
|
||||
rt_uint8_t flags;
|
||||
rt_uint8_t file_unit_size;
|
||||
rt_uint8_t interleave_gap_size;
|
||||
rt_le16_t vol_seq_num;
|
||||
rt_le16_t vol_seq_num_be;
|
||||
#define MAX_NAMELEN 255
|
||||
rt_uint8_t namelen;
|
||||
char name[0];
|
||||
});
|
||||
|
||||
rt_packed(struct iso9660_date
|
||||
{
|
||||
rt_uint8_t year[4];
|
||||
rt_uint8_t month[2];
|
||||
rt_uint8_t day[2];
|
||||
rt_uint8_t hour[2];
|
||||
rt_uint8_t minute[2];
|
||||
rt_uint8_t second[2];
|
||||
rt_uint8_t hundredth[2];
|
||||
rt_uint8_t offset;
|
||||
});
|
||||
|
||||
/* Common volume descriptor */
|
||||
rt_packed(struct iso9660_common_voldesc
|
||||
{
|
||||
struct iso9660_voldesc voldesc;
|
||||
rt_uint8_t sysname[33];
|
||||
rt_uint8_t volname[32];
|
||||
rt_uint8_t unused2[8];
|
||||
rt_le32_t vol_space_size_le;
|
||||
rt_le32_t vol_space_size_be;
|
||||
rt_uint8_t escape[32];
|
||||
rt_le16_t vol_set_size_le;
|
||||
rt_le16_t vol_set_size_be;
|
||||
rt_le16_t vol_seq_num_le;
|
||||
rt_le16_t vol_seq_num_be;
|
||||
rt_le16_t logical_block_size_le;
|
||||
rt_le16_t logical_block_size_be;
|
||||
rt_le32_t path_table_size;
|
||||
rt_le32_t path_table_size_be;
|
||||
rt_le32_t path_table;
|
||||
rt_le32_t path_table_be;
|
||||
rt_uint8_t unused3[8];
|
||||
struct iso9660_dir rootdir;
|
||||
rt_uint8_t unused4[624];
|
||||
struct iso9660_date created;
|
||||
struct iso9660_date modified;
|
||||
rt_uint8_t unused5[0 /* 1201 */];
|
||||
});
|
||||
|
||||
struct iso9660
|
||||
{
|
||||
struct rt_device *dev;
|
||||
|
||||
rt_uint8_t joliet;
|
||||
rt_uint8_t swap[ISO9660_BLKSZ];
|
||||
|
||||
struct iso9660_common_voldesc primary, supp;
|
||||
};
|
||||
|
||||
struct iso9660_fd
|
||||
{
|
||||
struct iso9660 *iso;
|
||||
|
||||
struct iso9660_dir dirent;
|
||||
};
|
||||
|
||||
struct iso9660_iterate
|
||||
{
|
||||
struct iso9660_fd *fd;
|
||||
|
||||
int i, index, count;
|
||||
struct dirent *dirp;
|
||||
};
|
||||
|
||||
static void iso9660_convert_string(char *dest, rt_uint16_t *src, int len)
|
||||
{
|
||||
/* UTF16 to ASCII */
|
||||
len >>= 1;
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
rt_uint16_t utf16 = rt_be16_to_cpu(*src++);
|
||||
|
||||
if (utf16 < 0x80)
|
||||
{
|
||||
*dest++ = (rt_uint8_t)utf16;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dest++ = '?';
|
||||
}
|
||||
}
|
||||
*dest = '\0';
|
||||
}
|
||||
|
||||
static void iso9660_convert_lower(char *dest, rt_uint8_t *src, int len)
|
||||
{
|
||||
for (int i = 0; i < len; ++i, ++src)
|
||||
{
|
||||
if (*src >= 'A' && *src <= 'Z')
|
||||
{
|
||||
*dest++ = *src - ('A' - 'a');
|
||||
}
|
||||
else
|
||||
{
|
||||
*dest++ = *src;
|
||||
}
|
||||
}
|
||||
|
||||
*dest = '\0';
|
||||
}
|
||||
|
||||
static time_t iso9660_convert_unixtime(struct iso9660_date *date)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
tm.tm_sec = (date->second[0] - '0') * 10 + (date->second[1] - '0');
|
||||
tm.tm_min = (date->minute[0] - '0') * 10 + (date->minute[1] - '0');
|
||||
tm.tm_hour = (date->hour[0] - '0') * 10 + (date->hour[1] - '0');
|
||||
tm.tm_mday = (date->day[0] - '0') * 10 + (date->day[1] - '0');
|
||||
tm.tm_mon = (date->month[0] - '0') * 10 + (date->month[1] - '0');
|
||||
tm.tm_year = (date->year[0] - '0') * 1000 + (date->year[1] - '0') * 100 +
|
||||
(date->year[2] - '0') * 10 + (date->year[3] - '0');
|
||||
tm.tm_wday = 0;
|
||||
|
||||
return mktime(&tm);
|
||||
}
|
||||
|
||||
static time_t iso9660_convert_unixtime2(struct iso9660_date2 *date)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
tm.tm_sec = date->second;
|
||||
tm.tm_min = date->minute;
|
||||
tm.tm_hour = date->hour;
|
||||
tm.tm_mday = date->day;
|
||||
tm.tm_mon = date->month;
|
||||
tm.tm_year = date->year + 1900;
|
||||
tm.tm_wday = 0;
|
||||
|
||||
return mktime(&tm);
|
||||
}
|
||||
|
||||
static struct iso9660_fd *iso9660_lookup(struct iso9660 *iso, const char *path,
|
||||
struct iso9660_iterate *it)
|
||||
{
|
||||
rt_uint32_t lba;
|
||||
rt_size_t sz, len, namelen;
|
||||
char sname[MAX_NAMELEN];
|
||||
struct iso9660_fd *fd;
|
||||
struct iso9660_dir *dirent;
|
||||
|
||||
if (it)
|
||||
{
|
||||
fd = it->fd;
|
||||
iso = fd->iso;
|
||||
dirent = &fd->dirent;
|
||||
|
||||
/* No next entry, always goon */
|
||||
len = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(fd = rt_malloc(sizeof(*fd))))
|
||||
{
|
||||
return fd;
|
||||
}
|
||||
|
||||
fd->iso = iso;
|
||||
dirent = iso->joliet ? &iso->supp.rootdir : &iso->primary.rootdir;
|
||||
|
||||
if (!rt_strcmp(path, "/"))
|
||||
{
|
||||
rt_memcpy(&fd->dirent, dirent, sizeof(*dirent));
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Skip the first '/' */
|
||||
++path;
|
||||
len = strchrnul(path, '/') - path;
|
||||
}
|
||||
|
||||
lba = rt_le32_to_cpu(dirent->first_sector);
|
||||
if (rt_device_read(iso->dev, lba, iso->swap, 1) <= 0)
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
dirent = (void *)iso->swap;
|
||||
sz = 0;
|
||||
|
||||
do {
|
||||
/* Ignore "." and ".." */
|
||||
do {
|
||||
rt_uint32_t dlen = rt_le32_to_cpu(dirent->len);
|
||||
|
||||
dirent = (void *)dirent + dlen;
|
||||
sz += dlen;
|
||||
|
||||
if (ISO9660_BLKSZ - sz < sizeof(*dirent))
|
||||
{
|
||||
/* Sector end, goto the next sector */
|
||||
if (rt_device_read(iso->dev, ++lba, iso->swap, 1) <= 0)
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
dirent = (void *)iso->swap;
|
||||
sz = 0;
|
||||
}
|
||||
|
||||
if (rt_le32_to_cpu(dirent->first_sector) == 0)
|
||||
{
|
||||
/* Is end, no found. */
|
||||
goto _fail;
|
||||
}
|
||||
} while (dirent->name[0] >> 1 == 0 && rt_le32_to_cpu(dirent->namelen) == 1);
|
||||
|
||||
namelen = rt_le32_to_cpu(dirent->namelen);
|
||||
|
||||
if (iso->joliet)
|
||||
{
|
||||
iso9660_convert_string(sname, (rt_uint16_t *)dirent->name, namelen);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(rt_le32_to_cpu(dirent->flags) & FLAG_TYPE_DIR))
|
||||
{
|
||||
/* Remove ";1" */
|
||||
namelen -= 2;
|
||||
}
|
||||
|
||||
iso9660_convert_lower(sname, (rt_uint8_t *)dirent->name, namelen);
|
||||
}
|
||||
|
||||
if (it)
|
||||
{
|
||||
if (it->i < it->index)
|
||||
{
|
||||
goto _next;
|
||||
}
|
||||
|
||||
if ((rt_le32_to_cpu(dirent->flags) & FLAG_TYPE) == FLAG_TYPE_DIR)
|
||||
{
|
||||
it->dirp->d_type = DT_DIR;
|
||||
}
|
||||
else
|
||||
{
|
||||
it->dirp->d_type = DT_REG;
|
||||
}
|
||||
|
||||
it->dirp->d_namlen = namelen;
|
||||
rt_strncpy(it->dirp->d_name, sname, namelen);
|
||||
it->dirp->d_name[namelen] = '\0';
|
||||
it->dirp->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
||||
|
||||
++it->dirp;
|
||||
|
||||
_next:
|
||||
++it->i;
|
||||
|
||||
if (it->i - it->index >= it->count)
|
||||
{
|
||||
/* Iterate end */
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/* No next entry */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rt_strncmp(sname, path, len))
|
||||
{
|
||||
/* The end of path, found ok */
|
||||
if (!path[len])
|
||||
{
|
||||
rt_memcpy(&fd->dirent, dirent, sizeof(*dirent));
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
lba = rt_le32_to_cpu(dirent->first_sector);
|
||||
if (rt_device_read(iso->dev, lba, iso->swap, 1) <= 0)
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
dirent = (void *)iso->swap;
|
||||
sz = 0;
|
||||
|
||||
path += len + 1;
|
||||
len = strchrnul(path, '/') - path;
|
||||
}
|
||||
} while (len);
|
||||
|
||||
_fail:
|
||||
if (!it)
|
||||
{
|
||||
rt_free(fd);
|
||||
}
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
static int dfs_iso9660_open(struct dfs_file *fd)
|
||||
{
|
||||
struct iso9660 *iso = fd->vnode->fs->data;
|
||||
|
||||
fd->vnode->data = iso9660_lookup(iso, fd->vnode->path, RT_NULL);
|
||||
|
||||
return fd->vnode->data ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
static int dfs_iso9660_close(struct dfs_file *fd)
|
||||
{
|
||||
struct iso9660_fd *iso_fd = fd->vnode->data;
|
||||
|
||||
rt_free(iso_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dfs_iso9660_read(struct dfs_file *fd, void *buf, size_t count)
|
||||
{
|
||||
rt_uint32_t pos;
|
||||
void *buf_ptr;
|
||||
ssize_t read_blk, toread_blk;
|
||||
size_t rcount = 0, remain, size;
|
||||
struct iso9660_fd *iso_fd = fd->vnode->data;
|
||||
struct iso9660 *iso = iso_fd->iso;
|
||||
|
||||
if (fd->pos + count > rt_le32_to_cpu(iso_fd->dirent.size))
|
||||
{
|
||||
count = rt_le32_to_cpu(iso_fd->dirent.size) - fd->pos;
|
||||
}
|
||||
pos = rt_le32_to_cpu(iso_fd->dirent.first_sector);
|
||||
|
||||
/* Align to a sector */
|
||||
if (fd->pos)
|
||||
{
|
||||
pos += fd->pos / ISO9660_BLKSZ;
|
||||
remain = fd->pos & (ISO9660_BLKSZ - 1);
|
||||
|
||||
if (rt_device_read(iso->dev, pos, iso->swap, 1) <= 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
size = rt_min_t(size_t, ISO9660_BLKSZ - remain, count);
|
||||
rt_memcpy(buf, &iso->swap[remain], size);
|
||||
rcount += size;
|
||||
count -= size;
|
||||
buf += size;
|
||||
pos += 1;
|
||||
fd->pos += size;
|
||||
|
||||
if (!count)
|
||||
{
|
||||
goto _end;
|
||||
}
|
||||
}
|
||||
|
||||
remain = count & (ISO9660_BLKSZ - 1);
|
||||
count = rt_max_t(size_t, count / ISO9660_BLKSZ, 1);
|
||||
|
||||
while ((ssize_t)count > 0)
|
||||
{
|
||||
if (count == 1)
|
||||
{
|
||||
buf_ptr = iso->swap;
|
||||
toread_blk = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf_ptr = buf;
|
||||
toread_blk = count;
|
||||
}
|
||||
|
||||
read_blk = rt_device_read(iso->dev, pos, buf_ptr, toread_blk);
|
||||
|
||||
if (read_blk <= 0)
|
||||
{
|
||||
return (int)read_blk;
|
||||
}
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
size = remain;
|
||||
rt_memcpy(buf, iso->swap, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
size = read_blk * ISO9660_BLKSZ;
|
||||
}
|
||||
|
||||
rcount += size;
|
||||
count -= read_blk;
|
||||
buf += size;
|
||||
pos += read_blk;
|
||||
fd->pos += size;
|
||||
}
|
||||
|
||||
_end:
|
||||
return rcount;
|
||||
}
|
||||
|
||||
static off_t dfs_iso9660_lseek(struct dfs_file *fd, off_t offset)
|
||||
{
|
||||
int ret = -EIO;
|
||||
|
||||
if (offset <= fd->vnode->size)
|
||||
{
|
||||
fd->pos = offset;
|
||||
ret = fd->pos;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_iso9660_getdents(struct dfs_file *fd, struct dirent *dirp, uint32_t count)
|
||||
{
|
||||
struct iso9660_iterate it;
|
||||
struct iso9660_fd *iso_fd = fd->vnode->data;
|
||||
|
||||
count = (count / sizeof(struct dirent));
|
||||
|
||||
if (!count)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
it.fd = iso_fd;
|
||||
it.i = 0;
|
||||
it.index = fd->pos;
|
||||
it.count = count;
|
||||
it.dirp = dirp;
|
||||
|
||||
iso9660_lookup(RT_NULL, RT_NULL, &it);
|
||||
|
||||
count = it.i - it.index;
|
||||
if (count > 0)
|
||||
{
|
||||
fd->pos += count;
|
||||
}
|
||||
|
||||
count *= sizeof(struct dirent);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops _iso9660_fops =
|
||||
{
|
||||
.open = dfs_iso9660_open,
|
||||
.close = dfs_iso9660_close,
|
||||
.read = dfs_iso9660_read,
|
||||
.lseek = dfs_iso9660_lseek,
|
||||
.getdents = dfs_iso9660_getdents,
|
||||
};
|
||||
|
||||
static int dfs_iso9660_mount(struct dfs_filesystem *fs,
|
||||
unsigned long rwflag, const void *data)
|
||||
{
|
||||
int err;
|
||||
struct iso9660 *iso;
|
||||
struct iso9660_voldesc *voldesc;
|
||||
struct rt_device_blk_geometry geometry;
|
||||
|
||||
if (!(iso = rt_malloc(sizeof(*iso))))
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
iso->dev = fs->dev_id;
|
||||
rt_device_control(iso->dev, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
|
||||
|
||||
if (geometry.bytes_per_sector != ISO9660_BLKSZ)
|
||||
{
|
||||
LOG_E("%s: Logical block size = %d is not supported",
|
||||
iso->dev->parent.name, geometry.bytes_per_sector);
|
||||
|
||||
err = -EINVAL;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
iso->primary.rootdir.first_sector = 0;
|
||||
iso->supp.rootdir.first_sector = 0;
|
||||
|
||||
/* LBA 0-15 is the bootloader's information */
|
||||
for (int lba = 16; ; ++lba)
|
||||
{
|
||||
if (rt_device_read(iso->dev, lba, &iso->swap, 1) <= 0)
|
||||
{
|
||||
err = -EIO;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
voldesc = (void *)iso->swap;
|
||||
|
||||
if (rt_strncmp((char *)voldesc->magic, "CD001", 5))
|
||||
{
|
||||
LOG_E("%s: Invalid magic \"%s\"", voldesc->magic);
|
||||
|
||||
err = -EINVAL;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
if (voldesc->type == ISO9660_VOLDESC_BOOT)
|
||||
{
|
||||
LOG_D("System Name: %s", ((struct iso9660_common_voldesc *)voldesc)->sysname);
|
||||
LOG_D("Volume Name: %s", ((struct iso9660_common_voldesc *)voldesc)->volname);
|
||||
}
|
||||
else if (voldesc->type == ISO9660_VOLDESC_PRIMARY)
|
||||
{
|
||||
iso->joliet = 0;
|
||||
rt_memcpy(&iso->primary, &iso->swap, sizeof(iso->primary));
|
||||
}
|
||||
else if (voldesc->type == ISO9660_VOLDESC_SUPP)
|
||||
{
|
||||
rt_memcpy(&iso->supp, &iso->swap, sizeof(iso->supp));
|
||||
|
||||
if (iso->supp.escape[0] == 0x25 && iso->supp.escape[1] == 0x2f)
|
||||
{
|
||||
if (iso->supp.escape[2] == 0x40)
|
||||
{
|
||||
iso->joliet = 1;
|
||||
}
|
||||
else if (iso->supp.escape[2] == 0x43)
|
||||
{
|
||||
iso->joliet = 2;
|
||||
}
|
||||
else if (iso->supp.escape[2] == 0x45)
|
||||
{
|
||||
iso->joliet = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (voldesc->type == ISO9660_VOLDESC_PART)
|
||||
{
|
||||
LOG_D("System Name: %s", ((struct iso9660_common_voldesc *)voldesc)->sysname);
|
||||
LOG_D("Volume Name: %s", ((struct iso9660_common_voldesc *)voldesc)->volname);
|
||||
}
|
||||
else if (voldesc->type == ISO9660_VOLDESC_END)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iso->primary.rootdir.first_sector || !iso->supp.rootdir.first_sector)
|
||||
{
|
||||
LOG_E("No primary or secondary partition found");
|
||||
|
||||
err = -EINVAL;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
fs->data = iso;
|
||||
|
||||
return 0;
|
||||
|
||||
_fail:
|
||||
rt_free(iso);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dfs_iso9660_unmount(struct dfs_filesystem *fs)
|
||||
{
|
||||
struct iso9660 *iso = fs->data;
|
||||
|
||||
rt_free(iso);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dfs_iso9660_stat(struct dfs_filesystem *fs,
|
||||
const char *filename, struct stat *st)
|
||||
{
|
||||
struct iso9660 *iso = fs->data;
|
||||
struct iso9660_fd *fd = iso9660_lookup(iso, filename, RT_NULL);
|
||||
|
||||
if (!fd)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
st->st_dev = 0;
|
||||
st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
|
||||
S_IWUSR | S_IWGRP | S_IWOTH;
|
||||
|
||||
if ((fd->dirent.flags & FLAG_TYPE) == FLAG_TYPE_DIR)
|
||||
{
|
||||
st->st_mode &= ~S_IFREG;
|
||||
st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
|
||||
}
|
||||
|
||||
st->st_atime = iso9660_convert_unixtime(iso->joliet ?
|
||||
&iso->supp.created : &iso->primary.created);
|
||||
st->st_mtime = iso9660_convert_unixtime2(&fd->dirent.mtime);
|
||||
st->st_size = rt_le32_to_cpu(fd->dirent.size);
|
||||
|
||||
rt_free(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dfs_filesystem_ops _iso9660 =
|
||||
{
|
||||
.name = "iso9660",
|
||||
.flags = DFS_FS_FLAG_DEFAULT,
|
||||
.fops = &_iso9660_fops,
|
||||
|
||||
.mount = dfs_iso9660_mount,
|
||||
.unmount = dfs_iso9660_unmount,
|
||||
|
||||
.stat = dfs_iso9660_stat,
|
||||
};
|
||||
|
||||
int dfs_iso9660_init(void)
|
||||
{
|
||||
/* register iso9660 file system */
|
||||
return dfs_register(&_iso9660);
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(dfs_iso9660_init);
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __DFS_ISO9660_H__
|
||||
#define __DFS_ISO9660_H__
|
||||
|
||||
int dfs_iso9660_init(void);
|
||||
|
||||
#endif /* __DFS_ISO9660_H__ */
|
@ -92,7 +92,7 @@ struct ramfs_dirent *dfs_ramfs_lookup(struct dfs_ramfs *ramfs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dfs_ramfs_read(struct dfs_file *file, void *buf, size_t count)
|
||||
ssize_t dfs_ramfs_read(struct dfs_file *file, void *buf, size_t count)
|
||||
{
|
||||
rt_size_t length;
|
||||
struct ramfs_dirent *dirent;
|
||||
@ -114,7 +114,7 @@ int dfs_ramfs_read(struct dfs_file *file, void *buf, size_t count)
|
||||
return length;
|
||||
}
|
||||
|
||||
int dfs_ramfs_write(struct dfs_file *fd, const void *buf, size_t count)
|
||||
ssize_t dfs_ramfs_write(struct dfs_file *fd, const void *buf, size_t count)
|
||||
{
|
||||
struct ramfs_dirent *dirent;
|
||||
struct dfs_ramfs *ramfs;
|
||||
@ -151,7 +151,7 @@ int dfs_ramfs_write(struct dfs_file *fd, const void *buf, size_t count)
|
||||
return count;
|
||||
}
|
||||
|
||||
int dfs_ramfs_lseek(struct dfs_file *file, off_t offset)
|
||||
off_t dfs_ramfs_lseek(struct dfs_file *file, off_t offset)
|
||||
{
|
||||
if (offset <= (off_t)file->vnode->size)
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -107,7 +107,8 @@ int dfs_init(void)
|
||||
INIT_PREV_EXPORT(dfs_init);
|
||||
|
||||
/**
|
||||
* this function will lock device file system.
|
||||
* @brief this function will lock device file system.
|
||||
* this lock (fslock) is used for protecting filesystem_operation_table and filesystem_table.
|
||||
*
|
||||
* @note please don't invoke it on ISR.
|
||||
*/
|
||||
@ -126,6 +127,12 @@ void dfs_lock(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief this function will lock file descriptors.
|
||||
* this lock (fdlock) is used for protecting fd table (_fdtab).
|
||||
*
|
||||
* @note please don't invoke it on ISR.
|
||||
*/
|
||||
void dfs_file_lock(void)
|
||||
{
|
||||
rt_err_t result = -RT_EBUSY;
|
||||
@ -142,7 +149,7 @@ void dfs_file_lock(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will lock device file system.
|
||||
* @brief this function will unlock device file system.
|
||||
*
|
||||
* @note please don't invoke it on ISR.
|
||||
*/
|
||||
@ -151,33 +158,56 @@ void dfs_unlock(void)
|
||||
rt_mutex_release(&fslock);
|
||||
}
|
||||
|
||||
#ifdef DFS_USING_POSIX
|
||||
|
||||
/**
|
||||
* @brief this function will unlock fd table.
|
||||
*/
|
||||
void dfs_file_unlock(void)
|
||||
{
|
||||
rt_mutex_release(&fdlock);
|
||||
}
|
||||
|
||||
#ifdef DFS_USING_POSIX
|
||||
/**
|
||||
* @brief Expand the file descriptor table to accommodate a specific file descriptor.
|
||||
*
|
||||
* This function ensures that the file descriptor table in the given `dfs_fdtable` structure
|
||||
* has sufficient capacity to include the specified file descriptor `fd`. If the table
|
||||
* needs to be expanded, it reallocates memory and initializes new slots to `NULL`.
|
||||
*
|
||||
* @param fdt Pointer to the `dfs_fdtable` structure representing the file descriptor table.
|
||||
* @param fd The file descriptor that the table must accommodate.
|
||||
* @return int
|
||||
* - The input file descriptor `fd` if it is within the current or newly expanded table's capacity.
|
||||
* - `-1` if the requested file descriptor exceeds `DFS_FD_MAX` or memory allocation fails.
|
||||
*/
|
||||
static int fd_slot_expand(struct dfs_fdtable *fdt, int fd)
|
||||
{
|
||||
int nr;
|
||||
int index;
|
||||
struct dfs_file **fds = NULL;
|
||||
|
||||
/* If the file descriptor is already within the current capacity, no expansion is needed.*/
|
||||
if (fd < fdt->maxfd)
|
||||
{
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* If the file descriptor exceeds the maximum allowable limit, return an error.*/
|
||||
if (fd >= DFS_FD_MAX)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Calculate the new capacity, rounding up to the nearest multiple of 4.*/
|
||||
nr = ((fd + 4) & ~3);
|
||||
|
||||
/* Ensure the new capacity does not exceed the maximum limit.*/
|
||||
if (nr > DFS_FD_MAX)
|
||||
{
|
||||
nr = DFS_FD_MAX;
|
||||
}
|
||||
|
||||
/* Attempt to reallocate the file descriptor table to the new capacity.*/
|
||||
fds = (struct dfs_file **)rt_realloc(fdt->fds, nr * sizeof(struct dfs_file *));
|
||||
if (!fds)
|
||||
{
|
||||
@ -189,12 +219,23 @@ static int fd_slot_expand(struct dfs_fdtable *fdt, int fd)
|
||||
{
|
||||
fds[index] = NULL;
|
||||
}
|
||||
|
||||
/* Update the file descriptor table and its capacity.*/
|
||||
fdt->fds = fds;
|
||||
fdt->maxfd = nr;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate a file descriptor slot starting from a specified index.
|
||||
*
|
||||
* @param fdt fdt Pointer to the `dfs_fdtable` structure representing the file descriptor table.
|
||||
* @param startfd The starting index for the search for an empty slot.
|
||||
* @return int
|
||||
* - The index of the first available slot if successful.
|
||||
* - `-1` if no slot is available or if table expansion fails
|
||||
*/
|
||||
static int fd_slot_alloc(struct dfs_fdtable *fdt, int startfd)
|
||||
{
|
||||
int idx;
|
||||
@ -219,6 +260,17 @@ static int fd_slot_alloc(struct dfs_fdtable *fdt, int startfd)
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate a new file descriptor and associate it with a newly allocated `struct dfs_file`.
|
||||
*
|
||||
* @param fdt Pointer to the `dfs_fdtable` structure representing the file descriptor table.
|
||||
* @param startfd The starting index for searching an available file descriptor slot.
|
||||
*
|
||||
* @return
|
||||
* - The index of the allocated file descriptor if successful.
|
||||
* - `-1` if no slot is available or memory allocation fails.
|
||||
*/
|
||||
static int fd_alloc(struct dfs_fdtable *fdt, int startfd)
|
||||
{
|
||||
int idx;
|
||||
@ -323,7 +375,11 @@ struct dfs_file *fd_get(int fd)
|
||||
/**
|
||||
* @ingroup Fd
|
||||
*
|
||||
* This function will put the file descriptor.
|
||||
* @brief This function will release the file descriptor.
|
||||
*
|
||||
* This function releases a file descriptor slot in the file descriptor table, decrements reference
|
||||
* counts, and cleans up resources associated with the `dfs_file` and `dfs_vnode` structures when applicable.
|
||||
*
|
||||
*/
|
||||
void fdt_fd_release(struct dfs_fdtable* fdt, int fd)
|
||||
{
|
||||
@ -378,6 +434,20 @@ void fd_release(int fd)
|
||||
fdt_fd_release(fdt, fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Duplicates a file descriptor.
|
||||
*
|
||||
* This function duplicates an existing file descriptor (`oldfd`) and returns
|
||||
* a new file descriptor that refers to the same underlying file object.
|
||||
*
|
||||
* @param oldfd The file descriptor to duplicate. It must be a valid file
|
||||
* descriptor within the range of allocated descriptors.
|
||||
*
|
||||
* @return The new file descriptor if successful, or a negative value
|
||||
* (e.g., -1) if an error occurs.
|
||||
*
|
||||
* @see sys_dup2()
|
||||
*/
|
||||
rt_err_t sys_dup(int oldfd)
|
||||
{
|
||||
int newfd = -1;
|
||||
@ -470,6 +540,23 @@ int fd_is_open(const char *pathname)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Duplicates a file descriptor to a specified file descriptor.
|
||||
*
|
||||
* This function duplicates an existing file descriptor (`oldfd`) and assigns it
|
||||
* to the specified file descriptor (`newfd`).
|
||||
*
|
||||
* @param oldfd The file descriptor to duplicate. It must be a valid and open file
|
||||
* descriptor within the range of allocated descriptors.
|
||||
* @param newfd The target file descriptor. If `newfd` is already in use, it will
|
||||
* be closed before duplication. If `newfd` exceeds the current file
|
||||
* descriptor table size, the table will be expanded to accommodate it.
|
||||
*
|
||||
* @return The value of `newfd` on success, or a negative value (e.g., -1) if an
|
||||
* error occurs.
|
||||
*
|
||||
* @see sys_dup()
|
||||
*/
|
||||
rt_err_t sys_dup2(int oldfd, int newfd)
|
||||
{
|
||||
struct dfs_fdtable *fdt = NULL;
|
||||
@ -550,6 +637,10 @@ static int fd_get_fd_index_form_fdt(struct dfs_fdtable *fdt, struct dfs_file *fi
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get fd (index) by dfs file object.
|
||||
*
|
||||
*/
|
||||
int fd_get_fd_index(struct dfs_file *file)
|
||||
{
|
||||
struct dfs_fdtable *fdt;
|
||||
@ -558,6 +649,21 @@ int fd_get_fd_index(struct dfs_file *file)
|
||||
return fd_get_fd_index_form_fdt(fdt, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Associates a file descriptor with a file object.
|
||||
*
|
||||
* This function associates a given file descriptor (`fd`) with a specified
|
||||
* file object (`file`) in the file descriptor table (`fdt`).
|
||||
*
|
||||
* @param fdt The file descriptor table to operate on. It must be a valid
|
||||
* and initialized `dfs_fdtable` structure.
|
||||
* @param fd The file descriptor to associate. It must be within the range
|
||||
* of allocated file descriptors and currently unoccupied.
|
||||
* @param file The file object to associate with the file descriptor. It must
|
||||
* be a valid and initialized `dfs_file` structure.
|
||||
*
|
||||
* @return The value of `fd` on success, or -1 if an error occurs.
|
||||
*/
|
||||
int fd_associate(struct dfs_fdtable *fdt, int fd, struct dfs_file *file)
|
||||
{
|
||||
int retfd = -1;
|
||||
@ -591,6 +697,10 @@ exit:
|
||||
return retfd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief initialize a dfs file object.
|
||||
*
|
||||
*/
|
||||
void fd_init(struct dfs_file *fd)
|
||||
{
|
||||
if (fd)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -18,10 +18,12 @@
|
||||
|
||||
#define DFS_VNODE_HASH_NR 128
|
||||
|
||||
/*dfs vnode manager, for saving and searching vnodes.*/
|
||||
struct dfs_vnode_mgr
|
||||
{
|
||||
struct rt_mutex lock;
|
||||
rt_list_t head[DFS_VNODE_HASH_NR];
|
||||
struct rt_mutex lock; /* mutex for protecting dfs vnode lists */
|
||||
rt_list_t head[DFS_VNODE_HASH_NR]; /* a group of dfs vnode lists, the dfs vnode is inserted to one of the lists
|
||||
according to path string's hash-value mod DFS_VNODE_HASH_NR. */
|
||||
};
|
||||
|
||||
static struct dfs_vnode_mgr dfs_fm;
|
||||
@ -36,6 +38,10 @@ void dfs_fm_unlock(void)
|
||||
rt_mutex_release(&dfs_fm.lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize dfs vnode manager structure, including a lock and hash tables for vnode.
|
||||
*
|
||||
*/
|
||||
void dfs_vnode_mgr_init(void)
|
||||
{
|
||||
int i = 0;
|
||||
@ -47,6 +53,23 @@ void dfs_vnode_mgr_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize a DFS vnode structure.
|
||||
*
|
||||
* @param vnode Pointer to the DFS vnode structure to be initialized.
|
||||
* The caller must ensure this is a valid, allocated structure.
|
||||
* @param type The type of the vnode, representing its role or category (e.g., regular file, directory).
|
||||
* @param fops Pointer to the file operations structure associated with this vnode.
|
||||
* This structure defines the behavior of the vnode for operations such as open, read, write, etc.
|
||||
* If `fops` is NULL, the vnode will have no associated file operations.
|
||||
*
|
||||
* @return 0 on success, or a negative error code on failure.
|
||||
*
|
||||
* @note The caller should ensure that:
|
||||
* - The `vnode` pointer is valid and properly allocated.
|
||||
* - The `fops` pointer (if not NULL) points to a valid `struct dfs_file_ops`
|
||||
* instance, where all necessary function pointers are properly set.
|
||||
*/
|
||||
int dfs_vnode_init(struct dfs_vnode *vnode, int type, const struct dfs_file_ops *fops)
|
||||
{
|
||||
if (vnode)
|
||||
@ -64,7 +87,7 @@ int dfs_vnode_init(struct dfs_vnode *vnode, int type, const struct dfs_file_ops
|
||||
/* BKDR Hash Function */
|
||||
static unsigned int bkdr_hash(const char *str)
|
||||
{
|
||||
unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
|
||||
unsigned int seed = 131; /* 31 131 1313 13131 131313 etc..*/
|
||||
unsigned int hash = 0;
|
||||
|
||||
while (*str)
|
||||
@ -75,6 +98,22 @@ static unsigned int bkdr_hash(const char *str)
|
||||
return (hash % DFS_VNODE_HASH_NR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find a DFS vnode by its path.
|
||||
*
|
||||
* This function searches for a vnode in the vnode hash table using the specified path.
|
||||
* If found, it returns a pointer to the vnode and updates the hash head if required.
|
||||
*
|
||||
* @param path The file path to search for. This should be a valid null-terminated string.
|
||||
* @param hash_head Pointer to a location where the hash table head associated with the vnode
|
||||
* can be stored. This can be NULL if the hash head is not needed.
|
||||
*
|
||||
* @return Pointer to the DFS vnode if found, or NULL if no vnode matches the specified path.
|
||||
*
|
||||
* @note The caller must ensure that:
|
||||
* - The `path` pointer is valid and points to a properly null-terminated string.
|
||||
* - If `hash_head` is not NULL, it points to a valid location to store the hash head.
|
||||
*/
|
||||
static struct dfs_vnode *dfs_vnode_find(const char *path, rt_list_t **hash_head)
|
||||
{
|
||||
struct dfs_vnode *vnode = NULL;
|
||||
@ -329,11 +368,12 @@ int dfs_file_close(struct dfs_file *fd)
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will perform a io control on a file descriptor.
|
||||
* this function will perform an io control on a file descriptor.
|
||||
*
|
||||
* @param fd the file descriptor.
|
||||
* @param cmd the command to send to file descriptor.
|
||||
* @param args the argument to send to file descriptor.
|
||||
* - When `cmd` is `F_SETFL`, an additional integer argument specifies the new status flags.
|
||||
*
|
||||
* @return 0 on successful, -1 on failed.
|
||||
*/
|
||||
@ -846,7 +886,7 @@ void cat(const char *filename)
|
||||
{
|
||||
buffer[length] = '\0';
|
||||
rt_device_t out_device = rt_console_get_device();
|
||||
rt_device_write(out_device, 0, (void *)buffer, sizeof(buffer));
|
||||
rt_device_write(out_device, 0, (void *)buffer, length);
|
||||
}
|
||||
} while (length > 0);
|
||||
rt_kprintf("\n");
|
||||
@ -1026,14 +1066,14 @@ void copy(const char *src, const char *dst)
|
||||
flag |= FLAG_DST_IS_FILE;
|
||||
}
|
||||
|
||||
//2. check status
|
||||
/*2. check status*/
|
||||
if ((flag & FLAG_SRC_IS_DIR) && (flag & FLAG_DST_IS_FILE))
|
||||
{
|
||||
rt_kprintf("cp faild, cp dir to file is not permitted!\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
//3. do copy
|
||||
/*3. do copy*/
|
||||
if (flag & FLAG_SRC_IS_FILE)
|
||||
{
|
||||
if (flag & FLAG_DST_IS_DIR)
|
||||
@ -1053,7 +1093,7 @@ void copy(const char *src, const char *dst)
|
||||
copyfile(src, dst);
|
||||
}
|
||||
}
|
||||
else //flag & FLAG_SRC_IS_DIR
|
||||
else /*flag & FLAG_SRC_IS_DIR*/
|
||||
{
|
||||
if (flag & FLAG_DST_IS_DIR)
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -322,8 +322,8 @@ int dfs_mount(const char *device_name,
|
||||
/* open device, but do not check the status of device */
|
||||
if (dev_id != NULL)
|
||||
{
|
||||
if (rt_device_open(fs->dev_id,
|
||||
RT_DEVICE_OFLAG_RDWR) != RT_EOK)
|
||||
if (rt_device_open(fs->dev_id, RT_DEVICE_OFLAG_RDWR) != RT_EOK &&
|
||||
rt_device_open(fs->dev_id, RT_DEVICE_OFLAG_RDONLY) != RT_EOK)
|
||||
{
|
||||
/* The underlying device has error, clear the entry. */
|
||||
dfs_lock();
|
||||
@ -529,7 +529,8 @@ int dfs_mount_device(rt_device_t dev)
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
if(dev == RT_NULL) {
|
||||
if(dev == RT_NULL)
|
||||
{
|
||||
rt_kprintf("the device is NULL to be mounted.\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
@ -538,7 +539,8 @@ int dfs_mount_device(rt_device_t dev)
|
||||
{
|
||||
if (mount_table[index].path == NULL) break;
|
||||
|
||||
if(strcmp(mount_table[index].device_name, dev->parent.name) == 0) {
|
||||
if(strcmp(mount_table[index].device_name, dev->parent.name) == 0)
|
||||
{
|
||||
if (dfs_mount(mount_table[index].device_name,
|
||||
mount_table[index].path,
|
||||
mount_table[index].filesystemtype,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -28,7 +28,17 @@
|
||||
* return a file descriptor according specified flags.
|
||||
*
|
||||
* @param file the path name of file.
|
||||
* @param flags the file open flags.
|
||||
* @param flags the file open flags. Common values include:
|
||||
* - Access modes (mutually exclusive):
|
||||
* - `O_RDONLY`: Open for read-only access.
|
||||
* - `O_WRONLY`: Open for write-only access.
|
||||
* - `O_RDWR`: Open for both reading and writing.
|
||||
* - File status flags (can be combined with bitwise OR `|`):
|
||||
* - `O_CREAT`: Create the file if it does not exist. Requires a `mode` argument.
|
||||
* - `O_TRUNC`: Truncate the file to zero length if it already exists.
|
||||
* - `O_APPEND`: Append writes to the end of the file.
|
||||
* - `O_EXCL`: Ensure that `O_CREAT` creates the file exclusively.
|
||||
* - Other platform-specific flags
|
||||
*
|
||||
* @return the non-negative integer on successful open, others for failed.
|
||||
*/
|
||||
@ -65,6 +75,22 @@ RTM_EXPORT(open);
|
||||
#ifndef AT_FDCWD
|
||||
#define AT_FDCWD (-100)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Opens a file relative to a directory file descriptor.
|
||||
*
|
||||
* @param dirfd The file descriptor of the directory to base the relative path on.
|
||||
* @param pathname The path to the file to be opened, relative to the directory specified by `dirfd`.
|
||||
* Can be an absolute path (in which case `dirfd` is ignored).
|
||||
* @param flags File access and status flags (e.g., `O_RDONLY`, `O_WRONLY`, `O_CREAT`).
|
||||
*
|
||||
* @return On success, returns a new file descriptor for the opened file.
|
||||
* On failure, returns `-1` and sets `errno` to indicate the error.
|
||||
*
|
||||
* @note When using relative paths, ensure `dirfd` is a valid directory descriptor.
|
||||
* When `pathname` is absolute, the `dirfd` argument is ignored.
|
||||
*
|
||||
*/
|
||||
int openat(int dirfd, const char *path, int flag, ...)
|
||||
{
|
||||
struct dfs_file *d;
|
||||
@ -241,14 +267,22 @@ ssize_t write(int fd, const void *buf, size_t len)
|
||||
RTM_EXPORT(write);
|
||||
|
||||
/**
|
||||
* this function is a POSIX compliant version, which will seek the offset for
|
||||
* this function is a POSIX compliant version, which will Reposition the file offset for
|
||||
* an open file descriptor.
|
||||
*
|
||||
* @param fd the file descriptor.
|
||||
* @param offset the offset to be seeked.
|
||||
* @param whence the directory of seek.
|
||||
* The `lseek` function sets the file offset for the file descriptor `fd`
|
||||
* to a new value, determined by the `offset` and `whence` parameters.
|
||||
* It can be used to seek to specific positions in a file for reading or writing.
|
||||
*
|
||||
* @return the current read/write position in the file, or -1 on failed.
|
||||
* @param fd the file descriptor.
|
||||
* @param offset The offset, in bytes, to set the file position.
|
||||
* The meaning of `offset` depends on the value of `whence`.
|
||||
* @param whence the directive of seek. It can be one of:
|
||||
* - `SEEK_SET`: Set the offset to `offset` bytes from the beginning of the file.
|
||||
* - `SEEK_CUR`: Set the offset to its current location plus `offset` bytes.
|
||||
* - `SEEK_END`: Set the offset to the size of the file plus `offset` bytes.
|
||||
*
|
||||
* @return the resulting read/write position in the file, or -1 on failed.
|
||||
*/
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
@ -436,9 +470,15 @@ RTM_EXPORT(fsync);
|
||||
* control functions on devices.
|
||||
*
|
||||
* @param fildes the file description
|
||||
* @param cmd the specified command
|
||||
* @param cmd the specified command, Common values include:
|
||||
* - `F_DUPFD`: Duplicate a file descriptor.
|
||||
* - `F_GETFD`: Get the file descriptor flags.
|
||||
* - `F_SETFD`: Set the file descriptor flags.
|
||||
* - `F_GETFL`: Get the file status flags.
|
||||
* - `F_SETFL`: Set the file status flags.
|
||||
* @param ... represents the additional information that is needed by this
|
||||
* specific device to perform the requested function.
|
||||
* specific device to perform the requested function. For example:
|
||||
* - When `cmd` is `F_SETFL`, an additional integer argument specifies the new status flags.
|
||||
*
|
||||
* @return 0 on successful completion. Otherwise, -1 shall be returned and errno
|
||||
* set to indicate the error.
|
||||
@ -595,7 +635,7 @@ RTM_EXPORT(fstatfs);
|
||||
* this function is a POSIX compliant version, which will make a directory
|
||||
*
|
||||
* @param path the directory path to be made.
|
||||
* @param mode
|
||||
* @param mode The permission mode for the new directory (unused here, can be set to 0).
|
||||
*
|
||||
* @return 0 on successful, others on failed.
|
||||
*/
|
||||
|
@ -786,18 +786,18 @@ static ssize_t dfs_cromfs_read(struct dfs_file *file, void *buf, size_t count, o
|
||||
rt_err_t result = RT_EOK;
|
||||
file_info *fi = NULL;
|
||||
cromfs_info *ci = NULL;
|
||||
uint32_t length = 0;
|
||||
ssize_t length = 0;
|
||||
|
||||
ci = (cromfs_info *)file->dentry->mnt->data;
|
||||
fi = (file_info *)file->vnode->data;
|
||||
|
||||
if (count < file->vnode->size - *pos)
|
||||
if ((off_t)count < (off_t)file->vnode->size - *pos)
|
||||
{
|
||||
length = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = file->vnode->size - *pos;
|
||||
length = (off_t)file->vnode->size - *pos;
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
|
@ -11,6 +11,9 @@
|
||||
#ifndef __DFS_CROMFS_H__
|
||||
#define __DFS_CROMFS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int dfs_cromfs_init(void);
|
||||
uint8_t *cromfs_get_partition_data(uint32_t *len);
|
||||
|
||||
#endif /*__DFS_CROMFS_H__*/
|
||||
|
@ -77,6 +77,7 @@ static int dfs_devfs_open(struct dfs_file *file)
|
||||
}
|
||||
}
|
||||
}
|
||||
rt_free(device_name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -113,6 +114,29 @@ static int dfs_devfs_close(struct dfs_file *file)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static rt_ubase_t _get_unit_shift(rt_device_t device)
|
||||
{
|
||||
rt_ubase_t shift = 0;
|
||||
|
||||
/**
|
||||
* transfer unit size from POSIX RW(in bytes) to rt_device_R/W
|
||||
* (block size for blk device, otherwise in bytes).
|
||||
*/
|
||||
if (device->type == RT_Device_Class_Block)
|
||||
{
|
||||
struct rt_device_blk_geometry geometry = {0};
|
||||
|
||||
/* default to 512 */
|
||||
shift = 9;
|
||||
if (!rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry))
|
||||
{
|
||||
shift = __rt_ffs(geometry.block_size) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return shift;
|
||||
}
|
||||
|
||||
static ssize_t dfs_devfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
ssize_t ret = -RT_EIO;
|
||||
@ -135,9 +159,14 @@ static ssize_t dfs_devfs_read(struct dfs_file *file, void *buf, size_t count, of
|
||||
if (device->ops)
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
{
|
||||
/* read device data */
|
||||
ret = rt_device_read(device, *pos, buf, count);
|
||||
*pos += ret;
|
||||
rt_ubase_t shift = _get_unit_shift(device);
|
||||
|
||||
ret = rt_device_read(device, *pos, buf, count >> shift);
|
||||
if (ret > 0)
|
||||
{
|
||||
ret <<= shift;
|
||||
*pos += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,9 +198,15 @@ static ssize_t dfs_devfs_write(struct dfs_file *file, const void *buf, size_t co
|
||||
if (device->ops)
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
{
|
||||
rt_ubase_t shift = _get_unit_shift(device);
|
||||
|
||||
/* read device data */
|
||||
ret = rt_device_write(device, *pos, buf, count);
|
||||
*pos += ret;
|
||||
ret = rt_device_write(device, *pos, buf, count >> shift);
|
||||
if (ret > 0)
|
||||
{
|
||||
ret <<= shift;
|
||||
*pos += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,7 +300,7 @@ static int dfs_devfs_flush(struct dfs_file *file)
|
||||
|
||||
static off_t dfs_devfs_lseek(struct dfs_file *file, off_t offset, int wherece)
|
||||
{
|
||||
off_t ret = 0;
|
||||
off_t ret = -EPERM;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
@ -408,16 +443,16 @@ mode_t dfs_devfs_device_to_mode(struct rt_device *device)
|
||||
switch (device->type)
|
||||
{
|
||||
case RT_Device_Class_Char:
|
||||
mode = S_IFCHR | 0777;
|
||||
mode = S_IFCHR | 0666;
|
||||
break;
|
||||
case RT_Device_Class_Block:
|
||||
mode = S_IFBLK | 0777;
|
||||
mode = S_IFBLK | 0666;
|
||||
break;
|
||||
case RT_Device_Class_Pipe:
|
||||
mode = S_IFIFO | 0777;
|
||||
mode = S_IFIFO | 0666;
|
||||
break;
|
||||
default:
|
||||
mode = S_IFCHR | 0777;
|
||||
mode = S_IFCHR | 0666;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_mnt.h>
|
||||
#include <dfs_vfs.h>
|
||||
#include <devfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -34,10 +35,9 @@ struct devtmpfs_file
|
||||
char name[DIRENT_NAME_MAX]; /* file name */
|
||||
|
||||
rt_uint32_t type; /* file type */
|
||||
rt_list_t subdirs; /* file subdir list */
|
||||
rt_list_t sibling; /* file sibling list */
|
||||
struct dfs_vfs_node node; /* file node in the devtmpfs */
|
||||
|
||||
struct devtmpfs_sb *sb; /* superblock ptr */
|
||||
struct devtmpfs_sb *sb; /* superblock ptr */
|
||||
|
||||
rt_uint32_t mode;
|
||||
char *link;
|
||||
@ -48,7 +48,6 @@ struct devtmpfs_sb
|
||||
rt_uint32_t magic; /* TMPFS_MAGIC */
|
||||
struct devtmpfs_file root; /* root dir */
|
||||
rt_size_t df_size; /* df size */
|
||||
rt_list_t sibling; /* sb sibling list */
|
||||
struct rt_spinlock lock; /* tmpfs lock */
|
||||
};
|
||||
|
||||
@ -111,15 +110,13 @@ static int _get_subdir(const char *path, char *name)
|
||||
#if 0
|
||||
static int _free_subdir(struct devtmpfs_file *dfile)
|
||||
{
|
||||
struct devtmpfs_file *file;
|
||||
rt_list_t *list, *temp_list;
|
||||
struct devtmpfs_file *file, *tmp;
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
|
||||
|
||||
rt_list_for_each_safe(list, temp_list, &dfile->subdirs)
|
||||
dfs_vfs_for_each_subnode(file, tmp, dfile, node)
|
||||
{
|
||||
file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
||||
if (file->type == TMPFS_TYPE_DIR)
|
||||
{
|
||||
_free_subdir(file);
|
||||
@ -134,7 +131,7 @@ static int _free_subdir(struct devtmpfs_file *dfile)
|
||||
RT_ASSERT(superblock);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(file->sibling));
|
||||
dfs_vfs_remove_node(&file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(file);
|
||||
@ -152,14 +149,12 @@ static int devtmpfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void
|
||||
{
|
||||
superblock->df_size = sizeof(struct devtmpfs_sb);
|
||||
superblock->magic = TMPFS_MAGIC;
|
||||
rt_list_init(&superblock->sibling);
|
||||
|
||||
superblock->root.name[0] = '/';
|
||||
superblock->root.sb = superblock;
|
||||
superblock->root.type = TMPFS_TYPE_DIR;
|
||||
superblock->root.mode = S_IFDIR | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH);
|
||||
rt_list_init(&superblock->root.sibling);
|
||||
rt_list_init(&superblock->root.subdirs);
|
||||
dfs_vfs_init_node(&superblock->root.node);
|
||||
|
||||
rt_spin_lock_init(&superblock->lock);
|
||||
|
||||
@ -193,8 +188,7 @@ static struct devtmpfs_file *devtmpfs_file_lookup(struct devtmpfs_sb *superblock
|
||||
{
|
||||
const char *subpath, *curpath, *filename = RT_NULL;
|
||||
char subdir_name[DIRENT_NAME_MAX];
|
||||
struct devtmpfs_file *file, *curfile;
|
||||
rt_list_t *list;
|
||||
struct devtmpfs_file *file, *curfile, *tmp;
|
||||
|
||||
subpath = path;
|
||||
while (*subpath == '/' && *subpath)
|
||||
@ -222,9 +216,8 @@ find_subpath:
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
|
||||
rt_list_for_each(list, &curfile->subdirs)
|
||||
dfs_vfs_for_each_subnode(file, tmp, curfile, node)
|
||||
{
|
||||
file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
||||
if (filename) /* find file */
|
||||
{
|
||||
if (rt_strcmp(file->name, filename) == 0)
|
||||
@ -293,7 +286,9 @@ static int devtmpfs_stat(struct dfs_dentry *dentry, struct stat *st)
|
||||
|
||||
static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
|
||||
{
|
||||
struct devtmpfs_file *d_file;
|
||||
rt_size_t index, end;
|
||||
struct dirent *d;
|
||||
struct devtmpfs_file *d_file, *n_file = RT_NULL, *tmp;
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(file);
|
||||
@ -306,11 +301,6 @@ static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_
|
||||
d_file = devtmpfs_file_lookup(superblock, file->dentry->pathname);
|
||||
if (d_file)
|
||||
{
|
||||
rt_size_t index, end;
|
||||
struct dirent *d;
|
||||
struct devtmpfs_file *n_file;
|
||||
rt_list_t *list;
|
||||
|
||||
/* make integer count */
|
||||
count = (count / sizeof(struct dirent));
|
||||
if (count == 0)
|
||||
@ -322,12 +312,10 @@ static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_
|
||||
index = 0;
|
||||
count = 0;
|
||||
|
||||
rt_list_for_each(list, &d_file->subdirs)
|
||||
dfs_vfs_for_each_subnode(n_file, tmp, d_file, node)
|
||||
{
|
||||
if (index >= (rt_size_t)file->fpos)
|
||||
{
|
||||
n_file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
||||
|
||||
d = dirp + count;
|
||||
if (n_file->type == TMPFS_TYPE_FILE)
|
||||
{
|
||||
@ -378,8 +366,7 @@ static int devtmpfs_symlink(struct dfs_dentry *parent_dentry, const char *target
|
||||
|
||||
strncpy(l_file->name, linkpath, DIRENT_NAME_MAX - 1);
|
||||
|
||||
rt_list_init(&(l_file->subdirs));
|
||||
rt_list_init(&(l_file->sibling));
|
||||
dfs_vfs_init_node(&l_file->node);
|
||||
l_file->sb = superblock;
|
||||
l_file->type = TMPFS_TYPE_FILE;
|
||||
l_file->mode = p_file->mode;
|
||||
@ -388,7 +375,7 @@ static int devtmpfs_symlink(struct dfs_dentry *parent_dentry, const char *target
|
||||
l_file->link = rt_strdup(target);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(l_file->sibling));
|
||||
dfs_vfs_append_node(&p_file->node, &l_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
}
|
||||
}
|
||||
@ -460,7 +447,7 @@ static int devtmpfs_unlink(struct dfs_dentry *dentry)
|
||||
}
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(d_file->sibling));
|
||||
dfs_vfs_remove_node(&d_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(d_file);
|
||||
@ -537,8 +524,7 @@ static struct dfs_vnode *devtmpfs_create_vnode(struct dfs_dentry *dentry, int ty
|
||||
|
||||
strncpy(d_file->name, file_name, DIRENT_NAME_MAX);
|
||||
|
||||
rt_list_init(&(d_file->subdirs));
|
||||
rt_list_init(&(d_file->sibling));
|
||||
dfs_vfs_init_node(&d_file->node);
|
||||
d_file->sb = superblock;
|
||||
|
||||
vnode->nlink = 1;
|
||||
@ -563,7 +549,7 @@ static struct dfs_vnode *devtmpfs_create_vnode(struct dfs_dentry *dentry, int ty
|
||||
d_file->mode = vnode->mode;
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
||||
dfs_vfs_append_node(&p_file->node, &d_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
}
|
||||
|
||||
|
166
rt-thread/components/dfs/dfs_v2/filesystems/procfs/README.md
Normal file
166
rt-thread/components/dfs/dfs_v2/filesystems/procfs/README.md
Normal file
@ -0,0 +1,166 @@
|
||||
# 进程文件系统 (procfs)
|
||||
|
||||
## 数据结构
|
||||
|
||||
```c
|
||||
struct proc_dentry
|
||||
{
|
||||
rt_uint32_t mode;
|
||||
rt_atomic_t ref_count;
|
||||
|
||||
struct proc_dentry *parent;
|
||||
struct dfs_vfs_node node;
|
||||
|
||||
const struct dfs_file_ops *fops;
|
||||
const struct proc_ops *ops;
|
||||
|
||||
char *name;
|
||||
void *data;
|
||||
};
|
||||
```
|
||||
|
||||
```log
|
||||
root { mode: S_IFDIR, ref_count: 1, parent: root, name: /, child->next: file1->node }
|
||||
|
|
||||
|—— file1 { mode: S_IFREG, ref_count: 1, parent: root, name: file1, node->next: link1->node }
|
||||
|—— link1 { mode: S_IFLNK, ref_count: 1, parent: root, name: link1, data: fullpath, node->next: dir1->node }
|
||||
|—— dir1 { mode: S_IFDIR, ref_count: 1, parent: root, name: dir1, node->next: file3->node, child->next: file2->node }
|
||||
| |
|
||||
| |—— dir2 { mode: S_IFDIR, ref_count: 1, parent: dir1, name: dir2, node->next: link2->node }
|
||||
| |—— link2 { mode: S_IFLNK, ref_count: 1, parent: dir1, name: link2, data: fullpath, node->next: file2->node }
|
||||
| |—— file2 { mode: S_IFREG, ref_count: 1, parent: dir1, name: file2 }
|
||||
|
|
||||
|—— file3 { mode: S_IFREG, ref_count: 1, parent: root, name: file3 }
|
||||
```
|
||||
|
||||
## API 介绍
|
||||
|
||||
```c
|
||||
struct proc_dentry *dfs_proc_find(const char *name);
|
||||
|
||||
struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||
const struct dfs_file_ops *fops, void *data);
|
||||
struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent);
|
||||
struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent);
|
||||
|
||||
struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||
const struct dfs_file_ops *fops, void *data);
|
||||
|
||||
struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest);
|
||||
|
||||
struct proc_dentry *proc_acquire(struct proc_dentry *dentry);
|
||||
void proc_release(struct proc_dentry *dentry);
|
||||
|
||||
void proc_remove(struct proc_dentry *dentry);
|
||||
```
|
||||
|
||||
- dfs_proc_find
|
||||
|
||||
查找指定节点,并返回节点数据指针
|
||||
|
||||
| 入参 | 说明 |
|
||||
| ---- | ---------------------------------------------------- |
|
||||
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2” |
|
||||
|
||||
- proc_mkdir_data
|
||||
|
||||
创建一个目录,并返回节点数据指针
|
||||
|
||||
| 入参 | 说明 |
|
||||
| ------ | ------------------------------------------------------------ |
|
||||
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
|
||||
| mode | 权限配置 |
|
||||
| parent | 指定创建目录的起始节点 |
|
||||
| fops | 文件操作接口配置 |
|
||||
| data | 私有数据 |
|
||||
|
||||
- proc_mkdir_mode
|
||||
|
||||
创建一个目录,并返回节点数据指针
|
||||
|
||||
| 入参 | 说明 |
|
||||
| ------ | ------------------------------------------------------------ |
|
||||
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
|
||||
| mode | 权限配置 |
|
||||
| parent | 指定创建目录的起始节点 |
|
||||
|
||||
- proc_mkdir
|
||||
|
||||
创建一个目录,并返回节点数据指针
|
||||
|
||||
| 入参 | 说明 |
|
||||
| ---- | ------------------------------------------------------------ |
|
||||
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
|
||||
| mode | 权限配置 |
|
||||
|
||||
- proc_create_data
|
||||
|
||||
创建一个文件,并返回节点数据指针
|
||||
|
||||
| 入参 | 说明 |
|
||||
| ------ | ------------------------------------------------------------ |
|
||||
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
|
||||
| mode | 权限配置 |
|
||||
| parent | 指定创建文件的起始节点 |
|
||||
| fops | 文件操作接口配置 |
|
||||
| data | 私有数据 |
|
||||
|
||||
- proc_symlink
|
||||
|
||||
创建一个符号链接,并返回节点数据指针
|
||||
|
||||
| 入参 | 说明 |
|
||||
| ------ | ------------------------------------------------------------ |
|
||||
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
|
||||
| parent | 指定创建文件的起始节点 |
|
||||
| dest | 链接的目标文件完整路径 |
|
||||
|
||||
- proc_acquire
|
||||
|
||||
引用一个节点,并返回节点数据指针
|
||||
|
||||
| 入参 | 说明 |
|
||||
| ------ | -------------- |
|
||||
| dentry | 需要引用的节点 |
|
||||
|
||||
- proc_release
|
||||
|
||||
释放一个节点
|
||||
|
||||
| 入参 | 说明 |
|
||||
| ------ | -------------- |
|
||||
| dentry | 需要释放的节点 |
|
||||
|
||||
- proc_remove
|
||||
|
||||
删除一个节点包含子节点
|
||||
|
||||
| 入参 | 说明 |
|
||||
| ------ | -------------- |
|
||||
| dentry | 需要删除的节点 |
|
||||
|
||||
## msh 调试命令
|
||||
|
||||
- proc_dump
|
||||
|
||||
遍历打印指定节点含子节点的信息(名称、引用计数),比如 `proc_dump /dir1` 或者 `proc_dump`
|
||||
|
||||
- proc_remove
|
||||
|
||||
删除指定节点含子节点,比如 `proc_remove /dir1` 或者 `proc_remove /file3`
|
||||
|
||||
- proc_symlink
|
||||
|
||||
创建一个符号链接,`proc_symlink /link3 /mnt`
|
||||
|
||||
- proc_echo
|
||||
|
||||
创建一个空文件,`proc_echo /file4`
|
||||
|
||||
- proc_mkdir
|
||||
|
||||
创建一个空目录,`proc_mkdir /dir3`
|
||||
|
||||
- proc_pid
|
||||
|
||||
创建一个 pid 目录,`proc_pid /101`
|
@ -0,0 +1,11 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_PROCFS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
733
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc.c
Normal file
733
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc.c
Normal file
@ -0,0 +1,733 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
* This is the root in the proc tree..
|
||||
*/
|
||||
static struct proc_dentry _proc_root = {
|
||||
.mode = S_IFDIR | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH),
|
||||
.ref_count = 1,
|
||||
|
||||
.parent = &_proc_root,
|
||||
.node.sibling = RT_LIST_OBJECT_INIT(_proc_root.node.sibling),
|
||||
.node.subnode = RT_LIST_OBJECT_INIT(_proc_root.node.subnode),
|
||||
|
||||
.fops = RT_NULL,
|
||||
|
||||
.name = "/",
|
||||
.data = RT_NULL,
|
||||
};
|
||||
|
||||
static int _proc_find(struct proc_dentry **parent, const char *name)
|
||||
{
|
||||
struct proc_dentry *dentry = RT_NULL, *tmp;
|
||||
|
||||
dfs_vfs_for_each_subnode(dentry, tmp, (*parent), node)
|
||||
{
|
||||
if (dentry == RT_NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (rt_strcmp(dentry->name, name) == 0)
|
||||
{
|
||||
*parent = dentry;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int proc_find(struct proc_dentry **parent, const char **name, rt_bool_t force_lookup)
|
||||
{
|
||||
int ret = 0;
|
||||
char *tmp = RT_NULL;
|
||||
|
||||
if (!(*parent))
|
||||
{
|
||||
*parent = &_proc_root;
|
||||
}
|
||||
|
||||
tmp = rt_strdup(*name);
|
||||
if (tmp)
|
||||
{
|
||||
char *begin = tmp, *end = RT_NULL;
|
||||
if (*begin == '/')
|
||||
{
|
||||
begin++;
|
||||
if (*begin == '\0')
|
||||
{
|
||||
rt_free(tmp);
|
||||
*parent = proc_acquire(*parent);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
end = rt_strstr(begin, "/");
|
||||
if (end)
|
||||
{
|
||||
*end = '\0';
|
||||
ret = _proc_find(parent, begin);
|
||||
if (ret < 0 || !S_ISDIR((*parent)->mode))
|
||||
{
|
||||
*parent = RT_NULL;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
begin = end + 1;
|
||||
}
|
||||
else if (force_lookup)
|
||||
{
|
||||
ret = _proc_find(parent, begin);
|
||||
if (ret < 0)
|
||||
{
|
||||
if ((*parent)->ops && (*parent)->ops->lookup)
|
||||
{
|
||||
*parent = (*parent)->ops->lookup(*parent, begin);
|
||||
if (*parent == RT_NULL)
|
||||
{
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*parent = RT_NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*parent = proc_acquire(*parent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
*parent = proc_acquire(*parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*name = *name + (begin - tmp);
|
||||
|
||||
rt_free(tmp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *single_start(struct dfs_seq_file *seq, off_t *index)
|
||||
{
|
||||
return NULL + (*index == 0);
|
||||
}
|
||||
|
||||
static void *single_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||
{
|
||||
++*index;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void single_stop(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static int proc_open(struct dfs_file *file)
|
||||
{
|
||||
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||
|
||||
if (entry->single_show)
|
||||
{
|
||||
struct dfs_seq_ops *seq_ops = (struct dfs_seq_ops *)rt_calloc(1, sizeof(struct dfs_seq_ops));
|
||||
if (seq_ops)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
seq_ops->start = single_start;
|
||||
seq_ops->next = single_next;
|
||||
seq_ops->stop = single_stop;
|
||||
seq_ops->show = entry->single_show;
|
||||
|
||||
ret = dfs_seq_open(file, seq_ops);
|
||||
if (ret != 0)
|
||||
{
|
||||
rt_free(seq_ops);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return dfs_seq_open(file, entry->seq_ops);
|
||||
}
|
||||
|
||||
static int proc_close(struct dfs_file *file)
|
||||
{
|
||||
struct dfs_seq_file *seq = file->data;
|
||||
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||
|
||||
if (seq && entry->single_show && seq->ops)
|
||||
{
|
||||
rt_free((void *)seq->ops);
|
||||
seq->ops = RT_NULL;
|
||||
}
|
||||
|
||||
return dfs_seq_release(file);
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops proc_file_ops = {
|
||||
.open = proc_open,
|
||||
.read = dfs_seq_read,
|
||||
.lseek = dfs_seq_lseek,
|
||||
.close = proc_close,
|
||||
};
|
||||
|
||||
static struct proc_dentry *proc_create(struct proc_dentry **parent, const char *name, mode_t mode)
|
||||
{
|
||||
int ret = 0;
|
||||
struct proc_dentry *dentry = RT_NULL;
|
||||
|
||||
ret = proc_find(parent, &name, 0);
|
||||
if (ret >= 0)
|
||||
{
|
||||
dentry = *parent;
|
||||
ret = proc_find(&dentry, &name, 1);
|
||||
if (ret < 0)
|
||||
{
|
||||
dentry = rt_calloc(1, sizeof(struct proc_dentry));
|
||||
if (dentry)
|
||||
{
|
||||
dentry->mode = mode;
|
||||
dentry->ref_count = 1;
|
||||
dentry->name = rt_strdup(name);
|
||||
dfs_vfs_init_node(&dentry->node);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
proc_release(dentry);
|
||||
dentry = RT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The dentry reference count is incremented by one
|
||||
*
|
||||
* @param dentry
|
||||
*
|
||||
* @return dentry
|
||||
*/
|
||||
struct proc_dentry *proc_acquire(struct proc_dentry *dentry)
|
||||
{
|
||||
if (dentry)
|
||||
{
|
||||
dentry->ref_count += 1;
|
||||
}
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The dentry reference count is minus one, or release
|
||||
*
|
||||
* @param dentry
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void proc_release(struct proc_dentry *dentry)
|
||||
{
|
||||
if (dentry)
|
||||
{
|
||||
if (dentry->ref_count == 1)
|
||||
{
|
||||
if (dentry->name)
|
||||
{
|
||||
rt_free(dentry->name);
|
||||
}
|
||||
|
||||
if (S_ISLNK(dentry->mode) && dentry->data)
|
||||
{
|
||||
rt_free(dentry->data);
|
||||
}
|
||||
|
||||
rt_free(dentry);
|
||||
}
|
||||
else
|
||||
{
|
||||
dentry->ref_count -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct proc_dentry *proc_register(struct proc_dentry *parent, struct proc_dentry *child)
|
||||
{
|
||||
child->parent = parent;
|
||||
dfs_vfs_append_node(&parent->node, &child->node);
|
||||
child->ref_count += 1;
|
||||
child->pid = parent->pid;
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Make a dir
|
||||
*
|
||||
* @param name fullpath based on _proc_root or parent
|
||||
* @param mode permission configuration
|
||||
* @param parent can be empty
|
||||
* @param fops
|
||||
* @param data
|
||||
*
|
||||
* @return dentry
|
||||
*/
|
||||
struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||
const struct dfs_file_ops *fops, void *data)
|
||||
{
|
||||
struct proc_dentry *dentry, *_parent = parent;
|
||||
|
||||
if (mode == 0)
|
||||
mode = (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH);
|
||||
|
||||
dentry = proc_create(&_parent, name, S_IFDIR | mode);
|
||||
if (dentry)
|
||||
{
|
||||
dentry->fops = fops;
|
||||
dentry->data = data;
|
||||
|
||||
dentry = proc_register(_parent, dentry);
|
||||
}
|
||||
proc_release(_parent);
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Make a dir
|
||||
*
|
||||
* @param name fullpath based on _proc_root or parent
|
||||
* @param mode permission configuration
|
||||
* @param parent can be empty
|
||||
*
|
||||
* @return dentry
|
||||
*/
|
||||
struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent)
|
||||
{
|
||||
return proc_mkdir_data(name, mode, parent, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Make a dir
|
||||
*
|
||||
* @param name fullpath based on _proc_root or parent
|
||||
* @param parent can be empty
|
||||
*
|
||||
* @return dentry
|
||||
*/
|
||||
struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent)
|
||||
{
|
||||
return proc_mkdir_data(name, 0, parent, NULL, NULL);
|
||||
}
|
||||
|
||||
static struct proc_dentry *proc_create_reg(const char *name, mode_t mode, struct proc_dentry **parent)
|
||||
{
|
||||
struct proc_dentry *dentry = RT_NULL;
|
||||
|
||||
if ((mode & S_IFMT) == 0)
|
||||
mode |= S_IFREG;
|
||||
if ((mode & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)) == 0)
|
||||
mode |= S_IRUSR | S_IRGRP | S_IROTH;
|
||||
|
||||
if (!S_ISREG(mode))
|
||||
{
|
||||
*parent = RT_NULL;
|
||||
return dentry;
|
||||
}
|
||||
|
||||
return proc_create(parent, name, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Make a file
|
||||
*
|
||||
* @param name fullpath based on _proc_root or parent
|
||||
* @param mode permission configuration
|
||||
* @param parent can be empty
|
||||
* @param fops
|
||||
* @param data
|
||||
*
|
||||
* @return dentry
|
||||
*/
|
||||
struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||
const struct dfs_file_ops *fops, void *data)
|
||||
{
|
||||
struct proc_dentry *dentry, *_parent = parent;
|
||||
|
||||
dentry = proc_create_reg(name, mode, &_parent);
|
||||
if (dentry)
|
||||
{
|
||||
dentry->fops = fops ? fops : &proc_file_ops;
|
||||
dentry->data = data;
|
||||
|
||||
dentry = proc_register(_parent, dentry);
|
||||
}
|
||||
proc_release(_parent);
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Make a file
|
||||
*
|
||||
* @param name fullpath based on _proc_root or parent
|
||||
* @param mode permission configuration
|
||||
* @param parent can be empty
|
||||
* @param show
|
||||
* @param data
|
||||
*
|
||||
* @return dentry
|
||||
*/
|
||||
struct proc_dentry *proc_create_single_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||
int (*show)(struct dfs_seq_file *, void *), void *data)
|
||||
{
|
||||
struct proc_dentry *dentry, *_parent = parent;
|
||||
|
||||
dentry = proc_create_reg(name, mode, &_parent);
|
||||
if (dentry)
|
||||
{
|
||||
dentry->fops = &proc_file_ops;
|
||||
dentry->single_show = show;
|
||||
dentry->data = data;
|
||||
|
||||
dentry = proc_register(_parent, dentry);
|
||||
}
|
||||
proc_release(_parent);
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Make a symlink
|
||||
*
|
||||
* @param name fullpath based on _proc_root or parent
|
||||
* @param parent can be empty
|
||||
* @param dest link file fullpath
|
||||
*
|
||||
* @return dentry
|
||||
*/
|
||||
struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest)
|
||||
{
|
||||
struct proc_dentry *dentry, *_parent = parent;
|
||||
|
||||
dentry = proc_create(&_parent, name, (S_IFLNK | (S_IRUSR | S_IRGRP | S_IROTH)
|
||||
| (S_IWUSR | S_IWGRP | S_IWOTH) | (S_IXUSR | S_IXGRP | S_IXOTH)));
|
||||
if (dentry)
|
||||
{
|
||||
dentry->data = (void *)rt_strdup(dest);
|
||||
if (dentry->data)
|
||||
{
|
||||
dentry = proc_register(_parent, dentry);
|
||||
}
|
||||
else
|
||||
{
|
||||
proc_release(dentry);
|
||||
dentry = NULL;
|
||||
}
|
||||
}
|
||||
proc_release(_parent);
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
static void remove_proc_subtree(struct proc_dentry *dentry)
|
||||
{
|
||||
struct proc_dentry *iter = RT_NULL, *iter_tmp, *tmp = RT_NULL;
|
||||
|
||||
dfs_vfs_for_each_subnode(iter, iter_tmp, dentry, node)
|
||||
{
|
||||
if (iter == RT_NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
proc_release(tmp);
|
||||
tmp = RT_NULL;
|
||||
}
|
||||
|
||||
tmp = iter;
|
||||
|
||||
if (S_ISDIR(dentry->mode))
|
||||
{
|
||||
remove_proc_subtree(iter);
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
proc_release(tmp);
|
||||
tmp = RT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief remove a dentry
|
||||
*
|
||||
* @param dentry
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void proc_remove(struct proc_dentry *dentry)
|
||||
{
|
||||
if (dentry && dentry != &_proc_root)
|
||||
{
|
||||
if (S_ISDIR(dentry->mode))
|
||||
{
|
||||
remove_proc_subtree(dentry);
|
||||
}
|
||||
|
||||
dfs_vfs_remove_node(&dentry->node);
|
||||
proc_release(dentry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief find dentry exist
|
||||
*
|
||||
* @param name fullpath based on _proc_root
|
||||
*
|
||||
* @return dentry
|
||||
*/
|
||||
struct proc_dentry *dfs_proc_find(const char *name)
|
||||
{
|
||||
struct proc_dentry *dentry = RT_NULL;
|
||||
|
||||
proc_find(&dentry, &name, 1);
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief remove a dentry on parent
|
||||
*
|
||||
* @param name fullpath based on parent
|
||||
* @param parent
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void proc_remove_dentry(const char *name, struct proc_dentry *parent)
|
||||
{
|
||||
struct proc_dentry *dentry = parent;
|
||||
|
||||
if (proc_find(&dentry, &name, 1) >= 0)
|
||||
{
|
||||
proc_remove(dentry);
|
||||
proc_release(dentry);
|
||||
}
|
||||
}
|
||||
|
||||
#define _COLOR_RED "\033[31m"
|
||||
#define _COLOR_GREEN "\033[32m"
|
||||
#define _COLOR_BLUE "\033[34m"
|
||||
#define _COLOR_CYAN "\033[36m"
|
||||
#define _COLOR_WHITE "\033[37m"
|
||||
#define _COLOR_NORMAL "\033[0m"
|
||||
|
||||
static void dump_proc_subtree(struct proc_dentry *dentry, int tab)
|
||||
{
|
||||
struct proc_dentry *iter = RT_NULL, *tmp;
|
||||
|
||||
dfs_vfs_for_each_subnode(iter, tmp, dentry, node)
|
||||
{
|
||||
if (iter == RT_NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
for(int i = 0; i < tab; i ++)
|
||||
{
|
||||
rt_kprintf("%-4s", i + 1 >= tab ? "|-" : " ");
|
||||
}
|
||||
|
||||
if (S_ISDIR(iter->mode))
|
||||
{
|
||||
rt_kprintf(_COLOR_BLUE "%-20s" _COLOR_NORMAL " %d\n", iter->name, iter->ref_count);
|
||||
dump_proc_subtree(iter, tab + 1);
|
||||
}
|
||||
else if (S_ISLNK(iter->mode))
|
||||
{
|
||||
rt_kprintf(_COLOR_CYAN "%-20s" _COLOR_NORMAL " %d\n", iter->name, iter->ref_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("%-20s %d\n", iter->name, iter->ref_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void proc_dump(struct proc_dentry *dentry)
|
||||
{
|
||||
if (dentry)
|
||||
{
|
||||
if (S_ISDIR(dentry->mode))
|
||||
{
|
||||
rt_kprintf(_COLOR_BLUE "%-20s" _COLOR_NORMAL " %d\n", dentry->name, dentry->ref_count);
|
||||
dump_proc_subtree(dentry, 1);
|
||||
}
|
||||
else if (S_ISLNK(dentry->mode))
|
||||
{
|
||||
rt_kprintf(_COLOR_CYAN "%-20s" _COLOR_NORMAL " %d\n", dentry->name, dentry->ref_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("%-20s %d\n", dentry->name, dentry->ref_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int msh_proc_dump(int argc, char** argv)
|
||||
{
|
||||
const char *name = argc > 1 ? argv[1] : "/";
|
||||
struct proc_dentry *dentry = RT_NULL;
|
||||
|
||||
int ret = proc_find(&dentry, &name, 1);
|
||||
if (ret >= 0)
|
||||
{
|
||||
proc_dump(dentry);
|
||||
}
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT_ALIAS(msh_proc_dump, proc_dump, proc dump);
|
||||
|
||||
static int msh_proc_remove(int argc, char** argv)
|
||||
{
|
||||
if (argc > 1)
|
||||
{
|
||||
const char *name = argv[1];
|
||||
struct proc_dentry *dentry = RT_NULL;
|
||||
|
||||
int ret = proc_find(&dentry, &name, 1);
|
||||
if (ret >= 0)
|
||||
{
|
||||
if (dentry != &_proc_root)
|
||||
{
|
||||
proc_remove(dentry);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct proc_dentry *iter = RT_NULL, *iter_tmp, *tmp = RT_NULL;
|
||||
|
||||
dfs_vfs_for_each_subnode(iter, iter_tmp, dentry, node)
|
||||
{
|
||||
if (iter == RT_NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
proc_remove(tmp);
|
||||
}
|
||||
|
||||
tmp = iter;
|
||||
}
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
proc_remove(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
proc_release(dentry);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("proc_remove path\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT_ALIAS(msh_proc_remove, proc_remove, proc remove);
|
||||
|
||||
static int msh_proc_symlink(int argc, char** argv)
|
||||
{
|
||||
if (argc > 2)
|
||||
{
|
||||
struct proc_dentry *entry = proc_symlink(argv[1], 0, argv[2]);
|
||||
if (entry)
|
||||
{
|
||||
proc_release(entry);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("proc_symlink path dest\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT_ALIAS(msh_proc_symlink, proc_symlink, proc symlink);
|
||||
|
||||
static int msh_proc_echo(int argc, char** argv)
|
||||
{
|
||||
if (argc > 1)
|
||||
{
|
||||
for(int i = 1; i <= argc - 1; i ++)
|
||||
{
|
||||
struct proc_dentry *entry = proc_create_data(argv[i], 0, 0, 0, 0);
|
||||
if (entry)
|
||||
{
|
||||
proc_release(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("proc_echo path\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT_ALIAS(msh_proc_echo, proc_echo, proc echo);
|
||||
|
||||
static int msh_proc_mkdir(int argc, char** argv)
|
||||
{
|
||||
if (argc > 1)
|
||||
{
|
||||
for(int i = 1; i <= argc - 1; i ++)
|
||||
{
|
||||
struct proc_dentry *entry = proc_mkdir(argv[i], 0);
|
||||
if (entry)
|
||||
{
|
||||
proc_release(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("proc_mkdir path\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT_ALIAS(msh_proc_mkdir, proc_mkdir, proc mkdir);
|
75
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc.h
Normal file
75
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef __PROC_H__
|
||||
#define __PROC_H__
|
||||
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_seq_file.h>
|
||||
#include <dfs_vfs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct proc_dentry;
|
||||
|
||||
struct proc_ops
|
||||
{
|
||||
struct proc_dentry *(*lookup)(struct proc_dentry *parent, const char *name);
|
||||
int (*readlink)(struct proc_dentry *dentry, char *buf, int len);
|
||||
};
|
||||
|
||||
struct proc_dentry
|
||||
{
|
||||
rt_uint32_t mode;
|
||||
rt_atomic_t ref_count;
|
||||
|
||||
struct proc_dentry *parent;
|
||||
struct dfs_vfs_node node;
|
||||
|
||||
const struct dfs_file_ops *fops;
|
||||
const struct proc_ops *ops;
|
||||
const struct dfs_seq_ops *seq_ops;
|
||||
int (*single_show)(struct dfs_seq_file *seq, void *data);
|
||||
|
||||
int pid;
|
||||
|
||||
char *name;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct proc_dentry *dfs_proc_find(const char *name);
|
||||
|
||||
struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||
const struct dfs_file_ops *fops, void *data);
|
||||
struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent);
|
||||
struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent);
|
||||
|
||||
struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||
const struct dfs_file_ops *fops, void *data);
|
||||
struct proc_dentry *proc_create_single_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||
int (*show)(struct dfs_seq_file *, void *), void *data);
|
||||
|
||||
struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest);
|
||||
|
||||
struct proc_dentry *proc_acquire(struct proc_dentry *dentry);
|
||||
void proc_release(struct proc_dentry *dentry);
|
||||
|
||||
void proc_remove(struct proc_dentry *dentry);
|
||||
void proc_remove_dentry(const char *name, struct proc_dentry *parent);
|
||||
|
||||
int proc_pid(int pid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
static char *__proc_cmdline = NULL;
|
||||
|
||||
int proc_cmdline_save(const char *cmdline)
|
||||
{
|
||||
if (__proc_cmdline)
|
||||
{
|
||||
free(__proc_cmdline);
|
||||
__proc_cmdline = NULL;
|
||||
}
|
||||
|
||||
__proc_cmdline = strdup(cmdline);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int single_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
if (__proc_cmdline)
|
||||
{
|
||||
dfs_seq_puts(seq, __proc_cmdline);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proc_cmdline_init(void)
|
||||
{
|
||||
struct proc_dentry *dentry = proc_create_single_data("cmdline", 0, NULL, single_show, NULL);
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_cmdline_init);
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||
{
|
||||
off_t i = *index; // seq->index
|
||||
|
||||
return NULL + (i == 0);
|
||||
}
|
||||
|
||||
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
off_t i = *index + 1; // seq->index
|
||||
|
||||
*index = i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
dfs_seq_puts(seq, "rt_weak const struct dfs_seq_ops *cpuinfo_get_seq_ops(void)\n--need your own function--\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dfs_seq_ops seq_ops = {
|
||||
.start = seq_start,
|
||||
.stop = seq_stop,
|
||||
.next = seq_next,
|
||||
.show = seq_show,
|
||||
};
|
||||
|
||||
rt_weak const struct dfs_seq_ops *cpuinfo_get_seq_ops(void)
|
||||
{
|
||||
return &seq_ops;
|
||||
}
|
||||
|
||||
static int proc_open(struct dfs_file *file)
|
||||
{
|
||||
return dfs_seq_open(file, cpuinfo_get_seq_ops());
|
||||
}
|
||||
|
||||
static int proc_close(struct dfs_file *file)
|
||||
{
|
||||
return dfs_seq_release(file);
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops file_ops = {
|
||||
.open = proc_open,
|
||||
.read = dfs_seq_read,
|
||||
.lseek = dfs_seq_lseek,
|
||||
.close = proc_close,
|
||||
};
|
||||
|
||||
int proc_cpuinfo_init(void)
|
||||
{
|
||||
struct proc_dentry *dentry = proc_create_data("cpuinfo", 0, NULL, &file_ops, NULL);
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_cpuinfo_init);
|
@ -0,0 +1,307 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define LIST_FIND_OBJ_NR 8
|
||||
|
||||
struct device_show
|
||||
{
|
||||
char *buf;
|
||||
int size;
|
||||
int len;
|
||||
int index;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rt_list_t *list;
|
||||
rt_list_t **array;
|
||||
rt_uint8_t type;
|
||||
int nr; /* input: max nr, can't be 0 */
|
||||
int nr_out; /* out: got nr */
|
||||
} list_get_next_t;
|
||||
|
||||
static void list_find_init(list_get_next_t *p, rt_uint8_t type, rt_list_t **array, int nr)
|
||||
{
|
||||
struct rt_object_information *info;
|
||||
rt_list_t *list;
|
||||
|
||||
info = rt_object_get_information((enum rt_object_class_type)type);
|
||||
list = &info->object_list;
|
||||
|
||||
p->list = list;
|
||||
p->type = type;
|
||||
p->array = array;
|
||||
p->nr = nr;
|
||||
p->nr_out = 0;
|
||||
}
|
||||
|
||||
static rt_list_t *list_get_next(rt_list_t *current, list_get_next_t *arg)
|
||||
{
|
||||
int first_flag = 0;
|
||||
rt_base_t level;
|
||||
rt_list_t *node, *list;
|
||||
rt_list_t **array;
|
||||
struct rt_object_information *info;
|
||||
int nr;
|
||||
|
||||
arg->nr_out = 0;
|
||||
|
||||
if (!arg->nr || !arg->type)
|
||||
{
|
||||
return (rt_list_t *)RT_NULL;
|
||||
}
|
||||
|
||||
list = arg->list;
|
||||
info = rt_list_entry(list, struct rt_object_information, object_list);
|
||||
|
||||
if (!current) /* find first */
|
||||
{
|
||||
node = list;
|
||||
first_flag = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = current;
|
||||
}
|
||||
|
||||
level = rt_spin_lock_irqsave(&info->spinlock);
|
||||
|
||||
if (!first_flag)
|
||||
{
|
||||
struct rt_object *obj;
|
||||
/* The node in the list? */
|
||||
obj = rt_list_entry(node, struct rt_object, list);
|
||||
if ((obj->type & ~RT_Object_Class_Static) != arg->type)
|
||||
{
|
||||
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||
return (rt_list_t *)RT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
nr = 0;
|
||||
array = arg->array;
|
||||
while (1)
|
||||
{
|
||||
node = node->next;
|
||||
|
||||
if (node == list)
|
||||
{
|
||||
node = (rt_list_t *)RT_NULL;
|
||||
break;
|
||||
}
|
||||
nr++;
|
||||
*array++ = node;
|
||||
if (nr == arg->nr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||
arg->nr_out = nr;
|
||||
return node;
|
||||
}
|
||||
|
||||
static char *const device_type_str[RT_Device_Class_Unknown] =
|
||||
{
|
||||
"Character Device",
|
||||
"Block Device",
|
||||
"Network Interface",
|
||||
"MTD Device",
|
||||
"CAN Device",
|
||||
"RTC",
|
||||
"Sound Device",
|
||||
"Graphic Device",
|
||||
"I2C Bus",
|
||||
"USB Slave Device",
|
||||
"USB Host Bus",
|
||||
"USB OTG Bus",
|
||||
"SPI Bus",
|
||||
"SPI Device",
|
||||
"SDIO Bus",
|
||||
"PM Pseudo Device",
|
||||
"Pipe",
|
||||
"Portal Device",
|
||||
"Timer Device",
|
||||
"Miscellaneous Device",
|
||||
"Sensor Device",
|
||||
"Touch Device",
|
||||
"Phy Device",
|
||||
"Security Device",
|
||||
"WLAN Device",
|
||||
"Pin Device",
|
||||
"ADC Device",
|
||||
"DAC Device",
|
||||
"WDT Device",
|
||||
"PWM Device",
|
||||
"Bus Device",
|
||||
};
|
||||
|
||||
static void save_info(struct device_show *dev, char *dev_name)
|
||||
{
|
||||
char tmp[256] = {0};
|
||||
int len;
|
||||
|
||||
dev->index ++;
|
||||
|
||||
rt_snprintf(tmp, 256, "%d %s\n", dev->index, dev_name);
|
||||
tmp[255] = 0;
|
||||
|
||||
len = rt_strlen(tmp);
|
||||
if (dev->size > dev->len + len)
|
||||
{
|
||||
strcat(dev->buf, tmp);
|
||||
dev->len += len;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dev->buf == RT_NULL)
|
||||
{
|
||||
dev->buf = rt_calloc(1, 4096);
|
||||
}
|
||||
else
|
||||
{
|
||||
dev->buf = rt_realloc(dev->buf, dev->size + 4096);
|
||||
}
|
||||
if (dev->buf)
|
||||
{
|
||||
dev->size += 4096;
|
||||
strcat(dev->buf, tmp);
|
||||
dev->len += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void list_device(struct device_show *dev)
|
||||
{
|
||||
rt_base_t level;
|
||||
list_get_next_t find_arg;
|
||||
struct rt_object_information *info;
|
||||
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
||||
rt_list_t *next = (rt_list_t *)RT_NULL;
|
||||
|
||||
list_find_init(&find_arg, RT_Object_Class_Device, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
||||
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
||||
|
||||
do
|
||||
{
|
||||
next = list_get_next(next, &find_arg);
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < find_arg.nr_out; i++)
|
||||
{
|
||||
struct rt_object *obj;
|
||||
struct rt_device *device;
|
||||
|
||||
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
||||
level = rt_spin_lock_irqsave(&info->spinlock);
|
||||
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
||||
{
|
||||
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||
continue;
|
||||
}
|
||||
|
||||
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||
|
||||
device = (struct rt_device *)obj;
|
||||
|
||||
if (device->type < RT_Device_Class_Unknown)
|
||||
{
|
||||
save_info(dev + device->type, device->parent.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (next != (rt_list_t *)RT_NULL);
|
||||
}
|
||||
|
||||
static int show_info(struct dfs_seq_file *seq)
|
||||
{
|
||||
struct device_show _show[RT_Device_Class_Unknown] = {0};
|
||||
|
||||
list_device(_show);
|
||||
|
||||
for (int i = 0; i < RT_Device_Class_Unknown; i++)
|
||||
{
|
||||
if (_show[i].buf)
|
||||
{
|
||||
dfs_seq_printf(seq, "%s:\n", device_type_str[i]);
|
||||
dfs_seq_write(seq, _show[i].buf, _show[i].len);
|
||||
dfs_seq_putc(seq, '\n');
|
||||
|
||||
rt_free(_show[i].buf);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||
{
|
||||
off_t i = *index; // seq->index
|
||||
|
||||
return NULL + (i == 0);
|
||||
}
|
||||
|
||||
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
off_t i = *index + 1; // seq->index
|
||||
|
||||
*index = i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
show_info(seq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dfs_seq_ops seq_ops = {
|
||||
.start = seq_start,
|
||||
.stop = seq_stop,
|
||||
.next = seq_next,
|
||||
.show = seq_show,
|
||||
};
|
||||
|
||||
int proc_devices_init(void)
|
||||
{
|
||||
struct proc_dentry *dentry = proc_create_data("devices", 0, NULL, NULL, NULL);
|
||||
if (dentry)
|
||||
{
|
||||
dentry->seq_ops = &seq_ops;
|
||||
}
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_devices_init);
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_fs.h>
|
||||
|
||||
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||
{
|
||||
off_t i = *index; // seq->index
|
||||
struct dfs_filesystem_type *fs = dfs_filesystems();
|
||||
|
||||
if (fs)
|
||||
{
|
||||
while (i--)
|
||||
{
|
||||
fs = fs->next;
|
||||
if (!fs)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fs;
|
||||
}
|
||||
|
||||
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
off_t i = *index + 1; // seq->index
|
||||
struct dfs_filesystem_type *fs = (struct dfs_filesystem_type *)data;
|
||||
|
||||
*index = i;
|
||||
|
||||
return fs->next;
|
||||
}
|
||||
|
||||
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
struct dfs_filesystem_type *fs = (struct dfs_filesystem_type *)data;
|
||||
|
||||
dfs_seq_printf(seq, "%-9s%s\n", (fs->fs_ops->flags == FS_NEED_DEVICE) ? "" : "nodev", fs->fs_ops->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dfs_seq_ops seq_ops = {
|
||||
.start = seq_start,
|
||||
.stop = seq_stop,
|
||||
.next = seq_next,
|
||||
.show = seq_show,
|
||||
};
|
||||
|
||||
int proc_filesystems_init(void)
|
||||
{
|
||||
struct proc_dentry *dentry = proc_create_data("filesystems", 0, NULL, NULL, NULL);
|
||||
if (dentry)
|
||||
{
|
||||
dentry->seq_ops = &seq_ops;
|
||||
}
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_filesystems_init);
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
#include <mm_page.h>
|
||||
|
||||
|
||||
extern void rt_memory_info(rt_size_t *total,
|
||||
rt_size_t *used,
|
||||
rt_size_t *max_used);
|
||||
|
||||
static int single_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
dfs_seq_printf(seq, "0.13 0.16 0.17 1/1035 380436\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proc_loadavg_init(void)
|
||||
{
|
||||
struct proc_dentry *dentry = proc_create_single_data("loadavg", 0, NULL, single_show, NULL);
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_loadavg_init);
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
#include <mm_page.h>
|
||||
|
||||
|
||||
extern void rt_memory_info(rt_size_t *total,
|
||||
rt_size_t *used,
|
||||
rt_size_t *max_used);
|
||||
|
||||
static int single_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
rt_size_t total, used, max_used, freed;
|
||||
rt_size_t total_sum = 0;
|
||||
rt_size_t total_freed = 0;
|
||||
|
||||
rt_memory_info(&total, &used, &max_used);
|
||||
total_sum = total_sum + total;
|
||||
total_freed = total_freed + total - used;
|
||||
|
||||
dfs_seq_printf(seq, "%-16s%8d KB\n", "MemMaxUsed:", max_used / 1024);
|
||||
dfs_seq_printf(seq, "%-16s%8d KB\n", "MemAvailable:", (total - used) / 1024);
|
||||
dfs_seq_printf(seq, "%-16s%8d KB\n", "Cached:", 0);
|
||||
dfs_seq_printf(seq, "%-16s%8d KB\n", "SReclaimable:", 0);
|
||||
|
||||
rt_page_get_info(&total, &freed);
|
||||
total_sum = total_sum + total * RT_MM_PAGE_SIZE;
|
||||
total_freed = total_freed + freed * RT_MM_PAGE_SIZE;
|
||||
|
||||
dfs_seq_printf(seq, "%-16s%8d KB\n", "MemTotal:", total_sum / 1024);
|
||||
dfs_seq_printf(seq, "%-16s%8d KB\n", "MemFree:", total_freed / 1024);
|
||||
dfs_seq_printf(seq, "%-16s%8d KB\n", "LowPageTotal:", total * RT_MM_PAGE_SIZE / 1024);
|
||||
dfs_seq_printf(seq, "%-16s%8d KB\n", "lowPageFree:", freed * RT_MM_PAGE_SIZE/ 1024);
|
||||
|
||||
rt_page_high_get_info(&total, &freed);
|
||||
|
||||
dfs_seq_printf(seq, "%-16s%8d KB\n", "HighPageTotal:", total * RT_MM_PAGE_SIZE / 1024);
|
||||
dfs_seq_printf(seq, "%-16s%8d KB\n", "HighPageFree:", freed * RT_MM_PAGE_SIZE / 1024);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proc_meminfo_init(void)
|
||||
{
|
||||
struct proc_dentry *dentry = proc_create_single_data("meminfo", 0, NULL, single_show, NULL);
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_meminfo_init);
|
101
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c
Normal file
101
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_mnt.h>
|
||||
|
||||
|
||||
const char *mnt_flag(int flag)
|
||||
{
|
||||
/*if (flag & MNT_READONLY)
|
||||
{
|
||||
return "ro";
|
||||
}*/
|
||||
|
||||
return "rw";
|
||||
}
|
||||
|
||||
static struct dfs_mnt* mnt_show(struct dfs_mnt *mnt, void *parameter)
|
||||
{
|
||||
struct dfs_seq_file *seq = (struct dfs_seq_file *)parameter;
|
||||
|
||||
if (mnt)
|
||||
{
|
||||
if (mnt->dev_id)
|
||||
{
|
||||
dfs_seq_printf(seq, "%s %s %s %s 0 0\n", mnt->dev_id->parent.name, mnt->fullpath,
|
||||
mnt->fs_ops->name, mnt_flag(mnt->flags));
|
||||
}
|
||||
else
|
||||
{
|
||||
dfs_seq_printf(seq, "%s %s %s %s 0 0\n", mnt->fs_ops->name, mnt->fullpath,
|
||||
mnt->fs_ops->name, mnt_flag(mnt->flags));
|
||||
}
|
||||
}
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||
{
|
||||
off_t i = *index; // seq->index
|
||||
|
||||
return NULL + (i == 0);
|
||||
}
|
||||
|
||||
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
off_t i = *index + 1; // seq->index
|
||||
|
||||
*index = i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
dfs_mnt_foreach(mnt_show, seq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dfs_seq_ops seq_ops = {
|
||||
.start = seq_start,
|
||||
.stop = seq_stop,
|
||||
.next = seq_next,
|
||||
.show = seq_show,
|
||||
};
|
||||
|
||||
int proc_mounts_init(void)
|
||||
{
|
||||
struct proc_dentry *dentry = proc_create_data("mounts", 0, NULL, NULL, NULL);
|
||||
if (dentry)
|
||||
{
|
||||
dentry->seq_ops = &seq_ops;
|
||||
}
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_mounts_init);
|
107
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_net.c
Normal file
107
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_net.c
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
#ifdef RT_USING_LWIP
|
||||
#include "lwip/opt.h"
|
||||
#endif
|
||||
|
||||
#if LWIP_ROUTE
|
||||
extern int inet_route_foreach(void (*func)(const char *name, uint32_t ip_addr, uint32_t netmask, void *parameter), void *parameter);
|
||||
#endif
|
||||
|
||||
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||
{
|
||||
off_t i = *index; // seq->index
|
||||
|
||||
return NULL + (i == 0);
|
||||
}
|
||||
|
||||
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
off_t i = *index + 1; // seq->index
|
||||
|
||||
*index = i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void route_show(const char *name, uint32_t ip_addr, uint32_t netmask, void *parameter)
|
||||
{
|
||||
struct dfs_seq_file *seq = (struct dfs_seq_file *)parameter;
|
||||
/* "Iface\tDestination\tGateway "
|
||||
"\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU"
|
||||
"\tWindow\tIRTT"); */
|
||||
/* "%63s%lx%lx%X%d%d%d%lx%d%d%d\n" */
|
||||
dfs_seq_printf(seq, "%s ", name);
|
||||
dfs_seq_printf(seq, "%lx ", ip_addr);
|
||||
dfs_seq_printf(seq, "%lx ", 0);
|
||||
dfs_seq_printf(seq, "%X ", 1);
|
||||
dfs_seq_printf(seq, "%d ", 0);
|
||||
dfs_seq_printf(seq, "%d ", 0);
|
||||
dfs_seq_printf(seq, "%d ", 0);
|
||||
dfs_seq_printf(seq, "%lx ", netmask);
|
||||
dfs_seq_printf(seq, "%d ", 0);
|
||||
dfs_seq_printf(seq, "%d ", 0);
|
||||
dfs_seq_printf(seq, "%d\n", 0);
|
||||
}
|
||||
|
||||
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
dfs_seq_printf(seq, "\n");
|
||||
#if LWIP_ROUTE
|
||||
inet_route_foreach(route_show, seq);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dfs_seq_ops seq_ops = {
|
||||
.start = seq_start,
|
||||
.stop = seq_stop,
|
||||
.next = seq_next,
|
||||
.show = seq_show,
|
||||
};
|
||||
|
||||
int proc_net_init(void)
|
||||
{
|
||||
struct proc_dentry *dentry;
|
||||
|
||||
dentry = proc_mkdir("net", NULL);
|
||||
if (!dentry)
|
||||
return -1;
|
||||
|
||||
proc_release(dentry);
|
||||
|
||||
dentry = proc_create_data("net/route", 0, NULL, NULL, NULL);
|
||||
if (dentry)
|
||||
{
|
||||
dentry->seq_ops = &seq_ops;
|
||||
}
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_net_init);
|
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define LIST_FIND_OBJ_NR 8
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rt_list_t *list;
|
||||
rt_list_t **array;
|
||||
rt_uint8_t type;
|
||||
int nr; /* input: max nr, can't be 0 */
|
||||
int nr_out; /* out: got nr */
|
||||
} list_get_next_t;
|
||||
|
||||
static void list_find_init(list_get_next_t *p, rt_uint8_t type, rt_list_t **array, int nr)
|
||||
{
|
||||
struct rt_object_information *info;
|
||||
rt_list_t *list;
|
||||
|
||||
info = rt_object_get_information((enum rt_object_class_type)type);
|
||||
list = &info->object_list;
|
||||
|
||||
p->list = list;
|
||||
p->type = type;
|
||||
p->array = array;
|
||||
p->nr = nr;
|
||||
p->nr_out = 0;
|
||||
}
|
||||
|
||||
static rt_list_t *list_get_next(rt_list_t *current, list_get_next_t *arg)
|
||||
{
|
||||
int first_flag = 0;
|
||||
rt_base_t level;
|
||||
rt_list_t *node, *list;
|
||||
rt_list_t **array;
|
||||
struct rt_object_information *info;
|
||||
int nr;
|
||||
|
||||
arg->nr_out = 0;
|
||||
|
||||
if (!arg->nr || !arg->type)
|
||||
{
|
||||
return (rt_list_t *)RT_NULL;
|
||||
}
|
||||
|
||||
list = arg->list;
|
||||
info = rt_list_entry(list, struct rt_object_information, object_list);
|
||||
|
||||
if (!current) /* find first */
|
||||
{
|
||||
node = list;
|
||||
first_flag = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = current;
|
||||
}
|
||||
|
||||
level = rt_spin_lock_irqsave(&info->spinlock);
|
||||
|
||||
if (!first_flag)
|
||||
{
|
||||
struct rt_object *obj;
|
||||
/* The node in the list? */
|
||||
obj = rt_list_entry(node, struct rt_object, list);
|
||||
if ((obj->type & ~RT_Object_Class_Static) != arg->type)
|
||||
{
|
||||
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||
return (rt_list_t *)RT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
nr = 0;
|
||||
array = arg->array;
|
||||
while (1)
|
||||
{
|
||||
node = node->next;
|
||||
|
||||
if (node == list)
|
||||
{
|
||||
node = (rt_list_t *)RT_NULL;
|
||||
break;
|
||||
}
|
||||
nr++;
|
||||
*array++ = node;
|
||||
if (nr == arg->nr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||
arg->nr_out = nr;
|
||||
return node;
|
||||
}
|
||||
|
||||
static int show_info(struct dfs_seq_file *seq)
|
||||
{
|
||||
rt_base_t level;
|
||||
list_get_next_t find_arg;
|
||||
struct rt_object_information *info;
|
||||
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
||||
rt_list_t *next = (rt_list_t *)RT_NULL;
|
||||
|
||||
list_find_init(&find_arg, RT_Object_Class_Device, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
||||
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
||||
|
||||
do
|
||||
{
|
||||
next = list_get_next(next, &find_arg);
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < find_arg.nr_out; i++)
|
||||
{
|
||||
struct rt_object *obj;
|
||||
struct rt_device *device;
|
||||
|
||||
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
||||
level = rt_spin_lock_irqsave(&info->spinlock);
|
||||
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
||||
{
|
||||
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||
continue;
|
||||
}
|
||||
|
||||
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||
|
||||
device = (struct rt_device *)obj;
|
||||
|
||||
if (device->type == RT_Device_Class_Block)
|
||||
{
|
||||
struct rt_device_blk_geometry geometry = { 0 };
|
||||
|
||||
rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
|
||||
|
||||
dfs_seq_printf(seq, "%4d %7d %14llu %s\n", 0, 0,
|
||||
geometry.sector_count, device->parent.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (next != (rt_list_t *)RT_NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||
{
|
||||
off_t i = *index; // seq->index
|
||||
|
||||
return NULL + (i == 0);
|
||||
}
|
||||
|
||||
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
off_t i = *index + 1; // seq->index
|
||||
|
||||
*index = i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
dfs_seq_puts(seq, "major minor #blocks name\n\n");
|
||||
/* data: The return value of the start or next*/
|
||||
show_info(seq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dfs_seq_ops seq_ops = {
|
||||
.start = seq_start,
|
||||
.stop = seq_stop,
|
||||
.next = seq_next,
|
||||
.show = seq_show,
|
||||
};
|
||||
|
||||
int proc_partitions_init(void)
|
||||
{
|
||||
struct proc_dentry *dentry = proc_create_data("partitions", 0, NULL, NULL, NULL);
|
||||
if (dentry)
|
||||
{
|
||||
dentry->seq_ops = &seq_ops;
|
||||
}
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_partitions_init);
|
449
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c
Normal file
449
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c
Normal file
@ -0,0 +1,449 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
#define __RT_IPC_SOURCE__
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lwp_internal.h"
|
||||
#include <dfs_dentry.h>
|
||||
#include "lwp_internal.h"
|
||||
|
||||
#if defined(RT_USING_SMART)
|
||||
|
||||
#include "lwp.h"
|
||||
#include "lwp_pid.h"
|
||||
#include <lwp_user_mm.h>
|
||||
|
||||
struct pid_dentry
|
||||
{
|
||||
const char *name;
|
||||
mode_t mode;
|
||||
const struct dfs_file_ops *fops;
|
||||
const struct proc_ops *ops;
|
||||
const struct dfs_seq_ops *seq_ops;
|
||||
int (*single_show)(struct dfs_seq_file *seq, void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
static char stat_transform(int __stat)
|
||||
{
|
||||
switch (__stat)
|
||||
{
|
||||
case RT_THREAD_RUNNING:
|
||||
return 'R';
|
||||
default:
|
||||
return 'T';
|
||||
}
|
||||
}
|
||||
|
||||
static int stat_single_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data;
|
||||
rt_list_t *list;
|
||||
int mask = 0;
|
||||
rt_thread_t thread;
|
||||
rt_uint64_t user_time_lwp = 0;
|
||||
rt_uint64_t system_time_lwp = 0;
|
||||
int lwp_oncpu = RT_CPUS_NR;
|
||||
int lwp_oncpu_ok = 0;
|
||||
struct rt_lwp *lwp = RT_NULL;
|
||||
char** argv = RT_NULL;
|
||||
char *filename = RT_NULL;
|
||||
char *dot = RT_NULL;
|
||||
|
||||
lwp_pid_lock_take();
|
||||
|
||||
lwp = lwp_from_pid_locked(dentry->pid);
|
||||
argv = lwp_get_command_line_args(lwp);
|
||||
|
||||
if (lwp)
|
||||
{
|
||||
dfs_seq_printf(seq,"%d ",dentry->pid);
|
||||
if (argv)
|
||||
{
|
||||
filename = strrchr(argv[0], '/');
|
||||
dot = strchr(argv[0], '.');
|
||||
|
||||
if (filename != NULL)
|
||||
{
|
||||
filename++;
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = argv[0];
|
||||
}
|
||||
|
||||
if (dot != NULL)
|
||||
{
|
||||
*dot = '\0';
|
||||
}
|
||||
|
||||
if (filename != NULL)
|
||||
{
|
||||
dfs_seq_printf(seq,"(%s) ", filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
dfs_seq_printf(seq,"(%s) ", argv[0]);
|
||||
}
|
||||
|
||||
lwp_free_command_line_args(argv);
|
||||
}
|
||||
else
|
||||
{
|
||||
dfs_seq_printf(seq,"(%s) ", "");
|
||||
}
|
||||
|
||||
if (lwp->terminated)
|
||||
{
|
||||
dfs_seq_printf(seq,"%c ",'Z');
|
||||
}
|
||||
else
|
||||
{
|
||||
list = lwp->t_grp.next;
|
||||
while (list != &lwp->t_grp)
|
||||
{
|
||||
thread = rt_list_entry(list, struct rt_thread, sibling);
|
||||
user_time_lwp = user_time_lwp + thread->user_time;
|
||||
system_time_lwp = system_time_lwp + thread->system_time;
|
||||
|
||||
#if RT_CPUS_NR > 1
|
||||
#define ONCPU(thread) RT_SCHED_CTX(thread).oncpu
|
||||
#else
|
||||
#define ONCPU(thread) 0
|
||||
#endif
|
||||
if (lwp_oncpu_ok == 0)
|
||||
{
|
||||
lwp_oncpu = ONCPU(thread);
|
||||
lwp_oncpu_ok = 1;
|
||||
}
|
||||
if (stat_transform(RT_SCHED_CTX(thread).stat) == 'R')
|
||||
{
|
||||
lwp_oncpu = ONCPU(thread);
|
||||
mask = 1;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if (mask == 1)
|
||||
{
|
||||
dfs_seq_printf(seq,"%c ",'R');
|
||||
}
|
||||
else
|
||||
{
|
||||
dfs_seq_printf(seq,"%c ",'S');
|
||||
}
|
||||
}
|
||||
lwp_pid_lock_release();
|
||||
|
||||
if (lwp->parent != NULL)
|
||||
dfs_seq_printf(seq,"%d ",lwp->parent->pid);
|
||||
else
|
||||
dfs_seq_printf(seq,"0 ");
|
||||
|
||||
dfs_seq_printf(seq, "1 1 0 -1 4194560 48245 133976064 732 425574 ");
|
||||
dfs_seq_printf(seq,"%llu ",user_time_lwp);//utime
|
||||
dfs_seq_printf(seq,"%llu ",system_time_lwp);//stime
|
||||
dfs_seq_printf(seq, "1204291 518742 20 0 1 0 50 ");
|
||||
dfs_seq_printf(seq, "%d ",rt_aspace_count_vsz(lwp->aspace));//VSZ
|
||||
dfs_seq_printf(seq, "1422 18446744073709551615 ");
|
||||
dfs_seq_printf(seq, "1 1 0 0 0 0 671173123 4096 1260 0 0 0 17 ");
|
||||
dfs_seq_printf(seq, "%d ", lwp_oncpu);//CPU
|
||||
dfs_seq_printf(seq, "0 0 0 0 0 0 0 0 0 0 0 0 0");
|
||||
dfs_seq_printf(seq,"\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
lwp_pid_lock_release();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmdline_single_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data;
|
||||
struct rt_lwp *lwp;
|
||||
char** argv;
|
||||
|
||||
lwp_pid_lock_take();
|
||||
lwp = lwp_from_pid_locked(dentry->pid);
|
||||
argv = lwp_get_command_line_args(lwp);
|
||||
lwp_pid_lock_release();
|
||||
|
||||
if (argv)
|
||||
{
|
||||
for (int i = 0; argv[i] != NULL; i++)
|
||||
{
|
||||
dfs_seq_printf(seq, "%s ", argv[i]);
|
||||
}
|
||||
dfs_seq_puts(seq, "\n");
|
||||
|
||||
lwp_free_command_line_args(argv);
|
||||
}
|
||||
else
|
||||
{
|
||||
dfs_seq_puts(seq, "error\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct proc_dentry *proc_pid_fd_lookup(struct proc_dentry *parent, const char *name)
|
||||
{
|
||||
struct proc_dentry *dentry = RT_NULL;
|
||||
char num[DIRENT_NAME_MAX];
|
||||
struct rt_lwp *lwp;
|
||||
struct dfs_fdtable *table;
|
||||
|
||||
lwp_pid_lock_take();
|
||||
lwp = lwp_from_pid_locked(parent->pid);
|
||||
table = lwp ? &lwp->fdt : RT_NULL;
|
||||
lwp_pid_lock_release();
|
||||
|
||||
if (!table)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
dfs_file_lock();
|
||||
for (int i = 0; i < table->maxfd; i++)
|
||||
{
|
||||
struct dfs_file *file = table->fds[i];
|
||||
if (file)
|
||||
{
|
||||
rt_snprintf(num, DIRENT_NAME_MAX, "%d", i);
|
||||
if (rt_strcmp(num, name) == 0)
|
||||
{
|
||||
dentry = rt_calloc(1, sizeof(struct proc_dentry));
|
||||
if (dentry)
|
||||
{
|
||||
dentry->mode = (S_IFLNK | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IWUSR | S_IWGRP | S_IWOTH) | (S_IXUSR | S_IXGRP | S_IXOTH));
|
||||
dentry->ref_count = 1;
|
||||
dentry->name = rt_strdup(name);
|
||||
dentry->data = (void *)dfs_dentry_full_path(file->dentry);
|
||||
|
||||
if (dentry->data == RT_NULL)
|
||||
{
|
||||
//todo add vnode->data
|
||||
if (file->vnode->type == FT_SOCKET)
|
||||
dentry->data = (void *)rt_strdup("socket");
|
||||
else if (file->vnode->type == FT_USER)
|
||||
dentry->data = (void *)rt_strdup("user");
|
||||
else if (file->vnode->type == FT_DEVICE)
|
||||
dentry->data = (void *)rt_strdup("device");
|
||||
else
|
||||
dentry->data = (void *)rt_strdup("unknown");
|
||||
}
|
||||
|
||||
dentry->pid = parent->pid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dfs_file_unlock();
|
||||
|
||||
return dentry;
|
||||
}
|
||||
|
||||
int proc_pid_fd_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
|
||||
{
|
||||
int ret = 0, index = 0;
|
||||
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||
struct rt_lwp *lwp;
|
||||
struct dfs_fdtable *table;
|
||||
|
||||
lwp_pid_lock_take();
|
||||
lwp = lwp_from_pid_locked(entry->pid);
|
||||
LWP_LOCK(lwp);
|
||||
table = lwp ? &lwp->fdt : RT_NULL;
|
||||
|
||||
if (!table->fds)
|
||||
{
|
||||
LWP_UNLOCK(lwp);
|
||||
lwp_pid_lock_release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
count = (count / sizeof(struct dirent));
|
||||
if (count == 0)
|
||||
{
|
||||
LWP_UNLOCK(lwp);
|
||||
lwp_pid_lock_release();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dfs_file_lock();
|
||||
for (int i = 0; i < table->maxfd; i++)
|
||||
{
|
||||
struct dfs_file *df = table->fds[i];
|
||||
if (df)
|
||||
{
|
||||
if (index >= file->fpos)
|
||||
{
|
||||
struct dirent *d = dirp + index - file->fpos;
|
||||
|
||||
d->d_type = DT_SYMLINK;
|
||||
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
||||
rt_snprintf(d->d_name, DIRENT_NAME_MAX, "%d", i);
|
||||
d->d_namlen = rt_strlen(d->d_name);
|
||||
|
||||
ret++;
|
||||
}
|
||||
|
||||
index++;
|
||||
if (index - file->fpos >= count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dfs_file_unlock();
|
||||
LWP_UNLOCK(lwp);
|
||||
lwp_pid_lock_release();
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
file->fpos = index;
|
||||
ret = ret * sizeof(struct dirent);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct proc_ops proc_pid_fd_ops = {
|
||||
.lookup = proc_pid_fd_lookup,
|
||||
};
|
||||
|
||||
static const struct dfs_file_ops proc_pid_fd_fops = {
|
||||
.getdents = proc_pid_fd_getdents,
|
||||
};
|
||||
|
||||
int proc_pid_exe_readlink(struct proc_dentry *dentry, char *buf, int len)
|
||||
{
|
||||
struct rt_lwp *lwp;
|
||||
|
||||
lwp = lwp_self();
|
||||
len = rt_snprintf(buf, len, "%s", lwp ? lwp->exe_file : "null");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct proc_ops proc_pid_exe_ops = {
|
||||
.readlink = proc_pid_exe_readlink,
|
||||
};
|
||||
|
||||
int proc_pid_cwd_readlink(struct proc_dentry *dentry, char *buf, int len)
|
||||
{
|
||||
struct rt_lwp *lwp;
|
||||
|
||||
lwp = lwp_self();
|
||||
len = rt_snprintf(buf, len, "%s", lwp ? lwp->working_directory : "null");
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct proc_ops proc_pid_cwd_ops = {
|
||||
.readlink = proc_pid_cwd_readlink,
|
||||
};
|
||||
|
||||
static struct pid_dentry pid_dentry_base[] = {
|
||||
{"cmdline", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, cmdline_single_show, 0},
|
||||
{"cwd", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_cwd_ops, 0, 0},
|
||||
{"exe", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_exe_ops, 0, 0},
|
||||
{"fd", S_IFDIR | S_IRUSR | S_IXUSR, &proc_pid_fd_fops, &proc_pid_fd_ops, 0, 0, 0},
|
||||
{"mounts", S_IFLNK | S_IRUSR | S_IXUSR, 0, 0, 0, 0, "/proc/mounts"},
|
||||
{"stat", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, stat_single_show, 0},
|
||||
};
|
||||
|
||||
int proc_pid(int pid)
|
||||
{
|
||||
char pid_str[64] = {0};
|
||||
struct proc_dentry *dentry;
|
||||
|
||||
rt_snprintf(pid_str, 64, "%d", pid);
|
||||
pid_str[63] = 0;
|
||||
|
||||
dentry = proc_mkdir(pid_str, 0);
|
||||
if (dentry)
|
||||
{
|
||||
struct proc_dentry *ent;
|
||||
|
||||
dentry->pid = pid;
|
||||
for (int j = 0; j < sizeof(pid_dentry_base) / sizeof(struct pid_dentry); j++)
|
||||
{
|
||||
if (S_ISDIR(pid_dentry_base[j].mode))
|
||||
{
|
||||
ent = proc_mkdir_data(pid_dentry_base[j].name, pid_dentry_base[j].mode, dentry,
|
||||
pid_dentry_base[j].fops, pid_dentry_base[j].data);
|
||||
}
|
||||
else if (S_ISLNK(pid_dentry_base[j].mode))
|
||||
{
|
||||
if (pid_dentry_base[j].data == RT_NULL)
|
||||
{
|
||||
pid_dentry_base[j].data = "NULL";
|
||||
}
|
||||
|
||||
ent = proc_symlink(pid_dentry_base[j].name, dentry, pid_dentry_base[j].data);
|
||||
}
|
||||
else
|
||||
{
|
||||
ent = proc_create_data(pid_dentry_base[j].name, pid_dentry_base[j].mode, dentry,
|
||||
pid_dentry_base[j].fops, pid_dentry_base[j].data);
|
||||
}
|
||||
|
||||
if (ent)
|
||||
{
|
||||
if (pid_dentry_base[j].ops)
|
||||
{
|
||||
ent->ops = pid_dentry_base[j].ops;
|
||||
}
|
||||
|
||||
if (pid_dentry_base[j].seq_ops)
|
||||
{
|
||||
ent->seq_ops = pid_dentry_base[j].seq_ops;
|
||||
}
|
||||
|
||||
if (pid_dentry_base[j].single_show)
|
||||
{
|
||||
ent->single_show = pid_dentry_base[j].single_show;
|
||||
}
|
||||
|
||||
proc_release(ent);
|
||||
}
|
||||
}
|
||||
proc_release(dentry);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int msh_proc_pid(int argc, char **argv)
|
||||
{
|
||||
if (argc > 1)
|
||||
{
|
||||
for (int i = 1; i <= argc - 1; i++)
|
||||
{
|
||||
proc_pid(atoi(argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT_ALIAS(msh_proc_pid, proc_pid, proc pid);
|
||||
|
||||
#endif
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
#if defined(RT_USING_SMART)
|
||||
|
||||
#include <lwp.h>
|
||||
|
||||
|
||||
int proc_self_readlink(struct proc_dentry *dentry, char *buf, int len)
|
||||
{
|
||||
struct rt_lwp *lwp = RT_NULL;
|
||||
|
||||
lwp = lwp_self();
|
||||
if (lwp)
|
||||
{
|
||||
rt_snprintf(buf, len, "%d", lwp_to_pid(lwp));
|
||||
buf[len - 1] = 0;
|
||||
return rt_strlen(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_snprintf(buf, len, "null");
|
||||
buf[len - 1] = 0;
|
||||
return rt_strlen(buf);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const struct proc_ops proc_pid_fd_ops = {
|
||||
.readlink = proc_self_readlink,
|
||||
};
|
||||
|
||||
int proc_self_init(void)
|
||||
{
|
||||
struct proc_dentry *ent;
|
||||
|
||||
ent = proc_symlink("self", NULL, "NULL");
|
||||
if (ent)
|
||||
{
|
||||
ent->ops = &proc_pid_fd_ops;
|
||||
}
|
||||
proc_release(ent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_self_init);
|
||||
|
||||
#endif
|
114
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c
Normal file
114
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
|
||||
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||
{
|
||||
off_t i = *index; // seq->index
|
||||
|
||||
return NULL + (i == 0);
|
||||
}
|
||||
|
||||
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
off_t i = *index + 1; // seq->index
|
||||
|
||||
*index = i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
int i;
|
||||
rt_cpu_t pcpu;
|
||||
rt_uint64_t user_total = 0;
|
||||
rt_uint64_t system_total = 0;
|
||||
rt_uint64_t idle_total = 0;
|
||||
|
||||
for (i = 0; i < RT_CPUS_NR; i++)
|
||||
{
|
||||
pcpu = rt_cpu_index(i);
|
||||
user_total = user_total + pcpu->cpu_stat.user;
|
||||
system_total = system_total + pcpu->cpu_stat.system;
|
||||
idle_total = idle_total + pcpu->cpu_stat.idle;
|
||||
}
|
||||
dfs_seq_printf(seq, "cpu %llu 0 %llu %llu 0 0 0 0 0 0\n", user_total, system_total, idle_total);
|
||||
|
||||
for (i = 0; i < RT_CPUS_NR; i++)
|
||||
{
|
||||
pcpu = rt_cpu_index(i);
|
||||
dfs_seq_printf(seq, "cpu%d ",i);
|
||||
dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.user);//user
|
||||
dfs_seq_printf(seq, "0 ");//nice
|
||||
dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.system);//system
|
||||
dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.idle);//idle
|
||||
dfs_seq_printf(seq, "0 ");//iowait
|
||||
dfs_seq_printf(seq, "0 ");//irq
|
||||
dfs_seq_printf(seq, "0 ");//softirq
|
||||
dfs_seq_printf(seq, "0 0 0\n");//steal,guest,guest_nice
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dfs_seq_ops seq_ops = {
|
||||
.start = seq_start,
|
||||
.stop = seq_stop,
|
||||
.next = seq_next,
|
||||
.show = seq_show,
|
||||
};
|
||||
|
||||
rt_weak const struct dfs_seq_ops *stat_get_seq_ops(void)
|
||||
{
|
||||
return &seq_ops;
|
||||
}
|
||||
|
||||
static int proc_open(struct dfs_file *file)
|
||||
{
|
||||
return dfs_seq_open(file, stat_get_seq_ops());
|
||||
}
|
||||
|
||||
static int proc_close(struct dfs_file *file)
|
||||
{
|
||||
return dfs_seq_release(file);
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops file_ops = {
|
||||
.open = proc_open,
|
||||
.read = dfs_seq_read,
|
||||
.lseek = dfs_seq_lseek,
|
||||
.close = proc_close,
|
||||
};
|
||||
|
||||
int proc_stat_init(void)
|
||||
{
|
||||
struct proc_dentry *dentry = proc_create_data("stat", 0, NULL, &file_ops, NULL);
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_stat_init);
|
100
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_tty.c
Normal file
100
rt-thread/components/dfs/dfs_v2/filesystems/procfs/proc_tty.c
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
|
||||
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||
{
|
||||
off_t i = *index; // seq->index
|
||||
|
||||
return NULL + (i == 0);
|
||||
}
|
||||
|
||||
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
off_t i = *index + 1; // seq->index
|
||||
|
||||
*index = i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
/* data: The return value of the start or next*/
|
||||
dfs_seq_puts(seq, "todo\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dfs_seq_ops seq_ops = {
|
||||
.start = seq_start,
|
||||
.stop = seq_stop,
|
||||
.next = seq_next,
|
||||
.show = seq_show,
|
||||
};
|
||||
|
||||
void proc_tty_register_driver(void *driver)
|
||||
{
|
||||
//todo
|
||||
}
|
||||
|
||||
void proc_tty_unregister_driver(void *driver)
|
||||
{
|
||||
//todo
|
||||
}
|
||||
|
||||
int proc_tty_init(void)
|
||||
{
|
||||
struct proc_dentry *dentry;
|
||||
|
||||
dentry = proc_mkdir("tty", NULL);
|
||||
if (!dentry)
|
||||
return -1;
|
||||
|
||||
proc_release(dentry);
|
||||
|
||||
dentry = proc_mkdir("tty/ldisc", NULL);
|
||||
proc_release(dentry);
|
||||
|
||||
dentry = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL);
|
||||
proc_release(dentry);
|
||||
|
||||
dentry = proc_create_data("tty/ldiscs", 0, NULL, NULL, NULL);
|
||||
if (dentry)
|
||||
{
|
||||
dentry->seq_ops = &seq_ops;
|
||||
}
|
||||
proc_release(dentry);
|
||||
|
||||
dentry = proc_create_data("tty/drivers", 0, NULL, NULL, NULL);
|
||||
if (dentry)
|
||||
{
|
||||
dentry->seq_ops = &seq_ops;
|
||||
}
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_tty_init);
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
|
||||
static int single_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
dfs_seq_printf(seq, "%lu.%02lu %lu.%02lu\n",
|
||||
(unsigned long)rt_tick_get_millisecond() / 1000, (unsigned long)(rt_tick_get_millisecond() % 1000) / 100,
|
||||
(unsigned long)rt_tick_get_millisecond() / 1000, (unsigned long)(rt_tick_get_millisecond() % 1000) / 100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proc_uptime_init(void)
|
||||
{
|
||||
struct proc_dentry *dentry = proc_create_single_data("uptime", 0, NULL, single_show, NULL);
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_uptime_init);
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
|
||||
static int single_show(struct dfs_seq_file *seq, void *data)
|
||||
{
|
||||
dfs_seq_puts(seq, "\n \\ | /\n");
|
||||
#ifdef RT_USING_SMART
|
||||
dfs_seq_puts(seq, "- RT - Thread Smart Operating System\n");
|
||||
#else
|
||||
dfs_seq_puts(seq, "- RT - Thread Operating System\n");
|
||||
#endif
|
||||
dfs_seq_printf(seq, " / | \\ %d.%d.%d build %s %s\n",
|
||||
(rt_int32_t)RT_VERSION_MAJOR, (rt_int32_t)RT_VERSION_MINOR, (rt_int32_t)RT_VERSION_PATCH,
|
||||
__DATE__, __TIME__);
|
||||
dfs_seq_puts(seq, " 2006 - 2022 Copyright by RT-Thread team\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proc_version_init(void)
|
||||
{
|
||||
struct proc_dentry *dentry = proc_create_single_data("version", 0, NULL, single_show, NULL);
|
||||
proc_release(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(proc_version_init);
|
447
rt-thread/components/dfs/dfs_v2/filesystems/procfs/procfs.c
Normal file
447
rt-thread/components/dfs/dfs_v2/filesystems/procfs/procfs.c
Normal file
@ -0,0 +1,447 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_posix.h>
|
||||
#include <dfs_mnt.h>
|
||||
#include <dfs_dentry.h>
|
||||
|
||||
#include "proc.h"
|
||||
#include "procfs.h"
|
||||
|
||||
#define PROC_DEBUG(...) //rt_kprintf
|
||||
|
||||
static int dfs_procfs_open(struct dfs_file *file)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||
|
||||
|
||||
RT_ASSERT(file->ref_count > 0);
|
||||
|
||||
// this file is opened and in an fdtable
|
||||
if (file->ref_count > 1)
|
||||
{
|
||||
file->fpos = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (entry->fops && entry->fops->open)
|
||||
{
|
||||
ret = entry->fops->open(file);
|
||||
}
|
||||
|
||||
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_procfs_close(struct dfs_file *file)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||
|
||||
RT_ASSERT(file->vnode->ref_count > 0);
|
||||
if (file->vnode->ref_count > 1)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (entry && entry->fops && entry->fops->close)
|
||||
{
|
||||
ret = entry->fops->close(file);
|
||||
}
|
||||
|
||||
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t dfs_procfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
ssize_t ret = -RT_ERROR;
|
||||
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||
|
||||
if (entry && entry->fops && entry->fops->read)
|
||||
{
|
||||
ret = entry->fops->read(file, buf, count, pos);
|
||||
}
|
||||
|
||||
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t dfs_procfs_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
ssize_t ret = -RT_ERROR;
|
||||
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||
|
||||
if (entry && entry->fops && entry->fops->write)
|
||||
{
|
||||
ret = entry->fops->write(file, buf, count, pos);
|
||||
}
|
||||
|
||||
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_procfs_ioctl(struct dfs_file *file, int cmd, void *args)
|
||||
{
|
||||
int ret = -RT_ERROR;
|
||||
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||
|
||||
if (entry && entry->fops && entry->fops->ioctl)
|
||||
{
|
||||
ret = entry->fops->ioctl(file, cmd, args);
|
||||
}
|
||||
|
||||
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_procfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
|
||||
{
|
||||
int ret = 0;
|
||||
rt_uint32_t index = 0;
|
||||
struct dirent *d;
|
||||
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||
|
||||
if (entry)
|
||||
{
|
||||
struct proc_dentry *iter = RT_NULL, *tmp;
|
||||
|
||||
/* make integer count */
|
||||
count = (count / sizeof(struct dirent));
|
||||
if (count == 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dfs_vfs_for_each_subnode(iter, tmp, entry, node)
|
||||
{
|
||||
if (iter == RT_NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (index >= file->fpos)
|
||||
{
|
||||
d = dirp + index - file->fpos;
|
||||
|
||||
if (S_ISDIR(entry->mode))
|
||||
{
|
||||
d->d_type = DT_DIR;
|
||||
}
|
||||
else if (S_ISLNK(entry->mode))
|
||||
{
|
||||
d->d_type = DT_SYMLINK;
|
||||
}
|
||||
else
|
||||
{
|
||||
d->d_type = DT_REG;
|
||||
}
|
||||
|
||||
d->d_namlen = rt_strlen(iter->name);
|
||||
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
||||
rt_strncpy(d->d_name, iter->name, rt_strlen(iter->name) + 1);
|
||||
|
||||
ret ++;
|
||||
}
|
||||
|
||||
index++;
|
||||
if (index - file->fpos >= count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
file->fpos = index;
|
||||
}
|
||||
|
||||
if (entry->fops && entry->fops->getdents && ret < count)
|
||||
{
|
||||
int r;
|
||||
|
||||
file->fpos -= index;
|
||||
|
||||
r = entry->fops->getdents(file, dirp + ret, (count - ret) * sizeof(struct dirent));
|
||||
|
||||
ret = ret * sizeof(struct dirent);
|
||||
|
||||
if (r > 0)
|
||||
{
|
||||
ret += r;
|
||||
}
|
||||
|
||||
file->fpos += index;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ret * sizeof(struct dirent);
|
||||
}
|
||||
}
|
||||
|
||||
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_procfs_poll(struct dfs_file *file, struct rt_pollreq *req)
|
||||
{
|
||||
int ret = -RT_ERROR;
|
||||
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||
|
||||
if (entry && entry->fops && entry->fops->poll)
|
||||
{
|
||||
ret = entry->fops->poll(file, req);
|
||||
}
|
||||
|
||||
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_procfs_flush(struct dfs_file *file)
|
||||
{
|
||||
int ret = -RT_ERROR;
|
||||
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||
|
||||
if (entry && entry->fops && entry->fops->flush)
|
||||
{
|
||||
ret = entry->fops->flush(file);
|
||||
}
|
||||
|
||||
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_procfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
|
||||
{
|
||||
RT_ASSERT(mnt != RT_NULL);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int dfs_procfs_umount(struct dfs_mnt *mnt)
|
||||
{
|
||||
RT_ASSERT(mnt != RT_NULL);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int dfs_procfs_readlink(struct dfs_dentry *dentry, char *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
struct proc_dentry *entry = dfs_proc_find(dentry->pathname);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
if (S_ISLNK(entry->mode) && entry->data)
|
||||
{
|
||||
if (entry->ops && entry->ops->readlink)
|
||||
{
|
||||
ret = entry->ops->readlink(entry, buf, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_strncpy(buf, (const char *)entry->data, len);
|
||||
buf[len - 1] = '\0';
|
||||
ret = rt_strlen(buf);
|
||||
}
|
||||
}
|
||||
|
||||
proc_release(entry);
|
||||
}
|
||||
|
||||
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_procfs_unlink(struct dfs_dentry *dentry)
|
||||
{
|
||||
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, -1);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
static int dfs_procfs_stat(struct dfs_dentry *dentry, struct stat *st)
|
||||
{
|
||||
int ret = RT_EOK;
|
||||
struct dfs_vnode *vnode;
|
||||
|
||||
if (dentry && dentry->vnode)
|
||||
{
|
||||
vnode = dentry->vnode;
|
||||
|
||||
st->st_dev = (dev_t)(dentry->mnt->dev_id);
|
||||
st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry);
|
||||
|
||||
st->st_gid = vnode->gid;
|
||||
st->st_uid = vnode->uid;
|
||||
st->st_mode = vnode->mode;
|
||||
st->st_nlink = vnode->nlink;
|
||||
st->st_size = vnode->size;
|
||||
st->st_mtim.tv_nsec = vnode->mtime.tv_nsec;
|
||||
st->st_mtim.tv_sec = vnode->mtime.tv_sec;
|
||||
st->st_ctim.tv_nsec = vnode->ctime.tv_nsec;
|
||||
st->st_ctim.tv_sec = vnode->ctime.tv_sec;
|
||||
st->st_atim.tv_nsec = vnode->atime.tv_nsec;
|
||||
st->st_atim.tv_sec = vnode->atime.tv_sec;
|
||||
}
|
||||
|
||||
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_procfs_statfs(struct dfs_mnt *mnt, struct statfs *buf)
|
||||
{
|
||||
if (mnt && buf)
|
||||
{
|
||||
buf->f_bsize = 512;
|
||||
buf->f_blocks = 2048 * 64; // 64M
|
||||
buf->f_bfree = buf->f_blocks;
|
||||
buf->f_bavail = buf->f_bfree;
|
||||
}
|
||||
|
||||
PROC_DEBUG(" %s %d\n", __func__, __LINE__);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static struct dfs_vnode *dfs_procfs_lookup(struct dfs_dentry *dentry)
|
||||
{
|
||||
struct dfs_vnode *vnode = RT_NULL;
|
||||
struct proc_dentry *entry = dfs_proc_find(dentry->pathname);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
vnode = dfs_vnode_create();
|
||||
if (vnode)
|
||||
{
|
||||
vnode->nlink = 1;
|
||||
vnode->size = 0;
|
||||
if (S_ISDIR(entry->mode))
|
||||
{
|
||||
vnode->mode = entry->mode;
|
||||
vnode->type = FT_DIRECTORY;
|
||||
}
|
||||
else if (S_ISLNK(entry->mode))
|
||||
{
|
||||
vnode->mode = entry->mode;
|
||||
vnode->type = FT_SYMLINK;
|
||||
}
|
||||
else
|
||||
{
|
||||
vnode->mode = entry->mode;
|
||||
vnode->type = FT_REGULAR;
|
||||
}
|
||||
|
||||
vnode->data = entry;
|
||||
vnode->mnt = dentry->mnt;
|
||||
}
|
||||
|
||||
proc_release(entry);
|
||||
}
|
||||
|
||||
PROC_DEBUG(" %s %d >> %s\n", __func__, __LINE__, dentry->pathname);
|
||||
|
||||
return vnode;
|
||||
}
|
||||
|
||||
static struct dfs_vnode *dfs_procfs_create_vnode(struct dfs_dentry *dentry, int type, mode_t mode)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
static int dfs_procfs_free_vnode(struct dfs_vnode *vnode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops _procfs_fops =
|
||||
{
|
||||
.open = dfs_procfs_open,
|
||||
.close = dfs_procfs_close,
|
||||
.lseek = generic_dfs_lseek,
|
||||
.read = dfs_procfs_read,
|
||||
.write = dfs_procfs_write,
|
||||
.ioctl = dfs_procfs_ioctl,
|
||||
.getdents = dfs_procfs_getdents,
|
||||
.poll = dfs_procfs_poll,
|
||||
.flush = dfs_procfs_flush,
|
||||
};
|
||||
|
||||
static const struct dfs_filesystem_ops _procfs_ops =
|
||||
{
|
||||
.name = "procfs",
|
||||
|
||||
.default_fops = &_procfs_fops,
|
||||
|
||||
.mount = dfs_procfs_mount,
|
||||
.umount = dfs_procfs_umount,
|
||||
.readlink = dfs_procfs_readlink,
|
||||
.unlink = dfs_procfs_unlink,
|
||||
.stat = dfs_procfs_stat,
|
||||
.statfs = dfs_procfs_statfs,
|
||||
.lookup = dfs_procfs_lookup,
|
||||
.create_vnode = dfs_procfs_create_vnode,
|
||||
.free_vnode = dfs_procfs_free_vnode,
|
||||
};
|
||||
|
||||
static struct dfs_filesystem_type _procfs =
|
||||
{
|
||||
.fs_ops = &_procfs_ops,
|
||||
};
|
||||
|
||||
int dfs_procfs_init(void)
|
||||
{
|
||||
/* register procfs file system */
|
||||
dfs_register(&_procfs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(dfs_procfs_init);
|
||||
|
||||
int proc_read_data(struct dfs_file *file, void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
if (file->fpos >= file->vnode->size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (file->data)
|
||||
{
|
||||
count = file->vnode->size - file->fpos >= count ? count : file->vnode->size - file->fpos;
|
||||
rt_strncpy(buf, file->data + file->fpos, count);
|
||||
|
||||
file->fpos += count;
|
||||
*pos = file->fpos;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
19
rt-thread/components/dfs/dfs_v2/filesystems/procfs/procfs.h
Normal file
19
rt-thread/components/dfs/dfs_v2/filesystems/procfs/procfs.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef __PROC_FS_H__
|
||||
#define __PROC_FS_H__
|
||||
|
||||
#include <dfs_file.h>
|
||||
|
||||
int dfs_procfs_init(void);
|
||||
|
||||
int proc_read_data(struct dfs_file *file, void *buf, size_t count, off_t *pos);
|
||||
|
||||
#endif
|
@ -262,7 +262,7 @@ ptsno_t ptyfs_register_pts(rt_device_t ptmx, rt_device_t pts)
|
||||
pts_file = rt_calloc(1, sizeof(struct ptyfs_file));
|
||||
if (pts_file)
|
||||
{
|
||||
snprintf(pts_file->basename, DIRENT_NAME_MAX, "%lu", rc);
|
||||
snprintf(pts_file->basename, DIRENT_NAME_MAX, "%lu", (unsigned long)rc);
|
||||
ptyfile_init(pts_file, sb, 0, PTYFS_TYPE_FILE_SLAVE,
|
||||
PTS_DEFAULT_FILE_MODE, pts);
|
||||
ptyfile_add_to_root(sb, pts_file);
|
||||
@ -296,7 +296,7 @@ rt_err_t ptyfs_unregister_pts(rt_device_t ptmx, ptsno_t ptsno)
|
||||
else
|
||||
{
|
||||
/* get path and findout device */
|
||||
snprintf(path_buf, sizeof(path_buf), "%lu", ptsno);
|
||||
snprintf(path_buf, sizeof(path_buf), "%lu", (unsigned long)ptsno);
|
||||
pts_file = ptyfile_lookup(sb, path_buf);
|
||||
if (pts_file)
|
||||
{
|
||||
|
@ -365,6 +365,7 @@ static const struct dfs_file_ops _rom_fops =
|
||||
{
|
||||
.open = dfs_romfs_open,
|
||||
.close = dfs_romfs_close,
|
||||
.ioctl = dfs_romfs_ioctl,
|
||||
.lseek = generic_dfs_lseek,
|
||||
.read = dfs_romfs_read,
|
||||
.getdents = dfs_romfs_getdents,
|
||||
|
@ -99,15 +99,13 @@ static int _get_subdir(const char *path, char *name)
|
||||
|
||||
static int _free_subdir(struct tmpfs_file *dfile)
|
||||
{
|
||||
struct tmpfs_file *file;
|
||||
rt_list_t *list, *temp_list;
|
||||
struct tmpfs_file *file = RT_NULL, *tmp;
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
|
||||
|
||||
rt_list_for_each_safe(list, temp_list, &dfile->subdirs)
|
||||
dfs_vfs_for_each_subnode(file, tmp, dfile, node)
|
||||
{
|
||||
file = rt_list_entry(list, struct tmpfs_file, sibling);
|
||||
if (file->type == TMPFS_TYPE_DIR)
|
||||
{
|
||||
_free_subdir(file);
|
||||
@ -122,7 +120,7 @@ static int _free_subdir(struct tmpfs_file *dfile)
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(file->sibling));
|
||||
dfs_vfs_remove_node(&file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(file);
|
||||
@ -141,13 +139,11 @@ static int dfs_tmpfs_mount(struct dfs_mnt *mnt,
|
||||
{
|
||||
superblock->df_size = sizeof(struct tmpfs_sb);
|
||||
superblock->magic = TMPFS_MAGIC;
|
||||
rt_list_init(&superblock->sibling);
|
||||
|
||||
superblock->root.name[0] = '/';
|
||||
superblock->root.sb = superblock;
|
||||
superblock->root.type = TMPFS_TYPE_DIR;
|
||||
rt_list_init(&superblock->root.sibling);
|
||||
rt_list_init(&superblock->root.subdirs);
|
||||
dfs_vfs_init_node(&superblock->root.node);
|
||||
|
||||
rt_spin_lock_init(&superblock->lock);
|
||||
|
||||
@ -236,8 +232,7 @@ struct tmpfs_file *dfs_tmpfs_lookup(struct tmpfs_sb *superblock,
|
||||
{
|
||||
const char *subpath, *curpath, *filename = RT_NULL;
|
||||
char subdir_name[TMPFS_NAME_MAX];
|
||||
struct tmpfs_file *file, *curfile;
|
||||
rt_list_t *list;
|
||||
struct tmpfs_file *file, *curfile, *tmp;
|
||||
|
||||
subpath = path;
|
||||
while (*subpath == '/' && *subpath)
|
||||
@ -265,9 +260,8 @@ find_subpath:
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
|
||||
rt_list_for_each(list, &curfile->subdirs)
|
||||
dfs_vfs_for_each_subnode(file, tmp, curfile, node)
|
||||
{
|
||||
file = rt_list_entry(list, struct tmpfs_file, sibling);
|
||||
if (filename) /* find file */
|
||||
{
|
||||
if (rt_strcmp(file->name, filename) == 0)
|
||||
@ -503,8 +497,7 @@ static int dfs_tmpfs_getdents(struct dfs_file *file,
|
||||
{
|
||||
rt_size_t index, end;
|
||||
struct dirent *d;
|
||||
struct tmpfs_file *d_file, *n_file;
|
||||
rt_list_t *list;
|
||||
struct tmpfs_file *d_file, *n_file, *tmp;
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
d_file = (struct tmpfs_file *)file->vnode->data;
|
||||
@ -527,9 +520,8 @@ static int dfs_tmpfs_getdents(struct dfs_file *file,
|
||||
index = 0;
|
||||
count = 0;
|
||||
|
||||
rt_list_for_each(list, &d_file->subdirs)
|
||||
dfs_vfs_for_each_subnode(n_file, tmp, d_file, node)
|
||||
{
|
||||
n_file = rt_list_entry(list, struct tmpfs_file, sibling);
|
||||
if (index >= (rt_size_t)file->fpos)
|
||||
{
|
||||
d = dirp + count;
|
||||
@ -573,7 +565,7 @@ static int dfs_tmpfs_unlink(struct dfs_dentry *dentry)
|
||||
return -ENOENT;
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(d_file->sibling));
|
||||
dfs_vfs_remove_node(&d_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
if (rt_atomic_load(&(dentry->ref_count)) == 1)
|
||||
@ -631,13 +623,13 @@ static int dfs_tmpfs_rename(struct dfs_dentry *old_dentry, struct dfs_dentry *ne
|
||||
RT_ASSERT(p_file != NULL);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(d_file->sibling));
|
||||
dfs_vfs_remove_node(&d_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
||||
dfs_vfs_append_node(&p_file->node, &d_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(parent_path);
|
||||
@ -745,8 +737,7 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t
|
||||
|
||||
strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
|
||||
|
||||
rt_list_init(&(d_file->subdirs));
|
||||
rt_list_init(&(d_file->sibling));
|
||||
dfs_vfs_init_node(&d_file->node);
|
||||
d_file->data = NULL;
|
||||
d_file->size = 0;
|
||||
d_file->sb = superblock;
|
||||
@ -767,7 +758,7 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t
|
||||
#endif
|
||||
}
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
||||
dfs_vfs_append_node(&p_file->node, &d_file->node);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
vnode->mnt = dentry->mnt;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#define __DFS_TMPFS_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <dfs_vfs.h>
|
||||
|
||||
#define TMPFS_NAME_MAX 32
|
||||
#define TMPFS_MAGIC 0x0B0B0B0B
|
||||
@ -25,8 +26,7 @@ struct tmpfs_file
|
||||
{
|
||||
rt_uint32_t type; /* file type */
|
||||
char name[TMPFS_NAME_MAX]; /* file name */
|
||||
rt_list_t subdirs; /* file subdir list */
|
||||
rt_list_t sibling; /* file sibling list */
|
||||
struct dfs_vfs_node node; /* file node in the tmpfs */
|
||||
struct tmpfs_sb *sb; /* superblock ptr */
|
||||
rt_uint8_t *data; /* file date ptr */
|
||||
rt_size_t size; /* file size */
|
||||
|
@ -20,6 +20,38 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define MS_RDONLY 1
|
||||
#define MS_NOSUID 2
|
||||
#define MS_NODEV 4
|
||||
#define MS_NOEXEC 8
|
||||
#define MS_SYNCHRONOUS 16
|
||||
#define MS_REMOUNT 32
|
||||
#define MS_MANDLOCK 64
|
||||
#define MS_DIRSYNC 128
|
||||
#define MS_NOATIME 1024
|
||||
#define MS_NODIRATIME 2048
|
||||
#define MS_BIND 4096
|
||||
#define MS_MOVE 8192
|
||||
#define MS_REC 16384
|
||||
#define MS_SILENT 32768
|
||||
#define MS_POSIXACL (1<<16)
|
||||
#define MS_UNBINDABLE (1<<17)
|
||||
#define MS_PRIVATE (1<<18)
|
||||
#define MS_SLAVE (1<<19)
|
||||
#define MS_SHARED (1<<20)
|
||||
#define MS_RELATIME (1<<21)
|
||||
#define MS_KERNMOUNT (1<<22)
|
||||
#define MS_I_VERSION (1<<23)
|
||||
#define MS_STRICTATIME (1<<24)
|
||||
#define MS_LAZYTIME (1<<25)
|
||||
#define MS_NOREMOTELOCK (1<<27)
|
||||
#define MS_NOSEC (1<<28)
|
||||
#define MS_BORN (1<<29)
|
||||
#define MS_ACTIVE (1<<30)
|
||||
#define MS_NOUSER (1U<<31)
|
||||
|
||||
#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|MS_LAZYTIME)
|
||||
|
||||
/* file system partition table */
|
||||
struct dfs_partition
|
||||
{
|
||||
@ -87,6 +119,7 @@ int dfs_unregister(struct dfs_filesystem_type *fs);
|
||||
int dfs_register(struct dfs_filesystem_type *fs);
|
||||
const char *dfs_filesystem_get_mounted_path(struct rt_device *device);
|
||||
|
||||
int dfs_remount(const char *path, rt_ubase_t flags, void *data);
|
||||
int dfs_mount(const char *device_name,
|
||||
const char *path,
|
||||
const char *filesystemtype,
|
||||
|
@ -39,6 +39,8 @@ struct dfs_mnt
|
||||
#define MNT_IS_UMOUNT 0x8 /* the mnt is unmount */
|
||||
#define MNT_IS_LOCKED 0x10 /* the mnt is locked */
|
||||
#define MNT_FORCE 0x20 /* the mnt force unmount */
|
||||
#define MNT_LAZY_UMNT 0x40 /* the mnt has pending umount */
|
||||
#define MNT_RDONLY 0x80 /* the mnt is read only */
|
||||
|
||||
rt_atomic_t ref_count; /* reference count */
|
||||
|
||||
@ -60,9 +62,16 @@ const char *dfs_mnt_get_mounted_path(struct rt_device *device);
|
||||
struct dfs_mnt* dfs_mnt_ref(struct dfs_mnt* mnt);
|
||||
int dfs_mnt_unref(struct dfs_mnt* mnt);
|
||||
|
||||
int dfs_mnt_umount(struct dfs_mnt *mnt, int flags);
|
||||
int dfs_mnt_setflags(struct dfs_mnt *mnt, int flags);
|
||||
|
||||
rt_bool_t dfs_mnt_has_child_mnt(struct dfs_mnt *mnt, const char* fullpath);
|
||||
|
||||
int dfs_mnt_foreach(struct dfs_mnt* (*func)(struct dfs_mnt *mnt, void *parameter), void *parameter);
|
||||
int dfs_mnt_umount_iter(rt_bool_t (*filter)(struct dfs_mnt *mnt, void *parameter), void *parameter);
|
||||
|
||||
typedef void (*dfs_mnt_umnt_cb_t)(struct dfs_mnt *mnt);
|
||||
RT_OBJECT_HOOKLIST_DECLARE(dfs_mnt_umnt_cb_t, dfs_mnt_umnt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -118,6 +118,7 @@ int dfs_aspace_mmap_write(struct dfs_file *file, struct rt_varea *varea, void *d
|
||||
|
||||
void dfs_pcache_release(size_t count);
|
||||
void dfs_pcache_unmount(struct dfs_mnt *mnt);
|
||||
void dfs_pcache_clean(struct dfs_mnt *mnt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ static inline void dfs_seq_setwidth(struct dfs_seq_file *seq, size_t size)
|
||||
|
||||
int dfs_seq_open(struct dfs_file *file, const struct dfs_seq_ops *ops);
|
||||
ssize_t dfs_seq_read(struct dfs_file *file, void *buf, size_t size, off_t *pos);
|
||||
ssize_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence);
|
||||
off_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence);
|
||||
int dfs_seq_release(struct dfs_file *file);
|
||||
int dfs_seq_write(struct dfs_seq_file *seq, const void *data, size_t len);
|
||||
|
||||
|
50
rt-thread/components/dfs/dfs_v2/include/dfs_vfs.h
Normal file
50
rt-thread/components/dfs/dfs_v2/include/dfs_vfs.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef __DFS_VFS_H__
|
||||
#define __DFS_VFS_H__
|
||||
|
||||
#include "dfs_file.h"
|
||||
#include "dfs_fs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct dfs_vfs_node
|
||||
{
|
||||
rt_list_t subnode; /* file subnode list */
|
||||
rt_list_t sibling; /* file sibling list */
|
||||
};
|
||||
|
||||
rt_inline void dfs_vfs_init_node(struct dfs_vfs_node *node)
|
||||
{
|
||||
rt_list_init(&node->subnode);
|
||||
rt_list_init(&node->sibling);
|
||||
}
|
||||
|
||||
rt_inline void dfs_vfs_append_node(struct dfs_vfs_node *dir, struct dfs_vfs_node *node)
|
||||
{
|
||||
rt_list_insert_after(&(dir->subnode), &(node->sibling));
|
||||
}
|
||||
|
||||
rt_inline void dfs_vfs_remove_node(struct dfs_vfs_node *node)
|
||||
{
|
||||
rt_list_remove(&(node->sibling));
|
||||
}
|
||||
|
||||
#define dfs_vfs_for_each_subnode(node, tmp, dir, member) \
|
||||
rt_list_for_each_entry_safe(node, tmp, &dir->member.subnode, member.sibling)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__DFS_VFS_H__*/
|
@ -537,6 +537,7 @@ int dfs_dup(int oldfd, int startfd)
|
||||
fdt = dfs_fdtable_get();
|
||||
if ((oldfd < 0) || (oldfd >= fdt->maxfd))
|
||||
{
|
||||
rt_set_errno(-EBADF);
|
||||
goto exit;
|
||||
}
|
||||
if (!fdt->fds[oldfd])
|
||||
@ -668,12 +669,17 @@ sysret_t sys_dup(int oldfd)
|
||||
int sys_dup(int oldfd)
|
||||
#endif
|
||||
{
|
||||
int err = 0;
|
||||
int newfd = dfs_dup(oldfd, (dfs_fdtable_get() == &_fdtab) ? DFS_STDIO_OFFSET : 0);
|
||||
if(newfd < 0)
|
||||
{
|
||||
err = rt_get_errno();
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SMART
|
||||
return (sysret_t)newfd;
|
||||
return err < 0 ? err : newfd;
|
||||
#else
|
||||
return newfd;
|
||||
return err < 0 ? err : newfd;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1379,6 +1379,7 @@ int dfs_file_link(const char *oldname, const char *newname)
|
||||
|
||||
if (dfs_file_isdir(oldname) == 0)
|
||||
{
|
||||
rt_set_errno(-EPERM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1567,6 +1568,10 @@ int dfs_file_symlink(const char *target, const char *linkpath)
|
||||
rt_free(parent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_set_errno(-EPERM);
|
||||
}
|
||||
|
||||
if (fullpath != linkpath)
|
||||
rt_free(fullpath);
|
||||
|
@ -95,6 +95,52 @@ int dfs_unregister(struct dfs_filesystem_type *fs)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define REMNT_UNSUPP_FLAGS (~(MS_REMOUNT | MS_RMT_MASK))
|
||||
int dfs_remount(const char *path, rt_ubase_t flags, void *data)
|
||||
{
|
||||
int rc = 0;
|
||||
char *fullpath = RT_NULL;
|
||||
struct dfs_mnt *mnt = RT_NULL;
|
||||
|
||||
if (flags & REMNT_UNSUPP_FLAGS)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fullpath = dfs_normalize_path(RT_NULL, path);
|
||||
if (!fullpath)
|
||||
{
|
||||
rc = -ENOENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt = dfs_mnt_lookup(%s)", fullpath);
|
||||
mnt = dfs_mnt_lookup(fullpath);
|
||||
if (mnt)
|
||||
{
|
||||
dfs_lock();
|
||||
dfs_mnt_setflags(mnt, flags);
|
||||
dfs_unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
struct stat buf = {0};
|
||||
if (dfs_file_stat(fullpath, &buf) == 0 && S_ISBLK(buf.st_mode))
|
||||
{
|
||||
/* path was not already mounted on target */
|
||||
rc = -EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* path is not a directory */
|
||||
rc = -ENOTDIR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* parent(mount path)
|
||||
* mnt_parent <- - - - - - - +
|
||||
@ -127,7 +173,7 @@ int dfs_mount(const char *device_name,
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_set_errno(ENOENT);
|
||||
rt_set_errno(ENODEV);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
@ -300,7 +346,7 @@ int dfs_mount(const char *device_name,
|
||||
|
||||
int dfs_umount(const char *specialfile, int flags)
|
||||
{
|
||||
int ret = -RT_ERROR;
|
||||
int ret = -1;
|
||||
char *fullpath = RT_NULL;
|
||||
struct dfs_mnt *mnt = RT_NULL;
|
||||
|
||||
@ -314,7 +360,7 @@ int dfs_umount(const char *specialfile, int flags)
|
||||
if (strcmp(mnt->fullpath, fullpath) == 0)
|
||||
{
|
||||
/* is the mount point */
|
||||
rt_atomic_t ref_count = rt_atomic_load(&(mnt->ref_count));
|
||||
rt_base_t ref_count = rt_atomic_load(&(mnt->ref_count));
|
||||
|
||||
if (!(mnt->flags & MNT_IS_LOCKED) && rt_list_isempty(&mnt->child) && (ref_count == 1 || (flags & MNT_FORCE)))
|
||||
{
|
||||
@ -327,17 +373,19 @@ int dfs_umount(const char *specialfile, int flags)
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("the file system is busy!");
|
||||
LOG_I("the file system is busy!");
|
||||
ret = -EBUSY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("the path:%s is not a mountpoint!", fullpath);
|
||||
LOG_I("the path:%s is not a mountpoint!", fullpath);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("no filesystem found.");
|
||||
LOG_I("no filesystem found.");
|
||||
}
|
||||
rt_free(fullpath);
|
||||
}
|
||||
|
@ -10,17 +10,21 @@
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "dfs.h"
|
||||
#include "dfs_mnt.h"
|
||||
#include "dfs_dentry.h"
|
||||
#include "dfs_private.h"
|
||||
|
||||
#include <dfs.h>
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_mnt.h>
|
||||
#include <dfs_pcache.h>
|
||||
|
||||
#define DBG_TAG "DFS.mnt"
|
||||
#define DBG_LVL DBG_WARNING
|
||||
#include <rtdbg.h>
|
||||
|
||||
static struct dfs_mnt *_root_mnt = RT_NULL;
|
||||
|
||||
RT_OBJECT_HOOKLIST_DEFINE(dfs_mnt_umnt);
|
||||
|
||||
/*
|
||||
* mnt tree structure
|
||||
*
|
||||
@ -75,6 +79,7 @@ int dfs_mnt_insert(struct dfs_mnt* mnt, struct dfs_mnt* child)
|
||||
child = _root_mnt;
|
||||
rt_atomic_sub(&(_root_mnt->parent->ref_count), 1);
|
||||
rt_atomic_sub(&(_root_mnt->ref_count), 1);
|
||||
_root_mnt->flags &= ~MNT_IS_LOCKED;
|
||||
|
||||
_root_mnt = dfs_mnt_ref(mnt);
|
||||
mnt->parent = dfs_mnt_ref(mnt);
|
||||
@ -242,21 +247,24 @@ struct dfs_mnt* dfs_mnt_ref(struct dfs_mnt* mnt)
|
||||
return mnt;
|
||||
}
|
||||
|
||||
int dfs_mnt_unref(struct dfs_mnt* mnt)
|
||||
int dfs_mnt_unref(struct dfs_mnt *mnt)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
rt_base_t ref_count;
|
||||
|
||||
if (mnt)
|
||||
{
|
||||
rt_atomic_sub(&(mnt->ref_count), 1);
|
||||
ref_count = rt_atomic_sub(&(mnt->ref_count), 1) - 1;
|
||||
|
||||
if (rt_atomic_load(&(mnt->ref_count)) == 0)
|
||||
if (ref_count == 0)
|
||||
{
|
||||
dfs_lock();
|
||||
|
||||
if (mnt->flags & MNT_IS_UMOUNT)
|
||||
{
|
||||
mnt->fs_ops->umount(mnt);
|
||||
|
||||
RT_OBJECT_HOOKLIST_CALL(dfs_mnt_umnt, (mnt));
|
||||
}
|
||||
|
||||
/* free full path */
|
||||
@ -278,6 +286,21 @@ int dfs_mnt_unref(struct dfs_mnt* mnt)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dfs_mnt_setflags(struct dfs_mnt *mnt, int flags)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if (flags & MS_RDONLY)
|
||||
{
|
||||
mnt->flags |= MNT_RDONLY;
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
dfs_pcache_clean(mnt);
|
||||
#endif
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int dfs_mnt_destroy(struct dfs_mnt* mnt)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
@ -13,17 +13,19 @@
|
||||
#define DBG_LVL DBG_WARNING
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "dfs_pcache.h"
|
||||
#include "dfs_dentry.h"
|
||||
#include "dfs_mnt.h"
|
||||
#include "mm_page.h"
|
||||
#include <mmu.h>
|
||||
#include <tlb.h>
|
||||
#include <dfs_pcache.h>
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_mnt.h>
|
||||
|
||||
#include <rthw.h>
|
||||
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
|
||||
#include <mm_page.h>
|
||||
#include <mm_private.h>
|
||||
#include <mmu.h>
|
||||
#include <tlb.h>
|
||||
|
||||
#ifndef RT_PAGECACHE_COUNT
|
||||
#define RT_PAGECACHE_COUNT 4096
|
||||
#endif
|
||||
@ -160,7 +162,7 @@ void dfs_pcache_release(size_t count)
|
||||
dfs_pcache_unlock();
|
||||
}
|
||||
|
||||
void dfs_pcache_unmount(struct dfs_mnt *mnt)
|
||||
static void _pcache_clean(struct dfs_mnt *mnt, int (*cb)(struct dfs_aspace *aspace))
|
||||
{
|
||||
rt_list_t *node = RT_NULL;
|
||||
struct dfs_aspace *aspace = RT_NULL;
|
||||
@ -175,7 +177,7 @@ void dfs_pcache_unmount(struct dfs_mnt *mnt)
|
||||
if (aspace && aspace->mnt == mnt)
|
||||
{
|
||||
dfs_aspace_clean(aspace);
|
||||
dfs_aspace_release(aspace);
|
||||
cb(aspace);
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,13 +189,28 @@ void dfs_pcache_unmount(struct dfs_mnt *mnt)
|
||||
if (aspace && aspace->mnt == mnt)
|
||||
{
|
||||
dfs_aspace_clean(aspace);
|
||||
dfs_aspace_release(aspace);
|
||||
cb(aspace);
|
||||
}
|
||||
}
|
||||
|
||||
dfs_pcache_unlock();
|
||||
}
|
||||
|
||||
void dfs_pcache_unmount(struct dfs_mnt *mnt)
|
||||
{
|
||||
_pcache_clean(mnt, dfs_aspace_release);
|
||||
}
|
||||
|
||||
static int _dummy_cb(struct dfs_aspace *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dfs_pcache_clean(struct dfs_mnt *mnt)
|
||||
{
|
||||
_pcache_clean(mnt, _dummy_cb);
|
||||
}
|
||||
|
||||
static int dfs_pcache_limit_check(void)
|
||||
{
|
||||
int index = 4;
|
||||
@ -1138,14 +1155,21 @@ int dfs_aspace_write(struct dfs_file *file, const void *buf, size_t count, off_t
|
||||
|
||||
if (file && file->vnode && file->vnode->aspace)
|
||||
{
|
||||
if (!(file->vnode->aspace->ops->write))
|
||||
return ret;
|
||||
struct dfs_vnode *vnode = file->vnode;
|
||||
struct dfs_aspace *aspace = vnode->aspace;
|
||||
|
||||
struct dfs_page *page;
|
||||
char *ptr = (char *)buf;
|
||||
|
||||
if (!(aspace->ops->write))
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
else if (aspace->mnt && (aspace->mnt->flags & MNT_RDONLY))
|
||||
{
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
while (count)
|
||||
@ -1380,7 +1404,8 @@ int dfs_aspace_unmap(struct dfs_file *file, struct rt_varea *varea)
|
||||
|
||||
rt_varea_unmap_page(map_varea, vaddr);
|
||||
|
||||
if (varea->attr == MMU_MAP_U_RWCB && page->fpos < page->aspace->vnode->size)
|
||||
if (!rt_varea_is_private_locked(varea) &&
|
||||
page->fpos < page->aspace->vnode->size)
|
||||
{
|
||||
dfs_page_dirty(page);
|
||||
}
|
||||
@ -1425,7 +1450,7 @@ int dfs_aspace_page_unmap(struct dfs_file *file, struct rt_varea *varea, void *v
|
||||
|
||||
if (map && varea->aspace == map->aspace && vaddr == map->vaddr)
|
||||
{
|
||||
if (varea->attr == MMU_MAP_U_RWCB)
|
||||
if (!rt_varea_is_private_locked(varea))
|
||||
{
|
||||
dfs_page_dirty(page);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -31,7 +31,17 @@
|
||||
* return a file descriptor according specified flags.
|
||||
*
|
||||
* @param file the path name of file.
|
||||
* @param flags the file open flags.
|
||||
* @param flags the file open flags. Common values include:
|
||||
* - Access modes (mutually exclusive):
|
||||
* - `O_RDONLY`: Open for read-only access.
|
||||
* - `O_WRONLY`: Open for write-only access.
|
||||
* - `O_RDWR`: Open for both reading and writing.
|
||||
* - File status flags (can be combined with bitwise OR `|`):
|
||||
* - `O_CREAT`: Create the file if it does not exist. Requires a `mode` argument.
|
||||
* - `O_TRUNC`: Truncate the file to zero length if it already exists.
|
||||
* - `O_APPEND`: Append writes to the end of the file.
|
||||
* - `O_EXCL`: Ensure that `O_CREAT` creates the file exclusively.
|
||||
* - Other platform-specific flags
|
||||
*
|
||||
* @return the non-negative integer on successful open, others for failed.
|
||||
*/
|
||||
@ -81,6 +91,22 @@ RTM_EXPORT(open);
|
||||
#ifndef AT_FDCWD
|
||||
#define AT_FDCWD (-100)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Opens a file relative to a directory file descriptor.
|
||||
*
|
||||
* @param dirfd The file descriptor of the directory to base the relative path on.
|
||||
* @param path The path to the file to be opened, relative to the directory specified by `dirfd`.
|
||||
* Can be an absolute path (in which case `dirfd` is ignored).
|
||||
* @param flag File access and status flags (e.g., `O_RDONLY`, `O_WRONLY`, `O_CREAT`).
|
||||
*
|
||||
* @return On success, returns a new file descriptor for the opened file.
|
||||
* On failure, returns `-1` and sets `errno` to indicate the error.
|
||||
*
|
||||
* @note When using relative paths, ensure `dirfd` is a valid directory descriptor.
|
||||
* When `pathname` is absolute, the `dirfd` argument is ignored.
|
||||
*
|
||||
*/
|
||||
int openat(int dirfd, const char *path, int flag, ...)
|
||||
{
|
||||
struct dfs_file *d;
|
||||
@ -171,7 +197,7 @@ int utimensat(int __fd, const char *__path, const struct timespec __times[2], in
|
||||
}
|
||||
}
|
||||
|
||||
//update time
|
||||
/*update time*/
|
||||
attr.ia_valid = ATTR_ATIME_SET | ATTR_MTIME_SET;
|
||||
time(¤t_time);
|
||||
if (UTIME_NOW == __times[0].tv_nsec)
|
||||
@ -374,14 +400,22 @@ ssize_t write(int fd, const void *buf, size_t len)
|
||||
RTM_EXPORT(write);
|
||||
|
||||
/**
|
||||
* this function is a POSIX compliant version, which will seek the offset for
|
||||
* this function is a POSIX compliant version, which will Reposition the file offset for
|
||||
* an open file descriptor.
|
||||
*
|
||||
* @param fd the file descriptor.
|
||||
* @param offset the offset to be seeked.
|
||||
* @param whence the directory of seek.
|
||||
* The `lseek` function sets the file offset for the file descriptor `fd`
|
||||
* to a new value, determined by the `offset` and `whence` parameters.
|
||||
* It can be used to seek to specific positions in a file for reading or writing.
|
||||
*
|
||||
* @return the current read/write position in the file, or -1 on failed.
|
||||
* @param fd the file descriptor.
|
||||
* @param offset The offset, in bytes, to set the file position.
|
||||
* The meaning of `offset` depends on the value of `whence`.
|
||||
* @param whence the directive of seek. It can be one of:
|
||||
* - `SEEK_SET`: Set the offset to `offset` bytes from the beginning of the file.
|
||||
* - `SEEK_CUR`: Set the offset to its current location plus `offset` bytes.
|
||||
* - `SEEK_END`: Set the offset to the size of the file plus `offset` bytes.
|
||||
*
|
||||
* @return the resulting read/write position in the file, or -1 on failed.
|
||||
*/
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
@ -399,7 +433,7 @@ off_t lseek(int fd, off_t offset, int whence)
|
||||
result = dfs_file_lseek(file, offset, whence);
|
||||
if (result < 0)
|
||||
{
|
||||
rt_set_errno(result);
|
||||
rt_set_errno(-EPERM);
|
||||
|
||||
return -1;
|
||||
}
|
||||
@ -581,9 +615,15 @@ RTM_EXPORT(fsync);
|
||||
* control functions on devices.
|
||||
*
|
||||
* @param fildes the file description
|
||||
* @param cmd the specified command
|
||||
* @param cmd the specified command, Common values include:
|
||||
* - `F_DUPFD`: Duplicate a file descriptor.
|
||||
* - `F_GETFD`: Get the file descriptor flags.
|
||||
* - `F_SETFD`: Set the file descriptor flags.
|
||||
* - `F_GETFL`: Get the file status flags.
|
||||
* - `F_SETFL`: Set the file status flags.
|
||||
* @param ... represents the additional information that is needed by this
|
||||
* specific device to perform the requested function.
|
||||
* specific device to perform the requested function. For example:
|
||||
* - When `cmd` is `F_SETFL`, an additional integer argument specifies the new status flags.
|
||||
*
|
||||
* @return 0 on successful completion. Otherwise, -1 shall be returned and errno
|
||||
* set to indicate the error.
|
||||
@ -765,7 +805,7 @@ RTM_EXPORT(fstatfs);
|
||||
* this function is a POSIX compliant version, which will make a directory
|
||||
*
|
||||
* @param path the directory path to be made.
|
||||
* @param mode
|
||||
* @param mode The permission mode for the new directory (unused here, can be set to 0).
|
||||
*
|
||||
* @return 0 on successful, others on failed.
|
||||
*/
|
||||
@ -827,7 +867,7 @@ int rmdir(const char *pathname)
|
||||
|
||||
if (!pathname)
|
||||
{
|
||||
rt_set_errno(-RT_ERROR);
|
||||
rt_set_errno(-EPERM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -852,7 +892,7 @@ int rmdir(const char *pathname)
|
||||
|
||||
if (dirent)
|
||||
{
|
||||
rt_set_errno(-RT_ERROR);
|
||||
rt_set_errno(-EPERM);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -861,7 +901,7 @@ int rmdir(const char *pathname)
|
||||
{
|
||||
if (S_ISLNK(stat.st_mode))
|
||||
{
|
||||
rt_set_errno(-RT_ERROR);
|
||||
rt_set_errno(-EPERM);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ Enomem:
|
||||
goto Done;
|
||||
}
|
||||
|
||||
ssize_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence)
|
||||
off_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence)
|
||||
{
|
||||
struct dfs_seq_file *seq = file->data;
|
||||
off_t retval = -EINVAL;
|
||||
|
@ -21,8 +21,21 @@ rsource "touch/Kconfig"
|
||||
rsource "graphic/Kconfig"
|
||||
rsource "hwcrypto/Kconfig"
|
||||
rsource "wlan/Kconfig"
|
||||
rsource "led/Kconfig"
|
||||
rsource "mailbox/Kconfig"
|
||||
rsource "phye/Kconfig"
|
||||
rsource "ata/Kconfig"
|
||||
rsource "nvme/Kconfig"
|
||||
rsource "block/Kconfig"
|
||||
rsource "scsi/Kconfig"
|
||||
rsource "regulator/Kconfig"
|
||||
rsource "reset/Kconfig"
|
||||
rsource "thermal/Kconfig"
|
||||
rsource "virtio/Kconfig"
|
||||
rsource "dma/Kconfig"
|
||||
rsource "mfd/Kconfig"
|
||||
rsource "ofw/Kconfig"
|
||||
rsource "pci/Kconfig"
|
||||
rsource "pic/Kconfig"
|
||||
rsource "pin/Kconfig"
|
||||
rsource "pinctrl/Kconfig"
|
||||
|
22
rt-thread/components/drivers/ata/Kconfig
Normal file
22
rt-thread/components/drivers/ata/Kconfig
Normal file
@ -0,0 +1,22 @@
|
||||
menuconfig RT_USING_ATA
|
||||
bool "Using Advanced Technology Attachment (ATA) device drivers"
|
||||
depends on RT_USING_DM
|
||||
depends on RT_USING_BLK
|
||||
depends on RT_USING_DMA
|
||||
default n
|
||||
|
||||
config RT_ATA_AHCI
|
||||
bool "Advanced Host Controller Interface (AHCI)"
|
||||
depends on RT_USING_ATA
|
||||
depends on RT_USING_SCSI
|
||||
default y
|
||||
|
||||
config RT_ATA_AHCI_PCI
|
||||
bool "AHCI support on PCI bus"
|
||||
depends on RT_ATA_AHCI
|
||||
depends on RT_USING_PCI
|
||||
default n
|
||||
|
||||
if RT_USING_ATA
|
||||
osource "$(SOC_DM_ATA_DIR)/Kconfig"
|
||||
endif
|
21
rt-thread/components/drivers/ata/SConscript
Normal file
21
rt-thread/components/drivers/ata/SConscript
Normal file
@ -0,0 +1,21 @@
|
||||
from building import *
|
||||
|
||||
group = []
|
||||
|
||||
if not GetDepend(['RT_USING_ATA']):
|
||||
Return('group')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd + '/../include']
|
||||
|
||||
src = []
|
||||
|
||||
if GetDepend(['RT_ATA_AHCI']):
|
||||
src += ['ahci.c']
|
||||
|
||||
if GetDepend(['RT_ATA_AHCI_PCI']):
|
||||
src += ['ahci-pci.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
206
rt-thread/components/drivers/ata/ahci-pci.c
Normal file
206
rt-thread/components/drivers/ata/ahci-pci.c
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define AHCI_REG_BAR 5
|
||||
|
||||
struct pci_ahci_quirk
|
||||
{
|
||||
int bar_idx;
|
||||
rt_bool_t bar_offset;
|
||||
|
||||
const struct rt_ahci_ops *ops;
|
||||
};
|
||||
|
||||
struct pci_ahci_host
|
||||
{
|
||||
struct rt_ahci_host parent;
|
||||
const struct pci_ahci_quirk *quirk;
|
||||
|
||||
rt_bool_t is_msi;
|
||||
};
|
||||
|
||||
#define raw_to_pci_ahci_host(raw) rt_container_of(raw, struct pci_ahci_host, parent)
|
||||
|
||||
static rt_err_t pci_ahci_init(struct rt_ahci_host *host)
|
||||
{
|
||||
struct rt_pci_device *pdev;
|
||||
|
||||
pdev = rt_container_of(host->parent.dev, struct rt_pci_device, parent);
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_JMICRON)
|
||||
{
|
||||
rt_pci_write_config_u8(pdev, 0x41, 0xa1);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_ahci_ops pci_ahci_ops =
|
||||
{
|
||||
.host_init = pci_ahci_init,
|
||||
};
|
||||
|
||||
static rt_err_t pci_ahci_intel_init(struct rt_ahci_host *host)
|
||||
{
|
||||
rt_uint16_t val;
|
||||
struct rt_pci_device *pdev;
|
||||
|
||||
pdev = rt_container_of(host->parent.dev, struct rt_pci_device, parent);
|
||||
|
||||
rt_pci_read_config_u16(pdev, 0x92, &val);
|
||||
rt_pci_write_config_u16(pdev, 0x92, val & ~0xf);
|
||||
|
||||
rt_thread_mdelay(10);
|
||||
rt_pci_write_config_u16(pdev, 0x92, val | 0xf);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_ahci_ops pci_ahci_intel_ops =
|
||||
{
|
||||
.host_init = pci_ahci_intel_init,
|
||||
};
|
||||
|
||||
static rt_err_t pci_ahci_probe(struct rt_pci_device *pdev)
|
||||
{
|
||||
rt_err_t err;
|
||||
int bar_idx;
|
||||
struct rt_ahci_host *ahci;
|
||||
struct pci_ahci_host *pci_ahci = rt_calloc(1, sizeof(*pci_ahci));
|
||||
const struct pci_ahci_quirk *quirk = pdev->id->data;
|
||||
|
||||
if (!pci_ahci)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
pci_ahci->quirk = quirk;
|
||||
ahci = &pci_ahci->parent;
|
||||
ahci->parent.dev = &pdev->parent;
|
||||
|
||||
bar_idx = quirk && quirk->bar_offset ? quirk->bar_idx : AHCI_REG_BAR;
|
||||
|
||||
ahci->regs = rt_pci_iomap(pdev, bar_idx);
|
||||
|
||||
if (!ahci->regs)
|
||||
{
|
||||
err = -RT_EIO;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
ahci->ops = quirk && quirk->ops ? quirk->ops : &pci_ahci_ops;
|
||||
|
||||
if (rt_pci_msi_enable(pdev) > 0)
|
||||
{
|
||||
pci_ahci->is_msi = RT_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_pci_irq_unmask(pdev);
|
||||
}
|
||||
ahci->irq = pdev->irq;
|
||||
|
||||
rt_pci_set_master(pdev);
|
||||
|
||||
if ((err = rt_ahci_host_register(ahci)))
|
||||
{
|
||||
goto _disable;
|
||||
}
|
||||
|
||||
pdev->parent.user_data = pci_ahci;
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_disable:
|
||||
if (pci_ahci->is_msi)
|
||||
{
|
||||
rt_pci_msix_disable(pdev);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_pci_irq_mask(pdev);
|
||||
}
|
||||
rt_pci_clear_master(pdev);
|
||||
rt_iounmap(ahci->regs);
|
||||
|
||||
_fail:
|
||||
rt_free(pci_ahci);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static rt_err_t pci_ahci_remove(struct rt_pci_device *pdev)
|
||||
{
|
||||
struct rt_ahci_host *ahci;
|
||||
struct pci_ahci_host *pci_ahci = pdev->parent.user_data;
|
||||
|
||||
ahci = &pci_ahci->parent;
|
||||
|
||||
rt_ahci_host_unregister(ahci);
|
||||
|
||||
if (pci_ahci->is_msi)
|
||||
{
|
||||
rt_pci_msi_disable(pdev);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INTx is shared, don't mask all */
|
||||
rt_hw_interrupt_umask(pdev->irq);
|
||||
rt_pci_irq_mask(pdev);
|
||||
}
|
||||
|
||||
rt_pci_clear_master(pdev);
|
||||
|
||||
rt_iounmap(ahci->regs);
|
||||
rt_free(pci_ahci);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t pci_ahci_shutdown(struct rt_pci_device *pdev)
|
||||
{
|
||||
return pci_ahci_remove(pdev);
|
||||
}
|
||||
|
||||
static struct pci_ahci_quirk intel_quirk =
|
||||
{
|
||||
.ops = &pci_ahci_intel_ops,
|
||||
};
|
||||
|
||||
static struct pci_ahci_quirk cavium_sata_quirk =
|
||||
{
|
||||
.bar_idx = 0,
|
||||
.bar_offset = RT_TRUE,
|
||||
};
|
||||
|
||||
static const struct rt_pci_device_id pci_ahci_ids[] =
|
||||
{
|
||||
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_INTEL, 0x2922), .data = &intel_quirk },
|
||||
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_ASMEDIA, 0x0611) },
|
||||
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_MARVELL, 0x6121) },
|
||||
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_MARVELL, 0x6145) },
|
||||
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_CAVIUM, 0xa01c), .data = &cavium_sata_quirk },
|
||||
{ RT_PCI_DEVICE_CLASS(PCIS_STORAGE_SATA_AHCI, ~0) },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_pci_driver pci_ahci_driver =
|
||||
{
|
||||
.name = "ahci-pci",
|
||||
|
||||
.ids = pci_ahci_ids,
|
||||
.probe = pci_ahci_probe,
|
||||
.remove = pci_ahci_remove,
|
||||
.shutdown = pci_ahci_shutdown,
|
||||
};
|
||||
RT_PCI_DRIVER_EXPORT(pci_ahci_driver);
|
896
rt-thread/components/drivers/ata/ahci.c
Normal file
896
rt-thread/components/drivers/ata/ahci.c
Normal file
@ -0,0 +1,896 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "rtdm.ahci"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define HWREG32_FLUSH(base, value) \
|
||||
do { \
|
||||
rt_uint32_t __value = value; \
|
||||
HWREG32(base) = __value; \
|
||||
__value = HWREG32(base); \
|
||||
} while (0)
|
||||
|
||||
static void ahci_fill_cmd_slot(struct rt_ahci_port *port, rt_uint32_t opts)
|
||||
{
|
||||
rt_ubase_t dma_addr = port->cmd_tbl_dma;
|
||||
struct rt_ahci_cmd_hdr *cmd_slot = port->cmd_slot;
|
||||
|
||||
cmd_slot->opts = rt_cpu_to_le32(opts);
|
||||
cmd_slot->status = 0;
|
||||
cmd_slot->tbl_addr_lo = rt_cpu_to_le32(rt_lower_32_bits(dma_addr));
|
||||
cmd_slot->tbl_addr_hi = rt_cpu_to_le32(rt_upper_32_bits(dma_addr));
|
||||
}
|
||||
|
||||
static int ahci_fill_sg(struct rt_ahci_host *host, int id,
|
||||
void *buffer, rt_size_t buffer_size)
|
||||
{
|
||||
int sg_count;
|
||||
rt_ubase_t dma_addr;
|
||||
struct rt_ahci_port *port = &host->ports[id];
|
||||
struct rt_ahci_sg *ahci_sg = port->cmd_tbl_sg;
|
||||
|
||||
sg_count = ((buffer_size - 1) / RT_ACHI_PRDT_BYTES_MAX) + 1;
|
||||
|
||||
if (sg_count > RT_AHCI_MAX_SG)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
dma_addr = (rt_ubase_t)rt_kmem_v2p(buffer);
|
||||
|
||||
for (int i = 0; i < sg_count; ++i, ++ahci_sg)
|
||||
{
|
||||
ahci_sg->addr_lo = rt_cpu_to_le32(rt_lower_32_bits(dma_addr));
|
||||
ahci_sg->addr_hi = rt_cpu_to_le32(rt_upper_32_bits(dma_addr));
|
||||
|
||||
if (ahci_sg->addr_hi && !(host->cap & RT_AHCI_CAP_64))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ahci_sg->flags_size = rt_cpu_to_le32(0x3fffff &
|
||||
(rt_min_t(rt_uint32_t, buffer_size, RT_ACHI_PRDT_BYTES_MAX) - 1));
|
||||
|
||||
dma_addr += RT_ACHI_PRDT_BYTES_MAX;
|
||||
buffer_size -= RT_ACHI_PRDT_BYTES_MAX;
|
||||
}
|
||||
|
||||
return sg_count;
|
||||
}
|
||||
|
||||
static rt_err_t ahci_request_io(struct rt_ahci_host *host, int id,
|
||||
void *fis, rt_size_t fis_size,
|
||||
void *buffer, rt_size_t buffer_size, rt_bool_t is_read)
|
||||
{
|
||||
int sg_count;
|
||||
rt_err_t err;
|
||||
struct rt_ahci_port *port = &host->ports[id];
|
||||
|
||||
if ((HWREG32(port->regs + RT_AHCI_PORT_SSTS) & 0xf) != RT_AHCI_PORT_SSTS_DET_PHYRDY)
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
if ((sg_count = ahci_fill_sg(host, id, buffer, buffer_size)) <= 0)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
rt_memcpy(port->cmd_tbl, fis, fis_size);
|
||||
ahci_fill_cmd_slot(port, (fis_size >> 2) | (sg_count << 16) | (!is_read << 6));
|
||||
|
||||
if (!is_read)
|
||||
{
|
||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, buffer, buffer_size);
|
||||
}
|
||||
|
||||
HWREG32_FLUSH(port->regs + RT_AHCI_PORT_CI, 1);
|
||||
|
||||
err = rt_completion_wait(&port->done, rt_tick_from_millisecond(10000));
|
||||
|
||||
if (!err && is_read)
|
||||
{
|
||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, buffer, buffer_size);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static rt_err_t ahci_scsi_cmd_rw(struct rt_ahci_host *host, int id,
|
||||
rt_off_t lba, void *buffer, rt_ssize_t size, rt_bool_t is_read)
|
||||
{
|
||||
rt_err_t err;
|
||||
rt_uint8_t fis[20];
|
||||
struct rt_ahci_port *port = &host->ports[id];
|
||||
|
||||
rt_memset(fis, 0, sizeof(fis));
|
||||
fis[0] = RT_AHCI_FIS_TYPE_REG_H2D;
|
||||
fis[1] = 1 << 7; /* Command */
|
||||
fis[2] = is_read ? RT_AHCI_ATA_CMD_READ_EXT : RT_AHCI_ATA_CMD_WRITE_EXT;
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
rt_size_t t_size, t_lba;
|
||||
|
||||
t_lba = rt_min_t(rt_size_t, host->max_blocks, size);
|
||||
t_size = port->block_size * t_lba;
|
||||
|
||||
fis[3] = 0xe0; /* Features */
|
||||
fis[4] = (lba >> 0) & 0xff; /* LBA low register */
|
||||
fis[5] = (lba >> 8) & 0xff; /* LBA mid register */
|
||||
fis[6] = (lba >> 16) & 0xff; /* LBA high register */
|
||||
fis[7] = 1 << 6; /* Device */
|
||||
fis[8] = ((lba >> 24) & 0xff); /* LBA register, 31:24 */
|
||||
fis[9] = ((lba >> 32) & 0xff); /* LBA register, 39:32 */
|
||||
fis[10] = ((lba >> 40) & 0xff); /* LBA register, 47:40 */
|
||||
fis[12] = (t_lba >> 0) & 0xff; /* Count register, 7:0 */
|
||||
fis[13] = (t_lba >> 8) & 0xff; /* Count register, 15:8 */
|
||||
|
||||
if ((err = ahci_request_io(host, id, fis, sizeof(fis), buffer, t_size, is_read)))
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
size -= t_lba;
|
||||
lba += t_lba;
|
||||
buffer += t_size;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t ahci_scsi_synchronize_cache(struct rt_ahci_host *host, int id,
|
||||
rt_off_t lba, rt_size_t size)
|
||||
{
|
||||
rt_uint8_t fis[20];
|
||||
rt_uint16_t *ataid;
|
||||
struct rt_ahci_port *port = &host->ports[id];
|
||||
|
||||
ataid = port->ataid;
|
||||
|
||||
if (!rt_ahci_ata_id_wcache_enabled(ataid) &&
|
||||
!rt_ahci_ata_id_has_flush(ataid) &&
|
||||
!rt_ahci_ata_id_has_flush_ext(ataid))
|
||||
{
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
rt_memset(fis, 0, sizeof(fis));
|
||||
fis[0] = RT_AHCI_FIS_TYPE_REG_H2D;
|
||||
fis[1] = 1 << 7; /* Command */
|
||||
|
||||
if (rt_ahci_ata_id_has_flush_ext(ataid))
|
||||
{
|
||||
fis[2] = RT_AHCI_ATA_CMD_FLUSH_EXT;
|
||||
}
|
||||
else
|
||||
{
|
||||
fis[2] = RT_AHCI_ATA_CMD_FLUSH;
|
||||
}
|
||||
|
||||
rt_memcpy(port->cmd_tbl, fis, 20);
|
||||
ahci_fill_cmd_slot(port, 5);
|
||||
|
||||
HWREG32_FLUSH(port->regs + RT_AHCI_PORT_CI, 1);
|
||||
|
||||
return rt_completion_wait(&port->done, rt_tick_from_millisecond(5000));
|
||||
}
|
||||
|
||||
static rt_err_t ahci_scsi_cmd_write_same(struct rt_ahci_host *host, int id,
|
||||
rt_off_t lba, rt_size_t size)
|
||||
{
|
||||
rt_uint8_t fis[20];
|
||||
struct rt_ahci_port *port = &host->ports[id];
|
||||
|
||||
rt_memset(fis, 0, sizeof(fis));
|
||||
fis[0] = RT_AHCI_FIS_TYPE_REG_H2D;
|
||||
fis[1] = 1 << 7; /* Command */
|
||||
fis[2] = RT_AHCI_ATA_CMD_DSM;
|
||||
fis[3] = RT_AHCI_ATA_DSM_TRIM; /* Features */
|
||||
fis[4] = (lba >> 0) & 0xff; /* LBA low register */
|
||||
fis[5] = (lba >> 8) & 0xff; /* LBA mid register */
|
||||
fis[6] = (lba >> 16) & 0xff; /* LBA high register */
|
||||
fis[7] = 1 << 6; /* Device */
|
||||
fis[8] = ((lba >> 24) & 0xff); /* LBA register, 31:24 */
|
||||
fis[9] = ((lba >> 32) & 0xff); /* LBA register, 39:32 */
|
||||
fis[10] = ((lba >> 40) & 0xff); /* LBA register, 47:40 */
|
||||
fis[12] = (size >> 0) & 0xff; /* Count register, 7:0 */
|
||||
fis[13] = (size >> 8) & 0xff; /* Count register, 15:8 */
|
||||
|
||||
HWREG32_FLUSH(port->regs + RT_AHCI_PORT_CI, 1);
|
||||
|
||||
return rt_completion_wait(&port->done, rt_tick_from_millisecond(5000));
|
||||
}
|
||||
|
||||
static rt_err_t ahci_scsi_cmd_read_capacity(struct rt_ahci_host *host, int id,
|
||||
rt_size_t *out_last_block, rt_size_t *out_block_size)
|
||||
{
|
||||
struct rt_ahci_port *port = &host->ports[id];
|
||||
|
||||
if (!port->ataid)
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
*out_last_block = rt_ahci_ata_id_n_sectors(port->ataid) - 1;
|
||||
*out_block_size = port->block_size;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t ahci_scsi_cmd_test_unit_ready(struct rt_ahci_host *host, int id)
|
||||
{
|
||||
struct rt_ahci_port *port = &host->ports[id];
|
||||
|
||||
return port->ataid ? RT_EOK : -RT_EIO;
|
||||
}
|
||||
|
||||
static rt_err_t ahci_scsi_cmd_inquiry(struct rt_ahci_host *host, int id,
|
||||
char *prodid, rt_size_t prodid_len, char *prodrev, rt_size_t prodrev_len)
|
||||
{
|
||||
rt_err_t err;
|
||||
rt_uint8_t fis[20];
|
||||
rt_uint16_t *ataid;
|
||||
struct rt_ahci_port *port = &host->ports[id];
|
||||
|
||||
if (!port->link)
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
if (!port->ataid && !(port->ataid = rt_malloc(RT_AHCI_ATA_ID_WORDS * 2)))
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
ataid = port->ataid;
|
||||
|
||||
rt_memset(fis, 0, sizeof(fis));
|
||||
fis[0] = RT_AHCI_FIS_TYPE_REG_H2D;
|
||||
fis[1] = 1 << 7; /* Command */
|
||||
fis[2] = RT_AHCI_ATA_CMD_ID_ATA;
|
||||
|
||||
if ((err = ahci_request_io(host, id, fis, sizeof(fis),
|
||||
ataid, RT_AHCI_ATA_ID_WORDS * 2, RT_TRUE)))
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
for (int i = 0; i < RT_AHCI_ATA_ID_WORDS; ++i)
|
||||
{
|
||||
ataid[i] = rt_le16_to_cpu(ataid[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < prodid_len / 2; ++i)
|
||||
{
|
||||
rt_uint16_t src = ataid[RT_AHCI_ATA_ID_PROD + i];
|
||||
|
||||
prodid[i] = (src & 0x00ff) << 8 | (src & 0xff00) >> 8;
|
||||
}
|
||||
|
||||
for (int i = 0; i < prodrev_len / 2; ++i)
|
||||
{
|
||||
rt_uint16_t src = ataid[RT_AHCI_ATA_ID_FW_REV + i];
|
||||
|
||||
prodrev[i] = (src & 0x00ff) << 8 | (src & 0xff00) >> 8;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static rt_err_t ahci_scsi_transfer(struct rt_scsi_device *sdev,
|
||||
struct rt_scsi_cmd *cmd)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_ahci_host *host;
|
||||
|
||||
host = rt_container_of(sdev->host, struct rt_ahci_host, parent);
|
||||
|
||||
switch (cmd->op.unknow.opcode)
|
||||
{
|
||||
case RT_SCSI_CMD_REQUEST_SENSE:
|
||||
{
|
||||
struct rt_scsi_request_sense_data *request_sense = &cmd->data.request_sense;
|
||||
|
||||
request_sense->error_code = 0x72;
|
||||
|
||||
err = RT_EOK;
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_READ10:
|
||||
{
|
||||
struct rt_scsi_read10 *read10 = &cmd->op.read10;
|
||||
|
||||
err = ahci_scsi_cmd_rw(host, sdev->id,
|
||||
rt_be32_to_cpu(read10->lba),
|
||||
cmd->data.ptr,
|
||||
rt_be16_to_cpu(read10->size),
|
||||
RT_TRUE);
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_READ16:
|
||||
{
|
||||
struct rt_scsi_read16 *read16 = &cmd->op.read16;
|
||||
|
||||
err = ahci_scsi_cmd_rw(host, sdev->id,
|
||||
rt_be64_to_cpu(read16->lba),
|
||||
cmd->data.ptr,
|
||||
rt_be32_to_cpu(read16->size),
|
||||
RT_TRUE);
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_READ12:
|
||||
{
|
||||
struct rt_scsi_read12 *read12 = &cmd->op.read12;
|
||||
|
||||
err = ahci_scsi_cmd_rw(host, sdev->id,
|
||||
rt_be32_to_cpu(read12->lba),
|
||||
cmd->data.ptr,
|
||||
rt_be32_to_cpu(read12->size),
|
||||
RT_TRUE);
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_WRITE10:
|
||||
{
|
||||
struct rt_scsi_write10 *write10 = &cmd->op.write10;
|
||||
|
||||
err = ahci_scsi_cmd_rw(host, sdev->id,
|
||||
rt_be32_to_cpu(write10->lba),
|
||||
cmd->data.ptr,
|
||||
rt_be16_to_cpu(write10->size),
|
||||
RT_FALSE);
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_WRITE16:
|
||||
{
|
||||
struct rt_scsi_write16 *write16 = &cmd->op.write16;
|
||||
|
||||
err = ahci_scsi_cmd_rw(host, sdev->id,
|
||||
rt_be64_to_cpu(write16->lba),
|
||||
cmd->data.ptr,
|
||||
rt_be32_to_cpu(write16->size),
|
||||
RT_FALSE);
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_WRITE12:
|
||||
{
|
||||
struct rt_scsi_write12 *write12 = &cmd->op.write12;
|
||||
|
||||
err = ahci_scsi_cmd_rw(host, sdev->id,
|
||||
rt_be32_to_cpu(write12->lba),
|
||||
cmd->data.ptr,
|
||||
rt_be32_to_cpu(write12->size),
|
||||
RT_FALSE);
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_SYNCHRONIZE_CACHE10:
|
||||
{
|
||||
struct rt_scsi_synchronize_cache10 *synchronize_cache10 = &cmd->op.synchronize_cache10;
|
||||
|
||||
err = ahci_scsi_synchronize_cache(host, sdev->id,
|
||||
rt_be32_to_cpu(synchronize_cache10->lba),
|
||||
rt_be16_to_cpu(synchronize_cache10->size));
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_SYNCHRONIZE_CACHE16:
|
||||
{
|
||||
struct rt_scsi_synchronize_cache16 *synchronize_cache16 = &cmd->op.synchronize_cache16;
|
||||
|
||||
err = ahci_scsi_synchronize_cache(host, sdev->id,
|
||||
rt_be64_to_cpu(synchronize_cache16->lba),
|
||||
rt_be32_to_cpu(synchronize_cache16->size));
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_WRITE_SAME10:
|
||||
{
|
||||
struct rt_scsi_write_same10 *write_same10 = &cmd->op.write_same10;
|
||||
|
||||
err = ahci_scsi_cmd_write_same(host, sdev->id,
|
||||
rt_be32_to_cpu(write_same10->lba), rt_be16_to_cpu(write_same10->size));
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_WRITE_SAME16:
|
||||
{
|
||||
struct rt_scsi_write_same16 *write_same16 = &cmd->op.write_same16;
|
||||
|
||||
err = ahci_scsi_cmd_write_same(host, sdev->id,
|
||||
rt_be64_to_cpu(write_same16->lba), rt_be32_to_cpu(write_same16->size));
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_READ_CAPACITY10:
|
||||
{
|
||||
rt_size_t last_block, block_size;
|
||||
struct rt_scsi_read_capacity10_data *data = &cmd->data.read_capacity10;
|
||||
|
||||
err = ahci_scsi_cmd_read_capacity(host, sdev->id, &last_block, &block_size);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
if (last_block > 0x100000000ULL)
|
||||
{
|
||||
last_block = 0xffffffff;
|
||||
}
|
||||
|
||||
data->last_block = rt_cpu_to_be32(last_block);
|
||||
data->block_size = rt_cpu_to_be32(block_size);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_READ_CAPACITY16:
|
||||
{
|
||||
rt_size_t last_block, block_size;
|
||||
struct rt_scsi_read_capacity16_data *data = &cmd->data.read_capacity16;
|
||||
|
||||
err = ahci_scsi_cmd_read_capacity(host, sdev->id, &last_block, &block_size);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
data->last_block = rt_cpu_to_be64(last_block);
|
||||
data->block_size = rt_cpu_to_be32(block_size);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_TEST_UNIT_READY:
|
||||
err = ahci_scsi_cmd_test_unit_ready(host, sdev->id);
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_INQUIRY:
|
||||
{
|
||||
struct rt_ahci_port *port = &host->ports[sdev->id];
|
||||
struct rt_scsi_inquiry_data *inquiry = &cmd->data.inquiry;
|
||||
|
||||
err = ahci_scsi_cmd_inquiry(host, sdev->id,
|
||||
inquiry->prodid, sizeof(inquiry->prodid),
|
||||
inquiry->prodrev, sizeof(inquiry->prodrev));
|
||||
|
||||
if (!err)
|
||||
{
|
||||
rt_memcpy(inquiry->vendor, "ATA ", sizeof(inquiry->vendor));
|
||||
|
||||
if (HWREG32(port->regs + RT_AHCI_PORT_SIG) != RT_AHCI_PORT_SIG_SATA_CDROM)
|
||||
{
|
||||
port->block_size = 512;
|
||||
inquiry->devtype = SCSI_DEVICE_TYPE_DIRECT;
|
||||
}
|
||||
else
|
||||
{
|
||||
port->block_size = 2048;
|
||||
inquiry->devtype = SCSI_DEVICE_TYPE_CDROM;
|
||||
}
|
||||
inquiry->rmb = 0;
|
||||
inquiry->length = 95 - 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_SCSI_CMD_MODE_SENSE:
|
||||
case RT_SCSI_CMD_MODE_SENSE10:
|
||||
case RT_SCSI_CMD_MODE_SELECT:
|
||||
case RT_SCSI_CMD_MODE_SELECT10:
|
||||
return -RT_ENOSYS;
|
||||
|
||||
default:
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct rt_scsi_ops ahci_scsi_ops =
|
||||
{
|
||||
.transfer = ahci_scsi_transfer,
|
||||
};
|
||||
|
||||
static void ahci_isr(int irqno, void *param)
|
||||
{
|
||||
int id;
|
||||
rt_uint32_t isr;
|
||||
rt_bitmap_t int_map;
|
||||
struct rt_ahci_port *port;
|
||||
struct rt_ahci_host *host = param;
|
||||
|
||||
int_map = HWREG32(host->regs + RT_AHCI_HBA_INTS);
|
||||
|
||||
rt_bitmap_for_each_set_bit(&int_map, id, host->ports_nr)
|
||||
{
|
||||
port = &host->ports[id];
|
||||
|
||||
isr = HWREG32(port->regs + RT_AHCI_PORT_INTS);
|
||||
|
||||
if (port->link)
|
||||
{
|
||||
if (host->ops->port_isr)
|
||||
{
|
||||
host->ops->port_isr(host, port, isr);
|
||||
}
|
||||
|
||||
rt_completion_done(&port->done);
|
||||
}
|
||||
|
||||
HWREG32(port->regs + RT_AHCI_PORT_INTS) = isr;
|
||||
}
|
||||
|
||||
HWREG32(host->regs + RT_AHCI_HBA_INTS) = int_map;
|
||||
}
|
||||
|
||||
rt_err_t rt_ahci_host_register(struct rt_ahci_host *host)
|
||||
{
|
||||
rt_err_t err;
|
||||
rt_uint32_t value;
|
||||
char dev_name[RT_NAME_MAX];
|
||||
struct rt_scsi_host *scsi;
|
||||
|
||||
if (!host || !host->parent.dev || !host->ops)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
host->max_blocks = host->max_blocks ? : 0x80;
|
||||
|
||||
/*
|
||||
* 1. Reset HBA.
|
||||
*/
|
||||
err = -RT_EIO;
|
||||
value = HWREG32(host->regs + RT_AHCI_HBA_GHC);
|
||||
|
||||
if (!(value & RT_AHCI_GHC_RESET))
|
||||
{
|
||||
HWREG32_FLUSH(host->regs + RT_AHCI_HBA_GHC, value | RT_AHCI_GHC_RESET);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
rt_thread_mdelay(200);
|
||||
|
||||
if (!(HWREG32(host->regs + RT_AHCI_HBA_GHC) & RT_AHCI_GHC_RESET))
|
||||
{
|
||||
err = RT_EOK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2. Enable AHCI and get the ports' information.
|
||||
*/
|
||||
HWREG32_FLUSH(host->regs + RT_AHCI_HBA_GHC, RT_AHCI_GHC_AHCI_EN);
|
||||
|
||||
host->cap = HWREG32(host->regs + RT_AHCI_HBA_CAP);
|
||||
host->cap &= RT_AHCI_CAP_SPM | RT_AHCI_CAP_SSS | RT_AHCI_CAP_SIS;
|
||||
HWREG32(host->regs + RT_AHCI_HBA_CAP) = host->cap;
|
||||
host->cap = HWREG32(host->regs + RT_AHCI_HBA_CAP);
|
||||
|
||||
HWREG32_FLUSH(host->regs + RT_AHCI_HBA_PI, 0xf);
|
||||
|
||||
if (host->ops->host_init && (err = host->ops->host_init(host)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
host->ports_nr = (host->cap & RT_AHCI_CAP_NP) + 1;
|
||||
host->ports_map = HWREG32(host->regs + RT_AHCI_HBA_PI);
|
||||
|
||||
/* Check implemented in firmware */
|
||||
rt_dm_dev_prop_read_u32(host->parent.dev, "ports-implemented", &host->ports_map);
|
||||
|
||||
for (int i = 0; i < host->ports_nr; ++i)
|
||||
{
|
||||
struct rt_ahci_port *port;
|
||||
|
||||
if (!(host->ports_map & RT_BIT(i)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
port = &host->ports[i];
|
||||
|
||||
/*
|
||||
* 3. Alloc port io memory.
|
||||
*/
|
||||
port->regs = host->regs + 0x100 + (i * 0x80);
|
||||
|
||||
/*
|
||||
* 4. Make port stop.
|
||||
*/
|
||||
value = HWREG32(port->regs + RT_AHCI_PORT_CMD);
|
||||
if (value & (RT_AHCI_PORT_CMD_LIST_ON | RT_AHCI_PORT_CMD_FIS_ON |
|
||||
RT_AHCI_PORT_CMD_FIS_RX | RT_AHCI_PORT_CMD_START))
|
||||
{
|
||||
value &= ~(RT_AHCI_PORT_CMD_LIST_ON | RT_AHCI_PORT_CMD_FIS_ON |
|
||||
RT_AHCI_PORT_CMD_FIS_RX | RT_AHCI_PORT_CMD_START);
|
||||
|
||||
HWREG32_FLUSH(port->regs + RT_AHCI_PORT_CMD, value);
|
||||
|
||||
rt_thread_mdelay(500);
|
||||
}
|
||||
|
||||
if (host->ops->port_init && (err = host->ops->port_init(host, port)))
|
||||
{
|
||||
LOG_E("Init port[%d] error = %s", rt_strerror(err));
|
||||
continue;
|
||||
}
|
||||
|
||||
value = HWREG32(port->regs + RT_AHCI_PORT_CMD);
|
||||
value |= RT_AHCI_PORT_CMD_SPIN_UP;
|
||||
HWREG32(port->regs + RT_AHCI_PORT_CMD) = value;
|
||||
|
||||
/*
|
||||
* 5. Enable port's SATA link.
|
||||
*/
|
||||
if (host->ops->port_link_up)
|
||||
{
|
||||
err = host->ops->port_link_up(host, port);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_ETIMEOUT;
|
||||
|
||||
for (int retry = 0; retry < 5; ++retry)
|
||||
{
|
||||
value = HWREG32(port->regs + RT_AHCI_PORT_SSTS);
|
||||
|
||||
if ((value & RT_AHCI_PORT_SSTS_DET_MASK) == RT_AHCI_PORT_SSTS_DET_PHYRDY)
|
||||
{
|
||||
err = RT_EOK;
|
||||
break;
|
||||
}
|
||||
|
||||
rt_thread_mdelay(2);
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
if (HWREG32(port->regs + RT_AHCI_PORT_SSTS) & RT_AHCI_PORT_SSTS_DET_MASK)
|
||||
{
|
||||
LOG_E("SATA[%d] link error = %s", i, rt_strerror(err));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_D("SATA[%d] not device", i);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Clear error status */
|
||||
if ((value = HWREG32(port->regs + RT_AHCI_PORT_SERR)))
|
||||
{
|
||||
HWREG32(port->regs + RT_AHCI_PORT_SERR) = value;
|
||||
}
|
||||
|
||||
for (int retry = 0; retry < 5; ++retry)
|
||||
{
|
||||
value = HWREG32(port->regs + RT_AHCI_PORT_TFD);
|
||||
if (!(value & (RT_AHCI_PORT_TFDATA_BSY | RT_AHCI_PORT_TFDATA_DRQ)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
rt_thread_mdelay(2);
|
||||
|
||||
value = HWREG32(port->regs + RT_AHCI_PORT_SSTS);
|
||||
if ((value & RT_AHCI_PORT_SSTS_DET_MASK) == RT_AHCI_PORT_SSTS_DET_PHYRDY)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
value = HWREG32(port->regs + RT_AHCI_PORT_SSTS) & RT_AHCI_PORT_SSTS_DET_MASK;
|
||||
if (value == RT_AHCI_PORT_SSTS_DET_COMINIT)
|
||||
{
|
||||
/* Retry to setup */
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Clear error */
|
||||
value = HWREG32(port->regs + RT_AHCI_PORT_SERR);
|
||||
HWREG32(port->regs + RT_AHCI_PORT_SERR) = value;
|
||||
|
||||
/* Clear pending IRQ */
|
||||
if ((value = HWREG32(port->regs + RT_AHCI_PORT_INTS)))
|
||||
{
|
||||
HWREG32(port->regs + RT_AHCI_PORT_INTS) = value;
|
||||
}
|
||||
|
||||
HWREG32(host->regs + RT_AHCI_HBA_INTS) = RT_BIT(i);
|
||||
|
||||
value = HWREG32(port->regs + RT_AHCI_PORT_SSTS);
|
||||
if ((value & RT_AHCI_PORT_SSTS_DET_MASK) == RT_AHCI_PORT_SSTS_DET_PHYRDY)
|
||||
{
|
||||
port->link = RT_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
HWREG32(host->regs + RT_AHCI_HBA_GHC) |= RT_AHCI_GHC_IRQ_EN;
|
||||
|
||||
for (int i = 0; i < host->ports_nr; ++i)
|
||||
{
|
||||
void *dma;
|
||||
rt_ubase_t dma_addr;
|
||||
rt_tick_t timeout;
|
||||
struct rt_ahci_port *port = &host->ports[i];
|
||||
|
||||
if (!port->link)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* 6. Alloc transport memory, Port x Command List and FIS Base Address.
|
||||
*/
|
||||
port->dma = rt_dma_alloc_coherent(host->parent.dev,
|
||||
RT_AHCI_DMA_SIZE, &port->dma_handle);
|
||||
|
||||
if (!port->dma)
|
||||
{
|
||||
LOG_E("No memory to setup port[%d]", i);
|
||||
break;
|
||||
}
|
||||
dma = port->dma;
|
||||
|
||||
rt_memset(dma, 0, RT_AHCI_DMA_SIZE);
|
||||
|
||||
port->cmd_slot = dma;
|
||||
dma += (RT_AHCI_CMD_SLOT_SIZE + 224);
|
||||
|
||||
port->rx_fis = dma;
|
||||
dma += RT_AHCI_RX_FIS_SIZE;
|
||||
|
||||
port->cmd_tbl = dma;
|
||||
port->cmd_tbl_dma = (rt_ubase_t)rt_kmem_v2p(dma);
|
||||
dma += RT_AHCI_CMD_TBL_HDR;
|
||||
|
||||
port->cmd_tbl_sg = dma;
|
||||
|
||||
dma_addr = (rt_ubase_t)rt_kmem_v2p(port->cmd_slot);
|
||||
HWREG32_FLUSH(port->regs + RT_AHCI_PORT_CLB, rt_lower_32_bits(dma_addr));
|
||||
HWREG32_FLUSH(port->regs + RT_AHCI_PORT_CLBU, rt_upper_32_bits(dma_addr));
|
||||
|
||||
dma_addr = (rt_ubase_t)rt_kmem_v2p(port->rx_fis);
|
||||
HWREG32_FLUSH(port->regs + RT_AHCI_PORT_FB, rt_lower_32_bits(dma_addr));
|
||||
HWREG32_FLUSH(port->regs + RT_AHCI_PORT_FBU, rt_upper_32_bits(dma_addr));
|
||||
|
||||
if (host->ops->port_dma_init && (err = host->ops->port_dma_init(host, port)))
|
||||
{
|
||||
LOG_E("Init port[%d] DMA error = %s", rt_strerror(err));
|
||||
}
|
||||
|
||||
HWREG32_FLUSH(port->regs + RT_AHCI_PORT_CMD, RT_AHCI_PORT_CMD_ACTIVE |
|
||||
RT_AHCI_PORT_CMD_FIS_RX | RT_AHCI_PORT_CMD_POWER_ON |
|
||||
RT_AHCI_PORT_CMD_SPIN_UP | RT_AHCI_PORT_CMD_START);
|
||||
|
||||
/* Wait spinup */
|
||||
err = -RT_ETIMEOUT;
|
||||
timeout = rt_tick_from_millisecond(20000);
|
||||
timeout += rt_tick_get();
|
||||
do {
|
||||
if (!(HWREG32(port->regs + RT_AHCI_PORT_TFD) & RT_AHCI_PORT_TFDATA_BSY))
|
||||
{
|
||||
err = RT_EOK;
|
||||
break;
|
||||
}
|
||||
|
||||
rt_hw_cpu_relax();
|
||||
} while (rt_tick_get() < timeout);
|
||||
|
||||
if (err)
|
||||
{
|
||||
rt_dma_free_coherent(host->parent.dev, RT_AHCI_DMA_SIZE, port->dma,
|
||||
port->dma_handle);
|
||||
port->dma = RT_NULL;
|
||||
|
||||
LOG_E("Start up port[%d] fail", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
port->int_enabled |= RT_AHCI_PORT_INTE_HBUS_ERR | RT_AHCI_PORT_INTE_IF_ERR |
|
||||
RT_AHCI_PORT_INTE_CONNECT | RT_AHCI_PORT_INTE_PHYRDY |
|
||||
RT_AHCI_PORT_INTE_UNK_FIS | RT_AHCI_PORT_INTE_BAD_PMP |
|
||||
RT_AHCI_PORT_INTE_TF_ERR | RT_AHCI_PORT_INTE_HBUS_DATA_ERR |
|
||||
RT_AHCI_PORT_INTE_SG_DONE | RT_AHCI_PORT_INTE_SDB_FIS |
|
||||
RT_AHCI_PORT_INTE_DMAS_FIS | RT_AHCI_PORT_INTE_PIOS_FIS |
|
||||
RT_AHCI_PORT_INTE_D2H_REG_FIS;
|
||||
|
||||
HWREG32(port->regs + RT_AHCI_PORT_INTE) = port->int_enabled;
|
||||
|
||||
rt_completion_init(&port->done);
|
||||
}
|
||||
|
||||
rt_snprintf(dev_name, sizeof(dev_name), "ahci-%s",
|
||||
rt_dm_dev_get_name(host->parent.dev));
|
||||
|
||||
rt_hw_interrupt_install(host->irq, ahci_isr, host, dev_name);
|
||||
rt_hw_interrupt_umask(host->irq);
|
||||
|
||||
scsi = &host->parent;
|
||||
scsi->max_lun = rt_max_t(rt_size_t, scsi->max_lun, 1);
|
||||
scsi->max_id = host->ports_nr;
|
||||
scsi->ops = &ahci_scsi_ops;
|
||||
|
||||
if ((err = rt_scsi_host_register(scsi)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
rt_hw_interrupt_mask(host->irq);
|
||||
rt_pic_detach_irq(host->irq, host);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_err_t rt_ahci_host_unregister(struct rt_ahci_host *host)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_scsi_host *scsi;
|
||||
|
||||
if (!host)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
scsi = &host->parent;
|
||||
|
||||
if ((err = rt_scsi_host_unregister(scsi)))
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_hw_interrupt_mask(host->irq);
|
||||
rt_pic_detach_irq(host->irq, host);
|
||||
|
||||
for (int i = 0; i < host->ports_nr; ++i)
|
||||
{
|
||||
struct rt_ahci_port *port = &host->ports[i];
|
||||
|
||||
if (port->ataid)
|
||||
{
|
||||
rt_free(port->ataid);
|
||||
}
|
||||
|
||||
HWREG32(port->regs) &= ~(RT_AHCI_PORT_CMD_ACTIVE | RT_AHCI_PORT_CMD_POWER_ON |
|
||||
RT_AHCI_PORT_CMD_SPIN_UP | RT_AHCI_PORT_CMD_START);
|
||||
|
||||
if (port->dma)
|
||||
{
|
||||
rt_dma_free_coherent(host->parent.dev, RT_AHCI_DMA_SIZE, port->dma,
|
||||
port->dma_handle);
|
||||
}
|
||||
}
|
||||
|
||||
HWREG32(host->regs + RT_AHCI_HBA_GHC) &= ~(RT_AHCI_GHC_AHCI_EN | RT_AHCI_GHC_IRQ_EN);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
@ -10,9 +10,9 @@
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdevice.h>
|
||||
#include "audio_pipe.h"
|
||||
#include "dev_audio_pipe.h"
|
||||
|
||||
static void _rt_pipe_resume_writer(struct rt_audio_pipe *pipe)
|
||||
static void _rt_audio_pipe_resume_writer(struct rt_audio_pipe *pipe)
|
||||
{
|
||||
if (!rt_list_isempty(&pipe->suspended_write_list))
|
||||
{
|
||||
@ -30,7 +30,7 @@ static void _rt_pipe_resume_writer(struct rt_audio_pipe *pipe)
|
||||
}
|
||||
}
|
||||
|
||||
static rt_ssize_t rt_pipe_read(rt_device_t dev,
|
||||
static rt_ssize_t rt_audio_pipe_read(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
@ -50,7 +50,7 @@ static rt_ssize_t rt_pipe_read(rt_device_t dev,
|
||||
|
||||
/* if the ringbuffer is empty, there won't be any writer waiting */
|
||||
if (read_nbytes)
|
||||
_rt_pipe_resume_writer(pipe);
|
||||
_rt_audio_pipe_resume_writer(pipe);
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
@ -78,7 +78,7 @@ static rt_ssize_t rt_pipe_read(rt_device_t dev,
|
||||
}
|
||||
else
|
||||
{
|
||||
_rt_pipe_resume_writer(pipe);
|
||||
_rt_audio_pipe_resume_writer(pipe);
|
||||
rt_hw_interrupt_enable(level);
|
||||
break;
|
||||
}
|
||||
@ -88,7 +88,7 @@ static rt_ssize_t rt_pipe_read(rt_device_t dev,
|
||||
return read_nbytes;
|
||||
}
|
||||
|
||||
static void _rt_pipe_resume_reader(struct rt_audio_pipe *pipe)
|
||||
static void _rt_audio_pipe_resume_reader(struct rt_audio_pipe *pipe)
|
||||
{
|
||||
if (pipe->parent.rx_indicate)
|
||||
pipe->parent.rx_indicate(&pipe->parent,
|
||||
@ -110,7 +110,7 @@ static void _rt_pipe_resume_reader(struct rt_audio_pipe *pipe)
|
||||
}
|
||||
}
|
||||
|
||||
static rt_ssize_t rt_pipe_write(rt_device_t dev,
|
||||
static rt_ssize_t rt_audio_pipe_write(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
@ -135,7 +135,7 @@ static rt_ssize_t rt_pipe_write(rt_device_t dev,
|
||||
write_nbytes = rt_ringbuffer_put(&(pipe->ringbuffer),
|
||||
(const rt_uint8_t *)buffer, size);
|
||||
|
||||
_rt_pipe_resume_reader(pipe);
|
||||
_rt_audio_pipe_resume_reader(pipe);
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
@ -164,7 +164,7 @@ static rt_ssize_t rt_pipe_write(rt_device_t dev,
|
||||
}
|
||||
else
|
||||
{
|
||||
_rt_pipe_resume_reader(pipe);
|
||||
_rt_audio_pipe_resume_reader(pipe);
|
||||
rt_hw_interrupt_enable(level);
|
||||
break;
|
||||
}
|
||||
@ -174,7 +174,7 @@ static rt_ssize_t rt_pipe_write(rt_device_t dev,
|
||||
return write_nbytes;
|
||||
}
|
||||
|
||||
static rt_err_t rt_pipe_control(rt_device_t dev, int cmd, void *args)
|
||||
static rt_err_t rt_audio_pipe_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
struct rt_audio_pipe *pipe;
|
||||
|
||||
@ -191,9 +191,9 @@ const static struct rt_device_ops audio_pipe_ops =
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
rt_pipe_read,
|
||||
rt_pipe_write,
|
||||
rt_pipe_control
|
||||
rt_audio_pipe_read,
|
||||
rt_audio_pipe_write,
|
||||
rt_audio_pipe_control
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -235,9 +235,9 @@ rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe,
|
||||
pipe->parent.init = RT_NULL;
|
||||
pipe->parent.open = RT_NULL;
|
||||
pipe->parent.close = RT_NULL;
|
||||
pipe->parent.read = rt_pipe_read;
|
||||
pipe->parent.write = rt_pipe_write;
|
||||
pipe->parent.control = rt_pipe_control;
|
||||
pipe->parent.read = rt_audio_pipe_read;
|
||||
pipe->parent.write = rt_audio_pipe_write;
|
||||
pipe->parent.control = rt_audio_pipe_control;
|
||||
#endif
|
||||
|
||||
return rt_device_register(&(pipe->parent), name, RT_DEVICE_FLAG_RDWR);
|
@ -6,8 +6,8 @@
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
#ifndef __AUDIO_PIPE_H__
|
||||
#define __AUDIO_PIPE_H__
|
||||
#ifndef __DEV_AUDIO_PIPE_H__
|
||||
#define __DEV_AUDIO_PIPE_H__
|
||||
|
||||
/**
|
||||
* Pipe Device
|
||||
@ -72,4 +72,4 @@ rt_err_t rt_audio_pipe_create(const char *name, rt_int32_t flag, rt_size_t size)
|
||||
void rt_audio_pipe_destroy(struct rt_audio_pipe *pipe);
|
||||
#endif /* RT_USING_HEAP */
|
||||
|
||||
#endif /* __AUDIO_PIPE_H__ */
|
||||
#endif /* __DEV_AUDIO_PIPE_H__ */
|
7
rt-thread/components/drivers/block/Kconfig
Normal file
7
rt-thread/components/drivers/block/Kconfig
Normal file
@ -0,0 +1,7 @@
|
||||
menuconfig RT_USING_BLK
|
||||
bool "Using Block device drivers"
|
||||
default n
|
||||
|
||||
if RT_USING_BLK
|
||||
rsource "partitions/Kconfig"
|
||||
endif
|
23
rt-thread/components/drivers/block/SConscript
Normal file
23
rt-thread/components/drivers/block/SConscript
Normal file
@ -0,0 +1,23 @@
|
||||
from building import *
|
||||
|
||||
group = []
|
||||
objs = []
|
||||
|
||||
if not GetDepend(['RT_USING_BLK']):
|
||||
Return('group')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
list = os.listdir(cwd)
|
||||
CPPPATH = [cwd + '/../include']
|
||||
|
||||
src = ['blk.c', 'blk_dev.c', 'blk_dfs.c', 'blk_partition.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
for d in list:
|
||||
path = os.path.join(cwd, d)
|
||||
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||
objs = objs + SConscript(os.path.join(d, 'SConscript'))
|
||||
objs = objs + group
|
||||
|
||||
Return('objs')
|
573
rt-thread/components/drivers/block/blk.c
Normal file
573
rt-thread/components/drivers/block/blk.c
Normal file
@ -0,0 +1,573 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#define DBG_TAG "rtdm.blk"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "blk_dev.h"
|
||||
#include "blk_dfs.h"
|
||||
|
||||
static void blk_remove_all(struct rt_blk_disk *disk)
|
||||
{
|
||||
struct rt_blk_device *blk, *blk_next;
|
||||
|
||||
/* Remove all partitions */
|
||||
rt_list_for_each_entry_safe(blk, blk_next, &disk->part_nodes, list)
|
||||
{
|
||||
disk_remove_blk_dev(blk, RT_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t blk_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
{
|
||||
struct rt_blk_disk *disk = to_blk_disk(dev);
|
||||
|
||||
if (disk->read_only && (oflag & RT_DEVICE_OFLAG_WRONLY))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t blk_close(rt_device_t dev)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_ssize_t blk_read(rt_device_t dev, rt_off_t sector,
|
||||
void *buffer, rt_size_t sector_count)
|
||||
{
|
||||
rt_ssize_t res;
|
||||
struct rt_blk_disk *disk = to_blk_disk(dev);
|
||||
|
||||
rt_sem_take(&disk->usr_lock, RT_WAITING_FOREVER);
|
||||
|
||||
res = disk->ops->read(disk, sector, buffer, sector_count);
|
||||
|
||||
rt_sem_release(&disk->usr_lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static rt_ssize_t blk_write(rt_device_t dev, rt_off_t sector,
|
||||
const void *buffer, rt_size_t sector_count)
|
||||
{
|
||||
rt_ssize_t res;
|
||||
struct rt_blk_disk *disk = to_blk_disk(dev);
|
||||
|
||||
if (!disk->read_only)
|
||||
{
|
||||
rt_sem_take(&disk->usr_lock, RT_WAITING_FOREVER);
|
||||
|
||||
res = disk->ops->write(disk, sector, buffer, sector_count);
|
||||
|
||||
rt_sem_release(&disk->usr_lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
static rt_ssize_t blk_parallel_read(rt_device_t dev, rt_off_t sector,
|
||||
void *buffer, rt_size_t sector_count)
|
||||
{
|
||||
struct rt_blk_disk *disk = to_blk_disk(dev);
|
||||
|
||||
return disk->ops->read(disk, sector, buffer, sector_count);
|
||||
}
|
||||
|
||||
static rt_ssize_t blk_parallel_write(rt_device_t dev, rt_off_t sector,
|
||||
const void *buffer, rt_size_t sector_count)
|
||||
{
|
||||
struct rt_blk_disk *disk = to_blk_disk(dev);
|
||||
|
||||
if (!disk->read_only)
|
||||
{
|
||||
return disk->ops->write(disk, sector, buffer, sector_count);
|
||||
}
|
||||
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
static rt_err_t blk_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_blk_disk *disk = to_blk_disk(dev);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case RT_DEVICE_CTRL_BLK_GETGEOME:
|
||||
if (args)
|
||||
{
|
||||
err = disk->ops->getgeome(disk, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_BLK_SYNC:
|
||||
if (disk->ops->sync)
|
||||
{
|
||||
rt_sem_take(&disk->usr_lock, RT_WAITING_FOREVER);
|
||||
|
||||
spin_lock(&disk->lock);
|
||||
|
||||
err = disk->ops->sync(disk);
|
||||
|
||||
spin_unlock(&disk->lock);
|
||||
|
||||
rt_sem_release(&disk->usr_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_ENOSYS;
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_BLK_ERASE:
|
||||
if (disk->ops->erase)
|
||||
{
|
||||
rt_sem_take(&disk->usr_lock, RT_WAITING_FOREVER);
|
||||
|
||||
spin_lock(&disk->lock);
|
||||
|
||||
if (disk->parent.ref_count != 1)
|
||||
{
|
||||
err = -RT_EBUSY;
|
||||
goto _unlock;
|
||||
}
|
||||
|
||||
blk_remove_all(disk);
|
||||
|
||||
err = disk->ops->erase(disk);
|
||||
|
||||
_unlock:
|
||||
spin_unlock(&disk->lock);
|
||||
|
||||
rt_sem_release(&disk->usr_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_ENOSYS;
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_BLK_AUTOREFRESH:
|
||||
if (disk->ops->autorefresh)
|
||||
{
|
||||
err = disk->ops->autorefresh(disk, !!args);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_ENOSYS;
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_BLK_PARTITION:
|
||||
err = -RT_EINVAL;
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_BLK_SSIZEGET:
|
||||
device_get_blk_ssize(dev, args);
|
||||
err = RT_EOK;
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_ALL_BLK_SSIZEGET:
|
||||
device_get_all_blk_ssize(dev, args);
|
||||
err = RT_EOK;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (disk->ops->control)
|
||||
{
|
||||
err = disk->ops->control(disk, RT_NULL, cmd, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_ENOSYS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops blk_ops =
|
||||
{
|
||||
.open = blk_open,
|
||||
.close = blk_close,
|
||||
.read = blk_read,
|
||||
.write = blk_write,
|
||||
.control = blk_control,
|
||||
};
|
||||
|
||||
const static struct rt_device_ops blk_parallel_ops =
|
||||
{
|
||||
.open = blk_open,
|
||||
.close = blk_close,
|
||||
.read = blk_parallel_read,
|
||||
.write = blk_parallel_write,
|
||||
.control = blk_control,
|
||||
};
|
||||
#endif /* RT_USING_DEVICE_OPS */
|
||||
|
||||
rt_err_t rt_hw_blk_disk_register(struct rt_blk_disk *disk)
|
||||
{
|
||||
rt_err_t err;
|
||||
#ifdef RT_USING_DM
|
||||
int device_id;
|
||||
#endif
|
||||
const char *disk_name;
|
||||
rt_uint16_t flags = RT_DEVICE_FLAG_RDONLY;
|
||||
|
||||
if (!disk || !disk->ops)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DM
|
||||
if (!disk->ida)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if RT_NAME_MAX > 0
|
||||
if (disk->parent.parent.name[0] == '\0')
|
||||
#else
|
||||
if (disk->parent.parent.name)
|
||||
#endif
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DM
|
||||
if ((device_id = rt_dm_ida_alloc(disk->ida)) < 0)
|
||||
{
|
||||
return -RT_EFULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
disk->__magic = RT_BLK_DISK_MAGIC;
|
||||
disk_name = to_disk_name(disk);
|
||||
|
||||
err = rt_sem_init(&disk->usr_lock, disk_name, 1, RT_IPC_FLAG_PRIO);
|
||||
|
||||
if (err)
|
||||
{
|
||||
#ifdef RT_USING_DM
|
||||
rt_dm_ida_free(disk->ida, device_id);
|
||||
#endif
|
||||
|
||||
LOG_E("%s: Init user mutex error = %s", rt_strerror(err));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_list_init(&disk->part_nodes);
|
||||
rt_spin_lock_init(&disk->lock);
|
||||
|
||||
disk->parent.type = RT_Device_Class_Block;
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
if (disk->parallel_io)
|
||||
{
|
||||
disk->parent.ops = &blk_parallel_ops;
|
||||
}
|
||||
else
|
||||
{
|
||||
disk->parent.ops = &blk_ops;
|
||||
}
|
||||
#else
|
||||
disk->parent.open = blk_open;
|
||||
disk->parent.close = blk_close;
|
||||
|
||||
if (disk->parallel_io)
|
||||
{
|
||||
disk->parent.read = blk_parallel_read;
|
||||
disk->parent.write = blk_parallel_write;
|
||||
}
|
||||
else
|
||||
{
|
||||
disk->parent.read = blk_read;
|
||||
disk->parent.write = blk_write;
|
||||
}
|
||||
disk->parent.control = blk_control;
|
||||
#endif
|
||||
|
||||
if (!disk->ops->write)
|
||||
{
|
||||
disk->read_only = RT_TRUE;
|
||||
}
|
||||
|
||||
if (!disk->read_only)
|
||||
{
|
||||
flags |= RT_DEVICE_FLAG_WRONLY;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DM
|
||||
disk->parent.master_id = disk->ida->master_id;
|
||||
disk->parent.device_id = device_id;
|
||||
#endif
|
||||
device_set_blk_fops(&disk->parent);
|
||||
|
||||
err = rt_device_register(&disk->parent, disk_name, flags);
|
||||
|
||||
if (err)
|
||||
{
|
||||
rt_sem_detach(&disk->usr_lock);
|
||||
}
|
||||
|
||||
/* Ignore partition scanning errors */
|
||||
rt_blk_disk_probe_partition(disk);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_err_t rt_hw_blk_disk_unregister(struct rt_blk_disk *disk)
|
||||
{
|
||||
rt_err_t err;
|
||||
|
||||
if (!disk)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
spin_lock(&disk->lock);
|
||||
|
||||
if (disk->parent.ref_count > 0)
|
||||
{
|
||||
err = -RT_EBUSY;
|
||||
goto _unlock;
|
||||
}
|
||||
|
||||
/* Flush all data */
|
||||
if (disk->ops->sync)
|
||||
{
|
||||
err = disk->ops->sync(disk);
|
||||
|
||||
if (err)
|
||||
{
|
||||
LOG_E("%s: Sync error = %s", to_disk_name(disk), rt_strerror(err));
|
||||
|
||||
goto _unlock;
|
||||
}
|
||||
}
|
||||
|
||||
rt_sem_detach(&disk->usr_lock);
|
||||
|
||||
blk_remove_all(disk);
|
||||
|
||||
#ifdef RT_USING_DM
|
||||
rt_dm_ida_free(disk->ida, disk->parent.device_id);
|
||||
#endif
|
||||
|
||||
err = rt_device_unregister(&disk->parent);
|
||||
|
||||
_unlock:
|
||||
spin_unlock(&disk->lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_ssize_t rt_blk_disk_get_capacity(struct rt_blk_disk *disk)
|
||||
{
|
||||
rt_ssize_t res;
|
||||
struct rt_device_blk_geometry geometry;
|
||||
|
||||
if (!disk)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
res = disk->ops->getgeome(disk, &geometry);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
return geometry.sector_count;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
rt_ssize_t rt_blk_disk_get_logical_block_size(struct rt_blk_disk *disk)
|
||||
{
|
||||
rt_ssize_t res;
|
||||
struct rt_device_blk_geometry geometry;
|
||||
|
||||
if (!disk)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
res = disk->ops->getgeome(disk, &geometry);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
return geometry.bytes_per_sector;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DFS_MNTTABLE
|
||||
static int blk_dfs_mnt_table(void)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
struct rt_object *obj;
|
||||
struct rt_device *dev;
|
||||
struct rt_blk_disk *disk;
|
||||
struct rt_blk_device *blk_dev;
|
||||
struct rt_object_information *info = rt_object_get_information(RT_Object_Class_Device);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
rt_list_for_each_entry(obj, &info->object_list, list)
|
||||
{
|
||||
dev = rt_container_of(obj, struct rt_device, parent);
|
||||
|
||||
if (dev->type != RT_Device_Class_Block)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
disk = to_blk_disk(dev);
|
||||
|
||||
if (disk->__magic != RT_BLK_DISK_MAGIC)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (disk->max_partitions == RT_BLK_PARTITION_NONE)
|
||||
{
|
||||
dfs_mount_device(&disk->parent);
|
||||
continue;
|
||||
}
|
||||
|
||||
rt_list_for_each_entry(blk_dev, &disk->part_nodes, list)
|
||||
{
|
||||
dfs_mount_device(&blk_dev->parent);
|
||||
}
|
||||
}
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(blk_dfs_mnt_table);
|
||||
#endif /* RT_USING_DFS_MNTTABLE */
|
||||
|
||||
#if defined(RT_USING_CONSOLE) && defined(RT_USING_MSH)
|
||||
const char *convert_size(struct rt_device_blk_geometry *geome,
|
||||
rt_size_t sector_count, rt_size_t *out_cap, rt_size_t *out_minor)
|
||||
{
|
||||
rt_size_t cap, minor = 0;
|
||||
int size_index = 0;
|
||||
const char *size_name[] = { "B", "K", "M", "G", "T", "P", "E" };
|
||||
|
||||
cap = geome->bytes_per_sector * sector_count;
|
||||
|
||||
for (size_index = 0; size_index < RT_ARRAY_SIZE(size_name) - 1; ++size_index)
|
||||
{
|
||||
if (cap < 1024)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Only one decimal point */
|
||||
minor = (cap % 1024) * 10 / 1024;
|
||||
cap = cap / 1024;
|
||||
}
|
||||
|
||||
*out_cap = cap;
|
||||
*out_minor = minor;
|
||||
|
||||
return size_name[size_index];
|
||||
}
|
||||
|
||||
static int list_blk(int argc, char**argv)
|
||||
{
|
||||
rt_ubase_t level;
|
||||
rt_size_t cap, minor;
|
||||
const char *size_name;
|
||||
struct rt_object *obj;
|
||||
struct rt_device *dev;
|
||||
struct rt_blk_disk *disk;
|
||||
struct rt_blk_device *blk_dev;
|
||||
struct rt_device_blk_geometry geome;
|
||||
struct rt_object_information *info = rt_object_get_information(RT_Object_Class_Device);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
rt_kprintf("%-*.s MAJ:MIN RM SIZE\tRO TYPE MOUNTPOINT\n", RT_NAME_MAX, "NAME");
|
||||
|
||||
rt_list_for_each_entry(obj, &info->object_list, list)
|
||||
{
|
||||
dev = rt_container_of(obj, struct rt_device, parent);
|
||||
|
||||
if (dev->type != RT_Device_Class_Block)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
disk = to_blk_disk(dev);
|
||||
|
||||
if (disk->__magic != RT_BLK_DISK_MAGIC)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (disk->ops->getgeome(disk, &geome))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
size_name = convert_size(&geome, geome.sector_count, &cap, &minor);
|
||||
|
||||
rt_kprintf("%-*.s %3u.%-3u %u %u.%u%s\t%u disk %s\n",
|
||||
RT_NAME_MAX, to_disk_name(disk),
|
||||
#ifdef RT_USING_DM
|
||||
disk->parent.master_id, disk->parent.device_id,
|
||||
#else
|
||||
0, 0,
|
||||
#endif
|
||||
disk->removable, cap, minor, size_name, disk->read_only,
|
||||
disk->max_partitions != RT_BLK_PARTITION_NONE ? "\b" :
|
||||
(dfs_filesystem_get_mounted_path(&disk->parent) ? : "\b"));
|
||||
|
||||
rt_list_for_each_entry(blk_dev, &disk->part_nodes, list)
|
||||
{
|
||||
size_name = convert_size(&geome, blk_dev->sector_count, &cap, &minor);
|
||||
|
||||
rt_kprintf("%c--%-*.s %3u.%-3u %u %u.%u%s\t%u part %s\n",
|
||||
blk_dev->list.next != &disk->part_nodes ? '|' : '`',
|
||||
RT_NAME_MAX - 3, to_blk_name(blk_dev),
|
||||
#ifdef RT_USING_DM
|
||||
blk_dev->parent.master_id, blk_dev->parent.device_id,
|
||||
#else
|
||||
0, 0,
|
||||
#endif
|
||||
disk->removable, cap, minor, size_name, disk->read_only,
|
||||
dfs_filesystem_get_mounted_path(&blk_dev->parent) ? : "");
|
||||
}
|
||||
}
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT(list_blk, dump all of blks information);
|
||||
#endif /* RT_USING_CONSOLE && RT_USING_MSH */
|
297
rt-thread/components/drivers/block/blk_dev.c
Normal file
297
rt-thread/components/drivers/block/blk_dev.c
Normal file
@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include "blk_dev.h"
|
||||
#include "blk_dfs.h"
|
||||
|
||||
#define DBG_TAG "blk.dm"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#ifdef RT_USING_DFS
|
||||
#include <dfs_fs.h>
|
||||
#endif
|
||||
|
||||
static rt_err_t blk_dev_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
{
|
||||
struct rt_blk_device *blk = to_blk(dev);
|
||||
|
||||
return rt_device_open(&blk->disk->parent, oflag);
|
||||
}
|
||||
|
||||
static rt_err_t blk_dev_close(rt_device_t dev)
|
||||
{
|
||||
struct rt_blk_device *blk = to_blk(dev);
|
||||
|
||||
return rt_device_close(&blk->disk->parent);
|
||||
}
|
||||
|
||||
static rt_ssize_t blk_dev_read(rt_device_t dev, rt_off_t sector,
|
||||
void *buffer, rt_size_t sector_count)
|
||||
{
|
||||
struct rt_blk_device *blk = to_blk(dev);
|
||||
|
||||
if (sector <= blk->sector_start + blk->sector_count &&
|
||||
sector_count <= blk->sector_count)
|
||||
{
|
||||
return rt_device_read(&blk->disk->parent,
|
||||
blk->sector_start + sector, buffer, sector_count);
|
||||
}
|
||||
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
static rt_ssize_t blk_dev_write(rt_device_t dev, rt_off_t sector,
|
||||
const void *buffer, rt_size_t sector_count)
|
||||
{
|
||||
struct rt_blk_device *blk = to_blk(dev);
|
||||
|
||||
if (sector <= blk->sector_start + blk->sector_count &&
|
||||
sector_count <= blk->sector_count)
|
||||
{
|
||||
return rt_device_write(&blk->disk->parent,
|
||||
blk->sector_start + sector, buffer, sector_count);
|
||||
}
|
||||
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
static rt_err_t blk_dev_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
rt_err_t err = -RT_EINVAL;
|
||||
struct rt_blk_device *blk = to_blk(dev);
|
||||
struct rt_blk_disk *disk = blk->disk;
|
||||
struct rt_device_blk_geometry disk_geometry, *geometry;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case RT_DEVICE_CTRL_BLK_GETGEOME:
|
||||
if ((geometry = args))
|
||||
{
|
||||
if (!(err = disk->ops->getgeome(disk, &disk_geometry)))
|
||||
{
|
||||
geometry->bytes_per_sector = disk_geometry.bytes_per_sector;
|
||||
geometry->block_size = disk_geometry.block_size;
|
||||
geometry->sector_count = blk->sector_count;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_BLK_SYNC:
|
||||
rt_device_control(&disk->parent, cmd, args);
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_BLK_ERASE:
|
||||
case RT_DEVICE_CTRL_BLK_AUTOREFRESH:
|
||||
if (disk->partitions <= 1)
|
||||
{
|
||||
rt_device_control(&disk->parent, cmd, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_BLK_PARTITION:
|
||||
if (args)
|
||||
{
|
||||
rt_memcpy(args, &blk->partition, sizeof(blk->partition));
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_BLK_SSIZEGET:
|
||||
device_get_blk_ssize(dev, args);
|
||||
err = RT_EOK;
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_ALL_BLK_SSIZEGET:
|
||||
device_get_all_blk_ssize(dev, args);
|
||||
err = RT_EOK;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (disk->ops->control)
|
||||
{
|
||||
err = disk->ops->control(disk, blk, cmd, args);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops blk_dev_ops =
|
||||
{
|
||||
.open = blk_dev_open,
|
||||
.close = blk_dev_close,
|
||||
.read = blk_dev_read,
|
||||
.write = blk_dev_write,
|
||||
.control = blk_dev_control,
|
||||
};
|
||||
#endif
|
||||
|
||||
rt_err_t blk_dev_initialize(struct rt_blk_device *blk)
|
||||
{
|
||||
struct rt_device *dev;
|
||||
|
||||
if (!blk)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
dev = &blk->parent;
|
||||
dev->type = RT_Device_Class_Block;
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
dev->ops = &blk_dev_ops;
|
||||
#else
|
||||
dev->open = blk_dev_open;
|
||||
dev->close = blk_dev_close;
|
||||
dev->read = blk_dev_read;
|
||||
dev->write = blk_dev_write;
|
||||
dev->control = blk_dev_control;
|
||||
#endif
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t disk_add_blk_dev(struct rt_blk_disk *disk, struct rt_blk_device *blk)
|
||||
{
|
||||
rt_err_t err;
|
||||
#ifdef RT_USING_DM
|
||||
int device_id;
|
||||
#endif
|
||||
const char *disk_name, *name_fmt;
|
||||
|
||||
if (!disk || !blk)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DM
|
||||
if ((device_id = rt_dm_ida_alloc(disk->ida)) < 0)
|
||||
{
|
||||
return -RT_EFULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
blk->disk = disk;
|
||||
rt_list_init(&blk->list);
|
||||
|
||||
disk_name = to_disk_name(disk);
|
||||
|
||||
/* End is [a-zA-Z] or [0-9] */
|
||||
if (disk_name[rt_strlen(disk_name) - 1] < 'a')
|
||||
{
|
||||
name_fmt = "%sp%d";
|
||||
}
|
||||
else
|
||||
{
|
||||
name_fmt = "%s%d";
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DM
|
||||
rt_dm_dev_set_name(&blk->parent, name_fmt, disk_name, blk->partno);
|
||||
blk->parent.master_id = disk->ida->master_id;
|
||||
blk->parent.device_id = device_id;
|
||||
#else
|
||||
rt_snprintf(blk->parent.parent.name, RT_NAME_MAX, name_fmt, disk_name, blk->partno);
|
||||
#endif
|
||||
device_set_blk_fops(&blk->parent);
|
||||
|
||||
err = rt_device_register(&blk->parent, to_blk_name(blk),
|
||||
disk->parent.flag & RT_DEVICE_FLAG_RDWR);
|
||||
|
||||
if (err)
|
||||
{
|
||||
#ifdef RT_USING_DM
|
||||
rt_dm_ida_free(disk->ida, device_id);
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
spin_lock(&disk->lock);
|
||||
|
||||
rt_list_insert_before(&disk->part_nodes, &blk->list);
|
||||
|
||||
spin_unlock(&disk->lock);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t disk_remove_blk_dev(struct rt_blk_device *blk, rt_bool_t lockless)
|
||||
{
|
||||
struct rt_blk_disk *disk;
|
||||
|
||||
if (!blk)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
disk = blk->disk;
|
||||
|
||||
if (!disk)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef RT_USING_DFS
|
||||
const char *mountpath;
|
||||
|
||||
if ((mountpath = dfs_filesystem_get_mounted_path(&blk->parent)))
|
||||
{
|
||||
dfs_unmount(mountpath);
|
||||
LOG_D("%s: Unmount file system on %s",
|
||||
to_blk_name(blk), mountpath);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DM
|
||||
rt_dm_ida_free(disk->ida, blk->parent.device_id);
|
||||
#endif
|
||||
|
||||
rt_device_unregister(&blk->parent);
|
||||
|
||||
if (!lockless)
|
||||
{
|
||||
spin_lock(&disk->lock);
|
||||
}
|
||||
|
||||
rt_list_remove(&blk->list);
|
||||
|
||||
if (!lockless)
|
||||
{
|
||||
spin_unlock(&disk->lock);
|
||||
}
|
||||
|
||||
--disk->partitions;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_uint32_t blk_request_ioprio(void)
|
||||
{
|
||||
struct rt_thread *task = rt_thread_self();
|
||||
|
||||
return task ? RT_SCHED_PRIV(task).current_priority : 0;
|
||||
}
|
49
rt-thread/components/drivers/block/blk_dev.h
Normal file
49
rt-thread/components/drivers/block/blk_dev.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#ifndef __BLK_DEV_H__
|
||||
#define __BLK_DEV_H__
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <drivers/blk.h>
|
||||
#include <drivers/misc.h>
|
||||
|
||||
#define to_blk_disk(dev) rt_container_of(dev, struct rt_blk_disk, parent)
|
||||
#define to_blk(dev) rt_container_of(dev, struct rt_blk_device, parent)
|
||||
|
||||
#ifdef RT_USING_DM
|
||||
#define to_disk_name(disk) rt_dm_dev_get_name(&(disk)->parent)
|
||||
#define to_blk_name(blk) rt_dm_dev_get_name(&(blk)->parent)
|
||||
#else
|
||||
#define to_disk_name(disk) (disk)->parent.parent.name
|
||||
#define to_blk_name(blk) (blk)->parent.parent.name
|
||||
#endif
|
||||
|
||||
/* %c%c name */
|
||||
#define letter_name(n) ('a' + (n) / ((n) >= 26 ? (26 * 2) : 1)), ((n) >= 26 ? 'a' + (n) % 26 : '\0')
|
||||
|
||||
rt_inline void spin_lock(struct rt_spinlock *spinlock)
|
||||
{
|
||||
rt_hw_spin_lock(&spinlock->lock);
|
||||
}
|
||||
|
||||
rt_inline void spin_unlock(struct rt_spinlock *spinlock)
|
||||
{
|
||||
rt_hw_spin_unlock(&spinlock->lock);
|
||||
}
|
||||
|
||||
rt_err_t blk_dev_initialize(struct rt_blk_device *blk);
|
||||
rt_err_t disk_add_blk_dev(struct rt_blk_disk *disk, struct rt_blk_device *blk);
|
||||
rt_err_t disk_remove_blk_dev(struct rt_blk_device *blk, rt_bool_t lockless);
|
||||
|
||||
rt_uint32_t blk_request_ioprio(void);
|
||||
|
||||
#endif /* __BLK_DEV_H__ */
|
274
rt-thread/components/drivers/block/blk_dfs.c
Normal file
274
rt-thread/components/drivers/block/blk_dfs.c
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-08-08 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include "blk_dfs.h"
|
||||
|
||||
#include <dfs_file.h>
|
||||
#include <drivers/classes/block.h>
|
||||
|
||||
#if defined(RT_USING_POSIX_DEVIO) && defined(RT_USING_DFS_V2)
|
||||
struct blk_fops_data
|
||||
{
|
||||
struct rt_device_blk_geometry geometry;
|
||||
};
|
||||
|
||||
static int blk_fops_open(struct dfs_file *file)
|
||||
{
|
||||
struct rt_device *dev = file->vnode->data;
|
||||
struct blk_fops_data *data = rt_malloc(sizeof(*data));
|
||||
|
||||
if (!data)
|
||||
{
|
||||
return (int)-RT_ENOMEM;
|
||||
}
|
||||
|
||||
dev->user_data = data;
|
||||
rt_device_control(dev, RT_DEVICE_CTRL_BLK_GETGEOME, &data->geometry);
|
||||
rt_device_control(dev, RT_DEVICE_CTRL_ALL_BLK_SSIZEGET, &file->vnode->size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blk_fops_close(struct dfs_file *file)
|
||||
{
|
||||
struct rt_device *dev = file->vnode->data;
|
||||
|
||||
rt_free(dev->user_data);
|
||||
dev->user_data = RT_NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blk_fops_ioctl(struct dfs_file *file, int cmd, void *arg)
|
||||
{
|
||||
struct rt_device *dev = file->vnode->data;
|
||||
|
||||
return (int)rt_device_control(dev, cmd, arg);
|
||||
}
|
||||
|
||||
static ssize_t blk_fops_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
void *rbuf;
|
||||
rt_ssize_t res = 0;
|
||||
int bytes_per_sector, blk_pos, first_offs, rsize = 0;
|
||||
struct rt_device *dev = file->vnode->data;
|
||||
struct blk_fops_data *data = dev->user_data;
|
||||
|
||||
bytes_per_sector = data->geometry.bytes_per_sector;
|
||||
blk_pos = *pos / bytes_per_sector;
|
||||
first_offs = *pos % bytes_per_sector;
|
||||
|
||||
if ((rbuf = rt_malloc(bytes_per_sector)))
|
||||
{
|
||||
/*
|
||||
** #1: read first unalign block size.
|
||||
*/
|
||||
res = rt_device_read(dev, blk_pos, rbuf, 1);
|
||||
|
||||
if (res == 1)
|
||||
{
|
||||
if (count > bytes_per_sector - first_offs)
|
||||
{
|
||||
rsize = bytes_per_sector - first_offs;
|
||||
}
|
||||
else
|
||||
{
|
||||
rsize = count;
|
||||
}
|
||||
rt_memcpy(buf, rbuf + first_offs, rsize);
|
||||
++blk_pos;
|
||||
|
||||
/*
|
||||
** #2: read continuous block size.
|
||||
*/
|
||||
while (rsize < count)
|
||||
{
|
||||
res = rt_device_read(dev, blk_pos++, rbuf, 1);
|
||||
|
||||
if (res != 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (count - rsize >= bytes_per_sector)
|
||||
{
|
||||
rt_memcpy(buf + rsize, rbuf, bytes_per_sector);
|
||||
rsize += bytes_per_sector;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_memcpy(buf + rsize, rbuf, count - rsize);
|
||||
rsize = count;
|
||||
}
|
||||
}
|
||||
|
||||
*pos += rsize;
|
||||
}
|
||||
|
||||
rt_free(rbuf);
|
||||
}
|
||||
|
||||
return rsize;
|
||||
}
|
||||
|
||||
static ssize_t blk_fops_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
void *rbuf;
|
||||
rt_ssize_t res = 0;
|
||||
int bytes_per_sector, blk_pos, first_offs, wsize = 0;
|
||||
struct rt_device *dev = file->vnode->data;
|
||||
struct blk_fops_data *data = dev->user_data;
|
||||
|
||||
bytes_per_sector = data->geometry.bytes_per_sector;
|
||||
blk_pos = *pos / bytes_per_sector;
|
||||
first_offs = *pos % bytes_per_sector;
|
||||
|
||||
/*
|
||||
** #1: write first unalign block size.
|
||||
*/
|
||||
if (first_offs != 0)
|
||||
{
|
||||
if (count > bytes_per_sector - first_offs)
|
||||
{
|
||||
wsize = bytes_per_sector - first_offs;
|
||||
}
|
||||
else
|
||||
{
|
||||
wsize = count;
|
||||
}
|
||||
|
||||
if ((rbuf = rt_malloc(bytes_per_sector)))
|
||||
{
|
||||
res = rt_device_read(dev, blk_pos, rbuf, 1);
|
||||
|
||||
if (res == 1)
|
||||
{
|
||||
rt_memcpy(rbuf + first_offs, buf, wsize);
|
||||
res = rt_device_write(dev, blk_pos, (const void *)rbuf, 1);
|
||||
|
||||
if (res == 1)
|
||||
{
|
||||
blk_pos += 1;
|
||||
rt_free(rbuf);
|
||||
|
||||
goto _goon;
|
||||
}
|
||||
}
|
||||
|
||||
rt_free(rbuf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_goon:
|
||||
/*
|
||||
** #2: write continuous block size.
|
||||
*/
|
||||
if ((count - wsize) / bytes_per_sector != 0)
|
||||
{
|
||||
res = rt_device_write(dev, blk_pos, buf + wsize, (count - wsize) / bytes_per_sector);
|
||||
wsize += res * bytes_per_sector;
|
||||
blk_pos += res;
|
||||
|
||||
if (res != (count - wsize) / bytes_per_sector)
|
||||
{
|
||||
*pos += wsize;
|
||||
return wsize;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** # 3: write last unalign block size.
|
||||
*/
|
||||
if ((count - wsize) != 0)
|
||||
{
|
||||
if ((rbuf = rt_malloc(bytes_per_sector)))
|
||||
{
|
||||
res = rt_device_read(dev, blk_pos, rbuf, 1);
|
||||
|
||||
if (res == 1)
|
||||
{
|
||||
rt_memcpy(rbuf, buf + wsize, count - wsize);
|
||||
res = rt_device_write(dev, blk_pos, (const void *)rbuf, 1);
|
||||
|
||||
if (res == 1)
|
||||
{
|
||||
wsize += count - wsize;
|
||||
}
|
||||
}
|
||||
|
||||
rt_free(rbuf);
|
||||
}
|
||||
}
|
||||
|
||||
*pos += wsize;
|
||||
return wsize;
|
||||
}
|
||||
|
||||
static int blk_fops_flush(struct dfs_file *file)
|
||||
{
|
||||
struct rt_device *dev = file->vnode->data;
|
||||
|
||||
return (int)rt_device_control(dev, RT_DEVICE_CTRL_BLK_SYNC, RT_NULL);
|
||||
}
|
||||
|
||||
static int blk_fops_poll(struct dfs_file *file, struct rt_pollreq *req)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
const static struct dfs_file_ops blk_fops =
|
||||
{
|
||||
.open = blk_fops_open,
|
||||
.close = blk_fops_close,
|
||||
.ioctl = blk_fops_ioctl,
|
||||
.read = blk_fops_read,
|
||||
.write = blk_fops_write,
|
||||
.flush = blk_fops_flush,
|
||||
.lseek = generic_dfs_lseek,
|
||||
.poll = blk_fops_poll
|
||||
};
|
||||
|
||||
void device_set_blk_fops(struct rt_device *dev)
|
||||
{
|
||||
dev->fops = &blk_fops;
|
||||
}
|
||||
#else
|
||||
void device_set_blk_fops(struct rt_device *dev)
|
||||
{
|
||||
}
|
||||
#endif /* RT_USING_POSIX_DEVIO && RT_USING_DFS_V2 */
|
||||
|
||||
void device_get_blk_ssize(struct rt_device *dev, void *args)
|
||||
{
|
||||
rt_uint32_t bytes_per_sector;
|
||||
struct rt_device_blk_geometry geometry;
|
||||
|
||||
rt_device_control(dev, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
|
||||
bytes_per_sector = geometry.bytes_per_sector;
|
||||
|
||||
RT_ASSERT(sizeof(bytes_per_sector) == sizeof(geometry.bytes_per_sector));
|
||||
|
||||
rt_memcpy(args, &bytes_per_sector, sizeof(bytes_per_sector));
|
||||
}
|
||||
|
||||
void device_get_all_blk_ssize(struct rt_device *dev, void *args)
|
||||
{
|
||||
rt_uint64_t count_mul_per;
|
||||
struct rt_device_blk_geometry geometry;
|
||||
|
||||
rt_device_control(dev, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
|
||||
count_mul_per = geometry.bytes_per_sector * geometry.sector_count;
|
||||
|
||||
rt_memcpy(args, &count_mul_per, sizeof(count_mul_per));
|
||||
}
|
23
rt-thread/components/drivers/block/blk_dfs.h
Normal file
23
rt-thread/components/drivers/block/blk_dfs.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-08-08 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#ifndef __BLK_DFS_H__
|
||||
#define __BLK_DFS_H__
|
||||
|
||||
#include <rtdef.h>
|
||||
|
||||
#define RT_DEVICE_CTRL_BLK_SSIZEGET 0x00001268 /**< get number of bytes per sector */
|
||||
#define RT_DEVICE_CTRL_ALL_BLK_SSIZEGET 0x80081272 /**< get number of bytes per sector * sector counts */
|
||||
|
||||
void device_set_blk_fops(struct rt_device *dev);
|
||||
void device_get_blk_ssize(struct rt_device *dev, void *args);
|
||||
void device_get_all_blk_ssize(struct rt_device *dev, void *args);
|
||||
|
||||
#endif /* __BLK_DFS_H__ */
|
154
rt-thread/components/drivers/block/blk_partition.c
Normal file
154
rt-thread/components/drivers/block/blk_partition.c
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#define DBG_TAG "blk.part"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "blk_partition.h"
|
||||
|
||||
static rt_err_t (*partition_list[])(struct rt_blk_disk *) =
|
||||
{
|
||||
#ifdef RT_BLK_PARTITION_EFI
|
||||
efi_partition,
|
||||
#endif
|
||||
#ifdef RT_BLK_PARTITION_DFS
|
||||
dfs_partition,
|
||||
#endif
|
||||
};
|
||||
|
||||
rt_err_t blk_put_partition(struct rt_blk_disk *disk, const char *type,
|
||||
rt_size_t start, rt_size_t count, int partno)
|
||||
{
|
||||
rt_err_t err;
|
||||
|
||||
struct rt_blk_device *blk = rt_calloc(1, sizeof(*blk));
|
||||
|
||||
if (type && rt_strcmp(type, "dfs"))
|
||||
{
|
||||
rt_uint32_t ssz = rt_blk_disk_get_logical_block_size(disk);
|
||||
|
||||
rt_kprintf("found part[%u], begin: %lu, size: ", partno, start * ssz);
|
||||
|
||||
if ((count >> 11) == 0)
|
||||
{
|
||||
rt_kprintf("%u%cB\n", count >> 1, 'K'); /* KB */
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_uint32_t size_mb = count >> 11; /* MB */
|
||||
|
||||
if ((size_mb >> 10) == 0)
|
||||
{
|
||||
rt_kprintf("%u.%u%cB\n", size_mb, (count >> 1) & 0x3ff, 'M');
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("%u.%u%cB\n", size_mb >> 10, size_mb & 0x3ff, 'G');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!blk)
|
||||
{
|
||||
err = -RT_ENOMEM;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
err = blk_dev_initialize(blk);
|
||||
|
||||
if (err)
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
blk->partno = partno;
|
||||
blk->sector_start = start;
|
||||
blk->sector_count = count;
|
||||
|
||||
blk->partition.offset = start;
|
||||
blk->partition.size = count;
|
||||
blk->partition.lock = &disk->usr_lock;
|
||||
|
||||
err = disk_add_blk_dev(disk, blk);
|
||||
|
||||
if (err)
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
++disk->partitions;
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
LOG_E("%s: Put partition.%s[%u] start = %lu count = %lu error = %s",
|
||||
to_disk_name(disk), type, partno, start, count, rt_strerror(err));
|
||||
|
||||
if (blk)
|
||||
{
|
||||
rt_free(blk);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_err_t rt_blk_disk_probe_partition(struct rt_blk_disk *disk)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
|
||||
if (!disk)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
LOG_D("%s: Probing disk partitions", to_disk_name(disk));
|
||||
|
||||
if (disk->partitions)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
err = -RT_EEMPTY;
|
||||
|
||||
if (disk->max_partitions == RT_BLK_PARTITION_NONE)
|
||||
{
|
||||
LOG_D("%s: Unsupported partitions", to_disk_name(disk));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
for (int i = 0; i < RT_ARRAY_SIZE(partition_list); ++i)
|
||||
{
|
||||
rt_err_t part_err = partition_list[i](disk);
|
||||
|
||||
if (part_err == -RT_ENOMEM)
|
||||
{
|
||||
err = part_err;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!part_err)
|
||||
{
|
||||
err = RT_EOK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((err && err != -RT_ENOMEM) || disk->partitions == 0)
|
||||
{
|
||||
/* No partition found */
|
||||
rt_size_t total_sectors = rt_blk_disk_get_capacity(disk);
|
||||
|
||||
err = blk_put_partition(disk, RT_NULL, 0, total_sectors, 0);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
22
rt-thread/components/drivers/block/blk_partition.h
Normal file
22
rt-thread/components/drivers/block/blk_partition.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#ifndef __BLK_PARTITION_H__
|
||||
#define __BLK_PARTITION_H__
|
||||
|
||||
#include "blk_dev.h"
|
||||
|
||||
rt_err_t blk_put_partition(struct rt_blk_disk *disk, const char *type,
|
||||
rt_size_t start, rt_size_t count, int partno);
|
||||
|
||||
rt_err_t dfs_partition(struct rt_blk_disk *disk);
|
||||
rt_err_t efi_partition(struct rt_blk_disk *disk);
|
||||
|
||||
#endif /* __BLK_PARTITION_H__ */
|
12
rt-thread/components/drivers/block/partitions/Kconfig
Normal file
12
rt-thread/components/drivers/block/partitions/Kconfig
Normal file
@ -0,0 +1,12 @@
|
||||
menu "Partition Types"
|
||||
|
||||
config RT_BLK_PARTITION_DFS
|
||||
bool "DFS Partition support"
|
||||
depends on RT_USING_DFS
|
||||
default y
|
||||
|
||||
config RT_BLK_PARTITION_EFI
|
||||
bool "EFI Globally Unique Identifier (GUID) Partition support"
|
||||
default y
|
||||
|
||||
endmenu
|
18
rt-thread/components/drivers/block/partitions/SConscript
Normal file
18
rt-thread/components/drivers/block/partitions/SConscript
Normal file
@ -0,0 +1,18 @@
|
||||
from building import *
|
||||
|
||||
group = []
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd + '/../../include']
|
||||
|
||||
src = []
|
||||
|
||||
if GetDepend(['RT_BLK_PARTITION_DFS']):
|
||||
src += ['dfs.c']
|
||||
|
||||
if GetDepend(['RT_BLK_PARTITION_EFI']):
|
||||
src += ['efi.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
55
rt-thread/components/drivers/block/partitions/dfs.c
Normal file
55
rt-thread/components/drivers/block/partitions/dfs.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2011-07-25 weety first version
|
||||
* 2023-02-25 GuEe-GUI make blk interface
|
||||
*/
|
||||
|
||||
#include "efi.h"
|
||||
|
||||
#define DBG_TAG "blk.part.dfs"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
rt_err_t dfs_partition(struct rt_blk_disk *disk)
|
||||
{
|
||||
rt_ssize_t res;
|
||||
struct dfs_partition part;
|
||||
rt_uint8_t *sector = rt_malloc(rt_blk_disk_get_logical_block_size(disk));
|
||||
|
||||
if (!sector)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
res = disk->ops->read(disk, 0, sector, 1);
|
||||
|
||||
if (res < 0)
|
||||
{
|
||||
rt_free(sector);
|
||||
return res;
|
||||
}
|
||||
|
||||
for (rt_size_t i = 0; i < disk->max_partitions; ++i)
|
||||
{
|
||||
res = dfs_filesystem_get_partition(&part, sector, i);
|
||||
|
||||
if (res)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (blk_put_partition(disk, "dfs", part.offset, part.size, i) == -RT_ENOMEM)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rt_free(sector);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
738
rt-thread/components/drivers/block/partitions/efi.c
Normal file
738
rt-thread/components/drivers/block/partitions/efi.c
Normal file
@ -0,0 +1,738 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-05-05 linzhenxing first version
|
||||
* 2023-02-25 GuEe-GUI make blk interface
|
||||
*/
|
||||
|
||||
#include "efi.h"
|
||||
|
||||
#define DBG_TAG "blk.part.efi"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
static rt_bool_t force_gpt = 0;
|
||||
|
||||
static int force_gpt_setup(void)
|
||||
{
|
||||
#ifdef RT_USING_OFW
|
||||
force_gpt = !!rt_ofw_bootargs_select("gpt", 0);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_CORE_EXPORT(force_gpt_setup);
|
||||
|
||||
/**
|
||||
* @brief This function is EFI version of crc32 function.
|
||||
*
|
||||
* @param buf the buffer to calculate crc32 of.
|
||||
* @param len the length of buf.
|
||||
* @return EFI-style CRC32 value for @buf.
|
||||
*/
|
||||
rt_inline rt_uint32_t efi_crc32(const rt_uint8_t *buf, rt_size_t len)
|
||||
{
|
||||
rt_ubase_t crc = 0xffffffffUL;
|
||||
|
||||
for (rt_size_t i = 0; i < len; ++i)
|
||||
{
|
||||
crc ^= buf[i];
|
||||
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320L : 0);
|
||||
}
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function get number of last logical block of device.
|
||||
*
|
||||
* @param disk the blk of disk.
|
||||
* @return last LBA value on success, 0 on error.
|
||||
* This is stored (by sd and ide-geometry) in
|
||||
* the part[0] entry for this disk, and is the number of
|
||||
* physical sectors available on the disk.
|
||||
*/
|
||||
static rt_size_t last_lba(struct rt_blk_disk *disk)
|
||||
{
|
||||
return rt_blk_disk_get_capacity(disk) - 1ULL;
|
||||
}
|
||||
|
||||
rt_inline int pmbr_part_valid(gpt_mbr_record *part)
|
||||
{
|
||||
if (part->os_type != EFI_PMBR_OSTYPE_EFI_GPT)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set to 0x00000001 (i.e., the LBA of the GPT Partition Header) */
|
||||
if (rt_le32_to_cpu(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return GPT_MBR_PROTECTIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function test Protective MBR for validity.
|
||||
*
|
||||
* @param mbr the pointer to a legacy mbr structure.
|
||||
* @param total_sectors the amount of sectors in the device
|
||||
* @return
|
||||
* 0 -> Invalid MBR
|
||||
* 1 -> GPT_MBR_PROTECTIVE
|
||||
* 2 -> GPT_MBR_HYBRID
|
||||
*/
|
||||
static int is_pmbr_valid(legacy_mbr *mbr, rt_size_t total_sectors)
|
||||
{
|
||||
rt_uint32_t sz = 0;
|
||||
int part = 0, ret = 0; /* invalid by default */
|
||||
|
||||
if (!mbr || rt_le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
|
||||
{
|
||||
goto _done;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
ret = pmbr_part_valid(&mbr->partition_record[i]);
|
||||
|
||||
if (ret == GPT_MBR_PROTECTIVE)
|
||||
{
|
||||
part = i;
|
||||
/*
|
||||
* Ok, we at least know that there's a protective MBR,
|
||||
* now check if there are other partition types for
|
||||
* hybrid MBR.
|
||||
*/
|
||||
goto _check_hybrid;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != GPT_MBR_PROTECTIVE)
|
||||
{
|
||||
goto _done;
|
||||
}
|
||||
|
||||
_check_hybrid:
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (mbr->partition_record[i].os_type != EFI_PMBR_OSTYPE_EFI_GPT &&
|
||||
mbr->partition_record[i].os_type != 0x00)
|
||||
{
|
||||
ret = GPT_MBR_HYBRID;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Protective MBRs take up the lesser of the whole disk
|
||||
* or 2 TiB (32bit LBA), ignoring the rest of the disk.
|
||||
* Some partitioning programs, nonetheless, choose to set
|
||||
* the size to the maximum 32-bit limitation, disregarding
|
||||
* the disk size.
|
||||
*
|
||||
* Hybrid MBRs do not necessarily comply with this.
|
||||
*
|
||||
* Consider a bad value here to be a warning to support dd'ing
|
||||
* an image from a smaller disk to a larger disk.
|
||||
*/
|
||||
if (ret == GPT_MBR_PROTECTIVE)
|
||||
{
|
||||
sz = rt_le32_to_cpu(mbr->partition_record[part].size_in_lba);
|
||||
|
||||
if (sz != (rt_uint32_t)total_sectors - 1 && sz != 0xffffffff)
|
||||
{
|
||||
LOG_W("GPT: mbr size in lba (%u) different than whole disk (%u)",
|
||||
sz, rt_min_t(rt_uint32_t, total_sectors - 1, 0xffffffff));
|
||||
}
|
||||
}
|
||||
|
||||
_done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function read bytes from disk, starting at given LBA.
|
||||
*
|
||||
* @param disk the blk of disk.
|
||||
* @param lba the Logical Block Address of the partition table.
|
||||
* @param buffer the destination buffer.
|
||||
* @param count the bytes to read.
|
||||
* @return number of bytes read on success, 0 on error.
|
||||
*/
|
||||
static rt_size_t read_lba(struct rt_blk_disk *disk,
|
||||
rt_uint64_t lba, rt_uint8_t *buffer, rt_size_t count)
|
||||
{
|
||||
rt_size_t totalreadcount = 0;
|
||||
|
||||
if (!buffer || lba > last_lba(disk))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (rt_uint64_t n = lba; count; ++n)
|
||||
{
|
||||
int copied = 512;
|
||||
|
||||
disk->ops->read(disk, n, buffer, 1);
|
||||
|
||||
if (copied > count)
|
||||
{
|
||||
copied = count;
|
||||
}
|
||||
|
||||
buffer += copied;
|
||||
totalreadcount += copied;
|
||||
count -= copied;
|
||||
}
|
||||
|
||||
return totalreadcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function reads partition entries from disk.
|
||||
*
|
||||
* @param disk the blk of disk.
|
||||
* @param gpt the GPT header
|
||||
* @return ptes on success, null on error.
|
||||
*/
|
||||
static gpt_entry *alloc_read_gpt_entries(struct rt_blk_disk *disk,
|
||||
gpt_header *gpt)
|
||||
{
|
||||
rt_size_t count;
|
||||
gpt_entry *pte;
|
||||
rt_uint64_t entry_lba;
|
||||
|
||||
if (!gpt)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
count = (rt_size_t)rt_le32_to_cpu(gpt->num_partition_entries) *
|
||||
rt_le32_to_cpu(gpt->sizeof_partition_entry);
|
||||
|
||||
if (!count)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
pte = rt_malloc(count);
|
||||
|
||||
if (!pte)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
entry_lba = rt_le64_to_cpu(gpt->partition_entry_lba);
|
||||
|
||||
if (read_lba(disk, entry_lba, (rt_uint8_t *)pte, count) < count)
|
||||
{
|
||||
rt_free(pte);
|
||||
pte = RT_NULL;
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/* Remember to free pte when done */
|
||||
return pte;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function allocates GPT header, reads into it from disk.
|
||||
*
|
||||
* @param disk the blk of disk.
|
||||
* @param lba the Logical Block Address of the partition table
|
||||
* @return GPT header on success, null on error.
|
||||
*/
|
||||
static gpt_header *alloc_read_gpt_header(struct rt_blk_disk *disk, rt_uint64_t lba)
|
||||
{
|
||||
gpt_header *gpt;
|
||||
rt_uint32_t ssz = rt_blk_disk_get_logical_block_size(disk);
|
||||
|
||||
gpt = rt_malloc(ssz);
|
||||
|
||||
if (!gpt)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
if (read_lba(disk, lba, (rt_uint8_t *)gpt, ssz) < ssz)
|
||||
{
|
||||
rt_free(gpt);
|
||||
gpt = RT_NULL;
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/* Remember to free gpt when finished with it */
|
||||
return gpt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function tests one GPT header and PTEs for validity.
|
||||
*
|
||||
* @param disk the blk of disk.
|
||||
* @param lba the Logical Block Address of the GPT header to test.
|
||||
* @param gpt the GPT header ptr, filled on return.
|
||||
* @param ptes the PTEs ptr, filled on return.
|
||||
* @returns true if valid, false on error.
|
||||
* If valid, returns pointers to newly allocated GPT header and PTEs.
|
||||
*/
|
||||
static rt_bool_t is_gpt_valid(struct rt_blk_disk *disk,
|
||||
rt_uint64_t lba, gpt_header **gpt, gpt_entry **ptes)
|
||||
{
|
||||
rt_uint32_t crc, origcrc;
|
||||
rt_uint64_t lastlba, pt_size;
|
||||
rt_ssize_t logical_block_size;
|
||||
|
||||
if (!ptes)
|
||||
{
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
if (!(*gpt = alloc_read_gpt_header(disk, lba)))
|
||||
{
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
/* Check the GUID Partition Table signature */
|
||||
if (rt_le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE)
|
||||
{
|
||||
LOG_D("%s: GUID Partition Table Header signature is wrong: %lld != %lld",
|
||||
to_disk_name(disk),
|
||||
(rt_uint64_t)rt_le64_to_cpu((*gpt)->signature),
|
||||
(rt_uint64_t)GPT_HEADER_SIGNATURE);
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
/* Check the GUID Partition Table header size is too big */
|
||||
logical_block_size = rt_blk_disk_get_logical_block_size(disk);
|
||||
|
||||
if (rt_le32_to_cpu((*gpt)->header_size) > logical_block_size)
|
||||
{
|
||||
LOG_D("%s: GUID Partition Table Header size is too large: %u > %u",
|
||||
to_disk_name(disk),
|
||||
rt_le32_to_cpu((*gpt)->header_size),
|
||||
logical_block_size);
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
/* Check the GUID Partition Table header size is too small */
|
||||
if (rt_le32_to_cpu((*gpt)->header_size) < sizeof(gpt_header))
|
||||
{
|
||||
LOG_D("%s: GUID Partition Table Header size is too small: %u < %u",
|
||||
to_disk_name(disk),
|
||||
rt_le32_to_cpu((*gpt)->header_size),
|
||||
sizeof(gpt_header));
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
/* Check the GUID Partition Table CRC */
|
||||
origcrc = rt_le32_to_cpu((*gpt)->header_crc32);
|
||||
(*gpt)->header_crc32 = 0;
|
||||
crc = efi_crc32((const rt_uint8_t *)(*gpt), rt_le32_to_cpu((*gpt)->header_size));
|
||||
|
||||
if (crc != origcrc)
|
||||
{
|
||||
LOG_D("%s: GUID Partition Table Header CRC is wrong: %x != %x",
|
||||
to_disk_name(disk), crc, origcrc);
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
(*gpt)->header_crc32 = rt_cpu_to_le32(origcrc);
|
||||
|
||||
/*
|
||||
* Check that the start_lba entry points to the LBA that contains
|
||||
* the GUID Partition Table
|
||||
*/
|
||||
if (rt_le64_to_cpu((*gpt)->start_lba) != lba)
|
||||
{
|
||||
LOG_D("%s: GPT start_lba incorrect: %lld != %lld",
|
||||
to_disk_name(disk),
|
||||
(rt_uint64_t)rt_le64_to_cpu((*gpt)->start_lba),
|
||||
(rt_uint64_t)lba);
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
/* Check the first_usable_lba and last_usable_lba are within the disk */
|
||||
lastlba = last_lba(disk);
|
||||
|
||||
if (rt_le64_to_cpu((*gpt)->first_usable_lba) > lastlba)
|
||||
{
|
||||
LOG_D("%s: GPT: first_usable_lba incorrect: %lld > %lld",
|
||||
to_disk_name(disk),
|
||||
(rt_uint64_t)rt_le64_to_cpu((*gpt)->first_usable_lba),
|
||||
(rt_uint64_t)lastlba);
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
if (rt_le64_to_cpu((*gpt)->last_usable_lba) > lastlba)
|
||||
{
|
||||
LOG_D("%s: GPT: last_usable_lba incorrect: %lld > %lld",
|
||||
to_disk_name(disk),
|
||||
(rt_uint64_t)rt_le64_to_cpu((*gpt)->last_usable_lba),
|
||||
(rt_uint64_t)lastlba);
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
if (rt_le64_to_cpu((*gpt)->last_usable_lba) < rt_le64_to_cpu((*gpt)->first_usable_lba))
|
||||
{
|
||||
LOG_D("%s: GPT: last_usable_lba incorrect: %lld > %lld",
|
||||
to_disk_name(disk),
|
||||
(rt_uint64_t)rt_le64_to_cpu((*gpt)->last_usable_lba),
|
||||
(rt_uint64_t)rt_le64_to_cpu((*gpt)->first_usable_lba));
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
/* Check that sizeof_partition_entry has the correct value */
|
||||
if (rt_le32_to_cpu((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry))
|
||||
{
|
||||
LOG_D("%s: GUID Partition Entry Size check failed", to_disk_name(disk));
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
/* Sanity check partition table size */
|
||||
pt_size = (rt_uint64_t)rt_le32_to_cpu((*gpt)->num_partition_entries) *
|
||||
rt_le32_to_cpu((*gpt)->sizeof_partition_entry);
|
||||
|
||||
if (!(*ptes = alloc_read_gpt_entries(disk, *gpt)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
/* Check the GUID Partition Entry Array CRC */
|
||||
crc = efi_crc32((const rt_uint8_t *)(*ptes), pt_size);
|
||||
|
||||
if (crc != rt_le32_to_cpu((*gpt)->partition_entry_array_crc32))
|
||||
{
|
||||
LOG_D("%s: GUID Partition Entry Array CRC check failed", to_disk_name(disk));
|
||||
|
||||
goto _fail_ptes;
|
||||
}
|
||||
|
||||
/* We're done, all's well */
|
||||
return RT_TRUE;
|
||||
|
||||
_fail_ptes:
|
||||
rt_free(*ptes);
|
||||
*ptes = RT_NULL;
|
||||
|
||||
_fail:
|
||||
rt_free(*gpt);
|
||||
*gpt = RT_NULL;
|
||||
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function tests one PTE for validity.
|
||||
*
|
||||
* @param pte the pte to check.
|
||||
* @param lastlba the last lba of the disk.
|
||||
* @return valid boolean of pte.
|
||||
*/
|
||||
rt_inline rt_bool_t is_pte_valid(const gpt_entry *pte, const rt_size_t lastlba)
|
||||
{
|
||||
if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
|
||||
rt_le64_to_cpu(pte->starting_lba) > lastlba ||
|
||||
rt_le64_to_cpu(pte->ending_lba) > lastlba)
|
||||
{
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
return RT_TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function search disk for valid GPT headers and PTEs.
|
||||
*
|
||||
* @param disk the blk of disk.
|
||||
* @param pgpt the primary GPT header.
|
||||
* @param agpt the alternate GPT header.
|
||||
* @param lastlba the last LBA number.
|
||||
*/
|
||||
static void compare_gpts(struct rt_blk_disk *disk,
|
||||
gpt_header *pgpt, gpt_header *agpt, rt_uint64_t lastlba)
|
||||
{
|
||||
int error_found = 0;
|
||||
|
||||
if (!pgpt || !agpt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (rt_le64_to_cpu(pgpt->start_lba) != rt_le64_to_cpu(agpt->alternate_lba))
|
||||
{
|
||||
LOG_W("%s: GPT:Primary header LBA(%lld) != Alt(%lld), header alternate_lba",
|
||||
to_disk_name(disk),
|
||||
(rt_uint64_t)rt_le64_to_cpu(pgpt->start_lba),
|
||||
(rt_uint64_t)rt_le64_to_cpu(agpt->alternate_lba));
|
||||
|
||||
++error_found;
|
||||
}
|
||||
|
||||
if (rt_le64_to_cpu(pgpt->alternate_lba) != rt_le64_to_cpu(agpt->start_lba))
|
||||
{
|
||||
LOG_W("%s: GPT:Primary header alternate_lba(%lld) != Alt(%lld), header start_lba",
|
||||
to_disk_name(disk),
|
||||
(rt_uint64_t)rt_le64_to_cpu(pgpt->alternate_lba),
|
||||
(rt_uint64_t)rt_le64_to_cpu(agpt->start_lba));
|
||||
|
||||
++error_found;
|
||||
}
|
||||
|
||||
if (rt_le64_to_cpu(pgpt->first_usable_lba) != rt_le64_to_cpu(agpt->first_usable_lba))
|
||||
{
|
||||
LOG_W("%s: GPT:first_usable_lbas don't match %lld != %lld",
|
||||
to_disk_name(disk),
|
||||
(rt_uint64_t)rt_le64_to_cpu(pgpt->first_usable_lba),
|
||||
(rt_uint64_t)rt_le64_to_cpu(agpt->first_usable_lba));
|
||||
|
||||
++error_found;
|
||||
}
|
||||
|
||||
if (rt_le64_to_cpu(pgpt->last_usable_lba) != rt_le64_to_cpu(agpt->last_usable_lba))
|
||||
{
|
||||
LOG_W("%s: GPT:last_usable_lbas don't match %lld != %lld",
|
||||
to_disk_name(disk),
|
||||
(rt_uint64_t)rt_le64_to_cpu(pgpt->last_usable_lba),
|
||||
(rt_uint64_t)rt_le64_to_cpu(agpt->last_usable_lba));
|
||||
|
||||
++error_found;
|
||||
}
|
||||
|
||||
if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid))
|
||||
{
|
||||
LOG_W("%s: GPT:disk_guids don't match", to_disk_name(disk));
|
||||
|
||||
++error_found;
|
||||
}
|
||||
|
||||
if (rt_le32_to_cpu(pgpt->num_partition_entries) !=
|
||||
rt_le32_to_cpu(agpt->num_partition_entries))
|
||||
{
|
||||
LOG_W("%s: GPT:num_partition_entries don't match: 0x%x != 0x%x",
|
||||
to_disk_name(disk),
|
||||
rt_le32_to_cpu(pgpt->num_partition_entries),
|
||||
rt_le32_to_cpu(agpt->num_partition_entries));
|
||||
|
||||
++error_found;
|
||||
}
|
||||
|
||||
if (rt_le32_to_cpu(pgpt->sizeof_partition_entry) !=
|
||||
rt_le32_to_cpu(agpt->sizeof_partition_entry))
|
||||
{
|
||||
LOG_W("%s: GPT:sizeof_partition_entry values don't match: 0x%x != 0x%x",
|
||||
to_disk_name(disk),
|
||||
rt_le32_to_cpu(pgpt->sizeof_partition_entry),
|
||||
rt_le32_to_cpu(agpt->sizeof_partition_entry));
|
||||
|
||||
++error_found;
|
||||
}
|
||||
|
||||
if (rt_le32_to_cpu(pgpt->partition_entry_array_crc32) !=
|
||||
rt_le32_to_cpu(agpt->partition_entry_array_crc32))
|
||||
{
|
||||
LOG_W("%s: GPT:partition_entry_array_crc32 values don't match: 0x%x != 0x%x",
|
||||
to_disk_name(disk),
|
||||
rt_le32_to_cpu(pgpt->partition_entry_array_crc32),
|
||||
rt_le32_to_cpu(agpt->partition_entry_array_crc32));
|
||||
|
||||
++error_found;
|
||||
}
|
||||
|
||||
if (rt_le64_to_cpu(pgpt->alternate_lba) != lastlba)
|
||||
{
|
||||
LOG_W("%s: GPT:Primary header thinks Alt. header is not at the end of the disk: %lld != %lld",
|
||||
to_disk_name(disk),
|
||||
(rt_uint64_t)rt_le64_to_cpu(pgpt->alternate_lba),
|
||||
(rt_uint64_t)lastlba);
|
||||
|
||||
++error_found;
|
||||
}
|
||||
|
||||
if (rt_le64_to_cpu(agpt->start_lba) != lastlba)
|
||||
{
|
||||
LOG_W("%s: GPT:Alternate GPT header not at the end of the disk: %lld != %lld",
|
||||
to_disk_name(disk),
|
||||
(rt_uint64_t)rt_le64_to_cpu(agpt->start_lba),
|
||||
(rt_uint64_t)lastlba);
|
||||
|
||||
++error_found;
|
||||
}
|
||||
|
||||
if (error_found)
|
||||
{
|
||||
LOG_W("GPT: Use GNU Parted to correct GPT errors");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function search disk for valid GPT headers and PTEs.
|
||||
*
|
||||
* @param disk the disk parsed partitions.
|
||||
* @param gpt the GPT header ptr, filled on return.
|
||||
* @param ptes the PTEs ptr, filled on return.
|
||||
* @return 1 if valid, 0 on error.
|
||||
* If valid, returns pointers to newly allocated GPT header and PTEs.
|
||||
* Validity depends on PMBR being valid (or being overridden by the
|
||||
* 'gpt' kernel command line option) and finding either the Primary
|
||||
* GPT header and PTEs valid, or the Alternate GPT header and PTEs
|
||||
* valid. If the Primary GPT header is not valid, the Alternate GPT header
|
||||
* is not checked unless the 'gpt' kernel command line option is passed.
|
||||
* This protects against devices which misreport their size, and forces
|
||||
* the user to decide to use the Alternate GPT.
|
||||
*/
|
||||
static rt_bool_t find_valid_gpt(struct rt_blk_disk *disk,
|
||||
gpt_header **gpt, gpt_entry **ptes)
|
||||
{
|
||||
int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
|
||||
gpt_header *pgpt = RT_NULL, *agpt = RT_NULL;
|
||||
gpt_entry *pptes = RT_NULL, *aptes = RT_NULL;
|
||||
legacy_mbr *legacymbr;
|
||||
rt_size_t total_sectors = rt_blk_disk_get_capacity(disk);
|
||||
rt_size_t lastlba;
|
||||
|
||||
if (!ptes)
|
||||
{
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
lastlba = last_lba(disk);
|
||||
|
||||
if (!force_gpt)
|
||||
{
|
||||
/* This will be added to the EFI Spec. per Intel after v1.02. */
|
||||
legacymbr = rt_malloc(sizeof(*legacymbr));
|
||||
|
||||
if (!legacymbr)
|
||||
{
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
read_lba(disk, 0, (rt_uint8_t *)legacymbr, sizeof(*legacymbr));
|
||||
good_pmbr = is_pmbr_valid(legacymbr, total_sectors);
|
||||
rt_free(legacymbr);
|
||||
|
||||
if (!good_pmbr)
|
||||
{
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
LOG_D("%s: Device has a %s MBR", to_disk_name(disk),
|
||||
good_pmbr == GPT_MBR_PROTECTIVE ? "protective" : "hybrid");
|
||||
}
|
||||
|
||||
good_pgpt = is_gpt_valid(disk, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, &pptes);
|
||||
|
||||
if (good_pgpt)
|
||||
{
|
||||
good_agpt = is_gpt_valid(disk, rt_le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes);
|
||||
}
|
||||
|
||||
if (!good_agpt && force_gpt)
|
||||
{
|
||||
good_agpt = is_gpt_valid(disk, lastlba, &agpt, &aptes);
|
||||
}
|
||||
|
||||
/* The obviously unsuccessful case */
|
||||
if (!good_pgpt && !good_agpt)
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
compare_gpts(disk, pgpt, agpt, lastlba);
|
||||
|
||||
/* The good cases */
|
||||
if (good_pgpt)
|
||||
{
|
||||
*gpt = pgpt;
|
||||
*ptes = pptes;
|
||||
rt_free(agpt);
|
||||
rt_free(aptes);
|
||||
|
||||
if (!good_agpt)
|
||||
{
|
||||
LOG_D("%s: Alternate GPT is invalid, using primary GPT", to_disk_name(disk));
|
||||
}
|
||||
|
||||
return RT_TRUE;
|
||||
}
|
||||
else if (good_agpt)
|
||||
{
|
||||
*gpt = agpt;
|
||||
*ptes = aptes;
|
||||
rt_free(pgpt);
|
||||
rt_free(pptes);
|
||||
|
||||
LOG_D("%s: Primary GPT is invalid, using alternate GPT", to_disk_name(disk));
|
||||
|
||||
return RT_TRUE;
|
||||
}
|
||||
|
||||
_fail:
|
||||
rt_free(pgpt);
|
||||
rt_free(agpt);
|
||||
rt_free(pptes);
|
||||
rt_free(aptes);
|
||||
|
||||
*gpt = RT_NULL;
|
||||
*ptes = RT_NULL;
|
||||
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
rt_err_t efi_partition(struct rt_blk_disk *disk)
|
||||
{
|
||||
rt_uint32_t entries_nr;
|
||||
gpt_header *gpt = RT_NULL;
|
||||
gpt_entry *ptes = RT_NULL;
|
||||
|
||||
if (!find_valid_gpt(disk, &gpt, &ptes) || !gpt || !ptes)
|
||||
{
|
||||
rt_free(gpt);
|
||||
rt_free(ptes);
|
||||
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
entries_nr = rt_le32_to_cpu(gpt->num_partition_entries);
|
||||
|
||||
for (int i = 0; i < entries_nr && i < disk->max_partitions; ++i)
|
||||
{
|
||||
rt_uint64_t start = rt_le64_to_cpu(ptes[i].starting_lba);
|
||||
rt_uint64_t size = rt_le64_to_cpu(ptes[i].ending_lba) -
|
||||
rt_le64_to_cpu(ptes[i].starting_lba) + 1ULL;
|
||||
|
||||
if (!is_pte_valid(&ptes[i], last_lba(disk)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (blk_put_partition(disk, "gpt", start, size, i) == -RT_ENOMEM)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rt_free(gpt);
|
||||
rt_free(ptes);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
141
rt-thread/components/drivers/block/partitions/efi.h
Normal file
141
rt-thread/components/drivers/block/partitions/efi.h
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-05-05 linzhenxing first version
|
||||
* 2023-02-25 GuEe-GUI make blk interface
|
||||
*/
|
||||
|
||||
#ifndef __PARTITIONS_EFI_H__
|
||||
#define __PARTITIONS_EFI_H__
|
||||
|
||||
#include "../blk_partition.h"
|
||||
#include <drivers/misc.h>
|
||||
#include <drivers/byteorder.h>
|
||||
|
||||
#define MSDOS_MBR_SIGNATURE 0xaa55
|
||||
#define EFI_PMBR_OSTYPE_EFI 0xef
|
||||
#define EFI_PMBR_OSTYPE_EFI_GPT 0xee
|
||||
|
||||
#define GPT_MBR_PROTECTIVE 1
|
||||
#define GPT_MBR_HYBRID 2
|
||||
|
||||
#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
|
||||
#define GPT_HEADER_REVISION_V1 0x00010000
|
||||
#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
|
||||
|
||||
#ifndef __UUID_H__
|
||||
#define UUID_SIZE 16
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rt_uint8_t b[UUID_SIZE];
|
||||
} guid_t;
|
||||
#endif /* __UUID_H__ */
|
||||
|
||||
#ifndef __EFI_H__
|
||||
typedef guid_t efi_guid_t rt_align(4);
|
||||
|
||||
#define EFI_GUID(a, b, c, d...) (efi_guid_t) \
|
||||
{{ \
|
||||
(a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
|
||||
(b) & 0xff, ((b) >> 8) & 0xff, \
|
||||
(c) & 0xff, ((c) >> 8) & 0xff, \
|
||||
d \
|
||||
}}
|
||||
|
||||
#define NULL_GUID \
|
||||
EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
|
||||
|
||||
rt_inline int efi_guidcmp(efi_guid_t left, efi_guid_t right)
|
||||
{
|
||||
return rt_memcmp(&left, &right, sizeof (efi_guid_t));
|
||||
}
|
||||
#endif /* __EFI_H__ */
|
||||
|
||||
#define PARTITION_SYSTEM_GUID \
|
||||
EFI_GUID(0xc12a7328, 0xf81f, 0x11d2, 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b)
|
||||
|
||||
#define LEGACY_MBR_PARTITION_GUID \
|
||||
EFI_GUID(0x024dee41, 0x33e7, 0x11d3, 0x9d, 0x69, 0x00, 0x08, 0xc7, 0x81, 0xf3, 0x9f)
|
||||
|
||||
#define PARTITION_MSFT_RESERVED_GUID \
|
||||
EFI_GUID(0xe3c9e316, 0x0b5c, 0x4db8, 0x81, 0x7d, 0xf9, 0x2d, 0xf0, 0x02, 0x15, 0xae)
|
||||
|
||||
#define PARTITION_BASIC_DATA_GUID \
|
||||
EFI_GUID(0xebd0a0a2, 0xb9e5, 0x4433, 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7)
|
||||
|
||||
rt_packed(struct _gpt_header
|
||||
{
|
||||
rt_le64_t signature;
|
||||
rt_le32_t revision;
|
||||
rt_le32_t header_size;
|
||||
rt_le32_t header_crc32;
|
||||
rt_le32_t reserved1;
|
||||
rt_le64_t start_lba;
|
||||
rt_le64_t alternate_lba;
|
||||
rt_le64_t first_usable_lba;
|
||||
rt_le64_t last_usable_lba;
|
||||
efi_guid_t disk_guid;
|
||||
rt_le64_t partition_entry_lba;
|
||||
rt_le32_t num_partition_entries;
|
||||
rt_le32_t sizeof_partition_entry;
|
||||
rt_le32_t partition_entry_array_crc32;
|
||||
|
||||
/*
|
||||
* The rest of the logical block is reserved by UEFI and must be zero.
|
||||
* EFI standard handles this by:
|
||||
*
|
||||
* uint8_t reserved2[BlockSize - 92];
|
||||
*/
|
||||
});
|
||||
typedef struct _gpt_header gpt_header;
|
||||
|
||||
rt_packed(struct _gpt_entry_attributes
|
||||
{
|
||||
rt_uint64_t required_to_function:1;
|
||||
rt_uint64_t reserved:47;
|
||||
rt_uint64_t type_guid_specific:16;
|
||||
});
|
||||
typedef struct _gpt_entry_attributes gpt_entry_attributes;
|
||||
|
||||
rt_packed(struct _gpt_entry
|
||||
{
|
||||
efi_guid_t partition_type_guid;
|
||||
efi_guid_t unique_partition_guid;
|
||||
rt_le64_t starting_lba;
|
||||
rt_le64_t ending_lba;
|
||||
gpt_entry_attributes attributes;
|
||||
rt_le16_t partition_name[72/sizeof(rt_le16_t)];
|
||||
});
|
||||
typedef struct _gpt_entry gpt_entry;
|
||||
|
||||
rt_packed(struct _gpt_mbr_record
|
||||
{
|
||||
rt_uint8_t boot_indicator; /* unused by EFI, set to 0x80 for bootable */
|
||||
rt_uint8_t start_head; /* unused by EFI, pt start in CHS */
|
||||
rt_uint8_t start_sector; /* unused by EFI, pt start in CHS */
|
||||
rt_uint8_t start_track;
|
||||
rt_uint8_t os_type; /* EFI and legacy non-EFI OS types */
|
||||
rt_uint8_t end_head; /* unused by EFI, pt end in CHS */
|
||||
rt_uint8_t end_sector; /* unused by EFI, pt end in CHS */
|
||||
rt_uint8_t end_track; /* unused by EFI, pt end in CHS */
|
||||
rt_le32_t starting_lba; /* used by EFI - start addr of the on disk pt */
|
||||
rt_le32_t size_in_lba; /* used by EFI - size of pt in LBA */
|
||||
});
|
||||
typedef struct _gpt_mbr_record gpt_mbr_record;
|
||||
|
||||
rt_packed(struct _legacy_mbr
|
||||
{
|
||||
rt_uint8_t boot_code[440];
|
||||
rt_le32_t unique_mbr_signature;
|
||||
rt_le16_t unknown;
|
||||
gpt_mbr_record partition_record[4];
|
||||
rt_le16_t signature;
|
||||
});
|
||||
typedef struct _legacy_mbr legacy_mbr;
|
||||
|
||||
#endif /* __PARTITIONS_EFI_H__ */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -435,7 +435,7 @@ static rt_err_t rt_can_close(struct rt_device *dev)
|
||||
}
|
||||
|
||||
can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_CAN_INT_ERR);
|
||||
|
||||
can->ops->control(can, RT_CAN_CMD_START, RT_FALSE);
|
||||
CAN_UNLOCK(can);
|
||||
|
||||
return RT_EOK;
|
@ -3,3 +3,7 @@ menuconfig RT_USING_CLK
|
||||
depends on RT_USING_DM
|
||||
select RT_USING_ADT_REF
|
||||
default y
|
||||
|
||||
if RT_USING_CLK
|
||||
osource "$(SOC_DM_CLK_DIR)/Kconfig"
|
||||
endif
|
||||
|
@ -55,6 +55,10 @@ static struct rt_clk *clk_alloc(struct rt_clk_node *clk_np, const char *dev_id,
|
||||
|
||||
clk->fw_node = fw_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
clk = rt_err_ptr(-RT_ENOMEM);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
@ -76,7 +80,7 @@ static struct rt_clk *clk_create(struct rt_clk_node *clk_np, const char *dev_id,
|
||||
{
|
||||
struct rt_clk *clk = clk_alloc(clk_np, dev_id, con_id, fw_node);
|
||||
|
||||
if (clk)
|
||||
if (!rt_is_err(clk))
|
||||
{
|
||||
clk_get(clk_np);
|
||||
|
||||
@ -135,15 +139,6 @@ rt_err_t rt_clk_register(struct rt_clk_node *clk_np, struct rt_clk_node *parent_
|
||||
struct rt_clk *clk = RT_NULL;
|
||||
|
||||
if (clk_np)
|
||||
{
|
||||
clk = clk_alloc(clk_np, RT_NULL, RT_NULL, RT_NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (!err && clk_np)
|
||||
{
|
||||
clk_np->clk = clk;
|
||||
|
||||
@ -152,6 +147,12 @@ rt_err_t rt_clk_register(struct rt_clk_node *clk_np, struct rt_clk_node *parent_
|
||||
clk_np->ops = &unused_clk_ops;
|
||||
}
|
||||
|
||||
#if RT_NAME_MAX > 0
|
||||
rt_strncpy(clk_np->rt_parent.name, RT_CLK_NODE_OBJ_NAME, RT_NAME_MAX);
|
||||
#else
|
||||
clk_np->rt_parent.name = RT_CLK_NODE_OBJ_NAME;
|
||||
#endif
|
||||
|
||||
rt_ref_init(&clk_np->ref);
|
||||
rt_list_init(&clk_np->list);
|
||||
rt_list_init(&clk_np->children_nodes);
|
||||
@ -159,7 +160,16 @@ rt_err_t rt_clk_register(struct rt_clk_node *clk_np, struct rt_clk_node *parent_
|
||||
|
||||
if (parent_np)
|
||||
{
|
||||
clk_set_parent(clk_np, parent_np);
|
||||
clk_np->clk = clk_alloc(clk_np, RT_NULL, RT_NULL, RT_NULL);
|
||||
|
||||
if (clk_np->clk)
|
||||
{
|
||||
clk_set_parent(clk_np, parent_np);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_ENOMEM;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -265,11 +275,16 @@ static rt_err_t clk_prepare(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
||||
clk_prepare(clk_np->clk, clk_np->parent);
|
||||
}
|
||||
|
||||
if (clk_np->ops->prepare)
|
||||
if (clk->prepare_count == 0 && clk_np->ops->prepare)
|
||||
{
|
||||
err = clk_np->ops->prepare(clk);
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
++clk->prepare_count;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -287,10 +302,6 @@ rt_err_t rt_clk_prepare(struct rt_clk *clk)
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -302,10 +313,14 @@ static void clk_unprepare(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
||||
clk_unprepare(clk_np->clk, clk_np->parent);
|
||||
}
|
||||
|
||||
if (clk_np->ops->unprepare)
|
||||
if (clk->prepare_count == 1 && clk_np->ops->unprepare)
|
||||
{
|
||||
clk_np->ops->unprepare(clk);
|
||||
}
|
||||
if (clk->prepare_count)
|
||||
{
|
||||
--clk->prepare_count;
|
||||
}
|
||||
}
|
||||
|
||||
rt_err_t rt_clk_unprepare(struct rt_clk *clk)
|
||||
@ -322,10 +337,6 @@ rt_err_t rt_clk_unprepare(struct rt_clk *clk)
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -339,11 +350,16 @@ static rt_err_t clk_enable(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
||||
clk_enable(clk_np->clk, clk_np->parent);
|
||||
}
|
||||
|
||||
if (clk_np->ops->enable)
|
||||
if (clk->enable_count == 0 && clk_np->ops->enable)
|
||||
{
|
||||
err = clk_np->ops->enable(clk);
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
++clk->enable_count;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -359,10 +375,6 @@ rt_err_t rt_clk_enable(struct rt_clk *clk)
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -374,10 +386,14 @@ static void clk_disable(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
||||
clk_disable(clk_np->clk, clk_np->parent);
|
||||
}
|
||||
|
||||
if (clk_np->ops->disable)
|
||||
if (clk->enable_count == 1 && clk_np->ops->disable)
|
||||
{
|
||||
clk_np->ops->disable(clk);
|
||||
}
|
||||
if (clk->enable_count)
|
||||
{
|
||||
--clk->enable_count;
|
||||
}
|
||||
}
|
||||
|
||||
void rt_clk_disable(struct rt_clk *clk)
|
||||
@ -394,7 +410,7 @@ void rt_clk_disable(struct rt_clk *clk)
|
||||
|
||||
rt_err_t rt_clk_prepare_enable(struct rt_clk *clk)
|
||||
{
|
||||
rt_err_t err;
|
||||
rt_err_t err = RT_EOK;
|
||||
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
@ -412,10 +428,6 @@ rt_err_t rt_clk_prepare_enable(struct rt_clk *clk)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -453,10 +465,6 @@ rt_err_t rt_clk_array_prepare(struct rt_clk_array *clk_arr)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -478,10 +486,6 @@ rt_err_t rt_clk_array_unprepare(struct rt_clk_array *clk_arr)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -508,10 +512,6 @@ rt_err_t rt_clk_array_enable(struct rt_clk_array *clk_arr)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -529,29 +529,16 @@ void rt_clk_array_disable(struct rt_clk_array *clk_arr)
|
||||
|
||||
rt_err_t rt_clk_array_prepare_enable(struct rt_clk_array *clk_arr)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
rt_err_t err;
|
||||
|
||||
if (clk_arr)
|
||||
if ((err = rt_clk_array_prepare(clk_arr)))
|
||||
{
|
||||
for (int i = 0; i < clk_arr->count; ++i)
|
||||
{
|
||||
if ((err = rt_clk_prepare_enable(clk_arr->clks[i])))
|
||||
{
|
||||
LOG_E("CLK Array[%d] %s failed error = %s", i,
|
||||
"prepare_enable", rt_strerror(err));
|
||||
|
||||
while (i --> 0)
|
||||
{
|
||||
rt_clk_disable_unprepare(clk_arr->clks[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
else
|
||||
|
||||
if ((err = rt_clk_array_enable(clk_arr)))
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
rt_clk_array_unprepare(clk_arr);
|
||||
}
|
||||
|
||||
return err;
|
||||
@ -559,13 +546,8 @@ rt_err_t rt_clk_array_prepare_enable(struct rt_clk_array *clk_arr)
|
||||
|
||||
void rt_clk_array_disable_unprepare(struct rt_clk_array *clk_arr)
|
||||
{
|
||||
if (clk_arr)
|
||||
{
|
||||
for (int i = 0; i < clk_arr->count; ++i)
|
||||
{
|
||||
rt_clk_disable_unprepare(clk_arr->clks[i]);
|
||||
}
|
||||
}
|
||||
rt_clk_array_disable(clk_arr);
|
||||
rt_clk_array_unprepare(clk_arr);
|
||||
}
|
||||
|
||||
rt_err_t rt_clk_set_rate_range(struct rt_clk *clk, rt_ubase_t min, rt_ubase_t max)
|
||||
@ -604,10 +586,6 @@ rt_err_t rt_clk_set_rate_range(struct rt_clk *clk, rt_ubase_t min, rt_ubase_t ma
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -622,10 +600,6 @@ rt_err_t rt_clk_set_min_rate(struct rt_clk *clk, rt_ubase_t rate)
|
||||
|
||||
err = rt_clk_set_rate_range(clk, rate, clk_np->max_rate);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -640,10 +614,6 @@ rt_err_t rt_clk_set_max_rate(struct rt_clk *clk, rt_ubase_t rate)
|
||||
|
||||
err = rt_clk_set_rate_range(clk, clk_np->min_rate, rate);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -652,7 +622,9 @@ rt_err_t rt_clk_set_rate(struct rt_clk *clk, rt_ubase_t rate)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
|
||||
if (clk && clk->clk_np)
|
||||
rate = rt_clk_round_rate(clk, rate);
|
||||
|
||||
if (clk && clk->clk_np && rate > 0)
|
||||
{
|
||||
struct rt_clk_node *clk_np = clk->clk_np;
|
||||
|
||||
@ -690,17 +662,13 @@ rt_err_t rt_clk_set_rate(struct rt_clk *clk, rt_ubase_t rate)
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_ubase_t rt_clk_get_rate(struct rt_clk *clk)
|
||||
{
|
||||
rt_ubase_t rate = -1UL;
|
||||
rt_ubase_t rate = 0;
|
||||
|
||||
if (clk)
|
||||
{
|
||||
@ -729,10 +697,6 @@ rt_err_t rt_clk_set_phase(struct rt_clk *clk, int degrees)
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -749,38 +713,49 @@ rt_base_t rt_clk_get_phase(struct rt_clk *clk)
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
rt_base_t rt_clk_round_rate(struct rt_clk *clk, rt_ubase_t rate)
|
||||
{
|
||||
rt_base_t res = RT_EOK;
|
||||
rt_base_t res = -RT_EINVAL;
|
||||
|
||||
if (clk && clk->clk_np && clk->clk_np->ops->round_rate)
|
||||
if (clk && clk->clk_np)
|
||||
{
|
||||
rt_ubase_t best_parent_rate;
|
||||
struct rt_clk_node *clk_np = clk->clk_np;
|
||||
|
||||
rt_hw_spin_lock(&_clk_lock.lock);
|
||||
|
||||
if (clk_np->min_rate && clk_np->max_rate)
|
||||
if (clk_np->ops->round_rate)
|
||||
{
|
||||
rate = rt_clamp(rate, clk_np->min_rate, clk_np->max_rate);
|
||||
rt_ubase_t best_parent_rate;
|
||||
|
||||
rt_hw_spin_lock(&_clk_lock.lock);
|
||||
|
||||
if (clk_np->min_rate && clk_np->max_rate)
|
||||
{
|
||||
rate = rt_clamp(rate, clk_np->min_rate, clk_np->max_rate);
|
||||
}
|
||||
|
||||
res = clk_np->ops->round_rate(clk, rate, &best_parent_rate);
|
||||
(void)best_parent_rate;
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rate < clk_np->min_rate)
|
||||
{
|
||||
res = clk_np->min_rate;
|
||||
}
|
||||
else if (rate > clk_np->max_rate)
|
||||
{
|
||||
res = clk_np->max_rate;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = rate;
|
||||
}
|
||||
}
|
||||
|
||||
res = clk->clk_np->ops->round_rate(clk, rate, &best_parent_rate);
|
||||
(void)best_parent_rate;
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return res;
|
||||
@ -798,10 +773,6 @@ rt_err_t rt_clk_set_parent(struct rt_clk *clk, struct rt_clk *clk_parent)
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -887,7 +858,7 @@ void rt_clk_put(struct rt_clk *clk)
|
||||
}
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
static struct rt_clk *ofw_get_clk_no_lock(struct rt_ofw_node *np, int index, const char *name)
|
||||
static struct rt_clk *ofw_get_clk_no_lock(struct rt_ofw_node *np, int index, const char *name, rt_bool_t locked)
|
||||
{
|
||||
struct rt_clk *clk = RT_NULL;
|
||||
struct rt_ofw_cell_args clk_args;
|
||||
@ -895,10 +866,32 @@ static struct rt_clk *ofw_get_clk_no_lock(struct rt_ofw_node *np, int index, con
|
||||
if (!rt_ofw_parse_phandle_cells(np, "clocks", "#clock-cells", index, &clk_args))
|
||||
{
|
||||
int count;
|
||||
struct rt_object *obj;
|
||||
struct rt_clk_node *clk_np = RT_NULL;
|
||||
struct rt_ofw_node *clk_ofw_np = clk_args.data;
|
||||
struct rt_clk_node *clk_np = rt_ofw_data(clk_ofw_np);
|
||||
|
||||
count = rt_ofw_count_of_clk(clk_ofw_np);
|
||||
if (!rt_ofw_data(clk_ofw_np))
|
||||
{
|
||||
if (locked)
|
||||
{
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
|
||||
rt_platform_ofw_request(clk_ofw_np);
|
||||
|
||||
if (locked)
|
||||
{
|
||||
rt_hw_spin_lock(&_clk_lock.lock);
|
||||
}
|
||||
}
|
||||
|
||||
if (rt_ofw_data(clk_ofw_np) && (obj = rt_ofw_parse_object(clk_ofw_np,
|
||||
RT_CLK_NODE_OBJ_NAME, "#clock-cells")))
|
||||
{
|
||||
clk_np = rt_container_of(obj, struct rt_clk_node, rt_parent);
|
||||
|
||||
count = rt_ofw_count_of_clk(clk_ofw_np);
|
||||
}
|
||||
|
||||
rt_ofw_node_put(clk_ofw_np);
|
||||
|
||||
@ -912,6 +905,10 @@ static struct rt_clk *ofw_get_clk_no_lock(struct rt_ofw_node *np, int index, con
|
||||
|
||||
clk = clk_create(clk_np, np->full_name, name, &clk_args, np);
|
||||
}
|
||||
else
|
||||
{
|
||||
clk = rt_err_ptr(-RT_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
return clk;
|
||||
@ -923,7 +920,7 @@ static struct rt_clk *ofw_get_clk(struct rt_ofw_node *np, int index, const char
|
||||
|
||||
rt_hw_spin_lock(&_clk_lock.lock);
|
||||
|
||||
clk = ofw_get_clk_no_lock(np, index, name);
|
||||
clk = ofw_get_clk_no_lock(np, index, name, RT_TRUE);
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
|
||||
@ -935,6 +932,11 @@ struct rt_clk_array *rt_ofw_get_clk_array(struct rt_ofw_node *np)
|
||||
int count;
|
||||
struct rt_clk_array *clk_arr = RT_NULL;
|
||||
|
||||
if (!np)
|
||||
{
|
||||
return rt_err_ptr(-RT_EINVAL);
|
||||
}
|
||||
|
||||
if ((count = rt_ofw_count_phandle_cells(np, "clocks", "#clock-cells")) > 0)
|
||||
{
|
||||
clk_arr = rt_calloc(1, sizeof(*clk_arr) + sizeof(clk_arr->clks[0]) * count);
|
||||
@ -942,6 +944,7 @@ struct rt_clk_array *rt_ofw_get_clk_array(struct rt_ofw_node *np)
|
||||
if (clk_arr)
|
||||
{
|
||||
int i;
|
||||
rt_err_t err = RT_EOK;
|
||||
rt_bool_t has_name = rt_ofw_prop_read_bool(np, "clock-names");
|
||||
|
||||
clk_arr->count = count;
|
||||
@ -957,10 +960,12 @@ struct rt_clk_array *rt_ofw_get_clk_array(struct rt_ofw_node *np)
|
||||
rt_ofw_prop_read_string_index(np, "clock-names", i, &name);
|
||||
}
|
||||
|
||||
clk_arr->clks[i] = ofw_get_clk_no_lock(np, i, name);
|
||||
clk_arr->clks[i] = ofw_get_clk_no_lock(np, i, name, RT_FALSE);
|
||||
|
||||
if (!clk_arr->clks[i])
|
||||
if (rt_is_err(clk_arr->clks[i]))
|
||||
{
|
||||
err = rt_ptr_err(clk_arr->clks[i]);
|
||||
|
||||
--i;
|
||||
break;
|
||||
}
|
||||
@ -971,7 +976,7 @@ struct rt_clk_array *rt_ofw_get_clk_array(struct rt_ofw_node *np)
|
||||
if (i > 0 && i < count)
|
||||
{
|
||||
rt_clk_array_put(clk_arr);
|
||||
clk_arr = RT_NULL;
|
||||
clk_arr = rt_err_ptr(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -360,9 +360,9 @@ rt_err_t rt_bus_remove_device(rt_device_t dev)
|
||||
}
|
||||
else if (drv)
|
||||
{
|
||||
if (drv->shutdown)
|
||||
if (drv->remove)
|
||||
{
|
||||
err = drv->shutdown(dev);
|
||||
err = drv->remove(dev);
|
||||
}
|
||||
|
||||
/* device and driver are in the same bus */
|
||||
|
@ -13,6 +13,8 @@
|
||||
* 2013-07-09 Grissiom add ref_count support
|
||||
* 2016-04-02 Bernard fix the open_flag initialization issue.
|
||||
* 2021-03-19 Meco Man remove rt_device_init_all()
|
||||
* 2024-09-15 milo fix log format issue
|
||||
* fix reopen with a different oflag issue
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
@ -29,9 +31,9 @@
|
||||
#include <rtdevice.h> /* for wqueue_init */
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
|
||||
#ifdef RT_USING_DFS_V2
|
||||
#if defined (RT_USING_DFS_V2) && defined (RT_USING_DFS_DEVFS)
|
||||
#include <devfs.h>
|
||||
#endif /* RT_USING_DFS_V2 */
|
||||
#endif /* RT_USING_DFS_V2 RT_USING_DFS_DEVFS */
|
||||
|
||||
#ifdef RT_USING_DEVICE
|
||||
|
||||
@ -82,7 +84,7 @@ rt_err_t rt_device_register(rt_device_t dev,
|
||||
rt_wqueue_init(&(dev->wait_queue));
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
|
||||
#ifdef RT_USING_DFS_V2
|
||||
#if defined (RT_USING_DFS_V2) && defined (RT_USING_DFS_DEVFS)
|
||||
dfs_devfs_device_add(dev);
|
||||
#endif /* RT_USING_DFS_V2 */
|
||||
|
||||
@ -163,7 +165,7 @@ void rt_device_destroy(rt_device_t dev)
|
||||
{
|
||||
/* parameter check */
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
|
||||
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Null);
|
||||
RT_ASSERT(rt_object_is_systemobject(&dev->parent) == RT_FALSE);
|
||||
|
||||
rt_object_detach(&(dev->parent));
|
||||
@ -195,8 +197,8 @@ rt_err_t rt_device_init(rt_device_t dev)
|
||||
result = device_init(dev);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
LOG_E("To initialize device:%s failed. The error code is %d",
|
||||
dev->parent.name, result);
|
||||
LOG_E("To initialize device:%.*s failed. The error code is %d",
|
||||
RT_NAME_MAX, dev->parent.name, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -233,8 +235,8 @@ rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
result = device_init(dev);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
LOG_E("To initialize device:%s failed. The error code is %d",
|
||||
dev->parent.name, result);
|
||||
LOG_E("To initialize device:%.*s failed. The error code is %d",
|
||||
RT_NAME_MAX, dev->parent.name, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -252,7 +254,7 @@ rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag)
|
||||
|
||||
/* device is not opened or opened by other oflag, call device_open interface */
|
||||
if (!(dev->open_flag & RT_DEVICE_OFLAG_OPEN) ||
|
||||
((dev->open_flag & RT_DEVICE_OFLAG_MASK) != (oflag & RT_DEVICE_OFLAG_MASK)))
|
||||
((dev->open_flag & RT_DEVICE_OFLAG_MASK) != ((oflag & RT_DEVICE_OFLAG_MASK) | RT_DEVICE_OFLAG_OPEN)))
|
||||
{
|
||||
if (device_open != RT_NULL)
|
||||
{
|
||||
|
@ -53,6 +53,137 @@ void rt_dm_secondary_cpu_init(void)
|
||||
}
|
||||
#endif /* RT_USING_SMP */
|
||||
|
||||
/**
|
||||
* @brief This function will alloc an id in an IDA object
|
||||
*
|
||||
* @param ida is the IDA object
|
||||
*
|
||||
* @return the id or -RT_EEMPTY
|
||||
*/
|
||||
int rt_dm_ida_alloc(struct rt_dm_ida *ida)
|
||||
{
|
||||
int id;
|
||||
RT_ASSERT(ida != RT_NULL);
|
||||
|
||||
rt_spin_lock(&ida->lock);
|
||||
|
||||
id = rt_bitmap_next_clear_bit(ida->map, 0, RT_DM_IDA_NUM);
|
||||
|
||||
if (id != RT_DM_IDA_NUM)
|
||||
{
|
||||
rt_bitmap_set_bit(ida->map, id);
|
||||
}
|
||||
|
||||
rt_spin_unlock(&ida->lock);
|
||||
|
||||
if (id != RT_DM_IDA_NUM)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
return -RT_EEMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will take (force) an id in an IDA object
|
||||
*
|
||||
* @param ida is the IDA object
|
||||
*
|
||||
* @param id is the id that want to take
|
||||
*
|
||||
* @return the result of taking
|
||||
*/
|
||||
rt_bool_t rt_dm_ida_take(struct rt_dm_ida *ida, int id)
|
||||
{
|
||||
RT_ASSERT(ida != RT_NULL);
|
||||
RT_ASSERT(id >= 0);
|
||||
|
||||
rt_spin_lock(&ida->lock);
|
||||
|
||||
if (!rt_bitmap_test_bit(ida->map, id))
|
||||
{
|
||||
rt_bitmap_set_bit(ida->map, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
id = RT_DM_IDA_NUM;
|
||||
}
|
||||
|
||||
rt_spin_unlock(&ida->lock);
|
||||
|
||||
return id != RT_DM_IDA_NUM;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will release an id in an IDA object
|
||||
*
|
||||
* @param ida is the IDA object
|
||||
*
|
||||
* @param id is the id of IDA object
|
||||
*/
|
||||
void rt_dm_ida_free(struct rt_dm_ida *ida, int id)
|
||||
{
|
||||
RT_ASSERT(ida != RT_NULL);
|
||||
RT_ASSERT(id >= 0);
|
||||
|
||||
rt_spin_lock(&ida->lock);
|
||||
|
||||
rt_bitmap_clear_bit(ida->map, id);
|
||||
|
||||
rt_spin_unlock(&ida->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will return the specified master id and device id of device.
|
||||
*
|
||||
* @param master_id is the master id (0, 255] of device
|
||||
*
|
||||
* @param device_id is the device id [-1, 255] of device, when device_id is -1,
|
||||
* the function will end when find the first device.
|
||||
*
|
||||
* @return the device object or RT_NULL
|
||||
*/
|
||||
rt_device_t rt_dm_device_find(int master_id, int device_id)
|
||||
{
|
||||
struct rt_device *dev, *ret_dev = RT_NULL;
|
||||
struct rt_object_information *information = RT_NULL;
|
||||
|
||||
if (master_id <= 0 || device_id > 255)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
information = rt_object_get_information(RT_Object_Class_Device);
|
||||
|
||||
/* parameter check */
|
||||
if (!information)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/* which is invoke in interrupt status */
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
/* enter critical */
|
||||
rt_enter_critical();
|
||||
|
||||
/* try to find object */
|
||||
rt_list_for_each_entry(dev, &information->object_list, parent.list)
|
||||
{
|
||||
if (master_id == dev->master_id &&
|
||||
(device_id == -1 || device_id == dev->device_id))
|
||||
{
|
||||
ret_dev = dev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* leave critical */
|
||||
rt_exit_critical();
|
||||
|
||||
return ret_dev;
|
||||
}
|
||||
|
||||
struct prefix_track
|
||||
{
|
||||
rt_list_t list;
|
||||
|
@ -78,21 +78,21 @@ static rt_bool_t platform_match(rt_driver_t drv, rt_device_t dev)
|
||||
{
|
||||
struct rt_platform_driver *pdrv = rt_container_of(drv, struct rt_platform_driver, parent);
|
||||
struct rt_platform_device *pdev = rt_container_of(dev, struct rt_platform_device, parent);
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
struct rt_ofw_node *np = dev->ofw_node;
|
||||
|
||||
/* 1、match with ofw node */
|
||||
if (np)
|
||||
{
|
||||
#ifdef RT_USING_OFW
|
||||
pdev->id = rt_ofw_node_match(np, pdrv->ids);
|
||||
|
||||
#else
|
||||
pdev->id = RT_NULL;
|
||||
#endif
|
||||
if (pdev->id)
|
||||
{
|
||||
return RT_TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 2、match with name */
|
||||
if (pdev->name && pdrv->name)
|
||||
@ -123,7 +123,13 @@ static rt_err_t platform_probe(rt_device_t dev)
|
||||
|
||||
if (err && err != -RT_EEMPTY)
|
||||
{
|
||||
LOG_E("Attach power domain error = %s in device %s", pdev->name, rt_strerror(err));
|
||||
LOG_E("Attach power domain error = %s in device %s", rt_strerror(err),
|
||||
#ifdef RT_USING_OFW
|
||||
(pdev->name && pdev->name[0]) ? pdev->name : rt_ofw_node_full_name(np)
|
||||
#else
|
||||
pdev->name
|
||||
#endif
|
||||
);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <drivers/ofw_io.h>
|
||||
#include <drivers/ofw_fdt.h>
|
||||
#include <drivers/platform.h>
|
||||
#include <drivers/core/bus.h>
|
||||
#include <drivers/core/dm.h>
|
||||
|
||||
#include "../ofw/ofw_internal.h"
|
||||
@ -161,6 +162,7 @@ static rt_err_t platform_ofw_device_probe_once(struct rt_ofw_node *parent_np)
|
||||
}
|
||||
|
||||
pdev->dev_id = ofw_alias_node_id(np);
|
||||
np->dev = &pdev->parent;
|
||||
LOG_D("%s register to bus", np->full_name);
|
||||
|
||||
rt_platform_device_register(pdev);
|
||||
@ -199,6 +201,53 @@ rt_err_t rt_platform_ofw_device_probe_child(struct rt_ofw_node *np)
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_err_t rt_platform_ofw_request(struct rt_ofw_node *np)
|
||||
{
|
||||
rt_err_t err;
|
||||
|
||||
if (np)
|
||||
{
|
||||
struct rt_device *dev = np->dev;
|
||||
|
||||
if (dev)
|
||||
{
|
||||
/* Was create */
|
||||
if (dev->drv)
|
||||
{
|
||||
/* Was probe OK */
|
||||
err = RT_EOK;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = rt_bus_reload_driver_device(dev->bus, dev);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct rt_platform_device *pdev = alloc_ofw_platform_device(np);
|
||||
|
||||
if (pdev)
|
||||
{
|
||||
pdev->dev_id = ofw_alias_node_id(np);
|
||||
np->dev = &pdev->parent;
|
||||
LOG_D("%s register to bus", np->full_name);
|
||||
|
||||
err = rt_platform_device_register(pdev);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int platform_ofw_device_probe(void)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
@ -206,6 +255,8 @@ static int platform_ofw_device_probe(void)
|
||||
|
||||
if (ofw_node_root)
|
||||
{
|
||||
rt_ofw_node_get(ofw_node_root);
|
||||
|
||||
err = platform_ofw_device_probe_once(ofw_node_root);
|
||||
|
||||
rt_ofw_node_put(ofw_node_root);
|
||||
@ -216,11 +267,19 @@ static int platform_ofw_device_probe(void)
|
||||
rt_ofw_node_put(node);
|
||||
}
|
||||
|
||||
if ((node = rt_ofw_find_node_by_path("/clocks")))
|
||||
{
|
||||
platform_ofw_device_probe_once(node);
|
||||
rt_ofw_node_put(node);
|
||||
}
|
||||
|
||||
rt_ofw_node_get(ofw_node_chosen);
|
||||
if ((node = rt_ofw_get_child_by_compatible(ofw_node_chosen, "simple-framebuffer")))
|
||||
{
|
||||
platform_ofw_device_probe_once(node);
|
||||
rt_ofw_node_put(node);
|
||||
}
|
||||
rt_ofw_node_get(ofw_node_chosen);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -244,7 +303,7 @@ rt_err_t rt_platform_ofw_free(struct rt_platform_device *pdev)
|
||||
rt_ofw_node_clear_flag(np, RT_OFW_F_PLATFORM);
|
||||
rt_ofw_node_put(np);
|
||||
|
||||
pdev->parent.ofw_node = RT_NULL;
|
||||
rt_free(pdev);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
10
rt-thread/components/drivers/dma/Kconfig
Normal file
10
rt-thread/components/drivers/dma/Kconfig
Normal file
@ -0,0 +1,10 @@
|
||||
menuconfig RT_USING_DMA
|
||||
bool "Using Direct Memory Access (DMA)"
|
||||
depends on RT_USING_DM
|
||||
select RT_USING_ADT
|
||||
select RT_USING_ADT_BITMAP
|
||||
default n
|
||||
|
||||
if RT_USING_DMA
|
||||
osource "$(SOC_DM_DMA_DIR)/Kconfig"
|
||||
endif
|
15
rt-thread/components/drivers/dma/SConscript
Normal file
15
rt-thread/components/drivers/dma/SConscript
Normal file
@ -0,0 +1,15 @@
|
||||
from building import *
|
||||
|
||||
group = []
|
||||
|
||||
if not GetDepend(['RT_USING_DMA']):
|
||||
Return('group')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd + '/../include']
|
||||
|
||||
src = ['dma.c', 'dma_pool.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
589
rt-thread/components/drivers/dma/dma.c
Normal file
589
rt-thread/components/drivers/dma/dma.c
Normal file
@ -0,0 +1,589 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "rtdm.dma"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
static rt_list_t dmac_nodes = RT_LIST_OBJECT_INIT(dmac_nodes);
|
||||
static struct rt_spinlock dmac_nodes_lock = {};
|
||||
|
||||
rt_err_t rt_dma_controller_register(struct rt_dma_controller *ctrl)
|
||||
{
|
||||
const char *dev_name;
|
||||
char dma_name[RT_NAME_MAX];
|
||||
|
||||
if (!ctrl || !ctrl->dev || !ctrl->ops)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
dev_name = rt_dm_dev_get_name(ctrl->dev);
|
||||
|
||||
if (rt_bitmap_next_set_bit(ctrl->dir_cap, 0, RT_DMA_DIR_MAX) == RT_DMA_DIR_MAX)
|
||||
{
|
||||
LOG_E("%s: Not direction capability", dev_name);
|
||||
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
rt_snprintf(dma_name, sizeof(dma_name), "%s-dmac", dev_name);
|
||||
|
||||
rt_list_init(&ctrl->list);
|
||||
|
||||
rt_spin_lock(&dmac_nodes_lock);
|
||||
rt_list_insert_before(&dmac_nodes, &ctrl->list);
|
||||
rt_spin_unlock(&dmac_nodes_lock);
|
||||
|
||||
rt_list_init(&ctrl->channels_nodes);
|
||||
rt_mutex_init(&ctrl->mutex, dma_name, RT_IPC_FLAG_PRIO);
|
||||
|
||||
if (ctrl->dev->ofw_node)
|
||||
{
|
||||
rt_dm_dev_bind_fwdata(ctrl->dev, RT_NULL, ctrl);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t rt_dma_controller_unregister(struct rt_dma_controller *ctrl)
|
||||
{
|
||||
if (!ctrl)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
rt_mutex_take(&ctrl->mutex, RT_WAITING_FOREVER);
|
||||
|
||||
if (!rt_list_isempty(&ctrl->channels_nodes))
|
||||
{
|
||||
rt_mutex_release(&ctrl->mutex);
|
||||
return -RT_EBUSY;
|
||||
}
|
||||
|
||||
if (ctrl->dev->ofw_node)
|
||||
{
|
||||
rt_dm_dev_unbind_fwdata(ctrl->dev, RT_NULL);
|
||||
}
|
||||
|
||||
rt_mutex_release(&ctrl->mutex);
|
||||
rt_mutex_detach(&ctrl->mutex);
|
||||
|
||||
rt_spin_lock(&dmac_nodes_lock);
|
||||
rt_list_remove(&ctrl->list);
|
||||
rt_spin_unlock(&dmac_nodes_lock);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
rt_err_t rt_dma_chan_start(struct rt_dma_chan *chan)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_dma_controller *ctrl;
|
||||
|
||||
if (!chan)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (chan->prep_err)
|
||||
{
|
||||
LOG_D("%s: Not config done", rt_dm_dev_get_name(chan->slave));
|
||||
|
||||
return chan->prep_err;
|
||||
}
|
||||
|
||||
ctrl = chan->ctrl;
|
||||
|
||||
rt_mutex_take(&ctrl->mutex, RT_WAITING_FOREVER);
|
||||
|
||||
err = ctrl->ops->start(chan);
|
||||
|
||||
rt_mutex_release(&ctrl->mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_err_t rt_dma_chan_stop(struct rt_dma_chan *chan)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_dma_controller *ctrl;
|
||||
|
||||
if (!chan)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (chan->prep_err)
|
||||
{
|
||||
LOG_D("%s: Not prepare done", rt_dm_dev_get_name(chan->slave));
|
||||
|
||||
return chan->prep_err;
|
||||
}
|
||||
|
||||
ctrl = chan->ctrl;
|
||||
|
||||
rt_mutex_take(&ctrl->mutex, RT_WAITING_FOREVER);
|
||||
|
||||
err = ctrl->ops->stop(chan);
|
||||
|
||||
rt_mutex_release(&ctrl->mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_err_t rt_dma_chan_config(struct rt_dma_chan *chan,
|
||||
struct rt_dma_slave_config *conf)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_dma_controller *ctrl;
|
||||
enum rt_dma_transfer_direction dir;
|
||||
|
||||
if (!chan || !conf)
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
goto _end;
|
||||
}
|
||||
|
||||
dir = conf->direction;
|
||||
|
||||
if (dir >= RT_DMA_DIR_MAX)
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
goto _end;
|
||||
}
|
||||
|
||||
if (conf->src_addr_width >= RT_DMA_SLAVE_BUSWIDTH_BYTES_MAX ||
|
||||
conf->dst_addr_width >= RT_DMA_SLAVE_BUSWIDTH_BYTES_MAX)
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
goto _end;
|
||||
}
|
||||
|
||||
ctrl = chan->ctrl;
|
||||
|
||||
if (!rt_bitmap_test_bit(ctrl->dir_cap, dir))
|
||||
{
|
||||
err = -RT_ENOSYS;
|
||||
goto _end;
|
||||
}
|
||||
|
||||
if (!chan->name && dir != RT_DMA_MEM_TO_MEM)
|
||||
{
|
||||
LOG_E("%s: illegal config for uname channels",
|
||||
rt_dm_dev_get_name(ctrl->dev));
|
||||
|
||||
err = -RT_EINVAL;
|
||||
goto _end;
|
||||
}
|
||||
|
||||
rt_mutex_take(&ctrl->mutex, RT_WAITING_FOREVER);
|
||||
|
||||
err = ctrl->ops->config(chan, conf);
|
||||
|
||||
rt_mutex_release(&ctrl->mutex);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
rt_memcpy(&chan->conf, conf, sizeof(*conf));
|
||||
}
|
||||
|
||||
_end:
|
||||
chan->conf_err = err;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_err_t rt_dma_chan_done(struct rt_dma_chan *chan, rt_size_t size)
|
||||
{
|
||||
if (!chan)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (chan->callback)
|
||||
{
|
||||
chan->callback(chan, size);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_bool_t range_is_illegal(const char *name, const char *desc,
|
||||
rt_ubase_t addr0, rt_ubase_t addr1)
|
||||
{
|
||||
rt_bool_t illegal = addr0 < addr1;
|
||||
|
||||
if (illegal)
|
||||
{
|
||||
LOG_E("%s: %s %p is out of config %p", name, desc, addr0, addr1);
|
||||
}
|
||||
|
||||
return illegal;
|
||||
}
|
||||
|
||||
rt_err_t rt_dma_prep_memcpy(struct rt_dma_chan *chan,
|
||||
struct rt_dma_slave_transfer *transfer)
|
||||
{
|
||||
rt_err_t err;
|
||||
rt_size_t len;
|
||||
rt_ubase_t dma_addr_src, dma_addr_dst;
|
||||
struct rt_dma_controller *ctrl;
|
||||
struct rt_dma_slave_config *conf;
|
||||
|
||||
if (!chan || !transfer)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
ctrl = chan->ctrl;
|
||||
conf = &chan->conf;
|
||||
|
||||
if (chan->conf_err)
|
||||
{
|
||||
LOG_D("%s: Not config done", rt_dm_dev_get_name(chan->slave));
|
||||
|
||||
return chan->conf_err;
|
||||
}
|
||||
|
||||
RT_ASSERT(chan->conf.direction == RT_DMA_MEM_TO_MEM);
|
||||
dma_addr_src = transfer->src_addr;
|
||||
dma_addr_dst = transfer->dst_addr;
|
||||
len = transfer->buffer_len;
|
||||
|
||||
if (range_is_illegal(rt_dm_dev_get_name(ctrl->dev), "source",
|
||||
dma_addr_src, conf->src_addr))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (range_is_illegal(rt_dm_dev_get_name(ctrl->dev), "dest",
|
||||
dma_addr_dst, conf->dst_addr))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (ctrl->ops->prep_memcpy)
|
||||
{
|
||||
rt_mutex_take(&ctrl->mutex, RT_WAITING_FOREVER);
|
||||
|
||||
err = ctrl->ops->prep_memcpy(chan, dma_addr_dst, dma_addr_src, len);
|
||||
|
||||
rt_mutex_release(&ctrl->mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_ENOSYS;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
rt_memcpy(&chan->transfer, transfer, sizeof(*transfer));
|
||||
}
|
||||
|
||||
chan->prep_err = err;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_err_t rt_dma_prep_cyclic(struct rt_dma_chan *chan,
|
||||
struct rt_dma_slave_transfer *transfer)
|
||||
{
|
||||
rt_err_t err;
|
||||
rt_ubase_t dma_buf_addr;
|
||||
struct rt_dma_controller *ctrl;
|
||||
struct rt_dma_slave_config *conf;
|
||||
enum rt_dma_transfer_direction dir;
|
||||
|
||||
if (!chan || !transfer)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
ctrl = chan->ctrl;
|
||||
conf = &chan->conf;
|
||||
|
||||
if (chan->conf_err)
|
||||
{
|
||||
LOG_D("%s: Not config done", rt_dm_dev_get_name(chan->slave));
|
||||
|
||||
return chan->conf_err;
|
||||
}
|
||||
|
||||
dir = chan->conf.direction;
|
||||
|
||||
if (dir == RT_DMA_MEM_TO_DEV || dir == RT_DMA_MEM_TO_MEM)
|
||||
{
|
||||
dma_buf_addr = transfer->src_addr;
|
||||
|
||||
if (range_is_illegal(rt_dm_dev_get_name(ctrl->dev), "source",
|
||||
dma_buf_addr, conf->src_addr))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
}
|
||||
else if (dir == RT_DMA_DEV_TO_MEM)
|
||||
{
|
||||
dma_buf_addr = transfer->dst_addr;
|
||||
|
||||
if (range_is_illegal(rt_dm_dev_get_name(ctrl->dev), "dest",
|
||||
dma_buf_addr, conf->dst_addr))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dma_buf_addr = ~0UL;
|
||||
}
|
||||
|
||||
if (ctrl->ops->prep_cyclic)
|
||||
{
|
||||
rt_mutex_take(&ctrl->mutex, RT_WAITING_FOREVER);
|
||||
|
||||
err = ctrl->ops->prep_cyclic(chan, dma_buf_addr,
|
||||
transfer->buffer_len, transfer->period_len, dir);
|
||||
|
||||
rt_mutex_release(&ctrl->mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_ENOSYS;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
rt_memcpy(&chan->transfer, transfer, sizeof(*transfer));
|
||||
}
|
||||
|
||||
chan->prep_err = err;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_err_t rt_dma_prep_single(struct rt_dma_chan *chan,
|
||||
struct rt_dma_slave_transfer *transfer)
|
||||
{
|
||||
rt_err_t err;
|
||||
rt_ubase_t dma_buf_addr;
|
||||
struct rt_dma_controller *ctrl;
|
||||
struct rt_dma_slave_config *conf;
|
||||
enum rt_dma_transfer_direction dir;
|
||||
|
||||
if (!chan || !transfer)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
ctrl = chan->ctrl;
|
||||
conf = &chan->conf;
|
||||
|
||||
if (chan->conf_err)
|
||||
{
|
||||
LOG_D("%s: Not config done", rt_dm_dev_get_name(chan->slave));
|
||||
|
||||
return chan->conf_err;
|
||||
}
|
||||
|
||||
dir = chan->conf.direction;
|
||||
|
||||
if (dir == RT_DMA_MEM_TO_DEV || dir == RT_DMA_MEM_TO_MEM)
|
||||
{
|
||||
dma_buf_addr = transfer->src_addr;
|
||||
|
||||
if (range_is_illegal(rt_dm_dev_get_name(ctrl->dev), "source",
|
||||
dma_buf_addr, conf->src_addr))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
}
|
||||
else if (dir == RT_DMA_DEV_TO_MEM)
|
||||
{
|
||||
dma_buf_addr = transfer->dst_addr;
|
||||
|
||||
if (range_is_illegal(rt_dm_dev_get_name(ctrl->dev), "dest",
|
||||
dma_buf_addr, conf->dst_addr))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dma_buf_addr = ~0UL;
|
||||
}
|
||||
|
||||
if (ctrl->ops->prep_single)
|
||||
{
|
||||
rt_mutex_take(&ctrl->mutex, RT_WAITING_FOREVER);
|
||||
|
||||
err = ctrl->ops->prep_single(chan, dma_buf_addr,
|
||||
transfer->buffer_len, dir);
|
||||
|
||||
rt_mutex_release(&ctrl->mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_ENOSYS;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
rt_memcpy(&chan->transfer, transfer, sizeof(*transfer));
|
||||
}
|
||||
|
||||
chan->prep_err = err;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct rt_dma_controller *ofw_find_dma_controller(struct rt_device *dev,
|
||||
const char *name, struct rt_ofw_cell_args *args)
|
||||
{
|
||||
struct rt_dma_controller *ctrl = RT_NULL;
|
||||
#ifdef RT_USING_OFW
|
||||
int index;
|
||||
struct rt_ofw_node *np = dev->ofw_node, *ctrl_np;
|
||||
|
||||
if (!np)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
index = rt_ofw_prop_index_of_string(np, "dma-names", name);
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
if (!rt_ofw_parse_phandle_cells(np, "dmas", "#dma-cells", index, args))
|
||||
{
|
||||
ctrl_np = args->data;
|
||||
|
||||
if (!rt_ofw_data(ctrl_np))
|
||||
{
|
||||
rt_platform_ofw_request(ctrl_np);
|
||||
}
|
||||
|
||||
ctrl = rt_ofw_data(ctrl_np);
|
||||
rt_ofw_node_put(ctrl_np);
|
||||
}
|
||||
#endif /* RT_USING_OFW */
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
struct rt_dma_chan *rt_dma_chan_request(struct rt_device *dev, const char *name)
|
||||
{
|
||||
void *fw_data = RT_NULL;
|
||||
struct rt_dma_chan *chan;
|
||||
struct rt_ofw_cell_args dma_args;
|
||||
struct rt_dma_controller *ctrl = RT_NULL;
|
||||
|
||||
if (!dev)
|
||||
{
|
||||
return rt_err_ptr(-RT_EINVAL);
|
||||
}
|
||||
|
||||
if (name)
|
||||
{
|
||||
fw_data = &dma_args;
|
||||
ctrl = ofw_find_dma_controller(dev, name, &dma_args);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct rt_dma_controller *ctrl_tmp;
|
||||
|
||||
rt_spin_lock(&dmac_nodes_lock);
|
||||
rt_list_for_each_entry(ctrl_tmp, &dmac_nodes, list)
|
||||
{
|
||||
/* Only memory to memory for uname request */
|
||||
if (rt_bitmap_test_bit(ctrl_tmp->dir_cap, RT_DMA_MEM_TO_MEM))
|
||||
{
|
||||
ctrl = ctrl_tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rt_spin_unlock(&dmac_nodes_lock);
|
||||
}
|
||||
|
||||
if (rt_is_err_or_null(ctrl))
|
||||
{
|
||||
return ctrl ? ctrl : rt_err_ptr(-RT_ENOSYS);
|
||||
}
|
||||
|
||||
if (ctrl->ops->request_chan)
|
||||
{
|
||||
chan = ctrl->ops->request_chan(ctrl, dev, fw_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
chan = rt_calloc(1, sizeof(*chan));
|
||||
|
||||
if (!chan)
|
||||
{
|
||||
chan = rt_err_ptr(-RT_ENOMEM);
|
||||
}
|
||||
}
|
||||
|
||||
if (rt_is_err(chan))
|
||||
{
|
||||
return chan;
|
||||
}
|
||||
|
||||
if (!chan)
|
||||
{
|
||||
LOG_E("%s: unset request channels error", rt_dm_dev_get_name(ctrl->dev));
|
||||
|
||||
return rt_err_ptr(-RT_ERROR);
|
||||
}
|
||||
|
||||
chan->name = name;
|
||||
chan->ctrl = ctrl;
|
||||
chan->slave = dev;
|
||||
|
||||
rt_list_init(&chan->list);
|
||||
chan->conf_err = -RT_ERROR;
|
||||
chan->prep_err = -RT_ERROR;
|
||||
|
||||
rt_mutex_take(&ctrl->mutex, RT_WAITING_FOREVER);
|
||||
rt_list_insert_before(&ctrl->channels_nodes, &chan->list);
|
||||
rt_mutex_release(&ctrl->mutex);
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
rt_err_t rt_dma_chan_release(struct rt_dma_chan *chan)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
|
||||
if (!chan)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
rt_mutex_take(&chan->ctrl->mutex, RT_WAITING_FOREVER);
|
||||
rt_list_remove(&chan->list);
|
||||
rt_mutex_release(&chan->ctrl->mutex);
|
||||
|
||||
if (chan->ctrl->ops->release_chan)
|
||||
{
|
||||
err = chan->ctrl->ops->release_chan(chan);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_free(chan);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
691
rt-thread/components/drivers/dma/dma_pool.c
Normal file
691
rt-thread/components/drivers/dma/dma_pool.c
Normal file
@ -0,0 +1,691 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-02-25 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "dma.pool"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <mm_aspace.h>
|
||||
#include <dt-bindings/size.h>
|
||||
|
||||
static struct rt_spinlock dma_pools_lock = {};
|
||||
static rt_list_t dma_pool_nodes = RT_LIST_OBJECT_INIT(dma_pool_nodes);
|
||||
|
||||
static struct rt_dma_pool *dma_pool_install(rt_region_t *region);
|
||||
|
||||
static void *dma_alloc(struct rt_device *dev, rt_size_t size,
|
||||
rt_ubase_t *dma_handle, rt_ubase_t flags);
|
||||
static void dma_free(struct rt_device *dev, rt_size_t size,
|
||||
void *cpu_addr, rt_ubase_t dma_handle, rt_ubase_t flags);
|
||||
|
||||
rt_inline void region_pool_lock(void)
|
||||
{
|
||||
rt_hw_spin_lock(&dma_pools_lock.lock);
|
||||
}
|
||||
|
||||
rt_inline void region_pool_unlock(void)
|
||||
{
|
||||
rt_hw_spin_unlock(&dma_pools_lock.lock);
|
||||
}
|
||||
|
||||
static rt_err_t dma_map_coherent_sync_out_data(struct rt_device *dev,
|
||||
void *data, rt_size_t size, rt_ubase_t *dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
if (dma_handle)
|
||||
{
|
||||
*dma_handle = (rt_ubase_t)rt_kmem_v2p(data);
|
||||
}
|
||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, data, size);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t dma_map_coherent_sync_in_data(struct rt_device *dev,
|
||||
void *out_data, rt_size_t size, rt_ubase_t dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, out_data, size);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_dma_map_ops dma_map_coherent_ops =
|
||||
{
|
||||
.sync_out_data = dma_map_coherent_sync_out_data,
|
||||
.sync_in_data = dma_map_coherent_sync_in_data,
|
||||
};
|
||||
|
||||
static rt_err_t dma_map_nocoherent_sync_out_data(struct rt_device *dev,
|
||||
void *data, rt_size_t size, rt_ubase_t *dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
if (dma_handle)
|
||||
{
|
||||
*dma_handle = (rt_ubase_t)rt_kmem_v2p(data);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t dma_map_nocoherent_sync_in_data(struct rt_device *dev,
|
||||
void *out_data, rt_size_t size, rt_ubase_t dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_dma_map_ops dma_map_nocoherent_ops =
|
||||
{
|
||||
.sync_out_data = dma_map_nocoherent_sync_out_data,
|
||||
.sync_in_data = dma_map_nocoherent_sync_in_data,
|
||||
};
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
rt_inline rt_ubase_t ofw_addr_cpu2dma(struct rt_device *dev, rt_ubase_t addr)
|
||||
{
|
||||
return (rt_ubase_t)rt_ofw_translate_cpu2dma(dev->ofw_node, addr);
|
||||
}
|
||||
|
||||
rt_inline rt_ubase_t ofw_addr_dma2cpu(struct rt_device *dev, rt_ubase_t addr)
|
||||
{
|
||||
return (rt_ubase_t)rt_ofw_translate_dma2cpu(dev->ofw_node, addr);
|
||||
}
|
||||
|
||||
static void *ofw_dma_map_alloc(struct rt_device *dev, rt_size_t size,
|
||||
rt_ubase_t *dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
void *cpu_addr = dma_alloc(dev, size, dma_handle, flags);
|
||||
|
||||
if (cpu_addr && dma_handle)
|
||||
{
|
||||
*dma_handle = ofw_addr_cpu2dma(dev, *dma_handle);
|
||||
}
|
||||
|
||||
return cpu_addr;
|
||||
}
|
||||
|
||||
static void ofw_dma_map_free(struct rt_device *dev, rt_size_t size,
|
||||
void *cpu_addr, rt_ubase_t dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
dma_handle = ofw_addr_dma2cpu(dev, dma_handle);
|
||||
|
||||
dma_free(dev, size, cpu_addr, dma_handle, flags);
|
||||
}
|
||||
|
||||
static rt_err_t ofw_dma_map_sync_out_data(struct rt_device *dev,
|
||||
void *data, rt_size_t size,
|
||||
rt_ubase_t *dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
rt_err_t err;
|
||||
|
||||
if (flags & RT_DMA_F_NOCACHE)
|
||||
{
|
||||
err = dma_map_nocoherent_sync_out_data(dev, data, size, dma_handle, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = dma_map_coherent_sync_out_data(dev, data, size, dma_handle, flags);
|
||||
}
|
||||
|
||||
if (!err && dma_handle)
|
||||
{
|
||||
*dma_handle = ofw_addr_cpu2dma(dev, *dma_handle);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static rt_err_t ofw_dma_map_sync_in_data(struct rt_device *dev,
|
||||
void *out_data, rt_size_t size,
|
||||
rt_ubase_t dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
dma_handle = ofw_addr_dma2cpu(dev, dma_handle);
|
||||
|
||||
if (flags & RT_DMA_F_NOCACHE)
|
||||
{
|
||||
return dma_map_nocoherent_sync_in_data(dev, out_data, size, dma_handle, flags);
|
||||
}
|
||||
|
||||
return dma_map_coherent_sync_in_data(dev, out_data, size, dma_handle, flags);
|
||||
}
|
||||
|
||||
static const struct rt_dma_map_ops ofw_dma_map_ops =
|
||||
{
|
||||
.alloc = ofw_dma_map_alloc,
|
||||
.free = ofw_dma_map_free,
|
||||
.sync_out_data = ofw_dma_map_sync_out_data,
|
||||
.sync_in_data = ofw_dma_map_sync_in_data,
|
||||
};
|
||||
|
||||
static const struct rt_dma_map_ops *ofw_device_dma_ops(struct rt_device *dev)
|
||||
{
|
||||
rt_err_t err;
|
||||
int region_nr = 0;
|
||||
const fdt32_t *cell;
|
||||
rt_phandle phandle;
|
||||
rt_region_t region;
|
||||
struct rt_ofw_prop *prop;
|
||||
struct rt_dma_pool *dma_pool;
|
||||
const struct rt_dma_map_ops *ops = RT_NULL;
|
||||
struct rt_ofw_node *mem_np, *np = dev->ofw_node;
|
||||
|
||||
rt_ofw_foreach_prop_u32(np, "memory-region", prop, cell, phandle)
|
||||
{
|
||||
rt_uint64_t addr, size;
|
||||
|
||||
if (!(mem_np = rt_ofw_find_node_by_phandle(phandle)))
|
||||
{
|
||||
if (region_nr == 0)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((err = rt_ofw_get_address(mem_np, 0, &addr, &size)))
|
||||
{
|
||||
LOG_E("%s: Read '%s' error = %s", rt_ofw_node_full_name(mem_np),
|
||||
"memory-region", rt_strerror(err));
|
||||
|
||||
rt_ofw_node_put(mem_np);
|
||||
continue;
|
||||
}
|
||||
|
||||
region.start = addr;
|
||||
region.end = addr + size;
|
||||
region.name = rt_dm_dev_get_name(dev);
|
||||
|
||||
rt_ofw_node_put(mem_np);
|
||||
|
||||
if (!(dma_pool = dma_pool_install(®ion)))
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
if (rt_ofw_prop_read_bool(mem_np, "no-map"))
|
||||
{
|
||||
dma_pool->flags |= RT_DMA_F_NOMAP;
|
||||
}
|
||||
|
||||
if (!rt_dma_device_is_coherent(dev))
|
||||
{
|
||||
dma_pool->flags |= RT_DMA_F_NOCACHE;
|
||||
}
|
||||
|
||||
dma_pool->dev = dev;
|
||||
++region_nr;
|
||||
}
|
||||
|
||||
if (region_nr)
|
||||
{
|
||||
ops = &ofw_dma_map_ops;
|
||||
}
|
||||
|
||||
return ops;
|
||||
}
|
||||
#endif /* RT_USING_OFW */
|
||||
|
||||
static const struct rt_dma_map_ops *device_dma_ops(struct rt_device *dev)
|
||||
{
|
||||
const struct rt_dma_map_ops *ops = dev->dma_ops;
|
||||
|
||||
if (ops)
|
||||
{
|
||||
return ops;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_OFW
|
||||
if (dev->ofw_node && (ops = ofw_device_dma_ops(dev)))
|
||||
{
|
||||
return ops;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rt_dma_device_is_coherent(dev))
|
||||
{
|
||||
ops = &dma_map_coherent_ops;
|
||||
}
|
||||
else
|
||||
{
|
||||
ops = &dma_map_nocoherent_ops;
|
||||
}
|
||||
|
||||
dev->dma_ops = ops;
|
||||
|
||||
return ops;
|
||||
}
|
||||
|
||||
static rt_ubase_t dma_pool_alloc(struct rt_dma_pool *pool, rt_size_t size)
|
||||
{
|
||||
rt_size_t bit, next_bit, end_bit, max_bits;
|
||||
|
||||
size = RT_DIV_ROUND_UP(size, ARCH_PAGE_SIZE);
|
||||
max_bits = pool->bits - size;
|
||||
|
||||
rt_bitmap_for_each_clear_bit(pool->map, bit, max_bits)
|
||||
{
|
||||
end_bit = bit + size;
|
||||
|
||||
for (next_bit = bit + 1; next_bit < end_bit; ++next_bit)
|
||||
{
|
||||
if (rt_bitmap_test_bit(pool->map, next_bit))
|
||||
{
|
||||
bit = next_bit;
|
||||
goto _next;
|
||||
}
|
||||
}
|
||||
|
||||
if (next_bit == end_bit)
|
||||
{
|
||||
while (next_bit --> bit)
|
||||
{
|
||||
rt_bitmap_set_bit(pool->map, next_bit);
|
||||
}
|
||||
|
||||
return pool->start + bit * ARCH_PAGE_SIZE;
|
||||
}
|
||||
_next:
|
||||
}
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
static void dma_pool_free(struct rt_dma_pool *pool, rt_ubase_t offset, rt_size_t size)
|
||||
{
|
||||
rt_size_t bit = (offset - pool->start) / ARCH_PAGE_SIZE, end_bit;
|
||||
|
||||
size = RT_DIV_ROUND_UP(size, ARCH_PAGE_SIZE);
|
||||
end_bit = bit + size;
|
||||
|
||||
for (; bit < end_bit; ++bit)
|
||||
{
|
||||
rt_bitmap_clear_bit(pool->map, bit);
|
||||
}
|
||||
}
|
||||
|
||||
static void *dma_alloc(struct rt_device *dev, rt_size_t size,
|
||||
rt_ubase_t *dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
void *dma_buffer = RT_NULL;
|
||||
struct rt_dma_pool *pool;
|
||||
|
||||
region_pool_lock();
|
||||
|
||||
rt_list_for_each_entry(pool, &dma_pool_nodes, list)
|
||||
{
|
||||
if (pool->flags & RT_DMA_F_DEVICE)
|
||||
{
|
||||
if (!(flags & RT_DMA_F_DEVICE) || pool->dev != dev)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if ((flags & RT_DMA_F_DEVICE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((flags & RT_DMA_F_NOMAP) && !((pool->flags & RT_DMA_F_NOMAP)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((flags & RT_DMA_F_32BITS) && !((pool->flags & RT_DMA_F_32BITS)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((flags & RT_DMA_F_LINEAR) && !((pool->flags & RT_DMA_F_LINEAR)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
*dma_handle = dma_pool_alloc(pool, size);
|
||||
|
||||
if (*dma_handle && !(flags & RT_DMA_F_NOMAP))
|
||||
{
|
||||
if (flags & RT_DMA_F_NOCACHE)
|
||||
{
|
||||
dma_buffer = rt_ioremap_nocache((void *)*dma_handle, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
dma_buffer = rt_ioremap_cached((void *)*dma_handle, size);
|
||||
}
|
||||
|
||||
if (!dma_buffer)
|
||||
{
|
||||
dma_pool_free(pool, *dma_handle, size);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else if (*dma_handle)
|
||||
{
|
||||
dma_buffer = (void *)*dma_handle;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
region_pool_unlock();
|
||||
|
||||
return dma_buffer;
|
||||
}
|
||||
|
||||
static void dma_free(struct rt_device *dev, rt_size_t size,
|
||||
void *cpu_addr, rt_ubase_t dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
struct rt_dma_pool *pool;
|
||||
|
||||
region_pool_lock();
|
||||
|
||||
rt_list_for_each_entry(pool, &dma_pool_nodes, list)
|
||||
{
|
||||
if (dma_handle >= pool->region.start &&
|
||||
dma_handle <= pool->region.end)
|
||||
{
|
||||
rt_iounmap(cpu_addr);
|
||||
|
||||
dma_pool_free(pool, dma_handle, size);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
region_pool_unlock();
|
||||
}
|
||||
|
||||
void *rt_dma_alloc(struct rt_device *dev, rt_size_t size,
|
||||
rt_ubase_t *dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
void *dma_buffer = RT_NULL;
|
||||
rt_ubase_t dma_handle_s = 0;
|
||||
const struct rt_dma_map_ops *ops;
|
||||
|
||||
if (!dev || !size)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
ops = device_dma_ops(dev);
|
||||
|
||||
if (ops->alloc)
|
||||
{
|
||||
dma_buffer = ops->alloc(dev, size, &dma_handle_s, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
dma_buffer = dma_alloc(dev, size, &dma_handle_s, flags);
|
||||
}
|
||||
|
||||
if (!dma_buffer)
|
||||
{
|
||||
return dma_buffer;
|
||||
}
|
||||
|
||||
if (dma_handle)
|
||||
{
|
||||
*dma_handle = dma_handle_s;
|
||||
}
|
||||
|
||||
return dma_buffer;
|
||||
}
|
||||
|
||||
void rt_dma_free(struct rt_device *dev, rt_size_t size,
|
||||
void *cpu_addr, rt_ubase_t dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
const struct rt_dma_map_ops *ops;
|
||||
|
||||
if (!dev || !size || !cpu_addr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ops = device_dma_ops(dev);
|
||||
|
||||
if (ops->free)
|
||||
{
|
||||
ops->free(dev, size, cpu_addr, dma_handle, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
dma_free(dev, size, cpu_addr, dma_handle, flags);
|
||||
}
|
||||
}
|
||||
|
||||
rt_err_t rt_dma_sync_out_data(struct rt_device *dev, void *data, rt_size_t size,
|
||||
rt_ubase_t *dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
rt_err_t err;
|
||||
rt_ubase_t dma_handle_s = 0;
|
||||
const struct rt_dma_map_ops *ops;
|
||||
|
||||
if (!data || !size)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
ops = device_dma_ops(dev);
|
||||
err = ops->sync_out_data(dev, data, size, &dma_handle_s, flags);
|
||||
|
||||
if (dma_handle)
|
||||
{
|
||||
*dma_handle = dma_handle_s;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
rt_err_t rt_dma_sync_in_data(struct rt_device *dev, void *out_data, rt_size_t size,
|
||||
rt_ubase_t dma_handle, rt_ubase_t flags)
|
||||
{
|
||||
rt_err_t err;
|
||||
const struct rt_dma_map_ops *ops;
|
||||
|
||||
if (!out_data || !size)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
ops = device_dma_ops(dev);
|
||||
err = ops->sync_in_data(dev, out_data, size, dma_handle, flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct rt_dma_pool *dma_pool_install(rt_region_t *region)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_dma_pool *pool;
|
||||
|
||||
if (!(pool = rt_calloc(1, sizeof(*pool))))
|
||||
{
|
||||
LOG_E("Install pool[%p, %p] error = %s",
|
||||
region->start, region->end, rt_strerror(-RT_ENOMEM));
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
rt_memcpy(&pool->region, region, sizeof(*region));
|
||||
|
||||
pool->flags |= RT_DMA_F_LINEAR;
|
||||
|
||||
if (region->end < 4UL * SIZE_GB)
|
||||
{
|
||||
pool->flags |= RT_DMA_F_32BITS;
|
||||
}
|
||||
|
||||
pool->start = RT_ALIGN(pool->region.start, ARCH_PAGE_SIZE);
|
||||
pool->bits = (pool->region.end - pool->start) / ARCH_PAGE_SIZE;
|
||||
|
||||
if (!pool->bits)
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
pool->map = rt_calloc(RT_BITMAP_LEN(pool->bits), sizeof(*pool->map));
|
||||
|
||||
if (!pool->map)
|
||||
{
|
||||
err = -RT_ENOMEM;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
rt_list_init(&pool->list);
|
||||
|
||||
region_pool_lock();
|
||||
rt_list_insert_before(&dma_pool_nodes, &pool->list);
|
||||
region_pool_unlock();
|
||||
|
||||
return pool;
|
||||
|
||||
_fail:
|
||||
rt_free(pool);
|
||||
|
||||
LOG_E("Install pool[%p, %p] error = %s",
|
||||
region->start, region->end, rt_strerror(err));
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
struct rt_dma_pool *rt_dma_pool_install(rt_region_t *region)
|
||||
{
|
||||
struct rt_dma_pool *pool;
|
||||
|
||||
if (!region)
|
||||
{
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
if ((pool = dma_pool_install(region)))
|
||||
{
|
||||
region = &pool->region;
|
||||
|
||||
LOG_I("%s: Reserved %u.%u MiB at %p",
|
||||
region->name,
|
||||
(region->end - region->start) / SIZE_MB,
|
||||
(region->end - region->start) / SIZE_KB & (SIZE_KB - 1),
|
||||
region->start);
|
||||
}
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
rt_err_t rt_dma_pool_extract(rt_region_t *region_list, rt_size_t list_len,
|
||||
rt_size_t cma_size, rt_size_t coherent_pool_size)
|
||||
{
|
||||
struct rt_dma_pool *pool;
|
||||
rt_region_t *region = region_list, *region_high = RT_NULL, cma, coherent_pool;
|
||||
|
||||
if (!region_list || !list_len || cma_size < coherent_pool_size)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
for (rt_size_t i = 0; i < list_len; ++i, ++region)
|
||||
{
|
||||
if (!region->name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Always use low address in 4G */
|
||||
if (region->end - region->start >= cma_size)
|
||||
{
|
||||
if ((rt_ssize_t)((4UL * SIZE_GB) - region->start) < cma_size)
|
||||
{
|
||||
region_high = region;
|
||||
continue;
|
||||
}
|
||||
|
||||
goto _found;
|
||||
}
|
||||
}
|
||||
|
||||
if (region_high)
|
||||
{
|
||||
region = region_high;
|
||||
LOG_W("No available DMA zone in 4G");
|
||||
|
||||
goto _found;
|
||||
}
|
||||
|
||||
return -RT_EEMPTY;
|
||||
|
||||
_found:
|
||||
if (region->end - region->start != cma_size)
|
||||
{
|
||||
cma.start = region->start;
|
||||
cma.end = cma.start + cma_size;
|
||||
|
||||
/* Update input region */
|
||||
region->start += cma_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_memcpy(&cma, region, sizeof(cma));
|
||||
}
|
||||
|
||||
coherent_pool.name = "coherent-pool";
|
||||
coherent_pool.start = cma.start;
|
||||
coherent_pool.end = coherent_pool.start + coherent_pool_size;
|
||||
|
||||
cma.name = "cma";
|
||||
cma.start += coherent_pool_size;
|
||||
|
||||
if (!(pool = rt_dma_pool_install(&coherent_pool)))
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
/* Use: CMA > coherent-pool */
|
||||
if (!(pool = rt_dma_pool_install(&cma)))
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#if defined(RT_USING_CONSOLE) && defined(RT_USING_MSH)
|
||||
static int list_dma_pool(int argc, char**argv)
|
||||
{
|
||||
int count = 0;
|
||||
rt_region_t *region;
|
||||
struct rt_dma_pool *pool;
|
||||
|
||||
rt_kprintf("%-*.s Region\n", RT_NAME_MAX, "Name");
|
||||
|
||||
region_pool_lock();
|
||||
|
||||
rt_list_for_each_entry(pool, &dma_pool_nodes, list)
|
||||
{
|
||||
region = &pool->region;
|
||||
|
||||
rt_kprintf("%-*.s [%p, %p]\n", RT_NAME_MAX, region->name,
|
||||
region->start, region->end);
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
rt_kprintf("%d DMA memory found\n", count);
|
||||
|
||||
region_pool_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT(list_dma_pool, dump all dma memory pool);
|
||||
#endif /* RT_USING_CONSOLE && RT_USING_MSH */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -320,7 +320,14 @@ static rt_err_t rt_hwtimer_control(struct rt_device *dev, int cmd, void *args)
|
||||
break;
|
||||
default:
|
||||
{
|
||||
result = -RT_ENOSYS;
|
||||
if (timer->ops->control != RT_NULL)
|
||||
{
|
||||
result = timer->ops->control(timer, cmd, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -RT_ENOSYS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -17,203 +17,227 @@ if RT_USING_I2C
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_USING_SOFT_I2C
|
||||
menuconfig RT_USING_SOFT_I2C
|
||||
bool "Use GPIO to soft simulate I2C"
|
||||
default n
|
||||
select RT_USING_PIN
|
||||
select RT_USING_I2C_BITOPS
|
||||
if RT_USING_SOFT_I2C
|
||||
config RT_USING_SOFT_I2C1
|
||||
bool "Enable I2C1 Bus (software simulation)"
|
||||
default y
|
||||
if RT_USING_SOFT_I2C1
|
||||
config RT_SOFT_I2C1_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 1
|
||||
config RT_SOFT_I2C1_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 2
|
||||
config RT_SOFT_I2C1_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c1"
|
||||
config RT_SOFT_I2C1_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C1_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
config RT_USING_SOFT_I2C2
|
||||
bool "Enable I2C2 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C2
|
||||
config RT_SOFT_I2C2_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 3
|
||||
config RT_SOFT_I2C2_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 4
|
||||
config RT_SOFT_I2C2_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c2"
|
||||
config RT_SOFT_I2C2_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C2_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
config RT_USING_SOFT_I2C3
|
||||
bool "Enable I2C3 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C3
|
||||
config RT_SOFT_I2C3_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 5
|
||||
config RT_SOFT_I2C3_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 6
|
||||
config RT_SOFT_I2C3_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c3"
|
||||
config RT_SOFT_I2C3_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C3_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
config RT_USING_SOFT_I2C4
|
||||
bool "Enable I2C4 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C4
|
||||
config RT_SOFT_I2C4_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 7
|
||||
config RT_SOFT_I2C4_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 8
|
||||
config RT_SOFT_I2C4_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c4"
|
||||
config RT_SOFT_I2C4_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C4_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
config RT_USING_SOFT_I2C5
|
||||
bool "Enable I2C5 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C5
|
||||
config RT_SOFT_I2C5_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 9
|
||||
config RT_SOFT_I2C5_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C5_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c5"
|
||||
config RT_SOFT_I2C5_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C5_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
config RT_USING_SOFT_I2C6
|
||||
bool "Enable I2C6 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C6
|
||||
config RT_SOFT_I2C6_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 11
|
||||
config RT_SOFT_I2C6_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 12
|
||||
config RT_SOFT_I2C6_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c6"
|
||||
config RT_SOFT_I2C6_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C6_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
config RT_USING_SOFT_I2C7
|
||||
bool "Enable I2C7 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C7
|
||||
config RT_SOFT_I2C7_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 13
|
||||
config RT_SOFT_I2C7_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 14
|
||||
config RT_SOFT_I2C7_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c7"
|
||||
config RT_SOFT_I2C7_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C7_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
config RT_USING_SOFT_I2C8
|
||||
bool "Enable I2C8 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C8
|
||||
config RT_SOFT_I2C8_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 15
|
||||
config RT_SOFT_I2C8_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 16
|
||||
config RT_SOFT_I2C8_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c8"
|
||||
config RT_SOFT_I2C8_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C8_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
endif
|
||||
if RT_USING_SOFT_I2C
|
||||
menuconfig RT_USING_SOFT_I2C0
|
||||
bool "Enable I2C0 Bus (software simulation)"
|
||||
default y
|
||||
if RT_USING_SOFT_I2C0
|
||||
config RT_SOFT_I2C0_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 1
|
||||
config RT_SOFT_I2C0_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 2
|
||||
config RT_SOFT_I2C0_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c0"
|
||||
config RT_SOFT_I2C0_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C0_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
menuconfig RT_USING_SOFT_I2C1
|
||||
bool "Enable I2C1 Bus (software simulation)"
|
||||
default y
|
||||
if RT_USING_SOFT_I2C1
|
||||
config RT_SOFT_I2C1_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 3
|
||||
config RT_SOFT_I2C1_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 4
|
||||
config RT_SOFT_I2C1_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c1"
|
||||
config RT_SOFT_I2C1_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C1_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
menuconfig RT_USING_SOFT_I2C2
|
||||
bool "Enable I2C2 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C2
|
||||
config RT_SOFT_I2C2_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 5
|
||||
config RT_SOFT_I2C2_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 6
|
||||
config RT_SOFT_I2C2_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c2"
|
||||
config RT_SOFT_I2C2_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C2_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
menuconfig RT_USING_SOFT_I2C3
|
||||
bool "Enable I2C3 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C3
|
||||
config RT_SOFT_I2C3_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 7
|
||||
config RT_SOFT_I2C3_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 8
|
||||
config RT_SOFT_I2C3_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c3"
|
||||
config RT_SOFT_I2C3_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C3_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
menuconfig RT_USING_SOFT_I2C4
|
||||
bool "Enable I2C4 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C4
|
||||
config RT_SOFT_I2C4_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 9
|
||||
config RT_SOFT_I2C4_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C4_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c4"
|
||||
config RT_SOFT_I2C4_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C4_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
menuconfig RT_USING_SOFT_I2C5
|
||||
bool "Enable I2C5 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C5
|
||||
config RT_SOFT_I2C5_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 11
|
||||
config RT_SOFT_I2C5_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 12
|
||||
config RT_SOFT_I2C5_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c5"
|
||||
config RT_SOFT_I2C5_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C5_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
menuconfig RT_USING_SOFT_I2C6
|
||||
bool "Enable I2C6 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C6
|
||||
config RT_SOFT_I2C6_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 13
|
||||
config RT_SOFT_I2C6_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 14
|
||||
config RT_SOFT_I2C6_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c6"
|
||||
config RT_SOFT_I2C6_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C6_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
menuconfig RT_USING_SOFT_I2C7
|
||||
bool "Enable I2C7 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C7
|
||||
config RT_SOFT_I2C7_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 15
|
||||
config RT_SOFT_I2C7_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 16
|
||||
config RT_SOFT_I2C7_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c7"
|
||||
config RT_SOFT_I2C7_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C7_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
menuconfig RT_USING_SOFT_I2C8
|
||||
bool "Enable I2C8 Bus (software simulation)"
|
||||
default n
|
||||
if RT_USING_SOFT_I2C8
|
||||
config RT_SOFT_I2C8_SCL_PIN
|
||||
int "SCL pin number"
|
||||
range 0 32767
|
||||
default 17
|
||||
config RT_SOFT_I2C8_SDA_PIN
|
||||
int "SDA pin number"
|
||||
range 0 32767
|
||||
default 18
|
||||
config RT_SOFT_I2C8_BUS_NAME
|
||||
string "Bus name"
|
||||
default "i2c8"
|
||||
config RT_SOFT_I2C8_TIMING_DELAY
|
||||
int "Timing delay (us)"
|
||||
range 0 32767
|
||||
default 10
|
||||
config RT_SOFT_I2C8_TIMING_TIMEOUT
|
||||
int "Timing timeout (tick)"
|
||||
range 0 32767
|
||||
default 10
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
@ -3,16 +3,16 @@ from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Split("""
|
||||
i2c_core.c
|
||||
i2c_dev.c
|
||||
dev_i2c_core.c
|
||||
dev_i2c_dev.c
|
||||
""")
|
||||
|
||||
if GetDepend('RT_USING_I2C_BITOPS'):
|
||||
src = src + ['i2c-bit-ops.c']
|
||||
src = src + ['dev_i2c_bit_ops.c']
|
||||
if GetDepend('RT_USING_SOFT_I2C'):
|
||||
src = src + ['soft_i2c.c']
|
||||
src = src + ['dev_soft_i2c.c']
|
||||
if GetDepend(['RT_USING_DM']):
|
||||
src += ['i2c_bus.c', 'i2c_dm.c']
|
||||
src += ['dev_i2c_bus.c', 'dev_i2c_dm.c']
|
||||
|
||||
# The set of source files associated with this SConscript file.
|
||||
path = [cwd + '/../include']
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "i2c.bus"
|
||||
#define DBG_TAG "dev.i2c.bus"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
@ -30,7 +30,7 @@ rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus,
|
||||
|
||||
res = rt_i2c_bus_device_device_init(bus, bus_name);
|
||||
|
||||
LOG_I("I2C bus [%s] registered", bus_name);
|
||||
LOG_D("I2C bus [%s] registered", bus_name);
|
||||
|
||||
#ifdef RT_USING_DM
|
||||
if (!res)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user