summaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-12-12 14:48:18 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-12-12 14:48:18 -0500
commit80f1b3dea9d4262817b5510547b1313681669f66 (patch)
tree1a084972bb36a9a51d75ad6f68c41743bc11e0c8 /drivers/acpi
parentd2c2ba690180da366bdc5ca037c2d4f077bd5ffd (diff)
parentee39222d45839284f91e882df8a985e1af0f7e18 (diff)
Merge branch 'device-properties'
* device-properties: ACPI / property: Document usage rules for _DSD properties ACPI / property: Hierarchical properties support update
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/device_sysfs.c8
-rw-r--r--drivers/acpi/property.c125
2 files changed, 93 insertions, 40 deletions
diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c
index 7b2c48fde4e2..24418932612e 100644
--- a/drivers/acpi/device_sysfs.c
+++ b/drivers/acpi/device_sysfs.c
@@ -52,7 +52,7 @@ struct acpi_data_node_attr {
52 52
53static ssize_t data_node_show_path(struct acpi_data_node *dn, char *buf) 53static ssize_t data_node_show_path(struct acpi_data_node *dn, char *buf)
54{ 54{
55 return acpi_object_path(dn->handle, buf); 55 return dn->handle ? acpi_object_path(dn->handle, buf) : 0;
56} 56}
57 57
58DATA_NODE_ATTR(path); 58DATA_NODE_ATTR(path);
@@ -105,10 +105,10 @@ static void acpi_expose_nondev_subnodes(struct kobject *kobj,
105 init_completion(&dn->kobj_done); 105 init_completion(&dn->kobj_done);
106 ret = kobject_init_and_add(&dn->kobj, &acpi_data_node_ktype, 106 ret = kobject_init_and_add(&dn->kobj, &acpi_data_node_ktype,
107 kobj, "%s", dn->name); 107 kobj, "%s", dn->name);
108 if (ret) 108 if (!ret)
109 acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret);
110 else
111 acpi_expose_nondev_subnodes(&dn->kobj, &dn->data); 109 acpi_expose_nondev_subnodes(&dn->kobj, &dn->data);
110 else if (dn->handle)
111 acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret);
112 } 112 }
113} 113}
114 114
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 03f5ec11ab31..3afddcd834ef 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -41,14 +41,13 @@ static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
41static bool acpi_extract_properties(const union acpi_object *desc, 41static bool acpi_extract_properties(const union acpi_object *desc,
42 struct acpi_device_data *data); 42 struct acpi_device_data *data);
43 43
44static bool acpi_nondev_subnode_ok(acpi_handle scope, 44static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
45 const union acpi_object *link, 45 acpi_handle handle,
46 struct list_head *list) 46 const union acpi_object *link,
47 struct list_head *list)
47{ 48{
48 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
49 struct acpi_data_node *dn; 49 struct acpi_data_node *dn;
50 acpi_handle handle; 50 bool result;
51 acpi_status status;
52 51
53 dn = kzalloc(sizeof(*dn), GFP_KERNEL); 52 dn = kzalloc(sizeof(*dn), GFP_KERNEL);
54 if (!dn) 53 if (!dn)
@@ -58,43 +57,75 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope,
58 dn->fwnode.type = FWNODE_ACPI_DATA; 57 dn->fwnode.type = FWNODE_ACPI_DATA;
59 INIT_LIST_HEAD(&dn->data.subnodes); 58 INIT_LIST_HEAD(&dn->data.subnodes);
60 59
61 status = acpi_get_handle(scope, link->package.elements[1].string.pointer, 60 result = acpi_extract_properties(desc, &dn->data);
62 &handle);
63 if (ACPI_FAILURE(status))
64 goto fail;
65 61
66 status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf, 62 if (handle) {
67 ACPI_TYPE_PACKAGE); 63 acpi_handle scope;
68 if (ACPI_FAILURE(status)) 64 acpi_status status;
69 goto fail;
70 65
71 if (acpi_extract_properties(buf.pointer, &dn->data)) 66 /*
72 dn->handle = handle; 67 * The scope for the subnode object lookup is the one of the
68 * namespace node (device) containing the object that has
69 * returned the package. That is, it's the scope of that
70 * object's parent.
71 */
72 status = acpi_get_parent(handle, &scope);
73 if (ACPI_SUCCESS(status)
74 && acpi_enumerate_nondev_subnodes(scope, desc, &dn->data))
75 result = true;
76 } else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data)) {
77 result = true;
78 }
73 79
74 /* 80 if (result) {
75 * The scope for the subnode object lookup is the one of the namespace
76 * node (device) containing the object that has returned the package.
77 * That is, it's the scope of that object's parent.
78 */
79 status = acpi_get_parent(handle, &scope);
80 if (ACPI_SUCCESS(status)
81 && acpi_enumerate_nondev_subnodes(scope, buf.pointer, &dn->data))
82 dn->handle = handle; 81 dn->handle = handle;
83 82 dn->data.pointer = desc;
84 if (dn->handle) {
85 dn->data.pointer = buf.pointer;
86 list_add_tail(&dn->sibling, list); 83 list_add_tail(&dn->sibling, list);
87 return true; 84 return true;
88 } 85 }
89 86
87 kfree(dn);
90 acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n"); 88 acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
89 return false;
90}
91
92static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
93 const union acpi_object *link,
94 struct list_head *list)
95{
96 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
97 acpi_status status;
98
99 status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
100 ACPI_TYPE_PACKAGE);
101 if (ACPI_FAILURE(status))
102 return false;
103
104 if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list))
105 return true;
91 106
92 fail:
93 ACPI_FREE(buf.pointer); 107 ACPI_FREE(buf.pointer);
94 kfree(dn);
95 return false; 108 return false;
96} 109}
97 110
111static bool acpi_nondev_subnode_ok(acpi_handle scope,
112 const union acpi_object *link,
113 struct list_head *list)
114{
115 acpi_handle handle;
116 acpi_status status;
117
118 if (!scope)
119 return false;
120
121 status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
122 &handle);
123 if (ACPI_FAILURE(status))
124 return false;
125
126 return acpi_nondev_subnode_data_ok(handle, link, list);
127}
128
98static int acpi_add_nondev_subnodes(acpi_handle scope, 129static int acpi_add_nondev_subnodes(acpi_handle scope,
99 const union acpi_object *links, 130 const union acpi_object *links,
100 struct list_head *list) 131 struct list_head *list)
@@ -103,15 +134,37 @@ static int acpi_add_nondev_subnodes(acpi_handle scope,
103 int i; 134 int i;
104 135
105 for (i = 0; i < links->package.count; i++) { 136 for (i = 0; i < links->package.count; i++) {
106 const union acpi_object *link; 137 const union acpi_object *link, *desc;
138 acpi_handle handle;
139 bool result;
107 140
108 link = &links->package.elements[i]; 141 link = &links->package.elements[i];
109 /* Only two elements allowed, both must be strings. */ 142 /* Only two elements allowed. */
110 if (link->package.count == 2 143 if (link->package.count != 2)
111 && link->package.elements[0].type == ACPI_TYPE_STRING 144 continue;
112 && link->package.elements[1].type == ACPI_TYPE_STRING 145
113 && acpi_nondev_subnode_ok(scope, link, list)) 146 /* The first one must be a string. */
114 ret = true; 147 if (link->package.elements[0].type != ACPI_TYPE_STRING)
148 continue;
149
150 /* The second one may be a string, a reference or a package. */
151 switch (link->package.elements[1].type) {
152 case ACPI_TYPE_STRING:
153 result = acpi_nondev_subnode_ok(scope, link, list);
154 break;
155 case ACPI_TYPE_LOCAL_REFERENCE:
156 handle = link->package.elements[1].reference.handle;
157 result = acpi_nondev_subnode_data_ok(handle, link, list);
158 break;
159 case ACPI_TYPE_PACKAGE:
160 desc = &link->package.elements[1];
161 result = acpi_nondev_subnode_extract(desc, NULL, link, list);
162 break;
163 default:
164 result = false;
165 break;
166 }
167 ret = ret || result;
115 } 168 }
116 169
117 return ret; 170 return ret;