(2)字符设备驱动基本框架

  • 参考正点原子视频,做记录以及简单使用。

首先创建如下所示文件夹及文件,文件的内容如下三个所示。。。

 

/************************chrdevbase.c*****************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>

#define MAJOR_NUMBER 200
const char* CHR_NAME = "chr_test";


static int chrtest_open(struct inode *inode,struct file *filp)
{
    printk("chrtest_open !!!!\n");
    return 0;
}
//filp:要打开的设备文件(文件描述符)
//buf:返回给用户空间的数据缓冲区
//cnt:要读取的数据长度
//offt:相对于文件首地址的偏移
//return:返回读取到的字节数
static ssize_t chrtest_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    printk("chrtest_read !!!!\n");
    return 0;
}

static ssize_t chrtest_write(struct file *filp,const char __user *buf, size_t cnt, loff_t *offt)
{
    printk("chrtest_write !!!!\n");
    return 0;
}

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

static struct file_operations test_fops = { //实例化一个函数结构体
    .owner = THIS_MODULE,
    .open = chrtest_open,
    .read = chrtest_read,
    .write = chrtest_write,
    .release = chrtest_release,
};


//int major;
int xxx_init(void) //模块入口函数
{
    int retvalue = 0;

    retvalue = register_chrdev(MAJOR_NUMBER, CHR_NAME, &test_fops); //设备注册
    if(retvalue < 0){
        printk("register failed!!!!\n");  //printf 运行在用户态,printk 运行在内核态。
    }
    else{
        printk("register success!!!!\n");
    }



    return 0;
}
 
void xxx_exit(void) //模块退出函数
{
    unregister_chrdev(200, CHR_NAME); //设备注销
}
 

module_init(xxx_init);  
module_exit(xxx_exit);  

MODULE_LICENSE("Dual BSD/GPL");
/************************Makefile*************************/
KERNELDIR := /usr/src/linux-headers-$(shell uname -r) #内核源码目录
CURRENT_PATH := $(shell pwd)  #shell脚本执行pwd,得知当前位置
obj-m := chrdevbase.o #生成文件名

build: kernel_modules
 
 
kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules #表明编译生成的是.ko模块文件
 
clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean #删除生成文件
/*********************chrdevApp.c*************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char* argv[])
{
    int ret = 0;
    char* filename;
    char readbuf[10];
    char writebuf[50];

    int fd = 0;
    filename = argv[1];

    //open(打开的文件名,读写权限);
    fd = open(filename,O_RDWR);  //返回文件描述符  O_RDWR表示读写模式
    if(fd < 0){ //文件打开错误,返回<0
        printf("canot open file %s \r\n", filename);
        return -1;
    }
    else{
        printf(" open file %s sucess \r\n", filename);
    }

    ret = read (fd, readbuf, 50); //从open()打开的fd文件读50个字节
    if(ret < 0){
        printf("read file %s error !!!\n", filename);
    }
    else{
        printf("read file %s success !!!\n", filename);
    }

    ret = write(fd,writebuf, 50);//将writebuf中的50个字节写到fd对应的文件中
    if(ret < 0){
        printf("read file %s error !!!\n", filename);
    }
    else{
        printf("read file %s success !!!\n", filename);    
    }

    ret = close(fd);//关闭打开的fd文件
    if(ret < 0){
        printf("close file %s error !!!\n", filename);
    }
    else{
        printf("close file %s success !!!\n", filename);    
    }                                                                         
}

https://mp.csdn.net/editor/html/113354613配合此链接的第一张图起理解以下的4点) 

  1. 首先第一个文件chrdevbase.c, 此文件通过make编译生成chrdevbase.ko文件,然后通过sudo insmod chrdevbase.ko加载模块,然后用lsmod即可看到加载了的chrdevbase模块,这个时候代表模块已经加载到内核空间,驱动加载成功。。可用dmesg看到在chrdevbase.c中打印的register success!!!!。然后用cat /proc/device即可看到一个名为200 chr_test的chardev设备。
  2. 第二个文件chrdevAPP.c,此文件通过gcc chrdevApp.c -o chrdevApp生成可执行文件chrdevApp。然后在手动创建一个设备节点mknod /dev/chrdevbase c 200 0,(c:字符设备 200:主设备号 0:副设备号)此时通过ls /dev/chrdevbase -l即可查看设备节点chrdevbase文件。然后通过sudo ./chrdevApp /dev/chrdevbase代表执行chrdevApp,输入参数/dev/chrdevbase.
  3. 执行之后,可看到打印的chrdevApp中的内容,表明对文件的open file success等操作成功。而在用dmesg即可看到打印了chrtest_open等。。这表明 chrdevbaseAPP 使用 read 函数从 chrdevbase 设备读取数据,因此chrdevbase_read 函数就会执行并打印chrtest_read。。。
  4. 按照图来理解:用户空间的程序调用open函数对chrdevbase设备文件进行操作,系统调用到内核,内核根据手动创建的设备节点来找到chrdevbase设备驱动程序,然后驱动程序根据我们在chrdevbase.c写的read的函数来执行具体的操作。以上即为字符设备从应用程序到驱动程序的基本框架。。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值