📄 asus-laptop.c
字号:
/* * 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; ulong bsts_result, hwrs_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(ASUS_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(ASUS_ERR "Hotkey initialization failed\n"); return -ENODEV; } /* This needs to be called for some laptops to init properly */ status = acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result); if (ACPI_FAILURE(status)) printk(ASUS_WARNING "Error calling BSTS\n"); else if (bsts_result) printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n", (uint) bsts_result); /* This too ... */ write_acpi_int(hotk->handle, "CWAP", wapf, NULL); /* * 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: string = ""; break; } } hotk->name = kstrdup(string, GFP_KERNEL); if (!hotk->name) return -ENOMEM; if (*string) printk(ASUS_NOTICE " %s model detected\n", string); ASUS_HANDLE_INIT(mled_set); ASUS_HANDLE_INIT(tled_set); ASUS_HANDLE_INIT(rled_set); ASUS_HANDLE_INIT(pled_set); ASUS_HANDLE_INIT(gled_set); ASUS_HANDLE_INIT(ledd_set); /* * The HWRS method return informations about the hardware. * 0x80 bit is for WLAN, 0x100 for Bluetooth. * The significance of others is yet to be found. * If we don't find the method, we assume the device are present. */ status = acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result); if (ACPI_FAILURE(status)) hwrs_result = WL_HWRS | BT_HWRS; if (hwrs_result & WL_HWRS) ASUS_HANDLE_INIT(wl_switch); if (hwrs_result & BT_HWRS) ASUS_HANDLE_INIT(bt_switch); ASUS_HANDLE_INIT(wireless_status); ASUS_HANDLE_INIT(brightness_set); ASUS_HANDLE_INIT(brightness_get); ASUS_HANDLE_INIT(lcd_switch); ASUS_HANDLE_INIT(display_set); ASUS_HANDLE_INIT(display_get); /* There is a lot of models with "ALSL", but a few get a real light sens, so we need to check it. */ if (!ASUS_HANDLE_INIT(ls_switch)) ASUS_HANDLE_INIT(ls_level); ASUS_HANDLE_INIT(gps_on); ASUS_HANDLE_INIT(gps_off); ASUS_HANDLE_INIT(gps_status); 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(ASUS_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(ASUS_NOTICE "Asus Laptop Support version %s\n", ASUS_LAPTOP_VERSION); hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL); if (!hotk) return -ENOMEM; hotk->handle = device->handle; strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME); strcpy(acpi_device_class(device), ASUS_HOTK_CLASS); acpi_driver_data(device) = hotk; hotk->device = device; result = asus_hotk_check(); if (result) goto end; asus_hotk_add_fs(); /* * 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_ALL_NOTIFY, asus_hotk_notify, hotk); if (ACPI_FAILURE(status)) printk(ASUS_ERR "Error installing notify handler\n"); asus_hotk_found = 1; /* WLED and BLED are on by default */ write_status(bt_switch_handle, 1, BT_ON); write_status(wl_switch_handle, 1, WL_ON); /* If the h/w switch is off, we need to check the real status */ write_status(NULL, read_status(BT_ON), BT_ON); write_status(NULL, read_status(WL_ON), WL_ON); /* LCD Backlight is on by default */ write_status(NULL, 1, LCD_ON); /* LED display is off by default */ hotk->ledd_status = 0xFFF; /* Set initial values of light sensor and level */ hotk->light_switch = 1; /* Default to light sensor disabled */ hotk->light_level = 0; /* level 5 for sensor sensitivity */ if (ls_switch_handle) set_light_sens_switch(hotk->light_switch); if (ls_level_handle) set_light_sens_level(hotk->light_level); /* GPS is on by default */ write_status(NULL, 1, GPS_ON); end: if (result) { kfree(hotk->name); 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_ALL_NOTIFY, asus_hotk_notify); if (ACPI_FAILURE(status)) printk(ASUS_ERR "Error removing notify handler\n"); kfree(hotk->name); kfree(hotk); return 0;}static void asus_backlight_exit(void){ if (asus_backlight_device) backlight_device_unregister(asus_backlight_device);}#define ASUS_LED_UNREGISTER(object) \ if (object##_led.dev) \ led_classdev_unregister(&object##_led)static void asus_led_exit(void){ destroy_workqueue(led_workqueue); ASUS_LED_UNREGISTER(mled); ASUS_LED_UNREGISTER(tled); ASUS_LED_UNREGISTER(pled); ASUS_LED_UNREGISTER(rled); ASUS_LED_UNREGISTER(gled);}static void __exit asus_laptop_exit(void){ asus_backlight_exit(); asus_led_exit(); acpi_bus_unregister_driver(&asus_hotk_driver); sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group); platform_device_unregister(asuspf_device); platform_driver_unregister(&asuspf_driver);}static int asus_backlight_init(struct device *dev){ struct backlight_device *bd; if (brightness_set_handle && lcd_switch_handle) { bd = backlight_device_register(ASUS_HOTK_FILE, dev, NULL, &asusbl_ops); if (IS_ERR(bd)) { printk(ASUS_ERR "Could not register asus backlight device\n"); asus_backlight_device = NULL; return PTR_ERR(bd); } asus_backlight_device = bd; bd->props.max_brightness = 15; bd->props.brightness = read_brightness(NULL); bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); } return 0;}static int asus_led_register(acpi_handle handle, struct led_classdev *ldev, struct device *dev){ if (!handle) return 0; return led_classdev_register(dev, ldev);}#define ASUS_LED_REGISTER(object, device) \ asus_led_register(object##_set_handle, &object##_led, device)static int asus_led_init(struct device *dev){ int rv; rv = ASUS_LED_REGISTER(mled, dev); if (rv) goto out; rv = ASUS_LED_REGISTER(tled, dev); if (rv) goto out1; rv = ASUS_LED_REGISTER(rled, dev); if (rv) goto out2; rv = ASUS_LED_REGISTER(pled, dev); if (rv) goto out3; rv = ASUS_LED_REGISTER(gled, dev); if (rv) goto out4; led_workqueue = create_singlethread_workqueue("led_workqueue"); if (!led_workqueue) goto out5; return 0;out5: rv = -ENOMEM; ASUS_LED_UNREGISTER(gled);out4: ASUS_LED_UNREGISTER(pled);out3: ASUS_LED_UNREGISTER(rled);out2: ASUS_LED_UNREGISTER(tled);out1: ASUS_LED_UNREGISTER(mled);out: return rv;}static int __init asus_laptop_init(void){ struct device *dev; int result; if (acpi_disabled) return -ENODEV; result = acpi_bus_register_driver(&asus_hotk_driver); if (result < 0) 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); return -ENODEV; } dev = acpi_get_physical_device(hotk->device->handle); result = asus_backlight_init(dev); if (result) goto fail_backlight; result = asus_led_init(dev); if (result) goto fail_led; /* Register platform stuff */ result = platform_driver_register(&asuspf_driver); if (result) goto fail_platform_driver; asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1); if (!asuspf_device) { result = -ENOMEM; goto fail_platform_device1; } result = platform_device_add(asuspf_device); if (result) goto fail_platform_device2; result = sysfs_create_group(&asuspf_device->dev.kobj, &asuspf_attribute_group); if (result) goto fail_sysfs; return 0; fail_sysfs: platform_device_del(asuspf_device); fail_platform_device2: platform_device_put(asuspf_device); fail_platform_device1: platform_driver_unregister(&asuspf_driver); fail_platform_driver: asus_led_exit(); fail_led: asus_backlight_exit(); fail_backlight: return result;}module_init(asus_laptop_init);module_exit(asus_laptop_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -