////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2006-2008 MStar Semiconductor, Inc.
// All rights reserved.
//
// Unless otherwise stipulated in writing, any and all information contained
// herein regardless in any format shall remain the sole proprietary of
// MStar Semiconductor Inc. and be kept in strict confidence
// (��MStar Confidential Information��) by the recipient.
// Any unauthorized act including without limitation unauthorized disclosure,
// copying, use, reproduction, sale, distribution, modification, disassembling,
// reverse engineering and compiling of the contents of MStar Confidential
// Information is unlawful and strictly prohibited. MStar hereby reserves the
// rights to any and all damages, losses, costs and expenses resulting therefrom.
//
////////////////////////////////////////////////////////////////////////////////

#include <config.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#include <directfb.h>
#include <directfb_keynames.h>

#include "directfb.h"

#include <core/coredefs.h>
#include <core/coretypes.h>

#include <core/input.h>

#include <direct/debug.h>
#include <direct/mem.h>
#include <direct/messages.h>
#include <direct/thread.h>
#include <direct/util.h>

#include <core/input_driver.h>

#include <fcntl.h>
#include <signal.h>
#include <stropts.h>
#include <sys/ioctl.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <misc/conf.h>

#if DFB_BUILD_FOR_PRJ_OBAMA
#include "madp.h"
#else
#include "MsTypes.h"
#include "drvIR.h"
#endif

#define MSTARIR_KEYRELEASE_PATCH

#define DEBUG_IR(x) do{(x);}while(0)

DFB_INPUT_DRIVER( mstarir )
#define DEVICE "/dev/ir"
 void AddMstarirModule()
{
}
//static DirectFBKeySymbolNames(keynames);

#if DFB_BUILD_FOR_PRJ_OBAMA

struct Mstar_ircode_trans {
    EN_KEY ircode;
    DFBInputDeviceKeySymbol symbol;
    DFBInputDeviceKeyIdentifier identifier;
};

struct Mstar_ircode_trans  transform_ircode[]={
    {KEY_CHANNEL_FAV_LIST, DIKS_CHANNEL_FAV_LIST, DIKI_UNKNOWN}, //0x00,             //IR_KEY_FAV
    {KEY_CHANNEL_RETURN, DIKS_RETURN, DIKI_UNKNOWN},             //0x01,             //IR_KEY_FLASHBK
    {KEY_CHANNEL_PLUS, DIKS_CHANNEL_UP, DIKI_UNKNOWN},           //0x02,             //IR_KEY_CH_UP
    {KEY_CHANNEL_MINUS, DIKS_CHANNEL_DOWN, DIKI_UNKNOWN},        //0x03,             //IR_KEY_CH_DOWN

    {KEY_AUDIO, DIKS_AUDIO, DIKI_UNKNOWN},                       //0x04,             //IR_KEY_SOUND
    {KEY_VOLUME_PLUS, DIKS_VOLUME_UP, DIKI_UNKNOWN},             //0x05,             //IR_KEY_VOL_UP
    {KEY_VOLUME_MINUS, DIKS_VOLUME_DOWN, DIKI_UNKNOWN},          //0x06,             //IR_KEY_VOL_DOWN

    {KEY_UP, DIKS_CURSOR_UP, DIKI_UP},                      //0x07,             //IR_KEY_UP_ARROW
    {KEY_POWER, DIKS_POWER, DIKI_UNKNOWN},                       //0x08,             //IR_KEY_POWER
    {KEY_EXIT, DIKS_EXIT, DIKI_UNKNOWN},                         //0x09,             //IR_KEY_EXIT
    {KEY_MENU, DIKS_MENU, DIKI_UNKNOWN},                         //0x0A,             //IR_KEY_MENU
    {KEY_DOWN, DIKS_CURSOR_DOWN, DIKI_DOWN},                  //0x0B,             //IR_KEY_DOWN_ARROW
    {KEY_LEFT, DIKS_CURSOR_LEFT, DIKI_LEFT},                  //0x0C,             //IR_KEY_LEFT_ARROW
    {KEY_SELECT, DIKS_OK, DIKI_UNKNOWN},                     //0x0D,             //IR_KEY_ENTER
    {KEY_BACK, DIKS_NULL, DIKI_UNKNOWN},                         //0x0E,             //IR_KEY_BACK
    {KEY_RIGHT, DIKS_CURSOR_RIGHT, DIKI_RIGHT},                //0x0F,             //IR_KEY_RIGHT_ARROW

    {KEY_0, DIKS_0, DIKI_0},                               //0x10,             //IR_KEY_0
    {KEY_1, DIKS_1, DIKI_1},                               //0x11,             //IR_KEY_1
    {KEY_2, DIKS_2, DIKI_2},                               //0x12,             //IR_KEY_2
    {KEY_3, DIKS_3, DIKI_3},                               //0x13,             //IR_KEY_3
    {KEY_4, DIKS_4, DIKI_4},                               //0x14,             //IR_KEY_4
    {KEY_5, DIKS_5, DIKI_5},                               //0x15,             //IR_KEY_5
    {KEY_6, DIKS_6, DIKI_6},                               //0x16,             //IR_KEY_6
    {KEY_7, DIKS_7, DIKI_7},                               //0x17,             //IR_KEY_7
    {KEY_8, DIKS_8, DIKI_8},                               //0x18,             //IR_KEY_8
    {KEY_9, DIKS_9, DIKI_9},                               //0x19,             //IR_KEY_9

    {KEY_MUTE, DIKS_MUTE, DIKI_UNKNOWN},                         //0x1A,             //IR_KEY_MUTE

    {KEY_INFO, DIKS_INFO, DIKI_UNKNOWN},                         //0x1B,             //IR_KEY_INFO
    {KEY_RED, DIKS_RED, DIKI_UNKNOWN},                           //0x1C,             //IR_KEY_RED
    {KEY_GREEN, DIKS_GREEN, DIKI_UNKNOWN},                       //0x1D,             //IR_KEY_GREEN
    {KEY_MTS, DIKS_MTS, DIKI_UNKNOWN},                           //0x1E,             //IR_KEY_SAP
    {KEY_SUBTITLE, DIKS_SUBTITLE, DIKI_UNKNOWN},                 //0x1F,

    {KEY_INPUT_SOURCE, DIKS_SOURCE, DIKI_UNKNOWN},               //0x20,             //IR_KEY_INPUT
    {KEY_PICTURE, DIKS_PICTURE, DIKI_UNKNOWN},                   //0x21,             //IR_KEY_PICTURE

    {KEY_SOUND, DIKS_NULL, DIKI_UNKNOWN},                        //0x22,

    {KEY_ZOOM, DIKS_ZOOM, DIKI_UNKNOWN},                         //0x23,             //IR_KEY_RATIO
    {KEY_DASH, DIKS_NULL, DIKI_UNKNOWN},                         //0x24,             //IR_KEY_DASH
    {KEY_SLEEP, DIKS_SLEEP, DIKI_UNKNOWN},                       //0x25,             //IR_KEY_TIMER
    {KEY_EPG, DIKS_EPG, DIKI_UNKNOWN},                           //0x26,

