/*
 * LEGO® MINDSTORMS EV3
 *
 * Copyright (C) 2010-2013 The LEGO Group
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */


/*! \page IicModule IIC Module
 *
 *  <hr size="1"/>
 *
 *  Manages communication with intelligent IIC devices on an input port.\n
 *
 *-  \subpage IicDriver
 *-  \subpage IicModuleMemory
 *-  \subpage IicModuleResources
 *
 */


/*! \page IicDriver IIC Device Controller
 *
 *  <hr size="1"/>
 *
 *  Manages the sequence necessary when adding a IIC devices to an input port.\n
 *
 * \n
 *
 *  The IIC Device Controller gets information from the DCM driver \ref DcmDriver "Device Detection Manager Driver"
 *  about the port state and when the DCM driver detects a IIC device on the port the sequence below the following defines
 *  is started inside the IIC Device Controller.
 *
 * \verbatim
*/

/*!
\endverbatim
 *
 *  \n
 */



#if 0 // unused in EV3RT -- ertl-liyixiao

#ifndef PCASM
#include  <asm/types.h>
#endif

#include  "../../lms2012/source/lms2012.h"
#include  "../../lms2012/source/am1808.h"

#endif

#define   HW_ID_SUPPORT

#ifndef    DISABLE_FIQ_IIC
#include "d_iic.h"
#endif

#ifdef    DEBUG
#define   DEBUG_D_IIC
#endif
#ifdef    DEBUG_D_IIC
#define   DEBUG_IIC_WRITE
#define   HIGHDEBUG
#define   DEBUG_TRACE_MODE_CHANGE
#endif



#define   MODULE_NAME                   "iic_module"
#define   DEVICE1_NAME                  IIC_DEVICE

static    int  ModuleInit(void);

#if 0 // unused in EV3RT -- ertl-liyixiao
static    void ModuleExit(void);
#endif

#define   __USE_POSIX

#include  <linux/kernel.h>
#include  <linux/fs.h>

//#include  <linux/sched.h>


#ifndef   PCASM
#include  <linux/circ_buf.h>
#include  <linux/hrtimer.h>

#include  <linux/mm.h>
#include  <linux/hrtimer.h>

#include  <linux/init.h>
#include  <linux/uaccess.h>
//#include  <linux/debugfs.h>

//#include  <linux/ioport.h>
//#include  <asm/gpio.h>
#include  <asm/io.h>
#include  <linux/module.h>
//#include  <linux/miscdevice.h>
//#include  <asm/uaccess.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("The LEGO Group");
MODULE_DESCRIPTION(MODULE_NAME);
//MODULE_SUPPORTED_DEVICE(DEVICE1_NAME);

module_init(ModuleInit);
module_exit(ModuleExit);

#else
// Keep Eclipse happy
#endif


#define   NO_OF_IIC_PORTS             INPUTS


#ifndef    DISABLE_FIQ_IIC

extern    INPIN IicPortPin[NO_OF_IIC_PORTS][IIC_PORT_PINS];

#else

enum      IicPortPins
{
  IIC_PORT_BUFFER_CTRL,
  IIC_PORT_CLOCK,
  IIC_PORT_DATA,
  IIC_PORT_PINS,
};

INPIN     IicPortPin[NO_OF_IIC_PORTS][IIC_PORT_PINS];

#endif

#if 0 // unused in EV3RT -- ertl-liyixiao
int       Hw = 0;
#endif

/*! \page IicModuleResources Gpios and Resources used for Module
 *
 *  Describes use of gpio and resources\n
 *
 *  \verbatim
 */


INPIN     EP2_IicPortPin[][IIC_PORT_PINS] =
{
  { // Input port 1
    { GP8_11 , NULL, 0 }, // Buffer disable
    { GP1_0  , NULL, 0 }, // Pin 5  - Digital input   // CLOCK
    { GP0_15 , NULL, 0 }, // Pin 6  - Digital output  // DATA
  },
  { // Input port 2
    { GP8_14 , NULL, 0 }, // Buffer disable
    { GP8_3  , NULL, 0 }, // Pin 5  - Digital input   // CLOCK
    { GP0_13 , NULL, 0 }, // Pin 6  - Digital output  // DATA
  },
  { // Input port 3
    { GP7_9  , NULL, 0 }, // Buffer disable
    { GP1_12 , NULL, 0 }, // Pin 5  - Digital input   // CLOCK
    { GP1_14 , NULL, 0 }, // Pin 6  - Digital output  // DATA
  },
  { // Input port 4
    { GP7_10 , NULL, 0 }, // Buffer disable
    { GP1_11 , NULL, 0 }, // Pin 5  - Digital input   // CLOCK
    { GP1_15 , NULL, 0 }, // Pin 6  - Digital output  // DATA
  },
};


INPIN     FINALB_IicPortPin[][IIC_PORT_PINS] =
{
  { // Input port 1
    { GP8_11 , NULL, 0 }, // Buffer disable
    { GP1_0  , NULL, 0 }, // Pin 5  - Digital input   // CLOCK
    { GP0_15 , NULL, 0 }, // Pin 6  - Digital output  // DATA
  },
  { // Input port 2
    { GP8_14 , NULL, 0 }, // Buffer disable
    { GP8_3  , NULL, 0 }, // Pin 5  - Digital input   // CLOCK
    { GP0_13 , NULL, 0 }, // Pin 6  - Digital output  // DATA
  },
  { // Input port 3
    { GP7_9  , NULL, 0 }, // Buffer disable
    { GP1_12 , NULL, 0 }, // Pin 5  - Digital input   // CLOCK
    { GP1_14 , NULL, 0 }, // Pin 6  - Digital output  // DATA
  },
  { // Input port 4
    { GP7_10 , NULL, 0 }, // Buffer disable
    { GP1_11 , NULL, 0 }, // Pin 5  - Digital input   // CLOCK
    { GP1_15 , NULL, 0 }, // Pin 6  - Digital output  // DATA
  },
};


INPIN     FINAL_IicPortPin[][IIC_PORT_PINS] =
{
  { // Input port 1
    { GP8_11 , NULL, 0 }, // Buffer disable
    { GP0_2  , NULL, 0 }, // Pin 5  - Digital input   // CLOCK
    { GP0_15 , NULL, 0 }, // Pin 6  - Digital output  // DATA
  },
  { // Input port 2
    { GP8_14 , NULL, 0 }, // Buffer disable
    { GP0_14 , NULL, 0 }, // Pin 5  - Digital input   // CLOCK
    { GP0_13 , NULL, 0 }, // Pin 6  - Digital output  // DATA
  },
  { // Input port 3
    { GP7_9  , NULL, 0 }, // Buffer disable
    { GP0_12 , NULL, 0 }, // Pin 5  - Digital input   // CLOCK
    { GP1_14 , NULL, 0 }, // Pin 6  - Digital output  // DATA
  },
  { // Input port 4
    { GP7_10 , NULL, 0 }, // Buffer disable
    { GP1_13 , NULL, 0 }, // Pin 5  - Digital input   // CLOCK
    { GP1_15 , NULL, 0 }, // Pin 6  - Digital output  // DATA
  },
};



