/*  Copyright (C) MOXA Inc. All rights reserved.

    This software is distributed under the terms of the
    MOXA License.  See the file COPYING-MOXA for details.
*/
/*
    2011-04-21 WadeLiang
		new release
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include "moxa_dk02.h" 
/* 
 * Open/release
 */

static int dk02_open (struct inode *inode, struct file *file) 
{
	p("open\n");
	return 0;
}

static int dk02_release (struct inode *inode, struct file *file) 
{
	p("release\n");
	return 0;
}


/* 
 *  I/O control 
 */
static int dk02_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg) 
{
	struct slot_info   si;
	unsigned char regv;

	if (copy_from_user(&si, (struct slot_info *)arg, sizeof(struct slot_info)))
		return -EFAULT;

	if ((cmd != IOCTL_SET_SLOT) || (si.num > 4) || (si.num < 1) || (si.value > 1) || (si.value < 0)) {
		printk("Incorrect parameter\n");
		return -EINVAL;
	}

	/* 
	 * For the 0xf5 register, the value are
	 * bit 7: slot 4, 1 active
	 * bit 6: slot 3, 0 active
	 * bit 5: slot 2, 1 active
	 * bit 4: slot 1, 0 active
	 */
	superio_enter_config();
	superio_set_logic_device(9);//GPIO
	superio_set_reg(0x0f, 0xf4); /* set dio */
	regv = superio_get_reg(0xf5);
	p("current reg value is %x\n", regv);
	switch (si.num) {
		case 4:
			regv = (regv & 0x7f) | (si.value << 7); 
			break;
		case 3:
			if (si.value) 
				regv &= 0xbf;
			else 
				regv |= 0x40;
			break;
		case 2:
			regv = (regv & 0xdf) | (si.value << 5);
			break;
		case 1:
			if (si.value)
				regv &= 0xef;
			else
				regv |= 0x10;
			break;
	}
	p("set regv = %x\n", regv);
	superio_set_reg(regv, 0xf5); /* control register */
	superio_exit_config();
	return 0;
}

static struct file_operations mx_fops = {
	.owner	=	THIS_MODULE,
	.llseek	=	NULL,
	.read		=	NULL,
	.write	=	NULL,
	.readdir	=	NULL,
	.poll		=	NULL,
	.ioctl	=   dk02_ioctl,
	.mmap		=	NULL,
	.open		=   dk02_open,
	.flush	=	NULL,
	.release	=   dk02_release,
	.fsync	=	NULL,
	.fasync	=	NULL,
	.lock		=	NULL,
};

static struct miscdevice mx_miscdev = {
	.minor = MX_MINOR_NUMBER,
	.name = MX_NAME,
	.fops = &mx_fops,
};

static int __init dk02_init_module (void) 
{
	int res;
	printk("initializing MOXA DK02 driver\n");

	/* register misc driver */
	res = misc_register(&mx_miscdev);
	if (res) {
		printk("Moxa DK02 driver: Register misc fail !\n");
		return res;
	}
	return 0;
}

/*
 * close and cleanup module
 */
static void __exit dk02_cleanup_module (void) 
{
	printk("cleaning up module\n");
	misc_deregister(&mx_miscdev);
}

module_init(dk02_init_module);
module_exit(dk02_cleanup_module);
MODULE_AUTHOR("Wade_liang@moxa.com");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MOXA DK02 module");

