Linux GPIO驱动实例及GPIOLib简介

26.1 前言

Linux2.6.35 之后就有了gpiolib,其作用为对所有GPIO进行统一管理,避免多个驱动控制一个IO所带来的混乱,需要在编译内核的时候选上支持gpiolib选项。本文是基于Linux gpiolib库初试GPIO驱动编程的学习记录,供学习参考。

 

26.2 混杂设备

混杂设备主设备号为10,次设备号:0-255共256个设备。minor=MISC_DYNAMIC_MINOR时,表示动态分配次设备号,我们不用管,其会自动分配空闲的次设备号。

 

26.3 驱动ictol参数构建

在编写ioctl函数时,我们需要构建一些命令用以执行不同操作。_IOWR(幻数,基数,变量),_IOW(幻数,基数,变量), _IOR(幻数,基数,变量), _IO (幻数,基数)。

(1)_IOWR:构建读写命令

(2)_IOW:构建带参数的写命令

(3)_IOR:构建读命令

(4)_IO:构建不带读写的普通命令

示例:

#define IGPIO_IOCTL_MAGIC        0XF12
#define IGPIO_IOCTL_RESET        _IO(IGPIO_IOCTL_MAGIC, 0x0)
#define IGPIO_IOCTL_SET          _IO(IGPIO_IOCTL_MAGIC, 0x1)

#define IGPIO_IOCSET            _IOW(IGPIO_IOCTL_MAGIC, 0, 变量)
#define IGPIO_IOCGET            _IOR(IGPIO_IOCTL_MAGIC, 1, 变量)

 

26.4 GPIOLib常用函数

使用gpio接口需要包含#include <linux/gpio.h> ,在驱动中使用延时函数mdelay,需要包含#include <linux/delay.h>文件

gpio_request(gpioNum,gpioName)

申请一个空闲的GPIO

gpio_free(gpioNum)

释放申请到的GPIO

gpio_direction_input(gpioNum)

设置GPIO为输入模式

gpio_direction_output(gpioNum,value)

设置GPIO为输出模式+值

gpio_get_value(gpioNum)

获取GPIO的电平值

gpio_set_value(gpioNum,value)

设置GPIO输出电平值

gpio_to_irq(gpioNum)

返回GPIO对应的中断号

irq_to_gpio(irq)

返回irq对应的GPIO号

 

26.5 GPIOLib实例编程

gpiodrv.c

#include <linux/init.h>  
#include <linux/module.h>  
#include <asm/uaccess.h>  
#include <linux/fs.h>  
#include <linux/errno.h>  
#include <linux/gpio.h>  
#include <linux/sys_config.h>  
#include <linux/miscdevice.h>  
  
  
#define IGPIO_DEVICE_NAME       "igpioDrv"  
#define IGPIO_IOCTL_MAGIC       0XF12  
#define IGPIO_IOCTL_RESET       _IO(IGPIO_IOCTL_MAGIC, 0x0)  
#define IGPIO_IOCTL_SET         _IO(IGPIO_IOCTL_MAGIC, 0x1)  
static DEFINE_MUTEX(igpio_ioctlmutex);          /* 声明并初始化互斥锁 */  
static int gpioNumer = 0;                       /*用以保存申请到的io*/  
  
static int igpio_open(struct inode *node, struct file *filp)  
{  
    return 0;  
}  
  
static long igpio_ioctl(struct file *filp, unsigned int cmd, unsigned long gpioNum)  
{  
    int nRet = 0;  
  
    printk(KERN_EMERG "cmd= %d,gpioNum= %d\n",cmd,gpioNum);  
    mutex_lock(&igpio_ioctlmutex);  
    if(gpioNumer != gpioNum)  
    {     
        nRet = gpio_request(gpioNum, NULL);  
        if(nRet){  
            printk(KERN_EMERG "%d gpio_request failed\n", gpioNum);  
            nRet = -EINVAL;  
            goto iExit;  
        }  
  
        gpio_free(gpioNumer); //如果申请了新的那就释放掉旧的  
        gpioNumer = gpioNum;  
    }  
      
    switch(cmd){  
        case IGPIO_IOCTL_RESET:  
            gpio_direction_output(gpioNumer,0x00);  
            break;  
        case IGPIO_IOCTL_SET:  
            gpio_direction_output(gpioNumer,0x01);  
            break;  
        default:  
        nRet = -EINVAL;  
    }  
      
iExit:  
  
    mutex_unlock(&igpio_ioctlmutex);  
    return nRet;  
}  
  
