(4) led驱动--分层设计-添加具体硬件控制

1.led硬件控制独立层

//led_opr.h
 
#ifndef _LED_OPR_H
#define _LED_OPR_H
 
struct led_operations{
	int (*init)(int which);//初始化LED
	int (*ctl)(int which, char status);//控制亮(1)灭(0)
};
 
struct led_operations *get_board_led_opr(void);
 
#endif
//board_100ask_imx6ull.c

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <asm/io.h>

#include "led_opr.h"

static volatile unsigned int *CCM_CCGR1;								//使能
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;	//设置为GPIO模式
static volatile unsigned int *GPIO5_GDIR;								//设置方向(输入/输出)
static volatile unsigned int *GPIO5_DR;									//设置值(高/低)

static int board_demo_led_init(int which)
{
	unsigned int val;
	
	if(which == 0)
	{
		if(!CCM_CCGR1)
		{
			CCM_CCGR1	= ioremap(0x20C406C,4);
			IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x2290014,4);
			GPIO5_GDIR	= ioremap(0x020AC000+0x4,4);
			GPIO5_DR	= ioremap(0x020AC000,4);
		}
		
		CCM_CCGR1 |= (3<<30);
		
		val = *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
		val &= ~0xf;
		val |= 5;
		*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = val;
		
		*GPIO5_GDIR |= (1<<3);//输出
	}
	return 0;
}

static int board_demo_led_ctl(int which,char status)
{
	if(which == 0)
	{
		if(status)
		{
			*GPIO5_DR &= ~(1<<3);//输出低电平
		}
		else
		{
			*GPIO5_DR |= (1<<3);//输出高电平
		}
	}
}
static struct led_operations board_demo_led_opr = {
	.num	= 1,
	.init	= board_demo_led_init,
	.ctl	= board_demo_led_ctl,
};

struct led_operations *get_board_led_opr(void)
{
	return &board_demo_led_opr;
}

2.led驱动框架部分

//leddrv.c

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
 
#include "led_opr.h"
 
#define LED_NUM 	2
 
static int major = 0;
static struct class *led_class;
struct led_operations *p_led_opr;
 
#define MIN(a,b) (a < b) (a < b ? a : b)
 
static ssize_t led_drv_read(struct file *file,char __user *buf,size_t size,loff_t *offset)
{
	printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
	return 0;
}
 
static ssize_t led_drv_write(struct file *file,const char __user *buf,size_t size,loff_t *offset)
{
	int err;
	char status;
	struct inode *inode = file_inode(file);
	int minor = iminor(inode);
	
	printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
	err = copy_from_user(&stauts,buf,1);
	
	//根据次设备号和status控制LED
	p_led_opr->ctl(minor,status);
	
	return 1;
}
 
static int led_drv_open(struct inode *node,struct file *file)
{
	int minor = iminor(node);
	printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
	//根据此设备号初始化LED
	p_led_opr->init(minor);
	return 0;
}
 
static int led_drv_close(struct inode *node,struct file *file)
{
	printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
	return 0;
}
 
static struct file_operations led_drv = {
	.owner		= THIS_MODULE,
	.open		= led_drv_open,
	.read		= led_drv_read,
	.write		= led_drv_write,
	.release	= led_drv_close,
};
 
static int __init led_init(void)
{
	int err;
	int i;
	
	printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
	major = register_chrdev(0,"100ask_led",&led_drv);
	
	led_class = class_create(THIS_MODULE,"100ask_led_class");
	err = PTR_ERR(led_class);
	if(IS_ERR(led_class)){
		printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
		unregister_chrdev(major,"100ask_led");
		return -1;
	}
	
	for(i=0;i<LED_NUM;i++)
	{
		device_create(led_class,NULL,MKDEV(major,i),NULL,"100ask_led%d",i);
	}
	p_led_opr = get_board_led_opr();
	
	return 0;
}
 
static void __exit led_exit(void)
{
	int i;
	prink("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
	
	for(i=0;i<LED_NUM;I++)
	{
		device_destory(led_class,MKDEV(major,i));
	}
	
	class_destory(led_class);
	unregister_chrdev(major,"100ask_led");
}
 
module_init(led_init);
module_exit(led_exit);
 
MODULE_LICENSE("GPL");

3.应用例程 

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
 
/*
 * ./ledtest /dev/100ask_led0 on
 * ./ledtest /dev/100ask_led0 off
 */
int main(int argc, char **argv)
{
	int fd;
	char status;
	
	/* 1. 判断参数 */
	if (argc != 3) 
	{
		printf("Usage: %s <dev> <on | off>\n", argv[0]);
		return -1;
	}
 
	/* 2. 打开文件 */
	fd = open(argv[1], O_RDWR);
	if (fd == -1)
	{
		printf("can not open file %s\n", argv[1]);
		return -1;
	}
 
	/* 3. 写文件 */
	if (0 == strcmp(argv[2], "on"))
	{
		status = 1;
		write(fd, &status, 1);
	}
	else
	{
		status = 0;
		write(fd, &status, 1);
	}
	
	close(fd);
	
	return 0;
}

4.Makefile 

# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH,          比如: export ARCH=arm
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
# 2.3 PATH,          比如: export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin
 
 
# 参考内核源码drivers/char/ipmi/Makefile
# 要想把a.c, b.c编译成ab.ko, 可以这样指定:
# ab-y := a.o b.o
# obj-m += ab.o
 
 
KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88
 
all:
	make -C $(KERN_DIR) M=`pwd` modules
	$(CROSS_COMPILE)gcc -o ledtest ledtest.c
	
clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order
	rm -f ledtest
	
100ask_led-y := leddrv.o board_100ask_imx6ull.o
obj-m += 100ask_led.o

5.执行结果 

此笔记为学习韦东山老师教程的记录

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值