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 + -
显示快捷键?