设备驱动框架2——基于驱动框架写LED驱动(具体操作层)

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。

前言

之前写到,九鼎没有使用内核推荐的LED驱动框架。因此,我们打算基于LED驱动框架来编写x210开发板的LED驱动。编写前先要去除九鼎移植的LED驱动,然后配置内核支持LED驱动框架,最后根据LED驱动框架来编写LED驱动。

一、去除九鼎移植的LED驱动

九鼎移植的驱动在应用层的接口,位于/sys/devices/platform/x210-led/目录下,有led1、led2、led3、led4四个设备文件,各自管理一个led。(比如“echo 1 > led1”可以点亮其中的led1。)

[root@xjh ~]# cd /sys
[root@xjh sys]# ls    //sys目录内容
block     class     devices   fs        module
bus       dev       firmware  kernel    power
[root@xjh sys]# cd devices/ 
[root@xjh devices]# ls   //sys/devices目录内容
platform  system    virtual
[root@xjh devices]# cd platform/
[root@xjh platform]# ls    //sys/devices/platform目录内容
alarm             s3c-adc           s3c-sdhci.2       s5p-cec
android_pmem.1    s3c-button        s3c-sdhci.3       s5p-ehci
arm-pmu.0         s3c-csis          s3c-ts            s5p-hpd
dm9000.0          s3c-fimc.0        s3c2410-wdt       s5p-tvout
pm-wifi           s3c-fimc.1        s3c2440-i2c.0     s5pv210-nand
power             s3c-fimc.2        s3c2440-i2c.1     s5pv210-uart.0
power.0           s3c-g2d           s3c2440-i2c.2     s5pv210-uart.1
pvrsrvkm          s3c-jpg           s3c24xx-pwm.0     s5pv210-uart.2
reg-s5pv210-pd.0  s3c-keypad        s3c24xx-pwm.1     s5pv210-uart.3
reg-s5pv210-pd.1  s3c-mfc           s3c24xx-pwm.2     sec-fake-battery
reg-s5pv210-pd.2  s3c-pl330.0       s3c24xx-pwm.3     smdkc110-rtc
reg-s5pv210-pd.3  s3c-pl330.1       s3c64xx-iis.0     soc-audio.1
reg-s5pv210-pd.4  s3c-pl330.2       s3c64xx-iis.1     switch-gpio
reg-s5pv210-pd.5  s3c-sdhci.0       s3c_lcd           uevent
regulatory.0      s3c-sdhci.1       s3cfb             x210-led  //这里
[root@xjh platform]# cd x210-led/ 
[root@xjh x210-led]# ls  // sys/devices/platform/x210-led目录内容
driver     led2       led4       power      uevent
led1       led3       modalias   subsystem
[root@xjh x210-led]#

要去除九鼎移植的LED驱动,需要在内核配置阶段去掉相应的选择项,然后重新编译得到zImage并烧录至开发板。新内核启动后,如果/sys/devices/platform/x210-led目录不存在,则说明成功去掉该驱动。

步骤如下(内核编译初体验_天糊土的博客-CSDN博客)

步骤1:在 /home/xjh/iot/embedded_basic/kernel/x210_kernel 执行make distclean、make x210ii_qt_defconfig、make menuconfig。

步骤2:在弹出的配置窗口中去除九鼎移植的LED驱动选项。

                |………Device Drivers  --->   

                |…………Character devices  --->  

                |………………[*] x210 led driver  //将 * 换成 n。

步骤3:在配置窗口中选择支持NFS功能的选项。

见以NFS方式挂载rootfs的设置方法_天糊土的博客-CSDN博客。

可以修改配置文件,使得默认设置都是想要的配置,这样就不用再进行步骤2与3了。

比如将drivers/char/led目录下的Kconfig文件中的内容修改成如下(实测好像不行?)

config X210_LED_DRIVERbool "x210 led driver"
#       default y   将默认值y改为ndefault nhelpcompile for leddriver,y for kernel,m for module.

步骤4:执行make得到zImage,它在arch/arm/boot目录中。

