• led的驱动及测试程序


    一、驱动源码

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    //#include <asm/irq.h>
    //#include <mach/regs-gpio.h>
    //#include <mach/hardware.h>
    #include <linux/device.h>
    #include <linux/gpio.h>
    #include <linux/miscdevice.h>
    #include <linux/types.h>
    #include <linux/ioctl.h>
    
    #include <linux/cdev.h>
    
    #define led_pin 0
    #define DEVICE_NAME "mydriver"
    //#define DEVICE_NAME "dragino2:red:wlan"
    static int MYDRIVER_Major = 12;
    
    static int mydriver_open(struct inode *inode,struct file *filp)
    {
        printk("My Driver Open Called!
    ");
        return 0;
    }
    
    static int mydriver_release(struct inode *inode,struct file *filp)
    {
        printk("My Driver Release Called!
    ");
        return 0;
    }
    
    static int mydriver_read(struct file *filp,char *buf,size_t count, loff_t *f_pos)
    {
        printk("My Driver Read Called!
    ");
        return 0;
    }
    
    static int mydriver_write(struct file *filp,char *buf,size_t count, loff_t *f_pos)
    {
        printk("My Driver Writet Called!
    ");
        return 0;
    }
    
    static long op_mydriver_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    {
        switch(cmd) {
            case 0:
                gpio_set_value(led_pin, 0);
                break;
            case 1:
                //if (arg > 2) {
                //    return -EINVAL;//判读用户的参数是否有误
                //}
    
                //gpio_set_value(led_pin, !cmd);//用户选定的LED并设置值
                gpio_set_value(led_pin, 1);
                //printk(DEVICE_NAME": %d %d
    ", arg, cmd);
                break;
            default:
                return -EINVAL;
        }
        return 0;
    }
    
    
    
    /*
    static int mydriver_probe()
    {
        printk("My Driver Probe Called!
    ");
    }
    
    static int mydriver_remove()
    {
        printk("My Driver Remove Called!
    ");
    }
    */
    
    //??
    /*
    static struct device_driver  mydriver_driver = {
        //.driver = {
        //    .name        = DEVICE_NAME,
        //    .owner        = THIS_MODULE,
        //},
        .name        = DEVICE_NAME,
        .probe        = mydriver_probe,
        .remove        = mydriver_remove,
    };
    */
    
    
    static struct file_operations mydriver_fops =
    {
        .owner = THIS_MODULE,
        .open = mydriver_open,
        .release = mydriver_release,
        .read = mydriver_read,
        .write =mydriver_write,
        .unlocked_ioctl = op_mydriver_unlocked_ioctl,
    };
    
    static struct miscdevice mydriver_miscdev =
    {
        .minor = MISC_DYNAMIC_MINOR,//由系统自动配置,次设备号
        .name = DEVICE_NAME,
        .fops = &mydriver_fops,
    };
    
    
    
    static int __init mydriver_init(void)
    {
       int ret;
         //ret =  ath79_register_leds_gpio(0,DEVICE_NAME,&mydriver_driver);
        //ret = driver_register(&mydriver_driver);
        ret = gpio_request(led_pin,"LED");//申请IO引脚gpio_request
        //ret = gpio_request_one(led_pin,10,"LED");
        ret = register_chrdev(MYDRIVER_Major, DEVICE_NAME, &mydriver_fops);
        if (ret) {
            printk("request GPIO for led error
    ");
            return ret;
        }
        gpio_direction_output(led_pin, 0);
        //gpio_set_value(led_pin, 1);
        
        
        ret = misc_register(&mydriver_miscdev);//创建设备节点
        if (ret) {
            printk("misc_unregister error
    ");
            return ret;
        }
        printk("MY DRIVER MODULE INIT
    ");
        return 0;//没有这句,那默认返回值是多少?
        
    }
    
    static void __exit mydriver_exit(void)
    {
        int ret;
        
        //gpio_free(led_pin);
        unregister_chrdev(MYDRIVER_Major, DEVICE_NAME);
        ret = misc_deregister(&mydriver_miscdev);
        if (ret) 
        {
            printk("misc_register error
    ");
            return ret;
         }
    
        printk("My DRIVER MODULE EXIT
    ");
    }
    
    module_init(mydriver_init);
    module_exit(mydriver_exit);
    
    MODULE_AUTHOR("www.txmcu.com");
    MODULE_DESCRIPTION("My Driver");
    MODULE_LICENSE("GPL");

    说明:

    1、在驱动初始化及驱动退出函数中,

    static int __init mydriver_init(void){...}

    static void __exit mydriver_exit(void){...}

    双下划线表示模块在内核启动和关闭时自动运行和退出,注意不是单下滑线。

    2、该设备注册用杂项(misc)设备方式进行注册,如果一个字符设备驱动要驱动多个设备,那么它就不应该用misc设备来实现。

    3、led管脚的选择,参考《AR9331.pdf》的第17页,选择led的管脚为LED0即GPIO0,所以

    #define led_pin 0

    该管脚为高电平点亮led灯,低电平为熄灭led灯。

    4、该驱动实现对led的控制是在以下函数中:

    static long op_mydriver_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg){...}

    以下两个函数实现对led管脚设置高低电平:

    gpio_set_value(led_pin, 0);

    gpio_set_value(led_pin, 1);

    5、初始化要return 0,否则加载驱动时,会输出很多乱起八糟的东西。

    二、驱动编译

    1、Kconfig文件的书写

    config DRIVER-MODEL
        tristate "Custom GPIO-based led driver"
        depends on GENERIC_GPIO
        select SPI_GPIO //this option would also be choosed
        help
          This is an led driver to register 1 
          GPIO lines. 
          The devices will be exposed to userspace as /dev/spidevX.X
          
          This module is maily intended to interface microcontrollers
          and other led devices without a specific kernel driver.
    
          This support is also available as a module.

    2、Makefile文件

    obj-${CONFIG_DRIVER_MODEL}    += driver-model.o
    #obj-m += driver-model.o

    说明:

    其中${CONFIG_DRIVER_MODEL}看作一个整体,一个变量,其值是由上级目录的Makefile文件确定。

    3、上级Makefile文件

    #
    # Copyright (C) 2008 OpenWrt.org
    #
    # This is free software, licensed under the GNU General Public License v2.
    # See /LICENSE for more information.
    #
    
    include $(TOPDIR)/rules.mk
    include $(INCLUDE_DIR)/kernel.mk
    
    PKG_NAME:=driver-model
    PKG_RELEASE:=1
    
    include $(INCLUDE_DIR)/package.mk
    
    define KernelPackage/driver-model
      SUBMENU:=LED modules
      TITLE:=gpio control led
    #  DEPENDS:=@GPIO_SUPPORT +kmod-spi-bitbang +kmod-spi-gpio
      DEPENDS:=@GPIO_SUPPORT
      FILES:=$(PKG_BUILD_DIR)/driver-model.ko
    #  KCONFIG:=CONFIG_DRIVER_MODEL=m 
    #      CONFIG_SPI_BITBANG=y
      KCONFIG:=
      AUTOLOAD:=$(call AutoLoad,50,driver-model,1)
    endef
    
    define KernelPackage/driver-model/description
      Kernel module for control a led.
    endef
    
    EXTRA_KCONFIG:= 
        CONFIG_DRIVER_MODEL=m
    
    EXTRA_CFLAGS:= 
        $(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) 
        $(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG)))) 
    
    MAKE_OPTS:= 
        ARCH="$(LINUX_KARCH)" 
        CROSS_COMPILE="$(TARGET_CROSS)" 
        SUBDIRS="$(PKG_BUILD_DIR)" 
        EXTRA_CFLAGS="$(EXTRA_CFLAGS)" 
        $(EXTRA_KCONFIG)
    
    define Build/Prepare
        mkdir -p $(PKG_BUILD_DIR)
        $(CP) ./src/* $(PKG_BUILD_DIR)/
    endef
    
    define Build/Compile
        $(MAKE) -C "$(LINUX_DIR)" 
            $(MAKE_OPTS) 
            modules
    endef
    
    $(eval $(call KernelPackage,driver-model))

    说明:

    AUTOLOAD:=$(call AutoLoad,50,driver-model,1)当把驱动编译进内核,即选择Y时,该函数实现开机自动安装驱动。

    4、make menuconfig

    clip_image002

    选中kmod-driver-model。

    三、测试源码

    #include <stdio.h>
    #include <unistd.h>
    
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #include <linux/ioctl.h>
    
    /*
    int main(int argc, char **argv)
    {
    int fd;
    char i;
    //char buff[1024];
    fd = open("/dev/mydriver", O_RDWR);
    if (fd < 0) {
        perror("open");
        return 1;
    }
    printf("open success!
    ");
    for(i=5;i>0;i--)
    {
    ioctl(fd,1,1);
    sleep(1);
    ioctl(fd,0,1);
    sleep(1);
    }
    close(fd);
    return 0;
    }
    */
    
    
    int main(int argc, char **argv)
    {
            int on;
            int led_no;
            int fd;
    
            if(argc != 3 ||sscanf(argv[1],"%d",&led_no) !=1 ||
                           sscanf(argv[2],"%d",&on) !=1 ||
                    on < 0 || on > 1 || led_no <0 || led_no>3)
            {
                    fprintf(stderr,"Usage:led led_no 0|1
    ");
                    exit(1);
            }
    
            //打开/dev/leds0设备文件
           fd = open("/dev/mydriver",0);
           if(fd <0 )
           {
                    perror("/dev/mydriver");
                    exit(1);
           }
    
           //通过系统调用ioctl和输入的参数控制led
     if(led_no ==0)//第一个参数为功能选择,0为手动控制功能;第二个参数为控制灭还是亮;
    {     
        ioctl(fd,on,led_no);
    }
    else//第一个参数为功能选择,1为自动控制功能;
    {
        while(1)
        {
        ioctl(fd,1,led_no);
        usleep(500000);
        ioctl(fd,0,led_no);
        usleep(500000);
        }
    }
          
           //关闭设备句柄
           close(fd);
           return 0;
    }

    说明:

    1、该测试程序需要外部输入两个参数;

    2、usleep的最大值不能超过1000000。

    四、应用程序编译

    1、Makefile文件

    all: led
    
    led: led.c
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
    
    clean:
        rm -f led

    2、上级目录的Makefile文件

    #
    # Copyright (C) 2010-2012 OpenWrt.org
    #
    # This is free software, licensed under the GNU General Public License v2.
    # See /LICENSE for more information.
    #
    
    include $(TOPDIR)/rules.mk
    
    PKG_NAME:=led
    PKG_VERSION:=1
    PKG_RELEASE:=1
    
    include $(INCLUDE_DIR)/package.mk
    
    define Package/led
      SECTION:=utils
      CATEGORY:=Utilities
      TITLE:=led 
      MAINTAINER:=tingpan
      PKGARCH:=all
    endef
    
    define Package/led/description
        led world!
    endef
    
    define Build/Prepare
        mkdir -p $(PKG_BUILD_DIR)
        $(CP) ./src/* $(PKG_BUILD_DIR)/
    endef
    
    define Build/Configure
    endef
    
    define Build/Compile
        $(MAKE) -C $(PKG_BUILD_DIR) 
            CC="$(TARGET_CC)" 
            CFLAGS="$(TARGET_CFLAGS) -Wall" 
            LDFLAGS="$(TARGET_LDFLAGS)"
    endef
    
    define Package/led/install
        $(INSTALL_DIR) $(1)/usr/sbin
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/led $(1)/usr/sbin/
    endef
    
    $(eval $(call BuildPackage,led))

    五、烧写固件及测试

    1、烧写固件

    (1)连接串口、网线;

    (2)打开SecureCRT ,两秒内按下键盘任意键,输入http

    (3)打开浏览器,输入192.168.0.250

    (4)开始刷机,自动重启。

    2、查看驱动

    在终端输入lsmod,存在driver-model的驱动,也可以进入dev文件查看存在mydriver设备。

    3、测试代码进行测试

    (1)led 0 1开启led灯

    (2)led 0 0 关闭led灯

    (3)led 1 0或led 1 1 实现led每秒闪一次

    (4)如果要实现开机启动,可在网页中进行设置,

    clip_image002[4]

    a、查看进程

    clip_image004

    b、杀死进程(这样才能手动控制,否则一直在后台运行,没法结束)

    clip_image006

    4、测试

    应用程序return 0 或中断执行会执行release函数。

    补充:开机启动

    可以再etc文件夹中添加,如果是系统服务加入init.d文件夹下,写入名字就好;

    如果是自己编写的应用程序,或需要网络启动后再启动,可以再rc.local文件中添加。

    可在makefile中添加:

    $(INSTALL_DIR) $(1)/usr/sbin
    $(INSTALL_DIR) $(1)/etc/config
    $(CP) ./files/scws $(1)/etc/config/
    $(INSTALL_BIN) $(PKG_BUILD_DIR)/scws $(1)/usr/sbin/ 

    相关源码下载地址:

    http://pan.baidu.com/s/1sDikY

  • 相关阅读:
    Python 正则表达式匹配两个指定字符串中间的内容
    Switch Case 和 If Else
    MYSQL LETT/RIGHT/INNER/FUll JOIN 注意事项
    MYSQL 批处理 Packet for query is too large
    Junit单元测试不支持多线程
    postman中 form-data、x-www-form-urlencoded、raw、binary的区别
    一个项目中:只能存在一个 WebMvcConfigurationSupport (添加swagger坑)
    Nginx 转发特点URL到指定服务
    基于UDP协议的程序设计
    TcpClient类与TcpListener类
  • 原文地址:https://www.cnblogs.com/smbx-ztbz/p/4418404.html
Copyright © 2020-2023  润新知