summaryrefslogtreecommitdiffstatsabout
path: root/SylixOS
diff options
context:
space:
mode:
authorHanhui <hanhui@acoinfo.com>2020-12-22 11:11:09 (GMT)
committer Hanhui <hanhui@acoinfo.com>2020-12-22 11:11:09 (GMT)
commit1cab5fd8469433075c9bb29fc86d2044e2b972ee (patch)
tree40ede0ce9d4e496f146c22e4c06289684a313849 /SylixOS
parentab5a514c1e59b91cc7ab312b3900a38d34a6152e (diff)
downloadlibsylixos-1cab5fd8469433075c9bb29fc86d2044e2b972ee.zip
libsylixos-1cab5fd8469433075c9bb29fc86d2044e2b972ee.tar.gz
libsylixos-1cab5fd8469433075c9bb29fc86d2044e2b972ee.tar.bz2
Add device tree support and update ppp and build system.
Diffstat (limited to 'SylixOS')
-rw-r--r--SylixOS/config/system/system_cfg.h6
-rw-r--r--SylixOS/devtree/devtree.h393
-rw-r--r--SylixOS/devtree/devtreeClock.c170
-rw-r--r--SylixOS/devtree/devtreeDev.c361
-rw-r--r--SylixOS/devtree/devtreeGpio.c331
-rw-r--r--SylixOS/devtree/devtreeHighLevel.c695
-rw-r--r--SylixOS/devtree/devtreeI2c.c163
-rw-r--r--SylixOS/devtree/devtreeIrq.c479
-rw-r--r--SylixOS/devtree/devtreeLib.c816
-rw-r--r--SylixOS/devtree/devtreeLowLevel.c466
-rw-r--r--SylixOS/devtree/devtreeMdio.c183
-rw-r--r--SylixOS/devtree/devtreePhandle.c335
-rw-r--r--SylixOS/devtree/devtreeProperty.c644
-rw-r--r--SylixOS/devtree/devtreeSpi.c235
-rw-r--r--SylixOS/devtree/devtree_error.h40
-rw-r--r--SylixOS/devtree/devtree_inline.h165
-rw-r--r--SylixOS/devtree/devtree_value.h37
-rw-r--r--SylixOS/driver/fdt/fdt.c98
-rw-r--r--SylixOS/driver/fdt/fdt.h19
-rw-r--r--SylixOS/driver/fdt/fdt_addresses.c84
-rw-r--r--SylixOS/driver/fdt/fdt_empty_tree.c4
-rw-r--r--SylixOS/driver/fdt/fdt_overlay.c67
-rw-r--r--SylixOS/driver/fdt/fdt_ro.c373
-rw-r--r--SylixOS/driver/fdt/fdt_rw.c118
-rw-r--r--SylixOS/driver/fdt/fdt_strerror.c4
-rw-r--r--SylixOS/driver/fdt/fdt_support.h325
-rw-r--r--SylixOS/driver/fdt/fdt_sw.c133
-rw-r--r--SylixOS/driver/fdt/fdt_wip.c14
-rw-r--r--SylixOS/driver/fdt/fdtdec.c1488
-rw-r--r--SylixOS/driver/fdt/fdtdec.h1033
-rw-r--r--SylixOS/driver/fdt/fdtdec_common.c66
-rw-r--r--SylixOS/driver/fdt/libfdt.h239
-rw-r--r--SylixOS/driver/fdt/libfdt_env.h35
-rw-r--r--SylixOS/driver/fdt/libfdt_internal.h37
-rw-r--r--SylixOS/driver/sio/16c550.c5
-rw-r--r--SylixOS/driver/sio/16c550.h2
-rw-r--r--SylixOS/hosttools/makedtc/dtc.exebin0 -> 916890 bytes
-rw-r--r--SylixOS/hosttools/makedtc/fdtdump.exebin0 -> 369949 bytes
-rw-r--r--SylixOS/hosttools/makedtc/fdtget.exebin0 -> 370807 bytes
-rw-r--r--SylixOS/hosttools/makedtc/fdtoverlay.exebin0 -> 368349 bytes
-rw-r--r--SylixOS/hosttools/makedtc/fdtput.exebin0 -> 378774 bytes
-rw-r--r--SylixOS/hosttools/makedtc/libfdt-1.6.0.sobin0 -> 394079 bytes
-rw-r--r--SylixOS/include/network/lwip/netif.h3
-rw-r--r--SylixOS/include/network/lwip/opt.h6
-rw-r--r--SylixOS/include/network/lwip/sio.h2
-rw-r--r--SylixOS/include/network/netif/ppp/ppp.h2
-rw-r--r--SylixOS/include/network/netif/ppp/ppp_impl.h59
-rw-r--r--SylixOS/include/network/netif/ppp/ppp_opts.h45
-rw-r--r--SylixOS/include/network/netif/ppp/pppos.h7
-rw-r--r--SylixOS/kernel/include/k_functype.h2
-rw-r--r--SylixOS/kernel/include/k_kernel.h4
-rw-r--r--SylixOS/mktemp/application.mk6
-rw-r--r--SylixOS/mktemp/bare-metal.mk4
-rw-r--r--SylixOS/mktemp/bsp.mk4
-rw-r--r--SylixOS/mktemp/clear-vars.mk5
-rw-r--r--SylixOS/mktemp/common.mk33
-rw-r--r--SylixOS/mktemp/dummy.mk2
-rw-r--r--SylixOS/mktemp/extension.mk2
-rw-r--r--SylixOS/mktemp/gtest.mk6
-rw-r--r--SylixOS/mktemp/header.mk242
-rw-r--r--SylixOS/mktemp/kernel-library.mk2
-rw-r--r--SylixOS/mktemp/kernel-module.mk2
-rw-r--r--SylixOS/mktemp/library.mk8
-rw-r--r--SylixOS/mktemp/libsylixos.mk4
-rw-r--r--SylixOS/mktemp/lite-bsp.mk6
-rw-r--r--SylixOS/mktemp/static-library.mk4
-rw-r--r--SylixOS/net/lwip/lwip_fix.c2
-rw-r--r--SylixOS/net/lwip/lwip_shell.c2
-rw-r--r--SylixOS/net/lwip/src/core/netif.c2
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/auth.c19
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/ccp.c4
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/chap-new.c6
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/demand.c10
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/eap.c16
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/fsm.c4
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/lcp.c24
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/magic.c54
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/multilink.c10
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/ppp.c51
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/pppoe.c35
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/pppol2tp.c26
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/pppos.c153
-rw-r--r--SylixOS/net/lwip/src/netif/ppp/upap.c6
-rw-r--r--SylixOS/net/lwip/tools/ppp/lwip_ppp.c2
-rw-r--r--SylixOS/system/device/base/baseDrvLib.c638
-rw-r--r--SylixOS/system/device/base/baseDrvLib.h148
-rw-r--r--SylixOS/system/device/clock/clock.c808
-rw-r--r--SylixOS/system/device/clock/clock.h272
-rw-r--r--SylixOS/system/device/clock/clockDivider.c530
-rw-r--r--SylixOS/system/device/clock/clockFixedFactor.c160
-rw-r--r--SylixOS/system/device/clock/clockFixedRate.c105
-rw-r--r--SylixOS/system/device/clock/clockGate.c146
-rw-r--r--SylixOS/system/device/clock/clockMux.c167
-rw-r--r--SylixOS/system/device/i2c/i2cLibDevTree.c382
-rw-r--r--SylixOS/system/device/i2c/i2cLibDevTree.h176
-rw-r--r--SylixOS/system/device/irqctrl/irqCtrlDev.c287
-rw-r--r--SylixOS/system/device/irqctrl/irqCtrlDev.h100
-rw-r--r--SylixOS/system/device/mii/mdioLib.c418
-rw-r--r--SylixOS/system/device/mii/mdioLib.h167
-rw-r--r--SylixOS/system/device/mii/phyDev.c193
-rw-r--r--SylixOS/system/device/mii/phyDev.h112
-rw-r--r--SylixOS/system/device/pinctrl/pinConfig.c196
-rw-r--r--SylixOS/system/device/pinctrl/pinConfig.h75
-rw-r--r--SylixOS/system/device/pinctrl/pinCtrl.c791
-rw-r--r--SylixOS/system/device/pinctrl/pinCtrl.h129
-rw-r--r--SylixOS/system/device/pinctrl/pinCtrlClass.h270
-rw-r--r--SylixOS/system/device/pinctrl/pinCtrlDev.c359
-rw-r--r--SylixOS/system/device/pinctrl/pinCtrlDev.h52
-rw-r--r--SylixOS/system/device/pinctrl/pinMux.c368
-rw-r--r--SylixOS/system/device/pinctrl/pinMux.h43
-rw-r--r--SylixOS/system/device/platform/platform.c129
-rw-r--r--SylixOS/system/device/platform/platform.h41
-rw-r--r--SylixOS/system/device/spi/spiLibDevTree.c680
-rw-r--r--SylixOS/system/device/spi/spiLibDevTree.h266
-rw-r--r--SylixOS/system/include/s_class.h82
-rw-r--r--SylixOS/system/include/s_system.h14
-rw-r--r--SylixOS/vpmpdm/dlmalloc/dlmalloc.h4
-rw-r--r--SylixOS/vpmpdm/ptmalloc3/ptmalloc3_sylixos.h4
118 files changed, 18310 insertions, 551 deletions
diff --git a/SylixOS/config/system/system_cfg.h b/SylixOS/config/system/system_cfg.h
index 5677367..f060b34 100644
--- a/SylixOS/config/system/system_cfg.h
+++ b/SylixOS/config/system/system_cfg.h
@@ -98,6 +98,12 @@
#define LW_CFG_DIR_MAX 256 /* 最深的目录级数 */
/*********************************************************************************************************
+* 设备树功能
+*********************************************************************************************************/
+
+#define LW_CFG_DEVTREE_EN 1 /* 是否允许系统提供设备树支持 */
+
+/*********************************************************************************************************
* 兼容 Linux 新加入可等待异步事件功能
* 依存关系: 1: 二进制信号量
2: 互斥信号量
diff --git a/SylixOS/devtree/devtree.h b/SylixOS/devtree/devtree.h
new file mode 100644
index 0000000..440160e
--- /dev/null
+++ b/SylixOS/devtree/devtree.h
@@ -0,0 +1,393 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtree.h
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 06 月 17 日
+**
+** 描 述: 设备树头文件
+*********************************************************************************************************/
+
+#ifndef __DEVTREE_H
+#define __DEVTREE_H
+
+/*********************************************************************************************************
+ 调试宏
+*********************************************************************************************************/
+
+#define DEVTREE_DEBUG_EN 0
+
+#if DEVTREE_DEBUG_EN > 0
+#define DEVTREE_MSG(fmt, args...) _DebugFormat(__PRINTMESSAGE_LEVEL, fmt, ##args)
+#define DEVTREE_ERR(fmt, args...) _DebugFormat(__ERRORMESSAGE_LEVEL, fmt, ##args)
+#else
+#define DEVTREE_MSG(fmt, args...)
+#define DEVTREE_ERR(fmt, args...)
+#endif
+
+/*********************************************************************************************************
+ 默认定义
+*********************************************************************************************************/
+
+#define ROOT_NODE_SIZE_CELLS_DEFAULT 1
+#define ROOT_NODE_ADDR_CELLS_DEFAULT 1
+
+/*********************************************************************************************************
+ 加载标识定义
+*********************************************************************************************************/
+
+#define OF_POPULATED 1
+#define OF_POPULATED_BUS 2
+#define OF_PHANDLE_ILLEGAL 0xdeadbeef
+
+/*********************************************************************************************************
+ 资源计算宏
+*********************************************************************************************************/
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+#define RESOURCE_SIZE(res) (res.iomem.DEVRES_ulEnd - \
+ res.iomem.DEVRES_ulStart + 1)
+
+/*********************************************************************************************************
+ 设备树相关定义
+*********************************************************************************************************/
+
+#define LW_DEVTREE_TABLE_END {}
+
+#define LW_DEVTREE_DECLARE(name, compatible, probefunc) \
+static LW_DEVTREE_TABLE _G_##name##Match[] = { \
+ { .DTITEM_cCompatible = compatible, }, \
+ {} \
+}; \
+static LW_DRV_INSTANCE _G_##name##Instance = { \
+ .DRVHD_pMatchTable = _G_##name##Match, \
+ .DRVHD_pfuncProbe = probefunc, \
+}
+
+#define LW_DEVTREE_MATCH_DECLARE(compatible, probefunc) { \
+ .DTITEM_cCompatible = compatible, \
+ .DTITEM_pvData = probefunc, \
+}
+
+/*********************************************************************************************************
+ 类型定义
+*********************************************************************************************************/
+
+typedef struct devtree_bus {
+ CPCHAR DTBUS_pcAddresses;
+ INT (*DTBUS_match)(PLW_DEVTREE_NODE pdtnParent); /* 总线匹配 */
+ VOID (*DTBUS_cellsCount)(PLW_DEVTREE_NODE pdtnChild,
+ INT *piCellAddr,
+ INT *piCellSize);/* cells 数量获取 */
+ UINT64 (*DTBUS_map)(UINT32 *puiAddr,
+ UINT32 *puiRange,
+ INT iAddrNum,
+ INT iSizeNum,
+ INT iPAddrNum);
+ INT (*DTBUS_translate)(UINT32 *puiAddr,
+ UINT64 ullOffset,
+ INT iAddrNum);
+} LW_DEVTREE_BUS;
+typedef LW_DEVTREE_BUS *PLW_DEVTREE_BUS;
+
+typedef struct devtree_alias_prop {
+ LW_LIST_LINE DTALP_plineManage; /* 别名属性节点链表管理 */
+ CPCHAR DTALP_pcAlias; /* 别名属性节点名指针 */
+ PLW_DEVTREE_NODE DTALP_pdtnDev; /* 别名属性节点指向的设备树节点*/
+ INT DTALP_iId;
+ CHAR DTALP_cStem[0]; /* 开辟实际存储节点名的内存 */
+} LW_DEVTREE_ALIAS_PROPERTY;
+typedef LW_DEVTREE_ALIAS_PROPERTY *PLW_DEVTREE_ALIAS_PROPERTY;
+
+typedef struct devtree_phandle_iterator {
+ CPCHAR DTPHI_pcCellsName;
+ INT DTPHI_iCellCount;
+ PLW_DEVTREE_NODE DTPHI_pdtnParent;
+
+ const UINT32 *DTPHI_puiListEnd;
+ const UINT32 *DTPHI_puiPhandleEnd;
+
+ const UINT32 *DTPHI_puiCurrent;
+ UINT32 DTPHI_uiCurCount;
+ UINT32 DTPHI_uiPhandle;
+ PLW_DEVTREE_NODE DTPHI_pdtnDev;
+} LW_DEVTREE_PHANDLE_ITERATOR;
+typedef LW_DEVTREE_PHANDLE_ITERATOR *PLW_DEVTREE_PHANDLE_ITERATOR;
+
+typedef PVOID (*FUNC_DT_ALLOC)(size_t stSize, size_t stAlign);
+typedef INT (*FUNC_SCAN_CALLBACK)(PVOID pvBase, INT iOffset,
+ CPCHAR cpcName, INT iDepth, PVOID pvData);
+typedef INT (*DEVTREE_INIT_FUNC)(PLW_DEVTREE_NODE pdtnDev);
+
+/*********************************************************************************************************
+ 节点固定属性获取
+*********************************************************************************************************/
+
+LW_API INT API_DeviceTreeNAddrCells(PLW_DEVTREE_NODE pdtnDev);
+
+LW_API INT API_DeviceTreeNSizeCells(PLW_DEVTREE_NODE pdtnDev);
+
+/*********************************************************************************************************
+ 地址相关接口
+*********************************************************************************************************/
+
+LW_API UINT64 API_DeviceTreeAddressTranslate(PLW_DEVTREE_NODE pdtnDev,
+ const UINT32 *puiInAddr);
+
+LW_API INT API_DeviceTreeRegAddressGet(PLW_DEVTREE_NODE pdtnDev,
+ PLW_DEV_RESOURCE pdevresource);
+
+LW_API const UINT32* API_DeviceTreeAddressGet(PLW_DEVTREE_NODE pdtnDev,
+ INT iIndex,
+ UINT64 *pullSize);
+
+LW_API INT API_DeviceTreeResourceGet(PLW_DEVTREE_NODE pdtnDev,
+ INT iIndex,
+ PLW_DEV_RESOURCE pdevresource);
+
+LW_API PVOID API_DeviceTreeAddressIoremap(PLW_DEVTREE_NODE pdtnDev, INT iIndex);
+
+/*********************************************************************************************************
+ 属性读取接口
+*********************************************************************************************************/
+
+LW_API PVOID API_DeviceTreePropertyGet(PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcName,
+ INT *piLen);
+
+LW_API INT API_DeviceTreePropertyU32Read(PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropname,
+ UINT32 *puiOutValue);
+
+LW_API INT API_DeviceTreePropertyU32ArrayRead(PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropname,
+ UINT32 *puiOutValue,
+ size_t stSize);
+
+LW_API INT API_DeviceTreePropertyU32VaraiableArrayRead(const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropname,
+ UINT32 *puiOutValue,
+ size_t stMin,
+ size_t stMax);
+
+LW_API UINT32* API_DeviceTreePropertyU32Next(PLW_DEVTREE_PROPERTY pdtproperty,
+ UINT32 *puiCur,
+ UINT32 *puiOut);
+
+LW_API BOOL API_DeviceTreePropertyBoolRead(PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropName);
+
+LW_API INT API_DeviceTreePropertyU32IndexRead(PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropname,
+ UINT32 uiIndex,
+ UINT32 *puiOutValue);
+
+LW_API INT API_DeviceTreePropertyStringHelperRead(PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropName,
+ CPCHAR *ppcOutStrs,
+ size_t stSize,
+ INT iSkip,
+ INT *piCount);
+
+LW_API CPCHAR API_DeviceTreePropertyStringNext(PLW_DEVTREE_PROPERTY pdtproperty,
+ CPCHAR pcCur);
+
+LW_API INT API_DeviceTreePropertyStringRead(PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropName,
+ CPCHAR *ppcOutString);
+
+LW_API INT API_DeviceTreePropertyStringMatch(PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropName,
+ CPCHAR pcString);
+
+LW_API INT API_DeviceTreePropertyStringIndexRead(const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropName,
+ INT iIndex,
+ CPCHAR *ppcOutPut);
+
+LW_API PLW_DEVTREE_PROPERTY API_DeviceTreePropertyFind(const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropName,
+ INT *piLen);
+
+LW_API INT API_DeviceTreePropertyStringCount(const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropName);
+
+LW_API BOOL API_DeviceTreeNodeIsOkayByOffset(PVOID pvDevTree, INT iOffset);
+
+LW_API BOOL API_DeviceTreeNodeIsOkay(PLW_DEVTREE_NODE pdtnDev);
+
+LW_API INT API_DeviceTreeModaliasGet(PLW_DEVTREE_NODE pdtnDev,
+ PCHAR pcName,
+ INT iLen);
+
+/*********************************************************************************************************
+ phandle 相关接口
+*********************************************************************************************************/
+
+LW_API INT API_DeviceTreePhandleIteratorInit(PLW_DEVTREE_PHANDLE_ITERATOR pdtpiterator,
+ const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcListName,
+ CPCHAR pcCellsName,
+ INT iCellCount);
+
+LW_API INT API_DeviceTreePhandleIteratorNext(PLW_DEVTREE_PHANDLE_ITERATOR pdtpiterator);
+
+LW_API INT API_DeviceTreePhandleParseWithArgs(const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcListName,
+ CPCHAR pcCellsName,
+ INT iIndex,
+ PLW_DEVTREE_PHANDLE_ARGS pdtpargsOut);
+
+LW_API PLW_DEVTREE_NODE API_DeviceTreePhandleParse(const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPhandleName,
+ INT iIndex);
+
+/*********************************************************************************************************
+ 查找相关接口
+*********************************************************************************************************/
+
+LW_API PLW_DEVTREE_NODE API_DeviceTreeFindNodeOptsByPath(CPCHAR pcPath, CPCHAR *ppcOpts);
+
+LW_API PLW_DEVTREE_NODE API_DeviceTreeFindNodeByPhandle(UINT32 uiHandle);
+
+LW_API PLW_DEVTREE_NODE API_DeviceTreeFindAllNodes(PLW_DEVTREE_NODE pdtnPrev);
+
+/*********************************************************************************************************
+ 遍历相关接口
+*********************************************************************************************************/
+
+LW_API PLW_DEVTREE_NODE API_DeviceTreeNextChildGet(const PLW_DEVTREE_NODE pdtnDev,
+ PLW_DEVTREE_NODE pdtnPrev);
+
+/*********************************************************************************************************
+ 系统相关接口
+*********************************************************************************************************/
+
+LW_API INT API_DeviceTreeLowLevelInit(PVOID pvDevtreeMem);
+
+LW_API INT API_DeviceTreeHighLevelInit(PVOID pvDevTreeMem);
+
+LW_API ssize_t API_DeviceTreeKernelStartParamGet(PCHAR pcParam, size_t stLen);
+
+LW_API INT API_DeviceTreeKernelVmmParamGet(PVOID pvDevtreeMem,
+ PLW_MMU_PHYSICAL_DESC pphyOriginDesc,
+ size_t stPhyOriginDesc,
+ PLW_MMU_PHYSICAL_DESC *ppphydesc,
+ PLW_MMU_VIRTUAL_DESC *ppvirdes);
+
+LW_API INT API_DeviceTreeAliasIdGet(PLW_DEVTREE_NODE pdtnDev, CPCHAR pcStem);
+
+LW_API INT API_DeviceTreeDevPopulate(PLW_DEVTREE_NODE pdtnDev,
+ PLW_DEVTREE_TABLE pdttMatch);
+
+LW_API INT API_DeviceTreeDefaultPopulate(VOID);
+
+LW_API INT API_DeviceTreeDrvMatchDev(PLW_DEV_INSTANCE pdevinstance,
+ PLW_DRV_INSTANCE pdrvinstance);
+
+LW_API INT API_DeviceTreeDevEarlyInit(PLW_DEVTREE_TABLE pdttMatch);
+
+LW_API INT API_DeviceTreeIsCompatible(PLW_DEVTREE_NODE pdtnDev,
+ PCHAR pcCompat);
+
+/*********************************************************************************************************
+ 中断相关接口
+*********************************************************************************************************/
+
+LW_API INT API_DeviceTreeIrqOneParse(PLW_DEVTREE_NODE pdtnDev,
+ INT iIndex,
+ PLW_DEVTREE_PHANDLE_ARGS pdtpaOut);
+
+LW_API INT API_DeviceTreeIrqCountGet(PLW_DEVTREE_NODE pdtnDev);
+
+LW_API PLW_DEVTREE_NODE API_DeviceTreeIrqFindParent(PLW_DEVTREE_NODE pdtnChild);
+
+LW_API INT API_DeviceTreeIrqRawParse(const UINT32 *puiAddr,
+ PLW_DEVTREE_PHANDLE_ARGS pdtpaOutIrq);
+
+LW_API INT API_DeviceTreeIrqToResource(PLW_DEVTREE_NODE pdtnDev,
+ INT iIndex,
+ PLW_DEV_RESOURCE pdevresource);
+
+LW_API INT API_DeviceTreeIrqToResouceTable(PLW_DEVTREE_NODE pdtnDev,
+ PLW_DEV_RESOURCE pdevresource,
+ INT iNrIrqs);
+
+LW_API INT API_DeviceTreeIrqGet(PLW_DEVTREE_NODE pdtnDev,
+ INT iIndex,
+ ULONG *pulVector);
+
+/*********************************************************************************************************
+ pinctrl 相关接口
+*********************************************************************************************************/
+
+LW_API VOID API_DeviceTreePinCtrlMapsFree(PLW_PINCTRL ppinctrl);
+
+LW_API INT API_DeviceTreePinCtrlMapsCreate(PLW_PINCTRL ppinctrl);
+
+LW_API PLW_PINCTRL_DEV API_DeviceTreePinCtrlDevGet(PLW_DEVTREE_NODE pdtnDev);
+
+/*********************************************************************************************************
+ clock 相关接口
+*********************************************************************************************************/
+
+LW_API PLW_CLOCK API_DeviceTreeClockGetByName(PLW_DEVTREE_NODE pdtnDev, CPCHAR pcName);
+
+LW_API CPCHAR API_DeviceTreeParentClockNameGet(PLW_DEVTREE_NODE pdtnDev, INT iIndex);
+
+LW_API PLW_CLOCK API_DeviceTreeClockGet(PLW_DEVTREE_NODE pdtnDev, INT iIndex);
+
+/*********************************************************************************************************
+ MDIO 相关接口
+*********************************************************************************************************/
+
+LW_API INT API_DeviceTreeMdioRegister(PMDIO_ADAPTER pmdioadapter,
+ PLW_DEVTREE_NODE pdtnDev);
+
+LW_API INT API_DeviceTreeMdioDevRegister(PMDIO_ADAPTER pmdioadapter,
+ PLW_DEVTREE_NODE pdtnDev,
+ UINT uiAddr);
+
+LW_API MDIO_DEVICE *API_DeviceTreeMdioDevFind(PLW_DEVTREE_NODE pdtnDev);
+
+/*********************************************************************************************************
+ I2C 相关接口
+*********************************************************************************************************/
+
+LW_API INT API_DeviceTreeI2cAdapterRegister(PLW_DT_I2C_ADAPTER pi2cadapter,
+ PLW_DEVTREE_NODE pdtnDev);
+
+LW_API INT API_DeviceTreeI2cDevRegister(PLW_DT_I2C_ADAPTER pi2cadapter,
+ PLW_DEVTREE_NODE pdtnDev);
+
+/*********************************************************************************************************
+ SPI 相关接口
+*********************************************************************************************************/
+
+LW_API INT API_DeviceTreeSpiCtrlRegister(PLW_DT_SPI_CTRL pspictrl,
+ PLW_DEVTREE_NODE pdtnDev);
+
+LW_API INT API_DeviceTreeSpiDevRegister(PLW_DT_SPI_CTRL pspictrl,
+ PLW_DEVTREE_NODE pdtnDev);
+
+#include "devtree_error.h"
+#include "devtree_inline.h"
+#include "devtree_value.h"
+
+#endif /* __DEVTREE_H */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtreeClock.c b/SylixOS/devtree/devtreeClock.c
new file mode 100644
index 0000000..3ca95db
--- /dev/null
+++ b/SylixOS/devtree/devtreeClock.c
@@ -0,0 +1,170 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtreeClock.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 09 月 02 日
+**
+** 描 述: 设备树接口时钟相关接口实现
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if LW_CFG_DEVTREE_EN > 0
+#include "devtree.h"
+#include "driver/fdt/libfdt_env.h"
+#include "driver/fdt/libfdt.h"
+#include "driver/fdt/fdt.h"
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeClockGetByName
+** 功能描述: 通过时钟名获取时钟结构
+** 输 入 : pdtnDev 设备树节点
+** pcName 时钟名称
+** 输 出 : 时钟结构
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_CLOCK API_DeviceTreeClockGetByName (PLW_DEVTREE_NODE pdtnDev, CPCHAR pcName)
+{
+ PLW_CLOCK pclk = LW_NULL;
+ INT iIndex = 0;
+
+ while (pdtnDev) {
+ if (pcName) {
+ iIndex = API_DeviceTreePropertyStringMatch(pdtnDev, "clock-names", pcName);
+ }
+
+ pclk = API_DeviceTreeClockGet(pdtnDev, iIndex);
+ if (!pclk) {
+ break;
+ } else if (pcName && (iIndex >= 0)) {
+ return (pclk);
+ }
+
+ pdtnDev = pdtnDev->DTN_pdtnparent;
+ if (pdtnDev && !API_DeviceTreePropertyGet(pdtnDev, "clock-ranges", LW_NULL)) {
+ break;
+ }
+ }
+
+ return (pclk);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeParentClockNameGet
+** 功能描述: 获取指定序号的父时钟名称
+** 输 入 : pdtnDev 设备树节点
+** iIndex 指定的时钟序号
+** 输 出 : 父时钟名称
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+CPCHAR API_DeviceTreeParentClockNameGet (PLW_DEVTREE_NODE pdtnDev, INT iIndex)
+{
+ LW_DEVTREE_PHANDLE_ARGS pdtpaClkSpec;
+ PLW_DEVTREE_PROPERTY pdtproperty;
+ PLW_CLOCK pclk;
+ CPCHAR pcClkName;
+ UINT *puiVal;
+ UINT32 uiPropVal;
+ INT iRet;
+ INT iCount;
+
+ iRet = API_DeviceTreePhandleParseWithArgs(pdtnDev,
+ "clocks",
+ "#clock-cells",
+ iIndex,
+ &pdtpaClkSpec);
+ if (iRet) {
+ return (LW_NULL);
+ }
+
+ iIndex = pdtpaClkSpec.DTPH_iArgsCount ? pdtpaClkSpec.DTPH_uiArgs[0] : 0;
+ iCount = 0;
+
+ _LIST_EACH_OF_UINT32_PROPERTY(pdtpaClkSpec.DTPH_pdtnDev,
+ "clock-indices",
+ pdtproperty,
+ puiVal,
+ uiPropVal) {
+ if (iIndex == uiPropVal) {
+ iIndex = iCount;
+ break;
+ }
+ iCount++;
+ }
+
+ if (pdtproperty && !puiVal) {
+ return (LW_NULL);
+ }
+
+ if (API_DeviceTreePropertyStringIndexRead(pdtpaClkSpec.DTPH_pdtnDev,
+ "clock-output-names",
+ iIndex,
+ &pcClkName) < 0) {
+ pclk = API_ClockGetFromProvider(&pdtpaClkSpec);
+ if (!pclk) {
+ if (pdtpaClkSpec.DTPH_iArgsCount == 0) {
+ pcClkName = pdtpaClkSpec.DTPH_pdtnDev->DTN_pcName;
+ } else {
+ pcClkName = LW_NULL;
+ }
+ } else {
+ pcClkName = pclk->CLK_pcName;
+ }
+ }
+
+ return (pcClkName);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeClockGet
+** 功能描述: 通过设备树节点获取时钟
+** 输 入 : pdtnDev 设备树节点
+** iIndex 设备序号
+** 输 出 : 获取的时钟
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_CLOCK API_DeviceTreeClockGet (PLW_DEVTREE_NODE pdtnDev, INT iIndex)
+{
+ LW_DEVTREE_PHANDLE_ARGS pdtpaClkSpec;
+ PLW_CLOCK pclk;
+ INT iRet;
+
+ iRet = API_DeviceTreePhandleParseWithArgs(pdtnDev,
+ "clocks",
+ "#clock-cells",
+ iIndex,
+ &pdtpaClkSpec);
+ if (iRet) {
+ return (LW_NULL);
+ }
+
+ pclk = API_ClockGetFromProvider(&pdtpaClkSpec);
+
+ return (pclk);
+}
+
+#endif /* LW_CFG_DEVTREE_EN > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtreeDev.c b/SylixOS/devtree/devtreeDev.c
new file mode 100644
index 0000000..e0e335b
--- /dev/null
+++ b/SylixOS/devtree/devtreeDev.c
@@ -0,0 +1,361 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtreeDev.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 06 月 21 日
+**
+** 描 述: 设备树接口设备相关接口实现
+**
+** 修改:
+** 2019.10.22 驱动模型更改,修改此文件
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+#include "linux/bitops.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if LW_CFG_DEVTREE_EN > 0
+#include "devtree.h"
+#include "driver/fdt/libfdt_env.h"
+#include "driver/fdt/libfdt.h"
+#include "driver/fdt/fdt.h"
+/*********************************************************************************************************
+ 设备总线匹配表
+*********************************************************************************************************/
+static LW_DEVTREE_TABLE _G_dttDefaultDevBus[] = {
+ { .DTITEM_cCompatible = "simple-bus", },
+ { .DTITEM_cCompatible = "simple-mfd", },
+ { .DTITEM_cCompatible = "isa", },
+ LW_DEVTREE_TABLE_END
+};
+/*********************************************************************************************************
+ 设备总线不匹配表
+*********************************************************************************************************/
+static LW_DEVTREE_TABLE _G_dttSkipDevBus[] = {
+ { .DTITEM_cCompatible = "operating-points-v2", },
+ LW_DEVTREE_TABLE_END
+};
+/*********************************************************************************************************
+** 函数名称: __deviceTreeIsCompatible
+** 功能描述: 检查节点与匹配表项是否匹配
+** 输 入 : pdtnDev 指定的节点
+** pcCompatible 匹配表项的兼容属性
+** pcType 匹配表项的类型属性
+** pcName 匹配表项的名称属性
+** 输 出 : 匹配的权重值,越大表示越匹配
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeIsCompatible (PLW_DEVTREE_NODE pdtnDev,
+ PCHAR pcCompatible,
+ PCHAR pcType,
+ PCHAR pcName)
+{
+ PLW_DEVTREE_PROPERTY pdtproperty;
+ CPCHAR pcTemp;
+ INT iIndex = 0;
+ INT iScore = 0;
+
+ if (pcCompatible && pcCompatible[0]) { /* 优先匹配 "compatible" */
+ pdtproperty = API_DeviceTreePropertyFind(pdtnDev, "compatible", LW_NULL);
+ for (pcTemp = API_DeviceTreePropertyStringNext(pdtproperty, LW_NULL);
+ pcTemp != LW_NULL;
+ pcTemp = API_DeviceTreePropertyStringNext(pdtproperty, pcTemp), iIndex++) {
+
+ if (lib_strcasecmp(pcTemp, pcCompatible) == 0) { /* 忽略大小写时完全匹配 */
+ iScore = INT_MAX / 2 - (iIndex << 2); /* 给予较大的权重 */
+ break;
+ }
+ }
+
+ if (!iScore) { /* 如果 "compatible" 不能匹配 */
+ return (0); /* 那么此项直接认为不能匹配 */
+ }
+ }
+
+ if (pcType && pcType[0]) { /* 如果要求匹配 type 类型 */
+ if (!pdtnDev->DTN_pcType ||
+ lib_strcasecmp(pcType, pdtnDev->DTN_pcType)) { /* type 类型不能匹配 */
+ return (0); /* 此项认为不能匹配 */
+ }
+
+ iScore += 2; /* type 类型匹配,权重增加 */
+ }
+
+ if (pcName && pcName[0]) { /* 如果要求匹配 name */
+ if (!pdtnDev->DTN_pcName ||
+ lib_strcasecmp(pcName, pdtnDev->DTN_pcName)) { /* name 不能匹配 */
+ return (0); /* 此项认为不能匹配 */
+ }
+
+ iScore++; /* name 匹配,权重增加 */
+ }
+
+ return (iScore);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeNodeMatch
+** 功能描述: 检查节点与匹配表是否匹配
+** 输 入 : pdtnDev 指定的节点
+** pdttMatch 匹配的表格
+** 输 出 : 若有匹配项,返回 最合适的表项;若没有匹配项,返回 LW_NULL。
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static const PLW_DEVTREE_TABLE __deviceTreeNodeMatch (PLW_DEVTREE_NODE pdtnDev,
+ PLW_DEVTREE_TABLE pdttMatch)
+{
+ PLW_DEVTREE_TABLE pdttBestMatch = LW_NULL;
+ INT iScore;
+ INT iBestScore = 0;
+
+ if (!pdttMatch) {
+ return (LW_NULL);
+ }
+
+ for (;
+ pdttMatch->DTITEM_cName[0] ||
+ pdttMatch->DTITEM_cType[0] ||
+ pdttMatch->DTITEM_cCompatible[0];
+ pdttMatch++) { /* 逐个对比匹配表中的表项 */
+
+ iScore = __deviceTreeIsCompatible(pdtnDev,
+ pdttMatch->DTITEM_cCompatible,
+ pdttMatch->DTITEM_cType,
+ pdttMatch->DTITEM_cName);
+ if (iScore > iBestScore) { /* 找到最合适的表项 */
+ pdttBestMatch = pdttMatch;
+ iBestScore = iScore;
+ }
+ }
+
+ return (pdttBestMatch);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeDevCreate
+** 功能描述: 创建设备
+** 输 入 : pdtnDev 指定的节点
+** 输 出 : 创建成功,返回设备实例;失败,返回 LW_NULL
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static PLW_DEV_INSTANCE __deviceTreeDevCreate (PLW_DEVTREE_NODE pdtnDev)
+{
+ PLW_DEV_INSTANCE pdevInstance;
+
+ pdevInstance = __SHEAP_ZALLOC(sizeof(LW_DEV_INSTANCE));
+ if (LW_NULL == pdevInstance) {
+ return (LW_NULL);
+ }
+
+ pdevInstance->DEVHD_pdtnDev = pdtnDev;
+ pdevInstance->DEVHD_pcName = pdtnDev->DTN_pcFullName;
+
+ API_PlatformDeviceRegister(pdevInstance);
+ __deviceTreeNodeFlagSet(pdtnDev, OF_POPULATED); /* 标记节点被加载 */
+
+ return (pdevInstance);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeDevPopulate
+** 功能描述: 设备树设备节点与设备实例链表匹配
+** 输 入 : pdtnDev 指定的节点
+** pdttMatch 指定的匹配表
+** 输 出 : 匹配成功,返回匹配的设备实例;匹配失败,返回 LW_NULL
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeDevPopulate (PLW_DEVTREE_NODE pdtnDev,
+ PLW_DEVTREE_TABLE pdttMatch)
+{
+ INT iRet = ERROR_NONE;
+ PLW_DEVTREE_NODE pdtnChild;
+ PLW_DEV_INSTANCE pdevInstance;
+ PCHAR pcCompat;
+
+ pcCompat = API_DeviceTreePropertyGet(pdtnDev, "compatible", LW_NULL);
+ if (pcCompat) {
+ DEVTREE_MSG("%s() - node %s compatible : %s\r\n",
+ __func__, pdtnDev->DTN_pcFullName, pcCompat);
+ } else {
+ return (ERROR_NONE);
+ }
+
+ if (__deviceTreeNodeFlagCheck(pdtnDev, OF_POPULATED_BUS)) { /* 已经匹配过的不再匹配 */
+ DEVTREE_MSG("%s() - skipping %s, already populated\r\n",
+ __func__, pdtnDev->DTN_pcFullName);
+
+ return (ERROR_NONE);
+ }
+
+ if (__deviceTreeNodeMatch(pdtnDev, _G_dttSkipDevBus)) { /* 跳过不需要匹配的节点 */
+ return (ERROR_NONE);
+ }
+
+ pdevInstance = __deviceTreeDevCreate(pdtnDev); /* 创建平台设备 */
+ if (LW_NULL == pdevInstance) {
+ return (ERROR_NONE);
+ }
+
+ if (!__deviceTreeNodeMatch(pdtnDev, pdttMatch)) { /* 进行总线兼容性匹配 */
+ return (ERROR_NONE);
+ }
+
+ _LIST_EACH_CHILD_OF_NODE(pdtnDev, pdtnChild) { /* 继续遍历该节点的子节点 */
+ iRet = __deviceTreeDevPopulate(pdtnChild, pdttMatch);
+ if (iRet) {
+ break;
+ }
+ }
+
+ return (iRet);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeDrvMatchDev
+** 功能描述: 设备和驱动对外匹配接口
+** 输 入 : pdevInstance 设备实例指针
+** pdrvInstance 驱动实例指针
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeDrvMatchDev (PLW_DEV_INSTANCE pdevInstance,
+ PLW_DRV_INSTANCE pdrvInstance)
+{
+ if (!pdevInstance || !pdrvInstance) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ if (__deviceTreeNodeMatch(pdevInstance->DEVHD_pdtnDev,
+ pdrvInstance->DRVHD_pMatchTable)) { /* 匹配设备实例的匹配表 */
+ return (ERROR_NONE);
+ }
+
+ return (PX_ERROR);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeDevPopulate
+** 功能描述: 设备树设备节点匹配加载
+** 输 入 : pdtnDev 指定的节点
+** pdttMatch 指定的匹配表
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeDevPopulate (PLW_DEVTREE_NODE pdtnDev,
+ PLW_DEVTREE_TABLE pdttMatch)
+{
+ PLW_DEVTREE_NODE pdtnChild;
+
+ pdtnDev = pdtnDev ? pdtnDev : __deviceTreeFindNodeByPath("/");
+
+ _LIST_EACH_CHILD_OF_NODE(pdtnDev, pdtnChild) { /* 继续遍历该节点的子节点 */
+ if (__deviceTreeDevPopulate(pdtnChild, pdttMatch)) {
+ return (PX_ERROR);
+ }
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeDevEarlyInit
+** 功能描述: 设备提前初始化接口
+** 输 入 : pdttMatch 匹配表
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeDevEarlyInit (PLW_DEVTREE_TABLE pdttMatch)
+{
+ PLW_DEVTREE_NODE pdtnDev;
+ DEVTREE_INIT_FUNC pfuncInitCb;
+ PLW_DEVTREE_TABLE pdttMatchTmp;
+
+ _LIST_EACH_OF_ALLNODES(pdtnDev) { /* 遍历结点,加载中断控制器 */
+ if (!API_DeviceTreePropertyGet(pdtnDev, "compatible", LW_NULL)) {
+ DEVTREE_MSG("%s() - skipping %s, no compatible prop\r\n",
+ __func__, pdtnDev->DTN_pcName);
+ continue;
+ }
+
+ if (__deviceTreeNodeFlagCheck(pdtnDev, OF_POPULATED)) { /* 已经匹配过的不再匹配 */
+ DEVTREE_MSG("%s() - skipping %s, already populated\r\n",
+ __func__, pdtnDev->DTN_pcName);
+ continue;
+ }
+
+ pdttMatchTmp = __deviceTreeNodeMatch(pdtnDev, pdttMatch);
+ if (LW_NULL != pdttMatchTmp) {
+ __deviceTreeNodeFlagSet(pdtnDev, OF_POPULATED); /* 标记节点被加载 */
+ pfuncInitCb = pdttMatchTmp->DTITEM_pvData;
+ if (pfuncInitCb) { /* 如果找到匹配项 */
+ pfuncInitCb(pdtnDev); /* 执行设备实例的 Probe 函数 */
+ }
+ }
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeDefaultPopulate
+** 功能描述: 设备树外设节点加载初始化入口
+** 输 入 : NONE
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeDefaultPopulate (VOID)
+{
+ DEVTREE_MSG("Device populate from root.\r\n");
+
+ return (API_DeviceTreeDevPopulate(NULL, _G_dttDefaultDevBus));
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeIsCompatible
+** 功能描述: 检查节点与匹配表项是否匹配
+** 输 入 : pdtnDev 指定的节点
+** pcCompat 匹配表项的兼容属性
+** 输 出 : 匹配的权重值,越大表示越匹配
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeIsCompatible (PLW_DEVTREE_NODE pdtnDev,
+ PCHAR pcCompat)
+{
+ if (!pdtnDev) {
+ _ErrorHandle(EINVAL);
+ return (0);
+ }
+
+ return (__deviceTreeIsCompatible(pdtnDev, pcCompat, LW_NULL, LW_NULL));
+}
+
+#endif /* LW_CFG_DEVTREE_EN > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtreeGpio.c b/SylixOS/devtree/devtreeGpio.c
new file mode 100644
index 0000000..d30b26a
--- /dev/null
+++ b/SylixOS/devtree/devtreeGpio.c
@@ -0,0 +1,331 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtreeGpio.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 08 月 02 日
+**
+** 描 述: 设备树接口引脚相关接口实现
+*********************************************************************************************************/
+#define __SYLIXOS_STDIO
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if LW_CFG_DEVTREE_EN > 0
+#include "devtree.h"
+#include "driver/fdt/libfdt_env.h"
+#include "driver/fdt/libfdt.h"
+#include "driver/fdt/fdt.h"
+/*********************************************************************************************************
+** 函数名称: __deviceTreeMapFree
+** 功能描述: 释放设备树使用的引脚映射结构
+** 输 入 : ppinctrldev 引脚控制器
+** ppinctrlmap 释放的引脚映射结构
+** uiNumMaps 引脚映射结构的元素数量
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __deviceTreeMapFree (PLW_PINCTRL_DEV ppinctrldev,
+ PLW_PINCTRL_MAP ppinctrlmap,
+ UINT uiNumMaps)
+{
+ PLW_PINCTRL_OPS ppinctrlops;
+
+ if (ppinctrldev) {
+ ppinctrlops = ppinctrldev->PCTLD_ppinctldesc->PCTLD_ppinctlops;
+ ppinctrlops->pinctrlMapFree(ppinctrldev, ppinctrlmap, uiNumMaps);
+
+ } else {
+ __SHEAP_FREE(ppinctrlmap);
+ }
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeRememberOrFreeMap
+** 功能描述: 增加非 DUMMY 的引脚复用映射结构
+** 输 入 : ppinctrl 引脚控制
+** pcStateName 关联的状态
+** ppinctrldev 关联的引脚控制器
+** ppinctrlmap 引脚映射结构
+** uiNumMaps 引脚映射结构元素数量
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeRememberOrFreeMap (PLW_PINCTRL ppinctrl,
+ CPCHAR pcStateName,
+ PLW_PINCTRL_DEV ppinctrldev,
+ PLW_PINCTRL_MAP ppinctrlmap,
+ UINT uiNumMaps)
+{
+ PLW_PINCTRL_MAPS ppinctlmaps;
+ INT i;
+
+ for (i = 0; i < uiNumMaps; i++) { /* 填充引脚映射结构中剩余部分 */
+ ppinctrlmap[i].PCTLM_pdtnDev = ppinctrl->PCTL_pdtnDev; /* 记录该引脚配置的设备树节点 */
+ ppinctrlmap[i].PCTLM_pcName = pcStateName; /* 记录该引脚配置的状态名称 */
+ if (ppinctrldev) {
+ ppinctrlmap[i].PCTLM_pdtnCtrlNode = ppinctrldev->PCTLD_pdtnDev;
+ /* 记录引脚控制器的设备树节点 */
+ }
+ }
+
+ ppinctlmaps = (PLW_PINCTRL_MAPS)__SHEAP_ALLOC(sizeof(LW_PINCTRL_MAPS));
+ if (!ppinctlmaps) {
+ __deviceTreeMapFree(ppinctrldev, ppinctrlmap, uiNumMaps);
+ _ErrorHandle(ENOMEM);
+ return (PX_ERROR);
+ }
+
+ ppinctlmaps->PCTLM_ppinctldev = ppinctrldev; /* 记录引脚控制器 */
+ ppinctlmaps->PCTLM_ppinctlmaps = ppinctrlmap; /* 记录引脚映射数组 */
+ ppinctlmaps->PCTLM_uiMapsNum = uiNumMaps; /* 记录引脚映射数组元素个数 */
+ _List_Line_Add_Ahead(&ppinctlmaps->PCTLM_lineManage,
+ &ppinctrl->PCTL_plinemaps); /* 添加引脚映射结构节点 */
+
+ return (API_PinCtrlMapAdd(ppinctlmaps)); /* 注册引脚映射结构集合 */
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeRememberDummyState
+** 功能描述: 增加虚拟的引脚映射结构
+** 输 入 : ppinctrl 引脚控制
+** pcStateName 关联的状态
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeRememberDummyState (PLW_PINCTRL ppinctrl, CPCHAR pcStateName)
+{
+ PLW_PINCTRL_MAP ppinctrlmap;
+
+ ppinctrlmap = (PLW_PINCTRL_MAP)__SHEAP_ALLOC(sizeof(LW_PINCTRL_MAP));
+ if (!ppinctrlmap) {
+ _ErrorHandle(ENOMEM);
+ return (PX_ERROR);
+ }
+
+ ppinctrlmap->PCTLM_pctlmaptype = PIN_MAP_TYPE_DUMMY_STATE;
+
+ return (__deviceTreeRememberOrFreeMap(ppinctrl, pcStateName, LW_NULL, ppinctrlmap, 1));
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeOneConfigMap
+** 功能描述: 解析一条设备树引脚配置转换为引脚映射结构
+** 输 入 : ppinctrl 引脚控制
+** pcStateName 对应的状态
+** pdtnConfig 引脚配置的设备树节点
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeOneConfigMap (PLW_PINCTRL ppinctrl,
+ CPCHAR pcStateName,
+ PLW_DEVTREE_NODE pdtnConfig)
+{
+ PLW_DEVTREE_NODE pdtnPinctrlDev;
+ PLW_PINCTRL_DEV ppinctrldev;
+ PLW_PINCTRL_OPS ppinctrlops;
+ PLW_PINCTRL_MAP ppinctrlmap = LW_NULL;
+ UINT uiNunMaps;
+ INT iRet;
+
+ pdtnPinctrlDev = pdtnConfig;
+ while (1) {
+ pdtnPinctrlDev = pdtnPinctrlDev->DTN_pdtnparent; /* 查找引脚控制器节点 */
+ if (!pdtnPinctrlDev || /* 如果没有父节点 */
+ !pdtnPinctrlDev->DTN_pdtnparent) { /* 或者父节点为根节点 */
+ _ErrorHandle(ERROR_DEVTREE_EPROBE_DEFER);
+ return (PX_ERROR);
+ }
+
+ ppinctrldev = API_PinCtrlDevGetByDevtreeNode(pdtnPinctrlDev); /* 找到引脚控制器 */
+ if (ppinctrldev) {
+ break;
+ }
+
+ if (pdtnPinctrlDev == ppinctrl->PCTL_pdtnDev) { /* 若引脚控制关联的外设是引脚 */
+ _ErrorHandle(ENODEV); /* 控制器 */
+ return (PX_ERROR);
+ }
+ }
+
+ ppinctrlops = ppinctrldev->PCTLD_ppinctldesc->PCTLD_ppinctlops;
+ if (!ppinctrlops->pinctrlMapCreate) { /* 若没有定义设备树转换方法 */
+ _ErrorHandle(ENODEV);
+ return (PX_ERROR);
+ }
+
+ iRet = ppinctrlops->pinctrlMapCreate(ppinctrldev,
+ pdtnConfig,
+ &ppinctrlmap,
+ &uiNunMaps); /* 调用引脚控制器解析接口 */
+ if (iRet < 0) {
+ return (iRet);
+ }
+
+ if (!ppinctrlmap) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ return (__deviceTreeRememberOrFreeMap(ppinctrl, pcStateName, ppinctrldev, ppinctrlmap, uiNunMaps));
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePinCtrlMapsFree
+** 功能描述: 释放设备树的引脚映射结构
+** 输 入 : ppinctrl 引脚控制
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+VOID API_DeviceTreePinCtrlMapsFree (PLW_PINCTRL ppinctrl)
+{
+ PLW_PINCTRL_MAPS pinctrlmaps;
+ PLW_LIST_LINE plineTemp;
+
+ if (!ppinctrl) {
+ return;
+ }
+
+ for (plineTemp = ppinctrl->PCTL_plinemaps;
+ plineTemp != LW_NULL;
+ plineTemp = _list_line_get_next(plineTemp)) { /* 遍历引脚控制的映射链表 */
+
+ pinctrlmaps = _LIST_ENTRY(plineTemp, LW_PINCTRL_MAPS, PCTLM_lineManage);
+
+ API_PinCtrlMapDel(pinctrlmaps->PCTLM_ppinctlmaps); /* 从全局链表中移除 */
+
+ _List_Line_Del(&pinctrlmaps->PCTLM_lineManage,
+ &ppinctrl->PCTL_plinemaps); /* 从引脚控制链表中移除 */
+
+ __deviceTreeMapFree(pinctrlmaps->PCTLM_ppinctldev,
+ pinctrlmaps->PCTLM_ppinctlmaps,
+ pinctrlmaps->PCTLM_uiMapsNum); /* 释放引脚映射内存 */
+ __SHEAP_FREE(pinctrlmaps);
+ }
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePinCtrlMapsCreate
+** 功能描述: 将引脚控制对应的设备树解析成引脚映射结构
+** 输 入 : ppinctrl 引脚控制
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreePinCtrlMapsCreate (PLW_PINCTRL ppinctrl)
+{
+ PLW_DEVTREE_NODE pdtnDev;
+ PLW_DEVTREE_NODE pdtnConfig;
+ PLW_DEVTREE_PROPERTY pdtproperty;
+ CPCHAR pcStateName;
+ CHAR cPropName[30];
+ UINT32 *puiList;
+ UINT32 uiPhandle;
+ INT iState = 0;
+ INT iConfig;
+ INT iSize;
+ INT iRet;
+
+ if (!ppinctrl) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ pdtnDev = ppinctrl->PCTL_pdtnDev;
+
+ while (1) { /* 按序号查找引脚控制属性 */
+ snprintf(cPropName, 30, "pinctrl-%d", iState);
+ pdtproperty = API_DeviceTreePropertyFind(pdtnDev, cPropName, &iSize);
+ if (!pdtproperty) { /* 如果已经找不到对应序号 */
+ if (0 == iState) {
+ return (PX_ERROR);
+ }
+ break;
+ }
+
+ puiList = pdtproperty->DTP_pvValue; /* 获取 phandle */
+ iSize /= sizeof(UINT32);
+
+ iRet = API_DeviceTreePropertyStringIndexRead(pdtnDev,
+ "pinctrl-names",
+ iState,
+ &pcStateName); /* 查找对应引脚名称 */
+ if (iRet < 0) { /* 未找到名称属性时的名称方式 */
+ pcStateName = pdtproperty->DTP_pcName + 8;
+ }
+
+ for (iConfig = 0; iConfig < iSize; iConfig++) {
+ uiPhandle = BE32_TO_CPU(puiList++); /* 根据引脚控制获取 phandle */
+ pdtnConfig = API_DeviceTreeFindNodeByPhandle(uiPhandle); /* 由 phandle 找对应设备树节点 */
+ if (!pdtnConfig) {
+ DEVTREE_ERR("prop %s index %i invalid phandle\r\n",
+ pdtproperty->DTP_pcName, iConfig);
+ iRet = -EINVAL;
+ goto __error_handle;
+ }
+
+ iRet = __deviceTreeOneConfigMap(ppinctrl,
+ pcStateName,
+ pdtnConfig); /* 解析该引脚控制配置 */
+ if (iRet < 0) {
+ goto __error_handle;
+ }
+ }
+
+ if (!iSize) { /* 如果引脚控制没有属性值 */
+ iRet = __deviceTreeRememberDummyState(ppinctrl, pcStateName);
+ if (iRet < 0) {
+ goto __error_handle;
+ }
+ }
+
+ iState++;
+ }
+
+ return (ERROR_NONE);
+
+__error_handle:
+ API_DeviceTreePinCtrlMapsFree(ppinctrl);
+ return (iRet);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePinCtrlDevGet
+** 功能描述: 根据设备树节点获取引脚控制器
+** 输 入 : pdtnDev 设备树节点
+** 输 出 : 引脚控制器
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_PINCTRL_DEV API_DeviceTreePinCtrlDevGet (PLW_DEVTREE_NODE pdtnDev)
+{
+ PLW_PINCTRL_DEV ppinctrldev;
+
+ ppinctrldev = API_PinCtrlDevGetByDevtreeNode(pdtnDev);
+
+ return (ppinctrldev);
+}
+
+#endif /* LW_CFG_DEVTREE_EN > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtreeHighLevel.c b/SylixOS/devtree/devtreeHighLevel.c
new file mode 100644
index 0000000..782b8aa
--- /dev/null
+++ b/SylixOS/devtree/devtreeHighLevel.c
@@ -0,0 +1,695 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtreeHighLevel.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 07 月 30 日
+**
+** 描 述: 设备树接口高层接口系统内核实现
+**
+** +------+
+** | Root |
+** +------+
+** __|
+** |
+** +------+ +------+ +------+
+** | Devm |--| Devn |-- ....--| Dev..|
+** +------+ +------+ +------+
+** __| |__ .... |__....
+** |
+** +------+ +------+ +------+
+** | Devx |--| Devy |-- ....--| Dev..|
+** +------+ +------+ +------+
+** ....__| |__ .... |__ ....
+**
+** 设备树的树型结构,只有一个父节点,每个父节点只有一个子节点,
+** 但子节点会有很多同一层次的兄弟节点。所有的兄弟节点都会指向该父节点。
+**
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+#include "linux/log2.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if LW_CFG_DEVTREE_EN > 0
+#include "devtree.h"
+#include "driver/fdt/libfdt_env.h"
+#include "driver/fdt/libfdt.h"
+#include "driver/fdt/fdt.h"
+/*********************************************************************************************************
+ 宏定义
+*********************************************************************************************************/
+#define DEVTREE_MEM_GUARD 0xdeadbeef /* 内存警戒区数据 */
+#define DEVTREE_MEM_GUARD_SIZE 4 /* 内存警戒区大小 */
+#define FDT_MAX_DEPTH 64 /* 支持的最大树深度 */
+
+#ifndef __GNUC__
+#define __alignof__(x) 8
+#endif
+/*********************************************************************************************************
+ 全局变量
+*********************************************************************************************************/
+static LW_LIST_LINE_HEADER _G_plineheadAliasesLookup;
+/*********************************************************************************************************
+** 函数名称: __deviceTreeMemoryPartGet
+** 功能描述: 从设备树申请的内存中获取一块
+** 输 入 : ppvMem 申请的内存基址(会改变)
+** stSize 申请的内存大小
+** stAlign 申请的对齐大小
+** 输 出 : 申请的内存地址
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static PVOID __deviceTreeMemoryPartGet (PVOID *ppvMem, size_t stSize, size_t stAlign)
+{
+ PVOID pvRes;
+
+ *ppvMem = (PVOID)ROUND_UP(*ppvMem, stAlign);
+ pvRes = *ppvMem;
+ *ppvMem = (PVOID)((size_t)*ppvMem + stSize);
+
+ return (pvRes);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeMemoryAlloc
+** 功能描述: 设备树内存申请接口
+** 输 入 : stSize 申请的内存大小
+** stAlign 申请的对齐大小
+** 输 出 : 申请的内存地址
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static PVOID __deviceTreeMemoryAlloc (size_t stSize, size_t stAlign)
+{
+ return (__SHEAP_ALLOC_ALIGN(stSize, stAlign));
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeMemGuardSet
+** 功能描述: 设置内存保护标志
+** 输 入 : pvMem 内存基址
+** iSize 内存大小
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __deviceTreeMemGuardSet (PVOID pvMem, INT iSize)
+{
+ *(UINT32 *)((addr_t)pvMem + iSize) = DEVTREE_MEM_GUARD;
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeMemGuardGet
+** 功能描述: 获取内存保护标志
+** 输 入 : pvMem 内存基址
+** iSize 内存大小
+** 输 出 : 内存保护标志位置当前值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeMemGuardGet (PVOID pvMem, INT iSize)
+{
+ return (*(UINT32 *)((addr_t)pvMem + iSize));
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeNodePropertiesPopulate
+** 功能描述: 生成设备树属性内容
+** 输 入 : pvDevTree 设备树基地址
+** iOffset 节点偏移
+** ppvMem 内存偏移
+** pdtnDev 当前用于生成属性的节点
+** pcNodeName 节点名称
+** bIsSkip 是否只遍历,不处理具体过程
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __deviceTreeNodePropertiesPopulate (CPVOID pvDevTree,
+ INT iOffset,
+ PVOID *ppvMem,
+ PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcNodeName,
+ BOOL bIsSkip)
+{
+ PLW_DEVTREE_PROPERTY *ppdtpprev;
+ PLW_DEVTREE_PROPERTY pdtpcurr;
+ INT iCur;
+ INT iSize;
+ BOOL bIsHasName = LW_FALSE;
+ const UINT32 *puiVal;
+ CPCHAR pcName;
+ CPCHAR pcTmp;
+ CPCHAR pcAddr;
+ CPCHAR pcStart;
+
+ ppdtpprev = &pdtnDev->DTN_pdtpproperties;
+
+ for (iCur = fdt_first_property_offset(pvDevTree, iOffset);
+ iCur >= 0;
+ iCur = fdt_next_property_offset(pvDevTree, iCur)) { /* 从指定偏移开始遍历属性节点 */
+
+ puiVal = fdt_getprop_by_offset(pvDevTree,
+ iCur,
+ &pcName,
+ &iSize); /* 获取属性 */
+ if (!puiVal) {
+ DEVTREE_ERR("Cannot locate property at 0x%x\r\n", iCur);
+ continue;
+ }
+
+ if (!pcName) {
+ DEVTREE_ERR("Cannot find property name at 0x%x\r\n", iCur);
+ continue;
+ }
+
+ if (!lib_strcmp(pcName, "name")) { /* 若属性名为 "name" */
+ bIsHasName = LW_TRUE;
+ }
+
+ pdtpcurr = __deviceTreeMemoryPartGet(ppvMem, /* 为属性分配内存 */
+ sizeof(LW_DEVTREE_PROPERTY),
+ __alignof__(LW_DEVTREE_PROPERTY));
+
+ if (bIsSkip) { /* 如果只遍历,则直接下一个 */
+ continue;
+ }
+
+ if (!strcmp(pcName, "phandle") && !pdtnDev->DTN_uiHandle) { /* 若属性名为 "phandle" */
+ pdtnDev->DTN_uiHandle = BE32_TO_CPU(puiVal); /* 记录句柄值 */
+ }
+
+ pdtpcurr->DTP_pcName = pcName; /* 记录属性的名称 */
+ pdtpcurr->DTP_iLength = iSize; /* 记录属性值的长度 */
+ pdtpcurr->DTP_pvValue = (UINT32 *)puiVal; /* 记录属性值的内容 */
+ *ppdtpprev = pdtpcurr;
+ ppdtpprev = &pdtpcurr->DTP_pdtpNext;
+ }
+
+ if (!bIsHasName) { /* 如果属性中有全路径名称 */
+ pcTmp = pcNodeName;
+ pcStart = pcTmp;
+ pcAddr = LW_NULL;
+
+ /*
+ * 形如:"/serial@e2900800" 这样的属性
+ * 通过以下循环可以获取到值 "serial"
+ */
+ while (*pcTmp) { /* 逐个字符查找 */
+ if (*pcTmp == '@') { /* 记录节点地址 */
+ pcAddr = pcTmp;
+ } else if (*pcTmp == '/') {
+ pcStart = pcTmp + 1;
+ }
+ pcTmp++;
+ }
+
+ if (pcAddr < pcStart) {
+ pcAddr = pcTmp;
+ }
+
+ iSize = (pcAddr - pcStart) + 1;
+ pdtpcurr = __deviceTreeMemoryPartGet(ppvMem,
+ sizeof(LW_DEVTREE_PROPERTY) + iSize,
+ __alignof__(LW_DEVTREE_PROPERTY));
+ if (!bIsSkip) {
+ pdtpcurr->DTP_pcName = "name";
+ pdtpcurr->DTP_iLength = iSize;
+ pdtpcurr->DTP_pvValue = pdtpcurr + 1;
+ *ppdtpprev = pdtpcurr;
+ ppdtpprev = &pdtpcurr->DTP_pdtpNext;
+
+ lib_memcpy(pdtpcurr->DTP_pvValue, pcStart, iSize - 1);
+ ((PCHAR)pdtpcurr->DTP_pvValue)[iSize - 1] = 0;
+
+ DEVTREE_MSG("Fixed up name for %s -> %s\r\n",
+ pcNodeName, pdtpcurr->DTP_pvValue);
+ }
+ }
+
+ if (!bIsSkip) {
+ *ppdtpprev = LW_NULL;
+ }
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeNodePopulate
+** 功能描述: 生成设备树节点
+** 输 入 : pvDevTree 设备树基地址
+** iOffset 节点偏移
+** ppvMem 开辟的内存偏移
+** pdtnFather 父节点
+** ppdtnCur 用于获取当前节点
+** bIsSkip 是否只遍历,不处理具体过程
+** 输 出 : LW_TRUE 表示生成成功,LW_FALSE 表示生成失败
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static BOOL __deviceTreeNodePopulate (PVOID pvDevTree,
+ INT iOffset,
+ PVOID *ppvMem,
+ PLW_DEVTREE_NODE pdtnFather,
+ PLW_DEVTREE_NODE *ppdtnCur,
+ BOOL bIsSkip)
+{
+ PLW_DEVTREE_NODE pdtnPtr;
+ CPCHAR pcPath;
+ INT iAllocLen;
+ INT iLen;
+
+ pcPath = fdt_get_name(pvDevTree, iOffset, &iLen); /* 获取节点全路径名 */
+ if (!pcPath) {
+ *ppdtnCur = LW_NULL;
+ return (LW_FALSE);
+ }
+
+ iAllocLen = iLen + 1; /* 内存大小需要增加 Full Name */
+ pdtnPtr = __deviceTreeMemoryPartGet(ppvMem, /* 从指定内存中取出一块 */
+ sizeof(LW_DEVTREE_NODE) + iAllocLen,
+ __alignof__(LW_DEVTREE_NODE));
+ if (!bIsSkip) {
+ pdtnPtr->DTN_pcFullName = (PCHAR)pdtnPtr + sizeof(LW_DEVTREE_NODE);
+ lib_memcpy((PVOID)pdtnPtr->DTN_pcFullName, pcPath, iAllocLen);
+ /* 记录节点全路径名 */
+ if (pdtnFather != LW_NULL) {
+ pdtnPtr->DTN_pdtnparent = pdtnFather; /* 记录父节点 */
+ pdtnPtr->DTN_pdtnsibling = pdtnFather->DTN_pdtnchild; /* 记录兄弟节点 */
+ pdtnFather->DTN_pdtnchild = pdtnPtr; /* 更新父节点的子节点 */
+ }
+ }
+
+ __deviceTreeNodePropertiesPopulate(pvDevTree,
+ iOffset,
+ ppvMem,
+ pdtnPtr,
+ pcPath,
+ bIsSkip); /* 填充属性结构 */
+ if (!bIsSkip) {
+ pdtnPtr->DTN_pcName = API_DeviceTreePropertyGet(pdtnPtr,
+ "name",
+ LW_NULL); /* 从属性结构中获取名称 */
+ pdtnPtr->DTN_pcType = API_DeviceTreePropertyGet(pdtnPtr,
+ "device_type",
+ LW_NULL); /* 从属性结构中获取名称 */
+ if (!pdtnPtr->DTN_pcName) {
+ pdtnPtr->DTN_pcName = "<NULL>";
+ }
+
+ if (!pdtnPtr->DTN_pcType) {
+ pdtnPtr->DTN_pcType = "<NULL>";
+ }
+ }
+
+ *ppdtnCur = pdtnPtr; /* 记录当前解析到的节点 */
+
+ return (LW_TRUE);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeNodesReverse
+** 功能描述: 反向排序设备树节点
+** 输 入 : pdtnParent 设备树父节点
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __deviceTreeNodesReverse (PLW_DEVTREE_NODE pdtnParent)
+{
+ PLW_DEVTREE_NODE pdtnChild;
+ PLW_DEVTREE_NODE pdtnNext;
+
+ pdtnChild = pdtnParent->DTN_pdtnchild; /* 获得当前的子节点 */
+ while (pdtnChild) { /* 递归子节点的子节点 */
+ __deviceTreeNodesReverse(pdtnChild);
+ pdtnChild = pdtnChild->DTN_pdtnsibling; /* 遍历每一个兄弟节点 */
+ }
+
+ pdtnChild = pdtnParent->DTN_pdtnchild; /* 执行到此,为最后一个兄弟节点*/
+ pdtnParent->DTN_pdtnchild = LW_NULL;
+ while (pdtnChild) {
+ pdtnNext = pdtnChild->DTN_pdtnsibling; /* 找到下一个兄弟节点 */
+
+ pdtnChild->DTN_pdtnsibling = pdtnParent->DTN_pdtnchild;
+ pdtnParent->DTN_pdtnchild = pdtnChild;
+ pdtnChild = pdtnNext;
+ }
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeAliasAdd
+** 功能描述: 将别名属性节点插入别名属性查找链表
+** 输 入 : pdtaprop 别名属性节点
+** pdtnDev 设备树节点
+** iId id 值
+** pcStem 设备名称
+** iStemLen 设备名称长度
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __deviceTreeAliasAdd (PLW_DEVTREE_ALIAS_PROPERTY pdtaprop,
+ PLW_DEVTREE_NODE pdtnDev,
+ INT iId,
+ CPCHAR pcStem,
+ INT iStemLen)
+{
+ pdtaprop->DTALP_pcAlias = pcStem;
+ pdtaprop->DTALP_pdtnDev = pdtnDev;
+ pdtaprop->DTALP_iId = iId;
+
+ lib_strncpy(pdtaprop->DTALP_cStem, pcStem, iStemLen);
+ pdtaprop->DTALP_cStem[iStemLen] = 0;
+
+ _List_Line_Add_Ahead(&pdtaprop->DTALP_plineManage,
+ &_G_plineheadAliasesLookup);
+
+ DEVTREE_MSG("Adding DT alias:%s: stem=%s id=%d\r\n",
+ pdtaprop->DTALP_pcAlias,
+ pdtaprop->DTALP_cStem,
+ pdtaprop->DTALP_iId);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeAliasScan
+** 功能描述: 对别名属性节点进行扫描
+** 输 入 : pfuncDtAlloc 内存申请函数
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __deviceTreeAliasScan (FUNC_DT_ALLOC pfuncDtAlloc)
+{
+ PLW_DEVTREE_ALIAS_PROPERTY pdtaprop;
+ PLW_DEVTREE_PROPERTY pdtpCur;
+ PLW_DEVTREE_NODE pdtnDev;
+ CPCHAR pcStart;
+ CPCHAR pcEnd;
+ INT iLen;
+ INT iId;
+
+ _G_pdtnAliases = __deviceTreeFindNodeByPath("/aliases"); /* 找到 aliases 节点 */
+ if (!_G_pdtnAliases) {
+ return;
+ }
+
+ for (pdtpCur = _G_pdtnAliases->DTN_pdtpproperties;
+ pdtpCur != LW_NULL;
+ pdtpCur = pdtpCur->DTP_pdtpNext) {
+
+ if (!strcmp(pdtpCur->DTP_pcName, "name") ||
+ !strcmp(pdtpCur->DTP_pcName, "phandle") ||
+ !strcmp(pdtpCur->DTP_pcName, "linux,phandle")) { /* 跳过不需要关心的数据 */
+ continue;
+ }
+
+ pcStart = pdtpCur->DTP_pcName;
+ pcEnd = pcStart + lib_strlen(pcStart);
+
+ pdtnDev = __deviceTreeFindNodeByPath(pdtpCur->DTP_pvValue); /* 通过全路径名查找设备树节点 */
+ if (!pdtnDev) {
+ continue;
+ }
+
+ while (lib_isdigit(*(pcEnd - 1)) && (pcEnd > pcStart)) { /* 找到数字起始的位置 */
+ pcEnd--;
+ }
+
+ iLen = pcEnd - pcStart;
+ iId = lib_atoi(pcEnd);
+ if (iId < 0) { /* 如果数字解析小于 0 */
+ continue;
+ }
+
+ pdtaprop = pfuncDtAlloc(sizeof(LW_DEVTREE_ALIAS_PROPERTY) + iLen + 1,
+ __alignof__(LW_DEVTREE_ALIAS_PROPERTY));
+ if (!pdtaprop) {
+ return;
+ }
+
+ lib_bzero(pdtaprop, sizeof(LW_DEVTREE_ALIAS_PROPERTY) + iLen + 1);
+
+ __deviceTreeAliasAdd(pdtaprop, pdtnDev,
+ iId, pcStart, iLen); /* 将 Alias 插入链表 */
+ }
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreePhandleCachePopulate
+** 功能描述: 生成 Phandle Cache 信息
+** 输 入 : NONE
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __deviceTreePhandleCachePopulate (VOID)
+{
+ PLW_DEVTREE_NODE pdtnDev;
+ UINT32 uiCacheEntries;
+ UINT32 uiPhandles = 0;
+
+ _LIST_EACH_OF_ALLNODES(pdtnDev) { /* 遍历结点,统计 phandle 数量 */
+ if (pdtnDev->DTN_uiHandle) {
+ uiPhandles++;
+ }
+ }
+
+ if (!uiPhandles) { /* 如果没有 phandle,返回 */
+ return;
+ }
+
+ uiCacheEntries = roundup_pow_of_two(uiPhandles); /* 找出小于 phandle 的 2^n 数 */
+ _G_uiPhandleCacheMask = uiCacheEntries - 1; /* 计算 phandle 的掩码 */
+
+ _G_ppdtnPhandleCache = __SHEAP_ZALLOC(uiCacheEntries * sizeof(PLW_DEVTREE_NODE));
+ if (!_G_ppdtnPhandleCache) { /* 开辟 phandle Cache 内存 */
+ return;
+ }
+
+ _LIST_EACH_OF_ALLNODES(pdtnDev) {
+ if (pdtnDev->DTN_uiHandle) { /* 根据 phandle 索引填充 Cache */
+ _G_ppdtnPhandleCache[pdtnDev->DTN_uiHandle & _G_uiPhandleCacheMask] = pdtnDev;
+ }
+ }
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeUnflattenNodes
+** 功能描述: 进行设备树型结构解析;
+** 当 pvMem 为空时,bIsSkip 为 LW_TRUE,此时只快速遍历,不处理过程,可快速得到树大小。
+** 输 入 : pvDevTree 设备树基地址
+** pvMem 设备树开辟的内存基址
+** pdtnFather 父节点
+** ppdtnCur 用于获取当前节点
+** 输 出 : 正确时返回当前遍历过的设备树内存偏移,
+** 错误时返回 PX_ERROR
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeUnflattenNodes (PVOID pvDevTree,
+ PVOID pvMem,
+ PLW_DEVTREE_NODE pdtnFather,
+ PLW_DEVTREE_NODE *ppdtnCur)
+{
+ PLW_DEVTREE_NODE pdtnPointers[FDT_MAX_DEPTH];
+ PLW_DEVTREE_NODE pdtnRoot;
+ INT iOffset;
+ INT iDepth;
+ INT iInitialDepth;
+ PVOID pvBase = pvMem;
+ BOOL bIsSkip = !pvMem; /* 是否只遍历,不处理过程 */
+
+ if (ppdtnCur) { /* 首先将当前节点置为 NULL */
+ *ppdtnCur = LW_NULL;
+ }
+
+ if (pdtnFather) { /* 如果有父节点 */
+ iDepth = 1; /* 初始的树深度设置为 1 */
+ iInitialDepth = 1;
+ } else {
+ iDepth = 0;
+ iInitialDepth = 0;
+ }
+
+ pdtnRoot = pdtnFather; /* 当前的根节点为 父节点 */
+ pdtnPointers[iDepth] = pdtnFather;
+
+ for (iOffset = 0;
+ (iOffset >= 0) && (iDepth >= iInitialDepth); /* 还没有遍历完整设备树 */
+ iOffset = fdt_next_node(pvDevTree, iOffset, &iDepth)) {
+
+ if (iDepth >= FDT_MAX_DEPTH) { /* 如果已经超出最大深度 */
+ _ErrorHandle(ERROR_DEVTREE_DEPTH_ERROR);
+ return (PX_ERROR);
+ }
+
+ if (!API_DeviceTreeNodeIsOkayByOffset(pvDevTree, iOffset)) { /* 如果节点不可用 */
+ continue;
+ }
+
+ if (!__deviceTreeNodePopulate(pvDevTree,
+ iOffset,
+ &pvMem, /* 过程中会更新 pvMem 的位置 */
+ pdtnPointers[iDepth],
+ &pdtnPointers[iDepth + 1],
+ bIsSkip)) { /* 生成可用的节点 */
+ return ((addr_t)pvMem - (addr_t)pvBase); /* 计算需要的内存大小 */
+ }
+
+ if (!bIsSkip && /* 需要记录节点 */
+ ppdtnCur &&
+ (*ppdtnCur == LW_NULL)) { /* 当前访问到的节点为空时, */
+ *ppdtnCur = pdtnPointers[iDepth + 1]; /* 记录当前访问到最后的节点 */
+ }
+
+ if (!bIsSkip && !pdtnRoot) { /* 需要记录节点且根节点为空 */
+ pdtnRoot = pdtnPointers[iDepth + 1]; /* 记录根节点 */
+ }
+ }
+
+ if ((iOffset < 0) && (iOffset != -FDT_ERR_NOTFOUND)) { /* 如果设备树解析出错 */
+ _ErrorHandle(ERROR_DEVTREE_POPULATE_ERROR);
+ return (PX_ERROR);
+ }
+
+ if (!bIsSkip) { /* 如果设备树解析结束 */
+ __deviceTreeNodesReverse(pdtnRoot); /* 反向排序树的结构 */
+ }
+
+ return ((addr_t)pvMem - (addr_t)pvBase); /* 计算需要的内存大小 */
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeUnflatten
+** 功能描述: 按照设备树树形结构展开设备树。
+** 先快速遍历一次设备树结构,获取设备树大小,再进行实际的设备树解析
+** 输 入 : pvDevtreeMem 设备树基地址
+** pdtnFather 父节点
+** ppdtnCur 用于获取当前节点
+** pfuncDtAlloc 内存申请函数
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeUnflatten (PVOID pvDevtreeMem,
+ PLW_DEVTREE_NODE pdtnFather,
+ PLW_DEVTREE_NODE *ppdtnCur,
+ FUNC_DT_ALLOC pfuncDtAlloc)
+{
+ PVOID pvMem;
+ INT iSize;
+
+ DEVTREE_MSG("Start unflatten device tree:\r\n");
+ DEVTREE_MSG("magic : %08x\r\n", fdt_magic(pvDevtreeMem));
+ DEVTREE_MSG("size : %08x\r\n", fdt_totalsize(pvDevtreeMem));
+ DEVTREE_MSG("version: %08x\r\n", fdt_version(pvDevtreeMem));
+
+ iSize = __deviceTreeUnflattenNodes(pvDevtreeMem, LW_NULL,
+ pdtnFather, LW_NULL); /* 获取设备树大小 */
+ if (iSize < 0) {
+ return (PX_ERROR);
+ }
+
+ iSize = ROUND_UP(iSize, 4); /* 找对齐的内存大小 */
+
+ DEVTREE_MSG("Device tree is allocating %d bytes...\r\n", iSize);
+
+ pvMem = pfuncDtAlloc(iSize + DEVTREE_MEM_GUARD_SIZE,
+ __alignof__(LW_DEVTREE_NODE)); /* 申请设备树所需内存 */
+ if (!pvMem) {
+ _ErrorHandle(ENOMEM);
+ return (PX_ERROR);
+ }
+
+ lib_bzero(pvMem, iSize);
+
+ __deviceTreeMemGuardSet(pvMem, iSize); /* 设置内存警戒标志 */
+
+ __deviceTreeUnflattenNodes(pvDevtreeMem, pvMem,
+ pdtnFather, ppdtnCur); /* 正式展开设备树 */
+
+ if (__deviceTreeMemGuardGet(pvMem, iSize) != DEVTREE_MEM_GUARD) { /* 如果产生了越界 */
+ _ErrorHandle(ERROR_DEVTREE_MEM_OVERLAP);
+ return (PX_ERROR);
+ }
+
+ DEVTREE_MSG("Device tree unflattened success!\r\n");
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeAliasIdGet
+** 功能描述: 从别名属性链表中查找对应设备的 ID
+** 输 入 : pdtnDev 设备树节点
+** pcStem 设备名称
+** 输 出 : 设备的 ID
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeAliasIdGet (PLW_DEVTREE_NODE pdtnDev, CPCHAR pcStem)
+{
+ PLW_DEVTREE_ALIAS_PROPERTY pdtaprop;
+ PLW_LIST_LINE plineTemp;
+ INT iId = -ENODEV;
+
+ for (plineTemp = _G_plineheadAliasesLookup;
+ plineTemp != LW_NULL;
+ plineTemp = _list_line_get_next(plineTemp)) {
+
+ pdtaprop = _LIST_ENTRY(plineTemp, LW_DEVTREE_ALIAS_PROPERTY, DTALP_plineManage);
+ if (lib_strcmp(pdtaprop->DTALP_cStem, pcStem) != 0) {
+ continue;
+ }
+
+ if (pdtnDev == pdtaprop->DTALP_pdtnDev) {
+ iId = pdtaprop->DTALP_iId;
+ break;
+ }
+ }
+
+ return (iId);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeHighLevelInit
+** 功能描述: 设备树高级初始化,需要在系统初始化完成后调用
+** 输 入 : pvDevtreeMem 设备树地址
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeHighLevelInit (PVOID pvDevtreeMem)
+{
+ if (!pvDevtreeMem) {
+ _ErrorHandle(ERROR_KERNEL_OBJECT_NULL);
+ return (PX_ERROR);
+ }
+
+ if (fdt_check_header(pvDevtreeMem)) { /* 设备树头部校验 */
+ _ErrorHandle(ERROR_DEVTREE_MAGIC_ERROR);
+ return (PX_ERROR);
+ }
+
+ if (__deviceTreeUnflatten(pvDevtreeMem,
+ LW_NULL,
+ &_G_pdtnRoot,
+ __deviceTreeMemoryAlloc)) { /* 实际生成设备树树形结构 */
+ return (PX_ERROR);
+ }
+
+ __deviceTreeAliasScan(__deviceTreeMemoryAlloc); /* 生成 Alias 节点 */
+
+ __deviceTreePhandleCachePopulate(); /* 生成 Phandle Cache 信息 */
+
+ return (ERROR_NONE);
+}
+
+#endif /* LW_CFG_DEVTREE_EN > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtreeI2c.c b/SylixOS/devtree/devtreeI2c.c
new file mode 100644
index 0000000..ec857b3
--- /dev/null
+++ b/SylixOS/devtree/devtreeI2c.c
@@ -0,0 +1,163 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtreeI2c.c
+**
+** 创 建 人: Zhang.Jian (张健)
+**
+** 文件创建日期: 2019 年 11 月 20 日
+**
+** 描 述: I2C 驱动框架中设备树相关接口
+*********************************************************************************************************/
+#define __SYLIXOS_STDIO
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if LW_CFG_DEVTREE_EN > 0
+#include "devtree.h"
+/*********************************************************************************************************
+** 函数名称: __deviceTreeI2cDevInfoGet
+** 功能描述: 获取 I2C 设备信息
+** 输 入 : pdti2cdevice I2C 设备指针
+** pdtnDev I2C 设备的设备树节点
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeI2cDevInfoGet (PLW_DT_I2C_DEVICE pdti2cdevice, PLW_DEVTREE_NODE pdtnDev)
+{
+ ULONG ulIrqNum = 0;
+ UINT32 uiAddr = 0;
+ INT iRet;
+
+ API_DeviceTreeIrqGet(pdtnDev, 0, &ulIrqNum); /* 获取 I2C 设备中断号 */
+ if (ulIrqNum > 0) {
+ pdti2cdevice->DTI2CDEV_ulIrq = ulIrqNum;
+ }
+
+ iRet = API_DeviceTreePropertyU32Read(pdtnDev, "reg", &uiAddr); /* 获取 I2C 设备地址 */
+ if (iRet) {
+ DEVTREE_ERR("%s has invalid address\n", pdtnDev->DTN_pcFullName);
+ return (PX_ERROR);
+ }
+
+ if (uiAddr & LW_I2C_TEN_BIT_ADDRESS) {
+ uiAddr &= ~LW_I2C_TEN_BIT_ADDRESS;
+ pdti2cdevice->DTI2CDEV_usFlag |= LW_I2C_CLIENT_TEN;
+ }
+
+ if (uiAddr & LW_I2C_OWN_SLAVE_ADDRESS) {
+ uiAddr &= ~LW_I2C_OWN_SLAVE_ADDRESS;
+ pdti2cdevice->DTI2CDEV_usFlag |= LW_I2C_CLIENT_SLAVE;
+ }
+
+ /*
+ * 检查地址合法性
+ */
+ if (pdti2cdevice->DTI2CDEV_usFlag & LW_I2C_CLIENT_TEN) {
+ if (uiAddr > 0x3ff) {
+ return (PX_ERROR);
+ }
+ } else {
+ if ((uiAddr == 0x00) || (uiAddr > 0x7f)) {
+ return (PX_ERROR);
+ }
+ }
+
+ pdti2cdevice->DTI2CDEV_usAddr = uiAddr;
+
+ snprintf(pdti2cdevice->DTI2CDEV_cName, LW_I2C_NAME_SIZE, "%s",
+ pdtnDev->DTN_pcFullName); /* 设置 I2C 设备名称 */
+
+ pdti2cdevice->DTI2CDEV_atomicUsageCnt.counter = 0;
+ pdti2cdevice->DTI2CDEV_devinstance.DEVHD_pdtnDev = pdtnDev;
+ pdti2cdevice->DTI2CDEV_devinstance.DEVHD_pcName = pdtnDev->DTN_pcFullName;
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeI2cAdapterRegister
+** 功能描述: 从设备树中解析 I2C 控制器下挂载的设备
+** 输 入 : pdti2cadapter I2C 控制器指针
+** pdtnDev I2C 控制器的设备树节点
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeI2cAdapterRegister (PLW_DT_I2C_ADAPTER pdti2cadapter,
+ PLW_DEVTREE_NODE pdtnDev)
+{
+ PLW_DEVTREE_NODE pdtnChild;
+ INT iRet;
+
+ iRet = API_I2cAdapterRegister(pdti2cadapter); /* 先注册 I2C 控制器 */
+ if (iRet) {
+ return (iRet);
+ }
+
+ _LIST_EACH_CHILD_OF_NODE(pdtnDev, pdtnChild) { /* 遍历该节点的子节点 */
+ API_DeviceTreeI2cDevRegister(pdti2cadapter, pdtnChild); /* 注册 I2C 设备 */
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeI2cDevRegister
+** 功能描述: 通过设备树注册 I2C 设备
+** 输 入 : pdti2cadapter I2C 控制器指针
+** pdtnDev I2C 设备节点
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeI2cDevRegister (PLW_DT_I2C_ADAPTER pdti2cadapter,
+ PLW_DEVTREE_NODE pdtnDev)
+{
+ PLW_DT_I2C_DEVICE pdti2cdevice;
+ INT iRet;
+
+ pdti2cdevice = API_I2cDevCreate(pdti2cadapter); /* 创建 I2C 设备 */
+ if (LW_NULL == pdti2cdevice) {
+ return (PX_ERROR);
+ }
+
+ iRet = __deviceTreeI2cDevInfoGet(pdti2cdevice, pdtnDev); /* 从设备树中获取 I2C 设备信息 */
+ if (iRet) {
+ API_I2cDevDelete(pdti2cdevice);
+ return (PX_ERROR);
+ }
+
+ iRet = API_I2cDevRegister(pdti2cdevice); /* 注册 I2C 设备到系统 */
+ if (iRet) {
+ DEVTREE_ERR("I2C device %s register failed.\r\n",
+ pdtnDev->DTN_pcFullName);
+ API_I2cDevDelete(pdti2cdevice);
+
+ } else {
+ DEVTREE_MSG("Register I2C device %s at addr 0x%x.\r\n",
+ pdtnDev->DTN_pcFullName, pdti2cdevice->DTI2CDEV_usAddr);
+ }
+
+ return (iRet);
+}
+
+#endif /* LW_CFG_DEVTREE_EN > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtreeIrq.c b/SylixOS/devtree/devtreeIrq.c
new file mode 100644
index 0000000..5deef87
--- /dev/null
+++ b/SylixOS/devtree/devtreeIrq.c
@@ -0,0 +1,479 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtreeIrq.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 06 月 21 日
+**
+** 描 述: 设备树接口中断相关接口实现
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if LW_CFG_DEVTREE_EN > 0
+#include "devtree.h"
+#include "driver/fdt/libfdt_env.h"
+#include "driver/fdt/libfdt.h"
+#include "driver/fdt/fdt.h"
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeIrqCountGet
+** 功能描述: 设备树节点的中断资源数获取
+** 输 入 : pdtnDev 指定的设备树节点
+** 输 出 : 中断资源数量
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeIrqCountGet (PLW_DEVTREE_NODE pdtnDev)
+{
+ LW_DEVTREE_PHANDLE_ARGS dtpaIrq;
+ INT iNr = 0;
+
+ while (API_DeviceTreeIrqOneParse(pdtnDev, iNr, &dtpaIrq) == ERROR_NONE) {
+ iNr++;
+ }
+
+ return (iNr);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeIrqFindParent
+** 功能描述: 查找设备树节点的中断父节点
+** 输 入 : pdtnChild 指定的设备树节点
+** 输 出 : 中断父节点
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_DEVTREE_NODE API_DeviceTreeIrqFindParent (PLW_DEVTREE_NODE pdtnChild)
+{
+ PLW_DEVTREE_NODE pdtnDev;
+ UINT32 uiParent;
+
+ if (!pdtnChild) { /* 若当前节点为空,父节点为空 */
+ return (LW_NULL);
+ }
+
+ do {
+ if (API_DeviceTreePropertyU32Read(pdtnChild,
+ "interrupt-parent",
+ &uiParent)) { /* 读取父节点的 phandle */
+ pdtnDev = pdtnChild->DTN_pdtnparent; /* 若读取失败,取当前节点父节点*/
+ } else {
+ pdtnDev = API_DeviceTreeFindNodeByPhandle(uiParent); /* 根据 phandle 查找节点 */
+ }
+ pdtnChild = pdtnDev;
+
+ } while (pdtnDev && /* 节点需 interrupt-cells 属性 */
+ (API_DeviceTreePropertyGet(pdtnDev, "#interrupt-cells", LW_NULL) == LW_NULL));
+
+ return (pdtnDev);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeIrqRawParse
+** 功能描述: 对 Irq 属性进行解析
+** 输 入 : puiAddr Irq 属性的基地址
+** pdtpaOutIrq 存储 Irq 信息的参数
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeIrqRawParse (const UINT32 *puiAddr, PLW_DEVTREE_PHANDLE_ARGS pdtpaOutIrq)
+{
+ static UINT32 uiDummyImask[MAX_PHANDLE_ARGS];
+ static BOOL bIsInited = LW_FALSE;
+ PLW_DEVTREE_NODE pdtnIpar;
+ PLW_DEVTREE_NODE pdtnDev;
+ PLW_DEVTREE_NODE pdtnOld = LW_NULL;
+ PLW_DEVTREE_NODE pdtnNewParent = LW_NULL;
+
+ UINT32 uiInitialMatchArray[MAX_PHANDLE_ARGS];
+ const UINT32 *puiMatchArray = uiInitialMatchArray;
+ const UINT32 *puiTmp;
+ const UINT32 *puiImap;
+ const UINT32 *puiImask;
+
+ UINT32 uiIntSize = 1;
+ UINT32 uiAddrSize;
+ UINT32 uiNewIntSize = 0;
+ UINT32 uiNewAddrSize = 0;
+ INT iImapLen;
+ INT iMatch;
+ INT i;
+ INT iRet = -EINVAL;
+
+ if (!pdtpaOutIrq) {
+ _ErrorHandle(EINVAL);
+ return (-EINVAL);
+ }
+
+ if (!bIsInited) {
+ bIsInited = LW_TRUE;
+ lib_memset(uiDummyImask, 0xff, sizeof(uiDummyImask));
+ }
+
+ pdtnIpar = pdtpaOutIrq->DTPH_pdtnDev; /* 获取中断父节点 */
+
+ do {
+ if (!API_DeviceTreePropertyU32Read(pdtnIpar,
+ "#interrupt-cells",
+ &uiIntSize)) { /* 读取 "#interrupt-cells" */
+ break;
+ }
+ pdtnDev = pdtnIpar;
+ pdtnIpar = API_DeviceTreeIrqFindParent(pdtnIpar);
+ } while (pdtnIpar);
+
+ if (pdtnIpar == LW_NULL) { /* 如果中断父节点为空 */
+ DEVTREE_MSG(" -> no parent found !\r\n");
+ goto __error_handle;
+ }
+
+ DEVTREE_MSG("of_irq_parse_raw: ipar=%p, size=%d\r\n", pdtnIpar, uiIntSize);
+
+ if (pdtpaOutIrq->DTPH_iArgsCount != uiIntSize) {
+ goto __error_handle;
+ }
+
+ pdtnOld = pdtnIpar;
+ do {
+ puiTmp = API_DeviceTreePropertyGet(pdtnOld,
+ "#address-cells",
+ LW_NULL); /* 查找 "#address-cells" 属性 */
+ pdtnDev = pdtnOld->DTN_pdtnparent;
+ pdtnOld = pdtnDev;
+ } while (pdtnOld && (puiTmp == LW_NULL));
+
+ pdtnOld = LW_NULL;
+ uiAddrSize = (puiTmp == LW_NULL) ? 2 : be32toh(*puiTmp); /* 得到地址占用的大小 */
+
+ DEVTREE_MSG(" -> addrsize=%d\r\n", uiAddrSize);
+
+ if ((uiAddrSize + uiIntSize) > MAX_PHANDLE_ARGS) { /* 如果总字节数大于参数长度 */
+ iRet = -EFAULT;
+ goto __error_handle;
+ }
+
+ for (i = 0; i < uiAddrSize; i++) { /* 读取地址字节 */
+ uiInitialMatchArray[i] = puiAddr ? puiAddr[i] : 0;
+ }
+
+ for (i = 0; i < uiIntSize; i++) { /* 读取中断参数 */
+ uiInitialMatchArray[uiAddrSize + i] = htobe32(pdtpaOutIrq->DTPH_uiArgs[i]);
+ }
+
+ while (pdtnIpar != LW_NULL) {
+ if (API_DeviceTreePropertyBoolRead(pdtnIpar,
+ "interrupt-controller")) { /* 查找 "interrupt-controller" */
+ DEVTREE_MSG(" -> got it !\r\n");
+ return (ERROR_NONE);
+ }
+
+ if (uiAddrSize && !puiAddr) {
+ DEVTREE_MSG(" -> no reg passed in when needed !\n");
+ goto __error_handle;
+ }
+
+ puiImap = API_DeviceTreePropertyGet(pdtnIpar,
+ "interrupt-map",
+ &iImapLen); /* 查找 "interrupt-map" */
+ if (puiImap == LW_NULL) {
+ DEVTREE_MSG(" -> no map, getting parent\n");
+ pdtnNewParent = API_DeviceTreeIrqFindParent(pdtnIpar);
+ goto __skip_level;
+ }
+ iImapLen /= sizeof(UINT32);
+
+ puiImask = API_DeviceTreePropertyGet(pdtnIpar,
+ "interrupt-map-mask",
+ LW_NULL); /* 查找 "interrupt-map-mask" */
+ if (!puiImask) {
+ puiImask = uiDummyImask;
+ }
+
+ iMatch = 0; /* 解析 "interrupt-map" */
+ while (iImapLen > (uiAddrSize + uiIntSize + 1) && !iMatch) {
+ iMatch = 1;
+ for (i = 0;
+ i < (uiAddrSize + uiIntSize);
+ i++, iImapLen--) {
+ iMatch &= !((puiMatchArray[i] ^ *puiImap++) & puiImask[i]);
+ }
+
+ DEVTREE_MSG(" -> match=%d (imaplen=%d)\n", iMatch, iImapLen);
+
+ pdtnNewParent = API_DeviceTreeFindNodeByPhandle(BE32_TO_CPU(puiImap));
+ puiImap++;
+ --iImapLen;
+
+ if (pdtnNewParent == LW_NULL) {
+ DEVTREE_MSG(" -> imap parent not found !\n");
+ goto __error_handle;
+ }
+
+ if (!API_DeviceTreeNodeIsOkay(pdtnNewParent)) {
+ iMatch = 0;
+ }
+
+ if (API_DeviceTreePropertyU32Read(pdtnNewParent,
+ "#interrupt-cells",
+ &uiNewIntSize)) {
+ DEVTREE_MSG(" -> parent lacks #interrupt-cells!\n");
+ goto __error_handle;
+ }
+
+ if (API_DeviceTreePropertyU32Read(pdtnNewParent,
+ "#address-cells",
+ &uiNewAddrSize)) {
+ uiNewAddrSize = 0;
+ }
+
+ DEVTREE_MSG(" -> newintsize=%d, newaddrsize=%d\n",
+ uiNewIntSize, uiNewAddrSize);
+
+ if (((uiNewAddrSize + uiNewIntSize) > MAX_PHANDLE_ARGS) ||
+ (iImapLen < (uiNewAddrSize + uiNewIntSize))) {
+ iRet = -EFAULT;
+ goto __error_handle;
+ }
+
+ puiImap += uiNewAddrSize + uiNewIntSize;
+ iImapLen -= uiNewAddrSize + uiNewIntSize;
+
+ DEVTREE_MSG(" -> imaplen=%d\n", iImapLen);
+ }
+
+ if (!iMatch) {
+ goto __error_handle;
+ }
+
+ puiMatchArray = puiImap - uiNewAddrSize - uiNewIntSize;
+ for (i = 0; i < uiNewIntSize; i++) {
+ pdtpaOutIrq->DTPH_uiArgs[i] = BE32_TO_CPU(puiImap - uiNewIntSize + i);
+ }
+ uiIntSize = uiNewIntSize;
+ pdtpaOutIrq->DTPH_iArgsCount = uiNewIntSize;
+ uiAddrSize = uiNewAddrSize;
+
+__skip_level:
+ pdtpaOutIrq->DTPH_pdtnDev = pdtnNewParent;
+ DEVTREE_MSG(" -> new parent: %p\n", pdtnNewParent);
+ pdtnIpar = pdtnNewParent;
+ pdtnNewParent = LW_NULL;
+ }
+
+ iRet = -ENOENT;
+
+__error_handle:
+ return (iRet);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeIrqOneParse
+** 功能描述: 解析一条中断资源
+** 输 入 : pdtnDev 设备树节点
+** iIndex 中断资源序号
+** pdtpaOutIrq 解析出的中断资源参数
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeIrqOneParse (PLW_DEVTREE_NODE pdtnDev,
+ INT iIndex,
+ PLW_DEVTREE_PHANDLE_ARGS pdtpaOutIrq)
+{
+ PLW_DEVTREE_NODE pnoTemp;
+ const UINT32 *puiAddr;
+ UINT32 uiIntSize;
+ INT i;
+ INT iRet;
+
+ DEVTREE_MSG("of_irq_parse_one: dev=%p, index=%d\r\n", pdtnDev, iIndex);
+
+ puiAddr = API_DeviceTreePropertyGet(pdtnDev, "reg", LW_NULL);
+
+ iRet = API_DeviceTreePhandleParseWithArgs(pdtnDev,
+ "interrupts-extended",
+ "#interrupt-cells",
+ iIndex, pdtpaOutIrq); /* 尝试按照中断扩展资源解析 */
+ if (!iRet) {
+ return API_DeviceTreeIrqRawParse(puiAddr, pdtpaOutIrq);
+ }
+
+ pnoTemp = API_DeviceTreeIrqFindParent(pdtnDev); /* 查找对应的中断父节点 */
+ if (pnoTemp == LW_NULL) {
+ return (-EINVAL);
+ }
+
+ if (API_DeviceTreePropertyU32Read(pnoTemp,
+ "#interrupt-cells",
+ &uiIntSize)) { /* 获取 interrupt-cells 大小 */
+ iRet = -EINVAL;
+ goto __error_handle;
+ }
+
+ DEVTREE_MSG(" parent=%p, intsize=%d\r\n", pnoTemp, uiIntSize);
+
+ pdtpaOutIrq->DTPH_pdtnDev = pnoTemp;
+ pdtpaOutIrq->DTPH_iArgsCount = uiIntSize;
+
+ for (i = 0; i < uiIntSize; i++) { /* 读取 interrupts 属性 */
+ iRet = API_DeviceTreePropertyU32IndexRead(pdtnDev,
+ "interrupts",
+ (iIndex * uiIntSize) + i,
+ pdtpaOutIrq->DTPH_uiArgs + i);
+ if (iRet) {
+ goto __error_handle;
+ }
+ }
+
+ DEVTREE_MSG(" intspec=%d\r\n", *pdtpaOutIrq->DTPH_uiArgs);
+
+ iRet = API_DeviceTreeIrqRawParse(puiAddr, pdtpaOutIrq); /* 解析属性值 */
+
+__error_handle:
+ return (iRet);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeIrqGet
+** 功能描述: 获取设备树节点的中断资源,转换为 SylixOS 中断号返回
+** 输 入 : pdtnDev 设备树节点
+** iIndex 中断资源序号
+** pulVector 存储获取的 SylixOS 中断号
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeIrqGet (PLW_DEVTREE_NODE pdtnDev, INT iIndex, ULONG *pulVector)
+{
+ LW_DEVTREE_PHANDLE_ARGS dtpaOutIrq;
+ PLW_IRQCTRL_DEV pirqctrldev;
+ ULONG ulHwIrq;
+ ULONG ulVector;
+ UINT uiType;
+ INT iRet;
+
+ if (!pulVector) {
+ return (PX_ERROR);
+ }
+
+ iRet = API_DeviceTreeIrqOneParse(pdtnDev, iIndex, &dtpaOutIrq); /* 解析一条中断资源 */
+ if (iRet) {
+ return (iRet);
+ }
+
+ pirqctrldev = API_IrqCtrlDevtreeNodeMatch(dtpaOutIrq.DTPH_pdtnDev); /* 找到对应的中断控制器 */
+ if (!pirqctrldev) {
+ return (PX_ERROR);
+ }
+
+ iRet = API_IrqCtrlDevtreeTrans(pirqctrldev, &dtpaOutIrq, &ulHwIrq, &uiType);
+ if (iRet) {
+ return (iRet);
+ }
+
+ iRet = API_IrqCtrlFindVectorByHwIrq(pirqctrldev, ulHwIrq, &ulVector);
+ if (iRet != PX_ERROR) {
+ *pulVector = ulVector;
+
+ } else {
+ iRet = API_IrqCtrlHwIrqMapToVector(pirqctrldev, ulHwIrq, &ulVector);
+ if (iRet != PX_ERROR) {
+ *pulVector = ulVector;
+ }
+ }
+
+ return (iRet);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeIrqToResource
+** 功能描述: 获取设备树节点的中断资源,转换为资源表项
+** 输 入 : pdtnDev 设备树节点
+** iIndex 中断资源序号
+** pdevresource 资源表指针
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeIrqToResource (PLW_DEVTREE_NODE pdtnDev,
+ INT iIndex,
+ PLW_DEV_RESOURCE pdevresource)
+{
+ ULONG ulVector;
+ INT iRet;
+
+ iRet = API_DeviceTreeIrqGet(pdtnDev, iIndex, &ulVector); /* 转换成 SylixOS 的中断号 */
+ if (iRet != ERROR_NONE) {
+ return (iRet);
+ }
+
+ if (pdevresource && ulVector) { /* 当资源指针有效时进行转换 */
+ CPCHAR pcName = LW_NULL;
+
+ lib_bzero(pdevresource, sizeof(LW_DEV_RESOURCE));
+
+ API_DeviceTreePropertyStringIndexRead(pdtnDev,
+ "interrupt-names",
+ iIndex,
+ &pcName); /* 获取中断名称属性 */
+
+ pdevresource->irq.DEVRES_ulIrq = ulVector; /* 记录中断号 */
+ pdevresource->DEVRES_pcName = pcName ? /* 记录中断名 */
+ pcName : __deviceTreeNodeFullName(pdtnDev);
+ }
+
+ return (iRet);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeIrqToResouceTable
+** 功能描述: 获取设备树节点的中断资源,转换为资源表
+** 输 入 : pdtnDev 设备树节点
+** pdevresource 资源表指针
+** iNrIrqs 中断资源数量
+** 输 出 : 已经转换的中断资源数量
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeIrqToResouceTable (PLW_DEVTREE_NODE pdtnDev,
+ PLW_DEV_RESOURCE pdevresource,
+ INT iNrIrqs)
+{
+ INT i;
+
+ for (i = 0; i < iNrIrqs; i++) {
+ if (API_DeviceTreeIrqToResource(pdtnDev, i, pdevresource) <= 0) {
+ break;
+ }
+ }
+
+ return (i);
+}
+
+#endif /* LW_CFG_DEVTREE_EN > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtreeLib.c b/SylixOS/devtree/devtreeLib.c
new file mode 100644
index 0000000..91c811a
--- /dev/null
+++ b/SylixOS/devtree/devtreeLib.c
@@ -0,0 +1,816 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtreeLib.c
+**
+** 创 建 人: Wang.Xuan(王翾)
+**
+** 文件创建日期: 2019 年 07 月 31 日
+**
+** 描 述: 设备树通用接口
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if LW_CFG_DEVTREE_EN > 0
+#include "devtree.h"
+#include "driver/fdt/libfdt_env.h"
+#include "driver/fdt/libfdt.h"
+#include "driver/fdt/fdt.h"
+/*********************************************************************************************************
+ 全局可见变量
+*********************************************************************************************************/
+PLW_DEVTREE_NODE _G_pdtnRoot; /* root 节点 */
+PLW_DEVTREE_NODE _G_pdtnAliases; /* aliases 节点 */
+PLW_DEVTREE_NODE *_G_ppdtnPhandleCache; /* phandle cache */
+UINT32 _G_uiPhandleCacheMask;
+/*********************************************************************************************************
+ 宏定义
+*********************************************************************************************************/
+#define DEVTREE_MAX_ADDR_CELLS 4
+#define DEVTREE_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= DEVTREE_MAX_ADDR_CELLS)
+#define DEVTREE_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= DEVTREE_MAX_ADDR_CELLS && (ns) > 0)
+/*********************************************************************************************************
+ 函数声明
+*********************************************************************************************************/
+static VOID __deviceTreeDefaultCountCells(PLW_DEVTREE_NODE pdtnDev,
+ INT *piCellAddr,
+ INT *piCellSize);
+static UINT64 __deviceTreeDefaultMap(UINT32 *puiAddr,
+ UINT32 *puiRange,
+ INT iNumAddr,
+ INT iNumSize,
+ INT iParentNumAddr);
+static INT __deviceTreeDefaultTranslate(UINT32 *puiAddr,
+ UINT64 ullOffset,
+ INT iNumAddr);
+/*********************************************************************************************************
+ 全局变量
+*********************************************************************************************************/
+static LW_DEVTREE_BUS _G_dtbBusses[] = {
+ { /* Default */
+ .DTBUS_pcAddresses = "reg",
+ .DTBUS_match = LW_NULL,
+ .DTBUS_cellsCount = __deviceTreeDefaultCountCells,
+ .DTBUS_map = __deviceTreeDefaultMap,
+ .DTBUS_translate = __deviceTreeDefaultTranslate,
+ },
+};
+/*********************************************************************************************************
+** 函数名称: __deviceTreeAddrDump
+** 功能描述: 打印 addr cells 里的信息
+** 输 入 : pcStr 前缀输出字符串
+** puiAddr addr cells 地址
+** iNumAddr addr cells 的个数
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __deviceTreeAddrDump (CPCHAR pcStr, const UINT32 *puiAddr, INT iNumAddr)
+{
+#if DEVTREE_DEBUG_EN > 0
+ DEVTREE_MSG("%s", pcStr);
+ while (iNumAddr--) {
+ DEVTREE_MSG(" %08x", be32toh(*(puiAddr++)));
+ }
+ DEVTREE_MSG("\r\n");
+#endif
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeDefaultCountCells
+** 功能描述: 默认总线类型计算 cells 个数
+** 输 入 : pdtnDev 设备树节点
+** piCellAddr 存储 addr cells 的个数
+** piCellSize 存储 size cells 的个数
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __deviceTreeDefaultCountCells (PLW_DEVTREE_NODE pdtnDev,
+ INT *piCellAddr,
+ INT *piCellSize)
+{
+ if (piCellAddr) {
+ *piCellAddr = API_DeviceTreeNAddrCells(pdtnDev);
+ }
+
+ if (piCellSize) {
+ *piCellSize = API_DeviceTreeNSizeCells(pdtnDev);
+ }
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeDefaultMap
+** 功能描述: 默认总线设备的映射方法
+** 输 入 : puiAddr 当前地址
+** puiRange range 属性指针
+** iNumAddr address-cells
+** iNumSize address-size
+** iParentNumAddr 父节点的 address-cells
+** 输 出 : 当前偏移
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static UINT64 __deviceTreeDefaultMap (UINT32 *puiAddr,
+ UINT32 *puiRange,
+ INT iNumAddr,
+ INT iNumSize,
+ INT iParentNumAddr)
+{
+ UINT64 ullCp;
+ UINT64 ullS;
+ UINT64 ullDa;
+
+ ullCp = __deviceTreeNumberRead(puiRange, iNumAddr);
+ ullS = __deviceTreeNumberRead(puiRange + iNumAddr + iParentNumAddr, iNumSize);
+ ullDa = __deviceTreeNumberRead(puiAddr, iNumAddr);
+
+ if ((ullDa < ullCp) || (ullDa >= (ullCp + ullS))) {
+ return (PX_ERROR);
+ }
+
+ return (ullDa - ullCp);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeDefaultTranslate
+** 功能描述: 默认地址总线类型的地址转换方法
+** 输 入 : puiAddr 存储转换后地址的变量指针
+** ullOffset 转换的偏移地址
+** iNumAddr 地址 cells 的个数
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeDefaultTranslate (UINT32 *puiAddr,
+ UINT64 ullOffset,
+ INT iNumAddr)
+{
+ UINT64 ullAddr = __deviceTreeNumberRead(puiAddr, iNumAddr);
+
+ lib_bzero(puiAddr, iNumAddr * 4);
+ ullAddr += ullOffset;
+
+ if (iNumAddr > 1) {
+ puiAddr[iNumAddr - 2] = htobe32(ullAddr >> 32);
+ }
+
+ puiAddr[iNumAddr - 1] = htobe32(ullAddr & 0xfffffffful);
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeBusMatch
+** 功能描述: 匹配合适的 bus
+** 输 入 : pdtnDev 用于匹配的设备树节点
+** 输 出 : 匹配到的 bus 或 LW_NULL
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static PLW_DEVTREE_BUS __deviceTreeBusMatch (PLW_DEVTREE_NODE pdtnDev)
+{
+ INT i;
+
+ for (i = 0; i < ARRAY_SIZE(_G_dtbBusses); i++) {
+ if (!_G_dtbBusses[i].DTBUS_match || /* 默认按照 default bus 匹配 */
+ _G_dtbBusses[i].DTBUS_match(pdtnDev)) {
+ return (&_G_dtbBusses[i]);
+ }
+ }
+
+ return (LW_NULL);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreePropertyStringIndexRead
+** 功能描述: 按照序号读取 String 类型属性
+** 输 入 : pdtnDev 设备树节点
+** pcPropName 属性名称
+** iIndex 属性序号
+** ppcOutput 读取的 String 属性
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreePropertyStringIndexRead (PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropName,
+ INT iIndex,
+ CPCHAR *ppcOutput)
+{
+ INT iRc = API_DeviceTreePropertyStringHelperRead(pdtnDev, pcPropName,
+ ppcOutput, 1, iIndex, LW_NULL);
+
+ return (iRc < 0 ? iRc : 0);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeTranslateOne
+** 功能描述: 将地址属性基址转换为实际 64 位地址
+** 注:ranges 属性值为空时,表示 1:1 映射
+** 输 入 : pdtnParent 父设备树节点
+** pdtbBus 对应的总线类型
+** pdtbParentBus 父设备对应的总线类型
+** puiAddr 当前地址
+** iNumAddr address-cells
+** iNumSize address-size
+** iParentNumAddr 父节点的 address-cells
+** pcResourceProp 按指定的属性类型转换
+** 输 出 : 实际 64 位地址
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeTranslateOne (PLW_DEVTREE_NODE pdtnParent,
+ PLW_DEVTREE_BUS pdtbBus,
+ PLW_DEVTREE_BUS pdtbParentBus,
+ UINT32 *puiAddr,
+ INT iNumAddr,
+ INT iNumSize,
+ INT iParentNumAddr,
+ CPCHAR pcResourceProp)
+{
+ UINT32 *puiRanges;
+ UINT uiResourceLen;
+ INT iResourceOne;
+ UINT64 ullOffset = PX_ERROR;
+
+ puiRanges = API_DeviceTreePropertyGet(pdtnParent,
+ pcResourceProp,
+ (INT *)&uiResourceLen); /* 读取父节点的 ranges 属性 */
+ if ((puiRanges == LW_NULL) || /* 如果 ranges 属性为空 */
+ (uiResourceLen == 0)) { /* 或者 ranges 属性长度为 0 */
+ ullOffset = __deviceTreeNumberRead(puiAddr, iNumAddr); /* 读取地址属性值 */
+ lib_bzero(puiAddr, iParentNumAddr * 4);
+ DEVTREE_MSG("empty ranges; 1:1 translation\r\n");
+ goto __finish;
+ }
+
+ DEVTREE_MSG("walking ranges...\r\n");
+
+ /*
+ * 以下对 ranges 属性进行处理
+ */
+ uiResourceLen /= 4;
+ iResourceOne = iNumAddr + iParentNumAddr + iNumSize;
+ for (;
+ uiResourceLen >= iResourceOne;
+ uiResourceLen -= iResourceOne, puiRanges += iResourceOne) {
+ ullOffset = pdtbBus->DTBUS_map(puiAddr, puiRanges, iNumAddr,
+ iNumSize, iParentNumAddr);
+ if (ullOffset != PX_ERROR) {
+ break;
+ }
+ }
+
+ if (ullOffset == PX_ERROR) {
+ DEVTREE_MSG("not found !\r\n");
+ return (PX_ERROR);
+ }
+
+ lib_memcpy(puiAddr, puiRanges + iNumAddr, 4 * iParentNumAddr);
+
+__finish:
+ __deviceTreeAddrDump("parent translation for:", puiAddr, iParentNumAddr);
+
+ DEVTREE_MSG("with offset: %llx\r\n", ullOffset);
+
+ return (pdtbParentBus->DTBUS_translate(puiAddr, ullOffset, iParentNumAddr));
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeAddressTranslate
+** 功能描述: 将地址属性基址转换为实际 64 位地址
+** 输 入 : pdtnDev 设备树节点
+** puiInAddr 地址属性基址
+** pcResourceProp 按指定的属性类型转换
+** 输 出 : 实际 64 位地址
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static UINT64 __deviceTreeAddressTranslate (PLW_DEVTREE_NODE pdtnDev,
+ const UINT32 *puiInAddr,
+ CPCHAR pcResourceProp)
+{
+ PLW_DEVTREE_NODE pdtnParent = LW_NULL;
+ PLW_DEVTREE_BUS pdtbBus;
+ PLW_DEVTREE_BUS pdtbParentBus;
+ UINT32 uiAddr[DEVTREE_MAX_ADDR_CELLS];
+ INT iNumAddr;
+ INT iNumSize;
+ INT iParentNumAddr;
+ INT iParentNumSize;
+ UINT64 ullResult = PX_ERROR;
+
+ DEVTREE_MSG("OF: ** translation for device %s **\r\n",
+ pdtnDev->DTN_pcFullName);
+
+ pdtnParent = pdtnDev->DTN_pdtnparent; /* 获取父节点 */
+ if (pdtnParent == LW_NULL) {
+ goto __end; /* 如果父节点为空,直接返回 */
+ }
+
+ pdtbBus = __deviceTreeBusMatch(pdtnParent); /* 找到对应的总线类型 */
+ pdtbBus->DTBUS_cellsCount(pdtnDev, &iNumAddr, &iNumSize); /* 获取 #size-cells */
+ /* 和 #address-cells */
+
+ if (!DEVTREE_CHECK_COUNTS(iNumAddr, iNumSize)) { /* 判断 cells 是否有效 */
+ DEVTREE_MSG("Bad cell count for %s\r\n",
+ pdtnDev->DTN_pcFullName);
+ goto __end;
+ }
+
+ lib_memcpy(uiAddr, puiInAddr, iNumAddr * 4); /* 按 #address-cells 拷贝数值 */
+
+ __deviceTreeAddrDump("OF: translating address:", uiAddr, iNumAddr);
+
+ for (;;) { /* 开始翻译地址 */
+ pdtnDev = pdtnParent; /* 获取父节点 */
+ pdtnParent = pdtnDev->DTN_pdtnparent; /* 获取爷爷节点 */
+
+ if (pdtnParent == LW_NULL) { /* 如果爷爷节点为 "/" */
+ DEVTREE_MSG("OF: reached root node\r\n");
+ ullResult = __deviceTreeNumberRead(uiAddr, iNumAddr); /* 当前地址基址为最终属性基址 */
+ break;
+ }
+
+ pdtbParentBus = __deviceTreeBusMatch(pdtnParent); /* 获取爷爷节点的总线类型 */
+ pdtbParentBus->DTBUS_cellsCount(pdtnDev,
+ &iParentNumAddr, /* 获取 #address-cells */
+ &iParentNumSize); /* 和 #size-cells */
+
+ if (!DEVTREE_CHECK_COUNTS(iParentNumAddr, iParentNumSize)) { /* 判断 cells 是否有效 */
+ DEVTREE_MSG("Bad cell count for %s\r\n",
+ pdtnDev->DTN_pcFullName);
+ break;
+ }
+
+ if (__deviceTreeTranslateOne(pdtnDev, pdtbBus,
+ pdtbParentBus, uiAddr,
+ iNumAddr, iNumSize,
+ iParentNumAddr, pcResourceProp)) { /* 应用地址转换 */
+ break;
+ }
+
+ iNumAddr = iParentNumAddr; /* 按照爷爷节点信息更新 */
+ iNumSize = iParentNumSize;
+ pdtbBus = pdtbParentBus;
+
+ __deviceTreeAddrDump("OF: one level translation:", uiAddr, iNumAddr);
+ }
+
+__end:
+ return (ullResult); /* 返回最终转换出的 64 位地址 */
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeFindNodeByParentPath
+** 功能描述: 通过设备树节点的父节点全路径查找节点
+** 输 入 : pdtnParent 设备树节点的父节点
+** pcPath 节点路径
+** 输 出 : 设备树节点
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static PLW_DEVTREE_NODE __deviceTreeFindNodeByParentPath (PLW_DEVTREE_NODE pdtnParent,
+ CPCHAR pcPath)
+{
+ PLW_DEVTREE_NODE pdtnChild;
+ CPCHAR pcName;
+ INT iLen;
+
+ iLen = lib_strcspn(pcPath, "/:");
+ if (!iLen) {
+ return (LW_NULL);
+ }
+
+ _LIST_EACH_CHILD_OF_NODE(pdtnParent, pdtnChild) {
+ pcName = __deviceTreeBaseNameGet(pdtnChild->DTN_pcFullName);
+ if ((lib_strncmp(pcPath, pcName, iLen) == 0) &&
+ (lib_strlen(pcName) == iLen)) {
+ return (pdtnChild);
+ }
+ }
+
+ return (LW_NULL);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeFindNodeByFullPath
+** 功能描述: 通过设备树节点全路径查找设备树节点
+** 输 入 : pdtnDev 开始的设备树节点
+** pcPath 节点全路径
+** 输 出 : 设备树节点
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static PLW_DEVTREE_NODE __deviceTreeFindNodeByFullPath (PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPath)
+{
+ CPCHAR pcSeparator = lib_strchr(pcPath, ':');
+
+ while (pdtnDev && (*pcPath == '/')) {
+ pcPath++; /* 从 '/' 之后字符开始查找 */
+ pdtnDev = __deviceTreeFindNodeByParentPath(pdtnDev, pcPath);
+ pcPath = strchrnul(pcPath, '/');
+ if (pcSeparator && (pcSeparator < pcPath)) {
+ break;
+ }
+ }
+
+ return (pdtnDev);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeNAddrCells
+** 功能描述: 获取 addr cells 的个数
+** 输 入 : pdtnDev 设备树节点
+** 输 出 : addr cells 的个数
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeNAddrCells (PLW_DEVTREE_NODE pdtnDev)
+{
+ UINT32 uiCells;
+
+ if (!pdtnDev) {
+ return (0);
+ }
+
+ do {
+ if (pdtnDev->DTN_pdtnparent) { /* 如果有父节点,获取其父节点 */
+ pdtnDev = pdtnDev->DTN_pdtnparent;
+ }
+
+ if (!API_DeviceTreePropertyU32Read(pdtnDev,
+ "#address-cells",
+ &uiCells)) { /* 读取 "#address-cells" 属性 */
+ return (uiCells);
+ }
+ } while (pdtnDev->DTN_pdtnparent); /* 若未读到,向上级父节点查找 */
+
+ return (ROOT_NODE_ADDR_CELLS_DEFAULT); /* 若正常读取不到,返回默认值 */
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeNSizeCells
+** 功能描述: 获取 size cells 的个数
+** 输 入 : pdtnDev 设备树节点
+** 输 出 : size cells 的个数
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeNSizeCells (PLW_DEVTREE_NODE pdtnDev)
+{
+ UINT32 uiCells;
+
+ if (!pdtnDev) {
+ return (0);
+ }
+
+ do {
+ if (pdtnDev->DTN_pdtnparent) { /* 如果有父节点,获取其父节点 */
+ pdtnDev = pdtnDev->DTN_pdtnparent;
+ }
+
+ if (!API_DeviceTreePropertyU32Read(pdtnDev,
+ "#size-cells",
+ &uiCells)) { /* 读取 "#size-cells" 属性 */
+ return (uiCells);
+ }
+ } while (pdtnDev->DTN_pdtnparent); /* 若未读到,向上级父节点查找 */
+
+ return (ROOT_NODE_SIZE_CELLS_DEFAULT); /* 若正常读取不到,返回默认值 */
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeAddressGet
+** 功能描述: 获取地址属性
+** 如对于 reg = <0x00 0x5000800 0x00 0x400>;
+** 该函数同时可以获取 addr 基址 与 size 值。
+** 输 入 : pdtnDev 用于获取属性的设备树节点
+** iIndex 指定的 cells 序号
+** pullSize 输出的资源大小
+** 输 出 : 地址属性对应的地址
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+const UINT32* API_DeviceTreeAddressGet (PLW_DEVTREE_NODE pdtnDev,
+ INT iIndex,
+ UINT64 *pullSize)
+{
+ const UINT32 *puiProp;
+ UINT uiPSize;
+ PLW_DEVTREE_NODE pdtnParent;
+ PLW_DEVTREE_BUS pdtbBus;
+ INT iOneSize;
+ INT i;
+ INT iNumAddr;
+ INT iNumSize;
+
+ if (!pdtnDev) {
+ return (LW_NULL);
+ }
+
+ pdtnParent = pdtnDev->DTN_pdtnparent;
+ if (pdtnParent == LW_NULL) { /* 当前节点的父节点不能为空 */
+ return (LW_NULL);
+ }
+
+ pdtbBus = __deviceTreeBusMatch(pdtnParent); /* 找到对应的总线类型 */
+ pdtbBus->DTBUS_cellsCount(pdtnDev, &iNumAddr, &iNumSize);
+ if (!DEVTREE_CHECK_ADDR_COUNT(iNumAddr)) { /* 如果 addr cells 不正确 */
+ return (LW_NULL);
+ }
+
+ puiProp = API_DeviceTreePropertyGet(pdtnDev,
+ pdtbBus->DTBUS_pcAddresses,
+ (INT *)&uiPSize); /* 获取对应属性名的属性值地址 */
+ if (puiProp == LW_NULL) {
+ return (LW_NULL);
+ }
+
+ uiPSize /= 4; /* 换算为 N 个 INT 长度 */
+ iOneSize = iNumAddr + iNumSize; /* 一个 cells 的长度 */
+
+ for (i = 0;
+ uiPSize >= iOneSize;
+ uiPSize -= iOneSize, puiProp += iOneSize, i++) {
+ if (i == iIndex) { /* 获取指定序号的 cells 属性值 */
+ if (pullSize) { /* 获取资源 size 大小 */
+ *pullSize = __deviceTreeNumberRead(puiProp + iNumAddr,
+ iNumSize);
+ }
+ return (puiProp); /* 返回资源 addr 地址 */
+ }
+ }
+
+ return (LW_NULL);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeAddressTranslate
+** 功能描述: 将地址属性基址转换为实际 64 位地址
+** 输 入 : pdtnDev 设备树节点
+** puiInAddr 地址属性基址
+** 输 出 : 实际 64 位地址
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+UINT64 API_DeviceTreeAddressTranslate (PLW_DEVTREE_NODE pdtnDev, const UINT32 *puiInAddr)
+{
+ UINT64 ullRet;
+
+ if (!pdtnDev) {
+ return (0);
+ }
+
+ ullRet = __deviceTreeAddressTranslate(pdtnDev, puiInAddr, "ranges");
+
+ return (ullRet);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeResourceGet
+** 功能描述: 将地址转换为资源变量
+** 输 入 : pdtnDev 设备树节点
+** iIndex 指定的 cells 序号
+** pdevresource 存储地址范围的资源变量
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeResourceGet (PLW_DEVTREE_NODE pdtnDev, INT iIndex, PLW_DEV_RESOURCE pdevresource)
+{
+ const UINT32 *puiAddr;
+ ULONG ulTmpAddr;
+ UINT64 ullSize;
+ CPCHAR pcName = LW_NULL;
+
+ if (!pdevresource) {
+ return (-EINVAL);
+ }
+
+ puiAddr = API_DeviceTreeAddressGet(pdtnDev, iIndex, &ullSize); /* 获取地址基址和地址范围 */
+ if (puiAddr == LW_NULL) {
+ return (-EINVAL);
+ }
+
+ __deviceTreePropertyStringIndexRead(pdtnDev,
+ "reg-names",
+ iIndex,
+ &pcName); /* 尝试读取 "reg-names" 属性 */
+
+ ulTmpAddr = API_DeviceTreeAddressTranslate(pdtnDev, puiAddr); /* 对地址进行转换 */
+ if (ulTmpAddr == PX_ERROR) {
+ return (-EINVAL);
+ }
+
+ lib_bzero(pdevresource, sizeof(LW_DEV_RESOURCE));
+
+ pdevresource->iomem.DEVRES_ulStart = ulTmpAddr; /* 填充起始地址 */
+ pdevresource->iomem.DEVRES_ulEnd = ulTmpAddr + ullSize - 1; /* 填充结束地址 */
+ pdevresource->DEVRES_pcName = pcName ?
+ pcName :
+ pdtnDev->DTN_pcFullName; /* 填充资源名称 */
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeRegAddressGet
+** 功能描述: 获取设备寄存器地址范围
+** 输 入 : pdtnDev 设备树节点
+** pdevresource 存储地址范围的资源变量
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeRegAddressGet (PLW_DEVTREE_NODE pdtnDev, PLW_DEV_RESOURCE pdevresource)
+{
+ LW_DEV_RESOURCE resTemp;
+ PLW_DEV_RESOURCE presTemp;
+ INT iNumReg = 0;
+ INT i;
+
+ if (!pdevresource) { /* 存储地址的资源变量不能为空 */
+ return (PX_ERROR);
+ }
+
+ while (!API_DeviceTreeResourceGet(pdtnDev, iNumReg, &resTemp)) { /* 获取存储地址的 cells 数量 */
+ iNumReg++;
+ }
+
+ presTemp = pdevresource;
+
+ if (iNumReg) {
+ for (i = 0; i < iNumReg; i++, presTemp++) { /* 获取地址资源 */
+ API_DeviceTreeResourceGet(pdtnDev, i, presTemp);
+ }
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeAddressIoremap
+** 功能描述: 获取设备树中的资源地址,并进行映射
+** 输 入 : pdtnDev 设备树节点
+** iIndex 设备树序号
+** 输 出 : 映射出的虚拟地址
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PVOID API_DeviceTreeAddressIoremap (PLW_DEVTREE_NODE pdtnDev, INT iIndex)
+{
+ LW_DEV_RESOURCE devresource;
+
+ if (API_DeviceTreeResourceGet(pdtnDev, iIndex, &devresource)) {
+ return (LW_NULL);
+ }
+
+ return (API_VmmIoRemapNocache((PVOID)devresource.iomem.DEVRES_ulStart,
+ RESOURCE_SIZE(&devresource)));
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeFindNodeOptsByPath
+** 功能描述: 通过节点路径查找设备树节点,并获取冒号分隔符之后的字符
+** 输 入 : pcPath 节点路径
+** 有效的节点路径只有以下几种:
+** (1)完整路径名,形如:/soc@03000000/spi@05010000
+** (2)别名,形如:spi0
+** (3)别名 + 相对路径名
+** ppcOpts 获取的分隔符之后的字符
+** 输 出 : 设备树节点
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_DEVTREE_NODE API_DeviceTreeFindNodeOptsByPath (CPCHAR pcPath, CPCHAR *ppcOpts)
+{
+ PLW_DEVTREE_NODE pdtnDev = LW_NULL;
+ PLW_DEVTREE_PROPERTY pdtprop;
+ CPCHAR pcSeparator; /* 获取冒号分隔符的位置 */
+ INT iLen;
+ CPCHAR pcTmp;
+
+ if (!pcPath) {
+ return (LW_NULL);
+ }
+
+ pcSeparator = lib_strchr(pcPath, ':'); /* 获取冒号分隔符的位置 */
+
+ if (ppcOpts) {
+ *ppcOpts = pcSeparator ? (pcSeparator + 1) : LW_NULL; /* 取冒号之后的字符串 */
+ }
+
+ if (lib_strcmp(pcPath, "/") == 0) { /* 如果是根节点 */
+ return (_G_pdtnRoot);
+ }
+
+ if (*pcPath != '/') { /* 如果当前路径首字符不是 '/' */
+ if (!_G_pdtnAliases) { /* aliases 节点不能为空 */
+ return (LW_NULL);
+ }
+
+ pcTmp = pcSeparator;
+ if (!pcTmp) {
+ pcTmp = lib_strchrnul(pcPath, '/'); /* 返回首字符或末尾空字符 */
+ }
+ iLen = pcTmp - pcPath; /* 得到路径字符串长度 */
+
+ for (pdtprop = _G_pdtnAliases->DTN_pdtpproperties;
+ pdtprop != LW_NULL;
+ pdtprop = pdtprop->DTP_pdtpNext) { /* 遍历 alises 节点每个属性 */
+
+ if ((lib_strlen(pdtprop->DTP_pcName) == iLen) &&
+ !lib_strncmp(pdtprop->DTP_pcName, pcPath, iLen)) {
+ pdtnDev = __deviceTreeFindNodeByPath(pdtprop->DTP_pvValue);
+ break;
+ }
+ }
+
+ if (!pdtnDev) {
+ return (LW_NULL);
+ }
+
+ pcPath = pcTmp;
+ }
+
+ if (!pdtnDev) { /* 若未找到,则从根节点开始查找*/
+ pdtnDev = _G_pdtnRoot;
+ }
+ pdtnDev = __deviceTreeFindNodeByFullPath(pdtnDev, pcPath);
+
+ return (pdtnDev);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeNextChildGet
+** 功能描述: 获取设备树节点的下一个孩子节点
+** 输 入 : pdtnDev 设备树节点
+** pdtnPrev 前一个节点
+** 输 出 : 下一个孩子节点
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_DEVTREE_NODE API_DeviceTreeNextChildGet (const PLW_DEVTREE_NODE pdtnDev,
+ PLW_DEVTREE_NODE pdtnPrev)
+{
+ PLW_DEVTREE_NODE pdtnNext;
+
+ if (!pdtnDev) {
+ return (LW_NULL);
+ }
+
+ pdtnNext = pdtnPrev ? pdtnPrev->DTN_pdtnsibling : pdtnDev->DTN_pdtnchild;
+
+ return (pdtnNext);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeFindAllNodes
+** 功能描述: 查找下一个节点
+** 输 入 : pdtnPrev 起始节点
+** 输 出 : 设备树节点
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_DEVTREE_NODE API_DeviceTreeFindAllNodes (PLW_DEVTREE_NODE pdtnPrev)
+{
+ PLW_DEVTREE_NODE pdtnode;
+
+ if (!pdtnPrev) {
+ pdtnode = _G_pdtnRoot;
+
+ } else if (pdtnPrev->DTN_pdtnchild) {
+ pdtnode = pdtnPrev->DTN_pdtnchild;
+
+ } else {
+ pdtnode = pdtnPrev;
+
+ while (pdtnode->DTN_pdtnparent && !pdtnode->DTN_pdtnsibling) {
+ pdtnode = pdtnode->DTN_pdtnparent;
+ }
+ pdtnode = pdtnode->DTN_pdtnsibling;
+ }
+
+ return (pdtnode);
+}
+
+#endif /* LW_CFG_DEVTREE_EN > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtreeLowLevel.c b/SylixOS/devtree/devtreeLowLevel.c
new file mode 100644
index 0000000..914a9a3
--- /dev/null
+++ b/SylixOS/devtree/devtreeLowLevel.c
@@ -0,0 +1,466 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtreeLowLevel.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 07 月 30 日
+**
+** 描 述: 设备树接口底层接口系统内核实现
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if LW_CFG_DEVTREE_EN > 0
+#include "devtree.h"
+#include "driver/fdt/libfdt_env.h"
+#include "driver/fdt/libfdt.h"
+#include "driver/fdt/fdt.h"
+/*********************************************************************************************************
+ 区域数量
+*********************************************************************************************************/
+#define MAX_REGION 3
+/*********************************************************************************************************
+ 节点名称
+*********************************************************************************************************/
+#define PHYSICAL_DMA "physical_dma"
+#define PHYSICAL_APP "physical_app"
+#define VIRTUAL_APP "virtual_app"
+#define VIRTUAL_IOMAP "virtual_iomap"
+/*********************************************************************************************************
+ 系统全局变量的
+*********************************************************************************************************/
+static addr_t _G_ulKernelParam; /* 启动参数的位置 */
+static PLW_MMU_PHYSICAL_DESC _G_pphysicalDesc; /* 物理内存描述 */
+static PLW_MMU_VIRTUAL_DESC _G_pvirtualDesc; /* 虚拟内存描述 */
+/*********************************************************************************************************
+ 文件内全局变量
+*********************************************************************************************************/
+static INT _G_iPhyDescNum;
+static INT _G_iVirDescNum;
+static INT _G_iRootAddrCells; /* 根节点 #address-cells 的值 */
+static INT _G_iRootSizeCells; /* 根节点 #size-cells 的值 */
+static size_t _G_stPhyOriginDesc;
+/*********************************************************************************************************
+** 函数名称: __deviceTreeChosenNodeScan
+** 功能描述: 查找设备树的 chosen 节点
+** 输 入 : pvDevtreeMem 设备树地址
+** iOffset 节点地址偏移
+** pcName 节点名称
+** iDepth 查找的深度
+** pvData 获取的 chosen 节点数据地址
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeChosenNodeScan (PVOID pvDevtreeMem,
+ INT iOffset,
+ CPCHAR pcName,
+ INT iDepth,
+ PVOID pvData)
+{
+ CPCHAR pcNodeProp;
+ INT iNodePropLen;
+
+ if ((iDepth != 1) ||
+ (pvData == LW_NULL) ||
+ ((lib_strcmp(pcName, "chosen") != 0) &&
+ (lib_strcmp(pcName, "chosen@0") != 0))) { /* 如果没有找到 chosen 节点 */
+ return (ERROR_NONE); /* 返回正确,继续查找下个节点 */
+ }
+
+ pcNodeProp = fdt_getprop(pvDevtreeMem, iOffset,
+ "bootargs", &iNodePropLen); /* 获取 "bootargs" */
+ if ((pcNodeProp != LW_NULL) && (iNodePropLen > 0)) {
+ *(addr_t *)pvData = (addr_t)pcNodeProp;
+ DEVTREE_MSG("Command line is: %s\r\n", pcNodeProp);
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeRootCellScan
+** 功能描述: 设备树查找根节点的 cells 定义
+** 输 入 : pvDevtreeMem 设备树地址
+** iOffset 节点地址偏移
+** pcName 节点名称
+** iDepth 查找的深度
+** pvData 获取的节点数据
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeRootCellScan (PVOID pvDevtreeMem,
+ INT iOffset,
+ CPCHAR pcName,
+ INT iDepth,
+ PVOID pvData)
+{
+ CPVOID pvSizeProp;
+ CPVOID pvAddrProp;
+
+ if (iDepth != 0) { /* 根节点的层次一定为 0 */
+ return (PX_ERROR);
+ }
+
+ pvAddrProp = fdt_getprop(pvDevtreeMem, iOffset,
+ "#address-cells", LW_NULL); /* 获取根节点的 address cells */
+ pvSizeProp = fdt_getprop(pvDevtreeMem, iOffset,
+ "#size-cells", LW_NULL); /* 获取根节点的 size cells */
+
+ _G_iRootAddrCells = pvAddrProp ? BE32_TO_CPU(pvAddrProp) : ROOT_NODE_ADDR_CELLS_DEFAULT;
+ _G_iRootSizeCells = pvSizeProp ? BE32_TO_CPU(pvSizeProp) : ROOT_NODE_SIZE_CELLS_DEFAULT;
+
+ DEVTREE_MSG("Root Node #address-cells: %d, #size-cells: %d\r\n",
+ _G_iRootAddrCells, _G_iRootSizeCells);
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeMemNextCell
+** 功能描述: 设备树读取下一个 memory cell 的信息
+** 输 入 : iSize 读取的数据长度
+** ppvCell Cell 基地址,函数内部会更新
+** 输 出 : 读取的信息内容
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static UINT64 __deviceTreeMemoryNextCell (INT iSize, PVOID *ppvCell)
+{
+ UINT32 *puiTemp = *ppvCell;
+
+ *(UINT32 **)ppvCell = puiTemp + iSize;
+
+ return (__deviceTreeNumberRead(puiTemp, iSize));
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeMemoryNodeSave
+** 功能描述: 记录设备树的 memory cell 的信息
+** 输 入 : pcMemName Cell 名称
+** ullBase Cell 基地址
+** ullSize Cell 大小
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeMemoryNodeSave (CPCHAR pcMemName,
+ UINT64 ullBase,
+ UINT64 ullSize)
+{
+ static INT iMaxPhyRegion = MAX_REGION;
+ static INT iMaxVirRegion = MAX_REGION;
+
+ if (_G_iPhyDescNum == (iMaxPhyRegion - 1)) {
+ iMaxPhyRegion = iMaxPhyRegion << 1;
+ _G_pphysicalDesc = __SHEAP_REALLOC(_G_pphysicalDesc,
+ sizeof(LW_MMU_PHYSICAL_DESC) * iMaxPhyRegion +
+ _G_stPhyOriginDesc);
+ if (!_G_pphysicalDesc) {
+ _ErrorHandle(ENOMEM);
+ return (PX_ERROR);
+ }
+ }
+
+ if (_G_iVirDescNum == (iMaxVirRegion - 1)) {
+ iMaxVirRegion = iMaxVirRegion << 1;
+ _G_pvirtualDesc = __SHEAP_REALLOC(_G_pvirtualDesc,
+ sizeof(LW_MMU_VIRTUAL_DESC) * iMaxVirRegion);
+ if (!_G_pvirtualDesc) {
+ _ErrorHandle(ENOMEM);
+ return (PX_ERROR);
+ }
+ }
+
+ if (!lib_strcmp(pcMemName, PHYSICAL_DMA)) { /* DMA 物理内存 */
+ _G_pphysicalDesc[_G_iPhyDescNum].PHYD_ulPhyAddr = (addr_t)ullBase;
+ _G_pphysicalDesc[_G_iPhyDescNum].PHYD_ulVirMap = (addr_t)ullBase;
+ _G_pphysicalDesc[_G_iPhyDescNum].PHYD_stSize = (size_t)ullSize;
+ _G_pphysicalDesc[_G_iPhyDescNum].PHYD_uiType = LW_PHYSICAL_MEM_DMA;
+ _G_iPhyDescNum++;
+ return (ERROR_NONE);
+ }
+
+ if (!lib_strcmp(pcMemName, PHYSICAL_APP)) { /* APP 物理内存 */
+ _G_pphysicalDesc[_G_iPhyDescNum].PHYD_ulPhyAddr = (addr_t)ullBase;
+ _G_pphysicalDesc[_G_iPhyDescNum].PHYD_stSize = (size_t)ullSize;
+ _G_pphysicalDesc[_G_iPhyDescNum].PHYD_uiType = LW_PHYSICAL_MEM_APP;
+ _G_iPhyDescNum++;
+ return (ERROR_NONE);
+ }
+
+ if (!lib_strcmp(pcMemName, VIRTUAL_APP)) { /* APP 虚拟内存 */
+ _G_pvirtualDesc[_G_iVirDescNum].VIRD_ulVirAddr = (addr_t)ullBase;
+ _G_pvirtualDesc[_G_iVirDescNum].VIRD_stSize = (size_t)ullSize;
+ _G_pvirtualDesc[_G_iVirDescNum].VIRD_uiType = LW_VIRTUAL_MEM_APP;
+ _G_iVirDescNum++;
+ return (ERROR_NONE);
+ }
+
+ if (!lib_strcmp(pcMemName, VIRTUAL_IOMAP)) { /* IOMAP 虚拟内存 */
+ _G_pvirtualDesc[_G_iVirDescNum].VIRD_ulVirAddr = (addr_t)ullBase;
+ _G_pvirtualDesc[_G_iVirDescNum].VIRD_stSize = (size_t)ullSize;
+ _G_pvirtualDesc[_G_iVirDescNum].VIRD_uiType = LW_VIRTUAL_MEM_DEV;
+ _G_iVirDescNum++;
+ return (ERROR_NONE);
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeMemoryParse
+** 功能描述: 设备树的 memory cell 的信息解析
+** 输 入 : pvDevtreeMem 设备树地址
+** iOffset 节点地址偏移
+** iTotalLen 数据总长
+** pcCellName 节点名称
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeMemoryParse (PVOID pvDevtreeMem,
+ INT iOffset,
+ INT iTotalLen,
+ CPCHAR pcCellName)
+{
+ UINT64 ullBase;
+ UINT64 ullSize;
+ CPVOID pvProp;
+ INT iLen;
+
+ pvProp = fdt_getprop(pvDevtreeMem, iOffset, pcCellName, &iLen);
+ if (!pvProp) {
+ _ErrorHandle(ENOENT);
+ return (PX_ERROR);
+ }
+
+ if (iLen && (iLen % iTotalLen != 0)) { /* 资源长度不正确 */
+ _DebugFormat(__ERRORMESSAGE_LEVEL, "Reserved memory: invalid reg property in '%s', "
+ "skipping node.\r\n", pcCellName);
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ while (iLen >= iTotalLen) { /* 逐条解析资源 */
+ ullBase = __deviceTreeMemoryNextCell(_G_iRootAddrCells, (PVOID *)&pvProp);
+ ullSize = __deviceTreeMemoryNextCell(_G_iRootSizeCells, (PVOID *)&pvProp);
+
+ iLen -= iTotalLen;
+
+ __deviceTreeMemoryNodeSave(pcCellName,
+ ullBase, ullSize); /* 记录信息 */
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeMemoryScan
+** 功能描述: 设备树查找根节点的 memory 定义
+** 输 入 : pvDevtreeMem 设备树地址
+** iOffset 节点地址偏移
+** pcName 节点名称
+** iDepth 查找的深度
+** pvData 原始物理描述列表
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeMemoryScan (PVOID pvDevtreeMem,
+ INT iOffset,
+ CPCHAR pcName,
+ INT iDepth,
+ PVOID pvData)
+{
+ INT iTotalLen;
+
+ if ((iDepth != 1) ||
+ (lib_strcmp(pcName, "memory") != 0)) { /* 如果没有找到 memory 节点 */
+ return (ERROR_NONE); /* 返回正确,继续查找下个节点 */
+ }
+
+ iTotalLen = (_G_iRootAddrCells + _G_iRootSizeCells) * sizeof(UINT32);
+ _G_stPhyOriginDesc = (size_t)pvData;
+
+ if (!_G_pphysicalDesc) { /* 申请物理描述结构区域 */
+ _G_pphysicalDesc = __SHEAP_ZALLOC(sizeof(LW_MMU_PHYSICAL_DESC) * MAX_REGION + _G_stPhyOriginDesc);
+ if (!_G_pphysicalDesc) {
+ _ErrorHandle(ENOMEM);
+ return (PX_ERROR);
+ }
+ }
+
+ if (!_G_pvirtualDesc) { /* 申请虚拟描述结构区域 */
+ _G_pvirtualDesc = __SHEAP_ZALLOC(sizeof(LW_MMU_VIRTUAL_DESC) * MAX_REGION);
+ if (!_G_pvirtualDesc) {
+ _ErrorHandle(ENOMEM);
+ return (PX_ERROR);
+ }
+ }
+
+ __deviceTreeMemoryParse(pvDevtreeMem, iOffset, iTotalLen, PHYSICAL_DMA);
+ __deviceTreeMemoryParse(pvDevtreeMem, iOffset, iTotalLen, PHYSICAL_APP);
+ __deviceTreeMemoryParse(pvDevtreeMem, iOffset, iTotalLen, VIRTUAL_APP);
+ __deviceTreeMemoryParse(pvDevtreeMem, iOffset, iTotalLen, VIRTUAL_IOMAP);
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeScan
+** 功能描述: 设备树节点扫描,并执行指定的扫描回调函数
+** 输 入 : pvDevtreeMem 设备树地址
+** pfuncScanCallBack 扫描节点时的回调函数
+** pvData 回调函数参数
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeScan (PVOID pvDevtreeMem, FUNC_SCAN_CALLBACK pfuncScanCallBack, PVOID pvData)
+{
+ CPCHAR pcNodeName;
+ INT iOffset;
+ INT iRet = 0;
+ INT iDepth = -1;
+
+ for (iOffset = fdt_next_node(pvDevtreeMem, -1, &iDepth);
+ (iOffset >= 0) && /* 节点偏移有效 */
+ (iDepth >= 0) && /* 节点深度有效 */
+ (iRet == ERROR_NONE); /* 回调执行有效 */
+ iOffset = fdt_next_node(pvDevtreeMem, iOffset, &iDepth)) { /* 遍历每一个节点 */
+
+ pcNodeName = fdt_get_name(pvDevtreeMem, iOffset, LW_NULL);
+ if (*pcNodeName == '/') { /* 如果节点是全路径名 */
+ pcNodeName = __deviceTreeBaseNameGet(pcNodeName); /* 获取节点的名称 */
+ }
+
+ iRet = pfuncScanCallBack(pvDevtreeMem, iOffset, pcNodeName, iDepth, pvData);
+ }
+
+ return (iRet);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeRootNodesScan
+** 功能描述: 扫描设备树根节点信息
+** 输 入 : pvDevtreeMem 设备树地址
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeRootNodesScan (PVOID pvDevtreeMem)
+{
+ if (__deviceTreeScan(pvDevtreeMem,
+ __deviceTreeChosenNodeScan,
+ (PVOID)&_G_ulKernelParam)) { /* 获取 chosen 节点 */
+ return (PX_ERROR);
+ }
+
+ if (__deviceTreeScan(pvDevtreeMem,
+ __deviceTreeRootCellScan,
+ LW_NULL)) { /* 获取根节点 cells 定义 */
+ return (ERROR_NONE); /* 修正返回值为 ERROR_NONE */
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeKernelVmmParamGet
+** 功能描述: 获得设备树定义的系统内存参数
+** 输 入 : pvDevtreeMem 设备树基地址
+** pphyOriginDesc 原始的设备树物理内存描述
+** stPhyOriginDesc 原始的设备树物理内存字节
+** ppphydesc 物理描述结构
+** ppvirdes 虚拟描述结构
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+ API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeKernelVmmParamGet (PVOID pvDevtreeMem,
+ PLW_MMU_PHYSICAL_DESC pphyOriginDesc,
+ size_t stPhyOriginDesc,
+ PLW_MMU_PHYSICAL_DESC *ppphydesc,
+ PLW_MMU_VIRTUAL_DESC *ppvirdes)
+{
+ if (!pphyOriginDesc || !ppphydesc || !ppvirdes) {
+ _ErrorHandle(ERROR_KERNEL_BUFFER_NULL);
+ return (PX_ERROR);
+ }
+
+ if (__deviceTreeScan(pvDevtreeMem,
+ __deviceTreeMemoryScan,
+ (PVOID)stPhyOriginDesc)) { /* 获得内存节点信息 */
+ return (PX_ERROR);
+ }
+
+ lib_memcpy(&_G_pphysicalDesc[_G_iPhyDescNum], pphyOriginDesc, stPhyOriginDesc);
+ *ppphydesc = _G_pphysicalDesc;
+ *ppvirdes = _G_pvirtualDesc;
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeKernelStartParamGet
+** 功能描述: 获得设备树定义的系统内核启动参数
+** 输 入 : pcParam 启动参数
+** stLen 缓冲区长度
+** 输 出 : 实际拷贝的启动参数长度
+** 全局变量:
+** 调用模块:
+ API 函数
+*********************************************************************************************************/
+LW_API
+ssize_t API_DeviceTreeKernelStartParamGet (PCHAR pcParam, size_t stLen)
+{
+ if (!pcParam || !stLen) {
+ _ErrorHandle(ERROR_KERNEL_BUFFER_NULL);
+ return (0);
+ }
+
+ return ((ssize_t)lib_strlcpy(pcParam, (PVOID)_G_ulKernelParam, stLen));
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeLowLevelInit
+** 功能描述: 设备树初级初始化,之后可以获取根节点信息
+** 输 入 : pvDevtreeMem 设备树基地址
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeLowLevelInit (PVOID pvDevtreeMem)
+{
+ if (!pvDevtreeMem) {
+ _ErrorHandle(ERROR_KERNEL_OBJECT_NULL);
+ return (PX_ERROR);
+ }
+
+ if (fdt_check_header(pvDevtreeMem)) { /* 设备树头部校验 */
+ _ErrorHandle(ERROR_DEVTREE_MAGIC_ERROR);
+ return (PX_ERROR);
+ }
+
+ if (__deviceTreeRootNodesScan(pvDevtreeMem)) { /* 扫描根节点信息 */
+ _ErrorHandle(ERROR_DEVTREE_SCAN_ERROR);
+ return (PX_ERROR);
+ }
+
+ return (ERROR_NONE);
+}
+
+#endif /* LW_CFG_DEVTREE_EN > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtreeMdio.c b/SylixOS/devtree/devtreeMdio.c
new file mode 100644
index 0000000..d4db08f
--- /dev/null
+++ b/SylixOS/devtree/devtreeMdio.c
@@ -0,0 +1,183 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtreeMdio.c
+**
+** 创 建 人: Zhang.Jian (张健)
+**
+** 文件创建日期: 2019 年 11 月 20 日
+**
+** 描 述: MDIO 驱动框架中设备树相关接口
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if LW_CFG_DEVTREE_EN > 0
+#include "devtree.h"
+/*********************************************************************************************************
+** 函数名称: __deviceTreeMdioAddrGet
+** 功能描述: 通过设备树获取 MDIO 设备地址
+** 输 入 : pdtnDev 设备树节点指针
+** 输 出 : 非 0 时为有效地址,错误时为 PX_ERROR
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreeMdioAddrGet (PLW_DEVTREE_NODE pdtnDev)
+{
+ UINT32 uiAddr = 0;
+ INT iRet;
+
+ iRet = API_DeviceTreePropertyU32Read(pdtnDev, "reg", &uiAddr); /* 获取 MDIO 设备地址 */
+ if (iRet) {
+ DEVTREE_ERR("%s has invalid PHY address\n", pdtnDev->DTN_pcFullName);
+ return (PX_ERROR);
+ }
+
+ if (uiAddr >= MDIO_MAX_ADDR) { /* 地址超过正常范围,返回失败 */
+ DEVTREE_ERR("%s PHY address %d is too large\n",
+ pdtnDev->DTN_pcFullName, uiAddr);
+ return (PX_ERROR);
+ }
+
+ return (uiAddr);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeMdioDevFind
+** 功能描述: 通过设备树节点查找 MDIO 设备
+** 输 入 : pdtnDev 设备树节点
+** 输 出 : 成功返回查找到的 MDIO 设备指针,
+** 失败返回 LW_NULL
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PMDIO_DEVICE API_DeviceTreeMdioDevFind (PLW_DEVTREE_NODE pdtnDev)
+{
+ PLW_DEV_INSTANCE pdevinstance;
+ PMDIO_DEVICE pmdiodev;
+
+ if (!pdtnDev) {
+ return (LW_NULL);
+ }
+
+ pdevinstance = API_BusFindDevice(API_MdioBusGet(), pdtnDev); /* 在 MDIO 总线上查找设备 */
+ if (pdevinstance) {
+ pmdiodev = __mdioDevGet(pdevinstance); /* 获取 MDIO 设备结构体 */
+ } else {
+ pmdiodev = LW_NULL;
+ }
+
+ return (pmdiodev);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeMdioRegister
+** 功能描述: 从设备树中解析 MDIO 控制器下挂载的设备
+** 输 入 : pmdioadapter MDIO 控制器指针
+** pdtnDev MDIO 控制器的设备树节点
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeMdioRegister (PMDIO_ADAPTER pmdioadapter,
+ PLW_DEVTREE_NODE pdtnDev)
+{
+ PLW_DEVTREE_NODE pdtnChild;
+ INT iDevAddr; /* MDIO 设备地址 */
+ INT iRet;
+
+ iRet = API_MdioAdapterRegister(pmdioadapter); /* 先注册 MDIO 控制器 */
+ if (iRet) {
+ return (iRet);
+ }
+
+ _LIST_EACH_CHILD_OF_NODE(pdtnDev, pdtnChild) { /* 遍历该节点的子节点 */
+ iDevAddr = __deviceTreeMdioAddrGet(pdtnChild); /* 必须有 reg 地址属性 */
+ if (iDevAddr < 0) {
+ continue;
+ }
+
+ API_DeviceTreeMdioDevRegister(pmdioadapter,
+ pdtnChild, iDevAddr); /* 注册 MDIO 设备 */
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeMdioDevRegister
+** 功能描述: 通过设备树注册 MDIO 设备
+** 输 入 : pmdioadapter MDIO 控制器指针
+** pdtnDev MDIO 控制器的设备树节点
+** uiAddr MDIO 设备地址
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeMdioDevRegister (PMDIO_ADAPTER pmdioadapter,
+ PLW_DEVTREE_NODE pdtnDev,
+ UINT uiAddr)
+{
+ PMDIO_DEVICE pmdiodevice;
+ ULONG ulIrqNum = 0; /* MDIO 设备的中断号 */
+ UINT uiFlag = 0;
+ INT iRet;
+
+ if (!pmdioadapter || !pdtnDev) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ if (API_DeviceTreePropertyFind(pdtnDev, "phy", LW_NULL)) {
+ uiFlag |= MDIO_DEVICE_IS_PHY; /* phy 设备设置 phy 标志 */
+ }
+
+ if (API_DeviceTreePropertyFind(pdtnDev, "c45", LW_NULL)) {
+ uiFlag |= MDIO_DEVICE_IS_C45; /* MDIO c45 协议设置 c45 标志 */
+ }
+
+ API_DeviceTreeIrqGet(pdtnDev, 0, &ulIrqNum);
+ if (ulIrqNum > 0) {
+ pmdioadapter->MDIOADPT_uiIrqMap[uiAddr] = ulIrqNum; /* 获取并存储设备的中断号 */
+ }
+
+ DEVTREE_MSG("Mdio addr = 0x%x ,flag = 0x%x\r\n", uiAddr, uiFlag);
+
+ pmdiodevice = API_MdioDevCreate(pmdioadapter, uiAddr, uiFlag); /* 创建 MDIO 设备 */
+ if (LW_NULL == pmdiodevice) {
+ return (PX_ERROR);
+ }
+
+ pmdiodevice->MDIODEV_devinstance.DEVHD_pdtnDev = pdtnDev;
+ /* 保存 MDIO 设备的设备树节点 */
+ pmdiodevice->MDIODEV_devinstance.DEVHD_pcName = pdtnDev->DTN_pcFullName;
+ /* 使用节点名作为设备名 */
+
+ iRet = API_MdioDevRegister(pmdiodevice); /* 注册 MDIO 设备到系统 */
+ if (iRet) {
+ DEVTREE_ERR("Mdio device %s register faild.\r\n", pdtnDev->DTN_pcFullName);
+ API_MdioDevDelete(pmdiodevice);
+ }
+
+ return (iRet);
+}
+
+#endif /* LW_CFG_DEVTREE_EN > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtreePhandle.c b/SylixOS/devtree/devtreePhandle.c
new file mode 100644
index 0000000..6ab3e17
--- /dev/null
+++ b/SylixOS/devtree/devtreePhandle.c
@@ -0,0 +1,335 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtreePhandle.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 07 月 30 日
+**
+** 描 述: 设备树 phandle 相关接口
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if LW_CFG_DEVTREE_EN > 0
+#include "devtree.h"
+#include "driver/fdt/libfdt_env.h"
+#include "driver/fdt/libfdt.h"
+#include "driver/fdt/fdt.h"
+/*********************************************************************************************************
+** 函数名称: __deviceTreePhandleIteratorArgs
+** 功能描述: 获取当前迭代器指示的 phandle 参数
+** 输 入 : pdtpiItor 迭代器指针
+** puiArgs 获取的参数
+** iSize 参数的大小
+** 输 出 : 参数占用的大小
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreePhandleIteratorArgs (PLW_DEVTREE_PHANDLE_ITERATOR pdtpiItor,
+ UINT32 *puiArgs,
+ INT iSize)
+{
+ INT iCount;
+ INT i;
+
+ iCount = pdtpiItor->DTPHI_uiCurCount;
+
+ if (iSize < iCount) {
+ iCount = iSize;
+ }
+
+ for (i = 0; i < iCount; i++) {
+ puiArgs[i] = BE32_TO_CPU(pdtpiItor->DTPHI_puiCurrent++);
+ }
+
+ return (iCount);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreePhandleParseWithArgs
+** 功能描述: 带有参数的 phandle 解析
+** 输 入 : pdtnDev 设备树节点
+** pcListName 列表名称
+** pcCellsName cells 名称
+** iCellCount cells 数量
+** iIndex 序号
+** pdtpaOutArgs 解析出的 phandle 参数
+** 输 出 : 设备树节点
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __deviceTreePhandleParseWithArgs (const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcListName,
+ CPCHAR pcCellsName,
+ INT iCellCount,
+ INT iIndex,
+ PLW_DEVTREE_PHANDLE_ARGS pdtpaOutArgs)
+{
+ LW_DEVTREE_PHANDLE_ITERATOR dtpiItor;
+ INT iRet;
+ INT iC;
+ INT iCurIndex = 0;
+
+ _LIST_EACH_PHANDLE(&dtpiItor, iRet, pdtnDev, pcListName, pcCellsName, iCellCount) {
+ if (iCurIndex == iIndex) {
+ if (!dtpiItor.DTPHI_uiPhandle) {
+ goto __error_handle;
+ }
+
+ if (pdtpaOutArgs) {
+ iC = __deviceTreePhandleIteratorArgs(&dtpiItor,
+ pdtpaOutArgs->DTPH_uiArgs,
+ MAX_PHANDLE_ARGS);
+ pdtpaOutArgs->DTPH_pdtnDev = dtpiItor.DTPHI_pdtnDev;
+ pdtpaOutArgs->DTPH_iArgsCount = iC;
+ }
+
+ return (ERROR_NONE);
+ }
+
+ iCurIndex++;
+ }
+
+__error_handle:
+ return (PX_ERROR);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePhandleIteratorInit
+** 功能描述: 初始化 phandle 的迭代器
+** 输 入 : pdtpiItor 需要初始化的迭代器
+** pdtnDev 设备树节点
+** pcListName 链表名称
+** pcCellsName cell 名称
+** iCellCount cell 的数量
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreePhandleIteratorInit (PLW_DEVTREE_PHANDLE_ITERATOR pdtpiItor,
+ const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcListName,
+ CPCHAR pcCellsName,
+ INT iCellCount)
+{
+ UINT32 *puiList;
+ INT iSize;
+
+ if (!pdtpiItor) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ lib_bzero(pdtpiItor, sizeof(LW_DEVTREE_PHANDLE_ITERATOR));
+
+ puiList = API_DeviceTreePropertyGet(pdtnDev, pcListName, &iSize);
+ if (!puiList) {
+ _ErrorHandle(ENOENT);
+ return (PX_ERROR);
+ }
+
+ pdtpiItor->DTPHI_pcCellsName = pcCellsName;
+ pdtpiItor->DTPHI_iCellCount = iCellCount;
+ pdtpiItor->DTPHI_pdtnParent = pdtnDev;
+ pdtpiItor->DTPHI_puiListEnd = puiList + iSize / sizeof(UINT32);
+ pdtpiItor->DTPHI_puiPhandleEnd = puiList;
+ pdtpiItor->DTPHI_puiCurrent = puiList;
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePhandleIteratorNext
+** 功能描述: 获取下一个迭代器
+** 输 入 : pdtpiItor 当前的迭代器指针
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreePhandleIteratorNext (PLW_DEVTREE_PHANDLE_ITERATOR pdtpiItor)
+{
+ UINT32 uiCount = 0;
+
+ if (!pdtpiItor) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ if (pdtpiItor->DTPHI_pdtnDev) {
+ pdtpiItor->DTPHI_pdtnDev = LW_NULL;
+ }
+
+ if (!pdtpiItor->DTPHI_puiCurrent ||
+ (pdtpiItor->DTPHI_puiPhandleEnd >= pdtpiItor->DTPHI_puiListEnd)) {
+ _ErrorHandle(ENOENT);
+ return (PX_ERROR);
+ }
+
+ pdtpiItor->DTPHI_puiCurrent = pdtpiItor->DTPHI_puiPhandleEnd;
+ pdtpiItor->DTPHI_uiPhandle = BE32_TO_CPU(pdtpiItor->DTPHI_puiCurrent++);
+
+ if (pdtpiItor->DTPHI_uiPhandle) {
+ pdtpiItor->DTPHI_pdtnDev = API_DeviceTreeFindNodeByPhandle(pdtpiItor->DTPHI_uiPhandle);
+
+ if (pdtpiItor->DTPHI_pcCellsName) {
+ if (!pdtpiItor->DTPHI_pdtnDev) {
+ goto __error_handle;
+ }
+
+ if (API_DeviceTreePropertyU32Read(pdtpiItor->DTPHI_pdtnDev,
+ pdtpiItor->DTPHI_pcCellsName,
+ &uiCount)) {
+ goto __error_handle;
+ }
+ } else {
+ uiCount = pdtpiItor->DTPHI_iCellCount;
+ }
+
+ if ((pdtpiItor->DTPHI_puiCurrent + uiCount) > pdtpiItor->DTPHI_puiListEnd) {
+ goto __error_handle;
+ }
+ }
+
+ pdtpiItor->DTPHI_puiPhandleEnd = pdtpiItor->DTPHI_puiCurrent + uiCount;
+ pdtpiItor->DTPHI_uiCurCount = uiCount;
+
+ return (ERROR_NONE);
+
+__error_handle:
+ if (pdtpiItor->DTPHI_pdtnDev) {
+ pdtpiItor->DTPHI_pdtnDev = LW_NULL;
+ }
+
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePhandleParseWithArgs
+** 功能描述: 带有参数的 phandle 解析
+** 输 入 : pdtnDev 设备树节点
+** pcListName 列表名称
+** pcCellsName 节点名称
+** iIndex 序号
+** pdtpaOutArgs 解析出的 phandle 参数
+** 输 出 : 设备树节点
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreePhandleParseWithArgs (const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcListName,
+ CPCHAR pcCellsName,
+ INT iIndex,
+ PLW_DEVTREE_PHANDLE_ARGS pdtpaOutArgs)
+{
+ if (!pdtnDev) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ if (iIndex < 0) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ return (__deviceTreePhandleParseWithArgs(pdtnDev, pcListName, pcCellsName, 0, iIndex, pdtpaOutArgs));
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePhandleParse
+** 功能描述: phandle 解析
+** 输 入 : pdtnDev 设备树节点
+** pcPhandleName 名称
+** iIndex 序号
+** 输 出 : 设备树节点
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_DEVTREE_NODE API_DeviceTreePhandleParse (const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPhandleName,
+ INT iIndex)
+{
+ LW_DEVTREE_PHANDLE_ARGS dtpaOutArgs;
+ INT iRet;
+
+ if (!pdtnDev) {
+ _ErrorHandle(EINVAL);
+ return (LW_NULL);
+ }
+
+ if (iIndex < 0) {
+ _ErrorHandle(EINVAL);
+ return (LW_NULL);
+ }
+
+ iRet = __deviceTreePhandleParseWithArgs(pdtnDev, pcPhandleName, LW_NULL, 0,
+ iIndex, &dtpaOutArgs);
+ if (iRet) {
+ return (LW_NULL);
+ }
+
+ return (dtpaOutArgs.DTPH_pdtnDev);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeFindNodeByPhandle
+** 功能描述: 通过 phandle 查找设备树节点
+** 输 入 : uiPhandle 设备树节点的 phandle
+** 输 出 : 设备树节点
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_DEVTREE_NODE API_DeviceTreeFindNodeByPhandle (UINT32 uiPhandle)
+{
+ PLW_DEVTREE_NODE pdtnDev = LW_NULL;
+ UINT32 uiMaskedHandle;
+
+ if (uiPhandle == 0) {
+ return (LW_NULL);
+ }
+
+ uiMaskedHandle = uiPhandle & _G_uiPhandleCacheMask;
+
+ if (_G_ppdtnPhandleCache) {
+ if (_G_ppdtnPhandleCache[uiMaskedHandle] &&
+ uiPhandle == _G_ppdtnPhandleCache[uiMaskedHandle]->DTN_uiHandle) {
+ pdtnDev = _G_ppdtnPhandleCache[uiMaskedHandle];
+ }
+ }
+
+ if (!pdtnDev) {
+ _LIST_EACH_OF_ALLNODES(pdtnDev) {
+ if (pdtnDev->DTN_uiHandle == uiPhandle) {
+ if (_G_ppdtnPhandleCache) {
+ _G_ppdtnPhandleCache[uiMaskedHandle] = pdtnDev;
+ }
+ break;
+ }
+ }
+ }
+
+ return (pdtnDev);
+}
+
+#endif /* LW_CFG_DEVTREE_EN > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtreeProperty.c b/SylixOS/devtree/devtreeProperty.c
new file mode 100644
index 0000000..aa17530
--- /dev/null
+++ b/SylixOS/devtree/devtreeProperty.c
@@ -0,0 +1,644 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtreeProperty.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 07 月 30 日
+**
+** 描 述: 设备树属性读取接口
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if LW_CFG_DEVTREE_EN > 0
+#include "devtree.h"
+#include "driver/fdt/libfdt_env.h"
+#include "driver/fdt/libfdt.h"
+#include "driver/fdt/fdt.h"
+/*********************************************************************************************************
+** 函数名称: __deviceTreePropertyValueOfSize
+** 功能描述: 在设备节点中搜索属性,获取属性的有效大小,并读取属性的值
+** 输 入 : pdtnDev 用于查找的设备树节点
+** pcPropname 属性名称
+** uiMin 属性值长度最小有效值
+** uiMax 属性值长度最大有效值
+** pstLen 属性值实际有效的长度
+** 输 出 : ERROR_CODE 或 属性值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static PVOID __deviceTreePropertyValueOfSize (const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropname,
+ UINT32 uiMin,
+ UINT32 uiMax,
+ size_t *pstLen)
+{
+ PLW_DEVTREE_PROPERTY pdtprop = API_DeviceTreePropertyFind(pdtnDev, pcPropname, LW_NULL);
+
+ if (!pdtprop) {
+ return (PVOID)(-EINVAL);
+ }
+
+ if (!pdtprop->DTP_pvValue) {
+ return (PVOID)(-ENODATA);
+ }
+
+ if (pdtprop->DTP_iLength < uiMin) {
+ return (PVOID)(-EOVERFLOW);
+ }
+
+ if (uiMax && pdtprop->DTP_iLength > uiMax) {
+ return (PVOID)(-EOVERFLOW);
+ }
+
+ if (pstLen) {
+ *pstLen = pdtprop->DTP_iLength;
+ }
+
+ return (pdtprop->DTP_pvValue);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeNodeIsOkay
+** 功能描述: 查看某个设备树节点是否为 okay 状态
+** 输 入 : pdtnDev 设备树节点
+** 输 出 : LW_TRUE 表示为 okay,LW_FALSE 表示不为 okay
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+BOOL API_DeviceTreeNodeIsOkay (PLW_DEVTREE_NODE pdtnDev)
+{
+ CPCHAR pcStatus;
+ INT iStatLen;
+
+ if (!pdtnDev) {
+ return (LW_FALSE);
+ }
+
+ pcStatus = API_DeviceTreePropertyGet(pdtnDev, "status", &iStatLen);
+ if (!pcStatus) { /* 没有 status 属性的都为 okay */
+ return (LW_TRUE);
+ }
+
+ if (iStatLen > 0) {
+ if (!strcmp(pcStatus, "ok") || !strcmp(pcStatus, "okay")) {
+ return (LW_TRUE);
+ }
+ }
+
+ return (LW_FALSE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeNodeIsOkayByOffset
+** 功能描述: 通过 offset 指定查看某个设备树节点是否为 okay 状态
+** 输 入 : pvDevTree 设备树基地址
+** iOffset 节点偏移
+** 输 出 : LW_TRUE 表示为 okay,LW_FALSE 表示不为 okay
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+BOOL API_DeviceTreeNodeIsOkayByOffset (PVOID pvDevTree, INT iOffset)
+{
+ CPCHAR pcStatus;
+
+ if (!pvDevTree) {
+ _ErrorHandle(EINVAL);
+ return (LW_FALSE);
+ }
+
+ pcStatus = fdt_getprop(pvDevTree, iOffset, "status", LW_NULL);
+ if (!pcStatus) { /* 没有 status 属性的都为 okay */
+ return (LW_TRUE);
+ }
+
+ if (!strcmp(pcStatus, "ok") || !strcmp(pcStatus, "okay")) {
+ return (LW_TRUE);
+ }
+
+ return (LW_FALSE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyFind
+** 功能描述: 查找属性节点
+** 输 入 : pdtnDev 设备树节点
+** pcPropname 属性名称
+** piLen 获取的属性值长度
+** 输 出 : 属性节点 或 LW_NULL
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_DEVTREE_PROPERTY API_DeviceTreePropertyFind (PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropname,
+ INT *piLen)
+{
+ PLW_DEVTREE_PROPERTY pdtprop;
+
+ if (!pdtnDev) {
+ return (LW_NULL);
+ }
+
+ for (pdtprop = pdtnDev->DTN_pdtpproperties;
+ pdtprop;
+ pdtprop = pdtprop->DTP_pdtpNext) { /* 遍历节点的属性结构 */
+
+ if (lib_strcmp(pdtprop->DTP_pcName, pcPropname) == 0) {
+ if (piLen) {
+ *piLen = pdtprop->DTP_iLength;
+ }
+ break;
+ }
+ }
+
+ return (pdtprop);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyU32VaraiableArrayRead
+** 功能描述: 读取 U32 Array 类型的属性值
+** 输 入 : pdtnDev 设备树节点
+** pcPropname 属性名称
+** puiOutValue 读出的数据
+** stMin 属性值长度最小有效值
+** stMax 属性值长度最大有效值
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreePropertyU32VaraiableArrayRead (const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropname,
+ UINT32 *puiOutValue,
+ size_t stMin,
+ size_t stMax)
+{
+ size_t stSize;
+ size_t stCount;
+ const UINT32 *puiVal = __deviceTreePropertyValueOfSize(pdtnDev,
+ pcPropname,
+ (stMin * sizeof(UINT32)),
+ (stMax * sizeof(UINT32)),
+ &stSize);
+
+ if ((ULONG)puiVal >= (ULONG)-ERRMAX) {
+ return (LONG)(puiVal);
+ }
+
+ if (!stMax) {
+ stSize = stMin;
+ } else {
+ stSize /= sizeof(UINT32);
+ }
+
+ stCount = stSize;
+ while (stCount--) {
+ *puiOutValue++ = BE32_TO_CPU(puiVal++);
+ }
+
+ return (stSize);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyU32ArrayRead
+** 功能描述: 读取 U32 Array 类型的属性值
+** 输 入 : pdtnDev 设备树节点
+** pcPropname 属性名称
+** puiOutValue 读出的数据
+** stSize Array 的 size
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreePropertyU32ArrayRead (PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropname,
+ UINT32 *puiOutValue,
+ size_t stSize)
+{
+ INT iRet = API_DeviceTreePropertyU32VaraiableArrayRead(pdtnDev,
+ pcPropname,
+ puiOutValue,
+ stSize,
+ 0);
+ if (iRet >= 0) {
+ return (ERROR_NONE);
+ } else {
+ return (iRet);
+ }
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyU32Read
+** 功能描述: 读取 U32 类型的属性值
+** 输 入 : pdtnDev 设备树节点
+** pcPropname 属性名称
+** puiOutValue 读出的数据
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreePropertyU32Read (PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropname,
+ UINT32 *puiOutValue)
+{
+ return (API_DeviceTreePropertyU32ArrayRead(pdtnDev, pcPropname, puiOutValue, 1));
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyU32IndexRead
+** 功能描述: 按序号读取 U32 类型的属性值
+** 输 入 : pdtnDev 设备树节点
+** pcPropname 属性名称
+** uiIndex 指定的序号
+** puiOutValue 读出的数据
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreePropertyU32IndexRead (PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropname,
+ UINT32 uiIndex,
+ UINT32 *puiOutValue)
+{
+ const UINT32 *puiVal = __deviceTreePropertyValueOfSize(pdtnDev,
+ pcPropname,
+ ((uiIndex + 1) * sizeof(UINT32)),
+ 0,
+ LW_NULL);
+
+ if ((ULONG)puiVal >= (ULONG)-ERRMAX) {
+ return (INT)(ULONG)(puiVal);
+ }
+
+ *puiOutValue = BE32_TO_CPU(((UINT32 *)puiVal) + uiIndex);
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyU32Next
+** 功能描述: 按顺序读取 U32 类型的下一个属性值
+** 输 入 : pdtprop 当前设备树属性节点
+** puiCur 当前属性地址
+** puiOut 读出的数据
+** 输 出 : 更新后的属性地址
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+UINT32* API_DeviceTreePropertyU32Next (PLW_DEVTREE_PROPERTY pdtprop,
+ UINT32 *puiCur,
+ UINT32 *puiOut)
+{
+ PVOID pvCur = puiCur;
+
+ if (!pdtprop) {
+ return (LW_NULL);
+ }
+
+ if (!puiCur) {
+ puiCur = pdtprop->DTP_pvValue;
+ goto __out_val;
+ }
+
+ pvCur += sizeof(PVOID);
+ if (pvCur >= (pdtprop->DTP_pvValue + pdtprop->DTP_iLength)) {
+ return (LW_NULL);
+ }
+
+__out_val:
+ *puiOut = BE32_TO_CPU(puiCur);
+
+ return (pvCur);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyStringHelperRead
+** 功能描述: 解析 string 类型的属性值
+** 输 入 : pdtnDev 用于获取属性的设备树节点
+** pcPropname 查找的属性名称
+** ppcOutStrs 输出的字符串指针数组
+** stSize 读取的数组元素数量
+** iSkip 开头跳过的字符串数量
+** piCount 获取 string 类型属性长度
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块: 不要直接调用该接口,而是通过 API_DeviceTreePropertyStringRead* 这样的接口来间接调用该接口
+**
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreePropertyStringHelperRead (PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropName,
+ CPCHAR *ppcOutStrs,
+ size_t stSize,
+ INT iSkip,
+ INT *piCount)
+{
+ PLW_DEVTREE_PROPERTY pdtprop;
+ INT l;
+ INT i;
+ CPCHAR pcTmp;
+ CPCHAR pcEnd;
+
+ pdtprop = API_DeviceTreePropertyFind(pdtnDev, pcPropName, LW_NULL);
+ if (!pdtprop) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ if (!pdtprop->DTP_pvValue) {
+ _ErrorHandle(ENODATA);
+ return (PX_ERROR);
+ }
+
+ pcTmp = pdtprop->DTP_pvValue;
+ pcEnd = pcTmp + pdtprop->DTP_iLength;
+
+ for (i = 0;
+ (pcTmp < pcEnd) && (!ppcOutStrs || (i < iSkip + stSize));
+ i++, pcTmp += l) {
+
+ l = lib_strnlen(pcTmp, pcEnd - pcTmp) + 1;
+ if ((pcTmp + l) > pcEnd) {
+ _ErrorHandle(EILSEQ);
+ return (PX_ERROR);
+ }
+
+ if (ppcOutStrs && (i >= iSkip)) {
+ *ppcOutStrs++ = pcTmp;
+ }
+ }
+
+ i -= iSkip;
+
+ if (i <= 0) {
+ _ErrorHandle(ENODATA);
+ return (PX_ERROR);
+ }
+
+ if (piCount) {
+ *piCount = i;
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyStringIndexRead
+** 功能描述: 读取指定序号的 String 类型的属性值
+** 输 入 : pdtnDev 设备树节点
+** pcPropName 属性名称
+** iIndex 指定的序号
+** ppcOutPut 读取出的属性字符串
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreePropertyStringIndexRead (const PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropName,
+ INT iIndex,
+ CPCHAR *ppcOutPut)
+{
+ return (API_DeviceTreePropertyStringHelperRead(pdtnDev, pcPropName, ppcOutPut, 1, iIndex, LW_NULL));
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyStringCount
+** 功能描述: 从一个由多条 String 类型组成的属性值中获取 String 的个数
+** 输 入 : pdtnDev 设备树节点
+** pcPropName 属性名称
+** 输 出 : 获取的 String 个数
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreePropertyStringCount (const PLW_DEVTREE_NODE pdtnDev, CPCHAR pcPropName)
+{
+ INT iCount;
+ INT iRet;
+
+ iRet = API_DeviceTreePropertyStringHelperRead(pdtnDev, pcPropName, LW_NULL, 0, 0, &iCount);
+ if (iRet) {
+ return (0);
+ } else {
+ return (iCount);
+ }
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyStringNext
+** 功能描述: 读取下一个类型为 String 的属性值
+** 输 入 : pdtprop 属性节点
+** pcCur 当前 String 类型属性指针,为 NULL 时获得当前 String 属性值
+** 输 出 : 读取出的 String 属性
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+CPCHAR API_DeviceTreePropertyStringNext (PLW_DEVTREE_PROPERTY pdtprop, CPCHAR pcCur)
+{
+ CPVOID pvCur = pcCur;
+
+ if (!pdtprop) {
+ return (LW_NULL);
+ }
+
+ if (!pcCur) { /* 为空时,返回当前属性值 */
+ return (pdtprop->DTP_pvValue);
+ }
+
+ pvCur += lib_strlen(pcCur) + 1;
+ if (pvCur >= (pdtprop->DTP_pvValue + pdtprop->DTP_iLength)) {
+ return (LW_NULL);
+ }
+
+ return (pvCur);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyStringRead
+** 功能描述: 读取 String 类型的属性值
+** 输 入 : pdtnDev 设备树节点
+** pcPropname 属性名称
+** ppcOutString 读取出的 String 属性
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreePropertyStringRead (PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropName,
+ CPCHAR *ppcOutString)
+{
+ const PLW_DEVTREE_PROPERTY pdtprop = API_DeviceTreePropertyFind(pdtnDev, pcPropName, LW_NULL);
+
+ if (!pdtprop) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ if (!pdtprop->DTP_pvValue) {
+ _ErrorHandle(ENODATA);
+ return (PX_ERROR);
+ }
+
+ if (lib_strnlen(pdtprop->DTP_pvValue, pdtprop->DTP_iLength) >= pdtprop->DTP_iLength) {
+ _ErrorHandle(EILSEQ);
+ return (PX_ERROR);
+ }
+
+ *ppcOutString = pdtprop->DTP_pvValue;
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyStringMatch
+** 功能描述: 属性值与指定字符串比较函数
+** 输 入 : pdtnDev 设备树节点
+** pcPropname 属性名称
+** pcString 指定字符串
+** 输 出 : PX_ERROR 或 属性序号
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreePropertyStringMatch (PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcPropName,
+ CPCHAR pcString)
+{
+ PLW_DEVTREE_PROPERTY pdtprop = API_DeviceTreePropertyFind(pdtnDev, pcPropName, LW_NULL);
+ PCHAR pcPropTmp;
+ PCHAR pcPropEnd;
+ size_t stLen;
+ INT i;
+
+ if (!pdtprop) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ if (!pdtprop->DTP_pvValue) {
+ _ErrorHandle(ENODATA);
+ return (PX_ERROR);
+ }
+
+ pcPropTmp = pdtprop->DTP_pvValue;
+ pcPropEnd = pcPropTmp + pdtprop->DTP_iLength;
+
+ for (i = 0; pcPropTmp < pcPropEnd; i++, pcPropTmp += stLen) {
+ stLen = lib_strnlen(pcPropTmp, pcPropEnd - pcPropTmp) + 1;
+ if ((pcPropTmp + stLen) > pcPropEnd) {
+ _ErrorHandle(EILSEQ);
+ return (PX_ERROR);
+ }
+
+ if (lib_strcmp(pcString, pcPropTmp) == 0) {
+ return (i);
+ }
+ }
+
+ _ErrorHandle(ENODATA);
+ return (PX_ERROR);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyBoolRead
+** 功能描述: 读取 BOOL 类型的属性值
+** 输 入 : pdtnDev 设备树节点
+** pcPropName 属性名称
+** 输 出 : LW_TRUE 或 LW_FALSE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+BOOL API_DeviceTreePropertyBoolRead (PLW_DEVTREE_NODE pdtnDev, CPCHAR pcPropName)
+{
+ PLW_DEVTREE_PROPERTY pdtprop = API_DeviceTreePropertyFind(pdtnDev, pcPropName, LW_NULL);
+
+ if (pdtprop) {
+ return (LW_TRUE);
+ }
+
+ return (LW_FALSE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreePropertyGet
+** 功能描述: 通过指定节点的指定属性名,获取一个属性值
+** 输 入 : pdtnDev 用于获取属性的设备树节点
+** pcName 查找的属性名称
+** piLen 属性的长度
+** 输 出 : 属性值 或 LW_NULL
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PVOID API_DeviceTreePropertyGet (PLW_DEVTREE_NODE pdtnDev,
+ CPCHAR pcName,
+ INT *piLen)
+{
+ PLW_DEVTREE_PROPERTY pdtprop = API_DeviceTreePropertyFind(pdtnDev, pcName, piLen);
+
+ if (pdtprop) {
+ return (pdtprop->DTP_pvValue);
+ }
+
+ return (LW_NULL);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeModaliasGet
+** 功能描述: 为设备节点找到一个合适的名称
+** 输 入 : pdtnDev 用于获取属性的设备树节点
+** pcName 存放属性名的内存指针
+** iLen 存放属性名的内存大小
+** 输 出 : 找到返回 ERROR_NONE, 未找到返回其他
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeModaliasGet (PLW_DEVTREE_NODE pdtnDev,
+ PCHAR pcName,
+ INT iLen)
+{
+ CPCHAR pcCompatible;
+ CPCHAR pcStart;
+ INT iCpLen;
+
+ pcCompatible = API_DeviceTreePropertyGet(pdtnDev, "compatible", &iCpLen);
+ if (!pcCompatible || (lib_strlen(pcCompatible) > iCpLen)) {
+ return (ENODEV);
+ }
+
+ pcStart = lib_strchr(pcCompatible, ',');
+ lib_strlcpy(pcName, pcStart ? (pcStart + 1) : pcCompatible, iLen);
+
+ return (ERROR_NONE);
+}
+
+#endif /* LW_CFG_DEVTREE_EN > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtreeSpi.c b/SylixOS/devtree/devtreeSpi.c
new file mode 100644
index 0000000..3894162
--- /dev/null
+++ b/SylixOS/devtree/devtreeSpi.c
@@ -0,0 +1,235 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtreeSpi.c
+**
+** 创 建 人: Zhang.Jian (张健)
+**
+** 文件创建日期: 2019 年 11 月 20 日
+**
+** 描 述: SPI 驱动框架中设备树相关接口
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if LW_CFG_DEVTREE_EN > 0
+#include "devtree.h"
+/*********************************************************************************************************
+** 函数名称: __deviceTreeSpiDevInfoGet
+** 功能描述: 获取 SPI 设备信息
+** 输 入 : pdtspidev SPI 设备指针
+** pdtnDev SPI 设备的设备树节点
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+INT __deviceTreeSpiDevInfoGet (PLW_DT_SPI_DEVICE pdtspidev, PLW_DEVTREE_NODE pdtnDev)
+{
+ UINT32 uiValue = 0;
+ INT iRet;
+
+ iRet = API_DeviceTreeModaliasGet(pdtnDev,
+ pdtspidev->DTSPIDEV_cName,
+ sizeof(pdtspidev->DTSPIDEV_cName));/* 获取 SPI 设备名称 */
+ if (iRet) {
+ DEVTREE_ERR("%s Get name failed supported\r\n",
+ pdtnDev->DTN_pcFullName);
+ return (PX_ERROR);
+ }
+
+ /*
+ * 获取基本的模式信息(相位、极性等)
+ */
+ if (API_DeviceTreePropertyBoolRead(pdtnDev, "spi-cpha")) {
+ pdtspidev->DTSPIDEV_uiMode |= LW_SPI_CPHA;
+ }
+ if (API_DeviceTreePropertyBoolRead(pdtnDev, "spi-cpol")) {
+ pdtspidev->DTSPIDEV_uiMode |= LW_SPI_CPOL;
+ }
+ if (API_DeviceTreePropertyBoolRead(pdtnDev, "spi-3wire")) {
+ pdtspidev->DTSPIDEV_uiMode |= LW_SPI_3WIRE;
+ }
+ if (API_DeviceTreePropertyBoolRead(pdtnDev, "spi-lsb-first")) {
+ pdtspidev->DTSPIDEV_uiMode |= LW_SPI_LSB_FIRST;
+ }
+ if (API_DeviceTreePropertyBoolRead(pdtnDev, "spi-cs-high")) {
+ pdtspidev->DTSPIDEV_uiMode |= LW_SPI_CS_HIGH;
+ }
+
+ /*
+ * 获取 SPI 发送总线的数据宽度,设置到模式中
+ */
+ if (!API_DeviceTreePropertyU32Read(pdtnDev, "spi-tx-bus-width", &uiValue)) {
+
+ switch (uiValue) {
+
+ case 1:
+ break;
+
+ case 2:
+ pdtspidev->DTSPIDEV_uiMode |= LW_SPI_TX_DUAL;
+ break;
+
+ case 4:
+ pdtspidev->DTSPIDEV_uiMode |= LW_SPI_TX_QUAD;
+ break;
+
+ case 8:
+ pdtspidev->DTSPIDEV_uiMode |= LW_SPI_TX_OCTAL;
+ break;
+
+ default:
+ DEVTREE_ERR("%s spi-tx-bus-width %d not supported\r\n",
+ pdtnDev->DTN_pcFullName, uiValue);
+ break;
+ }
+ }
+
+ /*
+ * 获取 SPI 接受总线的数据宽度,设置到模式中
+ */
+ if (!API_DeviceTreePropertyU32Read(pdtnDev, "spi-rx-bus-width", &uiValue)) {
+
+ switch (uiValue) {
+
+ case 1:
+ break;
+
+ case 2:
+ pdtspidev->DTSPIDEV_uiMode |= LW_SPI_RX_DUAL;
+ break;
+
+ case 4:
+ pdtspidev->DTSPIDEV_uiMode |= LW_SPI_RX_QUAD;
+ break;
+
+ case 8:
+ pdtspidev->DTSPIDEV_uiMode |= LW_SPI_RX_OCTAL;
+ break;
+
+ default:
+ DEVTREE_ERR("%s spi-rx-bus-width %d not supported\r\n",
+ pdtnDev->DTN_pcFullName, uiValue);
+ break;
+ }
+ }
+
+ /*
+ * 获取设备地址
+ */
+ iRet = API_DeviceTreePropertyU32Read(pdtnDev, "reg", &uiValue);
+ if (iRet) {
+ DEVTREE_ERR("%s has no valid 'reg' property.\r\n",
+ pdtnDev->DTN_pcFullName);
+
+ return (PX_ERROR);
+ }
+ pdtspidev->DTSPIDEV_ucChipSel = uiValue;
+
+ /*
+ * 获取 SPI 设备最大传输速率
+ */
+ iRet = API_DeviceTreePropertyU32Read(pdtnDev, "spi-max-frequency", &uiValue);
+ if (iRet) {
+ DEVTREE_ERR("%s has no valid 'spi-max-frequency' property.\r\n",
+ pdtnDev->DTN_pcFullName);
+
+ return (PX_ERROR);
+ }
+
+ pdtspidev->DTSPIDEV_uiSpeedMax = uiValue;
+ pdtspidev->DTSPIDEV_atomicUsageCnt.counter = 0;
+ pdtspidev->DTSPIDEV_devinstance.DEVHD_pdtnDev = pdtnDev;
+ pdtspidev->DTSPIDEV_devinstance.DEVHD_pcName = pdtnDev->DTN_pcFullName;
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeSpiCtrlRegister
+** 功能描述: 从设备树中解析并注册 SPI 控制器下挂载的设备
+** 输 入 : pdtspictrl SPI 控制器指针
+** pdtnDev SPI 设备节点
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeSpiCtrlRegister (PLW_DT_SPI_CTRL pdtspictrl,
+ PLW_DEVTREE_NODE pdtnDev)
+{
+ PLW_DEVTREE_NODE pdtnChild;
+ INT iRet;
+
+ iRet = API_SpiCtrlRegister(pdtspictrl); /* 注册 SPI 控制器 */
+ if (iRet) {
+ return (iRet);
+ }
+
+ _LIST_EACH_CHILD_OF_NODE(pdtnDev, pdtnChild) { /* 遍历该节点的子节点 */
+ API_DeviceTreeSpiDevRegister(pdtspictrl, pdtnChild); /* 注册 SPI 设备 */
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceTreeSpiDevRegister
+** 功能描述: 通过设备树注册 SPI 设备
+** 输 入 : pdtspictrl SPI 控制器指针
+** pdtnDev SPI 设备节点
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceTreeSpiDevRegister (PLW_DT_SPI_CTRL pdtspictrl,
+ PLW_DEVTREE_NODE pdtnDev)
+{
+ PLW_DT_SPI_DEVICE pdtspidev;
+ INT iRet;
+
+ pdtspidev = API_SpiDevCreate(); /* 创建 SPI 设备 */
+ if (LW_NULL == pdtspidev) {
+ return (PX_ERROR);
+ }
+ pdtspidev->DTSPIDEV_pdtspictrl = pdtspictrl; /* 设置 SPI 设备连接的控制器 */
+
+ iRet = __deviceTreeSpiDevInfoGet(pdtspidev, pdtnDev); /* 从设备树中获取 SPI 设备信息 */
+ if (iRet) {
+ goto __error_handle;
+ }
+
+ iRet = API_SpiDevRegister(pdtspidev); /* 注册 SPI 设备到系统 */
+ if (iRet) {
+ DEVTREE_ERR("SPI device %s register failed.\r\n",
+ pdtspidev->DTSPIDEV_cName);
+ goto __error_handle;
+ } else {
+ DEVTREE_MSG("SPI device %s register successfully.\r\n",
+ pdtspidev->DTSPIDEV_cName);
+ }
+
+ return (ERROR_NONE);
+
+__error_handle:
+ API_SpiDevDelete(pdtspidev);
+ return (iRet);
+}
+
+#endif /* LW_CFG_DEVTREE_EN > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtree_error.h b/SylixOS/devtree/devtree_error.h
new file mode 100644
index 0000000..c6449e6
--- /dev/null
+++ b/SylixOS/devtree/devtree_error.h
@@ -0,0 +1,40 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtree_error.h
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 06 月 24 日
+**
+** 描 述: 设备树错误号
+*********************************************************************************************************/
+
+#ifndef __DEVTREE_ERROR_H
+#define __DEVTREE_ERROR_H
+
+/*********************************************************************************************************
+ 设备树 6000 - 6500
+*********************************************************************************************************/
+
+#define ERROR_DEVTREE_MAGIC_ERROR 6000 /* 设备树数据错误 */
+#define ERROR_DEVTREE_DEPTH_ERROR 6001 /* 设备树当前层次错误 */
+#define ERROR_DEVTREE_SCAN_ERROR 6002 /* 设备树扫描错误 */
+#define ERROR_DEVTREE_POPULATE_ERROR 6003 /* 设备树解析错误 */
+#define ERROR_DEVTREE_MEM_OVERLAP 6004 /* 设备树内存产生重叠 */
+#define ERROR_DEVTREE_TABLE_NULL 6005 /* 设备树匹配表格为空 */
+#define ERROR_DEVTREE_EPROBE_DEFER 6006 /* 设备树 probe 出错 */
+
+#endif /* __DEVTREE_ERROR_H */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtree_inline.h b/SylixOS/devtree/devtree_inline.h
new file mode 100644
index 0000000..a75a253
--- /dev/null
+++ b/SylixOS/devtree/devtree_inline.h
@@ -0,0 +1,165 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtree_inline.h
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 06 月 24 日
+**
+** 描 述: 设备树接口系统内联接口实现
+*********************************************************************************************************/
+
+#ifndef __DEVTREE_INLINE_H
+#define __DEVTREE_INLINE_H
+
+#define __SYLIXOS_KERNEL
+#include "SylixOS.h"
+#include "devtree.h"
+#include "linux/bitops.h"
+
+/*********************************************************************************************************
+ 将对应地址内的整型值转换为主机序
+*********************************************************************************************************/
+
+#define BE32_TO_CPU(puiVal) (be32toh(*(UINT32 *)(puiVal)))
+
+/*********************************************************************************************************
+ 获取父节点的每一个子节点
+*********************************************************************************************************/
+
+#define _LIST_EACH_CHILD_OF_NODE(pdtnParent, pdtnChild) \
+ for (pdtnChild = API_DeviceTreeNextChildGet(pdtnParent, LW_NULL); \
+ pdtnChild != LW_NULL; \
+ pdtnChild = API_DeviceTreeNextChildGet(pdtnParent, pdtnChild))
+
+#define _LIST_EACH_OF_PROPERTY(pdtnDev, pcPropName, pdtproperty, pcStr) \
+ for (pdtproperty = API_DeviceTreePropertyFind(pdtnDev, pcPropName, LW_NULL), \
+ pcStr = API_DeviceTreePropertyStringNext(pdtproperty, LW_NULL); \
+ pcStr != LW_NULL; \
+ pcStr = API_DeviceTreePropertyStringNext(pdtproperty, pcStr))
+
+#define _LIST_EACH_OF_UINT32_PROPERTY(pdtnDev, pcPropName, pdtproperty, puiCur, uiOut) \
+ for (pdtproperty = API_DeviceTreePropertyFind(pdtnDev, pcPropName, NULL), \
+ puiCur = API_DeviceTreePropertyU32Next(pdtproperty, LW_NULL, &uiOut); \
+ puiCur != LW_NULL; \
+ puiCur = API_DeviceTreePropertyU32Next(pdtproperty, puiCur, &uiOut))
+
+/*********************************************************************************************************
+ 遍历每一个节点
+*********************************************************************************************************/
+
+#define _LIST_EACH_OF_ALLNODES_FROM(pdtnFrom, pdtnDev) \
+ for (pdtnDev = API_DeviceTreeFindAllNodes(pdtnFrom); \
+ pdtnDev != LW_NULL; \
+ pdtnDev = API_DeviceTreeFindAllNodes(pdtnDev))
+
+#define _LIST_EACH_OF_ALLNODES(dn) _LIST_EACH_OF_ALLNODES_FROM(LW_NULL, dn)
+
+/*********************************************************************************************************
+ 遍历每一个 PHANDLE
+*********************************************************************************************************/
+
+#define _LIST_EACH_PHANDLE(it, err, np, ln, cn, cc) \
+ for (API_DeviceTreePhandleIteratorInit((it), (np), (ln), (cn), (cc)), \
+ err = API_DeviceTreePhandleIteratorNext(it); \
+ err == 0; \
+ err = API_DeviceTreePhandleIteratorNext(it))
+
+/*********************************************************************************************************
+** 函数名称: __deviceTreeNodeFlagSet
+** 功能描述: 设置设备树节点的标志
+** 输 入 : pdtnDev 设备树节点
+** ulFlag 设置的设备树节点标志
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static LW_INLINE VOID __deviceTreeNodeFlagSet (PLW_DEVTREE_NODE pdtnDev, ULONG ulFlag)
+{
+ __set_bit(ulFlag, &(pdtnDev->DTN_ulFlags));
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeNodeFlagCheck
+** 功能描述: 检查设备树节点的某个标志是否设置
+** 输 入 : pdtnDev 设备树节点
+** ulFlag 检查的设备树节点标志
+** 输 出 : 非零值表示有设置
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static LW_INLINE INT __deviceTreeNodeFlagCheck (PLW_DEVTREE_NODE pdtnDev, ULONG ulFlag)
+{
+ return (__test_bit(ulFlag, &(pdtnDev->DTN_ulFlags)));
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeNodeFullName
+** 功能描述: 获取设备树节点的全路径
+** 输 入 : pdtnDev 设备树节点
+** 输 出 : 设备树节点的全路径
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static LW_INLINE CPCHAR __deviceTreeNodeFullName (const PLW_DEVTREE_NODE pdtnDev)
+{
+ return (pdtnDev ? pdtnDev->DTN_pcFullName : "<no-node>");
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeFindNodeByPath
+** 功能描述: 通过路径查找设备树节点
+** 输 入 : pcPath 设备树节点路径
+** 输 出 : 设备树节点
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static LW_INLINE PLW_DEVTREE_NODE __deviceTreeFindNodeByPath (CPCHAR pcPath)
+{
+ return (API_DeviceTreeFindNodeOptsByPath(pcPath, LW_NULL));
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeNumberRead
+** 功能描述: 读取 cells 中的值
+** 输 入 : puiCell cells 属性的基地址
+** iSize cells 的 size 大小
+** 输 出 : cells 中的值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static LW_INLINE UINT64 __deviceTreeNumberRead (const UINT32 *puiCell, INT iSize)
+{
+ UINT64 ullRet = 0;
+
+ while (iSize--) {
+ ullRet = (ullRet << 32) | be32toh(*(puiCell++));
+ }
+
+ return (ullRet);
+}
+/*********************************************************************************************************
+** 函数名称: __deviceTreeBaseNameGet
+** 功能描述: 获取节点名称
+** 输 入 : pcPath 节点的全路径
+** 输 出 : 节点名称
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static LW_INLINE CPCHAR __deviceTreeBaseNameGet (CPCHAR pcPath)
+{
+ CPCHAR pcTail = lib_strrchr(pcPath, '/');
+
+ return (pcTail ? (pcTail + 1) : pcPath);
+}
+
+#endif /* __DEVTREE_INLINE_H */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/devtree/devtree_value.h b/SylixOS/devtree/devtree_value.h
new file mode 100644
index 0000000..d2402ea
--- /dev/null
+++ b/SylixOS/devtree/devtree_value.h
@@ -0,0 +1,37 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: devtree_value.h
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 06 月 24 日
+**
+** 描 述: 设备树全局变量声明
+*********************************************************************************************************/
+
+#ifndef __DEVTREE_VALUE_H
+#define __DEVTREE_VALUE_H
+
+/*********************************************************************************************************
+ 外部引用声明
+*********************************************************************************************************/
+
+extern PLW_DEVTREE_NODE _G_pdtnRoot;
+extern PLW_DEVTREE_NODE _G_pdtnAliases;
+extern PLW_DEVTREE_NODE *_G_ppdtnPhandleCache;
+extern UINT32 _G_uiPhandleCacheMask;
+
+#endif /* __DEVTREE_VALUE_H */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/driver/fdt/fdt.c b/SylixOS/driver/fdt/fdt.c
index 22286a1..6d58ae1 100644
--- a/SylixOS/driver/fdt/fdt.c
+++ b/SylixOS/driver/fdt/fdt.c
@@ -50,12 +50,17 @@
*/
#include "libfdt_env.h"
-#include <fdt.h>
-#include <libfdt.h>
+#include "fdt.h"
+#include "libfdt.h"
#include "libfdt_internal.h"
-int fdt_check_header(const void *fdt)
+/*
+ * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
+ * that the given buffer contains what appears to be a flattened
+ * device tree with sane information in its header.
+ */
+int fdt_ro_probe_(const void *fdt)
{
if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */
@@ -74,6 +79,78 @@ int fdt_check_header(const void *fdt)
return 0;
}
+static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
+{
+ return (off >= hdrsize) && (off <= totalsize);
+}
+
+static int check_block_(uint32_t hdrsize, uint32_t totalsize,
+ uint32_t base, uint32_t size)
+{
+ if (!check_off_(hdrsize, totalsize, base))
+ return 0; /* block start out of bounds */
+ if ((base + size) < base)
+ return 0; /* overflow */
+ if (!check_off_(hdrsize, totalsize, base + size))
+ return 0; /* block end out of bounds */
+ return 1;
+}
+
+size_t fdt_header_size_(uint32_t version)
+{
+ if (version <= 1)
+ return FDT_V1_SIZE;
+ else if (version <= 2)
+ return FDT_V2_SIZE;
+ else if (version <= 3)
+ return FDT_V3_SIZE;
+ else if (version <= 16)
+ return FDT_V16_SIZE;
+ else
+ return FDT_V17_SIZE;
+}
+
+int fdt_check_header(const void *fdt)
+{
+ size_t hdrsize;
+
+ if (fdt_magic(fdt) != FDT_MAGIC)
+ return -FDT_ERR_BADMAGIC;
+ hdrsize = fdt_header_size(fdt);
+ if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+ || (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION))
+ return -FDT_ERR_BADVERSION;
+ if (fdt_version(fdt) < fdt_last_comp_version(fdt))
+ return -FDT_ERR_BADVERSION;
+
+ if ((fdt_totalsize(fdt) < hdrsize)
+ || (fdt_totalsize(fdt) > INT_MAX))
+ return -FDT_ERR_TRUNCATED;
+
+ /* Bounds check memrsv block */
+ if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt)))
+ return -FDT_ERR_TRUNCATED;
+
+ /* Bounds check structure block */
+ if (fdt_version(fdt) < 17) {
+ if (!check_off_(hdrsize, fdt_totalsize(fdt),
+ fdt_off_dt_struct(fdt)))
+ return -FDT_ERR_TRUNCATED;
+ } else {
+ if (!check_block_(hdrsize, fdt_totalsize(fdt),
+ fdt_off_dt_struct(fdt),
+ fdt_size_dt_struct(fdt)))
+ return -FDT_ERR_TRUNCATED;
+ }
+
+ /* Bounds check strings block */
+ if (!check_block_(hdrsize, fdt_totalsize(fdt),
+ fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt)))
+ return -FDT_ERR_TRUNCATED;
+
+ return 0;
+}
+
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{
unsigned absoffset = offset + fdt_off_dt_struct(fdt);
@@ -88,7 +165,7 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
|| ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL;
- return _fdt_offset_ptr(fdt, offset);
+ return fdt_offset_ptr_(fdt, offset);
}
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
@@ -123,6 +200,9 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
/* skip-name offset, length and value */
offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ fdt32_to_cpu(*lenp);
+ if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
+ ((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
+ offset += 4;
break;
case FDT_END:
@@ -141,7 +221,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
return tag;
}
-int _fdt_check_node_offset(const void *fdt, int offset)
+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))
@@ -150,7 +230,7 @@ int _fdt_check_node_offset(const void *fdt, int offset)
return offset;
}
-int _fdt_check_prop_offset(const void *fdt, int 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))
@@ -165,7 +245,7 @@ int fdt_next_node(const void *fdt, int offset, int *depth)
uint32_t tag;
if (offset >= 0)
- if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
+ if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0)
return nextoffset;
do {
@@ -227,7 +307,7 @@ int fdt_next_subnode(const void *fdt, int offset)
return offset;
}
-const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
+const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
{
int len = strlen(s) + 1;
const char *last = strtab + tabsize - len;
@@ -241,7 +321,7 @@ const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
int fdt_move(const void *fdt, void *buf, int bufsize)
{
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
if (fdt_totalsize(fdt) > bufsize)
return -FDT_ERR_NOSPACE;
diff --git a/SylixOS/driver/fdt/fdt.h b/SylixOS/driver/fdt/fdt.h
index 526aedb..bbc59dd 100644
--- a/SylixOS/driver/fdt/fdt.h
+++ b/SylixOS/driver/fdt/fdt.h
@@ -1,5 +1,5 @@
-#ifndef _FDT_H
-#define _FDT_H
+#ifndef FDT_H
+#define FDT_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
@@ -54,12 +54,21 @@
#ifndef __ASSEMBLY__
+/*
+ * fdt_header 分为 version1、version2、version3、version16、version17 几种类型
+ * FDT_V1_SIZE 表示 version1 的大小,7 个 fdt32_t 类型;
+ * FDT_V2_SIZE 为 FDT_V1_SIZE + 1 个 fdt32_t 类型;
+ * FDT_V3_SIZE 为 FDT_V2_SIZE + 1 个 fdt32_t 类型;
+ * FDT_V16_SIZE 与 FDT_V3_SIZE 相同;
+ * FDT_V17_SIZE 为 FDT_V16_SIZE + 1 个 fdt32_t 类型;
+ */
+
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 off_mem_rsvmap; /* offset to memory reserve map */ // dtb 中内存保留块偏移地址
fdt32_t version; /* format version */
fdt32_t last_comp_version; /* last compatible version */
@@ -73,7 +82,7 @@ struct fdt_header {
fdt32_t size_dt_struct; /* size of the structure block */
};
-struct fdt_reserve_entry {
+struct fdt_reserve_entry { // 保留区域的入口、大小
fdt64_t address;
fdt64_t size;
};
@@ -108,4 +117,4 @@ struct fdt_property {
#define FDT_V16_SIZE FDT_V3_SIZE
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
-#endif /* _FDT_H */
+#endif /* FDT_H */
diff --git a/SylixOS/driver/fdt/fdt_addresses.c b/SylixOS/driver/fdt/fdt_addresses.c
index eff4dbc..0bc49fd 100644
--- a/SylixOS/driver/fdt/fdt_addresses.c
+++ b/SylixOS/driver/fdt/fdt_addresses.c
@@ -1,6 +1,7 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
+ * Copyright (C) 2018 embedded brains GmbH
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
@@ -50,47 +51,94 @@
*/
#include "libfdt_env.h"
-#include <fdt.h>
-#include <libfdt.h>
+#include "fdt.h"
+#include "libfdt.h"
#include "libfdt_internal.h"
-int fdt_address_cells(const void *fdt, int nodeoffset)
+static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
{
- const fdt32_t *ac;
+ const fdt32_t *c;
int val;
int len;
- ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len);
- if (!ac)
- return 2;
+ c = fdt_getprop(fdt, nodeoffset, name, &len);
+ if (!c)
+ return len;
- if (len != sizeof(*ac))
+ if (len != sizeof(*c))
return -FDT_ERR_BADNCELLS;
- val = fdt32_to_cpu(*ac);
+ val = fdt32_to_cpu(*c);
if ((val <= 0) || (val > FDT_MAX_NCELLS))
return -FDT_ERR_BADNCELLS;
return val;
}
-int fdt_size_cells(const void *fdt, int nodeoffset)
+int fdt_address_cells(const void *fdt, int nodeoffset)
{
- const fdt32_t *sc;
int val;
- int len;
- sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len);
- if (!sc)
+ val = fdt_cells(fdt, nodeoffset, "#address-cells");
+ if (val == -FDT_ERR_NOTFOUND)
return 2;
+ return val;
+}
+
+int fdt_size_cells(const void *fdt, int nodeoffset)
+{
+ int val;
- if (len != sizeof(*sc))
+ 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;
+ }
- val = fdt32_to_cpu(*sc);
- if ((val < 0) || (val > FDT_MAX_NCELLS))
+ /* 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 val;
+ return fdt_appendprop(fdt, nodeoffset, name, data,
+ (addr_cells + size_cells) * sizeof(fdt32_t));
}
diff --git a/SylixOS/driver/fdt/fdt_empty_tree.c b/SylixOS/driver/fdt/fdt_empty_tree.c
index f2ae9b7..a85de66 100644
--- a/SylixOS/driver/fdt/fdt_empty_tree.c
+++ b/SylixOS/driver/fdt/fdt_empty_tree.c
@@ -50,8 +50,8 @@
*/
#include "libfdt_env.h"
-#include <fdt.h>
-#include <libfdt.h>
+#include "fdt.h"
+#include "libfdt.h"
#include "libfdt_internal.h"
diff --git a/SylixOS/driver/fdt/fdt_overlay.c b/SylixOS/driver/fdt/fdt_overlay.c
index bd81241..1bb83af 100644
--- a/SylixOS/driver/fdt/fdt_overlay.c
+++ b/SylixOS/driver/fdt/fdt_overlay.c
@@ -1,7 +1,58 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2016 Free Electrons
+ * Copyright (C) 2016 NextThing Co.
+ *
+ * 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 "fdt.h"
+#include "libfdt.h"
#include "libfdt_internal.h"
@@ -646,7 +697,7 @@ static int get_path_len(const void *fdt, int nodeoffset)
int len = 0, namelen;
const char *name;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
for (;;) {
name = fdt_get_name(fdt, nodeoffset, &namelen);
@@ -812,11 +863,15 @@ static int overlay_symbol_update(void *fdt, void *fdto)
int fdt_overlay_apply(void *fdt, void *fdto)
{
- uint32_t delta = fdt_get_max_phandle(fdt);
+ uint32_t delta;
int ret;
- FDT_CHECK_HEADER(fdt);
- FDT_CHECK_HEADER(fdto);
+ FDT_RO_PROBE(fdt);
+ FDT_RO_PROBE(fdto);
+
+ ret = fdt_find_max_phandle(fdt, &delta);
+ if (ret)
+ goto err;
ret = overlay_adjust_local_phandles(fdto, delta);
if (ret)
diff --git a/SylixOS/driver/fdt/fdt_ro.c b/SylixOS/driver/fdt/fdt_ro.c
index 08de2cc..66a0698 100644
--- a/SylixOS/driver/fdt/fdt_ro.c
+++ b/SylixOS/driver/fdt/fdt_ro.c
@@ -50,17 +50,18 @@
*/
#include "libfdt_env.h"
-#include <fdt.h>
-#include <libfdt.h>
+#include "fdt.h"
+#include "libfdt.h"
#include "libfdt_internal.h"
-static int _fdt_nodename_eq(const void *fdt, int offset,
+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);
+ int olen;
+ const char *p = fdt_get_name(fdt, offset, &olen);
- if (!p)
+ if (!p || olen < len)
/* short match */
return 0;
@@ -75,63 +76,159 @@ static int _fdt_nodename_eq(const void *fdt, int offset,
return 0;
}
+const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
+{
+ uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt);
+ size_t len;
+ int err;
+ const char *s, *n;
+
+ err = fdt_ro_probe_(fdt);
+ if (err != 0)
+ goto fail;
+
+ err = -FDT_ERR_BADOFFSET;
+ if (absoffset >= fdt_totalsize(fdt))
+ goto fail;
+ len = fdt_totalsize(fdt) - absoffset;
+
+ if (fdt_magic(fdt) == FDT_MAGIC) {
+ if (stroffset < 0)
+ goto fail;
+ if (fdt_version(fdt) >= 17) {
+ if (stroffset >= fdt_size_dt_strings(fdt))
+ goto fail;
+ if ((fdt_size_dt_strings(fdt) - stroffset) < len)
+ len = fdt_size_dt_strings(fdt) - stroffset;
+ }
+ } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+ if ((stroffset >= 0)
+ || (stroffset < -fdt_size_dt_strings(fdt)))
+ goto fail;
+ if ((-stroffset) < len)
+ len = -stroffset;
+ } else {
+ err = -FDT_ERR_INTERNAL;
+ goto fail;
+ }
+
+ s = (const char *)fdt + absoffset;
+ n = memchr(s, '\0', len);
+ if (!n) {
+ /* missing terminating NULL */
+ err = -FDT_ERR_TRUNCATED;
+ goto fail;
+ }
+
+ if (lenp)
+ *lenp = n - s;
+ return s;
+
+fail:
+ if (lenp)
+ *lenp = err;
+ return NULL;
+}
+
const char *fdt_string(const void *fdt, int stroffset)
{
- return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+ return fdt_get_string(fdt, stroffset, NULL);
}
-static int _fdt_string_eq(const void *fdt, int stroffset,
+static int fdt_string_eq_(const void *fdt, int stroffset,
const char *s, int len)
{
- const char *p = fdt_string(fdt, stroffset);
+ int slen;
+ const char *p = fdt_get_string(fdt, stroffset, &slen);
- return (strlen(p) == len) && (memcmp(p, s, len) == 0);
+ return p && (slen == len) && (memcmp(p, s, len) == 0);
}
-uint32_t fdt_get_max_phandle(const void *fdt)
+int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
{
- uint32_t max_phandle = 0;
- int offset;
+ uint32_t max = 0;
+ int offset = -1;
- for (offset = fdt_next_node(fdt, -1, NULL);;
- offset = fdt_next_node(fdt, offset, NULL)) {
- uint32_t phandle;
+ while (true) {
+ uint32_t value;
- if (offset == -FDT_ERR_NOTFOUND)
- return max_phandle;
+ offset = fdt_next_node(fdt, offset, NULL);
+ if (offset < 0) {
+ if (offset == -FDT_ERR_NOTFOUND)
+ break;
- if (offset < 0)
- return (uint32_t)-1;
+ return offset;
+ }
- phandle = fdt_get_phandle(fdt, offset);
- if (phandle == (uint32_t)-1)
- continue;
+ value = fdt_get_phandle(fdt, offset);
- if (phandle > max_phandle)
- max_phandle = phandle;
+ if (value > max)
+ max = value;
}
+ if (phandle)
+ *phandle = max;
+
+ return 0;
+}
+
+int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
+{
+ uint32_t max;
+ int err;
+
+ err = fdt_find_max_phandle(fdt, &max);
+ if (err < 0)
+ return err;
+
+ if (max == FDT_MAX_PHANDLE)
+ return -FDT_ERR_NOPHANDLES;
+
+ if (phandle)
+ *phandle = max + 1;
+
return 0;
}
+static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
+{
+ int offset = n * sizeof(struct fdt_reserve_entry);
+ int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
+
+ if (absoffset < fdt_off_mem_rsvmap(fdt))
+ return NULL;
+ if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry))
+ return NULL;
+ return fdt_mem_rsv_(fdt, n);
+}
+
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);
+ const struct fdt_reserve_entry *re;
+
+ FDT_RO_PROBE(fdt);
+ re = fdt_mem_rsv(fdt, n);
+ if (!re)
+ return -FDT_ERR_BADOFFSET;
+
+ *address = fdt64_ld(&re->address);
+ *size = fdt64_ld(&re->size);
return 0;
}
int fdt_num_mem_rsv(const void *fdt)
{
- int i = 0;
+ int i;
+ const struct fdt_reserve_entry *re;
- while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
- i++;
- return i;
+ for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
+ if (fdt64_ld(&re->size) == 0)
+ return i;
+ }
+ return -FDT_ERR_TRUNCATED;
}
-static int _nextprop(const void *fdt, int offset)
+static int nextprop_(const void *fdt, int offset)
{
uint32_t tag;
int nextoffset;
@@ -160,13 +257,13 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
{
int depth;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(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))
+ && fdt_nodename_eq_(fdt, offset, name, namelen))
return offset;
if (depth < 0)
@@ -186,7 +283,7 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
const char *p = path;
int offset = 0;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
/* see if we have an alias */
if (*path != '/') {
@@ -232,17 +329,35 @@ int fdt_path_offset(const void *fdt, const char *path)
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
{
- const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
+ const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
+ const char *nameptr;
int err;
- if (((err = fdt_check_header(fdt)) != 0)
- || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+ if (((err = fdt_ro_probe_(fdt)) != 0)
+ || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
goto fail;
+ nameptr = nh->name;
+
+ if (fdt_version(fdt) < 0x10) {
+ /*
+ * For old FDT versions, match the naming conventions of V16:
+ * give only the leaf name (after all /). The actual tree
+ * contents are loosely checked.
+ */
+ const char *leaf;
+ leaf = strrchr(nameptr, '/');
+ if (leaf == NULL) {
+ err = -FDT_ERR_BADSTRUCTURE;
+ goto fail;
+ }
+ nameptr = leaf+1;
+ }
+
if (len)
- *len = strlen(nh->name);
+ *len = strlen(nameptr);
- return nh->name;
+ return nameptr;
fail:
if (len)
@@ -254,58 +369,79 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset)
{
int offset;
- if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+ if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
return offset;
- return _nextprop(fdt, offset);
+ return nextprop_(fdt, offset);
}
int fdt_next_property_offset(const void *fdt, int offset)
{
- if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
+ if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
return offset;
- return _nextprop(fdt, offset);
+ return nextprop_(fdt, offset);
}
-const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
- int offset,
- int *lenp)
+static 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 ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
if (lenp)
*lenp = err;
return NULL;
}
- prop = _fdt_offset_ptr(fdt, offset);
+ prop = fdt_offset_ptr_(fdt, offset);
if (lenp)
- *lenp = fdt32_to_cpu(prop->len);
+ *lenp = fdt32_ld(&prop->len);
return prop;
}
-const struct fdt_property *fdt_get_property_namelen(const void *fdt,
- int offset,
- const char *name,
- int namelen, int *lenp)
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+ int offset,
+ int *lenp)
+{
+ /* Prior to version 16, properties may need realignment
+ * and this API does not work. fdt_getprop_*() will, however. */
+
+ if (fdt_version(fdt) < 0x10) {
+ if (lenp)
+ *lenp = -FDT_ERR_BADVERSION;
+ return NULL;
+ }
+
+ return fdt_get_property_by_offset_(fdt, offset, lenp);
+}
+
+static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
+ int offset,
+ const char *name,
+ int namelen,
+ int *lenp,
+ int *poffset)
{
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))) {
+ 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))
+ if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
+ name, namelen)) {
+ if (poffset)
+ *poffset = offset;
return prop;
+ }
}
if (lenp)
@@ -313,6 +449,25 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
return NULL;
}
+
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+ int offset,
+ const char *name,
+ int namelen, int *lenp)
+{
+ /* Prior to version 16, properties may need realignment
+ * and this API does not work. fdt_getprop_*() will, however. */
+ if (fdt_version(fdt) < 0x10) {
+ if (lenp)
+ *lenp = -FDT_ERR_BADVERSION;
+ return NULL;
+ }
+
+ return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
+ NULL);
+}
+
+
const struct fdt_property *fdt_get_property(const void *fdt,
int nodeoffset,
const char *name, int *lenp)
@@ -324,12 +479,18 @@ const struct fdt_property *fdt_get_property(const void *fdt,
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const char *name, int namelen, int *lenp)
{
+ int poffset;
const struct fdt_property *prop;
- prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
+ prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
+ &poffset);
if (!prop)
return NULL;
+ /* Handle realignment */
+ if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
+ fdt32_ld(&prop->len) >= 8)
+ return prop->data + 4;
return prop->data;
}
@@ -338,11 +499,26 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
{
const struct fdt_property *prop;
- prop = fdt_get_property_by_offset(fdt, offset, lenp);
+ prop = fdt_get_property_by_offset_(fdt, offset, lenp);
if (!prop)
return NULL;
- if (namep)
- *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+ if (namep) {
+ const char *name;
+ int namelen;
+ name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
+ &namelen);
+ if (!name) {
+ if (lenp)
+ *lenp = namelen;
+ return NULL;
+ }
+ *namep = name;
+ }
+
+ /* Handle realignment */
+ if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
+ fdt32_ld(&prop->len) >= 8)
+ return prop->data + 4;
return prop->data;
}
@@ -366,7 +542,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
return 0;
}
- return fdt32_to_cpu(*php);
+ return fdt32_ld(php);
}
const char *fdt_get_alias_namelen(const void *fdt,
@@ -392,7 +568,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
int offset, depth, namelen;
const char *name;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
if (buflen < 2)
return -FDT_ERR_NOSPACE;
@@ -444,7 +620,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
int offset, depth;
int supernodeoffset = -FDT_ERR_INTERNAL;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
if (supernodedepth < 0)
return -FDT_ERR_NOTFOUND;
@@ -503,7 +679,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const void *val;
int len;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_getprop(), then if that didn't
@@ -529,7 +705,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in
@@ -682,7 +858,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
{
int offset, err;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible(), then if
@@ -701,3 +877,66 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
return offset; /* error from fdt_next_node() */
}
+
+int fdt_check_full(const void *fdt, size_t bufsize)
+{
+ int err;
+ int num_memrsv;
+ int offset, nextoffset = 0;
+ uint32_t tag;
+ unsigned depth = 0;
+ const void *prop;
+ const char *propname;
+
+ if (bufsize < FDT_V1_SIZE) // 判断大小若小于 FDT_V1_SIZE, 则肯定出错
+ return -FDT_ERR_TRUNCATED;
+ err = fdt_check_header(fdt); // 检查 fdt 的头部信息
+ if (err != 0)
+ return err;
+ if (bufsize < fdt_totalsize(fdt)) // 总大小检查
+ return -FDT_ERR_TRUNCATED;
+
+ num_memrsv = fdt_num_mem_rsv(fdt); // 获取保留区域的数量
+ if (num_memrsv < 0)
+ return num_memrsv;
+
+ while (1) { // 循环检查数据区域是否符合标准
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ if (nextoffset < 0)
+ return nextoffset;
+
+ switch (tag) {
+ case FDT_NOP:
+ break;
+
+ case FDT_END:
+ if (depth != 0)
+ return -FDT_ERR_BADSTRUCTURE;
+ return 0;
+
+ case FDT_BEGIN_NODE:
+ depth++;
+ if (depth > INT_MAX)
+ return -FDT_ERR_BADSTRUCTURE;
+ break;
+
+ case FDT_END_NODE:
+ if (depth == 0)
+ return -FDT_ERR_BADSTRUCTURE;
+ depth--;
+ break;
+
+ case FDT_PROP:
+ prop = fdt_getprop_by_offset(fdt, offset, &propname,
+ &err);
+ if (!prop)
+ return err;
+ break;
+
+ default:
+ return -FDT_ERR_INTERNAL;
+ }
+ }
+}
diff --git a/SylixOS/driver/fdt/fdt_rw.c b/SylixOS/driver/fdt/fdt_rw.c
index 5c3a2bb..68e38a1 100644
--- a/SylixOS/driver/fdt/fdt_rw.c
+++ b/SylixOS/driver/fdt/fdt_rw.c
@@ -50,13 +50,13 @@
*/
#include "libfdt_env.h"
-#include <fdt.h>
-#include <libfdt.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)
+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) <
@@ -67,13 +67,13 @@ static int _fdt_blocks_misordered(const void *fdt,
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
}
-static int _fdt_rw_check_header(void *fdt)
+static int fdt_rw_probe_(void *fdt)
{
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
if (fdt_version(fdt) < 17)
return -FDT_ERR_BADVERSION;
- if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+ if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT;
if (fdt_version(fdt) > 17)
@@ -82,22 +82,22 @@ static int _fdt_rw_check_header(void *fdt)
return 0;
}
-#define FDT_RW_CHECK_HEADER(fdt) \
+#define FDT_RW_PROBE(fdt) \
{ \
- int __err; \
- if ((__err = _fdt_rw_check_header(fdt)) != 0) \
- return __err; \
+ int err_; \
+ if ((err_ = fdt_rw_probe_(fdt)) != 0) \
+ return err_; \
}
-static inline int _fdt_data_size(void *fdt)
+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)
+static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
{
char *p = splicepoint;
- char *end = (char *)fdt + _fdt_data_size(fdt);
+ char *end = (char *)fdt + fdt_data_size_(fdt);
if (((p + oldlen) < p) || ((p + oldlen) > end))
return -FDT_ERR_BADOFFSET;
@@ -109,12 +109,12 @@ static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
return 0;
}
-static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+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));
+ 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);
@@ -122,13 +122,13 @@ static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
return 0;
}
-static int _fdt_splice_struct(void *fdt, void *p,
+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)))
+ if ((err = fdt_splice_(fdt, p, oldlen, newlen)))
return err;
fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
@@ -136,20 +136,20 @@ static int _fdt_splice_struct(void *fdt, void *p,
return 0;
}
-static int _fdt_splice_string(void *fdt, int newlen)
+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)))
+ 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)
+static int fdt_find_add_string_(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
const char *p;
@@ -157,13 +157,13 @@ static int _fdt_find_add_string(void *fdt, const char *s)
int len = strlen(s) + 1;
int err;
- p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
+ 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);
+ err = fdt_splice_string_(fdt, len);
if (err)
return err;
@@ -176,10 +176,10 @@ 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);
+ FDT_RW_PROBE(fdt);
- re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
- err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
+ re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
+ err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
if (err)
return err;
@@ -190,17 +190,17 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
int fdt_del_mem_rsv(void *fdt, int n)
{
- struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+ struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
- FDT_RW_CHECK_HEADER(fdt);
+ FDT_RW_PROBE(fdt);
if (n >= fdt_num_mem_rsv(fdt))
return -FDT_ERR_NOTFOUND;
- return _fdt_splice_mem_rsv(fdt, re, 1, 0);
+ return fdt_splice_mem_rsv_(fdt, re, 1, 0);
}
-static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
+static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name,
int len, struct fdt_property **prop)
{
int oldlen;
@@ -210,7 +210,7 @@ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
if (!*prop)
return oldlen;
- if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
+ if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(len))))
return err;
@@ -218,7 +218,7 @@ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
return 0;
}
-static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
+static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
int len, struct fdt_property **prop)
{
int proplen;
@@ -226,17 +226,17 @@ static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
int namestroff;
int err;
- if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+ if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
return nextoffset;
- namestroff = _fdt_find_add_string(fdt, name);
+ namestroff = fdt_find_add_string_(fdt, name);
if (namestroff < 0)
return namestroff;
- *prop = _fdt_offset_ptr_w(fdt, nextoffset);
+ *prop = fdt_offset_ptr_w_(fdt, nextoffset);
proplen = sizeof(**prop) + FDT_TAGALIGN(len);
- err = _fdt_splice_struct(fdt, *prop, 0, proplen);
+ err = fdt_splice_struct_(fdt, *prop, 0, proplen);
if (err)
return err;
@@ -252,7 +252,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
int oldlen, newlen;
int err;
- FDT_RW_CHECK_HEADER(fdt);
+ FDT_RW_PROBE(fdt);
namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
if (!namep)
@@ -260,7 +260,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
newlen = strlen(name);
- err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
+ err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1),
FDT_TAGALIGN(newlen+1));
if (err)
return err;
@@ -275,11 +275,11 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
struct fdt_property *prop;
int err;
- FDT_RW_CHECK_HEADER(fdt);
+ FDT_RW_PROBE(fdt);
- err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
+ err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
if (err == -FDT_ERR_NOTFOUND)
- err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+ err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
@@ -308,12 +308,12 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
struct fdt_property *prop;
int err, oldlen, newlen;
- FDT_RW_CHECK_HEADER(fdt);
+ FDT_RW_PROBE(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (prop) {
newlen = len + oldlen;
- err = _fdt_splice_struct(fdt, prop->data,
+ err = fdt_splice_struct_(fdt, prop->data,
FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(newlen));
if (err)
@@ -321,7 +321,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
prop->len = cpu_to_fdt32(newlen);
memcpy(prop->data + oldlen, val, len);
} else {
- err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+ err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
memcpy(prop->data, val, len);
@@ -334,14 +334,14 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
struct fdt_property *prop;
int len, proplen;
- FDT_RW_CHECK_HEADER(fdt);
+ FDT_RW_PROBE(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);
+ return fdt_splice_struct_(fdt, prop, proplen, 0);
}
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
@@ -354,7 +354,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
uint32_t tag;
fdt32_t *endtag;
- FDT_RW_CHECK_HEADER(fdt);
+ FDT_RW_PROBE(fdt);
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
if (offset >= 0)
@@ -369,10 +369,10 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
tag = fdt_next_tag(fdt, offset, &nextoffset);
} while ((tag == FDT_PROP) || (tag == FDT_NOP));
- nh = _fdt_offset_ptr_w(fdt, offset);
+ nh = fdt_offset_ptr_w_(fdt, offset);
nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
- err = _fdt_splice_struct(fdt, nh, 0, nodelen);
+ err = fdt_splice_struct_(fdt, nh, 0, nodelen);
if (err)
return err;
@@ -394,17 +394,17 @@ int fdt_del_node(void *fdt, int nodeoffset)
{
int endoffset;
- FDT_RW_CHECK_HEADER(fdt);
+ FDT_RW_PROBE(fdt);
- endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+ endoffset = fdt_node_end_offset_(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;
- return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+ return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset),
endoffset - nodeoffset, 0);
}
-static void _fdt_packblocks(const char *old, char *new,
+static void fdt_packblocks_(const char *old, char *new,
int mem_rsv_size, int struct_size)
{
int mem_rsv_off, struct_off, strings_off;
@@ -435,7 +435,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
const char *fdtend = fdtstart + fdt_totalsize(fdt);
char *tmp;
- FDT_CHECK_HEADER(fdt);
+ FDT_RO_PROBE(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
@@ -450,7 +450,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return struct_size;
}
- if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+ if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
/* no further work necessary */
err = fdt_move(fdt, buf, bufsize);
if (err)
@@ -478,7 +478,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return -FDT_ERR_NOSPACE;
}
- _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
+ fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size);
memmove(buf, tmp, newsize);
fdt_set_magic(buf, FDT_MAGIC);
@@ -494,12 +494,12 @@ int fdt_pack(void *fdt)
{
int mem_rsv_size;
- FDT_RW_CHECK_HEADER(fdt);
+ FDT_RW_PROBE(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));
+ fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+ fdt_set_totalsize(fdt, fdt_data_size_(fdt));
return 0;
}
diff --git a/SylixOS/driver/fdt/fdt_strerror.c b/SylixOS/driver/fdt/fdt_strerror.c
index 9677a18..371d584 100644
--- a/SylixOS/driver/fdt/fdt_strerror.c
+++ b/SylixOS/driver/fdt/fdt_strerror.c
@@ -50,8 +50,8 @@
*/
#include "libfdt_env.h"
-#include <fdt.h>
-#include <libfdt.h>
+#include "fdt.h"
+#include "libfdt.h"
#include "libfdt_internal.h"
diff --git a/SylixOS/driver/fdt/fdt_support.h b/SylixOS/driver/fdt/fdt_support.h
new file mode 100644
index 0000000..2211305
--- /dev/null
+++ b/SylixOS/driver/fdt/fdt_support.h
@@ -0,0 +1,325 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2007
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
+ */
+
+#ifndef __FDT_SUPPORT_H
+#define __FDT_SUPPORT_H
+
+#ifdef SYLIXOS
+#define CONFIG_OF_LIBFDT
+typedef ULONG ulong;
+typedef UINT uint;
+#endif
+
+#ifdef CONFIG_OF_LIBFDT
+
+#ifndef SYLIXOS
+#include <linux/libfdt.h>
+#else
+#include "libfdt.h"
+#endif
+
+u32 fdt_getprop_u32_default_node(const void *fdt, int off, int cell,
+ const char *prop, const u32 dflt);
+u32 fdt_getprop_u32_default(const void *fdt, const char *path,
+ const char *prop, const u32 dflt);
+
+/**
+ * Add data to the root of the FDT before booting the OS.
+ *
+ * See doc/device-tree-bindings/root.txt
+ *
+ * @param fdt FDT address in memory
+ * @return 0 if ok, or -FDT_ERR_... on error
+ */
+int fdt_root(void *fdt);
+
+/**
+ * Add chosen data the FDT before booting the OS.
+ *
+ * In particular, this adds the kernel command line (bootargs) to the FDT.
+ *
+ * @param fdt FDT address in memory
+ * @return 0 if ok, or -FDT_ERR_... on error
+ */
+int fdt_chosen(void *fdt);
+
+/**
+ * Add initrd information to the FDT before booting the OS.
+ *
+ * @param fdt FDT address in memory
+ * @return 0 if ok, or -FDT_ERR_... on error
+ */
+int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end);
+
+void do_fixup_by_path(void *fdt, const char *path, const char *prop,
+ const void *val, int len, int create);
+void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop,
+ u32 val, int create);
+
+static inline void do_fixup_by_path_string(void *fdt, const char *path,
+ const char *prop, const char *status)
+{
+ do_fixup_by_path(fdt, path, prop, status, strlen(status) + 1, 1);
+}
+
+void do_fixup_by_prop(void *fdt,
+ const char *pname, const void *pval, int plen,
+ const char *prop, const void *val, int len,
+ int create);
+void do_fixup_by_prop_u32(void *fdt,
+ const char *pname, const void *pval, int plen,
+ const char *prop, u32 val, int create);
+void do_fixup_by_compat(void *fdt, const char *compat,
+ const char *prop, const void *val, int len, int create);
+void do_fixup_by_compat_u32(void *fdt, const char *compat,
+ const char *prop, u32 val, int create);
+/**
+ * Setup the memory node in the DT. Creates one if none was existing before.
+ * Calls fdt_fixup_memory_banks() to populate a single reg pair covering the
+ * whole memory.
+ *
+ * @param blob FDT blob to update
+ * @param start Begin of DRAM mapping in physical memory
+ * @param size Size of the single memory bank
+ * @return 0 if ok, or -1 or -FDT_ERR_... on error
+ */
+int fdt_fixup_memory(void *blob, u64 start, u64 size);
+
+/**
+ * Fill the DT memory node with multiple memory banks.
+ * Creates the node if none was existing before.
+ * If banks is 0, it will not touch the existing reg property. This allows
+ * boards to not mess with the existing DT setup, which may have been
+ * filled in properly before.
+ *
+ * @param blob FDT blob to update
+ * @param start Array of size <banks> to hold the start addresses.
+ * @param size Array of size <banks> to hold the size of each region.
+ * @param banks Number of memory banks to create. If 0, the reg
+ * property will be left untouched.
+ * @return 0 if ok, or -1 or -FDT_ERR_... on error
+ */
+#ifdef CONFIG_ARCH_FIXUP_FDT_MEMORY
+int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks);
+#else
+static inline int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[],
+ int banks)
+{
+ return 0;
+}
+#endif
+
+void fdt_fixup_ethernet(void *fdt);
+int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
+ const void *val, int len, int create);
+void fdt_fixup_qe_firmware(void *fdt);
+
+/**
+ * Update native-mode property of display-timings node to the phandle
+ * of the timings matching a display by name (case insensitive).
+ *
+ * see kernel Documentation/devicetree/bindings/video/display-timing.txt
+ *
+ * @param blob FDT blob to update
+ * @param path path within dt
+ * @param display name of display timing to match
+ * @return 0 if ok, or -FDT_ERR_... on error
+ */
+int fdt_fixup_display(void *blob, const char *path, const char *display);
+#ifndef SYLIXOS
+#if defined(CONFIG_USB_EHCI_FSL) || defined(CONFIG_USB_XHCI_FSL)
+void fsl_fdt_fixup_dr_usb(void *blob, bd_t *bd);
+#else
+static inline void fsl_fdt_fixup_dr_usb(void *blob, bd_t *bd) {}
+#endif /* defined(CONFIG_USB_EHCI_FSL) || defined(CONFIG_USB_XHCI_FSL) */
+#endif
+
+#if defined(CONFIG_SYS_FSL_SEC_COMPAT)
+void fdt_fixup_crypto_node(void *blob, int sec_rev);
+#else
+static inline void fdt_fixup_crypto_node(void *blob, int sec_rev) {}
+#endif
+
+/**
+ * Record information about a processed loadable in /fit-images (creating
+ * /fit-images if necessary).
+ *
+ * @param blob FDT blob to update
+ * @param index index of this loadable
+ * @param name name of the loadable
+ * @param load_addr address the loadable was loaded to
+ * @param size number of bytes loaded
+ * @param entry_point entry point (if specified, otherwise pass -1)
+ * @param type type (if specified, otherwise pass NULL)
+ * @param os os-type (if specified, otherwise pass NULL)
+ * @return 0 if ok, or -1 or -FDT_ERR_... on error
+ */
+int fdt_record_loadable(void *blob, u32 index, const char *name,
+ uintptr_t load_addr, u32 size, uintptr_t entry_point,
+ const char *type, const char *os);
+
+#ifdef CONFIG_PCI
+#include <pci.h>
+int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose);
+#endif
+
+int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name);
+
+#ifndef SYLIXOS
+/**
+ * Add board-specific data to the FDT before booting the OS.
+ *
+ * Use CONFIG_SYS_FDT_PAD to ensure there is sufficient space.
+ * This function is called if CONFIG_OF_BOARD_SETUP is defined
+ *
+ * @param blob FDT blob to update
+ * @param bd_t Pointer to board data
+ * @return 0 if ok, or -FDT_ERR_... on error
+ */
+int ft_board_setup(void *blob, bd_t *bd);
+/*
+ * The keystone2 SOC requires all 32 bit aliased addresses to be converted
+ * to their 36 physical format. This has to happen after all fdt nodes
+ * are added or modified by the image_setup_libfdt(). The ft_board_setup_ex()
+ * called at the end of the image_setup_libfdt() is to do that convertion.
+ */
+void ft_board_setup_ex(void *blob, bd_t *bd);
+void ft_cpu_setup(void *blob, bd_t *bd);
+void ft_pci_setup(void *blob, bd_t *bd);
+
+/**
+ * Add system-specific data to the FDT before booting the OS.
+ *
+ * Use CONFIG_SYS_FDT_PAD to ensure there is sufficient space.
+ * This function is called if CONFIG_OF_SYSTEM_SETUP is defined
+ *
+ * @param blob FDT blob to update
+ * @param bd_t Pointer to board data
+ * @return 0 if ok, or -FDT_ERR_... on error
+ */
+int ft_system_setup(void *blob, bd_t *bd);
+#endif
+
+void set_working_fdt_addr(ulong addr);
+
+/**
+ * shrink down the given blob to minimum size + some extrasize if required
+ *
+ * @param blob FDT blob to update
+ * @param extrasize additional bytes needed
+ * @return 0 if ok, or -FDT_ERR_... on error
+ */
+int fdt_shrink_to_minimum(void *blob, uint extrasize);
+int fdt_increase_size(void *fdt, int add_len);
+
+int fdt_fixup_nor_flash_size(void *blob);
+
+struct node_info;
+#if defined(CONFIG_FDT_FIXUP_PARTITIONS)
+void fdt_fixup_mtdparts(void *fdt, const struct node_info *node_info,
+ int node_info_size);
+#else
+static inline void fdt_fixup_mtdparts(void *fdt,
+ const struct node_info *node_info,
+ int node_info_size)
+{
+}
+#endif
+
+void fdt_del_node_and_alias(void *blob, const char *alias);
+u64 fdt_translate_address(const void *blob, int node_offset,
+ const __be32 *in_addr);
+int fdt_node_offset_by_compat_reg(void *blob, const char *compat,
+ phys_addr_t compat_off);
+int fdt_alloc_phandle(void *blob);
+int fdt_set_phandle(void *fdt, int nodeoffset, uint32_t phandle);
+unsigned int fdt_create_phandle(void *fdt, int nodeoffset);
+int fdt_add_edid(void *blob, const char *compat, unsigned char *buf);
+
+int fdt_verify_alias_address(void *fdt, int anode, const char *alias,
+ u64 addr);
+u64 fdt_get_base_address(const void *fdt, int node);
+int fdt_read_range(void *fdt, int node, int n, uint64_t *child_addr,
+ uint64_t *addr, uint64_t *len);
+
+enum fdt_status {
+ FDT_STATUS_OKAY,
+ FDT_STATUS_DISABLED,
+ FDT_STATUS_FAIL,
+ FDT_STATUS_FAIL_ERROR_CODE,
+};
+int fdt_set_node_status(void *fdt, int nodeoffset,
+ enum fdt_status status, unsigned int error_code);
+static inline int fdt_status_okay(void *fdt, int nodeoffset)
+{
+ return fdt_set_node_status(fdt, nodeoffset, FDT_STATUS_OKAY, 0);
+}
+static inline int fdt_status_disabled(void *fdt, int nodeoffset)
+{
+ return fdt_set_node_status(fdt, nodeoffset, FDT_STATUS_DISABLED, 0);
+}
+static inline int fdt_status_fail(void *fdt, int nodeoffset)
+{
+ return fdt_set_node_status(fdt, nodeoffset, FDT_STATUS_FAIL, 0);
+}
+
+int fdt_set_status_by_alias(void *fdt, const char *alias,
+ enum fdt_status status, unsigned int error_code);
+static inline int fdt_status_okay_by_alias(void *fdt, const char *alias)
+{
+ return fdt_set_status_by_alias(fdt, alias, FDT_STATUS_OKAY, 0);
+}
+static inline int fdt_status_disabled_by_alias(void *fdt, const char *alias)
+{
+ return fdt_set_status_by_alias(fdt, alias, FDT_STATUS_DISABLED, 0);
+}
+static inline int fdt_status_fail_by_alias(void *fdt, const char *alias)
+{
+ return fdt_set_status_by_alias(fdt, alias, FDT_STATUS_FAIL, 0);
+}
+
+/* Helper to read a big number; size is in cells (not bytes) */
+static inline u64 fdt_read_number(const fdt32_t *cell, int size)
+{
+ u64 r = 0;
+ while (size--)
+ r = (r << 32) | fdt32_to_cpu(*(cell++));
+ return r;
+}
+
+void fdt_support_default_count_cells(const void *blob, int parentoffset,
+ int *addrc, int *sizec);
+int ft_verify_fdt(void *fdt);
+int arch_fixup_memory_node(void *blob);
+
+int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
+ u32 height, u32 stride, const char *format);
+
+int fdt_overlay_apply_verbose(void *fdt, void *fdto);
+
+/**
+ * fdt_get_cells_len() - Get the length of a type of cell in top-level nodes
+ *
+ * Returns the length of the cell type in bytes (4 or 8).
+ *
+ * @blob: Pointer to device tree blob
+ * @nr_cells_name: Name to lookup, e.g. "#address-cells"
+ */
+int fdt_get_cells_len(const void *blob, char *nr_cells_name);
+
+#endif /* ifdef CONFIG_OF_LIBFDT */
+
+#ifdef USE_HOSTCC
+int fdtdec_get_int(const void *blob, int node, const char *prop_name,
+ int default_val);
+#endif
+#ifdef CONFIG_FMAN_ENET
+int fdt_update_ethernet_dt(void *blob);
+#endif
+#ifdef CONFIG_FSL_MC_ENET
+void fdt_fixup_board_enet(void *blob);
+#endif
+#endif /* ifndef __FDT_SUPPORT_H */
diff --git a/SylixOS/driver/fdt/fdt_sw.c b/SylixOS/driver/fdt/fdt_sw.c
index 2bd15e7..7befb2b 100644
--- a/SylixOS/driver/fdt/fdt_sw.c
+++ b/SylixOS/driver/fdt/fdt_sw.c
@@ -50,27 +50,83 @@
*/
#include "libfdt_env.h"
-#include <fdt.h>
-#include <libfdt.h>
+#include "fdt.h"
+#include "libfdt.h"
#include "libfdt_internal.h"
-static int _fdt_sw_check_header(void *fdt)
+static int fdt_sw_probe_(void *fdt)
{
- if (fdt_magic(fdt) != FDT_SW_MAGIC)
+ if (fdt_magic(fdt) == FDT_MAGIC)
+ return -FDT_ERR_BADSTATE;
+ else 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) \
+#define FDT_SW_PROBE(fdt) \
+ { \
+ int err; \
+ if ((err = fdt_sw_probe_(fdt)) != 0) \
+ return err; \
+ }
+
+/* 'memrsv' state: Initial state after fdt_create()
+ *
+ * Allowed functions:
+ * fdt_add_reservmap_entry()
+ * fdt_finish_reservemap() [moves to 'struct' state]
+ */
+static int fdt_sw_probe_memrsv_(void *fdt)
+{
+ int err = fdt_sw_probe_(fdt);
+ if (err)
+ return err;
+
+ if (fdt_off_dt_strings(fdt) != 0)
+ return -FDT_ERR_BADSTATE;
+ return 0;
+}
+
+#define FDT_SW_PROBE_MEMRSV(fdt) \
+ { \
+ int err; \
+ if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
+ return err; \
+ }
+
+/* 'struct' state: Enter this state after fdt_finish_reservemap()
+ *
+ * Allowed functions:
+ * fdt_begin_node()
+ * fdt_end_node()
+ * fdt_property*()
+ * fdt_finish() [moves to 'complete' state]
+ */
+static int fdt_sw_probe_struct_(void *fdt)
+{
+ int err = fdt_sw_probe_(fdt);
+ if (err)
+ return err;
+
+ if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
+ return -FDT_ERR_BADSTATE;
+ return 0;
+}
+
+#define FDT_SW_PROBE_STRUCT(fdt) \
{ \
int err; \
- if ((err = _fdt_sw_check_header(fdt)) != 0) \
+ if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
return err; \
}
-static void *_fdt_grab_space(void *fdt, size_t len)
+/* 'complete' state: Enter this state after fdt_finish()
+ *
+ * Allowed functions: none
+ */
+
+static void *fdt_grab_space_(void *fdt, size_t len)
{
int offset = fdt_size_dt_struct(fdt);
int spaceleft;
@@ -82,14 +138,16 @@ static void *_fdt_grab_space(void *fdt, size_t len)
return NULL;
fdt_set_size_dt_struct(fdt, offset + len);
- return _fdt_offset_ptr_w(fdt, offset);
+ return fdt_offset_ptr_w_(fdt, offset);
}
int fdt_create(void *buf, int bufsize)
{
+ const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
+ sizeof(struct fdt_reserve_entry));
void *fdt = buf;
- if (bufsize < sizeof(struct fdt_header))
+ if (bufsize < hdrsize)
return -FDT_ERR_NOSPACE;
memset(buf, 0, bufsize);
@@ -99,10 +157,9 @@ int fdt_create(void *buf, int bufsize)
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_mem_rsvmap(fdt, hdrsize);
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
- fdt_set_off_dt_strings(fdt, bufsize);
+ fdt_set_off_dt_strings(fdt, 0);
return 0;
}
@@ -112,11 +169,14 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
size_t headsize, tailsize;
char *oldtail, *newtail;
- FDT_SW_CHECK_HEADER(fdt);
+ FDT_SW_PROBE(fdt);
- headsize = fdt_off_dt_struct(fdt);
+ headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
tailsize = fdt_size_dt_strings(fdt);
+ if ((headsize + tailsize) > fdt_totalsize(fdt))
+ return -FDT_ERR_INTERNAL;
+
if ((headsize + tailsize) > bufsize)
return -FDT_ERR_NOSPACE;
@@ -133,8 +193,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
memmove(buf, fdt, headsize);
}
- fdt_set_off_dt_strings(buf, bufsize);
fdt_set_totalsize(buf, bufsize);
+ if (fdt_off_dt_strings(buf))
+ fdt_set_off_dt_strings(buf, bufsize);
return 0;
}
@@ -144,10 +205,7 @@ 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;
+ FDT_SW_PROBE_MEMRSV(fdt);
offset = fdt_off_dt_struct(fdt);
if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
@@ -164,17 +222,24 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
int fdt_finish_reservemap(void *fdt)
{
- return fdt_add_reservemap_entry(fdt, 0, 0);
+ int err = fdt_add_reservemap_entry(fdt, 0, 0);
+
+ if (err)
+ return err;
+
+ fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
+ return 0;
}
int fdt_begin_node(void *fdt, const char *name)
{
struct fdt_node_header *nh;
- int namelen = strlen(name) + 1;
+ int namelen;
- FDT_SW_CHECK_HEADER(fdt);
+ FDT_SW_PROBE_STRUCT(fdt);
- nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
+ namelen = strlen(name) + 1;
+ nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
if (! nh)
return -FDT_ERR_NOSPACE;
@@ -187,9 +252,9 @@ int fdt_end_node(void *fdt)
{
fdt32_t *en;
- FDT_SW_CHECK_HEADER(fdt);
+ FDT_SW_PROBE_STRUCT(fdt);
- en = _fdt_grab_space(fdt, FDT_TAGSIZE);
+ en = fdt_grab_space_(fdt, FDT_TAGSIZE);
if (! en)
return -FDT_ERR_NOSPACE;
@@ -197,7 +262,7 @@ int fdt_end_node(void *fdt)
return 0;
}
-static int _fdt_find_add_string(void *fdt, const char *s)
+static int fdt_find_add_string_(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
const char *p;
@@ -205,7 +270,7 @@ static int _fdt_find_add_string(void *fdt, const char *s)
int len = strlen(s) + 1;
int struct_top, offset;
- p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
+ p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
if (p)
return p - strtab;
@@ -225,13 +290,13 @@ int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
struct fdt_property *prop;
int nameoff;
- FDT_SW_CHECK_HEADER(fdt);
+ FDT_SW_PROBE_STRUCT(fdt);
- nameoff = _fdt_find_add_string(fdt, name);
+ nameoff = fdt_find_add_string_(fdt, name);
if (nameoff == 0)
return -FDT_ERR_NOSPACE;
- prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
+ prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
if (! prop)
return -FDT_ERR_NOSPACE;
@@ -262,10 +327,10 @@ int fdt_finish(void *fdt)
uint32_t tag;
int offset, nextoffset;
- FDT_SW_CHECK_HEADER(fdt);
+ FDT_SW_PROBE_STRUCT(fdt);
/* Add terminator */
- end = _fdt_grab_space(fdt, sizeof(*end));
+ end = fdt_grab_space_(fdt, sizeof(*end));
if (! end)
return -FDT_ERR_NOSPACE;
*end = cpu_to_fdt32(FDT_END);
@@ -281,7 +346,7 @@ int fdt_finish(void *fdt)
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
if (tag == FDT_PROP) {
struct fdt_property *prop =
- _fdt_offset_ptr_w(fdt, offset);
+ fdt_offset_ptr_w_(fdt, offset);
int nameoff;
nameoff = fdt32_to_cpu(prop->nameoff);
diff --git a/SylixOS/driver/fdt/fdt_wip.c b/SylixOS/driver/fdt/fdt_wip.c
index 5e85919..589d6be 100644
--- a/SylixOS/driver/fdt/fdt_wip.c
+++ b/SylixOS/driver/fdt/fdt_wip.c
@@ -50,8 +50,8 @@
*/
#include "libfdt_env.h"
-#include <fdt.h>
-#include <libfdt.h>
+#include "fdt.h"
+#include "libfdt.h"
#include "libfdt_internal.h"
@@ -93,7 +93,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
val, len);
}
-static void _fdt_nop_region(void *start, int len)
+static void fdt_nop_region_(void *start, int len)
{
fdt32_t *p;
@@ -110,12 +110,12 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
if (!prop)
return len;
- _fdt_nop_region(prop, len + sizeof(*prop));
+ fdt_nop_region_(prop, len + sizeof(*prop));
return 0;
}
-int _fdt_node_end_offset(void *fdt, int offset)
+int fdt_node_end_offset_(void *fdt, int offset)
{
int depth = 0;
@@ -129,11 +129,11 @@ int fdt_nop_node(void *fdt, int nodeoffset)
{
int endoffset;
- endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+ endoffset = fdt_node_end_offset_(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;
- _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
+ fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0),
endoffset - nodeoffset);
return 0;
}
diff --git a/SylixOS/driver/fdt/fdtdec.c b/SylixOS/driver/fdt/fdtdec.c
new file mode 100644
index 0000000..4cc6e3f
--- /dev/null
+++ b/SylixOS/driver/fdt/fdtdec.c
@@ -0,0 +1,1488 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ */
+
+#ifndef USE_HOSTCC
+#ifndef SYLIXOS
+#include <common.h>
+#include <boot_fit.h>
+#include <dm.h>
+#include <dm/of_extra.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <fdt_support.h>
+#include <mapmem.h>
+#include <linux/libfdt.h>
+#include <serial.h>
+#include <asm/sections.h>
+#include <linux/ctype.h>
+#include <linux/lzo.h>
+#else
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_STDIO
+#include <SylixOS.h>
+#include <linux/compat.h>
+#include "fdtdec.h"
+#include "fdt_support.h"
+
+#define be32_to_cpup(x) x
+#define simple_strtoul lib_strtoul
+#define trailing_strtol lib_atol
+#define debug printk
+#define assert(x)
+#endif
+
+#ifndef SYLIXOS
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+/*
+ * Here are the type we know about. One day we might allow drivers to
+ * register. For now we just put them here. The COMPAT macro allows us to
+ * turn this into a sparse list later, and keeps the ID with the name.
+ *
+ * NOTE: This list is basically a TODO list for things that need to be
+ * converted to driver model. So don't add new things here unless there is a
+ * good reason why driver-model conversion is infeasible. Examples include
+ * things which are used before driver model is available.
+ */
+#define COMPAT(id, name) name
+static const char * const compat_names[COMPAT_COUNT] = {
+ COMPAT(UNKNOWN, "<none>"),
+ COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"),
+ COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"),
+ COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"),
+ COMPAT(NVIDIA_TEGRA124_XUSB_PADCTL, "nvidia,tegra124-xusb-padctl"),
+ COMPAT(NVIDIA_TEGRA210_XUSB_PADCTL, "nvidia,tegra210-xusb-padctl"),
+ COMPAT(SMSC_LAN9215, "smsc,lan9215"),
+ COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"),
+ COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
+ COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"),
+ COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
+ COMPAT(SAMSUNG_EXYNOS_MIPI_DSI, "samsung,exynos-mipi-dsi"),
+ COMPAT(SAMSUNG_EXYNOS_DWMMC, "samsung,exynos-dwmmc"),
+ COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
+ COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"),
+ COMPAT(INTEL_MICROCODE, "intel,microcode"),
+ COMPAT(INTEL_QRK_MRC, "intel,quark-mrc"),
+ COMPAT(ALTERA_SOCFPGA_DWMAC, "altr,socfpga-stmmac"),
+ COMPAT(ALTERA_SOCFPGA_DWMMC, "altr,socfpga-dw-mshc"),
+ COMPAT(ALTERA_SOCFPGA_DWC2USB, "snps,dwc2"),
+ COMPAT(INTEL_BAYTRAIL_FSP, "intel,baytrail-fsp"),
+ COMPAT(INTEL_BAYTRAIL_FSP_MDP, "intel,baytrail-fsp-mdp"),
+ COMPAT(INTEL_IVYBRIDGE_FSP, "intel,ivybridge-fsp"),
+ COMPAT(COMPAT_SUNXI_NAND, "allwinner,sun4i-a10-nand"),
+ COMPAT(ALTERA_SOCFPGA_CLK, "altr,clk-mgr"),
+ COMPAT(ALTERA_SOCFPGA_PINCTRL_SINGLE, "pinctrl-single"),
+ COMPAT(ALTERA_SOCFPGA_H2F_BRG, "altr,socfpga-hps2fpga-bridge"),
+ COMPAT(ALTERA_SOCFPGA_LWH2F_BRG, "altr,socfpga-lwhps2fpga-bridge"),
+ COMPAT(ALTERA_SOCFPGA_F2H_BRG, "altr,socfpga-fpga2hps-bridge"),
+ COMPAT(ALTERA_SOCFPGA_F2SDR0, "altr,socfpga-fpga2sdram0-bridge"),
+ COMPAT(ALTERA_SOCFPGA_F2SDR1, "altr,socfpga-fpga2sdram1-bridge"),
+ COMPAT(ALTERA_SOCFPGA_F2SDR2, "altr,socfpga-fpga2sdram2-bridge"),
+ COMPAT(ALTERA_SOCFPGA_FPGA0, "altr,socfpga-a10-fpga-mgr"),
+ COMPAT(ALTERA_SOCFPGA_NOC, "altr,socfpga-a10-noc"),
+ COMPAT(ALTERA_SOCFPGA_CLK_INIT, "altr,socfpga-a10-clk-init")
+};
+
+const char *fdtdec_get_compatible(enum fdt_compat_id id)
+{
+ /* We allow reading of the 'unknown' ID for testing purposes */
+ assert(id >= 0 && id < COMPAT_COUNT);
+ return compat_names[id];
+}
+
+fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node,
+ const char *prop_name, int index, int na,
+ int ns, fdt_size_t *sizep,
+ bool translate)
+{
+ const fdt32_t *prop, *prop_end;
+ const fdt32_t *prop_addr, *prop_size, *prop_after_size;
+ int len;
+ fdt_addr_t addr;
+
+ debug("%s: %s: ", __func__, prop_name);
+
+ prop = fdt_getprop(blob, node, prop_name, &len);
+ if (!prop) {
+ debug("(not found)\n");
+ return FDT_ADDR_T_NONE;
+ }
+ prop_end = prop + (len / sizeof(*prop));
+
+ prop_addr = prop + (index * (na + ns));
+ prop_size = prop_addr + na;
+ prop_after_size = prop_size + ns;
+ if (prop_after_size > prop_end) {
+ debug("(not enough data: expected >= %d cells, got %d cells)\n",
+ (u32)(prop_after_size - prop), ((u32)(prop_end - prop)));
+ return FDT_ADDR_T_NONE;
+ }
+
+#ifndef SYLIXOS
+#if CONFIG_IS_ENABLED(OF_TRANSLATE)
+ if (translate)
+ addr = fdt_translate_address(blob, node, prop_addr);
+ else
+#endif
+#endif
+ addr = fdtdec_get_number(prop_addr, na);
+
+ if (sizep) {
+ *sizep = fdtdec_get_number(prop_size, ns);
+ debug("addr=%08llx, size=%llx\n", (unsigned long long)addr,
+ (unsigned long long)*sizep);
+ } else {
+ debug("addr=%08llx\n", (unsigned long long)addr);
+ }
+
+ return addr;
+}
+
+fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent,
+ int node, const char *prop_name,
+ int index, fdt_size_t *sizep,
+ bool translate)
+{
+ int na, ns;
+
+ debug("%s: ", __func__);
+
+ na = fdt_address_cells(blob, parent);
+ if (na < 1) {
+ debug("(bad #address-cells)\n");
+ return FDT_ADDR_T_NONE;
+ }
+
+ ns = fdt_size_cells(blob, parent);
+ if (ns < 0) {
+ debug("(bad #size-cells)\n");
+ return FDT_ADDR_T_NONE;
+ }
+
+ debug("na=%d, ns=%d, ", na, ns);
+
+ return fdtdec_get_addr_size_fixed(blob, node, prop_name, index, na,
+ ns, sizep, translate);
+}
+
+fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node,
+ const char *prop_name, int index,
+ fdt_size_t *sizep,
+ bool translate)
+{
+ int parent;
+
+ debug("%s: ", __func__);
+
+ parent = fdt_parent_offset(blob, node);
+ if (parent < 0) {
+ debug("(no parent found)\n");
+ return FDT_ADDR_T_NONE;
+ }
+
+ return fdtdec_get_addr_size_auto_parent(blob, parent, node, prop_name,
+ index, sizep, translate);
+}
+
+fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
+ const char *prop_name, fdt_size_t *sizep)
+{
+ int ns = sizep ? (sizeof(fdt_size_t) / sizeof(fdt32_t)) : 0;
+
+ return fdtdec_get_addr_size_fixed(blob, node, prop_name, 0,
+ sizeof(fdt_addr_t) / sizeof(fdt32_t),
+ ns, sizep, false);
+}
+
+fdt_addr_t fdtdec_get_addr(const void *blob, int node, const char *prop_name)
+{
+ return fdtdec_get_addr_size(blob, node, prop_name, NULL);
+}
+
+#ifndef SYLIXOS
+#if CONFIG_IS_ENABLED(PCI) && defined(CONFIG_DM_PCI)
+int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type,
+ const char *prop_name, struct fdt_pci_addr *addr)
+{
+ const u32 *cell;
+ int len;
+ int ret = -ENOENT;
+
+ debug("%s: %s: ", __func__, prop_name);
+
+ /*
+ * If we follow the pci bus bindings strictly, we should check
+ * the value of the node's parent node's #address-cells and
+ * #size-cells. They need to be 3 and 2 accordingly. However,
+ * for simplicity we skip the check here.
+ */
+ cell = fdt_getprop(blob, node, prop_name, &len);
+ if (!cell)
+ goto fail;
+
+ if ((len % FDT_PCI_REG_SIZE) == 0) {
+ int num = len / FDT_PCI_REG_SIZE;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ debug("pci address #%d: %08lx %08lx %08lx\n", i,
+ (ulong)fdt32_to_cpu(cell[0]),
+ (ulong)fdt32_to_cpu(cell[1]),
+ (ulong)fdt32_to_cpu(cell[2]));
+ if ((fdt32_to_cpu(*cell) & type) == type) {
+ addr->phys_hi = fdt32_to_cpu(cell[0]);
+ addr->phys_mid = fdt32_to_cpu(cell[1]);
+ addr->phys_lo = fdt32_to_cpu(cell[1]);
+ break;
+ }
+
+ cell += (FDT_PCI_ADDR_CELLS +
+ FDT_PCI_SIZE_CELLS);
+ }
+
+ if (i == num) {
+ ret = -ENXIO;
+ goto fail;
+ }
+
+ return 0;
+ }
+
+ ret = -EINVAL;
+
+fail:
+ debug("(not found)\n");
+ return ret;
+}
+
+int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device)
+{
+ const char *list, *end;
+ int len;
+
+ list = fdt_getprop(blob, node, "compatible", &len);
+ if (!list)
+ return -ENOENT;
+
+ end = list + len;
+ while (list < end) {
+ len = strlen(list);
+ if (len >= strlen("pciVVVV,DDDD")) {
+ char *s = strstr(list, "pci");
+
+ /*
+ * check if the string is something like pciVVVV,DDDD.RR
+ * or just pciVVVV,DDDD
+ */
+ if (s && s[7] == ',' &&
+ (s[12] == '.' || s[12] == 0)) {
+ s += 3;
+ *vendor = simple_strtol(s, NULL, 16);
+
+ s += 5;
+ *device = simple_strtol(s, NULL, 16);
+
+ return 0;
+ }
+ }
+ list += (len + 1);
+ }
+
+ return -ENOENT;
+}
+
+int fdtdec_get_pci_bar32(struct udevice *dev, struct fdt_pci_addr *addr,
+ u32 *bar)
+{
+ int barnum;
+
+ /* extract the bar number from fdt_pci_addr */
+ barnum = addr->phys_hi & 0xff;
+ if (barnum < PCI_BASE_ADDRESS_0 || barnum > PCI_CARDBUS_CIS)
+ return -EINVAL;
+
+ barnum = (barnum - PCI_BASE_ADDRESS_0) / 4;
+ *bar = dm_pci_read_bar32(dev, barnum);
+
+ return 0;
+}
+#endif
+#endif
+
+uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
+ uint64_t default_val)
+{
+ const uint64_t *cell64;
+ int length;
+
+ cell64 = fdt_getprop(blob, node, prop_name, &length);
+ if (!cell64 || length < sizeof(*cell64))
+ return default_val;
+
+ return fdt64_to_cpu(*cell64);
+}
+
+int fdtdec_get_is_enabled(const void *blob, int node)
+{
+ const char *cell;
+
+ /*
+ * It should say "okay", so only allow that. Some fdts use "ok" but
+ * this is a bug. Please fix your device tree source file. See here
+ * for discussion:
+ *
+ * http://www.mail-archive.com/u-boot@lists.denx.de/msg71598.html
+ */
+ cell = fdt_getprop(blob, node, "status", NULL);
+ if (cell)
+ return strcmp(cell, "okay") == 0;
+ return 1;
+}
+
+enum fdt_compat_id fdtdec_lookup(const void *blob, int node)
+{
+ enum fdt_compat_id id;
+
+ /* Search our drivers */
+ for (id = COMPAT_UNKNOWN; id < COMPAT_COUNT; id++)
+ if (fdt_node_check_compatible(blob, node,
+ compat_names[id]) == 0)
+ return id;
+ return COMPAT_UNKNOWN;
+}
+
+int fdtdec_next_compatible(const void *blob, int node, enum fdt_compat_id id)
+{
+ return fdt_node_offset_by_compatible(blob, node, compat_names[id]);
+}
+
+int fdtdec_next_compatible_subnode(const void *blob, int node,
+ enum fdt_compat_id id, int *depthp)
+{
+ do {
+ node = fdt_next_node(blob, node, depthp);
+ } while (*depthp > 1);
+
+ /* If this is a direct subnode, and compatible, return it */
+ if (*depthp == 1 && 0 == fdt_node_check_compatible(
+ blob, node, compat_names[id]))
+ return node;
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+int fdtdec_next_alias(const void *blob, const char *name, enum fdt_compat_id id,
+ int *upto)
+{
+#define MAX_STR_LEN 20
+ char str[MAX_STR_LEN + 20];
+ int node, err;
+
+ /* snprintf() is not available */
+ assert(strlen(name) < MAX_STR_LEN);
+ sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto);
+ node = fdt_path_offset(blob, str);
+ if (node < 0)
+ return node;
+ err = fdt_node_check_compatible(blob, node, compat_names[id]);
+ if (err < 0)
+ return err;
+ if (err)
+ return -FDT_ERR_NOTFOUND;
+ (*upto)++;
+ return node;
+}
+
+int fdtdec_find_aliases_for_id(const void *blob, const char *name,
+ enum fdt_compat_id id, int *node_list,
+ int maxcount)
+{
+ memset(node_list, '\0', sizeof(*node_list) * maxcount);
+
+ return fdtdec_add_aliases_for_id(blob, name, id, node_list, maxcount);
+}
+
+/* TODO: Can we tighten this code up a little? */
+int fdtdec_add_aliases_for_id(const void *blob, const char *name,
+ enum fdt_compat_id id, int *node_list,
+ int maxcount)
+{
+ int name_len = strlen(name);
+ int nodes[maxcount];
+ int num_found = 0;
+ int offset, node;
+ int alias_node;
+ int count;
+ int i, j;
+
+ /* find the alias node if present */
+ alias_node = fdt_path_offset(blob, "/aliases");
+
+ /*
+ * start with nothing, and we can assume that the root node can't
+ * match
+ */
+ memset(nodes, '\0', sizeof(nodes));
+
+ /* First find all the compatible nodes */
+ for (node = count = 0; node >= 0 && count < maxcount;) {
+ node = fdtdec_next_compatible(blob, node, id);
+ if (node >= 0)
+ nodes[count++] = node;
+ }
+ if (node >= 0)
+ debug("%s: warning: maxcount exceeded with alias '%s'\n",
+ __func__, name);
+
+ /* Now find all the aliases */
+ for (offset = fdt_first_property_offset(blob, alias_node);
+ offset > 0;
+ offset = fdt_next_property_offset(blob, offset)) {
+ const struct fdt_property *prop;
+ const char *path;
+ int number;
+ int found;
+
+ node = 0;
+ prop = fdt_get_property_by_offset(blob, offset, NULL);
+ path = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
+ if (prop->len && 0 == strncmp(path, name, name_len))
+ node = fdt_path_offset(blob, prop->data);
+ if (node <= 0)
+ continue;
+
+ /* Get the alias number */
+ number = simple_strtoul(path + name_len, NULL, 10);
+ if (number < 0 || number >= maxcount) {
+ debug("%s: warning: alias '%s' is out of range\n",
+ __func__, path);
+ continue;
+ }
+
+ /* Make sure the node we found is actually in our list! */
+ found = -1;
+ for (j = 0; j < count; j++)
+ if (nodes[j] == node) {
+ found = j;
+ break;
+ }
+
+ if (found == -1) {
+ debug("%s: warning: alias '%s' points to a node "
+ "'%s' that is missing or is not compatible "
+ " with '%s'\n", __func__, path,
+ fdt_get_name(blob, node, NULL),
+ compat_names[id]);
+ continue;
+ }
+
+ /*
+ * Add this node to our list in the right place, and mark
+ * it as done.
+ */
+ if (fdtdec_get_is_enabled(blob, node)) {
+ if (node_list[number]) {
+ debug("%s: warning: alias '%s' requires that "
+ "a node be placed in the list in a "
+ "position which is already filled by "
+ "node '%s'\n", __func__, path,
+ fdt_get_name(blob, node, NULL));
+ continue;
+ }
+ node_list[number] = node;
+ if (number >= num_found)
+ num_found = number + 1;
+ }
+ nodes[found] = 0;
+ }
+
+ /* Add any nodes not mentioned by an alias */
+ for (i = j = 0; i < maxcount; i++) {
+ if (!node_list[i]) {
+ for (; j < maxcount; j++)
+ if (nodes[j] &&
+ fdtdec_get_is_enabled(blob, nodes[j]))
+ break;
+
+ /* Have we run out of nodes to add? */
+ if (j == maxcount)
+ break;
+
+ assert(!node_list[i]);
+ node_list[i] = nodes[j++];
+ if (i >= num_found)
+ num_found = i + 1;
+ }
+ }
+
+ return num_found;
+}
+
+int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
+ int *seqp)
+{
+ int base_len = strlen(base);
+ const char *find_name;
+ int find_namelen;
+ int prop_offset;
+ int aliases;
+
+ find_name = fdt_get_name(blob, offset, &find_namelen);
+ debug("Looking for '%s' at %d, name %s\n", base, offset, find_name);
+
+ aliases = fdt_path_offset(blob, "/aliases");
+ for (prop_offset = fdt_first_property_offset(blob, aliases);
+ prop_offset > 0;
+ prop_offset = fdt_next_property_offset(blob, prop_offset)) {
+ const char *prop;
+ const char *name;
+ const char *slash;
+ int len, val;
+
+ prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len);
+ debug(" - %s, %s\n", name, prop);
+ if (len < find_namelen || *prop != '/' || prop[len - 1] ||
+ strncmp(name, base, base_len))
+ continue;
+
+ slash = strrchr(prop, '/');
+ if (strcmp(slash + 1, find_name))
+ continue;
+ val = trailing_strtol(name);
+ if (val != -1) {
+ *seqp = val;
+ debug("Found seq %d\n", *seqp);
+ return 0;
+ }
+ }
+
+ debug("Not found\n");
+ return -ENOENT;
+}
+
+int fdtdec_get_alias_highest_id(const void *blob, const char *base)
+{
+ int base_len = strlen(base);
+ int prop_offset;
+ int aliases;
+ int max = -1;
+
+ debug("Looking for highest alias id for '%s'\n", base);
+
+ aliases = fdt_path_offset(blob, "/aliases");
+ for (prop_offset = fdt_first_property_offset(blob, aliases);
+ prop_offset > 0;
+ prop_offset = fdt_next_property_offset(blob, prop_offset)) {
+ const char *prop;
+ const char *name;
+ int len, val;
+
+ prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len);
+ debug(" - %s, %s\n", name, prop);
+ if (*prop != '/' || prop[len - 1] ||
+ strncmp(name, base, base_len))
+ continue;
+
+ val = trailing_strtol(name);
+ if (val > max) {
+ debug("Found seq %d\n", val);
+ max = val;
+ }
+ }
+
+ return max;
+}
+
+const char *fdtdec_get_chosen_prop(const void *blob, const char *name)
+{
+ int chosen_node;
+
+ if (!blob)
+ return NULL;
+ chosen_node = fdt_path_offset(blob, "/chosen");
+ return fdt_getprop(blob, chosen_node, name, NULL);
+}
+
+int fdtdec_get_chosen_node(const void *blob, const char *name)
+{
+ const char *prop;
+
+ prop = fdtdec_get_chosen_prop(blob, name);
+ if (!prop)
+ return -FDT_ERR_NOTFOUND;
+ return fdt_path_offset(blob, prop);
+}
+
+int fdtdec_check_fdt(void)
+{
+ /*
+ * We must have an FDT, but we cannot panic() yet since the console
+ * is not ready. So for now, just assert(). Boards which need an early
+ * FDT (prior to console ready) will need to make their own
+ * arrangements and do their own checks.
+ */
+ assert(!fdtdec_prepare_fdt());
+ return 0;
+}
+
+/*
+ * This function is a little odd in that it accesses global data. At some
+ * point if the architecture board.c files merge this will make more sense.
+ * Even now, it is common code.
+ */
+int fdtdec_prepare_fdt(void)
+{
+#ifndef SYLIXOS
+ if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||
+ fdt_check_header(gd->fdt_blob)) {
+#ifdef CONFIG_SPL_BUILD
+ puts("Missing DTB\n");
+#else
+ puts("No valid device tree binary found - please append one to U-Boot binary, use u-boot-dtb.bin or define CONFIG_OF_EMBED. For sandbox, use -d <file.dtb>\n");
+# ifdef DEBUG
+ if (gd->fdt_blob) {
+ printf("fdt_blob=%p\n", gd->fdt_blob);
+ print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4,
+ 32, 0);
+ }
+# endif
+#endif
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name)
+{
+ const u32 *phandle;
+ int lookup;
+
+ debug("%s: %s\n", __func__, prop_name);
+ phandle = fdt_getprop(blob, node, prop_name, NULL);
+ if (!phandle)
+ return -FDT_ERR_NOTFOUND;
+
+ lookup = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*phandle));
+ return lookup;
+}
+
+/**
+ * Look up a property in a node and check that it has a minimum length.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param min_len minimum property length in bytes
+ * @param err 0 if ok, or -FDT_ERR_NOTFOUND if the property is not
+ found, or -FDT_ERR_BADLAYOUT if not enough data
+ * @return pointer to cell, which is only valid if err == 0
+ */
+static const void *get_prop_check_min_len(const void *blob, int node,
+ const char *prop_name, int min_len,
+ int *err)
+{
+ const void *cell;
+ int len;
+
+ debug("%s: %s\n", __func__, prop_name);
+ cell = fdt_getprop(blob, node, prop_name, &len);
+ if (!cell)
+ *err = -FDT_ERR_NOTFOUND;
+ else if (len < min_len)
+ *err = -FDT_ERR_BADLAYOUT;
+ else
+ *err = 0;
+ return cell;
+}
+
+int fdtdec_get_int_array(const void *blob, int node, const char *prop_name,
+ u32 *array, int count)
+{
+ const u32 *cell;
+ int err = 0;
+
+ debug("%s: %s\n", __func__, prop_name);
+ cell = get_prop_check_min_len(blob, node, prop_name,
+ sizeof(u32) * count, &err);
+ if (!err) {
+ int i;
+
+ for (i = 0; i < count; i++)
+ array[i] = fdt32_to_cpu(cell[i]);
+ }
+ return err;
+}
+
+int fdtdec_get_int_array_count(const void *blob, int node,
+ const char *prop_name, u32 *array, int count)
+{
+ const u32 *cell;
+ int len, elems;
+ int i;
+
+ debug("%s: %s\n", __func__, prop_name);
+ cell = fdt_getprop(blob, node, prop_name, &len);
+ if (!cell)
+ return -FDT_ERR_NOTFOUND;
+ elems = len / sizeof(u32);
+ if (count > elems)
+ count = elems;
+ for (i = 0; i < count; i++)
+ array[i] = fdt32_to_cpu(cell[i]);
+
+ return count;
+}
+
+const u32 *fdtdec_locate_array(const void *blob, int node,
+ const char *prop_name, int count)
+{
+ const u32 *cell;
+ int err;
+
+ cell = get_prop_check_min_len(blob, node, prop_name,
+ sizeof(u32) * count, &err);
+ return err ? NULL : cell;
+}
+
+int fdtdec_get_bool(const void *blob, int node, const char *prop_name)
+{
+ const s32 *cell;
+ int len;
+
+ debug("%s: %s\n", __func__, prop_name);
+ cell = fdt_getprop(blob, node, prop_name, &len);
+ return cell != NULL;
+}
+
+int fdtdec_parse_phandle_with_args(const void *blob, int src_node,
+ const char *list_name,
+ const char *cells_name,
+ int cell_count, int index,
+ struct fdtdec_phandle_args *out_args)
+{
+ const __be32 *list, *list_end;
+ int rc = 0, size, cur_index = 0;
+ uint32_t count = 0;
+ int node = -1;
+ int phandle;
+
+ /* Retrieve the phandle list property */
+ list = fdt_getprop(blob, src_node, 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.
+ */
+#ifdef SYLIXOS
+ phandle = (int)(ulong_t)be32_to_cpup(list++);
+#else
+ phandle = be32_to_cpup(list++);
+#endif
+ 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 = fdt_node_offset_by_phandle(blob,
+ phandle);
+ if (!node) {
+ debug("%s: could not find phandle\n",
+ fdt_get_name(blob, src_node,
+ NULL));
+ goto err;
+ }
+ }
+
+ if (cells_name) {
+ count = fdtdec_get_int(blob, node, cells_name,
+ -1);
+ if (count == -1) {
+ debug("%s: could not get %s for %s\n",
+ fdt_get_name(blob, src_node,
+ NULL),
+ cells_name,
+ fdt_get_name(blob, node,
+ NULL));
+ 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",
+ fdt_get_name(blob, src_node, NULL));
+ 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 > MAX_PHANDLE_ARGS) {
+ debug("%s: too many arguments %d\n",
+ fdt_get_name(blob, src_node,
+ NULL), count);
+ count = MAX_PHANDLE_ARGS;
+ }
+ out_args->node = node;
+ out_args->args_count = count;
+ for (i = 0; i < count; i++) {
+ out_args->args[i] =
+#ifdef SYLIXOS
+ (uint32_t)(ulong_t)be32_to_cpup(list++);
+#else
+ be32_to_cpup(list++);
+#endif
+ }
+ }
+
+ /* Found it! return success */
+ return 0;
+ }
+
+ node = -1;
+ list += count;
+ cur_index++;
+ }
+
+ /*
+ * 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:
+ return rc;
+}
+
+int fdtdec_get_child_count(const void *blob, int node)
+{
+ int subnode;
+ int num = 0;
+
+ fdt_for_each_subnode(subnode, blob, node)
+ num++;
+
+ return num;
+}
+
+int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name,
+ u8 *array, int count)
+{
+ const u8 *cell;
+ int err;
+
+ cell = get_prop_check_min_len(blob, node, prop_name, count, &err);
+ if (!err)
+ memcpy(array, cell, count);
+ return err;
+}
+
+const u8 *fdtdec_locate_byte_array(const void *blob, int node,
+ const char *prop_name, int count)
+{
+ const u8 *cell;
+ int err;
+
+ cell = get_prop_check_min_len(blob, node, prop_name, count, &err);
+ if (err)
+ return NULL;
+ return cell;
+}
+
+int fdtdec_get_config_int(const void *blob, const char *prop_name,
+ int default_val)
+{
+ int config_node;
+
+ debug("%s: %s\n", __func__, prop_name);
+ config_node = fdt_path_offset(blob, "/config");
+ if (config_node < 0)
+ return default_val;
+ return fdtdec_get_int(blob, config_node, prop_name, default_val);
+}
+
+int fdtdec_get_config_bool(const void *blob, const char *prop_name)
+{
+ int config_node;
+ const void *prop;
+
+ debug("%s: %s\n", __func__, prop_name);
+ config_node = fdt_path_offset(blob, "/config");
+ if (config_node < 0)
+ return 0;
+ prop = fdt_get_property(blob, config_node, prop_name, NULL);
+
+ return prop != NULL;
+}
+
+char *fdtdec_get_config_string(const void *blob, const char *prop_name)
+{
+ const char *nodep;
+ int nodeoffset;
+ int len;
+
+ debug("%s: %s\n", __func__, prop_name);
+ nodeoffset = fdt_path_offset(blob, "/config");
+ if (nodeoffset < 0)
+ return NULL;
+
+ nodep = fdt_getprop(blob, nodeoffset, prop_name, &len);
+ if (!nodep)
+ return NULL;
+
+ return (char *)nodep;
+}
+
+u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells)
+{
+ u64 number = 0;
+
+ while (cells--)
+ number = (number << 32) | fdt32_to_cpu(*ptr++);
+
+ return number;
+}
+
+int fdt_get_resource(const void *fdt, int node, const char *property,
+ unsigned int index, struct fdt_resource *res)
+{
+ const fdt32_t *ptr, *end;
+ int na, ns, len, parent;
+ unsigned int i = 0;
+
+ parent = fdt_parent_offset(fdt, node);
+ if (parent < 0)
+ return parent;
+
+ na = fdt_address_cells(fdt, parent);
+ ns = fdt_size_cells(fdt, parent);
+
+ ptr = fdt_getprop(fdt, node, property, &len);
+ if (!ptr)
+ return len;
+
+ end = ptr + len / sizeof(*ptr);
+
+ while (ptr + na + ns <= end) {
+ if (i == index) {
+ res->start = fdtdec_get_number(ptr, na);
+ res->end = res->start;
+ res->end += fdtdec_get_number(&ptr[na], ns) - 1;
+ return 0;
+ }
+
+ ptr += na + ns;
+ i++;
+ }
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+int fdt_get_named_resource(const void *fdt, int node, const char *property,
+ const char *prop_names, const char *name,
+ struct fdt_resource *res)
+{
+ int index;
+
+ index = fdt_stringlist_search(fdt, node, prop_names, name);
+ if (index < 0)
+ return index;
+
+ return fdt_get_resource(fdt, node, property, index, res);
+}
+
+static int decode_timing_property(const void *blob, int node, const char *name,
+ struct timing_entry *result)
+{
+ int length, ret = 0;
+ const u32 *prop;
+
+ prop = fdt_getprop(blob, node, name, &length);
+ if (!prop) {
+ debug("%s: could not find property %s\n",
+ fdt_get_name(blob, node, NULL), name);
+ return length;
+ }
+
+ if (length == sizeof(u32)) {
+ result->typ = fdtdec_get_int(blob, node, name, 0);
+ result->min = result->typ;
+ result->max = result->typ;
+ } else {
+ ret = fdtdec_get_int_array(blob, node, name, &result->min, 3);
+ }
+
+ return ret;
+}
+
+int fdtdec_decode_display_timing(const void *blob, int parent, int index,
+ struct display_timing *dt)
+{
+ int i, node, timings_node;
+ u32 val = 0;
+ int ret = 0;
+
+ timings_node = fdt_subnode_offset(blob, parent, "display-timings");
+ if (timings_node < 0)
+ return timings_node;
+
+ for (i = 0, node = fdt_first_subnode(blob, timings_node);
+ node > 0 && i != index;
+ node = fdt_next_subnode(blob, node))
+ i++;
+
+ if (node < 0)
+ return node;
+
+ memset(dt, 0, sizeof(*dt));
+
+ ret |= decode_timing_property(blob, node, "hback-porch",
+ &dt->hback_porch);
+ ret |= decode_timing_property(blob, node, "hfront-porch",
+ &dt->hfront_porch);
+ ret |= decode_timing_property(blob, node, "hactive", &dt->hactive);
+ ret |= decode_timing_property(blob, node, "hsync-len", &dt->hsync_len);
+ ret |= decode_timing_property(blob, node, "vback-porch",
+ &dt->vback_porch);
+ ret |= decode_timing_property(blob, node, "vfront-porch",
+ &dt->vfront_porch);
+ ret |= decode_timing_property(blob, node, "vactive", &dt->vactive);
+ ret |= decode_timing_property(blob, node, "vsync-len", &dt->vsync_len);
+ ret |= decode_timing_property(blob, node, "clock-frequency",
+ &dt->pixelclock);
+
+ dt->flags = 0;
+ val = fdtdec_get_int(blob, node, "vsync-active", -1);
+ if (val != -1) {
+ dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
+ DISPLAY_FLAGS_VSYNC_LOW;
+ }
+ val = fdtdec_get_int(blob, node, "hsync-active", -1);
+ if (val != -1) {
+ dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
+ DISPLAY_FLAGS_HSYNC_LOW;
+ }
+ val = fdtdec_get_int(blob, node, "de-active", -1);
+ if (val != -1) {
+ dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
+ DISPLAY_FLAGS_DE_LOW;
+ }
+ val = fdtdec_get_int(blob, node, "pixelclk-active", -1);
+ if (val != -1) {
+ dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
+ DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+ }
+
+ if (fdtdec_get_bool(blob, node, "interlaced"))
+ dt->flags |= DISPLAY_FLAGS_INTERLACED;
+ if (fdtdec_get_bool(blob, node, "doublescan"))
+ dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
+ if (fdtdec_get_bool(blob, node, "doubleclk"))
+ dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
+
+ return ret;
+}
+
+#ifndef SYLIXOS
+int fdtdec_setup_mem_size_base(void)
+{
+ int ret, mem;
+ struct fdt_resource res;
+
+ mem = fdt_path_offset(gd->fdt_blob, "/memory");
+ if (mem < 0) {
+ debug("%s: Missing /memory node\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = fdt_get_resource(gd->fdt_blob, mem, "reg", 0, &res);
+ if (ret != 0) {
+ debug("%s: Unable to decode first memory bank\n", __func__);
+ return -EINVAL;
+ }
+
+ gd->ram_size = (phys_size_t)(res.end - res.start + 1);
+ gd->ram_base = (unsigned long)res.start;
+ debug("%s: Initial DRAM size %llx\n", __func__,
+ (unsigned long long)gd->ram_size);
+
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_NR_DRAM_BANKS)
+
+static int get_next_memory_node(const void *blob, int mem)
+{
+ do {
+ mem = fdt_node_offset_by_prop_value(gd->fdt_blob, mem,
+ "device_type", "memory", 7);
+ } while (!fdtdec_get_is_enabled(blob, mem));
+
+ return mem;
+}
+
+int fdtdec_setup_memory_banksize(void)
+{
+ int bank, ret, mem, reg = 0;
+ struct fdt_resource res;
+
+ mem = get_next_memory_node(gd->fdt_blob, -1);
+ if (mem < 0) {
+ debug("%s: Missing /memory node\n", __func__);
+ return -EINVAL;
+ }
+
+ for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
+ ret = fdt_get_resource(gd->fdt_blob, mem, "reg", reg++, &res);
+ if (ret == -FDT_ERR_NOTFOUND) {
+ reg = 0;
+ mem = get_next_memory_node(gd->fdt_blob, mem);
+ if (mem == -FDT_ERR_NOTFOUND)
+ break;
+
+ ret = fdt_get_resource(gd->fdt_blob, mem, "reg", reg++, &res);
+ if (ret == -FDT_ERR_NOTFOUND)
+ break;
+ }
+ if (ret != 0) {
+ return -EINVAL;
+ }
+
+ gd->bd->bi_dram[bank].start = (phys_addr_t)res.start;
+ gd->bd->bi_dram[bank].size =
+ (phys_size_t)(res.end - res.start + 1);
+
+ debug("%s: DRAM Bank #%d: start = 0x%llx, size = 0x%llx\n",
+ __func__, bank,
+ (unsigned long long)gd->bd->bi_dram[bank].start,
+ (unsigned long long)gd->bd->bi_dram[bank].size);
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef SYLIXOS
+#if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
+# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_GZIP) ||\
+ CONFIG_IS_ENABLED(MULTI_DTB_FIT_LZO)
+static int uncompress_blob(const void *src, ulong sz_src, void **dstp)
+{
+ size_t sz_out = CONFIG_SPL_MULTI_DTB_FIT_UNCOMPRESS_SZ;
+ ulong sz_in = sz_src;
+ void *dst;
+ int rc;
+
+ if (CONFIG_IS_ENABLED(GZIP))
+ if (gzip_parse_header(src, sz_in) < 0)
+ return -1;
+ if (CONFIG_IS_ENABLED(LZO))
+ if (!lzop_is_valid_header(src))
+ return -EBADMSG;
+
+ if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC)) {
+ dst = malloc(sz_out);
+ if (!dst) {
+ puts("uncompress_blob: Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+ } else {
+# if CONFIG_IS_ENABLED(MULTI_DTB_FIT_USER_DEFINED_AREA)
+ dst = (void *)CONFIG_VAL(MULTI_DTB_FIT_USER_DEF_ADDR);
+# else
+ return -ENOTSUPP;
+# endif
+ }
+
+ if (CONFIG_IS_ENABLED(GZIP))
+ rc = gunzip(dst, sz_out, (u8 *)src, &sz_in);
+ else if (CONFIG_IS_ENABLED(LZO))
+ rc = lzop_decompress(src, sz_in, dst, &sz_out);
+
+ if (rc < 0) {
+ /* not a valid compressed blob */
+ puts("uncompress_blob: Unable to uncompress\n");
+ if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC))
+ free(dst);
+ return -EBADMSG;
+ }
+ *dstp = dst;
+ return 0;
+}
+# else
+static int uncompress_blob(const void *src, ulong sz_src, void **dstp)
+{
+ *dstp = (void *)src;
+ return 0;
+}
+# endif
+#endif
+#endif
+
+#if defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE)
+/*
+ * For CONFIG_OF_SEPARATE, the board may optionally implement this to
+ * provide and/or fixup the fdt.
+ */
+__weak void *board_fdt_blob_setup(void)
+{
+ void *fdt_blob = NULL;
+#ifdef CONFIG_SPL_BUILD
+ /* FDT is at end of BSS unless it is in a different memory region */
+ if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS))
+ fdt_blob = (ulong *)&_image_binary_end;
+ else
+ fdt_blob = (ulong *)&__bss_end;
+#else
+ /* FDT is at end of image */
+ fdt_blob = (ulong *)&_end;
+#endif
+ return fdt_blob;
+}
+#endif
+
+int fdtdec_setup(void)
+{
+#ifndef SYLIXOS
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
+ void *fdt_blob;
+# endif
+# ifdef CONFIG_OF_EMBED
+ /* Get a pointer to the FDT */
+# ifdef CONFIG_SPL_BUILD
+ gd->fdt_blob = __dtb_dt_spl_begin;
+# else
+ gd->fdt_blob = __dtb_dt_begin;
+# endif
+# elif defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE)
+ /* Allow the board to override the fdt address. */
+ gd->fdt_blob = board_fdt_blob_setup();
+# elif defined(CONFIG_OF_HOSTFILE)
+ if (sandbox_read_fdt_from_file()) {
+ puts("Failed to read control FDT\n");
+ return -1;
+ }
+# endif
+# ifndef CONFIG_SPL_BUILD
+ /* Allow the early environment to override the fdt address */
+# if CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
+ gd->fdt_blob = (void *)prior_stage_fdt_address;
+# else
+ gd->fdt_blob = map_sysmem
+ (env_get_ulong("fdtcontroladdr", 16,
+ (unsigned long)map_to_sysmem(gd->fdt_blob)), 0);
+# endif
+# endif
+
+# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
+ /*
+ * Try and uncompress the blob.
+ * Unfortunately there is no way to know how big the input blob really
+ * is. So let us set the maximum input size arbitrarily high. 16MB
+ * ought to be more than enough for packed DTBs.
+ */
+ if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0)
+ gd->fdt_blob = fdt_blob;
+
+ /*
+ * Check if blob is a FIT images containings DTBs.
+ * If so, pick the most relevant
+ */
+ fdt_blob = locate_dtb_in_fit(gd->fdt_blob);
+ if (fdt_blob) {
+ gd->multi_dtb_fit = gd->fdt_blob;
+ gd->fdt_blob = fdt_blob;
+ }
+
+# endif
+#endif
+#endif
+ return fdtdec_prepare_fdt();
+}
+
+#ifndef SYLIXOS
+#if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
+int fdtdec_resetup(int *rescan)
+{
+ void *fdt_blob;
+
+ /*
+ * If the current DTB is part of a compressed FIT image,
+ * try to locate the best match from the uncompressed
+ * FIT image stillpresent there. Save the time and space
+ * required to uncompress it again.
+ */
+ if (gd->multi_dtb_fit) {
+ fdt_blob = locate_dtb_in_fit(gd->multi_dtb_fit);
+
+ if (fdt_blob == gd->fdt_blob) {
+ /*
+ * The best match did not change. no need to tear down
+ * the DM and rescan the fdt.
+ */
+ *rescan = 0;
+ return 0;
+ }
+
+ *rescan = 1;
+ gd->fdt_blob = fdt_blob;
+ return fdtdec_prepare_fdt();
+ }
+
+ /*
+ * If multi_dtb_fit is NULL, it means that blob appended to u-boot is
+ * not a FIT image containings DTB, but a single DTB. There is no need
+ * to teard down DM and rescan the DT in this case.
+ */
+ *rescan = 0;
+ return 0;
+}
+#endif
+#endif
+
+#ifdef CONFIG_NR_DRAM_BANKS
+int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id,
+ phys_addr_t *basep, phys_size_t *sizep, bd_t *bd)
+{
+ int addr_cells, size_cells;
+ const u32 *cell, *end;
+ u64 total_size, size, addr;
+ int node, child;
+ bool auto_size;
+ int bank;
+ int len;
+
+ debug("%s: board_id=%d\n", __func__, board_id);
+ if (!area)
+ area = "/memory";
+ node = fdt_path_offset(blob, area);
+ if (node < 0) {
+ debug("No %s node found\n", area);
+ return -ENOENT;
+ }
+
+ cell = fdt_getprop(blob, node, "reg", &len);
+ if (!cell) {
+ debug("No reg property found\n");
+ return -ENOENT;
+ }
+
+ addr_cells = fdt_address_cells(blob, node);
+ size_cells = fdt_size_cells(blob, node);
+
+ /* Check the board id and mask */
+ for (child = fdt_first_subnode(blob, node);
+ child >= 0;
+ child = fdt_next_subnode(blob, child)) {
+ int match_mask, match_value;
+
+ match_mask = fdtdec_get_int(blob, child, "match-mask", -1);
+ match_value = fdtdec_get_int(blob, child, "match-value", -1);
+
+ if (match_value >= 0 &&
+ ((board_id & match_mask) == match_value)) {
+ /* Found matching mask */
+ debug("Found matching mask %d\n", match_mask);
+ node = child;
+ cell = fdt_getprop(blob, node, "reg", &len);
+ if (!cell) {
+ debug("No memory-banks property found\n");
+ return -EINVAL;
+ }
+ break;
+ }
+ }
+ /* Note: if no matching subnode was found we use the parent node */
+
+ if (bd) {
+ memset(bd->bi_dram, '\0', sizeof(bd->bi_dram[0]) *
+ CONFIG_NR_DRAM_BANKS);
+ }
+
+ auto_size = fdtdec_get_bool(blob, node, "auto-size");
+
+ total_size = 0;
+ end = cell + len / 4 - addr_cells - size_cells;
+ debug("cell at %p, end %p\n", cell, end);
+ for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
+ if (cell > end)
+ break;
+ addr = 0;
+ if (addr_cells == 2)
+ addr += (u64)fdt32_to_cpu(*cell++) << 32UL;
+ addr += fdt32_to_cpu(*cell++);
+ if (bd)
+ bd->bi_dram[bank].start = addr;
+ if (basep && !bank)
+ *basep = (phys_addr_t)addr;
+
+ size = 0;
+ if (size_cells == 2)
+ size += (u64)fdt32_to_cpu(*cell++) << 32UL;
+ size += fdt32_to_cpu(*cell++);
+
+ if (auto_size) {
+ u64 new_size;
+
+ debug("Auto-sizing %llx, size %llx: ", addr, size);
+ new_size = get_ram_size((long *)(uintptr_t)addr, size);
+ if (new_size == size) {
+ debug("OK\n");
+ } else {
+ debug("sized to %llx\n", new_size);
+ size = new_size;
+ }
+ }
+
+ if (bd)
+ bd->bi_dram[bank].size = size;
+ total_size += size;
+ }
+
+ debug("Memory size %llu\n", total_size);
+ if (sizep)
+ *sizep = (phys_size_t)total_size;
+
+ return 0;
+}
+#endif /* CONFIG_NR_DRAM_BANKS */
+
+#endif /* !USE_HOSTCC */
diff --git a/SylixOS/driver/fdt/fdtdec.h b/SylixOS/driver/fdt/fdtdec.h
new file mode 100644
index 0000000..51a8998
--- /dev/null
+++ b/SylixOS/driver/fdt/fdtdec.h
@@ -0,0 +1,1033 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ */
+
+#ifndef __fdtdec_h
+#define __fdtdec_h
+
+/*
+ * This file contains convenience functions for decoding useful and
+ * enlightening information from FDTs. It is intended to be used by device
+ * drivers and board-specific code within U-Boot. It aims to reduce the
+ * amount of FDT munging required within U-Boot itself, so that driver code
+ * changes to support FDT are minimized.
+ */
+#ifndef SYLIXOS
+#include <linux/libfdt.h>
+#include <pci.h>
+#else
+#include "libfdt.h"
+
+#define phys_size_t size_t
+#endif
+
+/*
+ * A typedef for a physical address. Note that fdt data is always big
+ * endian even on a litle endian machine.
+ */
+typedef phys_addr_t fdt_addr_t;
+typedef phys_size_t fdt_size_t;
+#ifdef CONFIG_PHYS_64BIT
+#define FDT_ADDR_T_NONE (-1U)
+#define fdt_addr_to_cpu(reg) be64_to_cpu(reg)
+#define fdt_size_to_cpu(reg) be64_to_cpu(reg)
+typedef fdt64_t fdt_val_t;
+#else
+#define FDT_ADDR_T_NONE (-1U)
+#define fdt_addr_to_cpu(reg) be32_to_cpu(reg)
+#define fdt_size_to_cpu(reg) be32_to_cpu(reg)
+typedef fdt32_t fdt_val_t;
+#endif
+
+/* Information obtained about memory from the FDT */
+struct fdt_memory {
+ fdt_addr_t start;
+ fdt_addr_t end;
+};
+
+struct bd_info;
+
+#ifdef CONFIG_SPL_BUILD
+#define SPL_BUILD 1
+#else
+#define SPL_BUILD 0
+#endif
+
+#ifndef SYLIXOS
+#if CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
+extern phys_addr_t prior_stage_fdt_address;
+#endif
+#endif
+
+/*
+ * Information about a resource. start is the first address of the resource
+ * and end is the last address (inclusive). The length of the resource will
+ * be equal to: end - start + 1.
+ */
+struct fdt_resource {
+ fdt_addr_t start;
+ fdt_addr_t end;
+};
+
+enum fdt_pci_space {
+ FDT_PCI_SPACE_CONFIG = 0,
+ FDT_PCI_SPACE_IO = 0x01000000,
+ FDT_PCI_SPACE_MEM32 = 0x02000000,
+ FDT_PCI_SPACE_MEM64 = 0x03000000,
+ FDT_PCI_SPACE_MEM32_PREF = 0x42000000,
+ FDT_PCI_SPACE_MEM64_PREF = 0x43000000,
+};
+
+#define FDT_PCI_ADDR_CELLS 3
+#define FDT_PCI_SIZE_CELLS 2
+#define FDT_PCI_REG_SIZE \
+ ((FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS) * sizeof(u32))
+
+/*
+ * The Open Firmware spec defines PCI physical address as follows:
+ *
+ * bits# 31 .... 24 23 .... 16 15 .... 08 07 .... 00
+ *
+ * phys.hi cell: npt000ss bbbbbbbb dddddfff rrrrrrrr
+ * phys.mid cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh
+ * phys.lo cell: llllllll llllllll llllllll llllllll
+ *
+ * where:
+ *
+ * n: is 0 if the address is relocatable, 1 otherwise
+ * p: is 1 if addressable region is prefetchable, 0 otherwise
+ * t: is 1 if the address is aliased (for non-relocatable I/O) below 1MB
+ * (for Memory), or below 64KB (for relocatable I/O)
+ * ss: is the space code, denoting the address space
+ * bbbbbbbb: is the 8-bit Bus Number
+ * ddddd: is the 5-bit Device Number
+ * fff: is the 3-bit Function Number
+ * rrrrrrrr: is the 8-bit Register Number
+ * hhhhhhhh: is a 32-bit unsigned number
+ * llllllll: is a 32-bit unsigned number
+ */
+struct fdt_pci_addr {
+ u32 phys_hi;
+ u32 phys_mid;
+ u32 phys_lo;
+};
+
+/**
+ * Compute the size of a resource.
+ *
+ * @param res the resource to operate on
+ * @return the size of the resource
+ */
+static inline fdt_size_t fdt_resource_size(const struct fdt_resource *res)
+{
+ return res->end - res->start + 1;
+}
+
+/**
+ * Compat types that we know about and for which we might have drivers.
+ * Each is named COMPAT_<dir>_<filename> where <dir> is the directory
+ * within drivers.
+ */
+enum fdt_compat_id {
+ COMPAT_UNKNOWN,
+ COMPAT_NVIDIA_TEGRA20_EMC, /* Tegra20 memory controller */
+ COMPAT_NVIDIA_TEGRA20_EMC_TABLE, /* Tegra20 memory timing table */
+ COMPAT_NVIDIA_TEGRA20_NAND, /* Tegra2 NAND controller */
+ COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL,
+ /* Tegra124 XUSB pad controller */
+ COMPAT_NVIDIA_TEGRA210_XUSB_PADCTL,
+ /* Tegra210 XUSB pad controller */
+ COMPAT_SMSC_LAN9215, /* SMSC 10/100 Ethernet LAN9215 */
+ COMPAT_SAMSUNG_EXYNOS5_SROMC, /* Exynos5 SROMC */
+ COMPAT_SAMSUNG_EXYNOS_USB_PHY, /* Exynos phy controller for usb2.0 */
+ COMPAT_SAMSUNG_EXYNOS5_USB3_PHY,/* Exynos phy controller for usb3.0 */
+ COMPAT_SAMSUNG_EXYNOS_TMU, /* Exynos TMU */
+ COMPAT_SAMSUNG_EXYNOS_MIPI_DSI, /* Exynos mipi dsi */
+ COMPAT_SAMSUNG_EXYNOS_DWMMC, /* Exynos DWMMC controller */
+ COMPAT_GENERIC_SPI_FLASH, /* Generic SPI Flash chip */
+ COMPAT_SAMSUNG_EXYNOS_SYSMMU, /* Exynos sysmmu */
+ COMPAT_INTEL_MICROCODE, /* Intel microcode update */
+ COMPAT_INTEL_QRK_MRC, /* Intel Quark MRC */
+ COMPAT_ALTERA_SOCFPGA_DWMAC, /* SoCFPGA Ethernet controller */
+ COMPAT_ALTERA_SOCFPGA_DWMMC, /* SoCFPGA DWMMC controller */
+ COMPAT_ALTERA_SOCFPGA_DWC2USB, /* SoCFPGA DWC2 USB controller */
+ COMPAT_INTEL_BAYTRAIL_FSP, /* Intel Bay Trail FSP */
+ COMPAT_INTEL_BAYTRAIL_FSP_MDP, /* Intel FSP memory-down params */
+ COMPAT_INTEL_IVYBRIDGE_FSP, /* Intel Ivy Bridge FSP */
+ COMPAT_SUNXI_NAND, /* SUNXI NAND controller */
+ COMPAT_ALTERA_SOCFPGA_CLK, /* SoCFPGA Clock initialization */
+ COMPAT_ALTERA_SOCFPGA_PINCTRL_SINGLE, /* SoCFPGA pinctrl-single */
+ COMPAT_ALTERA_SOCFPGA_H2F_BRG, /* SoCFPGA hps2fpga bridge */
+ COMPAT_ALTERA_SOCFPGA_LWH2F_BRG, /* SoCFPGA lwhps2fpga bridge */
+ COMPAT_ALTERA_SOCFPGA_F2H_BRG, /* SoCFPGA fpga2hps bridge */
+ COMPAT_ALTERA_SOCFPGA_F2SDR0, /* SoCFPGA fpga2SDRAM0 bridge */
+ COMPAT_ALTERA_SOCFPGA_F2SDR1, /* SoCFPGA fpga2SDRAM1 bridge */
+ COMPAT_ALTERA_SOCFPGA_F2SDR2, /* SoCFPGA fpga2SDRAM2 bridge */
+ COMPAT_ALTERA_SOCFPGA_FPGA0, /* SOCFPGA FPGA manager */
+ COMPAT_ALTERA_SOCFPGA_NOC, /* SOCFPGA Arria 10 NOC */
+ COMPAT_ALTERA_SOCFPGA_CLK_INIT, /* SOCFPGA Arria 10 clk init */
+
+ COMPAT_COUNT,
+};
+
+#define MAX_PHANDLE_ARGS 16
+struct fdtdec_phandle_args {
+ int node;
+ int args_count;
+ uint32_t args[MAX_PHANDLE_ARGS];
+};
+
+/**
+ * fdtdec_parse_phandle_with_args() - Find a node pointed by phandle in a list
+ *
+ * This function is useful to parse lists of phandles and their arguments.
+ *
+ * Example:
+ *
+ * phandle1: node1 {
+ * #list-cells = <2>;
+ * }
+ *
+ * phandle2: node2 {
+ * #list-cells = <1>;
+ * }
+ *
+ * node3 {
+ * list = <&phandle1 1 2 &phandle2 3>;
+ * }
+ *
+ * To get a device_node of the `node2' node you may call this:
+ * fdtdec_parse_phandle_with_args(blob, node3, "list", "#list-cells", 0, 1,
+ * &args);
+ *
+ * (This function is a modified version of __of_parse_phandle_with_args() from
+ * Linux 3.18)
+ *
+ * @blob: Pointer to device tree
+ * @src_node: Offset of device tree node containing a list
+ * @list_name: property name that contains a list
+ * @cells_name: property name that specifies the phandles' arguments count,
+ * or NULL to use @cells_count
+ * @cells_count: Cell count to use if @cells_name is NULL
+ * @index: index of a phandle to parse out
+ * @out_args: optional pointer to output arguments structure (will be filled)
+ * @return 0 on success (with @out_args filled out if not NULL), -ENOENT if
+ * @list_name does not exist, a phandle was not found, @cells_name
+ * could not be found, the arguments were truncated or there were too
+ * many arguments.
+ *
+ */
+int fdtdec_parse_phandle_with_args(const void *blob, int src_node,
+ const char *list_name,
+ const char *cells_name,
+ int cell_count, int index,
+ struct fdtdec_phandle_args *out_args);
+
+/**
+ * Find the next numbered alias for a peripheral. This is used to enumerate
+ * all the peripherals of a certain type.
+ *
+ * Do the first call with *upto = 0. Assuming /aliases/<name>0 exists then
+ * this function will return a pointer to the node the alias points to, and
+ * then update *upto to 1. Next time you call this function, the next node
+ * will be returned.
+ *
+ * All nodes returned will match the compatible ID, as it is assumed that
+ * all peripherals use the same driver.
+ *
+ * @param blob FDT blob to use
+ * @param name Root name of alias to search for
+ * @param id Compatible ID to look for
+ * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more
+ */
+int fdtdec_next_alias(const void *blob, const char *name,
+ enum fdt_compat_id id, int *upto);
+
+/**
+ * Find the compatible ID for a given node.
+ *
+ * Generally each node has at least one compatible string attached to it.
+ * This function looks through our list of known compatible strings and
+ * returns the corresponding ID which matches the compatible string.
+ *
+ * @param blob FDT blob to use
+ * @param node Node containing compatible string to find
+ * @return compatible ID, or COMPAT_UNKNOWN if we cannot find a match
+ */
+enum fdt_compat_id fdtdec_lookup(const void *blob, int node);
+
+/**
+ * Find the next compatible node for a peripheral.
+ *
+ * Do the first call with node = 0. This function will return a pointer to
+ * the next compatible node. Next time you call this function, pass the
+ * value returned, and the next node will be provided.
+ *
+ * @param blob FDT blob to use
+ * @param node Start node for search
+ * @param id Compatible ID to look for (enum fdt_compat_id)
+ * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more
+ */
+int fdtdec_next_compatible(const void *blob, int node,
+ enum fdt_compat_id id);
+
+/**
+ * Find the next compatible subnode for a peripheral.
+ *
+ * Do the first call with node set to the parent and depth = 0. This
+ * function will return the offset of the next compatible node. Next time
+ * you call this function, pass the node value returned last time, with
+ * depth unchanged, and the next node will be provided.
+ *
+ * @param blob FDT blob to use
+ * @param node Start node for search
+ * @param id Compatible ID to look for (enum fdt_compat_id)
+ * @param depthp Current depth (set to 0 before first call)
+ * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more
+ */
+int fdtdec_next_compatible_subnode(const void *blob, int node,
+ enum fdt_compat_id id, int *depthp);
+
+/*
+ * Look up an address property in a node and return the parsed address, and
+ * optionally the parsed size.
+ *
+ * This variant assumes a known and fixed number of cells are used to
+ * represent the address and size.
+ *
+ * You probably don't want to use this function directly except to parse
+ * non-standard properties, and never to parse the "reg" property. Instead,
+ * use one of the "auto" variants below, which automatically honor the
+ * #address-cells and #size-cells properties in the parent node.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param index which address to retrieve from a list of addresses. Often 0.
+ * @param na the number of cells used to represent an address
+ * @param ns the number of cells used to represent a size
+ * @param sizep a pointer to store the size into. Use NULL if not required
+ * @param translate Indicates whether to translate the returned value
+ * using the parent node's ranges property.
+ * @return address, if found, or FDT_ADDR_T_NONE if not
+ */
+fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node,
+ const char *prop_name, int index, int na, int ns,
+ fdt_size_t *sizep, bool translate);
+
+/*
+ * Look up an address property in a node and return the parsed address, and
+ * optionally the parsed size.
+ *
+ * This variant automatically determines the number of cells used to represent
+ * the address and size by parsing the provided parent node's #address-cells
+ * and #size-cells properties.
+ *
+ * @param blob FDT blob
+ * @param parent parent node of @node
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param index which address to retrieve from a list of addresses. Often 0.
+ * @param sizep a pointer to store the size into. Use NULL if not required
+ * @param translate Indicates whether to translate the returned value
+ * using the parent node's ranges property.
+ * @return address, if found, or FDT_ADDR_T_NONE if not
+ */
+fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent,
+ int node, const char *prop_name, int index, fdt_size_t *sizep,
+ bool translate);
+
+/*
+ * Look up an address property in a node and return the parsed address, and
+ * optionally the parsed size.
+ *
+ * This variant automatically determines the number of cells used to represent
+ * the address and size by parsing the parent node's #address-cells
+ * and #size-cells properties. The parent node is automatically found.
+ *
+ * The automatic parent lookup implemented by this function is slow.
+ * Consequently, fdtdec_get_addr_size_auto_parent() should be used where
+ * possible.
+ *
+ * @param blob FDT blob
+ * @param parent parent node of @node
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param index which address to retrieve from a list of addresses. Often 0.
+ * @param sizep a pointer to store the size into. Use NULL if not required
+ * @param translate Indicates whether to translate the returned value
+ * using the parent node's ranges property.
+ * @return address, if found, or FDT_ADDR_T_NONE if not
+ */
+fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node,
+ const char *prop_name, int index, fdt_size_t *sizep,
+ bool translate);
+
+/*
+ * Look up an address property in a node and return the parsed address.
+ *
+ * This variant hard-codes the number of cells used to represent the address
+ * and size based on sizeof(fdt_addr_t) and sizeof(fdt_size_t). It also
+ * always returns the first address value in the property (index 0).
+ *
+ * Use of this function is not recommended due to the hard-coding of cell
+ * counts. There is no programmatic validation that these hard-coded values
+ * actually match the device tree content in any way at all. This assumption
+ * can be satisfied by manually ensuring CONFIG_PHYS_64BIT is appropriately
+ * set in the U-Boot build and exercising strict control over DT content to
+ * ensure use of matching #address-cells/#size-cells properties. However, this
+ * approach is error-prone; those familiar with DT will not expect the
+ * assumption to exist, and could easily invalidate it. If the assumption is
+ * invalidated, this function will not report the issue, and debugging will
+ * be required. Instead, use fdtdec_get_addr_size_auto_parent().
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @return address, if found, or FDT_ADDR_T_NONE if not
+ */
+fdt_addr_t fdtdec_get_addr(const void *blob, int node,
+ const char *prop_name);
+
+/*
+ * Look up an address property in a node and return the parsed address, and
+ * optionally the parsed size.
+ *
+ * This variant hard-codes the number of cells used to represent the address
+ * and size based on sizeof(fdt_addr_t) and sizeof(fdt_size_t). It also
+ * always returns the first address value in the property (index 0).
+ *
+ * Use of this function is not recommended due to the hard-coding of cell
+ * counts. There is no programmatic validation that these hard-coded values
+ * actually match the device tree content in any way at all. This assumption
+ * can be satisfied by manually ensuring CONFIG_PHYS_64BIT is appropriately
+ * set in the U-Boot build and exercising strict control over DT content to
+ * ensure use of matching #address-cells/#size-cells properties. However, this
+ * approach is error-prone; those familiar with DT will not expect the
+ * assumption to exist, and could easily invalidate it. If the assumption is
+ * invalidated, this function will not report the issue, and debugging will
+ * be required. Instead, use fdtdec_get_addr_size_auto_parent().
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param sizep a pointer to store the size into. Use NULL if not required
+ * @return address, if found, or FDT_ADDR_T_NONE if not
+ */
+fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
+ const char *prop_name, fdt_size_t *sizep);
+
+/**
+ * Look at an address property in a node and return the pci address which
+ * corresponds to the given type in the form of fdt_pci_addr.
+ * The property must hold one fdt_pci_addr with a lengh.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param type pci address type (FDT_PCI_SPACE_xxx)
+ * @param prop_name name of property to find
+ * @param addr returns pci address in the form of fdt_pci_addr
+ * @return 0 if ok, -ENOENT if the property did not exist, -EINVAL if the
+ * format of the property was invalid, -ENXIO if the requested
+ * address type was not found
+ */
+int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type,
+ const char *prop_name, struct fdt_pci_addr *addr);
+
+/**
+ * Look at the compatible property of a device node that represents a PCI
+ * device and extract pci vendor id and device id from it.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param vendor vendor id of the pci device
+ * @param device device id of the pci device
+ * @return 0 if ok, negative on error
+ */
+int fdtdec_get_pci_vendev(const void *blob, int node,
+ u16 *vendor, u16 *device);
+
+#ifndef SYLIXOS
+/**
+ * Look at the pci address of a device node that represents a PCI device
+ * and return base address of the pci device's registers.
+ *
+ * @param dev device to examine
+ * @param addr pci address in the form of fdt_pci_addr
+ * @param bar returns base address of the pci device's registers
+ * @return 0 if ok, negative on error
+ */
+int fdtdec_get_pci_bar32(struct udevice *dev, struct fdt_pci_addr *addr,
+ u32 *bar);
+#endif
+/**
+ * Look up a 32-bit integer property in a node and return it. The property
+ * must have at least 4 bytes of data. The value of the first cell is
+ * returned.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param default_val default value to return if the property is not found
+ * @return integer value, if found, or default_val if not
+ */
+s32 fdtdec_get_int(const void *blob, int node, const char *prop_name,
+ s32 default_val);
+
+/**
+ * Unsigned version of fdtdec_get_int. The property must have at least
+ * 4 bytes of data. The value of the first cell is returned.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param default_val default value to return if the property is not found
+ * @return unsigned integer value, if found, or default_val if not
+ */
+unsigned int fdtdec_get_uint(const void *blob, int node, const char *prop_name,
+ unsigned int default_val);
+
+/**
+ * Get a variable-sized number from a property
+ *
+ * This reads a number from one or more cells.
+ *
+ * @param ptr Pointer to property
+ * @param cells Number of cells containing the number
+ * @return the value in the cells
+ */
+u64 fdtdec_get_number(const fdt32_t *ptr, unsigned int cells);
+
+/**
+ * Look up a 64-bit integer property in a node and return it. The property
+ * must have at least 8 bytes of data (2 cells). The first two cells are
+ * concatenated to form a 8 bytes value, where the first cell is top half and
+ * the second cell is bottom half.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param default_val default value to return if the property is not found
+ * @return integer value, if found, or default_val if not
+ */
+uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
+ uint64_t default_val);
+
+/**
+ * Checks whether a node is enabled.
+ * This looks for a 'status' property. If this exists, then returns 1 if
+ * the status is 'ok' and 0 otherwise. If there is no status property,
+ * it returns 1 on the assumption that anything mentioned should be enabled
+ * by default.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @return integer value 0 (not enabled) or 1 (enabled)
+ */
+int fdtdec_get_is_enabled(const void *blob, int node);
+
+/**
+ * Make sure we have a valid fdt available to control U-Boot.
+ *
+ * If not, a message is printed to the console if the console is ready.
+ *
+ * @return 0 if all ok, -1 if not
+ */
+int fdtdec_prepare_fdt(void);
+
+/**
+ * Checks that we have a valid fdt available to control U-Boot.
+
+ * However, if not then for the moment nothing is done, since this function
+ * is called too early to panic().
+ *
+ * @returns 0
+ */
+int fdtdec_check_fdt(void);
+
+/**
+ * Find the nodes for a peripheral and return a list of them in the correct
+ * order. This is used to enumerate all the peripherals of a certain type.
+ *
+ * To use this, optionally set up a /aliases node with alias properties for
+ * a peripheral. For example, for usb you could have:
+ *
+ * aliases {
+ * usb0 = "/ehci@c5008000";
+ * usb1 = "/ehci@c5000000";
+ * };
+ *
+ * Pass "usb" as the name to this function and will return a list of two
+ * nodes offsets: /ehci@c5008000 and ehci@c5000000.
+ *
+ * All nodes returned will match the compatible ID, as it is assumed that
+ * all peripherals use the same driver.
+ *
+ * If no alias node is found, then the node list will be returned in the
+ * order found in the fdt. If the aliases mention a node which doesn't
+ * exist, then this will be ignored. If nodes are found with no aliases,
+ * they will be added in any order.
+ *
+ * If there is a gap in the aliases, then this function return a 0 node at
+ * that position. The return value will also count these gaps.
+ *
+ * This function checks node properties and will not return nodes which are
+ * marked disabled (status = "disabled").
+ *
+ * @param blob FDT blob to use
+ * @param name Root name of alias to search for
+ * @param id Compatible ID to look for
+ * @param node_list Place to put list of found nodes
+ * @param maxcount Maximum number of nodes to find
+ * @return number of nodes found on success, FDT_ERR_... on error
+ */
+int fdtdec_find_aliases_for_id(const void *blob, const char *name,
+ enum fdt_compat_id id, int *node_list, int maxcount);
+
+/*
+ * This function is similar to fdtdec_find_aliases_for_id() except that it
+ * adds to the node_list that is passed in. Any 0 elements are considered
+ * available for allocation - others are considered already used and are
+ * skipped.
+ *
+ * You can use this by calling fdtdec_find_aliases_for_id() with an
+ * uninitialised array, then setting the elements that are returned to -1,
+ * say, then calling this function, perhaps with a different compat id.
+ * Any elements you get back that are >0 are new nodes added by the call
+ * to this function.
+ *
+ * Note that if you have some nodes with aliases and some without, you are
+ * sailing close to the wind. The call to fdtdec_find_aliases_for_id() with
+ * one compat_id may fill in positions for which you have aliases defined
+ * for another compat_id. When you later call *this* function with the second
+ * compat_id, the alias positions may already be used. A debug warning may
+ * be generated in this case, but it is safest to define aliases for all
+ * nodes when you care about the ordering.
+ */
+int fdtdec_add_aliases_for_id(const void *blob, const char *name,
+ enum fdt_compat_id id, int *node_list, int maxcount);
+
+/**
+ * Get the alias sequence number of a node
+ *
+ * This works out whether a node is pointed to by an alias, and if so, the
+ * sequence number of that alias. Aliases are of the form <base><num> where
+ * <num> is the sequence number. For example spi2 would be sequence number
+ * 2.
+ *
+ * @param blob Device tree blob (if NULL, then error is returned)
+ * @param base Base name for alias (before the underscore)
+ * @param node Node to look up
+ * @param seqp This is set to the sequence number if one is found,
+ * but otherwise the value is left alone
+ * @return 0 if a sequence was found, -ve if not
+ */
+int fdtdec_get_alias_seq(const void *blob, const char *base, int node,
+ int *seqp);
+
+/**
+ * Get the highest alias number for susbystem.
+ *
+ * It parses all aliases and find out highest recorded alias for subsystem.
+ * Aliases are of the form <base><num> where <num> is the sequence number.
+ *
+ * @param blob Device tree blob (if NULL, then error is returned)
+ * @param base Base name for alias susbystem (before the number)
+ *
+ * @return 0 highest alias ID, -1 if not found
+ */
+int fdtdec_get_alias_highest_id(const void *blob, const char *base);
+
+/**
+ * Get a property from the /chosen node
+ *
+ * @param blob Device tree blob (if NULL, then NULL is returned)
+ * @param name Property name to look up
+ * @return Value of property, or NULL if it does not exist
+ */
+const char *fdtdec_get_chosen_prop(const void *blob, const char *name);
+
+/**
+ * Get the offset of the given /chosen node
+ *
+ * This looks up a property in /chosen containing the path to another node,
+ * then finds the offset of that node.
+ *
+ * @param blob Device tree blob (if NULL, then error is returned)
+ * @param name Property name, e.g. "stdout-path"
+ * @return Node offset referred to by that chosen node, or -ve FDT_ERR_...
+ */
+int fdtdec_get_chosen_node(const void *blob, const char *name);
+
+/*
+ * Get the name for a compatible ID
+ *
+ * @param id Compatible ID to look for
+ * @return compatible string for that id
+ */
+const char *fdtdec_get_compatible(enum fdt_compat_id id);
+
+/* Look up a phandle and follow it to its node. Then return the offset
+ * of that node.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @return node offset if found, -ve error code on error
+ */
+int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name);
+
+/**
+ * Look up a property in a node and return its contents in an integer
+ * array of given length. The property must have at least enough data for
+ * the array (4*count bytes). It may have more, but this will be ignored.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param array array to fill with data
+ * @param count number of array elements
+ * @return 0 if ok, or -FDT_ERR_NOTFOUND if the property is not found,
+ * or -FDT_ERR_BADLAYOUT if not enough data
+ */
+int fdtdec_get_int_array(const void *blob, int node, const char *prop_name,
+ u32 *array, int count);
+
+/**
+ * Look up a property in a node and return its contents in an integer
+ * array of given length. The property must exist but may have less data that
+ * expected (4*count bytes). It may have more, but this will be ignored.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param array array to fill with data
+ * @param count number of array elements
+ * @return number of array elements if ok, or -FDT_ERR_NOTFOUND if the
+ * property is not found
+ */
+int fdtdec_get_int_array_count(const void *blob, int node,
+ const char *prop_name, u32 *array, int count);
+
+/**
+ * Look up a property in a node and return a pointer to its contents as a
+ * unsigned int array of given length. The property must have at least enough
+ * data for the array ('count' cells). It may have more, but this will be
+ * ignored. The data is not copied.
+ *
+ * Note that you must access elements of the array with fdt32_to_cpu(),
+ * since the elements will be big endian even on a little endian machine.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param count number of array elements
+ * @return pointer to array if found, or NULL if the property is not
+ * found or there is not enough data
+ */
+const u32 *fdtdec_locate_array(const void *blob, int node,
+ const char *prop_name, int count);
+
+/**
+ * Look up a boolean property in a node and return it.
+ *
+ * A boolean properly is true if present in the device tree and false if not
+ * present, regardless of its value.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @return 1 if the properly is present; 0 if it isn't present
+ */
+int fdtdec_get_bool(const void *blob, int node, const char *prop_name);
+
+/*
+ * Count child nodes of one parent node.
+ *
+ * @param blob FDT blob
+ * @param node parent node
+ * @return number of child node; 0 if there is not child node
+ */
+int fdtdec_get_child_count(const void *blob, int node);
+
+/**
+ * Look in the FDT for a config item with the given name and return its value
+ * as a 32-bit integer. The property must have at least 4 bytes of data. The
+ * value of the first cell is returned.
+ *
+ * @param blob FDT blob to use
+ * @param prop_name Node property name
+ * @param default_val default value to return if the property is not found
+ * @return integer value, if found, or default_val if not
+ */
+int fdtdec_get_config_int(const void *blob, const char *prop_name,
+ int default_val);
+
+/**
+ * Look in the FDT for a config item with the given name
+ * and return whether it exists.
+ *
+ * @param blob FDT blob
+ * @param prop_name property name to look up
+ * @return 1, if it exists, or 0 if not
+ */
+int fdtdec_get_config_bool(const void *blob, const char *prop_name);
+
+/**
+ * Look in the FDT for a config item with the given name and return its value
+ * as a string.
+ *
+ * @param blob FDT blob
+ * @param prop_name property name to look up
+ * @returns property string, NULL on error.
+ */
+char *fdtdec_get_config_string(const void *blob, const char *prop_name);
+
+/*
+ * Look up a property in a node and return its contents in a byte
+ * array of given length. The property must have at least enough data for
+ * the array (count bytes). It may have more, but this will be ignored.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param array array to fill with data
+ * @param count number of array elements
+ * @return 0 if ok, or -FDT_ERR_MISSING if the property is not found,
+ * or -FDT_ERR_BADLAYOUT if not enough data
+ */
+int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name,
+ u8 *array, int count);
+
+/**
+ * Look up a property in a node and return a pointer to its contents as a
+ * byte array of given length. The property must have at least enough data
+ * for the array (count bytes). It may have more, but this will be ignored.
+ * The data is not copied.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param count number of array elements
+ * @return pointer to byte array if found, or NULL if the property is not
+ * found or there is not enough data
+ */
+const u8 *fdtdec_locate_byte_array(const void *blob, int node,
+ const char *prop_name, int count);
+
+/**
+ * Obtain an indexed resource from a device property.
+ *
+ * @param fdt FDT blob
+ * @param node node to examine
+ * @param property name of the property to parse
+ * @param index index of the resource to retrieve
+ * @param res returns the resource
+ * @return 0 if ok, negative on error
+ */
+int fdt_get_resource(const void *fdt, int node, const char *property,
+ unsigned int index, struct fdt_resource *res);
+
+/**
+ * Obtain a named resource from a device property.
+ *
+ * Look up the index of the name in a list of strings and return the resource
+ * at that index.
+ *
+ * @param fdt FDT blob
+ * @param node node to examine
+ * @param property name of the property to parse
+ * @param prop_names name of the property containing the list of names
+ * @param name the name of the entry to look up
+ * @param res returns the resource
+ */
+int fdt_get_named_resource(const void *fdt, int node, const char *property,
+ const char *prop_names, const char *name,
+ struct fdt_resource *res);
+
+/* Display timings from linux include/video/display_timing.h */
+enum display_flags {
+ DISPLAY_FLAGS_HSYNC_LOW = 1 << 0,
+ DISPLAY_FLAGS_HSYNC_HIGH = 1 << 1,
+ DISPLAY_FLAGS_VSYNC_LOW = 1 << 2,
+ DISPLAY_FLAGS_VSYNC_HIGH = 1 << 3,
+
+ /* data enable flag */
+ DISPLAY_FLAGS_DE_LOW = 1 << 4,
+ DISPLAY_FLAGS_DE_HIGH = 1 << 5,
+ /* drive data on pos. edge */
+ DISPLAY_FLAGS_PIXDATA_POSEDGE = 1 << 6,
+ /* drive data on neg. edge */
+ DISPLAY_FLAGS_PIXDATA_NEGEDGE = 1 << 7,
+ DISPLAY_FLAGS_INTERLACED = 1 << 8,
+ DISPLAY_FLAGS_DOUBLESCAN = 1 << 9,
+ DISPLAY_FLAGS_DOUBLECLK = 1 << 10,
+};
+
+/*
+ * 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 {
+ u32 min;
+ u32 typ;
+ u32 max;
+};
+
+/*
+ * Single "mode" entry. This describes one set of signal timings a display can
+ * have in one setting. This struct can later be converted to struct videomode
+ * (see include/video/videomode.h). As each timing_entry can be defined as a
+ * range, one struct display_timing may become multiple struct videomodes.
+ *
+ * Example: hsync active high, vsync active low
+ *
+ * Active Video
+ * Video ______________________XXXXXXXXXXXXXXXXXXXXXX_____________________
+ * |<- sync ->|<- back ->|<----- active ----->|<- front ->|<- sync..
+ * | | porch | | porch |
+ *
+ * HSync _|炉炉炉炉炉炉炉炉炉炉|___________________________________________|炉炉炉炉炉炉炉炉炉
+ *
+ * VSync 炉|__________|炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉炉|_________
+ */
+struct display_timing {
+ struct timing_entry pixelclock;
+
+ struct timing_entry hactive; /* hor. active video */
+ struct timing_entry hfront_porch; /* hor. front porch */
+ struct timing_entry hback_porch; /* hor. back porch */
+ struct timing_entry hsync_len; /* hor. sync len */
+
+ struct timing_entry vactive; /* ver. active video */
+ struct timing_entry vfront_porch; /* ver. front porch */
+ struct timing_entry vback_porch; /* ver. back porch */
+ struct timing_entry vsync_len; /* ver. sync len */
+
+ enum display_flags flags; /* display flags */
+ bool hdmi_monitor; /* is hdmi monitor? */
+};
+
+/**
+ * fdtdec_decode_display_timing() - decode display timings
+ *
+ * Decode display timings from the supplied 'display-timings' node.
+ * See doc/device-tree-bindings/video/display-timing.txt for binding
+ * information.
+ *
+ * @param blob FDT blob
+ * @param node 'display-timing' node containing the timing subnodes
+ * @param index Index number to read (0=first timing subnode)
+ * @param config Place to put timings
+ * @return 0 if OK, -FDT_ERR_NOTFOUND if not found
+ */
+int fdtdec_decode_display_timing(const void *blob, int node, int index,
+ struct display_timing *config);
+
+/**
+ * fdtdec_setup_mem_size_base() - decode and setup gd->ram_size and
+ * gd->ram_start
+ *
+ * Decode the /memory 'reg' property to determine the size and start of the
+ * first memory bank, populate the global data with the size and start of the
+ * first bank of memory.
+ *
+ * This function should be called from a boards dram_init(). This helper
+ * function allows for boards to query the device tree for DRAM size and start
+ * address instead of hard coding the value in the case where the memory size
+ * and start address cannot be detected automatically.
+ *
+ * @return 0 if OK, -EINVAL if the /memory node or reg property is missing or
+ * invalid
+ */
+int fdtdec_setup_mem_size_base(void);
+
+/**
+ * fdtdec_setup_memory_banksize() - decode and populate gd->bd->bi_dram
+ *
+ * Decode the /memory 'reg' property to determine the address and size of the
+ * memory banks. Use this data to populate the global data board info with the
+ * phys address and size of memory banks.
+ *
+ * This function should be called from a boards dram_init_banksize(). This
+ * helper function allows for boards to query the device tree for memory bank
+ * information instead of hard coding the information in cases where it cannot
+ * be detected automatically.
+ *
+ * @return 0 if OK, -EINVAL if the /memory node or reg property is missing or
+ * invalid
+ */
+int fdtdec_setup_memory_banksize(void);
+
+/**
+ * Set up the device tree ready for use
+ */
+int fdtdec_setup(void);
+
+#ifndef SYLIXOS
+#if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
+/**
+ * fdtdec_resetup() - Set up the device tree again
+ *
+ * The main difference with fdtdec_setup() is that it returns if the fdt has
+ * changed because a better match has been found.
+ * This is typically used for boards that rely on a DM driver to detect the
+ * board type. This function sould be called by the board code after the stuff
+ * needed by board_fit_config_name_match() to operate porperly is available.
+ * If this functions signals that a rescan is necessary, the board code must
+ * unbind all the drivers using dm_uninit() and then rescan the DT with
+ * dm_init_and_scan().
+ *
+ * @param rescan Returns a flag indicating that fdt has changed and rescanning
+ * the fdt is required
+ *
+ * @return 0 if OK, -ve on error
+ */
+int fdtdec_resetup(int *rescan);
+#endif
+#endif
+
+/**
+ * Board-specific FDT initialization. Returns the address to a device tree blob.
+ * Called when CONFIG_OF_BOARD is defined, or if CONFIG_OF_SEPARATE is defined
+ * and the board implements it.
+ */
+void *board_fdt_blob_setup(void);
+
+/*
+ * Decode the size of memory
+ *
+ * RAM size is normally set in a /memory node and consists of a list of
+ * (base, size) cells in the 'reg' property. This information is used to
+ * determine the total available memory as well as the address and size
+ * of each bank.
+ *
+ * Optionally the memory configuration can vary depending on a board id,
+ * typically read from strapping resistors or an EEPROM on the board.
+ *
+ * Finally, memory size can be detected (within certain limits) by probing
+ * the available memory. It is safe to do so within the limits provides by
+ * the board's device tree information. This makes it possible to produce
+ * boards with different memory sizes, where the device tree specifies the
+ * maximum memory configuration, and the smaller memory configuration is
+ * probed.
+ *
+ * This function decodes that information, returning the memory base address,
+ * size and bank information. See the memory.txt binding for full
+ * documentation.
+ *
+ * @param blob Device tree blob
+ * @param area Name of node to check (NULL means "/memory")
+ * @param board_id Board ID to look up
+ * @param basep Returns base address of first memory bank (NULL to
+ * ignore)
+ * @param sizep Returns total memory size (NULL to ignore)
+ * @param bd Updated with the memory bank information (NULL to skip)
+ * @return 0 if OK, -ve on error
+ */
+int fdtdec_decode_ram_size(const void *blob, const char *area, int board_id,
+ phys_addr_t *basep, phys_size_t *sizep,
+ struct bd_info *bd);
+
+#endif
diff --git a/SylixOS/driver/fdt/fdtdec_common.c b/SylixOS/driver/fdt/fdtdec_common.c
new file mode 100644
index 0000000..518f132
--- /dev/null
+++ b/SylixOS/driver/fdt/fdtdec_common.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2014
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ *
+ * Based on lib/fdtdec.c:
+ * Copyright (c) 2011 The Chromium OS Authors.
+ */
+
+#ifndef SYLIXOS
+#ifndef USE_HOSTCC
+#include <common.h>
+#include <linux/libfdt.h>
+#include <fdtdec.h>
+#else
+#include "libfdt.h"
+#include "fdt_support.h"
+
+#define debug(...)
+#endif
+#else
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_STDIO
+#include <SylixOS.h>
+#include <linux/compat.h>
+#include "libfdt.h"
+#include "fdt_support.h"
+
+#define debug(...)
+#endif
+
+int fdtdec_get_int(const void *blob, int node, const char *prop_name,
+ int default_val)
+{
+ const int *cell;
+ int len;
+
+ debug("%s: %s: ", __func__, prop_name);
+ cell = fdt_getprop(blob, node, prop_name, &len);
+ if (cell && len >= sizeof(int)) {
+ int val = fdt32_to_cpu(cell[0]);
+
+ debug("%#x (%d)\n", val, val);
+ return val;
+ }
+ debug("(not found)\n");
+ return default_val;
+}
+
+unsigned int fdtdec_get_uint(const void *blob, int node, const char *prop_name,
+ unsigned int default_val)
+{
+ const int *cell;
+ int len;
+
+ debug("%s: %s: ", __func__, prop_name);
+ cell = fdt_getprop(blob, node, prop_name, &len);
+ if (cell && len >= sizeof(unsigned int)) {
+ unsigned int val = fdt32_to_cpu(cell[0]);
+
+ debug("%#x (%d)\n", val, val);
+ return val;
+ }
+ debug("(not found)\n");
+ return default_val;
+}
diff --git a/SylixOS/driver/fdt/libfdt.h b/SylixOS/driver/fdt/libfdt.h
index 7f83023..5614513 100644
--- a/SylixOS/driver/fdt/libfdt.h
+++ b/SylixOS/driver/fdt/libfdt.h
@@ -1,5 +1,5 @@
-#ifndef _LIBFDT_H
-#define _LIBFDT_H
+#ifndef LIBFDT_H
+#define LIBFDT_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
@@ -54,7 +54,7 @@
#include "libfdt_env.h"
#include "fdt.h"
-#define FDT_FIRST_SUPPORTED_VERSION 0x10
+#define FDT_FIRST_SUPPORTED_VERSION 0x02
#define FDT_LAST_SUPPORTED_VERSION 0x11
/* Error codes: informative error codes */
@@ -90,8 +90,9 @@
/* Error codes: codes for bad device tree blobs */
#define FDT_ERR_TRUNCATED 8
- /* FDT_ERR_TRUNCATED: Structure block of the given device tree
- * ends without an FDT_END tag. */
+ /* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly
+ * terminated (overflows, goes outside allowed bounds, or
+ * isn't properly terminated). */
#define FDT_ERR_BADMAGIC 9
/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
* device tree at all - it is missing the flattened device
@@ -139,6 +140,10 @@
#define FDT_ERR_MAX 17
+/* constants */
+#define FDT_MAX_PHANDLE 0xfffffffe
+ /* Valid values for phandles range from 1 to 2^32-2. */
+
/**********************************************************************/
/* Low-level functions (you probably don't need these) */
/**********************************************************************/
@@ -153,6 +158,61 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+/*
+ * Alignment helpers:
+ * These helpers access words from a device tree blob. They're
+ * built to work even with unaligned pointers on platforms (ike
+ * ARM) that don't like unaligned loads and stores
+ */
+
+static inline uint32_t fdt32_ld(const fdt32_t *p)
+{
+ const uint8_t *bp = (const uint8_t *)p;
+
+ return ((uint32_t)bp[0] << 24)
+ | ((uint32_t)bp[1] << 16)
+ | ((uint32_t)bp[2] << 8)
+ | bp[3];
+}
+
+static inline void fdt32_st(void *property, uint32_t value)
+{
+ uint8_t *bp = property;
+
+ bp[0] = value >> 24;
+ bp[1] = (value >> 16) & 0xff;
+ bp[2] = (value >> 8) & 0xff;
+ bp[3] = value & 0xff;
+}
+
+static inline uint64_t fdt64_ld(const fdt64_t *p)
+{
+ const uint8_t *bp = (const uint8_t *)p;
+
+ return ((uint64_t)bp[0] << 56)
+ | ((uint64_t)bp[1] << 48)
+ | ((uint64_t)bp[2] << 40)
+ | ((uint64_t)bp[3] << 32)
+ | ((uint64_t)bp[4] << 24)
+ | ((uint64_t)bp[5] << 16)
+ | ((uint64_t)bp[6] << 8)
+ | bp[7];
+}
+
+static inline void fdt64_st(void *property, uint64_t value)
+{
+ uint8_t *bp = property;
+
+ bp[0] = value >> 56;
+ bp[1] = (value >> 48) & 0xff;
+ bp[2] = (value >> 40) & 0xff;
+ bp[3] = (value >> 32) & 0xff;
+ bp[4] = (value >> 24) & 0xff;
+ bp[5] = (value >> 16) & 0xff;
+ bp[6] = (value >> 8) & 0xff;
+ bp[7] = value & 0xff;
+}
+
/**********************************************************************/
/* Traversal functions */
/**********************************************************************/
@@ -195,7 +255,7 @@ int fdt_next_subnode(const void *fdt, int offset);
* ...
* }
*
- * if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) {
+ * if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) {
* Error handling
* }
*
@@ -213,7 +273,7 @@ int fdt_next_subnode(const void *fdt, int offset);
/* General functions */
/**********************************************************************/
#define fdt_get_header(fdt, field) \
- (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+ (fdt32_ld(&((const struct fdt_header *)(fdt))->field))
#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
@@ -225,37 +285,50 @@ int fdt_next_subnode(const void *fdt, int offset);
#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
-#define __fdt_set_hdr(name) \
+#define fdt_set_hdr_(name) \
static inline void fdt_set_##name(void *fdt, uint32_t val) \
{ \
struct fdt_header *fdth = (struct fdt_header *)fdt; \
fdth->name = cpu_to_fdt32(val); \
}
-__fdt_set_hdr(magic);
-__fdt_set_hdr(totalsize);
-__fdt_set_hdr(off_dt_struct);
-__fdt_set_hdr(off_dt_strings);
-__fdt_set_hdr(off_mem_rsvmap);
-__fdt_set_hdr(version);
-__fdt_set_hdr(last_comp_version);
-__fdt_set_hdr(boot_cpuid_phys);
-__fdt_set_hdr(size_dt_strings);
-__fdt_set_hdr(size_dt_struct);
-#undef __fdt_set_hdr
-
-/**
- * fdt_check_header - sanity check a device tree or possible device tree
+fdt_set_hdr_(magic);
+fdt_set_hdr_(totalsize);
+fdt_set_hdr_(off_dt_struct);
+fdt_set_hdr_(off_dt_strings);
+fdt_set_hdr_(off_mem_rsvmap);
+fdt_set_hdr_(version);
+fdt_set_hdr_(last_comp_version);
+fdt_set_hdr_(boot_cpuid_phys);
+fdt_set_hdr_(size_dt_strings);
+fdt_set_hdr_(size_dt_struct);
+#undef fdt_set_hdr_
+
+/**
+ * fdt_header_size - return the size of the tree's header
+ * @fdt: pointer to a flattened device tree
+ */
+size_t fdt_header_size_(uint32_t version);
+static inline size_t fdt_header_size(const void *fdt)
+{
+ return fdt_header_size_(fdt_version(fdt));
+}
+
+/**
+ * fdt_check_header - sanity check a device tree header
+
* @fdt: pointer to data which might be a flattened device tree
*
* fdt_check_header() checks that the given buffer contains what
- * appears to be a flattened device tree with sane information in its
- * header.
+ * appears to be a flattened device tree, and that the header contains
+ * valid information (to the extent that can be determined from the
+ * header alone).
*
* returns:
* 0, if the buffer appears to contain a valid device tree
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
- * -FDT_ERR_BADSTATE, standard meanings, as above
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_TRUNCATED, standard meanings, as above
*/
int fdt_check_header(const void *fdt);
@@ -284,6 +357,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
/* Read-only functions */
/**********************************************************************/
+int fdt_check_full(const void *fdt, size_t bufsize);
+
+/**
+ * fdt_get_string - retrieve a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ * @lenp: optional pointer to return the string's length
+ *
+ * fdt_get_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt, and optionally also
+ * returns the string's length in *lenp.
+ *
+ * returns:
+ * a pointer to the string, on success
+ * NULL, if stroffset is out of bounds, or doesn't point to a valid string
+ */
+const char *fdt_get_string(const void *fdt, int stroffset, int *lenp);
+
/**
* fdt_string - retrieve a string from the strings block of a device tree
* @fdt: pointer to the device tree blob
@@ -294,11 +385,25 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
*
* returns:
* a pointer to the string, on success
- * NULL, if stroffset is out of bounds
+ * NULL, if stroffset is out of bounds, or doesn't point to a valid string
*/
const char *fdt_string(const void *fdt, int stroffset);
/**
+ * fdt_find_max_phandle - find and return the highest phandle in a tree
+ * @fdt: pointer to the device tree blob
+ * @phandle: return location for the highest phandle value found in the tree
+ *
+ * fdt_find_max_phandle() finds the highest phandle value in the given device
+ * tree. The value returned in @phandle is only valid if the function returns
+ * success.
+ *
+ * returns:
+ * 0 on success or a negative error code on failure
+ */
+int fdt_find_max_phandle(const void *fdt, uint32_t *phandle);
+
+/**
* fdt_get_max_phandle - retrieves the highest phandle in a tree
* @fdt: pointer to the device tree blob
*
@@ -306,12 +411,39 @@ const char *fdt_string(const void *fdt, int stroffset);
* device tree. This will ignore badly formatted phandles, or phandles
* with a value of 0 or -1.
*
+ * This function is deprecated in favour of fdt_find_max_phandle().
+ *
* returns:
* the highest phandle on success
* 0, if no phandle was found in the device tree
* -1, if an error occurred
*/
-uint32_t fdt_get_max_phandle(const void *fdt);
+static inline uint32_t fdt_get_max_phandle(const void *fdt)
+{
+ uint32_t phandle;
+ int err;
+
+ err = fdt_find_max_phandle(fdt, &phandle);
+ if (err < 0)
+ return (uint32_t)-1;
+
+ return phandle;
+}
+
+/**
+ * fdt_generate_phandle - return a new, unused phandle for a device tree blob
+ * @fdt: pointer to the device tree blob
+ * @phandle: return location for the new phandle
+ *
+ * Walks the device tree blob and looks for the highest phandle value. On
+ * success, the new, unused phandle value (one higher than the previously
+ * highest phandle value in the device tree blob) will be returned in the
+ * @phandle parameter.
+ *
+ * Returns:
+ * 0 on success or a negative error-code on failure
+ */
+int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
/**
* fdt_num_mem_rsv - retrieve the number of memory reserve map entries
@@ -503,7 +635,7 @@ int fdt_next_property_offset(const void *fdt, int offset);
* ...
* }
*
- * if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) {
+ * if ((property < 0) && (property != -FDT_ERR_NOTFOUND)) {
* Error handling
* }
*
@@ -527,6 +659,9 @@ int fdt_next_property_offset(const void *fdt, int offset);
* offset. If lenp is non-NULL, the length of the property value is
* also returned, in the integer pointed to by lenp.
*
+ * Note that this code only works on device tree versions >= 16. fdt_getprop()
+ * works on all versions.
+ *
* returns:
* pointer to the structure representing the property
* if lenp is non-NULL, *lenp contains the length of the property
@@ -603,7 +738,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
/**
* fdt_getprop_by_offset - retrieve the value of a property at a given offset
* @fdt: pointer to the device tree blob
- * @ffset: offset of the property to read
+ * @offset: offset of the property to read
* @namep: pointer to a string variable (will be overwritten) or NULL
* @lenp: pointer to an integer variable (will be overwritten) or NULL
*
@@ -1087,7 +1222,7 @@ int fdt_address_cells(const void *fdt, int nodeoffset);
*
* returns:
* 0 <= n < FDT_MAX_NCELLS, on success
- * 2, if the node has no #address-cells property
+ * 1, if the node has no #size-cells property
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
* #size-cells property
* -FDT_ERR_BADMAGIC,
@@ -1310,10 +1445,13 @@ static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val)
fdt64_t tmp = cpu_to_fdt64(val);
return fdt_property(fdt, name, &tmp, sizeof(tmp));
}
+
+#ifndef SWIG /* Not available in Python */
static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
{
return fdt_property_u32(fdt, name, val);
}
+#endif
/**
* fdt_property_placeholder - add a new property and return a ptr to its value
@@ -1449,7 +1587,7 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len);
/**
- * fdt_setprop _placeholder - allocate space for a property
+ * fdt_setprop_placeholder - allocate space for a property
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to change
@@ -1763,6 +1901,43 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
/**
+ * fdt_appendprop_addrrange - append a address range property
+ * @fdt: pointer to the device tree blob
+ * @parent: offset of the parent node
+ * @nodeoffset: offset of the node to add a property at
+ * @name: name of property
+ * @addr: start address of a given range
+ * @size: size of a given range
+ *
+ * fdt_appendprop_addrrange() appends an address range value (start
+ * address and size) to the value of the named property in the given
+ * node, or creates a new property with that value if it does not
+ * already exist.
+ * If "name" is not specified, a default "reg" is used.
+ * Cell sizes are determined by parent's #address-cells and #size-cells.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ * #address-cells property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain a new property
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
+ const char *name, uint64_t addr, uint64_t size);
+
+/**
* fdt_delprop - delete a property
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to nop
@@ -1896,4 +2071,4 @@ int fdt_overlay_apply(void *fdt, void *fdto);
const char *fdt_strerror(int errval);
-#endif /* _LIBFDT_H */
+#endif /* LIBFDT_H */
diff --git a/SylixOS/driver/fdt/libfdt_env.h b/SylixOS/driver/fdt/libfdt_env.h
index 952056c..4d1cdfa 100644
--- a/SylixOS/driver/fdt/libfdt_env.h
+++ b/SylixOS/driver/fdt/libfdt_env.h
@@ -1,5 +1,5 @@
-#ifndef _LIBFDT_ENV_H
-#define _LIBFDT_ENV_H
+#ifndef LIBFDT_ENV_H
+#define LIBFDT_ENV_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
@@ -52,10 +52,12 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#ifdef __CHECKER__
#define FDT_FORCE __attribute__((force))
@@ -109,4 +111,31 @@ static inline fdt64_t cpu_to_fdt64(uint64_t x)
#undef CPU_TO_FDT16
#undef EXTRACT_BYTE
-#endif /* _LIBFDT_ENV_H */
+#ifdef __APPLE__
+#include <AvailabilityMacros.h>
+
+/* strnlen() is not available on Mac OS < 10.7 */
+# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \
+ MAC_OS_X_VERSION_10_7)
+
+#define strnlen fdt_strnlen
+
+/*
+ * fdt_strnlen: returns the length of a string or max_count - which ever is
+ * smallest.
+ * Input 1 string: the string whose size is to be determined
+ * Input 2 max_count: the maximum value returned by this function
+ * Output: length of the string or max_count (the smallest of the two)
+ */
+static inline size_t fdt_strnlen(const char *string, size_t max_count)
+{
+ const char *p = memchr(string, 0, max_count);
+ return p ? p - string : max_count;
+}
+
+#endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED <
+ MAC_OS_X_VERSION_10_7) */
+
+#endif /* __APPLE__ */
+
+#endif /* LIBFDT_ENV_H */
diff --git a/SylixOS/driver/fdt/libfdt_internal.h b/SylixOS/driver/fdt/libfdt_internal.h
index 02cfa6f..6230538 100644
--- a/SylixOS/driver/fdt/libfdt_internal.h
+++ b/SylixOS/driver/fdt/libfdt_internal.h
@@ -1,5 +1,5 @@
-#ifndef _LIBFDT_INTERNAL_H
-#define _LIBFDT_INTERNAL_H
+#ifndef LIBFDT_INTERNAL_H
+#define LIBFDT_INTERNAL_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
@@ -50,34 +50,35 @@
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <fdt.h>
+#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 fdt_ro_probe_(const void *fdt);
+#define FDT_RO_PROBE(fdt) \
{ \
- int __err; \
- if ((__err = fdt_check_header(fdt)) != 0) \
- return __err; \
+ int err_; \
+ if ((err_ = fdt_ro_probe_(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);
+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)
+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)
+static inline void *fdt_offset_ptr_w_(void *fdt, int offset)
{
- return (void *)(uintptr_t)_fdt_offset_ptr(fdt, 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)
+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 *)
@@ -85,11 +86,11 @@ static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int
return rsv_table + n;
}
-static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
+static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
{
- return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
+ return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n);
}
#define FDT_SW_MAGIC (~FDT_MAGIC)
-#endif /* _LIBFDT_INTERNAL_H */
+#endif /* LIBFDT_INTERNAL_H */
diff --git a/SylixOS/driver/sio/16c550.c b/SylixOS/driver/sio/16c550.c
index 72564cb..1bd6b03 100644
--- a/SylixOS/driver/sio/16c550.c
+++ b/SylixOS/driver/sio/16c550.c
@@ -1183,6 +1183,11 @@ VOID sio16c550Isr (SIO16C550_CHAN *psiochan)
LW_SPIN_UNLOCK_QUICK(&psiochan->slock, intreg);
break;
+ case IIR_BUSY:
+ GET_REG(psiochan, USR);
+ LW_SPIN_UNLOCK_QUICK(&psiochan->slock, intreg);
+ break;
+
default:
SET_REG(psiochan, IER, psiochan->ier); /* update ier */
LW_SPIN_UNLOCK_QUICK(&psiochan->slock, intreg);
diff --git a/SylixOS/driver/sio/16c550.h b/SylixOS/driver/sio/16c550.h
index 9962bde..8753c5c 100644
--- a/SylixOS/driver/sio/16c550.h
+++ b/SylixOS/driver/sio/16c550.h
@@ -41,6 +41,7 @@
#define LSR 0x05 /* line status register */
#define MSR 0x06 /* modem status register */
#define SCR 0x07 /* scratch register */
+#define USR 0x1f /* uart status register */
#define BAUD_LO(uart_freq, baud) ((uart_freq / (16 * baud)) & 0xff)
#define BAUD_HI(uart_freq, baud) (((uart_freq / (16 * baud)) & 0xff00) >> 8)
@@ -90,6 +91,7 @@
#define IIR_THRE 0x02 /* transmit holding register empty */
#define TxFIFO_INT IIR_THRE
#define IIR_MSTAT 0x00 /* modem status */
+#define IIR_BUSY 0x07 /* busy detect */
#define IIR_TIMEOUT 0x0c /* char receive timeout */
/*********************************************************************************************************
diff --git a/SylixOS/hosttools/makedtc/dtc.exe b/SylixOS/hosttools/makedtc/dtc.exe
new file mode 100644
index 0000000..634e58b
--- /dev/null
+++ b/SylixOS/hosttools/makedtc/dtc.exe
Binary files differ
diff --git a/SylixOS/hosttools/makedtc/fdtdump.exe b/SylixOS/hosttools/makedtc/fdtdump.exe
new file mode 100644
index 0000000..a967595
--- /dev/null
+++ b/SylixOS/hosttools/makedtc/fdtdump.exe
Binary files differ
diff --git a/SylixOS/hosttools/makedtc/fdtget.exe b/SylixOS/hosttools/makedtc/fdtget.exe
new file mode 100644
index 0000000..c4b9550
--- /dev/null
+++ b/SylixOS/hosttools/makedtc/fdtget.exe
Binary files differ
diff --git a/SylixOS/hosttools/makedtc/fdtoverlay.exe b/SylixOS/hosttools/makedtc/fdtoverlay.exe
new file mode 100644
index 0000000..745d46b
--- /dev/null
+++ b/SylixOS/hosttools/makedtc/fdtoverlay.exe
Binary files differ
diff --git a/SylixOS/hosttools/makedtc/fdtput.exe b/SylixOS/hosttools/makedtc/fdtput.exe
new file mode 100644
index 0000000..ff285b3
--- /dev/null
+++ b/SylixOS/hosttools/makedtc/fdtput.exe
Binary files differ
diff --git a/SylixOS/hosttools/makedtc/libfdt-1.6.0.so b/SylixOS/hosttools/makedtc/libfdt-1.6.0.so
new file mode 100644
index 0000000..e7f43f2
--- /dev/null
+++ b/SylixOS/hosttools/makedtc/libfdt-1.6.0.so
Binary files differ
diff --git a/SylixOS/include/network/lwip/netif.h b/SylixOS/include/network/lwip/netif.h
index 9721505..fd387e6 100644
--- a/SylixOS/include/network/lwip/netif.h
+++ b/SylixOS/include/network/lwip/netif.h
@@ -616,7 +616,8 @@ char * netif_index_to_name(u8_t idx, char *name);
struct netif* netif_get_by_index(u8_t idx);
#ifdef SYLIXOS /* SylixOS Add these function */
-#define LWIP_NETIF_TCP_ACK_FREQ_MIN 2
+#define LWIP_NETIF_TCP_ACK_FREQ_MIN 1
+#define LWIP_NETIF_TCP_ACK_FREQ_DEF 2
#define LWIP_NETIF_TCP_ACK_FREQ_MAX 127
#define netif_set_tcp_ack_freq(netif, tcpaf) ((netif)->tcp_ack_freq = tcpaf)
diff --git a/SylixOS/include/network/lwip/opt.h b/SylixOS/include/network/lwip/opt.h
index a3460f8..b2b1d14 100644
--- a/SylixOS/include/network/lwip/opt.h
+++ b/SylixOS/include/network/lwip/opt.h
@@ -505,7 +505,7 @@
* The number of sys timeouts used by the core stack (not apps)
* The default number of timeouts is calculated here for all enabled modules.
*/
-#define LWIP_NUM_SYS_TIMEOUT_INTERNAL (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_NUM_TIMEOUTS + (LWIP_IPV6 * (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD)))
+#define LWIP_NUM_SYS_TIMEOUT_INTERNAL (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_NUM_TIMEOUTS + (LWIP_IPV6 * (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD + LWIP_IPV6_DHCP6)))
/**
* MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active timeouts.
@@ -1563,7 +1563,7 @@
* TCP_MSS, IP header, and link header.
*/
#if !defined PBUF_POOL_BUFSIZE || defined __DOXYGEN__
-#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN)
+#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+PBUF_IP_HLEN+PBUF_TRANSPORT_HLEN+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN)
#endif
/**
@@ -2483,7 +2483,7 @@
* network startup.
*/
#if !defined LWIP_IPV6_SEND_ROUTER_SOLICIT || defined __DOXYGEN__
-#define LWIP_IPV6_SEND_ROUTER_SOLICIT 1
+#define LWIP_IPV6_SEND_ROUTER_SOLICIT LWIP_IPV6
#endif
/**
diff --git a/SylixOS/include/network/lwip/sio.h b/SylixOS/include/network/lwip/sio.h
index 7643e19..12d2a7e 100644
--- a/SylixOS/include/network/lwip/sio.h
+++ b/SylixOS/include/network/lwip/sio.h
@@ -123,7 +123,7 @@ u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len);
*
* @note This function will block until all data can be sent.
*/
-u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len);
+u32_t sio_write(sio_fd_t fd, const u8_t *data, u32_t len);
#endif
#ifndef sio_read_abort
diff --git a/SylixOS/include/network/netif/ppp/ppp.h b/SylixOS/include/network/netif/ppp/ppp.h
index 3d73c36..f93747f 100644
--- a/SylixOS/include/network/netif/ppp/ppp.h
+++ b/SylixOS/include/network/netif/ppp/ppp.h
@@ -266,9 +266,9 @@ typedef struct ppp_settings_s {
#endif /* PAP_SUPPPORT */
#if CHAP_SUPPORT
+#if PPP_SERVER
u8_t chap_timeout_time; /* Timeout (seconds) for retransmitting req */
u8_t chap_max_transmits; /* max # times to send challenge */
-#if PPP_SERVER
u8_t chap_rechallenge_time; /* Time to wait for auth-req from peer */
#endif /* PPP_SERVER */
#endif /* CHAP_SUPPPORT */
diff --git a/SylixOS/include/network/netif/ppp/ppp_impl.h b/SylixOS/include/network/netif/ppp/ppp_impl.h
index 8d4d834..2282831 100644
--- a/SylixOS/include/network/netif/ppp/ppp_impl.h
+++ b/SylixOS/include/network/netif/ppp/ppp_impl.h
@@ -60,16 +60,10 @@ extern "C" {
/*
* Memory used for control packets.
*
- * PPP_CTRL_PBUF_MAX_SIZE is the amount of memory we allocate when we
+ * PPP_CTRL_PBUF_UNKNOWN_SIZE is the amount of memory we allocate when we
* cannot figure out how much we are going to use before filling the buffer.
*/
-#if PPP_USE_PBUF_RAM
-#define PPP_CTRL_PBUF_TYPE PBUF_RAM
-#define PPP_CTRL_PBUF_MAX_SIZE 512
-#else /* PPP_USE_PBUF_RAM */
-#define PPP_CTRL_PBUF_TYPE PBUF_POOL
-#define PPP_CTRL_PBUF_MAX_SIZE PBUF_POOL_BUFSIZE
-#endif /* PPP_USE_PBUF_RAM */
+#define PPP_CTRL_PBUF_UNKNOWN_SIZE 512
/*
* The basic PPP frame.
@@ -88,9 +82,17 @@ extern "C" {
#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */
/*
+ * PPP_DEFMRU: MRU value used prior negotiation and unless negotiated later.
+ * Must be 1500.
+ */
+#define PPP_DEFMRU 1500
+
+/*
* Protocol field values.
*/
+#if PPP_IPV4_SUPPORT
#define PPP_IP 0x21 /* Internet Protocol */
+#endif /* PPP_IPV4_SUPPORT */
#if 0 /* UNUSED */
#define PPP_AT 0x29 /* AppleTalk Protocol */
#define PPP_IPX 0x2b /* IPX protocol */
@@ -456,8 +458,8 @@ int sif6down (ppp_pcb *pcb);
int sifnpmode(ppp_pcb *pcb, int proto, enum NPmode mode);
#endif /* DEMAND_SUPPORt */
-void netif_set_mtu(ppp_pcb *pcb, int mtu);
-int netif_get_mtu(ppp_pcb *pcb);
+void ppp_netif_set_mtu(ppp_pcb *pcb, int mtu);
+int ppp_netif_get_mtu(ppp_pcb *pcb);
#if CCP_SUPPORT
#if 0 /* unused */
@@ -559,7 +561,7 @@ void start_networks(ppp_pcb *pcb); /* start all the network control protos */
void continue_networks(ppp_pcb *pcb); /* start network [ip, etc] control protos */
#if PPP_AUTH_SUPPORT
#if PPP_SERVER
-int auth_check_passwd(ppp_pcb *pcb, char *auser, int userlen, char *apasswd, int passwdlen, const char **msg, int *msglen);
+int auth_check_passwd(ppp_pcb *pcb, char *auser, unsigned int userlen, char *apasswd, unsigned int passwdlen, const char **msg, int *msglen);
/* check the user name and passwd against configuration */
void auth_peer_fail(ppp_pcb *pcb, int protocol);
/* peer failed to authenticate itself */
@@ -672,11 +674,10 @@ void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len);
* |. . .
* | . .
* PPP_PHASE_AUTHENTICATE
- * | . .
* || . .
* PPP_PHASE_NETWORK
- * | || . .
- * | ||| .
+ * |||| . .
+ * || ||| .
* PPP_PHASE_RUNNING
* | .|||||
* | . ||||
@@ -692,33 +693,39 @@ void ppp_dump_packet(ppp_pcb *pcb, const char *tag, unsigned char *p, int len);
* 1
*
* If authentication is enabled one timer is necessary during authentication.
+ * This timer might still be running up to network phase for any necessary
+ * rechallenge, mostly for PPP server support.
* 1 + PPP_AUTH_SUPPORT
*
* If ECP is enabled one timer is necessary before IPCP and/or IP6CP, one more
* is necessary if CCP is enabled (only with MPPE support but we don't care much
* up to this detail level).
- * 1 + ECP_SUPPORT + CCP_SUPPORT
+ * 1 + PPP_AUTH_SUPPORT + ECP_SUPPORT + CCP_SUPPORT
*
* If CCP is enabled it might consume a timer during IPCP or IP6CP, thus
- * we might use IPCP, IP6CP and CCP timers simultaneously.
- * 1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT
+ * we might use AUTH, IPCP, IP6CP and CCP timers simultaneously.
+ * 1 + PPP_AUTH_SUPPORT + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT
*
* When entering running phase, IPCP or IP6CP is still running. If idle time limit
* is enabled one more timer is necessary. Same for max connect time and max
* octets features. Furthermore CCP RACK might be used past this point.
* 1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS + CCP_SUPPORT
*
- * IPv4 or IPv6 must be enabled, therefore we don't need to take care the authentication
- * and the CCP + ECP case, thus reducing overall complexity.
- * 1 + LWIP_MAX(PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT, PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS + CCP_SUPPORT)
+ * Then the maximum number of simultaneously running timers is given by:
+ * 1 + MAX(PPP_AUTH_SUPPORT + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT,
+ * PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS + CCP_SUPPORT)
*
- * We don't support PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS features
- * and adding those defines to ppp_opts.h just for having the value always
- * defined to 0 isn't worth it.
- * 1 + LWIP_MAX(PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT, PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + CCP_SUPPORT)
+ * We don't support ECP_SUPPORT + PPP_IDLETIMELIMIT + PPP_MAXCONNECT + MAXOCTETS features
+ * and adding those defines to ppp_opts.h just for having the value always defined to 0
+ * is not worth it, thus reducing the overall complexity.
+ * 1 + MAX(PPP_AUTH_SUPPORT + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT,
+ * PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT -1 + CCP_SUPPORT)
*
- * Thus, the following is enough for now.
- * 1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT
+ * PPP_AUTH_SUPPORT is not available in ppp_opts.h because it is defined later in ppp.h,
+ * but we do not need to be that picky about the real number of simultaneously running
+ * timers so we just set the base number of timeouts to 2, thus the following is enough
+ * for now.
+ * 2 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT
*/
#ifdef __cplusplus
diff --git a/SylixOS/include/network/netif/ppp/ppp_opts.h b/SylixOS/include/network/netif/ppp/ppp_opts.h
index 479a006..be22c4c 100644
--- a/SylixOS/include/network/netif/ppp/ppp_opts.h
+++ b/SylixOS/include/network/netif/ppp/ppp_opts.h
@@ -95,7 +95,7 @@
* timers analysis.
*/
#ifndef PPP_NUM_TIMEOUTS_PER_PCB
-#define PPP_NUM_TIMEOUTS_PER_PCB (1 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT)
+#define PPP_NUM_TIMEOUTS_PER_PCB (2 + PPP_IPV4_SUPPORT + PPP_IPV6_SUPPORT + CCP_SUPPORT)
#endif
/* The number of sys_timeouts required for the PPP module */
@@ -185,20 +185,6 @@
#endif
/**
- * pbuf_type PPP is using for LCP, PAP, CHAP, EAP, CCP, IPCP and IP6CP packets.
- *
- * Memory allocated must be single buffered for PPP to works, it requires pbuf
- * that are not going to be chained when allocated. This requires setting
- * PBUF_POOL_BUFSIZE to at least 512 bytes, which is quite huge for small systems.
- *
- * Setting PPP_USE_PBUF_RAM to 1 makes PPP use memory from heap where continuous
- * buffers are required, allowing you to use a smaller PBUF_POOL_BUFSIZE.
- */
-#ifndef PPP_USE_PBUF_RAM
-#define PPP_USE_PBUF_RAM 0
-#endif
-
-/**
* PPP_FCS_TABLE: Keep a 256*2 byte table to speed up FCS calculation for PPPoS
*/
#ifndef PPP_FCS_TABLE
@@ -311,9 +297,11 @@
/**
* VJ_SUPPORT==1: Support VJ header compression.
+ *
+ * BEWARE: It is known to be broken when built with some compiler optimizations enabled.
*/
#ifndef VJ_SUPPORT
-#define VJ_SUPPORT 1
+#define VJ_SUPPORT 0
#endif
/* VJ compression is only supported for TCP over IPv4 over PPPoS. */
#if !PPPOS_SUPPORT || !PPP_IPV4_SUPPORT || !LWIP_TCP
@@ -507,28 +495,33 @@
*/
/**
- * PPP_MRU: Default MRU
+ * PPP_MRU: MRU value we want to negotiate (peer MTU)
+ *
+ * It only affects PPPoS because PPPoE value is derived from the
+ * Ethernet interface MTU and PPPoL2TP have a separate setting.
*/
#ifndef PPP_MRU
#define PPP_MRU 1500
#endif
/**
- * PPP_DEFMRU: Default MRU to try
- */
-#ifndef PPP_DEFMRU
-#define PPP_DEFMRU 1500
-#endif
-
-/**
- * PPP_MAXMRU: Normally limit MRU to this (pppd default = 16384)
+ * PPP_MAXMRU: Normally limit peer MRU to this
+ *
+ * This is the upper limit value to which we set our interface MTU.
+ * If the peer sends a larger number, we will just ignore it as we
+ * are not required to maximize the use of the peer capacity.
+ *
+ * It only affects PPPoS because PPPoE value is derived from the
+ * Ethernet interface MTU and PPPoL2TP have a separate setting.
*/
#ifndef PPP_MAXMRU
#define PPP_MAXMRU 1500
#endif
/**
- * PPP_MINMRU: No MRUs below this
+ * PPP_MINMRU: No peer MRUs below this
+ *
+ * Peer must be able to receive at least our minimum MTU.
*/
#ifndef PPP_MINMRU
#define PPP_MINMRU 128
diff --git a/SylixOS/include/network/netif/ppp/pppos.h b/SylixOS/include/network/netif/ppp/pppos.h
index 380a965..f587498 100644
--- a/SylixOS/include/network/netif/ppp/pppos.h
+++ b/SylixOS/include/network/netif/ppp/pppos.h
@@ -50,7 +50,6 @@ extern "C" {
* completed. */
enum {
PDIDLE = 0, /* Idle state - waiting. */
- PDSTART, /* Process start flag. */
PDADDRESS, /* Process address field. */
PDCONTROL, /* Process control field. */
PDPROTOCOL1, /* Process protocol field 1. */
@@ -59,7 +58,7 @@ enum {
};
/* PPPoS serial output callback function prototype */
-typedef u32_t (*pppos_output_cb_fn)(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx);
+typedef u32_t (*pppos_output_cb_fn)(ppp_pcb *pcb, const void *data, u32_t len, void *ctx);
/*
* Extended asyncmap - allows any character to be escaped.
@@ -103,11 +102,11 @@ ppp_pcb *pppos_create(struct netif *pppif, pppos_output_cb_fn output_cb,
#if !NO_SYS && !PPP_INPROC_IRQ_SAFE
/* Pass received raw characters to PPPoS to be decoded through lwIP TCPIP thread. */
-err_t pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l);
+err_t pppos_input_tcpip(ppp_pcb *ppp, const void *s, int l);
#endif /* !NO_SYS && !PPP_INPROC_IRQ_SAFE */
/* PPP over Serial: this is the input function to be called for received data. */
-void pppos_input(ppp_pcb *ppp, u8_t* data, int len);
+void pppos_input(ppp_pcb *ppp, const void* data, int len);
/*
diff --git a/SylixOS/kernel/include/k_functype.h b/SylixOS/kernel/include/k_functype.h
index 5345a44..ff63ae7 100644
--- a/SylixOS/kernel/include/k_functype.h
+++ b/SylixOS/kernel/include/k_functype.h
@@ -28,6 +28,7 @@
#ifdef __cplusplus
typedef INT (*FUNCPTR)(...); /* function returning int */
+typedef UINT (*UINTFUNCPTR)(...); /* function returning uint */
typedef off_t (*OFFTFUNCPTR)(...); /* function returning off_t */
typedef size_t (*SIZETFUNCPTR)(...); /* function returning size_t */
typedef ssize_t (*SSIZETFUNCPTR)(...); /* function returning ssize_t */
@@ -39,6 +40,7 @@ typedef BOOL (*BOOLFUNCPTR)(...); /* func
#else
typedef INT (*FUNCPTR)(); /* function returning int */
+typedef UINT (*UINTFUNCPTR)(); /* function returning uint */
typedef off_t (*OFFTFUNCPTR)(); /* function returning off_t */
typedef size_t (*SIZETFUNCPTR)(); /* function returning size_t */
typedef ssize_t (*SSIZETFUNCPTR)(); /* function returning ssize_t */
diff --git a/SylixOS/kernel/include/k_kernel.h b/SylixOS/kernel/include/k_kernel.h
index bac6416..0356deb 100644
--- a/SylixOS/kernel/include/k_kernel.h
+++ b/SylixOS/kernel/include/k_kernel.h
@@ -52,8 +52,8 @@
*********************************************************************************************************/
#define __SYLIXOS_MAJOR_VER 2
-#define __SYLIXOS_MINOR_VER 0
-#define __SYLIXOS_PATCH_VER 4
+#define __SYLIXOS_MINOR_VER 1
+#define __SYLIXOS_PATCH_VER 0
#define __SYLIXOS_PATCH_PAD 0
/*********************************************************************************************************
diff --git a/SylixOS/mktemp/application.mk b/SylixOS/mktemp/application.mk
index 0b7eaa8..497dd94 100644
--- a/SylixOS/mktemp/application.mk
+++ b/SylixOS/mktemp/application.mk
@@ -122,7 +122,7 @@ $(target)_DEPEND_LIB += $(TOOLCHAIN_LINK_PIC_M) $(TOOLCHAIN_LINK_PIC_GCC)
# Link object files
#*********************************************************************************************************
ifeq ($(ARCH), c6x)
-$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@
@@ -134,7 +134,7 @@ $($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
@rm -f $@_nm.txt $@_dis.txt
$(__POST_LINK_CMD)
else ifeq ($(findstring mips,$(ARCH))_$($(target)_NO_UNDEF_SYM), mips_yes)
-$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
@$(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(TOOLCHAIN_NO_UNDEF_SYM_FLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@.tmp
@@ -142,7 +142,7 @@ $($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
$(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@
$(__POST_LINK_CMD)
else
-$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@
diff --git a/SylixOS/mktemp/bare-metal.mk b/SylixOS/mktemp/bare-metal.mk
index ebcf878..ba51a3e 100644
--- a/SylixOS/mktemp/bare-metal.mk
+++ b/SylixOS/mktemp/bare-metal.mk
@@ -101,7 +101,7 @@ LOCAL_LD_SCRIPT_NT := $(LOCAL_LD_SCRIPT) config.ld
# Link object files
#*********************************************************************************************************
ifeq ($(ARCH), c6x)
-$($(target)_IMG): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_IMG): $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(__LD) $(__CPUFLAGS) $(ARCH_KERNEL_LDFLAGS) $(__LINKFLAGS) --abi=eabi -z --dynamic --trampolines=off --dsbt_size=64 -o $@ $(LOCAL_LD_SCRIPT) $(__OBJS) $(__LIBRARIES)
@@ -113,7 +113,7 @@ $($(target)_IMG): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
@rm -f $@_nm.txt $@_dis.txt
$(__POST_LINK_CMD)
else
-$($(target)_IMG): $(LOCAL_LD_SCRIPT_NT) $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_IMG): $(LOCAL_LD_SCRIPT_NT) $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(CPP) $(__CPUFLAGS) -E -P $(__DSYMBOL) config.ld -o config.lds
diff --git a/SylixOS/mktemp/bsp.mk b/SylixOS/mktemp/bsp.mk
index 0af95bb..6dbbc0b 100644
--- a/SylixOS/mktemp/bsp.mk
+++ b/SylixOS/mktemp/bsp.mk
@@ -129,7 +129,7 @@ LOCAL_LD_SCRIPT_NT := $(LOCAL_LD_SCRIPT) config.ld
# Link object files
#*********************************************************************************************************
ifeq ($(ARCH), c6x)
-$($(target)_IMG): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_IMG): $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(__LD) $(__CPUFLAGS) $(ARCH_KERNEL_LDFLAGS) $(__LINKFLAGS) --abi=eabi -z --dynamic --trampolines=off --dsbt_size=64 -o $@ $(LOCAL_LD_SCRIPT) $(__OBJS) $(__LIBRARIES)
@@ -141,7 +141,7 @@ $($(target)_IMG): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
@rm -f $@_nm.txt $@_dis.txt
$(__POST_LINK_CMD)
else
-$($(target)_IMG): $(LOCAL_LD_SCRIPT_NT) $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_IMG): $(LOCAL_LD_SCRIPT_NT) $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(CPP) $(__CPUFLAGS) -E -P $(__DSYMBOL) config.ld -o config.lds
diff --git a/SylixOS/mktemp/clear-vars.mk b/SylixOS/mktemp/clear-vars.mk
index 9584fb2..a8b2a44 100644
--- a/SylixOS/mktemp/clear-vars.mk
+++ b/SylixOS/mktemp/clear-vars.mk
@@ -123,5 +123,10 @@ LOCAL_USE_EXTENSION := no
LOCAL_SHARED_LIB_ONLY := no
#*********************************************************************************************************
+# Use short command for link and ar
+#*********************************************************************************************************
+LOCAL_USE_SHORT_CMD := no
+
+#*********************************************************************************************************
# End
#*********************************************************************************************************
diff --git a/SylixOS/mktemp/common.mk b/SylixOS/mktemp/common.mk
index 6ce181a..3c2b5a1 100644
--- a/SylixOS/mktemp/common.mk
+++ b/SylixOS/mktemp/common.mk
@@ -116,13 +116,14 @@ $(target)_LINKFLAGS := $(LOCAL_LINKFLAGS)
#*********************************************************************************************************
# Define some useful variables
#*********************************************************************************************************
-$(target)_USE_CXX := $(LOCAL_USE_CXX)
-$(target)_USE_CXX_EXCEPT := $(LOCAL_USE_CXX_EXCEPT)
-$(target)_USE_GCOV := $(LOCAL_USE_GCOV)
-$(target)_USE_OMP := $(LOCAL_USE_OMP)
-$(target)_USE_EXTENSION := $(LOCAL_USE_EXTENSION)
+$(target)_USE_CXX := $(strip $(LOCAL_USE_CXX))
+$(target)_USE_CXX_EXCEPT := $(strip $(LOCAL_USE_CXX_EXCEPT))
+$(target)_USE_GCOV := $(strip $(LOCAL_USE_GCOV))
+$(target)_USE_OMP := $(strip $(LOCAL_USE_OMP))
+$(target)_USE_EXTENSION := $(strip $(LOCAL_USE_EXTENSION))
+$(target)_USE_SHORT_CMD := $(strip $(LOCAL_USE_SHORT_CMD))
-$(target)_NO_UNDEF_SYM := $(LOCAL_NO_UNDEF_SYM)
+$(target)_NO_UNDEF_SYM := $(strip $(LOCAL_NO_UNDEF_SYM))
$(target)_PRE_LINK_CMD := $(LOCAL_PRE_LINK_CMD)
$(target)_POST_LINK_CMD := $(LOCAL_POST_LINK_CMD)
@@ -131,7 +132,7 @@ $(target)_PRE_STRIP_CMD := $(LOCAL_PRE_STRIP_CMD)
$(target)_POST_STRIP_CMD := $(LOCAL_POST_STRIP_CMD)
$(target)_DEPEND_TARGET := $(LOCAL_DEPEND_TARGET)
-$(target)_SHARED_LIB_ONLY := $(LOCAL_SHARED_LIB_ONLY)
+$(target)_SHARED_LIB_ONLY := $(strip $(LOCAL_SHARED_LIB_ONLY))
ifeq ($($(target)_USE_CXX), yes)
$(target)_LD := $(CXX_LD)
@@ -140,6 +141,24 @@ $(target)_LD := $(C_LD)
endif
#*********************************************************************************************************
+# Objects list file and objects flags
+#*********************************************************************************************************
+ifeq ($(ARCH), c6x)
+$(target)_OBJS_LIST_FILE :=
+$(target)_OBJS_FLAGS := $($(target)_OBJS)
+else
+ifeq ($($(target)_USE_SHORT_CMD), yes)
+$(target)_OBJS_LIST_FILE := $(OBJPATH)/$(target)/objects.lst
+$(call generate-list-file,$($(target)_OBJS),$($(target)_OBJS_LIST_FILE))
+
+$(target)_OBJS_FLAGS := @$($(target)_OBJS_LIST_FILE)
+else
+$(target)_OBJS_LIST_FILE :=
+$(target)_OBJS_FLAGS := $($(target)_OBJS)
+endif
+endif
+
+#*********************************************************************************************************
# Compile source files
#*********************************************************************************************************
ifeq ($(ARCH), c6x)
diff --git a/SylixOS/mktemp/dummy.mk b/SylixOS/mktemp/dummy.mk
index 1271c32..f3ffa65 100644
--- a/SylixOS/mktemp/dummy.mk
+++ b/SylixOS/mktemp/dummy.mk
@@ -60,7 +60,7 @@ $(target)_A := $(OUTPATH)/$(LOCAL_TARGET_NAME)
#*********************************************************************************************************
# Make archive object files
#*********************************************************************************************************
-$($(target)_A): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_A): $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
$(__PRE_LINK_CMD)
$(__POST_LINK_CMD)
$(__PRE_STRIP_CMD)
diff --git a/SylixOS/mktemp/extension.mk b/SylixOS/mktemp/extension.mk
index b0f417c..d8f0e25 100644
--- a/SylixOS/mktemp/extension.mk
+++ b/SylixOS/mktemp/extension.mk
@@ -105,7 +105,7 @@ LOCAL_LD_SCRIPT_NT := $(LOCAL_LD_SCRIPT) config.ld
#*********************************************************************************************************
# Link object files
#*********************************************************************************************************
-$($(target)_IMG): $(LOCAL_LD_SCRIPT_NT) $($(target)_OBJS) $($(target)_DEPEND_TARGET) SylixOSBSPSymbol.ld
+$($(target)_IMG): $(LOCAL_LD_SCRIPT_NT) $($(target)_OBJS) $($(target)_DEPEND_TARGET) SylixOSBSPSymbol.ld $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(CPP) $(__CPUFLAGS) -E -P $(__DSYMBOL) config.ld -o config.lds
diff --git a/SylixOS/mktemp/gtest.mk b/SylixOS/mktemp/gtest.mk
index f0951de..15f23b2 100644
--- a/SylixOS/mktemp/gtest.mk
+++ b/SylixOS/mktemp/gtest.mk
@@ -123,7 +123,7 @@ $(target)_DEPEND_LIB += $(TOOLCHAIN_LINK_PIC_M) $(TOOLCHAIN_LINK_PIC_GCC)
# Link object files
#*********************************************************************************************************
ifeq ($(ARCH), c6x)
-$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@
@@ -135,7 +135,7 @@ $($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
@rm -f $@_nm.txt $@_dis.txt
$(__POST_LINK_CMD)
else ifeq ($(findstring mips,$(ARCH))_$($(target)_NO_UNDEF_SYM), mips_yes)
-$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
@$(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(TOOLCHAIN_NO_UNDEF_SYM_FLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@.tmp
@@ -143,7 +143,7 @@ $($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
$(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@
$(__POST_LINK_CMD)
else
-$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@
diff --git a/SylixOS/mktemp/header.mk b/SylixOS/mktemp/header.mk
index 32bf59e..2549074 100644
--- a/SylixOS/mktemp/header.mk
+++ b/SylixOS/mktemp/header.mk
@@ -82,17 +82,18 @@ SPACE = $(EMPTY) $(EMPTY)
SYLIXOS_BASE_PATH := $(subst \,/,$(subst $(SPACE),\ ,$(SYLIXOS_BASE_PATH)))
-__TARGET = $(word $(TARGET_WORD_POS),$(subst $(BIAS),$(SPACE),$(@)))
-__DEP = $(addprefix $(DEPPATH)/$(__TARGET)/, $(addsuffix .d, $(basename $(<))))
+__TARGET = $(word $(TARGET_WORD_POS),$(subst $(BIAS),$(SPACE),$(@)))
+__DEP = $(addprefix $(DEPPATH)/$(__TARGET)/, $(addsuffix .d, $(basename $(<))))
ifneq (,$(findstring cl6x,$(TOOLCHAIN_PREFIX)))
-__PP = $(addprefix $(DEPPATH)/$(__TARGET)/, $(addsuffix .pp, $(basename $(<))))
+__PP = $(addprefix $(DEPPATH)/$(__TARGET)/, $(addsuffix .pp, $(basename $(<))))
endif
-__LIBRARIES = $($(@F)_DEPEND_LIB_PATH) $($(@F)_DEPEND_LIB)
-__OBJS = $($(@F)_OBJS)
-__CPUFLAGS = $($(@F)_CPUFLAGS)
-__DSYMBOL = $($(@F)_DSYMBOL)
-__LINKFLAGS = $($(@F)_LINKFLAGS)
-__LD = $($(@F)_LD)
+__LIBRARIES = $($(@F)_DEPEND_LIB_PATH) $($(@F)_DEPEND_LIB)
+__OBJS = $($(@F)_OBJS_FLAGS)
+__AR_SO_OBJS = $($(addsuffix .so, $(basename $(@F)))_OBJS_FLAGS)
+__CPUFLAGS = $($(@F)_CPUFLAGS)
+__DSYMBOL = $($(@F)_DSYMBOL)
+__LINKFLAGS = $($(@F)_LINKFLAGS)
+__LD = $($(@F)_LD)
__PRE_LINK_CMD = $($(@F)_PRE_LINK_CMD)
__POST_LINK_CMD = $($(@F)_POST_LINK_CMD)
@@ -101,6 +102,229 @@ __PRE_STRIP_CMD = $($(@F)_PRE_STRIP_CMD)
__POST_STRIP_CMD = $($(@F)_POST_STRIP_CMD)
#*********************************************************************************************************
+# HOST_OS
+#*********************************************************************************************************
+UNAME = $(shell uname -sm)
+
+ifneq (,$(findstring Linux, $(UNAME)))
+HOST_OS = linux
+endif
+ifneq (,$(findstring Darwin, $(UNAME)))
+HOST_OS = darwin
+endif
+ifneq (,$(findstring Macintosh, $(UNAME)))
+HOST_OS = darwin
+endif
+ifneq (,$(findstring CYGWIN, $(UNAME)))
+HOST_OS = windows
+endif
+ifneq (,$(findstring windows, $(UNAME)))
+HOST_OS = windows
+endif
+ifneq (,$(findstring MINGW, $(UNAME)))
+HOST_OS = linux
+endif
+
+ifeq ($(HOST_OS),)
+$(error Unable to determine HOST_OS from uname -sm: $(UNAME)!)
+endif
+
+hide = @
+
+#*********************************************************************************************************
+# Define HOST_ECHO_N to perform the equivalent of 'echo -n' on all platforms.
+#*********************************************************************************************************
+ifeq ($(HOST_OS),windows)
+HOST_ECHO_N := echo -n
+else
+# On Posix, just use bare printf.
+HOST_ECHO_N := printf %s
+endif
+
+#*********************************************************************************************************
+# Function : generate-list-file
+# Arguments: 1: list of strings (possibly very long)
+# 2: file name
+# Returns : write the content of a possibly very long string list to a file.
+# this shall be used in commands and will work around limitations
+# of host command-line lengths.
+# Usage : $(call host-echo-to-file,<string-list>,<file>)
+# Rationale: When there is a very large number of objects and/or libraries at
+# link time, the size of the command becomes too large for the
+# host system's maximum. Various tools however support the
+# @<listfile> syntax, where <listfile> is the path of a file
+# which content will be parsed as if they were options.
+#
+# This function is used to generate such a list file from a long
+# list of strings in input.
+#
+#*********************************************************************************************************
+
+#*********************************************************************************************************
+# Helper functions because the GNU Make $(word ...) function does
+# not accept a 0 index, so we need to bump any of these to 1 when
+# we find them.
+#*********************************************************************************************************
+index-is-zero = $(filter 0 00 000 0000 00000 000000 0000000,$1)
+bump-0-to-1 = $(if $(call index-is-zero,$1),1,$1)
+
+#*********************************************************************************************************
+# Same as $(wordlist ...) except the start index, if 0, is bumped to 1
+#*********************************************************************************************************
+index-word-list = $(wordlist $(call bump-0-to-1,$1),$2,$3)
+
+#*********************************************************************************************************
+# NOTE: With GNU Make $1 and $(1) are equivalent, which means
+# that $10 is equivalent to $(1)0, and *not* $(10).
+#
+# Used to generate a slice of up to 10 items starting from index $1,
+# If $1 is 0, it will be bumped to 1 (and only 9 items will be printed)
+# $1: start (tenth) index. Can be 0
+# $2: word list
+#*********************************************************************************************************
+define list-file-start-gen-10
+ $$(hide) $$(HOST_ECHO_N) "$(call index-word-list,$10,$19,$2) " >> $$@
+endef
+
+#*********************************************************************************************************
+# Used to generate a slice of always 10 items starting from index $1
+# $1: start (tenth) index. CANNOT BE 0
+# $2: word list
+#*********************************************************************************************************
+define list-file-always-gen-10
+ $$(hide) $$(HOST_ECHO_N) "$(wordlist $10,$19,$2) " >> $$@
+endef
+
+#*********************************************************************************************************
+# Same as list-file-always-gen-10, except that the word list might be
+# empty at position $10 (i.e. $(1)0)
+#*********************************************************************************************************
+define list-file-maybe-gen-10
+ifneq ($(word $10,$2),)
+ $$(hide) $$(HOST_ECHO_N) "$(wordlist $10,$19,$2) " >> $$@
+endif
+endef
+
+define list-file-start-gen-100
+$(call list-file-start-gen-10,$10,$2)
+$(call list-file-always-gen-10,$11,$2)
+$(call list-file-always-gen-10,$12,$2)
+$(call list-file-always-gen-10,$13,$2)
+$(call list-file-always-gen-10,$14,$2)
+$(call list-file-always-gen-10,$15,$2)
+$(call list-file-always-gen-10,$16,$2)
+$(call list-file-always-gen-10,$17,$2)
+$(call list-file-always-gen-10,$18,$2)
+$(call list-file-always-gen-10,$19,$2)
+endef
+
+define list-file-always-gen-100
+$(call list-file-always-gen-10,$10,$2)
+$(call list-file-always-gen-10,$11,$2)
+$(call list-file-always-gen-10,$12,$2)
+$(call list-file-always-gen-10,$13,$2)
+$(call list-file-always-gen-10,$14,$2)
+$(call list-file-always-gen-10,$15,$2)
+$(call list-file-always-gen-10,$16,$2)
+$(call list-file-always-gen-10,$17,$2)
+$(call list-file-always-gen-10,$18,$2)
+$(call list-file-always-gen-10,$19,$2)
+endef
+
+define list-file-maybe-gen-100
+ifneq ($(word $(call bump-0-to-1,$100),$2),)
+ifneq ($(word $199,$2),)
+$(call list-file-start-gen-10,$10,$2)
+$(call list-file-always-gen-10,$11,$2)
+$(call list-file-always-gen-10,$12,$2)
+$(call list-file-always-gen-10,$13,$2)
+$(call list-file-always-gen-10,$14,$2)
+$(call list-file-always-gen-10,$15,$2)
+$(call list-file-always-gen-10,$16,$2)
+$(call list-file-always-gen-10,$17,$2)
+$(call list-file-always-gen-10,$18,$2)
+$(call list-file-always-gen-10,$19,$2)
+else
+ifneq ($(word $150,$2),)
+$(call list-file-start-gen-10,$10,$2)
+$(call list-file-always-gen-10,$11,$2)
+$(call list-file-always-gen-10,$12,$2)
+$(call list-file-always-gen-10,$13,$2)
+$(call list-file-always-gen-10,$14,$2)
+$(call list-file-maybe-gen-10,$15,$2)
+$(call list-file-maybe-gen-10,$16,$2)
+$(call list-file-maybe-gen-10,$17,$2)
+$(call list-file-maybe-gen-10,$18,$2)
+$(call list-file-maybe-gen-10,$19,$2)
+else
+$(call list-file-start-gen-10,$10,$2)
+$(call list-file-maybe-gen-10,$11,$2)
+$(call list-file-maybe-gen-10,$12,$2)
+$(call list-file-maybe-gen-10,$13,$2)
+$(call list-file-maybe-gen-10,$14,$2)
+endif
+endif
+endif
+endef
+
+define list-file-maybe-gen-1000
+ifneq ($(word $(call bump-0-to-1,$1000),$2),)
+ifneq ($(word $1999,$2),)
+$(call list-file-start-gen-100,$10,$2)
+$(call list-file-always-gen-100,$11,$2)
+$(call list-file-always-gen-100,$12,$2)
+$(call list-file-always-gen-100,$13,$2)
+$(call list-file-always-gen-100,$14,$2)
+$(call list-file-always-gen-100,$15,$2)
+$(call list-file-always-gen-100,$16,$2)
+$(call list-file-always-gen-100,$17,$2)
+$(call list-file-always-gen-100,$18,$2)
+$(call list-file-always-gen-100,$19,$2)
+else
+ifneq ($(word $1500,$2),)
+$(call list-file-start-gen-100,$10,$2)
+$(call list-file-always-gen-100,$11,$2)
+$(call list-file-always-gen-100,$12,$2)
+$(call list-file-always-gen-100,$13,$2)
+$(call list-file-always-gen-100,$14,$2)
+$(call list-file-maybe-gen-100,$15,$2)
+$(call list-file-maybe-gen-100,$16,$2)
+$(call list-file-maybe-gen-100,$17,$2)
+$(call list-file-maybe-gen-100,$18,$2)
+$(call list-file-maybe-gen-100,$19,$2)
+else
+$(call list-file-start-gen-100,$10,$2)
+$(call list-file-maybe-gen-100,$11,$2)
+$(call list-file-maybe-gen-100,$12,$2)
+$(call list-file-maybe-gen-100,$13,$2)
+$(call list-file-maybe-gen-100,$14,$2)
+endif
+endif
+endif
+endef
+
+define generate-list-file-ev
+__list_file := $2
+
+$$(__list_file): $1
+ @if [ ! -d "$(dir $2)" ]; then \
+ mkdir -p "$(dir $2)"; fi
+ $$(hide) $$(HOST_ECHO_N) "" > $$@
+$(call list-file-maybe-gen-1000,0,$1)
+$(call list-file-maybe-gen-1000,1,$1)
+$(call list-file-maybe-gen-1000,2,$1)
+$(call list-file-maybe-gen-1000,3,$1)
+$(call list-file-maybe-gen-1000,4,$1)
+$(call list-file-maybe-gen-1000,5,$1)
+$(call list-file-maybe-gen-1000,6,$1)
+$(call list-file-maybe-gen-1000,7,$1)
+$(call list-file-maybe-gen-1000,8,$1)
+$(call list-file-maybe-gen-1000,9,$1)
+endef
+
+generate-list-file = $(eval $(call generate-list-file-ev,$1,$2))
+
+#*********************************************************************************************************
# Do not export the following environment variables
#*********************************************************************************************************
unexport CPATH
diff --git a/SylixOS/mktemp/kernel-library.mk b/SylixOS/mktemp/kernel-library.mk
index 08f83ad..4580f92 100644
--- a/SylixOS/mktemp/kernel-library.mk
+++ b/SylixOS/mktemp/kernel-library.mk
@@ -60,7 +60,7 @@ $(target)_A := $(OUTPATH)/$(LOCAL_TARGET_NAME)
#*********************************************************************************************************
# Make archive object files
#*********************************************************************************************************
-$($(target)_A): $($(target)_OBJS)
+$($(target)_A): $($(target)_OBJS) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(AR) $(TOOLCHAIN_AR_FLAGS) $@ $(__OBJS)
diff --git a/SylixOS/mktemp/kernel-module.mk b/SylixOS/mktemp/kernel-module.mk
index 144265e..bd66dda 100644
--- a/SylixOS/mktemp/kernel-module.mk
+++ b/SylixOS/mktemp/kernel-module.mk
@@ -84,7 +84,7 @@ $(target)_STRIP_KO := $(OUTPATH)/strip/$(LOCAL_TARGET_NAME)
#*********************************************************************************************************
# Make archive object files
#*********************************************************************************************************
-$($(target)_KO): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_KO): $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(__LD) $(__CPUFLAGS) $(ARCH_KO_LDFLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@
diff --git a/SylixOS/mktemp/library.mk b/SylixOS/mktemp/library.mk
index f2dd645..be95314 100644
--- a/SylixOS/mktemp/library.mk
+++ b/SylixOS/mktemp/library.mk
@@ -111,7 +111,7 @@ $(target)_DEPEND_LIB += $(TOOLCHAIN_LINK_PIC_M) $(TOOLCHAIN_LINK_PIC_GCC)
# Link object files
#*********************************************************************************************************
ifeq ($(ARCH), c6x)
-$($(target)_SO): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_SO): $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@
@@ -123,7 +123,7 @@ $($(target)_SO): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
@rm -f $@_nm.txt $@_dis.txt
$(__POST_LINK_CMD)
else
-$($(target)_SO): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_SO): $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@
@@ -143,9 +143,9 @@ $($(target)_STRIP_SO): $($(target)_SO)
#*********************************************************************************************************
# Make archive object files
#*********************************************************************************************************
-$($(target)_A): $($(target)_OBJS)
+$($(target)_A): $($(target)_OBJS) $($(target)_OBJS_LIST_FILE)
@rm -f $@
- $(AR) $(TOOLCHAIN_AR_FLAGS) $@ $^
+ $(AR) $(TOOLCHAIN_AR_FLAGS) $@ $(__AR_SO_OBJS)
#*********************************************************************************************************
# Add targets
diff --git a/SylixOS/mktemp/libsylixos.mk b/SylixOS/mktemp/libsylixos.mk
index 2089c6e..9a6002a 100644
--- a/SylixOS/mktemp/libsylixos.mk
+++ b/SylixOS/mktemp/libsylixos.mk
@@ -82,6 +82,7 @@ OBJS_SYMBOL := $(addprefix $(OBJPATH)/libsylixos.a/, $(addsuffix .o, $(basename
OBJS_SYS := $(addprefix $(OBJPATH)/libsylixos.a/, $(addsuffix .o, $(basename $(SYS_SRCS))))
OBJS_SYSPERF := $(addprefix $(OBJPATH)/libsylixos.a/, $(addsuffix .o, $(basename $(SYSPERF_SRCS))))
OBJS_CPP := $(addprefix $(OBJPATH)/libsylixos.a/, $(addsuffix .o, $(basename $(CPP_SRCS))))
+OBJS_DEVTREE := $(addprefix $(OBJPATH)/libsylixos.a/, $(addsuffix .o, $(basename $(DEVTREE_SRCS))))
#*********************************************************************************************************
# Make archive object files
@@ -107,6 +108,7 @@ $($(target)_A): $($(target)_OBJS)
$(AR) $(TOOLCHAIN_AR_FLAGS) $@ $(OBJS_SYS)
$(AR) $(TOOLCHAIN_AR_FLAGS) $@ $(OBJS_SYSPERF)
$(AR) $(TOOLCHAIN_AR_FLAGS) $@ $(OBJS_CPP)
+ $(AR) $(TOOLCHAIN_AR_FLAGS) $@ $(OBJS_DEVTREE)
$(__POST_LINK_CMD)
#*********************************************************************************************************
@@ -124,7 +126,7 @@ else
$(OUTPATH)/symbol.c: $($(target)_A)
@rm -f $@
cp SylixOS/hosttools/makesymbol/Makefile $(OUTDIR)
- cp SylixOS/hosttools/makesymbol/makesymbol.bat $(OUTDIR)
+ cp SylixOS/hosttools/makesymbol/makesymbol.exe $(OUTDIR)
cp SylixOS/hosttools/makesymbol/makesymbol.sh $(OUTDIR)
cp SylixOS/hosttools/makesymbol/nm.exe $(OUTDIR)
make -C $(OUTDIR)
diff --git a/SylixOS/mktemp/lite-bsp.mk b/SylixOS/mktemp/lite-bsp.mk
index 0d49357..6b91ecf 100644
--- a/SylixOS/mktemp/lite-bsp.mk
+++ b/SylixOS/mktemp/lite-bsp.mk
@@ -127,7 +127,7 @@ LOCAL_LD_SCRIPT_NT := $(LOCAL_LD_SCRIPT) config.ld
# Link object files
#*********************************************************************************************************
ifeq ($(ARCH), c6x)
-$($(target)_IMG): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_IMG): $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(__LD) $(__CPUFLAGS) $(ARCH_KERNEL_LDFLAGS) $(__LINKFLAGS) --abi=eabi -z --dynamic --trampolines=off --dsbt_size=64 -o $@ $(LOCAL_LD_SCRIPT) $(__OBJS) $(__LIBRARIES)
@@ -140,7 +140,7 @@ $($(target)_IMG): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
$(__POST_LINK_CMD)
else
ifeq ($($(target)_USE_EXTENSION), yes)
-$($(target)_IMG): $(LOCAL_LD_SCRIPT_NT) $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_IMG): $(LOCAL_LD_SCRIPT_NT) $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@echo Link $@ first time
@rm -f $@
$(__PRE_LINK_CMD)
@@ -167,7 +167,7 @@ $($(target)_IMG): $(LOCAL_LD_SCRIPT_NT) $($(target)_OBJS) $($(target)_DEPEND_TAR
$(__LD) $(__CPUFLAGS) $(ARCH_KERNEL_LDFLAGS) $(__LINKFLAGS) -nostdlib $(addprefix -T, $<) -o $@ $(__OBJS) $(BSP_CERT_OBJ) $(__LIBRARIES)
$(__POST_LINK_CMD)
else
-$($(target)_IMG): $(LOCAL_LD_SCRIPT_NT) $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+$($(target)_IMG): $(LOCAL_LD_SCRIPT_NT) $($(target)_OBJS) $($(target)_DEPEND_TARGET) $($(target)_OBJS_LIST_FILE)
@rm -f $@
$(__PRE_LINK_CMD)
$(CPP) $(__CPUFLAGS) -E -P $(__DSYMBOL) config.ld -o config.lds
diff --git a/SylixOS/mktemp/static-library.mk b/SylixOS/mktemp/static-library.mk
index 589192a..7298290 100644
--- a/SylixOS/mktemp/static-library.mk
+++ b/SylixOS/mktemp/static-library.mk
@@ -71,9 +71,9 @@ $(target)_DEPEND_LIB :=
#*********************************************************************************************************
# Make archive object files
#*********************************************************************************************************
-$($(target)_A): $($(target)_OBJS)
+$($(target)_A): $($(target)_OBJS) $($(target)_OBJS_LIST_FILE)
@rm -f $@
- $(AR) $(TOOLCHAIN_AR_FLAGS) $@ $^
+ $(AR) $(TOOLCHAIN_AR_FLAGS) $@ $(__OBJS)
#*********************************************************************************************************
# Add targets
diff --git a/SylixOS/net/lwip/lwip_fix.c b/SylixOS/net/lwip/lwip_fix.c
index ce7e0c2..f4b4ded 100644
--- a/SylixOS/net/lwip/lwip_fix.c
+++ b/SylixOS/net/lwip/lwip_fix.c
@@ -1174,7 +1174,7 @@ u32_t sio_tryread (sio_fd_t fd, u8_t *buffer, u32_t num)
** 全局变量:
** 调用模块:
*********************************************************************************************************/
-u32_t sio_write (sio_fd_t fd, u8_t *buffer, u32_t num)
+u32_t sio_write (sio_fd_t fd, const u8_t *buffer, u32_t num)
{
ssize_t ssWriteNum;
diff --git a/SylixOS/net/lwip/lwip_shell.c b/SylixOS/net/lwip/lwip_shell.c
index 188e060..2c05cef 100644
--- a/SylixOS/net/lwip/lwip_shell.c
+++ b/SylixOS/net/lwip/lwip_shell.c
@@ -1651,7 +1651,7 @@ VOID __tshellNetInit (VOID)
" ipqos ipv6 0 (disable IPv6 QoS support)\n");
API_TShellKeywordAdd("iftcpaf", __tshellIfTcpaf);
- API_TShellFormatAdd("iftcpaf", " [ifname] [tcpaf (2~127)]");
+ API_TShellFormatAdd("iftcpaf", " [ifname] [tcpaf (1~127)]");
API_TShellHelpAdd("iftcpaf", "Set/Get TCP ACK Frequency for net interface\n"
"eg. iftcpaf lo0 (get 'lo0' TCP ACK Frequency setting)\n"
" iftcpaf en1 4 (set 'en1' TCP ACK Frequency to 4)\n");
diff --git a/SylixOS/net/lwip/src/core/netif.c b/SylixOS/net/lwip/src/core/netif.c
index cb8fc4a..a3e354f 100644
--- a/SylixOS/net/lwip/src/core/netif.c
+++ b/SylixOS/net/lwip/src/core/netif.c
@@ -396,7 +396,7 @@ netif_add(struct netif *netif,
netif->flowctl = NULL;
netif->vlanid = (u16_t)-1;
netif->metric = 1;
- netif->tcp_ack_freq = LWIP_NETIF_TCP_ACK_FREQ_MIN;
+ netif->tcp_ack_freq = LWIP_NETIF_TCP_ACK_FREQ_DEF;
netif->tcp_wnd = TCP_WND;
netif->mipif = NULL;
netif->masterif = NULL;
diff --git a/SylixOS/net/lwip/src/netif/ppp/auth.c b/SylixOS/net/lwip/src/netif/ppp/auth.c
index 7a74292..3e17418 100644
--- a/SylixOS/net/lwip/src/netif/ppp/auth.c
+++ b/SylixOS/net/lwip/src/netif/ppp/auth.c
@@ -1003,13 +1003,13 @@ void continue_networks(ppp_pcb *pcb) {
* 1: Authentication succeeded.
* In either case, msg points to an appropriate message and msglen to the message len.
*/
-int auth_check_passwd(ppp_pcb *pcb, char *auser, int userlen, char *apasswd, int passwdlen, const char **msg, int *msglen) {
- int secretuserlen;
- int secretpasswdlen;
+int auth_check_passwd(ppp_pcb *pcb, char *auser, unsigned int userlen, char *apasswd, unsigned int passwdlen, const char **msg, int *msglen) {
+ size_t secretuserlen;
+ size_t secretpasswdlen;
if (pcb->settings.user && pcb->settings.passwd) {
- secretuserlen = (int)strlen(pcb->settings.user);
- secretpasswdlen = (int)strlen(pcb->settings.passwd);
+ secretuserlen = strlen(pcb->settings.user);
+ secretpasswdlen = strlen(pcb->settings.passwd);
if (secretuserlen == userlen
&& secretpasswdlen == passwdlen
&& !memcmp(auser, pcb->settings.user, userlen)
@@ -1049,6 +1049,7 @@ void auth_peer_success(ppp_pcb *pcb, int protocol, int prot_flavor, const char *
LWIP_UNUSED_ARG(name);
LWIP_UNUSED_ARG(namelen);
#endif /* HAVE_MULTILINK */
+ LWIP_UNUSED_ARG(prot_flavor); /* if CHAP_SUPPORT is disabled */
switch (protocol) {
#if CHAP_SUPPORT
@@ -1136,6 +1137,7 @@ void auth_withpeer_fail(ppp_pcb *pcb, int protocol) {
void auth_withpeer_success(ppp_pcb *pcb, int protocol, int prot_flavor) {
int bit;
const char *prot = "";
+ LWIP_UNUSED_ARG(prot_flavor); /* if CHAP_SUPPORT is disabled */
switch (protocol) {
#if CHAP_SUPPORT
@@ -1902,7 +1904,7 @@ have_srp_secret(client, server, need_ip, lacks_ipp)
* (We could be either client or server).
*/
int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secret, int *secret_len, int am_server) {
- int len;
+ size_t len;
LWIP_UNUSED_ARG(server);
LWIP_UNUSED_ARG(am_server);
@@ -1910,7 +1912,7 @@ int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secre
return 0;
}
- len = (int)strlen(pcb->settings.passwd);
+ len = strlen(pcb->settings.passwd);
if (len > MAXSECRETLEN) {
ppp_error(("Secret for %s on %s is too long", client, server));
len = MAXSECRETLEN;
@@ -1922,7 +1924,8 @@ int get_secret(ppp_pcb *pcb, const char *client, const char *server, char *secre
#if 0 /* UNUSED */
FILE *f;
- int ret, len;
+ int ret;
+ size_t len;
char *filename;
struct wordlist *addrs, *opts;
char secbuf[MAXWORDLEN];
diff --git a/SylixOS/net/lwip/src/netif/ppp/ccp.c b/SylixOS/net/lwip/src/netif/ppp/ccp.c
index 6c2dadc..86ecb9f 100644
--- a/SylixOS/net/lwip/src/netif/ppp/ccp.c
+++ b/SylixOS/net/lwip/src/netif/ppp/ccp.c
@@ -1213,9 +1213,9 @@ static int ccp_reqci(fsm *f, u_char *p, int *lenp, int dont_nak) {
* because MPPE frames **grow**. The kernel [must]
* allocate MPPE_PAD extra bytes in xmit buffers.
*/
- mtu = netif_get_mtu(pcb);
+ mtu = ppp_netif_get_mtu(pcb);
if (mtu)
- netif_set_mtu(pcb, mtu - MPPE_PAD);
+ ppp_netif_set_mtu(pcb, mtu - MPPE_PAD);
else
newret = CONFREJ;
}
diff --git a/SylixOS/net/lwip/src/netif/ppp/chap-new.c b/SylixOS/net/lwip/src/netif/ppp/chap-new.c
index 2f7532b..da12430 100644
--- a/SylixOS/net/lwip/src/netif/ppp/chap-new.c
+++ b/SylixOS/net/lwip/src/netif/ppp/chap-new.c
@@ -236,7 +236,7 @@ static void chap_timeout(void *arg) {
return;
}
- p = pbuf_alloc(PBUF_RAW, (u16_t)(pcb->chap_server.challenge_pktlen), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(pcb->chap_server.challenge_pktlen), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
@@ -345,7 +345,7 @@ static void chap_handle_response(ppp_pcb *pcb, int id,
/* send the response */
mlen = strlen(message);
len = CHAP_HDRLEN + mlen;
- p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +len), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +len), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
@@ -441,7 +441,7 @@ static void chap_respond(ppp_pcb *pcb, int id,
char rname[MAXNAMELEN+1];
char secret[MAXSECRETLEN+1];
- p = pbuf_alloc(PBUF_RAW, (u16_t)(RESP_MAX_PKTLEN), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(RESP_MAX_PKTLEN), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
diff --git a/SylixOS/net/lwip/src/netif/ppp/demand.c b/SylixOS/net/lwip/src/netif/ppp/demand.c
index 26c6c30..709e5ea 100644
--- a/SylixOS/net/lwip/src/netif/ppp/demand.c
+++ b/SylixOS/net/lwip/src/netif/ppp/demand.c
@@ -86,8 +86,8 @@ demand_conf()
const struct protent *protp;
/* framemax = lcp_allowoptions[0].mru;
- if (framemax < PPP_MRU) */
- framemax = PPP_MRU;
+ if (framemax < PPP_DEFMRU) */
+ framemax = PPP_DEFMRU;
framemax += PPP_HDRLEN + PPP_FCSLEN;
frame = malloc(framemax);
if (frame == NULL)
@@ -98,9 +98,9 @@ demand_conf()
flush_flag = 0;
fcs = PPP_INITFCS;
- netif_set_mtu(pcb, LWIP_MIN(lcp_allowoptions[0].mru, PPP_MRU));
- if (ppp_send_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0
- || ppp_recv_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0)
+ ppp_netif_set_mtu(pcb, LWIP_MIN(lcp_allowoptions[0].mru, PPP_DEFMRU));
+ if (ppp_send_config(pcb, PPP_DEFMRU, (u32_t) 0, 0, 0) < 0
+ || ppp_recv_config(pcb, PPP_DEFMRU, (u32_t) 0, 0, 0) < 0)
fatal("Couldn't set up demand-dialled PPP interface: %m");
#ifdef PPP_FILTER
diff --git a/SylixOS/net/lwip/src/netif/ppp/eap.c b/SylixOS/net/lwip/src/netif/ppp/eap.c
index 7ff52b4..ea684bf 100644
--- a/SylixOS/net/lwip/src/netif/ppp/eap.c
+++ b/SylixOS/net/lwip/src/netif/ppp/eap.c
@@ -251,7 +251,7 @@ static void eap_send_failure(ppp_pcb *pcb) {
struct pbuf *p;
u_char *outp;
- p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
@@ -282,7 +282,7 @@ static void eap_send_success(ppp_pcb *pcb) {
struct pbuf *p;
u_char *outp;
- p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
@@ -683,7 +683,7 @@ static void eap_send_request(ppp_pcb *pcb) {
return;
}
- p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_UNKNOWN_SIZE), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
@@ -1018,7 +1018,7 @@ static void eap_send_response(ppp_pcb *pcb, u_char id, u_char typenum, const u_c
int msglen;
msglen = EAP_HEADERLEN + sizeof (u_char) + lenstr;
- p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
@@ -1052,7 +1052,7 @@ static void eap_chap_response(ppp_pcb *pcb, u_char id, u_char *hash, const char
msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + MD5_SIGNATURE_SIZE +
namelen;
- p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
@@ -1097,7 +1097,7 @@ int lenstr;
int msglen;
msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + lenstr;
- p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
@@ -1139,7 +1139,7 @@ u_char *str;
msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + sizeof (u32_t) +
SHA_DIGESTSIZE;
- p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
@@ -1170,7 +1170,7 @@ static void eap_send_nak(ppp_pcb *pcb, u_char id, u_char type) {
int msglen;
msglen = EAP_HEADERLEN + 2 * sizeof (u_char);
- p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
diff --git a/SylixOS/net/lwip/src/netif/ppp/fsm.c b/SylixOS/net/lwip/src/netif/ppp/fsm.c
index d299f86..2ba1207 100644
--- a/SylixOS/net/lwip/src/netif/ppp/fsm.c
+++ b/SylixOS/net/lwip/src/netif/ppp/fsm.c
@@ -735,7 +735,7 @@ static void fsm_sconfreq(fsm *f, int retransmit) {
} else
cilen = 0;
- p = pbuf_alloc(PBUF_RAW, (u16_t)(cilen + HEADERLEN + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(cilen + HEADERLEN + PPP_HDRLEN), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
@@ -778,7 +778,7 @@ void fsm_sdata(fsm *f, u_char code, u_char id, const u_char *data, int datalen)
datalen = pcb->peer_mru - HEADERLEN;
outlen = datalen + HEADERLEN;
- p = pbuf_alloc(PBUF_RAW, (u16_t)(outlen + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(outlen + PPP_HDRLEN), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
diff --git a/SylixOS/net/lwip/src/netif/ppp/lcp.c b/SylixOS/net/lwip/src/netif/ppp/lcp.c
index e77ec40..9c55052 100644
--- a/SylixOS/net/lwip/src/netif/ppp/lcp.c
+++ b/SylixOS/net/lwip/src/netif/ppp/lcp.c
@@ -373,7 +373,7 @@ static void lcp_init(ppp_pcb *pcb) {
BZERO(wo, sizeof(*wo));
wo->neg_mru = 1;
- wo->mru = PPP_DEFMRU;
+ wo->mru = PPP_MRU;
wo->neg_asyncmap = 1;
wo->neg_magicnumber = 1;
wo->neg_pcompression = 1;
@@ -462,11 +462,11 @@ void lcp_lowerup(ppp_pcb *pcb) {
* but accept A/C and protocol compressed packets
* if we are going to ask for A/C and protocol compression.
*/
- if (ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0) < 0
- || ppp_recv_config(pcb, PPP_MRU, (pcb->settings.lax_recv? 0: 0xffffffff),
+ if (ppp_send_config(pcb, PPP_DEFMRU, 0xffffffff, 0, 0) < 0
+ || ppp_recv_config(pcb, PPP_DEFMRU, (pcb->settings.lax_recv? 0: 0xffffffff),
wo->neg_pcompression, wo->neg_accompression) < 0)
return;
- pcb->peer_mru = PPP_MRU;
+ pcb->peer_mru = PPP_DEFMRU;
if (pcb->settings.listen_time != 0) {
f->flags |= DELAYED_UP;
@@ -757,7 +757,7 @@ static void lcp_resetci(fsm *f) {
#endif /* HAVE_MULTILINK */
if (pcb->settings.noendpoint)
ao->neg_endpoint = 0;
- pcb->peer_mru = PPP_MRU;
+ pcb->peer_mru = PPP_DEFMRU;
#if 0 /* UNUSED */
auth_reset(pcb);
#endif /* UNUSED */
@@ -1843,7 +1843,7 @@ static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree) {
* Process all his options.
*/
next = inp;
- nakp = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE);
+ nakp = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_UNKNOWN_SIZE), PBUF_RAM);
if(NULL == nakp)
return 0;
if(nakp->tot_len != nakp->len) {
@@ -2309,12 +2309,12 @@ static void lcp_up(fsm *f) {
* the interface MTU is set to the lowest of that, the
* MTU we want to use, and our link MRU.
*/
- mtu = ho->neg_mru? ho->mru: PPP_MRU;
- mru = go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU;
+ mtu = ho->neg_mru? ho->mru: PPP_DEFMRU;
+ mru = go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_DEFMRU;
#ifdef HAVE_MULTILINK
if (!(multilink && go->neg_mrru && ho->neg_mrru))
#endif /* HAVE_MULTILINK */
- netif_set_mtu(pcb, LWIP_MIN(LWIP_MIN(mtu, mru), ao->mru));
+ ppp_netif_set_mtu(pcb, LWIP_MIN(LWIP_MIN(mtu, mru), ao->mru));
ppp_send_config(pcb, mtu,
(ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
ho->neg_pcompression, ho->neg_accompression);
@@ -2344,11 +2344,11 @@ static void lcp_down(fsm *f) {
link_down(pcb);
- ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0);
- ppp_recv_config(pcb, PPP_MRU,
+ ppp_send_config(pcb, PPP_DEFMRU, 0xffffffff, 0, 0);
+ ppp_recv_config(pcb, PPP_DEFMRU,
(go->neg_asyncmap? go->asyncmap: 0xffffffff),
go->neg_pcompression, go->neg_accompression);
- pcb->peer_mru = PPP_MRU;
+ pcb->peer_mru = PPP_DEFMRU;
}
diff --git a/SylixOS/net/lwip/src/netif/ppp/magic.c b/SylixOS/net/lwip/src/netif/ppp/magic.c
index 21911af..ce21326 100644
--- a/SylixOS/net/lwip/src/netif/ppp/magic.c
+++ b/SylixOS/net/lwip/src/netif/ppp/magic.c
@@ -114,12 +114,12 @@ static void magic_churnrand(char *rand_data, u32_t rand_len) {
u32_t rand;
#endif /* LWIP_RAND */
} sys_data;
+ /* Load sys_data fields here. */
magic_randomseed += sys_jiffies();
sys_data.jiffies = magic_randomseed;
#ifdef LWIP_RAND
sys_data.rand = LWIP_RAND();
#endif /* LWIP_RAND */
- /* Load sys_data fields here. */
lwip_md5_update(&md5_ctx, (u_char *)&sys_data, sizeof(sys_data));
}
lwip_md5_finish(&md5_ctx, (u_char *)magic_randpool);
@@ -142,7 +142,7 @@ void magic_randomize(void) {
}
/*
- * magic_random_bytes - Fill a buffer with random bytes.
+ * Fill a buffer with random bytes.
*
* Use the random pool to generate random data. This degrades to pseudo
* random when used faster than randomness is supplied using magic_churnrand().
@@ -180,56 +180,45 @@ void magic_random_bytes(unsigned char *buf, u32_t buf_len) {
}
/*
- * Return a new random number.
+ * Return a new 32-bit random number.
*/
u32_t magic(void) {
u32_t new_rand;
magic_random_bytes((unsigned char *)&new_rand, sizeof(new_rand));
-
return new_rand;
}
#else /* PPP_MD5_RANDM */
-/*****************************/
-/*** LOCAL DATA STRUCTURES ***/
-/*****************************/
#ifndef LWIP_RAND
static int magic_randomized; /* Set when truly randomized. */
#endif /* LWIP_RAND */
static u32_t magic_randomseed; /* Seed used for random number generation. */
-
-/***********************************/
-/*** PUBLIC FUNCTION DEFINITIONS ***/
-/***********************************/
-
/*
* Initialize the random number generator.
*
* Here we attempt to compute a random number seed but even if
* it isn't random, we'll randomize it later.
*
- * The current method uses the fields from the real time clock,
- * the idle process counter, the millisecond counter, and the
- * hardware timer tick counter. When this is invoked
- * in startup(), then the idle counter and timer values may
- * repeat after each boot and the real time clock may not be
- * operational. Thus we call it again on the first random
- * event.
+ * The current method uses the jiffies counter. When this is
+ * invoked at startup the jiffies counter value may repeat
+ * after each boot. Thus we call it again on the first
+ * random event.
+ *
+ * If LWIP_RAND if available, we do not call srand() as we are
+ * not going to call rand().
*/
void magic_init(void) {
magic_randomseed += sys_jiffies();
#ifndef LWIP_RAND
- /* Initialize the Borland random number generator. */
+ /* Initialize the random number generator. */
srand((unsigned)magic_randomseed);
#endif /* LWIP_RAND */
}
/*
- * magic_init - Initialize the magic number generator.
- *
* Randomize our random seed value. Here we use the fact that
* this function is called at *truly random* times by the polling
* and network functions. Here we only get 16 bits of new random
@@ -242,34 +231,37 @@ void magic_randomize(void) {
magic_randomized = !0;
magic_init();
/* The initialization function also updates the seed. */
- } else {
-#endif /* LWIP_RAND */
- magic_randomseed += sys_jiffies();
-#ifndef LWIP_RAND
+ return;
}
#endif /* LWIP_RAND */
+ magic_randomseed += sys_jiffies();
}
/*
- * Return a new random number.
+ * Return a new 32-bit random number.
*
- * Here we use the Borland rand() function to supply a pseudo random
+ * Here we use the rand() function to supply a pseudo random
* number which we make truly random by combining it with our own
* seed which is randomized by truly random events.
* Thus the numbers will be truly random unless there have been no
* operator or network events in which case it will be pseudo random
- * seeded by the real time clock.
+ * seeded by srand().
+ *
+ * Alternatively, use LWIP_RAND if available, but we do not assume
+ * it is returning 32 bits of random data because it is probably
+ * going to be defined to directly return the rand() value. For
+ * example, LCP magic numbers are 32-bit random values.
*/
u32_t magic(void) {
#ifdef LWIP_RAND
- return LWIP_RAND() + magic_randomseed;
+ return (LWIP_RAND() << 16) + LWIP_RAND() + magic_randomseed;
#else /* LWIP_RAND */
return ((u32_t)rand() << 16) + (u32_t)rand() + magic_randomseed;
#endif /* LWIP_RAND */
}
/*
- * magic_random_bytes - Fill a buffer with random bytes.
+ * Fill a buffer with random bytes.
*/
void magic_random_bytes(unsigned char *buf, u32_t buf_len) {
u32_t new_rand, n;
diff --git a/SylixOS/net/lwip/src/netif/ppp/multilink.c b/SylixOS/net/lwip/src/netif/ppp/multilink.c
index 62014e8..795d6b5 100644
--- a/SylixOS/net/lwip/src/netif/ppp/multilink.c
+++ b/SylixOS/net/lwip/src/netif/ppp/multilink.c
@@ -142,18 +142,18 @@ mp_join_bundle()
/* not doing multilink */
if (go->neg_mrru)
notice("oops, multilink negotiated only for receive");
- mtu = ho->neg_mru? ho->mru: PPP_MRU;
+ mtu = ho->neg_mru? ho->mru: PPP_DEFMRU;
if (mtu > ao->mru)
mtu = ao->mru;
if (demand) {
/* already have a bundle */
cfg_bundle(0, 0, 0, 0);
- netif_set_mtu(pcb, mtu);
+ ppp_netif_set_mtu(pcb, mtu);
return 0;
}
make_new_bundle(0, 0, 0, 0);
set_ifunit(1);
- netif_set_mtu(pcb, mtu);
+ ppp_netif_set_mtu(pcb, mtu);
return 0;
}
@@ -198,7 +198,7 @@ mp_join_bundle()
mtu = LWIP_MIN(ho->mrru, ao->mru);
if (demand) {
cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
- netif_set_mtu(pcb, mtu);
+ ppp_netif_set_mtu(pcb, mtu);
script_setenv("BUNDLE", bundle_id + 7, 1);
return 0;
}
@@ -245,7 +245,7 @@ mp_join_bundle()
/* we have to make a new bundle */
make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf);
set_ifunit(1);
- netif_set_mtu(pcb, mtu);
+ ppp_netif_set_mtu(pcb, mtu);
script_setenv("BUNDLE", bundle_id + 7, 1);
make_bundle_links(pcb);
unlock_db();
diff --git a/SylixOS/net/lwip/src/netif/ppp/ppp.c b/SylixOS/net/lwip/src/netif/ppp/ppp.c
index 4555d89..8d3ae13 100644
--- a/SylixOS/net/lwip/src/netif/ppp/ppp.c
+++ b/SylixOS/net/lwip/src/netif/ppp/ppp.c
@@ -216,7 +216,8 @@ static err_t ppp_netif_output(struct netif *netif, struct pbuf *pb, u16_t protoc
/***********************************/
#if PPP_AUTH_SUPPORT
void ppp_set_auth(ppp_pcb *pcb, u8_t authtype, const char *user, const char *passwd) {
- LWIP_ASSERT_CORE_LOCKED();
+ LWIP_ASSERT("pcb->phase == PPP_PHASE_DEAD", pcb->phase == PPP_PHASE_DEAD);
+
#if PAP_SUPPORT
pcb->settings.refuse_pap = !(authtype & PPPAUTHTYPE_PAP);
#endif /* PAP_SUPPORT */
@@ -238,6 +239,8 @@ void ppp_set_auth(ppp_pcb *pcb, u8_t authtype, const char *user, const char *pas
#if MPPE_SUPPORT
/* Set MPPE configuration */
void ppp_set_mppe(ppp_pcb *pcb, u8_t flags) {
+ LWIP_ASSERT("pcb->phase == PPP_PHASE_DEAD", pcb->phase == PPP_PHASE_DEAD);
+
if (flags == PPP_MPPE_DISABLE) {
pcb->settings.require_mppe = 0;
return;
@@ -252,6 +255,7 @@ void ppp_set_mppe(ppp_pcb *pcb, u8_t flags) {
#if PPP_NOTIFY_PHASE
void ppp_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb) {
+ LWIP_ASSERT_CORE_LOCKED();
pcb->notify_phase_cb = notify_phase_cb;
notify_phase_cb(pcb, pcb->phase, pcb->ctx_cb);
}
@@ -670,9 +674,9 @@ ppp_pcb *ppp_new(struct netif *pppif, const struct link_callbacks *callbacks, vo
#endif /* PAP_SUPPORT */
#if CHAP_SUPPORT
+#if PPP_SERVER
pcb->settings.chap_timeout_time = CHAP_DEFTIMEOUT;
pcb->settings.chap_max_transmits = CHAP_DEFTRANSMITS;
-#if PPP_SERVER
pcb->settings.chap_rechallenge_time = CHAP_DEFRECHALLENGETIME;
#endif /* PPP_SERVER */
#endif /* CHAP_SUPPPORT */
@@ -775,8 +779,10 @@ void ppp_link_end(ppp_pcb *pcb) {
void ppp_input(ppp_pcb *pcb, struct pbuf *pb) {
u16_t protocol;
#if PPP_DEBUG && PPP_PROTOCOLNAME
- const char *pname;
+ const char *pname;
#endif /* PPP_DEBUG && PPP_PROTOCOLNAME */
+ LWIP_ASSERT("pcb->phase >= PPP_PHASE_ESTABLISH && pcb->phase <= PPP_PHASE_TERMINATE",
+ pcb->phase >= PPP_PHASE_ESTABLISH && pcb->phase <= PPP_PHASE_TERMINATE);
magic_randomize();
@@ -874,7 +880,7 @@ void ppp_input(ppp_pcb *pcb, struct pbuf *pb) {
}
#endif /* CCP_SUPPORT */
- switch(protocol) {
+ switch (protocol) {
#if PPP_IPV4_SUPPORT
case PPP_IP: /* Internet Protocol */
@@ -930,6 +936,10 @@ void ppp_input(ppp_pcb *pcb, struct pbuf *pb) {
for (i = 0; (protp = protocols[i]) != NULL; ++i) {
if (protp->protocol == protocol) {
pb = pbuf_coalesce(pb, PBUF_RAW);
+ if (pb->next != NULL) {
+ PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping (pbuf_coalesce failed), len=%d\n", pcb->netif->num, pb->tot_len));
+ goto drop;
+ }
(*protp->input)(pcb, (u8_t*)pb->payload, pb->len);
goto out;
}
@@ -963,13 +973,14 @@ void ppp_input(ppp_pcb *pcb, struct pbuf *pb) {
#endif /* PPP_PROTOCOLNAME */
ppp_warn(("Unsupported protocol 0x%x received", protocol));
#endif /* PPP_DEBUG */
- if (pbuf_add_header(pb, sizeof(protocol))) {
- PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping (pbuf_add_header failed)\n", pcb->netif->num));
- goto drop;
- }
- lcp_sprotrej(pcb, (u8_t*)pb->payload, pb->len);
+
+ if (pbuf_add_header(pb, sizeof(protocol))) {
+ PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping (pbuf_add_header failed)\n", pcb->netif->num));
+ goto drop;
}
- break;
+ lcp_sprotrej(pcb, (u8_t*)pb->payload, pb->len);
+ }
+ break;
}
drop:
@@ -1026,13 +1037,13 @@ void new_phase(ppp_pcb *pcb, int p) {
*/
int ppp_send_config(ppp_pcb *pcb, int mtu, u32_t accm, int pcomp, int accomp) {
LWIP_UNUSED_ARG(mtu);
- /* pcb->mtu = mtu; -- set correctly with netif_set_mtu */
+
+ PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]\n", pcb->netif->num));
if (pcb->link_cb->send_config) {
pcb->link_cb->send_config(pcb, pcb->link_ctx_cb, accm, pcomp, accomp);
}
- PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]\n", pcb->netif->num) );
return 0;
}
@@ -1043,11 +1054,12 @@ int ppp_send_config(ppp_pcb *pcb, int mtu, u32_t accm, int pcomp, int accomp) {
int ppp_recv_config(ppp_pcb *pcb, int mru, u32_t accm, int pcomp, int accomp) {
LWIP_UNUSED_ARG(mru);
+ PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]\n", pcb->netif->num));
+
if (pcb->link_cb->recv_config) {
pcb->link_cb->recv_config(pcb, pcb->link_ctx_cb, accm, pcomp, accomp);
}
- PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]\n", pcb->netif->num));
return 0;
}
@@ -1341,18 +1353,21 @@ int sifnpmode(ppp_pcb *pcb, int proto, enum NPmode mode) {
#endif /* DEMAND_SUPPORT */
/*
- * netif_set_mtu - set the MTU on the PPP network interface.
+ * ppp_netif_set_mtu - set the MTU on the PPP network interface.
*/
-void netif_set_mtu(ppp_pcb *pcb, int mtu) {
+void ppp_netif_set_mtu(ppp_pcb *pcb, int mtu) {
pcb->netif->mtu = mtu;
- PPPDEBUG(LOG_INFO, ("netif_set_mtu[%d]: mtu=%d\n", pcb->netif->num, mtu));
+#if PPP_IPV6_SUPPORT && LWIP_ND6_ALLOW_RA_UPDATES
+ pcb->netif->mtu6 = mtu;
+#endif /* PPP_IPV6_SUPPORT && LWIP_ND6_ALLOW_RA_UPDATES */
+ PPPDEBUG(LOG_INFO, ("ppp_netif_set_mtu[%d]: mtu=%d\n", pcb->netif->num, mtu));
}
/*
- * netif_get_mtu - get PPP interface MTU
+ * ppp_netif_get_mtu - get PPP interface MTU
*/
-int netif_get_mtu(ppp_pcb *pcb) {
+int ppp_netif_get_mtu(ppp_pcb *pcb) {
return pcb->netif->mtu;
}
diff --git a/SylixOS/net/lwip/src/netif/ppp/pppoe.c b/SylixOS/net/lwip/src/netif/ppp/pppoe.c
index de16451..86b1815 100644
--- a/SylixOS/net/lwip/src/netif/ppp/pppoe.c
+++ b/SylixOS/net/lwip/src/netif/ppp/pppoe.c
@@ -175,12 +175,29 @@ ppp_pcb *pppoe_create(struct netif *pppif,
{
ppp_pcb *ppp;
struct pppoe_softc *sc;
-#if !PPPOE_SCNAME_SUPPORT
+#if PPPOE_SCNAME_SUPPORT
+ size_t l;
+#else /* PPPOE_SCNAME_SUPPORT */
LWIP_UNUSED_ARG(service_name);
LWIP_UNUSED_ARG(concentrator_name);
-#endif /* !PPPOE_SCNAME_SUPPORT */
+#endif /* PPPOE_SCNAME_SUPPORT */
LWIP_ASSERT_CORE_LOCKED();
+#if PPPOE_SCNAME_SUPPORT
+ /*
+ * Check that service_name and concentrator_name strings length will
+ * not trigger integer overflows when computing packets length.
+ */
+ l = strlen(service_name);
+ if (l > 1024) {
+ return NULL;
+ }
+ l = strlen(concentrator_name);
+ if (l > 1024) {
+ return NULL;
+ }
+#endif /* PPPOE_SCNAME_SUPPORT */
+
sc = (struct pppoe_softc *)LWIP_MEMPOOL_ALLOC(PPPOE_IF);
if (sc == NULL) {
return NULL;
@@ -406,6 +423,10 @@ pppoe_disc_input(struct netif *netif, struct pbuf *pb)
}
pb = pbuf_coalesce(pb, PBUF_RAW);
+ if (pb->next != NULL) {
+ PPPDEBUG(LOG_DEBUG, ("pppoe: pbuf_coalesce failed: %d\n", pb->tot_len));
+ goto done;
+ }
ethhdr = (struct eth_hdr *)pb->payload;
@@ -766,20 +787,20 @@ pppoe_send_padi(struct pppoe_softc *sc)
{
struct pbuf *pb;
u8_t *p;
- int len;
+ size_t len;
#if PPPOE_SCNAME_SUPPORT
- int l1 = 0, l2 = 0; /* XXX: gcc */
+ size_t l1 = 0, l2 = 0; /* XXX: gcc */
#endif /* PPPOE_SCNAME_SUPPORT */
/* calculate length of frame (excluding ethernet header + pppoe header) */
len = 2 + 2 + 2 + 2 + sizeof sc; /* service name tag is required, host unique is send too */
#if PPPOE_SCNAME_SUPPORT
if (sc->sc_service_name != NULL) {
- l1 = (int)strlen(sc->sc_service_name);
+ l1 = strlen(sc->sc_service_name);
len += l1;
}
if (sc->sc_concentrator_name != NULL) {
- l2 = (int)strlen(sc->sc_concentrator_name);
+ l2 = strlen(sc->sc_concentrator_name);
len += 2 + 2 + l2;
}
#ifdef SYLIXOS /* SylixOS Add empty AC name */
@@ -872,7 +893,6 @@ pppoe_timeout(void *arg)
/* initialize for quick retry mode */
retry_wait = LWIP_MIN(PPPOE_DISC_TIMEOUT * sc->sc_padi_retried, PPPOE_SLOW_RETRY);
if ((err = pppoe_send_padi(sc)) != 0) {
- sc->sc_padi_retried--;
PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to transmit PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));
LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */
}
@@ -893,7 +913,6 @@ pppoe_timeout(void *arg)
return;
}
if ((err = pppoe_send_padr(sc)) != 0) {
- sc->sc_padr_retried--;
PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));
LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */
}
diff --git a/SylixOS/net/lwip/src/netif/ppp/pppol2tp.c b/SylixOS/net/lwip/src/netif/ppp/pppol2tp.c
index 4c4557f..a6a0421 100644
--- a/SylixOS/net/lwip/src/netif/ppp/pppol2tp.c
+++ b/SylixOS/net/lwip/src/netif/ppp/pppol2tp.c
@@ -172,6 +172,9 @@ static err_t pppol2tp_write(ppp_pcb *ppp, void *ctx, struct pbuf *p) {
LWIP_UNUSED_ARG(ppp);
#endif /* MIB2_STATS */
+ /* skip address & flags */
+ pbuf_remove_header(p, 2);
+
ph = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(PPPOL2TP_OUTPUT_DATA_HEADER_LEN), PBUF_RAM);
if(!ph) {
LINK_STATS_INC(link.memerr);
@@ -440,7 +443,7 @@ static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const
/* printf("LEN=%d, TUNNEL_ID=%d, SESSION_ID=%d, NS=%d, NR=%d, OFFSET=%d\n", len, tunnel_id, session_id, ns, nr, offset); */
PPPDEBUG(LOG_DEBUG, ("pppol2tp: input packet, len=%"U16_F", tunnel=%"U16_F", session=%"U16_F", ns=%"U16_F", nr=%"U16_F"\n",
- len, tunnel_id, session_id, ns, nr));
+ p->tot_len, tunnel_id, session_id, ns, nr));
/* Control packet */
if (hflags & PPPOL2TP_HEADERFLAG_CONTROL) {
@@ -463,8 +466,16 @@ static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, const
/*
* skip address & flags if necessary
*
- * RFC 2661 does not specify whether the PPP frame in the L2TP payload should
- * have a HDLC header or not. We handle both cases for compatibility.
+ * RFC 2661 (L2TPv2) does not specify whether the PPP frame in the L2TP payload
+ * should have a HDLC header or not, both behaviors are seen in the wild.
+ *
+ * On the other hand, L2TPv3 draft-ietf-l2tpext-l2tp-ppp versions 00 and 01 say
+ * it must be included, versions 02 to 05 say it must be omitted, and versions
+ * 06 and onwards say it should be omitted so it changed along the path when
+ * L2TPv3 was designed. Latest versions state that receivers must handle both
+ * cases.
+ *
+ * We handle both cases for compatibility.
*/
if (p->len >= 2) {
GETSHORT(hflags, inp);
@@ -530,6 +541,11 @@ static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, u16_t port, str
l2tp->peer_ns = ns+1;
p = pbuf_coalesce(p, PBUF_RAW);
+ if (p->next != NULL) {
+ PPPDEBUG(LOG_DEBUG, ("pppol2tp: pbuf_coalesce failed: %d\n", p->tot_len));
+ return;
+ }
+
inp = (u8_t*)p->payload;
/* Decode AVPs */
while (p->len > 0) {
@@ -749,7 +765,6 @@ static void pppol2tp_timeout(void *arg) {
retry_wait = LWIP_MIN(PPPOL2TP_CONTROL_TIMEOUT * l2tp->sccrq_retried, PPPOL2TP_SLOW_RETRY);
PPPDEBUG(LOG_DEBUG, ("pppol2tp: sccrq_retried=%d\n", l2tp->sccrq_retried));
if ((err = pppol2tp_send_sccrq(l2tp)) != 0) {
- l2tp->sccrq_retried--;
PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCRQ, error=%d\n", err));
LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */
}
@@ -765,7 +780,6 @@ static void pppol2tp_timeout(void *arg) {
PPPDEBUG(LOG_DEBUG, ("pppol2tp: icrq_retried=%d\n", l2tp->icrq_retried));
if ((s16_t)(l2tp->peer_nr - l2tp->our_ns) < 0) { /* the SCCCN was not acknowledged */
if ((err = pppol2tp_send_scccn(l2tp, l2tp->our_ns -1)) != 0) {
- l2tp->icrq_retried--;
PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCCN, error=%d\n", err));
LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */
sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp);
@@ -773,7 +787,6 @@ static void pppol2tp_timeout(void *arg) {
}
}
if ((err = pppol2tp_send_icrq(l2tp, l2tp->our_ns)) != 0) {
- l2tp->icrq_retried--;
PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICRQ, error=%d\n", err));
LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */
}
@@ -788,7 +801,6 @@ static void pppol2tp_timeout(void *arg) {
}
PPPDEBUG(LOG_DEBUG, ("pppol2tp: iccn_retried=%d\n", l2tp->iccn_retried));
if ((err = pppol2tp_send_iccn(l2tp, l2tp->our_ns)) != 0) {
- l2tp->iccn_retried--;
PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICCN, error=%d\n", err));
LWIP_UNUSED_ARG(err); /* if PPPDEBUG is disabled */
}
diff --git a/SylixOS/net/lwip/src/netif/ppp/pppos.c b/SylixOS/net/lwip/src/netif/ppp/pppos.c
index 57a4cf5..71fe25b 100644
--- a/SylixOS/net/lwip/src/netif/ppp/pppos.c
+++ b/SylixOS/net/lwip/src/netif/ppp/pppos.c
@@ -207,10 +207,9 @@ pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p)
err_t err;
LWIP_UNUSED_ARG(ppp);
- /* Grab an output buffer. Using PBUF_POOL here for tx is ok since the pbuf
- gets freed by 'pppos_output_last' before this function returns and thus
- cannot starve rx. */
- nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
+ /* Grab an output buffer. Assume PBUF_POOL_BUFSIZE is an acceptable
+ * chunk size for Tx as well. */
+ nb = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_RAM);
if (nb == NULL) {
PPPDEBUG(LOG_WARNING, ("pppos_write[%d]: alloc fail\n", ppp->netif->num));
LINK_STATS_INC(link.memerr);
@@ -220,6 +219,8 @@ pppos_write(ppp_pcb *ppp, void *ctx, struct pbuf *p)
return ERR_MEM;
}
+ /* Empty the buffer */
+ nb->len = 0;
/* Set nb->tot_len to actual payload length */
nb->tot_len = p->len;
@@ -258,10 +259,9 @@ pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol)
err_t err;
LWIP_UNUSED_ARG(ppp);
- /* Grab an output buffer. Using PBUF_POOL here for tx is ok since the pbuf
- gets freed by 'pppos_output_last' before this function returns and thus
- cannot starve rx. */
- nb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
+ /* Grab an output buffer. Assume PBUF_POOL_BUFSIZE is an acceptable
+ * chunk size for Tx as well. */
+ nb = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_RAM);
if (nb == NULL) {
PPPDEBUG(LOG_WARNING, ("pppos_netif_output[%d]: alloc fail\n", ppp->netif->num));
LINK_STATS_INC(link.memerr);
@@ -270,6 +270,8 @@ pppos_netif_output(ppp_pcb *ppp, void *ctx, struct pbuf *pb, u16_t protocol)
return ERR_MEM;
}
+ /* Empty the buffer */
+ nb->len = 0;
/* Set nb->tot_len to actual payload length */
nb->tot_len = pb->tot_len;
@@ -420,7 +422,7 @@ pppos_destroy(ppp_pcb *ppp, void *ctx)
* @param l length of received data
*/
err_t
-pppos_input_tcpip(ppp_pcb *ppp, u8_t *s, int l)
+pppos_input_tcpip(ppp_pcb *ppp, const void *s, int l)
{
struct pbuf *p;
err_t err;
@@ -445,7 +447,7 @@ err_t pppos_input_sys(struct pbuf *p, struct netif *inp) {
LWIP_ASSERT_CORE_LOCKED();
for (n = p; n; n = n->next) {
- pppos_input(ppp, (u8_t*)n->payload, n->len);
+ pppos_input(ppp, n->payload, n->len);
}
pbuf_free(p);
return ERR_OK;
@@ -475,10 +477,11 @@ PACK_STRUCT_END
* @param l length of received data
*/
void
-pppos_input(ppp_pcb *ppp, u8_t *s, int l)
+pppos_input(ppp_pcb *ppp, const void *s, int l)
{
pppos_pcb *pppos = (pppos_pcb *)ppp->link_ctx_cb;
struct pbuf *next_pbuf;
+ const u8_t *s_u8 = (const u8_t *)s;
u8_t cur_char;
u8_t escaped;
PPPOS_DECL_PROTECT(lev);
@@ -486,22 +489,24 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l)
LWIP_ASSERT_CORE_LOCKED();
#endif
+ /* Don't even bother parsing data if we are disconnected.
+ * Added to that, ppp_input must never be called if the upper layer is down.
+ */
+ PPPOS_PROTECT(lev);
+ if (!pppos->open) {
+ PPPOS_UNPROTECT(lev);
+ return;
+ }
+ PPPOS_UNPROTECT(lev);
+
PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", ppp->netif->num, l));
while (l-- > 0) {
- cur_char = *s++;
+ cur_char = *s_u8++;
PPPOS_PROTECT(lev);
- /* ppp_input can disconnect the interface, we need to abort to prevent a memory
- * leak if there are remaining bytes because pppos_connect and pppos_listen
- * functions expect input buffer to be free. Furthermore there are no real
- * reason to continue reading bytes if we are disconnected.
- */
- if (!pppos->open) {
- PPPOS_UNPROTECT(lev);
- return;
- }
escaped = ESCAPE_P(pppos->in_accm, cur_char);
PPPOS_UNPROTECT(lev);
+
/* Handle special characters. */
if (escaped) {
/* Check for escape sequences. */
@@ -558,7 +563,16 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l)
pppos->in_tail = NULL;
#if IP_FORWARD || LWIP_IPV6_FORWARD
/* hide the room for Ethernet forwarding header */
- pbuf_remove_header(inp, PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN);
+ if (0
+#if PPP_IPV4_SUPPORT
+ || pppos->in_protocol == PPP_IP
+#endif /* PPP_IPV4_SUPPORT */
+#if PPP_IPV6_SUPPORT
+ || pppos->in_protocol == PPP_IPV6
+#endif /* PPP_IPV6_SUPPORT */
+ ) {
+ pbuf_remove_header(inp, PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN);
+ }
#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
#if PPP_INPROC_IRQ_SAFE
if(tcpip_try_callback(pppos_input_callback, inp) != ERR_OK) {
@@ -569,6 +583,14 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l)
}
#else /* PPP_INPROC_IRQ_SAFE */
ppp_input(ppp, inp);
+ /* ppp_input can disconnect the interface, we need to abort to prevent a memory
+ * leak if there are remaining bytes because pppos_connect and pppos_listen
+ * functions expect input buffer to be free. Furthermore there are no real
+ * reason to continue reading bytes if we are disconnected.
+ */
+ if (!pppos->open) {
+ break;
+ }
#endif /* PPP_INPROC_IRQ_SAFE */
}
@@ -591,50 +613,24 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l)
}
/* Process character relative to current state. */
- switch(pppos->in_state) {
- case PDIDLE: /* Idle state - waiting. */
- /* Drop the character if it's not 0xff
- * we would have processed a flag character above. */
- if (cur_char != PPP_ALLSTATIONS) {
- break;
- }
- /* no break */
- /* Fall through */
-
- case PDSTART: /* Process start flag. */
- /* Prepare for a new packet. */
- pppos->in_fcs = PPP_INITFCS;
- /* no break */
- /* Fall through */
-
+ switch (pppos->in_state) {
+ case PDIDLE: /* Idle state - wait for flag character. */
+ break;
case PDADDRESS: /* Process address field. */
if (cur_char == PPP_ALLSTATIONS) {
pppos->in_state = PDCONTROL;
break;
}
- /* no break */
-
/* Else assume compressed address and control fields so
* fall through to get the protocol... */
/* Fall through */
case PDCONTROL: /* Process control field. */
- /* If we don't get a valid control code, restart. */
if (cur_char == PPP_UI) {
pppos->in_state = PDPROTOCOL1;
break;
}
- /* no break */
-
-#if 0
- else {
- PPPDEBUG(LOG_WARNING,
- ("pppos_input[%d]: Invalid control <%d>\n", ppp->netif->num, cur_char));
- pppos->in_state = PDSTART;
- }
-#endif
/* Fall through */
-
- case PDPROTOCOL1: /* Process protocol field 1. */
+ case PDPROTOCOL1: /* Process protocol field 1. */
/* If the lower bit is set, this is the end of the protocol
* field. */
if (cur_char & 1) {
@@ -654,12 +650,37 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l)
if (pppos->in_tail == NULL || pppos->in_tail->len == PBUF_POOL_BUFSIZE) {
u16_t pbuf_alloc_len;
if (pppos->in_tail != NULL) {
+ u16_t mru;
pppos->in_tail->tot_len = pppos->in_tail->len;
if (pppos->in_tail != pppos->in_head) {
pbuf_cat(pppos->in_head, pppos->in_tail);
/* give up the in_tail reference now */
pppos->in_tail = NULL;
}
+ /* Compute MRU including headers length. If smaller packets are
+ * requested, we must still be able to receive packets of the
+ * default MRU for control packets. */
+ mru = LWIP_MAX(PPP_MRU, PPP_DEFMRU)
+ /* Add 10% more. We only want to avoid filling all PBUFs with garbage,
+ * we don't have to be pedantic. */
+ + LWIP_MAX(PPP_MRU, PPP_DEFMRU)/10
+#if IP_FORWARD || LWIP_IPV6_FORWARD
+ + PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN
+#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
+#if PPP_INPROC_IRQ_SAFE
+ + sizeof(struct pppos_input_header)
+#endif /* PPP_INPROC_IRQ_SAFE */
+ + sizeof(pppos->in_protocol);
+ if (pppos->in_head->tot_len > mru) {
+ /* Packet too big. Drop the input packet and let the
+ * higher layers deal with it. Continue processing
+ * received characters in case a new packet starts. */
+ PPPDEBUG(LOG_ERR, ("pppos_input[%d]: packet too big, max_len=%d, dropping packet\n", ppp->netif->num, mru));
+ LINK_STATS_INC(link.lenerr);
+ pppos_input_drop(pppos);
+ pppos->in_state = PDIDLE; /* Wait for flag character. */
+ break;
+ }
}
/* If we haven't started a packet, we need a packet header. */
pbuf_alloc_len = 0;
@@ -668,7 +689,14 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l)
* + PBUF_LINK_HLEN bytes so the packet is being allocated with enough header
* space to be forwarded (to Ethernet for example).
*/
- if (pppos->in_head == NULL) {
+ if (pppos->in_head == NULL && (0
+#if PPP_IPV4_SUPPORT
+ || pppos->in_protocol == PPP_IP
+#endif /* PPP_IPV4_SUPPORT */
+#if PPP_IPV6_SUPPORT
+ || pppos->in_protocol == PPP_IPV6
+#endif /* PPP_IPV6_SUPPORT */
+ )) {
pbuf_alloc_len = PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN;
}
#endif /* IP_FORWARD || LWIP_IPV6_FORWARD */
@@ -676,11 +704,11 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l)
if (next_pbuf == NULL) {
/* No free buffers. Drop the input packet and let the
* higher layers deal with it. Continue processing
- * the received pbuf chain in case a new packet starts. */
+ * received characters in case a new packet starts. */
PPPDEBUG(LOG_ERR, ("pppos_input[%d]: NO FREE PBUFS!\n", ppp->netif->num));
LINK_STATS_INC(link.memerr);
pppos_input_drop(pppos);
- pppos->in_state = PDSTART; /* Wait for flag sequence. */
+ pppos->in_state = PDIDLE; /* Wait for flag character. */
break;
}
if (pppos->in_head == NULL) {
@@ -716,6 +744,7 @@ pppos_input(ppp_pcb *ppp, u8_t *s, int l)
static void pppos_input_callback(void *arg) {
struct pbuf *pb = (struct pbuf*)arg;
ppp_pcb *ppp;
+ pppos_pcb *pppos;
ppp = ((struct pppos_input_header*)pb->payload)->ppp;
if(pbuf_remove_header(pb, sizeof(struct pppos_input_header))) {
@@ -723,6 +752,16 @@ static void pppos_input_callback(void *arg) {
goto drop;
}
+ /* A previous call to ppp_input might have disconnected the session
+ * while there were still packets in flight in the tcpip mailbox.
+ * Drop incoming packets because ppp_input must never be called if
+ * the upper layer is down.
+ */
+ pppos = (pppos_pcb *)ppp->link_ctx_cb;
+ if (!pppos->open) {
+ goto drop;
+ }
+
/* Dispatch the packet thereby consuming it. */
ppp_input(ppp, pb);
return;
@@ -830,7 +869,7 @@ pppos_output_append(pppos_pcb *pppos, err_t err, struct pbuf *nb, u8_t c, u8_t a
* Sure we don't quite fill the buffer if the character doesn't
* get escaped but is one character worth complicating this? */
if ((PBUF_POOL_BUFSIZE - nb->len) < 2) {
- u32_t l = pppos->output_cb(pppos->ppp, (u8_t*)nb->payload, nb->len, pppos->ppp->ctx_cb);
+ u32_t l = pppos->output_cb(pppos->ppp, nb->payload, nb->len, pppos->ppp->ctx_cb);
if (l != nb->len) {
return ERR_IF;
}
@@ -873,7 +912,7 @@ pppos_output_last(pppos_pcb *pppos, err_t err, struct pbuf *nb, u16_t *fcs)
/* Send remaining buffer if not empty */
if (nb->len > 0) {
- u32_t l = pppos->output_cb(ppp, (u8_t*)nb->payload, nb->len, ppp->ctx_cb);
+ u32_t l = pppos->output_cb(ppp, nb->payload, nb->len, ppp->ctx_cb);
if (l != nb->len) {
err = ERR_IF;
goto failed;
diff --git a/SylixOS/net/lwip/src/netif/ppp/upap.c b/SylixOS/net/lwip/src/netif/ppp/upap.c
index 1a1340a..c8cd394 100644
--- a/SylixOS/net/lwip/src/netif/ppp/upap.c
+++ b/SylixOS/net/lwip/src/netif/ppp/upap.c
@@ -481,6 +481,7 @@ static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len) {
}
}
+ UNTIMEOUT(upap_timeout, pcb);
pcb->upap.us_clientstate = UPAPCS_OPEN;
auth_withpeer_success(pcb, PPP_PAP, 0);
@@ -516,6 +517,7 @@ static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len) {
}
}
+ UNTIMEOUT(upap_timeout, pcb);
pcb->upap.us_clientstate = UPAPCS_BADAUTH;
ppp_error(("PAP authentication failed"));
@@ -533,7 +535,7 @@ static void upap_sauthreq(ppp_pcb *pcb) {
outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
pcb->upap.us_userlen + pcb->upap.us_passwdlen;
- p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
@@ -570,7 +572,7 @@ static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, in
int outlen;
outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
- p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE);
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PBUF_RAM);
if(NULL == p)
return;
if(p->tot_len != p->len) {
diff --git a/SylixOS/net/lwip/tools/ppp/lwip_ppp.c b/SylixOS/net/lwip/tools/ppp/lwip_ppp.c
index e20875b..4478926 100644
--- a/SylixOS/net/lwip/tools/ppp/lwip_ppp.c
+++ b/SylixOS/net/lwip/tools/ppp/lwip_ppp.c
@@ -284,7 +284,7 @@ static VOID __pppOsThread (ppp_pcb *pcb)
** 全局变量:
** 调用模块:
*********************************************************************************************************/
-static u32_t __pppOsOutput (ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx)
+static u32_t __pppOsOutput (ppp_pcb *pcb, const void *data, u32_t len, void *ctx)
{
PPP_CTX_PRIV *pctxp = (PPP_CTX_PRIV *)ctx;
u32_t uiRet;
diff --git a/SylixOS/system/device/base/baseDrvLib.c b/SylixOS/system/device/base/baseDrvLib.c
new file mode 100644
index 0000000..67a852b
--- /dev/null
+++ b/SylixOS/system/device/base/baseDrvLib.c
@@ -0,0 +1,638 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: baseDrvLib.c
+**
+** 创 建 人: Zhang.Jian (张健)
+**
+** 文件创建日期: 2019 年 10 月 28 日
+**
+** 描 述: 基础驱动框架库
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if (LW_CFG_DEVICE_EN > 0) && (LW_CFG_DEVTREE_EN > 0)
+#include "baseDrvLib.h"
+/*********************************************************************************************************
+ 静态函数声明
+*********************************************************************************************************/
+static INT __busAddDevice(PLW_DEV_INSTANCE pdevinstance);
+static VOID __busDelDevice(PLW_DEV_INSTANCE pdevinstance);
+static INT __busAddDriver(PLW_DRV_INSTANCE pdrvinstance);
+static VOID __busDelDriver(PLW_DRV_INSTANCE pdrvinstance);
+static VOID __devInit(PLW_DEV_INSTANCE pdevinstance);
+static INT __devAdd(PLW_DEV_INSTANCE pdevinstance);
+static VOID __devDel(PLW_DEV_INSTANCE pdevinstance);
+static VOID __devReleaseDrv(PLW_DEV_INSTANCE pdevinstance);
+static INT __drvAttach(PLW_DEV_INSTANCE pdevinstance, PLW_DRV_INSTANCE pdrvinstance);
+static VOID __drvDetach(PLW_DRV_INSTANCE pdrvinstance);
+static PLW_DRV_INSTANCE __drvFind(CPCHAR pcName, PLW_BUS_TYPE pbustype);
+static INT __drvMatchDev(PLW_DEV_INSTANCE pdevinstance, PLW_DRV_INSTANCE pdrvinstance);
+/*********************************************************************************************************
+ 内联函数
+*********************************************************************************************************/
+static LW_INLINE VOID __baseSemInit (LW_OBJECT_HANDLE *pulSem)
+{
+ if (*pulSem == LW_OBJECT_HANDLE_INVALID) {
+ *pulSem = API_SemaphoreMCreate("dt_base_lock", LW_PRIO_DEF_CEILING,
+ LW_OPTION_WAIT_PRIORITY | LW_OPTION_DELETE_SAFE |
+ LW_OPTION_INHERIT_PRIORITY | LW_OPTION_OBJECT_GLOBAL,
+ LW_NULL);
+ }
+}
+/*********************************************************************************************************
+ 各种操作锁的宏定义
+*********************************************************************************************************/
+#define __BUS_HD_LOCK_INIT(pbustype) __baseSemInit(&pbustype->BUS_hBusLock)
+#define __BUS_HD_LOCK_DEL(pbustype) API_SemaphoreMDelete(&pbustype->BUS_hBusLock)
+#define __BUS_HD_UNLOCK(pbustype) API_SemaphoreMPost(pbustype->BUS_hBusLock)
+#define __BUS_HD_LOCK(pbustype) API_SemaphoreMPend(pbustype->BUS_hBusLock, \
+ LW_OPTION_WAIT_INFINITE)
+
+#define __DEV_HD_LOCK_INIT(pdevinstance) __baseSemInit(&pdevinstance->DEVHD_hDevLock);
+#define __DEV_HD_LOCK_DEL(pbustype) API_SemaphoreMDelete(&pdevinstance->DEVHD_hDevLock)
+#define __DEV_HD_UNLOCK(pdevinstance) API_SemaphoreMPost(pdevinstance->DEVHD_hDevLock)
+#define __DEV_HD_LOCK(pdevinstance) API_SemaphoreMPend(pdevinstance->DEVHD_hDevLock, \
+ LW_OPTION_WAIT_INFINITE)
+
+#define __BUS_DEV_LIST_LOCK_INIT(pbustype) __baseSemInit(&pbustype->BUS_hDevListLock)
+#define __BUS_DEV_LIST_LOCK_DEL(pbustype) API_SemaphoreMDelete(&pbustype->BUS_hDevListLock)
+#define __BUS_DEV_LIST_UNLOCK(pbustype) API_SemaphoreMPost(pbustype->BUS_hDevListLock)
+#define __BUS_DEV_LIST_LOCK(pbustype) API_SemaphoreMPend(pbustype->BUS_hDevListLock, \
+ LW_OPTION_WAIT_INFINITE)
+
+#define __BUS_DRV_LIST_LOCK_INIT(pbustype) __baseSemInit(&pbustype->BUS_hDrvListLock)
+#define __BUS_DRV_LIST_LOCK_DEL(pbustype) API_SemaphoreMDelete(&pbustype->BUS_hDrvListLock)
+#define __BUS_DRV_LIST_UNLOCK(pbustype) API_SemaphoreMPost(pbustype->BUS_hDrvListLock)
+#define __BUS_DRV_LIST_LOCK(pbustype) API_SemaphoreMPend(pbustype->BUS_hDrvListLock, \
+ LW_OPTION_WAIT_INFINITE)
+
+#define __DRV_DEV_LIST_LOCK_INIT(pdrvinstance) __baseSemInit(&pdrvinstance->DRVHD_hDevListLock);
+#define __DRV_DEV_LIST_LOCK_DEL(pdrvinstance) API_SemaphoreMDelete(&pdrvinstance->DRVHD_hDevListLock);
+#define __DRV_DEV_LIST_UNLOCK(pdrvinstance) API_SemaphoreMPost(pdrvinstance->DRVHD_hDevListLock)
+#define __DRV_DEV_LIST_LOCK(pdrvinstance) API_SemaphoreMPend(pdrvinstance->DRVHD_hDevListLock, \
+ LW_OPTION_WAIT_INFINITE)
+/*********************************************************************************************************
+** 函数名称: __busAddDevice
+** 功能描述: 在总线上添加设备
+** 输 入 : pdevinstance 设备实例指针
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __busAddDevice (PLW_DEV_INSTANCE pdevinstance)
+{
+ PLW_DRV_INSTANCE pdrvinstance;
+ PLW_LIST_LINE plineNode;
+ PLW_BUS_TYPE pbustype = pdevinstance->DEVHD_pbustype;
+ INT iRet;
+
+ __BUS_DEV_LIST_LOCK(pbustype);
+ _List_Line_Add_Ahead(&pdevinstance->DEVHD_lineBus,
+ &pbustype->BUS_plineDevList); /* 添加设备到总线链表 */
+ __BUS_DEV_LIST_UNLOCK(pbustype);
+
+ if ((pbustype->BUS_uiFlag & BUS_AUTO_PROBE) && /* 总线使能了自动 probe */
+ (LW_NULL == pdevinstance->DEVHD_pdrvinstance)) {
+
+ __DEV_HD_LOCK(pdevinstance);
+ __BUS_DRV_LIST_LOCK(pbustype);
+
+ for (plineNode = pbustype->BUS_plineDrvList;
+ plineNode != LW_NULL;
+ plineNode = _list_line_get_next(plineNode)) { /* 遍历总线上的驱动 */
+
+ pdrvinstance = _LIST_ENTRY(plineNode, LW_DRV_INSTANCE, DRVHD_lineBus);
+ iRet = __drvMatchDev(pdevinstance, pdrvinstance); /* 设备与驱动进行匹配 */
+ if (!iRet) {
+ __drvAttach(pdevinstance, pdrvinstance); /* 匹配成功关联驱动 */
+ break;
+ }
+ }
+
+ __BUS_DRV_LIST_UNLOCK(pbustype);
+ __DEV_HD_UNLOCK(pdevinstance);
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __busDelDevice
+** 功能描述: 从总线上删除设备
+** 输 入 : pdevinstance 设备实例指针
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __busDelDevice (PLW_DEV_INSTANCE pdevinstance)
+{
+ PLW_BUS_TYPE pbustype = pdevinstance->DEVHD_pbustype;
+
+ __BUS_DEV_LIST_LOCK(pbustype);
+ _List_Line_Del(&pdevinstance->DEVHD_lineBus, &pbustype->BUS_plineDevList);
+ __BUS_DEV_LIST_UNLOCK(pbustype);
+
+ __devReleaseDrv(pdevinstance);
+}
+/*********************************************************************************************************
+** 函数名称: __busAddDriver
+** 功能描述: 向总线添加驱动
+** 输 入 : pdrvinstance 驱动实例指针
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __busAddDriver (PLW_DRV_INSTANCE pdrvinstance)
+{
+ PLW_DEV_INSTANCE pdevinstance;
+ PLW_LIST_LINE plineNode;
+ PLW_BUS_TYPE pbustype = pdrvinstance->DRVHD_pbustype;
+ INT iRet;
+
+ __DRV_DEV_LIST_LOCK_INIT(pdrvinstance); /* 初始化驱动的设备链表操作锁 */
+ pdrvinstance->DRVHD_plineDevList = LW_NULL; /* 初始化驱动的设备链表 */
+
+ __BUS_DRV_LIST_LOCK(pbustype);
+ _List_Line_Add_Ahead(&pdrvinstance->DRVHD_lineBus,
+ &pbustype->BUS_plineDrvList); /* 将驱动添加到总线驱动链表中 */
+ __BUS_DRV_LIST_UNLOCK(pbustype);
+
+ if (pbustype->BUS_uiFlag & BUS_AUTO_PROBE) { /* 设置了总线自动 probe */
+
+ __BUS_DEV_LIST_LOCK(pbustype);
+ for (plineNode = pbustype->BUS_plineDevList;
+ plineNode != LW_NULL;
+ plineNode = _list_line_get_next(plineNode)) { /* 遍历总线上的设备 */
+
+ pdevinstance = _LIST_ENTRY(plineNode, LW_DEV_INSTANCE, DEVHD_lineBus);
+
+ __DEV_HD_LOCK(pdevinstance);
+ iRet = __drvMatchDev(pdevinstance, pdrvinstance); /* 检查设备和驱动是否匹配 */
+ if (!iRet) {
+ __drvAttach(pdevinstance, pdrvinstance); /* 设备和驱动匹配上则进行关联 */
+ }
+ __DEV_HD_UNLOCK(pdevinstance);
+ }
+ __BUS_DEV_LIST_UNLOCK(pbustype);
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __busDelDriver
+** 功能描述: 从总线上删除驱动
+** 输 入 : pdrvinstance 驱动实例指针
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __busDelDriver (PLW_DRV_INSTANCE pdrvinstance)
+{
+ PLW_BUS_TYPE pbustype = pdrvinstance->DRVHD_pbustype;
+
+ __BUS_DRV_LIST_LOCK(pbustype);
+ _List_Line_Del(&pdrvinstance->DRVHD_lineBus, &pbustype->BUS_plineDrvList);
+ __BUS_DRV_LIST_UNLOCK(pbustype);
+
+ __drvDetach(pdrvinstance);
+}
+/*********************************************************************************************************
+** 函数名称: __devInit
+** 功能描述: 设备初始化
+** 输 入 : pdevinstance 设备实例指针
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __devInit (PLW_DEV_INSTANCE pdevinstance)
+{
+ __DEV_HD_LOCK_INIT(pdevinstance);
+}
+/*********************************************************************************************************
+** 函数名称: __devReleaseDrv
+** 功能描述: 解除设备与驱动的绑定
+** 输 入 : pdevinstance 设备实例指针
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __devReleaseDrv (PLW_DEV_INSTANCE pdevinstance)
+{
+ PLW_DRV_INSTANCE pdrvinstance = pdevinstance->DEVHD_pdrvinstance;
+
+ if (pdrvinstance) {
+ __DEV_HD_LOCK(pdevinstance);
+
+ /*
+ * 调用 remove 接口
+ */
+ if (pdevinstance->DEVHD_pbustype->BUS_pfuncRemove) {
+ pdevinstance->DEVHD_pbustype->BUS_pfuncRemove(pdevinstance);
+
+ } else if (pdrvinstance->DRVHD_pfuncRemove) {
+ pdrvinstance->DRVHD_pfuncRemove(pdevinstance);
+ }
+
+ __DRV_DEV_LIST_LOCK(pdrvinstance);
+ _List_Line_Del(&pdevinstance->DEVHD_lineDrv,
+ &pdrvinstance->DRVHD_plineDevList); /* 从驱动链表中删除设备 */
+ __DRV_DEV_LIST_UNLOCK(pdrvinstance);
+
+ /*
+ * 清空数据
+ */
+ pdevinstance->DEVHD_pdrvinstance = LW_NULL;
+ API_DevSetDrvdata(pdevinstance, LW_NULL);
+
+ __DEV_HD_UNLOCK(pdevinstance);
+ }
+}
+/*********************************************************************************************************
+** 函数名称: __devDel
+** 功能描述: 删除设备
+** 输 入 : pdevinstance 设备实例指针
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __devDel (PLW_DEV_INSTANCE pdevinstance)
+{
+ __busDelDevice(pdevinstance);
+}
+/*********************************************************************************************************
+** 函数名称: __devAdd
+** 功能描述: 添加设备
+** 输 入 : pdevinstance 设备实例指针
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __devAdd (PLW_DEV_INSTANCE pdevinstance)
+{
+ return (__busAddDevice(pdevinstance));
+}
+/*********************************************************************************************************
+** 函数名称: __drvFind
+** 功能描述: 在总线上查找驱动
+** 输 入 : pcName 驱动名字
+** pbustype 总线
+** 输 出 : 成功返回驱动实例指针
+** 失败返回 LW_NULL
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static PLW_DRV_INSTANCE __drvFind (CPCHAR pcName, PLW_BUS_TYPE pbustype)
+{
+ PLW_DRV_INSTANCE pdrvinstance;
+ PLW_LIST_LINE plineNode;
+
+ __BUS_DRV_LIST_LOCK(pbustype);
+ for (plineNode = pbustype->BUS_plineDrvList;
+ plineNode != LW_NULL;
+ plineNode = _list_line_get_next(plineNode),
+ pdrvinstance = LW_NULL) { /* 遍历总线上的驱动链表 */
+
+ pdrvinstance = _LIST_ENTRY(plineNode, LW_DRV_INSTANCE, DRVHD_lineBus);
+ if (!lib_strcmp(pdrvinstance->DRVHD_pcName, pcName)) { /* 通过名字进行比较匹配 */
+ break;
+ }
+ }
+ __BUS_DRV_LIST_UNLOCK(pbustype);
+
+ if (plineNode == LW_NULL) { /* 如果没匹配到 */
+ pdrvinstance = LW_NULL;
+ }
+
+ return (pdrvinstance);
+}
+/*********************************************************************************************************
+** 函数名称: __drvMatchDev
+** 功能描述: 检查驱动和设备是否匹配
+** 输 入 : pdevinstance 设备实例指针
+** pdrvinstance 驱动实例指针
+** 输 出 : 匹配返回 0, 不匹配返回其他
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __drvMatchDev (PLW_DEV_INSTANCE pdevinstance, PLW_DRV_INSTANCE pdrvinstance)
+{
+ INT iRet = 0;
+
+ /*
+ * 检测设备和驱动是否匹配,bus 的匹配函数不存在则默认匹配
+ */
+ if (pdrvinstance->DRVHD_pbustype->BUS_pfuncMatch) {
+ iRet = pdrvinstance->DRVHD_pbustype->BUS_pfuncMatch(pdevinstance, pdrvinstance);
+ }
+
+ return (iRet);
+}
+/*********************************************************************************************************
+** 函数名称: __drvAttach
+** 功能描述: 将设备和驱动绑定
+** 输 入 : pdevinstance 设备实例指针
+** pdrvinstance 驱动实例指针
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __drvAttach (PLW_DEV_INSTANCE pdevinstance, PLW_DRV_INSTANCE pdrvinstance)
+{
+ UINT uiFlag;
+ INT iRet;
+
+ /*
+ * 绑定设备和驱动
+ */
+ __DRV_DEV_LIST_LOCK(pdrvinstance);
+ _List_Line_Add_Ahead(&pdevinstance->DEVHD_lineDrv, &pdrvinstance->DRVHD_plineDevList);
+ __DRV_DEV_LIST_UNLOCK(pdrvinstance);
+ pdevinstance->DEVHD_pdrvinstance = pdrvinstance;
+
+ iRet = API_PinBind(pdevinstance); /* 进行设备引脚的绑定处理 */
+ if (iRet) {
+ goto __error_handle;
+ }
+
+ uiFlag = pdevinstance->DEVHD_pbustype->BUS_uiFlag;
+ if (pdevinstance->DEVHD_pbustype->BUS_pfuncProbe) { /* 总线的 probe 函数存在则调用 */
+ iRet = pdevinstance->DEVHD_pbustype->BUS_pfuncProbe(pdevinstance);
+ } else {
+ uiFlag |= BUS_FORCE_DRV_PROBE;
+ }
+
+ if ((uiFlag & BUS_FORCE_DRV_PROBE) && (pdrvinstance->DRVHD_pfuncProbe)) {
+ iRet = pdrvinstance->DRVHD_pfuncProbe(pdevinstance); /* 驱动 probe 函数存在则调用 */
+ }
+
+ if (iRet) {
+ goto __error_handle;
+ }
+
+ _DebugFormat(__LOGMESSAGE_LEVEL, "Bind driver %s and device %s\r\n",
+ pdrvinstance->DRVHD_pcName, pdevinstance->DEVHD_pcName);
+
+ return (ERROR_NONE);
+
+__error_handle:
+ __DRV_DEV_LIST_LOCK(pdrvinstance);
+ _List_Line_Del(&pdevinstance->DEVHD_lineDrv,
+ &pdrvinstance->DRVHD_plineDevList); /* 处理失败则解除绑定 */
+ __DRV_DEV_LIST_UNLOCK(pdrvinstance);
+ pdevinstance->DEVHD_pdrvinstance = NULL;
+
+ _DebugFormat(__ERRORMESSAGE_LEVEL,"Failed to probe device: %s",
+ pdevinstance->DEVHD_pcName);
+
+ return (PX_ERROR);
+}
+/*********************************************************************************************************
+** 函数名称: __drvDetach
+** 功能描述: 解除驱动上的设备与驱动的绑定
+** 输 入 : pdrvinstance 驱动实例指针
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __drvDetach (PLW_DRV_INSTANCE pdrvinstance)
+{
+ PLW_DEV_INSTANCE pdevinstance;
+ PLW_LIST_LINE plineNode;
+
+ __DRV_DEV_LIST_LOCK(pdrvinstance);
+ for (plineNode = pdrvinstance->DRVHD_plineDevList; /* 遍历驱动上关联的设备 */
+ plineNode != NULL;) {
+
+ pdevinstance = _LIST_ENTRY(plineNode, LW_DEV_INSTANCE, DEVHD_lineBus);
+ plineNode = _list_line_get_next(plineNode);
+
+ __DEV_HD_LOCK(pdevinstance);
+
+ /*
+ * 调用 remove 接口
+ */
+ if (pdevinstance->DEVHD_pbustype->BUS_pfuncRemove) {
+ pdevinstance->DEVHD_pbustype->BUS_pfuncRemove(pdevinstance);
+
+ } else if(pdrvinstance->DRVHD_pfuncRemove) {
+ pdrvinstance->DRVHD_pfuncRemove(pdevinstance);
+ }
+
+ _List_Line_Del(&pdevinstance->DEVHD_lineDrv,
+ &pdrvinstance->DRVHD_plineDevList); /* 从驱动链表中删除设备 */
+
+ /*
+ * 清空数据
+ */
+ pdevinstance->DEVHD_pdrvinstance = LW_NULL;
+ API_DevSetDrvdata(pdevinstance, LW_NULL);
+
+ __DEV_HD_UNLOCK(pdevinstance);
+ }
+ __DRV_DEV_LIST_UNLOCK(pdrvinstance);
+}
+/*********************************************************************************************************
+** 函数名称: API_BusInit
+** 功能描述: 总线初始化
+** 输 入 : pbustype 总线实例指针
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_BusInit (PLW_BUS_TYPE pbustype)
+{
+ if (pbustype == LW_NULL) {
+ return (PX_ERROR);
+ }
+
+ __BUS_HD_LOCK_INIT(pbustype); /* 总线操作锁初始化 */
+ __BUS_DEV_LIST_LOCK_INIT(pbustype); /* 总线上设备链表操作锁初始化 */
+ __BUS_DRV_LIST_LOCK_INIT(pbustype); /* 总线上驱动链表操作锁初始化 */
+ pbustype->BUS_plineDevList = LW_NULL; /* 设备链表初始化 */
+ pbustype->BUS_plineDrvList = LW_NULL; /* 驱动链表初始化 */
+ pbustype->BUS_uiStatus = BUS_INITIALIZED; /* 设置总线状态已初始化 */
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_BusFindDevice
+** 功能描述: 通过设备树节点查找总线上是否已有此设备
+** 输 入 : pbustype 总线指针
+** pdtnDev 设备树节点
+** 输 出 : 成功返回查找到的设备指针, 失败返回 LW_NULL
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_DEV_INSTANCE API_BusFindDevice (PLW_BUS_TYPE pbustype, PLW_DEVTREE_NODE pdtnDev)
+{
+ PLW_DEV_INSTANCE pdevinstance = LW_NULL;
+ PLW_LIST_LINE plineNode;
+
+ __BUS_DEV_LIST_LOCK(pbustype);
+ for (plineNode = pbustype->BUS_plineDevList;
+ plineNode != LW_NULL;
+ plineNode = _list_line_get_next(plineNode)) { /* 遍历总线上的已注册设备 */
+
+ pdevinstance = _LIST_ENTRY(plineNode, LW_DEV_INSTANCE, DEVHD_lineBus);
+ if (pdevinstance->DEVHD_pdtnDev == pdtnDev) { /* 设备的设备树节点相同则匹配 */
+ break;
+ }
+ pdevinstance = LW_NULL;
+ }
+ __BUS_DEV_LIST_UNLOCK(pbustype);
+
+ return (pdevinstance);
+}
+/*********************************************************************************************************
+** 函数名称: API_DriverRegister
+** 功能描述: 驱动注册
+** 输 入 : pdrvinstance 驱动指针
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DriverRegister (PLW_DRV_INSTANCE pdrvinstance)
+{
+ PLW_DRV_INSTANCE pdrvinstanceOther;
+ PLW_BUS_TYPE pbustype;
+ INT iRet;
+
+ if (pdrvinstance == LW_NULL) {
+ return (PX_ERROR);
+ }
+
+ pbustype = pdrvinstance->DRVHD_pbustype;
+ if (pbustype == LW_NULL) {
+ return (PX_ERROR);
+ }
+
+ if (!(pbustype->BUS_uiStatus & BUS_INITIALIZED)) { /* 总线尚未初始化返回错误 */
+ _DebugFormat(__ERRORMESSAGE_LEVEL, "Bus %s was not initialized.\n",
+ pbustype->BUS_pcName);
+ return (PX_ERROR);
+ }
+
+ if (!pdrvinstance->DRVHD_pcName) { /* 驱动名字未初始化返回失败 */
+ _DebugFormat(__ERRORMESSAGE_LEVEL, "Driver name is NULL");
+ return (PX_ERROR);
+ }
+
+ pdrvinstanceOther = __drvFind(pdrvinstance->DRVHD_pcName,
+ pdrvinstance->DRVHD_pbustype); /* 查找驱动是否已注册 */
+ if (pdrvinstanceOther) {
+ _DebugFormat(__ERRORMESSAGE_LEVEL, "Driver %s is already registered",
+ pdrvinstance->DRVHD_pcName);
+ return (PX_ERROR);
+ }
+
+ iRet = __busAddDriver(pdrvinstance); /* 尚未注册,则在总线上注册 */
+
+ return (iRet);
+}
+/*********************************************************************************************************
+** 函数名称: API_DriverUnregister
+** 功能描述: 卸载驱动
+** 输 入 : pdrvinstance 驱动指针
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+VOID API_DriverUnregister (PLW_DRV_INSTANCE pdrvinstance)
+{
+ if ((pdrvinstance == LW_NULL) || (pdrvinstance->DRVHD_pbustype == LW_NULL)) {
+ return;
+ }
+
+ __busDelDriver(pdrvinstance);
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceRegister
+** 功能描述: 注册设备
+** 输 入 : pdevinstance 设备实例指针
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_DeviceRegister (PLW_DEV_INSTANCE pdevinstance)
+{
+ UINT uiStatus;
+
+ if ((pdevinstance == LW_NULL) ||
+ (pdevinstance->DEVHD_pbustype == LW_NULL)) {
+ return (PX_ERROR);
+ }
+
+ uiStatus = pdevinstance->DEVHD_pbustype->BUS_uiStatus;
+ if (!(uiStatus & BUS_INITIALIZED)) { /* 总线尚未初始化返回失败 */
+ _DebugFormat(__ERRORMESSAGE_LEVEL, "Bus %s was not initialized.\n",
+ pdevinstance->DEVHD_pbustype->BUS_pcName);
+ return (PX_ERROR);
+ }
+
+ __devInit(pdevinstance);
+
+ return (__devAdd(pdevinstance));
+}
+/*********************************************************************************************************
+** 函数名称: API_DeviceUnregister
+** 功能描述: 卸载设备
+** 输 入 : pdevinstance 设备实例指针
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+VOID API_DeviceUnregister (PLW_DEV_INSTANCE pdevinstance)
+{
+ if ((pdevinstance == LW_NULL) ||
+ (pdevinstance->DEVHD_pbustype == LW_NULL)) {
+ return;
+ }
+
+ __devDel(pdevinstance);
+}
+/*********************************************************************************************************
+** 函数名称: API_DevSetDrvdata
+** 功能描述: 设置设备私有数据
+** 输 入 : pdevinstance 设备实例指针
+** pvData 设备私有数据指针
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+VOID API_DevSetDrvdata (PLW_DEV_INSTANCE pdevinstance, PVOID pvData)
+{
+ pdevinstance->DEVHD_pvPrivData = pvData;
+}
+
+#endif /* (LW_CFG_DEVICE_EN > 0) && */
+ /* (LW_CFG_DEVTREE_EN > 0) */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/system/device/base/baseDrvLib.h b/SylixOS/system/device/base/baseDrvLib.h
new file mode 100644
index 0000000..dc59cb2
--- /dev/null
+++ b/SylixOS/system/device/base/baseDrvLib.h
@@ -0,0 +1,148 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: baseDrvLib.h
+**
+** 创 建 人: Zhang.Jian (张健)
+**
+** 文件创建日期: 2019 年 10 月 28 日
+**
+** 描 述: 基础驱动框架库头文件
+*********************************************************************************************************/
+
+#ifndef __BASEDRVLIB_H
+#define __BASEDRVLIB_H
+
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if (LW_CFG_DEVICE_EN > 0) && (LW_CFG_DEVTREE_EN > 0)
+
+/*********************************************************************************************************
+ 类型提前声明
+*********************************************************************************************************/
+
+struct lw_bus_type;
+struct lw_dev_instance;
+struct lw_drv_instance;
+struct lw_device_pin_info;
+
+/*********************************************************************************************************
+ 设备实体结构体
+*********************************************************************************************************/
+
+typedef struct lw_dev_instance {
+ CPCHAR DEVHD_pcName; /* 设备名称 */
+ UINT32 DEVHD_uiId; /* 设备 ID */
+ struct lw_bus_type *DEVHD_pbustype; /* 设备挂载的总线 */
+ struct lw_drv_instance *DEVHD_pdrvinstance; /* 设备的驱动 */
+ struct lw_dev_instance *DEVHD_pdevinstanceParent; /* 设备的父设备 */
+ PLW_DEVTREE_NODE DEVHD_pdtnDev; /* 设备的设备树节点 */
+ PVOID DEVHD_pvPrivData; /* 设备的私有数据 */
+ struct lw_device_pin_info *DEVHD_pdevpininfo; /* 设备使用的引脚 */
+
+ LW_OBJECT_HANDLE DEVHD_hDevLock; /* 设备的操作锁 */
+ LW_LIST_LINE DEVHD_lineDrv; /* 设备在驱动链表的节点 */
+ LW_LIST_LINE DEVHD_lineBus; /* 设备在总线链表的节点 */
+
+ /*
+ * 以下为设备子项,暂未使用
+ */
+ LW_LIST_LINE DEVHD_lineParent;
+ LW_LIST_LINE_HEADER DEVHD_plineChildrenList;
+ LW_OBJECT_HANDLE DEVHD_hChildrenListLock;
+} LW_DEV_INSTANCE;
+typedef LW_DEV_INSTANCE *PLW_DEV_INSTANCE;
+
+/*********************************************************************************************************
+ 驱动实体结构体
+*********************************************************************************************************/
+
+typedef struct lw_drv_instance {
+ CPCHAR DRVHD_pcName; /* 驱动名称 */
+ struct lw_bus_type *DRVHD_pbustype; /* 驱动使用的总线 */
+ PLW_DEVTREE_TABLE DRVHD_pMatchTable; /* 驱动匹配表 */
+
+ LW_LIST_LINE DRVHD_lineBus; /* 驱动所在总线链表的节点 */
+ LW_LIST_LINE_HEADER DRVHD_plineDevList; /* 匹配的设备链表头 */
+ LW_OBJECT_HANDLE DRVHD_hDevListLock; /* 匹配的设备链表操作锁 */
+
+ PVOID DRVHD_pvPriData; /* 驱动的私有数据 */
+
+ /*
+ * 以下为驱动操作函数
+ */
+ INT (*DRVHD_pfuncProbe )(PLW_DEV_INSTANCE pDev);
+ INT (*DRVHD_pfuncRemove )(PLW_DEV_INSTANCE pDev);
+ VOID (*DRVHD_pfuncShutdown)(PLW_DEV_INSTANCE pDev);
+ INT (*DRVHD_pfuncSuspend )(PLW_DEV_INSTANCE pDev);
+ INT (*DRVHD_pfuncResume )(PLW_DEV_INSTANCE pDev);
+} LW_DRV_INSTANCE;
+typedef LW_DRV_INSTANCE *PLW_DRV_INSTANCE;
+
+/*********************************************************************************************************
+ 总线实体结构体
+*********************************************************************************************************/
+
+typedef struct lw_bus_type {
+ CPCHAR BUS_pcName; /* 总线名称 */
+ CPCHAR BUS_pcDevName; /* 总线上设备名模板 */
+
+ UINT BUS_uiStatus; /* 总线状态 */
+ UINT BUS_uiFlag; /* 总线标志 */
+#define BUS_INITIALIZED 0x01
+#define BUS_AUTO_PROBE 0x02
+#define BUS_FORCE_DRV_PROBE 0x03
+
+ LW_OBJECT_HANDLE BUS_hBusLock; /* 总线操作锁 */
+ LW_LIST_LINE_HEADER BUS_plineDevList; /* 总线上设备链表头 */
+ LW_LIST_LINE_HEADER BUS_plineDrvList; /* 总线上驱动链表头 */
+ LW_OBJECT_HANDLE BUS_hDevListLock; /* 设备链表操作锁 */
+ LW_OBJECT_HANDLE BUS_hDrvListLock; /* 驱动链表操作锁 */
+
+ /*
+ * 以下为总线操作函数
+ */
+ INT (*BUS_pfuncMatch )(PLW_DEV_INSTANCE pDev, PLW_DRV_INSTANCE pDrv);
+ INT (*BUS_pfuncProbe )(PLW_DEV_INSTANCE pDev);
+ INT (*BUS_pfuncRemove )(PLW_DEV_INSTANCE pDev);
+ VOID (*BUS_pfuncShutdown)(PLW_DEV_INSTANCE pDev);
+ INT (*BUS_pfuncSuspend )(PLW_DEV_INSTANCE pDev);
+ INT (*BUS_pfuncResume )(PLW_DEV_INSTANCE pDev);
+} LW_BUS_TYPE;
+typedef LW_BUS_TYPE *PLW_BUS_TYPE;
+
+/*********************************************************************************************************
+ API
+*********************************************************************************************************/
+
+LW_API INT API_BusInit(PLW_BUS_TYPE pBus);
+
+LW_API PLW_DEV_INSTANCE API_BusFindDevice(PLW_BUS_TYPE pvBus,
+ PLW_DEVTREE_NODE pdtNode);
+
+LW_API INT API_DeviceRegister(PLW_DEV_INSTANCE pDev);
+
+LW_API VOID API_DeviceUnregister(PLW_DEV_INSTANCE pDev);
+
+LW_API INT API_DriverRegister(PLW_DRV_INSTANCE pDrv);
+
+LW_API VOID API_DriverUnregister(PLW_DRV_INSTANCE pDrv);
+
+LW_API VOID API_DevSetDrvdata(PLW_DEV_INSTANCE pDev, PVOID pvData);
+
+#endif /* (LW_CFG_DEVICE_EN > 0) && */
+ /* (LW_CFG_DEVTREE_EN > 0) */
+#endif /* __BASEDRVLIB_H */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/system/device/clock/clock.c b/SylixOS/system/device/clock/clock.c
new file mode 100644
index 0000000..6c248ae
--- /dev/null
+++ b/SylixOS/system/device/clock/clock.c
@@ -0,0 +1,808 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: clock.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 08 月 26 日
+**
+** 描 述: 物理时钟控制逻辑
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if (LW_CFG_DEVICE_EN > 0) && (LW_CFG_DEVTREE_EN > 0)
+#include "clock.h"
+/*********************************************************************************************************
+ 全局变量定义
+*********************************************************************************************************/
+static LW_LIST_LINE_HEADER _G_plineClockRoot; /* 有效时钟的树 */
+static LW_LIST_LINE_HEADER _G_plineClockOrphan; /* 孤立时钟的树 */
+static LW_LIST_LINE_HEADER _G_plineClockProviders;
+
+static LW_OBJECT_HANDLE _G_hClkProviderLock = LW_OBJECT_HANDLE_INVALID;
+static LW_OBJECT_HANDLE _G_hClkListLock = LW_OBJECT_HANDLE_INVALID;
+
+#define __CLOCK_PROVIDER_LOCK() API_SemaphoreMPend(_G_hClkProviderLock, LW_OPTION_WAIT_INFINITE)
+#define __CLOCK_PROVIDER_UNLOCK() API_SemaphoreMPost(_G_hClkProviderLock)
+#define __CLOCK_LIST_LOCK() API_SemaphoreMPend(_G_hClkListLock, LW_OPTION_WAIT_INFINITE)
+#define __CLOCK_LIST_UNLOCK() API_SemaphoreMPost(_G_hClkListLock)
+/*********************************************************************************************************
+** 函数名称: __clockSubtreeFind
+** 功能描述: 查找一个时钟子树中的时钟
+** 输 入 : pcName 时钟的名称
+** pclk 需要初始化的时钟
+** 输 出 : 查找到的时钟
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static PLW_CLOCK __clockSubtreeFind (CPCHAR pcName, PLW_CLOCK pclk)
+{
+ PLW_LIST_LINE plineTemp;
+ PLW_CLOCK pclkchild;
+ PLW_CLOCK pclkRet;
+
+ if (!lib_strcmp(pclk->CLK_pcName, pcName)) { /* 当前时钟为匹配时钟 */
+ return (pclk);
+ }
+
+ for (plineTemp = pclk->CLK_plineclkchild;
+ plineTemp != LW_NULL;
+ plineTemp = _list_line_get_next(plineTemp)) { /* 遍历该时钟的孩子时钟 */
+
+ pclkchild = _LIST_ENTRY(plineTemp, LW_CLOCK, CLK_lineManage);
+ pclkRet = __clockSubtreeFind(pcName, pclkchild);
+ if (pclkRet) {
+ return (pclkRet);
+ }
+ }
+
+ return (LW_NULL);
+}
+/*********************************************************************************************************
+** 函数名称: __clockHwTreeFind
+** 功能描述: 在时钟树中查找一个时钟
+** 输 入 : pcName 时钟的名称
+** 输 出 : 查找到的时钟
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static PLW_CLOCK __clockTreeFind (CPCHAR pcName)
+{
+ PLW_LIST_LINE plineTemp;
+ PLW_CLOCK pclk;
+ PLW_CLOCK pclkRet;
+
+ __CLOCK_LIST_LOCK();
+ for (plineTemp = _G_plineClockRoot;
+ plineTemp != LW_NULL;
+ plineTemp = _list_line_get_next(plineTemp)) { /* 在有效时钟树中查找 */
+
+ pclk = _LIST_ENTRY(plineTemp, LW_CLOCK, CLK_lineManage);
+ pclkRet = __clockSubtreeFind(pcName, pclk);
+ if (pclkRet) {
+ __CLOCK_LIST_UNLOCK();
+ return (pclkRet);
+ }
+ }
+
+ for (plineTemp = _G_plineClockOrphan;
+ plineTemp != LW_NULL;
+ plineTemp = _list_line_get_next(plineTemp)) { /* 在孤立时钟树中查找 */
+
+ pclk = _LIST_ENTRY(plineTemp, LW_CLOCK, CLK_lineManage);
+ pclkRet = __clockSubtreeFind(pcName, pclk);
+ if (pclkRet) {
+ __CLOCK_LIST_UNLOCK();
+ return (pclkRet);
+ }
+ }
+ __CLOCK_LIST_UNLOCK();
+
+ return (LW_NULL);
+}
+/*********************************************************************************************************
+** 函数名称: __clockParentGetByIndex
+** 功能描述: 通过序号获取一个时钟的父时钟
+** 输 入 : pclk 时钟指针
+** ucIndex 父时钟序号
+** 输 出 : 获得的父时钟
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static PLW_CLOCK __clockParentGetByIndex (PLW_CLOCK pclk, UINT8 ucIndex)
+{
+ if (ucIndex >= pclk->CLK_uiNumParents) { /* 父时钟序号无效 */
+ return (LW_NULL);
+ }
+
+ if (!pclk->CLK_clkparents[ucIndex]) { /* 对应的父时钟位置当前为空 */
+ pclk->CLK_clkparents[ucIndex] = __clockTreeFind(pclk->CLK_ppcParentNames[ucIndex]);
+ }
+
+ return (pclk->CLK_clkparents[ucIndex]);
+}
+/*********************************************************************************************************
+** 函数名称: __clockParentGet
+** 功能描述: 获得一个时钟的父时钟
+** 输 入 : pclk 时钟指针
+** 输 出 : 获得的父时钟
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static PLW_CLOCK __clockParentGet (PLW_CLOCK pclk)
+{
+ UINT8 ucIndex = 0;
+
+ if ((pclk->CLK_uiNumParents > 1) && /* 当存在多个父时钟时 */
+ pclk->CLK_clkops->clockParentGet) {
+ ucIndex = pclk->CLK_clkops->clockParentGet(pclk); /* 获得父时钟对应的序号 */
+ }
+
+ return (__clockParentGetByIndex(pclk, ucIndex));
+}
+/*********************************************************************************************************
+** 函数名称: __clockParentIndexFetch
+** 功能描述: 获得一个时钟父时钟的序号
+** 输 入 : pclk 时钟指针
+** pclkParent 父时钟指针
+** 输 出 : 父时钟的序号
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __clockParentIndexFetch (PLW_CLOCK pclk, PLW_CLOCK pclkParent)
+{
+ INT i;
+
+ if (!pclkParent) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ for (i = 0; i < pclk->CLK_uiNumParents; i++) {
+ if (__clockParentGetByIndex(pclk, i) == pclkParent) {
+ return (i);
+ }
+ }
+
+ _ErrorHandle(EINVAL);
+
+ return (PX_ERROR);
+}
+/*********************************************************************************************************
+** 函数名称: __clockParentUpdate
+** 功能描述: 更新一个时钟的父时钟
+** 输 入 : pclk 需要更新的时钟
+** pclknewparent 新的父时钟;为空时,该时钟被设置为孤立时钟
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __clockParentUpdate (PLW_CLOCK pclk, PLW_CLOCK pclknewparent)
+{
+ if (pclk->CLK_clkparent) {
+ _List_Line_Del(&pclk->CLK_lineManage,
+ &pclk->CLK_clkparent->CLK_plineclkchild); /* 从原父时钟链表中删除 */
+ } else {
+ _List_Line_Del(&pclk->CLK_lineManage,
+ &_G_plineClockOrphan);
+ }
+
+ if (pclknewparent) { /* 如果存在需更新的父时钟 */
+ _List_Line_Add_Ahead(&pclk->CLK_lineManage,
+ &pclknewparent->CLK_plineclkchild);
+ } else {
+ _List_Line_Add_Ahead(&pclk->CLK_lineManage,
+ &_G_plineClockOrphan);
+ }
+
+ pclk->CLK_clkparent = pclknewparent;
+}
+/*********************************************************************************************************
+** 函数名称: __clockParentSet
+** 功能描述: 设置一个时钟的父时钟
+** 输 入 : pclk 时钟指针
+** pclkParent 父时钟指针
+** ucParentIndex 父时钟序号
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __clockParentSet (PLW_CLOCK pclk, PLW_CLOCK pclkParent, UINT8 ucParentIndex)
+{
+ __clockParentUpdate(pclk, pclkParent);
+
+ if (pclkParent && pclk->CLK_clkops->clockParentSet) {
+ pclk->CLK_clkops->clockParentSet(pclk, ucParentIndex);
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __clockRateRecalc
+** 功能描述: 设置一个时钟的频率
+** 输 入 : pclk 需要初始化的时钟
+** bRecalcChild 是否设置子时钟
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __clockRateRecalc (PLW_CLOCK pclk, BOOL bRecalcChild)
+{
+ PLW_CLOCK_OPS pclkfuncs;
+ PLW_LIST_LINE plineTemp;
+ PLW_CLOCK pclkchild;
+ ULONG ulParentRate;
+
+ pclkfuncs = pclk->CLK_clkops;
+
+ if (pclk->CLK_clkparent) { /* 记录父时钟频率 */
+ ulParentRate = pclk->CLK_clkparent->CLK_ulRate;
+ } else {
+ ulParentRate = 0;
+ }
+
+ if (pclkfuncs->clockRateRecalc) { /* 根据父时钟频率计算频率 */
+ pclk->CLK_ulRate = pclkfuncs->clockRateRecalc(pclk, ulParentRate);
+ } else { /* 否则频率为父时钟频率 */
+ pclk->CLK_ulRate = ulParentRate;
+ }
+
+ if (bRecalcChild) { /* 对所有子时钟重新计算频率 */
+ for (plineTemp = pclk->CLK_plineclkchild;
+ plineTemp != LW_NULL;
+ plineTemp = _list_line_get_next(plineTemp)) {
+
+ pclkchild = _LIST_ENTRY(plineTemp, LW_CLOCK, CLK_lineManage);
+ __clockRateRecalc(pclkchild, LW_TRUE);
+ }
+ }
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockParentSet
+** 功能描述: 设置一个时钟的父时钟
+** 输 入 : pclk 时钟指针
+** pclkParent 父时钟指针
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_ClockParentSet (PLW_CLOCK pclk, PLW_CLOCK pclkParent)
+{
+ INT iParentIndex;
+ INT iRet;
+
+ if (!pclk) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ if (pclk->CLK_clkparent == pclkParent) { /* 当前父节点已经为预设值 */
+ return (ERROR_NONE);
+ }
+
+ if ((pclk->CLK_uiNumParents > 1) &&
+ !pclk->CLK_clkops->clockParentSet) { /* 未定义父时钟设置的接口 */
+ _ErrorHandle(EPERM);
+ return (PX_ERROR);
+ }
+
+ if (pclkParent) { /* 查找父时钟的序号 */
+ iParentIndex = __clockParentIndexFetch(pclk, pclkParent);
+ if (iParentIndex < 0) {
+ return (iParentIndex);
+ }
+ }
+
+ iRet = __clockParentSet(pclk, pclkParent, iParentIndex); /* 设置父时钟 */
+
+ return (iRet);
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockRateSet
+** 功能描述: 设置一个时钟的频率
+** 输 入 : pclk 时钟
+** ulReqRate 预设时钟频率值
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_ClockRateSet (PLW_CLOCK pclk, ULONG ulReqRate)
+{
+ ULONG ulRate;
+
+ if (!pclk) {
+ return (PX_ERROR);
+ }
+
+ if (pclk->CLK_clkops->clockRateRound) { /* 获得最接近的时钟 */
+ ulRate = pclk->CLK_clkops->clockRateRound(pclk,
+ ulReqRate,
+ &pclk->CLK_clkparent->CLK_ulRate);
+ } else {
+ ulRate = ulReqRate;
+ }
+
+ if (ulRate < 0) {
+ return (ulRate);
+ }
+
+ if (ulRate == API_ClockRateGet(pclk)) { /* 如果和当前时钟相等,返回 */
+ return (ERROR_NONE);
+ }
+
+ pclk->CLK_clkops->clockRateSet(pclk, ulRate, pclk->CLK_clkparent->CLK_ulRate);
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockRateGet
+** 功能描述: 获得一个时钟的当前频率
+** 输 入 : pclk 时钟
+** 输 出 : 时钟频率
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+ULONG API_ClockRateGet (PLW_CLOCK pclk)
+{
+ ULONG ulRate;
+
+ if (!pclk) { /* 参数无效 */
+ return (0);
+ }
+
+ __clockRateRecalc(pclk, LW_FALSE); /* 重新计算一下当前时钟频率 */
+
+ ulRate = pclk->CLK_ulRate; /* 获得当前时钟频率 */
+
+ if (!pclk->CLK_uiNumParents) { /* 如果为时钟源 */
+ return (ulRate);
+
+ } else if (!pclk->CLK_clkparent) { /* 有父时钟,但父时钟还未有效 */
+ return (0);
+ }
+
+ return (ulRate);
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockRateRound
+** 功能描述: 获得一个时钟的最接近时钟
+** 输 入 : pclk 需要求最接近时钟的时钟
+** ulRate 需要求最接近时钟的频率
+** 输 出 : 最接近的时钟,如果没有求最接近时钟接口,则返回父时钟
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+LONG API_ClockRateRound (PLW_CLOCK pclk, ULONG ulRate)
+{
+ ULONG ulParentRate;
+
+ if (!pclk) {
+ return (0);
+ }
+
+ if (pclk->CLK_clkparent) {
+ ulParentRate = pclk->CLK_clkparent->CLK_ulRate;
+ } else {
+ ulParentRate = 0;
+ }
+
+ if (pclk->CLK_clkops->clockRateRound) {
+ ulRate = pclk->CLK_clkops->clockRateRound(pclk,
+ ulRate,
+ &ulParentRate);
+ if (ulRate < 0) {
+ return (ulRate);
+ }
+
+ } else {
+ return (pclk->CLK_ulRate);
+ }
+
+ return (ulRate);
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockSimpleGet
+** 功能描述: 获取时钟
+** 输 入 : pdtpaClkSpec 设备树参数
+** pvData 私有参数
+** 输 出 : 获取时钟
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_CLOCK API_ClockSimpleGet (PLW_DEVTREE_PHANDLE_ARGS pdtpaClkSpec, PVOID pvData)
+{
+ return (pvData);
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockProviderAdd
+** 功能描述: 添加一个时钟提供者
+** 输 入 : pdtnDev 设备树节点
+** pfuncClkGet 获得时钟的函数
+** pvData 私有参数
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_ClockProviderAdd (PLW_DEVTREE_NODE pdtnDev,
+ PLW_CLOCK (*pfuncClkGet)(PLW_DEVTREE_PHANDLE_ARGS pdtpaClkSpec,
+ PVOID pvData),
+ PVOID pvData)
+{
+ PLW_CLOCK_PROVIDER pclkprovider;
+
+ pclkprovider = __SHEAP_ALLOC(sizeof(LW_CLOCK_PROVIDER));
+ if (!pclkprovider) {
+ _ErrorHandle(ENOMEM);
+ return (PX_ERROR);
+ }
+
+ pclkprovider->CLKP_pdtndev = pdtnDev;
+ pclkprovider->CLKP_clkGet = pfuncClkGet;
+ pclkprovider->CLKP_pvData = pvData;
+
+ __CLOCK_PROVIDER_LOCK();
+ _List_Line_Add_Ahead(&pclkprovider->CLKP_lineManage,
+ &_G_plineClockProviders);
+ __CLOCK_PROVIDER_UNLOCK();
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockGetFromProvider
+** 功能描述: 通过设备树参数获取一个时钟
+** 输 入 : pdtpaClkSpec 设备树参数
+** 输 出 : 获得的时钟
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_CLOCK API_ClockGetFromProvider (PLW_DEVTREE_PHANDLE_ARGS pdtpaClkSpec)
+{
+ PLW_CLOCK_PROVIDER pclkprovider;
+ PLW_CLOCK pclk = LW_NULL;
+ PLW_LIST_LINE plineTemp;
+
+ if (!pdtpaClkSpec) {
+ _ErrorHandle(EINVAL);
+ return (LW_NULL);
+ }
+
+ if (_G_hClkProviderLock == LW_OBJECT_HANDLE_INVALID) {
+ _G_hClkProviderLock = API_SemaphoreMCreate("provider_lock", LW_PRIO_DEF_CEILING,
+ LW_OPTION_WAIT_PRIORITY |
+ LW_OPTION_INHERIT_PRIORITY |
+ LW_OPTION_DELETE_SAFE |
+ LW_OPTION_OBJECT_GLOBAL, LW_NULL);
+ }
+
+ __CLOCK_PROVIDER_LOCK();
+ for (plineTemp = _G_plineClockProviders;
+ plineTemp != LW_NULL;
+ plineTemp = _list_line_get_next(plineTemp)) { /* 查找在时钟树中的时钟 */
+
+ pclkprovider = _LIST_ENTRY(plineTemp, LW_CLOCK_PROVIDER, CLKP_lineManage);
+ if (pclkprovider->CLKP_pdtndev == pdtpaClkSpec->DTPH_pdtnDev) { /* 找到对应的时钟提供者 */
+ pclk = pclkprovider->CLKP_clkGet(pdtpaClkSpec,
+ pclkprovider->CLKP_pvData);
+ if (!pclk) {
+ _ErrorHandle(ENOENT);
+ break;
+ }
+ }
+ }
+ __CLOCK_PROVIDER_UNLOCK();
+
+ return (pclk);
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockFind
+** 功能描述: 查找时钟
+** 输 入 : pcName 查找的时钟名称
+** 输 出 : 查找到的时钟指针
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_CLOCK API_ClockFind (CPCHAR pcName)
+{
+ if (!pcName) {
+ return (LW_NULL);
+ }
+
+ return (__clockTreeFind(pcName));
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockEnable
+** 功能描述: 时钟使能
+** 输 入 : pclk 时钟指针
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_ClockEnable (PLW_CLOCK pclk)
+{
+ INT iRet;
+
+ if (!pclk){
+ return (PX_ERROR);
+ }
+
+ if (pclk->CLK_ulFlags & LW_CLOCK_IS_ROOT) { /* 根时钟类型认为使能 */
+ return (ERROR_NONE);
+ }
+
+ if (pclk->CLK_uiEnableCount == 0) { /* 如果未使能 */
+ iRet = API_ClockEnable(pclk->CLK_clkparent); /* 使能其父时钟 */
+ if (iRet) {
+ return (PX_ERROR);
+ }
+
+ if (pclk->CLK_clkops->clockEnable) { /* 调用该接口的使能操作 */
+ iRet = pclk->CLK_clkops->clockEnable(pclk);
+ if (iRet) {
+ API_ClockDisable(pclk->CLK_clkparent); /* 使能失败需要禁能父时钟 */
+ return (PX_ERROR);
+ }
+ }
+ }
+
+ pclk->CLK_uiEnableCount++; /* 增加使能计数 */
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockDisable
+** 功能描述: 时钟禁能
+** 输 入 : pclk 时钟指针
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+VOID API_ClockDisable (PLW_CLOCK pclk)
+{
+ if (!pclk) {
+ return;
+ }
+
+ if (pclk->CLK_uiEnableCount == 0) {
+ return;
+ }
+
+ if (pclk->CLK_uiEnableCount > 0) {
+ pclk->CLK_uiEnableCount--;
+ return;
+ }
+
+ if (pclk->CLK_clkops->clockDisable) {
+ pclk->CLK_clkops->clockDisable(pclk);
+ }
+
+ API_ClockDisable(pclk->CLK_clkparent);
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockInitDataSet
+** 功能描述: 填充时钟初始化参数
+** 输 入 : pclk 时钟指针
+** pcName 时钟名称
+** pclkops 时钟操作函数
+** ulFlags 初始化标识
+** ppcParentName 父时钟名称
+** uiParentNum 父时钟数量
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_ClockInitDataSet (PLW_CLOCK pclk,
+ CPCHAR pcName,
+ PLW_CLOCK_OPS pclkops,
+ ULONG ulFlags,
+ CHAR **ppcParentName,
+ UINT uiParentNum)
+{
+ INT i;
+
+ if (!pclk || !pclkops) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ if (pclkops->clockRateSet &&
+ !(pclkops->clockRateRound && pclkops->clockRateRecalc)) {
+ _DebugHandle(__ERRORMESSAGE_LEVEL, "must implement .clockRateRound() "
+ "in addition to .clockRateRecalc()\r\n");
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ if (pclkops->clockParentSet && !pclkops->clockParentGet) {
+ _DebugHandle(__ERRORMESSAGE_LEVEL, "must implement .clockParentGet() & "
+ ".clockParentSet()\r\n");
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ if ((uiParentNum > 1) && !pclkops->clockParentGet) {
+ _DebugHandle(__ERRORMESSAGE_LEVEL, "must implement .clockParentGet() as "
+ "it has multi parents\r\n");
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ pclk->CLK_clkops = pclkops;
+ pclk->CLK_ulFlags = ulFlags;
+ pclk->CLK_uiNumParents = uiParentNum;
+ pclk->CLK_pcName = lib_strdup(pcName);
+ if (!pclk->CLK_pcName) {
+ _ErrorHandle(ENOMEM);
+ goto __error_handle0;
+ }
+
+ pclk->CLK_ppcParentNames = __SHEAP_ZALLOC(sizeof(PCHAR) * uiParentNum);
+ if (!pclk->CLK_ppcParentNames) {
+ _ErrorHandle(ENOMEM);
+ goto __error_handle1;
+ }
+
+ for (i = 0; i < uiParentNum; i++) { /* 记录每一个父时钟的名称 */
+ if (!ppcParentName[i]) {
+ _DebugHandle(__ERRORMESSAGE_LEVEL, "invalid NULL in parent_names\r\n");
+ _ErrorHandle(EINVAL);
+ goto __error_handle2;
+ }
+
+ pclk->CLK_ppcParentNames[i] = lib_strdup(ppcParentName[i]);
+ if (!pclk->CLK_ppcParentNames[i]) {
+ _ErrorHandle(ENOMEM);
+ goto __error_handle2;
+ }
+ }
+
+ pclk->CLK_clkparents = __SHEAP_ZALLOC(sizeof(PLW_CLOCK) * uiParentNum);
+ if (!pclk->CLK_clkparents) {
+ _ErrorHandle(ENOMEM);
+ goto __error_handle3;
+ }
+
+ return (ERROR_NONE);
+
+__error_handle3:
+ while (--i >= 0) {
+ lib_free(pclk->CLK_ppcParentNames[i]);
+ }
+
+__error_handle2:
+ __SHEAP_FREE(pclk->CLK_ppcParentNames);
+
+__error_handle1:
+ __SHEAP_FREE(pclk->CLK_pcName);
+
+__error_handle0:
+ return (PX_ERROR);
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockRegister
+** 功能描述: 注册一个时钟管理结构
+** 输 入 : pclk 时钟指针
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_ClockRegister (PLW_CLOCK pclk)
+{
+ PLW_LIST_LINE plineTemp;
+ PLW_CLOCK pclkorphan;
+ PLW_CLOCK pclkparent;
+
+ if (!pclk) { /* 参数判断 */
+ return (PX_ERROR);
+ }
+
+ if (__clockTreeFind(pclk->CLK_pcName)) { /* 时钟树中不应已有该时钟 */
+ _ErrorHandle(EEXIST);
+ return (PX_ERROR);
+ }
+
+ pclk->CLK_clkparent = __clockParentGet(pclk); /* 获取当前指向的父时钟 */
+
+ __CLOCK_LIST_LOCK();
+ if (pclk->CLK_clkparent) { /* 如果有父时钟 */
+ _List_Line_Add_Ahead(&pclk->CLK_lineManage, /* 将该时钟加入父时钟的子链表 */
+ &pclk->CLK_clkparent->CLK_plineclkchild);
+ } else if (!pclk->CLK_uiNumParents) { /* 如果没有父时钟 */
+ _List_Line_Add_Ahead(&pclk->CLK_lineManage, /* 将该时钟加入有效时钟树 */
+ &_G_plineClockRoot);
+ } else { /* 未找到父时钟,但应有父时钟 */
+ _List_Line_Add_Ahead(&pclk->CLK_lineManage, /* 将该时钟加入孤立时钟树 */
+ &_G_plineClockOrphan);
+ }
+ __CLOCK_LIST_UNLOCK();
+
+ if (pclk->CLK_clkops->clockInit) { /* 执行时钟的初始化操作 */
+ pclk->CLK_clkops->clockInit(pclk);
+ }
+
+ for (plineTemp = _G_plineClockOrphan;
+ plineTemp != LW_NULL; /* 检查孤立树中是否有可移除的 */
+ plineTemp = _list_line_get_next(plineTemp)) { /* 更新时钟拓扑中的结构 */
+
+ pclkorphan = _LIST_ENTRY(plineTemp, LW_CLOCK, CLK_lineManage);
+ pclkparent = __clockParentGet(pclkorphan);
+ if (pclkparent) { /* 如果此时可找到父时钟了 */
+ __clockParentUpdate(pclkorphan, pclkparent); /* 父时钟更新 */
+ }
+ }
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockCoreInit
+** 功能描述: 系统时钟核心初始化
+** 输 入 : NONE
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+INT API_ClockCoreInit (VOID)
+{
+ if (_G_hClkListLock == LW_OBJECT_HANDLE_INVALID) {
+ _G_hClkListLock = API_SemaphoreMCreate("clk_list_lock", LW_PRIO_DEF_CEILING,
+ LW_OPTION_WAIT_PRIORITY |
+ LW_OPTION_INHERIT_PRIORITY |
+ LW_OPTION_DELETE_SAFE |
+ LW_OPTION_OBJECT_GLOBAL, LW_NULL);
+ }
+
+ if (_G_hClkProviderLock == LW_OBJECT_HANDLE_INVALID) {
+ _G_hClkProviderLock = API_SemaphoreMCreate("clk_provider_lock", LW_PRIO_DEF_CEILING,
+ LW_OPTION_WAIT_PRIORITY |
+ LW_OPTION_INHERIT_PRIORITY |
+ LW_OPTION_DELETE_SAFE |
+ LW_OPTION_OBJECT_GLOBAL, LW_NULL);
+ }
+
+ return (ERROR_NONE);
+}
+
+#endif /* (LW_CFG_DEVICE_EN > 0) && */
+ /* (LW_CFG_DEVTREE_EN > 0) */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/system/device/clock/clock.h b/SylixOS/system/device/clock/clock.h
new file mode 100644
index 0000000..fbef946
--- /dev/null
+++ b/SylixOS/system/device/clock/clock.h
@@ -0,0 +1,272 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: clock.h
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 08 月 26 日
+**
+** 描 述: 时钟控制核心逻辑
+*********************************************************************************************************/
+
+#ifndef __CLOCK_H
+#define __CLOCK_H
+
+/*********************************************************************************************************
+ 裁减控制
+*********************************************************************************************************/
+#if (LW_CFG_DEVICE_EN > 0) && (LW_CFG_DEVTREE_EN > 0)
+
+/*********************************************************************************************************
+ 操作宏
+*********************************************************************************************************/
+
+#define LW_CLOCK_IS_ROOT 0x0001 /* 根时钟类型 */
+#define LW_CLOCK_SET_RATE_PARENT 0x0002
+#define LW_CLOCK_GET_RATE_NOCACHE 0x0004
+#define LW_CLOCK_DIVIDER_ROUND_CLOSEST 0x0008
+
+#define __HW_FLAGS_GET(clk) (clk->CLK_ulFlags)
+#define __HW_PARENT_GET(clk) (clk->CLK_clkparent ? clk->CLK_clkparent : LW_NULL)
+
+#ifndef __OFFSET_OF
+#define __OFFSET_OF(type, member) ((ULONG)((CHAR *)&((type *)0)->member - (CHAR *)(type *)0))
+#endif
+#ifndef __CONTAINER_OF
+#define __CONTAINER_OF(ptr, type, member) ((type *)((CHAR *)ptr - __OFFSET_OF(type, member)))
+#endif
+
+#define __CLK_TO_CLK_FIXED_FACTOR(clk) __CONTAINER_OF(clk, LW_CLOCK_FIXED_FACTOR, CLKFF_clk)
+#define __CLK_TO_CLK_FIXED_RATE(clk) __CONTAINER_OF(clk, LW_CLOCK_FIXED_RATE, CLKFR_clk)
+#define __CLK_TO_CLK_DIVIDER(clk) __CONTAINER_OF(clk, LW_CLOCK_DIVIDER, CLKD_clk)
+#define __CLK_TO_CLK_GATE(clk) __CONTAINER_OF(clk, LW_CLOCK_GATE, CLKG_clk)
+#define __CLK_TO_CLK_MUX(clk) __CONTAINER_OF(clk, LW_CLOCK_MUX, CLKM_clk)
+
+/*********************************************************************************************************
+ 类型提前声明
+*********************************************************************************************************/
+
+struct lw_clk;
+struct lw_clk_ops;
+struct lw_clk_div_table;
+struct lw_clk_mux_table;
+
+/*********************************************************************************************************
+ 时钟管理结构
+*********************************************************************************************************/
+
+typedef struct lw_clk {
+ LW_LIST_LINE CLK_lineManage; /* 时钟管理链表 */
+ PCHAR CLK_pcName; /* 时钟名称 */
+ struct lw_clk_ops *CLK_clkops; /* 时钟操作集 */
+ struct lw_clk *CLK_clkparent; /* 当前的父时钟 */
+ struct lw_clk **CLK_clkparents; /* 父时钟集合 */
+ CHAR **CLK_ppcParentNames; /* 父时钟名称集合 */
+ UINT CLK_uiNumParents; /* 父时钟数量 */
+ ULONG CLK_ulFlags; /* 时钟标示 */
+ LW_LIST_LINE_HEADER CLK_plineclkchild; /* 所有的子时钟节点 */
+
+ ULONG CLK_ulRate; /* 时钟频率 */
+ UINT CLK_uiEnableCount; /* 时钟使能计数 */
+} LW_CLOCK;
+typedef LW_CLOCK *PLW_CLOCK;
+
+/*********************************************************************************************************
+ 时钟的操作函数集合
+
+ clockPrepare : 时钟使能前需执行的操作,可以有阻塞操作
+ clockUnprepare : 时钟禁能前需执行的操作,可以有阻塞操作
+ clockIsPrepared: 时钟使能前执行的操作是否完成
+
+ clockEnable : 时钟使能操作,不可有阻塞操作
+ clockDisable : 时钟禁能操作,不可有阻塞操作
+ clockIsEnabled : 时钟是否使能
+
+ clockRateRecalc: 获取时钟当前频率
+ clockRateRound : 获取与预期时钟最接近的实际时钟频率
+ clockRateSet : 设置时钟频率
+
+ clockParentSet : 设置当前选中的父时钟
+ clockParentGet : 获取当前选中的父时钟
+
+ clockInit : 时钟初始化
+*********************************************************************************************************/
+
+typedef struct lw_clk_ops {
+ INT (*clockPrepare )(PLW_CLOCK pclk);
+ VOID (*clockUnprepare )(PLW_CLOCK pclk);
+ BOOL (*clockIsPrepared)(PLW_CLOCK pclk);
+
+ INT (*clockEnable )(PLW_CLOCK pclk);
+ VOID (*clockDisable )(PLW_CLOCK pclk);
+ BOOL (*clockIsEnabled )(PLW_CLOCK pclk);
+
+ ULONG (*clockRateRecalc)(PLW_CLOCK pclk, ULONG ulParentRate);
+ LONG (*clockRateRound )(PLW_CLOCK pclk, ULONG ulRate, ULONG *pulParentRate);
+ INT (*clockRateSet )(PLW_CLOCK pclk, ULONG ulRate, ULONG ulParentRate);
+
+ INT (*clockParentSet )(PLW_CLOCK pclk, UINT8 uiIndex);
+ UINT8 (*clockParentGet )(PLW_CLOCK pclk);
+
+ VOID (*clockInit )(PLW_CLOCK pclk);
+} LW_CLOCK_OPS;
+typedef LW_CLOCK_OPS *PLW_CLOCK_OPS;
+
+/*********************************************************************************************************
+ 时钟数据管理结构
+*********************************************************************************************************/
+
+typedef struct lw_clk_div_table { /* 时钟分频表 */
+ UINT CLKDT_uiVal; /* 寄存器对应数值 */
+ UINT CLKDT_uiDiv; /* 时钟分频值 */
+} LW_CLOCK_DIV_TABLE;
+typedef LW_CLOCK_DIV_TABLE *PLW_CLOCK_DIV_TABLE;
+
+typedef struct lw_clk_mux_table { /* 时钟多路选择表 */
+ UINT CLKMT_uiVal; /* 寄存器对应数值 */
+ UINT CLKMT_uiSource; /* 时钟源序号 */
+} LW_CLOCK_MUX_TABLE;
+typedef LW_CLOCK_MUX_TABLE *PLW_CLOCK_MUX_TABLE;
+
+/*********************************************************************************************************
+ 支持的时钟控制类型
+*********************************************************************************************************/
+
+typedef struct lw_clk_provider { /* 统一抽象的时钟类型 */
+ LW_LIST_LINE CLKP_lineManage;
+ PLW_DEVTREE_NODE CLKP_pdtndev;
+ PLW_CLOCK (*CLKP_clkGet)(PLW_DEVTREE_PHANDLE_ARGS pdtpaClkSpec,
+ PVOID pvData);
+ PVOID CLKP_pvData;
+} LW_CLOCK_PROVIDER;
+typedef LW_CLOCK_PROVIDER *PLW_CLOCK_PROVIDER;
+
+typedef struct lw_clk_fixed_rate { /* 固定频率时钟 */
+ struct lw_clk CLKFR_clk; /* 时钟管理单元 */
+ ULONG CLKFR_ulFixedRate; /* 固定时钟频率 */
+ ULONG CLKFR_ulFlags; /* 时钟标示 */
+} LW_CLOCK_FIXED_RATE;
+typedef LW_CLOCK_FIXED_RATE *PLW_CLOCK_FIXED_RATE;
+
+typedef struct lw_clk_fixed_factor { /* 固定分频或倍频时钟 */
+ struct lw_clk CLKFF_clk; /* 时钟管理单元 */
+ UINT32 CLKFF_uiFixedMult; /* 固定时钟倍频值 */
+ UINT32 CLKFF_uiFixedDiv; /* 固定时钟分频值 */
+} LW_CLOCK_FIXED_FACTOR;
+typedef LW_CLOCK_FIXED_FACTOR *PLW_CLOCK_FIXED_FACTOR;
+
+typedef struct lw_clk_divider { /* 可调整分频值的时钟 */
+ struct lw_clk CLKD_clk; /* 时钟管理单元 */
+ struct lw_clk_div_table *CLKD_pclkdivtable; /* 分频值表格 */
+ UINT CLKD_uiMask; /* 寄存器对应掩码 */
+ UINT CLKD_uiShift; /* 寄存器对应移位 */
+ UINT (*CLKD_pfuncValGet)(VOID); /* 寄存器数值获取 */
+ INT (*CLKD_pfuncValSet)(UINT uiVal); /* 寄存器数值设置 */
+} LW_CLOCK_DIVIDER;
+typedef LW_CLOCK_DIVIDER *PLW_CLOCK_DIVIDER;
+
+typedef struct lw_clk_gate { /* 时钟控制门 */
+ struct lw_clk CLKG_clk; /* 时钟管理单元 */
+ INT (*CLKG_pfuncEnable)(VOID); /* 时钟使能 */
+ INT (*CLKG_pfuncDisable)(VOID); /* 时钟禁能 */
+ BOOL (*CLKG_pfuncIsEnabled)(VOID); /* 时钟是否使能 */
+} LW_CLOCK_GATE;
+typedef LW_CLOCK_GATE *PLW_CLOCK_GATE;
+
+typedef struct lw_clk_mux { /* 多路选择门 */
+ struct lw_clk CLKM_clk; /* 时钟管理单元 */
+ struct lw_clk_mux_table *CLKM_pclktable; /* 多路复选表格 */
+ UINT CLKM_uiMask; /* 寄存器对应掩码 */
+ UINT CLKM_uiShift; /* 寄存器对应移位 */
+ UINT (*CLKM_pfuncValGet)(VOID); /* 寄存器数值获取 */
+ INT (*CLKM_pfuncValSet)(UINT uiVal); /* 寄存器数值设置 */
+} LW_CLOCK_MUX;
+typedef LW_CLOCK_MUX *PLW_CLOCK_MUX;
+
+/*********************************************************************************************************
+ API
+*********************************************************************************************************/
+
+LW_API INT API_ClockRegister(PLW_CLOCK pclk);
+
+LW_API INT API_ClockParentSet(PLW_CLOCK pclk, PLW_CLOCK pclkParent);
+
+LW_API ULONG API_ClockRateGet(PLW_CLOCK pclk);
+
+LW_API INT API_ClockRateSet(PLW_CLOCK pclk, ULONG ulReqRate);
+
+LW_API LONG API_ClockRateRound(PLW_CLOCK pclk, ULONG ulRate);
+
+LW_API INT API_ClockInitDataSet(PLW_CLOCK pclk, CPCHAR pcName,
+ PLW_CLOCK_OPS pclkops, ULONG ulFlags,
+ CHAR **ppcParentName, UINT uiParentNum);
+
+LW_API PLW_CLOCK API_ClockSimpleGet(PLW_DEVTREE_PHANDLE_ARGS pdtpaClkSpec, PVOID pvData);
+
+LW_API INT API_ClockProviderAdd(PLW_DEVTREE_NODE pdtndev,
+ PLW_CLOCK (*pfuncClkGet)(PLW_DEVTREE_PHANDLE_ARGS pdtpaClkSpec,
+ PVOID pvData),
+ PVOID pvData);
+
+LW_API PLW_CLOCK API_ClockGetFromProvider(PLW_DEVTREE_PHANDLE_ARGS pdtpaClkSpec);
+
+LW_API PLW_CLOCK API_ClockFind(CPCHAR pcName);
+
+LW_API INT API_ClockEnable(PLW_CLOCK pclk);
+
+LW_API VOID API_ClockDisable(PLW_CLOCK pclk);
+
+LW_API INT API_ClockCoreInit(VOID);
+
+LW_API PLW_CLOCK API_ClockDividerRegister(CPCHAR pcName,
+ CHAR **ppcParentName,
+ ULONG ulFlags,
+ PLW_CLOCK_DIV_TABLE pclkdivtable,
+ UINT uiMask,
+ UINT uiShift,
+ UINTFUNCPTR pfuncValGet,
+ FUNCPTR pfuncValSet);
+
+LW_API PLW_CLOCK API_ClockFixedFactorRegister(CPCHAR pcName,
+ CHAR **pcParentName,
+ ULONG ulFlags,
+ UINT uiFixedMult,
+ UINT uiFixedDiv);
+
+LW_API PLW_CLOCK API_ClockFixedRateRegister(CPCHAR pcName,
+ ULONG ulFlags,
+ ULONG ulFixedRate);
+
+LW_API PLW_CLOCK API_ClockGateRegister(CPCHAR pcName,
+ CHAR **pcParentName,
+ ULONG ulFlags,
+ FUNCPTR pfuncEnable,
+ FUNCPTR pfuncDisable,
+ BOOLFUNCPTR pfuncIsEnabled);
+
+LW_API PLW_CLOCK API_ClockMuxRegister(CPCHAR pcName,
+ CHAR **pcParentName,
+ ULONG ulFlags,
+ UINT uiParentNum,
+ PLW_CLOCK_MUX_TABLE pclkmuxtable,
+ UINT uiMask,
+ UINT uiShift,
+ UINTFUNCPTR pfuncValGet,
+ FUNCPTR pfuncValSet);
+
+#endif /* (LW_CFG_DEVICE_EN > 0) && */
+ /* (LW_CFG_DEVTREE_EN > 0) */
+#endif /* __CLOCK_H */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/system/device/clock/clockDivider.c b/SylixOS/system/device/clock/clockDivider.c
new file mode 100644
index 0000000..9267210
--- /dev/null
+++ b/SylixOS/system/device/clock/clockDivider.c
@@ -0,0 +1,530 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: clockDivider.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 08 月 26 日
+**
+** 描 述: 可变分频值的时钟
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if (LW_CFG_DEVICE_EN > 0) && (LW_CFG_DEVTREE_EN > 0)
+#include "clock.h"
+/*********************************************************************************************************
+ 宏定义
+*********************************************************************************************************/
+#define DIV_ROUND_DOWN_ULL(ll, d) \
+ ({ \
+ lib_lldiv_t ullDiv; \
+ ULONG ullTmp; \
+ ullDiv = lib_lldiv(ll, d); \
+ ullTmp = ullDiv.quot; \
+ ullTmp; \
+ })
+#define DIV_ROUND_UP_ULL(ll, d) DIV_ROUND_DOWN_ULL((ll) + (d) - 1, (d))
+/*********************************************************************************************************
+ 函数声明
+*********************************************************************************************************/
+static ULONG __clockDividerRateRecalc(PLW_CLOCK pclk, ULONG ulParentRate);
+static LONG __clockDividerRateRound(PLW_CLOCK pclk, ULONG ulRate, ULONG *pulRate);
+static INT __clockDividerRateSet(PLW_CLOCK pclk, ULONG ulRate, ULONG ulParentRate);
+/*********************************************************************************************************
+ 变量定义
+*********************************************************************************************************/
+static LW_CLOCK_OPS _G_clkopsDivider = {
+ .clockRateRecalc = __clockDividerRateRecalc,
+ .clockRateRound = __clockDividerRateRound,
+ .clockRateSet = __clockDividerRateSet,
+};
+/*********************************************************************************************************
+** 函数名称: __clockIsBestDiv
+** 功能描述: 判断是否是最合适的分频值
+** 输 入 : ulRate 预期分频数值
+** ulNow 当前分频数值
+** ulBest 当前最佳分频数值
+** ulFlags 时钟标志
+** 输 出 : LW_TRUE 为最佳分频值,LW_FALSE 不为最佳分频值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static BOOL __clockIsBestDiv (ULONG ulRate, ULONG ulNow, ULONG ulBest, ULONG ulFlags)
+{
+ if (ulFlags & LW_CLOCK_DIVIDER_ROUND_CLOSEST) { /* 如果采用最接近的分频值 */
+ return (lib_labs(ulRate - ulNow) < lib_labs(ulRate - ulBest));
+ }
+
+ return (ulNow <= ulRate) && (ulNow > ulBest);
+}
+/*********************************************************************************************************
+** 函数名称: __clockIsValidDiv
+** 功能描述: 判断是否是有效的分频值
+** 输 入 : pclkdivtable 分频表
+** uiDiv 分频值
+** 输 出 : LW_TRUE 为有效分频值,LW_FALSE 不为有效分频值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static BOOL __clockIsValidDiv (PLW_CLOCK_DIV_TABLE pclkdivtable, UINT uiDiv)
+{
+ PLW_CLOCK_DIV_TABLE pclkdivitem;
+
+ for (pclkdivitem = pclkdivtable; pclkdivitem->CLKDT_uiDiv; pclkdivitem++) {
+ if (pclkdivitem->CLKDT_uiDiv == uiDiv) {
+ return (LW_TRUE);
+ }
+ }
+
+ return (LW_FALSE);
+}
+/*********************************************************************************************************
+** 函数名称: __clockTableMinDivGet
+** 功能描述: 获取表中最小分频值
+** 输 入 : pclkdivtable 分频表
+** 输 出 : 最大分频值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static UINT __clockTableMinDivGet (PLW_CLOCK_DIV_TABLE pclkdivtable)
+{
+ PLW_CLOCK_DIV_TABLE pclkdivitem;
+ UINT uiMinDiv = UINT_MAX;
+
+ for (pclkdivitem = pclkdivtable; pclkdivitem->CLKDT_uiDiv; pclkdivitem++) {
+ if (pclkdivitem->CLKDT_uiDiv < uiMinDiv) {
+ uiMinDiv = pclkdivitem->CLKDT_uiDiv;
+ }
+ }
+
+ return (uiMinDiv);
+}
+/*********************************************************************************************************
+** 函数名称: __clockTableDivRoundUpGet
+** 功能描述: 获得表中最接近预期分频值且大于预期分频值的分频值
+** 输 入 : pclkdivtable 分频表
+** uiDiv 预期分频值
+** 输 出 : 最接近预期分频值且大于预期分频值的分频值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static UINT __clockTableDivRoundUpGet (PLW_CLOCK_DIV_TABLE pclkdivtable, UINT uiDiv)
+{
+ PLW_CLOCK_DIV_TABLE pclkdivitem;
+ UINT uiUp = UINT_MAX;
+
+ for (pclkdivitem = pclkdivtable; pclkdivitem->CLKDT_uiDiv; pclkdivitem++) {
+ if (pclkdivitem->CLKDT_uiDiv == uiDiv) { /* 找到最匹配的分频值 */
+ return (pclkdivitem->CLKDT_uiDiv);
+
+ } else if (pclkdivitem->CLKDT_uiDiv < uiDiv) { /* 表项分频值比预期分频值小 */
+ continue;
+ }
+
+ if ((pclkdivitem->CLKDT_uiDiv - uiDiv) < (uiUp - uiDiv)) { /* 表项值与预期值差距更小 */
+ uiUp = pclkdivitem->CLKDT_uiDiv;
+ }
+ }
+
+ return (uiUp);
+}
+/*********************************************************************************************************
+** 函数名称: __clockTableDivRoundDownGet
+** 功能描述: 获得表中最接近预期分频值且小于预期分频值的分频值
+** 输 入 : pclkdivtable 分频表
+** uiDiv 预期分频值
+** 输 出 : 最接近预期分频值且小于预期分频值的分频值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static UINT __clockTableDivRoundDownGet (PLW_CLOCK_DIV_TABLE pclkdivtable, UINT uiDiv)
+{
+ PLW_CLOCK_DIV_TABLE pclkdivitem;
+ UINT uiDown = __clockTableMinDivGet(pclkdivtable);
+
+ for (pclkdivitem = pclkdivtable; pclkdivitem->CLKDT_uiDiv; pclkdivitem++) {
+ if (pclkdivitem->CLKDT_uiDiv == uiDiv) { /* 找到最匹配的分频值 */
+ return (pclkdivitem->CLKDT_uiDiv);
+
+ } else if (pclkdivitem->CLKDT_uiDiv > uiDiv) { /* 表项分频值比预期分频值大 */
+ continue;
+ }
+
+ if ((uiDiv - pclkdivitem->CLKDT_uiDiv) < (uiDiv - uiDown)) { /* 表项值与预期值差距更小 */
+ uiDown = pclkdivitem->CLKDT_uiDiv;
+ }
+ }
+
+ return (uiDown);
+}
+/*********************************************************************************************************
+** 函数名称: __clockDivRoundClosest
+** 功能描述: 获得表中最接近预期分频值的分频值
+** 输 入 : pclkdivtable 分频表
+** ulParentRate 父时钟频率
+** ulRate 预期分频值
+** 输 出 : 最接近预期分频值的分频值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static UINT __clockDivRoundClosest (PLW_CLOCK_DIV_TABLE pclkdivtable,
+ ULONG ulParentRate,
+ ULONG ulRate)
+{
+ ULONG ulUpRate;
+ ULONG ulDownRate;
+ UINT uiDivUp;
+ UINT uiDivDown;
+
+ uiDivUp = DIV_ROUND_UP_ULL((UINT64)ulParentRate, ulRate); /* 分频值的上界 */
+ uiDivDown = ulParentRate / ulRate; /* 分频值的下界 */
+
+ uiDivUp = __clockTableDivRoundUpGet(pclkdivtable, uiDivUp);
+ uiDivDown = __clockTableDivRoundDownGet(pclkdivtable, uiDivDown);
+
+ ulUpRate = DIV_ROUND_UP_ULL((UINT64)ulParentRate, uiDivUp);
+ ulDownRate = DIV_ROUND_UP_ULL((UINT64)ulParentRate, uiDivDown);
+
+ return ((ulRate - ulUpRate) <= (ulDownRate - ulRate) ? uiDivUp : uiDivDown);
+}
+/*********************************************************************************************************
+** 函数名称: __clockDivRound
+** 功能描述: 获得最接近的分频值
+** 输 入 : pclkdivtable 分频表
+** ulParentRate 父时钟频率
+** ulRate 本时钟频率
+** ulFlags 时钟标志
+** 输 出 : 最接近的分频值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static UINT __clockDivRound (PLW_CLOCK_DIV_TABLE pclkdivtable,
+ ULONG ulParentRate,
+ ULONG ulRate,
+ ULONG ulFlags)
+{
+ UINT uiDiv;
+
+ if (ulFlags & LW_CLOCK_DIVIDER_ROUND_CLOSEST) { /* 如果采用最接近的分频值 */
+ return (__clockDivRoundClosest(pclkdivtable, ulParentRate, ulRate));
+ }
+
+ uiDiv = DIV_ROUND_UP_ULL((UINT64)ulParentRate, ulRate);
+
+ return (__clockTableDivRoundUpGet(pclkdivtable, uiDiv)); /* 采用略大于的分频值 */
+}
+/*********************************************************************************************************
+** 函数名称: __clockTableValGet
+** 功能描述: 通过分频值获取寄存器数值
+** 输 入 : pclkdivtable 分频表
+** uiDiv 分频值
+** 输 出 : 寄存器数值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static UINT __clockTableValGet (PLW_CLOCK_DIV_TABLE pclkdivtable, UINT uiDiv)
+{
+ PLW_CLOCK_DIV_TABLE pclkdivitem;
+
+ for (pclkdivitem = pclkdivtable; pclkdivitem->CLKDT_uiDiv; pclkdivitem++) {
+ if (pclkdivitem->CLKDT_uiDiv == uiDiv) {
+ return (pclkdivitem->CLKDT_uiVal);
+ }
+ }
+
+ return (0);
+}
+/*********************************************************************************************************
+** 函数名称: __clockTableDivGet
+** 功能描述: 通过寄存器数值获取分频值
+** 输 入 : pclkdivtable 分频表
+** uiVal 寄存器数值
+** 输 出 : 分频值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static UINT __clockTableDivGet (PLW_CLOCK_DIV_TABLE pclkdivtable, UINT uiVal)
+{
+ PLW_CLOCK_DIV_TABLE pclkdivitem;
+
+ for (pclkdivitem = pclkdivtable; pclkdivitem->CLKDT_uiDiv; pclkdivitem++) {
+ if (pclkdivitem->CLKDT_uiVal == uiVal) {
+ return (pclkdivitem->CLKDT_uiDiv);
+ }
+ }
+
+ return (1);
+}
+/*********************************************************************************************************
+** 函数名称: __clockTableMaxDivGet
+** 功能描述: 获取表中最大分频值
+** 输 入 : pclkdivtable 分频表
+** 输 出 : 最大分频值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static UINT __clockTableMaxDivGet (PLW_CLOCK_DIV_TABLE pclkdivtable)
+{
+ PLW_CLOCK_DIV_TABLE pclkdivitem;
+ UINT uiMaxDiv = 0;
+
+ for (pclkdivitem = pclkdivtable; pclkdivitem->CLKDT_uiDiv; pclkdivitem++) {
+ if (pclkdivitem->CLKDT_uiDiv > uiMaxDiv) {
+ uiMaxDiv = pclkdivitem->CLKDT_uiDiv;
+ }
+ }
+
+ return (uiMaxDiv);
+}
+/*********************************************************************************************************
+** 函数名称: __clockTableBestdivGet
+** 功能描述: 获得最合适的分频值
+** 输 入 : pclk 时钟设备
+** pclkParent 父时钟设备
+** ulRate 时钟频率
+** pulBestParentRate 最适合的父时钟频率
+** pclkdivtable 分频表
+** 输 出 : 最合适的分频值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static UINT __clockTableBestdivGet (PLW_CLOCK pclk,
+ PLW_CLOCK pclkParent,
+ ULONG ulRate,
+ ULONG *pulBestParentRate,
+ PLW_CLOCK_DIV_TABLE pclkdivtable)
+{
+ ULONG ulParentRate;
+ ULONG ulParentRateSaved = *pulBestParentRate;
+ ULONG ulBest = 0;
+ ULONG ulNow;
+ UINT uiMaxDiv;
+ UINT uiBestDiv = 0;
+ INT i;
+
+ if (!ulRate) {
+ ulRate = 1;
+ }
+
+ uiMaxDiv = __clockTableMaxDivGet(pclkdivtable);
+
+ if (!(__HW_FLAGS_GET(pclk) & LW_CLOCK_SET_RATE_PARENT)) {
+ ulParentRate = *pulBestParentRate;
+ uiBestDiv = __clockDivRound(pclkdivtable,
+ ulParentRate,
+ ulRate,
+ __HW_FLAGS_GET(pclk));
+ uiBestDiv = uiBestDiv > uiMaxDiv ? uiMaxDiv : uiBestDiv;
+ return (uiBestDiv);
+ }
+
+ uiMaxDiv = __MIN(ULONG_MAX / ulRate, uiMaxDiv);
+
+ for (i = __clockTableDivRoundUpGet(pclkdivtable, 1);
+ i <= uiMaxDiv;
+ i = __clockTableDivRoundUpGet(pclkdivtable, i)) {
+
+ if (ulRate * i == ulParentRateSaved) {
+ *pulBestParentRate = ulParentRateSaved;
+ return (i);
+ }
+
+ ulParentRate = API_ClockRateRound(pclk, ulRate * i);
+ ulNow = DIV_ROUND_UP_ULL((UINT64)ulParentRate, i);
+ if (__clockIsBestDiv(ulRate, ulNow, ulBest, __HW_FLAGS_GET(pclk))) {
+ uiBestDiv = i;
+ ulBest = ulNow;
+ *pulBestParentRate = ulParentRate;
+ }
+ }
+
+ if (!uiBestDiv) {
+ uiBestDiv = __clockTableMaxDivGet(pclkdivtable);
+ *pulBestParentRate = API_ClockRateRound(pclkParent, ulRate);
+ }
+
+ return (uiBestDiv);
+}
+/*********************************************************************************************************
+** 函数名称: __clockDividerValGet
+** 功能描述: 获得对应频率的寄存器数值
+** 输 入 : pclkdivtable 分频表
+** ulParentRate 父时钟频率
+** ulRate 本时钟频率
+** 输 出 : 寄存器数值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __clockDividerValGet (PLW_CLOCK_DIV_TABLE pclkdivtable,
+ ULONG ulParentRate,
+ ULONG ulRate)
+{
+ UINT uiDiv;
+ UINT uiValue;
+
+ uiDiv = DIV_ROUND_UP_ULL((UINT64)ulParentRate, ulRate);
+
+ if (!__clockIsValidDiv(pclkdivtable, uiDiv)) { /* 判断是否是有效分频值 */
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ uiValue = __clockTableValGet(pclkdivtable, uiDiv);
+
+ return (uiValue);
+}
+/*********************************************************************************************************
+** 函数名称: __clockDividerRateRecalc
+** 功能描述: 获得分频或倍频时钟的频率值
+** 输 入 : pclk 时钟设备
+** ulParentRate 父时钟频率
+** 输 出 : 时钟的频率值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static ULONG __clockDividerRateRecalc (PLW_CLOCK pclk, ULONG ulParentRate)
+{
+ PLW_CLOCK_DIVIDER pclkdivider = __CLK_TO_CLK_DIVIDER(pclk);
+ UINT32 uiRegVal;
+ UINT32 uiDiv;
+
+ uiRegVal = pclkdivider->CLKD_pfuncValGet();
+ uiRegVal &= pclkdivider->CLKD_uiMask;
+ uiRegVal = uiRegVal >> pclkdivider->CLKD_uiShift;
+ uiDiv = __clockTableDivGet(pclkdivider->CLKD_pclkdivtable, uiRegVal);
+
+ return (DIV_ROUND_UP_ULL((UINT64)ulParentRate, uiDiv));
+}
+/*********************************************************************************************************
+** 函数名称: __clockDividerRateSet
+** 功能描述: 设置频率
+** 输 入 : pclk 时钟设备
+** ulRate 预设置的频率值
+** ulParentRate 父时钟的频率值
+** 输 出 : ERROR_NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __clockDividerRateSet (PLW_CLOCK pclk, ULONG ulRate, ULONG ulParentRate)
+{
+ PLW_CLOCK_DIVIDER pclkdivider = __CLK_TO_CLK_DIVIDER(pclk);
+ UINT uiRegVal;
+ INT iVal;
+
+ iVal = __clockDividerValGet(pclkdivider->CLKD_pclkdivtable, ulRate, ulParentRate);
+ if (iVal < 0) {
+ return (iVal);
+ }
+
+ uiRegVal = pclkdivider->CLKD_pfuncValGet();
+ uiRegVal &= ~pclkdivider->CLKD_uiMask;
+ uiRegVal |= iVal << pclkdivider->CLKD_uiShift;
+
+ return (pclkdivider->CLKD_pfuncValSet(iVal));
+}
+/*********************************************************************************************************
+** 函数名称: __clockDividerRateRound
+** 功能描述: 获得最接近预设频率的频率值
+** 输 入 : pclk 时钟设备
+** ulRate 预设置的频率值
+** pulParentRate 父时钟的频率值
+** 输 出 : 最接近预设频率的频率值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static LONG __clockDividerRateRound (PLW_CLOCK pclk, ULONG ulRate, ULONG *pulParentRate)
+{
+ PLW_CLOCK_DIVIDER pclkdivider = __CLK_TO_CLK_DIVIDER(pclk);
+ PLW_CLOCK pclkParent = pclk->CLK_clkparent;
+ UINT32 uiDiv;
+
+ uiDiv = __clockTableBestdivGet(pclk,
+ pclkParent,
+ ulRate,
+ pulParentRate,
+ pclkdivider->CLKD_pclkdivtable);
+
+ return (DIV_ROUND_UP_ULL((UINT64)*pulParentRate, uiDiv));
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockDividerRegister
+** 功能描述: 注册可变分频的时钟
+** 输 入 : pcName 时钟名称
+** ppcParentName 父时钟名称
+** ulFlags 初始化标识
+** pclkdivtable 分频表
+** uiMask 寄存器掩码
+** uiShift 寄存器移位
+** pfuncValGet 寄存器值获取函数
+** pfuncValSet 寄存器值设置函数
+** 输 出 : 可变分频的时钟
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_CLOCK API_ClockDividerRegister (CPCHAR pcName,
+ CHAR **ppcParentName,
+ ULONG ulFlags,
+ PLW_CLOCK_DIV_TABLE pclkdivtable,
+ UINT uiMask,
+ UINT uiShift,
+ UINTFUNCPTR pfuncValGet,
+ FUNCPTR pfuncValSet)
+{
+ PLW_CLOCK_DIVIDER pclkdivider;
+ PLW_CLOCK pclk;
+ INT iRet;
+
+ pclkdivider = __SHEAP_ZALLOC(sizeof(LW_CLOCK_DIVIDER));
+ if (!pclkdivider) {
+ _ErrorHandle(ENOMEM);
+ return (LW_NULL);
+ }
+
+ iRet = API_ClockInitDataSet(&pclkdivider->CLKD_clk,
+ pcName,
+ &_G_clkopsDivider,
+ ulFlags,
+ ppcParentName,
+ 1);
+ if (iRet) {
+ __SHEAP_FREE(pclkdivider);
+ return (LW_NULL);
+ }
+
+ pclk = &pclkdivider->CLKD_clk;
+ pclkdivider->CLKD_pclkdivtable = pclkdivtable;
+ pclkdivider->CLKD_uiMask = uiMask;
+ pclkdivider->CLKD_uiShift = uiShift;
+ pclkdivider->CLKD_pfuncValGet = pfuncValGet;
+ pclkdivider->CLKD_pfuncValSet = pfuncValSet;
+
+ iRet = API_ClockRegister(pclk);
+ if (iRet) {
+ __SHEAP_FREE(pclkdivider);
+ return (LW_NULL);
+ }
+
+ return (pclk);
+}
+
+#endif /* (LW_CFG_DEVICE_EN > 0) && */
+ /* (LW_CFG_DEVTREE_EN > 0) */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/system/device/clock/clockFixedFactor.c b/SylixOS/system/device/clock/clockFixedFactor.c
new file mode 100644
index 0000000..1fd810a
--- /dev/null
+++ b/SylixOS/system/device/clock/clockFixedFactor.c
@@ -0,0 +1,160 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: clockFixedFactor.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 08 月 26 日
+**
+** 描 述: 有固定分频或倍频值的时钟
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if (LW_CFG_DEVICE_EN > 0) && (LW_CFG_DEVTREE_EN > 0)
+#include "clock.h"
+/*********************************************************************************************************
+ 函数声明
+*********************************************************************************************************/
+static ULONG __clockFixedFactorRateRecalc(PLW_CLOCK pclk, ULONG ulParentRate);
+static LONG __clockFixedFactorRateRound(PLW_CLOCK pclk, ULONG ulRate, ULONG *pulRate);
+static INT __clockFixedFactorRateSet(PLW_CLOCK pclk, ULONG ulRate, ULONG ulParentRate);
+/*********************************************************************************************************
+ 变量定义
+*********************************************************************************************************/
+static LW_CLOCK_OPS _G_clkopsFixedFactor = {
+ .clockRateRecalc = __clockFixedFactorRateRecalc,
+ .clockRateRound = __clockFixedFactorRateRound,
+ .clockRateSet = __clockFixedFactorRateSet,
+};
+/*********************************************************************************************************
+** 函数名称: __clockFixedFactorRateRecalc
+** 功能描述: 获得分频或倍频时钟的频率值
+** 输 入 : pclk 时钟设备
+** ulParentRate 父时钟频率
+** 输 出 : 固定频率时钟的频率值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static ULONG __clockFixedFactorRateRecalc (PLW_CLOCK pclk, ULONG ulParentRate)
+{
+ PLW_CLOCK_FIXED_FACTOR pclkfixedfactor = __CLK_TO_CLK_FIXED_FACTOR(pclk);
+ UINT64 ullRate;
+ lib_lldiv_t ullDiv;
+
+ ullRate = (UINT64)ulParentRate * pclkfixedfactor->CLKFF_uiFixedMult;/* 父时钟倍频 */
+ ullDiv = lib_lldiv(ullRate, pclkfixedfactor->CLKFF_uiFixedDiv); /* 父时钟分频 */
+ ullRate = ullDiv.quot;
+
+ return ((ULONG)ullRate);
+}
+/*********************************************************************************************************
+** 函数名称: __clockFixedFactorRateRound
+** 功能描述: 获得最接近预设频率的频率值
+** 输 入 : pclk 时钟设备
+** ulRate 预设置的频率值
+** pulParentRate 父时钟的频率值
+** 输 出 : 最接近预设频率的频率值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static LONG __clockFixedFactorRateRound (PLW_CLOCK pclk, ULONG ulRate, ULONG *pulParentRate)
+{
+ PLW_CLOCK_FIXED_FACTOR pclkfixedfactor = __CLK_TO_CLK_FIXED_FACTOR(pclk);
+ ULONG ulBestParent;
+
+ if (__HW_FLAGS_GET(pclk) & LW_CLOCK_SET_RATE_PARENT) { /* 同时设置父时钟的频率 */
+ ulBestParent = (ulRate / pclkfixedfactor->CLKFF_uiFixedMult) *
+ pclkfixedfactor->CLKFF_uiFixedDiv;
+ *pulParentRate = API_ClockRateRound(__HW_PARENT_GET(pclk), ulBestParent);
+ }
+
+ return ((*pulParentRate / pclkfixedfactor->CLKFF_uiFixedDiv) *
+ pclkfixedfactor->CLKFF_uiFixedMult);
+}
+/*********************************************************************************************************
+** 函数名称: __clockFixedFactorRateRound
+** 功能描述: 设置频率
+** 输 入 : pclk 时钟设备
+** ulRate 预设置的频率值
+** ulParentRate 父时钟的频率值
+** 输 出 : ERROR_NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __clockFixedFactorRateSet (PLW_CLOCK pclk, ULONG ulRate, ULONG ulParentRate)
+{
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockFixedFactorRegister
+** 功能描述: 注册固定分频或倍频的时钟
+** 输 入 : pcName 时钟名称
+** pcParentName 父时钟名称
+** ulFlags 初始化标识
+** uiFixedMult 固定的倍频值
+** uiFixedDiv 固定的分频值
+** 输 出 : 固定分频或倍频的时钟
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_CLOCK API_ClockFixedFactorRegister (CPCHAR pcName,
+ CHAR **pcParentName,
+ ULONG ulFlags,
+ UINT uiFixedMult,
+ UINT uiFixedDiv)
+{
+ PLW_CLOCK_FIXED_FACTOR pclkfixedfactor;
+ PLW_CLOCK pclk;
+ INT iRet;
+
+ pclkfixedfactor = __SHEAP_ZALLOC(sizeof(LW_CLOCK_FIXED_FACTOR));
+ if (!pclkfixedfactor) {
+ _ErrorHandle(ENOMEM);
+ return (LW_NULL);
+ }
+
+ iRet = API_ClockInitDataSet(&pclkfixedfactor->CLKFF_clk,
+ pcName,
+ &_G_clkopsFixedFactor,
+ ulFlags,
+ pcParentName,
+ 1);
+ if (iRet) {
+ __SHEAP_FREE(pclkfixedfactor);
+ return (LW_NULL);
+ }
+
+ pclk = &pclkfixedfactor->CLKFF_clk;
+ pclkfixedfactor->CLKFF_uiFixedMult = uiFixedMult;
+ pclkfixedfactor->CLKFF_uiFixedDiv = uiFixedDiv;
+
+ iRet = API_ClockRegister(pclk);
+ if (iRet) {
+ __SHEAP_FREE(pclkfixedfactor);
+ return (LW_NULL);
+ }
+
+ return (pclk);
+}
+
+#endif /* (LW_CFG_DEVICE_EN > 0) && */
+ /* (LW_CFG_DEVTREE_EN > 0) */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/system/device/clock/clockFixedRate.c b/SylixOS/system/device/clock/clockFixedRate.c
new file mode 100644
index 0000000..dfebe4d
--- /dev/null
+++ b/SylixOS/system/device/clock/clockFixedRate.c
@@ -0,0 +1,105 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: clockFixedRate.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 08 月 26 日
+**
+** 描 述: 标准固定频率时钟驱动(如 Oscillator 或 Crystal).
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if (LW_CFG_DEVICE_EN > 0) && (LW_CFG_DEVTREE_EN > 0)
+#include "clock.h"
+/*********************************************************************************************************
+ 函数声明
+*********************************************************************************************************/
+static ULONG __clockFixedRateRecalc(PLW_CLOCK pclk, ULONG ulParentRate);
+/*********************************************************************************************************
+ 变量定义
+*********************************************************************************************************/
+static LW_CLOCK_OPS _G_clkopsFixedRate = {
+ .clockRateRecalc = __clockFixedRateRecalc,
+};
+/*********************************************************************************************************
+** 函数名称: __clockFixedRateRecalc
+** 功能描述: 获得固定频率时钟的频率值
+** 输 入 : pclk 时钟设备
+** ulParentRate 父时钟频率,暂时无用
+** 输 出 : 固定频率时钟的频率值
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static ULONG __clockFixedRateRecalc (PLW_CLOCK pclk, ULONG ulParentRate)
+{
+ return (__CLK_TO_CLK_FIXED_RATE(pclk)->CLKFR_ulFixedRate);
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockFixedRateRegister
+** 功能描述: 注册一个固定频率的时钟
+** 输 入 : pcName 时钟名称
+** ulFlags 时钟标识
+** ulFixedRate 固定的频率
+** 输 出 : 注册的固定频率时钟
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_CLOCK API_ClockFixedRateRegister (CPCHAR pcName,
+ ULONG ulFlags,
+ ULONG ulFixedRate)
+{
+ PLW_CLOCK_FIXED_RATE pclkfixedrate;
+ PLW_CLOCK pclk;
+ INT iRet;
+
+ pclkfixedrate = __SHEAP_ZALLOC(sizeof(LW_CLOCK_FIXED_RATE));
+ if (!pclkfixedrate) {
+ _ErrorHandle(ENOMEM);
+ return (LW_NULL);
+ }
+
+ iRet = API_ClockInitDataSet(&pclkfixedrate->CLKFR_clk,
+ pcName,
+ &_G_clkopsFixedRate,
+ ulFlags,
+ LW_NULL,
+ 0);
+ if (iRet) {
+ __SHEAP_FREE(pclkfixedrate);
+ return (LW_NULL);
+ }
+
+ pclk = &pclkfixedrate->CLKFR_clk;
+ pclkfixedrate->CLKFR_ulFixedRate = ulFixedRate;
+
+ iRet = API_ClockRegister(pclk);
+ if (iRet) {
+ __SHEAP_FREE(pclkfixedrate);
+ return (LW_NULL);
+ }
+
+ return (pclk);
+}
+
+#endif /* (LW_CFG_DEVICE_EN > 0) && */
+ /* (LW_CFG_DEVTREE_EN > 0) */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/system/device/clock/clockGate.c b/SylixOS/system/device/clock/clockGate.c
new file mode 100644
index 0000000..fef7faa
--- /dev/null
+++ b/SylixOS/system/device/clock/clockGate.c
@@ -0,0 +1,146 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: clockGate.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 08 月 27 日
+**
+** 描 述: 门控时钟驱动(只能控制时钟使能和禁能).
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if (LW_CFG_DEVICE_EN > 0) && (LW_CFG_DEVTREE_EN > 0)
+#include "clock.h"
+/*********************************************************************************************************
+ 函数声明
+*********************************************************************************************************/
+static INT __clockGateEnable(PLW_CLOCK pclk);
+static VOID __clockGateDisable(PLW_CLOCK pclk);
+static BOOL __clockGateIsEnabled(PLW_CLOCK pclk);
+/*********************************************************************************************************
+ 变量定义
+*********************************************************************************************************/
+static LW_CLOCK_OPS _G_clkopsGate = {
+ .clockEnable = __clockGateEnable,
+ .clockDisable = __clockGateDisable,
+ .clockIsEnabled = __clockGateIsEnabled,
+};
+/*********************************************************************************************************
+** 函数名称: __clockGateEnable
+** 功能描述: 使能时钟
+** 输 入 : pclk 时钟设备
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __clockGateEnable (PLW_CLOCK pclk)
+{
+ PLW_CLOCK_GATE pclkgate = __CLK_TO_CLK_GATE(pclk);
+
+ return (pclkgate->CLKG_pfuncEnable());
+}
+/*********************************************************************************************************
+** 函数名称: __clockGateDisable
+** 功能描述: 禁能时钟
+** 输 入 : pclk 时钟设备
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __clockGateDisable (PLW_CLOCK pclk)
+{
+ PLW_CLOCK_GATE pclkgate = __CLK_TO_CLK_GATE(pclk);
+
+ pclkgate->CLKG_pfuncDisable();
+}
+/*********************************************************************************************************
+** 函数名称: __clockGateIsEnabled
+** 功能描述: 判断时钟是否使能
+** 输 入 : pclk 时钟设备
+** 输 出 : LW_TRUE 时钟使能,LW_FALSE 时钟禁能
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static BOOL __clockGateIsEnabled (PLW_CLOCK pclk)
+{
+ PLW_CLOCK_GATE pclkgate = __CLK_TO_CLK_GATE(pclk);
+
+ return (pclkgate->CLKG_pfuncIsEnabled());
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockGateRegister
+** 功能描述: 注册一个控制门时钟
+** 输 入 : pcName 时钟名称
+** pcParentName 父时钟名称
+** ulFlags 初始化标识
+** pfuncEnable 使能操作函数
+** pfuncDisable 禁能操作函数
+** pfuncIsEnabled 是否使能判断函数
+** 输 出 : 注册的控制门时钟
+** 全局变量:
+** 调用模块:
+** API 函数
+*********************************************************************************************************/
+LW_API
+PLW_CLOCK API_ClockGateRegister (CPCHAR pcName,
+ CHAR **pcParentName,
+ ULONG ulFlags,
+ FUNCPTR pfuncEnable,
+ FUNCPTR pfuncDisable,
+ BOOLFUNCPTR pfuncIsEnabled)
+{
+ PLW_CLOCK_GATE pclkgate;
+ PLW_CLOCK pclk;
+ INT iRet;
+
+ pclkgate = __SHEAP_ZALLOC(sizeof(LW_CLOCK_GATE));
+ if (!pclkgate) {
+ _ErrorHandle(ENOMEM);
+ return (LW_NULL);
+ }
+
+ iRet = API_ClockInitDataSet(&pclkgate->CLKG_clk,
+ pcName,
+ &_G_clkopsGate,
+ ulFlags,
+ pcParentName,
+ pcParentName ? 1 : 0);
+ if (iRet) {
+ __SHEAP_FREE(pclkgate);
+ return (LW_NULL);
+ }
+
+ pclk = &pclkgate->CLKG_clk;
+ pclkgate->CLKG_pfuncEnable = pfuncEnable;
+ pclkgate->CLKG_pfuncDisable = pfuncDisable;
+ pclkgate->CLKG_pfuncIsEnabled = pfuncIsEnabled;
+
+ iRet = API_ClockRegister(pclk);
+ if (iRet) {
+ __SHEAP_FREE(pclkgate);
+ return (LW_NULL);
+ }
+
+ return (pclk);
+}
+
+#endif /* (LW_CFG_DEVICE_EN > 0) && */
+ /* (LW_CFG_DEVTREE_EN > 0) */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/system/device/clock/clockMux.c b/SylixOS/system/device/clock/clockMux.c
new file mode 100644
index 0000000..8d798a3
--- /dev/null
+++ b/SylixOS/system/device/clock/clockMux.c
@@ -0,0 +1,167 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: clockGate.c
+**
+** 创 建 人: Wang.Xuan (王翾)
+**
+** 文件创建日期: 2019 年 08 月 27 日
+**
+** 描 述: 多选一时钟驱动(控制父时钟选择).
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#define __SYLIXOS_DEVTREE_DRV
+#include "SylixOS.h"
+/*********************************************************************************************************
+ 裁剪宏
+*********************************************************************************************************/
+#if (LW_CFG_DEVICE_EN > 0) && (LW_CFG_DEVTREE_EN > 0)
+#include "clock.h"
+/*********************************************************************************************************
+ 函数声明
+*********************************************************************************************************/
+static UINT8 __clockMuxParentGet(PLW_CLOCK pclk);
+static INT __clockMuxParentSet(PLW_CLOCK pclk, UINT8 ucIndex);
+/*********************************************************************************************************
+ 变量定义
+*********************************************************************************************************/
+static LW_CLOCK_OPS _G_clkopsMux = {
+ .clockParentGet = __clockMuxParentGet,
+ .clockParentSet = __clockMuxParentSet,
+};
+/*********************************************************************************************************
+** 函数名称: __clockMuxParentGet
+** 功能描述: 获得当前选中的父时钟序号
+** 输 入 : pclk 时钟设备
+** 输 出 : 当前选中的父时钟序号
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static UINT8 __clockMuxParentGet (PLW_CLOCK pclk)
+{
+ PLW_CLOCK_MUX pclkmux = __CLK_TO_CLK_MUX(pclk);
+ PLW_CLOCK_MUX_TABLE pclkmuxtable = pclkmux->CLKM_pclktable;
+ UINT uiNumParents = pclk->CLK_uiNumParents;
+ UINT uiVal = pclkmux->CLKM_pfuncValGet();
+ UINT i;
+
+ uiVal &= pclkmux->CLKM_uiMask;
+ uiVal = uiVal >> pclkmux->CLKM_uiShift;
+
+ for (i = 0; i < uiNumParents; i++) {
+ if (pclkmuxtable[i].CLKMT_uiVal == uiVal) {
+ return (pclkmuxtable[i].CLKMT_uiSource);
+ }
+ }
+
+ return (0);
+}
+/*********************************************************************************************************
+** 函数名称: __clockMuxParentSet
+** 功能描述: 设置当前的父时钟序号
+** 输 入 : pclk 时钟设备
+** ucIndex 对应的父时钟序号
+** 输 出 : ERROR_CODE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __clockMuxParentSet (PLW_CLOCK pclk, UINT8 ucIndex)
+{
+ PLW_CLOCK_MUX pclkmux = __CLK_TO_CLK_MUX(pclk);
+ PLW_CLOCK_MUX_TABLE pclkmuxtable = pclkmux->CLKM_pclktable;
+ UINT uiNumParents = pclk->CLK_uiNumParents;
+ UINT uiVal = pclkmux->CLKM_pfuncValGet();
+ UINT uiRegVal;
+ UINT i;
+
+ for (i = 0; i < uiNumParents; i++) {
+ if (pclkmuxtable[i].CLKMT_uiSource == ucIndex) {
+ uiVal = pclkmuxtable[i].CLKMT_uiVal;
+ }
+ }
+
+ uiVal = uiVal << pclkmux->CLKM_uiShift;
+ uiRegVal = pclkmux->CLKM_pfuncValGet();
+ uiRegVal &= ~pclkmux->CLKM_uiMask;
+ uiRegVal |= uiVal;
+
+ return (pclkmux->CLKM_pfuncValSet(uiVal));
+}
+/*********************************************************************************************************
+** 函数名称: API_ClockDividerRegister
+** 功能描述: 注册可变分频的时钟
+** 输 入 : pcName 时钟名称
+** pcParentName 父时钟名称
+** ulFlags 初始化标识
+** pclkmuxtable 分频表
+** uiMask 掩码
+** uiShift 移位
+** pfuncValGet 寄存器值获取函数
+** pfuncValSet 寄存器值设置函数
+** 输 出 : 可变分频的时钟