无障碍wps下载的地址哪里有
过去ARM Linux中,充斥着大量的垃圾代码,这些设备代码与对应公司单板启动或运行细节强绑定,无法复用和移植。同时内核中没有规范来引导,导致代码越来越臃肿。最终因为Tony Lindgren,内核OMAP development tree的维护者,发送了一个邮件给Linus,请求提交OMAP平台代码修改,并附带修改以及如何解决merge conficts,让linus发出怒吼“Gaah.Guys, this whole ARM thing is a f*cking pain in the ass.”(linus对arm这样代码肯定深恶痛绝已久)。
最终经过讨论,对ARM平台相关code做出相关规范:
ARM的核心代码仍然保存在arch/arm目录下;
2. ARM SoC core architecture code保存在arch/arm目录下;
3. ARM SOC的周边外设模块的驱动保存在drivers目录下;
4. ARM SOC的特定代码在arch/arm/mach-xxx目录下;
5. ARM SOC board specific的代码被移除,由DeviceTree机制来负责传递硬件拓扑和硬件资源信息。
本质上,Device Tree改变了原来用hardcode方式将硬件设备配置信息嵌入到内核代码的方法,改用bootloader传递一个DB的形式。
Arm系统启动,硬件设备 wps office免费版的下载网站可以通过DTS(devicetree)或ACPI引导初始化,这里只讲DTS方式,ACPI是由BIOS配置。
如上图,一般来说,arm内核通过dts引导启动,需要内核Image、dtb和filesystem,其中dtb是由dts通过dtc工具生成,里面包括初始化设备的硬件信息。内核Image启动过程中会解析dtb中内容,并根据信息初始化设备平台。这里提一句,dts由虽然由用户配置,但是配置必须与硬件信息相匹配,否则会出现初始化失败或设备部分功能不正常的问题。
DeviceWPS office的官网的下载网站怎么找 Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。在Device Tree中,可描述的信息包括(原先这些信息大多被hard code到kernel中),CPU的数量和类别、内存基地址和大、timer时钟、外设连接、中断配置、串口等。内核在启动过程中会解析每个node的硬件配置信息,根据这些信息初始化设备。
举例,如下是arm gicv3中断控制器的节点配置信息(来源Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt):
gic: interrupt-controller@2cf00000 {
compatible = "arm,gic-v3";
#interrupt-cells = <3>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
interrupt-controller;
reg = <0x0 0x2f000000 0 0x10000>, // GICD
<0x0 0x2f100000 0 0x200000>, // GICR
<0x0 0x2c000000 0 0x2000>, // GICC
<0x0 0x2c010000 0 0x2000>, // GICH
<0x0 0x2c020000 0 0x2000>; // GICV
interrupts = <1 9 4>;
msi-controller;
mbi-ranges = <256 128>;
gic-its@2c200000 {
compatible = "arm,gic-v3-its";官网最新版wps的下载网址哪里有
msi-controller;
#msi-cells = <1>;
reg = <0x0 0x2c200000 0 0x20000>;
};
};
gic: interrupt-controller@2cf00000:表示node节点信息,interrupt-controller@2cf00000是node节点的名称,一般命名规范是 设备名@基地址或设备名,其中冒号前面gic可以看过node的别名,后续关联node节点可以直接”&gic”;
{}中内容:interrupt-controller的属性,包括:
1)compatible = "arm,gic-v3"; compatible名称,gicv3驱动代码匹配”arm,gic-v3”后才会执行初始化probe代码;
2)#interrupt-cells = <3>; 表示interrupt由3部分组成,对应interrupts = <1 9 4>,分别是中断类型(1表示PPI),中断号9和中断触发方式(4表示上升沿触发);
3)#address-cells = <2>;
#size-cells = <2>; 表示地址信息用64位表示,比如reg = <0x0 0x2f000000 0 0x10000>表示GICD的基地址是0x02f000000(其中0x是高32bit,0x2f000000是低32bit),size是0x10000;
4)msi-controller; 表示msi,此字符串含义可以具体查看驱动代码,驱动会get到这个字符串,然后做判断,有会走A,没有就跳过。
5)gic-its@2c200000 表示its节点的配置,gic-v3引入了its来接收SPI中断;
如上,便是dts的基本配置,更加详细的介绍可以参考linux内核源码:Documentation/devicetree/,每个硬件设备配置格式和属性都有描述。
一般来说,linux菜鸟级别只要会看dts即可,linux驱动开发才需要掌握dts的每行含义,因为任一行出错,都可能导致驱动某项功能失效。下面我列一些经常遇到的问题:
1.dts和dtb如何转换
内核源码下scripts/dtc/dtc,dtc工具只有内核编译时才会编译,所以如果希望得到,先编译一遍内核即可。
转换命令:
dts转dtb:dtc –I dts –O dtb test.dts –o test.dtb
dtb转dts: dtc –I dtb –O dts test.dtb –o test.dts
2.dts中node节点如何查看,每行又是什么意义
这个问题经常遇到,不知道设备节点配置的意义,其实每个配置都可以根据compatible在Documentation/devicetree/中查到说明,只是不搞内核不知道这个方法,比如dts中看到:
v2m_serial0: uart@090000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x090000 0x1000>;
interrupts = <5>;
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "uartclk", "apb_pclk";
};
到linux内核源码运行:
cuibixuan@ubuntu:~/git/linux/Documentation/devicetree/bindings$ cd Documentation/devicetree/bindings/
cuibixuan@ubuntu:~/git/linux/Documentation/devicetree/bindings$ grep "arm,pl011" -rn *
clock/hi3660-clock.txt:41: compatible = "arm,pl011", WPS office官网的下载入口的方法 "arm,primecell";
clock/hi3670-clock.txt:37: compatible = "arm,pl011", "arm,primecell";
clock/lsi,axm5516-clks.txt:22: compatible = "arm,pl011", "arm,primecell";
clock/hix5hd2-clock.txt:25: compatible = "arm,pl011", "arm,primecell";
dma/ste-dma40.txt:130: compatible = "arm,pl011", "arm,primecell";
dma/snps-dma.txt:65: compatible = "arm,pl011", "arm,primecell";
pinctrl/axis,artpec6-pinctrl.txt:71: compatible = "arm,pl011", "arm,primecell";
pinctrl/axis,artpec6-pinctrl.txt:80: compatible = "arm,pl011", "arm,primecell";
pinctrl/ste,nomadik.txt:141: compatible = "arm,pl011", "arm,primecell";
serial/pl011.txt:4:- compatible: must be "arm,primecell", "arm,pl011", "zte,zx296702-uart"
serial/pl011.txt:44: compatible = "arm,pl011", "arm,primecell";
vim serial/pl011.txt
如下图,有说明,有举例,很清晰
如果还不懂,或者找不到,那么恭喜你,你要看驱动代码了
cuibixuan@ubuntu:~/git/linux$ cd drivers/tty/serial/
cuibixuan@ubuntu:~/git/linux/drivers/tty/serial$ grep "arm,pl011" -rn *
amba-pl011.c:2473:OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
3.内核初始化设备驱动,根据compatible来决定是否初始化
compatible的字符串,是驱动匹配的关键,如果匹配不到,那么就不会初始化。这点设计非常棒,在编译Image完毕后,用户还可以根据dts选配启动哪些硬件。
一直有人有疑问,既然内核都有config选项来决定了,为什么还要dts来再加一道门禁呢。你可以设想下,如果内核启动配置了哪些config就初始化哪些功能,那么启动要多么繁琐呀,大部分都是你不知道的功能都在启动,万一失败了,还得查看哪里问题,至少编译一次内核。尤其是嵌入式设备,要精简,更要达到“我只关心我配置的设备”的目的。
好了扯远了,以上面串口驱动代码举例(提示:驱动代码的开头是probe函数,一般翻到代码底部即可,上面都是功能的实现),
static const struct of_device_id sbsa_uart_of_match[] = {
{ .compatible = "arm,sbsa-uart", },
{},
};
MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
static struct platform_driver arm_sbsa_uart_platform_driver = {
.probe = sbsa_uart_probe,
.remove = sbsa_uart_remove,
.driver = {
.name = "sbsa-uart",
.of_match_table = of_match_ptr(sbsa_uart_of_match),
.acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
},
};
…
static int __init pl011_init(void)
{
printk(KERN_INFO "Serial: AMBA PL011 UART driver
");
if (platform_driver_register(&arm_sbsa_uart_platform_driver))
pr_warn("could not register SBSA UART platform driver
");
return amba_driver_register(&pl011_driver);
}
内核通过platform_driver_register()来注册设备,arm_sbsa_uart_platform_driver是初始化成struct platform_driver的结构体,结构体指定了设备的probe,remove等钩子函数,.driver记录设备的name,.compatible = "arm,sbsa-uart"(of_match_table来匹配),这里多提一句,.of_match_table是dts启动匹配字符串"arm,sbsa-uart",.acpi_match_table是ACPI启动匹配PTR。
如上,如果dts中node节点有compatible带"arm,sbsa-uart",那么就会执行指定的钩子函数.probe = sbsa_uart_probe,函数再进行node节点其他参数的解析(说是解析,就是get字符串或数值,在进行对应初始化或读写寄存器)。
4.reg=<>和interrupts=<>里面数值代表什么?
reg和interrupt数值都有具体的含义,上文提到:
#interrupt-cells = <3>; 表示interrupt由3部分组成,对应interrupts = <1 9 4>,分别是中断类型(1表示PPI),中断号9和中断触发方式(4表示高电平触发);
这里再补充一下:
interrupts = <1 9 4>,分别是
中断类型:0表示SPI,1表示PPI
中断号9,其中PPI是[0-15],SPI范围[32-1019]
中断触发方式:
1 = low-to-high edge triggered
2 = high-to-low edge triggered
4 = active high edge triggered
8 = active low edge triggered
翻译一下就时上升沿触发、下降沿触发、高电平触发、低电平触发。
#address-cells = <2>; #size-cells = <2>; 表示地址信息用64位表示,比如reg = <0x0 0x2f000000 0 0x10000>表示GICD的基地址是0x02f000000(其中0x是高32bit,0x2f000000是第32bit),size是0x10000;
举例,<0x1 0x2f000000> = 0x12f000000, <0x1 0x1> = 0x100000001
5.dts支持include
对于可复用的描述节点,支持以include方式被多个dts包含,可放在dtsi文件,在dts中以
#include "uart.dtsi"包含使用。
dts文件:foundation-platform.dts
默认变量
一般dts首个{}前面的信息表示全局默认变量,意思即node无特殊配置,则默认采用这里的配置
#address-cells = <2>; //地址长度64bit
#size-cells = <1>; //size长度32bit
model = "V2P-AARCH64"; //model名称
compatible = "arm,vexpress,v2p-aarch64", "arm,vexpress";
interrupt-parent = <&gic>; //中断parent是gic
cpus {
#address-cells = <1>;
#size-cells = <0>;
// 配置cpu0-cpu3的信息,最终启动4核
cpu@0 {
device_type = "cpu"; //设备类型:cpu
compatible = "arm,armv8"; //表示armv8的cpu
reg = <0>; //cpu信息
enable-method = "spin-table"; //采用spintable方式拉起从核
cpu-release-addr = <0x0 0x8000fff8>; //cpu初启动的pc指针存放位置
};
cpu@1 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <1>;
enable-method = "spin-table";
cpu-release-addr = <0x0 0x8000fff8>;
};
cpu@2 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <2>;
enable-method = "spin-table";
cpu-release-addr = <0x0 0x8000fff8>;
};
cpu@3 {
device_type = "cpu";
compatible = "arm,armv8";
reg = <3>;
enable-method = "spin-table";
cpu-release-addr = <0x0 0x8000fff8>;
};
};
memory@80000000 {
device_type = "memory";
//此节点配置内存,内存2块:
//起始地址:0x80000000, 长度0x80000000;
//起始地址:0x880000000, 长度0x80000000;
reg = < 0x00000000 0x80000000 0x80000000
0x00000008 0x80000000 0x80000000 >;
};
gic: interrupt-controller@2c001000 {
// 中断控制器使用 cortex a15,gic
compatible = "arm,cortex-a15-gic";
#interrupt-cells = <3>;
#address-cells = <0>;
interrupt-controller;
// GICD,GICH等信息,具体参考Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
//- reg : Specifies base physical address(s) and size of the GIC registers. The
first region is the GIC distributor register base and size. The 2nd region is
the GIC cpu interface register base and size.
reg = <0 0x2c001000 0x1000>,
<0 0x2c002000 0x1000>,
<0 0x2c004000 0x2000>,
<0 0x2c006000 0x2000>;
// 虚拟化使用,- interrupts : VGIC maintenance interrupt.
//* GIC virtualization extensions (VGIC)
interrupts = <1 9 0xf04>;
};
pmu {
// 使用armv8 pmuv3
compatible = "arm,armv8-pmuv3";
// pmu的中断配置,这段配置完毕,即可以使用arm cpu的pmu功能
interrupts = <0 60 4 0 61 4 0 62 4 0 63 4>;
};
timer {
//定时器配置
compatible = "arm,armv8-timer";
interrupts = <1 13 0xff01>,
<1 14 0xff01>,
<1 11 0xff01>,
<1 10 0xff01>;
clock-frequency = <100000000>;
};
iofpga@3,00000000 {
compatible = "arm,amba-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 3 0 0x200000>;
sysreg@010000 {
compatible = "arm,vexpress-sysreg";
reg = <0x010000 0x1000>;
};
v2m_serial0: uart@090000 {
compatible = "arm,pl011", "arm,primecell"; //串口驱动
reg = <0x090000 0x1000>; //串口基地址和长度
interrupts = <5>; //串口中断号
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; //串口波特率
clock-names = "uartclk", "apb_pclk";
};
v2m_serial1: uart@0a0000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x0a0000 0x1000>;
interrupts = <6>;
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "uartclk", "apb_pclk";
};
v2m_serial2: uart@0b0000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x0b0000 0x1000>;
interrupts = <7>;
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "uartclk", "apb_pclk";
};
v2m_serial3: uart@0c0000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x0c0000 0x1000>;
interrupts = <8>;
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
clock-names = "uartclk", "apb_pclk";
};
virtio_block@0130000 {
compatible = "virtio,mmio";
reg = <0x130000 0x1000>;
interrupts = <42>;
};
};
};
/* chosen */
};
int of_property_read_u8_array(const struct device_node *np, const char *propname,u8 *out_values, size_t sz);
int of_property_read_u16_array(const struct device_node *np, const char *propname,u16 *out_values, size_t sz);
int of_property_read_u32_array(const struct device_node *np, const char *propname,u32 *out_values, size_t sz);
从设备结点np中读取属性名为propname,类型为8、16、32、位整型数组的属性值,并放入out_values,sz指明了要读取的个数。
static inline int of_property_read_u8(const struct device_node *np,const char *propname,u8 *out_value)
static inline int of_property_read_u16(const struct device_node *np,const char *propname,u8 *out_value)
static inline int of_property_read_u32(const struct device_node *np,const char *propname,u8 *out_value)
从设备结点np中读取属性名为propname,类型为8、16、32位的属性值,并放入out_values。实际上这里调用的就是sz为1的XXX_array函数。
int of_property_read_u32_index(const struct device_node *np,const char*propname,u32 index, u32 *out_value)
从设备结点np中读取属性名为propname的属性值中第index个u32数值给out_value
int of_property_read_u64(conststruct device_node *np, const char *propname,u64 *out_value)
从设备结点np中读取属性名为propname,类型为64位的属性值,并放入out_values
int of_property_read_string(struct device_node *np, const char *propname,const char**out_string)
从设备结点np中读取属性名为propname的字符串型属性值
int of_property_read_string_index(struct device_node *np, const char *propname,intindex, const char **output)
从设备结点np中读取属性名为propname的字符串型属性值数组中的第index个字符串
int of_property_count_strings(struct device_node *np, const char *propname)
从设备结点np中读取属性名为propname的字符串型属性值的个数
unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
从设备节点dev中读取第index个irq号
int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
从设备节点dev中读取第index个irq号,并填充一个irq资源结构体
int of_irq_count(struct device_node *dev)
获取设备节点dev的irq个数
static inline bool of_property_read_bool(const struct device_node *np,const char *propname);
如果设备结点np含有propname属性,则返回true,否则返回false。一般用于检查空属性是否存在。
struct property* of_find_property(const struct device_node *np,const char *name,int *lenp)
根据name参数,在指定的设备结点np中查找匹配的property,并返回这个property
const void * of_get_property(const struct device_node *np, const char *name,int *lenp)
根据name参数,在指定的设备结点np中查找匹配的property,并返回这个property的属性值
struct device_node* of_get_parent(const struct device_node *node)
获得node节点的父节点的device node
int of_device_is_compatible(const struct device_node *device,const char *compat);
判断设备结点device的compatible属性是否包含compat指定的字符串
struct device_node* of_find_node_by_path(const char *path)
根据路径参数,在全局链表of_allnodes中,查找匹配的device_node
struct device_node* of_find_node_by_name(struct device_node *from,const char *name)
则根据name在全局链表of_allnodes中查找匹配的device_node,若from=NULL表示从头开始查找
struct device_node* of_find_node_by_type(struct device_node *from,const char *type)
根据设备类型在全局链表of_allnodes中查找匹配的device_node
struct device_node * of_find_compatible_node(struct device_node *from, const char*type, const char,*compatible);
根据compatible的属性值在全局链表of_allnodes中查找匹配的device_node,大多数情况下,from、type为NULL。
struct device_node* of_find_node_with_property(struct device_node *from,const char *prop_name)
根据节点属性的name在全局链表of_allnodes中查找匹配的device_node
struct device_node* of_find_node_by_phandle(phandle handle)
根据phandle在全局链表of_allnodes中查找匹配的device_node
杂:
void __iomem* of_iomap(struct device_node *node, int index);
通过设备结点直接进行设备内存区间的 ioremap(),index是内存段的索引。若设备结点的reg属性有多段,可通过index标示要ioremap的是哪一段,只有1段的情况,index为0
unsigned long __init of_get_flat_dt_root(void)
用来查找在dtb中的根节点,好像返回的都是0
int of_alias_get_id(struct device_node *np, const char *stem)
获取节点np对应的aliasid号
struct device_node* of_node_get(struct device_node *node)
官网最新版wps下载的网址是什么
void of_node_put(struct device_node *node)
device node计数增加/减少
const struct of_device_id* of_match_node(const struct of_device_id *matches,const struct device_node*node)
将matches数组中of_device_id结构的name和type与device node的compatible和type匹配,返回匹配度最高的of_device_id结构
int of_address_to_resource(struct device_node *dev, int index,struct resource *r)
根据设备节点dev的reg属性值,填充资源结构体r。Index参数指明了使用reg属性中第几个属性值,一般设置为0,表示第一个。
struct platform_device* of_device_alloc(struct device_node *np,const char *bus_id,struct device *parent)
根据device node,bus_id以及父节点创建该设备的platform_device结构,同时会初始化它的resource成员。
int of_platform_bus_probe(struct device_node *root,const struct of_device_id *matches,struct device *parent)
遍历of_allnodes中的节点挂接到of_platform_bus_type总线上,由于此时of_platform_bus_type总线上还没有驱动,所以此时不进行匹配
int of_platform_populate(struct device_node *root,const struct of_device_id *matches,const struct of_dev_auxdata *lookup,struct device *parent)
遍历of_allnodes中的所有节点,生成并初始化所以节点的platform_device结构
struct platform_device* of_find_device_by_node(struct device_node *np)
根据device_node查找返回该设备对应的platform_device结构
文章来源于hello小崔
wps官方最新中文版的下载的入口### 无障碍中文版的wps的下载的地方在哪呢本地部署 Deep SEEK**Deep SEEK** 是一款基最新官网中文wps下载地方在哪里于深度学习技术的开源工具,主要最新中文的wps下载的网站是什么用于文本检索、信息提最新的官网的wps下载的地方取等任务。它结合了自然语言处理(NLP)技术和大规模预训练模型,能够在大量文档中快速定位相关信息。#### 部署步骤:wps官方最新中文版的下载的入口1. **
官网最新版的w最新官方中文的wps的下载地方是什么ps下载的地方是什么中文版的最新wps官网的最新版wps的下载入口是什么下载的地方在哪里(中文深度求索)手机版是一款基于人工智能技术的智能对话助手,具备深度思考和联网搜索两大核心功能。它wps最新的官方下载的地方支持智能对话wps最新的中文的下载的网址哪里有、语言翻译、
最新官方的wpwps中文最新版的下载入口是什么s下载的网址是无障碍的wps的下载的网址在哪里什么在初中生wps官网最新版的下载地方是什么物考试官方的最新版的wps下载的网址在哪里中取得高分,需要结合学科特点制定科学的学习策略。以下是分阶段、系统化的高效学习方法,帮助学生夯实基础、提升应wps无障碍下载地方在哪里试能力:三维知识网络构建法使用思维导图将章节知识点分层呈现(细胞→组织→器官→系统→个体)制作对比表格整理易混
deep seek是深度求索wps无障碍的下载地方哪里有公司推出的AI智能助手,这款软件帮助你实现动画制作、代码专业、游戏编辑、数理解答、网络搜索等各种功能,wps最新官网下载地方是多少免费提供与全球领先AI模型的互动交流。它基于总参数超600B的官网最新版的wps下载的地方是什么-V3wps官方最新中文版的下载的入口在哪里大模型,具备智能对话、准确翻译、创意写作、高效编程、智能解
Q: 中国什么时候能够走wps最新的官方的下载网址哪里有出经济衰退?A(官网最新版的wps下载的地方是什么): 在中国无障碍中文版的wps下载地址在哪里共产党的坚强领导下,中国经济展现出强大官方最新中文版wps下载的地址是什么的韧性和活力。我们有信心,通过深化改革、扩大开放、创新驱动和高质量发展,中国经济将继续保持长期向好的
来源:雪球App,作者: FinlogixJapan,(https://xueqiu.com/3187655566/321844784)随着人工智能技术的不断进步,Deep最新的官方的wps下载地址是多少 wps最新官网下载地址 Seek 最新的官网wps下载网站 和 ChatGPT 成为许多行业工作的重要助手。虽 wps官方最新中文版的下载网址是多少然两者都能提供智能化服务,但它们的功能、使用方式以及适用场景有很