    {KEY_HOLD, DIKS_HOLD, DIKI_UNKNOWN},                         //0x27,             //IR_KEY_HOLD

    {KEY_ADJUST, DIKS_NULL, DIKI_UNKNOWN},                       //0x28,             //IR_KEY_ADJST
    {KEY_TV_INPUT, DIKS_NULL, DIKI_UNKNOWN},                     //0x29,

    {KEY_P_CHECK, DIKS_NULL, DIKI_UNKNOWN},                      //0x2C,
    {KEY_S_CHECK, DIKS_NULL, DIKI_UNKNOWN},                      //0x2D,
    {KEY_POWERONLY, DIKS_NULL, DIKI_UNKNOWN},                    //0x2E,
    {KEY_BRIGHTNESS_PLUS, DIKS_NULL, DIKI_UNKNOWN},              //0x31,
    {KEY_BRIGHTNESS_MINUS, DIKS_NULL, DIKI_UNKNOWN},             //0x32,

    {KEY_YELLOW, DIKS_YELLOW, DIKI_UNKNOWN},                     //0x33,
    {KEY_BLUE, DIKS_BLUE, DIKI_UNKNOWN},                         //0x34,
    {KEY_TTX, DIKS_TTX, DIKI_UNKNOWN},                           //0x35,
    {KEY_SIZE, DIKS_SIZE, DIKI_UNKNOWN},                         //0x36,
    {KEY_MIX, DIKS_MIX, DIKI_UNKNOWN},                           //0x37,
    {KEY_INDEX, DIKS_INDEX, DIKI_UNKNOWN},                       //0x38,
    {KEY_TV_RADIO, DIKS_NULL, DIKI_UNKNOWN},                     //0x39,
    {KEY_REVEAL, DIKS_REVEAL, DIKI_UNKNOWN},                     //0x3A,
    {KEY_CHANNEL_LIST, DIKS_LIST, DIKI_UNKNOWN},                 //0x3B,
    {KEY_TIME, DIKS_TIME, DIKI_UNKNOWN},                         //0x3C,
    {KEY_CLOCK, DIKS_CLOCK, DIKI_UNKNOWN},                       //0x3D,
    {KEY_TTX_MODE, DIKS_NULL, DIKI_UNKNOWN},                     //0x3E,
    {KEY_UPDATE, DIKS_UPDATE, DIKI_UNKNOWN},                     //0x3F,

    {DSC_KEY_PWRON, DIKS_NULL, DIKI_UNKNOWN},                    //0x40,
    {DSC_KEY_PWROFF, DIKS_NULL, DIKI_UNKNOWN},                   //0x41,
    {DSC_KEY_ARC4X3, DIKS_NULL, DIKI_UNKNOWN},                   //0x42,
    {DSC_KEY_ARC16X9, DIKS_NULL, DIKI_UNKNOWN},                  //0x43,
    {DSC_KEY_ARCZOOM, DIKS_NULL, DIKI_UNKNOWN},                  //0x44,
    {DSC_KEY_TV, DIKS_NULL, DIKI_UNKNOWN},                       //0x45,
    {DSC_KEY_VIDEO1, DIKS_NULL, DIKI_UNKNOWN},                   //0x46,
    {DSC_KEY_VIDEO2, DIKS_NULL, DIKI_UNKNOWN},                   //0x47,
    {DSC_KEY_VIDEO3, DIKS_NULL, DIKI_UNKNOWN},                   //0x48,
    {DSC_KEY_COMP1, DIKS_NULL, DIKI_UNKNOWN},                    //0x49,
    {DSC_KEY_COMP2, DIKS_NULL, DIKI_UNKNOWN},                    //0x4A,
    {DSC_KEY_RGBPC, DIKS_NULL, DIKI_UNKNOWN},                    //0x4B,
    {DSC_KEY_RGBDTV, DIKS_NULL, DIKI_UNKNOWN},                   //0x4C,
    {DSC_KEY_RGBDVI, DIKS_NULL, DIKI_UNKNOWN},                   //0x4D,
    {DSC_KEY_HDMI1, DIKS_NULL, DIKI_UNKNOWN},                    //0x4E,
    {DSC_KEY_HDMI2, DIKS_NULL, DIKI_UNKNOWN},                    //0x4F,
    {DSC_KEY_MULTI_PIP, DIKS_NULL, DIKI_UNKNOWN},                //0x50,
    {DSC_KEY_MULTIMEDIA, DIKS_NULL, DIKI_UNKNOWN},               //0x51,
    {DSC_KEY_DVIPC, DIKS_NULL, DIKI_UNKNOWN},                    //0x52,

    {KEY_MMI, DIKS_NULL, DIKI_UNKNOWN},                          //0x5C,
    {KEY_MMI_ENTER_MENU, DIKS_NULL, DIKI_UNKNOWN},               //0x5D,

    {KEY_UARTDEBUGPORT, DIKS_NULL, DIKI_UNKNOWN},                //0x5E,

    {KEY_PAUSE, DIKS_PAUSE, DIKI_PAUSE},                       //0x60,
    {KEY_PLAY, DIKS_PLAY, DIKI_UNKNOWN},                         //0x61,

    {KEY_RECORD, DIKS_RECORD, DIKI_UNKNOWN},                     //0x62,
    {KEY_STOP, DIKS_STOP, DIKI_UNKNOWN},                         //0x63,

    {KEY_SUBCODE, DIKS_NULL, DIKI_UNKNOWN},                      //0x69,

    {KEY_DA, DIKS_NULL, DIKI_UNKNOWN},                           //0x6A,
    {KEY_SUBPAGE, DIKS_NULL, DIKI_UNKNOWN},                      //0x6B,
    {KEY_DVD, DIKS_NULL, DIKI_UNKNOWN},                          //0x6C,
    {KEY_COUNTDOWN_EXIT_TT_SUBTITLE, DIKS_NULL, DIKI_UNKNOWN},   //0x6F,
    {KEY_EPGTIMER_COUNTDOWN, DIKS_NULL, DIKI_UNKNOWN},           //0x70,

    {KEY_DTV, DIKS_NULL, DIKI_UNKNOWN},                          //0x82,
    {KEY_TV, DIKS_NULL, DIKI_UNKNOWN},                           //0x83,
    {KEY_SCART, DIKS_NULL, DIKI_UNKNOWN},                        //0x84,
    {KEY_COMPONENT, DIKS_NULL, DIKI_UNKNOWN},                    //0x85,
    {KEY_PC, DIKS_NULL, DIKI_UNKNOWN},                           //0x86,
    {KEY_HDMI, DIKS_NULL, DIKI_UNKNOWN},                         //0x87,
    {KEY_AV, DIKS_NULL, DIKI_UNKNOWN},                           //0x88,
    {KEY_SV, DIKS_NULL, DIKI_UNKNOWN},                           //0x89,

    {KEY_FREEZE, DIKS_FREEZE, DIKI_UNKNOWN},                     //0x8A,

