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
卸载驱动: