import RT-Thread@9217865c without bsp, libcpu and components/net

This commit is contained in:
Zihao Yu 2023-05-20 16:23:33 +08:00
commit e2376a3709
1414 changed files with 390370 additions and 0 deletions

972
components/drivers/Kconfig Executable file
View file

@ -0,0 +1,972 @@
menu "Device Drivers"
config RT_USING_DEVICE_IPC
bool "Using device drivers IPC"
default y
config RT_UNAMED_PIPE_NUMBER
int "The number of unamed pipe"
default 64
if RT_USING_DEVICE_IPC
config RT_USING_SYSTEM_WORKQUEUE
bool "Using system default workqueue"
default n
if RT_USING_SYSTEM_WORKQUEUE
config RT_SYSTEM_WORKQUEUE_STACKSIZE
int "The stack size for system workqueue thread"
default 2048
config RT_SYSTEM_WORKQUEUE_PRIORITY
int "The priority level of system workqueue thread"
default 23
endif
endif
menuconfig RT_USING_SERIAL
bool "USING Serial device drivers"
select RT_USING_DEVICE_IPC
select RT_USING_DEVICE
default y
if RT_USING_SERIAL
choice
prompt "Choice Serial version"
default RT_USING_SERIAL_V1
config RT_USING_SERIAL_V1
bool "RT_USING_SERIAL_V1"
config RT_USING_SERIAL_V2
bool "RT_USING_SERIAL_V2"
endchoice
config RT_SERIAL_USING_DMA
bool "Enable serial DMA mode"
default y
config RT_SERIAL_RB_BUFSZ
int "Set RX buffer size"
depends on !RT_USING_SERIAL_V2
default 64
endif
config RT_USING_TTY
bool "Using TTY SYSTEM"
depends on RT_USING_SMART
default y
if RT_USING_TTY
config RT_TTY_DEBUG
bool "Using TTY DEBUG"
default n
endif
config RT_USING_CAN
bool "Using CAN device drivers"
default n
if RT_USING_CAN
config RT_CAN_USING_HDR
bool "Enable CAN hardware filter"
default n
config RT_CAN_USING_CANFD
bool "Enable CANFD support"
default n
endif
config RT_USING_HWTIMER
bool "Using hardware timer device drivers"
default n
config RT_USING_CPUTIME
bool "Enable CPU time for high resolution clock counter"
default n
help
When enable this option, the BSP should provide a rt_clock_cputime_ops
for CPU time by:
const static struct rt_clock_cputime_ops _ops = {...};
clock_cpu_setops(&_ops);
Then user can use high resolution clock counter with:
ts1 = clock_cpu_gettime();
ts2 = clock_cpu_gettime();
/* and get the ms of delta tick with API: */
ms_tick = clock_cpu_millisecond(t2 - t1);
us_tick = clock_cpu_microsecond(t2 - t1);
if RT_USING_CPUTIME
config RT_USING_CPUTIME_CORTEXM
bool "Support Cortex-M CPU"
default y
depends on ARCH_ARM_CORTEX_M0 || ARCH_ARM_CORTEX_M3 || ARCH_ARM_CORTEX_M4 || ARCH_ARM_CORTEX_M7
select PKG_USING_PERF_COUNTER
config RT_USING_CPUTIME_RISCV
bool "Use rdtime instructions for CPU time"
default y
depends on ARCH_RISCV64
help
Some RISCV64 MCU Use rdtime instructions read CPU time.
config CPUTIME_TIMER_FREQ
int "CPUTIME timer freq"
default 0
endif
config RT_USING_I2C
bool "Using I2C device drivers"
default n
if RT_USING_I2C
config RT_I2C_DEBUG
bool "Use I2C debug message"
default n
config RT_USING_I2C_BITOPS
bool "Use GPIO to simulate I2C"
default y
if RT_USING_I2C_BITOPS
config RT_I2C_BITOPS_DEBUG
bool "Use simulate I2C debug message"
default n
endif
endif
config RT_USING_PHY
bool "Using ethernet phy device drivers"
default n
config RT_USING_PIN
bool "Using generic GPIO device drivers"
default y
config RT_USING_ADC
bool "Using ADC device drivers"
default n
config RT_USING_DAC
bool "Using DAC device drivers"
default n
config RT_USING_NULL
bool "Using NULL device drivers"
default n
config RT_USING_ZERO
bool "Using ZERO device drivers"
default n
config RT_USING_RANDOM
bool "Using RANDOM device drivers"
default n
config RT_USING_PWM
bool "Using PWM device drivers"
default n
config RT_USING_MTD_NOR
bool "Using MTD Nor Flash device drivers"
default n
config RT_USING_MTD_NAND
bool "Using MTD Nand Flash device drivers"
default n
if RT_USING_MTD_NAND
config RT_MTD_NAND_DEBUG
bool "Enable MTD Nand operations debug information"
default n
endif
config RT_USING_PM
bool "Using Power Management device drivers"
default n
if RT_USING_PM
config PM_TICKLESS_THRESHOLD_TIME
int "PM tickless threashold time"
default 2
config PM_USING_CUSTOM_CONFIG
bool "PM using custom pm config"
default n
config PM_ENABLE_DEBUG
bool "PM Enable Debug"
default n
config PM_ENABLE_SUSPEND_SLEEP_MODE
bool "PM Device suspend change sleep mode"
default n
config PM_ENABLE_THRESHOLD_SLEEP_MODE
bool "PM using threshold time change sleep mode"
default n
if PM_ENABLE_THRESHOLD_SLEEP_MODE
config PM_LIGHT_THRESHOLD_TIME
int "PM light mode threashold time"
default 5
config PM_DEEP_THRESHOLD_TIME
int "PM deep mode threashold time"
default 20
config PM_STANDBY_THRESHOLD_TIME
int "PM standby mode threashold time"
default 100
endif
endif
config RT_USING_FDT
bool "Using fdt interface for device drivers"
default n
if RT_USING_FDT
config RT_USING_FDTLIB
bool "Using fdt lib for device drivers"
default y
config FDT_USING_DEBUG
bool "Using fdt debug function "
default n
endif
config RT_USING_RTC
bool "Using RTC device drivers"
default n
if RT_USING_RTC
config RT_USING_ALARM
bool "Using RTC alarm"
default n
config RT_USING_SOFT_RTC
bool "Using software simulation RTC device"
default n
endif
config RT_USING_SDIO
bool "Using SD/MMC device drivers"
default n
if RT_USING_SDIO
config RT_SDIO_STACK_SIZE
int "The stack size for sdio irq thread"
default 512
config RT_SDIO_THREAD_PRIORITY
int "The priority level value of sdio irq thread"
default 15
config RT_MMCSD_STACK_SIZE
int "The stack size for mmcsd thread"
default 1024
config RT_MMCSD_THREAD_PREORITY
int "The priority level value of mmcsd thread"
default 22
config RT_MMCSD_MAX_PARTITION
int "mmcsd max partition"
default 16
config RT_SDIO_DEBUG
bool "Enable SDIO debug log output"
default n
endif
config RT_USING_SPI
bool "Using SPI Bus/Device device drivers"
default n
if RT_USING_SPI
config RT_USING_SPI_BITOPS
select RT_USING_PIN
bool "Use GPIO to simulate SPI"
default n
if RT_USING_SPI_BITOPS
config RT_SPI_BITOPS_DEBUG
bool "Use simulate SPI debug message"
default n
endif
config RT_USING_QSPI
bool "Enable QSPI mode"
default n
config RT_USING_SPI_MSD
bool "Using SD/TF card driver with spi"
select RT_USING_DFS
default n
config RT_USING_SFUD
bool "Using Serial Flash Universal Driver"
default n
help
An using JEDEC's SFDP standard serial (SPI) flash universal driver library
if RT_USING_SFUD
config RT_SFUD_USING_SFDP
bool "Using auto probe flash JEDEC SFDP parameter"
default y
config RT_SFUD_USING_FLASH_INFO_TABLE
bool "Using defined supported flash chip information table"
default y
config RT_SFUD_USING_QSPI
bool "Using QSPI mode support"
select RT_USING_QSPI
default n
config RT_SFUD_SPI_MAX_HZ
int "Default spi maximum speed(HZ)"
range 0 50000000
default 50000000
help
Read the JEDEC SFDP command must run at 50 MHz or less,and you also can use rt_spi_configure(); to config spi speed.
config RT_DEBUG_SFUD
bool "Show more SFUD debug information"
default n
endif
config RT_USING_ENC28J60
bool "Using ENC28J60 SPI Ethernet network interface"
select RT_USING_LWIP
default n
config RT_USING_SPI_WIFI
bool "Using RW009/007 SPI Wi-Fi wireless interface"
select RT_USING_LWIP
default n
endif
config RT_USING_WDT
bool "Using Watch Dog device drivers"
default n
config RT_USING_AUDIO
bool "Using Audio device drivers"
default n
if RT_USING_AUDIO
config RT_AUDIO_REPLAY_MP_BLOCK_SIZE
int "Replay memory pool block size"
default 4096
config RT_AUDIO_REPLAY_MP_BLOCK_COUNT
int "Replay memory pool block count"
default 2
config RT_AUDIO_RECORD_PIPE_SIZE
int "Record pipe size"
default 2048
endif
config RT_USING_SENSOR
bool "Using Sensor device drivers"
select RT_USING_PIN
default n
if RT_USING_SENSOR
config RT_USING_SENSOR_CMD
bool "Using Sensor cmd"
select PKG_USING_RT_VSNPRINTF_FULL
default y
endif
config RT_USING_TOUCH
bool "Using Touch device drivers"
default n
if RT_USING_TOUCH
config RT_TOUCH_PIN_IRQ
bool "touch irq use pin irq"
default n
endif
config RT_USING_LCD
bool "Using LCD graphic drivers"
default n
menuconfig RT_USING_HWCRYPTO
bool "Using Hardware Crypto drivers"
default n
if RT_USING_HWCRYPTO
config RT_HWCRYPTO_DEFAULT_NAME
string "Hardware crypto device name"
default "hwcryto"
config RT_HWCRYPTO_IV_MAX_SIZE
int "IV max size"
default "16"
config RT_HWCRYPTO_KEYBIT_MAX_SIZE
int "Key max bit length"
default 256
config RT_HWCRYPTO_USING_GCM
bool "Using Hardware GCM"
default n
config RT_HWCRYPTO_USING_AES
bool "Using Hardware AES"
default n
if RT_HWCRYPTO_USING_AES
config RT_HWCRYPTO_USING_AES_ECB
bool "Using Hardware AES ECB mode"
default y
config RT_HWCRYPTO_USING_AES_CBC
bool "Using Hardware AES CBC mode"
default n
config RT_HWCRYPTO_USING_AES_CFB
bool "Using Hardware AES CFB mode"
default n
config RT_HWCRYPTO_USING_AES_CTR
bool "Using Hardware AES CTR mode"
default n
config RT_HWCRYPTO_USING_AES_OFB
bool "Using Hardware AES OFB mode"
default n
endif
config RT_HWCRYPTO_USING_DES
bool "Using Hardware DES"
default n
if RT_HWCRYPTO_USING_DES
config RT_HWCRYPTO_USING_DES_ECB
bool "Using Hardware DES ECB mode"
default y
config RT_HWCRYPTO_USING_DES_CBC
bool "Using Hardware DES CBC mode"
default n
endif
config RT_HWCRYPTO_USING_3DES
bool "Using Hardware 3DES"
default n
if RT_HWCRYPTO_USING_3DES
config RT_HWCRYPTO_USING_3DES_ECB
bool "Using Hardware 3DES ECB mode"
default y
config RT_HWCRYPTO_USING_3DES_CBC
bool "Using Hardware 3DES CBC mode"
default n
endif
config RT_HWCRYPTO_USING_RC4
bool "Using Hardware RC4"
default n
config RT_HWCRYPTO_USING_MD5
bool "Using Hardware MD5"
default n
config RT_HWCRYPTO_USING_SHA1
bool "Using Hardware SHA1"
default n
config RT_HWCRYPTO_USING_SHA2
bool "Using Hardware SHA2"
default n
if RT_HWCRYPTO_USING_SHA2
config RT_HWCRYPTO_USING_SHA2_224
bool "Using Hardware SHA2_224 mode"
default n
config RT_HWCRYPTO_USING_SHA2_256
bool "Using Hardware SHA2_256 mode"
default y
config RT_HWCRYPTO_USING_SHA2_384
bool "Using Hardware SHA2_384 mode"
default n
config RT_HWCRYPTO_USING_SHA2_512
bool "Using Hardware SHA2_512 mode"
default n
endif
config RT_HWCRYPTO_USING_RNG
bool "Using Hardware RNG"
default n
config RT_HWCRYPTO_USING_CRC
bool "Using Hardware CRC"
default n
if RT_HWCRYPTO_USING_CRC
config RT_HWCRYPTO_USING_CRC_07
bool "Using Hardware CRC-8 0x07 polynomial"
default n
config RT_HWCRYPTO_USING_CRC_8005
bool "Using Hardware CRC-16 0x8005 polynomial"
default n
config RT_HWCRYPTO_USING_CRC_1021
bool "Using Hardware CRC-16 0x1021 polynomial"
default n
config RT_HWCRYPTO_USING_CRC_3D65
bool "Using Hardware CRC-16 0x3D65 polynomial"
default n
config RT_HWCRYPTO_USING_CRC_04C11DB7
bool "Using Hardware CRC-32 0x04C11DB7 polynomial"
default n
endif
config RT_HWCRYPTO_USING_BIGNUM
bool "Using Hardware bignum"
default n
if RT_HWCRYPTO_USING_BIGNUM
config RT_HWCRYPTO_USING_BIGNUM_EXPTMOD
bool "Using Hardware bignum expt_mod operation"
default y
config RT_HWCRYPTO_USING_BIGNUM_MULMOD
bool "Using Hardware bignum mul_mod operation"
default y
config RT_HWCRYPTO_USING_BIGNUM_MUL
bool "Using Hardware bignum mul operation"
default n
config RT_HWCRYPTO_USING_BIGNUM_ADD
bool "Using Hardware bignum add operation"
default n
config RT_HWCRYPTO_USING_BIGNUM_SUB
bool "Using Hardware bignum sub operation"
default n
endif
endif
config RT_USING_PULSE_ENCODER
bool "Using PULSE ENCODER device drivers"
default n
config RT_USING_INPUT_CAPTURE
bool "Using INPUT CAPTURE device drivers"
default n
if RT_USING_INPUT_CAPTURE
config RT_INPUT_CAPTURE_RB_SIZE
int "Set input capture ringbuffer size"
default 100
endif
config RT_USING_DEV_BUS
bool "Using Device Bus device drivers"
default y if RT_USING_SMART
default n if !RT_USING_SMART
menuconfig RT_USING_WIFI
bool "Using Wi-Fi framework"
default n
if RT_USING_WIFI
config RT_WLAN_DEVICE_STA_NAME
string "The device name for station"
default "wlan0"
config RT_WLAN_DEVICE_AP_NAME
string "The device name for ap"
default "wlan1"
config RT_WLAN_SSID_MAX_LENGTH
int "SSID maximum length"
default 32
config RT_WLAN_PASSWORD_MAX_LENGTH
int "Password maximum length"
default 32
config RT_WLAN_DEV_EVENT_NUM
int "Driver events maxcount"
default 2
config RT_WLAN_MANAGE_ENABLE
bool "Connection management Enable"
default y
if RT_WLAN_MANAGE_ENABLE
config RT_WLAN_SCAN_WAIT_MS
int "Set scan timeout time(ms)"
default 10000
config RT_WLAN_CONNECT_WAIT_MS
int "Set connect timeout time(ms)"
default 10000
config RT_WLAN_SCAN_SORT
bool "Automatic sorting of scan results"
default y
config RT_WLAN_MSH_CMD_ENABLE
bool "MSH command Enable"
default y
config RT_WLAN_AUTO_CONNECT_ENABLE
bool "Auto connect Enable"
select RT_WLAN_CFG_ENABLE
select RT_WLAN_WORK_THREAD_ENABLE
default y
if RT_WLAN_AUTO_CONNECT_ENABLE
config AUTO_CONNECTION_PERIOD_MS
int "Auto connect period(ms)"
default 2000
endif
endif
config RT_WLAN_CFG_ENABLE
bool "WiFi information automatically saved Enable"
default y
if RT_WLAN_CFG_ENABLE
config RT_WLAN_CFG_INFO_MAX
int "Maximum number of WiFi information automatically saved"
default 3
endif
config RT_WLAN_PROT_ENABLE
bool "Transport protocol manage Enable"
default y
if RT_WLAN_PROT_ENABLE
config RT_WLAN_PROT_NAME_LEN
int "Transport protocol name length"
default 8
config RT_WLAN_PROT_MAX
int "Transport protocol maxcount"
default 2
config RT_WLAN_DEFAULT_PROT
string "Default transport protocol"
default "lwip"
config RT_WLAN_PROT_LWIP_ENABLE
bool "LWIP transport protocol Enable"
select RT_USING_LWIP
default y
if RT_WLAN_PROT_LWIP_ENABLE
config RT_WLAN_PROT_LWIP_NAME
string "LWIP transport protocol name"
default "lwip"
config RT_WLAN_PROT_LWIP_PBUF_FORCE
bool "Forced use of PBUF transmission"
default n
endif
endif
config RT_WLAN_WORK_THREAD_ENABLE
bool "WLAN work queue thread Enable"
default y
if RT_WLAN_WORK_THREAD_ENABLE
config RT_WLAN_WORKQUEUE_THREAD_NAME
string "WLAN work queue thread name"
default "wlan"
config RT_WLAN_WORKQUEUE_THREAD_SIZE
int "WLAN work queue thread size"
default 2048
config RT_WLAN_WORKQUEUE_THREAD_PRIO
int "WLAN work queue thread priority"
default 15
endif
menuconfig RT_WLAN_DEBUG
bool "Enable WLAN Debugging Options"
default n
if RT_WLAN_DEBUG
config RT_WLAN_CMD_DEBUG
bool "Enable Debugging of wlan_cmd.c"
default n
config RT_WLAN_MGNT_DEBUG
bool "Enable Debugging of wlan_mgnt.c"
default n
config RT_WLAN_DEV_DEBUG
bool "Enable Debugging of wlan_dev.c"
default n
config RT_WLAN_PROT_DEBUG
bool "Enable Debugging of wlan_prot.c"
default n
config RT_WLAN_CFG_DEBUG
bool "Enable Debugging of wlan_cfg.c"
default n
config RT_WLAN_LWIP_DEBUG
bool "Enable Debugging of wlan_lwip.c"
default n
endif
endif
menuconfig RT_USING_VIRTIO
bool "Using VirtIO device drivers"
default n
if RT_USING_VIRTIO
choice
prompt "VirtIO Version"
default RT_USING_VIRTIO10
config RT_USING_VIRTIO10
bool "VirtIO v1.0"
endchoice
config RT_USING_VIRTIO_MMIO_ALIGN
bool "Using VirtIO MMIO alignment"
default y
config RT_USING_VIRTIO_BLK
bool "Using VirtIO BLK"
default y
config RT_USING_VIRTIO_NET
bool "Using VirtIO NET"
default y
menuconfig RT_USING_VIRTIO_CONSOLE
bool "Using VirtIO Console"
default y
if RT_USING_VIRTIO_CONSOLE
config RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR
int "Max number of port in VirtIO Console"
default 4
endif
config RT_USING_VIRTIO_GPU
bool "Using VirtIO GPU"
default y
config RT_USING_VIRTIO_INPUT
bool "Using VirtIO Input"
default y
endif
menu "Using USB"
config RT_USING_USB
bool
default n
config RT_USING_USB_HOST
bool "Using USB host"
default n
select RT_USING_USB
if RT_USING_USB_HOST
config RT_USBH_MSTORAGE
bool "Enable Udisk Drivers"
default n
if RT_USBH_MSTORAGE
config UDISK_MOUNTPOINT
string "Udisk mount dir"
default "/"
endif
config RT_USBH_HID
bool "Enable HID Drivers"
default n
if RT_USBH_HID
config RT_USBH_HID_MOUSE
bool "Enable HID mouse protocol"
default n
config RT_USBH_HID_KEYBOARD
bool "Enable HID keyboard protocol"
default n
endif
endif
config RT_USING_USB_DEVICE
bool "Using USB device"
default n
select RT_USING_USB
if RT_USING_USB_DEVICE || RT_USING_USB_HOST
config RT_USBD_THREAD_STACK_SZ
int "usb thread stack size"
default 4096
endif
if RT_USING_USB_DEVICE
config USB_VENDOR_ID
hex "USB Vendor ID"
default 0x0FFE
config USB_PRODUCT_ID
hex "USB Product ID"
default 0x0001
config RT_USB_DEVICE_COMPOSITE
bool "Enable composite device"
default n
choice
prompt "Device type"
default _RT_USB_DEVICE_NONE
depends on !RT_USB_DEVICE_COMPOSITE
config _RT_USB_DEVICE_NONE
bool "Using custom class by register interface"
select RT_USB_DEVICE_NONE
config _RT_USB_DEVICE_CDC
bool "Enable to use device as CDC device"
select RT_USB_DEVICE_CDC
config _RT_USB_DEVICE_MSTORAGE
bool "Enable to use device as Mass Storage device"
select RT_USB_DEVICE_MSTORAGE
config _RT_USB_DEVICE_HID
bool "Enable to use device as HID device"
select RT_USB_DEVICE_HID
config _RT_USB_DEVICE_RNDIS
bool "Enable to use device as rndis device"
select RT_USB_DEVICE_RNDIS
depends on RT_USING_LWIP
config _RT_USB_DEVICE_ECM
bool "Enable to use device as ecm device"
select RT_USB_DEVICE_ECM
depends on RT_USING_LWIP
config _RT_USB_DEVICE_WINUSB
bool "Enable to use device as winusb device"
select RT_USB_DEVICE_WINUSB
config _RT_USB_DEVICE_AUDIO
bool "Enable to use device as audio device"
select RT_USB_DEVICE_AUDIO
endchoice
if RT_USB_DEVICE_COMPOSITE
config RT_USB_DEVICE_CDC
bool "Enable to use device as CDC device"
default n
config RT_USB_DEVICE_NONE
bool
default y
config RT_USB_DEVICE_MSTORAGE
bool "Enable to use device as Mass Storage device"
default n
config RT_USB_DEVICE_HID
bool "Enable to use device as HID device"
default n
config RT_USB_DEVICE_RNDIS
bool "Enable to use device as rndis device"
default n
depends on RT_USING_LWIP
config RT_USB_DEVICE_ECM
bool "Enable to use device as ecm device"
default n
depends on RT_USING_LWIP
config RT_USB_DEVICE_WINUSB
bool "Enable to use device as winusb device"
default n
config RT_USB_DEVICE_AUDIO
bool "Enable to use device as audio device"
default n
endif
if RT_USB_DEVICE_CDC
config RT_VCOM_TASK_STK_SIZE
int "virtual com thread stack size"
default 512
config RT_CDC_RX_BUFSIZE
int "virtual com rx buffer size"
default 128
config RT_VCOM_TX_USE_DMA
bool "Enable to use dma for vcom tx"
default n
config RT_VCOM_SERNO
string "serial number of virtual com"
default "32021919830108"
config RT_VCOM_SER_LEN
int "serial number length of virtual com"
default 14
config RT_VCOM_TX_TIMEOUT
int "tx timeout(ticks) of virtual com"
default 1000
endif
if RT_USB_DEVICE_WINUSB
config RT_WINUSB_GUID
string "Guid for winusb"
default "{6860DC3C-C05F-4807-8807-1CA861CC1D66}"
endif
if RT_USB_DEVICE_MSTORAGE
config RT_USB_MSTORAGE_DISK_NAME
string "msc class disk name"
default "flash0"
endif
if RT_USB_DEVICE_RNDIS
config RNDIS_DELAY_LINK_UP
bool "Delay linkup media connection"
select RT_USING_TIMER_SOFT
default n
endif
if RT_USB_DEVICE_HID
config RT_USB_DEVICE_HID_KEYBOARD
bool "Use to HID device as Keyboard"
default n
if RT_USB_DEVICE_HID_KEYBOARD
config RT_USB_DEVICE_HID_KEYBOARD_NUMBER
int "Number of Keyboard(max 3)"
default 1
range 1 3
endif
config RT_USB_DEVICE_HID_MOUSE
bool "Use to HID device as Mouse"
default n
config RT_USB_DEVICE_HID_GENERAL
bool "Use to HID device as General HID device"
default y
if RT_USB_DEVICE_HID_GENERAL
config RT_USB_DEVICE_HID_GENERAL_OUT_REPORT_LENGTH
int "General HID device out report length"
default 63
range 0 63
config RT_USB_DEVICE_HID_GENERAL_IN_REPORT_LENGTH
int "General HID device in report length"
default 63
range 0 63
endif
config RT_USB_DEVICE_HID_MEDIA
bool "Use to HID device as media keyboard"
default y
endif
if RT_USB_DEVICE_AUDIO
config RT_USB_DEVICE_AUDIO_MIC
bool "Use usb mic device as audio device"
default n
if RT_USB_DEVICE_AUDIO_MIC
config RT_USBD_MIC_DEVICE_NAME
string "audio mic device name"
default "mic0"
endif
config RT_USB_DEVICE_AUDIO_SPEAKER
bool "Use usb speaker device as audio device"
default n
if RT_USB_DEVICE_AUDIO_SPEAKER
config RT_USBD_SPEAKER_DEVICE_NAME
string "audio speaker device name"
default "sound0"
endif
endif
endif
endmenu
endmenu

View file

@ -0,0 +1,14 @@
# for module compiling
import os
from building import *
cwd = GetCurrentDir()
objs = []
list = os.listdir(cwd)
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'))
Return('objs')

View file

@ -0,0 +1,9 @@
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_AUDIO'], CPPPATH = CPPPATH)
Return('group')

View file

@ -0,0 +1,612 @@
/*
* 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);
}

View file

@ -0,0 +1,300 @@
/*
* 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 "audio_pipe.h"
static void _rt_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_list_entry(pipe->suspended_write_list.next,
struct rt_thread,
tlist);
/* resume the write thread */
rt_thread_resume(thread);
rt_schedule();
}
}
static rt_ssize_t rt_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_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),
&(thread->tlist));
rt_hw_interrupt_enable(level);
rt_schedule();
}
else
{
_rt_pipe_resume_writer(pipe);
rt_hw_interrupt_enable(level);
break;
}
}
while (read_nbytes == 0);
return read_nbytes;
}
static void _rt_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_list_entry(pipe->suspended_read_list.next,
struct rt_thread,
tlist);
/* resume the read thread */
rt_thread_resume(thread);
rt_schedule();
}
}
static rt_ssize_t rt_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_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),
&(thread->tlist));
rt_hw_interrupt_enable(level);
rt_schedule();
}
else
{
_rt_pipe_resume_reader(pipe);
rt_hw_interrupt_enable(level);
break;
}
}
while (write_nbytes == 0);
return write_nbytes;
}
static rt_err_t rt_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_pipe_read,
rt_pipe_write,
rt_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_pipe_read;
pipe->parent.write = rt_pipe_write;
pipe->parent.control = rt_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 */

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef __AUDIO_PIPE_H__
#define __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 /* __AUDIO_PIPE_H__ */

View file

@ -0,0 +1,8 @@
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd + '/../include']
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_CAN'], CPPPATH = CPPPATH)
Return('group')

View file

@ -0,0 +1,971 @@
/*
* Copyright (c) 2006-2023, 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 int _can_int_rx(struct rt_can_device *can, struct rt_can_msg *data, int msgs)
{
int 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)
{
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_uint32_t)tx_tosnd - (rt_uint32_t)tx_fifo->buffer) / sizeof(struct rt_can_sndbxinx_list);
tx_tosnd->result = RT_CAN_SND_RESULT_WAIT;
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;
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;
/* clear can rx interrupt */
can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
}
if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
{
struct rt_can_tx_fifo *tx_fifo;
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;
/* clear can tx interrupt */
can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_TX);
}
can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_CAN_INT_ERR);
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)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

View file

@ -0,0 +1,132 @@
说明:
本驱动完成了can控制器硬件抽象
一 CAN Driver 注册
Can driver注册需要填充以下几个数据结构
1、struct can_configure
{
rt_uint32_t baud_rate;
rt_uint32_t msgboxsz;
rt_uint32_t sndboxnumber;
rt_uint32_t mode :8;
rt_uint32_t privmode :8;
rt_uint32_t reserved :16;
#ifdef RT_CAN_USING_LED
const struct rt_can_led* rcvled;
const struct rt_can_led* sndled;
const struct rt_can_led* errled;
#endif /*RT_CAN_USING_LED*/
rt_uint32_t ticks;
#ifdef RT_CAN_USING_HDR
rt_uint32_t maxhdr;
#endif
};
struct can_configure 为can驱动的基本配置信息:
baud_rate :
enum CANBAUD
{
CAN1MBaud=0, // 1 MBit/sec
CAN800kBaud, // 800 kBit/sec
CAN500kBaud, // 500 kBit/sec
CAN250kBaud, // 250 kBit/sec
CAN125kBaud, // 125 kBit/sec
CAN100kBaud, // 100 kBit/sec
CAN50kBaud, // 50 kBit/sec
CAN20kBaud, // 20 kBit/sec
CAN10kBaud // 10 kBit/sec
};
配置Can的波特率。
msgboxsz : Can接收邮箱缓冲数量本驱动在软件层开辟msgboxsz个接收邮箱。
sndboxnumber : can 发送通道数量该配置为Can控制器实际的发送通道数量。
mode
#define RT_CAN_MODE_NORMAL 0 正常模式
#define RT_CAN_MODE_LISEN 1 只听模式
#define RT_CAN_MODE_LOOPBACK 2 自发自收模式
#define RT_CAN_MODE_LOOPBACKANLISEN 3 自发自收只听模式
配置Can 的工作状态。
privmode :
#define RT_CAN_MODE_PRIV 0x01 处于优先级模式,高优先级的消息优先发送。
#define RT_CAN_MODE_NOPRIV 0x00
配置Can driver的优先级模式。
#ifdef RT_CAN_USING_LED
const struct rt_can_led* rcvled;
const struct rt_can_led* sndled;
const struct rt_can_led* errled;
#endif /*RT_CAN_USING_LED*/
配置can led信息, 当前can驱动的led使用了 pin驱动
开启RT_CAN_USING_LED时要确保当前系统已实现pin驱动。
rt_uint32_t ticks : 配置Can driver timer周期。
#ifdef RT_CAN_USING_HDR
rt_uint32_t maxhdr;
#endif
如果使用硬件过滤则开启RT_CAN_USING_HDR, maxhdr 为Can控制器过滤表的数量。
2、struct rt_can_ops
{
rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg);
rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg);
int (*sendmsg)(struct rt_can_device *can, const void* buf, rt_uint32_t boxno);
int (*recvmsg)(struct rt_can_device *can,void* buf, rt_uint32_t boxno);
};
struct rt_can_ops 为要实现的特定的can控制器操作。
rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg);
configure根据配置信息初始化Can控制器工作模式。
rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg);
control 当前接受以下cmd参数
#define RT_CAN_CMD_SET_FILTER 0x13
#define RT_CAN_CMD_SET_BAUD 0x14
#define RT_CAN_CMD_SET_MODE 0x15
#define RT_CAN_CMD_SET_PRIV 0x16
#define RT_CAN_CMD_GET_STATUS 0x17
#define RT_CAN_CMD_SET_STATUS_IND 0x18
int (*sendmsg)(struct rt_can_device *can, const void* buf, rt_uint32_t boxno);
sendmsg向Can控制器发送数boxno为发送通道号。
int (*recvmsg)(struct rt_can_device *can,void* buf, rt_uint32_t boxno);
recvmsg从Can控制器接收数据boxno为接收通道号。
struct rt_can_device
{
struct rt_device parent;
const struct rt_can_ops *ops;
struct can_configure config;
struct rt_can_status status;
rt_uint32_t timerinitflag;
struct rt_timer timer;
struct rt_can_status_ind_type status_indicate;
#ifdef RT_CAN_USING_HDR
struct rt_can_hdr* hdr;
#endif
void *can_rx;
void *can_tx;
};
填充完成后便可调用rt_hw_can_register完成can驱动的注册。
二、 CAN Driver 的添加:
要添加一个新的Can驱动至少要完成以下接口。
1、struct rt_can_ops
{
rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg);
rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg);
int (*sendmsg)(struct rt_can_device *can, const void* buf, rt_uint32_t boxno);
int (*recvmsg)(struct rt_can_device *can,void* buf, rt_uint32_t boxno);
};
2、 rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg);
接口的
#define RT_CAN_CMD_SET_FILTER 0x13
#define RT_CAN_CMD_SET_BAUD 0x14
#define RT_CAN_CMD_SET_MODE 0x15
#define RT_CAN_CMD_SET_PRIV 0x16
#define RT_CAN_CMD_GET_STATUS 0x17
#define RT_CAN_CMD_SET_STATUS_IND 0x18
若干命令。
3、can口中断要完接收发送结束以及错误中断。
#define RT_CAN_EVENT_RX_IND 0x01 /* Rx indication */
#define RT_CAN_EVENT_TX_DONE 0x02 /* Tx complete */
#define RT_CAN_EVENT_TX_FAIL 0x03 /* Tx complete */
#define RT_CAN_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */
#define RT_CAN_EVENT_RXOF_IND 0x06 /* Rx overflow */
中断产生后调用rt_hw_can_isr(struct rt_can_device *can, int event)
进入相应的操作其中接收发送中断的event最低8位为上面的事件16到24位为通信通道号。
一个作为一个例子参见bsp/stm32f10x/driver下的bxcan.c 。
三、CAN Driver的使用
一个使用的例子参数bsp/stm32f10x/applications下的canapp.c
四、当前Can驱动没有实现轮模式采用中断模式bxcan驱动工作在loopback模式下的时候不能读数据。
五、当前Can驱动在stm32f105上测试暂无问题。

View file

@ -0,0 +1,18 @@
from building import *
cwd = GetCurrentDir()
CPPPATH = [cwd + '/../include']
src = Split('''
cputime.c
cputimer.c
''')
if GetDepend('RT_USING_CPUTIME_CORTEXM'):
src += ['cputime_cortexm.c']
if GetDepend('RT_USING_CPUTIME_RISCV'):
src += ['cputime_riscv.c']
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_CPUTIME'], CPPPATH = CPPPATH)
Return('group')

View file

@ -0,0 +1,116 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-12-23 Bernard first version
*/
#include <rtdevice.h>
#include <rtthread.h>
#include <sys/errno.h>
static const struct rt_clock_cputime_ops *_cputime_ops = RT_NULL;
/**
* The clock_cpu_getres() function shall return the resolution of CPU time, the
* number of nanosecond per tick.
*
* @return the number of nanosecond per tick(x (1000UL * 1000))
*/
uint64_t clock_cpu_getres(void)
{
if (_cputime_ops)
return _cputime_ops->cputime_getres();
rt_set_errno(ENOSYS);
return 0;
}
/**
* The clock_cpu_gettime() function shall return the current value of cpu time tick.
*
* @return the cpu tick
*/
uint64_t clock_cpu_gettime(void)
{
if (_cputime_ops)
return _cputime_ops->cputime_gettime();
rt_set_errno(ENOSYS);
return 0;
}
/**
* The clock_cpu_settimeout() fucntion set timeout time and timeout callback function
* The timeout callback function will be called when the timeout time is reached
*
* @param tick the Timeout tick
* @param timeout the Timeout function
* @param parameter the Parameters of timeout function
*
*/
int clock_cpu_settimeout(uint64_t tick, void (*timeout)(void *param), void *param)
{
if (_cputime_ops)
return _cputime_ops->cputime_settimeout(tick, timeout, param);
rt_set_errno(ENOSYS);
return 0;
}
int clock_cpu_issettimeout(void)
{
if (_cputime_ops)
return _cputime_ops->cputime_settimeout != RT_NULL;
return RT_FALSE;
}
/**
* The clock_cpu_microsecond() fucntion shall return the microsecond according to
* cpu_tick parameter.
*
* @param cpu_tick the cpu tick
*
* @return the microsecond
*/
uint64_t clock_cpu_microsecond(uint64_t cpu_tick)
{
uint64_t unit = clock_cpu_getres();
return (uint64_t)(((cpu_tick * unit) / (1000UL * 1000)) / 1000);
}
/**
* The clock_cpu_microsecond() fucntion shall return the millisecond according to
* cpu_tick parameter.
*
* @param cpu_tick the cpu tick
*
* @return the millisecond
*/
uint64_t clock_cpu_millisecond(uint64_t cpu_tick)
{
uint64_t unit = clock_cpu_getres();
return (uint64_t)(((cpu_tick * unit) / (1000UL * 1000)) / (1000UL * 1000));
}
/**
* The clock_cpu_seops() function shall set the ops of cpu time.
*
* @return always return 0.
*/
int clock_cpu_setops(const struct rt_clock_cputime_ops *ops)
{
_cputime_ops = ops;
if (ops)
{
RT_ASSERT(ops->cputime_getres != RT_NULL);
RT_ASSERT(ops->cputime_gettime != RT_NULL);
}
return 0;
}

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-12-23 Bernard first version
* 2022-06-14 Meco Man suuport pref_counter
*/
#include <rthw.h>
#include <rtdevice.h>
#include <rtthread.h>
#include <board.h>
#ifdef PKG_USING_PERF_COUNTER
#include <perf_counter.h>
#endif
/* Use Cycle counter of Data Watchpoint and Trace Register for CPU time */
static uint64_t cortexm_cputime_getres(void)
{
uint64_t ret = 1000UL * 1000 * 1000;
ret = (ret * (1000UL * 1000)) / SystemCoreClock;
return ret;
}
static uint64_t cortexm_cputime_gettime(void)
{
#ifdef PKG_USING_PERF_COUNTER
return get_system_ticks();
#else
return DWT->CYCCNT;
#endif
}
const static struct rt_clock_cputime_ops _cortexm_ops =
{
cortexm_cputime_getres,
cortexm_cputime_gettime
};
int cortexm_cputime_init(void)
{
#ifdef PKG_USING_PERF_COUNTER
clock_cpu_setops(&_cortexm_ops);
#else
/* check support bit */
if ((DWT->CTRL & (1UL << DWT_CTRL_NOCYCCNT_Pos)) == 0)
{
/* enable trace*/
CoreDebug->DEMCR |= (1UL << CoreDebug_DEMCR_TRCENA_Pos);
/* whether cycle counter not enabled */
if ((DWT->CTRL & (1UL << DWT_CTRL_CYCCNTENA_Pos)) == 0)
{
/* enable cycle counter */
DWT->CTRL |= (1UL << DWT_CTRL_CYCCNTENA_Pos);
}
clock_cpu_setops(&_cortexm_ops);
}
#endif /* PKG_USING_PERF_COUNTER */
return 0;
}
INIT_BOARD_EXPORT(cortexm_cputime_init);

View file

@ -0,0 +1,37 @@
#include <rthw.h>
#include <rtdevice.h>
#include <rtthread.h>
#include <board.h>
/* Use Cycle counter of Data Watchpoint and Trace Register for CPU time */
static uint64_t riscv_cputime_getres(void)
{
uint64_t ret = 1000UL * 1000 * 1000;
ret = (ret * (1000UL * 1000)) / CPUTIME_TIMER_FREQ;
return ret;
}
static uint64_t riscv_cputime_gettime(void)
{
uint64_t time_elapsed;
__asm__ __volatile__(
"rdtime %0"
: "=r"(time_elapsed));
return time_elapsed;
}
const static struct rt_clock_cputime_ops _riscv_ops =
{
riscv_cputime_getres,
riscv_cputime_gettime
};
int riscv_cputime_init(void)
{
clock_cpu_setops(&_riscv_ops);
return 0;
}
INIT_BOARD_EXPORT(riscv_cputime_init);

View file

@ -0,0 +1,339 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-02-13 zhkag first version
* 2023-04-03 xqyjlj fix cputimer in multithreading
*/
#include <rtdevice.h>
#include <rthw.h>
#include <rtthread.h>
static rt_list_t _cputimer_list = RT_LIST_OBJECT_INIT(_cputimer_list);
static struct rt_cputimer *_cputimer_nowtimer = RT_NULL;
static void _cputime_sleep_timeout(void *parameter)
{
struct rt_semaphore *sem;
sem = (struct rt_semaphore *)parameter;
rt_sem_release(sem);
}
static void _cputime_timeout_callback(void *parameter)
{
struct rt_cputimer *timer;
timer = (struct rt_cputimer *)parameter;
rt_base_t level;
level = rt_hw_interrupt_disable();
_cputimer_nowtimer = RT_NULL;
rt_list_remove(&(timer->row));
rt_hw_interrupt_enable(level);
timer->timeout_func(timer->parameter);
if (&_cputimer_list != _cputimer_list.prev)
{
struct rt_cputimer *t;
t = rt_list_entry(_cputimer_list.next, struct rt_cputimer, row);
clock_cpu_settimeout(t->timeout_tick, _cputime_timeout_callback, t);
}
else
{
clock_cpu_settimeout(RT_NULL, RT_NULL, RT_NULL);
}
}
static void _set_next_timeout()
{
struct rt_cputimer *t;
if (&_cputimer_list != _cputimer_list.prev)
{
t = rt_list_entry((&_cputimer_list)->next, struct rt_cputimer, row);
if (_cputimer_nowtimer != RT_NULL)
{
if (t != _cputimer_nowtimer && t->timeout_tick < _cputimer_nowtimer->timeout_tick)
{
_cputimer_nowtimer = t;
clock_cpu_settimeout(t->timeout_tick, _cputime_timeout_callback, t);
}
}
else
{
_cputimer_nowtimer = t;
clock_cpu_settimeout(t->timeout_tick, _cputime_timeout_callback, t);
}
}
else
{
_cputimer_nowtimer = RT_NULL;
clock_cpu_settimeout(RT_NULL, RT_NULL, RT_NULL);
}
}
void rt_cputimer_init(rt_cputimer_t timer,
const char *name,
void (*timeout)(void *parameter),
void *parameter,
rt_uint64_t tick,
rt_uint8_t flag)
{
/* parameter check */
RT_ASSERT(timer != RT_NULL);
RT_ASSERT(timeout != RT_NULL);
RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE);
/* set flag */
timer->parent.flag = flag;
/* set deactivated */
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
timer->timeout_func = timeout;
timer->parameter = parameter;
timer->timeout_tick = tick + clock_cpu_gettime();
timer->init_tick = tick;
rt_list_init(&(timer->row));
rt_sem_init(&(timer->sem), "cputime", 0, RT_IPC_FLAG_PRIO);
}
rt_err_t rt_cputimer_delete(rt_cputimer_t timer)
{
rt_base_t level;
/* parameter check */
RT_ASSERT(timer != RT_NULL);
RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE);
/* disable interrupt */
level = rt_hw_interrupt_disable();
rt_list_remove(&timer->row);
/* stop timer */
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
/* enable interrupt */
rt_hw_interrupt_enable(level);
_set_next_timeout();
return RT_EOK;
}
rt_err_t rt_cputimer_start(rt_cputimer_t timer)
{
rt_list_t *timer_list;
rt_base_t level;
/* parameter check */
RT_ASSERT(timer != RT_NULL);
RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE);
/* stop timer firstly */
level = rt_hw_interrupt_disable();
/* remove timer from list */
rt_list_remove(&timer->row);
/* change status of timer */
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
timer_list = &_cputimer_list;
for (; timer_list != _cputimer_list.prev;
timer_list = timer_list->next)
{
struct rt_cputimer *t;
rt_list_t *p = timer_list->next;
t = rt_list_entry(p, struct rt_cputimer, row);
if ((t->timeout_tick - timer->timeout_tick) == 0)
{
continue;
}
else if ((t->timeout_tick - timer->timeout_tick) < 0x7fffffffffffffff)
{
break;
}
}
rt_list_insert_after(timer_list, &(timer->row));
timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
_set_next_timeout();
/* enable interrupt */
rt_hw_interrupt_enable(level);
return RT_EOK;
}
rt_err_t rt_cputimer_stop(rt_cputimer_t timer)
{
rt_base_t level;
/* disable interrupt */
level = rt_hw_interrupt_disable();
/* timer check */
RT_ASSERT(timer != RT_NULL);
RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE);
if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
{
rt_hw_interrupt_enable(level);
return -RT_ERROR;
}
rt_list_remove(&timer->row);
/* change status */
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
_set_next_timeout();
/* enable interrupt */
rt_hw_interrupt_enable(level);
return RT_EOK;
}
rt_err_t rt_cputimer_control(rt_cputimer_t timer, int cmd, void *arg)
{
rt_base_t level;
/* parameter check */
RT_ASSERT(timer != RT_NULL);
RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE);
level = rt_hw_interrupt_disable();
switch (cmd)
{
case RT_TIMER_CTRL_GET_TIME:
*(rt_uint64_t *)arg = timer->init_tick;
break;
case RT_TIMER_CTRL_SET_TIME:
RT_ASSERT((*(rt_uint64_t *)arg) < 0x7fffffffffffffff);
timer->init_tick = *(rt_uint64_t *)arg;
timer->timeout_tick = *(rt_uint64_t *)arg + clock_cpu_gettime();
break;
case RT_TIMER_CTRL_SET_ONESHOT:
timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC;
break;
case RT_TIMER_CTRL_SET_PERIODIC:
timer->parent.flag |= RT_TIMER_FLAG_PERIODIC;
break;
case RT_TIMER_CTRL_GET_STATE:
if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
{
/*timer is start and run*/
*(rt_uint32_t *)arg = RT_TIMER_FLAG_ACTIVATED;
}
else
{
/*timer is stop*/
*(rt_uint32_t *)arg = RT_TIMER_FLAG_DEACTIVATED;
}
break;
case RT_TIMER_CTRL_GET_REMAIN_TIME:
*(rt_uint64_t *)arg = timer->timeout_tick;
break;
case RT_TIMER_CTRL_GET_FUNC:
arg = (void *)timer->timeout_func;
break;
case RT_TIMER_CTRL_SET_FUNC:
timer->timeout_func = (void (*)(void *))arg;
break;
case RT_TIMER_CTRL_GET_PARM:
*(void **)arg = timer->parameter;
break;
case RT_TIMER_CTRL_SET_PARM:
timer->parameter = arg;
break;
default:
break;
}
rt_hw_interrupt_enable(level);
return RT_EOK;
}
rt_err_t rt_cputimer_detach(rt_cputimer_t timer)
{
rt_base_t level;
/* parameter check */
RT_ASSERT(timer != RT_NULL);
RT_ASSERT(clock_cpu_issettimeout() != RT_FALSE);
/* disable interrupt */
level = rt_hw_interrupt_disable();
rt_list_remove(&timer->row);
/* stop timer */
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
_set_next_timeout();
/* enable interrupt */
rt_hw_interrupt_enable(level);
rt_sem_detach(&(timer->sem));
return RT_EOK;
}
rt_err_t rt_cputime_sleep(rt_uint64_t tick)
{
rt_base_t level;
struct rt_cputimer cputimer;
if (!clock_cpu_issettimeout())
{
rt_int32_t ms = clock_cpu_millisecond(tick);
return rt_thread_delay(rt_tick_from_millisecond(ms));
}
if (tick == 0)
{
return -RT_EINVAL;
}
rt_cputimer_init(&cputimer, "cputime_sleep", _cputime_sleep_timeout, &(cputimer.sem), tick,
RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER);
/* disable interrupt */
level = rt_hw_interrupt_disable();
rt_cputimer_start(&cputimer); /* reset the timeout of thread timer and start it */
rt_hw_interrupt_enable(level);
rt_sem_take_interruptible(&(cputimer.sem), RT_WAITING_FOREVER);
rt_cputimer_detach(&cputimer);
return RT_EOK;
}
rt_err_t rt_cputime_ndelay(rt_uint64_t ns)
{
uint64_t unit = clock_cpu_getres();
return rt_cputime_sleep(ns * (1000UL * 1000) / unit);
}
rt_err_t rt_cputime_udelay(rt_uint64_t us)
{
return rt_cputime_ndelay(us * 1000);
}
rt_err_t rt_cputime_mdelay(rt_uint64_t ms)
{
return rt_cputime_ndelay(ms * 1000000);
}

View file

@ -0,0 +1,41 @@
# fdt
## 1、介绍
fdt基于libfdt进行封装可实现在内存或文件系统中加载dtb设备树对内存中的设备树修改、解析并转换为设备节点树通过该节点树开发者可通过设备树信息开发驱动。
### 1.1 目录结构
| 名称 | 说明 |
| ---- | ---- |
| docs | 文档目录 |
| examples | 例子目录,并有相应的一些说明 |
| inc | 头文件目录 |
| src | 源代码目录 |
### 1.2 许可证
fdt package 遵循 GPL-3.0 许可,详见 LICENSE 文件。
### 1.3 依赖
- RT-Thread 3.0+
## 2、如何打开 fdt
使用 fdt package 需要在 RT-Thread 的包管理器中选择它,具体路径如下:
```
RT-Thread online packages
tools packages --->
[*] Device Tree package in RT-Thread
```
## 3、使用 fdt
在打开 fdt package 后,当进行 bsp 编译时,它会被加入到 bsp 工程中进行编译。
* 完整的 API 手册可以访问这个[链接](docs/api.md)
* 更多文档位于 [`/docs`](/docs) 下,使用前 **务必查看**
## 4、注意事项
如果发生`libfdt`库冲突在package管理菜单中取消选择`Enable libfdt`
## 5、联系方式
* 维护GuEe-GUI
* 主页https://github.com/GuEe-GUI/fdt

View file

@ -0,0 +1,16 @@
# RT-Thread building script for bridge
import os
from building import *
cwd = GetCurrentDir()
objs = []
list = os.listdir(cwd)
if GetDepend('RT_USING_FDT'):
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'))
Return('objs')

View file

@ -0,0 +1,13 @@
# 文档
## 软件包地址
- https://gitee.com/GuEe_GUI/fdt
## 文档列表
|文件名 |描述|
|:----- |:----|
|[examples.md](examples.md) |示例程序|
|[version.md](version.md) |版本信息|
|[api.md](api.md) |API 说明|

View file

@ -0,0 +1,434 @@
# fdt load API
## 从文件系统上读取设备树
```c
void *fdt_load_from_fs(char *dtb_filename)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|dtb_filename | 设备树文件名 |
| **返回** | **描述** |
|void* | 设备树在内存上的地址 |
## 从内存上读取设备树
```c
void *fdt_load_from_memory(void *dtb_ptr, rt_bool_t is_clone)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|dtb_ptr | 设备树在内存上的内存地址 |
|is_clone | 是否克隆到新的内存区域 |
| **返回** | **描述** |
|void* | 设备树在内存上的地址 |
# fdt set API
## 设置Linux启动参数
```c
rt_size_t fdt_set_linux_cmdline(void *fdt, char *cmdline)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|fdt | 设备树指针 |
|cmdline | 启动参数 |
| **返回** | **描述** |
|rt_size_t | 修改设备树后设备树的大小 |
## 设置Linux init ramdisk
```c
rt_size_t fdt_set_linux_initrd(void *fdt, rt_uint64_t initrd_addr, rt_size_t initrd_size)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|fdt | 设备树指针 |
|initrd_addr | init ramdisk 内存地址 |
|initrd_size | init 大小 |
| **返回** | **描述** |
|rt_size_t | 修改设备树后设备树的大小 |
## 设置节点属性值
```c
rt_size_t fdt_set_dtb_property(void *fdt, char *pathname, char *property_name, rt_uint32_t *cells, rt_size_t cells_size);
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|fdt | 设备树指针 |
|pathname | 节点路径 |
|property_name | 属性名称 |
|cells | 属性值地址 |
|cells_size | 属性值长度 |
| **返回** | **描述** |
|rt_size_t | 修改设备树后设备树的大小 |
## 添加保留内存
```c
rt_size_t fdt_add_dtb_memreserve(void *fdt, rt_uint64_t address, rt_uint64_t size)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|fdt | 设备树指针 |
|address | 保留内存起始地址 |
|size | 保留内存大小 |
| **返回** | **描述** |
|rt_size_t | 修改设备树后设备树的大小 |
## 删除保留内存
```c
rt_size_t fdt_del_dtb_memreserve(void *fdt, rt_uint64_t address)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|fdt | 设备树指针 |
|address | 保留内存起始地址 |
| **返回** | **描述** |
|rt_size_t | 修改设备树后设备树的大小 |
# fdt get API
## 获取设备树软件包执行状态
```c
rt_err_t fdt_get_exec_status()
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|无 | 无参数 |
| **返回** | **描述** |
|FDT_RET_NO_MEMORY | 内存不足 |
|FDT_RET_NO_LOADED | 设备树还未加载进内存 |
|FDT_RET_GET_OK | 执行成功 |
|FDT_RET_GET_EMPTY | 读取数据为空 |
## 将原始设备树转换为设备节点树
```c
struct dtb_node *fdt_get_dtb_list(void *fdt)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|fdt | 设备树在内存上的地址 |
| **返回** | **描述** |
|struct dtb_node * | 设备节点树头指针 |
## 释放设备节点树内存
```c
void fdt_free_dtb_list(struct dtb_node *dtb_node_head)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|dtb_node_head | 设备节点树头节点 |
| **返回** | **描述** |
|无返回值 | 无描述 |
示例:加载设备树
```c
#include <rtthread.h>
#include <fdt.h>
int main()
{
void *fdt = fdt_load_from_fs("sample.dtb");
if (fdt != RT_NULL)
{
struct dtb_node *dtb_node_list = fdt_get_dtb_list(fdt);
if (dtb_node_list != RT_NULL)
{
/* load dtb node list OK */
/* free dtb_node_list here */
fdt_free_dtb_list(dtb_node_list);
}
rt_free(fdt);
}
return 0;
}
```
## 打印设备树信息
```c
void fdt_get_dts_dump(struct dtb_node *dtb_node_head)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|dtb_node_head | 设备节点树头节点 |
| **返回** | **描述** |
|无返回值 | 无描述 |
## 遍历设备节点树并使用程序定义的回调函数
```c
void fdt_get_enum_dtb_node(struct dtb_node *dtb_node_head, void (*callback(struct dtb_node *dtb_node)))
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|dtb_node_head | 设备节点树头节点 |
|callback | 程序定义的回调函数 |
| **返回** | **描述** |
|无返回值 | 无描述 |
示例:遍历设备树节点,并打印每个节点名称
```c
#include <rtthread.h>
#include <fdt.h>
void callback(struct dtb_node *node)
{
rt_kprintf("this node's name is %s\n", node->name);
}
int main()
{
/* loaded dtb_node */
extern struct dtb_node *dtb_node_list;
if (dtb_node_list != RT_NULL)
{
fdt_get_enum_dtb_node(dtb_node_list, callback);
}
return 0;
}
```
## 通过节点名称查找节点
```c
struct dtb_node *fdt_get_dtb_node_by_name_DFS(struct dtb_node *dtb_node, const char *nodename)
```
```c
struct dtb_node *fdt_get_dtb_node_by_name_BFS(struct dtb_node *dtb_node, const char *nodename)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|dtb_node | 设备节点树节点 |
|nodename | 查找节点的名称 |
| **返回** | **描述** |
|struct dtb_node * | 返回查找的节点 |
|RT_NULL | 未找到为RT_NULL |
## 通过节点路径查找节点
```c
struct dtb_node *fdt_get_dtb_node_by_path(struct dtb_node *dtb_node, const char *pathname)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|dtb_node | 设备节点树节点 |
|pathname | 查找节点的路径 |
| **返回** | **描述** |
|struct dtb_node * | 返回查找的节点 |
|RT_NULL | 未找到为RT_NULL |
## 通过节点phandle值查找节点
```c
struct dtb_node *fdt_get_dtb_node_by_phandle_DFS(struct dtb_node *dtb_node, phandle handle)
```
```c
struct dtb_node *fdt_get_dtb_node_by_phandle_BFS(struct dtb_node *dtb_node, phandle handle)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|dtb_node | 设备节点树节点 |
|handle | 查找节点的phandle值 |
| **返回** | **描述** |
|struct dtb_node * | 返回查找的节点 |
|RT_NULL | 未找到为RT_NULL |
DFS和BFS是用于区分不同深度节点的搜索方法时间复杂度和空间复杂度都较高建议使用路径查找。
## 读取节点属性值的单位
```c
void fdt_get_dtb_node_cells(struct dtb_node *dtb_node, int *addr_cells, int *size_cells)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|dtb_node | 设备节点树节点 |
|addr_cells | 返回的地址块的单位u32大小 |
|size_cells | 返回的尺寸块的单位u32大小 |
| **返回** | **描述** |
|无返回值 | 无描述 |
## 读取节点属性值
```c
void *fdt_get_dtb_node_property(struct dtb_node *dtb_node, const char *property_name, rt_size_t *property_size)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|dtb_node | 设备节点树节点 |
|property_name | 属性名称 |
|property_size | 属性大小 |
| **返回** | **描述** |
|void * | 无描述 |
|RT_NULL | 该设备树没有该属性 |
读取的值为在设备树中存储的值CPU小端模式下可能需要使用其他API进行转换才是正确的值
## 读取预留内存信息
```c
struct dtb_memreserve *fdt_get_dtb_memreserve(struct dtb_node *dtb_node, int *memreserve_size)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|dtb_node | 设备节点树节点 |
|memreserve_size | 返回的内存信息数组长度 |
| **返回** | **描述** |
|struct dtb_memreserve *| 内存预留信息数组的内存地址 |
|RT_NULL | 该设备树没有预留内存信息 |
## 读取节点的状态
```c
rt_bool_t fdt_get_dtb_node_status(struct dtb_node *dtb_node)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|dtb_node | 设备节点树节点 |
| **返回** | **描述** |
|RT_FALSE | 状态为禁用 |
|RT_TRUE | 状态为使用 |
## 用于参数为字符串列表的函数
```c
fdt_string_list(string, ...)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|string | 字符串集合 |
## 读取节点compatible标志匹配
```c
rt_bool_t fdt_get_dtb_node_compatible_match(struct dtb_node *dtb_node, char **compatibles)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|dtb_node | 设备节点树节点 |
|compatibles | 所有要匹配的字符串列表 |
| **返回** | **描述** |
|RT_FALSE | 匹配失败 |
|RT_TRUE | 匹配成功 |
## 读取属性值中的字符串
```c
char *fdt_get_dtb_string_list_value(void *value, int size, int index)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|value | 节点属性的内存地址 |
|size | 节点属性的尺寸 |
|index | 要读取字符串的索引 |
| **返回** | **描述** |
|char * | 字符串的内存地址 |
|RT_NULL | 该索引没有字符串 |
## 读取值为字符串属性下一个字符串
```c
char *fdt_get_dtb_string_list_value_next(void *value, void *end)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|value | 节点属性的内存地址 |
|end | 节点属性的结束地址 |
| **返回** | **描述** |
|char * | 字符串的内存地址 |
|RT_NULL | 没有下一个字符串 |
## 读取值为u32属性的值
```c
rt_uint32_t fdt_get_dtb_cell_value(void *value)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|value | 节点属性的内存地址 |
| **返回** | **描述** |
|rt_uint32_t | 该值小端的值 |
## 读取值为u8属性的值
```c
rt_uint8_t fdt_get_dtb_byte_value(void *value)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|value | 节点属性的内存地址 |
| **返回** | **描述** |
|rt_uint8_t | 该值小端的值 |
# fdt foreach API
## 遍历属性中字符串宏
```c
for_each_property_string(node_ptr, property_name, str, size)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|node_ptr | 设备节点树节点 |
|property_name | 节点属性名称 |
|str | 每次遍历到的字符串 |
|size | 用于保存节点属性的尺寸 |
## 遍历属性中u32宏
```c
for_each_property_cell(node_ptr, property_name, value, list, size)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|node_ptr | 设备节点树节点 |
|property_name | 节点属性名称 |
|value | 每次遍历到的值 |
|list | 用于保存节点属性的值内存地址 |
|size | 用于保存节点属性的尺寸 |
## 遍历属性中u8宏
```c
for_each_property_byte(node_ptr, property_name, value, list, size)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|node_ptr | 设备节点树节点 |
|property_name | 节点属性名称 |
|value | 每次遍历到的值 |
|list | 用于保存节点属性的值内存地址 |
|size | 用于保存节点属性的尺寸 |
## 遍历子节点宏
```c
for_each_node_child(node_ptr)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|node_ptr | 设备节点树节点 |
## 遍历兄弟节点宏
```c
for_each_node_sibling(node_ptr)
```
| 参数 | 描述 |
|:------------------|:------------------------------------|
|node_ptr | 设备节点树节点 |

View file

@ -0,0 +1,81 @@
# fdt示例 #
`examples`文件夹中存放`bcm2711-rpi-4-b.dtb``vexpress-v2p-ca9.dtb`可供测试如果系统可以从bootloader或其他方式获取到bsp本身的dtb也可以通过修改示例程序进行测试
## fdt_dump
```bash
fdt_dump vexpress-v2p-ca9.dtb
```
#### 示例结果 ####
```bash
/dts-v1/;
/ {
model = "V2P-CA9";
arm,hbi = <0x191>;
arm,vexpress,site = <0xf>;
compatible = "arm,vexpress,v2p-ca9", "arm,vexpress";
interrupt-parent = <0x1>;
#address-cells = <0x1>;
#size-cells = <0x1>;
chosen {
};
aliases {
serial0 = "/smb@4000000/motherboard/iofpga@7,00000000/uart@9000";
serial1 = "/smb@4000000/motherboard/iofpga@7,00000000/uart@a000";
serial2 = "/smb@4000000/motherboard/iofpga@7,00000000/uart@b000";
serial3 = "/smb@4000000/motherboard/iofpga@7,00000000/uart@c000";
i2c0 = "/smb@4000000/motherboard/iofpga@7,00000000/i2c@16000";
i2c1 = "/smb@4000000/motherboard/iofpga@7,00000000/i2c@2000";
};
...... 省略
hsb@e0000000 {
compatible = "simple-bus";
#address-cells = <0x1>;
#size-cells = <0x1>;
ranges = <0x0 0xe0000000 0x20000000>;
#interrupt-cells = <0x1>;
interrupt-map-mask = <0x0 0x3>;
interrupt-map = <0x0 0x0 0x1 0x0 0x24 0x4 0x0 0x1 0x1 0x0 0x25 0x4 0x0 0x2 0x1 0x0 0x26 0x4 0x0 0x3 0x1 0x0 0x27 0x4>;
};
};
```
## fdt_test
```bash
fdt_test
```
#### 示例结果 ####
```bash
name = uart@9000
reg = <0x9000,0x1000>;
compatible = "arm,pl011","arm,primecell";
name = cpus
path = /cpus/cpu@0/
path = /cpus/cpu@1/
path = /cpus/cpu@2/
path = /cpus/cpu@3/
name = user1, lable = v2m:green:user1
name = user2, lable = v2m:green:user2
name = user3, lable = v2m:green:user3
name = user4, lable = v2m:green:user4
name = user5, lable = v2m:green:user5
name = user6, lable = v2m:green:user6
name = user7, lable = v2m:green:user7
name = user8, lable = v2m:green:user8
/memreserve/ 0x0000000000000000 0x0000000000001000;
phandle = <0x9>
name = bt_pins
path = /soc/gpio@7e200000/bt_pins/
brcm,pins = [2d 00]
```

View file

@ -0,0 +1,7 @@
# 版本和修订 #
| Date | Version | Author | Note |
| -------- | :-----: | :---- | :---- |
| 2021-9-1 | v0.0.1 | GuEe-GUI | 初始版本 |
| 2021-11-11 | v1.0.0 | GuEe-GUI | API确定版本 |
| | | | |

View file

@ -0,0 +1,10 @@
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
group = DefineGroup('FDT', src, depend = ['FDT_USING_DEBUG'], CPPPATH = CPPPATH)
Return('group')

View file

@ -0,0 +1,143 @@
#include <rtthread.h>
#include "dtb_node.h"
int dtb_test()
{
void *fdt;
if ((fdt = dtb_node_load_from_fs("vexpress-v2p-ca9.dtb")) != RT_NULL)
{
struct dtb_node *dtb_node_list = dtb_node_get_dtb_list(fdt);
if (dtb_node_list != RT_NULL)
{
struct dtb_node *serial0 = dtb_node_get_dtb_node_by_path(dtb_node_list, "/smb@4000000/motherboard/iofpga@7,00000000/uart@9000");
struct dtb_node *cpu = dtb_node_get_dtb_node_by_path(dtb_node_list, "/cpus");
struct dtb_node *user1 = dtb_node_get_dtb_node_by_path(dtb_node_list, "/smb@4000000/motherboard/leds/user1");
if (serial0 != RT_NULL)
{
int property_size;
rt_uint32_t u32_value;
rt_uint32_t *u32_ptr;
char *str_ptr;
rt_kprintf("name = %s\n", serial0->name);
rt_kputs("reg = <");
for_each_property_cell(serial0, "reg", u32_value, u32_ptr, property_size)
{
rt_kprintf("0x%x,", u32_value);
}
rt_kputs("\b>;\n");
rt_kputs("compatible = ");
for_each_property_string(serial0, "compatible", str_ptr, property_size)
{
rt_kprintf("\"%s\",", str_ptr);
}
rt_kputs("\b;\n");
}
if (cpu != RT_NULL)
{
struct dtb_node *cpu_child = cpu;
rt_kprintf("\nname = %s\n", cpu->name);
for_each_node_child(cpu_child)
{
rt_kprintf("path = %s\n", cpu_child->path);
}
}
if (user1 != RT_NULL)
{
struct dtb_node *user = user1;
rt_kprintf("\nname = %s, lable = %s\n", user1->name, dtb_node_get_dtb_node_property(user1, "label", RT_NULL));
for_each_node_sibling(user)
{
rt_kprintf("name = %s, lable = %s\n", user->name, dtb_node_get_dtb_node_property(user, "label", RT_NULL));
}
}
}
dtb_node_free_dtb_list(dtb_node_list);
}
if ((fdt = dtb_node_load_from_fs("bcm2711-rpi-4-b.dtb")) != RT_NULL)
{
struct dtb_node *dtb_node_list = dtb_node_get_dtb_list(fdt);
if (dtb_node_list != RT_NULL)
{
struct dtb_node *bt_pins;
int memreserve_size;
struct dtb_memreserve *memreserve;
bt_pins = dtb_node_get_dtb_node_by_name_DFS(dtb_node_list, "bt_pins");
bt_pins = dtb_node_get_dtb_node_by_name_BFS(dtb_node_list, bt_pins->name);
bt_pins = dtb_node_get_dtb_node_by_phandle_DFS(dtb_node_list, bt_pins->handle);
bt_pins = dtb_node_get_dtb_node_by_phandle_BFS(dtb_node_list, bt_pins->handle);
memreserve = dtb_node_get_dtb_memreserve(bt_pins, &memreserve_size);
if (memreserve_size > 0)
{
int i;
for (i = 0; i < memreserve_size; ++i)
{
rt_kputs("\n/memreserve/\t");
if (IN_64BITS_MODE)
{
rt_kprintf("0x%016x 0x%016x;", memreserve[i].address, memreserve[i].size);
}
else
{
rt_kprintf("0x%08x%08x 0x%08x%08x;", memreserve[i].address, memreserve[i].size);
}
}
}
if (bt_pins != RT_NULL)
{
int property_size;
rt_uint8_t u8_value;
rt_uint8_t *u8_ptr;
rt_kprintf("\n\nphandle = <0x%x>\n", bt_pins->handle);
rt_kprintf("name = %s\n", bt_pins->name);
rt_kprintf("path = %s\n", bt_pins->path);
rt_kputs("brcm,pins = [");
for_each_property_byte(bt_pins, "brcm,pins", u8_value, u8_ptr, property_size)
{
rt_kprintf("%02x ", u8_value);
}
rt_kputs("\b]\n");
}
}
dtb_node_free_dtb_list(dtb_node_list);
}
return 0;
}
MSH_CMD_EXPORT(dtb_test, dtb API test);
int dtb_dump(int argc, char** argv)
{
struct dtb_node *dtb_root_node = get_dtb_node_head();
if(argc == 1)
{
if (dtb_root_node != RT_NULL)
{
dtb_node_get_dts_dump(dtb_root_node);
}
}
else
{
rt_kprintf("invailed parameter\n");
}
return 0;
}
MSH_CMD_EXPORT(dtb_dump, dtb dump from mem);

View file

@ -0,0 +1,381 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _DTB_NODE_H__
#define _DTB_NODE_H__
#include "libfdt_env.h"
#include <rtthread.h>
#include <stdint.h>
//#define RT_DTB_DEBUG
#ifdef RT_DTB_DEBUG
#define debug(fmt, args...) rt_kprintf(fmt, ##args)
#else
#define debug(fmt, args...)
#endif
#define ERR_PTR(err) ((void *)((long)(err)))
#define PTR_ERR(ptr) ((long)(ptr))
#define IS_ERR(ptr) ((unsigned long)(ptr) > (unsigned long)(-1000))
#define DEV_ROOT_NODE_ADDR_CELLS_DEFAULT 2
#define DEV_ROOT_NODE_SIZE_CELLS_DEFAULT 1
/* will be optimized to only u64 or u32 by gcc */
#define IN_64BITS_MODE (sizeof(void *) == 8)
#define FDT_ROOT_ADDR_CELLS_DEFAULT 1
#define FDT_ROOT_SIZE_CELLS_DEFAULT 1
#define FDT_DTB_ALL_NODES_PATH_SIZE (32 * 1024)
#define FDT_DTB_PAD_SIZE 1024
#define FDT_RET_NO_MEMORY 2
#define FDT_RET_NO_LOADED 1
#define FDT_RET_GET_OK 0
#define FDT_RET_GET_EMPTY (-1)
typedef uint32_t phandle;
struct dtb_memreserve
{
uintptr_t address;
size_t size;
};
struct dtb_header
{
char root, zero; /* "/" */
struct dtb_memreserve *memreserve;
size_t memreserve_sz;
};
struct dtb_property
{
const char *name;
int size;
void *value;
struct dtb_property *next;
};
struct dtb_node
{
union
{
const char *name;
const struct dtb_header *header;
};
const char *path;
phandle handle;
struct dtb_property *properties;
struct dtb_node *parent;
struct dtb_node *child;
struct dtb_node *sibling;
};
#define FDT_MAX_PHANDLE_ARGS 16
/**
* struct dtb_node_phandle_args - structure to hold phandle and arguments
*
* This is used when decoding a phandle in a device tree property. Typically
* these look like this:
*
* wibble {
* phandle = <5>;
* };
*
* ...
* some-prop = <&wibble 1 2 3>
*
* Here &node is the phandle of the node 'wibble', i.e. 5. There are three
* arguments: 1, 2, 3.
*
* So when decoding the phandle in some-prop, np will point to wibble,
* args_count will be 3 and the three arguments will be in args.
*
* @np: Node that the phandle refers to
* @args_count: Number of arguments
* @args: Argument values
*/
struct fdt_phandle_args
{
struct dtb_node *np;
int args_count;
uint32_t args[FDT_MAX_PHANDLE_ARGS];
};
/*
* A single signal can be specified via a range of minimal and maximal values
* with a typical value, that lies somewhere inbetween.
*/
struct timing_entry
{
uint32_t min;
uint32_t typ;
uint32_t max;
};
void *get_fdt_blob(void);
struct dtb_node *get_dtb_node_head(void);
rt_bool_t dtb_node_active(void);
int device_tree_setup(void *mem_addr);
void *dtb_node_load_from_fs(char *dtb_filename);
void *dtb_node_load_from_memory(void *dtb_ptr, rt_bool_t is_clone);
size_t dtb_node_set_linux_cmdline(void *fdt, char *cmdline);
size_t dtb_node_set_linux_initrd(void *fdt, uint64_t initrd_addr, size_t initrd_size);
size_t dtb_node_set_dtb_property(void *fdt, char *pathname, char *property_name, uint32_t *cells, size_t cells_size);
size_t dtb_node_add_dtb_memreserve(void *fdt, uint64_t address, uint64_t size);
size_t dtb_node_del_dtb_memreserve(void *fdt, uint64_t address);
int dtb_node_get_exec_status();
struct dtb_node *dtb_node_get_dtb_list(void *fdt);
void dtb_node_free_dtb_list(struct dtb_node *dtb_node_head);
void dtb_node_get_dts_dump(struct dtb_node *dtb_node_head);
void dtb_node_get_enum_dtb_node(struct dtb_node *dtb_node_head, void(callback(struct dtb_node *dtb_node)));
struct dtb_node *dtb_node_get_dtb_node_by_name_DFS(struct dtb_node *dtb_node, const char *nodename);
struct dtb_node *dtb_node_get_dtb_node_by_name_BFS(struct dtb_node *dtb_node, const char *nodename);
struct dtb_node *dtb_node_get_dtb_node_by_path(struct dtb_node *dtb_node, const char *pathname);
struct dtb_node *dtb_node_get_dtb_node_by_phandle_DFS(struct dtb_node *dtb_node, phandle handle);
struct dtb_node *dtb_node_get_dtb_node_by_phandle_BFS(struct dtb_node *dtb_node, phandle handle);
void dtb_node_get_dtb_node_cells(struct dtb_node *dtb_node, int *addr_cells, int *size_cells);
struct dtb_memreserve *dtb_node_get_dtb_memreserve(struct dtb_node *dtb_node, int *memreserve_size);
uint8_t dtb_node_get_dtb_byte_value(void *value);
char *dtb_node_get_dtb_string_list_value(void *value, int size, int index);
char *dtb_node_get_dtb_string_list_value_next(void *value, void *end);
uint32_t dtb_node_get_dtb_cell_value(void *value);
rt_bool_t dtb_node_get_dtb_node_status(const struct dtb_node *dtb_node);
rt_bool_t dtb_node_get_dtb_node_compatible_match(const struct dtb_node *dtb_node, const char *compatibles);
/*dtb_node_access.c */
int dtb_node_read_u32(const struct dtb_node *dn, const char *propname, uint32_t *outp);
uint32_t dtb_node_read_u32_default(const struct dtb_node *node, const char *propname, uint32_t def);
int dtb_node_read_u32_index(const struct dtb_node *node, const char *propname, int index,
uint32_t *outp);
uint32_t dtb_node_read_u32_index_default(const struct dtb_node *node, const char *propname, int index,
uint32_t def);
int dtb_node_read_u32_array(const struct dtb_node *dn, const char *propname,
uint32_t *out_values, size_t sz);
int dtb_node_read_u32_index(const struct dtb_node *dn, const char *propname,
int index, uint32_t *outp);
int dtb_node_read_s32_default(const struct dtb_node *node, const char *propname, int32_t def);
int dtb_node_read_u64(const struct dtb_node *dn, const char *propname, uint64_t *outp);
uint64_t dtb_node_read_u64_default(const struct dtb_node *node, const char *propname, uint64_t def);
int dtb_node_n_addr_cells(const struct dtb_node *dn);
int dtb_node_n_size_cells(const struct dtb_node *dn);
int dtb_node_simple_addr_cells(const struct dtb_node *np);
int dtb_node_simple_size_cells(const struct dtb_node *np);
struct dtb_node *dtb_node_find_all_nodes(const struct dtb_node *prev);
struct dtb_node *dtb_node_find_node_by_phandle(phandle handle);
struct dtb_node *dtb_node_find_compatible_node(struct dtb_node *from, const char *compatible);
void *dtb_node_get_dtb_node_property_value(const struct dtb_node *dtb_node, const char *property_name, int *property_size);
struct dtb_property *dtb_node_get_dtb_node_property(const struct dtb_node *dtb_node, const char *property_name, int *property_size);
const struct dtb_node *dtb_node_find_node_by_prop_value(struct dtb_node *from, const char *propname, const void *propval, int proplen);
struct dtb_node *dtb_node_find_node_opts_by_path(const char *path,
const char **opts);
static inline struct dtb_node *dtb_node_find_node_by_path(const char *path)
{
return dtb_node_find_node_opts_by_path(path, NULL);
}
rt_bool_t dtb_node_device_is_available(const struct dtb_node *device);
struct dtb_node *dtb_node_get_parent(const struct dtb_node *node);
int dtb_node_property_match_string(const struct dtb_node *dn, const char *propname,
const char *string);
int dtb_node_property_read_string_helper(const struct dtb_node *dn,
const char *propname, const char **out_strs,
size_t sz, int skip);
/**
* of_property_read_string_index() - Find and read a string from a multiple
* strings property.
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @index: index of the string in the list of strings
* @out_string: pointer to null terminated return string, modified only if
* return value is 0.
*
* Search for a property in a device tree node and retrieve a null
* terminated string value (pointer to data, not a copy) in the list of strings
* contained in that property.
* Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if
* property does not have a value, and -EILSEQ if the string is not
* null-terminated within the length of the property data.
*
* The out_string pointer is modified only if a valid string can be decoded.
*/
static inline int dtb_node_property_read_string_index(const struct dtb_node *dn,
const char *propname,
int index, const char **output)
{
int rc = dtb_node_property_read_string_helper(dn, propname, output, 1, index);
return rc < 0 ? rc : 0;
}
/**
* of_property_count_strings() - Find and return the number of strings from a
* multiple strings property.
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
*
* Search for a property in a device tree node and retrieve the number of null
* terminated string contain in it. Returns the number of strings on
* success, -EINVAL if the property does not exist, -ENODATA if property
* does not have a value, and -EILSEQ if the string is not null-terminated
* within the length of the property data.
*/
static inline int dtb_node_property_count_strings(const struct dtb_node *dn,
const char *propname)
{
return dtb_node_property_read_string_helper(dn, propname, NULL, 0, 0);
}
struct dtb_node *dtb_node_parse_phandle(const struct dtb_node *dn,
const char *phandle_name, int index);
int dtb_node_parse_phandle_with_args(const struct dtb_node *dn,
const char *list_name, const char *cells_name,
int index, struct fdt_phandle_args *out_args);
int dtb_node_count_phandle_with_args(const struct dtb_node *dn,
const char *list_name, const char *cells_name);
/* dtb_node_addr.c */
const uint32_t *dtb_node_get_address(const struct dtb_node *dev, int index,
uint64_t *size, unsigned int *flags);
#define dtb_node_string_list(string, ...) ((char *[]){string, ##__VA_ARGS__, NULL})
#define for_each_property_string(node_ptr, property_name, str, size) \
for (str = dtb_node_get_dtb_node_property_value(node_ptr, property_name, &size), \
size += (typeof(size))(size_t)str; \
str && *str; \
str = dtb_node_get_dtb_string_list_value_next((void *)str, (void *)(size_t)size))
#define for_each_property_cell(node_ptr, property_name, value, list, size) \
for (list = dtb_node_get_dtb_node_property_value(node_ptr, property_name, &size), \
value = dtb_node_get_dtb_cell_value(list), \
size /= sizeof(uint32_t); \
size > 0; \
value = dtb_node_get_dtb_cell_value(++list), --size)
#define for_each_property_byte(node_ptr, property_name, value, list, size) \
for (list = dtb_node_get_dtb_node_property_value(node_ptr, property_name, &size), \
value = dtb_node_get_dtb_byte_value(list); \
size > 0; \
value = dtb_node_get_dtb_byte_value(++list), --size)
#define for_each_node_child(node_ptr) \
for (node_ptr = (node_ptr ? node_ptr->child : NULL); \
node_ptr != NULL; \
node_ptr = node_ptr->sibling)
#define for_each_node_sibling(node_ptr) \
for (node_ptr = (node_ptr ? node_ptr->sibling : NULL); \
node_ptr != NULL; \
node_ptr = node_ptr->sibling)
#define for_each_of_allnodes_from(from, dn) \
for (dn = dtb_node_find_all_nodes(from); dn; dn = dtb_node_find_all_nodes(dn))
#define for_each_of_allnodes(dn) for_each_of_allnodes_from(NULL, dn)
#define dtb_node_get(x) (x)
static inline void dtb_node_put(const struct dtb_node *np)
{
}
/* Helper to read a big number; size is in cells (not bytes) */
static inline uint64_t dtb_node_read_number(const uint32_t *cell, int size)
{
uint64_t r = 0;
while (size--)
r = (r << 32) | fdt32_to_cpu(*(cell++));
return r;
}
/**
* ofnode_valid() - check if an ofnode is valid
*
* @return true if the reference contains a valid ofnode, RT_FALSE if it is NULL
*/
static inline rt_bool_t dtb_node_valid(const struct dtb_node *node)
{
if (dtb_node_active())
return node != NULL;
return RT_FALSE;
}
/*dtb_base.c */
rt_bool_t dtb_node_read_bool(const struct dtb_node *node, const char *propname);
const void *dtb_node_read_prop(const struct dtb_node *node, const char *propname, int *sizep);
const char *dtb_node_read_string(const struct dtb_node *node, const char *propname);
const struct dtb_node *dtb_node_find_subnode(const struct dtb_node *node, const char *subnode_name);
int dtb_node_read_u32_array(const struct dtb_node *node, const char *propname,
uint32_t *out_values, size_t sz);
struct dtb_node *dtb_node_first_subnode(const struct dtb_node *node);
struct dtb_node *dtb_node_next_subnode(const struct dtb_node *node);
struct dtb_node *dtb_node_get_parent(const struct dtb_node *node);
const char *dtb_node_get_name(const struct dtb_node *node);
struct dtb_node *dtb_node_get_by_phandle(uint32_t phandle);
int dtb_node_read_size(const struct dtb_node *node, const char *propname);
int dtb_node_get_addr_and_size_by_index(const struct dtb_node *node, int index, size_t *addr, size_t *size);
size_t dtb_node_get_addr_index(const struct dtb_node *node, int index);
size_t dtb_node_get_addr(const struct dtb_node *node);
int dtb_node_stringlist_search(const struct dtb_node *node, const char *property,
const char *string);
int dtb_node_read_string_index(const struct dtb_node *node, const char *property, int index,
const char **outp);
int dtb_node_read_string_count(const struct dtb_node *node, const char *property);
struct dtb_node *dtb_node_path(const char *path);
const char *dtb_node_get_chosen_prop(const char *name);
struct dtb_node *dtb_node_get_chosen_node(const char *name);
const void *dtb_node_get_property(const struct dtb_node *node, const char *propname, int *lenp);
rt_bool_t dtb_node_is_available(const struct dtb_node *node);
size_t dtb_node_get_addr_size(const struct dtb_node *node, const char *property,
size_t *sizep);
const uint8_t *dtb_node_read_u8_array_ptr(const struct dtb_node *node, const char *propname, size_t sz);
int dtb_node_find_all_compatible_node(const struct dtb_node *from, const char *compatible, struct dtb_node **node_table, int max_num, int *node_num);
int dtb_node_write_prop(const struct dtb_node *node, const char *propname, int len,
const void *value);
int dtb_node_write_string(const struct dtb_node *node, const char *propname, const char *value);
int dtb_node_set_enabled(const struct dtb_node *node, rt_bool_t value);
int dtb_node_irq_get(struct dtb_node *dev, int index);
int dtb_node_irq_get_byname(struct dtb_node *dev, const char *name);
int dtb_node_irq_count(struct dtb_node *dev);
/**
* dtb_node_for_each_subnode() - iterate over all subnodes of a parent
*
* @node: child node (ofnode, lvalue)
* @parent: parent node (ofnode)
*
* This is a wrapper around a for loop and is used like so:
*
* ofnode node;
*
* dtb_node_for_each_subnode(node, parent) {
* Use node
* ...
* }
*
* Note that this is implemented as a macro and @node is used as
* iterator in the loop. The parent variable can be a constant or even a
* literal.
*/
#define dtb_node_for_each_subnode(node, parent) \
for (node = dtb_node_first_subnode(parent); \
dtb_node_valid(node); \
node = dtb_node_next_subnode(node))
#endif /* RT_FDT_H__ */

View file

@ -0,0 +1,10 @@
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
group = DefineGroup('FDT', src, depend = ['RT_USING_FDTLIB'], CPPPATH = CPPPATH)
Return('group')

View file

@ -0,0 +1,249 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include "fdt.h"
#include "libfdt.h"
#include "libfdt_internal.h"
int fdt_check_header(const void *fdt)
{
if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
/* Unfinished sequential-write blob */
if (fdt_size_dt_struct(fdt) == 0)
return -FDT_ERR_BADSTATE;
} else {
return -FDT_ERR_BADMAGIC;
}
return 0;
}
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{
unsigned absoffset = offset + fdt_off_dt_struct(fdt);
if ((absoffset < offset)
|| ((absoffset + len) < absoffset)
|| (absoffset + len) > fdt_totalsize(fdt))
return NULL;
if (fdt_version(fdt) >= 0x11)
if (((offset + len) < offset)
|| ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL;
return _fdt_offset_ptr(fdt, offset);
}
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
{
const fdt32_t *tagp, *lenp;
uint32_t tag;
int offset = startoffset;
const char *p;
*nextoffset = -FDT_ERR_TRUNCATED;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (!tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;
*nextoffset = -FDT_ERR_BADSTRUCTURE;
switch (tag) {
case FDT_BEGIN_NODE:
/* skip name */
do {
p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0'));
if (!p)
return FDT_END; /* premature end */
break;
case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (!lenp)
return FDT_END; /* premature end */
/* skip-name offset, length and value */
offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ fdt32_to_cpu(*lenp);
break;
case FDT_END:
case FDT_END_NODE:
case FDT_NOP:
break;
default:
return FDT_END;
}
if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
return FDT_END; /* premature end */
*nextoffset = FDT_TAGALIGN(offset);
return tag;
}
int _fdt_check_node_offset(const void *fdt, int offset)
{
if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
return -FDT_ERR_BADOFFSET;
return offset;
}
int _fdt_check_prop_offset(const void *fdt, int offset)
{
if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
return -FDT_ERR_BADOFFSET;
return offset;
}
int fdt_next_node(const void *fdt, int offset, int *depth)
{
int nextoffset = 0;
uint32_t tag;
if (offset >= 0)
if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
return nextoffset;
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_PROP:
case FDT_NOP:
break;
case FDT_BEGIN_NODE:
if (depth)
(*depth)++;
break;
case FDT_END_NODE:
if (depth && ((--(*depth)) < 0))
return nextoffset;
break;
case FDT_END:
if ((nextoffset >= 0)
|| ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
return -FDT_ERR_NOTFOUND;
else
return nextoffset;
}
} while (tag != FDT_BEGIN_NODE);
return offset;
}
int fdt_first_subnode(const void *fdt, int offset)
{
int depth = 0;
offset = fdt_next_node(fdt, offset, &depth);
if (offset < 0 || depth != 1)
return -FDT_ERR_NOTFOUND;
return offset;
}
int fdt_next_subnode(const void *fdt, int offset)
{
int depth = 1;
/*
* With respect to the parent, the depth of the next subnode will be
* the same as the last.
*/
do {
offset = fdt_next_node(fdt, offset, &depth);
if (offset < 0 || depth < 1)
return -FDT_ERR_NOTFOUND;
} while (depth > 1);
return offset;
}
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
{
int len = strlen(s) + 1;
const char *last = strtab + tabsize - len;
const char *p;
for (p = strtab; p <= last; p++)
if (memcmp(p, s, len) == 0)
return p;
return NULL;
}
int fdt_move(const void *fdt, void *buf, int bufsize)
{
FDT_CHECK_HEADER(fdt);
if (fdt_totalsize(fdt) > bufsize)
return -FDT_ERR_NOSPACE;
memmove(buf, fdt, fdt_totalsize(fdt));
return 0;
}

View file

@ -0,0 +1,125 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-12-20 RT-Thread the first version
*/
#ifndef _FDT_H
#define _FDT_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ASSEMBLY__
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
struct fdt_header {
fdt32_t magic; /* magic word FDT_MAGIC */
fdt32_t totalsize; /* total size of DT block */
fdt32_t off_dt_struct; /* offset to structure */
fdt32_t off_dt_strings; /* offset to strings */
fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
fdt32_t version; /* format version */
fdt32_t last_comp_version; /* last compatible version */
/* version 2 fields below */
fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
booting on */
/* version 3 fields below */
fdt32_t size_dt_strings; /* size of the strings block */
/* version 17 fields below */
fdt32_t size_dt_struct; /* size of the structure block */
};
struct fdt_reserve_entry {
fdt64_t address;
fdt64_t size;
};
struct fdt_node_header {
fdt32_t tag;
char name[0];
};
struct fdt_property {
fdt32_t tag;
fdt32_t len;
fdt32_t nameoff;
char data[0];
};
#endif /* !__ASSEMBLY */
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
#define FDT_TAGSIZE sizeof(fdt32_t)
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
#define FDT_END_NODE 0x2 /* End node */
#define FDT_PROP 0x3 /* Property: name off,
size, content */
#define FDT_NOP 0x4 /* nop */
#define FDT_END 0x9
#define FDT_V1_SIZE (7*sizeof(fdt32_t))
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
#define FDT_V16_SIZE FDT_V3_SIZE
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
#endif /* _FDT_H */

View file

@ -0,0 +1,99 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
* Copyright (C) 2018 embedded brains GmbH
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
{
const fdt32_t *c;
uint32_t val;
int len;
c = fdt_getprop(fdt, nodeoffset, name, &len);
if (!c)
return len;
if (len != sizeof(*c))
return -FDT_ERR_BADNCELLS;
val = fdt32_to_cpu(*c);
if (val > FDT_MAX_NCELLS)
return -FDT_ERR_BADNCELLS;
return (int)val;
}
int fdt_address_cells(const void *fdt, int nodeoffset)
{
int val;
val = fdt_cells(fdt, nodeoffset, "#address-cells");
if (val == 0)
return -FDT_ERR_BADNCELLS;
if (val == -FDT_ERR_NOTFOUND)
return 2;
return val;
}
int fdt_size_cells(const void *fdt, int nodeoffset)
{
int val;
val = fdt_cells(fdt, nodeoffset, "#size-cells");
if (val == -FDT_ERR_NOTFOUND)
return 1;
return val;
}
/* This function assumes that [address|size]_cells is 1 or 2 */
int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
const char *name, uint64_t addr, uint64_t size)
{
int addr_cells, size_cells, ret;
uint8_t data[sizeof(fdt64_t) * 2], *prop;
ret = fdt_address_cells(fdt, parent);
if (ret < 0)
return ret;
addr_cells = ret;
ret = fdt_size_cells(fdt, parent);
if (ret < 0)
return ret;
size_cells = ret;
/* check validity of address */
prop = data;
if (addr_cells == 1) {
if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
return -FDT_ERR_BADVALUE;
fdt32_st(prop, (uint32_t)addr);
} else if (addr_cells == 2) {
fdt64_st(prop, addr);
} else {
return -FDT_ERR_BADNCELLS;
}
/* check validity of size */
prop += addr_cells * sizeof(fdt32_t);
if (size_cells == 1) {
if (size > UINT32_MAX)
return -FDT_ERR_BADVALUE;
fdt32_st(prop, (uint32_t)size);
} else if (size_cells == 2) {
fdt64_st(prop, size);
} else {
return -FDT_ERR_BADNCELLS;
}
return fdt_appendprop(fdt, nodeoffset, name, data,
(addr_cells + size_cells) * sizeof(fdt32_t));
}

View file

@ -0,0 +1,84 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2012 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include "fdt.h"
#include "libfdt.h"
#include "libfdt_internal.h"
int fdt_create_empty_tree(void *buf, int bufsize)
{
int err;
err = fdt_create(buf, bufsize);
if (err)
return err;
err = fdt_finish_reservemap(buf);
if (err)
return err;
err = fdt_begin_node(buf, "");
if (err)
return err;
err = fdt_end_node(buf);
if (err)
return err;
err = fdt_finish(buf);
if (err)
return err;
return fdt_open_into(buf, buf, bufsize);
}

View file

@ -0,0 +1,701 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include "fdt.h"
#include "libfdt.h"
#include "libfdt_internal.h"
static int _fdt_nodename_eq(const void *fdt, int offset,
const char *s, int len)
{
const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
if (! p)
/* short match */
return 0;
if (memcmp(p, s, len) != 0)
return 0;
if (p[len] == '\0')
return 1;
else if (!memchr(s, '@', len) && (p[len] == '@'))
return 1;
else
return 0;
}
const char *fdt_string(const void *fdt, int stroffset)
{
return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
}
static int _fdt_string_eq(const void *fdt, int stroffset,
const char *s, int len)
{
const char *p = fdt_string(fdt, stroffset);
return (strlen(p) == len) && (memcmp(p, s, len) == 0);
}
uint32_t fdt_get_max_phandle(const void *fdt)
{
uint32_t max_phandle = 0;
int offset;
for (offset = fdt_next_node(fdt, -1, NULL);;
offset = fdt_next_node(fdt, offset, NULL)) {
uint32_t phandle;
if (offset == -FDT_ERR_NOTFOUND)
return max_phandle;
if (offset < 0)
return (uint32_t)-1;
phandle = fdt_get_phandle(fdt, offset);
if (phandle == (uint32_t)-1)
continue;
if (phandle > max_phandle)
max_phandle = phandle;
}
return 0;
}
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{
FDT_CHECK_HEADER(fdt);
*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
return 0;
}
int fdt_num_mem_rsv(const void *fdt)
{
int i = 0;
while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
i++;
return i;
}
static int _nextprop(const void *fdt, int offset)
{
uint32_t tag;
int nextoffset;
do {
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_END:
if (nextoffset >= 0)
return -FDT_ERR_BADSTRUCTURE;
else
return nextoffset;
case FDT_PROP:
return offset;
}
offset = nextoffset;
} while (tag == FDT_NOP);
return -FDT_ERR_NOTFOUND;
}
int fdt_subnode_offset_namelen(const void *fdt, int offset,
const char *name, int namelen)
{
int depth;
FDT_CHECK_HEADER(fdt);
for (depth = 0;
(offset >= 0) && (depth >= 0);
offset = fdt_next_node(fdt, offset, &depth))
if ((depth == 1)
&& _fdt_nodename_eq(fdt, offset, name, namelen))
return offset;
if (depth < 0)
return -FDT_ERR_NOTFOUND;
return offset; /* error */
}
int fdt_subnode_offset(const void *fdt, int parentoffset,
const char *name)
{
return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
}
int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
{
const char *end = path + namelen;
const char *p = path;
int offset = 0;
FDT_CHECK_HEADER(fdt);
/* see if we have an alias */
if (*path != '/') {
const char *q = memchr(path, '/', end - p);
if (!q)
q = end;
p = fdt_get_alias_namelen(fdt, p, q - p);
if (!p)
return -FDT_ERR_BADPATH;
offset = fdt_path_offset(fdt, p);
p = q;
}
while (p < end) {
const char *q;
while (*p == '/') {
p++;
if (p == end)
return offset;
}
q = memchr(p, '/', end - p);
if (! q)
q = end;
offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
if (offset < 0)
return offset;
p = q;
}
return offset;
}
int fdt_path_offset(const void *fdt, const char *path)
{
return fdt_path_offset_namelen(fdt, path, strlen(path));
}
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
{
const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
int err;
if (((err = fdt_check_header(fdt)) != 0)
|| ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
goto fail;
if (len)
*len = strlen(nh->name);
return nh->name;
fail:
if (len)
*len = err;
return NULL;
}
int fdt_first_property_offset(const void *fdt, int nodeoffset)
{
int offset;
if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
return offset;
return _nextprop(fdt, offset);
}
int fdt_next_property_offset(const void *fdt, int offset)
{
if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
return offset;
return _nextprop(fdt, offset);
}
const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
int offset,
int *lenp)
{
int err;
const struct fdt_property *prop;
if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
if (lenp)
*lenp = err;
return NULL;
}
prop = _fdt_offset_ptr(fdt, offset);
if (lenp)
*lenp = fdt32_to_cpu(prop->len);
return prop;
}
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
int offset,
const char *name,
int namelen, int *lenp)
{
for (offset = fdt_first_property_offset(fdt, offset);
(offset >= 0);
(offset = fdt_next_property_offset(fdt, offset))) {
const struct fdt_property *prop;
if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
offset = -FDT_ERR_INTERNAL;
break;
}
if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
name, namelen))
return prop;
}
if (lenp)
*lenp = offset;
return NULL;
}
const struct fdt_property *fdt_get_property(const void *fdt,
int nodeoffset,
const char *name, int *lenp)
{
return fdt_get_property_namelen(fdt, nodeoffset, name,
strlen(name), lenp);
}
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const char *name, int namelen, int *lenp)
{
const struct fdt_property *prop;
prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
if (! prop)
return NULL;
return prop->data;
}
const void *fdt_getprop_by_offset(const void *fdt, int offset,
const char **namep, int *lenp)
{
const struct fdt_property *prop;
prop = fdt_get_property_by_offset(fdt, offset, lenp);
if (!prop)
return NULL;
if (namep)
*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
return prop->data;
}
const void *fdt_getprop(const void *fdt, int nodeoffset,
const char *name, int *lenp)
{
return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
}
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
{
const fdt32_t *php;
int len;
/* FIXME: This is a bit sub-optimal, since we potentially scan
* over all the properties twice. */
php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
if (!php || (len != sizeof(*php))) {
php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
if (!php || (len != sizeof(*php)))
return 0;
}
return fdt32_to_cpu(*php);
}
const char *fdt_get_alias_namelen(const void *fdt,
const char *name, int namelen)
{
int aliasoffset;
aliasoffset = fdt_path_offset(fdt, "/aliases");
if (aliasoffset < 0)
return NULL;
return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
}
const char *fdt_get_alias(const void *fdt, const char *name)
{
return fdt_get_alias_namelen(fdt, name, strlen(name));
}
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
{
int pdepth = 0, p = 0;
int offset, depth, namelen;
const char *name;
FDT_CHECK_HEADER(fdt);
if (buflen < 2)
return -FDT_ERR_NOSPACE;
for (offset = 0, depth = 0;
(offset >= 0) && (offset <= nodeoffset);
offset = fdt_next_node(fdt, offset, &depth)) {
while (pdepth > depth) {
do {
p--;
} while (buf[p-1] != '/');
pdepth--;
}
if (pdepth >= depth) {
name = fdt_get_name(fdt, offset, &namelen);
if (!name)
return namelen;
if ((p + namelen + 1) <= buflen) {
memcpy(buf + p, name, namelen);
p += namelen;
buf[p++] = '/';
pdepth++;
}
}
if (offset == nodeoffset) {
if (pdepth < (depth + 1))
return -FDT_ERR_NOSPACE;
if (p > 1) /* special case so that root path is "/", not "" */
p--;
buf[p] = '\0';
return 0;
}
}
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
return -FDT_ERR_BADOFFSET;
else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
return offset; /* error from fdt_next_node() */
}
int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
int supernodedepth, int *nodedepth)
{
int offset, depth;
int supernodeoffset = -FDT_ERR_INTERNAL;
FDT_CHECK_HEADER(fdt);
if (supernodedepth < 0)
return -FDT_ERR_NOTFOUND;
for (offset = 0, depth = 0;
(offset >= 0) && (offset <= nodeoffset);
offset = fdt_next_node(fdt, offset, &depth)) {
if (depth == supernodedepth)
supernodeoffset = offset;
if (offset == nodeoffset) {
if (nodedepth)
*nodedepth = depth;
if (supernodedepth > depth)
return -FDT_ERR_NOTFOUND;
else
return supernodeoffset;
}
}
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
return -FDT_ERR_BADOFFSET;
else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
return offset; /* error from fdt_next_node() */
}
int fdt_node_depth(const void *fdt, int nodeoffset)
{
int nodedepth;
int err;
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
if (err)
return (err < 0) ? err : -FDT_ERR_INTERNAL;
return nodedepth;
}
int fdt_parent_offset(const void *fdt, int nodeoffset)
{
int nodedepth = fdt_node_depth(fdt, nodeoffset);
if (nodedepth < 0)
return nodedepth;
return fdt_supernode_atdepth_offset(fdt, nodeoffset,
nodedepth - 1, NULL);
}
int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const char *propname,
const void *propval, int proplen)
{
int offset;
const void *val;
int len;
FDT_CHECK_HEADER(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_getprop(), then if that didn't
* find what we want, we scan over them again making our way
* to the next node. Still it's the easiest to implement
* approach; performance can come later. */
for (offset = fdt_next_node(fdt, startoffset, NULL);
offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
val = fdt_getprop(fdt, offset, propname, &len);
if (val && (len == proplen)
&& (memcmp(val, propval, len) == 0))
return offset;
}
return offset; /* error from fdt_next_node() */
}
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
{
int offset;
if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE;
FDT_CHECK_HEADER(fdt);
/* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in
* fdt_get_phandle(), then if that didn't find what
* we want, we scan over them again making our way to the next
* node. Still it's the easiest to implement approach;
* performance can come later. */
for (offset = fdt_next_node(fdt, -1, NULL);
offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
if (fdt_get_phandle(fdt, offset) == phandle)
return offset;
}
return offset; /* error from fdt_next_node() */
}
int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
{
int len = strlen(str);
const char *p;
while (listlen >= len) {
if (memcmp(str, strlist, len+1) == 0)
return 1;
p = memchr(strlist, '\0', listlen);
if (!p)
return 0; /* malformed strlist.. */
listlen -= (p-strlist) + 1;
strlist = p + 1;
}
return 0;
}
int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
{
const char *list, *end;
int length, count = 0;
list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list)
return length;
end = list + length;
while (list < end) {
length = strnlen(list, end - list) + 1;
/* Abort if the last string isn't properly NUL-terminated. */
if (list + length > end)
return -FDT_ERR_BADVALUE;
list += length;
count++;
}
return count;
}
int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
const char *string)
{
int length, len, idx = 0;
const char *list, *end;
list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list)
return length;
len = strlen(string) + 1;
end = list + length;
while (list < end) {
length = strnlen(list, end - list) + 1;
/* Abort if the last string isn't properly NUL-terminated. */
if (list + length > end)
return -FDT_ERR_BADVALUE;
if (length == len && memcmp(list, string, length) == 0)
return idx;
list += length;
idx++;
}
return -FDT_ERR_NOTFOUND;
}
const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
const char *property, int idx,
int *lenp)
{
const char *list, *end;
int length;
list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list) {
if (lenp)
*lenp = length;
return NULL;
}
end = list + length;
while (list < end) {
length = strnlen(list, end - list) + 1;
/* Abort if the last string isn't properly NUL-terminated. */
if (list + length > end) {
if (lenp)
*lenp = -FDT_ERR_BADVALUE;
return NULL;
}
if (idx == 0) {
if (lenp)
*lenp = length - 1;
return list;
}
list += length;
idx--;
}
if (lenp)
*lenp = -FDT_ERR_NOTFOUND;
return NULL;
}
int fdt_node_check_compatible(const void *fdt, int nodeoffset,
const char *compatible)
{
const void *prop;
int len;
prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
if (!prop)
return len;
return !fdt_stringlist_contains(prop, len, compatible);
}
int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
const char *compatible)
{
int offset, err;
FDT_CHECK_HEADER(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible(), then if
* that didn't find what we want, we scan over them again
* making our way to the next node. Still it's the easiest to
* implement approach; performance can come later. */
for (offset = fdt_next_node(fdt, startoffset, NULL);
offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
err = fdt_node_check_compatible(fdt, offset, compatible);
if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
return err;
else if (err == 0)
return offset;
}
return offset; /* error from fdt_next_node() */
}

View file

@ -0,0 +1,489 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include "fdt.h"
#include "libfdt.h"
#include "libfdt_internal.h"
static int _fdt_blocks_misordered(const void *fdt,
int mem_rsv_size, int struct_size)
{
return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
|| (fdt_off_dt_struct(fdt) <
(fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
|| (fdt_off_dt_strings(fdt) <
(fdt_off_dt_struct(fdt) + struct_size))
|| (fdt_totalsize(fdt) <
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
}
static int _fdt_rw_check_header(void *fdt)
{
FDT_CHECK_HEADER(fdt);
if (fdt_version(fdt) < 17)
return -FDT_ERR_BADVERSION;
if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT;
if (fdt_version(fdt) > 17)
fdt_set_version(fdt, 17);
return 0;
}
#define FDT_RW_CHECK_HEADER(fdt) \
{ \
int __err; \
if ((__err = _fdt_rw_check_header(fdt)) != 0) \
return __err; \
}
static inline int _fdt_data_size(void *fdt)
{
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
}
static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
{
char *p = splicepoint;
char *end = (char *)fdt + _fdt_data_size(fdt);
if (((p + oldlen) < p) || ((p + oldlen) > end))
return -FDT_ERR_BADOFFSET;
if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
return -FDT_ERR_BADOFFSET;
if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
return -FDT_ERR_NOSPACE;
memmove(p + newlen, p + oldlen, end - p - oldlen);
return 0;
}
static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
int oldn, int newn)
{
int delta = (newn - oldn) * sizeof(*p);
int err;
err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
if (err)
return err;
fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
return 0;
}
static int _fdt_splice_struct(void *fdt, void *p,
int oldlen, int newlen)
{
int delta = newlen - oldlen;
int err;
if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
return err;
fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
return 0;
}
static int _fdt_splice_string(void *fdt, int newlen)
{
void *p = (char *)fdt
+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
int err;
if ((err = _fdt_splice(fdt, p, 0, newlen)))
return err;
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
return 0;
}
static int _fdt_find_add_string(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
const char *p;
char *new;
int len = strlen(s) + 1;
int err;
p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
if (p)
/* found it */
return (p - strtab);
new = strtab + fdt_size_dt_strings(fdt);
err = _fdt_splice_string(fdt, len);
if (err)
return err;
memcpy(new, s, len);
return (new - strtab);
}
int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
{
struct fdt_reserve_entry *re;
int err;
FDT_RW_CHECK_HEADER(fdt);
re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
if (err)
return err;
re->address = cpu_to_fdt64(address);
re->size = cpu_to_fdt64(size);
return 0;
}
int fdt_del_mem_rsv(void *fdt, int n)
{
struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
FDT_RW_CHECK_HEADER(fdt);
if (n >= fdt_num_mem_rsv(fdt))
return -FDT_ERR_NOTFOUND;
return _fdt_splice_mem_rsv(fdt, re, 1, 0);
}
static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
int len, struct fdt_property **prop)
{
int oldlen;
int err;
*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (! (*prop))
return oldlen;
if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(len))))
return err;
(*prop)->len = cpu_to_fdt32(len);
return 0;
}
static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
int len, struct fdt_property **prop)
{
int proplen;
int nextoffset;
int namestroff;
int err;
if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
return nextoffset;
namestroff = _fdt_find_add_string(fdt, name);
if (namestroff < 0)
return namestroff;
*prop = _fdt_offset_ptr_w(fdt, nextoffset);
proplen = sizeof(**prop) + FDT_TAGALIGN(len);
err = _fdt_splice_struct(fdt, *prop, 0, proplen);
if (err)
return err;
(*prop)->tag = cpu_to_fdt32(FDT_PROP);
(*prop)->nameoff = cpu_to_fdt32(namestroff);
(*prop)->len = cpu_to_fdt32(len);
return 0;
}
int fdt_set_name(void *fdt, int nodeoffset, const char *name)
{
char *namep;
int oldlen, newlen;
int err;
FDT_RW_CHECK_HEADER(fdt);
namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
if (!namep)
return oldlen;
newlen = strlen(name);
err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
FDT_TAGALIGN(newlen+1));
if (err)
return err;
memcpy(namep, name, newlen+1);
return 0;
}
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
struct fdt_property *prop;
int err;
FDT_RW_CHECK_HEADER(fdt);
err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
if (err == -FDT_ERR_NOTFOUND)
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
if (len)
memcpy(prop->data, val, len);
return 0;
}
int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
struct fdt_property *prop;
int err, oldlen, newlen;
FDT_RW_CHECK_HEADER(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (prop) {
newlen = len + oldlen;
err = _fdt_splice_struct(fdt, prop->data,
FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(newlen));
if (err)
return err;
prop->len = cpu_to_fdt32(newlen);
memcpy(prop->data + oldlen, val, len);
} else {
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
memcpy(prop->data, val, len);
}
return 0;
}
int fdt_delprop(void *fdt, int nodeoffset, const char *name)
{
struct fdt_property *prop;
int len, proplen;
FDT_RW_CHECK_HEADER(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (! prop)
return len;
proplen = sizeof(*prop) + FDT_TAGALIGN(len);
return _fdt_splice_struct(fdt, prop, proplen, 0);
}
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
const char *name, int namelen)
{
struct fdt_node_header *nh;
int offset, nextoffset;
int nodelen;
int err;
uint32_t tag;
fdt32_t *endtag;
FDT_RW_CHECK_HEADER(fdt);
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
if (offset >= 0)
return -FDT_ERR_EXISTS;
else if (offset != -FDT_ERR_NOTFOUND)
return offset;
/* Try to place the new node after the parent's properties */
fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
} while ((tag == FDT_PROP) || (tag == FDT_NOP));
nh = _fdt_offset_ptr_w(fdt, offset);
nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
err = _fdt_splice_struct(fdt, nh, 0, nodelen);
if (err)
return err;
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
memcpy(nh->name, name, namelen);
endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
*endtag = cpu_to_fdt32(FDT_END_NODE);
return offset;
}
int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
{
return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
}
int fdt_del_node(void *fdt, int nodeoffset)
{
int endoffset;
FDT_RW_CHECK_HEADER(fdt);
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;
return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
endoffset - nodeoffset, 0);
}
static void _fdt_packblocks(const char *old, char *new,
int mem_rsv_size, int struct_size)
{
int mem_rsv_off, struct_off, strings_off;
mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
struct_off = mem_rsv_off + mem_rsv_size;
strings_off = struct_off + struct_size;
memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
fdt_set_off_mem_rsvmap(new, mem_rsv_off);
memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
fdt_set_off_dt_struct(new, struct_off);
fdt_set_size_dt_struct(new, struct_size);
memmove(new + strings_off, old + fdt_off_dt_strings(old),
fdt_size_dt_strings(old));
fdt_set_off_dt_strings(new, strings_off);
fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
}
int fdt_open_into(const void *fdt, void *buf, int bufsize)
{
int err;
int mem_rsv_size, struct_size;
int newsize;
const char *fdtstart = fdt;
const char *fdtend = fdtstart + fdt_totalsize(fdt);
char *tmp;
FDT_CHECK_HEADER(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
if (fdt_version(fdt) >= 17) {
struct_size = fdt_size_dt_struct(fdt);
} else {
struct_size = 0;
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
;
if (struct_size < 0)
return struct_size;
}
if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
/* no further work necessary */
err = fdt_move(fdt, buf, bufsize);
if (err)
return err;
fdt_set_version(buf, 17);
fdt_set_size_dt_struct(buf, struct_size);
fdt_set_totalsize(buf, bufsize);
return 0;
}
/* Need to reorder */
newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+ struct_size + fdt_size_dt_strings(fdt);
if (bufsize < newsize)
return -FDT_ERR_NOSPACE;
/* First attempt to build converted tree at beginning of buffer */
tmp = buf;
/* But if that overlaps with the old tree... */
if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
/* Try right after the old tree instead */
tmp = (char *)(uintptr_t)fdtend;
if ((tmp + newsize) > ((char *)buf + bufsize))
return -FDT_ERR_NOSPACE;
}
_fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
memmove(buf, tmp, newsize);
fdt_set_magic(buf, FDT_MAGIC);
fdt_set_totalsize(buf, bufsize);
fdt_set_version(buf, 17);
fdt_set_last_comp_version(buf, 16);
fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
return 0;
}
int fdt_pack(void *fdt)
{
int mem_rsv_size;
FDT_RW_CHECK_HEADER(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
_fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
fdt_set_totalsize(fdt, _fdt_data_size(fdt));
return 0;
}

View file

@ -0,0 +1,100 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include "fdt.h"
#include "libfdt.h"
#include "libfdt_internal.h"
struct fdt_errtabent {
const char *str;
};
#define FDT_ERRTABENT(val) \
[(val)] = { .str = #val, }
static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_NOTFOUND),
FDT_ERRTABENT(FDT_ERR_EXISTS),
FDT_ERRTABENT(FDT_ERR_NOSPACE),
FDT_ERRTABENT(FDT_ERR_BADOFFSET),
FDT_ERRTABENT(FDT_ERR_BADPATH),
FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
FDT_ERRTABENT(FDT_ERR_BADSTATE),
FDT_ERRTABENT(FDT_ERR_TRUNCATED),
FDT_ERRTABENT(FDT_ERR_BADMAGIC),
FDT_ERRTABENT(FDT_ERR_BADVERSION),
FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
FDT_ERRTABENT(FDT_ERR_INTERNAL),
FDT_ERRTABENT(FDT_ERR_BADNCELLS),
FDT_ERRTABENT(FDT_ERR_BADVALUE),
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
};
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
const char *fdt_strerror(int errval)
{
if (errval > 0)
return "<valid offset/length>";
else if (errval == 0)
return "<no error>";
else if (errval > -FDT_ERRTABSIZE) {
const char *s = fdt_errtable[-errval].str;
if (s)
return s;
}
return "<unknown error>";
}

View file

@ -0,0 +1,286 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include "fdt.h"
#include "libfdt.h"
#include "libfdt_internal.h"
static int _fdt_sw_check_header(void *fdt)
{
if (fdt_magic(fdt) != FDT_SW_MAGIC)
return -FDT_ERR_BADMAGIC;
/* FIXME: should check more details about the header state */
return 0;
}
#define FDT_SW_CHECK_HEADER(fdt) \
{ \
int err; \
if ((err = _fdt_sw_check_header(fdt)) != 0) \
return err; \
}
static void *_fdt_grab_space(void *fdt, size_t len)
{
int offset = fdt_size_dt_struct(fdt);
int spaceleft;
spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
- fdt_size_dt_strings(fdt);
if ((offset + len < offset) || (offset + len > spaceleft))
return NULL;
fdt_set_size_dt_struct(fdt, offset + len);
return _fdt_offset_ptr_w(fdt, offset);
}
int fdt_create(void *buf, int bufsize)
{
void *fdt = buf;
if (bufsize < sizeof(struct fdt_header))
return -FDT_ERR_NOSPACE;
memset(buf, 0, bufsize);
fdt_set_magic(fdt, FDT_SW_MAGIC);
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
fdt_set_totalsize(fdt, bufsize);
fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
sizeof(struct fdt_reserve_entry)));
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
fdt_set_off_dt_strings(fdt, bufsize);
return 0;
}
int fdt_resize(void *fdt, void *buf, int bufsize)
{
size_t headsize, tailsize;
char *oldtail, *newtail;
FDT_SW_CHECK_HEADER(fdt);
headsize = fdt_off_dt_struct(fdt);
tailsize = fdt_size_dt_strings(fdt);
if ((headsize + tailsize) > bufsize)
return -FDT_ERR_NOSPACE;
oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
newtail = (char *)buf + bufsize - tailsize;
/* Two cases to avoid clobbering data if the old and new
* buffers partially overlap */
if (buf <= fdt) {
memmove(buf, fdt, headsize);
memmove(newtail, oldtail, tailsize);
} else {
memmove(newtail, oldtail, tailsize);
memmove(buf, fdt, headsize);
}
fdt_set_off_dt_strings(buf, bufsize);
fdt_set_totalsize(buf, bufsize);
return 0;
}
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
{
struct fdt_reserve_entry *re;
int offset;
FDT_SW_CHECK_HEADER(fdt);
if (fdt_size_dt_struct(fdt))
return -FDT_ERR_BADSTATE;
offset = fdt_off_dt_struct(fdt);
if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
return -FDT_ERR_NOSPACE;
re = (struct fdt_reserve_entry *)((char *)fdt + offset);
re->address = cpu_to_fdt64(addr);
re->size = cpu_to_fdt64(size);
fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
return 0;
}
int fdt_finish_reservemap(void *fdt)
{
return fdt_add_reservemap_entry(fdt, 0, 0);
}
int fdt_begin_node(void *fdt, const char *name)
{
struct fdt_node_header *nh;
int namelen = strlen(name) + 1;
FDT_SW_CHECK_HEADER(fdt);
nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
if (! nh)
return -FDT_ERR_NOSPACE;
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
memcpy(nh->name, name, namelen);
return 0;
}
int fdt_end_node(void *fdt)
{
fdt32_t *en;
FDT_SW_CHECK_HEADER(fdt);
en = _fdt_grab_space(fdt, FDT_TAGSIZE);
if (! en)
return -FDT_ERR_NOSPACE;
*en = cpu_to_fdt32(FDT_END_NODE);
return 0;
}
static int _fdt_find_add_string(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
const char *p;
int strtabsize = fdt_size_dt_strings(fdt);
int len = strlen(s) + 1;
int struct_top, offset;
p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
if (p)
return p - strtab;
/* Add it */
offset = -strtabsize - len;
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
if (fdt_totalsize(fdt) + offset < struct_top)
return 0; /* no more room :( */
memcpy(strtab + offset, s, len);
fdt_set_size_dt_strings(fdt, strtabsize + len);
return offset;
}
int fdt_property(void *fdt, const char *name, const void *val, int len)
{
struct fdt_property *prop;
int nameoff;
FDT_SW_CHECK_HEADER(fdt);
nameoff = _fdt_find_add_string(fdt, name);
if (nameoff == 0)
return -FDT_ERR_NOSPACE;
prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
if (! prop)
return -FDT_ERR_NOSPACE;
prop->tag = cpu_to_fdt32(FDT_PROP);
prop->nameoff = cpu_to_fdt32(nameoff);
prop->len = cpu_to_fdt32(len);
memcpy(prop->data, val, len);
return 0;
}
int fdt_finish(void *fdt)
{
char *p = (char *)fdt;
fdt32_t *end;
int oldstroffset, newstroffset;
uint32_t tag;
int offset, nextoffset;
FDT_SW_CHECK_HEADER(fdt);
/* Add terminator */
end = _fdt_grab_space(fdt, sizeof(*end));
if (! end)
return -FDT_ERR_NOSPACE;
*end = cpu_to_fdt32(FDT_END);
/* Relocate the string table */
oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
fdt_set_off_dt_strings(fdt, newstroffset);
/* Walk the structure, correcting string offsets */
offset = 0;
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
if (tag == FDT_PROP) {
struct fdt_property *prop =
_fdt_offset_ptr_w(fdt, offset);
int nameoff;
nameoff = fdt32_to_cpu(prop->nameoff);
nameoff += fdt_size_dt_strings(fdt);
prop->nameoff = cpu_to_fdt32(nameoff);
}
offset = nextoffset;
}
if (nextoffset < 0)
return nextoffset;
/* Finally, adjust the header */
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
fdt_set_magic(fdt, FDT_MAGIC);
return 0;
}

View file

@ -0,0 +1,137 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include "fdt.h"
#include "libfdt.h"
#include "libfdt_internal.h"
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
const char *name, int namelen,
uint32_t idx, const void *val,
int len)
{
void *propval;
int proplen;
propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen,
&proplen);
if (!propval)
return proplen;
if (proplen < (len + idx))
return -FDT_ERR_NOSPACE;
memcpy((char *)propval + idx, val, len);
return 0;
}
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
const void *propval;
int proplen;
propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
if (! propval)
return proplen;
if (proplen != len)
return -FDT_ERR_NOSPACE;
return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
strlen(name), 0,
val, len);
}
static void _fdt_nop_region(void *start, int len)
{
fdt32_t *p;
for (p = start; (char *)p < ((char *)start + len); p++)
*p = cpu_to_fdt32(FDT_NOP);
}
int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
{
struct fdt_property *prop;
int len;
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (! prop)
return len;
_fdt_nop_region(prop, len + sizeof(*prop));
return 0;
}
int _fdt_node_end_offset(void *fdt, int offset)
{
int depth = 0;
while ((offset >= 0) && (depth >= 0))
offset = fdt_next_node(fdt, offset, &depth);
return offset;
}
int fdt_nop_node(void *fdt, int nodeoffset)
{
int endoffset;
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;
_fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
endoffset - nodeoffset);
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,113 @@
#ifndef _LIBFDT_ENV_H
#define _LIBFDT_ENV_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef __CHECKER__
#define FDT_FORCE __attribute__((force))
#define FDT_BITWISE __attribute__((bitwise))
#else
#define FDT_FORCE
#define FDT_BITWISE
#endif
typedef uint16_t FDT_BITWISE fdt16_t;
typedef uint32_t FDT_BITWISE fdt32_t;
typedef uint64_t FDT_BITWISE fdt64_t;
typedef uint64_t unaligned_fdt64_t __attribute__((aligned(4)));
#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
(EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
(EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
(EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
(EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
static inline uint16_t fdt16_to_cpu(fdt16_t x)
{
return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
}
static inline fdt16_t cpu_to_fdt16(uint16_t x)
{
return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
}
static inline uint32_t fdt32_to_cpu(fdt32_t x)
{
return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
}
static inline fdt32_t cpu_to_fdt32(uint32_t x)
{
return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
}
static inline uint64_t fdt64_to_cpu(fdt64_t x)
{
return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
}
static inline fdt64_t cpu_to_fdt64(uint64_t x)
{
return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
}
#undef CPU_TO_FDT64
#undef CPU_TO_FDT32
#undef CPU_TO_FDT16
#undef EXTRACT_BYTE
#endif /* _LIBFDT_ENV_H */

View file

@ -0,0 +1,95 @@
#ifndef _LIBFDT_INTERNAL_H
#define _LIBFDT_INTERNAL_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "fdt.h"
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
#define FDT_CHECK_HEADER(fdt) \
{ \
int __err; \
if ((__err = fdt_check_header(fdt)) != 0) \
return __err; \
}
int _fdt_check_node_offset(const void *fdt, int offset);
int _fdt_check_prop_offset(const void *fdt, int offset);
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
int _fdt_node_end_offset(void *fdt, int nodeoffset);
static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
{
return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
}
static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
{
return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
}
static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
{
const struct fdt_reserve_entry *rsv_table =
(const struct fdt_reserve_entry *)
((const char *)fdt + fdt_off_mem_rsvmap(fdt));
return rsv_table + n;
}
static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
{
return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
}
#define FDT_SW_MAGIC (~FDT_MAGIC)
#endif /* _LIBFDT_INTERNAL_H */

View file

@ -0,0 +1,17 @@
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
list = os.listdir(cwd)
CPPPATH = [cwd + '/../inc' , cwd + '/libfdt']
objs = []
group = DefineGroup('FDT', src, depend = ['RT_USING_FDT'], 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')

View file

@ -0,0 +1,648 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "libfdt.h"
#include "dtb_node.h"
/* "/aliaes" node */
static struct dtb_node *fdt_aliases;
/**
* of_find_property_value_of_size() - find property of given size
*
* Search for a property in a device node and validate the requested size.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @len: requested length of property value
*
* @return the property value on success, -EINVAL if the property does not
* exist, -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data isn't large enough.
*/
static void *dtb_node_find_property_value_of_size(const struct dtb_node *dn,
const char *propname, uint32_t len)
{
struct dtb_property *prop = dtb_node_get_dtb_node_property(dn, propname, NULL);
if (!prop)
return ERR_PTR(-EINVAL);
if (!prop->value)
return ERR_PTR(-ENODATA);
if (len > prop->size)
return ERR_PTR(-EOVERFLOW);
return prop->value;
}
int dtb_node_read_u32(const struct dtb_node *dn, const char *propname, uint32_t *outp)
{
const uint32_t *val;
debug("%s: %s: \n", __func__, propname);
if (!dn)
return -EINVAL;
val = dtb_node_find_property_value_of_size(dn, propname, sizeof(*outp));
if (IS_ERR(val))
{
debug("(not found)\n");
return PTR_ERR(val);
}
*outp = fdt32_to_cpu(*val);
debug("%#x (%d)\n", *outp, *outp);
return 0;
}
uint32_t dtb_node_read_u32_default(const struct dtb_node *node, const char *propname, uint32_t def)
{
dtb_node_read_u32(node, propname, &def);
return def;
}
int dtb_node_read_u32_array(const struct dtb_node *dn, const char *propname,
uint32_t *out_values, size_t sz)
{
const uint32_t *val;
debug("%s: %s: ", __func__, propname);
val = dtb_node_find_property_value_of_size(dn, propname,
sz * sizeof(*out_values));
if (IS_ERR(val))
return PTR_ERR(val);
debug("size %zd, val:%d\n", sz, *val);
while (sz--)
*out_values++ = fdt32_to_cpu(*val++);
return 0;
}
uint32_t dtb_node_read_u32_index_default(const struct dtb_node *node, const char *propname, int index,
uint32_t def)
{
RT_ASSERT(dtb_node_valid(node));
dtb_node_read_u32_index(node, propname, index, &def);
return def;
}
int dtb_node_read_s32_default(const struct dtb_node *node, const char *propname, int32_t def)
{
RT_ASSERT(dtb_node_valid(node));
dtb_node_read_u32(node, propname, (uint32_t *)&def);
return def;
}
int dtb_node_read_u32_index(const struct dtb_node *dn, const char *propname,
int index, uint32_t *outp)
{
const uint32_t *val;
debug("%s: %s: ", __func__, propname);
if (!dn)
return -EINVAL;
val = dtb_node_find_property_value_of_size(dn, propname,
sizeof(*outp) * (index + 1));
if (IS_ERR(val))
{
debug("(not found)\n");
return PTR_ERR(val);
}
*outp = fdt32_to_cpu(val[index]);
debug("%#x (%d)\n", *outp, *outp);
return 0;
}
int dtb_node_read_u64(const struct dtb_node *dn, const char *propname, uint64_t *outp)
{
const uint64_t *val;
debug("%s: %s: ", __func__, propname);
if (!dn)
return -EINVAL;
val = dtb_node_find_property_value_of_size(dn, propname, sizeof(*outp));
if (IS_ERR(val))
{
debug("(not found)\n");
return PTR_ERR(val);
}
*outp = fdt64_to_cpu(*val);
debug("%#llx (%lld)\n", (unsigned long long)*outp,
(unsigned long long)*outp);
return 0;
}
uint64_t dtb_node_read_u64_default(const struct dtb_node *node, const char *propname, uint64_t def)
{
RT_ASSERT(dtb_node_valid(node));
dtb_node_read_u64(node, propname, &def);
return def;
}
int dtb_node_n_addr_cells(const struct dtb_node *dn)
{
const uint32_t *ip;
do
{
if (dn->parent)
dn = dn->parent;
ip = dtb_node_get_dtb_node_property_value(dn, "#address-cells", NULL);
if (ip)
return fdt32_to_cpu(*ip);
} while (dn->parent);
/* No #address-cells property for the root node */
return DEV_ROOT_NODE_ADDR_CELLS_DEFAULT;
}
int dtb_node_n_size_cells(const struct dtb_node *dn)
{
const uint32_t *ip;
do
{
if (dn->parent)
dn = dn->parent;
ip = dtb_node_get_dtb_node_property_value(dn, "#size-cells", NULL);
if (ip)
return fdt32_to_cpu(*ip);
} while (dn->parent);
/* No #size-cells property for the root node */
return DEV_ROOT_NODE_SIZE_CELLS_DEFAULT;
}
int dtb_node_simple_addr_cells(const struct dtb_node *dn)
{
const uint32_t *ip;
ip = dtb_node_get_dtb_node_property_value(dn, "#address-cells", NULL);
if (ip)
return fdt32_to_cpu(*ip);
/* Return a default of 2 to match fdt_address_cells()*/
return 2;
}
int dtb_node_simple_size_cells(const struct dtb_node *dn)
{
const uint32_t *ip;
ip = dtb_node_get_dtb_node_property_value(dn, "#size-cells", NULL);
if (ip)
return fdt32_to_cpu(*ip);
/* Return a default of 2 to match fdt_size_cells()*/
return 2;
}
struct dtb_property *dtb_node_get_dtb_node_property(const struct dtb_node *dtb_node, const char *property_name, int *property_size)
{
struct dtb_property *dtb_property = NULL;
if (dtb_node != NULL && property_name != NULL)
{
dtb_property = dtb_node->properties;
while (dtb_property != NULL)
{
if (!strcmp(dtb_property->name, property_name))
{
if (property_size != NULL)
{
*property_size = dtb_property->size;
}
return dtb_property;
}
dtb_property = dtb_property->next;
}
}
return dtb_property;
}
#define for_each_property_of_node(dn, pp) \
for (pp = dn->properties; pp != NULL; pp = pp->next)
struct dtb_node *dtb_node_find_node_opts_by_path(const char *path,
const char **opts)
{
struct dtb_node *np = NULL;
struct dtb_property *pp;
const char *separator = strchr(path, ':');
if (opts)
*opts = separator ? separator + 1 : NULL;
if (strcmp(path, "/") == 0)
return dtb_node_get(get_dtb_node_head());
/* The path could begin with an alias */
if (*path != '/')
{
int len;
const char *p = separator;
if (!p)
p = strchrnul(path, '/');
len = p - path;
/* of_aliases must not be NULL */
if (!fdt_aliases)
return NULL;
for_each_property_of_node(fdt_aliases, pp)
{
if (strlen(pp->name) == len && !strncmp(pp->name, path,
len))
{
np = dtb_node_find_node_by_path(pp->value);
break;
}
}
if (!np)
return NULL;
path = p;
}
/* Step down the tree matching path components */
if (!np)
np = dtb_node_get(get_dtb_node_head());
while (np && *path == '/')
{
struct dtb_node *tmp = np;
path++; /* Increment past '/' delimiter */
np = dtb_node_get_dtb_node_by_path(np, path);
dtb_node_put(tmp);
path = strchrnul(path, '/');
if (separator && separator < path)
break;
}
return np;
}
struct dtb_node *dtb_node_find_compatible_node(struct dtb_node *from, const char *compatible)
{
struct dtb_node *dn;
for_each_of_allnodes_from(from, dn)
{
if (dtb_node_get_dtb_node_compatible_match(dn, compatible) &&
dtb_node_get(dn))
break;
}
dtb_node_put(from);
return dn;
}
void *dtb_node_get_dtb_node_property_value(const struct dtb_node *dtb_node, const char *property_name, int *property_size)
{
struct dtb_property *dtb_property = dtb_node_get_dtb_node_property(dtb_node, property_name, NULL);
if (!dtb_property || !dtb_property->value || !dtb_property->size)
{
return NULL;
}
if (property_size != NULL)
{
*property_size = dtb_property->size;
}
return dtb_property->value;
}
const struct dtb_node *dtb_node_find_node_by_prop_value(struct dtb_node *from,
const char *propname,
const void *propval, int proplen)
{
struct dtb_node *np;
void *value;
for_each_of_allnodes_from(from, np)
{
value = dtb_node_get_dtb_node_property_value(np, propname, &proplen);
if (!memcmp(value, propval, proplen) && dtb_node_get(np))
break;
}
dtb_node_put(from);
return np;
}
struct dtb_node *dtb_node_find_all_nodes(const struct dtb_node *prev)
{
const struct dtb_node *dn;
if (!prev)
{
dn = get_dtb_node_head();
}
else if (prev->child)
{
dn = prev->child;
}
else
{
/*
* Walk back up looking for a sibling, or the end of the
* structure
*/
dn = prev;
while (dn->parent && !dn->sibling)
dn = dn->parent;
dn = dn->sibling; /* Might be null at the end of the tree */
}
return (struct dtb_node *)dn;
}
rt_bool_t dtb_node_device_is_available(const struct dtb_node *device)
{
const char *status;
int statlen;
if (!device)
return RT_FALSE;
status = dtb_node_get_dtb_node_property_value(device, "status", &statlen);
if (status == NULL)
return RT_TRUE;
if (statlen > 0)
{
if (!strcmp(status, "okay"))
return RT_TRUE;
}
return RT_FALSE;
}
struct dtb_node *dtb_node_get_parent(const struct dtb_node *node)
{
const struct dtb_node *dn;
if (!node)
return NULL;
dn = dtb_node_get(node->parent);
return (struct dtb_node *)dn;
}
struct dtb_node *dtb_node_find_node_by_phandle(phandle handle)
{
struct dtb_node *dn;
if (!handle)
return NULL;
for_each_of_allnodes(dn) if (dn->handle == handle) break;
(void)dtb_node_get(dn);
return dn;
}
int dtb_node_property_match_string(const struct dtb_node *dn, const char *propname,
const char *string)
{
const struct dtb_property *prop = dtb_node_get_dtb_node_property(dn, propname, NULL);
size_t l;
int i;
const char *p, *end;
if (!prop)
return -EINVAL;
if (!prop->value)
return -ENODATA;
p = prop->value;
end = p + prop->size;
for (i = 0; p < end; i++, p += l)
{
l = strnlen(p, end - p) + 1;
if (p + l > end)
return -EILSEQ;
debug("comparing %s with %s\n", string, p);
if (strcmp(string, p) == 0)
return i; /* Found it; return index */
}
return -ENODATA;
}
/**
* of_property_read_string_helper() - Utility helper for parsing string properties
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_strs: output array of string pointers.
* @sz: number of array elements to read.
* @skip: Number of strings to skip over at beginning of list.
*
* Don't call this function directly. It is a utility helper for the
* of_property_read_string*() family of functions.
*/
int dtb_node_property_read_string_helper(const struct dtb_node *dn,
const char *propname, const char **out_strs,
size_t sz, int skip)
{
const struct dtb_property *prop = dtb_node_get_dtb_node_property(dn, propname, NULL);
int l = 0, i = 0;
const char *p, *end;
if (!prop)
return -EINVAL;
if (!prop->value)
return -ENODATA;
p = prop->value;
end = p + prop->size;
for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l)
{
l = strnlen(p, end - p) + 1;
if (p + l > end)
return -EILSEQ;
if (out_strs && i >= skip)
*out_strs++ = p;
}
i -= skip;
return i <= 0 ? -ENODATA : i;
}
static int __dtb_node_parse_phandle_with_args(const struct dtb_node *dn,
const char *list_name,
const char *cells_name,
int cell_count, int index,
struct fdt_phandle_args *out_args)
{
const uint32_t *list, *list_end;
int rc = 0, cur_index = 0;
uint32_t count = 0;
struct dtb_node *node = NULL;
phandle phandle;
int size;
/* Retrieve the phandle list property */
list = dtb_node_get_dtb_node_property_value(dn, list_name, &size);
if (!list)
return -ENOENT;
list_end = list + size / sizeof(*list);
/* Loop over the phandles until all the requested entry is found */
while (list < list_end)
{
rc = -EINVAL;
count = 0;
/*
* If phandle is 0, then it is an empty entry with no
* arguments. Skip forward to the next entry.
*/
phandle = fdt32_to_cpu(*(list++));
if (phandle)
{
/*
* Find the provider node and parse the #*-cells
* property to determine the argument length.
*
* This is not needed if the cell count is hard-coded
* (i.e. cells_name not set, but cell_count is set),
* except when we're going to return the found node
* below.
*/
if (cells_name || cur_index == index)
{
node = dtb_node_find_node_by_phandle(phandle);
if (!node)
{
debug("%s: could not find phandle\n",
dn->path);
goto err;
}
}
if (cells_name)
{
if (dtb_node_read_u32(node, cells_name, &count))
{
debug("%s: could not get %s for %s\n",
dn->path, cells_name,
node->path);
goto err;
}
}
else
{
count = cell_count;
}
/*
* Make sure that the arguments actually fit in the
* remaining property data length
*/
if (list + count > list_end)
{
debug("%s: arguments longer than property\n",
dn->path);
goto err;
}
}
/*
* All of the error cases above bail out of the loop, so at
* this point, the parsing is successful. If the requested
* index matches, then fill the out_args structure and return,
* or return -ENOENT for an empty entry.
*/
rc = -ENOENT;
if (cur_index == index)
{
if (!phandle)
goto err;
if (out_args)
{
int i;
if (count > FDT_MAX_PHANDLE_ARGS)
count = FDT_MAX_PHANDLE_ARGS;
out_args->np = node;
out_args->args_count = count;
for (i = 0; i < count; i++)
out_args->args[i] =
fdt32_to_cpu(*(list++));
}
else
{
dtb_node_put(node);
}
/* Found it! return success */
return 0;
}
dtb_node_put(node);
node = NULL;
list += count;
cur_index++;
}
/*
* Unlock node before returning result; will be one of:
* -ENOENT : index is for empty phandle
* -EINVAL : parsing error on data
* [1..n] : Number of phandle (count mode; when index = -1)
*/
rc = index < 0 ? cur_index : -ENOENT;
err:
if (node)
dtb_node_put(node);
return rc;
}
struct dtb_node *dtb_node_parse_phandle(const struct dtb_node *dn,
const char *phandle_name, int index)
{
struct fdt_phandle_args args;
if (index < 0)
return NULL;
if (__dtb_node_parse_phandle_with_args(dn, phandle_name, NULL, 0, index,
&args))
return NULL;
return args.np;
}
int dtb_node_parse_phandle_with_args(const struct dtb_node *dn,
const char *list_name, const char *cells_name,
int index, struct fdt_phandle_args *out_args)
{
if (index < 0)
return -EINVAL;
return __dtb_node_parse_phandle_with_args(dn, list_name, cells_name, 0,
index, out_args);
}
int dtb_node_count_phandle_with_args(const struct dtb_node *dn,
const char *list_name, const char *cells_name)
{
return __dtb_node_parse_phandle_with_args(dn, list_name, cells_name, 0,
-1, NULL);
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "libfdt.h"
#include "dtb_node.h"
/* Max address size we deal with */
#define FDT_MAX_ADDR_CELLS 4
#define FDT_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= FDT_MAX_ADDR_CELLS)
#define FDT_CHECK_COUNTS(na, ns) (FDT_CHECK_ADDR_COUNT(na) && (ns) > 0)
static void dtb_node_default_count_cells(const struct dtb_node *dn,
int *addrc, int *sizec)
{
if (addrc)
*addrc = dtb_node_n_addr_cells(dn);
if (sizec)
*sizec = dtb_node_n_size_cells(dn);
}
const uint32_t *dtb_node_get_address(const struct dtb_node *dev, int index,
uint64_t *size, unsigned int *flags)
{
const uint32_t *prop;
int psize;
struct dtb_node *parent;
int onesize, i, na, ns;
/* Get parent */
parent = dtb_node_get_parent(dev);
if (parent == NULL)
return NULL;
dtb_node_default_count_cells(dev, &na, &ns);
if (!FDT_CHECK_ADDR_COUNT(na))
return NULL;
/* Get "reg" or "assigned-addresses" property */
prop = dtb_node_get_dtb_node_property_value(dev, "reg", &psize);
if (prop == NULL)
return NULL;
psize /= 4;
onesize = na + ns;
for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
if (i == index)
{
if (size)
*size = dtb_node_read_number(prop + na, ns);
if (flags)
*flags = 0x200;
return prop;
}
return NULL;
}

View file

@ -0,0 +1,574 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "dtb_node.h"
#include "libfdt.h"
#include "libfdt_env.h"
#include <ctype.h>
static const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
{
if (*base == 0)
{
if (s[0] == '0')
{
if (tolower(s[1]) == 'x' && isxdigit((int)s[2]))
*base = 16;
else
*base = 8;
}
else
*base = 10;
}
if (*base == 16 && s[0] == '0' && tolower(s[1]) == 'x')
s += 2;
return s;
}
unsigned long simple_strtoul(const char *cp, char **endp,
unsigned int base)
{
unsigned long result = 0;
unsigned long value;
cp = _parse_integer_fixup_radix(cp, &base);
while (isxdigit((int)*cp) && (value = isdigit((int)*cp) ? *cp-'0' : (islower((int)*cp)
? toupper(*cp) : *cp)-'A'+10) < base)
{
result = result*base + value;
cp++;
}
if (endp)
*endp = (char *)cp;
return result;
}
int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
{
char *tail;
unsigned long val;
size_t len;
*res = 0;
len = strlen(cp);
if (len == 0)
return -EINVAL;
val = simple_strtoul(cp, &tail, base);
if (tail == cp)
return -EINVAL;
if ((*tail == '\0') ||
((len == (size_t)(tail - cp) + 1) && (*tail == '\n')))
{
*res = val;
return 0;
}
return -EINVAL;
}
long simple_strtol(const char *cp, char **endp, unsigned int base)
{
if (*cp == '-')
return -simple_strtoul(cp + 1, endp, base);
return simple_strtoul(cp, endp, base);
}
rt_bool_t dtb_node_read_bool(const struct dtb_node *node, const char *propname)
{
const void *prop;
RT_ASSERT(dtb_node_valid(node));
debug("%s: %s: ", __func__, propname);
prop = dtb_node_get_property(node, propname, NULL);
debug("%s\n", prop ? "true" : "false");
return prop ? RT_TRUE : RT_FALSE;
}
const void *dtb_node_read_prop(const struct dtb_node *node, const char *propname, int *sizep)
{
const char *val = NULL;
int len;
RT_ASSERT(dtb_node_valid(node));
debug("%s: %s: ", __func__, propname);
struct dtb_property *prop = dtb_node_get_dtb_node_property(node, propname, &len);
if (prop)
{
val = prop->value;
len = prop->size;
}
if (!val)
{
debug("<not found>\n");
if (sizep)
*sizep = -FDT_ERR_NOTFOUND;
return NULL;
}
if (sizep)
*sizep = len;
return val;
}
const char *dtb_node_read_string(const struct dtb_node *node, const char *propname)
{
const char *str;
int len;
str = dtb_node_read_prop(node, propname, &len);
if (!str)
return NULL;
if (strnlen(str, len) >= len)
{
debug("<invalid>\n");
return NULL;
}
debug("%s\n", str);
return str;
}
const struct dtb_node *dtb_node_find_subnode(const struct dtb_node *node, const char *subnode_name)
{
const struct dtb_node *subnode;
RT_ASSERT(dtb_node_valid(node));
debug("%s: %s: ", __func__, subnode_name);
for (node = node->child; node; node = node->sibling)
{
if (!strcmp(subnode_name, node->name))
break;
}
subnode = node;
debug("%s\n", dtb_node_valid(subnode) ?\
dtb_node_get_name(subnode) : "<none>");
return subnode;
}
struct dtb_node *dtb_node_first_subnode(const struct dtb_node *node)
{
RT_ASSERT(dtb_node_valid(node));
return node->child;
}
struct dtb_node *dtb_node_next_subnode(const struct dtb_node *node)
{
RT_ASSERT(dtb_node_valid(node));
return node->sibling;
}
const char *dtb_node_get_name(const struct dtb_node *node)
{
if (!dtb_node_valid(node))
{
debug("%s node not valid\n", __func__);
return NULL;
}
return strrchr(node->path, '/') + 1;
}
struct dtb_node *dtb_node_get_by_phandle(uint32_t phandle)
{
if (dtb_node_active())
return dtb_node_find_node_by_phandle(phandle);
return NULL;
}
int dtb_node_read_size(const struct dtb_node *node, const char *propname)
{
struct dtb_property *prop = dtb_node_get_dtb_node_property( node, propname, NULL);
if (prop)
return prop->size;
return -EINVAL;
}
int dtb_node_get_addr_and_size_by_index(const struct dtb_node *node, int index, size_t *addr, size_t *size)
{
const uint32_t *prop;
int psize;
int onesize, na, ns;
na = dtb_node_n_addr_cells(node);
ns = dtb_node_n_size_cells(node);
prop = dtb_node_get_dtb_node_property_value(node, "reg", &psize);
if (prop == NULL)
{
return -1;
}
psize /= 4;
onesize = na + ns;
if (psize >= (index + 1) * onesize)
{
prop += index * onesize;
if (addr)
{
*addr = dtb_node_read_number(prop, na);
}
if (size)
{
*size = dtb_node_read_number(prop + na, ns);
}
return 0;
}
return -1;
}
size_t dtb_node_get_addr_index(const struct dtb_node *node, int index)
{
int na;
size_t size;
const uint32_t *prop_val;
uint flags;
prop_val = dtb_node_get_address(node, index,
(uint64_t *)&size, &flags);
if (!prop_val)
return -1;
na = dtb_node_n_addr_cells(node);
return dtb_node_read_number(prop_val, na);
}
size_t dtb_node_get_addr(const struct dtb_node *node)
{
return dtb_node_get_addr_index(node, 0);
}
int dtb_node_stringlist_search(const struct dtb_node *node, const char *property,
const char *string)
{
return dtb_node_property_match_string(node, property, string);
}
int dtb_node_read_string_index(const struct dtb_node *node, const char *property, int index,
const char **outp)
{
return dtb_node_property_read_string_index(node, property, index, outp);
}
int dtb_node_read_string_count(const struct dtb_node *node, const char *property)
{
return dtb_node_property_count_strings(node, property);
}
struct dtb_node *dtb_node_path(const char *path)
{
if (dtb_node_active())
return dtb_node_find_node_by_path(path);
return NULL;
}
const char *dtb_node_get_chosen_prop(const char *name)
{
const struct dtb_node *chosen_node;
chosen_node = (const struct dtb_node *)dtb_node_path("/chosen");
return dtb_node_read_string(chosen_node, name);
}
struct dtb_node *dtb_node_get_chosen_node(const char *name)
{
const char *prop;
prop = dtb_node_get_chosen_prop(name);
if (!prop)
return NULL;
return dtb_node_path(prop);
}
const void *dtb_node_get_property(const struct dtb_node *node, const char *propname, int *lenp)
{
return dtb_node_get_dtb_node_property_value(node, propname, lenp);
}
rt_bool_t dtb_node_is_available(const struct dtb_node *node)
{
return dtb_node_device_is_available(node);
}
size_t dtb_node_get_addr_size(const struct dtb_node *node, const char *property,
size_t *sizep)
{
int na, ns;
int psize;
const uint32_t *prop = dtb_node_get_dtb_node_property_value(node, property, &psize);
if (!prop)
return -1;
na = dtb_node_n_addr_cells(node);
ns = dtb_node_n_size_cells(node);
*sizep = dtb_node_read_number(prop + na, ns);
return dtb_node_read_number(prop, na);
}
const uint8_t *dtb_node_read_u8_array_ptr(const struct dtb_node *node, const char *propname,
size_t sz)
{
int psize;
const uint32_t *prop = dtb_node_get_dtb_node_property_value(node, propname, &psize);
if (!prop || sz != psize)
return NULL;
return (uint8_t *)prop;
}
int dtb_node_find_all_compatible_node(const struct dtb_node *from, const char *compatible, struct dtb_node **node_table, int max_num, int *node_num)
{
const struct dtb_node *dn;
int num = 0;
for_each_of_allnodes_from(from, dn)
{
if (dtb_node_get_dtb_node_compatible_match(dn, compatible) &&
dtb_node_get(dn))
{
num++;
*node_table = (struct dtb_node *)dn;
node_table++;
if (num >= max_num)
{
break;
}
}
}
*node_num = num;
dtb_node_put(from);
return 0;
}
int dtb_node_write_prop(const struct dtb_node *node, const char *propname, int len,
const void *value)
{
struct dtb_property *pp;
struct dtb_property *pp_last = NULL;
struct dtb_property *new;
if (!dtb_node_active())
return -ENOSYS;
if (!node)
return -EINVAL;
for (pp = node->properties; pp; pp = pp->next)
{
if (strcmp(pp->name, propname) == 0)
{
/* Property exists -> change value */
pp->value = (void *)value;
pp->size = len;
return 0;
}
pp_last = pp;
}
if (!pp_last)
return -ENOENT;
/* Property does not exist -> append new property */
new = (struct dtb_property *)malloc(sizeof(struct dtb_property));
if (!new)
return -ENOMEM;
new->name = strdup(propname);
if (!new->name)
{
free(new);
return -ENOMEM;
}
new->value = (void *)value;
new->size = len;
new->next = NULL;
pp_last->next = new;
return 0;
}
int dtb_node_write_string(const struct dtb_node *node, const char *propname, const char *value)
{
if (!dtb_node_active())
return -ENOSYS;
RT_ASSERT(dtb_node_valid(node));
debug("%s: %s = %s", __func__, propname, value);
return dtb_node_write_prop(node, propname, strlen(value) + 1, value);
}
int dtb_node_set_enabled(const struct dtb_node *node, rt_bool_t value)
{
if (!dtb_node_active())
return -ENOSYS;
RT_ASSERT(dtb_node_valid(node));
if (value)
return dtb_node_write_string(node, "status", "okay");
else
return dtb_node_write_string(node, "status", "disable");
}
/**
* dtb_node_irq_find_parent - Given a device node, find its interrupt parent node
* @child: pointer to device node
*
* Returns a pointer to the interrupt parent node, or NULL if the interrupt
* parent could not be determined.
*/
static struct dtb_node *dtb_node_irq_find_parent(struct dtb_node *child)
{
struct dtb_node *p;
phandle parent;
if (!dtb_node_get(child))
return NULL;
do
{
if (dtb_node_read_u32_array(child, "interrupt-parent", &parent, 1))
{
p = dtb_node_get_parent(child);
}
else
{
p = dtb_node_get_by_phandle(parent);
}
dtb_node_put(child);
child = p;
} while (p && dtb_node_get_property(p, "#interrupt-cells", NULL) == NULL);
return p;
}
int dtb_node_irq_get(struct dtb_node *dev, int index)
{
int rc = 0;
struct fdt_phandle_args out_irq;
struct dtb_node *p;
uint32_t intsize;
int res, i;
p = dtb_node_irq_find_parent(dev);
if (p == NULL)
return -EINVAL;
/* Get size of interrupt specifier */
if (dtb_node_read_u32_array(p, "#interrupt-cells", &intsize, 1))
{
res = -EINVAL;
goto out;
}
debug(" path:%s, parent=%pOF, intsize=%d\n", p->path,p, intsize);
/* Copy intspec into irq structure */
out_irq.np = p;
out_irq.args_count = intsize;
for (i = 0; i < intsize; i++)
{
res = dtb_node_read_u32_index(dev, "interrupts",
(index * 3 + i),
out_irq.args + i);
if (res)
goto out;
}
rc = out_irq.args[1];
out:
dtb_node_put(p);
return rc;
}
/**
* dtb_node_irq_get_byname - Decode a node's IRQ and return it as a Linux IRQ number
* @dev: pointer to device tree node
* @name: IRQ name
*
* Returns Linux IRQ number on success, or 0 on the IRQ mapping failure, or
* -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
* of any other failure.
*/
int dtb_node_irq_get_byname(struct dtb_node *dev, const char *name)
{
int index;
if (!name)
return -EINVAL;
index = dtb_node_stringlist_search(dev, "interrupt-names", name);
if (index < 0)
return index;
return dtb_node_irq_get(dev, index);
}
/**
* dtb_node_irq_count - Count the number of IRQs a node uses
* @dev: pointer to device tree node
*/
int dtb_node_irq_count(struct dtb_node *device)
{
struct dtb_node *p;
uint32_t intsize;
int nr = 0, res = 0;
p = dtb_node_irq_find_parent(device);
if (p == NULL)
return -EINVAL;
/* Get size of interrupt specifier */
if (dtb_node_read_u32_array(p, "#interrupt-cells", &intsize, 1))
{
res = -EINVAL;
goto out;
}
debug(" path:%s, parent=%pOF, intsize=%d\n", p->path,p, intsize);
res = dtb_node_read_size(device, "interrupts");
if (res < 0)
{
goto out;
}
nr = res / (intsize * 4);
out:
dtb_node_put(p);
return nr;
}

View file

@ -0,0 +1,820 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "libfdt.h"
#include "dtb_node.h"
static struct
{
const char *ptr;
const char *end;
char *cur;
} paths_buf = {NULL, NULL};
static void *current_fdt;
int fdt_exec_status = FDT_RET_GET_OK;
int dtb_node_get_exec_status()
{
return fdt_exec_status;
}
static int _dtb_node_get_dtb_properties_list(struct dtb_property *dtb_property, off_t node_off)
{
/* caller alrealy checked current_fdt */
off_t property_off = fdt_first_property_offset(current_fdt, node_off);
struct fdt_property *fdt_property;
if (property_off < 0)
{
return FDT_RET_GET_EMPTY;
}
for (;;)
{
fdt_property = (struct fdt_property *)fdt_get_property_by_offset(current_fdt, property_off, &dtb_property->size);
if (fdt_property != NULL)
{
dtb_property->name = fdt_string(current_fdt, fdt32_to_cpu(fdt_property->nameoff));
dtb_property->value = fdt_property->data;
dtb_property->size = fdt32_to_cpu(fdt_property->len);
}
property_off = fdt_next_property_offset(current_fdt, property_off);
if (property_off >= 0)
{
dtb_property->next = (struct dtb_property *)malloc(sizeof(struct dtb_property));
if (dtb_property->next == NULL)
{
return FDT_RET_NO_MEMORY;
}
dtb_property = dtb_property->next;
}
else
{
dtb_property->next = NULL;
break;
}
}
return FDT_RET_GET_OK;
}
static int _dtb_node_get_dtb_nodes_list(struct dtb_node *dtb_node_head, struct dtb_node *dtb_node, const char *pathname)
{
off_t root_off;
off_t node_off;
int pathname_sz;
int node_name_sz;
/* caller alrealy checked current_fdt */
if ((root_off = fdt_path_offset(current_fdt, pathname)) >= 0)
{
pathname_sz = strlen(pathname);
node_off = fdt_first_subnode(current_fdt, root_off);
if (node_off < 0)
{
return FDT_RET_GET_EMPTY;
}
for (;;)
{
dtb_node->parent = dtb_node_head;
dtb_node->sibling = NULL;
dtb_node->name = fdt_get_name(current_fdt, node_off, &node_name_sz);
/* parent_path + name + '/' + '\0' */
if (paths_buf.cur + pathname_sz + node_name_sz + 2 < paths_buf.end)
{
dtb_node->path = (const char *)paths_buf.cur;
strncpy(paths_buf.cur, pathname, pathname_sz);
paths_buf.cur += pathname_sz;
strncpy(paths_buf.cur, (char *)dtb_node->name, node_name_sz);
paths_buf.cur += node_name_sz;
*paths_buf.cur++ = '/';
*paths_buf.cur++ = '\0';
}
else
{
dtb_node->path = NULL;
rt_kprintf("\033[31m\rERROR: `FDT_DTB_ALL_NODES_PATH_SIZE' = %d bytes is configured too low.\033[0m\n", FDT_DTB_ALL_NODES_PATH_SIZE);
return FDT_RET_NO_MEMORY;
}
dtb_node->handle = fdt_get_phandle(current_fdt, node_off);
dtb_node->properties = (struct dtb_property *)malloc(sizeof(struct dtb_property));
dtb_node->child = (struct dtb_node *)malloc(sizeof(struct dtb_node));
if (dtb_node->properties == NULL || dtb_node->child == NULL)
{
return FDT_RET_NO_MEMORY;
}
fdt_exec_status = _dtb_node_get_dtb_properties_list(dtb_node->properties, node_off);
if (fdt_exec_status == FDT_RET_GET_EMPTY)
{
free(dtb_node->properties);
dtb_node->properties = NULL;
}
else if (fdt_exec_status != FDT_RET_GET_OK)
{
return fdt_exec_status;
}
fdt_exec_status = _dtb_node_get_dtb_nodes_list(dtb_node, dtb_node->child, dtb_node->path);
if (fdt_exec_status == FDT_RET_GET_EMPTY)
{
free(dtb_node->child);
dtb_node->child = NULL;
}
else if (fdt_exec_status != FDT_RET_GET_OK)
{
return fdt_exec_status;
}
node_off = fdt_next_subnode(current_fdt, node_off);
if (node_off >= 0)
{
dtb_node->sibling = (struct dtb_node *)malloc(sizeof(struct dtb_node));
if (dtb_node->sibling == NULL)
{
return FDT_RET_NO_MEMORY;
}
dtb_node = dtb_node->sibling;
}
else
{
break;
}
}
}
return FDT_RET_GET_OK;
}
struct dtb_node *dtb_node_get_dtb_list(void *fdt)
{
int root_off;
struct dtb_node *dtb_node_head = NULL;
if (fdt == NULL)
{
fdt_exec_status = FDT_RET_NO_LOADED;
goto fail;
}
current_fdt = fdt;
if ((dtb_node_head = (struct dtb_node *)malloc(sizeof(struct dtb_node))) == NULL)
{
fdt_exec_status = FDT_RET_NO_MEMORY;
goto fail;
}
if (paths_buf.ptr == NULL)
{
paths_buf.ptr = (char *)malloc(FDT_DTB_ALL_NODES_PATH_SIZE);
if (paths_buf.ptr == NULL)
{
fdt_exec_status = FDT_RET_NO_MEMORY;
goto fail;
}
paths_buf.cur = (char *)paths_buf.ptr;
paths_buf.end = (char *)(paths_buf.ptr + FDT_DTB_ALL_NODES_PATH_SIZE);
}
root_off = fdt_path_offset(fdt, "/");
if ((dtb_node_head->header = (struct dtb_header *)malloc(sizeof(struct dtb_header))) == NULL)
{
fdt_exec_status = FDT_RET_NO_MEMORY;
goto fail;
}
else
{
((struct dtb_header *)dtb_node_head->header)->root = '/';
((struct dtb_header *)dtb_node_head->header)->zero = '\0';
((struct dtb_header *)dtb_node_head->header)->memreserve_sz = fdt_num_mem_rsv(fdt);
if (dtb_node_head->header->memreserve_sz > 0)
{
int i;
int memreserve_sz = dtb_node_head->header->memreserve_sz;
uint32_t off_mem_rsvmap = fdt_off_mem_rsvmap(fdt);
struct fdt_reserve_entry *rsvmap = (struct fdt_reserve_entry *)((char *)fdt + off_mem_rsvmap);
((struct dtb_header *)dtb_node_head->header)->memreserve = (struct dtb_memreserve *)malloc(sizeof(struct dtb_memreserve) * memreserve_sz);
if (dtb_node_head->header->memreserve == NULL)
{
fdt_exec_status = FDT_RET_NO_MEMORY;
goto fail;
}
for (i = 0; i < memreserve_sz; ++i)
{
((struct dtb_header *)dtb_node_head->header)->memreserve[i].address = fdt64_to_cpu(rsvmap[i].address);
((struct dtb_header *)dtb_node_head->header)->memreserve[i].size = fdt64_to_cpu(rsvmap[i].size);
}
}
else
{
((struct dtb_header *)dtb_node_head->header)->memreserve = NULL;
}
}
dtb_node_head->path = paths_buf.ptr;
*paths_buf.cur++ = '/';
*paths_buf.cur++ = '\0';
dtb_node_head->parent = NULL;
dtb_node_head->sibling = NULL;
dtb_node_head->handle = fdt_get_phandle(fdt, root_off);
dtb_node_head->properties = (struct dtb_property *)malloc(sizeof(struct dtb_property));
dtb_node_head->child = (struct dtb_node *)malloc(sizeof(struct dtb_node));
if (dtb_node_head->properties == NULL || dtb_node_head->child == NULL)
{
fdt_exec_status = FDT_RET_NO_MEMORY;
goto fail;
}
if ((fdt_exec_status = _dtb_node_get_dtb_properties_list(dtb_node_head->properties, root_off)) != FDT_RET_GET_OK)
{
goto fail;
}
if ((fdt_exec_status = _dtb_node_get_dtb_nodes_list(dtb_node_head, dtb_node_head->child, dtb_node_head->path)) != FDT_RET_GET_OK)
{
goto fail;
}
/* paths_buf.ptr addr save in the dtb_node_head's path */
paths_buf.ptr = NULL;
paths_buf.cur = NULL;
return dtb_node_head;
fail:
if (dtb_node_head != NULL)
{
dtb_node_free_dtb_list(dtb_node_head);
}
return NULL;
}
static void _dtb_node_free_dtb_node(struct dtb_node *dtb_node)
{
struct dtb_node *dtb_node_last;
struct dtb_property *dtb_property;
struct dtb_property *dtb_property_last;
while (dtb_node != NULL)
{
dtb_property = dtb_node->properties;
while (dtb_property != NULL)
{
dtb_property_last = dtb_property;
dtb_property = dtb_property->next;
free(dtb_property_last);
}
_dtb_node_free_dtb_node(dtb_node->child);
dtb_node_last = dtb_node;
dtb_node = dtb_node->sibling;
free(dtb_node_last);
}
}
void dtb_node_free_dtb_list(struct dtb_node *dtb_node_head)
{
if (dtb_node_head == NULL)
{
return;
}
/* only root node can free all path buffer */
if (dtb_node_head->parent == NULL || (dtb_node_head->path != NULL && !strcmp(dtb_node_head->path, "/")))
{
if (dtb_node_head->path != NULL)
{
free((void *)dtb_node_head->path);
}
if (dtb_node_head->header != NULL)
{
if (dtb_node_head->header->memreserve != NULL)
{
free((void *)dtb_node_head->header->memreserve);
}
free((void *)dtb_node_head->header);
}
}
_dtb_node_free_dtb_node(dtb_node_head);
}
static void _dtb_node_printf_depth(int depth)
{
int i = depth;
while (i --> 0)
{
rt_kputs("\t");
}
}
rt_bool_t _dtb_node_test_string_list(const void *value, int size)
{
const char *str = value;
const char *str_start, *str_end;
if (size == 0)
{
return RT_FALSE;
}
/* string end with '\0' */
if (str[size - 1] != '\0')
{
return RT_FALSE;
}
/* get string list end */
str_end = str + size;
while (str < str_end)
{
str_start = str;
/* before string list end, not '\0' and a printable characters */
while (str < str_end && *str && ((unsigned char)*str >= ' ' && (unsigned char)*str <= '~'))
{
++str;
}
/* not zero, or not increased */
if (*str != '\0' || str == str_start)
{
return RT_FALSE;
}
/* next string */
++str;
}
return RT_TRUE;
}
static void _dtb_node_printf_dtb_node_info(struct dtb_node *dtb_node)
{
static int depth = 0;
struct dtb_property *dtb_property;
while (dtb_node != NULL)
{
rt_kputs("\n");
_dtb_node_printf_depth(depth);
rt_kputs(dtb_node->name);
rt_kputs(" {\n");
++depth;
dtb_property = dtb_node->properties;
while (dtb_property != NULL)
{
_dtb_node_printf_depth(depth);
rt_kputs(dtb_property->name);
if (dtb_property->size > 0)
{
int size = dtb_property->size;
char *value = dtb_property->value;
rt_kputs(" = ");
if (_dtb_node_test_string_list(value, size) == RT_TRUE)
{
/* print string list */
char *str = value;
do
{
rt_kprintf("\"%s\"", str);
str += strlen(str) + 1;
rt_kputs(", ");
} while (str < value + size);
rt_kputs("\b\b");
}
else if ((size % 4) == 0)
{
/* print addr and size cell */
int i;
fdt32_t *cell = (fdt32_t *)value;
rt_kputs("<");
for (i = 0, size /= 4; i < size; ++i)
{
rt_kprintf("0x%x ", fdt32_to_cpu(cell[i]));
}
rt_kputs("\b>");
}
else
{
/* print bytes array */
int i;
uint8_t *byte = (uint8_t *)value;
rt_kputs("[");
for (i = 0; i < size; ++i)
{
rt_kprintf("%02x ", *byte++);
}
rt_kputs("\b]");
}
}
rt_kputs(";\n");
dtb_property = dtb_property->next;
}
_dtb_node_printf_dtb_node_info(dtb_node->child);
dtb_node = dtb_node->sibling;
--depth;
_dtb_node_printf_depth(depth);
rt_kputs("};\n");
}
}
void dtb_node_get_dts_dump(struct dtb_node *dtb_node_head)
{
if (dtb_node_head != NULL)
{
int i = dtb_node_head->header->memreserve_sz;
rt_kputs("/dts-v1/;\n");
while (i --> 0)
{
rt_kprintf("\n/memreserve/\t0x%lx 0x%zx;", dtb_node_head->header->memreserve[i].address, dtb_node_head->header->memreserve[i].size);
}
_dtb_node_printf_dtb_node_info(dtb_node_head);
}
}
static void _dtb_node_get_enum_dtb_node(struct dtb_node *dtb_node, void (callback(struct dtb_node *dtb_node)))
{
while (dtb_node != NULL)
{
callback(dtb_node);
_dtb_node_get_enum_dtb_node(dtb_node->child, callback);
dtb_node = dtb_node->sibling;
}
}
void dtb_node_get_enum_dtb_node(struct dtb_node *dtb_node_head, void (callback(struct dtb_node *dtb_node)))
{
if (dtb_node_head == NULL || callback == NULL)
{
return;
}
_dtb_node_get_enum_dtb_node(dtb_node_head, callback);
}
struct dtb_node *dtb_node_get_dtb_node_by_name_DFS(struct dtb_node *dtb_node, const char *nodename)
{
struct dtb_node *dtb_node_child;
while (dtb_node != NULL)
{
if (!strcmp(nodename, dtb_node->name))
{
return dtb_node;
}
dtb_node_child = dtb_node_get_dtb_node_by_name_DFS(dtb_node->child, nodename);
if (dtb_node_child != NULL)
{
return dtb_node_child;
}
dtb_node = dtb_node->sibling;
}
return NULL;
}
struct dtb_node *dtb_node_get_dtb_node_by_name_BFS(struct dtb_node *dtb_node, const char *nodename)
{
if (dtb_node != NULL)
{
struct dtb_node *dtb_node_child, *dtb_node_head = dtb_node;
while (dtb_node != NULL)
{
if (!strcmp(nodename, dtb_node->name))
{
return dtb_node;
}
dtb_node = dtb_node->sibling;
}
dtb_node = dtb_node_head;
while (dtb_node != NULL)
{
dtb_node_child = dtb_node_get_dtb_node_by_name_BFS(dtb_node->child, nodename);
if (dtb_node_child != NULL)
{
return dtb_node_child;
}
dtb_node = dtb_node->sibling;
}
}
return NULL;
}
struct dtb_node *dtb_node_get_dtb_node_by_path(struct dtb_node *dtb_node, const char *pathname)
{
int i = 0;
char *node_name;
char *pathname_clone;
int pathname_sz;
if (pathname == NULL || dtb_node == NULL)
{
return NULL;
}
/* skip '/' */
if (*pathname == '/')
{
++pathname;
}
/* root not have sibling, so skip */
if (dtb_node->parent == NULL || !strcmp(dtb_node->path, "/"))
{
dtb_node = dtb_node->child;
}
pathname_sz = strlen(pathname) + 1;
pathname_clone = (char *)malloc(pathname_sz);
if (pathname_clone == NULL)
{
return NULL;
}
strncpy(pathname_clone, pathname, pathname_sz);
node_name = pathname_clone;
while (pathname_clone[i])
{
if (pathname_clone[i] == '/')
{
/* set an end of name that can used to strcmp */
pathname_clone[i] = '\0';
while (dtb_node != NULL)
{
if (!strcmp(dtb_node->name, node_name))
{
break;
}
dtb_node = dtb_node->sibling;
}
if (dtb_node == NULL)
{
free(pathname_clone);
return NULL;
}
dtb_node = dtb_node->child;
node_name = &pathname_clone[i + 1];
}
++i;
}
/*
* found the end node and it's name:
* (pathname[pathname_sz - 1]) is '\0'
* (&pathname_clone[i] - node_name) is the node_name's length
*/
node_name = &((char *)pathname)[(pathname_sz - 1) - (&pathname_clone[i] - node_name)];
free(pathname_clone);
while (dtb_node != NULL)
{
if (!strcmp(dtb_node->name, node_name))
{
return dtb_node;
}
dtb_node = dtb_node->sibling;
}
return NULL;
}
struct dtb_node *dtb_node_get_dtb_node_by_phandle_DFS(struct dtb_node *dtb_node, phandle handle)
{
struct dtb_node *dtb_node_child;
while (dtb_node != NULL)
{
if (dtb_node->handle == handle)
{
return dtb_node;
}
dtb_node_child = dtb_node_get_dtb_node_by_phandle_DFS(dtb_node->child, handle);
if (dtb_node_child != NULL)
{
return dtb_node_child;
}
dtb_node = dtb_node->sibling;
}
return NULL;
}
struct dtb_node *dtb_node_get_dtb_node_by_phandle_BFS(struct dtb_node *dtb_node, phandle handle)
{
if (dtb_node != NULL)
{
struct dtb_node *dtb_node_child, *dtb_node_head = dtb_node;
while (dtb_node != NULL)
{
if (dtb_node->handle == handle)
{
return dtb_node;
}
dtb_node = dtb_node->sibling;
}
dtb_node = dtb_node_head;
while (dtb_node != NULL)
{
dtb_node_child = dtb_node_get_dtb_node_by_phandle_BFS(dtb_node->child, handle);
if (dtb_node_child != NULL)
{
return dtb_node_child;
}
dtb_node = dtb_node->sibling;
}
}
return NULL;
}
void dtb_node_get_dtb_node_cells(struct dtb_node *dtb_node, int *addr_cells, int *size_cells)
{
if (dtb_node != NULL && addr_cells != NULL && size_cells != NULL)
{
struct dtb_property *dtb_property;
*addr_cells = -1;
*size_cells = -1;
/* if couldn't found, check parent */
while ((dtb_node = dtb_node->parent) != NULL)
{
dtb_property = dtb_node->properties;
while (dtb_property != NULL)
{
if (!strcmp(dtb_property->name, "#address-cells"))
{
*addr_cells = fdt32_to_cpu(*(int *)dtb_property->value);
}
else if (!strcmp(dtb_property->name, "#size-cells"))
{
*size_cells = fdt32_to_cpu(*(int *)dtb_property->value);
}
if (*addr_cells != -1 && *size_cells != -1)
{
return;
}
dtb_property = dtb_property->next;
}
}
if (*addr_cells == -1)
{
*addr_cells = FDT_ROOT_ADDR_CELLS_DEFAULT;
}
if (*size_cells == -1)
{
*size_cells = FDT_ROOT_SIZE_CELLS_DEFAULT;
}
}
}
struct dtb_memreserve *dtb_node_get_dtb_memreserve(struct dtb_node *dtb_node, int *memreserve_size)
{
if (dtb_node != NULL && memreserve_size != NULL)
{
struct dtb_node *dtb_node_root = dtb_node;
while (dtb_node_root != NULL)
{
if (!strcmp(dtb_node_root->path, "/"))
{
break;
}
dtb_node_root = dtb_node_root->parent;
}
if(dtb_node_root == NULL) return NULL;
*memreserve_size = dtb_node_root->header->memreserve_sz;
return dtb_node_root->header->memreserve;
}
return NULL;
}
rt_bool_t dtb_node_get_dtb_node_status(const struct dtb_node *dtb_node)
{
if (dtb_node != NULL)
{
char *status = dtb_node_get_dtb_node_property_value(dtb_node, "status", NULL);
if (status != NULL)
{
return (!strcmp(status, "okay") || !strcmp(status, "ok")) ? RT_TRUE : RT_FALSE;
}
return RT_TRUE;
}
return RT_FALSE;
}
rt_bool_t dtb_node_get_dtb_node_compatible_match(const struct dtb_node *dtb_node, const char *compatibles)
{
if (dtb_node != NULL)
{
if (compatibles != NULL)
{
char *str_ptr;
int prop_sz;
for_each_property_string(dtb_node, "compatible", str_ptr, prop_sz)
{
if (!strcmp(compatibles, str_ptr))
{
return RT_TRUE;
}
}
}
}
return RT_FALSE;
}
char *dtb_node_get_dtb_string_list_value(void *value, int size, int index)
{
int i = 0;
char *str = value;
if (str != NULL)
{
do
{
if (i++ == index)
{
return str;
}
str += strlen(str) + 1;
} while (str < (char *)value + size);
}
return NULL;
}
char *dtb_node_get_dtb_string_list_value_next(void *value, void *end)
{
char *str = value;
if (str != NULL)
{
str += strlen(str) + 1;
if (str < (char *)end)
{
return str;
}
}
return NULL;
}
uint32_t dtb_node_get_dtb_cell_value(void *value)
{
return fdt32_to_cpu(*(fdt32_t *)value);
}
uint8_t dtb_node_get_dtb_byte_value(void *value)
{
return *(uint8_t *)value;
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "dtb_node.h"
static void *dtb_root = NULL;
static struct dtb_node *dtb_node_list = NULL;
void *get_fdt_blob(void)
{
return dtb_root;
}
struct dtb_node *get_dtb_node_head(void)
{
return dtb_node_list;
}
rt_bool_t dtb_node_active(void)
{
return dtb_node_list != NULL;
}
int device_tree_setup(void *mem_addr)
{
if(mem_addr)
{
if ((dtb_root = dtb_node_load_from_memory(mem_addr,1)) != NULL)
{
dtb_node_list = dtb_node_get_dtb_list(dtb_root);
if (dtb_node_list != NULL)
{
return -1;
}
}
return 0;
}
return -1;
}

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "libfdt.h"
#include <stdio.h>
#include <unistd.h>
#include "dtb_node.h"
extern int fdt_exec_status;
rt_bool_t dtb_node_check(void *fdt)
{
return fdt_check_header(fdt) == 0 ? RT_TRUE : RT_FALSE;
}
void *dtb_node_load_from_fs(char *dtb_filename)
{
void *fdt = NULL;
size_t dtb_sz;
int fd = -1;
if (dtb_filename == NULL)
{
fdt_exec_status = FDT_RET_GET_EMPTY;
goto end;
}
fd = open(dtb_filename, O_RDONLY, 0);
if (fd == -1)
{
rt_kprintf("File `%s' not found.\n", dtb_filename);
fdt_exec_status = FDT_RET_GET_EMPTY;
goto end;
}
dtb_sz = lseek(fd, 0, SEEK_END);
if (dtb_sz > 0)
{
if ((fdt = (struct fdt_header *)malloc(sizeof(uint8_t) * dtb_sz)) == NULL)
{
fdt_exec_status = FDT_RET_NO_MEMORY;
goto end;
}
lseek(fd, 0, SEEK_SET);
read(fd, fdt, sizeof(uint8_t) * dtb_sz);
if (dtb_node_check(fdt) == RT_FALSE)
{
free(fdt);
fdt=NULL;
}
}
end:
if (fd != -1)
{
close(fd);
}
return fdt;
}
void *dtb_node_load_from_memory(void *dtb_ptr, rt_bool_t is_clone)
{
void *fdt = NULL;
if (dtb_ptr == NULL)
{
fdt_exec_status = FDT_RET_GET_EMPTY;
goto end;
}
if (dtb_node_check(dtb_ptr) == RT_FALSE)
{
fdt_exec_status = FDT_RET_GET_EMPTY;
fdt = NULL;
goto end;
}
if (is_clone)
{
size_t dtb_sz = fdt_totalsize(dtb_ptr);
if (dtb_sz > 0)
{
if ((fdt = (size_t *)malloc(dtb_sz)) != NULL)
{
memcpy(fdt, dtb_ptr, dtb_sz);
}
else
{
fdt_exec_status = FDT_RET_NO_MEMORY;
}
}
}
else
{
fdt = dtb_ptr;
}
end:
return fdt;
}

View file

@ -0,0 +1,166 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "libfdt.h"
#include "dtb_node.h"
static off_t dtb_node_find_and_add_subnode(void *fdt, char* name)
{
off_t chosen_offset = 0;
chosen_offset = fdt_subnode_offset(fdt, 0, name);
if (chosen_offset == -FDT_ERR_NOTFOUND)
{
chosen_offset = fdt_add_subnode(fdt, 0, name);
}
return chosen_offset;
}
size_t dtb_node_set_linux_cmdline(void *fdt, char *cmdline)
{
off_t chosen_offset;
size_t cmdline_size;
if (cmdline == NULL || fdt == NULL)
{
goto end;
}
chosen_offset = dtb_node_find_and_add_subnode(fdt, "chosen");
cmdline_size = strlen(cmdline);
/* install bootargs */
if (chosen_offset >= 0 || chosen_offset == -FDT_ERR_EXISTS)
{
if (fdt_setprop(fdt, chosen_offset, "bootargs", cmdline, cmdline_size) < 0)
{
fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_DTB_PAD_SIZE);
fdt_setprop(fdt, chosen_offset, "bootargs", cmdline, cmdline_size);
}
}
end:
return fdt_totalsize(fdt);
}
size_t dtb_node_set_linux_initrd(void *fdt, uint64_t initrd_addr, size_t initrd_size)
{
uint64_t addr, size_ptr;
off_t chosen_offset;
int i;
if (fdt == NULL)
{
goto end;
}
chosen_offset = dtb_node_find_and_add_subnode(fdt, "chosen");
/* update the entry */
for (i = fdt_num_mem_rsv(fdt) - 1; i >= 0; --i)
{
fdt_get_mem_rsv(fdt, i, &addr, &size_ptr);
if (addr == initrd_addr)
{
fdt_del_mem_rsv(fdt, i);
break;
}
}
/* add the memory */
if (fdt_add_mem_rsv(fdt, initrd_addr, initrd_size) < 0)
{
/* move the memory */
fdt_open_into(fdt, fdt, fdt_totalsize(fdt) + FDT_DTB_PAD_SIZE);
if (fdt_add_mem_rsv(fdt, initrd_addr, initrd_size) < 0)
{
goto end;
}
}
/* install initrd */
if (chosen_offset >= 0 || chosen_offset == -FDT_ERR_EXISTS)
{
chosen_offset = fdt_path_offset(fdt, "/chosen");
if (IN_64BITS_MODE)
{
fdt_setprop_u64(fdt, chosen_offset, "linux,initrd-start", initrd_addr);
fdt_setprop_u64(fdt, chosen_offset, "linux,initrd-end", initrd_addr + initrd_size);
}
else
{
fdt_setprop_u32(fdt, chosen_offset, "linux,initrd-start", initrd_addr);
fdt_setprop_u32(fdt, chosen_offset, "linux,initrd-end", initrd_addr + initrd_size);
}
}
end:
return fdt_totalsize(fdt);
}
size_t dtb_node_set_dtb_property(void *fdt, char *pathname, char *property_name, uint32_t *cells, size_t cells_size)
{
int node_off;
if (fdt == NULL)
{
goto end;
}
node_off = fdt_path_offset(fdt, pathname);
if (node_off >= 0 && cells_size != 0)
{
fdt_setprop(fdt, node_off, property_name, cells, cells_size);
}
end:
return fdt_totalsize(fdt);
}
size_t dtb_node_add_dtb_memreserve(void *fdt, uint64_t address, uint64_t size)
{
if (fdt == NULL)
{
goto end;
}
fdt_add_mem_rsv(fdt, address, size);
end:
return fdt_totalsize(fdt);
}
size_t dtb_node_del_dtb_memreserve(void *fdt, uint64_t address)
{
int i;
int num_mem_rsvmap;
uint32_t off_mem_rsvmap;
struct fdt_reserve_entry *rsvmap;
if (fdt == NULL)
{
goto end;
}
num_mem_rsvmap = fdt_num_mem_rsv(fdt);
off_mem_rsvmap = fdt_off_mem_rsvmap(fdt);
rsvmap = (struct fdt_reserve_entry *)((char *)fdt + off_mem_rsvmap);
for (i = 0; i < num_mem_rsvmap; ++i)
{
if (address == fdt64_to_cpu(rsvmap[i].address))
{
fdt_del_mem_rsv(fdt, i);
break;
}
}
end:
return fdt_totalsize(fdt);
}

View file

@ -0,0 +1,34 @@
Import('RTT_ROOT')
Import('rtconfig')
from building import *
cwd = GetCurrentDir()
CPPPATH = [cwd, str(Dir('#'))]
src = ['hwcrypto.c']
if (GetDepend(['RT_HWCRYPTO_USING_AES']) or
GetDepend(['RT_HWCRYPTO_USING_DES']) or
GetDepend(['RT_HWCRYPTO_USING_3DES']) or
GetDepend(['RT_HWCRYPTO_USING_RC4'])):
src += ['hw_symmetric.c']
if GetDepend(['RT_HWCRYPTO_USING_GCM']):
src += ['hw_gcm.c']
if (GetDepend(['RT_HWCRYPTO_USING_MD5']) or
GetDepend(['RT_HWCRYPTO_USING_SHA1']) or
GetDepend(['RT_HWCRYPTO_USING_SHA2'])):
src += ['hw_hash.c']
if GetDepend(['RT_HWCRYPTO_USING_RNG']):
src += ['hw_rng.c']
if GetDepend(['RT_HWCRYPTO_USING_CRC']):
src += ['hw_crc.c']
if GetDepend(['RT_HWCRYPTO_USING_BIGNUM']):
src += ['hw_bignum.c']
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_HWCRYPTO'], CPPPATH = CPPPATH)
Return('group')

View file

@ -0,0 +1,318 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-04-25 tyx the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <hw_bignum.h>
static struct rt_hwcrypto_ctx *bignum_default;
rt_inline rt_err_t hwcrypto_bignum_dev_is_init(void)
{
struct rt_hwcrypto_device *dev;
if (bignum_default)
{
return RT_EOK;
}
dev = rt_hwcrypto_dev_default();
if (dev == RT_NULL)
{
return -RT_ERROR;
}
return rt_hwcrypto_bignum_default(dev);
}
/**
* @brief Setting bignum default devices
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_bignum_default(struct rt_hwcrypto_device *device)
{
if (bignum_default)
{
rt_hwcrypto_ctx_destroy(bignum_default);
bignum_default = RT_NULL;
}
if (device == RT_NULL)
{
return RT_EOK;
}
bignum_default = rt_hwcrypto_ctx_create(device, HWCRYPTO_TYPE_BIGNUM, sizeof(struct hwcrypto_bignum));
if (bignum_default == RT_NULL)
{
return -RT_ERROR;
}
return RT_EOK;
}
/**
* @brief Init bignum obj
*
* @param n bignum obj
*/
void rt_hwcrypto_bignum_init(struct hw_bignum_mpi *n)
{
if(n == RT_NULL)
return;
n->sign = 1;
n->total = 0;
n->p = RT_NULL;
}
/**
* @brief free a bignum obj
*
* @param Pointer to bignum obj
*/
void rt_hwcrypto_bignum_free(struct hw_bignum_mpi *n)
{
if (n)
{
rt_memset(n->p, 0xFF, n->total);
rt_free(n->p);
n->sign = 0;
n->total = 0;
n->p = RT_NULL;
}
}
/**
* @brief Get length of bignum as an unsigned binary buffer
*
* @param n bignum obj
*
* @return binary buffer length
*/
int rt_hwcrypto_bignum_get_len(const struct hw_bignum_mpi *n)
{
int tmp_len, total;
if (n == RT_NULL || n->p == RT_NULL)
{
return 0;
}
tmp_len = 0;
total = n->total;
while ((total > 0) && (n->p[total - 1] == 0))
{
tmp_len++;
total--;
}
return n->total - tmp_len;
}
/**
* @brief Export n into unsigned binary data, big endian
*
* @param n bignum obj
* @param buf Buffer for the binary number
* @param len Length of the buffer
*
* @return export bin length
*/
int rt_hwcrypto_bignum_export_bin(struct hw_bignum_mpi *n, rt_uint8_t *buf, int len)
{
int cp_len, i, j;
if (n == RT_NULL || buf == RT_NULL)
{
return 0;
}
rt_memset(buf, 0, len);
cp_len = (int)n->total > len ? len : (int)n->total;
for(i = cp_len, j = 0; i > 0; i--, j++)
{
buf[i - 1] = n->p[j];
}
return cp_len;
}
/**
* @brief Import n from unsigned binary data, big endian
*
* @param n bignum obj
* @param buf Buffer for the binary number
* @param len Length of the buffer
*
* @return import length.
*/
int rt_hwcrypto_bignum_import_bin(struct hw_bignum_mpi *n, rt_uint8_t *buf, int len)
{
int cp_len, i, j;
void *temp_p;
if (n == RT_NULL || buf == RT_NULL)
{
return 0;
}
if ((int)n->total < len)
{
temp_p = rt_malloc(len);
if (temp_p == RT_NULL)
{
return 0;
}
rt_free(n->p);
n->p = temp_p;
n->total = len;
}
n->sign = 1;
rt_memset(n->p, 0, n->total);
cp_len = (int)n->total > len ? len : n->total;
for(i = cp_len, j = 0; i > 0; i--, j++)
{
n->p[j] = buf[i - 1];
}
return cp_len;
}
/**
* @brief x = a + b
*
* @param a bignum obj
* @param b bignum obj
* @param c bignum obj
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_bignum_add(struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b)
{
struct hwcrypto_bignum *bignum_ctx;
if (hwcrypto_bignum_dev_is_init() != RT_EOK)
{
return -RT_ERROR;
}
bignum_ctx = (struct hwcrypto_bignum *)bignum_default;
if (bignum_ctx->ops->add)
{
return bignum_ctx->ops->add(bignum_ctx, x, a, b);
}
return -RT_ERROR;
}
/**
* @brief x = a - b
*
* @param a bignum obj
* @param b bignum obj
* @param c bignum obj
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_bignum_sub(struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b)
{
struct hwcrypto_bignum *bignum_ctx;
if (hwcrypto_bignum_dev_is_init() != RT_EOK)
{
return -RT_ERROR;
}
bignum_ctx = (struct hwcrypto_bignum *)bignum_default;
if (bignum_ctx->ops->sub)
{
return bignum_ctx->ops->sub(bignum_ctx, x, a, b);
}
return -RT_ERROR;
}
/**
* @brief x = a * b
*
* @param a bignum obj
* @param b bignum obj
* @param c bignum obj
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_bignum_mul(struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b)
{
struct hwcrypto_bignum *bignum_ctx;
if (hwcrypto_bignum_dev_is_init() != RT_EOK)
{
return -RT_ERROR;
}
bignum_ctx = (struct hwcrypto_bignum *)bignum_default;
if (bignum_ctx->ops->mul)
{
return bignum_ctx->ops->mul(bignum_ctx, x, a, b);
}
return -RT_ERROR;
}
/**
* @brief x = a * b (mod c)
*
* @param a bignum obj
* @param b bignum obj
* @param c bignum obj
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_bignum_mulmod(struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b,
const struct hw_bignum_mpi *c)
{
struct hwcrypto_bignum *bignum_ctx;
if (hwcrypto_bignum_dev_is_init() != RT_EOK)
{
return -RT_ERROR;
}
bignum_ctx = (struct hwcrypto_bignum *)bignum_default;
if (bignum_ctx->ops->mulmod)
{
return bignum_ctx->ops->mulmod(bignum_ctx, x, a, b, c);
}
return -RT_ERROR;
}
/**
* @brief x = a ^ b (mod c)
*
* @param a bignum obj
* @param b bignum obj
* @param c bignum obj
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_bignum_exptmod(struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b,
const struct hw_bignum_mpi *c)
{
struct hwcrypto_bignum *bignum_ctx;
if (hwcrypto_bignum_dev_is_init() != RT_EOK)
{
return -RT_ERROR;
}
bignum_ctx = (struct hwcrypto_bignum *)bignum_default;
if (bignum_ctx->ops->exptmod)
{
return bignum_ctx->ops->exptmod(bignum_ctx, x, a, b, c);
}
return -RT_ERROR;
}

View file

@ -0,0 +1,186 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-04-25 tyx the first version
*/
#ifndef __HW_BIGNUM_H__
#define __HW_BIGNUM_H__
#include <hwcrypto.h>
#ifdef __cplusplus
extern "C" {
#endif
struct hwcrypto_bignum;
/* bignum obj */
struct hw_bignum_mpi
{
int sign; /**< integer sign. -1 or 1 */
rt_size_t total; /**< total of limbs */
rt_uint8_t *p; /**< pointer to limbs */
};
struct hwcrypto_bignum_ops
{
rt_err_t (*add)(struct hwcrypto_bignum *bignum_ctx,
struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b); /**< x = a + b */
rt_err_t (*sub)(struct hwcrypto_bignum *bignum_ctx,
struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b); /**< x = a - b */
rt_err_t (*mul)(struct hwcrypto_bignum *bignum_ctx,
struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b); /**< x = a * b */
rt_err_t (*mulmod)(struct hwcrypto_bignum *bignum_ctx,
struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b,
const struct hw_bignum_mpi *c); /**< x = a * b (mod c) */
rt_err_t (*exptmod)(struct hwcrypto_bignum *bignum_ctx,
struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b,
const struct hw_bignum_mpi *c); /**< x = a ^ b (mod c) */
};
/**
* @brief bignum context. Hardware driver usage
*/
struct hwcrypto_bignum
{
struct rt_hwcrypto_ctx parent; /**< Inheritance from hardware crypto context */
const struct hwcrypto_bignum_ops *ops; /**< !! Hardware initializes this value when creating context !! */
};
/**
* @brief Setting bignum default devices
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_bignum_default(struct rt_hwcrypto_device *device);
/**
* @brief Init bignum obj
*/
void rt_hwcrypto_bignum_init(struct hw_bignum_mpi *n);
/**
* @brief free a bignum obj
*
* @param Pointer to bignum obj
*/
void rt_hwcrypto_bignum_free(struct hw_bignum_mpi *n);
/**
* @brief Get length of bignum as an unsigned binary buffer
*
* @param n bignum obj
*
* @return binary buffer Length
*/
int rt_hwcrypto_bignum_get_len(const struct hw_bignum_mpi *n);
/**
* @brief Export n into unsigned binary data, big endian
*
* @param n bignum obj
* @param buf Buffer for the binary number
* @param len Length of the buffer
*
* @return export bin length
*/
int rt_hwcrypto_bignum_export_bin(struct hw_bignum_mpi *n, rt_uint8_t *buf, int len);
/**
* @brief Import n from unsigned binary data, big endian
*
* @param n bignum obj
* @param buf Buffer for the binary number
* @param len Length of the buffer
*
* @return import length.
*/
int rt_hwcrypto_bignum_import_bin(struct hw_bignum_mpi *n, rt_uint8_t *buf, int len);
/**
* @brief x = a + b
*
* @param a bignum obj
* @param b bignum obj
* @param c bignum obj
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_bignum_add(struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b);
/**
* @brief x = a - b
*
* @param a bignum obj
* @param b bignum obj
* @param c bignum obj
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_bignum_sub(struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b);
/**
* @brief x = a * b
*
* @param a bignum obj
* @param b bignum obj
* @param c bignum obj
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_bignum_mul(struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b);
/**
* @brief x = a * b (mod c)
*
* @param a bignum obj
* @param b bignum obj
* @param c bignum obj
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_bignum_mulmod(struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b,
const struct hw_bignum_mpi *c);
/**
* @brief x = a ^ b (mod c)
*
* @param a bignum obj
* @param b bignum obj
* @param c bignum obj
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_bignum_exptmod(struct hw_bignum_mpi *x,
const struct hw_bignum_mpi *a,
const struct hw_bignum_mpi *b,
const struct hw_bignum_mpi *c);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-04-25 tyx the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <hw_crc.h>
/**
* @brief Creating CRC Context
*
* @param device Hardware crypto device
* @param mode Setting default mode or custom mode
*
* @return CRC context
*/
struct rt_hwcrypto_ctx *rt_hwcrypto_crc_create(struct rt_hwcrypto_device *device,
hwcrypto_crc_mode mode)
{
struct hwcrypto_crc *crc_ctx;
crc_ctx = (struct hwcrypto_crc *)rt_hwcrypto_ctx_create(device, HWCRYPTO_TYPE_CRC, sizeof(struct hwcrypto_crc));
if (crc_ctx == RT_NULL)
{
return RT_NULL;
}
switch (mode)
{
case HWCRYPTO_CRC_CRC8:
{
struct hwcrypto_crc_cfg temp = HWCRYPTO_CRC8_CFG;
crc_ctx->crc_cfg = temp;
break;
}
case HWCRYPTO_CRC_CRC16:
{
struct hwcrypto_crc_cfg temp = HWCRYPTO_CRC16_CFG;
crc_ctx->crc_cfg = temp;
break;
}
case HWCRYPTO_CRC_CRC32:
{
struct hwcrypto_crc_cfg temp = HWCRYPTO_CRC32_CFG;
crc_ctx->crc_cfg = temp;
break;
}
case HWCRYPTO_CRC_CCITT:
{
struct hwcrypto_crc_cfg temp = HWCRYPTO_CRC_CCITT_CFG;
crc_ctx->crc_cfg = temp;
break;
}
case HWCRYPTO_CRC_DNP:
{
struct hwcrypto_crc_cfg temp = HWCRYPTO_CRC_DNP_CFG;
crc_ctx->crc_cfg = temp;
break;
}
default:
break;
}
return &crc_ctx->parent;
}
/**
* @brief Destroy CRC Context
*
* @param ctx CRC context
*/
void rt_hwcrypto_crc_destroy(struct rt_hwcrypto_ctx *ctx)
{
rt_hwcrypto_ctx_destroy(ctx);
}
/**
* @brief Processing a packet of data
*
* @param ctx CRC context
* @param input Data buffer to be Processed
* @param length Data Buffer length
*
* @return CRC value
*/
rt_uint32_t rt_hwcrypto_crc_update(struct rt_hwcrypto_ctx *ctx,
const rt_uint8_t *input,
rt_size_t length)
{
struct hwcrypto_crc *crc_ctx = (struct hwcrypto_crc *)ctx;
if (ctx && crc_ctx->ops->update)
{
return crc_ctx->ops->update(crc_ctx, input, length);
}
return 0;
}
/**
* @brief CRC context configuration
*
* @param ctx CRC context
* @param cfg CRC config
*/
void rt_hwcrypto_crc_cfg(struct rt_hwcrypto_ctx *ctx,
struct hwcrypto_crc_cfg *cfg)
{
if (cfg)
{
((struct hwcrypto_crc *)ctx)->crc_cfg = *cfg;
}
}

View file

@ -0,0 +1,148 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-04-25 tyx the first version
*/
#ifndef __HW_CRC_H__
#define __HW_CRC_H__
#include <hwcrypto.h>
#define CRC_FLAG_REFIN (0x1 << 0)
#define CRC_FLAG_REFOUT (0x1 << 1)
#define HWCRYPTO_CRC8_CFG \
{ \
.last_val = 0x00, \
.poly = 0x07, \
.width = 8, \
.xorout = 0x00, \
.flags = 0, \
}
#define HWCRYPTO_CRC16_CFG \
{ \
.last_val = 0x0000, \
.poly = 0x8005, \
.width = 16, \
.xorout = 0x0000, \
.flags = 0, \
}
#define HWCRYPTO_CRC32_CFG \
{ \
.last_val = 0x00000000, \
.poly = 0x04C11DB7, \
.width = 32, \
.xorout = 0x00000000, \
.flags = 0, \
}
#define HWCRYPTO_CRC_CCITT_CFG \
{ \
.last_val = 0x0000, \
.poly = 0x1021, \
.width = 16, \
.xorout = 0x0000, \
.flags = CRC_FLAG_REFIN | CRC_FLAG_REFOUT, \
}
#define HWCRYPTO_CRC_DNP_CFG \
{ \
.last_val = 0x0000, \
.poly = 0x3D65, \
.width = 16, \
.xorout = 0xffff, \
.flags = CRC_FLAG_REFIN | CRC_FLAG_REFOUT, \
}
#ifdef __cplusplus
extern "C" {
#endif
struct hwcrypto_crc;
typedef enum
{
HWCRYPTO_CRC_CUSTOM, /**< Custom CRC mode */
HWCRYPTO_CRC_CRC8, /**< poly : 0x07 */
HWCRYPTO_CRC_CRC16, /**< poly : 0x8005 */
HWCRYPTO_CRC_CRC32, /**< poly : 0x04C11DB7 */
HWCRYPTO_CRC_CCITT, /**< poly : 0x1021 */
HWCRYPTO_CRC_DNP, /**< poly : 0x3D65 */
} hwcrypto_crc_mode;
struct hwcrypto_crc_cfg
{
rt_uint32_t last_val; /**< Last CRC value cache */
rt_uint32_t poly; /**< CRC polynomial */
rt_uint16_t width; /**< CRC value width */
rt_uint32_t xorout; /**< Result XOR Value */
rt_uint16_t flags; /**< Input or output data reverse. CRC_FLAG_REFIN or CRC_FLAG_REFOUT */
};
struct hwcrypto_crc_ops
{
rt_uint32_t (*update)(struct hwcrypto_crc *ctx,
const rt_uint8_t *in, rt_size_t length); /**< Perform a CRC calculation. return CRC value */
};
/**
* @brief CRC context. Hardware driver usage
*/
struct hwcrypto_crc
{
struct rt_hwcrypto_ctx parent; /**< Inherited from the standard device */
struct hwcrypto_crc_cfg crc_cfg; /**< CRC configure */
const struct hwcrypto_crc_ops *ops; /**< !! Hardware initializes this value when creating context !! */
};
/**
* @brief Creating CRC Context
*
* @param device Hardware crypto device
* @param mode Setting default mode or custom mode
*
* @return CRC context
*/
struct rt_hwcrypto_ctx *rt_hwcrypto_crc_create(struct rt_hwcrypto_device *device,
hwcrypto_crc_mode mode);
/**
* @brief Destroy CRC Context
*
* @param ctx CRC context
*/
void rt_hwcrypto_crc_destroy(struct rt_hwcrypto_ctx *ctx);
/**
* @brief Processing a packet of data
*
* @param ctx CRC context
* @param input Data buffer to be Processed
* @param length Data Buffer length
*
* @return CRC value
*/
rt_uint32_t rt_hwcrypto_crc_update(struct rt_hwcrypto_ctx *ctx,
const rt_uint8_t *input, rt_size_t length);
/**
* @brief CRC context configuration
*
* @param ctx CRC context
* @param cfg CRC config
*/
void rt_hwcrypto_crc_cfg(struct rt_hwcrypto_ctx *ctx,
struct hwcrypto_crc_cfg *cfg);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,218 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-05-14 tyx the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <hw_gcm.h>
/**
* @brief Creating GCM Context
*
* @param device Hardware crypto device
* @param type Type of symmetric crypto context
*
* @return GCM context
*/
struct rt_hwcrypto_ctx *rt_hwcrypto_gcm_create(struct rt_hwcrypto_device *device,
hwcrypto_type crypt_type)
{
struct rt_hwcrypto_ctx *ctx;
ctx = rt_hwcrypto_ctx_create(device, HWCRYPTO_TYPE_GCM, sizeof(struct hwcrypto_gcm));
if (ctx)
{
((struct hwcrypto_gcm *)ctx)->crypt_type = crypt_type;
}
return ctx;
}
/**
* @brief Destroy GCM Context
*
* @param ctx GCM context
*/
void rt_hwcrypto_gcm_destroy(struct rt_hwcrypto_ctx *ctx)
{
rt_hwcrypto_ctx_destroy(ctx);
}
/**
* @brief This function starts a GCM encryption or decryption operation
*
* @param ctx GCM context
* @param add The buffer holding the additional data
* @param add_len The length of the additional data
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_gcm_start(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *add,
rt_size_t add_len)
{
struct hwcrypto_gcm *gcm_ctx = (struct hwcrypto_gcm *)ctx;
if (gcm_ctx && gcm_ctx->ops->start)
{
return gcm_ctx->ops->start(gcm_ctx, add, add_len);
}
return -RT_EINVAL;
}
/**
* @brief This function finishes the GCM operation and generates the authentication tag
*
* @param ctx GCM context
* @param tag The buffer for holding the tag
* @param tag_len The length of the tag to generate
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_gcm_finish(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *tag,
rt_size_t tag_len)
{
struct hwcrypto_gcm *gcm_ctx = (struct hwcrypto_gcm *)ctx;
if (gcm_ctx && gcm_ctx->ops->finish)
{
return gcm_ctx->ops->finish(gcm_ctx, tag, tag_len);
}
return -RT_EINVAL;
}
/**
* @brief This function performs a symmetric encryption or decryption operation
*
* @param ctx GCM context
* @param mode Operation mode. HWCRYPTO_MODE_ENCRYPT or HWCRYPTO_MODE_DECRYPT
* @param length The length of the input data in Bytes. This must be a multiple of the block size
* @param in The buffer holding the input data
* @param out The buffer holding the output data
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_gcm_crypt(struct rt_hwcrypto_ctx *ctx, hwcrypto_mode mode,
rt_size_t length, const rt_uint8_t *in, rt_uint8_t *out)
{
return rt_hwcrypto_symmetric_crypt(ctx, mode, length, in, out);
}
/**
* @brief Set Symmetric Encryption and Decryption Key
*
* @param ctx GCM context
* @param key The crypto key
* @param bitlen The crypto key bit length
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_gcm_setkey(struct rt_hwcrypto_ctx *ctx,
const rt_uint8_t *key, rt_uint32_t bitlen)
{
return rt_hwcrypto_symmetric_setkey(ctx, key, bitlen);
}
/**
* @brief Get Symmetric Encryption and Decryption Key
*
* @param ctx GCM context
* @param key The crypto key buffer
* @param bitlen The crypto key bit length
*
* @return Key length of copy
*/
rt_err_t rt_hwcrypto_gcm_getkey(struct rt_hwcrypto_ctx *ctx,
rt_uint8_t *key, rt_uint32_t bitlen)
{
return rt_hwcrypto_symmetric_getkey(ctx, key, bitlen);
}
/**
* @brief Set Symmetric Encryption and Decryption initialization vector
*
* @param ctx GCM context
* @param iv The crypto initialization vector
* @param len The crypto initialization vector length
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_gcm_setiv(struct rt_hwcrypto_ctx *ctx,
const rt_uint8_t *iv, rt_size_t len)
{
return rt_hwcrypto_symmetric_setiv(ctx, iv, len);
}
/**
* @brief Get Symmetric Encryption and Decryption initialization vector
*
* @param ctx GCM context
* @param iv The crypto initialization vector buffer
* @param len The crypto initialization vector buffer length
*
* @return IV length of copy
*/
rt_err_t rt_hwcrypto_gcm_getiv(struct rt_hwcrypto_ctx *ctx,
rt_uint8_t *iv, rt_size_t len)
{
return rt_hwcrypto_symmetric_getiv(ctx, iv, len);
}
/**
* @brief Set offset in initialization vector
*
* @param ctx GCM context
* @param iv_off The offset in IV
*/
void rt_hwcrypto_gcm_set_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t iv_off)
{
rt_hwcrypto_symmetric_set_ivoff(ctx, iv_off);
}
/**
* @brief Get offset in initialization vector
*
* @param ctx GCM context
* @param iv_off It must point to a valid memory
*/
void rt_hwcrypto_gcm_get_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t *iv_off)
{
rt_hwcrypto_symmetric_get_ivoff(ctx, iv_off);
}
/**
* @brief This function copy GCM context
*
* @param des The destination GCM context
* @param src The GCM context to be copy
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_gcm_cpy(struct rt_hwcrypto_ctx *des,
const struct rt_hwcrypto_ctx *src)
{
struct hwcrypto_gcm *gcm_des = (struct hwcrypto_gcm *)des;
struct hwcrypto_gcm *gcm_src = (struct hwcrypto_gcm *)src;
if (des != RT_NULL && src != RT_NULL)
{
gcm_des->crypt_type = gcm_src->crypt_type;
/* symmetric crypto context copy */
return rt_hwcrypto_symmetric_cpy(des, src);
}
return -RT_EINVAL;
}
/**
* @brief Reset GCM context
*
* @param ctx GCM context
*/
void rt_hwcrypto_gcm_reset(struct rt_hwcrypto_ctx *ctx)
{
rt_hwcrypto_symmetric_reset(ctx);
}

View file

@ -0,0 +1,182 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-05-14 tyx the first version
*/
#ifndef __HW_GCM_H__
#define __HW_GCM_H__
#include "hw_symmetric.h"
#ifdef __cplusplus
extern "C" {
#endif
struct hwcrypto_gcm;
struct hwcrypto_gcm_ops
{
rt_err_t (*start)(struct hwcrypto_gcm *gcm_ctx,
const unsigned char *add, rt_size_t add_len); /**< Set additional data. start GCM operation */
rt_err_t (*finish)(struct hwcrypto_gcm *gcm_ctx,
const unsigned char *tag, rt_size_t tag_len); /**< finish GCM operation. get tag */
};
/**
* @brief GCM context. Hardware driver usage
*/
struct hwcrypto_gcm
{
struct hwcrypto_symmetric parent; /**< Inheritance from hardware symmetric crypto context */
hwcrypto_type crypt_type; /**< symmetric crypto type. eg: AES/DES */
const struct hwcrypto_gcm_ops *ops; /**< !! Hardware initializes this value when creating context !! */
};
/**
* @brief Creating GCM Context
*
* @param device Hardware crypto device
* @param type Type of symmetric crypto context
*
* @return GCM context
*/
struct rt_hwcrypto_ctx *rt_hwcrypto_gcm_create(struct rt_hwcrypto_device *device,
hwcrypto_type crypt_type);
/**
* @brief Destroy GCM Context
*
* @param ctx GCM context
*/
void rt_hwcrypto_gcm_destroy(struct rt_hwcrypto_ctx *ctx);
/**
* @brief This function starts a GCM encryption or decryption operation
*
* @param ctx GCM context
* @param add The buffer holding the additional data
* @param add_len The length of the additional data
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_gcm_start(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *add,
rt_size_t add_len);
/**
* @brief This function finishes the GCM operation and generates the authentication tag
*
* @param ctx GCM context
* @param tag The buffer for holding the tag
* @param tag_len The length of the tag to generate
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_gcm_finish(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *tag,
rt_size_t tag_len);
/**
* @brief This function performs a symmetric encryption or decryption operation
*
* @param ctx GCM context
* @param mode Operation mode. HWCRYPTO_MODE_ENCRYPT or HWCRYPTO_MODE_DECRYPT
* @param length The length of the input data in Bytes. This must be a multiple of the block size
* @param in The buffer holding the input data
* @param out The buffer holding the output data
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_gcm_crypt(struct rt_hwcrypto_ctx *ctx, hwcrypto_mode mode,
rt_size_t length, const rt_uint8_t *in, rt_uint8_t *out);
/**
* @brief Set Symmetric Encryption and Decryption Key
*
* @param ctx GCM context
* @param key The crypto key
* @param bitlen The crypto key bit length
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_gcm_setkey(struct rt_hwcrypto_ctx *ctx,
const rt_uint8_t *key, rt_uint32_t bitlen);
/**
* @brief Get Symmetric Encryption and Decryption Key
*
* @param ctx GCM context
* @param key The crypto key buffer
* @param bitlen The crypto key bit length
*
* @return Key length of copy
*/
rt_err_t rt_hwcrypto_gcm_getkey(struct rt_hwcrypto_ctx *ctx,
rt_uint8_t *key, rt_uint32_t bitlen);
/**
* @brief Set Symmetric Encryption and Decryption initialization vector
*
* @param ctx GCM context
* @param iv The crypto initialization vector
* @param len The crypto initialization vector length
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_gcm_setiv(struct rt_hwcrypto_ctx *ctx,
const rt_uint8_t *iv, rt_size_t len);
/**
* @brief Get Symmetric Encryption and Decryption initialization vector
*
* @param ctx GCM context
* @param iv The crypto initialization vector buffer
* @param len The crypto initialization vector buffer length
*
* @return IV length of copy
*/
rt_err_t rt_hwcrypto_gcm_getiv(struct rt_hwcrypto_ctx *ctx,
rt_uint8_t *iv, rt_size_t len);
/**
* @brief Set offset in initialization vector
*
* @param ctx GCM context
* @param iv_off The offset in IV
*/
void rt_hwcrypto_gcm_set_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t iv_off);
/**
* @brief Get offset in initialization vector
*
* @param ctx GCM context
* @param iv_off It must point to a valid memory
*/
void rt_hwcrypto_gcm_get_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t *iv_off);
/**
* @brief This function copy GCM context
*
* @param des The destination GCM context
* @param src The GCM context to be copy
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_gcm_cpy(struct rt_hwcrypto_ctx *des,
const struct rt_hwcrypto_ctx *src);
/**
* @brief Reset GCM context
*
* @param ctx GCM context
*/
void rt_hwcrypto_gcm_reset(struct rt_hwcrypto_ctx *ctx);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-04-23 tyx the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <hw_hash.h>
/**
* @brief Creating hash Context
*
* @param device Hardware crypto device
* @param type Type of hash context
*
* @return Hash context
*/
struct rt_hwcrypto_ctx *rt_hwcrypto_hash_create(struct rt_hwcrypto_device *device, hwcrypto_type type)
{
struct rt_hwcrypto_ctx *ctx;
ctx = rt_hwcrypto_ctx_create(device, type, sizeof(struct hwcrypto_hash));
return ctx;
}
/**
* @brief Destroy hash Context
*
* @param ctx Hash context
*/
void rt_hwcrypto_hash_destroy(struct rt_hwcrypto_ctx *ctx)
{
rt_hwcrypto_ctx_destroy(ctx);
}
/**
* @brief Get the final hash value
*
* @param ctx Hash context
* @param output Hash value buffer
* @param length Hash value buffer length
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_hash_finish(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *output, rt_size_t length)
{
if (ctx && ((struct hwcrypto_hash *)ctx)->ops->finish)
{
return ((struct hwcrypto_hash *)ctx)->ops->finish((struct hwcrypto_hash *)ctx, output, length);
}
return -RT_ERROR;
}
/**
* @brief Processing a packet of data
*
* @param ctx Hash context
* @param input Data buffer to be Processed
* @param length Data Buffer length
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_hash_update(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *input, rt_size_t length)
{
if (ctx && ((struct hwcrypto_hash *)ctx)->ops->update)
{
return ((struct hwcrypto_hash *)ctx)->ops->update((struct hwcrypto_hash *)ctx, input, length);
}
return -RT_ERROR;
}
/**
* @brief This function copy hash context
*
* @param des The destination hash context
* @param src The hash context to be copy
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_hash_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src)
{
return rt_hwcrypto_ctx_cpy(des, src);
}
/**
* @brief Reset hash context
*
* @param ctx Hash context
*/
void rt_hwcrypto_hash_reset(struct rt_hwcrypto_ctx *ctx)
{
rt_hwcrypto_ctx_reset(ctx);
}
/**
* @brief Setting hash context type
*
* @param ctx Hash context
* @param type Types of settings
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_hash_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type)
{
return rt_hwcrypto_set_type(ctx, type);
}

View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-04-23 tyx the first version
*/
#ifndef __HW_HASH_H__
#define __HW_HASH_H__
#include <hwcrypto.h>
#ifdef __cplusplus
extern "C" {
#endif
struct hwcrypto_hash;
struct hwcrypto_hash_ops
{
rt_err_t (*update)(struct hwcrypto_hash *hash_ctx,
const rt_uint8_t *in, rt_size_t length); /**< Processing a packet of data */
rt_err_t (*finish)(struct hwcrypto_hash *hash_ctx,
rt_uint8_t *out, rt_size_t length); /**< Get the final hash value */
};
/**
* @brief hash context. Hardware driver usage
*/
struct hwcrypto_hash
{
struct rt_hwcrypto_ctx parent; /**< Inheritance from hardware crypto context */
const struct hwcrypto_hash_ops *ops; /**< !! Hardware initializes this value when creating context !! */
};
/**
* @brief Creating hash Context
*
* @param device Hardware crypto device
* @param type Type of hash context
*
* @return Hash context
*/
struct rt_hwcrypto_ctx *rt_hwcrypto_hash_create(struct rt_hwcrypto_device *device,
hwcrypto_type type);
/**
* @brief Destroy hash Context
*
* @param ctx Hash context
*/
void rt_hwcrypto_hash_destroy(struct rt_hwcrypto_ctx *ctx);
/**
* @brief Get the final hash value
*
* @param ctx Hash context
* @param output Hash value buffer
* @param length Hash value buffer length
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_hash_finish(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *output, rt_size_t length);
/**
* @brief Processing a packet of data
*
* @param ctx Hash context
* @param input Data buffer to be Processed
* @param length Data Buffer length
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_hash_update(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *input, rt_size_t length);
/**
* @brief This function copy hash context
*
* @param des The destination hash context
* @param src The hash context to be copy
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_hash_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src);
/**
* @brief Reset hash context
*
* @param ctx Hash context
*/
void rt_hwcrypto_hash_reset(struct rt_hwcrypto_ctx *ctx);
/**
* @brief Setting hash context type
*
* @param ctx Hash context
* @param type Types of settings
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_hash_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-04-25 tyx the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <hw_rng.h>
/* Used to save default RNG Context */
static struct rt_hwcrypto_ctx *ctx_default;
/**
* @brief Creating RNG Context
*
* @param device Hardware crypto device
*
* @return RNG context
*/
struct rt_hwcrypto_ctx *rt_hwcrypto_rng_create(struct rt_hwcrypto_device *device)
{
struct rt_hwcrypto_ctx *ctx;
ctx = rt_hwcrypto_ctx_create(device, HWCRYPTO_TYPE_RNG, sizeof(struct hwcrypto_rng));
return ctx;
}
/**
* @brief Destroy RNG Context
*
* @param ctx RNG context
*/
void rt_hwcrypto_rng_destroy(struct rt_hwcrypto_ctx *ctx)
{
/* Destroy the defaule RNG Context ? */
if (ctx == ctx_default)
{
ctx_default = RT_NULL;
}
rt_hwcrypto_ctx_destroy(ctx);
}
/**
* @brief Setting RNG default devices
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_rng_default(struct rt_hwcrypto_device *device)
{
struct rt_hwcrypto_ctx *tmp_ctx;
/* if device is null, destroy default RNG Context */
if (device == RT_NULL)
{
if (ctx_default)
{
rt_hwcrypto_rng_destroy(ctx_default);
ctx_default = RT_NULL;
}
return RT_EOK;
}
/* Try create RNG Context */
tmp_ctx = rt_hwcrypto_rng_create(device);
if (tmp_ctx == RT_NULL)
{
return -RT_ERROR;
}
/* create RNG Context success, update default RNG Context */
rt_hwcrypto_rng_destroy(ctx_default);
ctx_default = tmp_ctx;
return RT_EOK;
}
/**
* @brief Getting Random Numbers from RNG Context
*
* @param ctx RNG context
*
* @return Random number
*/
rt_uint32_t rt_hwcrypto_rng_update_ctx(struct rt_hwcrypto_ctx *ctx)
{
if (ctx)
{
return ((struct hwcrypto_rng *)ctx)->ops->update((struct hwcrypto_rng *)ctx);
}
return 0;
}
/**
* @brief Return a random number
*
* @return Random number
*/
rt_uint32_t rt_hwcrypto_rng_update(void)
{
/* Default device does not exist ? */
if (ctx_default == RT_NULL)
{
/* try create Context from default device */
rt_hwcrypto_rng_default(rt_hwcrypto_dev_default());
}
return rt_hwcrypto_rng_update_ctx(ctx_default);
}

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-04-25 tyx the first version
*/
#ifndef __HW_RNG_H__
#define __HW_RNG_H__
#include <hwcrypto.h>
#ifdef __cplusplus
extern "C" {
#endif
struct hwcrypto_rng;
struct hwcrypto_rng_ops
{
rt_uint32_t (*update)(struct hwcrypto_rng *ctx); /**< Return a random number */
};
/**
* @brief random context. Hardware driver usage
*/
struct hwcrypto_rng
{
struct rt_hwcrypto_ctx parent; /**< Inheritance from hardware crypto context */
const struct hwcrypto_rng_ops *ops; /**< !! Hardware initializes this value when creating context !! */
};
/**
* @brief Creating RNG Context
*
* @param device Hardware crypto device
*
* @return RNG context
*/
struct rt_hwcrypto_ctx *rt_hwcrypto_rng_create(struct rt_hwcrypto_device *device);
/**
* @brief Destroy RNG Context
*
* @param ctx RNG context
*/
void rt_hwcrypto_rng_destroy(struct rt_hwcrypto_ctx *ctx);
/**
* @brief Setting RNG default devices
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_rng_default(struct rt_hwcrypto_device *device);
/**
* @brief Getting Random Numbers from RNG Context
*
* @param ctx RNG context
*
* @return Random number
*/
rt_uint32_t rt_hwcrypto_rng_update_ctx(struct rt_hwcrypto_ctx *ctx);
/**
* @brief Return a random number
*
* @return Random number
*/
rt_uint32_t rt_hwcrypto_rng_update(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,276 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-04-25 tyx the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <hw_symmetric.h>
/**
* @brief Creating Symmetric Encryption and Decryption Context
*
* @param device Hardware crypto device
* @param type Type of symmetric crypto context
*
* @return Symmetric crypto context
*/
struct rt_hwcrypto_ctx *rt_hwcrypto_symmetric_create(struct rt_hwcrypto_device *device, hwcrypto_type type)
{
struct rt_hwcrypto_ctx *ctx;
ctx = rt_hwcrypto_ctx_create(device, type, sizeof(struct hwcrypto_symmetric));
return ctx;
}
/**
* @brief Destroy Symmetric Encryption and Decryption Context
*
* @param ctx Symmetric crypto context
*/
void rt_hwcrypto_symmetric_destroy(struct rt_hwcrypto_ctx *ctx)
{
rt_hwcrypto_ctx_destroy(ctx);
}
/**
* @brief This function performs a symmetric encryption or decryption operation
*
* @param ctx Symmetric crypto context
* @param mode Operation mode. HWCRYPTO_MODE_ENCRYPT or HWCRYPTO_MODE_DECRYPT
* @param length The length of the input data in Bytes. This must be a multiple of the block size
* @param in The buffer holding the input data
* @param out The buffer holding the output data
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_symmetric_crypt(struct rt_hwcrypto_ctx *ctx, hwcrypto_mode mode, rt_size_t length, const rt_uint8_t *in, rt_uint8_t *out)
{
struct hwcrypto_symmetric *symmetric_ctx;
struct hwcrypto_symmetric_info symmetric_info;
rt_err_t err;
if (ctx == RT_NULL)
{
return -RT_EINVAL;
}
symmetric_ctx = (struct hwcrypto_symmetric *)ctx;
if (symmetric_ctx->ops->crypt == RT_NULL)
{
return -RT_ERROR;
}
if (mode != HWCRYPTO_MODE_ENCRYPT && mode != HWCRYPTO_MODE_DECRYPT)
{
return -RT_EINVAL;
}
/* Input information packaging */
symmetric_info.mode = mode;
symmetric_info.in = in;
symmetric_info.out = out;
symmetric_info.length = length;
/* Calling Hardware Encryption and Decryption Function */
err = symmetric_ctx->ops->crypt(symmetric_ctx, &symmetric_info);
/* clean up flags */
symmetric_ctx->flags &= ~(SYMMTRIC_MODIFY_KEY | SYMMTRIC_MODIFY_IV | SYMMTRIC_MODIFY_IVOFF);
return err;
}
/**
* @brief Set Symmetric Encryption and Decryption Key
*
* @param ctx Symmetric crypto context
* @param key The crypto key
* @param bitlen The crypto key bit length
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_symmetric_setkey(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *key, rt_uint32_t bitlen)
{
struct hwcrypto_symmetric *symmetric_ctx;
if (ctx && bitlen <= RT_HWCRYPTO_KEYBIT_MAX_SIZE)
{
symmetric_ctx = (struct hwcrypto_symmetric *)ctx;
rt_memcpy(symmetric_ctx->key, key, bitlen >> 3);
/* Record key length */
symmetric_ctx->key_bitlen = bitlen;
/* Key change flag set up */
symmetric_ctx->flags |= SYMMTRIC_MODIFY_KEY;
return RT_EOK;
}
return -RT_EINVAL;
}
/**
* @brief Get Symmetric Encryption and Decryption Key
*
* @param ctx Symmetric crypto context
* @param key The crypto key buffer
* @param bitlen The crypto key bit length
*
* @return Key length of copy
*/
int rt_hwcrypto_symmetric_getkey(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *key, rt_uint32_t bitlen)
{
struct hwcrypto_symmetric *symmetric_ctx = (struct hwcrypto_symmetric *)ctx;
if (ctx && bitlen >= symmetric_ctx->key_bitlen)
{
rt_memcpy(key, symmetric_ctx->key, symmetric_ctx->key_bitlen >> 3);
return symmetric_ctx->key_bitlen;
}
return 0;
}
/**
* @brief Set Symmetric Encryption and Decryption initialization vector
*
* @param ctx Symmetric crypto context
* @param iv The crypto initialization vector
* @param len The crypto initialization vector length
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_symmetric_setiv(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *iv, rt_size_t len)
{
struct hwcrypto_symmetric *symmetric_ctx;
if (ctx && len <= RT_HWCRYPTO_IV_MAX_SIZE)
{
symmetric_ctx = (struct hwcrypto_symmetric *)ctx;
rt_memcpy(symmetric_ctx->iv, iv, len);
symmetric_ctx->iv_len = len;
/* IV change flag set up */
symmetric_ctx->flags |= SYMMTRIC_MODIFY_IV;
return RT_EOK;
}
return -RT_EINVAL;
}
/**
* @brief Get Symmetric Encryption and Decryption initialization vector
*
* @param ctx Symmetric crypto context
* @param iv The crypto initialization vector buffer
* @param len The crypto initialization vector buffer length
*
* @return IV length of copy
*/
int rt_hwcrypto_symmetric_getiv(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *iv, rt_size_t len)
{
struct hwcrypto_symmetric *symmetric_ctx = (struct hwcrypto_symmetric *)ctx;;
if (ctx && len >= symmetric_ctx->iv_len)
{
rt_memcpy(iv, symmetric_ctx->iv, symmetric_ctx->iv_len);
return symmetric_ctx->iv_len;
}
return 0;
}
/**
* @brief Set offset in initialization vector
*
* @param ctx Symmetric crypto context
* @param iv_off The offset in IV
*/
void rt_hwcrypto_symmetric_set_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t iv_off)
{
if (ctx)
{
((struct hwcrypto_symmetric *)ctx)->iv_off = iv_off;
/* iv_off change flag set up */
((struct hwcrypto_symmetric *)ctx)->flags |= SYMMTRIC_MODIFY_IVOFF;
}
}
/**
* @brief Get offset in initialization vector
*
* @param ctx Symmetric crypto context
* @param iv_off It must point to a valid memory
*/
void rt_hwcrypto_symmetric_get_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t *iv_off)
{
if (ctx && iv_off)
{
*iv_off = ((struct hwcrypto_symmetric *)ctx)->iv_off;
}
}
/**
* @brief This function copy symmetric crypto context
*
* @param des The destination symmetric crypto context
* @param src The symmetric crypto context to be copy
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_symmetric_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src)
{
struct hwcrypto_symmetric *symmetric_des = (struct hwcrypto_symmetric *)des;
struct hwcrypto_symmetric *symmetric_src = (struct hwcrypto_symmetric *)src;
if (des != RT_NULL && src != RT_NULL)
{
/* Copy Symmetric Encryption and Decryption Context Information */
symmetric_des->flags = symmetric_src->flags ;
symmetric_des->iv_len = symmetric_src->iv_len ;
symmetric_des->iv_off = symmetric_src->iv_off ;
symmetric_des->key_bitlen = symmetric_src->key_bitlen;
rt_memcpy(symmetric_des->iv, symmetric_src->iv, symmetric_src->iv_len);
rt_memcpy(symmetric_des->key, symmetric_src->key, symmetric_src->key_bitlen >> 3);
/* Hardware context copy */
return rt_hwcrypto_ctx_cpy(des, src);
}
return -RT_EINVAL;
}
/**
* @brief Reset symmetric crypto context
*
* @param ctx Symmetric crypto context
*/
void rt_hwcrypto_symmetric_reset(struct rt_hwcrypto_ctx *ctx)
{
struct hwcrypto_symmetric *symmetric_ctx = (struct hwcrypto_symmetric *)ctx;
if (ctx != RT_NULL)
{
/* Copy Symmetric Encryption and Decryption Context Information */
symmetric_ctx->flags = 0x00;
symmetric_ctx->iv_len = 0x00;
symmetric_ctx->iv_off = 0x00;
symmetric_ctx->key_bitlen = 0x00;
rt_memset(symmetric_ctx->iv, 0, RT_HWCRYPTO_IV_MAX_SIZE);
rt_memset(symmetric_ctx->key, 0, RT_HWCRYPTO_KEYBIT_MAX_SIZE >> 3);
/* Hardware context reset */
rt_hwcrypto_ctx_reset(ctx);
}
}
/**
* @brief Setting symmetric crypto context type
*
* @param ctx Symmetric crypto context
* @param type Types of settings
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_symmetric_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type)
{
return rt_hwcrypto_set_type(ctx, type);
}

View file

@ -0,0 +1,189 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-04-25 tyx the first version
*/
#ifndef __HW_SYMMETRIC_H__
#define __HW_SYMMETRIC_H__
#include <hwcrypto.h>
#ifndef RT_HWCRYPTO_IV_MAX_SIZE
#define RT_HWCRYPTO_IV_MAX_SIZE (16)
#endif
#ifndef RT_HWCRYPTO_KEYBIT_MAX_SIZE
#define RT_HWCRYPTO_KEYBIT_MAX_SIZE (256)
#endif
#define SYMMTRIC_MODIFY_KEY (0x1 << 0)
#define SYMMTRIC_MODIFY_IV (0x1 << 1)
#define SYMMTRIC_MODIFY_IVOFF (0x1 << 2)
#ifdef __cplusplus
extern "C" {
#endif
struct hwcrypto_symmetric;
struct hwcrypto_symmetric_info;
struct hwcrypto_symmetric_ops
{
rt_err_t (*crypt)(struct hwcrypto_symmetric *symmetric_ctx,
struct hwcrypto_symmetric_info *symmetric_info); /**< Hardware Symmetric Encryption and Decryption Callback */
};
/**
* @brief Hardware driver usage, including input and output information
*/
struct hwcrypto_symmetric_info
{
hwcrypto_mode mode; /**< crypto mode. HWCRYPTO_MODE_ENCRYPT or HWCRYPTO_MODE_DECRYPT */
const rt_uint8_t *in; /**< Input data */
rt_uint8_t *out; /**< Output data will be written */
rt_size_t length; /**< The length of the input data in Bytes. It's a multiple of block size. */
};
/**
* @brief Symmetric crypto context. Hardware driver usage
*/
struct hwcrypto_symmetric
{
struct rt_hwcrypto_ctx parent; /**< Inheritance from hardware crypto context */
rt_uint16_t flags; /**< key or iv or ivoff has been changed. The flag will be set up */
rt_uint16_t iv_len; /**< initialization vector effective length */
rt_uint16_t iv_off; /**< The offset in IV */
rt_uint16_t key_bitlen; /**< The crypto key bit length */
rt_uint8_t iv[RT_HWCRYPTO_IV_MAX_SIZE]; /**< The initialization vector */
rt_uint8_t key[RT_HWCRYPTO_KEYBIT_MAX_SIZE >> 3]; /**< The crypto key */
const struct hwcrypto_symmetric_ops *ops; /**< !! Hardware initializes this value when creating context !! */
};
/**
* @brief Creating Symmetric Encryption and Decryption Context
*
* @param device Hardware crypto device
* @param type Type of symmetric crypto context
*
* @return Symmetric crypto context
*/
struct rt_hwcrypto_ctx *rt_hwcrypto_symmetric_create(struct rt_hwcrypto_device *device,
hwcrypto_type type);
/**
* @brief Destroy Symmetric Encryption and Decryption Context
*
* @param ctx Symmetric crypto context
*/
void rt_hwcrypto_symmetric_destroy(struct rt_hwcrypto_ctx *ctx);
/**
* @brief This function performs a symmetric encryption or decryption operation
*
* @param ctx Symmetric crypto context
* @param mode Operation mode. HWCRYPTO_MODE_ENCRYPT or HWCRYPTO_MODE_DECRYPT
* @param length The length of the input data in Bytes. This must be a multiple of the block size
* @param in The buffer holding the input data
* @param out The buffer holding the output data
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_symmetric_crypt(struct rt_hwcrypto_ctx *ctx, hwcrypto_mode mode,
rt_size_t length, const rt_uint8_t *in, rt_uint8_t *out);
/**
* @brief Set Symmetric Encryption and Decryption Key
*
* @param ctx Symmetric crypto context
* @param key The crypto key
* @param bitlen The crypto key bit length
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_symmetric_setkey(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *key, rt_uint32_t bitlen);
/**
* @brief Get Symmetric Encryption and Decryption Key
*
* @param ctx Symmetric crypto context
* @param key The crypto key buffer
* @param bitlen The crypto key bit length
*
* @return Key length of copy
*/
int rt_hwcrypto_symmetric_getkey(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *key, rt_uint32_t bitlen);
/**
* @brief Set Symmetric Encryption and Decryption initialization vector
*
* @param ctx Symmetric crypto context
* @param iv The crypto initialization vector
* @param len The crypto initialization vector length
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_symmetric_setiv(struct rt_hwcrypto_ctx *ctx, const rt_uint8_t *iv, rt_size_t len);
/**
* @brief Get Symmetric Encryption and Decryption initialization vector
*
* @param ctx Symmetric crypto context
* @param iv The crypto initialization vector buffer
* @param len The crypto initialization vector buffer length
*
* @return IV length of copy
*/
int rt_hwcrypto_symmetric_getiv(struct rt_hwcrypto_ctx *ctx, rt_uint8_t *iv, rt_size_t len);
/**
* @brief Set offset in initialization vector
*
* @param ctx Symmetric crypto context
* @param iv_off The offset in IV
*/
void rt_hwcrypto_symmetric_set_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t iv_off);
/**
* @brief Get offset in initialization vector
*
* @param ctx Symmetric crypto context
* @param iv_off It must point to a valid memory
*/
void rt_hwcrypto_symmetric_get_ivoff(struct rt_hwcrypto_ctx *ctx, rt_int32_t *iv_off);
/**
* @brief This function copy symmetric crypto context
*
* @param des The destination symmetric crypto context
* @param src The symmetric crypto context to be copy
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_symmetric_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src);
/**
* @brief Reset symmetric crypto context
*
* @param ctx Symmetric crypto context
*/
void rt_hwcrypto_symmetric_reset(struct rt_hwcrypto_ctx *ctx);
/**
* @brief Setting symmetric crypto context type
*
* @param ctx Symmetric crypto context
* @param type Types of settings
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_symmetric_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,255 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-04-23 tyx the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <hwcrypto.h>
/**
* @brief Setting context type (Direct calls are not recommended)
*
* @param ctx Crypto context
* @param type Types of settings
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type)
{
if (ctx)
{
/* Is it the same category? */
if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == (type & HWCRYPTO_MAIN_TYPE_MASK))
{
ctx->type = type;
return RT_EOK;
}
/* Context is empty type */
else if (ctx->type == HWCRYPTO_TYPE_NULL)
{
ctx->type = type;
return RT_EOK;
}
else
{
return -RT_ERROR;
}
}
return -RT_EINVAL;
}
/**
* @brief Reset context type (Direct calls are not recommended)
*
* @param ctx Crypto context
*
*/
void rt_hwcrypto_ctx_reset(struct rt_hwcrypto_ctx *ctx)
{
if (ctx && ctx->device->ops->reset)
{
ctx->device->ops->reset(ctx);
}
}
/**
* @brief Init crypto context
*
* @param ctx The context to initialize
* @param device Hardware crypto device
* @param type Type of context
* @param obj_size Size of context object
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_ctx_init(struct rt_hwcrypto_ctx *ctx, struct rt_hwcrypto_device *device, hwcrypto_type type)
{
rt_err_t err;
/* Setting context type */
rt_hwcrypto_set_type(ctx, type);
ctx->device = device;
/* Create hardware context */
err = ctx->device->ops->create(ctx);
if (err != RT_EOK)
{
return err;
}
return RT_EOK;
}
/**
* @brief Create crypto context
*
* @param device Hardware crypto device
* @param type Type of context
* @param obj_size Size of context object
*
* @return Crypto context
*/
struct rt_hwcrypto_ctx *rt_hwcrypto_ctx_create(struct rt_hwcrypto_device *device, hwcrypto_type type, rt_uint32_t obj_size)
{
struct rt_hwcrypto_ctx *ctx;
rt_err_t err;
/* Parameter checking */
if (device == RT_NULL || obj_size < sizeof(struct rt_hwcrypto_ctx))
{
return RT_NULL;
}
ctx = rt_malloc(obj_size);
if (ctx == RT_NULL)
{
return ctx;
}
rt_memset(ctx, 0, obj_size);
/* Init context */
err = rt_hwcrypto_ctx_init(ctx, device, type);
if (err != RT_EOK)
{
rt_free(ctx);
ctx = RT_NULL;
}
return ctx;
}
/**
* @brief Destroy crypto context
*
* @param device Crypto context
*/
void rt_hwcrypto_ctx_destroy(struct rt_hwcrypto_ctx *ctx)
{
if (ctx == RT_NULL)
{
return;
}
/* Destroy hardware context */
if (ctx->device->ops->destroy)
{
ctx->device->ops->destroy(ctx);
}
/* Free the resources */
rt_free(ctx);
}
/**
* @brief Copy crypto context
*
* @param des The destination context
* @param src The context to be copy
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_ctx_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src)
{
if (des == RT_NULL || src == RT_NULL)
{
return -RT_EINVAL;
}
/* The equipment is different or of different types and cannot be copied */
if (des->device != src->device ||
(des->type & HWCRYPTO_MAIN_TYPE_MASK) != (src->type & HWCRYPTO_MAIN_TYPE_MASK))
{
return -RT_EINVAL;
}
des->type = src->type;
/* Calling Hardware Context Copy Function */
return src->device->ops->copy(des, src);
}
/**
* @brief Get the default hardware crypto device
*
* @return Hardware crypto device
*
*/
struct rt_hwcrypto_device *rt_hwcrypto_dev_default(void)
{
static struct rt_hwcrypto_device *hwcrypto_dev;
/* If there is a default device, return the device */
if (hwcrypto_dev)
{
return hwcrypto_dev;
}
/* Find by default device name */
hwcrypto_dev = (struct rt_hwcrypto_device *)rt_device_find(RT_HWCRYPTO_DEFAULT_NAME);
return hwcrypto_dev;
}
/**
* @brief Get the unique ID of the device
*
* @param device Device object
*
* @return Device unique ID
*/
rt_uint64_t rt_hwcrypto_id(struct rt_hwcrypto_device *device)
{
if (device)
{
return device->id;
}
return 0;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops hwcrypto_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL
};
#endif
/**
* @brief Register hardware crypto device
*
* @param device Hardware crypto device
* @param name Name of device
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_register(struct rt_hwcrypto_device *device, const char *name)
{
rt_err_t err;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(name != RT_NULL);
RT_ASSERT(device->ops != RT_NULL);
RT_ASSERT(device->ops->create != RT_NULL);
RT_ASSERT(device->ops->destroy != RT_NULL);
RT_ASSERT(device->ops->copy != RT_NULL);
RT_ASSERT(device->ops->reset != RT_NULL);
rt_memset(&device->parent, 0, sizeof(struct rt_device));
#ifdef RT_USING_DEVICE_OPS
device->parent.ops = &hwcrypto_ops;
#else
device->parent.init = RT_NULL;
device->parent.open = RT_NULL;
device->parent.close = RT_NULL;
device->parent.read = RT_NULL;
device->parent.write = RT_NULL;
device->parent.control = RT_NULL;
#endif
device->parent.user_data = RT_NULL;
device->parent.type = RT_Device_Class_Security;
/* Register device */
err = rt_device_register(&device->parent, name, RT_DEVICE_FLAG_RDWR);
return err;
}

View file

@ -0,0 +1,193 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-04-23 tyx the first version
*/
#ifndef __HWCRYPTO_H__
#define __HWCRYPTO_H__
#include <rtthread.h>
#ifndef RT_HWCRYPTO_DEFAULT_NAME
#define RT_HWCRYPTO_DEFAULT_NAME ("hwcryto")
#endif
#define HWCRYPTO_MAIN_TYPE_MASK (0xffffUL << 16)
#define HWCRYPTO_SUB_TYPE_MASK (0xffUL << 8)
#ifdef __cplusplus
extern "C" {
#endif
typedef enum
{
HWCRYPTO_TYPE_NULL = 0x00000000,
/* Main Type */
/* symmetric Type */
HWCRYPTO_TYPE_HEAD = __LINE__,
HWCRYPTO_TYPE_AES = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< AES */
HWCRYPTO_TYPE_DES = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< DES */
HWCRYPTO_TYPE_3DES = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< 3DES */
HWCRYPTO_TYPE_RC4 = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< RC4 */
HWCRYPTO_TYPE_GCM = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< GCM */
/* HASH Type */
HWCRYPTO_TYPE_MD5 = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< MD5 */
HWCRYPTO_TYPE_SHA1 = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< SHA1 */
HWCRYPTO_TYPE_SHA2 = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< SHA2 */
/* Other Type */
HWCRYPTO_TYPE_RNG = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< RNG */
HWCRYPTO_TYPE_CRC = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< CRC */
HWCRYPTO_TYPE_BIGNUM = ((__LINE__ - HWCRYPTO_TYPE_HEAD) & 0xffff) << 16, /**< BIGNUM */
/* AES Subtype */
HWCRYPTO_TYPE_AES_ECB = HWCRYPTO_TYPE_AES | (0x01 << 8),
HWCRYPTO_TYPE_AES_CBC = HWCRYPTO_TYPE_AES | (0x02 << 8),
HWCRYPTO_TYPE_AES_CFB = HWCRYPTO_TYPE_AES | (0x03 << 8),
HWCRYPTO_TYPE_AES_CTR = HWCRYPTO_TYPE_AES | (0x04 << 8),
HWCRYPTO_TYPE_AES_OFB = HWCRYPTO_TYPE_AES | (0x05 << 8),
/* DES Subtype */
HWCRYPTO_TYPE_DES_ECB = HWCRYPTO_TYPE_DES | (0x01 << 8),
HWCRYPTO_TYPE_DES_CBC = HWCRYPTO_TYPE_DES | (0x02 << 8),
/* 3DES Subtype */
HWCRYPTO_TYPE_3DES_ECB = HWCRYPTO_TYPE_3DES | (0x01 << 8),
HWCRYPTO_TYPE_3DES_CBC = HWCRYPTO_TYPE_3DES | (0x02 << 8),
/* SHA2 Subtype */
HWCRYPTO_TYPE_SHA224 = HWCRYPTO_TYPE_SHA2 | (0x01 << 8),
HWCRYPTO_TYPE_SHA256 = HWCRYPTO_TYPE_SHA2 | (0x02 << 8),
HWCRYPTO_TYPE_SHA384 = HWCRYPTO_TYPE_SHA2 | (0x03 << 8),
HWCRYPTO_TYPE_SHA512 = HWCRYPTO_TYPE_SHA2 | (0x04 << 8),
} hwcrypto_type;
typedef enum
{
HWCRYPTO_MODE_ENCRYPT = 0x1, /**< Encryption operations */
HWCRYPTO_MODE_DECRYPT = 0x2, /**< Decryption operations */
HWCRYPTO_MODE_UNKNOWN = 0x7fffffff, /**< Unknown */
} hwcrypto_mode;
struct rt_hwcrypto_ctx;
struct rt_hwcrypto_ops
{
rt_err_t (*create)(struct rt_hwcrypto_ctx *ctx); /**< Creating hardware context */
void (*destroy)(struct rt_hwcrypto_ctx *ctx); /**< Delete hardware context */
rt_err_t (*copy)(struct rt_hwcrypto_ctx *des,
const struct rt_hwcrypto_ctx *src); /**< Cpoy hardware context */
void (*reset)(struct rt_hwcrypto_ctx *ctx); /**< Reset hardware context */
};
struct rt_hwcrypto_device
{
struct rt_device parent; /**< Inherited from the standard device */
const struct rt_hwcrypto_ops *ops; /**< Hardware crypto ops */
rt_uint64_t id; /**< Unique id */
void *user_data; /**< Device user data */
};
struct rt_hwcrypto_ctx
{
struct rt_hwcrypto_device *device; /**< Binding device */
hwcrypto_type type; /**< Encryption and decryption types */
void *contex; /**< Hardware context */
};
/**
* @brief Setting context type (Direct calls are not recommended)
*
* @param ctx Crypto context
* @param type Types of settings
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_set_type(struct rt_hwcrypto_ctx *ctx, hwcrypto_type type);
/**
* @brief Reset context type (Direct calls are not recommended)
*
* @param ctx Crypto context
*/
void rt_hwcrypto_ctx_reset(struct rt_hwcrypto_ctx *ctx);
/**
* @brief Init crypto context (Direct calls are not recommended)
*
* @param ctx The context to initialize
* @param device Hardware crypto device
* @param type Type of context
* @param obj_size Size of context object
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_ctx_init(struct rt_hwcrypto_ctx *ctx,
struct rt_hwcrypto_device *device, hwcrypto_type type);
/**
* @brief Create crypto context (Direct calls are not recommended)
*
* @param device Hardware crypto device
* @param type Type of context
* @param obj_size Size of context object
*
* @return Crypto context
*/
struct rt_hwcrypto_ctx *rt_hwcrypto_ctx_create(struct rt_hwcrypto_device *device,
hwcrypto_type type, rt_uint32_t obj_size);
/**
* @brief Destroy crypto context (Direct calls are not recommended)
*
* @param device Crypto context
*/
void rt_hwcrypto_ctx_destroy(struct rt_hwcrypto_ctx *ctx);
/**
* @brief Copy crypto context (Direct calls are not recommended)
*
* @param des The destination context
* @param src The context to be copy
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_ctx_cpy(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src);
/**
* @brief Register hardware crypto device
*
* @param device Hardware crypto device
* @param name Name of device
*
* @return RT_EOK on success.
*/
rt_err_t rt_hwcrypto_register(struct rt_hwcrypto_device *device, const char *name);
/**
* @brief Get the default hardware crypto device
*
* @return Hardware crypto device
*
*/
struct rt_hwcrypto_device *rt_hwcrypto_dev_default(void);
/**
* @brief Get the unique ID of the device
*
* @param device Device object
*
* @return Device unique ID
*/
rt_uint64_t rt_hwcrypto_id(struct rt_hwcrypto_device *device);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,8 @@
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd + '/../include']
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_HWTIMER'], CPPPATH = CPPPATH)
Return('group')

View file

@ -0,0 +1,388 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2015-08-31 heyuanjie87 first version
*/
#include <rtdevice.h>
#include <rthw.h>
#define DBG_TAG "hwtimer"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
rt_inline rt_uint32_t timeout_calc(rt_hwtimer_t *timer, rt_hwtimerval_t *tv)
{
float overflow;
float timeout;
rt_uint32_t counter;
int i, index = 0;
float tv_sec;
float devi_min = 1;
float devi;
/* changed to second */
overflow = timer->info->maxcnt/(float)timer->freq;
tv_sec = tv->sec + tv->usec/(float)1000000;
if (tv_sec < (1/(float)timer->freq))
{
/* little timeout */
i = 0;
timeout = 1/(float)timer->freq;
}
else
{
for (i = 1; i > 0; i ++)
{
timeout = tv_sec/i;
if (timeout <= overflow)
{
counter = (rt_uint32_t)(timeout * timer->freq);
devi = tv_sec - (counter / (float)timer->freq) * i;
/* Minimum calculation error */
if (devi > devi_min)
{
i = index;
timeout = tv_sec/i;
break;
}
else if (devi == 0)
{
break;
}
else if (devi < devi_min)
{
devi_min = devi;
index = i;
}
}
}
}
timer->cycles = i;
timer->reload = i;
timer->period_sec = timeout;
counter = (rt_uint32_t)(timeout * timer->freq);
return counter;
}
static rt_err_t rt_hwtimer_init(struct rt_device *dev)
{
rt_err_t result = RT_EOK;
rt_hwtimer_t *timer;
timer = (rt_hwtimer_t *)dev;
/* try to change to 1MHz */
if ((1000000 <= timer->info->maxfreq) && (1000000 >= timer->info->minfreq))
{
timer->freq = 1000000;
}
else
{
timer->freq = timer->info->minfreq;
}
timer->mode = HWTIMER_MODE_ONESHOT;
timer->cycles = 0;
timer->overflow = 0;
if (timer->ops->init)
{
timer->ops->init(timer, 1);
}
else
{
result = -RT_ENOSYS;
}
return result;
}
static rt_err_t rt_hwtimer_open(struct rt_device *dev, rt_uint16_t oflag)
{
rt_err_t result = RT_EOK;
rt_hwtimer_t *timer;
timer = (rt_hwtimer_t *)dev;
if (timer->ops->control != RT_NULL)
{
timer->ops->control(timer, HWTIMER_CTRL_FREQ_SET, &timer->freq);
}
else
{
result = -RT_ENOSYS;
}
return result;
}
static rt_err_t rt_hwtimer_close(struct rt_device *dev)
{
rt_err_t result = RT_EOK;
rt_hwtimer_t *timer;
timer = (rt_hwtimer_t*)dev;
if (timer->ops->init != RT_NULL)
{
timer->ops->init(timer, 0);
}
else
{
result = -RT_ENOSYS;
}
dev->flag &= ~RT_DEVICE_FLAG_ACTIVATED;
dev->rx_indicate = RT_NULL;
return result;
}
static rt_ssize_t rt_hwtimer_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
{
rt_hwtimer_t *timer;
rt_hwtimerval_t tv;
rt_uint32_t cnt;
rt_base_t level;
rt_int32_t overflow;
float t;
timer = (rt_hwtimer_t *)dev;
if (timer->ops->count_get == RT_NULL)
return 0;
level = rt_hw_interrupt_disable();
cnt = timer->ops->count_get(timer);
overflow = timer->overflow;
rt_hw_interrupt_enable(level);
if (timer->info->cntmode == HWTIMER_CNTMODE_DW)
{
cnt = (rt_uint32_t)(timer->freq * timer->period_sec) - cnt;
}
t = overflow * timer->period_sec + cnt/(float)timer->freq;
tv.sec = (rt_int32_t)t;
tv.usec = (rt_int32_t)((t - tv.sec) * 1000000);
size = size > sizeof(tv)? sizeof(tv) : size;
rt_memcpy(buffer, &tv, size);
return size;
}
static rt_ssize_t rt_hwtimer_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
rt_base_t level;
rt_uint32_t t;
rt_hwtimer_mode_t opm = HWTIMER_MODE_PERIOD;
rt_hwtimer_t *timer;
timer = (rt_hwtimer_t *)dev;
if ((timer->ops->start == RT_NULL) || (timer->ops->stop == RT_NULL))
return 0;
if (size != sizeof(rt_hwtimerval_t))
return 0;
timer->ops->stop(timer);
level = rt_hw_interrupt_disable();
timer->overflow = 0;
rt_hw_interrupt_enable(level);
t = timeout_calc(timer, (rt_hwtimerval_t*)buffer);
if ((timer->cycles <= 1) && (timer->mode == HWTIMER_MODE_ONESHOT))
{
opm = HWTIMER_MODE_ONESHOT;
}
if (timer->ops->start(timer, t, opm) != RT_EOK)
size = 0;
return size;
}
static rt_err_t rt_hwtimer_control(struct rt_device *dev, int cmd, void *args)
{
rt_base_t level;
rt_err_t result = RT_EOK;
rt_hwtimer_t *timer;
timer = (rt_hwtimer_t *)dev;
switch (cmd)
{
case HWTIMER_CTRL_STOP:
{
if (timer->ops->stop != RT_NULL)
{
timer->ops->stop(timer);
}
else
{
result = -RT_ENOSYS;
}
}
break;
case HWTIMER_CTRL_FREQ_SET:
{
rt_int32_t *f;
if (args == RT_NULL)
{
result = -RT_EEMPTY;
break;
}
f = (rt_int32_t*)args;
if ((*f > timer->info->maxfreq) || (*f < timer->info->minfreq))
{
LOG_W("frequency setting out of range! It will maintain at %d Hz", timer->freq);
result = -RT_EINVAL;
break;
}
if (timer->ops->control != RT_NULL)
{
result = timer->ops->control(timer, cmd, args);
if (result == RT_EOK)
{
level = rt_hw_interrupt_disable();
timer->freq = *f;
rt_hw_interrupt_enable(level);
}
}
else
{
result = -RT_ENOSYS;
}
}
break;
case HWTIMER_CTRL_INFO_GET:
{
if (args == RT_NULL)
{
result = -RT_EEMPTY;
break;
}
*((struct rt_hwtimer_info*)args) = *timer->info;
}
break;
case HWTIMER_CTRL_MODE_SET:
{
rt_hwtimer_mode_t *m;
if (args == RT_NULL)
{
result = -RT_EEMPTY;
break;
}
m = (rt_hwtimer_mode_t*)args;
if ((*m != HWTIMER_MODE_ONESHOT) && (*m != HWTIMER_MODE_PERIOD))
{
result = -RT_ERROR;
break;
}
level = rt_hw_interrupt_disable();
timer->mode = *m;
rt_hw_interrupt_enable(level);
}
break;
default:
{
result = -RT_ENOSYS;
}
break;
}
return result;
}
void rt_device_hwtimer_isr(rt_hwtimer_t *timer)
{
rt_base_t level;
RT_ASSERT(timer != RT_NULL);
level = rt_hw_interrupt_disable();
timer->overflow ++;
if (timer->cycles != 0)
{
timer->cycles --;
}
if (timer->cycles == 0)
{
timer->cycles = timer->reload;
rt_hw_interrupt_enable(level);
if (timer->mode == HWTIMER_MODE_ONESHOT)
{
if (timer->ops->stop != RT_NULL)
{
timer->ops->stop(timer);
}
}
if (timer->parent.rx_indicate != RT_NULL)
{
timer->parent.rx_indicate(&timer->parent, sizeof(struct rt_hwtimerval));
}
}
else
{
rt_hw_interrupt_enable(level);
}
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops hwtimer_ops =
{
rt_hwtimer_init,
rt_hwtimer_open,
rt_hwtimer_close,
rt_hwtimer_read,
rt_hwtimer_write,
rt_hwtimer_control
};
#endif
rt_err_t rt_device_hwtimer_register(rt_hwtimer_t *timer, const char *name, void *user_data)
{
struct rt_device *device;
RT_ASSERT(timer != RT_NULL);
RT_ASSERT(timer->ops != RT_NULL);
RT_ASSERT(timer->info != RT_NULL);
device = &(timer->parent);
device->type = RT_Device_Class_Timer;
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
#ifdef RT_USING_DEVICE_OPS
device->ops = &hwtimer_ops;
#else
device->init = rt_hwtimer_init;
device->open = rt_hwtimer_open;
device->close = rt_hwtimer_close;
device->read = rt_hwtimer_read;
device->write = rt_hwtimer_write;
device->control = rt_hwtimer_control;
#endif
device->user_data = user_data;
return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
}

View file

@ -0,0 +1,18 @@
Import('RTT_ROOT')
from building import *
cwd = GetCurrentDir()
src = Split("""
i2c_core.c
i2c_dev.c
""")
if GetDepend('RT_USING_I2C_BITOPS'):
src = src + ['i2c-bit-ops.c']
# The set of source files associated with this SConscript file.
path = [cwd + '/../include']
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_I2C'], CPPPATH = path)
Return('group')

View file

@ -0,0 +1,458 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-04-25 weety first version
*/
#include <rtdevice.h>
#define DBG_TAG "I2C"
#ifdef RT_I2C_BITOPS_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif
#include <rtdbg.h>
#define SET_SDA(ops, val) ops->set_sda(ops->data, val)
#define SET_SCL(ops, val) ops->set_scl(ops->data, val)
#define GET_SDA(ops) ops->get_sda(ops->data)
#define GET_SCL(ops) ops->get_scl(ops->data)
rt_inline void i2c_delay(struct rt_i2c_bit_ops *ops)
{
ops->udelay((ops->delay_us + 1) >> 1);
}
rt_inline void i2c_delay2(struct rt_i2c_bit_ops *ops)
{
ops->udelay(ops->delay_us);
}
#define SDA_L(ops) SET_SDA(ops, 0)
#define SDA_H(ops) SET_SDA(ops, 1)
#define SCL_L(ops) SET_SCL(ops, 0)
/**
* release scl line, and wait scl line to high.
*/
static rt_err_t SCL_H(struct rt_i2c_bit_ops *ops)
{
rt_tick_t start;
SET_SCL(ops, 1);
if (!ops->get_scl)
goto done;
start = rt_tick_get();
while (!GET_SCL(ops))
{
if ((rt_tick_get() - start) > ops->timeout)
return -RT_ETIMEOUT;
i2c_delay(ops);
}
#ifdef RT_I2C_BITOPS_DEBUG
if (rt_tick_get() != start)
{
LOG_D("wait %ld tick for SCL line to go high",
rt_tick_get() - start);
}
#endif
done:
i2c_delay(ops);
return RT_EOK;
}
static void i2c_start(struct rt_i2c_bit_ops *ops)
{
#ifdef RT_I2C_BITOPS_DEBUG
if (ops->get_scl && !GET_SCL(ops))
{
LOG_E("I2C bus error, SCL line low");
}
if (ops->get_sda && !GET_SDA(ops))
{
LOG_E("I2C bus error, SDA line low");
}
#endif
SDA_L(ops);
i2c_delay(ops);
SCL_L(ops);
}
static void i2c_restart(struct rt_i2c_bit_ops *ops)
{
SDA_H(ops);
SCL_H(ops);
i2c_delay(ops);
SDA_L(ops);
i2c_delay(ops);
SCL_L(ops);
}
static void i2c_stop(struct rt_i2c_bit_ops *ops)
{
SDA_L(ops);
i2c_delay(ops);
SCL_H(ops);
i2c_delay(ops);
SDA_H(ops);
i2c_delay2(ops);
}
rt_inline rt_bool_t i2c_waitack(struct rt_i2c_bit_ops *ops)
{
rt_bool_t ack;
SDA_H(ops);
i2c_delay(ops);
if (SCL_H(ops) < 0)
{
LOG_W("wait ack timeout");
return -RT_ETIMEOUT;
}
ack = !GET_SDA(ops); /* ACK : SDA pin is pulled low */
LOG_D("%s", ack ? "ACK" : "NACK");
SCL_L(ops);
return ack;
}
static rt_int32_t i2c_writeb(struct rt_i2c_bus_device *bus, rt_uint8_t data)
{
rt_int32_t i;
rt_uint8_t bit;
struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
for (i = 7; i >= 0; i--)
{
SCL_L(ops);
bit = (data >> i) & 1;
SET_SDA(ops, bit);
i2c_delay(ops);
if (SCL_H(ops) < 0)
{
LOG_D("i2c_writeb: 0x%02x, "
"wait scl pin high timeout at bit %d",
data, i);
return -RT_ETIMEOUT;
}
}
SCL_L(ops);
i2c_delay(ops);
return i2c_waitack(ops);
}
static rt_int32_t i2c_readb(struct rt_i2c_bus_device *bus)
{
rt_uint8_t i;
rt_uint8_t data = 0;
struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
SDA_H(ops);
i2c_delay(ops);
for (i = 0; i < 8; i++)
{
data <<= 1;
if (SCL_H(ops) < 0)
{
LOG_D("i2c_readb: wait scl pin high "
"timeout at bit %d", 7 - i);
return -RT_ETIMEOUT;
}
if (GET_SDA(ops))
data |= 1;
SCL_L(ops);
i2c_delay2(ops);
}
return data;
}
static rt_ssize_t i2c_send_bytes(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg *msg)
{
rt_int32_t ret;
rt_size_t bytes = 0;
const rt_uint8_t *ptr = msg->buf;
rt_int32_t count = msg->len;
rt_uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
while (count > 0)
{
ret = i2c_writeb(bus, *ptr);
if ((ret > 0) || (ignore_nack && (ret == 0)))
{
count --;
ptr ++;
bytes ++;
}
else if (ret == 0)
{
LOG_D("send bytes: NACK.");
return 0;
}
else
{
LOG_E("send bytes: error %d", ret);
return ret;
}
}
return bytes;
}
static rt_err_t i2c_send_ack_or_nack(struct rt_i2c_bus_device *bus, int ack)
{
struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
if (ack)
SET_SDA(ops, 0);
i2c_delay(ops);
if (SCL_H(ops) < 0)
{
LOG_E("ACK or NACK timeout.");
return -RT_ETIMEOUT;
}
SCL_L(ops);
return RT_EOK;
}
static rt_ssize_t i2c_recv_bytes(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg *msg)
{
rt_int32_t val;
rt_int32_t bytes = 0; /* actual bytes */
rt_uint8_t *ptr = msg->buf;
rt_int32_t count = msg->len;
const rt_uint32_t flags = msg->flags;
while (count > 0)
{
val = i2c_readb(bus);
if (val >= 0)
{
*ptr = val;
bytes ++;
}
else
{
break;
}
ptr ++;
count --;
LOG_D("recieve bytes: 0x%02x, %s",
val, (flags & RT_I2C_NO_READ_ACK) ?
"(No ACK/NACK)" : (count ? "ACK" : "NACK"));
if (!(flags & RT_I2C_NO_READ_ACK))
{
val = i2c_send_ack_or_nack(bus, count);
if (val < 0)
return val;
}
}
return bytes;
}
static rt_int32_t i2c_send_address(struct rt_i2c_bus_device *bus,
rt_uint8_t addr,
rt_int32_t retries)
{
struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
rt_int32_t i;
rt_err_t ret = 0;
for (i = 0; i <= retries; i++)
{
ret = i2c_writeb(bus, addr);
if (ret == 1 || i == retries)
break;
LOG_D("send stop condition");
i2c_stop(ops);
i2c_delay2(ops);
LOG_D("send start condition");
i2c_start(ops);
}
return ret;
}
static rt_err_t i2c_bit_send_address(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg *msg)
{
rt_uint16_t flags = msg->flags;
rt_uint16_t ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
rt_uint8_t addr1, addr2;
rt_int32_t retries;
rt_err_t ret;
retries = ignore_nack ? 0 : bus->retries;
if (flags & RT_I2C_ADDR_10BIT)
{
addr1 = 0xf0 | ((msg->addr >> 7) & 0x06);
addr2 = msg->addr & 0xff;
LOG_D("addr1: %d, addr2: %d", addr1, addr2);
ret = i2c_send_address(bus, addr1, retries);
if ((ret != 1) && !ignore_nack)
{
LOG_W("NACK: sending first addr");
return -RT_EIO;
}
ret = i2c_writeb(bus, addr2);
if ((ret != 1) && !ignore_nack)
{
LOG_W("NACK: sending second addr");
return -RT_EIO;
}
if (flags & RT_I2C_RD)
{
LOG_D("send repeated start condition");
i2c_restart(ops);
addr1 |= 0x01;
ret = i2c_send_address(bus, addr1, retries);
if ((ret != 1) && !ignore_nack)
{
LOG_E("NACK: sending repeated addr");
return -RT_EIO;
}
}
}
else
{
/* 7-bit addr */
addr1 = msg->addr << 1;
if (flags & RT_I2C_RD)
addr1 |= 1;
ret = i2c_send_address(bus, addr1, retries);
if ((ret != 1) && !ignore_nack)
return -RT_EIO;
}
return RT_EOK;
}
static rt_ssize_t i2c_bit_xfer(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num)
{
struct rt_i2c_msg *msg;
struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
rt_int32_t ret;
rt_uint32_t i;
rt_uint16_t ignore_nack;
if (num == 0) return 0;
for (i = 0; i < num; i++)
{
msg = &msgs[i];
ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
if (!(msg->flags & RT_I2C_NO_START))
{
if (i)
{
i2c_restart(ops);
}
else
{
LOG_D("send start condition");
i2c_start(ops);
}
ret = i2c_bit_send_address(bus, msg);
if ((ret != RT_EOK) && !ignore_nack)
{
LOG_D("receive NACK from device addr 0x%02x msg %d",
msgs[i].addr, i);
goto out;
}
}
if (msg->flags & RT_I2C_RD)
{
ret = i2c_recv_bytes(bus, msg);
if (ret >= 1)
{
LOG_D("read %d byte%s", ret, ret == 1 ? "" : "s");
}
if (ret < msg->len)
{
if (ret >= 0)
ret = -RT_EIO;
goto out;
}
}
else
{
ret = i2c_send_bytes(bus, msg);
if (ret >= 1)
{
LOG_D("write %d byte%s", ret, ret == 1 ? "" : "s");
}
if (ret < msg->len)
{
if (ret >= 0)
ret = -RT_ERROR;
goto out;
}
}
}
ret = i;
out:
if (!(msg->flags & RT_I2C_NO_STOP))
{
LOG_D("send stop condition");
i2c_stop(ops);
}
return ret;
}
static const struct rt_i2c_bus_device_ops i2c_bit_bus_ops =
{
i2c_bit_xfer,
RT_NULL,
RT_NULL
};
rt_err_t rt_i2c_bit_add_bus(struct rt_i2c_bus_device *bus,
const char *bus_name)
{
bus->ops = &i2c_bit_bus_ops;
return rt_i2c_bus_device_register(bus, bus_name);
}

View file

@ -0,0 +1,146 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-04-25 weety first version
* 2021-04-20 RiceChen added support for bus control api
*/
#include <rtdevice.h>
#define DBG_TAG "I2C"
#ifdef RT_I2C_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif
#include <rtdbg.h>
rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus,
const char *bus_name)
{
rt_err_t res = RT_EOK;
rt_mutex_init(&bus->lock, "i2c_bus_lock", RT_IPC_FLAG_PRIO);
if (bus->timeout == 0) bus->timeout = RT_TICK_PER_SECOND;
res = rt_i2c_bus_device_device_init(bus, bus_name);
LOG_I("I2C bus [%s] registered", bus_name);
return res;
}
struct rt_i2c_bus_device *rt_i2c_bus_device_find(const char *bus_name)
{
struct rt_i2c_bus_device *bus;
rt_device_t dev = rt_device_find(bus_name);
if (dev == RT_NULL || dev->type != RT_Device_Class_I2CBUS)
{
LOG_E("I2C bus %s not exist", bus_name);
return RT_NULL;
}
bus = (struct rt_i2c_bus_device *)dev->user_data;
return bus;
}
rt_ssize_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num)
{
rt_ssize_t ret;
rt_err_t err;
if (bus->ops->master_xfer)
{
#ifdef RT_I2C_DEBUG
for (ret = 0; ret < num; ret++)
{
LOG_D("msgs[%d] %c, addr=0x%02x, len=%d", ret,
(msgs[ret].flags & RT_I2C_RD) ? 'R' : 'W',
msgs[ret].addr, msgs[ret].len);
}
#endif
err = rt_mutex_take(&bus->lock, RT_WAITING_FOREVER);
if (err != RT_EOK)
{
return (rt_ssize_t)err;
}
ret = bus->ops->master_xfer(bus, msgs, num);
err = rt_mutex_release(&bus->lock);
if (err != RT_EOK)
{
return (rt_ssize_t)err;
}
return ret;
}
else
{
LOG_E("I2C bus operation not supported");
return -RT_EINVAL;
}
}
rt_err_t rt_i2c_control(struct rt_i2c_bus_device *bus,
rt_uint32_t cmd,
rt_uint32_t arg)
{
rt_err_t ret;
if(bus->ops->i2c_bus_control)
{
ret = bus->ops->i2c_bus_control(bus, cmd, arg);
return ret;
}
else
{
LOG_E("I2C bus operation not supported");
return -RT_EINVAL;
}
}
rt_ssize_t rt_i2c_master_send(struct rt_i2c_bus_device *bus,
rt_uint16_t addr,
rt_uint16_t flags,
const rt_uint8_t *buf,
rt_uint32_t count)
{
rt_ssize_t ret;
struct rt_i2c_msg msg;
msg.addr = addr;
msg.flags = flags;
msg.len = count;
msg.buf = (rt_uint8_t *)buf;
ret = rt_i2c_transfer(bus, &msg, 1);
return (ret == 1) ? count : ret;
}
rt_ssize_t rt_i2c_master_recv(struct rt_i2c_bus_device *bus,
rt_uint16_t addr,
rt_uint16_t flags,
rt_uint8_t *buf,
rt_uint32_t count)
{
rt_ssize_t ret;
struct rt_i2c_msg msg;
RT_ASSERT(bus != RT_NULL);
msg.addr = addr;
msg.flags = flags | RT_I2C_RD;
msg.len = count;
msg.buf = buf;
ret = rt_i2c_transfer(bus, &msg, 1);
return (ret == 1) ? count : ret;
}

View file

@ -0,0 +1,146 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-04-25 weety first version
* 2014-08-03 bernard fix some compiling warning
* 2021-04-20 RiceChen added support for bus clock control
*/
#include <rtdevice.h>
#define DBG_TAG "I2C"
#ifdef RT_I2C_DEBUG
#define DBG_LVL DBG_LOG
#else
#define DBG_LVL DBG_INFO
#endif
#include <rtdbg.h>
static rt_ssize_t i2c_bus_device_read(rt_device_t dev,
rt_off_t pos,
void *buffer,
rt_size_t count)
{
rt_uint16_t addr;
rt_uint16_t flags;
struct rt_i2c_bus_device *bus = (struct rt_i2c_bus_device *)dev->user_data;
RT_ASSERT(bus != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
LOG_D("I2C bus dev [%s] reading %u bytes.", dev->parent.name, count);
addr = pos & 0xffff;
flags = (pos >> 16) & 0xffff;
return rt_i2c_master_recv(bus, addr, flags, (rt_uint8_t *)buffer, count);
}
static rt_ssize_t i2c_bus_device_write(rt_device_t dev,
rt_off_t pos,
const void *buffer,
rt_size_t count)
{
rt_uint16_t addr;
rt_uint16_t flags;
struct rt_i2c_bus_device *bus = (struct rt_i2c_bus_device *)dev->user_data;
RT_ASSERT(bus != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
LOG_D("I2C bus dev [%s] writing %u bytes.", dev->parent.name, count);
addr = pos & 0xffff;
flags = (pos >> 16) & 0xffff;
return rt_i2c_master_send(bus, addr, flags, (const rt_uint8_t *)buffer, count);
}
static rt_err_t i2c_bus_device_control(rt_device_t dev,
int cmd,
void *args)
{
rt_err_t ret;
struct rt_i2c_priv_data *priv_data;
struct rt_i2c_bus_device *bus = (struct rt_i2c_bus_device *)dev->user_data;
rt_uint32_t bus_clock;
RT_ASSERT(bus != RT_NULL);
switch (cmd)
{
/* set 10-bit addr mode */
case RT_I2C_DEV_CTRL_10BIT:
bus->flags |= RT_I2C_ADDR_10BIT;
break;
case RT_I2C_DEV_CTRL_TIMEOUT:
bus->timeout = *(rt_uint32_t *)args;
break;
case RT_I2C_DEV_CTRL_RW:
priv_data = (struct rt_i2c_priv_data *)args;
ret = rt_i2c_transfer(bus, priv_data->msgs, priv_data->number);
if (ret < 0)
{
return -RT_EIO;
}
break;
case RT_I2C_DEV_CTRL_CLK:
bus_clock = *(rt_uint32_t *)args;
ret = rt_i2c_control(bus, cmd, bus_clock);
if (ret < 0)
{
return -RT_EIO;
}
break;
default:
break;
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops i2c_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
i2c_bus_device_read,
i2c_bus_device_write,
i2c_bus_device_control
};
#endif
rt_err_t rt_i2c_bus_device_device_init(struct rt_i2c_bus_device *bus,
const char *name)
{
struct rt_device *device;
RT_ASSERT(bus != RT_NULL);
device = &bus->parent;
device->user_data = bus;
/* set device type */
device->type = RT_Device_Class_I2CBUS;
/* initialize device interface */
#ifdef RT_USING_DEVICE_OPS
device->ops = &i2c_ops;
#else
device->init = RT_NULL;
device->open = RT_NULL;
device->close = RT_NULL;
device->read = i2c_bus_device_read;
device->write = i2c_bus_device_write;
device->control = i2c_bus_device_control;
#endif
/* register to device manager */
rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
return RT_EOK;
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-05-07 aozima the first version
* 2018-11-16 Ernest Chen add finsh command and update adc function
* 2022-05-11 Stanley Lwin add finsh voltage conversion command
*/
#ifndef __ADC_H__
#define __ADC_H__
#include <rtthread.h>
#define RT_ADC_INTERN_CH_TEMPER (-1)
#define RT_ADC_INTERN_CH_VREF (-2)
#define RT_ADC_INTERN_CH_VBAT (-3)
struct rt_adc_device;
struct rt_adc_ops
{
rt_err_t (*enabled)(struct rt_adc_device *device, rt_int8_t channel, rt_bool_t enabled);
rt_err_t (*convert)(struct rt_adc_device *device, rt_int8_t channel, rt_uint32_t *value);
rt_uint8_t (*get_resolution)(struct rt_adc_device *device);
rt_int16_t (*get_vref) (struct rt_adc_device *device);
};
struct rt_adc_device
{
struct rt_device parent;
const struct rt_adc_ops *ops;
};
typedef struct rt_adc_device *rt_adc_device_t;
typedef enum
{
RT_ADC_CMD_ENABLE = RT_DEVICE_CTRL_BASE(ADC) + 1,
RT_ADC_CMD_DISABLE = RT_DEVICE_CTRL_BASE(ADC) + 2,
RT_ADC_CMD_GET_RESOLUTION = RT_DEVICE_CTRL_BASE(ADC) + 3, /* get the resolution in bits */
RT_ADC_CMD_GET_VREF = RT_DEVICE_CTRL_BASE(ADC) + 4, /* get reference voltage */
} rt_adc_cmd_t;
rt_err_t rt_hw_adc_register(rt_adc_device_t adc,const char *name, const struct rt_adc_ops *ops, const void *user_data);
rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_int8_t channel);
rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_int8_t channel);
rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_int8_t channel);
rt_int16_t rt_adc_voltage(rt_adc_device_t dev, rt_int8_t channel);
#endif /* __ADC_H__ */

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-10-27 heyuanjie87 first version.
* 2013-05-17 aozima initial alarm event & mutex in system init.
* 2020-10-15 zhangsz add alarm flags hour minute second.
*/
#ifndef __ALARM_H__
#define __ALARM_H__
#include <sys/time.h>
#include <rtdef.h>
#define RT_ALARM_TM_NOW -1 /* set the alarm tm_day,tm_mon,tm_sec,etc.
to now.we also call it "don't care" value */
/* alarm flags */
#define RT_ALARM_ONESHOT 0x000 /* only alarm once */
#define RT_ALARM_DAILY 0x100 /* alarm everyday */
#define RT_ALARM_WEEKLY 0x200 /* alarm weekly at Monday or Friday etc. */
#define RT_ALARM_MONTHLY 0x400 /* alarm monthly at someday */
#define RT_ALARM_YAERLY 0x800 /* alarm yearly at a certain date */
#define RT_ALARM_HOUR 0x1000 /* alarm each hour at a certain min:second */
#define RT_ALARM_MINUTE 0x2000 /* alarm each minute at a certain second */
#define RT_ALARM_SECOND 0x4000 /* alarm each second */
#define RT_ALARM_STATE_INITED 0x02
#define RT_ALARM_STATE_START 0x01
#define RT_ALARM_STATE_STOP 0x00
/* alarm control cmd */
#define RT_ALARM_CTRL_MODIFY 1 /* modify alarm time or alarm flag */
typedef struct rt_alarm *rt_alarm_t;
typedef void (*rt_alarm_callback_t)(rt_alarm_t alarm, time_t timestamp);
struct rt_alarm
{
rt_list_t list;
rt_uint32_t flag;
rt_alarm_callback_t callback;
struct tm wktime;
void *user_data;
};
struct rt_alarm_setup
{
rt_uint32_t flag; /* alarm flag */
struct tm wktime; /* when will the alarm wake up user */
};
struct rt_alarm_container
{
rt_list_t head;
struct rt_mutex mutex;
struct rt_event event;
struct rt_alarm *current;
};
rt_alarm_t rt_alarm_create(rt_alarm_callback_t callback,
struct rt_alarm_setup *setup);
rt_err_t rt_alarm_control(rt_alarm_t alarm, int cmd, void *arg);
void rt_alarm_update(rt_device_t dev, rt_uint32_t event);
rt_err_t rt_alarm_delete(rt_alarm_t alarm);
rt_err_t rt_alarm_start(rt_alarm_t alarm);
rt_err_t rt_alarm_stop(rt_alarm_t alarm);
int rt_alarm_system_init(void);
#endif /* __ALARM_H__ */

View file

@ -0,0 +1,176 @@
/*
* 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
*
*/
#ifndef __AUDIO_H__
#define __AUDIO_H__
#include "audio_pipe.h"
/* AUDIO command */
#define _AUDIO_CTL(a) (RT_DEVICE_CTRL_BASE(Sound) + a)
#define AUDIO_CTL_GETCAPS _AUDIO_CTL(1)
#define AUDIO_CTL_CONFIGURE _AUDIO_CTL(2)
#define AUDIO_CTL_START _AUDIO_CTL(3)
#define AUDIO_CTL_STOP _AUDIO_CTL(4)
#define AUDIO_CTL_GETBUFFERINFO _AUDIO_CTL(5)
/* Audio Device Types */
#define AUDIO_TYPE_QUERY 0x00
#define AUDIO_TYPE_INPUT 0x01
#define AUDIO_TYPE_OUTPUT 0x02
#define AUDIO_TYPE_MIXER 0x04
/* Supported Sampling Rates */
#define AUDIO_SAMP_RATE_8K 0x0001
#define AUDIO_SAMP_RATE_11K 0x0002
#define AUDIO_SAMP_RATE_16K 0x0004
#define AUDIO_SAMP_RATE_22K 0x0008
#define AUDIO_SAMP_RATE_32K 0x0010
#define AUDIO_SAMP_RATE_44K 0x0020
#define AUDIO_SAMP_RATE_48K 0x0040
#define AUDIO_SAMP_RATE_96K 0x0080
#define AUDIO_SAMP_RATE_128K 0x0100
#define AUDIO_SAMP_RATE_160K 0x0200
#define AUDIO_SAMP_RATE_172K 0x0400
#define AUDIO_SAMP_RATE_192K 0x0800
/* Supported Bit Rates */
#define AUDIO_BIT_RATE_22K 0x01
#define AUDIO_BIT_RATE_44K 0x02
#define AUDIO_BIT_RATE_48K 0x04
#define AUDIO_BIT_RATE_96K 0x08
#define AUDIO_BIT_RATE_128K 0x10
#define AUDIO_BIT_RATE_160K 0x20
#define AUDIO_BIT_RATE_172K 0x40
#define AUDIO_BIT_RATE_192K 0x80
/* Support Dsp(input/output) Units controls */
#define AUDIO_DSP_PARAM 0 /* get/set all params */
#define AUDIO_DSP_SAMPLERATE 1 /* samplerate */
#define AUDIO_DSP_CHANNELS 2 /* channels */
#define AUDIO_DSP_SAMPLEBITS 3 /* sample bits width */
/* Supported Mixer Units controls */
#define AUDIO_MIXER_QUERY 0x0000
#define AUDIO_MIXER_MUTE 0x0001
#define AUDIO_MIXER_VOLUME 0x0002
#define AUDIO_MIXER_BASS 0x0004
#define AUDIO_MIXER_MID 0x0008
#define AUDIO_MIXER_TREBLE 0x0010
#define AUDIO_MIXER_EQUALIZER 0x0020
#define AUDIO_MIXER_LINE 0x0040
#define AUDIO_MIXER_DIGITAL 0x0080
#define AUDIO_MIXER_MIC 0x0100
#define AUDIO_MIXER_VITURAL 0x0200
#define AUDIO_MIXER_EXTEND 0x8000 /* extend mixer command */
#define AUDIO_VOLUME_MAX (100)
#define AUDIO_VOLUME_MIN (0)
#define CFG_AUDIO_REPLAY_QUEUE_COUNT 4
enum
{
AUDIO_STREAM_REPLAY = 0,
AUDIO_STREAM_RECORD,
AUDIO_STREAM_LAST = AUDIO_STREAM_RECORD,
};
/* the preferred number and size of audio pipeline buffer for the audio device */
struct rt_audio_buf_info
{
rt_uint8_t *buffer;
rt_uint16_t block_size;
rt_uint16_t block_count;
rt_uint32_t total_size;
};
struct rt_audio_device;
struct rt_audio_caps;
struct rt_audio_configure;
struct rt_audio_ops
{
rt_err_t (*getcaps)(struct rt_audio_device *audio, struct rt_audio_caps *caps);
rt_err_t (*configure)(struct rt_audio_device *audio, struct rt_audio_caps *caps);
rt_err_t (*init)(struct rt_audio_device *audio);
rt_err_t (*start)(struct rt_audio_device *audio, int stream);
rt_err_t (*stop)(struct rt_audio_device *audio, int stream);
rt_ssize_t (*transmit)(struct rt_audio_device *audio, const void *writeBuf, void *readBuf, rt_size_t size);
/* get page size of codec or private buffer's info */
void (*buffer_info)(struct rt_audio_device *audio, struct rt_audio_buf_info *info);
};
struct rt_audio_configure
{
rt_uint32_t samplerate;
rt_uint16_t channels;
rt_uint16_t samplebits;
};
struct rt_audio_caps
{
int main_type;
int sub_type;
union
{
rt_uint32_t mask;
int value;
struct rt_audio_configure config;
} udata;
};
struct rt_audio_replay
{
struct rt_mempool *mp;
struct rt_data_queue queue;
struct rt_mutex lock;
struct rt_completion cmp;
struct rt_audio_buf_info buf_info;
rt_uint8_t *write_data;
rt_uint16_t write_index;
rt_uint16_t read_index;
rt_uint32_t pos;
rt_uint8_t event;
rt_bool_t activated;
};
struct rt_audio_record
{
struct rt_audio_pipe pipe;
rt_bool_t activated;
};
struct rt_audio_device
{
struct rt_device parent;
struct rt_audio_ops *ops;
struct rt_audio_replay *replay;
struct rt_audio_record *record;
};
rt_err_t rt_audio_register(struct rt_audio_device *audio, const char *name, rt_uint32_t flag, void *data);
void rt_audio_tx_complete(struct rt_audio_device *audio);
void rt_audio_rx_done(struct rt_audio_device *audio, rt_uint8_t *pbuf, rt_size_t len);
/* Device Control Commands */
#define CODEC_CMD_RESET 0
#define CODEC_CMD_SET_VOLUME 1
#define CODEC_CMD_GET_VOLUME 2
#define CODEC_CMD_SAMPLERATE 3
#define CODEC_CMD_EQ 4
#define CODEC_CMD_3D 5
#define CODEC_VOLUME_MAX (63)
#endif /* __AUDIO_H__ */

View file

@ -0,0 +1,364 @@
/*
* Copyright (c) 2006-2023, 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 remove RT_CAN_USING_LED.
* 2022-05-08 hpmicro add CANFD support, fixed typos
*/
#ifndef CAN_H_
#define CAN_H_
#include <rtthread.h>
#ifndef RT_CANMSG_BOX_SZ
#define RT_CANMSG_BOX_SZ 16
#endif
#ifndef RT_CANSND_BOX_NUM
#define RT_CANSND_BOX_NUM 1
#endif
enum CAN_DLC
{
CAN_MSG_0BYTE = 0,
CAN_MSG_1BYTE,
CAN_MSG_2BYTES,
CAN_MSG_3BYTES,
CAN_MSG_4BYTES,
CAN_MSG_5BYTES,
CAN_MSG_6BYTES,
CAN_MSG_7BYTES,
CAN_MSG_8BYTES,
CAN_MSG_12BYTES,
CAN_MSG_16BYTES,
CAN_MSG_20BYTES,
CAN_MSG_24BYTES,
CAN_MSG_32BYTES,
CAN_MSG_48BYTES,
CAN_MSG_64BYTES,
};
enum CANBAUD
{
CAN1MBaud = 1000UL * 1000,/* 1 MBit/sec */
CAN800kBaud = 1000UL * 800, /* 800 kBit/sec */
CAN500kBaud = 1000UL * 500, /* 500 kBit/sec */
CAN250kBaud = 1000UL * 250, /* 250 kBit/sec */
CAN125kBaud = 1000UL * 125, /* 125 kBit/sec */
CAN100kBaud = 1000UL * 100, /* 100 kBit/sec */
CAN50kBaud = 1000UL * 50, /* 50 kBit/sec */
CAN20kBaud = 1000UL * 20, /* 20 kBit/sec */
CAN10kBaud = 1000UL * 10 /* 10 kBit/sec */
};
#define RT_CAN_MODE_NORMAL 0
#define RT_CAN_MODE_LISTEN 1
#define RT_CAN_MODE_LOOPBACK 2
#define RT_CAN_MODE_LOOPBACKANLISTEN 3
#define RT_CAN_MODE_PRIV 0x01
#define RT_CAN_MODE_NOPRIV 0x00
/** @defgroup CAN_receive_FIFO_number CAN Receive FIFO Number
* @{
*/
#define CAN_RX_FIFO0 (0x00000000U) /*!< CAN receive FIFO 0 */
#define CAN_RX_FIFO1 (0x00000001U) /*!< CAN receive FIFO 1 */
struct rt_can_filter_item
{
rt_uint32_t id : 29;
rt_uint32_t ide : 1;
rt_uint32_t rtr : 1;
rt_uint32_t mode : 1;
rt_uint32_t mask;
rt_int32_t hdr_bank;/*Should be defined as:rx.FilterBank,which should be changed to rt_int32_t hdr_bank*/
rt_uint32_t rxfifo;/*Add a configuration item that CAN_RX_FIFO0/CAN_RX_FIFO1*/
#ifdef RT_CAN_USING_HDR
rt_err_t (*ind)(rt_device_t dev, void *args , rt_int32_t hdr, rt_size_t size);
void *args;
#endif /*RT_CAN_USING_HDR*/
};
#ifdef RT_CAN_USING_HDR
#define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask,ind,args) \
{(id), (ide), (rtr), (mode),(mask), -1, CAN_RX_FIFO0,(ind), (args)}/*0:CAN_RX_FIFO0*/
#define RT_CAN_FILTER_STD_INIT(id,ind,args) \
RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF,ind,args)
#define RT_CAN_FILTER_EXT_INIT(id,ind,args) \
RT_CAN_FILTER_ITEM_INIT(id,1,0,0,0xFFFFFFFF,ind,args)
#define RT_CAN_STD_RMT_FILTER_INIT(id,ind,args) \
RT_CAN_FILTER_ITEM_INIT(id,0,1,0,0xFFFFFFFF,ind,args)
#define RT_CAN_EXT_RMT_FILTER_INIT(id,ind,args) \
RT_CAN_FILTER_ITEM_INIT(id,1,1,0,0xFFFFFFFF,ind,args)
#define RT_CAN_STD_RMT_DATA_FILTER_INIT(id,ind,args) \
RT_CAN_FILTER_ITEM_INIT(id,0,0,1,0xFFFFFFFF,ind,args)
#define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id,ind,args) \
RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF,ind,args)
#else
#define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask) \
{(id), (ide), (rtr), (mode), (mask), -1, CAN_RX_FIFO0 }/*0:CAN_RX_FIFO0*/
#define RT_CAN_FILTER_STD_INIT(id) \
RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF)
#define RT_CAN_FILTER_EXT_INIT(id) \
RT_CAN_FILTER_ITEM_INIT(id,1,0,0,0xFFFFFFFF)
#define RT_CAN_STD_RMT_FILTER_INIT(id) \
RT_CAN_FILTER_ITEM_INIT(id,0,1,0,0xFFFFFFFF)
#define RT_CAN_EXT_RMT_FILTER_INIT(id) \
RT_CAN_FILTER_ITEM_INIT(id,1,1,0,0xFFFFFFFF)
#define RT_CAN_STD_RMT_DATA_FILTER_INIT(id) \
RT_CAN_FILTER_ITEM_INIT(id,0,0,1,0xFFFFFFFF)
#define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id) \
RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF)
#endif
struct rt_can_filter_config
{
rt_uint32_t count;
rt_uint32_t actived;
struct rt_can_filter_item *items;
};
struct rt_can_bit_timing
{
rt_uint16_t prescaler; /* Pre-scaler */
rt_uint16_t num_seg1; /* Bit Timing Segment 1, in terms of Tq */
rt_uint16_t num_seg2; /* Bit Timing Segment 2, in terms of Tq */
rt_uint8_t num_sjw; /* Synchronization Jump Width, in terms of Tq */
rt_uint8_t num_sspoff; /* Secondary Sample Point Offset, in terms of Tq */
};
/**
* CAN bit timing configuration list
* NOTE:
* items[0] always for CAN2.0/CANFD Arbitration Phase
* items[1] always for CANFD (if it exists)
*/
struct rt_can_bit_timing_config
{
rt_uint32_t count;
struct rt_can_bit_timing *items;
};
struct can_configure
{
rt_uint32_t baud_rate;
rt_uint32_t msgboxsz;
rt_uint32_t sndboxnumber;
rt_uint32_t mode : 8;
rt_uint32_t privmode : 8;
rt_uint32_t reserved : 16;
rt_uint32_t ticks;
#ifdef RT_CAN_USING_HDR
rt_uint32_t maxhdr;
#endif
#ifdef RT_CAN_USING_CANFD
rt_uint32_t baud_rate_fd; /* CANFD data bit rate*/
rt_uint32_t use_bit_timing: 8; /* Use the bit timing for CAN timing configuration */
rt_uint32_t enable_canfd : 8; /* Enable CAN-FD mode */
rt_uint32_t reserved1 : 16;
/* The below fields take effect only if use_bit_timing is non-zero */
struct rt_can_bit_timing can_timing; /* CAN bit-timing /CANFD bit-timing for arbitration phase */
struct rt_can_bit_timing canfd_timing; /* CANFD bit-timing for datat phase */
#endif
};
#define CANDEFAULTCONFIG \
{\
CAN1MBaud,\
RT_CANMSG_BOX_SZ,\
RT_CANSND_BOX_NUM,\
RT_CAN_MODE_NORMAL,\
};
struct rt_can_ops;
#define RT_CAN_CMD_SET_FILTER 0x13
#define RT_CAN_CMD_SET_BAUD 0x14
#define RT_CAN_CMD_SET_MODE 0x15
#define RT_CAN_CMD_SET_PRIV 0x16
#define RT_CAN_CMD_GET_STATUS 0x17
#define RT_CAN_CMD_SET_STATUS_IND 0x18
#define RT_CAN_CMD_SET_BUS_HOOK 0x19
#define RT_CAN_CMD_SET_CANFD 0x1A
#define RT_CAN_CMD_SET_BAUD_FD 0x1B
#define RT_CAN_CMD_SET_BITTIMING 0x1C
#define RT_DEVICE_CAN_INT_ERR 0x1000
enum RT_CAN_STATUS_MODE
{
NORMAL = 0,
ERRWARNING = 1,
ERRPASSIVE = 2,
BUSOFF = 4,
};
enum RT_CAN_BUS_ERR
{
RT_CAN_BUS_NO_ERR = 0,
RT_CAN_BUS_BIT_PAD_ERR = 1,
RT_CAN_BUS_FORMAT_ERR = 2,
RT_CAN_BUS_ACK_ERR = 3,
RT_CAN_BUS_IMPLICIT_BIT_ERR = 4,
RT_CAN_BUS_EXPLICIT_BIT_ERR = 5,
RT_CAN_BUS_CRC_ERR = 6,
};
struct rt_can_status
{
rt_uint32_t rcverrcnt;
rt_uint32_t snderrcnt;
rt_uint32_t errcode;
rt_uint32_t rcvpkg;
rt_uint32_t dropedrcvpkg;
rt_uint32_t sndpkg;
rt_uint32_t dropedsndpkg;
rt_uint32_t bitpaderrcnt;
rt_uint32_t formaterrcnt;
rt_uint32_t ackerrcnt;
rt_uint32_t biterrcnt;
rt_uint32_t crcerrcnt;
rt_uint32_t rcvchange;
rt_uint32_t sndchange;
rt_uint32_t lasterrtype;
};
#ifdef RT_CAN_USING_HDR
struct rt_can_hdr
{
rt_uint32_t connected;
rt_uint32_t msgs;
struct rt_can_filter_item filter;
struct rt_list_node list;
};
#endif
struct rt_can_device;
typedef rt_err_t (*rt_canstatus_ind)(struct rt_can_device *, void *);
typedef struct rt_can_status_ind_type
{
rt_canstatus_ind ind;
void *args;
} *rt_can_status_ind_type_t;
typedef void (*rt_can_bus_hook)(struct rt_can_device *);
struct rt_can_device
{
struct rt_device parent;
const struct rt_can_ops *ops;
struct can_configure config;
struct rt_can_status status;
rt_uint32_t timerinitflag;
struct rt_timer timer;
struct rt_can_status_ind_type status_indicate;
#ifdef RT_CAN_USING_HDR
struct rt_can_hdr *hdr;
#endif
#ifdef RT_CAN_USING_BUS_HOOK
rt_can_bus_hook bus_hook;
#endif /*RT_CAN_USING_BUS_HOOK*/
struct rt_mutex lock;
void *can_rx;
void *can_tx;
};
typedef struct rt_can_device *rt_can_t;
#define RT_CAN_STDID 0
#define RT_CAN_EXTID 1
#define RT_CAN_DTR 0
#define RT_CAN_RTR 1
typedef struct rt_can_status *rt_can_status_t;
struct rt_can_msg
{
rt_uint32_t id : 29;
rt_uint32_t ide : 1;
rt_uint32_t rtr : 1;
rt_uint32_t rsv : 1;
rt_uint32_t len : 8;
rt_uint32_t priv : 8;
rt_int32_t hdr_index : 8;/*Should be defined as:rx.FilterMatchIndex,which should be changed to rt_int32_t hdr_index : 8*/
#ifdef RT_CAN_USING_CANFD
rt_uint32_t fd_frame : 1;
rt_uint32_t brs : 1;
rt_uint32_t rxfifo : 2;/*Redefined to return :CAN RX FIFO0/CAN RX FIFO1*/
rt_uint32_t reserved : 4;
#else
rt_uint32_t rxfifo : 2;/*Redefined to return :CAN RX FIFO0/CAN RX FIFO1*/
rt_uint32_t reserved : 6;
#endif
#ifdef RT_CAN_USING_CANFD
rt_uint8_t data[64];
#else
rt_uint8_t data[8];
#endif
};
typedef struct rt_can_msg *rt_can_msg_t;
struct rt_can_msg_list
{
struct rt_list_node list;
#ifdef RT_CAN_USING_HDR
struct rt_list_node hdrlist;
struct rt_can_hdr *owner;
#endif
struct rt_can_msg data;
};
struct rt_can_rx_fifo
{
/* software fifo */
struct rt_can_msg_list *buffer;
rt_uint32_t freenumbers;
struct rt_list_node freelist;
struct rt_list_node uselist;
};
#define RT_CAN_SND_RESULT_OK 0
#define RT_CAN_SND_RESULT_ERR 1
#define RT_CAN_SND_RESULT_WAIT 2
#define RT_CAN_EVENT_RX_IND 0x01 /* Rx indication */
#define RT_CAN_EVENT_TX_DONE 0x02 /* Tx complete */
#define RT_CAN_EVENT_TX_FAIL 0x03 /* Tx fail */
#define RT_CAN_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */
#define RT_CAN_EVENT_RXOF_IND 0x06 /* Rx overflow */
struct rt_can_sndbxinx_list
{
struct rt_list_node list;
struct rt_completion completion;
rt_uint32_t result;
};
struct rt_can_tx_fifo
{
struct rt_can_sndbxinx_list *buffer;
struct rt_semaphore sem;
struct rt_list_node freelist;
};
struct rt_can_ops
{
rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg);
rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg);
int (*sendmsg)(struct rt_can_device *can, const void *buf, rt_uint32_t boxno);
int (*recvmsg)(struct rt_can_device *can, void *buf, rt_uint32_t boxno);
};
rt_err_t rt_hw_can_register(struct rt_can_device *can,
const char *name,
const struct rt_can_ops *ops,
void *data);
void rt_hw_can_isr(struct rt_can_device *can, int event);
#endif /*_CAN_H*/

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-12-23 Bernard first version
*/
#ifndef CPUTIME_H__
#define CPUTIME_H__
#include <stdint.h>
#include "cputimer.h"
struct rt_clock_cputime_ops
{
uint64_t (*cputime_getres)(void);
uint64_t (*cputime_gettime)(void);
int (*cputime_settimeout)(uint64_t tick, void (*timeout)(void *param), void *param);
};
uint64_t clock_cpu_getres(void);
uint64_t clock_cpu_gettime(void);
int clock_cpu_settimeout(uint64_t tick, void (*timeout)(void *param), void *param);
int clock_cpu_issettimeout(void);
uint64_t clock_cpu_microsecond(uint64_t cpu_tick);
uint64_t clock_cpu_millisecond(uint64_t cpu_tick);
int clock_cpu_setops(const struct rt_clock_cputime_ops *ops);
#endif

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-02-13 zhkag first version
*/
#ifndef CPUTIMER_H__
#define CPUTIMER_H__
#include <rtthread.h>
struct rt_cputimer
{
struct rt_object parent; /**< inherit from rt_object */
rt_list_t row;
void (*timeout_func)(void *parameter);
void *parameter;
rt_uint64_t init_tick;
rt_uint64_t timeout_tick;
struct rt_semaphore sem;
};
typedef struct rt_cputimer *rt_cputimer_t;
rt_err_t rt_cputimer_detach(rt_cputimer_t timer);
#ifdef RT_USING_HEAP
void rt_cputimer_init(rt_cputimer_t timer,
const char *name,
void (*timeout)(void *parameter),
void *parameter,
rt_uint64_t tick,
rt_uint8_t flag);
rt_err_t rt_cputimer_delete(rt_cputimer_t timer);
#endif
rt_err_t rt_cputimer_start(rt_cputimer_t timer);
rt_err_t rt_cputimer_stop(rt_cputimer_t timer);
rt_err_t rt_cputimer_control(rt_cputimer_t timer, int cmd, void *arg);
rt_err_t rt_cputime_sleep(rt_uint64_t tick);
rt_err_t rt_cputime_ndelay(rt_uint64_t ns);
rt_err_t rt_cputime_udelay(rt_uint64_t us);
rt_err_t rt_cputime_mdelay(rt_uint64_t ms);
#endif

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-05-17 tyx the first version
*/
#ifndef __CRYPTO_H__
#define __CRYPTO_H__
#include <rtthread.h>
#include <hwcrypto.h>
#include <hw_symmetric.h>
#include <hw_rng.h>
#include <hw_hash.h>
#include <hw_crc.h>
#include <hw_gcm.h>
#include <hw_bignum.h>
#endif

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-06-19 thread-liu the first version
*/
#ifndef __DAC_H__
#define __DAC_H__
#include <rtthread.h>
struct rt_dac_device;
struct rt_dac_ops
{
rt_err_t (*disabled)(struct rt_dac_device *device, rt_uint32_t channel);
rt_err_t (*enabled)(struct rt_dac_device *device, rt_uint32_t channel);
rt_err_t (*convert)(struct rt_dac_device *device, rt_uint32_t channel, rt_uint32_t *value);
rt_uint8_t (*get_resolution)(struct rt_dac_device *device);
};
struct rt_dac_device
{
struct rt_device parent;
const struct rt_dac_ops *ops;
};
typedef struct rt_dac_device *rt_dac_device_t;
typedef enum
{
RT_DAC_CMD_ENABLE = RT_DEVICE_CTRL_BASE(DAC) + 0,
RT_DAC_CMD_DISABLE = RT_DEVICE_CTRL_BASE(DAC) + 1,
RT_DAC_CMD_GET_RESOLUTION = RT_DEVICE_CTRL_BASE(DAC) + 2,
} rt_dac_cmd_t;
rt_err_t rt_hw_dac_register(rt_dac_device_t dac,const char *name, const struct rt_dac_ops *ops, const void *user_data);
rt_err_t rt_dac_write(rt_dac_device_t dev, rt_uint32_t channel, rt_uint32_t value);
rt_err_t rt_dac_enable(rt_dac_device_t dev, rt_uint32_t channel);
rt_err_t rt_dac_disable(rt_dac_device_t dev, rt_uint32_t channel);
#endif /* __dac_H__ */

View file

@ -0,0 +1,132 @@
/*
* 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
*/
#ifndef __GPT_H
#define __GPT_H
#include <rtthread.h>
#include <stdint.h>
typedef struct
{
uint8_t b[16]; /* GUID 16 bytes*/
} guid_t;
#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
typedef guid_t gpt_guid_t __attribute__ ((aligned (4)));
#define EFI_GUID(a, b, c, d...) (gpt_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)
#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)
#define PARTITION_LINUX_RAID_GUID \
EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
#define PARTITION_LINUX_SWAP_GUID \
EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
#define PARTITION_LINUX_LVM_GUID \
EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
#pragma pack(push, 1)
typedef struct _gpt_header
{
uint64_t signature;
uint32_t revision;
uint32_t header_size;
uint32_t header_crc32;
uint32_t reserved1;
uint64_t start_lba; /*GPT head start sector*/
uint64_t alternate_lba; /*GPT head alternate sector*/
uint64_t first_usable_lba;
uint64_t last_usable_lba;
gpt_guid_t disk_guid;
uint64_t partition_entry_lba;
uint32_t num_partition_entries;
uint32_t sizeof_partition_entry;
uint32_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 ];
*/
} gpt_header;
typedef struct _gpt_entry_attributes
{
uint64_t required_to_function:1;
uint64_t reserved:47;
uint64_t type_guid_specific:16;
} gpt_entry_attributes;
typedef struct _gpt_entry
{
gpt_guid_t partition_type_guid;
gpt_guid_t unique_partition_guid;
uint64_t starting_lba;
uint64_t ending_lba;
gpt_entry_attributes attributes;
uint16_t partition_name[72/sizeof(uint16_t)];
} gpt_entry;
typedef struct _gpt_mbr_record
{
uint8_t boot_indicator; /* unused by EFI, set to 0x80 for bootable */
uint8_t start_head; /* unused by EFI, pt start in CHS */
uint8_t start_sector; /* unused by EFI, pt start in CHS */
uint8_t start_track;
uint8_t os_type; /* EFI and legacy non-EFI OS types */
uint8_t end_head; /* unused by EFI, pt end in CHS */
uint8_t end_sector; /* unused by EFI, pt end in CHS */
uint8_t end_track; /* unused by EFI, pt end in CHS */
uint32_t starting_lba; /* used by EFI - start addr of the on disk pt */
uint32_t size_in_lba; /* used by EFI - size of pt in LBA */
} gpt_mbr_record;
typedef struct _legacy_mbr
{
uint8_t boot_code[440];
uint32_t unique_mbr_signature;
uint16_t unknown;
gpt_mbr_record partition_record[4];
uint16_t signature;
} legacy_mbr;
#pragma pack(pop)
int check_gpt(struct rt_mmcsd_card *card);
int gpt_get_partition_param(struct rt_mmcsd_card *card, struct dfs_partition *part, uint32_t pindex);
void gpt_free(void);
#endif /*__GPT_H*/

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef __HWTIMER_H__
#define __HWTIMER_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Timer Control Command */
typedef enum
{
HWTIMER_CTRL_FREQ_SET = RT_DEVICE_CTRL_BASE(Timer) + 0x01, /* set the count frequency */
HWTIMER_CTRL_STOP = RT_DEVICE_CTRL_BASE(Timer) + 0x02, /* stop timer */
HWTIMER_CTRL_INFO_GET = RT_DEVICE_CTRL_BASE(Timer) + 0x03, /* get a timer feature information */
HWTIMER_CTRL_MODE_SET = RT_DEVICE_CTRL_BASE(Timer) + 0x04 /* Setting the timing mode(oneshot/period) */
} rt_hwtimer_ctrl_t;
/* Timing Mode */
typedef enum
{
HWTIMER_MODE_ONESHOT = 0x01,
HWTIMER_MODE_PERIOD
} rt_hwtimer_mode_t;
/* Time Value */
typedef struct rt_hwtimerval
{
rt_int32_t sec; /* second */
rt_int32_t usec; /* microsecond */
} rt_hwtimerval_t;
#define HWTIMER_CNTMODE_UP 0x01 /* increment count mode */
#define HWTIMER_CNTMODE_DW 0x02 /* decreasing count mode */
struct rt_hwtimer_device;
struct rt_hwtimer_ops
{
void (*init)(struct rt_hwtimer_device *timer, rt_uint32_t state);
rt_err_t (*start)(struct rt_hwtimer_device *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode);
void (*stop)(struct rt_hwtimer_device *timer);
rt_uint32_t (*count_get)(struct rt_hwtimer_device *timer);
rt_err_t (*control)(struct rt_hwtimer_device *timer, rt_uint32_t cmd, void *args);
};
/* Timer Feature Information */
struct rt_hwtimer_info
{
rt_int32_t maxfreq; /* the maximum count frequency timer support */
rt_int32_t minfreq; /* the minimum count frequency timer support */
rt_uint32_t maxcnt; /* counter maximum value */
rt_uint8_t cntmode; /* count mode (inc/dec) */
};
typedef struct rt_hwtimer_device
{
struct rt_device parent;
const struct rt_hwtimer_ops *ops;
const struct rt_hwtimer_info *info;
rt_int32_t freq; /* counting frequency set by the user */
rt_int32_t overflow; /* timer overflows */
float period_sec;
rt_int32_t cycles; /* how many times will generate a timeout event after overflow */
rt_int32_t reload; /* reload cycles(using in period mode) */
rt_hwtimer_mode_t mode; /* timing mode(oneshot/period) */
} rt_hwtimer_t;
rt_err_t rt_device_hwtimer_register(rt_hwtimer_t *timer, const char *name, void *user_data);
void rt_device_hwtimer_isr(rt_hwtimer_t *timer);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-04-25 weety first version
*/
#ifndef __I2C_BIT_OPS_H__
#define __I2C_BIT_OPS_H__
#ifdef __cplusplus
extern "C" {
#endif
struct rt_i2c_bit_ops
{
void *data; /* private data for lowlevel routines */
void (*set_sda)(void *data, rt_int32_t state);
void (*set_scl)(void *data, rt_int32_t state);
rt_int32_t (*get_sda)(void *data);
rt_int32_t (*get_scl)(void *data);
void (*udelay)(rt_uint32_t us);
rt_uint32_t delay_us; /* scl and sda line delay */
rt_uint32_t timeout; /* in tick */
};
rt_err_t rt_i2c_bit_add_bus(struct rt_i2c_bus_device *bus,
const char *bus_name);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-04-25 weety first version
* 2021-04-20 RiceChen added support for bus control api
*/
#ifndef __I2C_H__
#define __I2C_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
#define RT_I2C_WR 0x0000
#define RT_I2C_RD (1u << 0)
#define RT_I2C_ADDR_10BIT (1u << 2) /* this is a ten bit chip address */
#define RT_I2C_NO_START (1u << 4)
#define RT_I2C_IGNORE_NACK (1u << 5)
#define RT_I2C_NO_READ_ACK (1u << 6) /* when I2C reading, we do not ACK */
#define RT_I2C_NO_STOP (1u << 7)
struct rt_i2c_msg
{
rt_uint16_t addr;
rt_uint16_t flags;
rt_uint16_t len;
rt_uint8_t *buf;
};
struct rt_i2c_bus_device;
struct rt_i2c_bus_device_ops
{
rt_ssize_t (*master_xfer)(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num);
rt_ssize_t (*slave_xfer)(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num);
rt_err_t (*i2c_bus_control)(struct rt_i2c_bus_device *bus,
rt_uint32_t,
rt_uint32_t);
};
/*for i2c bus driver*/
struct rt_i2c_bus_device
{
struct rt_device parent;
const struct rt_i2c_bus_device_ops *ops;
rt_uint16_t flags;
struct rt_mutex lock;
rt_uint32_t timeout;
rt_uint32_t retries;
void *priv;
};
struct rt_i2c_client
{
struct rt_i2c_bus_device *bus;
rt_uint16_t client_addr;
};
rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus,
const char *bus_name);
struct rt_i2c_bus_device *rt_i2c_bus_device_find(const char *bus_name);
rt_ssize_t rt_i2c_transfer(struct rt_i2c_bus_device *bus,
struct rt_i2c_msg msgs[],
rt_uint32_t num);
rt_err_t rt_i2c_control(struct rt_i2c_bus_device *bus,
rt_uint32_t cmd,
rt_uint32_t arg);
rt_ssize_t rt_i2c_master_send(struct rt_i2c_bus_device *bus,
rt_uint16_t addr,
rt_uint16_t flags,
const rt_uint8_t *buf,
rt_uint32_t count);
rt_ssize_t rt_i2c_master_recv(struct rt_i2c_bus_device *bus,
rt_uint16_t addr,
rt_uint16_t flags,
rt_uint8_t *buf,
rt_uint32_t count);
rt_inline rt_err_t rt_i2c_bus_lock(struct rt_i2c_bus_device *bus, rt_tick_t timeout)
{
return rt_mutex_take(&bus->lock, timeout);
}
rt_inline rt_err_t rt_i2c_bus_unlock(struct rt_i2c_bus_device *bus)
{
return rt_mutex_release(&bus->lock);
}
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-04-25 weety first version
* 2021-04-20 RiceChen added bus clock command
*/
#ifndef __I2C_DEV_H__
#define __I2C_DEV_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
#define RT_I2C_DEV_CTRL_10BIT (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x01)
#define RT_I2C_DEV_CTRL_ADDR (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x02)
#define RT_I2C_DEV_CTRL_TIMEOUT (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x03)
#define RT_I2C_DEV_CTRL_RW (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x04)
#define RT_I2C_DEV_CTRL_CLK (RT_DEVICE_CTRL_BASE(I2CBUS) + 0x05)
struct rt_i2c_priv_data
{
struct rt_i2c_msg *msgs;
rt_size_t number;
};
rt_err_t rt_i2c_bus_device_device_init(struct rt_i2c_bus_device *bus,
const char *name);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-03-05 bernard first version.
*/
#ifndef RT_LCD_H__
#define RT_LCD_H__
/* ioctls
0x46 is 'F' */
#define FBIOGET_VSCREENINFO 0x4600
#define FBIOPUT_VSCREENINFO 0x4601
#define FBIOGET_FSCREENINFO 0x4602
#define FBIOGETCMAP 0x4604
#define FBIOPUTCMAP 0x4605
#define FBIOPAN_DISPLAY 0x4606
#define FBIO_CURSOR 0x4608
/* #define FBIOGET_MONITORSPEC 0x460C */
/* #define FBIOPUT_MONITORSPEC 0x460D */
/* #define FBIOSWITCH_MONIBIT 0x460E */
#define FBIOGET_CON2FBMAP 0x460F
#define FBIOPUT_CON2FBMAP 0x4610
#define FBIOBLANK 0x4611 /* arg: 0 or vesa level + 1 */
#define FBIOGET_VBLANK 0x4612
#define FBIO_ALLOC 0x4613
#define FBIO_FREE 0x4614
#define FBIOGET_GLYPH 0x4615
#define FBIOGET_HWCINFO 0x4616
#define FBIOPUT_MODEINFO 0x4617
#define FBIOGET_DISPINFO 0x4618
#define FBIO_WAITFORVSYNC 0x4620
struct fb_bitfield
{
uint32_t offset; /* beginning of bitfield */
uint32_t length; /* length of bitfield */
uint32_t msb_right; /* != 0 : Most significant bit is */
/* right */
};
struct fb_var_screeninfo
{
uint32_t xres; /* visible resolution */
uint32_t yres;
uint32_t xres_virtual; /* virtual resolution */
uint32_t yres_virtual;
uint32_t xoffset; /* offset from virtual to visible */
uint32_t yoffset; /* resolution */
uint32_t bits_per_pixel; /* guess what */
uint32_t grayscale; /* 0 = color, 1 = grayscale, */
/* >1 = FOURCC */
struct fb_bitfield red; /* bitfield in fb mem if true color, */
struct fb_bitfield green; /* else only length is significant */
struct fb_bitfield blue;
struct fb_bitfield transp; /* transparency */
uint32_t nonstd; /* != 0 Non standard pixel format */
uint32_t activate; /* see FB_ACTIVATE_* */
uint32_t height; /* height of picture in mm */
uint32_t width; /* width of picture in mm */
uint32_t accel_flags; /* (OBSOLETE) see fb_info.flags */
/* Timing: All values in pixclocks, except pixclock (of course) */
uint32_t pixclock; /* pixel clock in ps (pico seconds) */
uint32_t left_margin; /* time from sync to picture */
uint32_t right_margin; /* time from picture to sync */
uint32_t upper_margin; /* time from sync to picture */
uint32_t lower_margin;
uint32_t hsync_len; /* length of horizontal sync */
uint32_t vsync_len; /* length of vertical sync */
uint32_t sync; /* see FB_SYNC_* */
uint32_t vmode; /* see FB_VMODE_* */
uint32_t rotate; /* angle we rotate counter clockwise */
uint32_t colorspace; /* colorspace for FOURCC-based modes */
uint32_t reserved[4]; /* Reserved for future compatibility */
};
struct fb_fix_screeninfo
{
char id[16]; /* identification string eg "TT Builtin" */
unsigned long smem_start; /* Start of frame buffer mem */
/* (physical address) */
uint32_t smem_len; /* Length of frame buffer mem */
uint32_t type; /* see FB_TYPE_* */
uint32_t type_aux; /* Interleave for interleaved Planes */
uint32_t visual; /* see FB_VISUAL_* */
uint16_t xpanstep; /* zero if no hardware panning */
uint16_t ypanstep; /* zero if no hardware panning */
uint16_t ywrapstep; /* zero if no hardware ywrap */
uint32_t line_length; /* length of a line in bytes */
unsigned long mmio_start; /* Start of Memory Mapped I/O */
/* (physical address) */
uint32_t mmio_len; /* Length of Memory Mapped I/O */
uint32_t accel; /* Indicate to driver which */
/* specific chip/card we have */
uint16_t capabilities; /* see FB_CAP_* */
uint16_t reserved[2]; /* Reserved for future compatibility */
};
#endif

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-10-11 zhangsz the first version
*/
#ifndef __LPTIMER_H__
#define __LPTIMER_H__
#include <rtthread.h>
struct rt_lptimer
{
struct rt_timer timer;
rt_list_t list;
};
typedef struct rt_lptimer *rt_lptimer_t;
void rt_lptimer_init(rt_lptimer_t timer,
const char *name,
void (*timeout)(void *parameter),
void *parameter,
rt_tick_t time,
rt_uint8_t flag);
rt_err_t rt_lptimer_detach(rt_lptimer_t timer);
rt_err_t rt_lptimer_start(rt_lptimer_t timer);
rt_err_t rt_lptimer_stop(rt_lptimer_t timer);
rt_err_t rt_lptimer_control(rt_lptimer_t timer, int cmd, void *arg);
rt_tick_t rt_lptimer_next_timeout_tick(void);
#endif

View file

@ -0,0 +1,192 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2015-06-15 hichard first version
*/
#ifndef __MMC_H__
#define __MMC_H__
#include <rtthread.h>
#include <drivers/mmcsd_host.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* EXT_CSD fields
*/
#define EXT_CSD_FLUSH_CACHE 32 /* W */
#define EXT_CSD_CACHE_CTRL 33 /* R/W */
#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */
#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */
#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */
#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */
#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */
#define EXT_CSD_HPI_MGMT 161 /* R/W */
#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */
#define EXT_CSD_BKOPS_EN 163 /* R/W */
#define EXT_CSD_BKOPS_START 164 /* W */
#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
#define EXT_CSD_RPMB_MULT 168 /* RO */
#define EXT_CSD_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */
#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_POWER_CLASS 187 /* R/W */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_STRUCTURE 194 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */
#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
#define EXT_CSD_PWR_CL_52_195 200 /* RO */
#define EXT_CSD_PWR_CL_26_195 201 /* RO */
#define EXT_CSD_PWR_CL_52_360 202 /* RO */
#define EXT_CSD_PWR_CL_26_360 203 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
#define EXT_CSD_S_A_TIMEOUT 217 /* RO */
#define EXT_CSD_REL_WR_SEC_C 222 /* RO */
#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */
#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */
#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */
#define EXT_CSD_BOOT_MULT 226 /* RO */
#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */
#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */
#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */
#define EXT_CSD_TRIM_MULT 232 /* RO */
#define EXT_CSD_PWR_CL_200_195 236 /* RO */
#define EXT_CSD_PWR_CL_200_360 237 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */
#define EXT_CSD_BKOPS_STATUS 246 /* RO */
#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */
#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
#define EXT_CSD_MAX_PACKED_READS 501 /* RO */
#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */
#define EXT_CSD_HPI_FEATURES 503 /* RO */
/*
* EXT_CSD field definitions
*/
#define EXT_CSD_WR_REL_PARAM_EN (1<<2)
#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40)
#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10)
#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04)
#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01)
#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
#define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3)
#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4)
#define EXT_CSD_PART_SUPPORT_PART_EN (0x1)
#define EXT_CSD_CMD_SET_NORMAL (1<<0)
#define EXT_CSD_CMD_SET_SECURE (1<<1)
#define EXT_CSD_CMD_SET_CPSECURE (1<<2)
#define EXT_CSD_CARD_TYPE_HS_26 (1<<0) /* Card can run at 26MHz */
#define EXT_CSD_CARD_TYPE_HS_52 (1<<1) /* Card can run at 52MHz */
#define EXT_CSD_CARD_TYPE_HS (EXT_CSD_CARD_TYPE_HS_26 | \
EXT_CSD_CARD_TYPE_HS_52)
#define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */
/* DDR mode @1.8V or 3V I/O */
#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */
/* DDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \
| EXT_CSD_CARD_TYPE_DDR_1_2V)
#define EXT_CSD_CARD_TYPE_HS200_1_8V (1<<4) /* Card can run at 200MHz */
#define EXT_CSD_CARD_TYPE_HS200_1_2V (1<<5) /* Card can run at 200MHz */
/* SDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \
EXT_CSD_CARD_TYPE_HS200_1_2V)
#define EXT_CSD_CARD_TYPE_HS400_1_8V (1<<6) /* Card can run at 200MHz DDR, 1.8V */
#define EXT_CSD_CARD_TYPE_HS400_1_2V (1<<7) /* Card can run at 200MHz DDR, 1.2V */
#define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | \
EXT_CSD_CARD_TYPE_HS400_1_2V)
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */
#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */
#define EXT_CSD_TIMING_BC 0 /* Backwards compatility */
#define EXT_CSD_TIMING_HS 1 /* High speed */
#define EXT_CSD_TIMING_HS200 2 /* HS200 */
#define EXT_CSD_TIMING_HS400 3 /* HS400 */
#define EXT_CSD_SEC_ER_EN BIT(0)
#define EXT_CSD_SEC_BD_BLK_EN BIT(2)
#define EXT_CSD_SEC_GB_CL_EN BIT(4)
#define EXT_CSD_SEC_SANITIZE BIT(6) /* v4.5 only */
#define EXT_CSD_RST_N_EN_MASK 0x3
#define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */
#define EXT_CSD_NO_POWER_NOTIFICATION 0
#define EXT_CSD_POWER_ON 1
#define EXT_CSD_POWER_OFF_SHORT 2
#define EXT_CSD_POWER_OFF_LONG 3
#define EXT_CSD_PWR_CL_8BIT_MASK 0xF0 /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
#define EXT_CSD_PACKED_EVENT_EN BIT(3)
/*
* EXCEPTION_EVENT_STATUS field
*/
#define EXT_CSD_URGENT_BKOPS BIT(0)
#define EXT_CSD_DYNCAP_NEEDED BIT(1)
#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2)
#define EXT_CSD_PACKED_FAILURE BIT(3)
#define EXT_CSD_PACKED_GENERIC_ERROR BIT(0)
#define EXT_CSD_PACKED_INDEXED_ERROR BIT(1)
/*
* BKOPS status level
*/
#define EXT_CSD_BKOPS_LEVEL_2 0x2
/*
* MMC_SWITCH access modes
*/
#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */
#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
/*
* extern function
*/
rt_err_t mmc_send_op_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr, rt_uint32_t *rocr);
rt_int32_t init_mmc(struct rt_mmcsd_host *host, rt_uint32_t ocr);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,173 @@
/*
* 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
*/
#ifndef __MMCSD_CARD_H__
#define __MMCSD_CARD_H__
#include <drivers/mmcsd_host.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SD_SCR_BUS_WIDTH_1 (1 << 0)
#define SD_SCR_BUS_WIDTH_4 (1 << 2)
struct rt_mmcsd_cid {
rt_uint8_t mid; /* ManufacturerID */
rt_uint8_t prv; /* Product Revision */
rt_uint16_t oid; /* OEM/Application ID */
rt_uint32_t psn; /* Product Serial Number */
rt_uint8_t pnm[5]; /* Product Name */
rt_uint8_t reserved1;/* reserved */
rt_uint16_t mdt; /* Manufacturing Date */
rt_uint8_t crc; /* CID CRC */
rt_uint8_t reserved2;/* not used, always 1 */
};
struct rt_mmcsd_csd {
rt_uint8_t csd_structure; /* CSD register version */
rt_uint8_t taac;
rt_uint8_t nsac;
rt_uint8_t tran_speed; /* max data transfer rate */
rt_uint16_t card_cmd_class; /* card command classes */
rt_uint8_t rd_blk_len; /* max read data block length */
rt_uint8_t rd_blk_part;
rt_uint8_t wr_blk_misalign;
rt_uint8_t rd_blk_misalign;
rt_uint8_t dsr_imp; /* DSR implemented */
rt_uint8_t c_size_mult; /* CSD 1.0 , device size multiplier */
rt_uint32_t c_size; /* device size */
rt_uint8_t r2w_factor;
rt_uint8_t wr_blk_len; /* max wtire data block length */
rt_uint8_t wr_blk_partial;
rt_uint8_t csd_crc;
};
struct rt_sd_scr {
rt_uint8_t sd_version;
rt_uint8_t sd_bus_widths;
};
struct rt_sdio_cccr {
rt_uint8_t sdio_version;
rt_uint8_t sd_version;
rt_uint8_t direct_cmd:1, /* Card Supports Direct Commands during data transfer
only SD mode, not used for SPI mode */
multi_block:1, /* Card Supports Multi-Block */
read_wait:1, /* Card Supports Read Wait
only SD mode, not used for SPI mode */
suspend_resume:1, /* Card supports Suspend/Resume
only SD mode, not used for SPI mode */
s4mi:1, /* generate interrupts during a 4-bit
multi-block data transfer */
e4mi:1, /* Enable the multi-block IRQ during
4-bit transfer for the SDIO card */
low_speed:1, /* Card is a Low-Speed card */
low_speed_4:1; /* 4-bit support for Low-Speed cards */
rt_uint8_t bus_width:1, /* Support SDIO bus width, 1:4bit, 0:1bit */
cd_disable:1, /* Connect[0]/Disconnect[1] the 10K-90K ohm pull-up
resistor on CD/DAT[3] (pin 1) of the card */
power_ctrl:1, /* Support Master Power Control */
high_speed:1; /* Support High-Speed */
};
struct rt_sdio_cis {
rt_uint16_t manufacturer;
rt_uint16_t product;
rt_uint16_t func0_blk_size;
rt_uint32_t max_tran_speed;
};
/*
* SDIO function CIS tuple (unknown to the core)
*/
struct rt_sdio_function_tuple {
struct rt_sdio_function_tuple *next;
rt_uint8_t code;
rt_uint8_t size;
rt_uint8_t *data;
};
struct rt_sdio_function;
typedef void (rt_sdio_irq_handler_t)(struct rt_sdio_function *);
/*
* SDIO function devices
*/
struct rt_sdio_function {
struct rt_mmcsd_card *card; /* the card this device belongs to */
rt_sdio_irq_handler_t *irq_handler; /* IRQ callback */
rt_uint8_t num; /* function number */
rt_uint8_t func_code; /* Standard SDIO Function interface code */
rt_uint16_t manufacturer; /* manufacturer id */
rt_uint16_t product; /* product id */
rt_uint32_t max_blk_size; /* maximum block size */
rt_uint32_t cur_blk_size; /* current block size */
rt_uint32_t enable_timeout_val; /* max enable timeout in msec */
struct rt_sdio_function_tuple *tuples;
void *priv;
};
#define SDIO_MAX_FUNCTIONS 7
struct rt_mmcsd_card {
struct rt_mmcsd_host *host;
rt_uint32_t rca; /* card addr */
rt_uint32_t resp_cid[4]; /* card CID register */
rt_uint32_t resp_csd[4]; /* card CSD register */
rt_uint32_t resp_scr[2]; /* card SCR register */
rt_uint16_t tacc_clks; /* data access time by ns */
rt_uint32_t tacc_ns; /* data access time by clk cycles */
rt_uint32_t max_data_rate; /* max data transfer rate */
rt_uint32_t card_capacity; /* card capacity, unit:KB */
rt_uint32_t card_blksize; /* card block size */
rt_uint32_t card_sec_cnt; /* card sector count*/
rt_uint32_t erase_size; /* erase size in sectors */
rt_uint16_t card_type;
#define CARD_TYPE_MMC 0 /* MMC card */
#define CARD_TYPE_SD 1 /* SD card */
#define CARD_TYPE_SDIO 2 /* SDIO card */
#define CARD_TYPE_SDIO_COMBO 3 /* SD combo (IO+mem) card */
rt_uint16_t flags;
#define CARD_FLAG_HIGHSPEED (1 << 0) /* SDIO bus speed 50MHz */
#define CARD_FLAG_SDHC (1 << 1) /* SDHC card */
#define CARD_FLAG_SDXC (1 << 2) /* SDXC card */
#define CARD_FLAG_HIGHSPEED_DDR (1 << 3) /*HIGH SPEED DDR*/
#define CARD_FLAG_HS200 (1 << 4) /* BUS SPEED 200mHz*/
struct rt_sd_scr scr;
struct rt_mmcsd_csd csd;
rt_uint32_t hs_max_data_rate; /* max data transfer rate in high speed mode */
rt_uint8_t sdio_function_num; /* totol number of SDIO functions */
struct rt_sdio_cccr cccr; /* common card info */
struct rt_sdio_cis cis; /* common tuple info */
struct rt_sdio_function *sdio_function[SDIO_MAX_FUNCTIONS + 1]; /* SDIO functions (devices) */
rt_list_t blk_devices; /* for block device list */
};
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,130 @@
/*
* 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
*/
#ifndef __CMD_H__
#define __CMD_H__
#ifdef __cplusplus
extern "C" {
#endif
/* class 1 */
#define GO_IDLE_STATE 0 /* bc */
#define SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
#define ALL_SEND_CID 2 /* bcr R2 */
#define SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
#define SET_DSR 4 /* bc [31:16] RCA */
#define SWITCH 6 /* ac [31:0] See below R1b */
#define SELECT_CARD 7 /* ac [31:16] RCA R1 */
#define SEND_EXT_CSD 8 /* adtc R1 */
#define SEND_CSD 9 /* ac [31:16] RCA R2 */
#define SEND_CID 10 /* ac [31:16] RCA R2 */
#define READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
#define STOP_TRANSMISSION 12 /* ac R1b */
#define SEND_STATUS 13 /* ac [31:16] RCA R1 */
#define GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
#define SPI_READ_OCR 58 /* spi spi_R3 */
#define SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */
/* class 2 */
#define SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
#define READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
#define READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
#define SEND_TUNING_BLOCK 19 /* adtc R1 */
#define SEND_TUNING_BLOCK_HS200 21 /* adtc R1*/
/* class 3 */
#define WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
/* class 4 */
#define SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
#define WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
#define WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
#define PROGRAM_CID 26 /* adtc R1 */
#define PROGRAM_CSD 27 /* adtc R1 */
/* class 6 */
#define SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
#define CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
#define SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
/* class 5 */
#define ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
#define ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
#define ERASE 38 /* ac R1b */
/* class 9 */
#define FAST_IO 39 /* ac <Complex> R4 */
#define GO_IRQ_STATE 40 /* bcr R5 */
/* class 7 */
#define LOCK_UNLOCK 42 /* adtc R1b */
/* class 8 */
#define APP_CMD 55 /* ac [31:16] RCA R1 */
#define GEN_CMD 56 /* adtc [0] RD/WR R1 */
/* SD commands type argument response */
/* class 0 */
/* This is basically the same command as for MMC with some quirks. */
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
/* class 10 */
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
/* Application commands */
#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */
#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
#define SD_APP_SEND_SCR 51 /* adtc R1 */
#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */
#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */
#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */
/* SDIO commands type argument response */
#define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */
#define SD_IO_RW_DIRECT 52 /* ac [31:0] See below R5 */
#define SD_IO_RW_EXTENDED 53 /* adtc [31:0] See below R5 */
/* CMD52 arguments */
#define SDIO_ARG_CMD52_READ (0<<31)
#define SDIO_ARG_CMD52_WRITE (1u<<31)
#define SDIO_ARG_CMD52_FUNC_SHIFT 28
#define SDIO_ARG_CMD52_FUNC_MASK 0x7
#define SDIO_ARG_CMD52_RAW_FLAG (1u<<27)
#define SDIO_ARG_CMD52_REG_SHIFT 9
#define SDIO_ARG_CMD52_REG_MASK 0x1ffff
#define SDIO_ARG_CMD52_DATA_SHIFT 0
#define SDIO_ARG_CMD52_DATA_MASK 0xff
#define SDIO_R5_DATA(resp) ((resp)[0] & 0xff)
/* CMD53 arguments */
#define SDIO_ARG_CMD53_READ (0<<31)
#define SDIO_ARG_CMD53_WRITE (1u<<31)
#define SDIO_ARG_CMD53_FUNC_SHIFT 28
#define SDIO_ARG_CMD53_FUNC_MASK 0x7
#define SDIO_ARG_CMD53_BLOCK_MODE (1u<<27)
#define SDIO_ARG_CMD53_INCREMENT (1u<<26)
#define SDIO_ARG_CMD53_REG_SHIFT 9
#define SDIO_ARG_CMD53_REG_MASK 0x1ffff
#define SDIO_ARG_CMD53_LENGTH_SHIFT 0
#define SDIO_ARG_CMD53_LENGTH_MASK 0x1ff
#define SDIO_ARG_CMD53_LENGTH_MAX 511
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,262 @@
/*
* 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
*/
#ifndef __CORE_H__
#define __CORE_H__
#include <rtthread.h>
#include <drivers/mmcsd_host.h>
#include <drivers/mmcsd_card.h>
#include <drivers/mmcsd_cmd.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef RT_MMCSD_DBG
#define mmcsd_dbg(fmt, ...) rt_kprintf(fmt, ##__VA_ARGS__)
#else
#define mmcsd_dbg(fmt, ...)
#endif
struct rt_mmcsd_data
{
rt_uint32_t blksize;
rt_uint32_t blks;
rt_uint32_t *buf;
rt_int32_t err;
rt_uint32_t flags;
#define DATA_DIR_WRITE (1 << 0)
#define DATA_DIR_READ (1 << 1)
#define DATA_STREAM (1 << 2)
unsigned int bytes_xfered;
struct rt_mmcsd_cmd *stop; /* stop command */
struct rt_mmcsd_req *mrq; /* associated request */
rt_uint32_t timeout_ns;
rt_uint32_t timeout_clks;
void *sg; /* scatter list */
rt_uint16_t sg_len; /* size of scatter list */
rt_int16_t sg_count; /* mapped sg entries */
rt_ubase_t host_cookie; /* host driver private data */
};
struct rt_mmcsd_cmd
{
rt_uint32_t cmd_code;
rt_uint32_t arg;
rt_uint32_t resp[4];
rt_uint32_t flags;
/*rsponse types
*bits:0~3
*/
#define RESP_MASK (0xF)
#define RESP_NONE (0)
#define RESP_R1 (1 << 0)
#define RESP_R1B (2 << 0)
#define RESP_R2 (3 << 0)
#define RESP_R3 (4 << 0)
#define RESP_R4 (5 << 0)
#define RESP_R6 (6 << 0)
#define RESP_R7 (7 << 0)
#define RESP_R5 (8 << 0) /*SDIO command response type*/
/*command types
*bits:4~5
*/
#define CMD_MASK (3 << 4) /* command type */
#define CMD_AC (0 << 4)
#define CMD_ADTC (1 << 4)
#define CMD_BC (2 << 4)
#define CMD_BCR (3 << 4)
#define resp_type(cmd) ((cmd)->flags & RESP_MASK)
/*spi rsponse types
*bits:6~8
*/
#define RESP_SPI_MASK (0x7 << 6)
#define RESP_SPI_R1 (1 << 6)
#define RESP_SPI_R1B (2 << 6)
#define RESP_SPI_R2 (3 << 6)
#define RESP_SPI_R3 (4 << 6)
#define RESP_SPI_R4 (5 << 6)
#define RESP_SPI_R5 (6 << 6)
#define RESP_SPI_R7 (7 << 6)
#define spi_resp_type(cmd) ((cmd)->flags & RESP_SPI_MASK)
/*
* These are the command types.
*/
#define cmd_type(cmd) ((cmd)->flags & CMD_MASK)
rt_int32_t retries; /* max number of retries */
rt_int32_t err;
unsigned int busy_timeout; /* busy detect timeout in ms */
struct rt_mmcsd_data *data;
struct rt_mmcsd_req *mrq; /* associated request */
};
struct rt_mmcsd_req
{
struct rt_mmcsd_data *data;
struct rt_mmcsd_cmd *cmd;
struct rt_mmcsd_cmd *stop;
struct rt_mmcsd_cmd *sbc; /* SET_BLOCK_COUNT for multiblock */
/* Allow other commands during this ongoing data transfer or busy wait */
int cap_cmd_during_tfr;
};
/*the following is response bit*/
#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
#define R1_ERASE_PARAM (1 << 27) /* ex, c */
#define R1_WP_VIOLATION (1 << 26) /* erx, c */
#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
#define R1_CC_ERROR (1 << 20) /* erx, c */
#define R1_ERROR (1 << 19) /* erx, c */
#define R1_UNDERRUN (1 << 18) /* ex, c */
#define R1_OVERRUN (1 << 17) /* ex, c */
#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
#define R1_ERASE_RESET (1 << 13) /* sr, c */
#define R1_STATUS(x) (x & 0xFFFFE000)
#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
#define R1_APP_CMD (1 << 5) /* sr, c */
#define R1_SPI_IDLE (1 << 0)
#define R1_SPI_ERASE_RESET (1 << 1)
#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
#define R1_SPI_COM_CRC (1 << 3)
#define R1_SPI_ERASE_SEQ (1 << 4)
#define R1_SPI_ADDRESS (1 << 5)
#define R1_SPI_PARAMETER (1 << 6)
/* R1 bit 7 is always zero */
#define R2_SPI_CARD_LOCKED (1 << 8)
#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */
#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP
#define R2_SPI_ERROR (1 << 10)
#define R2_SPI_CC_ERROR (1 << 11)
#define R2_SPI_CARD_ECC_ERROR (1 << 12)
#define R2_SPI_WP_VIOLATION (1 << 13)
#define R2_SPI_ERASE_PARAM (1 << 14)
#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */
#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE
#define CARD_BUSY 0x80000000 /* Card Power up status bit */
/* R5 response bits */
#define R5_COM_CRC_ERROR (1 << 15)
#define R5_ILLEGAL_COMMAND (1 << 14)
#define R5_ERROR (1 << 11)
#define R5_FUNCTION_NUMBER (1 << 9)
#define R5_OUT_OF_RANGE (1 << 8)
#define R5_STATUS(x) (x & 0xCB00)
#define R5_IO_CURRENT_STATE(x) ((x & 0x3000) >> 12)
/**
* fls - find last (most-significant) bit set
* @x: the word to search
*
* This is defined the same way as ffs.
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
rt_inline rt_uint32_t __rt_fls(rt_uint32_t val)
{
rt_uint32_t bit = 32;
if (!val)
return 0;
if (!(val & 0xffff0000u))
{
val <<= 16;
bit -= 16;
}
if (!(val & 0xff000000u))
{
val <<= 8;
bit -= 8;
}
if (!(val & 0xf0000000u))
{
val <<= 4;
bit -= 4;
}
if (!(val & 0xc0000000u))
{
val <<= 2;
bit -= 2;
}
if (!(val & 0x80000000u))
{
bit -= 1;
}
return bit;
}
#define MMCSD_HOST_PLUGED 0
#define MMCSD_HOST_UNPLUGED 1
rt_int32_t mmcsd_excute_tuning(struct rt_mmcsd_card *card);
int mmcsd_wait_cd_changed(rt_int32_t timeout);
void mmcsd_host_lock(struct rt_mmcsd_host *host);
void mmcsd_host_unlock(struct rt_mmcsd_host *host);
void mmcsd_req_complete(struct rt_mmcsd_host *host);
void mmcsd_send_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req);
rt_int32_t mmcsd_send_cmd(struct rt_mmcsd_host *host, struct rt_mmcsd_cmd *cmd, int retries);
rt_int32_t mmcsd_go_idle(struct rt_mmcsd_host *host);
rt_int32_t mmcsd_spi_read_ocr(struct rt_mmcsd_host *host, rt_int32_t high_capacity, rt_uint32_t *ocr);
rt_int32_t mmcsd_all_get_cid(struct rt_mmcsd_host *host, rt_uint32_t *cid);
rt_int32_t mmcsd_get_cid(struct rt_mmcsd_host *host, rt_uint32_t *cid);
rt_int32_t mmcsd_get_csd(struct rt_mmcsd_card *card, rt_uint32_t *csd);
rt_int32_t mmcsd_select_card(struct rt_mmcsd_card *card);
rt_int32_t mmcsd_deselect_cards(struct rt_mmcsd_card *host);
rt_int32_t mmcsd_spi_use_crc(struct rt_mmcsd_host *host, rt_int32_t use_crc);
void mmcsd_set_chip_select(struct rt_mmcsd_host *host, rt_int32_t mode);
void mmcsd_set_clock(struct rt_mmcsd_host *host, rt_uint32_t clk);
void mmcsd_set_bus_mode(struct rt_mmcsd_host *host, rt_uint32_t mode);
void mmcsd_set_bus_width(struct rt_mmcsd_host *host, rt_uint32_t width);
void mmcsd_set_timing(struct rt_mmcsd_host *host, rt_uint32_t timing);
void mmcsd_set_data_timeout(struct rt_mmcsd_data *data, const struct rt_mmcsd_card *card);
rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr);
void mmcsd_change(struct rt_mmcsd_host *host);
void mmcsd_detect(void *param);
void mmcsd_host_init(struct rt_mmcsd_host *host);
struct rt_mmcsd_host *mmcsd_alloc_host(void);
void mmcsd_free_host(struct rt_mmcsd_host *host);
int rt_mmcsd_core_init(void);
int rt_mmcsd_blk_init(void);
rt_int32_t read_lba(struct rt_mmcsd_card *card, size_t lba, uint8_t *buffer, size_t count);
rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card);
void rt_mmcsd_blk_remove(struct rt_mmcsd_card *card);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,154 @@
/*
* 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
*/
#ifndef __HOST_H__
#define __HOST_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
struct rt_mmcsd_io_cfg
{
rt_uint32_t clock; /* clock rate */
rt_uint16_t vdd;
/* vdd stores the bit number of the selected voltage range from below. */
rt_uint8_t bus_mode; /* command output mode */
#define MMCSD_BUSMODE_OPENDRAIN 1
#define MMCSD_BUSMODE_PUSHPULL 2
rt_uint8_t chip_select; /* SPI chip select */
#define MMCSD_CS_IGNORE 0
#define MMCSD_CS_HIGH 1
#define MMCSD_CS_LOW 2
rt_uint8_t power_mode; /* power supply mode */
#define MMCSD_POWER_OFF 0
#define MMCSD_POWER_UP 1
#define MMCSD_POWER_ON 2
rt_uint8_t bus_width; /* data bus width */
#define MMCSD_BUS_WIDTH_1 0
#define MMCSD_BUS_WIDTH_4 2
#define MMCSD_BUS_WIDTH_8 3
unsigned char timing; /* timing specification used */
#define MMCSD_TIMING_LEGACY 0
#define MMCSD_TIMING_MMC_HS 1
#define MMCSD_TIMING_SD_HS 2
#define MMCSD_TIMING_UHS_SDR12 3
#define MMCSD_TIMING_UHS_SDR25 4
#define MMCSD_TIMING_UHS_SDR50 5
#define MMCSD_TIMING_UHS_SDR104 6
#define MMCSD_TIMING_UHS_DDR50 7
#define MMCSD_TIMING_MMC_DDR52 8
#define MMCSD_TIMING_MMC_HS200 9
#define MMCSD_TIMING_MMC_HS400 10
unsigned char drv_type; /* driver type (A, B, C, D) */
#define MMCSD_SET_DRIVER_TYPE_B 0
#define MMCSD_SET_DRIVER_TYPE_A 1
#define MMCSD_SET_DRIVER_TYPE_C 2
#define MMCSD_SET_DRIVER_TYPE_D 3
unsigned char signal_voltage;
#define MMCSD_SIGNAL_VOLTAGE_330 0
#define MMCSD_SIGNAL_VOLTAGE_180 1
#define MMCSD_SIGNAL_VOLTAGE_120 2
};
struct rt_mmcsd_host;
struct rt_mmcsd_req;
struct rt_mmcsd_host_ops
{
void (*request)(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req);
void (*set_iocfg)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg);
rt_int32_t (*get_card_status)(struct rt_mmcsd_host *host);
void (*enable_sdio_irq)(struct rt_mmcsd_host *host, rt_int32_t en);
rt_int32_t (*execute_tuning)(struct rt_mmcsd_host *host, rt_int32_t opcode);
};
struct rt_mmcsd_host
{
char name[RT_NAME_MAX];
struct rt_mmcsd_card *card;
const struct rt_mmcsd_host_ops *ops;
rt_uint32_t freq_min;
rt_uint32_t freq_max;
struct rt_mmcsd_io_cfg io_cfg;
rt_uint32_t valid_ocr; /* current valid OCR */
#define VDD_165_195 (1 << 7) /* VDD voltage 1.65 - 1.95 */
#define VDD_20_21 (1 << 8) /* VDD voltage 2.0 ~ 2.1 */
#define VDD_21_22 (1 << 9) /* VDD voltage 2.1 ~ 2.2 */
#define VDD_22_23 (1 << 10) /* VDD voltage 2.2 ~ 2.3 */
#define VDD_23_24 (1 << 11) /* VDD voltage 2.3 ~ 2.4 */
#define VDD_24_25 (1 << 12) /* VDD voltage 2.4 ~ 2.5 */
#define VDD_25_26 (1 << 13) /* VDD voltage 2.5 ~ 2.6 */
#define VDD_26_27 (1 << 14) /* VDD voltage 2.6 ~ 2.7 */
#define VDD_27_28 (1 << 15) /* VDD voltage 2.7 ~ 2.8 */
#define VDD_28_29 (1 << 16) /* VDD voltage 2.8 ~ 2.9 */
#define VDD_29_30 (1 << 17) /* VDD voltage 2.9 ~ 3.0 */
#define VDD_30_31 (1 << 18) /* VDD voltage 3.0 ~ 3.1 */
#define VDD_31_32 (1 << 19) /* VDD voltage 3.1 ~ 3.2 */
#define VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */
#define VDD_33_34 (1 << 21) /* VDD voltage 3.3 ~ 3.4 */
#define VDD_34_35 (1 << 22) /* VDD voltage 3.4 ~ 3.5 */
#define VDD_35_36 (1 << 23) /* VDD voltage 3.5 ~ 3.6 */
rt_uint32_t flags; /* define device capabilities */
#define MMCSD_BUSWIDTH_4 (1 << 0)
#define MMCSD_BUSWIDTH_8 (1 << 1)
#define MMCSD_MUTBLKWRITE (1 << 2)
#define MMCSD_HOST_IS_SPI (1 << 3)
#define controller_is_spi(host) (host->flags & MMCSD_HOST_IS_SPI)
#define MMCSD_SUP_SDIO_IRQ (1 << 4) /* support signal pending SDIO IRQs */
#define MMCSD_SUP_HIGHSPEED (1 << 5) /* support high speed SDR*/
#define MMCSD_SUP_DDR_3V3 (1 << 6)
#define MMCSD_SUP_DDR_1V8 (1 << 7)
#define MMCSD_SUP_DDR_1V2 (1 << 8)
#define MMCSD_SUP_HIGHSPEED_DDR (MMCSD_SUP_DDR_3V3 | MMCSD_SUP_DDR_1V8 | MMCSD_SUP_DDR_1V2)/* HIGH SPEED DDR*/
#define MMCSD_SUP_HS200_1V8 (1 << 9)
#define MMCSD_SUP_HS200_1V2 (1 << 10)
#define MMCSD_SUP_HS200 (MMCSD_SUP_HS200_1V2 | MMCSD_SUP_HS200_1V8) /* hs200 sdr */
#define MMCSD_SUP_NONREMOVABLE (1 << 11)
rt_uint32_t max_seg_size; /* maximum size of one dma segment */
rt_uint32_t max_dma_segs; /* maximum number of dma segments in one request */
rt_uint32_t max_blk_size; /* maximum block size */
rt_uint32_t max_blk_count; /* maximum block count */
rt_uint32_t id; /* Assigned host id */
rt_uint32_t spi_use_crc;
struct rt_mutex bus_lock;
struct rt_semaphore sem_ack;
rt_uint32_t sdio_irq_num;
struct rt_semaphore *sdio_irq_sem;
struct rt_thread *sdio_irq_thread;
void *private_data;
};
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-05 Bernard the first version
* 2011-04-02 prife add mark_badblock and check_block
*/
/*
* COPYRIGHT (C) 2012, Shanghai Real Thread
*/
#ifndef __MTD_NAND_H__
#define __MTD_NAND_H__
#include <rtthread.h>
struct rt_mtd_nand_driver_ops;
#define RT_MTD_NAND_DEVICE(device) ((struct rt_mtd_nand_device*)(device))
#define RT_MTD_EOK 0 /* NO error */
#define RT_MTD_EECC 101 /* ECC error */
#define RT_MTD_EBUSY 102 /* hardware busy */
#define RT_MTD_EIO 103 /* generic IO issue */
#define RT_MTD_ENOMEM 104 /* out of memory */
#define RT_MTD_ESRC 105 /* source issue */
#define RT_MTD_EECC_CORRECT 106 /* ECC error but correct */
struct rt_mtd_nand_device
{
struct rt_device parent;
rt_uint16_t page_size; /* The Page size in the flash */
rt_uint16_t oob_size; /* Out of bank size */
rt_uint16_t oob_free; /* the free area in oob that flash driver not use */
rt_uint16_t plane_num; /* the number of plane in the NAND Flash */
rt_uint32_t pages_per_block; /* The number of page a block */
rt_uint16_t block_total;
/* Only be touched by driver */
rt_uint32_t block_start; /* The start of available block*/
rt_uint32_t block_end; /* The end of available block */
/* operations interface */
const struct rt_mtd_nand_driver_ops *ops;
void *priv;
};
typedef struct rt_mtd_nand_device* rt_mtd_nand_t;
struct rt_mtd_nand_driver_ops
{
rt_err_t (*read_id)(struct rt_mtd_nand_device *device);
rt_err_t (*read_page)(struct rt_mtd_nand_device *device,
rt_off_t page,
rt_uint8_t *data, rt_uint32_t data_len,
rt_uint8_t *spare, rt_uint32_t spare_len);
rt_err_t (*write_page)(struct rt_mtd_nand_device *device,
rt_off_t page,
const rt_uint8_t *data, rt_uint32_t data_len,
const rt_uint8_t *spare, rt_uint32_t spare_len);
rt_err_t (*move_page)(struct rt_mtd_nand_device *device, rt_off_t src_page, rt_off_t dst_page);
rt_err_t (*erase_block)(struct rt_mtd_nand_device *device, rt_uint32_t block);
rt_err_t (*check_block)(struct rt_mtd_nand_device *device, rt_uint32_t block);
rt_err_t (*mark_badblock)(struct rt_mtd_nand_device *device, rt_uint32_t block);
};
rt_err_t rt_mtd_nand_register_device(const char *name, struct rt_mtd_nand_device *device);
rt_uint32_t rt_mtd_nand_read_id(struct rt_mtd_nand_device *device);
rt_err_t rt_mtd_nand_read(
struct rt_mtd_nand_device *device,
rt_off_t page,
rt_uint8_t *data, rt_uint32_t data_len,
rt_uint8_t *spare, rt_uint32_t spare_len);
rt_err_t rt_mtd_nand_write(
struct rt_mtd_nand_device *device,
rt_off_t page,
const rt_uint8_t *data, rt_uint32_t data_len,
const rt_uint8_t *spare, rt_uint32_t spare_len);
rt_err_t rt_mtd_nand_move_page(struct rt_mtd_nand_device *device,
rt_off_t src_page, rt_off_t dst_page);
rt_err_t rt_mtd_nand_erase_block(struct rt_mtd_nand_device *device, rt_uint32_t block);
rt_err_t rt_mtd_nand_check_block(struct rt_mtd_nand_device *device, rt_uint32_t block);
rt_err_t rt_mtd_nand_mark_badblock(struct rt_mtd_nand_device *device, rt_uint32_t block);
#endif /* MTD_NAND_H_ */

View file

@ -0,0 +1,50 @@
/*
* COPYRIGHT (C) 2011-2023, Real-Thread Information Technology Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-5-30 Bernard the first version
*/
#ifndef __MTD_NOR_H__
#define __MTD_NOR_H__
#include <rtthread.h>
struct rt_mtd_nor_driver_ops;
#define RT_MTD_NOR_DEVICE(device) ((struct rt_mtd_nor_device*)(device))
struct rt_mtd_nor_device
{
struct rt_device parent;
rt_uint32_t block_size; /* The Block size in the flash */
rt_uint32_t block_start; /* The start of available block*/
rt_uint32_t block_end; /* The end of available block */
/* operations interface */
const struct rt_mtd_nor_driver_ops* ops;
};
struct rt_mtd_nor_driver_ops
{
rt_err_t (*read_id) (struct rt_mtd_nor_device* device);
rt_ssize_t (*read) (struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint8_t* data, rt_size_t length);
rt_ssize_t (*write) (struct rt_mtd_nor_device* device, rt_off_t offset, const rt_uint8_t* data, rt_size_t length);
rt_err_t (*erase_block)(struct rt_mtd_nor_device* device, rt_off_t offset, rt_size_t length);
};
rt_err_t rt_mtd_nor_register_device(const char* name, struct rt_mtd_nor_device* device);
rt_uint32_t rt_mtd_nor_read_id(struct rt_mtd_nor_device* device);
rt_ssize_t rt_mtd_nor_read(struct rt_mtd_nor_device* device,
rt_off_t offset, rt_uint8_t* data, rt_size_t length);
rt_ssize_t rt_mtd_nor_write(struct rt_mtd_nor_device* device,
rt_off_t offset, const rt_uint8_t* data, rt_size_t length);
rt_err_t rt_mtd_nor_erase_block(struct rt_mtd_nor_device* device,
rt_off_t offset, rt_size_t length);
#endif

View file

@ -0,0 +1,71 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-10-14 wangqiang the first version
* 2022-08-17 xjy198903 add 1000M definition
*/
#ifndef __PHY_H__
#define __PHY_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C"
{
#endif
/* Defines the PHY link speed. This is align with the speed for MAC. */
#define PHY_SPEED_10M 0U /* PHY 10M speed. */
#define PHY_SPEED_100M 1U /* PHY 100M speed. */
#define PHY_SPEED_1000M 2U /* PHY 1000M speed. */
/* Defines the PHY link duplex. */
#define PHY_HALF_DUPLEX 0U /* PHY half duplex. */
#define PHY_FULL_DUPLEX 1U /* PHY full duplex. */
/*! @brief Defines the PHY loopback mode. */
#define PHY_LOCAL_LOOP 0U /* PHY local loopback. */
#define PHY_REMOTE_LOOP 1U /* PHY remote loopback. */
#define PHY_STATUS_OK 0U
#define PHY_STATUS_FAIL 1U
#define PHY_STATUS_TIMEOUT 2U
typedef struct rt_phy_msg
{
rt_uint32_t reg;
rt_uint32_t value;
}rt_phy_msg_t;
typedef struct rt_phy_device
{
struct rt_device parent;
struct rt_mdio_bus *bus;
rt_uint32_t addr;
struct rt_phy_ops *ops;
}rt_phy_t;
typedef rt_int32_t rt_phy_status;
struct rt_phy_ops
{
rt_phy_status (*init)(void *object, rt_uint32_t phy_addr, rt_uint32_t src_clock_hz);
rt_phy_status (*read)(rt_uint32_t reg, rt_uint32_t *data);
rt_phy_status (*write)(rt_uint32_t reg, rt_uint32_t data);
rt_phy_status (*loopback)(rt_uint32_t mode, rt_uint32_t speed, rt_bool_t enable);
rt_phy_status (*get_link_status)(rt_bool_t *status);
rt_phy_status (*get_link_speed_duplex)(rt_uint32_t *speed, rt_uint32_t *duplex);
};
rt_err_t rt_hw_phy_register(struct rt_phy_device *phy, const char *name);
#ifdef __cplusplus
}
#endif
#endif /* __PHY_H__*/

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-10-14 wangqiang the first version
*/
#ifndef __MDIO_H__
#define __MDIO_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C"
{
#endif
struct rt_mdio_bus_ops
{
rt_bool_t (*init)(void *bus, rt_uint32_t src_clock_hz);
rt_size_t (*read)(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size);
rt_size_t (*write)(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size);
rt_bool_t (*uninit)(void *bus);
};
struct rt_mdio_bus
{
void *hw_obj;
char *name;
struct rt_mdio_bus_ops *ops;
};
typedef struct rt_mdio_bus rt_mdio_t;
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2015-01-20 Bernard the first version
* 2017-10-20 ZYH add mode open drain and input pull down
*/
#ifndef PIN_H__
#define PIN_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
/* pin device and operations for RT-Thread */
struct rt_device_pin
{
struct rt_device parent;
const struct rt_pin_ops *ops;
};
#define PIN_NONE (-1)
#define PIN_LOW 0x00
#define PIN_HIGH 0x01
#define PIN_MODE_OUTPUT 0x00
#define PIN_MODE_INPUT 0x01
#define PIN_MODE_INPUT_PULLUP 0x02
#define PIN_MODE_INPUT_PULLDOWN 0x03
#define PIN_MODE_OUTPUT_OD 0x04
#define PIN_IRQ_MODE_RISING 0x00
#define PIN_IRQ_MODE_FALLING 0x01
#define PIN_IRQ_MODE_RISING_FALLING 0x02
#define PIN_IRQ_MODE_HIGH_LEVEL 0x03
#define PIN_IRQ_MODE_LOW_LEVEL 0x04
#define PIN_IRQ_DISABLE 0x00
#define PIN_IRQ_ENABLE 0x01
#define PIN_IRQ_PIN_NONE PIN_NONE
struct rt_device_pin_mode
{
rt_base_t pin;
rt_uint8_t mode; /* e.g. PIN_MODE_OUTPUT */
};
struct rt_device_pin_value
{
rt_base_t pin;
rt_uint8_t value; /* PIN_LOW or PIN_HIGH */
};
struct rt_pin_irq_hdr
{
rt_base_t pin;
rt_uint8_t mode; /* e.g. PIN_IRQ_MODE_RISING */
void (*hdr)(void *args);
void *args;
};
struct rt_pin_ops
{
void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_uint8_t mode);
void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_uint8_t value);
rt_int8_t (*pin_read)(struct rt_device *device, rt_base_t pin);
rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_base_t pin,
rt_uint8_t mode, void (*hdr)(void *args), void *args);
rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_base_t pin);
rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled);
rt_base_t (*pin_get)(const char *name);
};
int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data);
void rt_pin_mode(rt_base_t pin, rt_uint8_t mode);
void rt_pin_write(rt_base_t pin, rt_uint8_t value);
rt_int8_t rt_pin_read(rt_base_t pin);
rt_base_t rt_pin_get(const char *name);
rt_err_t rt_pin_attach_irq(rt_base_t pin, rt_uint8_t mode,
void (*hdr)(void *args), void *args);
rt_err_t rt_pin_detach_irq(rt_base_t pin);
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint8_t enabled);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,229 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-06-02 Bernard the first version
* 2018-08-02 Tanek split run and sleep modes, support custom mode
* 2019-04-28 Zero-Free improve PM mode and device ops interface
* 2020-11-23 zhangsz update pm mode select
* 2020-11-27 zhangsz update pm 2.0
*/
#ifndef __PM_H__
#define __PM_H__
#include <stdint.h>
#include <rtthread.h>
#include <drivers/lptimer.h>
/* All modes used for rt_pm_request() and rt_pm_release() */
enum
{
/* sleep modes */
PM_SLEEP_MODE_NONE = 0,
PM_SLEEP_MODE_IDLE,
PM_SLEEP_MODE_LIGHT,
PM_SLEEP_MODE_DEEP,
PM_SLEEP_MODE_STANDBY,
PM_SLEEP_MODE_SHUTDOWN,
PM_SLEEP_MODE_MAX,
};
enum
{
/* run modes*/
PM_RUN_MODE_HIGH_SPEED = 0,
PM_RUN_MODE_NORMAL_SPEED,
PM_RUN_MODE_MEDIUM_SPEED,
PM_RUN_MODE_LOW_SPEED,
PM_RUN_MODE_MAX,
};
enum
{
RT_PM_FREQUENCY_PENDING = 0x01,
};
/* The name of all modes used in the msh command "pm_dump" */
#define PM_SLEEP_MODE_NAMES \
{ \
"None Mode", \
"Idle Mode", \
"LightSleep Mode", \
"DeepSleep Mode", \
"Standby Mode", \
"Shutdown Mode", \
}
#define PM_RUN_MODE_NAMES \
{ \
"High Speed", \
"Normal Speed", \
"Medium Speed", \
"Low Mode", \
}
#ifndef PM_USING_CUSTOM_CONFIG
/**
* Modules used for
* pm_module_request(PM_BOARD_ID, PM_SLEEP_MODE_IDLE)
* pm_module_release(PM_BOARD_ID, PM_SLEEP_MODE_IDLE)
* pm_module_release_all(PM_BOARD_ID, PM_SLEEP_MODE_IDLE)
*/
enum pm_module_id {
PM_NONE_ID = 0,
PM_POWER_ID,
PM_BOARD_ID,
PM_BSP_ID,
PM_MAIN_ID,
PM_PMS_ID,
PM_PMC_ID,
PM_TASK_ID,
PM_SPI_ID,
PM_I2C_ID,
PM_UART_ID,
PM_CAN_ID,
PM_ETH_ID,
PM_SENSOR_ID,
PM_LCD_ID,
PM_KEY_ID,
PM_TP_ID,
PM_MODULE_MAX_ID, /* enum must! */
};
#else
#include <pm_cfg.h>
#endif /* PM_USING_CUSTOM_CONFIG */
#ifndef RT_PM_DEFAULT_SLEEP_MODE
#define RT_PM_DEFAULT_SLEEP_MODE PM_SLEEP_MODE_NONE
#endif
#ifndef RT_PM_DEFAULT_DEEPSLEEP_MODE
#define RT_PM_DEFAULT_DEEPSLEEP_MODE PM_SLEEP_MODE_DEEP
#endif
#ifndef RT_PM_DEFAULT_RUN_MODE
#define RT_PM_DEFAULT_RUN_MODE PM_RUN_MODE_NORMAL_SPEED
#endif
/**
* device control flag to request or release power
*/
#define RT_PM_DEVICE_CTRL_RELEASE (RT_DEVICE_CTRL_BASE(PM) + 0x00)
#define RT_PM_DEVICE_CTRL_REQUEST (RT_DEVICE_CTRL_BASE(PM) + 0x01)
struct rt_pm;
/**
* low power mode operations
*/
struct rt_pm_ops
{
void (*sleep)(struct rt_pm *pm, rt_uint8_t mode);
void (*run)(struct rt_pm *pm, rt_uint8_t mode);
void (*timer_start)(struct rt_pm *pm, rt_uint32_t timeout);
void (*timer_stop)(struct rt_pm *pm);
rt_tick_t (*timer_get_tick)(struct rt_pm *pm);
};
struct rt_device_pm_ops
{
int (*suspend)(const struct rt_device *device, rt_uint8_t mode);
void (*resume)(const struct rt_device *device, rt_uint8_t mode);
int (*frequency_change)(const struct rt_device *device, rt_uint8_t mode);
};
struct rt_device_pm
{
const struct rt_device *device;
const struct rt_device_pm_ops *ops;
};
struct rt_pm_module
{
rt_uint8_t req_status;
rt_bool_t busy_flag;
rt_uint32_t timeout;
rt_uint32_t start_time;
};
/**
* power management
*/
struct rt_pm
{
struct rt_device parent;
/* modes */
rt_uint8_t modes[PM_SLEEP_MODE_MAX];
rt_uint8_t sleep_mode; /* current sleep mode */
rt_uint8_t run_mode; /* current running mode */
/* modules request status*/
struct rt_pm_module module_status[PM_MODULE_MAX_ID];
/* sleep request table */
rt_uint32_t sleep_status[PM_SLEEP_MODE_MAX - 1][(PM_MODULE_MAX_ID + 31) / 32];
/* the list of device, which has PM feature */
rt_uint8_t device_pm_number;
struct rt_device_pm *device_pm;
/* if the mode has timer, the corresponding bit is 1*/
rt_uint8_t timer_mask;
rt_uint8_t flags;
const struct rt_pm_ops *ops;
};
enum
{
RT_PM_ENTER_SLEEP = 0,
RT_PM_EXIT_SLEEP,
};
struct rt_pm_notify
{
void (*notify)(rt_uint8_t event, rt_uint8_t mode, void *data);
void *data;
};
void rt_pm_request(rt_uint8_t sleep_mode);
void rt_pm_release(rt_uint8_t sleep_mode);
void rt_pm_release_all(rt_uint8_t sleep_mode);
int rt_pm_run_enter(rt_uint8_t run_mode);
void rt_pm_device_register(struct rt_device *device, const struct rt_device_pm_ops *ops);
void rt_pm_device_unregister(struct rt_device *device);
void rt_pm_notify_set(void (*notify)(rt_uint8_t event, rt_uint8_t mode, void *data), void *data);
void rt_pm_default_set(rt_uint8_t sleep_mode);
void rt_system_pm_init(const struct rt_pm_ops *ops,
rt_uint8_t timer_mask,
void *user_data);
void rt_pm_module_request(uint8_t module_id, rt_uint8_t sleep_mode);
void rt_pm_module_release(uint8_t module_id, rt_uint8_t sleep_mode);
void rt_pm_module_release_all(uint8_t module_id, rt_uint8_t sleep_mode);
void rt_pm_module_delay_sleep(rt_uint8_t module_id, rt_tick_t timeout);
rt_uint32_t rt_pm_module_get_status(void);
rt_uint8_t rt_pm_get_sleep_mode(void);
struct rt_pm *rt_pm_get_handle(void);
/* sleep : request or release */
void rt_pm_sleep_request(rt_uint16_t module_id, rt_uint8_t mode);
void rt_pm_sleep_release(rt_uint16_t module_id, rt_uint8_t mode);
void rt_pm_sleep_none_request(rt_uint16_t module_id);
void rt_pm_sleep_none_release(rt_uint16_t module_id);
void rt_pm_sleep_idle_request(rt_uint16_t module_id);
void rt_pm_sleep_idle_release(rt_uint16_t module_id);
void rt_pm_sleep_light_request(rt_uint16_t module_id);
void rt_pm_sleep_light_release(rt_uint16_t module_id);
#endif /* __PM_H__ */

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-08-08 balanceTWK the first version
*/
#ifndef __PULSE_ENCODER_H__
#define __PULSE_ENCODER_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
/* pulse_encoder control command */
#define PULSE_ENCODER_CMD_GET_TYPE (128 + 0) /* get a pulse_encoder type information */
#define PULSE_ENCODER_CMD_ENABLE (128 + 1) /* enable pulse_encoder */
#define PULSE_ENCODER_CMD_DISABLE (128 + 2) /* disable pulse_encoder */
#define PULSE_ENCODER_CMD_CLEAR_COUNT (128 + 3) /* clear pulse_encoder count */
/* pulse_encoder type */
enum rt_pulse_encoder_type
{
UNKNOWN_PULSE_ENCODER_TYPE = 0x00, /* Unknown pulse_encoder type */
SINGLE_PHASE_PULSE_ENCODER, /* single phase pulse_encoder */
AB_PHASE_PULSE_ENCODER /* two phase pulse_encoder */
};
struct rt_pulse_encoder_device;
struct rt_pulse_encoder_ops
{
rt_err_t (*init)(struct rt_pulse_encoder_device *pulse_encoder);
rt_int32_t (*get_count)(struct rt_pulse_encoder_device *pulse_encoder);
rt_err_t (*clear_count)(struct rt_pulse_encoder_device *pulse_encoder);
rt_err_t (*control)(struct rt_pulse_encoder_device *pulse_encoder, rt_uint32_t cmd, void *args);
};
struct rt_pulse_encoder_device
{
struct rt_device parent;
const struct rt_pulse_encoder_ops *ops;
enum rt_pulse_encoder_type type;
};
rt_err_t rt_device_pulse_encoder_register(struct rt_pulse_encoder_device *pulse_encoder, const char *name, void *user_data);
#ifdef __cplusplus
}
#endif
#endif /* __PULSE_ENCODER_H__ */

View file

@ -0,0 +1,18 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-10-13 flybreak the first version
*/
#ifndef __RT_DEV_BUS_H__
#define __RT_DEV_BUS_H__
#include <rtthread.h>
rt_device_t rt_device_bus_create(char *name, int attach_size);
rt_err_t rt_device_bus_destroy(rt_device_t dev);
#endif /* __RT_BUS_H__ */

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-05-07 aozima the first version
* 2022-09-24 yuqi add phase and dead time configuration
*/
#ifndef __DRV_PWM_H_INCLUDE__
#define __DRV_PWM_H_INCLUDE__
#include <rtthread.h>
#define PWM_CMD_ENABLE (RT_DEVICE_CTRL_BASE(PWM) + 0)
#define PWM_CMD_DISABLE (RT_DEVICE_CTRL_BASE(PWM) + 1)
#define PWM_CMD_SET (RT_DEVICE_CTRL_BASE(PWM) + 2)
#define PWM_CMD_GET (RT_DEVICE_CTRL_BASE(PWM) + 3)
#define PWMN_CMD_ENABLE (RT_DEVICE_CTRL_BASE(PWM) + 4)
#define PWMN_CMD_DISABLE (RT_DEVICE_CTRL_BASE(PWM) + 5)
#define PWM_CMD_SET_PERIOD (RT_DEVICE_CTRL_BASE(PWM) + 6)
#define PWM_CMD_SET_PULSE (RT_DEVICE_CTRL_BASE(PWM) + 7)
#define PWM_CMD_SET_DEAD_TIME (RT_DEVICE_CTRL_BASE(PWM) + 8)
#define PWM_CMD_SET_PHASE (RT_DEVICE_CTRL_BASE(PWM) + 9)
#define PWM_CMD_ENABLE_IRQ (RT_DEVICE_CTRL_BASE(PWM) + 10)
#define PWM_CMD_DISABLE_IRQ (RT_DEVICE_CTRL_BASE(PWM) + 11)
struct rt_pwm_configuration
{
rt_uint32_t channel; /* 0 ~ n or 0 ~ -n, which depends on specific MCU requirements */
rt_uint32_t period; /* unit:ns 1ns~4.29s:1Ghz~0.23hz */
rt_uint32_t pulse; /* unit:ns (pulse<=period) */
rt_uint32_t dead_time; /* unit:ns */
rt_uint32_t phase; /*unit: degree, 0~360, which is the phase of pwm output, */
/*
* RT_TRUE : The channel of pwm is complememtary.
* RT_FALSE : The channel of pwm is nomal.
*/
rt_bool_t complementary;
};
struct rt_device_pwm;
struct rt_pwm_ops
{
rt_err_t (*control)(struct rt_device_pwm *device, int cmd, void *arg);
};
struct rt_device_pwm
{
struct rt_device parent;
const struct rt_pwm_ops *ops;
};
rt_err_t rt_device_pwm_register(struct rt_device_pwm *device, const char *name, const struct rt_pwm_ops *ops, const void *user_data);
rt_err_t rt_pwm_enable(struct rt_device_pwm *device, int channel);
rt_err_t rt_pwm_disable(struct rt_device_pwm *device, int channel);
rt_err_t rt_pwm_set(struct rt_device_pwm *device, int channel, rt_uint32_t period, rt_uint32_t pulse);
rt_err_t rt_pwm_set_period(struct rt_device_pwm *device, int channel, rt_uint32_t period);
rt_err_t rt_pwm_set_pulse(struct rt_device_pwm *device, int channel, rt_uint32_t pulse);
rt_err_t rt_pwm_set_dead_time(struct rt_device_pwm *device, int channel, rt_uint32_t dead_time);
rt_err_t rt_pwm_set_phase(struct rt_device_pwm *device, int channel, rt_uint32_t phase);
#endif /* __DRV_PWM_H_INCLUDE__ */

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-08-13 balanceTWK first version.
*/
#ifndef __RT_INPUT_CAPTURE_H__
#define __RT_INPUT_CAPTURE_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
/* capture control command */
#define INPUTCAPTURE_CMD_CLEAR_BUF (128 + 0) /* clear capture buf */
#define INPUTCAPTURE_CMD_SET_WATERMARK (128 + 1) /* Set the callback threshold */
struct rt_inputcapture_data
{
rt_uint32_t pulsewidth_us;
rt_bool_t is_high;
};
struct rt_inputcapture_device
{
struct rt_device parent;
const struct rt_inputcapture_ops *ops;
struct rt_ringbuffer *ringbuff;
rt_size_t watermark;
};
/**
* capture operators
*/
struct rt_inputcapture_ops
{
rt_err_t (*init)(struct rt_inputcapture_device *inputcapture);
rt_err_t (*open)(struct rt_inputcapture_device *inputcapture);
rt_err_t (*close)(struct rt_inputcapture_device *inputcapture);
rt_err_t (*get_pulsewidth)(struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us);
};
void rt_hw_inputcapture_isr(struct rt_inputcapture_device *inputcapture, rt_bool_t level);
rt_err_t rt_device_inputcapture_register(struct rt_inputcapture_device *inputcapture,
const char *name,
void *data);
#ifdef __cplusplus
}
#endif
#endif /* __RT_INPUT_CAPTURE_H__ */

View file

@ -0,0 +1,71 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-10-10 aozima first version.
* 2021-06-11 iysheng implement RTC framework V2.0
* 2021-07-30 Meco Man move rtc_core.h to rtc.h
* 2022-04-05 tyx add timestamp function
*/
#ifndef __RTC_H__
#define __RTC_H__
#include <rtdef.h>
#include <sys/time.h>
#ifdef __cplusplus
extern "C" {
#endif
#define RT_DEVICE_CTRL_RTC_GET_TIME (RT_DEVICE_CTRL_BASE(RTC) + 0x01) /**< get second time */
#define RT_DEVICE_CTRL_RTC_SET_TIME (RT_DEVICE_CTRL_BASE(RTC) + 0x02) /**< set second time */
#define RT_DEVICE_CTRL_RTC_GET_TIMEVAL (RT_DEVICE_CTRL_BASE(RTC) + 0x03) /**< get timeval for gettimeofday */
#define RT_DEVICE_CTRL_RTC_SET_TIMEVAL (RT_DEVICE_CTRL_BASE(RTC) + 0x04) /**< set timeval for gettimeofday */
#define RT_DEVICE_CTRL_RTC_GET_ALARM (RT_DEVICE_CTRL_BASE(RTC) + 0x05) /**< get alarm */
#define RT_DEVICE_CTRL_RTC_SET_ALARM (RT_DEVICE_CTRL_BASE(RTC) + 0x06) /**< set alarm */
/* used for alarm function */
struct rt_rtc_wkalarm
{
rt_bool_t enable; /* 0 = alarm disabled, 1 = alarm enabled */
rt_int32_t tm_sec; /* alarm at tm_sec */
rt_int32_t tm_min; /* alarm at tm_min */
rt_int32_t tm_hour; /* alarm at tm_hour */
};
struct rt_rtc_ops
{
rt_err_t (*init)(void);
rt_err_t (*get_secs)(time_t *sec);
rt_err_t (*set_secs)(time_t *sec);
rt_err_t (*get_alarm)(struct rt_rtc_wkalarm *alarm);
rt_err_t (*set_alarm)(struct rt_rtc_wkalarm *alarm);
rt_err_t (*get_timeval)(struct timeval *tv);
rt_err_t (*set_timeval)(struct timeval *tv);
};
typedef struct rt_rtc_device
{
struct rt_device parent;
const struct rt_rtc_ops *ops;
} rt_rtc_dev_t;
rt_err_t rt_hw_rtc_register(rt_rtc_dev_t *rtc,
const char *name,
rt_uint32_t flag,
void *data);
rt_err_t set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day);
rt_err_t set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second);
rt_err_t set_timestamp(time_t timestamp);
rt_err_t get_timestamp(time_t *timestamp);
#ifdef __cplusplus
}
#endif
#endif /* __RTC_H__ */

View file

@ -0,0 +1,33 @@
/*
* 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
*/
#ifndef __SD_H__
#define __SD_H__
#include <rtthread.h>
#include <drivers/mmcsd_host.h>
#ifdef __cplusplus
extern "C" {
#endif
rt_err_t mmcsd_send_if_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr);
rt_err_t mmcsd_send_app_op_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr, rt_uint32_t *rocr);
rt_err_t mmcsd_get_card_addr(struct rt_mmcsd_host *host, rt_uint32_t *rca);
rt_int32_t mmcsd_get_scr(struct rt_mmcsd_card *card, rt_uint32_t *scr);
rt_int32_t init_sd(struct rt_mmcsd_host *host, rt_uint32_t ocr);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,231 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-01-15 weety first version
*/
#ifndef __SDIO_H__
#define __SDIO_H__
#include <rtthread.h>
#include <drivers/mmcsd_host.h>
#include <drivers/mmcsd_card.h>
#include <drivers/sdio_func_ids.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Card Common Control Registers (CCCR)
*/
#define SDIO_REG_CCCR_CCCR_REV 0x00
#define SDIO_CCCR_REV_1_00 0 /* CCCR/FBR Version 1.00 */
#define SDIO_CCCR_REV_1_10 1 /* CCCR/FBR Version 1.10 */
#define SDIO_CCCR_REV_1_20 2 /* CCCR/FBR Version 1.20 */
#define SDIO_CCCR_REV_3_00 3 /* CCCR/FBR Version 2.00 */
#define SDIO_SDIO_REV_1_00 0 /* SDIO Spec Version 1.00 */
#define SDIO_SDIO_REV_1_10 1 /* SDIO Spec Version 1.10 */
#define SDIO_SDIO_REV_1_20 2 /* SDIO Spec Version 1.20 */
#define SDIO_SDIO_REV_2_00 3 /* SDIO Spec Version 2.00 */
#define SDIO_REG_CCCR_SD_REV 0x01
#define SDIO_SD_REV_1_01 0 /* SD Physical Spec Version 1.01 */
#define SDIO_SD_REV_1_10 1 /* SD Physical Spec Version 1.10 */
#define SDIO_SD_REV_2_00 2 /* SD Physical Spec Version 2.00 */
#define SDIO_REG_CCCR_IO_EN 0x02
#define SDIO_REG_CCCR_IO_RDY 0x03
#define SDIO_REG_CCCR_INT_EN 0x04 /* Function/Master Interrupt Enable */
#define SDIO_REG_CCCR_INT_PEND 0x05 /* Function Interrupt Pending */
#define SDIO_REG_CCCR_IO_ABORT 0x06 /* function abort/card reset */
#define SDIO_REG_CCCR_BUS_IF 0x07 /* bus interface controls */
#define SDIO_BUS_WIDTH_1BIT 0x00
#define SDIO_BUS_WIDTH_4BIT 0x02
#define SDIO_BUS_ECSI 0x20 /* Enable continuous SPI interrupt */
#define SDIO_BUS_SCSI 0x40 /* Support continuous SPI interrupt */
#define SDIO_BUS_ASYNC_INT 0x20
#define SDIO_BUS_CD_DISABLE 0x80 /* disable pull-up on DAT3 (pin 1) */
#define SDIO_REG_CCCR_CARD_CAPS 0x08
#define SDIO_CCCR_CAP_SDC 0x01 /* can do CMD52 while data transfer */
#define SDIO_CCCR_CAP_SMB 0x02 /* can do multi-block xfers (CMD53) */
#define SDIO_CCCR_CAP_SRW 0x04 /* supports read-wait protocol */
#define SDIO_CCCR_CAP_SBS 0x08 /* supports suspend/resume */
#define SDIO_CCCR_CAP_S4MI 0x10 /* interrupt during 4-bit CMD53 */
#define SDIO_CCCR_CAP_E4MI 0x20 /* enable ints during 4-bit CMD53 */
#define SDIO_CCCR_CAP_LSC 0x40 /* low speed card */
#define SDIO_CCCR_CAP_4BLS 0x80 /* 4 bit low speed card */
#define SDIO_REG_CCCR_CIS_PTR 0x09 /* common CIS pointer (3 bytes) */
/* Following 4 regs are valid only if SBS is set */
#define SDIO_REG_CCCR_BUS_SUSPEND 0x0c
#define SDIO_REG_CCCR_FUNC_SEL 0x0d
#define SDIO_REG_CCCR_EXEC_FLAG 0x0e
#define SDIO_REG_CCCR_READY_FLAG 0x0f
#define SDIO_REG_CCCR_FN0_BLKSIZE 0x10 /* 2bytes, 0x10~0x11 */
#define SDIO_REG_CCCR_POWER_CTRL 0x12
#define SDIO_POWER_SMPC 0x01 /* Supports Master Power Control */
#define SDIO_POWER_EMPC 0x02 /* Enable Master Power Control */
#define SDIO_REG_CCCR_SPEED 0x13
#define SDIO_SPEED_SHS 0x01 /* Supports High-Speed mode */
#define SDIO_SPEED_EHS 0x02 /* Enable High-Speed mode */
/*
* Function Basic Registers (FBR)
*/
#define SDIO_REG_FBR_BASE(f) ((f) * 0x100) /* base of function f's FBRs */
#define SDIO_REG_FBR_STD_FUNC_IF 0x00
#define SDIO_FBR_SUPPORTS_CSA 0x40 /* supports Code Storage Area */
#define SDIO_FBR_ENABLE_CSA 0x80 /* enable Code Storage Area */
#define SDIO_REG_FBR_STD_IF_EXT 0x01
#define SDIO_REG_FBR_POWER 0x02
#define SDIO_FBR_POWER_SPS 0x01 /* Supports Power Selection */
#define SDIO_FBR_POWER_EPS 0x02 /* Enable (low) Power Selection */
#define SDIO_REG_FBR_CIS 0x09 /* CIS pointer (3 bytes) */
#define SDIO_REG_FBR_CSA 0x0C /* CSA pointer (3 bytes) */
#define SDIO_REG_FBR_CSA_DATA 0x0F
#define SDIO_REG_FBR_BLKSIZE 0x10 /* block size (2 bytes) */
/* SDIO CIS Tuple code */
#define CISTPL_NULL 0x00
#define CISTPL_CHECKSUM 0x10
#define CISTPL_VERS_1 0x15
#define CISTPL_ALTSTR 0x16
#define CISTPL_MANFID 0x20
#define CISTPL_FUNCID 0x21
#define CISTPL_FUNCE 0x22
#define CISTPL_SDIO_STD 0x91
#define CISTPL_SDIO_EXT 0x92
#define CISTPL_END 0xff
/* SDIO device id */
#define SDIO_ANY_FUNC_ID 0xff
#define SDIO_ANY_MAN_ID 0xffff
#define SDIO_ANY_PROD_ID 0xffff
struct rt_sdio_device_id
{
rt_uint8_t func_code;
rt_uint16_t manufacturer;
rt_uint16_t product;
};
struct rt_sdio_driver
{
char *name;
rt_int32_t (*probe)(struct rt_mmcsd_card *card);
rt_int32_t (*remove)(struct rt_mmcsd_card *card);
struct rt_sdio_device_id *id;
};
rt_int32_t sdio_io_send_op_cond(struct rt_mmcsd_host *host,
rt_uint32_t ocr,
rt_uint32_t *cmd5_resp);
rt_int32_t sdio_io_rw_direct(struct rt_mmcsd_card *card,
rt_int32_t rw,
rt_uint32_t fn,
rt_uint32_t reg_addr,
rt_uint8_t *pdata,
rt_uint8_t raw);
rt_int32_t sdio_io_rw_extended(struct rt_mmcsd_card *card,
rt_int32_t rw,
rt_uint32_t fn,
rt_uint32_t addr,
rt_int32_t op_code,
rt_uint8_t *buf,
rt_uint32_t blocks,
rt_uint32_t blksize);
rt_int32_t sdio_io_rw_extended_block(struct rt_sdio_function *func,
rt_int32_t rw,
rt_uint32_t addr,
rt_int32_t op_code,
rt_uint8_t *buf,
rt_uint32_t len);
rt_uint8_t sdio_io_readb(struct rt_sdio_function *func,
rt_uint32_t reg,
rt_int32_t *err);
rt_int32_t sdio_io_writeb(struct rt_sdio_function *func,
rt_uint32_t reg,
rt_uint8_t data);
rt_uint16_t sdio_io_readw(struct rt_sdio_function *func,
rt_uint32_t addr,
rt_int32_t *err);
rt_int32_t sdio_io_writew(struct rt_sdio_function *func,
rt_uint16_t data,
rt_uint32_t addr);
rt_uint32_t sdio_io_readl(struct rt_sdio_function *func,
rt_uint32_t addr,
rt_int32_t *err);
rt_int32_t sdio_io_writel(struct rt_sdio_function *func,
rt_uint32_t data,
rt_uint32_t addr);
rt_int32_t sdio_io_read_multi_fifo_b(struct rt_sdio_function *func,
rt_uint32_t addr,
rt_uint8_t *buf,
rt_uint32_t len);
rt_int32_t sdio_io_write_multi_fifo_b(struct rt_sdio_function *func,
rt_uint32_t addr,
rt_uint8_t *buf,
rt_uint32_t len);
rt_int32_t sdio_io_read_multi_incr_b(struct rt_sdio_function *func,
rt_uint32_t addr,
rt_uint8_t *buf,
rt_uint32_t len);
rt_int32_t sdio_io_write_multi_incr_b(struct rt_sdio_function *func,
rt_uint32_t addr,
rt_uint8_t *buf,
rt_uint32_t len);
rt_int32_t init_sdio(struct rt_mmcsd_host *host, rt_uint32_t ocr);
rt_int32_t sdio_attach_irq(struct rt_sdio_function *func,
rt_sdio_irq_handler_t *handler);
rt_int32_t sdio_detach_irq(struct rt_sdio_function *func);
void sdio_irq_wakeup(struct rt_mmcsd_host *host);
rt_int32_t sdio_enable_func(struct rt_sdio_function *func);
rt_int32_t sdio_disable_func(struct rt_sdio_function *func);
void sdio_set_drvdata(struct rt_sdio_function *func, void *data);
void* sdio_get_drvdata(struct rt_sdio_function *func);
rt_int32_t sdio_set_block_size(struct rt_sdio_function *func,
rt_uint32_t blksize);
rt_int32_t sdio_register_driver(struct rt_sdio_driver *driver);
rt_int32_t sdio_unregister_driver(struct rt_sdio_driver *driver);
void rt_sdio_init(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-02-26 weety first version
*/
#ifndef __SDIO_FUNC_IDS_H__
#define __SDIO_FUNC_IDS_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Standard SDIO Function Interfaces */
#define SDIO_FUNC_CODE_NONE 0x00 /* Not a SDIO standard interface */
#define SDIO_FUNC_CODE_UART 0x01 /* SDIO Standard UART */
#define SDIO_FUNC_CODE_BT_A 0x02 /* SDIO Type-A for Bluetooth standard interface */
#define SDIO_FUNC_CODE_BT_B 0x03 /* SDIO Type-B for Bluetooth standard interface */
#define SDIO_FUNC_CODE_GPS 0x04 /* SDIO GPS standard interface */
#define SDIO_FUNC_CODE_CAMERA 0x05 /* SDIO Camera standard interface */
#define SDIO_FUNC_CODE_PHS 0x06 /* SDIO PHS standard interface */
#define SDIO_FUNC_CODE_WLAN 0x07 /* SDIO WLAN interface */
#define SDIO_FUNC_CODE_ATA 0x08 /* Embedded SDIO-ATA standard interface */
/* manufacturer id, product io */
#define SDIO_MANUFACTURER_ID_MARVELL 0x02df
#define SDIO_PRODUCT_ID_MARVELL_88W8686 0x9103
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,406 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-01-31 flybreak first version
* 2022-12-17 Meco Man re-implement sensor framework
*/
#ifndef __SENSOR_H__
#define __SENSOR_H__
#include <rtthread.h>
#include "pin.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef RT_USING_RTC
#define rt_sensor_get_ts() time(RT_NULL) /* API for the sensor to get the timestamp */
#else
#define rt_sensor_get_ts() rt_tick_get() /* API for the sensor to get the timestamp */
#endif
#define RT_DEVICE_FLAG_FIFO_RX 0x200 /* Flag to use when the sensor is open by fifo mode */
#define RT_SENSOR_MODULE_MAX (3) /* The maximum number of members of a sensor module */
#define RT_SENSOR_MACRO_GET_NAME(macro) (macro##_STR)
/* Sensor types */
#define RT_SENSOR_TYPE_NONE (0)
#define RT_SENSOR_TYPE_NONE_STR "None"
#define RT_SENSOR_TYPE_ACCE (1)
#define RT_SENSOR_TYPE_ACCE_STR "Accelerometer"
#define RT_SENSOR_TYPE_GYRO (2)
#define RT_SENSOR_TYPE_GYRO_STR "Gyroscope"
#define RT_SENSOR_TYPE_MAG (3)
#define RT_SENSOR_TYPE_MAG_STR "Magnetometer"
#define RT_SENSOR_TYPE_TEMP (4)
#define RT_SENSOR_TYPE_TEMP_STR "Temperature"
#define RT_SENSOR_TYPE_HUMI (5)
#define RT_SENSOR_TYPE_HUMI_STR "Relative Humidity"
#define RT_SENSOR_TYPE_BARO (6)
#define RT_SENSOR_TYPE_BARO_STR "Barometer"
#define RT_SENSOR_TYPE_LIGHT (7)
#define RT_SENSOR_TYPE_LIGHT_STR "Ambient Light"
#define RT_SENSOR_TYPE_PROXIMITY (8)
#define RT_SENSOR_TYPE_PROXIMITY_STR "Proximity"
#define RT_SENSOR_TYPE_HR (9)
#define RT_SENSOR_TYPE_HR_STR "Heart Rate"
#define RT_SENSOR_TYPE_TVOC (10)
#define RT_SENSOR_TYPE_TVOC_STR "TVOC Level"
#define RT_SENSOR_TYPE_NOISE (11)
#define RT_SENSOR_TYPE_NOISE_STR "Noise Loudness"
#define RT_SENSOR_TYPE_STEP (12)
#define RT_SENSOR_TYPE_STEP_STR "Step"
#define RT_SENSOR_TYPE_FORCE (13)
#define RT_SENSOR_TYPE_FORCE_STR "Force"
#define RT_SENSOR_TYPE_DUST (14)
#define RT_SENSOR_TYPE_DUST_STR "Dust"
#define RT_SENSOR_TYPE_ECO2 (15)
#define RT_SENSOR_TYPE_ECO2_STR "eCO2"
#define RT_SENSOR_TYPE_GNSS (16)
#define RT_SENSOR_TYPE_GNSS_STR "GNSS"
#define RT_SENSOR_TYPE_TOF (17)
#define RT_SENSOR_TYPE_TOF_STR "ToF"
#define RT_SENSOR_TYPE_SPO2 (18)
#define RT_SENSOR_TYPE_SPO2_STR "SpO2"
#define RT_SENSOR_TYPE_IAQ (19)
#define RT_SENSOR_TYPE_IAQ_STR "IAQ"
#define RT_SENSOR_TYPE_ETOH (20)
#define RT_SENSOR_TYPE_ETOH_STR "EtOH"
#define RT_SENSOR_TYPE_BP (21)
#define RT_SENSOR_TYPE_BP_STR "Blood Pressure"
#define RT_SENSOR_TYPE_VOLTAGE (22)
#define RT_SENSOR_TYPE_VOLTAGE_STR "Voltage"
#define RT_SENSOR_TYPE_CURRENT (23)
#define RT_SENSOR_TYPE_CURRENT_STR "Current"
/* Sensor vendor types */
#define RT_SENSOR_VENDOR_UNKNOWN (0)
#define RT_SENSOR_VENDOR_UNKNOWN_STR "Unknown"
#define RT_SENSOR_VENDOR_VIRTUAL (1)
#define RT_SENSOR_VENDOR_VIRTUAL_STR "Virtual Sensor"
#define RT_SENSOR_VENDOR_ONCHIP (2)
#define RT_SENSOR_VENDOR_ONCHIP_STR "OnChip"
#define RT_SENSOR_VENDOR_STM (3)
#define RT_SENSOR_VENDOR_STM_STR "STMicroelectronics"
#define RT_SENSOR_VENDOR_BOSCH (4)
#define RT_SENSOR_VENDOR_BOSCH_STR "Bosch"
#define RT_SENSOR_VENDOR_INVENSENSE (5)
#define RT_SENSOR_VENDOR_INVENSENSE_STR "Invensense"
#define RT_SENSOR_VENDOR_SEMTECH (6)
#define RT_SENSOR_VENDOR_SEMTECH_STR "Semtech"
#define RT_SENSOR_VENDOR_GOERTEK (7)
#define RT_SENSOR_VENDOR_GOERTEK_STR "Goertek"
#define RT_SENSOR_VENDOR_MIRAMEMS (8)
#define RT_SENSOR_VENDOR_MIRAMEMS_STR "MiraMEMS"
#define RT_SENSOR_VENDOR_DALLAS (9)
#define RT_SENSOR_VENDOR_DALLAS_STR "Dallas"
#define RT_SENSOR_VENDOR_ASAIR (10)
#define RT_SENSOR_VENDOR_ASAIR_STR "Aosong"
#define RT_SENSOR_VENDOR_SHARP (11)
#define RT_SENSOR_VENDOR_SHARP_STR "Sharp"
#define RT_SENSOR_VENDOR_SENSIRION (12)
#define RT_SENSOR_VENDOR_SENSIRION_STR "Sensirion"
#define RT_SENSOR_VENDOR_TI (13)
#define RT_SENSOR_VENDOR_TI_STR "Texas Instruments"
#define RT_SENSOR_VENDOR_PLANTOWER (14)
#define RT_SENSOR_VENDOR_PLANTOWER_STR "Plantower"
#define RT_SENSOR_VENDOR_AMS (15)
#define RT_SENSOR_VENDOR_AMS_STR "ams-OSRAM AG"
#define RT_SENSOR_VENDOR_MAXIM (16)
#define RT_SENSOR_VENDOR_MAXIM_STR "Maxim Integrated"
#define RT_SENSOR_VENDOR_MELEXIS (17)
#define RT_SENSOR_VENDOR_MELEXIS_STR "Melexis"
#define RT_SENSOR_VENDOR_LSC (18)
#define RT_SENSOR_VENDOR_LSC_STR "Lite On"
/* Sensor unit types */
#define RT_SENSOR_UNIT_NONE (0) /* Dimensionless quantity */
#define RT_SENSOR_UNIT_NONE_STR ""
#define RT_SENSOR_UNIT_MG (1) /* Accelerometer unit: mG */
#define RT_SENSOR_UNIT_MG_STR "mG"
#define RT_SENSOR_UNIT_MDPS (2) /* Gyroscope unit: mdps */
#define RT_SENSOR_UNIT_MDPS_STR "mdps"
#define RT_SENSOR_UNIT_MGAUSS (3) /* Magnetometer unit: mGauss */
#define RT_SENSOR_UNIT_MGAUSS_STR "mGauss"
#define RT_SENSOR_UNIT_LUX (4) /* Ambient light unit: lux */
#define RT_SENSOR_UNIT_LUX_STR "lux"
#define RT_SENSOR_UNIT_M (5) /* Distance unit: m */
#define RT_SENSOR_UNIT_M_STR "m"
#define RT_SENSOR_UNIT_CM (6) /* Distance unit: cm */
#define RT_SENSOR_UNIT_CM_STR "cm"
#define RT_SENSOR_UNIT_MM (7) /* Distance unit: mm */
#define RT_SENSOR_UNIT_MM_STR "mm"
#define RT_SENSOR_UNIT_PA (8) /* Barometer unit: Pa */
#define RT_SENSOR_UNIT_PA_STR "Pa"
#define RT_SENSOR_UNIT_MMHG (9) /* Blood Pressure unit: mmHg */
#define RT_SENSOR_UNIT_MMHG_STR "mmHg"
#define RT_SENSOR_UNIT_PERCENTAGE (10) /* Relative Humidity unit: percentage */
#define RT_SENSOR_UNIT_PERCENTAGE_STR "%"
#define RT_SENSOR_UNIT_PERMILLAGE (11) /* Relative Humidity unit: permillage */
#define RT_SENSOR_UNIT_PERMILLAGE_STR "‰"
#define RT_SENSOR_UNIT_CELSIUS (12) /* Temperature unit: Celsius ℃ */
#define RT_SENSOR_UNIT_CELSIUS_STR "℃"
#define RT_SENSOR_UNIT_FAHRENHEIT (13) /* Temperature unit: Fahrenheit ℉ */
#define RT_SENSOR_UNIT_FAHRENHEIT_STR "℉"
#define RT_SENSOR_UNIT_KELVIN (14) /* Temperature unit: Kelvin K */
#define RT_SENSOR_UNIT_KELVIN_STR "K"
#define RT_SENSOR_UNIT_HZ (15) /* Frequency unit: Hz */
#define RT_SENSOR_UNIT_HZ_STR "Hz"
#define RT_SENSOR_UNIT_V (16) /* Voltage unit: V */
#define RT_SENSOR_UNIT_V_STR "V"
#define RT_SENSOR_UNIT_MV (17) /* Voltage unit: mV */
#define RT_SENSOR_UNIT_MV_STR "mV"
#define RT_SENSOR_UNIT_A (18) /* Current unit: A */
#define RT_SENSOR_UNIT_A_STR "A"
#define RT_SENSOR_UNIT_MA (19) /* Current unit: mA */
#define RT_SENSOR_UNIT_MA_STR "mA"
#define RT_SENSOR_UNIT_N (20) /* Force unit: N */
#define RT_SENSOR_UNIT_N_STR "N"
#define RT_SENSOR_UNIT_MN (21) /* Force unit: mN */
#define RT_SENSOR_UNIT_MN_STR "mN"
#define RT_SENSOR_UNIT_BPM (22) /* Heart rate unit: bpm */
#define RT_SENSOR_UNIT_BPM_STR "bpm"
#define RT_SENSOR_UNIT_PPM (23) /* Concentration unit: ppm */
#define RT_SENSOR_UNIT_PPM_STR "ppm"
#define RT_SENSOR_UNIT_PPB (24) /* Concentration unit: ppb */
#define RT_SENSOR_UNIT_PPB_STR "ppb"
#define RT_SENSOR_UNIT_DMS (25) /* Coordinates unit: DMS */
#define RT_SENSOR_UNIT_DMS_STR "DMS"
#define RT_SENSOR_UNIT_DD (26) /* Coordinates unit: DD */
#define RT_SENSOR_UNIT_DD_STR "DD"
#define RT_SENSOR_UNIT_MGM3 (27) /* Concentration unit: mg/m3 */
#define RT_SENSOR_UNIT_MGM3_STR "mg/m3"
/* Sensor communication interface types */
#define RT_SENSOR_INTF_I2C (1 << 0)
#define RT_SENSOR_INTF_I2C_STR "I2C"
#define RT_SENSOR_INTF_SPI (1 << 1)
#define RT_SENSOR_INTF_SPI_STR "SPI"
#define RT_SENSOR_INTF_UART (1 << 2)
#define RT_SENSOR_INTF_UART_STR "UART"
#define RT_SENSOR_INTF_ONEWIRE (1 << 3)
#define RT_SENSOR_INTF_ONEWIRE_STR "1-Wire"
#define RT_SENSOR_INTF_CAN (1 << 4)
#define RT_SENSOR_INTF_CAN_STR "CAN"
#define RT_SENSOR_INTF_MODBUS (1 << 5)
#define RT_SENSOR_INTF_MODBUS_STR "Modbus"
/**
* Sensor mode
* rt_uint16_t mode
* 0000 | 0000 | 0000 | 0000
* unused accuracy power fetch data
*/
#define RT_SENSOR_MODE_ACCURACY_BIT_OFFSET (8)
#define RT_SENSOR_MODE_POWER_BIT_OFFSET (4)
#define RT_SENSOR_MODE_FETCH_BIT_OFFSET (0)
#define RT_SENSOR_MODE_GET_ACCURACY(mode) (rt_uint8_t)((mode >> RT_SENSOR_MODE_ACCURACY_BIT_OFFSET) & 0x0F)
#define RT_SENSOR_MODE_GET_POWER(mode) (rt_uint8_t)((mode >> RT_SENSOR_MODE_POWER_BIT_OFFSET) & 0x0F)
#define RT_SENSOR_MODE_GET_FETCH(mode) (rt_uint8_t)((mode >> RT_SENSOR_MODE_FETCH_BIT_OFFSET) & 0x0F)
#define RT_SENSOR_MODE_CLEAR_ACCURACY(mode) (mode &= ((rt_uint16_t)~((rt_uint16_t)0x0F << RT_SENSOR_MODE_ACCURACY_BIT_OFFSET)))
#define RT_SENSOR_MODE_CLEAR_POWER(mode) (mode &= ((rt_uint16_t)~((rt_uint16_t)0x0F << RT_SENSOR_MODE_POWER_BIT_OFFSET)))
#define RT_SENSOR_MODE_CLEAR_FETCH(mode) (mode &= ((rt_uint16_t)~((rt_uint16_t)0x0F << RT_SENSOR_MODE_FETCH_BIT_OFFSET)))
#define RT_SENSOR_MODE_SET_ACCURACY(mode, accuracy_mode) RT_SENSOR_MODE_CLEAR_ACCURACY(mode); (mode |= (accuracy_mode << RT_SENSOR_MODE_ACCURACY_BIT_OFFSET))
#define RT_SENSOR_MODE_SET_POWER(mode, power_mode) RT_SENSOR_MODE_CLEAR_POWER(mode); (mode |= (power_mode << RT_SENSOR_MODE_POWER_BIT_OFFSET))
#define RT_SENSOR_MODE_SET_FETCH(mode, fetch_mode) RT_SENSOR_MODE_CLEAR_FETCH(mode); (mode |= (fetch_mode << RT_SENSOR_MODE_FETCH_BIT_OFFSET))
/* Sensor mode: accuracy */
#define RT_SENSOR_MODE_ACCURACY_HIGHEST (0)
#define RT_SENSOR_MODE_ACCURACY_HIGHEST_STR "Accuracy Highest"
#define RT_SENSOR_MODE_ACCURACY_HIGH (1)
#define RT_SENSOR_MODE_ACCURACY_HIGH_STR "Accuracy High"
#define RT_SENSOR_MODE_ACCURACY_MEDIUM (2)
#define RT_SENSOR_MODE_ACCURACY_MEDIUM_STR "Accuracy Medium"
#define RT_SENSOR_MODE_ACCURACY_LOW (3)
#define RT_SENSOR_MODE_ACCURACY_LOW_STR "Accuracy Low"
#define RT_SENSOR_MODE_ACCURACY_LOWEST (4)
#define RT_SENSOR_MODE_ACCURACY_LOWEST_STR "Accuracy Lowest"
#define RT_SENSOR_MODE_ACCURACY_NOTRUST (5)
#define RT_SENSOR_MODE_ACCURACY_NOTRUST_STR "Accuracy No Trust"
/* Sensor mode: power */
#define RT_SENSOR_MODE_POWER_HIGHEST (0)
#define RT_SENSOR_MODE_POWER_HIGHEST_STR "Power Highest"
#define RT_SENSOR_MODE_POWER_HIGH (1)
#define RT_SENSOR_MODE_POWER_HIGH_STR "Power High"
#define RT_SENSOR_MODE_POWER_MEDIUM (2)
#define RT_SENSOR_MODE_POWER_MEDIUM_STR "Power Medium"
#define RT_SENSOR_MODE_POWER_LOW (3)
#define RT_SENSOR_MODE_POWER_LOW_STR "Power Low"
#define RT_SENSOR_MODE_POWER_LOWEST (4)
#define RT_SENSOR_MODE_POWER_LOWEST_STR "Power Lowest"
#define RT_SENSOR_MODE_POWER_DOWN (5)
#define RT_SENSOR_MODE_POWER_DOWN_STR "Power Down"
/* Sensor mode: fetch data */
#define RT_SENSOR_MODE_FETCH_POLLING (0) /* One shot only read a data */
#define RT_SENSOR_MODE_FETCH_POLLING_STR "Polling Mode"
#define RT_SENSOR_MODE_FETCH_INT (1) /* TODO: One shot interrupt only read a data */
#define RT_SENSOR_MODE_FETCH_INT_STR "Interrupt Mode"
#define RT_SENSOR_MODE_FETCH_FIFO (2) /* TODO: One shot interrupt read all fifo data */
#define RT_SENSOR_MODE_FETCH_FIFO_STR "FIFO Mode"
/* Sensor control cmd types */
#define RT_SENSOR_CTRL_GET_ID (RT_DEVICE_CTRL_BASE(Sensor) + 0) /* Get device id */
#define RT_SENSOR_CTRL_SELF_TEST (RT_DEVICE_CTRL_BASE(Sensor) + 1) /* Take a self test */
#define RT_SENSOR_CTRL_SOFT_RESET (RT_DEVICE_CTRL_BASE(Sensor) + 2) /* soft reset sensor */
#define RT_SENSOR_CTRL_SET_FETCH_MODE (RT_DEVICE_CTRL_BASE(Sensor) + 3) /* set fetch data mode */
#define RT_SENSOR_CTRL_SET_POWER_MODE (RT_DEVICE_CTRL_BASE(Sensor) + 4) /* set power mode */
#define RT_SENSOR_CTRL_SET_ACCURACY_MODE (RT_DEVICE_CTRL_BASE(Sensor) + 5) /* set accuracy mode */
#define RT_SENSOR_CTRL_USER_CMD_START 0x100 /* User commands should be greater than 0x100 */
/* sensor floating data type */
#ifdef RT_USING_SENSOR_DOUBLE_FLOAT
typedef double rt_sensor_float_t;
#else
typedef float rt_sensor_float_t;
#endif /* RT_USING_SENSOR_DOUBLE_FLOAT */
struct rt_sensor_accuracy
{
rt_sensor_float_t resolution; /* resolution of sesnor measurement */
rt_sensor_float_t error; /* error of sesnor measurement */
};
struct rt_sensor_scale
{
rt_sensor_float_t range_max; /* maximum range of this sensor's value. unit is 'unit' */
rt_sensor_float_t range_min; /* minimum range of this sensor's value. unit is 'unit' */
};
struct rt_sensor_info
{
rt_uint8_t type; /* sensor type */
rt_uint8_t vendor; /* sensors vendor */
const char *name; /* name of sensor */
rt_uint8_t unit; /* unit of measurement */
rt_uint8_t intf_type; /* communication interface type */
rt_uint16_t mode; /* sensor work mode */
rt_uint8_t fifo_max;
rt_sensor_float_t acquire_min; /* minimum acquirement period, unit:ms. zero = not a constant rate */
struct rt_sensor_accuracy accuracy; /* sensor current measure accuracy */
struct rt_sensor_scale scale; /* sensor current scale range */
};
struct rt_sensor_intf
{
char *dev_name; /* The name of the communication device */
rt_uint8_t type; /* Communication interface type */
void *arg; /* Interface argument for the sensor. ex. i2c addr,spi cs,control I/O */
};
struct rt_sensor_config
{
struct rt_sensor_intf intf; /* sensor interface config */
struct rt_device_pin_mode irq_pin; /* Interrupt pin, The purpose of this pin is to notification read data */
};
typedef struct rt_sensor_device *rt_sensor_t;
typedef struct rt_sensor_data *rt_sensor_data_t;
typedef struct rt_sensor_info *rt_sensor_info_t;
typedef struct rt_sensor_accuracy *rt_sensor_accuracy_t;
typedef struct rt_sensor_scale *rt_sensor_scale_t;
struct rt_sensor_device
{
struct rt_device parent; /* The standard device */
struct rt_sensor_info info; /* The sensor info data */
struct rt_sensor_config config; /* The sensor config data */
rt_sensor_data_t data_buf; /* The buf of the data received */
rt_size_t data_len; /* The size of the data received */
const struct rt_sensor_ops *ops; /* The sensor ops */
struct rt_sensor_module *module; /* The sensor module */
rt_err_t (*irq_handle)(rt_sensor_t sensor); /* Called when an interrupt is generated, registered by the driver */
};
struct rt_sensor_module
{
rt_mutex_t lock; /* The module lock */
rt_sensor_t sen[RT_SENSOR_MODULE_MAX]; /* The module contains a list of sensors */
rt_uint8_t sen_num; /* Number of sensors contained in the module */
};
/* 3-axis Data Type */
struct sensor_3_axis
{
rt_sensor_float_t x;
rt_sensor_float_t y;
rt_sensor_float_t z;
};
/* Blood Pressure Data Type */
struct sensor_bp
{
rt_sensor_float_t sbp; /* SBP : systolic pressure */
rt_sensor_float_t dbp; /* DBP : diastolic pressure */
};
struct coordinates
{
rt_sensor_float_t longitude;
rt_sensor_float_t latitude;
};
struct rt_sensor_data
{
rt_uint32_t timestamp; /* The timestamp when the data was received */
rt_uint8_t type; /* The sensor type of the data */
union
{
struct sensor_3_axis acce; /* Accelerometer. unit: mG */
struct sensor_3_axis gyro; /* Gyroscope. unit: mdps */
struct sensor_3_axis mag; /* Magnetometer. unit: mGauss */
struct coordinates coord; /* Coordinates unit: degrees */
struct sensor_bp bp; /* BloodPressure. unit: mmHg */
rt_sensor_float_t temp; /* Temperature. unit: dCelsius */
rt_sensor_float_t humi; /* Relative humidity. unit: permillage */
rt_sensor_float_t baro; /* Pressure. unit: pascal (Pa) */
rt_sensor_float_t light; /* Light. unit: lux */
rt_sensor_float_t proximity; /* Distance. unit: centimeters */
rt_sensor_float_t hr; /* Heart rate. unit: bpm */
rt_sensor_float_t tvoc; /* TVOC. unit: permillage */
rt_sensor_float_t noise; /* Noise Loudness. unit: HZ */
rt_sensor_float_t step; /* Step sensor. unit: 1 */
rt_sensor_float_t force; /* Force sensor. unit: mN */
rt_sensor_float_t dust; /* Dust sensor. unit: ug/m3 */
rt_sensor_float_t eco2; /* eCO2 sensor. unit: ppm */
rt_sensor_float_t spo2; /* SpO2 sensor. unit: permillage */
rt_sensor_float_t iaq; /* IAQ sensor. unit: 1 */
rt_sensor_float_t etoh; /* EtOH sensor. unit: ppm */
} data;
};
struct rt_sensor_ops
{
rt_ssize_t (*fetch_data)(rt_sensor_t sensor, rt_sensor_data_t buf, rt_size_t len);
rt_err_t (*control)(rt_sensor_t sensor, int cmd, void *arg);
};
int rt_hw_sensor_register(rt_sensor_t sensor,
const char *name,
rt_uint32_t flag,
void *data);
#ifdef __cplusplus
}
#endif
#endif /* __SENSOR_H__ */

Some files were not shown because too many files have changed in this diff Show more