    {KEY_FF, DIKS_NULL, DIKI_UNKNOWN},                           //0x8B,
    {KEY_REWIND, DIKS_NULL, DIKI_UNKNOWN},                       //0x8C,
    {KEY_NEXT, DIKS_NEXT, DIKI_UNKNOWN},                         //0x8D,
    {KEY_PREVIOUS, DIKS_PREVIOUS, DIKI_UNKNOWN},                 //0x8E,
    {KEY_PAGE_UP, DIKS_PAGE_UP, DIKI_PAGE_UP},                   //0x8F,
    {KEY_PAGE_DOWN, DIKS_PAGE_DOWN, DIKI_PAGE_DOWN},               //0x90,
    {KEY_CC, DIKS_CC, DIKI_UNKNOWN},                             //0x91,
    {KEY_VOLUME, DIKS_NULL, DIKI_UNKNOWN},                       //0x92,

    {KEY_PIP, DIKS_NULL, DIKI_UNKNOWN},                          //0x9A,
    {KEY_BACKWARD, DIKS_BACKWARD, DIKI_UNKNOWN},                 //0xAD,
    {KEY_FORWARD, DIKS_FORWARD, DIKI_UNKNOWN},                   //0xAE,
};

#endif

union semun {
 int val;
 struct semid_ds *buf;
 unsigned short *array;
} arg;

#if DFB_BUILD_FOR_PRJ_OBAMA
static int
compare_ircode( const void *a, const void *b ) {
    EN_KEY * ircode = (EN_KEY *) a;
    struct Mstar_ircode_trans * ircode_trans_node= (struct Mstar_ircode_trans *) b;
    return *ircode - ircode_trans_node->ircode;
}
#endif

static int
driver_get_available()
{
    /* Check if we are able to read from device */
    if (access( DEVICE, R_OK ))
       return 0;

    return 1;
}

static void
driver_get_info( InputDriverInfo *info )
{
     /* fill driver info structure */
     snprintf( info->name,
               DFB_INPUT_DRIVER_INFO_NAME_LENGTH, "MSTARIR Driver" );

     snprintf( info->vendor,
               DFB_INPUT_DRIVER_INFO_VENDOR_LENGTH, "MStar Semi" );

     info->version.major = 0;
     info->version.minor = 2;
}

#if !(DFB_MSTAR_HOST_IR)
#if DFB_HISENSE_MOUSE
typedef struct {
     DirectLink   link;
     His_Mouse_Event     ms_evt;
} HisMouseEvtItem;
#endif
typedef struct {
     DirectLink   link;
     DFBInputEvent ir_evt;
} MstarIREvtItem;

typedef struct {
     CoreInputDevice  *device;
     DirectThread *thread;
     pthread_mutex_t         ir_mutex;
     DirectLink                   *ir_events;
#if DFB_HISENSE_MOUSE
     DirectLink                   *mouse_events;
     int                               sensitive_numerator;
     int                               sensitive_denominator;
     int                               rel_axis_x_motion_reminder;
     int                               rel_axis_y_motion_reminder;
#endif
     int           fd;
     DirectThread *pollingThread;
     int           repeat_time;    
} MStarIrData;
static int mstarir_semid = -1;
static MStarIrData         *data;

static int sem_creat(key_t key)
{
    union semun sem;
    int semid;

    sem.val = 0;
    semid = semget(key,1,IPC_CREAT|0666);
    if (-1 == semid){
         printf("create semaphore error\n");
         return -1;
    }
    semctl(semid,0,SETVAL,sem);
    return semid;
}

static void del_sem(int semid)
{
     union semun sem;

     sem.val = 0;
     semctl(semid,0,IPC_RMID,sem);
}

static int mstarir_sem_wait(int semid)
{
    struct sembuf sops={0,-1,0};
    if(semid == -1)
        return -1;
    return (semop(semid,&sops,1));
}

static int mstarir_sem_signal(int semid)
{
     struct sembuf sops={0,1,0};
     if(semid == -1)
         return -1;
     return (semop(semid,&sops,1));
}
#if DFB_HISENSE_MOUSE
void mstar_mouse_callback(His_Mouse_Event *pMouseEvent)
{

     HisMouseEvtItem *mouse_item;
     mouse_item = D_MALLOC(sizeof(HisMouseEvtItem));
     if(!mouse_item)
     {
          printf("Warning, run out of memory in callback mouse!\n");
          return;
     }
     memcpy(&mouse_item->ms_evt, pMouseEvent, sizeof(His_Mouse_Event));

     pthread_mutex_lock( &data->ir_mutex );

     direct_list_append( &data->mouse_events, &mouse_item->link );

     pthread_mutex_unlock( &data->ir_mutex );
    mstarir_sem_signal(mstarir_semid);
}

void dispatch_his_mouse_event(     CoreInputDevice  *device, MStarIrData *data,
                                                                                                His_Mouse_Event *pMouseEvent)
{
     DFBInputEvent evt = { .type = DIET_UNKNOWN };

     if(pMouseEvent->event_type == HISENSE_MOUSE_AXISMOTION_EVENT)
     {
         if (pMouseEvent->axis_vector.deltaX)
      {
              evt.type    = DIET_AXISMOTION;
              evt.flags   = DIEF_AXISREL;
              evt.axis    = DIAI_X;
              evt.axisrel = pMouseEvent->axis_vector.deltaX;

              data->rel_axis_x_motion_reminder  += evt.axisrel*data->sensitive_numerator;
              evt.axisrel = data->rel_axis_x_motion_reminder/data->sensitive_denominator;
              data->rel_axis_x_motion_reminder %=data->sensitive_denominator;

              /* Signal immediately following event. */
              if (pMouseEvent->axis_vector.deltaY||pMouseEvent->axis_vector.deltaZ)
                    evt.flags |= DIEF_FOLLOW;

              dfb_input_dispatch( device, &evt );
          }
         if (pMouseEvent->axis_vector.deltaY)
      {
              evt.type    = DIET_AXISMOTION;
              evt.flags   = DIEF_AXISREL;
              evt.axis    = DIAI_Y;
              evt.axisrel = pMouseEvent->axis_vector.deltaY;
              data->rel_axis_y_motion_reminder  += evt.axisrel*data->sensitive_numerator;
              evt.axisrel = data->rel_axis_y_motion_reminder/data->sensitive_denominator;
              data->rel_axis_y_motion_reminder %=data->sensitive_denominator;
              /* Signal immediately following event. */
              if (pMouseEvent->axis_vector.deltaZ)
                    evt.flags |= DIEF_FOLLOW;

              dfb_input_dispatch(device, &evt );
          }
         if (pMouseEvent->axis_vector.deltaZ)
      {
              evt.type    = DIET_AXISMOTION;
              evt.flags   = DIEF_AXISREL;
              evt.axis    = DIAI_Z;
              evt.axisrel = pMouseEvent->axis_vector.deltaZ;
              dfb_input_dispatch(device, &evt );
          }
         }
    else
    {
         if(pMouseEvent->button_status.left_button_chg_status == button_pressed)
         {
              evt.type    = DIET_BUTTONPRESS;
                 evt.flags  = DIEF_NONE;
                 evt.button = DIBI_LEFT;
           if(pMouseEvent->button_status.right_button_chg_status != button_no_change)
               evt.flags |= DIEF_FOLLOW;
                 dfb_input_dispatch(device, &evt);
        }
        else if(pMouseEvent->button_status.left_button_chg_status == button_released)
        {
              evt.type    = DIET_BUTTONRELEASE;
                 evt.flags  = DIEF_NONE;
                 evt.button = DIBI_LEFT;
           if(pMouseEvent->button_status.right_button_chg_status != button_no_change)
               evt.flags |= DIEF_FOLLOW;
                 dfb_input_dispatch(device, &evt);
        }
         if(pMouseEvent->button_status.right_button_chg_status == button_pressed)
         {
              evt.type    = DIET_BUTTONPRESS;
                 evt.flags  = DIEF_NONE;
                 evt.button = DIBI_RIGHT;
                 dfb_input_dispatch(device, &evt);
        }
        else if(pMouseEvent->button_status.right_button_chg_status == button_released)
        {
              evt.type    = DIET_BUTTONRELEASE;
                 evt.flags  = DIEF_NONE;
                 evt.button = DIBI_RIGHT;
                 dfb_input_dispatch(device, &evt);
        }
    }
}
#endif
void
mstarir_callback(u8 u8Key, u8 u8RepeatFlag)
{
    EN_KEY key = u8Key;
    MstarIREvtItem *ir_item;


    if(KEY_NULL != key)
    {
         ir_item = D_MALLOC(sizeof(MstarIREvtItem));
         if(!ir_item)
         {
              printf("Warning, run out of memory in callback ir!\n");
              return;
         }
        /* send the press event */
        ir_item->ir_evt.flags      = DIEF_KEYCODE;
        ir_item->ir_evt.type       = DIET_KEYPRESS;

        ir_item->ir_evt.key_code = key;

        if(u8RepeatFlag > 0x0)
        {
            ir_item->ir_evt.flags |= DIEF_REPEAT;
        }

        pthread_mutex_lock( &data->ir_mutex );

        direct_list_append( &data->ir_events, &ir_item->link );

         ir_item = D_MALLOC(sizeof(MstarIREvtItem));
         if(ir_item)
         {
                  /* send the release event */
                   ir_item->ir_evt.flags      = DIEF_KEYCODE;
                   ir_item->ir_evt.type       = DIET_KEYRELEASE;

                   ir_item->ir_evt.key_code = key;
                   direct_list_append( &data->ir_events, &ir_item->link );

         }

         pthread_mutex_unlock( &data->ir_mutex );
        //pthread_cond_signal(&data->evt_cond);

        mstarir_sem_signal(mstarir_semid);
    }
}

static void handler_system_polling(int arg)
{
    // monitor app running status
    MAdp_APMNG_PollingRunningStatus();
    // polling IR
    MAdp_IR_MStarFantasy_Polling();
    // polling D-BUS message/method call
    MAdp_MSGCH_PollingChannelEvent(MAdp_MSGCH_GetChannelIndex("IR"));
}


static void *
MstarIRSystemPollingThread(DirectThread *thread,void *driver_data);


static int start_system_polling(void)
{

    data->pollingThread = direct_thread_create( DTT_INPUT, MstarIRSystemPollingThread, data, "system polling" );
/*
    struct itimerval t;
    t.it_interval.tv_usec = 50000;
    t.it_interval.tv_sec = 0;
    t.it_value.tv_usec = 50000;
    t.it_value.tv_sec = 0;
    signal(SIGALRM, handler_system_polling);
    if (setitimer(ITIMER_REAL, &t, NULL) < 0)
    {
        return -1;
    }
*/
    return 0;
}
static int stop_system_polling(void)
{

    direct_thread_cancel( data->pollingThread );
    direct_thread_join( data->pollingThread );
    direct_thread_destroy( data->pollingThread );
    return 0;
/*
    struct itimerval t;
    t.it_interval.tv_usec = 0;
    t.it_interval.tv_sec = 0;
    t.it_value.tv_usec = 0;
    t.it_value.tv_sec = 0;
    setitimer(ITIMER_REAL, &t, NULL);
    signal(SIGALRM, NULL);
*/

}

static void*
MstarIREventThread( DirectThread *thread, void *driver_data )
{

     MStarIrData *data = (MStarIrData*) driver_data;

     /* Read keyboard data */
     DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
     while(1)
     {
        MstarIREvtItem *ir_item, *ir_tmp;
        //  pthread_cond_wait( &data->evt_cond, &data->evt_lock );


        DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
        mstarir_sem_wait(mstarir_semid);
        DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
        if(direct_thread_is_canceled(thread))
        {
            DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
            direct_thread_testcancel( thread );
            printf("\nthread is not canceled ====%s:%d \n",__FUNCTION__,__LINE__);
            DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
        }

        pthread_mutex_lock( &data->ir_mutex);
        direct_list_foreach_safe (ir_item, ir_tmp, data->ir_events)
        {

            direct_list_remove( &data->ir_events, &ir_item->link );
            dfb_input_dispatch( data->device, &ir_item->ir_evt );
            D_FREE( ir_item );

        }
#if DFB_HISENSE_MOUSE
        HisMouseEvtItem *mouse_item, *mouse_tmp;
        direct_list_foreach_safe (mouse_item, mouse_tmp, data->mouse_events)
        {
          direct_list_remove( &data->mouse_events, &mouse_item->link );
          dispatch_his_mouse_event(data->device, data, &mouse_item->ms_evt);
          D_FREE( mouse_item );
        }
#endif
        pthread_mutex_unlock( &data->ir_mutex);

        };
        DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);

        return NULL;
}

static void *
MstarIRSystemPollingThread(DirectThread *thread,void *driver_data)
{

    while(1)
    {

        direct_thread_testcancel( thread );
        handler_system_polling(0);
        usleep(50000);
    };
    return NULL;
}

#else

typedef struct {
     CoreInputDevice  *device;
     DirectThread *thread;
     int           fd;
     int           repeat_time;       
} MStarIrData;