步骤5:将新生成的zImage复制到tftp服务器的目录/tftp,开发板启动时uboot会自动从这里下载内核镜像。

步骤6:测试,/sys/devices/platform/x210-led目录不再存在。

[root@xjh platform]# pwd
/sys/devices/platform
[root@xjh platform]# ls
alarm             s3c-adc           s3c-sdhci.2       s5p-cec
android_pmem.1    s3c-button        s3c-sdhci.3       s5p-ehci
arm-pmu.0         s3c-csis          s3c-ts            s5p-hpd
dm9000.0          s3c-fimc.0        s3c2410-wdt       s5p-tvout
pm-wifi           s3c-fimc.1        s3c2440-i2c.0     s5pv210-nand
power             s3c-fimc.2        s3c2440-i2c.1     s5pv210-uart.0
power.0           s3c-g2d           s3c2440-i2c.2     s5pv210-uart.1
pvrsrvkm          s3c-jpg           s3c24xx-pwm.0     s5pv210-uart.2
reg-s5pv210-pd.0  s3c-keypad        s3c24xx-pwm.1     s5pv210-uart.3
reg-s5pv210-pd.1  s3c-mfc           s3c24xx-pwm.2     sec-fake-battery
reg-s5pv210-pd.2  s3c-pl330.0       s3c24xx-pwm.3     smdkc110-rtc
reg-s5pv210-pd.3  s3c-pl330.1       s3c64xx-iis.0     soc-audio.1
reg-s5pv210-pd.4  s3c-pl330.2       s3c64xx-iis.1     switch-gpio
reg-s5pv210-pd.5  s3c-sdhci.0       s3c_lcd           uevent
regulatory.0      s3c-sdhci.1       s3cfb             //不存在x210-led
[root@xjh platform]# 

二、添加LED驱动框架支持

当前内核中没有LED驱动框架,表现为/sys/class目录下没有此类,因此要添加LED驱动框架支持,这主要涉及menuconfig的操作。

1、添加LED驱动框架的步骤

在make menuconfig阶段,进行如下配置。

                |…………Device Drivers  --->

                |………………[*] LED Support  --->  

                |…………………… <*>   LED Class Support   

然后重新编译与下载,在开发板的/sys/class/目录下将出现leds目录。

[root@xjh ~]# cd /sys/class
[root@xjh class]# ls
backlight     i2c-adapter   misc          regulator     scsi_host   video4linux
bdi           i2c-dev       mmc_host      rfkill        sound       vtconsole
block         ieee80211     mtd           rtc           spi_master
firmware      input         net           s3c_bc        switch
gpio          lcd           power_supply  scsi_device   timed_output
graphics      leds //这里   ppp           scsi_disk     tty
hidraw        mem           pvr           scsi_generic  vc
[root@xjh class]# 

2、sysfs中的内容分析

三、基于驱动框架写LED驱动(具体操作层)

1、代码编写前的分析

(1)可参考的驱动程序在哪里?

drivers/leds/leds-s3c24xx.c文件,drivers/leds/led-class.c文件

(2)代码编写的关键点是什么?

led_classdev_register函数。

注意,在驱动框架核心层drivers/leds/led-class.c文件中,已经注册了一个类leds,会创建/sys/class/leds这个目录。我们现在要利用驱动框架提供的led_classdev_register函数,在/sys/class/leds目录下会创建一个设备。

(经过测试,不会在/dev下创建设备文件,因为这是两条不同的路线。现在的路线是在/sys/class/leds目录下创建一个设备目录,目录里有属性文件,应用层通过操作这些属性文件进而操作硬件。)

2、动手编写代码

这里没有像leds-s3c24xx.c那样使用驱动模型,而是参考其中部分内容,然后自己编写。