/*  \endverbatim
 *  \n
 */


#define   PUDisable                     iowrite32(ioread32(da8xx_syscfg1_base + 0x0C) & ~0xFFFFFFFF,da8xx_syscfg1_base + 0x0C)

INPIN     *pIicPortPin[] =
{
  [FINAL]     =   (INPIN*)&FINAL_IicPortPin[0],    //  FINAL   platform
  [FINALB]    =   (INPIN*)&FINALB_IicPortPin[0],   //  FINALB  platform
  [EP2]       =   (INPIN*)&EP2_IicPortPin[0],      //  EP2     platform
};


//*****************************************************************************

#if 0 // unused in EV3RT -- ertl-liyixiao
static    void      __iomem *GpioBase;

void      SetGpio(int Pin)
{
  int     Tmp = 0;
  void    __iomem *Reg;

  if (Pin >= 0)
  {
    // unlock
    REGUnlock;

    while ((MuxRegMap[Tmp].Pin != -1) && (MuxRegMap[Tmp].Pin != Pin))
    {
      Tmp++;
    }
    if (MuxRegMap[Tmp].Pin == Pin)
    {
      Reg   =  da8xx_syscfg0_base + 0x120 + (MuxRegMap[Tmp].MuxReg << 2);

      *(u32*)Reg &=  MuxRegMap[Tmp].Mask;
      *(u32*)Reg |=  MuxRegMap[Tmp].Mode;
  #ifdef DEBUG
      printk("    GP%d_%-2d  0x%08X and 0x%08X or 0x%08X\n",(Pin >> 4),(Pin & 0x0F),(u32)Reg, MuxRegMap[Tmp].Mask, MuxRegMap[Tmp].Mode);
  #endif
    }
    else
    {
      printk("*   GP%d_%-2d  ********* ERROR not found *********\n",(Pin >> 4),(Pin & 0x0F));
    }
    // lock
    REGLock;
  }
}
#endif

void      InitGpio(void)
{
  int     Port;
  int     Pin;


  memcpy(IicPortPin,pIicPortPin[Hw],sizeof(EP2_IicPortPin));

#ifdef DEBUG
  printk("\n\n");
  printk("FINALB_IicPortPin            = %p\n",FINALB_IicPortPin);
  printk("pIicPortPin[Hw]              = %p\n",pIicPortPin[Hw]);
  printk("sizeof(INPIN)                = %d\n",sizeof(INPIN));
  printk("sizeof(EP2_IicPortPin)       = %d\n",sizeof(EP2_IicPortPin));

#endif

  if (memcmp((const void*)IicPortPin,(const void*)pIicPortPin[Hw],sizeof(EP2_IicPortPin)) != 0)
  {
    printk("%s IicPortPin tabel broken!\n",MODULE_NAME);
  }

  for (Port = 0;Port < NO_OF_IIC_PORTS;Port++)
  {
#ifdef DEBUG
    printk("  Iic   port %d\n",Port + 1);
#endif
    for (Pin = 0;Pin < IIC_PORT_PINS;Pin++)
    {
      if ((Port != DEBUG_UART) || (Pin != IIC_PORT_CLOCK))
      {
        if (IicPortPin[Port][Pin].Pin >= 0)
        {
          IicPortPin[Port][Pin].pGpio  =  (struct gpio_controller *__iomem)(GpioBase + ((IicPortPin[Port][Pin].Pin >> 5) * 0x28) + 0x10);
          IicPortPin[Port][Pin].Mask   =  (1 << (IicPortPin[Port][Pin].Pin & 0x1F));

          SetGpio(IicPortPin[Port][Pin].Pin);
        }
      }
    }
  }

  // unlock
  REGUnlock;

  // Disable pull up/down
  PUDisable;

  // lock
  REGLock;
}


#ifdef    DISABLE_FIQ_IIC
#define   PINFloat(port,pin)            {\
                                          (*IicPortPin[port][pin].pGpio).dir |=  IicPortPin[port][pin].Mask;\
                                        }


#define   PINRead(port,pin)             ((*IicPortPin[port][pin].pGpio).in_data & IicPortPin[port][pin].Mask)


#define   PINHigh(port,pin)             {\
                                          (*IicPortPin[port][pin].pGpio).set_data  =  IicPortPin[port][pin].Mask;\
                                          (*IicPortPin[port][pin].pGpio).dir      &= ~IicPortPin[port][pin].Mask;\
                                        }

#define   PINLow(port,pin)              {\
                                          (*IicPortPin[port][pin].pGpio).clr_data  =  IicPortPin[port][pin].Mask;\
                                          (*IicPortPin[port][pin].pGpio).dir      &= ~IicPortPin[port][pin].Mask;\
                                        }
#endif


typedef struct
{
  RESULT  Result;
  UWORD   Timer;
  UWORD   Time;
  UBYTE   Initialised;
  UBYTE   ChangeMode;
  UBYTE   State;
  UBYTE   OldState;
  UBYTE   SubState;
  UBYTE   Repeat;
  UBYTE   Cmd;
  UBYTE   Mode;
  UBYTE   Addr;
  UBYTE   Retries;
  SBYTE   Name[TYPE_NAME_LENGTH + 1];
  UBYTE   Reverse;
  UBYTE   InLength;
  UBYTE   InPointer;
  UBYTE   OutLength;
  UBYTE   OutPointer;
  UBYTE   InBuffer[IIC_DATA_LENGTH];
  UBYTE   OutBuffer[IIC_DATA_LENGTH];
}
IICPORT;


IICPORT  IicPortDefault =
{
  STOP,                     // Result
  0,                        // Timer
  0,                        // Time
  0,                        // Initialised
  0,                        // ChangeMode
  0,                        // State
  -1,                       // OldState
  0,                        // SubState
  0,                        // Repeat
  0,                        // Cmd
  0,                        // Mode
  1,                        // Addr
  3,                        // Retries
  "",                       // Name
  0,                        // Reverse
  0,                        // InLength
  0,                        // InPointer
  0,                        // OutLength
  0,                        // OutPointer
};


#ifdef DEBUG_IIC_WRITE

#define   IICBUFFERSIZE    250
static    char IicBuffer[IICBUFFERSIZE];

#define   LOGPOOLSIZE       100000
ULONG     LogPointer = 0;
ULONG     LogOutPointer  =  0;
char      LogPool[LOGPOOLSIZE];

void      IicWrite(char *pString)
{
  ULONG   Tmp;

  while (*pString)
  {
    LogPool[LogPointer]  =  *pString;

    Tmp  =  LogPointer;
    Tmp++;
    if (Tmp >= LOGPOOLSIZE)
    {
      Tmp  =  0;
    }
    if (Tmp != LogOutPointer)
    {
      LogPointer  =  Tmp;
      pString++;

    }
    else
    {
      pString++;
    }
  }
}
#endif


UBYTE     IicConfigured[INPUTS];
IICPORT   IicPort[INPUTS];

static    IIC  IicDefault;
static    IIC *pIic   =  &IicDefault;

// FIQ Interface **************************************************************

#ifndef   DISABLE_FIQ_IIC

#ifndef   PCASM
#include  <linux/circ_buf.h>
#include  <linux/delay.h>
#endif

extern struct IIC_control_t IicCtrl;
extern void iic_fiq_start_transfer(unsigned int time, bool fiq_nirq);

#endif

#if 0 // unused in EV3RT -- ertl-liyixiao

static void IicPortDisable(UBYTE Port)
{
#ifndef   DISABLE_FIQ_IIC

  IicCtrl.port_enabled &= ~(1 << Port);

  if (Port != DEBUG_UART)
  {
    PINHigh(Port,IIC_PORT_BUFFER_CTRL);
  }
  PINInput(Port,IIC_PORT_DATA);

#endif
}

#endif

static void IicPortEnable(UBYTE Port)
{
#ifndef   DISABLE_FIQ_IIC

  SetGpio(IicPortPin[Port][IIC_PORT_CLOCK].Pin);

  PINLow(Port,IIC_PORT_BUFFER_CTRL);
  PINHigh(Port,IIC_PORT_CLOCK);
  PINHigh(Port,IIC_PORT_DATA);
  PINOutput(Port,IIC_PORT_BUFFER_CTRL);
  PINOutput(Port,IIC_PORT_CLOCK);
  PINOutput(Port,IIC_PORT_DATA);

  IicCtrl.data_package[Port].clock_state = 1;

  IicCtrl.port_enabled |=  (1 << Port);

#endif
}

#if 0 // unused in EV3RT -- ertl-liyixiao

static UBYTE IicPortBusy(UBYTE Port)
{
  UBYTE   Result = 0;

#ifndef   DISABLE_FIQ_IIC

  if (IicCtrl.transfers_active)
  {
    Result  =  1;
  }

#endif

  return (Result);
}


static RESULT IicPortSend(UBYTE Port)
{
  RESULT  Result = OK;

#ifndef   DISABLE_FIQ_IIC
  DATA8   Tmp;

  IicCtrl.data_package[Port].addr             =  IicPort[Port].OutBuffer[0];

#if defined(DEBUG_I2C_SENSOR) || 1
  syslog(LOG_NOTICE,"    %d Send %02X   ",Port,IicPort[Port].OutBuffer[0]);
#ifdef HIGHDEBUG
  snprintf(IicBuffer,IICBUFFERSIZE,"    %d Send %02X   ",Port,IicPort[Port].OutBuffer[0]);
  IicWrite(IicBuffer);
#endif
#endif
  for (Tmp = 1;Tmp < IicPort[Port].OutLength;Tmp++)
  {
#if defined(DEBUG_I2C_SENSOR) || 1
	  syslog(LOG_NOTICE, "%02X ",IicPort[Port].OutBuffer[Tmp]);
#ifdef HIGHDEBUG
    snprintf(IicBuffer,IICBUFFERSIZE,"%02X ",IicPort[Port].OutBuffer[Tmp]);
    IicWrite(IicBuffer);
#endif
#endif
    IicCtrl.data_package[Port].data[Tmp - 1]  =  IicPort[Port].OutBuffer[Tmp];
  }
#ifdef HIGHDEBUG
  snprintf(IicBuffer,IICBUFFERSIZE,"\r\n");
  IicWrite(IicBuffer);
#endif
  IicCtrl.data_package[Port].write_length     =  IicPort[Port].OutLength - 1;
  IicCtrl.data_package[Port].read_length      =  IicPort[Port].InLength;
  IicCtrl.data_package[Port].port             =  Port;

  IicCtrl.data_package[Port].nacked           =  0;
  IicCtrl.data_package[Port].clock_state      =  1;
  IicCtrl.data_package[Port].transfer_state   =  TRANSFER_START;

  iic_fiq_start_transfer(50,1);

#endif

  return (Result);
}


static RESULT IicPortReceive(UBYTE Port,UBYTE *pTmpBuffer)
{
  RESULT  Result = BUSY;

#ifndef   DISABLE_FIQ_IIC
  DATA8   Tmp;

  if (IicCtrl.data_package[Port].transfer_state == TRANSFER_IDLE)
  {
#if defined(DEBUG_I2C_SENSOR) || 1
	  syslog(LOG_NOTICE, "    %d Receiving %d byte, nackd %d",Port,IicCtrl.data_package[Port].byte,IicCtrl.data_package[Port].nacked);
#endif
    memset((void*)pTmpBuffer,0,IIC_DATA_LENGTH);
#ifdef HIGHDEBUG
    snprintf(IicBuffer,IICBUFFERSIZE,"    %d Receiving   ",Port);
    IicWrite(IicBuffer);
#endif
    for (Tmp = 0;Tmp < IicPort[Port].InLength;Tmp++)
    {
#ifdef HIGHDEBUG
      snprintf(IicBuffer,IICBUFFERSIZE,"%02X ",IicCtrl.data_package[Port].data[Tmp]);
      IicWrite(IicBuffer);
#endif
      pTmpBuffer[Tmp]        =  IicCtrl.data_package[Port].data[Tmp];
    }
#ifdef HIGHDEBUG
      snprintf(IicBuffer,IICBUFFERSIZE,"\r\n");
      IicWrite(IicBuffer);
#endif

    if (!(IicCtrl.data_package[Port].nacked))
    {
      Result  =  OK;
    }
    else
    {
      Result  =  FAIL;
    }
  }

#endif

  return (Result);
}

#endif


// DEVICE1 ********************************************************************


enum      IIC_STATE
{
  IIC_IDLE, // 0
  IIC_INIT,
  IIC_RESTART,
  IIC_ENABLE,
  IIC_NXT_TEMP_START,
  IIC_NXT_TEMP_WRITE,
  IIC_NXT_TEMP_READ,
  IIC_MANUFACTURER_START,
  IIC_MANUFACTURER_WRITE,
  IIC_MANUFACTURER_READ,
  IIC_TYPE_START,
  IIC_TYPE_WRITE,
  IIC_TYPE_READ,
  IIC_SETUP_WAIT,
  IIC_SETUP_START,
  IIC_SETUP_WRITE,
  IIC_SETUP_READ,
  IIC_WAITING,  // 17
  IIC_WRITING,
  IIC_READING,
  IIC_REPEAT,   // 20
  IIC_ERROR,
  IIC_EXIT,
  IIC_STATES
};


char      IicStateText[IIC_STATES][50] =
{
  "IDLE\n",
  "INIT",
  "RESTART",
  "ENABLE",
  "IIC_NXT_TEMP_START",
  "IIC_NXT_TEMP_WRITE",
  "IIC_NXT_TEMP_READ",
  "MANUFACTURER_START",
  "MANUFACTURER_WRITE",
  "MANUFACTURER_READ",
  "TYPE_START",
  "TYPE_WRITE",
  "TYPE_READ",
  "SETUP_WAIT",
  "SETUP_START",
  "SETUP_WRITE",
  "SETUP_READ",
  "WAITING",
  "WRITING",
  "READING",
  "REPEAT",
  "ERROR",
  "EXIT"
};


DATA8     IicPortType[INPUTS];
IICSTR    IicStrings[INPUTS];


#if 0 // state machine is unused. -- ertl-liyixiao
#define   IIC_TIMER_RESOLUTION            20 // [100u]
static    struct hrtimer Device1Timer;
static    ktime_t        Device1Time;

static enum hrtimer_restart Device1TimerInterrupt1(struct hrtimer *pTimer)
{
  UBYTE   Port;
  UBYTE   Tmp;
  UBYTE   TmpBuffer[IIC_DATA_LENGTH];
  RESULT  Result;

  hrtimer_forward_now(pTimer,Device1Time);

  for (Port = 0;Port < NO_OF_IIC_PORTS;Port++)
  { // look at one port at a time
  	Result = FAIL;

    switch (IicPort[Port].State)
    { // Main state machine

      case IIC_IDLE :
      { // Port inactive

        (*pIic).Status[Port]        =  0;
      }
      break;

      case IIC_INIT :
      { // Initialise port hardware

        memset((void*)IicStrings[Port].Manufacturer,0,IIC_NAME_LENGTH + 1);
        memset((void*)IicStrings[Port].SensorType,0,IIC_NAME_LENGTH + 1);
        IicPort[Port].State         =  IIC_ENABLE;
      }
      break;

      case IIC_RESTART :
      {
        IicPortDisable(Port);
        IicPort[Port].State         =  IIC_ENABLE;
      }
      break;

      case IIC_ENABLE :
      { // Initialise port variables

        IicPortEnable(Port);
        Tmp = IicPort[Port].Mode;
        IicPort[Port]               =  IicPortDefault;

        IicPort[Port].Timer         =  0;
        if (Tmp == 255)
        {
          IicPort[Port].Mode        = 255;
          IicPort[Port].Initialised = 1;
          IicPort[Port].State       =  IIC_WAITING;
        }
        else
          IicPort[Port].State       =  IIC_NXT_TEMP_START;
      }
      break;





      case IIC_NXT_TEMP_START :
      {
        if (++(IicPort[Port].Timer) >= (10 / IIC_TIMER_RESOLUTION))
        {
          IicPort[Port].OutBuffer[0]  =  0x4C;
          IicPort[Port].OutBuffer[1]  =  0x01;
          IicPort[Port].OutBuffer[2]  =  0x60;
          IicPort[Port].OutBuffer[3]  =  0x00;
          IicPort[Port].OutLength     =  3;
          IicPort[Port].InLength      =  1;
          IicPort[Port].Repeat        =  1;
          IicPort[Port].Time          =  0;
          IicPort[Port].Timer         =  0;
          IicPort[Port].State         =  IIC_NXT_TEMP_WRITE;
        }
      }
      break;

      case IIC_NXT_TEMP_WRITE :
      {
        IicPortSend(Port);
        IicPort[Port].Timer       =  0;
        IicPort[Port].State       =  IIC_NXT_TEMP_READ;
      }
      break;

      case IIC_NXT_TEMP_READ :
      {
      	Result = IicPortReceive(Port,TmpBuffer);
        if (Result != BUSY)
        {
          if (TmpBuffer[0] == 0x60)
          {
            memcpy((void*)IicStrings[Port].Manufacturer,(void*)"LEGO",IIC_NAME_LENGTH);
            IicStrings[Port].Manufacturer[IIC_NAME_LENGTH]  =  0;
            memcpy((void*)IicStrings[Port].SensorType,(void*)"Temp.",IIC_NAME_LENGTH);
            IicStrings[Port].SensorType[IIC_NAME_LENGTH]  =  0;

            (*pIic).Changed[Port]       =  1;

            IicPort[Port].Initialised   =  1;
            IicPort[Port].Timer         =  0;
            IicPort[Port].State         =  IIC_SETUP_WAIT;
          }
          else
          {
            IicPort[Port].Timer       =  0;
            IicPort[Port].State         =  IIC_MANUFACTURER_START;
          }
        }
        if (++(IicPort[Port].Timer) >= (500 / IIC_TIMER_RESOLUTION))
        {
          IicPort[Port].Timer       =  0;
          IicPort[Port].State         =  IIC_MANUFACTURER_START;
        }
      }
      break;

      case IIC_MANUFACTURER_START :
      {
        if (++(IicPort[Port].Timer) >= (10 / IIC_TIMER_RESOLUTION))
        {
          IicPort[Port].OutBuffer[0]  =  IicPort[Port].Addr;
          IicPort[Port].OutBuffer[1]  =  0x08;
          IicPort[Port].OutBuffer[2]  =  0x00;
          IicPort[Port].OutBuffer[3]  =  0x00;
          IicPort[Port].OutLength     =  2;
          IicPort[Port].InLength      =  8;
          IicPort[Port].Repeat        =  1;
          IicPort[Port].Time          =  0;
          IicPort[Port].Timer         =  0;
          IicPort[Port].State         =  IIC_MANUFACTURER_WRITE;
        }
      }
      break;

      case IIC_MANUFACTURER_WRITE :
      {
        IicPortSend(Port);
        IicPort[Port].Timer       =  0;
        IicPort[Port].State       =  IIC_MANUFACTURER_READ;
      }
      break;

      case IIC_MANUFACTURER_READ :
      {
      	Result = IicPortReceive(Port,TmpBuffer);
        if (Result != BUSY)
        {
          memcpy((void*)IicStrings[Port].Manufacturer,(void*)TmpBuffer,IIC_NAME_LENGTH);
          IicStrings[Port].Manufacturer[IIC_NAME_LENGTH]  =  0;

          if (TmpBuffer[0] == 0x08)
          {
            if (IicPort[Port].Addr < 0x50)
            {
              IicPort[Port].Addr++;
              IicPort[Port].Timer         =  0;
              IicPort[Port].State         =  IIC_MANUFACTURER_START;
            }
            else
            {
              if (--IicPort[Port].Retries > 0)
              {
                IicPort[Port].Addr          =  0x01;
                IicPort[Port].Timer         =  0;
                IicPort[Port].State         =  IIC_MANUFACTURER_START;
              }
              else
              {
                IicPort[Port].Initialised   =  1;
                IicPort[Port].State         =  IIC_SETUP_START;
              }
            }
          }
          else
          {
            if (TmpBuffer[0] == 0)
            {
              memcpy((void*)IicStrings[Port].Manufacturer,(void*)"LEGO",IIC_NAME_LENGTH);
              IicStrings[Port].Manufacturer[IIC_NAME_LENGTH]  =  0;
            }
            IicPort[Port].Initialised     =  1;
            IicPort[Port].State           =  IIC_TYPE_START;
          }

        }
        if (++(IicPort[Port].Timer) >= (500 / IIC_TIMER_RESOLUTION))
        {
          printk("IIC timeout\n");
          IicPort[Port].Addr        =  0x01;
          (*pIic).Status[Port]     &= ~IIC_WRITE_REQUEST;
          (*pIic).Status[Port]     &= ~IIC_DATA_READY;
          IicPort[Port].State       =  IIC_WAITING;
        }
      }
      break;

      case IIC_TYPE_START :
      {
        IicPort[Port].OutBuffer[0]  =  IicPort[Port].Addr;
        IicPort[Port].OutBuffer[1]  =  0x10;
        IicPort[Port].OutBuffer[2]  =  0x00;
        IicPort[Port].OutBuffer[3]  =  0x00;
        IicPort[Port].OutLength     =  2;
        IicPort[Port].InLength      =  8;
        IicPort[Port].Repeat        =  1;
        IicPort[Port].Time          =  0;
        IicPort[Port].Timer         =  0;
        IicPort[Port].State         =  IIC_TYPE_WRITE;
      }
      break;

      case IIC_TYPE_WRITE :
      {
        IicPortSend(Port);
        IicPort[Port].Timer       =  0;
        IicPort[Port].State       =  IIC_TYPE_READ;
      }
      break;

      case IIC_TYPE_READ :
      {
      	Result = IicPortReceive(Port,TmpBuffer);
        if (Result != BUSY)
        {
          memcpy((void*)IicStrings[Port].SensorType,(void*)TmpBuffer,IIC_NAME_LENGTH);
          IicStrings[Port].SensorType[IIC_NAME_LENGTH]  =  0;

          if (TmpBuffer[0] == 0)
          {
            memcpy((void*)IicStrings[Port].SensorType,(void*)"Store",IIC_NAME_LENGTH);
            IicStrings[Port].Manufacturer[IIC_NAME_LENGTH]  =  0;
          }

          (*pIic).Changed[Port]       =  1;

          IicPort[Port].Initialised   =  1;
          IicPort[Port].Timer         =  0;
          IicPort[Port].State         =  IIC_SETUP_WAIT;
        }
        if (++(IicPort[Port].Timer) >= (500 / IIC_TIMER_RESOLUTION))
        {
          (*pIic).Status[Port]     &= ~IIC_WRITE_REQUEST;
          (*pIic).Status[Port]     &= ~IIC_DATA_READY;
          IicPort[Port].State       =  IIC_WAITING;
        }
      }
      break;

      case IIC_SETUP_WAIT :
      {
        if (++(IicPort[Port].Timer) >= (10000 / IIC_TIMER_RESOLUTION))
        {
          IicPort[Port]               =  IicPortDefault;
          IicPort[Port].Timer         =  0;
          IicPort[Port].State         =  IIC_NXT_TEMP_START;
        }
      }
      break;

      case IIC_SETUP_START :
      {
#ifndef DISABLE_FAST_DATALOG_BUFFER
        (*pIic).Actual[Port]        =  0;
        (*pIic).LogIn[Port]         =  0;
#endif

        if (IicStrings[Port].SetupLng)
        {
          IicPort[Port].OutBuffer[0]  =  (UBYTE)((IicStrings[Port].SetupString >> 24) & 0xFF);
          IicPort[Port].OutBuffer[1]  =  (UBYTE)((IicStrings[Port].SetupString >> 16) & 0xFF);
          IicPort[Port].OutBuffer[2]  =  (UBYTE)((IicStrings[Port].SetupString >>  8) & 0xFF);
          IicPort[Port].OutBuffer[3]  =  (UBYTE)((IicStrings[Port].SetupString) & 0xFF);
          IicPort[Port].OutLength     =  IicStrings[Port].SetupLng;
          IicPort[Port].InLength      =  0;
          IicPort[Port].Repeat        =  1;
          IicPort[Port].Time          =  0;
          IicPort[Port].State         =  IIC_SETUP_WRITE;
        }
        else
        {
          IicPort[Port].State         =  IIC_SETUP_READ;
        }
        IicPort[Port].Timer           =  0;
      }
      break;

      case IIC_SETUP_WRITE :
      {
        IicPortSend(Port);
        IicPort[Port].Timer       =  0;
        IicPort[Port].State       =  IIC_SETUP_READ;
      }
      break;

      case IIC_SETUP_READ :
      {
      	Result = IicPortReceive(Port,TmpBuffer);
        if (Result != BUSY)
        {
          IicPort[Port].State           =  IIC_WAITING;
          if (IicStrings[Port].PollLng)
          {
            IicPort[Port].OutBuffer[0]  =  (UBYTE)((IicStrings[Port].PollString >> 24) & 0xFF);
            IicPort[Port].OutBuffer[1]  =  (UBYTE)((IicStrings[Port].PollString >> 16) & 0xFF);
            IicPort[Port].OutBuffer[2]  =  (UBYTE)((IicStrings[Port].PollString >>  8) & 0xFF);
            IicPort[Port].OutBuffer[3]  =  (UBYTE)((IicStrings[Port].PollString) & 0xFF);
            IicPort[Port].OutLength     =  IicStrings[Port].PollLng;
            if (IicStrings[Port].ReadLng < 0)
            {
              IicPort[Port].InLength    =  0 - IicStrings[Port].ReadLng;
              IicPort[Port].Reverse     =  1;
            }
            else
            {
              IicPort[Port].InLength    =  IicStrings[Port].ReadLng;
              IicPort[Port].Reverse     =  0;
            }
            IicPort[Port].Repeat        =  0xFF;
            IicPort[Port].Time          =  IicStrings[Port].Time;
            IicPort[Port].Timer         =  0;
            IicPort[Port].State         =  IIC_WRITING;
            (*pIic).Status[Port]        =  0;
          }
          IicPort[Port].Initialised     =  1;
        }
        if (++(IicPort[Port].Timer) >= (500 / IIC_TIMER_RESOLUTION))
        {
          IicPort[Port].Result      =  STOP;
          (*pIic).Status[Port]     &= ~IIC_WRITE_REQUEST;
          (*pIic).Status[Port]     &= ~IIC_DATA_READY;
          IicPort[Port].State       =  IIC_WAITING;
        }
      }
      break;

      case IIC_WAITING :
      {
        if (++(IicPort[Port].Timer) >= ((MIN_IIC_REPEAT_TIME * 10) / IIC_TIMER_RESOLUTION))
        {
          if (IicPort[Port].Result == START)
          {
            if (IicPortBusy(Port) == 0)
            {
              IicPort[Port].Result      =  BUSY;
              IicPort[Port].Timer       =  0;
              IicPort[Port].State       =  IIC_WRITING;
            }
          }
        }
      }
      break;

      case IIC_WRITING :
      {
        IicPortSend(Port);
        ++(IicPort[Port].Timer);
        IicPort[Port].State       =  IIC_READING;
      }
      break;

      case IIC_READING :
      {
      	Result = IicPortReceive(Port,TmpBuffer);
      	if (Result == FAIL)
      	{
          (*pIic).Status[Port]     &= ~IIC_WRITE_REQUEST;
          (*pIic).Status[Port]     &= ~IIC_DATA_READY;
          IicPort[Port].Result      =  FAIL;
          IicPort[Port].State       =  IIC_WAITING;

#ifdef DEBUG_D_IIC
          printk("IIC_READING: failed\n");
#endif // DEBUG_D_IIC
      	}
      	else if (Result != BUSY)
        {
#ifndef DISABLE_FAST_DATALOG_BUFFER
          if (IicPort[Port].InLength > 1)
          {
            if (IicPort[Port].Reverse)
            {
              for (Tmp = 0;Tmp < IicPort[Port].InLength;Tmp++)
              {
                IicPort[Port].InBuffer[Tmp]                  =  TmpBuffer[Tmp];
                (*pIic).Raw[Port][(*pIic).LogIn[Port]][Tmp]  =  TmpBuffer[Tmp];
              }
            }
            else
            {
              for (Tmp = 0;Tmp < IicPort[Port].InLength;Tmp++)
              {
                IicPort[Port].InBuffer[Tmp]       =  TmpBuffer[(IicPort[Port].InLength - 1) - Tmp];
                (*pIic).Raw[Port][(*pIic).LogIn[Port]][Tmp]  =  TmpBuffer[(IicPort[Port].InLength - 1) - Tmp];
              }
            }
          }
          else
          {
            IicPort[Port].InBuffer[0]                  =  TmpBuffer[0];
            IicPort[Port].InBuffer[1]                  =  0;
            (*pIic).Raw[Port][(*pIic).LogIn[Port]][0]  =  TmpBuffer[0];
            (*pIic).Raw[Port][(*pIic).LogIn[Port]][1]  =  0;
          }

          (*pIic).Actual[Port]  =  (*pIic).LogIn[Port];
          (*pIic).Repeat[Port][(*pIic).Actual[Port]]  =  0;

          if (++((*pIic).LogIn[Port]) >= DEVICE_LOGBUF_SIZE)
          {
            (*pIic).LogIn[Port]      =  0;
          }
#else
          if (IicPort[Port].InLength > 1)
          {
            if (IicPort[Port].Reverse)
            {
              for (Tmp = 0;Tmp < IicPort[Port].InLength;Tmp++)
              {
                IicPort[Port].InBuffer[Tmp]       =  TmpBuffer[Tmp];
                (*pIic).Raw[Port][Tmp]            =  TmpBuffer[Tmp];
              }
            }
            else
            {
              for (Tmp = 0;Tmp < IicPort[Port].InLength;Tmp++)
              {
                IicPort[Port].InBuffer[Tmp]       =  TmpBuffer[(IicPort[Port].InLength - 1) - Tmp];
                (*pIic).Raw[Port][Tmp]            =  TmpBuffer[(IicPort[Port].InLength - 1) - Tmp];
              }
            }
          }
          else
          {
            IicPort[Port].InBuffer[0]                  =  TmpBuffer[0];
            IicPort[Port].InBuffer[1]                  =  0;
            (*pIic).Raw[Port][0]  =  TmpBuffer[0];
            (*pIic).Raw[Port][1]  =  0;
          }
#endif
          (*pIic).Status[Port]     |=  IIC_DATA_READY;
          IicPort[Port].Result      =  OK;
          IicPort[Port].State       =  IIC_WAITING;
        }
        if (++(IicPort[Port].Timer) >= (5000 / IIC_TIMER_RESOLUTION))
        {
          IicPort[Port].Result      =  FAIL;
          IicPort[Port].State       =  IIC_WAITING;
        }
        if (IicPort[Port].State == IIC_WAITING)
        {
          if (IicPort[Port].Repeat != 0xFF)
          {
            IicPort[Port].Repeat--;
            if (IicPort[Port].Repeat != 0)
            {
              IicPort[Port].State       =  IIC_REPEAT;
            }
          }
          else
          {
            IicPort[Port].State       =  IIC_REPEAT;
          }
        }
      }
      break;

      case IIC_REPEAT :
      {
        if ((*pIic).Status[Port] & IIC_WRITE_REQUEST)
        {
          (*pIic).Status[Port]      =  IIC_WRITE_REQUEST;
          IicPort[Port].State       =  IIC_WAITING;
        }
        else
        {
          if (++(IicPort[Port].Timer) >= (UWORD)(IicPort[Port].Time / (IIC_TIMER_RESOLUTION / 10)))
          {
            IicPort[Port].Timer       =  0;
            IicPort[Port].State       =  IIC_WRITING;
          }
        }
      }
      break;

      case IIC_EXIT :
      {
        IicPortDisable(Port);
        IicPort[Port]                           =  IicPortDefault;

        (*pIic).Status[Port]                    =  0;

        IicPort[Port].State                     =  IIC_IDLE;
      }
      break;

    }

#ifndef DISABLE_FAST_DATALOG_BUFFER
    ((*pIic).Repeat[Port][(*pIic).Actual[Port]]) += (IIC_TIMER_RESOLUTION / 10);
#endif

#if defined(DEBUG_I2C_SENSOR) || 1

//#ifdef HIGHDEBUG
    if (IicPort[Port].OldState != IicPort[Port].State)
    {
      IicPort[Port].OldState    =  IicPort[Port].State;
      if (IicPort[Port].State  !=  IIC_ENABLE)
      {
    	  syslog(LOG_EMERG, "    %d %s\r\n",Port,IicStateText[IicPort[Port].State]);
//        snprintf(IicBuffer,IICBUFFERSIZE,"    %d %s\r\n",Port,IicStateText[IicPort[Port].State]);
      }
      else
      {
    	  syslog(LOG_EMERG, "*** %d %s ***\r\n",Port,IicStateText[IicPort[Port].State]);
//        snprintf(IicBuffer,IICBUFFERSIZE,"*** %d %s ***\r\n",Port,IicStateText[IicPort[Port].State]);
      }
//      IicWrite(IicBuffer);
    }
//#endif

#endif

  }


  return (HRTIMER_RESTART);
}
#endif

#if 0 // unused in EV3RT -- ertl-liyixiao

static int Device1Ioctl(struct inode *pNode, struct file *File, unsigned int Request, unsigned long Pointer)
{
  DEVCON  *pDevCon;
  IICSTR  *pIicStr;
  IICDAT  *pIicDat;
  DATA8   Port = 0;

  switch (Request)
  {

    case IIC_SET_CONN :
    {
      pDevCon   =  (DEVCON*)Pointer;

      for (Port = 0;Port < INPUTS;Port++)
      {
        if ((*pDevCon).Connection[Port] == CONN_NXT_IIC)
        {
          if (IicConfigured[Port] == 0)
          {
#ifdef DEBUG_TRACE_MODE_CHANGE
            printk("d_iic  %d   Device1Ioctl: Changing to IIC\n",Port);
#endif
            IicConfigured[Port]        =  1;
            IicPortType[Port]          =  (*pDevCon).Type[Port];
            IicPort[Port].Mode         = (*pDevCon).Mode[Port];
            IicPort[Port].State        =  IIC_INIT;
          }
          else
          {
            if (IicPort[Port].Initialised)
            {
              if (IicPort[Port].Mode != (UBYTE)((*pDevCon).Mode[Port]))
              {
#ifdef DEBUG_TRACE_MODE_CHANGE
                printk("d_iic  %d   Device1Ioctl: Changing to    %c\n",Port,(*pDevCon).Mode[Port] + '0');
#endif
                IicPort[Port].Mode         =  (*pDevCon).Mode[Port];
                IicPort[Port].ChangeMode   =  1;
                (*pIic).Status[Port]      &= ~IIC_DATA_READY;
                IicPort[Port].State        =  IIC_SETUP_START;
              }
            }
          }
        }
        else
        {
#ifdef DEBUG_TRACE_MODE_CHANGE
          printk("d_iic  %d   Device1Ioctl: Changing to non IIC\n",Port);
#endif
          (*pIic).Status[Port] &= ~IIC_DATA_READY;
          if (IicConfigured[Port])
          {
            IicConfigured[Port]        =  0;
            IicPort[Port].State        =  IIC_EXIT;
          }
        }
      }

    }
    break;

    case IIC_SET :
    {
      pIicStr                     = (IICSTR*)Pointer;

      Port                        =  (*pIicStr).Port;

      memcpy((void*)&IicStrings[Port],(void*)pIicStr,sizeof(IICSTR));
      IicPort[Port].State         =  IIC_SETUP_START;

    }
    break;

#if 0 // unused -- ertl-liyixiao
    case IIC_SETUP :
    {
      pIicDat                     = (IICDAT*)Pointer;

      Port                        =  (*pIicDat).Port;

      if (IicPort[Port].Repeat == 0xFF)
      {
        IicPort[Port].Result  =  STOP;
      }
      if ((IicPort[Port].Result != BUSY) && (IicPort[Port].Result != START))
      {
        if ((IicPort[Port].Result == STOP) && ((*pIicDat).Repeat != 0))
        { // Ready for transfer

					IicPort[Port].Repeat      =  (*pIicDat).Repeat;
					IicPort[Port].Time        =  (*pIicDat).Time;
					IicPort[Port].OutLength   =  (*pIicDat).WrLng;
					if ((*pIicDat).RdLng < 0)
					{
						IicPort[Port].InLength    =  0 - (*pIicDat).RdLng;
						IicPort[Port].Reverse     =  1;
					}
					else
					{
						IicPort[Port].InLength    =  (*pIicDat).RdLng;
						IicPort[Port].Reverse     =  0;
					}

					if (IicPort[Port].OutLength > IIC_DATA_LENGTH)
					{
						IicPort[Port].OutLength =   IIC_DATA_LENGTH;
					}
					if (IicPort[Port].InLength > IIC_DATA_LENGTH)
					{
						IicPort[Port].InLength  =   IIC_DATA_LENGTH;
					}

					memcpy((void*)&IicPort[Port].OutBuffer[0],(void*)&(*pIicDat).WrData[0],IicPort[Port].OutLength);
					memset((void*)&IicPort[Port].InBuffer[0],0,IIC_DATA_LENGTH);

        	IicPort[Port].Result        =  START;

        }
        else
        { // Data ready

          if (IicPort[Port].Result == OK)
          { // Data ok

            memcpy((void*)&(*pIicDat).RdData[0],(void*)&IicPort[Port].InBuffer[0],IicPort[Port].InLength);

            (*pIicDat).Result         =  OK;
          }
          else
          { // Data error

            (*pIicDat).Result         =  FAIL;
          }

          IicPort[Port].Result        =  STOP;

        }
      }
    }
    break;
#endif

    case IIC_READ_TYPE_INFO :
    {
      pIicStr                     = (IICSTR*)Pointer;

      Port                        =  (*pIicStr).Port;
      memcpy((void*)((*pIicStr).Manufacturer),(void*)IicStrings[Port].Manufacturer,IIC_NAME_LENGTH + 1);
      memcpy((void*)((*pIicStr).SensorType),(void*)IicStrings[Port].SensorType,IIC_NAME_LENGTH + 1);

      (*pIic).Changed[Port]       =  0;

    }
    break;

#if 0
    case IIC_READ_STATUS:
    {
      pIicDat                     = (IICDAT*)Pointer;
      Port                        =  (*pIicDat).Port;
      (*pIicDat).Result 					= IicPort[Port].Result;
    }
    break;

    case IIC_READ_DATA:
    {
      pIicDat                     = (IICDAT*)Pointer;
      Port                        =  (*pIicDat).Port;

      if (IicPort[Port].Result == OK)
      { // Data ok

        memcpy((void*)&(*pIicDat).RdData[0],(void*)&IicPort[Port].InBuffer[0],IicPort[Port].InLength);
        (*pIicDat).Result         =  OK;
      }
      else
      { // Data error

        (*pIicDat).Result         =  FAIL;
      }
    }
    break;

    case IIC_WRITE_DATA:
    {
			pIicDat                     = (IICDAT*)Pointer;

			Port                        =  (*pIicDat).Port;

      if (IicPort[Port].Repeat == 0xFF)
      {
        IicPort[Port].Result  =  STOP;
      }
      if ((IicPort[Port].Result != BUSY) && (IicPort[Port].Result != START))
      {
				IicPort[Port].Repeat      =  1;
				IicPort[Port].Time        =  0;
				IicPort[Port].OutLength   =  (*pIicDat).WrLng;
				IicPort[Port].InLength    =  (*pIicDat).RdLng;
				IicPort[Port].Reverse     =  1;

				if (IicPort[Port].OutLength > IIC_DATA_LENGTH)
				{
					IicPort[Port].OutLength =   IIC_DATA_LENGTH;
				}
				if (IicPort[Port].InLength > IIC_DATA_LENGTH)
				{
					IicPort[Port].InLength  =   IIC_DATA_LENGTH;
				}

				memcpy((void*)&IicPort[Port].OutBuffer[0],(void*)&(*pIicDat).WrData[0],IicPort[Port].OutLength);
				memset((void*)&IicPort[Port].InBuffer[0],0,IIC_DATA_LENGTH);

				IicPort[Port].Result        =  START;
			}
    }
    break;
#endif
  }

  return (0);
}

static ssize_t Device1Write(struct file *File,const char *Buffer,size_t Count,loff_t *Data)
{
  int     Lng     = 0;

  Lng           =  Count;

  return (Lng);
}


static ssize_t Device1Read(struct file *File,char *Buffer,size_t Count,loff_t *Offset)
{
  int     Lng     = 0;

#ifdef DEBUG_IIC_WRITE
  if (LogOutPointer != LogPointer)
  {
    while ((Count--) && (LogOutPointer != LogPointer))
    {
      Buffer[Lng++]  =  LogPool[LogOutPointer];
      Buffer[Lng]    =  0;

      LogOutPointer++;
      if (LogOutPointer >= LOGPOOLSIZE)
      {
        LogOutPointer  =  0;
      }
    }
  }
  if (Lng == 0)
  {
    IicWrite(IicBuffer);
    snprintf(IicBuffer,IICBUFFERSIZE,"-----------------------------------------------------------------\r\n");
    IicWrite(IicBuffer);
    snprintf(IicBuffer,IICBUFFERSIZE,"    IIC DUMP\r\n");
    IicWrite(IicBuffer);
    snprintf(IicBuffer,IICBUFFERSIZE,"-----------------------------------------------------------------\r\n");
    IicWrite(IicBuffer);
  }
#else
  int     Tmp;
  int     Port;

  Port   =  0;
  Tmp    =  5;
  while ((Count > Tmp) && (Port < INPUTS))
  {
    if (Port != (INPUTS - 1))
    {
      Tmp    =  snprintf(&Buffer[Lng],4,"%2u ",(UWORD)IicPort[Port].State);
    }
    else
    {
      Tmp    =  snprintf(&Buffer[Lng],5,"%2u\r",(UWORD)IicPort[Port].State);
    }
    Lng   +=  Tmp;
    Count -=  Tmp;
    Port++;
  }
#endif

  return (Lng);
}

#define     SHM_LENGTH    (sizeof(IicDefault))
#define     NPAGES        ((SHM_LENGTH + PAGE_SIZE - 1) / PAGE_SIZE)
static void *kmalloc_ptr;

static int Device1Mmap(struct file *filp, struct vm_area_struct *vma)
{
   int ret;

   ret = remap_pfn_range(vma,vma->vm_start,virt_to_phys((void*)((unsigned long)pIic)) >> PAGE_SHIFT,vma->vm_end-vma->vm_start,PAGE_SHARED);

   if (ret != 0)
   {
     ret  =  -EAGAIN;
   }

   return (ret);
}


static    const struct file_operations Device1Entries =
{
  .owner        = THIS_MODULE,
  .read         = Device1Read,
  .write        = Device1Write,
  .mmap         = Device1Mmap,
  .ioctl        = Device1Ioctl,
};


static    struct miscdevice Device1 =
{
  MISC_DYNAMIC_MINOR,
  DEVICE1_NAME,
  &Device1Entries
};
#endif

static int Device1Init(void)
{
  int     Result = -1;
#if 0 // unused in EV3RT -- ertl-liyixiao
  UWORD   *pTmp;
  int     i;
#endif
#ifndef   DISABLE_FIQ_IIC
  UBYTE   Port;
#endif

#if 0 // unused in EV3RT -- ertl-liyixiao
  Result  =  misc_register(&Device1);
  if (Result)
  {
    printk("  %s device register failed\n",DEVICE1_NAME);
  }
  else
#endif
  {
#if 0 // unused in EV3RT -- ertl-liyixiao
    // allocate kernel shared memory for analog values (pAnalog)
    if ((kmalloc_ptr = kmalloc((NPAGES + 2) * PAGE_SIZE, GFP_KERNEL)) != NULL)
    {
      pTmp = (UWORD*)((((unsigned long)kmalloc_ptr) + PAGE_SIZE - 1) & PAGE_MASK);
      for (i = 0; i < NPAGES * PAGE_SIZE; i += PAGE_SIZE)
      {
        SetPageReserved(virt_to_page(((unsigned long)pTmp) + i));
      }
      pIic         =  (IIC*)pTmp;
#endif
      memset(pIic,0,sizeof(IIC));

#ifndef   DISABLE_FIQ_IIC
      IicCtrl.port_enabled  = 0;

      for (Port = 0;Port < INPUTS;Port++)
      {
        IicPort[Port]                               =  IicPortDefault;
        IicConfigured[Port]                         =  0;
        IicCtrl.data_package[Port].transfer_state   =  TRANSFER_IDLE;
        IicStrings[Port].Manufacturer[0]            =  0;
        IicStrings[Port].SensorType[0]              =  0;
        if (Port == DEBUG_UART)
        {
          PINLow(Port,IIC_PORT_BUFFER_CTRL);
          PINOutput(Port,IIC_PORT_BUFFER_CTRL);
        }
      }
#endif

#if 0 // disable the state machine -- ertl-liyixiao
      Device1Time  =  ktime_set(0,IIC_TIMER_RESOLUTION * 100000);
      hrtimer_init(&Device1Timer,CLOCK_MONOTONIC,HRTIMER_MODE_REL);
      Device1Timer.function  =  Device1TimerInterrupt1;
      hrtimer_start(&Device1Timer,Device1Time,HRTIMER_MODE_REL);
#endif

#ifdef DEBUG
      printk("  %s device register succes\n",DEVICE1_NAME);
#endif
#if 0 // unused in EV3RT -- ertl-liyixiao
    }
    else
    {
      printk("  %s kmalloc failed !!\n",DEVICE1_NAME);
    }
#endif
  }

  return (Result);
}

#if 0 // unused in EV3RT -- ertl-liyixiao

static void Device1Exit(void)
{
  IIC     *pTmp;
  int     i;

  hrtimer_cancel(&Device1Timer);

  pTmp      =  pIic;
  pIic      =  &IicDefault;

  // free shared memory
  for (i = 0; i < NPAGES * PAGE_SIZE; i+= PAGE_SIZE)
  {
    ClearPageReserved(virt_to_page(((unsigned long)pTmp) + i));
#ifdef DEBUG
    printk("  %s memory page %d unmapped\n",DEVICE1_NAME,i);
#endif
  }
  kfree(kmalloc_ptr);

  misc_deregister(&Device1);
#ifdef DEBUG
  printk("  %s device unregistered\n",DEVICE1_NAME);
#endif
}




// MODULE *********************************************************************


#ifndef PCASM
module_param (HwId, charp, 0);
#endif

#endif

static int ModuleInit(void)
{
#if 0 // unused in EV3RT
  Hw  =  HWID;

  if (Hw < PLATFORM_START)
  {
    Hw  =  PLATFORM_START;
  }
  if (Hw > PLATFORM_END)
  {
    Hw  =  PLATFORM_END;
  }
#endif

#ifdef DEBUG
  printk("%s init started\n",MODULE_NAME);
#endif
  if (request_mem_region(DA8XX_GPIO_BASE,0xD8,MODULE_NAME) >= 0)
  {
    //GpioBase  =  (void*)ioremap(DA8XX_GPIO_BASE,0xD8);
    if (GpioBase != NULL)
    {
#ifdef DEBUG
      printk("%s gpio address mapped\n",MODULE_NAME);
#endif

      InitGpio();

      Device1Init();
    }
  }

  return (0);
}

#if 0 // unused in EV3RT -- ertl-liyixiao
static void ModuleExit(void)
{
#ifdef DEBUG
  printk("%s exit started\n",MODULE_NAME);
#endif

  Device1Exit();

  iounmap(GpioBase);
}
#endif
