#include <asm/jz4730/regs.h>
#include <asm/jz4730/ops.h>


///#define SCAN_USE_TIMER 1

#if 0				//wjx
#define DBG(args...) printk(args)
#else
#define DBG(args...)
#endif


#define SCANHZ (HZ/20)

#define CAPSLOCKLED 27		//wjx 2007.12.10
#define NUMLOCKLED  86

static int capslock_flag = 0;	// wjx
static int numlock_flag = 0;
static int fn_f5_flag = 0;

/* KBD */
static struct input_dev *kbd_dev;
//static int kbd_thread_pid = -1;
#ifdef SCAN_USE_TIMER
struct timer_list scan_timer;
#else
static int kbd_start = 0;
static int kbd_tick = 0;
#endif
static int kbd_refcount = 0;

#if 1
const static unsigned int key_c[] = {
        /*     0  1  2  3  4   5   6   7   8   9  10   11  12  13  14  15  16   */
        96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
        125,
};

const static unsigned int key_r[] = {
        0, 1, 2, 3, 4, 5, 6, 7
};
#else
const static unsigned int key_c[] = {
        /*     0   1  2  3 4 5  6  7  8  9  10 11 12  13  14  15  16   */
        104, 97, 106, 6, 2, 5, 102, 1, 96, 111, 98, 7, 4, 110, 105, 125, 109,
};

const static unsigned int key_r[] = {
        3, 103, 100, 0, 108, 101, 99, 107,
};
#endif

#define KB_SCAN_LINE (sizeof(key_c)/sizeof(*key_c))

static unsigned char last_keys[KB_SCAN_LINE];
static unsigned char cur_keys[KB_SCAN_LINE];

#define KEY_FN 0

const static int kmap[KB_SCAN_LINE][8] = {
        /* 0*/ {KEY_PAUSE, 0, 0, 0, 0, 0, KEY_LEFTCTRL, KEY_F5,},
        /* 1*/ {KEY_Q, KEY_TAB, KEY_A, KEY_ESC, KEY_Z, 0, KEY_GRAVE, KEY_1,},
        /* 2*/ {KEY_W, KEY_CAPSLOCK, KEY_S, KEY_102ND, KEY_X, 0, 0, KEY_2,},//CZJ delet the KEY_BACKSLASH
        /* 3*/ {KEY_E, KEY_F3, KEY_D, KEY_F4, KEY_C, 0, 0, KEY_3,},
        /* 4*/ {KEY_R, KEY_T, KEY_F, KEY_G, KEY_V, KEY_B, KEY_5, KEY_4,},
        /* 5*/ {KEY_U, KEY_Y, KEY_J, KEY_H, KEY_M, KEY_N, KEY_6, KEY_7,},
        /* 6*/ {KEY_I, KEY_RIGHTBRACE, KEY_K, KEY_F6, KEY_COMMA, 0, KEY_EQUAL,
                KEY_8,},
        /* 7*/ {KEY_O, KEY_F7, KEY_L, 0, KEY_DOT, KEY_F19, KEY_F8, KEY_9,},
        /* 8*/ {0, 0, 0, KEY_SPACE, KEY_NUMLOCK, 0, KEY_DELETE, 0,},
        /* 9*/ {0, KEY_BACKSPACE, 0, 0, KEY_ENTER, 0, KEY_F9, 0,},
        /*10*/ {0, 0, 0, KEY_LEFTALT, 0, 0, 0, KEY_SYSRQ,},
        /*11*/ {KEY_P, KEY_LEFTBRACE, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_BACKSLASH,
                KEY_SLASH, KEY_MINUS, KEY_0,},
        /*12*/ {KEY_KP0, KEY_F20, KEY_KP1, KEY_KP2, KEY_KP3, KEY_KP4, KEY_KP5, KEY_F10,}, //CZJ ADD NUM PACK 
        /*13*/ {KEY_KP6, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KPPLUS, KEY_KPMINUS, KEY_F2, KEY_KPSLASH,}, //CZJ ADD NUM PACK
        /*14*/ {KEY_KPDOT, KEY_KPASTERISK, 0, 0, 0, 0, KEY_INSERT, 0,},  //CZJ ADD NUM PACK
        /*15*/ {0, 0, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, 0, 0,},
        /*16*/ {0, KEY_LEFTSHIFT, KEY_RIGHTSHIFT, 0, 0, 0, KEY_F1, KEY_FN,},
};

static int
xy2code (int col, int row)
{
        if ((col < KB_SCAN_LINE) && (row < 8))
        return kmap[col][row];
        else
        return 0;
}

#define KB_SCAN_LINE (sizeof(key_c)/sizeof(*key_c))

static void
setup_keybd (void)
{
        int i;
        
        for (i = 0; i < sizeof (key_r) / sizeof (*key_r); i++)
        {
                __gpio_as_input (key_r[i]);
                __gpio_disable_pull (key_r[i]);
        }
        
        __gpio_as_input (8);		/* key_int */
        
        for (i = 0; i < KB_SCAN_LINE; i++)
        {
                __gpio_as_output (key_c[i]);
                __gpio_clear_pin (key_c[i]);
        }
        
        __gpio_as_output (NUMLOCKLED);	//wjx 2007.12.10
        __gpio_set_pin (NUMLOCKLED);
        
        __gpio_as_output (CAPSLOCKLED);
        __gpio_set_pin (CAPSLOCKLED);
        
}

#define kb_scan_delay() udelay(3)

static int
scan_keybd (unsigned char *kr)
{
        int i, k;
        
        for (i = 0; i < 8; i++)
        {
                
                if (!__gpio_get_pin (key_r[i]))
                {
                        for (k = 0; k < KB_SCAN_LINE; k++)
                        {
                                __gpio_set_pin (key_c[k]);
                                kb_scan_delay ();
                                if (__gpio_get_pin (key_r[i]))
                                {
                                        if (kmap[k][i] == 0)
                                        DBG ("input [%d] %d\n", k, i);
                                        kr[k] |= (1U << i);
                                }
                                __gpio_clear_pin (key_c[k]);
                        }
                }
        }
        
        return (int) __gpio_get_pin (8);
}

static void scan_kbd (unsigned long);

static void
start_scan_timer (void)
{
        #ifdef SCAN_USE_TIMER
        
        scan_timer.expires = jiffies + SCANHZ;
        scan_timer.data = 0;
        scan_timer.function = scan_kbd;
        add_timer (&scan_timer);
        #else
        kbd_start = 1;
        #endif
}


static void
set_capslock_led ()
{
        
        capslock_flag = !capslock_flag;
        
        if (capslock_flag)
        {
                __gpio_clear_pin (CAPSLOCKLED);
        }
        else
        {
                __gpio_set_pin (CAPSLOCKLED);
        }
}

static void
set_numlock_led ()
{
        numlock_flag = !numlock_flag;
        
        if (numlock_flag)
        {
                __gpio_clear_pin (NUMLOCKLED);
        }
        else
        {
                __gpio_set_pin (NUMLOCKLED);
        }
}


/*for the "left-right" buttons beside touch pad.edwin*/
/*define gpio pin*/
#define TP_MOUSE_RIGHT 13
#define TP_MOUSE_LEFT  16

int left_up = 1;
int right_up = 1;

static struct input_dev *tp_mouse_dev;


static int
tp_mouse_event (struct input_dev *dev, unsigned int type, unsigned int code,
int value)
{
        return 1;
}

static int
tp_mouse_open (struct input_dev *dev)
{
        return 1;
}

static void
scan_mouse_left (void)
{
        int state;
        
        if (left_up != (state = __gpio_get_pin (TP_MOUSE_LEFT)))
        {
                left_up = state;
                input_report_key (tp_mouse_dev, BTN_LEFT, state);
        }
}

static void
scan_mouse_right (void)
{
        int state;
        if (right_up != (state = __gpio_get_pin (TP_MOUSE_RIGHT)))
        {
                right_up = state;
                input_report_key (tp_mouse_dev, BTN_RIGHT, state);
        }
}


static int
tp_mouse_setup (void)
{
        int retval;
        
        if (NULL ==
        (tp_mouse_dev = kmalloc (sizeof (struct input_dev), GFP_KERNEL)))
        return -ENOMEM;
        
        /*init gpio */
        __gpio_as_input (TP_MOUSE_LEFT);
        __gpio_disable_pull (TP_MOUSE_LEFT);
        __gpio_as_input (TP_MOUSE_RIGHT);
        __gpio_disable_pull (TP_MOUSE_RIGHT);
        
        memset (tp_mouse_dev, 0, sizeof (struct input_dev));
        
        tp_mouse_dev->evbit[0] = BIT (EV_KEY) | BIT (EV_REL);
        tp_mouse_dev->keybit[LONG (BTN_MOUSE)] = BIT (BTN_LEFT) | BIT (BTN_RIGHT);
        tp_mouse_dev->relbit[0] = BIT (REL_X);
        
        input_register_device (tp_mouse_dev);
        
        return 0;
}

static void
tp_mouse_exit (void)
{
        if (tp_mouse_dev)
        {
                input_unregister_device (tp_mouse_dev);
                kfree (tp_mouse_dev);
        }
}

/* end */
//wjx Fn + F5 change the lcd backlight 
extern inline void __lcd_set_backlight_level (int n);

