Skip to content

Commit 8765c5b

Browse files
committed
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 <[email protected]> Tested-by: Mika Westerberg <[email protected]>
1 parent 2b9c698 commit 8765c5b

File tree

1 file changed

+155
-94
lines changed

1 file changed

+155
-94
lines changed

drivers/acpi/scan.c

Lines changed: 155 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -114,76 +114,111 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
114114
return 0;
115115
}
116116

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+
*
118123
* Creates hid/cid(s) string needed for modalias and uevent
119124
* e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
120125
* char *modalias: "acpi:IBM0001:ACPI0001"
121126
* Return: 0: no _HID and no _CID
122127
* -EINVAL: output error
123128
* -ENOMEM: output is truncated
124129
*/
125-
static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
126-
int size)
130+
static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias,
131+
int size)
127132
{
128133
int len;
129134
int count;
130135
struct acpi_hardware_id *id;
131136

132-
if (list_empty(&acpi_dev->pnp.ids))
133-
return 0;
134-
135137
/*
136-
* If the device has PRP0001 we expose DT compatible modalias
137-
* instead in form of of:NnameTCcompatible.
138+
* Since we skip PRP0001 from the modalias below, 0 should be returned
139+
* if PRP0001 is the only ACPI/PNP ID in the device's list.
138140
*/
139-
if (acpi_dev->data.of_compatible) {
140-
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
141-
const union acpi_object *of_compatible, *obj;
142-
int i, nval;
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;
141+
count = 0;
142+
list_for_each_entry(id, &acpi_dev->pnp.ids, list)
143+
if (strcmp(id->id, "PRP0001"))
144+
count++;
175145

176-
list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
177-
count = snprintf(&modalias[len], size, "%s:", id->id);
178-
if (count < 0)
179-
return -EINVAL;
180-
if (count >= size)
181-
return -ENOMEM;
182-
len += count;
183-
size -= count;
184-
}
146+
if (!count)
147+
return 0;
148+
149+
len = snprintf(modalias, size, "acpi:");
150+
if (len <= 0)
151+
return len;
152+
153+
size -= len;
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;
185168
}
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+
*/
182+
static 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;
186190

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+
}
187222
modalias[len] = '\0';
188223
return len;
189224
}
@@ -236,61 +271,100 @@ static struct acpi_device *acpi_companion_match(const struct device *dev)
236271
return adev;
237272
}
238273

239-
/*
240-
* Creates uevent modalias field for ACPI enumerated devices.
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-
*/
245-
int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
274+
static int __acpi_device_uevent_modalias(struct acpi_device *adev,
275+
struct kobj_uevent_env *env)
246276
{
247277
int len;
248278

249-
if (!acpi_companion_match(dev))
279+
if (!adev)
250280
return -ENODEV;
251281

282+
if (list_empty(&adev->pnp.ids))
283+
return 0;
284+
252285
if (add_uevent_var(env, "MODALIAS="))
253286
return -ENOMEM;
254-
len = create_modalias(ACPI_COMPANION(dev), &env->buf[env->buflen - 1],
255-
sizeof(env->buf) - env->buflen);
256-
if (len <= 0)
287+
288+
len = create_pnp_modalias(adev, &env->buf[env->buflen - 1],
289+
sizeof(env->buf) - env->buflen);
290+
if (len < 0)
257291
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+
258305
env->buflen += len;
306+
259307
return 0;
260308
}
261-
EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
262309

263310
/*
264-
* Creates modalias sysfs attribute for ACPI enumerated devices.
311+
* Creates uevent modalias field for ACPI enumerated devices.
265312
* Because the other buses does not support ACPI HIDs & CIDs.
266313
* e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get:
267314
* "acpi:IBM0001:ACPI0001"
268315
*/
269-
int acpi_device_modalias(struct device *dev, char *buf, int size)
316+
int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
270317
{
271-
int len;
318+
return __acpi_device_uevent_modalias(acpi_companion_match(dev), env);
319+
}
320+
EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
321+
322+
static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size)
323+
{
324+
int len, count;
272325

273-
if (!acpi_companion_match(dev))
326+
if (!adev)
274327
return -ENODEV;
275328

276-
len = create_modalias(ACPI_COMPANION(dev), buf, size -1);
277-
if (len <= 0)
329+
if (list_empty(&adev->pnp.ids))
330+
return 0;
331+
332+
len = create_pnp_modalias(adev, buf, size - 1);
333+
if (len < 0) {
278334
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+
280350
return len;
281351
}
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+
*/
359+
int acpi_device_modalias(struct device *dev, char *buf, int size)
360+
{
361+
return __acpi_device_modalias(acpi_companion_match(dev), buf, size);
362+
}
282363
EXPORT_SYMBOL_GPL(acpi_device_modalias);
283364

284365
static ssize_t
285366
acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
286-
struct acpi_device *acpi_dev = to_acpi_device(dev);
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;
367+
return __acpi_device_modalias(to_acpi_device(dev), buf, 1024);
294368
}
295369
static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
296370

@@ -1046,20 +1120,7 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv)
10461120

10471121
static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
10481122
{
1049-
struct acpi_device *acpi_dev = to_acpi_device(dev);
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;
1123+
return __acpi_device_uevent_modalias(to_acpi_device(dev), env);
10631124
}
10641125

10651126
static void acpi_device_notify(acpi_handle handle, u32 event, void *data)

0 commit comments

Comments
 (0)