在linux电脑上加载模块

11 篇文章 0 订阅

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

1.须知

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

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

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


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

3.make   编译

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

5.编译测试用的APP

gcc chrdevbaseApp.c -o chrdevbaseApp

6.创建设备节点
mknod /dev/chrdevbase c 200 0

(输入  cat /proc/devices可以查看节点

其中“mknod”是创建节点命令,“/dev/chrdevbase”是要创建的节点文件,“c”表示这是个
字符设备,“ 200”是设备的主设备号,“ 0”是设备的次设备号。创建完成以后就会存在
/dev/chrdevbase 这个文件,可以使用“ls /dev/chrdevbase -l”命令查看,结果如图 40.4.4.7 所示:)

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


在这里插入图片描述

2.具体步骤

1.指定架构
在这里插入图片描述
2.指定编译器
在这里插入图片描述
3.编译模块
在这里插入图片描述
4.加载模块
在这里插入图片描述
5.编译测试用app
在这里插入图片描述
6.测试结果
在这里插入图片描述

3.我的操作步骤

1.文件夹内容
在这里插入图片描述

2.make下
在这里插入图片描述
3.加载
在这里插入图片描述
4.查看模块在这里插入图片描述
5.编译测试APP、测试
在这里插入图片描述

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下测试的)
在这里插入图片描述
从上图可以看到有四个 输入 uname -a 查看
在这里插入图片描述
可以看出 我的是4.15.0-142-generic
因此 把路径改为
在这里插入图片描述

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值