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

发布于:2025-07-02 ⋅ 阅读:(31) ⋅ 点赞:(0)

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 +4
	printk("打开\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");

网站公告

今日签到

点亮在社区的每一天
去签到