📄 xup_v2pro_led.c
字号:
/*
File: xup_v2pro_led.c
Description: LED driver for Xilinx XUP Virtex-II Pro board
Author:
Date:
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/devfs_fs_kernel.h>
//#include <linux/spinlock.h>
#include <linux/proc_fs.h>
//#include <linux/delay.h>
#define XUP_V2PRO_LED_DEVICENAME "xup_v2pro_led"
#define XUP_V2PRO_LED_REG_BASE_ADDR 0x40000000
#define LED_CHANNEL1_DATA_REG (*(volatile unsigned long *)(XUP_V2PRO_LED_REG_BASE_ADDR+0x00))
#define LED_CHANNEL1_3STATE_REG (*(volatile unsigned long *)(XUP_V2PRO_LED_REG_BASE_ADDR+0x04))
#ifdef LED_DUAL_CHANNEL
#define LED_CHANNEL2_DATA_REG (*(volatile unsigned long *)(XUP_V2PRO_LED_REG_BASE_ADDR+0x08))
#define LED_CHANNEL2_3STATE_REG (*(volatile unsigned long *)(XUP_V2PRO_LED_REG_BASE_ADDR+0x0C))
#endif
#define DEBUG
#ifdef DEBUG
#define LED_DEBUG(fmt,args...) printk("%s: " fmt, __FUNCTION__, ## args)
#else
#define LED_DEBUG(fmt,args...)
#endif
// #define XUP_V2PRO_LED_SET_TIMEOUT _IOWR('L', 0x80, unsigned long)
#define XUP_V2PRO_LED_START_TIMER _IOWR('L', 0x81, unsigned long)
#define XUP_V2PRO_LED_STOP_TIMER _IOWR('L', 0x82, unsigned long)
#ifdef CONFIG_DEVFS_FS
static devfs_handle_t devfs_xup_v2pro_led = NULL;
#endif
#define LED_TIMER_INTERVALS 1 //500 // 0.5s
// led timer flag
#define LED_TIMER_FLAG_ON 0x80
#define LED_TIMER_FLAG_OFF 0x81
static struct timer_list led_timer;
static int led_timer_flag = 0;
static spinlock_t led_timer_lock;
static struct proc_dir_entry * led_proc_dir_entry = NULL;
static int xup_v2pro_led_major;
#if 0
static void xup_v2pro_led_set_on( int bit )
{
volatile unsigned long data;
data = LED_CHANNEL1_3STATE_REG;
data = data & ( ~( 1<< (bit-1) ) );
LED_CHANNEL1_3STATE_REG = data;
LED_DEBUG( "data=0x%x,bit=0x%x\n", data, bit );
}
static void xup_v2pro_led_set_off( int bit )
{
volatile unsigned long data;
data = LED_CHANNEL1_3STATE_REG;
data = data | ( 1 << bit );
LED_CHANNEL1_3STATE_REG = data;
LED_DEBUG( "data=0x%x,bit=0x%x\n", data, bit );
}
#endif
static void xup_v2pro_led_timer_routine( void * pbit )
{
unsigned long expire;
volatile unsigned long led_data;
unsigned long bit;
LED_DEBUG( "Entering\n" );
expire = jiffies + (LED_TIMER_INTERVALS) * HZ ;/// 1000;
// read current value
led_data = LED_CHANNEL1_3STATE_REG;
bit = ( unsigned long)pbit;
LED_DEBUG( "1. bit=0x%x, pbit=0x%x,led_data=0x%x\n", bit, (unsigned long)pbit, led_data );
if( bit == 0 ){
led_data = ~(led_data & 0xf );
}
else{
if( ( led_data & ( 1 << (bit-1) ) ) == 0 ){
LED_DEBUG( "2. bit=0x%x, led_data=0x%x\n", bit, led_data );
led_data = led_data | ( 1 << (bit-1) );
}
else{
LED_DEBUG( "3. bit=0x%x, led_data=0x%x\n", bit, led_data );
led_data = led_data & ( 0xf - ( 1 << ( bit-1 ) ) ); //( 0 << (bit-1) );
}
}
LED_DEBUG( "4. after modified: led_data=0x%x\n", led_data );
LED_CHANNEL1_3STATE_REG = led_data;
mod_timer( &led_timer, expire );
LED_DEBUG( "Leaving\n" );
}
static void xup_v2pro_led_timer_init( int bit )
{
LED_DEBUG( "Entering\n" );
if( bit == 0 ){
LED_CHANNEL1_3STATE_REG = 0xf;
}
init_timer(&led_timer);
led_timer.function = xup_v2pro_led_timer_routine;
led_timer.data = bit;
led_timer.expires = jiffies + HZ * LED_TIMER_INTERVALS; // / 1000;
add_timer( &led_timer );
LED_DEBUG( "Leaving\n" );
}
static void xup_v2pro_led_timer_exit( void )
{
del_timer(&led_timer);
}
static void xup_v2pro_led_hardware_init( void )
{
// set all led to turn off
LED_CHANNEL1_3STATE_REG = (volatile unsigned long)0xf;
}
static int xup_v2pro_led_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
LED_DEBUG( "Entering\n" );
switch( cmd ){
case XUP_V2PRO_LED_START_TIMER:
LED_DEBUG( "Starting a new timer\n" );
spin_lock( &led_timer_lock );
// if timer had already started, stop it, and restart a new timer
if( led_timer_flag == LED_TIMER_FLAG_ON ){
xup_v2pro_led_timer_exit( );
// led_timer_flag = LED_TIMER_FLAG_OFF;
}
xup_v2pro_led_timer_init( arg );
led_timer_flag = LED_TIMER_FLAG_ON;
spin_unlock( &led_timer_lock );
// xup_v2pro_led_timer_init(arg);
break;
case XUP_V2PRO_LED_STOP_TIMER:
LED_DEBUG( "Stoping timer\n" );
spin_lock( &led_timer_lock );
if( led_timer_flag == LED_TIMER_FLAG_ON ){
xup_v2pro_led_timer_exit( );
led_timer_flag = LED_TIMER_FLAG_OFF;
}
spin_unlock( &led_timer_lock );
break;
}
LED_DEBUG( "Leaving\n" );
return 0;
}
static ssize_t xup_v2pro_led_read(struct file *filp, char *buf, size_t count, loff_t * f_pos)
{
buf[0] = (LED_CHANNEL1_3STATE_REG & 0xf); //Change the sequence of buf[0] to "human" way //Change the sequence of buf[0] to "human" way switch(buf[0]){ case 0x0f: buf[0]=(char)0x00;break; case 0x07: buf[0]=(char)0x01;break; case 0x0b: buf[0]=(char)0x02;break; case 0x03: buf[0]=(char)0x03;break; case 0x0d: buf[0]=(char)0x04;break; case 0x05: buf[0]=(char)0x05;break; case 0x09: buf[0]=(char)0x06;break; case 0x01: buf[0]=(char)0x07;break; case 0x0e: buf[0]=(char)0x08;break; case 0x06: buf[0]=(char)0x09;break; case 0x0a: buf[0]=(char)0x0a;break; case 0x02: buf[0]=(char)0x0b;break; case 0x0c: buf[0]=(char)0x0c;break; case 0x04: buf[0]=(char)0x0d;break; case 0x08: buf[0]=(char)0x0e;break; case 0x00: buf[0]=(char)0x0f;break; default : buf[0]=(char)0x0f;break; }
LED_DEBUG( "buffer:0x%x,0x%x\n", buf[0], buf[1] );
LED_DEBUG( "register value:0x%x\n", LED_CHANNEL1_3STATE_REG );
return 1;
}
static ssize_t xup_v2pro_led_write(struct file *filp, char *buf, size_t count, loff_t * f_pos)
{
#if 0
int i;
LED_CHANNEL1_3STATE_REG = (volatile unsigned long)(0xF);
for( i=0; i<1000; i++ );
#endif
spin_lock( &led_timer_lock );
if( led_timer_flag == LED_TIMER_FLAG_ON ){
xup_v2pro_led_timer_exit( );
led_timer_flag = LED_TIMER_FLAG_OFF;
}
spin_unlock( &led_timer_lock ); //Change the sequence of buf[0] to "human" way switch(buf[0]){ case 0x00: buf[0]=0x0f;break; case 0x01: buf[0]=0x07;break; case 0x02: buf[0]=0x0b;break; case 0x03: buf[0]=0x03;break; case 0x04: buf[0]=0x0d;break; case 0x05: buf[0]=0x05;break; case 0x06: buf[0]=0x09;break; case 0x07: buf[0]=0x01;break; case 0x08: buf[0]=0x0e;break; case 0x09: buf[0]=0x06;break; case 0x0a: buf[0]=0x0a;break; case 0x0b: buf[0]=0x02;break; case 0x0c: buf[0]=0x0c;break; case 0x0d: buf[0]=0x04;break; case 0x0e: buf[0]=0x08;break; case 0x0f: buf[0]=0x00;break; default : buf[0]=0x0f;break; }
LED_CHANNEL1_3STATE_REG = (volatile unsigned long)buf[0];
LED_DEBUG( "buffer:0x%x, count=0x%x\n", buf[0], count );
LED_DEBUG( "register 3-state:0x%x, data:0x%x\n", LED_CHANNEL1_3STATE_REG, LED_CHANNEL1_DATA_REG );
return 1;
}
static int xup_v2pro_led_open( struct inode * inode, struct file * file )
{
MOD_INC_USE_COUNT;
return 0;
}
static int xup_v2pro_led_close( struct inode * inode, struct file * file )
{
MOD_DEC_USE_COUNT;
return 0;
}
static struct file_operations xup_v2pro_led_fops = {
owner: THIS_MODULE,
ioctl: xup_v2pro_led_ioctl,
read: xup_v2pro_led_read,
write: xup_v2pro_led_write,
open: xup_v2pro_led_open,
release: xup_v2pro_led_close,
};
static int __init xup_v2pro_led_init( void )
{
xup_v2pro_led_major = register_chrdev( 0, XUP_V2PRO_LED_DEVICENAME, &xup_v2pro_led_fops );
if( xup_v2pro_led_major < 0 ){
printk( "register failed!\n" );
return -1;
}
#ifdef CONFIG_DEVFS_FS
devfs_xup_v2pro_led = devfs_register(NULL, XUP_V2PRO_LED_DEVICENAME, DEVFS_FL_DEFAULT,
xup_v2pro_led_major, 1, S_IFCHR | S_IRUGO | S_IWUSR,
&xup_v2pro_led_fops, NULL);
#endif
led_proc_dir_entry = create_proc_entry( XUP_V2PRO_LED_DEVICENAME, 0, NULL );
if( led_proc_dir_entry != NULL )
led_proc_dir_entry->proc_fops = &xup_v2pro_led_fops;
xup_v2pro_led_hardware_init( );
spin_lock( &led_timer_lock );
led_timer_flag = LED_TIMER_FLAG_OFF;
spin_unlock( &led_timer_lock );
return 0;
}
static void __exit xup_v2pro_led_exit( void )
{
spin_lock( &led_timer_lock );
if( led_timer_flag == LED_TIMER_FLAG_ON ){
xup_v2pro_led_timer_exit( );
led_timer_flag = LED_TIMER_FLAG_OFF;
}
spin_unlock( &led_timer_lock );
remove_proc_entry( XUP_V2PRO_LED_DEVICENAME, NULL );
#ifdef CONFIG_DEVFS_FS
devfs_unregister(devfs_xup_v2pro_led);
#endif
unregister_chrdev( xup_v2pro_led_major, XUP_V2PRO_LED_DEVICENAME );
}
//EXPORT_NO_SYMBOLS;
/* EXPORTED FUNCTIONS */
//EXPORT_SYMBOL(xup_v2pro_led_set_on);
//EXPORT_SYMBOL(xup_v2pro_led_set_off);
MODULE_AUTHOR("Cactus Software Labs.");
MODULE_LICENSE("GPL");
module_init(xup_v2pro_led_init);
module_exit(xup_v2pro_led_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -