驱动程序开发:Buildroot根文件系统构建并加载驱动文件xxx.ko测试
目录
- 一、buildroot根文件系统简介
- 二、buildroot下载
- 三、buildroot构建根文件系统
- 1、配置 buildroot
- ①配置 Target options
- ②配置 Toolchain
- ③配置 System configuration
- ④配置 Filesystem images
- ⑤禁止编译 Linux 内核和 uboot
- 2、 buildroot 下的 busybox 配置
- ①修改 Makefile,添加编译器
- ②busybox 中文字符支持
- ③配置 busybox
- ④编译busybox
- 3、编译buildroot
- 4、buildroot 根文件系统测试
- ①创建/lib/modules/4.1.15文件夹
- ①让命令行显示当前目录路径
- 四、加载驱动程序xxx.ko文件测试
- 1、将icm20608.ko文件拷贝到/buildroot/lib/modules/4.1.15目录下,如下图所示:
- 2、使用depmod命令驱动挂载
- 3、使用modprobe命令加载驱动,如下图所示:
- 4、使用icm20608APP应用程序测试,如下图所示:
- 5、使用lsmod查看当前加载的驱动程序和使用rmmod卸载驱动程序,如下图所示:
一、buildroot根文件系统简介
buildroot 构建的根文件系统相对比较齐全,很多东西需要它会自行添加,比如 lib 库文件。并且,如果单纯使用busybox的话,在后面的驱动开发中很多第三方软件也需要我们自己去移植,这些第三方软件有很多又依赖其他的库文件,导致移植过程非常的繁琐,而buildroot可以为我们省去这些大部分的麻烦。
二、buildroot下载
buildroot 官网下载地址为https://buildroot.org/。如下图所示:
三、buildroot构建根文件系统
1、配置 buildroot
将下载的buildroot源码拷贝到ubuntu中,然后对其进行解压,操作命令如下:
tar -vxjf buildroot-2019.02.6.tar.bz2
解压完成以后就会得到一个名为“buildroot-2019.02.6”的目录,此目录就是我们解压得到的 buildroot 源码,进入到此目录中,此目录如下图所示:
buildroot 和 uboot、 Linux kernel 一样也支持图形化配置,输入如下命令即可打开图形化配置界:
make menuconfig
打开以后的图形化配置界面如下图所示:
①配置 Target options
首先配置 Target options 选项,需要配置的项目和其对应的内容如下(“=”号后面是配置项
要选择的内容!):
Target options
-> Target Architecture = ARM (little endian)
-> Target Binary Format = ELF
-> Target Architecture Variant = cortex-A7
-> Target ABI = EABIhf
-> Floating point strategy = NEON/VFPv4
-> ARM instruction set = ARM
配置完成以后如下图所示:
②配置 Toolchain
③配置 System configuration
④配置 Filesystem images
⑤禁止编译 Linux 内核和 uboot
2、 buildroot 下的 busybox 配置
buildroot 在构建根文件系统的时候也是要用到 busybox 的,既然用到了 busybox 那么就涉及到 busybox 的配置。 buildroot 会自动下载 busybox 压缩包, buildroot 下载的源码压缩包都存放在/dl 目录下,在 dl 目录下就有一个叫做“busybox”的文件夹,此目录下保存着 busybox 压缩包,如下图所示:
可以看出, buildroot 下载的 busybox 版本为 1.29.3。要想编译 busybox,必须对上图中的压缩包进行解压缩, buildroot 将所有解压缩后的软件保存在/output/build 软件中,我们可以在找到/output/build/busybox-1.29.3 这个文件夹,此文件夹就是解压后的 busybox 源码,文件内容如下图所示:
①修改 Makefile,添加编译器
打开 busybox 的顶层 Makefile,添加 ARCH 和 CROSS_COMPILE的值,如下所示:
164 CROSS_COMPILE ?= /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
…
190 ARCH ?= arm
注意:CORSS_COMPILE 使用了绝对路径!主要是为了防止编译出错。
②busybox 中文字符支持
修改 busybox 源码,取消 busybox 对中文显示的限制,打开文件 busybox-1.29.3/libbb/printable_string.c,找到函数 printable_string,缩减后的函数内容如下:
12 const char* FAST_FUNC printable_string(uni_stat_t *stats, const char
*str)
13 {
14 char *dst;
15 const char *s;
16
17 s = str;
18 while (1) {
19 unsigned char c = *s;
20 if (c == '\0') {
......
28 }
29 if (c < ' ')
30 break;
31 if (c >= 0x7f)
32 break;
33 s++;
34 }
35
36 #if ENABLE_UNICODE_SUPPORT
37 dst = unicode_conv_to_printable(stats, str);
38 #else
39 {
40 char *d = dst = xstrdup(str);
41 while (1) {
42 unsigned char c = *d;
43 if (c == '\0')
44 break;
45 if (c < ' ' || c >= 0x7f)
46 *d = '?';
47 d++;
48 }
......
55 #endif
56 return auto_string(dst);
57 }
如果支持 UNICODE 码的话,当字符大于 0X7F 就直接输出‘?’。所以我们需要对这 4 行代码进行修改,修改以后如下所示:
12 const char* FAST_FUNC printable_string(uni_stat_t *stats, const char
*str)
13 {
14 char *dst;
15 const char *s;
16
17 s = str;
18 while (1) {
......
30 if (c < ' ')
31 break;
32 /* 注释掉下面这个两行代码 */
33 /* if (c >= 0x7f)
34 break; */
35 s++;
36 }
37
38 #if ENABLE_UNICODE_SUPPORT
39 dst = unicode_conv_to_printable(stats, str);
40 #else
41 {
42 char *d = dst = xstrdup(str);
43 while (1) {
44 unsigned char c = *d;
45 if (c == '\0')
46 break;
47 /* 修改下面代码 */
48 /* if (c < ' ' || c >= 0x7f) */
49 if( c < ' ')
50 *d = '?';
51 d++;
52 }
......
59 #endif
60 return auto_string(dst);
61 }
接着打开文件 busybox1.29.3/libbb/unicode.c,找到如下内容(修改后):
1003 static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t*stats, const char *src, unsigned width, int flags)
1004 {
1005 char *dst;
1006 unsigned dst_len;
1007 unsigned uni_count;
1008 unsigned uni_width;
1009
1010 if (unicode_status != UNICODE_ON) {
1011 char *d;
1012 if (flags & UNI_FLAG_PAD) {
1013 d = dst = xmalloc(width + 1);
......
1022 /* 修改下面一行代码 */
1023 /* *d++ = (c >= ' ' && c < 0x7f) ? c : '?'; */
1024 *d++ = (c >= ' ') ? c : '?';
1025 src++;
1026 }
1027 *d = '\0';
1028 } else {
1029 d = dst = xstrndup(src, width);
1030 while (*d) {
1031 unsigned char c = *d;
1032 /* 修改下面一行代码 */
1033 /* if (c < ' ' || c >= 0x7f) */
1034 if(c < ' ')
1035 *d = '?';
1036 d++;
1037 }
1038 }
......
1044 return dst;
1045 }
......
1047
1048 return dst;
1049 }
③配置 busybox
配置 buildroot 下的 busybox,因此打开 busybox 的配置界面,命令(两种打开方式)如下:
sudo make busybox-menuconfig
在buildroot根目录下
sudo make menuconfig在/output/build/busybox-1.29.3 目录下
配置界面如下图所示:
不采用静态编译,配置路径如下:
选项“Build static binary (no shared libs)”用来决定是静态编译 busybox 还是动态编译,静态编译的话就不需要库文件,但是编译出来的库会很大。动态编译的话要求根文件系统中有库文件,但是编译出来的 busybox 会小很多。这里我们不能采用静态编译!因为采用静态编译的话 DNS 会出问题!无法进行域名解析,配置如图下所示:
选择vi风格的行编辑命令,配置路径如下:
取消勾选Simplified modutils,配置路径如下:
使能系统启动和热插拔或动态加载驱动程序时,自动产生驱动程序所需的节点文件作用的选项mdev,配置路径如下:
使能 busybox 的 unicode 编码以支持中文,配置路径如下:
注意!
退出 linux Modules Utilites后 返回步骤 1 界面;在步骤 1界面选择最后一项 Save configuration to an alternate file,进入如下图界面:
在buildroot-2019.02.6/output/build/busybox-1.29.3目录下会生成busybox.config文件,如下图所示:
将buildroot-2019.02.6/package/busybox/busybox.config文件替换成上一步生成的buildroot-2019.02.6/output/build/busybox-1.29.3/busybox.config文件,如下图所示:
④编译busybox
查看当前 buildroot 所有配置了的目标软件包,也就是 packages,命令如下:
sudo make show-targets
单独编译并安装 busybox 如下命令:
sudo make busybox
3、编译buildroot
编译 buildroot,主要是对其进行打包,输入如下命令:
sudo make
然后在output/images目录下查看是否生成了rootfs.tar压缩包,如下图所示:
在 nfs 目录下新建一个名为 buildrootfs 的文件夹,然后将上图 中的 rootfs.tar 拷贝到 buildrootfs 目录下并解压,命令如下:
cd /home/djw/linux/nfs //进入到 nfs 目录下
mkdir buildrootfs //创建 buildrootfs 目录
cd buildrootfs //进入到 buildrootfs 目录
cp …/…/IMX6ULL/tool/buildroot-2019.02.6/output/images/rootfs.tar ./ //拷贝到 rootfs.tar
tar -vxf rootfs.tar //解压缩 rootfs.tar
rm rootfs.tar //删除 rootfs.tar
解压缩完成以后的 buildrootfs 目录如下图所示:
4、buildroot 根文件系统测试
buildroot 制作出来的根文件系统已经准备好了,接下来就是对其进行测试。测试方法也是通过 nfs 挂载的方式,启动 uboot,修改 bootargs 环境变量,设置 nfsroot 目录为 Ubuntu 中的buildrootfs 目录,命令如下:
setenv bootargs 'console=tty1 console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.111:
/home/djw/linux/nfs/buildrootfs rw ip=192.168.1.119:192.168.1.111:192.168.1.1:255.255.
255.0::eth0:off
这里我们重点说一下另外一个问题,我们使用构建的根文件系统启动以后会发现,输入命令的时候命令行前面一直都是“#”,如果我们进入到某个目录的话前面并不会显示当前目录路径,如下图 所示:
由上面可知,有两个问题,第一个是缺少/lib/modules文件夹,第二个是命令行不显示当前目录路径。
①创建/lib/modules/4.1.15文件夹
modprobe 命令主要智能在提供了模块的依赖性分析、错误检查、错误报告等功能,推荐使用 modprobe 命令来加载驱动。 modprobe 命令默认会去/lib/modules/目录中查找模块,我使用的 Linux kernel 的版本号为 4.1.15,因此 modprobe 命令默认会到/lib/modules/4.1.15 这个目录中查找相应的驱动模块,一般自己制作的根文件系统中是不会有这个目录的,所以需要自己手动创建,如下图所示:
①让命令行显示当前目录路径
先了解一下“PS1”这个环境变量, PS1 用于设置命令提示符格式,格式如下:
打开/etc/profile 文件,修改好后如下图所示:
etc/profile 文件修改完成以后重启开发板,这个时候我们就如到某个目录的时候命令行就会有提示,如下图所示:
四、加载驱动程序xxx.ko文件测试
1、将icm20608.ko文件拷贝到/buildroot/lib/modules/4.1.15目录下,如下图所示:
2、使用depmod命令驱动挂载
输入“depmod”命令以后会自动生成 modules.alias、modules.symbols 和 modules.dep 这三个文件,如下图所示:
3、使用modprobe命令加载驱动,如下图所示:
4、使用icm20608APP应用程序测试,如下图所示:
5、使用lsmod查看当前加载的驱动程序和使用rmmod卸载驱动程序,如下图所示:
相关文章:
驱动程序开发:Buildroot根文件系统构建并加载驱动文件xxx.ko测试
目录一、buildroot根文件系统简介二、buildroot下载三、buildroot构建根文件系统1、配置 buildroot①配置 Target options②配置 Toolchain③配置 System configuration④配置 Filesystem images⑤禁止编译 Linux 内核和 uboot2、 buildroot 下的 busybox 配置①修改 Makefile&…...
R+VIC模型融合实践技术应用及未来气候变化模型预测
目录 理论专题一:VIC模型的原理及特点 综合案例一:基于QGIS的VIC模型建模 理论专题二:VIC模型率定验证 综合案例二:基于R语言VIC参数率定和优化 理论专题三:遥感技术与未来气候变化 综合案例三:运用V…...
第六章.决策树(Decision Tree)—ID3算法,C4.5算法
第六章.决策树(Decision Tree) 6.1 ID3算法,C4.5算法 1.决策树适用的数据类型 比较适合分析离散数据,如果是连续数据要先转换成离散数据再做分析 2.信息熵 1).概念: 一条信息的信息量大小和它的不确定性有直接的关系,要搞清楚一件非常不确…...
springboot+pgbouncer+postgres数据库连接池集成方案及问题解决
期望通过每一次分享,让技术的门槛变低,落地更容易。 —— around 前言 旨在解决微服务项目全是连接池并影响数据库并发连接,作者的环境是基于sprongboot微服务连接postgres数据库,每个微服务的DAO层配置都使用了连接池技术。后续…...
Mysql 常用日期处理函数
Mysql 常用日期处理函数 1 建表语句 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0; -- ---------------------------- -- Table structure for emp -- ---------------------------- DROP TABLE IF EXISTS emp; CREATE TABLE emp (EMPNO int(4) NOT NULL,ENAME varchar(10…...
Pod中容器的健康检查
健康检查 上篇文章中我们了解了Pod中容器的生命周期的两个钩子函数,PostStart与PreStop,其中PostStart是在容器创建后立即执行的,而PreStop这个钩子函数则是在容器终止之前执行的。除了上面这两个钩子函数以外,还有一项配置会影响…...
信贷系统学习总结(5)—— 简单的风控示例(含代码)
一、背景1.为什么要做风控?目前我们业务有使用到非常多的AI能力,如ocr识别、语音测评等,这些能力往往都比较费钱或者费资源,所以在产品层面也希望我们对用户的能力使用次数做一定的限制,因此风控是必须的!2.为什么要自己写风控?那么多开源的风控组件,为什么还要写呢?是不是想…...
Java知识复习(四)多线程、并发编程
1、进程、线程和程序 进程:进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的;在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程…...
一个9个月测试经验的人,居然在面试时跟我要18K,我都被他吓到了····
2月初我入职了深圳某家创业公司,刚入职还是很兴奋的,到公司一看我傻了,公司除了我一个测试,公司的开发人员就只有3个前端2个后端还有2个UI,在粗略了解公司的业务后才发现是一个从零开始的项目,目前啥都没有…...
zigbee与WIFI同频干扰问题
zigbee与WIFI同频干扰 为了降低Wifi信道与Zigbee信道的同频干扰问题,Zigbee联盟在《Zigbee Home Automation Public Application Profile》中推荐使用11,14,15,19,20,24,25这七个信道。 为什么呢,我们看一下Wifi和Zigbee的信道分布。 WiFi带宽对干扰的…...
git拉取指定的单个或多个文件或文件夹
直接上步骤 初始化仓库 git init拉取远程仓库信息,省略号为仓库地址 git remote add -f origin http://****.git开启 sparse clone git config core.sparsecheckout true配置需要拉取的文件夹 有一个指定一个,有多个指定多个,路径写对即可&a…...
不是,到底有多少种图片懒加载方式?
一、也是我最开始了解到的 js方法,利用滚动事件,判断当时的图片位置是否在可视框内,然后进行渲染。 弊端:代码冗杂,你还要去监听页面的滚动事件,这本身就是一个不建议监听的事件,即便是我们做了…...
CAD坐标有哪些输入方式?来看看这些CAD坐标输入方式!
在CAD设计过程中,有时需要通过已知坐标点来画图,有时又需要通过已知角度和距离来画图,在这种情况下,由于已知条件不同,所以便需要用不同的方式来定位点。那么,你知道CAD坐标有哪些输入方式吗?本…...
铰链、弹簧,特殊的物理关节
title: 铰链、弹簧,特殊的物理关节 date: 2023-02-28T13:32:57Z lastmod: 2023-02-28T14:24:06Z 铰链关节(Hinge Join)组件 组件-Physics-Hinge Join Anchor 当物体挂载铰链组件以后,组件下Anchor等同于边长为1的立方体。当这…...
Android Studio相关记录
目录Android Studio 便捷插件Android LogcatJava文件的类头模板Android Studio 使用遇到的问题解决方案org.jetbrains.annotations.NullableBuild 控制台编译输出中文乱码Terminal 使用 git 命令窗口git 命令窗口中文乱码Android Studio 便捷插件 Android Logcat 配置路径 Fi…...
Linux 基础介绍-基础命令
文章目录01 学习目标02 Linux/Unix 操作系统简介2.1 Linux 操作系统的目标2.2 Linux 操作系统的作用2.3 Unix 家族历史2.4 Linux 家族历史2.5 Linux 和Unix 的联系2.6 Linux 内核介绍2.7 Linux 发行版本2.8 Unix/Linux 开发应用领域介绍03 Linux 目录结构3.1 Win 和Linux 文件系…...
Linux 进程:程序地址空间 与 虚拟内存
目录一、程序地址空间二、虚拟地址空间1.虚拟内存的原理2.使用虚拟内存的原因?3.如何实现虚拟空间?4.使用虚拟内存的好处本文主要介绍程序地址空间和虚拟地址空间的概念,理解了虚拟地址空间,才可以更好的理解物理内存和进程pcb之间…...
python 密码学编程
最近在看一本书。名字是 python密码学编程。在此做一些笔记,同时也为有需要的人提供一些参考。 ******************************************************************** * quote : "http://inventwithpython.com/" …...
【C++ | bug | 运算符重载】定义矩阵(模板)类时,使用 “友元函数” 进行 * 运算符重载时编译报错
作者:非妃是公主 专栏:《C》 博客地址:https://blog.csdn.net/myf_666 个性签:顺境不惰,逆境不馁,以心制境,万事可成。——曾国藩 文章目录专栏推荐一、类的声明及函数定义二、错误信息三、问题…...
数学小课堂:无穷小(以动态的眼光看待世界,理解无限的世界)
文章目录 引言I 芝诺四个著名的悖论1.1 二分法悖论:从A点到B点是不可能的。1.2 阿喀琉斯悖论:阿喀琉斯追不上乌龟。1.3 飞箭不动悖论:射出去的箭是静止的。1.4 基本空间和相对运动悖论II 回答芝诺的悖论2.1 阿喀琉斯悖论2.2 相对运动悖论III 无穷小3.1 无穷小的定义3.1 无穷…...
leetcode 427. Construct Quad Tree(构建四叉树)
刚看到题的时候是懵的,这也太长了。到底是要表达什么呢。 不妨把这个矩阵看成一个正方形的图片,想象你在处理图片,从整体逐步到局部。 刚开始看一整张图片,如果是全0或全1,这个就是叶子节点,怎么表达叶子节…...
Spring Boot 3.0系列【2】部署篇之使用GraalVM构建原生镜像
有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot版本2.7.0 文章目录概述JIT & AOTJIT (动态编译)AOT(静态编译)GraalVM简介运行模式Native Image(原生镜像)…...
复习知识点十之方法的重载
目录 方法的重载 练习1: 练习1: 数组遍历 练习2: 数组的最大值 练习3: 练习4: 复制数组 基本数据类型和引用数据类型 方法的重载 Java虚拟机会通过参数的不同来区分同名的方法 练习1: public class Test4 {public static void main(String[] args) {//调用方法 // …...
火爆全网的ChatGPT 和AI 可以为项目经理做什么?
作为一款人工智能聊天机器人,ChatGPT因其逼真和人性化的特性而风靡全球,无疑是当今技术的新流行。人工智能 (AI) 有可能彻底改变许多行业,包括项目管理,及时了解最新技术以及它如何影响你的工作至关重要。于是,我们与C…...
前端面试题 —— HTML
目录 一、src 和 href 的区别 二、对 HTML 语义化的理解 三、DOCTYPE(⽂档类型) 的作⽤ 四、script 标签中 defer 和 async 的区别 五、常⽤的 meta 标签有哪些? 六、HTML5 有哪些更新 八、行内元素有哪些?块级元素有哪些? 空(void)元素…...
同为(TOWE)电源线让家用电器随心放置
如今,随着科技水平的不断发展,人们工作、生活中越来越离不开各类电子设备和电器产品。当用电器数量多了以后,由于电器设备原有电线长度的限制,常常需要通过连接接线板来延长电器设备的电能传输线路。电源线虽然看着是一件不起眼的…...
2023上半年数学建模竞赛汇总(报名时间、比赛时间、难易程度、含金量、竞赛官网)
1、美国大学生数学建模竞赛等级:国家级是否可跨校:否竞赛开始时间:2月17日~2月21日综合难度:⭐⭐⭐⭐ 竞赛含金量:⭐⭐⭐⭐⭐竞赛官网:https://www.comap.com/2、MathorCup高校数学建模挑战赛---大数据竞赛…...
RK3568平台开发系列讲解(驱动基础篇)SMP(Symmetrical Multi-Processing)
🚀返回专栏总目录 文章目录 一、linux SMP 和 AMP二、linux SMP的启动流程三、CPU的描述:cpumask四、CPU之间的关系沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍 SMP(Symmetrical Multi-Processing)。 一、linux SMP 和 AMP 目前支持多核处理器的实时操…...
HIVE --- zeppelin安装
目录 把zeppelin压缩包拷贝到虚拟机里面 解压 改名 修改配置文件 编辑zeppelin-site.xml—将配置文件的ip地址和端口号进行修改 编辑 zeppelin-env.sh—添加JDK和Hadoop环境 配置环境变量 刷新环境变量 拷贝Hive文件 拷贝外部文件 启动zeppelin 启动Hadoop&Hi…...
数据分析中的变量解释
1.数值变量Numerical Variables 数值型变量(metric variable)是说明事物数字特征的一个名称,其取值是数值型数据。如“产品产量”、“商品销售额”、“零件尺寸”、“年龄”、“时间”等都是数值型变量,这些变量可以取不同的数值…...
怎么做体育直播网站/前端性能优化
以下列出mysql函数的使用,并不完全,涉及到多少写多少。length(str):返回字符串(str)的字符长度。一个汉字算三个字符,一个数字或字母算一个字符。select length(测试); --6select length(123abc); --6char_length(str):…...
wordpress 重定向循环/网络广告推广公司
背景 本文介绍ICML2021 I-BERT: Integer-only BERT Quantization 文章目的是对BERT进行更彻底的量化和整型计算; 作者认为之前的量化方案没有对gelu、softmax这些非线性操作进行量化计算(如下图1),即保持了float类型的计算&…...
wordpress设置系统邮箱/攀枝花网站seo
本机 hosts 配置后, 可以更灵活地访问内网服务 因为配置 hosts 后, 访问域名会根据 hosts 规则, 请求指定的 ip, 而不再请求 dns 服务器 windows 下 hosts 配置文件位置, 注意编辑时, 需要以管理员身份打开, 否则无法保存 C:\Windows\System32\drivers\etc\hostsLinux 下的 ho…...
海宁长安网站开发/百度灰色关键词排名代做
一、获取Code 假设我们需要网页授权的页面的地址为redirect_uri 需要获取Code的话我们第一步是跳转到授权地址,我们第一步便是获取拼接授权地址 --采用snsapi_base方式 public partial class WebAuth : System.Web.UI.Page{string Appid "XXXXXXXXXXXXXXXXXX…...
企业网站推广属于付费推广吗/平板电视seo优化关键词
Kinect中带了一种数据源,叫做BodyIndex,简单来说就是它利用深度摄像头识别出最多6个人体,并且用数据将属于人体的部分标记,将人体和背景区别开来。利用这一特性,就可以在环境中显示出人体的轮廓而略去背景的细节。我采…...
淘宝如何在其他网站做优惠/google关键词
随着课程的学习越来越深入,学期在不知不觉中已经过了三分之二。可是我自己仍觉得在课堂上没有学到什么知识,人家说大学生的学习效率最高的时候是在期末考试前的最后一天晚上,可能也适用于我现在的课程学习状态吧。下月中旬就要开始考四级了&a…...