asus_acpi.c

来自「linux 内核源代码」· C语言 代码 · 共 1,425 行 · 第 1/3 页

C
1,425
字号
{	struct proc_dir_entry *proc;	mode_t mode;	/*	 * If parameter uid or gid is not changed, keep the default setting for	 * our proc entries (-rw-rw-rw-) else, it means we care about security,	 * and then set to -rw-rw----	 */	if ((asus_uid == 0) && (asus_gid == 0)) {		mode = S_IFREG | S_IRUGO | S_IWUGO;	} else {		mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;		printk(KERN_WARNING "  asus_uid and asus_gid parameters are "		       "deprecated, use chown and chmod instead!\n");	}	acpi_device_dir(device) = asus_proc_dir;	if (!acpi_device_dir(device))		return -ENODEV;	proc = create_proc_entry(PROC_INFO, mode, acpi_device_dir(device));	if (proc) {		proc->read_proc = proc_read_info;		proc->data = acpi_driver_data(device);		proc->owner = THIS_MODULE;		proc->uid = asus_uid;		proc->gid = asus_gid;	} else {		printk(KERN_WARNING "  Unable to create " PROC_INFO		       " fs entry\n");	}	if (hotk->methods->mt_wled) {		asus_proc_add(PROC_WLED, &proc_write_wled, &proc_read_wled,			      mode, device);	}	if (hotk->methods->mt_ledd) {		asus_proc_add(PROC_LEDD, &proc_write_ledd, &proc_read_ledd,			      mode, device);	}	if (hotk->methods->mt_mled) {		asus_proc_add(PROC_MLED, &proc_write_mled, &proc_read_mled,			      mode, device);	}	if (hotk->methods->mt_tled) {		asus_proc_add(PROC_TLED, &proc_write_tled, &proc_read_tled,			      mode, device);	}	if (hotk->methods->mt_bt_switch) {		asus_proc_add(PROC_BT, &proc_write_bluetooth,			      &proc_read_bluetooth, mode, device);	}	/* 	 * We need both read node and write method as LCD switch is also accessible	 * from keyboard 	 */	if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {		asus_proc_add(PROC_LCD, &proc_write_lcd, &proc_read_lcd, mode,			      device);	}	if ((hotk->methods->brightness_up && hotk->methods->brightness_down) ||	    (hotk->methods->brightness_get && hotk->methods->brightness_set)) {		asus_proc_add(PROC_BRN, &proc_write_brn, &proc_read_brn, mode,			      device);	}	if (hotk->methods->display_set) {		asus_proc_add(PROC_DISP, &proc_write_disp, &proc_read_disp,			      mode, device);	}	return 0;}static int asus_hotk_remove_fs(struct acpi_device *device){	if (acpi_device_dir(device)) {		remove_proc_entry(PROC_INFO, acpi_device_dir(device));		if (hotk->methods->mt_wled)			remove_proc_entry(PROC_WLED, acpi_device_dir(device));		if (hotk->methods->mt_mled)			remove_proc_entry(PROC_MLED, acpi_device_dir(device));		if (hotk->methods->mt_tled)			remove_proc_entry(PROC_TLED, acpi_device_dir(device));		if (hotk->methods->mt_ledd)			remove_proc_entry(PROC_LEDD, acpi_device_dir(device));		if (hotk->methods->mt_bt_switch)			remove_proc_entry(PROC_BT, acpi_device_dir(device));		if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status)			remove_proc_entry(PROC_LCD, acpi_device_dir(device));		if ((hotk->methods->brightness_up		     && hotk->methods->brightness_down)		    || (hotk->methods->brightness_get			&& hotk->methods->brightness_set))			remove_proc_entry(PROC_BRN, acpi_device_dir(device));		if (hotk->methods->display_set)			remove_proc_entry(PROC_DISP, acpi_device_dir(device));	}	return 0;}static void asus_hotk_notify(acpi_handle handle, u32 event, void *data){	/* TODO Find a better way to handle events count. */	if (!hotk)		return;	if ((event & ~((u32) BR_UP)) < 16) {		hotk->brightness = (event & ~((u32) BR_UP));	} else if ((event & ~((u32) BR_DOWN)) < 16) {		hotk->brightness = (event & ~((u32) BR_DOWN));	}	acpi_bus_generate_proc_event(hotk->device, event,				hotk->event_count[event % 128]++);	return;}/* * Match the model string to the list of supported models. Return END_MODEL if * no match or model is NULL. */static int asus_model_match(char *model){	if (model == NULL)		return END_MODEL;	if (strncmp(model, "L3D", 3) == 0)		return L3D;	else if (strncmp(model, "L2E", 3) == 0 ||		 strncmp(model, "L3H", 3) == 0 || strncmp(model, "L5D", 3) == 0)		return L3H;	else if (strncmp(model, "L3", 2) == 0 || strncmp(model, "L2B", 3) == 0)		return L3C;	else if (strncmp(model, "L8L", 3) == 0)		return L8L;	else if (strncmp(model, "L4R", 3) == 0)		return L4R;	else if (strncmp(model, "M6N", 3) == 0 || strncmp(model, "W3N", 3) == 0)		return M6N;	else if (strncmp(model, "M6R", 3) == 0 || strncmp(model, "A3G", 3) == 0)		return M6R;	else if (strncmp(model, "M2N", 3) == 0 ||		 strncmp(model, "M3N", 3) == 0 ||		 strncmp(model, "M5N", 3) == 0 ||		 strncmp(model, "M6N", 3) == 0 ||		 strncmp(model, "S1N", 3) == 0 ||		 strncmp(model, "S5N", 3) == 0 || strncmp(model, "W1N", 3) == 0)		return xxN;	else if (strncmp(model, "M1", 2) == 0)		return M1A;	else if (strncmp(model, "M2", 2) == 0 || strncmp(model, "L4E", 3) == 0)		return M2E;	else if (strncmp(model, "L2", 2) == 0)		return L2D;	else if (strncmp(model, "L8", 2) == 0)		return S1x;	else if (strncmp(model, "D1", 2) == 0)		return D1x;	else if (strncmp(model, "A1", 2) == 0)		return A1x;	else if (strncmp(model, "A2", 2) == 0)		return A2x;	else if (strncmp(model, "J1", 2) == 0)		return S2x;	else if (strncmp(model, "L5", 2) == 0)		return L5x;	else if (strncmp(model, "A4G", 3) == 0)		return A4G;	else if (strncmp(model, "W1N", 3) == 0)		return W1N;	else if (strncmp(model, "W3V", 3) == 0)		return W3V;	else if (strncmp(model, "W5A", 3) == 0)		return W5A;	else if (strncmp(model, "A4S", 3) == 0)		return A4S;	else		return END_MODEL;}/* * This function is used to initialize the hotk with right values. In this * method, we can make all the detection we want, and modify the hotk struct */static int asus_hotk_get_info(void){	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };	union acpi_object *model = NULL;	int bsts_result;	char *string = NULL;	acpi_status status;	/*	 * Get DSDT headers early enough to allow for differentiating between 	 * models, but late enough to allow acpi_bus_register_driver() to fail 	 * before doing anything ACPI-specific. Should we encounter a machine,	 * which needs special handling (i.e. its hotkey device has a different	 * HID), this bit will be moved. A global variable asus_info contains	 * the DSDT header.	 */	status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);	if (ACPI_FAILURE(status))		printk(KERN_WARNING "  Couldn't get the DSDT table header\n");	/* We have to write 0 on init this far for all ASUS models */	if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {		printk(KERN_ERR "  Hotkey initialization failed\n");		return -ENODEV;	}	/* This needs to be called for some laptops to init properly */	if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result))		printk(KERN_WARNING "  Error calling BSTS\n");	else if (bsts_result)		printk(KERN_NOTICE "  BSTS called, 0x%02x returned\n",		       bsts_result);	/*	 * Try to match the object returned by INIT to the specific model.	 * Handle every possible object (or the lack of thereof) the DSDT 	 * writers might throw at us. When in trouble, we pass NULL to 	 * asus_model_match() and try something completely different.	 */	if (buffer.pointer) {		model = buffer.pointer;		switch (model->type) {		case ACPI_TYPE_STRING:			string = model->string.pointer;			break;		case ACPI_TYPE_BUFFER:			string = model->buffer.pointer;			break;		default:			kfree(model);			model = NULL;			break;		}	}	hotk->model = asus_model_match(string);	if (hotk->model == END_MODEL) {	/* match failed */		if (asus_info &&		    strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) {			hotk->model = P30;			printk(KERN_NOTICE			       "  Samsung P30 detected, supported\n");		} else {			hotk->model = M2E;			printk(KERN_NOTICE "  unsupported model %s, trying "			       "default values\n", string);			printk(KERN_NOTICE			       "  send /proc/acpi/dsdt to the developers\n");		}		hotk->methods = &model_conf[hotk->model];		return AE_OK;	}	hotk->methods = &model_conf[hotk->model];	printk(KERN_NOTICE "  %s model detected, supported\n", string);	/* Sort of per-model blacklist */	if (strncmp(string, "L2B", 3) == 0)		hotk->methods->lcd_status = NULL;	/* L2B is similar enough to L3C to use its settings, with this only 	   exception */	else if (strncmp(string, "A3G", 3) == 0)		hotk->methods->lcd_status = "\\BLFG";	/* A3G is like M6R */	else if (strncmp(string, "S5N", 3) == 0 ||		 strncmp(string, "M5N", 3) == 0 ||		 strncmp(string, "W3N", 3) == 0)		hotk->methods->mt_mled = NULL;	/* S5N, M5N and W3N have no MLED */	else if (strncmp(string, "L5D", 3) == 0)		hotk->methods->mt_wled = NULL;	/* L5D's WLED is not controlled by ACPI */	else if (strncmp(string, "M2N", 3) == 0 ||		 strncmp(string, "W3V", 3) == 0 ||		 strncmp(string, "S1N", 3) == 0)		hotk->methods->mt_wled = "WLED";	/* M2N, S1N and W3V have a usable WLED */	else if (asus_info) {		if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)			hotk->methods->mled_status = NULL;		/* S1300A reports L84F, but L1400B too, account for that */	}	kfree(model);	return AE_OK;}static int asus_hotk_check(void){	int result = 0;	result = acpi_bus_get_status(hotk->device);	if (result)		return result;	if (hotk->device->status.present) {		result = asus_hotk_get_info();	} else {		printk(KERN_ERR "  Hotkey device not present, aborting\n");		return -EINVAL;	}	return result;}static int asus_hotk_found;static int asus_hotk_add(struct acpi_device *device){	acpi_status status = AE_OK;	int result;	if (!device)		return -EINVAL;	printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n",	       ASUS_ACPI_VERSION);	hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);	if (!hotk)		return -ENOMEM;	hotk->handle = device->handle;	strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME);	strcpy(acpi_device_class(device), ACPI_HOTK_CLASS);	acpi_driver_data(device) = hotk;	hotk->device = device;	result = asus_hotk_check();	if (result)		goto end;	result = asus_hotk_add_fs(device);	if (result)		goto end;	/*	 * We install the handler, it will receive the hotk in parameter, so, we	 * could add other data to the hotk struct	 */	status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,					     asus_hotk_notify, hotk);	if (ACPI_FAILURE(status))		printk(KERN_ERR "  Error installing notify handler\n");	/* For laptops without GPLV: init the hotk->brightness value */	if ((!hotk->methods->brightness_get)	    && (!hotk->methods->brightness_status)	    && (hotk->methods->brightness_up && hotk->methods->brightness_down)) {		status =		    acpi_evaluate_object(NULL, hotk->methods->brightness_down,					 NULL, NULL);		if (ACPI_FAILURE(status))			printk(KERN_WARNING "  Error changing brightness\n");		else {			status =			    acpi_evaluate_object(NULL,						 hotk->methods->brightness_up,						 NULL, NULL);			if (ACPI_FAILURE(status))				printk(KERN_WARNING "  Strange, error changing"				       " brightness\n");		}	}	asus_hotk_found = 1;	/* LED display is off by default */	hotk->ledd_status = 0xFFF;      end:	if (result) {		kfree(hotk);	}	return result;}static int asus_hotk_remove(struct acpi_device *device, int type){	acpi_status status = 0;	if (!device || !acpi_driver_data(device))		return -EINVAL;	status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,					    asus_hotk_notify);	if (ACPI_FAILURE(status))		printk(KERN_ERR "Asus ACPI: Error removing notify handler\n");	asus_hotk_remove_fs(device);	kfree(hotk);	return 0;}static struct backlight_ops asus_backlight_data = {        .get_brightness = read_brightness,        .update_status  = set_brightness_status,};static void asus_acpi_exit(void){	if (asus_backlight_device)		backlight_device_unregister(asus_backlight_device);	acpi_bus_unregister_driver(&asus_hotk_driver);	remove_proc_entry(PROC_ASUS, acpi_root_dir);	return;}static int __init asus_acpi_init(void){	int result;	if (acpi_disabled)		return -ENODEV;	asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);	if (!asus_proc_dir) {		printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n");		return -ENODEV;	}	asus_proc_dir->owner = THIS_MODULE;	result = acpi_bus_register_driver(&asus_hotk_driver);	if (result < 0) {		remove_proc_entry(PROC_ASUS, acpi_root_dir);		return result;	}	/*	 * This is a bit of a kludge.  We only want this module loaded	 * for ASUS systems, but there's currently no way to probe the	 * ACPI namespace for ASUS HIDs.  So we just return failure if	 * we didn't find one, which will cause the module to be	 * unloaded.	 */	if (!asus_hotk_found) {		acpi_bus_unregister_driver(&asus_hotk_driver);		remove_proc_entry(PROC_ASUS, acpi_root_dir);		return -ENODEV;	}	asus_backlight_device = backlight_device_register("asus",NULL,NULL,							  &asus_backlight_data);        if (IS_ERR(asus_backlight_device)) {		printk(KERN_ERR "Could not register asus backlight device\n");		asus_backlight_device = NULL;		asus_acpi_exit();		return -ENODEV;	}        asus_backlight_device->props.max_brightness = 15;	return 0;}module_init(asus_acpi_init);module_exit(asus_acpi_exit);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?