嵌入式培训机构四个月实训课程笔记(完整版)-Linux ARM驱动编程第五天-ARM Linux编程之字符设备驱动(物联技术666)

链接:https://pan.baidu.com/s/1V0E9IHSoLbpiWJsncmFgdA?pwd=1688
提取码:1688

教学内容:

1、内核模块的简单框架:

__init __exit执行完后就释放空间

简单框架:包含三个部分

1)模块初始化和模块退出函数

2)注册模块函数

3)模块许可

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

#include <linux/module.h>    /*module_init()*/

#include <linux/kernel.h>        /* printk() */

#include <linux/init.h>            /* __init __exit */

static int __init myModule_init(void)   //红色名可自定义,使用static保证只能在本文件中调用

{

       /* Module init code */

       PRINTK("myModule_init\n");

       return 0;

}

static void __exit myModule_exit(void)          //红色名可自定义

{

       /* Module exit code */

       PRINTK("myModule_exit\n");

       return;

}

module_init(myModule_init);    //注册模块函数

module_exit(myModule_exit);   //注册

MODULE_AUTHOR("zhangda");       /*模块作者,可选*/

MODULE_LICENSE("GPL");                   /*模块许可证明,描述内核模块的许可权限,必须*/

MODULE_DESCRIPTION("A simple Hello World Module"); /*模块说明,可选*/

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

makefile的编写

驱动有两种方式,一为内核树之内,一为内核树以外,前者有点复杂,涉及到将驱动放到合适的内核树目录,修改相应的Makefile以及Kconfig文件,不过,天下无难易之事,为之,难亦不难了;后者所做的劳动就不用那么多了。这个Makfile只适合于后者。此外,内核的Makefile跟一般的应用程序的Makefile不太一样,就像驱动程序跟应用程序,内核头文件跟应用程序头文件等等,没必然关系,或者说是两码事,两者不能混为一谈。再有一点,驱动是跟内核打交道的,你的系统中必须有一个内核源代码。

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

obj-m := module_test.o    //目标文件

ifneq ($(KERNELRELEASE),)

KERNELDIR = $(KERNELRELEASE)

else

KERNELDIR = /home/zhangda/linux_kernel/linux-2.6.34    //内核源代码地址

endif

$(PWD) := $(shell pwd)

default:

       $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

       rm -rf *.o *.mod.c *.order *.symvers

clean:

       rm -rf *.ko

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

2、模块间符号的相互引用

       在模块编程或内核编程中经常会遇到需要调用其它模块中符号的情况,在内核中专门有一张表来管理这些符号,可以通过 cat/proc/kallsyms查看该内核符号表我们也可以自己编写一个模块,并导出其符号供其它模块使用。

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

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

上图1,通过EXPORT_SYMBOL导出模块符号,方便图2使用符号函数。由于是给文件外函数使用,所以不能使用static修饰函数。

3linux字符设备驱动结构

描述字符设备的结构体(详细参考内核和宋宝华的设备驱动书)

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

struct cdev {

       struct kobject kobj;     //内嵌kobject 对象

       struct module *owner;      //所属模块

       const struct file_operations *ops;    //文件操作结构

       struct list_head list;   

       dev_t dev;    //设备号

       unsigned int count;

};

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

设备号为32位,高12位为主设备号,低20位为次设备号;

此结构体描述了字符设备的信息,其中struct file_operations *ops结构体是向用户提高SPI接口函数的重要结构体。

file_operations :

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

#include <linux/fs.h>

struct file_operations {

       struct module *owner;

// 指向拥有该结构的模块的指针,避免正在操作时被卸载,一般为初始化为THIS_MODULES

       loff_t (*llseek) (struct file *, loff_t, int);

       ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);//读接口

       ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);//写接口

       ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);

       ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);

       int (*readdir) (struct file *, void *, filldir_t);

       unsigned int (*poll) (struct file *, struct poll_table_struct *);

       int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);//io控制接口

       long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

       long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

       int (*mmap) (struct file *, struct vm_area_struct *);

       int (*open) (struct inode *, struct file *);//打开接口

       int (*flush) (struct file *, fl_owner_t id);

       int (*release) (struct inode *, struct file *);//关闭接口

       int (*fsync) (struct file *, struct dentry *, int datasync);

       int (*aio_fsync) (struct kiocb *, int datasync);

       int (*fasync) (int, struct file *, int);

       int (*lock) (struct file *, int, struct file_lock *);

       ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);

       unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);

       int (*check_flags)(int);

       int (*flock) (struct file *, int, struct file_lock *);

       ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);

       ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);

       int (*setlease)(struct file *, long, struct file_lock **);

};

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

字符驱动设备的注册:

int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)

(内联函数)

第一个参数:主设备号,int型,0为内核自动分配

第二个参数:设备名

第三个参数:file_operations的结构体地址

返回分配的主设备号,大于0,错误返回负值。

void unregister_chrdev(MAJOR_NR, DRIVER_NAME);(内联函数)

第一个参数:分配的主设备号

第二个参数:设备名

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

MAJOR_NR = register_chrdev(MAJOR_NR, DRIVER_NAME, &GPG_fops);

if(MAJOR_NR < 0)

{

       PRINTK("register char device fail!\n");

       return MAJOR_NR;

}

unregister_chrdev(MAJOR_NR, DRIVER_NAME);

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

自动创建节点:

#include<linux/device.h>

static struct class *my_class;

my_class= class_create(THIS_MODULE, "my_class");

device_create(my_class,NULL,dev_n,NULL,"hello");

注意:dev_n = MKDEV(MAJOR_NR, MINOR_NR);

设备卸载删除类和设备节点

device_destroy(my_class,dev_n);

class_destroy(my_class);

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

my_class=class_create(THIS_MODULE,"udev_gpg");

device_create(my_class,NULL, MKDEV(MAJOR_NR, MINOR_NR), NULL,DRIVER_NAME);

device_destroy(my_class,MKDEV(MAJOR_NR, MINOR_NR));

class_destroy(my_class);

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

用户态与内核态数据的交互:

用户应用程序与驱动程序分属于不同的进程空间,因此二者之间的数据应当采用以下函数进行交换

#include <asm/uaccess.h>

copy_to_user(user_buffer, kernel_buffer, n)

//从内核空间拷贝n字节数据到用户空间

copy_from_user(kernel_buffer, user_buffer, n)

//从用户空间拷贝n字节数据到内核空间

put_user(kernel_value, user_buffer)

//从内核空间拷贝一数据变量到用户空间

get_user(kernel_value, user_buffer)

//从用户空间拷贝一数据变量到内核空间

(内核空间数据可是任意类型)

字符设备驱动的流程:

1)、建立__init和__exit函数;并注册这2个函数module_init,module_exit,声明MODULE_LICENSE;

2)、创建file_operations结构体,并指明函数地址;

3)、字符设备驱动的注册,在__init函数里面注册,在__exit注销;

4)、在__init函数里面完成节点创建,在__exit注销节点;

5)、编写file_operations结构体中的函数,具体功能可以结合裸机驱动编写功能

例如:

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

#include <linux/module.h>             /*module_init()*/

#include <linux/kernel.h> /* printk() */

#include <linux/init.h>      /* __init __exit */

#include <linux/fs.h>        /* file_operation */

#include <asm/uaccess.h> /* copy_to_user, copy_from_user */      

#include <linux/device.h>  /*class ,class_create ,device_create 等*/

#define GPGCON      (*(volatile unsigned long *)S3C2410_GPGCON) //虚拟地址

#define GPGDAT     (*(volatile unsigned long *)S3C2410_GPGDAT)

#define GPGUP      (*(volatile unsigned long *)S3C2410_GPGUP)

#include "my_ioctl.h"

#define MAJOR_NAME "my_ioctl_drv"

static int MAJOR_NR = 0;

static int MINOR_NR = 0;

struct class *myclass;

static int io_open(struct inode *inode, struct file *filp)

{     }

static int io_release(struct inode *inode, struct file *filp)

{     }

static ssize_t io_read(struct file *filp, char *buf,size_t count, loff_t *f_pos)

{     }

static ssize_t io_write(struct file *filp, const char *buf,size_t count, loff_t *f_pos)

{     }

static int io_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg)

{     }

static struct file_operations ioctl_file_opt = {

       .owner = THIS_MODULE,

       .write = io_write,

       .read = io_read,

       .ioctl = io_ioctl,

       .open = io_open,

       .release = io_release,

};

static int __init my_inctl_init(void)

{

       PRINTK("come in init\n");

       MAJOR_NR = register_chrdev(MAJOR_NR, DRIVER_NAME, &ioctl_file_opt);

       if(MAJOR_NR < 0)

       {

             PRINTK("register char device fail!\n");

             return MAJOR_NR;

       }

       myclass=class_create(THIS_MODULE,"my_ioctl");

       device_create(myclass,NULL, MKDEV(MAJOR_NR, MINOR_NR), NULL,"my_ioctl");

       return 0;

}

static void __exit my_inctl_exit(void)

{

       if(MAJOR_NR > 0)

       {

             unregister_chrdev(MAJOR_NR, DRIVER_NAME);

             device_destroy(myclass,MKDEV(MAJOR_NR, MINOR_NR));

             class_destroy(myclass);

       }

       PRINTK("exit ioctl\n");

       return;

}

module_init(my_inctl_init);

module_exit(my_inctl_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("HB");

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

配置s3c2410的文件

cp arch/arm/configs/s3c2410_defconfig .config

make menuconfig(执行s3c2410配置)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/389202.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

leetcode刷题记录:暴力搜索算法01 - 回溯

参考&#xff1a;labuladong的算法小抄 https://labuladong.online/algo/essential-technique/backtrack-framework/ 这篇太牛了&#xff0c;一个模板把所有的排列组合子集问题全秒了。 1. 简介 暴力搜索算法&#xff1a;回溯、dfs、bfs。这些都可以看做是从二叉树算法衍生出来…

个人 AI 的革命:Nvidia‘s Chat with RTX 深度探索

个人 AI 的革命&#xff1a;Nvidias Chat with RTX 深度探索 Nvidia 推出的 Chat with RTX 预示着个人 AI 新时代的到来。2 月 13 日&#xff0c;Nvidia 官宣了自家的 AI 聊天机器人&#xff0c;这不仅是人工智能交互的渐进式改进&#xff1b;更代表了个人如何利用自己的数据进…

Dirty PageTable

前言 Dirty PageTable 是一种针对堆相关漏洞的利用手法&#xff0c;主要就是针对 PTE 进行攻击。 参考文章&#xff1a; Dirty Pagetable: A Novel Exploitation Technique To Rule Linux Kernel – 该利用方式提出原文 上述文章已经讲的非常清楚了&#xff0c;就是实操写 e…

25天物理探索旅程 - 第四天:光的奇妙旅程揭秘

第四天&#xff0c;我们的科普探险队将踏上一段非凡的旅程&#xff0c;目标是揭开光——这位宇宙间最具魔法特质的信使的秘密面纱。今天&#xff0c;我们将以一种轻松愉快、幽默风趣的方式探讨光的本质&#xff0c;像看一场生动有趣的魔术表演般&#xff0c;领略光那波粒二象性…

Java基础常见面试题总结-并发(一)

线程池 线程池&#xff1a;一个管理线程的池子。 为什么平时都是使用线程池创建线程&#xff0c;直接new一个线程不好吗&#xff1f; 嗯&#xff0c;手动创建线程有两个缺点 不受控风险频繁创建开销大 为什么不受控&#xff1f; 系统资源有限&#xff0c;每个人针对不同业…

垃圾分类|城市垃圾分类管理系统|基于Springboot的城市垃圾分类管理系统设计与实现(源码+数据库+文档)

城市垃圾分类管理系统目录 目录 基于Springboot的城市垃圾分类管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、垃圾列表 2、公告信息管理 3、公告类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 …

thinkphp+vue企业产品展示网站f7enu

本文首先介绍了企业产品展示网站管理技术的发展背景与发展现状&#xff0c;然后遵循软件常规开发流程&#xff0c;首先针对系统选取适用的语言和开发平台&#xff0c;根据需求分析制定模块并设计数据库结构&#xff0c;再根据系统总体功能模块的设计绘制系统的功能模块图&#…

qml之Control类型布局讲解,padding属性和Inset属性细讲

1、Control布局图 2、如何理解&#xff1f; *padding和*Inset参数如何理解呢&#xff1f; //main.qml import QtQuick 2.0 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import QtQuick.Controls 1.4 import QtQml 2.12ApplicationWindow {id: windowvisible: …

CentOS7.9+Kubernetes1.29.2+Docker25.0.3高可用集群二进制部署

CentOS7.9Kubernetes1.29.2Docker25.0.3高可用集群二进制部署 Kubernetes高可用集群&#xff08;Kubernetes1.29.2Docker25.0.3&#xff09;二进制部署二进制软件部署flannel v0.22.3网络&#xff0c;使用的etcd是版本3&#xff0c;与之前使用版本2不同。查看官方文档进行了解…

无人机导航技术,无人机导航理论基础,无人机导航技术应用发展详解

惯性/卫星定位组合是一种比较理想的组合导航系统。在无人机导航领域&#xff0c;多年来惯性/卫星定位组合导航系统的研究一直受到普遍的关注&#xff0c;大量的理论研究成果得到实际应用。 常见的几类导航系统 单一导航 卫星导航系统 、多普勒导航、惯性导航系统(INS) 、图形…

苹果展示 AI 新模型 MGIE,可一句话精修图片

苹果公司近日发布了名为“MGIE”的新型开源人工智能模型&#xff0c;它可以根据自然语言指令编辑图像。 2 月 8 日消息&#xff0c;相比较微软的风生水起&#xff0c;苹果公司在 AI 领域的布局显得低调很多&#xff0c;但这并不意味着苹果在该领域就没有丝毫建树。苹果公司近日…

Unresolved reference: kotlinx 和 Unresolved reference:xxx

Unresolved reference: kotlinx 这个报错是因为build.gradle中忘记apply plugin了 apply plugin: kotlin-android-extensions如下 同步以后再次编译发现报错 Unresolved reference:xxx 是因为用于使用 Gradle 构建的 Kotlin 版本与 IDE 插件中的版本不一样的原因 解决方法 …

Lag-Llama:第一个时间序列预测的开源基础模型介绍和性能测试

2023年10月&#xff0c;我们发表了一篇关于TimeGPT的文章&#xff0c;TimeGPT是时间序列预测的第一个基础模型之一&#xff0c;具有零样本推理、异常检测和共形预测能力。 虽然TimeGPT是一个专有模型&#xff0c;只能通过API访问。但是它还是引发了对时间序列基础模型的更多研…

算法刷题:有效三角形个数

有效三角形个数 .题目链接题目详情算法原理补充知识点双指针:对撞指针 我的答案 . 题目链接 有效三角形个数 题目详情 算法原理 补充知识点 有效三角形需要满足的条件: ab>cac>bbc>a 其实在满足1的时候,c是最大的,那么2和3是显然成立的,因此我们可以这样解题: 对…

C# winfrom中NPOI操作EXCEL

前言 1.整个Excel表格叫做工作表&#xff1a;WorkBook&#xff08;工作薄&#xff09;&#xff0c;包含的叫页&#xff08;工作表&#xff09;&#xff1a;Sheet&#xff1b;行&#xff1a;Row&#xff1b;单元格Cell。 2.忘了告诉大家npoi是做什么的了&#xff0c;npoi 能够读…

react 【七】各种hooks的使用/SPA的缺点

文章目录 1、Hook1.1 为什么会出现hook1.2 useState1.3 useEffect1.4 useContext1.5 useReducer1.6 useCallback1.7 useMemo1.8 useRef1.8.1 ref绑定dom1.8.2 ref解决闭包缺陷 1.9 useImperativeHandle1.10 useLayoutEffect1.11 自定义Hook1.11.1 什么是自定义Hook1.11.2 Conte…

Python 字符串格式化输出

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站零基础入门的AI学习网站~。 前言 字符串格式化是编程中一个常见的需求&#xff0c;它可以们将不同类型的数据&#xff08;如数字、文本、日…

Django问题报错:TypeError: as_view() takes 1 positional argument but 2 were given

一、错误位置 from django.urls import pathfrom users_app.views import RegisterView, LoginView, LogoutViewapp_name users urlpatterns [path("register/", RegisterView.as_view, name"register"),path("login/", LoginView.as_view, n…

基于四叉树的图像分割算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ........................................................... Imgs(dx 1 : dx R1, dy 1 …

阿里云幻兽帕鲁Linux 服务器下载游戏存档的方法

阿里云幻兽帕鲁Linux 服务器下载游戏存档的方法也非常简单。 远程连接到阿里云的 linux服务器后&#xff0c;可以在 ECS 远程连接命令行界面&#xff0c;点击左上角的文件&#xff0c;打开文件树。通过一行命令打包。 在打包后的 Saved.tar 文件上右键&#xff0c;选择 下载文…