static const struct file_operations gpio_fops ={  
    .owner  = THIS_MODULE,  
    .open   = igpio_open,  
    .unlocked_ioctl = igpio_ioctl,  
};  
  
static struct miscdevice gpioMiscDevSt ={  
    .minor = MISC_DYNAMIC_MINOR,  
    .name  = IGPIO_DEVICE_NAME,  
    .fops  = &gpio_fops,  
};  
  
static int __init gpioDrv_init(void)  
{  
    int nRet = 0;  
    /*注册设备*/  
    nRet = misc_register(&gpioMiscDevSt);  
    printk(KERN_EMERG "%s misc_deregister nRet=%d \n",__FUNCTION__,nRet);  
  
    return nRet;  
}  
  
static void __exit gpioDrv_exit(void)  
{  
    int nRet = -1;  
  
    gpio_free(gpioNumer);  
    nRet = misc_deregister(&gpioMiscDevSt);  
    if(nRet<0)  
        printk(KERN_EMERG "%s misc_deregister failed\n",__FUNCTION__);  
}  
  
module_init(gpioDrv_init);  
module_exit(gpioDrv_exit);  
MODULE_LICENSE("GPL");  

iotest.c

#include <stdio.h>  
#include <unistd.h>  
#include <sys/ioctl.h>  
#include <fcntl.h>  
#include <string.h>  
  
#define IGPIO_IOCTL_MAGIC       0XF12  
#define IGPIO_IOCTL_RESET       _IO(IGPIO_IOCTL_MAGIC, 0x0)  
#define IGPIO_IOCTL_SET         _IO(IGPIO_IOCTL_MAGIC, 0x1)  
  
int main(int argc, char **argv)  
{  
    unsigned int id = 0;  
    unsigned int value = 0;  
    int fd = -1;  
    int ret;  
  
    if(argc <4){  
        printf("Usage:./app -s 194 0\n");  
        return -1;  
    }  
  
    sscanf(argv[2], "%d", &id);  
    sscanf(argv[3], "%x", &value);  
  
    fd = open("/dev/igpioDrv", O_RDWR, 0);  
    if (fd < 0) {  
        printf("open fail\n");  
        return -1;  
    }  
  
    if (0 == strncmp(argv[1], "-s", strlen(argv[1])))  
    {  
        if(value == 0)  
            ret = ioctl(fd, IGPIO_IOCTL_RESET, id);  
        else   
            ret = ioctl(fd, IGPIO_IOCTL_SET, id);  
        if (ret < 0) {  
            perror("ioctl fail\n");  
        }  
    }  
  
    close(fd);  
    return 0;  
}  

Makefile

ifneq ($(KERNELRELEASE),)  # linux内核源代码中的顶层makefile中有定义
	obj-m += gpiolibdrv.o
else
	ARCH = arm
	CROSS_COMPILER = $(CROSS_COMPILE)
	CC = $(CROSS_COMPILER)gcc
	LD = $(CROSS_COMPILER)ld

CURRENT_PATH := $(shell pwd)

KERNEL_PATH := ../../kernel/linux-3.10

CFLAGS+= -O2 -Wall
all:
	make -C $(KERNEL_PATH) M=$(CURRENT_PATH) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILER) modules

clean:
	rm -rf .tmp_versions
	rm -rf *.o *.ko *.mod.* test
	rm -rf .*.cmd*
	rm -rf modules* Module*
endif

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值