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

Linux驱动12 --- Linux2.6 开发方法文件接口

目录

一、Linux2.6 字符设备开发

1.1 介绍

1.2 特点

1.3 相关 API

Linux2.6 的开发过程

添加头文件

申请设备号

释放设备号

Linux2.6 核心结构体初始化

Linux2.6 核心结构体添加

Linux2.6 核心结构体删除

1.4 通过指令生成设备文件

1.5 自动生成设备文件     

设备创建

类的创建

设备的销毁

类的销毁

二、文件接口

2.1 read 文件接口

read 的实现函数

2.2 write文件接口

write 的实现函数

2.3 ioctl

应用接口

内核接口

三、GPIO 子系统

设置 GPIO 为输入方向

获取 GPIO 当前的电平状态


一、Linux2.6 字符设备开发

1.1 介绍

        驱动开发方式之一

1.2 特点

        1、真正意义上的 32 位设备号

        2、设备号需要开发者申请/释放

        3、无法自动生成设备文件

        4、相对比较复杂

1.3 相关 API

        关键字:cdev

        头文件:#include <linux/cdev.h>

                      #include <linux/fs.h>

Linux2.6 的开发过程

添加头文件
申请设备号

        函数原型       

                int alloc_chrdev_region(dev_t *dev, unsigned int baseminor, unsigned int count, const char *name)

        函数参数

                dev:设备号存放的地址,是连续开辟的

                baseminor:申请的次设备号起始值

                                    次设备号是我们指定的,主设备号是系统分配的

                count:连续申请次设备号的个数

                       例如:第二个参数填 54,第三个参数填 2

                        那么会得到两个设备号,其中第一个次设备为 54,第二个次设备号为 55

                name:无所谓,尽可能有意义 ,申请设备号操作,这个 name 不要重复

        函数返回值

                成功返回 0,失败返回负数

释放设备号

        函数原型      

                void unregister_chrdev_region(dev_t dev, unsigned int count)

        函数参数

                dev:要释放设备号的起始值

                count:释放的个数

Linux2.6 核心结构体初始化

        函数原型

                void cdev_init(struct cdev *cdev, const struct file_operations *ops)

        函数参数

                cdev:Linux2.6 核心结构体

struct cdev
{const struct file_operations *ops; //文件接口核心结构体dev_t dev;                        //起始设备号unsigned int count;               //设备号连续的数量struct module *owner;             //固定填写} 

                加粗的部分都是通过函数去填写的,我们只需要给 owner 赋值

Linux2.6 核心结构体添加

        函数原型

                int cdev_add(struct cdev *cdev, dev_t dev, unsigned int count)

        函数参数

                cdev:Linux2.6 核心结构体

                dev:起始设备号

                count:设备号的个数

        函数返回值

                成功返回 0,失败返回负数

Linux2.6 核心结构体删除

        函数原型

                void cdev_del(struct cdev *cdev)

        函数参数

                cdev:Linux2.6 核心结构体

1.4 通过指令生成设备文件

1.5 自动生成设备文件     

设备创建

        头文件:#include <linux/device.h>

        函数原型

                struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void

*drvdata, const char *fmt, ...)

        函数参数

                cls:是一个类 --- 这个类只需要调用函数生成即可

                parent:设备的上一级,但是我们的设备是你我创建,没有填 NULL

                devt:设备使用的设备号

                drvdata:传递给内核的参数,不使用填 NULL

                fmt:可以填格式控制符,也可以直接填一个字符串作为文件的名字

        函数返回值

                无所谓,不用

类的创建

        函数原型               

                class_create(owner, name)

        函数参数

                struct module *owner:固定填写

                const char *name:无所谓,尽量有意义,不要重复

        函数返回值

                类的核心结构体,struct class

设备的销毁

        函数原型

                void device_destroy(struct class *cls, dev_t devt)

        函数参数

                cls:类

                devt:设备号

类的销毁

        函数原型       

                void class_destroy(struct class *cls)

        函数参数

                cls:类

二、文件接口

        对于系统层来说:read 函数可以获取一个数据,数据由内核产生,所以对于内核来说本质上是输出了一个数据

        对于系统层来说:wirt 函数可以写入一个数据,数据由内核接收,所以对于内核来说本质上是获取了一个数据

2.1 read 文件接口

        函数原型

                ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

        函数参数

                struct file:用于多节点判断

                char __user *:应用层 read 函数存放数据空间的首地址

                size_t:获取内容的长度

                loff_t *:用在块设备,指代偏移量

read 的实现函数

        头文件:#include <linux/uaccess.h>

        函数原型

                static inline int copy_to_user(void __user volatile *to, const void *from, unsigned long n)

        函数参数

                to:数据到哪里去 --- 直接填写(*read)的第二个参数

                from:数据从哪里来 --- 内核定义一个变量,然后取地址即可

                n:数据的长度 --- 直接填写(*read)的第三个参数

        函数返回值

                必须承接,否则会报警告,而警告会被当成错误

2.2 write文件接口

        函数原型

                ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

        函数参数

                struct file:用于多节点判断

                const char __user *:应用层 write 函数存放数据空间的首地址

                size_t:获取内容的长度

                loff_t *:用在块设备,指代偏移量

         write 往内核中写数据,内核需要做接收

write 的实现函数

        函数原型

                static inline int copy_from_user(void *to, const void __user volatile *from, unsigned long n)

        函数参数

                to:数据到哪里去 --- 数据要到内核

                        内核就需要定义一个变量去承接 wirte 写入的数据

                from:数据从哪里来 --- (*write)第二个参数

                n:传入数据的长度

        函数返回值

                必须承接,否则会报错

2.3 ioctl

应用接口

        头文件

                #include <sys/ioctl.h>

        函数原型

                int ioctl(int fd, unsigned long request, ...)

        函数参数

                fd:文件描述符

                request:就是传递给内核的命令

                …:表示可变参数

                        可变参数具体是什么由第二个参数命令决定

        函数返回值

                成功返回 0,失败返回负数

内核接口

        函数原型

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

        函数参数

                struct file:用于多节点判断

                cmd:命令 --- 本质上是一个数字,但是数据传递无法直接传递数字

                          所以这个命令其实就是一个宏定义        

                          命令中,2 值已经被系统保留(我们没法用)

                n:数据长度

                ioctl 的应用主要在:标准文件接口

                        例如:

                                在 V4L2 摄像头开发中用于获取摄像头参数,以及设置摄像头参数,在屏幕开发中用于获取屏幕的参数

三、GPIO 子系统

设置 GPIO 为输入方向

        函数原型

                int gpio_direction_input(unsigned gpio)

        函数参数

                gpio:要设置的 GPIO 号

        函数返回值

                成功返回 0,失败返回负数

获取 GPIO 当前的电平状态

        函数原型

                int gpio_get_value(unsigned gpio)

        函数参数

                gpio:要获取电平状态的 GPIO 号

        函数返回值

                高电平,就返回 1,低电平返回 0     

http://www.lryc.cn/news/590612.html

相关文章:

  • C语言 --- 函数递归
  • Docker化Web服务部署全景指南:从基础服务器到企业级应用
  • 暑期算法训练.2
  • 【代码】基于CUDA优化的RANSAC实时激光雷达点云地面分割
  • 前端vue3获取word二进制流在页面展示
  • FAISS深度学习指南:构建高效向量检索系统的完整方法论
  • Node.js Process Events 深入全面讲解
  • 网络安全初级(Python实现sql自动化布尔盲注)
  • flink sql如何对hive string类型的时间戳进行排序
  • 设计模式三:观察者模式 (Observer Pattern)
  • ubuntu--自启动程序
  • 7.isaac sim4.2 教程-Core API-数据记录
  • 【cobalt strike手册0x06】Sleep Mask
  • JAVA进阶 项目实战:汽车租聘系统
  • 关于squareLineStudio软件使用步骤教程(LVGL软件组件编程)
  • Linux应急Rootkit后门查杀病毒查杀软件
  • 0系统与软件工程-标准体系
  • 1软件工程概念及其基本要素-思考题
  • 基于paddleDetect的半监督目标检测实战
  • 【论文阅读】A Survey on Knowledge-Oriented Retrieval-Augmented Generation(4)
  • 基于C#开发solidworks图库中文件(SLDPRT,SLDASM,SLDDRW等)转换为HTML和PDF,提供批量和实时转换
  • 【论文阅读 | IF 2025 | COMO:用于多模态目标检测的跨 Mamba 交互与偏移引导融合】
  • 【论文阅读 | CVPR 2023 |CDDFuse:基于相关性驱动的双分支特征分解的多模态图像融合】
  • Python+Tkinter制作音频格式转换器
  • 使用token调用Spring OAuth2 Resource Server接口错误 insufficient_scope
  • Scrapy无缝集成Splash:轻量级动态渲染爬虫终极解决方案
  • Oracle 数据库常见等待事件参数详解
  • 16路串口光纤通信FPGA项目实现指南 - 第二部分(上)
  • FPGA基础 -- Verilog 访问寄存器数组的指定位示例
  • 从函数调用到进程通信:Linux下的多语言协作实践