• 代码示例_ioctl



    //头文件
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/device.h>
    #include <linux/slab.h>
    
    #include <asm/io.h>
    #include <asm/uaccess.h>
    #include <asm-generic/ioctl.h>
    
    #define LED_NUM_ON        _IOW('L',0x1122,int)
    #define LED_NUM_OFF        _IOW('L',0x3344,int)
    #define LED_ALL_ON        _IO('L',0x1234)
    #define LED_ALL_OFF        _IO('L',0x5678)
    
    
    
    
    //面向对象编程----设计设备的类型
    struct s5pv210_led{
        unsigned int major;
        struct class * cls;
        struct device * dev;
        int data;
    };
    struct s5pv210_led *led_dev;
    
    volatile unsigned long *gpco_conf;
    volatile unsigned long *gpco_data;
    
    
    //实现设备操作接口
    int led_open(struct inode *inode, struct file *filp)
    {
        
        printk("--------^_^ %s------------
    ",__FUNCTION__);
        //将对应的管脚设置为输出
        *gpco_conf &= ~(0xff<<12);   //19--12清0
        *gpco_conf |= 0x11<<12;        //19---12赋值:00010001
    
        return 0;
    }
    ssize_t led_write(struct file *filp, const char __user *buf, size_t size, loff_t *flags)
    {
        int ret;
        printk("--------^_^ %s------------
    ",__FUNCTION__);
    
        //应用空间数据转换为内核空间数据
        ret = copy_from_user(&led_dev->data,buf,size);
        if(ret != 0){
            printk("copy_from_user error!
    ");
            return -EFAULT;
        }
    
        if(led_dev->data){
            //点灯
            *gpco_data |= 0x3<<3;
        }else{
            //灭灯
            *gpco_data &= ~(0x3<<3);
        }
    
        return size;
    }
    
    long led_ioctl(struct file *filp, unsigned int cmd , unsigned long args)
    {
        int num = args+2;
        printk("--------^_^ %s------------
    ",__FUNCTION__);
        switch(cmd){
            case LED_NUM_ON:        //将某个灯点亮
                if(num != 3 && num != 4)
                    return -EINVAL;
                else
                    *gpco_data |= 0x1 << num;
                break;
            case LED_NUM_OFF:        //将某个灯点灭掉
                if(num != 3 && num != 4)
                    return -EINVAL;
                else
                    *gpco_data &= ~(0x1 << num);
                break;
            case LED_ALL_ON:        //两个灯同时亮
                *gpco_data |= 0x3<<3;
                break;
            case LED_ALL_OFF:        //两个灯同时灭
                *gpco_data &= ~(0x3<<3);
                break;
            default:
                printk("unknow cmd!
    ");
        }
    
        return 0;
    }
    
    int led_close(struct inode *inode, struct file *filp)
    {
        printk("--------^_^ %s------------
    ",__FUNCTION__);
        //灭灯
            *gpco_data &= ~(0x3<<3);
        return 0;
    }
    
    
    static struct file_operations fops = {
        .open = led_open,
        .write = led_write,
        .unlocked_ioctl = led_ioctl,
        .release = led_close,
    };
    
    
    //加载函数和卸载函数
    static int __init led_init(void)   //加载函数-----在驱动被加载时执行
    {
        int ret;
        printk("--------^_^ %s------------
    ",__FUNCTION__);
        //0,实例化设备对象
        //参数1 ---- 要申请的空间的大小
        //参数2 ---- 申请的空间的标识
        led_dev = kzalloc(sizeof(struct s5pv210_led),GFP_KERNEL);
        if(IS_ERR(led_dev)){
            printk("kzalloc error!
    ");
            ret = PTR_ERR(led_dev);
            return -ENOMEM;
        }
        
        //1,申请设备号
    #if 0
        //静态申请主设备号
        led_dev->major = 256;
        ret = register_chrdev(led_dev->major,"led_drv",&fops);
        if(ret < 0){
            printk("register_chrdev error!
    ");
            return -EINVAL;
        }
    #else
        //动态申请主设备号
        led_dev->major = register_chrdev(0,"led_drv",&fops);
        if(led_dev->major < 0){
            printk("register_chrdev error!
    ");
            ret =  -EINVAL;
            goto err_kfree;
        }
    #endif
    
        //2,创建设备文件-----/dev/led1
        led_dev->cls = class_create(THIS_MODULE,"led_cls");
        if(IS_ERR(led_dev->cls)){
            printk("class_create error!
    ");
            ret = PTR_ERR(led_dev->cls);
            goto err_unregister;
        }
        
        led_dev->dev = device_create(led_dev->cls,NULL,MKDEV(led_dev->major,0),NULL,"led");
        if(IS_ERR(led_dev->dev)){
            printk("device_create error!
    ");
            ret = PTR_ERR(led_dev->dev);
            goto err_class;
        }
    
    
        //3,硬件初始化----地址映射
    
            gpco_conf = ioremap(0xE0200060,8);
            gpco_data = gpco_conf+1;
        
        return 0;
    
    err_class:
        class_destroy(led_dev->cls);
    
    err_unregister:
        unregister_chrdev(led_dev->major,"led_drv");
        
    err_kfree:
        kfree(led_dev);
        return ret;
    
        
    }
    
    static void __exit led_exit(void)   //卸载函数-----在驱动被卸载时执行
    {
        printk("--------^_^ %s------------
    ",__FUNCTION__);
        device_destroy(led_dev->cls,MKDEV(led_dev->major,0));
        class_destroy(led_dev->cls);
        unregister_chrdev(led_dev->major,"led_drv");
        kfree(led_dev);
    }
    
    //声明和认证
    module_init(led_init);
    module_exit(led_exit);
    MODULE_LICENSE("GPL");

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    
    #define LED_NUM_ON        _IOW('L',0x1122,int)
    #define LED_NUM_OFF        _IOW('L',0x3344,int)
    #define LED_ALL_ON        _IO('L',0x1234)
    #define LED_ALL_OFF        _IO('L',0x5678)
    
    
    int main(void)
    {
    
        int fd;
    
        fd = open("/dev/led",O_RDWR);
        if(fd < 0){
        perror("open");
        exit(1);
        }
    
        //闪灯
        while(1){
        //第一个灯闪
        ioctl(fd,LED_NUM_ON,1);
        sleep(1);
        ioctl(fd,LED_NUM_OFF,1);
        sleep(1);
        
        //第二个灯闪
        ioctl(fd,LED_NUM_ON,2);
        sleep(1);
        ioctl(fd,LED_NUM_OFF,2);
        sleep(1);
    
        //两个灯同时闪
        ioctl(fd,LED_ALL_ON);
        sleep(1);
        ioctl(fd,LED_ALL_OFF);
        sleep(1);
    
        }
    
        close(fd);
        return 0;
    }

    #指定内核源码路径
    KERNEL_DIR = /home/farsight/s5pv210/kernel/linux-3.0.8
    CUR_DIR = $(shell pwd)
    MYAPP = test
    
    all:
        #让make进入内核源码编译,同时将当前目录中的c程序作为内核模块一起编译
        make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
        arm-none-linux-gnueabi-gcc -o $(MYAPP) $(MYAPP).c
    
    clean:
        #删除上面编译生成的文件
        make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
        rm -rf $(MYAPP)
    
    install:
        cp *.ko $(MYAPP) /opt/rootfs/drv_module
    
    #指定当前目录下哪个文件作为内核模块编
    obj-m = led_drv.o
    Stay hungry, stay foolish 待续。。。
  • 相关阅读:
    StringBuffer与StringBuilder的区别比较
    JAVA数据结构--快速排序
    JAVA数据结构--优先队列(堆实现)
    JAVA数据结构--哈希表的实现(分离链接法)
    JAVA数据结构--AVL树的实现
    JAVA数据结构--二叉查找树
    JAVA普通内部类的用法
    关于JAVA泛型中的通配符类型
    JAVA泛型方法与类型限定
    Linux进程间通信的几种方式
  • 原文地址:https://www.cnblogs.com/panda-w/p/10991312.html
Copyright © 2020-2023  润新知