代码改变世界

linux驱动之LED驱动_1

2017-06-16 10:01  tlnshuju  阅读(209)  评论(0编辑  收藏  举报

步骤:

1、框架

2、完好硬件的操作:

    a.看原理图、引脚

    b.看2440手冊

    c.写代码: IO口须要用ioremap映射

我的板子电路例如以下所看到的


1、配置GPBCON 寄存器,配置输出   在open函数中去配置

2、配置GPBDAT 寄存器                        在write函数中去配置

#########################################################################

手冊资料:

GPBCON 寄存器的物理地址为:0x56000010

GPBDAT  寄存器的物理地址为:0x56000014

#########################################################################

1、首先声明全局变量:

volatile unsigned long *gpbcon = NULL;
volatile unsigned long *gpbdat = NULL;

2、在入口函数中对引脚进行映射

/*映射物理地址*/
	gpbcon = (volatile unsigned long *) ioremap(0x56000010,16);
	gpbdat = gpbcon + 1;
3、在出口函数中取消映射

iounmap(gpbcon);

4、在open函数中将引脚设置为输出

	/*配置 GPB 5 6 7 8为输出*/
	*gpbcon &=~((0x3<<(5*2))|(0x3<<(6*2))|(0x3<<(7*2))|(0x3<<(8*2)));//先清零
	*gpbcon |=((0x1<<(5*2))|(0x1<<(6*2))|(0x1<<(7*2))|(0x1<<(8*2)));// 配置为1 (输出)

5、在写函数中对用户空间数据进行简单处理

	int val;
	copy_from_user(&val,buf,count);//从用户空间向内核空间拷贝数据
	if(val == 1)
	{
		//点灯
		*gpbdat &=~((1<<5)|(1<<6)|(1<<7)|(1<<8));
	}
	else
	{
		//灭灯
		*gpbdat|=(1<<5)|(1<<6)|(1<<7)|(1<<8);
	}

完整的驱动代码例如以下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/uaccess.h>

static struct class *firstdrv_class;
static struct class_devices *firstdrv_class_dev;

volatile unsigned long *gpbcon = NULL;
volatile unsigned long *gpbdat = NULL;

MODULE_LICENSE("Dual BSD/GPL");
static int first_dev_open(struct inode *inode,struct file *file)
{
	/*配置 GPB 5 6 7 8为输出*/
	*gpbcon &=~((0x3<<(5*2))|(0x3<<(6*2))|(0x3<<(7*2))|(0x3<<(8*2)));//先清零
	*gpbcon |=((0x1<<(5*2))|(0x1<<(6*2))|(0x1<<(7*2))|(0x1<<(8*2)));// 配置为1 (输出)
	//printk("first dev open\n");
	return 0;
}
static ssize_t first_dev_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos)
{
	int val;
	copy_from_user(&val,buf,count);//从用户空间向内核空间拷贝数据
	if(val == 1)
	{
		//点灯
		*gpbdat &=~((1<<5)|(1<<6)|(1<<7)|(1<<8));
	}
	else
	{
		//灭灯
		*gpbdat|=(1<<5)|(1<<6)|(1<<7)|(1<<8);
	}

	//printk("first dev write\n");
	return 0;
}
static struct file_operations first_sdv_fops =
{
		.owner = THIS_MODULE,
		.open  = first_dev_open,
		.write = first_dev_write,
};
int major;
int first_drv_init(void)
{

	major = register_chrdev(0,"first_drv",&first_sdv_fops);//注冊
	firstdrv_class = class_create(THIS_MODULE,"first_drv");
	if(IS_ERR(firstdrv_class))
		return PTR_ERR(firstdrv_class);
	firstdrv_class_dev = device_create(firstdrv_class,NULL,MKDEV(major,0),NULL,"wq_device");
	if(unlikely(IS_ERR(firstdrv_class_dev)))
		return PTR_ERR(firstdrv_class_dev);

	/*映射物理地址*/
	gpbcon = (volatile unsigned long *) ioremap(0x56000010,16);
	gpbdat = gpbcon + 1;
	//printk("init   major= %d\n",major);
	return 0;
}

void first_dev_exit(void)
{
	//printk("exit\n");
	unregister_chrdev(major,"first_drv");//卸载

	device_unregister(firstdrv_class_dev);
	class_destroy(firstdrv_class);
	iounmap(gpbcon);
}
module_init(first_drv_init);
module_exit(first_dev_exit);

完整的測试代码例如以下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
/*wq_device on  打开
 *wq_device off 关闭
 */
int main(int argc, char **argv)
{
	int fd;
	int val = 1;
	fd = open("/dev/wq_device",	O_RDWR);
	if(fd < 0)
	{
		printf("can't open \n");
	}
	if(argc != 2)
	{
		printf("Usage :\n");
		printf("%s <on|off>\n",argv[0]);
		return 0;
	}
	if(strcmp(argv[1],"on") == 0)
	{
		val =1;
	}
	else
	{
		val =0;
	}
	write(fd,&val,4);
	return 0;
}