am335x gpio 控制的另一种方法
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/slab.h>
/*-----------------------------------------------------*/
#define DEVICE_NAME "kio"
#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))
/*------------------------------------------------------*/
struct gpio_qset;
/*设备编号存储结构体*/
struct dev_num
{
dev_t devNum;
unsigned int major;
unsigned int minor;
unsigned int minor_first;
unsigned int count;
};
struct dev_num gpio_dev_num;
/*设备描述结构体*/
struct gpio_dev
{
struct cdev cdev;
struct gpio_qset* dptr; //设备数据存储链表第一项
unsigned long size; //链表长度(随着申请的GPIO端口数增长)
};
struct gpio_dev *gpio_devp;
/*设备数据存储结构体(采用链式存储,不理解的可以看《数据结构》)*/
struct gpio_qset
{
unsigned long port; //端口号 #define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))
unsigned int ddr; //方向(输入(0)或输出(1))
char value; //高(1)低(0)电平
unsigned long num; //当前编号(按照申请顺序编号)
char label[10]; //申请的GPIO使用名称
struct gpio_qset* next; //指向链表下一项的指针
};
/**
* 功能:初始化gpio_dev
* *inode:
* *filp:
* 描述:用户空间调用open时运行
* int (*open) (struct inode *, struct file *);
* 返回值:0
*/
static int gpio_open(struct inode *inode, struct file *filp)
{
struct gpio_dev *dev;
//由container_of获得结构体指针inode中结构体cdev的指针,
//让结构体指针dev指向上述的指针所指的地址,
//再让file->private指向这一地址,
dev = container_of(inode->i_cdev, struct gpio_dev, cdev);
filp->private_data = dev;
dev->dptr = NULL;
dev->size = 0;
//printk(KERN_ERR "gpio_open success!\n");
return 0;
}
/**
* 功能:释放申请的GPIO端口以及释放链表(gpio_qset)
* *inode:
* *filp:
* 描述:用户空间调用close时运行
* int (*release) (struct inode *, struct file *);
* 返回值:0
*/
static int gpio_close(struct inode *inode, struct file *filp)
{
struct gpio_dev *dev = filp->private_data;
struct gpio_qset *qset, *qsetTmp;
qsetTmp = (struct gpio_qset *)kzalloc(sizeof(struct gpio_qset), GFP_KERNEL);
for(qset = dev->dptr; qset->next !=NULL; qset=qsetTmp)
{
qsetTmp = qset->next;
gpio_free(qset->port); //释放申请的端口
kfree(qset); //释放gpio_qset内存
}
gpio_free(qsetTmp->port);
kfree(qsetTmp);
//printk(KERN_ERR "gpio release!\n");
return 0;
}
/**
* 功能:申请新的gpio_qset的内存,确定相应的GPIO端口功能
* *inode:
* *filp:
* cmd:实现的功能,
* 0:读,
* 1:写,
* 2:释放GPIO端口
* arg:执行操作的GPIO端口
* 描述:用户空间调用ioctl时运行
* long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
* 返回值:成功返回操作的GPIO端口号
* 错误返回相应的错误码
*/
static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct gpio_dev *dev = filp->private_data;
struct gpio_qset *qset;
//cmd == 2 设计成为释放arg端口的功能,之后申请内存的任务便不必执行了,所以直接返回
if(cmd == 2)
{
gpio_free(arg);
return arg;
}
dev->size++;
if(dev->dptr == NULL)
{
dev->dptr = (struct gpio_qset *)kzalloc(sizeof(struct gpio_qset), GFP_KERNEL);
qset = dev->dptr;
}
else
{
for(qset = dev->dptr; qset->next != NULL; qset = qset->next); //找到链表最后一项
qset->next = (struct gpio_qset *)kzalloc(sizeof(struct gpio_qset), GFP_KERNEL);
qset = qset->next;
}
/*链表数据*/
qset->num = dev->size; //确定自己的编号
qset->ddr = cmd; //确定方向
qset->port = arg; //确定端口号
qset->next = NULL; //最后一项地址清空
//printk(KERN_ERR "qset->num=%d,qset->ddr=%d,qset->port=%d\n", qset->num, qset->ddr, qset->port);
sprintf(qset->label, "gpio%ld", qset->port); //确定申请的GPIO使用名称(和端口直接相关)
ret = gpio_request(qset->port, qset->label); //申请端口
/*由于gpio_requset会自己判断成功与否并且退出函数,故注释掉对ret的判断
if(ret < 0)
printk(KERN_ERR "%s_requset failled!%d \n", qset->label, ret);
*/
/*判断GPIO工作方向(输出或输出)*/
switch(qset->ddr)
{
case 0:
ret = gpio_direction_input(qset->port);
if(ret < 0)
printk(KERN_ERR "gpio_direction_input failled!\n");
break;
case 1:
ret = gpio_direction_output(qset->port, 1);
if(ret < 0)
printk(KERN_ERR "gpio_direction_output failled!\n");
break;
default:
return -EPERM; /* Operation not permitted */
}
return qset->num;
}
/**
* 功能:获取相应端口电平,写入相应的qset_dev->value,写到用户空间的readBuf
* *inode:
* *filp:
* *readBuf:读数据缓存指针,用户空间的指针
* port:被读取的GPIO端口号
* *offp:
* 描述:用户空间调用read时运行
* ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
* 返回值:成功返回qset->value
* 错误返回相应的错误码
*/
static ssize_t gpio_read (struct file *filp, char __user *readBuf, size_t port, loff_t *offp)
{
long ret;
struct gpio_dev *dev = filp->private_data;
struct gpio_qset *qset;
if(dev->dptr == NULL)
return -ENODEV; /* No such device */
for(qset = dev->dptr; qset != NULL; qset = qset->next)
{
if(qset->port == port)
break;
if(qset->next == NULL)
return -ENODEV; /* No such device */
}
if(qset->ddr != 0) //判断是否ioctl设置为读操作
return -EPERM; /* Operation not permitted */
qset->value = gpio_get_value(qset->port);
//printk(KERN_ERR "qset->port:%d, qset->value:%d\n", qset->port, qset->value);
switch(qset->value)
{
case 0:
ret = copy_to_user(readBuf, "0", 1);
break;
case 1:
ret = copy_to_user(readBuf, "1", 1);
break;
}
return qset->value;
}
/**
* 功能:写入相应端口电平,写入相应的qset_dev->value,数据来自用户空间的writeBuf
* *inode:
* *filp:
* *writeBuf:写数据缓存指针,用户空间的指针
* port:被写入的GPIO端口号
* *offp:
* 描述:用户空间调用write时运行
* ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
* 返回值:成功返回qset->value
* 错误返回相应的错误码
*/
static ssize_t gpio_write (struct file *filp, const char __user *writeBuf, size_t port, loff_t *offp)
{
long ret;
struct gpio_dev *dev = filp->private_data;
struct gpio_qset *qset;
if(dev->dptr == NULL)
return -ENODEV; /* No such device */
for(qset = dev->dptr; qset != NULL; qset = qset->next)
{
// printk(KERN_ERR "qset->port=%d,port=%d\n", qset->port, port);
if(qset->port == port)
break;
if(qset->next == NULL)
return -ENODEV; /* No such device */
}
if(qset->ddr != 1) //判断是否ioctl设置为写操作
return -EPERM; /* Operation not permitted */
ret = copy_from_user(&qset->value, writeBuf, 1);
//printk(KERN_ERR "write:%d\n", qset->value);
switch(qset->value)
{
case '0': qset->value = 0;
gpio_set_value(qset->port, 0);
break;
default : qset->value = 1;
gpio_set_value(qset->port, 1);
break;
}
return qset->value;
}
/*文件操作结构体*/
static const struct file_operations gpio_fops = {
.owner = THIS_MODULE,
.open = gpio_open,
.unlocked_ioctl = gpio_ioctl,
.write = gpio_write,
.read = gpio_read,
.release = gpio_close,
};
/*cdev注册函数*/
static void gpio_setup_cdev(struct gpio_dev *dev, int index)
{
int ret,devno = gpio_dev_num.devNum + index;
cdev_init(&dev->cdev, &gpio_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &gpio_fops;
ret = cdev_add(&dev->cdev, devno, 1);
if(ret)
printk(KERN_ERR "error %d : adding gpioCtl%d",ret,index);
}
static struct class *kio_class;
/*设备初始化函数*/
static int __init omap2gpio_init(void)
{
int ret;
gpio_dev_num.count = 1;
gpio_dev_num.minor_first = 0;
ret = alloc_chrdev_region(&gpio_dev_num.devNum,
gpio_dev_num.minor_first,
gpio_dev_num.count,
DEVICE_NAME);
if(ret < 0)
return ret;
gpio_dev_num.major = MAJOR(gpio_dev_num.devNum);
gpio_dev_num.minor = MINOR(gpio_dev_num.devNum);
gpio_devp = kzalloc(sizeof(struct gpio_dev),GFP_KERNEL);
gpio_setup_cdev(gpio_devp, 0);
printk(KERN_ERR "gpio alloc_chrdev_region success, major = %d\n",
gpio_dev_num.major);
kio_class = class_create(THIS_MODULE, DEVICE_NAME);
device_create(kio_class, //pointer to the struct class that this device should be registered to
NULL,
gpio_dev_num.devNum, //the dev_t for the char device to be added
NULL,
"%s",
DEVICE_NAME);
return 0;
}
/*设备释放函数*/
static void __exit omap2gpio_exit(void)
{
cdev_del(&gpio_devp->cdev);
kfree(gpio_devp);
unregister_chrdev_region(gpio_dev_num.devNum, 1);
device_destroy(kio_class, gpio_dev_num.devNum); //the dev_t for the char device to be added
class_destroy(kio_class);
printk(KERN_ERR "gpio unregister_chrdev_region success, major = %d\n",
gpio_dev_num.major);
}
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Mlo_Lv,Tute-421E-studio");
MODULE_DESCRIPTION("This module is used to conrtol ti omap2 gpio");
module_init(omap2gpio_init);
module_exit(omap2gpio_exit);
am335x gpio 控制的另一种方法的更多相关文章
- nodejs高并发大流量的设计实现,控制并发的三种方法
nodejs高并发大流量的设计实现,控制并发的三种方法eventproxy.async.mapLimit.async.queue控制并发Node.js是建立在Google V8 JavaScript引 ...
- delphi控制 word的几种方法--转
对几种方法的难易程度的判别 a.通过Delphi的控件TOleContainer 将Word嵌入 这是最简单的Ole嵌入,能够直接将Word文档调用,只需要使用ToleContainer.Run就可以 ...
- am335x gpio控制
1.执行下面的命令,可以显示目前驱动已经申请到的IO状态 : $ mount -t debugfs debugfs /sys/kernel/debug $ cat /sys/kernel/debug ...
- Linux 下操作GPIO(两种方法,驱动和mmap)(转载)
目前我所知道的在Linux下操作GPIO有两种方法: 1.编写驱动,这当然要熟悉Linux下驱动的编写方法和技巧,在驱动里可以使用ioremap函数获得GPIO物理基地址指针,然后使用这个指针根据io ...
- Linux 下操作gpio(两种方法,驱动和mmap)
目前我所知道的在linux下操作GPIO有两种方法: 1. 编写驱动,这当然要熟悉linux下驱动的编写方法和技巧,在驱动里可以使用ioremap函数获得GPIO物理基地址指针,然后使用这个指针根据 ...
- [转]iOS之浅谈纯代码控制UIViewController视图控制器跳转界面的几种方法
参考:http://www.mamicode.com/info-detail-469709.html 一.最普通的视图控制器UIViewContoller 一个普通的视图控制器一般只有模态跳转的功能( ...
- css控制div显示/隐藏方法及2种方法比较原码 - czf164的专栏 - 博客频道 - CSDN.NET
body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...
- iOS之浅谈纯代码控制UIViewController视图控制器跳转界面的几种方法
.最普通的视图控制器UIViewContoller 一个普通的视图控制器一般只有模态跳转的功能(ipad我不了解除外,这里只说iPhone),这个方法是所有视图控制器对象都可以用的,而实现这种功能,有 ...
- 控制页面打印的2种方法(css3的media媒体查询和window.print())
在实际开发中,有时可能会有打印的需求.下面我总结了2种打印的方法,希望对各位小伙伴有所帮助. ①:直接用window.print()方法就可以打印整个页面,下面是一个小demo <!DOCTYP ...
随机推荐
- linux 的空命令:(冒号)
php里面又“空操作”这个东西,于是想一想linux的命令中是否有“空命令”这种东西,搜索一下,结果发现真的有这个东西存在 -------:) 冒号 : 就是空命令.即什么也不做,是一个命令占位符 # ...
- 转:Android应用开发性能优化完全分析
转自:http://blog.csdn.net/yanbober/article/details/48394201 1 背景 其实有点不想写这篇文章的,但是又想写,有些矛盾.不想写的原因是随便上网一搜 ...
- linux free命令详解和使用实例(查看内存使用率)
转载:http://www.jb51.net/LINUXjishu/152017.html 1.命令格式: free [参数] 2.命令功能: free 命令显示系统使用和空闲的内存情况,包括物理内存 ...
- STL - C++ 11的Lambda表达式(下)
关于lambda的基础知识,请参考上一篇的地址如下: http://www.cnblogs.com/davidgu/p/4825625.html 我们再举个STL使用Lambda来进行排序的例子,如下 ...
- Python 数据驱动工具:DDT
背景 python 的unittest 没有自带数据驱动功能. 所以如果使用unittest,同时又想使用数据驱动,那么就可以使用DDT来完成. DDT是 “Data-Driven Tests”的缩写 ...
- 菜鸟从零学编程——GET与POST
相信大家在面试的时候经常会被问到:GET与POST有什么区别吧?你是怎么回答的呢?POST比GEt安全?GET有URL的长度限制而POST没有或者很大?GET通过URL或者Cookie传参数,POST ...
- 算法笔记_137:二分图的最大匹配(Java)
目录 1 问题描述 2 解决方案 1 问题描述 何为二分图的最大匹配问题? 引用自百度百科: 首先得说明一下何为匹配: 给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于 ...
- zuul源码分析-探究原生zuul的工作原理
前提 最近在项目中使用了SpringCloud,基于zuul搭建了一个提供加解密.鉴权等功能的网关服务.鉴于之前没怎么使用过Zuul,于是顺便仔细阅读了它的源码.实际上,zuul原来提供的功能是很单一 ...
- JQuery 之CSS操作
JQuery 之CSS操作 设置 <p> 元素的颜色: 将所有段落的颜色设为红色 $(".btn1").click(function(){ $("p" ...
- TP模板中如何使用函数
TP模板中如何使用函数 TP中如何将时间戳转换为时间显示 我们往往需要对模板输出变量使用函数,可以使用: {$data.name|md5} 编译后的结果是: <?php echo (md5($d ...