010——服务器开发环境搭建及开发方法(下)

目录

[三、 第一个驱动程序](#三、 第一个驱动程序)

[四、 buildroot](#四、 buildroot)

[4.1 制作根文件系统](#4.1 制作根文件系统)

[4.2 buildroot使用](#4.2 buildroot使用)

[五、 uboot](#五、 uboot)


009------服务器开发环境搭建及开发方法(上)-CSDN博客

三、 第一个驱动程序

# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH,          比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH,          比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin 
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
#       请参考各开发板的高级用户使用手册

KERN_DIR = /home/book/program/100ask_roc-rk3399-pc/linux-4.4

all:
	make -C $(KERN_DIR) M=`pwd` modules 
	$(CROSS_COMPILE)gcc -o hello_drv_test hello_drv_test.c 

clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order
	rm -f hello_drv_test

obj-m	+= hello_drv.o
cpp 复制代码
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>

/* 1. 确定主设备号                                                                 */
static int major = 0;
static char kernel_buf[1024];
static struct class *hello_class;


#define MIN(a, b) (a < b ? a : b)

/* 3. 实现对应的open/read/write等函数,填入file_operations结构体                   */
static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	int err;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = copy_to_user(buf, kernel_buf, MIN(1024, size));
	return MIN(1024, size);
}

static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
	int err;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = copy_from_user(kernel_buf, buf, MIN(1024, size));
	return MIN(1024, size);
}

static int hello_drv_open (struct inode *node, struct file *file)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

static int hello_drv_close (struct inode *node, struct file *file)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

/* 2. 定义自己的file_operations结构体                                              */
static struct file_operations hello_drv = {
	.owner	 = THIS_MODULE,
	.open    = hello_drv_open,
	.read    = hello_drv_read,
	.write   = hello_drv_write,
	.release = hello_drv_close,
};

/* 4. 把file_operations结构体告诉内核:注册驱动程序                                */
/* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
static int __init hello_init(void)
{
	int err;
	
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	major = register_chrdev(0, "hello", &hello_drv);  /* /dev/hello */


	hello_class = class_create(THIS_MODULE, "hello_class");
	err = PTR_ERR(hello_class);
	if (IS_ERR(hello_class)) {
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		unregister_chrdev(major, "hello");
		return -1;
	}
	
	device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */
	
	return 0;
}

/* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数           */
static void __exit hello_exit(void)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	device_destroy(hello_class, MKDEV(major, 0));
	class_destroy(hello_class);
	unregister_chrdev(major, "hello");
}


/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
cpp 复制代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

/*
 * ./hello_drv_test -w abc
 * ./hello_drv_test -r
 */
int main(int argc, char **argv)
{
	int fd;
	char buf[1024];
	int len;
	
	/* 1. 判断参数 */
	if (argc < 2) 
	{
		printf("Usage: %s -w <string>\n", argv[0]);
		printf("       %s -r\n", argv[0]);
		return -1;
	}

	/* 2. 打开文件 */
	fd = open("/dev/hello", O_RDWR);
	if (fd == -1)
	{
		printf("can not open file /dev/hello\n");
		return -1;
	}

	/* 3. 写文件或读文件 */
	if ((0 == strcmp(argv[1], "-w")) && (argc == 3))
	{
		len = strlen(argv[2]) + 1;
		len = len < 1024 ? len : 1024;
		write(fd, argv[2], len);
	}
	else
	{
		len = read(fd, buf, 1024);		
		buf[1023] = '\0';
		printf("APP read : %s\n", buf);
	}
	
	close(fd);
	
	return 0;
}

看来驱动模块还是要放到对应的modules目录下才可以正常modprobe。之前用3.14版本的内核就需要这样做现在4.9.88还是需要。

测试一下这个字符驱动没问题。

四、 buildroot

4.1 制作根文件系统

制作根文件系统有很多种方法:

使用 Busybox 手工制作

Busybox 本身包含了很了 Linux 命令,但是要编译其他程序的话需要手工下载、编译,如果它需要某些依赖库,你还需要手工下载、编译这些依赖库。如果想做一个极简的文件系统,可以使用 Busybox 手工制作。

使用 Buildroot 自动制作

它是一个自动化程序很高的系统,可以在里面配置、编译内核,配置编译 uboot、配置编译根文件系统。在编译某些 APP 时,它会自动去下载源码、下载它的依赖库,自动编译这些程序。

Buildroot 的语法跟一般的 Makefile 语法类似,很容易掌握。

使用 Yocto

NXP、 ST 等公司的官方开发包是使用 Yocto,但是 Yocto 语法复杂,并且Yocto 动辄 10GB,下载安装都很困难,普通笔记本编译可能需要 2-3 天甚至更久,非常不适合初学者(我们不推荐使用 yocto 构建文件系统)。

基于上述特点,我们选择 Buildroot。

Buildroot 是一组 Makefile 和补丁,可简化并自动化地为嵌入式系统构建完整的、可启动的 Linux 环境(包括 bootloader、 Linux 内核、包含各种 APP的文件系统)。 Buildroot 运行于 Linux 平台,可以使用交叉编译工具为多个目标板构建嵌入式 Linux 平台。 Buildroot 可以自动构建所需的交叉编译工具链,创建根文件系统,编译 Linux 内核映像,并生成引导加载程序用于目标嵌入式系

统,或者它可以执行这些步骤的任何独立组合。例如,可以单独使用已安装的交叉编译工具链,而 Buildroot 仅创建根文件系统。

Buildroot 参考网址:

•Buildroot 用户手册:

https://buildroot.org/downloads/manual/manual.html

• Buildroot 源码下载地址:

https://buildroot.org/downloads/

我们之前在exynos4412上做系统移植时使用的是busybox来做根文件系统这次需要使用的功能会多一些所以最终选择了buildroot。

4.2 buildroot使用

在 buildroot 下进入 menuconfig 包选择配置配置界面

book@100ask: ~/100ask_imx6ull_mini-sdk/Buildroot_2020.02.x$ make menuconfig

buildroot 下单独编译内核

book@100ask: ~/100ask_imx6ull_mini-sdk/Buildroot_2020.02.x$ make linux-rebuild

buildroot 下进入内核 make menuconfig 配置选项界面

book@100ask: ~/100ask_imx6ull_mini-sdk/Buildroot_2020.02.x$ make linux-menuconfig

buildroot 下单独编译 u-boot

book@100ask: ~/100ask_imx6ull_mini-sdk/Buildroot_2020.02.x$ make uboot-rebuild

buildroot 下单独编译某个软件包

book@100ask: ~/100ask_imx6ull_mini-sdk/Buildroot_2020.02.x$ make <pkg>-rebuild

buildroot 下进入 busybox 配置界面

book@100ask: ~/100ask_imx6ull_mini-sdk/Buildroot_2020.02.x$ make busybox-menuconfig

buildroot 下生成系统 sdk,最后生成的目录在 output/images/目录下

book@100ask: ~/100ask_imx6ull_mini-sdk/Buildroot_2020.02.x$ make sdk

时间很久不去做了,记录下方法。

韦东山老师已经做好了四种配置文件可以直接使用。这个就类似编译内核时的那种XXX_config

五、 uboot

这个uboot的版本很新,我们以前用的是2013这次是2017.3

=> printenv

baudrate=115200

board_name=EVK

board_rev=14X14

boot_fdt=try

bootcmd=run findfdt;run findtee;mmc dev ${mmcdev};mmc dev ${mmcdev}; if mmc rescan; then if run loadbootscript; then run bootscript; else if run loadimage; then run mmcboot; else run netboot; fi; fi; else run netboot; fi

bootcmd_mfg=run mfgtool_args; if test ${tee} = yes; then bootm ${tee_addr} ${initrd_addr} ${fdt_addr}; else bootz ${loadaddr} ${initrd_addr} ${fdt_addr}; fi;

bootdelay=3

bootdir=/boot

bootscript=echo Running bootscript from mmc ...; source

console=ttymxc0

eth1addr=00:01:1f:2d:3e:5d

ethact=ethernet@02188000

ethaddr=00:01:1f:2d:3e:4d

ethprime=eth0

fdt_addr=0x83000000

fdt_file=100ask_imx6ull_mini.dtb

fdt_high=0xffffffff

fdtcontroladdr=9ef40478

findfdt=if test $fdt_file = undefined; then if test $board_name = EVK && test $board_rev = 9X9; then setenv fdt_file imx6ull-9x9-evk.dtb; fi; if test $board_name = EVK && test $board_rev = 14X14; then setenv fdt_file imx6ull-14x14-evk.dtb; fi; if test $fdt_file = undefined; then setenv fdt_file imx6ull-14x14dtb; fi; fi;

image=zImage

initrd_addr=0x83800000

initrd_high=0xffffffff

ip_dyn=yes

loadaddr=0x80800000

loadbootscript=fatload mmc {mmcdev}:{mmcpart} ${loadaddr} ${script};

loadfdt=ext2load mmc {mmcdev}:{mmcpart} ${fdt_addr} {bootdir}/{fdt_file}

loadimage=ext2load mmc {mmcdev}:{mmcpart} ${loadaddr} {bootdir}/{image}

loadtee=fatload mmc {mmcdev}:{mmcpart} ${tee_addr} ${tee_file}

mfgtool_args=setenv bootargs console={console},{baudrate} rdinit=/linuxrc g_mass_storage.stall=0 g_mass_storage.removable=1 g_mass_storage.file=/fat g_mass_storage.ro=1 g_mass_storage.idVendor=0x066F g_mass_storage.idProduct=0x37FF g_mass_storage.iSerialNumber="" clk_ignore_unused

mmcargs=setenv bootargs console={console},{baudrate} root=${mmcroot}

mmcautodetect=yes

mmcboot=echo Booting from mmc ...; run mmcargs; if test ${tee} = yes; then run loadfdt; run loadtee; bootm ${tee_addr} - ${fdt_addr}; else if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if run loadfdt; then bootz ${loadaddr} - ${fdt_addr}; else if test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT; fi; fi; else bootz; fi; fi;

mmcdev=1

mmcpart=2

mmcroot=/dev/mmcblk1p2 rootwait rw

netargs=setenv bootargs console={console},{baudrate} root=/dev/nfs ip=dhcp nfsroot={serverip}:{nfsroot},v3,tcp

netboot=echo Booting from net ...; run netargs; setenv get_cmd tftp; ${get_cmd} ${image}; ${get_cmd} ${fdt_addr} ${fdt_file}; bootz ${loadaddr} - ${fdt_addr};

panel=TFT7016

script=boot.scr

tee=no

tee_addr=0x84000000

tee_file=uTee-6ullevk

Environment size: 2653/8188 bytes

这个内容有点多呀,而且可以看出来写了很多的uboot上的app,在启动的环境变量里是直接调用那些app的这样我们就看不到它做了什么了。

这里可以直接看到的有用的信息只有波特率,内核,设备树和根文件系统的地址。

系统移植基本就结束了,后面我们也不会去动uboot了,kernel可能需要动一动,然后就是开发这14个传感器的驱动程序以及开发服务器程序和客户端程序了。

相关推荐
Python私教2 分钟前
ubuntu搭建k8s环境详细教程
linux·ubuntu·kubernetes
羑悻的小杀马特15 分钟前
环境变量简介
linux
小陈phd1 小时前
Vscode LinuxC++环境配置
linux·c++·vscode
是阿建吖!1 小时前
【Linux】进程状态
linux·运维
明明跟你说过1 小时前
Linux中的【tcpdump】:深入介绍与实战使用
linux·运维·测试工具·tcpdump
Komorebi.py2 小时前
【Linux】-学习笔记05
linux·笔记·学习
Mr_Xuhhh2 小时前
重生之我在学环境变量
linux·运维·服务器·前端·chrome·算法
内核程序员kevin6 小时前
TCP Listen 队列详解与优化指南
linux·网络·tcp/ip
网易独家音乐人Mike Zhou7 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
朝九晚五ฺ10 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习