asus_acpi.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,237 行 · 第 1/3 页
C
1,237 行
int *eof, void *data);typedef int (proc_writefunc)(struct file *file, const char __user *buffer, unsigned long count, void *data);static int__init asus_proc_add(char *name, proc_writefunc *writefunc, proc_readfunc *readfunc, mode_t mode, struct acpi_device *device){ struct proc_dir_entry *proc = create_proc_entry(name, mode, acpi_device_dir(device)); if(!proc) { printk(KERN_WARNING " Unable to create %s fs entry\n", name); return -1; } proc->write_proc = writefunc; proc->read_proc = readfunc; proc->data = acpi_driver_data(device); proc->owner = THIS_MODULE; proc->uid = asus_uid; proc->gid = asus_gid; return 0;}static int __init asus_hotk_add_fs(struct acpi_device *device){ 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; } 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_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); } /* * 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_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_event(hotk->device, event, hotk->event_count[event % 128]++); return;}/* * 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 __init asus_hotk_get_info(void){ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *model = NULL; int bsts_result; 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_TABLE_DSDT, 1, &dsdt); if (ACPI_FAILURE(status)) printk(KERN_WARNING " Couldn't get the DSDT table header\n"); else asus_info = (struct acpi_table_header *) dsdt.pointer; /* 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); /* Samsung P30 has a device with a valid _HID whose INIT does not * return anything. Catch this one and any similar here */ if (buffer.pointer == NULL) { if (asus_info && /* Samsung P30 */ 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_WARNING " no string returned by INIT\n"); printk(KERN_WARNING " trying default values, supply " "the developers with your DSDT\n"); } hotk->methods = &model_conf[hotk->model]; return AE_OK; } model = (union acpi_object *) buffer.pointer; if (model->type == ACPI_TYPE_STRING) { printk(KERN_NOTICE " %s model detected, ", model->string.pointer); } hotk->model = END_MODEL; if (strncmp(model->string.pointer, "L3D", 3) == 0) hotk->model = L3D; else if (strncmp(model->string.pointer, "L3H", 3) == 0 || strncmp(model->string.pointer, "L2E", 3) == 0) hotk->model = L3H; else if (strncmp(model->string.pointer, "L3", 2) == 0 || strncmp(model->string.pointer, "L2B", 3) == 0) hotk->model = L3C; else if (strncmp(model->string.pointer, "L8L", 3) == 0) hotk->model = L8L; else if (strncmp(model->string.pointer, "L4R", 3) == 0) hotk->model = L4R; else if (strncmp(model->string.pointer, "M6N", 3) == 0) hotk->model = M6N; else if (strncmp(model->string.pointer, "M6R", 3) == 0) hotk->model = M6R; else if (strncmp(model->string.pointer, "M2N", 3) == 0 || strncmp(model->string.pointer, "M3N", 3) == 0 || strncmp(model->string.pointer, "M5N", 3) == 0 || strncmp(model->string.pointer, "M6N", 3) == 0 || strncmp(model->string.pointer, "S1N", 3) == 0 || strncmp(model->string.pointer, "S5N", 3) == 0 || strncmp(model->string.pointer, "W1N", 3) == 0) hotk->model = xxN; else if (strncmp(model->string.pointer, "M1", 2) == 0) hotk->model = M1A; else if (strncmp(model->string.pointer, "M2", 2) == 0 || strncmp(model->string.pointer, "L4E", 3) == 0) hotk->model = M2E; else if (strncmp(model->string.pointer, "L2", 2) == 0) hotk->model = L2D; else if (strncmp(model->string.pointer, "L8", 2) == 0) hotk->model = S1x; else if (strncmp(model->string.pointer, "D1", 2) == 0) hotk->model = D1x; else if (strncmp(model->string.pointer, "A1", 2) == 0) hotk->model = A1x; else if (strncmp(model->string.pointer, "A2", 2) == 0) hotk->model = A2x; else if (strncmp(model->string.pointer, "J1", 2) == 0) hotk->model = S2x; else if (strncmp(model->string.pointer, "L5", 2) == 0) hotk->model = L5x; if (hotk->model == END_MODEL) { printk("unsupported, trying default values, supply the " "developers with your DSDT\n"); hotk->model = M2E; } else { printk("supported\n"); } hotk->methods = &model_conf[hotk->model]; /* Sort of per-model blacklist */ if (strncmp(model->string.pointer, "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(model->string.pointer, "S5N", 3) == 0 || strncmp(model->string.pointer, "M5N", 3) == 0) hotk->methods->mt_mled = NULL; /* S5N and M5N have no MLED */ else if (strncmp(model->string.pointer, "M2N", 3) == 0 || strncmp(model->string.pointer, "W1N", 3) == 0) hotk->methods->mt_wled = "WLED"; /* M2N and W1N 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 */ } acpi_os_free(model); return AE_OK;}static int __init 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 __init 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 = (struct asus_hotk *) kmalloc(sizeof(struct asus_hotk), GFP_KERNEL); if (!hotk) return(-ENOMEM); memset(hotk, 0, sizeof(struct asus_hotk)); 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"); } } 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 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 < 1) { acpi_bus_unregister_driver(&asus_hotk_driver); remove_proc_entry(PROC_ASUS, acpi_root_dir); return -ENODEV; } return 0;}static void __exit asus_acpi_exit(void){ acpi_bus_unregister_driver(&asus_hotk_driver); remove_proc_entry(PROC_ASUS, acpi_root_dir); acpi_os_free(asus_info); return;}module_init(asus_acpi_init);module_exit(asus_acpi_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?