aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/amazon/files/drivers
diff options
context:
space:
mode:
authorblogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73>2012-10-05 10:12:53 +0000
committerblogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73>2012-10-05 10:12:53 +0000
commit5c105d9f3fd086aff195d3849dcf847d6b0bd927 (patch)
tree1229a11f725bfa58aa7c57a76898553bb5f6654a /target/linux/amazon/files/drivers
downloadopenwrt-5c105d9f3fd086aff195d3849dcf847d6b0bd927.tar.gz
openwrt-5c105d9f3fd086aff195d3849dcf847d6b0bd927.zip
branch Attitude Adjustment
git-svn-id: svn://svn.openwrt.org/openwrt/branches/attitude_adjustment@33625 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/amazon/files/drivers')
-rw-r--r--target/linux/amazon/files/drivers/atm/amazon_tpe.c3074
-rw-r--r--target/linux/amazon/files/drivers/char/amazon_mei.c7918
-rw-r--r--target/linux/amazon/files/drivers/char/ifx_ssc.c2121
-rw-r--r--target/linux/amazon/files/drivers/mtd/maps/amazon.c204
-rw-r--r--target/linux/amazon/files/drivers/net/ethernet/admmod.c1493
-rw-r--r--target/linux/amazon/files/drivers/net/ethernet/amazon_sw.c899
-rw-r--r--target/linux/amazon/files/drivers/tty/serial/amazon_asc.c711
-rw-r--r--target/linux/amazon/files/drivers/watchdog/amazon_wdt.c277
8 files changed, 16697 insertions, 0 deletions
diff --git a/target/linux/amazon/files/drivers/atm/amazon_tpe.c b/target/linux/amazon/files/drivers/atm/amazon_tpe.c
new file mode 100644
index 000000000..b50749440
--- /dev/null
+++ b/target/linux/amazon/files/drivers/atm/amazon_tpe.c
@@ -0,0 +1,3074 @@
+/*
+ * 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, IRQF_DISABLED, "tpe_swie", NULL);
+ request_irq(AMAZON_CBM_INT, amazon_atm_cbm_isr, IRQF_DISABLED, "tpe_cbm", NULL);
+#ifdef AMAZON_ATM_DEBUG
+ request_irq(AMAZON_HTU_INT , amazon_atm_htu_isr, IRQF_DISABLED, "tpe_htu", NULL);
+#endif
+#ifdef AMAZON_TPE_TEST_AAL5_INT
+ request_irq(AMAZON_AAL5_INT, amazon_atm_aal5_isr, IRQF_DISABLED, "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);
+
+
+
+
+
diff --git a/target/linux/amazon/files/drivers/char/amazon_mei.c b/target/linux/amazon/files/drivers/char/amazon_mei.c
new file mode 100644
index 000000000..7efe52ed6
--- /dev/null
+++ b/target/linux/amazon/files/drivers/char/amazon_mei.c
@@ -0,0 +1,7918 @@
+/* ============================================================================
+ * 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);
+
diff --git a/target/linux/amazon/files/drivers/char/ifx_ssc.c b/target/linux/amazon/files/drivers/char/ifx_ssc.c
new file mode 100644
index 000000000..ea01659a9
--- /dev/null
+++ b/target/linux/amazon/files/drivers/char/ifx_ssc.c
@@ -0,0 +1,2121 @@
+/**************************************************
+ *
+ * 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_TX)
+ return -EFAULT;
+ local_irq_save(flags);
+ info->rxbuf_ptr = info->rxbuf;
+ info->rxbuf_end = info->rxbuf + len;
+ if (info->opts.modeRxTx == IFX_SSC_MODE_RXTX) {
+ if ((info->txbuf == NULL) ||
+ (info->txbuf != info->txbuf_ptr) ||
+ (info->txbuf_end != len + info->txbuf)) {
+ local_irq_restore(flags);
+ printk("IFX SSC - %s: write must be called before calling "
+ "read in combined RX/TX!\n", __FUNCTION__);
+ return -EFAULT;
+ }
+ local_irq_restore(flags);
+ /* should enable tx, right?*/
+ tx_int(info);
+ if (info->txbuf_ptr < info->txbuf_end){
+ ifx_int_wrapper.enable(info->txirq);
+ }
+
+ ifx_int_wrapper.enable(info->rxirq);
+ } else { // rx mode
+ local_irq_restore(flags);
+ if (READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_RXCNT) &
+ IFX_SSC_RXCNT_TODO_MASK)
+ return -EBUSY;
+ ifx_int_wrapper.enable(info->rxirq);
+ // rx request limited to ' bytes
+/*
+ if (len < 65536)
+*/
+ if (len < IFX_SSC_RXREQ_BLOCK_SIZE)
+ WRITE_PERIPHERAL_REGISTER(len << 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);
+ }
+
+ __add_wait_queue(&info->rwait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ // wakeup done in rx_int
+
+ do {
+ local_irq_save(flags);
+ if (info->rxbuf_ptr >= info->rxbuf_end)
+ break;
+ local_irq_restore(flags);
+
+// if (filp->f_flags & O_NONBLOCK)
+// {
+// N = -EAGAIN;
+// goto out;
+// }
+ if (signal_pending(current)) {
+ ret_val = -ERESTARTSYS;
+ goto out;
+ }
+ schedule();
+ } while (1);
+
+ ret_val = info->rxbuf_ptr - info->rxbuf; // should be equal to len
+ local_irq_restore(flags);
+
+ out:
+ current->state = TASK_RUNNING;
+ __remove_wait_queue(&info->rwait, &wait);
+ return (ret_val);
+} // ifx_ssc_read_helper
+
+
+#if 0
+/* helper routine to handle reads from the kernel or user-space */
+/* appropriate in interrupt context */
+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_TX)
+ return -EFAULT;
+ local_irq_save(flags);
+ info->rxbuf_ptr = info->rxbuf;
+ info->rxbuf_end = info->rxbuf + len;
+ if (info->opts.modeRxTx == IFX_SSC_MODE_RXTX) {
+ if ((info->txbuf == NULL) ||
+ (info->txbuf != info->txbuf_ptr) ||
+ (info->txbuf_end != len + info->txbuf)) {
+ local_irq_restore(flags);
+ printk("IFX SSC - %s: write must be called before calling "
+ "read in combined RX/TX!\n", __FUNCTION__);
+ return -EFAULT;
+ }
+ local_irq_restore(flags);
+ /* should enable tx, right?*/
+ tx_int(info);
+ if (!in_irq()){
+ if (info->txbuf_ptr < info->txbuf_end){
+ ifx_int_wrapper.enable(info->txirq);
+ }
+ ifx_int_wrapper.enable(info->rxirq);
+ }
+ } else { // rx mode
+ local_irq_restore(flags);
+ if (READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_RXCNT) &
+ IFX_SSC_RXCNT_TODO_MASK)
+ return -EBUSY;
+ if (!in_irq()){
+ ifx_int_wrapper.enable(info->rxirq);
+ }
+
+ if (len < IFX_SSC_RXREQ_BLOCK_SIZE)
+ WRITE_PERIPHERAL_REGISTER(len << 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);
+ }
+ if (in_irq()){
+ do {
+ rx_int(info);
+ if (info->opts.modeRxTx == IFX_SSC_MODE_RXTX) {
+ tx_int(info);
+ }
+
+ if (info->rxbuf_ptr >= info->rxbuf_end)
+ break;
+ } while (1);
+ ret_val = info->rxbuf_ptr - info->rxbuf;
+ }else{
+ __add_wait_queue(&info->rwait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ // wakeup done in rx_int
+
+ do {
+ local_irq_save(flags);
+ if (info->rxbuf_ptr >= info->rxbuf_end)
+ break;
+ local_irq_restore(flags);
+
+ if (signal_pending(current)) {
+ ret_val = -ERESTARTSYS;
+ goto out;
+ }
+ schedule();
+ } while (1);
+
+ ret_val = info->rxbuf_ptr - info->rxbuf; // should be equal to len
+ local_irq_restore(flags);
+
+ out:
+ current->state = TASK_RUNNING;
+ __remove_wait_queue(&info->rwait, &wait);
+ }
+ return (ret_val);
+} // ifx_ssc_read_helper
+#endif
+
+/* helper routine to handle writes to the kernel or user-space */
+/* info->txbuf has two cases:
+ * 1) return value < 0 (-EFAULT), not touched at all
+ * 2) kfree and points to NULL in interrupt routine (but maybe later )
+ */
+static ssize_t
+ifx_ssc_write_helper(struct ifx_ssc_port *info, const char *buf,
+ size_t len, int from_kernel)
+{
+ // check if in tx or tx/rx mode
+ if (info->opts.modeRxTx == IFX_SSC_MODE_RX)
+ return -EFAULT;
+
+ info->txbuf_ptr = info->txbuf;
+ info->txbuf_end = len + info->txbuf;
+ /* start the transmission (not in rx/tx, see read helper) */
+ if (info->opts.modeRxTx == IFX_SSC_MODE_TX) {
+ tx_int(info);
+ if (info->txbuf_ptr < info->txbuf_end){
+ ifx_int_wrapper.enable(info->txirq);
+ }
+ }
+ //local_irq_restore(flags);
+ return len;
+}
+
+/*
+ * kernel interfaces for read and write.
+ * The caller must set port to: n for SSC<m> with n=m-1 (e.g. n=0 for SSC1)
+ */
+ssize_t
+ifx_ssc_kread(int port, char *kbuf, size_t len)
+{
+ struct ifx_ssc_port *info;
+ ssize_t ret_val;
+
+ if (port < 0 || port >= PORT_CNT)
+ return -ENXIO;
+
+ if (len == 0)
+ return 0;
+
+ info = &isp[port];
+
+ // check if reception in progress
+ if (info->rxbuf != NULL){
+ printk("SSC device busy\n");
+ return -EBUSY;
+ }
+
+ info->rxbuf = kbuf;
+ if (info->rxbuf == NULL){
+ printk("SSC device error\n");
+ return -EINVAL;
+ }
+
+/* changed by bingtao */
+ /* change by TaiCheng */
+ //if (!in_irq()){
+ if (0){
+ ret_val = ifx_ssc_read_helper(info, kbuf, len, 1);
+ }else{
+ ret_val = ifx_ssc_read_helper_poll(info, kbuf, len, 1);
+ };
+ info->rxbuf = NULL;
+
+ // ### TO DO: perhaps warn if ret_val != len
+ ifx_int_wrapper.disable(info->rxirq);
+
+ return (ret_val);
+} // ifx_ssc_kread
+EXPORT_SYMBOL(ifx_ssc_kread);
+
+ssize_t
+ifx_ssc_kwrite(int port, const char *kbuf, size_t len)
+{
+ struct ifx_ssc_port *info;
+ ssize_t ret_val;
+
+ if (port < 0 || port >= PORT_CNT)
+ return -ENXIO;
+
+ if (len == 0)
+ return 0;
+
+ info = &isp[port];
+
+ // check if transmission in progress
+ if (info->txbuf != NULL)
+ return -EBUSY;
+ info->txbuf = (char *)kbuf;
+
+ ret_val = ifx_ssc_write_helper(info, info->txbuf, len, 1);
+ if (ret_val < 0){
+ info->txbuf = NULL;
+ }
+ return ret_val;
+}
+EXPORT_SYMBOL(ifx_ssc_kwrite);
+
+
+/*
+ * user interfaces to read and write
+ */
+static ssize_t
+ifx_ssc_read(struct file *filp, char *ubuf, size_t len, loff_t *off)
+{
+ ssize_t ret_val;
+ int idx;
+ struct ifx_ssc_port *info;
+
+/*
+ if (len == 0)
+ return (0);
+*/
+ idx = MINOR(filp->f_dentry->d_inode->i_rdev);
+ info = &isp[idx];
+
+ // check if reception in progress
+ if (info->rxbuf != NULL)
+ return -EBUSY;
+
+ info->rxbuf = kmalloc(len+ 3, GFP_KERNEL);
+ if (info->rxbuf == NULL)
+ return -ENOMEM;
+
+ ret_val = ifx_ssc_read_helper(info, info->rxbuf, len, 0);
+ // ### TO DO: perhaps warn if ret_val != len
+ if (copy_to_user((void*)ubuf, info->rxbuf, ret_val) != 0)
+ ret_val = -EFAULT;
+
+ ifx_int_wrapper.disable(info->rxirq);
+
+ kfree(info->rxbuf);
+ info->rxbuf = NULL;
+ return (ret_val);
+} // ifx_ssc_read
+
+/*
+ * As many bytes as we have free space for are copied from the user
+ * into txbuf and the actual byte count is returned. The transmission is
+ * always kicked off by calling the appropriate TX routine.
+ */
+static ssize_t
+ifx_ssc_write(struct file *filp, const char *ubuf, size_t len, loff_t *off)
+{
+ int idx;
+ struct ifx_ssc_port *info;
+ int ret_val;
+
+ if (len == 0)
+ return (0);
+
+ idx = MINOR(filp->f_dentry->d_inode->i_rdev);
+ info = &isp[idx];
+
+ // check if transmission in progress
+ if (info->txbuf != NULL)
+ return -EBUSY;
+
+ info->txbuf = kmalloc(len+ 3, GFP_KERNEL);
+ if (info->txbuf == NULL)
+ return -ENOMEM;
+
+ ret_val = copy_from_user(info->txbuf, ubuf, len);
+ if (ret_val == 0)
+ ret_val = ifx_ssc_write_helper(info, info->txbuf, len, 0);
+ else
+ ret_val = -EFAULT;
+ if (ret_val < 0) {
+ kfree(info->txbuf); // otherwise will be done in ISR
+ info->txbuf = NULL;
+ }
+ return (ret_val);
+} /* ifx_ssc_write */
+
+
+/*
+ * ------------------------------------------------------------
+ * ifx_ssc_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+/*-----------------------------------------------------------------------------
+ FUNC-NAME : ifx_ssc_frm_status_get
+ LONG-NAME : framing status get
+ PURPOSE : Get the actual status of the framing.
+
+ PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
+
+ RESULT : pointer to a structure ifx_ssc_frm_status which holds busy and
+ count values.
+
+ REMARKS : Returns a register value independent of framing is enabled or
+ not! Changes structure inside of info, so the return value isn't
+ needed at all, but could be used for simple access.
+-----------------------------------------------------------------------------*/
+static struct ifx_ssc_frm_status *
+ifx_ssc_frm_status_get(struct ifx_ssc_port *info)
+{
+ unsigned long tmp;
+
+ tmp = READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_SFSTAT);
+ info->frm_status.DataBusy = (tmp & IFX_SSC_SFSTAT_IN_DATA) > 0;
+ info->frm_status.PauseBusy = (tmp & IFX_SSC_SFSTAT_IN_PAUSE) > 0;
+ info->frm_status.DataCount = (tmp & IFX_SSC_SFSTAT_DATA_COUNT_MASK)
+ >> IFX_SSC_SFSTAT_DATA_COUNT_OFFSET;
+ info->frm_status.PauseCount = (tmp & IFX_SSC_SFSTAT_PAUSE_COUNT_MASK)
+ >> IFX_SSC_SFSTAT_PAUSE_COUNT_OFFSET;
+ tmp = READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_SFCON);
+ info->frm_status.EnIntAfterData =
+ (tmp & IFX_SSC_SFCON_FIR_ENABLE_BEFORE_PAUSE) > 0;
+ info->frm_status.EnIntAfterPause =
+ (tmp & IFX_SSC_SFCON_FIR_ENABLE_AFTER_PAUSE) > 0;
+ return (&info->frm_status);
+} // ifx_ssc_frm_status_get
+
+
+/*-----------------------------------------------------------------------------
+ FUNC-NAME : ifx_ssc_frm_control_get
+ LONG-NAME : framing control get
+ PURPOSE : Get the actual control values of the framing.
+
+ PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
+
+ RESULT : pointer to a structure ifx_ssc_frm_opts which holds control bits
+ and count reload values.
+
+ REMARKS : Changes structure inside of info, so the return value isn't
+ needed at all, but could be used for simple access.
+-----------------------------------------------------------------------------*/
+static struct ifx_ssc_frm_opts *
+ifx_ssc_frm_control_get(struct ifx_ssc_port *info)
+{
+ unsigned long tmp;
+
+ tmp = READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_SFCON);
+ info->frm_opts.FrameEnable = (tmp & IFX_SSC_SFCON_SF_ENABLE) > 0;
+ info->frm_opts.DataLength = (tmp & IFX_SSC_SFCON_DATA_LENGTH_MASK)
+ >> IFX_SSC_SFCON_DATA_LENGTH_OFFSET;
+ info->frm_opts.PauseLength = (tmp & IFX_SSC_SFCON_PAUSE_LENGTH_MASK)
+ >> IFX_SSC_SFCON_PAUSE_LENGTH_OFFSET;
+ info->frm_opts.IdleData = (tmp & IFX_SSC_SFCON_PAUSE_DATA_MASK)
+ >> IFX_SSC_SFCON_PAUSE_DATA_OFFSET;
+ info->frm_opts.IdleClock = (tmp & IFX_SSC_SFCON_PAUSE_CLOCK_MASK)
+ >> IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET;
+ info->frm_opts.StopAfterPause =
+ (tmp & IFX_SSC_SFCON_STOP_AFTER_PAUSE) > 0;
+ return (&info->frm_opts);
+} // ifx_ssc_frm_control_get
+
+
+/*-----------------------------------------------------------------------------
+ FUNC-NAME : ifx_ssc_frm_control_set
+ LONG-NAME : framing control set
+ PURPOSE : Set the actual control values of the framing.
+
+ PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
+
+ RESULT : pointer to a structure ifx_ssc_frm_opts which holds control bits
+ and count reload values.
+
+ REMARKS :
+-----------------------------------------------------------------------------*/
+static int
+ifx_ssc_frm_control_set(struct ifx_ssc_port *info)
+{
+ unsigned long tmp;
+
+ // check parameters
+ if ((info->frm_opts.DataLength > IFX_SSC_SFCON_DATA_LENGTH_MAX) ||
+ (info->frm_opts.DataLength < 1) ||
+ (info->frm_opts.PauseLength > IFX_SSC_SFCON_PAUSE_LENGTH_MAX) ||
+ (info->frm_opts.PauseLength < 1) ||
+ ((info->frm_opts.IdleData & ~(IFX_SSC_SFCON_PAUSE_DATA_MASK >>
+ IFX_SSC_SFCON_PAUSE_DATA_OFFSET)) != 0 ) ||
+ ((info->frm_opts.IdleClock & ~(IFX_SSC_SFCON_PAUSE_CLOCK_MASK >>
+ IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET)) != 0 ))
+ return -EINVAL;
+
+ // read interrupt bits (they're not changed here)
+ tmp = READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_SFCON) &
+ (IFX_SSC_SFCON_FIR_ENABLE_BEFORE_PAUSE |
+ IFX_SSC_SFCON_FIR_ENABLE_AFTER_PAUSE);
+
+ // set all values with respect to it's bit position (for data and pause
+ // length set N-1)
+ tmp = (info->frm_opts.DataLength - 1) << IFX_SSC_SFCON_DATA_LENGTH_OFFSET;
+ tmp |= (info->frm_opts.PauseLength - 1) << IFX_SSC_SFCON_PAUSE_LENGTH_OFFSET;
+ tmp |= info->frm_opts.IdleData << IFX_SSC_SFCON_PAUSE_DATA_OFFSET;
+ tmp |= info->frm_opts.IdleClock << IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET;
+ tmp |= info->frm_opts.FrameEnable * IFX_SSC_SFCON_SF_ENABLE;
+ tmp |= info->frm_opts.StopAfterPause * IFX_SSC_SFCON_STOP_AFTER_PAUSE;
+
+ WRITE_PERIPHERAL_REGISTER(tmp, info->mapbase + IFX_SSC_SFCON);
+
+ return 0;
+} // ifx_ssc_frm_control_set
+
+
+/*-----------------------------------------------------------------------------
+ FUNC-NAME : ifx_ssc_rxtx_mode_set
+ LONG-NAME : rxtx mode set
+ PURPOSE : Set the transmission mode.
+
+ PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
+
+ RESULT : Returns error code
+
+ REMARKS : Assumes that SSC not used (SSC disabled, device not opened yet
+ or just closed)
+-----------------------------------------------------------------------------*/
+static int
+ifx_ssc_rxtx_mode_set(struct ifx_ssc_port *info, unsigned int val)
+{
+ unsigned long tmp;
+
+ // check parameters
+ if (!(info) || (val & ~(IFX_SSC_MODE_MASK)))
+ return -EINVAL;
+ /*check BUSY and RXCNT*/
+ if ( READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_BUSY
+ ||READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_RXCNT) & IFX_SSC_RXCNT_TODO_MASK)
+ return -EBUSY;
+ // modify
+ tmp = (READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_CON) &
+ ~(IFX_SSC_CON_RX_OFF | IFX_SSC_CON_TX_OFF)) | (val);
+ WRITE_PERIPHERAL_REGISTER(tmp, info->mapbase + IFX_SSC_CON);
+ info->opts.modeRxTx = val;
+/*
+ printk(KERN_DEBUG "IFX SSC%d: Setting mode to %s%s\n",
+ info->port_nr,
+ ((val & IFX_SSC_CON_RX_OFF) == 0) ? "rx ":"",
+ ((val & IFX_SSC_CON_TX_OFF) == 0) ? "tx":"");
+*/
+ return 0;
+} // ifx_ssc_rxtx_mode_set
+
+void ifx_gpio_init(void)
+{
+ u32 temp;
+/* set gpio pin p0.10(SPI_DIN) p0.11(SPI_DOUT) p0.12(SPI_CLK) p0.13(SPI_CS2) direction */
+ temp = *(AMAZON_GPIO_P0_DIR) ;
+ temp &= 0xFFFFFBFF;
+ temp |= 0x3800;
+ *(AMAZON_GPIO_P0_DIR) = temp;
+/* set port 0 alternate select register 0 */
+ temp = *(AMAZON_GPIO_P0_ALTSEL0) ;
+ temp &= 0xFFFFC3FF;
+ temp |= 0x00001c00;
+ *(AMAZON_GPIO_P0_ALTSEL0) = temp;
+
+/* set port 0 alternate select register 1 */
+ temp = *(AMAZON_GPIO_P0_ALTSEL1) ;
+ temp &= 0xFFFFC3FF;
+ temp |= 0x00002000;
+ *(AMAZON_GPIO_P0_ALTSEL1) = temp;
+
+/* set port 0 open drain mode register */
+ temp = *(AMAZON_GPIO_P0_OD);
+ temp |= 0x00003800; /* set output pin normal mode */
+ *(AMAZON_GPIO_P0_OD)= temp;
+}
+
+/*
+ * This routine intializes the SSC appropriately depending
+ * on slave/master and full-/half-duplex mode.
+ * It assumes that the SSC is disabled and the fifo's and buffers
+ * are flushes later on.
+ */
+static int
+ifx_ssc_sethwopts(struct ifx_ssc_port *info)
+{
+ unsigned long flags, bits;
+ struct ifx_ssc_hwopts *opts = &info->opts;
+
+ /* sanity checks */
+ if ((opts->dataWidth < IFX_SSC_MIN_DATA_WIDTH) ||
+ (opts->dataWidth > IFX_SSC_MAX_DATA_WIDTH)) {
+ printk("%s: sanity check failed\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ bits = (opts->dataWidth - 1) << IFX_SSC_CON_DATA_WIDTH_OFFSET;
+ bits |= IFX_SSC_CON_ENABLE_BYTE_VALID;
+// if (opts->abortErrDetect)
+// bits |= IFX_SSC_CON_ABORT_ERR_CHECK;
+ if (opts->rxOvErrDetect)
+ bits |= IFX_SSC_CON_RX_OFL_CHECK;
+ if (opts->rxUndErrDetect)
+ bits |= IFX_SSC_CON_RX_UFL_CHECK;
+ if (opts->txOvErrDetect)
+ bits |= IFX_SSC_CON_TX_OFL_CHECK;
+ if (opts->txUndErrDetect)
+ bits |= IFX_SSC_CON_TX_UFL_CHECK;
+ if (opts->loopBack)
+ bits |= IFX_SSC_CON_LOOPBACK_MODE;
+ if (opts->echoMode)
+ bits |= IFX_SSC_CON_ECHO_MODE_ON;
+ if (opts->headingControl)
+ bits |= IFX_SSC_CON_MSB_FIRST;
+ if (opts->clockPhase)
+ bits |= IFX_SSC_CON_LATCH_THEN_SHIFT;
+ if (opts->clockPolarity)
+ bits |= IFX_SSC_CON_CLOCK_FALL;
+ switch (opts->modeRxTx) {
+ case IFX_SSC_MODE_TX:
+ bits |= IFX_SSC_CON_RX_OFF;
+ break;
+ case IFX_SSC_MODE_RX:
+ bits |= IFX_SSC_CON_TX_OFF;
+ break;
+ } // switch (opts->modeRxT)
+ local_irq_save(flags);
+ WRITE_PERIPHERAL_REGISTER(bits, info->mapbase + IFX_SSC_CON);
+ WRITE_PERIPHERAL_REGISTER((info->opts.gpoCs << IFX_SSC_GPOCON_ISCSB0_POS) |
+ (info->opts.gpoInv << IFX_SSC_GPOCON_INVOUT0_POS),
+ info->mapbase + IFX_SSC_GPOCON);
+ //master mode
+ if (opts->masterSelect){
+ WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_SET_MASTER_SELECT,info->mapbase + IFX_SSC_WHBSTATE);
+ }else{
+ WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_MASTER_SELECT,info->mapbase + IFX_SSC_WHBSTATE);
+ }
+ // init serial framing
+ WRITE_PERIPHERAL_REGISTER(0, info->mapbase + IFX_SSC_SFCON);
+ /* set up the port pins */
+ //check for general requirements to switch (external) pad/pin characteristics
+ ifx_gpio_init();
+ local_irq_restore(flags);
+
+ return 0;
+} // ifx_ssc_sethwopts
+
+static int
+ifx_ssc_set_baud(struct ifx_ssc_port *info, unsigned int baud)
+{
+ unsigned int ifx_ssc_clock;
+ unsigned int br;
+ unsigned long flags;
+ bool enabled;
+
+ ifx_ssc_clock = ifx_ssc_get_kernel_clk(info);
+ if (ifx_ssc_clock ==0)
+ return -EINVAL;
+
+ local_irq_save(flags);
+ /* have to disable the SSC to set the baudrate */
+ 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);
+
+ // compute divider
+ br = ((ifx_ssc_clock >> 1)/baud) - 1;
+ asm("SYNC");
+ if (br > 0xffff ||
+ ((br == 0) &&
+ ((READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_STATE) &
+ IFX_SSC_STATE_IS_MASTER) == 0))){
+ local_irq_restore(flags);
+ printk("%s: illegal baudrate %u\n", __FUNCTION__, baud);
+ return -EINVAL;
+ }
+ WRITE_PERIPHERAL_REGISTER(br, info->mapbase + IFX_SSC_BR);
+ if (enabled)
+ WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_SET_ENABLE,
+ info->mapbase + IFX_SSC_WHBSTATE);
+
+ local_irq_restore(flags);
+ return 0;
+} // ifx_ssc_set_baud
+
+static int
+ifx_ssc_hwinit(struct ifx_ssc_port *info)
+{
+ unsigned long flags;
+ bool enabled;
+
+ /* have to disable the SSC */
+ 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);
+
+ if (ifx_ssc_sethwopts(info) < 0)
+ {
+ printk("%s: setting the hardware options failed\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+
+ if (ifx_ssc_set_baud(info, info->baud) < 0) {
+ printk("%s: setting the baud rate failed\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ local_irq_save(flags);
+ /* TX FIFO */
+ WRITE_PERIPHERAL_REGISTER((IFX_SSC_DEF_TXFIFO_FL <<
+ IFX_SSC_XFCON_ITL_OFFSET) |
+ IFX_SSC_XFCON_FIFO_ENABLE,
+ info->mapbase + IFX_SSC_TXFCON);
+ /* RX FIFO */
+ WRITE_PERIPHERAL_REGISTER((IFX_SSC_DEF_RXFIFO_FL <<
+ IFX_SSC_XFCON_ITL_OFFSET) |
+ IFX_SSC_XFCON_FIFO_ENABLE,
+ info->mapbase + IFX_SSC_RXFCON);
+ local_irq_restore(flags);
+ if (enabled)
+ WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_SET_ENABLE,
+ info->mapbase + IFX_SSC_WHBSTATE);
+ return 0;
+} // ifx_ssc_hwinit
+
+/*-----------------------------------------------------------------------------
+ FUNC-NAME : ifx_ssc_batch_exec
+ LONG-NAME :
+ PURPOSE :
+
+ PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
+
+ RESULT : Returns error code
+
+ REMARKS :
+-----------------------------------------------------------------------------*/
+static int
+ifx_ssc_batch_exec(struct ifx_ssc_port *info, struct ifx_ssc_batch_list *batch_anchor)
+{
+ // ### TO DO: implement user space batch execution
+ // first, copy the whole linked list from user to kernel space
+ // save some hardware options
+ // execute list
+ // restore hardware options if selected
+ return -EFAULT;
+} // ifx_ssc_batch_exec
+
+
+/*
+ * This routine allows the driver to implement device-
+ * specific ioctl's. If the ioctl number passed in cmd is
+ * not recognized by the driver, it should return ENOIOCTLCMD.
+ */
+int
+ifx_ssc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long data)
+{
+ struct ifx_ssc_port *info;
+ int line, ret_val = 0;
+ unsigned long flags;
+ unsigned long tmp;
+ 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);
+
+ /* don't use more minor devices than we can support */
+ if (line < 0 || line >= PORT_CNT)
+ return -ENXIO;
+
+ info = &isp[line];
+
+ switch (cmd) {
+ case IFX_SSC_STATS_READ:
+ /* data must be a pointer to a struct ifx_ssc_statistics */
+ if (from_kernel)
+ memcpy((void *)data, (void *)&info->stats,
+ sizeof(struct ifx_ssc_statistics));
+ else
+ if (copy_to_user((void *)data,
+ (void *)&info->stats,
+ sizeof(struct ifx_ssc_statistics)))
+ ret_val = -EFAULT;
+ break;
+ case IFX_SSC_STATS_RESET:
+ /* just resets the statistics counters */
+ memset((void *)&info->stats, 0, sizeof(struct ifx_ssc_statistics));
+ break;
+ case IFX_SSC_BAUD_SET:
+ /* if the buffers are not empty then the port is */
+ /* busy and we shouldn't change things on-the-fly! */
+ if (!info->txbuf || !info->rxbuf ||
+ (READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_STATE)
+ & IFX_SSC_STATE_BUSY)) {
+ ret_val = -EBUSY;
+ break;
+ }
+ /* misuse flags */
+ if (from_kernel)
+ flags = *((unsigned long *)data);
+ else
+ if (copy_from_user((void *)&flags,
+ (void *)data, sizeof(flags)))
+ {
+ ret_val = -EFAULT;
+ break;
+ }
+ if (flags == 0)
+ {
+ ret_val = -EINVAL;
+ break;
+ }
+ if (ifx_ssc_set_baud(info, flags) < 0)
+ {
+ ret_val = -EINVAL;
+ break;
+ }
+ info->baud = flags;
+ break;
+ case IFX_SSC_BAUD_GET:
+ if (from_kernel)
+ *((unsigned int *)data) = info->baud;
+ else
+ if (copy_to_user((void *)data,
+ (void *)&info->baud,
+ sizeof(unsigned long)))
+ ret_val = -EFAULT;
+ break;
+ case IFX_SSC_RXTX_MODE_SET:
+ if (from_kernel)
+ tmp = *((unsigned long *)data);
+ else
+ if (copy_from_user((void *)&tmp,
+ (void *)data, sizeof(tmp))) {
+ ret_val = -EFAULT;
+ break;
+ }
+ ret_val = ifx_ssc_rxtx_mode_set(info, tmp);
+ break;
+ case IFX_SSC_RXTX_MODE_GET:
+ tmp = READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_CON) &
+ (~(IFX_SSC_CON_RX_OFF | IFX_SSC_CON_TX_OFF));
+ if (from_kernel)
+ *((unsigned int *)data) = tmp;
+ else
+ if (copy_to_user((void *)data,
+ (void *)&tmp,
+ sizeof(tmp)))
+ ret_val = -EFAULT;
+ break;
+
+ case IFX_SSC_ABORT:
+ ifx_ssc_abort(info);
+ break;
+
+ case IFX_SSC_GPO_OUT_SET:
+ if (from_kernel)
+ tmp = *((unsigned long *)data);
+ else
+ if (copy_from_user((void *)&tmp,
+ (void *)data, sizeof(tmp))) {
+ ret_val = -EFAULT;
+ break;
+ }
+ if (tmp > IFX_SSC_MAX_GPO_OUT)
+ ret_val = -EINVAL;
+ else
+ WRITE_PERIPHERAL_REGISTER
+ (1<<(tmp + IFX_SSC_WHBGPOSTAT_SETOUT0_POS),
+ info->mapbase + IFX_SSC_WHBGPOSTAT);
+ break;
+ case IFX_SSC_GPO_OUT_CLR:
+ if (from_kernel)
+ tmp = *((unsigned long *)data);
+ else
+ if (copy_from_user((void *)&tmp,
+ (void *)data, sizeof(tmp))) {
+ ret_val = -EFAULT;
+ break;
+ }
+ if (tmp > IFX_SSC_MAX_GPO_OUT)
+ ret_val = -EINVAL;
+ else {
+ WRITE_PERIPHERAL_REGISTER
+ (1<<(tmp + IFX_SSC_WHBGPOSTAT_CLROUT0_POS),
+ info->mapbase + IFX_SSC_WHBGPOSTAT);
+ }
+ break;
+ case IFX_SSC_GPO_OUT_GET:
+ tmp = READ_PERIPHERAL_REGISTER
+ (info->mapbase + IFX_SSC_GPOSTAT);
+ if (from_kernel)
+ *((unsigned int *)data) = tmp;
+ else
+ if (copy_to_user((void *)data,
+ (void *)&tmp,
+ sizeof(tmp)))
+ ret_val = -EFAULT;
+ break;
+ case IFX_SSC_FRM_STATUS_GET:
+ ifx_ssc_frm_status_get(info);
+ if (from_kernel)
+ memcpy((void *)data, (void *)&info->frm_status,
+ sizeof(struct ifx_ssc_frm_status));
+ else
+ if (copy_to_user((void *)data,
+ (void *)&info->frm_status,
+ sizeof(struct ifx_ssc_frm_status)))
+ ret_val = -EFAULT;
+ break;
+ case IFX_SSC_FRM_CONTROL_GET:
+ ifx_ssc_frm_control_get(info);
+ if (from_kernel)
+ memcpy((void *)data, (void *)&info->frm_opts,
+ sizeof(struct ifx_ssc_frm_opts));
+ else
+ if (copy_to_user((void *)data,
+ (void *)&info->frm_opts,
+ sizeof(struct ifx_ssc_frm_opts)))
+ ret_val = -EFAULT;
+ break;
+ case IFX_SSC_FRM_CONTROL_SET:
+ if (from_kernel)
+ memcpy((void *)&info->frm_opts, (void *)data,
+ sizeof(struct ifx_ssc_frm_opts));
+ else
+ if (copy_to_user((void *)&info->frm_opts,
+ (void *)data,
+ sizeof(struct ifx_ssc_frm_opts))){
+ ret_val = -EFAULT;
+ break;
+ }
+ ret_val = ifx_ssc_frm_control_set(info);
+ break;
+ case IFX_SSC_HWOPTS_SET:
+ /* data must be a pointer to a struct ifx_ssc_hwopts */
+ /* if the buffers are not empty then the port is */
+ /* busy and we shouldn't change things on-the-fly! */
+ if (!info->txbuf || !info->rxbuf ||
+ (READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_STATE)
+ & IFX_SSC_STATE_BUSY)) {
+ ret_val = -EBUSY;
+ break;
+ }
+ if (from_kernel)
+ memcpy((void *)&info->opts, (void *)data,
+ sizeof(struct ifx_ssc_hwopts));
+ else
+ if (copy_from_user((void *)&info->opts,
+ (void *)data,
+ sizeof(struct ifx_ssc_hwopts)))
+ {
+ ret_val = -EFAULT;
+ break;
+ }
+ if (ifx_ssc_hwinit(info) < 0)
+ {
+ ret_val = -EIO;
+ }
+ break;
+ case IFX_SSC_HWOPTS_GET:
+ /* data must be a pointer to a struct ifx_ssc_hwopts */
+ if (from_kernel)
+ memcpy((void *)data, (void *)&info->opts,
+ sizeof(struct ifx_ssc_hwopts));
+ else
+ if (copy_to_user((void *)data,
+ (void *)&info->opts,
+ sizeof(struct ifx_ssc_hwopts)))
+ ret_val = -EFAULT;
+ break;
+ default:
+ ret_val = -ENOIOCTLCMD;
+ }
+
+ return ret_val;
+} /* ifx_ssc_ioctl */
+EXPORT_SYMBOL(ifx_ssc_ioctl);
+
+///* the poll routine */
+//static unsigned int
+//ifx_ssc_poll(struct file *filp, struct poll_table_struct *pts)
+//{
+// int unit = MINOR(filp->f_dentry->d_inode->i_rdev);
+// struct ifx_ssc_port *info;
+// unsigned int mask = 0;
+// int spc;
+//
+// info = &isp[unit];
+//
+// /* add event to the wait queues */
+// /* DO NOT FORGET TO DO A WAKEUP ON THESE !!!! */
+// poll_wait(filp, &info->pwait, pts);
+//
+// /* are there bytes in the RX SW-FIFO? */
+// if (info->rxrp != info->rxwp)
+// mask |= POLLIN | POLLRDNORM;
+//
+// /* free space in the TX SW-FIFO */
+// spc = info->txrp - info->txwp - 1;
+// if (spc < 0)
+// spc += TX_BUFSIZE;
+//#ifdef IFX_SSC_USEDMA
+// /* writing always works, except in the DMA case when all descriptors */
+// /* are used up */
+// if (unit == 1 && info->dma_freecnt == 0)
+// spc = 0;
+//#endif
+// if (spc > 0)
+// mask |= POLLOUT | POLLWRNORM;
+//
+// return (mask);
+//}
+
+static int
+ifx_ssc1_read_proc(char *page, char **start, off_t offset, int count, int *eof, void *data)
+{
+ int off = 0;
+ unsigned long flags;
+
+ /* don't want any interrupts here */
+ save_flags(flags);
+ cli();
+
+
+ /* print statistics */
+ off += sprintf(page+off, "Statistics for Infineon Synchronous Serial Controller SSC1\n");
+ off += sprintf(page+off, "RX overflow errors %d\n", isp[0].stats.rxOvErr);
+ off += sprintf(page+off, "RX underflow errors %d\n", isp[0].stats.rxUnErr);
+ off += sprintf(page+off, "TX overflow errors %d\n", isp[0].stats.txOvErr);
+ off += sprintf(page+off, "TX underflow errors %d\n", isp[0].stats.txUnErr);
+ off += sprintf(page+off, "Abort errors %d\n", isp[0].stats.abortErr);
+ off += sprintf(page+off, "Mode errors %d\n", isp[0].stats.modeErr);
+ off += sprintf(page+off, "RX Bytes %d\n", isp[0].stats.rxBytes);
+ off += sprintf(page+off, "TX Bytes %d\n", isp[0].stats.txBytes);
+
+ restore_flags (flags); /* XXXXX */
+ *eof = 1;
+ return (off);
+}
+
+
+/*
+ * This routine prints out the appropriate serial driver version number
+ */
+static inline void
+show_version(void)
+{
+#if 0
+ printk("Infineon Technologies Synchronous Serial Controller (SSC) driver\n"
+ " version %s - built %s %s\n", IFX_SSC_DRV_VERSION, __DATE__, __TIME__);
+#endif
+} /* show_version */
+
+
+/*
+ * Due to the fact that a port can be dynamically switched between slave
+ * and master mode using an IOCTL the hardware is not initialized here,
+ * but in ifx_ssc_hwinit() as a result of an IOCTL.
+ */
+int __init
+ifx_ssc_init(void)
+{
+ struct ifx_ssc_port *info;
+ int i, nbytes;
+ unsigned long flags;
+ int ret_val;
+
+ // ### TO DO: dynamic port count evaluation due to pin multiplexing
+
+ ret_val = -ENOMEM;
+ nbytes = PORT_CNT * sizeof(struct ifx_ssc_port);
+ isp = (struct ifx_ssc_port *)kmalloc(nbytes, GFP_KERNEL);
+ if (isp == NULL)
+ {
+ printk("%s: no memory for isp\n", __FUNCTION__);
+ return (ret_val);
+ }
+ memset(isp, 0, nbytes);
+
+ show_version();
+
+ /* register the device */
+ ret_val = -ENXIO;
+/*
+ i = maj;
+*/
+ if ((i = register_chrdev(maj, "ssc", &ifx_ssc_fops)) < 0)
+ {
+ printk("Unable to register major %d for the Infineon SSC\n", maj);
+ if (maj == 0){
+ goto errout;
+ }
+ else{
+ maj = 0;
+ if ((i = register_chrdev(maj, "ssc", &ifx_ssc_fops)) < 0)
+ {
+ printk("Unable to register major %d for the Infineon SSC\n", maj);
+ goto errout;
+ }
+ }
+ }
+ if (maj == 0) maj = i;
+ //printk("registered major %d for Infineon SSC\n", maj);
+
+ /* set default values in ifx_ssc_port */
+ for (i = 0; i < PORT_CNT; i++) {
+ info = &isp[i];
+ info->port_nr = i;
+ /* default values for the HwOpts */
+ info->opts.AbortErrDetect = IFX_SSC_DEF_ABRT_ERR_DETECT;
+ info->opts.rxOvErrDetect = IFX_SSC_DEF_RO_ERR_DETECT;
+ info->opts.rxUndErrDetect = IFX_SSC_DEF_RU_ERR_DETECT;
+ info->opts.txOvErrDetect = IFX_SSC_DEF_TO_ERR_DETECT;
+ info->opts.txUndErrDetect = IFX_SSC_DEF_TU_ERR_DETECT;
+ info->opts.loopBack = IFX_SSC_DEF_LOOP_BACK;
+ info->opts.echoMode = IFX_SSC_DEF_ECHO_MODE;
+ info->opts.idleValue = IFX_SSC_DEF_IDLE_DATA;
+ info->opts.clockPolarity = IFX_SSC_DEF_CLOCK_POLARITY;
+ info->opts.clockPhase = IFX_SSC_DEF_CLOCK_PHASE;
+ info->opts.headingControl = IFX_SSC_DEF_HEADING_CONTROL;
+ info->opts.dataWidth = IFX_SSC_DEF_DATA_WIDTH;
+ info->opts.modeRxTx = IFX_SSC_DEF_MODE_RXTX;
+ info->opts.gpoCs = IFX_SSC_DEF_GPO_CS;
+ info->opts.gpoInv = IFX_SSC_DEF_GPO_INV;
+ info->opts.masterSelect = IFX_SSC_DEF_MASTERSLAVE;
+ info->baud = IFX_SSC_DEF_BAUDRATE;
+ info->rxbuf = NULL;
+ info->txbuf = NULL;
+ /* values specific to SSC1 */
+ if (i == 0) {
+ info->mapbase = AMAZON_SSC_BASE_ADD_0;
+ // ### TO DO: power management
+
+ // setting interrupt vectors
+ info->txirq = IFX_SSC_TIR;
+ info->rxirq = IFX_SSC_RIR;
+ info->errirq = IFX_SSC_EIR;
+/*
+ info->frmirq = IFX_SSC_FIR;
+*/
+ }
+ /* activate SSC */
+ /* CLC.DISS = 0 */
+ WRITE_PERIPHERAL_REGISTER(IFX_SSC_DEF_RMC << IFX_CLC_RUN_DIVIDER_OFFSET, info->mapbase + IFX_SSC_CLC);
+
+// ### TO DO: multiple instances
+
+ init_waitqueue_head(&info->rwait);
+ //init_waitqueue_head(&info->pwait);
+
+ local_irq_save(flags);
+
+ // init serial framing register
+ WRITE_PERIPHERAL_REGISTER(IFX_SSC_DEF_SFCON, info->mapbase + IFX_SSC_SFCON);
+
+ /* try to get the interrupts */
+ // ### TO DO: interrupt handling with multiple instances
+ ret_val = ifx_int_wrapper.request(info->txirq, ifx_ssc_tx_int,
+ 0, "ifx_ssc_tx", info);
+ if (ret_val){
+ printk("%s: unable to get irq %d\n", __FUNCTION__,
+ info->txirq);
+ local_irq_restore(flags);
+ goto errout;
+ }
+ ret_val = ifx_int_wrapper.request(info->rxirq, ifx_ssc_rx_int,
+ 0, "ifx_ssc_rx", info);
+ if (ret_val){
+ printk("%s: unable to get irq %d\n", __FUNCTION__,
+ info->rxirq);
+ local_irq_restore(flags);
+ goto irqerr;
+ }
+ ret_val = ifx_int_wrapper.request(info->errirq, ifx_ssc_err_int,
+ 0, "ifx_ssc_err", info);
+ if (ret_val){
+ printk("%s: unable to get irq %d\n", __FUNCTION__,
+ info->errirq);
+ local_irq_restore(flags);
+ goto irqerr;
+ }
+/*
+ ret_val = ifx_int_wrapper.request(info->frmirq, ifx_ssc_frm_int,
+ 0, "ifx_ssc_frm", info);
+ if (ret_val){
+ printk("%s: unable to get irq %d\n", __FUNCTION__,
+ info->frmirq);
+ local_irq_restore(flags);
+ goto irqerr;
+ }
+
+*/
+ WRITE_PERIPHERAL_REGISTER(IFX_SSC_DEF_IRNEN, info->mapbase + IFX_SSC_IRN_EN);
+
+ local_irq_restore(flags);
+ } // for (i = 0; i < PORT_CNT; i++)
+
+ /* init the SSCs with default values */
+ for (i = 0; i < PORT_CNT; i++)
+ {
+ info = &isp[i];
+ if (ifx_ssc_hwinit(info) < 0)
+ {
+ printk("%s: hardware init failed for port %d\n",
+ __FUNCTION__, i);
+ goto irqerr;
+ }
+ }
+
+ /* register /proc read handler */
+ // ### TO DO: multiple instances
+ /* for SSC1, which is always present */
+ create_proc_read_entry("driver/ssc1", 0, NULL, ifx_ssc1_read_proc, NULL);
+ return 0;
+
+irqerr:
+ // ### TO DO: multiple instances
+ ifx_int_wrapper.free(isp[0].txirq,&isp[0]);
+ ifx_int_wrapper.free(isp[0].rxirq,&isp[0]);
+ ifx_int_wrapper.free(isp[0].errirq,&isp[0]);
+/*
+ ifx_int_wrapper.free(isp[0].frmirq, &isp[0]);
+*/
+errout:
+ /* free up any allocated memory in the error case */
+ kfree(isp);
+ return (ret_val);
+} /* ifx_ssc_init */
+
+
+void
+ifx_ssc_cleanup_module(void)
+{
+ int i;
+
+ /* free up any allocated memory */
+ for (i = 0; i < PORT_CNT; i++)
+ {
+ /* disable the SSC */
+ WRITE_PERIPHERAL_REGISTER(IFX_SSC_WHBSTATE_CLR_ENABLE,isp[i].mapbase + IFX_SSC_WHBSTATE);
+ /* free the interrupts */
+ ifx_int_wrapper.free(isp[i].txirq, &isp[i]);
+ ifx_int_wrapper.free(isp[i].rxirq, &isp[i]);
+ ifx_int_wrapper.free(isp[i].errirq, &isp[i]);
+/*
+ ifx_int_wrapper.free(isp[i].frmirq, &isp[i]);
+
+ if (isp[i].rxbuf != NULL)
+ kfree(isp[i].rxbuf);
+ if (isp[i].txbuf != NULL)
+ kfree(isp[i].txbuf);
+*/
+ }
+ kfree(isp);
+ /* unregister the device */
+ if (unregister_chrdev(maj, "ssc"))
+ {
+ printk("Unable to unregister major %d for the SSC\n", maj);
+ }
+ /* delete /proc read handler */
+ remove_proc_entry("driver/ssc1", NULL);
+ remove_proc_entry("driver/ssc2", NULL);
+} /* ifx_ssc_cleanup_module */
+
+module_exit(ifx_ssc_cleanup_module);
+
+/* Module entry-points */
+module_init(ifx_ssc_init);
+
+#ifndef MODULE
+static int __init
+ifx_ssc_set_maj(char *str)
+{
+ maj = simple_strtol(str, NULL, 0);
+ return 1;
+}
+__setup("ssc_maj=", ifx_ssc_set_maj);
+#endif /* !MODULE */
+
+#define AMAZON_SSC_EMSG(fmt,arg...) printk("%s: "fmt,__FUNCTION__, ##arg)
+/* Brief: chip select enable
+ */
+inline int amazon_ssc_cs_low(u32 pin)
+{
+ int ret=0;
+ if ((ret=ifx_ssc_ioctl((struct inode *)0, NULL,IFX_SSC_GPO_OUT_CLR, (unsigned long)&pin))){
+ AMAZON_SSC_EMSG("clear CS %d fails\n",pin);
+ }
+ wmb();
+ return ret;
+}
+EXPORT_SYMBOL(amazon_ssc_cs_low);
+/* Brief: chip select disable
+ */
+inline int amazon_ssc_cs_high(u32 pin)
+{
+ int ret=0;
+ if ((ret=ifx_ssc_ioctl((struct inode *)0, NULL,IFX_SSC_GPO_OUT_SET, (unsigned long)&pin))){
+ AMAZON_SSC_EMSG("set CS %d fails\n", pin);
+ }
+ wmb();
+ return ret;
+}
+EXPORT_SYMBOL(amazon_ssc_cs_high);
+/* Brief: one SSC session
+ * Parameter:
+ * tx_buf
+ * tx_len
+ * rx_buf
+ * rx_len
+ * session_mode: IFX_SSC_MODE_RXTX or IFX_SSC_MODE_TX
+ * Return: >=0 number of bytes received (if rx_buf != 0) or transmitted
+ * <0 error code
+ * Description:
+ * 0. copy data to internal buffer
+ * 1. Write command
+ * 2a. If SSC_SESSION_MODE_TXONLY, read tx_len data
+ * 2b. If not Read back (tx_len + rx_len) data
+ * 3. copy internal buffer to rx buf if necessary
+ */
+static int ssc_session(char * tx_buf, u32 tx_len, char * rx_buf, u32 rx_len)
+{
+ int ret=0;
+
+ char * ssc_tx_buf=NULL;
+ char * ssc_rx_buf=NULL;
+
+// volatile char ssc_tx_buf[128]={0};
+// volatile char ssc_rx_buf[128]={0};
+
+ int eff_size=0;
+ u8 mode=0;
+
+ if (tx_buf == NULL && tx_len ==0 && rx_buf == NULL && rx_len == 0){
+ AMAZON_SSC_EMSG("invalid parameters\n");
+ ret=-EINVAL;
+ goto ssc_session_exit;
+ }else if (tx_buf == NULL || tx_len == 0){
+ if (rx_buf != NULL && rx_len != 0){
+ mode = IFX_SSC_MODE_RX;
+ }else{
+ AMAZON_SSC_EMSG("invalid parameters\n");
+ ret=-EINVAL;
+ goto ssc_session_exit;
+ }
+ }else if (rx_buf == NULL || rx_len ==0){
+ if (tx_buf != NULL && tx_len != 0){
+ mode = IFX_SSC_MODE_TX;
+ }else{
+ AMAZON_SSC_EMSG("invalid parameters\n");
+ ret=-EINVAL;
+ goto ssc_session_exit;
+ }
+ }else{
+ mode = IFX_SSC_MODE_RXTX;
+ }
+
+ if (mode == IFX_SSC_MODE_RXTX){
+ eff_size = tx_len + rx_len;
+ }else if (mode == IFX_SSC_MODE_RX){
+ eff_size = rx_len;
+ }else{
+ eff_size = tx_len;
+ }
+
+ //4 bytes alignment, required by driver
+ /* change by TaiCheng */
+ //if (in_irq()){
+ if (1){
+ ssc_tx_buf = (char*) kmalloc(sizeof(char) * ((eff_size + 3) & (~3)), GFP_ATOMIC);
+ ssc_rx_buf = (char*) kmalloc(sizeof(char) * ((eff_size + 3) & (~3)), GFP_ATOMIC);
+ }else{
+ ssc_tx_buf = (char*) kmalloc(sizeof(char) * ((eff_size + 3) & (~3)), GFP_KERNEL);
+ ssc_rx_buf = (char*) kmalloc(sizeof(char) * ((eff_size + 3) & (~3)), GFP_KERNEL);
+ }
+ if (ssc_tx_buf == NULL || ssc_rx_buf == NULL){
+ AMAZON_SSC_EMSG("no memory for size of %d\n", eff_size);
+ ret = -ENOMEM;
+ goto ssc_session_exit;
+ }
+ memset((void*)ssc_tx_buf, 0, eff_size);
+ memset((void*)ssc_rx_buf, 0, eff_size);
+
+ if (tx_len>0){
+ memcpy(ssc_tx_buf, tx_buf, tx_len);
+ }
+
+ ret=ifx_ssc_kwrite(0, ssc_tx_buf, eff_size);
+
+ if (ret > 0) {
+ ssc_tx_buf = NULL; //should be freed by ifx_ssc_kwrite
+ }
+
+ if ( ret != eff_size ){
+ AMAZON_SSC_EMSG("ifx_ssc_write return %d\n",ret);
+ goto ssc_session_exit;
+ }
+ ret=ifx_ssc_kread(0, ssc_rx_buf,eff_size);
+ if ( ret != eff_size ){
+ AMAZON_SSC_EMSG("ifx_ssc_read return %d\n",ret);
+ goto ssc_session_exit;
+ }
+
+ memcpy(rx_buf, ssc_rx_buf+tx_len, rx_len);
+
+ if (mode == IFX_SSC_MODE_TX) {
+ ret = tx_len;
+ }else{
+ ret = rx_len;
+ }
+ssc_session_exit:
+
+ if (ssc_tx_buf != NULL) kfree(ssc_tx_buf);
+ if (ssc_rx_buf != NULL) kfree(ssc_rx_buf);
+
+ if (ret<0) {
+ printk("ssc session fails\n");
+ }
+ return ret;
+}
+/* Brief: TX-RX session
+ * Parameter:
+ * tx_buf
+ * tx_len
+ * rx_buf
+ * rx_len
+ * Return: >=0 number of bytes received
+ * <0 error code
+ * Description:
+ * 1. TX session
+ * 2. RX session
+ */
+int amazon_ssc_txrx(char * tx_buf, u32 tx_len, char * rx_buf, u32 rx_len)
+{
+ return ssc_session(tx_buf,tx_len,rx_buf,rx_len);
+}
+EXPORT_SYMBOL(amazon_ssc_txrx);
+/* Brief: TX only session
+ * Parameter:
+ * tx_buf
+ * tx_len
+ * Return: >=0 number of bytes transmitted
+ * <0 error code
+ */
+int amazon_ssc_tx(char * tx_buf, u32 tx_len)
+{
+ return ssc_session(tx_buf,tx_len,NULL,0);
+}
+EXPORT_SYMBOL(amazon_ssc_tx);
+/* Brief: RX only session
+ * Parameter:
+ * rx_buf
+ * rx_len
+ * Return: >=0 number of bytes received
+ * <0 error code
+ */
+int amazon_ssc_rx(char * rx_buf, u32 rx_len)
+{
+ return ssc_session(NULL,0,rx_buf,rx_len);
+}
+EXPORT_SYMBOL(amazon_ssc_rx);
+
diff --git a/target/linux/amazon/files/drivers/mtd/maps/amazon.c b/target/linux/amazon/files/drivers/mtd/maps/amazon.c
new file mode 100644
index 000000000..568f7d828
--- /dev/null
+++ b/target/linux/amazon/files/drivers/mtd/maps/amazon.c
@@ -0,0 +1,204 @@
+/*
+ * Handle mapping of the flash memory access routines
+ * on Amazon based devices.
+ *
+ * Copyright(C) 2004 peng.liu@infineon.com
+ *
+ * This code is GPLed
+ *
+ */
+// 000005:fchang 2005/6/2 Modified by Bingtao to double check if the EBU is enabled/disabled
+// 506231:tc.chen 2005/06/23 increase firmware partition size form 192KB to 256KB
+// 050701:linmars 2005/07/01 fix flash size wrong alignment after increase firmware partition
+// 165001:henryhsu 2005/8/18 Remove the support for Intel flash because of 2.1 not enough rootfs partition size
+// 165001:henryhsu 2005/9/7 Rolback to support INtel flash
+// 509071:tc.chen 2005/09/07 Reduced flash writing time
+// 511046:linmars 2005/11/04 change bootloader size from 128 into 64
+// 511241:linmars 2005/11/24 merge TaiChen's IRM patch
+
+// copyright 2005 infineon
+
+// copyright 2007 john crispin <blogic@openwrt.org>
+// copyright 2007 felix fietkau <nbd@openwrt.org>
+// copyright 2009 hauke mehrtens <hauke@hauke-m.de>
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <asm/amazon/amazon.h>
+
+#define AMAZON_PCI_ARB_CTL_ALT 0xb100205c
+#define AMAZON_MTD_REG32( addr ) (*(volatile u32 *)(addr))
+
+
+static struct map_info amazon_map = {
+ .name = "AMAZON_FLASH",
+ .bankwidth = 2,
+};
+
+static map_word amazon_read16(struct map_info * map, unsigned long ofs)
+{
+ map_word temp;
+ ofs ^= 2;
+ temp.x[0] = *((__u16 *) (map->virt + ofs));
+ return temp;
+}
+
+static void amazon_write16(struct map_info *map, map_word d, unsigned long adr)
+{
+ adr ^= 2;
+ *((__u16 *) (map->virt + adr)) = d.x[0];
+}
+
+void amazon_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ u8 *p;
+ u8 *to_8;
+ from = (unsigned long) (from + map->virt);
+ p = (u8 *) from;
+ to_8 = (u8 *) to;
+ while(len--){
+ *to_8++ = *p++;
+ }
+}
+
+void amazon_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ u8 *p = (u8*) from;
+ u8 *to_8;
+ to += (unsigned long) map->virt;
+ to_8 = (u8*)to;
+ while(len--){
+ *p++ = *to_8++;
+ }
+}
+
+#define UBOOT_SIZE 0x40000
+
+static struct mtd_partition amazon_partitions[3] = {
+ {
+ name:"U-Boot", /* U-Boot firmware */
+ offset:0x00000000,
+ size:UBOOT_SIZE , /* 128k */
+ },
+ {
+ name:"kernel", /* firmware */
+ offset:UBOOT_SIZE,
+ size:0x00100000, /* 192K */
+ },
+ {
+ name:"rootfs", /* default partition */
+ offset:0x00200000,
+ size:0x00200000,
+ },
+};
+
+unsigned long uImage_size = 0x10000d;
+
+int find_uImage_size(unsigned long start_offset)
+{
+ unsigned long magic;
+ unsigned long temp;
+ amazon_copy_from(&amazon_map, &magic, start_offset, 4);
+ if (!(ntohl(magic) == 0x27051956)) {
+ printk(KERN_INFO "amazon_mtd: invalid magic (0x%08X) of kernel at 0x%08lx \n", ntohl(magic), start_offset);
+ return 0;
+ }
+ amazon_copy_from(&amazon_map, &temp, start_offset + 12, 4);
+ printk(KERN_INFO "amazon_mtd: kernel size is %ld \n", temp + 0x40);
+ return temp + 0x40;
+}
+
+static int amazon_mtd_probe(struct platform_device *dev)
+{
+ unsigned long uimage_size;
+ struct mtd_info *mymtd = NULL;
+ struct mtd_partition *parts = NULL;
+
+ *AMAZON_EBU_BUSCON0 = 0x1d7ff;
+
+ amazon_map.read = amazon_read16;
+ amazon_map.write = amazon_write16;
+ amazon_map.copy_from = amazon_copy_from;
+ amazon_map.copy_to = amazon_copy_to;
+
+ amazon_map.phys = dev->resource->start;
+ amazon_map.size = dev->resource->end - amazon_map.phys + 1;
+ amazon_map.virt = ioremap_nocache(amazon_map.phys, amazon_map.size);
+
+ if (!amazon_map.virt) {
+ printk(KERN_WARNING "amazon_mtd: Failed to ioremap!\n");
+ return -EIO;
+ }
+
+ mymtd = (struct mtd_info *) do_map_probe("cfi_probe", &amazon_map);
+ if (!mymtd) {
+ iounmap(amazon_map.virt);
+ printk(KERN_WARNING "amazon_mtd: probing failed\n");
+ return -ENXIO;
+ }
+
+ mymtd->owner = THIS_MODULE;
+ parts = &amazon_partitions[0];
+
+ /* Some Samsung devices are containing a 16 MB flash chip with a bigger U-Boot partition. */
+ if(mymtd->size == 0x01000000 && mymtd->erasesize == 0x00020000) {
+ printk(KERN_INFO "amazon_mtd: Found big flash chip!\n");
+ amazon_partitions[0].size = 0x60000;
+ amazon_partitions[1].offset = 0x60000;
+ uimage_size = find_uImage_size(amazon_partitions[1].offset);
+ amazon_partitions[1].size = uimage_size;
+ amazon_partitions[2].offset = 0x60000 + uimage_size;
+ amazon_partitions[2].size = mymtd->size - amazon_partitions[2].offset - mymtd->erasesize;
+ } else {
+ printk(KERN_INFO "amazon_mtd: Found small flash chip!\n");
+ uimage_size = find_uImage_size(amazon_partitions[1].offset);
+ amazon_partitions[1].size = uimage_size;
+ amazon_partitions[2].offset = UBOOT_SIZE + uimage_size;
+ amazon_partitions[2].size = mymtd->size - amazon_partitions[2].offset - (2 * mymtd->erasesize);
+ }
+
+ mtd_device_register(mymtd, parts, 3);
+
+ printk(KERN_INFO "amazon_mtd: added %s flash with %dMB\n",
+ amazon_map.name, ((int)mymtd->size) >> 20);
+ return 0;
+}
+
+static struct platform_driver amazon_mtd_driver = {
+ .probe = amazon_mtd_probe,
+ .driver = {
+ .name = "amazon_mtd",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init amazon_mtd_init(void)
+{
+ int ret = platform_driver_register(&amazon_mtd_driver);
+ if (ret)
+ printk(KERN_WARNING "amazon_mtd: error registering platfom driver!\n");
+ return ret;
+}
+
+static void __exit amazon_mtd_cleanup(void)
+{
+ platform_driver_unregister(&amazon_mtd_driver);
+}
+
+module_init(amazon_mtd_init);
+module_exit(amazon_mtd_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("john crispin blogic@openwrt.org");
+MODULE_DESCRIPTION("MTD map driver for AMAZON boards");
+
diff --git a/target/linux/amazon/files/drivers/net/ethernet/admmod.c b/target/linux/amazon/files/drivers/net/ethernet/admmod.c
new file mode 100644
index 000000000..a11ee1d39
--- /dev/null
+++ b/target/linux/amazon/files/drivers/net/ethernet/admmod.c
@@ -0,0 +1,1493 @@
+/******************************************************************************
+ 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/version.h>
+#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)
+{
+ 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)
+{
+ return 0;
+}
+
+/* IOCTL function */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+static long adm_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
+#else
+static int adm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long args)
+#endif
+{
+ 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 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,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ unlocked_ioctl: adm_ioctl
+#else
+ ioctl: adm_ioctl
+#endif
+};
+
+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);
+
diff --git a/target/linux/amazon/files/drivers/net/ethernet/amazon_sw.c b/target/linux/amazon/files/drivers/net/ethernet/amazon_sw.c
new file mode 100644
index 000000000..d18b439ce
--- /dev/null
+++ b/target/linux/amazon/files/drivers/net/ethernet/amazon_sw.c
@@ -0,0 +1,899 @@
+/*
+ * 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 3 port switch
+ */
+//-----------------------------------------------------------------------
+/* Author: Wu Qi Ming[Qi-Ming.Wu@infineon.com]
+ * Created: 7-April-2004
+ */
+//-----------------------------------------------------------------------
+/* History
+ * Changed on: Jun 28, 2004
+ * Changed by: peng.liu@infineon.com
+ * Reason: add hardware flow control (HFC) (CONFIG_NET_HW_FLOWCONTROL)
+ *
+ * Changed on: Apr 6, 2005
+ * Changed by: mars.lin@infineon.com
+ * Reason : supoort port identification
+ */
+
+
+// copyright 2004-2005 infineon.com
+
+// copyright 2007 john crispin <blogic@openwrt.org>
+// copyright 2007 felix fietkau <nbd@openwrt.org>
+// copyright 2009 hauke mehrtens <hauke@hauke-m.de>
+
+
+// TODO
+// port vlan code from bcrm target... the tawainese code was scrapped due to crappyness
+// check all the mmi reg settings and possibly document them better
+// verify the ethtool code
+// remove the while(1) stuff
+// further clean up and rework ... but it works for now
+// check the mode[]=bridge stuff
+// verify that the ethaddr can be set from u-boot
+
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+
+#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
+#define MODVERSIONS
+#endif
+
+#if defined(MODVERSIONS) && !defined(__GENKSYMS__)
+#include <linux/modversions.h>
+#endif
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/mii.h>
+#include <asm/uaccess.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/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/ethtool.h>
+#include <asm/checksum.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/amazon_dma.h>
+#include <asm/amazon/amazon_sw.h>
+
+// how many mii ports are there ?
+#define AMAZON_SW_INT_NO 2
+
+#define ETHERNET_PACKET_DMA_BUFFER_SIZE 1536
+
+/***************************************** Module Parameters *************************************/
+static char mode[] = "bridge";
+module_param_array(mode, charp, NULL, 0);
+
+static int timeout = 1 * HZ;
+module_param(timeout, int, 0);
+
+int switch_init(struct net_device *dev);
+void switch_tx_timeout(struct net_device *dev);
+
+static struct net_device *switch_devs[2];
+
+int add_mac_table_entry(u64 entry_value)
+{
+ int i;
+ u32 data1, data2;
+
+ AMAZON_SW_REG32(AMAZON_SW_ARL_CTL) = ~7;
+
+ for (i = 0; i < 32; i++) {
+ AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0x80000000 | 0x20 | i;
+ while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {};
+ data1 = AMAZON_SW_REG32(AMAZON_SW_DATA1);
+ data2 = AMAZON_SW_REG32(AMAZON_SW_DATA2);
+ if ((data1 & (0x00700000)) != 0x00700000)
+ continue;
+ AMAZON_SW_REG32(AMAZON_SW_DATA1) = (u32) (entry_value >> 32);
+ AMAZON_SW_REG32(AMAZON_SW_DATA2) = (u32) entry_value & 0xffffffff;
+ AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0xc0000020 | i;
+ while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {};
+ break;
+ }
+ AMAZON_SW_REG32(AMAZON_SW_ARL_CTL) |= 7;
+ if (i >= 32)
+ return -1;
+ return OK;
+}
+
+u64 read_mac_table_entry(int index)
+{
+ u32 data1, data2;
+ u64 value;
+ AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0x80000000 | 0x20 | index;
+ while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {};
+ data1 = AMAZON_SW_REG32(AMAZON_SW_DATA1) & 0xffffff;
+ data2 = AMAZON_SW_REG32(AMAZON_SW_DATA2);
+ value = (u64) data1 << 32 | (u64) data2;
+ return value;
+}
+
+int write_mac_table_entry(int index, u64 value)
+{
+ u32 data1, data2;
+ data1 = (u32) (value >> 32);
+ data2 = (u32) value & 0xffffffff;
+ AMAZON_SW_REG32(AMAZON_SW_DATA1) = data1;
+ AMAZON_SW_REG32(AMAZON_SW_DATA2) = data2;
+ AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0xc0000020 | index;
+ while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {};
+ return OK;
+}
+
+u32 get_mdio_reg(int phy_addr, int reg_num)
+{
+ u32 value;
+ AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) = (3 << 30) | ((phy_addr & 0x1f) << 21) | ((reg_num & 0x1f) << 16);
+ while (AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) & (1 << 31)) {};
+ value = AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) & 0xffff;
+ return value;
+}
+
+int set_mdio_reg(int phy_addr, int reg_num, u32 value)
+{
+ AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) = (2 << 30) | ((phy_addr & 0x1f) << 21) | ((reg_num & 0x1f) << 16) | (value & 0xffff);
+ while (AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) & (1 << 31)) {};
+ return OK;
+}
+
+int auto_negotiate(int phy_addr)
+{
+ u32 value = 0;
+ value = get_mdio_reg(phy_addr, MDIO_BASE_CONTROL_REG);
+ set_mdio_reg(phy_addr, MDIO_BASE_CONTROL_REG, (value | RESTART_AUTO_NEGOTIATION | AUTO_NEGOTIATION_ENABLE | PHY_RESET));
+ return OK;
+}
+
+/*
+ In this version of switch driver, we split the dma channels for the switch.
+ 2 for port0 and 2 for port1. So that we can do internal bridging if necessary.
+ In switch mode, packets coming in from port0 or port1 is able to do Destination
+ address lookup. Packets coming from port0 with destination address of port1 should
+ not go to pmac again. The switch hardware should be able to do the switch in the hard
+ ware level. Packets coming from the pmac should not do the DA look up in that the
+ desination is already known for the kernel. It only needs to go to the correct NIC to
+ find its way out.
+ */
+int amazon_sw_chip_init(void)
+{
+ u32 tmp1;
+ int i = 0;
+
+ /* Aging tick select: 5mins */
+ tmp1 = 0xa0;
+ if (strcmp(mode, "bridge") == 0) {
+ // bridge mode, set militarised mode to 1, no learning!
+ tmp1 |= 0xC00;
+ } else {
+ // enable learning for P0 and P1,
+ tmp1 |= 3;
+ }
+
+ /* unknown broadcast/multicast/unicast to all ports */
+ AMAZON_SW_REG32(AMAZON_SW_UN_DEST) = 0x1ff;
+
+ AMAZON_SW_REG32(AMAZON_SW_ARL_CTL) = tmp1;
+
+ /* OCS:1 set OCS bit, split the two NIC in rx direction EDL:1 (enable DA lookup) */
+#if defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT) || defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT_MODULE)
+ AMAZON_SW_REG32(AMAZON_SW_P2_PCTL) = 0x700;
+#else
+ AMAZON_SW_REG32(AMAZON_SW_P2_PCTL) = 0x401;
+#endif
+
+ /* EPC: 1 split the two NIC in tx direction CRC is generated */
+ AMAZON_SW_REG32(AMAZON_SW_P2_CTL) = 0x6;
+
+ // for bi-directional
+ AMAZON_SW_REG32(AMAZON_SW_P0_WM) = 0x14141412;
+ AMAZON_SW_REG32(AMAZON_SW_P1_WM) = 0x14141412;
+ AMAZON_SW_REG32(AMAZON_SW_P2_WM) = 0x28282826;
+ AMAZON_SW_REG32(AMAZON_SW_GBL_WM) = 0x0;
+
+ AMAZON_SW_REG32(AMAZON_CGU_PLL0SR) = (AMAZON_SW_REG32(AMAZON_CGU_PLL0SR)) | 0x58000000;
+ // clock for PHY
+ AMAZON_SW_REG32(AMAZON_CGU_IFCCR) = (AMAZON_SW_REG32(AMAZON_CGU_IFCCR)) | 0x80000004;
+ // enable power for PHY
+ AMAZON_SW_REG32(AMAZON_PMU_PWDCR) = (AMAZON_SW_REG32(AMAZON_PMU_PWDCR)) | AMAZON_PMU_PWDCR_EPHY;
+ // set reverse MII, enable MDIO statemachine
+ AMAZON_SW_REG32(AMAZON_SW_MDIO_CFG) = 0x800027bf;
+ while (1)
+ if (((AMAZON_SW_REG32(AMAZON_SW_MDIO_CFG)) & 0x80000000) == 0)
+ break;
+ AMAZON_SW_REG32(AMAZON_SW_EPHY) = 0xff;
+
+ // auto negotiation
+ AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) = 0x83e08000;
+ auto_negotiate(0x1f);
+
+ /* enable all ports */
+ AMAZON_SW_REG32(AMAZON_SW_PS_CTL) = 0x7;
+ for (i = 0; i < 32; i++)
+ write_mac_table_entry(i, 1 << 50);
+ return 0;
+}
+
+static unsigned char my_ethaddr[MAX_ADDR_LEN];
+/* need to get the ether addr from u-boot */
+static int __init ethaddr_setup(char *line)
+{
+ char *ep;
+ int i;
+
+ memset(my_ethaddr, 0, MAX_ADDR_LEN);
+ for (i = 0; i < 6; i++) {
+ my_ethaddr[i] = line ? simple_strtoul(line, &ep, 16) : 0;
+ if (line)
+ line = (*ep) ? ep + 1 : ep;
+ }
+ printk(KERN_INFO "amazon_mii0: mac address %2x-%2x-%2x-%2x-%2x-%2x \n", my_ethaddr[0], my_ethaddr[1], my_ethaddr[2], my_ethaddr[3], my_ethaddr[4], my_ethaddr[5]);
+ return 0;
+}
+
+__setup("ethaddr=", ethaddr_setup);
+
+static void open_rx_dma(struct net_device *dev)
+{
+ struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev);
+ struct dma_device_info *dma_dev = priv->dma_device;
+ int i;
+
+ for (i = 0; i < dma_dev->num_rx_chan; i++)
+ dma_dev->rx_chan[i].control = 1;
+ dma_device_update_rx(dma_dev);
+}
+
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+static void close_rx_dma(struct net_device *dev)
+{
+ struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev);
+ struct dma_device_info *dma_dev = priv->dma_device;
+ int i;
+
+ for (i = 0; i < dma_dev->num_rx_chan; i++)
+ dma_dev->rx_chan[i].control = 0;
+ dma_device_update_rx(dma_dev);
+}
+
+void amazon_xon(struct net_device *dev)
+{
+ unsigned long flag;
+ local_irq_save(flag);
+ open_rx_dma(dev);
+ local_irq_restore(flag);
+}
+#endif
+
+int switch_open(struct net_device *dev)
+{
+ struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev);
+ if (!strcmp(dev->name, "eth1")) {
+ priv->mdio_phy_addr = PHY0_ADDR;
+ }
+ open_rx_dma(dev);
+
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+ if ((priv->fc_bit = netdev_register_fc(dev, amazon_xon)) == 0) {
+ printk(KERN_WARNING "amazon_mii0: Hardware Flow Control register fails\n");
+ }
+#endif
+
+ netif_start_queue(dev);
+ return OK;
+}
+
+int switch_release(struct net_device *dev)
+{
+ int i;
+ struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev);
+ struct dma_device_info *dma_dev = priv->dma_device;
+
+ for (i = 0; i < dma_dev->num_tx_chan; i++)
+ dma_dev->tx_chan[i].control = 0;
+ for (i = 0; i < dma_dev->num_rx_chan; i++)
+ dma_dev->rx_chan[i].control = 0;
+
+ dma_device_update(dma_dev);
+
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+ if (priv->fc_bit) {
+ netdev_unregister_fc(priv->fc_bit);
+ }
+#endif
+ netif_stop_queue(dev);
+
+ return OK;
+}
+
+
+void switch_rx(struct net_device *dev, int len, struct sk_buff *skb)
+{
+ struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev);
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+ int mit_sel = 0;
+#endif
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+
+#ifdef CONFIG_NET_HW_FLOWCONTROL
+ mit_sel = netif_rx(skb);
+ switch (mit_sel) {
+ case NET_RX_SUCCESS:
+ case NET_RX_CN_LOW:
+ case NET_RX_CN_MOD:
+ break;
+ case NET_RX_CN_HIGH:
+ break;
+ case NET_RX_DROP:
+ if ((priv->fc_bit)
+ && (!test_and_set_bit(priv->fc_bit, &netdev_fc_xoff))) {
+ close_rx_dma(dev);
+ }
+ break;
+ }
+#else
+ netif_rx(skb);
+#endif
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += len;
+ return;
+}
+
+int asmlinkage switch_hw_tx(char *buf, int len, struct net_device *dev)
+{
+ struct switch_priv *priv = netdev_priv(dev);
+ struct dma_device_info *dma_dev = priv->dma_device;
+
+ dma_dev->current_tx_chan = 0;
+ return dma_device_write(dma_dev, buf, len, priv->skb);
+}
+
+int asmlinkage switch_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ int len;
+ char *data;
+ struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev);
+
+ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+ data = skb->data;
+ priv->skb = skb;
+ dev->trans_start = jiffies;
+
+ if (switch_hw_tx(data, len, dev) != len) {
+ dev_kfree_skb_any(skb);
+ return OK;
+ }
+
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += len;
+ return OK;
+}
+
+void switch_tx_timeout(struct net_device *dev)
+{
+ struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev);
+ priv->stats.tx_errors++;
+ netif_wake_queue(dev);
+ return;
+}
+
+void negotiate(struct net_device *dev)
+{
+ struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev);
+ unsigned short data = get_mdio_reg(priv->mdio_phy_addr, MDIO_ADVERTISMENT_REG);
+
+ data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD);
+
+ switch (priv->current_speed_selection) {
+ case 10:
+ if (priv->current_duplex == full)
+ data |= MDIO_ADVERT_10_FD;
+ else if (priv->current_duplex == half)
+ data |= MDIO_ADVERT_10_HD;
+ else
+ data |= MDIO_ADVERT_10_HD | MDIO_ADVERT_10_FD;
+ break;
+
+ case 100:
+ if (priv->current_duplex == full)
+ data |= MDIO_ADVERT_100_FD;
+ else if (priv->current_duplex == half)
+ data |= MDIO_ADVERT_100_HD;
+ else
+ data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD;
+ break;
+
+ case 0: /* Auto */
+ if (priv->current_duplex == full)
+ data |= MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD;
+ else if (priv->current_duplex == half)
+ data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_10_HD;
+ else
+ data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD;
+ break;
+
+ default: /* assume autoneg speed and duplex */
+ data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD;
+ }
+
+ set_mdio_reg(priv->mdio_phy_addr, MDIO_ADVERTISMENT_REG, data);
+
+ /* Renegotiate with link partner */
+
+ data = get_mdio_reg(priv->mdio_phy_addr, MDIO_BASE_CONTROL_REG);
+ data |= MDIO_BC_NEGOTIATE;
+
+ set_mdio_reg(priv->mdio_phy_addr, MDIO_BASE_CONTROL_REG, data);
+
+}
+
+
+void set_duplex(struct net_device *dev, enum duplex new_duplex)
+{
+ struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev);
+ if (new_duplex != priv->current_duplex) {
+ priv->current_duplex = new_duplex;
+ negotiate(dev);
+ }
+}
+
+void set_speed(struct net_device *dev, unsigned long speed)
+{
+ struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev);
+ priv->current_speed_selection = speed;
+ negotiate(dev);
+}
+
+static int switch_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+ struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev);
+ struct ethtool_cmd ecmd;
+
+ if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd)))
+ return -EFAULT;
+
+ switch (ecmd.cmd) {
+ case ETHTOOL_GSET:
+ memset((void *) &ecmd, 0, sizeof(ecmd));
+ ecmd.supported = SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
+ ecmd.port = PORT_TP;
+ ecmd.transceiver = XCVR_EXTERNAL;
+ ecmd.phy_address = priv->mdio_phy_addr;
+
+ ecmd.speed = priv->current_speed;
+
+ ecmd.duplex = priv->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+
+ ecmd.advertising = ADVERTISED_TP;
+ if (priv->current_duplex == autoneg && priv->current_speed_selection == 0)
+ ecmd.advertising |= ADVERTISED_Autoneg;
+ else {
+ ecmd.advertising |= ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+ if (priv->current_speed_selection == 10)
+ ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full);
+ else if (priv->current_speed_selection == 100)
+ ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full);
+ if (priv->current_duplex == half)
+ ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full);
+ else if (priv->current_duplex == full)
+ ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half);
+ }
+ ecmd.autoneg = AUTONEG_ENABLE;
+ if (copy_to_user(ifr->ifr_data, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+ break;
+
+ case ETHTOOL_SSET:
+ if (!capable(CAP_NET_ADMIN)) {
+ return -EPERM;
+ }
+ if (ecmd.autoneg == AUTONEG_ENABLE) {
+ set_duplex(dev, autoneg);
+ set_speed(dev, 0);
+ } else {
+ set_duplex(dev, ecmd.duplex == DUPLEX_HALF ? half : full);
+ set_speed(dev, ecmd.speed == SPEED_10 ? 10 : 100);
+ }
+ break;
+
+ case ETHTOOL_GDRVINFO:
+ {
+ struct ethtool_drvinfo info;
+ memset((void *) &info, 0, sizeof(info));
+ strncpy(info.driver, "AMAZONE", sizeof(info.driver) - 1);
+ strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1);
+ strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1);
+ info.regdump_len = 0;
+ info.eedump_len = 0;
+ info.testinfo_len = 0;
+ if (copy_to_user(ifr->ifr_data, &info, sizeof(info)))
+ return -EFAULT;
+ }
+ break;
+ case ETHTOOL_NWAY_RST:
+ if (priv->current_duplex == autoneg && priv->current_speed_selection == 0)
+ negotiate(dev);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ break;
+ }
+ return 0;
+}
+
+
+
+int mac_table_tools_ioctl(struct net_device *dev, struct mac_table_req *req)
+{
+ int cmd;
+ int i;
+ cmd = req->cmd;
+ switch (cmd) {
+ case RESET_MAC_TABLE:
+ for (i = 0; i < 32; i++) {
+ write_mac_table_entry(i, 0);
+ }
+ break;
+ case READ_MAC_ENTRY:
+ req->entry_value = read_mac_table_entry(req->index);
+ break;
+ case WRITE_MAC_ENTRY:
+ write_mac_table_entry(req->index, req->entry_value);
+ break;
+ case ADD_MAC_ENTRY:
+ add_mac_table_entry(req->entry_value);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+/*
+ the ioctl for the switch driver is developed in the conventional way
+ the control type falls into some basic categories, among them, the
+ SIOCETHTOOL is the traditional eth interface. VLAN_TOOLS and
+ MAC_TABLE_TOOLS are designed specifically for amazon chip. User
+ should be aware of the data structures used in these interfaces.
+*/
+int switch_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct data_req *switch_data_req = (struct data_req *) ifr->ifr_data;
+ struct mac_table_req *switch_mac_table_req;
+ switch (cmd) {
+ case SIOCETHTOOL:
+ switch_ethtool_ioctl(dev, ifr);
+ break;
+ case SIOCGMIIPHY: /* Get PHY address */
+ break;
+ case SIOCGMIIREG: /* Read MII register */
+ break;
+ case SIOCSMIIREG: /* Write MII register */
+ break;
+ case SET_ETH_SPEED_10: /* 10 Mbps */
+ break;
+ case SET_ETH_SPEED_100: /* 100 Mbps */
+ break;
+ case SET_ETH_SPEED_AUTO: /* Auto negotiate speed */
+ break;
+ case SET_ETH_DUPLEX_HALF: /* Half duplex. */
+ break;
+ case SET_ETH_DUPLEX_FULL: /* Full duplex. */
+ break;
+ case SET_ETH_DUPLEX_AUTO: /* Autonegotiate duplex */
+ break;
+ case SET_ETH_REG:
+ AMAZON_SW_REG32(switch_data_req->index) = switch_data_req->value;
+ break;
+ case MAC_TABLE_TOOLS:
+ switch_mac_table_req = (struct mac_table_req *) ifr->ifr_data;
+ mac_table_tools_ioctl(dev, switch_mac_table_req);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+struct net_device_stats *switch_stats(struct net_device *dev)
+{
+ struct switch_priv *priv = (struct switch_priv *) netdev_priv(dev);
+ return &priv->stats;
+}
+
+int switch_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (new_mtu >= 1516)
+ new_mtu = 1516;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+int switch_hw_receive(struct net_device *dev, struct dma_device_info *dma_dev)
+{
+ u8 *buf = NULL;
+ int len = 0;
+ struct sk_buff *skb = NULL;
+
+ len = dma_device_read(dma_dev, &buf, (void **) &skb);
+
+ if (len >= 0x600) {
+ printk(KERN_WARNING "amazon_mii0: packet too large %d\n", len);
+ goto switch_hw_receive_err_exit;
+ }
+
+ /* remove CRC */
+ len -= 4;
+ if (skb == NULL) {
+ printk(KERN_WARNING "amazon_mii0: cannot restore pointer\n");
+ goto switch_hw_receive_err_exit;
+ }
+ if (len > (skb->end - skb->tail)) {
+ printk(KERN_WARNING "amazon_mii0: BUG, len:%d end:%p tail:%p\n", (len + 4), skb->end, skb->tail);
+ goto switch_hw_receive_err_exit;
+ }
+ skb_put(skb, len);
+ skb->dev = dev;
+ switch_rx(dev, len, skb);
+ return OK;
+
+ switch_hw_receive_err_exit:
+ if (skb)
+ dev_kfree_skb_any(skb);
+ return -EIO;
+}
+
+int dma_intr_handler(struct dma_device_info *dma_dev, int status)
+{
+ struct net_device *dev;
+
+ dev = dma_dev->priv;
+ switch (status) {
+ case RCV_INT:
+ switch_hw_receive(dev, dma_dev);
+ break;
+ case TX_BUF_FULL_INT:
+ netif_stop_queue(dev);
+ break;
+ case TRANSMIT_CPT_INT:
+ netif_wake_queue(dev);
+ break;
+ }
+ return OK;
+}
+
+/* reserve 2 bytes in front of data pointer*/
+u8 *dma_buffer_alloc(int len, int *byte_offset, void **opt)
+{
+ u8 *buffer = NULL;
+ struct sk_buff *skb = NULL;
+ skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE);
+ if (skb == NULL) {
+ return NULL;
+ }
+ buffer = (u8 *) (skb->data);
+ skb_reserve(skb, 2);
+ *(int *) opt = (int) skb;
+ *byte_offset = 2;
+ return buffer;
+}
+
+int dma_buffer_free(u8 * dataptr, void *opt)
+{
+ struct sk_buff *skb = NULL;
+ if (opt == NULL) {
+ kfree(dataptr);
+ } else {
+ skb = (struct sk_buff *) opt;
+ dev_kfree_skb_any(skb);
+ }
+ return OK;
+}
+
+int init_dma_device(_dma_device_info * dma_dev, struct net_device *dev)
+{
+ int i;
+ int num_tx_chan, num_rx_chan;
+ if (strcmp(dma_dev->device_name, "switch1") == 0) {
+ num_tx_chan = 1;
+ num_rx_chan = 2;
+ } else {
+ num_tx_chan = 1;
+ num_rx_chan = 2;
+ }
+ dma_dev->priv = dev;
+
+ dma_dev->weight = 1;
+ dma_dev->num_tx_chan = num_tx_chan;
+ dma_dev->num_rx_chan = num_rx_chan;
+ dma_dev->ack = 1;
+ dma_dev->tx_burst_len = 4;
+ dma_dev->rx_burst_len = 4;
+ for (i = 0; i < dma_dev->num_tx_chan; i++) {
+ dma_dev->tx_chan[i].weight = QOS_DEFAULT_WGT;
+ dma_dev->tx_chan[i].desc_num = 10;
+ dma_dev->tx_chan[i].packet_size = 0;
+ dma_dev->tx_chan[i].control = 0;
+ }
+ for (i = 0; i < num_rx_chan; i++) {
+ dma_dev->rx_chan[i].weight = QOS_DEFAULT_WGT;
+ dma_dev->rx_chan[i].desc_num = 10;
+ dma_dev->rx_chan[i].packet_size = ETHERNET_PACKET_DMA_BUFFER_SIZE;
+ dma_dev->rx_chan[i].control = 0;
+ }
+ dma_dev->intr_handler = dma_intr_handler;
+ dma_dev->buffer_alloc = dma_buffer_alloc;
+ dma_dev->buffer_free = dma_buffer_free;
+ return 0;
+}
+
+int switch_set_mac_address(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ return OK;
+}
+
+static const struct net_device_ops amazon_mii_ops = {
+ .ndo_init = switch_init,
+ .ndo_open = switch_open,
+ .ndo_stop = switch_release,
+ .ndo_start_xmit = switch_tx,
+ .ndo_do_ioctl = switch_ioctl,
+ .ndo_get_stats = switch_stats,
+ .ndo_change_mtu = switch_change_mtu,
+ .ndo_set_mac_address = switch_set_mac_address,
+ .ndo_tx_timeout = switch_tx_timeout,
+};
+
+int switch_init(struct net_device *dev)
+{
+ u64 retval = 0;
+ int i;
+ int result;
+ struct switch_priv *priv;
+ ether_setup(dev); /* assign some of the fields */
+ printk(KERN_INFO "amazon_mii0: %s up using ", dev->name);
+ dev->watchdog_timeo = timeout;
+
+ priv = netdev_priv(dev);
+ priv->dma_device = (struct dma_device_info *) kmalloc(sizeof(struct dma_device_info), GFP_KERNEL);
+ if (priv->num == 0) {
+ sprintf(priv->dma_device->device_name, "switch1");
+ } else if (priv->num == 1) {
+ sprintf(priv->dma_device->device_name, "switch2");
+ }
+ printk("\"%s\"\n", priv->dma_device->device_name);
+ init_dma_device(priv->dma_device, dev);
+ result = dma_device_register(priv->dma_device);
+
+ /* read the mac address from the mac table and put them into the mac table. */
+ for (i = 0; i < 6; i++) {
+ retval += my_ethaddr[i];
+ }
+ /* ethaddr not set in u-boot ? */
+ if (retval == 0) {
+ dev->dev_addr[0] = 0x00;
+ dev->dev_addr[1] = 0x20;
+ dev->dev_addr[2] = 0xda;
+ dev->dev_addr[3] = 0x86;
+ dev->dev_addr[4] = 0x23;
+ dev->dev_addr[5] = 0x74 + (unsigned char) priv->num;
+ } else {
+ for (i = 0; i < 6; i++) {
+ dev->dev_addr[i] = my_ethaddr[i];
+ }
+ dev->dev_addr[5] += +(unsigned char) priv->num;
+ }
+ return OK;
+}
+
+static int amazon_mii_probe(struct platform_device *dev)
+{
+ int i = 0, result, device_present = 0;
+ struct switch_priv *priv;
+
+ for (i = 0; i < AMAZON_SW_INT_NO; i++) {
+ switch_devs[i] = alloc_etherdev(sizeof(struct switch_priv));
+ switch_devs[i]->netdev_ops = &amazon_mii_ops;
+ strcpy(switch_devs[i]->name, "eth%d");
+ priv = (struct switch_priv *) netdev_priv(switch_devs[i]);
+ priv->num = i;
+ if ((result = register_netdev(switch_devs[i])))
+ printk(KERN_WARNING "amazon_mii0: error %i registering device \"%s\"\n", result, switch_devs[i]->name);
+ else
+ device_present++;
+ }
+ amazon_sw_chip_init();
+ return device_present ? 0 : -ENODEV;
+}
+
+static int amazon_mii_remove(struct platform_device *dev)
+{
+ int i;
+ struct switch_priv *priv;
+ for (i = 0; i < AMAZON_SW_INT_NO; i++) {
+ priv = netdev_priv(switch_devs[i]);
+ if (priv->dma_device) {
+ dma_device_unregister(priv->dma_device);
+ kfree(priv->dma_device);
+ }
+ kfree(netdev_priv(switch_devs[i]));
+ unregister_netdev(switch_devs[i]);
+ }
+ return 0;
+}
+
+static struct platform_driver amazon_mii_driver = {
+ .probe = amazon_mii_probe,
+ .remove = amazon_mii_remove,
+ .driver = {
+ .name = "amazon_mii0",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init amazon_mii_init(void)
+{
+ int ret = platform_driver_register(&amazon_mii_driver);
+ if (ret)
+ printk(KERN_WARNING "amazon_mii0: Error registering platfom driver!\n");
+ return ret;
+}
+
+static void __exit amazon_mii_cleanup(void)
+{
+ platform_driver_unregister(&amazon_mii_driver);
+}
+
+module_init(amazon_mii_init);
+module_exit(amazon_mii_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Wu Qi Ming");
+MODULE_DESCRIPTION("ethernet driver for AMAZON boards");
+
diff --git a/target/linux/amazon/files/drivers/tty/serial/amazon_asc.c b/target/linux/amazon/files/drivers/tty/serial/amazon_asc.c
new file mode 100644
index 000000000..bb2dd7222
--- /dev/null
+++ b/target/linux/amazon/files/drivers/tty/serial/amazon_asc.c
@@ -0,0 +1,711 @@
+/*
+ * Driver for AMAZONASC serial ports
+ *
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ * Based on drivers/serial/serial_s3c2400.c
+ *
+ * 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
+ *
+ * Copyright (C) 2004 Infineon IFAP DC COM CPE
+ * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2007 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/irq.h>
+#include <asm/amazon/serial.h>
+
+#define PORT_AMAZONASC 111
+
+#include <linux/serial_core.h>
+
+#define UART_NR 1
+
+#define UART_DUMMY_UER_RX 1
+
+#define SERIAL_AMAZONASC_MAJOR TTY_MAJOR
+#define CALLOUT_AMAZONASC_MAJOR TTYAUX_MAJOR
+#define SERIAL_AMAZONASC_MINOR 64
+#define SERIAL_AMAZONASC_NR UART_NR
+
+static void amazonasc_tx_chars(struct uart_port *port);
+static struct uart_port amazonasc_ports[UART_NR];
+static struct uart_driver amazonasc_reg;
+static unsigned int uartclk = 0;
+
+static void amazonasc_stop_tx(struct uart_port *port)
+{
+ /* fifo underrun shuts up after firing once */
+ return;
+}
+
+static void amazonasc_start_tx(struct uart_port *port)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ amazonasc_tx_chars(port);
+ local_irq_restore(flags);
+
+ return;
+}
+
+static void amazonasc_stop_rx(struct uart_port *port)
+{
+ /* clear the RX enable bit */
+ amazon_writel(ASCWHBCON_CLRREN, AMAZON_ASC_WHBCON);
+}
+
+static void amazonasc_enable_ms(struct uart_port *port)
+{
+ /* no modem signals */
+ return;
+}
+
+#include <linux/version.h>
+
+static void
+amazonasc_rx_chars(struct uart_port *port)
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31))
+ struct tty_struct *tty = port->state->port.tty;
+#else
+ struct tty_struct *tty = port->info->port.tty;
+#endif
+ unsigned int ch = 0, rsr = 0, fifocnt;
+
+ fifocnt = amazon_readl(AMAZON_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
+ while (fifocnt--)
+ {
+ u8 flag = TTY_NORMAL;
+ ch = amazon_readl(AMAZON_ASC_RBUF);
+ rsr = (amazon_readl(AMAZON_ASC_CON) & ASCCON_ANY) | UART_DUMMY_UER_RX;
+ tty_flip_buffer_push(tty);
+ port->icount.rx++;
+
+ /*
+ * Note that the error handling code is
+ * out of the main execution path
+ */
+ if (rsr & ASCCON_ANY) {
+ if (rsr & ASCCON_PE) {
+ port->icount.parity++;
+ amazon_writel_masked(AMAZON_ASC_WHBCON, ASCWHBCON_CLRPE, ASCWHBCON_CLRPE);
+ } else if (rsr & ASCCON_FE) {
+ port->icount.frame++;
+ amazon_writel_masked(AMAZON_ASC_WHBCON, ASCWHBCON_CLRFE, ASCWHBCON_CLRFE);
+ }
+ if (rsr & ASCCON_OE) {
+ port->icount.overrun++;
+ amazon_writel_masked(AMAZON_ASC_WHBCON, ASCWHBCON_CLROE, ASCWHBCON_CLROE);
+ }
+
+ rsr &= port->read_status_mask;
+
+ if (rsr & ASCCON_PE)
+ flag = TTY_PARITY;
+ else if (rsr & ASCCON_FE)
+ flag = TTY_FRAME;
+ }
+
+ if ((rsr & port->ignore_status_mask) == 0)
+ tty_insert_flip_char(tty, ch, flag);
+
+ if (rsr & ASCCON_OE)
+ /*
+ * Overrun is special, since it's reported
+ * immediately, and doesn't affect the current
+ * character
+ */
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ }
+ if (ch != 0)
+ tty_flip_buffer_push(tty);
+
+ return;
+}
+
+
+static void amazonasc_tx_chars(struct uart_port *port)
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31))
+ struct circ_buf *xmit = &port->state->xmit;
+#else
+ struct circ_buf *xmit = &port->info->xmit;
+#endif
+
+ if (uart_tx_stopped(port)) {
+ amazonasc_stop_tx(port);
+ return;
+ }
+
+ while (((amazon_readl(AMAZON_ASC_FSTAT) & ASCFSTAT_TXFFLMASK)
+ >> ASCFSTAT_TXFFLOFF) != AMAZONASC_TXFIFO_FULL)
+ {
+ if (port->x_char) {
+ amazon_writel(port->x_char, AMAZON_ASC_TBUF);
+ port->icount.tx++;
+ port->x_char = 0;
+ continue;
+ }
+
+ if (uart_circ_empty(xmit))
+ break;
+
+ amazon_writel(xmit->buf[xmit->tail], AMAZON_ASC_TBUF);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static irqreturn_t amazonasc_tx_int(int irq, void *port)
+{
+ amazon_writel(ASC_IRNCR_TIR, AMAZON_ASC_IRNCR1);
+ amazonasc_start_tx(port);
+
+ /* clear any pending interrupts */
+ amazon_writel_masked(AMAZON_ASC_WHBCON,
+ (ASCWHBCON_CLRPE | ASCWHBCON_CLRFE | ASCWHBCON_CLROE),
+ (ASCWHBCON_CLRPE | ASCWHBCON_CLRFE | ASCWHBCON_CLROE));
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t amazonasc_er_int(int irq, void *port)
+{
+ /* clear any pending interrupts */
+ amazon_writel_masked(AMAZON_ASC_WHBCON,
+ (ASCWHBCON_CLRPE | ASCWHBCON_CLRFE | ASCWHBCON_CLROE),
+ (ASCWHBCON_CLRPE | ASCWHBCON_CLRFE | ASCWHBCON_CLROE));
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t amazonasc_rx_int(int irq, void *port)
+{
+ amazon_writel(ASC_IRNCR_RIR, AMAZON_ASC_IRNCR1);
+ amazonasc_rx_chars((struct uart_port *) port);
+ return IRQ_HANDLED;
+}
+
+static u_int amazonasc_tx_empty(struct uart_port *port)
+{
+ int status;
+
+ /*
+ * FSTAT tells exactly how many bytes are in the FIFO.
+ * The question is whether we really need to wait for all
+ * 16 bytes to be transmitted before reporting that the
+ * transmitter is empty.
+ */
+ status = amazon_readl(AMAZON_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
+ return status ? 0 : TIOCSER_TEMT;
+}
+
+static u_int amazonasc_get_mctrl(struct uart_port *port)
+{
+ /* no modem control signals - the readme says to pretend all are set */
+ return TIOCM_CTS|TIOCM_CAR|TIOCM_DSR;
+}
+
+static void amazonasc_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+ /* no modem control - just return */
+ return;
+}
+
+static void amazonasc_break_ctl(struct uart_port *port, int break_state)
+{
+ /* no way to send a break */
+ return;
+}
+
+static int amazonasc_startup(struct uart_port *port)
+{
+ unsigned int con = 0;
+ unsigned long flags;
+ int retval;
+
+ /* this assumes: CON.BRS = CON.FDE = 0 */
+ if (uartclk == 0)
+ uartclk = amazon_get_fpi_hz();
+
+ amazonasc_ports[0].uartclk = uartclk;
+
+ local_irq_save(flags);
+
+ /* this setup was probably already done in u-boot */
+ /* ASC and GPIO Port 1 bits 3 and 4 share the same pins
+ * P1.3 (RX) in, Alternate 10
+ * P1.4 (TX) in, Alternate 10
+ */
+ amazon_writel_masked(AMAZON_GPIO_P1_DIR, 0x18, 0x10); //P1.4 output, P1.3 input
+ amazon_writel_masked(AMAZON_GPIO_P1_ALTSEL0, 0x18, 0x18); //ALTSETL0 11
+ amazon_writel_masked(AMAZON_GPIO_P1_ALTSEL1, 0x18, 0); //ALTSETL1 00
+ amazon_writel_masked(AMAZON_GPIO_P1_OD, 0x18, 0x10);
+
+ /* set up the CLC */
+ amazon_writel_masked(AMAZON_ASC_CLC, AMAZON_ASC_CLC_DISS, 0);
+ amazon_writel_masked(AMAZON_ASC_CLC, ASCCLC_RMCMASK, 1 << ASCCLC_RMCOFFSET);
+
+ /* asynchronous mode */
+ con = ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_OEN | ASCCON_PEN;
+
+ /* choose the line - there's only one */
+ amazon_writel(0, AMAZON_ASC_PISEL);
+ amazon_writel(((AMAZONASC_TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) | ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
+ AMAZON_ASC_TXFCON);
+ amazon_writel(((AMAZONASC_RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK) | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
+ AMAZON_ASC_RXFCON);
+ wmb();
+
+ amazon_writel_masked(AMAZON_ASC_CON, con, con);
+
+ retval = request_irq(AMAZONASC_RIR, amazonasc_rx_int, 0, "asc_rx", port);
+ if (retval){
+ printk("failed to request amazonasc_rx_int\n");
+ return retval;
+ }
+ retval = request_irq(AMAZONASC_TIR, amazonasc_tx_int, 0, "asc_tx", port);
+ if (retval){
+ printk("failed to request amazonasc_tx_int\n");
+ goto err1;
+ }
+
+ retval = request_irq(AMAZONASC_EIR, amazonasc_er_int, 0, "asc_er", port);
+ if (retval){
+ printk("failed to request amazonasc_er_int\n");
+ goto err2;
+ }
+
+ local_irq_restore(flags);
+ return 0;
+
+err2:
+ free_irq(AMAZONASC_TIR, port);
+
+err1:
+ free_irq(AMAZONASC_RIR, port);
+ local_irq_restore(flags);
+ return retval;
+}
+
+static void amazonasc_shutdown(struct uart_port *port)
+{
+ free_irq(AMAZONASC_RIR, port);
+ free_irq(AMAZONASC_TIR, port);
+ free_irq(AMAZONASC_EIR, port);
+ /*
+ * disable the baudrate generator to disable the ASC
+ */
+ amazon_writel(0, AMAZON_ASC_CON);
+
+ /* flush and then disable the fifos */
+ amazon_writel_masked(AMAZON_ASC_RXFCON, ASCRXFCON_RXFFLU, ASCRXFCON_RXFFLU);
+ amazon_writel_masked(AMAZON_ASC_RXFCON, ASCRXFCON_RXFEN, 0);
+ amazon_writel_masked(AMAZON_ASC_TXFCON, ASCTXFCON_TXFFLU, ASCTXFCON_TXFFLU);
+ amazon_writel_masked(AMAZON_ASC_TXFCON, ASCTXFCON_TXFEN, 0);
+}
+
+static void amazonasc_set_termios(struct uart_port *port, struct ktermios *new, struct ktermios *old)
+{
+ unsigned int cflag;
+ unsigned int iflag;
+ unsigned int baud, quot;
+ unsigned int con = 0;
+ unsigned long flags;
+
+ cflag = new->c_cflag;
+ iflag = new->c_iflag;
+
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ /* 7 bits are always with parity */
+ case CS7: con = ASCCON_M_7ASYNCPAR; break;
+ /* the ASC only suports 7 and 8 bits */
+ case CS5:
+ case CS6:
+ default:
+ if (cflag & PARENB)
+ con = ASCCON_M_8ASYNCPAR;
+ else
+ con = ASCCON_M_8ASYNC;
+ break;
+ }
+ if (cflag & CSTOPB)
+ con |= ASCCON_STP;
+ if (cflag & PARENB) {
+ if (!(cflag & PARODD))
+ con &= ~ASCCON_ODD;
+ else
+ con |= ASCCON_ODD;
+ }
+
+ port->read_status_mask = ASCCON_OE;
+ if (iflag & INPCK)
+ port->read_status_mask |= ASCCON_FE | ASCCON_PE;
+
+ port->ignore_status_mask = 0;
+ if (iflag & IGNPAR)
+ port->ignore_status_mask |= ASCCON_FE | ASCCON_PE;
+
+ if (iflag & IGNBRK) {
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (iflag & IGNPAR)
+ port->ignore_status_mask |= ASCCON_OE;
+ }
+
+ /*
+ * Ignore all characters if CREAD is not set.
+ */
+ if ((cflag & CREAD) == 0)
+ port->ignore_status_mask |= UART_DUMMY_UER_RX;
+
+ /* set error signals - framing, parity and overrun */
+ con |= ASCCON_FEN;
+ con |= ASCCON_OEN;
+ con |= ASCCON_PEN;
+ /* enable the receiver */
+ con |= ASCCON_REN;
+
+ /* block the IRQs */
+ local_irq_save(flags);
+
+ /* set up CON */
+ amazon_writel(con, AMAZON_ASC_CON);
+
+ /* Set baud rate - take a divider of 2 into account */
+ baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
+ quot = uart_get_divisor(port, baud);
+ quot = quot/2 - 1;
+
+ /* the next 3 probably already happened when we set CON above */
+ /* disable the baudrate generator */
+ amazon_writel_masked(AMAZON_ASC_CON, ASCCON_R, 0);
+ /* make sure the fractional divider is off */
+ amazon_writel_masked(AMAZON_ASC_CON, ASCCON_FDE, 0);
+ /* set up to use divisor of 2 */
+ amazon_writel_masked(AMAZON_ASC_CON, ASCCON_BRS, 0);
+ /* now we can write the new baudrate into the register */
+ amazon_writel(quot, AMAZON_ASC_BTR);
+ /* turn the baudrate generator back on */
+ amazon_writel_masked(AMAZON_ASC_CON, ASCCON_R, ASCCON_R);
+
+ local_irq_restore(flags);
+}
+
+static const char *amazonasc_type(struct uart_port *port)
+{
+ return port->type == PORT_AMAZONASC ? "AMAZONASC" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void amazonasc_release_port(struct uart_port *port)
+{
+ return;
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int amazonasc_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void amazonasc_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_AMAZONASC;
+ amazonasc_request_port(port);
+ }
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int amazonasc_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ int ret = 0;
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMAZONASC)
+ ret = -EINVAL;
+ if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ ret = -EINVAL;
+ if (ser->baud_base < 9600)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops amazonasc_pops = {
+ .tx_empty = amazonasc_tx_empty,
+ .set_mctrl = amazonasc_set_mctrl,
+ .get_mctrl = amazonasc_get_mctrl,
+ .stop_tx = amazonasc_stop_tx,
+ .start_tx = amazonasc_start_tx,
+ .stop_rx = amazonasc_stop_rx,
+ .enable_ms = amazonasc_enable_ms,
+ .break_ctl = amazonasc_break_ctl,
+ .startup = amazonasc_startup,
+ .shutdown = amazonasc_shutdown,
+ .set_termios = amazonasc_set_termios,
+ .type = amazonasc_type,
+ .release_port = amazonasc_release_port,
+ .request_port = amazonasc_request_port,
+ .config_port = amazonasc_config_port,
+ .verify_port = amazonasc_verify_port,
+};
+
+static struct uart_port amazonasc_ports[UART_NR] = {
+ {
+ membase: (void *)AMAZON_ASC,
+ mapbase: AMAZON_ASC,
+ iotype: SERIAL_IO_MEM,
+ irq: AMAZONASC_RIR, /* RIR */
+ uartclk: 0, /* filled in dynamically */
+ fifosize: 16,
+ unused: { AMAZONASC_TIR, AMAZONASC_EIR}, /* xmit/error/xmit-buffer-empty IRQ */
+ type: PORT_AMAZONASC,
+ ops: &amazonasc_pops,
+ flags: ASYNC_BOOT_AUTOCONF,
+ },
+};
+
+static void amazonasc_console_write(struct console *co, const char *s, u_int count)
+{
+ int i, fifocnt;
+ unsigned long flags;
+ local_irq_save(flags);
+ for (i = 0; i < count;)
+ {
+ /* wait until the FIFO is not full */
+ do
+ {
+ fifocnt = (amazon_readl(AMAZON_ASC_FSTAT) & ASCFSTAT_TXFFLMASK)
+ >> ASCFSTAT_TXFFLOFF;
+ } while (fifocnt == AMAZONASC_TXFIFO_FULL);
+ if (s[i] == '\0')
+ {
+ break;
+ }
+ if (s[i] == '\n')
+ {
+ amazon_writel('\r', AMAZON_ASC_TBUF);
+ do
+ {
+ fifocnt = (amazon_readl(AMAZON_ASC_FSTAT) &
+ ASCFSTAT_TXFFLMASK) >> ASCFSTAT_TXFFLOFF;
+ } while (fifocnt == AMAZONASC_TXFIFO_FULL);
+ }
+ amazon_writel(s[i], AMAZON_ASC_TBUF);
+ i++;
+ }
+
+ local_irq_restore(flags);
+}
+
+static void __init
+amazonasc_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
+{
+ u_int lcr_h;
+
+ lcr_h = amazon_readl(AMAZON_ASC_CON);
+ /* do this only if the ASC is turned on */
+ if (lcr_h & ASCCON_R) {
+ u_int quot, div, fdiv, frac;
+
+ *parity = 'n';
+ if ((lcr_h & ASCCON_MODEMASK) == ASCCON_M_7ASYNCPAR ||
+ (lcr_h & ASCCON_MODEMASK) == ASCCON_M_8ASYNCPAR) {
+ if (lcr_h & ASCCON_ODD)
+ *parity = 'o';
+ else
+ *parity = 'e';
+ }
+
+ if ((lcr_h & ASCCON_MODEMASK) == ASCCON_M_7ASYNCPAR)
+ *bits = 7;
+ else
+ *bits = 8;
+
+ quot = amazon_readl(AMAZON_ASC_BTR) + 1;
+
+ /* this gets hairy if the fractional divider is used */
+ if (lcr_h & ASCCON_FDE)
+ {
+ div = 1;
+ fdiv = amazon_readl(AMAZON_ASC_FDV);
+ if (fdiv == 0)
+ fdiv = 512;
+ frac = 512;
+ }
+ else
+ {
+ div = lcr_h & ASCCON_BRS ? 3 : 2;
+ fdiv = frac = 1;
+ }
+ /*
+ * This doesn't work exactly because we use integer
+ * math to calculate baud which results in rounding
+ * errors when we try to go from quot -> baud !!
+ * Try to make this work for both the fractional divider
+ * and the simple divider. Also try to avoid rounding
+ * errors using integer math.
+ */
+
+ *baud = frac * (port->uartclk / (div * 512 * 16 * quot));
+ if (*baud > 1100 && *baud < 2400)
+ *baud = 1200;
+ if (*baud > 2300 && *baud < 4800)
+ *baud = 2400;
+ if (*baud > 4700 && *baud < 9600)
+ *baud = 4800;
+ if (*baud > 9500 && *baud < 19200)
+ *baud = 9600;
+ if (*baud > 19000 && *baud < 38400)
+ *baud = 19200;
+ if (*baud > 38400 && *baud < 57600)
+ *baud = 38400;
+ if (*baud > 57600 && *baud < 115200)
+ *baud = 57600;
+ if (*baud > 115200 && *baud < 230400)
+ *baud = 115200;
+ }
+}
+
+static int __init amazonasc_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ /* this assumes: CON.BRS = CON.FDE = 0 */
+ if (uartclk == 0)
+ uartclk = amazon_get_fpi_hz();
+ co->index = 0;
+ port = &amazonasc_ports[0];
+ amazonasc_ports[0].uartclk = uartclk;
+ amazonasc_ports[0].type = PORT_AMAZONASC;
+
+ if (options){
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ }
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver amazonasc_reg;
+static struct console amazonasc_console = {
+ name: "ttyS",
+ write: amazonasc_console_write,
+ device: uart_console_device,
+ setup: amazonasc_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+ data: &amazonasc_reg,
+};
+
+static struct uart_driver amazonasc_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "serial",
+ .dev_name = "ttyS",
+ .major = TTY_MAJOR,
+ .minor = 64,
+ .nr = UART_NR,
+ .cons = &amazonasc_console,
+};
+
+static int amazon_asc_probe(struct platform_device *dev)
+{
+ unsigned char res;
+ uart_register_driver(&amazonasc_reg);
+ res = uart_add_one_port(&amazonasc_reg, &amazonasc_ports[0]);
+ return res;
+}
+
+static int amazon_asc_remove(struct platform_device *dev)
+{
+ uart_unregister_driver(&amazonasc_reg);
+ return 0;
+}
+
+static struct platform_driver amazon_asc_driver = {
+ .probe = amazon_asc_probe,
+ .remove = amazon_asc_remove,
+ .driver = {
+ .name = "amazon_asc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init amazon_asc_init(void)
+{
+ int ret = platform_driver_register(&amazon_asc_driver);
+ if (ret)
+ printk(KERN_WARNING "amazon_asc: error registering platfom driver!\n");
+ return ret;
+}
+
+static void __exit amazon_asc_cleanup(void)
+{
+ platform_driver_unregister(&amazon_asc_driver);
+}
+
+module_init(amazon_asc_init);
+module_exit(amazon_asc_cleanup);
+
+MODULE_AUTHOR("Gary Jennejohn, Felix Fietkau, John Crispin");
+MODULE_DESCRIPTION("MIPS AMAZONASC serial port driver");
+MODULE_LICENSE("GPL");
+
diff --git a/target/linux/amazon/files/drivers/watchdog/amazon_wdt.c b/target/linux/amazon/files/drivers/watchdog/amazon_wdt.c
new file mode 100644
index 000000000..b18296b79
--- /dev/null
+++ b/target/linux/amazon/files/drivers/watchdog/amazon_wdt.c
@@ -0,0 +1,277 @@
+/*
+ * 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
+ *
+ * Copyright 2004 Wu Qi Ming <gokimi@msn.com>
+ * Copyright (C) 2007 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/version.h>
+#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 <linux/platform_device.h>
+#include <asm/amazon/amazon.h>
+#include <asm/amazon/amazon_wdt.h>
+
+#define DRV_NAME "AMAZON WDT:"
+
+#undef AMAZON_WDT_DEBUG
+
+static int amazon_wdt_isopen = 0;
+
+#ifdef AMAZON_WDT_DEBUG
+static struct proc_dir_entry* amazon_wdt_dir;
+#endif
+
+int wdt_enable(int timeout)
+{
+ u32 hard_psw, ffpi;
+ int reload_value, divider = 1;
+
+ ffpi = amazon_get_fpi_hz();
+
+ reload_value = 65536 - timeout * ffpi / 256;
+
+ if (reload_value < 0) {
+ divider = 0;
+ reload_value = 65536 - timeout * ffpi / 16384;
+ }
+
+ if (reload_value < 0){
+ printk(KERN_INFO DRV_NAME "timeout too large %d\n", timeout);
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO DRV_NAME "timeout:%d reload_value: %8x\n", timeout, reload_value);
+
+ hard_psw = (amazon_readl(AMAZON_WDT_CON0) & 0xffffff01) +
+ (amazon_readl(AMAZON_WDT_CON1) & 0xc) + 0xf0;
+ amazon_writel(hard_psw, AMAZON_WDT_CON0);
+ wmb();
+
+ amazon_writel((hard_psw & 0xff00) + (reload_value << 16) + 0xf2, AMAZON_WDT_CON0);
+ wmb();
+
+ amazon_writel(divider << 2, AMAZON_WDT_CON1);
+ wmb();
+
+ hard_psw = (amazon_readl(AMAZON_WDT_CON0) & 0xffffff01) +
+ (amazon_readl(AMAZON_WDT_CON1) & 0xc) + 0xf0;
+ amazon_writel(hard_psw, AMAZON_WDT_CON0);
+ wmb();
+
+ amazon_writel_masked(AMAZON_WDT_CON0, 0xff, 0xf3);
+ wmb();
+ return 0;
+}
+
+void wdt_disable(void)
+{
+ u32 hard_psw = 0;
+
+ hard_psw = (amazon_readl(AMAZON_WDT_CON0) & 0xffffff01) +
+ (amazon_readl(AMAZON_WDT_CON1) & 0xc) + 0xf0;
+ amazon_writel(hard_psw, AMAZON_WDT_CON0);
+ wmb();
+
+ amazon_writel_masked(AMAZON_WDT_CON0, 0xff, 0xf2);
+ wmb();
+
+ amazon_writel_masked(AMAZON_WDT_CON1, 0x8, 0x8);
+ wmb();
+
+ hard_psw=(amazon_readl(AMAZON_WDT_CON0) & 0xffffff01) +
+ (amazon_readl(AMAZON_WDT_CON1) & 0xc) + 0xf0;
+ amazon_writel(hard_psw, AMAZON_WDT_CON0);
+ wmb();
+
+ amazon_writel_masked(AMAZON_WDT_CON0, 0xff, 0xf3);
+ wmb();
+
+ return;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+#else
+static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+#endif
+{
+ int result=0;
+ static int timeout=-1;
+
+ switch(cmd){
+ case AMAZON_WDT_IOC_START:
+ printk(KERN_INFO DRV_NAME "enable watch dog timer!\n");
+ if (copy_from_user((void*)&timeout, (void*)arg, sizeof (int))) {
+ printk(KERN_INFO DRV_NAME "invalid argument\n");
+ result=-EINVAL;
+ } else if ((result = wdt_enable(timeout)) < 0) {
+ timeout = -1;
+ }
+ break;
+
+ case AMAZON_WDT_IOC_STOP:
+ printk(KERN_INFO DRV_NAME "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);
+ }
+ break;
+
+ default:
+ result=-EINVAL;
+ break;
+ }
+ 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)
+{
+ if (amazon_wdt_isopen == 1)
+ return -EBUSY;
+
+ amazon_wdt_isopen = 1;
+ printk(KERN_INFO DRV_NAME "opened\n");
+ return 0;
+}
+
+static int wdt_release(struct inode *inode, struct file *file)
+{
+ amazon_wdt_isopen = 0;
+ printk(KERN_INFO DRV_NAME "closed\n");
+ return 0;
+}
+
+#ifdef AMAZON_WDT_DEBUG
+int wdt_register_proc_read(char *buf, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ int len=0;
+ 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;
+}
+#endif
+
+static struct file_operations wdt_fops = {
+ read: wdt_read,
+ write: wdt_write,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ unlocked_ioctl: wdt_ioctl,
+#else
+ ioctl: wdt_ioctl,
+#endif
+ open: wdt_open,
+ release: wdt_release,
+};
+
+static int amazon_wdt_probe(struct platform_device *dev)
+{
+ int result = result = register_chrdev(0, "watchdog", &wdt_fops);
+
+ if (result < 0) {
+ printk(KERN_INFO DRV_NAME "cannot register device\n");
+ return result;
+ }
+
+#ifdef AMAZON_WDT_DEBUG
+ amazon_wdt_dir=proc_mkdir("amazon_wdt",NULL);
+ create_proc_read_entry("wdt_register", 0, amazon_wdt_dir,
+ wdt_register_proc_read, NULL);
+#endif
+
+ amazon_wdt_isopen=0;
+ printk(KERN_INFO DRV_NAME "driver loaded but inactive\n");
+ return 0;
+}
+
+static int amazon_wdt_remove(struct platform_device *dev)
+{
+ unregister_chrdev(0, "watchdog");
+#ifdef AMAZON_WDT_DEBUG
+ remove_proc_entry("wdt_register", amazon_wdt_dir);
+ remove_proc_entry("amazon_wdt", NULL);
+#endif
+ printk(KERN_INFO DRV_NAME "unregistered\n");
+ return 0;
+}
+
+static struct platform_driver amazon_wdt_driver = {
+ .probe = amazon_wdt_probe,
+ .remove = amazon_wdt_remove,
+ .driver = {
+ .name = "amazon_wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init amazon_wdt_init(void)
+{
+ int ret = platform_driver_register(&amazon_wdt_driver);
+ if (ret)
+ printk(KERN_WARNING "amazon_wdt: error registering platfom driver!\n");
+ return ret;
+}
+
+static void __exit amazon_wdt_exit(void)
+{
+ platform_driver_unregister(&amazon_wdt_driver);
+}
+
+module_init(amazon_wdt_init);
+module_exit(amazon_wdt_exit);
+
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Infineon / John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("AMAZON WDT driver");
+