mirror of
https://github.com/HEYAHONG/rt-thread-no-bsp.git
synced 2025-05-09 00:02:13 +08:00
update by jenkins(20250201001522)
This commit is contained in:
parent
504d73aa19
commit
a17817ebb8
@ -32,7 +32,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: Tools
|
name: Tools
|
||||||
if: github.repository_owner == 'RT-Thread'
|
if: github.repository_owner == 'RT-Thread'
|
||||||
strategy:
|
strategy:
|
||||||
|
@ -26,7 +26,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: ${{ matrix.legs.UTEST }}
|
name: ${{ matrix.legs.UTEST }}
|
||||||
if: github.repository_owner == 'RT-Thread'
|
if: github.repository_owner == 'RT-Thread'
|
||||||
strategy:
|
strategy:
|
||||||
|
@ -20,6 +20,6 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/labeler@v5
|
- uses: actions/labeler@v5
|
@ -30,7 +30,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: ${{ matrix.legs.RTT_BSP }}
|
name: ${{ matrix.legs.RTT_BSP }}
|
||||||
if: github.repository_owner == 'RT-Thread'
|
if: github.repository_owner == 'RT-Thread'
|
||||||
strategy:
|
strategy:
|
||||||
@ -101,6 +101,7 @@ jobs:
|
|||||||
- "rm48x50"
|
- "rm48x50"
|
||||||
- "ht32/ht32f52352"
|
- "ht32/ht32f52352"
|
||||||
- "ht32/ht32f12366"
|
- "ht32/ht32f12366"
|
||||||
|
- "ht32/ht32f53252"
|
||||||
- "w60x"
|
- "w60x"
|
||||||
- "essemi/es32f0654"
|
- "essemi/es32f0654"
|
||||||
- "essemi/es32f365x"
|
- "essemi/es32f365x"
|
||||||
@ -509,4 +510,4 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
curl -X POST -H "Authorization: token ${{ secrets.RTTHREAD_GITHUB_TOKEN }}" \
|
curl -X POST -H "Authorization: token ${{ secrets.RTTHREAD_GITHUB_TOKEN }}" \
|
||||||
-d '{"body":"@${{ github.actor }}, Thank you for your contribution, but there was an error with the action. Could you please help check the BSP compilation issue? Thank you."}' \
|
-d '{"body":"@${{ github.actor }}, Thank you for your contribution, but there was an error with the action. Could you please help check the BSP compilation issue? Thank you."}' \
|
||||||
"https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments"
|
"https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments"
|
||||||
|
@ -33,7 +33,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: BSP Compilation with More Drivers
|
name: BSP Compilation with More Drivers
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
43
rt-thread-no-bsp/.github/workflows/doxygen.yml
vendored
43
rt-thread-no-bsp/.github/workflows/doxygen.yml
vendored
@ -11,18 +11,35 @@ on:
|
|||||||
- 'components/dfs/dfs_v2/include/**'
|
- 'components/dfs/dfs_v2/include/**'
|
||||||
- 'components/dfs/dfs_v2/src/**'
|
- 'components/dfs/dfs_v2/src/**'
|
||||||
- 'components/finsh/**'
|
- 'components/finsh/**'
|
||||||
|
- '.github/workflows/doxygen.yml'
|
||||||
# Runs at 16:00 UTC (BeiJing 00:00) on the 30st of every month
|
# Runs at 16:00 UTC (BeiJing 00:00) on the 30st of every month
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
paths:
|
||||||
|
- 'documentation/doxygen/**'
|
||||||
|
- 'src/**'
|
||||||
|
- 'include/**'
|
||||||
|
- 'components/drivers/include/drivers/**'
|
||||||
|
- 'components/dfs/dfs_v2/include/**'
|
||||||
|
- 'components/dfs/dfs_v2/src/**'
|
||||||
|
- 'components/finsh/**'
|
||||||
|
- '.github/workflows/doxygen.yml'
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 16 30 * *'
|
- cron: '0 16 30 * *'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
name: doxygen_doc generate
|
name: doxygen_doc generate
|
||||||
if: github.repository_owner == 'RT-Thread'
|
if: github.repository_owner == 'RT-Thread'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@main
|
||||||
with:
|
with:
|
||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
- name: Install Tools
|
- name: Install Tools
|
||||||
@ -30,9 +47,27 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get -qq install doxygen graphviz
|
sudo apt-get -qq install doxygen graphviz
|
||||||
- name: generat doxygen html
|
- name: generate doxygen html
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
cd documentation/doxygen
|
cd documentation
|
||||||
doxygen Doxyfile
|
doxygen Doxyfile
|
||||||
cat Doxyfile
|
cat Doxyfile
|
||||||
|
|
||||||
|
- name: Upload static files as artifact
|
||||||
|
id: deployment
|
||||||
|
uses: actions/upload-pages-artifact@main # or specific "vX.X.X" version tag for this action
|
||||||
|
with:
|
||||||
|
path: documentation/html/
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
needs: build
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@main
|
||||||
|
@ -11,7 +11,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
scancode_job:
|
scancode_job:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: Scan code format and license
|
name: Scan code format and license
|
||||||
if: github.repository_owner == 'RT-Thread'
|
if: github.repository_owner == 'RT-Thread'
|
||||||
steps:
|
steps:
|
||||||
|
@ -51,7 +51,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: ${{ github.event.inputs.bsp_options }}
|
name: ${{ github.event.inputs.bsp_options }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
@ -50,7 +50,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: ${{ github.event.inputs.bsp_options }}
|
name: ${{ github.event.inputs.bsp_options }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
@ -32,7 +32,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: ${{ matrix.legs.RTT_BSP }}
|
name: ${{ matrix.legs.RTT_BSP }}
|
||||||
if: github.repository_owner == 'RT-Thread'
|
if: github.repository_owner == 'RT-Thread'
|
||||||
strategy:
|
strategy:
|
||||||
|
@ -34,7 +34,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: ${{ matrix.legs.RTT_BSP }}
|
name: ${{ matrix.legs.RTT_BSP }}
|
||||||
if: github.repository_owner == 'RT-Thread'
|
if: github.repository_owner == 'RT-Thread'
|
||||||
strategy:
|
strategy:
|
||||||
|
@ -34,7 +34,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: ${{ matrix.legs.RTT_BSP }}
|
name: ${{ matrix.legs.RTT_BSP }}
|
||||||
if: github.repository_owner == 'RT-Thread'
|
if: github.repository_owner == 'RT-Thread'
|
||||||
strategy:
|
strategy:
|
||||||
|
@ -40,7 +40,7 @@ permissions:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: update and create pull request
|
name: update and create pull request
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
@ -9,7 +9,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
spelling:
|
spelling:
|
||||||
name: Check Spelling
|
name: Check Spelling
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
if: github.repository_owner == 'RT-Thread'
|
if: github.repository_owner == 'RT-Thread'
|
||||||
steps:
|
steps:
|
||||||
- name: output ignore words info
|
- name: output ignore words info
|
||||||
|
@ -21,7 +21,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
scancode_job:
|
scancode_job:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
name: Static code analysis
|
name: Static code analysis
|
||||||
if: github.repository_owner == 'RT-Thread'
|
if: github.repository_owner == 'RT-Thread'
|
||||||
steps:
|
steps:
|
||||||
|
7
rt-thread-no-bsp/.gitignore
vendored
7
rt-thread-no-bsp/.gitignore
vendored
@ -43,6 +43,7 @@ ncscope.*
|
|||||||
tags
|
tags
|
||||||
|
|
||||||
.idea
|
.idea
|
||||||
|
**/.cache/
|
||||||
.vscode
|
.vscode
|
||||||
*.code-workspace
|
*.code-workspace
|
||||||
*.eide.*
|
*.eide.*
|
||||||
@ -57,4 +58,8 @@ vdso.lds
|
|||||||
|
|
||||||
# cherryusb libraries
|
# cherryusb libraries
|
||||||
!components/drivers/usb/cherryusb/port/pusb2/*.a
|
!components/drivers/usb/cherryusb/port/pusb2/*.a
|
||||||
!components/drivers/usb/cherryusb/port/xhci/phytium/*.a
|
!components/drivers/usb/cherryusb/port/xhci/phytium/*.a
|
||||||
|
|
||||||
|
# stm32cubemx
|
||||||
|
**/CubeMX_Config/Drivers/
|
||||||
|
**/CubeMX_Config/MDK-ARM/
|
||||||
|
@ -123,7 +123,7 @@ Based on [STM32F103 BluePill](https://github.com/RT-Thread/rt-thread/tree/master
|
|||||||
## Simulator
|
## Simulator
|
||||||
|
|
||||||
RT-Thread BSP can be compiled directly and downloaded to the corresponding development board for use. In addition, RT-Thread also provides qemu-vexpress-a9 BSP, which can be used without hardware platform. See the getting started guide below for details. Getting Started of QEMU with Env:
|
RT-Thread BSP can be compiled directly and downloaded to the corresponding development board for use. In addition, RT-Thread also provides qemu-vexpress-a9 BSP, which can be used without hardware platform. See the getting started guide below for details. Getting Started of QEMU with Env:
|
||||||
[Windows](documentation/quick-start/quick_start_qemu/quick_start_qemu.md) | [Linux Ubuntu](documentation/quick-start/quick_start_qemu/quick_start_qemu_linux.md) | [Mac OS](documentation/quick-start/quick_start_qemu/quick_start_qemu_macos.md)
|
[Windows](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_windows.md) | [Linux Ubuntu](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_linux.md) | [Mac OS](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_macos.md)
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ Basierend auf [STM32F103 BluePill](https://github.com/RT-Thread/rt-thread/tree/m
|
|||||||
## Simulator
|
## Simulator
|
||||||
|
|
||||||
Das RT-Thread BSP kann direkt kompiliert und zur Verwendung auf das entsprechende Entwicklungsboard heruntergeladen werden. Darüber hinaus bietet RT-Thread auch das qemu-vexpress-a9 BSP, das ohne Hardware-Plattform verwendet werden kann. Weitere Informationen finden Sie in der Anleitung für die ersten Schritte unten.
|
Das RT-Thread BSP kann direkt kompiliert und zur Verwendung auf das entsprechende Entwicklungsboard heruntergeladen werden. Darüber hinaus bietet RT-Thread auch das qemu-vexpress-a9 BSP, das ohne Hardware-Plattform verwendet werden kann. Weitere Informationen finden Sie in der Anleitung für die ersten Schritte unten.
|
||||||
[Windows](documentation/quick-start/quick_start_qemu/quick_start_qemu.md) | [Linux Ubuntu](documentation/quick-start/quick_start_qemu/quick_start_qemu_linux.md) | [Mac OS](documentation/quick-start/quick_start_qemu/quick_start_qemu_macos.md)
|
[Windows](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_windows.md) | [Linux Ubuntu](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_linux.md) | [Mac OS](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_macos.md)
|
||||||
|
|
||||||
# Lizenz
|
# Lizenz
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ Basado en [STM32F103 BluePill](https://github.com/RT-Thread/rt-thread/tree/maste
|
|||||||
|
|
||||||
## Simulator
|
## Simulator
|
||||||
|
|
||||||
El BSP de RT-Thread puede compilarse directamente y descargarse en la placa de desarrollo correspondiente para su uso. Además, RT-Thread también proporciona el BSP qemu-vexpress-a9, que puede utilizarse sin plataforma de hardware. Consulte la guía de inicio más abajo para más detalles. [Windows](documentation/quick-start/quick_start_qemu/quick_start_qemu.md) | [Linux Ubuntu](documentation/quick-start/quick_start_qemu/quick_start_qemu_linux.md) | [Mac OS](documentation/quick-start/quick_start_qemu/quick_start_qemu_macos.md)
|
El BSP de RT-Thread puede compilarse directamente y descargarse en la placa de desarrollo correspondiente para su uso. Además, RT-Thread también proporciona el BSP qemu-vexpress-a9, que puede utilizarse sin plataforma de hardware. Consulte la guía de inicio más abajo para más detalles. [Windows](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_windows.md) | [Linux Ubuntu](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_linux.md) | [Mac OS](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_macos.md)
|
||||||
|
|
||||||
# Licencia
|
# Licencia
|
||||||
|
|
||||||
|
@ -124,9 +124,9 @@ RT-Thread Studio演示:
|
|||||||
|
|
||||||
RT-Thread BSP可以直接编译并下载到相应的开发板使用。此外,RT-Thread还提供 qemu-vexpress-a9 BSP,无需硬件平台即可使用。有关详细信息,请参阅下面的入门指南。
|
RT-Thread BSP可以直接编译并下载到相应的开发板使用。此外,RT-Thread还提供 qemu-vexpress-a9 BSP,无需硬件平台即可使用。有关详细信息,请参阅下面的入门指南。
|
||||||
|
|
||||||
[QEMU 入门指南(Windows)](documentation/quick-start/quick_start_qemu/quick_start_qemu.md)
|
[QEMU 入门指南(Windows)](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_windows.md)
|
||||||
|
|
||||||
[QEMU 入门指南(Ubuntu)](documentation/quick-start/quick_start_qemu/quick_start_qemu_linux.md)
|
[QEMU 入门指南(Ubuntu)](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_linux.md)
|
||||||
|
|
||||||
|
|
||||||
## 文档
|
## 文档
|
||||||
|
@ -169,20 +169,25 @@ if RT_USING_DFS_V1
|
|||||||
default n
|
default n
|
||||||
endif
|
endif
|
||||||
|
|
||||||
config RT_USING_DFS_ROMFS
|
menuconfig RT_USING_DFS_ROMFS
|
||||||
bool "Enable ReadOnly file system on flash"
|
bool "Enable ReadOnly file system on flash"
|
||||||
default n
|
default n
|
||||||
|
|
||||||
config RT_USING_DFS_ROMFS_USER_ROOT
|
if RT_USING_DFS_ROMFS
|
||||||
bool "Use user's romfs root"
|
config RT_USING_DFS_ROMFS_USER_ROOT
|
||||||
depends on RT_USING_DFS_ROMFS
|
bool "Use user's romfs root"
|
||||||
default n
|
depends on RT_USING_DFS_V1
|
||||||
|
default n
|
||||||
|
endif
|
||||||
|
|
||||||
if RT_USING_SMART
|
if RT_USING_SMART
|
||||||
config RT_USING_DFS_PTYFS
|
config RT_USING_DFS_PTYFS
|
||||||
bool "Using Pseudo-Teletype Filesystem (UNIX98 PTY)"
|
bool "Using Pseudo-Teletype Filesystem (UNIX98 PTY)"
|
||||||
depends on RT_USING_DFS_DEVFS
|
depends on RT_USING_DFS_DEVFS
|
||||||
default y
|
default y
|
||||||
|
config RT_USING_DFS_PROCFS
|
||||||
|
bool "Enable proc file system"
|
||||||
|
default n
|
||||||
endif
|
endif
|
||||||
|
|
||||||
config RT_USING_DFS_CROMFS
|
config RT_USING_DFS_CROMFS
|
||||||
|
@ -77,6 +77,7 @@ static int dfs_devfs_open(struct dfs_file *file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rt_free(device_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <dfs_dentry.h>
|
#include <dfs_dentry.h>
|
||||||
#include <dfs_file.h>
|
#include <dfs_file.h>
|
||||||
#include <dfs_mnt.h>
|
#include <dfs_mnt.h>
|
||||||
|
#include <dfs_vfs.h>
|
||||||
#include <devfs.h>
|
#include <devfs.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@ -34,10 +35,9 @@ struct devtmpfs_file
|
|||||||
char name[DIRENT_NAME_MAX]; /* file name */
|
char name[DIRENT_NAME_MAX]; /* file name */
|
||||||
|
|
||||||
rt_uint32_t type; /* file type */
|
rt_uint32_t type; /* file type */
|
||||||
rt_list_t subdirs; /* file subdir list */
|
struct dfs_vfs_node node; /* file node in the devtmpfs */
|
||||||
rt_list_t sibling; /* file sibling list */
|
|
||||||
|
|
||||||
struct devtmpfs_sb *sb; /* superblock ptr */
|
struct devtmpfs_sb *sb; /* superblock ptr */
|
||||||
|
|
||||||
rt_uint32_t mode;
|
rt_uint32_t mode;
|
||||||
char *link;
|
char *link;
|
||||||
@ -48,7 +48,6 @@ struct devtmpfs_sb
|
|||||||
rt_uint32_t magic; /* TMPFS_MAGIC */
|
rt_uint32_t magic; /* TMPFS_MAGIC */
|
||||||
struct devtmpfs_file root; /* root dir */
|
struct devtmpfs_file root; /* root dir */
|
||||||
rt_size_t df_size; /* df size */
|
rt_size_t df_size; /* df size */
|
||||||
rt_list_t sibling; /* sb sibling list */
|
|
||||||
struct rt_spinlock lock; /* tmpfs lock */
|
struct rt_spinlock lock; /* tmpfs lock */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -111,15 +110,13 @@ static int _get_subdir(const char *path, char *name)
|
|||||||
#if 0
|
#if 0
|
||||||
static int _free_subdir(struct devtmpfs_file *dfile)
|
static int _free_subdir(struct devtmpfs_file *dfile)
|
||||||
{
|
{
|
||||||
struct devtmpfs_file *file;
|
struct devtmpfs_file *file, *tmp;
|
||||||
rt_list_t *list, *temp_list;
|
|
||||||
struct devtmpfs_sb *superblock;
|
struct devtmpfs_sb *superblock;
|
||||||
|
|
||||||
RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
|
RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
|
||||||
|
|
||||||
rt_list_for_each_safe(list, temp_list, &dfile->subdirs)
|
dfs_vfs_for_each_subnode(file, tmp, dfile, node)
|
||||||
{
|
{
|
||||||
file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
|
||||||
if (file->type == TMPFS_TYPE_DIR)
|
if (file->type == TMPFS_TYPE_DIR)
|
||||||
{
|
{
|
||||||
_free_subdir(file);
|
_free_subdir(file);
|
||||||
@ -134,7 +131,7 @@ static int _free_subdir(struct devtmpfs_file *dfile)
|
|||||||
RT_ASSERT(superblock);
|
RT_ASSERT(superblock);
|
||||||
|
|
||||||
rt_spin_lock(&superblock->lock);
|
rt_spin_lock(&superblock->lock);
|
||||||
rt_list_remove(&(file->sibling));
|
dfs_vfs_remove_node(&file->node);
|
||||||
rt_spin_unlock(&superblock->lock);
|
rt_spin_unlock(&superblock->lock);
|
||||||
|
|
||||||
rt_free(file);
|
rt_free(file);
|
||||||
@ -152,14 +149,12 @@ static int devtmpfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void
|
|||||||
{
|
{
|
||||||
superblock->df_size = sizeof(struct devtmpfs_sb);
|
superblock->df_size = sizeof(struct devtmpfs_sb);
|
||||||
superblock->magic = TMPFS_MAGIC;
|
superblock->magic = TMPFS_MAGIC;
|
||||||
rt_list_init(&superblock->sibling);
|
|
||||||
|
|
||||||
superblock->root.name[0] = '/';
|
superblock->root.name[0] = '/';
|
||||||
superblock->root.sb = superblock;
|
superblock->root.sb = superblock;
|
||||||
superblock->root.type = TMPFS_TYPE_DIR;
|
superblock->root.type = TMPFS_TYPE_DIR;
|
||||||
superblock->root.mode = S_IFDIR | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH);
|
superblock->root.mode = S_IFDIR | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH);
|
||||||
rt_list_init(&superblock->root.sibling);
|
dfs_vfs_init_node(&superblock->root.node);
|
||||||
rt_list_init(&superblock->root.subdirs);
|
|
||||||
|
|
||||||
rt_spin_lock_init(&superblock->lock);
|
rt_spin_lock_init(&superblock->lock);
|
||||||
|
|
||||||
@ -193,8 +188,7 @@ static struct devtmpfs_file *devtmpfs_file_lookup(struct devtmpfs_sb *superblock
|
|||||||
{
|
{
|
||||||
const char *subpath, *curpath, *filename = RT_NULL;
|
const char *subpath, *curpath, *filename = RT_NULL;
|
||||||
char subdir_name[DIRENT_NAME_MAX];
|
char subdir_name[DIRENT_NAME_MAX];
|
||||||
struct devtmpfs_file *file, *curfile;
|
struct devtmpfs_file *file, *curfile, *tmp;
|
||||||
rt_list_t *list;
|
|
||||||
|
|
||||||
subpath = path;
|
subpath = path;
|
||||||
while (*subpath == '/' && *subpath)
|
while (*subpath == '/' && *subpath)
|
||||||
@ -222,9 +216,8 @@ find_subpath:
|
|||||||
|
|
||||||
rt_spin_lock(&superblock->lock);
|
rt_spin_lock(&superblock->lock);
|
||||||
|
|
||||||
rt_list_for_each(list, &curfile->subdirs)
|
dfs_vfs_for_each_subnode(file, tmp, curfile, node)
|
||||||
{
|
{
|
||||||
file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
|
||||||
if (filename) /* find file */
|
if (filename) /* find file */
|
||||||
{
|
{
|
||||||
if (rt_strcmp(file->name, filename) == 0)
|
if (rt_strcmp(file->name, filename) == 0)
|
||||||
@ -293,7 +286,9 @@ static int devtmpfs_stat(struct dfs_dentry *dentry, struct stat *st)
|
|||||||
|
|
||||||
static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
|
static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
|
||||||
{
|
{
|
||||||
struct devtmpfs_file *d_file;
|
rt_size_t index, end;
|
||||||
|
struct dirent *d;
|
||||||
|
struct devtmpfs_file *d_file, *n_file = RT_NULL, *tmp;
|
||||||
struct devtmpfs_sb *superblock;
|
struct devtmpfs_sb *superblock;
|
||||||
|
|
||||||
RT_ASSERT(file);
|
RT_ASSERT(file);
|
||||||
@ -306,11 +301,6 @@ static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_
|
|||||||
d_file = devtmpfs_file_lookup(superblock, file->dentry->pathname);
|
d_file = devtmpfs_file_lookup(superblock, file->dentry->pathname);
|
||||||
if (d_file)
|
if (d_file)
|
||||||
{
|
{
|
||||||
rt_size_t index, end;
|
|
||||||
struct dirent *d;
|
|
||||||
struct devtmpfs_file *n_file;
|
|
||||||
rt_list_t *list;
|
|
||||||
|
|
||||||
/* make integer count */
|
/* make integer count */
|
||||||
count = (count / sizeof(struct dirent));
|
count = (count / sizeof(struct dirent));
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
@ -322,12 +312,10 @@ static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_
|
|||||||
index = 0;
|
index = 0;
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
rt_list_for_each(list, &d_file->subdirs)
|
dfs_vfs_for_each_subnode(n_file, tmp, d_file, node)
|
||||||
{
|
{
|
||||||
if (index >= (rt_size_t)file->fpos)
|
if (index >= (rt_size_t)file->fpos)
|
||||||
{
|
{
|
||||||
n_file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
|
||||||
|
|
||||||
d = dirp + count;
|
d = dirp + count;
|
||||||
if (n_file->type == TMPFS_TYPE_FILE)
|
if (n_file->type == TMPFS_TYPE_FILE)
|
||||||
{
|
{
|
||||||
@ -378,8 +366,7 @@ static int devtmpfs_symlink(struct dfs_dentry *parent_dentry, const char *target
|
|||||||
|
|
||||||
strncpy(l_file->name, linkpath, DIRENT_NAME_MAX - 1);
|
strncpy(l_file->name, linkpath, DIRENT_NAME_MAX - 1);
|
||||||
|
|
||||||
rt_list_init(&(l_file->subdirs));
|
dfs_vfs_init_node(&l_file->node);
|
||||||
rt_list_init(&(l_file->sibling));
|
|
||||||
l_file->sb = superblock;
|
l_file->sb = superblock;
|
||||||
l_file->type = TMPFS_TYPE_FILE;
|
l_file->type = TMPFS_TYPE_FILE;
|
||||||
l_file->mode = p_file->mode;
|
l_file->mode = p_file->mode;
|
||||||
@ -388,7 +375,7 @@ static int devtmpfs_symlink(struct dfs_dentry *parent_dentry, const char *target
|
|||||||
l_file->link = rt_strdup(target);
|
l_file->link = rt_strdup(target);
|
||||||
|
|
||||||
rt_spin_lock(&superblock->lock);
|
rt_spin_lock(&superblock->lock);
|
||||||
rt_list_insert_after(&(p_file->subdirs), &(l_file->sibling));
|
dfs_vfs_append_node(&p_file->node, &l_file->node);
|
||||||
rt_spin_unlock(&superblock->lock);
|
rt_spin_unlock(&superblock->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,7 +447,7 @@ static int devtmpfs_unlink(struct dfs_dentry *dentry)
|
|||||||
}
|
}
|
||||||
|
|
||||||
rt_spin_lock(&superblock->lock);
|
rt_spin_lock(&superblock->lock);
|
||||||
rt_list_remove(&(d_file->sibling));
|
dfs_vfs_remove_node(&d_file->node);
|
||||||
rt_spin_unlock(&superblock->lock);
|
rt_spin_unlock(&superblock->lock);
|
||||||
|
|
||||||
rt_free(d_file);
|
rt_free(d_file);
|
||||||
@ -537,8 +524,7 @@ static struct dfs_vnode *devtmpfs_create_vnode(struct dfs_dentry *dentry, int ty
|
|||||||
|
|
||||||
strncpy(d_file->name, file_name, DIRENT_NAME_MAX);
|
strncpy(d_file->name, file_name, DIRENT_NAME_MAX);
|
||||||
|
|
||||||
rt_list_init(&(d_file->subdirs));
|
dfs_vfs_init_node(&d_file->node);
|
||||||
rt_list_init(&(d_file->sibling));
|
|
||||||
d_file->sb = superblock;
|
d_file->sb = superblock;
|
||||||
|
|
||||||
vnode->nlink = 1;
|
vnode->nlink = 1;
|
||||||
@ -563,7 +549,7 @@ static struct dfs_vnode *devtmpfs_create_vnode(struct dfs_dentry *dentry, int ty
|
|||||||
d_file->mode = vnode->mode;
|
d_file->mode = vnode->mode;
|
||||||
|
|
||||||
rt_spin_lock(&superblock->lock);
|
rt_spin_lock(&superblock->lock);
|
||||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
dfs_vfs_append_node(&p_file->node, &d_file->node);
|
||||||
rt_spin_unlock(&superblock->lock);
|
rt_spin_unlock(&superblock->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,166 @@
|
|||||||
|
# 进程文件系统 (procfs)
|
||||||
|
|
||||||
|
## 数据结构
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct proc_dentry
|
||||||
|
{
|
||||||
|
rt_uint32_t mode;
|
||||||
|
rt_atomic_t ref_count;
|
||||||
|
|
||||||
|
struct proc_dentry *parent;
|
||||||
|
struct dfs_vfs_node node;
|
||||||
|
|
||||||
|
const struct dfs_file_ops *fops;
|
||||||
|
const struct proc_ops *ops;
|
||||||
|
|
||||||
|
char *name;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```log
|
||||||
|
root { mode: S_IFDIR, ref_count: 1, parent: root, name: /, child->next: file1->node }
|
||||||
|
|
|
||||||
|
|—— file1 { mode: S_IFREG, ref_count: 1, parent: root, name: file1, node->next: link1->node }
|
||||||
|
|—— link1 { mode: S_IFLNK, ref_count: 1, parent: root, name: link1, data: fullpath, node->next: dir1->node }
|
||||||
|
|—— dir1 { mode: S_IFDIR, ref_count: 1, parent: root, name: dir1, node->next: file3->node, child->next: file2->node }
|
||||||
|
| |
|
||||||
|
| |—— dir2 { mode: S_IFDIR, ref_count: 1, parent: dir1, name: dir2, node->next: link2->node }
|
||||||
|
| |—— link2 { mode: S_IFLNK, ref_count: 1, parent: dir1, name: link2, data: fullpath, node->next: file2->node }
|
||||||
|
| |—— file2 { mode: S_IFREG, ref_count: 1, parent: dir1, name: file2 }
|
||||||
|
|
|
||||||
|
|—— file3 { mode: S_IFREG, ref_count: 1, parent: root, name: file3 }
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 介绍
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct proc_dentry *dfs_proc_find(const char *name);
|
||||||
|
|
||||||
|
struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||||
|
const struct dfs_file_ops *fops, void *data);
|
||||||
|
struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent);
|
||||||
|
struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent);
|
||||||
|
|
||||||
|
struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||||
|
const struct dfs_file_ops *fops, void *data);
|
||||||
|
|
||||||
|
struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest);
|
||||||
|
|
||||||
|
struct proc_dentry *proc_acquire(struct proc_dentry *dentry);
|
||||||
|
void proc_release(struct proc_dentry *dentry);
|
||||||
|
|
||||||
|
void proc_remove(struct proc_dentry *dentry);
|
||||||
|
```
|
||||||
|
|
||||||
|
- dfs_proc_find
|
||||||
|
|
||||||
|
查找指定节点,并返回节点数据指针
|
||||||
|
|
||||||
|
| 入参 | 说明 |
|
||||||
|
| ---- | ---------------------------------------------------- |
|
||||||
|
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2” |
|
||||||
|
|
||||||
|
- proc_mkdir_data
|
||||||
|
|
||||||
|
创建一个目录,并返回节点数据指针
|
||||||
|
|
||||||
|
| 入参 | 说明 |
|
||||||
|
| ------ | ------------------------------------------------------------ |
|
||||||
|
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
|
||||||
|
| mode | 权限配置 |
|
||||||
|
| parent | 指定创建目录的起始节点 |
|
||||||
|
| fops | 文件操作接口配置 |
|
||||||
|
| data | 私有数据 |
|
||||||
|
|
||||||
|
- proc_mkdir_mode
|
||||||
|
|
||||||
|
创建一个目录,并返回节点数据指针
|
||||||
|
|
||||||
|
| 入参 | 说明 |
|
||||||
|
| ------ | ------------------------------------------------------------ |
|
||||||
|
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
|
||||||
|
| mode | 权限配置 |
|
||||||
|
| parent | 指定创建目录的起始节点 |
|
||||||
|
|
||||||
|
- proc_mkdir
|
||||||
|
|
||||||
|
创建一个目录,并返回节点数据指针
|
||||||
|
|
||||||
|
| 入参 | 说明 |
|
||||||
|
| ---- | ------------------------------------------------------------ |
|
||||||
|
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
|
||||||
|
| mode | 权限配置 |
|
||||||
|
|
||||||
|
- proc_create_data
|
||||||
|
|
||||||
|
创建一个文件,并返回节点数据指针
|
||||||
|
|
||||||
|
| 入参 | 说明 |
|
||||||
|
| ------ | ------------------------------------------------------------ |
|
||||||
|
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
|
||||||
|
| mode | 权限配置 |
|
||||||
|
| parent | 指定创建文件的起始节点 |
|
||||||
|
| fops | 文件操作接口配置 |
|
||||||
|
| data | 私有数据 |
|
||||||
|
|
||||||
|
- proc_symlink
|
||||||
|
|
||||||
|
创建一个符号链接,并返回节点数据指针
|
||||||
|
|
||||||
|
| 入参 | 说明 |
|
||||||
|
| ------ | ------------------------------------------------------------ |
|
||||||
|
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
|
||||||
|
| parent | 指定创建文件的起始节点 |
|
||||||
|
| dest | 链接的目标文件完整路径 |
|
||||||
|
|
||||||
|
- proc_acquire
|
||||||
|
|
||||||
|
引用一个节点,并返回节点数据指针
|
||||||
|
|
||||||
|
| 入参 | 说明 |
|
||||||
|
| ------ | -------------- |
|
||||||
|
| dentry | 需要引用的节点 |
|
||||||
|
|
||||||
|
- proc_release
|
||||||
|
|
||||||
|
释放一个节点
|
||||||
|
|
||||||
|
| 入参 | 说明 |
|
||||||
|
| ------ | -------------- |
|
||||||
|
| dentry | 需要释放的节点 |
|
||||||
|
|
||||||
|
- proc_remove
|
||||||
|
|
||||||
|
删除一个节点包含子节点
|
||||||
|
|
||||||
|
| 入参 | 说明 |
|
||||||
|
| ------ | -------------- |
|
||||||
|
| dentry | 需要删除的节点 |
|
||||||
|
|
||||||
|
## msh 调试命令
|
||||||
|
|
||||||
|
- proc_dump
|
||||||
|
|
||||||
|
遍历打印指定节点含子节点的信息(名称、引用计数),比如 `proc_dump /dir1` 或者 `proc_dump`
|
||||||
|
|
||||||
|
- proc_remove
|
||||||
|
|
||||||
|
删除指定节点含子节点,比如 `proc_remove /dir1` 或者 `proc_remove /file3`
|
||||||
|
|
||||||
|
- proc_symlink
|
||||||
|
|
||||||
|
创建一个符号链接,`proc_symlink /link3 /mnt`
|
||||||
|
|
||||||
|
- proc_echo
|
||||||
|
|
||||||
|
创建一个空文件,`proc_echo /file4`
|
||||||
|
|
||||||
|
- proc_mkdir
|
||||||
|
|
||||||
|
创建一个空目录,`proc_mkdir /dir3`
|
||||||
|
|
||||||
|
- proc_pid
|
||||||
|
|
||||||
|
创建一个 pid 目录,`proc_pid /101`
|
@ -0,0 +1,11 @@
|
|||||||
|
# RT-Thread building script for component
|
||||||
|
|
||||||
|
from building import *
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
src = Glob('*.c')
|
||||||
|
CPPPATH = [cwd]
|
||||||
|
|
||||||
|
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_PROCFS'], CPPPATH = CPPPATH)
|
||||||
|
|
||||||
|
Return('group')
|
733
rt-thread-no-bsp/components/dfs/dfs_v2/filesystems/procfs/proc.c
Normal file
733
rt-thread-no-bsp/components/dfs/dfs_v2/filesystems/procfs/proc.c
Normal file
@ -0,0 +1,733 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the root in the proc tree..
|
||||||
|
*/
|
||||||
|
static struct proc_dentry _proc_root = {
|
||||||
|
.mode = S_IFDIR | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH),
|
||||||
|
.ref_count = 1,
|
||||||
|
|
||||||
|
.parent = &_proc_root,
|
||||||
|
.node.sibling = RT_LIST_OBJECT_INIT(_proc_root.node.sibling),
|
||||||
|
.node.subnode = RT_LIST_OBJECT_INIT(_proc_root.node.subnode),
|
||||||
|
|
||||||
|
.fops = RT_NULL,
|
||||||
|
|
||||||
|
.name = "/",
|
||||||
|
.data = RT_NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int _proc_find(struct proc_dentry **parent, const char *name)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = RT_NULL, *tmp;
|
||||||
|
|
||||||
|
dfs_vfs_for_each_subnode(dentry, tmp, (*parent), node)
|
||||||
|
{
|
||||||
|
if (dentry == RT_NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rt_strcmp(dentry->name, name) == 0)
|
||||||
|
{
|
||||||
|
*parent = dentry;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proc_find(struct proc_dentry **parent, const char **name, rt_bool_t force_lookup)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
char *tmp = RT_NULL;
|
||||||
|
|
||||||
|
if (!(*parent))
|
||||||
|
{
|
||||||
|
*parent = &_proc_root;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = rt_strdup(*name);
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
char *begin = tmp, *end = RT_NULL;
|
||||||
|
if (*begin == '/')
|
||||||
|
{
|
||||||
|
begin++;
|
||||||
|
if (*begin == '\0')
|
||||||
|
{
|
||||||
|
rt_free(tmp);
|
||||||
|
*parent = proc_acquire(*parent);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
end = rt_strstr(begin, "/");
|
||||||
|
if (end)
|
||||||
|
{
|
||||||
|
*end = '\0';
|
||||||
|
ret = _proc_find(parent, begin);
|
||||||
|
if (ret < 0 || !S_ISDIR((*parent)->mode))
|
||||||
|
{
|
||||||
|
*parent = RT_NULL;
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
begin = end + 1;
|
||||||
|
}
|
||||||
|
else if (force_lookup)
|
||||||
|
{
|
||||||
|
ret = _proc_find(parent, begin);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
if ((*parent)->ops && (*parent)->ops->lookup)
|
||||||
|
{
|
||||||
|
*parent = (*parent)->ops->lookup(*parent, begin);
|
||||||
|
if (*parent == RT_NULL)
|
||||||
|
{
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*parent = RT_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*parent = proc_acquire(*parent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*parent = proc_acquire(*parent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*name = *name + (begin - tmp);
|
||||||
|
|
||||||
|
rt_free(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *single_start(struct dfs_seq_file *seq, off_t *index)
|
||||||
|
{
|
||||||
|
return NULL + (*index == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *single_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||||
|
{
|
||||||
|
++*index;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void single_stop(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proc_open(struct dfs_file *file)
|
||||||
|
{
|
||||||
|
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||||
|
|
||||||
|
if (entry->single_show)
|
||||||
|
{
|
||||||
|
struct dfs_seq_ops *seq_ops = (struct dfs_seq_ops *)rt_calloc(1, sizeof(struct dfs_seq_ops));
|
||||||
|
if (seq_ops)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
seq_ops->start = single_start;
|
||||||
|
seq_ops->next = single_next;
|
||||||
|
seq_ops->stop = single_stop;
|
||||||
|
seq_ops->show = entry->single_show;
|
||||||
|
|
||||||
|
ret = dfs_seq_open(file, seq_ops);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
rt_free(seq_ops);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dfs_seq_open(file, entry->seq_ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proc_close(struct dfs_file *file)
|
||||||
|
{
|
||||||
|
struct dfs_seq_file *seq = file->data;
|
||||||
|
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||||
|
|
||||||
|
if (seq && entry->single_show && seq->ops)
|
||||||
|
{
|
||||||
|
rt_free((void *)seq->ops);
|
||||||
|
seq->ops = RT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dfs_seq_release(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dfs_file_ops proc_file_ops = {
|
||||||
|
.open = proc_open,
|
||||||
|
.read = dfs_seq_read,
|
||||||
|
.lseek = dfs_seq_lseek,
|
||||||
|
.close = proc_close,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct proc_dentry *proc_create(struct proc_dentry **parent, const char *name, mode_t mode)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct proc_dentry *dentry = RT_NULL;
|
||||||
|
|
||||||
|
ret = proc_find(parent, &name, 0);
|
||||||
|
if (ret >= 0)
|
||||||
|
{
|
||||||
|
dentry = *parent;
|
||||||
|
ret = proc_find(&dentry, &name, 1);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
dentry = rt_calloc(1, sizeof(struct proc_dentry));
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->mode = mode;
|
||||||
|
dentry->ref_count = 1;
|
||||||
|
dentry->name = rt_strdup(name);
|
||||||
|
dfs_vfs_init_node(&dentry->node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
proc_release(dentry);
|
||||||
|
dentry = RT_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The dentry reference count is incremented by one
|
||||||
|
*
|
||||||
|
* @param dentry
|
||||||
|
*
|
||||||
|
* @return dentry
|
||||||
|
*/
|
||||||
|
struct proc_dentry *proc_acquire(struct proc_dentry *dentry)
|
||||||
|
{
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->ref_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The dentry reference count is minus one, or release
|
||||||
|
*
|
||||||
|
* @param dentry
|
||||||
|
*
|
||||||
|
* @return none
|
||||||
|
*/
|
||||||
|
void proc_release(struct proc_dentry *dentry)
|
||||||
|
{
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
if (dentry->ref_count == 1)
|
||||||
|
{
|
||||||
|
if (dentry->name)
|
||||||
|
{
|
||||||
|
rt_free(dentry->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISLNK(dentry->mode) && dentry->data)
|
||||||
|
{
|
||||||
|
rt_free(dentry->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_free(dentry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dentry->ref_count -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct proc_dentry *proc_register(struct proc_dentry *parent, struct proc_dentry *child)
|
||||||
|
{
|
||||||
|
child->parent = parent;
|
||||||
|
dfs_vfs_append_node(&parent->node, &child->node);
|
||||||
|
child->ref_count += 1;
|
||||||
|
child->pid = parent->pid;
|
||||||
|
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Make a dir
|
||||||
|
*
|
||||||
|
* @param name fullpath based on _proc_root or parent
|
||||||
|
* @param mode permission configuration
|
||||||
|
* @param parent can be empty
|
||||||
|
* @param fops
|
||||||
|
* @param data
|
||||||
|
*
|
||||||
|
* @return dentry
|
||||||
|
*/
|
||||||
|
struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||||
|
const struct dfs_file_ops *fops, void *data)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry, *_parent = parent;
|
||||||
|
|
||||||
|
if (mode == 0)
|
||||||
|
mode = (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH);
|
||||||
|
|
||||||
|
dentry = proc_create(&_parent, name, S_IFDIR | mode);
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->fops = fops;
|
||||||
|
dentry->data = data;
|
||||||
|
|
||||||
|
dentry = proc_register(_parent, dentry);
|
||||||
|
}
|
||||||
|
proc_release(_parent);
|
||||||
|
|
||||||
|
return dentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Make a dir
|
||||||
|
*
|
||||||
|
* @param name fullpath based on _proc_root or parent
|
||||||
|
* @param mode permission configuration
|
||||||
|
* @param parent can be empty
|
||||||
|
*
|
||||||
|
* @return dentry
|
||||||
|
*/
|
||||||
|
struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent)
|
||||||
|
{
|
||||||
|
return proc_mkdir_data(name, mode, parent, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Make a dir
|
||||||
|
*
|
||||||
|
* @param name fullpath based on _proc_root or parent
|
||||||
|
* @param parent can be empty
|
||||||
|
*
|
||||||
|
* @return dentry
|
||||||
|
*/
|
||||||
|
struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent)
|
||||||
|
{
|
||||||
|
return proc_mkdir_data(name, 0, parent, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct proc_dentry *proc_create_reg(const char *name, mode_t mode, struct proc_dentry **parent)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = RT_NULL;
|
||||||
|
|
||||||
|
if ((mode & S_IFMT) == 0)
|
||||||
|
mode |= S_IFREG;
|
||||||
|
if ((mode & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)) == 0)
|
||||||
|
mode |= S_IRUSR | S_IRGRP | S_IROTH;
|
||||||
|
|
||||||
|
if (!S_ISREG(mode))
|
||||||
|
{
|
||||||
|
*parent = RT_NULL;
|
||||||
|
return dentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return proc_create(parent, name, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Make a file
|
||||||
|
*
|
||||||
|
* @param name fullpath based on _proc_root or parent
|
||||||
|
* @param mode permission configuration
|
||||||
|
* @param parent can be empty
|
||||||
|
* @param fops
|
||||||
|
* @param data
|
||||||
|
*
|
||||||
|
* @return dentry
|
||||||
|
*/
|
||||||
|
struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||||
|
const struct dfs_file_ops *fops, void *data)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry, *_parent = parent;
|
||||||
|
|
||||||
|
dentry = proc_create_reg(name, mode, &_parent);
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->fops = fops ? fops : &proc_file_ops;
|
||||||
|
dentry->data = data;
|
||||||
|
|
||||||
|
dentry = proc_register(_parent, dentry);
|
||||||
|
}
|
||||||
|
proc_release(_parent);
|
||||||
|
|
||||||
|
return dentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Make a file
|
||||||
|
*
|
||||||
|
* @param name fullpath based on _proc_root or parent
|
||||||
|
* @param mode permission configuration
|
||||||
|
* @param parent can be empty
|
||||||
|
* @param show
|
||||||
|
* @param data
|
||||||
|
*
|
||||||
|
* @return dentry
|
||||||
|
*/
|
||||||
|
struct proc_dentry *proc_create_single_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||||
|
int (*show)(struct dfs_seq_file *, void *), void *data)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry, *_parent = parent;
|
||||||
|
|
||||||
|
dentry = proc_create_reg(name, mode, &_parent);
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->fops = &proc_file_ops;
|
||||||
|
dentry->single_show = show;
|
||||||
|
dentry->data = data;
|
||||||
|
|
||||||
|
dentry = proc_register(_parent, dentry);
|
||||||
|
}
|
||||||
|
proc_release(_parent);
|
||||||
|
|
||||||
|
return dentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Make a symlink
|
||||||
|
*
|
||||||
|
* @param name fullpath based on _proc_root or parent
|
||||||
|
* @param parent can be empty
|
||||||
|
* @param dest link file fullpath
|
||||||
|
*
|
||||||
|
* @return dentry
|
||||||
|
*/
|
||||||
|
struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry, *_parent = parent;
|
||||||
|
|
||||||
|
dentry = proc_create(&_parent, name, (S_IFLNK | (S_IRUSR | S_IRGRP | S_IROTH)
|
||||||
|
| (S_IWUSR | S_IWGRP | S_IWOTH) | (S_IXUSR | S_IXGRP | S_IXOTH)));
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->data = (void *)rt_strdup(dest);
|
||||||
|
if (dentry->data)
|
||||||
|
{
|
||||||
|
dentry = proc_register(_parent, dentry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
proc_release(dentry);
|
||||||
|
dentry = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proc_release(_parent);
|
||||||
|
|
||||||
|
return dentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_proc_subtree(struct proc_dentry *dentry)
|
||||||
|
{
|
||||||
|
struct proc_dentry *iter = RT_NULL, *iter_tmp, *tmp = RT_NULL;
|
||||||
|
|
||||||
|
dfs_vfs_for_each_subnode(iter, iter_tmp, dentry, node)
|
||||||
|
{
|
||||||
|
if (iter == RT_NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
proc_release(tmp);
|
||||||
|
tmp = RT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = iter;
|
||||||
|
|
||||||
|
if (S_ISDIR(dentry->mode))
|
||||||
|
{
|
||||||
|
remove_proc_subtree(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
proc_release(tmp);
|
||||||
|
tmp = RT_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief remove a dentry
|
||||||
|
*
|
||||||
|
* @param dentry
|
||||||
|
*
|
||||||
|
* @return none
|
||||||
|
*/
|
||||||
|
void proc_remove(struct proc_dentry *dentry)
|
||||||
|
{
|
||||||
|
if (dentry && dentry != &_proc_root)
|
||||||
|
{
|
||||||
|
if (S_ISDIR(dentry->mode))
|
||||||
|
{
|
||||||
|
remove_proc_subtree(dentry);
|
||||||
|
}
|
||||||
|
|
||||||
|
dfs_vfs_remove_node(&dentry->node);
|
||||||
|
proc_release(dentry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief find dentry exist
|
||||||
|
*
|
||||||
|
* @param name fullpath based on _proc_root
|
||||||
|
*
|
||||||
|
* @return dentry
|
||||||
|
*/
|
||||||
|
struct proc_dentry *dfs_proc_find(const char *name)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = RT_NULL;
|
||||||
|
|
||||||
|
proc_find(&dentry, &name, 1);
|
||||||
|
|
||||||
|
return dentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief remove a dentry on parent
|
||||||
|
*
|
||||||
|
* @param name fullpath based on parent
|
||||||
|
* @param parent
|
||||||
|
*
|
||||||
|
* @return none
|
||||||
|
*/
|
||||||
|
void proc_remove_dentry(const char *name, struct proc_dentry *parent)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = parent;
|
||||||
|
|
||||||
|
if (proc_find(&dentry, &name, 1) >= 0)
|
||||||
|
{
|
||||||
|
proc_remove(dentry);
|
||||||
|
proc_release(dentry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _COLOR_RED "\033[31m"
|
||||||
|
#define _COLOR_GREEN "\033[32m"
|
||||||
|
#define _COLOR_BLUE "\033[34m"
|
||||||
|
#define _COLOR_CYAN "\033[36m"
|
||||||
|
#define _COLOR_WHITE "\033[37m"
|
||||||
|
#define _COLOR_NORMAL "\033[0m"
|
||||||
|
|
||||||
|
static void dump_proc_subtree(struct proc_dentry *dentry, int tab)
|
||||||
|
{
|
||||||
|
struct proc_dentry *iter = RT_NULL, *tmp;
|
||||||
|
|
||||||
|
dfs_vfs_for_each_subnode(iter, tmp, dentry, node)
|
||||||
|
{
|
||||||
|
if (iter == RT_NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < tab; i ++)
|
||||||
|
{
|
||||||
|
rt_kprintf("%-4s", i + 1 >= tab ? "|-" : " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISDIR(iter->mode))
|
||||||
|
{
|
||||||
|
rt_kprintf(_COLOR_BLUE "%-20s" _COLOR_NORMAL " %d\n", iter->name, iter->ref_count);
|
||||||
|
dump_proc_subtree(iter, tab + 1);
|
||||||
|
}
|
||||||
|
else if (S_ISLNK(iter->mode))
|
||||||
|
{
|
||||||
|
rt_kprintf(_COLOR_CYAN "%-20s" _COLOR_NORMAL " %d\n", iter->name, iter->ref_count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_kprintf("%-20s %d\n", iter->name, iter->ref_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void proc_dump(struct proc_dentry *dentry)
|
||||||
|
{
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
if (S_ISDIR(dentry->mode))
|
||||||
|
{
|
||||||
|
rt_kprintf(_COLOR_BLUE "%-20s" _COLOR_NORMAL " %d\n", dentry->name, dentry->ref_count);
|
||||||
|
dump_proc_subtree(dentry, 1);
|
||||||
|
}
|
||||||
|
else if (S_ISLNK(dentry->mode))
|
||||||
|
{
|
||||||
|
rt_kprintf(_COLOR_CYAN "%-20s" _COLOR_NORMAL " %d\n", dentry->name, dentry->ref_count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_kprintf("%-20s %d\n", dentry->name, dentry->ref_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int msh_proc_dump(int argc, char** argv)
|
||||||
|
{
|
||||||
|
const char *name = argc > 1 ? argv[1] : "/";
|
||||||
|
struct proc_dentry *dentry = RT_NULL;
|
||||||
|
|
||||||
|
int ret = proc_find(&dentry, &name, 1);
|
||||||
|
if (ret >= 0)
|
||||||
|
{
|
||||||
|
proc_dump(dentry);
|
||||||
|
}
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
MSH_CMD_EXPORT_ALIAS(msh_proc_dump, proc_dump, proc dump);
|
||||||
|
|
||||||
|
static int msh_proc_remove(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (argc > 1)
|
||||||
|
{
|
||||||
|
const char *name = argv[1];
|
||||||
|
struct proc_dentry *dentry = RT_NULL;
|
||||||
|
|
||||||
|
int ret = proc_find(&dentry, &name, 1);
|
||||||
|
if (ret >= 0)
|
||||||
|
{
|
||||||
|
if (dentry != &_proc_root)
|
||||||
|
{
|
||||||
|
proc_remove(dentry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct proc_dentry *iter = RT_NULL, *iter_tmp, *tmp = RT_NULL;
|
||||||
|
|
||||||
|
dfs_vfs_for_each_subnode(iter, iter_tmp, dentry, node)
|
||||||
|
{
|
||||||
|
if (iter == RT_NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
proc_remove(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp)
|
||||||
|
{
|
||||||
|
proc_remove(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proc_release(dentry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_kprintf("proc_remove path\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
MSH_CMD_EXPORT_ALIAS(msh_proc_remove, proc_remove, proc remove);
|
||||||
|
|
||||||
|
static int msh_proc_symlink(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (argc > 2)
|
||||||
|
{
|
||||||
|
struct proc_dentry *entry = proc_symlink(argv[1], 0, argv[2]);
|
||||||
|
if (entry)
|
||||||
|
{
|
||||||
|
proc_release(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_kprintf("proc_symlink path dest\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
MSH_CMD_EXPORT_ALIAS(msh_proc_symlink, proc_symlink, proc symlink);
|
||||||
|
|
||||||
|
static int msh_proc_echo(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (argc > 1)
|
||||||
|
{
|
||||||
|
for(int i = 1; i <= argc - 1; i ++)
|
||||||
|
{
|
||||||
|
struct proc_dentry *entry = proc_create_data(argv[i], 0, 0, 0, 0);
|
||||||
|
if (entry)
|
||||||
|
{
|
||||||
|
proc_release(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_kprintf("proc_echo path\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
MSH_CMD_EXPORT_ALIAS(msh_proc_echo, proc_echo, proc echo);
|
||||||
|
|
||||||
|
static int msh_proc_mkdir(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (argc > 1)
|
||||||
|
{
|
||||||
|
for(int i = 1; i <= argc - 1; i ++)
|
||||||
|
{
|
||||||
|
struct proc_dentry *entry = proc_mkdir(argv[i], 0);
|
||||||
|
if (entry)
|
||||||
|
{
|
||||||
|
proc_release(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_kprintf("proc_mkdir path\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
MSH_CMD_EXPORT_ALIAS(msh_proc_mkdir, proc_mkdir, proc mkdir);
|
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PROC_H__
|
||||||
|
#define __PROC_H__
|
||||||
|
|
||||||
|
#include <dfs_file.h>
|
||||||
|
#include <dfs_seq_file.h>
|
||||||
|
#include <dfs_vfs.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct proc_dentry;
|
||||||
|
|
||||||
|
struct proc_ops
|
||||||
|
{
|
||||||
|
struct proc_dentry *(*lookup)(struct proc_dentry *parent, const char *name);
|
||||||
|
int (*readlink)(struct proc_dentry *dentry, char *buf, int len);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct proc_dentry
|
||||||
|
{
|
||||||
|
rt_uint32_t mode;
|
||||||
|
rt_atomic_t ref_count;
|
||||||
|
|
||||||
|
struct proc_dentry *parent;
|
||||||
|
struct dfs_vfs_node node;
|
||||||
|
|
||||||
|
const struct dfs_file_ops *fops;
|
||||||
|
const struct proc_ops *ops;
|
||||||
|
const struct dfs_seq_ops *seq_ops;
|
||||||
|
int (*single_show)(struct dfs_seq_file *seq, void *data);
|
||||||
|
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
char *name;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct proc_dentry *dfs_proc_find(const char *name);
|
||||||
|
|
||||||
|
struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||||
|
const struct dfs_file_ops *fops, void *data);
|
||||||
|
struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent);
|
||||||
|
struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent);
|
||||||
|
|
||||||
|
struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||||
|
const struct dfs_file_ops *fops, void *data);
|
||||||
|
struct proc_dentry *proc_create_single_data(const char *name, mode_t mode, struct proc_dentry *parent,
|
||||||
|
int (*show)(struct dfs_seq_file *, void *), void *data);
|
||||||
|
|
||||||
|
struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest);
|
||||||
|
|
||||||
|
struct proc_dentry *proc_acquire(struct proc_dentry *dentry);
|
||||||
|
void proc_release(struct proc_dentry *dentry);
|
||||||
|
|
||||||
|
void proc_remove(struct proc_dentry *dentry);
|
||||||
|
void proc_remove_dentry(const char *name, struct proc_dentry *parent);
|
||||||
|
|
||||||
|
int proc_pid(int pid);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
|
||||||
|
static char *__proc_cmdline = NULL;
|
||||||
|
|
||||||
|
int proc_cmdline_save(const char *cmdline)
|
||||||
|
{
|
||||||
|
if (__proc_cmdline)
|
||||||
|
{
|
||||||
|
free(__proc_cmdline);
|
||||||
|
__proc_cmdline = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
__proc_cmdline = strdup(cmdline);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int single_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
if (__proc_cmdline)
|
||||||
|
{
|
||||||
|
dfs_seq_puts(seq, __proc_cmdline);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int proc_cmdline_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = proc_create_single_data("cmdline", 0, NULL, single_show, NULL);
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_cmdline_init);
|
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
|
||||||
|
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||||
|
{
|
||||||
|
off_t i = *index; // seq->index
|
||||||
|
|
||||||
|
return NULL + (i == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
off_t i = *index + 1; // seq->index
|
||||||
|
|
||||||
|
*index = i;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
dfs_seq_puts(seq, "rt_weak const struct dfs_seq_ops *cpuinfo_get_seq_ops(void)\n--need your own function--\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dfs_seq_ops seq_ops = {
|
||||||
|
.start = seq_start,
|
||||||
|
.stop = seq_stop,
|
||||||
|
.next = seq_next,
|
||||||
|
.show = seq_show,
|
||||||
|
};
|
||||||
|
|
||||||
|
rt_weak const struct dfs_seq_ops *cpuinfo_get_seq_ops(void)
|
||||||
|
{
|
||||||
|
return &seq_ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proc_open(struct dfs_file *file)
|
||||||
|
{
|
||||||
|
return dfs_seq_open(file, cpuinfo_get_seq_ops());
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proc_close(struct dfs_file *file)
|
||||||
|
{
|
||||||
|
return dfs_seq_release(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dfs_file_ops file_ops = {
|
||||||
|
.open = proc_open,
|
||||||
|
.read = dfs_seq_read,
|
||||||
|
.lseek = dfs_seq_lseek,
|
||||||
|
.close = proc_close,
|
||||||
|
};
|
||||||
|
|
||||||
|
int proc_cpuinfo_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = proc_create_data("cpuinfo", 0, NULL, &file_ops, NULL);
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_cpuinfo_init);
|
@ -0,0 +1,307 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtthread.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define LIST_FIND_OBJ_NR 8
|
||||||
|
|
||||||
|
struct device_show
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
int size;
|
||||||
|
int len;
|
||||||
|
int index;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
rt_list_t *list;
|
||||||
|
rt_list_t **array;
|
||||||
|
rt_uint8_t type;
|
||||||
|
int nr; /* input: max nr, can't be 0 */
|
||||||
|
int nr_out; /* out: got nr */
|
||||||
|
} list_get_next_t;
|
||||||
|
|
||||||
|
static void list_find_init(list_get_next_t *p, rt_uint8_t type, rt_list_t **array, int nr)
|
||||||
|
{
|
||||||
|
struct rt_object_information *info;
|
||||||
|
rt_list_t *list;
|
||||||
|
|
||||||
|
info = rt_object_get_information((enum rt_object_class_type)type);
|
||||||
|
list = &info->object_list;
|
||||||
|
|
||||||
|
p->list = list;
|
||||||
|
p->type = type;
|
||||||
|
p->array = array;
|
||||||
|
p->nr = nr;
|
||||||
|
p->nr_out = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rt_list_t *list_get_next(rt_list_t *current, list_get_next_t *arg)
|
||||||
|
{
|
||||||
|
int first_flag = 0;
|
||||||
|
rt_base_t level;
|
||||||
|
rt_list_t *node, *list;
|
||||||
|
rt_list_t **array;
|
||||||
|
struct rt_object_information *info;
|
||||||
|
int nr;
|
||||||
|
|
||||||
|
arg->nr_out = 0;
|
||||||
|
|
||||||
|
if (!arg->nr || !arg->type)
|
||||||
|
{
|
||||||
|
return (rt_list_t *)RT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
list = arg->list;
|
||||||
|
info = rt_list_entry(list, struct rt_object_information, object_list);
|
||||||
|
|
||||||
|
if (!current) /* find first */
|
||||||
|
{
|
||||||
|
node = list;
|
||||||
|
first_flag = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
||||||
|
|
||||||
|
if (!first_flag)
|
||||||
|
{
|
||||||
|
struct rt_object *obj;
|
||||||
|
/* The node in the list? */
|
||||||
|
obj = rt_list_entry(node, struct rt_object, list);
|
||||||
|
if ((obj->type & ~RT_Object_Class_Static) != arg->type)
|
||||||
|
{
|
||||||
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||||
|
return (rt_list_t *)RT_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nr = 0;
|
||||||
|
array = arg->array;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
node = node->next;
|
||||||
|
|
||||||
|
if (node == list)
|
||||||
|
{
|
||||||
|
node = (rt_list_t *)RT_NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nr++;
|
||||||
|
*array++ = node;
|
||||||
|
if (nr == arg->nr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||||
|
arg->nr_out = nr;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *const device_type_str[RT_Device_Class_Unknown] =
|
||||||
|
{
|
||||||
|
"Character Device",
|
||||||
|
"Block Device",
|
||||||
|
"Network Interface",
|
||||||
|
"MTD Device",
|
||||||
|
"CAN Device",
|
||||||
|
"RTC",
|
||||||
|
"Sound Device",
|
||||||
|
"Graphic Device",
|
||||||
|
"I2C Bus",
|
||||||
|
"USB Slave Device",
|
||||||
|
"USB Host Bus",
|
||||||
|
"USB OTG Bus",
|
||||||
|
"SPI Bus",
|
||||||
|
"SPI Device",
|
||||||
|
"SDIO Bus",
|
||||||
|
"PM Pseudo Device",
|
||||||
|
"Pipe",
|
||||||
|
"Portal Device",
|
||||||
|
"Timer Device",
|
||||||
|
"Miscellaneous Device",
|
||||||
|
"Sensor Device",
|
||||||
|
"Touch Device",
|
||||||
|
"Phy Device",
|
||||||
|
"Security Device",
|
||||||
|
"WLAN Device",
|
||||||
|
"Pin Device",
|
||||||
|
"ADC Device",
|
||||||
|
"DAC Device",
|
||||||
|
"WDT Device",
|
||||||
|
"PWM Device",
|
||||||
|
"Bus Device",
|
||||||
|
};
|
||||||
|
|
||||||
|
static void save_info(struct device_show *dev, char *dev_name)
|
||||||
|
{
|
||||||
|
char tmp[256] = {0};
|
||||||
|
int len;
|
||||||
|
|
||||||
|
dev->index ++;
|
||||||
|
|
||||||
|
rt_snprintf(tmp, 256, "%d %s\n", dev->index, dev_name);
|
||||||
|
tmp[255] = 0;
|
||||||
|
|
||||||
|
len = rt_strlen(tmp);
|
||||||
|
if (dev->size > dev->len + len)
|
||||||
|
{
|
||||||
|
strcat(dev->buf, tmp);
|
||||||
|
dev->len += len;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dev->buf == RT_NULL)
|
||||||
|
{
|
||||||
|
dev->buf = rt_calloc(1, 4096);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dev->buf = rt_realloc(dev->buf, dev->size + 4096);
|
||||||
|
}
|
||||||
|
if (dev->buf)
|
||||||
|
{
|
||||||
|
dev->size += 4096;
|
||||||
|
strcat(dev->buf, tmp);
|
||||||
|
dev->len += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_device(struct device_show *dev)
|
||||||
|
{
|
||||||
|
rt_base_t level;
|
||||||
|
list_get_next_t find_arg;
|
||||||
|
struct rt_object_information *info;
|
||||||
|
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
||||||
|
rt_list_t *next = (rt_list_t *)RT_NULL;
|
||||||
|
|
||||||
|
list_find_init(&find_arg, RT_Object_Class_Device, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
||||||
|
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
next = list_get_next(next, &find_arg);
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < find_arg.nr_out; i++)
|
||||||
|
{
|
||||||
|
struct rt_object *obj;
|
||||||
|
struct rt_device *device;
|
||||||
|
|
||||||
|
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
||||||
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
||||||
|
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
||||||
|
{
|
||||||
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||||
|
|
||||||
|
device = (struct rt_device *)obj;
|
||||||
|
|
||||||
|
if (device->type < RT_Device_Class_Unknown)
|
||||||
|
{
|
||||||
|
save_info(dev + device->type, device->parent.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (next != (rt_list_t *)RT_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int show_info(struct dfs_seq_file *seq)
|
||||||
|
{
|
||||||
|
struct device_show _show[RT_Device_Class_Unknown] = {0};
|
||||||
|
|
||||||
|
list_device(_show);
|
||||||
|
|
||||||
|
for (int i = 0; i < RT_Device_Class_Unknown; i++)
|
||||||
|
{
|
||||||
|
if (_show[i].buf)
|
||||||
|
{
|
||||||
|
dfs_seq_printf(seq, "%s:\n", device_type_str[i]);
|
||||||
|
dfs_seq_write(seq, _show[i].buf, _show[i].len);
|
||||||
|
dfs_seq_putc(seq, '\n');
|
||||||
|
|
||||||
|
rt_free(_show[i].buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||||
|
{
|
||||||
|
off_t i = *index; // seq->index
|
||||||
|
|
||||||
|
return NULL + (i == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
off_t i = *index + 1; // seq->index
|
||||||
|
|
||||||
|
*index = i;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
show_info(seq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dfs_seq_ops seq_ops = {
|
||||||
|
.start = seq_start,
|
||||||
|
.stop = seq_stop,
|
||||||
|
.next = seq_next,
|
||||||
|
.show = seq_show,
|
||||||
|
};
|
||||||
|
|
||||||
|
int proc_devices_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = proc_create_data("devices", 0, NULL, NULL, NULL);
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->seq_ops = &seq_ops;
|
||||||
|
}
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_devices_init);
|
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
#include <dfs_fs.h>
|
||||||
|
|
||||||
|
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||||
|
{
|
||||||
|
off_t i = *index; // seq->index
|
||||||
|
struct dfs_filesystem_type *fs = dfs_filesystems();
|
||||||
|
|
||||||
|
if (fs)
|
||||||
|
{
|
||||||
|
while (i--)
|
||||||
|
{
|
||||||
|
fs = fs->next;
|
||||||
|
if (!fs)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
off_t i = *index + 1; // seq->index
|
||||||
|
struct dfs_filesystem_type *fs = (struct dfs_filesystem_type *)data;
|
||||||
|
|
||||||
|
*index = i;
|
||||||
|
|
||||||
|
return fs->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
struct dfs_filesystem_type *fs = (struct dfs_filesystem_type *)data;
|
||||||
|
|
||||||
|
dfs_seq_printf(seq, "%-9s%s\n", (fs->fs_ops->flags == FS_NEED_DEVICE) ? "" : "nodev", fs->fs_ops->name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dfs_seq_ops seq_ops = {
|
||||||
|
.start = seq_start,
|
||||||
|
.stop = seq_stop,
|
||||||
|
.next = seq_next,
|
||||||
|
.show = seq_show,
|
||||||
|
};
|
||||||
|
|
||||||
|
int proc_filesystems_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = proc_create_data("filesystems", 0, NULL, NULL, NULL);
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->seq_ops = &seq_ops;
|
||||||
|
}
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_filesystems_init);
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
#include <mm_page.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern void rt_memory_info(rt_size_t *total,
|
||||||
|
rt_size_t *used,
|
||||||
|
rt_size_t *max_used);
|
||||||
|
|
||||||
|
static int single_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
dfs_seq_printf(seq, "0.13 0.16 0.17 1/1035 380436\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int proc_loadavg_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = proc_create_single_data("loadavg", 0, NULL, single_show, NULL);
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_loadavg_init);
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
#include <mm_page.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern void rt_memory_info(rt_size_t *total,
|
||||||
|
rt_size_t *used,
|
||||||
|
rt_size_t *max_used);
|
||||||
|
|
||||||
|
static int single_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
rt_size_t total, used, max_used, freed;
|
||||||
|
rt_size_t total_sum = 0;
|
||||||
|
rt_size_t total_freed = 0;
|
||||||
|
|
||||||
|
rt_memory_info(&total, &used, &max_used);
|
||||||
|
total_sum = total_sum + total;
|
||||||
|
total_freed = total_freed + total - used;
|
||||||
|
|
||||||
|
dfs_seq_printf(seq, "%-16s%8d KB\n", "MemMaxUsed:", max_used / 1024);
|
||||||
|
dfs_seq_printf(seq, "%-16s%8d KB\n", "MemAvailable:", (total - used) / 1024);
|
||||||
|
dfs_seq_printf(seq, "%-16s%8d KB\n", "Cached:", 0);
|
||||||
|
dfs_seq_printf(seq, "%-16s%8d KB\n", "SReclaimable:", 0);
|
||||||
|
|
||||||
|
rt_page_get_info(&total, &freed);
|
||||||
|
total_sum = total_sum + total * RT_MM_PAGE_SIZE;
|
||||||
|
total_freed = total_freed + freed * RT_MM_PAGE_SIZE;
|
||||||
|
|
||||||
|
dfs_seq_printf(seq, "%-16s%8d KB\n", "MemTotal:", total_sum / 1024);
|
||||||
|
dfs_seq_printf(seq, "%-16s%8d KB\n", "MemFree:", total_freed / 1024);
|
||||||
|
dfs_seq_printf(seq, "%-16s%8d KB\n", "LowPageTotal:", total * RT_MM_PAGE_SIZE / 1024);
|
||||||
|
dfs_seq_printf(seq, "%-16s%8d KB\n", "lowPageFree:", freed * RT_MM_PAGE_SIZE/ 1024);
|
||||||
|
|
||||||
|
rt_page_high_get_info(&total, &freed);
|
||||||
|
|
||||||
|
dfs_seq_printf(seq, "%-16s%8d KB\n", "HighPageTotal:", total * RT_MM_PAGE_SIZE / 1024);
|
||||||
|
dfs_seq_printf(seq, "%-16s%8d KB\n", "HighPageFree:", freed * RT_MM_PAGE_SIZE / 1024);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int proc_meminfo_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = proc_create_single_data("meminfo", 0, NULL, single_show, NULL);
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_meminfo_init);
|
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
#include <dfs_mnt.h>
|
||||||
|
|
||||||
|
|
||||||
|
const char *mnt_flag(int flag)
|
||||||
|
{
|
||||||
|
/*if (flag & MNT_READONLY)
|
||||||
|
{
|
||||||
|
return "ro";
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return "rw";
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dfs_mnt* mnt_show(struct dfs_mnt *mnt, void *parameter)
|
||||||
|
{
|
||||||
|
struct dfs_seq_file *seq = (struct dfs_seq_file *)parameter;
|
||||||
|
|
||||||
|
if (mnt)
|
||||||
|
{
|
||||||
|
if (mnt->dev_id)
|
||||||
|
{
|
||||||
|
dfs_seq_printf(seq, "%s %s %s %s 0 0\n", mnt->dev_id->parent.name, mnt->fullpath,
|
||||||
|
mnt->fs_ops->name, mnt_flag(mnt->flags));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dfs_seq_printf(seq, "%s %s %s %s 0 0\n", mnt->fs_ops->name, mnt->fullpath,
|
||||||
|
mnt->fs_ops->name, mnt_flag(mnt->flags));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||||
|
{
|
||||||
|
off_t i = *index; // seq->index
|
||||||
|
|
||||||
|
return NULL + (i == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
off_t i = *index + 1; // seq->index
|
||||||
|
|
||||||
|
*index = i;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
dfs_mnt_foreach(mnt_show, seq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dfs_seq_ops seq_ops = {
|
||||||
|
.start = seq_start,
|
||||||
|
.stop = seq_stop,
|
||||||
|
.next = seq_next,
|
||||||
|
.show = seq_show,
|
||||||
|
};
|
||||||
|
|
||||||
|
int proc_mounts_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = proc_create_data("mounts", 0, NULL, NULL, NULL);
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->seq_ops = &seq_ops;
|
||||||
|
}
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_mounts_init);
|
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
|
||||||
|
#ifdef RT_USING_LWIP
|
||||||
|
#include "lwip/opt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LWIP_ROUTE
|
||||||
|
extern int inet_route_foreach(void (*func)(const char *name, uint32_t ip_addr, uint32_t netmask, void *parameter), void *parameter);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||||
|
{
|
||||||
|
off_t i = *index; // seq->index
|
||||||
|
|
||||||
|
return NULL + (i == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
off_t i = *index + 1; // seq->index
|
||||||
|
|
||||||
|
*index = i;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void route_show(const char *name, uint32_t ip_addr, uint32_t netmask, void *parameter)
|
||||||
|
{
|
||||||
|
struct dfs_seq_file *seq = (struct dfs_seq_file *)parameter;
|
||||||
|
/* "Iface\tDestination\tGateway "
|
||||||
|
"\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU"
|
||||||
|
"\tWindow\tIRTT"); */
|
||||||
|
/* "%63s%lx%lx%X%d%d%d%lx%d%d%d\n" */
|
||||||
|
dfs_seq_printf(seq, "%s ", name);
|
||||||
|
dfs_seq_printf(seq, "%lx ", ip_addr);
|
||||||
|
dfs_seq_printf(seq, "%lx ", 0);
|
||||||
|
dfs_seq_printf(seq, "%X ", 1);
|
||||||
|
dfs_seq_printf(seq, "%d ", 0);
|
||||||
|
dfs_seq_printf(seq, "%d ", 0);
|
||||||
|
dfs_seq_printf(seq, "%d ", 0);
|
||||||
|
dfs_seq_printf(seq, "%lx ", netmask);
|
||||||
|
dfs_seq_printf(seq, "%d ", 0);
|
||||||
|
dfs_seq_printf(seq, "%d ", 0);
|
||||||
|
dfs_seq_printf(seq, "%d\n", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
dfs_seq_printf(seq, "\n");
|
||||||
|
#if LWIP_ROUTE
|
||||||
|
inet_route_foreach(route_show, seq);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dfs_seq_ops seq_ops = {
|
||||||
|
.start = seq_start,
|
||||||
|
.stop = seq_stop,
|
||||||
|
.next = seq_next,
|
||||||
|
.show = seq_show,
|
||||||
|
};
|
||||||
|
|
||||||
|
int proc_net_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry;
|
||||||
|
|
||||||
|
dentry = proc_mkdir("net", NULL);
|
||||||
|
if (!dentry)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
dentry = proc_create_data("net/route", 0, NULL, NULL, NULL);
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->seq_ops = &seq_ops;
|
||||||
|
}
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_net_init);
|
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtthread.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define LIST_FIND_OBJ_NR 8
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
rt_list_t *list;
|
||||||
|
rt_list_t **array;
|
||||||
|
rt_uint8_t type;
|
||||||
|
int nr; /* input: max nr, can't be 0 */
|
||||||
|
int nr_out; /* out: got nr */
|
||||||
|
} list_get_next_t;
|
||||||
|
|
||||||
|
static void list_find_init(list_get_next_t *p, rt_uint8_t type, rt_list_t **array, int nr)
|
||||||
|
{
|
||||||
|
struct rt_object_information *info;
|
||||||
|
rt_list_t *list;
|
||||||
|
|
||||||
|
info = rt_object_get_information((enum rt_object_class_type)type);
|
||||||
|
list = &info->object_list;
|
||||||
|
|
||||||
|
p->list = list;
|
||||||
|
p->type = type;
|
||||||
|
p->array = array;
|
||||||
|
p->nr = nr;
|
||||||
|
p->nr_out = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rt_list_t *list_get_next(rt_list_t *current, list_get_next_t *arg)
|
||||||
|
{
|
||||||
|
int first_flag = 0;
|
||||||
|
rt_base_t level;
|
||||||
|
rt_list_t *node, *list;
|
||||||
|
rt_list_t **array;
|
||||||
|
struct rt_object_information *info;
|
||||||
|
int nr;
|
||||||
|
|
||||||
|
arg->nr_out = 0;
|
||||||
|
|
||||||
|
if (!arg->nr || !arg->type)
|
||||||
|
{
|
||||||
|
return (rt_list_t *)RT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
list = arg->list;
|
||||||
|
info = rt_list_entry(list, struct rt_object_information, object_list);
|
||||||
|
|
||||||
|
if (!current) /* find first */
|
||||||
|
{
|
||||||
|
node = list;
|
||||||
|
first_flag = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
||||||
|
|
||||||
|
if (!first_flag)
|
||||||
|
{
|
||||||
|
struct rt_object *obj;
|
||||||
|
/* The node in the list? */
|
||||||
|
obj = rt_list_entry(node, struct rt_object, list);
|
||||||
|
if ((obj->type & ~RT_Object_Class_Static) != arg->type)
|
||||||
|
{
|
||||||
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||||
|
return (rt_list_t *)RT_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nr = 0;
|
||||||
|
array = arg->array;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
node = node->next;
|
||||||
|
|
||||||
|
if (node == list)
|
||||||
|
{
|
||||||
|
node = (rt_list_t *)RT_NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nr++;
|
||||||
|
*array++ = node;
|
||||||
|
if (nr == arg->nr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||||
|
arg->nr_out = nr;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int show_info(struct dfs_seq_file *seq)
|
||||||
|
{
|
||||||
|
rt_base_t level;
|
||||||
|
list_get_next_t find_arg;
|
||||||
|
struct rt_object_information *info;
|
||||||
|
rt_list_t *obj_list[LIST_FIND_OBJ_NR];
|
||||||
|
rt_list_t *next = (rt_list_t *)RT_NULL;
|
||||||
|
|
||||||
|
list_find_init(&find_arg, RT_Object_Class_Device, obj_list, sizeof(obj_list) / sizeof(obj_list[0]));
|
||||||
|
info = rt_list_entry(find_arg.list, struct rt_object_information, object_list);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
next = list_get_next(next, &find_arg);
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < find_arg.nr_out; i++)
|
||||||
|
{
|
||||||
|
struct rt_object *obj;
|
||||||
|
struct rt_device *device;
|
||||||
|
|
||||||
|
obj = rt_list_entry(obj_list[i], struct rt_object, list);
|
||||||
|
level = rt_spin_lock_irqsave(&info->spinlock);
|
||||||
|
if ((obj->type & ~RT_Object_Class_Static) != find_arg.type)
|
||||||
|
{
|
||||||
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_spin_unlock_irqrestore(&info->spinlock, level);
|
||||||
|
|
||||||
|
device = (struct rt_device *)obj;
|
||||||
|
|
||||||
|
if (device->type == RT_Device_Class_Block)
|
||||||
|
{
|
||||||
|
struct rt_device_blk_geometry geometry = { 0 };
|
||||||
|
|
||||||
|
rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
|
||||||
|
|
||||||
|
dfs_seq_printf(seq, "%4d %7d %14llu %s\n", 0, 0,
|
||||||
|
geometry.sector_count, device->parent.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (next != (rt_list_t *)RT_NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||||
|
{
|
||||||
|
off_t i = *index; // seq->index
|
||||||
|
|
||||||
|
return NULL + (i == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
off_t i = *index + 1; // seq->index
|
||||||
|
|
||||||
|
*index = i;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
dfs_seq_puts(seq, "major minor #blocks name\n\n");
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
show_info(seq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dfs_seq_ops seq_ops = {
|
||||||
|
.start = seq_start,
|
||||||
|
.stop = seq_stop,
|
||||||
|
.next = seq_next,
|
||||||
|
.show = seq_show,
|
||||||
|
};
|
||||||
|
|
||||||
|
int proc_partitions_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = proc_create_data("partitions", 0, NULL, NULL, NULL);
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->seq_ops = &seq_ops;
|
||||||
|
}
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_partitions_init);
|
@ -0,0 +1,449 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
#define __RT_IPC_SOURCE__
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "lwp_internal.h"
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
#include "lwp_internal.h"
|
||||||
|
|
||||||
|
#if defined(RT_USING_SMART)
|
||||||
|
|
||||||
|
#include "lwp.h"
|
||||||
|
#include "lwp_pid.h"
|
||||||
|
#include <lwp_user_mm.h>
|
||||||
|
|
||||||
|
struct pid_dentry
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
mode_t mode;
|
||||||
|
const struct dfs_file_ops *fops;
|
||||||
|
const struct proc_ops *ops;
|
||||||
|
const struct dfs_seq_ops *seq_ops;
|
||||||
|
int (*single_show)(struct dfs_seq_file *seq, void *data);
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static char stat_transform(int __stat)
|
||||||
|
{
|
||||||
|
switch (__stat)
|
||||||
|
{
|
||||||
|
case RT_THREAD_RUNNING:
|
||||||
|
return 'R';
|
||||||
|
default:
|
||||||
|
return 'T';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stat_single_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data;
|
||||||
|
rt_list_t *list;
|
||||||
|
int mask = 0;
|
||||||
|
rt_thread_t thread;
|
||||||
|
rt_uint64_t user_time_lwp = 0;
|
||||||
|
rt_uint64_t system_time_lwp = 0;
|
||||||
|
int lwp_oncpu = RT_CPUS_NR;
|
||||||
|
int lwp_oncpu_ok = 0;
|
||||||
|
struct rt_lwp *lwp = RT_NULL;
|
||||||
|
char** argv = RT_NULL;
|
||||||
|
char *filename = RT_NULL;
|
||||||
|
char *dot = RT_NULL;
|
||||||
|
|
||||||
|
lwp_pid_lock_take();
|
||||||
|
|
||||||
|
lwp = lwp_from_pid_locked(dentry->pid);
|
||||||
|
argv = lwp_get_command_line_args(lwp);
|
||||||
|
|
||||||
|
if (lwp)
|
||||||
|
{
|
||||||
|
dfs_seq_printf(seq,"%d ",dentry->pid);
|
||||||
|
if (argv)
|
||||||
|
{
|
||||||
|
filename = strrchr(argv[0], '/');
|
||||||
|
dot = strchr(argv[0], '.');
|
||||||
|
|
||||||
|
if (filename != NULL)
|
||||||
|
{
|
||||||
|
filename++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filename = argv[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dot != NULL)
|
||||||
|
{
|
||||||
|
*dot = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filename != NULL)
|
||||||
|
{
|
||||||
|
dfs_seq_printf(seq,"(%s) ", filename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dfs_seq_printf(seq,"(%s) ", argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
lwp_free_command_line_args(argv);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dfs_seq_printf(seq,"(%s) ", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lwp->terminated)
|
||||||
|
{
|
||||||
|
dfs_seq_printf(seq,"%c ",'Z');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list = lwp->t_grp.next;
|
||||||
|
while (list != &lwp->t_grp)
|
||||||
|
{
|
||||||
|
thread = rt_list_entry(list, struct rt_thread, sibling);
|
||||||
|
user_time_lwp = user_time_lwp + thread->user_time;
|
||||||
|
system_time_lwp = system_time_lwp + thread->system_time;
|
||||||
|
|
||||||
|
#if RT_CPUS_NR > 1
|
||||||
|
#define ONCPU(thread) RT_SCHED_CTX(thread).oncpu
|
||||||
|
#else
|
||||||
|
#define ONCPU(thread) 0
|
||||||
|
#endif
|
||||||
|
if (lwp_oncpu_ok == 0)
|
||||||
|
{
|
||||||
|
lwp_oncpu = ONCPU(thread);
|
||||||
|
lwp_oncpu_ok = 1;
|
||||||
|
}
|
||||||
|
if (stat_transform(RT_SCHED_CTX(thread).stat) == 'R')
|
||||||
|
{
|
||||||
|
lwp_oncpu = ONCPU(thread);
|
||||||
|
mask = 1;
|
||||||
|
}
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask == 1)
|
||||||
|
{
|
||||||
|
dfs_seq_printf(seq,"%c ",'R');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dfs_seq_printf(seq,"%c ",'S');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lwp_pid_lock_release();
|
||||||
|
|
||||||
|
if (lwp->parent != NULL)
|
||||||
|
dfs_seq_printf(seq,"%d ",lwp->parent->pid);
|
||||||
|
else
|
||||||
|
dfs_seq_printf(seq,"0 ");
|
||||||
|
|
||||||
|
dfs_seq_printf(seq, "1 1 0 -1 4194560 48245 133976064 732 425574 ");
|
||||||
|
dfs_seq_printf(seq,"%llu ",user_time_lwp);//utime
|
||||||
|
dfs_seq_printf(seq,"%llu ",system_time_lwp);//stime
|
||||||
|
dfs_seq_printf(seq, "1204291 518742 20 0 1 0 50 ");
|
||||||
|
dfs_seq_printf(seq, "%d ",rt_aspace_count_vsz(lwp->aspace));//VSZ
|
||||||
|
dfs_seq_printf(seq, "1422 18446744073709551615 ");
|
||||||
|
dfs_seq_printf(seq, "1 1 0 0 0 0 671173123 4096 1260 0 0 0 17 ");
|
||||||
|
dfs_seq_printf(seq, "%d ", lwp_oncpu);//CPU
|
||||||
|
dfs_seq_printf(seq, "0 0 0 0 0 0 0 0 0 0 0 0 0");
|
||||||
|
dfs_seq_printf(seq,"\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lwp_pid_lock_release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmdline_single_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data;
|
||||||
|
struct rt_lwp *lwp;
|
||||||
|
char** argv;
|
||||||
|
|
||||||
|
lwp_pid_lock_take();
|
||||||
|
lwp = lwp_from_pid_locked(dentry->pid);
|
||||||
|
argv = lwp_get_command_line_args(lwp);
|
||||||
|
lwp_pid_lock_release();
|
||||||
|
|
||||||
|
if (argv)
|
||||||
|
{
|
||||||
|
for (int i = 0; argv[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
dfs_seq_printf(seq, "%s ", argv[i]);
|
||||||
|
}
|
||||||
|
dfs_seq_puts(seq, "\n");
|
||||||
|
|
||||||
|
lwp_free_command_line_args(argv);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dfs_seq_puts(seq, "error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct proc_dentry *proc_pid_fd_lookup(struct proc_dentry *parent, const char *name)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = RT_NULL;
|
||||||
|
char num[DIRENT_NAME_MAX];
|
||||||
|
struct rt_lwp *lwp;
|
||||||
|
struct dfs_fdtable *table;
|
||||||
|
|
||||||
|
lwp_pid_lock_take();
|
||||||
|
lwp = lwp_from_pid_locked(parent->pid);
|
||||||
|
table = lwp ? &lwp->fdt : RT_NULL;
|
||||||
|
lwp_pid_lock_release();
|
||||||
|
|
||||||
|
if (!table)
|
||||||
|
{
|
||||||
|
return RT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dfs_file_lock();
|
||||||
|
for (int i = 0; i < table->maxfd; i++)
|
||||||
|
{
|
||||||
|
struct dfs_file *file = table->fds[i];
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
rt_snprintf(num, DIRENT_NAME_MAX, "%d", i);
|
||||||
|
if (rt_strcmp(num, name) == 0)
|
||||||
|
{
|
||||||
|
dentry = rt_calloc(1, sizeof(struct proc_dentry));
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->mode = (S_IFLNK | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IWUSR | S_IWGRP | S_IWOTH) | (S_IXUSR | S_IXGRP | S_IXOTH));
|
||||||
|
dentry->ref_count = 1;
|
||||||
|
dentry->name = rt_strdup(name);
|
||||||
|
dentry->data = (void *)dfs_dentry_full_path(file->dentry);
|
||||||
|
|
||||||
|
if (dentry->data == RT_NULL)
|
||||||
|
{
|
||||||
|
//todo add vnode->data
|
||||||
|
if (file->vnode->type == FT_SOCKET)
|
||||||
|
dentry->data = (void *)rt_strdup("socket");
|
||||||
|
else if (file->vnode->type == FT_USER)
|
||||||
|
dentry->data = (void *)rt_strdup("user");
|
||||||
|
else if (file->vnode->type == FT_DEVICE)
|
||||||
|
dentry->data = (void *)rt_strdup("device");
|
||||||
|
else
|
||||||
|
dentry->data = (void *)rt_strdup("unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
dentry->pid = parent->pid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dfs_file_unlock();
|
||||||
|
|
||||||
|
return dentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
int proc_pid_fd_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
|
||||||
|
{
|
||||||
|
int ret = 0, index = 0;
|
||||||
|
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||||
|
struct rt_lwp *lwp;
|
||||||
|
struct dfs_fdtable *table;
|
||||||
|
|
||||||
|
lwp_pid_lock_take();
|
||||||
|
lwp = lwp_from_pid_locked(entry->pid);
|
||||||
|
LWP_LOCK(lwp);
|
||||||
|
table = lwp ? &lwp->fdt : RT_NULL;
|
||||||
|
|
||||||
|
if (!table->fds)
|
||||||
|
{
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
lwp_pid_lock_release();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = (count / sizeof(struct dirent));
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
lwp_pid_lock_release();
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dfs_file_lock();
|
||||||
|
for (int i = 0; i < table->maxfd; i++)
|
||||||
|
{
|
||||||
|
struct dfs_file *df = table->fds[i];
|
||||||
|
if (df)
|
||||||
|
{
|
||||||
|
if (index >= file->fpos)
|
||||||
|
{
|
||||||
|
struct dirent *d = dirp + index - file->fpos;
|
||||||
|
|
||||||
|
d->d_type = DT_SYMLINK;
|
||||||
|
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
||||||
|
rt_snprintf(d->d_name, DIRENT_NAME_MAX, "%d", i);
|
||||||
|
d->d_namlen = rt_strlen(d->d_name);
|
||||||
|
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
if (index - file->fpos >= count)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dfs_file_unlock();
|
||||||
|
LWP_UNLOCK(lwp);
|
||||||
|
lwp_pid_lock_release();
|
||||||
|
|
||||||
|
if (ret > 0)
|
||||||
|
{
|
||||||
|
file->fpos = index;
|
||||||
|
ret = ret * sizeof(struct dirent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct proc_ops proc_pid_fd_ops = {
|
||||||
|
.lookup = proc_pid_fd_lookup,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct dfs_file_ops proc_pid_fd_fops = {
|
||||||
|
.getdents = proc_pid_fd_getdents,
|
||||||
|
};
|
||||||
|
|
||||||
|
int proc_pid_exe_readlink(struct proc_dentry *dentry, char *buf, int len)
|
||||||
|
{
|
||||||
|
struct rt_lwp *lwp;
|
||||||
|
|
||||||
|
lwp = lwp_self();
|
||||||
|
len = rt_snprintf(buf, len, "%s", lwp ? lwp->exe_file : "null");
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct proc_ops proc_pid_exe_ops = {
|
||||||
|
.readlink = proc_pid_exe_readlink,
|
||||||
|
};
|
||||||
|
|
||||||
|
int proc_pid_cwd_readlink(struct proc_dentry *dentry, char *buf, int len)
|
||||||
|
{
|
||||||
|
struct rt_lwp *lwp;
|
||||||
|
|
||||||
|
lwp = lwp_self();
|
||||||
|
len = rt_snprintf(buf, len, "%s", lwp ? lwp->working_directory : "null");
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct proc_ops proc_pid_cwd_ops = {
|
||||||
|
.readlink = proc_pid_cwd_readlink,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct pid_dentry pid_dentry_base[] = {
|
||||||
|
{"cmdline", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, cmdline_single_show, 0},
|
||||||
|
{"cwd", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_cwd_ops, 0, 0},
|
||||||
|
{"exe", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_exe_ops, 0, 0},
|
||||||
|
{"fd", S_IFDIR | S_IRUSR | S_IXUSR, &proc_pid_fd_fops, &proc_pid_fd_ops, 0, 0, 0},
|
||||||
|
{"mounts", S_IFLNK | S_IRUSR | S_IXUSR, 0, 0, 0, 0, "/proc/mounts"},
|
||||||
|
{"stat", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, stat_single_show, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
int proc_pid(int pid)
|
||||||
|
{
|
||||||
|
char pid_str[64] = {0};
|
||||||
|
struct proc_dentry *dentry;
|
||||||
|
|
||||||
|
rt_snprintf(pid_str, 64, "%d", pid);
|
||||||
|
pid_str[63] = 0;
|
||||||
|
|
||||||
|
dentry = proc_mkdir(pid_str, 0);
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
struct proc_dentry *ent;
|
||||||
|
|
||||||
|
dentry->pid = pid;
|
||||||
|
for (int j = 0; j < sizeof(pid_dentry_base) / sizeof(struct pid_dentry); j++)
|
||||||
|
{
|
||||||
|
if (S_ISDIR(pid_dentry_base[j].mode))
|
||||||
|
{
|
||||||
|
ent = proc_mkdir_data(pid_dentry_base[j].name, pid_dentry_base[j].mode, dentry,
|
||||||
|
pid_dentry_base[j].fops, pid_dentry_base[j].data);
|
||||||
|
}
|
||||||
|
else if (S_ISLNK(pid_dentry_base[j].mode))
|
||||||
|
{
|
||||||
|
if (pid_dentry_base[j].data == RT_NULL)
|
||||||
|
{
|
||||||
|
pid_dentry_base[j].data = "NULL";
|
||||||
|
}
|
||||||
|
|
||||||
|
ent = proc_symlink(pid_dentry_base[j].name, dentry, pid_dentry_base[j].data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ent = proc_create_data(pid_dentry_base[j].name, pid_dentry_base[j].mode, dentry,
|
||||||
|
pid_dentry_base[j].fops, pid_dentry_base[j].data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ent)
|
||||||
|
{
|
||||||
|
if (pid_dentry_base[j].ops)
|
||||||
|
{
|
||||||
|
ent->ops = pid_dentry_base[j].ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid_dentry_base[j].seq_ops)
|
||||||
|
{
|
||||||
|
ent->seq_ops = pid_dentry_base[j].seq_ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid_dentry_base[j].single_show)
|
||||||
|
{
|
||||||
|
ent->single_show = pid_dentry_base[j].single_show;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc_release(ent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proc_release(dentry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int msh_proc_pid(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc > 1)
|
||||||
|
{
|
||||||
|
for (int i = 1; i <= argc - 1; i++)
|
||||||
|
{
|
||||||
|
proc_pid(atoi(argv[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
MSH_CMD_EXPORT_ALIAS(msh_proc_pid, proc_pid, proc pid);
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
|
||||||
|
#if defined(RT_USING_SMART)
|
||||||
|
|
||||||
|
#include <lwp.h>
|
||||||
|
|
||||||
|
|
||||||
|
int proc_self_readlink(struct proc_dentry *dentry, char *buf, int len)
|
||||||
|
{
|
||||||
|
struct rt_lwp *lwp = RT_NULL;
|
||||||
|
|
||||||
|
lwp = lwp_self();
|
||||||
|
if (lwp)
|
||||||
|
{
|
||||||
|
rt_snprintf(buf, len, "%d", lwp_to_pid(lwp));
|
||||||
|
buf[len - 1] = 0;
|
||||||
|
return rt_strlen(buf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_snprintf(buf, len, "null");
|
||||||
|
buf[len - 1] = 0;
|
||||||
|
return rt_strlen(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct proc_ops proc_pid_fd_ops = {
|
||||||
|
.readlink = proc_self_readlink,
|
||||||
|
};
|
||||||
|
|
||||||
|
int proc_self_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *ent;
|
||||||
|
|
||||||
|
ent = proc_symlink("self", NULL, "NULL");
|
||||||
|
if (ent)
|
||||||
|
{
|
||||||
|
ent->ops = &proc_pid_fd_ops;
|
||||||
|
}
|
||||||
|
proc_release(ent);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_self_init);
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
|
||||||
|
|
||||||
|
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||||
|
{
|
||||||
|
off_t i = *index; // seq->index
|
||||||
|
|
||||||
|
return NULL + (i == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
off_t i = *index + 1; // seq->index
|
||||||
|
|
||||||
|
*index = i;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
rt_cpu_t pcpu;
|
||||||
|
rt_uint64_t user_total = 0;
|
||||||
|
rt_uint64_t system_total = 0;
|
||||||
|
rt_uint64_t idle_total = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < RT_CPUS_NR; i++)
|
||||||
|
{
|
||||||
|
pcpu = rt_cpu_index(i);
|
||||||
|
user_total = user_total + pcpu->cpu_stat.user;
|
||||||
|
system_total = system_total + pcpu->cpu_stat.system;
|
||||||
|
idle_total = idle_total + pcpu->cpu_stat.idle;
|
||||||
|
}
|
||||||
|
dfs_seq_printf(seq, "cpu %llu 0 %llu %llu 0 0 0 0 0 0\n", user_total, system_total, idle_total);
|
||||||
|
|
||||||
|
for (i = 0; i < RT_CPUS_NR; i++)
|
||||||
|
{
|
||||||
|
pcpu = rt_cpu_index(i);
|
||||||
|
dfs_seq_printf(seq, "cpu%d ",i);
|
||||||
|
dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.user);//user
|
||||||
|
dfs_seq_printf(seq, "0 ");//nice
|
||||||
|
dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.system);//system
|
||||||
|
dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.idle);//idle
|
||||||
|
dfs_seq_printf(seq, "0 ");//iowait
|
||||||
|
dfs_seq_printf(seq, "0 ");//irq
|
||||||
|
dfs_seq_printf(seq, "0 ");//softirq
|
||||||
|
dfs_seq_printf(seq, "0 0 0\n");//steal,guest,guest_nice
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dfs_seq_ops seq_ops = {
|
||||||
|
.start = seq_start,
|
||||||
|
.stop = seq_stop,
|
||||||
|
.next = seq_next,
|
||||||
|
.show = seq_show,
|
||||||
|
};
|
||||||
|
|
||||||
|
rt_weak const struct dfs_seq_ops *stat_get_seq_ops(void)
|
||||||
|
{
|
||||||
|
return &seq_ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proc_open(struct dfs_file *file)
|
||||||
|
{
|
||||||
|
return dfs_seq_open(file, stat_get_seq_ops());
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proc_close(struct dfs_file *file)
|
||||||
|
{
|
||||||
|
return dfs_seq_release(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dfs_file_ops file_ops = {
|
||||||
|
.open = proc_open,
|
||||||
|
.read = dfs_seq_read,
|
||||||
|
.lseek = dfs_seq_lseek,
|
||||||
|
.close = proc_close,
|
||||||
|
};
|
||||||
|
|
||||||
|
int proc_stat_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = proc_create_data("stat", 0, NULL, &file_ops, NULL);
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_stat_init);
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
|
||||||
|
|
||||||
|
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
|
||||||
|
{
|
||||||
|
off_t i = *index; // seq->index
|
||||||
|
|
||||||
|
return NULL + (i == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void seq_stop(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
off_t i = *index + 1; // seq->index
|
||||||
|
|
||||||
|
*index = i;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seq_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
/* data: The return value of the start or next*/
|
||||||
|
dfs_seq_puts(seq, "todo\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dfs_seq_ops seq_ops = {
|
||||||
|
.start = seq_start,
|
||||||
|
.stop = seq_stop,
|
||||||
|
.next = seq_next,
|
||||||
|
.show = seq_show,
|
||||||
|
};
|
||||||
|
|
||||||
|
void proc_tty_register_driver(void *driver)
|
||||||
|
{
|
||||||
|
//todo
|
||||||
|
}
|
||||||
|
|
||||||
|
void proc_tty_unregister_driver(void *driver)
|
||||||
|
{
|
||||||
|
//todo
|
||||||
|
}
|
||||||
|
|
||||||
|
int proc_tty_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry;
|
||||||
|
|
||||||
|
dentry = proc_mkdir("tty", NULL);
|
||||||
|
if (!dentry)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
dentry = proc_mkdir("tty/ldisc", NULL);
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
dentry = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL);
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
dentry = proc_create_data("tty/ldiscs", 0, NULL, NULL, NULL);
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->seq_ops = &seq_ops;
|
||||||
|
}
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
dentry = proc_create_data("tty/drivers", 0, NULL, NULL, NULL);
|
||||||
|
if (dentry)
|
||||||
|
{
|
||||||
|
dentry->seq_ops = &seq_ops;
|
||||||
|
}
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_tty_init);
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
|
||||||
|
|
||||||
|
static int single_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
dfs_seq_printf(seq, "%lu.%02lu %lu.%02lu\n",
|
||||||
|
(unsigned long)rt_tick_get_millisecond() / 1000, (unsigned long)(rt_tick_get_millisecond() % 1000) / 100,
|
||||||
|
(unsigned long)rt_tick_get_millisecond() / 1000, (unsigned long)(rt_tick_get_millisecond() % 1000) / 100);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int proc_uptime_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = proc_create_single_data("uptime", 0, NULL, single_show, NULL);
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_uptime_init);
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
|
||||||
|
|
||||||
|
static int single_show(struct dfs_seq_file *seq, void *data)
|
||||||
|
{
|
||||||
|
dfs_seq_puts(seq, "\n \\ | /\n");
|
||||||
|
#ifdef RT_USING_SMART
|
||||||
|
dfs_seq_puts(seq, "- RT - Thread Smart Operating System\n");
|
||||||
|
#else
|
||||||
|
dfs_seq_puts(seq, "- RT - Thread Operating System\n");
|
||||||
|
#endif
|
||||||
|
dfs_seq_printf(seq, " / | \\ %d.%d.%d build %s %s\n",
|
||||||
|
(rt_int32_t)RT_VERSION_MAJOR, (rt_int32_t)RT_VERSION_MINOR, (rt_int32_t)RT_VERSION_PATCH,
|
||||||
|
__DATE__, __TIME__);
|
||||||
|
dfs_seq_puts(seq, " 2006 - 2022 Copyright by RT-Thread team\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int proc_version_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dentry *dentry = proc_create_single_data("version", 0, NULL, single_show, NULL);
|
||||||
|
proc_release(dentry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_ENV_EXPORT(proc_version_init);
|
@ -0,0 +1,447 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <dfs.h>
|
||||||
|
#include <dfs_fs.h>
|
||||||
|
#include <dfs_file.h>
|
||||||
|
#include <dfs_posix.h>
|
||||||
|
#include <dfs_mnt.h>
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
|
||||||
|
#include "proc.h"
|
||||||
|
#include "procfs.h"
|
||||||
|
|
||||||
|
#define PROC_DEBUG(...) //rt_kprintf
|
||||||
|
|
||||||
|
static int dfs_procfs_open(struct dfs_file *file)
|
||||||
|
{
|
||||||
|
rt_err_t ret = RT_EOK;
|
||||||
|
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||||
|
|
||||||
|
|
||||||
|
RT_ASSERT(file->ref_count > 0);
|
||||||
|
|
||||||
|
// this file is opened and in an fdtable
|
||||||
|
if (file->ref_count > 1)
|
||||||
|
{
|
||||||
|
file->fpos = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->fops && entry->fops->open)
|
||||||
|
{
|
||||||
|
ret = entry->fops->open(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfs_procfs_close(struct dfs_file *file)
|
||||||
|
{
|
||||||
|
rt_err_t ret = RT_EOK;
|
||||||
|
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||||
|
|
||||||
|
RT_ASSERT(file->vnode->ref_count > 0);
|
||||||
|
if (file->vnode->ref_count > 1)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry && entry->fops && entry->fops->close)
|
||||||
|
{
|
||||||
|
ret = entry->fops->close(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t dfs_procfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
|
||||||
|
{
|
||||||
|
ssize_t ret = -RT_ERROR;
|
||||||
|
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||||
|
|
||||||
|
if (entry && entry->fops && entry->fops->read)
|
||||||
|
{
|
||||||
|
ret = entry->fops->read(file, buf, count, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t dfs_procfs_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
|
||||||
|
{
|
||||||
|
ssize_t ret = -RT_ERROR;
|
||||||
|
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||||
|
|
||||||
|
if (entry && entry->fops && entry->fops->write)
|
||||||
|
{
|
||||||
|
ret = entry->fops->write(file, buf, count, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfs_procfs_ioctl(struct dfs_file *file, int cmd, void *args)
|
||||||
|
{
|
||||||
|
int ret = -RT_ERROR;
|
||||||
|
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||||
|
|
||||||
|
if (entry && entry->fops && entry->fops->ioctl)
|
||||||
|
{
|
||||||
|
ret = entry->fops->ioctl(file, cmd, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfs_procfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
rt_uint32_t index = 0;
|
||||||
|
struct dirent *d;
|
||||||
|
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||||
|
|
||||||
|
if (entry)
|
||||||
|
{
|
||||||
|
struct proc_dentry *iter = RT_NULL, *tmp;
|
||||||
|
|
||||||
|
/* make integer count */
|
||||||
|
count = (count / sizeof(struct dirent));
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dfs_vfs_for_each_subnode(iter, tmp, entry, node)
|
||||||
|
{
|
||||||
|
if (iter == RT_NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= file->fpos)
|
||||||
|
{
|
||||||
|
d = dirp + index - file->fpos;
|
||||||
|
|
||||||
|
if (S_ISDIR(entry->mode))
|
||||||
|
{
|
||||||
|
d->d_type = DT_DIR;
|
||||||
|
}
|
||||||
|
else if (S_ISLNK(entry->mode))
|
||||||
|
{
|
||||||
|
d->d_type = DT_SYMLINK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->d_type = DT_REG;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->d_namlen = rt_strlen(iter->name);
|
||||||
|
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
||||||
|
rt_strncpy(d->d_name, iter->name, rt_strlen(iter->name) + 1);
|
||||||
|
|
||||||
|
ret ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
if (index - file->fpos >= count)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret > 0)
|
||||||
|
{
|
||||||
|
file->fpos = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->fops && entry->fops->getdents && ret < count)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
file->fpos -= index;
|
||||||
|
|
||||||
|
r = entry->fops->getdents(file, dirp + ret, (count - ret) * sizeof(struct dirent));
|
||||||
|
|
||||||
|
ret = ret * sizeof(struct dirent);
|
||||||
|
|
||||||
|
if (r > 0)
|
||||||
|
{
|
||||||
|
ret += r;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->fpos += index;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = ret * sizeof(struct dirent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfs_procfs_poll(struct dfs_file *file, struct rt_pollreq *req)
|
||||||
|
{
|
||||||
|
int ret = -RT_ERROR;
|
||||||
|
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||||
|
|
||||||
|
if (entry && entry->fops && entry->fops->poll)
|
||||||
|
{
|
||||||
|
ret = entry->fops->poll(file, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfs_procfs_flush(struct dfs_file *file)
|
||||||
|
{
|
||||||
|
int ret = -RT_ERROR;
|
||||||
|
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
|
||||||
|
|
||||||
|
if (entry && entry->fops && entry->fops->flush)
|
||||||
|
{
|
||||||
|
ret = entry->fops->flush(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfs_procfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
|
||||||
|
{
|
||||||
|
RT_ASSERT(mnt != RT_NULL);
|
||||||
|
|
||||||
|
return RT_EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfs_procfs_umount(struct dfs_mnt *mnt)
|
||||||
|
{
|
||||||
|
RT_ASSERT(mnt != RT_NULL);
|
||||||
|
|
||||||
|
return RT_EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfs_procfs_readlink(struct dfs_dentry *dentry, char *buf, int len)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct proc_dentry *entry = dfs_proc_find(dentry->pathname);
|
||||||
|
|
||||||
|
if (entry)
|
||||||
|
{
|
||||||
|
if (S_ISLNK(entry->mode) && entry->data)
|
||||||
|
{
|
||||||
|
if (entry->ops && entry->ops->readlink)
|
||||||
|
{
|
||||||
|
ret = entry->ops->readlink(entry, buf, len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_strncpy(buf, (const char *)entry->data, len);
|
||||||
|
buf[len - 1] = '\0';
|
||||||
|
ret = rt_strlen(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proc_release(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfs_procfs_unlink(struct dfs_dentry *dentry)
|
||||||
|
{
|
||||||
|
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, -1);
|
||||||
|
return -RT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfs_procfs_stat(struct dfs_dentry *dentry, struct stat *st)
|
||||||
|
{
|
||||||
|
int ret = RT_EOK;
|
||||||
|
struct dfs_vnode *vnode;
|
||||||
|
|
||||||
|
if (dentry && dentry->vnode)
|
||||||
|
{
|
||||||
|
vnode = dentry->vnode;
|
||||||
|
|
||||||
|
st->st_dev = (dev_t)(dentry->mnt->dev_id);
|
||||||
|
st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry);
|
||||||
|
|
||||||
|
st->st_gid = vnode->gid;
|
||||||
|
st->st_uid = vnode->uid;
|
||||||
|
st->st_mode = vnode->mode;
|
||||||
|
st->st_nlink = vnode->nlink;
|
||||||
|
st->st_size = vnode->size;
|
||||||
|
st->st_mtim.tv_nsec = vnode->mtime.tv_nsec;
|
||||||
|
st->st_mtim.tv_sec = vnode->mtime.tv_sec;
|
||||||
|
st->st_ctim.tv_nsec = vnode->ctime.tv_nsec;
|
||||||
|
st->st_ctim.tv_sec = vnode->ctime.tv_sec;
|
||||||
|
st->st_atim.tv_nsec = vnode->atime.tv_nsec;
|
||||||
|
st->st_atim.tv_sec = vnode->atime.tv_sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfs_procfs_statfs(struct dfs_mnt *mnt, struct statfs *buf)
|
||||||
|
{
|
||||||
|
if (mnt && buf)
|
||||||
|
{
|
||||||
|
buf->f_bsize = 512;
|
||||||
|
buf->f_blocks = 2048 * 64; // 64M
|
||||||
|
buf->f_bfree = buf->f_blocks;
|
||||||
|
buf->f_bavail = buf->f_bfree;
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC_DEBUG(" %s %d\n", __func__, __LINE__);
|
||||||
|
|
||||||
|
return RT_EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dfs_vnode *dfs_procfs_lookup(struct dfs_dentry *dentry)
|
||||||
|
{
|
||||||
|
struct dfs_vnode *vnode = RT_NULL;
|
||||||
|
struct proc_dentry *entry = dfs_proc_find(dentry->pathname);
|
||||||
|
|
||||||
|
if (entry)
|
||||||
|
{
|
||||||
|
vnode = dfs_vnode_create();
|
||||||
|
if (vnode)
|
||||||
|
{
|
||||||
|
vnode->nlink = 1;
|
||||||
|
vnode->size = 0;
|
||||||
|
if (S_ISDIR(entry->mode))
|
||||||
|
{
|
||||||
|
vnode->mode = entry->mode;
|
||||||
|
vnode->type = FT_DIRECTORY;
|
||||||
|
}
|
||||||
|
else if (S_ISLNK(entry->mode))
|
||||||
|
{
|
||||||
|
vnode->mode = entry->mode;
|
||||||
|
vnode->type = FT_SYMLINK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vnode->mode = entry->mode;
|
||||||
|
vnode->type = FT_REGULAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
vnode->data = entry;
|
||||||
|
vnode->mnt = dentry->mnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc_release(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
PROC_DEBUG(" %s %d >> %s\n", __func__, __LINE__, dentry->pathname);
|
||||||
|
|
||||||
|
return vnode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dfs_vnode *dfs_procfs_create_vnode(struct dfs_dentry *dentry, int type, mode_t mode)
|
||||||
|
{
|
||||||
|
return RT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dfs_procfs_free_vnode(struct dfs_vnode *vnode)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dfs_file_ops _procfs_fops =
|
||||||
|
{
|
||||||
|
.open = dfs_procfs_open,
|
||||||
|
.close = dfs_procfs_close,
|
||||||
|
.lseek = generic_dfs_lseek,
|
||||||
|
.read = dfs_procfs_read,
|
||||||
|
.write = dfs_procfs_write,
|
||||||
|
.ioctl = dfs_procfs_ioctl,
|
||||||
|
.getdents = dfs_procfs_getdents,
|
||||||
|
.poll = dfs_procfs_poll,
|
||||||
|
.flush = dfs_procfs_flush,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct dfs_filesystem_ops _procfs_ops =
|
||||||
|
{
|
||||||
|
.name = "procfs",
|
||||||
|
|
||||||
|
.default_fops = &_procfs_fops,
|
||||||
|
|
||||||
|
.mount = dfs_procfs_mount,
|
||||||
|
.umount = dfs_procfs_umount,
|
||||||
|
.readlink = dfs_procfs_readlink,
|
||||||
|
.unlink = dfs_procfs_unlink,
|
||||||
|
.stat = dfs_procfs_stat,
|
||||||
|
.statfs = dfs_procfs_statfs,
|
||||||
|
.lookup = dfs_procfs_lookup,
|
||||||
|
.create_vnode = dfs_procfs_create_vnode,
|
||||||
|
.free_vnode = dfs_procfs_free_vnode,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dfs_filesystem_type _procfs =
|
||||||
|
{
|
||||||
|
.fs_ops = &_procfs_ops,
|
||||||
|
};
|
||||||
|
|
||||||
|
int dfs_procfs_init(void)
|
||||||
|
{
|
||||||
|
/* register procfs file system */
|
||||||
|
dfs_register(&_procfs);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
INIT_COMPONENT_EXPORT(dfs_procfs_init);
|
||||||
|
|
||||||
|
int proc_read_data(struct dfs_file *file, void *buf, size_t count, off_t *pos)
|
||||||
|
{
|
||||||
|
if (file->fpos >= file->vnode->size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file->data)
|
||||||
|
{
|
||||||
|
count = file->vnode->size - file->fpos >= count ? count : file->vnode->size - file->fpos;
|
||||||
|
rt_strncpy(buf, file->data + file->fpos, count);
|
||||||
|
|
||||||
|
file->fpos += count;
|
||||||
|
*pos = file->fpos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PROC_FS_H__
|
||||||
|
#define __PROC_FS_H__
|
||||||
|
|
||||||
|
#include <dfs_file.h>
|
||||||
|
|
||||||
|
int dfs_procfs_init(void);
|
||||||
|
|
||||||
|
int proc_read_data(struct dfs_file *file, void *buf, size_t count, off_t *pos);
|
||||||
|
|
||||||
|
#endif
|
@ -365,6 +365,7 @@ static const struct dfs_file_ops _rom_fops =
|
|||||||
{
|
{
|
||||||
.open = dfs_romfs_open,
|
.open = dfs_romfs_open,
|
||||||
.close = dfs_romfs_close,
|
.close = dfs_romfs_close,
|
||||||
|
.ioctl = dfs_romfs_ioctl,
|
||||||
.lseek = generic_dfs_lseek,
|
.lseek = generic_dfs_lseek,
|
||||||
.read = dfs_romfs_read,
|
.read = dfs_romfs_read,
|
||||||
.getdents = dfs_romfs_getdents,
|
.getdents = dfs_romfs_getdents,
|
||||||
|
@ -99,15 +99,13 @@ static int _get_subdir(const char *path, char *name)
|
|||||||
|
|
||||||
static int _free_subdir(struct tmpfs_file *dfile)
|
static int _free_subdir(struct tmpfs_file *dfile)
|
||||||
{
|
{
|
||||||
struct tmpfs_file *file;
|
struct tmpfs_file *file = RT_NULL, *tmp;
|
||||||
rt_list_t *list, *temp_list;
|
|
||||||
struct tmpfs_sb *superblock;
|
struct tmpfs_sb *superblock;
|
||||||
|
|
||||||
RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
|
RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
|
||||||
|
|
||||||
rt_list_for_each_safe(list, temp_list, &dfile->subdirs)
|
dfs_vfs_for_each_subnode(file, tmp, dfile, node)
|
||||||
{
|
{
|
||||||
file = rt_list_entry(list, struct tmpfs_file, sibling);
|
|
||||||
if (file->type == TMPFS_TYPE_DIR)
|
if (file->type == TMPFS_TYPE_DIR)
|
||||||
{
|
{
|
||||||
_free_subdir(file);
|
_free_subdir(file);
|
||||||
@ -122,7 +120,7 @@ static int _free_subdir(struct tmpfs_file *dfile)
|
|||||||
RT_ASSERT(superblock != NULL);
|
RT_ASSERT(superblock != NULL);
|
||||||
|
|
||||||
rt_spin_lock(&superblock->lock);
|
rt_spin_lock(&superblock->lock);
|
||||||
rt_list_remove(&(file->sibling));
|
dfs_vfs_remove_node(&file->node);
|
||||||
rt_spin_unlock(&superblock->lock);
|
rt_spin_unlock(&superblock->lock);
|
||||||
|
|
||||||
rt_free(file);
|
rt_free(file);
|
||||||
@ -141,13 +139,11 @@ static int dfs_tmpfs_mount(struct dfs_mnt *mnt,
|
|||||||
{
|
{
|
||||||
superblock->df_size = sizeof(struct tmpfs_sb);
|
superblock->df_size = sizeof(struct tmpfs_sb);
|
||||||
superblock->magic = TMPFS_MAGIC;
|
superblock->magic = TMPFS_MAGIC;
|
||||||
rt_list_init(&superblock->sibling);
|
|
||||||
|
|
||||||
superblock->root.name[0] = '/';
|
superblock->root.name[0] = '/';
|
||||||
superblock->root.sb = superblock;
|
superblock->root.sb = superblock;
|
||||||
superblock->root.type = TMPFS_TYPE_DIR;
|
superblock->root.type = TMPFS_TYPE_DIR;
|
||||||
rt_list_init(&superblock->root.sibling);
|
dfs_vfs_init_node(&superblock->root.node);
|
||||||
rt_list_init(&superblock->root.subdirs);
|
|
||||||
|
|
||||||
rt_spin_lock_init(&superblock->lock);
|
rt_spin_lock_init(&superblock->lock);
|
||||||
|
|
||||||
@ -236,8 +232,7 @@ struct tmpfs_file *dfs_tmpfs_lookup(struct tmpfs_sb *superblock,
|
|||||||
{
|
{
|
||||||
const char *subpath, *curpath, *filename = RT_NULL;
|
const char *subpath, *curpath, *filename = RT_NULL;
|
||||||
char subdir_name[TMPFS_NAME_MAX];
|
char subdir_name[TMPFS_NAME_MAX];
|
||||||
struct tmpfs_file *file, *curfile;
|
struct tmpfs_file *file, *curfile, *tmp;
|
||||||
rt_list_t *list;
|
|
||||||
|
|
||||||
subpath = path;
|
subpath = path;
|
||||||
while (*subpath == '/' && *subpath)
|
while (*subpath == '/' && *subpath)
|
||||||
@ -265,9 +260,8 @@ find_subpath:
|
|||||||
|
|
||||||
rt_spin_lock(&superblock->lock);
|
rt_spin_lock(&superblock->lock);
|
||||||
|
|
||||||
rt_list_for_each(list, &curfile->subdirs)
|
dfs_vfs_for_each_subnode(file, tmp, curfile, node)
|
||||||
{
|
{
|
||||||
file = rt_list_entry(list, struct tmpfs_file, sibling);
|
|
||||||
if (filename) /* find file */
|
if (filename) /* find file */
|
||||||
{
|
{
|
||||||
if (rt_strcmp(file->name, filename) == 0)
|
if (rt_strcmp(file->name, filename) == 0)
|
||||||
@ -503,8 +497,7 @@ static int dfs_tmpfs_getdents(struct dfs_file *file,
|
|||||||
{
|
{
|
||||||
rt_size_t index, end;
|
rt_size_t index, end;
|
||||||
struct dirent *d;
|
struct dirent *d;
|
||||||
struct tmpfs_file *d_file, *n_file;
|
struct tmpfs_file *d_file, *n_file, *tmp;
|
||||||
rt_list_t *list;
|
|
||||||
struct tmpfs_sb *superblock;
|
struct tmpfs_sb *superblock;
|
||||||
|
|
||||||
d_file = (struct tmpfs_file *)file->vnode->data;
|
d_file = (struct tmpfs_file *)file->vnode->data;
|
||||||
@ -527,9 +520,8 @@ static int dfs_tmpfs_getdents(struct dfs_file *file,
|
|||||||
index = 0;
|
index = 0;
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
rt_list_for_each(list, &d_file->subdirs)
|
dfs_vfs_for_each_subnode(n_file, tmp, d_file, node)
|
||||||
{
|
{
|
||||||
n_file = rt_list_entry(list, struct tmpfs_file, sibling);
|
|
||||||
if (index >= (rt_size_t)file->fpos)
|
if (index >= (rt_size_t)file->fpos)
|
||||||
{
|
{
|
||||||
d = dirp + count;
|
d = dirp + count;
|
||||||
@ -573,7 +565,7 @@ static int dfs_tmpfs_unlink(struct dfs_dentry *dentry)
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
rt_spin_lock(&superblock->lock);
|
rt_spin_lock(&superblock->lock);
|
||||||
rt_list_remove(&(d_file->sibling));
|
dfs_vfs_remove_node(&d_file->node);
|
||||||
rt_spin_unlock(&superblock->lock);
|
rt_spin_unlock(&superblock->lock);
|
||||||
|
|
||||||
if (rt_atomic_load(&(dentry->ref_count)) == 1)
|
if (rt_atomic_load(&(dentry->ref_count)) == 1)
|
||||||
@ -631,13 +623,13 @@ static int dfs_tmpfs_rename(struct dfs_dentry *old_dentry, struct dfs_dentry *ne
|
|||||||
RT_ASSERT(p_file != NULL);
|
RT_ASSERT(p_file != NULL);
|
||||||
|
|
||||||
rt_spin_lock(&superblock->lock);
|
rt_spin_lock(&superblock->lock);
|
||||||
rt_list_remove(&(d_file->sibling));
|
dfs_vfs_remove_node(&d_file->node);
|
||||||
rt_spin_unlock(&superblock->lock);
|
rt_spin_unlock(&superblock->lock);
|
||||||
|
|
||||||
strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
|
strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
|
||||||
|
|
||||||
rt_spin_lock(&superblock->lock);
|
rt_spin_lock(&superblock->lock);
|
||||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
dfs_vfs_append_node(&p_file->node, &d_file->node);
|
||||||
rt_spin_unlock(&superblock->lock);
|
rt_spin_unlock(&superblock->lock);
|
||||||
|
|
||||||
rt_free(parent_path);
|
rt_free(parent_path);
|
||||||
@ -745,8 +737,7 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t
|
|||||||
|
|
||||||
strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
|
strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
|
||||||
|
|
||||||
rt_list_init(&(d_file->subdirs));
|
dfs_vfs_init_node(&d_file->node);
|
||||||
rt_list_init(&(d_file->sibling));
|
|
||||||
d_file->data = NULL;
|
d_file->data = NULL;
|
||||||
d_file->size = 0;
|
d_file->size = 0;
|
||||||
d_file->sb = superblock;
|
d_file->sb = superblock;
|
||||||
@ -767,7 +758,7 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
rt_spin_lock(&superblock->lock);
|
rt_spin_lock(&superblock->lock);
|
||||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
dfs_vfs_append_node(&p_file->node, &d_file->node);
|
||||||
rt_spin_unlock(&superblock->lock);
|
rt_spin_unlock(&superblock->lock);
|
||||||
|
|
||||||
vnode->mnt = dentry->mnt;
|
vnode->mnt = dentry->mnt;
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#define __DFS_TMPFS_H__
|
#define __DFS_TMPFS_H__
|
||||||
|
|
||||||
#include <rtthread.h>
|
#include <rtthread.h>
|
||||||
|
#include <dfs_vfs.h>
|
||||||
|
|
||||||
#define TMPFS_NAME_MAX 32
|
#define TMPFS_NAME_MAX 32
|
||||||
#define TMPFS_MAGIC 0x0B0B0B0B
|
#define TMPFS_MAGIC 0x0B0B0B0B
|
||||||
@ -25,8 +26,7 @@ struct tmpfs_file
|
|||||||
{
|
{
|
||||||
rt_uint32_t type; /* file type */
|
rt_uint32_t type; /* file type */
|
||||||
char name[TMPFS_NAME_MAX]; /* file name */
|
char name[TMPFS_NAME_MAX]; /* file name */
|
||||||
rt_list_t subdirs; /* file subdir list */
|
struct dfs_vfs_node node; /* file node in the tmpfs */
|
||||||
rt_list_t sibling; /* file sibling list */
|
|
||||||
struct tmpfs_sb *sb; /* superblock ptr */
|
struct tmpfs_sb *sb; /* superblock ptr */
|
||||||
rt_uint8_t *data; /* file date ptr */
|
rt_uint8_t *data; /* file date ptr */
|
||||||
rt_size_t size; /* file size */
|
rt_size_t size; /* file size */
|
||||||
|
@ -20,6 +20,38 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MS_RDONLY 1
|
||||||
|
#define MS_NOSUID 2
|
||||||
|
#define MS_NODEV 4
|
||||||
|
#define MS_NOEXEC 8
|
||||||
|
#define MS_SYNCHRONOUS 16
|
||||||
|
#define MS_REMOUNT 32
|
||||||
|
#define MS_MANDLOCK 64
|
||||||
|
#define MS_DIRSYNC 128
|
||||||
|
#define MS_NOATIME 1024
|
||||||
|
#define MS_NODIRATIME 2048
|
||||||
|
#define MS_BIND 4096
|
||||||
|
#define MS_MOVE 8192
|
||||||
|
#define MS_REC 16384
|
||||||
|
#define MS_SILENT 32768
|
||||||
|
#define MS_POSIXACL (1<<16)
|
||||||
|
#define MS_UNBINDABLE (1<<17)
|
||||||
|
#define MS_PRIVATE (1<<18)
|
||||||
|
#define MS_SLAVE (1<<19)
|
||||||
|
#define MS_SHARED (1<<20)
|
||||||
|
#define MS_RELATIME (1<<21)
|
||||||
|
#define MS_KERNMOUNT (1<<22)
|
||||||
|
#define MS_I_VERSION (1<<23)
|
||||||
|
#define MS_STRICTATIME (1<<24)
|
||||||
|
#define MS_LAZYTIME (1<<25)
|
||||||
|
#define MS_NOREMOTELOCK (1<<27)
|
||||||
|
#define MS_NOSEC (1<<28)
|
||||||
|
#define MS_BORN (1<<29)
|
||||||
|
#define MS_ACTIVE (1<<30)
|
||||||
|
#define MS_NOUSER (1U<<31)
|
||||||
|
|
||||||
|
#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|MS_LAZYTIME)
|
||||||
|
|
||||||
/* file system partition table */
|
/* file system partition table */
|
||||||
struct dfs_partition
|
struct dfs_partition
|
||||||
{
|
{
|
||||||
@ -87,6 +119,7 @@ int dfs_unregister(struct dfs_filesystem_type *fs);
|
|||||||
int dfs_register(struct dfs_filesystem_type *fs);
|
int dfs_register(struct dfs_filesystem_type *fs);
|
||||||
const char *dfs_filesystem_get_mounted_path(struct rt_device *device);
|
const char *dfs_filesystem_get_mounted_path(struct rt_device *device);
|
||||||
|
|
||||||
|
int dfs_remount(const char *path, rt_ubase_t flags, void *data);
|
||||||
int dfs_mount(const char *device_name,
|
int dfs_mount(const char *device_name,
|
||||||
const char *path,
|
const char *path,
|
||||||
const char *filesystemtype,
|
const char *filesystemtype,
|
||||||
|
@ -39,6 +39,8 @@ struct dfs_mnt
|
|||||||
#define MNT_IS_UMOUNT 0x8 /* the mnt is unmount */
|
#define MNT_IS_UMOUNT 0x8 /* the mnt is unmount */
|
||||||
#define MNT_IS_LOCKED 0x10 /* the mnt is locked */
|
#define MNT_IS_LOCKED 0x10 /* the mnt is locked */
|
||||||
#define MNT_FORCE 0x20 /* the mnt force unmount */
|
#define MNT_FORCE 0x20 /* the mnt force unmount */
|
||||||
|
#define MNT_LAZY_UMNT 0x40 /* the mnt has pending umount */
|
||||||
|
#define MNT_RDONLY 0x80 /* the mnt is read only */
|
||||||
|
|
||||||
rt_atomic_t ref_count; /* reference count */
|
rt_atomic_t ref_count; /* reference count */
|
||||||
|
|
||||||
@ -60,9 +62,16 @@ const char *dfs_mnt_get_mounted_path(struct rt_device *device);
|
|||||||
struct dfs_mnt* dfs_mnt_ref(struct dfs_mnt* mnt);
|
struct dfs_mnt* dfs_mnt_ref(struct dfs_mnt* mnt);
|
||||||
int dfs_mnt_unref(struct dfs_mnt* mnt);
|
int dfs_mnt_unref(struct dfs_mnt* mnt);
|
||||||
|
|
||||||
|
int dfs_mnt_umount(struct dfs_mnt *mnt, int flags);
|
||||||
|
int dfs_mnt_setflags(struct dfs_mnt *mnt, int flags);
|
||||||
|
|
||||||
rt_bool_t dfs_mnt_has_child_mnt(struct dfs_mnt *mnt, const char* fullpath);
|
rt_bool_t dfs_mnt_has_child_mnt(struct dfs_mnt *mnt, const char* fullpath);
|
||||||
|
|
||||||
int dfs_mnt_foreach(struct dfs_mnt* (*func)(struct dfs_mnt *mnt, void *parameter), void *parameter);
|
int dfs_mnt_foreach(struct dfs_mnt* (*func)(struct dfs_mnt *mnt, void *parameter), void *parameter);
|
||||||
|
int dfs_mnt_umount_iter(rt_bool_t (*filter)(struct dfs_mnt *mnt, void *parameter), void *parameter);
|
||||||
|
|
||||||
|
typedef void (*dfs_mnt_umnt_cb_t)(struct dfs_mnt *mnt);
|
||||||
|
RT_OBJECT_HOOKLIST_DECLARE(dfs_mnt_umnt_cb_t, dfs_mnt_umnt);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,7 @@ int dfs_aspace_mmap_write(struct dfs_file *file, struct rt_varea *varea, void *d
|
|||||||
|
|
||||||
void dfs_pcache_release(size_t count);
|
void dfs_pcache_release(size_t count);
|
||||||
void dfs_pcache_unmount(struct dfs_mnt *mnt);
|
void dfs_pcache_unmount(struct dfs_mnt *mnt);
|
||||||
|
void dfs_pcache_clean(struct dfs_mnt *mnt);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
50
rt-thread-no-bsp/components/dfs/dfs_v2/include/dfs_vfs.h
Normal file
50
rt-thread-no-bsp/components/dfs/dfs_v2/include/dfs_vfs.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DFS_VFS_H__
|
||||||
|
#define __DFS_VFS_H__
|
||||||
|
|
||||||
|
#include "dfs_file.h"
|
||||||
|
#include "dfs_fs.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct dfs_vfs_node
|
||||||
|
{
|
||||||
|
rt_list_t subnode; /* file subnode list */
|
||||||
|
rt_list_t sibling; /* file sibling list */
|
||||||
|
};
|
||||||
|
|
||||||
|
rt_inline void dfs_vfs_init_node(struct dfs_vfs_node *node)
|
||||||
|
{
|
||||||
|
rt_list_init(&node->subnode);
|
||||||
|
rt_list_init(&node->sibling);
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_inline void dfs_vfs_append_node(struct dfs_vfs_node *dir, struct dfs_vfs_node *node)
|
||||||
|
{
|
||||||
|
rt_list_insert_after(&(dir->subnode), &(node->sibling));
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_inline void dfs_vfs_remove_node(struct dfs_vfs_node *node)
|
||||||
|
{
|
||||||
|
rt_list_remove(&(node->sibling));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define dfs_vfs_for_each_subnode(node, tmp, dir, member) \
|
||||||
|
rt_list_for_each_entry_safe(node, tmp, &dir->member.subnode, member.sibling)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*__DFS_VFS_H__*/
|
@ -95,6 +95,52 @@ int dfs_unregister(struct dfs_filesystem_type *fs)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define REMNT_UNSUPP_FLAGS (~(MS_REMOUNT | MS_RMT_MASK))
|
||||||
|
int dfs_remount(const char *path, rt_ubase_t flags, void *data)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
char *fullpath = RT_NULL;
|
||||||
|
struct dfs_mnt *mnt = RT_NULL;
|
||||||
|
|
||||||
|
if (flags & REMNT_UNSUPP_FLAGS)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fullpath = dfs_normalize_path(RT_NULL, path);
|
||||||
|
if (!fullpath)
|
||||||
|
{
|
||||||
|
rc = -ENOENT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt = dfs_mnt_lookup(%s)", fullpath);
|
||||||
|
mnt = dfs_mnt_lookup(fullpath);
|
||||||
|
if (mnt)
|
||||||
|
{
|
||||||
|
dfs_lock();
|
||||||
|
dfs_mnt_setflags(mnt, flags);
|
||||||
|
dfs_unlock();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct stat buf = {0};
|
||||||
|
if (dfs_file_stat(fullpath, &buf) == 0 && S_ISBLK(buf.st_mode))
|
||||||
|
{
|
||||||
|
/* path was not already mounted on target */
|
||||||
|
rc = -EINVAL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* path is not a directory */
|
||||||
|
rc = -ENOTDIR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* parent(mount path)
|
* parent(mount path)
|
||||||
* mnt_parent <- - - - - - - +
|
* mnt_parent <- - - - - - - +
|
||||||
@ -300,7 +346,7 @@ int dfs_mount(const char *device_name,
|
|||||||
|
|
||||||
int dfs_umount(const char *specialfile, int flags)
|
int dfs_umount(const char *specialfile, int flags)
|
||||||
{
|
{
|
||||||
int ret = -RT_ERROR;
|
int ret = -1;
|
||||||
char *fullpath = RT_NULL;
|
char *fullpath = RT_NULL;
|
||||||
struct dfs_mnt *mnt = RT_NULL;
|
struct dfs_mnt *mnt = RT_NULL;
|
||||||
|
|
||||||
@ -314,7 +360,7 @@ int dfs_umount(const char *specialfile, int flags)
|
|||||||
if (strcmp(mnt->fullpath, fullpath) == 0)
|
if (strcmp(mnt->fullpath, fullpath) == 0)
|
||||||
{
|
{
|
||||||
/* is the mount point */
|
/* is the mount point */
|
||||||
rt_atomic_t ref_count = rt_atomic_load(&(mnt->ref_count));
|
rt_base_t ref_count = rt_atomic_load(&(mnt->ref_count));
|
||||||
|
|
||||||
if (!(mnt->flags & MNT_IS_LOCKED) && rt_list_isempty(&mnt->child) && (ref_count == 1 || (flags & MNT_FORCE)))
|
if (!(mnt->flags & MNT_IS_LOCKED) && rt_list_isempty(&mnt->child) && (ref_count == 1 || (flags & MNT_FORCE)))
|
||||||
{
|
{
|
||||||
@ -327,17 +373,19 @@ int dfs_umount(const char *specialfile, int flags)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_E("the file system is busy!");
|
LOG_I("the file system is busy!");
|
||||||
|
ret = -EBUSY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_E("the path:%s is not a mountpoint!", fullpath);
|
LOG_I("the path:%s is not a mountpoint!", fullpath);
|
||||||
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_E("no filesystem found.");
|
LOG_I("no filesystem found.");
|
||||||
}
|
}
|
||||||
rt_free(fullpath);
|
rt_free(fullpath);
|
||||||
}
|
}
|
||||||
|
@ -10,17 +10,21 @@
|
|||||||
|
|
||||||
#include <rtthread.h>
|
#include <rtthread.h>
|
||||||
|
|
||||||
#include "dfs.h"
|
|
||||||
#include "dfs_mnt.h"
|
|
||||||
#include "dfs_dentry.h"
|
|
||||||
#include "dfs_private.h"
|
#include "dfs_private.h"
|
||||||
|
|
||||||
|
#include <dfs.h>
|
||||||
|
#include <dfs_dentry.h>
|
||||||
|
#include <dfs_mnt.h>
|
||||||
|
#include <dfs_pcache.h>
|
||||||
|
|
||||||
#define DBG_TAG "DFS.mnt"
|
#define DBG_TAG "DFS.mnt"
|
||||||
#define DBG_LVL DBG_WARNING
|
#define DBG_LVL DBG_WARNING
|
||||||
#include <rtdbg.h>
|
#include <rtdbg.h>
|
||||||
|
|
||||||
static struct dfs_mnt *_root_mnt = RT_NULL;
|
static struct dfs_mnt *_root_mnt = RT_NULL;
|
||||||
|
|
||||||
|
RT_OBJECT_HOOKLIST_DEFINE(dfs_mnt_umnt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mnt tree structure
|
* mnt tree structure
|
||||||
*
|
*
|
||||||
@ -75,6 +79,7 @@ int dfs_mnt_insert(struct dfs_mnt* mnt, struct dfs_mnt* child)
|
|||||||
child = _root_mnt;
|
child = _root_mnt;
|
||||||
rt_atomic_sub(&(_root_mnt->parent->ref_count), 1);
|
rt_atomic_sub(&(_root_mnt->parent->ref_count), 1);
|
||||||
rt_atomic_sub(&(_root_mnt->ref_count), 1);
|
rt_atomic_sub(&(_root_mnt->ref_count), 1);
|
||||||
|
_root_mnt->flags &= ~MNT_IS_LOCKED;
|
||||||
|
|
||||||
_root_mnt = dfs_mnt_ref(mnt);
|
_root_mnt = dfs_mnt_ref(mnt);
|
||||||
mnt->parent = dfs_mnt_ref(mnt);
|
mnt->parent = dfs_mnt_ref(mnt);
|
||||||
@ -242,21 +247,24 @@ struct dfs_mnt* dfs_mnt_ref(struct dfs_mnt* mnt)
|
|||||||
return mnt;
|
return mnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dfs_mnt_unref(struct dfs_mnt* mnt)
|
int dfs_mnt_unref(struct dfs_mnt *mnt)
|
||||||
{
|
{
|
||||||
rt_err_t ret = RT_EOK;
|
rt_err_t ret = RT_EOK;
|
||||||
|
rt_base_t ref_count;
|
||||||
|
|
||||||
if (mnt)
|
if (mnt)
|
||||||
{
|
{
|
||||||
rt_atomic_sub(&(mnt->ref_count), 1);
|
ref_count = rt_atomic_sub(&(mnt->ref_count), 1) - 1;
|
||||||
|
|
||||||
if (rt_atomic_load(&(mnt->ref_count)) == 0)
|
if (ref_count == 0)
|
||||||
{
|
{
|
||||||
dfs_lock();
|
dfs_lock();
|
||||||
|
|
||||||
if (mnt->flags & MNT_IS_UMOUNT)
|
if (mnt->flags & MNT_IS_UMOUNT)
|
||||||
{
|
{
|
||||||
mnt->fs_ops->umount(mnt);
|
mnt->fs_ops->umount(mnt);
|
||||||
|
|
||||||
|
RT_OBJECT_HOOKLIST_CALL(dfs_mnt_umnt, (mnt));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free full path */
|
/* free full path */
|
||||||
@ -278,6 +286,21 @@ int dfs_mnt_unref(struct dfs_mnt* mnt)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dfs_mnt_setflags(struct dfs_mnt *mnt, int flags)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
if (flags & MS_RDONLY)
|
||||||
|
{
|
||||||
|
mnt->flags |= MNT_RDONLY;
|
||||||
|
#ifdef RT_USING_PAGECACHE
|
||||||
|
dfs_pcache_clean(mnt);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
int dfs_mnt_destroy(struct dfs_mnt* mnt)
|
int dfs_mnt_destroy(struct dfs_mnt* mnt)
|
||||||
{
|
{
|
||||||
rt_err_t ret = RT_EOK;
|
rt_err_t ret = RT_EOK;
|
||||||
|
@ -16,15 +16,16 @@
|
|||||||
#include <dfs_pcache.h>
|
#include <dfs_pcache.h>
|
||||||
#include <dfs_dentry.h>
|
#include <dfs_dentry.h>
|
||||||
#include <dfs_mnt.h>
|
#include <dfs_mnt.h>
|
||||||
#include <mm_page.h>
|
|
||||||
#include <mm_private.h>
|
|
||||||
#include <mmu.h>
|
|
||||||
#include <tlb.h>
|
|
||||||
|
|
||||||
#include <rthw.h>
|
#include <rthw.h>
|
||||||
|
|
||||||
#ifdef RT_USING_PAGECACHE
|
#ifdef RT_USING_PAGECACHE
|
||||||
|
|
||||||
|
#include <mm_page.h>
|
||||||
|
#include <mm_private.h>
|
||||||
|
#include <mmu.h>
|
||||||
|
#include <tlb.h>
|
||||||
|
|
||||||
#ifndef RT_PAGECACHE_COUNT
|
#ifndef RT_PAGECACHE_COUNT
|
||||||
#define RT_PAGECACHE_COUNT 4096
|
#define RT_PAGECACHE_COUNT 4096
|
||||||
#endif
|
#endif
|
||||||
@ -161,7 +162,7 @@ void dfs_pcache_release(size_t count)
|
|||||||
dfs_pcache_unlock();
|
dfs_pcache_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dfs_pcache_unmount(struct dfs_mnt *mnt)
|
static void _pcache_clean(struct dfs_mnt *mnt, int (*cb)(struct dfs_aspace *aspace))
|
||||||
{
|
{
|
||||||
rt_list_t *node = RT_NULL;
|
rt_list_t *node = RT_NULL;
|
||||||
struct dfs_aspace *aspace = RT_NULL;
|
struct dfs_aspace *aspace = RT_NULL;
|
||||||
@ -176,7 +177,7 @@ void dfs_pcache_unmount(struct dfs_mnt *mnt)
|
|||||||
if (aspace && aspace->mnt == mnt)
|
if (aspace && aspace->mnt == mnt)
|
||||||
{
|
{
|
||||||
dfs_aspace_clean(aspace);
|
dfs_aspace_clean(aspace);
|
||||||
dfs_aspace_release(aspace);
|
cb(aspace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,13 +189,28 @@ void dfs_pcache_unmount(struct dfs_mnt *mnt)
|
|||||||
if (aspace && aspace->mnt == mnt)
|
if (aspace && aspace->mnt == mnt)
|
||||||
{
|
{
|
||||||
dfs_aspace_clean(aspace);
|
dfs_aspace_clean(aspace);
|
||||||
dfs_aspace_release(aspace);
|
cb(aspace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dfs_pcache_unlock();
|
dfs_pcache_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dfs_pcache_unmount(struct dfs_mnt *mnt)
|
||||||
|
{
|
||||||
|
_pcache_clean(mnt, dfs_aspace_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _dummy_cb(struct dfs_aspace *mnt)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dfs_pcache_clean(struct dfs_mnt *mnt)
|
||||||
|
{
|
||||||
|
_pcache_clean(mnt, _dummy_cb);
|
||||||
|
}
|
||||||
|
|
||||||
static int dfs_pcache_limit_check(void)
|
static int dfs_pcache_limit_check(void)
|
||||||
{
|
{
|
||||||
int index = 4;
|
int index = 4;
|
||||||
@ -1139,14 +1155,21 @@ int dfs_aspace_write(struct dfs_file *file, const void *buf, size_t count, off_t
|
|||||||
|
|
||||||
if (file && file->vnode && file->vnode->aspace)
|
if (file && file->vnode && file->vnode->aspace)
|
||||||
{
|
{
|
||||||
if (!(file->vnode->aspace->ops->write))
|
|
||||||
return ret;
|
|
||||||
struct dfs_vnode *vnode = file->vnode;
|
struct dfs_vnode *vnode = file->vnode;
|
||||||
struct dfs_aspace *aspace = vnode->aspace;
|
struct dfs_aspace *aspace = vnode->aspace;
|
||||||
|
|
||||||
struct dfs_page *page;
|
struct dfs_page *page;
|
||||||
char *ptr = (char *)buf;
|
char *ptr = (char *)buf;
|
||||||
|
|
||||||
|
if (!(aspace->ops->write))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else if (aspace->mnt && (aspace->mnt->flags & MNT_RDONLY))
|
||||||
|
{
|
||||||
|
return -EROFS;
|
||||||
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
while (count)
|
while (count)
|
||||||
|
@ -1,17 +1,27 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
* Copyright (c) 2006-2025 RT-Thread Development Team
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2022-11-26 GuEe-GUI first version
|
* 2022-11-26 GuEe-GUI first version
|
||||||
|
* 2025-01-24 wumingzi add doxygen comment
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <rtthread.h>
|
#include <rtthread.h>
|
||||||
#include <rtservice.h>
|
#include <rtservice.h>
|
||||||
#include <rtdevice.h>
|
#include <rtdevice.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup Drivers RTTHREAD Driver
|
||||||
|
* @defgroup clk clk
|
||||||
|
* @brief clk driver api
|
||||||
|
* @ingroup Drivers
|
||||||
|
* @addtogroup clk
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
#define DBG_TAG "rtdm.clk"
|
#define DBG_TAG "rtdm.clk"
|
||||||
#define DBG_LVL DBG_INFO
|
#define DBG_LVL DBG_INFO
|
||||||
#include <rtdbg.h>
|
#include <rtdbg.h>
|
||||||
@ -20,6 +30,12 @@ static struct rt_spinlock _clk_lock = { 0 };
|
|||||||
static rt_list_t _clk_nodes = RT_LIST_OBJECT_INIT(_clk_nodes);
|
static rt_list_t _clk_nodes = RT_LIST_OBJECT_INIT(_clk_nodes);
|
||||||
static rt_list_t _clk_notifier_nodes = RT_LIST_OBJECT_INIT(_clk_notifier_nodes);
|
static rt_list_t _clk_notifier_nodes = RT_LIST_OBJECT_INIT(_clk_notifier_nodes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Release clock node
|
||||||
|
*
|
||||||
|
* @param r point to reference count of clock node
|
||||||
|
* @warning The function only can print log and MORE DETAILS SHOULD BE IMPLEMENTED.
|
||||||
|
*/
|
||||||
static void clk_release(struct rt_ref *r)
|
static void clk_release(struct rt_ref *r)
|
||||||
{
|
{
|
||||||
struct rt_clk_node *clk_np = rt_container_of(r, struct rt_clk_node, ref);
|
struct rt_clk_node *clk_np = rt_container_of(r, struct rt_clk_node, ref);
|
||||||
@ -30,6 +46,13 @@ static void clk_release(struct rt_ref *r)
|
|||||||
RT_ASSERT(0);
|
RT_ASSERT(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Increase reference count for clock node
|
||||||
|
*
|
||||||
|
* @param clk_np point to clock node
|
||||||
|
*
|
||||||
|
* @return struct rt_clk_node * point to clock node whose reference count has increased
|
||||||
|
*/
|
||||||
rt_inline struct rt_clk_node *clk_get(struct rt_clk_node *clk_np)
|
rt_inline struct rt_clk_node *clk_get(struct rt_clk_node *clk_np)
|
||||||
{
|
{
|
||||||
rt_ref_get(&clk_np->ref);
|
rt_ref_get(&clk_np->ref);
|
||||||
@ -37,11 +60,27 @@ rt_inline struct rt_clk_node *clk_get(struct rt_clk_node *clk_np)
|
|||||||
return clk_np;
|
return clk_np;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decrease reference count for clock node
|
||||||
|
*
|
||||||
|
* @param clk_np point to clock node
|
||||||
|
*
|
||||||
|
*/
|
||||||
rt_inline void clk_put(struct rt_clk_node *clk_np)
|
rt_inline void clk_put(struct rt_clk_node *clk_np)
|
||||||
{
|
{
|
||||||
rt_ref_put(&clk_np->ref, &clk_release);
|
rt_ref_put(&clk_np->ref, &clk_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate memory space for struct clock and return it
|
||||||
|
*
|
||||||
|
* @param clk_np point to clock node
|
||||||
|
* @param dev_id device identifier for the clock
|
||||||
|
* @param con_id connection identifier for the clock
|
||||||
|
* @param fw_node point to the firmware node associated with the clock
|
||||||
|
*
|
||||||
|
* @return struct rt_clk* point to clock
|
||||||
|
*/
|
||||||
static struct rt_clk *clk_alloc(struct rt_clk_node *clk_np, const char *dev_id,
|
static struct rt_clk *clk_alloc(struct rt_clk_node *clk_np, const char *dev_id,
|
||||||
const char *con_id, void *fw_node)
|
const char *con_id, void *fw_node)
|
||||||
{
|
{
|
||||||
@ -63,6 +102,12 @@ static struct rt_clk *clk_alloc(struct rt_clk_node *clk_np, const char *dev_id,
|
|||||||
return clk;
|
return clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free memory space of clock object
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
*
|
||||||
|
*/
|
||||||
static void clk_free(struct rt_clk *clk)
|
static void clk_free(struct rt_clk *clk)
|
||||||
{
|
{
|
||||||
struct rt_clk_node *clk_np = clk->clk_np;
|
struct rt_clk_node *clk_np = clk->clk_np;
|
||||||
@ -75,6 +120,17 @@ static void clk_free(struct rt_clk *clk)
|
|||||||
rt_free(clk);
|
rt_free(clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate memory space and creat clock object
|
||||||
|
*
|
||||||
|
* @param clk_np point to clock node
|
||||||
|
* @param dev_id device identifier for the clock
|
||||||
|
* @param con_id connection identifier for the clock
|
||||||
|
* @param fw_data point to the firmware data associated with the clock
|
||||||
|
* @param fw_node point to the firmware node associated with the clock
|
||||||
|
*
|
||||||
|
* @return struct rt_clk* point to clock
|
||||||
|
*/
|
||||||
static struct rt_clk *clk_create(struct rt_clk_node *clk_np, const char *dev_id,
|
static struct rt_clk *clk_create(struct rt_clk_node *clk_np, const char *dev_id,
|
||||||
const char *con_id, void *fw_data, void *fw_node)
|
const char *con_id, void *fw_data, void *fw_node)
|
||||||
{
|
{
|
||||||
@ -96,6 +152,16 @@ static struct rt_clk *clk_create(struct rt_clk_node *clk_np, const char *dev_id,
|
|||||||
return clk;
|
return clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Notify corresponding clock from all
|
||||||
|
*
|
||||||
|
* @param clk_np point to clock node
|
||||||
|
* @param msg message identifier for the event
|
||||||
|
* @param old_rate old rate of the clock before the event
|
||||||
|
* @param new_rate new rate of the clock after the event
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on notify clock sucessfully, and other value is failed.
|
||||||
|
*/
|
||||||
static rt_err_t clk_notify(struct rt_clk_node *clk_np, rt_ubase_t msg, rt_ubase_t old_rate, rt_ubase_t new_rate)
|
static rt_err_t clk_notify(struct rt_clk_node *clk_np, rt_ubase_t msg, rt_ubase_t old_rate, rt_ubase_t new_rate)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -118,6 +184,13 @@ static rt_err_t clk_notify(struct rt_clk_node *clk_np, rt_ubase_t msg, rt_ubase_
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set parent clock
|
||||||
|
*
|
||||||
|
* @param clk_np point to clock node
|
||||||
|
* @param parent_np point to parent rt_clk
|
||||||
|
*
|
||||||
|
*/
|
||||||
static void clk_set_parent(struct rt_clk_node *clk_np, struct rt_clk_node *parent_np)
|
static void clk_set_parent(struct rt_clk_node *clk_np, struct rt_clk_node *parent_np)
|
||||||
{
|
{
|
||||||
rt_hw_spin_lock(&_clk_lock.lock);
|
rt_hw_spin_lock(&_clk_lock.lock);
|
||||||
@ -133,6 +206,15 @@ static const struct rt_clk_ops unused_clk_ops =
|
|||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register clock node into clock list
|
||||||
|
*
|
||||||
|
* @param clk_np point to child node that will be registered node.
|
||||||
|
* @param parent_np point to parent rt_clk. If it is RT_NULL, clock node will be linked to init node.
|
||||||
|
*
|
||||||
|
* @retval RT_EOK
|
||||||
|
* @retval -RT_ENOMEM
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_register(struct rt_clk_node *clk_np, struct rt_clk_node *parent_np)
|
rt_err_t rt_clk_register(struct rt_clk_node *clk_np, struct rt_clk_node *parent_np)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -190,6 +272,15 @@ rt_err_t rt_clk_register(struct rt_clk_node *clk_np, struct rt_clk_node *parent_
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unregister clock node from clock list
|
||||||
|
*
|
||||||
|
* @param clk_np point to child node that will be Unregistered node.
|
||||||
|
*
|
||||||
|
* @retval RT_EOK
|
||||||
|
* @retval -RT_EBUSY
|
||||||
|
* @retval -RT_EINVAL
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_unregister(struct rt_clk_node *clk_np)
|
rt_err_t rt_clk_unregister(struct rt_clk_node *clk_np)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -221,6 +312,15 @@ rt_err_t rt_clk_unregister(struct rt_clk_node *clk_np)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register clock notifier into notifier list
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
* @param notifier point to notifier for register
|
||||||
|
*
|
||||||
|
* @retval RT_EOK
|
||||||
|
* @retval -RT_EINVAL
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_notifier_register(struct rt_clk *clk, struct rt_clk_notifier *notifier)
|
rt_err_t rt_clk_notifier_register(struct rt_clk *clk, struct rt_clk_notifier *notifier)
|
||||||
{
|
{
|
||||||
if (!clk || !clk->clk_np || !notifier)
|
if (!clk || !clk->clk_np || !notifier)
|
||||||
@ -239,6 +339,15 @@ rt_err_t rt_clk_notifier_register(struct rt_clk *clk, struct rt_clk_notifier *no
|
|||||||
return RT_EOK;
|
return RT_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unregister clock notifier into notifier list
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
* @param notifier point to notifier for unregister
|
||||||
|
*
|
||||||
|
* @retval RT_EOK
|
||||||
|
* @retval -RT_EINVAL
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_notifier_unregister(struct rt_clk *clk, struct rt_clk_notifier *notifier)
|
rt_err_t rt_clk_notifier_unregister(struct rt_clk *clk, struct rt_clk_notifier *notifier)
|
||||||
{
|
{
|
||||||
struct rt_clk_notifier *notifier_find;
|
struct rt_clk_notifier *notifier_find;
|
||||||
@ -266,6 +375,14 @@ rt_err_t rt_clk_notifier_unregister(struct rt_clk *clk, struct rt_clk_notifier *
|
|||||||
return RT_EOK;
|
return RT_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Recursively prepare clock
|
||||||
|
*
|
||||||
|
* @param clk Ponit to clock that will be prepared
|
||||||
|
* @param clk_np Ponit to clock node that will be prepared
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on prepare clock sucessfully, and other value is failed.
|
||||||
|
*/
|
||||||
static rt_err_t clk_prepare(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
static rt_err_t clk_prepare(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -288,6 +405,13 @@ static rt_err_t clk_prepare(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prepare clock
|
||||||
|
*
|
||||||
|
* @param clk
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on prepare clock sucessfully, and other value is failed.
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_prepare(struct rt_clk *clk)
|
rt_err_t rt_clk_prepare(struct rt_clk *clk)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -306,6 +430,13 @@ rt_err_t rt_clk_prepare(struct rt_clk *clk)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Recursively unprepare clock
|
||||||
|
*
|
||||||
|
* @param clk Ponit to clock that will be unprepared
|
||||||
|
* @param clk_np Ponit to clock node that will be unprepared
|
||||||
|
*
|
||||||
|
*/
|
||||||
static void clk_unprepare(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
static void clk_unprepare(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
||||||
{
|
{
|
||||||
if (clk_np->parent)
|
if (clk_np->parent)
|
||||||
@ -341,6 +472,13 @@ rt_err_t rt_clk_unprepare(struct rt_clk *clk)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable clock
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on enable clock FOREVER.
|
||||||
|
*/
|
||||||
static rt_err_t clk_enable(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
static rt_err_t clk_enable(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -363,6 +501,13 @@ static rt_err_t clk_enable(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable clock
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on enable clock sucessfully, and other value is failed.
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_enable(struct rt_clk *clk)
|
rt_err_t rt_clk_enable(struct rt_clk *clk)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -379,6 +524,13 @@ rt_err_t rt_clk_enable(struct rt_clk *clk)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Recursively disable clock
|
||||||
|
*
|
||||||
|
* @param clk Ponit to clock that will be disabled
|
||||||
|
* @param clk_np Ponit to clock node that will be disabled
|
||||||
|
*
|
||||||
|
*/
|
||||||
static void clk_disable(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
static void clk_disable(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
||||||
{
|
{
|
||||||
if (clk_np->parent)
|
if (clk_np->parent)
|
||||||
@ -396,6 +548,12 @@ static void clk_disable(struct rt_clk *clk, struct rt_clk_node *clk_np)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable clock
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
*
|
||||||
|
*/
|
||||||
void rt_clk_disable(struct rt_clk *clk)
|
void rt_clk_disable(struct rt_clk *clk)
|
||||||
{
|
{
|
||||||
if (clk && clk->clk_np)
|
if (clk && clk->clk_np)
|
||||||
@ -408,6 +566,13 @@ void rt_clk_disable(struct rt_clk *clk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prepare and enable clock
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on prepare and enable clock sucessfully, and other value is failed.
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_prepare_enable(struct rt_clk *clk)
|
rt_err_t rt_clk_prepare_enable(struct rt_clk *clk)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -432,6 +597,12 @@ rt_err_t rt_clk_prepare_enable(struct rt_clk *clk)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable and unprepare clock
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
*
|
||||||
|
*/
|
||||||
void rt_clk_disable_unprepare(struct rt_clk *clk)
|
void rt_clk_disable_unprepare(struct rt_clk *clk)
|
||||||
{
|
{
|
||||||
RT_DEBUG_NOT_IN_INTERRUPT;
|
RT_DEBUG_NOT_IN_INTERRUPT;
|
||||||
@ -443,6 +614,13 @@ void rt_clk_disable_unprepare(struct rt_clk *clk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prepare clock array for mutipule out clock
|
||||||
|
*
|
||||||
|
* @param clk_arr point to clock array
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on prepare clock array sucessfully, and other value is failed.
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_array_prepare(struct rt_clk_array *clk_arr)
|
rt_err_t rt_clk_array_prepare(struct rt_clk_array *clk_arr)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -490,6 +668,13 @@ rt_err_t rt_clk_array_unprepare(struct rt_clk_array *clk_arr)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable clock array for mutipule out clock
|
||||||
|
*
|
||||||
|
* @param clk_arr point to clock array
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on Enable clock array sucessfully, and other value is failed.
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_array_enable(struct rt_clk_array *clk_arr)
|
rt_err_t rt_clk_array_enable(struct rt_clk_array *clk_arr)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -516,6 +701,12 @@ rt_err_t rt_clk_array_enable(struct rt_clk_array *clk_arr)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable clock array for mutipule out clock
|
||||||
|
*
|
||||||
|
* @param clk_arr point to clock array
|
||||||
|
*
|
||||||
|
*/
|
||||||
void rt_clk_array_disable(struct rt_clk_array *clk_arr)
|
void rt_clk_array_disable(struct rt_clk_array *clk_arr)
|
||||||
{
|
{
|
||||||
if (clk_arr)
|
if (clk_arr)
|
||||||
@ -527,6 +718,14 @@ void rt_clk_array_disable(struct rt_clk_array *clk_arr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prepare and enable clock array
|
||||||
|
*
|
||||||
|
* @param clk_arr point to clock array
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on prepare and enable clock array sucessfully, and other
|
||||||
|
value is failed.
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_array_prepare_enable(struct rt_clk_array *clk_arr)
|
rt_err_t rt_clk_array_prepare_enable(struct rt_clk_array *clk_arr)
|
||||||
{
|
{
|
||||||
rt_err_t err;
|
rt_err_t err;
|
||||||
@ -544,12 +743,27 @@ rt_err_t rt_clk_array_prepare_enable(struct rt_clk_array *clk_arr)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable and unprepare clock array
|
||||||
|
*
|
||||||
|
* @param clk_arr point to clock array
|
||||||
|
*
|
||||||
|
*/
|
||||||
void rt_clk_array_disable_unprepare(struct rt_clk_array *clk_arr)
|
void rt_clk_array_disable_unprepare(struct rt_clk_array *clk_arr)
|
||||||
{
|
{
|
||||||
rt_clk_array_disable(clk_arr);
|
rt_clk_array_disable(clk_arr);
|
||||||
rt_clk_array_unprepare(clk_arr);
|
rt_clk_array_unprepare(clk_arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set clock rate range
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
* @param min minimum clock rate
|
||||||
|
* @param max minimum clock rate
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on set clock rate range sucessfully, and other value is failed.
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_set_rate_range(struct rt_clk *clk, rt_ubase_t min, rt_ubase_t max)
|
rt_err_t rt_clk_set_rate_range(struct rt_clk *clk, rt_ubase_t min, rt_ubase_t max)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -590,6 +804,14 @@ rt_err_t rt_clk_set_rate_range(struct rt_clk *clk, rt_ubase_t min, rt_ubase_t ma
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set minimum clock rate
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
* @param rate miminum clock rate
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on set minimum clock rate sucessfully, and other value is failed.
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_set_min_rate(struct rt_clk *clk, rt_ubase_t rate)
|
rt_err_t rt_clk_set_min_rate(struct rt_clk *clk, rt_ubase_t rate)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -604,6 +826,14 @@ rt_err_t rt_clk_set_min_rate(struct rt_clk *clk, rt_ubase_t rate)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set maximum clock rate
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
* @param rate maximum clock rate
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on set maximum clock rate sucessfully, and other value is failed.
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_set_max_rate(struct rt_clk *clk, rt_ubase_t rate)
|
rt_err_t rt_clk_set_max_rate(struct rt_clk *clk, rt_ubase_t rate)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -618,6 +848,14 @@ rt_err_t rt_clk_set_max_rate(struct rt_clk *clk, rt_ubase_t rate)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set clock rate
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
* @param rate target rate
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on set clock rate sucessfully, and other value is failed.
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_set_rate(struct rt_clk *clk, rt_ubase_t rate)
|
rt_err_t rt_clk_set_rate(struct rt_clk *clk, rt_ubase_t rate)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -666,6 +904,13 @@ rt_err_t rt_clk_set_rate(struct rt_clk *clk, rt_ubase_t rate)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get clock rate
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
*
|
||||||
|
* @return rt_ubase_t clock rate or error code
|
||||||
|
*/
|
||||||
rt_ubase_t rt_clk_get_rate(struct rt_clk *clk)
|
rt_ubase_t rt_clk_get_rate(struct rt_clk *clk)
|
||||||
{
|
{
|
||||||
rt_ubase_t rate = 0;
|
rt_ubase_t rate = 0;
|
||||||
@ -685,6 +930,14 @@ rt_ubase_t rt_clk_get_rate(struct rt_clk *clk)
|
|||||||
return rate;
|
return rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set clock phase
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
* @param degrees target phase and the unit of phase is degree
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on set clock phase sucessfully, and other value is failed.
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_set_phase(struct rt_clk *clk, int degrees)
|
rt_err_t rt_clk_set_phase(struct rt_clk *clk, int degrees)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -701,6 +954,13 @@ rt_err_t rt_clk_set_phase(struct rt_clk *clk, int degrees)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get clock phase
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
*
|
||||||
|
* @return rt_base_t clock phase or error code
|
||||||
|
*/
|
||||||
rt_base_t rt_clk_get_phase(struct rt_clk *clk)
|
rt_base_t rt_clk_get_phase(struct rt_clk *clk)
|
||||||
{
|
{
|
||||||
rt_base_t res = RT_EOK;
|
rt_base_t res = RT_EOK;
|
||||||
@ -717,6 +977,16 @@ rt_base_t rt_clk_get_phase(struct rt_clk *clk)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if clock rate is in the minimum to maximun and get it
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
* @param rate rate will be checked
|
||||||
|
*
|
||||||
|
* @return rt_base_t get the correct rate
|
||||||
|
* @note if parameter rate less than the minimum or more than maximum, the
|
||||||
|
retrun rate will be set to minimum ormaximum value
|
||||||
|
*/
|
||||||
rt_base_t rt_clk_round_rate(struct rt_clk *clk, rt_ubase_t rate)
|
rt_base_t rt_clk_round_rate(struct rt_clk *clk, rt_ubase_t rate)
|
||||||
{
|
{
|
||||||
rt_base_t res = -RT_EINVAL;
|
rt_base_t res = -RT_EINVAL;
|
||||||
@ -761,6 +1031,14 @@ rt_base_t rt_clk_round_rate(struct rt_clk *clk, rt_ubase_t rate)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set clock parent object
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
* @param clk_parent point to parent clock
|
||||||
|
*
|
||||||
|
* @return rt_err_t RT_EOK on set clock parent sucessfully, and other value is failed.
|
||||||
|
*/
|
||||||
rt_err_t rt_clk_set_parent(struct rt_clk *clk, struct rt_clk *clk_parent)
|
rt_err_t rt_clk_set_parent(struct rt_clk *clk, struct rt_clk *clk_parent)
|
||||||
{
|
{
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
@ -777,6 +1055,14 @@ rt_err_t rt_clk_set_parent(struct rt_clk *clk, struct rt_clk *clk_parent)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get parent clock pointer
|
||||||
|
*
|
||||||
|
* @param clk child clock
|
||||||
|
*
|
||||||
|
* @return struct rt_clk* parent clock object pointer will be return, unless child
|
||||||
|
clock node havn't parent node instead return RT_NULL
|
||||||
|
*/
|
||||||
struct rt_clk *rt_clk_get_parent(struct rt_clk *clk)
|
struct rt_clk *rt_clk_get_parent(struct rt_clk *clk)
|
||||||
{
|
{
|
||||||
struct rt_clk *parent = RT_NULL;
|
struct rt_clk *parent = RT_NULL;
|
||||||
@ -795,6 +1081,14 @@ struct rt_clk *rt_clk_get_parent(struct rt_clk *clk)
|
|||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get clock array pointer from ofw device node
|
||||||
|
*
|
||||||
|
* @param dev point to dev
|
||||||
|
*
|
||||||
|
* @return struct rt_clk_array* if use ofw and under normal circumstance, it will return
|
||||||
|
clock array pointer and other value is RT_NULL
|
||||||
|
*/
|
||||||
struct rt_clk_array *rt_clk_get_array(struct rt_device *dev)
|
struct rt_clk_array *rt_clk_get_array(struct rt_device *dev)
|
||||||
{
|
{
|
||||||
struct rt_clk_array *clk_arr = RT_NULL;
|
struct rt_clk_array *clk_arr = RT_NULL;
|
||||||
@ -806,6 +1100,15 @@ struct rt_clk_array *rt_clk_get_array(struct rt_device *dev)
|
|||||||
return clk_arr;
|
return clk_arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get clock pointer from ofw device node by index
|
||||||
|
*
|
||||||
|
* @param dev point to dev
|
||||||
|
* @param index index of clock object
|
||||||
|
*
|
||||||
|
* @return struct rt_clk* if use ofw and under normal circumstance, it will return clock
|
||||||
|
pointer and other value is RT_NULL
|
||||||
|
*/
|
||||||
struct rt_clk *rt_clk_get_by_index(struct rt_device *dev, int index)
|
struct rt_clk *rt_clk_get_by_index(struct rt_device *dev, int index)
|
||||||
{
|
{
|
||||||
struct rt_clk *clk = RT_NULL;
|
struct rt_clk *clk = RT_NULL;
|
||||||
@ -817,6 +1120,15 @@ struct rt_clk *rt_clk_get_by_index(struct rt_device *dev, int index)
|
|||||||
return clk;
|
return clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get clock pointer from ofw device node by name
|
||||||
|
*
|
||||||
|
* @param dev point to dev
|
||||||
|
* @param name name of clock object
|
||||||
|
*
|
||||||
|
* @return struct rt_clk* if use ofw and under normal circumstance, it will return clock
|
||||||
|
pointer and other value is RT_NULL
|
||||||
|
*/
|
||||||
struct rt_clk *rt_clk_get_by_name(struct rt_device *dev, const char *name)
|
struct rt_clk *rt_clk_get_by_name(struct rt_device *dev, const char *name)
|
||||||
{
|
{
|
||||||
struct rt_clk *clk = RT_NULL;
|
struct rt_clk *clk = RT_NULL;
|
||||||
@ -828,6 +1140,12 @@ struct rt_clk *rt_clk_get_by_name(struct rt_device *dev, const char *name)
|
|||||||
return clk;
|
return clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Put reference count of all colock in the clock array
|
||||||
|
*
|
||||||
|
* @param clk_arr point to clock array
|
||||||
|
*
|
||||||
|
*/
|
||||||
void rt_clk_array_put(struct rt_clk_array *clk_arr)
|
void rt_clk_array_put(struct rt_clk_array *clk_arr)
|
||||||
{
|
{
|
||||||
if (clk_arr)
|
if (clk_arr)
|
||||||
@ -848,6 +1166,12 @@ void rt_clk_array_put(struct rt_clk_array *clk_arr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Put reference count of clock
|
||||||
|
*
|
||||||
|
* @param clk point to clock
|
||||||
|
*
|
||||||
|
*/
|
||||||
void rt_clk_put(struct rt_clk *clk)
|
void rt_clk_put(struct rt_clk *clk)
|
||||||
{
|
{
|
||||||
if (clk)
|
if (clk)
|
||||||
@ -858,6 +1182,16 @@ void rt_clk_put(struct rt_clk *clk)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RT_USING_OFW
|
#ifdef RT_USING_OFW
|
||||||
|
/**
|
||||||
|
* @brief Get a clock object from a device tree node without acquiring a lock
|
||||||
|
*
|
||||||
|
* @param np point to ofw node
|
||||||
|
* @param index index of clock in ofw
|
||||||
|
* @param name connection identifier for the clock
|
||||||
|
* @param locked lock flag for indicating whether the caller holds the lock
|
||||||
|
*
|
||||||
|
* @return struct rt_clk* point to the newly created clock object, or an error pointer
|
||||||
|
*/
|
||||||
static struct rt_clk *ofw_get_clk_no_lock(struct rt_ofw_node *np, int index, const char *name, rt_bool_t locked)
|
static struct rt_clk *ofw_get_clk_no_lock(struct rt_ofw_node *np, int index, const char *name, rt_bool_t locked)
|
||||||
{
|
{
|
||||||
struct rt_clk *clk = RT_NULL;
|
struct rt_clk *clk = RT_NULL;
|
||||||
@ -914,6 +1248,15 @@ static struct rt_clk *ofw_get_clk_no_lock(struct rt_ofw_node *np, int index, con
|
|||||||
return clk;
|
return clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get clock from ofw with acquiring a spin lock
|
||||||
|
*
|
||||||
|
* @param np point to ofw node
|
||||||
|
* @param index index of clock in ofw
|
||||||
|
* @param name connection identifier for the clock
|
||||||
|
*
|
||||||
|
* @return struct rt_clk* point to the newly created clock object, or an error pointer
|
||||||
|
*/
|
||||||
static struct rt_clk *ofw_get_clk(struct rt_ofw_node *np, int index, const char *name)
|
static struct rt_clk *ofw_get_clk(struct rt_ofw_node *np, int index, const char *name)
|
||||||
{
|
{
|
||||||
struct rt_clk *clk;
|
struct rt_clk *clk;
|
||||||
@ -927,6 +1270,13 @@ static struct rt_clk *ofw_get_clk(struct rt_ofw_node *np, int index, const char
|
|||||||
return clk;
|
return clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get clock array from ofw
|
||||||
|
*
|
||||||
|
* @param np point to ofw node
|
||||||
|
*
|
||||||
|
* @return struct rt_clk_array* point to the newly created clock array, or an error pointer
|
||||||
|
*/
|
||||||
struct rt_clk_array *rt_ofw_get_clk_array(struct rt_ofw_node *np)
|
struct rt_clk_array *rt_ofw_get_clk_array(struct rt_ofw_node *np)
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
@ -984,6 +1334,14 @@ struct rt_clk_array *rt_ofw_get_clk_array(struct rt_ofw_node *np)
|
|||||||
return clk_arr;
|
return clk_arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get clock from ofw with acquiring a spin lock by index and node pointer
|
||||||
|
*
|
||||||
|
* @param np point to ofw node
|
||||||
|
* @param index index of clock in ofw
|
||||||
|
*
|
||||||
|
* @return struct rt_clk* point to the newly created clock object, or an error pointer
|
||||||
|
*/
|
||||||
struct rt_clk *rt_ofw_get_clk(struct rt_ofw_node *np, int index)
|
struct rt_clk *rt_ofw_get_clk(struct rt_ofw_node *np, int index)
|
||||||
{
|
{
|
||||||
struct rt_clk *clk = RT_NULL;
|
struct rt_clk *clk = RT_NULL;
|
||||||
@ -996,6 +1354,14 @@ struct rt_clk *rt_ofw_get_clk(struct rt_ofw_node *np, int index)
|
|||||||
return clk;
|
return clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get clock from ofw with acquiring a spin lock by name
|
||||||
|
*
|
||||||
|
* @param np point to ofw node
|
||||||
|
* @param name name of clock will be returned
|
||||||
|
*
|
||||||
|
* @return struct rt_clk* point to the newly created clock object, or an error pointer
|
||||||
|
*/
|
||||||
struct rt_clk *rt_ofw_get_clk_by_name(struct rt_ofw_node *np, const char *name)
|
struct rt_clk *rt_ofw_get_clk_by_name(struct rt_ofw_node *np, const char *name)
|
||||||
{
|
{
|
||||||
struct rt_clk *clk = RT_NULL;
|
struct rt_clk *clk = RT_NULL;
|
||||||
@ -1013,6 +1379,13 @@ struct rt_clk *rt_ofw_get_clk_by_name(struct rt_ofw_node *np, const char *name)
|
|||||||
return clk;
|
return clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Count number of clocks in ofw
|
||||||
|
*
|
||||||
|
* @param clk_ofw_np point to ofw node
|
||||||
|
*
|
||||||
|
* @return rt_ssize_t number of clocks
|
||||||
|
*/
|
||||||
rt_ssize_t rt_ofw_count_of_clk(struct rt_ofw_node *clk_ofw_np)
|
rt_ssize_t rt_ofw_count_of_clk(struct rt_ofw_node *clk_ofw_np)
|
||||||
{
|
{
|
||||||
if (clk_ofw_np)
|
if (clk_ofw_np)
|
||||||
@ -1080,4 +1453,7 @@ rt_ssize_t rt_ofw_count_of_clk(struct rt_ofw_node *clk_ofw_np)
|
|||||||
|
|
||||||
return -RT_EINVAL;
|
return -RT_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* RT_USING_OFW */
|
#endif /* RT_USING_OFW */
|
||||||
|
|
||||||
|
/**@}*/
|
@ -31,9 +31,9 @@
|
|||||||
#include <rtdevice.h> /* for wqueue_init */
|
#include <rtdevice.h> /* for wqueue_init */
|
||||||
#endif /* RT_USING_POSIX_DEVIO */
|
#endif /* RT_USING_POSIX_DEVIO */
|
||||||
|
|
||||||
#ifdef RT_USING_DFS_V2
|
#if defined (RT_USING_DFS_V2) && defined (RT_USING_DFS_DEVFS)
|
||||||
#include <devfs.h>
|
#include <devfs.h>
|
||||||
#endif /* RT_USING_DFS_V2 */
|
#endif /* RT_USING_DFS_V2 RT_USING_DFS_DEVFS */
|
||||||
|
|
||||||
#ifdef RT_USING_DEVICE
|
#ifdef RT_USING_DEVICE
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ rt_err_t rt_device_register(rt_device_t dev,
|
|||||||
rt_wqueue_init(&(dev->wait_queue));
|
rt_wqueue_init(&(dev->wait_queue));
|
||||||
#endif /* RT_USING_POSIX_DEVIO */
|
#endif /* RT_USING_POSIX_DEVIO */
|
||||||
|
|
||||||
#ifdef RT_USING_DFS_V2
|
#if defined (RT_USING_DFS_V2) && defined (RT_USING_DFS_DEVFS)
|
||||||
dfs_devfs_device_add(dev);
|
dfs_devfs_device_add(dev);
|
||||||
#endif /* RT_USING_DFS_V2 */
|
#endif /* RT_USING_DFS_V2 */
|
||||||
|
|
||||||
|
@ -17,203 +17,227 @@ if RT_USING_I2C
|
|||||||
default n
|
default n
|
||||||
endif
|
endif
|
||||||
|
|
||||||
config RT_USING_SOFT_I2C
|
menuconfig RT_USING_SOFT_I2C
|
||||||
bool "Use GPIO to soft simulate I2C"
|
bool "Use GPIO to soft simulate I2C"
|
||||||
default n
|
default n
|
||||||
select RT_USING_PIN
|
select RT_USING_PIN
|
||||||
select RT_USING_I2C_BITOPS
|
select RT_USING_I2C_BITOPS
|
||||||
if RT_USING_SOFT_I2C
|
if RT_USING_SOFT_I2C
|
||||||
config RT_USING_SOFT_I2C1
|
menuconfig RT_USING_SOFT_I2C0
|
||||||
bool "Enable I2C1 Bus (software simulation)"
|
bool "Enable I2C0 Bus (software simulation)"
|
||||||
default y
|
default y
|
||||||
if RT_USING_SOFT_I2C1
|
if RT_USING_SOFT_I2C0
|
||||||
config RT_SOFT_I2C1_SCL_PIN
|
config RT_SOFT_I2C0_SCL_PIN
|
||||||
int "SCL pin number"
|
int "SCL pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 1
|
default 1
|
||||||
config RT_SOFT_I2C1_SDA_PIN
|
config RT_SOFT_I2C0_SDA_PIN
|
||||||
int "SDA pin number"
|
int "SDA pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 2
|
default 2
|
||||||
config RT_SOFT_I2C1_BUS_NAME
|
config RT_SOFT_I2C0_BUS_NAME
|
||||||
string "Bus name"
|
string "Bus name"
|
||||||
default "i2c1"
|
default "i2c0"
|
||||||
config RT_SOFT_I2C1_TIMING_DELAY
|
config RT_SOFT_I2C0_TIMING_DELAY
|
||||||
int "Timing delay (us)"
|
int "Timing delay (us)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
config RT_SOFT_I2C1_TIMING_TIMEOUT
|
config RT_SOFT_I2C0_TIMING_TIMEOUT
|
||||||
int "Timing timeout (tick)"
|
int "Timing timeout (tick)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
endif
|
endif
|
||||||
config RT_USING_SOFT_I2C2
|
menuconfig RT_USING_SOFT_I2C1
|
||||||
bool "Enable I2C2 Bus (software simulation)"
|
bool "Enable I2C1 Bus (software simulation)"
|
||||||
default n
|
default y
|
||||||
if RT_USING_SOFT_I2C2
|
if RT_USING_SOFT_I2C1
|
||||||
config RT_SOFT_I2C2_SCL_PIN
|
config RT_SOFT_I2C1_SCL_PIN
|
||||||
int "SCL pin number"
|
int "SCL pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 3
|
default 3
|
||||||
config RT_SOFT_I2C2_SDA_PIN
|
config RT_SOFT_I2C1_SDA_PIN
|
||||||
int "SDA pin number"
|
int "SDA pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 4
|
default 4
|
||||||
config RT_SOFT_I2C2_BUS_NAME
|
config RT_SOFT_I2C1_BUS_NAME
|
||||||
string "Bus name"
|
string "Bus name"
|
||||||
default "i2c2"
|
default "i2c1"
|
||||||
config RT_SOFT_I2C2_TIMING_DELAY
|
config RT_SOFT_I2C1_TIMING_DELAY
|
||||||
int "Timing delay (us)"
|
int "Timing delay (us)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
config RT_SOFT_I2C2_TIMING_TIMEOUT
|
config RT_SOFT_I2C1_TIMING_TIMEOUT
|
||||||
int "Timing timeout (tick)"
|
int "Timing timeout (tick)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
endif
|
endif
|
||||||
config RT_USING_SOFT_I2C3
|
menuconfig RT_USING_SOFT_I2C2
|
||||||
bool "Enable I2C3 Bus (software simulation)"
|
bool "Enable I2C2 Bus (software simulation)"
|
||||||
default n
|
default n
|
||||||
if RT_USING_SOFT_I2C3
|
if RT_USING_SOFT_I2C2
|
||||||
config RT_SOFT_I2C3_SCL_PIN
|
config RT_SOFT_I2C2_SCL_PIN
|
||||||
int "SCL pin number"
|
int "SCL pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 5
|
default 5
|
||||||
config RT_SOFT_I2C3_SDA_PIN
|
config RT_SOFT_I2C2_SDA_PIN
|
||||||
int "SDA pin number"
|
int "SDA pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 6
|
default 6
|
||||||
config RT_SOFT_I2C3_BUS_NAME
|
config RT_SOFT_I2C2_BUS_NAME
|
||||||
string "Bus name"
|
string "Bus name"
|
||||||
default "i2c3"
|
default "i2c2"
|
||||||
config RT_SOFT_I2C3_TIMING_DELAY
|
config RT_SOFT_I2C2_TIMING_DELAY
|
||||||
int "Timing delay (us)"
|
int "Timing delay (us)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
config RT_SOFT_I2C3_TIMING_TIMEOUT
|
config RT_SOFT_I2C2_TIMING_TIMEOUT
|
||||||
int "Timing timeout (tick)"
|
int "Timing timeout (tick)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
endif
|
endif
|
||||||
config RT_USING_SOFT_I2C4
|
menuconfig RT_USING_SOFT_I2C3
|
||||||
bool "Enable I2C4 Bus (software simulation)"
|
bool "Enable I2C3 Bus (software simulation)"
|
||||||
default n
|
default n
|
||||||
if RT_USING_SOFT_I2C4
|
if RT_USING_SOFT_I2C3
|
||||||
config RT_SOFT_I2C4_SCL_PIN
|
config RT_SOFT_I2C3_SCL_PIN
|
||||||
int "SCL pin number"
|
int "SCL pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 7
|
default 7
|
||||||
config RT_SOFT_I2C4_SDA_PIN
|
config RT_SOFT_I2C3_SDA_PIN
|
||||||
int "SDA pin number"
|
int "SDA pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 8
|
default 8
|
||||||
config RT_SOFT_I2C4_BUS_NAME
|
config RT_SOFT_I2C3_BUS_NAME
|
||||||
string "Bus name"
|
string "Bus name"
|
||||||
default "i2c4"
|
default "i2c3"
|
||||||
config RT_SOFT_I2C4_TIMING_DELAY
|
config RT_SOFT_I2C3_TIMING_DELAY
|
||||||
int "Timing delay (us)"
|
int "Timing delay (us)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
config RT_SOFT_I2C4_TIMING_TIMEOUT
|
config RT_SOFT_I2C3_TIMING_TIMEOUT
|
||||||
int "Timing timeout (tick)"
|
int "Timing timeout (tick)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
endif
|
endif
|
||||||
config RT_USING_SOFT_I2C5
|
menuconfig RT_USING_SOFT_I2C4
|
||||||
bool "Enable I2C5 Bus (software simulation)"
|
bool "Enable I2C4 Bus (software simulation)"
|
||||||
default n
|
default n
|
||||||
if RT_USING_SOFT_I2C5
|
if RT_USING_SOFT_I2C4
|
||||||
config RT_SOFT_I2C5_SCL_PIN
|
config RT_SOFT_I2C4_SCL_PIN
|
||||||
int "SCL pin number"
|
int "SCL pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 9
|
default 9
|
||||||
config RT_SOFT_I2C5_SDA_PIN
|
config RT_SOFT_I2C4_SDA_PIN
|
||||||
int "SDA pin number"
|
int "SDA pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
config RT_SOFT_I2C5_BUS_NAME
|
config RT_SOFT_I2C4_BUS_NAME
|
||||||
string "Bus name"
|
string "Bus name"
|
||||||
default "i2c5"
|
default "i2c4"
|
||||||
config RT_SOFT_I2C5_TIMING_DELAY
|
config RT_SOFT_I2C4_TIMING_DELAY
|
||||||
int "Timing delay (us)"
|
int "Timing delay (us)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
config RT_SOFT_I2C5_TIMING_TIMEOUT
|
config RT_SOFT_I2C4_TIMING_TIMEOUT
|
||||||
int "Timing timeout (tick)"
|
int "Timing timeout (tick)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
endif
|
endif
|
||||||
config RT_USING_SOFT_I2C6
|
menuconfig RT_USING_SOFT_I2C5
|
||||||
bool "Enable I2C6 Bus (software simulation)"
|
bool "Enable I2C5 Bus (software simulation)"
|
||||||
default n
|
default n
|
||||||
if RT_USING_SOFT_I2C6
|
if RT_USING_SOFT_I2C5
|
||||||
config RT_SOFT_I2C6_SCL_PIN
|
config RT_SOFT_I2C5_SCL_PIN
|
||||||
int "SCL pin number"
|
int "SCL pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 11
|
default 11
|
||||||
config RT_SOFT_I2C6_SDA_PIN
|
config RT_SOFT_I2C5_SDA_PIN
|
||||||
int "SDA pin number"
|
int "SDA pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 12
|
default 12
|
||||||
config RT_SOFT_I2C6_BUS_NAME
|
config RT_SOFT_I2C5_BUS_NAME
|
||||||
string "Bus name"
|
string "Bus name"
|
||||||
default "i2c6"
|
default "i2c5"
|
||||||
config RT_SOFT_I2C6_TIMING_DELAY
|
config RT_SOFT_I2C5_TIMING_DELAY
|
||||||
int "Timing delay (us)"
|
int "Timing delay (us)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
config RT_SOFT_I2C6_TIMING_TIMEOUT
|
config RT_SOFT_I2C5_TIMING_TIMEOUT
|
||||||
int "Timing timeout (tick)"
|
int "Timing timeout (tick)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
endif
|
endif
|
||||||
config RT_USING_SOFT_I2C7
|
menuconfig RT_USING_SOFT_I2C6
|
||||||
bool "Enable I2C7 Bus (software simulation)"
|
bool "Enable I2C6 Bus (software simulation)"
|
||||||
default n
|
default n
|
||||||
if RT_USING_SOFT_I2C7
|
if RT_USING_SOFT_I2C6
|
||||||
config RT_SOFT_I2C7_SCL_PIN
|
config RT_SOFT_I2C6_SCL_PIN
|
||||||
int "SCL pin number"
|
int "SCL pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 13
|
default 13
|
||||||
config RT_SOFT_I2C7_SDA_PIN
|
config RT_SOFT_I2C6_SDA_PIN
|
||||||
int "SDA pin number"
|
int "SDA pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 14
|
default 14
|
||||||
config RT_SOFT_I2C7_BUS_NAME
|
config RT_SOFT_I2C6_BUS_NAME
|
||||||
string "Bus name"
|
string "Bus name"
|
||||||
default "i2c7"
|
default "i2c6"
|
||||||
config RT_SOFT_I2C7_TIMING_DELAY
|
config RT_SOFT_I2C6_TIMING_DELAY
|
||||||
int "Timing delay (us)"
|
int "Timing delay (us)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
config RT_SOFT_I2C7_TIMING_TIMEOUT
|
config RT_SOFT_I2C6_TIMING_TIMEOUT
|
||||||
int "Timing timeout (tick)"
|
int "Timing timeout (tick)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
endif
|
endif
|
||||||
config RT_USING_SOFT_I2C8
|
menuconfig RT_USING_SOFT_I2C7
|
||||||
bool "Enable I2C8 Bus (software simulation)"
|
bool "Enable I2C7 Bus (software simulation)"
|
||||||
default n
|
default n
|
||||||
if RT_USING_SOFT_I2C8
|
if RT_USING_SOFT_I2C7
|
||||||
config RT_SOFT_I2C8_SCL_PIN
|
config RT_SOFT_I2C7_SCL_PIN
|
||||||
int "SCL pin number"
|
int "SCL pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 15
|
default 15
|
||||||
config RT_SOFT_I2C8_SDA_PIN
|
config RT_SOFT_I2C7_SDA_PIN
|
||||||
int "SDA pin number"
|
int "SDA pin number"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 16
|
default 16
|
||||||
config RT_SOFT_I2C8_BUS_NAME
|
config RT_SOFT_I2C7_BUS_NAME
|
||||||
string "Bus name"
|
string "Bus name"
|
||||||
default "i2c8"
|
default "i2c7"
|
||||||
config RT_SOFT_I2C8_TIMING_DELAY
|
config RT_SOFT_I2C7_TIMING_DELAY
|
||||||
int "Timing delay (us)"
|
int "Timing delay (us)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
config RT_SOFT_I2C8_TIMING_TIMEOUT
|
config RT_SOFT_I2C7_TIMING_TIMEOUT
|
||||||
int "Timing timeout (tick)"
|
int "Timing timeout (tick)"
|
||||||
range 0 32767
|
range 0 32767
|
||||||
default 10
|
default 10
|
||||||
endif
|
endif
|
||||||
endif
|
menuconfig RT_USING_SOFT_I2C8
|
||||||
|
bool "Enable I2C8 Bus (software simulation)"
|
||||||
|
default n
|
||||||
|
if RT_USING_SOFT_I2C8
|
||||||
|
config RT_SOFT_I2C8_SCL_PIN
|
||||||
|
int "SCL pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 17
|
||||||
|
config RT_SOFT_I2C8_SDA_PIN
|
||||||
|
int "SDA pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 18
|
||||||
|
config RT_SOFT_I2C8_BUS_NAME
|
||||||
|
string "Bus name"
|
||||||
|
default "i2c8"
|
||||||
|
config RT_SOFT_I2C8_TIMING_DELAY
|
||||||
|
int "Timing delay (us)"
|
||||||
|
range 0 32767
|
||||||
|
default 10
|
||||||
|
config RT_SOFT_I2C8_TIMING_TIMEOUT
|
||||||
|
int "Timing timeout (tick)"
|
||||||
|
range 0 32767
|
||||||
|
default 10
|
||||||
|
endif
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
#include <rtdevice.h>
|
#include <rtdevice.h>
|
||||||
|
|
||||||
#ifdef RT_USING_SOFT_I2C
|
#ifdef RT_USING_SOFT_I2C
|
||||||
#if !defined(RT_USING_SOFT_I2C1) && !defined(RT_USING_SOFT_I2C2) &&\
|
#if !defined(RT_USING_SOFT_I2C0) &&\
|
||||||
|
!defined(RT_USING_SOFT_I2C1) && !defined(RT_USING_SOFT_I2C2) &&\
|
||||||
!defined(RT_USING_SOFT_I2C3) && !defined(RT_USING_SOFT_I2C4) &&\
|
!defined(RT_USING_SOFT_I2C3) && !defined(RT_USING_SOFT_I2C4) &&\
|
||||||
!defined(RT_USING_SOFT_I2C5) && !defined(RT_USING_SOFT_I2C6) &&\
|
!defined(RT_USING_SOFT_I2C5) && !defined(RT_USING_SOFT_I2C6) &&\
|
||||||
!defined(RT_USING_SOFT_I2C7) && !defined(RT_USING_SOFT_I2C8)
|
!defined(RT_USING_SOFT_I2C7) && !defined(RT_USING_SOFT_I2C8)
|
||||||
@ -48,6 +49,15 @@ struct rt_soft_i2c
|
|||||||
|
|
||||||
struct soft_i2c_config i2c_cfg[] =
|
struct soft_i2c_config i2c_cfg[] =
|
||||||
{
|
{
|
||||||
|
#ifdef RT_USING_SOFT_I2C0
|
||||||
|
{
|
||||||
|
.scl_pin = RT_SOFT_I2C0_SCL_PIN,
|
||||||
|
.sda_pin = RT_SOFT_I2C0_SDA_PIN,
|
||||||
|
.bus_name = RT_SOFT_I2C0_BUS_NAME,
|
||||||
|
.timing_delay = RT_SOFT_I2C0_TIMING_DELAY,
|
||||||
|
.timing_timeout = RT_SOFT_I2C0_TIMING_TIMEOUT,
|
||||||
|
},
|
||||||
|
#endif //RT_USING_SOFT_I2C0
|
||||||
#ifdef RT_USING_SOFT_I2C1
|
#ifdef RT_USING_SOFT_I2C1
|
||||||
{
|
{
|
||||||
.scl_pin = RT_SOFT_I2C1_SCL_PIN,
|
.scl_pin = RT_SOFT_I2C1_SCL_PIN,
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
* Copyright (c) 2006-2025 RT-Thread Development Team
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2023-02-25 GuEe-GUI first version
|
* 2023-02-25 GuEe-GUI first version
|
||||||
|
* 2025-01-24 wumingzi add doxygen comment
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __BLK_H__
|
#ifndef __BLK_H__
|
||||||
@ -15,10 +16,22 @@
|
|||||||
#include <rtthread.h>
|
#include <rtthread.h>
|
||||||
#include <drivers/classes/block.h>
|
#include <drivers/classes/block.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup Drivers RTTHREAD Driver
|
||||||
|
* @defgroup blk blk
|
||||||
|
* @brief blk driver api
|
||||||
|
* @ingroup Drivers
|
||||||
|
* @addtogroup blk
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
struct rt_dm_ida;
|
struct rt_dm_ida;
|
||||||
struct rt_blk_device;
|
struct rt_blk_device;
|
||||||
struct rt_blk_disk_ops;
|
struct rt_blk_disk_ops;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Physical blk device
|
||||||
|
*/
|
||||||
struct rt_blk_disk
|
struct rt_blk_disk
|
||||||
{
|
{
|
||||||
struct rt_device parent;
|
struct rt_device parent;
|
||||||
@ -44,6 +57,9 @@ struct rt_blk_disk
|
|||||||
struct rt_semaphore usr_lock;
|
struct rt_semaphore usr_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure the blk device.
|
||||||
|
*/
|
||||||
struct rt_blk_disk_ops
|
struct rt_blk_disk_ops
|
||||||
{
|
{
|
||||||
rt_ssize_t (*read)(struct rt_blk_disk *disk, rt_off_t sector, void *buffer,
|
rt_ssize_t (*read)(struct rt_blk_disk *disk, rt_off_t sector, void *buffer,
|
||||||
@ -60,6 +76,9 @@ struct rt_blk_disk_ops
|
|||||||
#ifndef __DFS_H__
|
#ifndef __DFS_H__
|
||||||
#include <dfs_fs.h>
|
#include <dfs_fs.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Logical blk device, if you don't used DFS it will be defined by default.
|
||||||
|
*/
|
||||||
struct rt_blk_device
|
struct rt_blk_device
|
||||||
{
|
{
|
||||||
struct rt_device parent;
|
struct rt_device parent;
|
||||||
@ -77,11 +96,41 @@ struct rt_blk_device
|
|||||||
struct rt_blk_device;
|
struct rt_blk_device;
|
||||||
#endif /* __DFS_H__ */
|
#endif /* __DFS_H__ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register the blk disk device
|
||||||
|
* @param disk Point to blk disk
|
||||||
|
* @return rt_err_t error code
|
||||||
|
*/
|
||||||
rt_err_t rt_hw_blk_disk_register(struct rt_blk_disk *disk);
|
rt_err_t rt_hw_blk_disk_register(struct rt_blk_disk *disk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unregister the blk disk device
|
||||||
|
* @param disk Point to blk disk
|
||||||
|
* @return rt_err_t error code
|
||||||
|
*/
|
||||||
rt_err_t rt_hw_blk_disk_unregister(struct rt_blk_disk *disk);
|
rt_err_t rt_hw_blk_disk_unregister(struct rt_blk_disk *disk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Probe and register the blk disk partition
|
||||||
|
* @param disk Point to blk disk
|
||||||
|
* @return rt_err_t error code
|
||||||
|
*/
|
||||||
rt_err_t rt_blk_disk_probe_partition(struct rt_blk_disk *disk);
|
rt_err_t rt_blk_disk_probe_partition(struct rt_blk_disk *disk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the blk disk capacity
|
||||||
|
* @param disk Point to blk disk
|
||||||
|
* @return rt_ssize_t sector count or error code
|
||||||
|
*/
|
||||||
rt_ssize_t rt_blk_disk_get_capacity(struct rt_blk_disk *disk);
|
rt_ssize_t rt_blk_disk_get_capacity(struct rt_blk_disk *disk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the sector size
|
||||||
|
* @param disk Point to blk disk
|
||||||
|
* @return rt_ssize_t bytes per sector or error code
|
||||||
|
*/
|
||||||
rt_ssize_t rt_blk_disk_get_logical_block_size(struct rt_blk_disk *disk);
|
rt_ssize_t rt_blk_disk_get_logical_block_size(struct rt_blk_disk *disk);
|
||||||
|
|
||||||
#endif /* __BLK_H__ */
|
/*! @}*/
|
||||||
|
|
||||||
|
#endif /* __BLK_H__ */
|
@ -1,11 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
* Copyright (c) 2006-2025 RT-Thread Development Team
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2022-11-26 GuEe-GUI first version
|
* 2022-11-26 GuEe-GUI first version
|
||||||
|
* 2025-01-24 wumingzi add doxygen comment
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CLK_H__
|
#ifndef __CLK_H__
|
||||||
@ -16,29 +17,40 @@
|
|||||||
#include <ref.h>
|
#include <ref.h>
|
||||||
#include <drivers/ofw.h>
|
#include <drivers/ofw.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup Drivers RTTHREAD Driver
|
||||||
|
* @defgroup clk clk
|
||||||
|
* @brief clk driver api
|
||||||
|
* @ingroup Drivers
|
||||||
|
* @addtogroup clk
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
#define RT_CLK_NODE_OBJ_NAME "CLKNP"
|
#define RT_CLK_NODE_OBJ_NAME "CLKNP"
|
||||||
|
|
||||||
struct rt_clk_ops;
|
struct rt_clk_ops;
|
||||||
struct rt_reset_control_node;
|
struct rt_reset_control_node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clk node, it is a pat of clk source or controller
|
||||||
|
* @note Defined as the array like this if the CLK have multi out clocks:
|
||||||
|
* @code{.c}
|
||||||
|
* struct XYZ_single_clk
|
||||||
|
* {
|
||||||
|
* struct rt_clk_node parent;
|
||||||
|
* ...
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* struct XYZ_multi_clk
|
||||||
|
* {
|
||||||
|
* struct rt_clk_node parent[N];
|
||||||
|
* ...
|
||||||
|
* };
|
||||||
|
* @endcode
|
||||||
|
* We assume the 'N' is the max value of element in 'clock-indices' if OFW.
|
||||||
|
*/
|
||||||
struct rt_clk_node
|
struct rt_clk_node
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Defined as the array like this if if the CLK have multi out clocks:
|
|
||||||
*
|
|
||||||
* struct XYZ_single_clk
|
|
||||||
* {
|
|
||||||
* struct rt_clk_node parent;
|
|
||||||
* ...
|
|
||||||
* };
|
|
||||||
*
|
|
||||||
* struct XYZ_multi_clk
|
|
||||||
* {
|
|
||||||
* struct rt_clk_node parent[N];
|
|
||||||
* ...
|
|
||||||
* };
|
|
||||||
* We assume the 'N' is the max value of element in 'clock-indices' if OFW.
|
|
||||||
*/
|
|
||||||
struct rt_object rt_parent;
|
struct rt_object rt_parent;
|
||||||
|
|
||||||
rt_list_t list;
|
rt_list_t list;
|
||||||
@ -62,6 +74,9 @@ struct rt_clk_node
|
|||||||
rt_size_t multi_clk;
|
rt_size_t multi_clk;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constant rate clk
|
||||||
|
*/
|
||||||
struct rt_clk_fixed_rate
|
struct rt_clk_fixed_rate
|
||||||
{
|
{
|
||||||
struct rt_clk_node clk;
|
struct rt_clk_node clk;
|
||||||
@ -70,6 +85,9 @@ struct rt_clk_fixed_rate
|
|||||||
rt_ubase_t fixed_accuracy;
|
rt_ubase_t fixed_accuracy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clk object, it can be clk source or controller
|
||||||
|
*/
|
||||||
struct rt_clk
|
struct rt_clk
|
||||||
{
|
{
|
||||||
struct rt_clk_node *clk_np;
|
struct rt_clk_node *clk_np;
|
||||||
@ -85,6 +103,9 @@ struct rt_clk
|
|||||||
void *priv;
|
void *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clk array
|
||||||
|
*/
|
||||||
struct rt_clk_array
|
struct rt_clk_array
|
||||||
{
|
{
|
||||||
rt_size_t count;
|
rt_size_t count;
|
||||||
@ -118,6 +139,9 @@ struct rt_clk_notifier;
|
|||||||
typedef rt_err_t (*rt_clk_notifier_callback)(struct rt_clk_notifier *notifier,
|
typedef rt_err_t (*rt_clk_notifier_callback)(struct rt_clk_notifier *notifier,
|
||||||
rt_ubase_t msg, rt_ubase_t old_rate, rt_ubase_t new_rate);
|
rt_ubase_t msg, rt_ubase_t old_rate, rt_ubase_t new_rate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clock notifier, it containers of clock list and callback function
|
||||||
|
*/
|
||||||
struct rt_clk_notifier
|
struct rt_clk_notifier
|
||||||
{
|
{
|
||||||
rt_list_t list;
|
rt_list_t list;
|
||||||
@ -192,4 +216,6 @@ rt_inline rt_ssize_t rt_ofw_count_of_clk(struct rt_ofw_node *clk_ofw_np)
|
|||||||
}
|
}
|
||||||
#endif /* RT_USING_OFW */
|
#endif /* RT_USING_OFW */
|
||||||
|
|
||||||
#endif /* __CLK_H__ */
|
/*! @}*/
|
||||||
|
|
||||||
|
#endif /* __CLK_H__ */
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <rtdef.h>
|
#include <rtdef.h>
|
||||||
#include <rtconfig.h>
|
#include <rtconfig.h>
|
||||||
|
#include "completion.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -42,6 +43,7 @@ struct rt_workqueue
|
|||||||
struct rt_semaphore sem;
|
struct rt_semaphore sem;
|
||||||
rt_thread_t work_thread;
|
rt_thread_t work_thread;
|
||||||
struct rt_spinlock spinlock;
|
struct rt_spinlock spinlock;
|
||||||
|
struct rt_completion wakeup_completion;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rt_work
|
struct rt_work
|
||||||
@ -52,7 +54,7 @@ struct rt_work
|
|||||||
void *work_data;
|
void *work_data;
|
||||||
rt_uint16_t flags;
|
rt_uint16_t flags;
|
||||||
rt_uint16_t type;
|
rt_uint16_t type;
|
||||||
struct rt_timer timer;
|
rt_tick_t timeout_tick;
|
||||||
struct rt_workqueue *workqueue;
|
struct rt_workqueue *workqueue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@ -10,6 +10,7 @@
|
|||||||
* 2021-08-14 Jackistang add comments for function interface
|
* 2021-08-14 Jackistang add comments for function interface
|
||||||
* 2022-01-16 Meco Man add rt_work_urgent()
|
* 2022-01-16 Meco Man add rt_work_urgent()
|
||||||
* 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
|
* 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
|
||||||
|
* 2024-12-21 yuqingli delete timer, using list
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <rthw.h>
|
#include <rthw.h>
|
||||||
@ -17,8 +18,6 @@
|
|||||||
|
|
||||||
#ifdef RT_USING_HEAP
|
#ifdef RT_USING_HEAP
|
||||||
|
|
||||||
static void _delayed_work_timeout_handler(void *parameter);
|
|
||||||
|
|
||||||
rt_inline rt_err_t _workqueue_work_completion(struct rt_workqueue *queue)
|
rt_inline rt_err_t _workqueue_work_completion(struct rt_workqueue *queue)
|
||||||
{
|
{
|
||||||
rt_err_t result;
|
rt_err_t result;
|
||||||
@ -50,38 +49,61 @@ rt_inline rt_err_t _workqueue_work_completion(struct rt_workqueue *queue)
|
|||||||
|
|
||||||
static void _workqueue_thread_entry(void *parameter)
|
static void _workqueue_thread_entry(void *parameter)
|
||||||
{
|
{
|
||||||
rt_base_t level;
|
rt_base_t level;
|
||||||
struct rt_work *work;
|
struct rt_work *work;
|
||||||
struct rt_workqueue *queue;
|
struct rt_workqueue *queue;
|
||||||
|
rt_tick_t current_tick;
|
||||||
|
rt_int32_t delay_tick;
|
||||||
|
void (*work_func)(struct rt_work *work, void *work_data);
|
||||||
|
void *work_data;
|
||||||
|
|
||||||
queue = (struct rt_workqueue *) parameter;
|
queue = (struct rt_workqueue *)parameter;
|
||||||
RT_ASSERT(queue != RT_NULL);
|
RT_ASSERT(queue != RT_NULL);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
level = rt_spin_lock_irqsave(&(queue->spinlock));
|
level = rt_spin_lock_irqsave(&(queue->spinlock));
|
||||||
|
|
||||||
|
/* timer check */
|
||||||
|
current_tick = rt_tick_get();
|
||||||
|
delay_tick = RT_WAITING_FOREVER;
|
||||||
|
while (!rt_list_isempty(&(queue->delayed_list)))
|
||||||
|
{
|
||||||
|
work = rt_list_entry(queue->delayed_list.next, struct rt_work, list);
|
||||||
|
if ((current_tick - work->timeout_tick) < RT_TICK_MAX / 2)
|
||||||
|
{
|
||||||
|
rt_list_remove(&(work->list));
|
||||||
|
rt_list_insert_after(queue->work_list.prev, &(work->list));
|
||||||
|
work->flags &= ~RT_WORK_STATE_SUBMITTING;
|
||||||
|
work->flags |= RT_WORK_STATE_PENDING;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delay_tick = work->timeout_tick - current_tick;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (rt_list_isempty(&(queue->work_list)))
|
if (rt_list_isempty(&(queue->work_list)))
|
||||||
{
|
{
|
||||||
/* no software timer exist, suspend self. */
|
|
||||||
rt_thread_suspend_with_flag(rt_thread_self(), RT_UNINTERRUPTIBLE);
|
|
||||||
|
|
||||||
/* release lock after suspend so we will not lost any wakeups */
|
|
||||||
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
||||||
|
/* wait for work completion */
|
||||||
rt_schedule();
|
rt_completion_wait(&(queue->wakeup_completion), delay_tick);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we have work to do with. */
|
/* we have work to do with. */
|
||||||
work = rt_list_entry(queue->work_list.next, struct rt_work, list);
|
work = rt_list_entry(queue->work_list.next, struct rt_work, list);
|
||||||
rt_list_remove(&(work->list));
|
rt_list_remove(&(work->list));
|
||||||
queue->work_current = work;
|
queue->work_current = work;
|
||||||
work->flags &= ~RT_WORK_STATE_PENDING;
|
work->flags &= ~RT_WORK_STATE_PENDING;
|
||||||
work->workqueue = RT_NULL;
|
work->workqueue = RT_NULL;
|
||||||
|
work_func = work->work_func;
|
||||||
|
work_data = work->work_data;
|
||||||
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
||||||
|
|
||||||
/* do work */
|
/* do work */
|
||||||
work->work_func(work, work->work_data);
|
work_func(work, work_data);
|
||||||
/* clean current work */
|
/* clean current work */
|
||||||
queue->work_current = RT_NULL;
|
queue->work_current = RT_NULL;
|
||||||
|
|
||||||
@ -93,52 +115,52 @@ static void _workqueue_thread_entry(void *parameter)
|
|||||||
static rt_err_t _workqueue_submit_work(struct rt_workqueue *queue,
|
static rt_err_t _workqueue_submit_work(struct rt_workqueue *queue,
|
||||||
struct rt_work *work, rt_tick_t ticks)
|
struct rt_work *work, rt_tick_t ticks)
|
||||||
{
|
{
|
||||||
rt_base_t level;
|
rt_base_t level;
|
||||||
rt_err_t err = RT_EOK;
|
rt_err_t err = RT_EOK;
|
||||||
|
struct rt_work *work_tmp;
|
||||||
|
rt_list_t *list_tmp;
|
||||||
|
|
||||||
level = rt_spin_lock_irqsave(&(queue->spinlock));
|
level = rt_spin_lock_irqsave(&(queue->spinlock));
|
||||||
|
|
||||||
/* remove list */
|
/* remove list */
|
||||||
rt_list_remove(&(work->list));
|
rt_list_remove(&(work->list));
|
||||||
work->flags &= ~RT_WORK_STATE_PENDING;
|
work->flags = 0;
|
||||||
|
|
||||||
if (ticks == 0)
|
if (ticks == 0)
|
||||||
{
|
{
|
||||||
rt_list_insert_after(queue->work_list.prev, &(work->list));
|
rt_list_insert_after(queue->work_list.prev, &(work->list));
|
||||||
work->flags |= RT_WORK_STATE_PENDING;
|
work->flags |= RT_WORK_STATE_PENDING;
|
||||||
work->workqueue = queue;
|
work->workqueue = queue;
|
||||||
|
|
||||||
/* whether the workqueue is doing work */
|
rt_completion_done(&(queue->wakeup_completion));
|
||||||
if (queue->work_current == RT_NULL)
|
err = RT_EOK;
|
||||||
{
|
|
||||||
/* resume work thread, and do a re-schedule if succeed */
|
|
||||||
rt_thread_resume(queue->work_thread);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (ticks < RT_TICK_MAX / 2)
|
else if (ticks < RT_TICK_MAX / 2)
|
||||||
{
|
{
|
||||||
/* Timer started */
|
|
||||||
if (work->flags & RT_WORK_STATE_SUBMITTING)
|
|
||||||
{
|
|
||||||
rt_timer_control(&work->timer, RT_TIMER_CTRL_SET_TIME, &ticks);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rt_timer_init(&(work->timer), "work", _delayed_work_timeout_handler,
|
|
||||||
work, ticks, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER);
|
|
||||||
work->flags |= RT_WORK_STATE_SUBMITTING;
|
|
||||||
}
|
|
||||||
work->workqueue = queue;
|
|
||||||
/* insert delay work list */
|
/* insert delay work list */
|
||||||
rt_list_insert_after(queue->delayed_list.prev, &(work->list));
|
work->flags |= RT_WORK_STATE_SUBMITTING;
|
||||||
|
work->workqueue = queue;
|
||||||
|
work->timeout_tick = rt_tick_get() + ticks;
|
||||||
|
|
||||||
err = rt_timer_start(&(work->timer));
|
list_tmp = &(queue->delayed_list);
|
||||||
|
for (work_tmp = rt_list_entry(list_tmp->next, struct rt_work, list);
|
||||||
|
&work_tmp->list != list_tmp;
|
||||||
|
work_tmp = rt_list_entry(work_tmp->list.next, struct rt_work, list))
|
||||||
|
{
|
||||||
|
if ((work_tmp->timeout_tick - work->timeout_tick) < RT_TICK_MAX / 2)
|
||||||
|
{
|
||||||
|
list_tmp = &(work_tmp->list);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rt_list_insert_before(list_tmp, &(work->list));
|
||||||
|
|
||||||
|
rt_completion_done(&(queue->wakeup_completion));
|
||||||
|
err = RT_EOK;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err = - RT_ERROR;
|
err = -RT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -146,61 +168,17 @@ static rt_err_t _workqueue_submit_work(struct rt_workqueue *queue,
|
|||||||
static rt_err_t _workqueue_cancel_work(struct rt_workqueue *queue, struct rt_work *work)
|
static rt_err_t _workqueue_cancel_work(struct rt_workqueue *queue, struct rt_work *work)
|
||||||
{
|
{
|
||||||
rt_base_t level;
|
rt_base_t level;
|
||||||
rt_err_t err;
|
rt_err_t err;
|
||||||
|
|
||||||
level = rt_spin_lock_irqsave(&(queue->spinlock));
|
level = rt_spin_lock_irqsave(&(queue->spinlock));
|
||||||
rt_list_remove(&(work->list));
|
rt_list_remove(&(work->list));
|
||||||
work->flags &= ~RT_WORK_STATE_PENDING;
|
work->flags = 0;
|
||||||
/* Timer started */
|
err = queue->work_current != work ? RT_EOK : -RT_EBUSY;
|
||||||
if (work->flags & RT_WORK_STATE_SUBMITTING)
|
|
||||||
{
|
|
||||||
if ((err = rt_timer_stop(&(work->timer))) != RT_EOK)
|
|
||||||
{
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
rt_timer_detach(&(work->timer));
|
|
||||||
work->flags &= ~RT_WORK_STATE_SUBMITTING;
|
|
||||||
}
|
|
||||||
err = queue->work_current != work ? RT_EOK : -RT_EBUSY;
|
|
||||||
work->workqueue = RT_NULL;
|
work->workqueue = RT_NULL;
|
||||||
exit:
|
|
||||||
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _delayed_work_timeout_handler(void *parameter)
|
|
||||||
{
|
|
||||||
struct rt_work *work;
|
|
||||||
struct rt_workqueue *queue;
|
|
||||||
rt_base_t level;
|
|
||||||
|
|
||||||
work = (struct rt_work *)parameter;
|
|
||||||
queue = work->workqueue;
|
|
||||||
|
|
||||||
RT_ASSERT(work->flags & RT_WORK_STATE_SUBMITTING);
|
|
||||||
RT_ASSERT(queue != RT_NULL);
|
|
||||||
|
|
||||||
level = rt_spin_lock_irqsave(&(queue->spinlock));
|
|
||||||
rt_timer_detach(&(work->timer));
|
|
||||||
work->flags &= ~RT_WORK_STATE_SUBMITTING;
|
|
||||||
/* remove delay list */
|
|
||||||
rt_list_remove(&(work->list));
|
|
||||||
/* insert work queue */
|
|
||||||
if (queue->work_current != work)
|
|
||||||
{
|
|
||||||
rt_list_insert_after(queue->work_list.prev, &(work->list));
|
|
||||||
work->flags |= RT_WORK_STATE_PENDING;
|
|
||||||
}
|
|
||||||
/* whether the workqueue is doing work */
|
|
||||||
if (queue->work_current == RT_NULL)
|
|
||||||
{
|
|
||||||
/* resume work thread, and do a re-schedule if succeed */
|
|
||||||
rt_thread_resume(queue->work_thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize a work item, binding with a callback function.
|
* @brief Initialize a work item, binding with a callback function.
|
||||||
*
|
*
|
||||||
@ -221,8 +199,8 @@ void rt_work_init(struct rt_work *work,
|
|||||||
work->work_func = work_func;
|
work->work_func = work_func;
|
||||||
work->work_data = work_data;
|
work->work_data = work_data;
|
||||||
work->workqueue = RT_NULL;
|
work->workqueue = RT_NULL;
|
||||||
work->flags = 0;
|
work->flags = 0;
|
||||||
work->type = 0;
|
work->type = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -248,6 +226,7 @@ struct rt_workqueue *rt_workqueue_create(const char *name, rt_uint16_t stack_siz
|
|||||||
rt_list_init(&(queue->delayed_list));
|
rt_list_init(&(queue->delayed_list));
|
||||||
queue->work_current = RT_NULL;
|
queue->work_current = RT_NULL;
|
||||||
rt_sem_init(&(queue->sem), "wqueue", 0, RT_IPC_FLAG_FIFO);
|
rt_sem_init(&(queue->sem), "wqueue", 0, RT_IPC_FLAG_FIFO);
|
||||||
|
rt_completion_init(&(queue->wakeup_completion));
|
||||||
|
|
||||||
/* create the work thread */
|
/* create the work thread */
|
||||||
queue->work_thread = rt_thread_create(name, _workqueue_thread_entry, queue, stack_size, priority, 10);
|
queue->work_thread = rt_thread_create(name, _workqueue_thread_entry, queue, stack_size, priority, 10);
|
||||||
@ -292,7 +271,6 @@ rt_err_t rt_workqueue_destroy(struct rt_workqueue *queue)
|
|||||||
* @param work is a pointer to the work item object.
|
* @param work is a pointer to the work item object.
|
||||||
*
|
*
|
||||||
* @return RT_EOK Success.
|
* @return RT_EOK Success.
|
||||||
* -RT_EBUSY This work item is executing.
|
|
||||||
*/
|
*/
|
||||||
rt_err_t rt_workqueue_dowork(struct rt_workqueue *queue, struct rt_work *work)
|
rt_err_t rt_workqueue_dowork(struct rt_workqueue *queue, struct rt_work *work)
|
||||||
{
|
{
|
||||||
@ -314,7 +292,6 @@ rt_err_t rt_workqueue_dowork(struct rt_workqueue *queue, struct rt_work *work)
|
|||||||
* NOTE: The max timeout tick should be no more than (RT_TICK_MAX/2 - 1)
|
* NOTE: The max timeout tick should be no more than (RT_TICK_MAX/2 - 1)
|
||||||
*
|
*
|
||||||
* @return RT_EOK Success.
|
* @return RT_EOK Success.
|
||||||
* -RT_EBUSY This work item is executing.
|
|
||||||
* -RT_ERROR The ticks parameter is invalid.
|
* -RT_ERROR The ticks parameter is invalid.
|
||||||
*/
|
*/
|
||||||
rt_err_t rt_workqueue_submit_work(struct rt_workqueue *queue, struct rt_work *work, rt_tick_t ticks)
|
rt_err_t rt_workqueue_submit_work(struct rt_workqueue *queue, struct rt_work *work, rt_tick_t ticks)
|
||||||
@ -346,14 +323,10 @@ rt_err_t rt_workqueue_urgent_work(struct rt_workqueue *queue, struct rt_work *wo
|
|||||||
/* NOTE: the work MUST be initialized firstly */
|
/* NOTE: the work MUST be initialized firstly */
|
||||||
rt_list_remove(&(work->list));
|
rt_list_remove(&(work->list));
|
||||||
rt_list_insert_after(&queue->work_list, &(work->list));
|
rt_list_insert_after(&queue->work_list, &(work->list));
|
||||||
/* whether the workqueue is doing work */
|
|
||||||
if (queue->work_current == RT_NULL)
|
|
||||||
{
|
|
||||||
/* resume work thread, and do a re-schedule if succeed */
|
|
||||||
rt_thread_resume(queue->work_thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
rt_completion_done(&(queue->wakeup_completion));
|
||||||
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
||||||
|
|
||||||
return RT_EOK;
|
return RT_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,7 +421,6 @@ static struct rt_workqueue *sys_workq; /* system work queue */
|
|||||||
* NOTE: The max timeout tick should be no more than (RT_TICK_MAX/2 - 1)
|
* NOTE: The max timeout tick should be no more than (RT_TICK_MAX/2 - 1)
|
||||||
*
|
*
|
||||||
* @return RT_EOK Success.
|
* @return RT_EOK Success.
|
||||||
* -RT_EBUSY This work item is executing.
|
|
||||||
* -RT_ERROR The ticks parameter is invalid.
|
* -RT_ERROR The ticks parameter is invalid.
|
||||||
*/
|
*/
|
||||||
rt_err_t rt_work_submit(struct rt_work *work, rt_tick_t ticks)
|
rt_err_t rt_work_submit(struct rt_work *work, rt_tick_t ticks)
|
||||||
|
@ -131,7 +131,7 @@ static rt_err_t _serial_ty_bypass(struct rt_serial_device* serial, char ch,void
|
|||||||
rt_inline void _setup_serial(struct rt_serial_device* serial, lwp_tty_t tp,
|
rt_inline void _setup_serial(struct rt_serial_device* serial, lwp_tty_t tp,
|
||||||
struct serial_tty_context *softc)
|
struct serial_tty_context *softc)
|
||||||
{
|
{
|
||||||
rt_bypass_lower_register(serial, "tty",RT_BYPASS_PROTECT_LEVEL_1, _serial_ty_bypass,(void *)tp);
|
rt_bypass_lower_register(serial, "tty", RT_BYPASS_PROTECT_LEVEL_1, _serial_ty_bypass, (void *)tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
rt_inline void _restore_serial(struct rt_serial_device *serial, lwp_tty_t tp,
|
rt_inline void _restore_serial(struct rt_serial_device *serial, lwp_tty_t tp,
|
||||||
@ -232,7 +232,7 @@ static void serial_tty_close(struct lwp_tty *tp)
|
|||||||
|
|
||||||
LOG_D("%s", __func__);
|
LOG_D("%s", __func__);
|
||||||
|
|
||||||
_restore_serial(serial, tp, softc);
|
rt_bypass_lower_unregister(serial, RT_BYPASS_PROTECT_LEVEL_1);
|
||||||
rt_device_close(&serial->parent);
|
rt_device_close(&serial->parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,183 @@ config RT_USING_SPI
|
|||||||
default n
|
default n
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
menuconfig RT_USING_SOFT_SPI
|
||||||
|
bool "Use GPIO to soft simulate SPI"
|
||||||
|
default n
|
||||||
|
select RT_USING_PIN
|
||||||
|
select RT_USING_SPI_BITOPS
|
||||||
|
if RT_USING_SOFT_SPI
|
||||||
|
menuconfig RT_USING_SOFT_SPI0
|
||||||
|
bool "Enable SPI0 Bus (software simulation)"
|
||||||
|
default y
|
||||||
|
if RT_USING_SOFT_SPI0
|
||||||
|
config RT_SOFT_SPI0_SCK_PIN
|
||||||
|
int "SCK pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 1
|
||||||
|
config RT_SOFT_SPI0_MISO_PIN
|
||||||
|
int "MISO pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 2
|
||||||
|
config RT_SOFT_SPI0_MOSI_PIN
|
||||||
|
int "MOSI pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 3
|
||||||
|
config RT_SOFT_SPI0_BUS_NAME
|
||||||
|
string "Bus name"
|
||||||
|
default "spi0"
|
||||||
|
config RT_SOFT_SPI0_TIMING_DELAY
|
||||||
|
int "Timing delay (us)"
|
||||||
|
range 0 32767
|
||||||
|
default 1
|
||||||
|
endif
|
||||||
|
menuconfig RT_USING_SOFT_SPI1
|
||||||
|
bool "Enable SPI1 Bus (software simulation)"
|
||||||
|
default y
|
||||||
|
if RT_USING_SOFT_SPI1
|
||||||
|
config RT_SOFT_SPI1_SCK_PIN
|
||||||
|
int "SCK pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 4
|
||||||
|
config RT_SOFT_SPI1_MISO_PIN
|
||||||
|
int "MISO pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 5
|
||||||
|
config RT_SOFT_SPI1_MOSI_PIN
|
||||||
|
int "MOSI pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 6
|
||||||
|
config RT_SOFT_SPI1_BUS_NAME
|
||||||
|
string "Bus name"
|
||||||
|
default "spi1"
|
||||||
|
config RT_SOFT_SPI1_TIMING_DELAY
|
||||||
|
int "Timing delay (us)"
|
||||||
|
range 0 32767
|
||||||
|
default 1
|
||||||
|
endif
|
||||||
|
menuconfig RT_USING_SOFT_SPI2
|
||||||
|
bool "Enable SPI2 Bus (software simulation)"
|
||||||
|
default n
|
||||||
|
if RT_USING_SOFT_SPI2
|
||||||
|
config RT_SOFT_SPI2_SCK_PIN
|
||||||
|
int "SCK pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 7
|
||||||
|
config RT_SOFT_SPI2_MISO_PIN
|
||||||
|
int "MISO pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 8
|
||||||
|
config RT_SOFT_SPI2_MOSI_PIN
|
||||||
|
int "MOSI pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 9
|
||||||
|
config RT_SOFT_SPI2_BUS_NAME
|
||||||
|
string "Bus name"
|
||||||
|
default "spi2"
|
||||||
|
config RT_SOFT_SPI2_TIMING_DELAY
|
||||||
|
int "Timing delay (us)"
|
||||||
|
range 0 32767
|
||||||
|
default 1
|
||||||
|
endif
|
||||||
|
menuconfig RT_USING_SOFT_SPI3
|
||||||
|
bool "Enable SPI3 Bus (software simulation)"
|
||||||
|
default n
|
||||||
|
if RT_USING_SOFT_SPI3
|
||||||
|
config RT_SOFT_SPI3_SCK_PIN
|
||||||
|
int "SCK pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 10
|
||||||
|
config RT_SOFT_SPI3_MISO_PIN
|
||||||
|
int "MISO pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 11
|
||||||
|
config RT_SOFT_SPI3_MOSI_PIN
|
||||||
|
int "MOSI pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 12
|
||||||
|
config RT_SOFT_SPI3_BUS_NAME
|
||||||
|
string "Bus name"
|
||||||
|
default "spi3"
|
||||||
|
config RT_SOFT_SPI3_TIMING_DELAY
|
||||||
|
int "Timing delay (us)"
|
||||||
|
range 0 32767
|
||||||
|
default 1
|
||||||
|
endif
|
||||||
|
menuconfig RT_USING_SOFT_SPI4
|
||||||
|
bool "Enable SPI4 Bus (software simulation)"
|
||||||
|
default n
|
||||||
|
if RT_USING_SOFT_SPI4
|
||||||
|
config RT_SOFT_SPI4_SCK_PIN
|
||||||
|
int "SCK pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 13
|
||||||
|
config RT_SOFT_SPI4_MISO_PIN
|
||||||
|
int "MISO pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 14
|
||||||
|
config RT_SOFT_SPI4_MOSI_PIN
|
||||||
|
int "MOSI pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 15
|
||||||
|
config RT_SOFT_SPI4_BUS_NAME
|
||||||
|
string "Bus name"
|
||||||
|
default "spi4"
|
||||||
|
config RT_SOFT_SPI4_TIMING_DELAY
|
||||||
|
int "Timing delay (us)"
|
||||||
|
range 0 32767
|
||||||
|
default 1
|
||||||
|
endif
|
||||||
|
menuconfig RT_USING_SOFT_SPI5
|
||||||
|
bool "Enable SPI5 Bus (software simulation)"
|
||||||
|
default n
|
||||||
|
if RT_USING_SOFT_SPI5
|
||||||
|
config RT_SOFT_SPI5_SCK_PIN
|
||||||
|
int "SCK pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 16
|
||||||
|
config RT_SOFT_SPI5_MISO_PIN
|
||||||
|
int "MISO pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 17
|
||||||
|
config RT_SOFT_SPI5_MOSI_PIN
|
||||||
|
int "MOSI pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 18
|
||||||
|
config RT_SOFT_SPI5_BUS_NAME
|
||||||
|
string "Bus name"
|
||||||
|
default "spi5"
|
||||||
|
config RT_SOFT_SPI5_TIMING_DELAY
|
||||||
|
int "Timing delay (us)"
|
||||||
|
range 0 32767
|
||||||
|
default 1
|
||||||
|
endif
|
||||||
|
menuconfig RT_USING_SOFT_SPI6
|
||||||
|
bool "Enable SPI6 Bus (software simulation)"
|
||||||
|
default n
|
||||||
|
if RT_USING_SOFT_SPI6
|
||||||
|
config RT_SOFT_SPI6_SCK_PIN
|
||||||
|
int "SCK pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 19
|
||||||
|
config RT_SOFT_SPI6_MISO_PIN
|
||||||
|
int "MISO pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 20
|
||||||
|
config RT_SOFT_SPI6_MOSI_PIN
|
||||||
|
int "MOSI pin number"
|
||||||
|
range 0 32767
|
||||||
|
default 21
|
||||||
|
config RT_SOFT_SPI6_BUS_NAME
|
||||||
|
string "Bus name"
|
||||||
|
default "spi6"
|
||||||
|
config RT_SOFT_SPI6_TIMING_DELAY
|
||||||
|
int "Timing delay (us)"
|
||||||
|
range 0 32767
|
||||||
|
default 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
config RT_USING_QSPI
|
config RT_USING_QSPI
|
||||||
bool "Enable QSPI mode"
|
bool "Enable QSPI mode"
|
||||||
default n
|
default n
|
||||||
|
@ -10,6 +10,9 @@ LOCAL_CFLAGS = ''
|
|||||||
if GetDepend('RT_USING_SPI_BITOPS'):
|
if GetDepend('RT_USING_SPI_BITOPS'):
|
||||||
src += ['dev_spi_bit_ops.c']
|
src += ['dev_spi_bit_ops.c']
|
||||||
|
|
||||||
|
if GetDepend('RT_USING_SOFT_SPI'):
|
||||||
|
src += ['dev_soft_spi.c']
|
||||||
|
|
||||||
if GetDepend('RT_USING_QSPI'):
|
if GetDepend('RT_USING_QSPI'):
|
||||||
src += ['dev_qspi_core.c']
|
src += ['dev_qspi_core.c']
|
||||||
|
|
||||||
|
269
rt-thread-no-bsp/components/drivers/spi/dev_soft_spi.c
Normal file
269
rt-thread-no-bsp/components/drivers/spi/dev_soft_spi.c
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2025 RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2025-01-23 CYFS first version
|
||||||
|
*/
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtdevice.h>
|
||||||
|
#include <dev_spi_bit_ops.h>
|
||||||
|
|
||||||
|
#ifdef RT_USING_SOFT_SPI
|
||||||
|
#if !defined(RT_USING_SOFT_SPI0) &&\
|
||||||
|
!defined(RT_USING_SOFT_SPI1) && !defined(RT_USING_SOFT_SPI2) &&\
|
||||||
|
!defined(RT_USING_SOFT_SPI3) && !defined(RT_USING_SOFT_SPI4) &&\
|
||||||
|
!defined(RT_USING_SOFT_SPI5) && !defined(RT_USING_SOFT_SPI6)
|
||||||
|
#error "Please define at least one RT_USING_SOFT_SPIx"
|
||||||
|
/*
|
||||||
|
This driver can be disabled at:
|
||||||
|
menuconfig -> RT-Thread Components -> Device Drivers -> Using I2C device drivers
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DBG_ENABLE
|
||||||
|
#define DBG_TAG "SPI_S"
|
||||||
|
#ifdef RT_SPI_BITOPS_DEBUG
|
||||||
|
#define DBG_LEVEL DBG_LOG
|
||||||
|
#endif
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
/* spi config class */
|
||||||
|
struct rt_soft_spi_config
|
||||||
|
{
|
||||||
|
rt_base_t sck;
|
||||||
|
rt_base_t miso;
|
||||||
|
rt_base_t mosi;
|
||||||
|
rt_uint32_t timing_delay;
|
||||||
|
const char *bus_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* spi dirver class */
|
||||||
|
struct rt_soft_spi
|
||||||
|
{
|
||||||
|
struct rt_spi_bit_obj spi;
|
||||||
|
struct rt_spi_bit_ops ops;
|
||||||
|
struct rt_soft_spi_config *cfg;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct rt_soft_spi_config soft_spi_config[] =
|
||||||
|
{
|
||||||
|
#ifdef RT_USING_SOFT_SPI0
|
||||||
|
{
|
||||||
|
.sck = RT_SOFT_SPI0_SCK_PIN,
|
||||||
|
.miso = RT_SOFT_SPI0_MISO_PIN,
|
||||||
|
.mosi = RT_SOFT_SPI0_MOSI_PIN,
|
||||||
|
.timing_delay = RT_SOFT_SPI0_TIMING_DELAY,
|
||||||
|
.bus_name = RT_SOFT_SPI0_BUS_NAME,
|
||||||
|
},
|
||||||
|
#endif /*RT_USING_SOFT_SPI0*/
|
||||||
|
#ifdef RT_USING_SOFT_SPI1
|
||||||
|
{
|
||||||
|
.sck = RT_SOFT_SPI1_SCK_PIN,
|
||||||
|
.miso = RT_SOFT_SPI1_MISO_PIN,
|
||||||
|
.mosi = RT_SOFT_SPI1_MOSI_PIN,
|
||||||
|
.timing_delay = RT_SOFT_SPI1_TIMING_DELAY,
|
||||||
|
.bus_name = RT_SOFT_SPI1_BUS_NAME,
|
||||||
|
},
|
||||||
|
#endif /*RT_USING_SOFT_SPI1*/
|
||||||
|
#ifdef RT_USING_SOFT_SPI2
|
||||||
|
{
|
||||||
|
.sck = RT_SOFT_SPI2_SCK_PIN,
|
||||||
|
.miso = RT_SOFT_SPI2_MISO_PIN,
|
||||||
|
.mosi = RT_SOFT_SPI2_MOSI_PIN,
|
||||||
|
.timing_delay = RT_SOFT_SPI2_TIMING_DELAY,
|
||||||
|
.bus_name = RT_SOFT_SPI2_BUS_NAME,
|
||||||
|
},
|
||||||
|
#endif /*RT_USING_SOFT_SPI2*/
|
||||||
|
#ifdef RT_USING_SOFT_SPI3
|
||||||
|
{
|
||||||
|
.sck = RT_SOFT_SPI3_SCK_PIN,
|
||||||
|
.miso = RT_SOFT_SPI3_MISO_PIN,
|
||||||
|
.mosi = RT_SOFT_SPI3_MOSI_PIN,
|
||||||
|
.timing_delay = RT_SOFT_SPI3_TIMING_DELAY,
|
||||||
|
.bus_name = RT_SOFT_SPI3_BUS_NAME,
|
||||||
|
},
|
||||||
|
#endif /*RT_USING_SOFT_SPI3*/
|
||||||
|
#ifdef RT_USING_SOFT_SPI4
|
||||||
|
{
|
||||||
|
.sck = RT_SOFT_SPI4_SCK_PIN,
|
||||||
|
.miso = RT_SOFT_SPI4_MISO_PIN,
|
||||||
|
.mosi = RT_SOFT_SPI4_MOSI_PIN,
|
||||||
|
.timing_delay = RT_SOFT_SPI4_TIMING_DELAY,
|
||||||
|
.bus_name = RT_SOFT_SPI4_BUS_NAME,
|
||||||
|
},
|
||||||
|
#endif /*RT_USING_SOFT_SPI4*/
|
||||||
|
#ifdef RT_USING_SOFT_SPI5
|
||||||
|
{
|
||||||
|
.sck = RT_SOFT_SPI5_SCK_PIN,
|
||||||
|
.miso = RT_SOFT_SPI5_MISO_PIN,
|
||||||
|
.mosi = RT_SOFT_SPI5_MOSI_PIN,
|
||||||
|
.timing_delay = RT_SOFT_SPI5_TIMING_DELAY,
|
||||||
|
.bus_name = RT_SOFT_SPI5_BUS_NAME,
|
||||||
|
},
|
||||||
|
#endif /*RT_USING_SOFT_SPI5*/
|
||||||
|
#ifdef RT_USING_SOFT_SPI6
|
||||||
|
{
|
||||||
|
.sck = RT_SOFT_SPI6_SCK_PIN,
|
||||||
|
.miso = RT_SOFT_SPI6_MISO_PIN,
|
||||||
|
.mosi = RT_SOFT_SPI6_MOSI_PIN,
|
||||||
|
.timing_delay = RT_SOFT_SPI6_TIMING_DELAY,
|
||||||
|
.bus_name = RT_SOFT_SPI6_BUS_NAME,
|
||||||
|
},
|
||||||
|
#endif /*RT_USING_SOFT_SPI6*/
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct rt_soft_spi spi_obj[sizeof(soft_spi_config) / sizeof(soft_spi_config[0])];
|
||||||
|
|
||||||
|
static void spi_soft_pin_init(struct rt_soft_spi * soft_spi)
|
||||||
|
{
|
||||||
|
struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)soft_spi->cfg;
|
||||||
|
rt_pin_mode(cfg->sck, PIN_MODE_OUTPUT);
|
||||||
|
rt_pin_mode(cfg->miso, PIN_MODE_INPUT);
|
||||||
|
rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT);
|
||||||
|
|
||||||
|
rt_pin_write(cfg->miso, PIN_HIGH);
|
||||||
|
rt_pin_write(cfg->sck, PIN_HIGH);
|
||||||
|
rt_pin_write(cfg->mosi, PIN_HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void spi_soft_tog_sclk(void *data)
|
||||||
|
{
|
||||||
|
struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
|
||||||
|
if(rt_pin_read(cfg->sck) == PIN_HIGH)
|
||||||
|
{
|
||||||
|
rt_pin_write(cfg->sck, PIN_LOW);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_pin_write(cfg->sck, PIN_HIGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spi_soft_set_sclk(void *data, rt_int32_t state)
|
||||||
|
{
|
||||||
|
struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
rt_pin_write(cfg->sck, PIN_HIGH);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_pin_write(cfg->sck, PIN_LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spi_soft_set_mosi(void *data, rt_int32_t state)
|
||||||
|
{
|
||||||
|
struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
rt_pin_write(cfg->mosi, PIN_HIGH);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_pin_write(cfg->mosi, PIN_LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spi_soft_set_miso(void *data, rt_int32_t state)
|
||||||
|
{
|
||||||
|
struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
rt_pin_write(cfg->miso, PIN_HIGH);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_pin_write(cfg->miso, PIN_LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static rt_int32_t spi_soft_get_sclk(void *data)
|
||||||
|
{
|
||||||
|
struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
|
||||||
|
return rt_pin_read(cfg->sck);
|
||||||
|
}
|
||||||
|
|
||||||
|
static rt_int32_t spi_soft_get_mosi(void *data)
|
||||||
|
{
|
||||||
|
struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
|
||||||
|
return rt_pin_read(cfg->mosi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static rt_int32_t spi_soft_get_miso(void *data)
|
||||||
|
{
|
||||||
|
struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
|
||||||
|
return rt_pin_read(cfg->miso);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spi_soft_dir_mosi(void *data, rt_int32_t state)
|
||||||
|
{
|
||||||
|
struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
rt_pin_mode(cfg->mosi, PIN_MODE_INPUT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_pin_mode(cfg->mosi, PIN_MODE_OUTPUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spi_soft_dir_miso(void *data, rt_int32_t state)
|
||||||
|
{
|
||||||
|
struct rt_soft_spi_config *cfg = (struct rt_soft_spi_config *)data;
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
rt_pin_mode(cfg->miso, PIN_MODE_INPUT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rt_pin_mode(cfg->miso, PIN_MODE_OUTPUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct rt_spi_bit_ops soft_spi_ops=
|
||||||
|
{
|
||||||
|
.data = RT_NULL,
|
||||||
|
.pin_init = RT_NULL,
|
||||||
|
.tog_sclk = spi_soft_tog_sclk,
|
||||||
|
.set_sclk = spi_soft_set_sclk,
|
||||||
|
.set_mosi = spi_soft_set_mosi,
|
||||||
|
.set_miso = spi_soft_set_miso,
|
||||||
|
.get_sclk = spi_soft_get_sclk,
|
||||||
|
.get_mosi = spi_soft_get_mosi,
|
||||||
|
.get_miso = spi_soft_get_miso,
|
||||||
|
.dir_mosi = spi_soft_dir_mosi,
|
||||||
|
.dir_miso = spi_soft_dir_miso,
|
||||||
|
.udelay = rt_hw_us_delay,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Soft SPI initialization function */
|
||||||
|
int rt_soft_spi_init(void)
|
||||||
|
{
|
||||||
|
rt_size_t obj_num = sizeof(spi_obj) / sizeof(struct rt_soft_spi);
|
||||||
|
rt_err_t result;
|
||||||
|
|
||||||
|
for (rt_size_t i = 0; i < obj_num; i++)
|
||||||
|
{
|
||||||
|
rt_memcpy(&spi_obj[i].ops, &soft_spi_ops, sizeof(struct rt_spi_bit_ops));
|
||||||
|
spi_obj[i].ops.data = (void *)&soft_spi_config[i];
|
||||||
|
spi_obj[i].spi.ops = &soft_spi_ops;
|
||||||
|
spi_obj[i].cfg = (void *)&soft_spi_config[i];
|
||||||
|
spi_soft_pin_init(&spi_obj[i]);
|
||||||
|
spi_obj[i].spi.ops->delay_us = soft_spi_config[i].timing_delay;
|
||||||
|
result = rt_spi_bit_add_bus(&spi_obj[i].spi, soft_spi_config[i].bus_name, &spi_obj[i].ops);
|
||||||
|
RT_ASSERT(result == RT_EOK);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RT_EOK;
|
||||||
|
}
|
||||||
|
INIT_PREV_EXPORT(rt_soft_spi_init);
|
||||||
|
|
||||||
|
#endif /* RT_USING_SOFT_SPI */
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
* Copyright (c) 2006-2025 RT-Thread Development Team
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@ -87,11 +87,23 @@ rt_inline rt_ssize_t spi_xfer_4line_data8(struct rt_spi_bit_ops *ops,
|
|||||||
|
|
||||||
TOG_SCLK(ops);
|
TOG_SCLK(ops);
|
||||||
|
|
||||||
if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x01; }
|
if (config->mode & RT_SPI_MSB)
|
||||||
else { rx_data >>= 1; bit = 0x80; }
|
{
|
||||||
|
rx_data <<= 1; bit = 0x01;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rx_data >>= 1; bit = 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
if (GET_MISO(ops)) { rx_data |= bit; }
|
if (GET_MISO(ops))
|
||||||
else { rx_data &= ~bit; }
|
{
|
||||||
|
rx_data |= bit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rx_data &= ~bit;
|
||||||
|
}
|
||||||
|
|
||||||
spi_delay2(ops);
|
spi_delay2(ops);
|
||||||
|
|
||||||
@ -150,11 +162,23 @@ rt_inline rt_ssize_t spi_xfer_4line_data16(struct rt_spi_bit_ops *ops,
|
|||||||
|
|
||||||
TOG_SCLK(ops);
|
TOG_SCLK(ops);
|
||||||
|
|
||||||
if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x0001; }
|
if (config->mode & RT_SPI_MSB)
|
||||||
else { rx_data >>= 1; bit = 0x8000; }
|
{
|
||||||
|
rx_data <<= 1; bit = 0x0001;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rx_data >>= 1; bit = 0x8000;
|
||||||
|
}
|
||||||
|
|
||||||
if (GET_MISO(ops)) { rx_data |= bit; }
|
if (GET_MISO(ops))
|
||||||
else { rx_data &= ~bit; }
|
{
|
||||||
|
rx_data |= bit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rx_data &= ~bit;
|
||||||
|
}
|
||||||
|
|
||||||
spi_delay2(ops);
|
spi_delay2(ops);
|
||||||
|
|
||||||
@ -244,11 +268,23 @@ rt_inline rt_ssize_t spi_xfer_3line_data8(struct rt_spi_bit_ops *ops,
|
|||||||
|
|
||||||
TOG_SCLK(ops);
|
TOG_SCLK(ops);
|
||||||
|
|
||||||
if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x01; }
|
if (config->mode & RT_SPI_MSB)
|
||||||
else { rx_data >>= 1; bit = 0x80; }
|
{
|
||||||
|
rx_data <<= 1; bit = 0x01;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rx_data >>= 1; bit = 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
if (GET_MOSI(ops)) { rx_data |= bit; }
|
if (GET_MOSI(ops))
|
||||||
else { rx_data &= ~bit; }
|
{
|
||||||
|
rx_data |= bit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rx_data &= ~bit;
|
||||||
|
}
|
||||||
|
|
||||||
spi_delay2(ops);
|
spi_delay2(ops);
|
||||||
|
|
||||||
@ -345,11 +381,23 @@ rt_inline rt_ssize_t spi_xfer_3line_data16(struct rt_spi_bit_ops *ops,
|
|||||||
|
|
||||||
TOG_SCLK(ops);
|
TOG_SCLK(ops);
|
||||||
|
|
||||||
if (config->mode & RT_SPI_MSB) { rx_data <<= 1; bit = 0x0001; }
|
if (config->mode & RT_SPI_MSB)
|
||||||
else { rx_data >>= 1; bit = 0x8000; }
|
{
|
||||||
|
rx_data <<= 1; bit = 0x0001;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rx_data >>= 1; bit = 0x8000;
|
||||||
|
}
|
||||||
|
|
||||||
if (GET_MOSI(ops)) { rx_data |= bit; }
|
if (GET_MOSI(ops))
|
||||||
else { rx_data &= ~bit; }
|
{
|
||||||
|
rx_data |= bit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rx_data &= ~bit;
|
||||||
|
}
|
||||||
|
|
||||||
spi_delay2(ops);
|
spi_delay2(ops);
|
||||||
|
|
||||||
@ -456,15 +504,14 @@ rt_ssize_t spi_bit_xfer(struct rt_spi_device *device, struct rt_spi_message *mes
|
|||||||
rt_pin_write(cs_pin, PIN_LOW);
|
rt_pin_write(cs_pin, PIN_LOW);
|
||||||
}
|
}
|
||||||
spi_delay(ops);
|
spi_delay(ops);
|
||||||
|
}
|
||||||
|
|
||||||
/* spi phase */
|
/* spi phase */
|
||||||
if (config->mode & RT_SPI_CPHA)
|
if ((config->mode & RT_SPI_CPHA))
|
||||||
{
|
{
|
||||||
spi_delay(ops);
|
spi_delay(ops);
|
||||||
TOG_SCLK(ops);
|
TOG_SCLK(ops);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (config->mode & RT_SPI_3WIRE)
|
if (config->mode & RT_SPI_3WIRE)
|
||||||
{
|
{
|
||||||
if (config->data_width <= 8)
|
if (config->data_width <= 8)
|
||||||
@ -487,10 +534,15 @@ rt_ssize_t spi_bit_xfer(struct rt_spi_device *device, struct rt_spi_message *mes
|
|||||||
length = spi_xfer_4line_data16(ops, config, message->send_buf, message->recv_buf, message->length);
|
length = spi_xfer_4line_data16(ops, config, message->send_buf, message->recv_buf, message->length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* release CS */
|
/* release CS */
|
||||||
if (message->cs_take && !(device->config.mode & RT_SPI_NO_CS) && (cs_pin != PIN_NONE))
|
if (message->cs_release && !(device->config.mode & RT_SPI_NO_CS) && (cs_pin != PIN_NONE))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if ((config->mode & RT_SPI_CPOL) && !GET_SCLK(ops))
|
||||||
|
{
|
||||||
|
spi_delay(ops);
|
||||||
|
TOG_SCLK(ops);
|
||||||
|
}
|
||||||
spi_delay(ops);
|
spi_delay(ops);
|
||||||
if (device->config.mode & RT_SPI_CS_HIGH)
|
if (device->config.mode & RT_SPI_CS_HIGH)
|
||||||
{
|
{
|
||||||
@ -501,6 +553,7 @@ rt_ssize_t spi_bit_xfer(struct rt_spi_device *device, struct rt_spi_message *mes
|
|||||||
rt_pin_write(cs_pin, PIN_HIGH);
|
rt_pin_write(cs_pin, PIN_HIGH);
|
||||||
}
|
}
|
||||||
LOG_I("spi release cs\n");
|
LOG_I("spi release cs\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
* Copyright (c) 2006-2025 RT-Thread Development Team
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@ -140,7 +140,7 @@ rt_err_t rt_spi_bus_configure(struct rt_spi_device *device)
|
|||||||
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
|
result = rt_mutex_take(&(device->bus->lock), RT_WAITING_FOREVER);
|
||||||
if (result == RT_EOK)
|
if (result == RT_EOK)
|
||||||
{
|
{
|
||||||
if (device->bus->owner == device)
|
if (device->bus->owner == RT_NULL || device->bus->owner == device)
|
||||||
{
|
{
|
||||||
/* current device is using, re-configure SPI bus */
|
/* current device is using, re-configure SPI bus */
|
||||||
result = device->bus->ops->configure(device, &device->config);
|
result = device->bus->ops->configure(device, &device->config);
|
||||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
@ -38,6 +38,8 @@ if RT_USING_CHERRYUSB
|
|||||||
bool "dwc2_gd"
|
bool "dwc2_gd"
|
||||||
config RT_CHERRYUSB_DEVICE_DWC2_HC
|
config RT_CHERRYUSB_DEVICE_DWC2_HC
|
||||||
bool "dwc2_hc"
|
bool "dwc2_hc"
|
||||||
|
config RT_CHERRYUSB_DEVICE_DWC2_KENDRYTE
|
||||||
|
bool "dwc2_kendryte"
|
||||||
config RT_CHERRYUSB_DEVICE_DWC2_CUSTOM
|
config RT_CHERRYUSB_DEVICE_DWC2_CUSTOM
|
||||||
bool "dwc2_custom"
|
bool "dwc2_custom"
|
||||||
config RT_CHERRYUSB_DEVICE_MUSB_ES
|
config RT_CHERRYUSB_DEVICE_MUSB_ES
|
||||||
@ -66,6 +68,8 @@ if RT_USING_CHERRYUSB
|
|||||||
bool "aic"
|
bool "aic"
|
||||||
config RT_CHERRYUSB_DEVICE_PUSB2
|
config RT_CHERRYUSB_DEVICE_PUSB2
|
||||||
bool "pusb2"
|
bool "pusb2"
|
||||||
|
config RT_CHERRYUSB_DEVICE_NRF5X
|
||||||
|
bool "nrf5x"
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
config RT_CHERRYUSB_DEVICE_CDC_ACM
|
config RT_CHERRYUSB_DEVICE_CDC_ACM
|
||||||
@ -182,6 +186,8 @@ if RT_USING_CHERRYUSB
|
|||||||
bool "dwc2_st"
|
bool "dwc2_st"
|
||||||
config RT_CHERRYUSB_HOST_DWC2_ESP
|
config RT_CHERRYUSB_HOST_DWC2_ESP
|
||||||
bool "dwc2_esp"
|
bool "dwc2_esp"
|
||||||
|
config RT_CHERRYUSB_HOST_DWC2_KENDRYTE
|
||||||
|
bool "dwc2_kendryte"
|
||||||
config RT_CHERRYUSB_HOST_DWC2_CUSTOM
|
config RT_CHERRYUSB_HOST_DWC2_CUSTOM
|
||||||
bool "dwc2_custom"
|
bool "dwc2_custom"
|
||||||
config RT_CHERRYUSB_HOST_MUSB_ES
|
config RT_CHERRYUSB_HOST_MUSB_ES
|
||||||
|
@ -1,6 +1,16 @@
|
|||||||
# CherryUSB
|
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">CherryUSB</h1>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/cherry-embedded/CherryUSB/releases"><img src="https://img.shields.io/github/release/cherry-embedded/CherryUSB.svg"><a>
|
||||||
|
<a href="https://github.com/cherry-embedded/CherryUSB/blob/master/LICENSE"><img src="https://img.shields.io/github/license/cherry-embedded/CherryUSB.svg?style=flat-square"></a>
|
||||||
|
<a href="https://github.com/cherry-embedded/CherryUSB/actions/workflows/deploy-docs.yml"><img src="https://github.com/cherry-embedded/CherryUSB/actions/workflows/deploy-docs.yml/badge.svg"> </a>
|
||||||
|
<a href="https://discord.com/invite/wFfvrSAey8"><img src="https://img.shields.io/badge/Discord-blue?logo=discord&style=flat-square"> </a>
|
||||||
|
</p>
|
||||||
|
|
||||||
[中文版](./README_zh.md)
|
<p align="center">
|
||||||
|
<a href="./README_zh.md">中文</a>
|
||||||
|
|
|
||||||
|
<a href="./README.md">English</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
CherryUSB is a tiny, beautiful and portable USB host and device stack for embedded system with USB IP.
|
CherryUSB is a tiny, beautiful and portable USB host and device stack for embedded system with USB IP.
|
||||||
|
|
||||||
@ -103,6 +113,7 @@ CherryUSB Host Stack has the following functions:
|
|||||||
- Support USB Bluetooth class (support nimble and zephyr bluetooth stack, support **CLASS:0xE0** or vendor class like cdc acm)
|
- Support USB Bluetooth class (support nimble and zephyr bluetooth stack, support **CLASS:0xE0** or vendor class like cdc acm)
|
||||||
- Support Vendor class (serial, net, wifi)
|
- Support Vendor class (serial, net, wifi)
|
||||||
- Support USB modeswitch
|
- Support USB modeswitch
|
||||||
|
- Support Android Open Accessory
|
||||||
- Support multi host with the same USB IP
|
- Support multi host with the same USB IP
|
||||||
|
|
||||||
The CherryUSB Host stack also provides the lsusb function, which allows you to view information about all mounted devices, including those on external hubs, with the help of a shell plugin.
|
The CherryUSB Host stack also provides the lsusb function, which allows you to view information about all mounted devices, including those on external hubs, with the help of a shell plugin.
|
||||||
@ -149,7 +160,7 @@ Only standard and commercial USB IP are listed.
|
|||||||
|
|
||||||
| IP | device | host | Support status |
|
| IP | device | host | Support status |
|
||||||
|:----------------:|:----------:|:--------:|:--------------:|
|
|:----------------:|:----------:|:--------:|:--------------:|
|
||||||
| OHCI(intel) | none | OHCI | × |
|
| OHCI(intel) | none | OHCI | √ |
|
||||||
| EHCI(intel) | none | EHCI | √ |
|
| EHCI(intel) | none | EHCI | √ |
|
||||||
| XHCI(intel) | none | XHCI | √ |
|
| XHCI(intel) | none | XHCI | √ |
|
||||||
| UHCI(intel) | none | UHCI | × |
|
| UHCI(intel) | none | UHCI | × |
|
||||||
@ -186,6 +197,7 @@ USB basic concepts and how the CherryUSB Device stack is implemented, see [Cherr
|
|||||||
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Long-term |
|
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Long-term |
|
||||||
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | Long-term |
|
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | Long-term |
|
||||||
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Long-term |
|
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Long-term |
|
||||||
|
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/canmv_k230)|v1.2.0 | Long-term |
|
||||||
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | the same with musb |
|
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | the same with musb |
|
||||||
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | the same with musb |
|
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | the same with musb |
|
||||||
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | TBD |
|
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | TBD |
|
||||||
@ -212,4 +224,4 @@ CherryUSB discord: https://discord.com/invite/wFfvrSAey8.
|
|||||||
|
|
||||||
Thanks to the following companies for their support (in no particular order).
|
Thanks to the following companies for their support (in no particular order).
|
||||||
|
|
||||||
<img src="docs/assets/bouffalolab.jpg" width="100" height="80"/> <img src="docs/assets/hpmicro.jpg" width="100" height="80" /> <img src="docs/assets/eastsoft.jpg" width="100" height="80" /> <img src="docs/assets/rtthread.jpg" width="100" height="80" /> <img src="docs/assets/sophgo.jpg" width="100" height="80" /> <img src="docs/assets/phytium.jpg" width="100" height="80" /> <img src="docs/assets/thead.jpg" width="100" height="80" /> <img src="docs/assets/nuvoton.jpg" width="100" height="80" /> <img src="docs/assets/artinchip.jpg" width="100" height="80" /> <img src="docs/assets/bekencorp.jpg" width="100" height="80" /> <img src="docs/assets/nxp.png" width="100" height="80" /> <img src="docs/assets/espressif.png" width="100" height="80" />
|
<img src="docs/assets/bouffalolab.jpg" width="100" height="80"/> <img src="docs/assets/hpmicro.jpg" width="100" height="80" /> <img src="docs/assets/eastsoft.jpg" width="100" height="80" /> <img src="docs/assets/rtthread.jpg" width="100" height="80" /> <img src="docs/assets/sophgo.jpg" width="100" height="80" /> <img src="docs/assets/phytium.jpg" width="100" height="80" /> <img src="docs/assets/thead.jpg" width="100" height="80" /> <img src="docs/assets/nuvoton.jpg" width="100" height="80" /> <img src="docs/assets/artinchip.jpg" width="100" height="80" /> <img src="docs/assets/bekencorp.jpg" width="100" height="80" /> <img src="docs/assets/nxp.png" width="100" height="80" /> <img src="docs/assets/espressif.png" width="100" height="80" /> <img src="docs/assets/canaan.jpg" width="100" height="80" />
|
||||||
|
@ -1,6 +1,16 @@
|
|||||||
# CherryUSB
|
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">CherryUSB</h1>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/cherry-embedded/CherryUSB/releases"><img src="https://img.shields.io/github/release/cherry-embedded/CherryUSB.svg"><a>
|
||||||
|
<a href="https://github.com/cherry-embedded/CherryUSB/blob/master/LICENSE"><img src="https://img.shields.io/github/license/cherry-embedded/CherryUSB.svg?style=flat-square"></a>
|
||||||
|
<a href="https://github.com/cherry-embedded/CherryUSB/actions/workflows/deploy-docs.yml"><img src="https://github.com/cherry-embedded/CherryUSB/actions/workflows/deploy-docs.yml/badge.svg"> </a>
|
||||||
|
<a href="https://discord.com/invite/wFfvrSAey8"><img src="https://img.shields.io/badge/Discord-blue?logo=discord&style=flat-square"> </a>
|
||||||
|
</p>
|
||||||
|
|
||||||
[English](./README.md)
|
<p align="center">
|
||||||
|
<a href="./README_zh.md">中文</a>
|
||||||
|
|
|
||||||
|
<a href="./README.md">English</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统(带 USB IP)的 USB 主从协议栈。
|
CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统(带 USB IP)的 USB 主从协议栈。
|
||||||
|
|
||||||
@ -103,6 +113,7 @@ CherryUSB Host 协议栈当前实现以下功能:
|
|||||||
- 支持 USB Bluetooth (支持 nimble and zephyr bluetooth 协议栈,支持 **CLASS: 0xE0** 或者厂家自定义类,类似于 cdc acm 功能)
|
- 支持 USB Bluetooth (支持 nimble and zephyr bluetooth 协议栈,支持 **CLASS: 0xE0** 或者厂家自定义类,类似于 cdc acm 功能)
|
||||||
- 支持 Vendor 类 class (serial, net, wifi)
|
- 支持 Vendor 类 class (serial, net, wifi)
|
||||||
- 支持 USB modeswitch
|
- 支持 USB modeswitch
|
||||||
|
- 支持 Android Open Accessory
|
||||||
- 支持相同 USB IP 的多主机
|
- 支持相同 USB IP 的多主机
|
||||||
|
|
||||||
同时,CherryUSB Host 协议栈还提供了 lsusb 的功能,借助 shell 插件可以查看所有挂载设备的信息,包括外部 hub 上的设备的信息。
|
同时,CherryUSB Host 协议栈还提供了 lsusb 的功能,借助 shell 插件可以查看所有挂载设备的信息,包括外部 hub 上的设备的信息。
|
||||||
@ -149,7 +160,7 @@ x 受以下宏影响:
|
|||||||
|
|
||||||
| IP | device | host | Support status |
|
| IP | device | host | Support status |
|
||||||
|:----------------:|:----------:|:--------:|:--------------:|
|
|:----------------:|:----------:|:--------:|:--------------:|
|
||||||
| OHCI(intel) | none | OHCI | × |
|
| OHCI(intel) | none | OHCI | √ |
|
||||||
| EHCI(intel) | none | EHCI | √ |
|
| EHCI(intel) | none | EHCI | √ |
|
||||||
| XHCI(intel) | none | XHCI | √ |
|
| XHCI(intel) | none | XHCI | √ |
|
||||||
| UHCI(intel) | none | UHCI | × |
|
| UHCI(intel) | none | UHCI | × |
|
||||||
@ -187,6 +198,7 @@ CherryUSB 快速入门、USB 基本概念,API 手册,Class 基本概念和
|
|||||||
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Long-term |
|
|Artinchip | d12x/d13x/d21x | aic/ehci/ohci |[luban-lite](https://gitee.com/artinchip/luban-lite)|<= latest | Long-term |
|
||||||
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | Long-term |
|
|Espressif | esp32s2/esp32s3/esp32p4 | dwc2 |[esp32_repo](https://github.com/CherryUSB/cherryusb_esp32)|<= latest | Long-term |
|
||||||
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Long-term |
|
|NXP | mcx | kinetis/chipidea/ehci |[nxp_mcx_repo](https://github.com/CherryUSB/cherryusb_mcx)|<= latest | Long-term |
|
||||||
|
|Kendryte | k230 | dwc2 |[k230_repo](https://github.com/CherryUSB/canmv_k230)|v1.2.0 | Long-term |
|
||||||
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | the same with musb |
|
|AllwinnerTech | F1C100S/F1C200S | musb |[cherryusb_rtt_f1c100s](https://github.com/CherryUSB/cherryusb_rtt_f1c100s)|<= latest | the same with musb |
|
||||||
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | the same with musb |
|
|Bekencorp | bk7256/bk7258 | musb |[bk_idk](https://github.com/CherryUSB/bk_idk)| v0.7.0 | the same with musb |
|
||||||
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | TBD |
|
|Sophgo | cv18xx | dwc2 |[cvi_alios_open](https://github.com/CherryUSB/cvi_alios_open)| v0.7.0 | TBD |
|
||||||
@ -214,4 +226,4 @@ CherryUSB 微信群:与我联系后邀请加入
|
|||||||
|
|
||||||
感谢以下企业支持(顺序不分先后)。
|
感谢以下企业支持(顺序不分先后)。
|
||||||
|
|
||||||
<img src="docs/assets/bouffalolab.jpg" width="100" height="80"/> <img src="docs/assets/hpmicro.jpg" width="100" height="80" /> <img src="docs/assets/eastsoft.jpg" width="100" height="80" /> <img src="docs/assets/rtthread.jpg" width="100" height="80" /> <img src="docs/assets/sophgo.jpg" width="100" height="80" /> <img src="docs/assets/phytium.jpg" width="100" height="80" /> <img src="docs/assets/thead.jpg" width="100" height="80" /> <img src="docs/assets/nuvoton.jpg" width="100" height="80" /> <img src="docs/assets/artinchip.jpg" width="100" height="80" /> <img src="docs/assets/bekencorp.jpg" width="100" height="80" /> <img src="docs/assets/nxp.png" width="100" height="80" /> <img src="docs/assets/espressif.png" width="100" height="80" />
|
<img src="docs/assets/bouffalolab.jpg" width="100" height="80"/> <img src="docs/assets/hpmicro.jpg" width="100" height="80" /> <img src="docs/assets/eastsoft.jpg" width="100" height="80" /> <img src="docs/assets/rtthread.jpg" width="100" height="80" /> <img src="docs/assets/sophgo.jpg" width="100" height="80" /> <img src="docs/assets/phytium.jpg" width="100" height="80" /> <img src="docs/assets/thead.jpg" width="100" height="80" /> <img src="docs/assets/nuvoton.jpg" width="100" height="80" /> <img src="docs/assets/artinchip.jpg" width="100" height="80" /> <img src="docs/assets/bekencorp.jpg" width="100" height="80" /> <img src="docs/assets/nxp.png" width="100" height="80" /> <img src="docs/assets/espressif.png" width="100" height="80" /> <img src="docs/assets/canaan.jpg" width="100" height="80" />
|
||||||
|
@ -28,6 +28,8 @@ if GetDepend(['RT_CHERRYUSB_DEVICE']):
|
|||||||
if GetDepend(['RT_CHERRYUSB_DEVICE_SPEED_HS']):
|
if GetDepend(['RT_CHERRYUSB_DEVICE_SPEED_HS']):
|
||||||
CPPDEFINES+=['CONFIG_USB_HS']
|
CPPDEFINES+=['CONFIG_USB_HS']
|
||||||
|
|
||||||
|
if GetDepend(['RT_CHERRYUSB_DEVICE_NRF5X']):
|
||||||
|
src += Glob('port/nrf5x/usb_dc_nrf5x.c')
|
||||||
if GetDepend(['RT_CHERRYUSB_DEVICE_FSDEV']):
|
if GetDepend(['RT_CHERRYUSB_DEVICE_FSDEV']):
|
||||||
src += Glob('port/fsdev/usb_dc_fsdev.c')
|
src += Glob('port/fsdev/usb_dc_fsdev.c')
|
||||||
if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_ST']):
|
if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_ST']):
|
||||||
@ -45,6 +47,9 @@ if GetDepend(['RT_CHERRYUSB_DEVICE']):
|
|||||||
if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_HC']):
|
if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_HC']):
|
||||||
src += Glob('port/dwc2/usb_dc_dwc2.c')
|
src += Glob('port/dwc2/usb_dc_dwc2.c')
|
||||||
src += Glob('port/dwc2/usb_glue_hc.c')
|
src += Glob('port/dwc2/usb_glue_hc.c')
|
||||||
|
if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_KENDRYTE']):
|
||||||
|
src += Glob('port/dwc2/usb_dc_dwc2.c')
|
||||||
|
src += Glob('port/dwc2/usb_glue_kendryte.c')
|
||||||
if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_CUSTOM']):
|
if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_CUSTOM']):
|
||||||
src += Glob('port/dwc2/usb_dc_dwc2.c')
|
src += Glob('port/dwc2/usb_dc_dwc2.c')
|
||||||
if GetDepend(['RT_CHERRYUSB_DEVICE_MUSB_ES']):
|
if GetDepend(['RT_CHERRYUSB_DEVICE_MUSB_ES']):
|
||||||
@ -177,6 +182,9 @@ if GetDepend(['RT_CHERRYUSB_HOST']):
|
|||||||
if GetDepend(['RT_CHERRYUSB_HOST_DWC2_ESP']):
|
if GetDepend(['RT_CHERRYUSB_HOST_DWC2_ESP']):
|
||||||
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
||||||
src += Glob('port/dwc2/usb_glue_esp.c')
|
src += Glob('port/dwc2/usb_glue_esp.c')
|
||||||
|
if GetDepend(['RT_CHERRYUSB_HOST_DWC2_KENDRYTE']):
|
||||||
|
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
||||||
|
src += Glob('port/dwc2/usb_glue_kendryte.c')
|
||||||
if GetDepend(['RT_CHERRYUSB_HOST_DWC2_CUSTOM']):
|
if GetDepend(['RT_CHERRYUSB_HOST_DWC2_CUSTOM']):
|
||||||
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
src += Glob('port/dwc2/usb_hc_dwc2.c')
|
||||||
if GetDepend(['RT_CHERRYUSB_HOST_MUSB_STANDARD']):
|
if GetDepend(['RT_CHERRYUSB_HOST_MUSB_STANDARD']):
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
VERSION_MAJOR = 1
|
VERSION_MAJOR = 1
|
||||||
VERSION_MINOR = 4
|
VERSION_MINOR = 4
|
||||||
PATCHLEVEL = 1
|
PATCHLEVEL = 2
|
||||||
VERSION_TWEAK = 0
|
VERSION_TWEAK = 0
|
||||||
EXTRAVERSION = 0
|
EXTRAVERSION = 0
|
||||||
|
@ -40,6 +40,7 @@ ${CMAKE_CURRENT_LIST_DIR}/class/adb
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/class/vendor/net
|
${CMAKE_CURRENT_LIST_DIR}/class/vendor/net
|
||||||
${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial
|
${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial
|
||||||
${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi
|
${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/class/aoa
|
||||||
)
|
)
|
||||||
|
|
||||||
if(CONFIG_CHERRYUSB_DEVICE)
|
if(CONFIG_CHERRYUSB_DEVICE)
|
||||||
@ -218,6 +219,9 @@ if(CONFIG_CHERRYUSB_HOST)
|
|||||||
if(CONFIG_CHERRYUSB_HOST_BL616)
|
if(CONFIG_CHERRYUSB_HOST_BL616)
|
||||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi/usbh_bl616.c)
|
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi/usbh_bl616.c)
|
||||||
endif()
|
endif()
|
||||||
|
if(CONFIG_CHERRYUSB_HOST_AOA)
|
||||||
|
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/aoa/usbh_aoa.c)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(DEFINED CONFIG_CHERRYUSB_HOST_HCD)
|
if(DEFINED CONFIG_CHERRYUSB_HOST_HCD)
|
||||||
if("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "ehci_bouffalo")
|
if("${CONFIG_CHERRYUSB_HOST_HCD}" STREQUAL "ehci_bouffalo")
|
||||||
@ -294,4 +298,9 @@ endif()
|
|||||||
if(CONFIG_CHERRYMP)
|
if(CONFIG_CHERRYMP)
|
||||||
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherrymp/chry_mempool.c)
|
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherrymp/chry_mempool.c)
|
||||||
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherrymp)
|
list(APPEND cherryusb_incs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherrymp)
|
||||||
|
if("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "freertos")
|
||||||
|
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherrymp/chry_mempool_osal_freertos.c)
|
||||||
|
elseif("${CONFIG_CHERRYUSB_OSAL}" STREQUAL "rtthread")
|
||||||
|
list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/third_party/cherrymp/chry_mempool_osal_rtthread.c)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
@ -208,6 +208,9 @@
|
|||||||
#define CONFIG_USBDEV_EP_NUM 8
|
#define CONFIG_USBDEV_EP_NUM 8
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* When your chip hardware supports high-speed and wants to initialize it in high-speed mode, the relevant IP will configure the internal or external high-speed PHY according to CONFIG_USB_HS. */
|
||||||
|
// #define CONFIG_USB_HS
|
||||||
|
|
||||||
/* ---------------- FSDEV Configuration ---------------- */
|
/* ---------------- FSDEV Configuration ---------------- */
|
||||||
//#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2 // maybe 1 or 2, many chips may have a difference
|
//#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2 // maybe 1 or 2, many chips may have a difference
|
||||||
|
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, sakumisu
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#ifndef USB_AOA_H
|
||||||
|
#define USB_AOA_H
|
||||||
|
|
||||||
|
//AOA 1.0
|
||||||
|
#define AOA_ACCESSORY_VENDOR_ID 0x18D1
|
||||||
|
#define AOA_ACCESSORY_PRODUCT_ID 0x2D00
|
||||||
|
#define AOA_ACCESSORY_ADB_PRODUCT_ID 0x2D01
|
||||||
|
|
||||||
|
//AOA 2.0
|
||||||
|
#define AOA_AUDIO_PRODUCT_ID 0x2D02
|
||||||
|
#define AOA_AUDIO_ADB_PRODUCT_ID 0x2D03
|
||||||
|
#define AOA_ACCESSORY_AUDIO_PRODUCT_ID 0x2D04
|
||||||
|
#define AOA_ACCESSORY_AUDIO_ADB_PRODUCT_ID 0x2D05
|
||||||
|
|
||||||
|
//AOA 1.0
|
||||||
|
#define AOA_ACCESSORY_GET_PROTOCOL 51
|
||||||
|
#define AOA_ACCESSORY_SEND_STRING 52
|
||||||
|
#define AOA_ACCESSORY_START 53
|
||||||
|
|
||||||
|
//AOA 2.0
|
||||||
|
#define AOA_ACCESSORY_REGISTER_HID 54
|
||||||
|
#define AOA_ACCESSORY_UNREGISTER_HID 55
|
||||||
|
#define AOA_ACCESSORY_SET_HID_REPORT_DESC 56
|
||||||
|
#define AOA_ACCESSORY_SEND_HID_EVENT 57
|
||||||
|
#define AOA_ACCESSORY_SET_AUDIO_MODE 58
|
||||||
|
|
||||||
|
#define AOA_ACCESSORY_STRING_MANUFACTURER 0
|
||||||
|
#define AOA_ACCESSORY_STRING_MODEL 1
|
||||||
|
#define AOA_ACCESSORY_STRING_DESCRIPTION 2
|
||||||
|
#define AOA_ACCESSORY_STRING_VERSION 3
|
||||||
|
#define AOA_ACCESSORY_STRING_URI 4
|
||||||
|
#define AOA_ACCESSORY_STRING_SERIAL 5
|
||||||
|
|
||||||
|
struct aoa_string_info {
|
||||||
|
char acc_manufacturer[64];
|
||||||
|
char acc_model[64];
|
||||||
|
char acc_description[64];
|
||||||
|
char acc_version[64];
|
||||||
|
char acc_uri[64];
|
||||||
|
char acc_serial[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* USB_AOA_H */
|
@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, sakumisu
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include "usbh_core.h"
|
||||||
|
#include "usbh_aoa.h"
|
||||||
|
|
||||||
|
#undef USB_DBG_TAG
|
||||||
|
#define USB_DBG_TAG "usbh_aoa"
|
||||||
|
#include "usb_log.h"
|
||||||
|
|
||||||
|
#define DEV_FORMAT "/dev/aoa"
|
||||||
|
|
||||||
|
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_aoa_buffer[128];
|
||||||
|
|
||||||
|
static struct usbh_aoa g_aoa_class;
|
||||||
|
|
||||||
|
int usbh_aoa_switch(struct usbh_hubport *hport, struct aoa_string_info *info)
|
||||||
|
{
|
||||||
|
struct usb_setup_packet *setup;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
setup = hport->setup;
|
||||||
|
|
||||||
|
if (setup == NULL) {
|
||||||
|
return -USB_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
USB_LOG_INFO("Try switch into aoa mode\r\n");
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||||
|
setup->bRequest = AOA_ACCESSORY_GET_PROTOCOL;
|
||||||
|
setup->wValue = 0;
|
||||||
|
setup->wIndex = 0;
|
||||||
|
setup->wLength = 2;
|
||||||
|
|
||||||
|
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
USB_LOG_INFO("AOA version: v%d.%d\r\n", g_aoa_buffer[0], g_aoa_buffer[1]);
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||||
|
setup->bRequest = AOA_ACCESSORY_SEND_STRING;
|
||||||
|
setup->wValue = 0;
|
||||||
|
setup->wIndex = AOA_ACCESSORY_STRING_MANUFACTURER;
|
||||||
|
setup->wLength = strlen(info->acc_manufacturer) + 1;
|
||||||
|
|
||||||
|
memcpy(g_aoa_buffer, info->acc_manufacturer, strlen(info->acc_manufacturer));
|
||||||
|
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||||
|
setup->bRequest = AOA_ACCESSORY_SEND_STRING;
|
||||||
|
setup->wValue = 0;
|
||||||
|
setup->wIndex = AOA_ACCESSORY_STRING_MODEL;
|
||||||
|
setup->wLength = strlen(info->acc_model) + 1;
|
||||||
|
|
||||||
|
memcpy(g_aoa_buffer, info->acc_model, strlen(info->acc_model));
|
||||||
|
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||||
|
setup->bRequest = AOA_ACCESSORY_SEND_STRING;
|
||||||
|
setup->wValue = 0;
|
||||||
|
setup->wIndex = AOA_ACCESSORY_STRING_DESCRIPTION;
|
||||||
|
setup->wLength = strlen(info->acc_description) + 1;
|
||||||
|
|
||||||
|
memcpy(g_aoa_buffer, info->acc_description, strlen(info->acc_description));
|
||||||
|
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||||
|
setup->bRequest = AOA_ACCESSORY_SEND_STRING;
|
||||||
|
setup->wValue = 0;
|
||||||
|
setup->wIndex = AOA_ACCESSORY_STRING_VERSION;
|
||||||
|
setup->wLength = strlen(info->acc_version) + 1;
|
||||||
|
|
||||||
|
memcpy(g_aoa_buffer, info->acc_version, strlen(info->acc_version));
|
||||||
|
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||||
|
setup->bRequest = AOA_ACCESSORY_SEND_STRING;
|
||||||
|
setup->wValue = 0;
|
||||||
|
setup->wIndex = AOA_ACCESSORY_STRING_URI;
|
||||||
|
setup->wLength = strlen(info->acc_uri) + 1;
|
||||||
|
|
||||||
|
memcpy(g_aoa_buffer, info->acc_uri, strlen(info->acc_uri));
|
||||||
|
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||||
|
setup->bRequest = AOA_ACCESSORY_SEND_STRING;
|
||||||
|
setup->wValue = 0;
|
||||||
|
setup->wIndex = AOA_ACCESSORY_STRING_SERIAL;
|
||||||
|
setup->wLength = strlen(info->acc_serial) + 1;
|
||||||
|
|
||||||
|
memcpy(g_aoa_buffer, info->acc_serial, strlen(info->acc_serial));
|
||||||
|
ret = usbh_control_transfer(hport, setup, g_aoa_buffer);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||||
|
setup->bRequest = AOA_ACCESSORY_START;
|
||||||
|
setup->wValue = 0;
|
||||||
|
setup->wIndex = 0;
|
||||||
|
setup->wLength = 0;
|
||||||
|
|
||||||
|
ret = usbh_control_transfer(hport, setup, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
USB_LOG_INFO("Switch into aoa mode success, wait usb device restart...\r\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int usbh_aoa_register_hid(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *report, uint32_t report_len)
|
||||||
|
{
|
||||||
|
struct usb_setup_packet *setup;
|
||||||
|
int ret;
|
||||||
|
uint8_t len;
|
||||||
|
uint32_t offset;
|
||||||
|
|
||||||
|
if (!aoa_class || !aoa_class->hport) {
|
||||||
|
return -USB_ERR_INVAL;
|
||||||
|
}
|
||||||
|
setup = aoa_class->hport->setup;
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||||
|
setup->bRequest = AOA_ACCESSORY_REGISTER_HID;
|
||||||
|
setup->wValue = id;
|
||||||
|
setup->wIndex = report_len;
|
||||||
|
setup->wLength = 0;
|
||||||
|
|
||||||
|
ret = usbh_control_transfer(aoa_class->hport, setup, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
while (report_len > 0) {
|
||||||
|
len = report_len > 64 ? 64 : report_len;
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||||
|
setup->bRequest = AOA_ACCESSORY_SET_HID_REPORT_DESC;
|
||||||
|
setup->wValue = id;
|
||||||
|
setup->wIndex = offset;
|
||||||
|
setup->wLength = len;
|
||||||
|
|
||||||
|
memcpy(g_aoa_buffer, report + offset, len);
|
||||||
|
ret = usbh_control_transfer(aoa_class->hport, setup, g_aoa_buffer);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
offset += len;
|
||||||
|
report_len -= len;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int usbh_aoa_send_hid_event(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *event, uint32_t event_len)
|
||||||
|
{
|
||||||
|
struct usb_setup_packet *setup;
|
||||||
|
int ret;
|
||||||
|
uint8_t len;
|
||||||
|
uint32_t offset;
|
||||||
|
|
||||||
|
if (!aoa_class || !aoa_class->hport) {
|
||||||
|
return -USB_ERR_INVAL;
|
||||||
|
}
|
||||||
|
setup = aoa_class->hport->setup;
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_VENDOR | USB_REQUEST_RECIPIENT_DEVICE;
|
||||||
|
setup->bRequest = AOA_ACCESSORY_SEND_HID_EVENT;
|
||||||
|
setup->wValue = id;
|
||||||
|
setup->wIndex = 0;
|
||||||
|
setup->wLength = event_len;
|
||||||
|
|
||||||
|
memcpy(g_aoa_buffer, event, event_len);
|
||||||
|
return usbh_control_transfer(aoa_class->hport, setup, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int usbh_aoa_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||||
|
{
|
||||||
|
struct usb_endpoint_descriptor *ep_desc;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
struct usbh_aoa *aoa_class = &g_aoa_class;
|
||||||
|
|
||||||
|
memset(aoa_class, 0, sizeof(struct usbh_aoa));
|
||||||
|
|
||||||
|
aoa_class->hport = hport;
|
||||||
|
aoa_class->intf = intf;
|
||||||
|
|
||||||
|
hport->config.intf[intf].priv = aoa_class;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
|
||||||
|
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
|
||||||
|
|
||||||
|
if (ep_desc->bEndpointAddress & 0x80) {
|
||||||
|
USBH_EP_INIT(aoa_class->bulkin, ep_desc);
|
||||||
|
} else {
|
||||||
|
USBH_EP_INIT(aoa_class->bulkout, ep_desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
|
||||||
|
|
||||||
|
USB_LOG_INFO("Register AOA Class:%s\r\n", hport->config.intf[intf].devname);
|
||||||
|
|
||||||
|
usbh_aoa_run(aoa_class);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int usbh_aoa_disconnect(struct usbh_hubport *hport, uint8_t intf)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
struct usbh_aoa *aoa_class = (struct usbh_aoa *)hport->config.intf[intf].priv;
|
||||||
|
|
||||||
|
if (aoa_class) {
|
||||||
|
if (aoa_class->bulkin) {
|
||||||
|
usbh_kill_urb(&aoa_class->bulkin_urb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aoa_class->bulkout) {
|
||||||
|
usbh_kill_urb(&aoa_class->bulkout_urb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hport->config.intf[intf].devname[0] != '\0') {
|
||||||
|
USB_LOG_INFO("Unregister AOA Class:%s\r\n", hport->config.intf[intf].devname);
|
||||||
|
usbh_aoa_stop(aoa_class);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(aoa_class, 0, sizeof(struct usbh_aoa));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
__WEAK void usbh_aoa_run(struct usbh_aoa *aoa_class)
|
||||||
|
{
|
||||||
|
(void)aoa_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
__WEAK void usbh_aoa_stop(struct usbh_aoa *aoa_class)
|
||||||
|
{
|
||||||
|
(void)aoa_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint16_t aoa_id_table[][2] = {
|
||||||
|
{ AOA_ACCESSORY_VENDOR_ID, AOA_ACCESSORY_PRODUCT_ID },
|
||||||
|
{ AOA_ACCESSORY_VENDOR_ID, AOA_ACCESSORY_ADB_PRODUCT_ID },
|
||||||
|
{ AOA_ACCESSORY_VENDOR_ID, AOA_AUDIO_PRODUCT_ID },
|
||||||
|
{ AOA_ACCESSORY_VENDOR_ID, AOA_AUDIO_ADB_PRODUCT_ID },
|
||||||
|
{ AOA_ACCESSORY_VENDOR_ID, AOA_ACCESSORY_AUDIO_PRODUCT_ID },
|
||||||
|
{ AOA_ACCESSORY_VENDOR_ID, AOA_ACCESSORY_AUDIO_ADB_PRODUCT_ID },
|
||||||
|
{ 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct usbh_class_driver aoa_class_driver = {
|
||||||
|
.driver_name = "aoa",
|
||||||
|
.connect = usbh_aoa_connect,
|
||||||
|
.disconnect = usbh_aoa_disconnect
|
||||||
|
};
|
||||||
|
|
||||||
|
CLASS_INFO_DEFINE const struct usbh_class_info aoa_intf_class_info = {
|
||||||
|
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
|
||||||
|
.bInterfaceClass = 0xff,
|
||||||
|
.bInterfaceSubClass = 0xff,
|
||||||
|
.bInterfaceProtocol = 0x00,
|
||||||
|
.id_table = aoa_id_table,
|
||||||
|
.class_driver = &aoa_class_driver
|
||||||
|
};
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2024, sakumisu
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#ifndef USBH_AOA_H
|
||||||
|
#define USBH_AOA_H
|
||||||
|
|
||||||
|
#include "usb_aoa.h"
|
||||||
|
|
||||||
|
struct usbh_aoa {
|
||||||
|
struct usbh_hubport *hport;
|
||||||
|
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
|
||||||
|
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
|
||||||
|
|
||||||
|
struct usbh_urb bulkout_urb;
|
||||||
|
struct usbh_urb bulkin_urb;
|
||||||
|
|
||||||
|
uint8_t intf;
|
||||||
|
uint8_t minor;
|
||||||
|
|
||||||
|
void *user_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int usbh_aoa_switch(struct usbh_hubport *hport, struct aoa_string_info *info);
|
||||||
|
int usbh_aoa_register_hid(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *report, uint32_t report_len);
|
||||||
|
int usbh_aoa_send_hid_event(struct usbh_aoa *aoa_class, uint16_t id, uint8_t *event, uint32_t event_len);
|
||||||
|
|
||||||
|
void usbh_aoa_run(struct usbh_aoa *aoa_class);
|
||||||
|
void usbh_aoa_stop(struct usbh_aoa *aoa_class);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* USBH_AOA_H */
|
@ -648,6 +648,18 @@ struct audio_cs_if_ac_feature_unit_descriptor {
|
|||||||
|
|
||||||
#define AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(ch, n) (7 + (ch + 1) * n)
|
#define AUDIO_SIZEOF_AC_FEATURE_UNIT_DESC(ch, n) (7 + (ch + 1) * n)
|
||||||
|
|
||||||
|
struct audio_cs_if_ac_selector_unit_descriptor {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint8_t bDescriptorSubtype;
|
||||||
|
uint8_t bUnitID;
|
||||||
|
uint8_t bNrInPins;
|
||||||
|
uint8_t baSourceID[1];
|
||||||
|
uint8_t iSelector;
|
||||||
|
} __PACKED;
|
||||||
|
|
||||||
|
#define AUDIO_SIZEOF_AC_SELECTOR_UNIT_DESC(n) (6 + n)
|
||||||
|
|
||||||
struct audio_cs_if_as_general_descriptor {
|
struct audio_cs_if_as_general_descriptor {
|
||||||
uint8_t bLength;
|
uint8_t bLength;
|
||||||
uint8_t bDescriptorType;
|
uint8_t bDescriptorType;
|
||||||
|
@ -136,27 +136,26 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
|||||||
memcpy(&volume, *data, *len);
|
memcpy(&volume, *data, *len);
|
||||||
if (volume < 0x8000) {
|
if (volume < 0x8000) {
|
||||||
volume_db = volume / 256;
|
volume_db = volume / 256;
|
||||||
} else if (volume > 0x8000) {
|
} else {
|
||||||
volume_db = (0xffff - volume + 1) / -256;
|
volume_db = (volume - 0x10000) / 256;
|
||||||
}
|
}
|
||||||
volume_db += 128; /* 0 ~ 255 */
|
USB_LOG_DBG("Set ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
|
||||||
USB_LOG_DBG("Set ep:0x%02x ch:%d volume:0x%04x\r\n", ep, ch, volume);
|
|
||||||
usbd_audio_set_volume(busid, ep, ch, volume_db);
|
usbd_audio_set_volume(busid, ep, ch, volume_db);
|
||||||
break;
|
break;
|
||||||
case AUDIO_REQUEST_GET_CUR:
|
case AUDIO_REQUEST_GET_CUR:
|
||||||
volume_db = usbd_audio_get_volume(busid, ep, ch);
|
volume_db = usbd_audio_get_volume(busid, ep, ch);
|
||||||
volume_db -= 128;
|
|
||||||
if (volume_db >= 0) {
|
if (volume_db >= 0) {
|
||||||
volume = volume_db * 256;
|
volume = volume_db * 256;
|
||||||
} else {
|
} else {
|
||||||
volume = volume_db * 256 + 0xffff + 1;
|
volume = volume_db * 256 + 0x10000;
|
||||||
}
|
}
|
||||||
|
USB_LOG_DBG("Get ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
|
||||||
memcpy(*data, &volume, 2);
|
memcpy(*data, &volume, 2);
|
||||||
*len = 2;
|
*len = 2;
|
||||||
break;
|
break;
|
||||||
case AUDIO_REQUEST_GET_MIN:
|
case AUDIO_REQUEST_GET_MIN:
|
||||||
(*data)[0] = 0x00; /* -2560/256 dB */
|
(*data)[0] = 0x00; /* -100 dB */
|
||||||
(*data)[1] = 0xdb;
|
(*data)[1] = 0x9c;
|
||||||
*len = 2;
|
*len = 2;
|
||||||
break;
|
break;
|
||||||
case AUDIO_REQUEST_GET_MAX:
|
case AUDIO_REQUEST_GET_MAX:
|
||||||
@ -165,7 +164,7 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
|||||||
*len = 2;
|
*len = 2;
|
||||||
break;
|
break;
|
||||||
case AUDIO_REQUEST_GET_RES:
|
case AUDIO_REQUEST_GET_RES:
|
||||||
(*data)[0] = 0x00; /* -256/256 dB */
|
(*data)[0] = 0x00; /* 1 dB */
|
||||||
(*data)[1] = 0x01;
|
(*data)[1] = 0x01;
|
||||||
*len = 2;
|
*len = 2;
|
||||||
break;
|
break;
|
||||||
@ -178,22 +177,31 @@ static int audio_class_interface_request_handler(uint8_t busid, struct usb_setup
|
|||||||
case AUDIO_REQUEST_CUR:
|
case AUDIO_REQUEST_CUR:
|
||||||
if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
|
if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
|
||||||
volume_db = usbd_audio_get_volume(busid, ep, ch);
|
volume_db = usbd_audio_get_volume(busid, ep, ch);
|
||||||
volume = volume_db;
|
if (volume_db >= 0) {
|
||||||
|
volume = volume_db * 256;
|
||||||
|
} else {
|
||||||
|
volume = volume_db * 256 + 0x10000;
|
||||||
|
}
|
||||||
|
USB_LOG_DBG("Get ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
|
||||||
memcpy(*data, &volume, 2);
|
memcpy(*data, &volume, 2);
|
||||||
*len = 2;
|
*len = 2;
|
||||||
} else {
|
} else {
|
||||||
memcpy(&volume, *data, *len);
|
memcpy(&volume, *data, *len);
|
||||||
volume_db = volume;
|
if (volume < 0x8000) {
|
||||||
USB_LOG_DBG("Set ep:0x%02x ch:%d volume:0x%02x\r\n", ep, ch, volume);
|
volume_db = volume / 256;
|
||||||
|
} else {
|
||||||
|
volume_db = (volume - 0x10000) / 256;
|
||||||
|
}
|
||||||
|
USB_LOG_DBG("Set ep:0x%02x ch:%d vol_hex:0x%04x, vol_db:%d dB\r\n", ep, ch, volume, volume_db);
|
||||||
usbd_audio_set_volume(busid, ep, ch, volume_db);
|
usbd_audio_set_volume(busid, ep, ch, volume_db);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AUDIO_REQUEST_RANGE:
|
case AUDIO_REQUEST_RANGE:
|
||||||
if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
|
if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
|
||||||
*((uint16_t *)(*data + 0)) = 1;
|
*((uint16_t *)(*data + 0)) = 1;
|
||||||
*((uint16_t *)(*data + 2)) = 0;
|
*((uint16_t *)(*data + 2)) = 0x9c00; /* MIN -100 dB */
|
||||||
*((uint16_t *)(*data + 4)) = 100;
|
*((uint16_t *)(*data + 4)) = 0x0000; /* MAX 0 dB */
|
||||||
*((uint16_t *)(*data + 6)) = 1;
|
*((uint16_t *)(*data + 6)) = 0x100; /* RES 1 dB */
|
||||||
*len = 8;
|
*len = 8;
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
@ -312,12 +320,12 @@ struct usbd_interface *usbd_audio_init_intf(uint8_t busid,
|
|||||||
return intf;
|
return intf;
|
||||||
}
|
}
|
||||||
|
|
||||||
__WEAK void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume)
|
__WEAK void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume_db)
|
||||||
{
|
{
|
||||||
(void)busid;
|
(void)busid;
|
||||||
(void)ep;
|
(void)ep;
|
||||||
(void)ch;
|
(void)ch;
|
||||||
(void)volume;
|
(void)volume_db;
|
||||||
}
|
}
|
||||||
|
|
||||||
__WEAK int usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch)
|
__WEAK int usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch)
|
||||||
|
@ -27,7 +27,7 @@ struct usbd_interface *usbd_audio_init_intf(uint8_t busid, struct usbd_interface
|
|||||||
void usbd_audio_open(uint8_t busid, uint8_t intf);
|
void usbd_audio_open(uint8_t busid, uint8_t intf);
|
||||||
void usbd_audio_close(uint8_t busid, uint8_t intf);
|
void usbd_audio_close(uint8_t busid, uint8_t intf);
|
||||||
|
|
||||||
void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume);
|
void usbd_audio_set_volume(uint8_t busid, uint8_t ep, uint8_t ch, int volume_db);
|
||||||
int usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch);
|
int usbd_audio_get_volume(uint8_t busid, uint8_t ep, uint8_t ch);
|
||||||
void usbd_audio_set_mute(uint8_t busid, uint8_t ep, uint8_t ch, bool mute);
|
void usbd_audio_set_mute(uint8_t busid, uint8_t ep, uint8_t ch, bool mute);
|
||||||
bool usbd_audio_get_mute(uint8_t busid, uint8_t ep, uint8_t ch);
|
bool usbd_audio_get_mute(uint8_t busid, uint8_t ep, uint8_t ch);
|
||||||
|
@ -184,18 +184,21 @@ int usbh_audio_close(struct usbh_audio *audio_class, const char *name)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, uint8_t volume)
|
int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, int volume_db)
|
||||||
{
|
{
|
||||||
struct usb_setup_packet *setup;
|
struct usb_setup_packet *setup;
|
||||||
int ret;
|
int ret;
|
||||||
uint8_t feature_id = 0xff;
|
uint8_t feature_id = 0xff;
|
||||||
|
uint8_t intf;
|
||||||
uint16_t volume_hex;
|
uint16_t volume_hex;
|
||||||
|
int volume_min_db;
|
||||||
|
int volume_max_db;
|
||||||
|
|
||||||
if (!audio_class || !audio_class->hport) {
|
if (!audio_class || !audio_class->hport) {
|
||||||
return -USB_ERR_INVAL;
|
return -USB_ERR_INVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (volume > 100) {
|
if ((volume_db > 127) || (volume_db < -127)) {
|
||||||
return -USB_ERR_INVAL;
|
return -USB_ERR_INVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,20 +207,102 @@ int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint
|
|||||||
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
|
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
|
||||||
if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
|
if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
|
||||||
feature_id = audio_class->as_msg_table[i].feature_terminal_id;
|
feature_id = audio_class->as_msg_table[i].feature_terminal_id;
|
||||||
|
intf = audio_class->as_msg_table[i].stream_intf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (feature_id == 0xff) {
|
||||||
|
return -USB_ERR_NODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||||
|
setup->bRequest = AUDIO_REQUEST_GET_CUR;
|
||||||
|
setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
|
||||||
|
setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
|
||||||
|
setup->wLength = 2;
|
||||||
|
|
||||||
|
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_cur, g_audio_buf, 2);
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||||
|
setup->bRequest = AUDIO_REQUEST_GET_MIN;
|
||||||
|
setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
|
||||||
|
setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
|
||||||
|
setup->wLength = 2;
|
||||||
|
|
||||||
|
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min, g_audio_buf, 2);
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||||
|
setup->bRequest = AUDIO_REQUEST_GET_MAX;
|
||||||
|
setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
|
||||||
|
setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
|
||||||
|
setup->wLength = 2;
|
||||||
|
|
||||||
|
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max, g_audio_buf, 2);
|
||||||
|
|
||||||
|
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||||
|
setup->bRequest = AUDIO_REQUEST_GET_RES;
|
||||||
|
setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
|
||||||
|
setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
|
||||||
|
setup->wLength = 2;
|
||||||
|
|
||||||
|
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_res, g_audio_buf, 2);
|
||||||
|
|
||||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||||
setup->bRequest = AUDIO_REQUEST_SET_CUR;
|
setup->bRequest = AUDIO_REQUEST_SET_CUR;
|
||||||
setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
|
setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
|
||||||
setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
|
setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
|
||||||
setup->wLength = 2;
|
setup->wLength = 2;
|
||||||
|
|
||||||
volume_hex = -0xDB00 / 100 * volume + 0xdb00;
|
if (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min < 0x8000) {
|
||||||
|
volume_min_db = audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min / 256;
|
||||||
|
} else {
|
||||||
|
volume_min_db = (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min - 0x10000) / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max < 0x8000) {
|
||||||
|
volume_max_db = audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max / 256;
|
||||||
|
} else {
|
||||||
|
volume_max_db = (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max - 0x10000) / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
USB_LOG_INFO("Get ch:%d dB range: %d dB ~ %d dB\r\n", volume_min_db, volume_max_db);
|
||||||
|
|
||||||
|
if (volume_db >= 0) {
|
||||||
|
volume_hex = volume_db * 256;
|
||||||
|
if (volume_hex > audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max) {
|
||||||
|
return -USB_ERR_RANGE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
volume_hex = volume_db * 256 + 0x10000;
|
||||||
|
if (volume_hex < audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min) {
|
||||||
|
return -USB_ERR_RANGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(g_audio_buf, &volume_hex, 2);
|
memcpy(g_audio_buf, &volume_hex, 2);
|
||||||
ret = usbh_control_transfer(audio_class->hport, setup, NULL);
|
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_cur = volume_hex;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +311,7 @@ int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_
|
|||||||
struct usb_setup_packet *setup;
|
struct usb_setup_packet *setup;
|
||||||
int ret;
|
int ret;
|
||||||
uint8_t feature_id = 0xff;
|
uint8_t feature_id = 0xff;
|
||||||
|
uint8_t intf = 0xff;
|
||||||
|
|
||||||
if (!audio_class || !audio_class->hport) {
|
if (!audio_class || !audio_class->hport) {
|
||||||
return -USB_ERR_INVAL;
|
return -USB_ERR_INVAL;
|
||||||
@ -235,9 +321,14 @@ int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_
|
|||||||
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
|
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
|
||||||
if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
|
if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
|
||||||
feature_id = audio_class->as_msg_table[i].feature_terminal_id;
|
feature_id = audio_class->as_msg_table[i].feature_terminal_id;
|
||||||
|
intf = audio_class->as_msg_table[i].stream_intf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (feature_id == 0xff) {
|
||||||
|
return -USB_ERR_NODEV;
|
||||||
|
}
|
||||||
|
|
||||||
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
|
||||||
setup->bRequest = AUDIO_REQUEST_SET_CUR;
|
setup->bRequest = AUDIO_REQUEST_SET_CUR;
|
||||||
setup->wValue = (AUDIO_FU_CONTROL_MUTE << 8) | ch;
|
setup->wValue = (AUDIO_FU_CONTROL_MUTE << 8) | ch;
|
||||||
@ -246,7 +337,10 @@ int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_
|
|||||||
|
|
||||||
memcpy(g_audio_buf, &mute, 1);
|
memcpy(g_audio_buf, &mute, 1);
|
||||||
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
|
ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].mute = mute;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,13 +380,14 @@ void usbh_audio_list_module(struct usbh_audio *audio_class)
|
|||||||
static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
|
static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
uint8_t cur_iface = 0xff;
|
uint8_t cur_iface = 0;
|
||||||
uint8_t cur_iface_count = 0xff;
|
uint8_t cur_iface_count = 0;
|
||||||
uint8_t cur_alt_setting = 0xff;
|
uint8_t cur_alt_setting = 0;
|
||||||
uint8_t input_offset = 0;
|
uint8_t input_offset = 0;
|
||||||
uint8_t output_offset = 0;
|
uint8_t output_offset = 0;
|
||||||
uint8_t feature_unit_offset = 0;
|
uint8_t feature_unit_offset = 0;
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
|
struct usbh_audio_ac_msg ac_msg_table[CONFIG_USBHOST_AUDIO_MAX_STREAMS];
|
||||||
|
|
||||||
struct usbh_audio *audio_class = usbh_audio_class_alloc();
|
struct usbh_audio *audio_class = usbh_audio_class_alloc();
|
||||||
if (audio_class == NULL) {
|
if (audio_class == NULL) {
|
||||||
@ -327,26 +422,24 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
|
|||||||
case AUDIO_CONTROL_INPUT_TERMINAL: {
|
case AUDIO_CONTROL_INPUT_TERMINAL: {
|
||||||
struct audio_cs_if_ac_input_terminal_descriptor *desc = (struct audio_cs_if_ac_input_terminal_descriptor *)p;
|
struct audio_cs_if_ac_input_terminal_descriptor *desc = (struct audio_cs_if_ac_input_terminal_descriptor *)p;
|
||||||
|
|
||||||
memcpy(&audio_class->ac_msg_table[input_offset].ac_input, desc, sizeof(struct audio_cs_if_ac_input_terminal_descriptor));
|
memcpy(&ac_msg_table[input_offset].ac_input, desc, sizeof(struct audio_cs_if_ac_input_terminal_descriptor));
|
||||||
input_offset++;
|
input_offset++;
|
||||||
} break;
|
} break;
|
||||||
case AUDIO_CONTROL_OUTPUT_TERMINAL: {
|
case AUDIO_CONTROL_OUTPUT_TERMINAL: {
|
||||||
struct audio_cs_if_ac_output_terminal_descriptor *desc = (struct audio_cs_if_ac_output_terminal_descriptor *)p;
|
struct audio_cs_if_ac_output_terminal_descriptor *desc = (struct audio_cs_if_ac_output_terminal_descriptor *)p;
|
||||||
|
|
||||||
memcpy(&audio_class->ac_msg_table[output_offset].ac_output, desc, sizeof(struct audio_cs_if_ac_output_terminal_descriptor));
|
memcpy(&ac_msg_table[output_offset].ac_output, desc, sizeof(struct audio_cs_if_ac_output_terminal_descriptor));
|
||||||
output_offset++;
|
output_offset++;
|
||||||
} break;
|
} break;
|
||||||
case AUDIO_CONTROL_FEATURE_UNIT: {
|
case AUDIO_CONTROL_FEATURE_UNIT: {
|
||||||
struct audio_cs_if_ac_feature_unit_descriptor *desc = (struct audio_cs_if_ac_feature_unit_descriptor *)p;
|
struct audio_cs_if_ac_feature_unit_descriptor *desc = (struct audio_cs_if_ac_feature_unit_descriptor *)p;
|
||||||
|
|
||||||
memcpy(&audio_class->ac_msg_table[feature_unit_offset].ac_feature_unit, desc, desc->bLength);
|
memcpy(&ac_msg_table[feature_unit_offset].ac_feature_unit, desc, desc->bLength);
|
||||||
feature_unit_offset++;
|
feature_unit_offset++;
|
||||||
} break;
|
} break;
|
||||||
case AUDIO_CONTROL_PROCESSING_UNIT:
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
USB_LOG_ERR("Do not support %02x subtype\r\n", p[DESC_bDescriptorSubType]);
|
||||||
|
return -USB_ERR_NOTSUPP;
|
||||||
}
|
}
|
||||||
} else if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) {
|
} else if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) {
|
||||||
switch (p[DESC_bDescriptorSubType]) {
|
switch (p[DESC_bDescriptorSubType]) {
|
||||||
@ -383,7 +476,12 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((input_offset != output_offset) && (input_offset != feature_unit_offset)) {
|
if ((input_offset != output_offset) && (input_offset != feature_unit_offset)) {
|
||||||
USB_LOG_ERR("Audio descriptor is invalid\r\n");
|
USB_LOG_ERR("Audio control descriptor is invalid\r\n");
|
||||||
|
return -USB_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur_iface_count == 0xff) {
|
||||||
|
USB_LOG_ERR("Audio descriptor must have iad descriptor\r\n");
|
||||||
return -USB_ERR_INVAL;
|
return -USB_ERR_INVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,21 +490,21 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
|
|||||||
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
|
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
|
||||||
/* Search 0x0101 in input or output desc */
|
/* Search 0x0101 in input or output desc */
|
||||||
for (uint8_t streamidx = 0; streamidx < audio_class->stream_intf_num; streamidx++) {
|
for (uint8_t streamidx = 0; streamidx < audio_class->stream_intf_num; streamidx++) {
|
||||||
if (audio_class->as_msg_table[i].as_general.bTerminalLink == audio_class->ac_msg_table[streamidx].ac_input.bTerminalID) {
|
if (audio_class->as_msg_table[i].as_general.bTerminalLink == ac_msg_table[streamidx].ac_input.bTerminalID) {
|
||||||
/* INPUT --> FEATURE UNIT --> OUTPUT */
|
/* INPUT --> FEATURE UNIT --> OUTPUT */
|
||||||
audio_class->as_msg_table[i].input_terminal_id = audio_class->ac_msg_table[streamidx].ac_input.bTerminalID;
|
audio_class->as_msg_table[i].input_terminal_id = ac_msg_table[streamidx].ac_input.bTerminalID;
|
||||||
|
|
||||||
/* Search input terminal id in feature desc */
|
/* Search input terminal id in feature desc */
|
||||||
for (uint8_t featureidx = 0; featureidx < audio_class->stream_intf_num; featureidx++) {
|
for (uint8_t featureidx = 0; featureidx < audio_class->stream_intf_num; featureidx++) {
|
||||||
if (audio_class->ac_msg_table[streamidx].ac_input.bTerminalID == audio_class->ac_msg_table[featureidx].ac_feature_unit.bSourceID) {
|
if (ac_msg_table[streamidx].ac_input.bTerminalID == ac_msg_table[featureidx].ac_feature_unit.bSourceID) {
|
||||||
audio_class->as_msg_table[i].feature_terminal_id = audio_class->ac_msg_table[featureidx].ac_feature_unit.bUnitID;
|
audio_class->as_msg_table[i].feature_terminal_id = ac_msg_table[featureidx].ac_feature_unit.bUnitID;
|
||||||
|
|
||||||
/* Search feature unit id in output desc */
|
/* Search feature unit id in output desc */
|
||||||
for (uint8_t outputid = 0; outputid < audio_class->stream_intf_num; outputid++) {
|
for (uint8_t outputid = 0; outputid < audio_class->stream_intf_num; outputid++) {
|
||||||
if (audio_class->ac_msg_table[featureidx].ac_feature_unit.bUnitID == audio_class->ac_msg_table[outputid].ac_output.bSourceID) {
|
if (ac_msg_table[featureidx].ac_feature_unit.bUnitID == ac_msg_table[outputid].ac_output.bSourceID) {
|
||||||
audio_class->as_msg_table[i].output_terminal_id = audio_class->ac_msg_table[outputid].ac_output.bTerminalID;
|
audio_class->as_msg_table[i].output_terminal_id = ac_msg_table[outputid].ac_output.bTerminalID;
|
||||||
|
|
||||||
switch (audio_class->ac_msg_table[outputid].ac_output.wTerminalType) {
|
switch (ac_msg_table[outputid].ac_output.wTerminalType) {
|
||||||
case AUDIO_OUTTERM_SPEAKER:
|
case AUDIO_OUTTERM_SPEAKER:
|
||||||
audio_class->as_msg_table[i].stream_name = "speaker";
|
audio_class->as_msg_table[i].stream_name = "speaker";
|
||||||
break;
|
break;
|
||||||
@ -426,21 +524,21 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (audio_class->as_msg_table[i].as_general.bTerminalLink == audio_class->ac_msg_table[streamidx].ac_output.bTerminalID) {
|
} else if (audio_class->as_msg_table[i].as_general.bTerminalLink == ac_msg_table[streamidx].ac_output.bTerminalID) {
|
||||||
/* OUTPUT --> FEATURE UNIT --> INPUT */
|
/* OUTPUT --> FEATURE UNIT --> INPUT */
|
||||||
audio_class->as_msg_table[i].output_terminal_id = audio_class->ac_msg_table[streamidx].ac_output.bTerminalID;
|
audio_class->as_msg_table[i].output_terminal_id = ac_msg_table[streamidx].ac_output.bTerminalID;
|
||||||
|
|
||||||
/* Search output terminal id in feature desc */
|
/* Search output terminal id in feature desc */
|
||||||
for (uint8_t featureidx = 0; featureidx < audio_class->stream_intf_num; featureidx++) {
|
for (uint8_t featureidx = 0; featureidx < audio_class->stream_intf_num; featureidx++) {
|
||||||
if (audio_class->ac_msg_table[streamidx].ac_output.bSourceID == audio_class->ac_msg_table[featureidx].ac_feature_unit.bUnitID) {
|
if (ac_msg_table[streamidx].ac_output.bSourceID == ac_msg_table[featureidx].ac_feature_unit.bUnitID) {
|
||||||
audio_class->as_msg_table[i].feature_terminal_id = audio_class->ac_msg_table[featureidx].ac_feature_unit.bUnitID;
|
audio_class->as_msg_table[i].feature_terminal_id = ac_msg_table[featureidx].ac_feature_unit.bUnitID;
|
||||||
|
|
||||||
/* Search feature unit id in input desc */
|
/* Search feature unit id in input desc */
|
||||||
for (uint8_t inputid = 0; inputid < audio_class->stream_intf_num; inputid++) {
|
for (uint8_t inputid = 0; inputid < audio_class->stream_intf_num; inputid++) {
|
||||||
if (audio_class->ac_msg_table[featureidx].ac_feature_unit.bSourceID == audio_class->ac_msg_table[inputid].ac_input.bTerminalID) {
|
if (ac_msg_table[featureidx].ac_feature_unit.bSourceID == ac_msg_table[inputid].ac_input.bTerminalID) {
|
||||||
audio_class->as_msg_table[i].input_terminal_id = audio_class->ac_msg_table[inputid].ac_input.bTerminalID;
|
audio_class->as_msg_table[i].input_terminal_id = ac_msg_table[inputid].ac_input.bTerminalID;
|
||||||
|
|
||||||
switch (audio_class->ac_msg_table[inputid].ac_input.wTerminalType) {
|
switch (ac_msg_table[inputid].ac_input.wTerminalType) {
|
||||||
case AUDIO_INTERM_MIC:
|
case AUDIO_INTERM_MIC:
|
||||||
audio_class->as_msg_table[i].stream_name = "mic";
|
audio_class->as_msg_table[i].stream_name = "mic";
|
||||||
break;
|
break;
|
||||||
@ -458,6 +556,13 @@ static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
|
||||||
|
if (audio_class->as_msg_table[i].stream_name == NULL) {
|
||||||
|
USB_LOG_ERR("Audio stream search fail\r\n");
|
||||||
|
return -USB_ERR_NODEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
|
for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
|
||||||
ret = usbh_audio_close(audio_class, audio_class->as_msg_table[i].stream_name);
|
ret = usbh_audio_close(audio_class, audio_class->as_msg_table[i].stream_name);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -537,18 +642,18 @@ const struct usbh_class_driver audio_streaming_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info audio_ctrl_intf_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info audio_ctrl_intf_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
|
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
|
||||||
.class = USB_DEVICE_CLASS_AUDIO,
|
.bInterfaceClass = USB_DEVICE_CLASS_AUDIO,
|
||||||
.subclass = AUDIO_SUBCLASS_AUDIOCONTROL,
|
.bInterfaceSubClass = AUDIO_SUBCLASS_AUDIOCONTROL,
|
||||||
.protocol = 0x00,
|
.bInterfaceProtocol = 0x00,
|
||||||
.id_table = NULL,
|
.id_table = NULL,
|
||||||
.class_driver = &audio_ctrl_class_driver
|
.class_driver = &audio_ctrl_class_driver
|
||||||
};
|
};
|
||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info audio_streaming_intf_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info audio_streaming_intf_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
|
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
|
||||||
.class = USB_DEVICE_CLASS_AUDIO,
|
.bInterfaceClass = USB_DEVICE_CLASS_AUDIO,
|
||||||
.subclass = AUDIO_SUBCLASS_AUDIOSTREAMING,
|
.bInterfaceSubClass = AUDIO_SUBCLASS_AUDIOSTREAMING,
|
||||||
.protocol = 0x00,
|
.bInterfaceProtocol = 0x00,
|
||||||
.id_table = NULL,
|
.id_table = NULL,
|
||||||
.class_driver = &audio_streaming_class_driver
|
.class_driver = &audio_streaming_class_driver
|
||||||
};
|
};
|
||||||
|
@ -26,6 +26,11 @@ struct usbh_audio_as_msg {
|
|||||||
uint8_t output_terminal_id;
|
uint8_t output_terminal_id;
|
||||||
uint8_t ep_attr;
|
uint8_t ep_attr;
|
||||||
uint8_t num_of_altsetting;
|
uint8_t num_of_altsetting;
|
||||||
|
uint16_t volume_min;
|
||||||
|
uint16_t volume_max;
|
||||||
|
uint16_t volume_res;
|
||||||
|
uint16_t volume_cur;
|
||||||
|
bool mute;
|
||||||
struct audio_cs_if_as_general_descriptor as_general;
|
struct audio_cs_if_as_general_descriptor as_general;
|
||||||
struct audio_cs_if_as_format_type_descriptor as_format[CONFIG_USBHOST_MAX_INTF_ALTSETTINGS];
|
struct audio_cs_if_as_format_type_descriptor as_format[CONFIG_USBHOST_MAX_INTF_ALTSETTINGS];
|
||||||
};
|
};
|
||||||
@ -43,7 +48,6 @@ struct usbh_audio {
|
|||||||
uint16_t bcdADC;
|
uint16_t bcdADC;
|
||||||
uint8_t bInCollection;
|
uint8_t bInCollection;
|
||||||
uint8_t stream_intf_num;
|
uint8_t stream_intf_num;
|
||||||
struct usbh_audio_ac_msg ac_msg_table[CONFIG_USBHOST_AUDIO_MAX_STREAMS];
|
|
||||||
struct usbh_audio_as_msg as_msg_table[CONFIG_USBHOST_AUDIO_MAX_STREAMS];
|
struct usbh_audio_as_msg as_msg_table[CONFIG_USBHOST_AUDIO_MAX_STREAMS];
|
||||||
|
|
||||||
void *user_data;
|
void *user_data;
|
||||||
@ -55,7 +59,7 @@ extern "C" {
|
|||||||
|
|
||||||
int usbh_audio_open(struct usbh_audio *audio_class, const char *name, uint32_t samp_freq, uint8_t bitresolution);
|
int usbh_audio_open(struct usbh_audio *audio_class, const char *name, uint32_t samp_freq, uint8_t bitresolution);
|
||||||
int usbh_audio_close(struct usbh_audio *audio_class, const char *name);
|
int usbh_audio_close(struct usbh_audio *audio_class, const char *name);
|
||||||
int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, uint8_t volume);
|
int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, int volume_db);
|
||||||
int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_t ch, bool mute);
|
int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_t ch, bool mute);
|
||||||
|
|
||||||
void usbh_audio_run(struct usbh_audio *audio_class);
|
void usbh_audio_run(struct usbh_audio *audio_class);
|
||||||
|
@ -524,7 +524,7 @@ struct cdc_ncm_ndp16 {
|
|||||||
int_ep, /* bEndpointAddress */ \
|
int_ep, /* bEndpointAddress */ \
|
||||||
0x03, /* bmAttributes */ \
|
0x03, /* bmAttributes */ \
|
||||||
0x08, 0x00, /* wMaxPacketSize */ \
|
0x08, 0x00, /* wMaxPacketSize */ \
|
||||||
0x10, /* bInterval */ \
|
0x05, /* bInterval */ \
|
||||||
0x09, /* bLength */ \
|
0x09, /* bLength */ \
|
||||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||||
(uint8_t)(bFirstInterface + 1), /* bInterfaceNumber */ \
|
(uint8_t)(bFirstInterface + 1), /* bInterfaceNumber */ \
|
||||||
@ -596,7 +596,7 @@ eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx)
|
|||||||
int_ep, /* bEndpointAddress */ \
|
int_ep, /* bEndpointAddress */ \
|
||||||
0x03, /* bmAttributes */ \
|
0x03, /* bmAttributes */ \
|
||||||
0x10, 0x00, /* wMaxPacketSize */ \
|
0x10, 0x00, /* wMaxPacketSize */ \
|
||||||
0x10, /* bInterval */ \
|
0x05, /* bInterval */ \
|
||||||
0x09, /* bLength */ \
|
0x09, /* bLength */ \
|
||||||
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \
|
||||||
(uint8_t)(bFirstInterface + 1), /* bInterfaceNumber */ \
|
(uint8_t)(bFirstInterface + 1), /* bInterfaceNumber */ \
|
||||||
|
@ -7,17 +7,21 @@
|
|||||||
#include "usbd_cdc_ecm.h"
|
#include "usbd_cdc_ecm.h"
|
||||||
|
|
||||||
#define CDC_ECM_OUT_EP_IDX 0
|
#define CDC_ECM_OUT_EP_IDX 0
|
||||||
#define CDC_ECM_IN_EP_IDX 1
|
#define CDC_ECM_IN_EP_IDX 1
|
||||||
#define CDC_ECM_INT_EP_IDX 2
|
#define CDC_ECM_INT_EP_IDX 2
|
||||||
|
|
||||||
|
/* Ethernet Maximum Segment size, typically 1514 bytes */
|
||||||
|
#define CONFIG_CDC_ECM_ETH_MAX_SEGSZE 1536U
|
||||||
|
|
||||||
/* Describe EndPoints configuration */
|
/* Describe EndPoints configuration */
|
||||||
static struct usbd_endpoint cdc_ecm_ep_data[3];
|
static struct usbd_endpoint cdc_ecm_ep_data[3];
|
||||||
|
|
||||||
|
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
|
||||||
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
|
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
|
||||||
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
|
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
|
||||||
|
#endif
|
||||||
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_notify_buf[16];
|
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_notify_buf[16];
|
||||||
|
|
||||||
volatile uint8_t *g_cdc_ecm_rx_data_buffer = NULL;
|
|
||||||
volatile uint32_t g_cdc_ecm_rx_data_length = 0;
|
volatile uint32_t g_cdc_ecm_rx_data_length = 0;
|
||||||
volatile uint32_t g_cdc_ecm_tx_data_length = 0;
|
volatile uint32_t g_cdc_ecm_tx_data_length = 0;
|
||||||
|
|
||||||
@ -68,8 +72,10 @@ void usbd_cdc_ecm_send_notify(uint8_t notifycode, uint8_t value, uint32_t *speed
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes2send) {
|
if (usb_device_is_configured(0)) {
|
||||||
usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr, g_cdc_ecm_notify_buf, bytes2send);
|
if (bytes2send) {
|
||||||
|
usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr, g_cdc_ecm_notify_buf, bytes2send);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,11 +99,11 @@ static int cdc_ecm_class_interface_request_handler(uint8_t busid, struct usb_set
|
|||||||
* bit3 Broadcast
|
* bit3 Broadcast
|
||||||
* bit4 Multicast
|
* bit4 Multicast
|
||||||
*/
|
*/
|
||||||
if (g_current_net_status == 0) {
|
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
|
||||||
g_current_net_status = 1;
|
g_connect_speed_table[0] = 100000000; /* 100 Mbps */
|
||||||
usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, NULL);
|
g_connect_speed_table[1] = 100000000; /* 100 Mbps */
|
||||||
}
|
usbd_cdc_ecm_set_connect(true, g_connect_speed_table);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
USB_LOG_WRN("Unhandled CDC ECM Class bRequest 0x%02x\r\n", setup->bRequest);
|
USB_LOG_WRN("Unhandled CDC ECM Class bRequest 0x%02x\r\n", setup->bRequest);
|
||||||
@ -117,10 +123,11 @@ void cdc_ecm_notify_handler(uint8_t busid, uint8_t event, void *arg)
|
|||||||
g_current_net_status = 0;
|
g_current_net_status = 0;
|
||||||
g_cdc_ecm_rx_data_length = 0;
|
g_cdc_ecm_rx_data_length = 0;
|
||||||
g_cdc_ecm_tx_data_length = 0;
|
g_cdc_ecm_tx_data_length = 0;
|
||||||
g_cdc_ecm_rx_data_buffer = NULL;
|
|
||||||
break;
|
break;
|
||||||
case USBD_EVENT_CONFIGURED:
|
case USBD_EVENT_CONFIGURED:
|
||||||
usbd_ep_start_read(0, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_data_length], usbd_get_ep_mps(busid, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr));
|
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
|
||||||
|
usbd_cdc_ecm_start_read(g_cdc_ecm_rx_buffer, CONFIG_CDC_ECM_ETH_MAX_SEGSZE);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -132,14 +139,8 @@ void cdc_ecm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
|||||||
{
|
{
|
||||||
(void)busid;
|
(void)busid;
|
||||||
|
|
||||||
g_cdc_ecm_rx_data_length += nbytes;
|
g_cdc_ecm_rx_data_length = nbytes;
|
||||||
|
usbd_cdc_ecm_data_recv_done(g_cdc_ecm_rx_data_length);
|
||||||
if (nbytes < usbd_get_ep_mps(0, ep)) {
|
|
||||||
g_cdc_ecm_rx_data_buffer = g_cdc_ecm_rx_buffer;
|
|
||||||
usbd_cdc_ecm_data_recv_done(g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_data_length);
|
|
||||||
} else {
|
|
||||||
usbd_ep_start_read(0, ep, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_data_length], usbd_get_ep_mps(0, ep));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cdc_ecm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
void cdc_ecm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
||||||
@ -150,6 +151,7 @@ void cdc_ecm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
|||||||
/* send zlp */
|
/* send zlp */
|
||||||
usbd_ep_start_write(0, ep, NULL, 0);
|
usbd_ep_start_write(0, ep, NULL, 0);
|
||||||
} else {
|
} else {
|
||||||
|
usbd_cdc_ecm_data_send_done(g_cdc_ecm_tx_data_length);
|
||||||
g_cdc_ecm_tx_data_length = 0;
|
g_cdc_ecm_tx_data_length = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,14 +162,20 @@ void cdc_ecm_int_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
|
|||||||
(void)ep;
|
(void)ep;
|
||||||
(void)nbytes;
|
(void)nbytes;
|
||||||
|
|
||||||
if (g_current_net_status == 1) {
|
if (g_current_net_status == 2) {
|
||||||
g_current_net_status = 2;
|
g_current_net_status = 3;
|
||||||
usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, g_connect_speed_table);
|
usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE, 0, g_connect_speed_table);
|
||||||
|
} else {
|
||||||
|
g_current_net_status = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int usbd_cdc_ecm_start_write(uint8_t *buf, uint32_t len)
|
int usbd_cdc_ecm_start_write(uint8_t *buf, uint32_t len)
|
||||||
{
|
{
|
||||||
|
if (!usb_device_is_configured(0)) {
|
||||||
|
return -USB_ERR_NODEV;
|
||||||
|
}
|
||||||
|
|
||||||
if (g_cdc_ecm_tx_data_length > 0) {
|
if (g_cdc_ecm_tx_data_length > 0) {
|
||||||
return -USB_ERR_BUSY;
|
return -USB_ERR_BUSY;
|
||||||
}
|
}
|
||||||
@ -175,14 +183,17 @@ int usbd_cdc_ecm_start_write(uint8_t *buf, uint32_t len)
|
|||||||
g_cdc_ecm_tx_data_length = len;
|
g_cdc_ecm_tx_data_length = len;
|
||||||
|
|
||||||
USB_LOG_DBG("txlen:%d\r\n", g_cdc_ecm_tx_data_length);
|
USB_LOG_DBG("txlen:%d\r\n", g_cdc_ecm_tx_data_length);
|
||||||
return usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr, buf, g_cdc_ecm_tx_data_length);
|
return usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void usbd_cdc_ecm_start_read_next(void)
|
int usbd_cdc_ecm_start_read(uint8_t *buf, uint32_t len)
|
||||||
{
|
{
|
||||||
|
if (!usb_device_is_configured(0)) {
|
||||||
|
return -USB_ERR_NODEV;
|
||||||
|
}
|
||||||
|
|
||||||
g_cdc_ecm_rx_data_length = 0;
|
g_cdc_ecm_rx_data_length = 0;
|
||||||
g_cdc_ecm_rx_data_buffer = NULL;
|
return usbd_ep_start_read(0, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, buf, len);
|
||||||
usbd_ep_start_read(0, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, g_cdc_ecm_rx_buffer, usbd_get_ep_mps(0, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
|
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
|
||||||
@ -190,19 +201,19 @@ struct pbuf *usbd_cdc_ecm_eth_rx(void)
|
|||||||
{
|
{
|
||||||
struct pbuf *p;
|
struct pbuf *p;
|
||||||
|
|
||||||
if (g_cdc_ecm_rx_data_buffer == NULL) {
|
if (g_cdc_ecm_rx_data_length == 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
p = pbuf_alloc(PBUF_RAW, g_cdc_ecm_rx_data_length, PBUF_POOL);
|
p = pbuf_alloc(PBUF_RAW, g_cdc_ecm_rx_data_length, PBUF_POOL);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
usbd_cdc_ecm_start_read_next();
|
usbd_cdc_ecm_start_read(g_cdc_ecm_rx_buffer, CONFIG_CDC_ECM_ETH_MAX_SEGSZE);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
usb_memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_data_length);
|
usb_memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_data_length);
|
||||||
p->len = g_cdc_ecm_rx_data_length;
|
p->len = g_cdc_ecm_rx_data_length;
|
||||||
|
|
||||||
USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_data_length);
|
USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_data_length);
|
||||||
usbd_cdc_ecm_start_read_next();
|
usbd_cdc_ecm_start_read(g_cdc_ecm_rx_buffer, CONFIG_CDC_ECM_ETH_MAX_SEGSZE);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,13 +261,24 @@ struct usbd_interface *usbd_cdc_ecm_init_intf(struct usbd_interface *intf, const
|
|||||||
return intf;
|
return intf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void usbd_cdc_ecm_set_connect_speed(uint32_t speed[2])
|
void usbd_cdc_ecm_set_connect(bool connect, uint32_t speed[2])
|
||||||
{
|
{
|
||||||
memcpy(g_connect_speed_table, speed, 8);
|
if (connect) {
|
||||||
|
g_current_net_status = 2;
|
||||||
|
memcpy(g_connect_speed_table, speed, 8);
|
||||||
|
usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, NULL);
|
||||||
|
} else {
|
||||||
|
g_current_net_status = 1;
|
||||||
|
usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_DISCONNECTED, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__WEAK void usbd_cdc_ecm_data_recv_done(uint8_t *buf, uint32_t len)
|
__WEAK void usbd_cdc_ecm_data_recv_done(uint32_t len)
|
||||||
|
{
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
__WEAK void usbd_cdc_ecm_data_send_done(uint32_t len)
|
||||||
{
|
{
|
||||||
(void)buf;
|
|
||||||
(void)len;
|
(void)len;
|
||||||
}
|
}
|
||||||
|
@ -12,21 +12,15 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Ethernet Maximum Segment size, typically 1514 bytes */
|
|
||||||
#define CONFIG_CDC_ECM_ETH_MAX_SEGSZE 1514U
|
|
||||||
|
|
||||||
/* Init cdc ecm interface driver */
|
/* Init cdc ecm interface driver */
|
||||||
struct usbd_interface *usbd_cdc_ecm_init_intf(struct usbd_interface *intf, const uint8_t int_ep, const uint8_t out_ep, const uint8_t in_ep);
|
struct usbd_interface *usbd_cdc_ecm_init_intf(struct usbd_interface *intf, const uint8_t int_ep, const uint8_t out_ep, const uint8_t in_ep);
|
||||||
|
|
||||||
/* Setup request command callback api */
|
void usbd_cdc_ecm_set_connect(bool connect, uint32_t speed[2]);
|
||||||
void usbd_cdc_ecm_set_connect_speed(uint32_t speed[2]);
|
|
||||||
|
|
||||||
/* Api for eth only without any net stack */
|
void usbd_cdc_ecm_data_recv_done(uint32_t len);
|
||||||
uint8_t *usbd_cdc_ecm_get_tx_buffer(void);
|
void usbd_cdc_ecm_data_send_done(uint32_t len);
|
||||||
void usbd_cdc_ecm_send_done(void);
|
|
||||||
int usbd_cdc_ecm_start_write(uint8_t *buf, uint32_t len);
|
int usbd_cdc_ecm_start_write(uint8_t *buf, uint32_t len);
|
||||||
void usbd_cdc_ecm_data_recv_done(uint8_t *buf, uint32_t len);
|
int usbd_cdc_ecm_start_read(uint8_t *buf, uint32_t len);
|
||||||
void usbd_cdc_ecm_start_read_next(void);
|
|
||||||
|
|
||||||
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
|
#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
|
||||||
#include "lwip/netif.h"
|
#include "lwip/netif.h"
|
||||||
|
@ -267,18 +267,18 @@ const struct usbh_class_driver cdc_data_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info cdc_acm_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info cdc_acm_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
|
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
|
||||||
.class = USB_DEVICE_CLASS_CDC,
|
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
|
||||||
.subclass = CDC_ABSTRACT_CONTROL_MODEL,
|
.bInterfaceSubClass = CDC_ABSTRACT_CONTROL_MODEL,
|
||||||
.protocol = 0x00,
|
.bInterfaceProtocol = 0x00,
|
||||||
.id_table = NULL,
|
.id_table = NULL,
|
||||||
.class_driver = &cdc_acm_class_driver
|
.class_driver = &cdc_acm_class_driver
|
||||||
};
|
};
|
||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info cdc_data_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info cdc_data_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
|
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
|
||||||
.class = USB_DEVICE_CLASS_CDC_DATA,
|
.bInterfaceClass = USB_DEVICE_CLASS_CDC_DATA,
|
||||||
.subclass = 0x00,
|
.bInterfaceSubClass = 0x00,
|
||||||
.protocol = 0x00,
|
.bInterfaceProtocol = 0x00,
|
||||||
.id_table = NULL,
|
.id_table = NULL,
|
||||||
.class_driver = &cdc_data_class_driver
|
.class_driver = &cdc_data_class_driver
|
||||||
};
|
};
|
||||||
|
@ -323,9 +323,9 @@ const struct usbh_class_driver cdc_ecm_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info cdc_ecm_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info cdc_ecm_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
||||||
.class = USB_DEVICE_CLASS_CDC,
|
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
|
||||||
.subclass = CDC_ETHERNET_NETWORKING_CONTROL_MODEL,
|
.bInterfaceSubClass = CDC_ETHERNET_NETWORKING_CONTROL_MODEL,
|
||||||
.protocol = CDC_COMMON_PROTOCOL_NONE,
|
.bInterfaceProtocol = CDC_COMMON_PROTOCOL_NONE,
|
||||||
.id_table = NULL,
|
.id_table = NULL,
|
||||||
.class_driver = &cdc_ecm_class_driver
|
.class_driver = &cdc_ecm_class_driver
|
||||||
};
|
};
|
@ -403,9 +403,9 @@ const struct usbh_class_driver cdc_ncm_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info cdc_ncm_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info cdc_ncm_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
||||||
.class = USB_DEVICE_CLASS_CDC,
|
.bInterfaceClass = USB_DEVICE_CLASS_CDC,
|
||||||
.subclass = CDC_NETWORK_CONTROL_MODEL,
|
.bInterfaceSubClass = CDC_NETWORK_CONTROL_MODEL,
|
||||||
.protocol = CDC_COMMON_PROTOCOL_NONE,
|
.bInterfaceProtocol = CDC_COMMON_PROTOCOL_NONE,
|
||||||
.id_table = NULL,
|
.id_table = NULL,
|
||||||
.class_driver = &cdc_ncm_class_driver
|
.class_driver = &cdc_ncm_class_driver
|
||||||
};
|
};
|
||||||
|
@ -303,9 +303,9 @@ const struct usbh_class_driver hid_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info hid_custom_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info hid_custom_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
|
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
|
||||||
.class = USB_DEVICE_CLASS_HID,
|
.bInterfaceClass = USB_DEVICE_CLASS_HID,
|
||||||
.subclass = 0x00,
|
.bInterfaceSubClass = 0x00,
|
||||||
.protocol = 0x00,
|
.bInterfaceProtocol = 0x00,
|
||||||
.id_table = NULL,
|
.id_table = NULL,
|
||||||
.class_driver = &hid_class_driver
|
.class_driver = &hid_class_driver
|
||||||
};
|
};
|
||||||
|
@ -734,9 +734,9 @@ const struct usbh_class_driver hub_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info hub_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info hub_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
|
.match_flags = USB_CLASS_MATCH_INTF_CLASS,
|
||||||
.class = USB_DEVICE_CLASS_HUB,
|
.bInterfaceClass = USB_DEVICE_CLASS_HUB,
|
||||||
.subclass = 0,
|
.bInterfaceSubClass = 0,
|
||||||
.protocol = 0,
|
.bInterfaceProtocol = 0,
|
||||||
.id_table = NULL,
|
.id_table = NULL,
|
||||||
.class_driver = &hub_class_driver
|
.class_driver = &hub_class_driver
|
||||||
};
|
};
|
||||||
|
@ -443,9 +443,9 @@ const struct usbh_class_driver msc_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info msc_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info msc_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
||||||
.class = USB_DEVICE_CLASS_MASS_STORAGE,
|
.bInterfaceClass = USB_DEVICE_CLASS_MASS_STORAGE,
|
||||||
.subclass = MSC_SUBCLASS_SCSI,
|
.bInterfaceSubClass = MSC_SUBCLASS_SCSI,
|
||||||
.protocol = MSC_PROTOCOL_BULK_ONLY,
|
.bInterfaceProtocol = MSC_PROTOCOL_BULK_ONLY,
|
||||||
.id_table = NULL,
|
.id_table = NULL,
|
||||||
.class_driver = &msc_class_driver
|
.class_driver = &msc_class_driver
|
||||||
};
|
};
|
||||||
|
@ -89,9 +89,9 @@ static const struct usbh_class_driver xxx_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info xxx_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info xxx_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
|
||||||
.class = 0,
|
.bInterfaceClass = 0,
|
||||||
.subclass = 0,
|
.bInterfaceSubClass = 0,
|
||||||
.protocol = 0,
|
.bInterfaceProtocol = 0,
|
||||||
.id_table = NULL,
|
.id_table = NULL,
|
||||||
.class_driver = &xxx_class_driver
|
.class_driver = &xxx_class_driver
|
||||||
};
|
};
|
||||||
|
@ -817,9 +817,9 @@ static const struct usbh_class_driver asix_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info asix_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info asix_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
||||||
.class = 0xff,
|
.bInterfaceClass = 0xff,
|
||||||
.subclass = 0x00,
|
.bInterfaceSubClass = 0x00,
|
||||||
.protocol = 0x00,
|
.bInterfaceProtocol = 0x00,
|
||||||
.id_table = asix_id_table,
|
.id_table = asix_id_table,
|
||||||
.class_driver = &asix_class_driver
|
.class_driver = &asix_class_driver
|
||||||
};
|
};
|
@ -2272,9 +2272,9 @@ static const struct usbh_class_driver rtl8152_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info rtl8152_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info rtl8152_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
||||||
.class = 0xff,
|
.bInterfaceClass = 0xff,
|
||||||
.subclass = 0x00,
|
.bInterfaceSubClass = 0x00,
|
||||||
.protocol = 0x00,
|
.bInterfaceProtocol = 0x00,
|
||||||
.id_table = rtl_id_table,
|
.id_table = rtl_id_table,
|
||||||
.class_driver = &rtl8152_class_driver
|
.class_driver = &rtl8152_class_driver
|
||||||
};
|
};
|
||||||
|
@ -370,9 +370,9 @@ const struct usbh_class_driver ch34x_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info ch34x_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info ch34x_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
||||||
.class = 0xff,
|
.bInterfaceClass = 0xff,
|
||||||
.subclass = 0x00,
|
.bInterfaceSubClass = 0x00,
|
||||||
.protocol = 0x00,
|
.bInterfaceProtocol = 0x00,
|
||||||
.id_table = ch34x_id_table,
|
.id_table = ch34x_id_table,
|
||||||
.class_driver = &ch34x_class_driver
|
.class_driver = &ch34x_class_driver
|
||||||
};
|
};
|
@ -319,9 +319,9 @@ const struct usbh_class_driver cp210x_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info cp210x_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info cp210x_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
||||||
.class = 0xff,
|
.bInterfaceClass = 0xff,
|
||||||
.subclass = 0x00,
|
.bInterfaceSubClass = 0x00,
|
||||||
.protocol = 0x00,
|
.bInterfaceProtocol = 0x00,
|
||||||
.id_table = cp210x_id_table,
|
.id_table = cp210x_id_table,
|
||||||
.class_driver = &cp210x_class_driver
|
.class_driver = &cp210x_class_driver
|
||||||
};
|
};
|
@ -392,9 +392,9 @@ const struct usbh_class_driver ftdi_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info ftdi_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info ftdi_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
||||||
.class = 0xff,
|
.bInterfaceClass = 0xff,
|
||||||
.subclass = 0x00,
|
.bInterfaceSubClass = 0x00,
|
||||||
.protocol = 0x00,
|
.bInterfaceProtocol = 0x00,
|
||||||
.id_table = ftdi_id_table,
|
.id_table = ftdi_id_table,
|
||||||
.class_driver = &ftdi_class_driver
|
.class_driver = &ftdi_class_driver
|
||||||
};
|
};
|
@ -440,9 +440,9 @@ const struct usbh_class_driver pl2303_class_driver = {
|
|||||||
|
|
||||||
CLASS_INFO_DEFINE const struct usbh_class_info pl2303_class_info = {
|
CLASS_INFO_DEFINE const struct usbh_class_info pl2303_class_info = {
|
||||||
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
|
||||||
.class = 0xff,
|
.bInterfaceClass = 0xff,
|
||||||
.subclass = 0x00,
|
.bInterfaceSubClass = 0x00,
|
||||||
.protocol = 0x00,
|
.bInterfaceProtocol = 0x00,
|
||||||
.id_table = pl2303_id_table,
|
.id_table = pl2303_id_table,
|
||||||
.class_driver = &pl2303_class_driver
|
.class_driver = &pl2303_class_driver
|
||||||
};
|
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user