#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/atmbr2684.h>

#include "xdsl_types.h"
#include "xdsl_ctrl.h"
#include "xdsl_ctrl_api.h"

ctrl_pkt_t ctrl_buf_master, ctrl_buf_slave;

int xdsl_ctrl_transmit(ctrl_pkt_t *ctrlp, uint8 category, uint8 sleep)
{
	int res=0;

	switch(category) {

	#if defined(CONFIG_XDSL_CTRL_ON_SOC)
	case CTRL_2DSL_SET:
		xdsl_ctrl_set(ctrlp, sleep);
		break;

	case CTRL_2DSL_GET:
		if (ctrlp->protocol==XDSL_CMD_GET || ctrlp->protocol==PTM_CMD_GET){
			res = xdsl_ctrl_get(ctrlp, sleep);
		}
		break;
	#endif

	#if defined(CONFIG_XDSL_CTRL_ON_DSL)
	case CTRL_2SOC_RET:
		xdsl_ctrl_return_data(ctrlp);
		break;
	#endif

	#if defined(CONFIG_PTM_BONDING_MASTER)
	case CTRL_2SLAVE_RET:
		bonding_master_return_data(ctrlp, sleep);
		break;
	#endif

	#if defined(CONFIG_PTM_BONDING_SLAVE)
	case CTRL_2MASTER_SET:
		bonding_slave_set_master(ctrlp, sleep);
		break;

	case CTRL_2MASTER_GET:
		if (ctrlp->protocol==XDSL_CMD_GET){
			res = bonding_slave_get_master(ctrlp, sleep);
		}
		break;
	#endif

		break;


	default:
		break;
	}
	return res;
}

int xdsl_ctrl_tx_final(uint8 category, uint8 protocol, uint8 devnum, uint32 command,
					 uint32 arg, uint32 argsize, uint32 ret, uint32 seg_num)
{
	ctrl_pkt_t *ctrlp;
	int i, res=0;
	unsigned char *argp;
	unsigned char sleep = 1;

#if defined(CONFIG_PTM_BONDING_MASTER)
	if (category==CTRL_2DSL_SET || category==CTRL_2DSL_GET)
		ctrlp = &ctrl_buf_master;
	else
		ctrlp = &ctrl_buf_slave;
#elif defined(CONFIG_PTM_BONDING_SLAVE)
	if (category==CTRL_2MASTER_SET || category==CTRL_2MASTER_GET)
		ctrlp = &ctrl_buf_slave;
	else
		ctrlp = &ctrl_buf_master;
#endif

	ctrlp->devnum = devnum;
	ctrlp->category = category;
	ctrlp->protocol = protocol;
	ctrlp->command = htonl(command);
	ctrlp->argsize = htonl(argsize);

	switch (protocol)
	{
		case XDSL_CMD_SET:
		case XDSL_CMD_GET:
		{
			i = 0;

			if (command==RLCM_UserSetDslData || command==RLCM_UserGetDslData){
				ctrlp->msg = htonl(*(int*)arg);
				argp = (unsigned char*)(*((int*)arg+1));
                        // protocol: XDSL_CMD_SET
			} else if (protocol == XDSL_CMD_SET){
				argp = (unsigned char*)arg;
			// protocol: XDSL_CMD_GET
			} else {
				argp = (unsigned char*)arg;
			}

			if (arg){
				memcpy(ctrlp->arg, argp, (ctrlp->argsize));
			}

			break;
		}
		case XDSL_ERB_SET:
		{
			argp = (unsigned char*)arg;
			
			for (i=0; i<argsize; i++){
				ctrlp->rxbuf[i] = argp[ seg_num*DSL_RXBUF_MAX_SIZE+i ];
			}
			erb_printk("Slave send erb to Master\n");
			if (ctrlp->command != 0) {
				printk("ctrlp->command = %d\n", ctrlp->command);
				dump_stack();
				ctrlp->command = 0;
			}
			erb_dump_ctrlp(ctrlp);

			break;
		}			

		case PTM_CMD_SET:
		{
			sleep = 0;
			if (arg && argsize>0){
				argp = (unsigned char*)arg;
				memcpy(ctrlp->arg, argp, argsize);
			}
			break;
		}

		case PTM_CMD_GET:
		{
			sleep = 0;
			if (arg && argsize>0){
				argp = (unsigned char*)arg;
				memcpy(ctrlp->arg, argp, argsize);
			}
			break;
		}

		case XDSL_CMD_DATA:
		case XDSL_CMD_DATA_EOF:
		{
			ctrlp->ret = htonl(ret);
			if (arg){
				i = 0;
				if (command==RLCM_UserGetDslData){
					ctrlp->msg = htonl(*(int*)arg);
					argp = (unsigned char*)(*((int*)arg+1));
				} else {  
					argp = (unsigned char*)arg;
				}	

				for (i=0; i<argsize; i++){
					ctrlp->rxbuf[i] = argp[ seg_num*DSL_RXBUF_MAX_SIZE+i ];
				}
			}	
			break;
		}

		case PTM_CMD_DATA:
		{
			
			ctrlp->argsize = 4;
			argp = (unsigned char*)(&ret);
	
			for (i=0; i<4; i++){
				ctrlp->rxbuf[i] = argp[i];
			}

			break;
		}

		default:
			break;
	}

	res = xdsl_ctrl_transmit(ctrlp, category, sleep);

	return res;
}


void xdsl_ctrl_tx_init(void)
{
}