• Linux LED字符设备驱动




    // 申请IO资源
    int gpio_request(unsigned gpio, const char *label);
    // 释放IO资源
    void gpio_free(unsigned gpio);
    // 将IO引脚配置为输入
    int gpio_direction_input(unsigned gpio);
    // 将IO引脚配置为输出并设置引脚电平
    int gpio_direction_output(unsigned gpio, int value);
    // 读取引脚电平
    int gpio_get_value(unsigned gpio);
    // 设置引脚电平
    void gpio_set_value(unsigned gpio, int value);


    // 应用层的open/close/read/write/ioctl/llseek会调用以下对应的函数
    struct file_operations {
    int (*open) (struct inode *, struct file *);
    int (*release) (struct inode *, struct file *);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    loff_t (*llseek) (struct file *, loff_t, int);
    };

    //此命令用于应用和驱动之间的ioctl通信

    // 参数1--表示一个魔幻数--用一个字符表示
     //参数2--区分不同命令的整数
     //参数3--传递的数据的类型

    // 自动生成一个普通的命令号
    _IO(type,nr)
    // 自动生成一个带可读参数的命令号
    _IOR(type,nr,size)
    // 自动生成一个带可写参数的命令号
    _IOW(type,nr,size)
    // 自动生成一个带可读写参数的命令号
    _IOWR(type,nr,size)
    // 例:
    #define LED_ON_IOW('L', 0x90, int)
    #define LED_OFF_IOW('L', 0x91, int)
    #define LED_ON_ALL_IO('L', 0x92)
    #define LED_OFF_ALL_IO('L', 0x93)


    // 1,向系统申请设备号
    //参数1:需要申请的主设备号,次设备号默认为0---如果参数1大于0表示静态指定,等于由系统分配
    //参数2:用于描述设备信息--自定义--会显示在/proc/devices
    //参数3:文件操作对象,为用户提供文件IO操作集合
    //返回值:错误返回负数,成功返回0
    static inline int register_chrdev(unsigned int major, const char *name,
      const struct file_operations *fops);
    // 释放设备号
    static inline void unregister_chrdev(unsigned int major, const char *name);


    // 在/sys/class目录下创建一个目录,目录名是name指定的
    // 参数1:THIS_MODULE
    // 参数2:设备名
    // 返回值:class指针
    struct class *class_create(struct module *owner, const char *name);


    // 删除class指针指向的目录
    // 参数:class指针
    void class_destroy(struct class *cls);


    // 在class指针指向的目录下再创建一个目录
    // 参数1:class指针
    // 参数2:父对象,一般写NULL
    // 参数3:设备号
    // 参数4:私有数据,一般写NULL
    // 参数5:/dev下的设备名,可变参数
    // 返回值:device指针
    struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);


    // 删除device_create创建的目录
    // 参数:class指针

    void device_destroy(struct class *cls, dev_t devt);


    led_drv.c

    #include <linux/module.h>
    #include <linux/init.h>
    
    #include <linux/fs.h>
    #include <linux/gpio.h>
    #include <linux/device.h>
    #include <linux/slab.h>
    
    #include <asm/ioctl.h>
    
    //根据参数由内核生成一个唯一的命令号供ioctl使用
    #define LED_ON            _IOW('L', 0x90, int)
    #define LED_OFF            _IOW('L', 0x91, int)
    #define LED_ON_ALL        _IO('L', 0x92)
    #define LED_OFF_ALL        _IO('L', 0x93)
    
    
    struct samsung
    {
        int major;
        struct class *cls;
        struct device *dev;
    };
    
    static struct samsung *led_dev;
    
    static int led_open(struct inode *inode, struct file *filp)
    {
        int ret;
        
        printk(KERN_INFO "^_^ %s
    ", __FUNCTION__);
    
        //申请IO资源,并起名为led0
        ret = gpio_request(EXYNOS4_GPL2(0), "led0");
        if (ret < 0)
        {
            printk("gpio_request fail!
    ");
            return -EBUSY;
        }
    
        //将IO口配置为输出并设置为低电平
        gpio_direction_output(EXYNOS4_GPL2(0), 0);
    
        ret = gpio_request(EXYNOS4_GPK1(1), "led1");
        if (ret < 0)
        {
            printk("gpio_request fail!
    ");
            return -EBUSY;
        }
        gpio_direction_output(EXYNOS4_GPK1(1), 0);
    
        return 0;
    }
    static int led_close(struct inode *inode, struct file *filp)
    {
        printk(KERN_INFO "^_^ %s
    ", __FUNCTION__);
    
        gpio_direction_output(EXYNOS4_GPL2(0), 0);
        //释放IO口资源
        gpio_free(EXYNOS4_GPL2(0));
    
        gpio_direction_output(EXYNOS4_GPK1(1), 0);
        gpio_free(EXYNOS4_GPK1(1));
    
        return 0;
    }
    static ssize_t led_read(struct file *filp, char __user *buf, size_t len, loff_t *pos)
    {
        printk(KERN_INFO "^_^ %s
    ", __FUNCTION__);
    
        return 0;
    }
    static ssize_t led_write(struct file *filp, const char __user *buf, size_t len, loff_t *pos)
    {
        printk(KERN_INFO "^_^ %s
    ", __FUNCTION__);
    
        return 0;
    }
    static long led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
    {
        printk(KERN_INFO "^_^ %s
    ", __FUNCTION__);
    
        switch (cmd)
        {
            case LED_ON:
                if (arg == 0)
                    gpio_direction_output(EXYNOS4_GPL2(0), 1);
                else
                    gpio_direction_output(EXYNOS4_GPK1(1), 1);
                break;
                
            case LED_OFF:
                if (arg == 0)
                    gpio_direction_output(EXYNOS4_GPL2(0), 0);
                else
                    gpio_direction_output(EXYNOS4_GPK1(1), 0);
                break;
                
            case LED_ON_ALL:
                gpio_direction_output(EXYNOS4_GPL2(0), 1);
                gpio_direction_output(EXYNOS4_GPK1(1), 1);
                break;
                
            case LED_OFF_ALL:
                gpio_direction_output(EXYNOS4_GPL2(0), 0);
                gpio_direction_output(EXYNOS4_GPK1(1), 0);
                break;
                
            default:
                printk(KERN_ERR "cmd is error!
    ");
                break;
        }
    
        return 0;
    }
    
    struct file_operations led_fops = 
    {
        .open = led_open,
        .release = led_close,
        .read = led_read,
        .write = led_write,
        .unlocked_ioctl = led_ioctl,
    };
    
    
    static int __init led_init(void)
    {
        int ret;
    
        printk(KERN_INFO "^_^ %s
    ", __FUNCTION__);
    
        //向内核申请内存
        led_dev = kmalloc(sizeof(struct samsung), GFP_KERNEL);
        if (led_dev == NULL)
        {
            printk("kmalloc err!
    ");
            return -ENOMEM;
        }
    
        //申请设备号
        ret = register_chrdev(0, "led", &led_fops);
        if (ret < 0)
        {
            printk(KERN_ERR "register_chrdev error!
    ");
            goto major_err;;
        }
        led_dev->major = ret;
        printk(KERN_INFO "major = %d
    ", led_dev->major);
    
        //在/sys/class目录下创建一个名为"led"的目录
        led_dev->cls = class_create(THIS_MODULE, "led");
        if (led_dev->cls == NULL)
        {
            printk(KERN_ERR "class_create error!
    ");
            ret = -EEXIST;
            goto class_err;
        }
    
        //在class指针指向的目录下再创建一个名为"led0"的目录
        led_dev->dev= device_create(led_dev->cls, NULL, MKDEV(led_dev->major, 0), NULL, "led0");
        if (led_dev->dev == NULL)
        {
            printk(KERN_ERR "device_create error!
    ");
            ret = -EEXIST;
            goto device_err;
        }
    
        return 0;
    
    device_err:
        class_destroy(led_dev->cls);
    class_err:
        unregister_chrdev(led_dev->major, "led");
    major_err:
        kfree(led_dev);
    
        return ret;
    }
    
    static void __exit led_exit(void)
    {
        printk(KERN_INFO "^_^ %s
    ", __FUNCTION__);
    
        //删除device_create创建的目录
        device_destroy(led_dev->cls, MKDEV(led_dev->major, 0));
        //删除class指针指向的目录
        class_destroy(led_dev->cls);
        //释放设备号
        unregister_chrdev(led_dev->major, "led");
        //释放内存
        kfree(led_dev);
    }
    
    module_init(led_init);
    module_exit(led_exit);
    
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("Aaron Lee");

    led_app.c

    #include <stdio.h>
    
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    
    
    
    #define LED_ON            _IOW('L', 0x90, int)
    #define LED_OFF            _IOW('L', 0x91, int)
    #define LED_ON_ALL        _IO('L', 0x92)
    #define LED_OFF_ALL        _IO('L', 0x93)
    
    int main(void)
    {
        int fd;
    
        fd = open("/dev/led0", O_RDWR);
    
        while(1)
        {
            ioctl(fd,LED_ON,0);
            sleep(1);
            
            ioctl(fd,LED_OFF,0);
            sleep(1);
    
            ioctl(fd,LED_ON,1);
            sleep(1);
    
            ioctl(fd,LED_OFF,1);
            sleep(1);
    
            
            ioctl(fd,LED_ON_ALL,0);
            sleep(1);
    
            ioctl(fd,LED_OFF_ALL,0);
            sleep(1);
        }
    
        return 0;
    }

    Makefile文件请参照:http://www.cnblogs.com/lialong1st/p/7756677.html


  • 相关阅读:
    MySQL命令行基本操作
    MYSQL多表查询笔记
    MYSQL事务笔记
    Linux测试环境部署相关命令和步骤
    Jmeter录制脚本
    办公软件通讯录排序相关测试点
    Burp Suite抓包App
    安全测试 Burp Suite抓包工具
    及时通信办公软件,验证码登录,获取验证码失败原因分析和规避方法
    redis内存溢出问题分析和后续规避方法
  • 原文地址:https://www.cnblogs.com/lialong1st/p/7756676.html
Copyright © 2020-2023  润新知