📄 lkkbd.c
字号:
case 1: sprintf (lk->name, "DEC LK201 keyboard"); if (lk201_compose_is_alt) lk->keycode[0xb1] = KEY_LEFTALT; break; case 2: sprintf (lk->name, "DEC LK401 keyboard"); break; default: sprintf (lk->name, "Unknown DEC keyboard"); printk (KERN_ERR "lkkbd: keyboard on %s is unknown, " "please report to Jan-Benedict Glaw " "<jbglaw@lug-owl.de>\n", lk->phys); printk (KERN_ERR "lkkbd: keyboard ID'ed as:"); for (i = 0; i < LK_NUM_IGNORE_BYTES; i++) printk (" 0x%02x", lk->id[i]); printk ("\n"); break; } printk (KERN_INFO "lkkbd: keyboard on %s identified as: %s\n", lk->phys, lk->name); /* * Report errors during keyboard boot-up. */ switch (lk->id[2]) { case 0x00: /* All okay */ break; case LK_STUCK_KEY: printk (KERN_ERR "lkkbd: Stuck key on keyboard at " "%s\n", lk->phys); break; case LK_SELFTEST_FAILED: printk (KERN_ERR "lkkbd: Selftest failed on keyboard " "at %s, keyboard may not work " "properly\n", lk->phys); break; default: printk (KERN_ERR "lkkbd: Unknown error %02x on " "keyboard at %s\n", lk->id[2], lk->phys); break; } /* * Try to hint user if there's a stuck key. */ if (lk->id[2] == LK_STUCK_KEY && lk->id[3] != 0) printk (KERN_ERR "Scancode of stuck key is 0x%02x, keycode " "is 0x%04x\n", lk->id[3], lk->keycode[lk->id[3]]); return;}/* * lkkbd_interrupt() is called by the low level driver when a character * is received. */static irqreturn_tlkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs){ struct lkkbd *lk = serio_get_drvdata (serio); int i; DBG (KERN_INFO "Got byte 0x%02x\n", data); if (lk->ignore_bytes > 0) { DBG (KERN_INFO "Ignoring a byte on %s\n", lk->name); lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; if (lk->ignore_bytes == 0) lkkbd_detection_done (lk); return IRQ_HANDLED; } switch (data) { case LK_ALL_KEYS_UP: input_regs (lk->dev, regs); for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++) if (lk->keycode[i] != KEY_RESERVED) input_report_key (lk->dev, lk->keycode[i], 0); input_sync (lk->dev); break; case 0x01: DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n"); lk->ignore_bytes = LK_NUM_IGNORE_BYTES; lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; schedule_work (&lk->tq); break; case LK_METRONOME: case LK_OUTPUT_ERROR: case LK_INPUT_ERROR: case LK_KBD_LOCKED: case LK_KBD_TEST_MODE_ACK: case LK_PREFIX_KEY_DOWN: case LK_MODE_CHANGE_ACK: case LK_RESPONSE_RESERVED: DBG (KERN_INFO "Got %s and don't know how to handle...\n", response_name (data)); break; default: if (lk->keycode[data] != KEY_RESERVED) { input_regs (lk->dev, regs); if (!test_bit (lk->keycode[data], lk->dev->key)) input_report_key (lk->dev, lk->keycode[data], 1); else input_report_key (lk->dev, lk->keycode[data], 0); input_sync (lk->dev); } else printk (KERN_WARNING "%s: Unknown key with " "scancode 0x%02x on %s.\n", __FILE__, data, lk->name); } return IRQ_HANDLED;}/* * lkkbd_event() handles events from the input module. */static intlkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, int value){ struct lkkbd *lk = dev->private; unsigned char leds_on = 0; unsigned char leds_off = 0; switch (type) { case EV_LED: CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK); CHECK_LED (lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE); CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK); CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT); if (leds_on != 0) { lk->serio->write (lk->serio, LK_CMD_LED_ON); lk->serio->write (lk->serio, leds_on); } if (leds_off != 0) { lk->serio->write (lk->serio, LK_CMD_LED_OFF); lk->serio->write (lk->serio, leds_off); } return 0; case EV_SND: switch (code) { case SND_CLICK: if (value == 0) { DBG ("%s: Deactivating key clicks\n", __FUNCTION__); lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK); lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK); } else { DBG ("%s: Activating key clicks\n", __FUNCTION__); lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); } return 0; case SND_BELL: if (value != 0) lk->serio->write (lk->serio, LK_CMD_SOUND_BELL); return 0; } break; default: printk (KERN_ERR "%s (): Got unknown type %d, code %d, value %d\n", __FUNCTION__, type, code, value); } return -1;}/* * lkkbd_reinit() sets leds and beeps to a state the computer remembers they * were in. */static voidlkkbd_reinit (void *data){ struct lkkbd *lk = data; int division; unsigned char leds_on = 0; unsigned char leds_off = 0; /* Ask for ID */ lk->serio->write (lk->serio, LK_CMD_REQUEST_ID); /* Reset parameters */ lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS); /* Set LEDs */ CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK); CHECK_LED (lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE); CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK); CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT); if (leds_on != 0) { lk->serio->write (lk->serio, LK_CMD_LED_ON); lk->serio->write (lk->serio, leds_on); } if (leds_off != 0) { lk->serio->write (lk->serio, LK_CMD_LED_OFF); lk->serio->write (lk->serio, leds_off); } /* * Try to activate extended LK401 mode. This command will * only work with a LK401 keyboard and grants access to * LAlt, RAlt, RCompose and RShift. */ lk->serio->write (lk->serio, LK_CMD_ENABLE_LK401); /* Set all keys to UPDOWN mode */ for (division = 1; division <= 14; division++) lk->serio->write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN, division)); /* Enable bell and set volume */ lk->serio->write (lk->serio, LK_CMD_ENABLE_BELL); lk->serio->write (lk->serio, volume_to_hw (lk->bell_volume)); /* Enable/disable keyclick (and possibly set volume) */ if (test_bit (SND_CLICK, lk->dev->snd)) { lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK); lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume)); lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK); lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume)); } else { lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK); lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK); } /* Sound the bell if needed */ if (test_bit (SND_BELL, lk->dev->snd)) lk->serio->write (lk->serio, LK_CMD_SOUND_BELL);}/* * lkkbd_connect() probes for a LK keyboard and fills the necessary structures. */static intlkkbd_connect (struct serio *serio, struct serio_driver *drv){ struct lkkbd *lk; struct input_dev *input_dev; int i; int err; lk = kzalloc (sizeof (struct lkkbd), GFP_KERNEL); input_dev = input_allocate_device (); if (!lk || !input_dev) { err = -ENOMEM; goto fail; } lk->serio = serio; lk->dev = input_dev; INIT_WORK (&lk->tq, lkkbd_reinit, lk); lk->bell_volume = bell_volume; lk->keyclick_volume = keyclick_volume; lk->ctrlclick_volume = ctrlclick_volume; memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES); strlcpy (lk->name, "DEC LK keyboard", sizeof(lk->name)); snprintf (lk->phys, sizeof(lk->phys), "%s/input0", serio->phys); input_dev->name = lk->name; input_dev->phys = lk->phys; input_dev->id.bustype = BUS_RS232; input_dev->id.vendor = SERIO_LKKBD; input_dev->id.product = 0; input_dev->id.version = 0x0100; input_dev->cdev.dev = &serio->dev; input_dev->event = lkkbd_event; input_dev->private = lk; set_bit (EV_KEY, input_dev->evbit); set_bit (EV_LED, input_dev->evbit); set_bit (EV_SND, input_dev->evbit); set_bit (EV_REP, input_dev->evbit); set_bit (LED_CAPSL, input_dev->ledbit); set_bit (LED_SLEEP, input_dev->ledbit); set_bit (LED_COMPOSE, input_dev->ledbit); set_bit (LED_SCROLLL, input_dev->ledbit); set_bit (SND_BELL, input_dev->sndbit); set_bit (SND_CLICK, input_dev->sndbit); input_dev->keycode = lk->keycode; input_dev->keycodesize = sizeof (lk_keycode_t); input_dev->keycodemax = LK_NUM_KEYCODES; for (i = 0; i < LK_NUM_KEYCODES; i++) set_bit (lk->keycode[i], input_dev->keybit); serio_set_drvdata (serio, lk); err = serio_open (serio, drv); if (err) goto fail; input_register_device (lk->dev); lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET); return 0; fail: serio_set_drvdata (serio, NULL); input_free_device (input_dev); kfree (lk); return err;}/* * lkkbd_disconnect() unregisters and closes behind us. */static voidlkkbd_disconnect (struct serio *serio){ struct lkkbd *lk = serio_get_drvdata (serio); input_get_device (lk->dev); input_unregister_device (lk->dev); serio_close (serio); serio_set_drvdata (serio, NULL); input_put_device (lk->dev); kfree (lk);}static struct serio_device_id lkkbd_serio_ids[] = { { .type = SERIO_RS232, .proto = SERIO_LKKBD, .id = SERIO_ANY, .extra = SERIO_ANY, }, { 0 }};MODULE_DEVICE_TABLE(serio, lkkbd_serio_ids);static struct serio_driver lkkbd_drv = { .driver = { .name = "lkkbd", }, .description = DRIVER_DESC, .id_table = lkkbd_serio_ids, .connect = lkkbd_connect, .disconnect = lkkbd_disconnect, .interrupt = lkkbd_interrupt,};/* * The functions for insering/removing us as a module. */static int __initlkkbd_init (void){ serio_register_driver(&lkkbd_drv); return 0;}static void __exitlkkbd_exit (void){ serio_unregister_driver(&lkkbd_drv);}module_init (lkkbd_init);module_exit (lkkbd_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -