原始版本

This commit is contained in:
冯佳
2025-06-19 21:56:46 +08:00
parent fe98e5f010
commit a4841450cf
4152 changed files with 1910684 additions and 0 deletions

View File

@ -0,0 +1,2 @@
rsource "usb/Kconfig"
rsource "fdt/Kconfig"

View File

@ -0,0 +1,2 @@
# RT-Thread Legacy

View File

@ -0,0 +1,22 @@
from building import *
import os
src = Split('''
ipc/workqueue_legacy.c
''')
cwd = GetCurrentDir()
CPPPATH = [cwd]
if GetDepend('RT_USING_DFS'):
dfs_cwd = os.path.join(cwd,'dfs')
CPPPATH += [dfs_cwd]
group = DefineGroup('Legacy', src, depend = ['RT_USING_LEGACY'], CPPPATH = CPPPATH)
list = os.listdir(cwd)
for item in list:
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
group = group + SConscript(os.path.join(item, 'SConscript'))
Return('group')

View File

@ -0,0 +1,16 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-11-14 Meco Man the first version
*/
#ifndef DFS_POLL_H__
#define DFS_POLL_H__
#include <poll.h>
#endif /* DFS_POLL_H__ */

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2009-05-27 Yi.qiu The first version.
* 2010-07-18 Bernard add stat and statfs structure definitions.
* 2011-05-16 Yi.qiu Change parameter name of rename, "new" is C++ key word.
* 2017-12-27 Bernard Add fcntl API.
* 2018-02-07 Bernard Change the 3rd parameter of open/fcntl/ioctl to '...'
*/
#ifndef __DFS_POSIX_H__
#define __DFS_POSIX_H__
#include <dfs_file.h>
#include <unistd.h>
#include <stdio.h> /* rename() */
#include <sys/stat.h>
#include <sys/statfs.h> /* statfs() */
#endif

View File

@ -0,0 +1,16 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-11-14 Meco Man the first version
*/
#ifndef DFS_SELECT_H__
#define DFS_SELECT_H__
#include <sys/select.h>
#endif /* DFS_SELECT_H__ */

View File

@ -0,0 +1,15 @@
config RT_USING_FDT
bool "Using fdt legacy version"
default n
if RT_USING_FDT
config RT_USING_FDTLIB
bool "Using fdt lib for device drivers"
default y
config RT_USING_FDT_FWNODE
bool "Using fdt fwnode for device drivers"
default n
config FDT_USING_DEBUG
bool "Using fdt debug function"
default n
endif

View File

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

View File

@ -0,0 +1,16 @@
# RT-Thread building script for bridge
import os
from building import *
cwd = GetCurrentDir()
objs = []
list = os.listdir(cwd)
if GetDepend('RT_USING_FDT'):
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript'))
Return('objs')

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,125 @@
#ifndef __DTB_FWNODE_H__
#define __DTB_FWNODE_H__
#include "libfdt_env.h"
#include <rtthread.h>
#include <stdint.h>
#include <stdbool.h>
struct fwnode_operations;
struct rt_device;
#define FWNODE_FLAG_LINKS_ADDED 0x01
#define FWNODE_FLAG_NOT_DEVICE 0x02
#define FWNODE_FLAG_INITIALIZED 0x04
#define NR_FWNODE_REFERENCE_ARGS 8
struct fwnode_handle
{
struct fwnode_handle *secondary;
const struct fwnode_operations *ops;
struct rt_device *dev;
struct rt_list_node suppliers;
struct rt_list_node consumers;
uint8_t flags;
};
struct fwnode_link
{
struct fwnode_handle *supplier;
struct rt_list_node s_hook;
struct fwnode_handle *consumer;
struct rt_list_node c_hook;
};
struct fwnode_endpoint
{
unsigned int port;
unsigned int id;
const struct fwnode_handle *local_fwnode;
};
struct fwnode_reference_args
{
struct fwnode_handle *fwnode;
unsigned int nargs;
uint64_t args[NR_FWNODE_REFERENCE_ARGS];
};
struct fwnode_operations
{
struct fwnode_handle *(*get)(struct fwnode_handle *fwnode);
void (*put)(struct fwnode_handle *fwnode);
bool (*device_is_available)(const struct fwnode_handle *fwnode);
const void *(*device_get_match_data)(const struct fwnode_handle *fwnode,
const struct rt_device *dev);
bool (*property_present)(const struct fwnode_handle *fwnode,
const char *propname);
int (*property_read_int_array)(const struct fwnode_handle *fwnode,
const char *propname,
unsigned int elem_size, void *val,
size_t nval);
int (*property_read_string_array)(const struct fwnode_handle *fwnode_handle,
const char *propname, const char **val,
size_t nval);
const char *(*get_name)(const struct fwnode_handle *fwnode);
const char *(*get_name_prefix)(const struct fwnode_handle *fwnode);
struct fwnode_handle *(*get_parent)(const struct fwnode_handle *fwnode);
struct fwnode_handle *(*get_next_child_node)(const struct fwnode_handle *fwnode,
struct fwnode_handle *child);
struct fwnode_handle *(*get_named_child_node)(const struct fwnode_handle *fwnode,
const char *name);
int (*get_reference_args)(const struct fwnode_handle *fwnode,
const char *prop, const char *nargs_prop,
unsigned int nargs, unsigned int index,
struct fwnode_reference_args *args);
struct fwnode_handle *(*graph_get_next_endpoint)(const struct fwnode_handle *fwnode,
struct fwnode_handle *prev);
struct fwnode_handle *(*graph_get_remote_endpoint)(const struct fwnode_handle *fwnode);
struct fwnode_handle *(*graph_get_port_parent)(struct fwnode_handle *fwnode);
int (*graph_parse_endpoint)(const struct fwnode_handle *fwnode,
struct fwnode_endpoint *endpoint);
int (*add_links)(struct fwnode_handle *fwnode);
};
#define fwnode_has_op(fwnode, op) \
((fwnode) && (fwnode)->ops && (fwnode)->ops->op)
#define fwnode_call_int_op(fwnode, op, ...) \
(fwnode ? (fwnode_has_op(fwnode, op) ? (fwnode)->ops->op(fwnode, ##__VA_ARGS__) : -ENXIO) : -EINVAL)
#define fwnode_call_bool_op(fwnode, op, ...) \
(fwnode_has_op(fwnode, op) ? (fwnode)->ops->op(fwnode, ##__VA_ARGS__) : false)
#define fwnode_call_ptr_op(fwnode, op, ...) \
(fwnode_has_op(fwnode, op) ? (fwnode)->ops->op(fwnode, ##__VA_ARGS__) : NULL)
#define fwnode_call_void_op(fwnode, op, ...) \
do \
{ \
if (fwnode_has_op(fwnode, op)) \
(fwnode)->ops->op(fwnode, ##__VA_ARGS__); \
} while (false)
#define get_dev_from_fwnode(fwnode) ((fwnode)->dev)
static inline void fwnode_init(struct fwnode_handle *fwnode,
const struct fwnode_operations *ops)
{
fwnode->ops = ops;
rt_list_init(&fwnode->consumers);
rt_list_init(&fwnode->suppliers);
}
static inline void fwnode_dev_initialized(struct fwnode_handle *fwnode,
bool initialized)
{
if (!fwnode)
return;
if (initialized)
fwnode->flags |= FWNODE_FLAG_INITIALIZED;
else
fwnode->flags &= ~FWNODE_FLAG_INITIALIZED;
}
#endif //__DTB_FWNODE_H__

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -0,0 +1,17 @@
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
list = os.listdir(cwd)
CPPPATH = [cwd + '/../inc' , cwd + '/libfdt']
objs = []
group = DefineGroup('FDT', src, depend = ['RT_USING_FDT'], CPPPATH = CPPPATH)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript'))
objs = objs + group
Return('objs')

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,18 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-11-14 Meco Man the first version
*/
#include "workqueue_legacy.h"
void rt_delayed_work_init(struct rt_delayed_work *work,
void (*work_func)(struct rt_work *work,
void *work_data), void *work_data)
{
rt_work_init(&work->work, work_func, work_data);
}

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-11-14 Meco Man the first version
*/
#ifndef __WORKQUEUE_LEGACY_H__
#define __WORKQUEUE_LEGACY_H__
#include <ipc/workqueue.h>
struct rt_delayed_work
{
struct rt_work work;
};
void rt_delayed_work_init(struct rt_delayed_work *work,
void (*work_func)(struct rt_work *work,
void *work_data), void *work_data);
#endif

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-11-14 Meco Man the first version
*/
#ifndef __RT_LEGACY_H__
#define __RT_LEGACY_H__
#include <rtconfig.h>
#include <rtdef.h>
/* rtdef.h */
/* legacy version macros (<5.0.0) */
#define RT_VERSION RT_VERSION_MAJOR /**< major version number */
#define RT_SUBVERSION RT_VERSION_MINOR /**< minor version number */
#define RT_REVISION RT_VERSION_PATCH /**< revise version number */
/* legacy attributes define (<5.0.0) */
#define RT_SECTION rt_section
#define RT_WEAK rt_weak
#define RT_USED rt_used
#ifndef ALIGN
#define ALIGN rt_align
#endif
/* IPC */
#ifdef RT_USING_DEVICE_IPC
#include "ipc/workqueue_legacy.h"
#endif /* RT_USING_DEVICE_IPC */
/* FinSH */
#endif /* __RT_LEGACY_H__ */

View File

@ -0,0 +1,200 @@
menu "Using USB legacy version"
config RT_USING_USB
bool
default n
config RT_USING_USB_HOST
bool "Using USB host"
default n
select RT_USING_USB
if RT_USING_USB_HOST
config RT_USBH_MSTORAGE
bool "Enable Udisk Drivers"
default n
if RT_USBH_MSTORAGE
config UDISK_MOUNTPOINT
string "Udisk mount dir"
default "/"
endif
config RT_USBH_HID
bool "Enable HID Drivers"
default n
if RT_USBH_HID
config RT_USBH_HID_MOUSE
bool "Enable HID mouse protocol"
default n
config RT_USBH_HID_KEYBOARD
bool "Enable HID keyboard protocol"
default n
endif
endif
config RT_USING_USB_DEVICE
bool "Using USB device"
default n
select RT_USING_USB
if RT_USING_USB_DEVICE || RT_USING_USB_HOST
config RT_USBD_THREAD_STACK_SZ
int "usb thread stack size"
default 4096
endif
if RT_USING_USB_DEVICE
config USB_VENDOR_ID
hex "USB Vendor ID"
default 0x0FFE
config USB_PRODUCT_ID
hex "USB Product ID"
default 0x0001
config RT_USB_DEVICE_COMPOSITE
bool "Enable composite device"
default n
choice
prompt "Device type"
default _RT_USB_DEVICE_NONE
depends on !RT_USB_DEVICE_COMPOSITE
config _RT_USB_DEVICE_NONE
bool "Using custom class by register interface"
select RT_USB_DEVICE_NONE
config _RT_USB_DEVICE_CDC
bool "Enable to use device as CDC device"
select RT_USB_DEVICE_CDC
config _RT_USB_DEVICE_MSTORAGE
bool "Enable to use device as Mass Storage device"
select RT_USB_DEVICE_MSTORAGE
config _RT_USB_DEVICE_HID
bool "Enable to use device as HID device"
select RT_USB_DEVICE_HID
config _RT_USB_DEVICE_RNDIS
bool "Enable to use device as rndis device"
select RT_USB_DEVICE_RNDIS
depends on RT_USING_LWIP
config _RT_USB_DEVICE_ECM
bool "Enable to use device as ecm device"
select RT_USB_DEVICE_ECM
depends on RT_USING_LWIP
config _RT_USB_DEVICE_WINUSB
bool "Enable to use device as winusb device"
select RT_USB_DEVICE_WINUSB
config _RT_USB_DEVICE_AUDIO
bool "Enable to use device as audio device"
select RT_USB_DEVICE_AUDIO
endchoice
if RT_USB_DEVICE_COMPOSITE
config RT_USB_DEVICE_CDC
bool "Enable to use device as CDC device"
default n
config RT_USB_DEVICE_NONE
bool
default y
config RT_USB_DEVICE_MSTORAGE
bool "Enable to use device as Mass Storage device"
default n
config RT_USB_DEVICE_HID
bool "Enable to use device as HID device"
default n
config RT_USB_DEVICE_RNDIS
bool "Enable to use device as rndis device"
default n
depends on RT_USING_LWIP
config RT_USB_DEVICE_ECM
bool "Enable to use device as ecm device"
default n
depends on RT_USING_LWIP
config RT_USB_DEVICE_WINUSB
bool "Enable to use device as winusb device"
default n
config RT_USB_DEVICE_AUDIO
bool "Enable to use device as audio device"
default n
endif
if RT_USB_DEVICE_CDC
config RT_VCOM_TASK_STK_SIZE
int "virtual com thread stack size"
default 512
config RT_CDC_RX_BUFSIZE
int "virtual com rx buffer size"
default 128
config RT_VCOM_TX_USE_DMA
bool "Enable to use dma for vcom tx"
default n
config RT_VCOM_SERNO
string "serial number of virtual com"
default "32021919830108"
config RT_VCOM_SER_LEN
int "serial number length of virtual com"
default 14
config RT_VCOM_TX_TIMEOUT
int "tx timeout(ticks) of virtual com"
default 1000
endif
if RT_USB_DEVICE_WINUSB
config RT_WINUSB_GUID
string "Guid for winusb"
default "{6860DC3C-C05F-4807-8807-1CA861CC1D66}"
endif
if RT_USB_DEVICE_MSTORAGE
config RT_USB_MSTORAGE_DISK_NAME
string "msc class disk name"
default "flash0"
endif
if RT_USB_DEVICE_RNDIS
config RNDIS_DELAY_LINK_UP
bool "Delay linkup media connection"
select RT_USING_TIMER_SOFT
default n
endif
if RT_USB_DEVICE_HID
config RT_USB_DEVICE_HID_KEYBOARD
bool "Use to HID device as Keyboard"
default n
if RT_USB_DEVICE_HID_KEYBOARD
config RT_USB_DEVICE_HID_KEYBOARD_NUMBER
int "Number of Keyboard(max 3)"
default 1
range 1 3
endif
config RT_USB_DEVICE_HID_MOUSE
bool "Use to HID device as Mouse"
default n
config RT_USB_DEVICE_HID_GENERAL
bool "Use to HID device as General HID device"
default y
if RT_USB_DEVICE_HID_GENERAL
config RT_USB_DEVICE_HID_GENERAL_OUT_REPORT_LENGTH
int "General HID device out report length"
default 63
range 0 63
config RT_USB_DEVICE_HID_GENERAL_IN_REPORT_LENGTH
int "General HID device in report length"
default 63
range 0 63
endif
config RT_USB_DEVICE_HID_MEDIA
bool "Use to HID device as media keyboard"
default y
endif
if RT_USB_DEVICE_AUDIO
config RT_USB_DEVICE_AUDIO_MIC
bool "Use usb mic device as audio device"
default n
if RT_USB_DEVICE_AUDIO_MIC
config RT_USBD_MIC_DEVICE_NAME
string "audio mic device name"
default "mic0"
endif
config RT_USB_DEVICE_AUDIO_SPEAKER
bool "Use usb speaker device as audio device"
default n
if RT_USB_DEVICE_AUDIO_SPEAKER
config RT_USBD_SPEAKER_DEVICE_NAME
string "audio speaker device name"
default "sound0"
endif
endif
endif
endmenu

View File

@ -0,0 +1,13 @@
# for module compiling
import os
from building import *
cwd = GetCurrentDir()
objs = []
list = os.listdir(cwd)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript'))
Return('objs')

View File

@ -0,0 +1,38 @@
Import('RTT_ROOT')
from building import *
cwd = GetCurrentDir()
src = Split("""
core/usbdevice_core.c
core/usbdevice.c
""")
if GetDepend('RT_USB_DEVICE_CDC'):
src += Glob('class/cdc_vcom.c')
if GetDepend('RT_USB_DEVICE_HID'):
src += Glob('class/hid.c')
if GetDepend('RT_USB_DEVICE_MSTORAGE'):
src += Glob('class/mstorage.c')
if GetDepend('RT_USB_DEVICE_ECM'):
src += Glob('class/ecm.c')
if GetDepend('RT_USB_DEVICE_RNDIS'):
src += Glob('class/rndis.c')
if GetDepend('RT_USB_DEVICE_WINUSB'):
src += Glob('class/winusb.c')
if GetDepend('RT_USB_DEVICE_AUDIO_MIC'):
src += Glob('class/audio_mic.c')
if GetDepend('RT_USB_DEVICE_AUDIO_SPEAKER'):
src += Glob('class/audio_speaker.c')
CPPPATH = [cwd]
group = DefineGroup('rt_usbd', src, depend = ['RT_USING_USB_DEVICE'], CPPPATH = CPPPATH)
Return('group')

View File

@ -0,0 +1,581 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-09-07 flybreak the first version
*/
#include <rthw.h>
#include <rtdevice.h>
#include "drivers/usb_device.h"
#include "uaudioreg.h"
#define DBG_TAG "usbd.audio.mic"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#define RECORD_SAMPLERATE 16000
#define RECORD_CHANNEL 1
#define RESOLUTION_BITS 16
#define RESOLUTION_BYTE (RESOLUTION_BITS / 8)
#define RECORD_PER_MS_SZ ((RECORD_SAMPLERATE * RECORD_CHANNEL * RESOLUTION_BYTE) / 1000)
#define RECORD_BUFFER_SZ (RECORD_PER_MS_SZ * 20) /* 20ms */
#if defined(RT_USBD_MIC_DEVICE_NAME)
#define MIC_DEVICE_NAME RT_USBD_MIC_DEVICE_NAME
#else
#define MIC_DEVICE_NAME "mic0"
#endif
#define EVENT_RECORD_START (1 << 0)
#define EVENT_RECORD_STOP (1 << 1)
#define EVENT_RECORD_DATA (1 << 2)
#define MIC_INTF_STR_INDEX 8
/*
* uac mic descriptor define
*/
#define UAC_CS_INTERFACE 0x24
#define UAC_CS_ENDPOINT 0x25
#define UAC_MAX_PACKET_SIZE 64
#define UAC_EP_MAX_PACKET_SIZE 32
#define UAC_CHANNEL_NUM RECORD_CHANNEL
struct uac_ac_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct usb_audio_control_descriptor hdr_desc;
struct usb_audio_input_terminal it_desc;
struct usb_audio_output_terminal ot_desc;
#if UAC_USE_FEATURE_UNIT
struct usb_audio_feature_unit feature_unit_desc;
#endif
};
struct uac_as_descriptor
{
struct uinterface_descriptor intf_desc;
struct usb_audio_streaming_interface_descriptor hdr_desc;
struct usb_audio_streaming_type1_descriptor format_type_desc;
struct uendpoint_descriptor ep_desc;
struct usb_audio_streaming_endpoint_descriptor as_ep_desc;
};
/*
* uac mic device type
*/
struct uac_audio_mic
{
rt_device_t dev;
rt_event_t event;
rt_uint8_t open_count;
rt_uint8_t *buffer;
rt_uint32_t buffer_index;
uep_t ep;
};
static struct uac_audio_mic mic;
rt_align(4)
static struct udevice_descriptor dev_desc =
{
USB_DESC_LENGTH_DEVICE, //bLength;
USB_DESC_TYPE_DEVICE, //type;
USB_BCD_VERSION, //bcdUSB;
USB_CLASS_DEVICE, //bDeviceClass;
0x00, //bDeviceSubClass;
0x00, //bDeviceProtocol;
UAC_MAX_PACKET_SIZE, //bMaxPacketSize0;
_VENDOR_ID, //idVendor;
_PRODUCT_ID, //idProduct;
USB_BCD_DEVICE, //bcdDevice;
USB_STRING_MANU_INDEX, //iManufacturer;
USB_STRING_PRODUCT_INDEX, //iProduct;
USB_STRING_SERIAL_INDEX, //iSerialNumber;Unused.
USB_DYNAMIC, //bNumConfigurations;
};
//FS and HS needed
rt_align(4)
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier), //bLength
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
0x0200, //bcdUSB
USB_CLASS_AUDIO, //bDeviceClass
0x00, //bDeviceSubClass
0x00, //bDeviceProtocol
64, //bMaxPacketSize0
0x01, //bNumConfigurations
0,
};
rt_align(4)
const static char *_ustring[] =
{
"Language",
"RT-Thread Team.",
"RT-Thread Audio Microphone",
"32021919830108",
"Configuration",
"Interface",
};
rt_align(4)
static struct uac_ac_descriptor ac_desc =
{
#ifdef RT_USB_DEVICE_COMPOSITE
/* Interface Association Descriptor */
{
USB_DESC_LENGTH_IAD,
USB_DESC_TYPE_IAD,
USB_DYNAMIC,
0x02,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOSTREAMING,
0x00,
0x00,
},
#endif
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x00,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOCONTROL,
0x00,
#ifdef RT_USB_DEVICE_COMPOSITE
MIC_INTF_STR_INDEX,
#else
0x00,
#endif
},
/* Header Descriptor */
{
sizeof(struct usb_audio_control_descriptor),
UAC_CS_INTERFACE,
UDESCSUB_AC_HEADER,
0x0100, /* Version: 1.00 */
0x001E, /* Total length: 30 */
0x01, /* Total number of interfaces: 1 */
{0x01}, /* Interface number: 1 */
},
/* Input Terminal Descriptor */
{
sizeof(struct usb_audio_input_terminal),
UAC_CS_INTERFACE,
UDESCSUB_AC_INPUT,
0x01, /* Terminal ID: 1 */
0x0201, /* Terminal Type: Microphone (0x0201) */
0x00, /* Assoc Terminal: 0 */
0x01, /* Number Channels: 1 */
0x0000, /* Channel Config: 0x0000 */
0x00, /* Channel Names: 0 */
0x00, /* Terminal: 0 */
},
/* Output Terminal Descriptor */
{
sizeof(struct usb_audio_output_terminal),
UAC_CS_INTERFACE,
UDESCSUB_AC_OUTPUT,
0x02, /* Terminal ID: 2 */
0x0101, /* Terminal Type: USB Streaming (0x0101) */
0x00, /* Assoc Terminal: 0 */
0x01, /* Source ID: 1 */
0x00, /* Terminal: 0 */
},
#if UAC_USE_FEATURE_UNIT
/* Feature unit Descriptor */
{
sizeof(struct usb_audio_feature_unit),
UAC_CS_INTERFACE,
UDESCSUB_AC_FEATURE,
0x02,
0x01,
0x01,
0x00,
0x01,
},
#endif
};
rt_align(4)
static struct uinterface_descriptor as_desc0 =
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x00,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOSTREAMING,
0x00,
0x00,
};
rt_align(4)
static struct uac_as_descriptor as_desc =
{
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x01,
0x01,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOSTREAMING,
0x00,
0x00,
},
/* General AS Descriptor */
{
sizeof(struct usb_audio_streaming_interface_descriptor),
UAC_CS_INTERFACE,
AS_GENERAL,
0x02, /* Terminal ID: 2 */
0x01, /* Interface delay in frames: 1 */
UA_FMT_PCM,
},
/* Format type i Descriptor */
{
sizeof(struct usb_audio_streaming_type1_descriptor),
UAC_CS_INTERFACE,
FORMAT_TYPE,
FORMAT_TYPE_I,
UAC_CHANNEL_NUM,
2, /* Subframe Size: 2 */
RESOLUTION_BITS,
0x01, /* Samples Frequence Type: 1 */
{0}, /* Samples Frequence */
},
/* Endpoint Descriptor */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_IN,
USB_EP_ATTR_ISOC,
UAC_EP_MAX_PACKET_SIZE,
0x01,
},
/* AS Endpoint Descriptor */
{
sizeof(struct usb_audio_streaming_endpoint_descriptor),
UAC_CS_ENDPOINT,
AS_GENERAL,
},
};
void mic_entry(void *parameter)
{
struct rt_audio_caps caps = {0};
rt_uint32_t e, index;
mic.buffer = rt_malloc(RECORD_BUFFER_SZ);
if (mic.buffer == RT_NULL)
{
LOG_E("malloc failed");
goto __exit;
}
mic.dev = rt_device_find(MIC_DEVICE_NAME);
if (mic.dev == RT_NULL)
{
LOG_E("can't find device:%s", MIC_DEVICE_NAME);
goto __exit;
}
while (1)
{
if (rt_event_recv(mic.event, EVENT_RECORD_START | EVENT_RECORD_STOP,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
1000, &e) != RT_EOK)
{
continue;
}
if (mic.open_count == 0)
{
continue;
}
LOG_D("record start");
rt_device_open(mic.dev, RT_DEVICE_OFLAG_RDONLY);
caps.main_type = AUDIO_TYPE_INPUT;
caps.sub_type = AUDIO_DSP_PARAM;
caps.udata.config.samplerate = RECORD_SAMPLERATE;
caps.udata.config.channels = RECORD_CHANNEL;
caps.udata.config.samplebits = RESOLUTION_BITS;
rt_device_control(mic.dev, AUDIO_CTL_CONFIGURE, &caps);
while (1)
{
if (rt_event_recv(mic.event, EVENT_RECORD_DATA | EVENT_RECORD_STOP,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
1000, &e) != RT_EOK)
{
if (mic.open_count > 0)
continue;
else
break;
}
if (e & EVENT_RECORD_DATA)
{
index = (mic.buffer_index >= RECORD_BUFFER_SZ / 2) ? 0 : (RECORD_BUFFER_SZ / 2);
rt_device_read(mic.dev, 0, mic.buffer + index, RECORD_BUFFER_SZ / 2);
}
else if (e & EVENT_RECORD_STOP)
{
break;
}
}
LOG_D("record stop");
rt_device_close(mic.dev);
}
__exit:
if (mic.buffer)
rt_free(mic.buffer);
}
static rt_err_t _record_start(ufunction_t func)
{
mic.ep->request.buffer = RT_NULL;
mic.ep->request.size = UAC_EP_MAX_PACKET_SIZE;
mic.ep->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, mic.ep, &mic.ep->request);
mic.open_count ++;
rt_event_send(mic.event, EVENT_RECORD_START);
return 0;
}
static rt_err_t _record_stop(ufunction_t func)
{
mic.open_count --;
rt_event_send(mic.event, EVENT_RECORD_STOP);
return 0;
}
static rt_err_t _ep_data_in_handler(ufunction_t func, rt_size_t size)
{
RT_ASSERT(func != RT_NULL);
LOG_D("_ep_data_in_handler");
mic.ep->request.buffer = mic.buffer + mic.buffer_index;
mic.ep->request.size = UAC_EP_MAX_PACKET_SIZE;
mic.ep->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, mic.ep, &mic.ep->request);
mic.buffer_index += UAC_EP_MAX_PACKET_SIZE;
if (mic.buffer_index >= RECORD_BUFFER_SZ)
{
mic.buffer_index = 0;
rt_event_send(mic.event, EVENT_RECORD_DATA);
}
else if (mic.buffer_index == RECORD_BUFFER_SZ / 2)
{
rt_event_send(mic.event, EVENT_RECORD_DATA);
}
return RT_EOK;
}
static rt_err_t _interface_as_handler(ufunction_t func, ureq_t setup)
{
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
LOG_D("_interface_as_handler");
if ((setup->request_type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
{
switch (setup->bRequest)
{
case USB_REQ_GET_INTERFACE:
break;
case USB_REQ_SET_INTERFACE:
LOG_D("set interface handler");
if (setup->wValue == 1)
{
_record_start(func);
}
else if (setup->wValue == 0)
{
_record_stop(func);
}
break;
default:
LOG_D("unknown uac request 0x%x", setup->bRequest);
return -RT_ERROR;
}
}
return RT_EOK;
}
static rt_err_t _function_enable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
LOG_D("uac function enable");
return RT_EOK;
}
static rt_err_t _function_disable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
LOG_D("uac function disable");
_record_stop(func);
return RT_EOK;
}
static struct ufunction_ops ops =
{
_function_enable,
_function_disable,
RT_NULL,
};
/**
* This function will configure uac descriptor.
*
* @param comm the communication interface number.
* @param data the data interface number.
*
* @return RT_EOK on successful.
*/
static rt_err_t _uac_descriptor_config(struct uac_ac_descriptor *ac,
rt_uint8_t cintf_nr, struct uac_as_descriptor *as, rt_uint8_t sintf_nr)
{
ac->hdr_desc.baInterfaceNr[0] = sintf_nr;
#ifdef RT_USB_DEVICE_COMPOSITE
ac->iad_desc.bFirstInterface = cintf_nr;
#endif
return RT_EOK;
}
static rt_err_t _uac_samplerate_config(struct uac_as_descriptor *as, rt_uint32_t samplerate)
{
as->format_type_desc.tSamFreq[0 * 3 + 2] = samplerate >> 16 & 0xff;
as->format_type_desc.tSamFreq[0 * 3 + 1] = samplerate >> 8 & 0xff;
as->format_type_desc.tSamFreq[0 * 3 + 0] = samplerate & 0xff;
return RT_EOK;
}
/**
* This function will create a uac function instance.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
ufunction_t rt_usbd_function_uac_mic_create(udevice_t device)
{
ufunction_t func;
uintf_t intf_ac, intf_as;
ualtsetting_t setting_as0;
ualtsetting_t setting_ac, setting_as;
struct uac_as_descriptor *as_desc_t;
/* parameter check */
RT_ASSERT(device != RT_NULL);
#ifdef RT_USB_DEVICE_COMPOSITE
rt_usbd_device_set_interface_string(device, MIC_INTF_STR_INDEX, _ustring[2]);
#else
/* set usb device string description */
rt_usbd_device_set_string(device, _ustring);
#endif
/* create a uac function */
func = rt_usbd_function_new(device, &dev_desc, &ops);
//not support HS
//rt_usbd_device_set_qualifier(device, &dev_qualifier);
/* create interface */
intf_ac = rt_usbd_interface_new(device, RT_NULL);
intf_as = rt_usbd_interface_new(device, _interface_as_handler);
/* create alternate setting */
setting_ac = rt_usbd_altsetting_new(sizeof(struct uac_ac_descriptor));
setting_as0 = rt_usbd_altsetting_new(sizeof(struct uinterface_descriptor));
setting_as = rt_usbd_altsetting_new(sizeof(struct uac_as_descriptor));
/* config desc in alternate setting */
rt_usbd_altsetting_config_descriptor(setting_ac, &ac_desc,
(rt_off_t) & ((struct uac_ac_descriptor *)0)->intf_desc);
rt_usbd_altsetting_config_descriptor(setting_as0, &as_desc0, 0);
rt_usbd_altsetting_config_descriptor(setting_as, &as_desc,
(rt_off_t) & ((struct uac_as_descriptor *)0)->intf_desc);
/* configure the uac interface descriptor */
_uac_descriptor_config(setting_ac->desc, intf_ac->intf_num, setting_as->desc, intf_as->intf_num);
_uac_samplerate_config(setting_as->desc, RECORD_SAMPLERATE);
/* create endpoint */
as_desc_t = (struct uac_as_descriptor *)setting_as->desc;
mic.ep = rt_usbd_endpoint_new(&as_desc_t->ep_desc, _ep_data_in_handler);
/* add the endpoint to the alternate setting */
rt_usbd_altsetting_add_endpoint(setting_as, mic.ep);
/* add the alternate setting to the interface, then set default setting of the interface */
rt_usbd_interface_add_altsetting(intf_ac, setting_ac);
rt_usbd_set_altsetting(intf_ac, 0);
rt_usbd_interface_add_altsetting(intf_as, setting_as0);
rt_usbd_interface_add_altsetting(intf_as, setting_as);
rt_usbd_set_altsetting(intf_as, 0);
/* add the interface to the uac function */
rt_usbd_function_add_interface(func, intf_ac);
rt_usbd_function_add_interface(func, intf_as);
return func;
}
int audio_mic_init(void)
{
rt_thread_t mic_tid;
mic.event = rt_event_create("mic_event", RT_IPC_FLAG_FIFO);
mic_tid = rt_thread_create("mic_thread",
mic_entry, RT_NULL,
1024,
5, 10);
if (mic_tid != RT_NULL)
rt_thread_startup(mic_tid);
return RT_EOK;
}
INIT_COMPONENT_EXPORT(audio_mic_init);
/*
* register uac class
*/
struct udclass uac_class =
{
.rt_usbd_function_create = rt_usbd_function_uac_mic_create
};
int rt_usbd_uac_mic_class_register(void)
{
rt_usbd_class_register(&uac_class);
return 0;
}
INIT_PREV_EXPORT(rt_usbd_uac_mic_class_register);

View File

@ -0,0 +1,582 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-09-19 flybreak the first version
*/
#include <rthw.h>
#include <rtdevice.h>
#include "drivers/usb_device.h"
#define AUFMT_MAX_FREQUENCIES 1
#include "uaudioreg.h"
#define DBG_TAG "usbd.audio.speaker"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#define AUDIO_SAMPLERATE 16000
#define AUDIO_CHANNEL 1
#define RESOLUTION_BITS 16
#define RESOLUTION_BYTE (RESOLUTION_BITS / 8)
#define AUDIO_PER_MS_SZ ((AUDIO_SAMPLERATE * AUDIO_CHANNEL * RESOLUTION_BYTE) / 1000)
#define AUDIO_BUFFER_SZ (AUDIO_PER_MS_SZ * 20) /* 20ms */
#if defined(RT_USBD_SPEAKER_DEVICE_NAME)
#define SPEAKER_DEVICE_NAME RT_USBD_SPEAKER_DEVICE_NAME
#else
#define SPEAKER_DEVICE_NAME "sound0"
#endif
#define EVENT_AUDIO_START (1 << 0)
#define EVENT_AUDIO_STOP (1 << 1)
#define EVENT_AUDIO_DATA (1 << 2)
#define SPK_INTF_STR_INDEX 9
/*
* uac speaker descriptor define
*/
#define UAC_CS_INTERFACE 0x24
#define UAC_CS_ENDPOINT 0x25
#define UAC_MAX_PACKET_SIZE 64
#define UAC_EP_MAX_PACKET_SIZE 32
#define UAC_CHANNEL_NUM AUDIO_CHANNEL
struct uac_ac_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct usb_audio_control_descriptor hdr_desc;
struct usb_audio_input_terminal it_desc;
struct usb_audio_output_terminal ot_desc;
#if UAC_USE_FEATURE_UNIT
struct usb_audio_feature_unit feature_unit_desc;
#endif
};
struct uac_as_descriptor
{
struct uinterface_descriptor intf_desc;
struct usb_audio_streaming_interface_descriptor hdr_desc;
struct usb_audio_streaming_type1_descriptor format_type_desc;
struct uendpoint_descriptor ep_desc;
struct usb_audio_streaming_endpoint_descriptor as_ep_desc;
};
/*
* uac speaker device type
*/
struct uac_audio_speaker
{
rt_device_t dev;
rt_event_t event;
rt_uint8_t open_count;
rt_uint8_t *buffer;
rt_uint32_t buffer_index;
uep_t ep;
};
static struct uac_audio_speaker speaker;
rt_align(4)
static struct udevice_descriptor dev_desc =
{
USB_DESC_LENGTH_DEVICE, //bLength;
USB_DESC_TYPE_DEVICE, //type;
USB_BCD_VERSION, //bcdUSB;
USB_CLASS_DEVICE, //bDeviceClass;
0x00, //bDeviceSubClass;
0x00, //bDeviceProtocol;
UAC_MAX_PACKET_SIZE, //bMaxPacketSize0;
_VENDOR_ID, //idVendor;
_PRODUCT_ID, //idProduct;
USB_BCD_DEVICE, //bcdDevice;
USB_STRING_MANU_INDEX, //iManufacturer;
USB_STRING_PRODUCT_INDEX, //iProduct;
USB_STRING_SERIAL_INDEX, //iSerialNumber;Unused.
USB_DYNAMIC, //bNumConfigurations;
};
//FS and HS needed
rt_align(4)
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier), //bLength
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
0x0200, //bcdUSB
USB_CLASS_AUDIO, //bDeviceClass
0x00, //bDeviceSubClass
0x00, //bDeviceProtocol
64, //bMaxPacketSize0
0x01, //bNumConfigurations
0,
};
rt_align(4)
const static char *_ustring[] =
{
"Language",
"RT-Thread Team.",
"RT-Thread Audio Speaker",
"32021919830108",
"Configuration",
"Interface",
};
rt_align(4)
static struct uac_ac_descriptor ac_desc =
{
#ifdef RT_USB_DEVICE_COMPOSITE
/* Interface Association Descriptor */
{
USB_DESC_LENGTH_IAD,
USB_DESC_TYPE_IAD,
USB_DYNAMIC,
0x02,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOSTREAMING,
0x00,
0x00,
},
#endif
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x00,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOCONTROL,
0x00,
#ifdef RT_USB_DEVICE_COMPOSITE
SPK_INTF_STR_INDEX,
#else
0x00,
#endif
},
/* Header Descriptor */
{
sizeof(struct usb_audio_control_descriptor),
UAC_CS_INTERFACE,
UDESCSUB_AC_HEADER,
0x0100, /* Version: 1.00 */
0x0027, /* Total length: 39 */
0x01, /* Total number of interfaces: 1 */
{0x01}, /* Interface number: 1 */
},
/* Input Terminal Descriptor */
{
sizeof(struct usb_audio_input_terminal),
UAC_CS_INTERFACE,
UDESCSUB_AC_INPUT,
0x01, /* Terminal ID: 1 */
0x0101, /* Terminal Type: USB Streaming (0x0101) */
0x00, /* Assoc Terminal: 0 */
0x01, /* Number Channels: 1 */
0x0000, /* Channel Config: 0x0000 */
0x00, /* Channel Names: 0 */
0x00, /* Terminal: 0 */
},
/* Output Terminal Descriptor */
{
sizeof(struct usb_audio_output_terminal),
UAC_CS_INTERFACE,
UDESCSUB_AC_OUTPUT,
0x02, /* Terminal ID: 2 */
0x0302, /* Terminal Type: Headphones (0x0302) */
0x00, /* Assoc Terminal: 0 */
0x01, /* Source ID: 1 */
0x00, /* Terminal: 0 */
},
#if UAC_USE_FEATURE_UNIT
/* Feature unit Descriptor */
{
UAC_DT_FEATURE_UNIT_SIZE(UAC_CH_NUM),
UAC_CS_INTERFACE,
UAC_FEATURE_UNIT,
0x02,
0x0101,
0x00,
0x01,
},
#endif
};
rt_align(4)
static struct uinterface_descriptor as_desc0 =
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x00,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOSTREAMING,
0x00,
0x00,
};
rt_align(4)
static struct uac_as_descriptor as_desc =
{
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x01,
0x01,
USB_CLASS_AUDIO,
USB_SUBCLASS_AUDIOSTREAMING,
0x00,
0x00,
},
/* General AS Descriptor */
{
sizeof(struct usb_audio_streaming_interface_descriptor),
UAC_CS_INTERFACE,
AS_GENERAL,
0x01, /* Terminal ID: 1 */
0x01, /* Interface delay in frames: 1 */
UA_FMT_PCM,
},
/* Format type i Descriptor */
{
sizeof(struct usb_audio_streaming_type1_descriptor),
UAC_CS_INTERFACE,
FORMAT_TYPE,
FORMAT_TYPE_I,
UAC_CHANNEL_NUM,
2, /* Subframe Size: 2 */
RESOLUTION_BITS,
0x01, /* Samples Frequence Type: 1 */
{0}, /* Samples Frequence */
},
/* Endpoint Descriptor */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_OUT,
USB_EP_ATTR_ISOC,
UAC_EP_MAX_PACKET_SIZE,
0x01,
},
/* AS Endpoint Descriptor */
{
sizeof(struct usb_audio_streaming_endpoint_descriptor),
UAC_CS_ENDPOINT,
AS_GENERAL,
},
};
void speaker_entry(void *parameter)
{
struct rt_audio_caps caps = {0};
rt_uint32_t e, index;
speaker.buffer = rt_malloc(AUDIO_BUFFER_SZ);
if (speaker.buffer == RT_NULL)
{
LOG_E("malloc failed");
goto __exit;
}
speaker.dev = rt_device_find(SPEAKER_DEVICE_NAME);
if (speaker.dev == RT_NULL)
{
LOG_E("can't find device:%s", SPEAKER_DEVICE_NAME);
goto __exit;
}
while (1)
{
if (rt_event_recv(speaker.event, EVENT_AUDIO_START | EVENT_AUDIO_STOP,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
1000, &e) != RT_EOK)
{
continue;
}
if (speaker.open_count == 0)
{
continue;
}
LOG_D("play start");
rt_device_open(speaker.dev, RT_DEVICE_OFLAG_WRONLY);
caps.main_type = AUDIO_TYPE_OUTPUT;
caps.sub_type = AUDIO_DSP_PARAM;
caps.udata.config.samplerate = AUDIO_SAMPLERATE;
caps.udata.config.channels = AUDIO_CHANNEL;
caps.udata.config.samplebits = RESOLUTION_BITS;
rt_device_control(speaker.dev, AUDIO_CTL_CONFIGURE, &caps);
while (1)
{
if (rt_event_recv(speaker.event, EVENT_AUDIO_DATA | EVENT_AUDIO_STOP,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
1000, &e) != RT_EOK)
{
if (speaker.open_count > 0)
continue;
else
break;
}
if (e & EVENT_AUDIO_DATA)
{
index = (speaker.buffer_index >= AUDIO_BUFFER_SZ / 2) ? 0 : (AUDIO_BUFFER_SZ / 2);
rt_device_write(speaker.dev, 0, speaker.buffer + index, AUDIO_BUFFER_SZ / 2);
}
else if (e & EVENT_AUDIO_STOP)
{
break;
}
}
LOG_D("play stop");
rt_device_close(speaker.dev);
}
__exit:
if (speaker.buffer)
rt_free(speaker.buffer);
}
static rt_err_t _audio_start(ufunction_t func)
{
speaker.ep->request.buffer = speaker.buffer;
speaker.ep->request.size = UAC_EP_MAX_PACKET_SIZE;
speaker.ep->request.req_type = UIO_REQUEST_READ_FULL;
rt_usbd_io_request(func->device, speaker.ep, &speaker.ep->request);
speaker.open_count ++;
rt_event_send(speaker.event, EVENT_AUDIO_START);
return 0;
}
static rt_err_t _audio_stop(ufunction_t func)
{
speaker.open_count --;
rt_event_send(speaker.event, EVENT_AUDIO_STOP);
return 0;
}
static rt_err_t _ep_data_handler(ufunction_t func, rt_size_t size)
{
RT_ASSERT(func != RT_NULL);
LOG_D("_ep_data_handler");
speaker.ep->request.buffer = speaker.buffer + speaker.buffer_index;
speaker.ep->request.size = UAC_EP_MAX_PACKET_SIZE;
speaker.ep->request.req_type = UIO_REQUEST_READ_FULL;
rt_usbd_io_request(func->device, speaker.ep, &speaker.ep->request);
speaker.buffer_index += UAC_EP_MAX_PACKET_SIZE;
if (speaker.buffer_index >= AUDIO_BUFFER_SZ)
{
speaker.buffer_index = 0;
rt_event_send(speaker.event, EVENT_AUDIO_DATA);
}
else if (speaker.buffer_index == AUDIO_BUFFER_SZ / 2)
{
rt_event_send(speaker.event, EVENT_AUDIO_DATA);
}
return RT_EOK;
}
static rt_err_t _interface_as_handler(ufunction_t func, ureq_t setup)
{
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
LOG_D("_interface_as_handler");
if ((setup->request_type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
{
switch (setup->bRequest)
{
case USB_REQ_GET_INTERFACE:
break;
case USB_REQ_SET_INTERFACE:
LOG_D("set interface handler");
if (setup->wValue == 1)
{
_audio_start(func);
}
else if (setup->wValue == 0)
{
_audio_stop(func);
}
break;
default:
LOG_D("unknown uac request 0x%x", setup->bRequest);
return -RT_ERROR;
}
}
return RT_EOK;
}
static rt_err_t _function_enable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
LOG_D("uac function enable");
return RT_EOK;
}
static rt_err_t _function_disable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
LOG_D("uac function disable");
_audio_stop(func);
return RT_EOK;
}
static struct ufunction_ops ops =
{
_function_enable,
_function_disable,
RT_NULL,
};
/**
* This function will configure uac descriptor.
*
* @param comm the communication interface number.
* @param data the data interface number.
*
* @return RT_EOK on successful.
*/
static rt_err_t _uac_descriptor_config(struct uac_ac_descriptor *ac,
rt_uint8_t cintf_nr, struct uac_as_descriptor *as, rt_uint8_t sintf_nr)
{
ac->hdr_desc.baInterfaceNr[0] = sintf_nr;
#ifdef RT_USB_DEVICE_COMPOSITE
ac->iad_desc.bFirstInterface = cintf_nr;
#endif
return RT_EOK;
}
static rt_err_t _uac_samplerate_config(struct uac_as_descriptor *as, rt_uint32_t samplerate)
{
as->format_type_desc.tSamFreq[0 * 3 + 2] = samplerate >> 16 & 0xff;
as->format_type_desc.tSamFreq[0 * 3 + 1] = samplerate >> 8 & 0xff;
as->format_type_desc.tSamFreq[0 * 3 + 0] = samplerate & 0xff;
return RT_EOK;
}
/**
* This function will create a uac function instance.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
ufunction_t rt_usbd_function_uac_speaker_create(udevice_t device)
{
ufunction_t func;
uintf_t intf_ac, intf_as;
ualtsetting_t setting_as0;
ualtsetting_t setting_ac, setting_as;
struct uac_as_descriptor *as_desc_t;
/* parameter check */
RT_ASSERT(device != RT_NULL);
#ifdef RT_USB_DEVICE_COMPOSITE
rt_usbd_device_set_interface_string(device, SPK_INTF_STR_INDEX, _ustring[2]);
#else
/* set usb device string description */
rt_usbd_device_set_string(device, _ustring);
#endif
/* create a uac function */
func = rt_usbd_function_new(device, &dev_desc, &ops);
//not support HS
//rt_usbd_device_set_qualifier(device, &dev_qualifier);
/* create interface */
intf_ac = rt_usbd_interface_new(device, RT_NULL);
intf_as = rt_usbd_interface_new(device, _interface_as_handler);
/* create alternate setting */
setting_ac = rt_usbd_altsetting_new(sizeof(struct uac_ac_descriptor));
setting_as0 = rt_usbd_altsetting_new(sizeof(struct uinterface_descriptor));
setting_as = rt_usbd_altsetting_new(sizeof(struct uac_as_descriptor));
/* config desc in alternate setting */
rt_usbd_altsetting_config_descriptor(setting_ac, &ac_desc,
(rt_off_t) & ((struct uac_ac_descriptor *)0)->intf_desc);
rt_usbd_altsetting_config_descriptor(setting_as0, &as_desc0, 0);
rt_usbd_altsetting_config_descriptor(setting_as, &as_desc,
(rt_off_t) & ((struct uac_as_descriptor *)0)->intf_desc);
/* configure the uac interface descriptor */
_uac_descriptor_config(setting_ac->desc, intf_ac->intf_num, setting_as->desc, intf_as->intf_num);
_uac_samplerate_config(setting_as->desc, AUDIO_SAMPLERATE);
/* create endpoint */
as_desc_t = (struct uac_as_descriptor *)setting_as->desc;
speaker.ep = rt_usbd_endpoint_new(&as_desc_t->ep_desc, _ep_data_handler);
/* add the endpoint to the alternate setting */
rt_usbd_altsetting_add_endpoint(setting_as, speaker.ep);
/* add the alternate setting to the interface, then set default setting of the interface */
rt_usbd_interface_add_altsetting(intf_ac, setting_ac);
rt_usbd_set_altsetting(intf_ac, 0);
rt_usbd_interface_add_altsetting(intf_as, setting_as0);
rt_usbd_interface_add_altsetting(intf_as, setting_as);
rt_usbd_set_altsetting(intf_as, 0);
/* add the interface to the uac function */
rt_usbd_function_add_interface(func, intf_ac);
rt_usbd_function_add_interface(func, intf_as);
return func;
}
int audio_speaker_init(void)
{
rt_thread_t speaker_tid;
speaker.event = rt_event_create("speaker_event", RT_IPC_FLAG_FIFO);
speaker_tid = rt_thread_create("speaker_thread",
speaker_entry, RT_NULL,
1024,
5, 10);
if (speaker_tid != RT_NULL)
rt_thread_startup(speaker_tid);
return RT_EOK;
}
INIT_COMPONENT_EXPORT(audio_speaker_init);
/*
* register uac class
*/
static struct udclass uac_speaker_class =
{
.rt_usbd_function_create = rt_usbd_function_uac_speaker_create
};
int rt_usbd_uac_speaker_class_register(void)
{
rt_usbd_class_register(&uac_speaker_class);
return 0;
}
INIT_PREV_EXPORT(rt_usbd_uac_speaker_class_register);

View File

@ -0,0 +1,229 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-10-03 Yi Qiu first version
* 2012-12-12 heyuanjie87 add CDC endpoints collection
*/
#ifndef __CDC_H__
#define __CDC_H__
#define USB_CDC_BUFSIZE 0x40
#define USB_CDC_CLASS_COMM 0x02
#define USB_CDC_CLASS_DATA 0x0A
#define USB_CDC_SUBCLASS_NONE 0x00
#define USB_CDC_SUBCLASS_DLCM 0x01
#define USB_CDC_SUBCLASS_ACM 0x02
#define USB_CDC_SUBCLASS_TCM 0x03
#define USB_CDC_SUBCLASS_MCCM 0x04
#define USB_CDC_SUBCLASS_CCM 0x05
#define USB_CDC_SUBCLASS_ETH 0x06
#define USB_CDC_SUBCLASS_ATM 0x07
#define USB_CDC_SUBCLASS_EEM 0x0C
#define USB_CDC_PROTOCOL_NONE 0x00
#define USB_CDC_PROTOCOL_V25TER 0x01
#define USB_CDC_PROTOCOL_I430 0x30
#define USB_CDC_PROTOCOL_HDLC 0x31
#define USB_CDC_PROTOCOL_TRANS 0x32
#define USB_CDC_PROTOCOL_Q921M 0x50
#define USB_CDC_PROTOCOL_Q921 0x51
#define USB_CDC_PROTOCOL_Q921TM 0x52
#define USB_CDC_PROTOCOL_V42BIS 0x90
#define USB_CDC_PROTOCOL_Q931 0x91
#define USB_CDC_PROTOCOL_V120 0x92
#define USB_CDC_PROTOCOL_CAPI20 0x93
#define USB_CDC_PROTOCOL_HOST 0xFD
#define USB_CDC_PROTOCOL_PUFD 0xFE
#define USB_CDC_PROTOCOL_VENDOR 0xFF
#define USB_CDC_PROTOCOL_EEM 0x07
#define USB_CDC_CS_INTERFACE 0x24
#define USB_CDC_CS_ENDPOINT 0x25
#define USB_CDC_SCS_HEADER 0x00
#define USB_CDC_SCS_CALL_MGMT 0x01
#define USB_CDC_SCS_ACM 0x02
#define USB_CDC_SCS_UNION 0x06
#define USB_CDC_SCS_ETH 0x0F
#define CDC_SEND_ENCAPSULATED_COMMAND 0x00
#define CDC_GET_ENCAPSULATED_RESPONSE 0x01
#define CDC_SET_COMM_FEATURE 0x02
#define CDC_GET_COMM_FEATURE 0x03
#define CDC_CLEAR_COMM_FEATURE 0x04
#define CDC_SET_AUX_LINE_STATE 0x10
#define CDC_SET_HOOK_STATE 0x11
#define CDC_PULSE_SETUP 0x12
#define CDC_SEND_PULSE 0x13
#define CDC_SET_PULSE_TIME 0x14
#define CDC_RING_AUX_JACK 0x15
#define CDC_SET_LINE_CODING 0x20
#define CDC_GET_LINE_CODING 0x21
#define CDC_SET_CONTROL_LINE_STATE 0x22
#define CDC_SEND_BREAK 0x23
#define CDC_SET_RINGER_PARMS 0x30
#define CDC_GET_RINGER_PARMS 0x31
#define CDC_SET_OPERATION_PARMS 0x32
#define CDC_GET_OPERATION_PARMS 0x33
#define CDC_SET_LINE_PARMS 0x34
#define CDC_GET_LINE_PARMS 0x35
#define CDC_DIAL_DIGITS 0x36
#define CDC_SET_UNIT_PARAMETER 0x37
#define CDC_GET_UNIT_PARAMETER 0x38
#define CDC_CLEAR_UNIT_PARAMETER 0x39
#define CDC_GET_PROFILE 0x3A
#define CDC_SET_ETH_MULTICAST_FILTERS 0x40
#define CDC_SET_ETH_POWER_MGMT_FILT 0x41
#define CDC_GET_ETH_POWER_MGMT_FILT 0x42
#define CDC_SET_ETH_PACKET_FILTER 0x43
#define CDC_GET_ETH_STATISTIC 0x44
#define CDC_SET_ATM_DATA_FORMAT 0x50
#define CDC_GET_ATM_DEVICE_STATISTICS 0x51
#define CDC_SET_ATM_DEFAULT_VC 0x52
#define CDC_GET_ATM_VC_STATISTICS 0x53
#pragma pack(1)
struct ucdc_header_descriptor
{
rt_uint8_t length;
rt_uint8_t type;
rt_uint8_t subtype;
rt_uint16_t bcd;
};
typedef struct ucdc_header_descriptor* ucdc_hdr_desc_t;
struct ucdc_acm_descriptor
{
rt_uint8_t length;
rt_uint8_t type;
rt_uint8_t subtype;
rt_uint8_t capabilties;
};
typedef struct ucdc_acm_descriptor* ucdc_acm_desc_t;
struct ucdc_call_mgmt_descriptor
{
rt_uint8_t length;
rt_uint8_t type;
rt_uint8_t subtype;
rt_uint8_t capabilties;
rt_uint8_t data_interface;
};
typedef struct ucdc_call_mgmt_descriptor* ucdc_call_mgmt_desc_t;
struct ucdc_union_descriptor
{
rt_uint8_t length;
rt_uint8_t type;
rt_uint8_t subtype;
rt_uint8_t master_interface;
rt_uint8_t slave_interface0;
};
typedef struct ucdc_union_descriptor* ucdc_union_desc_t;
struct ucdc_comm_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct ucdc_header_descriptor hdr_desc;
struct ucdc_call_mgmt_descriptor call_mgmt_desc;
struct ucdc_acm_descriptor acm_desc;
struct ucdc_union_descriptor union_desc;
struct uendpoint_descriptor ep_desc;
};
typedef struct ucdc_comm_descriptor* ucdc_comm_desc_t;
struct ucdc_enet_descriptor
{
rt_uint8_t bFunctionLength;
rt_uint8_t bDescriptorType;
rt_uint8_t bDescriptorSubtype;
rt_uint8_t iMACAddress;
rt_uint8_t bmEthernetStatistics[4];
rt_uint16_t wMaxSegmentSize;
rt_uint16_t wMCFilters;
rt_uint8_t bNumberPowerFilters;
};
struct ucdc_eth_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct ucdc_header_descriptor hdr_desc;
struct ucdc_union_descriptor union_desc;
struct ucdc_enet_descriptor enet_desc;
struct uendpoint_descriptor ep_desc;
};
typedef struct ucdc_eth_descriptor* ucdc_eth_desc_t;
struct ucdc_data_descriptor
{
struct uinterface_descriptor intf_desc;
struct uendpoint_descriptor ep_out_desc;
struct uendpoint_descriptor ep_in_desc;
};
typedef struct ucdc_data_descriptor* ucdc_data_desc_t;
struct ucdc_line_coding
{
rt_uint32_t dwDTERate;
rt_uint8_t bCharFormat;
rt_uint8_t bParityType;
rt_uint8_t bDataBits;
};
typedef struct ucdc_line_coding* ucdc_line_coding_t;
struct cdc_eps
{
uep_t ep_out;
uep_t ep_in;
uep_t ep_cmd;
};
typedef struct cdc_eps* cdc_eps_t;
struct ucdc_management_element_notifications
{
rt_uint8_t bmRequestType;
rt_uint8_t bNotificatinCode;
rt_uint16_t wValue;
rt_uint16_t wIndex;
rt_uint16_t wLength;
};
typedef struct ucdc_management_element_notifications * ucdc_mg_notifications_t;
struct ucdc_connection_speed_change_data
{
rt_uint32_t down_bit_rate;
rt_uint32_t up_bit_rate;
};
typedef struct connection_speed_change_data * connect_speed_data_t;
enum ucdc_notification_code
{
UCDC_NOTIFI_NETWORK_CONNECTION = 0x00,
UCDC_NOTIFI_RESPONSE_AVAILABLE = 0x01,
UCDC_NOTIFI_AUX_JACK_HOOK_STATE = 0x08,
UCDC_NOTIFI_RING_DETECT = 0x09,
UCDC_NOTIFI_SERIAL_STATE = 0x20,
UCDC_NOTIFI_CALL_STATE_CHANGE = 0x28,
UCDC_NOTIFI_LINE_STATE_CHANGE = 0x29,
UCDC_NOTIFI_CONNECTION_SPEED_CHANGE = 0x2A,
};
typedef enum ucdc_notification_code ucdc_notification_code_t;
#pragma pack()
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,682 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-11-19 ZYH first version
* 2019-06-10 ZYH fix hotplug
*/
#include <rtdevice.h>
#ifdef RT_USB_DEVICE_ECM
#include "cdc.h"
#define DBG_LEVEL DBG_WARNING
#define DBG_SECTION_NAME "ECM"
#include <rtdbg.h>
/* RT-Thread LWIP ethernet interface */
#include <netif/ethernetif.h>
#ifndef USB_ETH_MTU
#define USB_ETH_MTU 1514
#endif
#define MAX_ADDR_LEN 6
#define ECM_INTF_STR_INDEX 10
struct rt_ecm_eth
{
/* inherit from ethernet device */
struct eth_device parent;
struct ufunction * func;
struct cdc_eps eps;
/* interface address info */
rt_uint8_t host_addr[MAX_ADDR_LEN];
rt_uint8_t dev_addr[MAX_ADDR_LEN];
rt_align(4)
rt_uint8_t rx_pool[512];
rt_align(4)
rt_size_t rx_size;
rt_align(4)
rt_size_t rx_offset;
rt_align(4)
char rx_buffer[USB_ETH_MTU];
char tx_buffer[USB_ETH_MTU];
struct rt_semaphore tx_buffer_free;
};
typedef struct rt_ecm_eth * rt_ecm_eth_t;
rt_align(4)
static struct udevice_descriptor _dev_desc =
{
USB_DESC_LENGTH_DEVICE, /* bLength */
USB_DESC_TYPE_DEVICE, /* type */
USB_BCD_VERSION, /* bcdUSB */
USB_CLASS_CDC, /* bDeviceClass */
USB_CDC_SUBCLASS_ETH, /* bDeviceSubClass */
USB_CDC_PROTOCOL_NONE, /* bDeviceProtocol */
0x40, /* bMaxPacketSize0 */
_VENDOR_ID, /* idVendor */
_PRODUCT_ID, /* idProduct */
USB_BCD_DEVICE, /* bcdDevice */
USB_STRING_MANU_INDEX, /* iManufacturer */
USB_STRING_PRODUCT_INDEX, /* iProduct */
USB_STRING_SERIAL_INDEX, /* iSerialNumber */
USB_DYNAMIC /* bNumConfigurations */
};
/* communcation interface descriptor */
rt_align(4)
const static struct ucdc_eth_descriptor _comm_desc =
{
#ifdef RT_USB_DEVICE_COMPOSITE
/* Interface Association Descriptor */
{
USB_DESC_LENGTH_IAD,
USB_DESC_TYPE_IAD,
USB_DYNAMIC,
0x02,
USB_CDC_CLASS_COMM,
USB_CDC_SUBCLASS_ETH,
USB_CDC_PROTOCOL_NONE,
0x00,
},
#endif
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x01,
USB_CDC_CLASS_COMM,
USB_CDC_SUBCLASS_ETH,
USB_CDC_PROTOCOL_NONE,
#ifdef RT_USB_DEVICE_COMPOSITE
ECM_INTF_STR_INDEX,
#else
0x00,
#endif
},
/* Header Functional Descriptor */
{
sizeof(struct ucdc_header_descriptor),
USB_CDC_CS_INTERFACE,
USB_CDC_SCS_HEADER,
0x0110,
},
/* Union Functional Descriptor */
{
sizeof(struct ucdc_union_descriptor),
USB_CDC_CS_INTERFACE,
USB_CDC_SCS_UNION,
USB_DYNAMIC,
USB_DYNAMIC,
},
/* Abstract Control Management Functional Descriptor */
{
sizeof(struct ucdc_enet_descriptor),
USB_CDC_CS_INTERFACE,
USB_CDC_SCS_ETH,
USB_STRING_SERIAL_INDEX,
{0,0,0,0},
USB_ETH_MTU,
0x00,
0x00,
},
/* Endpoint Descriptor */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DIR_IN | USB_DYNAMIC,
USB_EP_ATTR_INT,
0x08,
0xFF,
},
};
/* data interface descriptor */
rt_align(4)
const static struct ucdc_data_descriptor _data_desc =
{
/* interface descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x02,
USB_CDC_CLASS_DATA,
USB_CDC_SUBCLASS_ETH,
0x00,
0x00,
},
/* endpoint, bulk out */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DIR_OUT | USB_DYNAMIC,
USB_EP_ATTR_BULK,
USB_DYNAMIC,
0x00,
},
/* endpoint, bulk in */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_IN,
USB_EP_ATTR_BULK,
USB_DYNAMIC,
0x00,
},
};
rt_align(4)
const static char* _ustring[] =
{
"Language", /* LANGID */
"RT-Thread Team.", /* MANU */
"RT-Thread ECM device", /* PRODUCT */
"3497F694ECAB", /* SERIAL (MAC)*/
"Configuration", /* CONFIG */
"Interface", /* INTERFACE */
};
rt_align(4)
//FS and HS needed
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier), //bLength
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
0x0200, //bcdUSB
USB_CLASS_CDC, //bDeviceClass
USB_CDC_SUBCLASS_ETH, //bDeviceSubClass
USB_CDC_PROTOCOL_NONE, //bDeviceProtocol
64, //bMaxPacketSize0
0x01, //bNumConfigurations
0,
};
static rt_err_t _cdc_send_notifi(ufunction_t func,ucdc_notification_code_t notifi,rt_uint16_t wValue,rt_uint16_t wLength)
{
static struct ucdc_management_element_notifications _notifi;
cdc_eps_t eps;
RT_ASSERT(func!=RT_NULL)
eps = &((rt_ecm_eth_t)func->user_data)->eps;
_notifi.bmRequestType = 0xA1;
_notifi.bNotificatinCode = notifi;
_notifi.wValue = wValue;
_notifi.wLength = wLength;
eps->ep_cmd->request.buffer = (void *)&_notifi;
eps->ep_cmd->request.size = 8;
eps->ep_cmd->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, eps->ep_cmd, &eps->ep_cmd->request);
return RT_EOK;
}
static rt_err_t _ecm_set_eth_packet_filter(ufunction_t func, ureq_t setup)
{
rt_ecm_eth_t _ecm_eth = (rt_ecm_eth_t)func->user_data;
dcd_ep0_send_status(func->device->dcd);
/* send link up. */
eth_device_linkchange(&_ecm_eth->parent, RT_TRUE);
_cdc_send_notifi(func, UCDC_NOTIFI_NETWORK_CONNECTION, 1, 0);
#ifdef LWIP_USING_DHCPD
extern void dhcpd_start(const char *netif_name);
dhcpd_start("u0");
#endif
return RT_EOK;
}
/**
* This function will handle rndis interface request.
*
* @param device the usb device object.
* @param setup the setup request.
*
* @return RT_EOK on successful.
*/
static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
{
RT_ASSERT(func != RT_NULL);
RT_ASSERT(setup != RT_NULL);
switch(setup->bRequest)
{
case CDC_SET_ETH_PACKET_FILTER:
LOG_D("CDC_SET_ETH_PACKET_FILTER");
_ecm_set_eth_packet_filter(func, setup);
break;
default:
LOG_E("Unknow setup->bRequest: 0x%02X", setup->bRequest);
break;
}
return RT_EOK;
}
/**
* This function will handle rndis bulk in endpoint request.
*
* @param device the usb device object.
* @param size request size.
*
* @return RT_EOK.
*/
static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
{
rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data;
rt_sem_release(&ecm_device->tx_buffer_free);
return RT_EOK;
}
/**
* This function will handle RNDIS bulk out endpoint request.
*
* @param device the usb device object.
* @param size request size.
*
* @return RT_EOK.
*/
static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
{
rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data;
rt_memcpy((void *)(ecm_device->rx_buffer + ecm_device->rx_offset),ecm_device->rx_pool,size);
ecm_device->rx_offset += size;
if(size < EP_MAXPACKET(ecm_device->eps.ep_out))
{
ecm_device->rx_size = ecm_device->rx_offset;
ecm_device->rx_offset = 0;
eth_device_ready(&ecm_device->parent);
}else
{
ecm_device->eps.ep_out->request.buffer = ecm_device->eps.ep_out->buffer;
ecm_device->eps.ep_out->request.size = EP_MAXPACKET(ecm_device->eps.ep_out);
ecm_device->eps.ep_out->request.req_type = UIO_REQUEST_READ_BEST;
rt_usbd_io_request(ecm_device->func->device, ecm_device->eps.ep_out, &ecm_device->eps.ep_out->request);
}
return RT_EOK;
}
static rt_err_t rt_ecm_eth_init(rt_device_t dev)
{
return RT_EOK;
}
static rt_err_t rt_ecm_eth_open(rt_device_t dev, rt_uint16_t oflag)
{
return RT_EOK;
}
static rt_err_t rt_ecm_eth_close(rt_device_t dev)
{
return RT_EOK;
}
static rt_ssize_t rt_ecm_eth_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
{
rt_set_errno(-RT_ENOSYS);
return 0;
}
static rt_ssize_t rt_ecm_eth_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
{
rt_set_errno(-RT_ENOSYS);
return 0;
}
static rt_err_t rt_ecm_eth_control(rt_device_t dev, int cmd, void *args)
{
rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev;
switch(cmd)
{
case NIOCTL_GADDR:
/* get mac address */
if(args) rt_memcpy(args, ecm_eth_dev->dev_addr, MAX_ADDR_LEN);
else return -RT_ERROR;
break;
default :
break;
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops ecm_device_ops =
{
rt_ecm_eth_init,
rt_ecm_eth_open,
rt_ecm_eth_close,
rt_ecm_eth_read,
rt_ecm_eth_write,
rt_ecm_eth_control
};
#endif
struct pbuf *rt_ecm_eth_rx(rt_device_t dev)
{
struct pbuf* p = RT_NULL;
rt_uint32_t offset = 0;
rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev;
if(ecm_eth_dev->rx_size != 0)
{
/* allocate buffer */
p = pbuf_alloc(PBUF_RAW, ecm_eth_dev->rx_size, PBUF_RAM);
if (p != RT_NULL)
{
struct pbuf* q;
for (q = p; q != RT_NULL; q= q->next)
{
/* Copy the received frame into buffer from memory pointed by the current ETHERNET DMA Rx descriptor */
rt_memcpy(q->payload,
(rt_uint8_t *)((ecm_eth_dev->rx_buffer) + offset),
q->len);
offset += q->len;
}
}
}
{
if(ecm_eth_dev->func->device->state == USB_STATE_CONFIGURED)
{
ecm_eth_dev->rx_size = 0;
ecm_eth_dev->rx_offset = 0;
ecm_eth_dev->eps.ep_out->request.buffer = ecm_eth_dev->eps.ep_out->buffer;
ecm_eth_dev->eps.ep_out->request.size = EP_MAXPACKET(ecm_eth_dev->eps.ep_out);
ecm_eth_dev->eps.ep_out->request.req_type = UIO_REQUEST_READ_BEST;
rt_usbd_io_request(ecm_eth_dev->func->device, ecm_eth_dev->eps.ep_out, &ecm_eth_dev->eps.ep_out->request);
}
}
return p;
}
rt_err_t rt_ecm_eth_tx(rt_device_t dev, struct pbuf* p)
{
struct pbuf* q;
char * pbuffer;
rt_err_t result = RT_EOK;
rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev;
if(!ecm_eth_dev->parent.link_status)
{
LOG_D("linkdown, drop pkg");
return RT_EOK;
}
if(p->tot_len > USB_ETH_MTU)
{
LOG_W("ECM MTU is:%d, but the send packet size is %d",
USB_ETH_MTU, p->tot_len);
p->tot_len = USB_ETH_MTU;
}
result = rt_sem_take(&ecm_eth_dev->tx_buffer_free, rt_tick_from_millisecond(1000));
if(result != RT_EOK)
{
LOG_W("wait for buffer free timeout");
/* if cost 1s to wait send done it said that connection is close . drop it */
rt_sem_release(&ecm_eth_dev->tx_buffer_free);
return result;
}
pbuffer = (char *)&ecm_eth_dev->tx_buffer;
for (q = p; q != NULL; q = q->next)
{
rt_memcpy(pbuffer, q->payload, q->len);
pbuffer += q->len;
}
{
if(ecm_eth_dev->func->device->state == USB_STATE_CONFIGURED)
{
ecm_eth_dev->eps.ep_in->request.buffer = (void *)&ecm_eth_dev->tx_buffer;
ecm_eth_dev->eps.ep_in->request.size = p->tot_len;
ecm_eth_dev->eps.ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(ecm_eth_dev->func->device, ecm_eth_dev->eps.ep_in, &ecm_eth_dev->eps.ep_in->request);
}
}
return result;
}
/**
* This function will handle RNDIS interrupt in endpoint request.
*
* @param device the usb device object.
* @param size request size.
*
* @return RT_EOK.
*/
static rt_err_t _ep_cmd_handler(ufunction_t func, rt_size_t size)
{
return RT_EOK;
}
/**
* This function will run cdc class, it will be called on handle set configuration request.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _function_enable(ufunction_t func)
{
cdc_eps_t eps;
rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data;
LOG_D("plugged in");
eps = (cdc_eps_t)&ecm_device->eps;
eps->ep_out->buffer = ecm_device->rx_pool;
/* reset eth rx tx */
ecm_device->rx_size = 0;
ecm_device->rx_offset = 0;
eps->ep_out->request.buffer = (void *)eps->ep_out->buffer;
eps->ep_out->request.size = EP_MAXPACKET(eps->ep_out);
eps->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
rt_usbd_io_request(func->device, eps->ep_out, &eps->ep_out->request);
return RT_EOK;
}
/**
* This function will stop cdc class, it will be called on handle set configuration request.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _function_disable(ufunction_t func)
{
LOG_D("plugged out");
eth_device_linkchange(&((rt_ecm_eth_t)func->user_data)->parent, RT_FALSE);
/* reset eth rx tx */
((rt_ecm_eth_t)func->user_data)->rx_size = 0;
((rt_ecm_eth_t)func->user_data)->rx_offset = 0;
return RT_EOK;
}
static struct ufunction_ops ops =
{
_function_enable,
_function_disable,
RT_NULL,
};
/**
* This function will configure cdc descriptor.
*
* @param comm the communication interface number.
* @param data the data interface number.
*
* @return RT_EOK on successful.
*/
static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm, rt_uint8_t cintf_nr, ucdc_data_desc_t data, rt_uint8_t dintf_nr, rt_uint8_t device_is_hs)
{
comm->call_mgmt_desc.data_interface = dintf_nr;
comm->union_desc.master_interface = cintf_nr;
comm->union_desc.slave_interface0 = dintf_nr;
#ifdef RT_USB_DEVICE_COMPOSITE
comm->iad_desc.bFirstInterface = cintf_nr;
#endif
data->ep_out_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
data->ep_in_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
return RT_EOK;
}
/**
* This function will create a cdc ecm class instance.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
ufunction_t rt_usbd_function_ecm_create(udevice_t device)
{
ufunction_t cdc;
rt_ecm_eth_t _ecm_eth;
cdc_eps_t eps;
uintf_t intf_comm, intf_data;
ualtsetting_t comm_setting, data_setting;
ucdc_data_desc_t data_desc;
ucdc_eth_desc_t comm_desc;
/* parameter check */
RT_ASSERT(device != RT_NULL);
/* set usb device string description */
#ifdef RT_USB_DEVICE_COMPOSITE
rt_usbd_device_set_interface_string(device, ECM_INTF_STR_INDEX, _ustring[2]);
#else
rt_usbd_device_set_string(device, _ustring);
#endif
/* create a cdc class */
cdc = rt_usbd_function_new(device, &_dev_desc, &ops);
rt_usbd_device_set_qualifier(device, &dev_qualifier);
_ecm_eth= rt_malloc(sizeof(struct rt_ecm_eth));
RT_ASSERT(_ecm_eth != RT_NULL);
rt_memset(_ecm_eth, 0, sizeof(struct rt_ecm_eth));
cdc->user_data = _ecm_eth;
_ecm_eth->func = cdc;
/* create a cdc class endpoints collection */
eps = &_ecm_eth->eps;
/* create a cdc communication interface and a cdc data interface */
intf_comm = rt_usbd_interface_new(device, _interface_handler);
intf_data = rt_usbd_interface_new(device, _interface_handler);
/* create a communication alternate setting and a data alternate setting */
comm_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_eth_descriptor));
data_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_data_descriptor));
/* config desc in alternate setting */
rt_usbd_altsetting_config_descriptor(comm_setting, &_comm_desc,
(rt_off_t)&((ucdc_eth_desc_t)0)->intf_desc);
rt_usbd_altsetting_config_descriptor(data_setting, &_data_desc, 0);
/* configure the cdc interface descriptor */
_cdc_descriptor_config(comm_setting->desc, intf_comm->intf_num, data_setting->desc, intf_data->intf_num, device->dcd->device_is_hs);
/* create a command endpoint */
comm_desc = (ucdc_eth_desc_t)comm_setting->desc;
eps->ep_cmd = rt_usbd_endpoint_new(&comm_desc->ep_desc, _ep_cmd_handler);
/* add the command endpoint to the cdc communication interface */
rt_usbd_altsetting_add_endpoint(comm_setting, eps->ep_cmd);
/* add the communication alternate setting to the communication interface,
then set default setting of the interface */
rt_usbd_interface_add_altsetting(intf_comm, comm_setting);
rt_usbd_set_altsetting(intf_comm, 0);
/* add the communication interface to the cdc class */
rt_usbd_function_add_interface(cdc, intf_comm);
/* create a bulk in and a bulk out endpoint */
data_desc = (ucdc_data_desc_t)data_setting->desc;
eps->ep_out = rt_usbd_endpoint_new(&data_desc->ep_out_desc, _ep_out_handler);
eps->ep_in = rt_usbd_endpoint_new(&data_desc->ep_in_desc, _ep_in_handler);
/* add the bulk out and bulk in endpoints to the data alternate setting */
rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_in);
rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_out);
/* add the data alternate setting to the data interface
then set default setting of the interface */
rt_usbd_interface_add_altsetting(intf_data, data_setting);
rt_usbd_set_altsetting(intf_data, 0);
/* add the cdc data interface to cdc class */
rt_usbd_function_add_interface(cdc, intf_data);
rt_sem_init(&_ecm_eth->tx_buffer_free, "ue_tx", 1, RT_IPC_FLAG_FIFO);
/* OUI 00-00-00, only for test. */
_ecm_eth->dev_addr[0] = 0x34;
_ecm_eth->dev_addr[1] = 0x97;
_ecm_eth->dev_addr[2] = 0xF6;
/* generate random MAC. */
_ecm_eth->dev_addr[3] = 0x94;//*(const rt_uint8_t *)(0x1fff7a10);
_ecm_eth->dev_addr[4] = 0xEC;//*(const rt_uint8_t *)(0x1fff7a14);
_ecm_eth->dev_addr[5] = 0xAC;//(const rt_uint8_t *)(0x1fff7a18);
/* OUI 00-00-00, only for test. */
_ecm_eth->host_addr[0] = 0x34;
_ecm_eth->host_addr[1] = 0x97;
_ecm_eth->host_addr[2] = 0xF6;
/* generate random MAC. */
_ecm_eth->host_addr[3] = 0x94;//*(const rt_uint8_t *)(0x1fff7a10);
_ecm_eth->host_addr[4] = 0xEC;//*(const rt_uint8_t *)(0x1fff7a14);
_ecm_eth->host_addr[5] = 0xAB;//*(const rt_uint8_t *)(0x1fff7a18);
#ifdef RT_USING_DEVICE_OPS
_ecm_eth->parent.parent.ops = &ecm_device_ops;
#else
_ecm_eth->parent.parent.init = rt_ecm_eth_init;
_ecm_eth->parent.parent.open = rt_ecm_eth_open;
_ecm_eth->parent.parent.close = rt_ecm_eth_close;
_ecm_eth->parent.parent.read = rt_ecm_eth_read;
_ecm_eth->parent.parent.write = rt_ecm_eth_write;
_ecm_eth->parent.parent.control = rt_ecm_eth_control;
#endif
_ecm_eth->parent.parent.user_data = device;
_ecm_eth->parent.eth_rx = rt_ecm_eth_rx;
_ecm_eth->parent.eth_tx = rt_ecm_eth_tx;
/* register eth device */
eth_device_init(&_ecm_eth->parent, "u0");
/* send link up. */
eth_device_linkchange(&_ecm_eth->parent, RT_FALSE);
return cdc;
}
struct udclass ecm_class =
{
.rt_usbd_function_create = rt_usbd_function_ecm_create
};
int rt_usbd_ecm_class_register(void)
{
rt_usbd_class_register(&ecm_class);
return 0;
}
INIT_PREV_EXPORT(rt_usbd_ecm_class_register);
#endif /* RT_USB_DEVICE_ECM */

View File

@ -0,0 +1,756 @@
/*
* File : hid.c
* COPYRIGHT (C) 2006 - 2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-03-13 Urey the first version
* 2017-11-16 ZYH Update to common hid
*/
#include <rthw.h>
#include <rtdevice.h>
#include "drivers/usb_common.h"
#include "drivers/usb_device.h"
#include "hid.h"
#ifdef RT_USB_DEVICE_HID
#define DBG_TAG "usbdevice.hid"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#define HID_INTF_STR_INDEX 7
struct hid_s
{
struct rt_device parent;
struct ufunction *func;
uep_t ep_in;
uep_t ep_out;
int status;
rt_uint8_t protocol;
rt_uint8_t report_buf[MAX_REPORT_SIZE];
struct rt_messagequeue hid_mq;
};
/* CustomHID_ConfigDescriptor */
rt_align(4)
const rt_uint8_t _report_desc[]=
{
#ifdef RT_USB_DEVICE_HID_KEYBOARD
USAGE_PAGE(1), 0x01,
USAGE(1), 0x06,
COLLECTION(1), 0x01,
REPORT_ID(1), HID_REPORT_ID_KEYBOARD1,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0xE0,
USAGE_MAXIMUM(1), 0xE7,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
REPORT_SIZE(1), 0x01,
REPORT_COUNT(1), 0x08,
INPUT(1), 0x02,
REPORT_COUNT(1), 0x01,
REPORT_SIZE(1), 0x08,
INPUT(1), 0x01,
REPORT_COUNT(1), 0x05,
REPORT_SIZE(1), 0x01,
USAGE_PAGE(1), 0x08,
USAGE_MINIMUM(1), 0x01,
USAGE_MAXIMUM(1), 0x05,
OUTPUT(1), 0x02,
REPORT_COUNT(1), 0x01,
REPORT_SIZE(1), 0x03,
OUTPUT(1), 0x01,
REPORT_COUNT(1), 0x06,
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x65,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0x00,
USAGE_MAXIMUM(1), 0x65,
INPUT(1), 0x00,
END_COLLECTION(0),
#if RT_USB_DEVICE_HID_KEYBOARD_NUMBER>1
/****keyboard2*****/
USAGE_PAGE(1), 0x01,
USAGE(1), 0x06,
COLLECTION(1), 0x01,
REPORT_ID(1), HID_REPORT_ID_KEYBOARD2,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0xE0,
USAGE_MAXIMUM(1), 0xE7,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
REPORT_SIZE(1), 0x01,
REPORT_COUNT(1), 0x08,
INPUT(1), 0x02,
REPORT_COUNT(1), 0x01,
REPORT_SIZE(1), 0x08,
INPUT(1), 0x01,
REPORT_COUNT(1), 0x06,
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x65,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0x00,
USAGE_MAXIMUM(1), 0x65,
INPUT(1), 0x00,
END_COLLECTION(0),
#if RT_USB_DEVICE_HID_KEYBOARD_NUMBER>2
USAGE_PAGE(1), 0x01,
USAGE(1), 0x06,
COLLECTION(1), 0x01,
REPORT_ID(1), HID_REPORT_ID_KEYBOARD3,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0xE0,
USAGE_MAXIMUM(1), 0xE7,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
REPORT_SIZE(1), 0x01,
REPORT_COUNT(1), 0x08,
INPUT(1), 0x02,
REPORT_COUNT(1), 0x01,
REPORT_SIZE(1), 0x08,
INPUT(1), 0x01,
REPORT_COUNT(1), 0x06,
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x65,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0x00,
USAGE_MAXIMUM(1), 0x65,
INPUT(1), 0x00,
END_COLLECTION(0),
#if RT_USB_DEVICE_HID_KEYBOARD_NUMBER>3
USAGE_PAGE(1), 0x01,
USAGE(1), 0x06,
COLLECTION(1), 0x01,
REPORT_ID(1), HID_REPORT_ID_KEYBOARD4,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0xE0,
USAGE_MAXIMUM(1), 0xE7,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
REPORT_SIZE(1), 0x01,
REPORT_COUNT(1), 0x08,
INPUT(1), 0x02,
REPORT_COUNT(1), 0x01,
REPORT_SIZE(1), 0x08,
INPUT(1), 0x01,
REPORT_COUNT(1), 0x06,
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x65,
USAGE_PAGE(1), 0x07,
USAGE_MINIMUM(1), 0x00,
USAGE_MAXIMUM(1), 0x65,
INPUT(1), 0x00,
END_COLLECTION(0),
#endif
#endif
#endif
#endif
// Media Control
#ifdef RT_USB_DEVICE_HID_MEDIA
USAGE_PAGE(1), 0x0C,
USAGE(1), 0x01,
COLLECTION(1), 0x01,
REPORT_ID(1), HID_REPORT_ID_MEDIA,
USAGE_PAGE(1), 0x0C,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
REPORT_SIZE(1), 0x01,
REPORT_COUNT(1), 0x07,
USAGE(1), 0xB5, // Next Track
USAGE(1), 0xB6, // Previous Track
USAGE(1), 0xB7, // Stop
USAGE(1), 0xCD, // Play / Pause
USAGE(1), 0xE2, // Mute
USAGE(1), 0xE9, // Volume Up
USAGE(1), 0xEA, // Volume Down
INPUT(1), 0x02, // Input (Data, Variable, Absolute)
REPORT_COUNT(1), 0x01,
INPUT(1), 0x01,
END_COLLECTION(0),
#endif
#ifdef RT_USB_DEVICE_HID_GENERAL
USAGE_PAGE(1), 0x8c,
USAGE(1), 0x01,
COLLECTION(1), 0x01,
REPORT_ID(1), HID_REPORT_ID_GENERAL,
REPORT_COUNT(1), RT_USB_DEVICE_HID_GENERAL_IN_REPORT_LENGTH,
USAGE(1), 0x03,
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0xFF,
INPUT(1), 0x02,
REPORT_COUNT(1), RT_USB_DEVICE_HID_GENERAL_OUT_REPORT_LENGTH,
USAGE(1), 0x04,
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0xFF,
OUTPUT(1), 0x02,
END_COLLECTION(0),
#endif
#ifdef RT_USB_DEVICE_HID_MOUSE
USAGE_PAGE(1), 0x01, // Generic Desktop
USAGE(1), 0x02, // Mouse
COLLECTION(1), 0x01, // Application
USAGE(1), 0x01, // Pointer
COLLECTION(1), 0x00, // Physical
REPORT_ID(1), HID_REPORT_ID_MOUSE,
REPORT_COUNT(1), 0x03,
REPORT_SIZE(1), 0x01,
USAGE_PAGE(1), 0x09, // Buttons
USAGE_MINIMUM(1), 0x1,
USAGE_MAXIMUM(1), 0x3,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
INPUT(1), 0x02,
REPORT_COUNT(1), 0x01,
REPORT_SIZE(1), 0x05,
INPUT(1), 0x01,
REPORT_COUNT(1), 0x03,
REPORT_SIZE(1), 0x08,
USAGE_PAGE(1), 0x01,
USAGE(1), 0x30, // X
USAGE(1), 0x31, // Y
USAGE(1), 0x38, // scroll
LOGICAL_MINIMUM(1), 0x81,
LOGICAL_MAXIMUM(1), 0x7f,
INPUT(1), 0x06,
END_COLLECTION(0),
END_COLLECTION(0),
#endif
}; /* CustomHID_ReportDescriptor */
rt_align(4)
static struct udevice_descriptor _dev_desc =
{
USB_DESC_LENGTH_DEVICE, //bLength;
USB_DESC_TYPE_DEVICE, //type;
USB_BCD_VERSION, //bcdUSB;
0x0, //bDeviceClass;
0x00, //bDeviceSubClass;
0x00, //bDeviceProtocol;
64, //bMaxPacketSize0;
_VENDOR_ID, //idVendor;
_PRODUCT_ID, //idProduct;
USB_BCD_DEVICE, //bcdDevice;
USB_STRING_MANU_INDEX, //iManufacturer;
USB_STRING_PRODUCT_INDEX, //iProduct;
USB_STRING_SERIAL_INDEX, //iSerialNumber;
USB_DYNAMIC, //bNumConfigurations;
};
//FS and HS needed
rt_align(4)
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier), //bLength
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
0x0200, //bcdUSB
0x0, //bDeviceClass
0x0, //bDeviceSubClass
0x50, //bDeviceProtocol
64, //bMaxPacketSize0
0x01, //bNumConfigurations
0,
};
/* hid interface descriptor */
rt_align(4)
const static struct uhid_comm_descriptor _hid_comm_desc =
{
#ifdef RT_USB_DEVICE_COMPOSITE
/* Interface Association Descriptor */
{
USB_DESC_LENGTH_IAD,
USB_DESC_TYPE_IAD,
USB_DYNAMIC,
0x01,
0x03, /* bInterfaceClass: HID */
#if defined(RT_USB_DEVICE_HID_KEYBOARD)||defined(RT_USB_DEVICE_HID_MOUSE)
USB_HID_SUBCLASS_BOOT, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
#else
USB_HID_SUBCLASS_NOBOOT, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
#endif
#if !defined(RT_USB_DEVICE_HID_KEYBOARD)||!defined(RT_USB_DEVICE_HID_MOUSE)||!defined(RT_USB_DEVICE_HID_MEDIA)
USB_HID_PROTOCOL_NONE, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#elif !defined(RT_USB_DEVICE_HID_MOUSE)
USB_HID_PROTOCOL_KEYBOARD, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#else
USB_HID_PROTOCOL_MOUSE, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#endif
0x00,
},
#endif
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints */
0x03, /* bInterfaceClass: HID */
#if defined(RT_USB_DEVICE_HID_KEYBOARD)||defined(RT_USB_DEVICE_HID_MOUSE)
USB_HID_SUBCLASS_BOOT, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
#else
USB_HID_SUBCLASS_NOBOOT, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
#endif
#if !defined(RT_USB_DEVICE_HID_KEYBOARD)||!defined(RT_USB_DEVICE_HID_MOUSE)||!defined(RT_USB_DEVICE_HID_MEDIA)
USB_HID_PROTOCOL_NONE, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#elif !defined(RT_USB_DEVICE_HID_MOUSE)
USB_HID_PROTOCOL_KEYBOARD, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#else
USB_HID_PROTOCOL_MOUSE, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#endif
#ifdef RT_USB_DEVICE_COMPOSITE
HID_INTF_STR_INDEX, /* iInterface: Index of string descriptor */
#else
0,
#endif
},
/* HID Descriptor */
{
HID_DESCRIPTOR_SIZE, /* bLength: HID Descriptor size */
HID_DESCRIPTOR_TYPE, /* bDescriptorType: HID */
0x0110, /* bcdHID: HID Class Spec release number */
0x00, /* bCountryCode: Hardware target country */
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
{
{
0x22, /* bDescriptorType */
sizeof(_report_desc), /* wItemLength: Total length of Report descriptor */
},
},
},
/* Endpoint Descriptor IN */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_IN,
USB_EP_ATTR_INT,
0x40,
0x0A,
},
/* Endpoint Descriptor OUT */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_OUT,
USB_EP_ATTR_INT,
0x40,
0x01,
},
};
rt_align(4)
const static char* _ustring[] =
{
"Language",
"RT-Thread Team.",
"RTT HID-Device",
"32021919830108",
"Configuration",
"Interface",
};
static void dump_data(rt_uint8_t *data, rt_size_t size)
{
rt_size_t i;
for (i = 0; i < size; i++)
{
rt_kprintf("%02x ", *data++);
if ((i + 1) % 8 == 0)
{
rt_kprintf("\n");
}else if ((i + 1) % 4 == 0){
rt_kprintf(" ");
}
}
}
static void dump_report(struct hid_report * report)
{
rt_kprintf("\nHID Recived:");
rt_kprintf("\nReport ID %02x \n", report->report_id);
dump_data(report->report,report->size);
}
static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
{
struct hid_s *data;
struct hid_report report;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
data = (struct hid_s *) func->user_data;
if(size != 0)
{
rt_memcpy((void *)&report,(void*)data->ep_out->buffer,size);
report.size = size-1;
rt_mq_send(&data->hid_mq,(void *)&report,sizeof(report));
}
data->ep_out->request.buffer = data->ep_out->buffer;
data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
return RT_EOK;
}
static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
{
struct hid_s *data;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
data = (struct hid_s *) func->user_data;
if(data->parent.tx_complete != RT_NULL)
{
data->parent.tx_complete(&data->parent,RT_NULL);
}
return RT_EOK;
}
static rt_err_t _hid_set_report_callback(udevice_t device, rt_size_t size)
{
LOG_D("_hid_set_report_callback");
if(size != 0)
{
}
dcd_ep0_send_status(device->dcd);
return RT_EOK;
}
/**
* This function will handle hid interface bRequest.
*
* @param device the usb device object.
* @param setup the setup bRequest.
*
* @return RT_EOK on successful.
*/
static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
{
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
struct hid_s *data = (struct hid_s *) func->user_data;
switch (setup->bRequest)
{
case USB_REQ_GET_DESCRIPTOR:
if((setup->wValue >> 8) == USB_DESC_TYPE_REPORT)
{
rt_usbd_ep0_write(func->device, (void *)(&_report_desc[0]), sizeof(_report_desc));
}
else if((setup->wValue >> 8) == USB_DESC_TYPE_HID)
{
rt_usbd_ep0_write(func->device, (void *)(&_hid_comm_desc.hid_desc), sizeof(struct uhid_descriptor));
}
break;
case USB_HID_REQ_GET_REPORT:
if(setup->wLength == 0)
{
rt_usbd_ep0_set_stall(func->device);
break;
}
if((setup->wLength == 0) || (setup->wLength > MAX_REPORT_SIZE))
setup->wLength = MAX_REPORT_SIZE;
rt_usbd_ep0_write(func->device, data->report_buf,setup->wLength);
break;
case USB_HID_REQ_GET_IDLE:
dcd_ep0_send_status(func->device->dcd);
break;
case USB_HID_REQ_GET_PROTOCOL:
rt_usbd_ep0_write(func->device, &data->protocol,1);
break;
case USB_HID_REQ_SET_REPORT:
if((setup->wLength == 0) || (setup->wLength > MAX_REPORT_SIZE))
rt_usbd_ep0_set_stall(func->device);
rt_usbd_ep0_read(func->device, data->report_buf, setup->wLength, _hid_set_report_callback);
break;
case USB_HID_REQ_SET_IDLE:
dcd_ep0_send_status(func->device->dcd);
break;
case USB_HID_REQ_SET_PROTOCOL:
data->protocol = setup->wValue;
dcd_ep0_send_status(func->device->dcd);
break;
}
return RT_EOK;
}
/**
* This function will run cdc function, it will be called on handle set configuration bRequest.
*
* @param func the usb function object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _function_enable(ufunction_t func)
{
struct hid_s *data;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
data = (struct hid_s *) func->user_data;
LOG_D("hid function enable");
//
// _vcom_reset_state(func);
//
if(data->ep_out->buffer == RT_NULL)
{
data->ep_out->buffer = rt_malloc(HID_RX_BUFSIZE);
}
data->ep_out->request.buffer = data->ep_out->buffer;
data->ep_out->request.size = EP_MAXPACKET(data->ep_out);
data->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
rt_usbd_io_request(func->device, data->ep_out, &data->ep_out->request);
return RT_EOK;
}
/**
* This function will stop cdc function, it will be called on handle set configuration bRequest.
*
* @param func the usb function object.
*
* @return RT_EOK on successful.
*/
static rt_err_t _function_disable(ufunction_t func)
{
struct hid_s *data;
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
data = (struct hid_s *) func->user_data;
LOG_D("hid function disable");
if(data->ep_out->buffer != RT_NULL)
{
rt_free(data->ep_out->buffer);
data->ep_out->buffer = RT_NULL;
}
return RT_EOK;
}
static struct ufunction_ops ops =
{
_function_enable,
_function_disable,
RT_NULL,
};
/**
* This function will configure hid descriptor.
*
* @param comm the communication interface number.
* @param data the data interface number.
*
* @return RT_EOK on successful.
*/
static rt_err_t _hid_descriptor_config(uhid_comm_desc_t hid, rt_uint8_t cintf_nr)
{
#ifdef RT_USB_DEVICE_COMPOSITE
hid->iad_desc.bFirstInterface = cintf_nr;
#endif
return RT_EOK;
}
static rt_ssize_t _hid_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
struct hid_s *hiddev = (struct hid_s *)dev;
struct hid_report report;
if (hiddev->func->device->state == USB_STATE_CONFIGURED)
{
report.report_id = pos;
rt_memcpy((void *)report.report,(void *)buffer,size);
report.size = size;
hiddev->ep_in->request.buffer = (void *)&report;
hiddev->ep_in->request.size = (size+1) > 64 ? 64 : size+1;
hiddev->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(hiddev->func->device, hiddev->ep_in, &hiddev->ep_in->request);
return size;
}
return 0;
}
rt_weak void HID_Report_Received(hid_report_t report)
{
dump_report(report);
}
rt_align(RT_ALIGN_SIZE)
static rt_uint8_t hid_thread_stack[512];
static struct rt_thread hid_thread;
static void hid_thread_entry(void* parameter)
{
struct hid_report report;
struct hid_s *hiddev;
hiddev = (struct hid_s *)parameter;
while(1)
{
if(rt_mq_recv(&hiddev->hid_mq, &report, sizeof(report),RT_WAITING_FOREVER) < 0)
continue;
HID_Report_Received(&report);
}
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops hid_device_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
_hid_write,
RT_NULL,
};
#endif
static rt_uint8_t hid_mq_pool[(sizeof(struct hid_report)+sizeof(void*))*8];
static void rt_usb_hid_init(struct ufunction *func)
{
struct hid_s *hiddev;
hiddev = (struct hid_s *)func->user_data;
rt_memset(&hiddev->parent, 0, sizeof(hiddev->parent));
#ifdef RT_USING_DEVICE_OPS
hiddev->parent.ops = &hid_device_ops;
#else
hiddev->parent.write = _hid_write;
#endif
hiddev->func = func;
rt_device_register(&hiddev->parent, "hidd", RT_DEVICE_FLAG_RDWR);
rt_mq_init(&hiddev->hid_mq, "hiddmq", hid_mq_pool, sizeof(struct hid_report),
sizeof(hid_mq_pool), RT_IPC_FLAG_FIFO);
rt_thread_init(&hid_thread, "hidd", hid_thread_entry, hiddev,
hid_thread_stack, sizeof(hid_thread_stack), RT_USBD_THREAD_PRIO, 20);
rt_thread_startup(&hid_thread);
}
/**
* This function will create a hid function instance.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
ufunction_t rt_usbd_function_hid_create(udevice_t device)
{
ufunction_t func;
struct hid_s *data;
uintf_t hid_intf;
ualtsetting_t hid_setting;
uhid_comm_desc_t hid_desc;
/* parameter check */
RT_ASSERT(device != RT_NULL);
/* set usb device string description */
#ifdef RT_USB_DEVICE_COMPOSITE
rt_usbd_device_set_interface_string(device, HID_INTF_STR_INDEX, _ustring[2]);
#else
rt_usbd_device_set_string(device, _ustring);
#endif
/* create a cdc function */
func = rt_usbd_function_new(device, &_dev_desc, &ops);
/* For high speed mode supporting */
rt_usbd_device_set_qualifier(device, &dev_qualifier);
/* allocate memory for cdc vcom data */
data = (struct hid_s*)rt_malloc(sizeof(struct hid_s));
rt_memset(data, 0, sizeof(struct hid_s));
func->user_data = (void*)data;
/* create an interface object */
hid_intf = rt_usbd_interface_new(device, _interface_handler);
/* create an alternate setting object */
hid_setting = rt_usbd_altsetting_new(sizeof(struct uhid_comm_descriptor));
/* config desc in alternate setting */
rt_usbd_altsetting_config_descriptor(hid_setting, &_hid_comm_desc, (rt_off_t)&((uhid_comm_desc_t)0)->intf_desc);
/* configure the hid interface descriptor */
_hid_descriptor_config(hid_setting->desc, hid_intf->intf_num);
/* create endpoint */
hid_desc = (uhid_comm_desc_t)hid_setting->desc;
data->ep_out = rt_usbd_endpoint_new(&hid_desc->ep_out_desc, _ep_out_handler);
data->ep_in = rt_usbd_endpoint_new(&hid_desc->ep_in_desc, _ep_in_handler);
/* add the int out and int in endpoint to the alternate setting */
rt_usbd_altsetting_add_endpoint(hid_setting, data->ep_out);
rt_usbd_altsetting_add_endpoint(hid_setting, data->ep_in);
/* add the alternate setting to the interface, then set default setting */
rt_usbd_interface_add_altsetting(hid_intf, hid_setting);
rt_usbd_set_altsetting(hid_intf, 0);
/* add the interface to the mass storage function */
rt_usbd_function_add_interface(func, hid_intf);
/* initilize hid */
rt_usb_hid_init(func);
return func;
}
struct udclass hid_class =
{
.rt_usbd_function_create = rt_usbd_function_hid_create
};
int rt_usbd_hid_class_register(void)
{
rt_usbd_class_register(&hid_class);
return 0;
}
INIT_PREV_EXPORT(rt_usbd_hid_class_register);
#endif /* RT_USB_DEVICE_HID */

View File

@ -0,0 +1,258 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-03-13 Urey the first version
* 2017-11-16 ZYH Update to common hid
*/
#ifndef _USBDEVICE_CLASS_HID_H_
#define _USBDEVICE_CLASS_HID_H_
#ifdef __cplusplus
extern "C" {
#endif
#define HID_DESCRIPTOR_TYPE 0x21
#define HID_DESCRIPTOR_SIZE 0x09
#define HID_OFF_HID_DESC 0x12
#define USB_HID_SUBCLASS_BOOT 0x01
#define USB_HID_SUBCLASS_NOBOOT 0x00
#define USB_HID_PROTOCOL_NONE 0x00
#define USB_HID_PROTOCOL_KEYBOARD 0x01
#define USB_HID_PROTOCOL_MOUSE 0x02
#define USB_HID_REQ_GET_REPORT 0x01
#define USB_HID_REQ_GET_IDLE 0x02
#define USB_HID_REQ_GET_PROTOCOL 0x03
#define USB_HID_REQ_SET_REPORT 0x09
#define USB_HID_REQ_SET_IDLE 0x0a
#define USB_HID_REQ_SET_PROTOCOL 0x0b
#define MAX_REPORT_SIZE 64
#define HID_RX_BUFSIZE 64
/* HID Report Types */
#define HID_REPORT_INPUT 0x01
#define HID_REPORT_OUTPUT 0x02
#define HID_REPORT_FEATURE 0x03
/* Usage Pages */
#define USAGEPAGE_UNDEFINED 0x00
#define USAGEPAGE_GENERIC 0x01
#define USAGEPAGE_SIMULATION 0x02
#define USAGEPAGE_VR 0x03
#define USAGEPAGE_SPORT 0x04
#define USAGEPAGE_GAME 0x05
#define USAGEPAGE_DEV_CONTROLS 0x06
#define USAGEPAGE_KEYBOARD 0x07
#define USAGEPAGE_LED 0x08
#define USAGEPAGE_BUTTON 0x09
#define USAGEPAGE_ORDINAL 0x0A
#define USAGEPAGE_TELEPHONY 0x0B
#define USAGEPAGE_CONSUMER 0x0C
#define USAGEPAGE_DIGITIZER 0x0D
#define USAGEPAGE_PIDPAGE 0x0F
#define USAGEPAGE_UNICODE 0x10
#define USAGEPAGE_ALPHANUMERIC 0x14
#define USAGEPAGE_BARCODESCANNER 0x8C
/* Generic Desktop Page (0x01) */
#define USAGE_GENERIC_POINTER 0x01
#define USAGE_GENERIC_MOUSE 0x02
#define USAGE_GENERIC_JOYSTICK 0x04
#define USAGE_GENERIC_GAMEPAD 0x05
#define USAGE_GENERIC_KEYBOARD 0x06
#define USAGE_GENERIC_KEYPAD 0x07
#define USAGE_GENERIC_X 0x30
#define USAGE_GENERIC_Y 0x31
#define USAGE_GENERIC_Z 0x32
#define USAGE_GENERIC_RX 0x33
#define USAGE_GENERIC_RY 0x34
#define USAGE_GENERIC_RZ 0x35
#define USAGE_GENERIC_SLIDER 0x36
#define USAGE_GENERIC_DIAL 0x37
#define USAGE_GENERIC_WHEEL 0x38
#define USAGE_GENERIC_HATSWITCH 0x39
#define USAGE_GENERIC_COUNTED_BUFFER 0x3A
#define USAGE_GENERIC_BYTE_COUNT 0x3B
#define USAGE_GENERIC_MOTION_WAKEUP 0x3C
#define USAGE_GENERIC_VX 0x40
#define USAGE_GENERIC_VY 0x41
#define USAGE_GENERIC_VZ 0x42
#define USAGE_GENERIC_VBRX 0x43
#define USAGE_GENERIC_VBRY 0x44
#define USAGE_GENERIC_VBRZ 0x45
#define USAGE_GENERIC_VNO 0x46
#define USAGE_GENERIC_SYSTEM_CTL 0x80
#define USAGE_GENERIC_SYSCTL_POWER 0x81
#define USAGE_GENERIC_SYSCTL_SLEEP 0x82
#define USAGE_GENERIC_SYSCTL_WAKE 0x83
#define USAGE_GENERIC_SYSCTL_CONTEXT_MENU 0x84
#define USAGE_GENERIC_SYSCTL_MAIN_MENU 0x85
#define USAGE_GENERIC_SYSCTL_APP_MENU 0x86
#define USAGE_GENERIC_SYSCTL_HELP_MENU 0x87
#define USAGE_GENERIC_SYSCTL_MENU_EXIT 0x88
#define USAGE_GENERIC_SYSCTL_MENU_SELECT 0x89
#define USAGE_GENERIC_SYSCTL_MENU_RIGHT 0x8A
#define USAGE_GENERIC_SYSCTL_MENU_LEFT 0x8B
#define USAGE_GENERIC_SYSCTL_MENU_UP 0x8C
#define USAGE_GENERIC_SYSCTL_MENU_DOWN 0x8D
/* Simulation Controls Page(0x02) */
#define USAGE_SIMCTRL_THROTTLE 0xBB
/* HID Report Items */
/* Main Items */
#define HID_Input(x) 0x81,x
#define HID_Output(x) 0x91,x
#define HID_Feature(x) 0xB1,x
#define HID_Collection(x) 0xA1,x
#define HID_EndCollection() 0xC0
/* Local Items */
#define HID_Usage(x) 0x09,x
#define HID_UsageMin(x) 0x19,x
#define HID_UsageMax(x) 0x29,x
/* Global Items */
#define HID_UsagePage(x) 0x05,x
#define HID_UsagePageVendor(x) 0x06,x,0xFF
#define HID_LogicalMin(x) 0x15,x
#define HID_LogicalMinS(x) 0x16,(x&0xFF),((x>>8)&0xFF)
#define HID_LogicalMinL(x) 0x17,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_LogicalMax(x) 0x25,x
#define HID_LogicalMaxS(x) 0x26,(x&0xFF),((x>>8)&0xFF)
#define HID_LogicalMaxL(x) 0x27,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_PhysicalMin(x) 0x35,x
#define HID_PhysicalMinS(x) 0x36,(x&0xFF),((x>>8)&0xFF)
#define HID_PhysicalMinL(x) 0x37,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_PhysicalMax(x) 0x45,x
#define HID_PhysicalMaxS(x) 0x46,(x&0xFF),((x>>8)&0xFF)
#define HID_PhysicalMaxL(x) 0x47,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_UnitExponent(x) 0x55,x
#define HID_Unit(x) 0x65,x
#define HID_UnitS(x) 0x66,(x&0xFF),((x>>8)&0xFF)
#define HID_UnitL(x) 0x67,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_ReportSize(x) 0x75,x
#define HID_ReportSizeS(x) 0x76,(x&0xFF),((x>>8)&0xFF))
#define HID_ReportSizeL(x) 0x77,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_ReportID(x) 0x85,x
#define HID_ReportCount(x) 0x95,x
#define HID_ReportCountS(x) 0x96,(x&0xFF),((x>>8)&0xFF)
#define HID_ReportCountL(x) 0x97,(x&0xFF),((x>>8)&0xFF),((x>>16)&0xFF),((x>>24)&0xFF)
#define HID_Push() 0xA4
#define HID_Pop() 0xB4
/* Input, Output, Feature Data */
#define HID_DATA (0<<0)
#define HID_CONST (1<<0)
#define HID_ARRAY (0<<1)
#define HID_VAR (1<<1)
#define HID_ABS (0<<2)
#define HID_REL (1<<2)
#define HID_NOWRAP (0<<3)
#define HID_WRAP (1<<3)
#define HID_LINEAR (0<<4)
#define HID_NONLINEAR (1<<4)
#define HID_PREFERREDSTATE (0<<5)
#define HID_NOPREFERRED (1<<5)
#define HID_NONULLPOSITION (0<<6)
#define HID_NULLSTATE (1<<6)
#define HID_NONVOLATILE (0<<7)
#define HID_VOLATILE (1<<7)
/* Collection Data */
#define HID_PHYSICAL 0x00
#define HID_APPLICATION 0x01
#define HID_LOGICAL 0x02
#define HID_REPORT 0x03
#define HID_NAMEDARRAY 0x04
#define HID_USAGESWITCH 0x05
#define HID_USAGEMODIFIER 0x06
//HID_MBED_DEFINE
#define HID_VERSION_1_11 (0x0111)
/* HID Class */
#define HID_CLASS (3)
#define HID_SUBCLASS_NONE (0)
#define HID_SUBCLASS_BOOT (1)
#define HID_PROTOCOL_NONE (0)
#define HID_PROTOCOL_KEYBOARD (1)
#define HID_PROTOCOL_MOUSE (2)
/* Descriptors */
#define HID_DESCRIPTOR (33)
#define HID_DESCRIPTOR_LENGTH (0x09)
#define REPORT_DESCRIPTOR (34)
/* Class requests */
#define GET_REPORT (0x1)
#define GET_IDLE (0x2)
#define SET_REPORT (0x9)
#define SET_IDLE (0xa)
/* HID Class Report Descriptor */
/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */
/* of data as per HID Class standard */
/* Main items */
#define INPUT(size) (0x80 | size)
#define OUTPUT(size) (0x90 | size)
#define FEATURE(size) (0xb0 | size)
#define COLLECTION(size) (0xa0 | size)
#define END_COLLECTION(size) (0xc0 | size)
/* Global items */
#define USAGE_PAGE(size) (0x04 | size)
#define LOGICAL_MINIMUM(size) (0x14 | size)
#define LOGICAL_MAXIMUM(size) (0x24 | size)
#define PHYSICAL_MINIMUM(size) (0x34 | size)
#define PHYSICAL_MAXIMUM(size) (0x44 | size)
#define UNIT_EXPONENT(size) (0x54 | size)
#define UNIT(size) (0x64 | size)
#define REPORT_SIZE(size) (0x74 | size)
#define REPORT_ID(size) (0x84 | size)
#define REPORT_COUNT(size) (0x94 | size)
#define PUSH(size) (0xa4 | size)
#define POP(size) (0xb4 | size)
/* Local items */
#define USAGE(size) (0x08 | size)
#define USAGE_MINIMUM(size) (0x18 | size)
#define USAGE_MAXIMUM(size) (0x28 | size)
#define DESIGNATOR_INDEX(size) (0x38 | size)
#define DESIGNATOR_MINIMUM(size) (0x48 | size)
#define DESIGNATOR_MAXIMUM(size) (0x58 | size)
#define STRING_INDEX(size) (0x78 | size)
#define STRING_MINIMUM(size) (0x88 | size)
#define STRING_MAXIMUM(size) (0x98 | size)
#define DELIMITER(size) (0xa8 | size)
#define LSB(n) ((n)&0xff)
#define MSB(n) (((n)&0xff00)>>8)
struct uhid_comm_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct uhid_descriptor hid_desc;
struct uendpoint_descriptor ep_in_desc;
struct uendpoint_descriptor ep_out_desc;
};
typedef struct uhid_comm_descriptor* uhid_comm_desc_t;
#ifdef __cplusplus
}
#endif
#endif /* _USBDEVICE_CLASS_HID_H_ */

File diff suppressed because it is too large Load Diff

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
* 2012-10-01 Yi Qiu first version
* 2012-12-12 heyuanjie87 add MASS endpoints collection
*/
#ifndef __MSTORAGE_H__
#define __MSTORAGE_H__
#include <rtthread.h>
#pragma pack(1)
struct umass_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct uendpoint_descriptor ep_out_desc;
struct uendpoint_descriptor ep_in_desc;
};
typedef struct umass_descriptor* umass_desc_t;
struct capacity_data
{
rt_uint8_t LastLogicalBlockAddress[4];
rt_uint8_t BlockLengthInBytes[4];
};
struct request_sense_data
{
rt_uint8_t ErrorCode:7;
rt_uint8_t Valid:1;
rt_uint8_t Reserved1;
rt_uint8_t SenseKey:4;
rt_uint8_t Reserved2:4;
rt_uint8_t Information[4];
rt_uint8_t AdditionalSenseLength;
rt_uint8_t Reserved3[4];
rt_uint8_t AdditionalSenseCode;
rt_uint8_t AdditionalSenseCodeQualifier;
rt_uint8_t Reserved4[4];
}request_sense_data_t;
#pragma pack()
#endif

View File

@ -0,0 +1,237 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
/*
* ndis.h
*
* Modified by Colin O'Flynn <coflynn@newae.com>
* ntddndis.h modified by Benedikt Spranger <b.spranger@pengutronix.de>
*
* Thanks to the cygwin development team,
* espacially to Casper S. Hornstrup <chorns@users.sourceforge.net>
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* This code is distributed in the hope that it will be useful but
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
* DISCLAIMED. This includes but is not limited to warranties of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#ifndef __NDIS_H__
#define __NDIS_H__
#define NDIS_STATUS_MULTICAST_FULL 0xC0010009
#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A
#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B
/* from drivers/net/sk98lin/h/skgepnmi.h */
#define OID_PNP_CAPABILITIES 0xFD010100
#define OID_PNP_SET_POWER 0xFD010101
#define OID_PNP_QUERY_POWER 0xFD010102
#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103
#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104
#define OID_PNP_ENABLE_WAKE_UP 0xFD010106
enum NDIS_DEVICE_POWER_STATE
{
NdisDeviceStateUnspecified = 0,
NdisDeviceStateD0,
NdisDeviceStateD1,
NdisDeviceStateD2,
NdisDeviceStateD3,
NdisDeviceStateMaximum
};
struct NDIS_PM_WAKE_UP_CAPABILITIES
{
enum NDIS_DEVICE_POWER_STATE MinMagicPacketWakeUp;
enum NDIS_DEVICE_POWER_STATE MinPatternWakeUp;
enum NDIS_DEVICE_POWER_STATE MinLinkChangeWakeUp;
};
/* NDIS_PNP_CAPABILITIES.Flags constants */
#define NDIS_DEVICE_WAKE_UP_ENABLE 0x00000001
#define NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002
#define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004
/* Required Object IDs (OIDs) */
#define OID_GEN_SUPPORTED_LIST 0x00010101
#define OID_GEN_HARDWARE_STATUS 0x00010102
#define OID_GEN_MEDIA_SUPPORTED 0x00010103
#define OID_GEN_MEDIA_IN_USE 0x00010104
#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
#define OID_GEN_LINK_SPEED 0x00010107
#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
#define OID_GEN_VENDOR_ID 0x0001010C
#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
#define OID_GEN_DRIVER_VERSION 0x00010110
#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
#define OID_GEN_MAC_OPTIONS 0x00010113
#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
#define OID_GEN_SUPPORTED_GUIDS 0x00010117
#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118
#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119
#define OID_GEN_MACHINE_NAME 0x0001021A
#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B
#define OID_GEN_VLAN_ID 0x0001021C
/* Optional OIDs */
#define OID_GEN_MEDIA_CAPABILITIES 0x00010201
#define OID_GEN_PHYSICAL_MEDIUM 0x00010202
/* Required statistics OIDs */
#define OID_GEN_XMIT_OK 0x00020101
#define OID_GEN_RCV_OK 0x00020102
#define OID_GEN_XMIT_ERROR 0x00020103
#define OID_GEN_RCV_ERROR 0x00020104
#define OID_GEN_RCV_NO_BUFFER 0x00020105
/* Optional statistics OIDs */
#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
#define OID_GEN_RCV_CRC_ERROR 0x0002020D
#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
#define OID_GEN_GET_TIME_CAPS 0x0002020F
#define OID_GEN_GET_NETCARD_TIME 0x00020210
#define OID_GEN_NETCARD_LOAD 0x00020211
#define OID_GEN_DEVICE_PROFILE 0x00020212
#define OID_GEN_INIT_TIME_MS 0x00020213
#define OID_GEN_RESET_COUNTS 0x00020214
#define OID_GEN_MEDIA_SENSE_COUNTS 0x00020215
#define OID_GEN_FRIENDLY_NAME 0x00020216
#define OID_GEN_MINIPORT_INFO 0x00020217
#define OID_GEN_RESET_VERIFY_PARAMETERS 0x00020218
/* IEEE 802.3 (Ethernet) OIDs */
#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001
#define OID_802_3_PERMANENT_ADDRESS 0x01010101
#define OID_802_3_CURRENT_ADDRESS 0x01010102
#define OID_802_3_MULTICAST_LIST 0x01010103
#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104
#define OID_802_3_MAC_OPTIONS 0x01010105
#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101
#define OID_802_3_XMIT_ONE_COLLISION 0x01020102
#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103
#define OID_802_3_XMIT_DEFERRED 0x01020201
#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202
#define OID_802_3_RCV_OVERRUN 0x01020203
#define OID_802_3_XMIT_UNDERRUN 0x01020204
#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205
#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206
#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207
/* Wireless LAN OIDs */
#define OID_802_11_BSSID 0x0D010101 /* Q S */
#define OID_802_11_SSID 0x0D010102 /* Q S */
#define OID_802_11_NETWORK_TYPE_IN_USE 0x0D010204 /* Q S */
#define OID_802_11_RSSI 0x0D010206 /* Q I */
#define OID_802_11_BSSID_LIST 0x0D010217 /* Q */
#define OID_802_11_BSSID_LIST_SCAN 0x0D01011A /* S */
#define OID_802_11_INFRASTRUCTURE_MODE 0x0D010108 /* Q S */
#define OID_802_11_SUPPORTED_RATES 0x0D01020E /* Q */
#define OID_802_11_CONFIGURATION 0x0D010211 /* Q S */
#define OID_802_11_ADD_WEP 0x0D010113 /* S */
#define OID_802_11_WEP_STATUS 0x0D01011B /* Q S */
#define OID_802_11_REMOVE_WEP 0x0D010114 /* S */
#define OID_802_11_DISASSOCIATE 0x0D010115 /* S */
#define OID_802_11_AUTHENTICATION_MODE 0x0D010118 /* Q S */
#define OID_802_11_RELOAD_DEFAULTS 0x0D01011C /* S */
/* OID_GEN_MINIPORT_INFO constants */
#define NDIS_MINIPORT_BUS_MASTER 0x00000001
#define NDIS_MINIPORT_WDM_DRIVER 0x00000002
#define NDIS_MINIPORT_SG_LIST 0x00000004
#define NDIS_MINIPORT_SUPPORTS_MEDIA_QUERY 0x00000008
#define NDIS_MINIPORT_INDICATES_PACKETS 0x00000010
#define NDIS_MINIPORT_IGNORE_PACKET_QUEUE 0x00000020
#define NDIS_MINIPORT_IGNORE_REQUEST_QUEUE 0x00000040
#define NDIS_MINIPORT_IGNORE_TOKEN_RING_ERRORS 0x00000080
#define NDIS_MINIPORT_INTERMEDIATE_DRIVER 0x00000100
#define NDIS_MINIPORT_IS_NDIS_5 0x00000200
#define NDIS_MINIPORT_IS_CO 0x00000400
#define NDIS_MINIPORT_DESERIALIZE 0x00000800
#define NDIS_MINIPORT_REQUIRES_MEDIA_POLLING 0x00001000
#define NDIS_MINIPORT_SUPPORTS_MEDIA_SENSE 0x00002000
#define NDIS_MINIPORT_NETBOOT_CARD 0x00004000
#define NDIS_MINIPORT_PM_SUPPORTED 0x00008000
#define NDIS_MINIPORT_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00010000
#define NDIS_MINIPORT_USES_SAFE_BUFFER_APIS 0x00020000
#define NDIS_MINIPORT_HIDDEN 0x00040000
#define NDIS_MINIPORT_SWENUM 0x00080000
#define NDIS_MINIPORT_SURPRISE_REMOVE_OK 0x00100000
#define NDIS_MINIPORT_NO_HALT_ON_SUSPEND 0x00200000
#define NDIS_MINIPORT_HARDWARE_DEVICE 0x00400000
#define NDIS_MINIPORT_SUPPORTS_CANCEL_SEND_PACKETS 0x00800000
#define NDIS_MINIPORT_64BITS_DMA 0x01000000
#define NDIS_MEDIUM_802_3 0x00000000
#define NDIS_MEDIUM_802_5 0x00000001
#define NDIS_MEDIUM_FDDI 0x00000002
#define NDIS_MEDIUM_WAN 0x00000003
#define NDIS_MEDIUM_LOCAL_TALK 0x00000004
#define NDIS_MEDIUM_DIX 0x00000005
#define NDIS_MEDIUM_ARCENT_RAW 0x00000006
#define NDIS_MEDIUM_ARCENT_878_2 0x00000007
#define NDIS_MEDIUM_ATM 0x00000008
#define NDIS_MEDIUM_WIRELESS_LAN 0x00000009
#define NDIS_MEDIUM_IRDA 0x0000000A
#define NDIS_MEDIUM_BPC 0x0000000B
#define NDIS_MEDIUM_CO_WAN 0x0000000C
#define NDIS_MEDIUM_1394 0x0000000D
#define NDIS_PACKET_TYPE_DIRECTED 0x00000001
#define NDIS_PACKET_TYPE_MULTICAST 0x00000002
#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004
#define NDIS_PACKET_TYPE_BROADCAST 0x00000008
#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010
#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020
#define NDIS_PACKET_TYPE_SMT 0x00000040
#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080
#define NDIS_PACKET_TYPE_GROUP 0x00000100
#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200
#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400
#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800
#define NDIS_MEDIA_STATE_CONNECTED 0x00000000
#define NDIS_MEDIA_STATE_DISCONNECTED 0x00000001
#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001
#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002
#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004
#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008
#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010
#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020
#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040
#define NDIS_MAC_OPTION_RESERVED 0x80000000
#endif /* __NDIS_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,227 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-12-24 heyuanjie87 first version
*/
#ifndef __RNDIS_H__
#define __RNDIS_H__
#include <rtthread.h>
#define USB_ETH_MTU 1500+14
#define RNDIS_MESSAGE_BUFFER_SIZE 128
#define RESPONSE_AVAILABLE 0x00000001
/* Remote NDIS version numbers */
#define RNDIS_MAJOR_VERSION 1
#define RNDIS_MINOR_VERSION 0
/* common status values */
#define RNDIS_STATUS_SUCCESS 0X00000000
#define RNDIS_STATUS_FAILURE 0XC0000001
#define RNDIS_STATUS_INVALID_DATA 0XC0010015
#define RNDIS_STATUS_NOT_SUPPORTED 0XC00000BB
#define RNDIS_STATUS_MEDIA_CONNECT 0X4001000B
#define RNDIS_STATUS_MEDIA_DISCONNECT 0X4001000C
/* Remote NDIS message types */
#define REMOTE_NDIS_PACKET_MSG 0x00000001
#define REMOTE_NDIS_INITIALIZE_MSG 0X00000002
#define REMOTE_NDIS_HALT_MSG 0X00000003
#define REMOTE_NDIS_QUERY_MSG 0X00000004
#define REMOTE_NDIS_SET_MSG 0X00000005
#define REMOTE_NDIS_RESET_MSG 0X00000006
#define REMOTE_NDIS_INDICATE_STATUS_MSG 0X00000007
#define REMOTE_NDIS_KEEPALIVE_MSG 0X00000008
#define REMOTE_NDIS_INITIALIZE_CMPLT 0X80000002
#define REMOTE_NDIS_QUERY_CMPLT 0X80000004
#define REMOTE_NDIS_SET_CMPLT 0X80000005
#define REMOTE_NDIS_RESET_CMPLT 0X80000006
#define REMOTE_NDIS_KEEPALIVE_CMPLT 0X80000008
/* device flags */
#define RNDIS_DF_CONNECTIONLESS 0x00000001
#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002
/* mediums */
#define RNDIS_MEDIUM_802_3 0x00000000
struct ucls_rndis
{
uep_t notify;
rt_uint32_t filter;
rt_bool_t header;
rt_uint8_t rndis_state;
rt_uint8_t media_state;
rt_uint8_t ethaddr[6];
};
/* Remote NDIS generic message type */
struct rndis_gen_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
};
typedef struct rndis_gen_msg* rndis_gen_msg_t;
struct rndis_packet_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t DataOffset;
rt_uint32_t DataLength;
rt_uint32_t OOBDataOffset;
rt_uint32_t OOBDataLength;
rt_uint32_t NumOOBDataElements;
rt_uint32_t PerPacketInfoOffset;
rt_uint32_t PerPacketInfoLength;
rt_uint32_t VcHandle;
rt_uint32_t Reserved;
};
typedef struct rndis_packet_msg* rndis_packet_msg_t;
/* Remote NDIS Initialize Message */
struct rndis_init_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t MajorVersion;
rt_uint32_t MinorVersion;
rt_uint32_t MaxTransferSize;
};
typedef struct rndis_init_msg* rndis_init_msg_t;
/* Response */
struct rndis_init_cmplt
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t Status;
rt_uint32_t MajorVersion;
rt_uint32_t MinorVersion;
rt_uint32_t DeviceFlags;
rt_uint32_t Medium;
rt_uint32_t MaxPacketsPerTransfer;
rt_uint32_t MaxTransferSize;
rt_uint32_t PacketAlignmentFactor;
rt_uint32_t AfListOffset;
rt_uint32_t AfListSize;
};
typedef struct rndis_init_cmplt* rndis_init_cmplt_t;
/* Remote NDIS Halt Message */
struct rndis_halt_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
};
/* Remote NDIS Query Message */
struct rndis_query_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t Oid;
rt_uint32_t InformationBufferLength;
rt_uint32_t InformationBufferOffset;
rt_uint32_t DeviceVcHandle;
};
typedef struct rndis_query_msg* rndis_query_msg_t;
/* Response */
struct rndis_query_cmplt
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t Status;
rt_uint32_t InformationBufferLength;
rt_uint32_t InformationBufferOffset;
};
typedef struct rndis_query_cmplt* rndis_query_cmplt_t;
/* Remote NDIS Set Message */
struct rndis_set_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t Oid;
rt_uint32_t InformationBufferLength;
rt_uint32_t InformationBufferOffset;
rt_uint32_t DeviceVcHandle;
};
typedef struct rndis_set_msg* rndis_set_msg_t;
/* Response */
struct rndis_set_cmplt
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t Status;
};
typedef struct rndis_set_cmplt* rndis_set_cmplt_t;
/* Remote NDIS Soft Reset Message */
struct rndis_reset_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t Reserved;
};
/* Remote NDIS Soft Reset Response */
struct rndis_reset_cmplt
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t Status;
rt_uint32_t AddressingReset;
};
/* Remote NDIS Indicate Status Message */
struct rndis_indicate_status_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t Status;
rt_uint32_t StatusBufferLength;
rt_uint32_t StatusBufferOffset;
};
typedef struct rndis_indicate_status_msg* rndis_indicate_status_msg_t;
struct rndis_keepalive_msg
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestID;
};
typedef struct rndis_keepalive_msg* rndis_keepalive_msg_t;
/* Response: */
struct rndis_keepalive_cmplt
{
rt_uint32_t MessageType;
rt_uint32_t MessageLength;
rt_uint32_t RequestId;
rt_uint32_t Status;
};
typedef struct rndis_keepalive_cmplt* rndis_keepalive_cmplt_t;
#endif

View File

@ -0,0 +1,419 @@
/* $NetBSD: uaudioreg.h,v 1.15.38.1 2012/06/02 11:09:29 mrg Exp $ */
/*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (lennart@augustsson.net) at
* Carlstedt Research & Technology.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <rtdef.h>
#include <stdint.h>
typedef uint8_t uByte;
typedef uint16_t uWord;
#define UPACKED __attribute__ ((packed))
#define UAUDIO_VERSION 0x100
#define USB_SUBCLASS_AUDIOCONTROL 1
#define USB_SUBCLASS_AUDIOSTREAMING 2
#define USB_SUBCLASS_AUDIOMIDISTREAM 3
#define UDESC_CS_CONFIG 0x22
#define UDESC_CS_STRING 0x23
#define UDESC_CS_INTERFACE 0x24
#define UDESC_CS_ENDPOINT 0x25
#define UDESCSUB_AC_HEADER 1
#define UDESCSUB_AC_INPUT 2
#define UDESCSUB_AC_OUTPUT 3
#define UDESCSUB_AC_MIXER 4
#define UDESCSUB_AC_SELECTOR 5
#define UDESCSUB_AC_FEATURE 6
#define UDESCSUB_AC_PROCESSING 7
#define UDESCSUB_AC_EXTENSION 8
#ifndef AUFMT_MAX_FREQUENCIES
#define AUFMT_MAX_FREQUENCIES 1
#endif
/* The first fields are identical to usb_endpoint_descriptor_t */
typedef struct {
uByte bLength;
uByte bDescriptorType;
uByte bEndpointAddress;
uByte bmAttributes;
uWord wMaxPacketSize;
uByte bInterval;
/*
* The following two entries are only used by the Audio Class.
* And according to the specs the Audio Class is the only one
* allowed to extend the endpoint descriptor.
* Who knows what goes on in the minds of the people in the USB
* standardization? :-(
*/
uByte bRefresh;
uByte bSynchAddress;
} UPACKED usb_endpoint_descriptor_audio_t;
/* generic, for iteration */
typedef struct {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
} UPACKED uaudio_cs_descriptor_t;
struct usb_audio_control_descriptor {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uWord bcdADC;
uWord wTotalLength;
uByte bInCollection;
uByte baInterfaceNr[1];
} UPACKED;
struct usb_audio_streaming_interface_descriptor {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bTerminalLink;
uByte bDelay;
uWord wFormatTag;
} UPACKED;
struct usb_audio_streaming_endpoint_descriptor {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bmAttributes;
#define UA_SED_FREQ_CONTROL 0x01
#define UA_SED_PITCH_CONTROL 0x02
#define UA_SED_MAXPACKETSONLY 0x80
uByte bLockDelayUnits;
uWord wLockDelay;
} UPACKED;
struct usb_audio_streaming_type1_descriptor {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bFormatType;
uByte bNrChannels;
uByte bSubFrameSize;
uByte bBitResolution;
uByte bSamFreqType;
#define UA_SAMP_CONTNUOUS 0
uByte tSamFreq[3*AUFMT_MAX_FREQUENCIES];
#define UA_GETSAMP(p, n) ((p)->tSamFreq[(n)*3+0] | ((p)->tSamFreq[(n)*3+1] << 8) | ((p)->tSamFreq[(n)*3+2] << 16))
#define UA_SAMP_LO(p) UA_GETSAMP(p, 0)
#define UA_SAMP_HI(p) UA_GETSAMP(p, 1)
} UPACKED;
struct usb_audio_cluster {
uByte bNrChannels;
uWord wChannelConfig;
#define UA_CHANNEL_LEFT 0x0001
#define UA_CHANNEL_RIGHT 0x0002
#define UA_CHANNEL_CENTER 0x0004
#define UA_CHANNEL_LFE 0x0008
#define UA_CHANNEL_L_SURROUND 0x0010
#define UA_CHANNEL_R_SURROUND 0x0020
#define UA_CHANNEL_L_CENTER 0x0040
#define UA_CHANNEL_R_CENTER 0x0080
#define UA_CHANNEL_SURROUND 0x0100
#define UA_CHANNEL_L_SIDE 0x0200
#define UA_CHANNEL_R_SIDE 0x0400
#define UA_CHANNEL_TOP 0x0800
uByte iChannelNames;
} UPACKED;
/* Shared by all units and terminals */
struct usb_audio_unit {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bUnitId;
};
/* UDESCSUB_AC_INPUT */
struct usb_audio_input_terminal {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bTerminalId;
uWord wTerminalType;
uByte bAssocTerminal;
uByte bNrChannels;
uWord wChannelConfig;
uByte iChannelNames;
uByte iTerminal;
} UPACKED;
/* UDESCSUB_AC_OUTPUT */
struct usb_audio_output_terminal {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bTerminalId;
uWord wTerminalType;
uByte bAssocTerminal;
uByte bSourceId;
uByte iTerminal;
} UPACKED;
/* UDESCSUB_AC_MIXER */
struct usb_audio_mixer_unit {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bUnitId;
uByte bNrInPins;
uByte baSourceId[255]; /* [bNrInPins] */
/* struct usb_audio_mixer_unit_1 */
} UPACKED;
struct usb_audio_mixer_unit_1 {
uByte bNrChannels;
uWord wChannelConfig;
uByte iChannelNames;
uByte bmControls[255]; /* [bNrChannels] */
/*uByte iMixer;*/
} UPACKED;
/* UDESCSUB_AC_SELECTOR */
struct usb_audio_selector_unit {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bUnitId;
uByte bNrInPins;
uByte baSourceId[255]; /* [bNrInPins] */
/* uByte iSelector; */
} UPACKED;
/* UDESCSUB_AC_FEATURE */
struct usb_audio_feature_unit {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bUnitId;
uByte bSourceId;
uByte bControlSize;
uByte bmaControls[2]; /* size for more than enough */
/* uByte iFeature; */
} UPACKED;
/* UDESCSUB_AC_PROCESSING */
struct usb_audio_processing_unit {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bUnitId;
uWord wProcessType;
uByte bNrInPins;
uByte baSourceId[255]; /* [bNrInPins] */
/* struct usb_audio_processing_unit_1 */
} UPACKED;
struct usb_audio_processing_unit_1{
uByte bNrChannels;
uWord wChannelConfig;
uByte iChannelNames;
uByte bControlSize;
uByte bmControls[255]; /* [bControlSize] */
#define UA_PROC_ENABLE_MASK 1
} UPACKED;
struct usb_audio_processing_unit_updown {
uByte iProcessing;
uByte bNrModes;
uWord waModes[255]; /* [bNrModes] */
} UPACKED;
/* UDESCSUB_AC_EXTENSION */
struct usb_audio_extension_unit {
uByte bLength;
uByte bDescriptorType;
uByte bDescriptorSubtype;
uByte bUnitId;
uWord wExtensionCode;
uByte bNrInPins;
uByte baSourceId[255]; /* [bNrInPins] */
/* struct usb_audio_extension_unit_1 */
} UPACKED;
struct usb_audio_extension_unit_1 {
uByte bNrChannels;
uWord wChannelConfig;
uByte iChannelNames;
uByte bControlSize;
uByte bmControls[255]; /* [bControlSize] */
#define UA_EXT_ENABLE_MASK 1
#define UA_EXT_ENABLE 1
/*uByte iExtension;*/
} UPACKED;
/* USB terminal types */
#define UAT_UNDEFINED 0x0100
#define UAT_STREAM 0x0101
#define UAT_VENDOR 0x01ff
/* input terminal types */
#define UATI_UNDEFINED 0x0200
#define UATI_MICROPHONE 0x0201
#define UATI_DESKMICROPHONE 0x0202
#define UATI_PERSONALMICROPHONE 0x0203
#define UATI_OMNIMICROPHONE 0x0204
#define UATI_MICROPHONEARRAY 0x0205
#define UATI_PROCMICROPHONEARR 0x0206
/* output terminal types */
#define UATO_UNDEFINED 0x0300
#define UATO_SPEAKER 0x0301
#define UATO_HEADPHONES 0x0302
#define UATO_DISPLAYAUDIO 0x0303
#define UATO_DESKTOPSPEAKER 0x0304
#define UATO_ROOMSPEAKER 0x0305
#define UATO_COMMSPEAKER 0x0306
#define UATO_SUBWOOFER 0x0307
/* bidir terminal types */
#define UATB_UNDEFINED 0x0400
#define UATB_HANDSET 0x0401
#define UATB_HEADSET 0x0402
#define UATB_SPEAKERPHONE 0x0403
#define UATB_SPEAKERPHONEESUP 0x0404
#define UATB_SPEAKERPHONEECANC 0x0405
/* telephony terminal types */
#define UATT_UNDEFINED 0x0500
#define UATT_PHONELINE 0x0501
#define UATT_TELEPHONE 0x0502
#define UATT_DOWNLINEPHONE 0x0503
/* external terminal types */
#define UATE_UNDEFINED 0x0600
#define UATE_ANALOGCONN 0x0601
#define UATE_DIGITALAUIFC 0x0602
#define UATE_LINECONN 0x0603
#define UATE_LEGACYCONN 0x0604
#define UATE_SPDIF 0x0605
#define UATE_1394DA 0x0606
#define UATE_1394DV 0x0607
/* embedded function terminal types */
#define UATF_UNDEFINED 0x0700
#define UATF_CALIBNOISE 0x0701
#define UATF_EQUNOISE 0x0702
#define UATF_CDPLAYER 0x0703
#define UATF_DAT 0x0704
#define UATF_DCC 0x0705
#define UATF_MINIDISK 0x0706
#define UATF_ANALOGTAPE 0x0707
#define UATF_PHONOGRAPH 0x0708
#define UATF_VCRAUDIO 0x0709
#define UATF_VIDEODISCAUDIO 0x070a
#define UATF_DVDAUDIO 0x070b
#define UATF_TVTUNERAUDIO 0x070c
#define UATF_SATELLITE 0x070d
#define UATF_CABLETUNER 0x070e
#define UATF_DSS 0x070f
#define UATF_RADIORECV 0x0710
#define UATF_RADIOXMIT 0x0711
#define UATF_MULTITRACK 0x0712
#define UATF_SYNTHESIZER 0x0713
#define SET_CUR 0x01
#define GET_CUR 0x81
#define SET_MIN 0x02
#define GET_MIN 0x82
#define SET_MAX 0x03
#define GET_MAX 0x83
#define SET_RES 0x04
#define GET_RES 0x84
#define SET_MEM 0x05
#define GET_MEM 0x85
#define GET_STAT 0xff
#define MUTE_CONTROL 0x01
#define VOLUME_CONTROL 0x02
#define BASS_CONTROL 0x03
#define MID_CONTROL 0x04
#define TREBLE_CONTROL 0x05
#define GRAPHIC_EQUALIZER_CONTROL 0x06
#define AGC_CONTROL 0x07
#define DELAY_CONTROL 0x08
#define BASS_BOOST_CONTROL 0x09
#define LOUDNESS_CONTROL 0x0a
#define FU_MASK(u) (1 << ((u)-1))
#define MASTER_CHAN 0
#define AS_GENERAL 1
#define FORMAT_TYPE 2
#define FORMAT_SPECIFIC 3
#define UA_FMT_PCM 1
#define UA_FMT_PCM8 2
#define UA_FMT_IEEE_FLOAT 3
#define UA_FMT_ALAW 4
#define UA_FMT_MULAW 5
#define UA_FMT_MPEG 0x1001
#define UA_FMT_AC3 0x1002
#define SAMPLING_FREQ_CONTROL 0x01
#define PITCH_CONTROL 0x02
#define FORMAT_TYPE_UNDEFINED 0
#define FORMAT_TYPE_I 1
#define FORMAT_TYPE_II 2
#define FORMAT_TYPE_III 3
#define UA_PROC_MASK(n) (1<< ((n)-1))
#define PROCESS_UNDEFINED 0
#define XX_ENABLE_CONTROL 1
#define UPDOWNMIX_PROCESS 1
#define UD_ENABLE_CONTROL 1
#define UD_MODE_SELECT_CONTROL 2
#define DOLBY_PROLOGIC_PROCESS 2
#define DP_ENABLE_CONTROL 1
#define DP_MODE_SELECT_CONTROL 2
#define P3D_STEREO_EXTENDER_PROCESS 3
#define P3D_ENABLE_CONTROL 1
#define P3D_SPACIOUSNESS_CONTROL 2
#define REVERBATION_PROCESS 4
#define RV_ENABLE_CONTROL 1
#define RV_LEVEL_CONTROL 2
#define RV_TIME_CONTROL 3
#define RV_FEEDBACK_CONTROL 4
#define CHORUS_PROCESS 5
#define CH_ENABLE_CONTROL 1
#define CH_LEVEL_CONTROL 2
#define CH_RATE_CONTROL 3
#define CH_DEPTH_CONTROL 4
#define DYN_RANGE_COMP_PROCESS 6
#define DR_ENABLE_CONTROL 1
#define DR_COMPRESSION_RATE_CONTROL 2
#define DR_MAXAMPL_CONTROL 3
#define DR_THRESHOLD_CONTROL 4
#define DR_ATTACK_TIME_CONTROL 5
#define DR_RELEASE_TIME_CONTROL 6

View File

@ -0,0 +1,375 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-11-16 ZYH first version
*/
#include <rthw.h>
#include <rtdevice.h>
#include <drivers/usb_device.h>
#include "winusb.h"
struct winusb_device
{
struct rt_device parent;
void (*cmd_handler)(rt_uint8_t *buffer,rt_size_t size);
rt_uint8_t cmd_buff[256];
uep_t ep_out;
uep_t ep_in;
};
#define WINUSB_INTF_STR_INDEX 13
typedef struct winusb_device * winusb_device_t;
rt_align(4)
static struct udevice_descriptor dev_desc =
{
USB_DESC_LENGTH_DEVICE, //bLength;
USB_DESC_TYPE_DEVICE, //type;
USB_BCD_VERSION, //bcdUSB;
0x00, //bDeviceClass;
0x00, //bDeviceSubClass;
0x00, //bDeviceProtocol;
0x40, //bMaxPacketSize0;
_VENDOR_ID, //idVendor;
_PRODUCT_ID, //idProduct;
USB_BCD_DEVICE, //bcdDevice;
USB_STRING_MANU_INDEX, //iManufacturer;
USB_STRING_PRODUCT_INDEX, //iProduct;
USB_STRING_SERIAL_INDEX, //iSerialNumber;
USB_DYNAMIC, //bNumConfigurations;
};
//FS and HS needed
rt_align(4)
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier), //bLength
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
0x0200, //bcdUSB
0xFF, //bDeviceClass
0x00, //bDeviceSubClass
0x00, //bDeviceProtocol
64, //bMaxPacketSize0
0x01, //bNumConfigurations
0,
};
rt_align(4)
struct winusb_descriptor _winusb_desc =
{
#ifdef RT_USB_DEVICE_COMPOSITE
/* Interface Association Descriptor */
{
USB_DESC_LENGTH_IAD,
USB_DESC_TYPE_IAD,
USB_DYNAMIC,
0x01,
0xFF,
0x00,
0x00,
0x00,
},
#endif
/*interface descriptor*/
{
USB_DESC_LENGTH_INTERFACE, //bLength;
USB_DESC_TYPE_INTERFACE, //type;
USB_DYNAMIC, //bInterfaceNumber;
0x00, //bAlternateSetting;
0x02, //bNumEndpoints
0xFF, //bInterfaceClass;
0x00, //bInterfaceSubClass;
0x00, //bInterfaceProtocol;
#ifdef RT_USB_DEVICE_COMPOSITE
WINUSB_INTF_STR_INDEX,
#else
0x00, //iInterface;
#endif
},
/*endpoint descriptor*/
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_OUT,
USB_EP_ATTR_BULK,
USB_DYNAMIC,
0x00,
},
/*endpoint descriptor*/
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_IN,
USB_EP_ATTR_BULK,
USB_DYNAMIC,
0x00,
},
};
rt_align(4)
const static char* _ustring[] =
{
"Language",
"RT-Thread Team.",
"RTT Win USB",
"32021919830108",
"Configuration",
"Interface",
USB_STRING_OS//must be
};
rt_align(4)
struct usb_os_proerty winusb_proerty[] =
{
USB_OS_PROPERTY_DESC(USB_OS_PROPERTY_TYPE_REG_SZ,"DeviceInterfaceGUID",RT_WINUSB_GUID),
};
rt_align(4)
struct usb_os_function_comp_id_descriptor winusb_func_comp_id_desc =
{
.bFirstInterfaceNumber = USB_DYNAMIC,
.reserved1 = 0x01,
.compatibleID = {'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00},
.subCompatibleID = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.reserved2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
{
winusb_device_t winusb_device = (winusb_device_t)func->user_data;
if(winusb_device->parent.rx_indicate != RT_NULL)
{
winusb_device->parent.rx_indicate(&winusb_device->parent, size);
}
return RT_EOK;
}
static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
{
winusb_device_t winusb_device = (winusb_device_t)func->user_data;
if(winusb_device->parent.tx_complete != RT_NULL)
{
winusb_device->parent.tx_complete(&winusb_device->parent, winusb_device->ep_in->buffer);
}
return RT_EOK;
}
static ufunction_t cmd_func = RT_NULL;
static rt_err_t _ep0_cmd_handler(udevice_t device, rt_size_t size)
{
winusb_device_t winusb_device;
if(cmd_func != RT_NULL)
{
winusb_device = (winusb_device_t)cmd_func->user_data;
cmd_func = RT_NULL;
if(winusb_device->cmd_handler != RT_NULL)
{
winusb_device->cmd_handler(winusb_device->cmd_buff,size);
}
}
dcd_ep0_send_status(device->dcd);
return RT_EOK;
}
static rt_err_t _ep0_cmd_read(ufunction_t func, ureq_t setup)
{
winusb_device_t winusb_device = (winusb_device_t)func->user_data;
cmd_func = func;
rt_usbd_ep0_read(func->device,winusb_device->cmd_buff,setup->wLength,_ep0_cmd_handler);
return RT_EOK;
}
static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
{
switch(setup->bRequest)
{
case 'A':
switch(setup->wIndex)
{
case 0x05:
usbd_os_proerty_descriptor_send(func,setup,winusb_proerty,sizeof(winusb_proerty)/sizeof(winusb_proerty[0]));
break;
}
break;
case 0x0A://customer
_ep0_cmd_read(func, setup);
break;
}
return RT_EOK;
}
static rt_err_t _function_enable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
return RT_EOK;
}
static rt_err_t _function_disable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
return RT_EOK;
}
static struct ufunction_ops ops =
{
_function_enable,
_function_disable,
RT_NULL,
};
static rt_err_t _winusb_descriptor_config(winusb_desc_t winusb, rt_uint8_t cintf_nr, rt_uint8_t device_is_hs)
{
#ifdef RT_USB_DEVICE_COMPOSITE
winusb->iad_desc.bFirstInterface = cintf_nr;
#endif
winusb->ep_out_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
winusb->ep_in_desc.wMaxPacketSize = device_is_hs ? 512 : 64;
winusb_func_comp_id_desc.bFirstInterfaceNumber = cintf_nr;
return RT_EOK;
}
static rt_ssize_t win_usb_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
if(((ufunction_t)dev->user_data)->device->state != USB_STATE_CONFIGURED)
{
return 0;
}
winusb_device_t winusb_device = (winusb_device_t)dev;
winusb_device->ep_out->buffer = buffer;
winusb_device->ep_out->request.buffer = buffer;
winusb_device->ep_out->request.size = size;
winusb_device->ep_out->request.req_type = UIO_REQUEST_READ_FULL;
rt_usbd_io_request(((ufunction_t)dev->user_data)->device,winusb_device->ep_out,&winusb_device->ep_out->request);
return size;
}
static rt_ssize_t win_usb_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
if(((ufunction_t)dev->user_data)->device->state != USB_STATE_CONFIGURED)
{
return 0;
}
winusb_device_t winusb_device = (winusb_device_t)dev;
winusb_device->ep_in->buffer = (void *)buffer;
winusb_device->ep_in->request.buffer = winusb_device->ep_in->buffer;
winusb_device->ep_in->request.size = size;
winusb_device->ep_in->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(((ufunction_t)dev->user_data)->device,winusb_device->ep_in,&winusb_device->ep_in->request);
return size;
}
static rt_err_t win_usb_control(rt_device_t dev, int cmd, void *args)
{
winusb_device_t winusb_device = (winusb_device_t)dev;
if(RT_DEVICE_CTRL_CONFIG == cmd)
{
winusb_device->cmd_handler = (void(*)(rt_uint8_t*,rt_size_t))args;
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops winusb_device_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
win_usb_read,
win_usb_write,
win_usb_control,
};
#endif
static rt_err_t rt_usb_winusb_init(ufunction_t func)
{
winusb_device_t winusb_device = (winusb_device_t)func->user_data;
winusb_device->parent.type = RT_Device_Class_Miscellaneous;
#ifdef RT_USING_DEVICE_OPS
winusb_device->parent.ops = &winusb_device_ops;
#else
winusb_device->parent.init = RT_NULL;
winusb_device->parent.open = RT_NULL;
winusb_device->parent.close = RT_NULL;
winusb_device->parent.read = win_usb_read;
winusb_device->parent.write = win_usb_write;
winusb_device->parent.control = win_usb_control;
#endif
winusb_device->parent.user_data = func;
return rt_device_register(&winusb_device->parent, "winusb", RT_DEVICE_FLAG_RDWR);
}
ufunction_t rt_usbd_function_winusb_create(udevice_t device)
{
ufunction_t func;
winusb_device_t winusb_device;
uintf_t winusb_intf;
ualtsetting_t winusb_setting;
winusb_desc_t winusb_desc;
/* parameter check */
RT_ASSERT(device != RT_NULL);
/* set usb device string description */
#ifdef RT_USB_DEVICE_COMPOSITE
rt_usbd_device_set_interface_string(device, WINUSB_INTF_STR_INDEX, _ustring[2]);
#else
rt_usbd_device_set_string(device, _ustring);
#endif
/* create a cdc function */
func = rt_usbd_function_new(device, &dev_desc, &ops);
rt_usbd_device_set_qualifier(device, &dev_qualifier);
/* allocate memory for cdc vcom data */
winusb_device = (winusb_device_t)rt_malloc(sizeof(struct winusb_device));
if (winusb_device == NULL)
return RT_NULL;
rt_memset((void *)winusb_device, 0, sizeof(struct winusb_device));
func->user_data = (void*)winusb_device;
/* create an interface object */
winusb_intf = rt_usbd_interface_new(device, _interface_handler);
/* create an alternate setting object */
winusb_setting = rt_usbd_altsetting_new(sizeof(struct winusb_descriptor));
/* config desc in alternate setting */
rt_usbd_altsetting_config_descriptor(winusb_setting, &_winusb_desc, (rt_off_t)&((winusb_desc_t)0)->intf_desc);
/* configure the hid interface descriptor */
_winusb_descriptor_config(winusb_setting->desc, winusb_intf->intf_num, device->dcd->device_is_hs);
/* create endpoint */
winusb_desc = (winusb_desc_t)winusb_setting->desc;
winusb_device->ep_out = rt_usbd_endpoint_new(&winusb_desc->ep_out_desc, _ep_out_handler);
winusb_device->ep_in = rt_usbd_endpoint_new(&winusb_desc->ep_in_desc, _ep_in_handler);
/* add the int out and int in endpoint to the alternate setting */
rt_usbd_altsetting_add_endpoint(winusb_setting, winusb_device->ep_out);
rt_usbd_altsetting_add_endpoint(winusb_setting, winusb_device->ep_in);
/* add the alternate setting to the interface, then set default setting */
rt_usbd_interface_add_altsetting(winusb_intf, winusb_setting);
rt_usbd_set_altsetting(winusb_intf, 0);
/* add the interface to the mass storage function */
rt_usbd_function_add_interface(func, winusb_intf);
rt_usbd_os_comp_id_desc_add_os_func_comp_id_desc(device->os_comp_id_desc, &winusb_func_comp_id_desc);
/* initilize winusb */
rt_usb_winusb_init(func);
return func;
}
struct udclass winusb_class =
{
.rt_usbd_function_create = rt_usbd_function_winusb_create
};
int rt_usbd_winusb_class_register(void)
{
rt_usbd_class_register(&winusb_class);
return 0;
}
INIT_PREV_EXPORT(rt_usbd_winusb_class_register);

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-11-16 ZYH first version
*/
#ifndef __WINUSB_H__
#define __WINUSB_H__
#include <rtthread.h>
struct winusb_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct uendpoint_descriptor ep_out_desc;
struct uendpoint_descriptor ep_in_desc;
};
typedef struct winusb_descriptor* winusb_desc_t;
#endif

View File

@ -0,0 +1,164 @@
/*
* File : hid.c
* COPYRIGHT (C) 2006 - 2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-10-02 Yi Qiu first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <rtservice.h>
#ifdef RT_USING_USB_DEVICE
#define USB_DEVICE_CONTROLLER_NAME "usbd"
#ifdef RT_USB_DEVICE_COMPOSITE
const static char* ustring[] =
{
"Language",
"RT-Thread Team.",
"RTT Composite Device",
"320219198301",
"Configuration",
"Interface",
USB_STRING_OS
};
static struct udevice_descriptor compsit_desc =
{
USB_DESC_LENGTH_DEVICE, //bLength;
USB_DESC_TYPE_DEVICE, //type;
USB_BCD_VERSION, //bcdUSB;
USB_CLASS_MISC, //bDeviceClass;
0x02, //bDeviceSubClass;
0x01, //bDeviceProtocol;
0x40, //bMaxPacketSize0;
_VENDOR_ID, //idVendor;
_PRODUCT_ID, //idProduct;
USB_BCD_DEVICE, //bcdDevice;
USB_STRING_MANU_INDEX, //iManufacturer;
USB_STRING_PRODUCT_INDEX, //iProduct;
USB_STRING_SERIAL_INDEX, //iSerialNumber;
USB_DYNAMIC, //bNumConfigurations;
};
//FS and HS needed
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier), //bLength
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
0x0200, //bcdUSB
USB_CLASS_MISC, //bDeviceClass
0x02, //bDeviceSubClass
0x01, //bDeviceProtocol
64, //bMaxPacketSize0
0x01, //bNumConfigurations
0,
};
#endif
struct usb_os_comp_id_descriptor usb_comp_id_desc =
{
//head section
{
USB_DYNAMIC,
0x0100,
0x04,
USB_DYNAMIC,
{0x00,0x00,0x00,0x00,0x00,0x00,0x00},
},
};
static rt_list_t class_list;
int rt_usbd_class_list_init(void)
{
rt_list_init(&class_list);
return 0;
}
INIT_BOARD_EXPORT(rt_usbd_class_list_init);
rt_err_t rt_usbd_class_register(udclass_t udclass)
{
#ifndef RT_USB_DEVICE_COMPOSITE
if(!rt_list_isempty(&class_list))
{
rt_kprintf("[D/USBD] If you want to use usb composite device please define RT_USB_DEVICE_COMPOSITE\n");
return -RT_ERROR;
}
#endif
rt_list_insert_before(&class_list,&udclass->list);
return RT_EOK;
}
rt_err_t rt_usb_device_init(void)
{
rt_device_t udc;
udevice_t udevice;
uconfig_t cfg;
ufunction_t func;
rt_list_t *i;
udclass_t udclass;
if(rt_list_isempty(&class_list))
{
rt_kprintf("[D/USBD] No class register on usb device\n");
return -RT_ERROR;
}
/* create and startup usb device thread */
rt_usbd_core_init();
/* create a device object */
udevice = rt_usbd_device_new();
udc = rt_device_find(USB_DEVICE_CONTROLLER_NAME);
if(udc == RT_NULL)
{
rt_kprintf("can't find usb device controller %s\n", USB_DEVICE_CONTROLLER_NAME);
return -RT_ERROR;
}
/* set usb controller driver to the device */
rt_usbd_device_set_controller(udevice, (udcd_t)udc);
/* create a configuration object */
cfg = rt_usbd_config_new();
rt_usbd_device_set_os_comp_id_desc(udevice, &usb_comp_id_desc);
for(i = class_list.next; i!= &class_list; i = i->next)
{
/* get a class creater */
udclass = rt_list_entry(i, struct udclass, list);
/* create a function object */
func = udclass->rt_usbd_function_create(udevice);
/* add the function to the configuration */
rt_usbd_config_add_function(cfg, func);
}
/* set device descriptor to the device */
#ifdef RT_USB_DEVICE_COMPOSITE
rt_usbd_device_set_descriptor(udevice, &compsit_desc);
rt_usbd_device_set_string(udevice, ustring);
if(udevice->dcd->device_is_hs)
{
rt_usbd_device_set_qualifier(udevice, &dev_qualifier);
}
#else
rt_usbd_device_set_descriptor(udevice, func->dev_desc);
#endif
/* add the configuration to the device */
rt_usbd_device_add_config(udevice, cfg);
/* initialize usb device controller */
rt_device_init(udc);
/* set default configuration to 1 */
rt_usbd_set_config(udevice, 1);
return RT_EOK;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
Import('RTT_ROOT')
from building import *
cwd = GetCurrentDir()
src = Split("""
core/usbhost_core.c
core/driver.c
core/usbhost.c
core/hub.c
""")
if GetDepend('RT_USBH_ADK'):
src += Glob('class/adk.c')
src += Glob('class/adkapp.c')
if GetDepend('RT_USBH_MSTORAGE'):
src += Glob('class/mass.c')
src += Glob('class/udisk.c')
if GetDepend('RT_USBH_HID'):
src += Glob('class/hid.c')
if GetDepend('RT_USBH_HID_MOUSE'):
src += Glob('class/umouse.c')
if GetDepend('RT_USBH_HID_KEYBOARD'):
src += Glob('class/ukbd.c')
CPPPATH = [cwd, cwd + '/class', cwd + '/core', \
cwd + '/include', cwd + '../../../include']
group = DefineGroup('rt_usbh', src, depend = ['RT_USING_USB_HOST'], CPPPATH = CPPPATH)
Return('group')

View File

@ -0,0 +1,426 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#include <rtthread.h>
#include <drivers/usb_host.h>
#include "adk.h"
#ifdef RT_USBH_ADK
#define DBG_TAG "usbhost.adk"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
static struct uclass_driver adk_driver;
static const char* _adk_manufacturer = RT_NULL;
static const char* _adk_model = RT_NULL;
static const char* _adk_description = RT_NULL;
static const char* _adk_version = RT_NULL;
static const char* _adk_uri = RT_NULL;
static const char* _adk_serial = RT_NULL;
rt_err_t rt_usbh_adk_set_string(const char* manufacturer, const char* model,
const char* description, const char* _version, const char* uri,
const char* serial)
{
_adk_manufacturer = manufacturer;
_adk_model = model;
_adk_description = description;
_adk_version = _version;
_adk_uri = uri;
_adk_serial = serial;
return RT_EOK;
}
#ifdef RT_USING_MODULE
#include <rtm.h>
RTM_EXPORT(rt_usbh_adk_set_string);
#endif
/**
* This function will do USB_REQ_GET_PROTOCOL request to set idle period to the usb adk device
*
* @param intf the interface instance.
* @duration the idle period of requesting data.
* @report_id the report id
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_adk_get_protocol(struct uintf* intf, rt_uint16_t *protocol)
{
struct urequest setup;
uinst_t device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_VENDOR |
USB_REQ_TYPE_DEVICE;
setup.request = USB_REQ_GET_PROTOCOL;
setup.index = 0;
setup.length = 2;
setup.value = 0;
if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, (void*)protocol, 2,
timeout) == 0) return RT_EOK;
else return -RT_FALSE;
}
/**
* This function will do USB_REQ_SEND_STRING request to set idle period to the usb adk device
*
* @param intf the interface instance.
* @duration the idle period of requesting data.
* @report_id the report id
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_adk_send_string(struct uintf* intf, rt_uint16_t index,
const char* str)
{
struct urequest setup;
uinst_t device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_VENDOR |
USB_REQ_TYPE_DEVICE;
setup.request = USB_REQ_SEND_STRING;
setup.index = index;
setup.length = rt_strlen(str) + 1;
setup.value = 0;
if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, (void*)str,
rt_strlen(str) + 1, timeout) == 0) return RT_EOK;
else return -RT_FALSE;
}
/**
* This function will do USB_REQ_START request to set idle period to the usb adk device
*
* @param intf the interface instance.
* @duration the idle period of requesting data.
* @report_id the report id
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_adk_start(struct uintf* intf)
{
struct urequest setup;
uinst_t device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_VENDOR |
USB_REQ_TYPE_DEVICE;
setup.request = USB_REQ_START;
setup.index = 0;
setup.length = 0;
setup.value = 0;
if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, RT_NULL, 0,
timeout) == 0) return RT_EOK;
else return -RT_FALSE;
}
/**
* This function will read data from usb adk device
*
* @param intf the interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_ssize_t rt_usbh_adk_read(rt_device_t device, rt_off_t pos, void* buffer,
rt_size_t size)
{
uadk_t adk;
rt_size_t length;
struct uintf* intf;
/* check parameter */
RT_ASSERT(device != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
intf = (struct uintf*)device->user_data;
adk = (uadk_t)intf->user_data;
length = rt_usb_hcd_bulk_xfer(intf->device->hcd, adk->pipe_in,
buffer, size, 300);
return length;
}
/**
* This function will write data to usb adk device
*
* @param intf the interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_ssize_t rt_usbh_adk_write (rt_device_t device, rt_off_t pos, const void* buffer,
rt_size_t size)
{
uadk_t adk;
rt_size_t length;
struct uintf* intf;
RT_ASSERT(buffer != RT_NULL);
intf = (struct uintf*)device->user_data;
adk = (uadk_t)intf->user_data;
length = rt_usb_hcd_bulk_xfer(intf->device->hcd, adk->pipe_out,
(void*)buffer, size, 300);
return length;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops adk_device_ops =
{
RT_NULL;
RT_NULL;
RT_NULL;
rt_usbh_adk_read;
rt_usbh_adk_write;
RT_NULL;
};
#endif
/**
* This function will run adk class driver when usb device is detected and identified
* as a adk class device, it will continue the enumulate process.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_adk_enable(void* arg)
{
int i = 0;
uadk_t adk;
struct uintf* intf = (struct uintf*)arg;
udev_desc_t dev_desc;
rt_uint16_t protocol;
rt_err_t ret;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
LOG_D("rt_usbh_adk_run");
dev_desc = &intf->device->dev_desc;
if(dev_desc->idVendor == USB_ACCESSORY_VENDOR_ID &&
(dev_desc->idProduct == USB_ACCESSORY_PRODUCT_ID ||
dev_desc->idProduct == USB_ACCESSORY_ADB_PRODUCT_ID))
{
if(intf->intf_desc->bInterfaceSubClass != 0xFF) return -RT_ERROR;
LOG_D("found android accessory device");
}
else
{
LOG_D("switch device");
if((ret = rt_usbh_adk_get_protocol(intf, &protocol)) != RT_EOK)
{
rt_kprintf("rt_usbh_adk_get_protocol failed\n");
return ret;
}
if(protocol != 1)
{
rt_kprintf("read protocol failed\n");
return -RT_ERROR;
}
rt_usbh_adk_send_string(intf,
ACCESSORY_STRING_MANUFACTURER, _adk_manufacturer);
rt_usbh_adk_send_string(intf,
ACCESSORY_STRING_MODEL, _adk_model);
rt_usbh_adk_send_string(intf,
ACCESSORY_STRING_DESCRIPTION, _adk_description);
rt_usbh_adk_send_string(intf,
ACCESSORY_STRING_VERSION, _adk_version);
rt_usbh_adk_send_string(intf,
ACCESSORY_STRING_URI, _adk_uri);
rt_usbh_adk_send_string(intf,
ACCESSORY_STRING_SERIAL, _adk_serial);
LOG_D("manufacturer %s", _adk_manufacturer);
LOG_D("model %s", _adk_model);
LOG_D("description %s", _adk_description);
LOG_D("version %s", _adk_version);
LOG_D("uri %s", _adk_uri);
LOG_D("serial %s", _adk_serial);
if((ret = rt_usbh_adk_start(intf)) != RT_EOK)
{
rt_kprintf("rt_usbh_adk_start failed\n");
return ret;
}
return RT_EOK;
}
adk = rt_malloc(sizeof(struct uadkinst));
RT_ASSERT(adk != RT_NULL);
/* initilize the data structure */
rt_memset(adk, 0, sizeof(struct uadkinst));
intf->user_data = (void*)adk;
for(i=0; i<intf->intf_desc->bNumEndpoints; i++)
{
uep_desc_t ep_desc;
/* get endpoint descriptor from interface descriptor */
rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc);
if(ep_desc == RT_NULL)
{
rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
return -RT_ERROR;
}
/* the endpoint type of adk class should be BULK */
if((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
continue;
/* allocate pipes according to the endpoint type */
if(ep_desc->bEndpointAddress & USB_DIR_IN)
{
/* allocate an in pipe for the adk instance */
ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &adk->pipe_in,
intf, ep_desc, RT_NULL);
if(ret != RT_EOK) return ret;
}
else
{
/* allocate an output pipe for the adk instance */
ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &adk->pipe_out,
intf, ep_desc, RT_NULL);
if(ret != RT_EOK) return ret;
}
}
/* check pipes infomation */
if(adk->pipe_in == RT_NULL || adk->pipe_out == RT_NULL)
{
rt_kprintf("pipe error, unsupported device\n");
return -RT_ERROR;
}
/* set configuration */
ret = rt_usbh_set_configure(intf->device, 1);
if(ret != RT_EOK) return ret;
/* register adk device */
adk->device.type = RT_Device_Class_Char;
#ifdef RT_USING_DEVICE_OPS
adk->device.ops = &adk_device_ops;
#else
adk->device.init = RT_NULL;
adk->device.open = RT_NULL;
adk->device.close = RT_NULL;
adk->device.read = rt_usbh_adk_read;
adk->device.write = rt_usbh_adk_write;
adk->device.control = RT_NULL;
#endif
adk->device.user_data = (void*)intf;
rt_device_register(&adk->device, "adkdev", RT_DEVICE_FLAG_RDWR);
return RT_EOK;
}
/**
* This function will be invoked when usb device plug out is detected and it would clean
* and release all hub class related resources.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_adk_disable(void* arg)
{
uadk_t adk;
struct uintf* intf = (struct uintf*)arg;
RT_ASSERT(intf != RT_NULL);
LOG_D("rt_usbh_adk_stop");
adk = (uadk_t)intf->user_data;
if(adk == RT_NULL)
{
rt_free(intf);
return RT_EOK;
}
if(adk->pipe_in != RT_NULL)
rt_usb_hcd_free_pipe(intf->device->hcd, adk->pipe_in);
if(adk->pipe_out != RT_NULL)
rt_usb_hcd_free_pipe(intf->device->hcd, adk->pipe_out);
/* unregister adk device */
rt_device_unregister(&adk->device);
/* free adk instance */
if(adk != RT_NULL)
{
rt_free(adk);
}
/* free interface instance */
rt_free(intf);
return RT_EOK;
}
/**
* This function will register adk class driver to the usb class driver manager.
* and it should be invoked in the usb system initialization.
*
* @return the error code, RT_EOK on successfully.
*/
ucd_t rt_usbh_class_driver_adk(void)
{
adk_driver.class_code = USB_CLASS_ADK;
adk_driver.enable = rt_usbh_adk_enable;
adk_driver.disable = rt_usbh_adk_disable;
return &adk_driver;
}
#endif

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#ifndef __ADK_H__
#define __ADK_H__
#include <rtthread.h>
struct uadkinst
{
upipe_t pipe_in;
upipe_t pipe_out;
struct rt_device device;
};
typedef struct uadkinst* uadk_t;
#define USB_ACCESSORY_VENDOR_ID 0x18D1
#define USB_ACCESSORY_PRODUCT_ID 0x2D00
#define USB_ACCESSORY_ADB_PRODUCT_ID 0x2D01
#define ACCESSORY_STRING_MANUFACTURER 0
#define ACCESSORY_STRING_MODEL 1
#define ACCESSORY_STRING_DESCRIPTION 2
#define ACCESSORY_STRING_VERSION 3
#define ACCESSORY_STRING_URI 4
#define ACCESSORY_STRING_SERIAL 5
#define USB_REQ_GET_PROTOCOL 51
#define USB_REQ_SEND_STRING 52
#define USB_REQ_START 53
#define USB_CLASS_ADK 0xff
#endif

View File

@ -0,0 +1,410 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
* 2021-02-23 Leslie Lee update with current usb api
*/
#include <rtthread.h>
#include <drivers/usb_host.h>
#include "hid.h"
#ifdef RT_USBH_HID
#define DBG_TAG "usbhost.hid"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
static struct uclass_driver hid_driver;
static rt_list_t _protocal_list;
/**
* This function will do USB_REQ_SET_IDLE request to set idle period to the usb hid device
*
* @param intf the interface instance.
* @duration the idle period of requesting data.
* @report_id the report id
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hid_set_idle(struct uhintf* intf, int duration, int report_id)
{
struct urequest setup;
struct uinstance* device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_SET_IDLE;
setup.wIndex = 0;
setup.wLength = 0;
setup.wValue = (duration << 8 )| report_id;
if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
return RT_EOK;
return -RT_FALSE;
}
/**
* This function will do USB_REQ_GET_REPORT request to get report from the usb hid device
*
* @param intf the interface instance.
* @buffer the data buffer to save usb report descriptor.
* @param nbytes the size of buffer
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hid_get_report(struct uhintf* intf, rt_uint8_t type,
rt_uint8_t id, rt_uint8_t *buffer, rt_size_t size)
{
struct urequest setup;
struct uinstance* device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_GET_REPORT;
setup.wIndex = intf->intf_desc->bInterfaceNumber;
setup.wLength = size;
setup.wValue = (type << 8 ) + id;
if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, size, timeout) == size)
{
if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
}
else
return -RT_FALSE;
return -RT_FALSE;
}
/**
* This function will do USB_REQ_SET_REPORT request to set report to the usb hid device
*
* @param intf the interface instance.
* @buffer the data buffer to save usb report descriptor.
* @param nbytes the size of buffer
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hid_set_report(struct uhintf* intf, rt_uint8_t *buffer, rt_size_t size)
{
struct urequest setup;
struct uinstance* device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_SET_REPORT;
setup.wIndex = intf->intf_desc->bInterfaceNumber;
setup.wLength = size;
setup.wValue = 0x02 << 8;
if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
return RT_EOK;
else
return -RT_FALSE;
}
/**
* This function will do USB_REQ_SET_PROTOCOL request to set protocal to the usb hid device.
*
* @param intf the interface instance.
* @param protocol the protocol id.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hid_set_protocal(struct uhintf* intf, int protocol)
{
struct urequest setup;
struct uinstance* device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_SET_PROTOCOL;
setup.wIndex = 0;
setup.wLength = 0;
setup.wValue = protocol;
if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
return RT_EOK;
else
return -RT_FALSE;
}
/**
* This function will do USB_REQ_GET_DESCRIPTOR request for the device instance
* to set feature of the hub port.
*
* @param intf the interface instance.
* @buffer the data buffer to save usb report descriptor.
* @param nbytes the size of buffer
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hid_get_report_descriptor(struct uhintf* intf,
rt_uint8_t *buffer, rt_size_t size)
{
struct urequest setup;
struct uinstance* device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
device = intf->device;
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD|
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_GET_DESCRIPTOR;
setup.wIndex = 0;
setup.wLength = size;
setup.wValue = USB_DESC_TYPE_REPORT << 8;
if (rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, size, timeout) == size)
{
if (rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
}
else
return -RT_FALSE;
return -RT_FALSE;
}
/**
* This function will register specified hid protocal to protocal list
*
* @param protocal the specified protocal.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hid_protocal_register(uprotocal_t protocal)
{
RT_ASSERT(protocal != RT_NULL);
if (protocal == RT_NULL) return -RT_ERROR;
/* insert class driver into driver list */
rt_list_insert_after(&_protocal_list, &(protocal->list));
return RT_EOK;
}
/**
* This function is the callback function of hid's int endpoint, it is invoked when data comes.
*
* @param context the context of the callback function.
*
* @return none.
*/
static void rt_usbh_hid_callback(void* context)
{
upipe_t pipe;
struct uhid* hid;
int timeout = USB_TIMEOUT_LONG;
/* parameter check */
RT_ASSERT(context != RT_NULL);
pipe = (upipe_t)context;
hid = (struct uhid*)((struct uhintf*)pipe->inst)->user_data;
/* invoke protocal callback function */
hid->protocal->callback((void*)hid);
/* parameter check */
RT_ASSERT(((struct uhintf*)pipe->inst)->device->hcd != RT_NULL);
rt_usb_hcd_pipe_xfer(((struct uhintf*)pipe->inst)->device->hcd, pipe,
hid->buffer, pipe->ep.wMaxPacketSize, timeout);
}
/**
* This function will find specified hid protocal from protocal list
*
* @param pro_id the protocal id.
*
* @return the found protocal or RT_NULL if there is no this protocal.
*/
static uprotocal_t rt_usbh_hid_protocal_find(int pro_id)
{
struct rt_list_node *node;
/* try to find protocal object */
for (node = _protocal_list.next; node != &_protocal_list; node = node->next)
{
uprotocal_t protocal =
(uprotocal_t)rt_list_entry(node, struct uprotocal, list);
if (protocal->pro_id == pro_id) return protocal;
}
/* not found */
return RT_NULL;
}
/**
* This function will run hid class driver when usb device is detected and identified
* as a hid class device, it will continue the enumulate process.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_hid_enable(void* arg)
{
int i = 0, pro_id;
uprotocal_t protocal;
struct uhid* hid;
struct uhintf* intf = (struct uhintf*)arg;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
pro_id = intf->intf_desc->bInterfaceProtocol;
LOG_D("HID device enable, protocal id %d", pro_id);
protocal = rt_usbh_hid_protocal_find(pro_id);
if(protocal == RT_NULL)
{
rt_kprintf("can't find hid protocal %d\n", pro_id);
intf->user_data = RT_NULL;
return -RT_ERROR;
}
hid = rt_malloc(sizeof(struct uhid));
RT_ASSERT(hid != RT_NULL);
/* initilize the data structure */
rt_memset(hid, 0, sizeof(struct uhid));
intf->user_data = (void*)hid;
hid->protocal = protocal;
for(i=0; i<intf->intf_desc->bNumEndpoints; i++)
{
rt_err_t ret;
uep_desc_t ep_desc;
/* get endpoint descriptor */
rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc);
if(ep_desc == RT_NULL)
{
rt_kprintf("rt_usbh_get_endpoint_descriptor error\n");
return -RT_ERROR;
}
if(USB_EP_ATTR(ep_desc->bmAttributes) != USB_EP_ATTR_INT)
continue;
if(!(ep_desc->bEndpointAddress & USB_DIR_IN)) continue;
ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &hid->pipe_in,
intf->device, ep_desc);
if(ret != RT_EOK) return ret;
}
/* initialize hid protocal */
hid->protocal->init((void*)intf);
return RT_EOK;
}
/**
* This function will be invoked when usb device plug out is detected and it would clean
* and release all hub class related resources.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_hid_disable(void* arg)
{
struct uhid* hid;
struct uhintf* intf = (struct uhintf*)arg;
RT_ASSERT(intf != RT_NULL);
LOG_D("rt_usbh_hid_disable");
hid = (struct uhid*)intf->user_data;
if(hid != RT_NULL)
{
if(hid->pipe_in != RT_NULL)
{
/* free the HID in pipe */
rt_usb_hcd_free_pipe(intf->device->hcd, hid->pipe_in);
}
/* free the hid instance */
rt_free(hid);
}
return RT_EOK;
}
/**
* This function will register hid class driver to the usb class driver manager.
* and it should be invoked in the usb system initialization.
*
* @return the error code, RT_EOK on successfully.
*/
ucd_t rt_usbh_class_driver_hid(void)
{
rt_list_init(&_protocal_list);
hid_driver.class_code = USB_CLASS_HID;
hid_driver.enable = rt_usbh_hid_enable;
hid_driver.disable = rt_usbh_hid_disable;
return &hid_driver;
}
#endif

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
* 2011-12-12 Yi Qiu first version
*/
#ifndef __HID_H__
#define __HID_H__
#include <rtthread.h>
struct uhid
{
upipe_t pipe_in;
rt_uint8_t buffer[8];
uprotocal_t protocal;
};
typedef struct uhid uhid_t;
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_GET_IDLE 0x02
#define USB_REQ_GET_PROTOCOL 0x03
#define USB_REQ_SET_REPORT 0x09
#define USB_REQ_SET_IDLE 0x0a
#define USB_REQ_SET_PROTOCOL 0x0b
#define USB_HID_KEYBOARD 1
#define USB_HID_MOUSE 2
rt_err_t rt_usbh_hid_set_idle(struct uhintf* intf, int duration, int report_id);
rt_err_t rt_usbh_hid_get_report(struct uhintf* intf, rt_uint8_t type, rt_uint8_t id, rt_uint8_t *buffer, rt_size_t size);
rt_err_t rt_usbh_hid_set_report(struct uhintf* intf, rt_uint8_t *buffer, rt_size_t size);
rt_err_t rt_usbh_hid_set_protocal(struct uhintf* intf, int protocol);
rt_err_t rt_usbh_hid_get_report_descriptor(struct uhintf* intf, rt_uint8_t *buffer, rt_size_t size);
rt_err_t rt_usbh_hid_protocal_register(uprotocal_t protocal);
#endif

View File

@ -0,0 +1,647 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#include <rtthread.h>
#include <drivers/usb_host.h>
#include "mass.h"
#ifdef RT_USBH_MSTORAGE
#define DBG_TAG "usbhost.mass"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
extern rt_err_t rt_udisk_run(struct uhintf* intf);
extern rt_err_t rt_udisk_stop(struct uhintf* intf);
static struct uclass_driver storage_driver;
/**
* This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
*
* @param intf the interface instance.
* @param max_lun the buffer to save max_lun.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t _pipe_check(struct uhintf* intf, upipe_t pipe)
{
struct uinstance* device;
rt_err_t ret;
ustor_t stor;
int size = 0;
struct ustorage_csw csw;
if(intf == RT_NULL || pipe == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
/* get usb device instance from the interface instance */
device = intf->device;
/* get storage instance from the interface instance */
stor = (ustor_t)intf->user_data;
/* check pipe status */
if(pipe->status == UPIPE_STATUS_OK) return RT_EOK;
if(pipe->status == UPIPE_STATUS_ERROR)
{
rt_kprintf("pipe status error\n");
return -RT_EIO;
}
if(pipe->status == UPIPE_STATUS_STALL)
{
/* clear the pipe stall status */
ret = rt_usbh_clear_feature(device, pipe->ep.bEndpointAddress,
USB_FEATURE_ENDPOINT_HALT);
if(ret != RT_EOK) return ret;
}
rt_thread_delay(50);
rt_kprintf("pipes1 0x%x, 0x%x\n", stor->pipe_in, stor->pipe_out);
stor->pipe_in->status = UPIPE_STATUS_OK;
LOG_D("clean storage in pipe stall");
/* it should receive csw after clear the stall feature */
size = rt_usb_hcd_pipe_xfer(stor->pipe_in->inst->hcd,
stor->pipe_in, &csw, SIZEOF_CSW, 100);
if(size != SIZEOF_CSW)
{
rt_kprintf("receive the csw after stall failed\n");
return -RT_EIO;
}
return -RT_ERROR;
}
/**
* This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
*
* @param intf the interface instance.
* @param max_lun the buffer to save max_lun.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usb_bulk_only_xfer(struct uhintf* intf,
ustorage_cbw_t cmd, rt_uint8_t* buffer, int timeout)
{
rt_size_t size;
rt_err_t ret;
upipe_t pipe;
struct ustorage_csw csw;
ustor_t stor;
RT_ASSERT(cmd != RT_NULL);
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
/* get storage instance from the interface instance */
stor = (ustor_t)intf->user_data;
do
{
/* send the cbw */
size = rt_usb_hcd_pipe_xfer(stor->pipe_out->inst->hcd, stor->pipe_out,
cmd, SIZEOF_CBW, timeout);
if(size != SIZEOF_CBW)
{
rt_kprintf("CBW size error\n");
return -RT_EIO;
}
if(cmd->xfer_len != 0)
{
pipe = (cmd->dflags == CBWFLAGS_DIR_IN) ? stor->pipe_in :
stor->pipe_out;
size = rt_usb_hcd_pipe_xfer(pipe->inst->hcd, pipe, (void*)buffer,
cmd->xfer_len, timeout);
if(size != cmd->xfer_len)
{
rt_kprintf("request size %d, transfer size %d\n",
cmd->xfer_len, size);
break;
}
}
/* receive the csw */
size = rt_usb_hcd_pipe_xfer(stor->pipe_in->inst->hcd, stor->pipe_in,
&csw, SIZEOF_CSW, timeout);
if(size != SIZEOF_CSW)
{
rt_kprintf("csw size error\n");
return -RT_EIO;
}
}while(0);
/* check in pipes status */
ret = _pipe_check(intf, stor->pipe_in);
if(ret != RT_EOK)
{
rt_kprintf("in pipe error\n");
return ret;
}
/* check out pipes status */
ret = _pipe_check(intf, stor->pipe_out);
if(ret != RT_EOK)
{
rt_kprintf("out pipe error\n");
return ret;
}
/* check csw status */
if(csw.signature != CSW_SIGNATURE || csw.tag != CBW_TAG_VALUE)
{
rt_kprintf("csw signature error\n");
return -RT_EIO;
}
if(csw.status != 0)
{
//rt_kprintf("csw status error:%d\n",csw.status);
return -RT_ERROR;
}
return RT_EOK;
}
/**
* This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
*
* @param intf the interface instance.
* @param max_lun the buffer to save max_lun.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_get_max_lun(struct uhintf* intf, rt_uint8_t* max_lun)
{
struct uinstance* device;
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
/* parameter check */
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_get_max_lun");
/* get usb device instance from the interface instance */
device = intf->device;
/* construct the request */
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USBREQ_GET_MAX_LUN;
setup.wValue = intf->intf_desc->bInterfaceNumber;
setup.wIndex = 0;
setup.wLength = 1;
/* do control transfer request */
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
{
return -RT_EIO;
}
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, max_lun, 1, timeout) != 1)
{
return -RT_EIO;
}
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) != 0)
{
return -RT_EIO;
}
return RT_EOK;
}
/**
* This function will do USBREQ_MASS_STORAGE_RESET request for the usb interface instance.
*
* @param intf the interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_reset(struct uhintf* intf)
{
struct urequest setup;
struct uinstance* device;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_reset");
/* get usb device instance from the interface instance */
device = intf->device;
/* construct the request */
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USBREQ_MASS_STORAGE_RESET;
setup.wIndex = intf->intf_desc->bInterfaceNumber;
setup.wLength = 0;
setup.wValue = 0;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
{
return -RT_EIO;
}
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
{
return -RT_EIO;
}
return RT_EOK;
}
/**
* This function will execute SCSI_READ_10 command to read data from the usb device.
*
* @param intf the interface instance.
* @param buffer the data buffer to save read data
* @param sector the start sector address to read.
* @param sector the sector count to read.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_read10(struct uhintf* intf, rt_uint8_t *buffer,
rt_uint32_t sector, rt_size_t count, int timeout)
{
struct ustorage_cbw cmd;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_read10");
/* construct the command block wrapper */
rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
cmd.signature = CBW_SIGNATURE;
cmd.tag = CBW_TAG_VALUE;
cmd.xfer_len = SECTOR_SIZE * count;
cmd.dflags = CBWFLAGS_DIR_IN;
cmd.lun = 0;
cmd.cb_len = 10;
cmd.cb[0] = SCSI_READ_10;
cmd.cb[1] = 0;
cmd.cb[2] = (rt_uint8_t)(sector >> 24);
cmd.cb[3] = (rt_uint8_t)(sector >> 16);
cmd.cb[4] = (rt_uint8_t)(sector >> 8);
cmd.cb[5] = (rt_uint8_t)sector;
cmd.cb[6] = 0;
cmd.cb[7] = (count & 0xff00) >> 8;
cmd.cb[8] = (rt_uint8_t) count & 0xff;
return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
}
/**
* This function will execute SCSI_WRITE_10 command to write data to the usb device.
*
* @param intf the interface instance.
* @param buffer the data buffer to save write data
* @param sector the start sector address to write.
* @param sector the sector count to write.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_write10(struct uhintf* intf, rt_uint8_t *buffer,
rt_uint32_t sector, rt_size_t count, int timeout)
{
struct ustorage_cbw cmd;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_write10");
/* construct the command block wrapper */
rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
cmd.signature = CBW_SIGNATURE;
cmd.tag = CBW_TAG_VALUE;
cmd.xfer_len = SECTOR_SIZE * count;
cmd.dflags = CBWFLAGS_DIR_OUT;
cmd.lun = 0;
cmd.cb_len = 10;
cmd.cb[0] = SCSI_WRITE_10;
cmd.cb[1] = 0;
cmd.cb[2] = (rt_uint8_t)(sector >> 24);
cmd.cb[3] = (rt_uint8_t)(sector >> 16);
cmd.cb[4] = (rt_uint8_t)(sector >> 8);
cmd.cb[5] = (rt_uint8_t)sector;
cmd.cb[6] = 0;
cmd.cb[7] = (count & 0xff00) >> 8;
cmd.cb[8] = (rt_uint8_t) count & 0xff;
return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
}
/**
* This function will execute SCSI_REQUEST_SENSE command to get sense data.
*
* @param intf the interface instance.
* @param buffer the data buffer to save sense data
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_request_sense(struct uhintf* intf, rt_uint8_t* buffer)
{
struct ustorage_cbw cmd;
int timeout = USB_TIMEOUT_LONG;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_request_sense");
/* construct the command block wrapper */
rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
cmd.signature = CBW_SIGNATURE;
cmd.tag = CBW_TAG_VALUE;
cmd.xfer_len = 18;
cmd.dflags = CBWFLAGS_DIR_IN;
cmd.lun = 0;
cmd.cb_len = 6;
cmd.cb[0] = SCSI_REQUEST_SENSE;
cmd.cb[4] = 18;
return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
}
/**
* This function will execute SCSI_TEST_UNIT_READY command to get unit ready status.
*
* @param intf the interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_test_unit_ready(struct uhintf* intf)
{
struct ustorage_cbw cmd;
int timeout = USB_TIMEOUT_LONG;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_test_unit_ready");
/* construct the command block wrapper */
rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
cmd.signature = CBW_SIGNATURE;
cmd.tag = CBW_TAG_VALUE;
cmd.xfer_len = 0;
cmd.dflags = CBWFLAGS_DIR_OUT;
cmd.lun = 0;
cmd.cb_len = 12;
cmd.cb[0] = SCSI_TEST_UNIT_READY;
return rt_usb_bulk_only_xfer(intf, &cmd, RT_NULL, timeout);
}
/**
* This function will execute SCSI_INQUIRY_CMD command to get inquiry data.
*
* @param intf the interface instance.
* @param buffer the data buffer to save inquiry data
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_inquiry(struct uhintf* intf, rt_uint8_t* buffer)
{
struct ustorage_cbw cmd;
int timeout = USB_TIMEOUT_LONG;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_inquiry");
/* construct the command block wrapper */
rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
cmd.signature = CBW_SIGNATURE;
cmd.tag = CBW_TAG_VALUE;
cmd.xfer_len = 36;
cmd.dflags = CBWFLAGS_DIR_IN;
cmd.lun = 0;
cmd.cb_len = 6;//12
cmd.cb[0] = SCSI_INQUIRY_CMD;
cmd.cb[4] = 36;
return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
}
/**
* This function will execute SCSI_READ_CAPACITY command to get capacity data.
*
* @param intf the interface instance.
* @param buffer the data buffer to save capacity data
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_storage_get_capacity(struct uhintf* intf, rt_uint8_t* buffer)
{
struct ustorage_cbw cmd;
int timeout = USB_TIMEOUT_LONG;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_get_capacity");
/* construct the command block wrapper */
rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
cmd.signature = CBW_SIGNATURE;
cmd.tag = CBW_TAG_VALUE;
cmd.xfer_len = 8;
cmd.dflags = CBWFLAGS_DIR_IN;
cmd.lun = 0;
cmd.cb_len = 12;
cmd.cb[0] = SCSI_READ_CAPACITY;
return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
}
/**
* This function will run mass storage class driver when usb device is detected
* and identified as a mass storage class device, it will continue to do the enumulate
* process.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_storage_enable(void* arg)
{
int i = 0;
rt_err_t ret;
ustor_t stor;
struct uhintf* intf = (struct uhintf*)arg;
/* parameter check */
if(intf == RT_NULL)
{
rt_kprintf("the interface is not available\n");
return -RT_EIO;
}
LOG_D("subclass %d, protocal %d",
intf->intf_desc->bInterfaceSubClass,
intf->intf_desc->bInterfaceProtocol);
LOG_D("rt_usbh_storage_run");
/* only support SCSI subclass and bulk only protocal */
stor = rt_malloc(sizeof(struct ustor));
RT_ASSERT(stor != RT_NULL);
/* initilize the data structure */
rt_memset(stor, 0, sizeof(struct ustor));
intf->user_data = (void*)stor;
for(i=0; i<intf->intf_desc->bNumEndpoints; i++)
{
uep_desc_t ep_desc;
/* get endpoint descriptor from interface descriptor */
rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc);
if(ep_desc == RT_NULL)
{
rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
return -RT_ERROR;
}
/* the endpoint type of mass storage class should be BULK */
if((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
continue;
/* allocate pipes according to the endpoint type */
if(ep_desc->bEndpointAddress & USB_DIR_IN)
{
/* alloc an in pipe for the storage instance */
stor->pipe_in = rt_usb_instance_find_pipe(intf->device,ep_desc->bEndpointAddress);
}
else
{
/* alloc an output pipe for the storage instance */
stor->pipe_out = rt_usb_instance_find_pipe(intf->device,ep_desc->bEndpointAddress);
}
}
/* check pipes infomation */
if(stor->pipe_in == RT_NULL || stor->pipe_out == RT_NULL)
{
rt_kprintf("pipe error, unsupported device\n");
return -RT_ERROR;
}
/* should implement as callback */
ret = rt_udisk_run(intf);
if(ret != RT_EOK) return ret;
return RT_EOK;
}
/**
* This function will be invoked when usb device plug out is detected and it would clean
* and release all mass storage class related resources.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_storage_disable(void* arg)
{
ustor_t stor;
struct uhintf* intf = (struct uhintf*)arg;
/* parameter check */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->user_data != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
LOG_D("rt_usbh_storage_stop");
/* get storage instance from interface instance */
stor = (ustor_t)intf->user_data;
rt_udisk_stop(intf);
/* free storage instance */
if(stor != RT_NULL) rt_free(stor);
return RT_EOK;
}
/**
* This function will register mass storage class driver to the usb class driver manager.
* and it should be invoked in the usb system initialization.
*
* @return the error code, RT_EOK on successfully.
*/
ucd_t rt_usbh_class_driver_storage(void)
{
storage_driver.class_code = USB_CLASS_MASS_STORAGE;
storage_driver.enable = rt_usbh_storage_enable;
storage_driver.disable = rt_usbh_storage_disable;
return &storage_driver;
}
#endif

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#ifndef __MASS_H__
#define __MASS_H__
#include <rtthread.h>
#include "dfs_fs.h"
#define MAX_PARTITION_COUNT 4
#define SECTOR_SIZE 512
struct ustor_data
{
struct dfs_partition part;
struct uhintf* intf;
int udisk_id;
const char path;
};
struct ustor
{
upipe_t pipe_in;
upipe_t pipe_out;
rt_uint32_t capicity[2];
struct rt_device dev[MAX_PARTITION_COUNT];
rt_uint8_t dev_cnt;
};
typedef struct ustor* ustor_t;
rt_err_t rt_usbh_storage_get_max_lun(struct uhintf* intf, rt_uint8_t* max_lun);
rt_err_t rt_usbh_storage_reset(struct uhintf* intf);
rt_err_t rt_usbh_storage_read10(struct uhintf* intf, rt_uint8_t *buffer,
rt_uint32_t sector, rt_size_t count, int timeout);
rt_err_t rt_usbh_storage_write10(struct uhintf* intf, rt_uint8_t *buffer,
rt_uint32_t sector, rt_size_t count, int timeout);
rt_err_t rt_usbh_storage_request_sense(struct uhintf* intf, rt_uint8_t* buffer);
rt_err_t rt_usbh_storage_test_unit_ready(struct uhintf* intf);
rt_err_t rt_usbh_storage_inquiry(struct uhintf* intf, rt_uint8_t* buffer);
rt_err_t rt_usbh_storage_get_capacity(struct uhintf* intf, rt_uint8_t* buffer);
#endif

View File

@ -0,0 +1,456 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#include <rtthread.h>
#include <dfs_fs.h>
#include <drivers/usb_host.h>
#include "mass.h"
#define DBG_TAG "usbhost.udisk"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#ifdef RT_USBH_MSTORAGE
#define UDISK_MAX_COUNT 8
static rt_uint8_t _udisk_idset = 0;
static int udisk_get_id(void)
{
int i;
for(i=0; i< UDISK_MAX_COUNT; i++)
{
if((_udisk_idset & (1 << i)) != 0) continue;
else break;
}
/* it should not happen */
if(i == UDISK_MAX_COUNT) RT_ASSERT(0);
_udisk_idset |= (1 << i);
return i;
}
static void udisk_free_id(int id)
{
RT_ASSERT(id < UDISK_MAX_COUNT)
_udisk_idset &= ~(1 << id);
}
/**
* This function will initialize the udisk device
*
* @param dev the pointer of device driver structure
*
* @return RT_EOK
*/
static rt_err_t rt_udisk_init(rt_device_t dev)
{
return RT_EOK;
}
/**
* This function will read some data from a device.
*
* @param dev the pointer of device driver structure
* @param pos the position of reading
* @param buffer the data buffer to save read data
* @param size the size of buffer
*
* @return the actually read size on successful, otherwise negative returned.
*/
static rt_ssize_t rt_udisk_read(rt_device_t dev, rt_off_t pos, void* buffer,
rt_size_t size)
{
rt_err_t ret;
struct uhintf* intf;
struct ustor_data* data;
int timeout = USB_TIMEOUT_LONG;
/* check parameter */
RT_ASSERT(dev != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
if(size > 4096) timeout *= 2;
data = (struct ustor_data*)dev->user_data;
intf = data->intf;
ret = rt_usbh_storage_read10(intf, (rt_uint8_t*)buffer, pos, size, timeout);
if (ret != RT_EOK)
{
rt_kprintf("usb mass_storage read failed\n");
return 0;
}
return size;
}
/**
* This function will write some data to a device.
*
* @param dev the pointer of device driver structure
* @param pos the position of written
* @param buffer the data buffer to be written to device
* @param size the size of buffer
*
* @return the actually written size on successful, otherwise negative returned.
*/
static rt_ssize_t rt_udisk_write (rt_device_t dev, rt_off_t pos, const void* buffer,
rt_size_t size)
{
rt_err_t ret;
struct uhintf* intf;
struct ustor_data* data;
int timeout = USB_TIMEOUT_LONG;
/* check parameter */
RT_ASSERT(dev != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
if(size * SECTOR_SIZE > 4096) timeout *= 2;
data = (struct ustor_data*)dev->user_data;
intf = data->intf;
ret = rt_usbh_storage_write10(intf, (rt_uint8_t*)buffer, pos, size, timeout);
if (ret != RT_EOK)
{
rt_kprintf("usb mass_storage write %d sector failed\n", size);
return 0;
}
return size;
}
/**
* This function will execute SCSI_INQUIRY_CMD command to get inquiry data.
*
* @param intf the interface instance.
* @param buffer the data buffer to save inquiry data
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_udisk_control(rt_device_t dev, int cmd, void *args)
{
ustor_t stor;
struct ustor_data* data;
/* check parameter */
RT_ASSERT(dev != RT_NULL);
data = (struct ustor_data*)dev->user_data;
stor = (ustor_t)data->intf->user_data;
if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
{
struct rt_device_blk_geometry *geometry;
geometry = (struct rt_device_blk_geometry *)args;
if (geometry == RT_NULL) return -RT_ERROR;
geometry->bytes_per_sector = SECTOR_SIZE;
geometry->block_size = stor->capicity[1];
geometry->sector_count = stor->capicity[0];
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops udisk_device_ops =
{
rt_udisk_init,
RT_NULL,
RT_NULL,
rt_udisk_read,
rt_udisk_write,
rt_udisk_control
};
#endif
/**
* This function will run udisk driver when usb disk is detected.
*
* @param intf the usb interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_udisk_run(struct uhintf* intf)
{
int i = 0;
rt_err_t ret;
char dname[8];
char sname[8];
rt_uint8_t max_lun, *sector, sense[18], inquiry[36];
struct dfs_partition part[MAX_PARTITION_COUNT];
ustor_t stor;
/* check parameter */
RT_ASSERT(intf != RT_NULL);
/* set interface */
// ret = rt_usbh_set_interface(intf->device, intf->intf_desc->bInterfaceNumber);
// if(ret != RT_EOK)
// rt_usbh_clear_feature(intf->device, 0, USB_FEATURE_ENDPOINT_HALT);
/* reset mass storage class device */
ret = rt_usbh_storage_reset(intf);
if(ret != RT_EOK) return ret;
stor = (ustor_t)intf->user_data;
/* get max logic unit number */
ret = rt_usbh_storage_get_max_lun(intf, &max_lun);
if(ret != RT_EOK)
rt_usbh_clear_feature(intf->device, 0, USB_FEATURE_ENDPOINT_HALT);
/* reset pipe in endpoint */
if(stor->pipe_in->status == UPIPE_STATUS_STALL)
{
ret = rt_usbh_clear_feature(intf->device,
stor->pipe_in->ep.bEndpointAddress, USB_FEATURE_ENDPOINT_HALT);
if(ret != RT_EOK) return ret;
}
/* reset pipe out endpoint */
if(stor->pipe_out->status == UPIPE_STATUS_STALL)
{
ret = rt_usbh_clear_feature(intf->device,
stor->pipe_out->ep.bEndpointAddress, USB_FEATURE_ENDPOINT_HALT);
if(ret != RT_EOK) return ret;
}
while((ret = rt_usbh_storage_inquiry(intf, inquiry)) != RT_EOK)
{
if(ret == -RT_EIO) return ret;
rt_thread_delay(5);
if(i++ < 10) continue;
rt_kprintf("rt_usbh_storage_inquiry error\n");
return -RT_ERROR;
}
i = 0;
/* wait device ready */
while((ret = rt_usbh_storage_test_unit_ready(intf)) != RT_EOK)
{
if(ret == -RT_EIO) return ret;
ret = rt_usbh_storage_request_sense(intf, sense);
if(ret == -RT_EIO) return ret;
rt_thread_delay(10);
if(i++ < 10) continue;
rt_kprintf("rt_usbh_storage_test_unit_ready error\n");
return -RT_ERROR;
}
i = 0;
rt_memset(stor->capicity, 0, sizeof(stor->capicity));
/* get storage capacity */
while((ret = rt_usbh_storage_get_capacity(intf,
(rt_uint8_t*)stor->capicity)) != RT_EOK)
{
if(ret == -RT_EIO) return ret;
rt_thread_delay(50);
if(i++ < 10) continue;
stor->capicity[0] = 2880;
stor->capicity[1] = 0x200;
rt_kprintf("rt_usbh_storage_get_capacity error\n");
break;
}
stor->capicity[0] = uswap_32(stor->capicity[0]);
stor->capicity[1] = uswap_32(stor->capicity[1]);
stor->capicity[0] += 1;
LOG_D("capicity %d, block size %d",
stor->capicity[0], stor->capicity[1]);
/* get the first sector to read partition table */
sector = (rt_uint8_t*) rt_malloc (SECTOR_SIZE);
if (sector == RT_NULL)
{
rt_kprintf("allocate partition sector buffer failed\n");
return -RT_ERROR;
}
rt_memset(sector, 0, SECTOR_SIZE);
LOG_D("read partition table");
/* get the partition table */
ret = rt_usbh_storage_read10(intf, sector, 0, 1, USB_TIMEOUT_LONG);
if(ret != RT_EOK)
{
rt_kprintf("read parition table error\n");
rt_free(sector);
return -RT_ERROR;
}
LOG_D("finished reading partition");
for(i=0; i<MAX_PARTITION_COUNT; i++)
{
/* get the first partition */
ret = dfs_filesystem_get_partition(&part[i], sector, i);
if (ret == RT_EOK)
{
struct ustor_data* data = rt_malloc(sizeof(struct ustor_data));
if (data == RT_NULL)
{
LOG_E("Allocate partition data buffer failed.");
continue;
}
rt_memset(data, 0, sizeof(struct ustor_data));
data->intf = intf;
data->udisk_id = udisk_get_id();
rt_snprintf(dname, 6, "ud%d-%d", data->udisk_id, i);
rt_snprintf(sname, 8, "sem_ud%d", i);
data->part.lock = rt_sem_create(sname, 1, RT_IPC_FLAG_FIFO);
/* register sdcard device */
stor->dev[i].type = RT_Device_Class_Block;
#ifdef RT_USING_DEVICE_OPS
stor->dev[i].ops = &udisk_device_ops;
#else
stor->dev[i].init = rt_udisk_init;
stor->dev[i].read = rt_udisk_read;
stor->dev[i].write = rt_udisk_write;
stor->dev[i].control = rt_udisk_control;
#endif
stor->dev[i].user_data = (void*)data;
rt_device_register(&stor->dev[i], dname, RT_DEVICE_FLAG_RDWR |
RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
stor->dev_cnt++;
if (dfs_mount(stor->dev[i].parent.name, UDISK_MOUNTPOINT, "elm",
0, 0) == 0)
{
LOG_D("udisk part %d mount successfully", i);
}
else
{
LOG_D("udisk part %d mount failed", i);
}
}
else
{
if(i == 0)
{
struct ustor_data* data = rt_malloc(sizeof(struct ustor_data));
if (data == RT_NULL)
{
LOG_E("Allocate partition data buffer failed.");
break;
}
rt_memset(data, 0, sizeof(struct ustor_data));
data->udisk_id = udisk_get_id();
/* there is no partition table */
data->part.offset = 0;
data->part.size = 0;
data->intf = intf;
data->part.lock = rt_sem_create("sem_ud", 1, RT_IPC_FLAG_FIFO);
rt_snprintf(dname, 7, "udisk%d", data->udisk_id);
/* register sdcard device */
stor->dev[0].type = RT_Device_Class_Block;
#ifdef RT_USING_DEVICE_OPS
stor->dev[i].ops = &udisk_device_ops;
#else
stor->dev[0].init = rt_udisk_init;
stor->dev[0].read = rt_udisk_read;
stor->dev[0].write = rt_udisk_write;
stor->dev[0].control = rt_udisk_control;
#endif
stor->dev[0].user_data = (void*)data;
rt_device_register(&stor->dev[0], dname,
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE
| RT_DEVICE_FLAG_STANDALONE);
stor->dev_cnt++;
if (dfs_mount(stor->dev[0].parent.name, UDISK_MOUNTPOINT,
"elm", 0, 0) == 0)
{
rt_kprintf("Mount FAT on Udisk successful.\n");
}
else
{
rt_kprintf("Mount FAT on Udisk failed.\n");
}
}
break;
}
}
rt_free(sector);
return RT_EOK;
}
/**
* This function will be invoked when usb disk plug out is detected and it would clean
* and release all udisk related resources.
*
* @param intf the usb interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_udisk_stop(struct uhintf* intf)
{
int i;
ustor_t stor;
struct ustor_data* data;
/* check parameter */
RT_ASSERT(intf != RT_NULL);
RT_ASSERT(intf->device != RT_NULL);
stor = (ustor_t)intf->user_data;
RT_ASSERT(stor != RT_NULL);
for(i=0; i<stor->dev_cnt; i++)
{
rt_device_t dev = &stor->dev[i];
data = (struct ustor_data*)dev->user_data;
/* unmount filesystem */
dfs_unmount(UDISK_MOUNTPOINT);
/* delete semaphore */
rt_sem_delete(data->part.lock);
udisk_free_id(data->udisk_id);
rt_free(data);
/* unregister device */
rt_device_unregister(&stor->dev[i]);
}
return RT_EOK;
}
#endif

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-01-03 Yi Qiu first version
*/
#include <rtthread.h>
#include <drivers/usb_host.h>
#include "hid.h"
#if defined(RT_USBH_HID) && defined(RT_USBH_HID_KEYBOARD)
#define DBG_TAG "usbhost.ukbd"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
static struct uprotocal kbd_protocal;
static rt_err_t rt_usbh_hid_kbd_callback(void* arg)
{
int int1, int2;
struct uhid* hid;
hid = (struct uhid*)arg;
int1 = *(rt_uint32_t*)hid->buffer;
int2 = *(rt_uint32_t*)(&hid->buffer[4]);
if(int1 != 0 || int2 != 0)
{
LOG_D("key down 0x%x, 0x%x", int1, int2);
}
return RT_EOK;
}
static rt_thread_t kbd_thread;
static void kbd_task(void* param)
{
struct uhintf* intf = (struct uhintf*)param;
while (1)
{
if (rt_usb_hcd_pipe_xfer(intf->device->hcd, ((struct uhid*)intf->user_data)->pipe_in,
((struct uhid*)intf->user_data)->buffer, ((struct uhid*)intf->user_data)->pipe_in->ep.wMaxPacketSize,
USB_TIMEOUT_BASIC) == 0)
{
break;
}
rt_usbh_hid_kbd_callback(intf->user_data);
}
}
static rt_err_t rt_usbh_hid_kbd_init(void* arg)
{
struct uhintf* intf = (struct uhintf*)arg;
RT_ASSERT(intf != RT_NULL);
rt_usbh_hid_set_protocal(intf, 0);
rt_usbh_hid_set_idle(intf, 10, 0);
LOG_D("start usb keyboard");
kbd_thread = rt_thread_create("kbd0", kbd_task, intf, 1024, 8, 100);
rt_thread_startup(kbd_thread);
return RT_EOK;
}
/**
* This function will define the hid keyboard protocal, it will be register to the protocal list.
*
* @return the keyboard protocal structure.
*/
uprotocal_t rt_usbh_hid_protocal_kbd(void)
{
kbd_protocal.pro_id = USB_HID_KEYBOARD;
kbd_protocal.init = rt_usbh_hid_kbd_init;
kbd_protocal.callback = rt_usbh_hid_kbd_callback;
return &kbd_protocal;
}
#endif

View File

@ -0,0 +1,190 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-01-03 Yi Qiu first version
*/
#include <rtthread.h>
#include <drivers/usb_host.h>
#include "hid.h"
#ifdef RT_USING_RTGUI
#include <rtgui/event.h>
#include <rtgui/rtgui_server.h>
#include "drv_lcd.h"
#endif
#if defined(RT_USBH_HID) && defined(RT_USBH_HID_MOUSE)
#define DBG_TAG "usbhost.umouse"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
static struct uprotocal mouse_protocal;
#ifdef RT_USING_RTGUI
#define LKEY_PRESS 0x01
#define RKEY_PRESS 0x02
#define MKEY_PRESS 0x04
#define MOUSE_SCALING 0x02
static rt_bool_t lkey_down=RT_FALSE;
//static rt_bool_t rkey_down=RT_FALSE;
//static rt_bool_t mkey_down=RT_FALSE;
static struct rtgui_event_mouse emouse;
#endif
static rt_err_t rt_usbh_hid_mouse_callback(void* arg)
{
struct uhid* hid;
#ifdef RT_USING_RTGUI
rt_uint16_t xoffset=0;
rt_uint16_t yoffset=0;
#endif
hid = (struct uhid*)arg;
LOG_D("hid 0x%x 0x%x",
*(rt_uint32_t*)hid->buffer,
*(rt_uint32_t*)(&hid->buffer[4]));
#ifdef RT_USING_RTGUI
if(hid->buffer[1]!=0)
{
if(hid->buffer[1]>127)
{
xoffset=(256-hid->buffer[1])*MOUSE_SCALING;
if(emouse.x>xoffset)
{
emouse.x-=xoffset;
}
else
{
emouse.x=0;
}
}
else
{
xoffset=(hid->buffer[1])*MOUSE_SCALING;
if((emouse.x+xoffset)<480)
{
emouse.x+=xoffset;
}
else
{
emouse.x=480;
}
}
}
if(hid->buffer[2]!=0)
{
if(hid->buffer[2]>127)
{
yoffset=(256-hid->buffer[2])*MOUSE_SCALING;
if(emouse.y>yoffset)
{
emouse.y-=yoffset;
}
else
{
emouse.y=0;
}
}
else
{
yoffset=hid->buffer[2]*MOUSE_SCALING;
if(emouse.y+yoffset<272)
{
emouse.y+=yoffset;
}
else
{
emouse.y=272;
}
}
}
if(xoffset!=0||yoffset!=0)
{
cursor_set_position(emouse.x,emouse.y);
}
if(hid->buffer[0]&LKEY_PRESS)
{
if(lkey_down==RT_FALSE)
{
// rt_kprintf("mouse left key press down\n");
emouse.button = (RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_DOWN);
rtgui_server_post_event(&emouse.parent, sizeof(struct rtgui_event_mouse));
lkey_down=RT_TRUE;
}
}
else if(lkey_down==RT_TRUE)
{
// rt_kprintf("mouse left key press up\n");
emouse.button = (RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_UP);
rtgui_server_post_event(&emouse.parent, sizeof(struct rtgui_event_mouse));
lkey_down=RT_FALSE;
}
#endif
return RT_EOK;
}
static rt_thread_t mouse_thread;
static void mouse_task(void* param)
{
struct uhintf* intf = (struct uhintf*)param;
while (1)
{
if (rt_usb_hcd_pipe_xfer(intf->device->hcd, ((struct uhid*)intf->user_data)->pipe_in,
((struct uhid*)intf->user_data)->buffer, ((struct uhid*)intf->user_data)->pipe_in->ep.wMaxPacketSize,
USB_TIMEOUT_BASIC) == 0)
{
break;
}
rt_usbh_hid_mouse_callback(intf->user_data);
}
}
static rt_err_t rt_usbh_hid_mouse_init(void* arg)
{
struct uhintf* intf = (struct uhintf*)arg;
RT_ASSERT(intf != RT_NULL);
rt_usbh_hid_set_protocal(intf, 0);
rt_usbh_hid_set_idle(intf, 0, 0);
mouse_thread = rt_thread_create("mouse0", mouse_task, intf, 1024, 8, 100);
rt_thread_startup(mouse_thread);
LOG_D("start usb mouse");
#ifdef RT_USING_RTGUI
RTGUI_EVENT_MOUSE_BUTTON_INIT(&emouse);
emouse.wid = RT_NULL;
cursor_display(RT_TRUE);
#endif
return RT_EOK;
}
/**
* This function will define the hid mouse protocal, it will be register to the protocal list.
*
* @return the keyboard protocal structure.
*/
uprotocal_t rt_usbh_hid_protocal_mouse(void)
{
mouse_protocal.pro_id = USB_HID_MOUSE;
mouse_protocal.init = rt_usbh_hid_mouse_init;
mouse_protocal.callback = rt_usbh_hid_mouse_callback;
return &mouse_protocal;
}
#endif

View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-03-12 Yi Qiu first version
* 2021-02-23 Leslie Lee provide possibility for multi usb host
*/
#include <rtthread.h>
#include <rtservice.h>
#include <drivers/usb_host.h>
static rt_list_t _driver_list;
static rt_bool_t _driver_list_created = RT_FALSE;
/**
* This function will initilize the usb class driver related data structure,
* and it should be invoked in the usb system initialization.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_class_driver_init(void)
{
if (_driver_list_created == RT_FALSE)
{
rt_list_init(&_driver_list);
_driver_list_created = RT_TRUE;
}
return RT_EOK;
}
/**
* This function will register an usb class driver to the class driver manager.
*
* @param drv the pointer of the usb class driver.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_class_driver_register(ucd_t drv)
{
if (drv == RT_NULL) return -RT_ERROR;
if (rt_usbh_class_driver_find(drv->class_code, drv->subclass_code) == RT_NULL)
{
/* insert class driver into driver list */
rt_list_insert_after(&_driver_list, &(drv->list));
}
return RT_EOK;
}
/**
* This function will removes a previously registed usb class driver.
*
* @param drv the pointer of the usb class driver structure.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_class_driver_unregister(ucd_t drv)
{
RT_ASSERT(drv != RT_NULL);
/* remove class driver from driver list */
rt_list_remove(&(drv->list));
return RT_EOK;
}
/**
* This function will run an usb class driver.
*
* @param drv the pointer of usb class driver.
* @param args the parameter of run function.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_class_driver_enable(ucd_t drv, void* args)
{
RT_ASSERT(drv != RT_NULL);
if(drv->enable != RT_NULL)
drv->enable(args);
return RT_EOK;
}
/**
* This function will stop a usb class driver.
*
* @param drv the pointer of usb class driver structure.
* @param args the argument of the stop function.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_class_driver_disable(ucd_t drv, void* args)
{
RT_ASSERT(drv != RT_NULL);
if(drv->disable != RT_NULL)
drv->disable(args);
return RT_EOK;
}
/**
* This function finds a usb class driver by specified class code and subclass code.
*
* @param class_code the usb class driver's class code.
* @param subclass_code the usb class driver's sub class code.
*
* @return the registered usb class driver on successful, or RT_NULL on failure.
*/
ucd_t rt_usbh_class_driver_find(int class_code, int subclass_code)
{
struct rt_list_node *node;
/* enter critical */
if (rt_thread_self() != RT_NULL)
rt_enter_critical();
/* try to find driver object */
for (node = _driver_list.next; node != &_driver_list; node = node->next)
{
ucd_t drv =
(ucd_t)rt_list_entry(node, struct uclass_driver, list);
if (drv->class_code == class_code)
{
/* leave critical */
if (rt_thread_self() != RT_NULL)
rt_exit_critical();
return drv;
}
}
/* leave critical */
if (rt_thread_self() != RT_NULL)
rt_exit_critical();
/* not found */
return RT_NULL;
}

View File

@ -0,0 +1,727 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
* 2021-02-23 Leslie Lee provide possibility for multi usb host
*/
#include <rtthread.h>
#include <drivers/usb_host.h>
#define USB_THREAD_STACK_SIZE 4096
#define DBG_TAG "usb.host.hub"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
// static struct rt_messagequeue *usb_mq;
static struct uclass_driver hub_driver;
// static struct uhub root_hub;
static rt_err_t root_hub_ctrl(struct uhcd *hcd, rt_uint16_t port, rt_uint8_t cmd, void *args)
{
switch(cmd)
{
case RH_GET_PORT_STATUS:
(*(rt_uint32_t *)args) = hcd->roothub->port_status[port-1];
break;
case RH_SET_PORT_STATUS:
hcd->roothub->port_status[port-1] = (*(rt_uint32_t *)args);
break;
case RH_CLEAR_PORT_FEATURE:
switch(((rt_uint32_t)args))
{
case PORT_FEAT_C_CONNECTION:
hcd->roothub->port_status[port-1] &= ~PORT_CCSC;
break;
case PORT_FEAT_C_ENABLE:
hcd->roothub->port_status[port-1] &= ~PORT_PESC;
break;
case PORT_FEAT_C_SUSPEND:
hcd->roothub->port_status[port-1] &= ~PORT_PSSC;
break;
case PORT_FEAT_C_OVER_CURRENT:
hcd->roothub->port_status[port-1] &= ~PORT_POCIC;
break;
case PORT_FEAT_C_RESET:
hcd->roothub->port_status[port-1] &= ~PORT_PRSC;
break;
}
break;
case RH_SET_PORT_FEATURE:
switch((rt_uint32_t)args)
{
case PORT_FEAT_CONNECTION:
hcd->roothub->port_status[port-1] |= PORT_CCSC;
break;
case PORT_FEAT_ENABLE:
hcd->roothub->port_status[port-1] |= PORT_PESC;
break;
case PORT_FEAT_SUSPEND:
hcd->roothub->port_status[port-1] |= PORT_PSSC;
break;
case PORT_FEAT_OVER_CURRENT:
hcd->roothub->port_status[port-1] |= PORT_POCIC;
break;
case PORT_FEAT_RESET:
hcd->ops->reset_port(port);
break;
case PORT_FEAT_POWER:
break;
case PORT_FEAT_LOWSPEED:
break;
case PORT_FEAT_HIGHSPEED:
break;
}
break;
default:
return -RT_ERROR;
}
return RT_EOK;
}
void rt_usbh_root_hub_connect_handler(struct uhcd *hcd, rt_uint8_t port, rt_bool_t isHS)
{
struct uhost_msg msg;
msg.type = USB_MSG_CONNECT_CHANGE;
msg.content.hub = hcd->roothub;
hcd->roothub->port_status[port - 1] |= PORT_CCS | PORT_CCSC;
if(isHS)
{
hcd->roothub->port_status[port - 1] &= ~PORT_LSDA;
}
else
{
hcd->roothub->port_status[port - 1] |= PORT_LSDA;
}
rt_usbh_event_signal(hcd, &msg);
}
void rt_usbh_root_hub_disconnect_handler(struct uhcd *hcd, rt_uint8_t port)
{
struct uhost_msg msg;
msg.type = USB_MSG_CONNECT_CHANGE;
msg.content.hub = hcd->roothub;
hcd->roothub->port_status[port - 1] |= PORT_CCSC;
hcd->roothub->port_status[port - 1] &= ~PORT_CCS;
rt_usbh_event_signal(hcd, &msg);
}
/**
* This function will do USB_REQ_GET_DESCRIPTOR bRequest for the device instance
* to get usb hub descriptor.
*
* @param intf the interface instance.
* @buffer the data buffer to save usb hub descriptor.
* @param nbytes the size of buffer
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_get_descriptor(struct uinstance* device, rt_uint8_t *buffer, rt_size_t nbytes)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE;
setup.bRequest = USB_REQ_GET_DESCRIPTOR;
setup.wIndex = 0;
setup.wLength = nbytes;
setup.wValue = USB_DESC_TYPE_HUB << 8;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, nbytes, timeout) == nbytes)
{
return RT_EOK;
}
}
return -RT_FALSE;
}
/**
* This function will do USB_REQ_GET_STATUS bRequest for the device instance
* to get usb hub status.
*
* @param intf the interface instance.
* @buffer the data buffer to save usb hub status.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_get_status(struct uinstance* device, rt_uint32_t* buffer)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE;
setup.bRequest = USB_REQ_GET_STATUS;
setup.wIndex = 0;
setup.wLength = 4;
setup.wValue = 0;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, 4, timeout) == 4)
{
return RT_EOK;
}
}
return -RT_FALSE;
}
/**
* This function will do USB_REQ_GET_STATUS bRequest for the device instance
* to get hub port status.
*
* @param intf the interface instance.
* @port the hub port to get status.
* @buffer the data buffer to save usb hub status.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_get_port_status(uhub_t hub, rt_uint16_t port, rt_uint32_t* buffer)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(hub != RT_NULL);
/* get roothub port status */
if(hub->is_roothub)
{
root_hub_ctrl(hub->hcd, port, RH_GET_PORT_STATUS,
(void*)buffer);
return RT_EOK;
}
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_OTHER;
setup.bRequest = USB_REQ_GET_STATUS;
setup.wIndex = port;
setup.wLength = 4;
setup.wValue = 0;
if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(hub->hcd, hub->self->pipe_ep0_in, buffer, 4, timeout) == 4)
{
return RT_EOK;
}
}
return -RT_FALSE;
}
/**
* This function will do USB_REQ_CLEAR_FEATURE bRequest for the device instance
* to clear feature of the hub port.
*
* @param intf the interface instance.
* @port the hub port.
* @feature feature to be cleared.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_clear_port_feature(uhub_t hub, rt_uint16_t port, rt_uint16_t feature)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(hub != RT_NULL);
/* clear roothub feature */
if(hub->is_roothub)
{
root_hub_ctrl(hub->hcd, port, RH_CLEAR_PORT_FEATURE,
(void*)(rt_uint32_t)feature);
return RT_EOK;
}
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_OTHER;
setup.bRequest = USB_REQ_CLEAR_FEATURE;
setup.wIndex = port;
setup.wLength = 0;
setup.wValue = feature;
if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8)
{
return RT_EOK;
}
return -RT_FALSE;
}
/**
* This function will do USB_REQ_SET_FEATURE bRequest for the device instance
* to set feature of the hub port.
*
* @param intf the interface instance.
* @port the hub port.
* @feature feature to be set.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_set_port_feature(uhub_t hub, rt_uint16_t port,
rt_uint16_t feature)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* parameter check */
RT_ASSERT(hub != RT_NULL);
/* clear roothub feature */
if(hub->is_roothub)
{
root_hub_ctrl(hub->hcd, port, RH_SET_PORT_FEATURE,
(void*)(rt_uint32_t)feature);
return RT_EOK;
}
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
USB_REQ_TYPE_OTHER;
setup.bRequest = USB_REQ_SET_FEATURE;
setup.wIndex = port;
setup.wLength = 0;
setup.wValue = feature;
if(rt_usb_hcd_setup_xfer(hub->hcd, hub->self->pipe_ep0_out, &setup, timeout) == 8)
{
return RT_EOK;
}
else return -RT_FALSE;
}
/**
* This function will rest hub port, it is invoked when sub device attached to the hub port.
*
* @param intf the interface instance.
* @param port the hub port.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_reset_port(uhub_t hub, rt_uint16_t port)
{
rt_err_t ret;
rt_uint32_t pstatus;
/* parameter check */
RT_ASSERT(hub != RT_NULL);
rt_thread_delay(50);
/* reset hub port */
ret = rt_usbh_hub_set_port_feature(hub, port, PORT_FEAT_RESET);
if(ret != RT_EOK) return ret;
while(1)
{
ret = rt_usbh_hub_get_port_status(hub, port, &pstatus);
if(!(pstatus & PORT_PRS)) break;
}
/* clear port reset feature */
ret = rt_usbh_hub_clear_port_feature(hub, port, PORT_FEAT_C_RESET);
if(ret != RT_EOK) return ret;
rt_thread_delay(50);
return RT_EOK;
}
/**
* This function will do debouce, it is invoked when sub device attached to the hub port.
*
* @param device the usb instance.
* @param port the hub port.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_hub_port_debounce(uhub_t hub, rt_uint16_t port)
{
rt_err_t ret;
int i = 0, times = 20;
rt_uint32_t pstatus;
rt_bool_t connect = RT_TRUE;
int delayticks = USB_DEBOUNCE_TIME / times;
if (delayticks < 1)
delayticks = 1;
/* parameter check */
RT_ASSERT(hub != RT_NULL);
for(i=0; i<times; i++)
{
ret = rt_usbh_hub_get_port_status(hub, port, &pstatus);
if(ret != RT_EOK) return ret;
if(!(pstatus & PORT_CCS))
{
connect = RT_FALSE;
break;
}
rt_thread_delay(delayticks);
}
if(connect) return RT_EOK;
else return -RT_ERROR;
}
/**
* This function will poll all the hub ports to detect port status, especially connect and
* disconnect events.
*
* @param intf the interface instance.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_hub_port_change(uhub_t hub)
{
int i;
rt_bool_t reconnect;
/* parameter check */
RT_ASSERT(hub != RT_NULL);
/* get usb device instance */
for (i = 0; i < hub->num_ports; i++)
{
rt_err_t ret;
struct uinstance* device;
rt_uint32_t pstatus = 0;
reconnect = RT_FALSE;
/* get hub port status */
ret = rt_usbh_hub_get_port_status(hub, i + 1, &pstatus);
if(ret != RT_EOK) continue;
LOG_D("port %d status 0x%x", i + 1, pstatus);
/* check port status change */
if (pstatus & PORT_CCSC)
{
/* clear port status change feature */
rt_usbh_hub_clear_port_feature(hub, i + 1, PORT_FEAT_C_CONNECTION);
reconnect = RT_TRUE;
}
if(pstatus & PORT_PESC)
{
rt_usbh_hub_clear_port_feature(hub, i + 1, PORT_FEAT_C_ENABLE);
reconnect = RT_TRUE;
}
if(reconnect)
{
if(hub->child[i] != RT_NULL && hub->child[i]->status != DEV_STATUS_IDLE)
{
rt_usbh_detach_instance(hub->child[i]);
/* Child device have been detach. Set hub->child[i] to NULL. */
hub->child[i] = RT_NULL;
}
ret = rt_usbh_hub_port_debounce(hub, i + 1);
if(ret != RT_EOK) continue;
/* allocate an usb instance for new connected device */
device = rt_usbh_alloc_instance(hub->hcd);
if(device == RT_NULL) break;
/* set usb device speed */
device->speed = (pstatus & PORT_LSDA) ? 1 : 0;
device->parent_hub = hub;
device->hcd = hub->hcd;
device->port = i + 1;
hub->child[i] = device;
/* reset usb roothub port */
rt_usbh_hub_reset_port(hub, i + 1);
/* attatch the usb instance to the hcd */
rt_usbh_attatch_instance(device);
}
}
return RT_EOK;
}
/**
* This function is the callback function of hub's int endpoint, it is invoked when data comes.
*
* @param context the context of the callback function.
*
* @return none.
*/
static void rt_usbh_hub_irq(void* context)
{
upipe_t pipe;
uhub_t hub;
int timeout = USB_TIMEOUT_BASIC;
RT_ASSERT(context != RT_NULL);
pipe = (upipe_t)context;
hub = (uhub_t)pipe->user_data;
if(pipe->status != UPIPE_STATUS_OK)
{
LOG_D("hub irq error");
return;
}
rt_usbh_hub_port_change(hub);
LOG_D("hub int xfer...");
/* parameter check */
RT_ASSERT(pipe->inst->hcd != RT_NULL);
rt_usb_hcd_pipe_xfer(hub->self->hcd, pipe, hub->buffer, pipe->ep.wMaxPacketSize, timeout);
}
/**
* This function will run usb hub class driver when usb hub is detected and identified
* as a hub class device, it will continue to do the enumulate process.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_hub_enable(void *arg)
{
int i = 0;
rt_err_t ret = RT_EOK;
uep_desc_t ep_desc = RT_NULL;
uhub_t hub;
struct uinstance* device;
struct uhintf* intf = (struct uhintf*)arg;
upipe_t pipe_in = RT_NULL;
int timeout = USB_TIMEOUT_LONG;
/* paremeter check */
RT_ASSERT(intf != RT_NULL);
/* get usb device instance */
device = intf->device;
/* create a hub instance */
hub = rt_malloc(sizeof(struct uhub));
RT_ASSERT(hub != RT_NULL);
rt_memset(hub, 0, sizeof(struct uhub));
/* make interface instance's user data point to hub instance */
intf->user_data = (void*)hub;
/* get hub descriptor head */
ret = rt_usbh_hub_get_descriptor(device, (rt_uint8_t*)&hub->hub_desc, 8);
if(ret != RT_EOK)
{
rt_kprintf("get hub descriptor failed\n");
return -RT_ERROR;
}
/* get full hub descriptor */
ret = rt_usbh_hub_get_descriptor(device, (rt_uint8_t*)&hub->hub_desc,
hub->hub_desc.length);
if(ret != RT_EOK)
{
rt_kprintf("get hub descriptor again failed\n");
return -RT_ERROR;
}
/* get hub ports number */
/* If hub device supported ports over USB_HUB_PORT_NUM(Ex: 8 port hub). Set hub->num_ports to USB_HUB_PORT_NUM */
if(hub->hub_desc.num_ports > USB_HUB_PORT_NUM)
hub->num_ports = USB_HUB_PORT_NUM;
else
hub->num_ports = hub->hub_desc.num_ports;
hub->hcd = device->hcd;
hub->self = device;
/* reset all hub ports */
for (i = 0; i < hub->num_ports; i++)
{
rt_usbh_hub_set_port_feature(hub, i + 1, PORT_FEAT_POWER);
rt_thread_delay(hub->hub_desc.pwron_to_good
* 2 * RT_TICK_PER_SECOND / 1000 );
}
if(intf->intf_desc->bNumEndpoints != 1)
return -RT_ERROR;
/* get endpoint descriptor from interface descriptor */
rt_usbh_get_endpoint_descriptor(intf->intf_desc, 0, &ep_desc);
if(ep_desc == RT_NULL)
{
rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
return -RT_ERROR;
}
/* the endpoint type of hub class should be interrupt */
if( USB_EP_ATTR(ep_desc->bmAttributes) == USB_EP_ATTR_INT)
{
/* the endpoint direction of hub class should be in */
if(ep_desc->bEndpointAddress & USB_DIR_IN)
{
/* allocate a pipe according to the endpoint type */
pipe_in = rt_usb_instance_find_pipe(device,ep_desc->bEndpointAddress);
if(pipe_in == RT_NULL)
{
return -RT_ERROR;
}
rt_usb_pipe_add_callback(pipe_in,rt_usbh_hub_irq);
}
else return -RT_ERROR;
}
/* parameter check */
RT_ASSERT(device->hcd != RT_NULL);
pipe_in->user_data = hub;
rt_usb_hcd_pipe_xfer(hub->hcd, pipe_in, hub->buffer,
pipe_in->ep.wMaxPacketSize, timeout);
return RT_EOK;
}
/**
* This function will be invoked when usb hub plug out is detected and it would clean
* and release all hub class related resources.
*
* @param arg the argument.
*
* @return the error code, RT_EOK on successfully.
*/
static rt_err_t rt_usbh_hub_disable(void* arg)
{
int i;
uhub_t hub;
struct uhintf* intf = (struct uhintf*)arg;
/* paremeter check */
RT_ASSERT(intf != RT_NULL);
LOG_D("rt_usbh_hub_stop");
hub = (uhub_t)intf->user_data;
for(i=0; i<hub->num_ports; i++)
{
if(hub->child[i] != RT_NULL)
rt_usbh_detach_instance(hub->child[i]);
}
if(hub != RT_NULL) rt_free(hub);
return RT_EOK;
}
/**
* This function will register hub class driver to the usb class driver manager.
* and it should be invoked in the usb system initialization.
*
* @return the error code, RT_EOK on successfully.
*/
ucd_t rt_usbh_class_driver_hub(void)
{
hub_driver.class_code = USB_CLASS_HUB;
hub_driver.enable = rt_usbh_hub_enable;
hub_driver.disable = rt_usbh_hub_disable;
return &hub_driver;
}
/**
* This function is the main entry of usb hub thread, it is in charge of
* processing all messages received from the usb message buffer.
*
* @param parameter the parameter of the usb host thread.
*
* @return none.
*/
static void rt_usbh_hub_thread_entry(void* parameter)
{
uhcd_t hcd = (uhcd_t)parameter;
while(1)
{
struct uhost_msg msg;
/* receive message */
if (rt_mq_recv(hcd->usb_mq, &msg, sizeof(struct uhost_msg), RT_WAITING_FOREVER) < 0)
continue;
switch (msg.type)
{
case USB_MSG_CONNECT_CHANGE:
rt_usbh_hub_port_change(msg.content.hub);
break;
case USB_MSG_CALLBACK:
/* invoke callback */
msg.content.cb.function(msg.content.cb.context);
break;
default:
break;
}
}
}
/**
* This function will post an message to the usb message queue,
*
* @param msg the message to be posted
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_event_signal(uhcd_t hcd, struct uhost_msg* msg)
{
RT_ASSERT(msg != RT_NULL);
/* send message to usb message queue */
rt_mq_send(hcd->usb_mq, (void*)msg, sizeof(struct uhost_msg));
return RT_EOK;
}
/**
* This function will initialize usb hub thread.
*
* @return none.
*
*/
void rt_usbh_hub_init(uhcd_t hcd)
{
rt_thread_t thread;
/* create root hub for hcd */
hcd->roothub = rt_malloc(sizeof(struct uhub));
if(hcd->roothub == RT_NULL)
{
LOG_E("hcd->roothub: allocate buffer failed.");
return;
}
rt_memset(hcd->roothub, 0, sizeof(struct uhub));
hcd->roothub->is_roothub = RT_TRUE;
hcd->roothub->hcd = hcd;
hcd->roothub->num_ports = hcd->num_ports;
/* create usb message queue */
hcd->usb_mq = rt_mq_create(hcd->parent.parent.name, 32, 16, RT_IPC_FLAG_FIFO);
/* create usb hub thread */
thread = rt_thread_create(hcd->parent.parent.name, rt_usbh_hub_thread_entry, hcd,
USB_THREAD_STACK_SIZE, 8, 20);
if(thread != RT_NULL)
{
/* startup usb host thread */
rt_thread_startup(thread);
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
* 2021-02-23 Leslie Lee provide possibility for multi usb host
*/
#include <rtthread.h>
#include <drivers/usb_host.h>
#define USB_HOST_CONTROLLER_NAME "usbh"
#if defined(RT_USBH_HID_KEYBOARD) || defined(RT_USBH_HID_MOUSE)
#include <hid.h>
#endif
/**
* This function will initialize the usb host stack, all the usb class driver and
* host controller driver are also be initialized here.
*
* @return none.
*/
rt_err_t rt_usb_host_init(const char *name)
{
ucd_t drv;
rt_device_t uhc;
uhc = rt_device_find(name);
if(uhc == RT_NULL)
{
rt_kprintf("can't find usb host controller %s\n", name);
return -RT_ERROR;
}
/* initialize usb hub */
rt_usbh_hub_init((uhcd_t)uhc);
/* initialize class driver */
rt_usbh_class_driver_init();
#ifdef RT_USBH_MSTORAGE
/* register mass storage class driver */
drv = rt_usbh_class_driver_storage();
rt_usbh_class_driver_register(drv);
#endif
#ifdef RT_USBH_HID
extern ucd_t rt_usbh_class_driver_hid(void);
/* register mass storage class driver */
drv = rt_usbh_class_driver_hid();
rt_usbh_class_driver_register(drv);
#ifdef RT_USBH_HID_MOUSE
{
extern uprotocal_t rt_usbh_hid_protocal_mouse(void);
rt_usbh_hid_protocal_register(rt_usbh_hid_protocal_mouse());
}
#endif
#ifdef RT_USBH_HID_KEYBOARD
{
extern uprotocal_t rt_usbh_hid_protocal_kbd(void);
rt_usbh_hid_protocal_register(rt_usbh_hid_protocal_kbd());
}
#endif
#endif
/* register hub class driver */
drv = rt_usbh_class_driver_hub();
rt_usbh_class_driver_register(drv);
/* initialize usb host controller */
rt_device_init(uhc);
return RT_EOK;
}

View File

@ -0,0 +1,586 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-12-12 Yi Qiu first version
*/
#include <rtthread.h>
#include <drivers/usb_host.h>
#define DBG_TAG "usbhost.core"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
static struct uinstance dev[USB_MAX_DEVICE];
/**
* This function will allocate an usb device instance from system.
*
* @param parent the hub instance to which the new allocated device attached.
* @param port the hub port.
*
* @return the allocate instance on successful, or RT_NULL on failure.
*/
uinst_t rt_usbh_alloc_instance(uhcd_t uhcd)
{
int i;
/* lock scheduler */
rt_enter_critical();
for(i=0; i<USB_MAX_DEVICE; i++)
{
/* to find an idle instance handle */
if(dev[i].status != DEV_STATUS_IDLE) continue;
/* initialize the usb device instance */
rt_memset(&dev[i], 0, sizeof(struct uinstance));
dev[i].status = DEV_STATUS_BUSY;
dev[i].index = i + 1;
dev[i].address = 0;
dev[i].max_packet_size = 0x8;
rt_list_init(&dev[i].pipe);
dev[i].hcd = uhcd;
/* unlock scheduler */
rt_exit_critical();
return &dev[i];
}
/* unlock scheduler */
rt_exit_critical();
return RT_NULL;
}
/**
* This function will attatch an usb device instance to a host controller,
* and do device enumunation process.
*
* @param hcd the host controller driver.
* @param device the usb device instance.
*
* @return the error code, RT_EOK on successfully.
*/
static struct uendpoint_descriptor ep0_out_desc =
{
/*endpoint descriptor*/
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
0x00 | USB_DIR_OUT,
USB_EP_ATTR_CONTROL,
0x00,
0x00,
};
static struct uendpoint_descriptor ep0_in_desc =
{
/*endpoint descriptor*/
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
0x00 | USB_DIR_IN,
USB_EP_ATTR_CONTROL,
0x00,
0x00,
};
rt_err_t rt_usbh_attatch_instance(uinst_t device)
{
int i = 0;
rt_err_t ret = RT_EOK;
struct uconfig_descriptor cfg_desc;
udev_desc_t dev_desc;
uintf_desc_t intf_desc;
uep_desc_t ep_desc;
rt_uint8_t ep_index;
upipe_t pipe;
ucd_t drv;
RT_ASSERT(device != RT_NULL);
rt_memset(&cfg_desc, 0, sizeof(struct uconfig_descriptor));
dev_desc = &device->dev_desc;
/* alloc address 0 ep0 pipe*/
ep0_out_desc.wMaxPacketSize = 8;
ep0_in_desc.wMaxPacketSize = 8;
rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_out, device, &ep0_out_desc);
rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_in, device, &ep0_in_desc);
LOG_D("start enumnation");
/* get device descriptor head */
ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, 8);
if(ret != RT_EOK)
{
rt_kprintf("get device descriptor head failed\n");
return ret;
}
/* reset bus */
rt_usbh_hub_reset_port(device->parent_hub, device->port);
rt_thread_delay(2);
rt_usbh_hub_clear_port_feature(device->parent_hub, i + 1, PORT_FEAT_C_CONNECTION);
/* set device address */
ret = rt_usbh_set_address(device);
if(ret != RT_EOK)
{
rt_kprintf("set device address failed\n");
return ret;
}
/* free address 0 ep0 pipe*/
rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_out);
rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_in);
/* set device max packet size */
ep0_out_desc.wMaxPacketSize = device->dev_desc.bMaxPacketSize0;
ep0_in_desc.wMaxPacketSize = device->dev_desc.bMaxPacketSize0;
/* alloc true address ep0 pipe*/
rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_out, device, &ep0_out_desc);
rt_usb_hcd_alloc_pipe(device->hcd, &device->pipe_ep0_in, device, &ep0_in_desc);
LOG_D("get device descriptor length %d",
dev_desc->bLength);
/* get full device descriptor again */
ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_DEVICE, (void*)dev_desc, dev_desc->bLength);
if(ret != RT_EOK)
{
rt_kprintf("get full device descriptor failed\n");
return ret;
}
LOG_D("Vendor ID 0x%x", dev_desc->idVendor);
LOG_D("Product ID 0x%x", dev_desc->idProduct);
/* get configuration descriptor head */
ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION, &cfg_desc, 18);
if(ret != RT_EOK)
{
rt_kprintf("get configuration descriptor head failed\n");
return ret;
}
/* alloc memory for configuration descriptor */
device->cfg_desc = (ucfg_desc_t)rt_malloc(cfg_desc.wTotalLength);
if(device->cfg_desc == RT_NULL)
{
return -RT_ENOMEM;
}
rt_memset(device->cfg_desc, 0, cfg_desc.wTotalLength);
/* get full configuration descriptor */
ret = rt_usbh_get_descriptor(device, USB_DESC_TYPE_CONFIGURATION,
device->cfg_desc, cfg_desc.wTotalLength);
if(ret != RT_EOK)
{
rt_kprintf("get full configuration descriptor failed\n");
return ret;
}
/* set configuration */
ret = rt_usbh_set_configure(device, 1);
if(ret != RT_EOK)
{
return ret;
}
for(i=0; i<device->cfg_desc->bNumInterfaces; i++)
{
/* get interface descriptor through configuration descriptor */
ret = rt_usbh_get_interface_descriptor(device->cfg_desc, i, &intf_desc);
if(ret != RT_EOK)
{
rt_kprintf("rt_usb_get_interface_descriptor error\n");
return -RT_ERROR;
}
LOG_D("interface class 0x%x, subclass 0x%x",
intf_desc->bInterfaceClass,
intf_desc->bInterfaceSubClass);
/* alloc pipe*/
for(ep_index = 0; ep_index < intf_desc->bNumEndpoints; ep_index++)
{
rt_usbh_get_endpoint_descriptor(intf_desc, ep_index, &ep_desc);
if(ep_desc != RT_NULL)
{
if(rt_usb_hcd_alloc_pipe(device->hcd, &pipe, device, ep_desc) != RT_EOK)
{
rt_kprintf("alloc pipe failed\n");
return -RT_ERROR;
}
rt_usb_instance_add_pipe(device,pipe);
}
else
{
rt_kprintf("get endpoint desc failed\n");
return -RT_ERROR;
}
}
/* find driver by class code found in interface descriptor */
drv = rt_usbh_class_driver_find(intf_desc->bInterfaceClass,
intf_desc->bInterfaceSubClass);
if(drv != RT_NULL)
{
/* allocate memory for interface device */
device->intf[i] = (struct uhintf*)rt_malloc(sizeof(struct uhintf));
if(device->intf[i] == RT_NULL)
{
return -RT_ENOMEM;
}
device->intf[i]->drv = drv;
device->intf[i]->device = device;
device->intf[i]->intf_desc = intf_desc;
device->intf[i]->user_data = RT_NULL;
/* open usb class driver */
ret = rt_usbh_class_driver_enable(drv, (void*)device->intf[i]);
if(ret != RT_EOK)
{
rt_kprintf("interface %d run class driver error\n", i);
}
}
else
{
rt_kprintf("find usb device driver failed\n");
continue;
}
}
return RT_EOK;
}
/**
* This function will detach an usb device instance from its host controller,
* and release all resource.
*
* @param device the usb device instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_detach_instance(uinst_t device)
{
int i = 0;
rt_list_t * l;
if(device == RT_NULL)
{
rt_kprintf("no usb instance to detach\n");
return -RT_ERROR;
}
/* free configration descriptor */
if (device->cfg_desc) {
for (i = 0; i < device->cfg_desc->bNumInterfaces; i++)
{
if (device->intf[i] == RT_NULL) continue;
if (device->intf[i]->drv == RT_NULL) continue;
RT_ASSERT(device->intf[i]->device == device);
LOG_D("free interface instance %d", i);
rt_usbh_class_driver_disable(device->intf[i]->drv, (void*)device->intf[i]);
rt_free(device->intf[i]);
}
rt_free(device->cfg_desc);
}
rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_out);
rt_usb_hcd_free_pipe(device->hcd,device->pipe_ep0_in);
while(device->pipe.next!= &device->pipe)
{
l = device->pipe.next;
rt_list_remove(l);
rt_usb_hcd_free_pipe(device->hcd,rt_list_entry(l,struct upipe,list));
}
rt_memset(device, 0, sizeof(struct uinstance));
return RT_EOK;
}
/**
* This function will do USB_REQ_GET_DESCRIPTO' bRequest for the usb device instance,
*
* @param device the usb device instance.
* @param type the type of descriptor bRequest.
* @param buffer the data buffer to save requested data
* @param nbytes the size of buffer
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_get_descriptor(uinst_t device, rt_uint8_t type, void* buffer,
int nbytes)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_DEVICE;
setup.bRequest = USB_REQ_GET_DESCRIPTOR;
setup.wIndex = 0;
setup.wLength = nbytes;
setup.wValue = type << 8;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) == 8)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, buffer, nbytes, timeout) == nbytes)
{
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_out, RT_NULL, 0, timeout) == 0)
{
return RT_EOK;
}
}
}
return -RT_ERROR;
}
/**
* This function will set an address to the usb device.
*
* @param device the usb device instance.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_set_address(uinst_t device)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
RT_ASSERT(device != RT_NULL);
LOG_D("rt_usb_set_address");
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_DEVICE;
setup.bRequest = USB_REQ_SET_ADDRESS;
setup.wIndex = 0;
setup.wLength = 0;
setup.wValue = device->index;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
{
return -RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) == 0)
{
device->address = device->index;
}
return RT_EOK;
}
/**
* This function will set a configuration to the usb device.
*
* @param device the usb device instance.
* @param config the configuration number.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_set_configure(uinst_t device, int config)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* check parameter */
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_DEVICE;
setup.bRequest = USB_REQ_SET_CONFIGURATION;
setup.wIndex = 0;
setup.wLength = 0;
setup.wValue = config;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
{
return -RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(device->hcd, device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
{
return -RT_ERROR;
}
return RT_EOK;
}
/**
* This function will set an interface to the usb device.
*
* @param device the usb device instance.
* @param intf the interface number.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_set_interface(uinst_t device, int intf)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* check parameter */
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_SET_INTERFACE;
setup.wIndex = 0;
setup.wLength = 0;
setup.wValue = intf;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
{
return -RT_ERROR;
}
return RT_EOK;
}
/**
* This function will clear feature for the endpoint of the usb device.
*
* @param device the usb device instance.
* @param endpoint the endpoint number of the usb device.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_clear_feature(uinst_t device, int endpoint, int feature)
{
struct urequest setup;
int timeout = USB_TIMEOUT_BASIC;
/* check parameter */
RT_ASSERT(device != RT_NULL);
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD |
USB_REQ_TYPE_ENDPOINT;
setup.bRequest = USB_REQ_CLEAR_FEATURE;
setup.wIndex = endpoint;
setup.wLength = 0;
setup.wValue = feature;
if(rt_usb_hcd_setup_xfer(device->hcd, device->pipe_ep0_out, &setup, timeout) != 8)
{
return -RT_ERROR;
}
return RT_EOK;
}
/**
* This function will get an interface descriptor from the configuration descriptor.
*
* @param cfg_desc the point of configuration descriptor structure.
* @param num the number of interface descriptor.
* @intf_desc the point of interface descriptor point.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_get_interface_descriptor(ucfg_desc_t cfg_desc, int num,
uintf_desc_t* intf_desc)
{
rt_uint32_t ptr, depth = 0;
udesc_t desc;
/* check parameter */
RT_ASSERT(cfg_desc != RT_NULL);
ptr = (rt_uint32_t)cfg_desc + cfg_desc->bLength;
while(ptr < (rt_uint32_t)cfg_desc + cfg_desc->wTotalLength)
{
if(depth++ > 0x20)
{
*intf_desc = RT_NULL;
return -RT_EIO;
}
desc = (udesc_t)ptr;
if(desc->type == USB_DESC_TYPE_INTERFACE)
{
if(((uintf_desc_t)desc)->bInterfaceNumber == num)
{
*intf_desc = (uintf_desc_t)desc;
LOG_D("rt_usb_get_interface_descriptor: %d", num);
return RT_EOK;
}
}
ptr = (rt_uint32_t)desc + desc->bLength;
}
rt_kprintf("rt_usb_get_interface_descriptor %d failed\n", num);
return -RT_EIO;
}
/**
* This function will get an endpoint descriptor from the interface descriptor.
*
* @param intf_desc the point of interface descriptor structure.
* @param num the number of endpoint descriptor.
* @param ep_desc the point of endpoint descriptor point.
*
* @return the error code, RT_EOK on successfully.
*/
rt_err_t rt_usbh_get_endpoint_descriptor(uintf_desc_t intf_desc, int num,
uep_desc_t* ep_desc)
{
int count = 0, depth = 0;
rt_uint32_t ptr;
udesc_t desc;
/* check parameter */
RT_ASSERT(intf_desc != RT_NULL);
RT_ASSERT(num < intf_desc->bNumEndpoints);
*ep_desc = RT_NULL;
ptr = (rt_uint32_t)intf_desc + intf_desc->bLength;
while(count < intf_desc->bNumEndpoints)
{
if(depth++ > 0x20)
{
*ep_desc = RT_NULL;
return -RT_EIO;
}
desc = (udesc_t)ptr;
if(desc->type == USB_DESC_TYPE_ENDPOINT)
{
if(num == count)
{
*ep_desc = (uep_desc_t)desc;
LOG_D("rt_usb_get_endpoint_descriptor: %d", num);
return RT_EOK;
}
else count++;
}
ptr = (rt_uint32_t)desc + desc->bLength;
}
rt_kprintf("rt_usb_get_endpoint_descriptor %d failed\n", num);
return -RT_EIO;
}
int rt_usb_hcd_pipe_xfer(uhcd_t hcd, upipe_t pipe, void* buffer, int nbytes, int timeout)
{
rt_size_t remain_size;
rt_size_t send_size;
remain_size = nbytes;
rt_uint8_t * pbuffer = (rt_uint8_t *)buffer;
do
{
LOG_D("pipe transform remain size,: %d", remain_size);
send_size = (remain_size > pipe->ep.wMaxPacketSize) ? pipe->ep.wMaxPacketSize : remain_size;
if(hcd->ops->pipe_xfer(pipe, USBH_PID_DATA, pbuffer, send_size, timeout) == send_size)
{
remain_size -= send_size;
pbuffer += send_size;
}
else
{
return 0;
}
}while(remain_size > 0);
return nbytes;
}