驱动移植 模块的概念、设备驱动、驱动函数open(),release() 7.6

驱动移植

模块

Linux 驱动有两种运行方式,第一种是将驱动编译进 Linux 内核中,当 Linux 内核启动的时就会自动运行驱动程序。第二种是将驱动编译成模块(Linux 下模块扩展名为.ko),在Linux 内核启动以后使用相应命令加载驱动模块。
模块(mod)只允许工作在内核态下
模块在内核中可以动态的(不影响系统的其他功能下)添加和删除
模块可以实现驱动,也可以实现简单的“hello world”(所以模块不一定是驱动)
模块是载体,驱动是功能

模块和应用程序的区别:
	1.模块有两个接口(一个进来的入口init()一个是出去的入口exit()),应用只有一个main的入口(从头到尾的单任务)
	2.模块一旦调用init()接口,会预先注册进内核,告知内核我要执行程序,但不是瞬间执行,而是由人控制执行时间,当exit()被调用时,才算执行结束
	3.模块占用内核空间,权限大,段错误会导致系统崩溃;应用占用应用空间,段错误对系统危害小
	
模块的好处:
	1.减小内核的体积
	2.如果驱动有问题可以直接修改驱动,无需更改内核
	
简单的Linux内核模块
	1.头文件:初始化 #include <linux/init.h>
	Linux表示include下的一个目录
	2.模块加载函数
	3.模块卸载函数
	4.模块信息描述 LICENSE协议必须要写
#module templet
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /home/hqyj/sys/linux-3.14
PWD := $(shell pwd)

all:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
	cp -af *.ko /home/hqyj/sys/newrootfs/
clean:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean

else
    obj-m := mod.o
endif

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZV0sJYcG-1688702593418)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20230706135733728.png)]

/*===============================================
*   文件名称:mod.c
*   创 建 者: memories
*   创建日期:2023年07月06日
*   描    述:have a nice day
================================================*/
    //1.header
#include <linux/init.h>
#include <linux/module.h>
    //2.init/exit fun
    static int myinit(void)
{
    printk("myinit ok\n");
    return 0;
}
    static int myexit(void)
{
    printk("myexit ok\n");
    return ;
}
    //3.reg kernel
module_init(myinit);
module_exit(myexit);
    //4.mod info
MODULE_LICENSE("GPL");
终端上运行:
insmod mod.ko(运行模块)
rmmod mod(结束模块)(如果出现问题 在rootfs/lib/下创建modules目录)
(若继续出现问题,在modules下继续创建目录)
lsmod (查看模块)

外部传参

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BhRGP4qr-1688702521966)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20230706141218742.png)]

static int no = 1;
 12 static char* name = "my led";
 13     
 14 //外部传参
 15 module_param(no,int,0000);
 16 module_param(name,charp,0000);
 17     
 18     //2.init/exit fun
 19     static int myinit(void)
 20 {   
 21     printk("name is %s,no is %d\n",name,no);
 22     printk("myinit ok\n");
 23     return 0;
 24 }   

设备驱动

1.字符设备驱动
	一个一个字节,按照字节流的形式进行读写操作的设备
2.块设备驱动
3.网络设备驱动

驱动向上与内核挂钩,向下面对设备硬件

主设备号:哪一类设备

次设备号:类设备中的哪一个

cat proc/devices (查看已经使用了的设备号)

驱动方式:

1.应用程序 2.驱动文件
应用程序运行在用户空间,驱动文件属于内核,用户空间不能直接对内核进行操作,因此必须使用系统调用的方法来实现用户对于内核的控制。


驱动函数(.c)-->驱动模块(.ko)
在/dev下创建一个与之对应的设备节点文件mknod xx(相当于我们的驱动文件)
运行应用程序(./a.out)--->控制驱动文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7y5SNglj-1688702521966)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20230706191131678.png)]

驱动函数

.open() .release()
int (*open) (struct inode *, struct file *);

int (*release) (struct inode *, struct file *);
/*===============================================
 *   文件名称:mod.c
 *   创 建 者: memories
 *   创建日期:2023年07月06日
 *   描    述:have a nice day
 ================================================*/
//1.header
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#define MA 300
#define MI 0

static dev_t no = 0;
static unsigned count = 1;
static const char *name = "mydev";
static struct cdev mydev;

int myopen(struct inode *pi,struct file *pf)
{
    printk("kernel open\n");
    return 0;
}

int myrelease(struct inode *pi,struct file *pf)
{
    printk("kernel close\n");
    return 0;
}
static const struct file_operations myfops={
    .release = myrelease,
    .open = myopen,

};//文件操作集
//2.init/exit fun
static int myinit(void)
{
    int ret = 1;
    //up: kernel
    //1.registed 把设备对象注册到系统中
    no = MKDEV(MA,MI);//组合主次设备号
    ret = register_chrdev_region(no,count,name);
    if(ret != 0)
    {
        printk("reg is error\n");
        return -1;
    }
    //2.init    设备初始化,抽象出来一个对象
    cdev_init(&mydev,&myfops);
    //3.add     添加设备
    ret = cdev_add(&mydev,no,count);
    if(ret != 0)
    {
        unregister_chrdev_region(no,count);
        return -1;
    }
    //down:hardware
    printk("myinit ok\n");
    return 0;
}
static int myexit(void)
{
    cdev_del(&mydev);
    unregister_chrdev_region(no,count);
    printk("myexit ok\n");
    return ;
}
//3.reg kernel
module_init(myinit);
module_exit(myexit);
//4.mod info
MODULE_LICENSE("GPL"); //使用GPL协议

调用open()函数的流程

  1. 应用调用open()函数
  2. C库中的open函数 (fd = open())
  3. 内核中的open()调用 (strcut file pf = open())
  4. 驱动程序中的open()函数 (my open())

应用函数

/*===============================================
*   文件名称:mainopen.c
*   创 建 者: memories
*   创建日期:2023年07月06日
*   描    述:have a nice day
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{ 
    int fd = open("/dev/mydev",O_RDONLY);
    return 0;
} 
mknod /dev/mydev c 300 0 (创建字符设备文件)
/dev/mydev :创建的一个设备文件
c:设备类型为C字符设备
300:主设备号
0:次设备号
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤独memories

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值