第1个linux驱动___应用程序才是大Boss

我们的驱动模块已经可以被自动分配主设备号了,可以说到目前为止,一个驱动模块所具备的一些“基础设施”它都具备了,就像是养兵前日,用兵一时,已经可以让first_drv这个驱动模块出去打仗了。

那么说是出去打仗,总得有个发号施令的首长吧,在linux系统中,这位调兵遣将的首长就是应用程序,应用程序才是大Boss,我们“一直精雕细琢的驱动模块”说白了只是个跑腿的。

这就是为什么我们的专题是第1个linux驱动却要讲应用程序的原因,因为应用程序是让驱动程序能够被应用的,而驱动程序是让应用被驱动的,两者是一种主仆关系、合作关系,在linux系统中缺一不可。

其实说到应用程序,大家应该还会有一种亲和感,它也是C语言写的,不过在写应用程序之前,你最好对C语言的文件IO操作有所了解。

应用程序的名字就定为app.c吧,首先得有一个main函数:

int main(void)
{     
    return 0;
}

框架已经完成,那我们要在app.c里写什么才能实现对first_drv这个驱动的调用呢。

我们说过是通过register_chrdev这个函数向内核中注册驱动后,系统中就能够访问并使用这个驱动了,而向内核注册驱动指的是将驱动的信息存放在一个数组中,而存放在这个数组中的第几个元素是取决于驱动程序的主设备号的,比如主设备号是100,就那就是存放在数组的第100个格子中。

其实应用程序是通过设备文件来找到驱动的,那么最好的方法就是通过打开这个设备文件,得知驱动的主设备号是多少,再通过这个主设备号来找到驱动。

我们通过执行:"mknod /dev/test 主设备号 次设备号"这个命令来建立一个设备文件。

如执行:mknod /dev/test 100 0 就建立了一个主设备号为100、次设备号为0的设备文件,这个次设备号是什么我们暂时不去关心,我们只要知道主设备号100对应了唯一的一个驱动模块。

有了100这个主设备号,就能找到确定的驱动模块。

我们稍后再建立first_drv的设备文件/dev/test,先来在app.c中把打开设备文件/dev/test的代码写好:

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

int main(void)
{
    int fd = -1;
    
     fd = open("/dev/test", O_RDWR);
     
     if(fd < 0)
     {
        printf("Open /dev/test failure!\n");
        return -1;
     }
     
     printf("Open /dev/test success...\n");
     
     close(fd);
          
     return 0;
}

open是linux内核为我们提供的访问系统的API接口,像这样的系统调用还有read、write、close等。

由于添加了app.c,在编译之前,我们得修改Makefile的all、cp和clean命令如下:

#KERN_VER = $(shell uname -r)
#KERN_DIR = /lib/modules/$(KERN_VER)/build
KERN_DIR = /work/kernel/linux-2.6.22.6

all:
        make -C $(KERN_DIR) M=`pwd` modules 
        arm-linux-gcc -o app app.c
        
cp:
        cp *.ko app /work/my_drivers/ko_file
        
clean:
        make -C $(KERN_DIR) M=`pwd` modules clean
        rm -rf Module.symvers app
        
obj-m   += zero_drv.o

修改好Makefile后,来执行make:

可以看到生成了app这个可执行文件,make cp将它和first_drv.ko拷贝到最小根文件系统的/mnt目录下。

在/mnt目录下执行:./app(执行前要确保已经安装驱动模块first_drv)

打印:Open /dev/test failure!

打开设备文件/dev/test失败,这是我们app.c中自己写的打开设备文件失败时的打印信息。

为什么打开失败,因为我们还没有创建这个设备文件,

我们先来cat /proc/devices查看一下当前first_drv驱动模块的主设备号是多少,我这里是252,你们去查看自己的主设备号是多少。次设备号暂定0好了。

我这边执行:mknod /dev/test c 252 0

没有异常,创建成功。

然后执行./app

显示:

It is in first_drv_open.

Open /dev/test success...It is in first_drv_release.

(此处是空行)

(光标在这行)

其中“It is in first_drv_open.”是我们驱动程序中first_drv_open函数的打印信息,而“Open /dev/test success...”是应用程序中的打印信息,我们看到紧接着没有回车,就打印了“It is in first_drv_release.”,这是我们驱动程序中first_drv_release函数的打印信息。

奇怪的是我们明明加了/n,为什么没有回车呢,这是因为驱动程序的优先级比应用程序要高,当应用程序正在打印信息时,如果驱动程序中也要执行打印信息,那么就会优先让驱动程序来打印信息,当驱动程序打印完成后,再让应用程序来打印信息,这就是为什么第3句话直接接在了第2句话的后面,而第3句话后又输出了第2句话最后的回车。

这一点不影响我们的功能测试,对于这个现象我们心知肚明就好。

总而言之,我们通过运行应用程序,让驱动得以工作了。

我们来对应用程序app.c进行一点小改进:

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

#define FILE "/dev/test"

int main(void)
{
    int fd = -1;
    
    fd = open(FILE, O_RDWR);
     
     if(fd < 0)
     {
        printf("Open %s failure!\n", FILE);
        return -1;
     }
     
     printf("Open %s success...\n", FILE);
     
     close(fd);
     
     return 0;
}

无非就是添加了一个宏定义,这样便于修改设备文件名。

再测试一次,同样可以让驱动程序工作。

但我们目前的调用仅仅只是让驱动程序打印个信息,下一篇博文我们来继续完善驱动程序,让驱动程序在被应用程序调用的时候,能够做更多的事情。

时间: 2024-08-12 20:11:49

第1个linux驱动___应用程序才是大Boss的相关文章

第1个linux驱动___整个系统是怎样工作的

接着上一篇博文中,我们已经在first_drv.c中写好了空壳驱动程序. 但是编译这个空壳驱动程序之前,我们需要了解整个系统是怎么工作的. 不着急,首先,我们先来了解一点linux驱动的基本概念: linux驱动分为字符设备驱动.块设备驱动.网络设备驱动. 这是按照驱动程序对不同的硬件的操作方式差异而划分的: [ 字符设备驱动 ] 以字节级别的数据量来对硬件设备进行操作,涉及的硬件如:LED.LCD.串口.触摸屏等. [ 块设备驱动 ] 则操作的数据量较大,如读写存储芯片的驱动就是块设备驱动,一

Linux驱动之触摸屏程序编写

本篇博客分以下几部分讲解 1.介绍电阻式触摸屏的原理 2.介绍触摸屏驱动的框架(输入子系统) 3.介绍程序用到的结构体 4.介绍程序用到的函数 5.编写程序 6.测试程序 1.介绍电阻式触摸屏的原理 所谓的电阻式触摸屏,只不过是在LCD屏幕上贴了一层膜,这层膜的大小与LCD的尺寸刚好相同,它分为上下两层膜(假设上层为X膜,下层为Y膜),按下膜的不同位置,会产生不同的电压值,这样根据不同的电压值可以确定触点的位置,这就是触摸屏的基本原理.其实是利用了最简单的电阻分压原理. 下面的图是四线式电阻触摸

第1个linux驱动___搭建环境,蓄势待发

如何开始写最简单的linux驱动? 在阅读本文前,你需要对linux的基本知识.ubuntu虚拟机的安装与命令行操作有基本的了解. 环境搭建:我在windows电脑上使用VMware打开安装好的虚拟机ubuntu9.0,ubuntu是运行linux内核的linux发行版. 我习惯secureCRT通过SSH远程登录到虚拟机上操作,当然你也可以直接在虚拟机环境下操作. 在根目录下建立一个目录树: cd / mkdir -p /work/my_drivers/frist_drv/1th 进入底层目录

第1个linux驱动___打印&quot;hello world&quot;

为了方便后续的深入,我们在驱动程序中用printk( )函数来打印"hello world",printk( )是内核中自带的函数,专门用于在打印内核信息. 在安装驱动模块到内核中的时,需要进行驱动模块的初始化,初始化具体做什么我们先不提,我们暂时只用printk( )打印"hello world": int first_drv_init(void) { printk("hello world!\n"); return 0; } · 关于prin

第1个linux驱动___安装驱动模块之内核再爱我一次

在上一篇博文中,我们已经通过Makefile编译得到first_drv.ko文件,这是一个可以被安装到ubuntu中的驱动模块,要怎样做呢? 在/work/my_drivers/first_drv/1th/目录下执行:insmod first_drv.ko 如果你是在普通用户状态下执行的这条命令,可以看到系统提醒我们:insmod: error inserting 'first_drv.ko': -1 Operation not permitted 这是因为安装驱动模块需要超级权限,你可以在普通

第1个linux驱动___给驱动模块上户口

我们已经成功地通过开发板的最小根文件系统的/mnt目录挂接了虚拟机ubuntu的/work/my_drivers/ko_file目录下的内容,我们只要在最小根文件系统环境中执行:insmod /mnt/first_drv.ko,即可把ubuntu中编译好的first_drv.ko安装到开发板的内核中,卸载执行:rmmod first_drv或rmmod first_drv.ko即可. 下面,先来写一个方便我们挂接到虚拟机ubuntu的/work/my_drivers/ko_file的脚本,在最小

第1个linux驱动___编译空壳驱动程序

在上一篇博文中我们已经了解到整个系统中各个层次之间是如何协调如何工作的,应用层发出的命令经由内核下达到驱动层,从而达到操作硬件层的目的. 我们先回顾上上篇博文最后成型的"空壳驱动程序"first_drv.c中的代码: #include <linux/module.h> #include <linux/init.h> static int __init first_drv_init(void) {        printk(KERN_INFO"hell

第1个linux驱动___给驱动模块上户口(二)

从这篇博文开始,我们终于可以给我们的驱动模块first_drv一个正式的编制了,现在他已经填好了自己的户口登记信息表,距离拿户口本儿只有一步了! 内核内部有自己的一套安装驱动模块的方法,就像是民政局工作人员知道怎么给一个人办户口一样,对于一个普通公民来说,工作人员做了哪些操作办好了户口本,并不是普通公民需要关心的,我们最关心的是如何把我们填好的户口信息登记表交给工作人员,如何向工作人员表明我们有办户口的请求. 在linux系统中,对于字符设备驱动,我们通过register_chrdev这个函数来

第1个linux驱动___投靠NFS网络文件系统

之前我们一直是在虚拟机ubuntu环境中测试我们的first_drv驱动模块,但是这不是我们的开发方向,在刚开始的学习中我们避免搭建过多的环境,因此选择了只在ubuntu中测试驱动. 我们的模式是: [first_drv.c]-->[使用ubuntu内核源码编译]-->[first_drv.ko(可运行于虚拟机)]--> [ 安装到虚拟机中 ]-->[ hello world! ]-->[ 从虚拟机中卸载 ]-->[ goodbye world... ] 但是我们的最终