forked from KolibriOS/kolibrios
9a7d86dfc0
git-svn-id: svn://kolibrios.org@6595 a494cfbc-eb01-0410-851d-a64ba20cac60
632 lines
15 KiB
C
632 lines
15 KiB
C
|
|
#include <syscall.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/ktime.h>
|
|
#include <linux/acpi.h>
|
|
#include <linux/dmi.h>
|
|
|
|
|
|
#define PREFIX "ACPI: "
|
|
|
|
int sbf_port __initdata = -1;
|
|
|
|
static bool acpi_os_initialized;
|
|
|
|
|
|
u32 __attribute__((externally_visible)) drvEntry(int action, char *cmdline)
|
|
{
|
|
int result;
|
|
|
|
if(action != 1)
|
|
return 0;
|
|
|
|
if( !dbg_open("/tmp0/1/acpi.log") )
|
|
{
|
|
printk("Can't open /tmp0/1/acpi.log\nExit\n");
|
|
return 0;
|
|
}
|
|
|
|
dmi_scan_machine();
|
|
|
|
acpi_boot_table_init();
|
|
|
|
early_acpi_boot_init();
|
|
|
|
acpi_noirq_set();
|
|
|
|
acpi_early_init();
|
|
|
|
|
|
// if (acpi_disabled) {
|
|
// printk(KERN_INFO PREFIX "Interpreter disabled.\n");
|
|
// return -ENODEV;
|
|
// }
|
|
|
|
// init_acpi_device_notify();
|
|
// result = acpi_bus_init();
|
|
// if (result) {
|
|
// disable_acpi();
|
|
// return result;
|
|
// }
|
|
|
|
// pci_mmcfg_late_init();
|
|
// acpi_scan_init();
|
|
// acpi_ec_init();
|
|
// acpi_debugfs_init();
|
|
// acpi_sleep_proc_init();
|
|
// acpi_wakeup_device_init();
|
|
|
|
dbgprintf("module loaded\n");
|
|
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
#define PREFIX "ACPI: "
|
|
|
|
u32 IMPORT AcpiGetRootPtr(void)__asm__("AcpiGetRootPtr");
|
|
|
|
acpi_physical_address __init acpi_os_get_root_pointer(void)
|
|
{
|
|
return AcpiGetRootPtr();
|
|
}
|
|
|
|
void* acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
|
|
{
|
|
return (void *)MapIoMem((addr_t)phys, size, PG_SW);
|
|
|
|
}
|
|
|
|
void acpi_os_unmap_memory(void *virt, acpi_size size)
|
|
{
|
|
u32 ptr = (u32)virt;
|
|
ptr &= 0xFFFFF000;
|
|
|
|
return FreeKernelSpace((void*)ptr);
|
|
}
|
|
|
|
void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
|
|
{
|
|
acpi_os_unmap_memory(virt, size);
|
|
}
|
|
|
|
|
|
int acpi_os_map_generic_address(struct acpi_generic_address *gas)
|
|
{
|
|
addr_t addr;
|
|
void *virt;
|
|
|
|
if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
|
|
return 0;
|
|
|
|
addr = (addr_t)gas->address;
|
|
|
|
if (!addr || !gas->bit_width)
|
|
return -EINVAL;
|
|
|
|
virt = (void *)MapIoMem(addr, gas->bit_width / 8, PG_SW);
|
|
if (!virt)
|
|
return -EIO;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void acpi_os_printf(const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
acpi_os_vprintf(fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
void acpi_os_vprintf(const char *fmt, va_list args)
|
|
{
|
|
static char buffer[512];
|
|
|
|
vsprintf(buffer, fmt, args);
|
|
|
|
#ifdef ENABLE_DEBUGGER
|
|
if (acpi_in_debugger) {
|
|
kdb_printf("%s", buffer);
|
|
} else {
|
|
printk("%s", buffer);
|
|
}
|
|
#else
|
|
printk("%s", buffer);
|
|
#endif
|
|
}
|
|
|
|
|
|
static void acpi_table_taint(struct acpi_table_header *table)
|
|
{
|
|
pr_warn(PREFIX
|
|
"Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n",
|
|
table->signature, table->oem_table_id);
|
|
add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
|
|
}
|
|
|
|
|
|
|
|
|
|
acpi_status
|
|
acpi_os_table_override(struct acpi_table_header * existing_table,
|
|
struct acpi_table_header ** new_table)
|
|
{
|
|
if (!existing_table || !new_table)
|
|
return AE_BAD_PARAMETER;
|
|
|
|
*new_table = NULL;
|
|
|
|
#ifdef CONFIG_ACPI_CUSTOM_DSDT
|
|
if (strncmp(existing_table->signature, "DSDT", 4) == 0)
|
|
*new_table = (struct acpi_table_header *)AmlCode;
|
|
#endif
|
|
if (*new_table != NULL)
|
|
acpi_table_taint(existing_table);
|
|
return AE_OK;
|
|
}
|
|
|
|
acpi_status
|
|
acpi_os_physical_table_override(struct acpi_table_header *existing_table,
|
|
acpi_physical_address *address,
|
|
u32 *table_length)
|
|
{
|
|
#ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE
|
|
*table_length = 0;
|
|
*address = 0;
|
|
return AE_OK;
|
|
#else
|
|
int table_offset = 0;
|
|
struct acpi_table_header *table;
|
|
|
|
*table_length = 0;
|
|
*address = 0;
|
|
|
|
if (!acpi_tables_addr)
|
|
return AE_OK;
|
|
|
|
do {
|
|
if (table_offset + ACPI_HEADER_SIZE > all_tables_size) {
|
|
WARN_ON(1);
|
|
return AE_OK;
|
|
}
|
|
|
|
table = acpi_os_map_memory(acpi_tables_addr + table_offset,
|
|
ACPI_HEADER_SIZE);
|
|
|
|
if (table_offset + table->length > all_tables_size) {
|
|
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
|
|
WARN_ON(1);
|
|
return AE_OK;
|
|
}
|
|
|
|
table_offset += table->length;
|
|
|
|
if (memcmp(existing_table->signature, table->signature, 4)) {
|
|
acpi_os_unmap_memory(table,
|
|
ACPI_HEADER_SIZE);
|
|
continue;
|
|
}
|
|
|
|
/* Only override tables with matching oem id */
|
|
if (memcmp(table->oem_table_id, existing_table->oem_table_id,
|
|
ACPI_OEM_TABLE_ID_SIZE)) {
|
|
acpi_os_unmap_memory(table,
|
|
ACPI_HEADER_SIZE);
|
|
continue;
|
|
}
|
|
|
|
table_offset -= table->length;
|
|
*table_length = table->length;
|
|
acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
|
|
*address = acpi_tables_addr + table_offset;
|
|
break;
|
|
} while (table_offset + ACPI_HEADER_SIZE < all_tables_size);
|
|
|
|
if (*address != 0)
|
|
acpi_table_taint(existing_table);
|
|
return AE_OK;
|
|
#endif
|
|
}
|
|
|
|
|
|
static struct osi_linux {
|
|
unsigned int enable:1;
|
|
unsigned int dmi:1;
|
|
unsigned int cmdline:1;
|
|
unsigned int default_disabling:1;
|
|
|
|
} osi_linux = {0, 0, 0, 0};
|
|
|
|
#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
|
|
#define OSI_STRING_ENTRIES_MAX 16 /* arbitrary */
|
|
|
|
struct osi_setup_entry {
|
|
char string[OSI_STRING_LENGTH_MAX];
|
|
bool enable;
|
|
};
|
|
|
|
static struct osi_setup_entry
|
|
osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = {
|
|
{"Module Device", true},
|
|
{"Processor Device", true},
|
|
{"3.0 _SCP Extensions", true},
|
|
{"Processor Aggregator Device", true},
|
|
};
|
|
void __init acpi_osi_setup(char *str)
|
|
{
|
|
struct osi_setup_entry *osi;
|
|
bool enable = true;
|
|
int i;
|
|
|
|
if (!acpi_gbl_create_osi_method)
|
|
return;
|
|
|
|
if (str == NULL || *str == '\0') {
|
|
printk(KERN_INFO PREFIX "_OSI method disabled\n");
|
|
acpi_gbl_create_osi_method = FALSE;
|
|
return;
|
|
}
|
|
|
|
if (*str == '!') {
|
|
str++;
|
|
if (*str == '\0') {
|
|
osi_linux.default_disabling = 1;
|
|
return;
|
|
} else if (*str == '*') {
|
|
acpi_update_interfaces(ACPI_DISABLE_ALL_STRINGS);
|
|
for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
|
|
osi = &osi_setup_entries[i];
|
|
osi->enable = false;
|
|
}
|
|
return;
|
|
}
|
|
enable = false;
|
|
}
|
|
|
|
for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
|
|
osi = &osi_setup_entries[i];
|
|
if (!strcmp(osi->string, str)) {
|
|
osi->enable = enable;
|
|
break;
|
|
} else if (osi->string[0] == '\0') {
|
|
osi->enable = enable;
|
|
strncpy(osi->string, str, OSI_STRING_LENGTH_MAX);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void __init set_osi_linux(unsigned int enable)
|
|
{
|
|
if (osi_linux.enable != enable)
|
|
osi_linux.enable = enable;
|
|
|
|
if (osi_linux.enable)
|
|
acpi_osi_setup("Linux");
|
|
else
|
|
acpi_osi_setup("!Linux");
|
|
|
|
return;
|
|
}
|
|
|
|
void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
|
|
{
|
|
printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
|
|
|
|
if (enable == -1)
|
|
return;
|
|
|
|
osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */
|
|
set_osi_linux(enable);
|
|
|
|
return;
|
|
}
|
|
|
|
acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
|
|
{
|
|
void *sem = (void*)handle;
|
|
|
|
if (!acpi_os_initialized)
|
|
return AE_OK;
|
|
|
|
if (!sem || (units < 1))
|
|
return AE_BAD_PARAMETER;
|
|
|
|
if (units > 1)
|
|
return AE_SUPPORT;
|
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n",
|
|
handle, units, timeout));
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
|
|
{
|
|
void *sem = (void*)handle;
|
|
|
|
if (!acpi_os_initialized)
|
|
return AE_OK;
|
|
|
|
if (!sem || (units < 1))
|
|
return AE_BAD_PARAMETER;
|
|
|
|
if (units > 1)
|
|
return AE_SUPPORT;
|
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle,
|
|
units));
|
|
|
|
// up(sem);
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
|
|
acpi_status __init acpi_os_initialize(void)
|
|
{
|
|
// acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
|
|
// acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block);
|
|
// acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block);
|
|
// acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block);
|
|
if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) {
|
|
/*
|
|
* Use acpi_os_map_generic_address to pre-map the reset
|
|
* register if it's in system memory.
|
|
*/
|
|
int rv;
|
|
|
|
rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register);
|
|
pr_debug(PREFIX "%s: map reset_reg status %d\n", __func__, rv);
|
|
}
|
|
acpi_os_initialized = true;
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
acpi_status __init acpi_os_initialize1(void)
|
|
{
|
|
// kacpid_wq = alloc_workqueue("kacpid", 0, 1);
|
|
// kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
|
|
// kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);
|
|
// BUG_ON(!kacpid_wq);
|
|
// BUG_ON(!kacpi_notify_wq);
|
|
// BUG_ON(!kacpi_hotplug_wq);
|
|
// acpi_install_interface_handler(acpi_osi_handler);
|
|
// acpi_osi_setup_late();
|
|
return AE_OK;
|
|
}
|
|
|
|
|
|
acpi_status acpi_os_delete_semaphore(acpi_handle handle)
|
|
{
|
|
// void *sem = (void*)handle;
|
|
|
|
// if (!sem)
|
|
// return AE_BAD_PARAMETER;
|
|
|
|
// kfree(sem);
|
|
// sem = NULL;
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
acpi_status acpi_os_create_semaphore(u32 max_units,
|
|
u32 initial_units, acpi_handle * out_handle)
|
|
{
|
|
*out_handle = (acpi_handle) 1;
|
|
return (AE_OK);
|
|
}
|
|
|
|
acpi_status
|
|
acpi_os_create_mutex(acpi_handle * handle)
|
|
{
|
|
struct mutex *mtx = NULL;
|
|
|
|
mtx = kzalloc(sizeof(struct mutex),0);
|
|
|
|
if (!mtx)
|
|
return AE_NO_MEMORY;
|
|
|
|
mutex_init(mtx);
|
|
|
|
*handle = (acpi_handle *) mtx;
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
void acpi_os_release_mutex(acpi_mutex handle)
|
|
{
|
|
struct mutex *mtx = (struct mutex*)handle;
|
|
|
|
if (!acpi_os_initialized)
|
|
return;
|
|
|
|
mutex_unlock(mtx);
|
|
}
|
|
|
|
acpi_status acpi_os_acquire_mutex(acpi_mutex handle, u16 timeout)
|
|
{
|
|
struct mutex *mtx = (struct mutex*)handle;
|
|
|
|
if (!acpi_os_initialized)
|
|
return AE_OK;
|
|
|
|
mutex_lock(mtx);
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
void acpi_os_delete_mutex(acpi_mutex handle)
|
|
{
|
|
struct mutex *mtx = (struct mutex*)handle;
|
|
|
|
kfree(mtx);
|
|
};
|
|
|
|
acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp)
|
|
{
|
|
acpi_cpu_flags flags;
|
|
spin_lock_irqsave(lockp, flags);
|
|
return flags;
|
|
}
|
|
|
|
|
|
void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags)
|
|
{
|
|
spin_unlock_irqrestore(lockp, flags);
|
|
}
|
|
|
|
|
|
acpi_status acpi_os_signal(u32 function, void *info)
|
|
{
|
|
switch (function) {
|
|
case ACPI_SIGNAL_FATAL:
|
|
printk(KERN_ERR PREFIX "Fatal opcode executed\n");
|
|
break;
|
|
case ACPI_SIGNAL_BREAKPOINT:
|
|
/*
|
|
* AML Breakpoint
|
|
* ACPI spec. says to treat it as a NOP unless
|
|
* you are debugging. So if/when we integrate
|
|
* AML debugger into the kernel debugger its
|
|
* hook will go here. But until then it is
|
|
* not useful to print anything on breakpoints.
|
|
*/
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
void acpi_os_sleep(u64 ms)
|
|
{
|
|
msleep(ms);
|
|
}
|
|
|
|
void acpi_os_stall(u32 us)
|
|
{
|
|
while (us) {
|
|
u32 delay = 1000;
|
|
|
|
if (delay > us)
|
|
delay = us;
|
|
udelay(delay);
|
|
// touch_nmi_watchdog();
|
|
us -= delay;
|
|
}
|
|
}
|
|
|
|
void msleep(unsigned int msecs)
|
|
{
|
|
msecs /= 10;
|
|
if(!msecs) msecs = 1;
|
|
|
|
__asm__ __volatile__ (
|
|
"call *__imp__Delay"
|
|
::"b" (msecs));
|
|
__asm__ __volatile__ (
|
|
"":::"ebx");
|
|
|
|
};
|
|
|
|
acpi_status acpi_os_execute(acpi_execute_type type,
|
|
acpi_osd_exec_callback function, void *context)
|
|
{
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
|
|
u64 acpi_os_get_timer(void)
|
|
{
|
|
u64 time_ns = ktime_to_ns(ktime_get());
|
|
do_div(time_ns, 100);
|
|
return time_ns;
|
|
}
|
|
|
|
ktime_t ktime_get(void)
|
|
{
|
|
ktime_t t;
|
|
|
|
t.tv64 = GetClockNs();
|
|
|
|
return t;
|
|
}
|
|
|
|
void __delay(unsigned long loops)
|
|
{
|
|
asm volatile(
|
|
"test %0,%0\n"
|
|
"jz 3f\n"
|
|
"jmp 1f\n"
|
|
|
|
".align 16\n"
|
|
"1: jmp 2f\n"
|
|
|
|
".align 16\n"
|
|
"2: dec %0\n"
|
|
" jnz 2b\n"
|
|
"3: dec %0\n"
|
|
|
|
: /* we don't need output */
|
|
: "a" (loops)
|
|
);
|
|
}
|
|
|
|
|
|
inline void __const_udelay(unsigned long xloops)
|
|
{
|
|
int d0;
|
|
|
|
xloops *= 4;
|
|
asm("mull %%edx"
|
|
: "=d" (xloops), "=&a" (d0)
|
|
: "1" (xloops), ""
|
|
(loops_per_jiffy * (HZ/4)));
|
|
|
|
__delay(++xloops);
|
|
}
|
|
|
|
void __udelay(unsigned long usecs)
|
|
{
|
|
__const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */
|
|
}
|
|
|
|
|
|
#define acpi_rev_override false
|
|
|
|
#define ACPI_MAX_OVERRIDE_LEN 100
|
|
|
|
static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN];
|
|
|
|
|
|
acpi_status
|
|
acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
|
|
char **new_val)
|
|
{
|
|
if (!init_val || !new_val)
|
|
return AE_BAD_PARAMETER;
|
|
|
|
*new_val = NULL;
|
|
if (!memcmp(init_val->name, "_OS_", 4) && strlen(acpi_os_name)) {
|
|
printk(KERN_INFO PREFIX "Overriding _OS definition to '%s'\n",
|
|
acpi_os_name);
|
|
*new_val = acpi_os_name;
|
|
}
|
|
|
|
if (!memcmp(init_val->name, "_REV", 4) && acpi_rev_override) {
|
|
printk(KERN_INFO PREFIX "Overriding _REV return value to 5\n");
|
|
*new_val = (char *)5;
|
|
}
|
|
|
|
return AE_OK;
|
|
}
|
|
|