update by jenkins(20250201001522)

This commit is contained in:
HEYAHONG 2025-02-01 00:15:22 +08:00
parent 504d73aa19
commit a17817ebb8
333 changed files with 11524 additions and 2746 deletions

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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"

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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/

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)
## 文档 ## 文档

View File

@ -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

View File

@ -77,6 +77,7 @@ static int dfs_devfs_open(struct dfs_file *file)
} }
} }
} }
rt_free(device_name);
} }
return ret; return ret;

View File

@ -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);
} }

View File

@ -0,0 +1,166 @@
# 进程文件系统 (procfs)
## 数据结构
```c
struct proc_dentry
{
rt_uint32_t mode;
rt_atomic_t ref_count;
struct proc_dentry *parent;
struct dfs_vfs_node node;
const struct dfs_file_ops *fops;
const struct proc_ops *ops;
char *name;
void *data;
};
```
```log
root { mode: S_IFDIR, ref_count: 1, parent: root, name: /, child->next: file1->node }
|
|—— file1 { mode: S_IFREG, ref_count: 1, parent: root, name: file1, node->next: link1->node }
|—— link1 { mode: S_IFLNK, ref_count: 1, parent: root, name: link1, data: fullpath, node->next: dir1->node }
|—— dir1 { mode: S_IFDIR, ref_count: 1, parent: root, name: dir1, node->next: file3->node, child->next: file2->node }
| |
| |—— dir2 { mode: S_IFDIR, ref_count: 1, parent: dir1, name: dir2, node->next: link2->node }
| |—— link2 { mode: S_IFLNK, ref_count: 1, parent: dir1, name: link2, data: fullpath, node->next: file2->node }
| |—— file2 { mode: S_IFREG, ref_count: 1, parent: dir1, name: file2 }
|
|—— file3 { mode: S_IFREG, ref_count: 1, parent: root, name: file3 }
```
## API 介绍
```c
struct proc_dentry *dfs_proc_find(const char *name);
struct proc_dentry *proc_mkdir_data(const char *name, mode_t mode, struct proc_dentry *parent,
const struct dfs_file_ops *fops, void *data);
struct proc_dentry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dentry *parent);
struct proc_dentry *proc_mkdir(const char *name, struct proc_dentry *parent);
struct proc_dentry *proc_create_data(const char *name, mode_t mode, struct proc_dentry *parent,
const struct dfs_file_ops *fops, void *data);
struct proc_dentry *proc_symlink(const char *name, struct proc_dentry *parent, const char *dest);
struct proc_dentry *proc_acquire(struct proc_dentry *dentry);
void proc_release(struct proc_dentry *dentry);
void proc_remove(struct proc_dentry *dentry);
```
- dfs_proc_find
查找指定节点,并返回节点数据指针
| 入参 | 说明 |
| ---- | ---------------------------------------------------- |
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2” |
- proc_mkdir_data
创建一个目录,并返回节点数据指针
| 入参 | 说明 |
| ------ | ------------------------------------------------------------ |
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
| mode | 权限配置 |
| parent | 指定创建目录的起始节点 |
| fops | 文件操作接口配置 |
| data | 私有数据 |
- proc_mkdir_mode
创建一个目录,并返回节点数据指针
| 入参 | 说明 |
| ------ | ------------------------------------------------------------ |
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
| mode | 权限配置 |
| parent | 指定创建目录的起始节点 |
- proc_mkdir
创建一个目录,并返回节点数据指针
| 入参 | 说明 |
| ---- | ------------------------------------------------------------ |
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
| mode | 权限配置 |
- proc_create_data
创建一个文件,并返回节点数据指针
| 入参 | 说明 |
| ------ | ------------------------------------------------------------ |
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
| mode | 权限配置 |
| parent | 指定创建文件的起始节点 |
| fops | 文件操作接口配置 |
| data | 私有数据 |
- proc_symlink
创建一个符号链接,并返回节点数据指针
| 入参 | 说明 |
| ------ | ------------------------------------------------------------ |
| name | 从 procfs 的 root 起始的完整路径,比如 “/dir1/file2”<br />从 parent 起始的完整路径 |
| parent | 指定创建文件的起始节点 |
| dest | 链接的目标文件完整路径 |
- proc_acquire
引用一个节点,并返回节点数据指针
| 入参 | 说明 |
| ------ | -------------- |
| dentry | 需要引用的节点 |
- proc_release
释放一个节点
| 入参 | 说明 |
| ------ | -------------- |
| dentry | 需要释放的节点 |
- proc_remove
删除一个节点包含子节点
| 入参 | 说明 |
| ------ | -------------- |
| dentry | 需要删除的节点 |
## msh 调试命令
- proc_dump
遍历打印指定节点含子节点的信息(名称、引用计数),比如 `proc_dump /dir1` 或者 `proc_dump`
- proc_remove
删除指定节点含子节点,比如 `proc_remove /dir1` 或者 `proc_remove /file3`
- proc_symlink
创建一个符号链接,`proc_symlink /link3 /mnt`
- proc_echo
创建一个空文件,`proc_echo /file4`
- proc_mkdir
创建一个空目录,`proc_mkdir /dir3`
- proc_pid
创建一个 pid 目录,`proc_pid /101`

View File

@ -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')

View 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);

View File

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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

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

View File

@ -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);

View File

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

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include "proc.h"
#include "procfs.h"
#include <rthw.h>
#include <rtdbg.h>
#include <fcntl.h>
#include <errno.h>
#include <dfs_dentry.h>
#include <dfs_mnt.h>
const char *mnt_flag(int flag)
{
/*if (flag & MNT_READONLY)
{
return "ro";
}*/
return "rw";
}
static struct dfs_mnt* mnt_show(struct dfs_mnt *mnt, void *parameter)
{
struct dfs_seq_file *seq = (struct dfs_seq_file *)parameter;
if (mnt)
{
if (mnt->dev_id)
{
dfs_seq_printf(seq, "%s %s %s %s 0 0\n", mnt->dev_id->parent.name, mnt->fullpath,
mnt->fs_ops->name, mnt_flag(mnt->flags));
}
else
{
dfs_seq_printf(seq, "%s %s %s %s 0 0\n", mnt->fs_ops->name, mnt->fullpath,
mnt->fs_ops->name, mnt_flag(mnt->flags));
}
}
return RT_NULL;
}
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
{
off_t i = *index; // seq->index
return NULL + (i == 0);
}
static void seq_stop(struct dfs_seq_file *seq, void *data)
{
}
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
{
/* data: The return value of the start or next*/
off_t i = *index + 1; // seq->index
*index = i;
return NULL;
}
static int seq_show(struct dfs_seq_file *seq, void *data)
{
/* data: The return value of the start or next*/
dfs_mnt_foreach(mnt_show, seq);
return 0;
}
static const struct dfs_seq_ops seq_ops = {
.start = seq_start,
.stop = seq_stop,
.next = seq_next,
.show = seq_show,
};
int proc_mounts_init(void)
{
struct proc_dentry *dentry = proc_create_data("mounts", 0, NULL, NULL, NULL);
if (dentry)
{
dentry->seq_ops = &seq_ops;
}
proc_release(dentry);
return 0;
}
INIT_ENV_EXPORT(proc_mounts_init);

View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include "proc.h"
#include "procfs.h"
#include <rthw.h>
#include <rtdbg.h>
#include <fcntl.h>
#include <errno.h>
#include <dfs_dentry.h>
#ifdef RT_USING_LWIP
#include "lwip/opt.h"
#endif
#if LWIP_ROUTE
extern int inet_route_foreach(void (*func)(const char *name, uint32_t ip_addr, uint32_t netmask, void *parameter), void *parameter);
#endif
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
{
off_t i = *index; // seq->index
return NULL + (i == 0);
}
static void seq_stop(struct dfs_seq_file *seq, void *data)
{
}
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
{
/* data: The return value of the start or next*/
off_t i = *index + 1; // seq->index
*index = i;
return NULL;
}
static void route_show(const char *name, uint32_t ip_addr, uint32_t netmask, void *parameter)
{
struct dfs_seq_file *seq = (struct dfs_seq_file *)parameter;
/* "Iface\tDestination\tGateway "
"\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU"
"\tWindow\tIRTT"); */
/* "%63s%lx%lx%X%d%d%d%lx%d%d%d\n" */
dfs_seq_printf(seq, "%s ", name);
dfs_seq_printf(seq, "%lx ", ip_addr);
dfs_seq_printf(seq, "%lx ", 0);
dfs_seq_printf(seq, "%X ", 1);
dfs_seq_printf(seq, "%d ", 0);
dfs_seq_printf(seq, "%d ", 0);
dfs_seq_printf(seq, "%d ", 0);
dfs_seq_printf(seq, "%lx ", netmask);
dfs_seq_printf(seq, "%d ", 0);
dfs_seq_printf(seq, "%d ", 0);
dfs_seq_printf(seq, "%d\n", 0);
}
static int seq_show(struct dfs_seq_file *seq, void *data)
{
/* data: The return value of the start or next*/
dfs_seq_printf(seq, "\n");
#if LWIP_ROUTE
inet_route_foreach(route_show, seq);
#endif
return 0;
}
static const struct dfs_seq_ops seq_ops = {
.start = seq_start,
.stop = seq_stop,
.next = seq_next,
.show = seq_show,
};
int proc_net_init(void)
{
struct proc_dentry *dentry;
dentry = proc_mkdir("net", NULL);
if (!dentry)
return -1;
proc_release(dentry);
dentry = proc_create_data("net/route", 0, NULL, NULL, NULL);
if (dentry)
{
dentry->seq_ops = &seq_ops;
}
proc_release(dentry);
return 0;
}
INIT_ENV_EXPORT(proc_net_init);

View File

@ -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);

View File

@ -0,0 +1,449 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#define __RT_IPC_SOURCE__
#include "proc.h"
#include "procfs.h"
#include <rthw.h>
#include <rtdbg.h>
#include <fcntl.h>
#include <errno.h>
#include "lwp_internal.h"
#include <dfs_dentry.h>
#include "lwp_internal.h"
#if defined(RT_USING_SMART)
#include "lwp.h"
#include "lwp_pid.h"
#include <lwp_user_mm.h>
struct pid_dentry
{
const char *name;
mode_t mode;
const struct dfs_file_ops *fops;
const struct proc_ops *ops;
const struct dfs_seq_ops *seq_ops;
int (*single_show)(struct dfs_seq_file *seq, void *data);
void *data;
};
static char stat_transform(int __stat)
{
switch (__stat)
{
case RT_THREAD_RUNNING:
return 'R';
default:
return 'T';
}
}
static int stat_single_show(struct dfs_seq_file *seq, void *data)
{
struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data;
rt_list_t *list;
int mask = 0;
rt_thread_t thread;
rt_uint64_t user_time_lwp = 0;
rt_uint64_t system_time_lwp = 0;
int lwp_oncpu = RT_CPUS_NR;
int lwp_oncpu_ok = 0;
struct rt_lwp *lwp = RT_NULL;
char** argv = RT_NULL;
char *filename = RT_NULL;
char *dot = RT_NULL;
lwp_pid_lock_take();
lwp = lwp_from_pid_locked(dentry->pid);
argv = lwp_get_command_line_args(lwp);
if (lwp)
{
dfs_seq_printf(seq,"%d ",dentry->pid);
if (argv)
{
filename = strrchr(argv[0], '/');
dot = strchr(argv[0], '.');
if (filename != NULL)
{
filename++;
}
else
{
filename = argv[0];
}
if (dot != NULL)
{
*dot = '\0';
}
if (filename != NULL)
{
dfs_seq_printf(seq,"(%s) ", filename);
}
else
{
dfs_seq_printf(seq,"(%s) ", argv[0]);
}
lwp_free_command_line_args(argv);
}
else
{
dfs_seq_printf(seq,"(%s) ", "");
}
if (lwp->terminated)
{
dfs_seq_printf(seq,"%c ",'Z');
}
else
{
list = lwp->t_grp.next;
while (list != &lwp->t_grp)
{
thread = rt_list_entry(list, struct rt_thread, sibling);
user_time_lwp = user_time_lwp + thread->user_time;
system_time_lwp = system_time_lwp + thread->system_time;
#if RT_CPUS_NR > 1
#define ONCPU(thread) RT_SCHED_CTX(thread).oncpu
#else
#define ONCPU(thread) 0
#endif
if (lwp_oncpu_ok == 0)
{
lwp_oncpu = ONCPU(thread);
lwp_oncpu_ok = 1;
}
if (stat_transform(RT_SCHED_CTX(thread).stat) == 'R')
{
lwp_oncpu = ONCPU(thread);
mask = 1;
}
list = list->next;
}
if (mask == 1)
{
dfs_seq_printf(seq,"%c ",'R');
}
else
{
dfs_seq_printf(seq,"%c ",'S');
}
}
lwp_pid_lock_release();
if (lwp->parent != NULL)
dfs_seq_printf(seq,"%d ",lwp->parent->pid);
else
dfs_seq_printf(seq,"0 ");
dfs_seq_printf(seq, "1 1 0 -1 4194560 48245 133976064 732 425574 ");
dfs_seq_printf(seq,"%llu ",user_time_lwp);//utime
dfs_seq_printf(seq,"%llu ",system_time_lwp);//stime
dfs_seq_printf(seq, "1204291 518742 20 0 1 0 50 ");
dfs_seq_printf(seq, "%d ",rt_aspace_count_vsz(lwp->aspace));//VSZ
dfs_seq_printf(seq, "1422 18446744073709551615 ");
dfs_seq_printf(seq, "1 1 0 0 0 0 671173123 4096 1260 0 0 0 17 ");
dfs_seq_printf(seq, "%d ", lwp_oncpu);//CPU
dfs_seq_printf(seq, "0 0 0 0 0 0 0 0 0 0 0 0 0");
dfs_seq_printf(seq,"\n");
}
else
{
lwp_pid_lock_release();
}
return 0;
}
static int cmdline_single_show(struct dfs_seq_file *seq, void *data)
{
struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data;
struct rt_lwp *lwp;
char** argv;
lwp_pid_lock_take();
lwp = lwp_from_pid_locked(dentry->pid);
argv = lwp_get_command_line_args(lwp);
lwp_pid_lock_release();
if (argv)
{
for (int i = 0; argv[i] != NULL; i++)
{
dfs_seq_printf(seq, "%s ", argv[i]);
}
dfs_seq_puts(seq, "\n");
lwp_free_command_line_args(argv);
}
else
{
dfs_seq_puts(seq, "error\n");
}
return 0;
}
struct proc_dentry *proc_pid_fd_lookup(struct proc_dentry *parent, const char *name)
{
struct proc_dentry *dentry = RT_NULL;
char num[DIRENT_NAME_MAX];
struct rt_lwp *lwp;
struct dfs_fdtable *table;
lwp_pid_lock_take();
lwp = lwp_from_pid_locked(parent->pid);
table = lwp ? &lwp->fdt : RT_NULL;
lwp_pid_lock_release();
if (!table)
{
return RT_NULL;
}
dfs_file_lock();
for (int i = 0; i < table->maxfd; i++)
{
struct dfs_file *file = table->fds[i];
if (file)
{
rt_snprintf(num, DIRENT_NAME_MAX, "%d", i);
if (rt_strcmp(num, name) == 0)
{
dentry = rt_calloc(1, sizeof(struct proc_dentry));
if (dentry)
{
dentry->mode = (S_IFLNK | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IWUSR | S_IWGRP | S_IWOTH) | (S_IXUSR | S_IXGRP | S_IXOTH));
dentry->ref_count = 1;
dentry->name = rt_strdup(name);
dentry->data = (void *)dfs_dentry_full_path(file->dentry);
if (dentry->data == RT_NULL)
{
//todo add vnode->data
if (file->vnode->type == FT_SOCKET)
dentry->data = (void *)rt_strdup("socket");
else if (file->vnode->type == FT_USER)
dentry->data = (void *)rt_strdup("user");
else if (file->vnode->type == FT_DEVICE)
dentry->data = (void *)rt_strdup("device");
else
dentry->data = (void *)rt_strdup("unknown");
}
dentry->pid = parent->pid;
break;
}
}
}
}
dfs_file_unlock();
return dentry;
}
int proc_pid_fd_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
{
int ret = 0, index = 0;
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
struct rt_lwp *lwp;
struct dfs_fdtable *table;
lwp_pid_lock_take();
lwp = lwp_from_pid_locked(entry->pid);
LWP_LOCK(lwp);
table = lwp ? &lwp->fdt : RT_NULL;
if (!table->fds)
{
LWP_UNLOCK(lwp);
lwp_pid_lock_release();
return 0;
}
count = (count / sizeof(struct dirent));
if (count == 0)
{
LWP_UNLOCK(lwp);
lwp_pid_lock_release();
return -EINVAL;
}
dfs_file_lock();
for (int i = 0; i < table->maxfd; i++)
{
struct dfs_file *df = table->fds[i];
if (df)
{
if (index >= file->fpos)
{
struct dirent *d = dirp + index - file->fpos;
d->d_type = DT_SYMLINK;
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
rt_snprintf(d->d_name, DIRENT_NAME_MAX, "%d", i);
d->d_namlen = rt_strlen(d->d_name);
ret++;
}
index++;
if (index - file->fpos >= count)
{
break;
}
}
}
dfs_file_unlock();
LWP_UNLOCK(lwp);
lwp_pid_lock_release();
if (ret > 0)
{
file->fpos = index;
ret = ret * sizeof(struct dirent);
}
return ret;
}
static const struct proc_ops proc_pid_fd_ops = {
.lookup = proc_pid_fd_lookup,
};
static const struct dfs_file_ops proc_pid_fd_fops = {
.getdents = proc_pid_fd_getdents,
};
int proc_pid_exe_readlink(struct proc_dentry *dentry, char *buf, int len)
{
struct rt_lwp *lwp;
lwp = lwp_self();
len = rt_snprintf(buf, len, "%s", lwp ? lwp->exe_file : "null");
return len;
}
static const struct proc_ops proc_pid_exe_ops = {
.readlink = proc_pid_exe_readlink,
};
int proc_pid_cwd_readlink(struct proc_dentry *dentry, char *buf, int len)
{
struct rt_lwp *lwp;
lwp = lwp_self();
len = rt_snprintf(buf, len, "%s", lwp ? lwp->working_directory : "null");
return len;
}
static const struct proc_ops proc_pid_cwd_ops = {
.readlink = proc_pid_cwd_readlink,
};
static struct pid_dentry pid_dentry_base[] = {
{"cmdline", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, cmdline_single_show, 0},
{"cwd", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_cwd_ops, 0, 0},
{"exe", S_IFLNK | S_IRUSR | S_IXUSR, 0, &proc_pid_exe_ops, 0, 0},
{"fd", S_IFDIR | S_IRUSR | S_IXUSR, &proc_pid_fd_fops, &proc_pid_fd_ops, 0, 0, 0},
{"mounts", S_IFLNK | S_IRUSR | S_IXUSR, 0, 0, 0, 0, "/proc/mounts"},
{"stat", S_IFREG | S_IRUSR | S_IRGRP | S_IROTH, 0, 0, 0, stat_single_show, 0},
};
int proc_pid(int pid)
{
char pid_str[64] = {0};
struct proc_dentry *dentry;
rt_snprintf(pid_str, 64, "%d", pid);
pid_str[63] = 0;
dentry = proc_mkdir(pid_str, 0);
if (dentry)
{
struct proc_dentry *ent;
dentry->pid = pid;
for (int j = 0; j < sizeof(pid_dentry_base) / sizeof(struct pid_dentry); j++)
{
if (S_ISDIR(pid_dentry_base[j].mode))
{
ent = proc_mkdir_data(pid_dentry_base[j].name, pid_dentry_base[j].mode, dentry,
pid_dentry_base[j].fops, pid_dentry_base[j].data);
}
else if (S_ISLNK(pid_dentry_base[j].mode))
{
if (pid_dentry_base[j].data == RT_NULL)
{
pid_dentry_base[j].data = "NULL";
}
ent = proc_symlink(pid_dentry_base[j].name, dentry, pid_dentry_base[j].data);
}
else
{
ent = proc_create_data(pid_dentry_base[j].name, pid_dentry_base[j].mode, dentry,
pid_dentry_base[j].fops, pid_dentry_base[j].data);
}
if (ent)
{
if (pid_dentry_base[j].ops)
{
ent->ops = pid_dentry_base[j].ops;
}
if (pid_dentry_base[j].seq_ops)
{
ent->seq_ops = pid_dentry_base[j].seq_ops;
}
if (pid_dentry_base[j].single_show)
{
ent->single_show = pid_dentry_base[j].single_show;
}
proc_release(ent);
}
}
proc_release(dentry);
}
return 0;
}
int msh_proc_pid(int argc, char **argv)
{
if (argc > 1)
{
for (int i = 1; i <= argc - 1; i++)
{
proc_pid(atoi(argv[i]));
}
}
return 0;
}
MSH_CMD_EXPORT_ALIAS(msh_proc_pid, proc_pid, proc pid);
#endif

