aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-04-12 18:29:36 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-04-12 18:29:36 -0400
commit8765c5ba19490c9167fe0c4e05c2dfdcc39873a3 (patch)
treed52a854777ef8f65e272277325e38886aa2644e8
parent2b9c698efa58bf7d9a0d3d3b28115cf9e55ca818 (diff)
ACPI / scan: Rework modalias creation when "compatible" is present
Currently, the ACPI modalias creation covers two mutually exclusive cases: If the PRP0001 device ID is present in the device's list of ACPI/PNP IDs and the "compatible" property is present in _DSD, the created modalias will follow the OF rules of modalias creation. Otherwise, ACPI rules are used. However, that is not really desirable, because the presence of PRP0001 in the list of device IDs generally does not preclude using other ACPI/PNP IDs with that device and those other IDs may be of higher priority. In those cases, the other IDs should take preference over PRP0001 and therefore they also should be present in the modalias. For this reason, rework the modalias creation for ACPI so that it shows both the ACPI-style and OF-style modalias strings if the device has a non-empty list of ACPI/PNP IDs (other than PRP0001) and a valid "compatible" property at the same time. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
-rw-r--r--drivers/acpi/scan.c249
1 files changed, 155 insertions, 94 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 8f3adf924e83..d2e3c3e3f9c9 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -114,7 +114,12 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
114 return 0; 114 return 0;
115} 115}
116 116
117/* 117/**
118 * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent
119 * @acpi_dev: ACPI device object.
120 * @modalias: Buffer to print into.
121 * @size: Size of the buffer.
122 *
118 * Creates hid/cid(s) string needed for modalias and uevent 123 * Creates hid/cid(s) string needed for modalias and uevent
119 * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: 124 * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
120 * char *modalias: "acpi:IBM0001:ACPI0001" 125 * char *modalias: "acpi:IBM0001:ACPI0001"
@@ -122,68 +127,98 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
122 * -EINVAL: output error 127 * -EINVAL: output error
123 * -ENOMEM: output is truncated 128 * -ENOMEM: output is truncated
124*/ 129*/
125static int create_modalias(struct acpi_device *acpi_dev, char *modalias, 130static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
126 int size) 131 int size)
127{ 132{
128 int len; 133 int len;
129 int count; 134 int count;
130 struct acpi_hardware_id *id; 135 struct acpi_hardware_id *id;
131 136
132 if (list_empty(&acpi_dev->pnp.ids))
133 return 0;
134
135 /* 137 /*
136 * If the device has PRP0001 we expose DT compatible modalias 138 * Since we skip PRP0001 from the modalias below, 0 should be returned
137 * instead in form of of:NnameTCcompatible. 139 * if PRP0001 is the only ACPI/PNP ID in the device's list.
138 */ 140 */
139 if (acpi_dev->data.of_compatible) { 141 count = 0;
140 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; 142 list_for_each_entry(id, &acpi_dev->pnp.ids, list)
141 const union acpi_object *of_compatible, *obj; 143 if (strcmp(id->id, "PRP0001"))
142 int i, nval; 144 count++;
143 char *c;
144
145 acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
146 /* DT strings are all in lower case */
147 for (c = buf.pointer; *c != '\0'; c++)
148 *c = tolower(*c);
149
150 len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
151 ACPI_FREE(buf.pointer);
152
153 of_compatible = acpi_dev->data.of_compatible;
154 if (of_compatible->type == ACPI_TYPE_PACKAGE) {
155 nval = of_compatible->package.count;
156 obj = of_compatible->package.elements;
157 } else { /* Must be ACPI_TYPE_STRING. */
158 nval = 1;
159 obj = of_compatible;
160 }
161 for (i = 0; i < nval; i++, obj++) {
162 count = snprintf(&modalias[len], size, "C%s",
163 obj->string.pointer);
164 if (count < 0)
165 return -EINVAL;
166 if (count >= size)
167 return -ENOMEM;
168
169 len += count;
170 size -= count;
171 }
172 } else {
173 len = snprintf(modalias, size, "acpi:");
174 size -= len;
175 145
176 list_for_each_entry(id, &acpi_dev->pnp.ids, list) { 146 if (!count)
177 count = snprintf(&modalias[len], size, "%s:", id->id); 147 return 0;
178 if (count < 0) 148
179 return -EINVAL; 149 len = snprintf(modalias, size, "acpi:");
180 if (count >= size) 150 if (len <= 0)
181 return -ENOMEM; 151 return len;
182 len += count; 152
183 size -= count; 153 size -= len;
184 } 154
155 list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
156 if (!strcmp(id->id, "PRP0001"))
157 continue;
158
159 count = snprintf(&modalias[len], size, "%s:", id->id);
160 if (count < 0)
161 return -EINVAL;
162
163 if (count >= size)
164 return -ENOMEM;
165
166 len += count;
167 size -= count;
185 } 168 }
169 modalias[len] = '\0';
170 return len;
171}
172
173/**
174 * create_of_modalias - Creates DT compatible string for modalias and uevent
175 * @acpi_dev: ACPI device object.
176 * @modalias: Buffer to print into.
177 * @size: Size of the buffer.
178 *
179 * Expose DT compatible modalias as of:NnameTCcompatible. This function should
180 * only be called for devices having PRP0001 in their list of ACPI/PNP IDs.
181 */
182static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias,
183 int size)
184{
185 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
186 const union acpi_object *of_compatible, *obj;
187 int len, count;
188 int i, nval;
189 char *c;
186 190
191 acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
192 /* DT strings are all in lower case */
193 for (c = buf.pointer; *c != '\0'; c++)
194 *c = tolower(*c);
195
196 len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
197 ACPI_FREE(buf.pointer);
198
199 if (len <= 0)
200 return len;
201
202 of_compatible = acpi_dev->data.of_compatible;
203 if (of_compatible->type == ACPI_TYPE_PACKAGE) {
204 nval = of_compatible->package.count;
205 obj = of_compatible->package.elements;
206 } else { /* Must be ACPI_TYPE_STRING. */
207 nval = 1;
208 obj = of_compatible;
209 }
210 for (i = 0; i < nval; i++, obj++) {
211 count = snprintf(&modalias[len], size, "C%s",
212 obj->string.pointer);
213 if (count < 0)
214 return -EINVAL;
215
216 if (count >= size)
217 return -ENOMEM;
218
219 len += count;
220 size -= count;
221 }
187 modalias[len] = '\0'; 222 modalias[len] = '\0';
188 return len; 223 return len;
189} 224}
@@ -236,61 +271,100 @@ static struct acpi_device *acpi_companion_match(const struct device *dev)
236 return adev; 271 return adev;
237} 272}
238 273
239/* 274static int __acpi_device_uevent_modalias(struct acpi_device *adev,
240 * Creates uevent modalias field for ACPI enumerated devices. 275 struct kobj_uevent_env *env)
241 * Because the other buses does not support ACPI HIDs & CIDs.
242 * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
243 * "acpi:IBM0001:ACPI0001"
244 */
245int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
246{ 276{
247 int len; 277 int len;
248 278
249 if (!acpi_companion_match(dev)) 279 if (!adev)
250 return -ENODEV; 280 return -ENODEV;
251 281
282 if (list_empty(&adev->pnp.ids))
283 return 0;
284
252 if (add_uevent_var(env, "MODALIAS=")) 285 if (add_uevent_var(env, "MODALIAS="))
253 return -ENOMEM; 286 return -ENOMEM;
254 len = create_modalias(ACPI_COMPANION(dev), &env->buf[env->buflen - 1], 287
255 sizeof(env->buf) - env->buflen); 288 len = create_pnp_modalias(adev, &env->buf[env->buflen - 1],
256 if (len <= 0) 289 sizeof(env->buf) - env->buflen);
290 if (len < 0)
257 return len; 291 return len;
292
293 env->buflen += len;
294 if (!adev->data.of_compatible)
295 return 0;
296
297 if (len > 0 && add_uevent_var(env, "MODALIAS="))
298 return -ENOMEM;
299
300 len = create_of_modalias(adev, &env->buf[env->buflen - 1],
301 sizeof(env->buf) - env->buflen);
302 if (len < 0)
303 return len;
304
258 env->buflen += len; 305 env->buflen += len;
306
259 return 0; 307 return 0;
260} 308}
261EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
262 309
263/* 310/*
264 * Creates modalias sysfs attribute for ACPI enumerated devices. 311 * Creates uevent modalias field for ACPI enumerated devices.
265 * Because the other buses does not support ACPI HIDs & CIDs. 312 * Because the other buses does not support ACPI HIDs & CIDs.
266 * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: 313 * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
267 * "acpi:IBM0001:ACPI0001" 314 * "acpi:IBM0001:ACPI0001"
268 */ 315 */
269int acpi_device_modalias(struct device *dev, char *buf, int size) 316int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
270{ 317{
271 int len; 318 return __acpi_device_uevent_modalias(acpi_companion_match(dev), env);
319}
320EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
321
322static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size)
323{
324 int len, count;
272 325
273 if (!acpi_companion_match(dev)) 326 if (!adev)
274 return -ENODEV; 327 return -ENODEV;
275 328
276 len = create_modalias(ACPI_COMPANION(dev), buf, size -1); 329 if (list_empty(&adev->pnp.ids))
277 if (len <= 0) 330 return 0;
331
332 len = create_pnp_modalias(adev, buf, size - 1);
333 if (len < 0) {
278 return len; 334 return len;
279 buf[len++] = '\n'; 335 } else if (len > 0) {
336 buf[len++] = '\n';
337 size -= len;
338 }
339 if (!adev->data.of_compatible)
340 return len;
341
342 count = create_of_modalias(adev, buf + len, size - 1);
343 if (count < 0) {
344 return count;
345 } else if (count > 0) {
346 len += count;
347 buf[len++] = '\n';
348 }
349
280 return len; 350 return len;
281} 351}
352
353/*
354 * Creates modalias sysfs attribute for ACPI enumerated devices.
355 * Because the other buses does not support ACPI HIDs & CIDs.
356 * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
357 * "acpi:IBM0001:ACPI0001"
358 */
359int acpi_device_modalias(struct device *dev, char *buf, int size)
360{
361 return __acpi_device_modalias(acpi_companion_match(dev), buf, size);
362}
282EXPORT_SYMBOL_GPL(acpi_device_modalias); 363EXPORT_SYMBOL_GPL(acpi_device_modalias);
283 364
284static ssize_t 365static ssize_t
285acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { 366acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
286 struct acpi_device *acpi_dev = to_acpi_device(dev); 367 return __acpi_device_modalias(to_acpi_device(dev), buf, 1024);
287 int len;
288
289 len = create_modalias(acpi_dev, buf, 1024);
290 if (len <= 0)
291 return len;
292 buf[len++] = '\n';
293 return len;
294} 368}
295static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); 369static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
296 370
@@ -1046,20 +1120,7 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv)
1046 1120
1047static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) 1121static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
1048{ 1122{
1049 struct acpi_device *acpi_dev = to_acpi_device(dev); 1123 return __acpi_device_uevent_modalias(to_acpi_device(dev), env);
1050 int len;
1051
1052 if (list_empty(&acpi_dev->pnp.ids))
1053 return 0;
1054
1055 if (add_uevent_var(env, "MODALIAS="))
1056 return -ENOMEM;
1057 len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
1058 sizeof(env->buf) - env->buflen);
1059 if (len <= 0)
1060 return len;
1061 env->buflen += len;
1062 return 0;
1063} 1124}
1064 1125
1065static void acpi_device_notify(acpi_handle handle, u32 event, void *data) 1126static void acpi_device_notify(acpi_handle handle, u32 event, void *data)