#include <linux/module.h>		// module_init  module_exit
#include <linux/init.h>			// __init   __exit
#include <linux/fs.h>
#include <linux/leds.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank.h>
#include <linux/io.h>
#include <linux/ioport.h>#define GPJ0CON		S5PV210_GPJ0CON
#define GPJ0DAT		S5PV210_GPJ0DATstatic struct led_classdev mydev;			// 定义结构体变量// 这个函数就是要去完成具体的硬件读写任务的
static void s5pv210_led_set(struct led_classdev *led_cdev,\enum led_brightness value)
{printk(KERN_INFO "s5pv210_led_set\n");// 在这里根据用户设置的值来操作硬件// 用户设置的值就是valueif (value == LED_OFF){// 用户给了个0,希望LED灭writel(0x11111111, GPJ0CON);writel(((1<<3) | (1<<4) | (1<<5)), GPJ0DAT);}else{// 用户给的是非0,希望LED亮writel(0x11111111, GPJ0CON);writel(((0<<3) | (0<<4) | (0<<5)), GPJ0DAT);}
}static int __init s5pv210_led_init(void)
{// 用户insmod安装驱动模块时会调用该函数// 该函数的主要任务就是去使用led驱动框架提供的设备注册函数来注册一个设备int ret = -1;//填充mydevmydev.name = "myled";//设备的名字mydev.brightness = 255;	mydev.brightness_set = s5pv210_led_set;ret = led_classdev_register(NULL, &mydev);if (ret < 0) {printk(KERN_ERR "led_classdev_register failed\n");return ret;}return 0;
}static void __exit s5pv210_led_exit(void)
{led_classdev_unregister(&mydev);
}module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL");							// 描述模块的许可证
MODULE_AUTHOR("aston <1264671872@qq.com>");		// 描述模块的作者
MODULE_DESCRIPTION("s5pv210 led driver");		// 描述模块的介绍信息
MODULE_ALIAS("s5pv210_led");					// 描述模块的别名信息

3、测试与分析

将上面的驱动程序进行编译,然后对比模块安装前后的情况。

[root@xjh ~]# cd /sys/class
[root@xjh class]# ls
backlight     i2c-adapter   misc          regulator     scsi_host   video4linux
bdi           i2c-dev       mmc_host      rfkill        sound       vtconsole
block         ieee80211     mtd           rtc           spi_master
firmware      input         net           s3c_bc        switch
gpio          lcd           power_supply  scsi_device   timed_output
graphics      leds          ppp           scsi_disk     tty
hidraw        mem           pvr           scsi_generic  vc
[root@xjh class]# cd leds
[root@xjh leds]# ls
mmc0::  mmc1::  mmc2::  mmc3::
[root@xjh leds]# insmod /mnt/module_test.ko 
[root@xjh leds]# ls
mmc0::  mmc1::  mmc2::  mmc3::  myled
[root@xjh leds]# cd myled/
[root@xjh myled]# ls
brightness      max_brightness  power           subsystem       uevent
[root@xjh myled]# 

这测试证明我们写的驱动确实被加载了,表现为/sys/class/leds/目录下出现了一个表示设备的文件夹myled(这个名字是我们写驱动的时候指定的)。

myled文件夹里面有LED硬件的2个属性brightness和max_brightness。

led-class.c文件中,有一个led_brightness_show函数和led_brightness_store函数,分别对应着用户读与写/sys/class/leds/myled/brightness这个文件时实际执行的代码。当我们在命令行执行“cat brightness”时(表示读),实际就会执行led_brightness_show函数;当我们执行“echo 1 > brightness”时(表示写),实际就会执行led_brightness_store函数。

led_brightness_show函数其实就是读取LED硬件信息,然后把硬件信息返回,因此该函数会去操控硬件。但是led-class.c文件属于驱动框架中核心层的文件,它本身无法直接读取具体硬件,因此该函数使用函数指针的方式,指向struct led_classdev结构体中相应的读取硬件信息的函数。而struct led_classdev结构体中实际用来读取硬件信息的函数,就是我们自己写的驱动文件leds-s5pv210.c中要提供的。同理,store函数也是如此。

4、在驱动中将4个LED分开

(1)机制与策略的含义

驱动只应该提供机制(具体实现)而不是策略(方法、主意、解决方案),策略由应用程序来做。

驱动设计时,不要对最终需求功能进行假定(不能假定用户进行什么操作,比如是几个led一起操作还是一个操作而已),而应该只是直接的对硬件的操作。

(2)在驱动中将4个LED分开

驱动层实现对各个LED设备的独立访问,并向应用层展示出4个操作接口led1、led2、led3、led4,这样应用层可以完全按照自己的需要对LED进行控制。

(3)代码示例

#include <linux/module.h>		// module_init  module_exit
#include <linux/init.h>			// __init   __exit
#include <linux/fs.h>
#include <linux/leds.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank.h>
#include <linux/io.h>
#include <linux/ioport.h>#define GPJ0CON		S5PV210_GPJ0CON
#define GPJ0DAT		S5PV210_GPJ0DATstatic struct led_classdev mydev1;			// 定义结构体变量
static struct led_classdev mydev2;			// 定义结构体变量
static struct led_classdev mydev3;			// 定义结构体变量// 这个函数就是要去完成具体的硬件读写任务的
static void s5pv210_led1_set(struct led_classdev *led_cdev,  \enum led_brightness value)
{printk(KERN_INFO "s5pv210_led1_set\n");writel(0x11111111, GPJ0CON);// 在这里根据用户设置的值来操作硬件// 用户设置的值就是valueif (value == LED_OFF){// 用户给了个0,希望LED灭//writel(0x11111111, GPJ0CON);// 读改写三部曲writel((readl(GPJ0DAT) | (1<<3)), GPJ0DAT);}else{// 用户给的是非0,希望LED亮//writel(0x11111111, GPJ0CON);writel((readl(GPJ0DAT) & ~(1<<3)), GPJ0DAT);}
}static void s5pv210_led2_set(struct led_classdev *led_cdev, \enum led_brightness value)
{printk(KERN_INFO "s5pv2102_led_set\n");writel(0x11111111, GPJ0CON);// 在这里根据用户设置的值来操作硬件// 用户设置的值就是valueif (value == LED_OFF){// 用户给了个0,希望LED灭//writel(0x11111111, GPJ0CON);// 读改写三部曲writel((readl(GPJ0DAT) | (1<<4)), GPJ0DAT);}else{// 用户给的是非0,希望LED亮//writel(0x11111111, GPJ0CON);writel((readl(GPJ0DAT) & ~(1<<4)), GPJ0DAT);}
}static void s5pv210_led3_set(struct led_classdev *led_cdev,enum led_brightness value)
{printk(KERN_INFO "s5pv210_led3_set\n");writel(0x11111111, GPJ0CON);// 在这里根据用户设置的值来操作硬件// 用户设置的值就是valueif (value == LED_OFF){// 用户给了个0,希望LED灭//writel(0x11111111, GPJ0CON);// 读改写三部曲writel((readl(GPJ0DAT) | (1<<5)), GPJ0DAT);}else{// 用户给的是非0,希望LED亮//writel(0x11111111, GPJ0CON);writel((readl(GPJ0DAT) & ~(1<<5)), GPJ0DAT);}
}static int __init s5pv210_led_init(void)
{// 用户insmod安装驱动模块时会调用该函数// 该函数的主要任务就是去使用led驱动框架提供的设备注册函数来注册一个设备int ret = -1;// led1mydev1.name = "led1";mydev1.brightness = 255;	mydev1.brightness_set = s5pv210_led1_set;ret = led_classdev_register(NULL, &mydev1);if (ret < 0) {printk(KERN_ERR "led_classdev_register failed\n");return ret;}// led2mydev2.name = "led2";mydev2.brightness = 255;	//这句话就把驱动框架第一部分,和第二部分关联起来了!!!!!mydev2.brightness_set = s5pv210_led2_set;ret = led_classdev_register(NULL, &mydev2);if (ret < 0) {printk(KERN_ERR "led_classdev_register failed\n");return ret;}// led3mydev3.name = "led3";mydev3.brightness = 255;	mydev3.brightness_set = s5pv210_led3_set;ret = led_classdev_register(NULL, &mydev3);if (ret < 0) {printk(KERN_ERR "led_classdev_register failed\n");return ret;}return 0;
}static void __exit s5pv210_led_exit(void)
{led_classdev_unregister(&mydev1);led_classdev_unregister(&mydev2);led_classdev_unregister(&mydev3);
}module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL");							// 描述模块的许可证
MODULE_AUTHOR("aston <1264671872@qq.com>");		// 描述模块的作者
MODULE_DESCRIPTION("s5pv210 led driver");		// 描述模块的介绍信息
MODULE_ALIAS("s5pv210_led");					// 描述模块的别名信息

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/461258.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql重新用户设置密码_mysql用户密码如何重新设置?

mysql用户密码重新设置停掉MySQL服务&#xff1a;sudo service mysql stop以上命令适用于Ubuntu和Debian。CentOS、Fedora和RHEL下使用mysqld替换mysql。以安全模式启动mysql&#xff1a;sudo mysqld_safe --skip-grant-tables --skip-networking &这样我们就可以直接用roo…

第三章 门电路

1 半导体二极管开关特性 1 二极管的特性可以近似的用3.2.1的PN结方程和图3.2.2伏安特性曲线描述 如下图 二极管近似伏安特性和对应的等效电路 1 a电路表示vcc和r都很小时候二极管正向导通压降和正向电阻都不能忽视 2 b电路表示二极管正向导通电压不可以忽视&#xff0c;但是二…

多个页面同时跳转到一个页面,然后返回到上级页面

第一步&#xff0c;在page_load事件中写入一下代码&#xff1a; string strUrl Request.UrlReferrer.AbsoluteUri;ViewState["Url"] strUrl;第二步&#xff0c;在返回事件中写入一下代码&#xff1a;string strUrl ViewState["Url"].ToString();Respons…

mysql查询数据库日期_mysql如何查询日期与时间

前言&#xff1a;在项目开发中&#xff0c;一些业务表字段经常使用日期和时间类型&#xff0c;而且后续还会牵涉到这类字段的查询。关于日期及时间的查询等各类需求也很多&#xff0c;本篇文章简单讲讲日期及时间字段的规范化查询方法。1.日期和时间类型概览MySQL支持的日期和时…

设备驱动框架3——使用gpiolib完成LED驱动

以下内容源于朱有鹏嵌入式课程的学习整理&#xff0c;如有侵权请告知删除。 一、前言 在实际情况中&#xff0c;很多硬件都要用到GPIO&#xff0c;因此GPIO会复用&#xff1b;如果同一个GPIO被2个驱动同时控制就会出现bug&#xff1b;因此内核提供了gpiolib来统一管理系统中所有…

from PyQt4 import QtGui,QtCore出错-解

from PyQt4 import QtGui,QtCore出错-解今天尝试着安装PyQt写界面&#xff0c;官网下载后发现import出错了&#xff0c;情况如下图&#xff1a;import PyQt4就可以&#xff0c;from PyQt4 import QtCore却不行提示DLL load faied找了下网上有些人说是某些dll文件丢失了&#xf…

多线程条件变量(pthread_cond_wait)用法

条件变量是利用线程间共享得全局变量进行同步的一种机制&#xff0c;主要包括两个动作&#xff1a;一个线程等待“条件变量的条件成立”而挂起&#xff1b;另一个线程使“条件成立”给出条件成立信号。为了防止竞争&#xff0c;条件变量得使用总是和一个互斥锁结合在一起。 1、…

mysql 文件系统规划_Mysql的文件系统规划以及日志配置

Mysql服务器文件系统规划:/dev/sda1 /boot/dev/sda2 //dev/sda3 /home/dev/sda4 /tmp/dev/sdb1 /data/dev/sdc1 /logsda:系统目录 sdb:数据目录 sdc:日志目录linux调度策略&#xff1a;--查看当前的调度策略:less /sys/block/sdb/queue/scheduler[noop] anticipatory deadli…

设备驱动框架4——将驱动集成到内核中

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 驱动集成到内核的概念 驱动开发的步骤一般是&#xff1a; &#xff08;1&#xff09;以模块的形式在内核外部编写与调试 &#xff08;2&#xff09;将调试好的驱动代码集成到kernel中 之前我们编写的…

