Revert "rtt更新"
This reverts commit d6009a0773d226206cf691dda1be16f5aa6299ee.
This commit is contained in:
parent
0abd316c90
commit
cabe8296ea
@ -1,189 +0,0 @@
|
||||
scons.args: &scons
|
||||
scons_arg:
|
||||
- '--strict'
|
||||
# ------ kernel CI ------
|
||||
kernel.klibc-stdlib:
|
||||
<<: *scons
|
||||
kconfig:
|
||||
- CONFIG_RT_KLIBC_USING_STDLIB=y
|
||||
- CONFIG_RT_KLIBC_USING_STDLIB_MEMORY=y
|
||||
kernel.klibc-tinysize:
|
||||
<<: *scons
|
||||
kconfig:
|
||||
- CONFIG_RT_KLIBC_USING_TINY_SIZE=y
|
||||
kernel.klibc-vsnprintf-std:
|
||||
<<: *scons
|
||||
kconfig:
|
||||
- CONFIG_RT_KLIBC_USING_VSNPRINTF_STANDARD=y
|
||||
- CONFIG_RT_KLIBC_USING_PRINTF_LONGLONG=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=y
|
||||
# ------ online-packages CI ------
|
||||
online-packages.iot.at_devices:
|
||||
<<: *scons
|
||||
kconfig:
|
||||
- CONFIG_PKG_USING_AT_DEVICE=y
|
||||
# Quectel M26/MC20
|
||||
- CONFIG_AT_DEVICE_USING_M26=y
|
||||
- CONFIG_AT_DEVICE_M26_INIT_ASYN=y
|
||||
# Quectel EC20
|
||||
- CONFIG_AT_DEVICE_USING_EC20=y
|
||||
- CONFIG_AT_DEVICE_EC20_INIT_ASYN=y
|
||||
# Espressif ESP32
|
||||
- CONFIG_AT_DEVICE_USING_ESP32=y
|
||||
- CONFIG_AT_DEVICE_ESP32_INIT_ASYN=y
|
||||
# Espressif ESP8266
|
||||
- CONFIG_AT_DEVICE_USING_ESP8266=y
|
||||
- CONFIG_AT_DEVICE_ESP8266_INIT_ASYN=y
|
||||
# Realthread RW007
|
||||
- CONFIG_AT_DEVICE_USING_RW007=y
|
||||
- CONFIG_AT_DEVICE_RW007_INIT_ASYN=y
|
||||
# SIMCom SIM800C
|
||||
- CONFIG_AT_DEVICE_USING_SIM800C=y
|
||||
- CONFIG_AT_DEVICE_SIM800C_INIT_ASYN=y
|
||||
# SIMCom SIM76XX
|
||||
- CONFIG_AT_DEVICE_USING_SIM76XX=y
|
||||
- CONFIG_AT_DEVICE_SIM76XX_INIT_ASYN=y
|
||||
# Notion MW31
|
||||
- CONFIG_AT_DEVICE_USING_MW31=y
|
||||
- CONFIG_AT_DEVICE_MW31_INIT_ASYN=y
|
||||
# WinnerMicro W60X
|
||||
- CONFIG_AT_DEVICE_USING_W60X=y
|
||||
- CONFIG_AT_DEVICE_W60X_INIT_ASYN=y
|
||||
# Ai-Think A9G
|
||||
- CONFIG_AT_DEVICE_USING_A9G=y
|
||||
- CONFIG_AT_DEVICE_A9G_INIT_ASYN=y
|
||||
# Quectel BC26
|
||||
- CONFIG_AT_DEVICE_USING_BC26=y
|
||||
- CONFIG_AT_DEVICE_BC26_INIT_ASYN=y
|
||||
# luat Air720
|
||||
- CONFIG_AT_DEVICE_USING_AIR720=y
|
||||
- CONFIG_AT_DEVICE_AIR720_INIT_ASYN=y
|
||||
# Gosuncn ME3616
|
||||
- CONFIG_AT_DEVICE_USING_ME3616=y
|
||||
- CONFIG_AT_DEVICE_ME3616_INIT_ASYN=y
|
||||
# ChinaMobile M6315
|
||||
- CONFIG_AT_DEVICE_USING_M6315=y
|
||||
- CONFIG_AT_DEVICE_M6315_INIT_ASYN=y
|
||||
# Quectel BC28
|
||||
- CONFIG_AT_DEVICE_USING_BC28=y
|
||||
- CONFIG_AT_DEVICE_BC28_INIT_ASYN=y
|
||||
# Quectel EC200T/EC200S
|
||||
- CONFIG_AT_DEVICE_USING_EC200X=y
|
||||
- CONFIG_AT_DEVICE_EC200X_INIT_ASYN=y
|
||||
# Neoway N21
|
||||
- CONFIG_AT_DEVICE_USING_N21=y
|
||||
- CONFIG_AT_DEVICE_N21_INIT_ASYN=y
|
||||
# Neoway N58
|
||||
- CONFIG_AT_DEVICE_USING_N58=y
|
||||
- CONFIG_AT_DEVICE_N58_INIT_ASYN=y
|
||||
# ChinaMobile M5311
|
||||
- CONFIG_AT_DEVICE_USING_M5311=y
|
||||
- CONFIG_AT_DEVICE_M5311_INIT_ASYN=y
|
||||
# Fibocom L610
|
||||
- CONFIG_AT_DEVICE_USING_L610=y
|
||||
- CONFIG_AT_DEVICE_L610_INIT_ASYN=y
|
||||
# Neoway N720
|
||||
- CONFIG_AT_DEVICE_USING_N720=y
|
||||
- CONFIG_AT_DEVICE_N720_INIT_ASYN=y
|
||||
# Gosuncn ML305
|
||||
- CONFIG_AT_DEVICE_USING_ML305=y
|
||||
- CONFIG_AT_DEVICE_ML305_INIT_ASYN=y
|
||||
online-packages.misc.misc:
|
||||
<<: *scons
|
||||
kconfig:
|
||||
- CONFIG_PKG_USING_MULTIBUTTON=y
|
||||
online-packages.misc.vi:
|
||||
<<: *scons
|
||||
kconfig:
|
||||
- CONFIG_PKG_USING_VI=y
|
||||
# - CONFIG_VI_ENABLE_8BIT=y
|
||||
- CONFIG_VI_ENABLE_COLON=y
|
||||
- CONFIG_VI_ENABLE_COLON_EXPAND=y
|
||||
- CONFIG_VI_ENABLE_YANKMARK=y
|
||||
- CONFIG_VI_ENABLE_SEARCH=y
|
||||
- CONFIG_VI_ENABLE_DOT_CMD=y
|
||||
- CONFIG_VI_ENABLE_READONLY=y
|
||||
- CONFIG_VI_ENABLE_SETOPTS=y
|
||||
- CONFIG_VI_ENABLE_SET=y
|
||||
- CONFIG_VI_ENABLE_WIN_RESIZE=y
|
||||
- CONFIG_VI_ENABLE_VI_ASK_TERMINAL=y
|
||||
- CONFIG_VI_ENABLE_UNDO=y
|
||||
- CONFIG_VI_ENABLE_UNDO_QUEUE=y
|
||||
- CONFIG_VI_ENABLE_VERBOSE_STATUS=y
|
||||
online-packages.multimedia.lvgl-v8.3-latest:
|
||||
<<: *scons
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_LVGL=y
|
||||
- CONFIG_BSP_USING_LVGL_DEMO=y
|
||||
- CONFIG_PKG_LVGL_USING_V8_3_LATEST=y
|
||||
online-packages.multimedia.lvgl-v8.3.11:
|
||||
<<: *scons
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_LVGL=y
|
||||
- CONFIG_BSP_USING_LVGL_DEMO=y
|
||||
- CONFIG_PKG_LVGL_USING_V080311=y
|
||||
online-packages.multimedia.lvgl-v8.4-latest:
|
||||
<<: *scons
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_LVGL=y
|
||||
- CONFIG_BSP_USING_LVGL_DEMO=y
|
||||
- CONFIG_PKG_LVGL_USING_V8_4_LATEST=y
|
||||
online-packages.system.enhanced-kservice:
|
||||
<<: *scons
|
||||
kconfig:
|
||||
- CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE=y
|
||||
- CONFIG_PKG_USING_RT_MEMCPY_CM=y
|
||||
online-packages.system.os-wrappers:
|
||||
<<: *scons
|
||||
kconfig:
|
||||
- CONFIG_PKG_USING_FREERTOS_WRAPPER=y
|
||||
# ------ peripheral CI ------
|
||||
peripheral.aht21:
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_AHT21=y
|
||||
peripheral.ap3216c:
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_AP3216C=y
|
||||
peripheral.ethernet_28j60:
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_ENC28j60=y
|
||||
peripheral.fal_easyflash:
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_EASYFLASH=y
|
||||
peripheral.filesystem:
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_FS=y
|
||||
- CONFIG_BSP_USING_FLASH_FATFS=y
|
||||
peripheral.icm20608:
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_ICM20608=y
|
||||
peripheral.lcd_st7787:
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_ONBOARD_LCD=y
|
||||
peripheral.led_matrix:
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_ONBOARD_LED_MATRIX=y
|
||||
peripheral.rs485:
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_RS485=y
|
||||
peripheral.rw007:
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_RW007_WLAN=y
|
||||
peripheral.spi_flash_w25q64:
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_SPI_FLASH=y
|
||||
peripheral.sram:
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_SRAM=y
|
||||
peripheral.usb_mouse:
|
||||
kconfig:
|
||||
- CONFIG_BSP_USING_USB_MOUSE=y
|
||||
# ------ nano CI ------
|
||||
nano:
|
||||
<<: *scons
|
||||
kconfig:
|
||||
- CONFIG_RT_USING_NANO=y
|
@ -52,10 +52,8 @@ if GetDepend(['RT_USING_DAC']):
|
||||
if GetDepend(['RT_USING_CAN']):
|
||||
src += ['drv_can.c']
|
||||
|
||||
if GetDepend(['RT_USING_PM']):
|
||||
if GetDepend(['RT_USING_PM', 'SOC_SERIES_STM32L4']):
|
||||
src += ['drv_pm.c']
|
||||
|
||||
if GetDepend(['BSP_USING_LPTIM']):
|
||||
src += ['drv_lptim.c']
|
||||
|
||||
if GetDepend('BSP_USING_SDRAM'):
|
||||
@ -124,6 +122,9 @@ if GetDepend(['BSP_USING_PULSE_ENCODER']):
|
||||
if GetDepend(['BSP_USING_USBH']):
|
||||
src += ['drv_usbh.c']
|
||||
|
||||
if GetDepend(['BSP_USING_TEST']):
|
||||
src += ['drv_test.c']
|
||||
|
||||
path += [os.path.join(cwd, 'config')]
|
||||
|
||||
if GetDepend('BSP_USING_ON_CHIP_FLASH'):
|
||||
|
@ -19,13 +19,6 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* DMA1 channel1 */
|
||||
#if defined(BSP_ADC1_USING_DMA) && !defined(ADC1_DMA_INSTANCE)
|
||||
#define ADC1_DMA_IRQHandler DMA1_Channel1_IRQHandler
|
||||
#define ADC1_DMA_RCC RCC_AHBENR_DMA1EN
|
||||
#define ADC1_DMA_INSTANCE DMA1_Channel1
|
||||
#define ADC1_DMA_IRQ DMA1_Channel1_IRQn
|
||||
#endif
|
||||
|
||||
/* DMA1 channel2 */
|
||||
#if defined(BSP_SPI1_RX_USING_DMA) && !defined(SPI1_RX_DMA_INSTANCE)
|
||||
#define SPI1_DMA_RX_IRQHandler DMA1_Channel2_IRQHandler
|
||||
@ -63,11 +56,6 @@ extern "C" {
|
||||
#define UART1_TX_DMA_RCC RCC_AHBENR_DMA1EN
|
||||
#define UART1_TX_DMA_INSTANCE DMA1_Channel4
|
||||
#define UART1_TX_DMA_IRQ DMA1_Channel4_IRQn
|
||||
#elif defined(BSP_I2C2_TX_USING_DMA) && !defined(I2C2_TX_DMA_INSTANCE)
|
||||
#define I2C2_DMA_TX_IRQHandler DMA1_Channel4_IRQHandler
|
||||
#define I2C2_TX_DMA_RCC RCC_AHBENR_DMA1EN
|
||||
#define I2C2_TX_DMA_INSTANCE DMA1_Channel4
|
||||
#define I2C2_TX_DMA_IRQ DMA1_Channel4_IRQn
|
||||
#endif
|
||||
|
||||
/* DMA1 channel5 */
|
||||
@ -76,16 +64,12 @@ extern "C" {
|
||||
#define SPI2_TX_DMA_RCC RCC_AHBENR_DMA1EN
|
||||
#define SPI2_TX_DMA_INSTANCE DMA1_Channel5
|
||||
#define SPI2_TX_DMA_IRQ DMA1_Channel5_IRQn
|
||||
|
||||
#elif defined(BSP_UART1_RX_USING_DMA) && !defined(UART1_RX_DMA_INSTANCE)
|
||||
#define UART1_DMA_RX_IRQHandler DMA1_Channel5_IRQHandler
|
||||
#define UART1_RX_DMA_RCC RCC_AHBENR_DMA1EN
|
||||
#define UART1_RX_DMA_INSTANCE DMA1_Channel5
|
||||
#define UART1_RX_DMA_IRQ DMA1_Channel5_IRQn
|
||||
#elif defined(BSP_I2C2_RX_USING_DMA) && !defined(I2C2_RX_DMA_INSTANCE)
|
||||
#define I2C2_DMA_RX_IRQHandler DMA1_Channel5_IRQHandler
|
||||
#define I2C2_RX_DMA_RCC RCC_AHBENR_DMA1EN
|
||||
#define I2C2_RX_DMA_INSTANCE DMA1_Channel5
|
||||
#define I2C2_RX_DMA_IRQ DMA1_Channel5_IRQn
|
||||
#endif
|
||||
|
||||
/* DMA1 channel6 */
|
||||
@ -94,11 +78,6 @@ extern "C" {
|
||||
#define UART2_RX_DMA_RCC RCC_AHBENR_DMA1EN
|
||||
#define UART2_RX_DMA_INSTANCE DMA1_Channel6
|
||||
#define UART2_RX_DMA_IRQ DMA1_Channel6_IRQn
|
||||
#elif defined(BSP_I2C1_TX_USING_DMA) && !defined(I2C1_TX_DMA_INSTANCE)
|
||||
#define I2C1_DMA_TX_IRQHandler DMA1_Channel6_IRQHandler
|
||||
#define I2C1_TX_DMA_RCC RCC_AHBENR_DMA1EN
|
||||
#define I2C1_TX_DMA_INSTANCE DMA1_Channel6
|
||||
#define I2C1_TX_DMA_IRQ DMA1_Channel6_IRQn
|
||||
#endif
|
||||
|
||||
/* DMA1 channel7 */
|
||||
@ -107,11 +86,6 @@ extern "C" {
|
||||
#define UART2_TX_DMA_RCC RCC_AHBENR_DMA1EN
|
||||
#define UART2_TX_DMA_INSTANCE DMA1_Channel7
|
||||
#define UART2_TX_DMA_IRQ DMA1_Channel7_IRQn
|
||||
#elif defined(BSP_I2C1_RX_USING_DMA) && !defined(I2C1_RX_DMA_INSTANCE)
|
||||
#define I2C1_DMA_RX_IRQHandler DMA1_Channel7_IRQHandler
|
||||
#define I2C1_RX_DMA_RCC RCC_AHBENR_DMA1EN
|
||||
#define I2C1_RX_DMA_INSTANCE DMA1_Channel7
|
||||
#define I2C1_RX_DMA_IRQ DMA1_Channel7_IRQn
|
||||
#endif
|
||||
|
||||
/* DMA2 channel1 */
|
||||
@ -137,27 +111,9 @@ extern "C" {
|
||||
#define UART4_RX_DMA_INSTANCE DMA2_Channel3
|
||||
#define UART4_RX_DMA_IRQ DMA2_Channel3_IRQn
|
||||
#endif
|
||||
|
||||
/* DMA2 channel4 */
|
||||
#if defined(BSP_SDIO_TX_USING_DMA) && !defined(SDIO_TX_DMA_INSTANCE)
|
||||
#define SDIO_DMA_TX_IRQHandler DMA2_Channel4_5_IRQHandler
|
||||
#define SDIO_TX_DMA_RCC RCC_AHBENR_DMA2EN
|
||||
#define SDIO_TX_DMA_INSTANCE DMA2_Channel4
|
||||
#define SDIO_TX_DMA_IRQ DMA2_Channel4_5_IRQn
|
||||
#elif defined(BSP_SDIO_RX_USING_DMA) && !defined(SDIO_RX_DMA_INSTANCE)
|
||||
#define SDIO_DMA_RX_IRQHandler DMA2_Channel4_5_IRQHandler
|
||||
#define SDIO_RX_DMA_RCC RCC_AHBENR_DMA2EN
|
||||
#define SDIO_RX_DMA_INSTANCE DMA2_Channel4
|
||||
#define SDIO_RX_DMA_IRQ DMA2_Channel4_5_IRQn
|
||||
#endif
|
||||
|
||||
/* DMA2 channel5 */
|
||||
#if defined(BSP_ADC3_USING_DMA) && !defined(ADC3_DMA_INSTANCE)
|
||||
#define ADC3_DMA_IRQHandler DMA2_Channel4_5_IRQHandler
|
||||
#define ADC3_DMA_RCC RCC_AHBENR_DMA2EN
|
||||
#define ADC3_DMA_INSTANCE DMA2_Channel5
|
||||
#define ADC3_DMA_IRQ DMA2_Channel4_5_IRQn
|
||||
#elif defined(BSP_UART4_TX_USING_DMA) && !defined(UART4_TX_DMA_INSTANCE)
|
||||
#if defined(BSP_UART4_TX_USING_DMA) && !defined(UART4_TX_DMA_INSTANCE)
|
||||
#define UART4_DMA_TX_IRQHandler DMA2_Channel4_5_IRQHandler
|
||||
#define UART4_TX_DMA_RCC RCC_AHBENR_DMA2EN
|
||||
#define UART4_TX_DMA_INSTANCE DMA2_Channel5
|
||||
|
@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-02-06 Dyyt587 first version
|
||||
* 2024-04-23 Zeidan Add I2Cx_xx_DMA_CONFIG
|
||||
*/
|
||||
#ifndef __I2C_HARD_CONFIG_H__
|
||||
#define __I2C_HARD_CONFIG_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_HARD_I2C1
|
||||
#ifndef I2C1_BUS_CONFIG
|
||||
#define I2C1_BUS_CONFIG \
|
||||
{ \
|
||||
.Instance = I2C1, \
|
||||
.timeout=0x1000, \
|
||||
.name = "hwi2c1", \
|
||||
.evirq_type = I2C1_EV_IRQn, \
|
||||
.erirq_type = I2C1_ER_IRQn, \
|
||||
}
|
||||
#endif /* I2C1_BUS_CONFIG */
|
||||
#endif /* BSP_USING_HARD_I2C1 */
|
||||
|
||||
#ifdef BSP_I2C1_TX_USING_DMA
|
||||
#ifndef I2C1_TX_DMA_CONFIG
|
||||
#define I2C1_TX_DMA_CONFIG \
|
||||
{ \
|
||||
.dma_rcc = I2C1_TX_DMA_RCC, \
|
||||
.Instance = I2C1_TX_DMA_INSTANCE, \
|
||||
.dma_irq = I2C1_TX_DMA_IRQ, \
|
||||
}
|
||||
#endif /* I2C1_TX_DMA_CONFIG */
|
||||
#endif /* BSP_I2C1_TX_USING_DMA */
|
||||
|
||||
#ifdef BSP_I2C1_RX_USING_DMA
|
||||
#ifndef I2C1_RX_DMA_CONFIG
|
||||
#define I2C1_RX_DMA_CONFIG \
|
||||
{ \
|
||||
.dma_rcc = I2C1_RX_DMA_RCC, \
|
||||
.Instance = I2C1_RX_DMA_INSTANCE, \
|
||||
.dma_irq = I2C1_RX_DMA_IRQ, \
|
||||
}
|
||||
#endif /* I2C1_RX_DMA_CONFIG */
|
||||
#endif /* BSP_I2C1_RX_USING_DMA */
|
||||
|
||||
#ifdef BSP_USING_HARD_I2C2
|
||||
#ifndef I2C2_BUS_CONFIG
|
||||
#define I2C2_BUS_CONFIG \
|
||||
{ \
|
||||
.Instance = I2C2, \
|
||||
.timeout=0x1000, \
|
||||
.name = "hwi2c2", \
|
||||
.evirq_type = I2C2_EV_IRQn, \
|
||||
.erirq_type = I2C2_ER_IRQn, \
|
||||
}
|
||||
#endif /* I2C2_BUS_CONFIG */
|
||||
#endif /* BSP_USING_HARD_I2C2 */
|
||||
|
||||
#ifdef BSP_I2C2_TX_USING_DMA
|
||||
#ifndef I2C2_TX_DMA_CONFIG
|
||||
#define I2C2_TX_DMA_CONFIG \
|
||||
{ \
|
||||
.dma_rcc = I2C2_TX_DMA_RCC, \
|
||||
.Instance = I2C2_TX_DMA_INSTANCE, \
|
||||
.dma_irq = I2C2_TX_DMA_IRQ, \
|
||||
}
|
||||
#endif /* I2C2_TX_DMA_CONFIG */
|
||||
#endif /* BSP_I2C2_TX_USING_DMA */
|
||||
|
||||
#ifdef BSP_I2C2_RX_USING_DMA
|
||||
#ifndef I2C2_RX_DMA_CONFIG
|
||||
#define I2C2_RX_DMA_CONFIG \
|
||||
{ \
|
||||
.dma_rcc = I2C2_RX_DMA_RCC, \
|
||||
.Instance = I2C2_RX_DMA_INSTANCE, \
|
||||
.dma_irq = I2C2_RX_DMA_IRQ, \
|
||||
}
|
||||
#endif /* I2C2_RX_DMA_CONFIG */
|
||||
#endif /* BSP_I2C2_RX_USING_DMA */
|
||||
|
||||
#ifdef BSP_USING_HARD_I2C3
|
||||
#ifndef I2C3_BUS_CONFIG
|
||||
#define I2C3_BUS_CONFIG \
|
||||
{ \
|
||||
.Instance = I2C3, \
|
||||
.timeout=0x1000, \
|
||||
.name = "hwi2c3", \
|
||||
.evirq_type = I2C3_EV_IRQn, \
|
||||
.erirq_type = I2C3_ER_IRQn, \
|
||||
}
|
||||
#endif /* I2C3_BUS_CONFIG */
|
||||
#endif /* BSP_USING_HARD_I2C3 */
|
||||
|
||||
#ifdef BSP_I2C3_TX_USING_DMA
|
||||
#ifndef I2C3_TX_DMA_CONFIG
|
||||
#define I2C3_TX_DMA_CONFIG \
|
||||
{ \
|
||||
.dma_rcc = I2C3_TX_DMA_RCC, \
|
||||
.Instance = I2C3_TX_DMA_INSTANCE, \
|
||||
.dma_irq = I2C3_TX_DMA_IRQ, \
|
||||
}
|
||||
#endif /* I2C3_TX_DMA_CONFIG */
|
||||
#endif /* BSP_I2C3_TX_USING_DMA */
|
||||
|
||||
#ifdef BSP_I2C3_RX_USING_DMA
|
||||
#ifndef I2C3_RX_DMA_CONFIG
|
||||
#define I2C3_RX_DMA_CONFIG \
|
||||
{ \
|
||||
.dma_rcc = I2C3_RX_DMA_RCC, \
|
||||
.Instance = I2C3_RX_DMA_INSTANCE, \
|
||||
.dma_irq = I2C3_RX_DMA_IRQ, \
|
||||
}
|
||||
#endif /* I2C3_RX_DMA_CONFIG */
|
||||
#endif /* BSP_I2C3_RX_USING_DMA */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__I2C_HARD_CONFIG_H__ */
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024-07-11 wdfk-prog first version
|
||||
*/
|
||||
|
||||
#ifndef __LPTIM_CONFIG_H__
|
||||
#define __LPTIM_CONFIG_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef LPTIM_DEV_INFO_CONFIG
|
||||
#define LPTIM_DEV_INFO_CONFIG \
|
||||
{ \
|
||||
.maxfreq = 1000000, \
|
||||
.minfreq = 3000, \
|
||||
.maxcnt = 0xFFFF, \
|
||||
.cntmode = HWTIMER_CNTMODE_UP, \
|
||||
}
|
||||
#endif /* TIM_DEV_INFO_CONFIG */
|
||||
|
||||
#ifdef BSP_USING_LPTIM1
|
||||
#ifndef LPTIM1_CONFIG
|
||||
#define LPTIM1_CONFIG \
|
||||
{ \
|
||||
.tim_handle.Instance = LPTIM1, \
|
||||
.tim_irqn = LPTIM1_IRQn, \
|
||||
.name = "lptim1", \
|
||||
}
|
||||
#endif /* LPTIM1_CONFIG */
|
||||
#endif /* BSP_USING_LPTIM1 */
|
||||
|
||||
#ifdef BSP_USING_LPTIM2
|
||||
#ifndef LPTIM2_CONFIG
|
||||
#define LPTIM2_CONFIG \
|
||||
{ \
|
||||
.tim_handle.Instance = LPTIM2, \
|
||||
.tim_irqn = LPTIM2_IRQn, \
|
||||
.name = "lptim2", \
|
||||
}
|
||||
#endif /* LPTIM1_CONFIG */
|
||||
#endif /* BSP_USING_LPTIM1 */
|
||||
|
||||
#ifdef BSP_USING_LPTIM3
|
||||
#ifndef LPTIM3_CONFIG
|
||||
#define LPTIM3_CONFIG \
|
||||
{ \
|
||||
.tim_handle.Instance = LPTIM3, \
|
||||
.tim_irqn = LPTIM3_IRQn, \
|
||||
.name = "lptim3", \
|
||||
}
|
||||
#endif /* LPTIM3_CONFIG */
|
||||
#endif /* BSP_USING_LPTIM3 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LPTIM_CONFIG_H__ */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -174,6 +174,8 @@ static rt_err_t _can_config(struct rt_can_device *can, struct can_configure *cfg
|
||||
|
||||
/* default filter config */
|
||||
HAL_CAN_ConfigFilter(&drv_can->CanHandle, &drv_can->FilterConfig);
|
||||
/* can start */
|
||||
HAL_CAN_Start(&drv_can->CanHandle);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
@ -319,7 +321,7 @@ static rt_err_t _can_control(struct rt_can_device *can, int cmd, void *arg)
|
||||
rt_uint32_t id_l = 0;
|
||||
rt_uint32_t mask_h = 0;
|
||||
rt_uint32_t mask_l = 0;
|
||||
rt_uint32_t mask_l_tail = 0; /*CAN_FxR2 bit [2:0]*/
|
||||
rt_uint32_t mask_l_tail = 0; //CAN_FxR2 bit [2:0]
|
||||
|
||||
if (RT_NULL == arg)
|
||||
{
|
||||
@ -465,19 +467,7 @@ static rt_err_t _can_control(struct rt_can_device *can, int cmd, void *arg)
|
||||
drv_can->device.status.errcode = errtype & 0x07;
|
||||
|
||||
rt_memcpy(arg, &drv_can->device.status, sizeof(drv_can->device.status));
|
||||
break;
|
||||
}
|
||||
case RT_CAN_CMD_START:
|
||||
argval = (rt_uint32_t) arg;
|
||||
if (argval == 0)
|
||||
{
|
||||
HAL_CAN_Stop(&drv_can->CanHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
HAL_CAN_Start(&drv_can->CanHandle);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -35,7 +35,6 @@ extern "C" {
|
||||
#include "f1/sdio_config.h"
|
||||
#include "f1/pwm_config.h"
|
||||
#include "f1/usbd_config.h"
|
||||
#include "f1/i2c_hard_config.h"
|
||||
#include "f1/pulse_encoder_config.h"
|
||||
#elif defined(SOC_SERIES_STM32F2)
|
||||
#include "f2/dma_config.h"
|
||||
@ -123,7 +122,6 @@ extern "C" {
|
||||
#include "h7/adc_config.h"
|
||||
#include "h7/dac_config.h"
|
||||
#include "h7/tim_config.h"
|
||||
#include "h7/lptim_config.h"
|
||||
#include "h7/sdio_config.h"
|
||||
#include "h7/pwm_config.h"
|
||||
#include "h7/usbd_config.h"
|
||||
|
@ -394,6 +394,7 @@ static rt_err_t stm32_pin_irq_enable(struct rt_device *device, rt_base_t pin,
|
||||
const struct pin_irq_map *irqmap;
|
||||
rt_base_t level;
|
||||
rt_int32_t irqindex = -1;
|
||||
GPIO_InitTypeDef GPIO_InitStruct;
|
||||
|
||||
if (PIN_PORT(pin) >= PIN_STPORT_MAX)
|
||||
{
|
||||
@ -402,8 +403,6 @@ static rt_err_t stm32_pin_irq_enable(struct rt_device *device, rt_base_t pin,
|
||||
|
||||
if (enabled == PIN_IRQ_ENABLE)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
|
||||
irqindex = bit2bitno(PIN_STPIN(pin));
|
||||
if (irqindex < 0 || irqindex >= (rt_int32_t)ITEM_NUM(pin_irq_map))
|
||||
{
|
||||
|
@ -7,10 +7,14 @@
|
||||
* Date Author Notes
|
||||
* 2024-02-17 Dyyt587 first version
|
||||
* 2024-04-23 Zeidan fix bugs, test on STM32F429IGTx
|
||||
* 2024-12-10 zzk597 add support for STM32F1 series
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include <board.h>
|
||||
#include "drv_hard_i2c.h"
|
||||
#include "drv_config.h"
|
||||
#include <string.h>
|
||||
|
||||
/* not fully support for I2C4 */
|
||||
#if defined(BSP_USING_HARD_I2C1) || defined(BSP_USING_HARD_I2C2) || defined(BSP_USING_HARD_I2C3)
|
||||
@ -47,27 +51,28 @@ static struct stm32_i2c_config i2c_config[] =
|
||||
|
||||
static struct stm32_i2c i2c_objs[sizeof(i2c_config) / sizeof(i2c_config[0])] = {0};
|
||||
|
||||
|
||||
static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv)
|
||||
{
|
||||
RT_ASSERT(i2c_drv != RT_NULL);
|
||||
|
||||
I2C_HandleTypeDef *i2c_handle = &i2c_drv->handle;
|
||||
struct stm32_i2c_config *cfg = i2c_drv->config;
|
||||
|
||||
rt_memset(i2c_handle, 0, sizeof(I2C_HandleTypeDef));
|
||||
|
||||
struct stm32_i2c_config *cfg = i2c_drv->config;
|
||||
i2c_handle->Instance = cfg->Instance;
|
||||
#if defined(SOC_SERIES_STM32H7)
|
||||
i2c_handle->Init.Timing = cfg->timing;
|
||||
#endif /* defined(SOC_SERIES_STM32H7) */
|
||||
#if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F4)
|
||||
#if defined(SOC_SERIES_STM32F4)
|
||||
i2c_handle->Init.ClockSpeed = 100000;
|
||||
i2c_handle->Init.DutyCycle = I2C_DUTYCYCLE_2;
|
||||
#endif /* defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F4) */
|
||||
#endif /* defined(SOC_SERIES_STM32F4) */
|
||||
i2c_handle->Init.OwnAddress1 = 0;
|
||||
i2c_handle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
|
||||
#if defined(SOC_SERIES_STM32H7)
|
||||
i2c_handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
|
||||
#endif /* defined(SOC_SERIES_STM32H7) */
|
||||
i2c_handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
|
||||
i2c_handle->Init.OwnAddress2 = 0;
|
||||
i2c_handle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
|
||||
i2c_handle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
|
||||
if (HAL_I2C_DeInit(i2c_handle) != HAL_OK)
|
||||
@ -115,12 +120,11 @@ static rt_err_t stm32_i2c_init(struct stm32_i2c *i2c_drv)
|
||||
HAL_NVIC_EnableIRQ(i2c_drv->config->dma_tx->dma_irq);
|
||||
}
|
||||
|
||||
/* In the data transfer function stm32_i2c_master_xfer(), the IT transfer function
|
||||
HAL_I2C_Master_Seq_Transmit_IT() is used when DMA is not used, so the IT interrupt
|
||||
must be enable anyway, regardless of the DMA configuration, otherwise
|
||||
the rt_completion_wait() will always timeout. */
|
||||
if (i2c_drv->i2c_dma_flag & I2C_USING_TX_DMA_FLAG || i2c_drv->i2c_dma_flag & I2C_USING_RX_DMA_FLAG)
|
||||
{
|
||||
HAL_NVIC_SetPriority(i2c_drv->config->evirq_type, 2, 0);
|
||||
HAL_NVIC_EnableIRQ(i2c_drv->config->evirq_type);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
@ -156,14 +160,11 @@ static rt_ssize_t stm32_i2c_master_xfer(struct rt_i2c_bus_device *bus,
|
||||
uint8_t next_flag = 0;
|
||||
struct rt_completion *completion;
|
||||
rt_uint32_t timeout;
|
||||
|
||||
if (num == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
RT_ASSERT((msgs != RT_NULL) && (bus != RT_NULL));
|
||||
|
||||
i2c_obj = rt_container_of(bus, struct stm32_i2c, i2c_bus);
|
||||
completion = &i2c_obj->completion;
|
||||
I2C_HandleTypeDef *handle = &i2c_obj->handle;
|
||||
@ -344,48 +345,6 @@ int RT_hw_i2c_bus_init(void)
|
||||
i2c_objs[i].config = &i2c_config[i];
|
||||
i2c_objs[i].i2c_bus.timeout = i2c_config[i].timeout;
|
||||
|
||||
if ((i2c_objs[i].i2c_dma_flag & I2C_USING_RX_DMA_FLAG))
|
||||
{
|
||||
i2c_objs[i].dma.handle_rx.Instance = i2c_config[i].dma_rx->Instance;
|
||||
#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7)
|
||||
i2c_objs[i].dma.handle_rx.Init.Channel = i2c_config[i].dma_rx->channel;
|
||||
#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32H7)
|
||||
i2c_objs[i].dma.handle_rx.Init.Request = i2c_config[i].dma_rx->request;
|
||||
#endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) */
|
||||
#ifndef SOC_SERIES_STM32U5
|
||||
i2c_objs[i].dma.handle_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
i2c_objs[i].dma.handle_rx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
i2c_objs[i].dma.handle_rx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
i2c_objs[i].dma.handle_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
i2c_objs[i].dma.handle_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
i2c_objs[i].dma.handle_rx.Init.Mode = DMA_NORMAL;
|
||||
i2c_objs[i].dma.handle_rx.Init.Priority = DMA_PRIORITY_LOW;
|
||||
#endif
|
||||
#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32H7)
|
||||
i2c_objs[i].dma.handle_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
i2c_objs[i].dma.handle_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||||
i2c_objs[i].dma.handle_tx.Init.MemBurst = DMA_MBURST_INC4;
|
||||
i2c_objs[i].dma.handle_tx.Init.PeriphBurst = DMA_PBURST_INC4;
|
||||
#endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32H7) */
|
||||
{
|
||||
rt_uint32_t tmpreg = 0x00U;
|
||||
#if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32F0)
|
||||
/* enable DMA clock && Delay after an RCC peripheral clock enabling*/
|
||||
SET_BIT(RCC->AHBENR, i2c_config[i].dma_rx->dma_rcc);
|
||||
tmpreg = READ_BIT(RCC->AHBENR, i2c_config[i].dma_rx->dma_rcc);
|
||||
#elif defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32H7)
|
||||
SET_BIT(RCC->AHB1ENR, i2c_config[i].dma_rx->dma_rcc);
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmpreg = READ_BIT(RCC->AHB1ENR, i2c_config[i].dma_rx->dma_rcc);
|
||||
#elif defined(SOC_SERIES_STM32MP1)
|
||||
__HAL_RCC_DMAMUX_CLK_ENABLE();
|
||||
SET_BIT(RCC->MP_AHB2ENSETR, i2c_config[i].dma_rx->dma_rcc);
|
||||
tmpreg = READ_BIT(RCC->MP_AHB2ENSETR, i2c_config[i].dma_rx->dma_rcc);
|
||||
#endif /* defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32F0) */
|
||||
UNUSED(tmpreg); /* To avoid compiler warnings */
|
||||
}
|
||||
}
|
||||
|
||||
if (i2c_objs[i].i2c_dma_flag & I2C_USING_TX_DMA_FLAG)
|
||||
{
|
||||
i2c_objs[i].dma.handle_tx.Instance = i2c_config[i].dma_tx->Instance;
|
||||
@ -409,6 +368,32 @@ int RT_hw_i2c_bus_init(void)
|
||||
i2c_objs[i].dma.handle_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||||
i2c_objs[i].dma.handle_tx.Init.MemBurst = DMA_MBURST_INC4;
|
||||
i2c_objs[i].dma.handle_tx.Init.PeriphBurst = DMA_PBURST_INC4;
|
||||
#endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32H7) */
|
||||
}
|
||||
if ((i2c_objs[i].i2c_dma_flag & I2C_USING_RX_DMA_FLAG))
|
||||
{
|
||||
i2c_objs[i].dma.handle_rx.Instance = i2c_config[i].dma_rx->Instance;
|
||||
#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7)
|
||||
i2c_objs[i].dma.handle_rx.Init.Channel = i2c_config[i].dma_rx->channel;
|
||||
#elif defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32H7)
|
||||
i2c_objs[i].dma.handle_rx.Init.Request = i2c_config[i].dma_rx->request;
|
||||
#endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) */
|
||||
#ifndef SOC_SERIES_STM32U5
|
||||
i2c_objs[i].dma.handle_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
i2c_objs[i].dma.handle_rx.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
i2c_objs[i].dma.handle_rx.Init.MemInc = DMA_MINC_ENABLE;
|
||||
i2c_objs[i].dma.handle_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
i2c_objs[i].dma.handle_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
i2c_objs[i].dma.handle_rx.Init.Mode = DMA_NORMAL;
|
||||
i2c_objs[i].dma.handle_rx.Init.Priority = DMA_PRIORITY_LOW;
|
||||
#endif /* SOC_SERIES_STM32U5 */
|
||||
#if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32H7)
|
||||
|
||||
i2c_objs[i].dma.handle_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
i2c_objs[i].dma.handle_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||||
i2c_objs[i].dma.handle_tx.Init.MemBurst = DMA_MBURST_INC4;
|
||||
i2c_objs[i].dma.handle_tx.Init.PeriphBurst = DMA_PBURST_INC4;
|
||||
}
|
||||
#endif /* defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32H7) */
|
||||
{
|
||||
rt_uint32_t tmpreg = 0x00U;
|
||||
@ -427,8 +412,6 @@ int RT_hw_i2c_bus_init(void)
|
||||
#endif /* defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32F0) */
|
||||
UNUSED(tmpreg); /* To avoid compiler warnings */
|
||||
}
|
||||
}
|
||||
|
||||
rt_completion_init(&i2c_objs[i].completion);
|
||||
stm32_i2c_configure(&i2c_objs[i].i2c_bus);
|
||||
ret = rt_i2c_bus_device_register(&i2c_objs[i].i2c_bus, i2c_objs[i].config->name);
|
||||
@ -711,11 +694,47 @@ void I2C3_DMA_TX_IRQHandler(void)
|
||||
}
|
||||
#endif /* defined(BSP_USING_HARD_I2C3) && defined(BSP_I2C3_TX_USING_DMA) */
|
||||
|
||||
#if defined(BSP_USING_I2C4) && defined(BSP_I2C4_RX_USING_DMA)
|
||||
/**
|
||||
* @brief This function handles DMA Rx interrupt request.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void I2C4_DMA_RX_IRQHandler(void)
|
||||
{
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
HAL_DMA_IRQHandler(&i2c_objs[I2C4_INDEX].dma.handle_rx);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif /* defined(BSP_USING_I2C4) && defined(BSP_I2C4_RX_USING_DMA) */
|
||||
|
||||
#if defined(BSP_USING_I2C4) && defined(BSP_I2C4_TX_USING_DMA)
|
||||
/**
|
||||
* @brief This function handles DMA Rx interrupt request.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void I2C4_DMA_TX_IRQHandler(void)
|
||||
{
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
HAL_DMA_IRQHandler(&i2c_objs[I2C4_INDEX].dma.handle_tx);
|
||||
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif /* defined(BSP_USING_I2C4) && defined(BSP_I2C4_TX_USING_DMA) */
|
||||
|
||||
int rt_hw_hw_i2c_init(void)
|
||||
{
|
||||
stm32_get_dma_info();
|
||||
return RT_hw_i2c_bus_init();
|
||||
}
|
||||
INIT_BOARD_EXPORT(rt_hw_hw_i2c_init);
|
||||
INIT_CORE_EXPORT(rt_hw_hw_i2c_init);
|
||||
|
||||
#endif /* defined(BSP_USING_HARD_I2C1) || defined(BSP_USING_HARD_I2C2) || defined(BSP_USING_HARD_I2C3) */
|
||||
|
@ -11,10 +11,14 @@
|
||||
#ifndef __DRV_HARD_I2C_H__
|
||||
#define __DRV_HARD_I2C_H__
|
||||
|
||||
#include "drv_config.h"
|
||||
#include <rtthread.h>
|
||||
#include "rtdevice.h"
|
||||
#include <rthw.h>
|
||||
#include <drv_common.h>
|
||||
#include "drv_dma.h"
|
||||
#include "drv_config.h"
|
||||
#include <ipc/completion.h>
|
||||
#if defined(RT_USING_I2C) && defined(BSP_USING_I2C)
|
||||
|
||||
/* C binding of definitions if building with C++ compiler */
|
||||
#ifdef __cplusplus
|
||||
@ -30,22 +34,23 @@ struct stm32_i2c_config
|
||||
rt_uint32_t timeout;
|
||||
IRQn_Type evirq_type;
|
||||
IRQn_Type erirq_type;
|
||||
struct dma_config *dma_rx;
|
||||
struct dma_config *dma_tx;
|
||||
|
||||
struct dma_config *dma_rx, *dma_tx;
|
||||
};
|
||||
|
||||
struct stm32_i2c
|
||||
{
|
||||
I2C_HandleTypeDef handle;
|
||||
struct stm32_i2c_config *config;
|
||||
struct
|
||||
{
|
||||
DMA_HandleTypeDef handle_rx;
|
||||
DMA_HandleTypeDef handle_tx;
|
||||
} dma;
|
||||
rt_uint8_t i2c_dma_flag;
|
||||
struct stm32_i2c_config *config;
|
||||
struct rt_i2c_bus_device i2c_bus;
|
||||
rt_uint8_t i2c_dma_flag;
|
||||
struct rt_completion completion;
|
||||
|
||||
};
|
||||
|
||||
#define I2C_USING_TX_DMA_FLAG (1U)
|
||||
@ -55,4 +60,6 @@ struct stm32_i2c
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BSP_USING_I2C */
|
||||
|
||||
#endif /* __DRV_I2C_H__ */
|
||||
|
@ -1,87 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-05-06 Zero-Free first version
|
||||
* 2024-07-04 wdfk-prog lptimer is register with hwtimer, only supports pm calls,the timer function is not supported
|
||||
*/
|
||||
|
||||
#include <board.h>
|
||||
#include <drv_lptim.h>
|
||||
#include <rtdevice.h>
|
||||
#include "drv_config.h"
|
||||
|
||||
/*#define DRV_DEBUG*/
|
||||
#define LOG_TAG "drv.lptim"
|
||||
#include <drv_log.h>
|
||||
static LPTIM_HandleTypeDef LptimHandle;
|
||||
|
||||
#ifdef BSP_USING_LPTIM
|
||||
|
||||
#define LPTIM_REG_MAX_VALUE (0xFFFF)
|
||||
|
||||
enum
|
||||
void LPTIM1_IRQHandler(void)
|
||||
{
|
||||
#ifdef BSP_USING_LPTIM1
|
||||
LPTIM1_INDEX,
|
||||
#endif
|
||||
#ifdef BSP_USING_LPTIM2
|
||||
LPTIM2_INDEX,
|
||||
#endif
|
||||
#ifdef BSP_USING_LPTIM3
|
||||
LPTIM3_INDEX,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32_hw_lptimer
|
||||
{
|
||||
rt_hwtimer_t time_device;
|
||||
LPTIM_HandleTypeDef tim_handle;
|
||||
IRQn_Type tim_irqn;
|
||||
char *name;
|
||||
};
|
||||
|
||||
static struct stm32_hw_lptimer stm32_hw_lptimer_obj[] =
|
||||
{
|
||||
#ifdef BSP_USING_LPTIM1
|
||||
LPTIM1_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_LPTIM2
|
||||
LPTIM2_CONFIG,
|
||||
#endif
|
||||
#ifdef BSP_USING_LPTIM3
|
||||
LPTIM3_CONFIG,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct rt_hwtimer_info _info = LPTIM_DEV_INFO_CONFIG;
|
||||
|
||||
static void timer_init(struct rt_hwtimer_device *timer, rt_uint32_t state)
|
||||
{
|
||||
if(timer == RT_NULL)
|
||||
{
|
||||
LOG_E("init timer is NULL");
|
||||
return;
|
||||
HAL_LPTIM_IRQHandler(&LptimHandle);
|
||||
}
|
||||
|
||||
if (state)
|
||||
void HAL_LPTIM_CompareMatchCallback(LPTIM_HandleTypeDef *hlptim)
|
||||
{
|
||||
struct stm32_hw_lptimer *tim_device = rt_container_of(timer, struct stm32_hw_lptimer, time_device);
|
||||
LPTIM_HandleTypeDef *tim = (LPTIM_HandleTypeDef *)timer->parent.user_data;
|
||||
/* enter interrupt */
|
||||
rt_interrupt_enter();
|
||||
|
||||
if(tim_device == RT_NULL)
|
||||
{
|
||||
LOG_E("start tim_device is NULL");
|
||||
return;
|
||||
}
|
||||
if(tim == RT_NULL)
|
||||
{
|
||||
LOG_E("start %s LPTIM_Handle is NULL", tim_device->name);
|
||||
return;
|
||||
/* leave interrupt */
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get current count value of LPTIM
|
||||
*
|
||||
* @return the count vlaue
|
||||
*/
|
||||
rt_uint32_t stm32l4_lptim_get_current_tick(void)
|
||||
{
|
||||
return HAL_LPTIM_ReadCounter(&LptimHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get the max value that LPTIM can count
|
||||
*
|
||||
* @return the max count
|
||||
*/
|
||||
rt_uint32_t stm32l4_lptim_get_tick_max(void)
|
||||
{
|
||||
return (0xFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function start LPTIM with reload value
|
||||
*
|
||||
* @param reload The value that LPTIM count down from
|
||||
*
|
||||
* @return RT_EOK
|
||||
*/
|
||||
rt_err_t stm32l4_lptim_start(rt_uint32_t reload)
|
||||
{
|
||||
HAL_LPTIM_TimeOut_Start_IT(&LptimHandle, 0xFFFF, reload);
|
||||
|
||||
return (RT_EOK);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function stop LPTIM
|
||||
*/
|
||||
void stm32l4_lptim_stop(void)
|
||||
{
|
||||
rt_uint32_t _ier;
|
||||
|
||||
_ier = LptimHandle.Instance->IER;
|
||||
LptimHandle.Instance->ICR = LptimHandle.Instance->ISR & _ier;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function get the count clock of LPTIM
|
||||
*
|
||||
* @return the count clock frequency in Hz
|
||||
*/
|
||||
rt_uint32_t stm32l4_lptim_get_countfreq(void)
|
||||
{
|
||||
return 32000 / 32;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function initialize the lptim
|
||||
*/
|
||||
int stm32l4_hw_lptim_init(void)
|
||||
{
|
||||
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
||||
RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct = {0};
|
||||
|
||||
@ -96,225 +101,23 @@ static void timer_init(struct rt_hwtimer_device *timer, rt_uint32_t state)
|
||||
RCC_PeriphCLKInitStruct.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSI;
|
||||
HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct);
|
||||
|
||||
tim->Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
|
||||
tim->Init.Clock.Prescaler = LPTIM_PRESCALER_DIV32;
|
||||
tim->Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
|
||||
tim->Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
|
||||
tim->Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
|
||||
tim->Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;
|
||||
|
||||
HAL_StatusTypeDef ret = HAL_LPTIM_Init(tim);
|
||||
if (ret != HAL_OK)
|
||||
LptimHandle.Instance = LPTIM1;
|
||||
LptimHandle.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
|
||||
LptimHandle.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV32;
|
||||
LptimHandle.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
|
||||
LptimHandle.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
|
||||
LptimHandle.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
|
||||
LptimHandle.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;
|
||||
if (HAL_LPTIM_Init(&LptimHandle) != HAL_OK)
|
||||
{
|
||||
LOG_E("%s init failed %d", tim_device->name, ret);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
NVIC_ClearPendingIRQ(LPTIM1_IRQn);
|
||||
NVIC_SetPriority(LPTIM1_IRQn, 0);
|
||||
NVIC_EnableIRQ(LPTIM1_IRQn);
|
||||
LOG_D("%s init success", tim_device->name);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_err_t timer_start(rt_hwtimer_t *timer, rt_uint32_t t, rt_hwtimer_mode_t opmode)
|
||||
{
|
||||
if(timer == RT_NULL)
|
||||
{
|
||||
LOG_E("start timer is NULL");
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
struct stm32_hw_lptimer *tim_device = rt_container_of(timer, struct stm32_hw_lptimer, time_device);
|
||||
LPTIM_HandleTypeDef *tim = (LPTIM_HandleTypeDef *)timer->parent.user_data;
|
||||
|
||||
if(tim_device == RT_NULL)
|
||||
{
|
||||
LOG_E("start tim_device is NULL");
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
if(tim == RT_NULL)
|
||||
{
|
||||
LOG_E("start %s LPTIM_Handle is NULL", tim_device->name);
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef ret = HAL_LPTIM_TimeOut_Start_IT(tim, LPTIM_REG_MAX_VALUE, t);
|
||||
if(ret != HAL_OK)
|
||||
{
|
||||
LOG_E("start %s failed %d", tim_device->name, ret);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_D("start %s success", tim_device->name);
|
||||
return RT_EOK;
|
||||
}
|
||||
}
|
||||
|
||||
static void timer_stop(rt_hwtimer_t *timer)
|
||||
{
|
||||
if(timer == RT_NULL)
|
||||
{
|
||||
LOG_E("stop timer is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
struct stm32_hw_lptimer *tim_device = rt_container_of(timer, struct stm32_hw_lptimer, time_device);
|
||||
LPTIM_HandleTypeDef *tim = (LPTIM_HandleTypeDef *)timer->parent.user_data;
|
||||
|
||||
if(tim_device == RT_NULL)
|
||||
{
|
||||
LOG_E("stop tim_device is NULL");
|
||||
return;
|
||||
}
|
||||
if(tim == RT_NULL)
|
||||
{
|
||||
LOG_E("stop %s LPTIM_Handle is NULL", tim_device->name);
|
||||
return;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef ret = HAL_LPTIM_TimeOut_Stop_IT(tim);
|
||||
if(ret != HAL_OK)
|
||||
{
|
||||
LOG_E("stop %s failed %d", tim_device->name, ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_D("stop %s success", tim_device->name);
|
||||
}
|
||||
}
|
||||
|
||||
static rt_uint32_t timer_get_freq(LPTIM_HandleTypeDef *tim)
|
||||
{
|
||||
/*No calculation is performed. The default initial configuration is 1000hz*/
|
||||
return 1000;
|
||||
}
|
||||
|
||||
|
||||
static rt_uint32_t timer_counter_get(rt_hwtimer_t *timer)
|
||||
{
|
||||
LPTIM_HandleTypeDef *tim = (LPTIM_HandleTypeDef *)timer->parent.user_data;
|
||||
return HAL_LPTIM_ReadCounter(tim);
|
||||
}
|
||||
|
||||
static rt_err_t timer_ctrl(rt_hwtimer_t *timer, rt_uint32_t cmd, void *arg)
|
||||
{
|
||||
if(timer == RT_NULL)
|
||||
{
|
||||
LOG_E("start timer is NULL");
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
struct stm32_hw_lptimer *tim_device = rt_container_of(timer, struct stm32_hw_lptimer, time_device);
|
||||
LPTIM_HandleTypeDef *tim = (LPTIM_HandleTypeDef *)timer->parent.user_data;
|
||||
|
||||
if(tim_device == RT_NULL)
|
||||
{
|
||||
LOG_E("start tim_device is NULL");
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
if(tim == RT_NULL)
|
||||
{
|
||||
LOG_E("start %s LPTIM_Handle is NULL", tim_device->name);
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
rt_err_t result = RT_EOK;
|
||||
switch (cmd)
|
||||
{
|
||||
case DRV_HW_LPTIMER_CTRL_GET_TICK_MAX:
|
||||
{
|
||||
*(rt_uint32_t *)arg = LPTIM_REG_MAX_VALUE;
|
||||
break;
|
||||
}
|
||||
case DRV_HW_LPTIMER_CTRL_GET_FREQ:
|
||||
{
|
||||
*(rt_uint32_t *)arg = timer_get_freq(tim);
|
||||
break;
|
||||
}
|
||||
case DRV_HW_LPTIMER_CTRL_START:
|
||||
{
|
||||
timer_start(timer, *(rt_uint32_t *)arg, HWTIMER_MODE_ONESHOT);
|
||||
break;
|
||||
}
|
||||
case DRV_HW_LPTIMER_CTRL_GET_COUNT:
|
||||
{
|
||||
*(rt_uint32_t *)arg = timer_counter_get(timer);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
result = -RT_ENOSYS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef BSP_USING_LPTIM1
|
||||
void LPTIM1_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
HAL_LPTIM_IRQHandler(&stm32_hw_lptimer_obj[LPTIM1_INDEX].tim_handle);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_LPTIM2
|
||||
void LPTIM2_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
HAL_LPTIM_IRQHandler(&stm32_hw_lptimer_obj[LPTIM2_INDEX].tim_handle);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USING_LPTIM3
|
||||
void LPTIM3_IRQHandler(void)
|
||||
{
|
||||
rt_interrupt_enter();
|
||||
HAL_LPTIM_IRQHandler(&stm32_hw_lptimer_obj[LPTIM3_INDEX].tim_handle);
|
||||
rt_interrupt_leave();
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct rt_hwtimer_ops _ops =
|
||||
{
|
||||
.init = timer_init,
|
||||
.start = timer_start,
|
||||
.stop = timer_stop,
|
||||
.count_get = timer_counter_get,
|
||||
.control = timer_ctrl,
|
||||
};
|
||||
|
||||
/**
|
||||
* This function initialize the lptim
|
||||
*/
|
||||
static int stm32_hw_lptim_init(void)
|
||||
{
|
||||
int i = 0;
|
||||
int result = RT_EOK;
|
||||
|
||||
for (i = 0; i < sizeof(stm32_hw_lptimer_obj) / sizeof(stm32_hw_lptimer_obj[0]); i++)
|
||||
{
|
||||
stm32_hw_lptimer_obj[i].time_device.info = &_info;
|
||||
stm32_hw_lptimer_obj[i].time_device.ops = &_ops;
|
||||
if (rt_device_hwtimer_register(&stm32_hw_lptimer_obj[i].time_device, stm32_hw_lptimer_obj[i].name, &stm32_hw_lptimer_obj[i].tim_handle) == RT_EOK)
|
||||
{
|
||||
LOG_D("%s register success", stm32_hw_lptimer_obj[i].name);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_E("%s register failed", stm32_hw_lptimer_obj[i].name);
|
||||
result = -RT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
INIT_BOARD_EXPORT(stm32_hw_lptim_init);
|
||||
#endif /* BSP_USING_LPTIM */
|
||||
INIT_DEVICE_EXPORT(stm32l4_hw_lptim_init);
|
||||
|
@ -1,12 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-05-06 Zero-Free first version
|
||||
* 2024-07-04 wdfk-prog lptimer is register with hwtimer, only supports pm calls,the timer function is not supported
|
||||
*/
|
||||
|
||||
#ifndef __DRV_PMTIMER_H__
|
||||
@ -14,13 +13,11 @@
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
/* 0x20 - 0x3F udevice control commands*/
|
||||
typedef enum
|
||||
{
|
||||
DRV_HW_LPTIMER_CTRL_GET_TICK_MAX = 0x20, /* get the maximum tick value*/
|
||||
DRV_HW_LPTIMER_CTRL_GET_FREQ = 0X21, /* get the timer frequency*/
|
||||
DRV_HW_LPTIMER_CTRL_START = 0X22, /* set the timeout value*/
|
||||
DRV_HW_LPTIMER_CTRL_GET_COUNT = 0X23, /* get the current count value*/
|
||||
} drv_hw_lptimer_ctrl_t;
|
||||
rt_uint32_t stm32l4_lptim_get_countfreq(void);
|
||||
rt_uint32_t stm32l4_lptim_get_tick_max(void);
|
||||
rt_uint32_t stm32l4_lptim_get_current_tick(void);
|
||||
|
||||
rt_err_t stm32l4_lptim_start(rt_uint32_t load);
|
||||
void stm32l4_lptim_stop(void);
|
||||
|
||||
#endif /* __DRV_PMTIMER_H__ */
|
||||
|
@ -1,50 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-05-06 Zero-Free first version
|
||||
* 2024-07-04 wdfk-prog lptimer is supported
|
||||
*/
|
||||
|
||||
#include <board.h>
|
||||
#include <drv_lptim.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
/*#define DRV_DEBUG*/
|
||||
#define LOG_TAG "drv.pm"
|
||||
#include <drv_log.h>
|
||||
|
||||
#ifdef RT_USING_PM
|
||||
|
||||
#ifndef BSP_USING_PM_TIMER
|
||||
/*
|
||||
! Using LPTIM timer, the maximum sleep time is 65535, less than 1 min. Use RTC alarm timers for longer periods.
|
||||
! For example: packages can be used :https://packages.rt-thread.org/detail.html?package=multi_rtimer
|
||||
*/
|
||||
#ifdef BSP_USING_LPTIM1
|
||||
#define BSP_USING_PM_TIMER "lptim1"
|
||||
#elif BSP_USING_LPTIM2
|
||||
#define BSP_USING_PM_TIMER "lptim2"
|
||||
#elif BSP_USING_LPTIM3
|
||||
#define BSP_USING_PM_TIMER "lptim3"
|
||||
#else
|
||||
#error "Please define BSP_USING_PM_TIMER"
|
||||
#endif
|
||||
|
||||
static rt_device_t timer = RT_NULL;
|
||||
|
||||
/* Re-configure the system clock */
|
||||
rt_weak void SystemClock_ReConfig(uint8_t run_mode)
|
||||
static void uart_console_reconfig(void)
|
||||
{
|
||||
/*todo add your code here*/
|
||||
}
|
||||
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
|
||||
|
||||
rt_weak void stm32_pm_device_run(struct rt_pm *pm, uint8_t mode)
|
||||
{
|
||||
/*todo add your code here*/
|
||||
rt_device_control(rt_console_get_device(), RT_DEVICE_CTRL_CONFIG, &config);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,6 +32,7 @@ static void sleep(struct rt_pm *pm, uint8_t mode)
|
||||
break;
|
||||
|
||||
case PM_SLEEP_MODE_IDLE:
|
||||
// __WFI();
|
||||
break;
|
||||
|
||||
case PM_SLEEP_MODE_LIGHT:
|
||||
@ -76,12 +49,10 @@ static void sleep(struct rt_pm *pm, uint8_t mode)
|
||||
break;
|
||||
|
||||
case PM_SLEEP_MODE_DEEP:
|
||||
#if defined(SOC_SERIES_STM32L4)
|
||||
/* Enter STOP 2 mode */
|
||||
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
|
||||
/* Re-configure the system clock */
|
||||
SystemClock_ReConfig(pm->run_mode);
|
||||
#endif /* defined(SOC_SERIES_STM32L4) */
|
||||
break;
|
||||
|
||||
case PM_SLEEP_MODE_STANDBY:
|
||||
@ -90,17 +61,74 @@ static void sleep(struct rt_pm *pm, uint8_t mode)
|
||||
break;
|
||||
|
||||
case PM_SLEEP_MODE_SHUTDOWN:
|
||||
#if defined(SOC_SERIES_STM32L4)
|
||||
/* Enter SHUTDOWNN mode */
|
||||
HAL_PWREx_EnterSHUTDOWNMode();
|
||||
#endif /* defined(SOC_SERIES_STM32L4) */
|
||||
break;
|
||||
|
||||
default:
|
||||
RT_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t run_speed[PM_RUN_MODE_MAX][2] =
|
||||
{
|
||||
{80, 0},
|
||||
{80, 1},
|
||||
{24, 2},
|
||||
{2, 3},
|
||||
};
|
||||
|
||||
static void run(struct rt_pm *pm, uint8_t mode)
|
||||
{
|
||||
static uint8_t last_mode;
|
||||
static char *run_str[] = PM_RUN_MODE_NAMES;
|
||||
|
||||
if (mode == last_mode)
|
||||
return;
|
||||
last_mode = mode;
|
||||
|
||||
/* 1. 设置 MSI 作为 SYSCLK 时钟源,以修改 PLL */
|
||||
SystemClock_MSI_ON();
|
||||
|
||||
/* 2. 根据RUN模式切换时钟频率(HSI) */
|
||||
switch (mode)
|
||||
{
|
||||
case PM_RUN_MODE_HIGH_SPEED:
|
||||
case PM_RUN_MODE_NORMAL_SPEED:
|
||||
HAL_PWREx_DisableLowPowerRunMode();
|
||||
SystemClock_80M();
|
||||
/* Configure the main internal regulator output voltage (Range1 by default)*/
|
||||
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
|
||||
break;
|
||||
case PM_RUN_MODE_MEDIUM_SPEED:
|
||||
HAL_PWREx_DisableLowPowerRunMode();
|
||||
SystemClock_24M();
|
||||
/* Configure the main internal regulator output voltage */
|
||||
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE2);
|
||||
break;
|
||||
case PM_RUN_MODE_LOW_SPEED:
|
||||
SystemClock_2M();
|
||||
/* Enter LP RUN mode */
|
||||
HAL_PWREx_EnableLowPowerRunMode();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* 3. 关闭 MSI 时钟 */
|
||||
// SystemClock_MSI_OFF();
|
||||
|
||||
/* 4. 更新外设时钟 */
|
||||
uart_console_reconfig();
|
||||
/* Re-Configure the Systick time */
|
||||
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / RT_TICK_PER_SECOND);
|
||||
/* Re-Configure the Systick */
|
||||
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
|
||||
|
||||
rt_kprintf("switch to %s mode, frequency = %d MHz\n", run_str[mode], run_speed[mode][0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function caculate the PM tick from OS tick
|
||||
*
|
||||
@ -108,19 +136,9 @@ static void sleep(struct rt_pm *pm, uint8_t mode)
|
||||
*
|
||||
* @return the PM tick
|
||||
*/
|
||||
static rt_tick_t stm32_pm_tick_from_os_tick(rt_tick_t tick)
|
||||
static rt_tick_t stm32l4_pm_tick_from_os_tick(rt_tick_t tick)
|
||||
{
|
||||
rt_uint32_t freq = 0;
|
||||
rt_err_t ret = rt_device_control(timer, DRV_HW_LPTIMER_CTRL_GET_FREQ, &freq);
|
||||
if(ret != RT_EOK)
|
||||
{
|
||||
LOG_E("Get PM timer %s frequency failed %d", timer->parent.name, ret);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_D("Get PM timer %s frequency %d", timer->parent.name, freq);
|
||||
}
|
||||
rt_uint32_t freq = stm32l4_lptim_get_countfreq();
|
||||
|
||||
return (freq * tick / RT_TICK_PER_SECOND);
|
||||
}
|
||||
@ -132,25 +150,18 @@ static rt_tick_t stm32_pm_tick_from_os_tick(rt_tick_t tick)
|
||||
*
|
||||
* @return the OS tick
|
||||
*/
|
||||
static rt_tick_t stm32_os_tick_from_pm_tick(rt_uint32_t tick)
|
||||
static rt_tick_t stm32l4_os_tick_from_pm_tick(rt_uint32_t tick)
|
||||
{
|
||||
static rt_uint32_t os_tick_remain = 0;
|
||||
rt_tick_t os_tick = 0;
|
||||
rt_uint32_t freq = 0;
|
||||
rt_uint32_t ret, freq;
|
||||
|
||||
rt_err_t ret = rt_device_control(timer, DRV_HW_LPTIMER_CTRL_GET_FREQ, &freq);
|
||||
if(ret != RT_EOK)
|
||||
{
|
||||
LOG_E("Get PM timer %s frequency failed %d", timer->parent.name, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
os_tick = (tick * RT_TICK_PER_SECOND + os_tick_remain) / freq;
|
||||
freq = stm32l4_lptim_get_countfreq();
|
||||
ret = (tick * RT_TICK_PER_SECOND + os_tick_remain) / freq;
|
||||
|
||||
os_tick_remain += (tick * RT_TICK_PER_SECOND);
|
||||
os_tick_remain %= freq;
|
||||
|
||||
return os_tick;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -163,33 +174,18 @@ static void pm_timer_start(struct rt_pm *pm, rt_uint32_t timeout)
|
||||
{
|
||||
RT_ASSERT(pm != RT_NULL);
|
||||
RT_ASSERT(timeout > 0);
|
||||
RT_ASSERT(timer != RT_NULL);
|
||||
|
||||
if (timeout != RT_TICK_MAX)
|
||||
{
|
||||
rt_uint32_t max_tick = 0;
|
||||
rt_err_t ret = rt_device_control(timer, DRV_HW_LPTIMER_CTRL_GET_TICK_MAX, &max_tick);
|
||||
if(ret != RT_EOK)
|
||||
{
|
||||
LOG_E("Get PM timer %s max tick failed %d", timer->parent.name, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert OS Tick to pmtimer timeout value */
|
||||
timeout = stm32_pm_tick_from_os_tick(timeout);
|
||||
|
||||
if (timeout > max_tick)
|
||||
timeout = stm32l4_pm_tick_from_os_tick(timeout);
|
||||
if (timeout > stm32l4_lptim_get_tick_max())
|
||||
{
|
||||
timeout = max_tick;
|
||||
timeout = stm32l4_lptim_get_tick_max();
|
||||
}
|
||||
|
||||
/* Enter PM_TIMER_MODE */
|
||||
ret = rt_device_control(timer, DRV_HW_LPTIMER_CTRL_START, &timeout);
|
||||
if(ret != RT_EOK)
|
||||
{
|
||||
LOG_E("Get PM timer %s max tick failed %d", timer->parent.name, ret);
|
||||
return;
|
||||
}
|
||||
stm32l4_lptim_start(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,7 +199,7 @@ static void pm_timer_stop(struct rt_pm *pm)
|
||||
RT_ASSERT(pm != RT_NULL);
|
||||
|
||||
/* Reset pmtimer status */
|
||||
rt_device_control(timer, HWTIMER_CTRL_STOP, RT_NULL);
|
||||
stm32l4_lptim_stop();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,42 +215,29 @@ static rt_tick_t pm_timer_get_tick(struct rt_pm *pm)
|
||||
|
||||
RT_ASSERT(pm != RT_NULL);
|
||||
|
||||
rt_err_t ret = rt_device_control(timer, DRV_HW_LPTIMER_CTRL_GET_COUNT, &timer_tick);
|
||||
timer_tick = stm32l4_lptim_get_current_tick();
|
||||
|
||||
if(ret != RT_EOK)
|
||||
{
|
||||
LOG_E("Get PM timer %s count failed %d", timer->parent.name, ret);
|
||||
return 0;
|
||||
return stm32l4_os_tick_from_pm_tick(timer_tick);
|
||||
}
|
||||
else
|
||||
{
|
||||
return stm32_os_tick_from_pm_tick(timer_tick);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct rt_pm_ops _ops =
|
||||
{
|
||||
sleep,
|
||||
stm32_pm_device_run,
|
||||
pm_timer_start,
|
||||
pm_timer_stop,
|
||||
pm_timer_get_tick
|
||||
};
|
||||
|
||||
/**
|
||||
* This function initialize the power manager
|
||||
*/
|
||||
int drv_pm_hw_init(void)
|
||||
{
|
||||
static const struct rt_pm_ops _ops =
|
||||
{
|
||||
sleep,
|
||||
run,
|
||||
pm_timer_start,
|
||||
pm_timer_stop,
|
||||
pm_timer_get_tick
|
||||
};
|
||||
|
||||
rt_uint8_t timer_mask = 0;
|
||||
|
||||
/* Enable Power Clock */
|
||||
#if !defined(SOC_SERIES_STM32H7) && !defined(SOC_SERIES_STM32WL) && !defined(SOC_SERIES_STM32WB)
|
||||
__HAL_RCC_PWR_CLK_ENABLE();
|
||||
#ifdef SOC_SERIES_STM32F1
|
||||
__HAL_RCC_BKP_CLK_ENABLE();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* initialize timer mask */
|
||||
timer_mask = 1UL << PM_SLEEP_MODE_DEEP;
|
||||
@ -262,18 +245,7 @@ int drv_pm_hw_init(void)
|
||||
/* initialize system pm module */
|
||||
rt_system_pm_init(&_ops, timer_mask, RT_NULL);
|
||||
|
||||
timer = rt_device_find(BSP_USING_PM_TIMER);
|
||||
|
||||
if(timer == RT_NULL)
|
||||
{
|
||||
LOG_E("Can't find PM timer device");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
return rt_device_init(timer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
INIT_CORE_EXPORT(drv_pm_hw_init);
|
||||
#endif /* RT_USING_PM */
|
||||
INIT_BOARD_EXPORT(drv_pm_hw_init);
|
||||
|
@ -15,7 +15,7 @@
|
||||
#ifdef BSP_USING_PWM
|
||||
#include "drv_config.h"
|
||||
#include "drv_tim.h"
|
||||
#include <drivers/dev_pwm.h>
|
||||
#include <drivers/rt_drv_pwm.h>
|
||||
|
||||
//#define DRV_DEBUG
|
||||
#define LOG_TAG "drv.pwm"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -22,7 +22,7 @@
|
||||
#define RTC_BKP_DR1 RT_NULL
|
||||
#endif
|
||||
|
||||
/* #define DRV_DEBUG*/
|
||||
//#define DRV_DEBUG
|
||||
#define LOG_TAG "drv.rtc"
|
||||
#include <drv_log.h>
|
||||
|
||||
@ -393,7 +393,7 @@ static rt_err_t rtc_alarm_time_set(struct rtc_device_object* p_dev)
|
||||
|
||||
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
|
||||
{
|
||||
/*LOG_D("rtc alarm isr.\n");*/
|
||||
//LOG_D("rtc alarm isr.\n");
|
||||
rt_alarm_update(&rtc_device.rtc_dev.parent, 1);
|
||||
}
|
||||
|
||||
@ -424,5 +424,5 @@ static int rt_hw_rtc_init(void)
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
INIT_BOARD_EXPORT(rt_hw_rtc_init);
|
||||
INIT_DEVICE_EXPORT(rt_hw_rtc_init);
|
||||
#endif /* BSP_USING_ONCHIP_RTC */
|
||||
|
@ -17,8 +17,8 @@
|
||||
#include <drv_common.h>
|
||||
#include "drv_dma.h"
|
||||
#include <string.h>
|
||||
#include <drivers/dev_mmcsd_core.h>
|
||||
#include <drivers/dev_sdio.h>
|
||||
#include <drivers/mmcsd_core.h>
|
||||
#include <drivers/sdio.h>
|
||||
|
||||
#if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4)
|
||||
#define SDCARD_INSTANCE_TYPE SDIO_TypeDef
|
||||
@ -35,6 +35,10 @@
|
||||
#define SDIO_BUFF_SIZE 4096
|
||||
#define SDIO_ALIGN_LEN 32
|
||||
|
||||
#ifndef SDIO_MAX_FREQ
|
||||
#define SDIO_MAX_FREQ (1000000)
|
||||
#endif
|
||||
|
||||
#ifndef SDIO_BASE_ADDRESS
|
||||
#define SDIO_BASE_ADDRESS (0x40012800U)
|
||||
#endif
|
||||
|
@ -18,8 +18,8 @@
|
||||
#include <rthw.h>
|
||||
#include <drv_common.h>
|
||||
#include <string.h>
|
||||
#include <drivers/dev_mmcsd_core.h>
|
||||
#include <drivers/dev_sdio.h>
|
||||
#include <drivers/mmcsd_core.h>
|
||||
#include <drivers/sdio.h>
|
||||
|
||||
#define SDIO_BUFF_SIZE 4096
|
||||
#define SDIO_ALIGN_LEN 32
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -156,6 +156,36 @@ void stm32_dir_miso(void *data, rt_int32_t state)
|
||||
}
|
||||
}
|
||||
|
||||
static void stm32_udelay(rt_uint32_t us)
|
||||
{
|
||||
rt_uint32_t ticks;
|
||||
rt_uint32_t told, tnow, tcnt = 0;
|
||||
rt_uint32_t reload = SysTick->LOAD;
|
||||
|
||||
ticks = us * reload / (1000000UL / RT_TICK_PER_SECOND);
|
||||
told = SysTick->VAL;
|
||||
while (1)
|
||||
{
|
||||
tnow = SysTick->VAL;
|
||||
if (tnow != told)
|
||||
{
|
||||
if (tnow < told)
|
||||
{
|
||||
tcnt += told - tnow;
|
||||
}
|
||||
else
|
||||
{
|
||||
tcnt += reload - tnow + told;
|
||||
}
|
||||
told = tnow;
|
||||
if (tcnt >= ticks)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void stm32_pin_init(void)
|
||||
{
|
||||
rt_size_t obj_num = sizeof(spi_obj) / sizeof(struct stm32_soft_spi);
|
||||
@ -179,7 +209,7 @@ static struct rt_spi_bit_ops stm32_soft_spi_ops =
|
||||
.get_miso = stm32_get_miso,
|
||||
.dir_mosi = stm32_dir_mosi,
|
||||
.dir_miso = stm32_dir_miso,
|
||||
.udelay = rt_hw_us_delay,
|
||||
.udelay = stm32_udelay,
|
||||
.delay_us = 1,
|
||||
};
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdevice.h>
|
||||
#include <dev_spi_bit_ops.h>
|
||||
#include <spi-bit-ops.h>
|
||||
|
||||
/* stm32 soft spi config */
|
||||
struct stm32_soft_spi_config
|
||||
|
@ -357,7 +357,7 @@ static int stm32_putc(struct rt_serial_device *serial, char c)
|
||||
#else
|
||||
uart->handle.Instance->DR = c;
|
||||
#endif
|
||||
while (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC) == RESET && --block_timeout);
|
||||
while (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC) == RESET && block_timeout--);
|
||||
return (block_timeout != 0) ? 1 : -1;
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,7 @@
|
||||
[](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,32 +162,20 @@ endif
|
||||
bool "Using devfs for device objects"
|
||||
default y
|
||||
|
||||
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
|
||||
config RT_USING_DFS_ROMFS
|
||||
bool "Enable ReadOnly file system on flash"
|
||||
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
|
||||
depends on RT_USING_DFS_ROMFS
|
||||
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,6 +1,4 @@
|
||||
from building import *
|
||||
from gcc import *
|
||||
import rtconfig
|
||||
import os
|
||||
|
||||
# The set of source files associated with this SConscript file.
|
||||
@ -8,7 +6,6 @@ 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']
|
||||
@ -16,12 +13,7 @@ if GetDepend('RT_USING_DFS') and not GetDepend('RT_USING_DFS_V2'):
|
||||
if GetDepend('DFS_USING_POSIX'):
|
||||
src += ['src/dfs_posix.c']
|
||||
|
||||
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)
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS'], CPPPATH = CPPPATH)
|
||||
|
||||
# search in the file system implementation
|
||||
list = os.listdir(cwd)
|
||||
|
@ -1,11 +0,0 @@
|
||||
# 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')
|
@ -1,698 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,16 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
ssize_t dfs_ramfs_read(struct dfs_file *file, void *buf, size_t count)
|
||||
int dfs_ramfs_read(struct dfs_file *file, void *buf, size_t count)
|
||||
{
|
||||
rt_size_t length;
|
||||
struct ramfs_dirent *dirent;
|
||||
@ -114,7 +114,7 @@ ssize_t dfs_ramfs_read(struct dfs_file *file, void *buf, size_t count)
|
||||
return length;
|
||||
}
|
||||
|
||||
ssize_t dfs_ramfs_write(struct dfs_file *fd, const void *buf, size_t count)
|
||||
int 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 @@ ssize_t dfs_ramfs_write(struct dfs_file *fd, const void *buf, size_t count)
|
||||
return count;
|
||||
}
|
||||
|
||||
off_t dfs_ramfs_lseek(struct dfs_file *file, off_t offset)
|
||||
int dfs_ramfs_lseek(struct dfs_file *file, off_t offset)
|
||||
{
|
||||
if (offset <= (off_t)file->vnode->size)
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -107,8 +107,7 @@ int dfs_init(void)
|
||||
INIT_PREV_EXPORT(dfs_init);
|
||||
|
||||
/**
|
||||
* @brief this function will lock device file system.
|
||||
* this lock (fslock) is used for protecting filesystem_operation_table and filesystem_table.
|
||||
* this function will lock device file system.
|
||||
*
|
||||
* @note please don't invoke it on ISR.
|
||||
*/
|
||||
@ -127,12 +126,6 @@ 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;
|
||||
@ -149,7 +142,7 @@ void dfs_file_lock(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief this function will unlock device file system.
|
||||
* this function will lock device file system.
|
||||
*
|
||||
* @note please don't invoke it on ISR.
|
||||
*/
|
||||
@ -158,56 +151,33 @@ void dfs_unlock(void)
|
||||
rt_mutex_release(&fslock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief this function will unlock fd table.
|
||||
*/
|
||||
#ifdef DFS_USING_POSIX
|
||||
|
||||
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)
|
||||
{
|
||||
@ -219,23 +189,12 @@ 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;
|
||||
@ -260,17 +219,6 @@ 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;
|
||||
@ -375,11 +323,7 @@ struct dfs_file *fd_get(int fd)
|
||||
/**
|
||||
* @ingroup Fd
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* This function will put the file descriptor.
|
||||
*/
|
||||
void fdt_fd_release(struct dfs_fdtable* fdt, int fd)
|
||||
{
|
||||
@ -434,20 +378,6 @@ 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;
|
||||
@ -540,23 +470,6 @@ 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;
|
||||
@ -637,10 +550,6 @@ 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;
|
||||
@ -649,21 +558,6 @@ 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;
|
||||
@ -697,10 +591,6 @@ 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-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -18,12 +18,10 @@
|
||||
|
||||
#define DFS_VNODE_HASH_NR 128
|
||||
|
||||
/*dfs vnode manager, for saving and searching vnodes.*/
|
||||
struct dfs_vnode_mgr
|
||||
{
|
||||
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. */
|
||||
struct rt_mutex lock;
|
||||
rt_list_t head[DFS_VNODE_HASH_NR];
|
||||
};
|
||||
|
||||
static struct dfs_vnode_mgr dfs_fm;
|
||||
@ -38,10 +36,6 @@ 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;
|
||||
@ -53,23 +47,6 @@ 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)
|
||||
@ -87,7 +64,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)
|
||||
@ -98,22 +75,6 @@ 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;
|
||||
@ -368,12 +329,11 @@ int dfs_file_close(struct dfs_file *fd)
|
||||
}
|
||||
|
||||
/**
|
||||
* this function will perform an io control on a file descriptor.
|
||||
* this function will perform a 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.
|
||||
*/
|
||||
@ -886,7 +846,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, length);
|
||||
rt_device_write(out_device, 0, (void *)buffer, sizeof(buffer));
|
||||
}
|
||||
} while (length > 0);
|
||||
rt_kprintf("\n");
|
||||
@ -1066,14 +1026,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)
|
||||
@ -1093,7 +1053,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-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2021, 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 &&
|
||||
rt_device_open(fs->dev_id, RT_DEVICE_OFLAG_RDONLY) != RT_EOK)
|
||||
if (rt_device_open(fs->dev_id,
|
||||
RT_DEVICE_OFLAG_RDWR) != RT_EOK)
|
||||
{
|
||||
/* The underlying device has error, clear the entry. */
|
||||
dfs_lock();
|
||||
@ -529,8 +529,7 @@ 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;
|
||||
}
|
||||
@ -539,8 +538,7 @@ 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-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -28,17 +28,7 @@
|
||||
* return a file descriptor according specified flags.
|
||||
*
|
||||
* @param file the path name of file.
|
||||
* @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
|
||||
* @param flags the file open flags.
|
||||
*
|
||||
* @return the non-negative integer on successful open, others for failed.
|
||||
*/
|
||||
@ -75,22 +65,6 @@ 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;
|
||||
@ -267,22 +241,14 @@ ssize_t write(int fd, const void *buf, size_t len)
|
||||
RTM_EXPORT(write);
|
||||
|
||||
/**
|
||||
* this function is a POSIX compliant version, which will Reposition the file offset for
|
||||
* this function is a POSIX compliant version, which will seek the offset for
|
||||
* an open file descriptor.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
* @param offset the offset to be seeked.
|
||||
* @param whence the directory of seek.
|
||||
*
|
||||
* @return the resulting read/write position in the file, or -1 on failed.
|
||||
* @return the current read/write position in the file, or -1 on failed.
|
||||
*/
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
@ -470,15 +436,9 @@ RTM_EXPORT(fsync);
|
||||
* control functions on devices.
|
||||
*
|
||||
* @param fildes the file description
|
||||
* @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 cmd the specified command
|
||||
* @param ... represents the additional information that is needed by this
|
||||
* specific device to perform the requested function. For example:
|
||||
* - When `cmd` is `F_SETFL`, an additional integer argument specifies the new status flags.
|
||||
* specific device to perform the requested function.
|
||||
*
|
||||
* @return 0 on successful completion. Otherwise, -1 shall be returned and errno
|
||||
* set to indicate the error.
|
||||
@ -635,7 +595,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 The permission mode for the new directory (unused here, can be set to 0).
|
||||
* @param mode
|
||||
*
|
||||
* @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;
|
||||
ssize_t length = 0;
|
||||
uint32_t length = 0;
|
||||
|
||||
ci = (cromfs_info *)file->dentry->mnt->data;
|
||||
fi = (file_info *)file->vnode->data;
|
||||
|
||||
if ((off_t)count < (off_t)file->vnode->size - *pos)
|
||||
if (count < file->vnode->size - *pos)
|
||||
{
|
||||
length = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = (off_t)file->vnode->size - *pos;
|
||||
length = file->vnode->size - *pos;
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
|
@ -11,9 +11,6 @@
|
||||
#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,7 +77,6 @@ static int dfs_devfs_open(struct dfs_file *file)
|
||||
}
|
||||
}
|
||||
}
|
||||
rt_free(device_name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -114,29 +113,6 @@ 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;
|
||||
@ -159,16 +135,11 @@ static ssize_t dfs_devfs_read(struct dfs_file *file, void *buf, size_t count, of
|
||||
if (device->ops)
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
{
|
||||
rt_ubase_t shift = _get_unit_shift(device);
|
||||
|
||||
ret = rt_device_read(device, *pos, buf, count >> shift);
|
||||
if (ret > 0)
|
||||
{
|
||||
ret <<= shift;
|
||||
/* read device data */
|
||||
ret = rt_device_read(device, *pos, buf, count);
|
||||
*pos += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -198,17 +169,11 @@ 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 >> shift);
|
||||
if (ret > 0)
|
||||
{
|
||||
ret <<= shift;
|
||||
ret = rt_device_write(device, *pos, buf, count);
|
||||
*pos += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -300,7 +265,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 = -EPERM;
|
||||
off_t ret = 0;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
@ -443,16 +408,16 @@ mode_t dfs_devfs_device_to_mode(struct rt_device *device)
|
||||
switch (device->type)
|
||||
{
|
||||
case RT_Device_Class_Char:
|
||||
mode = S_IFCHR | 0666;
|
||||
mode = S_IFCHR | 0777;
|
||||
break;
|
||||
case RT_Device_Class_Block:
|
||||
mode = S_IFBLK | 0666;
|
||||
mode = S_IFBLK | 0777;
|
||||
break;
|
||||
case RT_Device_Class_Pipe:
|
||||
mode = S_IFIFO | 0666;
|
||||
mode = S_IFIFO | 0777;
|
||||
break;
|
||||
default:
|
||||
mode = S_IFCHR | 0666;
|
||||
mode = S_IFCHR | 0777;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_mnt.h>
|
||||
#include <dfs_vfs.h>
|
||||
#include <devfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -35,7 +34,8 @@ struct devtmpfs_file
|
||||
char name[DIRENT_NAME_MAX]; /* file name */
|
||||
|
||||
rt_uint32_t type; /* file type */
|
||||
struct dfs_vfs_node node; /* file node in the devtmpfs */
|
||||
rt_list_t subdirs; /* file subdir list */
|
||||
rt_list_t sibling; /* file sibling list */
|
||||
|
||||
struct devtmpfs_sb *sb; /* superblock ptr */
|
||||
|
||||
@ -48,6 +48,7 @@ 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 */
|
||||
};
|
||||
|
||||
@ -110,13 +111,15 @@ static int _get_subdir(const char *path, char *name)
|
||||
#if 0
|
||||
static int _free_subdir(struct devtmpfs_file *dfile)
|
||||
{
|
||||
struct devtmpfs_file *file, *tmp;
|
||||
struct devtmpfs_file *file;
|
||||
rt_list_t *list, *temp_list;
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
|
||||
|
||||
dfs_vfs_for_each_subnode(file, tmp, dfile, node)
|
||||
rt_list_for_each_safe(list, temp_list, &dfile->subdirs)
|
||||
{
|
||||
file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
||||
if (file->type == TMPFS_TYPE_DIR)
|
||||
{
|
||||
_free_subdir(file);
|
||||
@ -131,7 +134,7 @@ static int _free_subdir(struct devtmpfs_file *dfile)
|
||||
RT_ASSERT(superblock);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
dfs_vfs_remove_node(&file->node);
|
||||
rt_list_remove(&(file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(file);
|
||||
@ -149,12 +152,14 @@ 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);
|
||||
dfs_vfs_init_node(&superblock->root.node);
|
||||
rt_list_init(&superblock->root.sibling);
|
||||
rt_list_init(&superblock->root.subdirs);
|
||||
|
||||
rt_spin_lock_init(&superblock->lock);
|
||||
|
||||
@ -188,7 +193,8 @@ 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, *tmp;
|
||||
struct devtmpfs_file *file, *curfile;
|
||||
rt_list_t *list;
|
||||
|
||||
subpath = path;
|
||||
while (*subpath == '/' && *subpath)
|
||||
@ -216,8 +222,9 @@ find_subpath:
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
|
||||
dfs_vfs_for_each_subnode(file, tmp, curfile, node)
|
||||
rt_list_for_each(list, &curfile->subdirs)
|
||||
{
|
||||
file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
||||
if (filename) /* find file */
|
||||
{
|
||||
if (rt_strcmp(file->name, filename) == 0)
|
||||
@ -286,9 +293,7 @@ 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)
|
||||
{
|
||||
rt_size_t index, end;
|
||||
struct dirent *d;
|
||||
struct devtmpfs_file *d_file, *n_file = RT_NULL, *tmp;
|
||||
struct devtmpfs_file *d_file;
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(file);
|
||||
@ -301,6 +306,11 @@ 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)
|
||||
@ -312,10 +322,12 @@ static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_
|
||||
index = 0;
|
||||
count = 0;
|
||||
|
||||
dfs_vfs_for_each_subnode(n_file, tmp, d_file, node)
|
||||
rt_list_for_each(list, &d_file->subdirs)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -366,7 +378,8 @@ static int devtmpfs_symlink(struct dfs_dentry *parent_dentry, const char *target
|
||||
|
||||
strncpy(l_file->name, linkpath, DIRENT_NAME_MAX - 1);
|
||||
|
||||
dfs_vfs_init_node(&l_file->node);
|
||||
rt_list_init(&(l_file->subdirs));
|
||||
rt_list_init(&(l_file->sibling));
|
||||
l_file->sb = superblock;
|
||||
l_file->type = TMPFS_TYPE_FILE;
|
||||
l_file->mode = p_file->mode;
|
||||
@ -375,7 +388,7 @@ static int devtmpfs_symlink(struct dfs_dentry *parent_dentry, const char *target
|
||||
l_file->link = rt_strdup(target);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
dfs_vfs_append_node(&p_file->node, &l_file->node);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(l_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
}
|
||||
}
|
||||
@ -447,7 +460,7 @@ static int devtmpfs_unlink(struct dfs_dentry *dentry)
|
||||
}
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
dfs_vfs_remove_node(&d_file->node);
|
||||
rt_list_remove(&(d_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(d_file);
|
||||
@ -524,7 +537,8 @@ static struct dfs_vnode *devtmpfs_create_vnode(struct dfs_dentry *dentry, int ty
|
||||
|
||||
strncpy(d_file->name, file_name, DIRENT_NAME_MAX);
|
||||
|
||||
dfs_vfs_init_node(&d_file->node);
|
||||
rt_list_init(&(d_file->subdirs));
|
||||
rt_list_init(&(d_file->sibling));
|
||||
d_file->sb = superblock;
|
||||
|
||||
vnode->nlink = 1;
|
||||
@ -549,7 +563,7 @@ static struct dfs_vnode *devtmpfs_create_vnode(struct dfs_dentry *dentry, int ty
|
||||
d_file->mode = vnode->mode;
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
dfs_vfs_append_node(&p_file->node, &d_file->node);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
}
|
||||
|
||||
|
@ -1,166 +0,0 @@
|
||||
# 进程文件系统 (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`
|
@ -1,11 +0,0 @@
|
||||
# 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')
|
@ -1,733 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* 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
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,307 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,101 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,215 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,449 +0,0 @@
|
||||
/*
|
||||
* 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
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* 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
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,447 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
/*
|
||||
* 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", (unsigned long)rc);
|
||||
snprintf(pts_file->basename, DIRENT_NAME_MAX, "%lu", 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", (unsigned long)ptsno);
|
||||
snprintf(path_buf, sizeof(path_buf), "%lu", ptsno);
|
||||
pts_file = ptyfile_lookup(sb, path_buf);
|
||||
if (pts_file)
|
||||
{
|
||||
|
@ -365,7 +365,6 @@ 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,13 +99,15 @@ static int _get_subdir(const char *path, char *name)
|
||||
|
||||
static int _free_subdir(struct tmpfs_file *dfile)
|
||||
{
|
||||
struct tmpfs_file *file = RT_NULL, *tmp;
|
||||
struct tmpfs_file *file;
|
||||
rt_list_t *list, *temp_list;
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
|
||||
|
||||
dfs_vfs_for_each_subnode(file, tmp, dfile, node)
|
||||
rt_list_for_each_safe(list, temp_list, &dfile->subdirs)
|
||||
{
|
||||
file = rt_list_entry(list, struct tmpfs_file, sibling);
|
||||
if (file->type == TMPFS_TYPE_DIR)
|
||||
{
|
||||
_free_subdir(file);
|
||||
@ -120,7 +122,7 @@ static int _free_subdir(struct tmpfs_file *dfile)
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
dfs_vfs_remove_node(&file->node);
|
||||
rt_list_remove(&(file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(file);
|
||||
@ -139,11 +141,13 @@ 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;
|
||||
dfs_vfs_init_node(&superblock->root.node);
|
||||
rt_list_init(&superblock->root.sibling);
|
||||
rt_list_init(&superblock->root.subdirs);
|
||||
|
||||
rt_spin_lock_init(&superblock->lock);
|
||||
|
||||
@ -232,7 +236,8 @@ 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, *tmp;
|
||||
struct tmpfs_file *file, *curfile;
|
||||
rt_list_t *list;
|
||||
|
||||
subpath = path;
|
||||
while (*subpath == '/' && *subpath)
|
||||
@ -260,8 +265,9 @@ find_subpath:
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
|
||||
dfs_vfs_for_each_subnode(file, tmp, curfile, node)
|
||||
rt_list_for_each(list, &curfile->subdirs)
|
||||
{
|
||||
file = rt_list_entry(list, struct tmpfs_file, sibling);
|
||||
if (filename) /* find file */
|
||||
{
|
||||
if (rt_strcmp(file->name, filename) == 0)
|
||||
@ -497,7 +503,8 @@ static int dfs_tmpfs_getdents(struct dfs_file *file,
|
||||
{
|
||||
rt_size_t index, end;
|
||||
struct dirent *d;
|
||||
struct tmpfs_file *d_file, *n_file, *tmp;
|
||||
struct tmpfs_file *d_file, *n_file;
|
||||
rt_list_t *list;
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
d_file = (struct tmpfs_file *)file->vnode->data;
|
||||
@ -520,8 +527,9 @@ static int dfs_tmpfs_getdents(struct dfs_file *file,
|
||||
index = 0;
|
||||
count = 0;
|
||||
|
||||
dfs_vfs_for_each_subnode(n_file, tmp, d_file, node)
|
||||
rt_list_for_each(list, &d_file->subdirs)
|
||||
{
|
||||
n_file = rt_list_entry(list, struct tmpfs_file, sibling);
|
||||
if (index >= (rt_size_t)file->fpos)
|
||||
{
|
||||
d = dirp + count;
|
||||
@ -565,7 +573,7 @@ static int dfs_tmpfs_unlink(struct dfs_dentry *dentry)
|
||||
return -ENOENT;
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
dfs_vfs_remove_node(&d_file->node);
|
||||
rt_list_remove(&(d_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
if (rt_atomic_load(&(dentry->ref_count)) == 1)
|
||||
@ -623,13 +631,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);
|
||||
dfs_vfs_remove_node(&d_file->node);
|
||||
rt_list_remove(&(d_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
dfs_vfs_append_node(&p_file->node, &d_file->node);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(parent_path);
|
||||
@ -737,7 +745,8 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t
|
||||
|
||||
strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
|
||||
|
||||
dfs_vfs_init_node(&d_file->node);
|
||||
rt_list_init(&(d_file->subdirs));
|
||||
rt_list_init(&(d_file->sibling));
|
||||
d_file->data = NULL;
|
||||
d_file->size = 0;
|
||||
d_file->sb = superblock;
|
||||
@ -758,7 +767,7 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t
|
||||
#endif
|
||||
}
|
||||
rt_spin_lock(&superblock->lock);
|
||||
dfs_vfs_append_node(&p_file->node, &d_file->node);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
vnode->mnt = dentry->mnt;
|
||||
|
@ -12,7 +12,6 @@
|
||||
#define __DFS_TMPFS_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <dfs_vfs.h>
|
||||
|
||||
#define TMPFS_NAME_MAX 32
|
||||
#define TMPFS_MAGIC 0x0B0B0B0B
|
||||
@ -26,7 +25,8 @@ struct tmpfs_file
|
||||
{
|
||||
rt_uint32_t type; /* file type */
|
||||
char name[TMPFS_NAME_MAX]; /* file name */
|
||||
struct dfs_vfs_node node; /* file node in the tmpfs */
|
||||
rt_list_t subdirs; /* file subdir list */
|
||||
rt_list_t sibling; /* file sibling list */
|
||||
struct tmpfs_sb *sb; /* superblock ptr */
|
||||
rt_uint8_t *data; /* file date ptr */
|
||||
rt_size_t size; /* file size */
|
||||
|
@ -20,38 +20,6 @@ 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
|
||||
{
|
||||
@ -119,7 +87,6 @@ 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,8 +39,6 @@ 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 */
|
||||
|
||||
@ -62,16 +60,9 @@ 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,7 +118,6 @@ 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);
|
||||
off_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence);
|
||||
ssize_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);
|
||||
|
||||
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* 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,7 +537,6 @@ 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])
|
||||
@ -669,17 +668,12 @@ 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 err < 0 ? err : newfd;
|
||||
return (sysret_t)newfd;
|
||||
#else
|
||||
return err < 0 ? err : newfd;
|
||||
return newfd;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1379,7 +1379,6 @@ int dfs_file_link(const char *oldname, const char *newname)
|
||||
|
||||
if (dfs_file_isdir(oldname) == 0)
|
||||
{
|
||||
rt_set_errno(-EPERM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1568,10 +1567,6 @@ 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,52 +95,6 @@ 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 <- - - - - - - +
|
||||
@ -173,7 +127,7 @@ int dfs_mount(const char *device_name,
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_set_errno(ENODEV);
|
||||
rt_set_errno(ENOENT);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
@ -346,7 +300,7 @@ int dfs_mount(const char *device_name,
|
||||
|
||||
int dfs_umount(const char *specialfile, int flags)
|
||||
{
|
||||
int ret = -1;
|
||||
int ret = -RT_ERROR;
|
||||
char *fullpath = RT_NULL;
|
||||
struct dfs_mnt *mnt = RT_NULL;
|
||||
|
||||
@ -360,7 +314,7 @@ int dfs_umount(const char *specialfile, int flags)
|
||||
if (strcmp(mnt->fullpath, fullpath) == 0)
|
||||
{
|
||||
/* is the mount point */
|
||||
rt_base_t ref_count = rt_atomic_load(&(mnt->ref_count));
|
||||
rt_atomic_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)))
|
||||
{
|
||||
@ -373,19 +327,17 @@ int dfs_umount(const char *specialfile, int flags)
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_I("the file system is busy!");
|
||||
ret = -EBUSY;
|
||||
LOG_E("the file system is busy!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_I("the path:%s is not a mountpoint!", fullpath);
|
||||
ret = -EINVAL;
|
||||
LOG_E("the path:%s is not a mountpoint!", fullpath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_I("no filesystem found.");
|
||||
LOG_E("no filesystem found.");
|
||||
}
|
||||
rt_free(fullpath);
|
||||
}
|
||||
|
@ -10,21 +10,17 @@
|
||||
|
||||
#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
|
||||
*
|
||||
@ -79,7 +75,6 @@ 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);
|
||||
@ -250,21 +245,18 @@ struct dfs_mnt* dfs_mnt_ref(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)
|
||||
{
|
||||
ref_count = rt_atomic_sub(&(mnt->ref_count), 1) - 1;
|
||||
rt_atomic_sub(&(mnt->ref_count), 1);
|
||||
|
||||
if (ref_count == 0)
|
||||
if (rt_atomic_load(&(mnt->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 */
|
||||
@ -286,21 +278,6 @@ 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,19 +13,17 @@
|
||||
#define DBG_LVL DBG_WARNING
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <dfs_pcache.h>
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_mnt.h>
|
||||
#include "dfs_pcache.h"
|
||||
#include "dfs_dentry.h"
|
||||
#include "dfs_mnt.h"
|
||||
#include "mm_page.h"
|
||||
#include <mmu.h>
|
||||
#include <tlb.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
|
||||
@ -162,7 +160,7 @@ void dfs_pcache_release(size_t count)
|
||||
dfs_pcache_unlock();
|
||||
}
|
||||
|
||||
static void _pcache_clean(struct dfs_mnt *mnt, int (*cb)(struct dfs_aspace *aspace))
|
||||
void dfs_pcache_unmount(struct dfs_mnt *mnt)
|
||||
{
|
||||
rt_list_t *node = RT_NULL;
|
||||
struct dfs_aspace *aspace = RT_NULL;
|
||||
@ -177,7 +175,7 @@ static void _pcache_clean(struct dfs_mnt *mnt, int (*cb)(struct dfs_aspace *aspa
|
||||
if (aspace && aspace->mnt == mnt)
|
||||
{
|
||||
dfs_aspace_clean(aspace);
|
||||
cb(aspace);
|
||||
dfs_aspace_release(aspace);
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,28 +187,13 @@ static void _pcache_clean(struct dfs_mnt *mnt, int (*cb)(struct dfs_aspace *aspa
|
||||
if (aspace && aspace->mnt == mnt)
|
||||
{
|
||||
dfs_aspace_clean(aspace);
|
||||
cb(aspace);
|
||||
dfs_aspace_release(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;
|
||||
@ -1155,21 +1138,14 @@ 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)
|
||||
@ -1404,8 +1380,7 @@ int dfs_aspace_unmap(struct dfs_file *file, struct rt_varea *varea)
|
||||
|
||||
rt_varea_unmap_page(map_varea, vaddr);
|
||||
|
||||
if (!rt_varea_is_private_locked(varea) &&
|
||||
page->fpos < page->aspace->vnode->size)
|
||||
if (varea->attr == MMU_MAP_U_RWCB && page->fpos < page->aspace->vnode->size)
|
||||
{
|
||||
dfs_page_dirty(page);
|
||||
}
|
||||
@ -1450,7 +1425,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 (!rt_varea_is_private_locked(varea))
|
||||
if (varea->attr == MMU_MAP_U_RWCB)
|
||||
{
|
||||
dfs_page_dirty(page);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@ -31,17 +31,7 @@
|
||||
* return a file descriptor according specified flags.
|
||||
*
|
||||
* @param file the path name of file.
|
||||
* @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
|
||||
* @param flags the file open flags.
|
||||
*
|
||||
* @return the non-negative integer on successful open, others for failed.
|
||||
*/
|
||||
@ -91,22 +81,6 @@ 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;
|
||||
@ -197,7 +171,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)
|
||||
@ -400,22 +374,14 @@ ssize_t write(int fd, const void *buf, size_t len)
|
||||
RTM_EXPORT(write);
|
||||
|
||||
/**
|
||||
* this function is a POSIX compliant version, which will Reposition the file offset for
|
||||
* this function is a POSIX compliant version, which will seek the offset for
|
||||
* an open file descriptor.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
* @param offset the offset to be seeked.
|
||||
* @param whence the directory of seek.
|
||||
*
|
||||
* @return the resulting read/write position in the file, or -1 on failed.
|
||||
* @return the current read/write position in the file, or -1 on failed.
|
||||
*/
|
||||
off_t lseek(int fd, off_t offset, int whence)
|
||||
{
|
||||
@ -433,7 +399,7 @@ off_t lseek(int fd, off_t offset, int whence)
|
||||
result = dfs_file_lseek(file, offset, whence);
|
||||
if (result < 0)
|
||||
{
|
||||
rt_set_errno(-EPERM);
|
||||
rt_set_errno(result);
|
||||
|
||||
return -1;
|
||||
}
|
||||
@ -615,15 +581,9 @@ RTM_EXPORT(fsync);
|
||||
* control functions on devices.
|
||||
*
|
||||
* @param fildes the file description
|
||||
* @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 cmd the specified command
|
||||
* @param ... represents the additional information that is needed by this
|
||||
* specific device to perform the requested function. For example:
|
||||
* - When `cmd` is `F_SETFL`, an additional integer argument specifies the new status flags.
|
||||
* specific device to perform the requested function.
|
||||
*
|
||||
* @return 0 on successful completion. Otherwise, -1 shall be returned and errno
|
||||
* set to indicate the error.
|
||||
@ -805,7 +765,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 The permission mode for the new directory (unused here, can be set to 0).
|
||||
* @param mode
|
||||
*
|
||||
* @return 0 on successful, others on failed.
|
||||
*/
|
||||
@ -867,7 +827,7 @@ int rmdir(const char *pathname)
|
||||
|
||||
if (!pathname)
|
||||
{
|
||||
rt_set_errno(-EPERM);
|
||||
rt_set_errno(-RT_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -892,7 +852,7 @@ int rmdir(const char *pathname)
|
||||
|
||||
if (dirent)
|
||||
{
|
||||
rt_set_errno(-EPERM);
|
||||
rt_set_errno(-RT_ERROR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -901,7 +861,7 @@ int rmdir(const char *pathname)
|
||||
{
|
||||
if (S_ISLNK(stat.st_mode))
|
||||
{
|
||||
rt_set_errno(-EPERM);
|
||||
rt_set_errno(-RT_ERROR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ Enomem:
|
||||
goto Done;
|
||||
}
|
||||
|
||||
off_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence)
|
||||
ssize_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,21 +21,8 @@ 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"
|
||||
|
@ -1,22 +0,0 @@
|
||||
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
|
@ -1,21 +0,0 @@
|
||||
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')
|
@ -1,206 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@ -1,896 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@ -1,612 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2017-05-09 Urey first version
|
||||
* 2019-07-09 Zero-Free improve device ops interface and data flows
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <rthw.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "audio"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
REPLAY_EVT_NONE = 0x00,
|
||||
REPLAY_EVT_START = 0x01,
|
||||
REPLAY_EVT_STOP = 0x02,
|
||||
};
|
||||
|
||||
static rt_err_t _audio_send_replay_frame(struct rt_audio_device *audio)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
rt_uint8_t *data;
|
||||
rt_size_t dst_size, src_size;
|
||||
rt_uint16_t position, remain_bytes = 0, index = 0;
|
||||
struct rt_audio_buf_info *buf_info;
|
||||
|
||||
RT_ASSERT(audio != RT_NULL);
|
||||
|
||||
buf_info = &audio->replay->buf_info;
|
||||
/* save current pos */
|
||||
position = audio->replay->pos;
|
||||
dst_size = buf_info->block_size;
|
||||
|
||||
/* check replay queue is empty */
|
||||
if (rt_data_queue_peek(&audio->replay->queue, (const void **)&data, &src_size) != RT_EOK)
|
||||
{
|
||||
/* ack stop event */
|
||||
if (audio->replay->event & REPLAY_EVT_STOP)
|
||||
rt_completion_done(&audio->replay->cmp);
|
||||
|
||||
/* send zero frames */
|
||||
rt_memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);
|
||||
|
||||
audio->replay->pos += dst_size;
|
||||
audio->replay->pos %= buf_info->total_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);
|
||||
|
||||
/* copy data from memory pool to hardware device fifo */
|
||||
while (index < dst_size)
|
||||
{
|
||||
result = rt_data_queue_peek(&audio->replay->queue, (const void **)&data, &src_size);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
LOG_D("under run %d, remain %d", audio->replay->pos, remain_bytes);
|
||||
audio->replay->pos -= remain_bytes;
|
||||
audio->replay->pos += dst_size;
|
||||
audio->replay->pos %= buf_info->total_size;
|
||||
audio->replay->read_index = 0;
|
||||
result = -RT_EEMPTY;
|
||||
break;
|
||||
}
|
||||
|
||||
remain_bytes = MIN((dst_size - index), (src_size - audio->replay->read_index));
|
||||
rt_memcpy(&buf_info->buffer[audio->replay->pos],
|
||||
&data[audio->replay->read_index], remain_bytes);
|
||||
|
||||
index += remain_bytes;
|
||||
audio->replay->read_index += remain_bytes;
|
||||
audio->replay->pos += remain_bytes;
|
||||
audio->replay->pos %= buf_info->total_size;
|
||||
|
||||
if (audio->replay->read_index == src_size)
|
||||
{
|
||||
/* free memory */
|
||||
audio->replay->read_index = 0;
|
||||
rt_data_queue_pop(&audio->replay->queue, (const void **)&data, &src_size, RT_WAITING_NO);
|
||||
rt_mp_free(data);
|
||||
|
||||
/* notify transmitted complete. */
|
||||
if (audio->parent.tx_complete != RT_NULL)
|
||||
audio->parent.tx_complete(&audio->parent, (void *)data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (audio->ops->transmit != RT_NULL)
|
||||
{
|
||||
if (audio->ops->transmit(audio, &buf_info->buffer[position], RT_NULL, dst_size) != dst_size)
|
||||
result = -RT_ERROR;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t _audio_flush_replay_frame(struct rt_audio_device *audio)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
if (audio->replay->write_index)
|
||||
{
|
||||
result = rt_data_queue_push(&audio->replay->queue,
|
||||
(const void **)audio->replay->write_data,
|
||||
audio->replay->write_index,
|
||||
RT_WAITING_FOREVER);
|
||||
|
||||
audio->replay->write_index = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t _aduio_replay_start(struct rt_audio_device *audio)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
if (audio->replay->activated != RT_TRUE)
|
||||
{
|
||||
/* start playback hardware device */
|
||||
if (audio->ops->start)
|
||||
result = audio->ops->start(audio, AUDIO_STREAM_REPLAY);
|
||||
|
||||
audio->replay->activated = RT_TRUE;
|
||||
LOG_D("start audio replay device");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t _aduio_replay_stop(struct rt_audio_device *audio)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
if (audio->replay->activated == RT_TRUE)
|
||||
{
|
||||
/* flush replay remian frames */
|
||||
_audio_flush_replay_frame(audio);
|
||||
|
||||
/* notify irq(or thread) to stop the data transmission */
|
||||
audio->replay->event |= REPLAY_EVT_STOP;
|
||||
|
||||
/* waiting for the remaining data transfer to complete */
|
||||
rt_completion_init(&audio->replay->cmp);
|
||||
rt_completion_wait(&audio->replay->cmp, RT_WAITING_FOREVER);
|
||||
audio->replay->event &= ~REPLAY_EVT_STOP;
|
||||
|
||||
/* stop playback hardware device */
|
||||
if (audio->ops->stop)
|
||||
result = audio->ops->stop(audio, AUDIO_STREAM_REPLAY);
|
||||
|
||||
audio->replay->activated = RT_FALSE;
|
||||
LOG_D("stop audio replay device");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t _audio_record_start(struct rt_audio_device *audio)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
if (audio->record->activated != RT_TRUE)
|
||||
{
|
||||
/* open audio record pipe */
|
||||
rt_device_open(RT_DEVICE(&audio->record->pipe), RT_DEVICE_OFLAG_RDONLY);
|
||||
|
||||
/* start record hardware device */
|
||||
if (audio->ops->start)
|
||||
result = audio->ops->start(audio, AUDIO_STREAM_RECORD);
|
||||
|
||||
audio->record->activated = RT_TRUE;
|
||||
LOG_D("start audio record device");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t _audio_record_stop(struct rt_audio_device *audio)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
|
||||
if (audio->record->activated == RT_TRUE)
|
||||
{
|
||||
/* stop record hardware device */
|
||||
if (audio->ops->stop)
|
||||
result = audio->ops->stop(audio, AUDIO_STREAM_RECORD);
|
||||
|
||||
/* close audio record pipe */
|
||||
rt_device_close(RT_DEVICE(&audio->record->pipe));
|
||||
|
||||
audio->record->activated = RT_FALSE;
|
||||
LOG_D("stop audio record device");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t _audio_dev_init(struct rt_device *dev)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct rt_audio_device *audio;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
audio = (struct rt_audio_device *) dev;
|
||||
|
||||
/* initialize replay & record */
|
||||
audio->replay = RT_NULL;
|
||||
audio->record = RT_NULL;
|
||||
|
||||
/* initialize replay */
|
||||
if (dev->flag & RT_DEVICE_FLAG_WRONLY)
|
||||
{
|
||||
struct rt_audio_replay *replay = (struct rt_audio_replay *) rt_malloc(sizeof(struct rt_audio_replay));
|
||||
|
||||
if (replay == RT_NULL)
|
||||
return -RT_ENOMEM;
|
||||
rt_memset(replay, 0, sizeof(struct rt_audio_replay));
|
||||
|
||||
/* init memory pool for replay */
|
||||
replay->mp = rt_mp_create("adu_mp", RT_AUDIO_REPLAY_MP_BLOCK_COUNT, RT_AUDIO_REPLAY_MP_BLOCK_SIZE);
|
||||
if (replay->mp == RT_NULL)
|
||||
{
|
||||
rt_free(replay);
|
||||
LOG_E("create memory pool for replay failed");
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
/* init queue for audio replay */
|
||||
rt_data_queue_init(&replay->queue, CFG_AUDIO_REPLAY_QUEUE_COUNT, 0, RT_NULL);
|
||||
|
||||
/* init mutex lock for audio replay */
|
||||
rt_mutex_init(&replay->lock, "replay", RT_IPC_FLAG_PRIO);
|
||||
|
||||
replay->activated = RT_FALSE;
|
||||
audio->replay = replay;
|
||||
}
|
||||
|
||||
/* initialize record */
|
||||
if (dev->flag & RT_DEVICE_FLAG_RDONLY)
|
||||
{
|
||||
struct rt_audio_record *record = (struct rt_audio_record *) rt_malloc(sizeof(struct rt_audio_record));
|
||||
rt_uint8_t *buffer;
|
||||
|
||||
if (record == RT_NULL)
|
||||
return -RT_ENOMEM;
|
||||
rt_memset(record, 0, sizeof(struct rt_audio_record));
|
||||
|
||||
/* init pipe for record*/
|
||||
buffer = rt_malloc(RT_AUDIO_RECORD_PIPE_SIZE);
|
||||
if (buffer == RT_NULL)
|
||||
{
|
||||
rt_free(record);
|
||||
LOG_E("malloc memory for for record pipe failed");
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
rt_audio_pipe_init(&record->pipe, "record",
|
||||
(rt_int32_t)(RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD),
|
||||
buffer,
|
||||
RT_AUDIO_RECORD_PIPE_SIZE);
|
||||
|
||||
record->activated = RT_FALSE;
|
||||
audio->record = record;
|
||||
}
|
||||
|
||||
/* initialize hardware configuration */
|
||||
if (audio->ops->init)
|
||||
audio->ops->init(audio);
|
||||
|
||||
/* get replay buffer information */
|
||||
if (audio->ops->buffer_info)
|
||||
audio->ops->buffer_info(audio, &audio->replay->buf_info);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag)
|
||||
{
|
||||
struct rt_audio_device *audio;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
audio = (struct rt_audio_device *) dev;
|
||||
|
||||
/* check device flag with the open flag */
|
||||
if ((oflag & RT_DEVICE_OFLAG_RDONLY) && !(dev->flag & RT_DEVICE_FLAG_RDONLY))
|
||||
return -RT_EIO;
|
||||
if ((oflag & RT_DEVICE_OFLAG_WRONLY) && !(dev->flag & RT_DEVICE_FLAG_WRONLY))
|
||||
return -RT_EIO;
|
||||
|
||||
/* get open flags */
|
||||
dev->open_flag = oflag & 0xff;
|
||||
|
||||
/* initialize the Rx/Tx structure according to open flag */
|
||||
if (oflag & RT_DEVICE_OFLAG_WRONLY)
|
||||
{
|
||||
if (audio->replay->activated != RT_TRUE)
|
||||
{
|
||||
LOG_D("open audio replay device, oflag = %x\n", oflag);
|
||||
audio->replay->write_index = 0;
|
||||
audio->replay->read_index = 0;
|
||||
audio->replay->pos = 0;
|
||||
audio->replay->event = REPLAY_EVT_NONE;
|
||||
}
|
||||
dev->open_flag |= RT_DEVICE_OFLAG_WRONLY;
|
||||
}
|
||||
|
||||
if (oflag & RT_DEVICE_OFLAG_RDONLY)
|
||||
{
|
||||
/* open record pipe */
|
||||
if (audio->record->activated != RT_TRUE)
|
||||
{
|
||||
LOG_D("open audio record device ,oflag = %x\n", oflag);
|
||||
|
||||
_audio_record_start(audio);
|
||||
audio->record->activated = RT_TRUE;
|
||||
}
|
||||
dev->open_flag |= RT_DEVICE_OFLAG_RDONLY;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t _audio_dev_close(struct rt_device *dev)
|
||||
{
|
||||
struct rt_audio_device *audio;
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
audio = (struct rt_audio_device *) dev;
|
||||
|
||||
if (dev->open_flag & RT_DEVICE_OFLAG_WRONLY)
|
||||
{
|
||||
/* stop replay stream */
|
||||
_aduio_replay_stop(audio);
|
||||
dev->open_flag &= ~RT_DEVICE_OFLAG_WRONLY;
|
||||
}
|
||||
|
||||
if (dev->open_flag & RT_DEVICE_OFLAG_RDONLY)
|
||||
{
|
||||
/* stop record stream */
|
||||
_audio_record_stop(audio);
|
||||
dev->open_flag &= ~RT_DEVICE_OFLAG_RDONLY;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_ssize_t _audio_dev_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
|
||||
{
|
||||
struct rt_audio_device *audio;
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
audio = (struct rt_audio_device *) dev;
|
||||
|
||||
if (!(dev->open_flag & RT_DEVICE_OFLAG_RDONLY) || (audio->record == RT_NULL))
|
||||
return 0;
|
||||
|
||||
return rt_device_read(RT_DEVICE(&audio->record->pipe), pos, buffer, size);
|
||||
}
|
||||
|
||||
static rt_ssize_t _audio_dev_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size)
|
||||
{
|
||||
|
||||
struct rt_audio_device *audio;
|
||||
rt_uint8_t *ptr;
|
||||
rt_uint16_t block_size, remain_bytes, index = 0;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
audio = (struct rt_audio_device *) dev;
|
||||
|
||||
if (!(dev->open_flag & RT_DEVICE_OFLAG_WRONLY) || (audio->replay == RT_NULL))
|
||||
return 0;
|
||||
|
||||
/* push a new frame to replay data queue */
|
||||
ptr = (rt_uint8_t *)buffer;
|
||||
block_size = RT_AUDIO_REPLAY_MP_BLOCK_SIZE;
|
||||
|
||||
rt_mutex_take(&audio->replay->lock, RT_WAITING_FOREVER);
|
||||
while (index < size)
|
||||
{
|
||||
/* request buffer from replay memory pool */
|
||||
if (audio->replay->write_index % block_size == 0)
|
||||
{
|
||||
audio->replay->write_data = rt_mp_alloc(audio->replay->mp, RT_WAITING_FOREVER);
|
||||
rt_memset(audio->replay->write_data, 0, block_size);
|
||||
}
|
||||
|
||||
/* copy data to replay memory pool */
|
||||
remain_bytes = MIN((block_size - audio->replay->write_index), (size - index));
|
||||
rt_memcpy(&audio->replay->write_data[audio->replay->write_index], &ptr[index], remain_bytes);
|
||||
|
||||
index += remain_bytes;
|
||||
audio->replay->write_index += remain_bytes;
|
||||
audio->replay->write_index %= block_size;
|
||||
|
||||
if (audio->replay->write_index == 0)
|
||||
{
|
||||
rt_data_queue_push(&audio->replay->queue,
|
||||
audio->replay->write_data,
|
||||
block_size,
|
||||
RT_WAITING_FOREVER);
|
||||
}
|
||||
}
|
||||
rt_mutex_release(&audio->replay->lock);
|
||||
|
||||
/* check replay state */
|
||||
if (audio->replay->activated != RT_TRUE)
|
||||
{
|
||||
_aduio_replay_start(audio);
|
||||
audio->replay->activated = RT_TRUE;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static rt_err_t _audio_dev_control(struct rt_device *dev, int cmd, void *args)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct rt_audio_device *audio;
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
audio = (struct rt_audio_device *) dev;
|
||||
|
||||
/* dev stat...*/
|
||||
switch (cmd)
|
||||
{
|
||||
case AUDIO_CTL_GETCAPS:
|
||||
{
|
||||
struct rt_audio_caps *caps = (struct rt_audio_caps *) args;
|
||||
|
||||
LOG_D("AUDIO_CTL_GETCAPS: main_type = %d,sub_type = %d", caps->main_type, caps->sub_type);
|
||||
if (audio->ops->getcaps != RT_NULL)
|
||||
{
|
||||
result = audio->ops->getcaps(audio, caps);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case AUDIO_CTL_CONFIGURE:
|
||||
{
|
||||
struct rt_audio_caps *caps = (struct rt_audio_caps *) args;
|
||||
|
||||
LOG_D("AUDIO_CTL_CONFIGURE: main_type = %d,sub_type = %d", caps->main_type, caps->sub_type);
|
||||
if (audio->ops->configure != RT_NULL)
|
||||
{
|
||||
result = audio->ops->configure(audio, caps);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case AUDIO_CTL_START:
|
||||
{
|
||||
int stream = *(int *) args;
|
||||
|
||||
LOG_D("AUDIO_CTL_START: stream = %d", stream);
|
||||
if (stream == AUDIO_STREAM_REPLAY)
|
||||
{
|
||||
result = _aduio_replay_start(audio);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = _audio_record_start(audio);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case AUDIO_CTL_STOP:
|
||||
{
|
||||
int stream = *(int *) args;
|
||||
|
||||
LOG_D("AUDIO_CTL_STOP: stream = %d", stream);
|
||||
if (stream == AUDIO_STREAM_REPLAY)
|
||||
{
|
||||
result = _aduio_replay_stop(audio);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = _audio_record_stop(audio);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops audio_ops =
|
||||
{
|
||||
_audio_dev_init,
|
||||
_audio_dev_open,
|
||||
_audio_dev_close,
|
||||
_audio_dev_read,
|
||||
_audio_dev_write,
|
||||
_audio_dev_control
|
||||
};
|
||||
#endif
|
||||
|
||||
rt_err_t rt_audio_register(struct rt_audio_device *audio, const char *name, rt_uint32_t flag, void *data)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct rt_device *device;
|
||||
|
||||
RT_ASSERT(audio != RT_NULL);
|
||||
device = &(audio->parent);
|
||||
|
||||
device->type = RT_Device_Class_Sound;
|
||||
device->rx_indicate = RT_NULL;
|
||||
device->tx_complete = RT_NULL;
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->ops = &audio_ops;
|
||||
#else
|
||||
device->init = _audio_dev_init;
|
||||
device->open = _audio_dev_open;
|
||||
device->close = _audio_dev_close;
|
||||
device->read = _audio_dev_read;
|
||||
device->write = _audio_dev_write;
|
||||
device->control = _audio_dev_control;
|
||||
#endif
|
||||
device->user_data = data;
|
||||
|
||||
/* register a character device */
|
||||
result = rt_device_register(device, name, flag | RT_DEVICE_FLAG_REMOVABLE);
|
||||
|
||||
/* initialize audio device */
|
||||
if (result == RT_EOK)
|
||||
result = rt_device_init(device);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int rt_audio_samplerate_to_speed(rt_uint32_t bitValue)
|
||||
{
|
||||
int speed = 0;
|
||||
switch (bitValue)
|
||||
{
|
||||
case AUDIO_SAMP_RATE_8K:
|
||||
speed = 8000;
|
||||
break;
|
||||
case AUDIO_SAMP_RATE_11K:
|
||||
speed = 11052;
|
||||
break;
|
||||
case AUDIO_SAMP_RATE_16K:
|
||||
speed = 16000;
|
||||
break;
|
||||
case AUDIO_SAMP_RATE_22K:
|
||||
speed = 22050;
|
||||
break;
|
||||
case AUDIO_SAMP_RATE_32K:
|
||||
speed = 32000;
|
||||
break;
|
||||
case AUDIO_SAMP_RATE_44K:
|
||||
speed = 44100;
|
||||
break;
|
||||
case AUDIO_SAMP_RATE_48K:
|
||||
speed = 48000;
|
||||
break;
|
||||
case AUDIO_SAMP_RATE_96K:
|
||||
speed = 96000;
|
||||
break;
|
||||
case AUDIO_SAMP_RATE_128K:
|
||||
speed = 128000;
|
||||
break;
|
||||
case AUDIO_SAMP_RATE_160K:
|
||||
speed = 160000;
|
||||
break;
|
||||
case AUDIO_SAMP_RATE_172K:
|
||||
speed = 176400;
|
||||
break;
|
||||
case AUDIO_SAMP_RATE_192K:
|
||||
speed = 192000;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return speed;
|
||||
}
|
||||
|
||||
void rt_audio_tx_complete(struct rt_audio_device *audio)
|
||||
{
|
||||
/* try to send next frame */
|
||||
_audio_send_replay_frame(audio);
|
||||
}
|
||||
|
||||
void rt_audio_rx_done(struct rt_audio_device *audio, rt_uint8_t *pbuf, rt_size_t len)
|
||||
{
|
||||
/* save data to record pipe */
|
||||
rt_device_write(RT_DEVICE(&audio->record->pipe), 0, pbuf, len);
|
||||
|
||||
/* invoke callback */
|
||||
if (audio->parent.rx_indicate != RT_NULL)
|
||||
audio->parent.rx_indicate(&audio->parent, len);
|
||||
}
|
@ -1,296 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2012-09-30 Bernard first version.
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtdevice.h>
|
||||
#include "dev_audio_pipe.h"
|
||||
|
||||
static void _rt_audio_pipe_resume_writer(struct rt_audio_pipe *pipe)
|
||||
{
|
||||
if (!rt_list_isempty(&pipe->suspended_write_list))
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
RT_ASSERT(pipe->flag & RT_PIPE_FLAG_BLOCK_WR);
|
||||
|
||||
/* get suspended thread */
|
||||
thread = RT_THREAD_LIST_NODE_ENTRY(pipe->suspended_write_list.next);
|
||||
|
||||
/* resume the write thread */
|
||||
rt_thread_resume(thread);
|
||||
|
||||
rt_schedule();
|
||||
}
|
||||
}
|
||||
|
||||
static rt_ssize_t rt_audio_pipe_read(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_thread_t thread;
|
||||
struct rt_audio_pipe *pipe;
|
||||
rt_size_t read_nbytes;
|
||||
|
||||
pipe = (struct rt_audio_pipe *)dev;
|
||||
RT_ASSERT(pipe != RT_NULL);
|
||||
|
||||
if (!(pipe->flag & RT_PIPE_FLAG_BLOCK_RD))
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
read_nbytes = rt_ringbuffer_get(&(pipe->ringbuffer), (rt_uint8_t *)buffer, size);
|
||||
|
||||
/* if the ringbuffer is empty, there won't be any writer waiting */
|
||||
if (read_nbytes)
|
||||
_rt_audio_pipe_resume_writer(pipe);
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return read_nbytes;
|
||||
}
|
||||
|
||||
thread = rt_thread_self();
|
||||
|
||||
/* current context checking */
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
do
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
read_nbytes = rt_ringbuffer_get(&(pipe->ringbuffer), (rt_uint8_t *)buffer, size);
|
||||
if (read_nbytes == 0)
|
||||
{
|
||||
rt_thread_suspend(thread);
|
||||
/* waiting on suspended read list */
|
||||
rt_list_insert_before(&(pipe->suspended_read_list),
|
||||
&RT_THREAD_LIST_NODE(thread));
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_schedule();
|
||||
}
|
||||
else
|
||||
{
|
||||
_rt_audio_pipe_resume_writer(pipe);
|
||||
rt_hw_interrupt_enable(level);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (read_nbytes == 0);
|
||||
|
||||
return read_nbytes;
|
||||
}
|
||||
|
||||
static void _rt_audio_pipe_resume_reader(struct rt_audio_pipe *pipe)
|
||||
{
|
||||
if (pipe->parent.rx_indicate)
|
||||
pipe->parent.rx_indicate(&pipe->parent,
|
||||
rt_ringbuffer_data_len(&pipe->ringbuffer));
|
||||
|
||||
if (!rt_list_isempty(&pipe->suspended_read_list))
|
||||
{
|
||||
rt_thread_t thread;
|
||||
|
||||
RT_ASSERT(pipe->flag & RT_PIPE_FLAG_BLOCK_RD);
|
||||
|
||||
/* get suspended thread */
|
||||
thread = RT_THREAD_LIST_NODE_ENTRY(pipe->suspended_read_list.next);
|
||||
|
||||
/* resume the read thread */
|
||||
rt_thread_resume(thread);
|
||||
|
||||
rt_schedule();
|
||||
}
|
||||
}
|
||||
|
||||
static rt_ssize_t rt_audio_pipe_write(rt_device_t dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_thread_t thread;
|
||||
struct rt_audio_pipe *pipe;
|
||||
rt_size_t write_nbytes;
|
||||
|
||||
pipe = (struct rt_audio_pipe *)dev;
|
||||
RT_ASSERT(pipe != RT_NULL);
|
||||
|
||||
if ((pipe->flag & RT_PIPE_FLAG_FORCE_WR) ||
|
||||
!(pipe->flag & RT_PIPE_FLAG_BLOCK_WR))
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
if (pipe->flag & RT_PIPE_FLAG_FORCE_WR)
|
||||
write_nbytes = rt_ringbuffer_put_force(&(pipe->ringbuffer),
|
||||
(const rt_uint8_t *)buffer, size);
|
||||
else
|
||||
write_nbytes = rt_ringbuffer_put(&(pipe->ringbuffer),
|
||||
(const rt_uint8_t *)buffer, size);
|
||||
|
||||
_rt_audio_pipe_resume_reader(pipe);
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
return write_nbytes;
|
||||
}
|
||||
|
||||
thread = rt_thread_self();
|
||||
|
||||
/* current context checking */
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
do
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
write_nbytes = rt_ringbuffer_put(&(pipe->ringbuffer), (const rt_uint8_t *)buffer, size);
|
||||
if (write_nbytes == 0)
|
||||
{
|
||||
/* pipe full, waiting on suspended write list */
|
||||
rt_thread_suspend(thread);
|
||||
/* waiting on suspended read list */
|
||||
rt_list_insert_before(&(pipe->suspended_write_list),
|
||||
&RT_THREAD_LIST_NODE(thread));
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_schedule();
|
||||
}
|
||||
else
|
||||
{
|
||||
_rt_audio_pipe_resume_reader(pipe);
|
||||
rt_hw_interrupt_enable(level);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (write_nbytes == 0);
|
||||
|
||||
return write_nbytes;
|
||||
}
|
||||
|
||||
static rt_err_t rt_audio_pipe_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
struct rt_audio_pipe *pipe;
|
||||
|
||||
pipe = (struct rt_audio_pipe *)dev;
|
||||
|
||||
if (cmd == PIPE_CTRL_GET_SPACE && args)
|
||||
*(rt_size_t *)args = rt_ringbuffer_space_len(&pipe->ringbuffer);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops audio_pipe_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
rt_audio_pipe_read,
|
||||
rt_audio_pipe_write,
|
||||
rt_audio_pipe_control
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function will initialize a pipe device and put it under control of
|
||||
* resource management.
|
||||
*
|
||||
* @param pipe the pipe device
|
||||
* @param name the name of pipe device
|
||||
* @param flag the attribute of the pipe device
|
||||
* @param buf the buffer of pipe device
|
||||
* @param size the size of pipe device buffer
|
||||
*
|
||||
* @return the operation status, RT_EOK on successful
|
||||
*/
|
||||
rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe,
|
||||
const char *name,
|
||||
rt_int32_t flag,
|
||||
rt_uint8_t *buf,
|
||||
rt_size_t size)
|
||||
{
|
||||
RT_ASSERT(pipe);
|
||||
RT_ASSERT(buf);
|
||||
|
||||
/* initialize suspended list */
|
||||
rt_list_init(&pipe->suspended_read_list);
|
||||
rt_list_init(&pipe->suspended_write_list);
|
||||
|
||||
/* initialize ring buffer */
|
||||
rt_ringbuffer_init(&pipe->ringbuffer, buf, size);
|
||||
|
||||
pipe->flag = flag;
|
||||
|
||||
/* create pipe */
|
||||
pipe->parent.type = RT_Device_Class_Pipe;
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
pipe->parent.ops = &audio_pipe_ops;
|
||||
#else
|
||||
pipe->parent.init = RT_NULL;
|
||||
pipe->parent.open = RT_NULL;
|
||||
pipe->parent.close = RT_NULL;
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will detach a pipe device from resource management
|
||||
*
|
||||
* @param pipe the pipe device
|
||||
*
|
||||
* @return the operation status, RT_EOK on successful
|
||||
*/
|
||||
rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe)
|
||||
{
|
||||
return rt_device_unregister(&pipe->parent);
|
||||
}
|
||||
|
||||
#ifdef RT_USING_HEAP
|
||||
rt_err_t rt_audio_pipe_create(const char *name, rt_int32_t flag, rt_size_t size)
|
||||
{
|
||||
rt_uint8_t *rb_memptr = RT_NULL;
|
||||
struct rt_audio_pipe *pipe = RT_NULL;
|
||||
|
||||
/* get aligned size */
|
||||
size = RT_ALIGN(size, RT_ALIGN_SIZE);
|
||||
pipe = (struct rt_audio_pipe *)rt_calloc(1, sizeof(struct rt_audio_pipe));
|
||||
if (pipe == RT_NULL)
|
||||
return -RT_ENOMEM;
|
||||
|
||||
/* create ring buffer of pipe */
|
||||
rb_memptr = (rt_uint8_t *)rt_malloc(size);
|
||||
if (rb_memptr == RT_NULL)
|
||||
{
|
||||
rt_free(pipe);
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
return rt_audio_pipe_init(pipe, name, flag, rb_memptr, size);
|
||||
}
|
||||
|
||||
void rt_audio_pipe_destroy(struct rt_audio_pipe *pipe)
|
||||
{
|
||||
if (pipe == RT_NULL)
|
||||
return;
|
||||
|
||||
/* un-register pipe device */
|
||||
rt_audio_pipe_detach(pipe);
|
||||
|
||||
/* release memory */
|
||||
rt_free(pipe->ringbuffer.buffer_ptr);
|
||||
rt_free(pipe);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* RT_USING_HEAP */
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
#ifndef __DEV_AUDIO_PIPE_H__
|
||||
#define __DEV_AUDIO_PIPE_H__
|
||||
|
||||
/**
|
||||
* Pipe Device
|
||||
*/
|
||||
#include <rtdevice.h>
|
||||
|
||||
#ifndef RT_PIPE_BUFSZ
|
||||
#define PIPE_BUFSZ 512
|
||||
#else
|
||||
#define PIPE_BUFSZ RT_PIPE_BUFSZ
|
||||
#endif
|
||||
|
||||
/* portal device */
|
||||
struct rt_audio_portal_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
struct rt_device *write_dev;
|
||||
struct rt_device *read_dev;
|
||||
};
|
||||
|
||||
enum rt_audio_pipe_flag
|
||||
{
|
||||
/* both read and write won't block */
|
||||
RT_PIPE_FLAG_NONBLOCK_RDWR = 0x00,
|
||||
/* read would block */
|
||||
RT_PIPE_FLAG_BLOCK_RD = 0x01,
|
||||
/* write would block */
|
||||
RT_PIPE_FLAG_BLOCK_WR = 0x02,
|
||||
/* write to this pipe will discard some data when the pipe is full.
|
||||
* When this flag is set, RT_PIPE_FLAG_BLOCK_WR will be ignored since write
|
||||
* operation will always be success. */
|
||||
RT_PIPE_FLAG_FORCE_WR = 0x04,
|
||||
};
|
||||
|
||||
struct rt_audio_pipe
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
/* ring buffer in pipe device */
|
||||
struct rt_ringbuffer ringbuffer;
|
||||
|
||||
rt_int32_t flag;
|
||||
|
||||
/* suspended list */
|
||||
rt_list_t suspended_read_list;
|
||||
rt_list_t suspended_write_list;
|
||||
|
||||
struct rt_audio_portal_device *write_portal;
|
||||
struct rt_audio_portal_device *read_portal;
|
||||
};
|
||||
|
||||
#define PIPE_CTRL_GET_SPACE 0x14 /**< get the remaining size of a pipe device */
|
||||
|
||||
rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe,
|
||||
const char *name,
|
||||
rt_int32_t flag,
|
||||
rt_uint8_t *buf,
|
||||
rt_size_t size);
|
||||
rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe);
|
||||
#ifdef RT_USING_HEAP
|
||||
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 /* __DEV_AUDIO_PIPE_H__ */
|
@ -1,7 +0,0 @@
|
||||
menuconfig RT_USING_BLK
|
||||
bool "Using Block device drivers"
|
||||
default n
|
||||
|
||||
if RT_USING_BLK
|
||||
rsource "partitions/Kconfig"
|
||||
endif
|
@ -1,23 +0,0 @@
|
||||
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')
|
@ -1,573 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
@ -1,297 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* 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__ */
|
@ -1,274 +0,0 @@
|
||||
/*
|
||||
* 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));
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
* 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__ */
|
@ -1,154 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* 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__ */
|
@ -1,12 +0,0 @@
|
||||
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
|
@ -1,18 +0,0 @@
|
||||
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')
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@ -1,738 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
/*
|
||||
* 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,974 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2015-05-14 aubrcool@qq.com first version
|
||||
* 2015-07-06 Bernard code cleanup and remove RT_CAN_USING_LED;
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define CAN_LOCK(can) rt_mutex_take(&(can->lock), RT_WAITING_FOREVER)
|
||||
#define CAN_UNLOCK(can) rt_mutex_release(&(can->lock))
|
||||
|
||||
static rt_err_t rt_can_init(struct rt_device *dev)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct rt_can_device *can;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
can = (struct rt_can_device *)dev;
|
||||
|
||||
/* initialize rx/tx */
|
||||
can->can_rx = RT_NULL;
|
||||
can->can_tx = RT_NULL;
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
can->hdr = RT_NULL;
|
||||
#endif
|
||||
|
||||
/* apply configuration */
|
||||
if (can->ops->configure)
|
||||
result = can->ops->configure(can, &can->config);
|
||||
else
|
||||
result = -RT_ENOSYS;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* can interrupt routines
|
||||
*/
|
||||
rt_inline rt_ssize_t _can_int_rx(struct rt_can_device *can, struct rt_can_msg *data, rt_ssize_t msgs)
|
||||
{
|
||||
rt_ssize_t size;
|
||||
struct rt_can_rx_fifo *rx_fifo;
|
||||
RT_ASSERT(can != RT_NULL);
|
||||
size = msgs;
|
||||
|
||||
rx_fifo = (struct rt_can_rx_fifo *) can->can_rx;
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
|
||||
/* read from software FIFO */
|
||||
while (msgs / sizeof(struct rt_can_msg) > 0)
|
||||
{
|
||||
rt_base_t level;
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
rt_int8_t hdr;
|
||||
#endif /*RT_CAN_USING_HDR*/
|
||||
struct rt_can_msg_list *listmsg = RT_NULL;
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
hdr = data->hdr_index;
|
||||
|
||||
if (hdr >= 0 && can->hdr && hdr < can->config.maxhdr && !rt_list_isempty(&can->hdr[hdr].list))
|
||||
{
|
||||
listmsg = rt_list_entry(can->hdr[hdr].list.next, struct rt_can_msg_list, hdrlist);
|
||||
rt_list_remove(&listmsg->list);
|
||||
rt_list_remove(&listmsg->hdrlist);
|
||||
if (can->hdr[hdr].msgs)
|
||||
{
|
||||
can->hdr[hdr].msgs--;
|
||||
}
|
||||
listmsg->owner = RT_NULL;
|
||||
}
|
||||
else if (hdr == -1)
|
||||
#endif /*RT_CAN_USING_HDR*/
|
||||
{
|
||||
if (!rt_list_isempty(&rx_fifo->uselist))
|
||||
{
|
||||
listmsg = rt_list_entry(rx_fifo->uselist.next, struct rt_can_msg_list, list);
|
||||
rt_list_remove(&listmsg->list);
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
rt_list_remove(&listmsg->hdrlist);
|
||||
if (listmsg->owner != RT_NULL && listmsg->owner->msgs)
|
||||
{
|
||||
listmsg->owner->msgs--;
|
||||
}
|
||||
listmsg->owner = RT_NULL;
|
||||
#endif /*RT_CAN_USING_HDR*/
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no data, enable interrupt and break out */
|
||||
rt_hw_interrupt_enable(level);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
if (listmsg != RT_NULL)
|
||||
{
|
||||
rt_memcpy(data, &listmsg->data, sizeof(struct rt_can_msg));
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
rt_list_insert_before(&rx_fifo->freelist, &listmsg->list);
|
||||
rx_fifo->freenumbers++;
|
||||
RT_ASSERT(rx_fifo->freenumbers <= can->config.msgboxsz);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
listmsg = RT_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
data ++;
|
||||
msgs -= sizeof(struct rt_can_msg);
|
||||
}
|
||||
|
||||
return (size - msgs);
|
||||
}
|
||||
|
||||
rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *data, int msgs)
|
||||
{
|
||||
int size;
|
||||
struct rt_can_tx_fifo *tx_fifo;
|
||||
|
||||
RT_ASSERT(can != RT_NULL);
|
||||
|
||||
size = msgs;
|
||||
tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
|
||||
RT_ASSERT(tx_fifo != RT_NULL);
|
||||
|
||||
while (msgs)
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_uint32_t no;
|
||||
rt_uint32_t result;
|
||||
struct rt_can_sndbxinx_list *tx_tosnd = RT_NULL;
|
||||
|
||||
rt_sem_take(&(tx_fifo->sem), RT_WAITING_FOREVER);
|
||||
level = rt_hw_interrupt_disable();
|
||||
tx_tosnd = rt_list_entry(tx_fifo->freelist.next, struct rt_can_sndbxinx_list, list);
|
||||
RT_ASSERT(tx_tosnd != RT_NULL);
|
||||
rt_list_remove(&tx_tosnd->list);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
no = ((rt_ubase_t)tx_tosnd - (rt_ubase_t)tx_fifo->buffer) / sizeof(struct rt_can_sndbxinx_list);
|
||||
tx_tosnd->result = RT_CAN_SND_RESULT_WAIT;
|
||||
rt_completion_init(&tx_tosnd->completion);
|
||||
if (can->ops->sendmsg(can, data, no) != RT_EOK)
|
||||
{
|
||||
/* send failed. */
|
||||
level = rt_hw_interrupt_disable();
|
||||
rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list);
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_sem_release(&(tx_fifo->sem));
|
||||
goto err_ret;
|
||||
}
|
||||
|
||||
can->status.sndchange = 1;
|
||||
rt_completion_wait(&(tx_tosnd->completion), RT_WAITING_FOREVER);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
result = tx_tosnd->result;
|
||||
if (!rt_list_isempty(&tx_tosnd->list))
|
||||
{
|
||||
rt_list_remove(&tx_tosnd->list);
|
||||
}
|
||||
rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list);
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_sem_release(&(tx_fifo->sem));
|
||||
|
||||
if (result == RT_CAN_SND_RESULT_OK)
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
can->status.sndpkg++;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
data ++;
|
||||
msgs -= sizeof(struct rt_can_msg);
|
||||
if (!msgs) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
err_ret:
|
||||
level = rt_hw_interrupt_disable();
|
||||
can->status.dropedsndpkg++;
|
||||
rt_hw_interrupt_enable(level);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (size - msgs);
|
||||
}
|
||||
|
||||
rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_msg *data, int msgs)
|
||||
{
|
||||
int size;
|
||||
rt_base_t level;
|
||||
rt_uint32_t no, result;
|
||||
struct rt_can_tx_fifo *tx_fifo;
|
||||
|
||||
RT_ASSERT(can != RT_NULL);
|
||||
|
||||
size = msgs;
|
||||
tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
|
||||
RT_ASSERT(tx_fifo != RT_NULL);
|
||||
|
||||
while (msgs)
|
||||
{
|
||||
no = data->priv;
|
||||
if (no >= can->config.sndboxnumber)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
if ((tx_fifo->buffer[no].result != RT_CAN_SND_RESULT_OK))
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_WAITING_FOREVER);
|
||||
continue;
|
||||
}
|
||||
tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_WAIT;
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
if (can->ops->sendmsg(can, data, no) != RT_EOK)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
can->status.sndchange = 1;
|
||||
rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_WAITING_FOREVER);
|
||||
|
||||
result = tx_fifo->buffer[no].result;
|
||||
if (result == RT_CAN_SND_RESULT_OK)
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
can->status.sndpkg++;
|
||||
rt_hw_interrupt_enable(level);
|
||||
data ++;
|
||||
msgs -= sizeof(struct rt_can_msg);
|
||||
if (!msgs) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
can->status.dropedsndpkg++;
|
||||
rt_hw_interrupt_enable(level);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (size - msgs);
|
||||
}
|
||||
|
||||
static rt_err_t rt_can_open(struct rt_device *dev, rt_uint16_t oflag)
|
||||
{
|
||||
struct rt_can_device *can;
|
||||
char tmpname[16];
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
can = (struct rt_can_device *)dev;
|
||||
|
||||
CAN_LOCK(can);
|
||||
|
||||
/* get open flags */
|
||||
dev->open_flag = oflag & 0xff;
|
||||
if (can->can_rx == RT_NULL)
|
||||
{
|
||||
if (oflag & RT_DEVICE_FLAG_INT_RX)
|
||||
{
|
||||
int i = 0;
|
||||
struct rt_can_rx_fifo *rx_fifo;
|
||||
|
||||
rx_fifo = (struct rt_can_rx_fifo *) rt_malloc(sizeof(struct rt_can_rx_fifo) +
|
||||
can->config.msgboxsz * sizeof(struct rt_can_msg_list));
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
|
||||
rx_fifo->buffer = (struct rt_can_msg_list *)(rx_fifo + 1);
|
||||
rt_memset(rx_fifo->buffer, 0, can->config.msgboxsz * sizeof(struct rt_can_msg_list));
|
||||
rt_list_init(&rx_fifo->freelist);
|
||||
rt_list_init(&rx_fifo->uselist);
|
||||
rx_fifo->freenumbers = can->config.msgboxsz;
|
||||
for (i = 0; i < can->config.msgboxsz; i++)
|
||||
{
|
||||
rt_list_insert_before(&rx_fifo->freelist, &rx_fifo->buffer[i].list);
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
rt_list_init(&rx_fifo->buffer[i].hdrlist);
|
||||
rx_fifo->buffer[i].owner = RT_NULL;
|
||||
#endif
|
||||
}
|
||||
can->can_rx = rx_fifo;
|
||||
|
||||
dev->open_flag |= RT_DEVICE_FLAG_INT_RX;
|
||||
/* open can rx interrupt */
|
||||
can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
|
||||
}
|
||||
}
|
||||
|
||||
if (can->can_tx == RT_NULL)
|
||||
{
|
||||
if (oflag & RT_DEVICE_FLAG_INT_TX)
|
||||
{
|
||||
int i = 0;
|
||||
struct rt_can_tx_fifo *tx_fifo;
|
||||
|
||||
tx_fifo = (struct rt_can_tx_fifo *) rt_malloc(sizeof(struct rt_can_tx_fifo) +
|
||||
can->config.sndboxnumber * sizeof(struct rt_can_sndbxinx_list));
|
||||
RT_ASSERT(tx_fifo != RT_NULL);
|
||||
|
||||
tx_fifo->buffer = (struct rt_can_sndbxinx_list *)(tx_fifo + 1);
|
||||
rt_memset(tx_fifo->buffer, 0,
|
||||
can->config.sndboxnumber * sizeof(struct rt_can_sndbxinx_list));
|
||||
rt_list_init(&tx_fifo->freelist);
|
||||
for (i = 0; i < can->config.sndboxnumber; i++)
|
||||
{
|
||||
rt_list_insert_before(&tx_fifo->freelist, &tx_fifo->buffer[i].list);
|
||||
rt_completion_init(&(tx_fifo->buffer[i].completion));
|
||||
tx_fifo->buffer[i].result = RT_CAN_SND_RESULT_OK;
|
||||
}
|
||||
|
||||
rt_sprintf(tmpname, "%stl", dev->parent.name);
|
||||
rt_sem_init(&(tx_fifo->sem), tmpname, can->config.sndboxnumber, RT_IPC_FLAG_FIFO);
|
||||
can->can_tx = tx_fifo;
|
||||
|
||||
dev->open_flag |= RT_DEVICE_FLAG_INT_TX;
|
||||
/* open can tx interrupt */
|
||||
can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX);
|
||||
}
|
||||
}
|
||||
|
||||
can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_CAN_INT_ERR);
|
||||
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
if (can->hdr == RT_NULL)
|
||||
{
|
||||
int i = 0;
|
||||
struct rt_can_hdr *phdr;
|
||||
|
||||
phdr = (struct rt_can_hdr *) rt_malloc(can->config.maxhdr * sizeof(struct rt_can_hdr));
|
||||
RT_ASSERT(phdr != RT_NULL);
|
||||
rt_memset(phdr, 0, can->config.maxhdr * sizeof(struct rt_can_hdr));
|
||||
for (i = 0; i < can->config.maxhdr; i++)
|
||||
{
|
||||
rt_list_init(&phdr[i].list);
|
||||
}
|
||||
|
||||
can->hdr = phdr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!can->timerinitflag)
|
||||
{
|
||||
can->timerinitflag = 1;
|
||||
|
||||
rt_timer_start(&can->timer);
|
||||
}
|
||||
|
||||
CAN_UNLOCK(can);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t rt_can_close(struct rt_device *dev)
|
||||
{
|
||||
struct rt_can_device *can;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
can = (struct rt_can_device *)dev;
|
||||
|
||||
CAN_LOCK(can);
|
||||
|
||||
/* this device has more reference count */
|
||||
if (dev->ref_count > 1)
|
||||
{
|
||||
CAN_UNLOCK(can);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
if (can->timerinitflag)
|
||||
{
|
||||
can->timerinitflag = 0;
|
||||
|
||||
rt_timer_stop(&can->timer);
|
||||
}
|
||||
|
||||
can->status_indicate.ind = RT_NULL;
|
||||
can->status_indicate.args = RT_NULL;
|
||||
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
if (can->hdr != RT_NULL)
|
||||
{
|
||||
rt_free(can->hdr);
|
||||
can->hdr = RT_NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dev->open_flag & RT_DEVICE_FLAG_INT_RX)
|
||||
{
|
||||
struct rt_can_rx_fifo *rx_fifo;
|
||||
|
||||
/* clear can rx interrupt */
|
||||
can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
|
||||
|
||||
rx_fifo = (struct rt_can_rx_fifo *)can->can_rx;
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
|
||||
rt_free(rx_fifo);
|
||||
dev->open_flag &= ~RT_DEVICE_FLAG_INT_RX;
|
||||
can->can_rx = RT_NULL;
|
||||
}
|
||||
|
||||
if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
|
||||
{
|
||||
struct rt_can_tx_fifo *tx_fifo;
|
||||
|
||||
/* clear can tx interrupt */
|
||||
can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_TX);
|
||||
|
||||
tx_fifo = (struct rt_can_tx_fifo *)can->can_tx;
|
||||
RT_ASSERT(tx_fifo != RT_NULL);
|
||||
|
||||
rt_sem_detach(&(tx_fifo->sem));
|
||||
rt_free(tx_fifo);
|
||||
dev->open_flag &= ~RT_DEVICE_FLAG_INT_TX;
|
||||
can->can_tx = RT_NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static rt_ssize_t rt_can_read(struct rt_device *dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
struct rt_can_device *can;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
if (size == 0) return 0;
|
||||
|
||||
can = (struct rt_can_device *)dev;
|
||||
|
||||
if ((dev->open_flag & RT_DEVICE_FLAG_INT_RX) && (dev->ref_count > 0))
|
||||
{
|
||||
return _can_int_rx(can, buffer, size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_ssize_t rt_can_write(struct rt_device *dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
struct rt_can_device *can;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
if (size == 0) return 0;
|
||||
|
||||
can = (struct rt_can_device *)dev;
|
||||
|
||||
if ((dev->open_flag & RT_DEVICE_FLAG_INT_TX) && (dev->ref_count > 0))
|
||||
{
|
||||
if (can->config.privmode)
|
||||
{
|
||||
return _can_int_tx_priv(can, buffer, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _can_int_tx(can, buffer, size);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_err_t rt_can_control(struct rt_device *dev,
|
||||
int cmd,
|
||||
void *args)
|
||||
{
|
||||
struct rt_can_device *can;
|
||||
rt_err_t res;
|
||||
|
||||
res = RT_EOK;
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
can = (struct rt_can_device *)dev;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case RT_DEVICE_CTRL_SUSPEND:
|
||||
/* suspend device */
|
||||
dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_RESUME:
|
||||
/* resume device */
|
||||
dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
|
||||
break;
|
||||
|
||||
case RT_DEVICE_CTRL_CONFIG:
|
||||
/* configure device */
|
||||
res = can->ops->configure(can, (struct can_configure *)args);
|
||||
break;
|
||||
|
||||
case RT_CAN_CMD_SET_PRIV:
|
||||
/* configure device */
|
||||
if ((rt_uint32_t)(rt_ubase_t)args != can->config.privmode)
|
||||
{
|
||||
int i;
|
||||
rt_base_t level;
|
||||
struct rt_can_tx_fifo *tx_fifo;
|
||||
|
||||
res = can->ops->control(can, cmd, args);
|
||||
if (res != RT_EOK) return res;
|
||||
tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
|
||||
if (can->config.privmode)
|
||||
{
|
||||
for (i = 0; i < can->config.sndboxnumber; i++)
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
if(rt_list_isempty(&tx_fifo->buffer[i].list))
|
||||
{
|
||||
rt_sem_release(&(tx_fifo->sem));
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_list_remove(&tx_fifo->buffer[i].list);
|
||||
}
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < can->config.sndboxnumber; i++)
|
||||
{
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (tx_fifo->buffer[i].result == RT_CAN_SND_RESULT_OK)
|
||||
{
|
||||
rt_list_insert_before(&tx_fifo->freelist, &tx_fifo->buffer[i].list);
|
||||
}
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RT_CAN_CMD_SET_STATUS_IND:
|
||||
can->status_indicate.ind = ((rt_can_status_ind_type_t)args)->ind;
|
||||
can->status_indicate.args = ((rt_can_status_ind_type_t)args)->args;
|
||||
break;
|
||||
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
case RT_CAN_CMD_SET_FILTER:
|
||||
res = can->ops->control(can, cmd, args);
|
||||
if (res != RT_EOK || can->hdr == RT_NULL)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
struct rt_can_filter_config *pfilter;
|
||||
struct rt_can_filter_item *pitem;
|
||||
rt_uint32_t count;
|
||||
rt_base_t level;
|
||||
|
||||
pfilter = (struct rt_can_filter_config *)args;
|
||||
RT_ASSERT(pfilter);
|
||||
count = pfilter->count;
|
||||
pitem = pfilter->items;
|
||||
if (pfilter->actived)
|
||||
{
|
||||
while (count)
|
||||
{
|
||||
if (pitem->hdr_bank >= can->config.maxhdr || pitem->hdr_bank < 0)
|
||||
{
|
||||
count--;
|
||||
pitem++;
|
||||
continue;
|
||||
}
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
if (!can->hdr[pitem->hdr_bank].connected)
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_memcpy(&can->hdr[pitem->hdr_bank].filter, pitem,
|
||||
sizeof(struct rt_can_filter_item));
|
||||
level = rt_hw_interrupt_disable();
|
||||
can->hdr[pitem->hdr_bank].connected = 1;
|
||||
can->hdr[pitem->hdr_bank].msgs = 0;
|
||||
rt_list_init(&can->hdr[pitem->hdr_bank].list);
|
||||
}
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
count--;
|
||||
pitem++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (count)
|
||||
{
|
||||
if (pitem->hdr_bank >= can->config.maxhdr || pitem->hdr_bank < 0)
|
||||
{
|
||||
count--;
|
||||
pitem++;
|
||||
continue;
|
||||
}
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
if (can->hdr[pitem->hdr_bank].connected)
|
||||
{
|
||||
can->hdr[pitem->hdr_bank].connected = 0;
|
||||
can->hdr[pitem->hdr_bank].msgs = 0;
|
||||
if (!rt_list_isempty(&can->hdr[pitem->hdr_bank].list))
|
||||
{
|
||||
rt_list_remove(can->hdr[pitem->hdr_bank].list.next);
|
||||
}
|
||||
rt_hw_interrupt_enable(level);
|
||||
rt_memset(&can->hdr[pitem->hdr_bank].filter, 0,
|
||||
sizeof(struct rt_can_filter_item));
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
count--;
|
||||
pitem++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /*RT_CAN_USING_HDR*/
|
||||
#ifdef RT_CAN_USING_BUS_HOOK
|
||||
case RT_CAN_CMD_SET_BUS_HOOK:
|
||||
can->bus_hook = (rt_can_bus_hook) args;
|
||||
break;
|
||||
#endif /*RT_CAN_USING_BUS_HOOK*/
|
||||
default :
|
||||
/* control device */
|
||||
if (can->ops->control != RT_NULL)
|
||||
{
|
||||
res = can->ops->control(can, cmd, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = -RT_ENOSYS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* can timer
|
||||
*/
|
||||
static void cantimeout(void *arg)
|
||||
{
|
||||
rt_can_t can;
|
||||
|
||||
can = (rt_can_t)arg;
|
||||
RT_ASSERT(can);
|
||||
rt_device_control((rt_device_t)can, RT_CAN_CMD_GET_STATUS, (void *)&can->status);
|
||||
|
||||
if (can->status_indicate.ind != RT_NULL)
|
||||
{
|
||||
can->status_indicate.ind(can, can->status_indicate.args);
|
||||
}
|
||||
#ifdef RT_CAN_USING_BUS_HOOK
|
||||
if(can->bus_hook)
|
||||
{
|
||||
can->bus_hook(can);
|
||||
}
|
||||
#endif /*RT_CAN_USING_BUS_HOOK*/
|
||||
if (can->timerinitflag == 1)
|
||||
{
|
||||
can->timerinitflag = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops can_device_ops =
|
||||
{
|
||||
rt_can_init,
|
||||
rt_can_open,
|
||||
rt_can_close,
|
||||
rt_can_read,
|
||||
rt_can_write,
|
||||
rt_can_control
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* can register
|
||||
*/
|
||||
rt_err_t rt_hw_can_register(struct rt_can_device *can,
|
||||
const char *name,
|
||||
const struct rt_can_ops *ops,
|
||||
void *data)
|
||||
{
|
||||
struct rt_device *device;
|
||||
RT_ASSERT(can != RT_NULL);
|
||||
|
||||
device = &(can->parent);
|
||||
|
||||
device->type = RT_Device_Class_CAN;
|
||||
device->rx_indicate = RT_NULL;
|
||||
device->tx_complete = RT_NULL;
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
can->hdr = RT_NULL;
|
||||
#endif
|
||||
can->can_rx = RT_NULL;
|
||||
can->can_tx = RT_NULL;
|
||||
rt_mutex_init(&(can->lock), "can", RT_IPC_FLAG_PRIO);
|
||||
#ifdef RT_CAN_USING_BUS_HOOK
|
||||
can->bus_hook = RT_NULL;
|
||||
#endif /*RT_CAN_USING_BUS_HOOK*/
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->ops = &can_device_ops;
|
||||
#else
|
||||
device->init = rt_can_init;
|
||||
device->open = rt_can_open;
|
||||
device->close = rt_can_close;
|
||||
device->read = rt_can_read;
|
||||
device->write = rt_can_write;
|
||||
device->control = rt_can_control;
|
||||
#endif
|
||||
can->ops = ops;
|
||||
|
||||
can->status_indicate.ind = RT_NULL;
|
||||
can->status_indicate.args = RT_NULL;
|
||||
rt_memset(&can->status, 0, sizeof(can->status));
|
||||
|
||||
device->user_data = data;
|
||||
|
||||
can->timerinitflag = 0;
|
||||
rt_timer_init(&can->timer,
|
||||
name,
|
||||
cantimeout,
|
||||
(void *)can,
|
||||
can->config.ticks,
|
||||
RT_TIMER_FLAG_PERIODIC);
|
||||
/* register a character device */
|
||||
return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
|
||||
}
|
||||
|
||||
/* ISR for can interrupt */
|
||||
void rt_hw_can_isr(struct rt_can_device *can, int event)
|
||||
{
|
||||
switch (event & 0xff)
|
||||
{
|
||||
case RT_CAN_EVENT_RXOF_IND:
|
||||
{
|
||||
rt_base_t level;
|
||||
level = rt_hw_interrupt_disable();
|
||||
can->status.dropedrcvpkg++;
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
case RT_CAN_EVENT_RX_IND:
|
||||
{
|
||||
struct rt_can_msg tmpmsg;
|
||||
struct rt_can_rx_fifo *rx_fifo;
|
||||
struct rt_can_msg_list *listmsg = RT_NULL;
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
rt_int8_t hdr;
|
||||
#endif
|
||||
int ch = -1;
|
||||
rt_base_t level;
|
||||
rt_uint32_t no;
|
||||
|
||||
rx_fifo = (struct rt_can_rx_fifo *)can->can_rx;
|
||||
RT_ASSERT(rx_fifo != RT_NULL);
|
||||
/* interrupt mode receive */
|
||||
RT_ASSERT(can->parent.open_flag & RT_DEVICE_FLAG_INT_RX);
|
||||
|
||||
no = event >> 8;
|
||||
ch = can->ops->recvmsg(can, &tmpmsg, no);
|
||||
if (ch == -1) break;
|
||||
|
||||
/* disable interrupt */
|
||||
level = rt_hw_interrupt_disable();
|
||||
can->status.rcvpkg++;
|
||||
can->status.rcvchange = 1;
|
||||
if (!rt_list_isempty(&rx_fifo->freelist))
|
||||
{
|
||||
listmsg = rt_list_entry(rx_fifo->freelist.next, struct rt_can_msg_list, list);
|
||||
rt_list_remove(&listmsg->list);
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
rt_list_remove(&listmsg->hdrlist);
|
||||
if (listmsg->owner != RT_NULL && listmsg->owner->msgs)
|
||||
{
|
||||
listmsg->owner->msgs--;
|
||||
}
|
||||
listmsg->owner = RT_NULL;
|
||||
#endif /*RT_CAN_USING_HDR*/
|
||||
RT_ASSERT(rx_fifo->freenumbers > 0);
|
||||
rx_fifo->freenumbers--;
|
||||
}
|
||||
else if (!rt_list_isempty(&rx_fifo->uselist))
|
||||
{
|
||||
listmsg = rt_list_entry(rx_fifo->uselist.next, struct rt_can_msg_list, list);
|
||||
can->status.dropedrcvpkg++;
|
||||
rt_list_remove(&listmsg->list);
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
rt_list_remove(&listmsg->hdrlist);
|
||||
if (listmsg->owner != RT_NULL && listmsg->owner->msgs)
|
||||
{
|
||||
listmsg->owner->msgs--;
|
||||
}
|
||||
listmsg->owner = RT_NULL;
|
||||
#endif
|
||||
}
|
||||
/* enable interrupt */
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
if (listmsg != RT_NULL)
|
||||
{
|
||||
rt_memcpy(&listmsg->data, &tmpmsg, sizeof(struct rt_can_msg));
|
||||
level = rt_hw_interrupt_disable();
|
||||
rt_list_insert_before(&rx_fifo->uselist, &listmsg->list);
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
hdr = tmpmsg.hdr_index;
|
||||
if (can->hdr != RT_NULL)
|
||||
{
|
||||
RT_ASSERT(hdr < can->config.maxhdr && hdr >= 0);
|
||||
if (can->hdr[hdr].connected)
|
||||
{
|
||||
rt_list_insert_before(&can->hdr[hdr].list, &listmsg->hdrlist);
|
||||
listmsg->owner = &can->hdr[hdr];
|
||||
can->hdr[hdr].msgs++;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
rt_hw_interrupt_enable(level);
|
||||
}
|
||||
|
||||
/* invoke callback */
|
||||
#ifdef RT_CAN_USING_HDR
|
||||
if (can->hdr != RT_NULL && can->hdr[hdr].connected && can->hdr[hdr].filter.ind)
|
||||
{
|
||||
rt_size_t rx_length;
|
||||
RT_ASSERT(hdr < can->config.maxhdr && hdr >= 0);
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
rx_length = can->hdr[hdr].msgs * sizeof(struct rt_can_msg);
|
||||
rt_hw_interrupt_enable(level);
|
||||
if (rx_length)
|
||||
{
|
||||
can->hdr[hdr].filter.ind(&can->parent, can->hdr[hdr].filter.args, hdr, rx_length);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (can->parent.rx_indicate != RT_NULL)
|
||||
{
|
||||
rt_size_t rx_length;
|
||||
|
||||
level = rt_hw_interrupt_disable();
|
||||
/* get rx length */
|
||||
rx_length = rt_list_len(&rx_fifo->uselist)* sizeof(struct rt_can_msg);
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
if (rx_length)
|
||||
{
|
||||
can->parent.rx_indicate(&can->parent, rx_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RT_CAN_EVENT_TX_DONE:
|
||||
case RT_CAN_EVENT_TX_FAIL:
|
||||
{
|
||||
struct rt_can_tx_fifo *tx_fifo;
|
||||
rt_uint32_t no;
|
||||
no = event >> 8;
|
||||
tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
|
||||
RT_ASSERT(tx_fifo != RT_NULL);
|
||||
|
||||
if ((event & 0xff) == RT_CAN_EVENT_TX_DONE)
|
||||
{
|
||||
tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_ERR;
|
||||
}
|
||||
rt_completion_done(&(tx_fifo->buffer[no].completion));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RT_USING_FINSH
|
||||
#include <finsh.h>
|
||||
int cmd_canstat(int argc, void **argv)
|
||||
{
|
||||
static const char *ErrCode[] =
|
||||
{
|
||||
"No Error!",
|
||||
"Warning !",
|
||||
"Passive !",
|
||||
"Bus Off !"
|
||||
};
|
||||
|
||||
if (argc >= 2)
|
||||
{
|
||||
struct rt_can_status status;
|
||||
rt_device_t candev = rt_device_find(argv[1]);
|
||||
if (!candev)
|
||||
{
|
||||
rt_kprintf(" Can't find can device %s\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
rt_kprintf(" Found can device: %s...", argv[1]);
|
||||
|
||||
rt_device_control(candev, RT_CAN_CMD_GET_STATUS, &status);
|
||||
rt_kprintf("\n Receive...error..count: %010ld. Send.....error....count: %010ld.",
|
||||
status.rcverrcnt, status.snderrcnt);
|
||||
rt_kprintf("\n Bit..pad..error..count: %010ld. Format...error....count: %010ld",
|
||||
status.bitpaderrcnt, status.formaterrcnt);
|
||||
rt_kprintf("\n Ack.......error..count: %010ld. Bit......error....count: %010ld.",
|
||||
status.ackerrcnt, status.biterrcnt);
|
||||
rt_kprintf("\n CRC.......error..count: %010ld. Error.code.[%010ld]: ",
|
||||
status.crcerrcnt, status.errcode);
|
||||
switch (status.errcode)
|
||||
{
|
||||
case 0:
|
||||
rt_kprintf("%s.", ErrCode[0]);
|
||||
break;
|
||||
case 1:
|
||||
rt_kprintf("%s.", ErrCode[1]);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
rt_kprintf("%s.", ErrCode[2]);
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
rt_kprintf("%s.", ErrCode[3]);
|
||||
break;
|
||||
}
|
||||
rt_kprintf("\n Total.receive.packages: %010ld. Dropped.receive.packages: %010ld.",
|
||||
status.rcvpkg, status.dropedrcvpkg);
|
||||
rt_kprintf("\n Total..send...packages: %010ld. Dropped...send..packages: %010ld.\n",
|
||||
status.sndpkg + status.dropedsndpkg, status.dropedsndpkg);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf(" Invalid Call %s\n", argv[0]);
|
||||
rt_kprintf(" Please using %s cannamex .Here canname is driver name and x is candrive number.\n", argv[0]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
MSH_CMD_EXPORT_ALIAS(cmd_canstat, canstat, stat can device status);
|
||||
#endif
|
@ -3,7 +3,3 @@ 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,10 +55,6 @@ 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;
|
||||
}
|
||||
@ -80,7 +76,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 (!rt_is_err(clk))
|
||||
if (clk)
|
||||
{
|
||||
clk_get(clk_np);
|
||||
|
||||
@ -139,6 +135,15 @@ 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;
|
||||
|
||||
@ -147,31 +152,16 @@ 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);
|
||||
clk_np->multi_clk = 0;
|
||||
|
||||
if (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
|
||||
{
|
||||
clk_np->parent = RT_NULL;
|
||||
|
||||
@ -275,16 +265,11 @@ 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->prepare_count == 0 && clk_np->ops->prepare)
|
||||
if (clk_np->ops->prepare)
|
||||
{
|
||||
err = clk_np->ops->prepare(clk);
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
++clk->prepare_count;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -302,6 +287,10 @@ rt_err_t rt_clk_prepare(struct rt_clk *clk)
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -313,14 +302,10 @@ static void clk_unprepare(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
||||
clk_unprepare(clk_np->clk, clk_np->parent);
|
||||
}
|
||||
|
||||
if (clk->prepare_count == 1 && clk_np->ops->unprepare)
|
||||
if (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)
|
||||
@ -337,6 +322,10 @@ rt_err_t rt_clk_unprepare(struct rt_clk *clk)
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -350,16 +339,11 @@ 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->enable_count == 0 && clk_np->ops->enable)
|
||||
if (clk_np->ops->enable)
|
||||
{
|
||||
err = clk_np->ops->enable(clk);
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
++clk->enable_count;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -375,6 +359,10 @@ rt_err_t rt_clk_enable(struct rt_clk *clk)
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -386,14 +374,10 @@ static void clk_disable(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
||||
clk_disable(clk_np->clk, clk_np->parent);
|
||||
}
|
||||
|
||||
if (clk->enable_count == 1 && clk_np->ops->disable)
|
||||
if (clk_np->ops->disable)
|
||||
{
|
||||
clk_np->ops->disable(clk);
|
||||
}
|
||||
if (clk->enable_count)
|
||||
{
|
||||
--clk->enable_count;
|
||||
}
|
||||
}
|
||||
|
||||
void rt_clk_disable(struct rt_clk *clk)
|
||||
@ -410,7 +394,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_EOK;
|
||||
rt_err_t err;
|
||||
|
||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||
|
||||
@ -428,6 +412,10 @@ rt_err_t rt_clk_prepare_enable(struct rt_clk *clk)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -465,6 +453,10 @@ rt_err_t rt_clk_array_prepare(struct rt_clk_array *clk_arr)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -486,6 +478,10 @@ rt_err_t rt_clk_array_unprepare(struct rt_clk_array *clk_arr)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -512,6 +508,10 @@ rt_err_t rt_clk_array_enable(struct rt_clk_array *clk_arr)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -529,16 +529,29 @@ 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_err_t err = RT_EOK;
|
||||
|
||||
if ((err = rt_clk_array_prepare(clk_arr)))
|
||||
if (clk_arr)
|
||||
{
|
||||
return err;
|
||||
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]);
|
||||
}
|
||||
|
||||
if ((err = rt_clk_array_enable(clk_arr)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_clk_array_unprepare(clk_arr);
|
||||
err = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
@ -546,8 +559,13 @@ 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)
|
||||
{
|
||||
rt_clk_array_disable(clk_arr);
|
||||
rt_clk_array_unprepare(clk_arr);
|
||||
if (clk_arr)
|
||||
{
|
||||
for (int i = 0; i < clk_arr->count; ++i)
|
||||
{
|
||||
rt_clk_disable_unprepare(clk_arr->clks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rt_err_t rt_clk_set_rate_range(struct rt_clk *clk, rt_ubase_t min, rt_ubase_t max)
|
||||
@ -586,6 +604,10 @@ 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;
|
||||
}
|
||||
@ -600,6 +622,10 @@ 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;
|
||||
}
|
||||
@ -614,6 +640,10 @@ 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;
|
||||
}
|
||||
@ -622,9 +652,7 @@ rt_err_t rt_clk_set_rate(struct rt_clk *clk, rt_ubase_t rate)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
|
||||
rate = rt_clk_round_rate(clk, rate);
|
||||
|
||||
if (clk && clk->clk_np && rate > 0)
|
||||
if (clk && clk->clk_np)
|
||||
{
|
||||
struct rt_clk_node *clk_np = clk->clk_np;
|
||||
|
||||
@ -662,13 +690,17 @@ 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 = 0;
|
||||
rt_ubase_t rate = -1UL;
|
||||
|
||||
if (clk)
|
||||
{
|
||||
@ -697,6 +729,10 @@ 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;
|
||||
}
|
||||
@ -713,21 +749,22 @@ 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_EINVAL;
|
||||
rt_base_t res = RT_EOK;
|
||||
|
||||
if (clk && clk->clk_np)
|
||||
{
|
||||
struct rt_clk_node *clk_np = clk->clk_np;
|
||||
|
||||
if (clk_np->ops->round_rate)
|
||||
if (clk && clk->clk_np && clk->clk_np->ops->round_rate)
|
||||
{
|
||||
rt_ubase_t best_parent_rate;
|
||||
struct rt_clk_node *clk_np = clk->clk_np;
|
||||
|
||||
rt_hw_spin_lock(&_clk_lock.lock);
|
||||
|
||||
@ -736,26 +773,14 @@ rt_base_t rt_clk_round_rate(struct rt_clk *clk, rt_ubase_t rate)
|
||||
rate = rt_clamp(rate, clk_np->min_rate, clk_np->max_rate);
|
||||
}
|
||||
|
||||
res = clk_np->ops->round_rate(clk, rate, &best_parent_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
|
||||
{
|
||||
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 = -RT_EINVAL;
|
||||
}
|
||||
|
||||
return res;
|
||||
@ -773,6 +798,10 @@ 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;
|
||||
}
|
||||
@ -858,7 +887,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, rt_bool_t locked)
|
||||
static struct rt_clk *ofw_get_clk_no_lock(struct rt_ofw_node *np, int index, const char *name)
|
||||
{
|
||||
struct rt_clk *clk = RT_NULL;
|
||||
struct rt_ofw_cell_args clk_args;
|
||||
@ -866,32 +895,10 @@ 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;
|
||||
|
||||
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);
|
||||
struct rt_clk_node *clk_np = rt_ofw_data(clk_ofw_np);
|
||||
|
||||
count = rt_ofw_count_of_clk(clk_ofw_np);
|
||||
}
|
||||
|
||||
rt_ofw_node_put(clk_ofw_np);
|
||||
|
||||
@ -905,10 +912,6 @@ 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;
|
||||
@ -920,7 +923,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, RT_TRUE);
|
||||
clk = ofw_get_clk_no_lock(np, index, name);
|
||||
|
||||
rt_hw_spin_unlock(&_clk_lock.lock);
|
||||
|
||||
@ -932,11 +935,6 @@ 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);
|
||||
@ -944,7 +942,6 @@ 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;
|
||||
@ -960,12 +957,10 @@ 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, RT_FALSE);
|
||||
clk_arr->clks[i] = ofw_get_clk_no_lock(np, i, name);
|
||||
|
||||
if (rt_is_err(clk_arr->clks[i]))
|
||||
if (!clk_arr->clks[i])
|
||||
{
|
||||
err = rt_ptr_err(clk_arr->clks[i]);
|
||||
|
||||
--i;
|
||||
break;
|
||||
}
|
||||
@ -976,7 +971,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_err_ptr(err);
|
||||
clk_arr = RT_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -360,9 +360,9 @@ rt_err_t rt_bus_remove_device(rt_device_t dev)
|
||||
}
|
||||
else if (drv)
|
||||
{
|
||||
if (drv->remove)
|
||||
if (drv->shutdown)
|
||||
{
|
||||
err = drv->remove(dev);
|
||||
err = drv->shutdown(dev);
|
||||
}
|
||||
|
||||
/* device and driver are in the same bus */
|
||||
|
@ -13,8 +13,6 @@
|
||||
* 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>
|
||||
@ -31,9 +29,9 @@
|
||||
#include <rtdevice.h> /* for wqueue_init */
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
|
||||
#if defined (RT_USING_DFS_V2) && defined (RT_USING_DFS_DEVFS)
|
||||
#ifdef RT_USING_DFS_V2
|
||||
#include <devfs.h>
|
||||
#endif /* RT_USING_DFS_V2 RT_USING_DFS_DEVFS */
|
||||
#endif /* RT_USING_DFS_V2 */
|
||||
|
||||
#ifdef RT_USING_DEVICE
|
||||
|
||||
@ -84,7 +82,7 @@ rt_err_t rt_device_register(rt_device_t dev,
|
||||
rt_wqueue_init(&(dev->wait_queue));
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
|
||||
#if defined (RT_USING_DFS_V2) && defined (RT_USING_DFS_DEVFS)
|
||||
#ifdef RT_USING_DFS_V2
|
||||
dfs_devfs_device_add(dev);
|
||||
#endif /* RT_USING_DFS_V2 */
|
||||
|
||||
@ -165,7 +163,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_Null);
|
||||
RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
|
||||
RT_ASSERT(rt_object_is_systemobject(&dev->parent) == RT_FALSE);
|
||||
|
||||
rt_object_detach(&(dev->parent));
|
||||
@ -197,8 +195,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",
|
||||
RT_NAME_MAX, dev->parent.name, result);
|
||||
LOG_E("To initialize device:%s failed. The error code is %d",
|
||||
dev->parent.name, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -235,8 +233,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",
|
||||
RT_NAME_MAX, dev->parent.name, result);
|
||||
LOG_E("To initialize device:%s failed. The error code is %d",
|
||||
dev->parent.name, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -254,7 +252,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) | RT_DEVICE_OFLAG_OPEN)))
|
||||
((dev->open_flag & RT_DEVICE_OFLAG_MASK) != (oflag & RT_DEVICE_OFLAG_MASK)))
|
||||
{
|
||||
if (device_open != RT_NULL)
|
||||
{
|
||||
|
@ -53,137 +53,6 @@ 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;
|
||||
|
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