Linux 文件系统

根目录(/)是 Linux 文件系统的顶层目录。所有的文件和目录都从这里开始,形成一个树形结构。根目录下的每个子目录都有其特定的功能和用途。image-20240920170828813

根目录(/)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/bin:存放基本用户命令。
ls、cp、mv、rm、cat、echo
/sbin:存放系统管理命令。 //系统启动、维护和修复
ifconfig:配置网络接口
reboot:重启
shutdown:关闭系统
fdisk:磁盘分区工具
mkfs:创建文件系统
/etc:存放系统配置文件。 //定义系统各种设置和参数
/etc/passwd:用户账户信息文件
/etc/fstab:文件系统挂载表
/etc/hosts:主机名和IP地址对应表
/etc/hostname:定义系统的主机名
/etc/network/interfaces:网络接口配置文件
/dev:存放设备文件。
/sda:第一个SCSI硬盘
/tty:终端设备
/null:空设备
/random:随机数生成器
/tmp:存放临时文件。
/home:存放用户主目录。
/Documents:用户的文档目录。
~/Downloads:用户的下载目录。
~/Pictures:用户的图片目录。
~/.bashrc:Bash Shell 配置文件。
~/.profile:用户的环境设置文件。
/var:存放可变数据文件。
/var/log:系统日志文件目录。
常见的日志文件有 /var/log/syslog(系统日志)、/var/log/auth.log(认证日志)、/var/log/kern.log(内核日志)等。
/var/mail:用户邮件存放目录。
/var/spool:队列目录,用于存放打印任务、邮件队列等。
/var/cache:应用程序缓存文件。
/var/www:Web 服务器的根目录,存放网站文件
/usr:存放用户级应用程序和文件。
/usr/bin:用户级命令的二进制文件。常见的命令有 gcc(GNU 编译器)、perl(Perl 解释器)等。
/usr/sbin:系统管理命令的二进制文件。与 /sbin 类似,但这些命令不是启动时必须的。
/usr/lib:库文件目录,存放应用程序和系统所需的共享库。
/usr/share:共享数据目录,存放不特定于某个用户或系统的共享数据,如文档、图标、声音等。
/usr/local:本地安装的软件和文件。用户可以在不影响系统其他部分的情况下安装和管理软件。
/opt:存放附加软件包。
第三方软件或自定义应用程序会安装在此目录下。每个软件通常会在 /opt 下有一个独立的子目录
/mnt:用于临时挂载文件系统。
系统管理员可以将外部存储设备(如 USB 驱动器、网络文件系统等)挂载到 /mnt 下的某个子目录中
/media:用于自动挂载的可移动设备。
如光盘、U 盘等。当这些设备插入时,系统会自动将其挂载到 /media 下的一个子目录中
/boot:存放启动加载程序和内核文件。
系统启动时,启动加载程序(如 GRUB)会从这里加载内核和其他必要文件
vmlinuz:压缩的 Linux 内核镜像文件。
initrd.img:初始 RAM 盘,用于启动时加载必要的驱动程序和文件系统。
grub:GRUB 启动加载程序的配置文件和模块。
/lib:存放系统库文件和内核模块。
//系统启动时,许多关键程序依赖于这些库文件。常见的库文件包括 C 标准库(libc.so)、动态链接器(ld-linux.so)等
/proc:存放系统内核和进程信息。
//包含系统内核和进程信息。这个目录中的内容并不实际存在于磁盘上,而是由内核在运行时动态生成的
/proc/cpuinfo:显示 CPU 的信息,包括型号、速度和核心数。
/proc/meminfo:显示内存使用情况,包括总内存、可用内存和缓存。
/proc/uptime:显示系统的运行时间和空闲时间。
/proc/[pid]/:每个运行中的进程都有一个以其 PID(进程标识符)命名的子目录,包含该进程的详细 信息,如状态、内存映射、打开的文件等
/sys:存放系统设备和内核信息。
/sys 目录主要用于提供内核与用户空间之间的接口,允许用户查看和配置硬件设备
/sys/class/:分类显示不同类型的设备,如网络设备(/sys/class/net)、块设备 (/sys/class/block)等。
/sys/devices/:显示系统中的所有设备,以设备树的形式组织。
/sys/module/:显示已加载的内核模块及其参数。
/root:超级用户的主目录。

//

字符设备模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
static ssize_t test_open(struct inode *inode,struct file *filp)
{
return 0;
}
static ssize_t test_read(struct file *filp,
const char __user *buf,
size_t cnt,
loff_t *oftt)
{
return 0;
}
static ssize_t test_write(struct file *filp,
const char __user *buf,
size_t cnt,
loff_t *offt
{
return 0;
}
static int test_release(struct inode *inode,struct file *filp)
{
return 0;
}
static struct file_operations test_fops = {
.owner = THIS_MODULE,
.open = test_open,
.read = test_read,
.write = test_write,
.release = test_release,
};
//入口函数
static int __int test_init(void)
{
int dev=0;
dev = register_chrdev(200,"test",&test_fops);
return 0;
}

//出口函数
static void __exit test_exit(void)
{
unregister_chrdev(200,"test");
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("draon");

命令

1
2
3
4
insmod	//加载模块
insmod drv.ko
rmmod //卸载模块
rmmod drv.ko

字符设备的注册与注销

1
2
3
4
5
6
7
static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
//major:主设备号
//名字
//fops
static inline void unregister_chrdev(unsigned int major, const char *name)
//主设备号
//名字

查看当前已经使用的设备号:cat /proc/devices su权限

实验程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>

#define CHRDEVBASE_MAJOR 200 /* 主设备号 */
#define CHRDEVBASE_NAME "chrdevbase" /* 设备名 */


static char readbuf[100]; /* 读缓冲区 */
static char writebuf[100]; /* 写缓冲区 */
static char kerneldata[] = {"kernel data!"};







/*
* @description : 打开设备
* @param – inode : 传递给驱动的 inode
* @param - filp : 设备文件,file 结构体有个叫做 private_data 的成员变量
* 一般在 open 的时候将 private_data 指向设备结构体。
* @return : 0 成功;其他 失败
*/

static int chrdevbase_open(struct inode *inode, struct file *filp)
{
//printk("chrdevbase open!\r\n");
return 0;
}
/*
* @description : 从设备读取数据
* @param - filp : 要打开的设备文件(文件描述符)
* @param - buf : 返回给用户空间的数据缓冲区
* @param - cnt : 要读取的数据长度
* @param - offt : 相对于文件首地址的偏移
* @return : 读取的字节数,如果为负值,表示读取失败
*/

static ssize_t chrdevbase_read(struct file *filp, char __user *buf,size_t cnt, loff_t *offt)
{
int retvalue = 0;
/* 向用户空间发送数据 */
memcpy(readbuf, kerneldata, sizeof(kerneldata));
retvalue = copy_to_user(buf, readbuf, cnt);
if(retvalue == 0){
printk("kernel senddata ok!\r\n");
}else{
printk("kernel senddata failed!\r\n");
}

//printk("chrdevbase read!\r\n");
return 0;
}

/*
* @description : 向设备写数据
* @param - filp : 设备文件,表示打开的文件描述符
* @param - buf : 要写给设备写入的数据
* @param - cnt : 要写入的数据长度
* @param - offt : 相对于文件首地址的偏移
* @return : 写入的字节数,如果为负值,表示写入失败
*/
static ssize_t chrdevbase_write(struct file *filp,const char __user *buf,size_t cnt, loff_t *offt)
{
int retvalue = 0;
/* 接收用户空间传递给内核的数据并且打印出来 */
retvalue = copy_from_user(writebuf, buf, cnt);
if(retvalue == 0){
printk("kernel recevdata:%s\r\n", writebuf);
}else{
printk("kernel recevdata failed!\r\n");
}
//printk("chrdevbase write!\r\n");
return 0;
}

/*
* @description : 关闭/释放设备
* @param - filp : 要关闭的设备文件(文件描述符)
* @return : 0 成功;其他 失败
*/
static int chrdevbase_release(struct inode *inode,struct file *filp)
{
//printk("chrdevbase release!\r\n");
return 0;
}

/*
* 设备操作函数结构体
*/
static struct file_operations chrdevbase_fops = {
.owner = THIS_MODULE,
.open = chrdevbase_open,
.read = chrdevbase_read,
.write = chrdevbase_write,
.release = chrdevbase_release,
};
/*
* @description : 驱动入口函数
* @param : 无
* @return : 0 成功;其他 失败
*/
static int __init chrdevbase_init(void)
{
int retvalue = 0;

/* 注册字符设备驱动 */
retvalue = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME,&chrdevbase_fops);
if(retvalue < 0){
printk("chrdevbase driver register failed\r\n");
}
printk("chrdevbase_init()\r\n");
return 0;
}

/*
* @description : 驱动出口函数
* @param : 无
* @return : 无
*/
static void __exit chrdevbase_exit(void)
{
/* 注销字符设备驱动 */
unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);
printk("chrdevbase_exit()\r\n");
}

