编制第一个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 © 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驱动程序中加点料了….

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

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

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

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

在…/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

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

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

/-------------- 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-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文件.

Well done!