/************************************************************
 *
 * COPYRIGHT (C) HITACHI,LTD. 2002 ALL RIGHTS RESERVED.
 * WRITTEN BY HITACHI SYSTEMS DEVELOPMENT LABORATORY,
 *            HITACHI CENTRAL RESEARCH LABORATORY.
 *
 * Created by K.SERIZAWA <serizawa@sdl.hitachi.co.jp>
 *
 ************************************************************/

#include<linux/version.h>
#include<linux/module.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/string.h>	/* for memset() */
#include <linux/sched.h>
#include<linux/lkst_private.h>

static lkst_maskset_id maskset_id_new = LKST_MASKSET_ID_VOID;
static lkst_maskset_id maskset_id_orig = LKST_MASKSET_ID_VOID;
static lkst_maskset_id maskset_id_base = LKST_MASKSET_ID_VOID;
static struct lkst_maskset_param	maskset_param;
static struct lkst_maskset_body 	body;

static int	evhandler_id = LKST_EVHANDLER_ID_VOID;

static int	lkst_mod_init(void);
static void	lkst_mod_cleanup(void);

module_init(lkst_mod_init);
module_exit(lkst_mod_cleanup);

MODULE_AUTHOR("K. Serizawa <serizawa@sdl.hitachi.co.jp>");
MODULE_DESCRIPTION("LKST module to dump current buffers in panic().");
MODULE_LICENSE("GPL");

MODULE_PARM(maskset_id_base, "i");
MODULE_PARM(evhandler_id, "i");
MODULE_PARM_DESC(maskset_id_base, "ID of a maskset used as a template.");
MODULE_PARM_DESC(evhandler_id, "id of event-hanlder to regist.");

void lkst_evhandler_panicdump(void *phookrec, 
			      int event_type,
				lkst_arg_t arg1,
				lkst_arg_t arg2,
				lkst_arg_t arg3,
				lkst_arg_t arg4)
{
	lkst_buffer_dump_current_txt();
}

int lkst_evhandler_test_ctrl(void *buf, size_t bufsize)
{
	if ((buf)&&(strncmp(buf, "panic", 5) == 0))
		panic("LKST PANIC TEST");
	return (0);
}

static int lkst_mod_init()
{
	int	retval;
	int	i;
	lkst_maskset_id id;

	/* Register an event handler for panic dump. */
	retval = lkst_evhandler_register(evhandler_id,
					 "lkst_evhandler_panicdump",
					 &lkst_evhandler_panicdump,
					 &lkst_evhandler_test_ctrl);
	if (retval < 0) {
		printk(KERN_ERR "cannot register event-handler function!\n");
		return retval;
	}
	evhandler_id = (lkst_evhandler_id) retval;

	/* Initialize Maskset */
	body.len = LKST_MASKSET_TABLE_LEN_MAX;
				/* This ID can be defined as 
				   a module parameter. */
	maskset_param.id = maskset_id_base;
	maskset_param.maskset_size = LKST_MASKSET_SIZE(body.len);
	maskset_param.maskset = &body;

	/* copy from template. */
	if ((retval = lkst_maskset_read(&maskset_param)))
		goto mod_cleanup;

	for (i = 0; i < body.len; i++) {
		if (body.entry[i].event_type == LKST_ETYPE_O_PANIC ) {
				/* replace handler */
			body.entry[i].id = (lkst_evhandler_id)evhandler_id;
		}
	}
	strcpy(body.name, "maskset_panicdump");
	
	/* Write new maskset */
	maskset_param.id = LKST_MASKSET_ID_VOID;
	if ((retval = lkst_maskset_write(&maskset_param))) {
		goto mod_cleanup;
	}
	maskset_id_new = maskset_param.id;

	/* Switch to the maskset. */
	id = maskset_id_new;
	if ((retval = lkst_maskset_xchg(&id))) {
		goto mod_cleanup;
	}
	maskset_id_orig = id;

	return 0;
mod_cleanup:
	lkst_mod_cleanup();
	return retval < 0 ? retval : -1;
}

static void lkst_mod_cleanup()
{
  		/* Switch to saved maskset. */
	if (maskset_id_orig != LKST_MASKSET_ID_VOID)
		lkst_maskset_xchg(&maskset_id_orig);

		/* deregister the event handler. */
	if (evhandler_id != LKST_EVHANDLER_ID_VOID)
		lkst_evhandler_unregister((lkst_evhandler_id)evhandler_id);

		/* Clean up maskset */
	if ( maskset_id_new != LKST_MASKSET_ID_VOID )
		lkst_maskset_delete(maskset_id_new);

	return;
}

/* END */
