📄 scan_smallkbd.c
字号:
#include <linux/module.h>#include <linux/config.h>#include <linux/spinlock.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/mm.h>#include <linux/signal.h>#include <linux/init.h>#include <linux/kbd_ll.h>#include <linux/delay.h>#include <linux/random.h>#include <linux/poll.h>#include <linux/miscdevice.h>#include <linux/slab.h>#include <linux/kbd_kern.h>#include <linux/ioport.h>#include <linux/tqueue.h>#include <linux/wait.h>#include <asm/hardware.h>#include <asm/bitops.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/io.h>#include <linux/pc_keyb.h>#include <asm/keyboard.h>#include <asm/hardware/sa1111.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/param.h>#include <linux/timer.h>#include <asm/arch/hardware.h>#define SMALLKBD_MAJOR 51#define MAX_SMALLKBD_BUFFER 1024static struct timer_list tmlist;static wait_queue_head_t smallkbd_wait;static spinlock_t smallkbd_lock = SPIN_LOCK_UNLOCKED;static int scan_interval = 200; static unsigned char smallkbd_buf[MAX_SMALLKBD_BUFFER];static int buf_head,buf_tail,key_count;#ifdef CONFIG_MAGIC_SYSRQstatic unsigned char sa1111_sysrq_xlate[128] = "\000\0331234567890-=\177\t" "qwertyuiop[]\r\000as" "dfghjkl;'`\000\\zxcv" "bnm,./\000*\000 \000\201\202\203\204\205" "\206\207\210\211\212\000\000789-456+1" "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" "\r\000/"; #endif#define E0_KPENTER 96#define E0_RCTRL 97#define E0_KPSLASH 98#define E0_PRSCR 99#define E0_RALT 100#define E0_BREAK 101 #define E0_HOME 102#define E0_UP 103#define E0_PGUP 104#define E0_LEFT 105#define E0_RIGHT 106#define E0_END 107#define E0_DOWN 108#define E0_PGDN 109#define E0_INS 110#define E0_DEL 111#define E0_YEN 124#define E0_BACKSLASH 89#define E1_PAUSE 119/* */#define SC_LIM 89#define FOCUS_PF1 85 #define FOCUS_PF2 89#define FOCUS_PF3 90#define FOCUS_PF4 91#define FOCUS_PF5 92#define FOCUS_PF6 93#define FOCUS_PF7 94#define FOCUS_PF8 95#define FOCUS_PF9 120#define FOCUS_PF10 121#define FOCUS_PF11 122#define FOCUS_PF12 123#define JAP_86 124#define RGN1 124#define RGN2 125#define RGN3 126#define RGN4 127static unsigned char high_keys[128 - SC_LIM] = { RGN1, RGN2, RGN3, RGN4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, FOCUS_PF8, JAP_86, FOCUS_PF10, 0 };#define E0_MACRO 112#define E0_F13 113#define E0_F14 114#define E0_HELP 115#define E0_DO 116#define E0_F17 117#define E0_KPMINPLUS 118/* */#define E0_OK 124/* */#define E0_MSLW 125#define E0_MSRW 126#define E0_MSTM 127static unsigned char e0_keys[128] = { 0, 0, 0, 0, 0, 0, 0, 0, /* */ 0, 0, 0, 0, 0, 0, 0, 0, /* */ 0, 0, 0, 0, 0, 0, 0, 0, /* */ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* */ 0, 0, 0, 0, 0, 0, 0, 0, /* */ 0, 0, 0, 0, 0, 0, 0, 0, /* */ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* */ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* */ E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* */ E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END, /* */ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* */ 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* */ 0, 0, 0, 0, 0, 0, 0, 0, /* */ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* */ //0, 0, 0, 0, 0, 0, 0, 0, /* */ 0, 0, 0, 0, 0, E0_BACKSLASH, 0, 0, /* */ 0, 0, 0, E0_YEN, 0, 0, 0, 0 /* */};int smallkbd_setkeycode(unsigned int scancode, unsigned int keycode){ if (scancode < SC_LIM || scancode > 255 || keycode > 127) return -EINVAL; if (scancode < 128) high_keys[scancode - SC_LIM] = keycode; else e0_keys[scancode - 128] = keycode; return 0;}int smallkbd_getkeycode(unsigned int scancode){ return (scancode < SC_LIM || scancode > 255) ? -EINVAL : (scancode < 128) ? high_keys[scancode - SC_LIM] : e0_keys[scancode - 128];}int smallkbd_translate(unsigned char scancode, unsigned char *keycode,char raw_mode){ static int prev_scancode = 0; if (scancode == 0xe0 || scancode == 0xe1) { prev_scancode = scancode; return 0; } if (scancode == 0x00 || scancode == 0xff) { prev_scancode = 0; return 0; } scancode &= 0x7f; if (prev_scancode) { /* */ if (prev_scancode != 0xe0) { if (prev_scancode == 0xe1 && scancode == 0x1d) { prev_scancode = 0x100; return 0; } else if (prev_scancode == 0x100 && scancode == 0x45) { *keycode = E1_PAUSE; prev_scancode = 0; } else {#ifdef KBD_REPORT_UNKN if (!raw_mode) printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");#endif prev_scancode = 0; return 0; } } else { prev_scancode = 0; /* */ /* */ if (scancode == 0x2a || scancode == 0x36) return 0; if (e0_keys[scancode]) *keycode = e0_keys[scancode]; else {#ifdef KBD_REPORT_UNKN if (!raw_mode) printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", scancode);#endif return 0; } } } else if (scancode >= SC_LIM) { *keycode = high_keys[scancode - SC_LIM]; if (!*keycode) { if (!raw_mode) {#ifdef KBD_REPORT_UNKN printk(KERN_INFO "keyboard: unrecognized scancode (%02x)" " - ignored\n", scancode);#endif } return 0; } } else *keycode = scancode; return 1;}char smallkbd_unexpected_up(unsigned char keycode){ if (keycode >= SC_LIM || keycode == 85) return 0; else return 0200;}void smallkbd_leds(unsigned char leds){ return; }static ssize_t smallkbd_read(struct file *fp,char *buf, size_t count,loff_t *l_t){ if (verify_area(VERIFY_WRITE, buf, 1) == -EFAULT) return -1; if (key_count == 0) return 0; copy_to_user(buf, &smallkbd_buf[buf_head], 1); key_count--; buf_head++; if (buf_head == MAX_SMALLKBD_BUFFER) buf_head = 0; return 1;}static int smallkbd_open(struct inode *node,struct file *fp){ buf_head = buf_tail = key_count = 0; return 0;}static int smallkbd_release(struct inode *node,struct file *fp){ return 0;}static ssize_t smallkbd_write(struct file *fp,const char *buf,size_t count,loff_t *l_t){ return 0;}static unsigned int smallkbd_poll(struct file *file,poll_table *table){ if (key_count) return 1; poll_wait(file,&smallkbd_wait,table); return 0;}static int smallkbd_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg){ switch (cmd) { case 1: if (50 > arg) arg = 50; else if (500 < arg) arg = 500; scan_interval = (int)arg; break; case 2: break; default: break; } return 0;}struct file_operations smallkbd_fops = { read: smallkbd_read, write: smallkbd_write, poll: smallkbd_poll, ioctl: smallkbd_ioctl, open: smallkbd_open, release: smallkbd_release,};unsigned char read_scancode(const unsigned char nScanCode){ unsigned char c; switch(nScanCode & 0x1f) { case 0x0f: GPCR0 = 0x40000000; break; case 0x17: GPCR0 = 0xa0000000; break; case 0x1b: GPCR1 = 0x01000000; break; case 0x1d: GPCR0 = 0x02000000; break; case 0x1e: GPCR0 = 0x01000000; break; default: return 0; break; } c = (GPLR0 >> 19) & 0x1f; switch(nScanCode & 0x1f) { case 0x0f: GPSR0 = 0x40000000; break; case 0x17: GPSR0 = 0xa0000000; break; case 0x1b: GPSR1 = 0x01000000; break; case 0x1d: GPSR0 = 0x02000000; break; case 0x1e: GPSR0 = 0x01000000; break; default: return 0; break; } return c;}static void handle_smallkbd_event(unsigned char scancode,unsigned char keycode,int flag){ unsigned long flags; spin_lock_irqsave(&smallkbd_lock,flags); handle_scancode(scancode,flag); tasklet_schedule(&keyboard_tasklet); spin_unlock_irqrestore(&smallkbd_lock,flags); if ((1 == flag) && (key_count < MAX_SMALLKBD_BUFFER)) { smallkbd_buf[buf_tail++] = keycode; key_count++; if (buf_tail >= MAX_SMALLKBD_BUFFER) buf_tail = 0; } wake_up(&smallkbd_wait); return;}static unsigned char _byOldScanCode1 = 0x00,_byOldScanCode2 = 0x00,_byOldScanCode3 = 0x00;static unsigned char _byOldScanCode4 = 0x00,_byOldScanCode5 = 0x00;static short _bKeyDownFlag1 = 0,_bKeyDownFlag2 = 0,_bKeyDownFlag3 = 0;static short _bKeyDownFlag4 = 0,_bKeyDownFlag5 = 0;static void smallkbd_timer(void){ unsigned char byScanCode1,byScanCode2,byScanCode3; unsigned char byScanCode4,byScanCode5; byScanCode1 = read_scancode(0x0f);// if ((_byOldScanCode1 == byScanCode1) && (0 == _bKeyDownFlag1)) { _bKeyDownFlag1 = 1; switch (byScanCode1) { case 0x0f: handle_smallkbd_event(0x15,21,1); handle_smallkbd_event(0x15,21,0); break; case 0x17: handle_smallkbd_event(0x2d,45,1); handle_smallkbd_event(0x2d,45,0); break; case 0x1b: handle_smallkbd_event(0x11,17,1); handle_smallkbd_event(0x11,17,0); break; case 0x1d: handle_smallkbd_event(0x2f,47,1); handle_smallkbd_event(0x2f,47,0); break; case 0x1e: handle_smallkbd_event(0x16,22,1); handle_smallkbd_event(0x16,22,0); break; default: break; } }// else if (_byOldScanCode1 != byScanCode1) { _bKeyDownFlag1 = 0; _byOldScanCode1 = byScanCode1; } byScanCode2 = read_scancode(0x17);// if ((_byOldScanCode2 == byScanCode2) && (0 == _bKeyDownFlag2)) { _bKeyDownFlag2 = 1; switch (byScanCode2) { case 0x0f: handle_smallkbd_event(0x14,20,1); handle_smallkbd_event(0x14,20,0); break; case 0x17: handle_smallkbd_event(0x1f,31,1); handle_smallkbd_event(0x1f,31,0); break; case 0x1b: handle_smallkbd_event(0x13,19,1); handle_smallkbd_event(0x13,19,0); break; case 0x1d: handle_smallkbd_event(0x10,16,1); handle_smallkbd_event(0x10,16,0); break; case 0x1e: handle_smallkbd_event(0x19,25,1); handle_smallkbd_event(0x19,25,0); break; default: break; } }// else if (_byOldScanCode2 != byScanCode2) { _bKeyDownFlag2 = 0; _byOldScanCode2 = byScanCode2; } byScanCode3 = read_scancode(0x1b);// if ((_byOldScanCode3 == byScanCode3) && (0 == _bKeyDownFlag3)) { _bKeyDownFlag3 = 1; switch (byScanCode3) { case 0x0f: handle_smallkbd_event(0x18,24,1); handle_smallkbd_event(0x18,24,0); break; case 0x17: handle_smallkbd_event(0x31,49,1); handle_smallkbd_event(0x31,49,0); break; case 0x1b: handle_smallkbd_event(0x32,50,1); handle_smallkbd_event(0x32,50,0); break; case 0x1d: handle_smallkbd_event(0x26,38,1); handle_smallkbd_event(0x26,38,0); break; case 0x1e: handle_smallkbd_event(0x25,37,1); handle_smallkbd_event(0x25,37,0); break; default: break; } }// else if (_byOldScanCode3 != byScanCode3) { _bKeyDownFlag3 = 0; _byOldScanCode3 = byScanCode3; } byScanCode4 = read_scancode(0x1d);// if ((_byOldScanCode4 == byScanCode4) && (0 == _bKeyDownFlag4)) { _bKeyDownFlag4 = 1; switch (byScanCode4) { case 0x0f: handle_smallkbd_event(0x24,36,1); handle_smallkbd_event(0x24,36,0); break; case 0x17: handle_smallkbd_event(0x17,23,1); handle_smallkbd_event(0x17,23,0); break; case 0x1b: handle_smallkbd_event(0x23,35,1); handle_smallkbd_event(0x23,35,0); break; case 0x1d: handle_smallkbd_event(0x22,34,1); handle_smallkbd_event(0x22,34,0); break; case 0x1e: handle_smallkbd_event(0x21,33,1); handle_smallkbd_event(0x21,33,0); break; default: break; } }// else if (_byOldScanCode4 != byScanCode4) { _bKeyDownFlag4 = 0; _byOldScanCode4 = byScanCode4; } byScanCode5 = read_scancode(0x1e);// if ((_byOldScanCode5 == byScanCode5) && (0 == _bKeyDownFlag5)) { _bKeyDownFlag5 = 1; switch (byScanCode5) { case 0x0f: handle_smallkbd_event(0x12,18,1); handle_smallkbd_event(0x12,18,0); break; case 0x17: handle_smallkbd_event(0x20,32,1); handle_smallkbd_event(0x20,32,0); break; case 0x1b: handle_smallkbd_event(0x2e,46,1); handle_smallkbd_event(0x2e,46,0); break; case 0x1d: handle_smallkbd_event(0x30,48,1); handle_smallkbd_event(0x30,48,0); break; case 0x1e: handle_smallkbd_event(0x1e,30,1); handle_smallkbd_event(0x1e,30,0); break; default: break; } }// else if (_byOldScanCode5 != byScanCode5) { _bKeyDownFlag5 = 0; _byOldScanCode5 = byScanCode5; } if ( (0 == byScanCode1) && (0 == byScanCode2) && (0 == byScanCode3) && (0 == byScanCode4) && (0 == byScanCode5) ) _byOldScanCode1 = _byOldScanCode2 = _byOldScanCode3 = _byOldScanCode4 = _byOldScanCode5 = 0x00; init_timer(&tmlist); tmlist.expires = jiffies + scan_interval*HZ/1000; tmlist.function = (void*)smallkbd_timer; add_timer(&tmlist);}int init_module(void){ int result; GAFR0_U &= 0x03f0003f; GAFR1_U &= 0xfffcffff; GPDR0 |= 0xe3000000; GPDR1 |= 0x01000000; GPDR0 &= 0xff07ffff; buf_head = buf_tail = key_count = 0; result = register_chrdev(SMALLKBD_MAJOR,"smallkbd",&smallkbd_fops); if (0 > result) { printk("smallkbd:can't get major %d.\n",SMALLKBD_MAJOR); return result; }#ifdef CONFIG_MAGIC_SYSRQ k_sysrq_xlate = smallkbd_sysrq_xlate; k_sysrq_key = 0x54;#endif init_waitqueue_head(&smallkbd_wait); init_timer(&tmlist); tmlist.expires = jiffies + HZ; tmlist.function = (void*)smallkbd_timer; add_timer(&tmlist); printk("Init smallkbd success.\n"); return 0;}void cleanup_module(void){ del_timer(&tmlist); unregister_chrdev(SMALLKBD_MAJOR,"smallkbd"); printk("Clean up smallkbd success.\n"); return;}EXPORT_SYMBOL(smallkbd_setkeycode);EXPORT_SYMBOL(smallkbd_getkeycode);EXPORT_SYMBOL(smallkbd_translate);EXPORT_SYMBOL(smallkbd_unexpected_up);EXPORT_SYMBOL(smallkbd_leds);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -