AT91RM9200下的LED驱动程序实现及其分析
时间:2007-06-29 来源:arm+linux
在FFT的AT91RM9200的企业版开发板上做了一个LED的驱动程序,帖上来和大家共享一下。FFT虽说此版为企业版,但并没有提供所有硬件的驱动程序,比如LED的驱动程序就没有,而在调试软件的时候又经常会用,无奈只有自己写了。
1)说明:在头文件里面有些是我调试时用的,调试完了,懒得删除。
2)源代码:该程序的源代码,是根据刘淼(《嵌入式系统接口设计与LINUX驱动程序开发》)的双色LED驱动程序,我采用了他的程序框架,同时拷贝了AT91下的串口驱动,改8改8就成这样了。
#include <linux/config.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
#include <asm/arch/AT91RM9200.h>
#include <asm/arch/pio.h>
#include <linux/kernel.h>
//#define MODVERSIONS
//#include <linux/modversions.h>
#include <asm/arch/hardware.h>
#include <asm/arch/pio.h> #undef DEBUG
#define DEBUG
#ifdef DEBUG
#define DPRINTK(x...) printk(KERN_ALERT##"s3c2410-led:"##x)
#else
#define DPRINTK(x...)
#endif
#define LED6 15
#define LED7 16
#define LED8 17
#define LED9 26
static unsigned int led[]={AT91C_PIO_PB15,AT91C_PIO_PB16,AT91C_PIO_PB17,AT91C_PIO_PB26};
#define LEDNUM (sizeof(led)/sizeof(*led))
#define DEVICE_NAME "AT91RM9200-LED"
#define DbLedRAW_MINOR 1
static int DbLedMajor =0;
static char ledstatus = 0x00; #define DLYNUM 100 static void Led_init1(void); static void Led_off_all(void)
{
AT91_SYS->PIOB_SODR = AT91C_PIO_PB15|AT91C_PIO_PB16|AT91C_PIO_PB17|AT91C_PIO_PB26;
} static void Updateled(void)
{ DPRINTK("in update ledstatus = %x\n",ledstatus);
if(ledstatus&0x01)AT91_SYS->PIOB_CODR=AT91C_PIO_PB15;
else AT91_SYS->PIOB_SODR=AT91C_PIO_PB15;
if(ledstatus&0x02)AT91_SYS->PIOB_CODR=AT91C_PIO_PB16;
else AT91_SYS->PIOB_SODR=AT91C_PIO_PB16;
if(ledstatus&0x04)AT91_SYS->PIOB_CODR=AT91C_PIO_PB17;
else AT91_SYS->PIOB_SODR=AT91C_PIO_PB17;
if(ledstatus&0x08)AT91_SYS->PIOB_CODR=AT91C_PIO_PB26;
else AT91_SYS->PIOB_SODR=AT91C_PIO_PB26; }
static void Led_init1(void)
{
AT91_SYS->PIOB_PER = AT91C_PIO_PB15|AT91C_PIO_PB16|AT91C_PIO_PB17|AT91C_PIO_PB26;
AT91_SYS->PIOB_OER = AT91C_PIO_PB15|AT91C_PIO_PB16|AT91C_PIO_PB17|AT91C_PIO_PB26;
AT91_SYS->PIOB_PPUDR = AT91C_PIO_PB15|AT91C_PIO_PB16|AT91C_PIO_PB17|AT91C_PIO_PB26;
AT91_SYS->PIOB_OWDR = AT91C_PIO_PB15|AT91C_PIO_PB16|AT91C_PIO_PB17|AT91C_PIO_PB26;
AT91_SYS->PMC_PCER = (1<<AT91C_ID_PIOB );
} static ssize_t s3c2410_DbLed_write(struct file *file,const char *buffer,size_t count,loff_t *ppos)
{
copy_from_user(&ledstatus,buffer,sizeof(ledstatus));
DPRINTK("buffer = %x, ledstatus = %x\n",*buffer,ledstatus);
Updateled();
return sizeof(ledstatus);
}
static int s32410_DbLed_open(struct inode *inode,struct file *filp)
{
MOD_INC_USE_COUNT;
DPRINTK("Open Led.\n");
return 0;
} static int s3c2410_DbLed_release(struct inode *inode,struct file *filp)
{
MOD_DEC_USE_COUNT;
DPRINTK("Led release.\n");
Led_off_all();
return 0;
} static struct file_operations s3c2410_fops={
owner: THIS_MODULE,
open: s32410_DbLed_open,
write: s3c2410_DbLed_write,
release: s3c2410_DbLed_release,
};
#ifdef CONFIG_DEVFS_FS
static devfs_handle_t devfs_DbLed_dir,devfs_DbLedraw;
#endif
static int __init s3c2410_DbLed_init(void)
{
int ret;
Led_init1();
DPRINTK("Led initialized.\n");
Updateled();
ret = register_chrdev(0,DEVICE_NAME,&s3c2410_fops);
if(ret<0)
{
DPRINTK(DEVICE_NAME" can't get major number.\n");
return ret;
}
DbLedMajor = ret;
#ifdef CONFIG_DEVFS_FS
devfs_DbLed_dir = devfs_mk_dir(NULL,"led",NULL);
devfs_DbLedraw = devfs_register(devfs_DbLed_dir,"0",DEVFS_FL_DEFAULT,DbLedMajor,DbLedRAW_MINOR,S_IFCHR|S_IRUSR | S_IWUSR,&s3c2410_fops,NULL);
#endif
DPRINTK(DEVICE_NAME" initialized.\n");
return 0;
} static void __exit s3c2410_DbLed_exit(void)
{
#ifdef CONFIG_DEVFS_FS
devfs_unregister(devfs_DbLedraw);
devfs_unregister(devfs_DbLed_dir);
#endif
unregister_chrdev(DbLedMajor,DEVICE_NAME);
Led_off_all();
}
module_init(s3c2410_DbLed_init);
module_exit(s3c2410_DbLed_exit); EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Robin Wang");
MODULE_DESCRIPTION("AT91 4Led driver");
MODULE_LICENSE("GPL"); 3)调试过程中遇到的问题: 我在自己见的目录(比如:/usr/debug)里面把驱动编译成模块的形式,当我把编译好的模块insmod的时候,报告错误“at91_led1.o: unresolved symbol AT91_SYS”,没有办法,我只有把驱动程序直接编译到内核里面,不过时间稍微长些把了。 不过,我希望有知道原因的朋友能一起交流一下。 具体分析就免了吧,网上太多了,自己有板子的话直接调试一下,就知道怎么回事了。
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
#include <asm/arch/AT91RM9200.h>
#include <asm/arch/pio.h>
#include <linux/kernel.h>
//#define MODVERSIONS
//#include <linux/modversions.h>
#include <asm/arch/hardware.h>
#include <asm/arch/pio.h> #undef DEBUG
#define DEBUG
#ifdef DEBUG
#define DPRINTK(x...) printk(KERN_ALERT##"s3c2410-led:"##x)
#else
#define DPRINTK(x...)
#endif
#define LED6 15
#define LED7 16
#define LED8 17
#define LED9 26
static unsigned int led[]={AT91C_PIO_PB15,AT91C_PIO_PB16,AT91C_PIO_PB17,AT91C_PIO_PB26};
#define LEDNUM (sizeof(led)/sizeof(*led))
#define DEVICE_NAME "AT91RM9200-LED"
#define DbLedRAW_MINOR 1
static int DbLedMajor =0;
static char ledstatus = 0x00; #define DLYNUM 100 static void Led_init1(void); static void Led_off_all(void)
{
AT91_SYS->PIOB_SODR = AT91C_PIO_PB15|AT91C_PIO_PB16|AT91C_PIO_PB17|AT91C_PIO_PB26;
} static void Updateled(void)
{ DPRINTK("in update ledstatus = %x\n",ledstatus);
if(ledstatus&0x01)AT91_SYS->PIOB_CODR=AT91C_PIO_PB15;
else AT91_SYS->PIOB_SODR=AT91C_PIO_PB15;
if(ledstatus&0x02)AT91_SYS->PIOB_CODR=AT91C_PIO_PB16;
else AT91_SYS->PIOB_SODR=AT91C_PIO_PB16;
if(ledstatus&0x04)AT91_SYS->PIOB_CODR=AT91C_PIO_PB17;
else AT91_SYS->PIOB_SODR=AT91C_PIO_PB17;
if(ledstatus&0x08)AT91_SYS->PIOB_CODR=AT91C_PIO_PB26;
else AT91_SYS->PIOB_SODR=AT91C_PIO_PB26; }
static void Led_init1(void)
{
AT91_SYS->PIOB_PER = AT91C_PIO_PB15|AT91C_PIO_PB16|AT91C_PIO_PB17|AT91C_PIO_PB26;
AT91_SYS->PIOB_OER = AT91C_PIO_PB15|AT91C_PIO_PB16|AT91C_PIO_PB17|AT91C_PIO_PB26;
AT91_SYS->PIOB_PPUDR = AT91C_PIO_PB15|AT91C_PIO_PB16|AT91C_PIO_PB17|AT91C_PIO_PB26;
AT91_SYS->PIOB_OWDR = AT91C_PIO_PB15|AT91C_PIO_PB16|AT91C_PIO_PB17|AT91C_PIO_PB26;
AT91_SYS->PMC_PCER = (1<<AT91C_ID_PIOB );
} static ssize_t s3c2410_DbLed_write(struct file *file,const char *buffer,size_t count,loff_t *ppos)
{
copy_from_user(&ledstatus,buffer,sizeof(ledstatus));
DPRINTK("buffer = %x, ledstatus = %x\n",*buffer,ledstatus);
Updateled();
return sizeof(ledstatus);
}
static int s32410_DbLed_open(struct inode *inode,struct file *filp)
{
MOD_INC_USE_COUNT;
DPRINTK("Open Led.\n");
return 0;
} static int s3c2410_DbLed_release(struct inode *inode,struct file *filp)
{
MOD_DEC_USE_COUNT;
DPRINTK("Led release.\n");
Led_off_all();
return 0;
} static struct file_operations s3c2410_fops={
owner: THIS_MODULE,
open: s32410_DbLed_open,
write: s3c2410_DbLed_write,
release: s3c2410_DbLed_release,
};
#ifdef CONFIG_DEVFS_FS
static devfs_handle_t devfs_DbLed_dir,devfs_DbLedraw;
#endif
static int __init s3c2410_DbLed_init(void)
{
int ret;
Led_init1();
DPRINTK("Led initialized.\n");
Updateled();
ret = register_chrdev(0,DEVICE_NAME,&s3c2410_fops);
if(ret<0)
{
DPRINTK(DEVICE_NAME" can't get major number.\n");
return ret;
}
DbLedMajor = ret;
#ifdef CONFIG_DEVFS_FS
devfs_DbLed_dir = devfs_mk_dir(NULL,"led",NULL);
devfs_DbLedraw = devfs_register(devfs_DbLed_dir,"0",DEVFS_FL_DEFAULT,DbLedMajor,DbLedRAW_MINOR,S_IFCHR|S_IRUSR | S_IWUSR,&s3c2410_fops,NULL);
#endif
DPRINTK(DEVICE_NAME" initialized.\n");
return 0;
} static void __exit s3c2410_DbLed_exit(void)
{
#ifdef CONFIG_DEVFS_FS
devfs_unregister(devfs_DbLedraw);
devfs_unregister(devfs_DbLed_dir);
#endif
unregister_chrdev(DbLedMajor,DEVICE_NAME);
Led_off_all();
}
module_init(s3c2410_DbLed_init);
module_exit(s3c2410_DbLed_exit); EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Robin Wang");
MODULE_DESCRIPTION("AT91 4Led driver");
MODULE_LICENSE("GPL"); 3)调试过程中遇到的问题: 我在自己见的目录(比如:/usr/debug)里面把驱动编译成模块的形式,当我把编译好的模块insmod的时候,报告错误“at91_led1.o: unresolved symbol AT91_SYS”,没有办法,我只有把驱动程序直接编译到内核里面,不过时间稍微长些把了。 不过,我希望有知道原因的朋友能一起交流一下。 具体分析就免了吧,网上太多了,自己有板子的话直接调试一下,就知道怎么回事了。
相关阅读 更多 +










