嵌入式LINUX驱动学习之5.ioctl字符设备驱动编程(二)内核空间实现代码

嵌入式LINUX驱动学习之5.ioctl字符设备驱动编程(二)内核空间实现代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
//定LED灯硬件信息
struct led_source {
    
    
   char *name;
   unsigned led_num;
};
struct led_source led_info[] = {
    
    
    {
    
    
        .name    = "LED1",
        .led_num = PAD_GPIO_C +12
    },
    {
    
    
        .name    = "LED2",
        .led_num = PAD_GPIO_C +11
    },
   {
    
    
        .name    = "LED3",
        .led_num = PAD_GPIO_C +7
    },
    {
    
    
        .name    = "LED4",
        .led_num = PAD_GPIO_B +26
    }


};
/*获取每个LED灯的状态,保存到kindex数组内
void led_state(unsigned long kindex[4]){
    int i = 0;
    for(;i < 4;i++){
    kindex[i] = (int ) gpio_get_value(led_info[i].led_num);
    }
}
#define LED_ON    0X100
#define LED_OFF   0X101
#define LED_STATE 0X110
/*
file  : 对应用户空间的fd(文件描述符
cmd   : 对应用户空间的ucmd
arg   : 在用户空间时是地址,内核空间是无符号长整形,
        在执行copy_from_user()函数时,可以将arg看做地址形参
*/
long led_ioctl(struct file * file,unsigned int cmd,unsigned long arg){
    
    
    unsigned long kindex[4] ;//用于保存用用户空间arg地址内的数据
    copy_from_user(kindex,arg,4);
    switch(cmd){
    
    
        case LED_ON :
            gpio_set_value(led_info[kindex[0]-1].led_num,0);
            //        用户空间对灯编号为:1~4                        
            break;
        case LED_OFF :
            gpio_set_value(led_info[kindex[0]-1].led_num,1);
            break;
        case LED_STATE :
            led_state(kindex);
            copy_to_user(arg,kindex,sizeof(int) *4);//将灯的状态信息拷贝到用户空间
            break;
        default :
            break;
    }
}
//定义ioctl函数操作接口
static struct file_operations fops={
    
    
    .owner = THIS_MODULE,
    .unlocked_ioctl = led_ioctl
};
static dev_t dev_num;
static struct cdev cdev;
static int led_init(void){
    
    
    /*申请GPIO资源*/
    int i = 0;
    for(; i < ARRAY_SIZE(led_info); i++){
    
    
        gpio_request(led_info[i].led_num,led_info[i].name);
        gpio_direction_output(led_info[i].led_num,1);
    }
    //申请设备号
    alloc_chrdev_region(&dev_num,0,4,"led_ioctl_test");
    //初始化字符设备
    cdev_init(&cdev,&fops);
    //注册字符设备
    cdev_add(&cdev,dev_num,4);

    return 0;
}
static void led_exit(void){
    
    
    /*释放GPIO资源*/
    int i = 0 ;
    for(; i< ARRAY_SIZE(led_info);i++){
    
    
        gpio_set_value(led_info[i].led_num,1);
        gpio_free(led_info[i].led_num);
    }
    /*卸载字符设备注册*/
    cdev_del(&cdev);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");


猜你喜欢

转载自blog.csdn.net/weixin_47273317/article/details/107848572