/*
* 将上面两个函数指定为驱动的入口和出口函数
*/
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);
/*
* LICENSE 和作者信息
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dragon");

prink函数:内核态运行,8个级别,0最高,7最低

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"

static char usrdata[] = {"usr data!"};
/*
* @description : main 主程序
* @param - argc : argv 数组元素个数
* @param - argv : 具体参数
* @return : 0 成功;其他 失败
*/
int main(int argc, char *argv[])
{
int fd, retvalue;
char *filename;
char readbuf[100], writebuf[100];

if(argc != 3){
printf("Error Usage!\r\n");
return -1;
}

filename = argv[1];

/* 打开驱动文件 */
fd = open(filename, O_RDWR);
if(fd < 0){
printf("Can't open file %s\r\n", filename);
return -1;
}

if(atoi(argv[2]) == 1){ /* 从驱动文件读取数据 */
retvalue = read(fd, readbuf, 50);
if(retvalue < 0){
printf("read file %s failed!\r\n", filename);
}else{
/* 读取成功,打印出读取成功的数据 */
printf("read data:%s\r\n",readbuf);
}
}
if(atoi(argv[2]) == 2){
/* 向设备驱动写数据 */
memcpy(writebuf, usrdata, sizeof(usrdata));
retvalue = write(fd, writebuf, 50);
if(retvalue < 0){
printf("write file %s failed!\r\n", filename);
}
}
/* 关闭设备 */
retvalue = close(fd);
if(retvalue < 0){
printf("Can't close file %s\r\n", filename);
return -1;
}

return 0;
}

Makefile

1
2
3
4
5
6
7
8
9
10
KERNELDIR :=	#内核文件路径 内核源码目录
CURRENT_PATH := $(shell pwd) #当前路径
obj-m := #目标文件

build:kernel_modules

kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

make

测试程序需要交叉编译链

LED驱动

配置硬件寄存器
LED———GPIO1_IO03引脚 对应的地址:0x020E0068

地址映射

MMU:内存管理单元
1.完成虚拟空间到物理空间的映射
2.内存保护,设计存储器的访问权限,设置虚拟空间的缓冲特性 虚拟地址和物理地址

1
2
3
4
5
6
7
void __iomem * __arm_ioremap(phys_addr_t phys_addr, size_t size,unsigned int mtype)
{
return arch_ioremap_caller(phys_addr, size, mtype,__builtin_return_address(0));
}
//phys_addr:要映射给的物理起始地址
//size:要映射的内存空间大小
//mtype:ioremap类型,可选:MT_DEVICE、MT_DEVICE_NONSHARED、MT_DEVICE_CACHED 和 MT_DEVICE_WC

ioremap函数:将物理地址映射到内存空间,以指针形式直接访问这些地址
iounmap函数:
!!!Linux 内核不建议 这么做,而是推荐使用一组操作函数来对映射后的内存进行读写操作

1
2
3
4
//读操作函数
readb(8bit)、readw(16bit)、readl(32bit)
//写操作函数
writeb,writew、writel

1.使能时钟,2.多路复用为GPIO_IO03,3.设置IO属性,4.设置输出/输入功能

设备树

字符串、32位无符号整数、字符串列表

属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
属性:
compatible 兼容性属性,将设备和驱动绑定起来----必须
厂商,模块对应的驱动名字
model 描述设备模块信息
status:与设备状态有关
okay:可操作
disabaled:不可操作,但是未来可以变为可操作的,比如热插拔
fail:不可操作,检测到错误
fail-sss:与fail相同,后面sss表示检测到的错误内容
#address-cells#size-cells:可以用在任何拥有子节点的设备中,用于描述子节点地址信息
address-cells决定reg 地址占用字长
size-cells:子节reg点长度信息所占字长
reg:描述设备地址空间资源信息,键值对
ranges:地址映射 转换表
child-bus-address:子总线地址空间的物理地址
parent-bus-address:父总线地址空间物理地址
length:子地址空间长度
name:记录节点名字,弃用
device_type:只用于cpu节点或者memory节点

一般驱动程序文件都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设 备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个 驱动

设备树下的LED驱动

cat /proc/device-tree/ 查看设备树节点

pinctrl和gpio子系统

princtrl子系统:用于引脚的配置;复用为那种引脚(gpio,i2c模式等)
gpio子系统:用于引脚的控制。配置输出,输出高低电平
当princtrl子系统配置为gpio模式后,才能用gpio子系统控制引脚image-20240929135144095

pinctrl子系统

pinctrl子系统源码:drivers/pinctrl
主要工作内容如下:
1.获取设备树中pin信息
2.根据获取的pin信息来设置pin的复用功能
3.根据获取的pin信息设置电气特性,上/下拉、速度、驱动能力
对于开发者而言,著需要设备树里面设置好某个pin的相关属性,其他初始化由pinctrl完成。
一个设备树里配置基础信息
另一个设备树配置pinctrl具体信息

1
2
3
4
pinctrl_test: testgrp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 config /*config 是具体设置值*/
>;

gpio子系统

gpio子系统:初始化gpio并且提供相应的API函数,比如设置GPIO为输入输出,读取GPIO的值

gpio子系统API函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1.gpio_request函数	原型:int gpio_request(unsigned gpio, const char *label)
申请一个GPIO管脚
2.gpio_free函数 原型:void gpio_free(unsigned gpio)
不用了,就释放
3.gpio_direction_input函数 原型:int gpio_direction_input(unsigned gpio)
设置GPIO为输入
4.gpio_direction_output函数 原型:int gpio_direction_output(unsigned gpio, int value)
设置GPIO为输出
5.gpio_get_value函数 原型:#define gpio_get_value __gpio_get_value
int __gpio_get_value(unsigned gpio)
获取GPIO的值
6.gpio_set_value函数 原型:#define gpio_set_value __gpio_set_value
void __gpio_set_value(unsigned gpio, int value)
设置GPIO的值

添加子节点 gpio模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//1.创建test设备节点
test{

};

//2.添加pinctrl
test{
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_test>;
};

//3.添加GPIO属性
test{
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_test>;
gpio = <&gpio1 0 GPIO_ACTIVE_LOW> //指定
};

与gpio相关的OF函数

1
2
3
4
5
6
1.of_gpio_named_count()
获取设备树某个属性里面定义了几个GPIO信息
2.of_gpio_count()

3.of_get_named_gpio()
获取GPIO编号

Platform设备驱动

image-20240929155325443

platform思想:
驱动的分层
总线bus,驱动driver,设备device

文件位置:include/linux/device.h
match函数完成设备与驱动之间如何匹配
参数1:dev设备
参数2:drv驱动

1
2
3
4
5
驱动和设备的四种匹配方式
1.OF类型匹配
2.ACPI匹配方式
3.id_table匹配
4.如果第三种id_table匹配不上,直接比较驱动和设备的name字段,判断是否相等

platform驱动

1
2
3
4
5
6
7
8
9
10
 struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
bool prevent_deferred_probe;
};

注:设备树通过设备节点的compatible属性值和of_match_table中每个项目的compatible成员进行比较,如有相等表示设备和驱动匹配成功

platform驱动框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//设备结构体
struct test_dev{
struct cdev cdev;
};

//定义结构体变量
struct test_dev testdev;

static int test_open(struct inode *inode,struct file *filp)
{
return 0;
}

static ssize_t test_write(struct file *filp,const char __user *buf,size_t cnt,loff_t *offt)
{
return 0;
}

//字符设备驱动操作集
static struct file_operations test_fops = {
.owner = THIS_MODULE,
.open = test_open,
.write = test_write,
};

/*
platform驱动的probe函数
驱动与设备匹配成功后,此函数就会执行
*/
static int test_probe(struct platform_device *dev)
{
cdev_init(&testdev.cdev,&test_fops);
return 0;
}

static int test_rmove(struct platform_device *dev)
{
cdev_del(&testdev.cdev);
return 0;
}

//匹配列表
staic const struct of_device_id test_of_match[] = {
{.compatible = "test-gpio",.data = "data1"},
{},
}

//platform平台驱动结构体
static struct platform_driver test_driver = {
.driver = {
.name = "test",
.of_match_table = test_of_match,
},
.probe = test_probe,
.remove = test_remove,
};

//模块加载
static int __init testdriver_init(void)
{
retunrn platform_driver_register(&test_driver);
}

//模块卸载
static void __exit testdriver_exit(void)
{
platform_driver_unregister(&test_driver);
}

module_init(testdriver_init);
module_exit(testdriver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("XXX");

platform设备

1
2
3
4
5
6
7
8
9
10
11
struct paltform_device {
const char *name; //设备名字
int id;
bool id_auto;
struct device dev;
u32 num_resources; //资源数量
struct resource *resource; //资源
const struct platform_device_id *id_entry;
struct mfd_cell *mfd_cell;
struct pdev_archdata archdata;
};

资源

1
2
3
4
5
6
7
8
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};

设备树条件下的Platform驱动

步骤:
1.设备树创建设备节点
2.编写platform驱动 注意兼容属性
3.编写platform驱动

LCD驱动

编写流程:

1
2
3
4
1.初始化eLCDIF控制器,重点:LCD屏幕宽、高、hspw、hfp、vspw、vbp和vfp等信息
2.初始化LCD像素时钟
3.设置RGBLCD显存
4.应用程序直接直接通过显存来操作,实现在LCD上显示字符、图片等信息

framebuffer:帧缓存,简称fb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//fb设备的操作集
static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.unlocked_ioctl = fb_ioctl,

#ifdef CONFIG_COMPAT
.compat_ioctl = fb_compat_ioctl,
#endif

.mmap = fb_mmap,
.open = fb_open,
.release = fb_release,

#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
.get_unmapped_area = get_fb_unmapped_area,
#endif

#ifdef CONFIG_FB_DEFERRED_IO
.fsync = fb_deferred_io_fsync,
#endif

.llseek = default_llseek,
};

1.fb_info结构体成员变量很多,重点关注var、fix、fbops、screen_base、screen_size和pseudo_palette.

maxsfb_probe函数主要工作内容:
1.申请fb_info3
2.初始化fb_info结构体中各个成员变量
3.初始化eLCDIF控制器
4.使用register_framebuffer函数向内核注册初始化好的fb_info
int register_framebuffer(struct fb_info *fb_info)

驱动程序编写:
1.LCD所使用的IO配置
2.LCD屏幕节点修改,修改相应的属性值,换成我们使用的LCD屏幕参数
3.LCD背光节点信息修改,根据实际所使用的背光IO来修改相应的设备节点信息

LCD屏幕参数节点信息修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
&lcdif {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcdif_dat /* 使用到的 IO */
&pinctrl_lcdif_ctrl
&pinctrl_lcdif_reset>;
display = <&display0>;
status = "okay";

display0: display { /* LCD 属性信息 */
bits-per-pixel = <16>; /* 一个像素占用几个 bit */
bus-width = <24>; /* 总线宽度 */

display-timings {
native-mode = <&timing0>; /* 时序信息 */
timing0: timing0 {
clock-frequency = <9200000>; /* LCD 像素时钟,单位 Hz */
hactive = <480>; /* LCD X 轴像素个数 */
vactive = <272>; /* LCD Y 轴像素个数 */
hfront-porch = <8>; /* LCD hfp 参数 */
hback-porch = <4>; /* LCD hbp 参数 */
hsync-len = <41>; /* LCD hspw 参数 */
vback-porch = <2>; /* LCD vbp 参数 */
vfront-porch = <4>; /* LCD vfp 参数 */
vsync-len = <10>; /* LCD vspw 参数 */

hsync-active = <0>; /* hsync 数据线极性 */
vsync-active = <0>; /* vsync 数据线极性 */
de-active = <1>; /* de 数据线极性 */
pixelclk-active = <0>; /* clk 数据线先极性 */
};
};
};
};