第一个驱动程序(在Ubuntu系统下运行)

发布时间 2023-10-21 16:46:05作者: imxiangzi

一、构造内核源码树

# apt-cache search linux-source
# apt-get install linux-source-4.4.0(下载的源码在目录/usr/src下)
# 解压内核源码tar xjf .....
进入源码目录
# make oldconfig
# make
# make modules
make modules_install
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

ref:http://blog.chinaunix.net/uid-24782829-id-3211008.html

由于我主机本身内核版本就为4.4.0-21-generic,所以/lib/modules/4.4.0-21-generic/本身就存在,所以上述过程就不需要执行了。至此,构造内核源码树完成。

make时报错:

scripts/sign-file.c:23:30: fatal error: openssl/opensslv.h: 没有那个文件或目录 compilation terminated. scripts/Makefile.host:91: recipe for target 'scripts/sign-file' failed make[1]: *** [scripts/sign-file] Error 1 Makefile:566: recipe for target 'scripts
  • 1

解决方法:ubuntu下缺少了如下的组件,安装一下即可

sudo apt-get install libssl-dev
  • 1

二、在Linux下写驱动程序

源代码firstdrv.c:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>

static int first_drv_open(struct inode *inode, struct file *file)
{
    printk("first_drv_open\n");
    return 0;
}

static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
    printk("first_drv_write\n");
    return 0;
}

static struct file_operations first_drv_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open   =   first_drv_open,     
    .write  =   first_drv_write,       
};

static int first_drv_init(void)
{
    register_chrdev(246, "first_drv", &first_drv_fops); // 注册, 告诉内核
    return 0;
}

static void first_drv_exit(void)
{
    unregister_chrdev(246, "first_drv"); // 卸载
}

module_init(first_drv_init);
module_exit(first_drv_exit);

MODULE_LICENSE("GPL");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

makefile:

obj-m:=firstdrv.o  #注意.o文件名要和驱动程序文件名一致
CURRENT_PATH :=$(shell pwd)  
LINUX_PATH :=/lib/modules/4.4.0-21-generic/build

all:  
    make -C $(LINUX_PATH) M=$(CURRENT_PATH) modules  
clean:  
    make -C $(LINUX_PATH) M=$(CURRENT_PATH) clean  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
# make 编译模块
# insmod firstdrv.ko
#lsmod 
#cat /proc/devices
  • 1
  • 2
  • 3
  • 4

测试程序firstdrvtest.c:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

int main()
{
    int fd;
    int val=1;
    fd=open("/dev/xyz",O_RDWR);
    if(fd<0)
        printf("can't open\n");
    write(fd,&val,4);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
# mknod /dev/xyz c 246 0 创建设备节点
# ./firstdrvtest 执行测试程序
  • 1
  • 2

2017/9/15目前的情况是firstdrv.c可以正常加载(insmod)到/proc/devices,lsmod命令也能够看到该模块,但是给/dev/xyz创建节点后,在执行firstdrvtest测试时,无法打开该文件。
这里写图片描述
2017/9/18切换成root用户执行./firstdrvtest可执行文件,文件可以打开,但没有按照模块中open和write函数指定的方式打印信息,打印信息只可以在日志中查看。查了原因,是因为printk函数运行在内核态,如果要让它显示到虚拟终端上,还要加上其他的配置,如果不更改printk函数的显示等级,只能用dmesg命令查看输出信息,我又花了点时间折腾了下修改printk的输出日志等级,但是不知道是哪里操作不对,也没有实现理想的效果,暂且把这个问题搁下,接下来学习如何实现设备模块自动设置设备号和设备节点先。
这里写图片描述

 

 

from:  https://codeleading.com/article/62054156384/