led的驱动及测试程序

时间:2021-04-02 03:33:50

一、驱动源码

#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 = ; static int mydriver_open(struct inode *inode,struct file *filp)
{
printk("My Driver Open Called!\n");
return ;
} static int mydriver_release(struct inode *inode,struct file *filp)
{
printk("My Driver Release Called!\n");
return ;
} static int mydriver_read(struct file *filp,char *buf,size_t count, loff_t *f_pos)
{
printk("My Driver Read Called!\n");
return ;
} static int mydriver_write(struct file *filp,char *buf,size_t count, loff_t *f_pos)
{
printk("My Driver Writet Called!\n");
return ;
} static long op_mydriver_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case :
gpio_set_value(led_pin, );
break;
case :
//if (arg > 2) {
// return -EINVAL;//判读用户的参数是否有误
//} //gpio_set_value(led_pin, !cmd);//用户选定的LED并设置值
gpio_set_value(led_pin, );
//printk(DEVICE_NAME": %d %d\n", arg, cmd);
break;
default:
return -EINVAL;
}
return ;
} /*
static int mydriver_probe()
{
printk("My Driver Probe Called!\n");
} static int mydriver_remove()
{
printk("My Driver Remove Called!\n");
}
*/ //??
/*
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\n");
return ret;
}
gpio_direction_output(led_pin, );
//gpio_set_value(led_pin, 1); ret = misc_register(&mydriver_miscdev);//创建设备节点
if (ret) {
printk("misc_unregister error\n");
return ret;
}
printk("MY DRIVER MODULE INIT\n");
return ;//没有这句,那默认返回值是多少? } 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\n");
return ret;
} printk("My DRIVER MODULE EXIT\n");
} 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
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) 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:= 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,,driver-model,)
endef define KernelPackage/driver-model/description
Kernel module for control a led.
endef EXTRA_KCONFIG:= \
CONFIG_DRIVER_MODEL=m EXTRA_CFLAGS:= \
$(patsubst CONFIG_%, -DCONFIG_%=, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \
$(patsubst CONFIG_%, -DCONFIG_%=, $(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

led的驱动及测试程序

选中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!\n");
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 != ||sscanf(argv[],"%d",&led_no) != ||
sscanf(argv[],"%d",&on) != ||
on < || on > || led_no < || led_no>)
{
fprintf(stderr,"Usage:led led_no 0|1\n");
exit();
} //打开/dev/leds0设备文件
fd = open("/dev/mydriver",);
if(fd < )
{
perror("/dev/mydriver");
exit();
} //通过系统调用ioctl和输入的参数控制led
if(led_no ==)//第一个参数为功能选择,0为手动控制功能;第二个参数为控制灭还是亮;
{
ioctl(fd,on,led_no);
}
else//第一个参数为功能选择,1为自动控制功能;
{
while()
{
ioctl(fd,,led_no);
usleep();
ioctl(fd,,led_no);
usleep();
}
} //关闭设备句柄
close(fd);
return ;
}

说明:

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

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

四、应用程序编译

1、Makefile文件

all: led

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

2、上级目录的Makefile文件

#
# Copyright (C) - 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:=
PKG_RELEASE:= 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) $()/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/led $()/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)如果要实现开机启动,可在网页中进行设置,

led的驱动及测试程序

a、查看进程

led的驱动及测试程序

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

led的驱动及测试程序

4、测试

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

补充:开机启动

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

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

可在makefile中添加:

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

相关源码下载地址:

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