Linux笔记(14)| 字符设备驱动基础入门(续)

2020-08-28 10:38:08 浏览数 (1)

3、Makefile的编写

前面讲完了最简单的驱动模块的代码结构,这里继续讲解Makefile文件的编写。

代码语言:javascript复制
KERNEL_DIR=/home/jianfei/workdir/linux_driver/ebf-buster-linux/build_image/build

ARCH=arm
CROSS_COMPILE=arm-linux-gnueabihf-
export  ARCH  CROSS_COMPILE

obj-m := led_driver.o
app_obj=led
all:
  $(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules
  arm-linux-gnueabihf-gcc led.c -o $(app_obj)
.PHONE:clean copy

clean:
  $(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean  
  sudo rm /home/jianfei/workdir/*.ko 
  sudo rm /home/jianfei/workdir/$(app_obj)
copy:
  sudo  cp  *.ko $(app_obj)  /home/jianfei/workdir
  

(1)KERNEL_DIR,变量的值就是我们用来编译这个模块的内核源码树的目录

(2)obj-m := led_driver.o,这一行就表示我们要将led_driver.c文件编译成一个模块

(3)make clean ,用来清除编译痕迹

总结:模块的makefile非常简单,本身并不能完成模块的编译,而是通过make -C进入到内核源码树下借用内核源码的体系来完成模块的编译链接的。这个Makefile本身是非常模式化的。

要注意第一个路径必须是自己编译的内核源码树,另外要注意编译工具链的选择,如果是在主机Ubuntu中编译,要使用交叉编译工具链。

编译好了之后就会生成一个.ko的驱动模块文件,我们就可以在linux系统中去安装这个模块,这在上一节已经提到过。

4、验证驱动程序工作是否正常

安装好这个模块之后,如何验证这个驱动模块能否正常工作呢?

在之前的驱动代码中,我们的代码逻辑就是当写入“on”的时候,点亮led灯,当写入“off”的时候,就关闭led灯。那么,到底是向哪里写入?这里涉及到设备文件的创建。之前说过,每个设备都可以抽象成一个设备文件,那么首先要创建这个设备文件,然后将这个设备文件和设备绑定起来,绑定的方法就是依据设备的设备号。我们可以使用mknod命令来创建设备文件。

代码语言:javascript复制
mknod /dev/xxx c 主设备号 次设备号

设备文件的关键信息是:设备号 = 主设备号 次设备号,使用ls -l去查看设备文件,就可以得到这个设备文件对应的主次设备号。

在这个试验中,要验证驱动程序是否正常,应该向设备文件中写入值,方法有两种,一种是直接在终端里面通过echo指令,这样比较简单,还有一种方法就是编写一个应用程序,这种方法在实际中比较常用。

第一种方法很简单,就是

代码语言:javascript复制
sudo sh -c "echo on >/dev/led c 244 0"

on是要写入的内容,/dev/led是设备文件,c代表字符设备,后面两个是主设备号和次设备号,这个是通过前面的mknod指定的。

这里主要讲一下应用程序的编写。其实也很容易,就是利用了之前的系统编程的知识,无非就是open、write这些。

代码语言:javascript复制
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define filename "/dev/led"

char  rbuf[10]={0};
int main(void)
{
    int fd;
    int ret;
    fd=open(filename,O_RDWR);
    if(fd<0)
    {
        perror("open");
        return -1;
    }

   while (1)
   {
       printf("please input on or off to control the led,and q for exitn");
        memset(rbuf,0,sizeof(rbuf));
        scanf("%s",rbuf);
        if(   (!strcmp(rbuf,"on"))  ||  (!strcmp(rbuf,"off"))     )
        {
            write(fd,rbuf,strlen(rbuf));
        }
        else if(!strcmp(rbuf,"q"))
        {
            return 0;
        }
        else
        {
            printf("error!   please input again");
        }
        
   }
   close(fd);
   return 0;
}

我们把编译好的程序放到开发板上执行,就可以在命令行里控制led灯的亮灭了。

当然,如果再要完整一点,应该还要包括类似GUI的设计,因为用户不可能去操作命令行。不过这里暂时不涉及。

好了,以上就是字符设备驱动开发的大致流程,后面将会逐步完善代码,包括建立一些框架什么的。总的来说,驱动部分应该只实现最基本的驱动硬件功能,而应用层部分就要完成用户的各种需求。

0 人点赞