简单的驱动编写:函数,流程,通信

1,编写一个空壳驱动,所需函数

        (1)模块安装函数 __init 和卸载函数 __exit : #include <linux/init.h>

        (2)如何调用上述的注册 : module_init  和  module_exit

        (3)register_chrdev(函数参数参考内核源码);向内核使用 file_operations 结构体注册自己的驱动
    
                成功返回0,失败返回其它

                major : 设备驱动的号(标志当前设备的编号 正数 1~ 255)

                *name : 设备名字 (当前设备驱动的,名字)

                *fops :    指向file_operations结构体

        (4)unregister_chrdev; 宏在 模块退出时,要记得回收

                        static inline void unregister_chrdev(unsigned int major, const char *name)

        (5)file_operations ; 结构体里封装的是 应用层的函数调用(函数指针)

 示例:                          

static const struct file_operations test_fops = {
	.owner = THIS_MODULE,
	
	.open  = test_chardev_open,		//打开文件
	.release = test_chrdev_release, //关闭文件,内核中close就是(release)
	
};

2, 如何让内核给我们自动分配设备号

        register_chrdev;函数注册的时候  major 给的值为0 即可

3,设备文件的创建 (应用层读写的是 安装模块的 设备文件)

        (1)查看所安装模块分配的设备号 : cat /proc/devices

        (2)mknod /dev/test c 250 0
    
                    mknod /dev/xxx c(字符设备文件) 主设备号 次设备号

4,应用和驱动之间的数据交换

    PS :应用层的数据不能直接传输到内核驱动当中,内核有提供到函数。主要思想:复制

       (1)copy_from_user : 将用户空间数据,传输到内核空间

                        原型copy_from_user(void *to, const void __user *from, unsigned long n);

                                *to : 内核buf空间

                                *from : 用户buf空间

                                unsigned long n : 多个个字节
    
       (2)copy_to_user : 将内核空间数据,传输到内核空间

5,简单驱动实例

        驱动:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>



#define TESTNAME "chrdev"

static int test_chardev_open(struct inode *inode, struct file *file);
static int test_chrdev_release(struct inode *inode, struct file *file);

int  major; //用来保存自动分配的驱动设备号

//1,自定义一个 file_operations test_fops 结构体变量,自己去填充
static const struct file_operations test_fops = {
	.owner = THIS_MODULE,
	
	.open  = test_chardev_open,		//打开文件
	.release = test_chrdev_release, //关闭文件,内核中close就是(release)
	
};


//2,注册驱动模块

static int __init chrdev_init(void)
{
	
	
	printk(KERN_INFO"test_chrdev_init is OK!\n");
	
	 major = register_chrdev(0,TESTNAME,&test_fops);  //注册设备号
	if (major < 0)
	{
		printk(KERN_ERR "register_chrdev fail\n");
		
		return -EINVAL;  //内核中的宏,用来知晓出错是怎样的
	}
	
	printk(KERN_INFO"register_chrdev success..\n");
	
	return 0;
	
}

//3,模块卸载
static void __exit chrdev_exit(void)
{
	unregister_chrdev( major,TESTNAME);
	
	printk(KERN_INFO"test_chrdev_exit is OK!\n");
	
}

//4,open函数实现
static int test_chardev_open(struct inode *inode, struct file *file)
{
	printk(KERN_INFO"test_chardev_open is OK\n");
	
	return 0;
}

//5,close 关闭函数实现
 static int test_chrdev_release(struct inode *inode, struct file *file)
 {
	 printk(KERN_INFO "test_chrdev_release is OK\n");
	 
	 return 0;
 }


module_init(chrdev_init);
module_exit(chrdev_exit);


MODULE_LICENSE("GPL");				// 描述模块的许可证
MODULE_AUTHOR("gj");				// 描述模块的作者
MODULE_DESCRIPTION("module test");	// 描述模块的介绍信息
MODULE_ALIAS("xxx");			// 描述模块的别名信息

        应用 :

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


#define FILE	"/dev/test"			// 刚才mknod创建的设备文件名


int main(void)
{
	int fd = -1;
	
	fd = open(FILE, O_RDWR);
	if (fd < 0)
	{
		printf("open %s error.\n", FILE);
		return -1;
	}
	printf("open %s success..\n", FILE);
	
	// 读写文件
	
	
	// 关闭文件
	close(fd);
	
	return 0;
}

 Makefile :

# 开发板的linux内核的源码树目录
KERN_DIR = /kernel


obj-m   += linux.o

all:
        make -C $(KERN_DIR) M=`pwd` modules 
        arm-linux-gnueabi-gcc app.c -o app #应用程序要在开发板上运行,用gcc交叉编译链

cp:
        cp *.ko /home/aston/rootfs/rootfs/driver_test
        cp app /home/aston/rootfs/rootfs/driver_test
        

.PHONY: clean
clean:
        make -C $(KERN_DIR) M=`pwd` modules clean

现象 :上述准确无误后

                (1)lsmod 安装模块和 rmmod 卸载模块,会看到正确打印的信息。

                (2)mknod 创建完成设备文件之后,执行 应用程序,也会看到正确的打印信息。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值