1、使用的是linux-5.0.1 ubuntu1910
2、安装依赖
build-essential
kernel-package
gcc
make
libncurses5-dev
libssl-dev
libelf-dev
均可用sudo apt-get install …
3、源文件获取与安装
3.1、获取内核源码
# 查看系统内核版本
uname -r
5.0.0-32-generic
# 获取源文件包
sudo apt-get install linux-source-5.0.0
# 文件包默认在/usr/src中
cd /usr/src
linux-source-5.0.0.bz2
# 解压至指定目录
sudo tar -jxvf linux-source-5.0.0.bz2 -C ~/linux-kernel
# 进入源码包目录
cd ~/linux-kernel/linux-source-5.0.0
3.2、安装
# 编译
sudo make oldconfig
# 最耗时
sudo make
# 生成设备树
sudo make modules
sudo make modules_install
# 在lib/modules目录中生成设备树
cd /lib/modules
yang@yang-Lenovo:/lib/modules$ ll
总用量 20
drwxr-xr-x 5 root root 4096 11月 16 14:30 ./
drwxr-xr-x 142 root root 4096 11月 12 20:37 ../
drwxr-xr-x 5 root root 4096 4月 17 2019 5.0.0-13-generic/
drwxr-xr-x 5 root root 4096 11月 12 11:22 5.0.0-32-generic/
drwxr-xr-x 3 root root 4096 11月 16 14:35 5.0.21/
(注意:我的执行编译sudo make oldconfig时会出现错误,
解决办法:安装bison
sudo apt-get install basion
(至少我的这样可以解决))
4、测试
(我直接在家目录下创建一个目录)
yang@yang-Lenovo:~/my_cdev$ ls
chr_dev_test.c led_dev.c Makefile my_chr_dev.c
(忽略led_dev.c)
1)字符设备驱动文件:my_chr_dev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#define BASEMINOR 0
#define COUNT 2
#define NAME "led_dev"
dev_t dev_num;
struct cdev *cdevp = NULL;
static char kernel_val = 6;
//对应用户层的int open(const char *pathname, int flags);
int open_cdev(struct inode *ino, struct file *filp)
{
printk("open_cdev secuss\n");
return 0;
}
//对应应用层的ssize_t read(int fd, void *buf, size_t count);
ssize_t read_cdev(struct file *filp, char __user *buf, size_t count, loff_t *loff)
{
int ret;
ret = copy_to_user(buf, &kernel_val, count);
if(ret > 0)
{
printk("copy_to_user error\n");
return -1;
}
return 0;
}
//对应应用层的write
ssize_t write_cdev(struct file *filp, const char __user *buf, size_t count, loff_t *loff)
{
char value;
int ret;
ret = copy_from_user(&value, buf, count);
if(ret > 0)
{
printk("copy_from_user error\n");
return -2;
}
printk("From user data: %d\n", value);
return 0;
}
struct file_operations fops = {
.owner = THIS_MODULE,
.open = open_cdev,
.write = write_cdev,
.read = read_cdev
};
static int my_cdev_init(void)
{
int ret;
//1、分配设备号
ret = alloc_chrdev_region(&dev_num, BASEMINOR, COUNT, NAME);
if(ret < 0){
printk("alloc_chrdev_region failed\n");
return -1;
}
//2、为cdev结构体分配内存空间
cdevp = cdev_alloc();
if(NULL == cdevp)
{
printk("cdev_alloc failed\n");
unregister_chrdev_region(dev_num, COUNT);
return -2;
}
//3、设备初始化
cdev_init(cdevp, &fops);
//4、注册字符设备到内核
ret = cdev_add(cdevp, dev_num, COUNT);
if(ret < 0){
printk("cdev_add failed\n");
unregister_chrdev_region(dev_num, COUNT);
return -3;
}
printk("major = %d\n", MAJOR(dev_num));
printk("my_cdev_init sucess\n");
return 0;
}
static void my_cdev_del(void)
{
//5、删除字符设备
cdev_del(cdevp);
//6、注销设备号
unregister_chrdev_region(dev_num, COUNT);
printk("my_cdev_del sucess\n");
}
module_init(my_cdev_init);
module_exit(my_cdev_del);
MODULE_LICENSE("GPL");
2)Makefile
ifneq ($(KERNELRELEASE),)
obj-m := my_chr_dev.o
else
PWD := $(shell pwd)
KVER := $(shell uname -r)
KDIR := /lib/modules/`uname -r`/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.* Module.*
endif
3)测试文件:chr_dev_test.c
#include "stdio.h"
#include "fcntl.h"
#include "unistd.h"
int main(void)
{
int ret;
int fd;
char rd_buf;
fd = open("/dev/led0", O_RDONLY);
if(fd < 0)
{
printf("open failed\n");
return -1;
}
read(fd, &rd_buf, 1);
printf("rd_buf = %d\n", rd_buf);
close(fd);
return 0;
}
运行验证步骤如下:
1)进入自己创建的所在目录下,直接输入make
:
yang@yang-Lenovo:~$ cd ./my_cdev/
yang@yang-Lenovo:~/my_cdev$ ls
chr_dev_test.c led_dev.c Makefile my_chr_dev.c
yang@yang-Lenovo:~/my_cdev$ make
make -C /lib/modules/`uname -r`/build M=/home/yang/my_cdev modules
make[1]: 进入目录“/usr/src/linux-headers-5.0.0-32-generic”
CC [M] /home/yang/my_cdev/my_chr_dev.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/yang/my_cdev/my_chr_dev.mod.o
LD [M] /home/yang/my_cdev/my_chr_dev.ko
make[1]: 离开目录“/usr/src/linux-headers-5.0.0-32-generic”
yang@yang-Lenovo:~/my_cdev$ ls
chr_dev_test.c modules.order my_chr_dev.ko my_chr_dev.o
led_dev.c Module.symvers my_chr_dev.mod.c
Makefile my_chr_dev.c my_chr_dev.mod.o
2)注册字符设备:
sudo insmod my_chr_dev.ko
然后能查看到设备中多了字符设备led_dev:
cat /proc/devices
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
204 ttyMAX
226 drm
*238 led_dev*
239 vfio
240 aux
241 mei
242 hidraw
3)创建字符设备对应的节点:
yang@yang-Lenovo:~/my_cdev$ sudo mknod /dev/led0 c 238 0 //注意:238为主设备号, 0为次设备号
yang@yang-Lenovo:~/my_cdev$ ll /dev/led0
crw-r--r-- 1 root root 238, 0 11月 16 15:24 /dev/led0
4)运行测试程序:
(由3)可以看出yang用户对led0只有’r’权限, 故测试文件中没有测试write,当然可以通过修改权限来测试write)
yang@yang-Lenovo:~/my_cdev$ gcc chr_dev_test.c
yang@yang-Lenovo:~/my_cdev$ ./a.out
rd_buf = 6
5)删除设备节点:
sudo rm /dev/led0
6)卸载字符设备:
sudo rmmod my_chr_dev.ko
(参考链接:https://blog.csdn.net/Xin_101/article/details/84791761)