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个传感器的驱动程序以及开发服务器程序和客户端程序了。

相关推荐
cominglately2 小时前
centos单机部署seata
linux·运维·centos
魏 无羡2 小时前
linux CentOS系统上卸载docker
linux·kubernetes·centos
CircleMouse2 小时前
Centos7, 使用yum工具,出现 Could not resolve host: mirrorlist.centos.org
linux·运维·服务器·centos
木子Linux3 小时前
【Linux打怪升级记 | 问题01】安装Linux系统忘记设置时区怎么办?3个方法教你回到东八区
linux·运维·服务器·centos·云计算
mit6.8243 小时前
Ubuntu 系统下性能剖析工具: perf
linux·运维·ubuntu
鹏大师运维3 小时前
聊聊开源的虚拟化平台--PVE
linux·开源·虚拟化·虚拟机·pve·存储·nfs
watermelonoops3 小时前
Windows安装Ubuntu,Deepin三系统启动问题(XXX has invalid signature 您需要先加载内核)
linux·运维·ubuntu·deepin
滴水之功4 小时前
VMware OpenWrt怎么桥接模式联网
linux·openwrt
ldinvicible4 小时前
How to run Flutter on an Embedded Device
linux
YRr YRr5 小时前
解决Ubuntu 20.04上编译OpenCV 3.2时遇到的stdlib.h缺失错误
linux·opencv·ubuntu