⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xup_v2pro_led.c

📁 Xilinx ISE&EDK 8.2平台的快速点餐系统设计
💻 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 + -