编制第一个widora-neo驱动



  • 对Widora-OpenWRT的兴致依旧不减,这两天学习了一下《openwrt入门经典教程》,同时参考网上的教程来编制了一个驱动程序。在此记录下步骤,以备将来复习。

    1. 建立驱动文件对应的目录和相关配置文件
    1.1首先在ubuntu的widora开发环境目录~/openwrt_widora/package/kernel 下建立一个名称为midas-driver的目录,再在midas-driver目录下建立一个名称为src的子目录。
    1.2 然后从midas-driver的同级目录spi-gpio-custom(其他的也可以)中复制Makefile文件到midas-driver目录下。
    1.3 再从 …/spi-gpio-custom/src 目录下同样复制Makefile到…/midas-driver/src目录下。
    1.4 最后将…/spi-gpio-custom/src 目录下的Kconfig文件复制到…/midas-driver/src目录下。

    2. 建立和修改驱动文件模板
    2.1 复制驱动模板文件demo.c 0_1478323686741_demo.c 到 …midas-driver/src 目录下。 驱动模板文件Demo.c的具体内容和函数功能可以在网上找到相关说明。 我就当它是套路,按照它的套路一步步来走。
    2.2 接下来修改demo.c,将文件名称改为midas-driver.c。接着把midas-driver.c源文件中的“xxx”字符串全部替换成“midas_driver”。用nano编辑的话非常方便,按下Ctrl+\键,提示Search(to replace): 输入 xxx 回车, 提示Replace with: 输入 midas_driver 回车。(我开始时把xxx替换成了midas-driver,结果编译的时候一大堆错误! C语言中的变量名千万不能用”-“,因为它同时也是减号 。C语言基础不好,幸好及时发现.)
    保存下文件,驱动程序的其他部分先不动,后来再增加吧,第一步先熟悉下套路。

    3. 修改Makefile 文件内容
    3.1 修改 …/midas-driver/Makefile 文件,注意红色标记处是修改过的.这只不过是套路.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:=midas-driver
    PKG_RELEASE:=1

    include $(INCLUDE_DIR)/package.mk

    define KernelPackage/midas-driver
    SUBMENU:=Other modules
    TITLE:=midas-driver
    FILES:=$(PKG_BUILD_DIR)/midas-driver.ko
    KCONFIG:=
    endef

    define KernelPackage/midas-driver/description
    midas-driver, for test only.
    endef

    EXTRA_KCONFIG:=
    CONFIG_MIDAS-DRIVER=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,midas-driver))

    3.2 修改…/midas-driver/src/Makefile 文件,内容很简单.注意红色标记处是修改过的.
    obj-$(CONFIG_MIDAS-DRIVER)+= midas-driver.o

    3.3 修改…/midas-driver/src/Kconfig 文件, 注意红色标记处是修改过的,同时删除了其他的语句.
    config MIDAS-DRIVER
    tristate "Midas-driver"
    default m
    help
    This is a test for midas-driver

    4. make menuconfig 选中对应的驱动
    回到 ~/openwrt_widora目录,执行 make menuconfig
    依次选中 kernel modules --> other modules --> kmod-midas-driver ( 用空格键选成M,表示编译成单独模块),然后保存退出。
    0_1478323406091_module-configure.JPG
    显然,midas-driver 在menu中的位置和选项是前面的Makerfile和Kconfig文件中配置好的.

    5. 编译生成ipk文件
    在 ~/openwrt_widora目录执行 make package/kernel/midas-driver/compile V=99
    没有错误的话会在 ~/openwrt_widora/bin/ramips/packages/base目录下生成 kmod-midas-driver_3.18.29-1_ramips_24kec.ipk文件。

    6. 安装和卸载驱动
    6.1 将上面的文件传到widora中,执行 opkg install kmod-midas-driver_3.18.29-1_ramips_24kec.ipk 安装驱动.
    安装完成后会在 /lib/modules/3.18.29 目录下生成 midas-driver.ko 驱动文件.
    6.2 接下来就可以加载驱动了,执行命令: insmod midas-driver.ko
    如果我们没有通过串口来连接widora, 终端不会出现任何加载成功的提示. 没关系用dmesg|tail命令就可以看到:
    [593416.020000] midas_driver drive init...
    [593416.020000] The drive info of midas_driver:
    [593416.020000] major: 252
    [593416.020000] minor: 0
    [593416.030000] auto mknod success!
    [593416.040000] midas_driver init success!
    对照一下前面的midas-driver.c驱动程序,我们可以找到相应的打印命令.

    驱动加载成功后可以看到在 /dev 目录下增加了设备 midas_driver

    6.3 卸载驱动,执行命令:rmmod midas-driver.ko
    [593759.920000] midas_driver drive exit...
    [593759.930000] free your resources...
    [593759.930000] free finish


    套路知道了,接下来准备在midas-driver.c驱动程序中加点料了….


  • administrators

    Well done!



  • @midas-zhou
    ------------------ 添加LED驱动 --------------
    接下来,我们在GPIO17脚接上一个LED, 为这个LED做一个驱动程序。

    1. 首先,需要了解与GPIO17设置相关的寄存器,主要有下面几个:
    1.1 根据手册,GPIO#14~#17脚是与SPI-SLAVE是功能复用的。需要通过设置APGIO_CFG[20:17] (1111) 和 GPIO1_MODE[3:2] (01)来设置其为GPIO功能。
    0_1478488754387_upload-2e42c5d7-5e63-47f8-87b2-f77c6c7cc6ff
    1.2 通过设置GPIO_CTRL_0 [17]为1将 GPIO17设置为输出模式。
    1.3 通过设置GPIO_DATA_0 [17]为0或1 将 GPIO17输出设置为0或1。

    2. 在midas-driver.c中增加如下代码
    2.1 定义相关寄存器
    volatile unsigned long *GPIO_CTRL_0;// GPIO0-GPIO31 direction control register
    volatile unsigned long *GPIO_DATA_0;// GPIO0-GPIO31 data register
    volatile unsigned long *GPIO1_MODE; // GPIO1 purpose selection register
    volatile unsigned long *AGPIO_CFG; // analog GPIO configuartion,GPIO14-17 purpose

    2.2 驱动打开初始化,见粗体部分。
    static int midas_driver_open(struct inode *inode, struct file *file)
    {
    printk("midas_driver drive open...,LED pin set to 0 \n");
    *GPIO_DATA_0 &=~(1<<17);//-----------set GPIO17 as 0
    return 0;
    }

    2.3 ioctl 函数中增加on 和off 命令
    static int midas_driver_ioctl (struct file *filp , unsigned int cmd , unsigned long arg)
    {
    int ret_v = 0;
    printk("midas_driver drive ioctl...\n");
    switch(cmd)
    {
    case MYLED_ON:
    *GPIO_DATA_0 |= (1<<17); //------------------set GPIO17 as 1
    break;
    case MYLED_OFF:
    *GPIO_DATA_0 &=~(1<<17); //-----------set GPIO17 as 0
    break;
    case _IOW(IOW_CHAR,IOW_NUM1,IOW_TYPE):
    {
    if(arg == 0x1)
    {
    }
    }
    break;
    default:
    break;
    }
    return ret_v;
    }

    2.4 在驱动初始化部分增加相关寄存器的配置 。
    static __init int midas_driver_init(void)
    {
    ……
    //---------- init register address -----------
    AGPIO_CFG=(volatile unsigned long *)ioremap(0x1000003c,4);
    GPIO1_MODE=(volatile unsigned long *)ioremap(0x10000060,4);
    GPIO_CTRL_0=(volatile unsigned long *)ioremap(0x10000600,4);
    GPIO_DATA_0=(volatile unsigned long *)ioremap(0x10000620,4);
    //---------------------- set value ----------------------------------
    *AGPIO_CFG |= (0b1111<<17);//--------set AGPIO_CFG[20:17] as 1111
    *GPIO1_MODE & =~(1<<3); //-------- set SPIS purpose as GPIO17
    *GPIO1_MODE | =(1<<2);
    *GPIO_CTRL_0 | =(1<<17); //-------- set GPIO17 as output pin
    ……
    }

    2.5 最后在驱动退出函数中增加释放内存映射部分 ,见粗体部分。
    static __exit void midas_driver_exit(void)
    {
    …….
    iounmap(AGPIO_CFG); //-----------------release ioremap resource
    iounmap(GPIO1_MODE);
    iounmap(GPIO_CTRL_0);
    iounmap(GPIO_DATA_0);

    …….
    }

    最后改成这样:0_1478488850162_midas-driver.c

    正常的话可以通过编译生成相应的安装ipk文件.



  • ------------- 打开并操作设备 -------------

    安装并载入驱动后,编制一个小程序来测试一下这个驱动:

    /-------------- myled.c -----------------------
    myled on --- turn on the LED
    myled off --- turn off the LED
    -------------------------------------
    /
    #include <stdio.h>
    #include <string.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h> //-----??
    #include <sys/ioctl.h>

    #define MYLED_ON 1
    #define MYLED_OFF 0

    char str_dev[]="/dev/midas_driver";

    int main(int argc,char* argv[])
    {
    int fd;

    if(argc!=2)
    {
    printf(" %s <on|off> to turn on or off LED on GPIO17\n",argv[0]);
    return -1;
    }

    fd=open(str_dev,O_RDWR|O_NONBLOCK); //--- GPIO17 will set to 0 when open
    if(fd<0)
    {
    printf("can't open %s \n",str_dev);
    return -1;
    }

    if(!strcmp("on",argv[1]))
    {
    while(1)
    {
    ioctl(fd,MYLED_ON);
    usleep(50000);
    ioctl(fd,MYLED_OFF);
    usleep(50000);
    }
    }
    else if(!strcmp("off",argv[1]))
    ioctl(fd,MYLED_OFF);
    else
    {
    printf(" %s <on|off> to turn on or off LED on GPIO17\n",argv[0]);
    return -1;
    }

    return 0;

    }

    编译后试验 myled on LED灯闪了~ 成功! myled off LED灯灭.

    0_1478498696983_myled.JPG



  • 在.../midas-driver/Makefile文件中添加一句代码(加粗部分),同时make menuconfig是选择“*”,则可以在编译固件并烧写程序之后,自动加载驱动

    define KernelPackage/midas-driver
    SUBMENU:=Other modules
    TITLE:=midas-driver
    FILES:=$(PKG_BUILD_DIR)/midas-driver.ko
    KCONFIG:=
    AUTOLOAD:=$(call AutoLoad,81,midas-driver) #系统启动时自动装载
    endef



  • 你好,能发个历程吗?GPIO的,新手,谢谢,这里边文件打不开了,几个关键地方过不去了,比如demo.c我就没找到,谢谢



  • @于大圣 上面都是参考了《openwrt入门经典教程》,里面有具体步骤说明。



  • @midas-zhou SUBMENU:= Other modules 这个地方要标红色的,不然会在Make menuconfig 中找不到标签



  • @midas-zhou 记得配置完需要要全编译,不全编译不行,make会提示缺少文件