View File

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

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include "proc.h"
#include "procfs.h"
#include <rthw.h>
#include <rtdbg.h>
#include <fcntl.h>
#include <errno.h>
#include <dfs_dentry.h>
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
{
off_t i = *index; // seq->index
return NULL + (i == 0);
}
static void seq_stop(struct dfs_seq_file *seq, void *data)
{
}
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
{
/* data: The return value of the start or next*/
off_t i = *index + 1; // seq->index
*index = i;
return NULL;
}
static int seq_show(struct dfs_seq_file *seq, void *data)
{
int i;
rt_cpu_t pcpu;
rt_uint64_t user_total = 0;
rt_uint64_t system_total = 0;
rt_uint64_t idle_total = 0;
for (i = 0; i < RT_CPUS_NR; i++)
{
pcpu = rt_cpu_index(i);
user_total = user_total + pcpu->cpu_stat.user;
system_total = system_total + pcpu->cpu_stat.system;
idle_total = idle_total + pcpu->cpu_stat.idle;
}
dfs_seq_printf(seq, "cpu %llu 0 %llu %llu 0 0 0 0 0 0\n", user_total, system_total, idle_total);
for (i = 0; i < RT_CPUS_NR; i++)
{
pcpu = rt_cpu_index(i);
dfs_seq_printf(seq, "cpu%d ",i);
dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.user);//user
dfs_seq_printf(seq, "0 ");//nice
dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.system);//system
dfs_seq_printf(seq, "%llu ",pcpu->cpu_stat.idle);//idle
dfs_seq_printf(seq, "0 ");//iowait
dfs_seq_printf(seq, "0 ");//irq
dfs_seq_printf(seq, "0 ");//softirq
dfs_seq_printf(seq, "0 0 0\n");//steal,guest,guest_nice
}
return 0;
}
static const struct dfs_seq_ops seq_ops = {
.start = seq_start,
.stop = seq_stop,
.next = seq_next,
.show = seq_show,
};
rt_weak const struct dfs_seq_ops *stat_get_seq_ops(void)
{
return &seq_ops;
}
static int proc_open(struct dfs_file *file)
{
return dfs_seq_open(file, stat_get_seq_ops());
}
static int proc_close(struct dfs_file *file)
{
return dfs_seq_release(file);
}
static const struct dfs_file_ops file_ops = {
.open = proc_open,
.read = dfs_seq_read,
.lseek = dfs_seq_lseek,
.close = proc_close,
};
int proc_stat_init(void)
{
struct proc_dentry *dentry = proc_create_data("stat", 0, NULL, &file_ops, NULL);
proc_release(dentry);
return 0;
}
INIT_ENV_EXPORT(proc_stat_init);

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include "proc.h"
#include "procfs.h"
#include <rthw.h>
#include <rtdbg.h>
#include <fcntl.h>
#include <errno.h>
#include <dfs_dentry.h>
static void *seq_start(struct dfs_seq_file *seq, off_t *index)
{
off_t i = *index; // seq->index
return NULL + (i == 0);
}
static void seq_stop(struct dfs_seq_file *seq, void *data)
{
}
static void *seq_next(struct dfs_seq_file *seq, void *data, off_t *index)
{
/* data: The return value of the start or next*/
off_t i = *index + 1; // seq->index
*index = i;
return NULL;
}
static int seq_show(struct dfs_seq_file *seq, void *data)
{
/* data: The return value of the start or next*/
dfs_seq_puts(seq, "todo\n");
return 0;
}
static const struct dfs_seq_ops seq_ops = {
.start = seq_start,
.stop = seq_stop,
.next = seq_next,
.show = seq_show,
};
void proc_tty_register_driver(void *driver)
{
//todo
}
void proc_tty_unregister_driver(void *driver)
{
//todo
}
int proc_tty_init(void)
{
struct proc_dentry *dentry;
dentry = proc_mkdir("tty", NULL);
if (!dentry)
return -1;
proc_release(dentry);
dentry = proc_mkdir("tty/ldisc", NULL);
proc_release(dentry);
dentry = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL);
proc_release(dentry);
dentry = proc_create_data("tty/ldiscs", 0, NULL, NULL, NULL);
if (dentry)
{
dentry->seq_ops = &seq_ops;
}
proc_release(dentry);
dentry = proc_create_data("tty/drivers", 0, NULL, NULL, NULL);
if (dentry)
{
dentry->seq_ops = &seq_ops;
}
proc_release(dentry);
return 0;
}
INIT_ENV_EXPORT(proc_tty_init);

View File

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

View File

@ -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);

View File

@ -0,0 +1,447 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include <rthw.h>
#include <rtdbg.h>
#include <fcntl.h>
#include <errno.h>
#include <dfs.h>
#include <dfs_fs.h>
#include <dfs_file.h>
#include <dfs_posix.h>
#include <dfs_mnt.h>
#include <dfs_dentry.h>
#include "proc.h"
#include "procfs.h"
#define PROC_DEBUG(...) //rt_kprintf
static int dfs_procfs_open(struct dfs_file *file)
{
rt_err_t ret = RT_EOK;
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
RT_ASSERT(file->ref_count > 0);
// this file is opened and in an fdtable
if (file->ref_count > 1)
{
file->fpos = 0;
return ret;
}
if (entry->fops && entry->fops->open)
{
ret = entry->fops->open(file);
}
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
return ret;
}
static int dfs_procfs_close(struct dfs_file *file)
{
rt_err_t ret = RT_EOK;
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
RT_ASSERT(file->vnode->ref_count > 0);
if (file->vnode->ref_count > 1)
{
return ret;
}
if (entry && entry->fops && entry->fops->close)
{
ret = entry->fops->close(file);
}
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
return ret;
}
static ssize_t dfs_procfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
{
ssize_t ret = -RT_ERROR;
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
if (entry && entry->fops && entry->fops->read)
{
ret = entry->fops->read(file, buf, count, pos);
}
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
return ret;
}
static ssize_t dfs_procfs_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
{
ssize_t ret = -RT_ERROR;
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
if (entry && entry->fops && entry->fops->write)
{
ret = entry->fops->write(file, buf, count, pos);
}
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
return ret;
}
static int dfs_procfs_ioctl(struct dfs_file *file, int cmd, void *args)
{
int ret = -RT_ERROR;
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
if (entry && entry->fops && entry->fops->ioctl)
{
ret = entry->fops->ioctl(file, cmd, args);
}
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
return ret;
}
static int dfs_procfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
{
int ret = 0;
rt_uint32_t index = 0;
struct dirent *d;
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
if (entry)
{
struct proc_dentry *iter = RT_NULL, *tmp;
/* make integer count */
count = (count / sizeof(struct dirent));
if (count == 0)
{
return -EINVAL;
}
dfs_vfs_for_each_subnode(iter, tmp, entry, node)
{
if (iter == RT_NULL)
{
break;
}
if (index >= file->fpos)
{
d = dirp + index - file->fpos;
if (S_ISDIR(entry->mode))
{
d->d_type = DT_DIR;
}
else if (S_ISLNK(entry->mode))
{
d->d_type = DT_SYMLINK;
}
else
{
d->d_type = DT_REG;
}
d->d_namlen = rt_strlen(iter->name);
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
rt_strncpy(d->d_name, iter->name, rt_strlen(iter->name) + 1);
ret ++;
}
index++;
if (index - file->fpos >= count)
{
break;
}
}
if (ret > 0)
{
file->fpos = index;
}
if (entry->fops && entry->fops->getdents && ret < count)
{
int r;
file->fpos -= index;
r = entry->fops->getdents(file, dirp + ret, (count - ret) * sizeof(struct dirent));
ret = ret * sizeof(struct dirent);
if (r > 0)
{
ret += r;
}
file->fpos += index;
}
else
{
ret = ret * sizeof(struct dirent);
}
}
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
return ret;
}
static int dfs_procfs_poll(struct dfs_file *file, struct rt_pollreq *req)
{
int ret = -RT_ERROR;
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
if (entry && entry->fops && entry->fops->poll)
{
ret = entry->fops->poll(file, req);
}
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
return ret;
}
static int dfs_procfs_flush(struct dfs_file *file)
{
int ret = -RT_ERROR;
struct proc_dentry *entry = (struct proc_dentry *)file->vnode->data;
if (entry && entry->fops && entry->fops->flush)
{
ret = entry->fops->flush(file);
}
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, file->dentry->pathname, ret);
return ret;
}
static int dfs_procfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
{
RT_ASSERT(mnt != RT_NULL);
return RT_EOK;
}
static int dfs_procfs_umount(struct dfs_mnt *mnt)
{
RT_ASSERT(mnt != RT_NULL);
return RT_EOK;
}
static int dfs_procfs_readlink(struct dfs_dentry *dentry, char *buf, int len)
{
int ret = 0;
struct proc_dentry *entry = dfs_proc_find(dentry->pathname);
if (entry)
{
if (S_ISLNK(entry->mode) && entry->data)
{
if (entry->ops && entry->ops->readlink)
{
ret = entry->ops->readlink(entry, buf, len);
}
else
{
rt_strncpy(buf, (const char *)entry->data, len);
buf[len - 1] = '\0';
ret = rt_strlen(buf);
}
}
proc_release(entry);
}
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, ret);
return ret;
}
static int dfs_procfs_unlink(struct dfs_dentry *dentry)
{
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, -1);
return -RT_ERROR;
}
static int dfs_procfs_stat(struct dfs_dentry *dentry, struct stat *st)
{
int ret = RT_EOK;
struct dfs_vnode *vnode;
if (dentry && dentry->vnode)
{
vnode = dentry->vnode;
st->st_dev = (dev_t)(dentry->mnt->dev_id);
st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry);
st->st_gid = vnode->gid;
st->st_uid = vnode->uid;
st->st_mode = vnode->mode;
st->st_nlink = vnode->nlink;
st->st_size = vnode->size;
st->st_mtim.tv_nsec = vnode->mtime.tv_nsec;
st->st_mtim.tv_sec = vnode->mtime.tv_sec;
st->st_ctim.tv_nsec = vnode->ctime.tv_nsec;
st->st_ctim.tv_sec = vnode->ctime.tv_sec;
st->st_atim.tv_nsec = vnode->atime.tv_nsec;
st->st_atim.tv_sec = vnode->atime.tv_sec;
}
PROC_DEBUG(" %s %d >> %s ret: %d\n", __func__, __LINE__, dentry->pathname, ret);
return ret;
}
static int dfs_procfs_statfs(struct dfs_mnt *mnt, struct statfs *buf)
{
if (mnt && buf)
{
buf->f_bsize = 512;
buf->f_blocks = 2048 * 64; // 64M
buf->f_bfree = buf->f_blocks;
buf->f_bavail = buf->f_bfree;
}
PROC_DEBUG(" %s %d\n", __func__, __LINE__);
return RT_EOK;
}
static struct dfs_vnode *dfs_procfs_lookup(struct dfs_dentry *dentry)
{
struct dfs_vnode *vnode = RT_NULL;
struct proc_dentry *entry = dfs_proc_find(dentry->pathname);
if (entry)
{
vnode = dfs_vnode_create();
if (vnode)
{
vnode->nlink = 1;
vnode->size = 0;
if (S_ISDIR(entry->mode))
{
vnode->mode = entry->mode;
vnode->type = FT_DIRECTORY;
}
else if (S_ISLNK(entry->mode))
{
vnode->mode = entry->mode;
vnode->type = FT_SYMLINK;
}
else
{
vnode->mode = entry->mode;
vnode->type = FT_REGULAR;
}
vnode->data = entry;
vnode->mnt = dentry->mnt;
}
proc_release(entry);
}
PROC_DEBUG(" %s %d >> %s\n", __func__, __LINE__, dentry->pathname);
return vnode;
}
static struct dfs_vnode *dfs_procfs_create_vnode(struct dfs_dentry *dentry, int type, mode_t mode)
{
return RT_NULL;
}
static int dfs_procfs_free_vnode(struct dfs_vnode *vnode)
{
return 0;
}
static const struct dfs_file_ops _procfs_fops =
{
.open = dfs_procfs_open,
.close = dfs_procfs_close,
.lseek = generic_dfs_lseek,
.read = dfs_procfs_read,
.write = dfs_procfs_write,
.ioctl = dfs_procfs_ioctl,
.getdents = dfs_procfs_getdents,
.poll = dfs_procfs_poll,
.flush = dfs_procfs_flush,
};
static const struct dfs_filesystem_ops _procfs_ops =
{
.name = "procfs",
.default_fops = &_procfs_fops,
.mount = dfs_procfs_mount,
.umount = dfs_procfs_umount,
.readlink = dfs_procfs_readlink,
.unlink = dfs_procfs_unlink,
.stat = dfs_procfs_stat,
.statfs = dfs_procfs_statfs,
.lookup = dfs_procfs_lookup,
.create_vnode = dfs_procfs_create_vnode,
.free_vnode = dfs_procfs_free_vnode,
};
static struct dfs_filesystem_type _procfs =
{
.fs_ops = &_procfs_ops,
};
int dfs_procfs_init(void)
{
/* register procfs file system */
dfs_register(&_procfs);
return 0;
}
INIT_COMPONENT_EXPORT(dfs_procfs_init);
int proc_read_data(struct dfs_file *file, void *buf, size_t count, off_t *pos)
{
if (file->fpos >= file->vnode->size)
{
return 0;
}
if (file->data)
{
count = file->vnode->size - file->fpos >= count ? count : file->vnode->size - file->fpos;
rt_strncpy(buf, file->data + file->fpos, count);
file->fpos += count;
*pos = file->fpos;
}
else
{
return 0;
}
return count;
}

