/** * acpi_parse_trt - Thermal Relationship Table _TRT for passive cooling * * @handle: ACPI handle of the device contains _TRT * @trt_count: the number of valid entries resulted from parsing _TRT * @trtp: pointer to pointer of array of _TRT entries in parsing result * @create_dev: whether to create platform devices for target and source *
*/ int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp, bool create_dev)
{
acpi_status status; int result = 0; int i; int nr_bad_entries = 0; struct trt *trts; union acpi_object *p; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer element = { 0, NULL }; struct acpi_buffer trt_format = { sizeof("RRNNNNNN"), "RRNNNNNN" };
status = acpi_evaluate_object(handle, "_TRT", NULL, &buffer); if (ACPI_FAILURE(status)) return -ENODEV;
p = buffer.pointer; if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
pr_err("Invalid _TRT data\n");
result = -EFAULT; goto end;
}
*trt_count = p->package.count;
trts = kcalloc(*trt_count, sizeof(struct trt), GFP_KERNEL); if (!trts) {
result = -ENOMEM; goto end;
}
for (i = 0; i < *trt_count; i++) { struct trt *trt = &trts[i - nr_bad_entries];
/** * acpi_parse_art - Parse Active Relationship Table _ART * * @handle: ACPI handle of the device contains _ART * @art_count: the number of valid entries resulted from parsing _ART * @artp: pointer to pointer of array of art entries in parsing result * @create_dev: whether to create platform devices for target and source *
*/ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp, bool create_dev)
{
acpi_status status; int result = 0; int i; int nr_bad_entries = 0; struct art *arts; union acpi_object *p; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer element = { 0, NULL }; struct acpi_buffer art_format = { sizeof("RRNNNNNNNNNNN"), "RRNNNNNNNNNNN" };
status = acpi_evaluate_object(handle, "_ART", NULL, &buffer); if (ACPI_FAILURE(status)) return -ENODEV;
p = buffer.pointer; if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
pr_err("Invalid _ART data\n");
result = -EFAULT; goto end;
}
/* ignore p->package.elements[0], as this is _ART Revision field */
*art_count = p->package.count - 1;
arts = kcalloc(*art_count, sizeof(struct art), GFP_KERNEL); if (!arts) {
result = -ENOMEM; goto end;
}
for (i = 0; i < *art_count; i++) { struct art *art = &arts[i - nr_bad_entries];
/* * acpi_parse_psvt - Passive Table (PSVT) for passive cooling * * @handle: ACPI handle of the device which contains PSVT * @psvt_count: the number of valid entries resulted from parsing PSVT * @psvtp: pointer to array of psvt entries *
*/ staticint acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **psvtp)
{ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; int nr_bad_entries = 0, revision = 0; union acpi_object *p;
acpi_status status; int i, result = 0; struct psvt *psvts;
if (!acpi_has_method(handle, "PSVT")) return -ENODEV;
status = acpi_evaluate_object(handle, "PSVT", NULL, &buffer); if (ACPI_FAILURE(status)) return -ENODEV;
p = buffer.pointer; if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
result = -EFAULT; goto end;
}
/* first package is the revision number */ if (p->package.count > 0) { union acpi_object *prev = &(p->package.elements[0]);
if (prev->type == ACPI_TYPE_INTEGER)
revision = (int)prev->integer.value;
} else {
result = -EFAULT; goto end;
}
/* Support only version 2 */ if (revision != 2) {
result = -EFAULT; goto end;
}
*psvt_count = p->package.count - 1; if (!*psvt_count) {
result = -EFAULT; goto end;
}
psvts = kcalloc(*psvt_count, sizeof(*psvts), GFP_KERNEL); if (!psvts) {
result = -ENOMEM; goto end;
}
/* Start index is 1 because the first package is the revision number */ for (i = 1; i < p->package.count; i++) { struct acpi_buffer psvt_int_format = { sizeof("RRNNNNNNNNNN"), "RRNNNNNNNNNN" }; struct acpi_buffer psvt_str_format = { sizeof("RRNNNNNSNNNN"), "RRNNNNNSNNNN" }; union acpi_object *package = &(p->package.elements[i]); struct psvt *psvt = &psvts[i - 1 - nr_bad_entries]; struct acpi_buffer *psvt_format = &psvt_int_format; struct acpi_buffer element = { 0, NULL }; union acpi_object *knob; struct acpi_device *res; struct psvt *psvt_ptr;
res = acpi_fetch_acpi_dev(psvt->source); if (!res) {
nr_bad_entries++;
pr_info("Failed to get source ACPI device\n"); continue;
}
res = acpi_fetch_acpi_dev(psvt->target); if (!res) {
nr_bad_entries++;
pr_info("Failed to get target ACPI device\n"); continue;
}
}
/* don't count bad entries */
*psvt_count -= nr_bad_entries;
if (!*psvt_count) {
result = -EFAULT;
kfree(psvts); goto end;
}
*psvtp = psvts;
return 0;
end:
kfree(buffer.pointer); return result;
}
/* get device name from acpi handle */ staticvoid get_single_name(acpi_handle handle, char *name)
{ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER};
if (ACPI_FAILURE(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)))
pr_warn("Failed to get device name from acpi handle\n"); else {
memcpy(name, buffer.pointer, ACPI_NAMESEG_SIZE);
kfree(buffer.pointer);
}
}
staticint fill_art(char __user *ubuf)
{ int i; int ret; int count; int art_len; struct art *arts = NULL; union art_object *art_user;
ret = acpi_parse_art(acpi_thermal_rel_handle, &count, &arts, false); if (ret) goto free_art;
art_len = count * sizeof(union art_object);
art_user = kzalloc(art_len, GFP_KERNEL); if (!art_user) {
ret = -ENOMEM; goto free_art;
} /* now fill in user art data */ for (i = 0; i < count; i++) { /* userspace art needs device name instead of acpi reference */
get_single_name(arts[i].source, art_user[i].source_device);
get_single_name(arts[i].target, art_user[i].target_device); /* copy the rest int data in addition to source and target */
BUILD_BUG_ON(sizeof(art_user[i].data) != sizeof(u64) * (ACPI_NR_ART_ELEMENTS - 2));
memcpy(&art_user[i].data, &arts[i].data, sizeof(art_user[i].data));
}
if (copy_to_user(ubuf, art_user, art_len))
ret = -EFAULT;
kfree(art_user);
free_art:
kfree(arts); return ret;
}
staticint fill_trt(char __user *ubuf)
{ int i; int ret; int count; int trt_len; struct trt *trts = NULL; union trt_object *trt_user;
ret = acpi_parse_trt(acpi_thermal_rel_handle, &count, &trts, false); if (ret) goto free_trt;
trt_len = count * sizeof(union trt_object);
trt_user = kzalloc(trt_len, GFP_KERNEL); if (!trt_user) {
ret = -ENOMEM; goto free_trt;
} /* now fill in user trt data */ for (i = 0; i < count; i++) { /* userspace trt needs device name instead of acpi reference */
get_single_name(trts[i].source, trt_user[i].source_device);
get_single_name(trts[i].target, trt_user[i].target_device);
trt_user[i].sample_period = trts[i].sample_period;
trt_user[i].influence = trts[i].influence;
}
if (copy_to_user(ubuf, trt_user, trt_len))
ret = -EFAULT;
kfree(trt_user);
free_trt:
kfree(trts); return ret;
}
staticint fill_psvt(char __user *ubuf)
{ int i, ret, count, psvt_len; union psvt_object *psvt_user; struct psvt *psvts;
ret = acpi_parse_psvt(acpi_thermal_rel_handle, &count, &psvts); if (ret) return ret;
psvt_len = count * sizeof(*psvt_user);
psvt_user = kzalloc(psvt_len, GFP_KERNEL); if (!psvt_user) {
ret = -ENOMEM; goto free_psvt;
}
/* now fill in user psvt data */ for (i = 0; i < count; i++) { /* userspace psvt needs device name instead of acpi reference */
get_single_name(psvts[i].source, psvt_user[i].source_device);
get_single_name(psvts[i].target, psvt_user[i].target_device);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.