Blame view

drivers/acpi/property.c 37.1 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
ffdcd955c   Mika Westerberg   ACPI: Add support...
2
3
4
5
6
7
8
9
10
  /*
   * ACPI device specific properties support.
   *
   * Copyright (C) 2014, Intel Corporation
   * All rights reserved.
   *
   * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
   *          Darren Hart <dvhart@linux.intel.com>
   *          Rafael J. Wysocki <rafael.j.wysocki@intel.com>
ffdcd955c   Mika Westerberg   ACPI: Add support...
11
12
13
14
15
16
17
   */
  
  #include <linux/acpi.h>
  #include <linux/device.h>
  #include <linux/export.h>
  
  #include "internal.h"
99a854646   Sakari Ailus   ACPI: Constify in...
18
  static int acpi_data_get_property_array(const struct acpi_device_data *data,
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
19
20
21
  					const char *name,
  					acpi_object_type type,
  					const union acpi_object **obj);
617654aae   Mika Westerberg   PCI / ACPI: Ident...
22
23
24
25
26
27
28
29
  /*
   * The GUIDs here are made equivalent to each other in order to avoid extra
   * complexity in the properties handling code, with the caveat that the
   * kernel will accept certain combinations of GUID and properties that are
   * not defined without a warning. For instance if any of the properties
   * from different GUID appear in a property list of another, it will be
   * accepted by the kernel. Firmware validation tools should catch these.
   */
5f5e4890d   Mika Westerberg   ACPI / property: ...
30
31
  static const guid_t prp_guids[] = {
  	/* ACPI _DSD device properties GUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
3689d3d69   Andy Shevchenko   ACPI: device prop...
32
  	GUID_INIT(0xdaffd814, 0x6eba, 0x4d8c,
5f5e4890d   Mika Westerberg   ACPI / property: ...
33
  		  0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01),
26ad34d51   Mika Westerberg   PCI / ACPI: White...
34
35
36
  	/* Hotplug in D3 GUID: 6211e2c0-58a3-4af3-90e1-927a4e0c55a4 */
  	GUID_INIT(0x6211e2c0, 0x58a3, 0x4af3,
  		  0x90, 0xe1, 0x92, 0x7a, 0x4e, 0x0c, 0x55, 0xa4),
617654aae   Mika Westerberg   PCI / ACPI: Ident...
37
38
39
  	/* External facing port GUID: efcc06cc-73ac-4bc3-bff0-76143807c389 */
  	GUID_INIT(0xefcc06cc, 0x73ac, 0x4bc3,
  		  0xbf, 0xf0, 0x76, 0x14, 0x38, 0x07, 0xc3, 0x89),
dfda20419   Mika Westerberg   ACPI / property: ...
40
41
42
43
44
45
  	/* Thunderbolt GUID for IMR_VALID: c44d002f-69f9-4e7d-a904-a7baabdf43f7 */
  	GUID_INIT(0xc44d002f, 0x69f9, 0x4e7d,
  		  0xa9, 0x04, 0xa7, 0xba, 0xab, 0xdf, 0x43, 0xf7),
  	/* Thunderbolt GUID for WAKE_SUPPORTED: 6c501103-c189-4296-ba72-9bf5a26ebe5d */
  	GUID_INIT(0x6c501103, 0xc189, 0x4296,
  		  0xba, 0x72, 0x9b, 0xf5, 0xa2, 0x6e, 0xbe, 0x5d),
df4f9bc4f   David E. Box   nvme-pci: add sup...
46
47
48
  	/* Storage device needs D3 GUID: 5025030f-842f-4ab4-a561-99a5189762d0 */
  	GUID_INIT(0x5025030f, 0x842f, 0x4ab4,
  		  0xa5, 0x61, 0x99, 0xa5, 0x18, 0x97, 0x62, 0xd0),
5f5e4890d   Mika Westerberg   ACPI / property: ...
49
  };
5f21f3055   Shunyong Yang   ACPI: property: r...
50
  /* ACPI _DSD data subnodes GUID: dbb8e3e6-5886-4ba6-8795-1319f52a966b */
3689d3d69   Andy Shevchenko   ACPI: device prop...
51
52
53
  static const guid_t ads_guid =
  	GUID_INIT(0xdbb8e3e6, 0x5886, 0x4ba6,
  		  0x87, 0x95, 0x13, 0x19, 0xf5, 0x2a, 0x96, 0x6b);
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
54
55
56
  
  static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
  					   const union acpi_object *desc,
dfa672fbc   Mika Westerberg   ACPI / property: ...
57
58
  					   struct acpi_device_data *data,
  					   struct fwnode_handle *parent);
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
59
60
  static bool acpi_extract_properties(const union acpi_object *desc,
  				    struct acpi_device_data *data);
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
61
62
63
  static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
  					acpi_handle handle,
  					const union acpi_object *link,
dfa672fbc   Mika Westerberg   ACPI / property: ...
64
65
  					struct list_head *list,
  					struct fwnode_handle *parent)
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
66
  {
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
67
  	struct acpi_data_node *dn;
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
68
  	bool result;
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
69
70
71
72
73
74
  
  	dn = kzalloc(sizeof(*dn), GFP_KERNEL);
  	if (!dn)
  		return false;
  
  	dn->name = link->package.elements[0].string.pointer;
db3e50f32   Sakari Ailus   device property: ...
75
  	dn->fwnode.ops = &acpi_data_fwnode_ops;
dfa672fbc   Mika Westerberg   ACPI / property: ...
76
  	dn->parent = parent;
5f5e4890d   Mika Westerberg   ACPI / property: ...
77
  	INIT_LIST_HEAD(&dn->data.properties);
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
78
  	INIT_LIST_HEAD(&dn->data.subnodes);
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
79
  	result = acpi_extract_properties(desc, &dn->data);
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
80

99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
81
82
83
  	if (handle) {
  		acpi_handle scope;
  		acpi_status status;
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
84

99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
85
86
87
88
89
90
91
92
  		/*
  		 * The scope for the subnode object lookup is the one of the
  		 * namespace node (device) containing the object that has
  		 * returned the package.  That is, it's the scope of that
  		 * object's parent.
  		 */
  		status = acpi_get_parent(handle, &scope);
  		if (ACPI_SUCCESS(status)
dfa672fbc   Mika Westerberg   ACPI / property: ...
93
94
  		    && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data,
  						      &dn->fwnode))
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
95
  			result = true;
dfa672fbc   Mika Westerberg   ACPI / property: ...
96
97
  	} else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data,
  						  &dn->fwnode)) {
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
98
99
  		result = true;
  	}
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
100

99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
101
  	if (result) {
263b4c1a6   Rafael J. Wysocki   ACPI / property: ...
102
  		dn->handle = handle;
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
103
  		dn->data.pointer = desc;
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
104
105
106
  		list_add_tail(&dn->sibling, list);
  		return true;
  	}
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
107
  	kfree(dn);
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
108
109
  	acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping
  ");
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
110
111
112
113
114
  	return false;
  }
  
  static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
  					const union acpi_object *link,
dfa672fbc   Mika Westerberg   ACPI / property: ...
115
116
  					struct list_head *list,
  					struct fwnode_handle *parent)
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
117
118
119
120
121
122
123
124
  {
  	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
  	acpi_status status;
  
  	status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
  					    ACPI_TYPE_PACKAGE);
  	if (ACPI_FAILURE(status))
  		return false;
dfa672fbc   Mika Westerberg   ACPI / property: ...
125
126
  	if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list,
  					parent))
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
127
  		return true;
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
128

445b0eb05   Rafael J. Wysocki   ACPI / property: ...
129
  	ACPI_FREE(buf.pointer);
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
130
131
  	return false;
  }
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
132
133
  static bool acpi_nondev_subnode_ok(acpi_handle scope,
  				   const union acpi_object *link,
dfa672fbc   Mika Westerberg   ACPI / property: ...
134
135
  				   struct list_head *list,
  				   struct fwnode_handle *parent)
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
136
137
138
139
140
141
142
143
144
145
146
  {
  	acpi_handle handle;
  	acpi_status status;
  
  	if (!scope)
  		return false;
  
  	status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
  				 &handle);
  	if (ACPI_FAILURE(status))
  		return false;
dfa672fbc   Mika Westerberg   ACPI / property: ...
147
  	return acpi_nondev_subnode_data_ok(handle, link, list, parent);
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
148
  }
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
149
150
  static int acpi_add_nondev_subnodes(acpi_handle scope,
  				    const union acpi_object *links,
dfa672fbc   Mika Westerberg   ACPI / property: ...
151
152
  				    struct list_head *list,
  				    struct fwnode_handle *parent)
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
153
154
155
156
157
  {
  	bool ret = false;
  	int i;
  
  	for (i = 0; i < links->package.count; i++) {
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
158
159
160
  		const union acpi_object *link, *desc;
  		acpi_handle handle;
  		bool result;
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
161
162
  
  		link = &links->package.elements[i];
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
163
164
165
166
167
168
169
170
171
172
173
  		/* Only two elements allowed. */
  		if (link->package.count != 2)
  			continue;
  
  		/* The first one must be a string. */
  		if (link->package.elements[0].type != ACPI_TYPE_STRING)
  			continue;
  
  		/* The second one may be a string, a reference or a package. */
  		switch (link->package.elements[1].type) {
  		case ACPI_TYPE_STRING:
dfa672fbc   Mika Westerberg   ACPI / property: ...
174
175
  			result = acpi_nondev_subnode_ok(scope, link, list,
  							 parent);
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
176
177
178
  			break;
  		case ACPI_TYPE_LOCAL_REFERENCE:
  			handle = link->package.elements[1].reference.handle;
dfa672fbc   Mika Westerberg   ACPI / property: ...
179
180
  			result = acpi_nondev_subnode_data_ok(handle, link, list,
  							     parent);
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
181
182
183
  			break;
  		case ACPI_TYPE_PACKAGE:
  			desc = &link->package.elements[1];
dfa672fbc   Mika Westerberg   ACPI / property: ...
184
185
  			result = acpi_nondev_subnode_extract(desc, NULL, link,
  							     list, parent);
99db5ff7f   Rafael J. Wysocki   ACPI / property: ...
186
187
188
189
190
191
  			break;
  		default:
  			result = false;
  			break;
  		}
  		ret = ret || result;
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
192
193
194
195
196
197
198
  	}
  
  	return ret;
  }
  
  static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
  					   const union acpi_object *desc,
dfa672fbc   Mika Westerberg   ACPI / property: ...
199
200
  					   struct acpi_device_data *data,
  					   struct fwnode_handle *parent)
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
201
202
  {
  	int i;
3689d3d69   Andy Shevchenko   ACPI: device prop...
203
  	/* Look for the ACPI data subnodes GUID. */
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
204
  	for (i = 0; i < desc->package.count; i += 2) {
3689d3d69   Andy Shevchenko   ACPI: device prop...
205
  		const union acpi_object *guid, *links;
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
206

3689d3d69   Andy Shevchenko   ACPI: device prop...
207
  		guid = &desc->package.elements[i];
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
208
209
210
  		links = &desc->package.elements[i + 1];
  
  		/*
3689d3d69   Andy Shevchenko   ACPI: device prop...
211
  		 * The first element must be a GUID and the second one must be
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
212
213
  		 * a package.
  		 */
3689d3d69   Andy Shevchenko   ACPI: device prop...
214
215
216
  		if (guid->type != ACPI_TYPE_BUFFER ||
  		    guid->buffer.length != 16 ||
  		    links->type != ACPI_TYPE_PACKAGE)
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
217
  			break;
3689d3d69   Andy Shevchenko   ACPI: device prop...
218
  		if (!guid_equal((guid_t *)guid->buffer.pointer, &ads_guid))
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
219
  			continue;
dfa672fbc   Mika Westerberg   ACPI / property: ...
220
221
  		return acpi_add_nondev_subnodes(scope, links, &data->subnodes,
  						parent);
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
222
223
224
225
  	}
  
  	return false;
  }
ffdcd955c   Mika Westerberg   ACPI: Add support...
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  
  static bool acpi_property_value_ok(const union acpi_object *value)
  {
  	int j;
  
  	/*
  	 * The value must be an integer, a string, a reference, or a package
  	 * whose every element must be an integer, a string, or a reference.
  	 */
  	switch (value->type) {
  	case ACPI_TYPE_INTEGER:
  	case ACPI_TYPE_STRING:
  	case ACPI_TYPE_LOCAL_REFERENCE:
  		return true;
  
  	case ACPI_TYPE_PACKAGE:
  		for (j = 0; j < value->package.count; j++)
  			switch (value->package.elements[j].type) {
  			case ACPI_TYPE_INTEGER:
  			case ACPI_TYPE_STRING:
  			case ACPI_TYPE_LOCAL_REFERENCE:
  				continue;
  
  			default:
  				return false;
  			}
  
  		return true;
  	}
  	return false;
  }
  
  static bool acpi_properties_format_valid(const union acpi_object *properties)
  {
  	int i;
  
  	for (i = 0; i < properties->package.count; i++) {
  		const union acpi_object *property;
  
  		property = &properties->package.elements[i];
  		/*
  		 * Only two elements allowed, the first one must be a string and
  		 * the second one has to satisfy certain conditions.
  		 */
  		if (property->package.count != 2
  		    || property->package.elements[0].type != ACPI_TYPE_STRING
  		    || !acpi_property_value_ok(&property->package.elements[1]))
  			return false;
  	}
  	return true;
  }
733e62513   Mika Westerberg   ACPI: Allow drive...
277
278
279
  static void acpi_init_of_compatible(struct acpi_device *adev)
  {
  	const union acpi_object *of_compatible;
733e62513   Mika Westerberg   ACPI: Allow drive...
280
  	int ret;
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
281
282
  	ret = acpi_data_get_property_array(&adev->data, "compatible",
  					   ACPI_TYPE_STRING, &of_compatible);
733e62513   Mika Westerberg   ACPI: Allow drive...
283
284
285
286
  	if (ret) {
  		ret = acpi_dev_get_property(adev, "compatible",
  					    ACPI_TYPE_STRING, &of_compatible);
  		if (ret) {
5c53b262c   Rafael J. Wysocki   ACPI / property: ...
287
288
289
  			if (adev->parent
  			    && adev->parent->flags.of_compatible_ok)
  				goto out;
733e62513   Mika Westerberg   ACPI: Allow drive...
290
291
292
293
  			return;
  		}
  	}
  	adev->data.of_compatible = of_compatible;
5c53b262c   Rafael J. Wysocki   ACPI / property: ...
294
295
296
  
   out:
  	adev->flags.of_compatible_ok = 1;
733e62513   Mika Westerberg   ACPI: Allow drive...
297
  }
5f5e4890d   Mika Westerberg   ACPI / property: ...
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  static bool acpi_is_property_guid(const guid_t *guid)
  {
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(prp_guids); i++) {
  		if (guid_equal(guid, &prp_guids[i]))
  			return true;
  	}
  
  	return false;
  }
  
  struct acpi_device_properties *
  acpi_data_add_props(struct acpi_device_data *data, const guid_t *guid,
  		    const union acpi_object *properties)
  {
  	struct acpi_device_properties *props;
  
  	props = kzalloc(sizeof(*props), GFP_KERNEL);
  	if (props) {
  		INIT_LIST_HEAD(&props->list);
  		props->guid = guid;
  		props->properties = properties;
  		list_add_tail(&props->list, &data->properties);
  	}
  
  	return props;
  }
bd8191cc8   Rafael J. Wysocki   ACPI / property: ...
326
327
  static bool acpi_extract_properties(const union acpi_object *desc,
  				    struct acpi_device_data *data)
ffdcd955c   Mika Westerberg   ACPI: Add support...
328
  {
ffdcd955c   Mika Westerberg   ACPI: Add support...
329
  	int i;
ffdcd955c   Mika Westerberg   ACPI: Add support...
330
  	if (desc->package.count % 2)
bd8191cc8   Rafael J. Wysocki   ACPI / property: ...
331
  		return false;
ffdcd955c   Mika Westerberg   ACPI: Add support...
332

3689d3d69   Andy Shevchenko   ACPI: device prop...
333
  	/* Look for the device properties GUID. */
ffdcd955c   Mika Westerberg   ACPI: Add support...
334
  	for (i = 0; i < desc->package.count; i += 2) {
3689d3d69   Andy Shevchenko   ACPI: device prop...
335
  		const union acpi_object *guid, *properties;
ffdcd955c   Mika Westerberg   ACPI: Add support...
336

3689d3d69   Andy Shevchenko   ACPI: device prop...
337
  		guid = &desc->package.elements[i];
ffdcd955c   Mika Westerberg   ACPI: Add support...
338
339
340
  		properties = &desc->package.elements[i + 1];
  
  		/*
3689d3d69   Andy Shevchenko   ACPI: device prop...
341
  		 * The first element must be a GUID and the second one must be
ffdcd955c   Mika Westerberg   ACPI: Add support...
342
343
  		 * a package.
  		 */
3689d3d69   Andy Shevchenko   ACPI: device prop...
344
345
346
  		if (guid->type != ACPI_TYPE_BUFFER ||
  		    guid->buffer.length != 16 ||
  		    properties->type != ACPI_TYPE_PACKAGE)
ffdcd955c   Mika Westerberg   ACPI: Add support...
347
  			break;
5f5e4890d   Mika Westerberg   ACPI / property: ...
348
  		if (!acpi_is_property_guid((guid_t *)guid->buffer.pointer))
ffdcd955c   Mika Westerberg   ACPI: Add support...
349
350
351
  			continue;
  
  		/*
3689d3d69   Andy Shevchenko   ACPI: device prop...
352
  		 * We found the matching GUID. Now validate the format of the
ffdcd955c   Mika Westerberg   ACPI: Add support...
353
354
355
  		 * package immediately following it.
  		 */
  		if (!acpi_properties_format_valid(properties))
5f5e4890d   Mika Westerberg   ACPI / property: ...
356
  			continue;
ffdcd955c   Mika Westerberg   ACPI: Add support...
357

5f5e4890d   Mika Westerberg   ACPI / property: ...
358
359
  		acpi_data_add_props(data, (const guid_t *)guid->buffer.pointer,
  				    properties);
bd8191cc8   Rafael J. Wysocki   ACPI / property: ...
360
  	}
733e62513   Mika Westerberg   ACPI: Allow drive...
361

5f5e4890d   Mika Westerberg   ACPI / property: ...
362
  	return !list_empty(&data->properties);
bd8191cc8   Rafael J. Wysocki   ACPI / property: ...
363
  }
5c53b262c   Rafael J. Wysocki   ACPI / property: ...
364

bd8191cc8   Rafael J. Wysocki   ACPI / property: ...
365
366
367
368
369
370
  void acpi_init_properties(struct acpi_device *adev)
  {
  	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
  	struct acpi_hardware_id *hwid;
  	acpi_status status;
  	bool acpi_of = false;
5f5e4890d   Mika Westerberg   ACPI / property: ...
371
  	INIT_LIST_HEAD(&adev->data.properties);
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
372
  	INIT_LIST_HEAD(&adev->data.subnodes);
75fc70e07   Lukas Wunner   ACPI / property: ...
373
374
  	if (!adev->handle)
  		return;
bd8191cc8   Rafael J. Wysocki   ACPI / property: ...
375
376
377
378
379
380
381
382
383
  	/*
  	 * Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in
  	 * Device Tree compatible properties for this device.
  	 */
  	list_for_each_entry(hwid, &adev->pnp.ids, list) {
  		if (!strcmp(hwid->id, ACPI_DT_NAMESPACE_HID)) {
  			acpi_of = true;
  			break;
  		}
ffdcd955c   Mika Westerberg   ACPI: Add support...
384
  	}
bd8191cc8   Rafael J. Wysocki   ACPI / property: ...
385
386
387
388
389
390
391
392
393
  	status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
  					    ACPI_TYPE_PACKAGE);
  	if (ACPI_FAILURE(status))
  		goto out;
  
  	if (acpi_extract_properties(buf.pointer, &adev->data)) {
  		adev->data.pointer = buf.pointer;
  		if (acpi_of)
  			acpi_init_of_compatible(adev);
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
394
  	}
dfa672fbc   Mika Westerberg   ACPI / property: ...
395
396
  	if (acpi_enumerate_nondev_subnodes(adev->handle, buf.pointer,
  					&adev->data, acpi_fwnode_handle(adev)))
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
397
398
399
  		adev->data.pointer = buf.pointer;
  
  	if (!adev->data.pointer) {
bd8191cc8   Rafael J. Wysocki   ACPI / property: ...
400
401
402
403
  		acpi_handle_debug(adev->handle, "Invalid _DSD data, skipping
  ");
  		ACPI_FREE(buf.pointer);
  	}
5c53b262c   Rafael J. Wysocki   ACPI / property: ...
404
405
406
407
  
   out:
  	if (acpi_of && !adev->flags.of_compatible_ok)
  		acpi_handle_info(adev->handle,
ee8920940   Rafael J. Wysocki   ACPI / property: ...
408
409
  			 ACPI_DT_NAMESPACE_HID " requires 'compatible' property
  ");
899596e09   Lukas Wunner   ACPI / property: ...
410
411
412
  
  	if (!adev->data.pointer)
  		acpi_extract_apple_properties(adev);
ffdcd955c   Mika Westerberg   ACPI: Add support...
413
  }
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
414
415
416
417
418
419
420
421
422
  static void acpi_destroy_nondev_subnodes(struct list_head *list)
  {
  	struct acpi_data_node *dn, *next;
  
  	if (list_empty(list))
  		return;
  
  	list_for_each_entry_safe_reverse(dn, next, list, sibling) {
  		acpi_destroy_nondev_subnodes(&dn->data.subnodes);
263b4c1a6   Rafael J. Wysocki   ACPI / property: ...
423
  		wait_for_completion(&dn->kobj_done);
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
424
425
426
427
428
  		list_del(&dn->sibling);
  		ACPI_FREE((void *)dn->data.pointer);
  		kfree(dn);
  	}
  }
ffdcd955c   Mika Westerberg   ACPI: Add support...
429
430
  void acpi_free_properties(struct acpi_device *adev)
  {
5f5e4890d   Mika Westerberg   ACPI / property: ...
431
  	struct acpi_device_properties *props, *tmp;
445b0eb05   Rafael J. Wysocki   ACPI / property: ...
432
  	acpi_destroy_nondev_subnodes(&adev->data.subnodes);
ffdcd955c   Mika Westerberg   ACPI: Add support...
433
  	ACPI_FREE((void *)adev->data.pointer);
733e62513   Mika Westerberg   ACPI: Allow drive...
434
  	adev->data.of_compatible = NULL;
ffdcd955c   Mika Westerberg   ACPI: Add support...
435
  	adev->data.pointer = NULL;
5f5e4890d   Mika Westerberg   ACPI / property: ...
436
437
438
439
  	list_for_each_entry_safe(props, tmp, &adev->data.properties, list) {
  		list_del(&props->list);
  		kfree(props);
  	}
ffdcd955c   Mika Westerberg   ACPI: Add support...
440
441
442
  }
  
  /**
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
443
444
   * acpi_data_get_property - return an ACPI property with given name
   * @data: ACPI device deta object to get the property from
ffdcd955c   Mika Westerberg   ACPI: Add support...
445
446
447
448
449
450
451
452
   * @name: Name of the property
   * @type: Expected property type
   * @obj: Location to store the property value (if not %NULL)
   *
   * Look up a property with @name and store a pointer to the resulting ACPI
   * object at the location pointed to by @obj if found.
   *
   * Callers must not attempt to free the returned objects.  These objects will be
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
453
   * freed by the ACPI core automatically during the removal of @data.
ffdcd955c   Mika Westerberg   ACPI: Add support...
454
455
456
   *
   * Return: %0 if property with @name has been found (success),
   *         %-EINVAL if the arguments are invalid,
3c60f1149   Andy Shevchenko   device property: ...
457
   *         %-EINVAL if the property doesn't exist,
ffdcd955c   Mika Westerberg   ACPI: Add support...
458
459
   *         %-EPROTO if the property value type doesn't match @type.
   */
99a854646   Sakari Ailus   ACPI: Constify in...
460
  static int acpi_data_get_property(const struct acpi_device_data *data,
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
461
462
  				  const char *name, acpi_object_type type,
  				  const union acpi_object **obj)
ffdcd955c   Mika Westerberg   ACPI: Add support...
463
  {
5f5e4890d   Mika Westerberg   ACPI / property: ...
464
  	const struct acpi_device_properties *props;
ffdcd955c   Mika Westerberg   ACPI: Add support...
465

3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
466
  	if (!data || !name)
ffdcd955c   Mika Westerberg   ACPI: Add support...
467
  		return -EINVAL;
5f5e4890d   Mika Westerberg   ACPI / property: ...
468
  	if (!data->pointer || list_empty(&data->properties))
3c60f1149   Andy Shevchenko   device property: ...
469
  		return -EINVAL;
ffdcd955c   Mika Westerberg   ACPI: Add support...
470

5f5e4890d   Mika Westerberg   ACPI / property: ...
471
472
473
  	list_for_each_entry(props, &data->properties, list) {
  		const union acpi_object *properties;
  		unsigned int i;
ffdcd955c   Mika Westerberg   ACPI: Add support...
474

5f5e4890d   Mika Westerberg   ACPI / property: ...
475
476
477
478
479
480
  		properties = props->properties;
  		for (i = 0; i < properties->package.count; i++) {
  			const union acpi_object *propname, *propvalue;
  			const union acpi_object *property;
  
  			property = &properties->package.elements[i];
ffdcd955c   Mika Westerberg   ACPI: Add support...
481

5f5e4890d   Mika Westerberg   ACPI / property: ...
482
483
  			propname = &property->package.elements[0];
  			propvalue = &property->package.elements[1];
ffdcd955c   Mika Westerberg   ACPI: Add support...
484

5f5e4890d   Mika Westerberg   ACPI / property: ...
485
486
487
488
489
490
  			if (!strcmp(name, propname->string.pointer)) {
  				if (type != ACPI_TYPE_ANY &&
  				    propvalue->type != type)
  					return -EPROTO;
  				if (obj)
  					*obj = propvalue;
ffdcd955c   Mika Westerberg   ACPI: Add support...
491

5f5e4890d   Mika Westerberg   ACPI / property: ...
492
493
  				return 0;
  			}
ffdcd955c   Mika Westerberg   ACPI: Add support...
494
495
  		}
  	}
3c60f1149   Andy Shevchenko   device property: ...
496
  	return -EINVAL;
ffdcd955c   Mika Westerberg   ACPI: Add support...
497
  }
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
498
499
500
501
502
503
504
505
  
  /**
   * acpi_dev_get_property - return an ACPI property with given name.
   * @adev: ACPI device to get the property from.
   * @name: Name of the property.
   * @type: Expected property type.
   * @obj: Location to store the property value (if not %NULL).
   */
99a854646   Sakari Ailus   ACPI: Constify in...
506
  int acpi_dev_get_property(const struct acpi_device *adev, const char *name,
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
507
508
509
510
  			  acpi_object_type type, const union acpi_object **obj)
  {
  	return adev ? acpi_data_get_property(&adev->data, name, type, obj) : -EINVAL;
  }
ffdcd955c   Mika Westerberg   ACPI: Add support...
511
  EXPORT_SYMBOL_GPL(acpi_dev_get_property);
99a854646   Sakari Ailus   ACPI: Constify in...
512
513
  static const struct acpi_device_data *
  acpi_device_data_of_node(const struct fwnode_handle *fwnode)
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
514
  {
db3e50f32   Sakari Ailus   device property: ...
515
  	if (is_acpi_device_node(fwnode)) {
99a854646   Sakari Ailus   ACPI: Constify in...
516
  		const struct acpi_device *adev = to_acpi_device_node(fwnode);
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
517
  		return &adev->data;
db3e50f32   Sakari Ailus   device property: ...
518
  	} else if (is_acpi_data_node(fwnode)) {
99a854646   Sakari Ailus   ACPI: Constify in...
519
  		const struct acpi_data_node *dn = to_acpi_data_node(fwnode);
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
520
521
522
523
  		return &dn->data;
  	}
  	return NULL;
  }
ffdcd955c   Mika Westerberg   ACPI: Add support...
524
  /**
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
525
526
527
528
529
   * acpi_node_prop_get - return an ACPI property with given name.
   * @fwnode: Firmware node to get the property from.
   * @propname: Name of the property.
   * @valptr: Location to store a pointer to the property value (if not %NULL).
   */
99a854646   Sakari Ailus   ACPI: Constify in...
530
531
  int acpi_node_prop_get(const struct fwnode_handle *fwnode,
  		       const char *propname, void **valptr)
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
532
533
534
535
536
537
538
539
540
  {
  	return acpi_data_get_property(acpi_device_data_of_node(fwnode),
  				      propname, ACPI_TYPE_ANY,
  				      (const union acpi_object **)valptr);
  }
  
  /**
   * acpi_data_get_property_array - return an ACPI array property with given name
   * @adev: ACPI data object to get the property from
ffdcd955c   Mika Westerberg   ACPI: Add support...
541
542
543
544
545
546
547
548
   * @name: Name of the property
   * @type: Expected type of array elements
   * @obj: Location to store a pointer to the property value (if not NULL)
   *
   * Look up an array property with @name and store a pointer to the resulting
   * ACPI object at the location pointed to by @obj if found.
   *
   * Callers must not attempt to free the returned objects.  Those objects will be
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
549
   * freed by the ACPI core automatically during the removal of @data.
ffdcd955c   Mika Westerberg   ACPI: Add support...
550
551
552
   *
   * Return: %0 if array property (package) with @name has been found (success),
   *         %-EINVAL if the arguments are invalid,
3c60f1149   Andy Shevchenko   device property: ...
553
   *         %-EINVAL if the property doesn't exist,
ffdcd955c   Mika Westerberg   ACPI: Add support...
554
555
556
   *         %-EPROTO if the property is not a package or the type of its elements
   *           doesn't match @type.
   */
99a854646   Sakari Ailus   ACPI: Constify in...
557
  static int acpi_data_get_property_array(const struct acpi_device_data *data,
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
558
559
560
  					const char *name,
  					acpi_object_type type,
  					const union acpi_object **obj)
ffdcd955c   Mika Westerberg   ACPI: Add support...
561
562
563
  {
  	const union acpi_object *prop;
  	int ret, i;
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
564
  	ret = acpi_data_get_property(data, name, ACPI_TYPE_PACKAGE, &prop);
ffdcd955c   Mika Westerberg   ACPI: Add support...
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  	if (ret)
  		return ret;
  
  	if (type != ACPI_TYPE_ANY) {
  		/* Check that all elements are of correct type. */
  		for (i = 0; i < prop->package.count; i++)
  			if (prop->package.elements[i].type != type)
  				return -EPROTO;
  	}
  	if (obj)
  		*obj = prop;
  
  	return 0;
  }
ffdcd955c   Mika Westerberg   ACPI: Add support...
579

4eb0c3bf5   Sakari Ailus   ACPI: property: A...
580
581
582
583
584
  static struct fwnode_handle *
  acpi_fwnode_get_named_child_node(const struct fwnode_handle *fwnode,
  				 const char *childname)
  {
  	struct fwnode_handle *child;
ee48cef6c   Heikki Krogerus   ACPI / property: ...
585
586
587
588
589
590
591
  
  	fwnode_for_each_child_node(fwnode, child) {
  		if (is_acpi_data_node(child)) {
  			if (acpi_data_node_match(child, childname))
  				return child;
  			continue;
  		}
cbdd865a9   Heikki Krogerus   ACPI: property: u...
592
593
  		if (!strncmp(acpi_device_bid(to_acpi_device_node(child)),
  			     childname, ACPI_NAMESEG_SIZE))
4eb0c3bf5   Sakari Ailus   ACPI: property: A...
594
  			return child;
ee48cef6c   Heikki Krogerus   ACPI / property: ...
595
  	}
4eb0c3bf5   Sakari Ailus   ACPI: property: A...
596
597
598
  
  	return NULL;
  }
ffdcd955c   Mika Westerberg   ACPI: Add support...
599
  /**
b60e4ea4a   Mika Westerberg   ACPI / property: ...
600
601
   * __acpi_node_get_property_reference - returns handle to the referenced object
   * @fwnode: Firmware node to get the property from
504a33749   Rafael J. Wysocki   ACPI / property: ...
602
   * @propname: Name of the property
ffdcd955c   Mika Westerberg   ACPI: Add support...
603
   * @index: Index of the reference to return
b60e4ea4a   Mika Westerberg   ACPI / property: ...
604
   * @num_args: Maximum number of arguments after each reference
ffdcd955c   Mika Westerberg   ACPI: Add support...
605
606
607
608
   * @args: Location to store the returned reference with optional arguments
   *
   * Find property with @name, verifify that it is a package containing at least
   * one object reference and if so, store the ACPI device object pointer to the
60ba032ed   Rafael J. Wysocki   ACPI / property: ...
609
610
   * target object in @args->adev.  If the reference includes arguments, store
   * them in the @args->args[] array.
ffdcd955c   Mika Westerberg   ACPI: Add support...
611
   *
60ba032ed   Rafael J. Wysocki   ACPI / property: ...
612
613
   * If there's more than one reference in the property value package, @index is
   * used to select the one to return.
ffdcd955c   Mika Westerberg   ACPI: Add support...
614
   *
b60e4ea4a   Mika Westerberg   ACPI / property: ...
615
616
617
618
619
620
621
622
623
624
625
626
627
   * It is possible to leave holes in the property value set like in the
   * example below:
   *
   * Package () {
   *     "cs-gpios",
   *     Package () {
   *        ^GPIO, 19, 0, 0,
   *        ^GPIO, 20, 0, 0,
   *        0,
   *        ^GPIO, 21, 0, 0,
   *     }
   * }
   *
c343bc2ce   Sakari Ailus   ACPI: properties:...
628
629
630
   * Calling this function with index %2 or index %3 return %-ENOENT. If the
   * property does not contain any more values %-ENOENT is returned. The NULL
   * entry must be single integer and preferably contain value %0.
b60e4ea4a   Mika Westerberg   ACPI / property: ...
631
   *
ffdcd955c   Mika Westerberg   ACPI: Add support...
632
633
   * Return: %0 on success, negative error code on failure.
   */
99a854646   Sakari Ailus   ACPI: Constify in...
634
  int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode,
b60e4ea4a   Mika Westerberg   ACPI / property: ...
635
  	const char *propname, size_t index, size_t num_args,
977d5ad39   Sakari Ailus   ACPI: Convert ACP...
636
  	struct fwnode_reference_args *args)
ffdcd955c   Mika Westerberg   ACPI: Add support...
637
638
639
  {
  	const union acpi_object *element, *end;
  	const union acpi_object *obj;
99a854646   Sakari Ailus   ACPI: Constify in...
640
  	const struct acpi_device_data *data;
ffdcd955c   Mika Westerberg   ACPI: Add support...
641
642
  	struct acpi_device *device;
  	int ret, idx = 0;
b60e4ea4a   Mika Westerberg   ACPI / property: ...
643
644
  	data = acpi_device_data_of_node(fwnode);
  	if (!data)
c343bc2ce   Sakari Ailus   ACPI: properties:...
645
  		return -ENOENT;
b60e4ea4a   Mika Westerberg   ACPI / property: ...
646

504a33749   Rafael J. Wysocki   ACPI / property: ...
647
  	ret = acpi_data_get_property(data, propname, ACPI_TYPE_ANY, &obj);
ffdcd955c   Mika Westerberg   ACPI: Add support...
648
  	if (ret)
51858a277   Sakari Ailus   ACPI: properties:...
649
  		return ret == -EINVAL ? -ENOENT : -EINVAL;
ffdcd955c   Mika Westerberg   ACPI: Add support...
650
651
652
653
654
655
  
  	/*
  	 * The simplest case is when the value is a single reference.  Just
  	 * return that reference then.
  	 */
  	if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
60ba032ed   Rafael J. Wysocki   ACPI / property: ...
656
  		if (index)
ffdcd955c   Mika Westerberg   ACPI: Add support...
657
658
659
660
  			return -EINVAL;
  
  		ret = acpi_bus_get_device(obj->reference.handle, &device);
  		if (ret)
51858a277   Sakari Ailus   ACPI: properties:...
661
  			return ret == -ENODEV ? -EINVAL : ret;
ffdcd955c   Mika Westerberg   ACPI: Add support...
662

977d5ad39   Sakari Ailus   ACPI: Convert ACP...
663
  		args->fwnode = acpi_fwnode_handle(device);
ffdcd955c   Mika Westerberg   ACPI: Add support...
664
665
666
667
668
669
670
671
672
673
674
675
676
  		args->nargs = 0;
  		return 0;
  	}
  
  	/*
  	 * If it is not a single reference, then it is a package of
  	 * references followed by number of ints as follows:
  	 *
  	 *  Package () { REF, INT, REF, INT, INT }
  	 *
  	 * The index argument is then used to determine which reference
  	 * the caller wants (along with the arguments).
  	 */
51858a277   Sakari Ailus   ACPI: properties:...
677
678
679
680
  	if (obj->type != ACPI_TYPE_PACKAGE)
  		return -EINVAL;
  	if (index >= obj->package.count)
  		return -ENOENT;
ffdcd955c   Mika Westerberg   ACPI: Add support...
681
682
683
684
685
686
  
  	element = obj->package.elements;
  	end = element + obj->package.count;
  
  	while (element < end) {
  		u32 nargs, i;
b60e4ea4a   Mika Westerberg   ACPI / property: ...
687
  		if (element->type == ACPI_TYPE_LOCAL_REFERENCE) {
4eb0c3bf5   Sakari Ailus   ACPI: property: A...
688
  			struct fwnode_handle *ref_fwnode;
b60e4ea4a   Mika Westerberg   ACPI / property: ...
689
690
691
  			ret = acpi_bus_get_device(element->reference.handle,
  						  &device);
  			if (ret)
c343bc2ce   Sakari Ailus   ACPI: properties:...
692
  				return -EINVAL;
b60e4ea4a   Mika Westerberg   ACPI / property: ...
693
694
695
  
  			nargs = 0;
  			element++;
4eb0c3bf5   Sakari Ailus   ACPI: property: A...
696
697
698
699
700
701
702
703
704
705
706
707
  			/*
  			 * Find the referred data extension node under the
  			 * referred device node.
  			 */
  			for (ref_fwnode = acpi_fwnode_handle(device);
  			     element < end && element->type == ACPI_TYPE_STRING;
  			     element++) {
  				ref_fwnode = acpi_fwnode_get_named_child_node(
  					ref_fwnode, element->string.pointer);
  				if (!ref_fwnode)
  					return -EINVAL;
  			}
b60e4ea4a   Mika Westerberg   ACPI / property: ...
708
709
710
711
712
713
714
715
716
  			/* assume following integer elements are all args */
  			for (i = 0; element + i < end && i < num_args; i++) {
  				int type = element[i].type;
  
  				if (type == ACPI_TYPE_INTEGER)
  					nargs++;
  				else if (type == ACPI_TYPE_LOCAL_REFERENCE)
  					break;
  				else
c343bc2ce   Sakari Ailus   ACPI: properties:...
717
  					return -EINVAL;
b60e4ea4a   Mika Westerberg   ACPI / property: ...
718
  			}
ffdcd955c   Mika Westerberg   ACPI: Add support...
719

977d5ad39   Sakari Ailus   ACPI: Convert ACP...
720
  			if (nargs > NR_FWNODE_REFERENCE_ARGS)
c343bc2ce   Sakari Ailus   ACPI: properties:...
721
  				return -EINVAL;
ffdcd955c   Mika Westerberg   ACPI: Add support...
722

b60e4ea4a   Mika Westerberg   ACPI / property: ...
723
  			if (idx == index) {
4eb0c3bf5   Sakari Ailus   ACPI: property: A...
724
  				args->fwnode = ref_fwnode;
b60e4ea4a   Mika Westerberg   ACPI / property: ...
725
726
727
  				args->nargs = nargs;
  				for (i = 0; i < nargs; i++)
  					args->args[i] = element[i].integer.value;
ffdcd955c   Mika Westerberg   ACPI: Add support...
728

b60e4ea4a   Mika Westerberg   ACPI / property: ...
729
730
731
732
733
734
735
736
737
  				return 0;
  			}
  
  			element += nargs;
  		} else if (element->type == ACPI_TYPE_INTEGER) {
  			if (idx == index)
  				return -ENOENT;
  			element++;
  		} else {
c343bc2ce   Sakari Ailus   ACPI: properties:...
738
  			return -EINVAL;
ffdcd955c   Mika Westerberg   ACPI: Add support...
739
  		}
b60e4ea4a   Mika Westerberg   ACPI / property: ...
740
  		idx++;
ffdcd955c   Mika Westerberg   ACPI: Add support...
741
  	}
c343bc2ce   Sakari Ailus   ACPI: properties:...
742
  	return -ENOENT;
504a33749   Rafael J. Wysocki   ACPI / property: ...
743
  }
b60e4ea4a   Mika Westerberg   ACPI / property: ...
744
  EXPORT_SYMBOL_GPL(__acpi_node_get_property_reference);
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
745

99a854646   Sakari Ailus   ACPI: Constify in...
746
  static int acpi_data_prop_read_single(const struct acpi_device_data *data,
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
747
748
  				      const char *propname,
  				      enum dev_prop_type proptype, void *val)
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
749
750
751
752
753
754
755
756
  {
  	const union acpi_object *obj;
  	int ret;
  
  	if (!val)
  		return -EINVAL;
  
  	if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
757
  		ret = acpi_data_get_property(data, propname, ACPI_TYPE_INTEGER, &obj);
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
  		if (ret)
  			return ret;
  
  		switch (proptype) {
  		case DEV_PROP_U8:
  			if (obj->integer.value > U8_MAX)
  				return -EOVERFLOW;
  			*(u8 *)val = obj->integer.value;
  			break;
  		case DEV_PROP_U16:
  			if (obj->integer.value > U16_MAX)
  				return -EOVERFLOW;
  			*(u16 *)val = obj->integer.value;
  			break;
  		case DEV_PROP_U32:
  			if (obj->integer.value > U32_MAX)
  				return -EOVERFLOW;
  			*(u32 *)val = obj->integer.value;
  			break;
  		default:
  			*(u64 *)val = obj->integer.value;
  			break;
  		}
  	} else if (proptype == DEV_PROP_STRING) {
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
782
  		ret = acpi_data_get_property(data, propname, ACPI_TYPE_STRING, &obj);
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
783
784
785
786
  		if (ret)
  			return ret;
  
  		*(char **)val = obj->string.pointer;
b0b027cee   Sakari Ailus   device property: ...
787
788
  
  		return 1;
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
789
790
791
792
793
  	} else {
  		ret = -EINVAL;
  	}
  	return ret;
  }
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
794
795
796
  int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
  			      enum dev_prop_type proptype, void *val)
  {
b0b027cee   Sakari Ailus   device property: ...
797
798
799
800
801
802
803
804
805
  	int ret;
  
  	if (!adev)
  		return -EINVAL;
  
  	ret = acpi_data_prop_read_single(&adev->data, propname, proptype, val);
  	if (ret < 0 || proptype != ACPI_TYPE_STRING)
  		return ret;
  	return 0;
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
806
  }
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
  static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
  				       size_t nval)
  {
  	int i;
  
  	for (i = 0; i < nval; i++) {
  		if (items[i].type != ACPI_TYPE_INTEGER)
  			return -EPROTO;
  		if (items[i].integer.value > U8_MAX)
  			return -EOVERFLOW;
  
  		val[i] = items[i].integer.value;
  	}
  	return 0;
  }
  
  static int acpi_copy_property_array_u16(const union acpi_object *items,
  					u16 *val, size_t nval)
  {
  	int i;
  
  	for (i = 0; i < nval; i++) {
  		if (items[i].type != ACPI_TYPE_INTEGER)
  			return -EPROTO;
  		if (items[i].integer.value > U16_MAX)
  			return -EOVERFLOW;
  
  		val[i] = items[i].integer.value;
  	}
  	return 0;
  }
  
  static int acpi_copy_property_array_u32(const union acpi_object *items,
  					u32 *val, size_t nval)
  {
  	int i;
  
  	for (i = 0; i < nval; i++) {
  		if (items[i].type != ACPI_TYPE_INTEGER)
  			return -EPROTO;
  		if (items[i].integer.value > U32_MAX)
  			return -EOVERFLOW;
  
  		val[i] = items[i].integer.value;
  	}
  	return 0;
  }
  
  static int acpi_copy_property_array_u64(const union acpi_object *items,
  					u64 *val, size_t nval)
  {
  	int i;
  
  	for (i = 0; i < nval; i++) {
  		if (items[i].type != ACPI_TYPE_INTEGER)
  			return -EPROTO;
  
  		val[i] = items[i].integer.value;
  	}
  	return 0;
  }
  
  static int acpi_copy_property_array_string(const union acpi_object *items,
  					   char **val, size_t nval)
  {
  	int i;
  
  	for (i = 0; i < nval; i++) {
  		if (items[i].type != ACPI_TYPE_STRING)
  			return -EPROTO;
  
  		val[i] = items[i].string.pointer;
  	}
b0b027cee   Sakari Ailus   device property: ...
880
  	return nval;
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
881
  }
99a854646   Sakari Ailus   ACPI: Constify in...
882
  static int acpi_data_prop_read(const struct acpi_device_data *data,
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
883
884
885
  			       const char *propname,
  			       enum dev_prop_type proptype,
  			       void *val, size_t nval)
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
886
887
888
889
890
891
  {
  	const union acpi_object *obj;
  	const union acpi_object *items;
  	int ret;
  
  	if (val && nval == 1) {
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
892
  		ret = acpi_data_prop_read_single(data, propname, proptype, val);
b0b027cee   Sakari Ailus   device property: ...
893
  		if (ret >= 0)
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
894
895
  			return ret;
  	}
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
896
  	ret = acpi_data_get_property_array(data, propname, ACPI_TYPE_ANY, &obj);
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
897
898
899
900
901
  	if (ret)
  		return ret;
  
  	if (!val)
  		return obj->package.count;
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
902

b0b027cee   Sakari Ailus   device property: ...
903
  	if (proptype != DEV_PROP_STRING && nval > obj->package.count)
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
904
  		return -EOVERFLOW;
7dc59dc93   Andy Shevchenko   device property: ...
905
906
  	else if (nval <= 0)
  		return -EINVAL;
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
907
908
  
  	items = obj->package.elements;
7dc59dc93   Andy Shevchenko   device property: ...
909

b31384fa5   Rafael J. Wysocki   Driver core: Unif...
910
911
912
913
914
915
916
917
918
919
920
921
922
923
  	switch (proptype) {
  	case DEV_PROP_U8:
  		ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
  		break;
  	case DEV_PROP_U16:
  		ret = acpi_copy_property_array_u16(items, (u16 *)val, nval);
  		break;
  	case DEV_PROP_U32:
  		ret = acpi_copy_property_array_u32(items, (u32 *)val, nval);
  		break;
  	case DEV_PROP_U64:
  		ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
  		break;
  	case DEV_PROP_STRING:
b0b027cee   Sakari Ailus   device property: ...
924
925
926
  		ret = acpi_copy_property_array_string(
  			items, (char **)val,
  			min_t(u32, nval, obj->package.count));
b31384fa5   Rafael J. Wysocki   Driver core: Unif...
927
928
929
930
931
932
933
  		break;
  	default:
  		ret = -EINVAL;
  		break;
  	}
  	return ret;
  }
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
934

99a854646   Sakari Ailus   ACPI: Constify in...
935
  int acpi_dev_prop_read(const struct acpi_device *adev, const char *propname,
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
  		       enum dev_prop_type proptype, void *val, size_t nval)
  {
  	return adev ? acpi_data_prop_read(&adev->data, propname, proptype, val, nval) : -EINVAL;
  }
  
  /**
   * acpi_node_prop_read - retrieve the value of an ACPI property with given name.
   * @fwnode: Firmware node to get the property from.
   * @propname: Name of the property.
   * @proptype: Expected property type.
   * @val: Location to store the property value (if not %NULL).
   * @nval: Size of the array pointed to by @val.
   *
   * If @val is %NULL, return the number of array elements comprising the value
   * of the property.  Otherwise, read at most @nval values to the array at the
   * location pointed to by @val.
   */
99a854646   Sakari Ailus   ACPI: Constify in...
953
954
955
  int acpi_node_prop_read(const struct fwnode_handle *fwnode,
  			const char *propname, enum dev_prop_type proptype,
  			void *val, size_t nval)
3a7a2ab83   Rafael J. Wysocki   ACPI / property: ...
956
957
958
959
  {
  	return acpi_data_prop_read(acpi_device_data_of_node(fwnode),
  				   propname, proptype, val, nval);
  }
504a33749   Rafael J. Wysocki   ACPI / property: ...
960
961
  
  /**
34055190b   Mika Westerberg   ACPI / property: ...
962
963
   * acpi_get_next_subnode - Return the next child node handle for a fwnode
   * @fwnode: Firmware node to find the next child node for.
504a33749   Rafael J. Wysocki   ACPI / property: ...
964
965
   * @child: Handle to one of the device's child nodes or a null handle.
   */
37ba983cf   Sakari Ailus   device property: ...
966
  struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode,
504a33749   Rafael J. Wysocki   ACPI / property: ...
967
968
  					    struct fwnode_handle *child)
  {
01c1da289   Sakari Ailus   ACPI: Prepare for...
969
  	const struct acpi_device *adev = to_acpi_device_node(fwnode);
01c1da289   Sakari Ailus   ACPI: Prepare for...
970
971
  	const struct list_head *head;
  	struct list_head *next;
504a33749   Rafael J. Wysocki   ACPI / property: ...
972

db3e50f32   Sakari Ailus   device property: ...
973
  	if (!child || is_acpi_device_node(child)) {
0c0bceb79   Sakari Ailus   ACPI: properties:...
974
  		struct acpi_device *child_adev;
34055190b   Mika Westerberg   ACPI / property: ...
975
976
977
978
  		if (adev)
  			head = &adev->children;
  		else
  			goto nondev;
504a33749   Rafael J. Wysocki   ACPI / property: ...
979
980
981
982
  		if (list_empty(head))
  			goto nondev;
  
  		if (child) {
0c0bceb79   Sakari Ailus   ACPI: properties:...
983
984
  			adev = to_acpi_device_node(child);
  			next = adev->node.next;
504a33749   Rafael J. Wysocki   ACPI / property: ...
985
986
987
988
  			if (next == head) {
  				child = NULL;
  				goto nondev;
  			}
01c1da289   Sakari Ailus   ACPI: Prepare for...
989
  			child_adev = list_entry(next, struct acpi_device, node);
504a33749   Rafael J. Wysocki   ACPI / property: ...
990
  		} else {
01c1da289   Sakari Ailus   ACPI: Prepare for...
991
992
  			child_adev = list_first_entry(head, struct acpi_device,
  						      node);
504a33749   Rafael J. Wysocki   ACPI / property: ...
993
  		}
01c1da289   Sakari Ailus   ACPI: Prepare for...
994
  		return acpi_fwnode_handle(child_adev);
504a33749   Rafael J. Wysocki   ACPI / property: ...
995
996
997
  	}
  
   nondev:
db3e50f32   Sakari Ailus   device property: ...
998
  	if (!child || is_acpi_data_node(child)) {
01c1da289   Sakari Ailus   ACPI: Prepare for...
999
  		const struct acpi_data_node *data = to_acpi_data_node(fwnode);
504a33749   Rafael J. Wysocki   ACPI / property: ...
1000
  		struct acpi_data_node *dn;
23583f779   Pierre-Louis Bossart   ACPI / property: ...
1001
1002
1003
1004
1005
1006
1007
1008
  		/*
  		 * We can have a combination of device and data nodes, e.g. with
  		 * hierarchical _DSD properties. Make sure the adev pointer is
  		 * restored before going through data nodes, otherwise we will
  		 * be looking for data_nodes below the last device found instead
  		 * of the common fwnode shared by device_nodes and data_nodes.
  		 */
  		adev = to_acpi_device_node(fwnode);
0c0bceb79   Sakari Ailus   ACPI: properties:...
1009
1010
  		if (adev)
  			head = &adev->data.subnodes;
34055190b   Mika Westerberg   ACPI / property: ...
1011
1012
1013
1014
  		else if (data)
  			head = &data->data.subnodes;
  		else
  			return NULL;
504a33749   Rafael J. Wysocki   ACPI / property: ...
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
  		if (list_empty(head))
  			return NULL;
  
  		if (child) {
  			dn = to_acpi_data_node(child);
  			next = dn->sibling.next;
  			if (next == head)
  				return NULL;
  
  			dn = list_entry(next, struct acpi_data_node, sibling);
  		} else {
  			dn = list_first_entry(head, struct acpi_data_node, sibling);
  		}
  		return &dn->fwnode;
  	}
  	return NULL;
  }
dfa672fbc   Mika Westerberg   ACPI / property: ...
1032
1033
1034
1035
1036
1037
1038
1039
  
  /**
   * acpi_node_get_parent - Return parent fwnode of this fwnode
   * @fwnode: Firmware node whose parent to get
   *
   * Returns parent node of an ACPI device or data firmware node or %NULL if
   * not available.
   */
37ba983cf   Sakari Ailus   device property: ...
1040
  struct fwnode_handle *acpi_node_get_parent(const struct fwnode_handle *fwnode)
dfa672fbc   Mika Westerberg   ACPI / property: ...
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
  {
  	if (is_acpi_data_node(fwnode)) {
  		/* All data nodes have parent pointer so just return that */
  		return to_acpi_data_node(fwnode)->parent;
  	} else if (is_acpi_device_node(fwnode)) {
  		acpi_handle handle, parent_handle;
  
  		handle = to_acpi_device_node(fwnode)->handle;
  		if (ACPI_SUCCESS(acpi_get_parent(handle, &parent_handle))) {
  			struct acpi_device *adev;
  
  			if (!acpi_bus_get_device(parent_handle, &adev))
  				return acpi_fwnode_handle(adev);
  		}
  	}
  
  	return NULL;
  }
79389a83b   Mika Westerberg   ACPI / property: ...
1059

18f1e58d1   Sakari Ailus   ACPI: property: U...
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
  /*
   * Return true if the node is an ACPI graph node. Called on either ports
   * or endpoints.
   */
  static bool is_acpi_graph_node(struct fwnode_handle *fwnode,
  			       const char *str)
  {
  	unsigned int len = strlen(str);
  	const char *name;
  
  	if (!len || !is_acpi_data_node(fwnode))
  		return false;
  
  	name = to_acpi_data_node(fwnode)->name;
  
  	return (fwnode_property_present(fwnode, "reg") &&
  		!strncmp(name, str, len) && name[len] == '@') ||
  		fwnode_property_present(fwnode, str);
  }
79389a83b   Mika Westerberg   ACPI / property: ...
1079
1080
1081
1082
1083
1084
  /**
   * acpi_graph_get_next_endpoint - Get next endpoint ACPI firmware node
   * @fwnode: Pointer to the parent firmware node
   * @prev: Previous endpoint node or %NULL to get the first
   *
   * Looks up next endpoint ACPI firmware node below a given @fwnode. Returns
0ef747863   Sakari Ailus   ACPI: property: M...
1085
1086
   * %NULL if there is no next endpoint or in case of error. In case of success
   * the next endpoint is returned.
79389a83b   Mika Westerberg   ACPI / property: ...
1087
   */
0ef747863   Sakari Ailus   ACPI: property: M...
1088
  static struct fwnode_handle *acpi_graph_get_next_endpoint(
37ba983cf   Sakari Ailus   device property: ...
1089
  	const struct fwnode_handle *fwnode, struct fwnode_handle *prev)
79389a83b   Mika Westerberg   ACPI / property: ...
1090
1091
1092
1093
1094
1095
1096
  {
  	struct fwnode_handle *port = NULL;
  	struct fwnode_handle *endpoint;
  
  	if (!prev) {
  		do {
  			port = fwnode_get_next_child_node(fwnode, port);
18f1e58d1   Sakari Ailus   ACPI: property: U...
1097
1098
1099
1100
1101
1102
1103
1104
  			/*
  			 * The names of the port nodes begin with "port@"
  			 * followed by the number of the port node and they also
  			 * have a "reg" property that also has the number of the
  			 * port node. For compatibility reasons a node is also
  			 * recognised as a port node from the "port" property.
  			 */
  			if (is_acpi_graph_node(port, "port"))
79389a83b   Mika Westerberg   ACPI / property: ...
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
  				break;
  		} while (port);
  	} else {
  		port = fwnode_get_parent(prev);
  	}
  
  	if (!port)
  		return NULL;
  
  	endpoint = fwnode_get_next_child_node(port, prev);
  	while (!endpoint) {
  		port = fwnode_get_next_child_node(fwnode, port);
  		if (!port)
  			break;
18f1e58d1   Sakari Ailus   ACPI: property: U...
1119
  		if (is_acpi_graph_node(port, "port"))
79389a83b   Mika Westerberg   ACPI / property: ...
1120
1121
  			endpoint = fwnode_get_next_child_node(port, NULL);
  	}
18f1e58d1   Sakari Ailus   ACPI: property: U...
1122
1123
1124
1125
1126
1127
1128
1129
  	/*
  	 * The names of the endpoint nodes begin with "endpoint@" followed by
  	 * the number of the endpoint node and they also have a "reg" property
  	 * that also has the number of the endpoint node. For compatibility
  	 * reasons a node is also recognised as an endpoint node from the
  	 * "endpoint" property.
  	 */
  	if (!is_acpi_graph_node(endpoint, "endpoint"))
0ef747863   Sakari Ailus   ACPI: property: M...
1130
  		return NULL;
79389a83b   Mika Westerberg   ACPI / property: ...
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
  
  	return endpoint;
  }
  
  /**
   * acpi_graph_get_child_prop_value - Return a child with a given property value
   * @fwnode: device fwnode
   * @prop_name: The name of the property to look for
   * @val: the desired property value
   *
   * Return the port node corresponding to a given port number. Returns
   * the child node on success, NULL otherwise.
   */
  static struct fwnode_handle *acpi_graph_get_child_prop_value(
37ba983cf   Sakari Ailus   device property: ...
1145
1146
  	const struct fwnode_handle *fwnode, const char *prop_name,
  	unsigned int val)
79389a83b   Mika Westerberg   ACPI / property: ...
1147
1148
1149
1150
1151
  {
  	struct fwnode_handle *child;
  
  	fwnode_for_each_child_node(fwnode, child) {
  		u32 nr;
b5212f57d   Sakari Ailus   ACPI: device prop...
1152
  		if (fwnode_property_read_u32(child, prop_name, &nr))
79389a83b   Mika Westerberg   ACPI / property: ...
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
  			continue;
  
  		if (val == nr)
  			return child;
  	}
  
  	return NULL;
  }
  
  
  /**
3a2650a87   Geert Uytterhoeven   ACPI / property: ...
1164
   * acpi_graph_get_remote_endpoint - Parses and returns remote end of an endpoint
79389a83b   Mika Westerberg   ACPI / property: ...
1165
   * @fwnode: Endpoint firmware node pointing to a remote device
79389a83b   Mika Westerberg   ACPI / property: ...
1166
1167
   * @endpoint: Firmware node of remote endpoint is filled here if not %NULL
   *
0ef747863   Sakari Ailus   ACPI: property: M...
1168
   * Returns the remote endpoint corresponding to @__fwnode. NULL on error.
79389a83b   Mika Westerberg   ACPI / property: ...
1169
   */
0ef747863   Sakari Ailus   ACPI: property: M...
1170
1171
  static struct fwnode_handle *
  acpi_graph_get_remote_endpoint(const struct fwnode_handle *__fwnode)
79389a83b   Mika Westerberg   ACPI / property: ...
1172
  {
37ba983cf   Sakari Ailus   device property: ...
1173
  	struct fwnode_handle *fwnode;
79389a83b   Mika Westerberg   ACPI / property: ...
1174
  	unsigned int port_nr, endpoint_nr;
977d5ad39   Sakari Ailus   ACPI: Convert ACP...
1175
  	struct fwnode_reference_args args;
79389a83b   Mika Westerberg   ACPI / property: ...
1176
1177
1178
  	int ret;
  
  	memset(&args, 0, sizeof(args));
37ba983cf   Sakari Ailus   device property: ...
1179
  	ret = acpi_node_get_property_reference(__fwnode, "remote-endpoint", 0,
79389a83b   Mika Westerberg   ACPI / property: ...
1180
1181
  					       &args);
  	if (ret)
0ef747863   Sakari Ailus   ACPI: property: M...
1182
  		return NULL;
79389a83b   Mika Westerberg   ACPI / property: ...
1183

6561eb3d3   Sakari Ailus   ACPI: property: A...
1184
  	/* Direct endpoint reference? */
977d5ad39   Sakari Ailus   ACPI: Convert ACP...
1185
  	if (!is_acpi_device_node(args.fwnode))
6561eb3d3   Sakari Ailus   ACPI: property: A...
1186
  		return args.nargs ? NULL : args.fwnode;
977d5ad39   Sakari Ailus   ACPI: Convert ACP...
1187

79389a83b   Mika Westerberg   ACPI / property: ...
1188
1189
1190
1191
1192
  	/*
  	 * Always require two arguments with the reference: port and
  	 * endpoint indices.
  	 */
  	if (args.nargs != 2)
0ef747863   Sakari Ailus   ACPI: property: M...
1193
  		return NULL;
79389a83b   Mika Westerberg   ACPI / property: ...
1194

977d5ad39   Sakari Ailus   ACPI: Convert ACP...
1195
  	fwnode = args.fwnode;
79389a83b   Mika Westerberg   ACPI / property: ...
1196
1197
  	port_nr = args.args[0];
  	endpoint_nr = args.args[1];
79389a83b   Mika Westerberg   ACPI / property: ...
1198
  	fwnode = acpi_graph_get_child_prop_value(fwnode, "port", port_nr);
79389a83b   Mika Westerberg   ACPI / property: ...
1199

18f1e58d1   Sakari Ailus   ACPI: property: U...
1200
  	return acpi_graph_get_child_prop_value(fwnode, "endpoint", endpoint_nr);
79389a83b   Mika Westerberg   ACPI / property: ...
1201
  }
3708184af   Sakari Ailus   device property: ...
1202

37ba983cf   Sakari Ailus   device property: ...
1203
  static bool acpi_fwnode_device_is_available(const struct fwnode_handle *fwnode)
2294b3af0   Sakari Ailus   device property: ...
1204
1205
1206
1207
1208
1209
  {
  	if (!is_acpi_device_node(fwnode))
  		return false;
  
  	return acpi_device_is_present(to_acpi_device_node(fwnode));
  }
37ba983cf   Sakari Ailus   device property: ...
1210
  static bool acpi_fwnode_property_present(const struct fwnode_handle *fwnode,
3708184af   Sakari Ailus   device property: ...
1211
1212
1213
1214
  					 const char *propname)
  {
  	return !acpi_node_prop_get(fwnode, propname, NULL);
  }
37ba983cf   Sakari Ailus   device property: ...
1215
1216
1217
1218
1219
  static int
  acpi_fwnode_property_read_int_array(const struct fwnode_handle *fwnode,
  				    const char *propname,
  				    unsigned int elem_size, void *val,
  				    size_t nval)
3708184af   Sakari Ailus   device property: ...
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
  {
  	enum dev_prop_type type;
  
  	switch (elem_size) {
  	case sizeof(u8):
  		type = DEV_PROP_U8;
  		break;
  	case sizeof(u16):
  		type = DEV_PROP_U16;
  		break;
  	case sizeof(u32):
  		type = DEV_PROP_U32;
  		break;
  	case sizeof(u64):
  		type = DEV_PROP_U64;
  		break;
  	default:
  		return -ENXIO;
  	}
  
  	return acpi_node_prop_read(fwnode, propname, type, val, nval);
  }
37ba983cf   Sakari Ailus   device property: ...
1242
1243
1244
1245
  static int
  acpi_fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
  				       const char *propname, const char **val,
  				       size_t nval)
3708184af   Sakari Ailus   device property: ...
1246
1247
1248
1249
  {
  	return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
  				   val, nval);
  }
3e3119d30   Sakari Ailus   device property: ...
1250
1251
1252
1253
1254
1255
  static int
  acpi_fwnode_get_reference_args(const struct fwnode_handle *fwnode,
  			       const char *prop, const char *nargs_prop,
  			       unsigned int args_count, unsigned int index,
  			       struct fwnode_reference_args *args)
  {
977d5ad39   Sakari Ailus   ACPI: Convert ACP...
1256
1257
  	return __acpi_node_get_property_reference(fwnode, prop, index,
  						  args_count, args);
3e3119d30   Sakari Ailus   device property: ...
1258
  }
bc0500c1e   Sakari Ailus   device property: ...
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
  static const char *acpi_fwnode_get_name(const struct fwnode_handle *fwnode)
  {
  	const struct acpi_device *adev;
  	struct fwnode_handle *parent;
  
  	/* Is this the root node? */
  	parent = fwnode_get_parent(fwnode);
  	if (!parent)
  		return "\\";
  
  	fwnode_handle_put(parent);
  
  	if (is_acpi_data_node(fwnode)) {
  		const struct acpi_data_node *dn = to_acpi_data_node(fwnode);
  
  		return dn->name;
  	}
  
  	adev = to_acpi_device_node(fwnode);
  	if (WARN_ON(!adev))
  		return NULL;
  
  	return acpi_device_bid(adev);
  }
e7e242bcc   Sakari Ailus   device property: ...
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
  static const char *
  acpi_fwnode_get_name_prefix(const struct fwnode_handle *fwnode)
  {
  	struct fwnode_handle *parent;
  
  	/* Is this the root node? */
  	parent = fwnode_get_parent(fwnode);
  	if (!parent)
  		return "";
  
  	/* Is this 2nd node from the root? */
  	parent = fwnode_get_next_parent(parent);
  	if (!parent)
  		return "";
  
  	fwnode_handle_put(parent);
  
  	/* ACPI device or data node. */
  	return ".";
  }
3b27d00e7   Sakari Ailus   device property: ...
1303
  static struct fwnode_handle *
37ba983cf   Sakari Ailus   device property: ...
1304
1305
1306
1307
1308
1309
  acpi_fwnode_get_parent(struct fwnode_handle *fwnode)
  {
  	return acpi_node_get_parent(fwnode);
  }
  
  static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
3b27d00e7   Sakari Ailus   device property: ...
1310
1311
1312
1313
1314
  					    struct fwnode_endpoint *endpoint)
  {
  	struct fwnode_handle *port_fwnode = fwnode_get_parent(fwnode);
  
  	endpoint->local_fwnode = fwnode;
18f1e58d1   Sakari Ailus   ACPI: property: U...
1315
1316
1317
1318
  	if (fwnode_property_read_u32(port_fwnode, "reg", &endpoint->port))
  		fwnode_property_read_u32(port_fwnode, "port", &endpoint->port);
  	if (fwnode_property_read_u32(fwnode, "reg", &endpoint->id))
  		fwnode_property_read_u32(fwnode, "endpoint", &endpoint->id);
3b27d00e7   Sakari Ailus   device property: ...
1319
1320
1321
  
  	return 0;
  }
67dcc26d2   Andy Shevchenko   device property: ...
1322
  static const void *
146b4dbb0   Sinan Kaya   ACPI: properties:...
1323
1324
1325
  acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
  				  const struct device *dev)
  {
29d5325a1   Andy Shevchenko   ACPI / bus: Renam...
1326
  	return acpi_device_get_match_data(dev);
146b4dbb0   Sinan Kaya   ACPI: properties:...
1327
  }
db3e50f32   Sakari Ailus   device property: ...
1328
1329
1330
  #define DECLARE_ACPI_FWNODE_OPS(ops) \
  	const struct fwnode_operations ops = {				\
  		.device_is_available = acpi_fwnode_device_is_available, \
146b4dbb0   Sinan Kaya   ACPI: properties:...
1331
  		.device_get_match_data = acpi_fwnode_device_get_match_data, \
db3e50f32   Sakari Ailus   device property: ...
1332
1333
1334
1335
1336
1337
1338
1339
  		.property_present = acpi_fwnode_property_present,	\
  		.property_read_int_array =				\
  			acpi_fwnode_property_read_int_array,		\
  		.property_read_string_array =				\
  			acpi_fwnode_property_read_string_array,		\
  		.get_parent = acpi_node_get_parent,			\
  		.get_next_child_node = acpi_get_next_subnode,		\
  		.get_named_child_node = acpi_fwnode_get_named_child_node, \
bc0500c1e   Sakari Ailus   device property: ...
1340
  		.get_name = acpi_fwnode_get_name,			\
e7e242bcc   Sakari Ailus   device property: ...
1341
  		.get_name_prefix = acpi_fwnode_get_name_prefix,		\
3e3119d30   Sakari Ailus   device property: ...
1342
  		.get_reference_args = acpi_fwnode_get_reference_args,	\
db3e50f32   Sakari Ailus   device property: ...
1343
  		.graph_get_next_endpoint =				\
0ef747863   Sakari Ailus   ACPI: property: M...
1344
  			acpi_graph_get_next_endpoint,			\
db3e50f32   Sakari Ailus   device property: ...
1345
  		.graph_get_remote_endpoint =				\
0ef747863   Sakari Ailus   ACPI: property: M...
1346
  			acpi_graph_get_remote_endpoint,			\
37ba983cf   Sakari Ailus   device property: ...
1347
  		.graph_get_port_parent = acpi_fwnode_get_parent,	\
db3e50f32   Sakari Ailus   device property: ...
1348
1349
1350
1351
1352
1353
1354
  		.graph_parse_endpoint = acpi_fwnode_graph_parse_endpoint, \
  	};								\
  	EXPORT_SYMBOL_GPL(ops)
  
  DECLARE_ACPI_FWNODE_OPS(acpi_device_fwnode_ops);
  DECLARE_ACPI_FWNODE_OPS(acpi_data_fwnode_ops);
  const struct fwnode_operations acpi_static_fwnode_ops;
9e987b70a   John Hubbard   ACPI / bus: Make ...
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
  
  bool is_acpi_device_node(const struct fwnode_handle *fwnode)
  {
  	return !IS_ERR_OR_NULL(fwnode) &&
  		fwnode->ops == &acpi_device_fwnode_ops;
  }
  EXPORT_SYMBOL(is_acpi_device_node);
  
  bool is_acpi_data_node(const struct fwnode_handle *fwnode)
  {
  	return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &acpi_data_fwnode_ops;
  }
  EXPORT_SYMBOL(is_acpi_data_node);