staticint power_supply_match_string(constchar * const *array, size_t n, constchar *s)
{ int ret;
/* First try an exact match */
ret = __sysfs_match_string(array, n, s); if (ret >= 0) return ret;
/* Second round, try matching with spaces replaced by '_' */ for (size_t i = 0; i < n; i++) { char buf[32];
power_supply_escape_spaces(array[i], buf, sizeof(buf)); if (sysfs_streq(buf, s)) return i;
}
return -EINVAL;
}
static ssize_t power_supply_show_enum_with_available( struct device *dev, constchar * const labels[], int label_count, unsignedint available_values, int value, char *buf)
{ bool match = false, available, active; char escaped_label[32];
ssize_t count = 0; int i;
for (i = 0; i < label_count; i++) {
available = available_values & BIT(i);
active = i == value;
power_supply_escape_spaces(labels[i], escaped_label, sizeof(escaped_label));
if (psp == POWER_SUPPLY_PROP_TYPE) {
value.intval = psy->desc->type;
} else {
ret = power_supply_get_property(psy, psp, &value);
if (ret < 0) { if (ret == -ENODATA)
dev_dbg_ratelimited(dev, "driver has no data for `%s' property\n",
attr->attr.name); elseif (ret != -ENODEV && ret != -EAGAIN && ret != -EINVAL)
dev_err_ratelimited(dev, "driver failed to report `%s' property: %zd\n",
attr->attr.name, ret); return ret;
}
}
switch (psp) { case POWER_SUPPLY_PROP_USB_TYPE:
ret = power_supply_show_enum_with_available(
dev, POWER_SUPPLY_USB_TYPE_TEXT,
ARRAY_SIZE(POWER_SUPPLY_USB_TYPE_TEXT),
psy->desc->usb_types, value.intval, buf); break; case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: if (uevent) /* no possible values in uevents */ goto default_format;
ret = power_supply_show_charge_behaviour(dev, psy, &value, buf); break; case POWER_SUPPLY_PROP_CHARGE_TYPES: if (uevent) /* no possible values in uevents */ goto default_format;
ret = power_supply_show_charge_types(dev, psy,
value.intval, buf); break; case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER:
ret = sysfs_emit(buf, "%s\n", value.strval); break; default:
default_format: if (ps_attr->text_values_len > 0 &&
value.intval < ps_attr->text_values_len && value.intval >= 0) {
ret = sysfs_emit(buf, "%s\n", ps_attr->text_values[value.intval]);
} else {
ret = sysfs_emit(buf, "%d\n", value.intval);
}
}
ret = -EINVAL; if (ps_attr->text_values_len > 0) {
ret = power_supply_match_string(ps_attr->text_values,
ps_attr->text_values_len, buf);
}
/* * If no match was found, then check to see if it is an integer. * Integer values are valid for enums in addition to the text value.
*/ if (ret < 0) { long long_val;
ret = kstrtol(buf, 10, &long_val); if (ret < 0) return ret;
ret = long_val;
}
value.intval = ret;
ret = power_supply_set_property(psy, psp, &value); if (ret < 0) return ret;
void __init power_supply_init_attrs(void)
{ int i;
for (i = 0; i < ARRAY_SIZE(power_supply_attrs); i++) { struct device_attribute *attr;
if (!power_supply_attrs[i].prop_name) {
pr_warn("%s: Property %d skipped because it is missing from power_supply_attrs\n",
__func__, i);
sprintf(power_supply_attrs[i].attr_name, "_err_%d", i);
} else {
string_lower(power_supply_attrs[i].attr_name,
power_supply_attrs[i].attr_name);
}
ret = power_supply_format_property((struct device *)dev, true, dev_attr, prop_buf); if (ret == -ENODEV || ret == -ENODATA || ret == -EINVAL) { /* * When a battery is absent, we expect -ENODEV. Don't abort; * send the uevent with at least the PRESENT=0 property
*/ return 0;
}
if (ret < 0) return ret;
line = strchr(prop_buf, '\n'); if (line)
*line = 0;
int power_supply_uevent(conststruct device *dev, struct kobj_uevent_env *env)
{ conststruct power_supply *psy = dev_to_psy(dev); int ret = 0, j; char *prop_buf;
if (!psy || !psy->desc) {
dev_dbg(dev, "No power supply yet\n"); return ret;
}
ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->desc->name); if (ret) return ret;
/* * Kernel generates KOBJ_REMOVE uevent in device removal path, after * resources have been freed. Exit early to avoid use-after-free.
*/ if (psy->removing) return 0;
prop_buf = (char *)get_zeroed_page(GFP_KERNEL); if (!prop_buf) return -ENOMEM;
ret = add_prop_uevent(dev, env, POWER_SUPPLY_PROP_TYPE, prop_buf); if (ret) goto out;
for (j = 0; j < POWER_SUPPLY_ATTR_CNT; j++) {
ret = add_prop_uevent(dev, env, j, prop_buf); if (ret) goto out;
}
int power_supply_charge_behaviour_parse(unsignedint available_behaviours, constchar*buf)
{ int i = sysfs_match_string(POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT, buf);
int power_supply_charge_types_parse(unsignedint available_types, constchar *buf)
{ int i = power_supply_match_string(POWER_SUPPLY_CHARGE_TYPE_TEXT,
ARRAY_SIZE(POWER_SUPPLY_CHARGE_TYPE_TEXT),
buf);
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.