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

LINUX2.6设备注册与GPIO相关的API

LINUX2.6设备注册与GPIO相关的API

linux2.6 设备注册和杂项设备注册的区别

杂项设备的特点

这种设备注册方法相对来说比较简单

杂项设备的主设备号固定为 10

次设备号 0-255

杂项设备注册成功之后会在/dev 目录下生成设备文件

linux2.6 设备注册的特点

linux2.6 设备注册相对比较复杂

这种设备注册方法比较流行

设备注册完成之后不会生成设备文件

主设备号和次设备号都是没有限制的

主设备号范围

0-2^12

次设备号

0-2^20

linux2.6 设备注册设备号存在的问题

由于主设备号和次设备号都是没有限制的

如果直接的指定主设备号和次设备号会造成

设备号冲突的问题

为了解决设备号存在的问题,在使用设备号的时候

一般不直接指定 而是借助于内核提供的函数来来向内核申请

linux2.6 的设备号的申请

函数的功能

向内核申请一个设备号

函数的头文件

linux/fs.h

函数的原型

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

函数的参数

dev_t *dev, 用来存放申请到的设备号的缓冲区

unsigned baseminor, 次设备号起始的位置

unsigned count, 要申请的设备号的个数

const char *name 设备号的名字 /proc/devices 文件里

函数的返回值

成功返回 0

失败返回 -1

linux2.6 设备注册相关的 API

cdev_init函数的功能

初始化一个 linux2.6 的核心结构体

函数的头文件

linux/cdev.h

函数的原型

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

函数的参数

struct cdev *cdev, linux2.6 的核心结构体

const struct file_operations *fops 操作集合结构体

函数的返回值

cdev_add函数的功能

向内核注册一个 linux2.6 的核心结构体

函数的头文件

linux/cdev.h

函数的原型

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

函数的参数

struct cdev *p, linux2.6 的核心结构体指针

dev_t dev, 设备号

unsigned count 要注册的 linux2.6 的设备的个数 1

函数的返回值

成功返回 0

失败返回 -1

cdev_del函数的功能

取消 linux2.6 的设备的注册

函数的头文件

linux/cdev.h

函数的原型

void cdev_del(struct cdev *p)

函数的参数

struct cdev *p:linux2.6 的核心结构体

函数的返回值

自动生成设备文件

通过验证可知 linux2.6 设备注册成功以后不会自动的生成设备文件,不能生成设备文件就会导致别的程序无法使用这个驱动,为了解决这个问题,就需要搞定驱动对应的设备文件,生成设备文件的方法主要有两种

手动生成

需要在终端执行命令

在执行命令之前需要了解主设备号和次设备号

执行如下指令

mknod /dev/myled c 234 0

借助于内核提供的 api 来实现自动的生成设备文件

在自动生成设备文件的时候需要使用一个类结构体,这个类结构体申请需要借助于内核提供的函数

class_create函数的功能

创建一个类结构体

函数的头文件

linux/device.h

函数的原型

struct class * class_create(struct module *owner, const char *name)

函数的参数

struct module *owner, 模块

const char *name 类结构体的名字

函数的返回值

成功返回 类结构体的指针

失败返回 NULL

ps:

类结构体是可以复用的

class_destroy函数的功能

销毁类结构体

函数的头文件

linux/device.h

函数的原型

void class_destroy(struct class *cls)

函数的参数

struct class *cls:类结构体的指针

函数的返回值

device_create函数的功能

自动生成设备文件

函数的头文件

linux/device.h

函数的原型

struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)

函数的参数

struct class *class, 类结构体指针

struct device *parent, 父节点的信息 NULL

dev_t devt, 设备号

void *drvdata, 私有数据 NULL

const char *fmt, … 设备名 会出现在/dev 目录下

函数的返回值

成功返回 设备的结构体指针

失败返回 NULL

device_destroy函数的功能

销毁设备文件

函数的头文件

linux/device.h

函数的原型

void device_destroy(struct class *class, dev_t devt)

函数的参数

struct class *class, 类结构体指针

dev_t devt 设备号

函数的返回值

linux2.6 设备注册的总结

注册的流程

申请设备号

初始化 linux2.6 的核心结构体

向内核注册一个 linux2.6 的核心结构体

创建类结构体

使用类结构体创建设备文件

取消注册的流程

销毁设备

销毁类结构体

取消 linux2.6 的设备注册

实例

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>dev_t mydev;
struct cdev mycdev;
struct file_operations myfops;
struct class * myclass=NULL;
struct device * mydevice=NULL;int myopen (struct inode *inode, struct file * file)
{printk("打开\n");return 0;
}
int myclose (struct inode *inode, struct file * file)
{printk("关闭\n");return 0;
}static int __init myled_init(void)
{//1申请设备号alloc_chrdev_region(&mydev, 0, 1, "myled");printk("设备号:%d\n",mydev);printk("主设备号:%d\n",(mydev >> 20));printk("次设备号:%d\n",(mydev)&0xFFFFF);//2初始化linux2.6核心结构体myfops.owner = THIS_MODULE;myfops.open = myopen;myfops.release = myclose;cdev_init(&mycdev, &myfops);//3向内核注册linux2.6核心结构体cdev_add(&mycdev, mydev, 1);//创建类结构体myclass=class_create(THIS_MODULE,"myled");//创建设备mydevice=device_create(myclass, NULL,mydev,NULL, "myled");return 0;
}static void __exit myled_exit(void)
{//销毁设备文件device_destroy(myclass, mydev);//取消类结构体class_destroy(myclass);//取消Linux2.6的注册cdev_del(&mycdev);
}module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");

应用层

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int fd;
int main()
{while(1){fd=open("/dev/myled",O_RDWR);sleep(1);close(fd);sleep(1);}return 0;
}

gpio 子系统相关的 API

gpio函数

gpio_request函数的功能

申请一个 GPIO 口

函数的头文件

linux/gpio.h

函数的原型

int gpio_request(unsigned gpio, const char *label);

函数的参数

unsigned gpio, gpio 口引脚的编号

const char *label 标签

函数的返回值

成功返回 0

失败返回 -1

gpio_direction_output函数的功能

设置 gpio 口的工作模式为输出

函数的头文件

linux/gpio.h

函数的原型

int gpio_direction_output(unsigned gpio, int value)

函数的参数

unsigned gpio, gpio 口引脚的编号

int value 默认的输出的值 一般是有效电平取反

函数的返回值

成功返回 0

失败返回 -1

gpio_direction_input函数的功能

设置 gpio 口引脚的工作模式为输入

函数的头文件

linux/gpio.h

函数的原型

int gpio_direction_input(unsigned gpio)

函数的参数

unsigned gpio:gpio 口引脚的编号

函数的返回值

成功返回 0

失败返回 -1

gpio_set_value函数的功能

设置 gpio 口引脚的值

函数的头文件

linux/gpio.h

函数的原型

void gpio_set_value(unsigned gpio, int value)

函数的参数

unsigned gpio, gpio 口引脚的编号

int value 要设置的值

函数的返回值

gpio_get_value函数的功能

获取 gpio 口引脚的值

函数的头文件

linux/gpio.h

函数的原型

int gpio_get_value(unsigned gpio)

函数的参数

unsigned gpio:gpio 引脚的编号

函数的返回值

成功返回 引脚值

实例

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/gpio.h>dev_t mydev;
struct cdev mycdev;
struct file_operations myfops;
struct class * myclass=NULL;
struct device * mydevice=NULL;int myopen (struct inode *inode, struct file * file)
{
//GPIO1_A4 1*32+A-A +4printk("打开\n");gpio_set_value(21, 1);gpio_set_value(22, 1);gpio_set_value(36, 1);return 0;
}
int myclose (struct inode *inode, struct file * file)
{printk("关闭\n");gpio_set_value(21, 0);gpio_set_value(22, 0);gpio_set_value(36, 0);return 0;
}static int __init myled_init(void)
{gpio_request(21, "led21");gpio_request(22, "led22");gpio_request(36, "beep");gpio_direction_output(21, 0);gpio_direction_output(22, 0);gpio_direction_output(36, 0);//1申请设备号alloc_chrdev_region(&mydev, 0, 1, "myled");printk("设备号:%d\n",mydev);printk("主设备号:%d\n",(mydev >> 20));printk("次设备号:%d\n",(mydev)&0xFFFFF);//2初始化linux2.6核心结构体myfops.owner = THIS_MODULE;myfops.open = myopen;myfops.release = myclose;cdev_init(&mycdev, &myfops);//3向内核注册linux2.6核心结构体cdev_add(&mycdev, mydev, 1);//创建类结构体myclass=class_create(THIS_MODULE,"myled");//创建设备mydevice=device_create(myclass, NULL,mydev,NULL, "myled");return 0;
}static void __exit myled_exit(void)
{//销毁设备文件device_destroy(myclass, mydev);//取消类结构体class_destroy(myclass);//取消Linux2.6的注册cdev_del(&mycdev);
}module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
http://www.xdnf.cn/news/1076203.html

相关文章:

  • Vue3 中 Excel 导出的性能优化与实战指南
  • JavaScript 安装使用教程
  • ip网络基础
  • FastGPT与MCP:解锁AI新时代的技术密码
  • 百度轮岗:任命新CFO,崔珊珊退居业务二线
  • 使用Electron开发跨平台RSS阅读器:从零到一的完整指南
  • Linux查看空间大小相关命令内容
  • 数据结构复习4
  • 前端计算机视觉:使用 OpenCV.js 在浏览器中实现图像处理
  • Oracle 常用函数
  • 38.docker启动python解释器,pycharm通过SSH服务直连
  • 【软考高项论文】论信息系统项目的进度管理
  • Zookeeper安装使用教程
  • SQL规范
  • IDEA相关配置记录
  • 【中文核心期刊推荐】《计算机应用与软件》
  • Windows CMD命令分类大全
  • 前端开发面试题总结-原生小程序部分
  • 衡石科技使用手册-企业即时通讯工具数据问答机器人用户手册
  • STM32要学到什么程度才算合格?
  • 华为云Flexus+DeepSeek征文|基于 Dify-LLM 构建网站智能客服助手的实践探索
  • Go语言安装使用教程
  • C++ 快速回顾(五)
  • Python 数据分析与机器学习入门 (二):NumPy 核心教程,玩转多维数组
  • 湖北理元理律师事务所债务解法:从法律技术到生活重建
  • 长短期记忆网络(LSTM):让神经网络拥有 “持久记忆力” 的神奇魔法
  • 安装bcolz包报错Cython.Compiler.Errors.CompileError: bcolz/carray_ext.pyx的解决方法
  • JavaScript异步编程的五种方式
  • 反射,枚举和lambda表达式
  • 七天学会SpringCloud分布式微服务——06——Sentinel