static bool _CheckProcessExist(pid_t pid)
{
    int r;

    if (pid <= 0)
    {
        //printf("1 pid %d doesn't exist!\n", pid);
        return false;
    }
    else
    {
        r = kill(pid, 0);
        if (r == 0)
        {
            //printf("1. pid %d exist!\n", pid);
            return true;
        }
        else if (r == -1)
        {
            //printf("errno: %d\n", errno);
            //printf("strerror: %s\n", strerror(errno));

            if (errno == ESRCH)
            {
                //printf("2 pid %d doesn't exist!\n", pid);
                return false;
            }
        }
    }
    //printf("2. pid %d exist!\n", pid);
    return true;
}
#ifdef IR_CUSTOMIZE
typedef enum
{
    _IR_SHOT_P = 0x01,   /// 2'b01: only pshot edge detect for counter
    _IR_SHOT_N = 0x02,   /// 2'b10: only nshot edge detect for counter
    _IR_SHOT_PN = 0x03,  /// 2'b11/2'b00: both pshot/nshot edge detect for counter
    _IR_SHOT_INVLD,      /// Invalid for value greater than 2'b11
} IR_Shot_Sel;
void ExeKeyCode()
{
    printf("This is user keycode\n");
}
static BOOL (*UserKeyCode)(unsigned char* pu8Key,unsigned char* pu8Repeat)=0;
extern  void SetUserSoftwareDecode(bool (*func)(unsigned char* pu8Key,unsigned char* pu8Repeat));
void SetUserSoftwareDecode(bool (*func)(unsigned char* pu8Key,unsigned char* pu8Repeat))
{
    UserKeyCode = func;
}
extern DFBInputDeviceKeymapEntry*  Get_keymap_entry( CoreInputDevice *device, int code );
#endif


    #ifdef MSTARIR_KEYRELEASE_PATCH
    #define REPEAT_TIME 250

    static void*
    MstarIREventThread( DirectThread *thread, void *driver_data )
    {
         MStarIrData *data = (MStarIrData*) driver_data;
         /* Read keyboard data */
     long long start;
     DFBInputEvent lastEvent = {0};
     bool thefirst = true;

	//printf("##################### MstarIREventThread $$$$$$$$$$$$$$$$$$$$$$$$$$  \n");

     DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
     while (1)
     {
            struct timeval tv =
            {
                .tv_sec = 0,
                .tv_usec = 100*1000
            };

            if(direct_thread_is_canceled(thread))
            {
                DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
                direct_thread_testcancel( thread );
                printf("\nthread is not canceled ====%s:%d \n",__FUNCTION__,__LINE__);
                DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
            }

#if 1

        if(lastEvent.flags & (DIEF_REPEAT | DIEF_KEYCODE))
        {
            if(thefirst)
            {
                if(direct_clock_get_millis() - start > data->repeat_time+100)
                {
                    thefirst = false;
                //    printf("the first time out!!!,end=%lld, start = %lld  \n",direct_clock_get_millis(),start);
                    goto sendrelease;
                }
            }
            else if(direct_clock_get_millis() - start > data->repeat_time)
            {

                //printf("time out!!!,end=%lld, start = %lld  \n",direct_clock_get_millis(),start);
                goto sendrelease;
            }
        }
        else
        {
    sendrelease:
            if(!thefirst && lastEvent.type != DIET_UNKNOWN)
            {
#if 0
                DFBInputEvent tempevt;
                memcpy(&tempevt,&lastEvent,sizeof(lastEvent));

                printf("111 type = %x, flags = %x , code = %x \n",lastEvent.type,lastEvent.flags,lastEvent.key_code);
                tempevt.type       = DIET_KEYRELEASE;
                tempevt.flags &= ~DIEF_REPEAT;
                dfb_input_dispatch( data->device, &tempevt);
                memset(&lastEvent,0,sizeof(lastEvent));
#endif
                D_INFO("~!~ DIET_KEYRELEASE type = %x, flags = %x , code = %x \n",lastEvent.type,lastEvent.flags,lastEvent.key_code);
                lastEvent.type       = DIET_KEYRELEASE;
                lastEvent.flags &= ~DIEF_REPEAT;
                dfb_input_dispatch( data->device, &lastEvent);
                lastEvent.type = DIET_UNKNOWN;
                lastEvent.flags = 0;
                //memset(&lastEvent,0,sizeof(lastEvent));
            }
        }
#endif

        fd_set fdset;
        FD_ZERO(&fdset);
        FD_SET(data->fd, &fdset);
        signed int ret;

            DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
            ret = select(data->fd+1, &fdset, NULL, NULL, &tv);
            DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);

            if (ret > 0 && FD_ISSET(data->fd, &fdset))
            {
                unsigned int u32Data;
                unsigned char u8FantasyClass;
                read(data->fd, &u32Data, sizeof(signed int));
                u8FantasyClass=((u32Data>>28)&0xF);
                unsigned int nRept;

				DBG_INPUT_MSG("%s (%d):read_data = 0x%x\n", __FUNCTION__, __LINE__, u32Data);
                switch(u8FantasyClass)
                {
                    case 0x0f:
                    case 0x8:
                    case 0x4:
                    case 0x1: //legacy IR keypad data
                        {
#ifndef IR_CUSTOMIZE

                            DFBInputEvent evt;
                            u8 u8KeyCode;
                            u16 u16KeyCode;

                            u8KeyCode = (u32Data >> 8) & 0xFF;

                            evt.clazz = DFEC_INPUT;
                            evt.flags      = DIEF_KEYCODE;
                            evt.type       = DIET_KEYPRESS;
                            evt.key_id    = DIKI_UNKNOWN;
                            evt.key_symbol = DIKS_NULL;
                            if(u8FantasyClass == 0x4)
                            {
                                evt.key_code = u8KeyCode|(0x1<<8);
                            }
                            else if(u8FantasyClass == 0x8)
                            {
                                evt.key_code = u8KeyCode|(0x1<<9);
                            }
                            else if(u8FantasyClass == 0x1)
                            {
                                evt.key_code = u8KeyCode;
                            }
                            else if(u8FantasyClass == 0xf)
                            {
                                evt.key_code = (u32Data >> 8) & 0x0000ffff;
                            }

                            thefirst = true;
                            if((u32Data & 0xFF) > 0x0)
                            {
                                evt.flags |= DIEF_REPEAT;
                            }

                            memcpy(&lastEvent,&evt,sizeof(evt));
                            D_INFO("~!~ DIET_KEYPRESS type = %x, flags = %x , code = %x \n",lastEvent.type,lastEvent.flags,lastEvent.key_code);
                            dfb_input_dispatch( data->device, &evt);
                            start = direct_clock_get_millis();
/* 
                                                        evt.type       = DIET_KEYRELEASE;
                                                        evt.flags &= ~DIEF_REPEAT;
                                                        dfb_input_dispatch( data->device, &evt);
*/
#endif
#ifdef IR_CUSTOMIZE
                            DFBInputEvent evt;
                            EN_KEY u8KeyCode;

                            //u8KeyCode = (u32Data >> 8) & 0xFF;
                            evt.clazz = DFEC_INPUT;
                            evt.flags      = DIEF_KEYCODE;
                            evt.type       = DIET_KEYPRESS;
                            //evt.key_code = u8KeyCode;

                            U8 u8ShotMode=0;
                            u8ShotMode = (u32Data>>24)&0x0F;

                          //  printf("shot mode = %d\n",u8ShotMode);
                            if(u8ShotMode==0)//HW decode mode
                            {
                                printf("This is HW decode mode \n");

                                u8KeyCode = (u32Data >> 8) & 0xFF;
                                if(u8FantasyClass == 0x4)
                                {
                                    evt.key_code = u8KeyCode|(0x1<<8);
                                }
                                else if(u8FantasyClass == 0x8)
                                {
                                    evt.key_code = u8KeyCode|(0x1<<9);
                                }
                                else if(u8FantasyClass == 0x1)
                                {
                                    evt.key_code = u8KeyCode;
                                }
                                printf("========================================\n");
                                printf("ir key code is: %d\n",u8KeyCode);
                                printf("========================================\n");
                                if((u32Data & 0xFF) > 0x0)
                                {
                                    evt.flags |= DIEF_REPEAT;
                                }
                                dfb_input_dispatch( data->device, &evt);

                            }
                            else if(u8ShotMode==_IR_SHOT_N)
                            {
                                printf("This is sw decode mode \n");

                                unsigned char uRepeat=0;
                                unsigned char u8SWKeyCode=0;
                                if(UserKeyCode)
                                {
                                    printf("UserKeyCode is invoked \n");

                                    UserKeyCode(&u8SWKeyCode,&uRepeat);
                                }
                                else
                                {
                                    printf("UserKeyCode is not invoked \n");
                                    u8SWKeyCode = (u32Data >> 8) & 0xFF;
                                }
                                printf("repeat is %d\n",uRepeat);
                                if(uRepeat==1)
                                {
                                    DFBInputDeviceKeymapEntry *entry=NULL;
                                    if(u8FantasyClass == 0x4)
                                    {
                                        evt.key_code = u8KeyCode|(0x1<<8);
                                    }
                                    else if(u8FantasyClass == 0x8)
                                    {
                                        evt.key_code = u8KeyCode|(0x1<<9);
                                    }
                                    else if(u8FantasyClass == 0x1)
                                    {
                                        evt.key_code = u8KeyCode;
                                    }
                                    printf("========================================\n");
                                    printf("1. evt.key_code is: %d\n",evt.key_code);
                                    printf("========================================\n");
                                    entry = Get_keymap_entry( data->device, evt.key_code );
                                    if(entry)
                                    {
                                        printf("Rept=%d\n",entry->nRept);
                                        if((u32Data & 0xFF) > 0x0)
                                        {
                                            evt.flags |= DIEF_REPEAT;
                                        }
                                        if(evt.flags&&entry->nRept==1)
                                        {
                                            dfb_input_dispatch( data->device, &evt);

                                        }
                                    }
                                    else
                                    {
                                        printf("entry is null\n");
                                    }
                                }
                                else
                                {
                                    if(u8FantasyClass == 0x4)
                                    {
                                        evt.key_code = u8KeyCode|(0x1<<8);
                                    }
                                    else if(u8FantasyClass == 0x8)
                                    {
                                        evt.key_code = u8KeyCode|(0x1<<9);
                                    }
                                    else if(u8FantasyClass == 0x1)
                                    {
                                        evt.key_code = u8KeyCode;
                                    }
                                    printf("========================================\n");
                                    printf("2. evt.key_code is: %d\n",evt.key_code);
                                    printf("========================================\n");
                                    dfb_input_dispatch( data->device, &evt);

                                }
                            }
#endif
                        }
                        break;
                    case    0x2: //relative X,Y ( 0~10 bit for amount, 11 bit for direction)
                        break;
                    case    0x3: //absolute X,Y ( 0~11 bit for amount)
                        break;
                    case   0x6: //legacy IR keypad data for  another header coder(HEAD CODE  TCL)
                  {
#ifndef IR_CUSTOMIZE
                      DFBInputEvent evt;
                      u8 u8KeyCode;

                      evt.key_code  = (u32Data >> 8) & 0xFFFF;

                      evt.clazz = DFEC_INPUT;
                      evt.flags     = DIEF_KEYCODE;
                      evt.type      = DIET_KEYPRESS;
                      evt.key_id    = DIKI_UNKNOWN;
                      evt.key_symbol = DIKS_NULL;
        

                      //printf("06_Fir_dfb.key_code is %d\n",evt.key_code);

                      thefirst = true;
                      if((u32Data & 0xFF) > 0x0)
                      {
                          evt.flags |= DIEF_REPEAT;
                      }

                      memcpy(&lastEvent,&evt,sizeof(evt));
                      dfb_input_dispatch( data->device, &evt);
                      start = direct_clock_get_millis();


#endif
                  }
                    break;

                    default:
                        break;
                }

            }

        }
        DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
         return NULL;
    }


    #else
    static void*
    MstarIREventThread( DirectThread *thread, void *driver_data )
    {
         MStarIrData *data = (MStarIrData*) driver_data;
         /* Read keyboard data */

         
         DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
         while (1)
         {
            struct timeval tv =
            {
                .tv_sec = 0,
                .tv_usec = 100*1000
            };

            if(direct_thread_is_canceled(thread))
            {
                DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
                direct_thread_testcancel( thread );
                printf("\nthread is not canceled ====%s:%d \n",__FUNCTION__,__LINE__);
                DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);
            }

            fd_set fdset;
            FD_ZERO(&fdset);
            FD_SET(data->fd, &fdset);
            signed int ret;

            DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
            ret = select(data->fd+1, &fdset, NULL, NULL, &tv);
            DFB_GLOBAL_LOCK(DFB_LOCK_FOR_EXEC);


            if (ret > 0 && FD_ISSET(data->fd, &fdset))
            {
                unsigned int u32Data;
                unsigned char u8FantasyClass;
                read(data->fd, &u32Data, sizeof(signed int));
                u8FantasyClass=((u32Data>>28)&0xF);
                unsigned int nRept;

                switch(u8FantasyClass)
                {
                    case 0x0f:
                    case 0x8:
                    case 0x4:
                    case 0x1: //legacy IR keypad data
                        {
#ifndef IR_CUSTOMIZE
                            DFBInputEvent evt;
                            u8 u8KeyCode;
                            u16 u16KeyCode;

                            u8KeyCode = (u32Data >> 8) & 0xFF;

                            evt.clazz = DFEC_INPUT;
                            evt.flags      = DIEF_KEYCODE;
                            evt.type       = DIET_KEYPRESS;
                            evt.key_id    = DIKI_UNKNOWN;
                            evt.key_symbol = DIKS_NULL;
                            if(u8FantasyClass == 0x4)
                            {
                                evt.key_code = u8KeyCode|(0x1<<8);
                            }
                            else if(u8FantasyClass == 0x8)
                            {
                                evt.key_code = u8KeyCode|(0x1<<9);
                            }
                            else if(u8FantasyClass == 0x1)
                            {
                                evt.key_code = u8KeyCode;
                            }
                            else if(u8FantasyClass == 0xf)
                            {
                                evt.key_code = (u32Data >> 8) & 0x0000ffff;
                            }

                            if((u32Data & 0xFF) > 0x0)
                            {
                                evt.flags |= DIEF_REPEAT;
                            }

                            dfb_input_dispatch( data->device, &evt);

                             evt.type       = DIET_KEYRELEASE;
                             evt.flags &= ~DIEF_REPEAT;
                             dfb_input_dispatch( data->device, &evt);
#endif
#ifdef IR_CUSTOMIZE
                            DFBInputEvent evt;
                            EN_KEY u8KeyCode;
                            //u8KeyCode = (u32Data >> 8) & 0xFF;
                            evt.clazz = DFEC_INPUT;
                            evt.flags      = DIEF_KEYCODE;
                            evt.type       = DIET_KEYPRESS;
                            //evt.key_code = u8KeyCode;

                            U8 u8ShotMode=0;
                            u8ShotMode = (u32Data>>24)&0x0F;

                          //  printf("shot mode = %d\n",u8ShotMode);
                            if(u8ShotMode==0)//HW decode mode
                            {
                                printf("This is HW decode mode \n");

                                u8KeyCode = (u32Data >> 8) & 0xFF;
                                if(u8FantasyClass == 0x4)
                                {
                                    evt.key_code = u8KeyCode|(0x1<<8);
                                }
                                else if(u8FantasyClass == 0x8)
                                {
                                    evt.key_code = u8KeyCode|(0x1<<9);
                                }
                                else if(u8FantasyClass == 0x1)
                                {
                                    evt.key_code = u8KeyCode;
                                }
                                printf("========================================\n");
                                printf("ir key code is: %d\n",u8KeyCode);
                                printf("========================================\n");
                                if((u32Data & 0xFF) > 0x0)
                                {
                                    evt.flags |= DIEF_REPEAT;
                                }
                                dfb_input_dispatch( data->device, &evt);
                                evt.type       = DIET_KEYRELEASE;
                                dfb_input_dispatch( data->device, &evt);
                            }
                            else if(u8ShotMode==_IR_SHOT_N)
                            {
                                printf("This is sw decode mode \n");

                                unsigned char uRepeat=0;
                                unsigned char u8SWKeyCode=0;
                                if(UserKeyCode)
                                {
                                    printf("UserKeyCode is invoked \n");

                                    UserKeyCode(&u8SWKeyCode,&uRepeat);
                                }
                                else
                                {
                                    printf("UserKeyCode is not invoked \n");
                                    u8SWKeyCode = (u32Data >> 8) & 0xFF;
                                }
                                printf("repeat is %d\n",uRepeat);
                                if(uRepeat==1)
                                {
                                    DFBInputDeviceKeymapEntry *entry=NULL;
                                    if(u8FantasyClass == 0x4)
                                    {
                                        evt.key_code = u8KeyCode|(0x1<<8);
                                    }
                                    else if(u8FantasyClass == 0x8)
                                    {
                                        evt.key_code = u8KeyCode|(0x1<<9);
                                    }
                                    else if(u8FantasyClass == 0x1)
                                    {
                                        evt.key_code = u8KeyCode;
                                    }
                                    printf("========================================\n");
                                    printf("1. evt.key_code is: %d\n",evt.key_code);
                                    printf("========================================\n");
                                    entry = Get_keymap_entry( data->device, evt.key_code );
                                    if(entry)
                                    {
                                        printf("Rept=%d\n",entry->nRept);
                                        if((u32Data & 0xFF) > 0x0)
                                        {
                                            evt.flags |= DIEF_REPEAT;
                                        }
                                        if(evt.flags&&entry->nRept==1)
                                        {
                                            dfb_input_dispatch( data->device, &evt);
                                            evt.type       = DIET_KEYRELEASE;
                                            dfb_input_dispatch( data->device, &evt);
                                        }
                                    }
                                    else
                                    {
                                        printf("entry is null\n");
                                    }
                                }
                                else
                                {
                                    if(u8FantasyClass == 0x4)
                                    {
                                        evt.key_code = u8KeyCode|(0x1<<8);
                                    }
                                    else if(u8FantasyClass == 0x8)
                                    {
                                        evt.key_code = u8KeyCode|(0x1<<9);
                                    }
                                    else if(u8FantasyClass == 0x1)
                                    {
                                        evt.key_code = u8KeyCode;
                                    }
                                    printf("========================================\n");
                                    printf("2. evt.key_code is: %d\n",evt.key_code);
                                    printf("========================================\n");
                                    dfb_input_dispatch( data->device, &evt);
                                    evt.type       = DIET_KEYRELEASE;
                                    dfb_input_dispatch( data->device, &evt);
                                }
                            }
#endif
                        }
                        break;
                    case    0x2: //relative X,Y ( 0~10 bit for amount, 11 bit for direction)
                        break;
                    case    0x3: //absolute X,Y ( 0~11 bit for amount)
                        break;
                    case   0x6: //legacy IR keypad data for  another header coder(HEAD CODE  TCL)
                  {
#ifndef IR_CUSTOMIZE
                      DFBInputEvent evt;
                      u8 u8KeyCode;

                      evt.key_code  = (u32Data >> 8) & 0xFFFF;

                      evt.clazz = DFEC_INPUT;
                      evt.flags     = DIEF_KEYCODE;
                      evt.type      = DIET_KEYPRESS;
                      evt.key_id    = DIKI_UNKNOWN;
                      evt.key_symbol = DIKS_NULL;
                      //evt.key_code = u8KeyCode|0x100;
                      //evt.key_code = evt.key_code & 0x00FF;

                      printf("06_11Fir_dfb.key_code is %x\n",evt.key_code);

                      if((u32Data & 0xFF) > 0x0)
                        {
                             evt.flags |= DIEF_REPEAT;
                        }

                      dfb_input_dispatch( data->device, &evt);

                      printf("06_11Fir_dfb.key_symbol is %x\n",evt.key_symbol);

                      evt.type      = DIET_KEYRELEASE;
                      evt.flags &= ~DIEF_REPEAT;
                      dfb_input_dispatch( data->device, &evt);
#endif
                  }
                    break;
                    default:
                        break;
                }

            }

        }
        DFB_GLOBAL_UNLOCK(DFB_LOCK_FOR_EXEC);
         return NULL;
    }
    #endif


