#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>

MODULE_LICENSE("GPL");

static struct class *led_class;
static struct class_device *led_class_device;

volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;

static int led_drv_open(struct inode *inode, struct file *file)
{
    *gpfcon &= ~((4 << 4*2) | (3 << 5*2) | (3 << 6*2));
    *gpfcon |= ((1 << 4*2) | (1 << 5*2) | (1 << 6*2));
    
    return 0;
}

static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    int val
    
    copy_from_user(&val, buf, count);
    
    if (val)
    {
        *gpfdat |= ((1 << 4*2) | (1 << 5*2) | (1 << 6*2));
    }
    else
    {
        *gpfdat &= ~((1 << 4*2) | (1 << 5*2) | (1 << 6*2));
    }
    
    return 0;
}

static struct file_operations led_fops = {
    .owner = THIS_MODULE,
    .open  = led_drv_open,
    .write = led_drv_write,
};

int major;
static int led_drv_init(void)
{
    major = register_chrdev(0, "led", &led_fops);
    led_class = class_create(THIS_MODULE, "led");
    led_class_device = class_device_create(led_class, NULL, MKDEV(major, 0), NULL, "abc"); /* 在应用层open("/dev/abc", O_RDWR)  */
    
    gpfcon = (volatile unsigned long *)ioremap(0x56000000, 16);
    gpfdat = gpfcon + 1;
   
    return 0;
}

static int led_drv_exit(void)
{
    unregister_chrdev(major, "led");
    class_device_unregister(led_class_device);
    class_destroy(led_class);
    iounmap(gpfcon);

    return 0;
}

module_init(led_drv_init);
module_exit(led_drv_exit);