📄 mb9260_kbd.c
字号:
/* * Keyboard driver for moblle9260. * * Copyright (c) 2008 liulf, liulf@ihep.ac.cn * Based on aaed2000_kbd.c. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/init.h>#include <linux/input-polldev.h>#include <linux/interrupt.h>#include <linux/jiffies.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/wfos_debug.h>#include <linux/wfos_iomem.h>#include <mach/hardware.h>#define NR_SCANCODES (128)#define SCAN_INTERVAL (50) /* ms */#define KEYBOARD_PHY_BASE0 0x30000040 /* key1 ~ key16 */#define KEYBOARD_PHY_BASE1 0x30000060 /* key17 ~ key32 */#if 0static unsigned char KEY0_MAP[1] = { KEY_0,};static unsigned char KEY1_MAP[1] = { KEY_1,};static unsigned char KEY2_MAP[4] = { KEY_2, KEY_A, KEY_B, KEY_C,};static unsigned char KEY3_MAP[4] = { KEY_3, KEY_D, KEY_E, KEY_F,};static unsigned char KEY4_MAP[4] = { KEY_4, KEY_G, KEY_H, KEY_I,};static unsigned char KEY5_MAP[4] = { KEY_5, KEY_J, KEY_K, KEY_L,};static unsigned char KEY6_MAP[4] = { KEY_6, KEY_M, KEY_N, KEY_O,};static unsigned char KEY7_MAP[5] = { KEY_7, KEY_P, KEY_Q, KEY_R, KEY_S,};static unsigned char KEY8_MAP[4] = { KEY_8, KEY_T, KEY_U, KEY_V,};static unsigned char KEY9_MAP[5] = { KEY_W, KEY_X, KEY_Y, KEY_Z,};#endifenum KEY_IDX { IDX_FUNC = 0, IDX_BACK, IDX_UP, IDX_FN, IDX_ENTER, IDX_DEL, IDX_LEFT, IDX_ENTER2, IDX_RIGHT, IDX_PLUS, IDX_DOWN, IDX_STAR, /* * */ IDX_3DEF, /* 3/D/E/F */ IDX_2ABC, /* 2/A/B/C */ IDX_1, /* 1 */ IDX_0, /* 0 */ IDX_POUND, /* # */ IDX_6MNO, /* 6/M/N/O */ IDX_9WXYZ, /* 9/W/X/Y/Z */ IDX_5JKL, /* 5/J/K/L */ IDX_8TUV, /* 8/T/U/V */ IDX_4GHI, /* 8/G/H/I */ IDX_7PQRS, /* 7/P/Q/R/S */};static unsigned int mb9260kbd_keycode[NR_SCANCODES] = { [IDX_FUNC] = KEY_MENU, [IDX_BACK] = KEY_BACK, [IDX_UP] = KEY_UP, [IDX_FN] = KEY_FN, [IDX_ENTER] = KEY_ENTER, [IDX_DEL] = KEY_DELETE, [IDX_LEFT] = KEY_LEFT, /* FIX ME! */ [IDX_ENTER2] = KEY_BACK, [IDX_RIGHT] = KEY_RIGHT, [IDX_PLUS] = KEY_KPPLUS, [IDX_DOWN] = KEY_DOWN, /* comobo key */ [IDX_STAR] = 0, [IDX_3DEF] = KEY_3, [IDX_2ABC] = KEY_2, [IDX_1] = KEY_1, [IDX_0] = KEY_0, /* comobo key */ [IDX_POUND] = 0, [IDX_6MNO] = KEY_6, [IDX_9WXYZ] = KEY_9, [IDX_5JKL] = KEY_5, [IDX_8TUV] = KEY_8, [IDX_4GHI] = KEY_4, [IDX_7PQRS] = KEY_7,};struct mb9260kbd { unsigned char keycode[ARRAY_SIZE(mb9260kbd_keycode)]; struct input_polled_dev *poll_dev; struct iomem_object *iomem0; struct iomem_object *iomem1; unsigned long key_ever_pressed; unsigned long kbdscan_state; unsigned int kbdscan_count[32];};#define KBDSCAN_STABLE_COUNT 2static inline u32 mb9260kbd_getkey(struct mb9260kbd *dev){ u16 key0 = 0xffff, key1 = 0xffff; struct iomem_object *iomem0 = dev->iomem0; struct iomem_object *iomem1 = dev->iomem1; iomem0->read_word(iomem0, &key0, IO_RDONLY); iomem1->read_word(iomem1, &key1, IO_RDONLY); key1 |= 0xff00; return (key0 | (key1 << 16));}static void mb9260kbd_report_key(struct mb9260kbd *mb9260kbd, unsigned long key_stat, unsigned int idx){ unsigned int pressed; if (unlikely(idx >= ARRAY_SIZE(mb9260kbd_keycode))) { return; } pressed = !test_bit(idx, &key_stat); switch (idx) { case IDX_STAR: /* Key *: SHIFT + 8 */ input_report_key(mb9260kbd->poll_dev->input, KEY_LEFTSHIFT, pressed); input_report_key(mb9260kbd->poll_dev->input, KEY_8, pressed); break; case IDX_POUND: /* Key #: SHIFT + 3 */ input_report_key(mb9260kbd->poll_dev->input, KEY_LEFTSHIFT, pressed); input_report_key(mb9260kbd->poll_dev->input, KEY_3, pressed); break; default: input_report_key(mb9260kbd->poll_dev->input, mb9260kbd->keycode[idx], pressed); break; } return;}/* Scan the hardware keyboard and push any changes up through the input layer */static void mb9260kbd_poll(struct input_polled_dev *dev){ struct mb9260kbd *mb9260kbd = dev->private; unsigned long key_stat = 0xffffffff; unsigned long idx = 0; int sync = 0; key_stat = mb9260kbd_getkey(mb9260kbd); if ((mb9260kbd->key_ever_pressed = 0) && (key_stat == 0xffffffff) && (mb9260kbd->kbdscan_state == key_stat)) { return; } for (idx = IDX_FUNC; idx <= IDX_7PQRS; idx++) { if (test_bit(idx, &key_stat) ^ test_bit(idx, &mb9260kbd->kbdscan_state)) { set_bit(idx, &mb9260kbd->key_ever_pressed); mb9260kbd->kbdscan_count[idx] = 0; mb9260kbd->kbdscan_state = key_stat; } else if (++mb9260kbd->kbdscan_count[idx] >= KBDSCAN_STABLE_COUNT) { if (test_and_clear_bit(idx, &mb9260kbd->key_ever_pressed)) { mb9260kbd_report_key(mb9260kbd, key_stat, idx); sync = 1; } mb9260kbd->kbdscan_count[idx] = 0; } } if (sync) { input_sync(dev->input); } return;}static int __devinit mb9260kbd_probe(struct platform_device *pdev){ struct mb9260kbd *mb9260kbd; struct input_polled_dev *poll_dev; struct input_dev *input_dev; int i; int error; mb9260kbd = kzalloc(sizeof(struct mb9260kbd), GFP_KERNEL); if (!mb9260kbd) { error = -ENOMEM; goto mb9260kbd_malloc_fail; } mb9260kbd->kbdscan_state = 0xffffffff; mb9260kbd->iomem0 = iomem_object_get(KEYBOARD_PHY_BASE0, 0xffffffff); if (!mb9260kbd->iomem0) { printk(KERN_ERR "Can NOT remap address 0x%08x\n", KEYBOARD_PHY_BASE0); error = -1; goto iomem0_fail; } mb9260kbd->iomem1 = iomem_object_get(KEYBOARD_PHY_BASE1, 0xffffffff); if (!mb9260kbd->iomem1) { printk(KERN_ERR "Can NOT remap address 0x%08x\n", KEYBOARD_PHY_BASE1); error = -1; goto iomem1_fail; } poll_dev = input_allocate_polled_device(); if (!mb9260kbd || !poll_dev) { error = -ENOMEM; goto fail; } platform_set_drvdata(pdev, mb9260kbd); mb9260kbd->poll_dev = poll_dev; memcpy(mb9260kbd->keycode, mb9260kbd_keycode, sizeof(mb9260kbd->keycode)); poll_dev->private = mb9260kbd; poll_dev->poll = mb9260kbd_poll; poll_dev->poll_interval = SCAN_INTERVAL; input_dev = poll_dev->input; input_dev->name = "Mobile9260 Keyboard"; input_dev->phys = "mb9260kbd/input0"; input_dev->id.bustype = BUS_HOST; input_dev->id.vendor = 0x0001; input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; input_dev->dev.parent = &pdev->dev; input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); input_dev->keycode = mb9260kbd->keycode; input_dev->keycodesize = sizeof(unsigned char); input_dev->keycodemax = ARRAY_SIZE(mb9260kbd_keycode); for (i = 0; i < ARRAY_SIZE(mb9260kbd_keycode); i++) set_bit(mb9260kbd->keycode[i], input_dev->keybit); clear_bit(0, input_dev->keybit); error = input_register_polled_device(mb9260kbd->poll_dev); if (error) goto fail; return 0;fail: input_free_polled_device(poll_dev); iomem_object_put(mb9260kbd->iomem1);iomem1_fail: iomem_object_put(mb9260kbd->iomem0);iomem0_fail: kfree(mb9260kbd);mb9260kbd_malloc_fail: return error;}static int __devexit mb9260kbd_remove(struct platform_device *pdev){ struct mb9260kbd *mb9260kbd = platform_get_drvdata(pdev); input_unregister_polled_device(mb9260kbd->poll_dev); input_free_polled_device(mb9260kbd->poll_dev); iomem_object_put(mb9260kbd->iomem1); iomem_object_put(mb9260kbd->iomem0); kfree(mb9260kbd); return 0;}/* work with hotplug and coldplug */MODULE_ALIAS("platform:mb9260-keyboard");static struct platform_driver mb9260kbd_driver = { .probe = mb9260kbd_probe, .remove = __devexit_p(mb9260kbd_remove), .driver = { .name = "mb9260-kbd", .owner = THIS_MODULE, },};static int __init mb9260kbd_init(void){ return platform_driver_register(&mb9260kbd_driver);}static void __exit mb9260kbd_exit(void){ platform_driver_unregister(&mb9260kbd_driver);}module_init(mb9260kbd_init);module_exit(mb9260kbd_exit);MODULE_AUTHOR("liulf");MODULE_DESCRIPTION("Mobile9260 Keyboard Driver");MODULE_LICENSE("GPL v2");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -