/*****************************************************************************/
/* Copyright (c) 2008 NXP B.V.                                               */
/*                                                                           */
/* This program is free software; you can redistribute it and/or modify      */
/* it under the terms of the GNU General Public License as published by      */
/* the Free Software Foundation, using version 2 of the License.             */
/*                                                                           */
/* This program is distributed in the hope that it will be useful,           */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
/* GNU General Public License for more details.                              */
/*                                                                           */
/* You should have received a copy of the GNU General Public License         */
/* along with this program; if not, write to the Free Software               */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307       */
/* USA.                                                                      */
/*                                                                           */
/*****************************************************************************/

#include "common.h"
#include <linux/moduleparam.h>

/* It's not recommended to use OSAL on non-preemptible kernel */
#ifndef CONFIG_PREEMPT
#warning Its not recommended to use OSAL on non-preemptible kernel
#endif

#define DEFAULT_RR_PRIO_START 21
int rr_prio_start = DEFAULT_RR_PRIO_START;

#define DEFAULT_RR_PRIO_MAPPING 1
int rr_prio_mapping = DEFAULT_RR_PRIO_MAPPING;

#define DEFAULT_PRIO_1_MAPPING 9
int prio_1_mapping = DEFAULT_PRIO_1_MAPPING;

int osal_debug_level = 0;

int __init osal_module_init(void)
{
	int ret;

	if (rr_prio_start < 1 || rr_prio_start > 40) {
		printk(KERN_ERR "osal: rr_prio_start value out of range [1..40]\n");
		return -EINVAL;
	}

	if (rr_prio_mapping < 1 || rr_prio_mapping > rr_prio_start + 36) {
		printk(KERN_ERR "osal: rr_prio_mapping value out of range [1..rr_prio_start+36]\n");
		return -EINVAL;
	}

	if (prio_1_mapping < rr_prio_start - 22 || prio_1_mapping > 19) {
		printk(KERN_ERR "osal: rr_prio_mapping value out of range [rr_prio_start-22..19]\n");
		return -EINVAL;
	}

	ret = osal_task_submodule_init();
	if (ret)
		return ret;

	ret = osal_time_submodule_init();
	if (ret)
		goto err1;

	ret = osal_int_submodule_init();
	if (ret)
		goto err2;

	ret = osal_sem_submodule_init();
	if (ret)
		goto err3;

	ret = osal_mutex_submodule_init();
	if (ret)
		goto err4;

	ret = osal_event_submodule_init();
	if (ret)
		goto err5;

	ret = osal_queue_submodule_init();
	if (ret)
		goto err6;

#ifdef CONFIG_FW_LOADER
	ret = osal_firmware_submodule_init();
	if (ret)
		goto err7;
#endif

	printk(KERN_NOTICE "osal: module ready\n");
	return 0;

#ifdef CONFIG_FW_LOADER
err7:
	osal_queue_submodule_uninit();
#endif
err6:
	osal_event_submodule_uninit();
err5:
	osal_mutex_submodule_uninit();
err4:
	osal_sem_submodule_uninit();
err3:
	osal_int_submodule_uninit();
err2:
	osal_time_submodule_uninit();
err1:
	osal_task_submodule_uninit();

	return ret;
}

void __exit osal_module_cleanup(void)
{
	osal_task_submodule_uninit();
	osal_time_submodule_uninit();
	osal_int_submodule_uninit();
	osal_sem_submodule_uninit();
	osal_mutex_submodule_uninit();
	osal_event_submodule_uninit();
	osal_queue_submodule_uninit();
#ifdef CONFIG_FW_LOADER
	osal_firmware_submodule_uninit();
#endif	
	printk(KERN_NOTICE "osal: module removed\n");
}

module_init(osal_module_init);
module_exit(osal_module_cleanup);

MODULE_AUTHOR("Nikita V. Youshchenko <yoush.cs.msu.su>, NXP B.V.");
MODULE_DESCRIPTION("OSAL in-kernel API");
/* This module has to be GPL. If not, it can't be linked against GPL-only
 * kernel symbols, such as sched_setscheduler */
MODULE_LICENSE("GPL v2");

/* Parameters that control scheduler priorities */
module_param(rr_prio_start, int, 0644);
MODULE_PARM_DESC(rr_prio_start, "First OSAL priority value that maps to SCHED_RR");

module_param(rr_prio_mapping, int, 0644);
MODULE_PARM_DESC(rr_prio_mapping, "Linux SCHED_RR priority value for OSAL rr_prio_start priority");

module_param(prio_1_mapping, int, 0644);
MODULE_PARM_DESC(prio_1_mapping, "Linux nice value for OSAL priority 1");

module_param(osal_debug_level, int, 0644);
MODULE_PARM_DESC(osal_debug_level, "Increase from 0 to 1 to enable Timedoctor tracing");
