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