initial merge of infineon code for amazon, pci is still broken a bit. a big thank you goes to infineon for providing info and reference code
initial merge of infineon code for amazon, pci is still broken a bit. a big thank you goes to infineon for providing info and reference code

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@8137 3c298f89-4303-0410-b956-a3cf2f4a3e73

--- /dev/null
+++ b/target/linux/amazon-2.6/Makefile
@@ -1,1 +1,26 @@
+# 
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
 
+ARCH:=mips
+BOARD:=amazon
+BOARDNAME:=Infineon Amazon
+FEATURES:=squashfs jffs2 broken
+
+define Target/Description
+	Build firmware images for Infineon Amazon boards
+endef
+
+KERNELNAME:="uImage"
+
+include $(INCLUDE_DIR)/kernel-build.mk
+
+# include the profiles
+-include profiles/*.mk
+
+$(eval $(call BuildKernel))
+

--- /dev/null
+++ b/target/linux/amazon-2.6/base-files/default/etc/config/network
@@ -1,1 +1,15 @@
+# Copyright (C) 2006 OpenWrt.org
 
+config interface loopback
+	option ifname	lo
+	option proto	static
+	option ipaddr	127.0.0.1
+	option netmask	255.0.0.0
+
+config interface lan
+	option ifname	eth1
+	option type 	bridge
+	option proto	static
+	option ipaddr	192.168.1.1
+	option netmask	255.255.255.0
+

--- /dev/null
+++ b/target/linux/amazon-2.6/config/default
@@ -1,1 +1,212 @@
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+CONFIG_AMAZON=y
+CONFIG_AMAZON_ASC_UART=y
+CONFIG_AMAZON_MTD=y
+CONFIG_AMAZON_NET_SW=y
+CONFIG_AMAZON_PCI=y
+CONFIG_AMAZON_WDT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+# CONFIG_ATM is not set
+# CONFIG_ATMEL is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_BCM43XX is not set
+CONFIG_BITREVERSE=y
+# CONFIG_BT is not set
+CONFIG_CMDLINE="console=ttyS0,115200 rootfstype=squashfs,jffs2 init=/bin/sh"
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_SYNC=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+CONFIG_CPU_MIPSR1=y
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_DM9000 is not set
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_GENERIC_GPIO is not set
+# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+# CONFIG_GEN_RTC is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAVE_STD_PC_SERIAL_PORT=y
+# CONFIG_HERMES is not set
+# CONFIG_HOSTAP is not set
+CONFIG_HW_HAS_PCI=y
+CONFIG_HW_RANDOM=y
+# CONFIG_I2C is not set
+# CONFIG_IDE is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+CONFIG_IRQ_CPU=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_VR41XX is not set
+CONFIG_MIPS=y
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_EV64120 is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_MTX1 is not set
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MIPS_VPE_LOADER is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+CONFIG_MTD=y
+# CONFIG_MTD_ABSENT is not set
+CONFIG_MTD_AMAZON_BUS_WIDTH_16=y
+# CONFIG_MTD_AMAZON_BUS_WIDTH_32 is not set
+# CONFIG_MTD_AMAZON_BUS_WIDTH_8 is not set
+# CONFIG_MTD_AMAZON_FLASH_SIZE_16 is not set
+# CONFIG_MTD_AMAZON_FLASH_SIZE_2 is not set
+CONFIG_MTD_AMAZON_FLASH_SIZE_4=y
+# CONFIG_MTD_AMAZON_FLASH_SIZE_8 is not set
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_MTD_BLOCK2MTD is not set
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_GEOMETRY is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PHRAM is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_BANKWIDTH=0
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_START=0x0
+# CONFIG_MTD_PLATRAM is not set
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-3
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_NET_PCI is not set
+CONFIG_NET_SCH_FIFO=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_PNPACPI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_RTC is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_TRAD_SIGNALS=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_USB is not set
 

--- /dev/null
+++ b/target/linux/amazon-2.6/files/arch/mips/amazon/Kconfig
@@ -1,1 +1,64 @@
+# copyright 2007 john crispin <blogic@openwrt.org>
 
+menu "Amazon built-in"
+
+config AMAZON_ASC_UART
+	bool "Amazon asc uart"
+	select SERIAL_CORE
+	select SERIAL_CORE_CONSOLE
+	default y
+
+config AMAZON_PCI
+	bool "Amazon PCI support"
+	default y
+	select HW_HAS_PCI
+	select PCI
+
+config AMAZON_NET_SW
+	bool "Amazon network"
+	default y
+
+config AMAZON_WDT
+	bool "Amazon watchdog timer"
+	default y
+
+config AMAZON_MTD
+	bool "Amazon MTD map"
+	default y
+
+choice 
+	prompt "Flash Size"
+	depends on AMAZON_MTD
+
+config MTD_AMAZON_FLASH_SIZE_2
+	bool "2MB"
+
+config MTD_AMAZON_FLASH_SIZE_4
+	bool "4MB"
+
+config MTD_AMAZON_FLASH_SIZE_8
+	bool "8MB"
+
+config MTD_AMAZON_FLASH_SIZE_16
+	bool "16MB"
+
+endchoice
+
+choice 
+	prompt "Bus Width"
+	depends on AMAZON_MTD
+
+config MTD_AMAZON_BUS_WIDTH_8
+	bool "8-bit"
+
+config MTD_AMAZON_BUS_WIDTH_16
+	bool "16-bit"
+
+config MTD_AMAZON_BUS_WIDTH_32
+	bool "32-bit"
+
+endchoice
+
+
+endmenu
+

--- /dev/null
+++ b/target/linux/amazon-2.6/files/arch/mips/amazon/Makefile
@@ -1,1 +1,10 @@
+#
+#  Copyright 2007 openwrt.org
+#       John Crispin <blogic@openwrt.org>
+#
+# Makefile for Infineon Amazon
+#
+obj-y := dma-core.o interrupt.o prom.o setup.o
+obj-$(CONFIG_PCI) += pci.o
 
+

--- /dev/null
+++ b/target/linux/amazon-2.6/files/arch/mips/amazon/dma-core.c
@@ -1,1 +1,1456 @@
-
+/*
+ *   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; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   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.
+ */
+//-----------------------------------------------------------------------
+/*
+ * Description:
+ *	Driver for Infineon Amazon DMA
+ */
+//-----------------------------------------------------------------------
+/* Author:	Wu Qi Ming[Qi-Ming.Wu@infineon.com]
+ * Created:	7-April-2004
+ */
+//-----------------------------------------------------------------------
+/* History
+ * Last changed on: 4-May-2004
+ * Last changed by: <peng.liu@infineon.com>
+ * Reason: debug
+ */
+//----------------------------------------------------------------------- 
+/* Last changed on: 03-Dec-2004
+ * Last changed by: peng.liu@infineon.com
+ * Reason: recover from TPE bug 
+ */
+
+//000004:fchang 2005/6/2 Modified by Linpeng as described below
+//----------------------------------------------------------------------- 
+/* Last changed on: 28-Jan-2004
+ * Last changed by: peng.liu@infineon.com
+ * Reason: 
+ * - handle "out of memory" bug
+ */
+//000003:tc.chen 2005/06/16 fix memory leak when Tx buffer full (heaving traffic).
+//507261:tc.chen 2005/07/26 re-organize code address map to improve performance.
+
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+#define MODVERSIONS
+#endif
+
+#if defined(MODVERSIONS) && !defined(__GENKSYMS__)
+#include <linux/modversions.h>
+#endif
+
+#ifndef EXPORT_SYMTAB
+#define EXPORT_SYMTAB			/* need this one 'cause we export symbols */
+#endif
+
+#undef DMA_NO_POLLING
+
+/* no TX interrupt handling */
+#define NO_TX_INT
+/* need for DMA workaround */
+#undef AMAZON_DMA_TPE_AAL5_RECOVERY
+
+#ifdef AMAZON_DMA_TPE_AAL5_RECOVERY
+#define MAX_SYNC_FAILS 1000000	// 000004:fchang
+unsigned int dma_sync_fails = 0;
+unsigned int total_dma_tpe_reset = 0;
+int (*tpe_reset) (void);
+int (*tpe_start) (void);
+int (*tpe_inject) (void);
+#endif							// AMAZON_DMA_TPE_AAL5_RECOVERY
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/selection.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/irq.h>
+#include <asm/amazon/amazon_dma.h>
+#include "dma-core.h"
+
+#define AMAZON_DMA_EMSG(fmt, args...) printk( KERN_ERR  "%s: " fmt,__FUNCTION__, ## args)
+
+static irqreturn_t dma_interrupt(int irq, void *dev_id);
+extern void mask_and_ack_amazon_irq(unsigned int irq_nr);
+
+/***************************************** global data *******************************************/
+u64 *g_desc_list;
+dev_list *g_current_dev = NULL;
+dev_list *g_head_dev = NULL;
+dev_list *g_tail_dev = NULL;
+channel_info g_log_chan[CHAN_TOTAL_NUM + 1];
+struct proc_dir_entry *g_amazon_dma_dir;
+static u8 rx_chan_list_len = 0;
+static u8 tx_chan_list_len = 0;
+static int rx_chan_list[RX_CHAN_NUM + 1];
+static int tx_chan_list[TX_CHAN_NUM + 1];
+static u32 comb_isr_mask[CHAN_TOTAL_NUM];
+
+static inline int is_rx_chan(int chan_no)
+/*judge if this is an rx channel*/
+{
+	int result = 0;
+	if (chan_no < RX_CHAN_NUM)
+		result = 1;
+	return result;
+}
+
+/* Ugly, Channel ON register is badly mapped to channel no. */
+static u8 ch_on_mapping[CHAN_TOTAL_NUM] =
+	{ 0, 1, 2, 3, 6, 7, 10, 4, 5, 8, 9, 11 };
+
+/* Brief: 	check wether the chan_no is legal
+ * Parameter:  	chan_no: logical channel number
+ * Return: 	0 if is not valid
+ *		1 if is valid
+ */
+static inline int is_valid_dma_ch(int chan_no)
+{
+	return ((chan_no >= 0) && (chan_no < CHAN_TOTAL_NUM));
+}
+
+/* Brief:	check whether a channel is open through Channel ON register
+ * Parameter:  chan_no: logical channel number
+ * Return: 	1 channel is open
+ *		0 not yet
+ *		EINVAL: invalid parameter
+ */
+static inline int is_channel_open(int chan_no)
+{
+	return (AMAZON_DMA_REG32(AMAZON_DMA_CH_ON) &
+			(1 << ch_on_mapping[chan_no]));
+}
+
+/* Brief: add a list entry
+ * Description: 
+ * 	always add to the tail and no redundancy allowed. (i.e. entries are unique)
+ *	0	: entry deleted
+ *	<0	: not deleted (due to not unique)
+ */
+static inline int _add_list_entry(int *list, int size_of_list, int entry)
+{
+	int i;
+	for (i = 0; i < size_of_list; i++) {
+		if (list[i] == entry)
+			break;
+		if (list[i] < 0) {
+			list[i] = entry;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+/* Brief: delete a list entry
+ * Description:
+ *	find the entry and remove it. shift all entries behind it one step forward if necessary\
+ * Return:
+ *	0	: entry deleted
+ *	<0	: not deleted (due to not found?)
+ */
+static inline int _delete_list_entry(int *list, int size_of_list,
+									 int entry)
+{
+	int i, j;
+	for (i = 0; i < size_of_list; i++) {
+		if (list[i] == entry) {
+			for (j = i; j < size_of_list; j++) {
+				list[j] = list[j + 1];
+				if (list[j + 1] < 0) {
+					break;
+				}
+			}
+			return 0;
+		}
+	}
+	return -1;
+}
+
+/* Brief:	enable a channel through Channel ON register
+ * Parameter:  chan_no: logical channel number
+ * Description:	
+ * 	Please don't open a channel without a valid descriptor (hardware pitfall)
+ */
+static inline void open_channel(int chan_no)
+{
+	AMAZON_DMA_REG32(AMAZON_DMA_CH_ON) |= (1 << ch_on_mapping[chan_no]);
+	if (is_rx_chan(chan_no)) {
+		if (_add_list_entry(rx_chan_list, RX_CHAN_NUM, chan_no) == 0) {
+			rx_chan_list_len++;
+		} else {
+			AMAZON_DMA_DMSG("cannot add chan %d to open list\n", chan_no);
+		}
+	} else {
+		if (_add_list_entry(tx_chan_list, TX_CHAN_NUM, chan_no) == 0) {
+			tx_chan_list_len++;
+		} else {
+			AMAZON_DMA_DMSG("cannot add chan %d to open list\n", chan_no);
+		}
+	}
+}
+
+/* Brief:	disable a channel through Channel ON register
+ * Parameter:  chan_no: logical channel number
+ */
+
+static inline void close_channel(int chan_no)
+{
+	AMAZON_DMA_REG32(AMAZON_DMA_CH_ON) &= ~(1 << ch_on_mapping[chan_no]);
+	if (is_rx_chan(chan_no)) {
+		if (_delete_list_entry(rx_chan_list, RX_CHAN_NUM, chan_no) == 0) {
+			rx_chan_list_len--;
+		} else {
+			AMAZON_DMA_DMSG("cannot remove chan %d from open list \n",
+							chan_no);
+		}
+	} else {
+		if (_delete_list_entry(tx_chan_list, TX_CHAN_NUM, chan_no) == 0) {
+			tx_chan_list_len--;
+		} else {
+			AMAZON_DMA_DMSG("cannot remove chan %d from open list \n",
+							chan_no);
+		}
+	}
+}
+
+/* Brief: clear RX interrupt
+ */
+inline void rx_chan_clear_isr(int chan_no)
+{
+#ifdef DMA_NO_POLLING
+	AMAZON_DMA_REG32(AMAZON_DMA_CH0_ISR + chan_no * AMAZON_DMA_CH_STEP) =
+		(AMAZON_DMA_REG32
+		 (AMAZON_DMA_CH0_ISR +
+		  chan_no *
+		  AMAZON_DMA_CH_STEP) & (DMA_ISR_CPT | DMA_ISR_EOP | DMA_ISR_CMDCPT
+								 | DMA_ISR_DURR));
+#else
+	AMAZON_DMA_REG32(AMAZON_DMA_CH0_ISR + chan_no * AMAZON_DMA_CH_STEP) =
+		(AMAZON_DMA_REG32
+		 (AMAZON_DMA_CH0_ISR +
+		  chan_no *
+		  AMAZON_DMA_CH_STEP) & (DMA_ISR_CPT | DMA_ISR_EOP |
+								 DMA_ISR_CMDCPT));
+#endif
+}
+
+
+/* Brief:	hacking function, this will reset all descriptors back to DMA
+ */
+static void dma_reset_all_descriptors(int chan_no)
+{
+	volatile struct rx_desc *rx_desc_p = NULL;
+	int i;
+	rx_desc_p =
+		(struct rx_desc *) g_desc_list +
+		g_log_chan[chan_no].offset_from_base;
+	for (i = 0; i < g_log_chan[chan_no].desc_len; i++) {
+		rx_desc_p->status.word &=
+			(~(DMA_DESC_SOP_SET | DMA_DESC_EOP_SET | DMA_DESC_CPT_SET));
+		rx_desc_p->status.word |=
+			(DMA_DESC_OWN_DMA | g_log_chan[chan_no].packet_size);
+		rx_desc_p++;
+	}
+}
+
+#ifdef AMAZON_DMA_TPE_AAL5_RECOVERY
+/* Brief:	Reset DMA descriptors 
+ */
+static void amazon_dma_reset_tpe_rx(int chan_no)
+{
+	struct tx_desc *tx_desc_p = NULL;
+	int j, i = 0;
+
+	// wait until all TX channels stop transmitting
+	for (j = 9; j <= 10; j++) {
+		tx_desc_p =
+			(struct tx_desc *) g_desc_list +
+			g_log_chan[j].offset_from_base;
+		for (i = 0; i < g_log_chan[j].desc_len; i++) {
+			while ((tx_desc_p->status.field.OWN != CPU_OWN)) {
+				AMAZON_DMA_DMSG("DMA TX in progress\n");	// 000004:fchang
+				udelay(100);
+			}
+			tx_desc_p++;
+		}
+	}
+
+	if (tpe_reset) {
+		total_dma_tpe_reset++;
+		AMAZON_DMA_DMSG
+			("\n===============resetting TPE========================== \n");
+		if ((*tpe_reset) ()) {
+			panic("cannot reset TPE engien\n");	// 000004:fchang
+		}
+	} else {
+		panic("no tpe_reset function\n");	// 000004:fchang
+		return;
+	}
+	dma_reset_all_descriptors(chan_no);
+	rx_chan_clear_isr(chan_no);
+	mb();
+
+	// send EoP
+	if (tpe_inject) {
+		if ((*tpe_inject) ()) {
+			panic("cannot inject a cell\n");	// 000004:fchang
+		}
+	} else {
+		AMAZON_DMA_EMSG("no tpe_inject function\n");
+		return;
+	}
+	mb();
+	while (1) {
+		if (AMAZON_DMA_REG32
+			(AMAZON_DMA_CH0_ISR +
+			 chan_no * AMAZON_DMA_CH_STEP) & (DMA_ISR_CPT)) {
+			rx_chan_clear_isr(chan_no);
+			mb();
+			dma_reset_all_descriptors(chan_no);
+			if (g_log_chan[chan_no].current_desc ==
+				(g_log_chan[chan_no].desc_len - 1)) {
+				g_log_chan[chan_no].current_desc = 0;
+			} else {
+				g_log_chan[chan_no].current_desc++;
+			}
+			break;
+		}
+		mdelay(1);
+	}
+	mb();
+#if 0
+	AMAZON_DMA_REG32(AMAZON_DMA_CH_ON) &= ~(1 << ch_on_mapping[chan_no]);
+	while (AMAZON_DMA_REG32(AMAZON_DMA_CH_ON) &
+		   (1 << ch_on_mapping[chan_no])) {
+		printk("TPE channel still on\n");
+		mdelay(1);
+	}
+
+	// AMAZON_DMA_REG32(AMAZON_DMA_CH_RST) = (1<<chan_no);
+	mb();
+	AMAZON_DMA_REG32(AMAZON_DMA_CH0_MSK + chan_no * AMAZON_DMA_CH_STEP) =
+		0x32;
+	mb();
+	rx_chan_clear_isr(chan_no);
+	dma_reset_all_descriptors(chan_no);
+	mb();
+	AMAZON_DMA_REG32(AMAZON_DMA_CH_ON) |= (1 << ch_on_mapping[chan_no]);
+	// g_log_chan[chan_no].current_desc=0;
+	mb();
+	mdelay(1);
+#endif
+	if (tpe_start) {
+		(*tpe_start) ();
+	} else {
+		AMAZON_DMA_EMSG("cannot restart TPE engien\n");
+	}
+}
+#endif							// AMAZON_DMA_TPE_AAL5_RECOVERY
+
+
+/* Brief:	RX channel interrupt handler 
+ * Parameter:	RX channel no
+ * Description: the interrupt handler for each RX channel
+ *		1. check descriptor, clear ISR if no incoming packet
+ *		2. inform upper layer to receive packet (and update descriptors)
+ */
+inline void rx_chan_intr_handler(int chan_no)
+{
+	volatile struct rx_desc *rx_desc_p = NULL;
+
+	/* fetch the current descriptor */
+	rx_desc_p =
+		(struct rx_desc *) g_desc_list +
+		g_log_chan[chan_no].offset_from_base +
+		g_log_chan[chan_no].current_desc;
+
+	g_log_chan[chan_no].dma_dev->current_rx_chan =
+		chan_no - g_log_chan[chan_no].dma_dev->logic_rx_chan_base;
+
+	// workaround for DMA pitfall: complete bit set happends before the
+	// other two bits (own,eop) are ready
+	if ((rx_desc_p->status.field.EoP != 1)
+		|| (rx_desc_p->status.field.OWN != CPU_OWN)
+		|| (rx_desc_p->status.field.data_length ==
+			g_log_chan[chan_no].packet_size)) {
+#ifdef AMAZON_DMA_TPE_AAL5_RECOVERY
+		if (chan_no == 4 || chan_no == 5) {
+			dma_sync_fails++;
+			if (dma_sync_fails > MAX_SYNC_FAILS) {
+				// detect bug
+				rx_desc_p0 =
+					(struct rx_desc *) g_desc_list +
+					g_log_chan[chan_no].offset_from_base;
+				rx_desc_p1 =
+					(struct rx_desc *) g_desc_list +
+					g_log_chan[chan_no].offset_from_base + 1;
+				if ((rx_desc_p0->status.field.OWN == CPU_OWN
+					 && rx_desc_p0->status.field.EoP != 1)
+					&& (rx_desc_p1->status.field.OWN == CPU_OWN
+						&& rx_desc_p1->status.field.EoP != 1)) {
+					amazon_dma_reset_tpe_rx(chan_no);
+					dma_sync_fails = 0;
+					return;
+				}
+				dma_sync_fails = 0;
+				AMAZON_DMA_DMSG("too many times ch:%d\n", chan_no);	// 000004:fchang
+				return;
+			}
+			udelay(10);			// 000004:fchang
+		}
+#endif							// //AMAZON_DMA_TPE_AAL5_RECOVERY
+		return;
+	}
+
+	/* inform the upper layer to receive the packet */
+	g_log_chan[chan_no].intr_handler(g_log_chan[chan_no].dma_dev, RCV_INT);
+	/* check the next descriptor, if still contains the incoming packet,
+	   then do not clear the interrupt status */
+	rx_desc_p =
+		(struct rx_desc *) g_desc_list +
+		g_log_chan[chan_no].offset_from_base +
+		g_log_chan[chan_no].current_desc;
+	if (!
+		((rx_desc_p->status.field.OWN == CPU_OWN)
+		 && (rx_desc_p->status.field.C == 1))) {
+		rx_chan_clear_isr(chan_no);
+	}
+}
+
+
+/* Brief:	TX channel interrupt handler 
+ * Parameter:	TX channel no
+ * Description: the interrupt handler for each TX channel
+ * 1. check all the descripters,if any of them had transmitted a packet, then free buffer
+ * because we cannot garantee the which one has already transmitted out, we have to go through all the descriptors here
+ * 2. clear the interrupt status bit
+ */
+inline void tx_chan_intr_handler(int chan_no)
+{
+	struct tx_desc *tx_desc_p = NULL;
+	int i = 0;
+
+	tx_desc_p =
+		(struct tx_desc *) g_desc_list +
+		g_log_chan[chan_no].offset_from_base;
+
+	for (i = 0; i < g_log_chan[chan_no].desc_len; i++) {
+		if ((tx_desc_p->status.field.OWN == CPU_OWN)
+			&& (tx_desc_p->status.field.C == 1)) {
+			/* if already transmitted, then free the buffer */
+			g_log_chan[chan_no].
+				buffer_free((u8 *) __va(tx_desc_p->Data_Pointer),
+							g_log_chan[chan_no].opt[i]);
+			tx_desc_p->status.field.C = 0;
+			/* inform the upper layer about the completion of the
+			   transmitted packet, the upper layer may want to free the
+			   packet */
+			g_log_chan[chan_no].intr_handler(g_log_chan[chan_no].dma_dev,
+											 TRANSMIT_CPT_INT);
+		}
+		tx_desc_p++;
+	}
+
+	/* after all these operations, clear the interrupt status bit */
+	AMAZON_DMA_REG32(AMAZON_DMA_CH0_ISR + chan_no * AMAZON_DMA_CH_STEP) =
+		(AMAZON_DMA_REG32
+		 (AMAZON_DMA_CH0_ISR +
+		  chan_no *
+		  AMAZON_DMA_CH_STEP) & (DMA_ISR_CPT | DMA_ISR_EOP |
+								 DMA_ISR_CMDCPT));
+}
+
+/*	Brief:	DMA interrupt handler
+ */
+static irqreturn_t dma_interrupt(int irq, void *dev_id)
+{
+	int i = 0;
+	int chan_no;
+	u32 isr = 0;
+#ifdef NO_TX_INT				// 000004:fchang
+	static int cnt = 0;			// 000004:fchang
+#endif							// 000004:fchang
+	while ((isr =
+			AMAZON_DMA_REG32(AMAZON_DMA_COMB_ISR)) & (COMB_ISR_RX_MASK |
+													  COMB_ISR_TX_MASK)) {
+		if (isr & COMB_ISR_RX_MASK) {
+			// RX Channels: start WFQ algorithm
+			chan_no = CHAN_TOTAL_NUM;
+			for (i = 0; i < RX_CHAN_NUM; i++) {
+				if ((isr & (comb_isr_mask[i]))
+					&& (g_log_chan[i].weight > 0)) {
+					if (g_log_chan[chan_no].weight < g_log_chan[i].weight) {
+						chan_no = i;
+					}
+				}
+			}
+			if (chan_no < CHAN_TOTAL_NUM) {
+				rx_chan_intr_handler(chan_no);
+			} else {
+				for (i = 0; i < RX_CHAN_NUM; i++) {
+					g_log_chan[i].weight = g_log_chan[i].default_weight;
+				}
+			}
+		}
+#ifdef NO_TX_INT
+		cnt++;
+		if (cnt == 10) {
+			cnt = 0;
+			for (i = 0; i < tx_chan_list_len; i++) {
+				if (AMAZON_DMA_REG32
+					(AMAZON_DMA_CH0_ISR +
+					 tx_chan_list[i] *
+					 AMAZON_DMA_CH_STEP) & (DMA_ISR_CPT | DMA_ISR_EOP)) {
+					tx_chan_intr_handler(tx_chan_list[i]);
+				}
+			}
+		}
+#else
+		if (isr & COMB_ISR_TX_MASK) {
+			// TX channels: RR
+			for (i = 0; i < tx_chan_list_len; i++) {
+				if (isr & (comb_isr_mask[tx_chan_list[i]])) {
+					tx_chan_intr_handler(tx_chan_list[i]);
+				}
+			}
+		}
+#endif
+	}							// while 
+	return IRQ_HANDLED;
+}
+
+
+/*	Brief:	read a packet from DMA RX channel
+ *	Parameter:
+ *	Return:	packet length
+ *	Description:
+ *		This is called back in a context of DMA interrupt
+ *		1. prepare new descriptor
+ *		2. read data
+ *		3. update WFQ weight
+ */
+//507261:tc.chen int dma_device_read(struct dma_device_info* dma_dev, u8** dataptr, void** opt)
+int asmlinkage dma_device_read(struct dma_device_info *dma_dev,
+							   u8 ** dataptr, void **opt)
+{
+	u8 *buf;
+	int len;
+	int chan_no = 0;
+	int byte_offset = 0;
+
+	struct rx_desc *rx_desc_p;
+	void *p = NULL;
+	int current_desc;
+
+	chan_no = dma_dev->logic_rx_chan_base + dma_dev->current_rx_chan;
+	current_desc = g_log_chan[chan_no].current_desc;
+	rx_desc_p =
+		(struct rx_desc *) (g_desc_list +
+							g_log_chan[chan_no].offset_from_base +
+							current_desc);
+	buf = (u8 *) __va(rx_desc_p->Data_Pointer);	/* extract the virtual
+												   address of the data
+												   pointer */
+	len = rx_desc_p->status.field.data_length;	/* extract the data length */
+#ifndef	CONFIG_MIPS_UNCACHED
+	dma_cache_inv((unsigned long) buf, len);
+#endif							// CONFIG_MIPS_UNCACHED
+	*(u32 *) dataptr = (u32) buf;
+	if (opt) {
+		*(int *) opt = (int) g_log_chan[chan_no].opt[current_desc];	/* read 
+																	   out 
+																	   the 
+																	   opt 
+																	   information */
+	}
+
+	buf =
+		(u8 *) g_log_chan[chan_no].buffer_alloc(g_log_chan[chan_no].
+												packet_size, &byte_offset,
+												&p);
+	// should check null!!!!
+	if (buf == NULL || p == NULL) {
+		*(u32 *) dataptr = 0;
+		*(int *) opt = 0;
+		len = 0;
+	} else {
+		g_log_chan[chan_no].opt[current_desc] = p;
+		/* reduce the weight for WFQ algorithm */
+		g_log_chan[chan_no].weight -= len;
+		rx_desc_p->Data_Pointer = (u32) CPHYSADDR((u32) buf);
+	}
+	if (current_desc == g_log_chan[chan_no].desc_len - 1) {
+		current_desc = 0;
+	} else {
+		current_desc++;
+	}
+	g_log_chan[chan_no].current_desc = current_desc;
+
+	rx_desc_p->status.word = DMA_DESC_OWN_DMA
+		| (byte_offset << DMA_DESC_BYTEOFF_SHIFT)
+		| g_log_chan[chan_no].packet_size;
+	return len;
+}
+
+/*	Brief:	write a packet through DMA RX channel to peripheral
+ *	Parameter:
+ *	Return:	packet length
+ *	Description:
+ *
+ */
+u64 dma_tx_drop = 0;
+//507261:tc.chen int dma_device_write(struct dma_device_info* dma_dev, u8* dataptr, int len,void* opt)
+int asmlinkage dma_device_write(struct dma_device_info *dma_dev,
+								u8 * dataptr, int len, void *opt)
+{
+	int chan_no = 0;
+	struct tx_desc *tx_desc_p;
+
+	int byte_offset = 0;
+	int current_desc;
+	static int cnt = 0;			// 000004:fchang
+
+	unsigned long flag;
+	local_irq_save(flag);
+
+	chan_no = dma_dev->logic_tx_chan_base + dma_dev->current_tx_chan;
+	current_desc = g_log_chan[chan_no].current_desc;
+	tx_desc_p =
+		(struct tx_desc *) (g_desc_list +
+							g_log_chan[chan_no].offset_from_base +
+							current_desc);
+	// 000003:tc.chen if(tx_desc_p->status.field.OWN==DMA_OWN){
+	if (tx_desc_p->status.field.OWN == DMA_OWN || tx_desc_p->status.field.C == 1) {	// 000003:tc.chen
+		AMAZON_DMA_DMSG("no TX desc for CPU, drop packet\n");
+		dma_tx_drop++;
+		g_log_chan[chan_no].intr_handler(dma_dev, TX_BUF_FULL_INT);
+		local_irq_restore(flag);
+		return 0;
+	}
+	g_log_chan[chan_no].opt[current_desc] = opt;
+
+	/* byte offset----to adjust the starting address of the data buffer,
+	   should be multiple of the burst length. */
+	byte_offset =
+		((u32) CPHYSADDR((u32) dataptr)) % (g_log_chan[chan_no].burst_len *
+											4);
+#ifndef	CONFIG_MIPS_UNCACHED
+	dma_cache_wback((unsigned long) dataptr, len);
+	wmb();
+#endif							// CONFIG_MIPS_UNCACHED
+
+	tx_desc_p->Data_Pointer = (u32) CPHYSADDR((u32) dataptr) - byte_offset;
+	wmb();
+	tx_desc_p->status.word = DMA_DESC_OWN_DMA
+		| DMA_DESC_SOP_SET
+		| DMA_DESC_EOP_SET | (byte_offset << DMA_DESC_BYTEOFF_SHIFT)
+		| len;
+	wmb();
+	if (is_channel_open(chan_no) == 0) {
+		// turn on if necessary
+		open_channel(chan_no);
+	}
+#ifdef DMA_NO_POLLING
+	if ((AMAZON_DMA_REG32
+		 (AMAZON_DMA_CH0_ISR +
+		  chan_no * AMAZON_DMA_CH_STEP) & (DMA_ISR_DURR | DMA_ISR_CPT)) ==
+		(DMA_ISR_DURR)) {
+		// clear DURR if (CPT is AND set and DURR is set)
+		AMAZON_DMA_REG32(AMAZON_DMA_CH0_ISR +
+						 chan_no * AMAZON_DMA_CH_STEP) = DMA_ISR_DURR;
+	}
+#endif
+
+	if (current_desc == (g_log_chan[chan_no].desc_len - 1)) {
+		current_desc = 0;
+	} else {
+		current_desc++;
+	}
+
+
+	g_log_chan[chan_no].current_desc = current_desc;
+	tx_desc_p =
+		(struct tx_desc *) (g_desc_list +
+							g_log_chan[chan_no].offset_from_base +
+							current_desc);
+	// 000003:tc.chen if(tx_desc_p->status.field.OWN==DMA_OWN){
+	if (tx_desc_p->status.field.OWN == DMA_OWN || tx_desc_p->status.field.C == 1) {	// 000003:tc.chen
+		g_log_chan[chan_no].intr_handler(dma_dev, TX_BUF_FULL_INT);
+	}
+#ifdef NO_TX_INT
+//000004:fchang Start
+	cnt++;
+	if (cnt == 5) {
+		cnt = 0;
+		tx_chan_intr_handler(chan_no);
+	}
+//000004:fchang End
+#endif
+	local_irq_restore(flag);	// 000004:fchang
+	return len;
+}
+
+
+
+int desc_list_proc_read(char *buf, char **start, off_t offset,
+						int count, int *eof, void *data)
+{
+	int i;
+	u32 *p = (u32 *) g_desc_list;
+	int len = 0;
+	len += sprintf(buf + len, "descriptor list:\n");
+	for (i = 0; i < 120; i++) {
+		len += sprintf(buf + len, "%d\n", i);
+		len += sprintf(buf + len, "%08x\n", *(p + i * 2 + 1));
+		len += sprintf(buf + len, "%08x\n", *(p + i * 2));
+
+	}
+
+	return len;
+
+}
+
+int channel_weight_proc_read(char *buf, char **start, off_t offset,
+							 int count, int *eof, void *data)
+{
+
+	// int i=0;
+	int len = 0;
+	len += sprintf(buf + len, "Qos dma channel weight list\n");
+	len +=
+		sprintf(buf + len,
+				"channel_num default_weight current_weight device Tx/Rx\n");
+	len +=
+		sprintf(buf + len,
+				"     0      %08x        %08x      Switch   Rx0\n",
+				g_log_chan[0].default_weight, g_log_chan[0].weight);
+	len +=
+		sprintf(buf + len,
+				"     1      %08x        %08x      Switch   Rx1\n",
+				g_log_chan[1].default_weight, g_log_chan[1].weight);
+	len +=
+		sprintf(buf + len,
+				"     2      %08x        %08x      Switch   Rx2\n",
+				g_log_chan[2].default_weight, g_log_chan[2].weight);
+	len +=
+		sprintf(buf + len,
+				"     3      %08x        %08x      Switch   Rx3\n",
+				g_log_chan[3].default_weight, g_log_chan[3].weight);
+	len +=
+		sprintf(buf + len,
+				"     4      %08x        %08x      Switch   Tx0\n",
+				g_log_chan[4].default_weight, g_log_chan[4].weight);
+	len +=
+		sprintf(buf + len,
+				"     5      %08x        %08x      Switch   Tx1\n",
+				g_log_chan[5].default_weight, g_log_chan[5].weight);
+	/* 
+	   len+=sprintf(buf+len," 6 %08x %08x TPE
+	   Rx0\n",g_log_chan[6].default_weight, g_log_chan[6].weight);
+	   len+=sprintf(buf+len," 7 %08x %08x TPE
+	   Rx0\n",g_log_chan[7].default_weight, g_log_chan[7].weight);
+	   len+=sprintf(buf+len," 8 %08x %08x TPE
+	   Tx0\n",g_log_chan[8].default_weight, g_log_chan[8].weight);
+	   len+=sprintf(buf+len," 9 %08x %08x TPE
+	   Rx0\n",g_log_chan[9].default_weight, g_log_chan[9].weight);
+	   len+=sprintf(buf+len," 10 %08x %08x DPLUS
+	   Rx0\n",g_log_chan[10].default_weight, g_log_chan[10].weight);
+	   len+=sprintf(buf+len," 11 %08x %08x DPLUS
+	   Rx0\n",g_log_chan[11].default_weight, g_log_chan[11].weight); */
+	return len;
+}
+
+int dma_register_proc_read(char *buf, char **start, off_t offset,
+						   int count, int *eof, void *data)
+{
+	dev_list *temp_dev;
+	int len = 0;;
+
+	len += sprintf(buf + len, "amazon dma driver\n");
+	len += sprintf(buf + len, "version 1.0\n");
+	len += sprintf(buf + len, "devices registered:\n");
+	for (temp_dev = g_head_dev; temp_dev; temp_dev = temp_dev->next) {
+		len += sprintf(buf + len, "%s ", temp_dev->dev->device_name);
+	}
+	len += sprintf(buf + len, "\n");
+	len += sprintf(buf + len, "CH_ON=%08x\n", AMAZON_DMA_REG32(AMAZON_DMA_CH_ON));
+	len += sprintf(buf + len, "CH_RST=%08x\n", AMAZON_DMA_REG32(AMAZON_DMA_CH_RST));
+	len += sprintf(buf + len, "CH0_ISR=%08x\n",	AMAZON_DMA_REG32(AMAZON_DMA_CH0_ISR));
+	len += sprintf(buf + len, "CH1_ISR=%08x\n",	AMAZON_DMA_REG32(AMAZON_DMA_CH1_ISR));
+	len += sprintf(buf + len, "CH2_ISR=%08x\n",	AMAZON_DMA_REG32(AMAZON_DMA_CH2_ISR));
+	len += sprintf(buf + len, "CH3_ISR=%08x\n",	AMAZON_DMA_REG32(AMAZON_DMA_CH3_ISR));
+	len += sprintf(buf + len, "CH4_ISR=%08x\n",	AMAZON_DMA_REG32(AMAZON_DMA_CH4_ISR));
+	len += sprintf(buf + len, "CH5_ISR=%08x\n",	AMAZON_DMA_REG32(AMAZON_DMA_CH5_ISR));
+	len += sprintf(buf + len, "CH6_ISR=%08x\n",	AMAZON_DMA_REG32(AMAZON_DMA_CH6_ISR));
+	len += sprintf(buf + len, "CH7_ISR=%08x\n", AMAZON_DMA_REG32(AMAZON_DMA_CH7_ISR));
+	len +=		sprintf(buf + len, "CH8_ISR=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH8_ISR));
+	len +=
+		sprintf(buf + len, "CH9_ISR=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH9_ISR));
+	len +=
+		sprintf(buf + len, "CH10_ISR=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH10_ISR));
+	len +=
+		sprintf(buf + len, "CH11_ISR=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH11_ISR));
+	len +=
+		sprintf(buf + len, "LCH0_MSK=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH0_MSK));
+	len +=
+		sprintf(buf + len, "LCH1_MSK=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH1_MSK));
+	len +=
+		sprintf(buf + len, "LCH2_MSK=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH2_MSK));
+	len +=
+		sprintf(buf + len, "LCH3_MSK=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH3_MSK));
+	len +=
+		sprintf(buf + len, "LCH4_MSK=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH4_MSK));
+	len +=
+		sprintf(buf + len, "LCH5_MSK=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH5_MSK));
+	len +=
+		sprintf(buf + len, "LCH6_MSK=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH6_MSK));
+	len +=
+		sprintf(buf + len, "LCH7_MSK=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH7_MSK));
+	len +=
+		sprintf(buf + len, "LCH8_MSK=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH8_MSK));
+	len +=
+		sprintf(buf + len, "LCH9_MSK=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH9_MSK));
+	len +=
+		sprintf(buf + len, "LCH10_MSK=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH10_MSK));
+	len +=
+		sprintf(buf + len, "LCH11_MSK=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH11_MSK));
+	len +=
+		sprintf(buf + len, "Desc_BA=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_Desc_BA));
+	len +=
+		sprintf(buf + len, "LCH0_DES_LEN=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH0_DES_LEN));
+	len +=
+		sprintf(buf + len, "LCH1_DES_LEN=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH1_DES_LEN));
+	len +=
+		sprintf(buf + len, "LCH2_DES_LEN=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH2_DES_LEN));
+	len +=
+		sprintf(buf + len, "LCH3_DES_LEN=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH3_DES_LEN));
+	len +=
+		sprintf(buf + len, "LCH4_DES_LEN=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH4_DES_LEN));
+	len +=
+		sprintf(buf + len, "LCH5_DES_LEN=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH5_DES_LEN));
+	len +=
+		sprintf(buf + len, "LCH6_DES_LEN=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH6_DES_LEN));
+	len +=
+		sprintf(buf + len, "LCH7_DES_LEN=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH7_DES_LEN));
+	len +=
+		sprintf(buf + len, "LCH8_DES_LEN=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH8_DES_LEN));
+	len +=
+		sprintf(buf + len, "LCH9_DES_LEN=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH9_DES_LEN));
+	len +=
+		sprintf(buf + len, "LCH10_DES_LEN=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH10_DES_LEN));
+	len +=
+		sprintf(buf + len, "LCH11_DES_LEN=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH11_DES_LEN));
+	len +=
+		sprintf(buf + len, "LCH1_DES_OFST=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH1_DES_OFST));
+	len +=
+		sprintf(buf + len, "LCH2_DES_OFST=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH2_DES_OFST));
+	len +=
+		sprintf(buf + len, "LCH3_DES_OFST=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH3_DES_OFST));
+	len +=
+		sprintf(buf + len, "LCH4_DES_OFST=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH4_DES_OFST));
+	len +=
+		sprintf(buf + len, "LCH5_DES_OFST=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH5_DES_OFST));
+	len +=
+		sprintf(buf + len, "LCH6_DES_OFST=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH6_DES_OFST));
+	len +=
+		sprintf(buf + len, "LCH7_DES_OFST=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH7_DES_OFST));
+	len +=
+		sprintf(buf + len, "LCH8_DES_OFST=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH8_DES_OFST));
+	len +=
+		sprintf(buf + len, "LCH9_DES_OFST=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH9_DES_OFST));
+	len +=
+		sprintf(buf + len, "LCH10_DES_OFST=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH10_DES_OFST));
+	len +=
+		sprintf(buf + len, "LCH11_DES_OFST=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH11_DES_OFST));
+	len +=
+		sprintf(buf + len, "AMAZON_DMA_SW_BL=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_SW_BL));
+	len +=
+		sprintf(buf + len, "AMAZON_DMA_TPE_BL=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_TPE_BL));
+	len +=
+		sprintf(buf + len, "DPlus2FPI_BL=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_DPlus2FPI_BL));
+	len +=
+		sprintf(buf + len, "GRX_BUF_LEN=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_GRX_BUF_LEN));
+	len +=
+		sprintf(buf + len, "DMA_ECON_REG=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_DMA_ECON_REG));
+	len +=
+		sprintf(buf + len, "POLLING_REG=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_POLLING_REG));
+	len +=
+		sprintf(buf + len, "CH_WGT=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_CH_WGT));
+	len +=
+		sprintf(buf + len, "TX_WGT=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_TX_WGT));
+	len +=
+		sprintf(buf + len, "DPlus2FPI_CLASS=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_DPLus2FPI_CLASS));
+	len +=
+		sprintf(buf + len, "COMB_ISR=%08x\n",
+				AMAZON_DMA_REG32(AMAZON_DMA_COMB_ISR));
+#ifdef AMAZON_DMA_TPE_AAL5_RECOVERY
+	len += sprintf(buf + len, "TPE fails:%u\n", total_dma_tpe_reset);	// 000004:fchang
+#endif
+	return len;
+}
+
+/*	Brief:	initialize DMA registers
+ *	Description:
+ */
+static void dma_chip_init(void)
+{
+	int i;
+	for (i = 0; i < CHAN_TOTAL_NUM; i++) {
+		AMAZON_DMA_REG32(AMAZON_DMA_CH1_DES_OFST +
+						 i * AMAZON_DMA_CH_STEP) = DEFAULT_OFFSET;
+	}
+#ifdef DMA_NO_POLLING
+	AMAZON_DMA_REG32(AMAZON_DMA_POLLING_REG) = 0;
+#else
+	// enable poll mode and set polling counter
+	AMAZON_DMA_REG32(AMAZON_DMA_POLLING_REG) = DMA_POLLING_CNT | DMA_POLLING_ENABLE;
+#endif
+	// to enable DMA drop
+	AMAZON_DMA_REG32(AMAZON_DMA_GRX_BUF_LEN) = 0x10000;
+}
+
+int insert_dev_list(dev_list * dev)
+{
+	dev_list *temp_dev;
+	if (g_head_dev == NULL) {
+		g_head_dev = dev;
+		g_tail_dev = dev;
+		dev->prev = NULL;
+		dev->next = NULL;
+	} else {
+		for (temp_dev = g_head_dev; temp_dev; temp_dev = temp_dev->next) {
+			if (temp_dev->weight < dev->weight) {
+				if (temp_dev->prev)
+					temp_dev->prev->next = dev;
+
+				dev->prev = temp_dev->prev;
+				dev->next = temp_dev;
+				temp_dev->prev = dev;
+				if (temp_dev == g_head_dev)
+					g_head_dev = dev;
+				break;
+			}
+		}
+
+		if (!temp_dev) {
+			g_tail_dev->next = dev;
+			dev->prev = g_tail_dev;
+			dev->next = NULL;
+			g_tail_dev = dev;
+		}
+
+	}
+
+	return 1;
+}
+
+u8 *common_buffer_alloc(int len, int *byte_offset, void **opt)
+{
+	u8 *buffer = (u8 *) kmalloc(len * sizeof(u8), GFP_KERNEL);
+	*byte_offset = 0;
+	return buffer;
+
+}
+
+int common_buffer_free(u8 * dataptr, void *opt)
+{
+	if (dataptr)
+		kfree(dataptr);
+	return 0;
+}
+
+
+int register_dev(struct dma_device_info *dma_dev)
+{
+	int i, j, temp;
+	int burst_reg = 0;
+	u8 *buffer;
+	void *p = NULL;
+	int byte_offset = 0;
+
+	struct rx_desc *rx_desc_p;
+	struct tx_desc *tx_desc_p;
+	if (strcmp(dma_dev->device_name, "switch1") == 0) {
+		AMAZON_DMA_REG32(AMAZON_DMA_CH_RST) = SWITCH1_RST_MASK;	// resest
+																// channel 
+																// 1st 
+		AMAZON_DMA_REG32(AMAZON_DMA_DMA_ECON_REG) |= 0x3;	// endian
+															// conversion
+															// for Switch
+		burst_reg = AMAZON_DMA_SW_BL;
+		dma_dev->logic_rx_chan_base = switch_rx_chan_base;
+		dma_dev->logic_tx_chan_base = switch_tx_chan_base;
+	}
+
+	else if (strcmp(dma_dev->device_name, "switch2") == 0) {
+		AMAZON_DMA_REG32(AMAZON_DMA_CH_RST) = SWITCH2_RST_MASK;	// resest
+																// channel 
+																// 1st
+		AMAZON_DMA_REG32(AMAZON_DMA_DMA_ECON_REG) |= 0x3;	// endian
+															// conversion
+															// for Switch
+		burst_reg = AMAZON_DMA_SW_BL;
+		dma_dev->logic_rx_chan_base = switch2_rx_chan_base;
+		dma_dev->logic_tx_chan_base = switch2_tx_chan_base;
+
+	} else if (strcmp(dma_dev->device_name, "TPE") == 0) {
+		AMAZON_DMA_REG32(AMAZON_DMA_CH_RST) = TPE_RST_MASK;	// resest
+															// channel 1st 
+															// 
+		burst_reg = AMAZON_DMA_TPE_BL;
+		dma_dev->logic_rx_chan_base = TPE_rx_chan_base;
+		dma_dev->logic_tx_chan_base = TPE_tx_chan_base;
+	}
+
+	else if (strcmp(dma_dev->device_name, "DPlus") == 0) {
+		AMAZON_DMA_REG32(AMAZON_DMA_CH_RST) = DPlus2FPI_RST_MASK;	// resest 
+																	// channel 
+																	// 1st
+		dma_dev->logic_rx_chan_base = DPLus2FPI_rx_chan_base;
+		dma_dev->logic_tx_chan_base = DPLus2FPI_tx_chan_base;
+
+	}
+
+	i = 0;
+	for (temp = dma_dev->tx_burst_len; temp > 2; temp /= 2) {
+		i += 1;
+	}
+
+
+	AMAZON_DMA_REG32(burst_reg) = i << 1;
+	i = 0;
+	for (temp = dma_dev->rx_burst_len; temp > 2; temp /= 2) {
+		i += 1;
+	}
+	AMAZON_DMA_REG32(burst_reg) += i;
+
+	for (i = 0; i < dma_dev->num_rx_chan; i++) {
+
+		temp = dma_dev->logic_rx_chan_base + i;
+		g_log_chan[temp].dma_dev = dma_dev;
+		g_log_chan[temp].weight = dma_dev->rx_chan[i].weight;
+		g_log_chan[temp].default_weight = dma_dev->rx_chan[i].weight;
+		g_log_chan[temp].current_desc = 0;
+		g_log_chan[temp].desc_ofst = DEFAULT_OFFSET;
+		g_log_chan[temp].desc_len = dma_dev->rx_chan[i].desc_num;
+		g_log_chan[temp].offset_from_base = temp * DEFAULT_OFFSET;
+		g_log_chan[temp].packet_size = dma_dev->rx_chan[i].packet_size;
+
+		AMAZON_DMA_REG32(AMAZON_DMA_CH0_DES_LEN + temp * AMAZON_DMA_CH_STEP) = dma_dev->rx_chan[i].desc_num;
+		// enable interrupt mask
+		if (temp == 4 || temp == 5) {
+			AMAZON_DMA_REG32(AMAZON_DMA_CH0_MSK + temp * AMAZON_DMA_CH_STEP) = 0x32;
+		} else {
+			AMAZON_DMA_REG32(AMAZON_DMA_CH0_MSK + temp * AMAZON_DMA_CH_STEP) = 0x36;
+		}
+		strcpy(g_log_chan[temp].device_name, dma_dev->device_name);
+		g_log_chan[temp].burst_len = dma_dev->rx_burst_len;
+		g_log_chan[temp].control = dma_dev->rx_chan[i].control;
+
+
+		/* specify the buffer allocation and free method */
+		if (dma_dev->buffer_alloc)
+			g_log_chan[temp].buffer_alloc = dma_dev->buffer_alloc;
+		else
+			g_log_chan[temp].buffer_alloc = common_buffer_alloc;
+
+		if (dma_dev->buffer_free)
+			g_log_chan[temp].buffer_free = dma_dev->buffer_free;
+		else
+			g_log_chan[temp].buffer_free = common_buffer_free;
+
+		if (dma_dev->intr_handler)
+			g_log_chan[temp].intr_handler = dma_dev->intr_handler;
+		else
+			g_log_chan[temp].intr_handler = NULL;
+
+		for (j = 0; j < g_log_chan[temp].desc_len; j++) {
+			rx_desc_p = (struct rx_desc *) (g_desc_list + g_log_chan[temp].offset_from_base + j);
+			rx_desc_p->status.word = 0;
+			rx_desc_p->status.field.data_length = g_log_chan[temp].packet_size;
+			buffer = (u8 *) g_log_chan[temp].buffer_alloc(g_log_chan[temp].packet_size, &byte_offset, &p);
+			rx_desc_p->Data_Pointer = (u32) CPHYSADDR((u32) buffer);
+			rx_desc_p->status.field.byte_offset = byte_offset;
+			/* fix me, should check if the addresss comply with the burst
+			   lenght requirment */
+			g_log_chan[temp].opt[j] = p;
+			rx_desc_p->status.field.OWN = DMA_OWN;
+
+		}
+		/* open or close the channel */
+		if (g_log_chan[temp].control)
+			open_channel(temp);
+		else
+			close_channel(temp);
+	}
+
+	for (i = 0; i < dma_dev->num_tx_chan; i++) {
+		temp = dma_dev->logic_tx_chan_base + i;
+		g_log_chan[temp].dma_dev = dma_dev;
+		g_log_chan[temp].weight = dma_dev->tx_chan[i].weight;
+		g_log_chan[temp].default_weight = dma_dev->tx_chan[i].weight;
+		g_log_chan[temp].current_desc = 0;
+		g_log_chan[temp].desc_ofst = DEFAULT_OFFSET;
+		g_log_chan[temp].desc_len = dma_dev->tx_chan[i].desc_num;
+		g_log_chan[temp].offset_from_base = temp * DEFAULT_OFFSET;
+		g_log_chan[temp].packet_size = dma_dev->tx_chan[i].packet_size;
+
+		AMAZON_DMA_REG32(AMAZON_DMA_CH0_DES_LEN + temp * AMAZON_DMA_CH_STEP) = dma_dev->tx_chan[i].desc_num;
+		// enable interrupt mask
+#ifdef NO_TX_INT
+		AMAZON_DMA_REG32(AMAZON_DMA_CH0_MSK + temp * AMAZON_DMA_CH_STEP) = 0x3e;
+#else
+		AMAZON_DMA_REG32(AMAZON_DMA_CH0_MSK + temp * AMAZON_DMA_CH_STEP) = 0x36;
+#endif
+
+		strcpy(g_log_chan[temp].device_name, dma_dev->device_name);
+		g_log_chan[temp].burst_len = dma_dev->tx_burst_len;
+		g_log_chan[temp].control = dma_dev->tx_chan[i].control;
+
+		if (dma_dev->buffer_alloc)
+			g_log_chan[temp].buffer_alloc = dma_dev->buffer_alloc;
+		else
+			g_log_chan[temp].buffer_alloc = common_buffer_alloc;
+
+		if (dma_dev->buffer_free)
+			g_log_chan[temp].buffer_free = dma_dev->buffer_free;
+		else
+			g_log_chan[temp].buffer_free = common_buffer_free;
+
+		if (dma_dev->intr_handler)
+			g_log_chan[temp].intr_handler = dma_dev->intr_handler;
+		else
+			g_log_chan[temp].intr_handler = NULL;
+
+		for (j = 0; j < g_log_chan[temp].desc_len; j++) {
+
+			tx_desc_p =
+				(struct tx_desc *) (g_desc_list +
+									g_log_chan[temp].offset_from_base + j);
+			tx_desc_p->status.word = 0;
+			tx_desc_p->status.field.data_length =
+				g_log_chan[temp].packet_size;
+			tx_desc_p->status.field.OWN = CPU_OWN;
+
+		}
+		/* workaround DMA pitfall, we never turn on channel if we don't
+		   have proper descriptors */
+		if (!g_log_chan[temp].control) {
+			close_channel(temp);
+		}
+
+	}
+
+	return 0;
+}
+
+int dma_device_register(struct dma_device_info *dma_dev)
+{
+	dev_list *temp_dev;
+	temp_dev = (dev_list *) kmalloc(sizeof(dev_list), GFP_KERNEL);
+	temp_dev->dev = dma_dev;
+	temp_dev->weight = dma_dev->weight;
+	insert_dev_list(temp_dev);
+	/* check whether this is a known device */
+	if ((strcmp(dma_dev->device_name, "switch1") == 0)
+		|| (strcmp(dma_dev->device_name, "TPE") == 0)
+		|| (strcmp(dma_dev->device_name, "switch2") == 0)
+		|| (strcmp(dma_dev->device_name, "DPlus") == 0)) {
+		register_dev(dma_dev);
+	}
+
+	return 0;
+}
+
+
+int unregister_dev(struct dma_device_info *dma_dev)
+{
+	int i, j, temp;
+	u8 *buffer;
+	struct rx_desc *rx_desc_p;
+
+	for (i = 0; i < dma_dev->num_rx_chan; i++) {
+		temp = dma_dev->logic_rx_chan_base + i;
+		close_channel(temp);
+		for (j = 0; j < g_log_chan[temp].desc_len; j++) {
+			rx_desc_p =
+				(struct rx_desc *) (g_desc_list +
+									g_log_chan[temp].offset_from_base + j);
+			buffer = (u8 *) __va(rx_desc_p->Data_Pointer);
+			g_log_chan[temp].buffer_free(buffer, g_log_chan[temp].opt[j]);
+		}
+	}
+	for (i = 0; i < dma_dev->num_tx_chan; i++) {
+		temp = dma_dev->logic_tx_chan_base + i;
+		close_channel(temp);
+	}
+	return 0;
+}
+
+int dma_device_unregister(struct dma_device_info *dev)
+{
+	dev_list *temp_dev;
+	for (temp_dev = g_head_dev; temp_dev; temp_dev = temp_dev->next) {
+		if (strcmp(dev->device_name, temp_dev->dev->device_name) == 0) {
+			if ((strcmp(dev->device_name, "switch1") == 0)
+				|| (strcmp(dev->device_name, "TPE") == 0)
+				|| (strcmp(dev->device_name, "switch2") == 0)
+				|| (strcmp(dev->device_name, "DPlus") == 0))
+				unregister_dev(dev);
+			if (temp_dev == g_head_dev) {
+				g_head_dev = temp_dev->next;
+				kfree(temp_dev);
+			} else {
+				if (temp_dev == g_tail_dev)
+					g_tail_dev = temp_dev->prev;
+				if (temp_dev->prev)
+					temp_dev->prev->next = temp_dev->next;
+				if (temp_dev->next)
+					temp_dev->next->prev = temp_dev->prev;
+				kfree(temp_dev);
+			}
+			break;
+		}
+
+	}
+	return 0;
+}
+
+void dma_device_update_rx(struct dma_device_info *dma_dev)
+{
+	int i, temp;
+	for (i = 0; i < dma_dev->num_rx_chan; i++) {
+		temp = dma_dev->logic_rx_chan_base + i;
+		g_log_chan[temp].control = dma_dev->rx_chan[i].control;
+
+		if (g_log_chan[temp].control)
+			open_channel(temp);
+		else
+			close_channel(temp);
+	}
+
+}
+
+void dma_device_update_tx(struct dma_device_info *dma_dev)
+{
+	int i, temp;
+	for (i = 0; i < dma_dev->num_tx_chan; i++) {
+		temp = dma_dev->logic_tx_chan_base + i;
+		g_log_chan[temp].control = dma_dev->tx_chan[i].control;
+		if (g_log_chan[temp].control) {
+			/* we turn on channel when send out the very first packet */
+			// open_channel(temp);
+		} else
+			close_channel(temp);
+	}
+}
+
+int dma_device_update(struct dma_device_info *dma_dev)
+{
+	dma_device_update_rx(dma_dev);
+	dma_device_update_tx(dma_dev);
+	return 0;
+}
+
+static int dma_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int dma_release(struct inode *inode, struct file *file)
+{
+	/* release the resources */
+	return 0;
+}
+
+static int dma_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int value = 0;
+	int result = 0;
+	int chan_no = 0;
+
+	switch (cmd) {
+	case 0:					/* get register value */
+		break;
+	case 1:					/* return channel weight */
+		chan_no = *((int *) arg);
+		*((int *) arg + 1) = g_log_chan[chan_no].default_weight;
+		break;
+	case 2:					/* set channel weight */
+		chan_no = *((int *) arg);
+		value = *((int *) arg + 1);
+		printk("new weight=%08x\n", value);
+		g_log_chan[chan_no].default_weight = value;
+		break;
+	default:
+		break;
+	}
+	return result;
+}
+
+
+static struct file_operations dma_fops = {
+  owner:THIS_MODULE,
+  open:dma_open,
+  release:dma_release,
+  ioctl:dma_ioctl,
+};
+
+static int dma_init(void)
+{
+	int result = 0;
+	int i;
+	printk("initialising dma core\n");
+	result = register_chrdev(DMA_MAJOR, "dma-core", &dma_fops);
+	if (result) {
+		AMAZON_DMA_EMSG("cannot register device dma-core!\n");
+		return result;
+	}
+	result = request_irq(AMAZON_DMA_INT, dma_interrupt, SA_INTERRUPT, "dma-core", (void *) &dma_interrupt);
+	if (result) {
+		AMAZON_DMA_EMSG("error, cannot get dma_irq!\n");
+		free_irq(AMAZON_DMA_INT, (void *) &dma_interrupt);
+		return -EFAULT;
+	}
+
+	g_desc_list = (u64 *) KSEG1ADDR(__get_free_page(GFP_DMA));
+
+	if (g_desc_list == NULL) {
+		AMAZON_DMA_EMSG("no memory for desriptor\n");
+		return -ENOMEM;
+	}
+	memset(g_desc_list, 0, PAGE_SIZE);
+	AMAZON_DMA_REG32(AMAZON_DMA_Desc_BA) = (u32) CPHYSADDR((u32) g_desc_list);
+	g_amazon_dma_dir = proc_mkdir("amazon_dma", NULL);
+	create_proc_read_entry("dma_register", 0, g_amazon_dma_dir, dma_register_proc_read, NULL);
+	create_proc_read_entry("g_desc_list", 0, g_amazon_dma_dir, desc_list_proc_read, NULL);
+	create_proc_read_entry("channel_weight", 0, g_amazon_dma_dir, channel_weight_proc_read, NULL);
+
+	dma_chip_init();
+	for (i = 0; i < (RX_CHAN_NUM + 1); i++) {
+		rx_chan_list[i] = -1;
+	}
+	for (i = 0; i < (TX_CHAN_NUM + 1); i++) {
+		tx_chan_list[i] = -1;
+	}
+
+	for (i = 0; i < CHAN_TOTAL_NUM; i++) {
+		comb_isr_mask[i] = 0x80000000 >> (i);
+	}
+
+	g_log_chan[CHAN_TOTAL_NUM].weight = 0;
+	printk("initialising dma core ... done\n");
+
+	return 0;
+}
+
+arch_initcall(dma_init);
+
+
+void dma_cleanup(void)
+{
+	dev_list *temp_dev;
+
+	unregister_chrdev(DMA_MAJOR, "dma-core");
+	for (temp_dev = g_head_dev; temp_dev; temp_dev = temp_dev->next) {
+		kfree(temp_dev);
+	}
+	free_page(KSEG0ADDR((unsigned long) g_desc_list));
+	remove_proc_entry("channel_weight", g_amazon_dma_dir);
+	remove_proc_entry("dma_list", g_amazon_dma_dir);
+	remove_proc_entry("dma_register", g_amazon_dma_dir);
+	remove_proc_entry("amazon_dma", NULL);
+	/* release the resources */
+	free_irq(AMAZON_DMA_INT, (void *) &dma_interrupt);
+}
+
+EXPORT_SYMBOL(dma_device_register);
+EXPORT_SYMBOL(dma_device_unregister);
+EXPORT_SYMBOL(dma_device_read);
+EXPORT_SYMBOL(dma_device_write);
+EXPORT_SYMBOL(dma_device_update);
+EXPORT_SYMBOL(dma_device_update_rx);
+
+MODULE_LICENSE("GPL");
+

--- /dev/null
+++ b/target/linux/amazon-2.6/files/arch/mips/amazon/dma-core.h
@@ -1,1 +1,70 @@
+#ifndef DMA_CORE_H 
+#define DMA_CORE_H 
 
+#define AMAZON_DMA_REG32(reg_num)  *((volatile u32*)(reg_num))
+#define AMAZON_DMA_CH_STEP            4
+
+#define COMB_ISR_RX_MASK 0xfe000000
+#define COMB_ISR_TX_MASK 0x01f00000
+
+
+#define DMA_OWN   1
+#define CPU_OWN   0   
+#define DMA_MAJOR 250
+
+//Descriptors
+#define DMA_DESC_OWN_CPU		0x0
+#define DMA_DESC_OWN_DMA		0x80000000
+#define DMA_DESC_CPT_SET		0x40000000
+#define DMA_DESC_SOP_SET		0x20000000
+#define DMA_DESC_EOP_SET		0x10000000
+
+#define switch_rx_chan_base 0
+#define switch_tx_chan_base 7
+#define switch2_rx_chan_base 2
+#define switch2_tx_chan_base 8
+#define TPE_rx_chan_base    4
+#define TPE_tx_chan_base    9
+#define DPLus2FPI_rx_chan_base  6
+#define DPLus2FPI_tx_chan_base  11 
+
+#define RX_CHAN_NUM 7
+#define TX_CHAN_NUM 5
+#define CHAN_TOTAL_NUM       (RX_CHAN_NUM+TX_CHAN_NUM)
+#define DEFAULT_OFFSET 20
+#define DESCRIPTOR_SIZE 8
+
+typedef struct dev_list{
+   struct dma_device_info* dev;
+   int weight;
+   struct dev_list* prev;
+   struct dev_list* next;
+}dev_list; 
+
+typedef struct channel_info{
+   char device_name[16];
+   int occupied;
+   enum attr_t attr;  
+   int current_desc;
+   int weight;
+   int default_weight;
+   int desc_num;
+   int burst_len;
+   int desc_len;
+   int desc_ofst;
+   int packet_size;
+   int offset_from_base;
+   int control;
+   void* opt[DEFAULT_OFFSET];
+   u8* (*buffer_alloc)(int len,int* offset, void** opt);
+   int (*buffer_free)(u8* dataptr,void* opt);
+   int (*intr_handler)(struct dma_device_info* info,int status);
+
+   struct dma_device_info* dma_dev;
+}channel_info;
+
+
+
+#endif
+
+

--- /dev/null
+++ b/target/linux/amazon-2.6/files/arch/mips/amazon/interrupt.c
@@ -1,1 +1,239 @@
-
+/*
+ *  Gary Jennejohn (C) 2003 <gj@denx.de>
+ *  Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ *
+ * Routines for generic manipulation of the interrupts found on the 
+ * AMAZON boards.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/irq.h>
+#include <asm/bootinfo.h>
+#include <asm/irq_cpu.h>
+#include <asm/irq.h>
+#include <asm/time.h>
+
+static void amazon_disable_irq(unsigned int irq_nr)
+{
+	/* have to access the correct register here */
+	if (irq_nr <= INT_NUM_IM0_IRL11 && irq_nr >= INT_NUM_IM0_IRL0)
+		/* access IM0 DMA channels */
+		*AMAZON_ICU_IM0_IER &= (~(AMAZON_DMA_H_MASK));
+	else if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL12)
+		/* access IM0 except DMA*/
+		*AMAZON_ICU_IM0_IER &= (~AMAZON_ICU_IM0_IER_IR(irq_nr));
+	else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0)
+		/* access IM1 */
+		*AMAZON_ICU_IM1_IER &= (~AMAZON_ICU_IM1_IER_IR(irq_nr - INT_NUM_IM1_IRL0));
+	else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0)
+		/* access IM2 */
+		*AMAZON_ICU_IM2_IER &= (~AMAZON_ICU_IM2_IER_IR(irq_nr - INT_NUM_IM2_IRL0));
+	else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0)
+		/* access IM3 */
+		*AMAZON_ICU_IM3_IER &= (~AMAZON_ICU_IM3_IER_IR((irq_nr - INT_NUM_IM3_IRL0)));
+	else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0)
+		/* access IM4 */
+		*AMAZON_ICU_IM4_IER &= (~AMAZON_ICU_IM4_IER_IR((irq_nr - INT_NUM_IM4_IRL0)));
+}
+
+static void amazon_mask_and_ack_irq(unsigned int irq_nr)
+{
+	/* have to access the correct register here */
+	if (irq_nr <= INT_NUM_IM0_IRL11 && irq_nr >= INT_NUM_IM0_IRL0) {
+		/* access IM0 DMA channels */
+		*AMAZON_ICU_IM0_IER &= (~(AMAZON_DMA_H_MASK)); /* mask */
+		*AMAZON_ICU_IM0_ISR = AMAZON_DMA_H_MASK; /* ack */
+	} else if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL12) {
+		/* access IM0 except DMA */
+		*AMAZON_ICU_IM0_IER &= ~AMAZON_ICU_IM0_IER_IR(irq_nr - INT_NUM_IM0_IRL0); /* mask */
+		*AMAZON_ICU_IM0_ISR = AMAZON_ICU_IM0_ISR_IR(irq_nr - INT_NUM_IM0_IRL0); /* ack */
+	} else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0) {
+		/* access IM1 */
+		*AMAZON_ICU_IM1_IER &= ~AMAZON_ICU_IM1_IER_IR(irq_nr - INT_NUM_IM1_IRL0); /* mask */
+		*AMAZON_ICU_IM1_ISR = AMAZON_ICU_IM1_ISR_IR(irq_nr - INT_NUM_IM1_IRL0); /* ack */
+	} else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0) {
+		/* access IM2 */
+		*AMAZON_ICU_IM2_IER &= ~AMAZON_ICU_IM2_IER_IR(irq_nr - INT_NUM_IM2_IRL0); /* mask */
+		*AMAZON_ICU_IM2_ISR = AMAZON_ICU_IM2_ISR_IR(irq_nr - INT_NUM_IM2_IRL0); /* ack */
+	} else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0) {
+		/* access IM3 */
+		*AMAZON_ICU_IM3_IER &= ~AMAZON_ICU_IM3_IER_IR(irq_nr - INT_NUM_IM3_IRL0); /* mask */
+		*AMAZON_ICU_IM3_ISR = AMAZON_ICU_IM3_ISR_IR(irq_nr - INT_NUM_IM3_IRL0); /* ack */
+	} else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0) {
+		*AMAZON_ICU_IM4_IER &= ~AMAZON_ICU_IM4_IER_IR(irq_nr - INT_NUM_IM4_IRL0); /* mask */
+		*AMAZON_ICU_IM4_ISR = AMAZON_ICU_IM4_ISR_IR(irq_nr - INT_NUM_IM4_IRL0); /* ack */
+	}
+}
+
+static void amazon_enable_irq(unsigned int irq_nr)
+{
+	/* have to access the correct register here */
+	if (irq_nr <= INT_NUM_IM0_IRL11 && irq_nr >= INT_NUM_IM0_IRL0)
+		/* access IM0 DMA*/
+		*AMAZON_ICU_IM0_IER |= AMAZON_DMA_H_MASK;
+	else if (irq_nr <= INT_NUM_IM0_IRL31 && irq_nr >= INT_NUM_IM0_IRL12)
+		/* access IM0 except DMA*/
+		*AMAZON_ICU_IM0_IER |= AMAZON_ICU_IM0_IER_IR(irq_nr - INT_NUM_IM0_IRL0);
+	else if (irq_nr <= INT_NUM_IM1_IRL31 && irq_nr >= INT_NUM_IM1_IRL0)
+		/* access IM1 */
+		*AMAZON_ICU_IM1_IER |= AMAZON_ICU_IM1_IER_IR(irq_nr - INT_NUM_IM1_IRL0);
+	else if (irq_nr <= INT_NUM_IM2_IRL31 && irq_nr >= INT_NUM_IM2_IRL0)
+		/* access IM2 */
+		*AMAZON_ICU_IM2_IER |= AMAZON_ICU_IM2_IER_IR(irq_nr - INT_NUM_IM2_IRL0);
+	else if (irq_nr <= INT_NUM_IM3_IRL31 && irq_nr >= INT_NUM_IM3_IRL0)
+		/* access IM3 */
+		*AMAZON_ICU_IM3_IER |= AMAZON_ICU_IM3_IER_IR((irq_nr - INT_NUM_IM3_IRL0));
+	else if (irq_nr <= INT_NUM_IM4_IRL31 && irq_nr >= INT_NUM_IM4_IRL0)
+		/* access IM4 */
+		*AMAZON_ICU_IM4_IER |= AMAZON_ICU_IM4_IER_IR((irq_nr - INT_NUM_IM4_IRL0));
+}
+
+static unsigned int amazon_startup_irq(unsigned int irq)
+{
+	amazon_enable_irq(irq);
+	return 0;
+}
+
+static void amazon_end_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+		amazon_enable_irq(irq);
+	}
+}
+
+static struct hw_interrupt_type amazon_irq_type = {
+	"AMAZON",
+	.startup = amazon_startup_irq,
+	.enable = amazon_enable_irq,
+	.disable = amazon_disable_irq,
+	.unmask = amazon_enable_irq,
+	.ack = amazon_mask_and_ack_irq,
+	.mask = amazon_disable_irq,
+	.mask_ack = amazon_mask_and_ack_irq,
+	.end = amazon_end_irq
+};
+
+/* Cascaded interrupts from IM0 */
+static inline void amazon_hw0_irqdispatch(void)
+{
+	u32 irq;
+																								 
+	irq = (*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM0_VEC_MASK;
+	if (irq <= 11 && irq >= 0) {
+		//DMA fixed to IM0_IRL0
+		irq = 0;
+	}
+	do_IRQ(irq + INT_NUM_IM0_IRL0);
+}
+                                                                                                         
+/* Cascaded interrupts from IM1 */
+static inline void amazon_hw1_irqdispatch(void)
+{
+	u32 irq;
+
+	irq = ((*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM1_VEC_MASK) >> 5;
+	do_IRQ(irq + INT_NUM_IM1_IRL0);
+}
+
+/* Cascaded interrupts from IM2 */
+static inline void amazon_hw2_irqdispatch(void)
+{
+	u32 irq;
+																								 
+	irq = ((*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM2_VEC_MASK) >> 10;
+	do_IRQ(irq + INT_NUM_IM2_IRL0);
+}
+
+/* Cascaded interrupts from IM3 */
+static inline void amazon_hw3_irqdispatch(void)
+{
+	u32 irq;
+
+	irq = ((*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM3_VEC_MASK) >> 15;
+	do_IRQ(irq + INT_NUM_IM3_IRL0);
+}
+
+/* Cascaded interrupts from IM4 */
+static inline void amazon_hw4_irqdispatch(void)
+{
+	u32 irq;
+
+	irq = ((*AMAZON_ICU_IM_VEC) & AMAZON_ICU_IM4_VEC_MASK) >> 20;
+	do_IRQ(irq + INT_NUM_IM4_IRL0);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+	unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+	if (pending & CAUSEF_IP7){
+		do_IRQ(MIPS_CPU_TIMER_IRQ);
+	}
+	else if (pending & CAUSEF_IP2)
+		amazon_hw0_irqdispatch();
+	else if (pending & CAUSEF_IP3)
+		amazon_hw1_irqdispatch();
+	else if (pending & CAUSEF_IP4)
+		amazon_hw2_irqdispatch();
+	else if (pending & CAUSEF_IP5)
+		amazon_hw3_irqdispatch();
+	else if (pending & CAUSEF_IP6)
+		amazon_hw4_irqdispatch();
+	else
+		printk("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
+}
+
+static struct irqaction cascade = {
+	.handler	= no_action,
+	.flags  	= SA_INTERRUPT,
+	.name   	= "cascade",
+};
+
+
+/* Function for careful CP0 interrupt mask access */
+
+void __init arch_init_irq(void)
+{
+	int i;
+
+	/* mask all interrupt sources */
+	*AMAZON_ICU_IM0_IER = 0;
+	*AMAZON_ICU_IM1_IER = 0;
+	*AMAZON_ICU_IM2_IER = 0;
+	*AMAZON_ICU_IM3_IER = 0;
+	*AMAZON_ICU_IM4_IER = 0;
+
+	mips_cpu_irq_init();
+
+	/* set up irq cascade */
+	for (i = 2; i <= 6; i++) {
+		setup_irq(i, &cascade);
+	}
+
+	for (i = INT_NUM_IRQ0; i <= INT_NUM_IM4_IRL31; i++) {
+		irq_desc[i].status	= IRQ_DISABLED;
+		irq_desc[i].action	= 0;
+		irq_desc[i].depth	= 1;
+		set_irq_chip(i, &amazon_irq_type);
+	}
+}
+

--- /dev/null
+++ b/target/linux/amazon-2.6/files/arch/mips/amazon/pci.c
@@ -1,1 +1,294 @@
-
+/*
+ *  Carsten Langgaard, carstenl@mips.com
+ *  Copyright (C) 1999, 2000 MIPS Technologies, Inc.  All rights reserved.
+ *  Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.
+ */
+
+/* FIXME: convert nasty volatile register derefs to readl/writel calls */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/paccess.h>
+#include <asm/amazon/irq.h>
+#include <asm/amazon/amazon.h>
+
+#define AMAZON_PCI_REG32( addr )		  (*(volatile u32 *)(addr))
+#ifndef AMAZON_PCI_MEM_BASE
+#define AMAZON_PCI_MEM_BASE    0xb2000000
+#endif
+#define AMAZON_PCI_MEM_SIZE    0x00400000
+#define AMAZON_PCI_IO_BASE     0xb2400000
+#define AMAZON_PCI_IO_SIZE     0x00002000
+
+#define AMAZON_PCI_CFG_BUSNUM_SHF 16
+#define AMAZON_PCI_CFG_DEVNUM_SHF 11
+#define AMAZON_PCI_CFG_FUNNUM_SHF 8
+
+#define PCI_ACCESS_READ  0
+#define PCI_ACCESS_WRITE 1
+
+static inline u32 amazon_r32(u32 addr)
+{
+	u32 *ptr = (u32 *) addr;
+	return __raw_readl(ptr);
+}
+
+static inline void amazon_w32(u32 addr, u32 val)
+{
+	u32 *ptr = (u32 *) addr;
+	__raw_writel(val, ptr);
+}
+
+
+static struct resource pci_io_resource = {
+	.name = "io pci IO space",
+#if 0
+	.start = AMAZON_PCI_IO_BASE,
+	.end = AMAZON_PCI_IO_BASE + AMAZON_PCI_IO_SIZE - 1,
+#endif
+	.start = 0,
+	.end = AMAZON_PCI_IO_SIZE - 1,
+	.flags = IORESOURCE_IO
+};
+
+static struct resource pci_mem_resource = {
+	.name = "ext pci memory space",
+	.start = AMAZON_PCI_MEM_BASE,
+	.end = AMAZON_PCI_MEM_BASE + AMAZON_PCI_MEM_SIZE - 1,
+	.flags = IORESOURCE_MEM
+};
+
+static inline u32 amazon_pci_swap(u32 val)
+{
+#ifdef CONFIG_AMAZON_PCI_HW_SWAP
+	return swab32(val);
+#else
+	return val;
+#endif
+}
+
+static int amazon_pci_config_access(unsigned char access_type,
+	struct pci_bus *bus, unsigned int devfn, unsigned int where, u32 *data)
+{
+	unsigned long flags;
+	u32 pci_addr;
+	u32 val;
+	int ret;
+   
+	/* Amazon support slot from 0 to 15 */
+	/* devfn 0 & 0x20 is itself */
+	if ((bus != 0) || (devfn == 0) || (devfn == 0x20))
+		return 1;
+
+	pci_addr=AMAZON_PCI_CFG_BASE |
+		bus->number << AMAZON_PCI_CFG_BUSNUM_SHF |
+		devfn << AMAZON_PCI_CFG_FUNNUM_SHF |
+		(where & ~0x3);
+    
+	local_irq_save(flags);
+	if (access_type == PCI_ACCESS_WRITE) {
+		val = amazon_pci_swap(*data);
+		ret = put_dbe(val, (u32 *)pci_addr);
+	} else {
+		ret = get_dbe(val, (u32 *)pci_addr);
+		*data = amazon_pci_swap(val);
+	}
+
+	amazon_w32(PCI_MODE, amazon_r32(PCI_MODE) & (~(1<<PCI_MODE_cfgok_bit)));
+	amazon_w32(STATUS_COMMAND_ADDR, amazon_r32(STATUS_COMMAND_ADDR));
+	amazon_w32(PCI_MODE, amazon_r32(PCI_MODE) | (~(1<<PCI_MODE_cfgok_bit)));
+	local_irq_restore(flags);
+
+	return ret; 
+}
+
+
+static int amazon_pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val)
+{
+	u32 data = 0;
+	int ret = PCIBIOS_SUCCESSFUL;
+
+	if (amazon_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) {
+		data = ~0;
+		ret = -1;
+	}
+
+	switch (size) {
+		case 1:
+			*((u8 *) val) = (data >> ((where & 3) << 3)) & 0xff;
+			break;
+		case 2:
+			*((u16 *) val) = (data >> ((where & 3) << 3)) & 0xffff;
+			break;
+		case 4:
+			*val = data;
+			break;
+		default:
+			return -1;
+	}
+
+	return ret;
+}
+
+
+static int amazon_pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val)
+{
+	if (size != 4) {
+		u32 data;
+
+		if (amazon_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+			return -1;
+
+		if (size == 1)
+			val = (data & ~(0xff << ((where & 3) << 3))) | (val << ((where & 3) << 3));
+		else if (size == 2)
+			val = (data & ~(0xffff << ((where & 3) << 3))) | (val << ((where & 3) << 3));
+		else
+			return -1;
+	}
+
+	if (amazon_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val))
+	       return -1;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops amazon_pci_ops = {
+	amazon_pci_read,
+	amazon_pci_write
+};
+
+static struct pci_controller amazon_pci_controller = {
+	.pci_ops = &amazon_pci_ops,
+	.mem_resource = &pci_mem_resource,
+	.io_resource = &pci_io_resource
+};
+
+int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	switch (slot) {
+		case 13:
+			/* IDSEL = AD29 --> USB Host Controller */
+			return INT_NUM_IM2_IRL15;
+		case 14:
+			/* IDSEL = AD30 --> mini PCI connector */
+			return INT_NUM_IM2_IRL14;
+		default:
+			printk("Warning: no IRQ found for PCI device in slot %d, pin %d\n", slot, pin);
+			return 0;
+	}
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+	switch(dev->irq) {
+		case INT_NUM_IM2_IRL15:
+			/* 
+			 * IDSEL = AD29 --> USB Host Controller
+			 * PCI_INTA/B/C--GPIO Port0.2--EXIN3
+			 * IN/ALT0:1 ALT1:0
+			 * PULL UP
+			 */
+			(*AMAZON_GPIO_P0_DIR) = (*AMAZON_GPIO_P0_DIR) & 0xfffffffb;
+			(*AMAZON_GPIO_P0_ALTSEL0) = (*AMAZON_GPIO_P0_ALTSEL0)| 4;
+			(*AMAZON_GPIO_P0_ALTSEL1) = (*AMAZON_GPIO_P0_ALTSEL1)& 0xfffffffb;
+			(*AMAZON_GPIO_P0_PUDSEL) =  (*AMAZON_GPIO_P0_PUDSEL) | 4;
+			(*AMAZON_GPIO_P0_PUDEN) = (*AMAZON_GPIO_P0_PUDEN) | 4;
+			//External Interrupt Node
+			(*AMAZON_ICU_EXTINTCR) = (*AMAZON_ICU_EXTINTCR)|0x6000; /* Low Level triggered */
+			(*AMAZON_ICU_IRNEN) = (*AMAZON_ICU_IRNEN)|0x8;
+			pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+			break;
+		case INT_NUM_IM2_IRL14:
+			/* 
+			 * IDSEL = AD30 --> mini PCI connector 
+			 * PCI_INTA--GPIO Port0.1--EXIN2
+			 * IN/ALT0:1 ALT1:0
+			 * PULL UP
+			 */
+			(*AMAZON_GPIO_P0_DIR) = (*AMAZON_GPIO_P0_DIR) & 0xfffffffd;
+			(*AMAZON_GPIO_P0_ALTSEL0) = (*AMAZON_GPIO_P0_ALTSEL0)| 2;
+			(*AMAZON_GPIO_P0_ALTSEL1) = (*AMAZON_GPIO_P0_ALTSEL1)& 0xfffffffd;
+			(*AMAZON_GPIO_P0_PUDSEL) =  (*AMAZON_GPIO_P0_PUDSEL) | 2;
+			(*AMAZON_GPIO_P0_PUDEN) = (*AMAZON_GPIO_P0_PUDEN) | 2;
+			//External Interrupt Node
+			(*AMAZON_ICU_EXTINTCR) = (*AMAZON_ICU_EXTINTCR)|0x600;
+			(*AMAZON_ICU_IRNEN) = (*AMAZON_ICU_IRNEN)|0x4;
+			pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+			break;
+		default:
+			return 1;
+	}
+	return 0;
+}
+
+int amazon_pci_init(void)
+{
+	u32 temp_buffer;
+
+#ifdef CONFIG_AMAZON_PCI_HW_SWAP
+	AMAZON_PCI_REG32(IRM) = AMAZON_PCI_REG32(IRM) | (1<<27) | (1<<28);
+	wmb();
+#endif
+
+	AMAZON_PCI_REG32(CLOCK_CONTROL) = AMAZON_PCI_REG32(CLOCK_CONTROL) | (1<<ARB_CTRL_bit);
+	amazon_w32(PCI_MODE, amazon_r32(PCI_MODE) & (~(1<<PCI_MODE_cfgok_bit)));
+
+	AMAZON_PCI_REG32(STATUS_COMMAND_ADDR) = AMAZON_PCI_REG32(STATUS_COMMAND_ADDR) | (1<<BUS_MASTER_ENABLE_BIT) |(1<<MEM_SPACE_ENABLE_BIT);
+
+	temp_buffer = AMAZON_PCI_REG32(PCI_ARB_CTRL_STATUS_ADDR);
+	temp_buffer = temp_buffer | (1<< INTERNAL_ARB_ENABLE_BIT);
+	temp_buffer = temp_buffer & ~(3<< PCI_MASTER0_REQ_MASK_2BITS);
+	temp_buffer = temp_buffer & ~(3<< PCI_MASTER0_GNT_MASK_2BITS);
+
+	/* flash */
+	temp_buffer = temp_buffer & ~(3<< PCI_MASTER1_REQ_MASK_2BITS);
+	temp_buffer = temp_buffer & ~(3<< PCI_MASTER1_GNT_MASK_2BITS);
+
+	/* external master */
+	temp_buffer = temp_buffer & ~(3<< PCI_MASTER2_REQ_MASK_2BITS);
+	temp_buffer = temp_buffer & ~(3<< PCI_MASTER2_GNT_MASK_2BITS);
+
+	AMAZON_PCI_REG32(PCI_ARB_CTRL_STATUS_ADDR) = temp_buffer;
+	wmb();
+
+	AMAZON_PCI_REG32(FPI_ADDRESS_MAP_0) = 0xb2000000;
+	AMAZON_PCI_REG32(FPI_ADDRESS_MAP_1) = 0xb2100000;
+	AMAZON_PCI_REG32(FPI_ADDRESS_MAP_2) = 0xb2200000;
+	AMAZON_PCI_REG32(FPI_ADDRESS_MAP_3) = 0xb2300000;
+	AMAZON_PCI_REG32(FPI_ADDRESS_MAP_4) = 0xb2400000;
+	AMAZON_PCI_REG32(FPI_ADDRESS_MAP_5) = 0xb2500000;
+	AMAZON_PCI_REG32(FPI_ADDRESS_MAP_6) = 0xb2600000;
+	AMAZON_PCI_REG32(FPI_ADDRESS_MAP_7) = 0xb2700000;
+	   
+	AMAZON_PCI_REG32(BAR11_MASK) = 0x0f000008;
+	AMAZON_PCI_REG32(PCI_ADDRESS_MAP_11) = 0x0;
+	AMAZON_PCI_REG32(BAR1_ADDR) = 0x0;
+	amazon_w32(PCI_MODE, amazon_r32(PCI_MODE) | (~(1<<PCI_MODE_cfgok_bit)));
+	//use 8 dw burse length
+	AMAZON_PCI_REG32(FPI_BURST_LENGTH) = 0x303;
+
+	set_io_port_base(ioremap(AMAZON_PCI_IO_BASE, AMAZON_PCI_IO_SIZE));
+	register_pci_controller(&amazon_pci_controller);
+	return 0;
+}
+arch_initcall(amazon_pci_init);
+

--- /dev/null
+++ b/target/linux/amazon-2.6/files/arch/mips/amazon/prom.c
@@ -1,1 +1,62 @@
+/*
+ * copyright 2007 john crispin <blogic@openwrt.org> 
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/ioport.h>
+#include <asm/bootinfo.h>
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/irq.h>
+#include <asm/amazon/model.h>
+#include <asm/cpu.h>
 
+void prom_putchar(char c)
+{
+	/* Wait for FIFO to empty */
+	while (((*AMAZON_ASC_FSTAT) >> 8) != 0x00) ;
+	/* Crude cr/nl handling is better than none */
+	if(c == '\n')
+		*AMAZON_ASC_TBUF=('\r');
+	*AMAZON_ASC_TBUF=(c);
+}
+
+void prom_printf(const char * fmt, ...)
+{
+	va_list args;
+	int l;
+	char *p, *buf_end;
+	char buf[1024];	
+
+	va_start(args, fmt);
+	l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */
+	va_end(args);
+	buf_end = buf + l;
+	
+	for (p = buf; p < buf_end; p++)
+		prom_putchar(*p);
+}
+
+
+void __init prom_init(void)
+{
+	mips_machgroup = MACH_GROUP_INFINEON;
+	mips_machtype = MACH_INFINEON_AMAZON;
+
+	strcpy(&(arcs_cmdline[0]), "console=ttyS0,115200 rootfstype=squashfs,jffs2 init=/etc/preinit");
+	
+	add_memory_region(0x00000000, 0x1000000, BOOT_MEM_RAM);
+}
+
+void prom_free_prom_memory(void)
+{
+}
+
+const char *get_system_type(void)
+{
+	return BOARD_SYSTEM_TYPE;
+}
+

--- /dev/null
+++ b/target/linux/amazon-2.6/files/arch/mips/amazon/setup.c
@@ -1,1 +1,217 @@
-
+/*
+ *	 Copyright (C) 2004 Peng Liu <peng.liu@infineon.com>
+ *	 Copyright (C) 2007 John Crispin <blogic@openwrt.org>
+ *	 Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ *	 
+ *   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; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   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 <linux/init.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/reboot.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/irq.h>
+#include <asm/amazon/model.h>
+
+extern void prom_printf(const char * fmt, ...);
+static void amazon_reboot_setup(void);
+
+/* the CPU clock rate - lifted from u-boot */
+unsigned int amazon_get_cpu_hz(void)
+{
+	/*-----------------------------------*/
+	/**CGU CPU Clock Reduction Register***/ 
+	/*-----------------------------------*/
+	switch((*AMAZON_CGU_CPUCRD) & 0x3){
+		case 0:
+			/*divider ration 1/1, 235 MHz clock */
+			return 235000000;
+		case 1:
+			/*divider ration 2/3, 235 MHz clock, clock not accurate, here */
+			return 150000000;
+		case 2:
+			/*divider ration 1/2, 235 MHz clock */
+			return 117500000;
+		default:
+			/*divider ration 1/4, 235 MHz clock */
+			return 58750000;
+	}
+}
+
+/* the FPI clock rate - lifted from u-boot */
+unsigned int amazon_get_fpi_hz(void)
+{
+	unsigned int  clkCPU;
+	clkCPU = amazon_get_cpu_hz();
+
+	/*-------------------------------------*/
+	/***CGU Clock Divider Select Register***/
+	/*-------------------------------------*/
+	switch ((*AMAZON_CGU_DIV) & 0x3)
+	{
+		case 1:
+			return clkCPU >> 1;
+		case 2:
+			return clkCPU >> 2;
+		default:
+			return clkCPU;
+		/* '11' is reserved */
+	}
+}
+
+/* get the CPU version number  - based on sysLib.c from VxWorks sources */
+/* this doesn't really belong here, but it's a convenient location */
+unsigned int amazon_get_cpu_ver(void)
+{
+	static unsigned int cpu_ver = 0;
+	if (cpu_ver == 0)
+		cpu_ver = *AMAZON_MCD_CHIPID & 0xFFFFF000;
+	return cpu_ver;
+}
+
+void amazon_time_init(void)
+{
+	mips_hpt_frequency = amazon_get_cpu_hz()/2;
+	printk("mips_hpt_frequency:%d\n",mips_hpt_frequency);
+}
+
+extern int hr_time_resolution;
+
+/* ISR GPTU Timer 6 for high resolution timer */
+static void amazon_timer6_interrupt(int irq, void *dev_id)
+{
+	timer_interrupt(AMAZON_TIMER6_INT, NULL);
+}
+
+static struct irqaction hrt_irqaction = {
+	.handler = amazon_timer6_interrupt,
+	.flags = SA_INTERRUPT,
+	.name = "hrt",
+};
+
+/*
+ * THe CPU counter for System timer, set to HZ
+ * GPTU Timer 6 for high resolution timer, set to hr_time_resolution
+ * Also misuse this routine to print out the CPU type and clock.
+ */
+void __init plat_timer_setup(struct irqaction *irq)
+{
+	/* cpu counter for timer interrupts */
+	setup_irq(MIPS_CPU_TIMER_IRQ, irq);
+
+#if 0
+	/* to generate the first CPU timer interrupt */
+	write_c0_compare(read_c0_count() + amazon_get_cpu_hz()/(2*HZ));
+#endif
+
+	/* enable the timer in the PMU */
+	*(AMAZON_PMU_PWDCR) = (*(AMAZON_PMU_PWDCR))| AMAZON_PMU_PWDCR_GPT|AMAZON_PMU_PWDCR_FPI;
+	/* setup the GPTU for timer tick  f_fpi == f_gptu*/
+	*(AMAZON_GPTU_CLC) = 0x100;
+
+	*(AMAZON_GPTU_CAPREL) = 0xffff;
+	*(AMAZON_GPTU_T6CON) = 0x80C0;
+	//setup_irq(AMAZON_TIMER6_INT,&hrt_irqaction);
+
+#if 0
+#ifdef CONFIG_HIGH_RES_TIMERS
+	/* GPTU timer 6 */
+	int retval;
+	if ( hr_time_resolution > 200000000 || hr_time_resolution < 40) {
+		prom_printf("hr_time_resolution is out of range, HIGH_RES_TIMER is diabled.\n");
+		return;
+	}
+	
+	/* enable the timer in the PMU */
+        *(AMAZON_PMU_PWDCR) = (*(AMAZON_PMU_PWDCR))| AMAZON_PMU_PWDCR_GPT|AMAZON_PMU_PWDCR_FPI;
+	/* setup the GPTU for timer tick  f_fpi == f_gptu*/
+	*(AMAZON_GPTU_CLC) = 0x100;
+
+	*(AMAZON_GPTU_CAPREL) = 0xffff;
+	*(AMAZON_GPTU_T6CON) = 0x80C0;
+	
+	retval = setup_irq(AMAZON_TIMER6_INT,&hrt_irqaction);
+	if (retval){
+		prom_printf("reqeust_irq failed %d. HIGH_RES_TIMER is diabled\n",AMAZON_TIMER6_INT);		
+	}
+#endif //CONFIG_HIGH_RES_TIMERS		
+#endif
+}
+
+void __init plat_mem_setup(void)
+{	
+	u32 chipid = 0;
+	u32 part_no = 0;
+	
+	chipid = *(AMAZON_MCD_CHIPID);
+	part_no = AMAZON_MCD_CHIPID_PART_NUMBER_GET(chipid);
+	
+	if(part_no == AMAZON_CHIPID_YANGTSE){
+		prom_printf("Yangtse Version\n");	
+	} else if (part_no == AMAZON_CHIPID_STANDARD) {
+		prom_printf(SYSTEM_MODEL_NAME "\n");
+	} else {
+		prom_printf("unknown version %8x\n",part_no);
+	}
+	
+	amazon_reboot_setup();
+	board_time_init = amazon_time_init;
+
+	//stop reset TPE and DFE
+	*(AMAZON_RST_REQ) = 0x0;
+	//clock
+	*(AMAZON_PMU_PWDCR) = 0x3fff;
+	//reenable trace capability
+	part_no = *(AMAZON_BCU_ECON);
+}
+
+static void amazon_machine_restart(char *command)
+{
+    local_irq_disable();
+    *AMAZON_RST_REQ = AMAZON_RST_ALL;
+    for (;;) ;
+}
+
+static void amazon_machine_halt(void)
+{
+    printk(KERN_NOTICE "System halted.\n");
+    local_irq_disable();
+    for (;;) ;
+}
+
+static void amazon_machine_power_off(void)
+{
+	printk(KERN_NOTICE "Please turn off the power now.\n");
+    local_irq_disable();
+    for (;;) ;
+}
+
+static void amazon_reboot_setup(void)
+{
+	_machine_restart = amazon_machine_restart;
+	_machine_halt = amazon_machine_halt;
+	pm_power_off = amazon_machine_power_off;
+}
+

--- /dev/null
+++ b/target/linux/amazon-2.6/files/drivers/atm/amazon_tpe.c
@@ -1,1 +1,3075 @@
-
+/*
+ *   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; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   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.
+ */
+//-----------------------------------------------------------------------
+/*
+ * Description:
+ *	Driver for Infineon Amazon TPE
+ */
+//-----------------------------------------------------------------------
+/* Author:	peng.liu@infineon.com
+ * Created:	12-April-2004
+ */
+//-----------------------------------------------------------------------
+/* History
+ * Last changed on: 13 Oct. 2004
+ * Last changed by: peng.liu@infineon.com
+ * Last changed on: 28 Jan. 2004
+ * Last changed by: peng.liu@infineon.com
+ * Last changed Reason:
+ *	- AAL5R may send more bytes than expected in MFL (so far, confirmed as 64 bytes)
+ */
+// 507261:tc.chen 2005/07/26 re-organize code address map to improve performance.
+// 507281:tc.chen 2005/07/28 fix f4 segment isssue
+/* 511045:linmars 2005/11/04 from Liu.Peng: change NRT_VBR bandwidth calculation based on scr instead of pcr */
+ 
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif 
+#ifndef EXPORT_SYMTAB
+#define EXPORT_SYMTAB
+#endif
+
+/*TPE level loopback, bypass AWARE DFE */
+#undef TPE_LOOPBACK
+
+/* enable debug options */			
+#undef AMAZON_ATM_DEBUG
+
+/* enable rx error packet analysis */
+#undef AMAZON_ATM_DEBUG_RX
+
+/* test AAL5 Interrupt */
+#undef  AMAZON_TPE_TEST_AAL5_INT
+
+/* dump packet */
+#undef AMAZON_TPE_DUMP
+
+/* read ARC register*/
+/* this register is located in side DFE module*/
+#undef AMAZON_TPE_READ_ARC
+
+/* software controlled reassembly */
+#undef AMAZON_TPE_SCR
+
+/* recovery from AAL5 bug */
+#undef AMAZON_TPE_AAL5_RECOVERY
+
+#if defined(AMAZON_TPE_READ_ARC) || defined(AMAZON_TPE_AAL5_RECOVERY)
+#define ALPHAEUS_BASE_ADDR	0x31c00
+#define A_CFG_ADDR		(ALPHAEUS_BASE_ADDR+0x04)
+#define AR_CB0_STATUS_ADDR		(ALPHAEUS_BASE_ADDR+0x2c)
+#define AR_CB1_STATUS_ADDR		(ALPHAEUS_BASE_ADDR+0x30)
+#define AT_CELL0_ADDR		(ALPHAEUS_BASE_ADDR+0x90)
+#define AR_CELL0_ADDR		(ALPHAEUS_BASE_ADDR+0x1a0)
+#define AR_CD_CNT0_ADDR		(ALPHAEUS_BASE_ADDR+0x1c8)
+#endif
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h> 
+#include <linux/slab.h>  
+#include <linux/fs.h> 
+#include <linux/types.h>
+#include <linux/errno.h>  
+#include <linux/time.h>
+#include <linux/atm.h>
+#include <linux/atmdev.h>
+#include <linux/netdevice.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/irq.h>
+
+#include <linux/in.h>
+#include <linux/netdevice.h> 
+#include <linux/etherdevice.h> 
+#include <linux/ip.h>
+#include <linux/tcp.h> 
+#include <linux/skbuff.h>
+#include <linux/in6.h>
+#include <linux/delay.h>
+#include <asm/amazon/atm_defines.h>
+#include <asm/amazon/amazon_dma.h>
+#include <asm/amazon/amazon_tpe.h>
+
+#if defined(AMAZON_TPE_READ_ARC) || defined(AMAZON_TPE_AAL5_RECOVERY)
+#include <asm/amazon/amazon_mei.h>
+#include <asm/amazon/amazon_mei_app.h>
+#endif
+
+#define AMAZON_TPE_EMSG(fmt, args...) printk( KERN_ERR  "%s: " fmt,__FUNCTION__, ## args)
+
+/***************************************** External Functions *******************************************/
+extern unsigned int amazon_get_fpi_hz(void);
+extern void mask_and_ack_amazon_irq(unsigned int irq_nr);
+extern void amz_push_oam(unsigned char *);
+
+//amazon_mei.c
+#if defined(AMAZON_TPE_READ_ARC) || defined(AMAZON_TPE_AAL5_RECOVERY)
+extern MEI_ERROR meiDebugRead(u32 srcaddr, u32 *databuff, u32 databuffsize);
+extern MEI_ERROR meiDebugWrite(u32 destaddr, u32 *databuff, u32 databuffsize);
+#endif
+
+/***************************************** Internal Functions *******************************************/
+int amazon_atm_read_procmem(char *buf, char **start, off_t offset,int count, int *eof, void *data);
+/***************************************** Global Data *******************************************/
+amazon_atm_dev_t g_atm_dev;		//device data
+static struct tq_struct swex_start_task;	//BH task
+static struct tq_struct swex_complete_task;	//BH task
+#ifdef AMAZON_TPE_SCR
+static struct tq_struct a5r_task; 		//BH task
+#endif
+static struct dma_device_info 	g_dma_dev;	//for DMA
+static struct atm_dev * amazon_atm_devs[AMAZON_ATM_PORT_NUM];
+static struct oam_last_activity g_oam_time_stamp[AMAZON_ATM_MAX_VCC_NUM];
+static u8 g_oam_cell[AMAZON_AAL0_SDU+4];	//for OAM cells
+#ifdef AMAZON_CHECK_LINK
+static int adsl_link_status;			//ADSL link status, 0:down, 1:up
+#endif //AMAZON_CHECK_LINK
+/***************************************** Module Parameters *************************************/
+// Parameter Definition for module
+static int port_enable0 = 1;				// Variable for parameter port_enable0
+static int port_enable1 = 0;				// Variable for parameter port_enable1
+static int port_max_conn0 = 15;				// Variable for parameter port_max_conn0
+static int port_max_conn1 = 0;				// Variable for parameter port_max_conn1
+static int port_cell_rate_up0 = 7500;			// Variable for parameter port_cell_rate_up0
+static int port_cell_rate_up1 = 7500;			// Variable for parameter port_cell_rate_up1
+
+
+static int qsb_tau = 1;					// Variable for parameter qsb_tau
+static int qsb_srvm = 0xf;				// Variable for parameter qsb_srvm
+static int qsb_tstep = 4 ;				// Variable for parameter qsb_tstep
+
+static int cbm_nrt = 3900;				// Variable for parameter cbm_nrt
+static int cbm_clp0 =3500;				// Variable for parameter cbm_clp0
+static int cbm_clp1 =3200;				// Variable for parameter cbm_clp1
+static int cbm_free_cell_no = AMAZON_ATM_FREE_CELLS;	// Variable for parameter cbm_free_cell_no
+
+static int a5_fill_pattern = 0x7e;			// Variable for parameter a5_fill_pattern '~'
+static int a5s_mtu = 0x700;				// mtu for tx
+static int a5r_mtu = 0x700;				// mtu for rx
+
+static int oam_q_threshold = 	64;			// oam queue threshold, minium value 64
+static int rx_q_threshold = 	1000;			// rx queue threshold, minium value 64
+static int tx_q_threshold = 	800;			// tx queue threshold, minium value 64
+
+MODULE_PARM(port_max_conn0, "i");
+MODULE_PARM_DESC(port_max_conn0, "Maximum atm connection for port #0");
+MODULE_PARM(port_max_conn1, "i");
+MODULE_PARM_DESC(port_max_conn1, "Maximum atm connection for port #1");
+MODULE_PARM(port_enable0, "i");
+MODULE_PARM_DESC(port_enable0, "0 -> port disabled, 1->port enabled");
+MODULE_PARM(port_enable1, "i");
+MODULE_PARM_DESC(port_enable1, "0 -> port disabled, 1->port enabled");
+MODULE_PARM(port_cell_rate_up0, "i");
+MODULE_PARM_DESC(port_cell_rate_up0, "ATM port upstream rate in cells/s");
+MODULE_PARM(port_cell_rate_up1, "i");
+MODULE_PARM_DESC(port_cell_rate_up1, "ATM port upstream rate in cells/s");
+
+MODULE_PARM(qsb_tau,"i");
+MODULE_PARM_DESC(qsb_tau, "Cell delay variation. value must be > 0");
+MODULE_PARM(qsb_srvm, "i");
+MODULE_PARM_DESC(qsb_srvm, "Maximum burst size");
+MODULE_PARM(qsb_tstep, "i");
+MODULE_PARM_DESC(qsb_tstep, "n*32 cycles per sbs cycles n=1,2,4");
+
+MODULE_PARM(cbm_nrt, "i");
+MODULE_PARM_DESC(cbm_nrt, "Non real time threshold for cell buffer");
+MODULE_PARM(cbm_clp0, "i");
+MODULE_PARM_DESC(cbm_clp0, "Threshold for cells with cell loss priority 0");
+MODULE_PARM(cbm_clp1, "i");
+MODULE_PARM_DESC(cbm_clp1, "Threshold for cells with cell loss priority 1");
+MODULE_PARM(cbm_free_cell_no, "i");
+MODULE_PARM_DESC(cbm_free_cell_no, "Number of cells in the cell buffer manager");
+
+MODULE_PARM(a5_fill_pattern, "i");
+MODULE_PARM_DESC(a5_fill_pattern, "filling pattern (PAD) for aal5 frames");
+MODULE_PARM(a5s_mtu, "i");
+MODULE_PARM_DESC(a5s_mtu, "max. SDU for upstream");
+MODULE_PARM(a5r_mtu, "i");
+MODULE_PARM_DESC(a5r_mtu, "max. SDU for downstream");                                                                               
+
+MODULE_PARM(oam_q_threshold, "i");
+MODULE_PARM_DESC(oam_q_threshold, "oam queue threshold");
+
+MODULE_PARM(rx_q_threshold, "i");
+MODULE_PARM_DESC(rx_q_threshold, "downstream/rx queue threshold");
+
+MODULE_PARM(tx_q_threshold, "i");
+MODULE_PARM_DESC(tx_q_threshold, "upstream/tx queue threshold");
+
+/***************************************** local functions *************************************/
+/* Brief: valid QID
+ * Return: 1 if valid
+ * 	   0 if not
+ */
+static inline int valid_qid(int qid)
+{
+	return ( (qid>0) && (qid<AMAZON_ATM_MAX_QUEUE_NUM));
+}
+
+/*
+ * Brief: align to 16 bytes boundary 
+ * Parameter:
+ *	skb
+ * Description:
+ *	use skb_reserve to adjust the data pointer
+ *	don't change head pointer
+ *	pls allocate extrac 16 bytes before call this function
+ */
+static void inline alloc_align_16(struct sk_buff * skb)
+{
+	if ( ( ((u32) (skb->data)) & 15) != 0){
+		AMAZON_TPE_DMSG("need to adjust the alignment manually\n");
+		skb_reserve(skb, 16 - (((u32) (skb->data)) & 15) );
+	}
+
+}
+
+/*
+ * Brief: initialize the device according to the module paramters
+ * Return: not NULL	-	ok
+ *	   NULL		-	fails
+ * Description: arrange load parameters and call the hardware initialization routines
+ */
+static void atm_init_parameters(amazon_atm_dev_t *dev)
+{
+	//port setting
+	dev->ports[0].enable = port_enable0;
+	dev->ports[0].max_conn = port_max_conn0;
+	dev->ports[0].tx_max_cr = port_cell_rate_up0;
+	if (port_enable1){
+		dev->ports[1].enable = port_enable1;
+		dev->ports[1].max_conn = port_max_conn1;
+		dev->ports[1].tx_max_cr = port_cell_rate_up1;
+	}
+
+	//aal5
+	dev->aal5.padding_byte = a5_fill_pattern;
+	dev->aal5.tx_max_sdu = a5s_mtu;
+	dev->aal5.rx_max_sdu = a5r_mtu;
+
+	//cbm
+	dev->cbm.nrt_thr = cbm_nrt;
+	dev->cbm.clp0_thr = cbm_clp0;
+	dev->cbm.clp1_thr = cbm_clp1;
+	dev->cbm.free_cell_cnt = cbm_free_cell_no;
+
+	//qsb
+	dev->qsb.tau = qsb_tau;
+	dev->qsb.tstepc =qsb_tstep;
+	dev->qsb.sbl = qsb_srvm;
+	
+	//allocate on the fly
+	dev->cbm.mem_addr = NULL;
+	dev->cbm.qd_addr = NULL;
+}
+
+
+/*	Brief: 		Find QID for VCC
+ *	Parameters:	vcc	- VCC data structure
+ *  	Return Value:	-EINVAL		- VCC not found
+ *			qid		- QID for this VCC
+ *	Description:
+ *	This function returns the QID of a given VCC
+ */
+static int amazon_atm_get_queue(struct atm_vcc* vcc)
+{
+	int	i;
+	for (i=0;i<AMAZON_ATM_MAX_QUEUE_NUM;i++) {
+		if (g_atm_dev.queues[i].vcc == vcc) return i;
+	}
+	return -EINVAL;
+}
+
+
+/*
+ *	Brief: 		Find QID for VPI/VCI
+ *	Parameters:	vpi	- VPI to found
+ *			vci	- VCI to found
+ *
+ *  	Return Value:	-EINVAL		- VPI/VCI not found
+ *			qid		- QID for this VPI/VCI
+ *
+ *	Description:
+ *	This function returns the QID for a given VPI/VCI. itf doesn't matter
+ */
+static int amazon_atm_find_vpivci(u8 vpi, u16 vci)
+{
+	int	i;
+	struct atm_vcc * vcc;
+	for (i=0;i<AMAZON_ATM_MAX_QUEUE_NUM;i++) {
+		if ( (vcc = g_atm_dev.queues[i].vcc)!= NULL) {
+			if ((vcc->vpi == vpi) && (vcc->vci == vci)) return i;
+		}
+	}
+	return -EINVAL;
+}
+
+/*	Brief: 		Find QID for VPI
+ *	Parameters:	vpi	- VPI to found
+ *  	Return Value:	-EINVAL		- VPI not found
+ *			qid		- QID for this VPI
+ *
+ *	Description:
+ *	This function returns the QID for a given VPI. itf and VCI don't matter
+ */
+static int amazon_atm_find_vpi(u8 vpi)
+{
+	int	i;
+	for (i=0;i<AMAZON_ATM_MAX_QUEUE_NUM;i++) {
+		if ( g_atm_dev.queues[i].vcc!= NULL) {
+			if (g_atm_dev.queues[i].vcc->vpi == vpi) return i;
+		}
+	}
+	return -EINVAL;
+}
+
+/*
+ *	Brief: 		Clears QID entries for VCC
+ *
+ *	Parameters:	vcc	- VCC to found
+ *
+ *	Description:
+ *	This function searches for the given VCC and sets it to NULL if found.
+ */
+static inline void amazon_atm_clear_vcc(int i)
+{
+	g_atm_dev.queues[i].vcc = NULL;
+	g_atm_dev.queues[i].free = 1;
+}
+
+
+/*
+ * Brief:	dump skb data
+ */
+static inline void dump_skb(u32 len, char * data)
+{
+#ifdef AMAZON_TPE_DUMP
+	int i;
+	for(i=0;i<len;i++){	
+		printk("%2.2x ",(u8)(data[i]));
+		if (i % 16 == 15)
+			printk("\n");
+	}
+	printk("\n");
+#endif
+}
+
+/*
+ * Brief:	dump queue descriptor
+ */
+static inline void dump_qd(int qid)
+{
+#ifdef AMAZON_TPE_DUMP
+	u8 * qd_addr;
+	if (valid_qid(qid) != 1) return;
+	qd_addr = (u8 *) KSEG1ADDR((unsigned long)g_atm_dev.cbm.qd_addr);
+	AMAZON_TPE_EMSG("qid: %u [%8x][%8x][%8x][%8x]\n", qid
+		,readl(qd_addr+qid*CBM_QD_SIZE+0x0)
+		,readl(qd_addr+qid*CBM_QD_SIZE+0x4)
+		,readl(qd_addr+qid*CBM_QD_SIZE+0x8)
+		,readl(qd_addr+qid*CBM_QD_SIZE+0xc));
+#endif
+}
+
+/*
+ * Brief:	release TX skbuff
+ */
+static inline void amazon_atm_free_tx_skb_vcc(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+	if ( vcc->pop != NULL) {
+		vcc->pop(vcc, skb);
+	 } else {
+	 	dev_kfree_skb_any(skb);
+        }
+}
+/*
+ * Brief:	release TX skbuff
+ */
+static inline void amazon_atm_free_tx_skb(struct sk_buff *skb)
+{
+	struct atm_vcc* vcc = ATM_SKB(skb)->vcc;
+	if (vcc!=NULL){
+		amazon_atm_free_tx_skb_vcc(vcc,skb);
+	} else {
+		dev_kfree_skb_any(skb);//fchang:Added
+	}
+}
+
+/* Brief:	divide by 64 and round up
+ */
+static inline u32 divide_by_64_round_up(int input)
+{
+	u32 tmp1;
+	tmp1 = (u32) input;
+        tmp1 = (tmp1%64)?(tmp1/64 + 1): (tmp1/64);
+        if (tmp1 == 0) tmp1 = 1;
+	return tmp1;
+}
+
+/*
+ * Brief:	statistics
+ */
+#ifdef AMAZON_ATM_DEBUG
+static inline void queue_statics(int qid, qs_t idx)
+{
+	if (valid_qid(qid)){
+		g_atm_dev.queues[qid].qs[idx]++;
+	}
+}
+#else	//not AMAZON_ATM_DEBUG
+static inline void queue_statics(int qid, qs_t idx){}
+#endif	//AMAZON_ATM_DEBUG		
+
+
+/*	Brief:	set dma tx full, i.e. there is no available descriptors
+ */
+static void inline atm_dma_full(void)
+{
+	AMAZON_TPE_DMSG("ch0 is full\n");
+	atomic_set(&g_atm_dev.dma_tx_free_0,0);
+}
+
+/*
+ *	Brief	set dma tx free (at least one descript is available)
+ */
+inline static void atm_dma_free(void)
+{
+	AMAZON_TPE_DMSG("ch0 is free\n");
+	atomic_set(&g_atm_dev.dma_tx_free_0,1);
+}
+
+
+/*	Brief:		return the status of DMA TX descriptors
+ *	Parameters:	TX channel  (DMA_TX_CH0, TX_CH1)
+ *	Return:
+ *		1:	there are availabel TX descriptors
+ *		0:	no available
+ *	Description:
+ *
+ */
+inline int dma_may_send(int ch)
+{
+	if (atomic_read(&g_atm_dev.dma_tx_free_0)){
+		return 1;
+	}
+	return 0;
+}
+
+/******************************* global functions *********************************/ 
+/*
+ *	Brief: 		SWIE Cell Extraction Start Routine
+ *			and task routine for swex_complete_task
+ *	Parameters:	irq_stat	- interrupt status
+ *
+ *	Description:
+ *	This is the routine for extracting cell. It will schedule itself if the hardware is busy.
+ *	This routine runs in interrupt context
+ */
+void amazon_atm_swex(void * irq_stat)
+{
+	u32 ex_stat=0;
+	u32 addr;
+	// Read extraction status register
+	ex_stat = readl(CBM_HWEXSTAT0_ADDR);
+
+	// Check if extraction/insertion is in progress 
+	if ( (ex_stat & CBM_EXSTAT_SCB) || (ex_stat & CBM_EXSTAT_FB) || (test_and_set_bit(SWIE_LOCK, &(g_atm_dev.swie.lock))!=0)) {
+		AMAZON_TPE_DMSG(" extraction in progress. Will wait\n");
+		swex_start_task.data = irq_stat;
+		queue_task(&swex_start_task, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}else {
+		// Extract QID
+		g_atm_dev.swie.qid = (((u32)irq_stat) >> 24);
+		AMAZON_TPE_DMSG("extracting from qid=%u\n",g_atm_dev.swie.qid);
+		//read status word
+		addr = KSEG1ADDR((unsigned long)g_atm_dev.cbm.qd_addr);
+		addr = readl((addr + g_atm_dev.swie.qid * 0x10 + 4) & 0xFFFFFFC0);
+		addr = KSEG1ADDR(addr);
+		g_atm_dev.swie.sw = readl(addr+52)&SWIE_ADDITION_DATA_MASK;
+		AMAZON_TPE_DMSG("cell addition word: %8x \n", g_atm_dev.swie.sw);
+		
+		// Start extraction
+		AMAZON_WRITE_REGISTER_L(g_atm_dev.swie.qid | SWIE_CBM_PID_SUBADDR, CBM_HWEXPAR0_ADDR);
+		AMAZON_WRITE_REGISTER_L(SWIE_CBM_SCE0, CBM_HWEXCMD_ADDR);
+	}
+}
+#ifdef AMAZON_TPE_SCR
+u32 g_a5r_wait=0;
+/*
+ *	Brief: 		AAL5 Packet Extraction Routine	and task routine for a5r_task
+ *	Parameters:	irq_stat	- interrupt status
+ *
+ *	Description:
+ *	This is the routine for extracting frame. It will schedule itself if the hardware is busy.
+ *	This routine runs in interrupt context
+ */
+void amazon_atm_a5r(void* qid)
+{
+	volatile u32 ex_stat=0;
+	u32 addr;
+	u32 a5r_wait=0;
+
+	ex_stat = readl(CBM_HWEXSTAT0_ADDR);
+#if 0
+	// Check if extraction/insertion is in progress 
+	if ( (ex_stat & CBM_EXSTAT_SCB) || (ex_stat & CBM_EXSTAT_FB) ) {
+		AMAZON_TPE_DMSG(" extraction in progress. Will wait\n");
+		a5r_task.data = qid;
+		queue_task(&a5r_task, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}else {
+		AMAZON_TPE_DMSG("extracting from qid=%u\n",(u8)qid);
+		// Start extraction
+		AMAZON_WRITE_REGISTER_L(((u8)qid) | CBM_HWEXPAR_PN_A5, CBM_HWEXPAR0_ADDR);
+		AMAZON_WRITE_REGISTER_L(CBM_HWEXCMD_FE0, CBM_HWEXCMD_ADDR);
+	}
+#else
+	//while ( (ex_stat & CBM_EXSTAT_SCB) || (ex_stat & CBM_EXSTAT_FB) ) {
+	while ( ex_stat != 0x80){
+		a5r_wait++;
+		ex_stat = readl(CBM_HWEXSTAT0_ADDR);
+#if	0
+		if (a5r_wait >= 0xffffff){
+			a5r_wait=0;
+			printk(".");
+		}
+#endif
+	}
+	if (a5r_wait > g_a5r_wait){
+		g_a5r_wait = a5r_wait;
+	}
+	AMAZON_WRITE_REGISTER_L(((u8)qid) | CBM_HWEXPAR_PN_A5, CBM_HWEXPAR0_ADDR);
+	AMAZON_WRITE_REGISTER_L(CBM_HWEXCMD_FE0, CBM_HWEXCMD_ADDR);
+#endif
+}
+
+#endif //AMAZON_TPE_SCR
+
+/*	Brief:	Handle F4/F5 OAM cell
+ *	Return:
+ *		0	ok
+ *		<0	fails
+ */
+static int inline amazon_handle_oam_cell(void *data, u8 vpi, u16 vci,u32 status)
+{
+	struct atm_vcc*		vcc=NULL;
+	int qid;
+	if (!status&SWIE_EOAM_MASK){
+		AMAZON_TPE_EMSG("unknown cell received, discarded\n");
+		goto amazon_handle_oam_cell_err_exit;
+	}else if (status&SWIE_ECRC10ERROR_MASK){
+		AMAZON_TPE_EMSG("CRC-10 Error Status:%8x, discarded\n", status);
+		goto amazon_handle_oam_cell_err_exit;
+	}else{
+		if(status & (SWIE_EVCI3_MASK |SWIE_EVCI4_MASK)){
+			//F4 level (VPI) OAM, Assume duplex
+			qid = amazon_atm_find_vpi(vpi)+CBM_RX_OFFSET;
+		}else if (status & (SWIE_EPTI4_MASK|SWIE_EPTI5_MASK)){
+			//F5 level (VCI) OAM, Assume duplex
+			qid = amazon_atm_find_vpivci(vpi,vci)+CBM_RX_OFFSET;			
+		}else{
+			qid = -1;
+			AMAZON_TPE_EMSG("non-F4/F5 OAM cells?, discarded\n");
+			goto amazon_handle_oam_cell_err_exit;
+		}
+	}
+	if (valid_qid(qid) && ((vcc = g_atm_dev.queues[qid].vcc)!=NULL)){
+		//TODO, should we do this for ALL OAM types? (Actually only User and CC)
+		g_atm_dev.queues[qid].access_time=xtime;
+		if (vcc->push_oam){
+			(*vcc->push_oam)(vcc,data);
+		}else{
+			amz_push_oam(data);
+		}
+	}else{
+		AMAZON_TPE_EMSG("no VCC yet\n");
+		goto amazon_handle_oam_cell_err_exit;
+	}
+	return 0;
+amazon_handle_oam_cell_err_exit:	
+	dump_skb(AMAZON_AAL0_SDU,(char *)data);	
+	return -1;
+}
+
+/*	Brief:	SWIE Cell Extraction Finish Routine 
+ *		and task routine for swex_complete_task
+ *	Description:
+ *	1.Allocate a buffer of type struct sk_buff
+ *	2.Copy the data from the temporary memory to this buffer
+ *	3.Push the data to upper layer
+ * 	4.Update the statistical data if necessary
+ *	5.Release the temporary data
+
+ */
+void amazon_atm_swex_push(void * data)
+{
+	struct atm_vcc*		vcc=NULL;
+	struct sk_buff*		skb=NULL;
+	struct amazon_atm_cell_header * cell_header;
+	u32 status;
+	int qid;
+	if (!data){
+		AMAZON_TPE_EMSG("data is NULL\n");
+		return;
+	}
+	qid = ((u8*)data)[AMAZON_AAL0_SDU];
+	status = ((u32*)data)[ATM_AAL0_SDU/4];
+	cell_header = (struct amazon_atm_cell_header *) data;
+	if (valid_qid(qid) != 1){
+		AMAZON_TPE_EMSG("error qid: %u\n",qid);
+		AMAZON_TPE_EMSG("unknown cells recieved\n");
+	}else if (qid == AMAZON_ATM_OAM_Q_ID){
+		//OAM or RM or OTHER cell
+		//Find real connection
+		
+#ifdef IKOS_MINI_BOOT	
+		//for OAM loop back test
+		dump_skb(56,(char *)data);
+		//kfree(data);	using g_oam_cell
+		return;
+#endif //IKOS_MINI_BOOT				
+#ifdef TPE_LOOPBACK					
+		amz_push_oam(data);
+		return;
+#endif//TPE_LOOPBACK
+		int ret = 0;
+		ret = amazon_handle_oam_cell(data,cell_header->bit.vpi,cell_header->bit.vci,status);
+		if (ret == 0)
+					return;
+				}else{
+		//should be normal AAL0 cells
+		// Get VCC
+		vcc = g_atm_dev.queues[qid].vcc;
+		if (vcc != NULL) {
+			AMAZON_TPE_DMSG("push to upper layer\n");
+			skb = dev_alloc_skb(AMAZON_AAL0_SDU);
+			if (skb != NULL) {
+				//skb->dev=vcc->dev;
+				memcpy(skb_put(skb, AMAZON_AAL0_SDU), data, AMAZON_AAL0_SDU);
+				skb->stamp = xtime;
+				ATM_SKB(skb)->vcc = vcc;
+				(*g_atm_dev.queues[qid].push)(vcc,skb,0);
+			}else{
+				AMAZON_TPE_EMSG(" No memory left for incoming AAL0 cell! Cell discarded!\n");
+				//inform the upper layer
+				(*g_atm_dev.queues[qid].push)(vcc,skb,-ENOMEM);
+				atomic_inc(&vcc->stats->rx_drop);
+			}
+		}else{
+			AMAZON_TPE_EMSG("invalid qid %u\n",qid);
+		}
+	}
+	//kfree(data);	using g_oam_cell
+}
+
+/*
+ *	Brief: 		Interrupt handler for software cell extraction (done)
+ *	Parameters:	irq	- CPPN for this interrupt
+ *			data	- Device ID for this interrupt
+ *			regs	- Register file
+ *
+ *	Description:
+ *	When a software extraction is finished this interrupt is issued.
+ *	It reads the cell data and sends it to the ATM stack.
+ */
+void amazon_atm_swex_isr(int irq, void *data, struct pt_regs *regs)
+{
+	u32 * cell = NULL;
+	int i;
+	//ATM_AAL0 SDU + QID
+	AMAZON_TPE_DMSG("SWIE extraction done\n");
+	cell = (u32 *) g_oam_cell;
+	if (cell != NULL){
+		//convert to host byte order from big endian
+		for(i=0;i<ATM_AAL0_SDU;i+=4){
+			cell[i/4]=readl(SWIE_ECELL_ADDR+i);	
+		}
+		cell[ATM_AAL0_SDU/4]= g_atm_dev.swie.sw;
+		((u8*)cell)[AMAZON_AAL0_SDU] = g_atm_dev.swie.qid;
+#ifdef IKOS_MINI_BOOT
+	for(i=0;i<ATM_AAL0_SDU;i+=4){
+		AMAZON_TPE_DMSG("[%2x][%2x][%2x][%2x]\n",
+			((char*)cell)[i],
+			((char*)cell)[i+1],
+			((char*)cell)[i+2],
+			((char*)cell)[i+3]
+			);
+	}
+	AMAZON_TPE_DMSG("qid: %u\n", ((u8*)cell)[AMAZON_AAL0_SDU]);
+	amazon_atm_swex_push((void *) cell);
+#else //not IKOS_MINI_BOOT
+	swex_complete_task.data = cell;
+	queue_task(&swex_complete_task,&tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+#endif //not IKOS_MINI_BOOT
+	}else{
+		AMAZON_TPE_EMSG("no memory for receiving AAL0 cell\n");
+	}
+	
+	/* release the lock and check */
+	if (test_and_clear_bit(SWIE_LOCK,&(g_atm_dev.swie.lock)) == 0){
+		AMAZON_TPE_EMSG("swie lock is already released\n");
+	}
+	wake_up(&g_atm_dev.swie.sleep);
+}
+/*	Brief: 		Interrupt handler for software cell insertion
+ *
+ *	Parameters:	irq	- CPPN for this interrupt
+ *			data	- Device ID for this interrupt
+ *			regs	- Register file
+ *
+ *	Description:
+ *	When a software insertion is finished this interrupt is issued.
+ *	The only purpose is to release the semaphore and read the status register.
+ */
+void amazon_atm_swin_isr(int irq, void *data, struct pt_regs *regs)
+{
+	AMAZON_TPE_DMSG("SWIE insertion done\n");
+	/* release the lock and check */
+	if (test_and_clear_bit(SWIE_LOCK,&(g_atm_dev.swie.lock)) == 0){
+		AMAZON_TPE_EMSG("swie lock is already released");
+	}
+	// Release semaphore
+	up(&g_atm_dev.swie.in_sem);
+
+}
+/*	Brief: 		Interrupt handler for software cell insertion & extraction
+ *	Parameters:	irq	- CPPN for this interrupt
+ *			data	- Device ID for this interrupt
+ *			regs	- Register file
+ *	Description:
+ *	When a software insertion or extractionis finished this interrupt is issued.
+ */
+void amazon_atm_swie_isr(int irq, void *data, struct pt_regs *regs)
+{
+	u32	status=0;
+	// Read status register
+	status = readl(SWIE_ISTAT_ADDR);
+	AMAZON_TPE_DMSG("insertion status: %8x\n", status);
+	if (status & SWIE_ISTAT_DONE){
+		//clear interrupt in peripheral and ICU
+		AMAZON_WRITE_REGISTER_L(SRC_TOS_MIPS | SRC_CLRR|SRC_SRE_ENABLE | AMAZON_SWIE_INT, SWIE_ISRC_ADDR);
+		mask_and_ack_amazon_irq(AMAZON_SWIE_INT);
+		
+		amazon_atm_swin_isr(irq,data,regs);
+	}
+	status = readl(SWIE_ESTAT_ADDR);
+	AMAZON_TPE_DMSG("extraction status: %8x\n", status);
+	if (status & SWIE_ESTAT_DONE){
+		//clear interrupt
+		AMAZON_WRITE_REGISTER_L(SRC_TOS_MIPS | SRC_CLRR|SRC_SRE_ENABLE | AMAZON_SWIE_INT, SWIE_ESRC_ADDR);
+		mask_and_ack_amazon_irq(AMAZON_SWIE_INT);
+		
+		amazon_atm_swex_isr(irq,data,regs);
+	}
+	//clear interrupt in ICU
+}
+ 
+/*
+ *	Brief: 		Insert ATM cell into CBM
+ *	Parameters:	queue	- Target queue
+ *			cell	- Pointer to cell data
+ *  	Return Value:	EBUSY		- CBM is busy
+ *			0		- OK, cell inserted
+ *	Description:
+ *	This function inserts a cell into the CBM using the software insertion
+ *	method. The format of the cell should be
+ *	Little Endian (address starting from 0)
+ *		H3, H2, H1, H0, P3, P2, P1, P0, P7, P6, P5, P4, ..., P47, P46, P45, P44
+ *	Big Endian (address starting from 0)
+ *		H0, H1, H2, H3, P0, P1, P2, P3, P4, P5, P6, P7, ..., P44, P45, P46, P47
+ *	This function does not free memory!!!
+ */
+int amazon_atm_swin(u8 queue, void* cell)
+{
+	u32	status=0;
+	int i;
+	// Read status register
+	status = readl(SWIE_ISTAT_ADDR);
+	AMAZON_TPE_DMSG(" SWIE status=0x%08x\n",status);
+
+	AMAZON_TPE_DMSG(" Inserting cell qid=%u\n",queue);
+	
+#ifdef AMAZON_CHECK_LINK
+	if (adsl_link_status == 0){
+		return -EFAULT;	
+	}
+#endif //AMAZON_CHECK_LINK
+
+	// Get semaphore (if possible)
+	if (down_interruptible(&g_atm_dev.swie.in_sem)) {
+		return -ERESTARTSYS;
+	}
+	/* try to set lock */
+	wait_event_interruptible(g_atm_dev.swie.sleep,(test_and_set_bit(SWIE_LOCK,&(g_atm_dev.swie.lock)) == 0));
+	if (signal_pending(current)){
+		return -ERESTARTSYS; 
+	}
+
+	// Store cell in CBM memory
+	for(i=0;i<ATM_AAL0_SDU;i+=4){
+		AMAZON_WRITE_REGISTER_L(((u32*)cell)[i/4],SWIE_ICELL_ADDR+i);
+	}
+	//Store queue id
+	AMAZON_WRITE_REGISTER_L((u32) queue,SWIE_IQID_ADDR);
+
+	//Start SWIE
+	AMAZON_WRITE_REGISTER_L(SWIE_ICMD_START,SWIE_ICMD_ADDR);
+	
+	return 0;
+}
+
+#ifdef AMAZON_ATM_DEBUG
+/*
+ *	Brief: 		Interrupt handler for HTU
+ *
+ *	Parameters:	irq	- CPPN for this interrupt
+ *			data	- Device ID for this interrupt
+ *			regs	- Register file
+ *
+ */
+void amazon_atm_htu_isr(int irq, void *data, struct pt_regs *regs)
+{
+	u32	irq_stat=0;
+
+	// Read interrupt status register
+	irq_stat = readl(HTU_ISR0_ADDR);
+	AMAZON_TPE_DMSG("HTU status: %8x\n",irq_stat);
+	//Clear interrupt in CBM and ICU
+	AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_HTU_INT, HTU_SRC0_ADDR);
+	mask_and_ack_amazon_irq(AMAZON_HTU_INT);	
+	// Check if Any Cell Arrived
+	if (irq_stat & (HTU_ISR_NE | HTU_ISR_PNE) ) {
+		AMAZON_TPE_EMSG("INFNOENTRY %8x\n", readl(HTU_INFNOENTRY_ADDR));		
+	}else if (irq_stat & (HTU_ISR_TORD|HTU_ISR_PT)){
+		AMAZON_TPE_EMSG("Time Out %8x\n", readl(HTU_INFTIMEOUT_ADDR));
+	}else if (irq_stat & HTU_ISR_IT){
+		AMAZON_TPE_EMSG("Interrupt Test\n");
+	}else if (irq_stat & HTU_ISR_OTOC){
+		AMAZON_TPE_EMSG("Overflow of Time Out Counter\n");
+	}else if (irq_stat & HTU_ISR_ONEC){
+		AMAZON_TPE_EMSG("Overflow of No Entry Counter\n");
+	}else{
+		AMAZON_TPE_EMSG("unknown HTU interrupt occurs %8x\n", irq_stat);
+	}
+
+}
+#endif //AMAZON_ATM_DEBUG
+
+#ifdef AMAZON_TPE_TEST_AAL5_INT
+/*
+ *	Brief: 		Interrupt handler for AAL5
+ *
+ *	Parameters:	irq	- CPPN for this interrupt
+ *			data	- Device ID for this interrupt
+ *			regs	- Register file
+ *
+ */
+void amazon_atm_aal5_isr(int irq, void *data, struct pt_regs *regs)
+{
+	volatile u32 irq_stat=0;
+
+	// Read interrupt status register
+	irq_stat = readl(AAL5_SISR0_ADDR);
+	if (irq_stat){
+		AMAZON_TPE_EMSG("A5S status: %8x\n",irq_stat);
+		//Clear interrupt in CBM and ICU
+		AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_AAL5_INT, AAL5_SSRC0_ADDR);
+		mask_and_ack_amazon_irq(AMAZON_AAL5_INT);	
+	}
+	irq_stat = readl(AAL5_RISR0_ADDR);
+	if (irq_stat){
+		AMAZON_TPE_EMSG("A5R status: %8x\n",irq_stat);
+		//Clear interrupt in CBM and ICU
+		AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_AAL5_INT, AAL5_RSRC0_ADDR);
+		mask_and_ack_amazon_irq(AMAZON_AAL5_INT);	
+	}
+}
+#endif //AMAZON_TPE_TEST_AAL5_INT
+
+/*
+ *	Brief: 		Interrupt handler for CBM
+ *
+ *	Parameters:	irq	- CPPN for this interrupt
+ *			data	- Device ID for this interrupt
+ *			regs	- Register file
+ *
+ *	Description:
+ *	This is the MIPS interrupt handler for the CBM. It processes incoming cells
+ *	for SWIE queues.
+ */
+void amazon_atm_cbm_isr(int irq, void *data, struct pt_regs *regs)
+{
+	u32	irq_stat=0;
+	u8 qid=0;
+
+	// Read interrupt status register
+	while ( (irq_stat = readl(CBM_INTINF0_ADDR))){
+		AMAZON_TPE_DMSG("CBM INT status: %8x\n",irq_stat);
+		//Clear interrupt in CBM and ICU
+		AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_CBM_INT, CBM_SRC0_ADDR);
+		qid = (u8) ((irq_stat & CBM_INTINF0_QID_MASK)>>CBM_INTINF0_QID_SHIFT);
+#ifdef AMAZON_TPE_SCR	
+		if (irq_stat & CBM_INTINF0_EF){
+			amazon_atm_a5r((void*)qid);
+		}
+#endif
+		// Check if Any Cell Arrived
+		if (irq_stat & CBM_INTINF0_ACA) {
+			amazon_atm_swex((void *)irq_stat);		
+		}
+		//TX AAL5 PDU discard
+		if (irq_stat & CBM_INTINF0_OPF){
+ 			if ( (qid) < CBM_RX_OFFSET ){
+ 				g_atm_dev.mib_counter.tx_drop++;
+			}
+			queue_statics(qid, QS_HW_DROP);
+		}
+		if (irq_stat & (CBM_INTINF0_ERR|CBM_INTINF0_Q0E|CBM_INTINF0_Q0I|CBM_INTINF0_RDE)){
+			AMAZON_TPE_EMSG("CBM INT status: %8x\n",irq_stat);
+			if (irq_stat & CBM_INTINF0_ERR){
+				AMAZON_TPE_EMSG("CBM Error: FPI Bus Error\n");
+			}
+			if (irq_stat & CBM_INTINF0_Q0E){
+				AMAZON_TPE_EMSG("CBM Error: Queue 0 Extract\n");
+			}
+			if (irq_stat & CBM_INTINF0_Q0I){
+				AMAZON_TPE_EMSG("CBM Error: Queue 0 Extract\n");
+			}
+			if (irq_stat & CBM_INTINF0_RDE){
+				AMAZON_TPE_EMSG("CBM Error: Read Empty Queue %u\n",qid);
+				dump_qd(qid);
+			}
+		}		
+	}
+	mask_and_ack_amazon_irq(AMAZON_CBM_INT);
+}
+
+/*	Brief:	check the status word after AAL SDU after reassembly
+ */
+static inline void check_aal5_error(u8 stw0, u8 stw1, int qid)
+{
+	if (stw0 & AAL5_STW0_MFL){
+		AMAZON_TPE_DMSG("Maximum Frame Length\n");
+		g_atm_dev.queues[qid].aal5VccOverSizedSDUs++;
+	} 
+	if (stw0 & AAL5_STW0_CRC){
+		AMAZON_TPE_DMSG("CRC\n");
+		g_atm_dev.queues[qid].aal5VccCrcErrors++;
+	}
+#ifdef AMAZON_ATM_DEBUG_RX
+	AMAZON_TPE_EMSG("qid:%u stw0:%8x stw1:%8x\n",qid,stw0,stw1);
+#endif
+}
+
+/* Brief: 	Process DMA rx data
+ * Parameters:
+ 	dma_dev:	pointer to the dma_device_info, provided by us when register the dma device
+ * Return: 	no
+ * Description: DMA interrupt handerl with OoS support. It is called when there is some data in rx direction.
+ *
+ */
+//507261:tc.chen void atm_process_dma_rx(struct dma_device_info* dma_dev)
+void __system atm_process_dma_rx(struct dma_device_info* dma_dev)
+{
+        u8 * head=NULL;
+        u32 length=0;
+        u8 stw0=0;
+        u8 stw1=0;
+
+	struct sk_buff * skb=NULL;
+	struct atm_vcc * vcc=NULL;
+	int qid=0;
+#ifdef AMAZON_ATM_DEBUG_RX
+	static int dma_rx_dump=0;
+	static u32 seq=0;
+	
+	seq++;
+	if (dma_rx_dump>0){
+		printk("\n=========================[%u]=========================\n",seq);
+	}
+#endif	
+	length=dma_device_read(dma_dev,&head,(void**)&skb);
+	AMAZON_TPE_DMSG("receive %8p[%u] from DMA\n", head,length);
+	if (head == NULL||length<=0) {
+		AMAZON_TPE_DMSG("dma_read null \n");
+		goto error_exit;
+	}
+
+	if (length > (g_atm_dev.aal5.rx_max_sdu+64)){
+		AMAZON_TPE_EMSG("received packet too large (%u)\n",length);
+		goto error_exit;
+	}
+	//check AAL5R trail for error and qid
+	//last byte is qid
+	length--;
+	qid = (int) head[length];
+	AMAZON_TPE_DMSG("head[%u] qid %u\n",length, qid);
+	//STW0 is always 4 bytes before qid
+	length -= 4;
+	stw0 = head[length]&0xff;
+	AMAZON_TPE_DMSG("head[%u] stw0 %8x\n",length, stw0);
+	//position of STW1 depends on the BE bits
+	length = length-4 + (stw0&AAL5_STW0_BE);
+	stw1 = head[length]&0xff;
+	AMAZON_TPE_DMSG("head[%u] stw1 %8x\n",length, stw1);	
+	if ( (stw0 & AAL5_STW0_MASK) || (stw1 & AAL5_STW1_MASK) ){
+		//AAL5 Error
+		check_aal5_error(stw0, stw1,qid);		
+		goto error_exit;
+	}
+	//make data pointers consistent
+	//UU + CPI
+	length -= 2;
+	AMAZON_TPE_DMSG("packet length %u\n", length);
+
+	//error: cannot restore the qid
+	if (valid_qid(qid) != 1){
+		AMAZON_TPE_EMSG("received frame in invalid qid %u!\n", qid);
+		goto error_exit;
+	}
+	vcc = g_atm_dev.queues[qid].vcc;
+	if (vcc == NULL){
+		AMAZON_TPE_EMSG("received frame in invalid vcc, qid=%u!\n",qid);
+		goto error_exit;
+	}
+	if (skb == NULL){
+		AMAZON_TPE_EMSG("cannot restore skb pointer!\n");
+		goto error_exit;
+	}
+	skb_put(skb,length);
+	skb->stamp = xtime;
+	g_atm_dev.queues[qid].access_time=xtime;
+	if ((*g_atm_dev.queues[qid].push)(vcc,skb,0)){
+		g_atm_dev.mib_counter.rx_drop++;
+		queue_statics(qid, QS_SW_DROP);					
+	}else{
+		g_atm_dev.mib_counter.rx++;
+		adsl_led_flash();//joelin adsl led
+		queue_statics(qid, QS_PKT);
+		AMAZON_TPE_DMSG("push successful!\n");
+	}
+#ifdef AMAZON_ATM_DEBUG_RX
+	if (dma_rx_dump>0){
+		printk("\nOK packet [dump=%u] length=%u\n",dma_rx_dump,length);
+		dump_skb(length+7, head);
+	}
+	if (dma_rx_dump >0) dma_rx_dump--;
+#endif	
+	return ;
+error_exit:
+#ifdef AMAZON_ATM_DEBUG_RX
+	if ( (head!=NULL) && (length >0)){
+		AMAZON_TPE_EMSG("length=%u\n",length);
+		dump_skb(length+5, head);
+	}	
+	dma_rx_dump++;
+#endif	
+	g_atm_dev.mib_counter.rx_err++;
+	queue_statics(qid, QS_ERR);
+	/*
+	if (vcc){
+		(*g_atm_dev.queues[qid].push)(vcc,skb,1);	
+	}
+	*/
+	if (skb != NULL) {
+		dev_kfree_skb_any(skb);
+	}
+	return;
+}
+
+/*Brief:	ISR for DMA pseudo interrupt
+ *Parameter:
+ 	dma_dev:	pointer to the dma_device_info, provided by us when register the dma device
+ 	intr_status:	
+ 		RCV_INT:		rx data available
+ 		TX_BUF_FULL_INT:	tx descriptor run out of
+ 		TRANSMIT_CPT_INT:	tx descriptor available again
+ *Return:
+ 	0 for success???
+ */
+//507261:tc.chen int amazon_atm_dma_handler(struct dma_device_info* dma_dev, int intr_status)
+int __system amazon_atm_dma_handler(struct dma_device_info* dma_dev, int intr_status)
+{
+	AMAZON_TPE_DMSG("status:%u\n",intr_status);
+	switch (intr_status) {
+		case RCV_INT:
+			atm_process_dma_rx(dma_dev);
+			break;
+		case TX_BUF_FULL_INT:
+			//TX full: no descriptors
+			atm_dma_full();
+			break;
+		case TRANSMIT_CPT_INT:
+			//TX free: at least one descriptor
+			atm_dma_free();
+			break;
+		default:
+			AMAZON_TPE_EMSG("unknown status!\n");
+	}
+	return 0;
+}
+
+/*Brief:	free buffer for DMA tx
+ *Parameter:
+ 	dataptr:	pointers to data buffer
+ 	opt:		optional parameter, used to convey struct skb pointer, passwd in dma_device_write
+ *Return:
+ 	0 for success???
+ *Description:
+ 	called by DMA module to release data buffer after DMA tx transaction
+ *Error:
+ 	cannot restore skb pointer
+ */
+int amazon_atm_free_tx(u8*dataptr, void* opt)
+{
+	struct sk_buff *skb;
+	if (opt){
+		AMAZON_TPE_DMSG("free skb%8p\n",opt);
+		skb = (struct sk_buff *)opt;
+		amazon_atm_free_tx_skb(skb);
+	}else{
+		AMAZON_TPE_EMSG("BUG: cannot restore skb pointer!\n");
+	}
+	return 0;
+}
+
+/*Brief:	allocate buffer & do alignment
+ */
+inline struct sk_buff * amazon_atm_alloc_buffer(int len)
+{
+	struct sk_buff *skb;
+	skb = dev_alloc_skb(len+16);
+	if (skb){
+		//alignment requriements (4x32 bits (16 bytes) boundary)
+		alloc_align_16(skb);
+	}
+	return skb;
+}
+
+/*Brief:	allocate buffer for DMA rx
+ *Parameter:
+ 	len: length
+ 	opt: optional data to convey the skb pointer, which will be returned to me in interrupt handler,
+ *Return:
+ 	pointer to buffer, NULL means error?
+ *Description:
+ 	must make sure byte alignment
+ */
+ 	
+u8* amazon_atm_alloc_rx(int len, int* offset, void **opt)
+{
+	struct sk_buff *skb;
+	*offset = 0;
+	skb = amazon_atm_alloc_buffer(len);
+	if (skb){
+		AMAZON_TPE_DMSG("alloc skb->data:%8p len:%u\n",skb->data,len);
+		*(struct sk_buff**)opt = skb;
+	}else{
+		AMAZON_TPE_DMSG("no memory for receiving atm frame!\n");
+		return NULL;
+	}
+	return skb->data;
+}
+
+
+
+
+/* Brief:	Allocate kernel memory for sending a datagram.
+ * Parameters
+ *	vcc	virtual connection
+ *	size	data buffer size
+ * Return:
+ *	NULL	fail
+ *	sk_buff	a pointer to a sk_buff
+ * Description:
+ *  This function can allocate our own additional memory for AAL5S inbound
+ * header (8bytes). We have to replace the protocol default one (alloc_tx in /net/atm/common.c) 
+ * when we open the device.
+ * byte alignment is done is DMA driver.
+ */
+struct sk_buff *amazon_atm_alloc_tx(struct atm_vcc *vcc,unsigned int size)
+{
+	struct sk_buff *skb;
+
+	if (!dma_may_send(DMA_TX_CH0)){
+		AMAZON_TPE_EMSG("no DMA descriptor available!\n");
+		return NULL;
+	}
+	//AAL5 inbound header space + alignment extra buffer
+	size+=8+AAL5S_INBOUND_HEADER;
+
+        if (atomic_read(&vcc->tx_inuse) && !atm_may_send(vcc,size)) {
+                AMAZON_TPE_EMSG("Sorry tx_inuse = %u, size = %u, sndbuf = %u\n",
+                    atomic_read(&vcc->tx_inuse),size,vcc->sk->sndbuf);
+                return NULL;
+        }
+
+        skb = amazon_atm_alloc_buffer(size);
+	if (skb == NULL){
+		AMAZON_TPE_EMSG("no memory\n");
+		return NULL;
+	}
+	AMAZON_TPE_DMSG("dev_alloc_skb(%u) = %x\n", skb->len, (u32)skb);
+        AMAZON_TPE_DMSG("tx_inuse %u += %u\n",atomic_read(&vcc->tx_inuse),skb->truesize);
+        atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
+
+	//reserve for AAL5 inbound header
+	skb_reserve(skb,AAL5S_INBOUND_HEADER);
+        return skb;
+}
+
+
+/* Brief:	change per queue QSB setting according to vcc qos parameters
+ * Paramters:
+ *	vcc:	atm_vcc pointer 
+ *	qid:	CBM queue id (1~15)
+ * Return:
+  */
+static inline void set_qsb(struct atm_vcc *vcc, struct atm_qos *qos, int qid)
+{
+	qsb_qptl_t	qptl;
+	qsb_qvpt_t	qvpt;
+	u32 tmp=0;
+	unsigned int qsb_clk;
+	
+	qsb_clk = amazon_get_fpi_hz()>>1;
+        
+	AMAZON_TPE_EMSG("Class=%u MAX_PCR=%u PCR=%u MIN_PCR=%u SCR=%u MBS=%u CDV=%u\n"
+		,qos->txtp.traffic_class
+		,qos->txtp.max_pcr
+		,qos->txtp.pcr
+		,qos->txtp.min_pcr
+		,qos->txtp.scr
+		,qos->txtp.mbs
+		,qos->txtp.cdv
+		);
+	
+	// PCR limiter
+	if (qos->txtp.max_pcr == 0){	
+		qptl.bit.tprs = 0;                  /* 0 disables the PCR limiter */
+	}else {
+		// peak cell rate will be slightly lower than requested	(maximum rate / pcr)= (qsbclock/2^3 * timestep/4)/pcr
+		tmp = (( (qsb_clk * g_atm_dev.qsb.tstepc)>>5)/ qos->txtp.max_pcr ) + 1;
+		// check if an overfow occured
+		if (tmp > QSB_TP_TS_MAX) {
+			AMAZON_TPE_EMSG("max_pcr is too small, max_pcr:%u tprs:%u\n",qos->txtp.max_pcr, tmp);
+		  	qptl.bit.tprs = QSB_TP_TS_MAX;
+		}else{
+			qptl.bit.tprs = tmp;
+		}
+	}
+	//WFQ
+	if (qos->txtp.traffic_class == ATM_CBR  || qos->txtp.traffic_class ==ATM_VBR_RT){
+		// real time queue gets weighted fair queueing bypass
+		qptl.bit.twfq  = 0;
+	}else if (qos->txtp.traffic_class ==ATM_VBR_NRT ||qos->txtp.traffic_class ==ATM_UBR_PLUS ){
+		// wfq calculation here are based on virtual cell rates, to reduce granularity for large rates
+		// wfq factor is maximum cell rate / garenteed cell rate.
+		//qptl.bit.twfq = g_atm_dev.qsb.min_cr * QSB_WFQ_NONUBR_MAX / qos->txtp.min_pcr;
+		if (qos->txtp.min_pcr == 0) {
+			AMAZON_TPE_EMSG("<warning> MIN_PCR should not be zero\n");
+			qptl.bit.twfq = QSB_WFQ_NONUBR_MAX;
+		}else{
+			tmp = QSB_GCR_MIN * QSB_WFQ_NONUBR_MAX / qos->txtp.min_pcr;		
+			if (tmp == 0 ){
+				qptl.bit.twfq = 1;
+			}else if (tmp > QSB_WFQ_NONUBR_MAX){
+				AMAZON_TPE_EMSG("min_pcr is too small, min_pcr:%u twfq:%u\n",qos->txtp.min_pcr, tmp);
+				qptl.bit.twfq = QSB_WFQ_NONUBR_MAX;
+			}else{
+				qptl.bit.twfq = tmp;	
+			}
+		}
+	}else if (qos->txtp.traffic_class == ATM_UBR){
+		// ubr bypass, twfq set to maximum value
+		qptl.bit.twfq = QSB_WFQ_UBR_BYPASS;
+	}else{
+		//tx is diabled, treated as UBR
+		AMAZON_TPE_EMSG("<warning> unsupported traffic class %u \n", qos->txtp.traffic_class);
+		qos->txtp.traffic_class = ATM_UBR;
+		qptl.bit.twfq = QSB_WFQ_UBR_BYPASS;
+	}
+	
+	//SCR Leaky Bucket Shaper VBR.0/VBR.1
+	if (qos->txtp.traffic_class ==ATM_VBR_RT || qos->txtp.traffic_class ==ATM_VBR_NRT){
+		if (qos->txtp.scr == 0){
+			//SCR == 0 disable the shaper
+			qvpt.bit.ts = 0;
+			qvpt.bit.taus = 0;
+		}else{
+			//CLP
+			if (vcc->atm_options&ATM_ATMOPT_CLP){
+				//CLP1
+				qptl.bit.vbr = 1;
+			}else{
+				//CLP0
+				qptl.bit.vbr = 0;
+			}
+			//TS and TauS
+			tmp = (( (qsb_clk * g_atm_dev.qsb.tstepc)>>5)/ qos->txtp.scr ) + 1;
+			if (tmp > QSB_TP_TS_MAX) {
+				AMAZON_TPE_EMSG("scr is too small, scr:%u ts:%u\n",qos->txtp.scr, tmp);
+				qvpt.bit.ts = QSB_TP_TS_MAX;
+			}else{
+				qvpt.bit.ts = tmp;
+			}
+			tmp = (qos->txtp.mbs - 1)*(qvpt.bit.ts - qptl.bit.tprs)/64;
+			if (tmp > QSB_TAUS_MAX){
+				AMAZON_TPE_EMSG("mbs is too large, mbr:%u taus:%u\n",qos->txtp.mbs, tmp);
+				qvpt.bit.taus = QSB_TAUS_MAX;
+			}else if (tmp == 0){
+				qvpt.bit.taus = 1;
+			}else{
+				qvpt.bit.taus = tmp;
+			}
+		}
+	}else{
+		qvpt.w0 = 0;
+	}
+	//write the QSB Queue Parameter Table (QPT)
+	AMAZON_WRITE_REGISTER_L(QSB_QPT_SET_MASK,QSB_RTM_ADDR);
+	AMAZON_WRITE_REGISTER_L(qptl.w0, QSB_RTD_ADDR);
+	AMAZON_WRITE_REGISTER_L((QSB_TABLESEL_QPT<<QSB_TABLESEL_SHIFT)
+		| QSB_RAMAC_REG_LOW
+		| QSB_WRITE
+		| qid
+		,QSB_RAMAC_ADDR);
+	//write the QSB Queue VBR Parameter Table (QVPT)
+	AMAZON_WRITE_REGISTER_L(QSB_QVPT_SET_MASK,QSB_RTM_ADDR);
+	AMAZON_WRITE_REGISTER_L(qvpt.w0, QSB_RTD_ADDR);
+	AMAZON_WRITE_REGISTER_L((QSB_TABLESEL_QVPT<<QSB_TABLESEL_SHIFT)
+		| QSB_RAMAC_REG_LOW
+		| QSB_WRITE
+		| qid
+		,QSB_RAMAC_ADDR);	
+	AMAZON_TPE_EMSG("tprs:%u twfq:%u ts:%u taus:%u\n",qptl.bit.tprs,qptl.bit.twfq,qvpt.bit.ts,qvpt.bit.taus);
+}
+
+/* 
+ * Brief:	create/change CBM queue descriptor
+ * Parameter:	
+ *	vcc:	atm_vcc pointer 
+ *	qid:	CBM queue id (1~15)
+ */
+static inline void set_qd(struct atm_vcc *vcc, u32 qid)
+{
+	u32 tx_config=0,rx_config=0;
+	u32 itf = (u32) vcc->itf;
+	u32 dma_qos=0;
+	u8 * qd_addr=NULL;
+		
+	tx_config|=CBM_QD_W3_WM_EN|CBM_QD_W3_CLPt;
+	//RT: check if the connection is a real time connection
+	if (vcc->qos.txtp.traffic_class == ATM_CBR || vcc->qos.txtp.traffic_class == ATM_VBR_RT){
+		tx_config|= CBM_QD_W3_RT;
+	}else{
+		tx_config|= CBM_QD_W3_AAL5; //don't set the AAL5 flag if it is a RT service
+	}
+	rx_config = tx_config;
+	
+	if(vcc->qos.aal == ATM_AAL5){	
+		//QoS: DMA QoS according to the traffic class
+		switch (vcc->qos.txtp.traffic_class){
+			case ATM_CBR: dma_qos = CBR_DMA_QOS;break;
+			case ATM_VBR_RT: dma_qos = VBR_RT_DMA_QOS;break;
+			case ATM_VBR_NRT: dma_qos = VBR_NRT_DMA_QOS;break;
+			case ATM_UBR_PLUS: dma_qos = UBR_PLUS_DMA_QOS;break;
+			case ATM_UBR: dma_qos = UBR_DMA_QOS;break;
+		}
+	
+		//TX: upstream, AAL5(EPD or PPD), NOINT, SBid
+		tx_config |= CBM_QD_W3_DIR_UP|CBM_QD_W3_INT_NOINT|(itf&CBM_QD_W3_SBID_MASK);
+		//RX: DMA QoS, downstream, no interrupt, AAL5(EPD, PPD), NO INT, HCR
+#ifdef AMAZON_TPE_SCR
+		rx_config |= dma_qos|CBM_QD_W3_DIR_DOWN|CBM_QD_W3_INT_EOF;
+#else		
+		rx_config |= dma_qos|CBM_QD_W3_DIR_DOWN|CBM_QD_W3_INT_NOINT|CBM_QD_W3_HCR;
+#endif		
+	}else {
+		//should be AAL0	
+		//upstream, NOINT, SBid
+		tx_config |= CBM_QD_W3_DIR_UP|CBM_QD_W3_INT_NOINT|(itf&CBM_QD_W3_SBID_MASK);
+		//RX: downstream, ACA interrupt, 
+		rx_config |= CBM_QD_W3_DIR_DOWN|CBM_QD_W3_INT_ACA;
+	}
+
+	//Threshold: maximum threshold for tx/rx queue, which is adjustable in steps of 64 cells
+	tx_config |=	( (divide_by_64_round_up(tx_q_threshold)&0xffff)<<CBM_QD_W3_THRESHOLD_SHIFT) & CBM_QD_W3_THRESHOLD_MASK;
+	rx_config |=	( (divide_by_64_round_up(rx_q_threshold)&0xffff)<<CBM_QD_W3_THRESHOLD_SHIFT) & CBM_QD_W3_THRESHOLD_MASK;
+	
+	qd_addr = (u8*) KSEG1ADDR((unsigned long)g_atm_dev.cbm.qd_addr);
+	//TX
+	AMAZON_WRITE_REGISTER_L(tx_config, (qd_addr+qid*CBM_QD_SIZE + 0xc));
+	AMAZON_WRITE_REGISTER_L(0, (qd_addr+qid*CBM_QD_SIZE + 0x8));
+	//RX
+	AMAZON_WRITE_REGISTER_L(rx_config, (qd_addr+(qid+CBM_RX_OFFSET)*CBM_QD_SIZE + 0xc));
+	AMAZON_WRITE_REGISTER_L(0, (qd_addr+(qid+CBM_RX_OFFSET)*CBM_QD_SIZE + 0x8));
+}
+/*
+ * Brief:	add HTU table entry
+ * Parameter:	
+ *	vpi.vci:
+ *	qid:	CBM queue id (DEST is qid + CBM_RX_OFFSET)
+ *	idx:	entry id (starting from zero to 14)
+ * Return:
+ *	0:	sucessful
+ *	EIO:	HTU table entry cannot be written
+ */
+
+inline int set_htu_entry(u8 vpi, u16 vci, u8 qid, u8 idx)
+{
+	int i = 0;
+	u32 tmp1=0;
+	while ((tmp1 = readl(HTU_RAMSTAT_ADDR))!=0 && i < 1024) i++;
+	if (i > 1024)
+	{
+		AMAZON_TPE_EMSG("timeout\n");
+		return -EIO;
+	}
+	// write address register,
+	AMAZON_WRITE_REGISTER_L(idx, HTU_RAMADDR_ADDR);
+	// configure transmit queue
+	tmp1 = vpi<<24|vci<<8;
+	tmp1|= 	HTU_RAMDAT1_VCON	// valid connection the entry is not validated here !!!!!!!!!!!!!!!!
+		|HTU_RAMDAT1_VCI3	// vci3 -> oam queue
+		|HTU_RAMDAT1_VCI4	// vci4 -> oam queue
+		|HTU_RAMDAT1_VCI6	// vci6 -> rm queue
+		|HTU_RAMDAT1_PTI4	// pti4 -> oam queue
+		|HTU_RAMDAT1_PTI5;	// pti5 -> oam queue
+
+	// ramdat 1 (in params & oam handling)
+	AMAZON_WRITE_REGISTER_L( tmp1, HTU_RAMDAT1_ADDR);
+	// ramdat 2 (out params & oam handling)
+	tmp1 = ((qid+CBM_RX_OFFSET)&HTU_RAMDAT2_QID_MASK)
+		|HTU_RAMDAT2_PTI6
+		|HTU_RAMDAT2_PTI7
+		|HTU_RAMDAT2_F4U
+		|HTU_RAMDAT2_F5U
+		;
+	AMAZON_WRITE_REGISTER_L( tmp1, HTU_RAMDAT2_ADDR);
+	wmb();
+	// write HTU entry
+	AMAZON_WRITE_REGISTER_L(HTU_RAMCMD_WR, HTU_RAMCMD_ADDR);
+	return 0;
+}
+/*
+ * Brief:	add HTU table entry
+ * Parameter:	
+ *	vcc:	atm_vcc pointer
+ *	qid:	CBM queue id
+ * Return:
+ *	0:	sucessful
+ *	EIO:	HTU table entry cannot be written
+ */
+inline static int set_htu(struct atm_vcc *vcc, u32 qid)
+{
+	return set_htu_entry(vcc->vpi, vcc->vci, qid, (qid - CBM_DEFAULT_Q_OFFSET));
+}
+
+/* 
+ * Brief:	allocate a queue
+ * Return:	
+ *		<=0	no available queues
+ *		>0	qid
+ */
+static int atm_allocate_q(short itf)
+{
+	int i;
+	u32 tmp1=0;
+	int qid=0;
+	amazon_atm_port_t * dev;
+	dev = &g_atm_dev.ports[itf];
+	//find start queue id for this interface
+	for (i=0; i< itf; i++)
+	{
+		qid+= g_atm_dev.ports[i].max_conn;
+	}
+	// apply default queue offset ( oam, free cell queue, others, rm )
+	qid += CBM_DEFAULT_Q_OFFSET;
+	tmp1 = qid;
+	// search for a free queue
+	while (	(qid<tmp1+dev->max_conn)
+		&& ( g_atm_dev.queues[qid].free != 1)) {
+		qid++;;
+	}
+	// if none was found, send failure message and return
+	if ( tmp1+dev->max_conn == qid)
+	{
+		return -EFAULT;
+	}
+	return qid;
+	
+}
+/* Brief:	open a aal5 or aal0 connection
+ */
+static int atm_open(struct atm_vcc *vcc, push_back_t push)
+{
+	int err=0;
+	int qid=0;
+	amazon_atm_port_t * port = & g_atm_dev.ports[vcc->itf];
+	unsigned long flags;
+	/***************** check bandwidth ******************/
+	/* 511045:linmars change ATM_VBR_NRT to use scr instead of pcr */
+	if ((vcc->qos.txtp.traffic_class==ATM_CBR&&vcc->qos.txtp.max_pcr>port->tx_rem_cr)
+	||(vcc->qos.txtp.traffic_class==ATM_VBR_RT&&vcc->qos.txtp.max_pcr>port->tx_rem_cr)
+	||(vcc->qos.txtp.traffic_class==ATM_VBR_NRT&&vcc->qos.txtp.scr>port->tx_rem_cr) 
+	||(vcc->qos.txtp.traffic_class==ATM_UBR_PLUS&&vcc->qos.txtp.min_pcr>port->tx_rem_cr)
+	) {
+                AMAZON_TPE_EMSG("not enough bandwidth left (%u) cells per seconds \n",port->tx_rem_cr);
+                return -EINVAL;
+	}
+	if ( (qid = amazon_atm_find_vpivci(vcc->vpi, vcc->vci)) >0 ){
+		AMAZON_TPE_EMSG("vpi:%u vci:%u is alreay open on queue:%u\n", vcc->vpi, vcc->vci, qid);
+		return -EADDRINUSE;
+	}
+
+	/***************** allocate entry queueID for this port *****************/
+	if ( (qid=atm_allocate_q(vcc->itf)) <= 0){
+		AMAZON_TPE_EMSG("port: %u max:%u qid: %u\n", vcc->itf, port->max_conn, qid);
+		AMAZON_TPE_EMSG("no availabel connections for this port:%u\n",vcc->itf);
+		return -EINVAL;
+	}
+	/**************QSB parameters and CBM descriptors*************/
+	set_qsb(vcc, &vcc->qos, qid);
+	set_qd(vcc, qid);
+	mb();
+	err=set_htu(vcc,qid);
+	if (err){
+		AMAZON_TPE_EMSG("set htu entry fails %u\n",err);
+		return err;
+	}
+	/************set internal mapping*************/
+	local_irq_save(flags);
+	g_atm_dev.queues[qid].free = 0;
+	g_atm_dev.queues[qid].vcc = vcc;
+	g_atm_dev.queues[qid].push = push;
+	g_atm_dev.queues[qid+CBM_RX_OFFSET].free = 0;
+	g_atm_dev.queues[qid+CBM_RX_OFFSET].vcc = vcc;
+	g_atm_dev.queues[qid+CBM_RX_OFFSET].push = push;
+	/******************reserve bandwidth**********************/
+	if (vcc->qos.txtp.traffic_class == ATM_CBR){
+		//CBR, real time connection, reserve PCR
+		port->tx_cur_cr += vcc->qos.txtp.max_pcr;
+		port->tx_rem_cr -= vcc->qos.txtp.max_pcr;
+	}else if (vcc->qos.txtp.traffic_class == ATM_VBR_RT){
+		//VBR_RT, real time connection, reserve PCR
+		port->tx_cur_cr += vcc->qos.txtp.max_pcr;
+		port->tx_rem_cr -= vcc->qos.txtp.max_pcr;
+	}else if (vcc->qos.txtp.traffic_class == ATM_VBR_NRT){
+		//VBR_NRT, reserve SCR
+		port->tx_cur_cr += vcc->qos.txtp.pcr;
+		port->tx_rem_cr -= vcc->qos.txtp.pcr;
+	}else if (vcc->qos.txtp.traffic_class == ATM_UBR_PLUS){
+		//UBR_PLUS, reserve MCR
+		port->tx_cur_cr += vcc->qos.txtp.min_pcr;
+		port->tx_rem_cr -= vcc->qos.txtp.min_pcr;
+	}
+	local_irq_restore(flags);
+	return err;
+}
+/* Brief: 	Open ATM connection
+ * Parameters: 	atm_vcc	- Pointer to VCC data structure
+ *		vpi	- VPI value for new connection
+ *		vci	- VCI value for new connection
+ *
+ * Return: 	0 	- sucessful
+ * 		-ENOMEM	- No memory available
+ *		-EINVAL	- No bandwidth/queue/ or unsupported AAL type
+ * Description:
+ *	This function opens an ATM connection on a specific device/interface
+ *
+ */
+int	amazon_atm_open(struct atm_vcc *vcc,push_back_t push)
+{
+	int err=0;
+
+	AMAZON_TPE_DMSG("vpi %u vci %u  itf %u aal %u\n"
+		,vcc->vpi
+		,vcc->vci
+		,vcc->itf
+		,vcc->qos.aal
+		);
+		
+	AMAZON_TPE_DMSG("tx cl %u bw %u mtu %u\n"
+		,vcc->qos.txtp.traffic_class
+		,vcc->qos.txtp.max_pcr
+		,vcc->qos.txtp.max_sdu
+		);
+	AMAZON_TPE_DMSG("rx cl %u bw %u mtu %u\n"
+		,vcc->qos.rxtp.traffic_class
+		,vcc->qos.rxtp.max_pcr
+		,vcc->qos.rxtp.max_sdu
+		);
+	if (vcc->qos.aal == ATM_AAL5 || vcc->qos.aal == ATM_AAL0){
+		err = atm_open(vcc,push);
+	}else{
+		AMAZON_TPE_EMSG("unsupported aal type %u\n", vcc->qos.aal);
+		err = -EPROTONOSUPPORT;
+	};
+	if (err == 0 ){
+		//replace the default memory allocation function with our own
+		vcc->alloc_tx = amazon_atm_alloc_tx;
+		set_bit(ATM_VF_READY,&vcc->flags);
+	}
+	return err;
+}
+
+/* Brief: 	Send ATM OAM cell
+ * Parameters: 	atm_vcc	- Pointer to VCC data structure
+ *		skb	- Pointer to sk_buff structure, that contains the data
+ * Return: 	0 		- sucessful
+ * 		-ENOMEM		- No memory available
+ *		-EINVAL		- Not supported
+ * Description:
+ * This function sends a cell over and ATM connection
+ * We always release the skb
+ * TODO: flags handling (ATM_OF_IMMED, ATM_OF_INRATE)
+ */
+int	amazon_atm_send_oam(struct atm_vcc *vcc, void * cell, int flags)
+{
+	int err=0;
+	int qid=0;
+	struct amazon_atm_cell_header * cell_header;
+	// Get cell header
+	cell_header = (struct amazon_atm_cell_header*) cell;
+	if ((cell_header->bit.pti == ATM_PTI_SEGF5) || (cell_header->bit.pti == ATM_PTI_E2EF5)) {
+		qid = amazon_atm_find_vpivci( cell_header->bit.vpi, cell_header->bit.vci);
+	}else if (cell_header->bit.vci == 0x3 || cell_header->bit.vci == 0x4) {
+		//507281:tc.chen qid = amazon_atm_find_vpi((int) cell_header->bit.vpi);
+		// 507281:tc.chen start
+		u8 f4_vpi;
+		f4_vpi = cell_header->bit.vpi;
+		qid = amazon_atm_find_vpi(f4_vpi );
+		// 507281:tc.chen end
+	}else{
+		//non-OAM cells, always invalid
+		qid = -EINVAL;
+	}
+	if (qid == -EINVAL) {
+		err =  -EINVAL;
+		AMAZON_TPE_EMSG("not valid AAL0 packet\n");
+	}else{
+		//send the cell using swie
+#ifdef TPE_LOOPBACK
+		err = amazon_atm_swin(AMAZON_ATM_OAM_Q_ID, cell);
+#else		
+		err = amazon_atm_swin(qid, cell);
+#endif
+	}
+	//kfree(cell);
+	return err;
+}
+
+/* Brief: 	Send AAL5 frame through DMA
+ * Parameters: 	vpi	- virtual path id 
+ *		vci	- virtual circuit id
+ *		clp	- cell loss priority
+ *		qid	- CBM queue to be sent to
+ *		skb	- packet to be sent
+ * Return: 	0 		- sucessful
+ * 		-ENOMEM		- No memory available
+ *		-EINVAL		- Not supported
+ * Description:
+ * This function sends a AAL5 frame over and ATM connection
+ * 	1. make sure that the data is aligned to 4x32-bit boundary
+ *	2. provide the inbound data (CPCS-UU and CPI, not used here)
+ *	3. set CLPn
+ *	4. send the frame by DMA
+ *	5. release the buffer ???
+ ** use our own allocation alloc_tx
+ ** we make sure the alignment and additional memory
+ *** we always release the skb
+
+ */
+int amazon_atm_dma_tx(u8 vpi, u16 vci, u8 clp, u8 qid, struct sk_buff *skb) 
+{
+     	int err=0,need_pop=1;
+	u32 * data=NULL;
+	int nwrite=0;
+	struct sk_buff *skb_tmp;
+	u32 len=skb->len;	
+
+	//AAL5S inbound header 8 bytes
+	if (skb->len > g_atm_dev.aal5.tx_max_sdu - AAL5S_INBOUND_HEADER) {
+		AMAZON_TPE_DMSG("tx_max_sdu:%u\n",g_atm_dev.aal5.tx_max_sdu); 
+		AMAZON_TPE_DMSG("skb too large [%u]!\n",skb->len);
+		err = -EMSGSIZE;
+		goto atm_dma_tx_error_exit;
+	}
+	
+	//Check the byte alignment requirement and header space
+	if ( ( ((u32)(skb->data)%16) !=AAL5S_INBOUND_HEADER)|| (skb_headroom(skb)<AAL5S_INBOUND_HEADER)){
+		//not aligned or no space for header, fall back to memcpy
+		skb_tmp = dev_alloc_skb(skb->len+16);
+		if (skb_tmp==NULL){
+			err = - ENOMEM;			
+			goto atm_dma_tx_error_exit;	
+		}
+		alloc_align_16(skb_tmp);
+		g_atm_dev.aal5.cnt_cpy++;
+		skb_reserve(skb_tmp,AAL5S_INBOUND_HEADER);
+		memcpy(skb_put(skb_tmp,skb->len), skb->data, skb->len);
+		amazon_atm_free_tx_skb(skb);
+		need_pop=0;
+		skb = skb_tmp;
+	}
+	//Provide AAL5S inbound header
+	data = (u32 *)skb_push(skb,8);
+	data[0] = __be32_to_cpu(vpi<<20|vci<<4|clp);
+	data[1] = __be32_to_cpu(g_atm_dev.aal5.padding_byte<<8|qid);
+	
+	len = skb->len;
+
+	//send through DMA
+	AMAZON_TPE_DMSG("AAL5S header 0 %8x\n", data[0]);
+	AMAZON_TPE_DMSG("AAL5S header 0 %8x\n", data[1]);
+	AMAZON_TPE_DMSG("about to call dma_write len: %u\n", len);
+	nwrite=dma_device_write( &g_dma_dev,skb->data,len,skb);
+	if (nwrite != len) {
+		//DMA descriptors full
+//		AMAZON_TPE_EMSG("AAL5 packet drop due to DMA nwrite:%u skb->len:%u\n", nwrite,len);
+		AMAZON_TPE_DMSG("AAL5 packet drop due to DMA nwrite:%u skb->len:%u\n", nwrite,len);
+		err = -EAGAIN;
+		goto atm_dma_tx_drop_exit;
+	}
+	AMAZON_TPE_DMSG("just finish call dma_write\n");
+	//release in the "dma done" call-back
+	return 0;
+atm_dma_tx_error_exit:
+	g_atm_dev.mib_counter.tx_err++;	
+	queue_statics(qid, QS_ERR);
+	goto atm_dma_tx_exit;
+	
+atm_dma_tx_drop_exit:
+	g_atm_dev.mib_counter.tx_drop++;
+	queue_statics(qid, QS_SW_DROP);
+atm_dma_tx_exit:
+	if (need_pop){
+		amazon_atm_free_tx_skb(skb);
+	}else{
+		dev_kfree_skb_any(skb);
+	}
+	return err;
+}
+
+/* Brief: 	Send AAL0/AAL5 packet
+ * Parameters: 	atm_vcc	- Pointer to VCC data structure
+ *		skb	- Pointer to sk_buff structure, that contains the data
+ * Return: 	0 		- sucessful
+ * 		-ENOMEM		- No memory available
+ *		-EINVAL		- Not supported
+ * Description:
+ *	See amazon_atm_dma_tx
+ */
+int	amazon_atm_send(struct atm_vcc *vcc,struct sk_buff *skb)
+{
+	int qid=0;
+	u8 clp=0;
+        int err=0;
+	u32 wm=0;
+
+	if (vcc == NULL || skb == NULL){
+		AMAZON_TPE_EMSG("invalid parameter\n");
+		return -EINVAL;
+	}
+	ATM_SKB(skb)->vcc = vcc;
+	qid = amazon_atm_get_queue(vcc);
+	if (valid_qid(qid) != 1) {
+		AMAZON_TPE_EMSG("invalid vcc!\n");
+		err = -EINVAL;
+		goto atm_send_err_exit;
+	}
+	
+	//Send AAL0 using SWIN
+	if (vcc->qos.aal == ATM_AAL0){
+#ifdef  TPE_LOOPBACK
+		err=amazon_atm_swin((qid+CBM_RX_OFFSET), skb->data);	
+#else
+		err=amazon_atm_swin(qid, skb->data);
+#endif
+		if (err){
+			goto atm_send_err_exit;
+		}	
+		goto atm_send_exit;
+	}
+	
+	//Should be AAl5
+	//MIB counter
+	g_atm_dev.mib_counter.tx++;
+	adsl_led_flash();//joelin adsl led
+	queue_statics(qid, QS_PKT);
+
+#ifdef AMAZON_CHECK_LINK
+	//check adsl link 
+	if (adsl_link_status == 0){
+		//link down
+		AMAZON_TPE_DMSG("ADSL link down, discarded!\n");
+		err=-EFAULT;
+		goto atm_send_drop_exit;
+	}
+#endif
+	clp = (vcc->atm_options&ATM_ATMOPT_CLP)?1:0;
+	//check watermark first
+	wm = readl(CBM_WMSTAT0_ADDR);
+	if (  (wm & (1<<qid))
+	    ||( (vcc->qos.txtp.traffic_class != ATM_CBR
+	         &&vcc->qos.txtp.traffic_class != ATM_VBR_RT) 
+		&(wm & (CBM_WM_NRT_MASK | (clp&CBM_WM_CLP1_MASK)) ))){
+		//wm hit: discard
+		AMAZON_TPE_DMSG("watermark hit, discarded!\n");
+		err=-EFAULT;
+		goto atm_send_drop_exit;
+	}
+#ifdef  TPE_LOOPBACK
+	return amazon_atm_dma_tx(vcc->vpi, vcc->vci,clp, (qid+CBM_RX_OFFSET),skb);
+#else	
+	return amazon_atm_dma_tx(vcc->vpi, vcc->vci,clp, qid,skb);
+#endif
+
+atm_send_exit:	
+	amazon_atm_free_tx_skb_vcc(vcc,skb);	
+	return 0;
+	
+atm_send_drop_exit:
+	g_atm_dev.mib_counter.tx_drop++;
+	queue_statics(qid,QS_SW_DROP);
+atm_send_err_exit:	
+	amazon_atm_free_tx_skb_vcc(vcc,skb);
+	return err;
+}
+
+/* Brief:	Return ATM port related MIB
+ * Parameter:	interface number
+ 	 atm_cell_ifEntry_t
+ */
+int amazon_atm_cell_mib(atm_cell_ifEntry_t* to,u32 itf)
+{
+	g_atm_dev.mib_counter.htu_unp += readl(HTU_MIBCIUP);
+	to->ifInUnknownProtos = g_atm_dev.mib_counter.htu_unp;
+#ifdef AMAZON_TPE_READ_ARC
+	u32 reg_val=0;
+	meiDebugRead((AR_CELL0_ADDR+itf*4),&reg_val,1);
+	g_atm_dev.mib_counter.rx_cells += reg_val;
+	reg_val=0;
+	meiDebugWrite((AR_CELL0_ADDR+itf*4),&reg_val,1);
+	to->ifHCInOctets_h = (g_atm_dev.mib_counter.rx_cells * 53)>>32;
+	to->ifHCInOctets_l = (g_atm_dev.mib_counter.rx_cells * 53) & 0xffff;
+	
+	meiDebugRead((AT_CELL0_ADDR+itf*4),&reg_val,1);
+	g_atm_dev.mib_counter.tx_cells += reg_val;
+	reg_val=0;
+	meiDebugWrite((AT_CELL0_ADDR+itf*4),&reg_val,1);
+	to->ifHCOutOctets_h = (g_atm_dev.mib_counter.tx_cells * 53)>>32;
+	to->ifHCOutOctets_l = (g_atm_dev.mib_counter.rx_cells * 53) & 0xffff;
+	
+	meiDebugRead((AR_CD_CNT0_ADDR+itf*4),&reg_val,1);
+	g_atm_dev.mib_counter.rx_err_cells += reg_val;
+	reg_val=0;
+	meiDebugWrite((AR_CD_CNT0_ADDR+itf*4),&reg_val,1);
+	to->ifInErrors = g_atm_dev.mib_counter.rx_err_cells;
+	
+	to->ifOutErrors = 0;
+#else
+	to->ifHCInOctets_h = 0;
+	to->ifHCInOctets_l = 0;
+	to->ifHCOutOctets_h = 0;
+	to->ifHCOutOctets_l = 0;
+	to->ifInErrors = 0;
+	to->ifOutErrors = 0;
+#endif
+	return 0;
+}
+
+/* Brief:	Return ATM AAL5 related MIB
+ * Parameter:
+ 	 atm_aal5_ifEntry_t
+ */
+int amazon_atm_aal5_mib(atm_aal5_ifEntry_t* to)
+{
+	u32 reg_l,reg_h;
+	//AAL5R	received Octets from ATM
+	reg_l = readl(AAL5_RIOL_ADDR);
+	reg_h = readl(AAL5_RIOM_ADDR);
+	g_atm_dev.mib_counter.rx_cnt_h +=reg_h;
+	if (reg_l + g_atm_dev.mib_counter.rx_cnt_l < reg_l){
+		g_atm_dev.mib_counter.rx_cnt_h++;
+	}
+	
+	g_atm_dev.mib_counter.rx_cnt_l+= reg_l;
+	//AAL5S	sent Octets to ATM
+	reg_l = readl(AAL5_SOOL_ADDR);
+	reg_h = readl(AAL5_SOOM_ADDR);
+	g_atm_dev.mib_counter.tx_cnt_h +=reg_h;
+	if (reg_l + g_atm_dev.mib_counter.tx_cnt_l < reg_l){
+		g_atm_dev.mib_counter.tx_cnt_h++;
+	}
+	g_atm_dev.mib_counter.tx_cnt_l+= reg_l;
+
+
+	g_atm_dev.mib_counter.tx_ppd += readl(CBM_AAL5ODIS_ADDR);
+	g_atm_dev.mib_counter.rx_drop += readl(CBM_AAL5IDIS_ADDR);
+	
+	//store 
+	to->ifHCInOctets_h = g_atm_dev.mib_counter.rx_cnt_h;
+	to->ifHCInOctets_l = g_atm_dev.mib_counter.rx_cnt_l;
+	to->ifHCOutOctets_h = g_atm_dev.mib_counter.tx_cnt_h;
+	to->ifHCOutOctets_l = g_atm_dev.mib_counter.tx_cnt_l;
+	to->ifOutDiscards = g_atm_dev.mib_counter.tx_drop;
+	to->ifInDiscards = g_atm_dev.mib_counter.rx_drop;
+
+	//Software provided counters
+	//packets passed to higher layer
+	to->ifInUcastPkts = g_atm_dev.mib_counter.rx;
+	//packets passed from higher layer
+	to->ifOutUcastPkts = g_atm_dev.mib_counter.tx;
+	//number of wrong downstream packets
+	to->ifInErrors = g_atm_dev.mib_counter.rx_err;
+	//number of wrong upstream packets
+	to->ifOutErros = g_atm_dev.mib_counter.tx_err;
+
+	return 0;
+}
+/* Brief:	Return ATM AAL5 VCC related MIB from internale use
+ * Parameter:
+ *	qid
+ *	atm_aal5_vcc_t
+ */
+static int __amazon_atm_vcc_mib(int qid, atm_aal5_vcc_t* to)
+{
+	//aal5VccCrcErrors
+	to->aal5VccCrcErrors = g_atm_dev.queues[qid].aal5VccCrcErrors;
+	to->aal5VccOverSizedSDUs =g_atm_dev.queues[qid].aal5VccOverSizedSDUs;
+	to->aal5VccSarTimeOuts = 0; //not supported yet
+	return 0;
+}
+/* Brief:	Return ATM AAL5 VCC related MIB from vpi/vci
+ * Parameter:	atm_vcc
+ * 	 atm_aal5_vcc_t
+ */
+int amazon_atm_vcc_mib_x(int vpi, int vci,atm_aal5_vcc_t* to)
+{
+	int qid=0;
+	int err=0;
+	qid =  amazon_atm_find_vpivci(vpi, vci);
+	if (qid >0 ){
+		err = __amazon_atm_vcc_mib(qid,to);
+	}else{
+		return -EINVAL;
+	}
+	return err;
+}
+
+
+/* Brief:	Return ATM AAL5 VCC related MIB
+ * Parameter:	atm_vcc
+ *	 atm_aal5_vcc_t
+ */
+int amazon_atm_vcc_mib(struct atm_vcc *vcc,atm_aal5_vcc_t* to)
+{
+	int qid=0;
+	int err=0;
+	qid =  amazon_atm_get_queue(vcc);
+	if (qid >0 ){
+		err = __amazon_atm_vcc_mib(qid,to);
+	}else{
+		return -EINVAL;
+	}
+	return err;
+}
+
+/* Brief: 	Close ATM connection
+ * Parameters: 	atm_vcc	- Pointer to VCC data structure
+ * Return: 	no
+ * Description:
+ * This function closes the given ATM connection
+ */
+void	amazon_atm_close(struct atm_vcc *vcc){
+	int i;
+	int qid=0;
+	u32 tmp1;
+	u8 * qd_addr;
+	unsigned long flags;
+	if (vcc == NULL){
+		AMAZON_TPE_EMSG("invalid parameter. vcc is null\n");
+		return;
+	}
+	u32 itf = (u32) vcc->itf;
+	//release bandwidth
+	if (vcc->qos.txtp.traffic_class == ATM_CBR){
+		g_atm_dev.ports[itf].tx_rem_cr += vcc->qos.txtp.max_pcr;
+		g_atm_dev.ports[itf].tx_cur_cr -= vcc->qos.txtp.max_pcr;
+	}else if (vcc->qos.txtp.traffic_class == ATM_VBR_RT){
+		g_atm_dev.ports[itf].tx_rem_cr += vcc->qos.txtp.max_pcr;
+		g_atm_dev.ports[itf].tx_cur_cr -= vcc->qos.txtp.max_pcr;
+	}else if (vcc->qos.txtp.traffic_class == ATM_VBR_NRT){
+		g_atm_dev.ports[itf].tx_rem_cr += vcc->qos.txtp.pcr;
+		g_atm_dev.ports[itf].tx_cur_cr -= vcc->qos.txtp.pcr;
+	}else if (vcc->qos.txtp.traffic_class == ATM_UBR_PLUS){
+		g_atm_dev.ports[itf].tx_rem_cr += vcc->qos.txtp.min_pcr;
+		g_atm_dev.ports[itf].tx_cur_cr -= vcc->qos.txtp.min_pcr;
+	}
+
+	qid = amazon_atm_get_queue(vcc);
+	if (qid == -EINVAL){
+		AMAZON_TPE_EMSG("unknown vcc %u.%u.%u\n", vcc->itf, vcc->vpi, vcc->vci);
+		return;
+	}
+	local_irq_save(flags);
+	//Disable HTU entry
+	i=0;
+	while ((tmp1 = readl(HTU_RAMSTAT_ADDR))!=0 && i < HTU_RAM_ACCESS_MAX) i++;
+ 	if (i == HTU_RAM_ACCESS_MAX){
+		AMAZON_TPE_EMSG("HTU RAM ACCESS out of time\n");
+	}
+
+	// write address register
+	AMAZON_WRITE_REGISTER_L(qid - CBM_DEFAULT_Q_OFFSET, HTU_RAMADDR_ADDR);
+	// invalidate the connection
+	AMAZON_WRITE_REGISTER_L(0, HTU_RAMDAT1_ADDR);
+	// write command
+	AMAZON_WRITE_REGISTER_L(HTU_RAMCMD_WR,HTU_RAMCMD_ADDR);
+	
+	qd_addr = (u8 *) KSEG1ADDR((unsigned long)g_atm_dev.cbm.qd_addr);
+#ifdef AMAZON_ATM_DEBUG
+	tmp1 = readl(qd_addr+qid*CBM_QD_SIZE+0x8) & 0xffff;
+	AMAZON_TPE_DMSG("TX queue has %u cells \n", tmp1);
+	tmp1 = readl( qd_addr+(qid+CBM_RX_OFFSET)*CBM_QD_SIZE+0x08)&0xffff;
+	AMAZON_TPE_DMSG("RX queue has %u cells \n", tmp1);
+#endif	
+	// set threshold of txqueue to 0
+	tmp1 = readl(qd_addr+qid*CBM_QD_SIZE+0x0c);
+	tmp1&= (~ CBM_QD_W3_THRESHOLD_MASK);
+	AMAZON_WRITE_REGISTER_L(tmp1, (qd_addr+qid*CBM_QD_SIZE+0x0c));
+	// set threshold of rxqueue to 0
+	tmp1 = readl( qd_addr+(qid+CBM_RX_OFFSET)*CBM_QD_SIZE+0x0c);
+	tmp1&= (~ CBM_QD_W3_THRESHOLD_MASK);
+	AMAZON_WRITE_REGISTER_L(tmp1,(qd_addr+(qid+CBM_RX_OFFSET)*CBM_QD_SIZE+0x0c));
+
+	//clear internal mapping
+	amazon_atm_clear_vcc(qid);
+	amazon_atm_clear_vcc(qid+CBM_RX_OFFSET);
+
+	local_irq_restore(flags);
+}
+
+
+/* Brief:	initialize internal data structure
+ */
+static void atm_constructor(amazon_atm_dev_t * dev)
+{
+	int i;
+	memset(dev,0,sizeof(amazon_atm_dev_t));
+	atm_init_parameters(dev);
+	//internal: queue "free" flag
+	for(i=1;i<AMAZON_ATM_MAX_QUEUE_NUM;i++) {
+		//dev->queues[i].vcc=NULL;
+		dev->queues[i].free = 1;
+	}
+	for(i=0;i<AMAZON_ATM_PORT_NUM;i++){
+		dev->ports[i].tx_rem_cr = dev->ports[i].tx_max_cr;
+	}
+	//MIB
+	atomic_set(&dev->dma_tx_free_0,1); //initially there should be free descriptors
+}
+
+/* Brief:	return round up base-2 logarithm
+ */
+static inline int get_log_2(u32 value)
+{
+	int i=0,j=1;
+	while (i<11){
+		if (j>=value) break;
+		j=j<<1;
+		i++;
+	}
+	AMAZON_TPE_DMSG("round up base-2 logarithm of %u is %u\n", value, i);
+	return i;
+}
+
+/* Brief:	TPE hardware initialization
+ * Parameter:	specifiy the configurations of the hardware
+ */
+static inline int atm_init_hard(amazon_atm_dev_t * dev)
+{
+	int i;
+	u32 tmp1, tmp2, tmp3;
+	u8 * mem_addr=NULL;
+	u8 * qd_addr=NULL;
+	//PMU power on the module 1st
+	*(AMAZON_PMU_PWDCR) = 	(*AMAZON_PMU_PWDCR) | (AMAZON_PMU_PWDCR_TPE);
+	//Reset the module
+	*(AMAZON_RST_REQ) = (* AMAZON_RST_REQ) | (AMAZON_RST_REQ_TPE);
+	mb();
+	mdelay(100);
+	*(AMAZON_RST_REQ) = (* AMAZON_RST_REQ) & (~(AMAZON_RST_REQ_TPE));
+	mb();
+	
+	unsigned long qsb_clk = amazon_get_fpi_hz()>>1;
+	/*********allocate & arrange memory for CBM *********/
+	if (dev->cbm.mem_addr == NULL){
+		dev->cbm.allocated = 1;
+		mem_addr = (u8 *)__get_free_pages(GFP_KERNEL, get_log_2(((CBM_CELL_SIZE * dev->cbm.free_cell_cnt) >>PAGE_SHIFT) + 1));
+		if (mem_addr != NULL){ 
+			dev->cbm.mem_addr = mem_addr;
+		} else	{
+			goto init_no_mem;
+		}
+	}
+	if (dev->cbm.qd_addr == NULL){
+#ifdef CONFIG_USE_VENUS
+		//to work around a bug, bit15 of QDOFF address should be 1,Aug4, 2004
+		//thus, we allocate 64k memory		
+		qd_addr = (u8 *)__get_free_pages(GFP_KERNEL, 4);
+		if (qd_addr != NULL) {
+			dev->cbm.qd_addr_free = (u8*) (((unsigned long) qd_addr));
+			dev->cbm.qd_addr = (u8*) (((unsigned long) qd_addr) | 0x8000);
+		}else{
+			goto init_no_mem;
+		}
+#else	//CONFIG_USE_VENUS
+		qd_addr = (u8 *)kmalloc( CBM_QD_SIZE * AMAZON_ATM_MAX_QUEUE_NUM, GFP_KERNEL);
+		if (qd_addr != NULL) {
+			dev->cbm.qd_addr = qd_addr;
+		}else {
+			goto init_no_mem;
+		}
+#endif //CONFIG_USE_VENUS			
+	}
+//#ifndef CONFIG_MIPS_UNCACHED
+	mem_addr = (u8 *)KSEG1ADDR((unsigned long)dev->cbm.mem_addr);
+	qd_addr = (u8 *)KSEG1ADDR((unsigned long)dev->cbm.qd_addr);
+//#endif
+	//CBM reset cell queue memory, 64 bytes / cell
+	memset_io(mem_addr, 0, CBM_CELL_SIZE * dev->cbm.free_cell_cnt);
+	//make a link list, last 4 bytes is pointer
+	for(i=1;i<dev->cbm.free_cell_cnt;i++){
+		AMAZON_WRITE_REGISTER_L(CPHYSADDR((mem_addr + CBM_CELL_SIZE * i)),(mem_addr + CBM_CELL_SIZE * (i-1) + 0x3c));
+	}
+	//reset queue descriptor
+	memset_io(qd_addr, 0, CBM_QD_SIZE * AMAZON_ATM_MAX_QUEUE_NUM);
+	//init word 0-2 of q0 (free cell list)
+	//address of last cell
+	AMAZON_WRITE_REGISTER_L(CPHYSADDR((mem_addr + CBM_CELL_SIZE * (dev->cbm.free_cell_cnt-1))), qd_addr);
+	//address of first cell
+	AMAZON_WRITE_REGISTER_L(CPHYSADDR((mem_addr)), (qd_addr + 4));
+	//no. of free cells
+	AMAZON_WRITE_REGISTER_L(dev->cbm.free_cell_cnt,(qd_addr + 8));
+	//init q descriptor for OAM receiving
+	AMAZON_WRITE_REGISTER_L((CBM_QD_W3_INT_ACA | (divide_by_64_round_up(oam_q_threshold)&0xff)<< CBM_QD_W3_THRESHOLD_SHIFT), (qd_addr + AMAZON_ATM_OAM_Q_ID * CBM_QD_SIZE + 0x0c));
+//	AMAZON_WRITE_REGISTER_L((CBM_QD_W3_INT_ACA | (u32)oam_q_threshold<< CBM_QD_W3_THRESHOLD_SHIFT), (qd_addr + AMAZON_ATM_OAM_Q_ID * CBM_QD_SIZE + 0x0c));
+	//config CBM
+	//set offset address and threshold
+	AMAZON_WRITE_REGISTER_L(CPHYSADDR(qd_addr), CBM_QDOFF_ADDR);
+	AMAZON_WRITE_REGISTER_L(((dev->cbm.nrt_thr&CBM_THR_MASK)|CBM_WM_3_1), CBM_NRTTHR_ADDR);
+	AMAZON_WRITE_REGISTER_L(((dev->cbm.clp0_thr&CBM_THR_MASK)|CBM_WM_3_1), CBM_CLP0THR_ADDR);
+	AMAZON_WRITE_REGISTER_L(((dev->cbm.clp1_thr&CBM_THR_MASK)|CBM_WM_3_1), CBM_CLP1THR_ADDR);
+	//config interrupts
+	AMAZON_WRITE_REGISTER_L( CBM_IMR_MASK & (~(CBM_IMR_ACA|CBM_IMR_Q0E|CBM_IMR_Q0I|CBM_IMR_RDE|CBM_IMR_OPF|CBM_IMR_ERR             	
+#ifdef AMAZON_ATM_DEBUG	
+						|CBM_IMR_DISC|CBM_IMR_QFD|CBM_IMR_NFCA|CBM_IMR_CLP1TR|CBM_IMR_CLP0TR|CBM_IMR_NRTTR|CBM_IMR_QTR
+#endif	
+#ifdef AMAZON_TPE_SCR
+						|CBM_IMR_EF 
+#endif
+							)), CBM_IMR0_ADDR);
+	AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_CBM_INT, CBM_SRC0_ADDR);
+	
+	//HTU
+	//RAM entry for number of possible connections per interface
+	tmp1 = dev->ports[0].max_conn?dev->ports[0].max_conn-1:0;
+	AMAZON_WRITE_REGISTER_L(tmp1, HTU_RX0_ADDR);
+	for(i=1;i<AMAZON_ATM_PORT_NUM;i++){
+		tmp1+=dev->ports[i].max_conn;
+		AMAZON_WRITE_REGISTER_L(tmp1, HTU_RX0_ADDR + 4 * i);
+	}
+	dev->cbm.max_q_off = tmp1+1;
+	//Queue ID for OAM/RM/Other cells
+	AMAZON_WRITE_REGISTER_L (AMAZON_ATM_OAM_Q_ID, HTU_DESTOAM_ADDR);
+	AMAZON_WRITE_REGISTER_L( AMAZON_ATM_RM_Q_ID, HTU_DESTRM_ADDR);
+	AMAZON_WRITE_REGISTER_L( AMAZON_ATM_OTHER_Q_ID, HTU_DESTOTHER_ADDR);
+	//Timeout
+	AMAZON_WRITE_REGISTER_L((u32) HTUTIMEOUT, HTU_TIMEOUT_ADDR);
+#ifdef AMAZON_ATM_DEBUG
+        AMAZON_WRITE_REGISTER_L((u32) HTU_ISR_MASK 
+				&(~(HTU_ISR_NE|HTU_ISR_TORD|HTU_ISR_OTOC|HTU_ISR_ONEC|HTU_ISR_PNE|HTU_ISR_PT)), HTU_IMR0_ADDR);
+	AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS|SRC_SRE_ENABLE|AMAZON_HTU_INT,HTU_SRC0_ADDR);
+#endif
+	//QSB
+	//global setting, TstepC, SBL, Tau
+	//Tau
+	AMAZON_WRITE_REGISTER_L(dev->qsb.tau, QSB_TAU_ADDR);
+	//SBL
+	AMAZON_WRITE_REGISTER_L(dev->qsb.sbl, QSB_SBL_ADDR);
+	//tstep
+	AMAZON_WRITE_REGISTER_L(dev->qsb.tstepc>>1, QSB_CONFIG_ADDR);
+
+	//port settting
+	for(i=0;i<AMAZON_ATM_PORT_NUM;i++){
+		if ( (dev->ports[i].enable) && (dev->ports[i].tx_max_cr!=0) ){
+			tmp1 = ((qsb_clk * dev->qsb.tstepc) >>1) / dev->ports[i].tx_max_cr;
+			tmp2 = tmp1 / 64;	//integer value of Tsb
+			tmp3 = tmp1%64 + 1; 	//fractional part of Tsb
+			//carry over to integer part (?)
+			if (tmp3 == 64) {
+				tmp3 = 0;
+				tmp2++;
+			}
+			if (tmp2 == 0){
+				tmp2 = 1;
+				tmp3 = 1;
+			}
+			//1. set mask 2. write value to data transfer register 3. start the transfer
+			//SCT(FracRate)
+			AMAZON_WRITE_REGISTER_L(QSB_SET_SCT_MASK, QSB_RTM_ADDR);
+			AMAZON_WRITE_REGISTER_L(tmp3,QSB_RTD_ADDR);
+			AMAZON_WRITE_REGISTER_L(((QSB_TABLESEL_SCT<<QSB_TABLESEL_SHIFT)|QSB_RAMAC_REG_LOW|QSB_WRITE|i),QSB_RAMAC_ADDR);
+			//SPT(SBV + PN + IntRage)
+			AMAZON_WRITE_REGISTER_L(QSB_SET_SPT_MASK, QSB_RTM_ADDR);
+			AMAZON_WRITE_REGISTER_L(QSB_SPT_SBVALID|tmp2|(i<<16),QSB_RTD_ADDR);
+			AMAZON_WRITE_REGISTER_L(((QSB_TABLESEL_SPT<<QSB_TABLESEL_SHIFT)|QSB_RAMAC_REG_LOW|QSB_WRITE|i),QSB_RAMAC_ADDR);
+
+
+		}
+	}
+	
+	//SWIE: Setup Service Request Control Registers to enable interrupts
+	AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_SWIE_INT, SWIE_ISRC_ADDR);
+	AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_SWIE_INT, SWIE_ESRC_ADDR);
+
+	wmb();
+#ifdef AMAZON_TPE_TEST_AAL5_INT
+	AMAZON_WRITE_REGISTER_L(AAL5R_ISR_FE,AAL5_RIMR0_ADDR);
+	AMAZON_WRITE_REGISTER_L(0, AAL5_SIMR0_ADDR);
+	AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_AAL5_INT,AAL5_SSRC0_ADDR);
+	AMAZON_WRITE_REGISTER_L(SRC_CLRR|SRC_TOS_MIPS | SRC_SRE_ENABLE | AMAZON_AAL5_INT,AAL5_RSRC0_ADDR);
+#endif //AMAZON_TPE_TEST_AAL5_INT
+
+	AMAZON_WRITE_REGISTER_L(dev->aal5.tx_max_sdu,AAL5_SMFL_ADDR);	
+ 	AMAZON_WRITE_REGISTER_L(dev->aal5.rx_max_sdu,AAL5_RMFL_ADDR);
+	AMAZON_WRITE_REGISTER_L(AAL5_SCMD_MODE_POLL // enable polling mode
+ 					|AAL5_SCMD_SS
+ 					|AAL5_SCMD_AR
+					,AAL5_SCMD_ADDR);
+	//start CBM
+ 	AMAZON_WRITE_REGISTER_L(CBM_CFG_START,CBM_CFG_ADDR);
+ 	wmb();
+	return 0;
+init_no_mem:
+	if (mem_addr != NULL) free_pages((unsigned long)mem_addr,get_log_2(((CBM_CELL_SIZE * dev->cbm.free_cell_cnt) >>PAGE_SHIFT) + 1));
+	
+#ifdef CONFIG_USE_VENUS	
+	//to work around a bug, bit15 of QDOFF address should be 1
+	if (qd_addr != NULL) free_pages((unsigned long)qd_addr,4);
+#else //CONFIG_USE_VENUS
+	if (qd_addr != NULL) kfree(qd_addr);	
+#endif //CONFIG_USE_VENUS	
+	return -ENOMEM;
+}
+
+/*	
+ *	Brief:	Create entry in /proc for status information
+ */
+void atm_create_proc(void)
+{
+	create_proc_read_entry("amazon_atm", 0,NULL, amazon_atm_read_procmem,(void*)PROC_ATM);
+        create_proc_read_entry("amazon_atm_mib", 0,NULL, amazon_atm_read_procmem,(void*)PROC_MIB);
+        create_proc_read_entry("amazon_atm_vcc", 0,NULL, amazon_atm_read_procmem,(void*)PROC_VCC);
+#if 0	
+	create_proc_read_entry("amazon_atm_aal5", 0,NULL, amazon_atm_read_procmem,(void*)PROC_AAL5);
+        create_proc_read_entry("amazon_atm_cbm", 0,NULL, amazon_atm_read_procmem,(void*)PROC_CBM);
+        create_proc_read_entry("amazon_atm_htu", 0,NULL, amazon_atm_read_procmem,(void*)PROC_HTU);
+        create_proc_read_entry("amazon_atm_qsb", 0,NULL, amazon_atm_read_procmem,(void*)PROC_QSB);
+        create_proc_read_entry("amazon_atm_swie", 0,NULL, amazon_atm_read_procmem,(void*)PROC_SWIE);
+#endif
+}
+
+/*
+ *	Brief:	Delete entry in /proc for status information
+ */
+void atm_delete_proc(void)
+{
+	remove_proc_entry("amazon_atm", NULL);
+        remove_proc_entry("amazon_atm_mib", NULL);
+        remove_proc_entry("amazon_atm_vcc", NULL);
+#if 0	
+	remove_proc_entry("amazon_atm_aal5", NULL);
+        remove_proc_entry("amazon_atm_cbm", NULL);
+        remove_proc_entry("amazon_atm_htu", NULL);
+        remove_proc_entry("amazon_atm_qsb", NULL);
+        remove_proc_entry("amazon_atm_swie", NULL);
+#endif	
+}
+/* Brief: 	Initialize ATM module
+ * Parameters: 	no
+ * Return: 	&g_atm_dev - sucessful
+ *		NULL	- fails: 
+ *			1. invalid parameter
+ * 			2. No memory available
+ * Description:
+ *  This function configure the TPE components according to the input info,
+ *	-CBM
+ *	-HTU
+ *	-QSB
+ *	-AAL5
+ *
+ */
+amazon_atm_dev_t * amazon_atm_create(void)
+{
+	int i;
+	AMAZON_TPE_DMSG("atm_init\n");
+	/************initialize global data structure****************/
+	atm_constructor(&g_atm_dev);
+	/***********allocate kernel resources****************/
+	//bottom halfs for SWEX
+	swex_start_task.routine = amazon_atm_swex;
+	swex_start_task.data = NULL;
+	swex_complete_task.routine = amazon_atm_swex_push;
+	swex_complete_task.data = NULL;
+#ifdef AMAZON_TPE_SCR
+	a5r_task.routine = amazon_atm_a5r;
+	a5r_task.data = NULL;
+#endif	//AMAZON_TPE_SCR
+	//SWIN semaphore
+	sema_init(&(g_atm_dev.swie.in_sem), 1);
+	//SWIE lock
+	clear_bit(SWIE_LOCK, &(g_atm_dev.swie.lock));
+	//SWIE wait queue
+	init_waitqueue_head(&(g_atm_dev.swie.sleep));
+	atm_create_proc();
+		
+	//register DMA
+	memset(&g_dma_dev,0,sizeof(struct dma_device_info));
+	strcpy(g_dma_dev.device_name,"TPE");
+	g_dma_dev.weight=1; 
+	g_dma_dev.num_tx_chan=2;
+     	g_dma_dev.num_rx_chan=2; 
+     	g_dma_dev.ack=1;
+     	g_dma_dev.tx_burst_len=4;
+     	g_dma_dev.rx_burst_len=4;
+     	//DMA TX
+
+	for(i=0;i<1;i++){
+		g_dma_dev.tx_chan[i].weight=QOS_DEFAULT_WGT;
+       		g_dma_dev.tx_chan[i].desc_num=10;
+       		g_dma_dev.tx_chan[i].packet_size=g_atm_dev.aal5.tx_max_sdu + AAL5S_INBOUND_HEADER;
+       		g_dma_dev.tx_chan[i].control=1;
+     	}
+	//DMA RX
+     	for(i=0;i<2;i++){
+       		g_dma_dev.rx_chan[i].weight=QOS_DEFAULT_WGT;
+		/* BingTao's suggestion, change from 5->10 will prevent packet loss in NO_TX_INT mode */
+		g_dma_dev.rx_chan[i].desc_num=10;
+		g_dma_dev.rx_chan[i].packet_size=(g_atm_dev.aal5.rx_max_sdu + AAL5R_TRAILER_LEN+0x10f)&(~0xf);
+		g_dma_dev.rx_chan[i].control=1;
+     	}
+	g_dma_dev.intr_handler=amazon_atm_dma_handler;
+    	g_dma_dev.buffer_alloc=amazon_atm_alloc_rx;
+     	g_dma_dev.buffer_free=amazon_atm_free_tx;
+     	dma_device_register(&g_dma_dev);
+/***********intialize the atm hardware ****************/
+	if ( atm_init_hard(&g_atm_dev) != 0){
+		return NULL;
+	}
+	//start CBM
+	AMAZON_WRITE_REGISTER_L(CBM_CFG_START,CBM_CFG_ADDR);
+	wmb();
+
+	//Start HTU
+	AMAZON_WRITE_REGISTER_L(HTU_CFG_START ,HTU_CFG_ADDR);
+	wmb();
+
+
+	// Register interrupts for insertion and extraction
+	request_irq(AMAZON_SWIE_INT, amazon_atm_swie_isr, SA_INTERRUPT, "tpe_swie", NULL);
+	request_irq(AMAZON_CBM_INT, amazon_atm_cbm_isr, SA_INTERRUPT, "tpe_cbm", NULL);
+#ifdef AMAZON_ATM_DEBUG
+	request_irq(AMAZON_HTU_INT , amazon_atm_htu_isr, SA_INTERRUPT, "tpe_htu", NULL);
+#endif
+#ifdef AMAZON_TPE_TEST_AAL5_INT	
+	request_irq(AMAZON_AAL5_INT, amazon_atm_aal5_isr, SA_INTERRUPT, "tpe_aal5", NULL);
+#endif
+	return &g_atm_dev;
+}
+
+/* Brief: 	clean up atm
+ * Parameters: 	no
+ * Return: 	no
+ * Description:
+ *  Disable the device.
+ */
+void	amazon_atm_cleanup(void){
+	int i;
+	clear_bit(SWIE_LOCK, &(g_atm_dev.swie.lock));
+	wake_up(&g_atm_dev.swie.sleep);
+	up(&g_atm_dev.swie.in_sem);
+	// diable SWIE interrupts
+	AMAZON_WRITE_REGISTER_L(0, SWIE_ISRC_ADDR);
+	AMAZON_WRITE_REGISTER_L(0, SWIE_ESRC_ADDR);
+	wmb();
+
+	// Disable schedulers ( including interrupts )-----------------------
+	for (i = 0; i < AMAZON_ATM_PORT_NUM; i++);
+	{
+		AMAZON_WRITE_REGISTER_L(QSB_SET_SPT_SBVALID_MASK, QSB_RTM_ADDR);
+		AMAZON_WRITE_REGISTER_L( 0 ,QSB_RTD_ADDR);
+		AMAZON_WRITE_REGISTER_L( (QSB_TABLESEL_SPT<<QSB_TABLESEL_SHIFT)
+						| QSB_RAMAC_REG_LOW
+						| QSB_WRITE
+						| i,
+						QSB_RAMAC_ADDR);
+	}
+	// disable QSB_Interrupts
+	AMAZON_WRITE_REGISTER_L( 0, QSB_IMR_ADDR);
+	AMAZON_WRITE_REGISTER_L( 0, QSB_SRC_ADDR);
+	// disable CBM interrupts
+	AMAZON_WRITE_REGISTER_L( 0	, CBM_IMR0_ADDR);
+	AMAZON_WRITE_REGISTER_L( 0 , CBM_SRC0_ADDR);
+	// set CBM start bit to 0
+	AMAZON_WRITE_REGISTER_L(0,CBM_CFG_ADDR);
+	// request hardware extraction of queue 0, wich should force the CBM
+	// to recognize that the start bit is not set
+	AMAZON_WRITE_REGISTER_L(CBM_HWEXPAR_PN_A5, CBM_HWEXPAR0_ADDR);
+	// write frame extraction command into the hw extract command register
+	AMAZON_WRITE_REGISTER_L(CBM_HWEXCMD_FE0, CBM_HWEXCMD_ADDR);
+	// disable htu
+ 	// disable all HTU interrupts
+	AMAZON_WRITE_REGISTER_L(0  ,HTU_IMR0_ADDR);
+	AMAZON_WRITE_REGISTER_L(0  ,HTU_SRC0_ADDR);
+	
+	if (g_atm_dev.cbm.allocated){
+		free_pages((unsigned long)g_atm_dev.cbm.mem_addr, get_log_2(((CBM_CELL_SIZE * g_atm_dev.cbm.free_cell_cnt) >>PAGE_SHIFT)+1));
+#ifdef CONFIG_USE_VENUS
+		//to work around a bug, bit15 of QDOFF address should be 1
+		free_pages((unsigned long)g_atm_dev.cbm.qd_addr_free,4);
+#else //CONFIG_USE_VENUS
+		kfree(g_atm_dev.cbm.qd_addr);
+#endif //CONFIG_USE_VENUS						
+	}
+	atm_delete_proc();
+	// free interrupts for insertion and extraction
+	dma_device_unregister(&g_dma_dev);
+	free_irq(AMAZON_SWIE_INT, NULL);
+	free_irq(AMAZON_CBM_INT, NULL);
+#ifdef AMAZON_ATM_DEBUG
+	free_irq(AMAZON_HTU_INT, NULL);
+#endif
+#ifdef AMAZON_TPE_TEST_AAL5_INT
+	free_irq(AMAZON_AAL5_INT, NULL);
+#endif
+
+}
+
+/************************ ATM network interface ***********************************************/
+/*	Brief:		getsockopt
+ */
+int amazon_atm_getsockopt(struct atm_vcc *vcc, int level, int optname, char *optval, int optlen)
+{
+	int err=0;
+	atm_aal5_vcc_t mib_vcc;
+	AMAZON_TPE_DMSG("1\n");
+	switch (optname){
+		case	SO_AMAZON_ATM_MIB_VCC:
+			AMAZON_TPE_DMSG("2\n");
+			err = amazon_atm_vcc_mib(vcc, &mib_vcc);
+			AMAZON_TPE_DMSG("%u\n",mib_vcc.aal5VccCrcErrors);
+                        err = copy_to_user((void *)optval,&mib_vcc, sizeof(mib_vcc));
+                        AMAZON_TPE_DMSG("err %u\n",err);
+                        break;
+                default:
+                	return -EFAULT;
+	}
+	return err;
+}
+
+/*	Brief:		IOCTL
+ */
+
+int amazon_atm_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
+{
+	int     err=0;
+	//MIB
+	atm_cell_ifEntry_t mib_cell;
+	atm_aal5_ifEntry_t mib_aal5;
+	atm_aal5_vcc_x_t mib_vcc;
+	if (_IOC_TYPE(cmd) != AMAZON_ATM_IOC_MAGIC) return -ENOTTY;
+	if (_IOC_NR(cmd) > AMAZON_ATM_IOC_MAXNR) return -ENOTTY;
+
+	if (_IOC_DIR(cmd) & _IOC_READ)
+		err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
+	else if (_IOC_DIR(cmd) & _IOC_WRITE)
+		err =  !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
+	if (err) {
+		AMAZON_TPE_EMSG("acess verification fails \n");
+		return -EFAULT;
+	}
+	switch(cmd) {
+		case AMAZON_ATM_MIB_CELL:
+			err = amazon_atm_cell_mib(&mib_cell,(u32)arg);
+			if (err==0){
+				err = __copy_to_user((void *)arg,&mib_cell,sizeof(mib_cell));
+			}else{
+				AMAZON_TPE_EMSG("cannot get MIB ATM_CELL\n");
+			}
+			break;
+		case AMAZON_ATM_MIB_AAL5:
+			err = amazon_atm_aal5_mib(&mib_aal5);
+			if (err==0){
+				err=__copy_to_user(arg, &mib_aal5, sizeof(mib_aal5));
+			}else{
+				AMAZON_TPE_EMSG("cannot get MIB ATM_AAL5\n");
+			}
+			break;
+		case AMAZON_ATM_MIB_VCC:
+			err=__copy_from_user(&mib_vcc,arg, sizeof(mib_vcc));
+			AMAZON_TPE_DMSG("return of copy_from_user %x\n",err);
+			err = amazon_atm_vcc_mib_x(mib_vcc.vpi, mib_vcc.vci, &(mib_vcc.mib_vcc));
+			if (err==0){
+				err=__copy_to_user(arg, &mib_vcc, sizeof(mib_vcc));	
+			}else{
+				AMAZON_TPE_EMSG("cannot get MIB ATM_VCC\n");
+			}
+				
+    		default:
+    			return -ENOTTY;
+	}
+	return err;
+}
+/*	Brief:	return a link list of OAM related time stamp info
+ *	Parameter:	none
+ *	Return:	
+ 		a link list of "struct oam_last_activity" data
+ *	Description:
+ 		Each time, a F4/F5 cell or AAL5 packet is received, the time stamp is updated.
+		Through this call, u get a list of this time stamp for all active connection.
+		Please note that u have read-only access.
+ */
+const struct oam_last_activity* get_oam_time_stamp()
+{
+	int i,j;
+	for(i=CBM_DEFAULT_Q_OFFSET+CBM_RX_OFFSET,j=0;i<CBM_RX_OFFSET+CBM_DEFAULT_Q_OFFSET+AMAZON_ATM_MAX_VCC_NUM;i++){
+		if (g_atm_dev.queues[i].free != 1 && g_atm_dev.queues[i].vcc != NULL){
+			//active connection
+			if (j !=0 ){
+				g_oam_time_stamp[j-1].next = &g_oam_time_stamp[j];
+			}
+			g_oam_time_stamp[j].vpi = g_atm_dev.queues[i].vcc->vpi;
+			g_oam_time_stamp[j].vci = g_atm_dev.queues[i].vcc->vci;
+			g_oam_time_stamp[j].stamp = g_atm_dev.queues[i].access_time;
+			g_oam_time_stamp[j].next = NULL;
+			j++;
+		}
+	}
+	if (j==0) {
+		return NULL;
+	}else{
+		return g_oam_time_stamp;
+	}
+}
+
+
+/*	Brief:	call back routine for rx
+ *	Parameter:
+ *		vcc atm_vcc pointer
+ *		skb	data if no error
+ 		err	error flag, 0: no error, 1:error
+ *	Return:	
+ *		0	
+ *		<>0	cannot push up
+ *	Description:
+ *		release the packet if cannot push up
+ */
+static	int amazon_atm_net_push(struct atm_vcc *vcc,struct sk_buff *skb, int err)
+{
+	if (err){
+		if (vcc && vcc->stats) {
+			atomic_inc(&vcc->stats->rx_err);
+		}
+	}else{	
+		ATM_SKB(skb)->vcc = vcc;
+	
+		if (!atm_charge(vcc, skb->truesize)){
+			//no space this vcc
+			AMAZON_TPE_EMSG("no space for this vcc\n");
+			dev_kfree_skb_any(skb);
+			return -ENOMEM;
+		}
+		atomic_inc(&vcc->stats->rx);
+		AMAZON_TPE_DMSG("push to vcc\n");
+		vcc->push(vcc,skb);
+	}
+	return 0;
+}
+int	amazon_atm_net_send_oam(struct atm_vcc*vcc, void *cell, int flags)
+{
+	return amazon_atm_send_oam(vcc,cell,flags);
+}
+
+int	amazon_atm_net_send(struct atm_vcc *vcc,struct sk_buff *skb)
+{
+	int err=0;
+	if (vcc->qos.aal == ATM_AAL0 || vcc->qos.aal == ATM_AAL5) {
+		err=amazon_atm_send(vcc,skb);
+	}else{
+		//not supported
+		err =  -EPROTONOSUPPORT;
+	}
+	if (err){
+		atomic_inc(&vcc->stats->tx_err);
+	}else{
+		atomic_inc(&vcc->stats->tx);
+	}
+	AMAZON_TPE_DMSG("sent, tx_inuse:%u\n", atomic_read(&vcc->tx_inuse));
+	return err;
+}
+
+int	amazon_atm_net_open(struct atm_vcc *vcc,short vpi, int vci)
+{
+	vcc->itf = (int)  vcc->dev->dev_data;
+	vcc->vpi = vpi;
+	vcc->vci = vci;
+	return(amazon_atm_open(vcc,amazon_atm_net_push));
+}
+
+static int amazon_atm_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flgs)
+{
+	int qid;
+	
+	if (vcc == NULL || qos == NULL){
+		AMAZON_TPE_EMSG("invalid parameters\n");
+		return -EINVAL;
+	}
+	qid = amazon_atm_get_queue(vcc);
+	if (valid_qid(qid) != 1) {
+		AMAZON_TPE_EMSG("no vcc connection opened\n");
+		return -EINVAL;
+	}
+	set_qsb(vcc,qos,qid);
+	return 0;
+}
+
+static struct atmdev_ops amazon_atm_ops = {
+   open:	amazon_atm_net_open,
+   close:	amazon_atm_close,
+   ioctl:	amazon_atm_ioctl,
+   send:	amazon_atm_net_send,
+   send_oam:	amazon_atm_net_send_oam,
+//   getsockopt:	amazon_atm_getsockopt,
+   change_qos:	amazon_atm_change_qos,
+//   proc_read:	amazon_atm_proc_read,
+   owner:	THIS_MODULE,
+};				// ATM device callback functions
+
+/*
+ * brief "/proc" function
+ */
+int amazon_atm_read_procmem(char *buf, char **start, off_t offset,int count, int *eof, void *data)
+{
+	int buf_off=0;	/* for buf */
+	int i=0,j=0;
+	int type= (u32)data;//which module
+	atm_aal5_ifEntry_t mib_aal5;
+	atm_cell_ifEntry_t mib_cell;
+	atm_aal5_vcc_t mib_vcc;
+    	switch(type){
+		case PROC_MIB:
+			//MIB counter
+			amazon_atm_aal5_mib(&mib_aal5);
+			//TX:
+			buf_off+=sprintf(buf+buf_off,"\n============= AAL5 Upstream =========\n");
+			buf_off+=sprintf(buf+buf_off,"received %u (pkts) from upper layer\n", mib_aal5.ifOutUcastPkts);
+			buf_off+=sprintf(buf+buf_off,"errors: %u (pkts)\n",mib_aal5.ifOutErros);
+			buf_off+=sprintf(buf+buf_off,"discards: %u (ptks)\n", mib_aal5.ifOutDiscards);
+			buf_off+=sprintf(buf+buf_off,"transmitted: %x-%x (bytes) \n",
+					mib_aal5.ifHCOutOctets_h, mib_aal5.ifHCOutOctets_l);
+			//RX:
+			buf_off+=sprintf(buf+buf_off,"\n============= AAL5 Downstream =========\n");
+			buf_off+=sprintf(buf+buf_off,"received %x-%x (bytes)\n",
+					mib_aal5.ifHCInOctets_h,mib_aal5.ifHCInOctets_l);
+			buf_off+=sprintf(buf+buf_off,"discards: %u (ptks)\n",mib_aal5.ifInDiscards);
+			buf_off+=sprintf(buf+buf_off,"errors: %u (ptks)\n",mib_aal5.ifInErrors);
+			buf_off+=sprintf(buf+buf_off,"passed %u (ptks) to upper layer\n",mib_aal5.ifInUcastPkts);
+			
+			//Cell level
+			buf_off+=sprintf(buf+buf_off,"\n============= ATM Cell =========\n");
+			amazon_atm_cell_mib(&mib_cell,0);
+#ifdef AMAZON_TPE_READ_ARC			
+			buf_off+=sprintf(buf+buf_off,"Port 0: downstream received: %x-%x (bytes)\n",mib_cell.ifHCInOctets_h,mib_cell.ifHCInOctets_l);
+			buf_off+=sprintf(buf+buf_off,"Port 0: upstream transmitted: %x-%x (bytes)\n",mib_cell.ifHCOutOctets_h,mib_cell.ifHCOutOctets_l);
+			buf_off+=sprintf(buf+buf_off,"Port 0: downstream errors: %u (cells)\n",mib_cell.ifInErrors);
+			amazon_atm_cell_mib(&mib_cell,1);
+			buf_off+=sprintf(buf+buf_off,"Port 1: downstream received: %x-%x (bytes)\n",mib_cell.ifHCInOctets_h,mib_cell.ifHCInOctets_l);
+			buf_off+=sprintf(buf+buf_off,"Port 1: upstream transmitted: %x-%x (bytes)\n",mib_cell.ifHCOutOctets_h,mib_cell.ifHCOutOctets_l);
+			buf_off+=sprintf(buf+buf_off,"Port 1: downstream errors: %u (cells)\n",mib_cell.ifInErrors);
+#endif
+			buf_off+=sprintf(buf+buf_off,"HTU discards: %u (cells)\n",mib_cell.ifInUnknownProtos);
+			
+			buf_off+=sprintf(buf+buf_off,"\n====== Specials =====\n");
+			buf_off+=sprintf(buf+buf_off,"AAL5S PPD: %u (cells)\n",g_atm_dev.mib_counter.tx_ppd);
+#ifdef AMAZON_TPE_SCR
+			buf_off+=sprintf(buf+buf_off,"Reassembly wait: %u \n",g_a5r_wait);
+#endif
+			break;
+		case PROC_ATM:
+			//Interface (Port)
+			buf_off+=sprintf(buf+buf_off,"[Interfaces]\n");
+			for(i=0;i<AMAZON_ATM_PORT_NUM;i++){
+				if (g_atm_dev.ports[i].enable==0){
+					buf_off+=sprintf(buf+buf_off,"\tport[%u] not in use\n",i);
+				}else{
+					buf_off+=sprintf(buf+buf_off,"\tport[%u]\n\t\tmax_conn=%u\n"
+									,i
+									,g_atm_dev.ports[i].max_conn
+									);
+					buf_off+=sprintf(buf+buf_off,"\t\ttx_max=%u\n\t\trem=%u\n\t\tcur=%u\n"
+									,g_atm_dev.ports[i].tx_max_cr
+									,g_atm_dev.ports[i].tx_rem_cr
+									,g_atm_dev.ports[i].tx_cur_cr
+									);
+				}
+
+			}
+			//Units Info
+			//AAL5
+			buf_off+=sprintf(buf+buf_off,"[AAL5]\n\tpad=%c(%x)\n\trx_mtu=%u\n\ttx_mtu=%u\n"
+    					,g_atm_dev.aal5.padding_byte
+    					,g_atm_dev.aal5.padding_byte
+    					,g_atm_dev.aal5.rx_max_sdu
+    					,g_atm_dev.aal5.tx_max_sdu
+    					);
+			//CBM
+			buf_off+=sprintf(buf+buf_off,
+				"[CBM]\n\tnrt_thr=%u\n\tclp0_thr=%u\n\tclp1_thr=%u\n\ttx_q_threshold=%u\n\trx_q_threshold=%u\n\toam_q_threshold=%u\n\tfree_cell_cnt=%u\n"
+    					,g_atm_dev.cbm.nrt_thr
+    					,g_atm_dev.cbm.clp0_thr
+    					,g_atm_dev.cbm.clp1_thr
+					,tx_q_threshold
+					,rx_q_threshold
+					,oam_q_threshold
+    					,g_atm_dev.cbm.free_cell_cnt
+    					);
+			//QSB
+			buf_off+=sprintf(buf+buf_off,"[QSB]\n\ttau=%u\n\ttstepc=%u\n\tsbl=%u\n"
+    					,g_atm_dev.qsb.tau
+    					,g_atm_dev.qsb.tstepc
+    					,g_atm_dev.qsb.sbl
+    					);
+			buf_off+=sprintf(buf+buf_off,"[Debugging]\n\taal5_need_copy=%u\n",g_atm_dev.aal5.cnt_cpy);
+			break;
+		case PROC_VCC:
+			for(i=CBM_DEFAULT_Q_OFFSET,j=0;i<g_atm_dev.cbm.max_q_off+CBM_DEFAULT_Q_OFFSET;i++){
+				if (g_atm_dev.queues[i].free!=1){
+					buf_off+=sprintf(buf+buf_off,"vcc[%u]\n\tvpi=%u vci=%u itf=%u qid=%u access_time=%u.%u\n"
+									,j++
+									,g_atm_dev.queues[i].vcc->vpi
+									,g_atm_dev.queues[i].vcc->vci
+									,g_atm_dev.queues[i].vcc->itf
+									,i
+									,(u32)g_atm_dev.queues[i+CBM_RX_OFFSET].access_time.tv_sec
+									,(u32)g_atm_dev.queues[i+CBM_RX_OFFSET].access_time.tv_usec
+									);
+					buf_off+=sprintf(buf+buf_off,"\tqos_tx class=%u max_pcr=%u pcr=%u min_pcr=%u scr=%u mbs=%u cdv=%u\n"
+									,g_atm_dev.queues[i].vcc->qos.txtp.traffic_class
+									,g_atm_dev.queues[i].vcc->qos.txtp.max_pcr
+									,g_atm_dev.queues[i].vcc->qos.txtp.pcr
+									,g_atm_dev.queues[i].vcc->qos.txtp.min_pcr
+									,g_atm_dev.queues[i].vcc->qos.txtp.scr
+									,g_atm_dev.queues[i].vcc->qos.txtp.mbs
+									,g_atm_dev.queues[i].vcc->qos.txtp.cdv
+									);
+					buf_off+=sprintf(buf+buf_off,"\tqos_rx class=%u max_pcr=%u pcr=%u min_pcr=%u scr=%u mbs=%u cdv=%u\n"
+									,g_atm_dev.queues[i].vcc->qos.rxtp.traffic_class
+									,g_atm_dev.queues[i].vcc->qos.rxtp.max_pcr
+									,g_atm_dev.queues[i].vcc->qos.rxtp.pcr
+									,g_atm_dev.queues[i].vcc->qos.rxtp.min_pcr
+									,g_atm_dev.queues[i].vcc->qos.rxtp.scr
+									,g_atm_dev.queues[i].vcc->qos.rxtp.mbs
+									,g_atm_dev.queues[i].vcc->qos.rxtp.cdv
+									);
+					__amazon_atm_vcc_mib((i+CBM_RX_OFFSET),&mib_vcc);
+					buf_off+=sprintf(buf+buf_off,"\tCRC error=%u\n", mib_vcc.aal5VccCrcErrors);
+					buf_off+=sprintf(buf+buf_off,"\toversized packet=%u\n", mib_vcc.aal5VccOverSizedSDUs);
+#ifdef 	AMAZON_ATM_DEBUG
+					if ( valid_qid(i+CBM_RX_OFFSET)){
+					buf_off+=sprintf(buf+buf_off,"\tdownstream statics\n" );
+					buf_off+=sprintf(buf+buf_off,"\t\tpackets=%u\n",g_atm_dev.queues[i+CBM_RX_OFFSET].qs[QS_PKT]);
+					buf_off+=sprintf(buf+buf_off,"\t\terr_packets=%u\n",g_atm_dev.queues[i+CBM_RX_OFFSET].qs[QS_ERR] );
+					buf_off+=sprintf(buf+buf_off,"\t\tsw_dropped=%u\n",g_atm_dev.queues[i+CBM_RX_OFFSET].qs[QS_SW_DROP] );
+					}
+
+					buf_off+=sprintf(buf+buf_off,"\tupstream statics\n" );
+					buf_off+=sprintf(buf+buf_off,"\t\tpackets=%u\n",g_atm_dev.queues[i].qs[QS_PKT]);
+					buf_off+=sprintf(buf+buf_off,"\t\terr_packets=%u\n",g_atm_dev.queues[i].qs[QS_ERR] );
+					buf_off+=sprintf(buf+buf_off,"\t\thw_dropped=%u\n",g_atm_dev.queues[i].qs[QS_HW_DROP] );
+					buf_off+=sprintf(buf+buf_off,"\t\tsw_dropped=%u\n",g_atm_dev.queues[i].qs[QS_SW_DROP] );
+
+#endif					
+	
+				}
+
+			}
+			break;
+		default:
+			break;
+    	}
+	if(buf_off>0)	*eof = 1;
+	return buf_off;
+}
+
+#ifdef AMAZON_TPE_AAL5_RECOVERY
+extern int (*tpe_reset)(void);
+extern int (*tpe_start)(void);
+extern int (*tpe_inject)(void);
+/*	Brief:		Reset TPE hardware
+ *	Description
+ *		This is a wordaround for AAL5 bug. It tries to reset TPE.
+ *	 take care of software
+ *	 setup all previous connection
+ */
+int amazon_tpe_reset(void)
+{
+	struct atm_vcc * vcc;	
+	int err=0;
+	int i;
+	u8 * qd_addr;
+	u32 reg_l, reg_h;
+	unsigned int a_cfg_value=0;
+	unsigned int a_cfg_old_value=0;
+	atm_aal5_ifEntry_t mib_aal5;
+	atm_cell_ifEntry_t mib_cell;
+	
+	//make sure all cells transmitting out first
+	//Segmentation done
+	amazon_atm_aal5_mib(&mib_aal5);
+	reg_l = g_atm_dev.mib_counter.tx_cnt_l;
+	reg_h = g_atm_dev.mib_counter.tx_cnt_h;
+	while(1){
+		mdelay(10);
+		amazon_atm_aal5_mib(&mib_aal5);
+		if( (reg_l == g_atm_dev.mib_counter.tx_cnt_l) && (reg_h == g_atm_dev.mib_counter.tx_cnt_h) ){
+			break;
+		}
+		AMAZON_TPE_DMSG("AAL5 Segmentation still in progress!\n");
+		reg_l = g_atm_dev.mib_counter.tx_cnt_l;
+		reg_h = g_atm_dev.mib_counter.tx_cnt_h;
+	}
+	//QSB done
+	qd_addr = (u8 *) KSEG1ADDR((unsigned long)g_atm_dev.cbm.qd_addr);
+	for (i=1;i<15;i++){
+		while ( (err=readl(qd_addr+i*CBM_QD_SIZE+0x8)&0xffff) !=0  ){
+			mdelay(20);
+			AMAZON_TPE_DMSG("queue %u not empty (%u)\n",i,err);
+		}
+	}
+	//insurance for interfaces between Aware and CARB
+	mdelay(100);
+	amazon_atm_cell_mib(&mib_cell,0);
+	amazon_atm_cell_mib(&mib_cell,1);
+	amazon_atm_aal5_mib(&mib_aal5);
+	
+	mb();
+	while ( (AMAZON_READ_REGISTER_L(AR_CELLRDY_BC0) != 0 ) || (AMAZON_READ_REGISTER_L(AR_CELLRDY_BC0) != 0 )  ){
+		AMAZON_TPE_EMSG("\nwaiting for AWARE");
+		AMAZON_TPE_EMSG(" BC0 %u ", AMAZON_READ_REGISTER_L(AR_CELLRDY_BC0));
+		AMAZON_TPE_EMSG(" BC1 %u ", AMAZON_READ_REGISTER_L(AR_CELLRDY_BC1));
+		AMAZON_TPE_EMSG("\n");
+		mdelay(1);
+	}
+	// disable AAI module
+	meiDebugRead(A_CFG_ADDR,&a_cfg_value,1);	
+	a_cfg_old_value=a_cfg_value;
+	a_cfg_value &= (~(0x2800));
+	meiDebugWrite(A_CFG_ADDR,&a_cfg_value,1);	
+	//clear buffer
+	a_cfg_value = 0x1;
+	meiDebugWrite(AR_CB0_STATUS_ADDR,&a_cfg_value,1);	
+	meiDebugWrite(AR_CB1_STATUS_ADDR,&a_cfg_value,1);	
+
+	if ( atm_init_hard(&g_atm_dev) != 0){
+		return -EIO;
+	}
+	sema_init(&(g_atm_dev.swie.in_sem), 1);
+	//SWIE lock
+	clear_bit(SWIE_LOCK, &(g_atm_dev.swie.lock));
+	//SWIE wait queue
+	init_waitqueue_head(&(g_atm_dev.swie.sleep));
+	
+	for (i=CBM_DEFAULT_Q_OFFSET;i<AMAZON_ATM_MAX_QUEUE_NUM/2;i++) {
+		vcc = g_atm_dev.queues[i].vcc;
+		if (vcc != NULL){
+			set_qsb(vcc, &vcc->qos, i);
+			set_qd(vcc, i);
+			mb();
+			err=set_htu(vcc,i);
+			if (err){
+				AMAZON_TPE_EMSG("set htu entry fails %u\n",err);
+			}
+		}
+	}
+	meiDebugWrite(A_CFG_ADDR,&a_cfg_old_value,1);	
+#if 0
+	//reset DFE
+	*(AMAZON_RST_REQ) = (* AMAZON_RST_REQ) | (AMAZON_RST_REQ_DFE);
+	mb();
+	*(AMAZON_RST_REQ) = (* AMAZON_RST_REQ) &  (~AMAZON_RST_REQ_DFE);
+	mb();
+#endif
+	
+	return 0;
+}
+
+/* Brief:	Send a ATM EoP packet to save DMA channel
+ */
+int amazon_tpe_inject_debug_cell(void)
+{
+	//Send a ATM cell to save DMA channel
+	u8 qid;
+	unsigned char atm_cell[48];
+	qid = 0x11;
+	AMAZON_TPE_DMSG("qid = %d\n",qid);
+	memset(atm_cell,0,48);
+	atm_cell[3] = 0x2;
+	if ( amazon_atm_swin(qid,atm_cell)) {
+		AMAZON_TPE_EMSG("cannot insert EoP cell\n");
+		return -1;
+	}
+	return 0;
+}
+
+/* Brief:	start HTU (TPE)
+ */
+
+int amazon_tpe_start(void)
+{
+	AMAZON_WRITE_REGISTER_L(HTU_CFG_START ,HTU_CFG_ADDR);
+	wmb();
+	return 0;
+}
+#endif //AMAZON_TPE_AAL5_RECOVERY
+
+#ifdef AMAZON_CHECK_LINK
+extern int (*adsl_link_notify)(int);
+/*	Brief:	notify link status of ADSL link
+ *	Parameters:	0	link down
+ *			1	link up
+ *	Returns:	0 	OK
+ *	Details:	called by MEI driver 
+ *	should update status and inform upper layer
+ */
+int amazon_tpe_link_notify(int status)
+{
+	adsl_link_status = status;
+	AMAZON_TPE_DMSG("link status %s\n",(status==1)?"Up":"Down");
+	if (status == 0){
+		//wait until no cells in upstream queues
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(2*HZ);
+	}
+	return 0;
+}
+#endif //ifdef AMAZON_CHECK_LINK
+
+/*
+ *	Brief: 		Initialize ATM module
+ *
+ *  	Return Value:	ENOMEM		- No memory available
+ *			EBUSY		- Cannot register atm device
+ *			ERESTARTSYS 	- Process interrupted by other signal
+ *			0		- OK, module initialized
+ *
+ *	Description:
+ *	This function registers an atm device for all UTOPIA devices.
+ *	It also allocates memory for the private device data structures
+ */
+int __init amazon_atm_net_init(void)
+{
+	int i;
+	int err=0;
+	amazon_atm_dev_t *dev = NULL;
+	
+	if ((dev=amazon_atm_create()) != NULL){
+		for(i=0;i<AMAZON_ATM_PORT_NUM;i++){
+			if (!dev->ports[i].enable){
+				amazon_atm_devs[i] = NULL;
+				continue;
+			}
+			amazon_atm_devs[i] =atm_dev_register("amazon_atm",&amazon_atm_ops,-1,0UL);
+			if (amazon_atm_devs[i] == NULL){
+				AMAZON_TPE_EMSG("atm_dev_register fails\n");
+				err = -EIO;
+				goto amazon_atm_net_init_exit;
+			}else{
+				AMAZON_TPE_DMSG("registering device %u\n",i);
+				amazon_atm_devs[i]->ci_range.vpi_bits = 8;
+				amazon_atm_devs[i]->ci_range.vci_bits = 16;
+				amazon_atm_devs[i]->link_rate = dev->ports[i].tx_max_cr;
+				amazon_atm_devs[i]->dev_data = (void *) i;
+			}
+		}
+			
+	}else{
+		err = -ENOMEM;
+		AMAZON_TPE_EMSG("cannot init atm device\n");
+		goto amazon_atm_net_init_exit;
+	}
+#ifdef AMAZON_TPE_AAL5_RECOVERY	
+	tpe_reset = & amazon_tpe_reset;
+	tpe_start = & amazon_tpe_start;
+	tpe_inject = & amazon_tpe_inject_debug_cell;
+#endif //AMAZON_TPE_AAL5_RECOVERY
+#ifdef AMAZON_CHECK_LINK
+	adsl_link_notify=amazon_tpe_link_notify;
+#endif //AMAZON_CHECK_LINK
+amazon_atm_net_init_exit:
+	return err;
+}
+
+void __exit amazon_atm_net_cleanup(void)
+{
+	int i;
+	amazon_atm_cleanup();
+	for(i=0;i<AMAZON_ATM_PORT_NUM;i++){
+		if (amazon_atm_devs[i] != NULL){
+			AMAZON_TPE_DMSG("unregister dev %u\n",i);
+			atm_dev_deregister(amazon_atm_devs[i]);
+		}
+	}
+	return;
+}
+EXPORT_SYMBOL(get_oam_time_stamp);
+
+MODULE_LICENSE ("GPL"); 
+MODULE_AUTHOR("Infineon IFAP DC COM peng.liu@infineon.com");
+MODULE_DESCRIPTION("AMAZON ATM driver");
+
+module_init(amazon_atm_net_init);
+module_exit(amazon_atm_net_cleanup);
+ 
+
+
+
+
+

--- /dev/null
+++ b/target/linux/amazon-2.6/files/drivers/char/admmod.c
@@ -1,1 +1,1487 @@
-
+/******************************************************************************
+     Copyright (c) 2004, Infineon Technologies.  All rights reserved.
+
+                               No Warranty
+   Because the program is licensed free of charge, there is no warranty for
+   the program, to the extent permitted by applicable law.  Except when
+   otherwise stated in writing the copyright holders and/or other parties
+   provide the program "as is" without warranty of any kind, either
+   expressed or implied, including, but not limited to, the implied
+   warranties of merchantability and fitness for a particular purpose. The
+   entire risk as to the quality and performance of the program is with
+   you.  should the program prove defective, you assume the cost of all
+   necessary servicing, repair or correction.
+
+   In no event unless required by applicable law or agreed to in writing
+   will any copyright holder, or any other party who may modify and/or
+   redistribute the program as permitted above, be liable to you for
+   damages, including any general, special, incidental or consequential
+   damages arising out of the use or inability to use the program
+   (including but not limited to loss of data or data being rendered
+   inaccurate or losses sustained by you or third parties or a failure of
+   the program to operate with any other programs), even if such holder or
+   other party has been advised of the possibility of such damages.
+ ******************************************************************************
+   Module      : admmod.c
+   Date        : 2004-09-01
+   Description : JoeLin
+   Remarks:
+
+   Revision:
+	MarsLin, add to support VLAN
+
+ *****************************************************************************/
+//000001.joelin 2005/06/02 add"ADM6996_MDC_MDIO_MODE" define, 
+//		if define ADM6996_MDC_MDIO_MODE==> ADM6996LC and ADM6996I will be in MDIO/MDC(SMI)(16 bit) mode,
+//		amazon should contrl ADM6996 by MDC/MDIO pin
+//  		if undef ADM6996_MDC_MDIO_MODE==> ADM6996  will be in EEProm(32 bit) mode,
+//		amazon should contrl ADM6996 by GPIO15,16,17,18  pin
+/* 507281:linmars 2005/07/28 support MDIO/EEPROM config mode */
+/* 509201:linmars remove driver testing codes */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <asm/atomic.h>
+#include <asm-mips/amazon/amazon.h>
+#include <asm-mips/amazon/adm6996.h>
+//#include <linux/amazon/adm6996.h>
+
+
+unsigned int ifx_sw_conf[ADM_SW_MAX_PORT_NUM+1] = \
+	{ADM_SW_PORT0_CONF, ADM_SW_PORT1_CONF, ADM_SW_PORT2_CONF, \
+	ADM_SW_PORT3_CONF, ADM_SW_PORT4_CONF, ADM_SW_PORT5_CONF};
+unsigned int ifx_sw_bits[8] = \
+	{0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff};
+unsigned int ifx_sw_vlan_port[6] = {0, 2, 4, 6, 7, 8};
+//050613:fchang 
+/* 507281:linmars start */
+#ifdef CONFIG_SWITCH_ADM6996_MDIO
+#define ADM6996_MDC_MDIO_MODE 1 //000001.joelin
+#else
+#undef ADM6996_MDC_MDIO_MODE
+#endif
+/* 507281:linmars end */
+#define adm6996i 0
+#define adm6996lc 1
+#define adm6996l  2
+unsigned int adm6996_mode=adm6996i;
+/*
+  initialize GPIO pins.
+  output mode, low
+*/
+void ifx_gpio_init(void)
+{
+ //GPIO16,17,18 direction:output
+ //GPIO16,17,18 output 0
+ 
+    AMAZON_SW_REG(AMAZON_GPIO_P1_DIR) |= (GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT) =AMAZON_SW_REG(AMAZON_GPIO_P1_IN)& ~(GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
+
+}
+
+/* read one bit from mdio port */
+int ifx_sw_mdio_readbit(void)
+{
+    //int val;
+
+    //val = (AMAZON_SW_REG(GPIO_conf0_REG) & GPIO0_INPUT_MASK) >> 8;
+    //return val;
+    //GPIO16
+    return AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&1;
+}
+
+/*
+  MDIO mode selection
+  1 -> output
+  0 -> input
+
+  switch input/output mode of GPIO 0
+*/
+void ifx_mdio_mode(int mode)
+{
+//    AMAZON_SW_REG(GPIO_conf0_REG) = mode ? GPIO_ENABLEBITS :
+//                             ((GPIO_ENABLEBITS | MDIO_INPUT) & ~MDIO_OUTPUT_EN);
+    mode?(AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)|=GPIO_MDIO):
+         (AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)&=~GPIO_MDIO);
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_DIR);
+    mode?(r|=GPIO_MDIO):(r&=~GPIO_MDIO);
+    AMAZON_SW_REG(AMAZON_GPIO_P1_DIR)=r;*/
+}
+
+void ifx_mdc_hi(void)
+{
+    //GPIO_SET_HI(GPIO_MDC);
+    //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDC;
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
+    r|=GPIO_MDC;
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
+
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDC;
+}
+
+void ifx_mdio_hi(void)
+{
+    //GPIO_SET_HI(GPIO_MDIO);
+    //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDIO;
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
+    r|=GPIO_MDIO;
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
+
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDIO;
+}
+
+void ifx_mdcs_hi(void)
+{
+    //GPIO_SET_HI(GPIO_MDCS);
+    //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)|=GPIO_MDCS;
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
+    r|=GPIO_MDCS;
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
+
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)|GPIO_MDCS;
+}
+
+void ifx_mdc_lo(void)
+{
+    //GPIO_SET_LOW(GPIO_MDC);
+    //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDC;
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
+    r&=~GPIO_MDC;
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
+
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDC);
+}
+
+void ifx_mdio_lo(void)
+{
+    //GPIO_SET_LOW(GPIO_MDIO);
+    //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDIO;
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
+    r&=~GPIO_MDIO;
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
+
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDIO);
+}
+
+void ifx_mdcs_lo(void)
+{
+    //GPIO_SET_LOW(GPIO_MDCS);
+    //AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)&=~GPIO_MDCS;
+    /*int r=AMAZON_SW_REG(AMAZON_GPIO_P1_OUT);
+    r&=~GPIO_MDCS;
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=r;*/
+    
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OUT)=AMAZON_SW_REG(AMAZON_GPIO_P1_IN)&(~GPIO_MDCS);
+}
+
+/*
+  mdc pulse
+  0 -> 1 -> 0
+*/
+static void ifx_sw_mdc_pulse(void)
+{
+    ifx_mdc_lo();
+    udelay(ADM_SW_MDC_DOWN_DELAY);
+    ifx_mdc_hi();
+    udelay(ADM_SW_MDC_UP_DELAY);
+    ifx_mdc_lo();
+}
+
+/*
+  mdc toggle
+  1 -> 0
+*/
+static void ifx_sw_mdc_toggle(void)
+{
+    ifx_mdc_hi();
+    udelay(ADM_SW_MDC_UP_DELAY);
+    ifx_mdc_lo();
+    udelay(ADM_SW_MDC_DOWN_DELAY);
+}
+
+/*
+  enable eeprom write
+  For ATC 93C66 type EEPROM; accessing ADM6996 internal EEPROM type registers
+*/
+static void ifx_sw_eeprom_write_enable(void)
+{
+    unsigned int op;
+
+    ifx_mdcs_lo();
+    ifx_mdc_lo();
+    ifx_mdio_hi();
+    udelay(ADM_SW_CS_DELAY);
+    /* enable chip select */
+    ifx_mdcs_hi();
+    udelay(ADM_SW_CS_DELAY);
+    /* start bit */
+    ifx_mdio_hi();
+    ifx_sw_mdc_pulse();
+
+    /* eeprom write enable */
+    op = ADM_SW_BIT_MASK_4;
+    while (op)
+    {
+        if (op & ADM_SW_EEPROM_WRITE_ENABLE)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 3);
+    while (op)
+    {
+        ifx_mdio_lo();
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+    /* disable chip select */
+    ifx_mdcs_lo();
+    udelay(ADM_SW_CS_DELAY);
+    ifx_sw_mdc_pulse();
+}
+
+/*
+  disable eeprom write
+*/
+static void ifx_sw_eeprom_write_disable(void)
+{
+    unsigned int op;
+
+    ifx_mdcs_lo();
+    ifx_mdc_lo();
+    ifx_mdio_hi();
+    udelay(ADM_SW_CS_DELAY);
+    /* enable chip select */
+    ifx_mdcs_hi();
+    udelay(ADM_SW_CS_DELAY);
+
+    /* start bit */
+    ifx_mdio_hi();
+    ifx_sw_mdc_pulse();
+    /* eeprom write disable */
+    op = ADM_SW_BIT_MASK_4;
+    while (op)
+    {
+        if (op & ADM_SW_EEPROM_WRITE_DISABLE)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 3);
+    while (op)
+    {
+        ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+    /* disable chip select */
+    ifx_mdcs_lo();
+    udelay(ADM_SW_CS_DELAY);
+    ifx_sw_mdc_pulse();
+}
+
+/*
+  read registers from ADM6996
+  serial registers start at 0x200 (addr bit 9 = 1b)
+  EEPROM registers -> 16bits; Serial registers -> 32bits
+*/
+#ifdef ADM6996_MDC_MDIO_MODE //smi mode//000001.joelin
+static int ifx_sw_read_adm6996i_smi(unsigned int addr, unsigned int *dat)
+{
+   addr=(addr<<16)&0x3ff0000;
+   AMAZON_SW_REG(AMAZON_SW_MDIO_ACC) =(0xC0000000|addr);
+   while ((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x80000000){};
+   *dat=((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x0FFFF);
+    return 0;
+}
+#endif
+
+static int ifx_sw_read_adm6996i(unsigned int addr, unsigned int *dat)
+{
+    unsigned int op;
+
+    ifx_gpio_init();
+
+    ifx_mdcs_hi();
+    udelay(ADM_SW_CS_DELAY);
+
+    ifx_mdcs_lo();
+    ifx_mdc_lo();
+    ifx_mdio_lo();
+
+    udelay(ADM_SW_CS_DELAY);
+
+    /* preamble, 32 bit 1 */
+    ifx_mdio_hi();
+    op = ADM_SW_BIT_MASK_32;
+    while (op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* command start (01b) */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_SMI_START)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* read command (10b) */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_SMI_READ)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* send address A9 ~ A0 */
+    op = ADM_SW_BIT_MASK_10;
+    while (op)
+    {
+        if (op & addr)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* turnaround bits */
+    op = ADM_SW_BIT_MASK_2;
+    ifx_mdio_hi();
+    while (op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    udelay(ADM_SW_MDC_DOWN_DELAY);
+
+    /* set MDIO pin to input mode */
+    ifx_mdio_mode(ADM_SW_MDIO_INPUT);
+
+    /* start read data */
+    *dat = 0;
+//adm6996i    op = ADM_SW_BIT_MASK_32;
+    op = ADM_SW_BIT_MASK_16;//adm6996i
+    while (op)
+    {
+        *dat <<= 1;
+        if (ifx_sw_mdio_readbit()) *dat |= 1;
+        ifx_sw_mdc_toggle();
+
+        op >>= 1;
+    }
+
+    /* set MDIO to output mode */
+    ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
+
+    /* dummy clock */
+    op = ADM_SW_BIT_MASK_4;
+    ifx_mdio_lo();
+    while(op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    ifx_mdc_lo();
+    ifx_mdio_lo();
+    ifx_mdcs_hi();
+
+    /* EEPROM registers */
+//adm6996i    if (!(addr & 0x200))
+//adm6996i    {
+//adm6996i        if (addr % 2)
+//adm6996i            *dat >>= 16;
+//adm6996i        else
+//adm6996i        *dat &= 0xffff;
+//adm6996i    }
+
+    return 0;
+}
+//adm6996
+static int ifx_sw_read_adm6996l(unsigned int addr, unsigned int *dat)
+{
+    unsigned int op;
+
+    ifx_gpio_init();
+
+    ifx_mdcs_hi();
+    udelay(ADM_SW_CS_DELAY);
+
+    ifx_mdcs_lo();
+    ifx_mdc_lo();
+    ifx_mdio_lo();
+
+    udelay(ADM_SW_CS_DELAY);
+
+    /* preamble, 32 bit 1 */
+    ifx_mdio_hi();
+    op = ADM_SW_BIT_MASK_32;
+    while (op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* command start (01b) */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_SMI_START)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* read command (10b) */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_SMI_READ)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* send address A9 ~ A0 */
+    op = ADM_SW_BIT_MASK_10;
+    while (op)
+    {
+        if (op & addr)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* turnaround bits */
+    op = ADM_SW_BIT_MASK_2;
+    ifx_mdio_hi();
+    while (op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    udelay(ADM_SW_MDC_DOWN_DELAY);
+
+    /* set MDIO pin to input mode */
+    ifx_mdio_mode(ADM_SW_MDIO_INPUT);
+
+    /* start read data */
+    *dat = 0;
+    op = ADM_SW_BIT_MASK_32;
+    while (op)
+    {
+        *dat <<= 1;
+        if (ifx_sw_mdio_readbit()) *dat |= 1;
+        ifx_sw_mdc_toggle();
+
+        op >>= 1;
+    }
+
+    /* set MDIO to output mode */
+    ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
+
+    /* dummy clock */
+    op = ADM_SW_BIT_MASK_4;
+    ifx_mdio_lo();
+    while(op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    ifx_mdc_lo();
+    ifx_mdio_lo();
+    ifx_mdcs_hi();
+
+    /* EEPROM registers */
+    if (!(addr & 0x200))
+    {
+        if (addr % 2)
+            *dat >>= 16;
+        else
+        *dat &= 0xffff;
+    }
+
+    return 0;
+}
+
+static int ifx_sw_read(unsigned int addr, unsigned int *dat)
+{
+#ifdef ADM6996_MDC_MDIO_MODE //smi mode ////000001.joelin
+	ifx_sw_read_adm6996i_smi(addr,dat);
+#else	
+	if (adm6996_mode==adm6996i) ifx_sw_read_adm6996i(addr,dat);
+		else ifx_sw_read_adm6996l(addr,dat);
+#endif		
+	return 0;
+	
+}
+
+/*
+  write register to ADM6996 eeprom registers
+*/
+//for adm6996i -start
+#ifdef ADM6996_MDC_MDIO_MODE //smi mode //000001.joelin
+static int ifx_sw_write_adm6996i_smi(unsigned int addr, unsigned int dat)
+{
+ 
+   AMAZON_SW_REG(AMAZON_SW_MDIO_ACC) = ((addr<<16)&0x3ff0000)|dat|0x80000000;
+   while ((AMAZON_SW_REG(AMAZON_SW_MDIO_ACC))&0x80000000){};
+  
+    return 0;
+ 
+}
+#endif //ADM6996_MDC_MDIO_MODE //000001.joelin
+
+static int ifx_sw_write_adm6996i(unsigned int addr, unsigned int dat)
+{
+    unsigned int op;
+
+    ifx_gpio_init();
+
+    ifx_mdcs_hi();
+    udelay(ADM_SW_CS_DELAY);
+
+    ifx_mdcs_lo();
+    ifx_mdc_lo();
+    ifx_mdio_lo();
+
+    udelay(ADM_SW_CS_DELAY);
+
+    /* preamble, 32 bit 1 */
+    ifx_mdio_hi();
+    op = ADM_SW_BIT_MASK_32;
+    while (op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* command start (01b) */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_SMI_START)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* write command (01b) */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_SMI_WRITE)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* send address A9 ~ A0 */
+    op = ADM_SW_BIT_MASK_10;
+    while (op)
+    {
+        if (op & addr)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* turnaround bits */
+    op = ADM_SW_BIT_MASK_2;
+    ifx_mdio_hi();
+    while (op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    udelay(ADM_SW_MDC_DOWN_DELAY);
+
+    /* set MDIO pin to output mode */
+    ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
+
+  
+    /* start write data */
+    op = ADM_SW_BIT_MASK_16;
+    while (op)
+    {
+        if (op & dat)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_toggle();
+        op >>= 1;
+    }
+
+ //   /* set MDIO to output mode */
+ //   ifx_mdio_mode(ADM_SW_MDIO_OUTPUT);
+
+    /* dummy clock */
+    op = ADM_SW_BIT_MASK_4;
+    ifx_mdio_lo();
+    while(op)
+    {
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    ifx_mdc_lo();
+    ifx_mdio_lo();
+    ifx_mdcs_hi();
+
+    /* EEPROM registers */
+//adm6996i    if (!(addr & 0x200))
+//adm6996i    {
+//adm6996i        if (addr % 2)
+//adm6996i            *dat >>= 16;
+//adm6996i        else
+//adm6996i        *dat &= 0xffff;
+//adm6996i    }
+
+    return 0;
+}
+//for adm6996i-end
+static int ifx_sw_write_adm6996l(unsigned int addr, unsigned int dat)
+{
+    unsigned int op;
+
+    ifx_gpio_init();
+
+    /* enable write */
+    ifx_sw_eeprom_write_enable();
+
+    /* chip select */
+    ifx_mdcs_hi();
+    udelay(ADM_SW_CS_DELAY);
+
+    /* issue write command */
+    /* start bit */
+    ifx_mdio_hi();
+    ifx_sw_mdc_pulse();
+
+    /* EEPROM write command */
+    op = ADM_SW_BIT_MASK_2;
+    while (op)
+    {
+        if (op & ADM_SW_EEPROM_WRITE)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_pulse();
+        op >>= 1;
+    }
+
+    /* send address A7 ~ A0 */
+    op = ADM_SW_BIT_MASK_1 << (EEPROM_TYPE - 1);
+
+    while (op)
+    {
+        if (op & addr)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_toggle();
+        op >>= 1;
+    }
+
+    /* start write data */
+    op = ADM_SW_BIT_MASK_16;
+    while (op)
+    {
+        if (op & dat)
+            ifx_mdio_hi();
+        else
+            ifx_mdio_lo();
+
+        ifx_sw_mdc_toggle();
+        op >>= 1;
+    }
+
+    /* disable cs & wait 1 clock */
+    ifx_mdcs_lo();
+    udelay(ADM_SW_CS_DELAY);
+    ifx_sw_mdc_toggle();
+
+    ifx_sw_eeprom_write_disable();
+
+    return 0;
+}
+
+static int ifx_sw_write(unsigned int addr, unsigned int dat)
+{
+#ifdef ADM6996_MDC_MDIO_MODE //smi mode ////000001.joelin
+	ifx_sw_write_adm6996i_smi(addr,dat);
+#else	//000001.joelin
+	if (adm6996_mode==adm6996i) ifx_sw_write_adm6996i(addr,dat);
+		else ifx_sw_write_adm6996l(addr,dat);
+#endif	//000001.joelin
+	return 0;
+}
+
+/*
+  do switch PHY reset
+*/
+int ifx_sw_reset(void)
+{
+    /* reset PHY */
+    ifx_sw_write(ADM_SW_PHY_RESET, 0);
+
+    return 0;
+}
+
+/* 509201:linmars start */
+#if 0
+/*
+  check port status
+*/
+int ifx_check_port_status(int port)
+{
+    unsigned int val;
+
+    if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM))
+    {
+        ifx_printf(("error on port number (%d)!!\n", port));
+        return -1;
+    }
+
+    ifx_sw_read(ifx_sw_conf[port], &val);
+    if (ifx_sw_conf[port]%2) val >>= 16;
+    /* only 16bits are effective */
+    val &= 0xFFFF;
+
+    ifx_printf(("Port %d status (%.8x): \n", port, val));
+
+    if (val & ADM_SW_PORT_FLOWCTL)
+        ifx_printf(("\t802.3x flow control supported!\n"));
+    else
+        ifx_printf(("\t802.3x flow control not supported!\n"));
+
+    if (val & ADM_SW_PORT_AN)
+        ifx_printf(("\tAuto negotiation ON!\n"));
+    else
+        ifx_printf(("\tAuto negotiation OFF!\n"));
+
+    if (val & ADM_SW_PORT_100M)
+        ifx_printf(("\tLink at 100M!\n"));
+    else
+        ifx_printf(("\tLink at 10M!\n"));
+
+    if (val & ADM_SW_PORT_FULL)
+        ifx_printf(("\tFull duplex!\n"));
+    else
+        ifx_printf(("\tHalf duplex!\n"));
+
+    if (val & ADM_SW_PORT_DISABLE)
+        ifx_printf(("\tPort disabled!\n"));
+    else
+        ifx_printf(("\tPort enabled!\n"));
+
+    if (val & ADM_SW_PORT_TOS)
+        ifx_printf(("\tTOS enabled!\n"));
+    else
+        ifx_printf(("\tTOS disabled!\n"));
+
+    if (val & ADM_SW_PORT_PPRI)
+        ifx_printf(("\tPort priority first!\n"));
+    else
+        ifx_printf(("\tVLAN or TOS priority first!\n"));
+
+    if (val & ADM_SW_PORT_MDIX)
+        ifx_printf(("\tAuto MDIX!\n"));
+    else
+        ifx_printf(("\tNo auto MDIX\n"));
+
+    ifx_printf(("\tPVID: %d\n", \
+  	    ((val >> ADM_SW_PORT_PVID_SHIFT)&ifx_sw_bits[ADM_SW_PORT_PVID_BITS])));
+
+    return 0;
+}
+/*
+  initialize a VLAN
+  clear all VLAN bits
+*/
+int ifx_sw_vlan_init(int vlanid)
+{
+    ifx_sw_write(ADM_SW_VLAN0_CONF + vlanid, 0);
+
+    return 0;
+}
+
+/*
+  add a port to certain vlan
+*/
+int ifx_sw_vlan_add(int port, int vlanid)
+{
+    int reg = 0;
+
+    if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM) || (vlanid < 0) ||
+        (vlanid > ADM_SW_MAX_VLAN_NUM))
+    {
+        ifx_printf(("Port number or VLAN number ERROR!!\n"));
+        return -1;
+    }
+    ifx_sw_read(ADM_SW_VLAN0_CONF + vlanid, &reg);
+    reg |= (1 << ifx_sw_vlan_port[port]);
+    ifx_sw_write(ADM_SW_VLAN0_CONF + vlanid, reg);
+
+    return 0;
+}
+
+/*
+  delete a given port from certain vlan
+*/
+int ifx_sw_vlan_del(int port, int vlanid)
+{
+    unsigned int reg = 0;
+
+    if ((port < 0) || (port > ADM_SW_MAX_PORT_NUM) || (vlanid < 0) || (vlanid > ADM_SW_MAX_VLAN_NUM))
+    {
+        ifx_printf(("Port number or VLAN number ERROR!!\n"));
+        return -1;
+    }
+    ifx_sw_read(ADM_SW_VLAN0_CONF + vlanid, &reg);
+    reg &= ~(1 << ifx_sw_vlan_port[port]);
+    ifx_sw_write(ADM_SW_VLAN0_CONF + vlanid, reg);
+
+    return 0;
+}
+
+/*
+  default VLAN setting
+
+  port 0~3 as untag port and PVID = 1
+  VLAN1: port 0~3 and port 5 (MII)
+*/
+static int ifx_sw_init(void)
+{
+    ifx_printf(("Setting default ADM6996 registers... \n"));
+
+    /* MAC clone, 802.1q based VLAN */
+    ifx_sw_write(ADM_SW_VLAN_MODE, 0xff30);
+    /* auto MDIX, PVID=1, untag */
+    ifx_sw_write(ADM_SW_PORT0_CONF, 0x840f);
+    ifx_sw_write(ADM_SW_PORT1_CONF, 0x840f);
+    ifx_sw_write(ADM_SW_PORT2_CONF, 0x840f);
+    ifx_sw_write(ADM_SW_PORT3_CONF, 0x840f);
+    /* auto MDIX, PVID=2, untag */
+    ifx_sw_write(ADM_SW_PORT5_CONF, 0x880f);
+    /* port 0~3 & 5 as VLAN1 */
+    ifx_sw_write(ADM_SW_VLAN0_CONF+1, 0x0155);
+
+    return 0;
+}
+#endif
+/* 509201:linmars end */
+
+int adm_open(struct inode *node, struct file *filp)
+{
+    MOD_INC_USE_COUNT;
+    return 0;
+}
+
+ssize_t adm_read(struct file *filep, char *buf, size_t count, loff_t *ppos)
+{
+    return count;
+}
+
+ssize_t adm_write(struct file *filep, const char *buf, size_t count, loff_t *ppos)
+{
+    return count;
+}
+
+/* close */
+int adm_release(struct inode *inode, struct file *filp)
+{
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+/* IOCTL function */
+int adm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long args)
+{
+    PREGRW uREGRW;
+    unsigned int rtval;
+    unsigned int val;		//6996i
+    unsigned int control[6] ;	//6996i
+    unsigned int status[6] ;	//6996i
+    
+    PMACENTRY mMACENTRY;//adm6996i
+    PPROTOCOLFILTER uPROTOCOLFILTER ;///adm6996i
+
+    if (_IOC_TYPE(cmd) != ADM_MAGIC)
+    {
+        printk("adm_ioctl: IOC_TYPE(%x) != ADM_MAGIC(%x)! \n", _IOC_TYPE(cmd), ADM_MAGIC);
+        return (-EINVAL);
+    }
+
+    if(_IOC_NR(cmd) >= KEY_IOCTL_MAX_KEY)
+    {
+        printk(KERN_WARNING "adm_ioctl: IOC_NR(%x) invalid! \n", _IOC_NR(cmd));
+        return (-EINVAL);
+    }
+
+    switch (cmd)
+    {
+        case ADM_IOCTL_REGRW:
+        {
+            uREGRW = (PREGRW)kmalloc(sizeof(REGRW), GFP_KERNEL);
+            rtval = copy_from_user(uREGRW, (PREGRW)args, sizeof(REGRW));
+            if (rtval != 0)
+            {
+                printk("ADM_IOCTL_REGRW: copy from user FAILED!! \n");
+                return (-EFAULT);
+            }
+
+            switch(uREGRW->mode)
+            {
+                case REG_READ:
+                    uREGRW->value = 0x12345678;//inl(uREGRW->addr);
+                    copy_to_user((PREGRW)args, uREGRW, sizeof(REGRW));
+                    break;
+                case REG_WRITE:
+                    //outl(uREGRW->value, uREGRW->addr);
+                    break;
+
+                default:
+                    printk("No such Register Read/Write function!! \n");
+                    return (-EFAULT);
+            }
+            kfree(uREGRW);
+            break;
+        }
+
+        case ADM_SW_IOCTL_REGRW:
+        {
+            unsigned int val = 0xff;
+
+            uREGRW = (PREGRW)kmalloc(sizeof(REGRW), GFP_KERNEL);
+            rtval = copy_from_user(uREGRW, (PREGRW)args, sizeof(REGRW));
+            if (rtval != 0)
+            {
+                printk("ADM_IOCTL_REGRW: copy from user FAILED!! \n");
+                return (-EFAULT);
+            }
+
+            switch(uREGRW->mode)
+            {
+                case REG_READ:
+                    ifx_sw_read(uREGRW->addr, &val);
+                    uREGRW->value = val;
+                    copy_to_user((PREGRW)args, uREGRW, sizeof(REGRW));
+                    break;
+
+                case REG_WRITE:
+                    ifx_sw_write(uREGRW->addr, uREGRW->value);
+                    break;
+                default:
+                    printk("No such Register Read/Write function!! \n");
+                    return (-EFAULT);
+            }
+            kfree(uREGRW);
+            break;
+        }
+/* 509201:linmars start */
+#if 0
+        case ADM_SW_IOCTL_PORTSTS:
+            for (rtval = 0; rtval < ADM_SW_MAX_PORT_NUM+1; rtval++)
+                ifx_check_port_status(rtval);
+            break;
+        case ADM_SW_IOCTL_INIT:
+            ifx_sw_init();
+            break;
+#endif
+/* 509201:linmars end */
+//adm6996i
+        case ADM_SW_IOCTL_MACENTRY_ADD:
+        case ADM_SW_IOCTL_MACENTRY_DEL:
+        case ADM_SW_IOCTL_MACENTRY_GET_INIT:
+        case ADM_SW_IOCTL_MACENTRY_GET_MORE:
+                
+
+           mMACENTRY = (PMACENTRY)kmalloc(sizeof(MACENTRY), GFP_KERNEL);
+            rtval = copy_from_user(mMACENTRY, (PMACENTRY)args, sizeof(MACENTRY));
+            if (rtval != 0)
+            {
+                printk("ADM_SW_IOCTL_MACENTRY: copy from user FAILED!! \n");
+                return (-EFAULT);
+            }
+           control[0]=(mMACENTRY->mac_addr[1]<<8)+mMACENTRY->mac_addr[0]     ; 
+           control[1]=(mMACENTRY->mac_addr[3]<<8)+mMACENTRY->mac_addr[2]      ;         
+           control[2]=(mMACENTRY->mac_addr[5]<<8)+mMACENTRY->mac_addr[4]     ;
+           control[3]=(mMACENTRY->fid&0xf)+((mMACENTRY->portmap&0x3f)<<4);
+           if (((mMACENTRY->info_type)&0x01)) control[4]=(mMACENTRY->ctrl.info_ctrl)+0x1000; //static ,info control
+           	else	control[4]=((mMACENTRY->ctrl.age_timer)&0xff);//not static ,agetimer
+         	if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT) { 	
+	           //initial  the pointer to the first address	
+			           val=0x8000;//busy ,status5[15]
+			           while(val&0x8000){		//check busy ?
+			 	          ifx_sw_read(0x125, &val);
+			        	}    
+			           control[5]=0x030;//initial the first address	
+			           ifx_sw_write(0x11f,control[5]);
+			        	       	
+			           	
+			           val=0x8000;//busy ,status5[15]
+			           while(val&0x8000){		//check busy ?
+			 	          ifx_sw_read(0x125, &val);
+			        	}           	
+	           	
+	           }	//if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)								
+           if (cmd==ADM_SW_IOCTL_MACENTRY_ADD) control[5]=0x07;//create a new address
+           	else if (cmd==ADM_SW_IOCTL_MACENTRY_DEL) control[5]=0x01f;//erased an existed address
+           	else if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) 
+           		control[5]=0x02c;//search by the mac address field
+           
+           val=0x8000;//busy ,status5[15]
+           while(val&0x8000){		//check busy ?
+ 	          ifx_sw_read(0x125, &val);
+        	}
+        	ifx_sw_write(0x11a,control[0]);	
+        	ifx_sw_write(0x11b,control[1]);	
+        	ifx_sw_write(0x11c,control[2]);	
+        	ifx_sw_write(0x11d,control[3]);	
+        	ifx_sw_write(0x11e,control[4]);	
+        	ifx_sw_write(0x11f,control[5]);	
+           val=0x8000;//busy ,status5[15]
+           while(val&0x8000){		//check busy ?
+ 	          ifx_sw_read(0x125, &val);
+        	}	
+           val=((val&0x7000)>>12);//result ,status5[14:12]
+           mMACENTRY->result=val;
+   
+           if (!val) {
+        		printk(" Command OK!! \n");
+        		if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) {
+			           	ifx_sw_read(0x120,&(status[0]));	
+			        	ifx_sw_read(0x121,&(status[1]));	
+			        	ifx_sw_read(0x122,&(status[2]));	
+			        	ifx_sw_read(0x123,&(status[3]));	
+			        	ifx_sw_read(0x124,&(status[4]));	
+			        	ifx_sw_read(0x125,&(status[5]));	
+		
+		           		
+		        		mMACENTRY->mac_addr[0]=(status[0]&0x00ff)	;
+		        		mMACENTRY->mac_addr[1]=(status[0]&0xff00)>>8    ;
+		        		mMACENTRY->mac_addr[2]=(status[1]&0x00ff)    ;
+		        		mMACENTRY->mac_addr[3]=(status[1]&0xff00)>>8 ;
+		        		mMACENTRY->mac_addr[4]=(status[2]&0x00ff)    ;
+		        		mMACENTRY->mac_addr[5]=(status[2]&0xff00)>>8 ;
+		        		mMACENTRY->fid=(status[3]&0xf);
+		        		mMACENTRY->portmap=((status[3]>>4)&0x3f);
+		        		if (status[5]&0x2) {//static info_ctrl //status5[1]????
+		        			mMACENTRY->ctrl.info_ctrl=(status[4]&0x00ff);
+		  				mMACENTRY->info_type=1;
+		        				}
+		        		else {//not static age_timer
+		        			mMACENTRY->ctrl.age_timer=(status[4]&0x00ff);
+		  				mMACENTRY->info_type=0;
+		        				}
+//status5[13]????					mMACENTRY->occupy=(status[5]&0x02)>>1;//status5[1]
+					mMACENTRY->occupy=(status[5]&0x02000)>>13;//status5[13] ???
+					mMACENTRY->bad=(status[5]&0x04)>>2;//status5[2]
+				}//if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) 
+			
+        	}
+           else if (val==0x001)  
+                printk(" All Entry Used!! \n");
+            else if (val==0x002) 
+                printk("  Entry Not Found!! \n");
+            else if (val==0x003) 
+                printk(" Try Next Entry!! \n");
+            else if (val==0x005)  
+                printk(" Command Error!! \n");   
+            else   
+                printk(" UnKnown Error!! \n");
+                
+            copy_to_user((PMACENTRY)args, mMACENTRY,sizeof(MACENTRY));    
+                
+ 	    break;  
+ 
+        case ADM_SW_IOCTL_FILTER_ADD:
+        case ADM_SW_IOCTL_FILTER_DEL:
+        case ADM_SW_IOCTL_FILTER_GET:
+
+            uPROTOCOLFILTER = (PPROTOCOLFILTER)kmalloc(sizeof(PROTOCOLFILTER), GFP_KERNEL);
+            rtval = copy_from_user(uPROTOCOLFILTER, (PPROTOCOLFILTER)args, sizeof(PROTOCOLFILTER));
+            if (rtval != 0)
+            {
+                printk("ADM_SW_IOCTL_FILTER_ADD: copy from user FAILED!! \n");
+                return (-EFAULT);
+            }
+            
+        	if(cmd==ADM_SW_IOCTL_FILTER_DEL) {	//delete filter
+			uPROTOCOLFILTER->ip_p=00;	//delet filter
+			uPROTOCOLFILTER->action=00;	//delete filter
+		}					//delete filter
+
+            ifx_sw_read(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), &val);//rx68~rx6b,protocol filter0~7	
+
+            	if (((uPROTOCOLFILTER->protocol_filter_num)%2)==00){	
+            		if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= val&0x00ff;//get filter ip_p
+            			else val=(val&0xff00)|(uPROTOCOLFILTER->ip_p);//set filter ip_p
+        	}
+        	else {
+        		if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= (val>>8);//get filter ip_p
+        			else val=(val&0x00ff)|((uPROTOCOLFILTER->ip_p)<<8);//set filter ip_p
+        	}	
+            if(cmd!=ADM_SW_IOCTL_FILTER_GET) ifx_sw_write(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), val);//write rx68~rx6b,protocol filter0~7	
+            		
+            ifx_sw_read(0x95, &val);	//protocol filter action
+            if(cmd==ADM_SW_IOCTL_FILTER_GET) {
+            		uPROTOCOLFILTER->action= ((val>>(uPROTOCOLFILTER->protocol_filter_num*2))&0x3);//get filter action
+            		copy_to_user((PPROTOCOLFILTER)args, uPROTOCOLFILTER, sizeof(PROTOCOLFILTER));
+            	
+            	}
+            	else {
+            		val=(val&(~(0x03<<(uPROTOCOLFILTER->protocol_filter_num*2))))|(((uPROTOCOLFILTER->action)&0x03)<<(uPROTOCOLFILTER->protocol_filter_num*2));
+  //          		printk("%d----\n",val);
+            		ifx_sw_write(0x95, val);	//write protocol filter action		
+            	}
+            	
+            break;
+//adm6996i  
+
+        /* others */
+        default:
+            return -EFAULT;
+    }
+    /* end of switch */
+    return 0;
+}
+
+/* Santosh: handle IGMP protocol filter ADD/DEL/GET */
+int adm_process_protocol_filter_request (unsigned int cmd, PPROTOCOLFILTER uPROTOCOLFILTER)
+{
+    unsigned int val;		//6996i
+
+	if(cmd==ADM_SW_IOCTL_FILTER_DEL) {	//delete filter
+	uPROTOCOLFILTER->ip_p=00;	//delet filter
+	uPROTOCOLFILTER->action=00;	//delete filter
+	}					//delete filter
+
+    ifx_sw_read(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), &val);//rx68~rx6b,protocol filter0~7	
+
+    if (((uPROTOCOLFILTER->protocol_filter_num)%2)==00){	
+    	if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= val&0x00ff;//get filter ip_p
+        else val=(val&0xff00)|(uPROTOCOLFILTER->ip_p);//set filter ip_p
+    }
+    else {
+    	if(cmd==ADM_SW_IOCTL_FILTER_GET) uPROTOCOLFILTER->ip_p= (val>>8);//get filter ip_p
+    	else val=(val&0x00ff)|((uPROTOCOLFILTER->ip_p)<<8);//set filter ip_p
+    }	
+    if(cmd!=ADM_SW_IOCTL_FILTER_GET) ifx_sw_write(((uPROTOCOLFILTER->protocol_filter_num/2)+0x68), val);//write rx68~rx6b,protocol filter0~7	
+            		
+    	ifx_sw_read(0x95, &val);	//protocol filter action
+    if(cmd==ADM_SW_IOCTL_FILTER_GET) {
+       	uPROTOCOLFILTER->action= ((val>>(uPROTOCOLFILTER->protocol_filter_num*2))&0x3);//get filter action
+    }
+    else {
+    	val=(val&(~(0x03<<(uPROTOCOLFILTER->protocol_filter_num*2))))|(((uPROTOCOLFILTER->action)&0x03)<<(uPROTOCOLFILTER->protocol_filter_num*2));
+        ifx_sw_write(0x95, val);	//write protocol filter action		
+    }
+            	
+	return 0;
+}
+
+
+/* Santosh: function for MAC ENTRY ADD/DEL/GET */
+
+int adm_process_mac_table_request (unsigned int cmd, PMACENTRY mMACENTRY)
+{
+    unsigned int rtval;
+    unsigned int val;		//6996i
+    unsigned int control[6] ;	//6996i
+    unsigned int status[6] ;	//6996i
+
+	// printk ("adm_process_mac_table_request: enter\n");	
+
+    control[0]=(mMACENTRY->mac_addr[1]<<8)+mMACENTRY->mac_addr[0]     ; 
+    control[1]=(mMACENTRY->mac_addr[3]<<8)+mMACENTRY->mac_addr[2]      ;         
+    control[2]=(mMACENTRY->mac_addr[5]<<8)+mMACENTRY->mac_addr[4]     ;
+    control[3]=(mMACENTRY->fid&0xf)+((mMACENTRY->portmap&0x3f)<<4);
+
+    if (((mMACENTRY->info_type)&0x01)) control[4]=(mMACENTRY->ctrl.info_ctrl)+0x1000; //static ,info control
+   		else	control[4]=((mMACENTRY->ctrl.age_timer)&0xff);//not static ,agetimer
+        	if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT) { 	
+	          //initial  the pointer to the first address	
+	           val=0x8000;//busy ,status5[15]
+	           while(val&0x8000){		//check busy ?
+	           ifx_sw_read(0x125, &val);
+	       	}    
+	        control[5]=0x030;//initial the first address	
+	        ifx_sw_write(0x11f,control[5]);
+			        	       	
+			           	
+			           val=0x8000;//busy ,status5[15]
+			           while(val&0x8000){		//check busy ?
+			 	          ifx_sw_read(0x125, &val);
+			        	}           	
+	           	
+	           }	//if (cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)								
+           if (cmd==ADM_SW_IOCTL_MACENTRY_ADD) control[5]=0x07;//create a new address
+           	else if (cmd==ADM_SW_IOCTL_MACENTRY_DEL) control[5]=0x01f;//erased an existed address
+           	else if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) 
+           		control[5]=0x02c;//search by the mac address field
+           
+           val=0x8000;//busy ,status5[15]
+           while(val&0x8000){		//check busy ?
+ 	          ifx_sw_read(0x125, &val);
+        	}
+        	ifx_sw_write(0x11a,control[0]);	
+        	ifx_sw_write(0x11b,control[1]);	
+        	ifx_sw_write(0x11c,control[2]);	
+        	ifx_sw_write(0x11d,control[3]);	
+        	ifx_sw_write(0x11e,control[4]);	
+        	ifx_sw_write(0x11f,control[5]);	
+           val=0x8000;//busy ,status5[15]
+           while(val&0x8000){		//check busy ?
+ 	          ifx_sw_read(0x125, &val);
+        	}	
+           val=((val&0x7000)>>12);//result ,status5[14:12]
+           mMACENTRY->result=val;
+   
+           if (!val) {
+        		printk(" Command OK!! \n");
+        		if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) {
+			           	ifx_sw_read(0x120,&(status[0]));	
+			        	ifx_sw_read(0x121,&(status[1]));	
+			        	ifx_sw_read(0x122,&(status[2]));	
+			        	ifx_sw_read(0x123,&(status[3]));	
+			        	ifx_sw_read(0x124,&(status[4]));	
+			        	ifx_sw_read(0x125,&(status[5]));	
+		
+		           		
+		        		mMACENTRY->mac_addr[0]=(status[0]&0x00ff)	;
+		        		mMACENTRY->mac_addr[1]=(status[0]&0xff00)>>8    ;
+		        		mMACENTRY->mac_addr[2]=(status[1]&0x00ff)    ;
+		        		mMACENTRY->mac_addr[3]=(status[1]&0xff00)>>8 ;
+		        		mMACENTRY->mac_addr[4]=(status[2]&0x00ff)    ;
+		        		mMACENTRY->mac_addr[5]=(status[2]&0xff00)>>8 ;
+		        		mMACENTRY->fid=(status[3]&0xf);
+		        		mMACENTRY->portmap=((status[3]>>4)&0x3f);
+		        		if (status[5]&0x2) {//static info_ctrl //status5[1]????
+		        			mMACENTRY->ctrl.info_ctrl=(status[4]&0x00ff);
+		  				mMACENTRY->info_type=1;
+		        				}
+		        		else {//not static age_timer
+		        			mMACENTRY->ctrl.age_timer=(status[4]&0x00ff);
+		  				mMACENTRY->info_type=0;
+		        				}
+//status5[13]????					mMACENTRY->occupy=(status[5]&0x02)>>1;//status5[1]
+					mMACENTRY->occupy=(status[5]&0x02000)>>13;//status5[13] ???
+					mMACENTRY->bad=(status[5]&0x04)>>2;//status5[2]
+				}//if ((cmd==ADM_SW_IOCTL_MACENTRY_GET_INIT)||(cmd==ADM_SW_IOCTL_MACENTRY_GET_MORE)) 
+			
+        	}
+           else if (val==0x001)  
+                printk(" All Entry Used!! \n");
+            else if (val==0x002) 
+                printk("  Entry Not Found!! \n");
+            else if (val==0x003) 
+                printk(" Try Next Entry!! \n");
+            else if (val==0x005)  
+                printk(" Command Error!! \n");   
+            else   
+                printk(" UnKnown Error!! \n");
+
+	// printk ("adm_process_mac_table_request: Exit\n");	
+	return 0;
+}
+
+/* Santosh: End of function for MAC ENTRY ADD/DEL*/
+struct file_operations adm_ops =
+{
+    read: adm_read,
+    write: adm_write,
+    open: adm_open,
+    release: adm_release,
+    ioctl: adm_ioctl
+};
+
+int adm_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data)
+{
+    int len = 0;
+
+    len += sprintf(buf+len, " ************ Registers ************ \n");
+    *eof = 1;
+    return len;
+}
+
+int __init init_adm6996_module(void)
+{
+    unsigned int val = 000;
+    unsigned int val1 = 000;
+
+    printk("Loading ADM6996 driver... \n");
+
+    /* if running on adm5120 */
+    /* set GPIO 0~2 as adm6996 control pins */
+    //outl(0x003f3f00, 0x12000028);
+    /* enable switch port 5 (MII) as RMII mode (5120MAC <-> 6996MAC) */
+    //outl(0x18a, 0x12000030);
+    /* group adm5120 port 1 ~ 5 as VLAN0, port 5 & 6(CPU) as VLAN1 */
+    //outl(0x417e, 0x12000040);
+    /* end adm5120 fixup */
+#ifdef ADM6996_MDC_MDIO_MODE //smi mode //000001.joelin
+    register_chrdev(69, "adm6996", &adm_ops);
+    AMAZON_SW_REG(AMAZON_SW_MDIO_CFG) = 0x27be;
+    AMAZON_SW_REG(AMAZON_SW_EPHY) = 0xfc;
+    adm6996_mode=adm6996i;
+    ifx_sw_read(0xa0, &val);
+    ifx_sw_read(0xa1, &val1);
+    val=((val1&0x0f)<<16)|val;
+    printk ("\nADM6996 SMI Mode-");
+    printk ("Chip ID:%5x \n ", val);
+#else    //000001.joelin
+ 
+    AMAZON_SW_REG(AMAZON_SW_MDIO_CFG) = 0x2c50;
+    AMAZON_SW_REG(AMAZON_SW_EPHY) = 0xff;
+
+    AMAZON_SW_REG(AMAZON_GPIO_P1_ALTSEL0) &= ~(GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
+    AMAZON_SW_REG(AMAZON_GPIO_P1_ALTSEL1) &= ~(GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
+    AMAZON_SW_REG(AMAZON_GPIO_P1_OD) |= (GPIO_MDIO|GPIO_MDCS|GPIO_MDC);
+  
+    ifx_gpio_init();
+    register_chrdev(69, "adm6996", &adm_ops);
+    mdelay(100);
+
+    /* create proc entries */
+    //  create_proc_read_entry("admide", 0, NULL, admide_proc, NULL);
+
+//joelin adm6996i support start
+    adm6996_mode=adm6996i;
+    ifx_sw_read(0xa0, &val);
+    adm6996_mode=adm6996l;
+    ifx_sw_read(0x200, &val1);
+//  printk ("\n %0x \n",val1);
+    if ((val&0xfff0)==0x1020) {
+        printk ("\n ADM6996I .. \n");
+        adm6996_mode=adm6996i;	
+    }
+    else if ((val1&0xffffff00)==0x71000) {//71010 or 71020
+        printk ("\n ADM6996LC .. \n");
+        adm6996_mode=adm6996lc;	
+    }
+    else  {
+        printk ("\n ADM6996L .. \n");
+        adm6996_mode=adm6996l;	
+    }
+#endif //ADM6996_MDC_MDIO_MODE //smi mode //000001.joelin	
+
+    if ((adm6996_mode==adm6996lc)||(adm6996_mode==adm6996i)){
+#if 0	/* removed by MarsLin */
+        ifx_sw_write(0x29,0xc000);
+        ifx_sw_write(0x30,0x0985);
+#else
+        ifx_sw_read(0xa0, &val);
+        if (val == 0x1021) // for both 6996LC and 6996I, only AB version need the patch
+            ifx_sw_write(0x29, 0x9000);
+        ifx_sw_write(0x30,0x0985);
+#endif
+    }
+//joelin adm6996i support end
+    return 0;
+}
+
+void __exit cleanup_adm6996_module(void)
+{
+    printk("Free ADM device driver... \n");
+
+    unregister_chrdev(69, "adm6996");
+
+    /* remove proc entries */
+    //  remove_proc_entry("admide", NULL);
+}
+
+/* MarsLin, add start */
+#if defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT) || defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT_MODULE)
+    #define SET_BIT(reg, mask)		reg |= (mask)
+    #define CLEAR_BIT(reg, mask)	reg &= (~mask)
+    static int ifx_hw_reset(void)
+    {
+        CLEAR_BIT((*AMAZON_GPIO_P0_ALTSEL0),0x2000);
+        CLEAR_BIT((*AMAZON_GPIO_P0_ALTSEL1),0x2000);
+        SET_BIT((*AMAZON_GPIO_P0_OD),0x2000);
+        SET_BIT((*AMAZON_GPIO_P0_DIR), 0x2000);
+	CLEAR_BIT((*AMAZON_GPIO_P0_OUT), 0x2000);
+	mdelay(500);
+	SET_BIT((*AMAZON_GPIO_P0_OUT), 0x2000);
+        cleanup_adm6996_module();
+        return init_adm6996_module();
+    }
+    int (*adm6996_hw_reset)(void) = ifx_hw_reset;
+    EXPORT_SYMBOL(adm6996_hw_reset);
+    EXPORT_SYMBOL(adm6996_mode);
+    int (*adm6996_sw_read)(unsigned int addr, unsigned int *data) = ifx_sw_read;
+    EXPORT_SYMBOL(adm6996_sw_read);
+    int (*adm6996_sw_write)(unsigned int addr, unsigned int data) = ifx_sw_write;
+    EXPORT_SYMBOL(adm6996_sw_write);
+#endif
+/* MarsLin, add end */
+
+/* Santosh: for IGMP proxy/snooping, Begin */
+EXPORT_SYMBOL (adm_process_mac_table_request);
+EXPORT_SYMBOL (adm_process_protocol_filter_request);
+/* Santosh: for IGMP proxy/snooping, End */
+	
+MODULE_DESCRIPTION("ADMtek 6996 Driver");
+MODULE_AUTHOR("Joe Lin <joe.lin@infineon.com>");
+MODULE_LICENSE("GPL");
+
+module_init(init_adm6996_module);
+module_exit(cleanup_adm6996_module);
+
+

--- /dev/null
+++ b/target/linux/amazon-2.6/files/drivers/char/amazon_mei.c
@@ -1,1 +1,7919 @@
-
+/* ============================================================================
+ * Copyright (C) 2004 -Infineon Technologies AG.
+ *
+ * All rights reserved.
+ * ============================================================================
+ *
+ *============================================================================
+ * Licensed under GNU GPL v2
+ * ============================================================================
+ */
+
+ 
+/* ===========================================================================
+ *
+ * File Name:   amazon_mei.c
+ * Author :     Ou Ke
+ *
+ * ===========================================================================
+ *
+ * Project: Amazon
+ *
+ * ===========================================================================
+ * Contents:This file implements the MEI driver for Amazon ADSL/ADSL2+
+ *  controller.
+ *  
+ * ===========================================================================
+ * References: 
+ *
+ */
+
+
+/* ===========================================================================
+ * Revision History:
+ * 		12/1/2005 : Ritesh Banerjee
+ * 			- Create a kernel thread kmibpoll to poll for periodic RFC 2662
+ * 			and RFC 3440 counters. Removes the need for user space 
+ * 			adsl_mibpoll_daemon and saves atleast 30KB of RAM.
+ *
+ * $Log$
+ * ===========================================================================
+ */
+
+/*
+ * ===========================================================================
+ *                           INCLUDE FILES
+ * ===========================================================================
+ */
+//000002:fchang 2005/6/2 joelin 04/27/2005 for pcm clock
+//000003:fchang 2005/6/2 Henry added for Amazon-E support
+//165001:henryhsu 2005/9/6 Modify for adsl firmware version 1.2.1.2.0.1 DATA_LED can't flash.
+// 509221:tc.chen 2005/09/22 Reset DFE added when MEI_TO_ARC_CS_DONE not cleared by ARC
+// 603221:tc.chen 2006/03/21 added APIs to support the WEB related parameters for ADSL Statistics
+
+#ifndef EXPORT_SYMTAB
+#define EXPORT_SYMTAB
+#endif
+#define AMAZON_MEI_MIB_RFC3440
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>               
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <asm/irq.h>
+#include <asm/segment.h>
+#include <asm/semaphore.h>
+#include <linux/init.h>                                  
+#include <linux/ioport.h>
+#include <asm/uaccess.h>                       
+#include <linux/proc_fs.h>
+#include <asm/io.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/list.h>
+#include <linux/time.h>
+
+#include <asm/amazon/amazon.h>
+#include <asm/irq.h>
+#include <asm/amazon/irq.h>
+#include <asm/amazon/amazon_mei.h>
+#include <asm/amazon/amazon_mei_app.h>
+#include <asm/amazon/amazon_mei_ioctl.h>
+#include <asm/amazon/amazon_mei_app_ioctl.h>
+
+#define SET_BIT(reg, mask)                  reg |= (mask)
+#define CLEAR_BIT(reg, mask)                reg &= (~mask)
+#define CLEAR_BITS(reg, mask)               CLEAR_BIT(reg, mask)
+#define SET_BITS(reg, mask)                 SET_BIT(reg, mask)
+#define SET_BITFIELD(reg, mask, off, val)   {reg &= (~mask); reg |= (val << off);}
+
+extern void mask_and_ack_amazon_irq(unsigned int irq_nr);
+
+#ifdef AMAZON_CHECK_LINK
+//amazon_tpe.c
+extern int (*adsl_link_notify)(int);
+#endif //AMAZON_CHECK_LINK
+
+// for ARC memory access
+#define WHILE_DELAY 20000
+#define AMAZON_DMA_DEBUG_MUTEX
+
+
+//TODO
+#undef DFE_LOOPBACK
+#define ARC_READY_ACK
+
+static amazon_mei_mib * current_intvl;
+static struct list_head interval_list;
+static amazon_mei_mib * mei_mib;
+
+static int reboot_firsttime=1;//000002:fchang
+
+	//PCM
+#define PCM_CHANNEL_NUM		2	//1 rx, 1 tx
+static pcm_data_struct	pcm_data[PCM_CHANNEL_NUM]__attribute__ ((aligned(4)));	//0=tx0, 1=rx0, 2=tx1, 3=rx1
+static u32 pcm_start_addr;
+//#define PCM_HRT_TIME_HZ		4000	//?us
+#define PCM_ACCESS_DEBUG
+static int irqtimes=0;
+#undef DATA_LED_ON_MODE
+#define ADSL_LED_SUPPORT	//joelin for adsl led
+#ifdef ADSL_LED_SUPPORT
+static int firmware_support_led=0; //joelin version check 	for adsl led	
+static int stop_led_module=0;	//wakeup and clean led module
+static int led_support_check=0;	//1.1.2.7.1.1
+#endif //ADSL_LED_SUPPORT
+#define IFX_DYING_GASP
+#ifdef IFX_DYING_GASP
+static wait_queue_head_t wait_queue_dying_gasp;	//dying gasp
+//struct tq_struct dying_gasp_task; 		//dying gasp
+static wait_queue_head_t wait_queue_uas_poll;	//joelin 04/16/2005
+static u16 unavailable_seconds=0;		//joelin 04/16/2005
+static meidebug lop_debugwr;				//dying gasp
+#endif //IFX_DYING_GASP
+static int dbg_int=0;
+//#define DEBUG_ACCESS_DELAY	for(dbg_int=0;dbg_int<100;dbg_int++){;}
+#define DEBUG_ACCESS_DELAY
+static u8 sampledata[512];
+static int firsttime[PCM_CHANNEL_NUM]={0,1};
+static int num_cmp[PCM_CHANNEL_NUM]={0,0};
+static int pcm_start_loc[PCM_CHANNEL_NUM]={0,0}; 
+
+	// for clearEoC 
+//#define MEI_CLREOC_BUFF_SIZE	512	//double the receive fifo size, bytes
+//static u8 clreoc[MEI_CLREOC_BUFF_SIZE]__attribute__ ((aligned(4)));	//buffer to hold clearEoC data in bytes
+#undef AMAZON_CLEAR_EOC
+#ifdef AMAZON_CLEAR_EOC
+extern void ifx_push_eoc(struct sk_buff * pkt);
+#endif
+static int meiResetArc(void); 
+#define IFX_POP_EOC_DONE	0
+#define IFX_POP_EOC_FAIL	-1
+static struct list_head clreoc_list;
+static amazon_clreoc_pkt * clreoc_pkt;
+#define CLREOC_BUFF_SIZE	12	//number of clreoc commands being buffered
+//static int clreoc_wr=0;
+//static int clreoc_rd=0;		//used to control clreoc circular buffer 
+static wait_queue_head_t wait_queue_clreoc;
+#ifdef ADSL_LED_SUPPORT
+static wait_queue_head_t wait_queue_led;	//adsl led
+static wait_queue_head_t wait_queue_led_polling;// adsl led
+struct tq_struct led_task; 			// adsl led
+static DECLARE_TASK_QUEUE(tq_ifx_led);		// task
+int adsl_led_flash_task(void *ptr);		// adsl led
+#endif	//ADSL_LED_SUPPORT
+static void * clreoc_command_pkt=NULL;
+static int clreoc_max_tx_len=0;
+
+// 603221:tc.chen start
+#define ME_HDLC_IDLE 0
+#define ME_HDLC_INVALID_MSG 1
+#define ME_HDLC_MSG_QUEUED 2
+#define ME_HDLC_MSG_SENT 3
+#define ME_HDLC_RESP_RCVD 4
+#define ME_HDLC_RESP_TIMEOUT 5
+#define ME_HDLC_RX_BUF_OVERFLOW 6
+#define ME_HDLC_UNRESOLVED 1
+#define ME_HDLC_RESOLVED 2
+// 603221:tc.chen end
+
+#ifdef LOCK_RETRY
+static int reboot_lock=0;
+#endif
+
+static mib_previous_read mib_pread={0,0,0,0,0,0,0,0,0,0,0,0};
+static mib_flags_pretime mib_pflagtime;// initialized when module loaded
+
+	static u32 ATUC_PERF_LOFS=0;
+	static u32 ATUC_PERF_LOSS=0;
+	static u32 ATUC_PERF_ESS=0;
+	static u32 ATUC_PERF_INITS=0;
+	static u32 ATUR_PERF_LOFS=0;
+	static u32 ATUR_PERF_LOSS=0;
+	static u32 ATUR_PERF_LPR=0;
+	static u32 ATUR_PERF_ESS=0;
+	static u32 ATUR_CHAN_RECV_BLK=0;
+	static u32 ATUR_CHAN_TX_BLK=0;
+	static u32 ATUR_CHAN_CORR_BLK=0;
+	static u32 ATUR_CHAN_UNCORR_BLK=0;
+	//RFC-3440
+	static u32 ATUC_PERF_STAT_FASTR=0;
+	static u32 ATUC_PERF_STAT_FAILED_FASTR=0;
+	static u32 ATUC_PERF_STAT_SESL=0;
+	static u32 ATUC_PERF_STAT_UASL=0;
+	static u32 ATUR_PERF_STAT_SESL=0;
+	static u32 ATUR_PERF_STAT_UASL=0;
+
+	static adslChanPrevTxRate PrevTxRate={0,0};
+	static adslPhysCurrStatus CurrStatus={0,0};
+	static ChanType chantype={0,0};
+	static adslLineAlarmConfProfileEntry AlarmConfProfile={"No Name\0",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
+// 603221:tc.chen start
+	static adslFarEndPerfStats FarendStatsData;
+	struct timeval FarendData_acquire_time={0};
+	static u32 adsl_mode,adsl_mode_extend; // adsl mode : adsl/ 2/ 2+
+	static adslInitStats AdslInitStatsData;
+//603221:tc.chen end
+static u32 loop_diagnostics_mode=0;
+static wait_queue_head_t wait_queue_loop_diagnostic;
+#ifdef AMAZON_MEI_MIB_RFC3440
+	static adslLineAlarmConfProfileExtEntry AlarmConfProfileExt={"No Name\0",0,0,0,0,0,0};
+#endif
+
+static int showtime=0;
+static int loop_diagnostics_completed=0;
+//////////////////////////////////////////////////////////////////////////////////
+static int phy_mei_net_init(struct net_device * dev);
+static int interleave_mei_net_init(struct net_device * dev);
+static int fast_mei_net_init(struct net_device * dev);
+static struct net_device_stats * phy_mei_net_get_stats(struct net_device * dev);
+static struct net_device_stats * interleave_mei_net_get_stats(struct net_device * dev);
+static struct net_device_stats * fast_mei_net_get_stats(struct net_device * dev);
+
+typedef struct mei_priv{
+        struct net_device_stats stats;
+}mei_priv;
+
+static struct net_device phy_mei_net = { init: phy_mei_net_init, name: "MEI_PHY"};
+static struct net_device interleave_mei_net = { init: interleave_mei_net_init, name: "MEI_INTL"};
+static struct net_device fast_mei_net = { init: fast_mei_net_init, name: "MEI_FAST"};
+///////////////////////////////////////////////////////////////////////////////////
+
+static int major=AMAZON_MEI_MAJOR;
+
+static struct semaphore mei_sema;
+
+// Mei to ARC CMV count, reply count, ARC Indicator count
+static int indicator_count=0;
+static int cmv_count=0;
+static int reply_count=0;
+static u16 Recent_indicator[MSG_LENGTH];
+
+// Used in interrupt handler as flags
+static int arcmsgav=0;
+static int cmv_reply=0;
+static int cmv_waiting=0;
+
+#define PROC_ITEMS 8
+
+long mei_debug_mode = 0; //509221:tc.chen for adsl firmware debug
+
+//  to wait for arc cmv reply, sleep on wait_queue_arcmsgav;
+static wait_queue_head_t wait_queue_arcmsgav;
+static wait_queue_head_t wait_queue_codeswap;
+static wait_queue_head_t wait_queue_mibdaemon;
+static wait_queue_head_t wait_queue_reboot;
+static u32 * image_buffer=NULL;        	// holding adsl firmware image
+static u16 RxMessage[MSG_LENGTH]__attribute__ ((aligned(4)));
+static u16 TxMessage[MSG_LENGTH]__attribute__ ((aligned(4)));                                                                                                               
+static u32 * mei_arc_swap_buff=NULL;   	//  holding swap pages
+static ARC_IMG_HDR * img_hdr;
+static int reboot_flag;
+
+#ifdef DFE_LOOPBACK
+#include "arc_pm.h"
+#endif
+
+
+/////////////////               net device                              ///////////////////////////////////////////////////
+static int phy_mei_net_init(struct net_device * dev)
+{
+        //ether_setup(dev);
+        dev->get_stats = phy_mei_net_get_stats;
+        dev->ip_ptr = NULL;
+	dev->type = 94;
+	
+//	dev->mtu=12345;
+	dev->flags=IFF_UP;
+	
+        dev->priv = kmalloc(sizeof(struct mei_priv), GFP_KERNEL);
+        if(dev->priv == NULL)
+                return -ENOMEM;
+        memset(dev->priv, 0, sizeof(struct mei_priv));
+        return 0;
+}
+
+static int interleave_mei_net_init(struct net_device * dev)
+{
+        //ether_setup(dev);
+        dev->get_stats = interleave_mei_net_get_stats;
+        dev->ip_ptr = NULL;
+	dev->type = 124;
+	dev->flags=IFF_UP;
+        dev->priv = kmalloc(sizeof(struct mei_priv), GFP_KERNEL);
+        if(dev->priv == NULL)
+                return -ENOMEM;
+        memset(dev->priv, 0, sizeof(struct mei_priv));
+        return 0;
+}
+
+static int fast_mei_net_init(struct net_device * dev)
+{
+        //ether_setup(dev);
+        dev->get_stats = fast_mei_net_get_stats;
+        dev->ip_ptr = NULL;
+	dev->type = 125;
+	dev->flags=IFF_UP;
+        dev->priv = kmalloc(sizeof(struct mei_priv), GFP_KERNEL);
+        if(dev->priv == NULL)
+                return -ENOMEM;
+        memset(dev->priv, 0, sizeof(struct mei_priv));
+        return 0;
+}
+
+static struct net_device_stats * phy_mei_net_get_stats(struct net_device * dev)
+{
+        struct mei_priv * priv;
+        priv = (struct mei_priv *)dev->priv;
+	// update statistics
+	(priv->stats).rx_packets = ATUR_CHAN_RECV_BLK;
+	(priv->stats).tx_packets = ATUR_CHAN_TX_BLK;
+	(priv->stats).rx_errors = ATUR_CHAN_CORR_BLK + ATUR_CHAN_UNCORR_BLK;
+	(priv->stats).rx_dropped = ATUR_CHAN_UNCORR_BLK;
+	
+        return &(priv->stats);
+}
+
+static struct net_device_stats * interleave_mei_net_get_stats(struct net_device * dev)
+{
+        struct mei_priv * priv;
+        priv = (struct mei_priv *)dev->priv;
+	// update statistics
+	(priv->stats).rx_packets = ATUR_CHAN_RECV_BLK;
+	(priv->stats).tx_packets = ATUR_CHAN_TX_BLK;
+	(priv->stats).rx_errors = ATUR_CHAN_CORR_BLK + ATUR_CHAN_UNCORR_BLK;
+	(priv->stats).rx_dropped = ATUR_CHAN_UNCORR_BLK;
+	
+        return &(priv->stats);
+}
+
+static struct net_device_stats * fast_mei_net_get_stats(struct net_device * dev)
+{
+        struct mei_priv * priv;
+        priv = (struct mei_priv *)dev->priv;
+	// update statistics
+	(priv->stats).rx_packets = ATUR_CHAN_RECV_BLK;
+	(priv->stats).tx_packets = ATUR_CHAN_TX_BLK;
+	(priv->stats).rx_errors = ATUR_CHAN_CORR_BLK + ATUR_CHAN_UNCORR_BLK;
+	(priv->stats).rx_dropped = ATUR_CHAN_UNCORR_BLK;
+	
+        return &(priv->stats);
+}
+/////////////////               mei access Rd/Wr methods       ///////////////////////////////////////////////////
+void meiLongwordWrite(u32 ul_address, u32 ul_data)
+{
+	*((volatile u32 *)ul_address) = ul_data;
+	asm("SYNC");
+	return;
+} //	end of "meiLongwordWrite(..."
+
+void meiLongwordRead(u32 ul_address, u32 *pul_data)
+{
+	*pul_data = *((volatile u32 *)ul_address);
+	asm("SYNC");
+	return;
+} //	end of "meiLongwordRead(..."
+
+MEI_ERROR meiDMAWrite(u32 destaddr, u32 *databuff, u32 databuffsize)
+{
+	u32 *p = databuff;
+	u32 temp;
+	u32 flags;
+
+	if( destaddr & 3)
+		return MEI_FAILURE;
+
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	save_flags(flags);
+	cli();
+#endif
+		
+
+	//	Set the write transfer address
+	meiLongwordWrite(MEI_XFR_ADDR, destaddr);
+
+	//	Write the data pushed across DMA
+	while (databuffsize--)
+	{
+		temp = *p;
+		if(databuff==(u32 *)TxMessage)	// swap half word
+			temp = ((temp & 0xffff)<<16) + ((temp & 0xffff0000)>>16);
+		meiLongwordWrite(MEI_DATA_XFR, temp);
+		p++;
+	} // 	end of "while(..."
+
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	restore_flags(flags);	
+#endif
+	
+	return MEI_SUCCESS;
+
+} //	end of "meiDMAWrite(..."
+
+MEI_ERROR meiDMAWrite_16(u32 destaddr, u32 *databuff, u32 databuffsize)
+{
+	u32 *p = databuff;
+	u32 temp;
+	u32 flags;
+
+	if( destaddr & 3)
+		return MEI_FAILURE;
+		
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	save_flags(flags);
+	cli();
+#endif
+		
+
+	//	Set the write transfer address
+	meiLongwordWrite(MEI_XFR_ADDR, destaddr);
+
+	//	Write the data pushed across DMA
+	while (databuffsize--)
+	{
+		temp = *p;
+		temp = ((temp & 0xffff)<<16) + ((temp & 0xffff0000)>>16);//swap half word
+		meiLongwordWrite(MEI_DATA_XFR, temp);
+		p++;
+	} // 	end of "while(..."
+	
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	restore_flags(flags);
+#endif
+
+	return MEI_SUCCESS;
+
+} //	end of "meiDMAWrite_16(..."
+
+MEI_ERROR meiDMAWrite_8(u32 destaddr, u32 *databuff, u32 databuffsize)
+{
+	u32 *p = databuff;
+	u32 temp;
+	u32 flags;
+
+	if( destaddr & 3)
+		return MEI_FAILURE;
+		
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	save_flags(flags);
+	cli();
+#endif
+		
+
+	//	Set the write transfer address
+	meiLongwordWrite(MEI_XFR_ADDR, destaddr);
+
+	//	Write the data pushed across DMA
+	while (databuffsize--)
+	{
+		temp = *p;
+		temp = ((temp & 0xff)<<24) + ((temp & 0xff00)<<8)+ ((temp & 0xff0000)>>8)+ ((temp & 0xff000000)>>24);//swap byte
+		meiLongwordWrite(MEI_DATA_XFR, temp);
+		p++;
+	} // 	end of "while(..."
+	
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	restore_flags(flags);
+#endif
+
+	return MEI_SUCCESS;
+
+} //	end of "meiDMAWrite_8(..."
+
+MEI_ERROR meiDMARead(u32 srcaddr, u32 *databuff, u32 databuffsize)
+{
+	u32 *p = databuff;
+	u32 temp;
+	u32 flags;
+	
+	if( srcaddr & 3)
+		return MEI_FAILURE;
+
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	save_flags(flags);
+	cli();
+#endif
+	
+
+	//	Set the read transfer address
+	meiLongwordWrite(MEI_XFR_ADDR, srcaddr);
+
+	//	Read the data popped across DMA
+	while (databuffsize--)
+	{
+		meiLongwordRead(MEI_DATA_XFR, &temp);
+		if(databuff==(u32 *)RxMessage)	// swap half word
+			temp = ((temp & 0xffff)<<16) + ((temp & 0xffff0000)>>16);
+		*p=temp;
+		p++;
+	} // 	end of "while(..."
+
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	restore_flags(flags);
+#endif
+
+	return MEI_SUCCESS;
+
+} //	end of "meiDMARead(..."
+
+MEI_ERROR meiDMARead_16(u32 srcaddr, u32 *databuff, u32 databuffsize)
+{
+	u32 *p = databuff;
+	u32 temp;
+	u32 flags;
+	
+	if( srcaddr & 3)
+		return MEI_FAILURE;
+		
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	save_flags(flags);
+	cli();
+#endif
+		
+
+	//	Set the read transfer address
+	meiLongwordWrite(MEI_XFR_ADDR, srcaddr);
+
+	//	Read the data popped across DMA
+	while (databuffsize--)
+	{
+		meiLongwordRead(MEI_DATA_XFR, &temp);
+		temp = ((temp & 0xffff)<<16) + ((temp & 0xffff0000)>>16);
+		*p=temp;
+		p++;
+	} // 	end of "while(..."
+	
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	restore_flags(flags);
+#endif
+
+	return MEI_SUCCESS;
+
+} //	end of "meiDMARead_16(..."
+
+MEI_ERROR meiDMARead_8(u32 srcaddr, u32 *databuff, u32 databuffsize)
+{
+	u32 *p = databuff;
+	u32 temp;
+	u32 flags;
+	
+	if( srcaddr & 3)
+		return MEI_FAILURE;
+		
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	save_flags(flags);
+	cli();
+#endif
+		
+
+	//	Set the read transfer address
+	meiLongwordWrite(MEI_XFR_ADDR, srcaddr);
+
+	//	Read the data popped across DMA
+	while (databuffsize--)
+	{
+		meiLongwordRead(MEI_DATA_XFR, &temp);
+		temp = ((temp & 0xff)<<24) + ((temp & 0xff00)<<8)+ ((temp & 0xff0000)>>8)+ ((temp & 0xff000000)>>24);//swap byte
+		*p=temp;
+		p++;
+	} // 	end of "while(..."
+	
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	restore_flags(flags);
+#endif
+
+	return MEI_SUCCESS;
+
+} //	end of "meiDMARead_8(..."
+
+void meiPollForDbgDone(void)
+{
+	u32	query = 0;
+	int 	i=0;
+	while (i<WHILE_DELAY)
+	{
+		meiLongwordRead(ARC_TO_MEI_INT, &query);
+		query &= (ARC_TO_MEI_DBG_DONE);
+		if(query)
+			break;
+		i++;
+		if(i==WHILE_DELAY){
+#ifdef AMAZON_MEI_DEBUG_ON
+			printk("\n\n PollforDbg fail");
+#endif
+		}
+			DEBUG_ACCESS_DELAY;
+	} 
+   	meiLongwordWrite(ARC_TO_MEI_INT,  ARC_TO_MEI_DBG_DONE);  // to clear this interrupt
+} //	end of "meiPollForDbgDone(..."
+
+MEI_ERROR meiDebugWrite_8(u32 destaddr, u32 *databuff, u32 databuffsize)
+{
+	u32 i;
+	u32 temp = 0x0;
+	u32 address = 0x0;
+	u32 *buffer = 0x0;
+	u32 flags;
+	
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	save_flags(flags);
+	cli();
+#endif
+	
+
+	//	Open the debug port before DMP memory write
+	meiLongwordRead(MEI_CONTROL, &temp);
+		DEBUG_ACCESS_DELAY;	
+	temp |= (HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, temp);
+		DEBUG_ACCESS_DELAY;
+	meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP1_MASK);
+		DEBUG_ACCESS_DELAY;
+
+	//	For the requested length, write the address and write the data
+	address = destaddr;
+	buffer = databuff;
+	for (i=0; i < databuffsize; i++)
+	{
+		meiLongwordWrite(MEI_DEBUG_WAD, address);
+			DEBUG_ACCESS_DELAY;
+		temp=*buffer;
+		temp = ((temp & 0xff)<<24) + ((temp & 0xff00)<<8)+ ((temp & 0xff0000)>>8)+ ((temp & 0xff000000)>>24);//swap byte
+		meiLongwordWrite(MEI_DEBUG_DATA, temp);
+			DEBUG_ACCESS_DELAY;
+		meiPollForDbgDone();
+		address += 4;
+		buffer++;
+	} //	end of "for(..."
+
+	//	Close the debug port after DMP memory write
+	meiLongwordRead(MEI_CONTROL, &temp);
+		DEBUG_ACCESS_DELAY;
+	temp &= ~(HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, temp);
+		DEBUG_ACCESS_DELAY;
+		
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	restore_flags(flags);
+#endif
+
+	//	Return
+	return MEI_SUCCESS;
+
+} //	end of "meiDebugWrite_8(..."
+
+MEI_ERROR meiDebugRead_8(u32 srcaddr, u32 *databuff, u32 databuffsize)
+{
+	u32 i;
+	u32 temp = 0x0;
+	u32 address = 0x0;
+	u32 *buffer = 0x0;
+	u32 flags;
+	
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	save_flags(flags);
+	cli();
+#endif
+	
+
+	//	Open the debug port before DMP memory read
+	meiLongwordRead(MEI_CONTROL, &temp);
+		DEBUG_ACCESS_DELAY;
+	temp |= (HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, temp);
+		DEBUG_ACCESS_DELAY;
+	meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP2_MASK);
+		DEBUG_ACCESS_DELAY;
+
+	//	For the requested length, write the address and read the data
+	address = srcaddr;
+	buffer = databuff;
+	for (i=0; i<databuffsize; i++)
+	{
+		meiLongwordWrite(MEI_DEBUG_RAD, address);
+			DEBUG_ACCESS_DELAY;
+		meiPollForDbgDone();
+		meiLongwordRead(MEI_DEBUG_DATA, &temp);
+			DEBUG_ACCESS_DELAY;
+		temp = ((temp & 0xff)<<24) + ((temp & 0xff00)<<8)+ ((temp & 0xff0000)>>8)+ ((temp & 0xff000000)>>24);//swap byte
+		*buffer=temp;
+		address += 4;
+		buffer++;
+	} //	end of "for(..."
+
+	//	Close the debug port after DMP memory read
+	meiLongwordRead(MEI_CONTROL, &temp);
+		DEBUG_ACCESS_DELAY;
+	temp &= ~(HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, temp);
+		DEBUG_ACCESS_DELAY;
+		
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	restore_flags(flags);
+#endif
+
+	//	Return
+	return MEI_SUCCESS;
+
+} //	end of "meiDebugRead_8(..."
+
+MEI_ERROR meiDebugWrite_16(u32 destaddr, u32 *databuff, u32 databuffsize)
+{
+	u32 i;
+	u32 temp = 0x0;
+	u32 address = 0x0;
+	u32 *buffer = 0x0;
+	u32 flags;
+	
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	save_flags(flags);
+	cli();
+#endif
+	
+
+	//	Open the debug port before DMP memory write
+	meiLongwordRead(MEI_CONTROL, &temp);
+		DEBUG_ACCESS_DELAY;
+	temp |= (HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, temp);
+		DEBUG_ACCESS_DELAY;
+	meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP1_MASK);
+		DEBUG_ACCESS_DELAY;
+
+	//	For the requested length, write the address and write the data
+	address = destaddr;
+	buffer = databuff;
+	for (i=0; i < databuffsize; i++)
+	{
+		meiLongwordWrite(MEI_DEBUG_WAD, address);
+			DEBUG_ACCESS_DELAY;
+		temp=*buffer;
+		temp = ((temp & 0xffff)<<16) + ((temp & 0xffff0000)>>16);//swap half word
+		meiLongwordWrite(MEI_DEBUG_DATA, temp);
+			DEBUG_ACCESS_DELAY;
+		meiPollForDbgDone();
+		address += 4;
+		buffer++;
+	} //	end of "for(..."
+
+	//	Close the debug port after DMP memory write
+	meiLongwordRead(MEI_CONTROL, &temp);
+		DEBUG_ACCESS_DELAY;
+	temp &= ~(HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, temp);
+		DEBUG_ACCESS_DELAY;
+		
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	restore_flags(flags);
+#endif
+
+	//	Return
+	return MEI_SUCCESS;
+
+} //	end of "meiDebugWrite_16(..."
+
+MEI_ERROR meiDebugRead_16(u32 srcaddr, u32 *databuff, u32 databuffsize)
+{
+	u32 i;
+	u32 temp = 0x0;
+	u32 address = 0x0;
+	u32 *buffer = 0x0;
+	u32 flags;
+	
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	save_flags(flags);
+	cli();
+#endif
+	
+
+	//	Open the debug port before DMP memory read
+	meiLongwordRead(MEI_CONTROL, &temp);
+		DEBUG_ACCESS_DELAY;
+	temp |= (HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, temp);
+		DEBUG_ACCESS_DELAY;
+	meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP2_MASK);
+		DEBUG_ACCESS_DELAY;
+
+	//	For the requested length, write the address and read the data
+	address = srcaddr;
+	buffer = databuff;
+	for (i=0; i<databuffsize; i++)
+	{
+		meiLongwordWrite(MEI_DEBUG_RAD, address);
+			DEBUG_ACCESS_DELAY;
+		meiPollForDbgDone();
+		meiLongwordRead(MEI_DEBUG_DATA, &temp);
+			DEBUG_ACCESS_DELAY;
+		temp = ((temp & 0xffff)<<16) + ((temp & 0xffff0000)>>16);//swap half word
+		*buffer=temp;
+		address += 4;
+		buffer++;
+	} //	end of "for(..."
+
+	//	Close the debug port after DMP memory read
+	meiLongwordRead(MEI_CONTROL, &temp);
+		DEBUG_ACCESS_DELAY;
+	temp &= ~(HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, temp);
+		DEBUG_ACCESS_DELAY;
+		
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	restore_flags(flags);
+#endif
+
+	//	Return
+	return MEI_SUCCESS;
+
+} //	end of "meiDebugRead_16(..."
+
+MEI_ERROR meiDebugWrite(u32 destaddr, u32 *databuff, u32 databuffsize)
+{
+	u32 i;
+	u32 temp = 0x0;
+	u32 address = 0x0;
+	u32 *buffer = 0x0;
+	u32 flags;
+	
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	save_flags(flags);
+	cli();
+#endif
+	
+
+	//	Open the debug port before DMP memory write
+	meiLongwordRead(MEI_CONTROL, &temp);
+		DEBUG_ACCESS_DELAY;
+	temp |= (HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, temp);
+		DEBUG_ACCESS_DELAY;
+	meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP1_MASK);
+		DEBUG_ACCESS_DELAY;
+
+	//	For the requested length, write the address and write the data
+	address = destaddr;
+	buffer = databuff;
+	for (i=0; i < databuffsize; i++)
+	{
+		meiLongwordWrite(MEI_DEBUG_WAD, address);
+			DEBUG_ACCESS_DELAY;
+		temp=*buffer;
+		meiLongwordWrite(MEI_DEBUG_DATA, temp);
+			DEBUG_ACCESS_DELAY;
+		meiPollForDbgDone();
+		address += 4;
+		buffer++;
+	} //	end of "for(..."
+
+	//	Close the debug port after DMP memory write
+	meiLongwordRead(MEI_CONTROL, &temp);
+		DEBUG_ACCESS_DELAY;
+	temp &= ~(HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, temp);
+		DEBUG_ACCESS_DELAY;
+
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	restore_flags(flags);
+#endif
+
+	//	Return
+	return MEI_SUCCESS;
+
+} //	end of "meiDebugWrite(..."
+
+MEI_ERROR meiDebugRead(u32 srcaddr, u32 *databuff, u32 databuffsize)
+{
+	u32 i;
+	u32 temp = 0x0;
+	u32 address = 0x0;
+	u32 *buffer = 0x0;
+	u32 flags;
+	
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	save_flags(flags);
+	cli();
+#endif
+	
+
+	//	Open the debug port before DMP memory read
+	meiLongwordRead(MEI_CONTROL, &temp);
+		DEBUG_ACCESS_DELAY;
+	temp |= (HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, temp);
+		DEBUG_ACCESS_DELAY;
+	meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP2_MASK);
+		DEBUG_ACCESS_DELAY;
+
+	//	For the requested length, write the address and read the data
+	address = srcaddr;
+	buffer = databuff;
+	for (i=0; i<databuffsize; i++)
+	{
+		meiLongwordWrite(MEI_DEBUG_RAD, address);
+			DEBUG_ACCESS_DELAY;
+		meiPollForDbgDone();
+		meiLongwordRead(MEI_DEBUG_DATA, &temp);
+			DEBUG_ACCESS_DELAY;
+		*buffer=temp;
+		address += 4;
+		buffer++;
+	} //	end of "for(..."
+
+	//	Close the debug port after DMP memory read
+	meiLongwordRead(MEI_CONTROL, &temp);
+		DEBUG_ACCESS_DELAY;
+	temp &= ~(HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, temp);
+		DEBUG_ACCESS_DELAY;
+		
+#ifdef AMAZON_DMA_DEBUG_MUTEX
+	restore_flags(flags);
+#endif
+
+	//	Return
+	return MEI_SUCCESS;
+
+} //	end of "meiDebugRead(..."
+EXPORT_SYMBOL(meiDebugRead);
+
+void meiMailboxInterruptsDisable(void)
+{
+	meiLongwordWrite(ARC_TO_MEI_INT_MASK, 0x0);
+} //	end of "meiMailboxInterruptsDisable(..."
+
+void meiMailboxInterruptsEnable(void)
+{
+	meiLongwordWrite(ARC_TO_MEI_INT_MASK, MSGAV_EN); 
+} //	end of "meiMailboxInterruptsEnable(..."
+
+MEI_ERROR meiMailboxWrite(u16 *msgsrcbuffer, u16 msgsize)
+{
+	int i;
+	u32 arc_mailbox_status = 0x0;
+	u32 temp=0;
+	MEI_ERROR meiMailboxError = MEI_SUCCESS;
+
+	//	Check arc if mailbox write can be initiated
+/*	meiLongwordRead(MEI_TO_ARC_INT, &arc_mailbox_status);
+	if ((arc_mailbox_status & MEI_TO_ARC_MSGAV))
+	{
+		return MEI_MAILBOX_FULL;
+	}
+*/
+	//	Write to mailbox
+	meiMailboxError = meiDMAWrite(MEI_TO_ARC_MAILBOX, (u32*)msgsrcbuffer, msgsize/2);
+	meiMailboxError = meiDMAWrite(MEI_TO_ARC_MAILBOXR, (u32 *)(&temp), 1); 
+
+	//	Notify arc that mailbox write completed
+	cmv_waiting=1;
+	meiLongwordWrite(MEI_TO_ARC_INT, MEI_TO_ARC_MSGAV);
+	
+	i=0;
+        while(i<WHILE_DELAY){ // wait for ARC to clear the bit
+		meiLongwordRead(MEI_TO_ARC_INT, &arc_mailbox_status);
+		if((arc_mailbox_status & MEI_TO_ARC_MSGAV) != MEI_TO_ARC_MSGAV)
+			break;
+		i++;
+		if(i==WHILE_DELAY){
+#ifdef AMAZON_MEI_DEBUG_ON
+			printk("\n\n MEI_TO_ARC_MSGAV not cleared by ARC");
+#endif
+			meiMailboxError = MEI_FAILURE;
+#if 0			
+			for(i=0;i<msgsize;i++)
+				printk("\n %8x", (*(msgsrcbuffer+i)));
+#endif
+		}	
+	}      
+		
+	//	Return
+	return meiMailboxError;
+
+} //	end of "meiMailboxWrite(..."
+
+MEI_ERROR meiMailboxRead(u16 *msgdestbuffer, u16 msgsize)
+{
+	//u32 arc_mailbox_status = 0x0;
+	//u32 *mei_arc_msgbuff = 0x0;
+	MEI_ERROR meiMailboxError = MEI_SUCCESS;
+
+            /*
+            //	Check arc if mailbox read can be initiated
+	meiLongwordRead(ARC_TO_MEI_INT, &arc_mailbox_status);
+	if ((arc_mailbox_status & ARC_TO_MEI_MSGAV) == 0)
+	{
+		return MEI_MAILBOX_EMPTY;
+	} //	end of "if(..."
+            */
+            
+	//	Read from mailbox
+	meiMailboxError = meiDMARead(ARC_TO_MEI_MAILBOX, (u32*)msgdestbuffer, msgsize/2);
+
+	//	Notify arc that mailbox read completed
+	meiLongwordWrite(ARC_TO_MEI_INT, ARC_TO_MEI_MSGAV);
+
+	//	Return
+	return meiMailboxError;
+
+} //	end of "meiMailboxRead(..."
+
+MEI_ERROR meiHaltArc(void)
+{
+	u32 arc_control_mode = 0x0;
+	u32 arc_debug_addr = 0x5;
+	u32 arc_debug_data = 0x0;
+
+	//	Switch arc control from JTAG mode to MEI mode- write '1' to bit0
+	meiLongwordRead(MEI_CONTROL, &arc_control_mode);
+	arc_control_mode |= (HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, arc_control_mode);
+
+	//	Write arc aux reg access mask (0x0) into debug addr decode reg
+	meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_AUX_MASK);
+
+	//	Write arc debug reg addr (0x5) into debug read addr reg
+	meiLongwordWrite(MEI_DEBUG_RAD, arc_debug_addr);
+	meiPollForDbgDone();
+
+	//	Read debug data reg and save content
+	meiLongwordRead(MEI_DEBUG_DATA, &arc_debug_data);
+
+	//	Write arc debug reg addr (0x5) into debug write addr reg
+	meiLongwordWrite(MEI_DEBUG_WAD, arc_debug_addr);
+
+	//	Write debug data reg with content ORd with 0x2 (halt bit set)
+	arc_debug_data |= (BIT1);
+	meiLongwordWrite(MEI_DEBUG_DATA, arc_debug_data);
+       	meiPollForDbgDone();
+
+	//	Switch arc control from MEI mode to JTAG mode- write '0' to bit0
+	meiLongwordRead(MEI_CONTROL, &arc_control_mode);
+	arc_control_mode &= ~(HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, arc_control_mode);
+
+	//	Return
+	return MEI_SUCCESS;
+
+} //	end of "meiHalt(..."
+
+MEI_ERROR meiDownloadBootCode(void)
+{
+	u32 arc_control_mode;
+	u32 boot_loop;
+	u32 page_size;
+	u32 dest_addr;
+
+	u32 arc_debug_addr = 0x31F00;
+	u32 arc_debug_data = 0x10;
+	u32 temp;
+//	int i;
+
+	//MEI_ERROR meiDMAError = MEI_SUCCESS;
+
+	//	Disable mask for arc codeswap interrupts
+	meiMailboxInterruptsDisable();
+
+	//	Switch arc control from JTAG mode to MEI mode- write '1' to bit0
+	meiLongwordRead(MEI_CONTROL, &arc_control_mode);
+	arc_control_mode |= (HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, arc_control_mode);
+
+	//	Write (0x10) to CRI_CCR0(0x31F00) to enable ac_clk signal	
+	meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP1_MASK);
+	meiLongwordWrite(MEI_DEBUG_RAD, arc_debug_addr);
+	meiPollForDbgDone();
+	meiLongwordRead(MEI_DEBUG_DATA, &temp);
+	temp |=arc_debug_data;
+	
+	meiLongwordWrite(MEI_DEBUG_WAD, arc_debug_addr);
+	meiLongwordWrite(MEI_DEBUG_DATA, temp);
+        meiPollForDbgDone();
+            //meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_AUX_MASK);
+
+	//	Switch arc control from MEI mode to JTAG mode- write '0' to bit0
+	meiLongwordRead(MEI_CONTROL, &arc_control_mode);
+	arc_control_mode &= ~(HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, arc_control_mode);
+	
+#ifdef 	AMAZON_MEI_DEBUG_ON   //to test ac_clk setting correctness
+	meiLongwordRead(MEI_CONTROL, &arc_control_mode);
+	arc_control_mode |= (HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, arc_control_mode);
+	
+	meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP1_MASK);
+	meiLongwordWrite(MEI_DEBUG_RAD, arc_debug_addr);
+	meiPollForDbgDone();
+	meiLongwordRead(MEI_DEBUG_DATA, &arc_debug_data);
+
+	meiLongwordRead(MEI_CONTROL, &arc_control_mode);
+	arc_control_mode &= ~(HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, arc_control_mode);
+	
+//	printk("\n\n ac_clk is %8x\n", arc_debug_data);
+#endif
+
+	/*
+	**	DMA the boot code page(s)
+	*/
+#ifdef AMAZON_MEI_DEBUG_ON
+//	printk("\n\n start download pages");
+#endif
+	for( boot_loop = 0; boot_loop < img_hdr->count; boot_loop++)
+	{
+		if( img_hdr->page[boot_loop].p_size & BOOT_FLAG)
+		{
+			page_size = meiGetPage( boot_loop, GET_PROG, MAXSWAPSIZE, mei_arc_swap_buff, &dest_addr);
+			if( page_size > 0)
+			{
+				meiDMAWrite(dest_addr, mei_arc_swap_buff, page_size);
+			}
+		}
+		if( img_hdr->page[boot_loop].d_size & BOOT_FLAG)
+		{
+			page_size = meiGetPage( boot_loop, GET_DATA, MAXSWAPSIZE, mei_arc_swap_buff, &dest_addr);
+			if( page_size > 0)
+			{
+				meiDMAWrite( dest_addr, mei_arc_swap_buff, page_size);
+			}
+		}
+	}
+#ifdef AMAZON_MEI_DEBUG_ON
+//	printk("\n\n pages downloaded");
+#endif
+	return MEI_SUCCESS;
+
+} //	end of "meiDownloadBootCode(..."
+
+MEI_ERROR meiRunArc(void)
+{
+	u32 arc_control_mode = 0x0;
+	u32 arc_debug_addr = 0x0;
+	u32 arc_debug_data = 0x0;
+
+	//	Switch arc control from JTAG mode to MEI mode- write '1' to bit0
+	meiLongwordRead(MEI_CONTROL, &arc_control_mode);
+	arc_control_mode |= (HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, arc_control_mode);
+
+	//	Write arc aux reg access mask (0x0) into debug addr decode reg
+	meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_AUX_MASK);
+
+	//	Write arc status aux reg addr (0x0) into debug read addr reg
+	meiLongwordWrite(MEI_DEBUG_RAD, arc_debug_addr);
+	meiPollForDbgDone();
+
+	//	Read debug data reg and save content
+	meiLongwordRead(MEI_DEBUG_DATA, &arc_debug_data);
+
+	//	Write arc status aux reg addr (0x0) into debug write addr reg
+	meiLongwordWrite(MEI_DEBUG_WAD, arc_debug_addr);
+
+	//	Write debug data reg with content ANDd with 0xFDFFFFFF (halt bit cleared)
+	arc_debug_data &= ~(BIT25);
+	meiLongwordWrite(MEI_DEBUG_DATA, arc_debug_data);
+        meiPollForDbgDone();
+
+	//	Switch arc control from MEI mode to JTAG mode- write '0' to bit0
+	meiLongwordRead(MEI_CONTROL, &arc_control_mode);
+	arc_control_mode &= ~(HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, arc_control_mode);
+
+	//	Enable mask for arc codeswap interrupts
+	meiMailboxInterruptsEnable();
+
+	//	Return
+	return MEI_SUCCESS;
+
+} //	end of "meiActivate(..."
+
+int meiGetPage( u32 Page, u32 data, u32 MaxSize, u32 *Buffer, u32 *Dest)
+{
+	u32	size;
+	u32	i;
+	u32	*p;
+
+	if( Page > img_hdr->count)
+		return -2;
+
+	/*
+	**	Get program or data size, depending on "data" flag
+	*/
+	size = (data == GET_DATA) ? img_hdr->page[ Page].d_size : img_hdr->page[ Page].p_size;
+
+	size &= BOOT_FLAG_MASK; 	//	Clear boot bit!
+	if( size > MaxSize)
+		return -1;
+
+	if( size == 0)
+		return 0;
+	/*
+	**	Get program or data offset, depending on "data" flag
+	*/
+	i = data ? img_hdr->page[ Page].d_offset : img_hdr->page[ Page].p_offset;
+
+	/*
+	**	Copy data/program to buffer
+	*/
+
+	i /= 4;	//	Adjust offset for byte-to-UINT for array operation
+
+	p = (u32 *)img_hdr + i;
+	for(i = 0; i < size; i++)
+		Buffer[i] = *p++;
+	/*
+	**	Pass back data/program destination address
+	*/
+	*Dest = data ? img_hdr->page[Page].d_dest : img_hdr->page[Page].p_dest;
+
+	return size;
+}
+
+MEI_ERROR meiCMV(u16 * request, int reply)            // write cmv to arc, if reply needed, wait for reply
+{
+        MEI_ERROR meierror;
+        wait_queue_t wait;
+        
+        cmv_reply=reply;
+        
+        meierror = meiMailboxWrite(request, MSG_LENGTH);
+	
+        if(meierror != MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+                printk("\n\n MailboxWrite Fail.");
+#endif
+                return meierror;
+        }
+        else{
+                cmv_count++;
+	}
+
+        if(cmv_reply == NO_REPLY)
+                return MEI_SUCCESS;
+
+        init_waitqueue_entry(&wait, current);
+        add_wait_queue(&wait_queue_arcmsgav, &wait);
+        set_current_state(TASK_INTERRUPTIBLE);
+//	cmv_waiting=1;
+	
+        if(arcmsgav==1){
+                set_current_state(TASK_RUNNING);
+                remove_wait_queue(&wait_queue_arcmsgav, &wait);
+        }
+        else{
+                schedule_timeout(CMV_TIMEOUT);
+                remove_wait_queue(&wait_queue_arcmsgav, &wait);
+        }
+	if(arcmsgav==0){//CMV_timeout
+		cmv_waiting=0;
+		arcmsgav=0;
+#ifdef AMAZON_MEI_DEBUG_ON
+		printk("\nmeiCMV: MEI_MAILBOX_TIMEOUT\n");
+#endif
+		return MEI_MAILBOX_TIMEOUT; 	
+	}
+	else{
+        	arcmsgav=0;
+       	 	reply_count++;
+        	return MEI_SUCCESS;
+	}
+}
+
+//TODO, for loopback test
+#ifdef DFE_LOOPBACK
+#define mte_reg_base                    (0x4800*4+0x20000)
+ 
+/* Iridia Registers Address Constants */
+#define MTE_Reg(r)                              (int)(mte_reg_base + (r*4))
+ 
+#define IT_AMODE                                MTE_Reg(0x0004)
+
+
+#define OMBOX_BASE 0x15F80
+#define IMBOX_BASE 0x15FC0
+
+#define TIMER_DELAY   (1024)
+#define BC0_BYTES     (32)
+#define BC1_BYTES     (30)
+#define NUM_MB        (12)
+#define TIMEOUT_VALUE 2000
+
+void BFMWait (u32 cycle) {
+  u32 i;
+  for (i = 0 ; i< cycle ; i++); 
+}
+
+void WriteRegLong(u32 addr, u32 data){
+  //printk("[%8x] <= %8x \n\n", addr, data);
+  *((volatile u32 *)(addr)) =  data; 
+}
+
+u32 ReadRegLong (u32 addr) {
+  u32	rd_val;
+  
+  rd_val = *((volatile u32 *)(addr));
+  //printk("[%8x] => %8x \n\n", addr, rd_val);
+  return rd_val;
+
+}
+
+/* This routine writes the mailbox with the data in an input array */
+void WriteMbox(u32 *mboxarray,u32 size) {
+  u32 i;
+  
+  WriteRegLong(MEI_XFR_ADDR,IMBOX_BASE);
+  for (i=0;i<size;i++) {
+    WriteRegLong(MEI_DATA_XFR,*(mboxarray+i));
+  }
+}
+
+/* This routine reads the output mailbox and places the results into an array */
+void ReadMbox(u32 *mboxarray,u32 size) {
+  u32 i;
+  
+  WriteRegLong(MEI_XFR_ADDR,OMBOX_BASE);
+  for (i=0;i<size;i++) {
+    mboxarray[i] = ReadRegLong(MEI_DATA_XFR);
+  }
+}
+
+void MEIWriteARCValue(u32 address, u32 value)
+{
+  u32 i,check = 0;
+  /* Write address register */
+  *((volatile u32 *)MEI_DEBUG_WAD) =  address;
+
+  /* Write data register */
+  *((volatile u32 *)MEI_DEBUG_DATA) =  value;
+
+  /* wait until complete - timeout at 40*/
+  for (i=0;i<40;i++) {
+    check = *((volatile u32 *)ARC_TO_MEI_INT);
+    if ((check & 0x20)) break;
+    //printk("MEIWriteARCValue: check:%8x\n\n", check);
+    }
+
+  /* clear the flag */
+  *((volatile u32 *)ARC_TO_MEI_INT)  = 0x20;
+
+}
+
+
+void post_mei_init(void)
+{
+u32 mailbox[NUM_MB];
+
+  mailbox[0] = TIMER_DELAY;
+ 
+  /* set bytes per bearer channel */
+  mailbox[1] = BC0_BYTES;
+  mailbox[2] = BC1_BYTES;
+  WriteMbox(mailbox, 3);
+
+  WriteRegLong(AAI_ACCESS, 0x00000001);
+
+  /* enable ADSL block clock, ac_clk */
+  WriteRegLong(MEI_CONTROL, 0x01);
+  WriteRegLong(MEI_DEBUG_DEC, 0x00000001); // select ld/st space
+  MEIWriteARCValue(0x31F00,   0x00000010); // write CRI_CCR0 to enable ac_clk
+
+  /* set the MTE to register start */
+  MEIWriteARCValue(IT_AMODE, 0xF);
+  BFMWait(10); 
+}
+
+
+int wait_sync(void)
+{
+u32 mailbox[NUM_MB];
+  /* wait for ATM sync to be achieved on both BC0 and BC1 */
+  u32 timeout=0;
+  ReadMbox(mailbox, 1);
+  u32 readval = mailbox[0];
+  while( ((readval & 0xFFFFFFFF) == 0) && (timeout < TIMEOUT_VALUE) ) {
+    BFMWait(1);
+    //printk("wait_sync\n\n");
+    ReadMbox(mailbox, 1);
+    readval = mailbox[0];
+    timeout++;
+  }
+  if(timeout == TIMEOUT_VALUE)return 0;
+  else return 1;
+}
+#endif //DFE_LOOPBACK
+//end of TODO, for loopback test
+
+MEI_ERROR meiForceRebootAdslModem(void)
+{
+#if 0
+//#ifdef	ARC_READY_ACK
+		if(down_interruptible(&mei_sema))	//disable CMV access until ARC ready
+		{
+                	return -ERESTARTSYS;
+		}
+#endif
+	if(reboot_firsttime==1){//000002:fchang Start
+		// reset ARC
+		*((volatile u32 *)0xB0100910) = 0x80;	//reset DFE
+		asm("SYNC");
+		*((volatile u32 *)0xB0100910) = 0x0;
+		asm("SYNC");
+		if((*((volatile u32 *)0xB0100910))!=0x0)
+#ifdef AMAZON_MEI_DEBUG_ON
+			printk("\n reset DFE fail");
+#endif
+		
+		// reset ARC
+		meiLongwordWrite(MEI_CONTROL, SOFT_RESET);
+		asm("SYNC");
+		meiLongwordWrite(MEI_CONTROL, 0);
+		asm("SYNC");	
+
+	}	//000002:fchang End		
+#ifdef DFE_LOOPBACK
+                img_hdr=(ARC_IMG_HDR *)lp_image;
+#else
+		img_hdr=(ARC_IMG_HDR *)image_buffer;
+#endif		
+//		printk("\n\n enter haltarc");
+                meiHaltArc();
+//		printk("\n\n haltarc done");
+//000002:fchang Start
+	if(reboot_firsttime==0){
+		printk("\n\n new reboot");
+		meiResetArc();
+		meiResetCore();
+	}
+	if(reboot_firsttime==1)
+                meiDownloadBootCode();
+	else
+		mei_ioctl((struct inode *)NULL, (struct file *)NULL, AMAZON_MEI_DOWNLOAD, (unsigned long)NULL);
+
+//000002:fchang End
+#ifdef AMAZON_MEI_DEBUG_ON
+//		printk("\n\n Download Done");
+#endif
+
+#ifdef	DFE_LOOPBACK
+		post_mei_init();
+#endif		
+
+//		sema_init(&mei_sema, 1);
+		//up(&mei_sema);
+
+//		enable_irq(AMAZON_MEI_INT);
+					
+		meiRunArc();
+//000002:fchang Start		
+	if(reboot_firsttime==0){
+		meiEnalbeMailboxInt();
+	}		
+//000002:fchang End
+		
+#ifdef AMAZON_MEI_DEBUG_ON
+//		printk("\n\n ARC Running");
+#endif
+		
+#ifdef 	AMAZON_MEI_DEBUG_ON   //to test ac_clk setting correctness
+	{
+	u32 arc_control_mode;
+	u32 arc_debug_addr = 0x31F00;
+	u32 arc_debug_data = 0x10;
+	meiLongwordRead(MEI_CONTROL, &arc_control_mode);
+	arc_control_mode |= (HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, arc_control_mode);
+	
+	meiLongwordWrite(MEI_DEBUG_DEC, MEI_DEBUG_DEC_DMP1_MASK);
+	meiLongwordWrite(MEI_DEBUG_RAD, arc_debug_addr);
+	meiPollForDbgDone();
+	meiLongwordRead(MEI_DEBUG_DATA, &arc_debug_data);
+
+	meiLongwordRead(MEI_CONTROL, &arc_control_mode);
+	arc_control_mode &= ~(HOST_MSTR);
+	meiLongwordWrite(MEI_CONTROL, arc_control_mode);
+	
+//	printk("\n\n ac_clk is %8x\n", arc_debug_data);
+	}
+#endif		
+			
+		
+#ifdef DFE_LOOPBACK
+		if (wait_sync() == 0){
+			printk("ARC fails to run: time out\n\n");
+		}else{
+//			printk("ARC is ready\n\n");
+		}
+#endif		
+		if(reboot_firsttime==1)	//000002:fchang
+			reboot_firsttime=0;	//000002:fchang
+		
+                return MEI_SUCCESS;
+}
+
+////////////////////            procfs debug            ////////////////////////////////////////////////////////
+#define MEI_DIRNAME     "mei"
+static struct proc_dir_entry *meidir;
+
+static ssize_t proc_write(struct file *, const char *, size_t, loff_t *);
+static ssize_t proc_read(struct file *, char *, size_t, loff_t *);
+
+static struct file_operations proc_operations = {
+	read:	proc_read,
+	write:	proc_write,
+};
+
+typedef struct reg_entry {
+	int * flag;
+	char name[30];          // big enough to hold names
+	char description[100];      // big enough to hold description
+	unsigned short low_ino;
+} reg_entry_t;
+
+static reg_entry_t regs[PROC_ITEMS];       // total items to be monitored by /proc/mei
+
+#define NUM_OF_REG_ENTRY	(sizeof(regs)/sizeof(reg_entry_t))
+
+static int proc_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
+{
+        int i_ino = (file->f_dentry->d_inode)->i_ino;
+	char outputbuf[64];
+	int count=0;
+	int i;
+	u32 version=0;
+	reg_entry_t* current_reg=NULL;
+	
+	for (i=0;i<NUM_OF_REG_ENTRY;i++) {
+		if (regs[i].low_ino==i_ino) {
+			current_reg = &regs[i];
+			break;
+		}
+	}
+	if (current_reg==NULL)
+		return -EINVAL;
+	
+	if (current_reg->flag == (int *) 8){
+	///proc/mei/version
+	//format:
+	//Firmware version: major.minor.sub_version.int_version.rel_state.spl_appl
+	//Firmware Date Time Code: date/month min:hour
+		if (*ppos>0) /* Assume reading completed in previous read*/
+			return 0;               // indicates end of file
+		if(down_interruptible(&mei_sema))
+                	return -ERESTARTSYS;
+		
+		//if (indicator_count != 1){
+		if (indicator_count < 1){
+			up(&mei_sema);
+			return -EAGAIN;
+		}
+		//major:bits 0-7 
+		//minor:bits 8-15
+		makeCMV(H2D_CMV_READ, INFO, 54, 0, 1, NULL);
+		if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#if 0
+#ifdef AMAZON_MEI_DEBUG_ON
+			printk("\n\n WINHOST CMV fail");
+#endif	
+#endif
+			up(&mei_sema);
+			return -EIO;
+		}
+		version = RxMessage[4];
+		count = sprintf(outputbuf, "%d.%d.",(version)&0xff,(version>>8)&0xff);
+		
+		//sub_version:bits 4-7
+		//int_version:bits 0-3
+		//spl_appl:bits 8-13
+		//rel_state:bits 14-15
+		makeCMV(H2D_CMV_READ, INFO, 54, 1, 1, NULL);
+		if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#if 0
+#ifdef AMAZON_MEI_DEBUG_ON
+			printk("\n\n WINHOST CMV fail");	
+#endif
+#endif
+			up(&mei_sema);
+			return -EFAULT;
+		}
+		version =RxMessage[4];
+		count += sprintf(outputbuf+count, "%d.%d.%d.%d",
+				(version>>4)&0xf, 
+				version&0xf,
+				(version>>14)&0x3, 
+				(version>>8)&0x3f);	
+#ifdef ADSL_LED_SUPPORT				
+// version check -start	for adsl led			
+		if ((((version>>4)&0xf)==2)&&((version&0xf)>=3)&&((version&0xf)<7)) firmware_support_led=1;
+		else if ((((version>>4)&0xf)==2)&&((version&0xf)>=7)) firmware_support_led=2;
+		else if (((version>>4)&0xf)>2) firmware_support_led=2;
+
+//165001:henryhsu:20050906:Modify for adsl firmware version 1.2.1.2.0.1 DATA_LED can't flash.
+	//else firmware_support_led=0;
+	else firmware_support_led=2;
+//165001		
+
+
+// version check -end	
+#endif	
+		//Date:bits 0-7
+		//Month:bits 8-15
+		makeCMV(H2D_CMV_READ, INFO, 55, 0, 1, NULL);
+		if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#if 0
+#ifdef AMAZON_MEI_DEBUG_ON
+			printk("\n\n WINHOST CMV fail");
+#endif	
+#endif
+			up(&mei_sema);
+			return -EIO;
+		}
+		version = RxMessage[4];
+		
+		//Hour:bits 0-7
+		//Minute:bits 8-15
+		makeCMV(H2D_CMV_READ, INFO, 55, 1, 1, NULL);
+		if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#if 0
+#ifdef AMAZON_MEI_DEBUG_ON
+			printk("\n\n WINHOST CMV fail");
+#endif	
+#endif
+			up(&mei_sema);
+			return -EFAULT;
+		}
+		version += (RxMessage[4]<<16);
+		count += sprintf(outputbuf+count, " %d/%d %d:%d\n"
+				,version&0xff
+				,(version>>8)&0xff
+				,(version>>25)&0xff
+				,(version>>16)&0xff);
+				
+		up(&mei_sema);	
+		
+		*ppos+=count;
+	}else if(current_reg->flag != (int *)Recent_indicator){
+        	if (*ppos>0) /* Assume reading completed in previous read*/
+			return 0;               // indicates end of file
+		count = sprintf(outputbuf, "0x%08X\n\n", *(current_reg->flag));
+	        *ppos+=count;
+	        if (count>nbytes)  /* Assume output can be read at one time */
+			return -EINVAL;
+        }else{
+        	if((int)(*ppos)/((int)7)==16)
+                	return 0;  // indicate end of the message
+        	count = sprintf(outputbuf, "0x%04X\n\n", *(((u16 *)(current_reg->flag))+ (int)(*ppos)/((int)7)));
+                *ppos+=count;
+	}
+	if (copy_to_user(buf, outputbuf, count))
+		return -EFAULT;
+	return count;
+}
+
+static ssize_t proc_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
+{
+	int i_ino = (file->f_dentry->d_inode)->i_ino;
+	reg_entry_t* current_reg=NULL;
+	int i;
+	unsigned long newRegValue;
+	char *endp;
+
+	for (i=0;i<NUM_OF_REG_ENTRY;i++) {
+		if (regs[i].low_ino==i_ino) {
+			current_reg = &regs[i];
+			break;
+		}
+	}
+	if ((current_reg==NULL) || (current_reg->flag == (int *)Recent_indicator))
+		return -EINVAL;
+
+	newRegValue = simple_strtoul(buffer,&endp,0);
+	*(current_reg->flag)=(int)newRegValue;
+	return (count+endp-buffer);
+}
+////////////////makeCMV(Opcode, Group, Address, Index, Size, Data), CMV in u16 TxMessage[MSG_LENGTH]///////////////////////////
+void makeCMV(u8 opcode, u8 group, u16 address, u16 index, int size, u16 * data)
+{
+	memset(TxMessage, 0, MSG_LENGTH*2);
+	TxMessage[0]= (opcode<<4) + (size&0xf);
+	TxMessage[1]= (((index==0)?0:1)<<7) + (group&0x7f);
+	TxMessage[2]= address;
+	TxMessage[3]= index;
+	if(opcode == H2D_CMV_WRITE)
+		memcpy(TxMessage+4, data, size*2);
+	return;
+}
+
+////////////////makeCMV(Opcode, Group, Address, Index, Size, Data), CMV in u16 TxMessage[MSG_LENGTH]///////////////////////////
+void makeCMV_local(u8 opcode, u8 group, u16 address, u16 index, int size, u16 * data,u16 *CMVMSG)
+{
+	memset(CMVMSG, 0, MSG_LENGTH*2);
+	CMVMSG[0]= (opcode<<4) + (size&0xf);
+	CMVMSG[1]= (((index==0)?0:1)<<7) + (group&0x7f);
+	CMVMSG[2]= address;
+	CMVMSG[3]= index;
+	if(opcode == H2D_CMV_WRITE)
+		memcpy(CMVMSG+4, data, size*2);
+	return;
+}
+
+////////////////                Driver Structure                /////////////////////////////////////////////////////////////////////////////
+static ssize_t mei_write(struct file *, const char *, size_t, loff_t *);
+static int mei_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+static struct file_operations mei_operations = {
+        write:         	mei_write,
+        ioctl:         	mei_ioctl,
+};
+
+
+static ssize_t mei_write(struct file * filp, const char * buf, size_t size, loff_t * loff)
+{
+//	printk("\n\n mei_write entered");
+//      image_buffer = (u32 *)kmalloc(size, GFP_KERNEL);
+	image_buffer = (u32 *)vmalloc(size);
+//	printk("\n\n image_buffer kmalloc done");
+	if(image_buffer == NULL){
+#ifdef AMAZON_MEI_DEBUG_ON
+//		printk("\n\n kmalloc for firmware image fail");
+		printk("\n\n vmalloc for firmware image fail");
+#endif
+		return -1;
+	}
+	copy_from_user((char *)image_buffer, buf, size);
+//	printk("\n\n copy_from_user done");
+        return size;
+}
+
+	////////// ISR GPTU Timer 6 for high resolution timer /////////////
+void amazon_timer6_interrupt_MEI(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int i,j;
+	u32 temp;
+	u16 temp16;
+	u16 rdindex, wrindex;
+	u16 num_rd=0;	//num of byte can be read
+	u16 bytes_to_wr=0;
+	
+//	printk("\n\nenter timer\n\n");
+	irqtimes++;
+//	printk("\n%d\n",irqtimes);
+
+
+/*
+#ifdef	PCM_ACCESS_DEBUG
+		meiDebugRead_8(0x30f20, &temp, 1);
+#else
+		meiDMARead_8(0x30f20, &temp, 1);
+#endif		
+	if((temp&0x4000)!=0){
+		printk("\nER_ERR");
+#ifdef	PCM_ACCESS_DEBUG
+		meiDebugWrite_8(0x30f20, &temp, 1);
+#else
+		meiDMAWrite_8(0x30f20, &temp, 1);
+#endif
+#ifdef	PCM_ACCESS_DEBUG
+		meiDebugRead_8(0x30f20, &temp, 1);
+#else
+		meiDMARead_8(0x30f20, &temp, 1);
+#endif
+		if((temp&0x4000)!=0)
+			printk("\nER_ERR not cleared");
+	}
+*/	
+	
+	for(i=PCM_CHANNEL_NUM-1;i>=0;i--){// start from last channel, which is rx  
+#ifdef	PCM_ACCESS_DEBUG
+		meiDebugRead_16(pcm_start_addr+i*16+12, &temp, 1);
+#else
+		meiDMARead_16(pcm_start_addr+i*16+12, &temp, 1);
+#endif
+		wrindex = (u16)((temp & 0xffff0000)>>16);
+//		printk(" %d",wrindex);
+#ifdef	PCM_ACCESS_DEBUG
+		meiDebugRead_16(pcm_start_addr+i*16+8, &temp, 1);
+#else
+		meiDMARead_16(pcm_start_addr+i*16+8, &temp, 1);
+#endif
+		rdindex = (u16)(temp & 0xffff);
+//		printk(" %d",rdindex);
+		if(rdindex<=wrindex)
+			num_rd=((wrindex-rdindex)/4)*4;	//read multiply of 4 bytes
+		else
+			num_rd=((pcm_data[i].len-(rdindex-wrindex))/4)*4;	//read multiply of 4 bytes
+		
+		if(i%2!=0){//rx channel
+			pcm_data[i].point=0;
+			for(j=0;j<num_rd/4;j++){
+				if(pcm_data[i].finish!=1){
+					if((rdindex+j*4)>=pcm_data[i].len)
+						temp16=(rdindex+j*4) - pcm_data[i].len;
+					else
+						temp16=rdindex+j*4;
+#ifdef	PCM_ACCESS_DEBUG
+					meiDebugRead_8((((u32)(pcm_data[i].LSW))+(((u32)(pcm_data[i].MSW))<<16))+temp16, (u32*)(pcm_data[i].buff+pcm_data[i].point), 1);
+#else
+					meiDMARead_8((((u32)(pcm_data[i].LSW))+(((u32)(pcm_data[i].MSW))<<16))+temp16, (u32*)(pcm_data[i].buff+pcm_data[i].point), 1);
+#endif
+				//	printk(" %8x", *((u32*)(pcm_data[i].buff+pcm_data[i].point))); 	
+				/*	if(pcm_data[i].point==0){
+						if(pcm_data[i].buff[0]==0xA5){// start of loopback data
+							pcm_data[i].point+=4;	
+							printk("\nstart receive data");
+						}	
+					} 
+					else*/
+						pcm_data[i].point+=4;
+				/*	if(pcm_data[i].point==PCM_BUFF_SIZE){	//finish rx
+						pcm_data[i].finish=1;
+						printk("\nchannel[%d] finished", i);
+					}	*/
+				}
+			}
+			if(firsttime[i]==1){
+				for(j=0;j<num_rd;j++){
+					if(pcm_data[i].buff[j]==0x1){
+						num_cmp[i]=num_rd-j;
+						firsttime[i]=0;
+						break;
+					}
+				}
+				if(memcmp(sampledata+1, pcm_data[i].buff+j, num_cmp[i])!=0)
+					printk("\n\ndata wrong,1st\n\n");
+				else
+					pcm_start_loc[i] = num_cmp[i]+1;
+			}
+			else{
+				if(memcmp(sampledata+pcm_start_loc[i], pcm_data[i].buff, num_rd)!=0)
+					printk("\n\ndata wrong\n\n");
+				else{
+					pcm_start_loc[i]+=num_rd;
+					if(pcm_start_loc[i]>=256)
+						pcm_start_loc[i]=pcm_start_loc[i]-256;
+				}
+			}
+			
+			rdindex +=num_rd;
+			if(rdindex>=pcm_data[i].len)
+				rdindex=rdindex-pcm_data[i].len;
+#ifdef	PCM_ACCESS_DEBUG
+			meiDebugRead_16(pcm_start_addr+i*16+8, &temp, 1);
+#else
+			meiDMARead_16(pcm_start_addr+i*16+8, &temp, 1);
+#endif
+			temp= (temp & 0xffff0000) + rdindex;
+#ifdef	PCM_ACCESS_DEBUG
+			meiDebugWrite_16(pcm_start_addr+i*16+8, &temp, 1); // update rdindex 
+#else
+			meiDMAWrite_16(pcm_start_addr+i*16+8, &temp, 1); // update rdindex
+#endif
+			
+			bytes_to_wr = num_rd;
+			
+	//		if(bytes_to_wr>0){
+		//		printk(" %d", num_rd);
+		//		printk(" %d", rdindex);
+//				printk("\n\nrdindex = %d", rdindex);	
+			//}
+		}
+		else{	//tx channel
+	//		if((bytes_to_wr + num_rd) < pcm_data[i].len){
+				for(j=0;j<bytes_to_wr/4;j++){
+					if(pcm_data[i].finish!=1){
+						if((wrindex+j*4)>=pcm_data[i].len)
+							temp16=(wrindex+j*4) - pcm_data[i].len;
+						else
+							temp16=wrindex + j*4;
+/*							
+#ifdef	PCM_ACCESS_DEBUG
+						meiDebugWrite_8((((u32)(pcm_data[i].LSW))+(((u32)(pcm_data[i].MSW))<<16))+temp16,(u32*)(pcm_data[i+1].buff+j*4), 1);
+#else
+						meiDMAWrite_8((((u32)(pcm_data[i].LSW))+(((u32)(pcm_data[i].MSW))<<16))+temp16,(u32*)(pcm_data[i+1].buff+j*4), 1);
+#endif*/
+							
+#ifdef	PCM_ACCESS_DEBUG
+						meiDebugWrite_8((((u32)(pcm_data[i].LSW))+(((u32)(pcm_data[i].MSW))<<16))+temp16,(u32*)(pcm_data[i].buff+pcm_data[i].point), 1);
+				//		meiDebugWrite_8((((u32)(pcm_data[i].LSW))+(((u32)(pcm_data[i].MSW))<<16))+temp16,(u32*)(pcm_data[i].buff), 1);
+#else
+						meiDMAWrite_8((((u32)(pcm_data[i].LSW))+(((u32)(pcm_data[i].MSW))<<16))+temp16,(u32*)(pcm_data[i].buff+pcm_data[i].point), 1);
+#endif		
+						pcm_data[i].point+=4;
+						if(pcm_data[i].point==PCM_BUFF_SIZE){
+					//		pcm_data[i].finish=1; 
+					//		printk("\nchannel[%d] finished", i);
+							pcm_data[i].point=0;
+						}	
+					}
+				}
+				wrindex+=bytes_to_wr;
+				if(wrindex>=pcm_data[i].len)
+					wrindex=wrindex-pcm_data[i].len;
+#ifdef	PCM_ACCESS_DEBUG
+				meiDebugRead_16(pcm_start_addr+i*16+12, &temp, 1);
+#else
+				meiDMARead_16(pcm_start_addr+i*16+12, &temp, 1);
+#endif
+				temp=(temp&0xffff) + (wrindex<<16);
+#ifdef	PCM_ACCESS_DEBUG
+				meiDebugWrite_16(pcm_start_addr+i*16+12, &temp, 1); // update wrindex
+#else
+				meiDMAWrite_16(pcm_start_addr+i*16+12, &temp, 1); // update wrindex
+#endif
+			
+				//if(bytes_to_wr>0){
+			//		printk(" %d", bytes_to_wr);
+			//		printk(" %d", wrindex);
+//					printk("\n\nwrindex = %d", wrindex);	
+				//}
+		//	}
+		}
+	}
+	return;
+}
+//000002:fchang Start
+static int meiResetArc(void)
+{
+	u32 auxreg0;
+	u32 auxreg5;
+	int flshcnt=0;
+	int flshcnt1=0;
+	int flshcnt2=0;
+	
+	meiLongwordWrite(MEI_CONTROL, 1);
+	meiLongwordWrite(MEI_DEBUG_DEC, 3);	
+	meiLongwordWrite(MEI_DEBUG_WAD, 0x3c);
+	meiLongwordWrite(MEI_DEBUG_DATA, 0x10);
+	meiPollForDbgDone();
+	meiLongwordWrite(MEI_DEBUG_DEC, 0x0);
+	meiLongwordWrite(MEI_DEBUG_WAD, 0x2);
+	meiLongwordWrite(MEI_DEBUG_DATA, 0x0);
+	meiPollForDbgDone();
+	meiLongwordWrite(MEI_DEBUG_WAD, 0x3);
+	meiLongwordWrite(MEI_DEBUG_DATA, 0x0);
+	meiPollForDbgDone();
+	meiLongwordWrite(MEI_DEBUG_DEC, 0x0);
+	meiLongwordWrite(MEI_DEBUG_RAD, 0x0);
+	meiPollForDbgDone();
+	meiLongwordRead(MEI_DEBUG_DATA, &auxreg0);
+	auxreg0 = auxreg0 & 0x03ffffff;
+	meiLongwordWrite(MEI_DEBUG_WAD, 0x0);
+	meiLongwordWrite(MEI_DEBUG_DATA, auxreg0);
+	meiPollForDbgDone();
+	meiLongwordWrite(MEI_DEBUG_WAD, 0x10a);
+	meiLongwordWrite(MEI_DEBUG_DATA, 0x0);
+	meiPollForDbgDone();
+	meiLongwordWrite(MEI_DEBUG_DEC, 0x2);
+	meiLongwordWrite(MEI_DEBUG_WAD, 0xfffc);
+	meiLongwordWrite(MEI_DEBUG_DATA, 0x1fffffff);
+	meiPollForDbgDone();
+	while(flshcnt<3){
+		meiLongwordWrite(MEI_DEBUG_DEC, 0x0);
+		meiLongwordWrite(MEI_DEBUG_RAD, 0x0);
+		meiPollForDbgDone();
+		meiLongwordRead(MEI_DEBUG_DATA, &auxreg0);
+		auxreg0 = auxreg0 & 0xff000000;
+		auxreg0 = auxreg0 | 0x3fff;
+		meiLongwordWrite(MEI_DEBUG_WAD, 0x0);
+		meiLongwordWrite(MEI_DEBUG_DATA, auxreg0);
+		meiPollForDbgDone();
+		
+		meiLongwordWrite(MEI_DEBUG_DEC, 0x0);
+		meiLongwordWrite(MEI_DEBUG_RAD, 0x5);
+		meiPollForDbgDone();
+		meiLongwordRead(MEI_DEBUG_DATA, &auxreg5);
+		auxreg5 = auxreg5 | 0x801;
+		meiLongwordWrite(MEI_DEBUG_WAD, 0x5);
+		meiLongwordWrite(MEI_DEBUG_DATA, auxreg5);
+		meiPollForDbgDone();
+		meiLongwordWrite(MEI_DEBUG_RAD, 0x0);
+		meiPollForDbgDone();
+		meiLongwordRead(MEI_DEBUG_DATA, &auxreg0);
+		auxreg0 = auxreg0 & 0x00ffffff;
+		if(auxreg0 == 0x4000)
+			flshcnt = flshcnt+1;
+		else{
+			if(flshcnt == 0)
+				flshcnt1 = flshcnt1 +1;
+			else
+				flshcnt2 = flshcnt2 +1;
+		}	
+	}
+	
+	return 1;
+}
+
+static int meiResetCore(void)
+{
+	meiLongwordWrite(MEI_CONTROL, 0x1);
+	meiLongwordWrite(MEI_DEBUG_DEC, 0x2);
+	meiLongwordWrite(MEI_DEBUG_WAD, 0x31f10);
+	meiLongwordWrite(MEI_DEBUG_DATA, 0xf);
+	meiPollForDbgDone();
+	meiLongwordWrite(MEI_DEBUG_WAD, 0x31f10);
+	meiLongwordWrite(MEI_DEBUG_DATA, 0x0);
+	meiPollForDbgDone();
+	meiLongwordWrite(MEI_DEBUG_WAD, 0x31f00);
+	meiLongwordWrite(MEI_DEBUG_DATA, 0x55);
+	meiPollForDbgDone();
+	return 1;
+}
+
+static int meiEnalbeMailboxInt(void)
+{
+	u32 arc2meiintmsk;
+	meiLongwordRead(ARC_TO_MEI_INT_MASK, &arc2meiintmsk);
+	arc2meiintmsk = arc2meiintmsk | 0x1;
+	meiLongwordWrite(ARC_TO_MEI_INT_MASK, arc2meiintmsk);
+	meiLongwordWrite(MEI_CONTROL, 0x0);
+	return 1;
+}
+
+
+
+//000002:fchang End
+
+static int mei_ioctl(struct inode * ino, struct file * fil, unsigned int command, unsigned long lon)
+{
+        int i,k;
+	u32 boot_loop;
+	u32 page_size;
+	u32 dest_addr;
+	u32 j;
+	u32 temp;
+	u32 temp2;
+	u16 trapsflag=0;
+	amazon_clreoc_pkt * current_clreoc;
+	struct timeval time_now;
+	struct timeval time_fini;
+	struct list_head * ptr;
+	amazon_mei_mib * mib_ptr;
+//	u16 buff[MSG_LENGTH]__attribute__ ((aligned(4)));
+	structpts pts;
+        int meierr=MEI_SUCCESS;
+	u16 data[12];  //used in makeCMV, to pass in payload when CMV set, ignored when CMV read.
+	meireg regrdwr;
+	meidebug debugrdwr;
+	amazon_mei_mib * temp_intvl;
+	struct sk_buff * eoc_skb;
+// 603221:tc.chen start
+	u16 hdlc_cmd[2];
+	u16 hdlc_rx_buffer[32];
+	int hdlc_rx_len=0;
+// 603221:tc.chen end
+	
+	int from_kernel = 0;//joelin
+	if (ino == (struct inode *)0) from_kernel = 1;//joelin
+	
+//	printk("\n switch.command = %i\n", command);
+        switch(command){
+		case GET_ADSL_LINE_CODE:
+			pts.adslLineTableEntry_pt = (adslLineTableEntry *)kmalloc(sizeof(adslLineTableEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.adslLineTableEntry_pt, (char *)lon, sizeof(adslLineTableEntry));
+			if(IS_FLAG_SET((&(pts.adslLineTableEntry_pt->flags)), LINE_CODE_FLAG)){
+				pts.adslLineTableEntry_pt->adslLineCode = 2;
+			}
+			copy_to_user((char *)lon, (char *)pts.adslLineTableEntry_pt, sizeof(adslLineTableEntry));
+			kfree(pts.adslLineTableEntry_pt);
+			break;
+#ifdef AMAZON_MEI_MIB_RFC3440
+		case GET_ADSL_ATUC_LINE_EXT:
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+			pts.adslLineExtTableEntry_pt = (adslLineExtTableEntry *)kmalloc(sizeof(adslLineExtTableEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.adslLineExtTableEntry_pt, (char *)lon, sizeof(adslLineExtTableEntry));
+			if(IS_FLAG_SET((&(pts.adslLineExtTableEntry_pt->flags)), ATUC_LINE_TRANS_CAP_FLAG)){
+				ATUC_LINE_TRANS_CAP_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 67 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslLineExtTableEntry_pt->flags)), ATUC_LINE_TRANS_CAP_FLAG);	
+				}	
+				else{
+					memcpy((&(pts.adslLineExtTableEntry_pt->adslLineTransAtucCap)), RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslLineExtTableEntry_pt->flags)), ATUC_LINE_TRANS_CONFIG_FLAG)){
+				ATUC_LINE_TRANS_CONFIG_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 67 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslLineExtTableEntry_pt->flags)), ATUC_LINE_TRANS_CONFIG_FLAG);	
+				}	
+				else{
+					memcpy((&(pts.adslLineExtTableEntry_pt->adslLineTransAtucConfig)), RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslLineExtTableEntry_pt->flags)), ATUC_LINE_TRANS_ACTUAL_FLAG)){
+				ATUC_LINE_TRANS_ACTUAL_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 2 Address 1 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslLineExtTableEntry_pt->flags)), ATUC_LINE_TRANS_ACTUAL_FLAG);	
+				}	
+				else{
+					memcpy((&(pts.adslLineExtTableEntry_pt->adslLineTransAtucActual)), RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslLineExtTableEntry_pt->flags)), LINE_GLITE_POWER_STATE_FLAG)){    // not supported currently
+/*
+				LINE_GLITE_POWER_STATE_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 2 Address 0 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslLineExtTableEntry_pt->flags)), LINE_GLITE_POWER_STATE_FLAG);	
+				}	
+				else{
+					memcpy((&(pts.adslLineExtTableEntry_pt->adslLineGlitePowerState)), RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+*/
+				CLR_FLAG((&(pts.adslLineExtTableEntry_pt->flags)), LINE_GLITE_POWER_STATE_FLAG);
+			}
+			copy_to_user((char *)lon, (char *)pts.adslLineExtTableEntry_pt, sizeof(adslLineExtTableEntry));
+			kfree(pts.adslLineTableEntry_pt);
+			up(&mei_sema);
+			break;
+#endif
+
+#ifdef AMAZON_MEI_MIB_RFC3440
+		case SET_ADSL_ATUC_LINE_EXT:
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+			pts.adslLineExtTableEntry_pt = (adslLineExtTableEntry *)kmalloc(sizeof(adslLineExtTableEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.adslLineExtTableEntry_pt, (char *)lon, sizeof(adslLineExtTableEntry));
+			
+			//only adslLineTransAtucConfig can be set.
+			CLR_FLAG((&(pts.adslLineExtTableEntry_pt->flags)), ATUC_LINE_TRANS_CAP_FLAG);
+			if(IS_FLAG_SET((&(pts.adslLineExtTableEntry_pt->flags)), ATUC_LINE_TRANS_CONFIG_FLAG)){
+				memcpy(data,(&(pts.adslLineExtTableEntry_pt->adslLineTransAtucConfig)), 2); 
+				ATUC_LINE_TRANS_CONFIG_FLAG_MAKECMV_WR;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 67 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslLineExtTableEntry_pt->flags)), ATUC_LINE_TRANS_CONFIG_FLAG);	
+				}	
+			}
+			CLR_FLAG((&(pts.adslLineExtTableEntry_pt->flags)), ATUC_LINE_TRANS_ACTUAL_FLAG);
+			CLR_FLAG((&(pts.adslLineExtTableEntry_pt->flags)), LINE_GLITE_POWER_STATE_FLAG);
+	
+			copy_to_user((char *)lon, (char *)pts.adslLineExtTableEntry_pt, sizeof(adslLineExtTableEntry));
+			kfree(pts.adslLineTableEntry_pt);
+			up(&mei_sema);
+			break;
+#endif
+
+		case GET_ADSL_ATUC_PHY:
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+			
+			pts.adslAtucPhysEntry_pt = (adslAtucPhysEntry *)kmalloc(sizeof(adslAtucPhysEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.adslAtucPhysEntry_pt, (char *)lon, sizeof(adslAtucPhysEntry));
+			if(IS_FLAG_SET((&(pts.adslAtucPhysEntry_pt->flags)), ATUC_PHY_SER_NUM_FLAG)){
+				ATUC_PHY_SER_NUM_FLAG_MAKECMV1;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 57 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslAtucPhysEntry_pt->flags)), ATUC_PHY_SER_NUM_FLAG);	
+				}
+				else{
+					memcpy(pts.adslAtucPhysEntry_pt->serial_no, RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+				ATUC_PHY_SER_NUM_FLAG_MAKECMV2;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 57 Index 12");
+#endif
+					CLR_FLAG((&(pts.adslAtucPhysEntry_pt->flags)), ATUC_PHY_SER_NUM_FLAG);	
+				}
+				else{
+					memcpy((pts.adslAtucPhysEntry_pt->serial_no+24), RxMessage+4, ((RxMessage[0]&0xf)*2));
+				} 
+			}
+			if(IS_FLAG_SET((&(pts.adslAtucPhysEntry_pt->flags)), ATUC_PHY_VENDOR_ID_FLAG)){
+				ATUC_PHY_VENDOR_ID_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 64 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslAtucPhysEntry_pt->flags)), ATUC_PHY_VENDOR_ID_FLAG);	
+				}	
+				else{
+					memcpy(pts.adslAtucPhysEntry_pt->vendor_id.vendor_id, RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslAtucPhysEntry_pt->flags)), ATUC_PHY_VER_NUM_FLAG)){
+				ATUC_PHY_VER_NUM_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 58 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslAtucPhysEntry_pt->flags)), ATUC_PHY_VER_NUM_FLAG);	
+				}	
+				else{
+					memcpy(pts.adslAtucPhysEntry_pt->version_no, RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslAtucPhysEntry_pt->flags)), ATUC_CURR_STAT_FLAG)){
+				pts.adslAtucPhysEntry_pt->status = CurrStatus.adslAtucCurrStatus;
+			}		
+			if(IS_FLAG_SET((&(pts.adslAtucPhysEntry_pt->flags)), ATUC_CURR_OUT_PWR_FLAG)){
+				ATUC_CURR_OUT_PWR_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 68 Index 5");
+#endif
+					CLR_FLAG((&(pts.adslAtucPhysEntry_pt->flags)), ATUC_CURR_OUT_PWR_FLAG);	
+				}	
+				else{
+					memcpy((&(pts.adslAtucPhysEntry_pt->outputPwr)), RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslAtucPhysEntry_pt->flags)), ATUC_CURR_ATTR_FLAG)){
+				ATUC_CURR_ATTR_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 69 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslAtucPhysEntry_pt->flags)), ATUC_CURR_ATTR_FLAG);	
+				}	
+				else{
+					memcpy((&(pts.adslAtucPhysEntry_pt->attainableRate)), RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+			}
+			copy_to_user((char *)lon, (char *)pts.adslAtucPhysEntry_pt, sizeof(adslAtucPhysEntry));
+			kfree(pts.adslAtucPhysEntry_pt);
+			
+			up(&mei_sema);
+			break;
+		case GET_ADSL_ATUR_PHY:
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+			
+			pts.adslAturPhysEntry_pt = (adslAturPhysEntry *)kmalloc(sizeof(adslAturPhysEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.adslAturPhysEntry_pt, (char *)lon, sizeof(adslAturPhysEntry));
+			if(IS_FLAG_SET((&(pts.adslAturPhysEntry_pt->flags)), ATUR_PHY_SER_NUM_FLAG)){
+				ATUR_PHY_SER_NUM_FLAG_MAKECMV1;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 62 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslAturPhysEntry_pt->flags)), ATUR_PHY_SER_NUM_FLAG);	
+				}
+				else{
+					memcpy(pts.adslAturPhysEntry_pt->serial_no, RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+				ATUR_PHY_SER_NUM_FLAG_MAKECMV2;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 62 Index 12");
+#endif
+					CLR_FLAG((&(pts.adslAturPhysEntry_pt->flags)), ATUR_PHY_SER_NUM_FLAG);	
+				}
+				else{
+					memcpy((pts.adslAturPhysEntry_pt->serial_no+24), RxMessage+4, ((RxMessage[0]&0xf)*2));
+				} 
+			}
+			if(IS_FLAG_SET((&(pts.adslAturPhysEntry_pt->flags)), ATUR_PHY_VENDOR_ID_FLAG)){
+				ATUR_PHY_VENDOR_ID_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 65 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslAturPhysEntry_pt->flags)), ATUR_PHY_VENDOR_ID_FLAG);	
+				}	
+				else{
+					memcpy(pts.adslAturPhysEntry_pt->vendor_id.vendor_id, RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslAturPhysEntry_pt->flags)), ATUR_PHY_VER_NUM_FLAG)){
+				ATUR_PHY_VER_NUM_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 61 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslAturPhysEntry_pt->flags)), ATUR_PHY_VER_NUM_FLAG);	
+				}	
+				else{
+					memcpy(pts.adslAturPhysEntry_pt->version_no, RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslAturPhysEntry_pt->flags)), ATUR_SNRMGN_FLAG)){
+				ATUR_SNRMGN_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 68 Index 4");
+#endif
+					CLR_FLAG((&(pts.adslAturPhysEntry_pt->flags)), ATUR_SNRMGN_FLAG);	
+				}	
+				else{
+					memcpy((&(pts.adslAturPhysEntry_pt->SnrMgn)), RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslAturPhysEntry_pt->flags)), ATUR_ATTN_FLAG)){
+				ATUR_ATTN_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 68 Index 2");
+#endif
+					CLR_FLAG((&(pts.adslAturPhysEntry_pt->flags)), ATUR_ATTN_FLAG);	
+				}	
+				else{
+					memcpy((&(pts.adslAturPhysEntry_pt->Attn)), RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslAturPhysEntry_pt->flags)), ATUR_CURR_STAT_FLAG)){
+				pts.adslAturPhysEntry_pt->status = CurrStatus.adslAturCurrStatus;
+			}
+			if(IS_FLAG_SET((&(pts.adslAturPhysEntry_pt->flags)), ATUR_CURR_OUT_PWR_FLAG)){
+				ATUR_CURR_OUT_PWR_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 69 Index 5");
+#endif
+					CLR_FLAG((&(pts.adslAturPhysEntry_pt->flags)), ATUR_CURR_OUT_PWR_FLAG);	
+				}	
+				else{
+					memcpy((&(pts.adslAturPhysEntry_pt->outputPwr)), RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslAturPhysEntry_pt->flags)), ATUR_CURR_ATTR_FLAG)){
+				ATUR_CURR_ATTR_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 68 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslAturPhysEntry_pt->flags)), ATUR_CURR_ATTR_FLAG);	
+				}	
+				else{
+					memcpy((&(pts.adslAturPhysEntry_pt->attainableRate)), RxMessage+4, ((RxMessage[0]&0xf)*2));
+				}
+			}
+			copy_to_user((char *)lon, (char *)pts.adslAturPhysEntry_pt, sizeof(adslAturPhysEntry));
+			kfree(pts.adslAturPhysEntry_pt);
+			
+			up(&mei_sema);
+			break;
+		case GET_ADSL_ATUC_CHAN_INFO:
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+			
+			pts.adslAtucChanInfo_pt = (adslAtucChanInfo *)kmalloc(sizeof(adslAtucChanInfo), GFP_KERNEL);
+			copy_from_user((char *)pts.adslAtucChanInfo_pt, (char *)lon, sizeof(adslAtucChanInfo));
+			if(IS_FLAG_SET((&(pts.adslAtucChanInfo_pt->flags)), ATUC_CHAN_INTLV_DELAY_FLAG)){
+				if((chantype.interleave!=1) || (chantype.fast==1)){
+					CLR_FLAG((&(pts.adslAtucChanInfo_pt->flags)), ATUC_CHAN_INTLV_DELAY_FLAG);
+				}
+				else{
+					ATUC_CHAN_INTLV_DELAY_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 6 Address 3 Index 1");
+#endif
+						CLR_FLAG((&(pts.adslAtucChanInfo_pt->flags)), ATUC_CHAN_INTLV_DELAY_FLAG);	
+					}	
+					else{
+						memcpy((&(pts.adslAtucChanInfo_pt->interleaveDelay)), RxMessage+4, ((RxMessage[0]&0xf)*2));
+					}
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslAtucChanInfo_pt->flags)), ATUC_CHAN_CURR_TX_RATE_FLAG)){
+				ATUC_CHAN_CURR_TX_RATE_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 6 Address 1 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslAtucChanInfo_pt->flags)), ATUC_CHAN_CURR_TX_RATE_FLAG);	
+				}	
+				else{
+					pts.adslAtucChanInfo_pt->currTxRate = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16);
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslAtucChanInfo_pt->flags)), ATUC_CHAN_PREV_TX_RATE_FLAG)){
+				pts.adslAtucChanInfo_pt->prevTxRate = PrevTxRate.adslAtucChanPrevTxRate;
+			}
+			copy_to_user((char *)lon, (char *)pts.adslAtucChanInfo_pt, sizeof(adslAtucChanInfo));
+			kfree(pts.adslAtucChanInfo_pt);
+			
+			up(&mei_sema);
+			break;
+		case GET_ADSL_ATUR_CHAN_INFO:
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+			
+			pts.adslAturChanInfo_pt = (adslAturChanInfo *)kmalloc(sizeof(adslAturChanInfo), GFP_KERNEL);
+			copy_from_user((char *)pts.adslAturChanInfo_pt, (char *)lon, sizeof(adslAturChanInfo));
+			if(IS_FLAG_SET((&(pts.adslAturChanInfo_pt->flags)), ATUR_CHAN_INTLV_DELAY_FLAG)){
+				if((chantype.interleave!=1) || (chantype.fast==1)){
+					CLR_FLAG((&(pts.adslAturChanInfo_pt->flags)), ATUR_CHAN_INTLV_DELAY_FLAG);
+				}
+				else{
+					ATUR_CHAN_INTLV_DELAY_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 6 Address 2 Index 1");
+#endif
+						CLR_FLAG((&(pts.adslAturChanInfo_pt->flags)), ATUR_CHAN_INTLV_DELAY_FLAG);	
+					}	
+					else{
+						memcpy((&(pts.adslAturChanInfo_pt->interleaveDelay)), RxMessage+4, ((RxMessage[0]&0xf)*2));
+					}
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslAturChanInfo_pt->flags)), ATUR_CHAN_CURR_TX_RATE_FLAG)){
+				ATUR_CHAN_CURR_TX_RATE_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 6 Address 0 Index 0");
+#endif
+					CLR_FLAG((&(pts.adslAturChanInfo_pt->flags)), ATUR_CHAN_CURR_TX_RATE_FLAG);	
+				}	
+				else{
+					pts.adslAturChanInfo_pt->currTxRate = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16);
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslAturChanInfo_pt->flags)), ATUR_CHAN_PREV_TX_RATE_FLAG)){
+				pts.adslAturChanInfo_pt->prevTxRate = PrevTxRate.adslAturChanPrevTxRate;
+			}
+			if(IS_FLAG_SET((&(pts.adslAturChanInfo_pt->flags)), ATUR_CHAN_CRC_BLK_LEN_FLAG)){
+				// ? no CMV to update this 
+				CLR_FLAG((&(pts.adslAturChanInfo_pt->flags)), ATUR_CHAN_CRC_BLK_LEN_FLAG);
+			}
+			copy_to_user((char *)lon, (char *)pts.adslAturChanInfo_pt, sizeof(adslAturChanInfo));
+			kfree(pts.adslAturChanInfo_pt);
+			
+			up(&mei_sema);
+			break;
+		case GET_ADSL_ATUC_PERF_DATA:
+			pts.atucPerfDataEntry_pt = (atucPerfDataEntry *)kmalloc(sizeof(atucPerfDataEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.atucPerfDataEntry_pt, (char *)lon, sizeof(atucPerfDataEntry));
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_LOFS_FLAG)){
+				pts.atucPerfDataEntry_pt->adslAtucPerfLofs=ATUC_PERF_LOFS;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_LOSS_FLAG)){
+				pts.atucPerfDataEntry_pt->adslAtucPerfLoss=ATUC_PERF_LOSS;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_ESS_FLAG)){
+				pts.atucPerfDataEntry_pt->adslAtucPerfESs=ATUC_PERF_ESS;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_INITS_FLAG)){
+				pts.atucPerfDataEntry_pt->adslAtucPerfInits=ATUC_PERF_INITS;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_VALID_INTVLS_FLAG)){
+				i=0;
+				for(ptr=(current_intvl->list).prev; ptr!=&interval_list; ptr=ptr->prev){
+					i++;
+					if(i==96)
+						break;
+				}
+				pts.atucPerfDataEntry_pt->adslAtucPerfValidIntervals=i;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_INVALID_INTVLS_FLAG)){
+				pts.atucPerfDataEntry_pt->adslAtucPerfInvalidIntervals=0;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_CURR_15MIN_TIME_ELAPSED_FLAG)){
+				do_gettimeofday(&time_now);
+				pts.atucPerfDataEntry_pt->adslAtucPerfCurr15MinTimeElapsed=time_now.tv_sec - (current_intvl->start_time).tv_sec;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_CURR_15MIN_LOFS_FLAG)){
+				pts.atucPerfDataEntry_pt->adslAtucPerfCurr15MinLofs=current_intvl->AtucPerfLof;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_CURR_15MIN_LOSS_FLAG)){
+				pts.atucPerfDataEntry_pt->adslAtucPerfCurr15MinLoss=current_intvl->AtucPerfLos;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_CURR_15MIN_ESS_FLAG)){
+				pts.atucPerfDataEntry_pt->adslAtucPerfCurr15MinESs=current_intvl->AtucPerfEs;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_CURR_15MIN_INIT_FLAG)){
+				pts.atucPerfDataEntry_pt->adslAtucPerfCurr15MinInits=current_intvl->AtucPerfInit;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_CURR_1DAY_TIME_ELAPSED_FLAG)){
+				i=0;		
+				for(ptr=(current_intvl->list).prev; ptr!=&interval_list; ptr=ptr->prev){
+					i+=900;	
+				}
+				do_gettimeofday(&time_now);
+				i+=time_now.tv_sec - (current_intvl->start_time).tv_sec;
+				if(i>=86400)
+					pts.atucPerfDataEntry_pt->adslAtucPerfCurr1DayTimeElapsed=i-86400;
+				else
+					pts.atucPerfDataEntry_pt->adslAtucPerfCurr1DayTimeElapsed=i;		
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_CURR_1DAY_LOFS_FLAG)){		
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfLof;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AtucPerfLof;
+				pts.atucPerfDataEntry_pt->adslAtucPerfCurr1DayLofs=j;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_CURR_1DAY_LOSS_FLAG)){		
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfLos;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AtucPerfLos;
+				pts.atucPerfDataEntry_pt->adslAtucPerfCurr1DayLoss=j;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_CURR_1DAY_ESS_FLAG)){		
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfEs;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AtucPerfEs;
+				pts.atucPerfDataEntry_pt->adslAtucPerfCurr1DayESs=j;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_CURR_1DAY_INIT_FLAG)){		
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfInit;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AtucPerfInit;
+				pts.atucPerfDataEntry_pt->adslAtucPerfCurr1DayInits=j;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_PREV_1DAY_MON_SEC_FLAG)){		
+				i=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					i++;		
+				}
+				if(i>=96)
+					pts.atucPerfDataEntry_pt->adslAtucPerfPrev1DayMoniSecs=86400;
+				else
+					pts.atucPerfDataEntry_pt->adslAtucPerfPrev1DayMoniSecs=0;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_PREV_1DAY_LOFS_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfLof;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.atucPerfDataEntry_pt->adslAtucPerfPrev1DayLofs=j;
+				else
+					pts.atucPerfDataEntry_pt->adslAtucPerfPrev1DayLofs=0;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_PREV_1DAY_LOSS_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfLos;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.atucPerfDataEntry_pt->adslAtucPerfPrev1DayLoss=j;
+				else
+					pts.atucPerfDataEntry_pt->adslAtucPerfPrev1DayLoss=0;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_PREV_1DAY_ESS_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfEs;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.atucPerfDataEntry_pt->adslAtucPerfPrev1DayESs=j;
+				else
+					pts.atucPerfDataEntry_pt->adslAtucPerfPrev1DayESs=0;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataEntry_pt->flags)), ATUC_PERF_PREV_1DAY_INITS_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfInit;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.atucPerfDataEntry_pt->adslAtucPerfPrev1DayInits=j;
+				else
+					pts.atucPerfDataEntry_pt->adslAtucPerfPrev1DayInits=0;
+			}
+			
+			copy_to_user((char *)lon, (char *)pts.atucPerfDataEntry_pt, sizeof(atucPerfDataEntry));
+			kfree(pts.atucPerfDataEntry_pt);
+			break;
+#ifdef AMAZON_MEI_MIB_RFC3440
+		case GET_ADSL_ATUC_PERF_DATA_EXT:	//??? CMV mapping not available
+			pts.atucPerfDataExtEntry_pt = (atucPerfDataExtEntry *)kmalloc(sizeof(atucPerfDataExtEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.atucPerfDataExtEntry_pt, (char *)lon, sizeof(atucPerfDataExtEntry));
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_STAT_FASTR_FLAG)){
+				pts.atucPerfDataExtEntry_pt->adslAtucPerfStatFastR=ATUC_PERF_STAT_FASTR;
+			}	
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_STAT_FAILED_FASTR_FLAG)){
+				pts.atucPerfDataExtEntry_pt->adslAtucPerfStatFailedFastR=ATUC_PERF_STAT_FAILED_FASTR;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_STAT_SESL_FLAG)){
+				pts.atucPerfDataExtEntry_pt->adslAtucPerfStatSesL=ATUC_PERF_STAT_SESL;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_STAT_UASL_FLAG)){
+				pts.atucPerfDataExtEntry_pt->adslAtucPerfStatUasL=ATUC_PERF_STAT_UASL;
+			}	
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_CURR_15MIN_FASTR_FLAG)){
+				pts.atucPerfDataExtEntry_pt->adslAtucPerfCurr15MinFastR=current_intvl->AtucPerfStatFastR;
+			}	
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_CURR_15MIN_FAILED_FASTR_FLAG)){
+				pts.atucPerfDataExtEntry_pt->adslAtucPerfCurr15MinFailedFastR=current_intvl->AtucPerfStatFailedFastR;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_CURR_15MIN_SESL_FLAG)){
+				pts.atucPerfDataExtEntry_pt->adslAtucPerfCurr15MinSesL=current_intvl->AtucPerfStatSesL;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_CURR_15MIN_UASL_FLAG)){
+				pts.atucPerfDataExtEntry_pt->adslAtucPerfCurr15MinUasL=current_intvl->AtucPerfStatUasL;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_CURR_1DAY_FASTR_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfStatFastR;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AtucPerfStatFastR;
+				pts.atucPerfDataExtEntry_pt->adslAtucPerfCurr1DayFastR=j;
+			}	
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_CURR_1DAY_FAILED_FASTR_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfStatFailedFastR;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AtucPerfStatFailedFastR;
+				pts.atucPerfDataExtEntry_pt->adslAtucPerfCurr1DayFailedFastR=j;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_CURR_1DAY_SESL_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfStatSesL;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AtucPerfStatSesL;
+				pts.atucPerfDataExtEntry_pt->adslAtucPerfCurr1DaySesL=j;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_CURR_1DAY_UASL_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfStatUasL;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AtucPerfStatUasL;
+				pts.atucPerfDataExtEntry_pt->adslAtucPerfCurr1DayUasL=j;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_PREV_1DAY_FASTR_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfStatFastR;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.atucPerfDataExtEntry_pt->adslAtucPerfPrev1DayFastR=j;
+				else
+					pts.atucPerfDataExtEntry_pt->adslAtucPerfPrev1DayFastR=0;
+			}	
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_PREV_1DAY_FAILED_FASTR_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfStatFailedFastR;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.atucPerfDataExtEntry_pt->adslAtucPerfPrev1DayFailedFastR=j;
+				else
+					pts.atucPerfDataExtEntry_pt->adslAtucPerfPrev1DayFailedFastR=0;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_PREV_1DAY_SESL_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfStatSesL;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.atucPerfDataExtEntry_pt->adslAtucPerfPrev1DaySesL=j;
+				else
+					pts.atucPerfDataExtEntry_pt->adslAtucPerfPrev1DaySesL=0;
+			}
+			if(IS_FLAG_SET((&(pts.atucPerfDataExtEntry_pt->flags)), ATUC_PERF_PREV_1DAY_UASL_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AtucPerfStatUasL;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.atucPerfDataExtEntry_pt->adslAtucPerfPrev1DayUasL=j;
+				else
+					pts.atucPerfDataExtEntry_pt->adslAtucPerfPrev1DayUasL=0;
+			}
+			copy_to_user((char *)lon, (char *)pts.atucPerfDataExtEntry_pt, sizeof(atucPerfDataExtEntry));
+			kfree(pts.atucPerfDataExtEntry_pt);
+			break;
+#endif
+		case GET_ADSL_ATUR_PERF_DATA:
+			pts.aturPerfDataEntry_pt = (aturPerfDataEntry *)kmalloc(sizeof(aturPerfDataEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.aturPerfDataEntry_pt, (char *)lon, sizeof(aturPerfDataEntry));
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_LOFS_FLAG)){
+				pts.aturPerfDataEntry_pt->adslAturPerfLofs=ATUR_PERF_LOFS;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_LOSS_FLAG)){
+				pts.aturPerfDataEntry_pt->adslAturPerfLoss=ATUR_PERF_LOSS;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_LPR_FLAG)){
+				pts.aturPerfDataEntry_pt->adslAturPerfLprs=ATUR_PERF_LPR;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_ESS_FLAG)){
+				pts.aturPerfDataEntry_pt->adslAturPerfESs=ATUR_PERF_ESS;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_VALID_INTVLS_FLAG)){
+				i=0;
+				for(ptr=(current_intvl->list).prev; ptr!=&interval_list; ptr=ptr->prev){
+					i++;
+					if(i==96)
+						break;
+				}
+				pts.aturPerfDataEntry_pt->adslAturPerfValidIntervals=i;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_INVALID_INTVLS_FLAG)){
+				pts.aturPerfDataEntry_pt->adslAturPerfInvalidIntervals=0;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_CURR_15MIN_TIME_ELAPSED_FLAG)){
+				do_gettimeofday(&time_now);
+				pts.aturPerfDataEntry_pt->adslAturPerfCurr15MinTimeElapsed=time_now.tv_sec - (current_intvl->start_time).tv_sec;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_CURR_15MIN_LOFS_FLAG)){
+				pts.aturPerfDataEntry_pt->adslAturPerfCurr15MinLofs=current_intvl->AturPerfLof;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_CURR_15MIN_LOSS_FLAG)){
+				pts.aturPerfDataEntry_pt->adslAturPerfCurr15MinLoss=current_intvl->AturPerfLos;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_CURR_15MIN_LPR_FLAG)){
+				pts.aturPerfDataEntry_pt->adslAturPerfCurr15MinLprs=current_intvl->AturPerfLpr;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_CURR_15MIN_ESS_FLAG)){
+				pts.aturPerfDataEntry_pt->adslAturPerfCurr15MinESs=current_intvl->AturPerfEs;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_CURR_1DAY_TIME_ELAPSED_FLAG)){
+				i=0;		
+				for(ptr=(current_intvl->list).prev; ptr!=&interval_list; ptr=ptr->prev){
+					i+=900;	
+				}
+				do_gettimeofday(&time_now);
+				i+=time_now.tv_sec - (current_intvl->start_time).tv_sec;
+				if(i>=86400)
+					pts.aturPerfDataEntry_pt->adslAturPerfCurr1DayTimeElapsed=i-86400;
+				else
+					pts.aturPerfDataEntry_pt->adslAturPerfCurr1DayTimeElapsed=i;		
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_CURR_1DAY_LOFS_FLAG)){		
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturPerfLof;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AturPerfLof;
+				pts.aturPerfDataEntry_pt->adslAturPerfCurr1DayLofs=j;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_CURR_1DAY_LOSS_FLAG)){		
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturPerfLos;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AturPerfLos;
+				pts.aturPerfDataEntry_pt->adslAturPerfCurr1DayLoss=j;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_CURR_1DAY_LPR_FLAG)){		
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturPerfLpr;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AturPerfLpr;
+				pts.aturPerfDataEntry_pt->adslAturPerfCurr1DayLprs=j;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_CURR_1DAY_ESS_FLAG)){		
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturPerfEs;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AturPerfEs;
+				pts.aturPerfDataEntry_pt->adslAturPerfCurr1DayESs=j;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_PREV_1DAY_MON_SEC_FLAG)){		
+				i=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					i++;		
+				}
+				if(i>=96)
+					pts.aturPerfDataEntry_pt->adslAturPerfPrev1DayMoniSecs=86400;
+				else
+					pts.aturPerfDataEntry_pt->adslAturPerfPrev1DayMoniSecs=0;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_PREV_1DAY_LOFS_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturPerfLof;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.aturPerfDataEntry_pt->adslAturPerfPrev1DayLofs=j;
+				else
+					pts.aturPerfDataEntry_pt->adslAturPerfPrev1DayLofs=0;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_PREV_1DAY_LOSS_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturPerfLos;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.aturPerfDataEntry_pt->adslAturPerfPrev1DayLoss=j;
+				else
+					pts.aturPerfDataEntry_pt->adslAturPerfPrev1DayLoss=0;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_PREV_1DAY_LPR_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturPerfLpr;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.aturPerfDataEntry_pt->adslAturPerfPrev1DayLprs=j;
+				else
+					pts.aturPerfDataEntry_pt->adslAturPerfPrev1DayLprs=0;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataEntry_pt->flags)), ATUR_PERF_PREV_1DAY_ESS_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturPerfEs;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.aturPerfDataEntry_pt->adslAturPerfPrev1DayESs=j;
+				else
+					pts.aturPerfDataEntry_pt->adslAturPerfPrev1DayESs=0;
+			}		
+			
+			copy_to_user((char *)lon, (char *)pts.aturPerfDataEntry_pt, sizeof(aturPerfDataEntry));
+			kfree(pts.aturPerfDataEntry_pt);
+			break;
+#ifdef AMAZON_MEI_MIB_RFC3440
+		case GET_ADSL_ATUR_PERF_DATA_EXT:
+			pts.aturPerfDataExtEntry_pt = (aturPerfDataExtEntry *)kmalloc(sizeof(aturPerfDataExtEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.aturPerfDataExtEntry_pt, (char *)lon, sizeof(aturPerfDataExtEntry));
+			if(IS_FLAG_SET((&(pts.aturPerfDataExtEntry_pt->flags)), ATUR_PERF_STAT_SESL_FLAG)){
+				pts.aturPerfDataExtEntry_pt->adslAturPerfStatSesL=ATUR_PERF_STAT_SESL;
+			}	
+			if(IS_FLAG_SET((&(pts.aturPerfDataExtEntry_pt->flags)), ATUR_PERF_STAT_UASL_FLAG)){
+				pts.aturPerfDataExtEntry_pt->adslAturPerfStatUasL=ATUR_PERF_STAT_UASL;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataExtEntry_pt->flags)), ATUR_PERF_CURR_15MIN_SESL_FLAG)){
+				pts.aturPerfDataExtEntry_pt->adslAturPerfCurr15MinSesL=current_intvl->AturPerfStatSesL;
+			}	
+			if(IS_FLAG_SET((&(pts.aturPerfDataExtEntry_pt->flags)), ATUR_PERF_CURR_15MIN_UASL_FLAG)){
+				pts.aturPerfDataExtEntry_pt->adslAturPerfCurr15MinUasL=current_intvl->AturPerfStatUasL;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataExtEntry_pt->flags)), ATUR_PERF_CURR_1DAY_SESL_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturPerfStatSesL;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AturPerfStatSesL;
+				pts.aturPerfDataExtEntry_pt->adslAturPerfCurr1DaySesL=j;	
+			}	
+			if(IS_FLAG_SET((&(pts.aturPerfDataExtEntry_pt->flags)), ATUR_PERF_CURR_1DAY_UASL_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturPerfStatUasL;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AturPerfStatUasL;
+				pts.aturPerfDataExtEntry_pt->adslAturPerfCurr1DayUasL=j;
+			}
+			if(IS_FLAG_SET((&(pts.aturPerfDataExtEntry_pt->flags)), ATUR_PERF_PREV_1DAY_SESL_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturPerfStatSesL;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.aturPerfDataExtEntry_pt->adslAturPerfPrev1DaySesL=j;
+				else
+					pts.aturPerfDataExtEntry_pt->adslAturPerfPrev1DaySesL=0;	
+			}	
+			if(IS_FLAG_SET((&(pts.aturPerfDataExtEntry_pt->flags)), ATUR_PERF_PREV_1DAY_UASL_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturPerfStatUasL;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.aturPerfDataExtEntry_pt->adslAturPerfPrev1DayUasL=j;
+				else
+					pts.aturPerfDataExtEntry_pt->adslAturPerfPrev1DayUasL=0;
+			}
+			copy_to_user((char *)lon, (char *)pts.aturPerfDataExtEntry_pt, sizeof(aturPerfDataExtEntry));
+			kfree(pts.aturPerfDataExtEntry_pt);
+			break;
+#endif
+		case GET_ADSL_ATUC_INTVL_INFO:
+			pts.adslAtucIntvlInfo_pt = (adslAtucIntvlInfo *)kmalloc(sizeof(adslAtucIntvlInfo), GFP_KERNEL);
+			copy_from_user((char *)pts.adslAtucIntvlInfo_pt, (char *)lon, sizeof(adslAtucIntvlInfo));
+			
+			if(pts.adslAtucIntvlInfo_pt->IntervalNumber <1){
+				pts.adslAtucIntvlInfo_pt->intervalLOF = ATUC_PERF_LOFS;
+				pts.adslAtucIntvlInfo_pt->intervalLOS = ATUC_PERF_LOSS;
+				pts.adslAtucIntvlInfo_pt->intervalES = ATUC_PERF_ESS;
+				pts.adslAtucIntvlInfo_pt->intervalInits = ATUC_PERF_INITS;
+				pts.adslAtucIntvlInfo_pt->intervalValidData = 1;	
+			}
+			else{
+				i=0;
+				for(ptr=(current_intvl->list).prev; ptr!=&interval_list; ptr=ptr->prev){
+					i++;
+					if(i==pts.adslAtucIntvlInfo_pt->IntervalNumber){
+						temp_intvl = list_entry(ptr, amazon_mei_mib, list);
+						pts.adslAtucIntvlInfo_pt->intervalLOF = temp_intvl->AtucPerfLof;
+						pts.adslAtucIntvlInfo_pt->intervalLOS = temp_intvl->AtucPerfLos;
+						pts.adslAtucIntvlInfo_pt->intervalES = temp_intvl->AtucPerfEs;
+						pts.adslAtucIntvlInfo_pt->intervalInits = temp_intvl->AtucPerfInit;
+						pts.adslAtucIntvlInfo_pt->intervalValidData = 1;
+						break;
+					}		
+				}
+				if(ptr==&interval_list){
+					pts.adslAtucIntvlInfo_pt->intervalValidData = 0;
+					pts.adslAtucIntvlInfo_pt->flags = 0;
+					pts.adslAtucIntvlInfo_pt->intervalLOF = 0;
+					pts.adslAtucIntvlInfo_pt->intervalLOS = 0;
+					pts.adslAtucIntvlInfo_pt->intervalES = 0;
+					pts.adslAtucIntvlInfo_pt->intervalInits = 0;	
+				}
+			}
+									
+			copy_to_user((char *)lon, (char *)pts.adslAtucIntvlInfo_pt, sizeof(adslAtucIntvlInfo));
+			kfree(pts.adslAtucIntvlInfo_pt);
+			break;
+#ifdef AMAZON_MEI_MIB_RFC3440
+		case GET_ADSL_ATUC_INTVL_EXT_INFO:
+			pts.adslAtucInvtlExtInfo_pt = (adslAtucInvtlExtInfo *)kmalloc(sizeof(adslAtucInvtlExtInfo), GFP_KERNEL);
+			copy_from_user((char *)pts.adslAtucInvtlExtInfo_pt, (char *)lon, sizeof(adslAtucInvtlExtInfo));
+			if(pts.adslAtucInvtlExtInfo_pt->IntervalNumber <1){
+				pts.adslAtucInvtlExtInfo_pt->adslAtucIntervalFastR = ATUC_PERF_STAT_FASTR;
+				pts.adslAtucInvtlExtInfo_pt->adslAtucIntervalFailedFastR = ATUC_PERF_STAT_FAILED_FASTR;
+				pts.adslAtucInvtlExtInfo_pt->adslAtucIntervalSesL = ATUC_PERF_STAT_SESL;
+				pts.adslAtucInvtlExtInfo_pt->adslAtucIntervalUasL = ATUC_PERF_STAT_UASL;
+//				pts.adslAtucInvtlExtInfo_pt->intervalValidData = 1;	
+			}
+			else{
+				i=0;
+				for(ptr=(current_intvl->list).prev; ptr!=&interval_list; ptr=ptr->prev){
+					i++;
+					if(i==pts.adslAtucInvtlExtInfo_pt->IntervalNumber){
+						temp_intvl = list_entry(ptr, amazon_mei_mib, list);
+						pts.adslAtucInvtlExtInfo_pt->adslAtucIntervalFastR = temp_intvl->AtucPerfStatFastR;
+						pts.adslAtucInvtlExtInfo_pt->adslAtucIntervalFailedFastR = temp_intvl->AtucPerfStatFailedFastR;
+						pts.adslAtucInvtlExtInfo_pt->adslAtucIntervalSesL = temp_intvl->AtucPerfStatSesL;
+						pts.adslAtucInvtlExtInfo_pt->adslAtucIntervalUasL = temp_intvl->AtucPerfStatUasL;
+//						pts.adslAtucInvtlExtInfo_pt->intervalValidData = 1;
+						break;
+					}		
+				} 
+				if(ptr==&interval_list){
+//					pts.adslAtucInvtlExtInfo_pt->intervalValidData = 0;
+					pts.adslAtucInvtlExtInfo_pt->flags = 0;	
+					pts.adslAtucInvtlExtInfo_pt->adslAtucIntervalFastR = 0;
+					pts.adslAtucInvtlExtInfo_pt->adslAtucIntervalFailedFastR = 0;
+					pts.adslAtucInvtlExtInfo_pt->adslAtucIntervalSesL = 0;
+					pts.adslAtucInvtlExtInfo_pt->adslAtucIntervalUasL = 0;
+				}
+			}
+			copy_to_user((char *)lon, (char *)pts.adslAtucInvtlExtInfo_pt, sizeof(adslAtucInvtlExtInfo));
+			kfree(pts.adslAtucInvtlExtInfo_pt);
+			break;
+#endif
+		case GET_ADSL_ATUR_INTVL_INFO:
+			pts.adslAturIntvlInfo_pt = (adslAturIntvlInfo *)kmalloc(sizeof(adslAturIntvlInfo), GFP_KERNEL);
+			copy_from_user((char *)pts.adslAturIntvlInfo_pt, (char *)lon, sizeof(adslAturIntvlInfo));
+			
+			if(pts.adslAturIntvlInfo_pt->IntervalNumber <1){
+				pts.adslAturIntvlInfo_pt->intervalLOF = ATUR_PERF_LOFS;
+				pts.adslAturIntvlInfo_pt->intervalLOS = ATUR_PERF_LOSS;
+				pts.adslAturIntvlInfo_pt->intervalES = ATUR_PERF_ESS;
+				pts.adslAturIntvlInfo_pt->intervalLPR = ATUR_PERF_LPR;
+				pts.adslAturIntvlInfo_pt->intervalValidData = 1;	
+			}
+			else{
+				i=0;
+				for(ptr=(current_intvl->list).prev; ptr!=&interval_list; ptr=ptr->prev){
+					i++;
+					if(i==pts.adslAturIntvlInfo_pt->IntervalNumber){
+						temp_intvl = list_entry(ptr, amazon_mei_mib, list);
+						pts.adslAturIntvlInfo_pt->intervalLOF = temp_intvl->AturPerfLof;
+						pts.adslAturIntvlInfo_pt->intervalLOS = temp_intvl->AturPerfLos;
+						pts.adslAturIntvlInfo_pt->intervalES = temp_intvl->AturPerfEs;
+						pts.adslAturIntvlInfo_pt->intervalLPR = temp_intvl->AturPerfLpr;
+						pts.adslAturIntvlInfo_pt->intervalValidData = 1;
+						break;
+					}		
+				}
+				if(ptr==&interval_list){
+					pts.adslAturIntvlInfo_pt->intervalValidData = 0;
+					pts.adslAturIntvlInfo_pt->flags = 0;
+					pts.adslAturIntvlInfo_pt->intervalLOF = 0;
+					pts.adslAturIntvlInfo_pt->intervalLOS = 0;
+					pts.adslAturIntvlInfo_pt->intervalES = 0;
+					pts.adslAturIntvlInfo_pt->intervalLPR = 0;	
+				}
+			}
+			
+			copy_to_user((char *)lon, (char *)pts.adslAturIntvlInfo_pt, sizeof(adslAturIntvlInfo));
+			kfree(pts.adslAturIntvlInfo_pt);
+			break;
+#ifdef AMAZON_MEI_MIB_RFC3440
+		case GET_ADSL_ATUR_INTVL_EXT_INFO:
+			pts.adslAturInvtlExtInfo_pt = (adslAturInvtlExtInfo *)kmalloc(sizeof(adslAturInvtlExtInfo), GFP_KERNEL);
+			copy_from_user((char *)pts.adslAturInvtlExtInfo_pt, (char *)lon, sizeof(adslAturInvtlExtInfo));
+			
+			if(pts.adslAturInvtlExtInfo_pt->IntervalNumber <1){
+				pts.adslAturInvtlExtInfo_pt->adslAturIntervalSesL = ATUR_PERF_STAT_SESL;
+				pts.adslAturInvtlExtInfo_pt->adslAturIntervalUasL = ATUR_PERF_STAT_UASL;
+//				pts.adslAturInvtlExtInfo_pt->intervalValidData = 1;
+			}
+			else{
+				i=0;
+				for(ptr=(current_intvl->list).prev; ptr!=&interval_list; ptr=ptr->prev){
+					i++;
+					if(i==pts.adslAturInvtlExtInfo_pt->IntervalNumber){
+						temp_intvl = list_entry(ptr, amazon_mei_mib, list);
+						pts.adslAturInvtlExtInfo_pt->adslAturIntervalSesL = temp_intvl->AturPerfStatSesL;
+						pts.adslAturInvtlExtInfo_pt->adslAturIntervalUasL = temp_intvl->AturPerfStatUasL;
+//						pts.adslAturInvtlExtInfo_pt->intervalValidData = 1;
+						break; 
+					}		
+				}
+				if(ptr==&interval_list){
+//					pts.adslAturInvtlExtInfo_pt->intervalValidData = 0;
+					pts.adslAturInvtlExtInfo_pt->flags = 0;	
+					pts.adslAturInvtlExtInfo_pt->adslAturIntervalSesL = 0;
+					pts.adslAturInvtlExtInfo_pt->adslAturIntervalUasL = 0; 
+				}
+			}
+			
+			copy_to_user((char *)lon, (char *)pts.adslAturInvtlExtInfo_pt, sizeof(adslAturInvtlExtInfo));
+			kfree(pts.adslAturInvtlExtInfo_pt);
+			break;
+#endif
+		case GET_ADSL_ATUC_CHAN_PERF_DATA:
+			pts.atucChannelPerfDataEntry_pt = (atucChannelPerfDataEntry *)kmalloc(sizeof(atucChannelPerfDataEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.atucChannelPerfDataEntry_pt, (char *)lon, sizeof(atucChannelPerfDataEntry));
+	
+			pts.atucChannelPerfDataEntry_pt->flags = 0;
+			
+			copy_to_user((char *)lon, (char *)pts.atucChannelPerfDataEntry_pt, sizeof(atucChannelPerfDataEntry));
+			kfree(pts.atucChannelPerfDataEntry_pt);
+			break;
+		case GET_ADSL_ATUR_CHAN_PERF_DATA:
+			pts.aturChannelPerfDataEntry_pt = (aturChannelPerfDataEntry *)kmalloc(sizeof(aturChannelPerfDataEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.aturChannelPerfDataEntry_pt, (char *)lon, sizeof(aturChannelPerfDataEntry));
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_RECV_BLK_FLAG)){
+				pts.aturChannelPerfDataEntry_pt->adslAturChanReceivedBlks=ATUR_CHAN_RECV_BLK;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_TX_BLK_FLAG)){
+				pts.aturChannelPerfDataEntry_pt->adslAturChanTransmittedBlks=ATUR_CHAN_TX_BLK;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_CORR_BLK_FLAG)){
+				pts.aturChannelPerfDataEntry_pt->adslAturChanCorrectedBlks=ATUR_CHAN_CORR_BLK;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_UNCORR_BLK_FLAG)){
+				pts.aturChannelPerfDataEntry_pt->adslAturChanUncorrectBlks=ATUR_CHAN_UNCORR_BLK;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_VALID_INTVL_FLAG)){
+				i=0;
+				for(ptr=(current_intvl->list).prev; ptr!=&interval_list; ptr=ptr->prev){
+					i++;
+					if(i==96)
+						break;
+				}
+				pts.aturChannelPerfDataEntry_pt->adslAturChanPerfValidIntervals=i;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_INVALID_INTVL_FLAG)){
+				pts.aturChannelPerfDataEntry_pt->adslAturChanPerfInvalidIntervals=0;
+			}
+ 			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_CURR_15MIN_TIME_ELAPSED_FLAG)){
+				do_gettimeofday(&time_now);
+				pts.aturChannelPerfDataEntry_pt->adslAturChanPerfCurr15MinTimeElapsed=time_now.tv_sec - (current_intvl->start_time).tv_sec;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_CURR_15MIN_RECV_BLK_FLAG)){
+				pts.aturChannelPerfDataEntry_pt->adslAturChanPerfCurr15MinReceivedBlks=current_intvl->AturChanPerfRxBlk;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_CURR_15MIN_TX_BLK_FLAG)){
+				pts.aturChannelPerfDataEntry_pt->adslAturChanPerfCurr15MinTransmittedBlks=current_intvl->AturChanPerfTxBlk;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_CURR_15MIN_CORR_BLK_FLAG)){
+				pts.aturChannelPerfDataEntry_pt->adslAturChanPerfCurr15MinCorrectedBlks=current_intvl->AturChanPerfCorrBlk;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_CURR_15MIN_UNCORR_BLK_FLAG)){
+				pts.aturChannelPerfDataEntry_pt->adslAturChanPerfCurr15MinUncorrectBlks=current_intvl->AturChanPerfUncorrBlk;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_CURR_1DAY_TIME_ELAPSED_FLAG)){
+				i=0;		
+				for(ptr=(current_intvl->list).prev; ptr!=&interval_list; ptr=ptr->prev){
+					i+=900;	
+				}
+				do_gettimeofday(&time_now);
+				i+=time_now.tv_sec - (current_intvl->start_time).tv_sec;
+				if(i>=86400)
+					pts.aturChannelPerfDataEntry_pt->adslAturChanPerfCurr1DayTimeElapsed=i-86400;
+				else
+					pts.aturChannelPerfDataEntry_pt->adslAturChanPerfCurr1DayTimeElapsed=i;		
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_CURR_1DAY_RECV_BLK_FLAG)){		
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturChanPerfRxBlk;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AturChanPerfRxBlk;
+				pts.aturChannelPerfDataEntry_pt->adslAturChanPerfCurr1DayReceivedBlks=j;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_CURR_1DAY_TX_BLK_FLAG)){		
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturChanPerfTxBlk;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AturChanPerfTxBlk;
+				pts.aturChannelPerfDataEntry_pt->adslAturChanPerfCurr1DayTransmittedBlks=j;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_CURR_1DAY_CORR_BLK_FLAG)){		
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturChanPerfCorrBlk;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AturChanPerfCorrBlk;
+				pts.aturChannelPerfDataEntry_pt->adslAturChanPerfCurr1DayCorrectedBlks=j;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_CURR_1DAY_UNCORR_BLK_FLAG)){		
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturChanPerfUncorrBlk;
+					i++;	
+					if(i==96)
+						j=0;
+				}
+				j+=current_intvl->AturChanPerfUncorrBlk;
+				pts.aturChannelPerfDataEntry_pt->adslAturChanPerfCurr1DayUncorrectBlks=j;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_PREV_1DAY_MONI_SEC_FLAG)){		
+				i=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					i++;		
+				}
+				if(i>=96)
+					pts.aturChannelPerfDataEntry_pt->adslAturChanPerfPrev1DayMoniSecs=86400;
+				else
+					pts.aturChannelPerfDataEntry_pt->adslAturChanPerfPrev1DayMoniSecs=0;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_PREV_1DAY_RECV_BLK_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturChanPerfRxBlk;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.aturChannelPerfDataEntry_pt->adslAturChanPerfPrev1DayReceivedBlks=j;
+				else
+					pts.aturChannelPerfDataEntry_pt->adslAturChanPerfPrev1DayReceivedBlks=0;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_PREV_1DAY_TRANS_BLK_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturChanPerfTxBlk;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.aturChannelPerfDataEntry_pt->adslAturChanPerfPrev1DayTransmittedBlks=j;
+				else
+					pts.aturChannelPerfDataEntry_pt->adslAturChanPerfPrev1DayTransmittedBlks=0;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_PREV_1DAY_CORR_BLK_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturChanPerfCorrBlk;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.aturChannelPerfDataEntry_pt->adslAturChanPerfPrev1DayCorrectedBlks=j;
+				else
+					pts.aturChannelPerfDataEntry_pt->adslAturChanPerfPrev1DayCorrectedBlks=0;
+			}
+			if(IS_FLAG_SET((&(pts.aturChannelPerfDataEntry_pt->flags)), ATUR_CHAN_PERF_PREV_1DAY_UNCORR_BLK_FLAG)){
+				i=0;
+				j=0;
+				for(ptr=interval_list.next; ptr!=&(current_intvl->list); ptr=ptr->next){
+					mib_ptr = list_entry(ptr, amazon_mei_mib, list);
+					j+=mib_ptr->AturChanPerfUncorrBlk;
+					i++;
+					if(i==96)
+						break;
+				}	
+				if(i==96)
+					pts.aturChannelPerfDataEntry_pt->adslAturChanPerfPrev1DayUncorrectBlks=j;
+				else
+					pts.aturChannelPerfDataEntry_pt->adslAturChanPerfPrev1DayUncorrectBlks=0;
+			}
+			
+			copy_to_user((char *)lon, (char *)pts.aturChannelPerfDataEntry_pt, sizeof(aturChannelPerfDataEntry));
+			kfree(pts.aturChannelPerfDataEntry_pt);
+			break;
+		case GET_ADSL_ATUC_CHAN_INTVL_INFO:
+			pts.adslAtucChanIntvlInfo_pt = (adslAtucChanIntvlInfo *)kmalloc(sizeof(adslAtucChanIntvlInfo), GFP_KERNEL);
+			copy_from_user((char *)pts.adslAtucChanIntvlInfo_pt, (char *)lon, sizeof(adslAtucChanIntvlInfo));
+				
+				pts.adslAtucChanIntvlInfo_pt->flags = 0;
+				
+			copy_to_user((char *)lon, (char *)pts.adslAtucChanIntvlInfo_pt, sizeof(adslAtucChanIntvlInfo));
+			kfree(pts.adslAtucChanIntvlInfo_pt);
+			break;
+		case GET_ADSL_ATUR_CHAN_INTVL_INFO:
+			pts.adslAturChanIntvlInfo_pt = (adslAturChanIntvlInfo *)kmalloc(sizeof(adslAturChanIntvlInfo), GFP_KERNEL);
+			copy_from_user((char *)pts.adslAturChanIntvlInfo_pt, (char *)lon, sizeof(adslAturChanIntvlInfo));
+			
+			if(pts.adslAturChanIntvlInfo_pt->IntervalNumber <1){
+				pts.adslAturChanIntvlInfo_pt->chanIntervalRecvdBlks = ATUR_CHAN_RECV_BLK;
+				pts.adslAturChanIntvlInfo_pt->chanIntervalXmitBlks = ATUR_CHAN_TX_BLK;
+				pts.adslAturChanIntvlInfo_pt->chanIntervalCorrectedBlks = ATUR_CHAN_CORR_BLK;
+				pts.adslAturChanIntvlInfo_pt->chanIntervalUncorrectBlks = ATUR_CHAN_UNCORR_BLK;
+				pts.adslAturChanIntvlInfo_pt->intervalValidData = 1;
+			}
+			else{
+				i=0;
+				for(ptr=(current_intvl->list).prev; ptr!=&interval_list; ptr=ptr->prev){
+					i++;
+					if(i==pts.adslAturChanIntvlInfo_pt->IntervalNumber){
+						temp_intvl = list_entry(ptr, amazon_mei_mib, list);
+						pts.adslAturChanIntvlInfo_pt->chanIntervalRecvdBlks = temp_intvl->AturChanPerfRxBlk;
+						pts.adslAturChanIntvlInfo_pt->chanIntervalXmitBlks = temp_intvl->AturChanPerfTxBlk;
+						pts.adslAturChanIntvlInfo_pt->chanIntervalCorrectedBlks = temp_intvl->AturChanPerfCorrBlk;
+						pts.adslAturChanIntvlInfo_pt->chanIntervalUncorrectBlks = temp_intvl->AturChanPerfUncorrBlk;
+						pts.adslAturChanIntvlInfo_pt->intervalValidData = 1;
+						break;
+					}		
+				}
+				if(ptr==&interval_list){
+					pts.adslAturChanIntvlInfo_pt->intervalValidData = 0;
+					pts.adslAturChanIntvlInfo_pt->flags = 0;	
+				}
+			}
+			
+			copy_to_user((char *)lon, (char *)pts.adslAturChanIntvlInfo_pt, sizeof(adslAturChanIntvlInfo));
+			kfree(pts.adslAturChanIntvlInfo_pt);
+			break;
+		case GET_ADSL_ALRM_CONF_PROF:
+			pts.adslLineAlarmConfProfileEntry_pt = (adslLineAlarmConfProfileEntry *)kmalloc(sizeof(adslLineAlarmConfProfileEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.adslLineAlarmConfProfileEntry_pt, (char *)lon, sizeof(adslLineAlarmConfProfileEntry));
+			
+			strncpy(pts.adslLineAlarmConfProfileEntry_pt->adslLineAlarmConfProfileName, AlarmConfProfile.adslLineAlarmConfProfileName, 32); 
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_15MIN_LOFS_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAtucThresh15MinLofs=AlarmConfProfile.adslAtucThresh15MinLofs;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_15MIN_LOSS_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAtucThresh15MinLoss=AlarmConfProfile.adslAtucThresh15MinLoss;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_15MIN_ESS_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAtucThresh15MinESs=AlarmConfProfile.adslAtucThresh15MinESs;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_FAST_RATEUP_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAtucThreshFastRateUp=AlarmConfProfile.adslAtucThreshFastRateUp;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_INTERLEAVE_RATEUP_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAtucThreshInterleaveRateUp=AlarmConfProfile.adslAtucThreshInterleaveRateUp;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_FAST_RATEDOWN_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAtucThreshFastRateDown=AlarmConfProfile.adslAtucThreshFastRateDown;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_INTERLEAVE_RATEDOWN_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAtucThreshInterleaveRateDown=AlarmConfProfile.adslAtucThreshInterleaveRateDown;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_INIT_FAILURE_TRAP_ENABLE_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAtucInitFailureTrapEnable=AlarmConfProfile.adslAtucInitFailureTrapEnable;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_15MIN_LOFS_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAturThresh15MinLofs=AlarmConfProfile.adslAturThresh15MinLofs;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_15MIN_LOSS_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAturThresh15MinLoss=AlarmConfProfile.adslAturThresh15MinLoss;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_15MIN_LPRS_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAturThresh15MinLprs=AlarmConfProfile.adslAturThresh15MinLprs;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_15MIN_ESS_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAturThresh15MinESs=AlarmConfProfile.adslAturThresh15MinESs;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_FAST_RATEUP_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAturThreshFastRateUp=AlarmConfProfile.adslAturThreshFastRateUp;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_INTERLEAVE_RATEUP_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAturThreshInterleaveRateUp=AlarmConfProfile.adslAturThreshInterleaveRateUp;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_FAST_RATEDOWN_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAturThreshFastRateDown=AlarmConfProfile.adslAturThreshFastRateDown;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_INTERLEAVE_RATEDOWN_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslAturThreshInterleaveRateDown=AlarmConfProfile.adslAturThreshInterleaveRateDown;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), LINE_ALARM_CONF_PROFILE_ROWSTATUS_FLAG)){
+				pts.adslLineAlarmConfProfileEntry_pt->adslLineAlarmConfProfileRowStatus=AlarmConfProfile.adslLineAlarmConfProfileRowStatus;
+			}
+			copy_to_user((char *)lon, (char *)pts.adslLineAlarmConfProfileEntry_pt, sizeof(adslLineAlarmConfProfileEntry));
+			kfree(pts.adslLineAlarmConfProfileEntry_pt);
+			break;
+#ifdef AMAZON_MEI_MIB_RFC3440
+		case GET_ADSL_ALRM_CONF_PROF_EXT:
+			pts.adslLineAlarmConfProfileExtEntry_pt = (adslLineAlarmConfProfileExtEntry *)kmalloc(sizeof(adslLineAlarmConfProfileExtEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.adslLineAlarmConfProfileExtEntry_pt, (char *)lon, sizeof(adslLineAlarmConfProfileExtEntry));
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileExtEntry_pt->flags)), ATUC_THRESH_15MIN_FAILED_FASTR_FLAG)){
+				pts.adslLineAlarmConfProfileExtEntry_pt->adslAtucThreshold15MinFailedFastR=AlarmConfProfileExt.adslAtucThreshold15MinFailedFastR;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileExtEntry_pt->flags)), ATUC_THRESH_15MIN_SESL_FLAG)){
+				pts.adslLineAlarmConfProfileExtEntry_pt->adslAtucThreshold15MinSesL=AlarmConfProfileExt.adslAtucThreshold15MinSesL;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileExtEntry_pt->flags)), ATUC_THRESH_15MIN_UASL_FLAG)){
+				pts.adslLineAlarmConfProfileExtEntry_pt->adslAtucThreshold15MinUasL=AlarmConfProfileExt.adslAtucThreshold15MinUasL;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileExtEntry_pt->flags)), ATUR_THRESH_15MIN_SESL_FLAG)){
+				pts.adslLineAlarmConfProfileExtEntry_pt->adslAturThreshold15MinSesL=AlarmConfProfileExt.adslAturThreshold15MinSesL;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileExtEntry_pt->flags)), ATUR_THRESH_15MIN_UASL_FLAG)){
+				pts.adslLineAlarmConfProfileExtEntry_pt->adslAturThreshold15MinUasL=AlarmConfProfileExt.adslAturThreshold15MinUasL;
+			}
+			copy_to_user((char *)lon, (char *)pts.adslLineAlarmConfProfileExtEntry_pt, sizeof(adslLineAlarmConfProfileExtEntry));
+			kfree(pts.adslLineAlarmConfProfileExtEntry_pt);
+			break;
+#endif
+		case SET_ADSL_ALRM_CONF_PROF:
+			pts.adslLineAlarmConfProfileEntry_pt = (adslLineAlarmConfProfileEntry *)kmalloc(sizeof(adslLineAlarmConfProfileEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.adslLineAlarmConfProfileEntry_pt, (char *)lon, sizeof(adslLineAlarmConfProfileEntry));
+
+			strncpy(AlarmConfProfile.adslLineAlarmConfProfileName, pts.adslLineAlarmConfProfileEntry_pt->adslLineAlarmConfProfileName, 32);
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_15MIN_LOFS_FLAG)){
+				AlarmConfProfile.adslAtucThresh15MinLofs=pts.adslLineAlarmConfProfileEntry_pt->adslAtucThresh15MinLofs;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_15MIN_LOSS_FLAG)){
+				AlarmConfProfile.adslAtucThresh15MinLoss=pts.adslLineAlarmConfProfileEntry_pt->adslAtucThresh15MinLoss;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_15MIN_ESS_FLAG)){
+				AlarmConfProfile.adslAtucThresh15MinESs=pts.adslLineAlarmConfProfileEntry_pt->adslAtucThresh15MinESs;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_FAST_RATEUP_FLAG)){
+				AlarmConfProfile.adslAtucThreshFastRateUp=pts.adslLineAlarmConfProfileEntry_pt->adslAtucThreshFastRateUp;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_INTERLEAVE_RATEUP_FLAG)){
+				AlarmConfProfile.adslAtucThreshInterleaveRateUp=pts.adslLineAlarmConfProfileEntry_pt->adslAtucThreshInterleaveRateUp;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_FAST_RATEDOWN_FLAG)){
+				AlarmConfProfile.adslAtucThreshFastRateDown=pts.adslLineAlarmConfProfileEntry_pt->adslAtucThreshFastRateDown;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_THRESH_INTERLEAVE_RATEDOWN_FLAG)){
+				AlarmConfProfile.adslAtucThreshInterleaveRateDown=pts.adslLineAlarmConfProfileEntry_pt->adslAtucThreshInterleaveRateDown;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUC_INIT_FAILURE_TRAP_ENABLE_FLAG)){
+				AlarmConfProfile.adslAtucInitFailureTrapEnable=pts.adslLineAlarmConfProfileEntry_pt->adslAtucInitFailureTrapEnable;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_15MIN_LOFS_FLAG)){
+				AlarmConfProfile.adslAturThresh15MinLofs=pts.adslLineAlarmConfProfileEntry_pt->adslAturThresh15MinLofs;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_15MIN_LOSS_FLAG)){
+				AlarmConfProfile.adslAturThresh15MinLoss=pts.adslLineAlarmConfProfileEntry_pt->adslAturThresh15MinLoss;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_15MIN_LPRS_FLAG)){
+				AlarmConfProfile.adslAturThresh15MinLprs=pts.adslLineAlarmConfProfileEntry_pt->adslAturThresh15MinLprs;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_15MIN_ESS_FLAG)){
+				AlarmConfProfile.adslAturThresh15MinESs=pts.adslLineAlarmConfProfileEntry_pt->adslAturThresh15MinESs;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_FAST_RATEUP_FLAG)){
+				AlarmConfProfile.adslAturThreshFastRateUp=pts.adslLineAlarmConfProfileEntry_pt->adslAturThreshFastRateUp;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_INTERLEAVE_RATEUP_FLAG)){
+				AlarmConfProfile.adslAturThreshInterleaveRateUp=pts.adslLineAlarmConfProfileEntry_pt->adslAturThreshInterleaveRateUp;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_FAST_RATEDOWN_FLAG)){
+				AlarmConfProfile.adslAturThreshFastRateDown=pts.adslLineAlarmConfProfileEntry_pt->adslAturThreshFastRateDown;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), ATUR_THRESH_INTERLEAVE_RATEDOWN_FLAG)){
+				AlarmConfProfile.adslAturThreshInterleaveRateDown=pts.adslLineAlarmConfProfileEntry_pt->adslAturThreshInterleaveRateDown;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileEntry_pt->flags)), LINE_ALARM_CONF_PROFILE_ROWSTATUS_FLAG)){
+				AlarmConfProfile.adslLineAlarmConfProfileRowStatus=pts.adslLineAlarmConfProfileEntry_pt->adslLineAlarmConfProfileRowStatus;
+			}
+			copy_to_user((char *)lon, (char *)pts.adslLineAlarmConfProfileEntry_pt, sizeof(adslLineAlarmConfProfileEntry));
+			kfree(pts.adslLineAlarmConfProfileEntry_pt);
+			break;
+			
+#ifdef AMAZON_MEI_MIB_RFC3440
+		case SET_ADSL_ALRM_CONF_PROF_EXT:
+			pts.adslLineAlarmConfProfileExtEntry_pt = (adslLineAlarmConfProfileExtEntry *)kmalloc(sizeof(adslLineAlarmConfProfileExtEntry), GFP_KERNEL);
+			copy_from_user((char *)pts.adslLineAlarmConfProfileExtEntry_pt, (char *)lon, sizeof(adslLineAlarmConfProfileExtEntry));
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileExtEntry_pt->flags)), ATUC_THRESH_15MIN_FAILED_FASTR_FLAG)){
+				AlarmConfProfileExt.adslAtucThreshold15MinFailedFastR=pts.adslLineAlarmConfProfileExtEntry_pt->adslAtucThreshold15MinFailedFastR;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileExtEntry_pt->flags)), ATUC_THRESH_15MIN_SESL_FLAG)){
+				AlarmConfProfileExt.adslAtucThreshold15MinSesL=pts.adslLineAlarmConfProfileExtEntry_pt->adslAtucThreshold15MinSesL;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileExtEntry_pt->flags)), ATUC_THRESH_15MIN_UASL_FLAG)){
+				AlarmConfProfileExt.adslAtucThreshold15MinUasL=pts.adslLineAlarmConfProfileExtEntry_pt->adslAtucThreshold15MinUasL;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileExtEntry_pt->flags)), ATUR_THRESH_15MIN_SESL_FLAG)){
+				AlarmConfProfileExt.adslAturThreshold15MinSesL=pts.adslLineAlarmConfProfileExtEntry_pt->adslAturThreshold15MinSesL;
+			}
+			if(IS_FLAG_SET((&(pts.adslLineAlarmConfProfileExtEntry_pt->flags)), ATUR_THRESH_15MIN_UASL_FLAG)){
+				AlarmConfProfileExt.adslAturThreshold15MinUasL=pts.adslLineAlarmConfProfileExtEntry_pt->adslAturThreshold15MinUasL;
+			}
+			copy_to_user((char *)lon, (char *)pts.adslLineAlarmConfProfileExtEntry_pt, sizeof(adslLineAlarmConfProfileExtEntry));
+			kfree(pts.adslLineAlarmConfProfileExtEntry_pt);
+			break;
+#endif
+
+		case ADSL_ATUR_TRAPS:
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+			
+			trapsflag=0;
+			if(AlarmConfProfile.adslAtucThresh15MinLofs!=0 && current_intvl->AtucPerfLof>=AlarmConfProfile.adslAtucThresh15MinLofs)
+				trapsflag|=ATUC_PERF_LOFS_THRESH_FLAG;
+			if(AlarmConfProfile.adslAtucThresh15MinLoss!=0 && current_intvl->AtucPerfLos>=AlarmConfProfile.adslAtucThresh15MinLoss)
+				trapsflag|=ATUC_PERF_LOSS_THRESH_FLAG;
+			if(AlarmConfProfile.adslAtucThresh15MinESs!=0 && current_intvl->AtucPerfEs>=AlarmConfProfile.adslAtucThresh15MinESs)
+				trapsflag|=ATUC_PERF_ESS_THRESH_FLAG;
+			if(chantype.fast==1){
+				if(AlarmConfProfile.adslAtucThreshFastRateUp!=0 || AlarmConfProfile.adslAtucThreshFastRateDown!=0){
+					ATUC_CHAN_CURR_TX_RATE_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 6 Address 1 Index 0");
+#endif			
+					}
+					else{
+						temp = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16); 
+						if((AlarmConfProfile.adslAtucThreshFastRateUp!=0) && (temp>=PrevTxRate.adslAtucChanPrevTxRate+AlarmConfProfile.adslAtucThreshFastRateUp)){
+							trapsflag|=ATUC_RATE_CHANGE_FLAG;
+							PrevTxRate.adslAtucChanPrevTxRate = temp;						
+						}
+						if((AlarmConfProfile.adslAtucThreshFastRateDown!=0) && (temp<=PrevTxRate.adslAtucChanPrevTxRate-AlarmConfProfile.adslAtucThreshFastRateDown)){
+							trapsflag|=ATUC_RATE_CHANGE_FLAG;
+							PrevTxRate.adslAtucChanPrevTxRate = temp;						
+						}
+					}
+				}
+			}	
+			if(chantype.interleave==1){
+				if(AlarmConfProfile.adslAtucThreshInterleaveRateUp!=0 || AlarmConfProfile.adslAtucThreshInterleaveRateDown!=0){
+					ATUC_CHAN_CURR_TX_RATE_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 6 Address 1 Index 0");
+#endif			
+					}
+					else{
+						temp = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16); 
+						if((AlarmConfProfile.adslAtucThreshInterleaveRateUp!=0) && (temp>=PrevTxRate.adslAtucChanPrevTxRate+AlarmConfProfile.adslAtucThreshInterleaveRateUp)){
+							trapsflag|=ATUC_RATE_CHANGE_FLAG;
+							PrevTxRate.adslAtucChanPrevTxRate = temp;						
+						}
+						if((AlarmConfProfile.adslAtucThreshInterleaveRateDown!=0) && (temp<=PrevTxRate.adslAtucChanPrevTxRate-AlarmConfProfile.adslAtucThreshInterleaveRateDown)){
+							trapsflag|=ATUC_RATE_CHANGE_FLAG;
+							PrevTxRate.adslAtucChanPrevTxRate = temp;						
+						}
+					}
+				}
+			}	
+			if(AlarmConfProfile.adslAturThresh15MinLofs!=0 && current_intvl->AturPerfLof>=AlarmConfProfile.adslAturThresh15MinLofs)
+				trapsflag|=ATUR_PERF_LOFS_THRESH_FLAG;
+			if(AlarmConfProfile.adslAturThresh15MinLoss!=0 && current_intvl->AturPerfLos>=AlarmConfProfile.adslAturThresh15MinLoss)
+				trapsflag|=ATUR_PERF_LOSS_THRESH_FLAG;
+			if(AlarmConfProfile.adslAturThresh15MinLprs!=0 && current_intvl->AturPerfLpr>=AlarmConfProfile.adslAturThresh15MinLprs)
+				trapsflag|=ATUR_PERF_LPRS_THRESH_FLAG;
+			if(AlarmConfProfile.adslAturThresh15MinESs!=0 && current_intvl->AturPerfEs>=AlarmConfProfile.adslAturThresh15MinESs)
+				trapsflag|=ATUR_PERF_ESS_THRESH_FLAG;	
+			if(chantype.fast==1){
+				if(AlarmConfProfile.adslAturThreshFastRateUp!=0 || AlarmConfProfile.adslAturThreshFastRateDown!=0){
+					ATUR_CHAN_CURR_TX_RATE_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 6 Address 0 Index 0");
+#endif			
+					}
+					else{
+						temp = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16); 
+						if((AlarmConfProfile.adslAturThreshFastRateUp!=0) && (temp>=PrevTxRate.adslAturChanPrevTxRate+AlarmConfProfile.adslAturThreshFastRateUp)){
+							trapsflag|=ATUR_RATE_CHANGE_FLAG;
+							PrevTxRate.adslAturChanPrevTxRate = temp;						
+						}
+						if((AlarmConfProfile.adslAturThreshFastRateDown!=0) && (temp<=PrevTxRate.adslAturChanPrevTxRate-AlarmConfProfile.adslAturThreshFastRateDown)){
+							trapsflag|=ATUR_RATE_CHANGE_FLAG;
+							PrevTxRate.adslAturChanPrevTxRate = temp;						
+						}
+					}
+				}
+			}	
+			if(chantype.interleave==1){
+				if(AlarmConfProfile.adslAturThreshInterleaveRateUp!=0 || AlarmConfProfile.adslAturThreshInterleaveRateDown!=0){
+					ATUR_CHAN_CURR_TX_RATE_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 6 Address 0 Index 0");
+#endif			
+					}
+					else{
+						temp = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16);
+						if((AlarmConfProfile.adslAturThreshInterleaveRateUp!=0) && (temp>=PrevTxRate.adslAturChanPrevTxRate+AlarmConfProfile.adslAturThreshInterleaveRateUp)){
+							trapsflag|=ATUR_RATE_CHANGE_FLAG;
+							PrevTxRate.adslAturChanPrevTxRate = temp;						
+						}
+						if((AlarmConfProfile.adslAturThreshInterleaveRateDown!=0) && (temp<=PrevTxRate.adslAturChanPrevTxRate-AlarmConfProfile.adslAturThreshInterleaveRateDown)){
+							trapsflag|=ATUR_RATE_CHANGE_FLAG;
+							PrevTxRate.adslAturChanPrevTxRate = temp;						
+						}
+					}
+				}
+			}	
+			copy_to_user((char *)lon, (char *)(&trapsflag), 2);
+			
+			up(&mei_sema);	
+			break;
+			
+#ifdef AMAZON_MEI_MIB_RFC3440
+		case ADSL_ATUR_EXT_TRAPS:
+			trapsflag=0;
+			if(AlarmConfProfileExt.adslAtucThreshold15MinFailedFastR!=0 && current_intvl->AtucPerfStatFailedFastR>=AlarmConfProfileExt.adslAtucThreshold15MinFailedFastR)
+				trapsflag|=ATUC_15MIN_FAILED_FASTR_TRAP_FLAG;
+			if(AlarmConfProfileExt.adslAtucThreshold15MinSesL!=0 && current_intvl->AtucPerfStatSesL>=AlarmConfProfileExt.adslAtucThreshold15MinSesL)
+				trapsflag|=ATUC_15MIN_SESL_TRAP_FLAG;
+			if(AlarmConfProfileExt.adslAtucThreshold15MinUasL!=0 && current_intvl->AtucPerfStatUasL>=AlarmConfProfileExt.adslAtucThreshold15MinUasL)
+				trapsflag|=ATUC_15MIN_UASL_TRAP_FLAG;
+			if(AlarmConfProfileExt.adslAturThreshold15MinSesL!=0 && current_intvl->AturPerfStatSesL>=AlarmConfProfileExt.adslAturThreshold15MinSesL)
+				trapsflag|=ATUR_15MIN_SESL_TRAP_FLAG;
+			if(AlarmConfProfileExt.adslAturThreshold15MinUasL!=0 && current_intvl->AturPerfStatUasL>=AlarmConfProfileExt.adslAturThreshold15MinUasL)
+				trapsflag|=ATUR_15MIN_UASL_TRAP_FLAG;
+			copy_to_user((char *)lon, (char *)(&trapsflag), 2);
+			break;
+#endif
+
+// 603221:tc.chen start
+		case GET_ADSL_LINE_STATUS:
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+			
+			pts.adslLineStatusInfo_pt = (adslLineStatusInfo *)kmalloc(sizeof(adslLineStatusInfo), GFP_KERNEL);
+			copy_from_user((char *)pts.adslLineStatusInfo_pt, (char *)lon, sizeof(adslLineStatusInfo));
+			
+			if(IS_FLAG_SET((&(pts.adslLineStatusInfo_pt->flags)), LINE_STAT_MODEM_STATUS_FLAG)){
+				LINE_STAT_MODEM_STATUS_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group STAT Address 0 Index 0");
+#endif
+					pts.adslLineStatusInfo_pt->adslModemStatus = 0;	
+				}
+				else{
+					pts.adslLineStatusInfo_pt->adslModemStatus = RxMessage[4];
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineStatusInfo_pt->flags)), LINE_STAT_MODE_SEL_FLAG)){
+				LINE_STAT_MODE_SEL_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group STAT Address 1 Index 0");
+#endif
+					pts.adslLineStatusInfo_pt->adslModeSelected = 0;	
+				}
+				else{
+					pts.adslLineStatusInfo_pt->adslModeSelected = RxMessage[4];
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineStatusInfo_pt->flags)), LINE_STAT_TRELLCOD_ENABLE_FLAG)){
+				LINE_STAT_TRELLCOD_ENABLE_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group OPTN Address 2 Index 0");
+#endif
+					pts.adslLineStatusInfo_pt->adslTrellisCodeEnable = 0;	
+				}
+				else{
+					
+					pts.adslLineStatusInfo_pt->adslTrellisCodeEnable = (RxMessage[4]>>13)&0x1==0x1?0:1;
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineStatusInfo_pt->flags)), LINE_STAT_LATENCY_FLAG)){
+				LINE_STAT_LATENCY_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group STAT Address 12 Index 0");
+#endif
+					pts.adslLineStatusInfo_pt->adslLatency = 0;	
+				}
+				else{
+					pts.adslLineStatusInfo_pt->adslLatency = RxMessage[4];
+				}
+			}
+			
+			copy_to_user((char *)lon, (char *)pts.adslLineStatusInfo_pt, sizeof(adslLineStatusInfo));
+			kfree(pts.adslLineStatusInfo_pt);
+			
+			up(&mei_sema);
+			break;
+
+
+		case GET_ADSL_LINE_RATE:
+			if (showtime!=1)
+				return -ERESTARTSYS;
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+			
+			pts.adslLineRateInfo_pt = (adslLineRateInfo *)kmalloc(sizeof(adslLineRateInfo), GFP_KERNEL);
+			copy_from_user((char *)pts.adslLineRateInfo_pt, (char *)lon, sizeof(adslLineRateInfo));
+			
+			if(IS_FLAG_SET((&(pts.adslLineRateInfo_pt->flags)), LINE_RATE_DATA_RATEDS_FLAG)){
+				if (adsl_mode <=8 && adsl_mode_extend==0) // adsl mode
+				{
+					if (chantype.interleave)
+						LINE_RATE_DATA_RATEDS_FLAG_ADSL1_LP0_MAKECMV;
+					else
+						LINE_RATE_DATA_RATEDS_FLAG_ADSL1_LP1_MAKECMV;
+						
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group RATE Address 1 Index 0");
+#endif
+						pts.adslLineRateInfo_pt->adslDataRateds = 0;	
+					}
+					else{
+						pts.adslLineRateInfo_pt->adslDataRateds = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16);
+					}		
+				}else  // adsl 2/2+
+				{
+					unsigned long Mp,Lp,Tp,Rp,Kp,Bpn,DataRate,DataRate_remain;
+					Mp=Lp=Tp=Rp=Kp=Bpn=DataRate=DataRate_remain=0;
+					//// up stream data rate
+					  
+					    if (chantype.interleave)
+					    {
+					    	    LINE_RATE_DATA_RATEUS_FLAG_ADSL2_LP_LP0_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 25 Index 0");
+#endif
+							Lp = 0;	
+						    }else
+				                    	Lp=RxMessage[4];
+				   
+				                    LINE_RATE_DATA_RATEUS_FLAG_ADSL2_RP_LP0_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 23 Index 0");
+#endif
+							Rp = 0;	
+						    }else
+				                    	Rp=RxMessage[4];
+				
+				                    LINE_RATE_DATA_RATEUS_FLAG_ADSL2_MP_LP0_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 24 Index 0");
+#endif
+							Mp = 0;	
+						    }else
+				                    	Mp=RxMessage[4];
+				
+				                    LINE_RATE_DATA_RATEUS_FLAG_ADSL2_TP_LP0_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 26 Index 0");
+#endif
+							Tp = 0;	
+						    }else
+				                    	Tp=RxMessage[4];
+				
+				                    LINE_RATE_DATA_RATEUS_FLAG_ADSL2_KP_LP0_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 28 Index 0");
+#endif
+							Kp = 0;	
+						    }else
+						    {
+				                    	Kp=RxMessage[4]+ RxMessage[5]+1;
+				                    	Bpn=RxMessage[4]+ RxMessage[5];
+				                    }
+			                    }else
+			                    {
+			                    	    LINE_RATE_DATA_RATEUS_FLAG_ADSL2_LP_LP1_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 25 Index 1");
+#endif
+							Lp = 0;	
+						    }else
+				                    	Lp=RxMessage[4];
+				   
+				                    LINE_RATE_DATA_RATEUS_FLAG_ADSL2_RP_LP1_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 23 Index 1");
+#endif
+							Rp = 0;	
+						    }else
+				                    	Rp=RxMessage[4];
+				
+				                    LINE_RATE_DATA_RATEUS_FLAG_ADSL2_MP_LP1_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 24 Index 1");
+#endif
+							Mp = 0;	
+						    }else
+				                    	Mp=RxMessage[4];
+				
+				                    LINE_RATE_DATA_RATEUS_FLAG_ADSL2_TP_LP1_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 26 Index 1");
+#endif
+							Tp = 0;	
+						    }else
+				                    	Tp=RxMessage[4];
+				
+				                    LINE_RATE_DATA_RATEUS_FLAG_ADSL2_KP_LP1_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 28 Index 2");
+#endif
+							Kp = 0;	
+						    }else
+						    {
+				                    	Kp=RxMessage[4]+ RxMessage[5]+1;
+				                    	Bpn=RxMessage[4]+ RxMessage[5];
+				                    }
+			                    }
+  					    DataRate=((Tp*(Bpn+1)-1)*Mp*Lp*4)/(Tp*(Kp*Mp+Rp));
+			                    //DataRate_remain=((((Tp*(Bpn+1)-1)*Mp*Lp*4)%(Tp*(Kp*Mp+Rp)))*1000)/(Tp*(Kp*Mp+Rp));
+			                    //pts.adslLineRateInfo_pt->adslDataRateds = DataRate * 1000 + DataRate_remain;
+			                    pts.adslLineRateInfo_pt->adslDataRateds = DataRate;
+				}		
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineRateInfo_pt->flags)), LINE_RATE_DATA_RATEUS_FLAG)){
+				if (adsl_mode <=8 && adsl_mode_extend==0) // adsl mode
+				{
+					if (chantype.interleave)
+						LINE_RATE_DATA_RATEUS_FLAG_ADSL1_LP0_MAKECMV;
+					else
+						LINE_RATE_DATA_RATEUS_FLAG_ADSL1_LP1_MAKECMV;
+						
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+	#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group RATE Address 0 Index 0");
+	#endif
+						pts.adslLineRateInfo_pt->adslDataRateus = 0;	
+					}
+					else{
+						pts.adslLineRateInfo_pt->adslDataRateus = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16);
+					}		
+				}else  // adsl 2/2+
+				{
+					unsigned long Mp,Lp,Tp,Rp,Kp,Bpn,DataRate,DataRate_remain;
+					Mp=Lp=Tp=Rp=Kp=Bpn=DataRate=DataRate_remain=0;
+					//// down stream data rate
+					   
+			 		    if (chantype.interleave)
+					    {
+					    	    LINE_RATE_DATA_RATEDS_FLAG_ADSL2_LP_LP0_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 14 Index 0");
+#endif
+							Lp = 0;	
+						    }else
+				                    	Lp=RxMessage[4];
+				   
+				                    LINE_RATE_DATA_RATEDS_FLAG_ADSL2_RP_LP0_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 12 Index 0");
+#endif
+							Rp = 0;	
+						    }else
+				                    	Rp=RxMessage[4];
+				
+				                    LINE_RATE_DATA_RATEDS_FLAG_ADSL2_MP_LP0_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 13 Index 0");
+#endif
+							Mp = 0;	
+						    }else
+				                    	Mp=RxMessage[4];
+				
+				                    LINE_RATE_DATA_RATEDS_FLAG_ADSL2_TP_LP0_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 15 Index 0");
+#endif
+							Tp = 0;	
+						    }else
+				                    	Tp=RxMessage[4];
+				
+				                    LINE_RATE_DATA_RATEDS_FLAG_ADSL2_KP_LP0_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 17 Index 0");
+#endif
+							Kp = 0;	
+						    }else
+						    {
+				                    	Kp=RxMessage[4]+ RxMessage[5]+1;
+				                    	Bpn=RxMessage[4]+ RxMessage[5];
+				                    }
+			                    }else
+			                    {
+			                    	    LINE_RATE_DATA_RATEDS_FLAG_ADSL2_LP_LP1_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 14 Index 1");
+#endif
+							Lp = 0;	
+						    }else
+				                    	Lp=RxMessage[4];
+				   
+				                    LINE_RATE_DATA_RATEDS_FLAG_ADSL2_RP_LP1_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 12 Index 1");
+#endif
+							Rp = 0;	
+						    }else
+				                    	Rp=RxMessage[4];
+				
+				                    LINE_RATE_DATA_RATEDS_FLAG_ADSL2_MP_LP1_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 13 Index 1");
+#endif
+							Mp = 0;	
+						    }else
+				                    	Mp=RxMessage[4];
+				
+				                    LINE_RATE_DATA_RATEDS_FLAG_ADSL2_TP_LP1_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 15 Index 1");
+#endif
+							Tp = 0;	
+						    }else
+				                    	Tp=RxMessage[4];
+				
+				                    LINE_RATE_DATA_RATEDS_FLAG_ADSL2_KP_LP1_MAKECMV;
+					    	    if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group CNFG Address 17 Index 2");
+#endif
+							Kp = 0;	
+						    }else
+						    {
+				                    	Kp=RxMessage[4]+ RxMessage[5]+1;
+				                    	Bpn=RxMessage[4]+ RxMessage[5];
+				                    }
+			                    }
+			                    DataRate=((Tp*(Bpn+1)-1)*Mp*Lp*4)/(Tp*(Kp*Mp+Rp));
+			                    //DataRate_remain=((((Tp*(Bpn+1)-1)*Mp*Lp*4)%(Tp*(Kp*Mp+Rp)))*1000)/(Tp*(Kp*Mp+Rp));
+			                    //pts.adslLineRateInfo_pt->adslDataRateus = DataRate * 1000 + DataRate_remain;
+			                    pts.adslLineRateInfo_pt->adslDataRateus = DataRate;
+				}		
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineRateInfo_pt->flags)), LINE_RATE_ATTNDRDS_FLAG)){
+				LINE_RATE_ATTNDRDS_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group INFO Address 68 Index 4");
+#endif
+					pts.adslLineRateInfo_pt->adslATTNDRds = 0;	
+				}
+				else{
+					pts.adslLineRateInfo_pt->adslATTNDRds = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16);
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineRateInfo_pt->flags)), LINE_RATE_ATTNDRUS_FLAG)){
+				if (adsl_mode <=8 && adsl_mode_extend==0) // adsl mode
+				{
+					LINE_RATE_ATTNDRUS_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+	#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group INFO Address 69 Index 4");
+	#endif
+						pts.adslLineRateInfo_pt->adslATTNDRus = 0;	
+					}
+					else{
+						pts.adslLineRateInfo_pt->adslATTNDRus = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16);
+					}
+				}else
+				{
+					hdlc_cmd[0]=0x0181;
+					hdlc_cmd[1]=0x24;
+					up(&mei_sema);
+					if (ifx_me_hdlc_send((unsigned char *)&hdlc_cmd[0],4)!= -EBUSY)
+					{
+						set_current_state(TASK_INTERRUPTIBLE);
+						schedule_timeout(1);		
+						hdlc_rx_len=0;			
+						hdlc_rx_len = ifx_mei_hdlc_read(&hdlc_rx_buffer,32*2);
+						if (hdlc_rx_len <=0)
+						{
+	                				meierr = -ERESTARTSYS;
+	                				goto GET_ADSL_LINE_RATE_END;
+	                			}
+						pts.adslLineRateInfo_pt->adslATTNDRus = (u32)le16_to_cpu(hdlc_rx_buffer[1])<<16 | (u32)le16_to_cpu(hdlc_rx_buffer[2]);
+					}
+					if(down_interruptible(&mei_sema))
+					{
+                				meierr = -ERESTARTSYS;
+                				goto GET_ADSL_LINE_RATE_END;
+                			}
+				}
+			}	
+			copy_to_user((char *)lon, (char *)pts.adslLineRateInfo_pt, sizeof(adslLineRateInfo));
+			up(&mei_sema);
+			
+GET_ADSL_LINE_RATE_END:						
+			kfree(pts.adslLineRateInfo_pt);
+			break;
+
+		case GET_ADSL_LINE_INFO:
+			if (showtime!=1)
+				return -ERESTARTSYS;
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+			
+			pts.adslLineInfo_pt = (adslLineInfo *)kmalloc(sizeof(adslLineInfo), GFP_KERNEL);
+			copy_from_user((char *)pts.adslLineInfo_pt, (char *)lon, sizeof(adslLineInfo));
+			
+			if(IS_FLAG_SET((&(pts.adslLineInfo_pt->flags)), LINE_INFO_INTLV_DEPTHDS_FLAG)){
+				if (chantype.interleave)
+					LINE_INFO_INTLV_DEPTHDS_FLAG_LP0_MAKECMV;
+				else
+					LINE_INFO_INTLV_DEPTHDS_FLAG_LP1_MAKECMV;
+					
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group CNFG Address 27 Index 0");
+#endif
+					pts.adslLineInfo_pt->adslInterleaveDepthds = 0;	
+				}
+				else{
+					pts.adslLineInfo_pt->adslInterleaveDepthds = RxMessage[4];
+				}				
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineInfo_pt->flags)), LINE_INFO_INTLV_DEPTHUS_FLAG)){
+				if (chantype.interleave)
+					LINE_INFO_INTLV_DEPTHUS_FLAG_LP0_MAKECMV;
+				else
+					LINE_INFO_INTLV_DEPTHUS_FLAG_LP1_MAKECMV;
+					
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group CNFG Address 16 Index 0");
+#endif
+					pts.adslLineInfo_pt->adslInterleaveDepthus = 0;	
+				}
+				else{
+					pts.adslLineInfo_pt->adslInterleaveDepthus = RxMessage[4];
+				}				
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineInfo_pt->flags)), LINE_INFO_LATNDS_FLAG)){
+				LINE_INFO_LATNDS_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group INFO Address 68 Index 1");
+#endif
+					pts.adslLineInfo_pt->adslLATNds = 0;	
+				}
+				else{
+					pts.adslLineInfo_pt->adslLATNds = RxMessage[4];
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineInfo_pt->flags)), LINE_INFO_LATNUS_FLAG)){
+				if (adsl_mode <=8 && adsl_mode_extend==0) // adsl mode
+				{
+					LINE_INFO_LATNUS_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group INFO Address 69 Index 1");
+#endif
+						pts.adslLineInfo_pt->adslLATNus = 0;	
+					}
+					else{
+						pts.adslLineInfo_pt->adslLATNus = RxMessage[4];
+					}
+				}else
+				{
+					hdlc_cmd[0]=0x0181;
+					hdlc_cmd[1]=0x21;
+					up(&mei_sema);
+					if (ifx_me_hdlc_send((unsigned char *)&hdlc_cmd[0],4)!= -EBUSY)
+					{
+						set_current_state(TASK_INTERRUPTIBLE);
+						schedule_timeout(1);		
+						hdlc_rx_len=0;			
+						hdlc_rx_len = ifx_mei_hdlc_read(&hdlc_rx_buffer,32*2);
+						if (hdlc_rx_len <=0)
+						{
+	                				meierr = -ERESTARTSYS;
+	                				goto GET_ADSL_LINE_INFO_END;
+	                			}
+						pts.adslLineInfo_pt->adslLATNus = le16_to_cpu(hdlc_rx_buffer[1]);
+					}
+					if(down_interruptible(&mei_sema))
+					{
+                				meierr = -ERESTARTSYS;
+                				goto GET_ADSL_LINE_INFO_END;
+                			}
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineInfo_pt->flags)), LINE_INFO_SATNDS_FLAG)){
+				LINE_INFO_SATNDS_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group INFO Address 68 Index 2");
+#endif
+					pts.adslLineInfo_pt->adslSATNds = 0;	
+				}
+				else{
+					pts.adslLineInfo_pt->adslSATNds = RxMessage[4];
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineInfo_pt->flags)), LINE_INFO_SATNUS_FLAG)){
+				if (adsl_mode <=8 && adsl_mode_extend==0) // adsl mode
+				{
+					LINE_INFO_SATNUS_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group INFO Address 69 Index 2");
+#endif
+						pts.adslLineInfo_pt->adslSATNus = 0;	
+					}
+					else{
+						pts.adslLineInfo_pt->adslSATNus = RxMessage[4];
+					}
+				}else
+				{
+					hdlc_cmd[0]=0x0181;
+					hdlc_cmd[1]=0x22;
+					up(&mei_sema);
+					if (ifx_me_hdlc_send((unsigned char *)&hdlc_cmd[0],4)!= -EBUSY)
+					{
+						set_current_state(TASK_INTERRUPTIBLE);
+						schedule_timeout(1);		
+						hdlc_rx_len=0;			
+						hdlc_rx_len = ifx_mei_hdlc_read(&hdlc_rx_buffer,32*2);
+						if (hdlc_rx_len <=0)
+						{
+	                				meierr = -ERESTARTSYS;
+	                				goto GET_ADSL_LINE_INFO_END;
+	                			}
+						pts.adslLineInfo_pt->adslSATNus = le16_to_cpu(hdlc_rx_buffer[1]);
+					}
+					if(down_interruptible(&mei_sema))
+                			{
+                				meierr = -ERESTARTSYS;
+                				goto GET_ADSL_LINE_INFO_END;
+                			}
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineInfo_pt->flags)), LINE_INFO_SNRMNDS_FLAG)){
+				if (adsl_mode <=8 && adsl_mode_extend==0) // adsl mode
+				{
+					LINE_INFO_SNRMNDS_FLAG_ADSL1_MAKECMV;
+				}
+				else if ((adsl_mode == 0x4000) || (adsl_mode == 0x8000) || adsl_mode_extend > 0)
+				{
+					LINE_INFO_SNRMNDS_FLAG_ADSL2PLUS_MAKECMV;
+				}
+				else
+				{
+					LINE_INFO_SNRMNDS_FLAG_ADSL2_MAKECMV;
+				}
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group INFO Address 68 Index 3");
+#endif
+					pts.adslLineInfo_pt->adslSNRMds = 0;	
+				}
+				else{
+					if (adsl_mode>8 || adsl_mode_extend>0)
+					{
+						int SNRMds,SNRMds_remain;
+						SNRMds=RxMessage[4]; 	
+						SNRMds_remain=((SNRMds&0xff)*1000)/256;
+						SNRMds=(SNRMds>>8)&0xff;
+						if ((SNRMds_remain%100)>=50) SNRMds_remain=(SNRMds_remain/100)+1;
+						else  SNRMds_remain=(SNRMds_remain/100);
+						pts.adslLineInfo_pt->adslSNRMds = SNRMds*10 + SNRMds_remain;
+					}else
+					{
+						pts.adslLineInfo_pt->adslSNRMds = RxMessage[4];
+					}
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineInfo_pt->flags)), LINE_INFO_SNRMNUS_FLAG)){
+				if (adsl_mode <=8 && adsl_mode_extend == 0)
+				{
+					LINE_INFO_SNRMNUS_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group INFO Address 69 Index 3");
+#endif
+						pts.adslLineInfo_pt->adslSNRMus = 0;	
+					}
+					else{
+						pts.adslLineInfo_pt->adslSNRMus = RxMessage[4];
+					}
+				}else
+				{
+					hdlc_cmd[0]=0x0181;
+					hdlc_cmd[1]=0x23;
+					up(&mei_sema);
+					if (ifx_me_hdlc_send((unsigned char *)&hdlc_cmd[0],4)!= -EBUSY)
+					{
+						set_current_state(TASK_INTERRUPTIBLE);
+						schedule_timeout(1);		
+						hdlc_rx_len=0;			
+						hdlc_rx_len = ifx_mei_hdlc_read(&hdlc_rx_buffer,32*2);
+						if (hdlc_rx_len <=0)
+						{
+	                				meierr = -ERESTARTSYS;
+	                				goto GET_ADSL_LINE_INFO_END;
+	                			}
+						pts.adslLineInfo_pt->adslSNRMus = le16_to_cpu(hdlc_rx_buffer[1]);
+					}
+					if(down_interruptible(&mei_sema))
+                			{
+                				meierr = -ERESTARTSYS;
+                				goto GET_ADSL_LINE_INFO_END;
+                			}
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineInfo_pt->flags)), LINE_INFO_ACATPDS_FLAG)){
+				if (adsl_mode <=8 && adsl_mode_extend == 0)
+				{
+					LINE_INFO_ACATPDS_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+	#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group INFO Address 68 Index 6");
+	#endif
+						pts.adslLineInfo_pt->adslACATPds = 0;	
+					}
+					else{
+						pts.adslLineInfo_pt->adslACATPds = RxMessage[4];
+					}
+				}else
+				{
+					hdlc_cmd[0]=0x0181;
+					hdlc_cmd[1]=0x25;
+					up(&mei_sema);
+					if (ifx_me_hdlc_send((unsigned char *)&hdlc_cmd[0],4)!= -EBUSY)
+					{
+						set_current_state(TASK_INTERRUPTIBLE);
+						schedule_timeout(1);		
+						hdlc_rx_len=0;			
+						hdlc_rx_len = ifx_mei_hdlc_read(&hdlc_rx_buffer,32*2);
+						if (hdlc_rx_len <=0)
+						{
+	                				meierr = -ERESTARTSYS;
+	                				goto GET_ADSL_LINE_INFO_END;
+	                			}
+						pts.adslLineInfo_pt->adslACATPds = le16_to_cpu(hdlc_rx_buffer[1]);
+					}
+					if(down_interruptible(&mei_sema))
+					{
+                				meierr = -ERESTARTSYS;
+                				goto GET_ADSL_LINE_INFO_END;
+                			}
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslLineInfo_pt->flags)), LINE_INFO_ACATPUS_FLAG)){
+				if (adsl_mode <=8 && adsl_mode_extend == 0)
+				{
+					LINE_INFO_ACATPUS_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group INFO Address 69 Index 6");
+#endif
+						pts.adslLineInfo_pt->adslACATPus = 0;	
+					}
+					else{
+						pts.adslLineInfo_pt->adslACATPus = RxMessage[4];
+					}
+				}else
+				{
+					hdlc_cmd[0]=0x0181;
+					hdlc_cmd[1]=0x26;
+					up(&mei_sema);
+					if (ifx_me_hdlc_send((unsigned char *)&hdlc_cmd[0],4)!= -EBUSY)
+					{
+						set_current_state(TASK_INTERRUPTIBLE);
+						schedule_timeout(1);		
+						hdlc_rx_len=0;			
+						hdlc_rx_len = ifx_mei_hdlc_read(&hdlc_rx_buffer,32*2);
+						if (hdlc_rx_len <=0)
+						{
+	                				meierr = -ERESTARTSYS;
+	                				goto GET_ADSL_LINE_INFO_END;
+	                			}
+						pts.adslLineInfo_pt->adslACATPus = le16_to_cpu(hdlc_rx_buffer[1]);
+					}
+					if(down_interruptible(&mei_sema))
+					{
+                				meierr = -ERESTARTSYS;
+                				goto GET_ADSL_LINE_INFO_END;
+                			}
+				}
+			}
+			
+			copy_to_user((char *)lon, (char *)pts.adslLineInfo_pt, sizeof(adslLineInfo));
+			up(&mei_sema);
+
+GET_ADSL_LINE_INFO_END:			
+			kfree(pts.adslLineInfo_pt);
+			break;
+
+		case GET_ADSL_NEAREND_STATS:
+			if (showtime!=1)
+				return -ERESTARTSYS;
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+			
+			pts.adslNearEndPerfStats_pt = (adslNearEndPerfStats *)kmalloc(sizeof(adslNearEndPerfStats), GFP_KERNEL);
+			copy_from_user((char *)pts.adslNearEndPerfStats_pt, (char *)lon, sizeof(adslNearEndPerfStats));
+			
+			if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_SUPERFRAME_FLAG)){
+				NEAREND_PERF_SUPERFRAME_FLAG_LSW_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 20 Index 0");
+#endif
+					pts.adslNearEndPerfStats_pt->adslSuperFrames = 0;	
+				}
+				else{
+					pts.adslNearEndPerfStats_pt->adslSuperFrames = (u32)(RxMessage[4]);
+				}
+				NEAREND_PERF_SUPERFRAME_FLAG_MSW_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 21 Index 0");
+#endif
+					pts.adslNearEndPerfStats_pt->adslSuperFrames = 0;	
+				}
+				else{
+					pts.adslNearEndPerfStats_pt->adslSuperFrames += (((u32)(RxMessage[4]))<<16);
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_LOS_FLAG) || 
+			   IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_LOF_FLAG) ||
+			   IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_LPR_FLAG) ||
+			   IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_NCD_FLAG) ||
+			   IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_LCD_FLAG) ){
+				NEAREND_PERF_LOS_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 0 Index 0");
+#endif					
+					RxMessage[4] = 0;
+				}
+				if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_LOS_FLAG)){
+					if( (RxMessage[4]&0x1) == 0x1)
+						pts.adslNearEndPerfStats_pt->adslneLOS = 1;
+					else
+						pts.adslNearEndPerfStats_pt->adslneLOS = 0;
+				}
+				
+				if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_LOF_FLAG)){
+					if( (RxMessage[4]&0x2) == 0x2)
+						pts.adslNearEndPerfStats_pt->adslneLOF = 1;
+					else
+						pts.adslNearEndPerfStats_pt->adslneLOF = 0;
+				}
+				
+				if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_LPR_FLAG)){
+					if( (RxMessage[4]&0x4) == 0x4)
+						pts.adslNearEndPerfStats_pt->adslneLPR = 1;
+					else
+						pts.adslNearEndPerfStats_pt->adslneLPR = 0;
+				}
+				
+				if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_NCD_FLAG)){
+					pts.adslNearEndPerfStats_pt->adslneNCD = (RxMessage[4]>>4)&0x3;
+				}
+				
+				if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_LCD_FLAG)){
+					pts.adslNearEndPerfStats_pt->adslneLCD = (RxMessage[4]>>6)&0x3;
+				}
+			}
+						
+			if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_CRC_FLAG)){
+				if (chantype.interleave)
+					NEAREND_PERF_CRC_FLAG_LP0_MAKECMV;
+				else
+					NEAREND_PERF_CRC_FLAG_LP1_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 2 Index 0");
+#endif
+					pts.adslNearEndPerfStats_pt->adslneCRC = 0;	
+				}
+				else{
+					pts.adslNearEndPerfStats_pt->adslneCRC = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16);
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_RSCORR_FLAG)){
+				if (chantype.interleave)
+					NEAREND_PERF_RSCORR_FLAG_LP0_MAKECMV;
+				else
+					NEAREND_PERF_RSCORR_FLAG_LP1_MAKECMV;
+					
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 3 Index 0");
+#endif
+					pts.adslNearEndPerfStats_pt->adslneRSCorr = 0;	
+				}
+				else{
+					pts.adslNearEndPerfStats_pt->adslneRSCorr = RxMessage[4];
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_FECS_FLAG)){
+				NEAREND_PERF_FECS_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 6 Index 0");
+#endif
+					pts.adslNearEndPerfStats_pt->adslneFECS = 0;	
+				}
+				else{
+					pts.adslNearEndPerfStats_pt->adslneFECS = RxMessage[4];
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_ES_FLAG)){
+				NEAREND_PERF_ES_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 7 Index 0");
+#endif
+					pts.adslNearEndPerfStats_pt->adslneES = 0;	
+				}
+				else{
+					pts.adslNearEndPerfStats_pt->adslneES = RxMessage[4];
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_SES_FLAG)){
+				NEAREND_PERF_SES_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 8 Index 0");
+#endif
+					pts.adslNearEndPerfStats_pt->adslneSES = 0;	
+				}
+				else{
+					pts.adslNearEndPerfStats_pt->adslneSES = RxMessage[4];
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_LOSS_FLAG)){
+				NEAREND_PERF_LOSS_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 9 Index 0");
+#endif
+					pts.adslNearEndPerfStats_pt->adslneLOSS = 0;	
+				}
+				else{
+					pts.adslNearEndPerfStats_pt->adslneLOSS = RxMessage[4];
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_UAS_FLAG)){
+				NEAREND_PERF_UAS_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 10 Index 0");
+#endif
+					pts.adslNearEndPerfStats_pt->adslneUAS = 0;	
+				}
+				else{
+					pts.adslNearEndPerfStats_pt->adslneUAS = RxMessage[4];
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslNearEndPerfStats_pt->flags)), NEAREND_PERF_HECERR_FLAG)){
+				if (chantype.bearchannel0)
+				{
+					NEAREND_PERF_HECERR_FLAG_BC0_MAKECMV;
+				}else if (chantype.bearchannel1)
+				{
+					NEAREND_PERF_HECERR_FLAG_BC1_MAKECMV;
+				}
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 11 Index 0");
+#endif
+					pts.adslNearEndPerfStats_pt->adslneHECErrors = 0;	
+				}
+				else{
+					pts.adslNearEndPerfStats_pt->adslneHECErrors = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16);
+				}
+			}
+			
+			copy_to_user((char *)lon, (char *)pts.adslNearEndPerfStats_pt, sizeof(adslNearEndPerfStats));
+			kfree(pts.adslNearEndPerfStats_pt);
+			
+			up(&mei_sema);
+			break;
+
+		case GET_ADSL_FAREND_STATS:
+
+                	if (showtime!=1)
+                		return -ERESTARTSYS;
+			
+			if (adsl_mode>8 || adsl_mode_extend > 0)
+			{
+				do_gettimeofday(&time_now);
+				if( FarendData_acquire_time.tv_sec==0 || time_now.tv_sec - FarendData_acquire_time.tv_sec>=1)
+				{								
+					hdlc_cmd[0]=0x105;
+					
+					if (ifx_me_hdlc_send((unsigned char *)&hdlc_cmd[0],2)!= -EBUSY)
+					{
+						set_current_state(TASK_INTERRUPTIBLE);
+						schedule_timeout(1);		
+						hdlc_rx_len=0;			
+						hdlc_rx_len = ifx_mei_hdlc_read(&hdlc_rx_buffer,32*2);
+						if (hdlc_rx_len <=0)
+						{
+							return -ERESTARTSYS;
+						}
+						FarendStatsData.adslfeRSCorr = ((u32)le16_to_cpu(hdlc_rx_buffer[1]) << 16) + (u32)le16_to_cpu(hdlc_rx_buffer[2]);
+						FarendStatsData.adslfeCRC = ((u32)le16_to_cpu(hdlc_rx_buffer[3]) << 16) + (u32)le16_to_cpu(hdlc_rx_buffer[4]);
+						FarendStatsData.adslfeFECS = ((u32)le16_to_cpu(hdlc_rx_buffer[5]) << 16) + (u32)le16_to_cpu(hdlc_rx_buffer[6]);
+						FarendStatsData.adslfeES = ((u32)le16_to_cpu(hdlc_rx_buffer[7]) << 16) + (u32)le16_to_cpu(hdlc_rx_buffer[8]);
+						FarendStatsData.adslfeSES = ((u32)le16_to_cpu(hdlc_rx_buffer[9]) << 16) + (u32)le16_to_cpu(hdlc_rx_buffer[10]);
+						FarendStatsData.adslfeLOSS = ((u32)le16_to_cpu(hdlc_rx_buffer[11]) << 16) + (u32)le16_to_cpu(hdlc_rx_buffer[12]);
+						FarendStatsData.adslfeUAS = ((u32)le16_to_cpu(hdlc_rx_buffer[13]) << 16) + (u32)le16_to_cpu(hdlc_rx_buffer[14]);
+						do_gettimeofday(&FarendData_acquire_time);
+					}
+					
+				}
+			}
+			
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+                	pts.adslFarEndPerfStats_pt = (adslFarEndPerfStats *)kmalloc(sizeof(adslFarEndPerfStats), GFP_KERNEL);
+			copy_from_user((char *)pts.adslFarEndPerfStats_pt, (char *)lon, sizeof(adslFarEndPerfStats));
+			if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_LOS_FLAG) || 
+			   IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_LOF_FLAG) ||
+			   IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_LPR_FLAG) ||
+			   IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_NCD_FLAG) ||
+			   IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_LCD_FLAG) ){
+				FAREND_PERF_LOS_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 1 Index 0");
+#endif					
+					RxMessage[4] = 0;
+				}
+				if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_LOS_FLAG)){
+					if((RxMessage[4]&0x1) == 0x1)
+						pts.adslFarEndPerfStats_pt->adslfeLOS = 1;
+					else
+						pts.adslFarEndPerfStats_pt->adslfeLOS = 0;
+				}
+				
+				if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_LOF_FLAG)){
+					if((RxMessage[4]&0x2) == 0x2)
+						pts.adslFarEndPerfStats_pt->adslfeLOF = 1;
+					else
+						pts.adslFarEndPerfStats_pt->adslfeLOF = 0;
+				}
+				
+				if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_LPR_FLAG)){
+					if((RxMessage[4]&0x4) == 0x4)
+						pts.adslFarEndPerfStats_pt->adslfeLPR = 1;
+					else
+						pts.adslFarEndPerfStats_pt->adslfeLPR = 0;
+				}
+				
+				if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_NCD_FLAG)){
+					pts.adslFarEndPerfStats_pt->adslfeNCD = (RxMessage[4]>>4)&0x3;
+				}
+				
+				if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_LCD_FLAG)){
+					pts.adslFarEndPerfStats_pt->adslfeLCD = (RxMessage[4]>>6)&0x3;
+				}
+			}
+						
+			if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_CRC_FLAG)){
+				if (adsl_mode<=8 && adsl_mode_extend == 0)
+				{
+					if (chantype.interleave)
+					{
+						FAREND_PERF_CRC_FLAG_LP0_MAKECMV;
+					}
+					else
+					{
+						FAREND_PERF_CRC_FLAG_LP1_MAKECMV;
+					}
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group PLAM Address 24 Index 0");
+#endif
+						pts.adslFarEndPerfStats_pt->adslfeCRC = 0;	
+					}
+					else{
+						pts.adslFarEndPerfStats_pt->adslfeCRC = RxMessage[4];					
+					}
+				}else
+				{
+					pts.adslFarEndPerfStats_pt->adslfeCRC = FarendStatsData.adslfeCRC;
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_RSCORR_FLAG)){
+				if (adsl_mode<=8 && adsl_mode_extend == 0)
+				{
+					if (chantype.interleave)
+						FAREND_PERF_RSCORR_FLAG_LP0_MAKECMV;
+					else
+						FAREND_PERF_RSCORR_FLAG_LP1_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group PLAM Address 28 Index 0");
+#endif
+						pts.adslFarEndPerfStats_pt->adslfeRSCorr = 0;	
+					}
+					else{
+						pts.adslFarEndPerfStats_pt->adslfeRSCorr = RxMessage[4];
+						
+					}
+				}
+				else
+				{
+					pts.adslFarEndPerfStats_pt->adslfeRSCorr = FarendStatsData.adslfeRSCorr;
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_FECS_FLAG)){
+				if (adsl_mode<=8 && adsl_mode_extend == 0)
+				{
+					FAREND_PERF_FECS_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group PLAM Address 32 Index 0");
+#endif
+						pts.adslFarEndPerfStats_pt->adslfeFECS = 0;	
+					}
+					else{
+						pts.adslFarEndPerfStats_pt->adslfeFECS = RxMessage[4];						
+					}
+				}else {
+					pts.adslFarEndPerfStats_pt->adslfeFECS = FarendStatsData.adslfeFECS;
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_ES_FLAG)){
+				if (adsl_mode<=8 && adsl_mode_extend == 0)
+				{
+					FAREND_PERF_ES_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group PLAM Address 33 Index 0");
+#endif
+						pts.adslFarEndPerfStats_pt->adslfeES = 0;	
+					}
+					else{
+						pts.adslFarEndPerfStats_pt->adslfeES = RxMessage[4];						
+					}
+				}else
+				{
+					pts.adslFarEndPerfStats_pt->adslfeES = FarendStatsData.adslfeES;
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_SES_FLAG)){
+				if (adsl_mode<=8 && adsl_mode_extend == 0)
+				{
+					FAREND_PERF_SES_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group PLAM Address 34 Index 0");
+#endif
+						pts.adslFarEndPerfStats_pt->adslfeSES = 0;	
+					}
+					else{
+						pts.adslFarEndPerfStats_pt->adslfeSES = RxMessage[4];
+						
+					}
+				}else
+				{
+					pts.adslFarEndPerfStats_pt->adslfeSES = FarendStatsData.adslfeSES;
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_LOSS_FLAG)){
+				if (adsl_mode<=8 && adsl_mode_extend == 0)
+				{
+					FAREND_PERF_LOSS_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+						pts.adslFarEndPerfStats_pt->adslfeLOSS = 0;	
+					}
+					else{
+						pts.adslFarEndPerfStats_pt->adslfeLOSS = RxMessage[4];
+						
+					}
+				}else
+				{
+					pts.adslFarEndPerfStats_pt->adslfeLOSS = FarendStatsData.adslfeLOSS;
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_UAS_FLAG)){
+				if (adsl_mode<=8 && adsl_mode_extend == 0)
+				{
+					FAREND_PERF_UAS_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group PLAM Address 36 Index 0");
+#endif
+						pts.adslFarEndPerfStats_pt->adslfeUAS = 0;	
+					}
+					else{
+						pts.adslFarEndPerfStats_pt->adslfeUAS = RxMessage[4];
+						
+					}
+				}else
+				{
+					pts.adslFarEndPerfStats_pt->adslfeUAS = FarendStatsData.adslfeUAS;
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslFarEndPerfStats_pt->flags)), FAREND_PERF_HECERR_FLAG)){
+				if (chantype.bearchannel0)
+				{
+					FAREND_PERF_HECERR_FLAG_BC0_MAKECMV;
+				}else if (chantype.bearchannel1)
+				{
+					FAREND_PERF_HECERR_FLAG_BC1_MAKECMV;
+				}
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 37 Index 0");
+#endif
+					pts.adslFarEndPerfStats_pt->adslfeHECErrors = 0;	
+				}
+				else{
+					pts.adslFarEndPerfStats_pt->adslfeHECErrors = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16);
+				}
+			}
+			
+			copy_to_user((char *)lon, (char *)pts.adslFarEndPerfStats_pt, sizeof(adslFarEndPerfStats));		
+			kfree(pts.adslFarEndPerfStats_pt);
+			
+			up(&mei_sema);
+			
+			break;
+// 603221:tc.chen end
+		case GET_ADSL_LOOP_DIAGNOSTICS_MODE:
+			//lon = loop_diagnostics_mode;
+			copy_to_user((char *)lon, (char *)&loop_diagnostics_mode, sizeof(int));	
+			break;
+//>> SHC
+		case IS_ADSL_LOOP_DIAGNOSTICS_MODE_COMPLETE:
+			copy_to_user((char *)lon, (char *)&loop_diagnostics_completed, sizeof(int));	
+			break;
+			
+//<< end SHC
+		case LOOP_DIAGNOSTIC_MODE_COMPLETE:
+			loop_diagnostics_completed = 1;
+			// read adsl mode
+			makeCMV(H2D_CMV_READ, STAT, 1, 0, 1, data); 
+			if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+				printk("\n\nCMV fail, Group STAT Address 1 Index 0");
+#endif
+			}
+			adsl_mode = RxMessage[4];
+
+			makeCMV(H2D_CMV_READ, STAT, 17, 0, 1, data); 
+			if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+				printk("\n\nCMV fail, Group STAT Address 1 Index 0");
+#endif
+			}
+			adsl_mode_extend = RxMessage[4];
+			wake_up_interruptible(&wait_queue_loop_diagnostic);	
+			break;
+		case SET_ADSL_LOOP_DIAGNOSTICS_MODE:
+			if (lon != loop_diagnostics_mode)
+			{
+				loop_diagnostics_completed = 0;
+				loop_diagnostics_mode = lon;
+
+				mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_REBOOT, NULL);
+				
+			}
+			break;
+		case GET_ADSL_ATUR_SUBCARRIER_STATS:
+			if (loop_diagnostics_completed == 0)
+			{
+				interruptible_sleep_on_timeout(&wait_queue_loop_diagnostic,300*HZ);
+				if (loop_diagnostics_completed==0)
+				{
+					return -ERESTARTSYS;
+				}
+			}
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+                		
+                	pts.adslATURSubcarrierInfo_pt = (adslATURSubcarrierInfo *)kmalloc(sizeof(adslATURSubcarrierInfo), GFP_KERNEL);
+			copy_from_user((char *)pts.adslATURSubcarrierInfo_pt, (char *)lon, sizeof(adslATURSubcarrierInfo));
+			
+			if(IS_FLAG_SET((&(pts.adslATURSubcarrierInfo_pt->flags)),  FAREND_HLINSC)){
+				FAREND_HLINSC_MAKECMV(H2D_CMV_READ);
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+					pts.adslATURSubcarrierInfo_pt->HLINSCds = 0;	
+				}
+				else{
+					pts.adslATURSubcarrierInfo_pt->HLINSCds = RxMessage[4];
+					
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslATURSubcarrierInfo_pt->flags)),  FAREND_HLINPS)){
+				int index=0,size=12;
+				//printk("FAREND_HLINPS\n");
+				for (index=0;index<1024;index+=size)
+				{
+					if (index+size>=1024)
+						size = 1024-index;
+					FAREND_HLINPS_MAKECMV(H2D_CMV_READ,index,size);
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+					}
+					else{
+						memcpy(&pts.adslATURSubcarrierInfo_pt->HLINpsds[index],&RxMessage[4],size*2);
+#if 0
+						int msg_idx;
+						for(msg_idx=0;msg_idx<size;msg_idx++)
+							printk("index:%d ,cmv_result: %04X\n",index+msg_idx,RxMessage[4+msg_idx]);
+#endif
+					}
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslATURSubcarrierInfo_pt->flags)),  FAREND_HLOGMT)){
+				FAREND_HLOGMT_MAKECMV(H2D_CMV_READ);
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+					pts.adslATURSubcarrierInfo_pt->HLOGMTds = 0;	
+				}
+				else{
+					pts.adslATURSubcarrierInfo_pt->HLOGMTds = RxMessage[4];
+					
+				}
+			}
+			
+			/////////////////////////////////////////////////////////////////////////
+			if(IS_FLAG_SET((&(pts.adslATURSubcarrierInfo_pt->flags)),  FAREND_HLOGPS)){
+				//printk("FAREND_HLOGPS\n");
+				int index=0,size=12;
+				for (index=0;index<256;index+=size)
+				{
+					if (index+size>=256)
+						size = 256-index;
+
+					FAREND_HLOGPS_MAKECMV(H2D_CMV_READ,index,size);
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+					}
+					else{
+						if (adsl_mode < 0x4000 && adsl_mode_extend==0)//adsl2 mode
+						{
+							memcpy(&pts.adslATURSubcarrierInfo_pt->HLOGpsds[index],&RxMessage[4],size*2);
+						}else
+						{
+							int msg_idx=0;
+							for (msg_idx=0;msg_idx<size;msg_idx++)
+							{
+								pts.adslATURSubcarrierInfo_pt->HLOGpsds[(index+msg_idx)*2+1] = RxMessage[4+msg_idx];
+								//printk("index:%d ,cmv_result: %04X\n",index+msg_idx,RxMessage[4+msg_idx]);
+							}
+						}	
+					}
+				}
+				if (adsl_mode >= 0x4000 || adsl_mode_extend >0)//adsl2+ mode
+				{
+					pts.adslATURSubcarrierInfo_pt->HLOGpsds[0] = pts.adslATURSubcarrierInfo_pt->HLOGpsds[1];
+					for (index=1;index<256;index++)
+					{
+						pts.adslATURSubcarrierInfo_pt->HLOGpsds[index*2]   = (pts.adslATURSubcarrierInfo_pt->HLOGpsds[(index)*2-1] +  pts.adslATURSubcarrierInfo_pt->HLOGpsds[(index)*2+1] +1) >>1;
+					}
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslATURSubcarrierInfo_pt->flags)),  FAREND_QLNMT)){
+				FAREND_QLNMT_MAKECMV(H2D_CMV_READ);
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+					pts.adslATURSubcarrierInfo_pt->QLNMTds = 0;	
+				}
+				else{
+					pts.adslATURSubcarrierInfo_pt->QLNMTds = RxMessage[4];					
+				}
+			}
+			
+			/////////////////////////////////////////////////////////////////////////
+			if(IS_FLAG_SET((&(pts.adslATURSubcarrierInfo_pt->flags)),  FAREND_QLNPS)){
+				int index=0,size=12;
+				//printk("FAREND_QLNPS\n");
+				for (index=0;index<128;index+=size)
+				{
+					if (index+size>=128)
+						size = 128-index;
+					FAREND_QLNPS_MAKECMV(H2D_CMV_READ,index,size);
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+					}
+					else{
+						int msg_idx=0;
+						for (msg_idx=0;msg_idx<size;msg_idx++)
+						{
+							//memcpy(&pts.adslATURSubcarrierInfo_pt->QLNpsds[index],&RxMessage[4],size*2);
+							if (adsl_mode < 0x4000 && adsl_mode_extend==0)//adsl2 mode
+							{
+								pts.adslATURSubcarrierInfo_pt->QLNpsds[(index+msg_idx)*2] = (u16)(RxMessage[4+msg_idx]&0xFF);
+								pts.adslATURSubcarrierInfo_pt->QLNpsds[(index+msg_idx)*2+1] = (u16)((RxMessage[4+msg_idx]>>8)&0xFF);
+							}else
+							{
+								pts.adslATURSubcarrierInfo_pt->QLNpsds[(index+msg_idx)*4+1] = (u16)(RxMessage[4+msg_idx]&0xFF);
+								pts.adslATURSubcarrierInfo_pt->QLNpsds[(index+msg_idx)*4+3] = (u16)((RxMessage[4+msg_idx]>>8)&0xFF);
+								//printk("index:%d ,cmv_result: %04X\n",index+msg_idx,RxMessage[4+msg_idx]);
+							}
+						}
+
+						
+					}
+				}
+				if (adsl_mode >= 0x4000 || adsl_mode_extend >0)//adsl2+ mode
+				{
+					pts.adslATURSubcarrierInfo_pt->QLNpsds[0] = pts.adslATURSubcarrierInfo_pt->QLNpsds[1];
+					for (index=1;index<256;index++)
+					{
+						pts.adslATURSubcarrierInfo_pt->QLNpsds[index*2]   = (pts.adslATURSubcarrierInfo_pt->QLNpsds[(index)*2-1] +  pts.adslATURSubcarrierInfo_pt->QLNpsds[(index)*2+1]) >>1;
+					}
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslATURSubcarrierInfo_pt->flags)),  FAREND_SNRMT)){
+				FAREND_SNRMT_MAKECMV(H2D_CMV_READ);
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+					pts.adslATURSubcarrierInfo_pt->SNRMTds = 0;	
+				}
+				else{
+					pts.adslATURSubcarrierInfo_pt->SNRMTds = RxMessage[4];					
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslATURSubcarrierInfo_pt->flags)),  FAREND_SNRPS)){
+				int index=0,size=12;
+				//printk("FAREND_SNRPS\n");
+				for (index=0;index<512;index+=size)
+				{
+					if (index+size>=512)
+						size = 512-index;
+					FAREND_SNRPS_MAKECMV(H2D_CMV_READ,index,size);
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+					}
+					else{
+						//memcpy(&pts.adslATURSubcarrierInfo_pt->SNRpsds[index],&RxMessage[4],size*2);
+						int msg_idx=0;
+						for (msg_idx=0;msg_idx<size;msg_idx++)
+						{
+							pts.adslATURSubcarrierInfo_pt->SNRpsds[index+msg_idx] = (u16)(RxMessage[4+msg_idx]&0xFF);
+							//printk("index:%d ,cmv_result: %04X\n",index+msg_idx,RxMessage[4+msg_idx]);
+						}
+						
+					}
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslATURSubcarrierInfo_pt->flags)),  FAREND_BITPS)){
+				int index=0,size=12;
+				//printk("FAREND_BITPS\n");
+				for (index=0;index<256;index+=size)
+				{
+					if (index+size>=256)
+						size = 256-index;
+					FAREND_BITPS_MAKECMV(H2D_CMV_READ,index,size);
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+					}
+					else{
+						int msg_idx=0;
+						for (msg_idx=0;msg_idx<size;msg_idx++)
+						{
+							pts.adslATURSubcarrierInfo_pt->BITpsds[(index+msg_idx)*2] = (u16)(RxMessage[4+msg_idx]&0xFF);
+							pts.adslATURSubcarrierInfo_pt->BITpsds[(index+msg_idx)*2+1] = (u16)((RxMessage[4+msg_idx]>>8)&0xFF);
+							//printk("index:%d ,cmv_result: %04X, %d\n",index+msg_idx,RxMessage[4+msg_idx],RxMessage[4+msg_idx]);
+							
+						}
+						
+					}
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslATURSubcarrierInfo_pt->flags)),  FAREND_GAINPS)){
+				int index=0,size=12;
+				//printk("FAREND_GAINPS\n");
+				for (index=0;index<512;index+=size)
+				{
+					FAREND_GAINPS_MAKECMV(H2D_CMV_READ,index,size);
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+					}
+					else{
+					/*
+						int msg_idx=0;
+						for (msg_idx=0;msg_idx<size;msg_idx++)
+						{
+							pts.adslATURSubcarrierInfo_pt->GAINpsds[(index+msg_idx)*2] = RxMessage[4+msg_idx]&0xFF;
+							pts.adslATURSubcarrierInfo_pt->GAINpsds[(index+msg_idx)*2+1] = (RxMessage[4+msg_idx]>>8)&0xFF;
+							
+						}
+						*/
+						memcpy(&pts.adslATURSubcarrierInfo_pt->GAINpsds[index],&RxMessage[4],size*2);	
+#if 0
+						int msg_idx=0;
+						for (msg_idx=0;msg_idx<size;msg_idx++)
+						{
+							printk("index:%d ,cmv_result: %04X\n",index+msg_idx,RxMessage[4+msg_idx]);
+							
+						}
+#endif
+					}
+				}
+			}				
+			copy_to_user((char *)lon, (char *)pts.adslATURSubcarrierInfo_pt, sizeof(adslATURSubcarrierInfo));		
+			kfree(pts.adslATURSubcarrierInfo_pt);
+			
+			up(&mei_sema);
+			break;
+		case GET_ADSL_ATUC_SUBCARRIER_STATS:
+			if (loop_diagnostics_completed == 0)
+			{
+				interruptible_sleep_on_timeout(&wait_queue_loop_diagnostic,300*HZ);
+				if (loop_diagnostics_completed==0)
+				{
+					return -ERESTARTSYS;
+				}
+			}
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+                	pts.adslATUCSubcarrierInfo_pt = (adslATUCSubcarrierInfo *)kmalloc(sizeof(adslATUCSubcarrierInfo), GFP_KERNEL);
+			copy_from_user((char *)pts.adslATUCSubcarrierInfo_pt, (char *)lon, sizeof(adslATUCSubcarrierInfo));
+			
+			
+			if(IS_FLAG_SET((&(pts.adslATUCSubcarrierInfo_pt->flags)),  NEAREND_HLINSC)){
+				NEAREND_HLINSC_MAKECMV(H2D_CMV_READ);
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group INFO Address 71 Index 2");
+#endif
+					pts.adslATUCSubcarrierInfo_pt->HLINSCus = 0;	
+				}
+				else{
+					pts.adslATUCSubcarrierInfo_pt->HLINSCus = RxMessage[4];
+					
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslATUCSubcarrierInfo_pt->flags)),  NEAREND_HLINPS)){
+				int index=0,size=12;
+				//printk("NEAREND_HLINPS\n");
+				for (index=0;index<128;index+=size)
+				{
+					if (index+size>=128)
+						size = 128-index;
+					NEAREND_HLINPS_MAKECMV(H2D_CMV_READ,index,size);
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group INFO Address 73 Index 0");
+#endif
+					}
+					else{
+						memcpy(&pts.adslATUCSubcarrierInfo_pt->HLINpsus[index],&RxMessage[4],size*2);
+#if 0
+						int msg_idx;
+						for (msg_idx=0;msg_idx<size;msg_idx++)
+						{
+							printk("index:%d ,cmv_result: %04X\n",index+msg_idx,RxMessage[4+msg_idx]);
+						}
+#endif
+					}
+				}
+			}
+			
+			if(IS_FLAG_SET((&(pts.adslATUCSubcarrierInfo_pt->flags)),  NEAREND_HLOGMT)){
+				NEAREND_HLOGMT_MAKECMV(H2D_CMV_READ);
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group INFO Address 80 Index 0");
+#endif
+					pts.adslATUCSubcarrierInfo_pt->HLOGMTus = 0;	
+				}
+				else{
+					pts.adslATUCSubcarrierInfo_pt->HLOGMTus = RxMessage[4];
+					
+				}
+			}
+			
+			/////////////////////////////////////////////////////////////////////////
+			if(IS_FLAG_SET((&(pts.adslATUCSubcarrierInfo_pt->flags)),  NEAREND_HLOGPS)){
+				int index=0,size=12;
+				//printk("NEAREND_HLOGPS\n");
+				for (index=0;index<64;index+=size)
+				{
+					if (index+size>=64)
+						size = 64-index;
+					NEAREND_HLOGPS_MAKECMV(H2D_CMV_READ,index,size);
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group INFO Address 75 Index 0");
+#endif
+					}
+					else{						
+#if 0
+						if (adsl_mode <0x4000)//adsl /adsl2 mode
+						{
+#endif
+						memcpy(&pts.adslATUCSubcarrierInfo_pt->HLOGpsus[index],&RxMessage[4],size*2);
+#if 0
+						}else
+						{
+							int msg_idx=0;
+							for (msg_idx=0;msg_idx<size;msg_idx++)
+							{
+								//pts.adslATUCSubcarrierInfo_pt->HLOGpsus[(index+msg_idx)*2+1] = RxMessage[4+msg_idx];
+								pts.adslATUCSubcarrierInfo_pt->HLOGpsus[(index+msg_idx)] = RxMessage[4+msg_idx];
+							}
+						}						
+#endif
+					}
+				}
+#if 0
+				if (adsl_mode >= 0x4000)//adsl2 mode
+				{
+					pts.adslATUCSubcarrierInfo_pt->HLOGpsus[0] = pts.adslATUCSubcarrierInfo_pt->HLOGpsus[1];
+					for (index=1;index<64;index++)
+					{
+						pts.adslATUCSubcarrierInfo_pt->HLOGpsus[index*2]   = (pts.adslATUCSubcarrierInfo_pt->HLOGpsus[(index)*2-1] +  pts.adslATUCSubcarrierInfo_pt->HLOGpsus[(index)*2+1]) >>1;
+					}
+				}
+#endif
+			}
+			if(IS_FLAG_SET((&(pts.adslATUCSubcarrierInfo_pt->flags)),  NEAREND_QLNMT)){
+				NEAREND_QLNMT_MAKECMV(H2D_CMV_READ);
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group INFO Address 80 Index 1");
+#endif
+					pts.adslATUCSubcarrierInfo_pt->QLNMTus = 0;	
+				}
+				else{
+					pts.adslATUCSubcarrierInfo_pt->QLNMTus = RxMessage[4];					
+				}
+			}
+			
+			/////////////////////////////////////////////////////////////////////////
+			if(IS_FLAG_SET((&(pts.adslATUCSubcarrierInfo_pt->flags)),  NEAREND_QLNPS)){
+				int index=0,size=12;
+				//printk("NEAREND_QLNPS\n");
+				for (index=0;index<32;index+=size)
+				{
+					if (index+size>=32)
+						size = 32-index;
+					NEAREND_QLNPS_MAKECMV(H2D_CMV_READ,index,size);
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group INFO Address 77 Index 0");
+#endif
+					}
+					else{
+						int msg_idx=0;
+						for (msg_idx=0;msg_idx<size;msg_idx++)
+						{
+
+#if 0
+							//memcpy(&pts.adslATUCSubcarrierInfo_pt->QLNpsds[index],&RxMessage[4],size*2);
+							if (adsl_mode == 0x200 || adsl_mode == 0x800 || adsl_mode ==0x2000  || adsl_mode ==0x4000 || (adsl_mode == 0 && (adsl_mode_extend == 0x4 || adsl_mode_extend == 0x2))//ADSL 2 Annex B(0x200)/J(0x800)/M(0x2000) //ADSL 2+ B,J,M
+							if (adsl_mode < 0x4000 && adsl_mode_extend==0)//adsl2 mode
+							{
+								pts.adslATUCSubcarrierInfo_pt->QLNpsus[(index+msg_idx)*4+1] = (u16)(RxMessage[4+msg_idx]&0xFF);
+								pts.adslATUCSubcarrierInfo_pt->QLNpsus[(index+msg_idx)*4+3] = (u16)((RxMessage[4+msg_idx]>>8)&0xFF);
+							}else
+#endif
+							{
+								pts.adslATUCSubcarrierInfo_pt->QLNpsus[(index+msg_idx)*2] = (u16)(RxMessage[4+msg_idx]&0xFF);
+								pts.adslATUCSubcarrierInfo_pt->QLNpsus[(index+msg_idx)*2+1] = (u16)((RxMessage[4+msg_idx]>>8)&0xFF);
+							//printk("index:%d ,cmv_result: %04X\n",index+msg_idx,RxMessage[4+msg_idx]);
+							}
+						}
+
+						
+					}
+				}
+#if 0
+				//if (adsl_mode <0x4000)//Annex I/J/L/M
+				if (adsl_mode == 0x200 || adsl_mode == 0x800 || adsl_mode ==0x2000  || adsl_mode ==0x4000 || (adsl_mode == 0 && (adsl_mode_extend == 0x4 || adsl_mode_extend == 0x2))//ADSL 2 Annex B(0x200)/J(0x800)/M(0x2000) //ADSL 2+ B,J,M
+				{
+					pts.adslATUCSubcarrierInfo_pt->QLNpsus[0] = pts.adslATUCSubcarrierInfo_pt->QLNpsus[1];
+					for (index=1;index<64;index++)
+					{
+						pts.adslATUCSubcarrierInfo_pt->QLNpsus[index*2]   = (pts.adslATUCSubcarrierInfo_pt->QLNpsus[(index)*2-1] +  pts.adslATUCSubcarrierInfo_pt->QLNpsus[(index)*2+1]) >>1;
+					}
+				}
+#endif
+			}
+			if(IS_FLAG_SET((&(pts.adslATUCSubcarrierInfo_pt->flags)),  NEAREND_SNRMT)){
+				NEAREND_SNRMT_MAKECMV(H2D_CMV_READ);
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group INFO Address 80 Index 2");
+#endif
+					pts.adslATUCSubcarrierInfo_pt->SNRMTus = 0;	
+				}
+				else{
+					pts.adslATUCSubcarrierInfo_pt->SNRMTus = RxMessage[4];					
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslATUCSubcarrierInfo_pt->flags)),  NEAREND_SNRPS)){
+				int index=0,size=12;
+				//printk("NEAREND_SNRPS\n");
+				for (index=0;index<64;index+=size)
+				{
+					if (index+size>=64)
+						size = 64-index;
+					NEAREND_SNRPS_MAKECMV(H2D_CMV_READ,index,size);
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group INFO Address 78 Index 0");
+#endif
+					}
+					else{
+						//memcpy(&pts.adslATUCSubcarrierInfo_pt->SNRpsus[index],&RxMessage[4],size*2);
+						int msg_idx=0;
+						for (msg_idx=0;msg_idx<size;msg_idx++)
+						{
+							pts.adslATUCSubcarrierInfo_pt->SNRpsus[index+msg_idx] = (u16)(RxMessage[4+msg_idx]&0xFF);
+							//printk("index:%d ,cmv_result: %04X\n",index+msg_idx,RxMessage[4+msg_idx]);
+						}
+						
+					}
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslATUCSubcarrierInfo_pt->flags)),  NEAREND_BITPS)){
+				int index=0,size=12;
+				//printk("NEAREND_BITPS\n");
+				for (index=0;index<32;index+=size)
+				{
+					if (index+size>=32)
+						size = 32-index;
+					NEAREND_BITPS_MAKECMV(H2D_CMV_READ,index,size);
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group INFO Address 22 Index 0");
+#endif
+					}
+					else{
+						int msg_idx=0;
+						for (msg_idx=0;msg_idx<size;msg_idx++)
+						{
+							pts.adslATUCSubcarrierInfo_pt->BITpsus[(index+msg_idx)*2] = (u16)(RxMessage[4+msg_idx]&0xFF);
+							pts.adslATUCSubcarrierInfo_pt->BITpsus[(index+msg_idx)*2+1] = (u16)((RxMessage[4+msg_idx]>>8)&0xFF);
+							//printk("index:%d ,cmv_result: %04X\n",index+msg_idx,RxMessage[4+msg_idx]);
+						}
+						
+					}
+				}
+			}
+			if(IS_FLAG_SET((&(pts.adslATUCSubcarrierInfo_pt->flags)),  NEAREND_GAINPS)){
+				int index=0,size=12;
+				//printk("NEAREND_GAINPS\n");
+				for (index=0;index<64;index+=size)
+				{
+					if (index+size>=64)
+						size = 64-index;
+					NEAREND_GAINPS_MAKECMV(H2D_CMV_READ,index,size);
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group INFO Address 24 Index 0");
+#endif
+					}
+					else{
+					/*
+						int msg_idx=0;
+						for (msg_idx=0;msg_idx<size;msg_idx++)
+						{
+							pts.adslATUCSubcarrierInfo_pt->GAINpsds[(index+msg_idx)*2] = RxMessage[4+msg_idx]&0xFF;
+							pts.adslATUCSubcarrierInfo_pt->GAINpsds[(index+msg_idx)*2+1] = (RxMessage[4+msg_idx]>>8)&0xFF;
+							
+						}
+						*/
+						memcpy(&pts.adslATUCSubcarrierInfo_pt->GAINpsus[index],&RxMessage[4],size*2);	
+#if 0
+						int msg_idx;
+						for (msg_idx=0;msg_idx<size;msg_idx++)
+						{
+							printk("index:%d ,cmv_result: %04X\n",index+msg_idx,RxMessage[4+msg_idx]);
+						}
+#endif
+					}
+				}
+			}				
+			copy_to_user((char *)lon, (char *)pts.adslATUCSubcarrierInfo_pt, sizeof(adslATUCSubcarrierInfo));		
+			kfree(pts.adslATUCSubcarrierInfo_pt);			
+			up(&mei_sema);
+			break;
+		case GET_ADSL_LINE_INIT_STATS:			
+			copy_to_user((char *)lon, (char *)&AdslInitStatsData, sizeof(AdslInitStatsData));		
+			break;
+		
+		case GET_ADSL_POWER_SPECTRAL_DENSITY:		
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+			i=0;
+			pts.adslPowerSpectralDensity_pt = (adslPowerSpectralDensity *)kmalloc(sizeof(adslPowerSpectralDensity), GFP_KERNEL);
+			memset((char *)pts.adslPowerSpectralDensity_pt, 0, sizeof(adslPowerSpectralDensity));	
+
+			//US
+			NOMPSD_US_MAKECMV;
+			if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+				printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+				i=-1;
+			}
+			else{
+				j=RxMessage[4];
+			}
+			PCB_US_MAKECMV;
+			if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+				printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+				i=-1;
+			}
+			else{
+				temp=RxMessage[4];
+			}
+			RMSGI_US_MAKECMV;
+			if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+				printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+				i=-1;
+			}
+			else{
+				k=(int16_t)RxMessage[4];
+			}
+			if (i==0)
+			{
+				pts.adslPowerSpectralDensity_pt->ACTPSDus = ((int )(j*256 - temp*10*256 + k*10)) /256;
+			}
+			// DS
+			i=0;
+			j=temp=temp2=0;
+			NOMPSD_DS_MAKECMV;
+			if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+				printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+				i=-1;
+			}
+			else{
+				j=RxMessage[4];
+			}
+			PCB_DS_MAKECMV;
+			if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+				printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+				i=-1;
+			}
+			else{
+				temp=RxMessage[4];
+			}
+			RMSGI_DS_MAKECMV;
+			if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+				printk("\n\nCMV fail, Group PLAM Address 35 Index 0");
+#endif
+				i=-1;
+			}
+			else{
+				//temp2=RxMessage[4];
+				k=(int16_t)RxMessage[4];
+			}
+			if (i==0)
+			{
+				pts.adslPowerSpectralDensity_pt->ACTPSDds = ((int )(j*256 - temp*10*256 + k*10)) /256;
+			}
+			copy_to_user((char *)lon, (char *)pts.adslPowerSpectralDensity_pt, sizeof(adslPowerSpectralDensity));	
+			kfree(pts.adslPowerSpectralDensity_pt);		
+			up(&mei_sema);
+			break;
+                case AMAZON_MEI_START:
+			showtime=0;
+			loop_diagnostics_completed = 0;
+#ifdef	ARC_READY_ACK
+#ifdef LOCK_RETRY
+			i=0;
+lock_retry:
+			if(down_trylock(&mei_sema)!=0)
+			{
+				reboot_lock = 1;
+				printk("lock fail\n");
+				i++;
+				if (i <=5)
+				{
+	        			set_current_state(TASK_INTERRUPTIBLE);
+	                		schedule_timeout(10);
+					goto lock_retry;
+				}else
+				{
+					printk("Force to Reboot ADSL!\n");
+					up(&mei_sema);
+	        			set_current_state(TASK_INTERRUPTIBLE);
+	                		schedule_timeout(1000);
+	        			sema_init(&mei_sema, 1);  // semaphore initialization, mutex
+				}
+			}else
+			{
+				reboot_lock = 1;
+			}
+#else
+			if(down_interruptible(&mei_sema))	//disable CMV access until ARC ready
+			{
+	                	return -ERESTARTSYS;
+			}
+#endif
+#endif
+                	//CLEAR_BIT((*((volatile u32 *)0xB0100B40)), 0x40); //Warning LED GPIO ON
+			if(chantype.interleave==1){
+				kfree(interleave_mei_net.priv);
+				unregister_netdev(&interleave_mei_net);
+			}
+			else if(chantype.fast==1){
+				kfree(fast_mei_net.priv);
+				unregister_netdev(&fast_mei_net);
+			}		
+			chantype.interleave=0;
+			chantype.fast=0;
+			meiMailboxInterruptsDisable(); //disable all MEI interrupts
+			if(mei_arc_swap_buff == NULL){
+			mei_arc_swap_buff = (u32 *)kmalloc(MAXSWAPSIZE*4, GFP_KERNEL);
+			if(mei_arc_swap_buff==NULL){
+#ifdef AMAZON_MEI_DEBUG_ON
+				printk("\n\n malloc fail for codeswap buff");
+#endif
+				meierr=MEI_FAILURE;
+			}
+			}
+                        if(meiForceRebootAdslModem() != MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+                                printk("\n\n meiForceRebootAdslModem()  error...");
+#endif
+                                meierr=MEI_FAILURE;
+                        }     
+			interruptible_sleep_on(&wait_queue_codeswap);
+			// reset is called
+                        break;
+		case AMAZON_MEI_MIB_DAEMON:
+#ifdef IFX_SMALL_FOOTPRINT /* [ */
+			return -1;
+#else /* ][ !IFX_SMALL_FOOTPRINT */
+			i=0;
+			while(1){
+				if(i<MIB_INTERVAL)
+					interruptible_sleep_on_timeout(&wait_queue_mibdaemon, ((MIB_INTERVAL-i)/(1000/HZ)));
+				i=0;
+				if(showtime==1){
+//					printk("\n\n update mib");
+					
+					do_gettimeofday(&time_now);
+					if(time_now.tv_sec - current_intvl->start_time.tv_sec>=900){
+						if(current_intvl->list.next!=&interval_list){
+							current_intvl = list_entry(current_intvl->list.next, amazon_mei_mib, list);
+							do_gettimeofday(&(current_intvl->start_time));
+						}
+						else{
+							mib_ptr = list_entry(interval_list.next, amazon_mei_mib, list);
+							list_del(interval_list.next);
+							memset(mib_ptr, 0, sizeof(amazon_mei_mib));
+							list_add_tail(&(mib_ptr->list), &interval_list);
+							if(current_intvl->list.next==&interval_list)
+#ifdef AMAZON_MEI_DEBUG_ON
+								printk("\n\nlink list error");
+#endif
+							current_intvl = list_entry(current_intvl->list.next, amazon_mei_mib, list);
+							do_gettimeofday(&(current_intvl->start_time));
+						}	
+					}
+					
+					if(down_interruptible(&mei_sema))
+                				return -ERESTARTSYS;
+/*						
+					ATUC_PERF_LO_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 7 Address 0 Index 0");
+#endif
+					}
+					else{
+						if(RxMessage[4]&PLAM_LOS_FailureBit){
+							current_intvl->AtucPerfLos++;
+							ATUC_PERF_LOSS++;
+							CurrStatus.adslAtucCurrStatus = 2;
+						}
+						if(RxMessage[4]&PLAM_LOF_FailureBit){
+							current_intvl->AtucPerfLof++;
+							ATUC_PERF_LOFS++;
+							CurrStatus.adslAtucCurrStatus = 1;
+						}
+						if(!(RxMessage[4]&(PLAM_LOS_FailureBit|PLAM_LOF_FailureBit)))
+							CurrStatus.adslAtucCurrStatus = 0;
+					}
+*/
+					ATUC_PERF_ESS_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 7 Address 7 Index 0");
+#endif
+					}
+					else{
+						temp = RxMessage[4]-mib_pread.ATUC_PERF_ESS;
+						if(temp>=0){
+							current_intvl->AtucPerfEs+=temp;
+							ATUC_PERF_ESS+=temp;
+							mib_pread.ATUC_PERF_ESS = RxMessage[4];
+						}
+						else{
+							current_intvl->AtucPerfEs+=0xffff-mib_pread.ATUC_PERF_ESS+RxMessage[4];
+							ATUC_PERF_ESS+=0xffff-mib_pread.ATUC_PERF_ESS+RxMessage[4];
+							mib_pread.ATUC_PERF_ESS = RxMessage[4];		
+						}
+					}
+/*		
+					ATUR_PERF_LO_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 7 Address 1 Index 0");
+#endif
+					}
+					else{
+						if(RxMessage[4]&PLAM_LOS_FailureBit){
+							current_intvl->AturPerfLos++;
+							ATUR_PERF_LOSS++;
+							CurrStatus.adslAturCurrStatus = 2;
+						}
+						if(RxMessage[4]&PLAM_LOF_FailureBit){
+							current_intvl->AturPerfLof++;
+							ATUR_PERF_LOFS++;
+							CurrStatus.adslAturCurrStatus = 1;
+						}
+						if(RxMessage[4]&PLAM_LPR_FailureBit){
+							current_intvl->AturPerfLpr++;
+							ATUR_PERF_LPR++;
+							CurrStatus.adslAturCurrStatus = 3;
+						}
+						if(!(RxMessage[4]&(PLAM_LOS_FailureBit|PLAM_LOF_FailureBit|PLAM_LPR_FailureBit)))
+							CurrStatus.adslAturCurrStatus = 0;	
+					}
+*/
+					ATUR_PERF_ESS_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 7 Address 33 Index 0");
+#endif
+					}
+					else{
+						temp = RxMessage[4]-mib_pread.ATUR_PERF_ESS;
+						if(temp>=0){
+							current_intvl->AturPerfEs+=temp;
+							ATUR_PERF_ESS+=temp;
+							mib_pread.ATUR_PERF_ESS = RxMessage[4];
+						}
+						else{
+							current_intvl->AturPerfEs+=0xffff-mib_pread.ATUR_PERF_ESS+RxMessage[4];
+							ATUR_PERF_ESS+=	0xffff-mib_pread.ATUR_PERF_ESS+RxMessage[4];
+							mib_pread.ATUR_PERF_ESS=RxMessage[4];
+						}
+					}
+					// to update rx/tx blocks
+					ATUR_CHAN_RECV_BLK_FLAG_MAKECMV_LSW;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 7 Address 20 Index 0");
+#endif
+					}
+					else{
+						temp = RxMessage[4];	
+					}
+					ATUR_CHAN_RECV_BLK_FLAG_MAKECMV_MSW;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 7 Address 21 Index 0");
+#endif
+					}
+					else{
+						temp2 = RxMessage[4];	
+					}
+					if((temp + (temp2<<16) - mib_pread.ATUR_CHAN_RECV_BLK)>=0){
+						current_intvl->AturChanPerfRxBlk+=temp + (temp2<<16) - mib_pread.ATUR_CHAN_RECV_BLK;
+						ATUR_CHAN_RECV_BLK+=temp + (temp2<<16) - mib_pread.ATUR_CHAN_RECV_BLK;
+						mib_pread.ATUR_CHAN_RECV_BLK = temp + (temp2<<16);
+						}	
+					else{
+						current_intvl->AturChanPerfRxBlk+=0xffffffff - mib_pread.ATUR_CHAN_RECV_BLK +(temp + (temp2<<16));
+						ATUR_CHAN_RECV_BLK+=0xffffffff - mib_pread.ATUR_CHAN_RECV_BLK +(temp + (temp2<<16));
+						mib_pread.ATUR_CHAN_RECV_BLK = temp + (temp2<<16);
+					}
+					current_intvl->AturChanPerfTxBlk = current_intvl->AturChanPerfRxBlk;
+					ATUR_CHAN_TX_BLK = ATUR_CHAN_RECV_BLK;
+/*					
+					ATUR_CHAN_TX_BLK_FLAG_MAKECMV_LSW;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS)
+						printk("\n\nCMV fail, Group 7 Address 20 Index 0");
+					else{
+						if(RxMessage[4]){
+							current_intvl->AturChanPerfTxBlk+=RxMessage[4];
+							ATUR_CHAN_TX_BLK+=RxMessage[4];
+						}	
+					}
+					ATUR_CHAN_TX_BLK_FLAG_MAKECMV_MSW;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS)
+						printk("\n\nCMV fail, Group 7 Address 21 Index 0");
+					else{
+						if(RxMessage[4]){
+							current_intvl->AturChanPerfTxBlk+=(int)((RxMessage[4])<<16);
+							ATUR_CHAN_TX_BLK+=(int)((RxMessage[4])<<16);
+						}	
+					}
+*/					
+					if(chantype.interleave == 1){
+						ATUR_CHAN_CORR_BLK_FLAG_MAKECMV_INTL;
+						if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group 7 Address 3 Index 0");
+#endif
+						}
+						else{
+							temp = RxMessage[4] - mib_pread.ATUR_CHAN_CORR_BLK_INTL;
+							if(temp>=0){
+								current_intvl->AturChanPerfCorrBlk+=temp;
+								ATUR_CHAN_CORR_BLK+=temp;
+								mib_pread.ATUR_CHAN_CORR_BLK_INTL = RxMessage[4];
+							}	
+							else{
+								current_intvl->AturChanPerfCorrBlk+=0xffff - mib_pread.ATUR_CHAN_CORR_BLK_INTL +RxMessage[4];
+								ATUR_CHAN_CORR_BLK+=0xffff - mib_pread.ATUR_CHAN_CORR_BLK_INTL +RxMessage[4];
+								mib_pread.ATUR_CHAN_CORR_BLK_INTL = RxMessage[4];	
+							}	
+						}	
+					}
+					else if(chantype.fast == 1){
+						ATUR_CHAN_CORR_BLK_FLAG_MAKECMV_FAST;
+						if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group 7 Address 3 Index 1");
+#endif
+						}
+						else{
+							temp = RxMessage[4] - mib_pread.ATUR_CHAN_CORR_BLK_FAST;
+							if(temp>=0){
+								current_intvl->AturChanPerfCorrBlk+=temp;
+								ATUR_CHAN_CORR_BLK+=temp;
+								mib_pread.ATUR_CHAN_CORR_BLK_FAST = RxMessage[4];
+							}	
+							else{
+								current_intvl->AturChanPerfCorrBlk+=0xffff - mib_pread.ATUR_CHAN_CORR_BLK_FAST + RxMessage[4];
+								ATUR_CHAN_CORR_BLK+=0xffff - mib_pread.ATUR_CHAN_CORR_BLK_FAST + RxMessage[4];
+								mib_pread.ATUR_CHAN_CORR_BLK_FAST = RxMessage[4];
+							}	
+						}		
+					}
+					
+					if(chantype.interleave == 1){
+						ATUR_CHAN_UNCORR_BLK_FLAG_MAKECMV_INTL;
+						if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group 7 Address 2 Index 0");
+#endif
+						}
+						else{
+							temp = RxMessage[4] - mib_pread.ATUR_CHAN_UNCORR_BLK_INTL;
+							if(temp>=0){
+								current_intvl->AturChanPerfUncorrBlk+=temp;
+								ATUR_CHAN_UNCORR_BLK+=temp;
+								mib_pread.ATUR_CHAN_UNCORR_BLK_INTL = RxMessage[4];
+							}
+							else{
+								current_intvl->AturChanPerfUncorrBlk+=0xffff - mib_pread.ATUR_CHAN_UNCORR_BLK_INTL + RxMessage[4];
+								ATUR_CHAN_UNCORR_BLK+=0xffff - mib_pread.ATUR_CHAN_UNCORR_BLK_INTL + RxMessage[4];
+								mib_pread.ATUR_CHAN_UNCORR_BLK_INTL = RxMessage[4];
+							}
+						}		
+					}
+					else if(chantype.fast == 1){
+						ATUR_CHAN_UNCORR_BLK_FLAG_MAKECMV_FAST;
+						if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n\nCMV fail, Group 7 Address 2 Index 1");
+#endif
+						}
+						else{
+							temp = RxMessage[4] - mib_pread.ATUR_CHAN_UNCORR_BLK_FAST;
+							if(temp>=0){
+								current_intvl->AturChanPerfUncorrBlk+=temp;
+								ATUR_CHAN_UNCORR_BLK+=temp;
+								mib_pread.ATUR_CHAN_UNCORR_BLK_FAST = RxMessage[4];
+							}
+							else{
+								current_intvl->AturChanPerfUncorrBlk+=0xffff - mib_pread.ATUR_CHAN_UNCORR_BLK_FAST + RxMessage[4];
+								ATUR_CHAN_UNCORR_BLK+=0xffff - mib_pread.ATUR_CHAN_UNCORR_BLK_FAST + RxMessage[4];
+								mib_pread.ATUR_CHAN_UNCORR_BLK_FAST = RxMessage[4];
+							}
+						}		
+					}
+					
+					//RFC-3440
+
+#ifdef AMAZON_MEI_MIB_RFC3440
+					ATUC_PERF_STAT_FASTR_FLAG_MAKECMV; //???
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 0 Address 0 Index 0");
+#endif
+					}
+					else{
+						temp = RxMessage[4] - mib_pread.ATUC_PERF_STAT_FASTR;
+						if(temp>=0){
+							current_intvl->AtucPerfStatFastR+=temp;
+							ATUC_PERF_STAT_FASTR+=temp;
+							mib_pread.ATUC_PERF_STAT_FASTR = RxMessage[4];
+						}
+						else{
+							current_intvl->AtucPerfStatFastR+=0xffff - mib_pread.ATUC_PERF_STAT_FASTR + RxMessage[4];
+							ATUC_PERF_STAT_FASTR+=0xffff - mib_pread.ATUC_PERF_STAT_FASTR + RxMessage[4];
+							mib_pread.ATUC_PERF_STAT_FASTR = RxMessage[4];
+						}
+					}
+					ATUC_PERF_STAT_FAILED_FASTR_FLAG_MAKECMV; //???
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 0 Address 0 Index 0");
+#endif
+					}
+					else{
+						temp = RxMessage[4] - mib_pread.ATUC_PERF_STAT_FAILED_FASTR;
+						if(temp>=0){
+							current_intvl->AtucPerfStatFailedFastR+=temp;
+							ATUC_PERF_STAT_FAILED_FASTR+=temp;
+							mib_pread.ATUC_PERF_STAT_FAILED_FASTR = RxMessage[4];
+						}
+						else{
+							current_intvl->AtucPerfStatFailedFastR+=0xffff - mib_pread.ATUC_PERF_STAT_FAILED_FASTR + RxMessage[4];
+							ATUC_PERF_STAT_FAILED_FASTR+=0xffff - mib_pread.ATUC_PERF_STAT_FAILED_FASTR + RxMessage[4];
+							mib_pread.ATUC_PERF_STAT_FAILED_FASTR = RxMessage[4];
+						}
+					}
+					ATUC_PERF_STAT_SESL_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 7 Address 8 Index 0");
+#endif
+					}
+					else{
+						temp = RxMessage[4] - mib_pread.ATUC_PERF_STAT_SESL;
+						if(temp>=0){
+							current_intvl->AtucPerfStatSesL+=temp;
+							ATUC_PERF_STAT_SESL+=temp;
+							mib_pread.ATUC_PERF_STAT_SESL = RxMessage[4];
+						}
+						else{
+							current_intvl->AtucPerfStatSesL+=0xffff - mib_pread.ATUC_PERF_STAT_SESL + RxMessage[4];
+							ATUC_PERF_STAT_SESL+=0xffff - mib_pread.ATUC_PERF_STAT_SESL + RxMessage[4];
+							mib_pread.ATUC_PERF_STAT_SESL = RxMessage[4];
+						}
+					}
+					ATUC_PERF_STAT_UASL_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 7 Address 10 Index 0");
+#endif
+					}
+					else{
+						temp = RxMessage[4] - mib_pread.ATUC_PERF_STAT_UASL;
+						if(temp>=0){
+							current_intvl->AtucPerfStatUasL+=temp;
+							ATUC_PERF_STAT_UASL+=temp;
+							mib_pread.ATUC_PERF_STAT_UASL = RxMessage[4];
+						}
+						else{
+							current_intvl->AtucPerfStatUasL+=0xffff - mib_pread.ATUC_PERF_STAT_UASL + RxMessage[4];
+							ATUC_PERF_STAT_UASL+=0xffff - mib_pread.ATUC_PERF_STAT_UASL + RxMessage[4];
+							mib_pread.ATUC_PERF_STAT_UASL = RxMessage[4];
+						}
+					}
+					ATUR_PERF_STAT_SESL_FLAG_MAKECMV;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 7 Address 34 Index 0");
+#endif
+					}
+					else{
+						temp = RxMessage[4] - mib_pread.ATUR_PERF_STAT_SESL;
+						if(temp>=0){
+							current_intvl->AtucPerfStatUasL+=temp;
+							ATUC_PERF_STAT_UASL+=temp;
+							mib_pread.ATUR_PERF_STAT_SESL = RxMessage[4];
+						}
+						else{
+							current_intvl->AtucPerfStatUasL+=0xffff - mib_pread.ATUR_PERF_STAT_SESL + RxMessage[4];
+							ATUC_PERF_STAT_UASL+=0xffff - mib_pread.ATUR_PERF_STAT_SESL + RxMessage[4];
+							mib_pread.ATUR_PERF_STAT_SESL = RxMessage[4];
+						}
+					}
+					
+#endif
+					up(&mei_sema);
+					
+					do_gettimeofday(&time_fini);
+					i = ((int)((time_fini.tv_sec-time_now.tv_sec)*1000)) + ((int)((time_fini.tv_usec-time_now.tv_usec)/1000))  ; //msec 
+				}//showtime==1
+			}	 
+			break;
+#endif /* ] !IFX_SMALL_FOOTPRINT */
+		case AMAZON_MEI_RESET:			
+		case AMAZON_MEI_REBOOT:
+		case AMAZON_MEI_SHOWTIME:
+/*			if(mei_arc_swap_buff !=NULL){
+				kfree(mei_arc_swap_buff);
+				mei_arc_swap_buff=NULL;
+			}	
+			if(image_buffer !=NULL){
+//				kfree(image_buffer);
+				vfree(image_buffer);
+				image_buffer =NULL;
+			}
+*/
+			if(clreoc_command_pkt !=NULL){
+				kfree(clreoc_command_pkt);
+				clreoc_command_pkt =NULL;
+			}
+			for(i=0;i<CLREOC_BUFF_SIZE;i++)
+				clreoc_pkt[i].len=0;	//flush all remaining clreoc commands in buffer
+/*
+			memset(mei_mib, 0, (sizeof(amazon_mei_mib)*INTERVAL_NUM));
+			INIT_LIST_HEAD(&interval_list);
+			for(i=0;i<INTERVAL_NUM;i++)
+				list_add_tail(&(mei_mib[i].list), &interval_list); 
+			current_intvl = list_entry(interval_list.next, amazon_mei_mib, list);
+			do_gettimeofday(&(current_intvl->start_time));
+			ATUC_PERF_LOFS=0;
+			ATUC_PERF_LOSS=0;
+			ATUC_PERF_ESS=0;
+	 		ATUC_PERF_INITS=0;
+ 			ATUR_PERF_LOFS=0;
+	 		ATUR_PERF_LOSS=0;
+	 		ATUR_PERF_LPR=0;
+	 		ATUR_PERF_ESS=0;
+	 		ATUR_CHAN_RECV_BLK=0;
+	 		ATUR_CHAN_TX_BLK=0;
+	 		ATUR_CHAN_CORR_BLK=0;
+	 		ATUR_CHAN_UNCORR_BLK=0;
+			memset((((u8 *)&AlarmConfProfile)+32), 0, 16*4);
+			AlarmConfProfile.adslLineAlarmConfProfileRowStatus=1;
+*/
+			PrevTxRate.adslAtucChanPrevTxRate=0;
+			PrevTxRate.adslAturChanPrevTxRate=0;
+			CurrStatus.adslAtucCurrStatus=0;
+			CurrStatus.adslAturCurrStatus=0;
+			
+			if((command==AMAZON_MEI_RESET) || (command==AMAZON_MEI_REBOOT)){
+#ifdef	AMAZON_CHECK_LINK
+				if (adsl_link_notify){
+					(*adsl_link_notify)(0);
+				}
+#endif
+				showtime=0;
+				//CLEAR_BIT((*((volatile u32 *)0xB0100B40)), 0x40); //Warning LED GPIO ON
+				// disconnect net_dev
+				if(chantype.interleave==1){
+					kfree(interleave_mei_net.priv);
+					unregister_netdev(&interleave_mei_net);
+//        				if(unregister_netdev(&interleave_mei_net)!=0)
+//						printk("\n unregister interleave fail");
+				}
+				else if(chantype.fast==1){
+					kfree(fast_mei_net.priv);
+					unregister_netdev(&fast_mei_net);
+//       				if(unregister_netdev(&fast_mei_net)!=0)
+//						printk("\n unregister fast fail");
+				}
+				chantype.interleave=0;
+				chantype.fast=0;
+// 603221:tc.chen start
+				chantype.bearchannel0 = 0;
+				chantype.bearchannel1 = 0;
+				adsl_mode = 0;
+// 603221:tc.chen end
+				
+				while(1){
+					
+					makeCMV(H2D_CMV_READ, STAT, 0, 0, 1, NULL); //maximum allowed tx message length, in bytes
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+						//printk("AdslInitStatsData.FullInitializationCount++\n");
+						AdslInitStatsData.FullInitializationCount++;
+						//printk("AdslInitStatsData.FailedFullInitializationCount++\n");
+						AdslInitStatsData.FailedFullInitializationCount++;
+						//printk("AdslInitStatsData.LINIT_Errors++\n");
+						AdslInitStatsData.LINIT_Errors++;
+					}else
+					{
+						//printk("RxMessage=%X\n",RxMessage[4]);
+						if ( RxMessage[4]!=0x1)
+						{
+							//printk("AdslInitStatsData.FullInitializationCount++\n");
+							AdslInitStatsData.FullInitializationCount++;	
+							if ( RxMessage[4] != 0x7)
+							{
+								//printk("AdslInitStatsData.LINIT_Errors++\n");
+								AdslInitStatsData.LINIT_Errors++;
+								//printk("AdslInitStatsData.FailedFullInitializationCount++\n");
+								AdslInitStatsData.FailedFullInitializationCount++;
+								
+							}			
+						}
+					}
+
+					reboot_flag=0;
+					wake_up_interruptible(&wait_queue_codeswap); //wake up codeswap daemon				
+
+					interruptible_sleep_on_timeout(&wait_queue_reboot, 1*HZ);  // sleep until arc ready
+#ifdef	ARC_READY_ACK
+					if(reboot_flag!=0)
+						break;
+					else
+					{
+						up(&mei_sema);
+						printk("\n reboot retry");
+					}
+#else
+					break;
+#endif
+				}
+			}
+			else{ //AMAZON_MEI_SHOWTIME 
+				if(down_interruptible(&mei_sema))
+                			return -ERESTARTSYS;
+				
+				// clreoc stuff
+				makeCMV(H2D_CMV_READ, INFO, 83, 0, 1, data); //maximum allowed tx message length, in bytes
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 83 Index 0");
+#endif
+				}
+				else{
+					clreoc_max_tx_len = (int)RxMessage[4];
+					clreoc_command_pkt = kmalloc((clreoc_max_tx_len*CLREOC_BUFF_SIZE), GFP_KERNEL);
+					if(clreoc_command_pkt == NULL){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("kmalloc error for clreoc_command_pkt\n\n");
+#endif
+						up(&mei_sema);
+						return -1;
+					}
+					for(i=0;i<CLREOC_BUFF_SIZE;i++){
+						clreoc_pkt[i].command = (u8 *)(((u8 *)clreoc_command_pkt) + (clreoc_max_tx_len*i));
+						clreoc_pkt[i].len=0;
+					}	
+				}
+				
+				// decide what channel, then register	
+				makeCMV(H2D_CMV_READ, STAT, 12, 0, 1, data); 
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 2 Address 12 Index 0");
+#endif
+				}
+				else{
+					if((RxMessage[4]&0x1)==1){	
+						if(register_netdev(&interleave_mei_net)!=0){
+#ifdef AMAZON_MEI_DEBUG_ON
+                					printk("\n\n Register interleave Device Failed.");
+#endif
+        					}
+						else{
+							chantype.interleave = 1;
+							chantype.fast= 0;
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n channel is interleave");
+#endif
+						}	
+					}
+					else if((RxMessage[4]&0x2)==2){	
+						if(register_netdev(&fast_mei_net)!=0){
+#ifdef AMAZON_MEI_DEBUG_ON
+                					printk("\n\n Register fast Device Failed.");
+#endif
+        					}
+						else{
+							chantype.fast = 1;
+							chantype.interleave = 0;
+#ifdef AMAZON_MEI_DEBUG_ON
+							printk("\n channel is fast");
+#endif
+						}
+					}
+					else{
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\nunknown channel type, 0x%8x", RxMessage[4]);
+#endif
+					}	
+// 603221:tc.chen start	
+					if ( (RxMessage[4]&0x100) == 0x100)
+					{
+						chantype.bearchannel0 = 1;
+					}else 	if ( (RxMessage[4]&0x100) == 0x200)
+					{
+						chantype.bearchannel1 = 1;
+					}
+// 603221:tc.chen end
+				}
+// 603221:tc.chen start			
+				// read adsl mode
+				makeCMV(H2D_CMV_READ, STAT, 1, 0, 1, data); 
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group STAT Address 1 Index 0");
+#endif
+				}
+				adsl_mode = RxMessage[4];
+// 603221:tc.chen end
+				makeCMV(H2D_CMV_READ, STAT, 17, 0, 1, data); 
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group STAT Address 1 Index 0");
+#endif
+				}
+				adsl_mode_extend = RxMessage[4];
+				
+				// update previous channel tx rate
+				ATUC_CHAN_CURR_TX_RATE_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 6 Address 1 Index 0");
+#endif
+					PrevTxRate.adslAtucChanPrevTxRate = 0;	
+				}
+				else{
+					PrevTxRate.adslAtucChanPrevTxRate = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16);
+				}
+				ATUR_CHAN_CURR_TX_RATE_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 6 Address 0 Index 0");
+#endif
+					PrevTxRate.adslAturChanPrevTxRate = 0;	
+				}
+				else{
+					PrevTxRate.adslAturChanPrevTxRate = (u32)(RxMessage[4]) + (((u32)(RxMessage[5]))<<16);
+				}
+				
+//				up(&mei_sema);
+				
+//				showtime=1;
+				//SET_BIT((*((volatile u32 *)0xB0100B40)), 0x40); //Warning LED GPIO OFF
+//dying gasp -start	
+#ifdef IFX_DYING_GASP			
+				lop_debugwr.buffer[0]=0xffffffff;		//dying gasp
+				lop_debugwr.iCount=1;				//dying gasp
+				makeCMV(H2D_CMV_READ, INFO, 66, 4, 1, NULL);
+				//mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, &RxMessage);	
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 66 Index 4");
+				}
+#endif
+				lop_debugwr.iAddress=(u32)RxMessage[4];
+				makeCMV(H2D_CMV_READ, INFO, 66, 5, 1, NULL);
+				//mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, &RxMessage);			
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 3 Address 66 Index 5");
+				}
+#endif
+				lop_debugwr.iAddress+=((u32)RxMessage[4])<<16;
+				
+//dying gasp -end				
+#endif	// IFX_DYING_GASP			
+
+//joelin 04/16/2005-start
+				makeCMV(H2D_CMV_WRITE, PLAM, 10, 0, 1, &unavailable_seconds);
+				//mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, &RxMessage);			
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 7 Address 10 Index 0");
+				
+#endif
+				}
+				
+
+//joelin 04/16/2005-end		
+				showtime=1;
+				up(&mei_sema);
+#ifdef	AMAZON_CHECK_LINK
+				if (adsl_link_notify){
+					(*adsl_link_notify)(1);
+				}
+#endif
+				
+				
+			}
+			break;
+/*
+                case AMAZON_MEI_REPLY:
+                        copy_from_user((char *)buff, (char *)lon, MSG_LENGTH * 2);
+                        if(meiCMV(buff, YES_REPLY) != MEI_SUCCESS){
+                                printk("\n\n meiCMV no reply back");
+                                meierr=MEI_FAILURE;
+                        }
+                        else
+                                copy_to_user((char *)lon, (char *)RxMessage, MSG_LENGTH * 2);
+                        break;
+                case AMAZON_MEI_NOREPLY:
+                        copy_from_user((char *)buff, (char *)lon, MSG_LENGTH * 2);
+                        if(meiCMV(buff, NO_REPLY) != MEI_SUCCESS){
+                                printk("\n\n meiCMV Host to DSP failed");
+                                meierr=MEI_FAILURE;
+                        }  
+                        break;
+*/
+		
+		case AMAZON_MEI_HALT:
+			meiHaltArc();
+			break;
+		case AMAZON_MEI_CMV_WINHOST:
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+
+			if (!from_kernel )	
+				copy_from_user((char *)TxMessage, (char *)lon, MSG_LENGTH*2);//joelin
+			else
+				memcpy(TxMessage,(char *)lon,MSG_LENGTH*2);
+				
+#if 0			
+//			if((TxMessage[0]&0xff0)==0x0a0){
+				for(i=0;i<16;i++){
+					printk("\nTxMessage[%i]=%8x", i, TxMessage[i]);
+				}
+//			}			
+#endif			
+			
+			if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+//				printk("\n\n WINHOST CMV fail ");
+                                printk("\n\nWINHOST CMV fail :TxMessage:%X %X %X %X, RxMessage:%X %X %X %X %X\n",TxMessage[0],TxMessage[1],TxMessage[2],TxMessage[3],RxMessage[0],RxMessage[1],RxMessage[2],RxMessage[3],RxMessage[4]);
+#endif
+				meierr = MEI_FAILURE;	
+			}
+			else 
+			{
+				if (!from_kernel )	//joelin
+				copy_to_user((char *)lon, (char *)RxMessage, MSG_LENGTH*2);
+				else
+					memcpy((char *)lon,(char *)RxMessage,MSG_LENGTH*2);
+			}
+				
+			up(&mei_sema);	
+			break;
+#ifdef AMAZON_MEI_CMV_EXTRA
+		case AMAZON_MEI_CMV_READ:
+			copy_from_user((char *)(&regrdwr), (char *)lon, sizeof(meireg));
+			meiLongwordRead(regrdwr.iAddress, &(regrdwr.iData));
+			{
+//				printk("\n\n iAddress = %8x",regrdwr.iAddress);
+			}
+			copy_to_user((char *)lon, (char *)(&regrdwr), sizeof(meireg));
+			{
+//				printk("\n\n iData readback = %8x", regrdwr.iData);
+			}
+			break;
+#endif
+
+#ifdef AMAZON_MEI_CMV_EXTRA
+		case AMAZON_MEI_CMV_WRITE:
+			copy_from_user((char *)(&regrdwr), (char *)lon, sizeof(meireg));
+			{
+//				printk("\n\n iAddress = %8x",regrdwr.iAddress);
+//				printk("\n\n iData = %8x",regrdwr.iData);
+			}
+			meiLongwordWrite(regrdwr.iAddress, regrdwr.iData);
+			break;
+#endif
+
+#ifdef AMAZON_MEI_CMV_EXTRA
+		case AMAZON_MEI_REMOTE:
+			copy_from_user((char *)(&i), (char *)lon, sizeof(int));
+			if(i==0){
+				meiMailboxInterruptsEnable();
+					
+				up(&mei_sema);
+			}
+			else if(i==1){
+				meiMailboxInterruptsDisable();
+				if(down_interruptible(&mei_sema))
+                			return -ERESTARTSYS;
+			}
+			else{
+#ifdef AMAZON_MEI_DEBUG_ON
+				printk("\n\n AMAZON_MEI_REMOTE argument error");
+#endif
+				meierr=MEI_FAILURE;
+			}		
+			break;
+#endif
+
+#ifdef AMAZON_MEI_CMV_EXTRA
+		case AMAZON_MEI_READDEBUG:
+		case AMAZON_MEI_WRITEDEBUG:
+			if(down_interruptible(&mei_sema))
+                		return -ERESTARTSYS;
+#ifdef IFX_DYING_GASP			
+	if (!from_kernel) copy_from_user((char *)(&debugrdwr), (char *)lon, sizeof(debugrdwr));//dying gasp
+				else memcpy((char *)(&debugrdwr), (char *)lon,  sizeof(debugrdwr));
+#else //IFX_DYING_GASP	
+			copy_from_user((char *)(&debugrdwr), (char *)lon, sizeof(debugrdwr));
+
+#endif //IFX_DYING_GASP							
+#if 0
+			printk("\nIN iAddress: %8x, iCount:%8x\n", debugrdwr.iAddress, debugrdwr.iCount);
+#endif
+			
+			if(command==AMAZON_MEI_READDEBUG)
+				meiDebugRead(debugrdwr.iAddress, debugrdwr.buffer, debugrdwr.iCount);
+			else
+				meiDebugWrite(debugrdwr.iAddress, debugrdwr.buffer, debugrdwr.iCount);	
+				
+#ifdef IFX_DYING_GASP				
+			if (!from_kernel) copy_to_user((char *)lon, (char*)(&debugrdwr), sizeof(debugrdwr));//dying gasp
+#else //IFX_DYING_GASP	
+			copy_to_user((char *)lon, (char*)(&debugrdwr), sizeof(debugrdwr));
+#endif //IFX_DYING_GASP	
+			up(&mei_sema);
+			
+#if 0
+			printk("\nOUT iAddress: %8x, iCount:%8x\n", debugrdwr.iAddress, debugrdwr.iCount);
+			for(i=0;i<debugrdwr.iCount;i++)
+				printk("\n %8x",debugrdwr.buffer[i]);
+#endif
+			break;
+#endif
+
+		case AMAZON_MEI_LOP:	
+		//GPIO31 :dying gasp event indication
+		//	(1) logic high: dying gasp event is false (default)
+		//	(2) logic low: dying gasp event is true
+#ifdef IFX_DYING_GASP
+			break;
+#else					
+			CLEAR_BIT((*((volatile u32 *)0xB0100B48)), 0x8000);
+			CLEAR_BIT((*((volatile u32 *)0xB0100B4C)), 0x8000);
+			CLEAR_BIT((*((volatile u32 *)0xB0100B50)), 0x8000);
+			SET_BIT((*((volatile u32 *)0xB0100B54)), 0x8000);
+			asm("SYNC");
+			if(((*((volatile u32 *)0xB0100B44))&0x8000)==0x0)
+				meierr=MEI_FAILURE; //return - to indicate loss of power
+			break;
+#endif //#ifdef IFX_DYING_GASP			
+			
+					//for PCM
+		case AMAZON_MEI_PCM_SETUP:
+			//gpio
+			
+			*AMAZON_GPIO_P0_DIR |=1<<15;
+    			*AMAZON_GPIO_P0_ALTSEL0 |=1<<15;
+    			*AMAZON_GPIO_P0_ALTSEL1 &=~(1<<15);
+    			*AMAZON_GPIO_P0_OD |=1<<15;
+                                                                                
+    			/*GPIO 16 TDM_DI*/
+    			*AMAZON_GPIO_P1_DIR &=~1;
+    			*AMAZON_GPIO_P1_ALTSEL0 |=1;
+    			*AMAZON_GPIO_P1_ALTSEL1 &=~1;
+                                                                                
+    			/*GPIO 17 TDM_DCL */
+    			*AMAZON_GPIO_P1_DIR|=0x02;
+    			*AMAZON_GPIO_P1_ALTSEL0|=0x02;
+    			*AMAZON_GPIO_P1_ALTSEL1 &=(u32)~0x02;
+    			*AMAZON_GPIO_P1_OD|=0x02;
+                                                                                
+    			/*GPIO 18 TDM FSC*/
+    			*AMAZON_GPIO_P1_DIR|=0x04;
+    			*AMAZON_GPIO_P1_ALTSEL0|=0x04;
+    			*AMAZON_GPIO_P1_ALTSEL1 &=(u32)~0x04;
+    			*AMAZON_GPIO_P1_OD|=0x04;
+			
+			for(i=0;i<2;i++){
+				for(j=0;j<256;j++)
+					sampledata[i*256+j]=j;
+			}
+			
+			pcm_start_addr = lon;
+			
+			printk("\n\n pcm_start_addr is %8x", lon);
+			
+			for(i=0;i<PCM_CHANNEL_NUM;i++){
+#ifdef	PCM_ACCESS_DEBUG
+				meiDebugRead_16((pcm_start_addr+i*16), (u32*)(pcm_data+i), 4);
+#else
+				meiDMARead_16((pcm_start_addr+i*16), (u32*)(pcm_data+i), 4);
+#endif
+				if((pcm_data[i].S!=8)||(pcm_data[i].len<1)||(pcm_data[i].rdindex!=0)||(pcm_data[i].wrindex!=0)||(pcm_data[i].flow!=0))
+					printk("\n\n pcm_data fill in wrongly\n\n");
+				printk("\npcm_data %d",i);
+				printk("\n S = %d", pcm_data[i].S);
+				printk("\n LSW = %4x", pcm_data[i].LSW);
+				printk("\n MSW = %4x", pcm_data[i].MSW);
+				printk("\n len = %d", pcm_data[i].len);
+				printk("\n rdindex = %d", pcm_data[i].rdindex);
+				printk("\n wrindex = %d", pcm_data[i].wrindex);	
+				printk("\n flow = %d", pcm_data[i].flow);				
+				pcm_data[i].finish=0;	
+				if(i%2==0){//tx channel
+					for(j=0;j<PCM_BUFF_SIZE/256;j++){
+						for(k=0;k<256;k++){
+							pcm_data[i].buff[j*256+k]=k;
+						/*	if(k%2==0)
+								pcm_data[i].buff[j*256+k]=0xaa;
+							else
+								pcm_data[i].buff[j*256+k]=0x55;*/
+						}
+					}
+#ifdef	PCM_ACCESS_DEBUG
+					meiDebugWrite_8((((u32)(pcm_data[i].LSW))+(((u32)(pcm_data[i].MSW))<<16)), (u32*)(pcm_data[i].buff),((pcm_data[i].len/4)/2));//fill half first
+//					meiDebugWrite_8((((u32)(pcm_data[i].LSW))+(((u32)(pcm_data[i].MSW))<<16)), (u32*)(pcm_data[i].buff),2);//fill half first
+#else
+					meiDMAWrite_8((((u32)(pcm_data[i].LSW))+(((u32)(pcm_data[i].MSW))<<16)), (u32*)(pcm_data[i].buff),((pcm_data[i].len/4)/2));//fill half first
+//					meiDMAWrite_8((((u32)(pcm_data[i].LSW))+(((u32)(pcm_data[i].MSW))<<16)), (u32*)(pcm_data[i].buff),2);//fill half first
+#endif
+					pcm_data[i].point=(pcm_data[i].len)/2;
+//					pcm_data[i].point=8;
+#ifdef	PCM_ACCESS_DEBUG
+					meiDebugRead_16(pcm_start_addr+i*16+12, &temp, 1);
+#else
+					meiDMARead_16(pcm_start_addr+i*16+12, &temp, 1);
+#endif
+					temp = (temp &0xffff) + (((u32)(pcm_data[i].point))<<16);
+#ifdef	PCM_ACCESS_DEBUG
+					meiDebugWrite_16(pcm_start_addr+i*16+12,&temp, 1);//update wrindex
+#else
+					meiDMAWrite_16(pcm_start_addr+i*16+12,&temp, 1);//update wrindex
+#endif
+				}
+				else{// rx channel
+					pcm_data[i].point=0;
+				}
+			}
+			break;
+		case AMAZON_MEI_PCM_START_TIMER:
+				/* GPTU timer 6 */
+			/* enable the timer in the PMU */
+        		*(AMAZON_PMU_PWDCR) = (*(AMAZON_PMU_PWDCR))| AMAZON_PMU_PWDCR_GPT|AMAZON_PMU_PWDCR_FPI;
+			/* setup the GPTU for timer tick  f_fpi == f_gptu*/
+			*(AMAZON_GPTU_CLC) = 0x100;
+			//reload value = fpi/(HZ * P), timer mode, Prescaler = 4 ( T6I = 000, T6BPS2 = 0)
+			*(AMAZON_GPTU_CAPREL) = (int)(117500000/(lon*4));	
+			*(AMAZON_GPTU_T6CON) = 0x80C0;
+			
+			if (request_irq(AMAZON_TIMER6_INT, amazon_timer6_interrupt_MEI,0, "hrt", NULL)!=0){
+#ifdef AMAZON_MEI_DEBUG_ON
+                		printk("\n\n unable to register irq for hrt!!!");
+#endif
+                		return -1;
+        		}
+			enable_irq(AMAZON_TIMER6_INT);
+			break;
+		case AMAZON_MEI_PCM_STOP_TIMER:
+			disable_irq(AMAZON_TIMER6_INT);
+			free_irq(AMAZON_TIMER6_INT, NULL);
+			break;
+		case AMAZON_MEI_PCM_CHECK:
+			for(i=0;i<PCM_CHANNEL_NUM;i++){
+				if(pcm_data[i].finish!=1)
+					return 0;	
+			}
+			for(i=0;i<PCM_CHANNEL_NUM/2;i++){
+				j=0;
+				while(1){
+					if((pcm_data[i*2+1].buff[j]==0x0) && (pcm_data[i*2+1].buff[j+1]==0x1)&& (pcm_data[i*2+1].buff[j+2]==0x2))
+						break;
+					else
+						j++;
+				}
+				printk("\n j=%d", j);
+				temp=0;
+				for(k=0;k<((PCM_BUFF_SIZE-j)/4);k++){
+					if(memcmp(pcm_data[i*2].buff+k*4, pcm_data[i*2+1].buff+j+k*4, 4)!=0){
+						temp++;
+						printk("\n\n%2x %2x %2x %2x %2x %2x %2x %2x\n\n", *((u8*)(pcm_data[i*2].buff+k*4)), *((u8*)(pcm_data[i*2].buff+k*4+1)),*((u8*)(pcm_data[i*2].buff+k*4+2)),*((u8*)(pcm_data[i*2].buff+k*4+3)),*((u8*)(pcm_data[i*2+1].buff+j+k*4)),*((u8*)(pcm_data[i*2+1].buff+j+k*4+1)),*((u8*)(pcm_data[i*2+1].buff+j+k*4+2)),*((u8*)(pcm_data[i*2+1].buff+j+k*4+3)));
+						break;
+					}
+				}
+				if(temp!=0)
+					printk("\n\n Channel pair %d not match: err32 %d\n\n", i, temp);
+				else
+					printk("\n\n Channel pair %d match\n\n", i);
+			}
+			for(i=0;i<PCM_CHANNEL_NUM;i++){
+				if(i%2==1){//rx channel
+#ifdef	PCM_ACCESS_DEBUG
+					meiDebugRead_16(pcm_start_addr+i*16+12, &temp, 1);
+#else
+					meiDMARead_16(pcm_start_addr+i*16+12, &temp, 1);
+#endif
+					printk("\n\nRx channel %d: Overflow Bytes %d", i, (temp&0xffff));	
+				}
+				else{//tx channel
+#ifdef	PCM_ACCESS_DEBUG
+					meiDebugRead_16(pcm_start_addr+i*16, &temp, 1);
+#else
+					meiDMARead_16(pcm_start_addr+i*16, &temp, 1);
+#endif
+					printk("\n\nElectra Err: %d",(temp&0xffff));		
+				}
+			}
+			//check electra overflow
+			
+			meierr=1;
+			break;
+		case AMAZON_MEI_PCM_GETDATA:
+			copy_to_user(lon, pcm_data[1].buff, PCM_BUFF_SIZE);
+			break;
+		case AMAZON_MEI_PCM_GPIO:
+			//gpio
+			
+			*AMAZON_GPIO_P0_DIR |=1<<15;
+    			*AMAZON_GPIO_P0_ALTSEL0 |=1<<15;
+    			*AMAZON_GPIO_P0_ALTSEL1 &=~(1<<15);
+    			*AMAZON_GPIO_P0_OD |=1<<15;
+                                                                                
+    			/*GPIO 16 TDM_DI*/
+    			*AMAZON_GPIO_P1_DIR &=~1;
+    			*AMAZON_GPIO_P1_ALTSEL0 |=1;
+    			*AMAZON_GPIO_P1_ALTSEL1 &=~1;
+                                                                                
+    			/*GPIO 17 TDM_DCL */
+    			*AMAZON_GPIO_P1_DIR|=0x02;
+    			*AMAZON_GPIO_P1_ALTSEL0|=0x02;
+    			*AMAZON_GPIO_P1_ALTSEL1 &=(u32)~0x02;
+    			*AMAZON_GPIO_P1_OD|=0x02;
+                                                                                
+    			/*GPIO 18 TDM FSC*/
+    			*AMAZON_GPIO_P1_DIR|=0x04;
+    			*AMAZON_GPIO_P1_ALTSEL0|=0x04;
+    			*AMAZON_GPIO_P1_ALTSEL1 &=(u32)~0x04;
+    			*AMAZON_GPIO_P1_OD|=0x04;	
+			break;
+			
+			
+			
+				//for clearEoC
+#ifdef AMAZON_CLEAR_EOC
+		case AMAZON_MEI_GET_EOC_LEN:
+			while(1){
+				current_clreoc = list_entry(clreoc_list.next, amazon_clreoc_pkt, list);
+				if((current_clreoc->len)>0){
+					copy_to_user((char *)lon, (char*)(&(current_clreoc->len)), 4);
+					break;	
+				}
+				else//wait for eoc data from higher layer
+					interruptible_sleep_on(&wait_queue_clreoc);	
+			}
+			break;
+		case AMAZON_MEI_GET_EOC_DATA:
+			current_clreoc = list_entry(clreoc_list.next, amazon_clreoc_pkt, list);
+			if((current_clreoc->len)>0){
+				copy_to_user((char*)lon, (char*)(current_clreoc->command), current_clreoc->len);
+				meierr=1;
+				list_del(clreoc_list.next);	//remove and add to end of list
+				current_clreoc->len = 0;
+				list_add_tail(&(current_clreoc->list), &clreoc_list);
+			}
+			else
+				meierr=-1;
+			break;
+		case AMAZON_MEI_EOC_SEND:
+			copy_from_user((char *)(&debugrdwr), (char *)lon, sizeof(debugrdwr));
+			eoc_skb = dev_alloc_skb(debugrdwr.iCount*4);
+			if(eoc_skb==NULL){
+				printk("\n\nskb alloc fail");
+				break;
+			}
+			
+			eoc_skb->len=debugrdwr.iCount*4;
+			memcpy(skb_put(eoc_skb, debugrdwr.iCount*4), (char *)debugrdwr.buffer, debugrdwr.iCount*4);
+			
+			ifx_push_eoc(eoc_skb);	//pass data to higher layer
+			break;
+#endif //#ifdef AMAZON_CLEAR_EOC
+		case AMAZON_MIB_LO_ATUC:
+			do_gettimeofday(&time_now);
+			if(lon&0x1){
+				if((time_now.tv_sec-(mib_pflagtime.ATUC_PERF_LOSS_PTIME).tv_sec)>2){
+					current_intvl->AtucPerfLos++;
+					ATUC_PERF_LOSS++;
+					CurrStatus.adslAtucCurrStatus = 2;
+				}
+				(mib_pflagtime.ATUC_PERF_LOSS_PTIME).tv_sec = time_now.tv_sec;
+			}
+			if(lon&0x2){
+				if((time_now.tv_sec-(mib_pflagtime.ATUC_PERF_LOFS_PTIME).tv_sec)>2){
+					current_intvl->AtucPerfLof++;
+					ATUC_PERF_LOFS++;
+					CurrStatus.adslAtucCurrStatus = 1;
+				}
+				(mib_pflagtime.ATUC_PERF_LOFS_PTIME).tv_sec = time_now.tv_sec;
+			}
+			if(!(lon&0x3))
+				CurrStatus.adslAtucCurrStatus = 0;
+			break;
+		case AMAZON_MIB_LO_ATUR:
+			do_gettimeofday(&time_now);
+			if(lon&0x1){
+				if((time_now.tv_sec-(mib_pflagtime.ATUR_PERF_LOSS_PTIME).tv_sec)>2){
+					current_intvl->AturPerfLos++;
+					ATUR_PERF_LOSS++;
+					CurrStatus.adslAturCurrStatus = 2;
+			}
+				(mib_pflagtime.ATUR_PERF_LOSS_PTIME).tv_sec = time_now.tv_sec;
+			}
+			if(lon&0x2){
+				if((time_now.tv_sec-(mib_pflagtime.ATUR_PERF_LOFS_PTIME).tv_sec)>2){
+					current_intvl->AturPerfLof++;
+					ATUR_PERF_LOFS++;
+					CurrStatus.adslAturCurrStatus = 1;
+				}
+				(mib_pflagtime.ATUR_PERF_LOFS_PTIME).tv_sec = time_now.tv_sec;
+			}
+			if(lon&0x4){
+				if((time_now.tv_sec-(mib_pflagtime.ATUR_PERF_LPR_PTIME).tv_sec)>2){
+					current_intvl->AturPerfLpr++;
+					ATUR_PERF_LPR++;
+					CurrStatus.adslAturCurrStatus = 3;
+				}
+				(mib_pflagtime.ATUR_PERF_LPR_PTIME).tv_sec = time_now.tv_sec;
+			}
+			if(!(lon&0x7))
+				CurrStatus.adslAturCurrStatus = 0;
+			break;
+		case AMAZON_MEI_DOWNLOAD:
+			// DMA the boot code page(s)
+#ifdef AMAZON_MEI_DEBUG_ON
+			printk("\n\n start download pages");
+#endif
+			for( boot_loop = 0; boot_loop < img_hdr->count; boot_loop++){
+				if( img_hdr->page[boot_loop].p_size & BOOT_FLAG){
+					page_size = meiGetPage( boot_loop, GET_PROG, MAXSWAPSIZE, mei_arc_swap_buff, &dest_addr);
+					if( page_size > 0){
+						meiDMAWrite(dest_addr, mei_arc_swap_buff, page_size);
+					}
+				}
+				if( img_hdr->page[boot_loop].d_size & BOOT_FLAG){
+					page_size = meiGetPage( boot_loop, GET_DATA, MAXSWAPSIZE, mei_arc_swap_buff, &dest_addr);
+					if( page_size > 0){
+						meiDMAWrite( dest_addr, mei_arc_swap_buff, page_size);
+					}
+				}
+			}
+#ifdef AMAZON_MEI_DEBUG_ON
+			printk("\n\n pages downloaded");
+#endif
+			break;
+		//509221:tc.chen start
+                case AMAZON_MEI_DEBUG_MODE:
+                        mei_debug_mode = lon;
+			break;
+		//509221:tc.chen end
+        }
+        return meierr;
+}
+
+
+//////////////////////          Interrupt handler               /////////////////////////////////////////////////////
+static void mei_interrupt_arcmsgav(int,void *,struct pt_regs *);
+static void mei_interrupt_arcmsgav(int int1, void * void0, struct pt_regs * regs)
+{
+        u32 scratch;
+        u32 fetchpage;
+        u32 size;
+        u32 dest_addr;
+	u32 temp;
+	int i;
+        
+        meiDebugRead(ARC_MEI_MAILBOXR, &scratch, 1);
+        if(scratch & OMB_CODESWAP_MESSAGE_MSG_TYPE_MASK)
+        {
+		if(showtime==1){
+#ifdef AMAZON_MEI_DEBUG_ON
+			printk("\n\n Code Swap Request After ShowTime !!!");
+#endif
+		}
+		else{
+#ifdef AMAZON_MEI_DEBUG_ON
+//			printk("\n\n Code Swap Request");
+#endif
+			fetchpage = scratch & ~OMB_CODESWAP_MESSAGE_MSG_TYPE_MASK;
+			size = meiGetPage( fetchpage, GET_PROG, MAXSWAPSIZE, mei_arc_swap_buff, &dest_addr);
+			if( size > 0)
+			{
+#ifdef AMAZON_MEI_DEBUG_ON
+//				printk("  : prom page num %d",fetchpage);
+#endif
+				meiDMAWrite( dest_addr, mei_arc_swap_buff, size);
+			}
+
+                	size = meiGetPage( fetchpage, GET_DATA, MAXSWAPSIZE, mei_arc_swap_buff, &dest_addr);
+			if( size > 0)
+			{
+#ifdef AMAZON_MEI_DEBUG_ON
+//				printk("  : data page num %d",fetchpage);
+#endif
+				meiDMAWrite( dest_addr, mei_arc_swap_buff, size);
+			}
+		}
+                        //	Notify arc that mailbox read complete
+ 		meiLongwordWrite(ARC_TO_MEI_INT, ARC_TO_MEI_MSGAV);
+
+		//	Tell ARC Codeswap is done
+		meiLongwordWrite(MEI_TO_ARC_INT, MEI_TO_ARC_CS_DONE);
+		asm("SYNC");
+		i=0;
+		while(i<WHILE_DELAY){
+			meiLongwordRead(MEI_TO_ARC_INT, &temp);
+			if((temp & MEI_TO_ARC_CS_DONE) ==0){
+#ifdef AMAZON_MEI_DEBUG_ON
+//				printk("\n\n Code Swap Done");
+#endif
+				break;
+			}
+			i++;
+			if(i==WHILE_DELAY){
+#ifdef AMAZON_MEI_DEBUG_ON
+				printk("\n\n MEI_TO_ARC_CS_DONE not cleared by ARC");
+				//509221:tc.chen start
+				if (!mei_debug_mode)
+				{
+					//printk("Reset Arc!\n");
+					//printk("AdslInitStatsData.FullInitializationCount++\n");
+					AdslInitStatsData.FullInitializationCount++;	
+					if (!showtime)
+					{
+						//printk("AdslInitStatsData.FailedFullInitializationCount++\n");
+						AdslInitStatsData.FailedFullInitializationCount++;
+						//printk("AdslInitStatsData.LINIT_Errors++\n");
+						AdslInitStatsData.LINIT_Errors++;
+					}
+
+					wake_up_interruptible(&wait_queue_codeswap);	// wait up ioctl reboot
+				}
+				//509221:tc.chen end
+#endif
+			}
+		}
+        }
+        else{    // normal message
+//			printk("\n\n interrupt");	
+                        meiMailboxRead(RxMessage, MSG_LENGTH);
+                        if(cmv_waiting==1){            
+                                arcmsgav=1;
+                                cmv_waiting=0;
+                                wake_up_interruptible(&wait_queue_arcmsgav);                  
+                        }
+                        else{
+                                indicator_count++;
+                                memcpy((char *)Recent_indicator, (char *)RxMessage,  MSG_LENGTH *2);
+#ifdef	ARC_READY_ACK
+				if(((RxMessage[0]&0xff0)>>4)==D2H_AUTONOMOUS_MODEM_READY_MSG){	//check ARC ready message
+					
+#ifdef LOCK_RETRY
+					if (reboot_lock)
+					{
+					    reboot_lock = 0;
+					    up(&mei_sema);	// allow cmv access
+					}
+#else
+				        up(&mei_sema);	// allow cmv access
+#endif
+					reboot_flag=1;
+//#ifdef ADSL_LED_SUPPORT					
+#if 0
+					led_support_check=1;//adsl led for 1.1.2.7.1.1
+					adsl_led_flash();//adsl led for 1.1.2.7.1.1
+#endif
+					wake_up_interruptible(&wait_queue_reboot);	// wait up ioctl reboot
+				}
+#endif
+      			}                  
+        }
+//	meiLongwordWrite(ARC_TO_MEI_INT, ARC_TO_MEI_MSGAV);
+	mask_and_ack_amazon_irq(AMAZON_MEI_INT);
+        return;
+}
+
+// 603221:tc.chen start
+////////////////////////hdlc ////////////////
+
+// get hdlc status
+static unsigned int ifx_me_hdlc_status(void)
+{
+	u16 CMVMSG[MSG_LENGTH]; 
+	int ret;
+
+	if (showtime!=1)
+		return -ENETRESET;
+	
+	makeCMV_local(H2D_CMV_READ, STAT, 14, 0, 1, NULL,CMVMSG);	//Get HDLC status 
+	ret = mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, CMVMSG);
+	if (ret != 0)
+	{
+		return -EIO;
+	}
+	return CMVMSG[4]&0x0F;
+}
+
+int ifx_me_is_resloved(int status)
+{
+	u16 CMVMSG[MSG_LENGTH];
+	int ret;
+	
+	if (status == ME_HDLC_MSG_QUEUED || status == ME_HDLC_MSG_SENT)
+		return ME_HDLC_UNRESOLVED;
+	if (status == ME_HDLC_IDLE)
+	{
+		makeCMV_local(H2D_CMV_READ, CNTL, 2, 0, 1, NULL,CMVMSG);	//Get ME-HDLC Control
+		ret = mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, CMVMSG);
+		if (ret != 0)
+		{
+			return IFX_POP_EOC_FAIL;
+		}
+		if (CMVMSG[4]&(1<<0))
+		{
+			return ME_HDLC_UNRESOLVED;
+		}
+		
+	}
+	return ME_HDLC_RESOLVED;
+}
+
+int _ifx_me_hdlc_send(unsigned char *hdlc_pkt,int len,int max_length)
+{
+	int ret;
+	u16 CMVMSG[MSG_LENGTH];
+	u16 data=0;
+	u16 pkt_len=len;
+	if (pkt_len > max_length)
+	{
+		printk("Exceed maximum eoc message length\n");
+		return -ENOBUFS;
+	}
+	//while(pkt_len > 0)
+	{		
+		makeCMV_local(H2D_CMV_WRITE, INFO, 81, 0, (pkt_len+1)/2,(u16 *)hdlc_pkt,CMVMSG);	//Write clear eoc message to ARC
+		ret = mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, CMVMSG);
+		if (ret != 0)
+		{
+			return -EIO;
+		}
+		
+		makeCMV_local(H2D_CMV_WRITE, INFO, 83, 2, 1,&pkt_len,CMVMSG);	//Update tx message length
+		ret = mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, CMVMSG);
+		if (ret != 0)
+		{
+			return -EIO;
+		}
+		
+		data = (1<<0);
+		makeCMV_local(H2D_CMV_WRITE, CNTL, 2, 0, 1,&data,CMVMSG);	//Start to send
+		ret = mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, CMVMSG);
+		if (ret != 0)
+		{
+			return -EIO;
+		}
+		return 0;
+	}
+}
+
+static int ifx_me_hdlc_send(unsigned char *hdlc_pkt,int hdlc_pkt_len)
+{
+	int hdlc_status=0;
+	u16 CMVMSG[MSG_LENGTH];
+	int max_hdlc_tx_length=0,ret=0,retry=0;
+	
+	while(retry<10)
+	{
+		hdlc_status = ifx_me_hdlc_status();
+		if (ifx_me_is_resloved(hdlc_status)==ME_HDLC_RESOLVED) // arc ready to send HDLC message
+		{
+			makeCMV_local(H2D_CMV_READ, INFO, 83, 0, 1, NULL,CMVMSG);	//Get Maximum Allowed HDLC Tx Message Length
+			ret = mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, CMVMSG);
+			if (ret != 0)
+			{
+				return -EIO;
+			}
+			max_hdlc_tx_length = CMVMSG[4];
+			ret = _ifx_me_hdlc_send(hdlc_pkt,hdlc_pkt_len,max_hdlc_tx_length);
+			return ret;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(10);
+	}
+	return -EBUSY;
+}
+
+int ifx_mei_hdlc_read(char *hdlc_pkt,int max_hdlc_pkt_len)
+{
+	u16 CMVMSG[MSG_LENGTH]; 
+	int msg_read_len,ret=0,pkt_len=0,retry = 0;
+		
+	while(retry<10)
+	{
+		ret = ifx_me_hdlc_status();
+		if (ret == ME_HDLC_RESP_RCVD)
+		{
+			int current_size=0;
+			makeCMV_local(H2D_CMV_READ, INFO, 83, 3, 1, NULL,CMVMSG);	//Get EoC packet length
+			ret = mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, CMVMSG);
+			if (ret != 0)
+			{
+				return -EIO;
+			}
+	
+			pkt_len = CMVMSG[4];
+			if (pkt_len > max_hdlc_pkt_len)
+			{
+				ret = -ENOMEM;
+				goto error;
+			}
+			while( current_size < pkt_len)
+			{
+				if (pkt_len - current_size >(MSG_LENGTH*2-8))
+					msg_read_len = (MSG_LENGTH*2-8);
+				else
+					msg_read_len = pkt_len - (current_size);
+				makeCMV_local(H2D_CMV_READ, INFO, 82, 0 + (current_size/2), (msg_read_len+1)/2, NULL,CMVMSG);	//Get hdlc packet
+				ret = mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, CMVMSG);
+				if (ret != 0)
+				{
+					goto error;
+				}
+				memcpy(hdlc_pkt+current_size,&CMVMSG[4],msg_read_len);
+				current_size +=msg_read_len;
+			}
+			ret = current_size;
+			break;
+		}else
+		{
+			ret = -ENODATA;
+		}
+		
+		retry++;
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(10);
+		
+	}
+	return ret;
+error:
+	
+	return ret;
+}
+
+////////////////////////hdlc ////////////////
+// 603221:tc.chen end
+
+/////////////////////// clearEoC, int ifx_pop_eoc(sk_buff * pkt)  //////////
+int ifx_pop_eoc(struct sk_buff * pkt);
+int ifx_pop_eoc(struct sk_buff * pkt)
+{
+	amazon_clreoc_pkt * current;
+	if(showtime!=1){
+		dev_kfree_skb(pkt);
+		return IFX_POP_EOC_FAIL;
+	}
+	if((pkt->len)>clreoc_max_tx_len){
+		dev_kfree_skb(pkt);
+		return IFX_POP_EOC_FAIL;
+	}
+	current = list_entry(clreoc_list.next, amazon_clreoc_pkt, list);
+	while(1){
+		if(current->len==0){
+			memcpy(current->command, pkt->data, pkt->len);
+			current->len=pkt->len;
+			break;
+		}
+		else{
+			if((current->list).next==&clreoc_list){
+				dev_kfree_skb(pkt);
+				return IFX_POP_EOC_FAIL;	//buffer full
+			}
+			current = list_entry((current->list).next,amazon_clreoc_pkt, list);
+		}
+	}	
+	wake_up_interruptible(&wait_queue_clreoc);
+	
+	dev_kfree_skb(pkt);
+	return IFX_POP_EOC_DONE;
+}	
+/*  this is used in circular fifo mode */
+/*
+int ifx_pop_eoc(sk_buff * pkt);
+int ifx_pop_eoc(sk_buff * pkt)
+{
+	int buff_space,i;
+	if(showtime!=1)
+		return IFX_POP_EOC_FAIL;
+	
+	if(clreoc_wr>=clreoc_rd)
+		buff_space = (MEI_CLREOC_BUFF_SIZE-1)-(clreoc_wr - clreoc_rd);
+	else
+		buff_space = clreoc_rd - clreoc_wr - 1;
+	if((pkt->len)>buff_space)
+		return IFX_POP_EOC_FAIL;
+					
+	if((clreoc_wr+pkt->len)>MEI_CLREOC_BUFF_SIZE){
+		memcpy((clreoc+clreoc_wr), pkt->data, ((clreoc_wr+pkt->len)-MEI_CLREOC_BUFF_SIZE+1));
+		memcpy(clreoc, (pkt->data)+((clreoc_wr+pkt->len)-MEI_CLREOC_BUFF_SIZE+1), (pkt->len)-((clreoc_wr+pkt->len)-MEI_CLREOC_BUFF_SIZE+1)); 
+		clreoc_wr=(clreoc_wr+pkt->len)-MEI_CLREOC_BUFF_SIZE;
+	}	
+	else{
+		memcpy((clreoc+clreoc_wr), pkt->data, pkt->len);
+		if((clreoc_wr+pkt->len)=MEI_CLREOC_BUFF_SIZE)
+			clreoc_wr=0;
+		else
+			clreoc_wr+=pkt->len;
+	}
+	wake_up_interruptible(&wait_queue_clreoc);
+	return IFX_POP_EOC_DONE; 			
+}
+*/
+
+
+////////////////////////////////////////////////////////////////////////////
+//int amazon_mei_init_module (void);
+//void amazon_mei_cleanup_module (void);
+//int __init init_module (void);
+//void __exit cleanup_module (void);
+
+int __init amazon_mei_init_module(void)
+//int __init init_module(void)
+{
+        struct proc_dir_entry *entry;
+        int i;
+	
+//dying gasp-start	
+#ifdef IFX_DYING_GASP
+
+//000003:fchang Start
+#ifdef CONFIG_CPU_AMAZON_E
+		//GPIO31 :dying gasp event indication
+		//	(1) logic high: dying gasp event is false (default)
+		//	(2) logic low: dying gasp event is true
+			CLEAR_BIT((*((volatile u32 *)0xB0100B18)), 0x4);
+			CLEAR_BIT((*((volatile u32 *)0xB0100B1c)), 0x4);
+			CLEAR_BIT((*((volatile u32 *)0xB0100B20)), 0x4);
+			SET_BIT((*((volatile u32 *)0xB0100B24)), 0x4);
+			asm("SYNC");			
+#else //000003:fchang End
+
+		//GPIO31 :dying gasp event indication
+		//	(1) logic high: dying gasp event is false (default)
+		//	(2) logic low: dying gasp event is true
+			CLEAR_BIT((*((volatile u32 *)0xB0100B48)), 0x8000);
+			CLEAR_BIT((*((volatile u32 *)0xB0100B4C)), 0x8000);
+			CLEAR_BIT((*((volatile u32 *)0xB0100B50)), 0x8000);
+			SET_BIT((*((volatile u32 *)0xB0100B54)), 0x8000);
+#if 0			
+//warning-led-start	
+//GPIO 22		
+			SET_BIT ((*((volatile u32 *)0xB0100B48)), 0x40);
+			CLEAR_BIT((*((volatile u32 *)0xB0100B4C)), 0x40);
+			CLEAR_BIT((*((volatile u32 *)0xB0100B50)), 0x40);
+			SET_BIT((*((volatile u32 *)0xB0100B54)), 0x40);			
+			CLEAR_BIT((*((volatile u32 *)0xB0100B40)), 0x40); //GPIO ON
+			printk("LED ON ON ON ON ON ON.....");
+//warning-led-end			
+#endif
+			asm("SYNC");	
+#endif //000003:fchang
+
+#endif //IFX_DYING_GASP	
+//dying gasp -end        
+        
+	
+        reg_entry_t regs_temp[PROC_ITEMS] =                                     // Items being debugged
+        {
+        /*	{       flag,          name,          description } */
+	{ &arcmsgav, "arcmsgav", "arc to mei message ", 0 },
+            { &cmv_reply, "cmv_reply", "cmv needs reply", 0},
+            { &cmv_waiting, "cmv_waiting", "waiting for cmv reply from arc", 0},
+            { &indicator_count, "indicator_count", "ARC to MEI indicator count", 0},
+            { &cmv_count, "cmv_count", "MEI to ARC CMVs", 0},
+            { &reply_count, "reply_count", "ARC to MEI Reply", 0},
+            { (int *)Recent_indicator, "Recent_indicator", "most recent indicator", 0},
+	    { (int *)8, "version", "version of firmware", 0},
+        };
+        memcpy((char *)regs, (char *)regs_temp, sizeof(regs_temp));
+
+
+        //sema_init(&mei_sema, 0);  // semaphore initialization, mutex
+        sema_init(&mei_sema, 1);  // semaphore initialization, mutex
+	
+        init_waitqueue_head(&wait_queue_arcmsgav);         	// for ARCMSGAV
+	init_waitqueue_head(&wait_queue_codeswap);		// for codeswap daemon
+	init_waitqueue_head(&wait_queue_mibdaemon);		// for mib daemon
+	init_waitqueue_head(&wait_queue_reboot);		// for ioctl reboot 
+	init_waitqueue_head(&wait_queue_clreoc);		// for clreoc_wr function
+	init_waitqueue_head(&wait_queue_loop_diagnostic);		// for loop diagnostic function
+#ifdef ADSL_LED_SUPPORT	
+	init_waitqueue_head(&wait_queue_led);			// adsl led for led function
+	init_waitqueue_head(&wait_queue_led_polling);		// adsl led for led function
+	led_task.routine = adsl_led_flash_task;			// adsl led for led function
+	led_poll_init();					// adsl led for led function
+#endif	//ADSL_LED_SUPPORT
+#ifdef IFX_DYING_GASP	
+	init_waitqueue_head(&wait_queue_dying_gasp);		// IFX_DYING_GASP
+	lop_poll_init();					// IFX_DYING_GASP 
+#endif	//IFX_DYING_GASP
+ 
+	init_waitqueue_head(&wait_queue_uas_poll);//joelin 04/16/2005
+	unavailable_seconds_poll_init();//joelin 04/16/2005
+	memset(&mib_pflagtime, 0, (sizeof(mib_flags_pretime)));
+	
+	// initialize link list for intervals
+	mei_mib = (amazon_mei_mib *)kmalloc((sizeof(amazon_mei_mib)*INTERVAL_NUM), GFP_KERNEL);
+	if(mei_mib == NULL){
+#ifdef AMAZON_MEI_DEBUG_ON
+		printk("kmalloc error for amazon_mei_mib\n\n");
+#endif
+		return -1;
+	}
+	memset(mei_mib, 0, (sizeof(amazon_mei_mib)*INTERVAL_NUM));
+	INIT_LIST_HEAD(&interval_list);
+	for(i=0;i<INTERVAL_NUM;i++)
+		list_add_tail(&(mei_mib[i].list), &interval_list); 
+	current_intvl = list_entry(interval_list.next, amazon_mei_mib, list);
+	do_gettimeofday(&(current_intvl->start_time)); 
+	// initialize clreoc list
+	clreoc_pkt = (amazon_clreoc_pkt *)kmalloc((sizeof(amazon_clreoc_pkt)*CLREOC_BUFF_SIZE), GFP_KERNEL);
+	if(clreoc_pkt == NULL){
+#ifdef AMAZON_MEI_DEBUG_ON
+		printk("kmalloc error for clreoc_pkt\n\n");
+#endif
+		return -1;
+	}
+	memset(clreoc_pkt, 0, (sizeof(amazon_clreoc_pkt)*CLREOC_BUFF_SIZE));
+	INIT_LIST_HEAD(&clreoc_list);
+	for(i=0;i<CLREOC_BUFF_SIZE;i++)
+		list_add_tail(&(clreoc_pkt[i].list), &clreoc_list);
+		
+        memset(&AdslInitStatsData, 0, sizeof(AdslInitStatsData));
+        if (register_chrdev(major, "amazon_mei", &mei_operations)!=0) {
+#ifdef AMAZON_MEI_DEBUG_ON
+                printk("\n\n unable to register major for amazon_mei!!!");
+#endif
+                return -1;
+        }
+        if (request_irq(AMAZON_MEI_INT, mei_interrupt_arcmsgav,0, "amazon_mei_arcmsgav", NULL)!=0){
+#ifdef AMAZON_MEI_DEBUG_ON
+                printk("\n\n unable to register irq for amazon_mei!!!");
+#endif
+                return -1;
+        }
+//        disable_irq(AMAZON_MEI_INT);
+	enable_irq(AMAZON_MEI_INT);
+        // procfs
+        meidir=proc_mkdir(MEI_DIRNAME, &proc_root);
+        if ( meidir == NULL) {
+#ifdef AMAZON_MEI_DEBUG_ON
+		printk(KERN_ERR ": can't create /proc/" MEI_DIRNAME "\n\n");
+#endif
+		return(-ENOMEM);
+        }
+
+        for(i=0;i<NUM_OF_REG_ENTRY;i++) {
+		entry = create_proc_entry(regs[i].name,
+				S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH,
+				meidir);
+		if(entry) {
+			regs[i].low_ino = entry->low_ino;
+			entry->proc_fops = &proc_operations;
+		} else {
+#ifdef AMAZON_MEI_DEBUG_ON
+			printk( KERN_ERR 
+				": can't create /proc/" MEI_DIRNAME
+				"/%s\n\n", regs[i].name);
+#endif
+			return(-ENOMEM);
+		}
+        }
+        ///////////////////////////////// register net device ////////////////////////////
+        if(register_netdev(&phy_mei_net)!=0){
+#ifdef AMAZON_MEI_DEBUG_ON
+                printk("\n\n Register phy Device Failed.");
+#endif
+                return -1;
+        }
+/*
+	if(register_netdev(&interleave_mei_net)!=0){
+                printk("\n\n Register interleave Device Failed.");
+                return -1;
+        }
+	if(register_netdev(&fast_mei_net)!=0){
+                printk("\n\n Register fast Device Failed.");
+                return -1;
+        }
+*/
+#ifdef DFE_LOOPBACK
+	mei_arc_swap_buff = (u32 *)kmalloc(MAXSWAPSIZE*4, GFP_KERNEL);
+	if (mei_arc_swap_buff){
+#ifdef	ARC_READY_ACK
+		if(down_interruptible(&mei_sema))	//disable CMV access until ARC ready
+		{
+                	return -ERESTARTSYS;
+		}
+#ifdef LOCK_RETRY
+		reboot_lock = 1;
+#endif
+#endif
+		meiForceRebootAdslModem();
+		kfree(mei_arc_swap_buff);
+	}else{
+#ifdef AMAZON_MEI_DEBUG_ON
+		printk("cannot load image: no memory\n\n");
+#endif
+	}
+#endif
+#ifdef IFX_SMALL_FOOTPRINT
+	mib_poll_init();
+#endif
+        return 0;
+}
+
+void __exit amazon_mei_cleanup_module(void)
+//void __exit cleanup_module(void)
+{
+        int i;
+#ifdef ADSL_LED_SUPPORT        
+        stop_led_module=1;			//wake up and clean led module 
+        led_support_check=0;//joelin , clear task
+        showtime=0;//joelin,clear task
+        //CLEAR_BIT((*((volatile u32 *)0xB0100B40)), 0x40); //Warning LED GPIO ON
+        firmware_support_led=0;//joelin ,clear task
+        wake_up_interruptible(&wait_queue_led); //wake up and clean led module 
+        wake_up_interruptible(&wait_queue_led_polling); //wake up and clean led module         
+#endif        
+        for(i=0;i<NUM_OF_REG_ENTRY;i++)
+		remove_proc_entry(regs[i].name, meidir);
+        remove_proc_entry(MEI_DIRNAME, &proc_root);
+	
+        disable_irq(AMAZON_MEI_INT);
+        free_irq(AMAZON_MEI_INT, NULL);
+        unregister_chrdev(major, "amazon_mei");
+
+        kfree(mei_mib);
+	kfree(clreoc_pkt);
+	
+	kfree(phy_mei_net.priv);
+        unregister_netdev(&phy_mei_net);
+	
+        return;
+}
+#ifdef IFX_SMALL_FOOTPRINT
+
+
+int adsl_mib_poll(void *unused)
+{
+	struct task_struct *tsk = current;
+	int i=0;
+	struct timeval time_now;
+	struct timeval time_fini;
+	u32 temp,temp2;
+
+	amazon_mei_mib * mib_ptr;
+//	u16 buff[MSG_LENGTH]__attribute__ ((aligned(4)));
+	u16 * data=NULL;  //used in makeCMV, to pass in payload when CMV set, ignored when CMV read.
+
+	daemonize();
+	strcpy(tsk->comm, "kmibpoll");
+	sigfillset(&tsk->blocked);
+
+	printk("Inside mib poll loop ...\n");
+	i=0;
+	while(1){
+		if(i<MIB_INTERVAL)
+			interruptible_sleep_on_timeout(&wait_queue_mibdaemon, ((MIB_INTERVAL-i)/(1000/HZ)));
+		i=0;
+		if(showtime==1){
+//			printk("\n\n update mib");
+					
+			do_gettimeofday(&time_now);
+			if(time_now.tv_sec - current_intvl->start_time.tv_sec>=900){
+				if(current_intvl->list.next!=&interval_list){
+					current_intvl = list_entry(current_intvl->list.next, amazon_mei_mib, list);
+					do_gettimeofday(&(current_intvl->start_time));
+				}
+				else{
+					mib_ptr = list_entry(interval_list.next, amazon_mei_mib, list);
+					list_del(interval_list.next);
+					memset(mib_ptr, 0, sizeof(amazon_mei_mib));
+					list_add_tail(&(mib_ptr->list), &interval_list);
+					if(current_intvl->list.next==&interval_list)
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nlink list error");
+#endif
+					current_intvl = list_entry(current_intvl->list.next, amazon_mei_mib, list);
+					do_gettimeofday(&(current_intvl->start_time));
+				}	
+			}
+					
+			if(down_interruptible(&mei_sema))
+      				return -ERESTARTSYS;
+/*						
+			ATUC_PERF_LO_FLAG_MAKECMV;
+			if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+				printk("\n\nCMV fail, Group 7 Address 0 Index 0");
+#endif
+			}
+			else{
+				if(RxMessage[4]&PLAM_LOS_FailureBit){
+					current_intvl->AtucPerfLos++;
+					ATUC_PERF_LOSS++;
+					CurrStatus.adslAtucCurrStatus = 2;
+				}
+				if(RxMessage[4]&PLAM_LOF_FailureBit){
+					current_intvl->AtucPerfLof++;
+					ATUC_PERF_LOFS++;
+					CurrStatus.adslAtucCurrStatus = 1;
+				}
+				if(!(RxMessage[4]&(PLAM_LOS_FailureBit|PLAM_LOF_FailureBit)))
+					CurrStatus.adslAtucCurrStatus = 0;
+				}
+*/
+				
+				if(showtime!=1)
+					goto mib_poll_end;
+				ATUC_PERF_ESS_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 7 Address 7 Index 0");
+#endif
+				}
+				else{
+						temp = RxMessage[4]-mib_pread.ATUC_PERF_ESS;
+						if(temp>=0){
+							current_intvl->AtucPerfEs+=temp;
+							ATUC_PERF_ESS+=temp;
+							mib_pread.ATUC_PERF_ESS = RxMessage[4];
+						}
+						else{
+							current_intvl->AtucPerfEs+=0xffff-mib_pread.ATUC_PERF_ESS+RxMessage[4];
+							ATUC_PERF_ESS+=0xffff-mib_pread.ATUC_PERF_ESS+RxMessage[4];
+							mib_pread.ATUC_PERF_ESS = RxMessage[4];		
+					}
+				}
+/*		
+				ATUR_PERF_LO_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 7 Address 1 Index 0");
+#endif
+				}
+				else{
+					if(RxMessage[4]&PLAM_LOS_FailureBit){
+						current_intvl->AturPerfLos++;
+						ATUR_PERF_LOSS++;
+						CurrStatus.adslAturCurrStatus = 2;
+					}
+					if(RxMessage[4]&PLAM_LOF_FailureBit){
+						current_intvl->AturPerfLof++;
+						ATUR_PERF_LOFS++;
+						CurrStatus.adslAturCurrStatus = 1;
+					}
+					if(RxMessage[4]&PLAM_LPR_FailureBit){
+						current_intvl->AturPerfLpr++;
+						ATUR_PERF_LPR++;
+						CurrStatus.adslAturCurrStatus = 3;
+					}
+					if(!(RxMessage[4]&(PLAM_LOS_FailureBit|PLAM_LOF_FailureBit|PLAM_LPR_FailureBit)))
+						CurrStatus.adslAturCurrStatus = 0;	
+				}
+*/
+				if(showtime!=1)
+					goto mib_poll_end;
+				ATUR_PERF_ESS_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 7 Address 33 Index 0");
+#endif
+				}
+				else{
+						temp = RxMessage[4]-mib_pread.ATUR_PERF_ESS;
+						if(temp>=0){
+							current_intvl->AturPerfEs+=temp;
+							ATUR_PERF_ESS+=temp;
+							mib_pread.ATUR_PERF_ESS = RxMessage[4];
+						}
+						else{
+							current_intvl->AturPerfEs+=0xffff-mib_pread.ATUR_PERF_ESS+RxMessage[4];
+							ATUR_PERF_ESS+=	0xffff-mib_pread.ATUR_PERF_ESS+RxMessage[4];
+							mib_pread.ATUR_PERF_ESS=RxMessage[4];
+					}
+				}
+				if(showtime!=1)
+					goto mib_poll_end;
+				// to update rx/tx blocks
+				ATUR_CHAN_RECV_BLK_FLAG_MAKECMV_LSW;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 7 Address 20 Index 0");
+#endif
+				}
+				else{
+						temp = RxMessage[4];	
+				}
+				if(showtime!=1)
+					goto mib_poll_end;
+				ATUR_CHAN_RECV_BLK_FLAG_MAKECMV_MSW;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 7 Address 21 Index 0");
+#endif
+				}
+				else{
+						temp2 = RxMessage[4];	
+					}	
+					if((temp + (temp2<<16) - mib_pread.ATUR_CHAN_RECV_BLK)>=0){
+						current_intvl->AturChanPerfRxBlk+=temp + (temp2<<16) - mib_pread.ATUR_CHAN_RECV_BLK;
+						ATUR_CHAN_RECV_BLK+=temp + (temp2<<16) - mib_pread.ATUR_CHAN_RECV_BLK;
+						mib_pread.ATUR_CHAN_RECV_BLK = temp + (temp2<<16);
+					}
+					else{
+						current_intvl->AturChanPerfRxBlk+=0xffffffff - mib_pread.ATUR_CHAN_RECV_BLK +(temp + (temp2<<16));
+						ATUR_CHAN_RECV_BLK+=0xffffffff - mib_pread.ATUR_CHAN_RECV_BLK +(temp + (temp2<<16));
+						mib_pread.ATUR_CHAN_RECV_BLK = temp + (temp2<<16);
+				}
+				current_intvl->AturChanPerfTxBlk = current_intvl->AturChanPerfRxBlk;
+				ATUR_CHAN_TX_BLK = ATUR_CHAN_RECV_BLK;
+/*					
+				ATUR_CHAN_TX_BLK_FLAG_MAKECMV_LSW;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS)
+					printk("\n\nCMV fail, Group 7 Address 20 Index 0");
+				else{
+					if(RxMessage[4]){
+						current_intvl->AturChanPerfTxBlk+=RxMessage[4];
+						ATUR_CHAN_TX_BLK+=RxMessage[4];
+					}	
+				}
+				ATUR_CHAN_TX_BLK_FLAG_MAKECMV_MSW;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS)
+					printk("\n\nCMV fail, Group 7 Address 21 Index 0");
+				else{
+					if(RxMessage[4]){
+						current_intvl->AturChanPerfTxBlk+=(int)((RxMessage[4])<<16);
+						ATUR_CHAN_TX_BLK+=(int)((RxMessage[4])<<16);
+					}	
+				}
+*/					
+				if(chantype.interleave == 1){
+				if(showtime!=1)
+					goto mib_poll_end;
+					ATUR_CHAN_CORR_BLK_FLAG_MAKECMV_INTL;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 7 Address 3 Index 0");
+#endif
+					}
+					else{
+							temp = RxMessage[4] - mib_pread.ATUR_CHAN_CORR_BLK_INTL;
+							if(temp>=0){
+								current_intvl->AturChanPerfCorrBlk+=temp;
+								ATUR_CHAN_CORR_BLK+=temp;
+								mib_pread.ATUR_CHAN_CORR_BLK_INTL = RxMessage[4];
+							}	
+							else{
+								current_intvl->AturChanPerfCorrBlk+=0xffff - mib_pread.ATUR_CHAN_CORR_BLK_INTL +RxMessage[4];
+								ATUR_CHAN_CORR_BLK+=0xffff - mib_pread.ATUR_CHAN_CORR_BLK_INTL +RxMessage[4];
+								mib_pread.ATUR_CHAN_CORR_BLK_INTL = RxMessage[4];	
+						}	
+					}	
+				}
+				else if(chantype.fast == 1){
+				if(showtime!=1)
+					goto mib_poll_end;
+					ATUR_CHAN_CORR_BLK_FLAG_MAKECMV_FAST;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 7 Address 3 Index 1");
+#endif
+					}
+					else{
+							temp = RxMessage[4] - mib_pread.ATUR_CHAN_CORR_BLK_FAST;
+							if(temp>=0){
+								current_intvl->AturChanPerfCorrBlk+=temp;
+								ATUR_CHAN_CORR_BLK+=temp;
+								mib_pread.ATUR_CHAN_CORR_BLK_FAST = RxMessage[4];
+							}	
+							else{
+								current_intvl->AturChanPerfCorrBlk+=0xffff - mib_pread.ATUR_CHAN_CORR_BLK_FAST + RxMessage[4];
+								ATUR_CHAN_CORR_BLK+=0xffff - mib_pread.ATUR_CHAN_CORR_BLK_FAST + RxMessage[4];
+								mib_pread.ATUR_CHAN_CORR_BLK_FAST = RxMessage[4];
+						}	
+					}		
+				}
+				
+				if(chantype.interleave == 1){
+				if(showtime!=1)
+					goto mib_poll_end;
+					ATUR_CHAN_UNCORR_BLK_FLAG_MAKECMV_INTL;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 7 Address 2 Index 0");
+#endif
+					}
+					else{
+							temp = RxMessage[4] - mib_pread.ATUR_CHAN_UNCORR_BLK_INTL;
+							if(temp>=0){
+								current_intvl->AturChanPerfUncorrBlk+=temp;
+								ATUR_CHAN_UNCORR_BLK+=temp;
+								mib_pread.ATUR_CHAN_UNCORR_BLK_INTL = RxMessage[4];
+							}
+							else{
+								current_intvl->AturChanPerfUncorrBlk+=0xffff - mib_pread.ATUR_CHAN_UNCORR_BLK_INTL + RxMessage[4];
+								ATUR_CHAN_UNCORR_BLK+=0xffff - mib_pread.ATUR_CHAN_UNCORR_BLK_INTL + RxMessage[4];
+								mib_pread.ATUR_CHAN_UNCORR_BLK_INTL = RxMessage[4];
+						}
+					}		
+				}
+				else if(chantype.fast == 1){
+				if(showtime!=1)
+					goto mib_poll_end;
+					ATUR_CHAN_UNCORR_BLK_FLAG_MAKECMV_FAST;
+					if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+						printk("\n\nCMV fail, Group 7 Address 2 Index 1");
+#endif
+					}
+					else{
+							temp = RxMessage[4] - mib_pread.ATUR_CHAN_UNCORR_BLK_FAST;
+							if(temp>=0){
+								current_intvl->AturChanPerfUncorrBlk+=temp;
+								ATUR_CHAN_UNCORR_BLK+=temp;
+								mib_pread.ATUR_CHAN_UNCORR_BLK_FAST = RxMessage[4];
+							}
+							else{
+								current_intvl->AturChanPerfUncorrBlk+=0xffff - mib_pread.ATUR_CHAN_UNCORR_BLK_FAST + RxMessage[4];
+								ATUR_CHAN_UNCORR_BLK+=0xffff - mib_pread.ATUR_CHAN_UNCORR_BLK_FAST + RxMessage[4];
+								mib_pread.ATUR_CHAN_UNCORR_BLK_FAST = RxMessage[4];
+						}
+					}		
+				}
+					
+				//RFC-3440
+
+#ifdef AMAZON_MEI_MIB_RFC3440
+				if(showtime!=1)
+					goto mib_poll_end;
+				ATUC_PERF_STAT_FASTR_FLAG_MAKECMV; //???
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 0 Address 0 Index 0");
+#endif
+				}
+				else{
+						temp = RxMessage[4] - mib_pread.ATUC_PERF_STAT_FASTR;
+						if(temp>=0){
+							current_intvl->AtucPerfStatFastR+=temp;
+							ATUC_PERF_STAT_FASTR+=temp;
+							mib_pread.ATUC_PERF_STAT_FASTR = RxMessage[4];
+						}
+						else{
+							current_intvl->AtucPerfStatFastR+=0xffff - mib_pread.ATUC_PERF_STAT_FASTR + RxMessage[4];
+							ATUC_PERF_STAT_FASTR+=0xffff - mib_pread.ATUC_PERF_STAT_FASTR + RxMessage[4];
+							mib_pread.ATUC_PERF_STAT_FASTR = RxMessage[4];
+					}
+				}
+				if(showtime!=1)
+					goto mib_poll_end;
+				ATUC_PERF_STAT_FAILED_FASTR_FLAG_MAKECMV; //???
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 0 Address 0 Index 0");
+#endif
+				}
+				else{
+						temp = RxMessage[4] - mib_pread.ATUC_PERF_STAT_FAILED_FASTR;
+						if(temp>=0){
+							current_intvl->AtucPerfStatFailedFastR+=temp;
+							ATUC_PERF_STAT_FAILED_FASTR+=temp;
+							mib_pread.ATUC_PERF_STAT_FAILED_FASTR = RxMessage[4];
+						}
+						else{
+							current_intvl->AtucPerfStatFailedFastR+=0xffff - mib_pread.ATUC_PERF_STAT_FAILED_FASTR + RxMessage[4];
+							ATUC_PERF_STAT_FAILED_FASTR+=0xffff - mib_pread.ATUC_PERF_STAT_FAILED_FASTR + RxMessage[4];
+							mib_pread.ATUC_PERF_STAT_FAILED_FASTR = RxMessage[4];
+					}
+				}
+				if(showtime!=1)
+					goto mib_poll_end;
+				ATUC_PERF_STAT_SESL_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 7 Address 8 Index 0");
+#endif
+				}
+				else{
+						temp = RxMessage[4] - mib_pread.ATUC_PERF_STAT_SESL;
+						if(temp>=0){
+							current_intvl->AtucPerfStatSesL+=temp;
+							ATUC_PERF_STAT_SESL+=temp;
+							mib_pread.ATUC_PERF_STAT_SESL = RxMessage[4];
+						}
+						else{
+							current_intvl->AtucPerfStatSesL+=0xffff - mib_pread.ATUC_PERF_STAT_SESL + RxMessage[4];
+							ATUC_PERF_STAT_SESL+=0xffff - mib_pread.ATUC_PERF_STAT_SESL + RxMessage[4];
+							mib_pread.ATUC_PERF_STAT_SESL = RxMessage[4];
+					}
+				}
+				if(showtime!=1)
+					goto mib_poll_end;
+				ATUC_PERF_STAT_UASL_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 7 Address 10 Index 0");
+#endif
+				}
+				else{
+						temp = RxMessage[4] - mib_pread.ATUC_PERF_STAT_UASL;
+						if(temp>=0){
+							current_intvl->AtucPerfStatUasL+=temp;
+							ATUC_PERF_STAT_UASL+=temp;
+							mib_pread.ATUC_PERF_STAT_UASL = RxMessage[4];
+						}
+						else{
+							current_intvl->AtucPerfStatUasL+=0xffff - mib_pread.ATUC_PERF_STAT_UASL + RxMessage[4];
+							ATUC_PERF_STAT_UASL+=0xffff - mib_pread.ATUC_PERF_STAT_UASL + RxMessage[4];
+							mib_pread.ATUC_PERF_STAT_UASL = RxMessage[4];
+					}
+				}
+				if(showtime!=1)
+					goto mib_poll_end;
+				ATUR_PERF_STAT_SESL_FLAG_MAKECMV;
+				if(meiCMV(TxMessage, YES_REPLY)!=MEI_SUCCESS){
+#ifdef AMAZON_MEI_DEBUG_ON
+					printk("\n\nCMV fail, Group 7 Address 34 Index 0");
+#endif
+				}
+				else{
+						temp = RxMessage[4] - mib_pread.ATUR_PERF_STAT_SESL;
+						if(temp>=0){
+							current_intvl->AtucPerfStatUasL+=temp;
+							ATUC_PERF_STAT_UASL+=temp;
+							mib_pread.ATUR_PERF_STAT_SESL = RxMessage[4];
+						}
+						else{
+							current_intvl->AtucPerfStatUasL+=0xffff - mib_pread.ATUR_PERF_STAT_SESL + RxMessage[4];
+							ATUC_PERF_STAT_UASL+=0xffff - mib_pread.ATUR_PERF_STAT_SESL + RxMessage[4];
+							mib_pread.ATUR_PERF_STAT_SESL = RxMessage[4];
+					}
+				}
+					
+#endif
+mib_poll_end:
+				up(&mei_sema);
+				
+				do_gettimeofday(&time_fini);
+				i = ((int)((time_fini.tv_sec-time_now.tv_sec)*1000)) + ((int)((time_fini.tv_usec-time_now.tv_usec)/1000))  ; //msec 
+			}//showtime==1
+		}	 
+	
+}
+int mib_poll_init(void)
+{
+	printk("Starting mib_poll...\n");
+
+	kernel_thread(adsl_mib_poll, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
+	return 0;
+}
+#endif //IFX_SMALL_FOOTPRINT
+//EXPORT_NO_SYMBOLS;
+
+#ifdef ADSL_LED_SUPPORT
+// adsl led -start
+int led_status_on=0,led_need_to_flash=0;
+int led_current_flashing=0;
+unsigned long led_delay=0;
+static int led_poll(void *unused)
+{
+	stop_led_module=0;	//begin polling ...
+	while(!stop_led_module){
+		if ((!led_status_on)&&(!led_need_to_flash)) interruptible_sleep_on_timeout (&wait_queue_led_polling,1000); //10 seconds timeout for waiting wakeup
+//			else printk("direct running task, no waiting");
+		run_task_queue(&tq_ifx_led);//joelin task
+//	printk("led and LOP polling...\n");
+		}
+	return 0;	
+}	
+static int led_poll_init(void)
+{
+//	printk("Starting adsl led polling...\n");
+
+//warning-led-start
+//	CLEAR_BIT((*((volatile u32 *)0xB0100B40)), 0x40); //Warning LED GPIO ON
+//warning-led-end
+
+	kernel_thread(led_poll, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
+	return 0;
+}
+
+int adsl_led_flash(void)
+{	
+	int i;
+	if (!firmware_support_led)	return 0;	//joelin version check 
+
+	if (led_status_on == 0 && led_need_to_flash == 0)
+	{
+		queue_task(&led_task, &tq_ifx_led);//joelin task
+		wake_up_interruptible(&wait_queue_led_polling); //wake up and clean led module 
+//		printk("queue Task 1...\n");	//joelin  test	
+	}
+	led_need_to_flash=1;//asking to flash led
+
+	return 0;
+}
+
+int adsl_led_flash_task(void *ptr)
+{
+
+	u16	one=1;
+	u16	zero=0;
+	u16	data=0x0600;
+	int kernel_use=1;
+	u16 CMVMSG[MSG_LENGTH];                                                                           
+//adsl-led-start for >v1.1.2.7.1.1
+//	printk("Task Running...\n");	//joelin  test
+	if ((firmware_support_led==2)&&(led_support_check))
+	{
+	led_support_check=0;
+	data=0x0600;
+	makeCMV_local(H2D_CMV_WRITE, INFO, 91, 0, 1, &data,CMVMSG);	//configure GPIO9 GPIO10 as outputs
+	mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, CMVMSG);
+
+	makeCMV_local(H2D_CMV_WRITE, INFO, 91, 2, 1, &data,CMVMSG);	//enable writing to bit 9 and bit10
+	mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, CMVMSG);
+	
+	data=0x0a01;
+	makeCMV_local(H2D_CMV_WRITE, INFO, 91, 4, 1, &data,CMVMSG);	//use GPIO10 for TR68 .Enable and don't invert.
+	mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, CMVMSG);	
+	
+#ifdef DATA_LED_ON_MODE	
+	data=0x0903;//tecom //use GPIO9 for TR68 data led .turn on.
+#else
+	data=0x0900;
+#endif	
+	makeCMV_local(H2D_CMV_WRITE, INFO, 91, 5, 1, &data,CMVMSG);	//use GPIO9 for TR68 data led .turn off.
+	mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, CMVMSG);		
+	
+	}
+	if (!showtime) {led_need_to_flash=0; return 0;} 
+//adsl-led-end for >v1.1.2.7.1.1
+
+	if (led_status_on == 0 || led_need_to_flash == 1)
+	{
+
+		if (led_current_flashing==0)
+		{
+			if (firmware_support_led==1){//>1.1.2.3.1.1
+			makeCMV_local(H2D_CMV_WRITE, INFO, 91, 0, 1, &one,CMVMSG);	//flash
+			mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, &CMVMSG);	
+		}
+			else if (firmware_support_led==2){//>1.1.2.7.1.1
+				data=0x0901;//flash
+				makeCMV_local(H2D_CMV_WRITE, INFO, 91, 5, 1, &data,CMVMSG);	//use GPIO9 for TR68 data led .flash.
+				mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, &CMVMSG);			
+				
+			}//(firmware_support_led==2)
+			led_current_flashing = 1;//turn on led
+		}
+		led_status_on=1;
+
+		do{//do nothing , waiting untill no data traffic 
+			led_need_to_flash=0;
+			interruptible_sleep_on_timeout(&wait_queue_led, 25); //the time for LED Off , if no data traffic			 
+		}while(led_need_to_flash==1);
+		
+	}else if (led_status_on == 1 && led_need_to_flash==0)
+	{
+		if (led_current_flashing==1)
+		{//turn off led
+			if (firmware_support_led==1){//>1.1.2.3.1.1
+			makeCMV_local(H2D_CMV_WRITE, INFO, 91, 0, 1, &zero,CMVMSG);//off	
+			mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, &CMVMSG);
+			}	//>1.1.2.3.1.1		
+			else if (firmware_support_led==2){//>1.1.2.7.1.1
+#ifdef DATA_LED_ON_MODE					
+				data=0x0903;//tecom //use GPIO9 for TR68 data led .turn on.
+#else
+				data=0x0900;//off
+#endif				
+				makeCMV_local(H2D_CMV_WRITE, INFO, 91, 5, 1, &data,CMVMSG);	//use GPIO9 for TR68 data led .off.
+			mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_CMV_WINHOST, &CMVMSG);
+				
+			}//(firmware_support_led==2)
+			led_status_on=0;
+			led_current_flashing = 0;
+		}
+		}
+	
+	if (led_status_on == 1 || led_need_to_flash)
+	{//led flash job on going or led need to flash 
+		queue_task(&led_task, &tq_ifx_led);	//joelin task	
+//		printk("queue Task 2...\n");	//joelin  test	
+	}
+	return 0;
+}
+//joelin adsl led-end
+#else 
+int adsl_led_flash(void)
+{
+	return 0;
+}
+#endif //ADSL_LED_SUPPORT
+#ifdef IFX_DYING_GASP
+static int lop_poll(void *unused)
+{
+	
+	while(1)
+	{
+	interruptible_sleep_on_timeout(&wait_queue_dying_gasp, 1); 
+#ifdef CONFIG_CPU_AMAZON_E //000003:fchang
+        if(showtime&&((*((volatile u32 *)0xB0100B14))&0x4)==0x0)	{//000003:fchang
+#else //000003:fchang
+	if(showtime&&((*((volatile u32 *)0xB0100B44))&0x8000)==0x0)	{
+#endif //CONFIG_CPU_AMAZON_E
+		mei_ioctl((struct inode *)0,NULL, AMAZON_MEI_WRITEDEBUG, &lop_debugwr);
+		printk("send dying gasp..\n");}
+		
+	}
+	return 0;	
+	}
+static int lop_poll_init(void)
+{
+//	printk("Starting LOP polling...\n");
+	kernel_thread(lop_poll, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
+	return 0;
+}
+
+#endif //IFX_DYING_GASP
+
+//joelin 04/16/2005-satrt
+static int unavailable_seconds_poll(void *unused)
+{
+	while(1){
+		interruptible_sleep_on_timeout (&wait_queue_uas_poll,100); //1 second timeout for waiting wakeup
+   		if (!showtime) unavailable_seconds++;
+	}
+	return 0;	
+}	
+static int unavailable_seconds_poll_init(void)
+{
+  
+	kernel_thread(unavailable_seconds_poll, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
+	return 0;
+}
+
+
+//joelin 04/16/2005-end
+EXPORT_SYMBOL(meiDebugWrite);
+EXPORT_SYMBOL(ifx_pop_eoc);
+
+MODULE_LICENSE("GPL");
+
+module_init(amazon_mei_init_module);
+module_exit(amazon_mei_cleanup_module);
+
+

--- /dev/null
+++ b/target/linux/amazon-2.6/files/drivers/char/amazon_wdt.c
@@ -1,1 +1,262 @@
-
+/*
+ * Infineon AP DC COM  Amazon WDT driver
+ * Copyright 2004 Wu Qi Ming <gokimi@msn.com>
+ * All rights reserved
+ */
+#if defined(MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/tty.h>
+#include <linux/selection.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/kdev_t.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/amazon_wdt.h>
+
+#define AMAZON_WDT_EMSG(fmt, args...) printk( "%s: " fmt, __FUNCTION__ , ##args)
+
+extern unsigned int amazon_get_fpi_hz(void);
+
+/* forward declarations for _fops */
+static ssize_t wdt_read(struct file *file, char *buf, size_t count, loff_t *offset);
+static ssize_t wdt_write(struct file *file, const char *buf, size_t count, loff_t *offset);
+static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int wdt_open(struct inode *inode, struct file *file);
+static int wdt_release(struct inode *inode, struct file *file);
+static int wdt_proc_read(char *buf, char **start, off_t offset,int count, int *eof, void *data);
+
+
+static struct file_operations wdt_fops = {
+	read:wdt_read,
+	write:wdt_write,
+	ioctl:wdt_ioctl,
+	open:wdt_open,
+	release:wdt_release,	
+};
+
+/* data */
+static struct wdt_dev *amazon_wdt_dev;
+static struct proc_dir_entry* amazon_wdt_dir;
+static int occupied=0;
+
+
+/* Brief: enable WDT
+ * Parameter:
+ 	timeout: time interval for WDT
+ * Return:
+ 	0	OK
+		EINVAL
+ * Describes:
+ 	1. Password Access
+	2. Modify Access (change ENDINIT => 0)
+	3. Change WDT_CON1 (enable WDT)
+	4. Password Access again
+	5. Modify Access (change ENDINIT => 1)
+ */
+int wdt_enable(int timeout)
+{
+  	u32 hard_psw,ffpi;
+  	int reload_value, divider=0;
+  
+	ffpi = amazon_get_fpi_hz();
+	
+  	divider = 1;
+  	if((reload_value=65536-timeout*ffpi/256)<0){
+        	divider = 0;
+        	reload_value=65536-timeout*ffpi/16384;
+  	}
+	if (reload_value < 0){
+		AMAZON_WDT_EMSG("timeout too large %d\n", timeout);
+		return -EINVAL;
+	}
+	
+	AMAZON_WDT_EMSG("timeout:%d reload_value: %8x\n", timeout, reload_value);
+  	
+	hard_psw=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff01)+(AMAZON_WDT_REG32(AMAZON_WDT_CON1)&0xc)+ 0xf0;  
+  	AMAZON_WDT_REG32(AMAZON_WDT_CON0)=hard_psw;
+  	wmb();
+	
+  	AMAZON_WDT_REG32(AMAZON_WDT_CON0)=(hard_psw&0xff00)+(reload_value<<16)+0xf2;
+  	wmb();
+
+  	AMAZON_WDT_REG32(AMAZON_WDT_CON1)=divider<<2;  
+	wmb();
+	
+  	hard_psw=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff01)+(AMAZON_WDT_REG32(AMAZON_WDT_CON1)&0xc)+ 0xf0;
+  	AMAZON_WDT_REG32(AMAZON_WDT_CON0)=hard_psw;
+  	
+	wmb();
+  	AMAZON_WDT_REG32(AMAZON_WDT_CON0)=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff00)+0xf3;
+	wmb();
+	return 0;
+}
+
+/*	Brief:	Disable/stop WDT
+ */
+void wdt_disable(void)
+{
+     	u32 hard_psw=0;
+	
+     	hard_psw=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff01)+(AMAZON_WDT_REG32(AMAZON_WDT_CON1)&0xc)+ 0xf0;  
+     	AMAZON_WDT_REG32(AMAZON_WDT_CON0)=hard_psw;
+     	wmb();
+
+     	AMAZON_WDT_REG32(AMAZON_WDT_CON0)=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff00)+0xf2;
+	wmb();
+	
+     	AMAZON_WDT_REG32(AMAZON_WDT_CON1)|=8;  
+	wmb();
+	
+     	hard_psw=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff01)+(AMAZON_WDT_REG32(AMAZON_WDT_CON1)&0xc)+ 0xf0;  
+     	AMAZON_WDT_REG32(AMAZON_WDT_CON0)=hard_psw;
+     	wmb();
+
+     	AMAZON_WDT_REG32(AMAZON_WDT_CON0)=(AMAZON_WDT_REG32(AMAZON_WDT_CON0)&0xffffff00)+0xf3;
+	wmb();
+	
+   	return;
+}
+
+static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+        int result=0;
+	static int timeout=-1;
+        
+        switch(cmd){
+         case AMAZON_WDT_IOC_START:
+          	AMAZON_WDT_DMSG("enable watch dog timer!\n");
+		if ( copy_from_user((void*)&timeout, (void*)arg, sizeof (int)) ){
+			AMAZON_WDT_EMSG("invalid argument\n");
+			result=-EINVAL;
+		}else{
+			if ((result = wdt_enable(timeout)) < 0){
+				timeout = -1;
+			}
+		}
+          	break;
+        case AMAZON_WDT_IOC_STOP:
+          	AMAZON_WDT_DMSG("disable watch dog timer\n");
+		timeout = -1;
+          	wdt_disable();
+		
+         	break;
+	case AMAZON_WDT_IOC_PING:
+		if (timeout <0 ){
+			result = -EIO;
+		}else{
+			result = wdt_enable(timeout); 
+		}		
+	}
+  	return result;
+}
+
+static ssize_t wdt_read(struct file *file, char *buf, size_t count, loff_t *offset)
+{
+	return 0;
+}
+
+static ssize_t wdt_write(struct file *file, const char *buf, size_t count, loff_t *offset)
+{	
+	return count;
+}
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+        AMAZON_WDT_DMSG("wdt_open\n");
+	
+	if (occupied == 1) return -EBUSY;
+	occupied = 1;
+	
+	return 0;
+}
+
+static int wdt_release(struct inode *inode, struct file *file)
+{
+        AMAZON_WDT_DMSG("wdt_release\n"); 
+	
+	occupied = 0;
+	return 0;
+}
+
+
+int wdt_register_proc_read(char *buf, char **start, off_t offset,
+                         int count, int *eof, void *data)
+{
+   	int len=0;
+   	printk("wdt_registers:\n");
+   	len+=sprintf(buf+len,"NMISR:    0x%08x\n",AMAZON_WDT_REG32(AMAZON_WDT_NMISR));
+   	len+=sprintf(buf+len,"RST_REQ:  0x%08x\n",AMAZON_WDT_REG32(AMAZON_RST_REQ));
+   	len+=sprintf(buf+len,"RST_SR:   0x%08x\n",AMAZON_WDT_REG32(AMAZON_RST_SR));
+   	len+=sprintf(buf+len,"WDT_CON0: 0x%08x\n",AMAZON_WDT_REG32(AMAZON_WDT_CON0));
+   	len+=sprintf(buf+len,"WDT_CON1: 0x%08x\n",AMAZON_WDT_REG32(AMAZON_WDT_CON1));
+   	len+=sprintf(buf+len,"WDT_SR:   0x%08x\n",AMAZON_WDT_REG32(AMAZON_WDT_SR));
+   	*eof = 1;
+   	return len;
+}
+
+
+int __init amazon_wdt_init_module(void)
+{
+	int result=0;
+
+   	amazon_wdt_dev = (wdt_dev*)kmalloc(sizeof(wdt_dev),GFP_KERNEL);
+   	if (amazon_wdt_dev == NULL){
+   		return -ENOMEM;
+   	}
+	memset(amazon_wdt_dev,0,sizeof(wdt_dev));
+	
+      	amazon_wdt_dev->major=result;
+	strcpy(amazon_wdt_dev->name,"wdt");
+	
+	result = register_chrdev(0,amazon_wdt_dev->name,&wdt_fops);
+   	if (result < 0) {
+        	AMAZON_WDT_EMSG("cannot register device\n");
+		kfree(amazon_wdt_dev);
+       	 	return result;
+   	}
+
+   	amazon_wdt_dir=proc_mkdir("amazon_wdt",NULL);
+   	create_proc_read_entry("wdt_register",
+                          	0,
+                          	amazon_wdt_dir,
+                          	wdt_register_proc_read,
+                          	NULL);  
+   
+	occupied=0;
+   	return 0;
+}
+
+void amazon_wdt_cleanup_module(void)
+{
+	unregister_chrdev(amazon_wdt_dev->major,amazon_wdt_dev->name);
+        kfree(amazon_wdt_dev);	
+    	remove_proc_entry("wdt_register",amazon_wdt_dir);
+	remove_proc_entry("amazon_wdt",NULL);
+        AMAZON_WDT_DMSG("unloaded\n");
+	return;
+}
+
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Infineon IFAP DC COM");
+MODULE_DESCRIPTION("AMAZON WDT driver");
+
+module_init(amazon_wdt_init_module);
+module_exit(amazon_wdt_cleanup_module);
+
+

--- /dev/null
+++ b/target/linux/amazon-2.6/files/drivers/char/ifx_ssc.c
@@ -1,1 +1,2122 @@
-
+/**************************************************
+ *
+ * drivers/ifx/serial/ifx_ssc.c
+ *
+ * Driver for IFX_SSC serial ports
+ *
+ * Copyright (C) 2004 Infineon Technologies AG
+ * Author Michael Schoenenborn (IFX COM TI BT)
+ *
+ */
+#define IFX_SSC_DRV_VERSION "0.2.1"
+/*
+ **************************************************
+ *
+ * This driver was originally based on the INCA-IP driver, but due to 
+ * fundamental conceptual drawbacks there has been changed a lot.
+ *
+ * Based on INCA-IP driver Copyright (c) 2003 Gary Jennejohn <gj@denx.de>
+ * Based on the VxWorks drivers Copyright (c) 2002, Infineon Technologies.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ */
+
+// ### TO DO: general issues:
+//	      - power management
+//	      - interrupt handling (direct/indirect)
+//	      - pin/mux-handling (just overall concept due to project dependency)
+//	      - multiple instances capability
+//	      - slave functionality
+
+/*
+ * Include section 
+ */
+#ifndef EXPORT_SYMTAB
+#define EXPORT_SYMTAB
+#endif
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+//#include <linux/poll.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/irq.h>
+#include <asm/amazon/ifx_ssc_defines.h>
+#include <asm/amazon/ifx_ssc.h>
+
+#ifdef SSC_FRAME_INT_ENABLE
+#undef SSC_FRAME_INT_ENABLE
+#endif
+
+#define not_yet
+
+#define SPI_VINETIC
+
+/*
+ * Deal with CONFIG_MODVERSIONS
+ */
+#if CONFIG_MODVERSIONS==1
+# include <linux/modversions.h>
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Schoenenborn");
+MODULE_DESCRIPTION("IFX SSC driver");
+MODULE_SUPPORTED_DEVICE("ifx_ssc");
+MODULE_PARM(maj, "i");
+MODULE_PARM_DESC(maj, "Major device number");
+
+/* allow the user to set the major device number */
+static int maj = 0;
+
+
+/*
+ * This is the per-channel data structure containing pointers, flags
+ * and variables for the port. This driver supports a maximum of PORT_CNT.
+ * isp is allocated in ifx_ssc_init() based on the chip version.
+ */
+static struct ifx_ssc_port *isp;
+
+/* prototypes for fops */
+static ssize_t ifx_ssc_read(struct file *, char *, size_t, loff_t *);
+static ssize_t ifx_ssc_write(struct file *, const char *, size_t, loff_t *);
+//static unsigned int ifx_ssc_poll(struct file *, struct poll_table_struct *);
+int ifx_ssc_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+int ifx_ssc_open(struct inode *, struct file *);
+int ifx_ssc_close(struct inode *, struct file *);
+
+/* other forward declarations */
+static unsigned int ifx_ssc_get_kernel_clk(struct ifx_ssc_port *info);
+static void ifx_ssc_rx_int(int, void *, struct pt_regs *);
+static void ifx_ssc_tx_int(int, void *, struct pt_regs *);
+static void ifx_ssc_err_int(int, void *, struct pt_regs *);
+#ifdef SSC_FRAME_INT_ENABLE
+static void ifx_ssc_frm_int(int, void *, struct pt_regs *);
+#endif
+static void tx_int(struct ifx_ssc_port *);
+static int ifx_ssc1_read_proc(char *, char **, off_t, int, int *, void *);
+static void ifx_gpio_init(void);
+/************************************************************************
+ *  Function declaration
+ ************************************************************************/
+//interrupt.c
+extern unsigned int amazon_get_fpi_hz(void);
+extern void disable_amazon_irq(unsigned int irq_nr);
+extern void enable_amazon_irq(unsigned int irq_nr);
+extern void mask_and_ack_amazon_irq(unsigned int irq_nr);
+
+
+/*****************************************************************/
+typedef struct {
+	int (*request)(unsigned int irq, 
+		       void (*handler)(int, void *, struct pt_regs *), 
+		       unsigned long irqflags,
+		       const char * devname, 
+		       void *dev_id);
+	void (*free)(unsigned int irq, void *dev_id);
+	void (*enable)(unsigned int irq);
+	void (*disable)(unsigned int irq);
+        void (*clear)(unsigned int irq);
+} ifx_int_wrapper_t;
+
+static ifx_int_wrapper_t ifx_int_wrapper = {
+	request:	request_irq,	// IM action: enable int
+	free:		free_irq,	// IM action: disable int
+	enable:		enable_amazon_irq,
+	disable:	disable_amazon_irq,
+        clear:          mask_and_ack_amazon_irq,
+	//end:		
+};
+
+/* Fops-struct */
+static struct file_operations ifx_ssc_fops = {
+        owner:		THIS_MODULE,
+	read:		ifx_ssc_read,    /* read */
+	write:		ifx_ssc_write,   /* write */
+//        poll:		ifx_ssc_poll,    /* poll */
+        ioctl:		ifx_ssc_ioctl,   /* ioctl */
+        open:		ifx_ssc_open,    /* open */
+        release:	ifx_ssc_close,   /* release */
+};
+
+
+static inline unsigned int ifx_ssc_get_kernel_clk(struct ifx_ssc_port *info)
+{ // ATTENTION: This function assumes that the CLC register is set with the 
+  // appropriate value for RMC.
+	unsigned int rmc;
+
+	rmc = (READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_CLC) & 
+	       IFX_CLC_RUN_DIVIDER_MASK) >> IFX_CLC_RUN_DIVIDER_OFFSET;
+	if (rmc == 0){
+		printk("ifx_ssc_get_kernel_clk rmc==0 \n");
+		return (0);
+	}
+	return (amazon_get_fpi_hz() / rmc);
+}
+
+#ifndef not_yet
+#ifdef IFX_SSC_INT_USE_BH
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver
+ * (also known as the "bottom half").  This can be called any
+ * number of times for any channel without harm.
+ */
+static inline void
+ifx_ssc_sched_event(struct ifx_ssc_port *info, int event)
+{
+    info->event |= 1 << event; /* remember what kind of event and who */
+    queue_task(&info->tqueue, &tq_cyclades); /* it belongs to */
+    mark_bh(CYCLADES_BH);                       /* then trigger event */
+} /* ifx_ssc_sched_event */
+
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using ifx_ssc_sched_event(), and they get done here.
+ *
+ * This is done through one level of indirection--the task queue.
+ * When a hardware interrupt service routine wants service by the
+ * driver's bottom half, it enqueues the appropriate tq_struct (one
+ * per port) to the tq_cyclades work queue and sets a request flag
+ * via mark_bh for processing that queue.  When the time is right,
+ * do_ifx_ssc_bh is called (because of the mark_bh) and it requests
+ * that the work queue be processed.
+ *
+ * Although this may seem unwieldy, it gives the system a way to
+ * pass an argument (in this case the pointer to the ifx_ssc_port
+ * structure) to the bottom half of the driver.  Previous kernels
+ * had to poll every port to see if that port needed servicing.
+ */
+static void
+do_ifx_ssc_bh(void)
+{
+    run_task_queue(&tq_cyclades);
+} /* do_ifx_ssc_bh */
+
+static void
+do_softint(void *private_)
+{
+  struct ifx_ssc_port *info = (struct ifx_ssc_port *) private_;
+
+    if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
+        wake_up_interruptible(&info->open_wait);
+        info->flags &= ~(ASYNC_NORMAL_ACTIVE|
+                             ASYNC_CALLOUT_ACTIVE);
+    }
+    if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
+        wake_up_interruptible(&info->open_wait);
+    }
+    if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event)) {
+	wake_up_interruptible(&info->delta_msr_wait);
+    }
+    if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
+        wake_up_interruptible(&tty->write_wait);
+    }
+#ifdef Z_WAKE
+    if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) {
+        wake_up_interruptible(&info->shutdown_wait);
+    }
+#endif
+} /* do_softint */
+#endif /* IFX_SSC_INT_USE_BH */
+#endif // not_yet
+
+inline static void
+rx_int(struct ifx_ssc_port *info)
+{
+	int		fifo_fill_lev, bytes_in_buf, i;
+	unsigned long	tmp_val;
+	unsigned long	*tmp_ptr;
+	unsigned int	rx_valid_cnt;
+	/* number of words waiting in the RX FIFO */
+	fifo_fill_lev = (READ_PERIPHERAL_REGISTER(info->mapbase + 
+                                                  IFX_SSC_FSTAT) & 
+                         IFX_SSC_FSTAT_RECEIVED_WORDS_MASK) >>
+                         IFX_SSC_FSTAT_RECEIVED_WORDS_OFFSET;
+        // Note: There are always 32 bits in a fifo-entry except for the last 
+        // word of a contigous transfer block and except for not in rx-only 
+        // mode and CON.ENBV set. But for this case it should be a convention 
+        // in software which helps:
+        // In tx or rx/tx mode all transfers from the buffer to the FIFO are 
+        // 32-bit wide, except for the last three bytes, which could be a 
+        // combination of 16- and 8-bit access.
+        // => The whole block is received as 32-bit words as a contigous stream, 
+        // even if there was a gap in tx which has the fifo run out of data! 
+        // Just the last fifo entry *may* be partially filled (0, 1, 2 or 3 bytes)!
+
+	/* free space in the RX buffer */
+	bytes_in_buf = info->rxbuf_end - info->rxbuf_ptr;
+        // transfer with 32 bits per entry
+	while ((bytes_in_buf >= 4) && (fifo_fill_lev > 0)) {
+		tmp_ptr = (unsigned long *)info->rxbuf_ptr;
+                *tmp_ptr = READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_RB);
+                info->rxbuf_ptr += 4;
+                info->stats.rxBytes += 4;
+                fifo_fill_lev --;
+                bytes_in_buf -= 4;
+	} // while ((bytes_in_buf >= 4) && (fifo_fill_lev > 0))
+        // now do the rest as mentioned in STATE.RXBV
+        while ((bytes_in_buf > 0) && (fifo_fill_lev > 0)) {
+                rx_valid_cnt = (READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_STATE) & 
+                                IFX_SSC_STATE_RX_BYTE_VALID_MASK) >> 
+                        IFX_SSC_STATE_RX_BYTE_VALID_OFFSET;
+		if (rx_valid_cnt == 0) break;
+                if (rx_valid_cnt > bytes_in_buf) {
+                        // ### TO DO: warning message: not block aligned data, other data 
+                        //                             in this entry will be lost
+                        rx_valid_cnt = bytes_in_buf;
+                }
+                tmp_val = READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_RB);
+		
+                for (i=0; i<rx_valid_cnt; i++) {		
+			*info->rxbuf_ptr = (tmp_val >> ( 8 * (rx_valid_cnt - i-1))) & 0xff;
+/*			
+                        *info->rxbuf_ptr = tmp_val & 0xff;
+                        tmp_val >>= 8;
+*/			
+			bytes_in_buf--;
+
+			
+			info->rxbuf_ptr++;
+                }
+                info->stats.rxBytes += rx_valid_cnt;
+        }  // while ((bytes_in_buf > 0) && (fifo_fill_lev > 0))
+
+        // check if transfer is complete
+        if (info->rxbuf_ptr >= info->rxbuf_end) {
+                ifx_int_wrapper.disable(info->rxirq);
+                /* wakeup any processes waiting in read() */
+                wake_up_interruptible(&info->rwait);
+                /* and in poll() */
+                //wake_up_interruptible(&info->pwait);
+        } else if ((info->opts.modeRxTx == IFX_SSC_MODE_RX) && 
+		   (READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_RXCNT) == 0)) {
+		// if buffer not filled completely and rx request done initiate new transfer
+/*
+		if  (info->rxbuf_end - info->rxbuf_ptr < 65536)
+*/
+		if  (info->rxbuf_end - info->rxbuf_ptr < IFX_SSC_RXREQ_BLOCK_SIZE)
+                        WRITE_PERIPHERAL_REGISTER((info->rxbuf_end - info->rxbuf_ptr) << 
+						  IFX_SSC_RXREQ_RXCOUNT_OFFSET, 
+                                                  info->mapbase + IFX_SSC_RXREQ);
+                else 
+			WRITE_PERIPHERAL_REGISTER(IFX_SSC_RXREQ_BLOCK_SIZE << IFX_SSC_RXREQ_RXCOUNT_OFFSET, 
+                                                  info->mapbase + IFX_SSC_RXREQ);
+	}
+} // rx_int
+
+inline static void
+tx_int(struct ifx_ssc_port *info)
+{
+	
+	int fifo_space, fill, i;
+	fifo_space = ((READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_ID) & 
+                       IFX_SSC_PERID_TXFS_MASK) >> IFX_SSC_PERID_TXFS_OFFSET) - 
+                ((READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_FSTAT) & 
+                  IFX_SSC_FSTAT_TRANSMIT_WORDS_MASK) >> 
+                 IFX_SSC_FSTAT_TRANSMIT_WORDS_OFFSET);
+
+	if (fifo_space == 0)
+		return;
+
+	fill = info->txbuf_end - info->txbuf_ptr;
+
+	if (fill > fifo_space * 4)
+		fill = fifo_space * 4;
+
+	for (i = 0; i < fill / 4; i++) {
+                // at first 32 bit access
+		WRITE_PERIPHERAL_REGISTER(*(UINT32 *)info->txbuf_ptr, info->mapbase + IFX_SSC_TB);
+                info->txbuf_ptr += 4;
+	}
+
+        fifo_space -= fill / 4;
+	info->stats.txBytes += fill & ~0x3;
+        fill &= 0x3;
+        if ((fifo_space > 0) & (fill > 1)) {
+                // trailing 16 bit access
+                WRITE_PERIPHERAL_REGISTER_16(*(UINT16 *)info->txbuf_ptr, info->mapbase + IFX_SSC_TB);
+                info->txbuf_ptr += 2;
+                info->stats.txBytes += 2;
+                fifo_space --;
+/* added by bingtao */
+		fill -=2;
+	}
+        if ((fifo_space > 0) & (fill > 0)) {
+                // trailing 8 bit access
+                WRITE_PERIPHERAL_REGISTER_8(*(UINT8 *)info->txbuf_ptr, info->mapbase + IFX_SSC_TB);
+                info->txbuf_ptr ++;
+                info->stats.txBytes ++;
+/*
+                fifo_space --;
+*/
+	}
+
+        // check if transmission complete
+        if (info->txbuf_ptr >= info->txbuf_end) {
+                ifx_int_wrapper.disable(info->txirq);
+                kfree(info->txbuf);
+                info->txbuf = NULL;
+                /* wake up any process waiting in poll() */
+                //wake_up_interruptible(&info->pwait);
+        }	
+
+} // tx_int
+
+static void
+ifx_ssc_rx_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct ifx_ssc_port *info = (struct ifx_ssc_port *)dev_id;
+	//WRITE_PERIPHERAL_REGISTER(IFX_SSC_R_BIT, info->mapbase + IFX_SSC_IRN_CR);
+        rx_int(info);
+}
+
+static void
+ifx_ssc_tx_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct ifx_ssc_port *info = (struct ifx_ssc_port *)dev_id;
+	//WRITE_PERIPHERAL_REGISTER(IFX_SSC_T_BIT, info->mapbase + IFX_SSC_IRN_CR);
+        tx_int(info);
+}
+
+static void
+ifx_ssc_err_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct ifx_ssc_port *info = (struct ifx_ssc_port *)dev_id;
+	unsigned int state;
+	unsigned int write_back = 0;
+	unsigned long flags;
+
+
+	local_irq_save(flags);
+	state = READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_STATE); 
+
+	if ((state & IFX_SSC_STATE_RX_UFL) != 0) {
+		info->stats.rxUnErr++;
+		write_back |= IFX_SSC_WHBSTATE_CLR_RX_UFL_ERROR;
+	}
+	if ((state & IFX_SSC_STATE_RX_OFL) != 0) {
+		info->stats.rxOvErr++;
+		write_back |= IFX_SSC_WHBSTATE_CLR_RX_OFL_ERROR;
+	}
+	if ((state & IFX_SSC_STATE_TX_OFL) != 0) {
+		info->stats.txOvErr++;
+		write_back |= IFX_SSC_WHBSTATE_CLR_TX_OFL_ERROR;
+	}
+	if ((state & IFX_SSC_STATE_TX_UFL) != 0) {
+		info->stats.txUnErr++;
+		write_back |= IFX_SSC_WHBSTATE_CLR_TX_UFL_ERROR;
+	}
+//	if ((state & IFX_SSC_STATE_ABORT_ERR) != 0) {
+//		info->stats.abortErr++;
+//		write_back |= IFX_SSC_WHBSTATE_CLR_ABORT_ERROR;
+//	}
+	if ((state & IFX_SSC_STATE_MODE_ERR) != 0) {
+		info->stats.modeErr++;
+		write_back |= IFX_SSC_WHBSTATE_CLR_MODE_ERROR;
+	}
+
+	if (write_back)
+		WRITE_PERIPHERAL_REGISTER(write_back, 
+					  info->mapbase + IFX_SSC_WHBSTATE);
+
+	local_irq_restore(flags);
+}
+
+#ifdef SSC_FRAME_INT_ENABLE
+static void
+ifx_ssc_frm_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	// ### TO DO: wake up framing wait-queue in conjunction with batch execution
+}
+#endif
+
+static void
+ifx_ssc_abort(struct ifx_ssc_port *info)
+{
+	unsigned long flags;
+	bool enabled;
+
+        local_irq_save(flags);
+
+	// disable all int's
+	ifx_int_wrapper.disable(info->rxirq);
+	ifx_int_wrapper.disable(info->txirq);
+	ifx_int_wrapper.disable(info->errirq);
+/*
+	ifx_int_wrapper.disable(info->frmirq);
+*/
+        local_irq_restore(flags);
+
+	// disable SSC (also aborts a receive request!)
+	// ### TO DO: Perhaps it's better to abort after the receiption of a 
+	// complete word. The disable cuts the transmission immediatly and 
+	// releases the chip selects. This could result in unpredictable 
+	// behavior of connected external devices!
+	enabled = (READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_STATE) 
+		   & IFX_SSC_STATE_IS_ENABLED) != 0;
+	WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_ENABLE, 
+				  info->mapbase + IFX_SSC_WHBSTATE);
+
+
+	// flush fifos
+        WRITE_PERIPHERAL_REGISTER(IFX_SSC_XFCON_FIFO_FLUSH, 
+                                  info->mapbase + IFX_SSC_TXFCON);
+        WRITE_PERIPHERAL_REGISTER(IFX_SSC_XFCON_FIFO_FLUSH, 
+                                  info->mapbase + IFX_SSC_RXFCON);
+
+	// free txbuf
+	if (info->txbuf != NULL) {
+		kfree(info->txbuf);
+		info->txbuf = NULL;
+	}
+
+	// wakeup read process
+	if (info->rxbuf != NULL)
+		wake_up_interruptible(&info->rwait);
+
+	// clear pending int's 
+	ifx_int_wrapper.clear(info->rxirq);
+	ifx_int_wrapper.clear(info->txirq);
+	ifx_int_wrapper.clear(info->errirq);
+/*
+	ifx_int_wrapper.clear(info->frmirq);
+*/
+
+	// clear error flags
+	WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_ALL_ERROR,
+				  info->mapbase + IFX_SSC_WHBSTATE);
+
+	//printk("IFX SSC%d: Transmission aborted\n", info->port_nr);
+	// enable SSC
+	if (enabled)
+		WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_SET_ENABLE, 
+					  info->mapbase + IFX_SSC_WHBSTATE);
+
+} // ifx_ssc_abort
+
+
+/*
+ * This routine is called whenever a port is opened.  It enforces
+ * exclusive opening of a port and enables interrupts, etc.
+ */
+int
+ifx_ssc_open(struct inode *inode, struct file * filp)
+{
+	struct ifx_ssc_port  *info;
+	int line;
+	int from_kernel = 0;
+
+	if ((inode == (struct inode *)0) || (inode == (struct inode *)1)) {
+		from_kernel = 1;
+		line = (int)inode;
+	}
+	else {
+		line = MINOR(filp->f_dentry->d_inode->i_rdev);
+		filp->f_op = &ifx_ssc_fops;
+	}
+
+	/* don't open more minor devices than we can support */
+	if (line < 0 || line >= PORT_CNT)
+		return -ENXIO;
+
+	info = &isp[line];
+
+	/* exclusive open */
+	if (info->port_is_open != 0)
+		return -EBUSY;
+	info->port_is_open++;
+
+	ifx_int_wrapper.disable(info->rxirq);
+	ifx_int_wrapper.disable(info->txirq);
+	ifx_int_wrapper.disable(info->errirq);
+/*
+	ifx_int_wrapper.disable(info->frmirq);
+*/
+
+	/* Flush and enable TX/RX FIFO */
+	WRITE_PERIPHERAL_REGISTER((IFX_SSC_DEF_TXFIFO_FL << 
+                                   IFX_SSC_XFCON_ITL_OFFSET) | 
+				  IFX_SSC_XFCON_FIFO_FLUSH   |
+                                  IFX_SSC_XFCON_FIFO_ENABLE, 
+                                  info->mapbase + IFX_SSC_TXFCON);
+        WRITE_PERIPHERAL_REGISTER((IFX_SSC_DEF_RXFIFO_FL << 
+                                   IFX_SSC_XFCON_ITL_OFFSET) |
+				  IFX_SSC_XFCON_FIFO_FLUSH   | 
+                                  IFX_SSC_XFCON_FIFO_ENABLE, 
+                                  info->mapbase + IFX_SSC_RXFCON);
+
+
+	/* logically flush the software FIFOs */
+	info->rxbuf_ptr = 0;
+	info->txbuf_ptr = 0;
+
+	/* clear all error bits */
+	WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_ALL_ERROR,
+				  info->mapbase + IFX_SSC_WHBSTATE);
+
+	// clear pending interrupts
+	ifx_int_wrapper.clear(info->rxirq);
+	ifx_int_wrapper.clear(info->txirq);
+	ifx_int_wrapper.clear(info->errirq);
+/*
+	ifx_int_wrapper.clear(info->frmirq);
+*/
+
+	// enable SSC
+	WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_SET_ENABLE, 
+				  info->mapbase + IFX_SSC_WHBSTATE);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+} /* ifx_ssc_open */
+EXPORT_SYMBOL(ifx_ssc_open);
+
+/*
+ * This routine is called when a particular device is closed.
+ */
+int
+ifx_ssc_close(struct inode *inode, struct file *filp)
+{
+	struct ifx_ssc_port *info;
+        int idx;
+
+	if ((inode == (struct inode *)0) || (inode == (struct inode *)1))
+		idx = (int)inode;
+	else
+		idx = MINOR(filp->f_dentry->d_inode->i_rdev);
+
+	if (idx < 0 || idx >= PORT_CNT)
+		return -ENXIO;
+
+	info = &isp[idx];
+        if (!info)
+                return -ENXIO;
+
+	// disable SSC
+	WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_ENABLE, 
+				  info->mapbase + IFX_SSC_WHBSTATE);
+
+	// call abort function to disable int's, flush fifos...
+	ifx_ssc_abort(info);
+
+	info->port_is_open --;
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+} /* ifx_ssc_close */
+EXPORT_SYMBOL(ifx_ssc_close);
+
+/* added by bingtao */
+/* helper routine to handle reads from the kernel or user-space */
+/* info->rxbuf : never kfree and contains valid data */
+/* should be points to NULL after copying data !!! */
+static ssize_t
+ifx_ssc_read_helper_poll(struct ifx_ssc_port *info, char *buf, size_t len,
+                    int from_kernel)
+{
+        ssize_t         ret_val;
+	unsigned long   flags;
+
+        if (info->opts.modeRxTx == IFX_SSC_MODE_TX) 
+                return -EFAULT;
+        local_irq_save(flags);
+        info->rxbuf_ptr = info->rxbuf;
+        info->rxbuf_end = info->rxbuf + len;
+        local_irq_restore(flags);
+/* Vinetic driver always works in IFX_SSC_MODE_RXTX */ 
+/* TXRX in poll mode */
+	while (info->rxbuf_ptr < info->rxbuf_end){
+/* This is the key point, if you don't check this condition 
+   kfree (NULL) will happen 
+   because tx only need write into FIFO, it's much fast than rx
+   So when rx still waiting , tx already finish and release buf	
+*/	
+		if (info->txbuf_ptr < info->txbuf_end) {
+			tx_int(info);
+		}
+		
+		rx_int(info);
+        };
+
+        ret_val = info->rxbuf_ptr - info->rxbuf; 
+	return (ret_val);
+} // ifx_ssc_read_helper_poll
+
+/* helper routine to handle reads from the kernel or user-space */
+/* info->rx_buf : never kfree and contains valid data */
+/* should be points to NULL after copying data !!! */
+static ssize_t
+ifx_ssc_read_helper(struct ifx_ssc_port *info, char *buf, size_t len,
+                    int from_kernel)
+{
+        ssize_t         ret_val;
+	unsigned long   flags;
+        DECLARE_WAITQUEUE(wait, current);
+
+        if (info->opts.modeRxTx == IFX_SSC_MODE_