赞
踩
以下是加了注释的Linux驱动程序代码,用于控制AXI GPIO外设:
```c
```c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
//GPIO的管脚号,此处为对应LED的管脚号
#define GPIO_LED 54
//设备驱动程序的名称
#define DEVICE_NAME “axi-gpio-driver”
//保存设备文件的主设备号
static int Major;
//定义设备文件的读函数
static ssize_t read_gpio(struct file *f, char __user *buf, size_t count, loff_t *offset)
{
//定义缓冲区
char val[2];
//读取GPIO的电平值
gpio_get_value(GPIO_LED, &val);
//将获得的电平值写入缓冲区
val[1] = '\n';
if (val[0] == 0)
val[0] = '0';
else
val[0] = '1';
//将缓冲区的数据拷贝到用户空间的缓冲区
copy_to_user(buf, val, 2);
//返回缓冲区的大小(此处为2)
return 2;
}
//定义设备文件的写函数
static ssize_t write_gpio(struct file *f, const char __user *buf, size_t count, loff_t *offset)
{
//定义缓冲区
char val[2];
//将用户空间的缓冲区拷贝到设备驱动程序的缓冲区
copy_from_user(val, buf, count);
//设置GPIO的电平值
if (val[0] == '0')
gpio_set_value(GPIO_LED,0);
else if (val[0] == '1')
gpio_set_value(GPIO_LED,1);
//返回缓冲区的大小(此处为count)
return count;
}
//定义设备文件的操作函数结构体
static struct file_operations gpio_fops =
{
.owner = THIS_MODULE,
.read = read_gpio,
.write = write_gpio,
};
//设备驱动程序的初始化函数
static int __init gpio_init(void)
{
//申请GPIO资源
if (gpio_request(GPIO_LED, “LED”) < 0)
{
printk(KERN_ALERT “gpio_request failure\n”);
return -1;
}
//设置GPIO为输出模式,初始值为0(关灯) if (gpio_direction_output(GPIO_LED, 0) < 0) { printk(KERN_ALERT "gpio_direction_output failure\n"); return -1; } //注册设备文件 Major = register_chrdev(0, DEVICE_NAME, &gpio_fops); if (Major < 0) { printk(KERN_ALERT "register_chrdev failure\n"); return Major; } printk(KERN_ALERT "axi-gpio-driver module is loaded\n"); return 0;
}
//设备驱动程序的卸载函数
static void __exit gpio_exit(void)
{
//释放GPIO资源
gpio_free(GPIO_LED);
//注销设备文件
unregister_chrdev(Major, DEVICE_NAME);
printk(KERN_ALERT "axi-gpio-driver module is unloaded\n");
}
//模块的初始化函数和卸载函数
module_init(gpio_init);
module_exit(gpio_exit);
//模块的说明信息
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“Your Name”);
MODULE_DESCRIPTION(“A simple GPIO device driver for AXI GPIO on Zynq”);
注释详解如下:
- 申请头文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
这里引入了一些Linux内核的头文件,它们的作用如下:
- <linux/init.h>:包含模块的初始化和清理函数宏定义。
- <linux/module.h>:包含模块定义和其他必要的宏、类和函数的声明和定义。
- <linux/kernel.h>:包含各种内核需要的常量和函数的声明。
- <linux/fs.h>:包含了文件系统相关的宏、类型定义等标准头文件。
- <linux/gpio.h>:包含了GPIO的宏定义和相关函数的声明。
- <asm/uaccess.h>:包含了访问用户空间缓冲区的函数等
- 定义GPIO管脚号
#define GPIO_LED 54
这里定义了一个宏变量GPIO_LED保存LED的管脚号54,方便后面使用。
- 定义设备的名称
#define DEVICE_NAME “axi-gpio-driver”
这里定义了一个字符串变量DEVICE_NAME保存设备的名称,用于生成设备文件。
- 保存主设备号
static int Major;
这里定义了一个静态变量Major,保存主设备号。
- 定义设备文件的读函数
static ssize_t read_gpio(struct file *f, char __user *buf, size_t count, loff_t *offset)
这里定义了read_gpio函数,用于从设备文件中读取GPIO的电平值。它有4个参数,分别是:
- struct file *f:文件操作对象
- char __user *buf:指向用户空间缓冲区的指针
- size_t count:缓冲区的大小
- loff_t *offset:文件读取的偏移量
- 定义设备文件的写函数
static ssize_t write_gpio(struct file *f, const char __user *buf, size_t count, loff_t *offset)
这里定义了write_gpio函数,用于向设备文件中写入GPIO的电平值。它有4个参数,分别是:
- struct file *f:文件操作对象
- const char __user *buf:指向用户空间缓冲区的指针
- size_t count:缓冲区的大小
- loff_t *offset:文件写入的偏移量
- 定义设备文件的操作函数结构体
static struct file_operations gpio_fops =
{
.owner = THIS_MODULE,
.read = read_gpio,
.write = write_gpio,
};
定义了一个静态变量gpio_fops,它是一个struct file_operations类型的结构体,定义了文件操作对象的设备函数表,它包含3个设备函数:读、写和设备打开时的操作。
- 定义设备驱动程序的初始化函数
static int __init gpio_init(void)
该函数用于初始化设备驱动程序(安装设备驱动程序),它没有参数。
- 申请GPIO资源
if (gpio_request(GPIO_LED, “LED”) < 0)
{
printk(KERN_ALERT “gpio_request failure\n”);
return -1;
}
该函数使用gpio_request()函数请求GPIO资源,如果请求失败,打印一个错误信息,并返回-1。
- 设置GPIO为输出模式,初始值为0(关灯)
if (gpio_direction_output(GPIO_LED, 0) < 0)
{
printk(KERN_ALERT “gpio_direction_output failure\n”);
return -1;
}
这里通过gpio_direction_output()函数设置GPIO为输出模式,初始值为0(关灯)。如果设置失败,打印一个错误信息,并返回-1。
- 注册设备文件
Major = register_chrdev(0, DEVICE_NAME, &gpio_fops);
if (Major < 0)
{
printk(KERN_ALERT “register_chrdev failure\n”);
return Major;
}
该函数调用register_chrdev()函数注册字符设备,成功后返回设备文件的主设备号(Major),同时保存文件操作对象的设备函数表,如果注册失败则返回错误号,打印一个错误信息,并结束函数执行。
- 设备驱动程序的卸载函数
static void __exit gpio_exit(void)
该函数用于卸载设备驱动程序(卸载设备驱动程序),它没有参数。
- 释放GPIO资源
gpio_free(GPIO_LED);
该函数使用gpio_free()函数释放GPIO资源,将GPIO管脚号设置为对应的管脚,释放占用的资源。
- 注销设备文件
unregister_chrdev(Major, DEVICE_NAME);
该函数使用unregister_chrdev()函数注销字符设备,同时释放占用的资源。
- 设备驱动程序的初始化函数和卸载函数
module_init(gpio_init);
module_exit(gpio_exit);
这两行代码分别调用设备驱动程序的初始化函数和卸载函数,用于加载或卸载设备驱动程序。
- 模块的说明信息
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“Your Name”);
MODULE_DESCRIPTION(“A simple GPIO device driver for AXI GPIO on Zynq”);
这几行是设备驱动程序的说明信息,包括了许可证、作者和一些基本描述。模块的许可证、作者和描述等信息,将会在模块被加载时在控制台上显示。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。