#include <linux/config.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#define NAME "led_drv"
static int major = 231;
//MODULE_AUTHOR("gec");
//MODULE_DESCRIPTION("LED Driver");
//MODULE_LICENSE("GPL");
//module_param(major, int, 0);
//MODULE_PARM_DESC(major, "Major device number");
#define S3C2410_ADDR(x) (0xF0000000 + (x))
#define S3C24XX_VA_GPIO S3C2410_ADDR(0x00E00000)
#define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO)
#define S3C2410_GPACON *((volatile unsigned long*)S3C2410_GPIOREG(0x00))
#define S3C2410_GPADAT *((volatile unsigned long*)S3C2410_GPIOREG(0x04))
// 用到B6,B0?
// Port B
#define S3C2410_GPBCON *((volatile unsigned long*)S3C2410_GPIOREG(0x10))
#define S3C2410_GPBDAT *((volatile unsigned long*)S3C2410_GPIOREG(0x14))
#define S3C2410_GPBUP *((volatile unsigned long*)S3C2410_GPIOREG(0x18))
//用到G7,G6?
// Port G
#define S3C2410_GPGCON *((volatile unsigned long*)S3C2410_GPIOREG(0x60))
#define S3C2410_GPGDAT *((volatile unsigned long*)S3C2410_GPIOREG(0x64))
#define S3C2410_GPGUP *((volatile unsigned long*)S3C2410_GPIOREG(0x68))
#define Led1_ON() (S3C2410_GPBDAT &= ~(1<<6))
#define Led1_OFF() (S3C2410_GPBDAT |= (1<<6))
#define Led2_ON() (S3C2410_GPBDAT &= ~(1<<0))
#define Led2_OFF() (S3C2410_GPBDAT |= (1<<0))
#define Led3_ON() (S3C2410_GPGDAT &= ~(1<<7))
#define Led3_OFF() (S3C2410_GPGDAT |= (1<<7))
#define Led4_ON() (S3C2410_GPGDAT &= ~(1<<6))
#define Led4_OFF() (S3C2410_GPGDAT |= (1<<6))
/*
* LedDisp函数根据参数led来显示相应的Led。
*/
void LedDisp(int led)
{
int mask;
// 某位位置为1点亮,否则熄灭,可无限添加更多效果
// 0 全灭, 1-4依次单独点亮灯1-4,熄灭其余
int arr_mask[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,};// 效果掩码
if( led < 0 || led >= (sizeof(arr_mask)/sizeof(arr_mask[0])) )
return;
mask = arr_mask[led];// 根据输入的数字选择效果
(mask & (1<<0)) ? Led1_ON() : Led1_OFF(); // 对应位置为1点亮,否则熄灭
(mask & (1<<1)) ? Led2_ON() : Led2_OFF();
(mask & (1<<2)) ? Led3_ON() : Led3_OFF();
(mask & (1<<3)) ? Led4_ON() : Led4_OFF();
}
static int led_drv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
printk("led- ioctl: param %u %lu\n", cmd, arg);
LedDisp(arg);
return 0;
}
static int led_drv_open(struct inode *inode, struct file *file)
{
unsigned m = iminor(inode);
if (m > 63)
return -EINVAL;
printk("LED driver opened!\n");
return nonseekable_open(inode, file);
}
static int led_drv_release(struct inode *inode, struct file *file)
{
printk("LED driver released!\n");
return 0;
}
static struct file_operations led_drv_fops = {
.owner = THIS_MODULE,
.ioctl = led_drv_ioctl,
.open = led_drv_open,
.release = led_drv_release,
};
static int __init led_drv_init(void)
{
int temp;
int ret;
unsigned long tmp;
printk("LED Driver.\n");
/* 注册LED设备 */
ret = register_chrdev(major, NAME, &led_drv_fops);
if (ret < 0) {
printk("Unable to register character device!\n");
return ret;
}
/*
*初始化GPA-IO寄存器
*/
// B6,B0,G7,G6 for output
temp = S3C2410_GPBCON & (~((3<<12) | (3<<0))); // 屏蔽
S3C2410_GPBCON = temp | (1<<12) | (1<<0);
temp = S3C2410_GPGCON & (~((3<<14) | (3<<12))); // 屏蔽
S3C2410_GPGCON = temp | (1<<14) | (1<<12);
// 是否上拉
S3C2410_GPBUP &= ~((1<<6) | (1<<0)); // enable poll up
S3C2410_GPGUP &= ~((1<<7) | (1<<6)); // enable poll up
//S3C2410_GPBUP |= (1<<6) | (1<<0); // disable poll up
//S3C2410_GPGUP |= (1<<7) | (1<<6); // disable poll up
// 初始化B6,B0,G7,G6输出高电平,可能点亮或者熄灭LED
S3C2410_GPBDAT |= (1<<6) | (1<<0);
S3C2410_GPGDAT |= (1<<7) | (1<<6);
printk("LED Test Driver initiated.\n");
return 0;
}
static void __exit led_drv_cleanup(void)
{
int ret;
ret = unregister_chrdev(major, NAME);
if (ret < 0)
printk("Unable to register character device!\n");
else
printk("LED Test Driver unloaded!");
}
module_init(led_drv_init);
module_exit(led_drv_cleanup);