Skip to content

Commit e49bd2d

Browse files
zhang-ruilenb
authored andcommitted
ACPI: use PNPID:instance_no as bus_id of ACPI device
Previously we used the device name in the DSDT, but would crash upon encountering a duplicate. Also, exposing the DSDT device name to the user in a patch isn't a good idea, because it is arbitrary. After some discussion, we finally decided to use "PNPID:instance_no" as the bus_id of ACPI devices. Two attributes for each device are added at the same time, the full pathname in ACPI namespace and hardware_id if it has. NOTE: acpi_bus_id_list is used to keep the information of PNPID and instance number of the given PNPID. Loop the acpi_bus_id_list to find the instance_no of the same PNPID when register a device. If failed, i.e. we don't have a node with this PNPID, allocate one and link it to this list. NOTE: Now I don't take the memory free work in charge. If necessary, I can add a reference count in struct acpi_device_bus_id, and check the reference and when unregister a device, i.e. memory is freed when the reference count of a given PNPID is 0. Signed-off-by: Li Shaohua <shaohua.li@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
1 parent ae84333 commit e49bd2d

File tree

1 file changed

+109
-9
lines changed

1 file changed

+109
-9
lines changed

drivers/acpi/scan.c

Lines changed: 109 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@ extern struct acpi_device *acpi_root;
2121
#define ACPI_BUS_DEVICE_NAME "System Bus"
2222

2323
static LIST_HEAD(acpi_device_list);
24+
static LIST_HEAD(acpi_bus_id_list);
2425
DEFINE_SPINLOCK(acpi_device_lock);
2526
LIST_HEAD(acpi_wakeup_device_list);
2627

28+
struct acpi_device_bus_id{
29+
char bus_id[9];
30+
unsigned int instance_no;
31+
struct list_head node;
32+
};
2733
static int acpi_eject_operation(acpi_handle handle, int lockable)
2834
{
2935
struct acpi_object_list arg_list;
@@ -103,18 +109,61 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
103109

104110
static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
105111

106-
static void acpi_device_setup_files(struct acpi_device *dev)
112+
static ssize_t
113+
acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
114+
struct acpi_device *acpi_dev = to_acpi_device(dev);
115+
116+
return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id);
117+
}
118+
static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
119+
120+
static ssize_t
121+
acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
122+
struct acpi_device *acpi_dev = to_acpi_device(dev);
123+
struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
124+
int result;
125+
126+
result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
127+
if(result)
128+
goto end;
129+
130+
result = sprintf(buf, "%s\n", (char*)path.pointer);
131+
kfree(path.pointer);
132+
end:
133+
return result;
134+
}
135+
static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
136+
137+
static int acpi_device_setup_files(struct acpi_device *dev)
107138
{
108139
acpi_status status;
109140
acpi_handle temp;
141+
int result = 0;
110142

111143
/*
112-
* If device has _EJ0, 'eject' file is created that is used to trigger
113-
* hot-removal function from userland.
144+
* Devices gotten from FADT don't have a "path" attribute
114145
*/
146+
if(dev->handle) {
147+
result = device_create_file(&dev->dev, &dev_attr_path);
148+
if(result)
149+
goto end;
150+
}
151+
152+
if(dev->flags.hardware_id) {
153+
result = device_create_file(&dev->dev, &dev_attr_hid);
154+
if(result)
155+
goto end;
156+
}
157+
158+
/*
159+
* If device has _EJ0, 'eject' file is created that is used to trigger
160+
* hot-removal function from userland.
161+
*/
115162
status = acpi_get_handle(dev->handle, "_EJ0", &temp);
116163
if (ACPI_SUCCESS(status))
117-
device_create_file(&dev->dev, &dev_attr_eject);
164+
result = device_create_file(&dev->dev, &dev_attr_eject);
165+
end:
166+
return result;
118167
}
119168

120169
static void acpi_device_remove_files(struct acpi_device *dev)
@@ -129,6 +178,11 @@ static void acpi_device_remove_files(struct acpi_device *dev)
129178
status = acpi_get_handle(dev->handle, "_EJ0", &temp);
130179
if (ACPI_SUCCESS(status))
131180
device_remove_file(&dev->dev, &dev_attr_eject);
181+
182+
if(dev->flags.hardware_id)
183+
device_remove_file(&dev->dev, &dev_attr_hid);
184+
if(dev->handle)
185+
device_remove_file(&dev->dev, &dev_attr_path);
132186
}
133187
/* --------------------------------------------------------------------------
134188
ACPI Bus operations
@@ -260,9 +314,12 @@ static struct bus_type acpi_bus_type = {
260314
.uevent = acpi_device_uevent,
261315
};
262316

263-
static void acpi_device_register(struct acpi_device *device,
317+
static int acpi_device_register(struct acpi_device *device,
264318
struct acpi_device *parent)
265319
{
320+
int result;
321+
struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
322+
int found = 0;
266323
/*
267324
* Linkage
268325
* -------
@@ -273,7 +330,33 @@ static void acpi_device_register(struct acpi_device *device,
273330
INIT_LIST_HEAD(&device->g_list);
274331
INIT_LIST_HEAD(&device->wakeup_list);
275332

333+
new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
334+
if (!new_bus_id) {
335+
printk(KERN_ERR PREFIX "Memory allocation error\n");
336+
return -ENOMEM;
337+
}
338+
276339
spin_lock(&acpi_device_lock);
340+
/*
341+
* Find suitable bus_id and instance number in acpi_bus_id_list
342+
* If failed, create one and link it into acpi_bus_id_list
343+
*/
344+
list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
345+
if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "PNPIDNON")) {
346+
acpi_device_bus_id->instance_no ++;
347+
found = 1;
348+
kfree(new_bus_id);
349+
break;
350+
}
351+
}
352+
if(!found) {
353+
acpi_device_bus_id = new_bus_id;
354+
strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "PNPIDNON");
355+
acpi_device_bus_id->instance_no = 0;
356+
list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
357+
}
358+
sprintf(device->dev.bus_id, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
359+
277360
if (device->parent) {
278361
list_add_tail(&device->node, &device->parent->children);
279362
list_add_tail(&device->g_list, &device->parent->g_list);
@@ -287,12 +370,29 @@ static void acpi_device_register(struct acpi_device *device,
287370
device->dev.parent = &parent->dev;
288371
device->dev.bus = &acpi_bus_type;
289372
device_initialize(&device->dev);
290-
sprintf(device->dev.bus_id, "%s", device->pnp.bus_id);
291373
device->dev.release = &acpi_device_release;
292-
device_add(&device->dev);
374+
result = device_add(&device->dev);
375+
if(result) {
376+
printk("Error adding device %s", device->dev.bus_id);
377+
goto end;
378+
}
379+
380+
result = acpi_device_setup_files(device);
381+
if(result)
382+
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id));
293383

294-
acpi_device_setup_files(device);
295384
device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
385+
return 0;
386+
end:
387+
spin_lock(&acpi_device_lock);
388+
if (device->parent) {
389+
list_del(&device->node);
390+
list_del(&device->g_list);
391+
} else
392+
list_del(&device->g_list);
393+
list_del(&device->wakeup_list);
394+
spin_unlock(&acpi_device_lock);
395+
return result;
296396
}
297397

298398
static void acpi_device_unregister(struct acpi_device *device, int type)
@@ -1035,7 +1135,7 @@ acpi_add_single_object(struct acpi_device **child,
10351135

10361136
acpi_device_get_debug_info(device, handle, type);
10371137

1038-
acpi_device_register(device, parent);
1138+
result = acpi_device_register(device, parent);
10391139

10401140
end:
10411141
if (!result)

0 commit comments

Comments
 (0)