VirtualBox 虚拟机的网络设置

http://cnzhx.net/blog/virtualbox-vm-network-setting/ 注意&#xff1a;修改第一个网卡虚拟机&#xff0c;此处网络设置添加的是第二个网卡虚拟机&#xff1f;&#xff1f;转载于:https://www.cnblogs.com/ztinass/p/3771225.html

[ios]UITableViewCell自适应高度 【转】

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { // 列寬 CGFloat contentWidth self.tableView.frame.size.width; // 用何種字體進行顯示 UIFont *font [UIFont systemFontOfSize:13]; // 該…

MYSQL存储磁盘创建vgcreate_【转】parted创建硬盘分区并创建LVM

目的&#xff1a;将两个三T的硬盘做成LVM(sdc,sdd)一、parted将硬盘进行分区&#xff1a;1)parted的命令方式Parted 命令分为两种模式&#xff1a;命令行模式和交互模式。1、命令行模式&#xff1a; parted [option] device [command] ,该模式可以直接在命令行下对磁盘进行分区…

Linux设备驱动模型1——设备驱动模型的简介与底层架构

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、linux设备驱动模型简介 1、设备驱动模型的含义 设备驱动模型主要体现为以下四个方面&#xff1a; &#xff08;1&#xff09;类class、总线bus、设备device、驱动driver 这四个概念分别对应着四…

例子简单说说C# ref和out

首写从这字段看 ref 就是引用的意思 out当然就是输出了public void getRefStr(ref string str) {str"hello 你好&#xff0c;你变成了Ref了" }public void getOutStr(out string outStr){outStr "hello 你好&#xff0c;你是out输出的值";} protected…

VARIANT变体类型数据

2019独角兽企业重金招聘Python工程师标准>>> 特殊 Variant 是一种特殊的数据类型&#xff0c;除了定长String数据及用户定义类型外&#xff0c;可以包含任何种类的数据。Variant 也可以包含Empty、Error、Nothing及Null等特殊值。可以用VarType函数或TypeName函数来…

mysql修改校对集_MySQL 图文详细教程之校对集问题

软件安装&#xff1a;装机软件必备包SQL是Structured Query Language(结构化查询语言)的缩写。SQL是专为数据库而建立的操作命令集&#xff0c;是一种功能齐全的数据库语言。在使用它时&#xff0c;只需要发出“做什么”的命令&#xff0c;“怎么做”是不用使用者考虑的。SQL功…

Linux设备驱动模型2——总线式设备驱动组织方式(总线、设备、驱动、类等结构体)

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 参考 Linux总线设备驱动模型的理解 struct class 和 struct class_device 前言 这里说的“总线式”&#xff0c;包括I2C总线等具体物理总线&#xff0c;以及平台总线这个虚拟总线。 rootubuntu:/sy…

C# winform 魔兽MH全图制作教程(1): 开发准备工作

C# winform 魔兽MH全图制作教程&#xff08;1&#xff09;: 开发准备工作 一、开发条件&#xff1a; Visual Studio 2008win xp,win 7,win 2003.C# 语言基础会调试能够运行游戏&#xff1a;《魔兽争霸3冰封王座》拥有版本魔兽客户端版本切换器1.20E,1.24E,1.24D二、设计思路&am…

从常识看中国经济社会-再续之续:套利

2019独角兽企业重金招聘Python工程师标准>>> 《全球化掠夺》提及财富流转的路径&#xff0c;世界仍旧是个丛林&#xff0c;每个人、每个族群都在争夺自己的利益。在一个经济体的内部&#xff0c;财富是垂直流动的&#xff1b;在全球化的经济体中&#xff0c;财富是纵…

python 面向对象编程简称_Python基础-面向对象编程

简介三中编程范式面向过程编程函数式编程面向对象编程面向对象和面向过程对比面向过程优点&#xff1a;性能比面向对象高&#xff0c;因为类调用时需要实例化&#xff0c;开销比较大&#xff0c;比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发&#x…