📄 osl.c
字号:
/* * acpi_osl.c - OS-dependent functions ($Revision: 83 $) * * Copyright (C) 2000 Andrew Henroid * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * */#include <linux/config.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/pci.h>#include <linux/smp_lock.h>#include <linux/interrupt.h>#include <linux/kmod.h>#include <linux/delay.h>#include <linux/workqueue.h>#include <linux/nmi.h>#include <acpi/acpi.h>#include <asm/io.h>#include <acpi/acpi_bus.h>#include <asm/uaccess.h>#include <linux/efi.h>#define _COMPONENT ACPI_OS_SERVICESACPI_MODULE_NAME ("osl")#define PREFIX "ACPI: "struct acpi_os_dpc{ acpi_osd_exec_callback function; void *context;};#ifdef CONFIG_ACPI_CUSTOM_DSDT#include CONFIG_ACPI_CUSTOM_DSDT_FILE#endif#ifdef ENABLE_DEBUGGER#include <linux/kdb.h>/* stuff for debugger support */int acpi_in_debugger;extern char line_buf[80];#endif /*ENABLE_DEBUGGER*/static unsigned int acpi_irq_irq;static acpi_osd_handler acpi_irq_handler;static void *acpi_irq_context;static struct workqueue_struct *kacpid_wq;acpi_statusacpi_os_initialize(void){ return AE_OK;}acpi_statusacpi_os_initialize1(void){ /* * Initialize PCI configuration space access, as we'll need to access * it while walking the namespace (bus 0 and root bridges w/ _BBNs). */#ifdef CONFIG_ACPI_PCI if (!raw_pci_ops) { printk(KERN_ERR PREFIX "Access to PCI configuration space unavailable\n"); return AE_NULL_ENTRY; }#endif kacpid_wq = create_singlethread_workqueue("kacpid"); BUG_ON(!kacpid_wq); return AE_OK;}acpi_statusacpi_os_terminate(void){ if (acpi_irq_handler) { acpi_os_remove_interrupt_handler(acpi_irq_irq, acpi_irq_handler); } destroy_workqueue(kacpid_wq); return AE_OK;}voidacpi_os_printf(const char *fmt,...){ va_list args; va_start(args, fmt); acpi_os_vprintf(fmt, args); va_end(args);}voidacpi_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}void *acpi_os_allocate(acpi_size size){ return kmalloc(size, GFP_KERNEL);}voidacpi_os_free(void *ptr){ kfree(ptr);}acpi_statusacpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr){ if (efi_enabled) { addr->pointer_type = ACPI_PHYSICAL_POINTER; if (efi.acpi20) addr->pointer.physical = (acpi_physical_address) virt_to_phys(efi.acpi20); else if (efi.acpi) addr->pointer.physical = (acpi_physical_address) virt_to_phys(efi.acpi); else { printk(KERN_ERR PREFIX "System description tables not found\n"); return AE_NOT_FOUND; } } else { if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) { printk(KERN_ERR PREFIX "System description tables not found\n"); return AE_NOT_FOUND; } } return AE_OK;}acpi_statusacpi_os_map_memory(acpi_physical_address phys, acpi_size size, void __iomem **virt){ if (efi_enabled) { if (EFI_MEMORY_WB & efi_mem_attributes(phys)) { *virt = (void __iomem *) phys_to_virt(phys); } else { *virt = ioremap(phys, size); } } else { if (phys > ULONG_MAX) { printk(KERN_ERR PREFIX "Cannot map memory that high\n"); return AE_BAD_PARAMETER; } /* * ioremap checks to ensure this is in reserved space */ *virt = ioremap((unsigned long) phys, size); } if (!*virt) return AE_NO_MEMORY; return AE_OK;}voidacpi_os_unmap_memory(void __iomem *virt, acpi_size size){ iounmap(virt);}acpi_statusacpi_os_get_physical_address(void *virt, acpi_physical_address *phys){ if(!phys || !virt) return AE_BAD_PARAMETER; *phys = virt_to_phys(virt); return AE_OK;}#define ACPI_MAX_OVERRIDE_LEN 100static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN];acpi_statusacpi_os_predefined_override (const struct acpi_predefined_names *init_val, acpi_string *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 %s\n", acpi_os_name); *new_val = acpi_os_name; } return AE_OK;}acpi_statusacpi_os_table_override (struct acpi_table_header *existing_table, struct acpi_table_header **new_table){ if (!existing_table || !new_table) return AE_BAD_PARAMETER;#ifdef CONFIG_ACPI_CUSTOM_DSDT if (strncmp(existing_table->signature, "DSDT", 4) == 0) *new_table = (struct acpi_table_header*)AmlCode; else *new_table = NULL;#else *new_table = NULL;#endif return AE_OK;}static irqreturn_tacpi_irq(int irq, void *dev_id, struct pt_regs *regs){ return (*acpi_irq_handler)(acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE;}acpi_statusacpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, void *context){ unsigned int irq; /* * Ignore the GSI from the core, and use the value in our copy of the * FADT. It may not be the same if an interrupt source override exists * for the SCI. */ gsi = acpi_fadt.sci_int; if (acpi_gsi_to_irq(gsi, &irq) < 0) { printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n", gsi); return AE_OK; } acpi_irq_handler = handler; acpi_irq_context = context; if (request_irq(irq, acpi_irq, SA_SHIRQ, "acpi", acpi_irq)) { printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); return AE_NOT_ACQUIRED; } acpi_irq_irq = irq; return AE_OK;}acpi_statusacpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler){ if (irq) { free_irq(irq, acpi_irq); acpi_irq_handler = NULL; acpi_irq_irq = 0; } return AE_OK;}/* * Running in interpreter thread context, safe to sleep */voidacpi_os_sleep(u32 sec, u32 ms){ current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ * sec + (ms * HZ) / 1000);}voidacpi_os_stall(u32 us){ while (us) { u32 delay = 1000; if (delay > us) delay = us; udelay(delay); touch_nmi_watchdog(); us -= delay; }}acpi_statusacpi_os_read_port( acpi_io_address port, u32 *value, u32 width){ u32 dummy; if (!value) value = &dummy; switch (width) { case 8: *(u8*) value = inb(port); break; case 16: *(u16*) value = inw(port); break; case 32: *(u32*) value = inl(port); break; default: BUG(); } return AE_OK;}acpi_statusacpi_os_write_port( acpi_io_address port, u32 value, u32 width){ switch (width) { case 8: outb(value, port); break; case 16: outw(value, port); break; case 32: outl(value, port); break; default: BUG(); } return AE_OK;}acpi_statusacpi_os_read_memory( acpi_physical_address phys_addr, u32 *value, u32 width){ u32 dummy; void __iomem *virt_addr; int iomem = 0; if (efi_enabled) { if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) { /* HACK ALERT! We can use readb/w/l on real memory too.. */ virt_addr = (void __iomem *) phys_to_virt(phys_addr); } else { iomem = 1; virt_addr = ioremap(phys_addr, width); } } else virt_addr = (void __iomem *) phys_to_virt(phys_addr); if (!value) value = &dummy; switch (width) { case 8: *(u8*) value = readb(virt_addr); break; case 16: *(u16*) value = readw(virt_addr); break; case 32: *(u32*) value = readl(virt_addr); break; default: BUG(); } if (efi_enabled) { if (iomem) iounmap(virt_addr); } return AE_OK;}acpi_statusacpi_os_write_memory( acpi_physical_address phys_addr, u32 value, u32 width){ void __iomem *virt_addr; int iomem = 0; if (efi_enabled) { if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) { /* HACK ALERT! We can use writeb/w/l on real memory too */ virt_addr = (void __iomem *) phys_to_virt(phys_addr); } else { iomem = 1; virt_addr = ioremap(phys_addr, width); } } else virt_addr = (void __iomem *) phys_to_virt(phys_addr); switch (width) { case 8: writeb(value, virt_addr); break; case 16: writew(value, virt_addr); break; case 32: writel(value, virt_addr); break; default: BUG(); } if (iomem) iounmap(virt_addr); return AE_OK;}#ifdef CONFIG_ACPI_PCIacpi_statusacpi_os_read_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, void *value, u32 width){ int result, size; if (!value) return AE_BAD_PARAMETER; switch (width) { case 8: size = 1; break; case 16: size = 2; break; case 32: size = 4; break; default: return AE_ERROR; } BUG_ON(!raw_pci_ops); result = raw_pci_ops->read(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, value); return (result ? AE_ERROR : AE_OK);}acpi_statusacpi_os_write_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, acpi_integer value, u32 width){ int result, size; switch (width) { case 8: size = 1; break; case 16: size = 2; break; case 32: size = 4; break; default: return AE_ERROR; } BUG_ON(!raw_pci_ops); result = raw_pci_ops->write(pci_id->segment, pci_id->bus, PCI_DEVFN(pci_id->device, pci_id->function), reg, size, value); return (result ? AE_ERROR : AE_OK);}/* TODO: Change code to take advantage of driver model more */voidacpi_os_derive_pci_id_2 ( acpi_handle rhandle, /* upper bound */ acpi_handle chandle, /* current node */ struct acpi_pci_id **id, int *is_bridge, u8 *bus_number){ acpi_handle handle; struct acpi_pci_id *pci_id = *id; acpi_status status; unsigned long temp; acpi_object_type type; u8 tu8; acpi_get_parent(chandle, &handle); if (handle != rhandle) { acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge, bus_number); status = acpi_get_type(handle, &type); if ( (ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE) ) return; status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &temp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -