···19192020#include "internal.h"21212222+static int acpi_data_get_property_array(struct acpi_device_data *data,2323+ const char *name,2424+ acpi_object_type type,2525+ const union acpi_object **obj);2626+2227/* ACPI _DSD device properties UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */2328static const u8 prp_uuid[16] = {2429 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,2530 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x012631};3232+/* ACPI _DSD data subnodes UUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */3333+static const u8 ads_uuid[16] = {3434+ 0xe6, 0xe3, 0xb8, 0xdb, 0x86, 0x58, 0xa6, 0x4b,3535+ 0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b3636+};3737+3838+static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,3939+ const union acpi_object *desc,4040+ struct acpi_device_data *data);4141+static bool acpi_extract_properties(const union acpi_object *desc,4242+ struct acpi_device_data *data);4343+4444+static bool acpi_nondev_subnode_ok(acpi_handle scope,4545+ const union acpi_object *link,4646+ struct list_head *list)4747+{4848+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };4949+ struct acpi_data_node *dn;5050+ acpi_handle handle;5151+ acpi_status status;5252+5353+ dn = kzalloc(sizeof(*dn), GFP_KERNEL);5454+ if (!dn)5555+ return false;5656+5757+ dn->name = link->package.elements[0].string.pointer;5858+ dn->fwnode.type = FWNODE_ACPI_DATA;5959+ INIT_LIST_HEAD(&dn->data.subnodes);6060+6161+ status = acpi_get_handle(scope, link->package.elements[1].string.pointer,6262+ &handle);6363+ if (ACPI_FAILURE(status))6464+ goto fail;6565+6666+ status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,6767+ ACPI_TYPE_PACKAGE);6868+ if (ACPI_FAILURE(status))6969+ goto fail;7070+7171+ if (acpi_extract_properties(buf.pointer, &dn->data))7272+ dn->handle = handle;7373+7474+ /*7575+ * The scope for the subnode object lookup is the one of the namespace7676+ * node (device) containing the object that has returned the package.7777+ * That is, it's the scope of that object's parent.7878+ */7979+ status = acpi_get_parent(handle, &scope);8080+ if (ACPI_SUCCESS(status)8181+ && acpi_enumerate_nondev_subnodes(scope, buf.pointer, &dn->data))8282+ dn->handle = handle;8383+8484+ if (dn->handle) {8585+ dn->data.pointer = buf.pointer;8686+ list_add_tail(&dn->sibling, list);8787+ return true;8888+ }8989+9090+ acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");9191+9292+ fail:9393+ ACPI_FREE(buf.pointer);9494+ kfree(dn);9595+ return false;9696+}9797+9898+static int acpi_add_nondev_subnodes(acpi_handle scope,9999+ const union acpi_object *links,100100+ struct list_head *list)101101+{102102+ bool ret = false;103103+ int i;104104+105105+ for (i = 0; i < links->package.count; i++) {106106+ const union acpi_object *link;107107+108108+ link = &links->package.elements[i];109109+ /* Only two elements allowed, both must be strings. */110110+ if (link->package.count == 2111111+ && link->package.elements[0].type == ACPI_TYPE_STRING112112+ && link->package.elements[1].type == ACPI_TYPE_STRING113113+ && acpi_nondev_subnode_ok(scope, link, list))114114+ ret = true;115115+ }116116+117117+ return ret;118118+}119119+120120+static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,121121+ const union acpi_object *desc,122122+ struct acpi_device_data *data)123123+{124124+ int i;125125+126126+ /* Look for the ACPI data subnodes UUID. */127127+ for (i = 0; i < desc->package.count; i += 2) {128128+ const union acpi_object *uuid, *links;129129+130130+ uuid = &desc->package.elements[i];131131+ links = &desc->package.elements[i + 1];132132+133133+ /*134134+ * The first element must be a UUID and the second one must be135135+ * a package.136136+ */137137+ if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16138138+ || links->type != ACPI_TYPE_PACKAGE)139139+ break;140140+141141+ if (memcmp(uuid->buffer.pointer, ads_uuid, sizeof(ads_uuid)))142142+ continue;143143+144144+ return acpi_add_nondev_subnodes(scope, links, &data->subnodes);145145+ }146146+147147+ return false;148148+}2714928150static bool acpi_property_value_ok(const union acpi_object *value)29151{···20381 const union acpi_object *of_compatible;20482 int ret;20583206206- ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,207207- &of_compatible);8484+ ret = acpi_data_get_property_array(&adev->data, "compatible",8585+ ACPI_TYPE_STRING, &of_compatible);20886 if (ret) {20987 ret = acpi_dev_get_property(adev, "compatible",21088 ACPI_TYPE_STRING, &of_compatible);···222100 adev->flags.of_compatible_ok = 1;223101}224102225225-void acpi_init_properties(struct acpi_device *adev)103103+static bool acpi_extract_properties(const union acpi_object *desc,104104+ struct acpi_device_data *data)226105{227227- struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };228228- bool acpi_of = false;229229- struct acpi_hardware_id *hwid;230230- const union acpi_object *desc;231231- acpi_status status;232106 int i;233107234234- /*235235- * Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in236236- * Device Tree compatible properties for this device.237237- */238238- list_for_each_entry(hwid, &adev->pnp.ids, list) {239239- if (!strcmp(hwid->id, ACPI_DT_NAMESPACE_HID)) {240240- acpi_of = true;241241- break;242242- }243243- }244244-245245- status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,246246- ACPI_TYPE_PACKAGE);247247- if (ACPI_FAILURE(status))248248- goto out;249249-250250- desc = buf.pointer;251108 if (desc->package.count % 2)252252- goto fail;109109+ return false;253110254111 /* Look for the device properties UUID. */255112 for (i = 0; i < desc->package.count; i += 2) {···255154 if (!acpi_properties_format_valid(properties))256155 break;257156258258- adev->data.pointer = buf.pointer;259259- adev->data.properties = properties;260260-261261- if (acpi_of)262262- acpi_init_of_compatible(adev);263263-264264- goto out;157157+ data->properties = properties;158158+ return true;265159 }266160267267- fail:268268- dev_dbg(&adev->dev, "Returned _DSD data is not valid, skipping\n");269269- ACPI_FREE(buf.pointer);161161+ return false;162162+}163163+164164+void acpi_init_properties(struct acpi_device *adev)165165+{166166+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };167167+ struct acpi_hardware_id *hwid;168168+ acpi_status status;169169+ bool acpi_of = false;170170+171171+ INIT_LIST_HEAD(&adev->data.subnodes);172172+173173+ /*174174+ * Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in175175+ * Device Tree compatible properties for this device.176176+ */177177+ list_for_each_entry(hwid, &adev->pnp.ids, list) {178178+ if (!strcmp(hwid->id, ACPI_DT_NAMESPACE_HID)) {179179+ acpi_of = true;180180+ break;181181+ }182182+ }183183+184184+ status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,185185+ ACPI_TYPE_PACKAGE);186186+ if (ACPI_FAILURE(status))187187+ goto out;188188+189189+ if (acpi_extract_properties(buf.pointer, &adev->data)) {190190+ adev->data.pointer = buf.pointer;191191+ if (acpi_of)192192+ acpi_init_of_compatible(adev);193193+ }194194+ if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer, &adev->data))195195+ adev->data.pointer = buf.pointer;196196+197197+ if (!adev->data.pointer) {198198+ acpi_handle_debug(adev->handle, "Invalid _DSD data, skipping\n");199199+ ACPI_FREE(buf.pointer);200200+ }270201271202 out:272203 if (acpi_of && !adev->flags.of_compatible_ok)···306173 ACPI_DT_NAMESPACE_HID " requires 'compatible' property\n");307174}308175176176+static void acpi_destroy_nondev_subnodes(struct list_head *list)177177+{178178+ struct acpi_data_node *dn, *next;179179+180180+ if (list_empty(list))181181+ return;182182+183183+ list_for_each_entry_safe_reverse(dn, next, list, sibling) {184184+ acpi_destroy_nondev_subnodes(&dn->data.subnodes);185185+ wait_for_completion(&dn->kobj_done);186186+ list_del(&dn->sibling);187187+ ACPI_FREE((void *)dn->data.pointer);188188+ kfree(dn);189189+ }190190+}191191+309192void acpi_free_properties(struct acpi_device *adev)310193{194194+ acpi_destroy_nondev_subnodes(&adev->data.subnodes);311195 ACPI_FREE((void *)adev->data.pointer);312196 adev->data.of_compatible = NULL;313197 adev->data.pointer = NULL;···332182}333183334184/**335335- * acpi_dev_get_property - return an ACPI property with given name336336- * @adev: ACPI device to get property185185+ * acpi_data_get_property - return an ACPI property with given name186186+ * @data: ACPI device deta object to get the property from337187 * @name: Name of the property338188 * @type: Expected property type339189 * @obj: Location to store the property value (if not %NULL)···342192 * object at the location pointed to by @obj if found.343193 *344194 * Callers must not attempt to free the returned objects. These objects will be345345- * freed by the ACPI core automatically during the removal of @adev.195195+ * freed by the ACPI core automatically during the removal of @data.346196 *347197 * Return: %0 if property with @name has been found (success),348198 * %-EINVAL if the arguments are invalid,349199 * %-ENODATA if the property doesn't exist,350200 * %-EPROTO if the property value type doesn't match @type.351201 */352352-int acpi_dev_get_property(struct acpi_device *adev, const char *name,353353- acpi_object_type type, const union acpi_object **obj)202202+static int acpi_data_get_property(struct acpi_device_data *data,203203+ const char *name, acpi_object_type type,204204+ const union acpi_object **obj)354205{355206 const union acpi_object *properties;356207 int i;357208358358- if (!adev || !name)209209+ if (!data || !name)359210 return -EINVAL;360211361361- if (!adev->data.pointer || !adev->data.properties)212212+ if (!data->pointer || !data->properties)362213 return -ENODATA;363214364364- properties = adev->data.properties;215215+ properties = data->properties;365216 for (i = 0; i < properties->package.count; i++) {366217 const union acpi_object *propname, *propvalue;367218 const union acpi_object *property;···383232 }384233 return -ENODATA;385234}386386-EXPORT_SYMBOL_GPL(acpi_dev_get_property);387235388236/**389389- * acpi_dev_get_property_array - return an ACPI array property with given name390390- * @adev: ACPI device to get property237237+ * acpi_dev_get_property - return an ACPI property with given name.238238+ * @adev: ACPI device to get the property from.239239+ * @name: Name of the property.240240+ * @type: Expected property type.241241+ * @obj: Location to store the property value (if not %NULL).242242+ */243243+int acpi_dev_get_property(struct acpi_device *adev, const char *name,244244+ acpi_object_type type, const union acpi_object **obj)245245+{246246+ return adev ? acpi_data_get_property(&adev->data, name, type, obj) : -EINVAL;247247+}248248+EXPORT_SYMBOL_GPL(acpi_dev_get_property);249249+250250+static struct acpi_device_data *acpi_device_data_of_node(struct fwnode_handle *fwnode)251251+{252252+ if (fwnode->type == FWNODE_ACPI) {253253+ struct acpi_device *adev = to_acpi_device_node(fwnode);254254+ return &adev->data;255255+ } else if (fwnode->type == FWNODE_ACPI_DATA) {256256+ struct acpi_data_node *dn = to_acpi_data_node(fwnode);257257+ return &dn->data;258258+ }259259+ return NULL;260260+}261261+262262+/**263263+ * acpi_node_prop_get - return an ACPI property with given name.264264+ * @fwnode: Firmware node to get the property from.265265+ * @propname: Name of the property.266266+ * @valptr: Location to store a pointer to the property value (if not %NULL).267267+ */268268+int acpi_node_prop_get(struct fwnode_handle *fwnode, const char *propname,269269+ void **valptr)270270+{271271+ return acpi_data_get_property(acpi_device_data_of_node(fwnode),272272+ propname, ACPI_TYPE_ANY,273273+ (const union acpi_object **)valptr);274274+}275275+276276+/**277277+ * acpi_data_get_property_array - return an ACPI array property with given name278278+ * @adev: ACPI data object to get the property from391279 * @name: Name of the property392280 * @type: Expected type of array elements393281 * @obj: Location to store a pointer to the property value (if not NULL)···435245 * ACPI object at the location pointed to by @obj if found.436246 *437247 * Callers must not attempt to free the returned objects. Those objects will be438438- * freed by the ACPI core automatically during the removal of @adev.248248+ * freed by the ACPI core automatically during the removal of @data.439249 *440250 * Return: %0 if array property (package) with @name has been found (success),441251 * %-EINVAL if the arguments are invalid,···443253 * %-EPROTO if the property is not a package or the type of its elements444254 * doesn't match @type.445255 */446446-int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,447447- acpi_object_type type,448448- const union acpi_object **obj)256256+static int acpi_data_get_property_array(struct acpi_device_data *data,257257+ const char *name,258258+ acpi_object_type type,259259+ const union acpi_object **obj)449260{450261 const union acpi_object *prop;451262 int ret, i;452263453453- ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &prop);264264+ ret = acpi_data_get_property(data, name, ACPI_TYPE_PACKAGE, &prop);454265 if (ret)455266 return ret;456267···466275467276 return 0;468277}469469-EXPORT_SYMBOL_GPL(acpi_dev_get_property_array);470278471279/**472472- * acpi_dev_get_property_reference - returns handle to the referenced object473473- * @adev: ACPI device to get property474474- * @name: Name of the property280280+ * acpi_data_get_property_reference - returns handle to the referenced object281281+ * @data: ACPI device data object containing the property282282+ * @propname: Name of the property475283 * @index: Index of the reference to return476284 * @args: Location to store the returned reference with optional arguments477285 *···484294 *485295 * Return: %0 on success, negative error code on failure.486296 */487487-int acpi_dev_get_property_reference(struct acpi_device *adev,488488- const char *name, size_t index,489489- struct acpi_reference_args *args)297297+static int acpi_data_get_property_reference(struct acpi_device_data *data,298298+ const char *propname, size_t index,299299+ struct acpi_reference_args *args)490300{491301 const union acpi_object *element, *end;492302 const union acpi_object *obj;493303 struct acpi_device *device;494304 int ret, idx = 0;495305496496- ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);306306+ ret = acpi_data_get_property(data, propname, ACPI_TYPE_ANY, &obj);497307 if (ret)498308 return ret;499309···568378569379 return -EPROTO;570380}571571-EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);572381573573-int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,574574- void **valptr)382382+/**383383+ * acpi_node_get_property_reference - get a handle to the referenced object.384384+ * @fwnode: Firmware node to get the property from.385385+ * @propname: Name of the property.386386+ * @index: Index of the reference to return.387387+ * @args: Location to store the returned reference with optional arguments.388388+ */389389+int acpi_node_get_property_reference(struct fwnode_handle *fwnode,390390+ const char *name, size_t index,391391+ struct acpi_reference_args *args)575392{576576- return acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,577577- (const union acpi_object **)valptr);578578-}393393+ struct acpi_device_data *data = acpi_device_data_of_node(fwnode);579394580580-int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,581581- enum dev_prop_type proptype, void *val)395395+ return data ? acpi_data_get_property_reference(data, name, index, args) : -EINVAL;396396+}397397+EXPORT_SYMBOL_GPL(acpi_node_get_property_reference);398398+399399+static int acpi_data_prop_read_single(struct acpi_device_data *data,400400+ const char *propname,401401+ enum dev_prop_type proptype, void *val)582402{583403 const union acpi_object *obj;584404 int ret;···597397 return -EINVAL;598398599399 if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {600600- ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_INTEGER, &obj);400400+ ret = acpi_data_get_property(data, propname, ACPI_TYPE_INTEGER, &obj);601401 if (ret)602402 return ret;603403···622422 break;623423 }624424 } else if (proptype == DEV_PROP_STRING) {625625- ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_STRING, &obj);425425+ ret = acpi_data_get_property(data, propname, ACPI_TYPE_STRING, &obj);626426 if (ret)627427 return ret;628428···631431 ret = -EINVAL;632432 }633433 return ret;434434+}435435+436436+int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,437437+ enum dev_prop_type proptype, void *val)438438+{439439+ return adev ? acpi_data_prop_read_single(&adev->data, propname, proptype, val) : -EINVAL;634440}635441636442static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,···715509 return 0;716510}717511718718-int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,719719- enum dev_prop_type proptype, void *val, size_t nval)512512+static int acpi_data_prop_read(struct acpi_device_data *data,513513+ const char *propname,514514+ enum dev_prop_type proptype,515515+ void *val, size_t nval)720516{721517 const union acpi_object *obj;722518 const union acpi_object *items;723519 int ret;724520725521 if (val && nval == 1) {726726- ret = acpi_dev_prop_read_single(adev, propname, proptype, val);522522+ ret = acpi_data_prop_read_single(data, propname, proptype, val);727523 if (!ret)728524 return ret;729525 }730526731731- ret = acpi_dev_get_property_array(adev, propname, ACPI_TYPE_ANY, &obj);527527+ ret = acpi_data_get_property_array(data, propname, ACPI_TYPE_ANY, &obj);732528 if (ret)733529 return ret;734530···765557 break;766558 }767559 return ret;560560+}561561+562562+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,563563+ enum dev_prop_type proptype, void *val, size_t nval)564564+{565565+ return adev ? acpi_data_prop_read(&adev->data, propname, proptype, val, nval) : -EINVAL;566566+}567567+568568+/**569569+ * acpi_node_prop_read - retrieve the value of an ACPI property with given name.570570+ * @fwnode: Firmware node to get the property from.571571+ * @propname: Name of the property.572572+ * @proptype: Expected property type.573573+ * @val: Location to store the property value (if not %NULL).574574+ * @nval: Size of the array pointed to by @val.575575+ *576576+ * If @val is %NULL, return the number of array elements comprising the value577577+ * of the property. Otherwise, read at most @nval values to the array at the578578+ * location pointed to by @val.579579+ */580580+int acpi_node_prop_read(struct fwnode_handle *fwnode, const char *propname,581581+ enum dev_prop_type proptype, void *val, size_t nval)582582+{583583+ return acpi_data_prop_read(acpi_device_data_of_node(fwnode),584584+ propname, proptype, val, nval);585585+}586586+587587+/**588588+ * acpi_get_next_subnode - Return the next child node handle for a device.589589+ * @dev: Device to find the next child node for.590590+ * @child: Handle to one of the device's child nodes or a null handle.591591+ */592592+struct fwnode_handle *acpi_get_next_subnode(struct device *dev,593593+ struct fwnode_handle *child)594594+{595595+ struct acpi_device *adev = ACPI_COMPANION(dev);596596+ struct list_head *head, *next;597597+598598+ if (!adev)599599+ return NULL;600600+601601+ if (!child || child->type == FWNODE_ACPI) {602602+ head = &adev->children;603603+ if (list_empty(head))604604+ goto nondev;605605+606606+ if (child) {607607+ adev = to_acpi_device_node(child);608608+ next = adev->node.next;609609+ if (next == head) {610610+ child = NULL;611611+ goto nondev;612612+ }613613+ adev = list_entry(next, struct acpi_device, node);614614+ } else {615615+ adev = list_first_entry(head, struct acpi_device, node);616616+ }617617+ return acpi_fwnode_handle(adev);618618+ }619619+620620+ nondev:621621+ if (!child || child->type == FWNODE_ACPI_DATA) {622622+ struct acpi_data_node *dn;623623+624624+ head = &adev->data.subnodes;625625+ if (list_empty(head))626626+ return NULL;627627+628628+ if (child) {629629+ dn = to_acpi_data_node(child);630630+ next = dn->sibling.next;631631+ if (next == head)632632+ return NULL;633633+634634+ dn = list_entry(next, struct acpi_data_node, sibling);635635+ } else {636636+ dn = list_first_entry(head, struct acpi_data_node, sibling);637637+ }638638+ return &dn->fwnode;639639+ }640640+ return NULL;768641}
-20
drivers/acpi/scan.c
···695695 return result;696696}697697698698-struct acpi_device *acpi_get_next_child(struct device *dev,699699- struct acpi_device *child)700700-{701701- struct acpi_device *adev = ACPI_COMPANION(dev);702702- struct list_head *head, *next;703703-704704- if (!adev)705705- return NULL;706706-707707- head = &adev->children;708708- if (list_empty(head))709709- return NULL;710710-711711- if (!child)712712- return list_first_entry(head, struct acpi_device, node);713713-714714- next = child->node.next;715715- return next == head ? NULL : list_entry(next, struct acpi_device, node);716716-}717717-718698/* --------------------------------------------------------------------------719699 Device Enumeration720700 -------------------------------------------------------------------------- */
+76-12
drivers/base/property.c
···134134 if (is_of_node(fwnode))135135 return of_property_read_bool(to_of_node(fwnode), propname);136136 else if (is_acpi_node(fwnode))137137- return !acpi_dev_prop_get(to_acpi_node(fwnode), propname, NULL);137137+ return !acpi_node_prop_get(fwnode, propname, NULL);138138139139 return !!pset_prop_get(to_pset(fwnode), propname);140140}···287287}288288EXPORT_SYMBOL_GPL(device_property_read_string);289289290290+/**291291+ * device_property_match_string - find a string in an array and return index292292+ * @dev: Device to get the property of293293+ * @propname: Name of the property holding the array294294+ * @string: String to look for295295+ *296296+ * Find a given string in a string array and if it is found return the297297+ * index back.298298+ *299299+ * Return: %0 if the property was found (success),300300+ * %-EINVAL if given arguments are not valid,301301+ * %-ENODATA if the property does not have a value,302302+ * %-EPROTO if the property is not an array of strings,303303+ * %-ENXIO if no suitable firmware interface is present.304304+ */305305+int device_property_match_string(struct device *dev, const char *propname,306306+ const char *string)307307+{308308+ return fwnode_property_match_string(dev_fwnode(dev), propname, string);309309+}310310+EXPORT_SYMBOL_GPL(device_property_match_string);311311+290312#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \291313 (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \292314 : of_property_count_elems_of_size((node), (propname), sizeof(type))···320298 _ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_, \321299 _type_, _val_, _nval_); \322300 else if (is_acpi_node(_fwnode_)) \323323- _ret_ = acpi_dev_prop_read(to_acpi_node(_fwnode_), _propname_, \324324- _proptype_, _val_, _nval_); \301301+ _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \302302+ _val_, _nval_); \325303 else if (is_pset(_fwnode_)) \326304 _ret_ = pset_prop_read_array(to_pset(_fwnode_), _propname_, \327305 _proptype_, _val_, _nval_); \···462440 propname, val, nval) :463441 of_property_count_strings(to_of_node(fwnode), propname);464442 else if (is_acpi_node(fwnode))465465- return acpi_dev_prop_read(to_acpi_node(fwnode), propname,466466- DEV_PROP_STRING, val, nval);443443+ return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,444444+ val, nval);467445 else if (is_pset(fwnode))468446 return pset_prop_read_array(to_pset(fwnode), propname,469447 DEV_PROP_STRING, val, nval);···492470 if (is_of_node(fwnode))493471 return of_property_read_string(to_of_node(fwnode), propname, val);494472 else if (is_acpi_node(fwnode))495495- return acpi_dev_prop_read(to_acpi_node(fwnode), propname,496496- DEV_PROP_STRING, val, 1);473473+ return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,474474+ val, 1);497475498476 return pset_prop_read_array(to_pset(fwnode), propname,499477 DEV_PROP_STRING, val, 1);500478}501479EXPORT_SYMBOL_GPL(fwnode_property_read_string);480480+481481+/**482482+ * fwnode_property_match_string - find a string in an array and return index483483+ * @fwnode: Firmware node to get the property of484484+ * @propname: Name of the property holding the array485485+ * @string: String to look for486486+ *487487+ * Find a given string in a string array and if it is found return the488488+ * index back.489489+ *490490+ * Return: %0 if the property was found (success),491491+ * %-EINVAL if given arguments are not valid,492492+ * %-ENODATA if the property does not have a value,493493+ * %-EPROTO if the property is not an array of strings,494494+ * %-ENXIO if no suitable firmware interface is present.495495+ */496496+int fwnode_property_match_string(struct fwnode_handle *fwnode,497497+ const char *propname, const char *string)498498+{499499+ const char **values;500500+ int nval, ret, i;501501+502502+ nval = fwnode_property_read_string_array(fwnode, propname, NULL, 0);503503+ if (nval < 0)504504+ return nval;505505+506506+ values = kcalloc(nval, sizeof(*values), GFP_KERNEL);507507+ if (!values)508508+ return -ENOMEM;509509+510510+ ret = fwnode_property_read_string_array(fwnode, propname, values, nval);511511+ if (ret < 0)512512+ goto out;513513+514514+ ret = -ENODATA;515515+ for (i = 0; i < nval; i++) {516516+ if (!strcmp(values[i], string)) {517517+ ret = i;518518+ break;519519+ }520520+ }521521+out:522522+ kfree(values);523523+ return ret;524524+}525525+EXPORT_SYMBOL_GPL(fwnode_property_match_string);502526503527/**504528 * device_get_next_child_node - Return the next child node handle for a device···561493 if (node)562494 return &node->fwnode;563495 } else if (IS_ENABLED(CONFIG_ACPI)) {564564- struct acpi_device *node;565565-566566- node = acpi_get_next_child(dev, to_acpi_node(child));567567- if (node)568568- return acpi_fwnode_handle(node);496496+ return acpi_get_next_subnode(dev, child);569497 }570498 return NULL;571499}
+16-7
drivers/dma/acpi-dma.c
···2121#include <linux/ioport.h>2222#include <linux/acpi.h>2323#include <linux/acpi_dma.h>2424+#include <linux/property.h>24252526static LIST_HEAD(acpi_dma_list);2627static DEFINE_MUTEX(acpi_dma_lock);···414413 * translate the names "tx" and "rx" here based on the most common case where415414 * the first FixedDMA descriptor is TX and second is RX.416415 *416416+ * If the device has "dma-names" property the FixedDMA descriptor indices417417+ * are retrieved based on those. Otherwise the function falls back using418418+ * hardcoded indices.419419+ *417420 * Return:418421 * Pointer to appropriate dma channel on success or an error pointer.419422 */420423struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev,421424 const char *name)422425{423423- size_t index;426426+ int index;424427425425- if (!strcmp(name, "tx"))426426- index = 0;427427- else if (!strcmp(name, "rx"))428428- index = 1;429429- else430430- return ERR_PTR(-ENODEV);428428+ index = device_property_match_string(dev, "dma-names", name);429429+ if (index < 0) {430430+ if (!strcmp(name, "tx"))431431+ index = 0;432432+ else if (!strcmp(name, "rx"))433433+ index = 1;434434+ else435435+ return ERR_PTR(-ENODEV);436436+ }431437438438+ dev_dbg(dev, "found DMA channel \"%s\" at index %d\n", name, index);432439 return acpi_dma_request_slave_chan_by_index(dev, index);433440}434441EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_name);
+110-45
drivers/gpio/gpiolib-acpi.c
···389389 struct acpi_gpio_info info;390390 int index;391391 int pin_index;392392+ bool active_low;393393+ struct acpi_device *adev;392394 struct gpio_desc *desc;393395 int n;394396};···427425 return 1;428426}429427428428+static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup,429429+ struct acpi_gpio_info *info)430430+{431431+ struct list_head res_list;432432+ int ret;433433+434434+ INIT_LIST_HEAD(&res_list);435435+436436+ ret = acpi_dev_get_resources(lookup->adev, &res_list, acpi_find_gpio,437437+ lookup);438438+ if (ret < 0)439439+ return ret;440440+441441+ acpi_dev_free_resource_list(&res_list);442442+443443+ if (!lookup->desc)444444+ return -ENOENT;445445+446446+ if (info) {447447+ *info = lookup->info;448448+ if (lookup->active_low)449449+ info->active_low = lookup->active_low;450450+ }451451+ return 0;452452+}453453+454454+static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,455455+ const char *propname, int index,456456+ struct acpi_gpio_lookup *lookup)457457+{458458+ struct acpi_reference_args args;459459+ int ret;460460+461461+ memset(&args, 0, sizeof(args));462462+ ret = acpi_node_get_property_reference(fwnode, propname, index, &args);463463+ if (ret) {464464+ struct acpi_device *adev = to_acpi_device_node(fwnode);465465+466466+ if (!adev)467467+ return ret;468468+469469+ if (!acpi_get_driver_gpio_data(adev, propname, index, &args))470470+ return ret;471471+ }472472+ /*473473+ * The property was found and resolved, so need to lookup the GPIO based474474+ * on returned args.475475+ */476476+ lookup->adev = args.adev;477477+ if (args.nargs >= 2) {478478+ lookup->index = args.args[0];479479+ lookup->pin_index = args.args[1];480480+ /* 3rd argument, if present is used to specify active_low. */481481+ if (args.nargs >= 3)482482+ lookup->active_low = !!args.args[2];483483+ }484484+ return 0;485485+}486486+430487/**431488 * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources432489 * @adev: pointer to a ACPI device to get GPIO from···513452 struct acpi_gpio_info *info)514453{515454 struct acpi_gpio_lookup lookup;516516- struct list_head resource_list;517517- bool active_low = false;518455 int ret;519456520457 if (!adev)···522463 lookup.index = index;523464524465 if (propname) {525525- struct acpi_reference_args args;526526-527466 dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname);528467529529- memset(&args, 0, sizeof(args));530530- ret = acpi_dev_get_property_reference(adev, propname,531531- index, &args);532532- if (ret) {533533- bool found = acpi_get_driver_gpio_data(adev, propname,534534- index, &args);535535- if (!found)536536- return ERR_PTR(ret);537537- }468468+ ret = acpi_gpio_property_lookup(acpi_fwnode_handle(adev),469469+ propname, index, &lookup);470470+ if (ret)471471+ return ERR_PTR(ret);538472539539- /*540540- * The property was found and resolved so need to541541- * lookup the GPIO based on returned args instead.542542- */543543- adev = args.adev;544544- if (args.nargs >= 2) {545545- lookup.index = args.args[0];546546- lookup.pin_index = args.args[1];547547- /*548548- * 3rd argument, if present is used to549549- * specify active_low.550550- */551551- if (args.nargs >= 3)552552- active_low = !!args.args[2];553553- }554554-555555- dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n",556556- dev_name(&adev->dev), args.nargs,557557- args.args[0], args.args[1], args.args[2]);473473+ dev_dbg(&adev->dev, "GPIO: _DSD returned %s %d %d %u\n",474474+ dev_name(&lookup.adev->dev), lookup.index,475475+ lookup.pin_index, lookup.active_low);558476 } else {559477 dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index);478478+ lookup.adev = adev;560479 }561480562562- INIT_LIST_HEAD(&resource_list);563563- ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,564564- &lookup);565565- if (ret < 0)481481+ ret = acpi_gpio_resource_lookup(&lookup, info);482482+ return ret ? ERR_PTR(ret) : lookup.desc;483483+}484484+485485+/**486486+ * acpi_node_get_gpiod() - get a GPIO descriptor from ACPI resources487487+ * @fwnode: pointer to an ACPI firmware node to get the GPIO information from488488+ * @propname: Property name of the GPIO489489+ * @index: index of GpioIo/GpioInt resource (starting from %0)490490+ * @info: info pointer to fill in (optional)491491+ *492492+ * If @fwnode is an ACPI device object, call %acpi_get_gpiod_by_index() for it.493493+ * Otherwise (ie. it is a data-only non-device object), use the property-based494494+ * GPIO lookup to get to the GPIO resource with the relevant information and use495495+ * that to obtain the GPIO descriptor to return.496496+ */497497+struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,498498+ const char *propname, int index,499499+ struct acpi_gpio_info *info)500500+{501501+ struct acpi_gpio_lookup lookup;502502+ struct acpi_device *adev;503503+ int ret;504504+505505+ adev = to_acpi_device_node(fwnode);506506+ if (adev)507507+ return acpi_get_gpiod_by_index(adev, propname, index, info);508508+509509+ if (!is_acpi_data_node(fwnode))510510+ return ERR_PTR(-ENODEV);511511+512512+ if (!propname)513513+ return ERR_PTR(-EINVAL);514514+515515+ memset(&lookup, 0, sizeof(lookup));516516+ lookup.index = index;517517+518518+ ret = acpi_gpio_property_lookup(fwnode, propname, index, &lookup);519519+ if (ret)566520 return ERR_PTR(ret);567521568568- acpi_dev_free_resource_list(&resource_list);569569-570570- if (lookup.desc && info) {571571- *info = lookup.info;572572- if (active_low)573573- info->active_low = active_low;574574- }575575-576576- return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);522522+ ret = acpi_gpio_resource_lookup(&lookup, info);523523+ return ret ? ERR_PTR(ret) : lookup.desc;577524}578525579526/**