字符设备驱动实验

65 篇文章 13 订阅
19 篇文章 1 订阅

Makefile

这是第一个程序,这里就贴出来程序,后面的就不贴了,都一样的。
Makefile

KERNELDIR := /home/luatao/linux/linux/luatao_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga_luatao
CURRENT_PATH := $(shell pwd)

obj-m := chrdevbase.o

build: kernel_modules

kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

一、驱动程序

chrdevbase.c 实现字符设备读写

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

/**
 * file name:chrdevbase
 * date: 2021-08-12  15:42
 * version:1.0
 * author:luatao
 * describe:Character device drive
 */



#define CHRDEVBASE_MAJOR        200  /*主设备号*/
#define CHRDEVBASE_NAME         "chrdevbase1"      /* 设备名*/

static char readbuf[100];       /* 读缓冲区 */
static char writebuf[100];      /* 写缓冲区 */
static char kerneldata[] = "kernel data!";   /* 被读出的数据 */

/* 打开设备 */
static int chrdevbase_open(struct inode *inode, struct file *filp)
{
    printk("chrdevbase open!\r\n");
    return 0;
}

/* 从设备读取数据 */
static ssize_t chrdevbase_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    int ret;
    /* 读取的是内核空间的数据 ,需要向用户空间发送数据 */
    memcpy(readbuf, kerneldata, sizeof(kerneldata));  
    /* 成功返回0,失败返回没有拷贝成功的数据字节数 */
    ret =  copy_to_user(buf, readbuf, cnt); // 拷贝cnt个数据到用户空间

    if(ret == 0){
        printk("kernel senddata ok!\r\n");
    }else{
        printk("kernel senddata failed!\r\n");
    }

    return 0;
}

/* 往设备写数据 */
static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
    int ret;
     /* 被写入的内核空间的数据 ,需要用户空间向内核空间发送数据 */
    ret = copy_from_user(writebuf, buf, cnt);
    if(ret ==0){
        printk("kernel receivedata:%s\r\n",writebuf);
    }else{
        printk("kernel receivedata failed!\r\n");
    }
    return 0;
}

/* 释放设备 */
static int chrdevbase_release(struct inode *inode, struct file *filp)
{
    /* 加上这一句可能打印信息会出现乱码,这是可能因为打印太快了(猜测)*/
  //  printk("chrdevbase release!\r\n");
    return 0;
}


/* 设备操作函数结构体  */
static struct file_operations chrdevbase_fops = {
    .owner = THIS_MODULE,
    .open = chrdevbase_open,
    .read = chrdevbase_read,
    .write = chrdevbase_write,
    .release = chrdevbase_release,
};

/* 驱动入口函数 */
static int __init chrdevbase_init(void)
{
    int ret = 0;

    /* 注册字符设备驱动 */
    ret = register_chrdev(CHRDEVBASE_MAJOR,CHRDEVBASE_NAME,&chrdevbase_fops);
    if(ret < 0){
        printk("chrdevbase drive register failed!\r\n");
        return ret;
    }
    printk("chrdevbase drive register ok!\r\n");
    return 0;
}


/* 驱动出口函数 */
static void __exit chrdevbase_exit(void)
{
    /* 注销字符设备驱动 */
    unregister_chrdev(CHRDEVBASE_MAJOR,CHRDEVBASE_NAME);
    printk("chrdevbase drive unregsister ok !\r\n");
}

/* 加载驱动入口和出口函数 */
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);

/* LICENSE 和 AUTHOR 信息*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("luatao");

二、应用程序

chrdevbaseApp.c

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

/**
 * file name:chrdevbaseApp
 * date: 2021-08-12  16:17
 * version:1.0
 * author:luatao
 * describe:字符设备驱动测试APP
 * 执行命令:./chrdevbaseApp 1 读取数据 或者是 ./chrdevbaseApp 2 写入数据
 */


static char userdata[] = "user data!";  // 用户空间需要写入的数据

/* 主程序 */
int main(int argc, char *argv[])
{
    char *filename;  // 可执行文件名
    int cmd,fd,ret;  // cmd:输入的命令  fd: 文件句柄 ret:函数操作返回值
    char readbuf[100],writebuf[100]; // 缓冲区
    /* 先判断输入的参数 */
    if(argc !=  3){  // 本身文件名带1个 执行文件1个  读出或者写入一个 
       printf("parameter error!\r\n");
       return -1;
    }

    /* 分析参数 ,提取有用的信息 */
    filename = argv[1];  // 可执行文件名 
    cmd = atoi(argv[2]); // 执行命令

    /* 打开文件 */
    fd = open(filename, O_RDWR);  // 可读可写 
    if(fd < 0){
        printf("can't open file:%s\r\n",filename);
        return -1;
    }

    /* 判断是什么命令 执行什么动作 */
    if(cmd == 1){  // 读取数据 
        ret = read(fd, readbuf, 50);  // 读取50个字符
        if(ret < 0 ){
            printf("read file %s failed !\r\n",filename);
            return -1;
        }else{ // 读取成功
            printf("read data:%s\r\n",readbuf);
        }
    }else if(cmd == 2){// 写入数据
        memcpy(writebuf,userdata,sizeof(userdata));
        ret = write(fd, writebuf, sizeof(userdata));
        if(ret < 0){
              printf("write file %s failed !\r\n",filename);
             return -1;
        }else{ // 写入成功
            printf("write data ok!\r\n");
        }
    }   

    /* 关闭文件 */
    ret = close(fd);
    if(ret < 0){
        printf("can't close file %s \r\n", filename);
        return -1;
    }

    return 0;
}
 

三、测试

加载驱动:
在这里插入图片描述

生成设备文件节点:

mknod /dev/chrdevbase c 200 0


在这里插入图片描述
读数据:

./chrdevbaseApp /dev/chrdevbase 1

在这里插入图片描述
写数据:

./chrdevbaseApp /dev/chrdevbase 2

在这里插入图片描述
卸载驱动:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值