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.c97
2 files changed, 108 insertions, 6 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index d141bdb3a7d4..7ef172c2a1d6 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -276,8 +276,10 @@ config ACPI_CUSTOM_DSDT
276 depends on !STANDALONE 276 depends on !STANDALONE
277 default n 277 default n
278 help 278 help
279 This option is to load a custom ACPI DSDT 279 This option supports a custom DSDT by linking it into the kernel.
280 If you don't know what that is, say N. 280 See Documentation/acpi/dsdt-override.txt
281
282 If unsure, say N.
281 283
282config ACPI_CUSTOM_DSDT_FILE 284config ACPI_CUSTOM_DSDT_FILE
283 string "Custom DSDT Table file to include" 285 string "Custom DSDT Table file to include"
@@ -287,6 +289,17 @@ config ACPI_CUSTOM_DSDT_FILE
287 Enter the full path name to the file which includes the AmlCode 289 Enter the full path name to the file which includes the AmlCode
288 declaration. 290 declaration.
289 291
292config ACPI_CUSTOM_DSDT_INITRD
293 bool "Read Custom DSDT from initramfs"
294 depends on BLK_DEV_INITRD
295 default n
296 help
297 This option supports a custom DSDT by optionally loading it from initrd.
298 See Documentation/acpi/dsdt-override.txt
299
300 If you are not using this feature now, but may use it later,
301 it is safe to say Y here.
302
290config ACPI_BLACKLIST_YEAR 303config ACPI_BLACKLIST_YEAR
291 int "Disable ACPI for systems before Jan 1st this year" if X86_32 304 int "Disable ACPI for systems before Jan 1st this year" if X86_32
292 default 0 305 default 0
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index c2c585366fa6..27ccd68b8f46 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -91,6 +91,10 @@ static DEFINE_SPINLOCK(acpi_res_lock);
91#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ 91#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
92static char osi_additional_string[OSI_STRING_LENGTH_MAX]; 92static char osi_additional_string[OSI_STRING_LENGTH_MAX];
93 93
94#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
95static int acpi_no_initrd_override;
96#endif
97
94/* 98/*
95 * "Ode to _OSI(Linux)" 99 * "Ode to _OSI(Linux)"
96 * 100 *
@@ -329,6 +333,67 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
329 return AE_OK; 333 return AE_OK;
330} 334}
331 335
336#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
337struct acpi_table_header *acpi_find_dsdt_initrd(void)
338{
339 struct file *firmware_file;
340 mm_segment_t oldfs;
341 unsigned long len, len2;
342 struct acpi_table_header *dsdt_buffer, *ret = NULL;
343 struct kstat stat;
344 char *ramfs_dsdt_name = "/DSDT.aml";
345
346 printk(KERN_INFO PREFIX "Checking initramfs for custom DSDT");
347
348 /*
349 * Never do this at home, only the user-space is allowed to open a file.
350 * The clean way would be to use the firmware loader.
351 * But this code must be run before there is any userspace available.
352 * A static/init firmware infrastructure doesn't exist yet...
353 */
354 if (vfs_stat(ramfs_dsdt_name, &stat) < 0)
355 return ret;
356
357 len = stat.size;
358 /* check especially against empty files */
359 if (len <= 4) {
360 printk(KERN_ERR PREFIX "Failed: DSDT only %lu bytes.\n", len);
361 return ret;
362 }
363
364 firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0);
365 if (IS_ERR(firmware_file)) {
366 printk(KERN_ERR PREFIX "Failed to open %s.\n", ramfs_dsdt_name);
367 return ret;
368 }
369
370 dsdt_buffer = kmalloc(len, GFP_ATOMIC);
371 if (!dsdt_buffer) {
372 printk(KERN_ERR PREFIX "Failed to allocate %lu bytes.\n", len);
373 goto err;
374 }
375
376 oldfs = get_fs();
377 set_fs(KERNEL_DS);
378 len2 = vfs_read(firmware_file, (char __user *)dsdt_buffer, len,
379 &firmware_file->f_pos);
380 set_fs(oldfs);
381 if (len2 < len) {
382 printk(KERN_ERR PREFIX "Failed to read %lu bytes from %s.\n",
383 len, ramfs_dsdt_name);
384 ACPI_FREE(dsdt_buffer);
385 goto err;
386 }
387
388 printk(KERN_INFO PREFIX "Found %lu byte DSDT in %s.\n",
389 len, ramfs_dsdt_name);
390 ret = dsdt_buffer;
391err:
392 filp_close(firmware_file, NULL);
393 return ret;
394}
395#endif
396
332acpi_status 397acpi_status
333acpi_os_table_override(struct acpi_table_header * existing_table, 398acpi_os_table_override(struct acpi_table_header * existing_table,
334 struct acpi_table_header ** new_table) 399 struct acpi_table_header ** new_table)
@@ -336,17 +401,41 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
336 if (!existing_table || !new_table) 401 if (!existing_table || !new_table)
337 return AE_BAD_PARAMETER; 402 return AE_BAD_PARAMETER;
338 403
404 *new_table = NULL;
405
339#ifdef CONFIG_ACPI_CUSTOM_DSDT 406#ifdef CONFIG_ACPI_CUSTOM_DSDT
340 if (strncmp(existing_table->signature, "DSDT", 4) == 0) 407 if (strncmp(existing_table->signature, "DSDT", 4) == 0)
341 *new_table = (struct acpi_table_header *)AmlCode; 408 *new_table = (struct acpi_table_header *)AmlCode;
342 else
343 *new_table = NULL;
344#else
345 *new_table = NULL;
346#endif 409#endif
410#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
411 if ((strncmp(existing_table->signature, "DSDT", 4) == 0) &&
412 !acpi_no_initrd_override) {
413 struct acpi_table_header *initrd_table;
414
415 initrd_table = acpi_find_dsdt_initrd();
416 if (initrd_table)
417 *new_table = initrd_table;
418 }
419#endif
420 if (*new_table != NULL) {
421 printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], "
422 "this is unsafe: tainting kernel\n",
423 existing_table->signature,
424 existing_table->oem_table_id);
425 add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
426 }
347 return AE_OK; 427 return AE_OK;
348} 428}
349 429
430#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
431int __init acpi_no_initrd_override_setup(char *s)
432{
433 acpi_no_initrd_override = 1;
434 return 1;
435}
436__setup("acpi_no_initrd_override", acpi_no_initrd_override_setup);
437#endif
438
350static irqreturn_t acpi_irq(int irq, void *dev_id) 439static irqreturn_t acpi_irq(int irq, void *dev_id)
351{ 440{
352 u32 handled; 441 u32 handled;