linux学习--2021/9/12

linux简单字符驱动(运行在电脑上,没有运行在开发板上)

文章目录

1.须知

写在前面:
驱动模块运行在linux中,满足条件:

1.编译的时候,架构要和电脑架构一样
输入  arch   可查看架构

如果是x86-64   就输入   export ARCH=x86-64


2.编译器不能是交叉编译器
用gcc 就行了
输入  export arm=CROSS_COMPILE gcc

3.make   编译

4.加载模块  
如果不行  就sudo 一下
(如果显示已经有该模块了  就sudo rmmod chrdevbase.ko,卸载一下)

5.编译测试用的APP

gcc chrdevbaseApp.c -o chrdevbaseApp

6.运行测试
sudo ./chrdevbaseApp /dev/chrdevbase  1


linux学习--2021/9/12

2.具体步骤

1.指定架构
linux学习--2021/9/12
2.指定编译器
linux学习--2021/9/12
3.编译模块
linux学习--2021/9/12
4.加载模块
linux学习--2021/9/12
5.编译测试用app
linux学习--2021/9/12
6.测试结果
linux学习--2021/9/12

3.我的操作步骤

1.文件夹内容
linux学习--2021/9/12

2.make下
linux学习--2021/9/12
3.加载
linux学习--2021/9/12
4.查看模块linux学习--2021/9/12
5.编译测试APP、测试
linux学习--2021/9/12

4.源码及下载

百度网盘
链接:https://pan.baidu.com/s/1Ift0bAbCpySsdUxe2dF3xg
提取码:7ja1

1.Makefile

KERNELDIR :=/usr/src/linux-headers-4.15.0-142-generic
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

KERNELDIR :=/usr/src/linux-headers-4.15.0-142-generic
指的是内核源码地方

…内核在系统目录下的路径,一般为:/usr/src/(我的ubuntu下测试的)
linux学习--2021/9/12
从上图可以看到有四个 输入 uname -a 查看
linux学习--2021/9/12
可以看出 我的是4.15.0-142-generic
因此 把路径改为
linux学习--2021/9/12

2.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>
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名		: chrdevbase.c
作者	  	: 左忠凯
版本	   	: V1.0
描述	   	: chrdevbase驱动文件。
其他	   	: 无
论坛 	   	: www.openedv.com
日志	   	: 初版V1.0 2019/1/30 左忠凯创建
***************************************************************/

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

static char readbuf[100];		/* 读缓冲区 */
static char writebuf[100];		/* 写缓冲区 */
static char kerneldata[] = {"kernel data!"};

/*
 * @description		: 打开设备
 * @param - inode 	: 传递给驱动的inode
 * @param - filp 	: 设备文件,file结构体有个叫做private_data的成员变量
 * 					  一般在open的时候将private_data指向设备结构体。
 * @return 			: 0 成功;其他 失败
 */
static int chrdevbase_open(struct inode *inode, struct file *filp)
{
	//printk("chrdevbase open!\r\n");
	return 0;
}

/*
 * @description		: 从设备读取数据 
 * @param - filp 	: 要打开的设备文件(文件描述符)
 * @param - buf 	: 返回给用户空间的数据缓冲区
 * @param - cnt 	: 要读取的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 读取的字节数,如果为负值,表示读取失败
 */
static ssize_t chrdevbase_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
	int retvalue = 0;
	
	/* 向用户空间发送数据 */
	memcpy(readbuf, kerneldata, sizeof(kerneldata));
	retvalue = copy_to_user(buf, readbuf, cnt);
	if(retvalue == 0){
		printk("kernel senddata ok!\r\n");
	}else{
		printk("kernel senddata failed!\r\n");
	}
	
	//printk("chrdevbase read!\r\n");
	return 0;
}

/*
 * @description		: 向设备写数据 
 * @param - filp 	: 设备文件,表示打开的文件描述符
 * @param - buf 	: 要写给设备写入的数据
 * @param - cnt 	: 要写入的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 写入的字节数,如果为负值,表示写入失败
 */
static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
	int retvalue = 0;
	/* 接收用户空间传递给内核的数据并且打印出来 */
	retvalue = copy_from_user(writebuf, buf, cnt);
	if(retvalue == 0){
		printk("kernel recevdata:%s\r\n", writebuf);
	}else{
		printk("kernel recevdata failed!\r\n");
	}
	
	//printk("chrdevbase write!\r\n");
	return 0;
}

/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @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,
};

/*
 * @description	: 驱动入口函数 
 * @param 		: 无
 * @return 		: 0 成功;其他 失败
 */
static int __init chrdevbase_init(void)
{
	int retvalue = 0;

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

/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static void __exit chrdevbase_exit(void)
{
	/* 注销字符设备驱动 */
	unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);
	printk("chrdevbase exit!\r\n");
}

/* 
 * 将上面两个函数指定为驱动的入口和出口函数 
 */
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);

/* 
 * LICENSE和作者信息
 */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");


3.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"

/***************************************************************

Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.

文件名		: chrdevbaseApp.c

作者	  	: 左忠凯

版本	   	: V1.0

描述	   	: chrdevbase驱测试APP。

其他	   	: 使用方法:./chrdevbase /dev/chrdevbase <1>|<2>

  			 argv[2] 1:读文件

  			 argv[2] 2:写文件		

论坛 	   	: www.openedv.com

日志	   	: 初版V1.0 2019/1/30 左忠凯创建

***************************************************************/



static char usrdata[] = {"usr data!"};



/*

 * @description		: main主程序

 * @param - argc 	: argv数组元素个数

 * @param - argv 	: 具体参数

 * @return 			: 0 成功;其他 失败

 */

int main(int argc, char *argv[])

{

	int fd, retvalue;

	char *filename;

	char readbuf[100], writebuf[100];



	if(argc != 3){

		printf("Error Usage!\r\n");

		return -1;

	}



	filename = argv[1];



	/* 打开驱动文件 */

	fd  = open(filename, O_RDWR);

	if(fd < 0){

		printf("Can't open file %s\r\n", filename);

		return -1;

	}



	if(atoi(argv[2]) == 1){ /* 从驱动文件读取数据 */

		retvalue = read(fd, readbuf, 50);

		if(retvalue < 0){

			printf("read file %s failed!\r\n", filename);

		}else{

			/*  读取成功,打印出读取成功的数据 */

			printf("read data:%s\r\n",readbuf);

		}

	}



	if(atoi(argv[2]) == 2){

 	/* 向设备驱动写数据 */

		memcpy(writebuf, usrdata, sizeof(usrdata));

		retvalue = write(fd, writebuf, 50);

		if(retvalue < 0){

			printf("write file %s failed!\r\n", filename);

		}

	}



	/* 关闭设备 */

	retvalue = close(fd);

	if(retvalue < 0){

		printf("Can't close file %s\r\n", filename);

		return -1;

	}



	return 0;

}






参考@原子哥
https://so.csdn.net/so/search?q=linux%20&t=blog&u=weixin_55796564

上一篇:(CVPR-2020)GaitPart:基于时间部分的步态识别模型(一)


下一篇:30.Linux-printk分析、使用__FILE__, __FUNCTION__, __LINE__ 调试