zoukankan      html  css  js  c++  java
  • LED驱动程序分析

             混杂设备 LED驱动程序分析

    /*******************************
     *
     *杂项设备驱动:miscdevice
     *majior=10;
     *
     * *****************************/
    
    
    
    
    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/types.h>
    #include <linux/init.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 <mach/regs-gpio.h>
    #include <plat/gpio-cfg.h>
     
     
    #define S3C_GPIO_SPECIAL_MARK      (0xfffffff0)
    #define S3C_GPIO_SPECIAL(x)        (S3C_GPIO_SPECIAL_MARK | (x))//内核当中定义
    
    
    #define DEVICE_NAME "leds"
    static int led_gpios[] = {
        S5PV210_MP04(4),
        S5PV210_MP04(5),
        S5PV210_MP04(6),
        S5PV210_MP04(7),
    };//4个LED
    #define LED_NUM        ARRAY_SIZE(led_gpios)
    
    
    static long fl210_leds_ioctl(struct file *filp, unsigned int cmd,
            unsigned long arg)
    {
        switch(cmd) {
            case 0:
            case 1:
                if (arg > LED_NUM) {
                    return -EINVAL;
                }
    
    
                gpio_set_value(led_gpios[arg], !cmd);//根据cmd设置LED的暗灭
                printk(DEVICE_NAME": %ld %d
    ", arg, cmd);
                break;
    
    
            default:
                return -EINVAL;
        }
    
    
        return 0;
    }
    static struct file_operations fl210_led_dev_fops = {
        .owner            = THIS_MODULE,
        .unlocked_ioctl    = fl210_leds_ioctl,
    };
    //----------------miscdevice------------------static struct miscdevice fl210_led_dev = {
        .minor            = MISC_DYNAMIC_MINOR,
        .name            = DEVICE_NAME,
        .fops            = &fl210_led_dev_fops,
    };//--------------------------------------------
    
    
    static int __init fl210_led_dev_init(void) {
        int ret;
        int i;
    
    
        for (i = 0; i < LED_NUM; i++) {
            ret = gpio_request(led_gpios[i], "LED");//申请GPIO口
            if (ret) {
                printk("%s: request GPIO %d for LED failed, ret = %d
    ", DEVICE_NAME,
                        led_gpios[i], ret);
                return ret;
            }
    
    
            s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);//设置GPIO口为输出
            gpio_set_value(led_gpios[i], 1);//初始化GPIO口的值
        }
    
    
        ret = misc_register(&fl210_led_dev);//注册杂项设备
    
    
        printk(DEVICE_NAME"	initialized
    ");
        printk("led num is: %d
    ",LED_NUM);
        return ret;
    }
    static void __exit fl210_led_dev_exit(void) {
        int i;
    
    
        for (i = 0; i < LED_NUM; i++) {
            gpio_free(led_gpios[i]);//释放GPIO口
        }
    
    
        misc_deregister(&fl210_led_dev);//注销设备
    }
    
    
    module_init(fl210_led_dev_init);
    module_exit(fl210_led_dev_exit);
    
    
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("");

    S5PV210_MP04宏定义在linux/arch/arm/mach-s5pv210/include/mach/gpio.h

    #define S5PV210_MP04(_nr) (S5PV210_GPIO_MP04_START + (_nr))

    S5PV210_GPIO_MP04_START = S5PV210_GPIO_NEXT(S5PV210_GPIO_MP03),

    #define S5PV210_GPIO_NEXT(__gpio) ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)

    //这里的CONFIG_S3C_GPIO_SPAC是内核配置选项,在.config中可以找到,我的配置为:   CONFIG_S3C_GPIO_SPACE = 0

    上述代码用到以下几个函数:

    gpio_set_value();

    s3c_gpio_cfgpin();

    gpio_request();

    gpio_free();

    misc_register();

    misc_deregister();

    后面会逐个分析。

    测试程序如下:

                       
       

    #include <stdio.h>//#include "sys/types.h"
    #include <sys/ioctl.h>
    #include <stdlib.h>
    #include <unistd.h>//read,write等等//#include "termios.h"//#include "sys/stat.h"
    #include <fcntl.h>
    #define LED2_ON 0x1#define LED2_OFF 0x0
    
    
    main(int argc,char *argv[])
    {
        int fd;
    
    
        if ((fd=open("/dev/leds",O_RDWR /*| O_NDELAY | O_NOCTTY*/)) < 0)
        {
            printf("Open Device  failed.
    ");
            exit(1);
        }
        else
        {
            printf("Open Device  successed.
    ");
        }
        if (argc<3)
        {
            /* code */
            printf("Usage: %s <on|off num>
    ",argv[0]);
            exit(1);
        }
        if(!strcmp(argv[1],"on"))
        {
            printf("led1 will on!!
    ");
           if(ioctl(fd,LED2_ON,atoi(argv[2]))<0)
           {
               printf("ioctl err!!
    ");     
           }
        
        }
        if(!strcmp(argv[1],"off"))
        {
            printf("led1 will off!!
    ");
            if(ioctl(fd,LED2_OFF,atoi(argv[2]))<0)
            {
                printf("ioctl err!!
    ");
            }
        }
        close(fd);
    }
     
     
     

     首先来看s3c_gpio_cfgpin();

     
    int s3c_gpio_cfgpin(unsigned int pin, unsigned int config)
    {
        struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);//得到对应GPIO结构体首指针,里面包含了该GPIO的各种参数
        unsigned long flags;
        int offset;
        int ret;
    
    
        if (!chip)
            return -EINVAL;
    
    
        offset = pin - chip->chip.base;
    
    
        s3c_gpio_lock(chip, flags);
        ret = s3c_gpio_do_setcfg(chip, offset, config);//设置该GPIO状态寄存器的数值为config
    s3c_gpio_unlock(chip, flags);
    
    
        return ret;
    }
     
    static inline struct s3c_gpio_chip *s3c_gpiolib_getchip(unsigned int chip)
    {
        return (chip < S3C_GPIO_END) ? s3c_gpios[chip] : NULL;
    }
     
     
     
    static inline int s3c_gpio_do_setcfg(struct s3c_gpio_chip *chip,
                         unsigned int off, unsigned int config)
    {
        return (chip->config->set_config)(chip, off, config);
    }
    static struct s3c_gpio_cfg gpio_cfg = {
        .set_config    = s3c_gpio_setcfg_s3c64xx_4bit,
        .set_pull    = s3c_gpio_setpull_updown,
        .get_pull    = s3c_gpio_getpull_updown,
    };
    int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
                     unsigned int off, unsigned int cfg)
    {
        void __iomem *reg = chip->base;
        unsigned int shift = (off & 7) * 4;
        u32 con;
    
    
        if (off < 8 && chip->chip.ngpio > 8)
            reg -= 4;
    
    
        if (s3c_gpio_is_cfg_special(cfg)) {
            cfg &= 0xf;
            cfg <<= shift;
        }
    
    
        con = __raw_readl(reg);//读GPXCON的值
        con &= ~(0xf << shift);//清零
        con |= cfg;//设置config
        __raw_writel(con, reg);//写值
    
    
        return 0;
    }

     其中结构体s3c_gpio_chip如下:

    
    
     */struct s3c_gpio_chip {
        struct gpio_chip    chip;
        struct s3c_gpio_cfg    *config;
        struct s3c_gpio_pm    *pm;
        void __iomem        *base;
        int            eint_offset;
        spinlock_t         lock;
    #ifdef CONFIG_PM
        u32            pm_save[7];#endif
    };
    static struct s3c_gpio_chip s5pv210_gpio_4bit[] = {//描述了芯片中所有的GPIO端口
        {
            .chip    = {
                .base    = S5PV210_GPA0(0),
                .ngpio    = S5PV210_GPIO_A0_NR,
                .label    = "GPA0",
                .to_irq = s5p_gpiolib_gpioint_to_irq,
            },
        },{
                     。。。。
                 }
                     。。。。
    };

    接下来看gpio_set_value();

    void __gpio_set_value(unsigned gpio, int value)
    {
        struct gpio_chip    *chip;
    
    
        chip = gpio_to_chip(gpio);//返回对应于pin的gpio_desc[pin].chip指针 
        WARN_ON(extra_checks && chip->can_sleep);
        chip->set(chip, gpio - chip->base, value);//调用chip->set
    }
     
     
  • 相关阅读:
    洛谷P1661 扩散
    Vijos1056 图形面积
    Python爬取猪肉价格网并获取Json数据
    C#中巧用Lambda表达式实现对象list进行截取
    Winform中在ZedGraph中最多可以添加多少条曲线
    Nginx配置实例-动静分离实例:搭建静态资源服务器
    解决pip使用异常No module named 'pip'
    C#在循环中使用Random时生成的随机数相同的解决办法
    Winform中自定义ZedGraph右键复制成功后的提示
    C#中巧用Lambda进行数据的筛选查询等处理
  • 原文地址:https://www.cnblogs.com/zxouxuewei/p/4937039.html
Copyright © 2011-2022 走看看