#endif

static DFBResult
driver_open_device( CoreInputDevice *device,
                    unsigned int    number,
                    InputDeviceInfo *info,
                    void            **driver_data )
{

#if (DFB_MSTAR_HOST_IR)
     MStarIrData *data;
     int fd;

     data = D_CALLOC(1, sizeof(MStarIrData));
     data->device = device;
     /* set private data pointer */
     *driver_data = data;

     fd = open(DEVICE, O_RDWR);
     if (fd > 0)
     {
          pid_t masterIrPid = getpid();
          int flag = 1;
          ioctl(fd, MDRV_IR_GET_MASTER_PID, &masterIrPid);

            // if master ir doesn't exist, set this as the mater ir
            if (_CheckProcessExist(masterIrPid) == false)
            {
                pid_t masterIrPid = getpid();
                // init IR
                ioctl(fd, MDRV_IR_INIT);
                ioctl(fd, MDRV_IR_SET_MASTER_PID, &masterIrPid);
            }
            ioctl(fd, MDRV_IR_ENABLE_IR, &flag);
   }
   else
   {
         DEBUG_IR(printf("Fail to open IR Kernal Module\n"));
         D_FREE(data);
         return DFB_FAILURE;
   }
   data->fd = fd;
   data->repeat_time= REPEAT_TIME;

#else
     /* allocate and fill private data */
     //MStarIrData* data = D_CALLOC(1, sizeof(MStarIrData));
     data = D_CALLOC(1, sizeof(MStarIrData));
     data->device = device;
     /* set private data pointer */
     *driver_data = data;

    if(dfb_config->mst_dfb_register_app_manager)
          MAdp_APMNG_Init();

     MAdp_IR_Init();

    // Set IR callback function
    // Set the key delay time
     MAdp_IR_Set_Callback(mstarir_callback);

   if(dfb_config->mst_dfb_register_app_manager && MAdp_SYS_HasNexus())
    {
        APP_REGISTER_INFO stAppReg;
        stAppReg.enType = KEY_DISPATCH_APP;
        stAppReg.suspend = NULL;
        stAppReg.resume = NULL;
        stAppReg.exit = NULL;
        MAdp_APMNG_AppRegister(&stAppReg);
    }


     direct_util_recursive_pthread_mutex_init( &data->ir_mutex );
     data->ir_events = NULL;
#if DFB_HISENSE_MOUSE
     data->mouse_events = NULL;
     data->sensitive_numerator = 1;
     data->sensitive_denominator = 1;
     data->rel_axis_x_motion_reminder = 0;
     data->rel_axis_y_motion_reminder = 0;
     MAdp_Mouse_Set_Callback(mstar_mouse_callback);

#endif
     
     data->fd     = MAdp_IR_GetFD();
     data->repeat_time = REPEAT_TIME;  
     {
         key_t sem_key;
         sem_key = ftok("/mstarir",0);
         mstarir_semid = sem_creat(sem_key);
     }
     MAdp_IR_EnableIR(TRUE);

#endif

     /* fill driver info structure */
     snprintf( info->desc.name,
               DFB_INPUT_DEVICE_DESC_NAME_LENGTH, "MSTARIR Device" );

     snprintf( info->desc.vendor,
               DFB_INPUT_DEVICE_DESC_VENDOR_LENGTH, "MStar Semi" );

     info->prefered_id = DIDID_MSTARIR;

     info->desc.type   = DIDTF_REMOTE;
     info->desc.caps   = DICAPS_KEYS;

     info->desc.min_keycode = 0;
     info->desc.max_keycode = dfb_config->mst_ir_max_keycode;  //0x7FFF;

     /* start input thread */

     data->thread = direct_thread_create( DTT_INPUT, MstarIREventThread, data, "MStar IR" );
#if !(DFB_MSTAR_HOST_IR)
     if(start_system_polling())
     {
         D_FREE(data);
         return DFB_FAILURE;
     }
#endif

     return DFB_OK;
}

/*
 * Fetch one entry from the device's keymap if supported.
 */
static DFBResult
driver_get_keymap_entry( CoreInputDevice           *device,
                         void                      *driver_data,
                         DFBInputDeviceKeymapEntry *entry )
{
#if DFB_BUILD_FOR_PRJ_OBAMA
     struct Mstar_ircode_trans* ircode_trans_node;
     EN_KEY key = entry->code;

     ircode_trans_node = bsearch(&key, transform_ircode,
        sizeof(transform_ircode) / sizeof(transform_ircode[0]) ,
        sizeof(transform_ircode[0]), compare_ircode );

     if ( ircode_trans_node == NULL )
        return DFB_FAILURE;

     /* get the identifier for basic mapping */
     entry->identifier = ircode_trans_node->identifier;

     /* get symbol to entry */
     entry->symbols[DIKSI_BASE] = ircode_trans_node->symbol;

     entry->symbols[DIKSI_BASE_SHIFT] = DIKS_NULL;
     entry->symbols[DIKSI_ALT] = DIKS_NULL;
     entry->symbols[DIKSI_ALT_SHIFT] = DIKS_NULL;

     return DFB_OK;
#else
     return DFB_UNSUPPORTED;
#endif
}


static void
driver_close_device( void *driver_data )
{
     MStarIrData *data = (MStarIrData*) driver_data;
#if !(DFB_MSTAR_HOST_IR)
     //MAdp_IR_EnableIR(FALSE);
     stop_system_polling();
     if(dfb_config->mst_dfb_register_app_manager)
             MAdp_APMNG_DeInit();

     mstarir_sem_signal(mstarir_semid);
#endif
     direct_thread_cancel( data->thread );
#if !(DFB_MSTAR_HOST_IR)
     mstarir_sem_signal(mstarir_semid);
#endif
     direct_thread_join( data->thread );
     direct_thread_destroy( data->thread );
     /* close socket */
     close( data->fd );
#if !(DFB_MSTAR_HOST_IR)
//remove semaphore
    del_sem(mstarir_semid);
    MstarIREvtItem *ir_evt, *ir_tmp;
   direct_list_foreach_safe (ir_evt, ir_tmp, data->ir_events)
   {
                direct_list_remove( &data->ir_events, &ir_evt->link );
                D_FREE( ir_evt );

   }
#if DFB_HISENSE_MOUSE
   HisMouseEvtItem *ms_evt, *ms_tmp;
   direct_list_foreach_safe (ms_evt, ms_tmp, data->mouse_events)
   {
            direct_list_remove( &data->mouse_events, &ms_evt->link );
            D_FREE( ms_evt );

   }
#endif

    pthread_mutex_destroy( &data->ir_mutex );
#endif
     /* free private data */
    D_FREE( data );
}

static DFBResult
driver_device_ioctl( CoreInputDevice              *device,
                      void                         *driver_data,
                     InputDeviceIoctlData *param)
{
     MStarIrData *data = (MStarIrData*) driver_data;


     if(MDRV_DFB_IOC_MAGIC!= _IOC_TYPE(param->request))
         return DFB_INVARG;

     switch(param->request)
     {
       case DFB_DEV_IOC_SET_MSTARIR_REPEAT_TIME:
          if(((int)param->param[0])<=0)
              return DFB_INVARG;
          data->repeat_time= ((int)param->param[0]);
          printf("[DFB] Mstarir Set repeat time:%d (ms)", data->repeat_time);
          break;
          
       case DFB_DEV_IOC_GET_MSTARIR_REPEAT_TIME:
          memset(param->param, 0, sizeof(param->param));
          param->param[0] = data->repeat_time;
          printf("[DFB] Mstarir Get repeat time:%d (ms)", data->repeat_time);
          break;
        
#if DFB_HISENSE_MOUSE
       case DFB_DEV_IOC_SET_REL_AXIS_SENSE_NUMERATOR:
          if(((int)param->param[0])<=0)
              return DFB_INVARG;
          data->sensitive_numerator = ((int)param->param[0]);
          data->rel_axis_x_motion_reminder = data->rel_axis_y_motion_reminder = 0;
          break;
       case DFB_DEV_IOC_SET_REL_AXIS_SENSE_DENOMINATOR:
          if(((int)param->param[0])<=0)
              return DFB_INVARG;
          data->sensitive_denominator = ((int)param->param[0]);
          data->rel_axis_x_motion_reminder = data->rel_axis_y_motion_reminder = 0;
          break;
#endif
       default:
          return DFB_UNSUPPORTED;
     }

     return DFB_OK;
}

