搜索
bottom↓
回复: 4

一个简单的字符设备驱动分析

[复制链接]

出0入4汤圆

发表于 2020-8-14 16:19:21 | 显示全部楼层 |阅读模式
本帖最后由 batou 于 2020-8-14 17:10 编辑

明白了字符设备驱动基本框架与相关概念之后,我们知道一个字符设备驱动如果想要像文件一样去操作,首先肯定需要有设备号,还需要有个驱动名,然后需要填充file_operations结构体,这样才能实现对设备的具体操作,可以开始写代码了,just do it!

#  接口介绍
1、写代码之前,先介绍两个宏
module_init()        //这个是加载模块的时候调用的,相当于模块入口
module_exit()        //这个是卸载模块的时候调用的,相当于模块出口

2、再介绍两个函数
①.注册字符设备驱动函数
用register_chrdev函数注册一个字符设备驱动,这个接口非常方便,传入些参数就一个字符设备注册完事了,虽然该函数算是老的接口了,以前认为要学就学新接口,老接口都淘汰了,学了也没啥用,其实不然,该老接口并没有弃用,并且新接口也只是对它做了拆分,走的还是它内部那些套路,其原型为:
static inline int register_chrdev(unsigned int major,  const char *name, const struct file_operations *fops);
major是主设备号,当它为0时系统会给你动态分配一个,也可以你自己找一个系统中没有用到的,name是字符设备驱动名,insmod之后cat /proc/devices可以看到的名字,*fops是该设备驱动所有操作的接口

②.注销字符设备驱动函数
unregister_chrdev函数,输入需要注销的设备驱动设备号与设备名称就可以了
原型为:static inline void unregister_chrdev(unsigned int major, const char *name)

③.找到一个可用的设备号
在开发板上查看,cat /proc/devices,看哪个设备号没用,一般是0~255,从大的开始选
当然这一步也不是必须的,因为上面说到的那个register_chrdev函数可以让系统给你分配,但是在我们学习过程中,这一步是应该了解的

//驱动代码
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ide.h>

MODULE_LICENSE("GPL");

#define HELLO_CNT        1
#define HELLO_MAJOR    222
#define HELLO_NAME            "hello"

static dev_t dev_num;

//文件打开函数
static int hello_open(struct inode *inode, struct file *file)
{
        printk(KERN_INFO "\nhello_open\n");
       
        return 0;
}

//文件释放函数
static int hello_release(struct inode *inode, struct file *file)
{
        printk(KERN_INFO "\nhello_release\n");

        return 0;
}

static struct file_operations chrdev_fops = {
        .owner                 = THIS_MODULE,        //这里都是这么赋值的,用来在它的操作还在被使用时阻止模块被卸载
       
        //应用层间接调用的就是如下接口, 应用层如果调用没有定义的接口是会出错的
        .open                = hello_open,               
        .release        = hello_release,       
};

//模块加载函数
static int hello_init(void)
{
    printk(KERN_ALERT "hello world!\n");

    //register_chrdev是注册字符设备, 这个接口可以一步到位
        dev_num = register_chrdev(HELLO_MAJOR, HELLO_NAME, &chrdev_fops);
        if (dev_num < 0) {
                printk(KERN_ERR "register_chrdev fail\n");
                return -EINVAL;
        }
        printk(KERN_INFO "register_chrdev success...\n");
    return 0;
}

//模块卸载函数
static void hello_exit(void)
{
        //注销字符设备驱动
    unregister_chrdev(HELLO_MAJOR, HELLO_NAME);
    printk(KERN_ALERT "hello_exit, goodbye!\n");
}

module_init(hello_init);
module_exit(hello_exit);

//测试代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#define FILE "/dev/hello"

int main(void)
{
        int fd = -1;
        int i = 0;

        fd = open(FILE, O_RDWR);
        if (fd < 0) {
                printf("\nopen %s fail:%d\n",  FILE, fd);
                return -1;
        }
        printf("App open %s ok\n", FILE);
       
        close(fd);
}

Makefile内容如下:
KERNELDIR := /home/mstar/ubuntu64/linux
CURRENT_PATH := $(shell pwd)
obj-m := hello_drv.o

build: kernel_modules

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

编译驱动与测试app

然后将hello_drv.ko与helloApp拷贝到开发板的共享盘
我是将ubuntu下的一个文件挂载到linux开发板上的,如通过如下指令:
mount -t nfs -o nolock,nfsvers=3 192.168.0.103:/home/mstar/ubuntu64/share mnt/ttt

# 开始测试
①.驱动加载
使用insmod指令加载驱动
root@ALIENTEK-IMX6U:/mnt/ttt# insmod hello_drv.ko
hello world!
register_chrdev success...

②.查看驱动
使用cat /proc/devices查看

说明驱动已经加载成功了,主设备号是222

③.创建设备文件
使用mknod指令创建设备文件,mknod 的标准形式为:mknod DEVNAME {b | c}  MAJOR  MINOR
如:mknod /dev/hello c 222 0 //其中/dev/hello是设备文件名,在应用程序中就可以通过该名进行访问,该名称是跟设备号绑定在一起的,后面的c代表字符设备,222是主设备号,0是次设备号,次设备号还可以有很多,代表同一种类型的不同文件!
如下:
root@ALIENTEK-IMX6U:/mnt/ttt# mknod /dev/hello c 222 0
root@ALIENTEK-IMX6U:/mnt/ttt# mknod /dev/hello1 c 222 1

于是通过ls -ll /dev查看到了两个文件

④.运行应用程序

下面打印出的字符很明显应用程序能正常运行

⑤.卸载驱动
通过rmmod指令

其中/dev下生成的hello与hello1两个文件需要手动rm删除

#  总结
一个简单的字符设备驱动,代码上的东西并不多,很多步骤都是需要我们手动去完成,像确定设备号、创建/删除设备文件等,这虽然比较麻烦,但在我们前期学习的过程中是有帮助的,我们对整个过程有了一个基本的了解,后面就算切换到由程序完成也有了一个更好的过渡!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入36汤圆

发表于 2020-8-14 16:38:03 | 显示全部楼层
楼主 图看不到

出0入36汤圆

发表于 2020-8-14 16:38:25 | 显示全部楼层
网络卡了,二连了,罪过罪过,楼主看下帖子里的图看不到

出0入4汤圆

 楼主| 发表于 2020-8-14 17:10:37 | 显示全部楼层
norman33 发表于 2020-8-14 16:38
网络卡了,二连了,罪过罪过,楼主看下帖子里的图看不到

修改了下,可以了吧

出0入36汤圆

发表于 2020-8-14 17:13:58 | 显示全部楼层
batou 发表于 2020-8-14 17:10
修改了下,可以了吧

可以了,谢谢分享,文章不错
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 05:42

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表