static void
scan_kbd (unsigned long dummy)
{
        int col, scancode;
        static int testcode = KEY_RESERVED;
        int state;
        int lcd_pwm_dut, key_down_flag = 0;
        
        dummy = dummy;
        
        memset (cur_keys, 0, sizeof (cur_keys));
        scan_keybd (cur_keys);
        for (col = 0; col < KB_SCAN_LINE; col++)
        {
                unsigned char change = cur_keys[col] ^ last_keys[col];
                if (change)
                {
                        int row;
                        for (row = 0; row < 8; row++)
                        {
                                if (((1U << row) & change) && (scancode = xy2code (col, row)))
                                {
                                        DBG ("KB  col=%d row=%d %d\n", col, row, scancode);
                                        if (cur_keys[col] & (1U << row))
                                        {
                                                key_down_flag = 1;
                                        }
                                        else
                                        {
                                                key_down_flag = 0;
                                        }
                                        if (last_keys[16] & (1 << 7))
                                        {		// Fn key down
                                                
                                                extern void keyboard_set_codec_volume (int);
                                                switch (scancode)
                                                {
                                                        case KEY_F1:
                                                        scancode = KEY_F11;
                                                        break;
                                                        case KEY_F2:
                                                        scancode = KEY_F12;
                                                        break;
                                                        case KEY_F10:
                                                        scancode = KEY_SCROLLLOCK;
                                                        break;
                                                        case KEY_UP:
                                                        scancode = KEY_PAGEUP;
                                                        break;
                                                        case KEY_DOWN:
                                                        scancode = KEY_PAGEDOWN;
                                                        break;
                                                        case KEY_LEFT:
                                                        scancode = KEY_HOME;
                                                        break;
                                                        case KEY_RIGHT:
                                                        scancode = KEY_END;
                                                        break;
                                                        
                                                        case KEY_MINUS:
                                                        if (key_down_flag)
                                                        keyboard_set_codec_volume (0);
                                                        scancode = KEY_RESERVED;	//wjx filter the - key     
                                                        break;
                                                        case KEY_EQUAL:
                                                        if (key_down_flag)
                                                        keyboard_set_codec_volume (1);
                                                        scancode = KEY_RESERVED;	//wjx filter the = key 
                                                        break;
                                                        
                                                        case KEY_F5:
                                                        if (key_down_flag && !(cur_keys[0] & (1U << 6) && cur_keys[16] & (1U << 6)))	// wjx 2008.2.27 change the lcd light (filter Fn + Ctrl + F1 change light )
                                                        {
                                                                #if 0
                                                                lcd_pwm_dut = REG_PWM_DUT (0) + 60;
                                                                if (lcd_pwm_dut > 300)
                                                                lcd_pwm_dut = 0;
                                                                __lcd_set_backlight_level (lcd_pwm_dut);
                                                                #else
                                                                if (REG_PWM_DUT (0) != 0)
                                                                {
                                                                        __lcd_set_backlight_level (0);	//wjx close the lcd backlight                           
                                                                }
                                                                else
                                                                {
                                                                        __lcd_set_backlight_level (300);	//wjx open the backlight                                
                                                                }
                                                                #endif
                                                                fn_f5_flag = 1;
                                                        }
                                                        else
                                                        {
                                                                fn_f5_flag = 0;
                                                        }
                                                        scancode = KEY_RESERVED;	//wjx filter the F5 key
                                                        break;
                                                        case KEY_F20:
                                                        if (key_down_flag && cur_keys[16] & (1U << 7))	// wjx 2008.5.19 change close the lcd back light
                                                        {
                                                                if (REG_PWM_DUT (0) != 0)
                                                                {
                                                                        __lcd_set_backlight_level (0);
                                                                }
                                                                else
                                                                {
                                                                        __lcd_set_backlight_level (300);
                                                                }
                                                        }
                                                        scancode = KEY_RESERVED;	//wjx filter the F5 key
                                                        break;
                                                        #if 0
                                                        case KEY_F9:
                                                        if (cur_keys[col] & (1U << row))
                                                        testcode++;
                                                        scancode = testcode;
                                                        if (testcode == KEY_MAX)
                                                        testcode = KEY_RESERVED;
                                                        break;
                                                        #endif
                                                }
                                        }
                                        if (scancode == KEY_CAPSLOCK && key_down_flag)	//wjx
                                        {
                                                set_capslock_led ();
                                        }
                                        
                                        if (scancode == KEY_NUMLOCK && key_down_flag)
                                        {
                                                set_numlock_led ();
                                        }
                                        
                                        if (numlock_flag)	//wjx 2008.2.25 add numlock keyboard function
                                        {
                                                switch (scancode)
                                                {
                                                        case KEY_7:                     
                                                        scancode = KEY_KP7;        
                                                        break;
                                                        case KEY_8:                     
                                                        scancode = KEY_KP8;        
                                                        break;
                                                        case KEY_9:                     
                                                        scancode = KEY_KP9;                               
                                                        break;
                                                        #if 0
                                                        case KEY_0:
                                                        if (key_down_flag)
                                                        {
                                                                input_report_key (kbd_dev, KEY_RIGHTSHIFT, 1);
                                                                scancode = KEY_8;
                                                        }
                                                        else
                                                        {
                                                                input_report_key (kbd_dev, KEY_8, 0);
                                                                scancode = KEY_KPRIGHTSHIFT;
                                                        }
                                                        break;
                                                        #endif
                                                        case KEY_0:
                                                        scancode = KEY_KPASTERISK;
                                                        break;
                                                        case KEY_U:
                                                        scancode = KEY_KP4; 
                                                        break;
                                                        case KEY_I:
                                                        scancode = KEY_KP5;
                                                        break;
                                                        case KEY_O:
                                                        scancode = KEY_KP6;
                                                        break;
                                                        case KEY_P:
                                                        scancode = KEY_KPMINUS;
                                                        break;
                                                        
                                                        case KEY_J:
                                                        scancode = KEY_KP1;
                                                        break;
                                                        case KEY_K:
                                                        scancode = KEY_KP2;
                                                        break;
                                                        case KEY_L:
                                                        scancode = KEY_KP3;
                                                        break;
                                                        #if 0
                                                        case KEY_SEMICOLON:
                                                        if (key_down_flag)
                                                        {
                                                                input_report_key (kbd_dev, KEY_RIGHTSHIFT, 1);
                                                                scancode = KEY_EQUAL;
                                                        }
                                                        else
                                                        {
                                                                input_report_key (kbd_dev, KEY_EQUAL, 0);
                                                                scancode = KEY_RIGHTSHIFT;
                                                        }
                                                        break;
                                                        #endif
                                                        case KEY_SEMICOLON:
                                                        scancode = KEY_KPPLUS;
                                                        break;
                                                        case KEY_SLASH:
                                                        scancode = KEY_KPSLASH;
                                                        break;
                                                        case KEY_M:
                                                        scancode = KEY_KP0;
                                                        break;
                                                        case KEY_DOT:
                                                        scancode = KEY_KPDOT;
                                                        break;
                                                        //      case KEY_SLASH:  scancode = KEY_SLASH;  break;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
                                                }
                                        }
                                        
                                        
                                        if (scancode == KEY_F5 && fn_f5_flag)	//wjx filter the fn + f5 key 
                                        {
                                                scancode = KEY_RESERVED;
                                                fn_f5_flag = 0;
                                        }
                                        if (scancode == KEY_F20)
                                        scancode = KEY_RESERVED;	//wjx filter the "zzz" key                                                                                                                                      
                                        
                                        if (scancode != KEY_RESERVED)
                                        input_report_key (kbd_dev, scancode,
                                        (cur_keys[col] & (1U << row)) ? 1 : 0);
                                }
                        }
                        last_keys[col] = cur_keys[col];
                }
        }
        
        /*for the "left-right" buttons beside touch pad.edwin */
        scan_mouse_left ();
        scan_mouse_right ();
        /*end */
        
        start_scan_timer ();
}

#ifndef SCAN_USE_TIMER
void
minipc_kbd_on_timer (void)
{
        if (kbd_start)
        {
                kbd_tick++;
                kbd_tick %= SCANHZ;
                if (0 == kbd_tick)
                {
                        scan_kbd (0);
                }
        }
}
#endif

static int
kbd_open (struct input_dev *dev)
{
        DBG ("%s %d\n", __FUNCTION__, kbd_refcount);
        if (0 == kbd_refcount)
        {
                #ifdef SCAN_USE_TIMER
                //memset (last_keys, 0, sizeof(last_keys));
                init_timer (&scan_timer);
                
                start_scan_timer ();
                #endif
        }
        
        kbd_refcount++;
        return 0;
}

static void
kbd_close (struct input_dev *dev)
{
        DBG ("%s %d\n", __FUNCTION__, kbd_refcount);
        kbd_refcount--;
        if (0 == kbd_refcount)
        {
                #ifdef SCAN_USE_TIMER
                del_timer (&scan_timer);
                #endif
        }
}

static int
kbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
int value)
{
        return -1;
}

static int Fn_scancode[] =
{ KEY_F11, KEY_F12, KEY_SCROLLLOCK, KEY_PAGEUP, KEY_PAGEDOWN, KEY_HOME,
        KEY_END, };

int __init
minipc_kbd_init (void)
{
        int nr;
        int i, j;
        
        DBG ("%s 1\n", __FUNCTION__);
        setup_keybd ();
        DBG ("%s 2\n", __FUNCTION__);
        
        if (NULL == (kbd_dev = kmalloc (sizeof (*kbd_dev), GFP_KERNEL)))
        return -ENOMEM;
        
        memset (kbd_dev, 0, sizeof (*kbd_dev));
        set_bit (EV_KEY, (kbd_dev->evbit));
        set_bit (EV_REP, (kbd_dev->evbit));
        DBG ("%s 3.2\n", __FUNCTION__);
        for (i = 0; i < KB_SCAN_LINE; i++)
        {
                for (j = 0; j < 8; j++)
                {
                        if (kmap[i][j])
                        set_bit (kmap[i][j], (kbd_dev->keybit));
                }
        }
        for (i = 0; i < (sizeof (Fn_scancode) / sizeof (Fn_scancode[0])); i++)
        set_bit (Fn_scancode[i], (kbd_dev->keybit));
        
        clear_bit (0, kbd_dev->keybit);
        
        kbd_dev->event = kbd_event;
        kbd_dev->open = kbd_open;
        kbd_dev->close = kbd_close;
        
        input_register_device (kbd_dev);
        /*for the "left-right" buttons beside touch pad.edwin */
        tp_mouse_setup ();
        DBG ("%s 4 %p\n", __FUNCTION__, kbd_dev->handle);
        #ifndef SCAN_USE_TIMER
        kbd_start = 1;
        #endif
        return 0;
}

static int __init
mod_minipc_kbd_init (void)
{
        #ifdef CONFIG_MINIPC_GPIOKB_MODULE
        minipc_kbd_init ();
        #endif
}

static void __exit
minipc_kbd_exit (void)
{
        DBG ("%s 1\n", __FUNCTION__);
        if (kbd_dev)
        {
                input_unregister_device (kbd_dev);
                kfree (kbd_dev);
        }
        /*for the "left-right" buttons beside touch pad.edwin */
        tp_mouse_exit ();
}

module_init (mod_minipc_kbd_init) module_exit (minipc_kbd_exit);
Topic revision: r1 - 14 Sep 2008 - 13:15:33 - ArdVanBreemen
 
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback