📄 thermal.c
字号:
return -EINVAL; if (!tz->flags.cooling_mode) return -ENODEV; if (copy_from_user(mode_string, buffer, count)) return -EFAULT; mode_string[count] = '\0'; result = acpi_thermal_set_cooling_mode(tz, simple_strtoul(mode_string, NULL, 0)); if (result) return result; acpi_thermal_check(tz); return count;}static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset){ struct acpi_thermal *tz = seq->private; if (!tz) goto end; if (!tz->polling_frequency) { seq_puts(seq, "<polling disabled>\n"); goto end; } seq_printf(seq, "polling frequency: %lu seconds\n", (tz->polling_frequency / 10)); end: return 0;}static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file){ return single_open(file, acpi_thermal_polling_seq_show, PDE(inode)->data);}static ssize_tacpi_thermal_write_polling(struct file *file, const char __user * buffer, size_t count, loff_t * ppos){ struct seq_file *m = file->private_data; struct acpi_thermal *tz = m->private; int result = 0; char polling_string[12] = { '\0' }; int seconds = 0; if (!tz || (count > sizeof(polling_string) - 1)) return -EINVAL; if (copy_from_user(polling_string, buffer, count)) return -EFAULT; polling_string[count] = '\0'; seconds = simple_strtoul(polling_string, NULL, 0); result = acpi_thermal_set_polling(tz, seconds); if (result) return result; acpi_thermal_check(tz); return count;}static int acpi_thermal_add_fs(struct acpi_device *device){ struct proc_dir_entry *entry = NULL; if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_thermal_dir); if (!acpi_device_dir(device)) return -ENODEV; acpi_device_dir(device)->owner = THIS_MODULE; } /* 'state' [R] */ entry = create_proc_entry(ACPI_THERMAL_FILE_STATE, S_IRUGO, acpi_device_dir(device)); if (!entry) return -ENODEV; else { entry->proc_fops = &acpi_thermal_state_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } /* 'temperature' [R] */ entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE, S_IRUGO, acpi_device_dir(device)); if (!entry) return -ENODEV; else { entry->proc_fops = &acpi_thermal_temp_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } /* 'trip_points' [R] */ entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS, S_IRUGO, acpi_device_dir(device)); if (!entry) return -ENODEV; else { entry->proc_fops = &acpi_thermal_trip_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } /* 'cooling_mode' [R/W] */ entry = create_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE, S_IFREG | S_IRUGO | S_IWUSR, acpi_device_dir(device)); if (!entry) return -ENODEV; else { entry->proc_fops = &acpi_thermal_cooling_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } /* 'polling_frequency' [R/W] */ entry = create_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ, S_IFREG | S_IRUGO | S_IWUSR, acpi_device_dir(device)); if (!entry) return -ENODEV; else { entry->proc_fops = &acpi_thermal_polling_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } return 0;}static int acpi_thermal_remove_fs(struct acpi_device *device){ if (acpi_device_dir(device)) { remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ, acpi_device_dir(device)); remove_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE, acpi_device_dir(device)); remove_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS, acpi_device_dir(device)); remove_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE, acpi_device_dir(device)); remove_proc_entry(ACPI_THERMAL_FILE_STATE, acpi_device_dir(device)); remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir); acpi_device_dir(device) = NULL; } return 0;}/* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data){ struct acpi_thermal *tz = data; struct acpi_device *device = NULL; if (!tz) return; device = tz->device; switch (event) { case ACPI_THERMAL_NOTIFY_TEMPERATURE: acpi_thermal_check(tz); break; case ACPI_THERMAL_NOTIFY_THRESHOLDS: acpi_thermal_get_trip_points(tz); acpi_thermal_check(tz); acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, device->dev.bus_id, event, 0); break; case ACPI_THERMAL_NOTIFY_DEVICES: if (tz->flags.devices) acpi_thermal_get_devices(tz); acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_netlink_event(device->pnp.device_class, device->dev.bus_id, event, 0); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); break; } return;}static int acpi_thermal_get_info(struct acpi_thermal *tz){ int result = 0; if (!tz) return -EINVAL; /* Get temperature [_TMP] (required) */ result = acpi_thermal_get_temperature(tz); if (result) return result; /* Get trip points [_CRT, _PSV, etc.] (required) */ result = acpi_thermal_get_trip_points(tz); if (result) return result; /* Set the cooling mode [_SCP] to active cooling (default) */ result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE); if (!result) tz->flags.cooling_mode = 1; /* Get default polling frequency [_TZP] (optional) */ if (tzp) tz->polling_frequency = tzp; else acpi_thermal_get_polling_frequency(tz); /* Get devices in this thermal zone [_TZD] (optional) */ result = acpi_thermal_get_devices(tz); if (!result) tz->flags.devices = 1; return 0;}static int acpi_thermal_add(struct acpi_device *device){ int result = 0; acpi_status status = AE_OK; struct acpi_thermal *tz = NULL; if (!device) return -EINVAL; tz = kzalloc(sizeof(struct acpi_thermal), GFP_KERNEL); if (!tz) return -ENOMEM; tz->device = device; strcpy(tz->name, device->pnp.bus_id); strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); acpi_driver_data(device) = tz; mutex_init(&tz->lock); result = acpi_thermal_get_info(tz); if (result) goto end; result = acpi_thermal_add_fs(device); if (result) goto end; init_timer(&tz->timer); acpi_thermal_check(tz); status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, acpi_thermal_notify, tz); if (ACPI_FAILURE(status)) { result = -ENODEV; goto end; } printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device), acpi_device_bid(device), KELVIN_TO_CELSIUS(tz->temperature)); end: if (result) { acpi_thermal_remove_fs(device); kfree(tz); } return result;}static int acpi_thermal_remove(struct acpi_device *device, int type){ acpi_status status = AE_OK; struct acpi_thermal *tz = NULL; if (!device || !acpi_driver_data(device)) return -EINVAL; tz = acpi_driver_data(device); /* avoid timer adding new defer task */ tz->zombie = 1; /* wait for running timer (on other CPUs) finish */ del_timer_sync(&(tz->timer)); /* synchronize deferred task */ acpi_os_wait_events_complete(NULL); /* deferred task may reinsert timer */ del_timer_sync(&(tz->timer)); status = acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, acpi_thermal_notify); /* Terminate policy */ if (tz->trips.passive.flags.valid && tz->trips.passive.flags.enabled) { tz->trips.passive.flags.enabled = 0; acpi_thermal_passive(tz); } if (tz->trips.active[0].flags.valid && tz->trips.active[0].flags.enabled) { tz->trips.active[0].flags.enabled = 0; acpi_thermal_active(tz); } acpi_thermal_remove_fs(device); mutex_destroy(&tz->lock); kfree(tz); return 0;}static int acpi_thermal_resume(struct acpi_device *device){ struct acpi_thermal *tz = NULL; int i, j, power_state, result; if (!device || !acpi_driver_data(device)) return -EINVAL; tz = acpi_driver_data(device); for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { if (!(&tz->trips.active[i])) break; if (!tz->trips.active[i].flags.valid) break; tz->trips.active[i].flags.enabled = 1; for (j = 0; j < tz->trips.active[i].devices.count; j++) { result = acpi_bus_get_power(tz->trips.active[i].devices. handles[j], &power_state); if (result || (power_state != ACPI_STATE_D0)) { tz->trips.active[i].flags.enabled = 0; break; } } tz->state.active |= tz->trips.active[i].flags.enabled; } acpi_thermal_check(tz); return AE_OK;}#ifdef CONFIG_DMIstatic int thermal_act(const struct dmi_system_id *d) { if (act == 0) { printk(KERN_NOTICE "ACPI: %s detected: " "disabling all active thermal trip points\n", d->ident); act = -1; } return 0;}static int thermal_nocrt(const struct dmi_system_id *d) { printk(KERN_NOTICE "ACPI: %s detected: " "disabling all critical thermal trip point actions.\n", d->ident); nocrt = 1; return 0;}static int thermal_tzp(const struct dmi_system_id *d) { if (tzp == 0) { printk(KERN_NOTICE "ACPI: %s detected: " "enabling thermal zone polling\n", d->ident); tzp = 300; /* 300 dS = 30 Seconds */ } return 0;}static int thermal_psv(const struct dmi_system_id *d) { if (psv == 0) { printk(KERN_NOTICE "ACPI: %s detected: " "disabling all passive thermal trip points\n", d->ident); psv = -1; } return 0;}static struct dmi_system_id thermal_dmi_table[] __initdata = { /* * Award BIOS on this AOpen makes thermal control almost worthless. * http://bugzilla.kernel.org/show_bug.cgi?id=8842 */ { .callback = thermal_act, .ident = "AOpen i915GMm-HFS", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"), DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"), }, }, { .callback = thermal_psv, .ident = "AOpen i915GMm-HFS", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"), DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"), }, }, { .callback = thermal_tzp, .ident = "AOpen i915GMm-HFS", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"), DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"), }, }, { .callback = thermal_nocrt, .ident = "Gigabyte GA-7ZX", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), DMI_MATCH(DMI_BOARD_NAME, "7ZX"), }, }, {}};#endif /* CONFIG_DMI */static int __init acpi_thermal_init(void){ int result = 0; dmi_check_system(thermal_dmi_table); if (off) { printk(KERN_NOTICE "ACPI: thermal control disabled\n"); return -ENODEV; } acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir); if (!acpi_thermal_dir) return -ENODEV; acpi_thermal_dir->owner = THIS_MODULE; result = acpi_bus_register_driver(&acpi_thermal_driver); if (result < 0) { remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir); return -ENODEV; } return 0;}static void __exit acpi_thermal_exit(void){ acpi_bus_unregister_driver(&acpi_thermal_driver); remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir); return;}module_init(acpi_thermal_init);module_exit(acpi_thermal_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -