gpio IOCTL控制


之前工作的時候,linux下用過GPIO的,無非就是配置輸出輸入模式,set/get value ,或者是gpio中斷之類的,用戶態配置GPIO主要是兩種方式:用戶態使用mmap直接將GPIO 地址映射過來,操作地址, 或者 IOCTL發命令給內核,內核來控制,最近半年都在寫單片機的代碼。時間久了有點忘了,最近使用都是偷懶直接使用了/sys下的設備,通過
system("echo \"out\" > /sys/class/gpio/gpio47/direction"); 這種方法去配置GPIO ,程序跑起來會經常出現sh: write error: Device or resource busy 這種問題,所以感覺還是使用IOCTL來管理GPIO 口,網上找了找,http://blog.csdn.net/oyhb_1992/article/details/77227276 大概參照這位大俠的用法。。先記下來,改改代碼,再繼續編輯

9月20日更新,參照網上的例子,寫了些代碼,期間簡單學習了下IOCTL參數及幻數的用法,思路很簡單,編寫一個模塊,里面初始化gpio,執行對於的IOCTL操作,只是簡單實現了read/write gpio vlaue的功能,set output/input 因為用不到沒有去實現,測試正常

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/uaccess.h> 
//#include <linux/moduleparam.h>
//#include <linux/slab.h>//kcalloc,kzalloc等內存分配函數

//---------ioctl------------
#include <linux/ioctl.h>

//---------misc_register----
#include <linux/miscdevice.h>

//----------cdev--------------
#include <linux/cdev.h>

//----------delay-------------
#include <linux/delay.h>

//----------GPIO---------------
#include <mach/gpio.h>
#include <linux/gpio.h>
#include <mach/regs-gpio.h>
//#include <plat/gpio-cfg.h>

//#define MISC_DYNAMIC_MINOR 0
#define DEVICE_NAME "gpio_ctrl"
//靜態映射的管腳虛擬地址
static int gpios[] = {
        NUC970_PB15,//reset gps
        NUC970_PH10,//reset 4g
        NUC970_PH13,//do1
        NUC970_PH14,//12v
        NUC970_PH15,//do2
        NUC970_PI5,
        NUC970_PI8,
        NUC970_PI9,
        NUC970_PI10,
        NUC970_PI11,
};//4個LED
#define GPIO_NUM        ARRAY_SIZE(gpios)
#define GET_CMD_MAGIC 0xde              //type字段,由於字段寬度為8 bits,所以不能大於0xff
#define SET_CMD_MAGIC 0xdf              //type字段,由於字段寬度為8 bits,所以不能大於0xff
#define GET_CMD  _IOWR(GET_CMD_MAGIC,0,unsigned int)
#define SET_CMD  _IOW(SET_CMD_MAGIC,0,unsigned int)           
struct ioctl_data{
        int gpionum;
        int value;
};
static long gpio_ctrl_ioctl(struct file *filp, unsigned int cmd,
                unsigned long arg)    //第二個參數是命令號,第三個參數是附加參數
{
        int ret = 0;

        struct ioctl_data val;    
        switch(cmd) {
                case SET_CMD:     //命令碼:如果寫規范格式如:#define LED2_OFF _IOR(‘L’,0,unsigned char) 
                        if(copy_from_user(&val, (struct ioctl_data *)arg, sizeof(struct ioctl_data))){
                                ret = - EFAULT;
                                return ret;
                        }
                        gpio_set_value(val.gpionum,val.value);
                        printk(DEVICE_NAME": gpio %d set value %d\n", val.gpionum,val.value);    
                        break;
                case GET_CMD:     //命令碼:如果寫規范格式如:#define LED2_ON _IOR(‘L’,1,unsigned char) 也可以把命令碼放在一個頭文件里,應用和驅動都包含它
                        if(copy_from_user(&val, (struct ioctl_data *)arg, sizeof(struct ioctl_data))){
                                return -EFAULT;
                        }

                        val.value = gpio_get_value(val.gpionum);//
                        printk(DEVICE_NAME": gpio %d value %d\n", val.gpionum,val.value);
                        //        retval = copy_to_user((unsigned int *)arg, &phone_num, sizeof(unsigned int));
                        if(copy_to_user((struct ioctl_data *)arg,&val,sizeof(struct ioctl_data))){
                                return -EFAULT;
                        }
                        break;

                default:
                        return -EINVAL;
        }
        return 0;
}

static struct file_operations gpio_ctrl_dev_fops = {
        .owner            = THIS_MODULE,
        .unlocked_ioctl    = gpio_ctrl_ioctl,
};

//----------------miscdevice------------------
static struct miscdevice gpio_ctrl_dev = {
        .minor            = MISC_DYNAMIC_MINOR,
        .name            = DEVICE_NAME,
        .fops            = &gpio_ctrl_dev_fops,
};
//--------------------------------------------


static int __init gpio_ctrl_dev_init(void) {
        int ret;
        int i;
        //申請gpio,只有在gpio_request后才可以調用gpio_set_value,gpio_get_value等函數
        for (i = 0; i < GPIO_NUM; i++) {
                ret = gpio_request(gpios[i], "GPIOCTRL");//申請GPIO口
                if (ret) {
                        printk("%s: request GPIO %d  failed, ret = %d\n", DEVICE_NAME,
                                        gpios[i], ret);
                        return ret;
                }

                gpio_direction_output(gpios[i],1);
                //也可以用函數gpio_direction_output(unsigned gpio, int value);
        //        gpio_set_value(led_gpios[i], 1);//初始化GPIO口的值
        }

        ret = misc_register(&gpio_ctrl_dev);//注冊混雜設備

        printk(DEVICE_NAME"\tinitialized\n");
//        printk("led num is: %d\n",LED_NUM);
        return ret;
}

static void __exit gpio_ctrl_dev_exit(void) {
        int i;

        for (i = 0; i < GPIO_NUM; i++) {
                gpio_free(gpios[i]);//釋放GPIO口
        }

        misc_deregister(&gpio_ctrl_dev);//注銷設備
}

module_init(gpio_ctrl_dev_init);
module_exit(gpio_ctrl_dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("");

用戶態代碼:

//應用程序設計

#include <stdio.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>//read,write等等
#include <fcntl.h>

#define GET_CMD_MAGIC 0xde              //type字段,由於字段寬度為8 bits,所以不能大於0xff
#define SET_CMD_MAGIC 0xdf              //type字段,由於字段寬度為8 bits,所以不能大於0xff
#define GET_CMD  _IOWR(GET_CMD_MAGIC,0,unsigned int)
#define SET_CMD  _IOW(SET_CMD_MAGIC,0,unsigned int)           
struct ioctl_data{
        int gpionum;
        int value;
};
int main(int argc,char *argv[])
{
    int fd;
    struct ioctl_data val;
    val.gpionum = 237;
    val.value = atoi(argv[1]);
    if ((fd=open("/dev/gpio_ctrl",O_RDWR /*| O_NDELAY | O_NOCTTY*/)) < 0)
    {
        printf("Open Device  failed.\r\n");
        exit(1);
    }
    else
    {
        printf("Open Device  successed.\r\n");
    }


        if(ioctl(fd,SET_CMD,&val)<0)//命令附加參數是atoi(argv[2])
        {
            printf("ioctl err!!\n");     
        }
    close(fd);
}



/*應用層里ioctl函數的原型是:
*#man ioctl 
*int ioctl(int d, int request, ...)
*內核驅動源碼里ioctl函數的原型是:
*long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
*可以知道雖然應用層是可變參數...,但是實際上應用層和驅動層的ioctl函數是對應的,
*所以我們知道,雖然應用層是用...,表示ioctl參數,但是我們應該明白
*應用層的ioctl函數的參數最多只能有3個
*/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM