📄 sunkbd.c
字号:
/* handle the case that two shift or control keys are depressed simultaneously */ if (k_down[value]) k_down[value]--; } else k_down[value]++; if (k_down[value]) shift_state |= (1 << value); else shift_state &= ~ (1 << value); /* kludge, no joke... */ if (up_flag && shift_state != old_state && npadch != -1) { put_queue(npadch & 0xff); npadch = -1; }}/* called after returning from RAW mode or when changing consoles - recompute k_down[] and shift_state from key_down[] *//* maybe called when keymap is undefined, so that shiftkey release is seen */void compute_shiftstate(void){ int i, j, k, sym, val; shift_state = 0; for(i=0; i < SIZE(k_down); i++) k_down[i] = 0; for(i=0; i < SIZE(key_down); i++) if(key_down[i]) { /* skip this word if not a single bit on */ k = i*BITS_PER_LONG; for(j=0; j<BITS_PER_LONG; j++,k++) if(test_bit(k, key_down)) { sym = U(plain_map[k]); if(KTYP(sym) == KT_SHIFT) { val = KVAL(sym); if (val == KVAL(K_CAPSSHIFT)) val = KVAL(K_SHIFT); k_down[val]++; shift_state |= (1<<val); } } }}static void do_meta(unsigned char value, char up_flag){ if (up_flag) return; if (vc_kbd_mode(kbd, VC_META)) { put_queue('\033'); put_queue(value); } else put_queue(value | 0x80);}static void do_ascii(unsigned char value, char up_flag){ int base; if (up_flag) return; if (value < 10) /* decimal input of code, while Alt depressed */ base = 10; else { /* hexadecimal input of code, while AltGr depressed */ value -= 10; base = 16; } if (npadch == -1) npadch = value; else npadch = npadch * base + value;}static void do_lock(unsigned char value, char up_flag){ if (up_flag || rep) return; chg_vc_kbd_lock(kbd, value);}/* * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, * or (ii) whatever pattern of lights people want to show using KDSETLED, * or (iii) specified bits of specified words in kernel memory. */static unsigned char ledstate = 0xff; /* undefined */static unsigned char ledioctl;unsigned char getledstate(void) { return ledstate;}void setledstate(struct kbd_struct *kbd, unsigned int led) { if (!(led & ~7)) { ledioctl = led; kbd->ledmode = LED_SHOW_IOCTL; } else kbd->ledmode = LED_SHOW_FLAGS; set_leds();}static struct ledptr { unsigned int *addr; unsigned int mask; unsigned char valid:1;} ledptrs[3];void register_leds(int console, unsigned int led, unsigned int *addr, unsigned int mask) { struct kbd_struct *kbd = kbd_table + console; if (led < 3) { ledptrs[led].addr = addr; ledptrs[led].mask = mask; ledptrs[led].valid = 1; kbd->ledmode = LED_SHOW_MEM; } else kbd->ledmode = LED_SHOW_FLAGS;}static inline unsigned char getleds(void){ struct kbd_struct *kbd = kbd_table + fg_console; unsigned char leds; if (kbd->ledmode == LED_SHOW_IOCTL) return ledioctl; leds = kbd->ledflagstate; if (kbd->ledmode == LED_SHOW_MEM) { if (ledptrs[0].valid) { if (*ledptrs[0].addr & ledptrs[0].mask) leds |= 1; else leds &= ~1; } if (ledptrs[1].valid) { if (*ledptrs[1].addr & ledptrs[1].mask) leds |= 2; else leds &= ~2; } if (ledptrs[2].valid) { if (*ledptrs[2].addr & ledptrs[2].mask) leds |= 4; else leds &= ~4; } } return leds;}/* * This routine is the bottom half of the keyboard interrupt * routine, and runs with all interrupts enabled. It does * console changing, led setting and copy_to_cooked, which can * take a reasonably long time. * * Aside from timing (which isn't really that important for * keyboard interrupts as they happen often), using the software * interrupt routines for this thing allows us to easily mask * this when we don't want any of the above to happen. Not yet * used, but this allows for easy and efficient race-condition * prevention later on. */static void kbd_bh(void){ unsigned char leds = getleds(); if (leds != ledstate) { ledstate = leds; send_cmd(SKBDCMD_SETLED); send_cmd(vcleds_to_sunkbd(leds)); }}int kbd_init(void){ int i, opt_node; struct kbd_struct kbd0; extern struct tty_driver console_driver; kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; kbd0.ledmode = LED_SHOW_FLAGS; kbd0.lockstate = KBD_DEFLOCK; kbd0.modeflags = KBD_DEFMODE; kbd0.kbdmode = VC_XLATE; for (i = 0 ; i < MAX_NR_CONSOLES ; i++) kbd_table[i] = kbd0; ttytab = console_driver.table; /* XXX Check keyboard-click? property in 'options' PROM node XXX */ if(sparc_cpu_model != sun4) { opt_node = prom_getchild(prom_root_node); opt_node = prom_searchsiblings(opt_node, "options"); i = prom_getintdefault(opt_node, "keyboard-click?", -1); if(i != -1) sunkbd_clickp = 1; else sunkbd_clickp = 0; } else { sunkbd_clickp = 0; } init_bh(KEYBOARD_BH, kbd_bh); mark_bh(KEYBOARD_BH); return 0;}/* /dev/kbd support */#define KBD_QSIZE 32static Firm_event kbd_queue [KBD_QSIZE];static int kbd_head, kbd_tail;char kbd_opened;static struct wait_queue *kbd_wait;static struct fasync_struct *kb_fasync;voidpush_kbd (int scan){ int next = (kbd_head + 1) % KBD_QSIZE; if (scan == KBD_IDLE) return; if (next != kbd_tail){ kbd_queue [kbd_head].id = scan & KBD_KEYMASK; kbd_queue [kbd_head].value=scan & KBD_UP ? VKEY_UP : VKEY_DOWN; kbd_queue [kbd_head].time = xtime; kbd_head = next; } if (kb_fasync) kill_fasync (kb_fasync, SIGIO); wake_up_interruptible (&kbd_wait);}static intkbd_read (struct inode *inode, struct file *f, char *buffer, int count){ struct wait_queue wait = { current, NULL }; char *end, *p; /* Return EWOULDBLOCK, because this is what the X server expects */ if (kbd_head == kbd_tail){ if (f->f_flags & O_NONBLOCK) return -EWOULDBLOCK; add_wait_queue (&kbd_wait, &wait); while (kbd_head == kbd_tail && !(current->signal & ~current->blocked)){ current->state = TASK_INTERRUPTIBLE; schedule (); } current->state = TASK_RUNNING; remove_wait_queue (&kbd_wait, &wait); } /* There is data in the keyboard, fill the user buffer */ end = buffer+count; p = buffer; for (; p < end && kbd_head != kbd_tail; p += sizeof (Firm_event)){ *(Firm_event *)p = kbd_queue [kbd_tail];#ifdef KBD_DEBUG printk ("[%s]", kbd_queue [kbd_tail].value == VKEY_UP ? "UP" : "DOWN");#endif kbd_tail++; kbd_tail %= KBD_QSIZE; } return p-buffer;}/* Needed by X */static intkbd_fasync (struct inode *inode, struct file *filp, int on){ int retval; retval = fasync_helper (inode, filp, on, &kb_fasync); if (retval < 0) return retval; return 0;}static intkbd_select (struct inode *i, struct file *f, int sel_type, select_table *wait){ if (sel_type != SEL_IN) return 0; if (kbd_head != kbd_tail) return 1; select_wait (&kbd_wait, wait); return 0;}static intkbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg){ switch (cmd){ case KIOCTYPE: /* return keyboard type */ if (verify_area (VERIFY_WRITE, (void *)arg, sizeof (int))) return -EFAULT; *(int *) arg = sunkbd_type; break; case KIOCGTRANS: if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int))) return -EFAULT; *(int *) arg = TR_UNTRANS_EVENT; break; case KIOCTRANS: if (verify_area (VERIFY_READ, (void *) arg, sizeof (int))) return -EFAULT; if (*(int *) arg != TR_UNTRANS_EVENT) return -EINVAL; break; case KIOCLAYOUT: if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int))) return -EFAULT; *(int *) arg = sunkbd_layout; break; case KIOCSDIRECT: if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int))) return -EFAULT;#ifndef CODING_NEW_DRIVER if (*(int *) arg) kbd_redirected = fg_console + 1; else kbd_redirected = 0; kbd_table [fg_console].kbdmode = kbd_redirected ? VC_RAW : VC_XLATE;#endif break; case KIOCCMD: /* Need to support beep on/off, keyclick on/off */ return 0; case FIONREAD: /* return number of bytes in kbd queue */ { int count; if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int))) return -EFAULT; count = kbd_head - kbd_tail; * (int *)arg = (count < 0) ? KBD_QSIZE - count : count; return 0; } default: printk ("Unknown Keyboard ioctl: %8.8x\n", cmd); return -EINVAL; } return 0;}static intkbd_open (struct inode *i, struct file *f){ if (kbd_opened) return 0; kbd_opened = fg_console + 1; kbd_head = kbd_tail = 0; return 0;}static voidkbd_close (struct inode *i, struct file *f){ if (kbd_redirected) kbd_table [kbd_opened-1].kbdmode = VC_XLATE; kbd_redirected = 0; kbd_opened = 0; kbd_fasync (i, f, 0);}static structfile_operations kbd_fops ={ NULL, /* seek */ kbd_read, /* read */ NULL, /* write */ NULL, /* readdir */ kbd_select, /* select */ kbd_ioctl, /* ioctl */ NULL, /* mmap */ kbd_open, /* open */ kbd_close, /* close */ NULL, /* fsync */ kbd_fasync, /* fasync */ NULL, /* check_media_change */ NULL, /* revalidate */};voidkeyboard_zsinit(void){ int timeout = 0; /* Test out the leds */ sunkbd_type = 255; send_cmd(SKBDCMD_RESET); while((sunkbd_type==255) && timeout < 500000) { udelay(100); timeout += 20; } if(timeout>=500000) { printk("keyboard: not present\n"); return; } if(sunkbd_type != SUNKBD_TYPE4) { printk("Sun TYPE %d keyboard detected ", sunkbd_type); } else { udelay(200); timeout=0; while(timeout++ < 500000) barrier(); printk("Sun TYPE %d keyboard detected ", ((sunkbd_layout==SUNKBD_LOUT_TYP5) ? 5 : 4)); } if(sunkbd_type == SUNKBD_TYPE2) sunkbd_clickp = 0; if(sunkbd_clickp) printk("with keyclick\n"); else printk("without keyclick\n"); /* Dork with led lights, then turn them all off */ send_cmd(SKBDCMD_SETLED); send_cmd(0xf); /* All on */ send_cmd(SKBDCMD_SETLED); send_cmd(0x0); /* All off */ /* Register the /dev/kbd interface */ if (register_chrdev (KBD_MAJOR, "kbd", &kbd_fops)){ printk ("Could not register /dev/kbd device\n"); return; } return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -