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

📄 pnxled.c

📁 nxp pnx8550的led驱动源代码
💻 C
字号:
/* func : pnx8550 LED driver
 * author : zhu weihua(zhuwas@163.com)
 * 2008-03-11T15:12:05+0800
 */

/*-----basic support for kernel module-----*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/stat.h>
#include <linux/miscdevice.h>

/*-----module will use the header file below-----*/
#include <asm/uaccess.h> /*copy content between user and kernel*/
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/string.h>


//FOR MACRO DEFINE
#define NAME "pnxled"

#define FPSCK0     pled->GPIO_MD2 = 0x01000000
#define FPSCK1     pled->GPIO_MD2 = 0x01000100
#define FPSTB0     pled->GPIO_MD2 = 0x02000000
#define FPSTB1     pled->GPIO_MD2 = 0x02000200
#define FPDATA0    pled->GPIO_MD2 = 0x08000000
#define FPDATA1    pled->GPIO_MD2 = 0x08000800

/*
//used for ioctrl.
#define GPIO_IOC_MAGIC          'I'
#define GPIO_IOCSETWAITPERIOD   _IO(GPIO_IOC_MAGIC,0)
#define GPIO_IOCGETWAITPERIOD   _IO(GPIO_IOC_MAGIC,1)
*/

MODULE_AUTHOR("zhu weihua<zhuwas@163.com>");
MODULE_DESCRIPTION ("pnx8550 driver");
MODULE_LICENSE("Dual BSD/GPL");

/*private data structure*/
struct pnxled_private {
	unsigned long *ref_cnt;		/*reference count*/
	spinlock_t lock;
	unsigned char b_mode;		/*blocking mode or not*/
};
//register for the GPIO
typedef volatile struct {
     __u32 GPIO_MC0;
     __u32 GPIO_MC1;
     __u32 GPIO_MC2;
     __u32 GPIO_MC3;
     __u32 GPIO_MD0;
     __u32 GPIO_MD1;
     __u32 GPIO_MD2;
     __u32 GPIO_MD3;
}PNXLEDRegs;

/*support interface*/
static void DelayNS(unsigned int dly);
static void Led_Single(unsigned char dig, unsigned char num);
static unsigned char getled_value(char str);
static void do_ledwrite(void);
static ssize_t pnxled_write(struct file *file,const char *data,size_t len,loff_t *ppos);
static int pnxled_ioctl(struct inode *inode,struct file *file,unsigned cmd,unsigned long arg);
static int pnxled_open(struct inode *inode,struct file *file);
static int pnxled_release(struct inode *inode,struct file *file);

/* Global data */
static struct file_operations pnxled_fops = {
        .owner  = THIS_MODULE,
        .write  = pnxled_write,
        .ioctl  = pnxled_ioctl,
        .open   = pnxled_open,
        .release= pnxled_release,
};
static struct miscdevice misc_pnxled = {
     .minor = MISC_DYNAMIC_MINOR,
     .name  = NAME,
     .fops  = &pnxled_fops
};
static struct pnxled_private pnxled_priv;

static unsigned int old_GPIO_MC2;
static PNXLEDRegs *pled = (PNXLEDRegs*)(0xBBE00000 + 0x00104000);
static unsigned char led_d[4]={0x0b,0x0d,0x0e,0x07};

struct timer_list led_timer;
static DECLARE_WAIT_QUEUE_HEAD(wq);
static volatile int flag = 0;
static volatile unsigned long long led_i = 0;

static volatile unsigned char buf[8]={'*','*','*','*','*','*','*','*'};

//map the ascii char to the keycode.
static unsigned char getled_value(char str)
{
    unsigned char Code;
    switch(str) {
        case '0':
        Code = 0x82;
        break;
        case '1':
        Code = 0xbe;
        break;
        case '2':
        Code = 0x23;
        break;
        case '3':
        Code = 0x2a;
        break;
        case '4':
        Code = 0x1e;
        break;
        case '5':
        Code = 0x4a;
        break;
        case '6':
        Code = 0x42;
        break;
        case '7':
        Code = 0xae;
        break;
        case '8':
        Code = 0x02;
        break;
        case '9':
        Code = 0x0a;
	break;
        case 'A':
        case 'a':
        Code = 0x06;
        break;
        case 'B':
        case 'b':
        Code = 0x52;
        break;
        case 'C':
        case 'c':
        Code = 0xc3;
        break;
        case 'D':
        case 'd':
        Code = 0x32;
        break;
        case 'E':
        case 'e':
        Code = 0x43;
        break;
        case 'F':
        case 'f':
        Code = 0x47;
        break;
        case 'H':
        Code = 0x16;
        break;
        case 'h':
        Code = 0x56;
        break;
        case 'L':
        case 'l':
        Code = 0xd3;
	break;
        case 'N':
        case 'n':
        Code = 0x86;
        break;
        case 'P':
        case 'p':
        Code = 0x07;
        break;
        case 'U':
        case 'u':
        case 'V':
        case 'v':
        Code = 0x92;
        break;
        case '-':
        Code = 0x7f;
        break;
        case '_':
        Code = 0xfb;
        break;
        case '.':
        Code = 0xfd;
        break;
        case '*':
        Code = 0xff;
        break;
        default:
        Code = 0x0;
        break;
    }
    return Code;
}

static void DelayNS(unsigned int dly)
{
	unsigned int i;
	for(; dly>0; dly--)
		for(i=0; i<50000; i++);
}

static void Led_Single(unsigned char dig, unsigned char num)
{
	unsigned int i;
	for(i=0;i<4;i++){
		if(dig&(0x01<<i))
			{FPSCK0;FPDATA1;FPSCK1;}
		else
			{FPSCK0;FPDATA0;FPSCK1;}
    	}
	for(i=0;i<8;i++){
		if(num&(0x01<<i))
			{FPSCK0;FPDATA1;FPSCK1;}
		else
			{FPSCK0;FPDATA0;FPSCK1;}
	}
	FPSTB0;
	DelayNS(1);
	FPSTB1;
}
//will do write by kernel timer
static void do_ledwrite(void)
{
	spin_lock(&pnxled_priv.lock);
	switch (led_i%8) {
		case 0:
			Led_Single(led_d[0],getled_value(buf[0]));	
			break;
		case 1:
			if (buf[1]=='.') {
				Led_Single(led_d[0],getled_value(buf[1]));	
			}
			break;
		case 2:
			Led_Single(led_d[1],getled_value(buf[2]));	
			break;
		case 3:
			if (buf[3]=='.') {
				Led_Single(led_d[1],getled_value(buf[3]));	
			}
			break;
		case 4:
			Led_Single(led_d[2],getled_value(buf[4]));	
			break;
		case 5:
			if (buf[5]=='.') {
				Led_Single(led_d[2],getled_value(buf[5]));	
			}
			break;
		case 6:
			Led_Single(led_d[3],getled_value(buf[6]));	
			break;
		case 7:
			if (buf[7]=='.') {
				Led_Single(led_d[3],getled_value(buf[7]));	
			}
			break;
		default:
			break;

	}
	spin_unlock(&pnxled_priv.lock);
	led_i++;
	flag = 1;
	wake_up_interruptible(&wq);
	mod_timer(&led_timer,jiffies+1);
}

static ssize_t pnxled_write(struct file *file,const char *data,size_t len,loff_t *ppos)
{
	//write the buf and let do_ledwrite to display by herslef
	memset((void *)buf,'*',8);
	memcpy((void *)buf,data,len);

	del_timer(&led_timer);
	led_timer.expires = jiffies+1;
	//led_timer.data = (unsigned long);
	led_timer.function = (void *)do_ledwrite;
	add_timer(&led_timer);
	wait_event_interruptible(wq, flag!=0);
	flag = 0;
	led_i = 0;

	return 0;
}

static int pnxled_ioctl(struct inode *inode,struct file *file,unsigned cmd,unsigned long arg)
{
	unsigned long *ptr = (unsigned long *)arg;
	if(ptr == NULL)
		return (-EIO);
	switch(cmd) {
		/*
		case GPIO_IOCSETWAITPERIOD:
			sleeptime = arg;
			break;
		case GPIO_IOCGETWAITPERIOD:
			copy_to_user(ptr, &sleeptime, sizeof(unsigned long));
			break;
		*/
		default:
			return (-EIO);
	}
	return 0;
}

static int pnxled_open(struct inode *inode,struct file *file)
{

	/*if (pnx_priv.ref_cnt != 0) {
		printk(KERN_WARNING NAME": exclusive access only\n");
		return (-EIO);
	}*/
	if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
		printk(KERN_WARNING "\n"NAME" is a write only device\n");
		return (-EIO);
	} 
	/*set the block mode and increase reference count*/
	//pnxled_priv.b_mode = ((file->f_flags & O_NONBLOCK) ? 0:1 );
	pnxled_priv.ref_cnt++;
	
	file->f_op = &pnxled_fops;
	file->private_data = (void *)&pnxled_priv;

	return 0;
}
//when close the device file
static int pnxled_release(struct inode *inode,struct file *file)
{
	pnxled_priv.ref_cnt--;
	return 0;
}

//exe when insmod the module
static int __init pnxled_init(void)
{
	/* do some usefull init work there*/
	int i;
	int miscret;

	memset(&pnxled_priv, 0, sizeof(struct pnxled_private));
	spin_lock_init(&pnxled_priv.lock);

	init_timer(&led_timer);

	old_GPIO_MC2 = pled->GPIO_MC2;
	pled->GPIO_MC2 = 0x008A0000;
	for(i=0;i<4;i++) {
		Led_Single(led_d[i], getled_value('8'));
		mdelay(100);
	}
	for(i=0;i<4;i++) {
		Led_Single(led_d[i], 0xff);
	}
	
	miscret = misc_register( &misc_pnxled );	
	if (miscret < 0) {
		printk(KERN_INFO NAME ": can't register misc pnx8550 led devices driver\n");
        	return miscret;
	}

	printk(KERN_INFO NAME ": pnx8550 led devices driver\n");
	return 0;
}
//exe when unload the module
static void __exit pnxled_cleanup(void)
{
	/*do some clean work there*/
	int i;
	del_timer_sync(&led_timer);
	for(i=0;i<4;i++) {
		Led_Single(led_d[i], getled_value('8'));
		mdelay(100);
	}
	for(i=0;i<4;i++) {
		Led_Single(led_d[i], 0xff);
	}
	misc_deregister(&misc_pnxled);
	pled->GPIO_MC2 = old_GPIO_MC2;
	printk(KERN_INFO NAME ": unload pnx8550 led devices driver now\n");
}
module_init(pnxled_init);
module_exit(pnxled_cleanup);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -