wistron_btns.c
来自「linux 内核源代码」· C语言 代码 · 共 1,383 行 · 第 1/3 页
C
1,383 行
const struct key_entry *key; struct key_entry *new_keymap; unsigned int length = 1; for (key = keymap; key->type != KE_END; key++) length++; new_keymap = kmalloc(length * sizeof(struct key_entry), GFP_KERNEL); if (!new_keymap) return -ENOMEM; memcpy(new_keymap, keymap, length * sizeof(struct key_entry)); keymap = new_keymap; return 0;}static int __init select_keymap(void){ dmi_check_system(dmi_ids); if (keymap_name != NULL) { if (strcmp (keymap_name, "1557/MS2141") == 0) keymap = keymap_wistron_ms2141; else if (strcmp (keymap_name, "generic") == 0) keymap = keymap_wistron_generic; else { printk(KERN_ERR "wistron_btns: Keymap unknown\n"); return -EINVAL; } } if (keymap == NULL) { if (!force) { printk(KERN_ERR "wistron_btns: System unknown\n"); return -ENODEV; } keymap = keymap_empty; } return copy_keymap();} /* Input layer interface */static struct input_polled_dev *wistron_idev;static unsigned long jiffies_last_press;static int wifi_enabled;static int bluetooth_enabled;static void report_key(struct input_dev *dev, unsigned int keycode){ input_report_key(dev, keycode, 1); input_sync(dev); input_report_key(dev, keycode, 0); input_sync(dev);}static void report_switch(struct input_dev *dev, unsigned int code, int value){ input_report_switch(dev, code, value); input_sync(dev);} /* led management */static void wistron_mail_led_set(struct led_classdev *led_cdev, enum led_brightness value){ bios_set_state(MAIL_LED, (value != LED_OFF) ? 1 : 0);}/* same as setting up wifi card, but for laptops on which the led is managed */static void wistron_wifi_led_set(struct led_classdev *led_cdev, enum led_brightness value){ bios_set_state(WIFI, (value != LED_OFF) ? 1 : 0);}static struct led_classdev wistron_mail_led = { .name = "mail:green", .brightness_set = wistron_mail_led_set,};static struct led_classdev wistron_wifi_led = { .name = "wifi:red", .brightness_set = wistron_wifi_led_set,};static void __devinit wistron_led_init(struct device *parent){ if (have_leds & FE_WIFI_LED) { u16 wifi = bios_get_default_setting(WIFI); if (wifi & 1) { wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF; if (led_classdev_register(parent, &wistron_wifi_led)) have_leds &= ~FE_WIFI_LED; else bios_set_state(WIFI, wistron_wifi_led.brightness); } else have_leds &= ~FE_WIFI_LED; } if (have_leds & FE_MAIL_LED) { /* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */ wistron_mail_led.brightness = LED_OFF; if (led_classdev_register(parent, &wistron_mail_led)) have_leds &= ~FE_MAIL_LED; else bios_set_state(MAIL_LED, wistron_mail_led.brightness); }}static void __devexit wistron_led_remove(void){ if (have_leds & FE_MAIL_LED) led_classdev_unregister(&wistron_mail_led); if (have_leds & FE_WIFI_LED) led_classdev_unregister(&wistron_wifi_led);}static inline void wistron_led_suspend(void){ if (have_leds & FE_MAIL_LED) led_classdev_suspend(&wistron_mail_led); if (have_leds & FE_WIFI_LED) led_classdev_suspend(&wistron_wifi_led);}static inline void wistron_led_resume(void){ if (have_leds & FE_MAIL_LED) led_classdev_resume(&wistron_mail_led); if (have_leds & FE_WIFI_LED) led_classdev_resume(&wistron_wifi_led);}static struct key_entry *wistron_get_entry_by_scancode(int code){ struct key_entry *key; for (key = keymap; key->type != KE_END; key++) if (code == key->code) return key; return NULL;}static struct key_entry *wistron_get_entry_by_keycode(int keycode){ struct key_entry *key; for (key = keymap; key->type != KE_END; key++) if (key->type == KE_KEY && keycode == key->keycode) return key; return NULL;}static void handle_key(u8 code){ const struct key_entry *key = wistron_get_entry_by_scancode(code); if (key) { switch (key->type) { case KE_KEY: report_key(wistron_idev->input, key->keycode); break; case KE_SW: report_switch(wistron_idev->input, key->sw.code, key->sw.value); break; case KE_WIFI: if (have_wifi) { wifi_enabled = !wifi_enabled; bios_set_state(WIFI, wifi_enabled); } break; case KE_BLUETOOTH: if (have_bluetooth) { bluetooth_enabled = !bluetooth_enabled; bios_set_state(BLUETOOTH, bluetooth_enabled); } break; default: BUG(); } jiffies_last_press = jiffies; } else printk(KERN_NOTICE "wistron_btns: Unknown key code %02X\n", code);}static void poll_bios(bool discard){ u8 qlen; u16 val; for (;;) { qlen = CMOS_READ(cmos_address); if (qlen == 0) break; val = bios_pop_queue(); if (val != 0 && !discard) handle_key((u8)val); }}static void wistron_flush(struct input_polled_dev *dev){ /* Flush stale event queue */ poll_bios(true);}static void wistron_poll(struct input_polled_dev *dev){ poll_bios(false); /* Increase poll frequency if user is currently pressing keys (< 2s ago) */ if (time_before(jiffies, jiffies_last_press + 2 * HZ)) dev->poll_interval = POLL_INTERVAL_BURST; else dev->poll_interval = POLL_INTERVAL_DEFAULT;}static int wistron_getkeycode(struct input_dev *dev, int scancode, int *keycode){ const struct key_entry *key = wistron_get_entry_by_scancode(scancode); if (key && key->type == KE_KEY) { *keycode = key->keycode; return 0; } return -EINVAL;}static int wistron_setkeycode(struct input_dev *dev, int scancode, int keycode){ struct key_entry *key; int old_keycode; if (keycode < 0 || keycode > KEY_MAX) return -EINVAL; key = wistron_get_entry_by_scancode(scancode); if (key && key->type == KE_KEY) { old_keycode = key->keycode; key->keycode = keycode; set_bit(keycode, dev->keybit); if (!wistron_get_entry_by_keycode(old_keycode)) clear_bit(old_keycode, dev->keybit); return 0; } return -EINVAL;}static int __devinit setup_input_dev(void){ const struct key_entry *key; struct input_dev *input_dev; int error; wistron_idev = input_allocate_polled_device(); if (!wistron_idev) return -ENOMEM; wistron_idev->flush = wistron_flush; wistron_idev->poll = wistron_poll; wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT; input_dev = wistron_idev->input; input_dev->name = "Wistron laptop buttons"; input_dev->phys = "wistron/input0"; input_dev->id.bustype = BUS_HOST; input_dev->dev.parent = &wistron_device->dev; input_dev->getkeycode = wistron_getkeycode; input_dev->setkeycode = wistron_setkeycode; for (key = keymap; key->type != KE_END; key++) { switch (key->type) { case KE_KEY: set_bit(EV_KEY, input_dev->evbit); set_bit(key->keycode, input_dev->keybit); break; case KE_SW: set_bit(EV_SW, input_dev->evbit); set_bit(key->sw.code, input_dev->swbit); break; default: break; } } /* reads information flags on KE_END */ if (key->code & FE_UNTESTED) printk(KERN_WARNING "Untested laptop multimedia keys, " "please report success or failure to eric.piel" "@tremplin-utc.net\n"); error = input_register_polled_device(wistron_idev); if (error) { input_free_polled_device(wistron_idev); return error; } return 0;}/* Driver core */static int __devinit wistron_probe(struct platform_device *dev){ int err; bios_attach(); cmos_address = bios_get_cmos_address(); if (have_wifi) { u16 wifi = bios_get_default_setting(WIFI); if (wifi & 1) wifi_enabled = (wifi & 2) ? 1 : 0; else have_wifi = 0; if (have_wifi) bios_set_state(WIFI, wifi_enabled); } if (have_bluetooth) { u16 bt = bios_get_default_setting(BLUETOOTH); if (bt & 1) bluetooth_enabled = (bt & 2) ? 1 : 0; else have_bluetooth = 0; if (have_bluetooth) bios_set_state(BLUETOOTH, bluetooth_enabled); } wistron_led_init(&dev->dev); err = setup_input_dev(); if (err) { bios_detach(); return err; } return 0;}static int __devexit wistron_remove(struct platform_device *dev){ wistron_led_remove(); input_unregister_polled_device(wistron_idev); input_free_polled_device(wistron_idev); bios_detach(); return 0;}#ifdef CONFIG_PMstatic int wistron_suspend(struct platform_device *dev, pm_message_t state){ if (have_wifi) bios_set_state(WIFI, 0); if (have_bluetooth) bios_set_state(BLUETOOTH, 0); wistron_led_suspend(); return 0;}static int wistron_resume(struct platform_device *dev){ if (have_wifi) bios_set_state(WIFI, wifi_enabled); if (have_bluetooth) bios_set_state(BLUETOOTH, bluetooth_enabled); wistron_led_resume(); poll_bios(true); return 0;}#else#define wistron_suspend NULL#define wistron_resume NULL#endifstatic struct platform_driver wistron_driver = { .driver = { .name = "wistron-bios", .owner = THIS_MODULE, }, .probe = wistron_probe, .remove = __devexit_p(wistron_remove), .suspend = wistron_suspend, .resume = wistron_resume,};static int __init wb_module_init(void){ int err; err = select_keymap(); if (err) return err; err = map_bios(); if (err) return err; err = platform_driver_register(&wistron_driver); if (err) goto err_unmap_bios; wistron_device = platform_device_alloc("wistron-bios", -1); if (!wistron_device) { err = -ENOMEM; goto err_unregister_driver; } err = platform_device_add(wistron_device); if (err) goto err_free_device; return 0; err_free_device: platform_device_put(wistron_device); err_unregister_driver: platform_driver_unregister(&wistron_driver); err_unmap_bios: unmap_bios(); return err;}static void __exit wb_module_exit(void){ platform_device_unregister(wistron_device); platform_driver_unregister(&wistron_driver); unmap_bios(); kfree(keymap);}module_init(wb_module_init);module_exit(wb_module_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?