📄 keyb.c.org
字号:
/* sets the "release_key" bit when a key is released. HP keyboard send f0 followed by the keycode while AT keyboard send the keycode with this bit set. */ brk = 0x80; return; case KBD_ESCAPEE0 : /* 2chars sequence, commonly used to differenciate the two ALT keys and the two ENTER keys and so on... */ esc0 = 2; /* e0-xx are 2 chars */ scancode = keyval; break; case KBD_ESCAPEE1 : /* 3chars sequence, only used by the Pause key. */ esc1 = 3; /* e1-xx-xx are 3 chars */ scancode = keyval; break; case 0x14 : /* translate e1-14-77-e1-f0-14-f0-77 to e1-1d-45-e1-9d-c5 (the Pause key) */ if (esc1==2) scancode = brk | 0x1d; break; case 0x77 : if (esc1==1) scancode = brk | 0x45; break; case 0x12 : /* an extended key is e0-12-e0-xx e0-f0-xx-e0-f0-12 on HP, while it is e0-2a-e0-xx e0-(xx|80)-f0-aa on AT. */ if (esc0==1) scancode = brk | 0x2a; break; } /* translates HP scancodes to AT scancodes */ if (!scancode) scancode = brk | keycode_translate[keyval]; if (!scancode) printk(KERN_INFO "keyboard: unexpected key code %02x\n",keyval); /* now behave like an AT keyboard */ handle_keyboard(scancode); if (esc0) esc0--; if (esc1) esc1--; /* release key bit must be unset for the next key */ brk = 0;}int kbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode){ static int prev_scancode; /* special prefix scancodes.. */ if (scancode == 0xe0 || scancode == 0xe1) { prev_scancode = scancode; return 0; } /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ if (scancode == 0x00 || scancode == 0xff) { prev_scancode = 0; return 0; } scancode &= 0x7f; if (prev_scancode) { /* * usually it will be 0xe0, but a Pause key generates * e1 1d 45 e1 9d c5 when pressed, and nothing when released */ 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; /* * The keyboard maintains its own internal caps lock and * num lock statuses. In caps lock mode E0 AA precedes make * code and E0 2A follows break code. In num lock mode, * E0 2A precedes make code and E0 AA follows break code. * We do our own book-keeping, so we will just ignore these. */ /* * For my keyboard there is no caps lock mode, but there are * both Shift-L and Shift-R modes. The former mode generates * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. * So, we should also ignore the latter. - aeb@cwi.nl */ 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) { /* This happens with the FOCUS 9000 keyboard Its keys PF1..PF12 are reported to generate 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f Moreover, unless repeated, they do not generate key-down events, so we have to zero up_flag below */ /* Also, Japanese 86/106 keyboards are reported to generate 0x73 and 0x7d for \ - and \ | respectively. */ /* Also, some Brazilian keyboard is reported to produce 0x73 and 0x7e for \ ? and KP-dot, respectively. */ *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; handle_keyboard(*keycode); //yhwang add return 1;}void command(unsigned char cmd){ int key; outportb(PORT_PSDAT,cmd); while((inportb(PORT_PSTAT)&0x2)==0); key = inportb(PORT_PSTAT); outportb(PORT_PSCON,0x80);}void pscon(unsigned char cmd){ outportb(PORT_PSCON,cmd);}void delay(int i){ do { int j =1000; // ori do { asm volatile ("nop"); } while (--j>=0); } while (--i>=0);}void init_kbd(void);void init_kbd(){ pscon(0x6c); command(0xff);}void pollingKeyboard(void){ int i; int stat; for(i=0;i<10;i++) { stat = inportb(PORT_PSTAT); if ((stat&0x0a)==0x0a) { int in_key; in_key = inportb(PORT_PSDAT); handle_at_scancode(in_key); if(debug>0) printk("kbd(%d)[%x] ",i,in_key); outportb(PORT_PSCON,0x80); } }}#ifdef SUPPORT_IRextern int read_ir(void);extern void init_ir(void);void polling_ir(void){ int i; int data; int keyb; for(i=0;i<1;i++) { data = read_ir(); if(data>=0) { keyb= ir_map[data]; if(debug>0) printk("ir(%d)[%x]->[%x] ",i,data, keyb); switch(keyb) { case R_UP: case R_DOWN: case R_LEFT: case R_RGHT:/* handle_at_scancode(0xe0); handle_at_scancode(keyb);*/ handle_at_scancode(0xe0); handle_at_scancode(0xf0); handle_at_scancode(keyb); default: handle_at_scancode(keyb); handle_at_scancode(0xf0); handle_at_scancode(keyb); break; } } }}#endif //SUPPORT_IRstruct timer_list keyboard_timer; static void dvd_keyboard_timeup(unsigned long data){ if(use_keyb) pollingKeyboard();#ifdef SUPPORT_IR if(use_ir) polling_ir();#endif mod_timer(&keyboard_timer, jiffies + SCANHZ); } static void dvd_keyboard_starttimer(void){ printk("dvd_keyboard_starttimer\n"); init_timer(&keyboard_timer); keyboard_timer.function = dvd_keyboard_timeup; keyboard_timer.data = 0; keyboard_timer.expires = jiffies + SCANHZ; add_timer(&keyboard_timer);}/* * PS/2 Auxiliary Device */static spinlock_t controller_lock = SPIN_LOCK_UNLOCKED; static struct aux_queue *queue; /* Mouse data buffer. */static int aux_count;static inline void handle_keyboard(unsigned char scancode){ static unsigned char prev_code; int head; prev_code = scancode; add_mouse_randomness(scancode); if (aux_count) { head = queue->head; queue->buf[head] = scancode; head = (head + 1) & (AUX_BUF_SIZE-1); if (head != queue->tail) { queue->head = head; kill_fasync(&queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); } }}static unsigned char get_from_queue(void){ unsigned char result; unsigned long flags; spin_lock_irqsave(&controller_lock, flags); result = queue->buf[queue->tail]; queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); spin_unlock_irqrestore(&controller_lock, flags); return result;}static inline int queue_empty(void){ return queue->head == queue->tail;}static int fasync_aux(int fd, struct file *filp, int on){ int retval; retval = fasync_helper(fd, filp, on, &queue->fasync); if (retval < 0) return retval; return 0;}/* * Random magic cookie for the aux device */#define AUX_DEV ((void *)queue)static int release_aux(struct inode * inode, struct file * file){ lock_kernel(); fasync_aux(-1, file, 0); if (--aux_count) { unlock_kernel(); return 0; } del_timer(&keyboard_timer); unlock_kernel(); return 0;}/* * Install interrupt handler. * Enable auxiliary device. */static int open_aux(struct inode * inode, struct file * file){ if (aux_count++) { return 0; } queue->head = queue->tail = 0; /* Flush input queue */ dvd_keyboard_starttimer(); return 0;}/* * Put bytes from input queue to buffer. */static ssize_t read_aux(struct file * file, char * buffer, size_t count, loff_t *ppos){ DECLARE_WAITQUEUE(wait, current); ssize_t i = count; unsigned char c; if (queue_empty()) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; add_wait_queue(&queue->proc_list, &wait);repeat: set_current_state(TASK_INTERRUPTIBLE); if (queue_empty() && !signal_pending(current)) { schedule(); goto repeat; } current->state = TASK_RUNNING; remove_wait_queue(&queue->proc_list, &wait); } while (i > 0 && !queue_empty()) { c = get_from_queue(); put_user(c, buffer++); i--; } if (count-i) { file->f_dentry->d_inode->i_atime = CURRENT_TIME; return count-i; } if (signal_pending(current)) return -ERESTARTSYS; return 0;}/* * Write to the aux device. */#if 0static ssize_t write_aux(struct file * file, const char * buffer, size_t count, loff_t *ppos){ ssize_t retval = 0; if (count) { ssize_t written = 0; if (count > 32) count = 32; /* Limit to 32 bytes. */ do { char c; get_user(c, buffer++); aux_write_dev(c); written++; } while (--count); retval = -EIO; if (written) { retval = written; file->f_dentry->d_inode->i_mtime = CURRENT_TIME; } } return retval;}#endifstatic int set_ir_map(int keymap){ switch(keymap) { case 1: ir_map = ir_map_coship; printk("INFO: sp_keyb: ir_map = ir_map_coship\n"); break; default: ir_map = ir_map_sunplus; printk("INFO: sp_keyb: ir_map = ir_map_sunplus\n"); break; } return 0;}/* No kernel lock held - fine */static unsigned int aux_poll(struct file *file, poll_table * wait){ poll_wait(file, &queue->proc_list, wait); if (!queue_empty()) return POLLIN | POLLRDNORM; return 0;}struct file_operations psaux_fops = { read: read_aux,// write: write_aux, poll: aux_poll, open: open_aux, release: release_aux, fasync: fasync_aux,};/* * Initialize driver. */static struct miscdevice psaux_mouse = { /*PSMOUSE_MINOR*/2, "psaux1", &psaux_fops};int __init psaux_init(void){ int retval; printk("Sunplus DVD PS/2 Keyboard Driver Initial\n");// printk("INFO: sp_keyb v0.1c(2003.11.28)\n");// printk("INFO: sp_keyb v0.1d(2003.12.30)[SUNPLUS IR]\n");// printk("INFO: sp_keyb v0.1d(2004.01.02)[SUNPLUS IR]\n");// printk("INFO: sp_keyb v0.1e(2004.01.02)[debug, ir_type]\n"); if ((retval = misc_register(&psaux_mouse))) return retval; queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); if (queue == NULL) { printk(KERN_ERR "psaux_init(): out of memory\n"); misc_deregister(&psaux_mouse); return -ENOMEM; } memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; init_waitqueue_head(&queue->proc_list); set_ir_map(ir_type); init_kbd();#ifdef SUPPORT_IR init_ir();#endif return 0;}#ifdef CONFIG_PROC_FS#include <linux/proc_fs.h>#define DRVNAME "sp_keyb"#define PROCNAME "driver/" DRVNAME//char sp_keyb_version[]="sp_keyb: v0.1(2004.01.19)";char sp_keyb_version[]="sp_keyb: v0.2a(2004.02.23) use_keyb use_ir time_tick";static int sp_keyb_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *private){ int clen=0; clen += sprintf(buf + clen, "%s\n", sp_keyb_version); *start = buf + offset; if (clen > offset) clen -= offset; else clen = 0; return clen < len ? clen : len;}#endif //CONFIG_PROC_FSstatic int init_module(void){#ifdef CONFIG_PROC_FS create_proc_read_entry(PROCNAME, 0, 0, sp_keyb_read_proc, NULL);#endif return psaux_init(); }static void cleanup_module(void){ #ifdef CONFIG_PROC_FS remove_proc_entry(PROCNAME, NULL);#endif del_timer(&keyboard_timer); //yhwang for testing misc_deregister(&psaux_mouse); printk("cleanup_module\n"); return;}MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -