aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Kconfig17
-rw-r--r--drivers/acpi/osl.c73
2 files changed, 86 insertions, 4 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index ccf6ea95f68c..0442ae153a24 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -274,6 +274,23 @@ config ACPI_CUSTOM_DSDT_FILE
274 Enter the full path name to the file which includes the AmlCode 274 Enter the full path name to the file which includes the AmlCode
275 declaration. 275 declaration.
276 276
277config ACPI_CUSTOM_DSDT_INITRD
278 bool "Read Custom DSDT from initramfs"
279 depends on BLK_DEV_INITRD
280 default n
281 help
282 The DSDT (Differentiated System Description Table) often needs to be
283 overridden because of broken BIOS implementations. If this feature is
284 activated you will be able to provide a customized DSDT by adding it
285 to your initramfs. If your mkinitrd tool does not support this feature
286 a script is provided in the documentation. For more details see
287 <file:Documentation/dsdt-initrd.txt> or <http://gaugusch.at/kernel.shtml>.
288 If there is no table found, it will fall-back to the custom DSDT
289 in-kernel (if activated) or to the DSDT from the BIOS.
290
291 Even if you do not need a new one at the moment, you may want to use a
292 better DSDT later. It is safe to say Y here.
293
277config ACPI_BLACKLIST_YEAR 294config ACPI_BLACKLIST_YEAR
278 int "Disable ACPI for systems before Jan 1st this year" if X86_32 295 int "Disable ACPI for systems before Jan 1st this year" if X86_32
279 default 0 296 default 0
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index e53fb516f9d4..131936e7ff17 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -312,6 +312,66 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
312 return AE_OK; 312 return AE_OK;
313} 313}
314 314
315#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
316struct acpi_table_header *acpi_find_dsdt_initrd(void)
317{
318 struct file *firmware_file;
319 mm_segment_t oldfs;
320 unsigned long len, len2;
321 struct acpi_table_header *dsdt_buffer, *ret = NULL;
322 struct kstat stat;
323 char *ramfs_dsdt_name = "/DSDT.aml";
324
325 printk(KERN_INFO PREFIX "Looking for DSDT in initramfs... ");
326
327 /*
328 * Never do this at home, only the user-space is allowed to open a file.
329 * The clean way would be to use the firmware loader. But this code must be run
330 * before there is any userspace available. So we need a static/init firmware
331 * infrastructure, which doesn't exist yet...
332 */
333 if (vfs_stat(ramfs_dsdt_name, &stat) < 0) {
334 printk("not found.\n");
335 return ret;
336 }
337
338 len = stat.size;
339 /* check especially against empty files */
340 if (len <= 4) {
341 printk("error, file is too small: only %lu bytes.\n", len);
342 return ret;
343 }
344
345 firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0);
346 if (IS_ERR(firmware_file)) {
347 printk("error, could not open file %s.\n", ramfs_dsdt_name);
348 return ret;
349 }
350
351 dsdt_buffer = ACPI_ALLOCATE(len);
352 if (!dsdt_buffer) {
353 printk("error when allocating %lu bytes of memory.\n", len);
354 goto err;
355 }
356
357 oldfs = get_fs();
358 set_fs(KERNEL_DS);
359 len2 = vfs_read(firmware_file, (char __user *)dsdt_buffer, len, &firmware_file->f_pos);
360 set_fs(oldfs);
361 if (len2 < len) {
362 printk("error trying to read %lu bytes from %s.\n", len, ramfs_dsdt_name);
363 ACPI_FREE(dsdt_buffer);
364 goto err;
365 }
366
367 printk("successfully read %lu bytes from %s.\n", len, ramfs_dsdt_name);
368 ret = dsdt_buffer;
369err:
370 filp_close(firmware_file, NULL);
371 return ret;
372}
373#endif
374
315acpi_status 375acpi_status
316acpi_os_table_override(struct acpi_table_header * existing_table, 376acpi_os_table_override(struct acpi_table_header * existing_table,
317 struct acpi_table_header ** new_table) 377 struct acpi_table_header ** new_table)
@@ -319,13 +379,18 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
319 if (!existing_table || !new_table) 379 if (!existing_table || !new_table)
320 return AE_BAD_PARAMETER; 380 return AE_BAD_PARAMETER;
321 381
382 *new_table = NULL;
383
322#ifdef CONFIG_ACPI_CUSTOM_DSDT 384#ifdef CONFIG_ACPI_CUSTOM_DSDT
323 if (strncmp(existing_table->signature, "DSDT", 4) == 0) 385 if (strncmp(existing_table->signature, "DSDT", 4) == 0)
324 *new_table = (struct acpi_table_header *)AmlCode; 386 *new_table = (struct acpi_table_header *)AmlCode;
325 else 387#endif
326 *new_table = NULL; 388#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
327#else 389 if (strncmp(existing_table->signature, "DSDT", 4) == 0) {
328 *new_table = NULL; 390 struct acpi_table_header *initrd_table = acpi_find_dsdt_initrd();
391 if (initrd_table)
392 *new_table = initrd_table;
393 }
329#endif 394#endif
330 return AE_OK; 395 return AE_OK;
331} 396}