led驱动测试成功
2011-10-07 20:42
375 查看
今天终于把te6410下linux中的led驱动给测试成功了,看着不断闪烁的led,感觉到一种久违的成功!
首先贴出led驱动的代码:
//#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/irq.h>
#include <mach/gpio.h>
#include <plat/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/hardware.h>
#include <linux/io.h>
#define DEVICE_NAME "leds"
#define LED_MAJOR 231
static unsigned long led_table [] = {
S3C64XX_GPM(0),
S3C64XX_GPM(1),
S3C64XX_GPM(2),
S3C64XX_GPM(3),
};
static unsigned int led_cfg_table [] = {
S3C64XX_GPM_OUTPUT(0),
S3C64XX_GPM_OUTPUT(1),
S3C64XX_GPM_OUTPUT(2),
S3C64XX_GPM_OUTPUT(3),
};
static int s3c6410_leds_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
unsigned long tmp;
switch(cmd) {
case 0:
case 1:
if (arg > 4) {
return -EINVAL;
}
tmp = __raw_readl(S3C64XX_GPMDAT);
if(cmd)
tmp &= (~(1<<arg));
else
tmp |= (1<<arg);
__raw_writel(tmp,S3C64XX_GPMDAT);
// gpio_set_value(led_table[arg], !cmd);
return 0;
default:
return -EINVAL;
}
}
static struct file_operations s3c6410_leds_fops = {
.owner = THIS_MODULE,
.ioctl = s3c6410_leds_ioctl,
};
static struct cdev cdev_leds;
struct class * my_class;
static int __init s3c6410_leds_init(void)
{
int ret;
unsigned long tmp;
int i;
dev_t devno;
printk(KERN_NOTICE "enter s3c6410_leds_init\n");
devno = MKDEV(LED_MAJOR,0);
ret = register_chrdev_region(devno,1,DEVICE_NAME);
ret = 0;
if(ret<0)
{
printk(KERN_NOTICE "can not register led device");
return ret;
}
cdev_init(&cdev_leds,&s3c6410_leds_fops);
cdev_leds.owner = THIS_MODULE;
ret =cdev_add(&cdev_leds,devno,1);
if(ret)
{
printk(KERN_NOTICE "can not add leds device");
return ret;
}
my_class = class_create(THIS_MODULE,"my_class");
if(IS_ERR(my_class))
{
printk("Err: Failed in creating class\n");
return -1;
}
device_create(my_class,NULL,MKDEV(LED_MAJOR,0),NULL,DEVICE_NAME);
//gpm0-3 pull up
tmp = __raw_readl(S3C64XX_GPMPUD);
tmp &= (~0xFF);
tmp |= 0xaa;
__raw_writel(tmp,S3C64XX_GPMPUD);
//gpm0-3 output mode
tmp = __raw_readl(S3C64XX_GPMCON);
tmp &= (~0xFFFF);
tmp |= 0x1111;
__raw_writel(tmp,S3C64XX_GPMCON);
//gpm0-3 output 0
tmp = __raw_readl(S3C64XX_GPMDAT);
tmp |= 0x10;
__raw_writel(tmp,S3C64XX_GPMDAT);
//printk("S3C64XX_GPMCON is %x\n",__raw_readl(S3C64XX_GPMCON));
//printk("S3C64XX_GPMDAT is %x\n",__raw_readl(S3C64XX_GPMDAT));
//printk("S3C64XX_GPMPUD is %x\n",__raw_readl(S3C64XX_GPMPUD));
printk(DEVICE_NAME " initialized\n");
return 0;
}
static void __exit s3c6410_leds_exit(void)
{
cdev_del(&cdev_leds);
unregister_chrdev_region(MKDEV(LED_MAJOR,0),1);
printk(KERN_NOTICE "s3c6440_leds_exit\n");
}
module_init(s3c6410_leds_init);
module_exit(s3c6410_leds_exit);
MODULE_LICENSE("GPL");
然后就是需要写一个Makefile文件,注意文件中的内核源码所在路径为解压飞凌提供的linux2.6.28内核的目录,同时解压后还必须进行编译。(不然后面生产驱动模块你会发现会少两个头文件的!)
ifneq ($(KERNELRELEASE),)
obj-m := s3c6410_leds.o
# Otherwise we were called directly from the command
# line; invoke the kernel build system.
else
KERNELDIR ?= /home/charcy/work/linux/kernel/linux2.6.28/
PWD := $(shell pwd)
default:
make -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
rm -f *.ko *.o *.mod *.mod.c *.symvers *.order
写完后那就直接使用make命令,就可以生产s3c6410_leds.ko内核模块文件
之后就是要用到测试led的文件,也就是测试程序,如下(注意没有头文件哦):
int main(void)
{
int on=1;
int led;
int fd;
fd = open("/dev/leds",0);
if(fd<0)
{
perror("open device leds");
exit(1);
}
printf("leds test show.press ctrl+c to exit\n");
while(1)
{
for(led=0;led<4;led++)
{
ioctl(fd,on,led);
usleep(60000);
}
on = !on;
}
close(fd);
return 0;
}
使用命令:arm-linux-gcc led_test.c -o led_test
以上都是在主机上进行编译的,那么接下来就是将s3c6410_leds.ko、led_test这两个文件下载到开发板,依次执行以下命令:
#insmod s3c6410_leds.ko
#chmod 777 led_test
#./led_test
好了,这个时候就可以看到开发板上led灯在循环闪烁了:)
注:
相关的寄存器虚地址定义在arch/arm/plat-s3c64xx/include/plat/gpio-bank-m.h
#define S3C64XX_GPMCON (S3C64XX_GPM_BASE +0x00)
#define S3C64XX_GPMDAT (S3C64XX_GPM_BASE +0x04)
#define S3C64XX_GPMPUD (S3C64XX_GPM_BASE +0x08)
GPIO M端口的基地址定义在arch/arm/plat-s3c64xx/include/plat/regs-gpio.h
#define S3C64XX_GPM_BASE (S3C64XX_VA_GPIO +0x0820)
GPIO的虚地址定义在arch/arm/mach-s3c6400/include/mach/map.h
#define S3C64XX_VA_GPIO S3C_ADDR(0x00500000)
GPIO的虚地址是有全局虚地址S3C_ADDR_BASE计算出来的,void __iomem __force *作用是强制转化为地址。arch/arm/plat-s3c/include/plat/map.h
#define S3C_ADDR_BASE (0xF4000000)
#ifndef __ASSEMBLY__
#define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE+ (x))
#else
#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
#endif
由此可以得到GPM寄存器对应的虚地址分别为:
S3C64XX_GPMCON 0xF4500820
S3C64XX_GPMDAT 0xF4500824
S3C64XX_GPMPUD 0xF4500828
首先贴出led驱动的代码:
//#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/irq.h>
#include <mach/gpio.h>
#include <plat/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/hardware.h>
#include <linux/io.h>
#define DEVICE_NAME "leds"
#define LED_MAJOR 231
static unsigned long led_table [] = {
S3C64XX_GPM(0),
S3C64XX_GPM(1),
S3C64XX_GPM(2),
S3C64XX_GPM(3),
};
static unsigned int led_cfg_table [] = {
S3C64XX_GPM_OUTPUT(0),
S3C64XX_GPM_OUTPUT(1),
S3C64XX_GPM_OUTPUT(2),
S3C64XX_GPM_OUTPUT(3),
};
static int s3c6410_leds_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
unsigned long tmp;
switch(cmd) {
case 0:
case 1:
if (arg > 4) {
return -EINVAL;
}
tmp = __raw_readl(S3C64XX_GPMDAT);
if(cmd)
tmp &= (~(1<<arg));
else
tmp |= (1<<arg);
__raw_writel(tmp,S3C64XX_GPMDAT);
// gpio_set_value(led_table[arg], !cmd);
return 0;
default:
return -EINVAL;
}
}
static struct file_operations s3c6410_leds_fops = {
.owner = THIS_MODULE,
.ioctl = s3c6410_leds_ioctl,
};
static struct cdev cdev_leds;
struct class * my_class;
static int __init s3c6410_leds_init(void)
{
int ret;
unsigned long tmp;
int i;
dev_t devno;
printk(KERN_NOTICE "enter s3c6410_leds_init\n");
devno = MKDEV(LED_MAJOR,0);
ret = register_chrdev_region(devno,1,DEVICE_NAME);
ret = 0;
if(ret<0)
{
printk(KERN_NOTICE "can not register led device");
return ret;
}
cdev_init(&cdev_leds,&s3c6410_leds_fops);
cdev_leds.owner = THIS_MODULE;
ret =cdev_add(&cdev_leds,devno,1);
if(ret)
{
printk(KERN_NOTICE "can not add leds device");
return ret;
}
my_class = class_create(THIS_MODULE,"my_class");
if(IS_ERR(my_class))
{
printk("Err: Failed in creating class\n");
return -1;
}
device_create(my_class,NULL,MKDEV(LED_MAJOR,0),NULL,DEVICE_NAME);
//gpm0-3 pull up
tmp = __raw_readl(S3C64XX_GPMPUD);
tmp &= (~0xFF);
tmp |= 0xaa;
__raw_writel(tmp,S3C64XX_GPMPUD);
//gpm0-3 output mode
tmp = __raw_readl(S3C64XX_GPMCON);
tmp &= (~0xFFFF);
tmp |= 0x1111;
__raw_writel(tmp,S3C64XX_GPMCON);
//gpm0-3 output 0
tmp = __raw_readl(S3C64XX_GPMDAT);
tmp |= 0x10;
__raw_writel(tmp,S3C64XX_GPMDAT);
//printk("S3C64XX_GPMCON is %x\n",__raw_readl(S3C64XX_GPMCON));
//printk("S3C64XX_GPMDAT is %x\n",__raw_readl(S3C64XX_GPMDAT));
//printk("S3C64XX_GPMPUD is %x\n",__raw_readl(S3C64XX_GPMPUD));
printk(DEVICE_NAME " initialized\n");
return 0;
}
static void __exit s3c6410_leds_exit(void)
{
cdev_del(&cdev_leds);
unregister_chrdev_region(MKDEV(LED_MAJOR,0),1);
printk(KERN_NOTICE "s3c6440_leds_exit\n");
}
module_init(s3c6410_leds_init);
module_exit(s3c6410_leds_exit);
MODULE_LICENSE("GPL");
然后就是需要写一个Makefile文件,注意文件中的内核源码所在路径为解压飞凌提供的linux2.6.28内核的目录,同时解压后还必须进行编译。(不然后面生产驱动模块你会发现会少两个头文件的!)
ifneq ($(KERNELRELEASE),)
obj-m := s3c6410_leds.o
# Otherwise we were called directly from the command
# line; invoke the kernel build system.
else
KERNELDIR ?= /home/charcy/work/linux/kernel/linux2.6.28/
PWD := $(shell pwd)
default:
make -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
rm -f *.ko *.o *.mod *.mod.c *.symvers *.order
写完后那就直接使用make命令,就可以生产s3c6410_leds.ko内核模块文件
之后就是要用到测试led的文件,也就是测试程序,如下(注意没有头文件哦):
int main(void)
{
int on=1;
int led;
int fd;
fd = open("/dev/leds",0);
if(fd<0)
{
perror("open device leds");
exit(1);
}
printf("leds test show.press ctrl+c to exit\n");
while(1)
{
for(led=0;led<4;led++)
{
ioctl(fd,on,led);
usleep(60000);
}
on = !on;
}
close(fd);
return 0;
}
使用命令:arm-linux-gcc led_test.c -o led_test
以上都是在主机上进行编译的,那么接下来就是将s3c6410_leds.ko、led_test这两个文件下载到开发板,依次执行以下命令:
#insmod s3c6410_leds.ko
#chmod 777 led_test
#./led_test
好了,这个时候就可以看到开发板上led灯在循环闪烁了:)
注:
相关的寄存器虚地址定义在arch/arm/plat-s3c64xx/include/plat/gpio-bank-m.h
#define S3C64XX_GPMCON (S3C64XX_GPM_BASE +0x00)
#define S3C64XX_GPMDAT (S3C64XX_GPM_BASE +0x04)
#define S3C64XX_GPMPUD (S3C64XX_GPM_BASE +0x08)
GPIO M端口的基地址定义在arch/arm/plat-s3c64xx/include/plat/regs-gpio.h
#define S3C64XX_GPM_BASE (S3C64XX_VA_GPIO +0x0820)
GPIO的虚地址定义在arch/arm/mach-s3c6400/include/mach/map.h
#define S3C64XX_VA_GPIO S3C_ADDR(0x00500000)
GPIO的虚地址是有全局虚地址S3C_ADDR_BASE计算出来的,void __iomem __force *作用是强制转化为地址。arch/arm/plat-s3c/include/plat/map.h
#define S3C_ADDR_BASE (0xF4000000)
#ifndef __ASSEMBLY__
#define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE+ (x))
#else
#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
#endif
由此可以得到GPM寄存器对应的虚地址分别为:
S3C64XX_GPMCON 0xF4500820
S3C64XX_GPMDAT 0xF4500824
S3C64XX_GPMPUD 0xF4500828
相关文章推荐
- linux驱动开发FL2440开发板-LED驱动及其测试程序
- jz2440(mini2440)led驱动测试过程(环境搭建d)
- Linux下实现流水灯等功能的LED驱动代码及测试实例
- fl2440使能linux-3.0内核自带的led驱动,并测试
- 编译加载mini2440_led驱动后,测试 该驱动是否有用
- led驱动模块编译、加载和测试
- LINUX2.6.26.6内核下的第一个LED驱动程序测试成功!
- 详细注释FL2440按键中断驱动(含poll机制),测试成功
- Android驱动入门-LED--测试APP编写③
- linux设备驱动之LED驱动测试
- Linux驱动开发之四-----LED改进测试(增加自动创建设备节点)
- 使用Spring搭建数据库连接驱动,测试是否成功
- Linux嵌入式驱动初体验(六)--- LED驱动测试程序
- platform之led驱动分析及测试程序
- VPM led driver LED显示驱动 20091010 VPM软件仿真硬件电路 屏幕录像上传成功
- Linux驱动:LED驱动测试
- Fedora 19 安装无线网卡驱动(亲自测试成功)
- 小小的led驱动和测试程序
- hibernate中使用MyEclipse工具时,加载数据库的配置信息时候,当加载数据库的驱动时测试不成功
- Linux下基于Platform的led驱动(二)——测试