一、Linux内核是什么?
Linux是一种开源电脑操作系统内核。它是一个用C语言写成,符合POSIX标准的类Unix操作系统 。操作系统是一个用来和硬件打交道并为用户程序提供一个有限服务集的低级支撑软件。一个计算机系统是一个硬件和软件的共生体,它们互相依赖,不可分割。计算机的硬件,含有外围设备、处理器、内存、硬盘和其他的电子设备组成计算机的发动机。但是没有软件来操作和控制它,自身是不能工作的。完成这个控制工作的软件就称为操作系统,在Linux的术语中被称为“内核”,也可以称为“核心”。Linux内核的主要模块(或组件)分以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信,以及系统的初始化(引导)、系统调用等。
二、如何在linux内核下写程序
三、代码编写
1.应用程序的编写
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
int fd;
char buf[1024];
int len;
/* 1. 打开文件 */
fd = open("/dev/hello", O_RDWR);
if (fd == -1)
{
printf("can not open file /dev/hello\n");
return -1;
}
/* 3. 写文件或读文件 */
write(fd, "hello world", len);
len = read(fd, buf, 1024);
buf[1023] = '\0';
printf("APP read : %s\n", buf);
return 0;
}
2.驱动程序的编写
#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结构体 */
/*读函数,连接应用层的read()函数*/
static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
int err;
err = copy_to_user(buf, kernel_buf, MIN(1024, size));
return MIN(1024, size);
}
/*写函数,连接应用层的write()函数*,/
static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int err;
err = copy_from_user(kernel_buf, buf, MIN(1024, size));
return MIN(1024, size);
}
/*打开函数,连接应用层的open()函数*,/
static int hello_drv_open (struct inode *node, struct file *file)
{
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,
};
/* 4. 把file_operations结构体告诉内核:注册驱动程序 */
/* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
static int __init hello_init(void)
{
int err;
major = register_chrdev(0, "hello", &hello_drv); //注册file_operations 结构体
//你只用知道下面两个函数是自动生成设备结点
hello_class = class_create(THIS_MODULE, "hello_class");
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);
//因为Linux内核是开源的,所以所有的开发者都要遵循这个GPL协议
MODULE_LICENSE("GPL");
3.使用Makefile进行程序的编译
在你的驱动程序和应用程序下写一个makefile
/*你内核的所在目录*/
KERN_DIR = /home/book/100ask_roc-rk3399-pc/linux-4.4
all:
//去到这个内核的目录下编译驱动模块
make -C $(KERN_DIR) M=`pwd` modules
//使用交叉编译工具链进行,生成应用程序,这样就可以在arm平台下进行程序的运行了
$(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变量即可/
obj-m += hello_drv.o
4.把在ubuntu生成的.ko文件和应用程序放在arm板子上执行
1.ubuntu要想把文件传输到arm平台上有很多种方式,相当于ubuntu和windows通信类似,可以使用tftp通信方式,或者NFS通信方式进行数据的传输。这里使用NFS通信
- 使用下面命令挂载NFS
挂载的意思:打个比方你要挂载hello这个文件到arm上,那么你的arm上的某个目录将会有和你这个hello文件一模一样的东西,如果你修改了东西,另外一个平台上的hello文件也会修改。 #mount -t nfs -o nolock,vers=3 192.168.1.100:/home/book/nfs_rootfs /mnt
2.在你挂载的目录下安装驱动程序:insmod hello_drv.ko ,这是将会在/dev/自动创建一个设备结点。 3.运行你的应用层程序:./hello_drv_test 。 这时候你的屏幕上将会显示应用层写入helloworld字符串。
总结
因为这其中涉及大量的准备工作,需要配置好很多的环境,所以说完成上机实验比较难,只是让大家了解一下驱动的开发流程,让大家有一个大体的了解。 我可以说这是我见过最难的hellowrold的编写,我不信你见过比这个更难得helloworld程序的编写。如果你想更深入的了解嵌入式,你可以去看韦东山老师的视频,Linux嵌入式教学第一人。 ????????????????????????????????????????????????????
|