View File

@ -0,0 +1,19 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef __PROC_FS_H__
#define __PROC_FS_H__
#include <dfs_file.h>
int dfs_procfs_init(void);
int proc_read_data(struct dfs_file *file, void *buf, size_t count, off_t *pos);
#endif

View File

@ -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,

View File

@ -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;

View File

@ -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 */

View File

@ -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,

View File

@ -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
} }

View File

@ -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
} }

View 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__*/

View File

@ -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);
} }

View File

@ -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;

View File

@ -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)

View File

@ -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 */
/**@}*/

View File

@ -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 */

View File

@ -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

View File

@ -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,

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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;
}; };

View File

@ -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)

View File

@ -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);
} }

View File

@ -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

View File

@ -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']

View 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 */

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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" />

View File

@ -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" />

View File

@ -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']):

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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 */

View File

@ -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
};

View File

@ -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 */

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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
}; };

View File

@ -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);

View File

@ -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 */ \

View File

@ -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;
} }

View File

@ -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"

View File

@ -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
}; };

View File

@ -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
}; };

View File

@ -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
}; };

View File

@ -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
}; };

View File

@ -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
}; };

View File

@ -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
}; };

View File

@ -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
}; };

View File

@ -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
}; };

View File

@ -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
}; };

View File

@ -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
}; };

View File

@ -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
}; };

View File

@ -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
}; };

View File

@ -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