当前位置: 首页 > news >正文

设备程序驱动框架

一、创建设备驱动文件

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>#define MAJOR_NUM 255    //主设备号
#define MIJOR_NUM 0      //次设备号
#define DEV_NAME "demo1"    //模块名(在注册时使用,主要用于内部维护)//open、read、write、close的具体操作方法
static int open(struct inode * node, struct file * file)
{printk("demo open...\n");return 0;
}static ssize_t read(struct file * file, char __user * buf, size_t len, loff_t * offset)
{printk("demo read...\n");return 0;
}static ssize_t write(struct file * file, const char __user * buf, size_t len, loff_t * offset)
{printk("demo write...\n");return 0;
}static int close(struct inode * node, struct file * file)
{printk("demo close...\n");return 0;
}static dev_t dev_num;    //设备号
static struct file_operations fops = 
{.owner = THIS_MODULE, //用来维护自己模块的结构体,THIS_MODULE这个宏就代表自己本身这个模块.open = open,.read = read,.write = write,.release = close
};//对设备的操作方法//这个结构用来绑定这个设备号和对这个设备的操作方法
static struct cdev dev;static int __init demo_init(void)
{//register dev(注册设备)dev_num = MKDEV(MAJOR_NUM,MIJOR_NUM);//(MAJOR_NUM << 20) | MINOR_NUM//MKDEV是一个宏//初始化cdev这个结构体cdev_init(&dev,&fops);cdev_add(&dev,dev_num,1);register_chrdev_region(dev_num,1,DEV_NAME);//将整个模块注册到操作系统中    printk("demo_init ##################\n");return 0;
}static void __exit demo_exit(void)
{unregister_chrdev_region(dev_num,1);cdev_del(&dev);printk("demo_exit ##################\n");
}module_init(demo_init);
module_exit(demo_exit);
//module_init和module_exit是内核留给用户的接口本质是宏,用来修饰括号里的函数,module_init在注册时使用module_exit在注销时使用
module_init:在开机时(或者说是操作系统启动时)内核会遍历整个程序找到被module_init修饰的函数并执行一次
module_exit:在关机时(或者说是操作系统关机时)内核会遍历整个程序找到被module_exit修饰的函数并执行一次利用Ctags可以快速查询(跳转)到相应的头文件或者函数(自行详细了解Ctags的使用规则)

将这个代码编译并加载进内核

在开发板上电操作系统加载完之后,我们会发现在/dev下并没有demo1这个设备

这个时候我们就需要手动创建设备节点

mknod /dev/demo1 c 255 0

利用这个命令我们就能创建相对应的字符设备 ,这里的/dev/demo1就是设备节点名,c代表的就是字符设备文件,255和0是它的主设备号和次设备号

二、应用程序

想要验证内核代码能够正确运行,我们就可以在应用层编写测试代码来进行测试,在开发板挂载的目录下进行编写

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>int main(int argc, const char *argv[])
{int fd = open("/dev/demo1", O_RDWR);perror("open demo1");if (fd < 0) {perror("open demo1");return 1;}unsigned char buf[48] = {0};read(fd, buf, sizeof(buf));write(fd, buf, sizeof(buf));close(fd);return 0;
}

这个代码因为我们要在开发板上运行,所以我们要使用arm-linux-gcc这个编译器来进行交叉编译 

编译好后运行程序,如果能打印出printk中的内容即为成功


http://www.mrgr.cn/news/36055.html

相关文章:

  • AI 大模型应用:AI开发的捷径工作流模式
  • AGI自学分享,简单有用的理论与实践
  • Mac的极速文件搜索工具,高效管理文件
  • openresty入门教程:rewrite_by_lua_block
  • 力扣 LeetCode 206. 反转链表(Day2:链表)
  • 软件设计师-操作系统
  • 【Linux】解锁文件描述符奥秘,高效缓存区的实战技巧
  • MySQL: 数据类型介绍
  • 只要孩子感兴趣,学什么都不会白学
  • 如何根据拍立淘API返回值进行商品数据分析
  • USB-CAN的使用说明
  • QT开发模式(二):QML/JS/C++混合编程
  • 初识C#(二)- 流程控制
  • 微积分复习笔记(1):单变量微积分
  • 提取出来的ip与我原本的ip是在同一个区吗
  • Icarus翼星求生教你使用服务器开服
  • 鸿萌数据恢复:如何降低 RAM 故障风险,以避免数据丢失?
  • WebGL与Web Workers
  • 用于扩展 微软Azure OpenAI 服务工作负载的全球预置托管部署
  • USB Micro-A、Micro-B 插头与 Micro-AB、Micro-B 插座,及其引脚定义
  • 一文理解AXI4-lite与AXI4-stream协议
  • GEE APP:基于gee开发一个在线监测Landsat5、7、8的云量面积和百分比的可视化应用
  • 戏曲多多 1.0.6.0 专为电视端设计的戏曲与生活内容APP,同样适用于安卓手机,方便老年人使用
  • 如何在算家云搭建text-generation-webui(文本生成)
  • Python 中的时间处理
  • hexo github部署,通过域名访问你的博客