关于tq2440开发板的led驱动

上篇文章分析了天嵌科技附带的led驱动程序的核心语句

		s3c2410_gpio_cfgpin(gpio_table[i], gpio_cfg_table[i]);
		s3c2410_gpio_setpin(gpio_table[i], 0);


本文将驱动改写了引脚配置方式,采用直接写虚拟地址的方法进行引脚配置及引脚电平读写操作。

另外,本文使用标准字符设备方式实现了led驱动,驱动程序比起使用杂项设备(misc_device)要稍复杂一些,但其操作更标准些,因此更适合于驱动程序的学习

下面贴出驱动程序及测试程序代码:

#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>

#define DEVICE_NAME "LED_DEV"

MODULE_DESCRIPTION("My kernel module");
MODULE_AUTHOR("traveler");
MODULE_LICENSE("Dual BSD/GPL");

dev_t led_dev_num;

struct cdev *led_cdev;

int led_ioctl(struct inode *inode,struct file *filp,
		unsigned int cmd,unsigned long flag);
int led_open(struct inode *inode,struct file *filp);
int led_release(struct inode *inode,struct file *filp);

static struct file_operations led_fops = 
{
	.owner = THIS_MODULE,
	.ioctl = led_ioctl,
	.open = led_open,
	.release = led_release, 
};

int led_open(struct inode *inode,struct file *filp)
{
	return 0;
}

int led_release(struct inode *inode,struct file *filp)
{
	return 0;
}

int led_ioctl(struct inode *inode,struct file *filp,
		unsigned int cmd,unsigned long flag)
{
	unsigned int gpio_base = (unsigned int)S3C24XX_VA_GPIO;
	unsigned int gpbdat = gpio_base + 16 + 4;
	if(flag>4 || cmd >1)
		return -1;
	if(cmd == 1)//on
	{
		//将GPBDAT寄存器指定位置0
		(*(unsigned int *)gpbdat) &= ~(0x020 << flag);
		printk("<1>ioctl led[%ld]-on[%d].\n",flag,cmd);
	}
	else
	{
		//将GPBDAT寄存器指定位置1
		(*(unsigned int *)gpbdat) |= (0x020 << flag);
		printk("<1>ioctl led[%ld]-off[%d].\n",flag,cmd);
	}
	return 0;
}

static int leds_init_module(void)
{
	int ret;
	unsigned int gpio_base = (unsigned int )S3C24XX_VA_GPIO;
	unsigned int gpbdat = gpio_base + 16 + 4;
	unsigned int gpbcon = gpio_base + 16 ;
	led_cdev = NULL;
	ret = alloc_chrdev_region(&led_dev_num,0,1,DEVICE_NAME);
	if(ret<0)
	{
		printk("<1>get device register failure!\n");
		return ret;
	}
	printk("<1>Module leds init,major:%d,minor:%d\n",MAJOR(led_dev_num),MINOR(led_dev_num) );
	led_cdev = kmalloc(sizeof(struct cdev),GFP_KERNEL);
	if(!led_cdev)
	{
		unregister_chrdev_region(led_dev_num,1);
		return -ENOMEM;
	}
	memset(led_cdev,0,sizeof(struct cdev));
	led_cdev->owner = THIS_MODULE;
	led_cdev->ops = &led_fops;
	cdev_init(led_cdev,&led_fops);
	ret = cdev_add(led_cdev,led_dev_num,1);
	if(ret)
	{
		kfree(led_cdev);
		unregister_chrdev_region(led_dev_num,1);
		return -1;
	}
	//配置GPBCON寄存器
	(*(unsigned int *)gpbcon) &= ~(0x0ff<<10);
	(*(unsigned int *)gpbcon) |= (0x055 << 10) ;

	//熄灭所有led
	(*(unsigned int *)gpbdat) |= (0x0e0 );

	return ret;
}

static void leds_exit_module(void)
{
	cdev_del(led_cdev);
	kfree(led_cdev);
	led_cdev = NULL;
	unregister_chrdev_region(led_dev_num,1);
	led_dev_num = 0;
	printk("<1>Module leds exit\n" );
}

module_init(leds_init_module);
module_exit(leds_exit_module);


使用insmod加载驱动程序之后,要根据printk得到的设备号建立字符设备文件节点/dev/LED_DEV

测试程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>

int main(int argc, char **argv)
{
	int fd;
	int i;
	fd = open("/dev/LED_DEV", 0);
	if (fd < 0) {
		perror("open device leds");
		exit(1);
	}
	for(i=0;i<64;i++)
	{
		ioctl(fd, i&0x01, 0);
		ioctl(fd, (i&0x02)>>1, 1);
		ioctl(fd, (i&0x04)>>2, 2);
		ioctl(fd, (i&0x08)>>3, 3);
		usleep(200000);
	}
	close(fd);
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sanzhong104204

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值