• LINUX字符型设备驱动 三.LED驱动


    1.LED.c

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include <linux/device.h>
    #include <linux/io.h>
    #include <linux/uaccess.h>
    
    static int major = 99;
    static int minor = 0;
    static dev_t devno;
    static struct class *cls;
    static struct device *test_device;
    
    #define PB_CFG 0x01c20824 //PB口控制寄存器
    #define PB_DAT 0x01c20834 //PB口数据寄存器
    #define DEVICE_MINOR_NUM 2
    #define DEVICE_NAME "led"
    
    static int *PBcfg;
    static int *PBdat;
    
    void fs4412_led_off(int num) //关灯
    {
        switch (num)//这里只要将管脚对应的位置1即可如pb4 那么或上0001 0000即可
        {
        case 1:
            iowrite32(ioread32(PBdat) | (1<<4),PBdat);//置高关灯
            break;
        case 2:
            iowrite32(ioread32(PBdat) | (1<<5),PBdat);  
            break;
        default:
            break;
        }
    }
    
    void fs4412_led_on(int num) //开灯程序
    {
        switch (num)//这里只要将管脚对应的位置0即可如pb4 那么与上1110 1111即可
        {
        case 1:
            iowrite32(ioread32(PBdat) &(~(1<<4)),PBdat);//置低开灯
            break;
        case 2:
            iowrite32(ioread32(PBdat) &(~(1<<5)),PBdat);//置低开灯
            break;
        default:
            fs4412_led_off(1);//如果输入错误那么都关灯
            fs4412_led_off(2);
            break;
        }
    }
    
    static int led_open(struct inode *inode, struct file *filep)//文件打开时默认都关灯
    { //open
        fs4412_led_off(1);
        fs4412_led_off(2);
        return 0;
    }
    
    static int led_release(struct inode *inode, struct file *filep)//文件关闭时默认都关灯
    { //close
        fs4412_led_off(1);
        fs4412_led_off(2);
        return 0;
    }
    
    static ssize_t led_read(struct file *filep, char __user *buf, size_t len, loff_t *pos)
    {
        return 0;
    }
    
    static ssize_t led_write(struct file *filep, const char __user *buf, size_t len, loff_t *pos)
    {
        int led_num;
    
        if (len != 4)
        {
            return -EINVAL;
        }
        if (copy_from_user(&led_num, buf, len))
        {
            return -EFAULT;
        }
    
        fs4412_led_on(led_num);
        //printk(KERN_INFO "led_num =%d 
    ", led_num);
        return 0;
    }
    
    static struct file_operations hello_ops =
        {
            .open = led_open,
            .release = led_release,//当执行close()函数时会调用release()
            .read = led_read,
            .write = led_write,
    };
    
    static void fs4412_led_init(void)
    {
        PBcfg = ioremap(PB_CFG, 4); //映射到物理地址
        PBdat = ioremap(PB_DAT, 4);
        //配置io口为输出模式   //先左移12位取反得 FFFF0FFF 相与 再或上 0x1<<12  ioread32就是调用readl
        writel((ioread32(PBcfg) & ~(7 << 16)) | (1 << 16), PBcfg); //PB4 设定out
        writel((ioread32(PBcfg) & ~(7 << 20)) | (1 << 20), PBcfg); //PB5 设定out
    }
    
    static int led_init(void)
    {
        int ret;
        if (major)//静态申请方法
        {
            devno = MKDEV(major, minor);
            ret = register_chrdev(major,DEVICE_NAME, &hello_ops);//
        }
        else//动态申请方法
        {
            ret=alloc_chrdev_region(&devno,minor,DEVICE_MINOR_NUM,DEVICE_NAME);//这个好像还没有添加file_operation
            major=MAJOR(devno);
            minor=MINOR(devno);
            ret = register_chrdev(major,DEVICE_NAME, &hello_ops);
            printk(KERN_INFO "alloc region %d 
    ",major);
        }
        cls = class_create(THIS_MODULE, "myclass");//创建类
        if (IS_ERR(cls))
        {
            unregister_chrdev(major, DEVICE_NAME);
            printk(KERN_ERR "class create failed 
    ");
            return -EBUSY;
        }
        printk(KERN_INFO "class create successs 
    ");
        //创建设备节点
        test_device = device_create(cls, NULL, devno, NULL, DEVICE_NAME); //mknod /dev/led
        if (IS_ERR(test_device))
        {
            class_destroy(cls);
            unregister_chrdev(major,DEVICE_NAME);
            printk(KERN_ERR "create /dev/led failed 
    ");
            return -EBUSY;
        }
        printk(KERN_INFO "create /dev/led successs 
    ");
        fs4412_led_init(); //初始化io
        return 0;
    }
    
    void fs4412_led_unmap(void)//内存取消映射
    {
        iounmap(PBcfg);
        iounmap(PBdat);
    }
    
    static void led_exit(void)
    {
        fs4412_led_unmap();//先取消映射
        device_destroy(cls, devno);
        class_destroy(cls);
        unregister_chrdev(major,DEVICE_NAME);
        printk(KERN_INFO "led_exit
    ");
    }
    
    MODULE_AUTHOR("Zheng qihang <zqh18268832867@gmail.com>");
    MODULE_DESCRIPTION("LED driver for V3s controllers");
    MODULE_LICENSE("GPL v2");
    MODULE_ALIAS("module:leds-V3s");
    module_init(led_init);
    module_exit(led_exit);

    2.main.c

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    int main(void)
    {
        int led_fd,i,lednum;
        led_fd=open("/dev/led",O_RDWR);
        if(led_fd<0)
        {
            perror("open failed!
    ");
            return -1;
        }
        for(i=0;i<10;i++)//循环10次
        {
            lednum=0;
            write(led_fd,&lednum,sizeof(int));
            lednum=i%2+1;
            write(led_fd,&lednum,sizeof(int));
            sleep(1);
        }
        close(led_fd);
        return 0;
    }

    3.Makefile

    #General Purpose Makefile for cross compile Linux Kernel module
    ifneq ($(KERNELRELEASE),)
    
    obj-m := led.o  #+=是连接字符串
    
    else
    
    OBJ := led
    ARCH := arm    
    CROSS_COMPILE := /usr/local/arm/arm-linux-gnueabihf-4.9/bin/arm-linux-gnueabihf-
    KERN_DIR := /home/zqh/lichee/linux-zero-4.14.y  #选择内核路径
    SOURCE := main.c
    TARGET := test_led
    PWD =$(shell pwd)  #当前路径
    FILE_PWD=$(strip $(PWD))
    LICHEDIR := /root/led_driver/
    all:
            make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERN_DIR) M=$(PWD) modules
            $(CROSS_COMPILE)gcc $(SOURCE) -o $(TARGET)
    .PHONY : clean   
    clean :                                
            rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order .*.o.ko.cmd .*.ko.cmd .*.mod.o.cmd .*.o.cmd $(TARGET)        
    install:
            scp $(FILE_PWD)/$(OBJ).ko root@172.24.41.12:$(LICHEDIR)
            scp $(FILE_PWD)/$(TARGET) root@172.24.41.12:$(LICHEDIR)
    endif
  • 相关阅读:
    asp读书笔记(二)内置对象
    网上收集的关于iframe的自适应高度代码js的
    第一遇到地震,虽然小点
    给网友写的控制页面元素高度的代码(js)
    给用户控件添加可枚举的属性
    标记(Tagging)能给网站带来的7大益处
    代码最重要的读者不再是编译器、解释器或者电脑,而是人!
    亚洲超大数据库会议(XLDB Asia 2012)
    每年15万美元!这是开发人员解决构造问题的总成本!
    华章IT图书书讯(2012年第7期)
  • 原文地址:https://www.cnblogs.com/ZQQH/p/8681917.html
Copyright © 2020-2023  润新知