Commit 6f982794 authored by Andy Grover's avatar Andy Grover

Merge groveronline.com:/root/bk/linux-2.5

into groveronline.com:/root/bk/linux-acpi
parents 2d00c1cc feb66678
obj-$(CONFIG_ACPI_HT_ONLY) := acpitable.o
obj-$(CONFIG_ACPI_BOOT) := boot.o
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
/*
* acpitable.c - IA32-specific ACPI boot-time initialization (Revision: 1)
*
* Copyright (C) 1999 Andrew Henroid
* Copyright (C) 2001 Richard Schaal
* Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
* Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
* Copyright (C) 2001 Arjan van de Ven <arjanv@redhat.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
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* $Id: acpitable.c,v 1.7 2001/11/04 12:21:18 fenrus Exp $
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <asm/mpspec.h>
#include <asm/io.h>
#include <asm/apic.h>
#include <asm/apicdef.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include "acpitable.h"
static acpi_table_handler acpi_boot_ops[ACPI_TABLE_COUNT];
int acpi_lapic;
static unsigned char __init
acpi_checksum(void *buffer, int length)
{
int i;
unsigned char *bytebuffer;
unsigned char sum = 0;
if (!buffer || length <= 0)
return 0;
bytebuffer = (unsigned char *) buffer;
for (i = 0; i < length; i++)
sum += *(bytebuffer++);
return sum;
}
static void __init
acpi_print_table_header(acpi_table_header * header)
{
if (!header)
return;
printk(KERN_INFO "ACPI table found: %.4s v%d [%.6s %.8s %d.%d]\n",
header->signature, header->revision, header->oem_id,
header->oem_table_id, header->oem_revision >> 16,
header->oem_revision & 0xffff);
return;
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_scan_memory_for_rsdp
*
* PARAMETERS: address - Starting pointer for search
* length - Maximum length to search
*
* RETURN: Pointer to the RSDP if found and valid, otherwise NULL.
*
* DESCRIPTION: Search a block of memory for the RSDP signature
*
******************************************************************************/
static void *__init
acpi_tb_scan_memory_for_rsdp(void *address, int length)
{
u32 offset;
if (length <= 0)
return NULL;
/* Search from given start addr for the requested length */
offset = 0;
while (offset < length) {
/* The signature must match and the checksum must be correct */
if (strncmp(address, RSDP_SIG, sizeof(RSDP_SIG) - 1) == 0 &&
acpi_checksum(address, RSDP_CHECKSUM_LENGTH) == 0) {
/* If so, we have found the RSDP */
printk(KERN_INFO "ACPI: RSDP located at physical address %p\n",
address);
return address;
}
offset += RSDP_SCAN_STEP;
address += RSDP_SCAN_STEP;
}
/* Searched entire block, no RSDP was found */
printk(KERN_INFO "ACPI: Searched entire block, no RSDP was found.\n");
return NULL;
}
/*******************************************************************************
*
* FUNCTION: acpi_find_root_pointer
*
* PARAMETERS: none
*
* RETURN: physical address of the RSDP
*
* DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
* pointer structure. If it is found, set *RSDP to point to it.
*
* NOTE: The RSDP must be either in the first 1_k of the Extended
* BIOS Data Area or between E0000 and FFFFF (ACPI 1.0 section
* 5.2.2; assertion #421).
*
******************************************************************************/
static struct acpi_table_rsdp * __init
acpi_find_root_pointer(void)
{
struct acpi_table_rsdp * rsdp;
/*
* Physical address is given
*/
/*
* Region 1) Search EBDA (low memory) paragraphs
*/
rsdp = acpi_tb_scan_memory_for_rsdp(__va(LO_RSDP_WINDOW_BASE),
LO_RSDP_WINDOW_SIZE);
if (rsdp)
return rsdp;
/*
* Region 2) Search upper memory: 16-byte boundaries in E0000h-F0000h
*/
rsdp = acpi_tb_scan_memory_for_rsdp(__va(HI_RSDP_WINDOW_BASE),
HI_RSDP_WINDOW_SIZE);
if (rsdp)
return rsdp;
printk(KERN_ERR "ACPI: System description tables not found\n");
return NULL;
}
/*
* Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
* to map the target physical address. The problem is that set_fixmap()
* provides a single page, and it is possible that the page is not
* sufficient.
* By using this area, we can map up to MAX_IO_APICS pages temporarily,
* i.e. until the next __va_range() call.
*
* Important Safety Note: The fixed I/O APIC page numbers are *subtracted*
* from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and
* count idx down while incrementing the phys address.
*/
static __init char *
__va_range(unsigned long phys, unsigned long size)
{
unsigned long base, offset, mapped_size;
int idx;
offset = phys & (PAGE_SIZE - 1);
mapped_size = PAGE_SIZE - offset;
set_fixmap(FIX_IO_APIC_BASE_END, phys);
base = fix_to_virt(FIX_IO_APIC_BASE_END);
dprintk("__va_range(0x%lx, 0x%lx): idx=%d mapped at %lx\n", phys, size,
FIX_IO_APIC_BASE_END, base);
/*
* Most cases can be covered by the below.
*/
idx = FIX_IO_APIC_BASE_END;
while (mapped_size < size) {
if (--idx < FIX_IO_APIC_BASE_0)
return 0; /* cannot handle this */
phys += PAGE_SIZE;
set_fixmap(idx, phys);
mapped_size += PAGE_SIZE;
}
return ((unsigned char *) base + offset);
}
static int __init acpi_tables_init(void)
{
int result = -ENODEV;
acpi_table_header *header = NULL;
struct acpi_table_rsdp *rsdp = NULL;
struct acpi_table_rsdt *rsdt = NULL;
struct acpi_table_rsdt saved_rsdt;
int tables = 0;
int type = 0;
int i = 0;
rsdp = (struct acpi_table_rsdp *) acpi_find_root_pointer();
if (!rsdp)
return -ENODEV;
printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision,
rsdp->oem_id);
if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) {
printk(KERN_WARNING "RSDP table signature incorrect\n");
return -EINVAL;
}
rsdt = (struct acpi_table_rsdt *)
__va_range(rsdp->rsdt_address, sizeof(struct acpi_table_rsdt));
if (!rsdt) {
printk(KERN_WARNING "ACPI: Invalid root system description tables (RSDT)\n");
return -ENODEV;
}
header = & rsdt->header;
acpi_print_table_header(header);
if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) {
printk(KERN_WARNING "ACPI: RSDT signature incorrect\n");
return -ENODEV;
}
/*
* The number of tables is computed by taking the
* size of all entries (header size minus total
* size of RSDT) divided by the size of each entry
* (4-byte table pointers).
*/
tables = (header->length - sizeof(acpi_table_header)) / 4;
memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt));
if (saved_rsdt.header.length > sizeof(saved_rsdt)) {
printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n", saved_rsdt.header.length);
return -ENODEV;
}
for (i = 0; i < tables; i++) {
/* Map in header, then map in full table length. */
header = (acpi_table_header *)
__va_range(saved_rsdt.entry[i],
sizeof(acpi_table_header));
if (!header)
break;
header = (acpi_table_header *)
__va_range(saved_rsdt.entry[i], header->length);
if (!header)
break;
acpi_print_table_header(header);
if (acpi_checksum(header,header->length)) {
printk(KERN_WARNING "ACPI %s has invalid checksum\n",
acpi_table_signatures[i]);
continue;
}
for (type = 0; type < ACPI_TABLE_COUNT; type++)
if (!strncmp((char *) &header->signature,
acpi_table_signatures[type],strlen(acpi_table_signatures[type])))
break;
if (type >= ACPI_TABLE_COUNT) {
printk(KERN_WARNING "ACPI: Unsupported table %.4s\n",
header->signature);
continue;
}
if (!acpi_boot_ops[type])
continue;
result = acpi_boot_ops[type] (header,
(unsigned long) saved_rsdt.
entry[i]);
}
return result;
}
static int total_cpus __initdata = 0;
int have_acpi_tables;
extern void __init MP_processor_info(struct mpc_config_processor *);
static void __init
acpi_parse_lapic(struct acpi_table_lapic *local_apic)
{
struct mpc_config_processor proc_entry;
int ix = 0;
if (!local_apic)
return;
printk(KERN_INFO "LAPIC (acpi_id[0x%04x] id[0x%x] enabled[%d])\n",
local_apic->acpi_id, local_apic->id, local_apic->flags.enabled);
printk(KERN_INFO "CPU %d (0x%02x00)", total_cpus, local_apic->id);
if (local_apic->flags.enabled) {
printk(" enabled");
ix = local_apic->id;
if (ix >= MAX_APICS) {
printk(KERN_WARNING
"Processor #%d INVALID - (Max ID: %d).\n", ix,
MAX_APICS);
return;
}
/*
* Fill in the info we want to save. Not concerned about
* the processor ID. Processor features aren't present in
* the table.
*/
proc_entry.mpc_type = MP_PROCESSOR;
proc_entry.mpc_apicid = local_apic->id;
proc_entry.mpc_cpuflag = CPU_ENABLED;
if (proc_entry.mpc_apicid == boot_cpu_physical_apicid) {
printk(" (BSP)");
proc_entry.mpc_cpuflag |= CPU_BOOTPROCESSOR;
}
proc_entry.mpc_cpufeature =
(boot_cpu_data.x86 << 8) |
(boot_cpu_data.x86_model << 4) |
boot_cpu_data.x86_mask;
proc_entry.mpc_featureflag = boot_cpu_data.x86_capability[0];
proc_entry.mpc_reserved[0] = 0;
proc_entry.mpc_reserved[1] = 0;
proc_entry.mpc_apicver = 0x10; /* integrated APIC */
MP_processor_info(&proc_entry);
} else {
printk(" disabled");
}
printk("\n");
total_cpus++;
return;
}
static void __init
acpi_parse_ioapic(struct acpi_table_ioapic *ioapic)
{
if (!ioapic)
return;
printk(KERN_INFO
"IOAPIC (id[0x%x] address[0x%x] global_irq_base[0x%x])\n",
ioapic->id, ioapic->address, ioapic->global_irq_base);
if (nr_ioapics >= MAX_IO_APICS) {
printk(KERN_WARNING
"Max # of I/O APICs (%d) exceeded (found %d).\n",
MAX_IO_APICS, nr_ioapics);
/* panic("Recompile kernel with bigger MAX_IO_APICS!\n"); */
}
}
/* Interrupt source overrides inform the machine about exceptions
to the normal "PIC" mode interrupt routing */
static void __init
acpi_parse_int_src_ovr(struct acpi_table_int_src_ovr *intsrc)
{
if (!intsrc)
return;
printk(KERN_INFO
"INT_SRC_OVR (bus[%d] irq[0x%x] global_irq[0x%x] polarity[0x%x] trigger[0x%x])\n",
intsrc->bus, intsrc->bus_irq, intsrc->global_irq,
intsrc->flags.polarity, intsrc->flags.trigger);
}
/*
* At this point, we look at the interrupt assignment entries in the MPS
* table.
*/
static void __init acpi_parse_nmi_src(struct acpi_table_nmi_src *nmisrc)
{
if (!nmisrc)
return;
printk(KERN_INFO
"NMI_SRC (polarity[0x%x] trigger[0x%x] global_irq[0x%x])\n",
nmisrc->flags.polarity, nmisrc->flags.trigger,
nmisrc->global_irq);
}
static void __init
acpi_parse_lapic_nmi(struct acpi_table_lapic_nmi *localnmi)
{
if (!localnmi)
return;
printk(KERN_INFO
"LAPIC_NMI (acpi_id[0x%04x] polarity[0x%x] trigger[0x%x] lint[0x%x])\n",
localnmi->acpi_id, localnmi->flags.polarity,
localnmi->flags.trigger, localnmi->lint);
}
static void __init
acpi_parse_lapic_addr_ovr(struct acpi_table_lapic_addr_ovr *lapic_addr_ovr)
{
if (!lapic_addr_ovr)
return;
printk(KERN_INFO "LAPIC_ADDR_OVR (address[0x%lx])\n",
(unsigned long) lapic_addr_ovr->address);
}
static void __init
acpi_parse_plat_int_src(struct acpi_table_plat_int_src *plintsrc)
{
if (!plintsrc)
return;
printk(KERN_INFO
"PLAT_INT_SRC (polarity[0x%x] trigger[0x%x] type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
plintsrc->flags.polarity, plintsrc->flags.trigger,
plintsrc->type, plintsrc->id, plintsrc->eid,
plintsrc->iosapic_vector, plintsrc->global_irq);
}
static int __init
acpi_parse_madt(acpi_table_header * header, unsigned long phys)
{
struct acpi_table_madt *madt;
acpi_madt_entry_header *entry_header;
int table_size;
madt = (struct acpi_table_madt *) __va_range(phys, header->length);
if (!madt)
return -EINVAL;
table_size = (int) (header->length - sizeof(*madt));
entry_header =
(acpi_madt_entry_header *) ((void *) madt + sizeof(*madt));
while (entry_header && (table_size > 0)) {
switch (entry_header->type) {
case ACPI_MADT_LAPIC:
acpi_parse_lapic((struct acpi_table_lapic *)
entry_header);
break;
case ACPI_MADT_IOAPIC:
acpi_parse_ioapic((struct acpi_table_ioapic *)
entry_header);
break;
case ACPI_MADT_INT_SRC_OVR:
acpi_parse_int_src_ovr((struct acpi_table_int_src_ovr *)
entry_header);
break;
case ACPI_MADT_NMI_SRC:
acpi_parse_nmi_src((struct acpi_table_nmi_src *)
entry_header);
break;
case ACPI_MADT_LAPIC_NMI:
acpi_parse_lapic_nmi((struct acpi_table_lapic_nmi *)
entry_header);
break;
case ACPI_MADT_LAPIC_ADDR_OVR:
acpi_parse_lapic_addr_ovr((struct
acpi_table_lapic_addr_ovr *)
entry_header);
break;
case ACPI_MADT_PLAT_INT_SRC:
acpi_parse_plat_int_src((struct acpi_table_plat_int_src
*) entry_header);
break;
default:
printk(KERN_WARNING
"Unsupported MADT entry type 0x%x\n",
entry_header->type);
break;
}
table_size -= entry_header->length;
entry_header =
(acpi_madt_entry_header *) ((void *) entry_header +
entry_header->length);
}
if (!total_cpus) {
printk("ACPI: No Processors found in the APCI table.\n");
return -EINVAL;
}
printk(KERN_INFO "%d CPUs total\n", total_cpus);
if (madt->lapic_address)
mp_lapic_addr = madt->lapic_address;
else
mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
printk(KERN_INFO "Local APIC address %x\n", madt->lapic_address);
return 0;
}
/*
* Configure the processor info using MADT in the ACPI tables. If we fail to
* configure that, then we use the MPS tables.
*/
void __init
acpi_boot_init(void)
{
memset(&acpi_boot_ops, 0, sizeof(acpi_boot_ops));
acpi_boot_ops[ACPI_APIC] = acpi_parse_madt;
/*
* Only do this when requested, either because of CPU/Bios type or from the command line
*/
if (!acpi_tables_init())
acpi_lapic = 1;
}
/*
* acpitable.c - IA32-specific ACPI boot-time initialization (Revision: 1)
*
* Copyright (C) 1999 Andrew Henroid
* Copyright (C) 2001 Richard Schaal
* Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
* Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
* Copyright (C) 2001 Arjan van de Ven <arjanv@redhat.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
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* $Id: acpitable.h,v 1.3 2001/11/03 22:41:34 fenrus Exp $
*/
/*
* The following codes are cut&pasted from drivers/acpi. Part of the code
* there can be not updated or delivered yet.
* To avoid conflicts when CONFIG_ACPI is defined, the following codes are
* modified so that they are self-contained in this file.
* -- jun
*/
#ifndef _HEADER_ACPITABLE_H_
#define _HEADER_ACPITABLE_H_
#define dprintk printk
typedef unsigned int ACPI_TBLPTR;
typedef struct { /* ACPI common table header */
char signature[4]; /* identifies type of table */
u32 length; /* length of table,
in bytes, * including header */
u8 revision; /* specification minor version # */
u8 checksum; /* to make sum of entire table == 0 */
char oem_id[6]; /* OEM identification */
char oem_table_id[8]; /* OEM table identification */
u32 oem_revision; /* OEM revision number */
char asl_compiler_id[4]; /* ASL compiler vendor ID */
u32 asl_compiler_revision; /* ASL compiler revision number */
} acpi_table_header __attribute__ ((packed));;
enum {
ACPI_APIC = 0,
ACPI_BOOT,
ACPI_DBGP,
ACPI_DSDT,
ACPI_ECDT,
ACPI_ETDT,
ACPI_FACP,
ACPI_FACS,
ACPI_OEMX,
ACPI_PSDT,
ACPI_SBST,
ACPI_SLIT,
ACPI_SPCR,
ACPI_SRAT,
ACPI_SSDT,
ACPI_SPMI,
ACPI_XSDT,
ACPI_TABLE_COUNT
};
static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
"APIC",
"BOOT",
"DBGP",
"DSDT",
"ECDT",
"ETDT",
"FACP",
"FACS",
"OEM",
"PSDT",
"SBST",
"SLIT",
"SPCR",
"SRAT",
"SSDT",
"SPMI",
"XSDT"
};
struct acpi_table_madt {
acpi_table_header header;
u32 lapic_address;
struct {
u32 pcat_compat:1;
u32 reserved:31;
} flags __attribute__ ((packed));
} __attribute__ ((packed));;
enum {
ACPI_MADT_LAPIC = 0,
ACPI_MADT_IOAPIC,
ACPI_MADT_INT_SRC_OVR,
ACPI_MADT_NMI_SRC,
ACPI_MADT_LAPIC_NMI,
ACPI_MADT_LAPIC_ADDR_OVR,
ACPI_MADT_IOSAPIC,
ACPI_MADT_LSAPIC,
ACPI_MADT_PLAT_INT_SRC,
ACPI_MADT_ENTRY_COUNT
};
#define RSDP_SIG "RSD PTR "
#define RSDT_SIG "RSDT"
#define ACPI_DEBUG_PRINT(pl)
#define ACPI_MEMORY_MODE 0x01
#define ACPI_LOGICAL_ADDRESSING 0x00
#define ACPI_PHYSICAL_ADDRESSING 0x01
#define LO_RSDP_WINDOW_BASE 0 /* Physical Address */
#define HI_RSDP_WINDOW_BASE 0xE0000 /* Physical Address */
#define LO_RSDP_WINDOW_SIZE 0x400
#define HI_RSDP_WINDOW_SIZE 0x20000
#define RSDP_SCAN_STEP 16
#define RSDP_CHECKSUM_LENGTH 20
typedef int (*acpi_table_handler) (acpi_table_header * header, unsigned long);
struct acpi_table_rsdp {
char signature[8];
u8 checksum;
char oem_id[6];
u8 revision;
u32 rsdt_address;
} __attribute__ ((packed));
struct acpi_table_rsdt {
acpi_table_header header;
u32 entry[ACPI_TABLE_COUNT];
} __attribute__ ((packed));
typedef struct {
u8 type;
u8 length;
} acpi_madt_entry_header __attribute__ ((packed));
typedef struct {
u16 polarity:2;
u16 trigger:2;
u16 reserved:12;
} acpi_madt_int_flags __attribute__ ((packed));
struct acpi_table_lapic {
acpi_madt_entry_header header;
u8 acpi_id;
u8 id;
struct {
u32 enabled:1;
u32 reserved:31;
} flags __attribute__ ((packed));
} __attribute__ ((packed));
struct acpi_table_ioapic {
acpi_madt_entry_header header;
u8 id;
u8 reserved;
u32 address;
u32 global_irq_base;
} __attribute__ ((packed));
struct acpi_table_int_src_ovr {
acpi_madt_entry_header header;
u8 bus;
u8 bus_irq;
u32 global_irq;
acpi_madt_int_flags flags;
} __attribute__ ((packed));
struct acpi_table_nmi_src {
acpi_madt_entry_header header;
acpi_madt_int_flags flags;
u32 global_irq;
} __attribute__ ((packed));
struct acpi_table_lapic_nmi {
acpi_madt_entry_header header;
u8 acpi_id;
acpi_madt_int_flags flags;
u8 lint;
} __attribute__ ((packed));
struct acpi_table_lapic_addr_ovr {
acpi_madt_entry_header header;
u8 reserved[2];
u64 address;
} __attribute__ ((packed));
struct acpi_table_iosapic {
acpi_madt_entry_header header;
u8 id;
u8 reserved;
u32 global_irq_base;
u64 address;
} __attribute__ ((packed));
struct acpi_table_lsapic {
acpi_madt_entry_header header;
u8 acpi_id;
u8 id;
u8 eid;
u8 reserved[3];
struct {
u32 enabled:1;
u32 reserved:31;
} flags;
} __attribute__ ((packed));
struct acpi_table_plat_int_src {
acpi_madt_entry_header header;
acpi_madt_int_flags flags;
u8 type;
u8 id;
u8 eid;
u8 iosapic_vector;
u32 global_irq;
u32 reserved;
} __attribute__ ((packed));
/*
* ACPI Table Descriptor. One per ACPI table
*/
typedef struct acpi_table_desc {
struct acpi_table_desc *prev;
struct acpi_table_desc *next;
struct acpi_table_desc *installed_desc;
acpi_table_header *pointer;
void *base_pointer;
u8 *aml_pointer;
u64 physical_address;
u32 aml_length;
u32 length;
u32 count;
u16 table_id;
u8 type;
u8 allocation;
u8 loaded_into_namespace;
} acpi_table_desc __attribute__ ((packed));;
#endif
......@@ -61,7 +61,12 @@ struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
unsigned long mmu_cr4_features;
EXPORT_SYMBOL_GPL(mmu_cr4_features);
int acpi_disabled __initdata = 0;
#ifdef CONFIG_ACPI_HT_ONLY
int acpi_disabled = 1;
#else
int acpi_disabled = 0;
#endif
EXPORT_SYMBOL(acpi_disabled);
int MCA_bus;
/* for MCA, but anyone else can use it if they want */
......@@ -515,6 +520,10 @@ static void __init parse_cmdline_early (char ** cmdline_p)
if (c == ' ' && !memcmp(from, "acpi=off", 8))
acpi_disabled = 1;
/* "acpismp=force" turns on ACPI again */
else if (!memcmp(from, "acpismp=force", 14))
acpi_disabled = 0;
/*
* highmem=size forces highmem to be exactly 'size' bytes.
* This works even on boxes that have no highmem otherwise.
......
......@@ -49,12 +49,12 @@ config ACPI_HT_ONLY
Full ACPI support (CONFIG_ACPI) is preferred. Use this option
only if you wish to limit ACPI's role to processor enumeration.
There is no command-line option to disable this, but the kernel
will fall back to the MPS table if the MADT is not present.
In this configuration, ACPI defaults to off. It must be enabled
on the command-line with the "acpismp=force" option.
config ACPI_BOOT
bool
depends on IA64 && (!IA64_HP_SIM || IA64_SGI_SN) || X86 && ACPI && !ACPI_HT_ONLY || X86 && ACPI
depends on IA64 && (!IA64_HP_SIM || IA64_SGI_SN) || X86 && ACPI && !ACPI_HT_ONLY
default y
config ACPI_SLEEP
......@@ -135,6 +135,31 @@ config ACPI_NUMA
bool "NUMA support" if NUMA && (IA64 && !IA64_HP_SIM || X86 && ACPI && !ACPI_HT_ONLY && !X86_64)
default y if IA64 && IA64_SGI_SN
config ACPI_ASUS
tristate "ASUS/Medion Laptop Extras"
depends on X86 && ACPI && !ACPI_HT_ONLY
---help---
This driver provides support for extra features of ACPI-compatible
ASUS laptops. As some of Medion laptops are made by ASUS, it may also
support some Medion laptops (such as 9675 for example). It makes all
the extra buttons generate standard ACPI events that go through
/proc/acpi/events, and (on some models) adds support for changing the
display brightness and output, switching the LCD backlight on and off,
and most importantly, allows you to blink those fancy LEDs intended
for reporting mail and wireless status.
All settings are changed via /proc/acpi/asus directory entries. Owner
and group for these entries can be set with asus_uid and asus_gid
parameters.
More information and a userspace daemon for handling the extra buttons
at <http://sourceforge.net/projects/acpi4asus/>.
If you have an ACPI-compatible ASUS laptop, say Y or M here. This
driver is still under development, so if your laptop is unsupported or
something works not quite as expected, please use the mailing list
available on the above page (acpi4asus-user@lists.sourceforge.net)
config ACPI_TOSHIBA
tristate "Toshiba Laptop Extras"
depends on X86 && ACPI && !ACPI_HT_ONLY
......
......@@ -44,5 +44,6 @@ obj-$(CONFIG_ACPI_THERMAL) += thermal.o
obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
obj-$(CONFIG_ACPI_DEBUG) += debug.o
obj-$(CONFIG_ACPI_NUMA) += numa.o
obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-$(CONFIG_ACPI_BUS) += scan.o
/*
* asus_acpi.c - Asus Laptop ACPI Extras
*
*
* Copyright (C) 2002, 2003 Julien Lerouge, Karol Kozimor
*
* 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
*
*
* The development page for this driver is located at
* http://sourceforge.net/projects/acpi4asus/
*
* Credits:
* Johann Wiesner - Small compile fixes
* John Belmonte - ACPI code for Toshiba laptop was a good starting point.
*
* TODO
* add Fn key status
* Add mode selection on module loading (parameter) -> still necessary ?
* Complete display switching -- may require dirty hacks?
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#define ASUS_ACPI_VERSION "0.24a"
#define PROC_ASUS "asus" //the directory
#define PROC_MLED "mled"
#define PROC_WLED "wled"
#define PROC_INFOS "info"
#define PROC_LCD "lcd"
#define PROC_BRN "brn"
#define PROC_DISP "disp"
#define ACPI_HOTK_NAME "Asus Laptop ACPI Extras Driver"
#define ACPI_HOTK_CLASS "hotkey"
#define ACPI_HOTK_DEVICE_NAME "Hotkey"
#define ACPI_HOTK_HID "ATK0100"
/*
* Some events we use, same for all Asus
*/
#define BR_UP 0x10
#define BR_DOWN 0x20
/*
* Flags for hotk status
*/
#define MLED_ON 0x01 //is MLED ON ?
#define WLED_ON 0x02
MODULE_AUTHOR("Julien Lerouge, Karol Kozimor");
MODULE_DESCRIPTION(ACPI_HOTK_NAME);
MODULE_LICENSE("GPL");
static uid_t asus_uid = 0;
static gid_t asus_gid = 0;
MODULE_PARM(asus_uid, "i");
MODULE_PARM_DESC(uid, "UID for entries in /proc/acpi/asus.\n");
MODULE_PARM(asus_gid, "i");
MODULE_PARM_DESC(gid, "GID for entries in /proc/acpi/asus.\n");
/* For each model, all features implemented */
struct model_data {
char *name; //name of the laptop
char *mt_mled; //method to handle mled
char *mled_status; //node to handle mled reading
char *mt_wled; //method to handle wled
char *wled_status; //node to handle wled reading
char *mt_lcd_switch; //method to turn LCD ON/OFF
char *lcd_status; //node to read LCD panel state
char *brightness_up; //method to set brightness up
char *brightness_down; //guess what ?
char *brightness_set; //method to set absolute brightness
char *brightness_get; //method to get absolute brightness
char *brightness_status;//node to get brightness
char *display_set; //method to set video output
char *display_get; //method to get video output
};
/*
* This is the main structure, we can use it to store anything interesting
* about the hotk device
*/
struct asus_hotk {
struct acpi_device *device; //the device we are in
acpi_handle handle; //the handle of the hotk device
char status; //status of the hotk, for LEDs, ...
struct model_data *methods; //methods available on the laptop
u8 brightness; //brighness level
enum {
L2X = 0, //L200D -> TODO check Q11 (Fn+F8)
// Calling this method simply hang the
// computer, ISMI method hangs the laptop.
L3X, //L3C
L3D, //L3400D
M2X, //M2400E
S1X, //S1300A -> TODO special keys do not work ?
D1X, //D1
L1X, //L1400B
A1X, //A1340D, A1300F
J1X, //S200 (J1)
//TODO A1370D does not seems to have a ATK device
// L8400 model doesn't have ATK
END_MODEL,
} model; //Models currently supported
u16 event_count[128]; //count for each event TODO make this better
};
/* Here we go */
#define L3X_PREFIX "\\_SB.PCI0.PX40.ECD0."
#define S1X_PREFIX "\\_SB.PCI0.PX40."
#define L1X_PREFIX S1X_PREFIX
#define A1X_PREFIX "\\_SB.PCI0.ISA.EC0."
#define J1X_PREFIX A1X_PREFIX
static struct model_data model_conf[END_MODEL] = {
/*
* name| mled |mled read| wled |wled read| lcd sw |lcd read |
* br up|br down | br set | br read | br status|set disp | get disp
*
* br set and read shall be in hotk device !
* same for set disp
*
* TODO I have seen a SWBX and AIBX method on some models, like L1400B,
* it seems to be a kind of switch, but what for ?
*
*/
{"L2X", "MLED", "\\SGP6", "WLED", "\\RCP3", "\\Q10", "\\SGP0",
"\\Q0E", "\\Q0F", NULL, NULL, NULL, "SDSP", "\\INFB"},
{"L3X", "MLED", NULL, "WLED", NULL, L3X_PREFIX "_Q10", "\\GL32",
L3X_PREFIX "_Q0F", L3X_PREFIX "_Q0E", "SPLV", "GPLV", "\\BLVL", "SDSP",
"\\_SB.PCI0.PCI1.VGAC.NMAP"},
{"L3D", "MLED", "\\MALD", "WLED", NULL, "\\Q10", "\\BKLG",
"\\Q0E", "\\Q0F", "SPLV", "GPLV", "\\BLVL", "SDSP", "\\INFB"},
{"M2X", "MLED", NULL, "WLED", NULL, "\\Q10", "\\GP06",
"\\Q0E","\\Q0F", "SPLV", "GPLV", NULL, "SDSP", "\\INFB"},
{"S1X", "MLED", "\\EMLE", "WLED", NULL, S1X_PREFIX "Q10", "\\PNOF",
S1X_PREFIX "Q0F", S1X_PREFIX "Q0E", "SPLV", "GPLV", "\\BRIT", NULL, NULL},
{"D1X", "MLED", NULL, NULL, NULL, "\\Q0D", "\\GP11",
"\\Q0C", "\\Q0B", NULL, NULL, "\\BLVL", "SDSP","\\INFB"},
{"L1X", "MLED", NULL, "WLED", NULL, L1X_PREFIX "Q10", "\\PNOF",
L1X_PREFIX "Q0F", L1X_PREFIX "Q0E", "SPLV", "GPLV", "\\BRIT", NULL, NULL},
{"A1X", "MLED", "\\MAIL", NULL, NULL, A1X_PREFIX "_Q10", "\\BKLI",
A1X_PREFIX "_Q0E", A1X_PREFIX "_Q0F", NULL, NULL, NULL, NULL, NULL},
{"J1X", "MLED", "\\MAIL", NULL, NULL, J1X_PREFIX "_Q10", "\\BKLI",
J1X_PREFIX "_Q0B", J1X_PREFIX "_Q0A", NULL, NULL, NULL, NULL, NULL}
};
/* procdir we use */
static struct proc_dir_entry *asus_proc_dir = NULL;
/*
* This header is made available to allow proper configuration given model,
* revision number , ... this info cannot go in struct asus_hotk because it is
* available before the hotk
*/
static struct acpi_table_header *asus_info = NULL;
/*
* The hotkey driver declaration
*/
static int asus_hotk_add(struct acpi_device *device);
static int asus_hotk_remove(struct acpi_device *device, int type);
static struct acpi_driver asus_hotk_driver = {
.name = ACPI_HOTK_NAME,
.class = ACPI_HOTK_CLASS,
.ids = ACPI_HOTK_HID,
.ops = {
.add = asus_hotk_add,
.remove = asus_hotk_remove,
},
};
/*
* This function evaluates an ACPI method, given an int as parameter, the
* method is searched within the scope of the handle, can be NULL. The output
* of the method is written is output, which can also be NULL
*
* returns 1 if write is successful, 0 else.
*/
static int write_acpi_int(acpi_handle handle, const char *method, int val,
struct acpi_buffer *output)
{
struct acpi_object_list params; //list of input parameters (an int here)
union acpi_object in_obj; //the only param we use
acpi_status status;
params.count = 1;
params.pointer = &in_obj;
in_obj.type = ACPI_TYPE_INTEGER;
in_obj.integer.value = val;
status = acpi_evaluate_object(handle, (char *) method, &params, output);
return (status == AE_OK);
}
static int read_acpi_int(acpi_handle handle, const char *method, int *val)
{
struct acpi_buffer output;
union acpi_object out_obj;
acpi_status status;
output.length = sizeof(out_obj);
output.pointer = &out_obj;
status = acpi_evaluate_object(handle, (char*) method, NULL, &output);
*val = out_obj.integer.value;
return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
}
/*
* We write our info in page, we begin at offset off and cannot write more
* than count bytes. We set eof to 1 if we handle those 2 values. We return the
* number of bytes written in page
*/
static int
proc_read_info(char *page, char **start, off_t off, int count, int *eof,
void *data)
{
int len = 0;
struct asus_hotk *hotk = (struct asus_hotk *) data;
char buf[16]; //enough for all info
/*
* We use the easy way, we don't care of off and count, so we don't set eof
* to 1
*/
len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
len +=
sprintf(page + len, "Model reference : %s\n",
hotk->methods->name);
if (asus_info) {
snprintf(buf, 5, "%s", asus_info->signature);
len += sprintf(page + len, "ACPI signature : %s\n", buf);
snprintf(buf, 16, "%d", asus_info->length);
len += sprintf(page + len, "Table length : %s\n", buf);
snprintf(buf, 16, "%d", asus_info->revision);
len += sprintf(page + len, "ACPI minor version : %s\n", buf);
snprintf(buf, 16, "%d", asus_info->checksum);
len += sprintf(page + len, "Checksum : %s\n", buf);
snprintf(buf, 7, "%s", asus_info->oem_id);
len += sprintf(page + len, "OEM identification : %s\n", buf);
snprintf(buf, 9, "%s", asus_info->oem_table_id);
len += sprintf(page + len, "OEM table id : %s\n", buf);
snprintf(buf, 16, "%x", asus_info->oem_revision);
len += sprintf(page + len, "OEM rev number : 0x%s\n", buf);
snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
len += sprintf(page + len, "ASL comp vendor ID : %s\n", buf);
snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
len += sprintf(page + len, "ASL comp rev number: 0x%s\n", buf);
}
return len;
}
/*
* proc file handlers
*/
static int
proc_read_mled(char *page, char **start, off_t off, int count, int *eof,
void *data)
{
int len = 0;
struct asus_hotk *hotk = (struct asus_hotk *) data;
int led_status = 0;
/*
* We use the easy way, we don't care of off and count, so we don't set eof
* to 1
*/
if (hotk->methods->mled_status) {
if (read_acpi_int(NULL, hotk->methods->mled_status,
&led_status))
len = sprintf(page, "%d\n", led_status);
else
printk(KERN_NOTICE "Asus ACPI: Error reading MLED "
"status\n");
} else {
len = sprintf(page, "%d\n", (hotk->status & MLED_ON) ? 1 : 0);
}
return len;
}
static int
proc_write_mled(struct file *file, const char *buffer,
unsigned long count, void *data)
{
int value;
int led_out = 0;
struct asus_hotk *hotk = (struct asus_hotk *) data;
/* scan expression. Multiple expressions may be delimited with ; */
if (sscanf(buffer, "%i", &value) == 1)
led_out = ~value & 1;
hotk->status =
(value) ? (hotk->status | MLED_ON) : (hotk->status & ~MLED_ON);
/* We don't have to check mt_mled exists if we are here :) */
if (!write_acpi_int(hotk->handle, hotk->methods->mt_mled, led_out,
NULL))
printk(KERN_NOTICE "Asus ACPI: MLED write failed\n");
return count;
}
/*
* We write our info in page, we begin at offset off and cannot write more
* than count bytes. We set eof to 1 if we handle those 2 values. We return the
* number of bytes written in page
*/
static int
proc_read_wled(char *page, char **start, off_t off, int count, int *eof,
void *data)
{
int len = 0;
struct asus_hotk *hotk = (struct asus_hotk *) data;
int led_status;
if (hotk->methods->wled_status) {
if (read_acpi_int(NULL, hotk->methods->mled_status,
&led_status))
len = sprintf(page, "%d\n", led_status);
else
printk(KERN_NOTICE "Asus ACPI: Error reading WLED "
"status\n");
} else {
len = sprintf(page, "%d\n", (hotk->status & WLED_ON) ? 1 : 0);
}
return len;
}
static int
proc_write_wled(struct file *file, const char *buffer,
unsigned long count, void *data)
{
int value;
int led_out = 0;
struct asus_hotk *hotk = (struct asus_hotk *) data;
/* scan expression. Multiple expressions may be delimited with ; */
if (sscanf(buffer, "%i", &value) == 1)
led_out = value & 1;
hotk->status =
(value) ? (hotk->status | WLED_ON) : (hotk->status & ~WLED_ON);
/* We don't have to check if mt_wled exists if we are here :) */
if (!write_acpi_int(hotk->handle, hotk->methods->mt_wled, led_out,
NULL))
printk(KERN_NOTICE "Asus ACPI: WLED write failed\n");
return count;
}
static int get_lcd_state(struct asus_hotk *hotk)
{
int lcd = 0;
/* We don't have to check anything, if we are here */
if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
printk(KERN_NOTICE "Asus ACPI: Error reading LCD status\n");
if (hotk->model == L2X)
lcd = ~lcd;
return (lcd & 1);
}
static int
proc_read_lcd(char *page, char **start, off_t off, int count, int *eof,
void *data)
{
return sprintf(page, "%d\n", get_lcd_state((struct asus_hotk *) data));
}
static int
proc_write_lcd(struct file *file, const char *buffer,
unsigned long count, void *data)
{
int value;
int lcd = 0;
acpi_status status = 0;
int lcd_status = 0;
struct asus_hotk *hotk = (struct asus_hotk *) data;
/* scan expression. Multiple expressions may be delimited with ; */
if (sscanf(buffer, "%i", &value) == 1)
lcd = value & 1;
lcd_status = get_lcd_state(hotk);
if (lcd_status != lcd) {
/* switch */
status =
acpi_evaluate_object(NULL, hotk->methods->mt_lcd_switch,
NULL, NULL);
if (ACPI_FAILURE(status))
printk(KERN_NOTICE "Asus ACPI: Error switching LCD\n");
}
return count;
}
/*
* Change the brightness level
*/
static void set_brightness(int value, struct asus_hotk *hotk)
{
acpi_status status = 0;
/* ATKD laptop */
if(hotk->methods->brightness_set) {
if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set,
value, NULL))
printk(KERN_NOTICE "Asus ACPI: Error changing brightness\n");
return;
}
/* HOTK laptop if we are here, act as appropriate */
value -= hotk->brightness;
while (value != 0) {
status = acpi_evaluate_object(NULL, (value > 0) ?
hotk->methods->brightness_up :
hotk->methods->brightness_down,
NULL, NULL);
(value > 0) ? value-- : value++;
if (ACPI_FAILURE(status))
printk(KERN_NOTICE "Asus ACPI: Error changing brightness\n");
}
return;
}
static int read_brightness(struct asus_hotk *hotk)
{
int value;
if(hotk->methods->brightness_get) { /* ATKD laptop */
if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get,
&value))
printk(KERN_NOTICE "Asus ACPI: Error reading brightness\n");
} else if (hotk->methods->brightness_status) { /* For D1 for example */
if (!read_acpi_int(NULL, hotk->methods->brightness_status,
&value))
printk(KERN_NOTICE "Asus ACPI: Error reading brightness\n");
} else /* HOTK laptop */
value = hotk->brightness;
return value;
}
static int
proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
void *data)
{
struct asus_hotk *hotk = (struct asus_hotk *) data;
return sprintf(page, "%d\n", read_brightness(hotk));
}
static int
proc_write_brn(struct file *file, const char *buffer,
unsigned long count, void *data)
{
int value;
struct asus_hotk *hotk = (struct asus_hotk *) data;
/* scan expression. Multiple expressions may be delimited with ; */
if (sscanf(buffer, "%d", &value) == 1) {
value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
/* 0 <= value <= 15 */
set_brightness(value, hotk);
} else {
printk(KERN_NOTICE "Asus ACPI: Error reading user input\n");
}
return count;
}
static void set_display(int value, struct asus_hotk *hotk)
{
/* no sanity check needed for now */
if (!write_acpi_int(hotk->handle, hotk->methods->display_set,
value, NULL))
printk(KERN_NOTICE "Asus ACPI: Error setting display\n");
return;
}
/*
* Now, *this* one could be more user-friendly, but so far, no-one has
* complained. The significance of bits is the same as in proc_write_disp()
*/
static int
proc_read_disp(char *page, char **start, off_t off, int count, int *eof,
void *data)
{
int value = 0;
struct asus_hotk *hotk = (struct asus_hotk *) data;
if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value))
printk(KERN_NOTICE "Asus ACPI: Error reading display status\n");
return sprintf(page, "%d\n", value);
}
/*
* Preliminary support for display switching. As of now: 0x01 should activate
* the LCD output, 0x02 should do for CRT, and 0x04 for TV-Out. Any combination
* (bitwise) of these will suffice. I never actually tested 3 displays hooked up
* simultaneously, so be warned.
*/
static int
proc_write_disp(struct file *file, const char *buffer,
unsigned long count, void *data)
{
int value;
struct asus_hotk *hotk = (struct asus_hotk *) data;
/* scan expression. Multiple expressions may be delimited with ; */
if (sscanf(buffer, "%d", &value) == 1)
set_display(value, hotk);
else {
printk(KERN_NOTICE "Asus ACPI: Error reading user input\n");
}
return count;
}
static int asus_hotk_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *proc;
struct asus_hotk *hotk = acpi_driver_data(device);
mode_t mode;
/*
* If parameter uid or gid is not changed, keep the default setting for
* our proc entries (-rw-rw-rw-) else, it means we care about security,
* and then set to -rw-rw----
*/
if ((asus_uid == 0) && (asus_gid == 0)){
mode = S_IFREG | S_IRUGO | S_IWUGO;
}else{
mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
}
acpi_device_dir(device) = asus_proc_dir;
if (!acpi_device_dir(device))
return(-ENODEV);
proc = create_proc_entry(PROC_INFOS, mode, acpi_device_dir(device));
if (proc) {
proc->read_proc = proc_read_info;
proc->data = acpi_driver_data(device);
proc->owner = THIS_MODULE;
proc->uid = asus_uid;
proc->gid = asus_gid;;
} else {
printk(KERN_NOTICE " Unable to create " PROC_INFOS
" fs entry\n");
}
if (hotk->methods->mt_wled) {
proc = create_proc_entry(PROC_WLED, mode, acpi_device_dir(device));
if (proc) {
proc->write_proc = proc_write_wled;
proc->read_proc = proc_read_wled;
proc->data = acpi_driver_data(device);
proc->owner = THIS_MODULE;
proc->uid = asus_uid;
proc->gid = asus_gid;;
} else {
printk(KERN_NOTICE " Unable to create " PROC_WLED
" fs entry\n");
}
}
if (hotk->methods->mt_mled) {
proc = create_proc_entry(PROC_MLED, mode, acpi_device_dir(device));
if (proc) {
proc->write_proc = proc_write_mled;
proc->read_proc = proc_read_mled;
proc->data = acpi_driver_data(device);
proc->owner = THIS_MODULE;
proc->uid = asus_uid;
proc->gid = asus_gid;;
} else {
printk(KERN_NOTICE " Unable to create " PROC_MLED
" fs entry\n");
}
}
/*
* We need both read node and write method as LCD switch is also accessible
* from keyboard
*/
if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {
proc = create_proc_entry(PROC_LCD, mode, acpi_device_dir(device));
if (proc) {
proc->write_proc = proc_write_lcd;
proc->read_proc = proc_read_lcd;
proc->data = acpi_driver_data(device);
proc->owner = THIS_MODULE;
proc->uid = asus_uid;
proc->gid = asus_gid;;
} else {
printk(KERN_NOTICE " Unable to create " PROC_LCD
" fs entry\n");
}
}
if ((hotk->methods->brightness_up && hotk->methods->brightness_down) ||
(hotk->methods->brightness_get && hotk->methods->brightness_get)) {
proc = create_proc_entry(PROC_BRN, mode, acpi_device_dir(device));
if (proc) {
proc->write_proc = proc_write_brn;
proc->read_proc = proc_read_brn;
proc->data = acpi_driver_data(device);
proc->owner = THIS_MODULE;
proc->uid = asus_uid;
proc->gid = asus_gid;;
} else {
printk(KERN_NOTICE " Unable to create " PROC_BRN
" fs entry\n");
}
}
if (hotk->methods->display_set) {
proc = create_proc_entry(PROC_DISP, mode, acpi_device_dir(device));
if (proc) {
proc->write_proc = proc_write_disp;
proc->read_proc = proc_read_disp;
proc->data = acpi_driver_data(device);
proc->owner = THIS_MODULE;
proc->uid = asus_uid;
proc->gid = asus_gid;;
} else {
printk(KERN_NOTICE " Unable to create " PROC_DISP
" fs entry\n");
}
}
return (AE_OK);
}
static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
{
/* TODO Find a better way to handle events count. Here, in data, we receive
* the hotk, so we can make anything !!
*/
struct asus_hotk *hotk = (struct asus_hotk *) data;
if (!hotk)
return;
if ((event & ~((u32) BR_UP)) < 16) {
hotk->brightness = (event & ~((u32) BR_UP));
} else if ((event & ~((u32) BR_DOWN)) < 16 ) {
hotk->brightness = (event & ~((u32) BR_DOWN));
}
acpi_bus_generate_event(hotk->device, event,
hotk->event_count[event % 128]++);
return;
}
/*
* This function is used to initialize the hotk with right values. In this
* method, we can make all the detection we want, and modify the hotk struct
*/
static int asus_hotk_get_info(struct asus_hotk *hotk)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *model = NULL;
/*
* We have to write 0 on init this far for all ASUS models
*/
if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
printk(KERN_NOTICE " Hotkey initialization failed\n");
return -ENODEV;
}
/*
* Here, we also use asus_info to make decision. For example, on INIT
* method, S1X and L1X models both reports to be L84F, but they don't
* have the same methods (L1X has WLED, S1X don't)
*/
model = (union acpi_object *) buffer.pointer;
if (model->type == ACPI_TYPE_STRING) {
printk(KERN_NOTICE " %s model detected, ", model->string.pointer);
}
hotk->model = END_MODEL;
if (strncmp(model->string.pointer, "L3D", 3) == 0)
hotk->model = L3D;
/*
* L2B has same settings that L3X, except for GL32, but as
* there is no node to get the LCD status, and as GL32 is never
* used anywhere else, I assume it's safe, even if lcd get is
* broken for this model (TODO fix it ?)
*/
else if (strncmp(model->string.pointer, "L3", 2) == 0 ||
strncmp(model->string.pointer, "L2B", 3) == 0)
hotk->model = L3X;
else if (strncmp(model->string.pointer, "M2", 2) == 0)
hotk->model = M2X;
else if (strncmp(model->string.pointer, "L2", 2) == 0)
hotk->model = L2X;
else if (strncmp(model->string.pointer, "L8", 2) == 0)
/* S1300A reports L84F, but L1400B too */
if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
hotk->model = L1X;
else
hotk->model = S1X;
else if (strncmp(model->string.pointer, "D1", 2) == 0)
hotk->model = D1X;
else if (strncmp(model->string.pointer, "A1", 2) == 0)
hotk->model = A1X;
else if (strncmp(model->string.pointer, "J1", 2) == 0)
hotk->model = J1X;
if (hotk->model == END_MODEL) {
/* By default use the same values, as I don't know others */
printk("unsupported, trying default values, contact the "
"developers\n");
hotk->model = L2X;
} else {
printk("supported\n");
}
hotk->methods = &model_conf[hotk->model];
acpi_os_free(model);
return AE_OK;
}
static int asus_hotk_check(struct asus_hotk *hotk)
{
int result = 0;
if (!hotk)
return(-EINVAL);
result = acpi_bus_get_status(hotk->device);
if (result)
return(result);
if (hotk->device->status.present) {
result = asus_hotk_get_info(hotk);
} else {
printk(KERN_NOTICE " Hotkey device not present, aborting\n");
return(-EINVAL);
}
return(result);
}
static int asus_hotk_add(struct acpi_device *device)
{
struct asus_hotk *hotk = NULL;
acpi_status status = AE_OK;
int result;
if (!device)
return(-EINVAL);
hotk =
(struct asus_hotk *) kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
if (!hotk)
return(-ENOMEM);
memset(hotk, 0, sizeof(struct asus_hotk));
hotk->handle = device->handle;
sprintf(acpi_device_name(device), "%s", ACPI_HOTK_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_HOTK_CLASS);
acpi_driver_data(device) = hotk;
hotk->device = device;
result = asus_hotk_check(hotk);
if (result)
goto end;
result = asus_hotk_add_fs(device);
if (result)
goto end;
/*
* We install the handler, it will receive the hotk in parameter, so, we
* could add other data to the hotk struct
*/
status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
asus_hotk_notify, hotk);
if (ACPI_FAILURE(status)) {
printk(KERN_NOTICE
" Error installing notify handler\n");
} else {
printk(KERN_DEBUG
" Notify Handler installed successfully\n");
}
/* For HOTK laptops: init the hotk->brightness value */
if ((!hotk->methods->brightness_get) && (!hotk->methods->brightness_status) &&
(hotk->methods->brightness_up && hotk->methods->brightness_down)) {
status = acpi_evaluate_object(NULL, hotk->methods->brightness_down,
NULL, NULL);
if (ACPI_FAILURE(status))
printk(KERN_NOTICE " Error changing brightness\n");
status = acpi_evaluate_object(NULL, hotk->methods->brightness_up,
NULL, NULL);
if (ACPI_FAILURE(status))
printk(KERN_NOTICE " Error changing brightness\n");
}
end:
if (result) {
kfree(hotk);
}
return(result);
}
static int asus_hotk_remove(struct acpi_device *device, int type)
{
acpi_status status = 0;
struct asus_hotk *hotk = NULL;
if (!device || !acpi_driver_data(device))
return(-EINVAL);
hotk = (struct asus_hotk *) acpi_driver_data(device);
status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
asus_hotk_notify);
if (ACPI_FAILURE(status))
printk(KERN_NOTICE "Error removing notify handler\n");
kfree(hotk);
return(0);
}
static int __init asus_acpi_init(void)
{
int result = 0;
acpi_status status = 0;
struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n",
ASUS_ACPI_VERSION);
/*
* Here is the code to know the model we are running on. We need to
* know this before calling the acpi_bus_register_driver function, in
* case the HID for the laptop we are running on is different from
* ACPI_HOTK_HID, which I have never seen yet :)
*
* This information is then available in the global var asus_info
*/
status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt);
if (ACPI_FAILURE(status)) {
printk(KERN_NOTICE " Couldn't get the DSDT table header\n");
} else {
asus_info = (struct acpi_table_header *) dsdt.pointer;
}
asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
if (!asus_proc_dir)
return(-ENODEV);
asus_proc_dir->owner = THIS_MODULE;
result = acpi_bus_register_driver(&asus_hotk_driver);
if (result < 0) {
printk(KERN_NOTICE " Error registering " ACPI_HOTK_NAME " \n");
remove_proc_entry(PROC_ASUS, acpi_root_dir);
return(-ENODEV);
}
return(0);
}
static void __exit asus_acpi_exit(void)
{
acpi_bus_unregister_driver(&asus_hotk_driver);
remove_proc_entry(PROC_ASUS, acpi_root_dir);
acpi_os_free(asus_info);
return;
}
module_init(asus_acpi_init);
module_exit(asus_acpi_exit);
......@@ -5,8 +5,8 @@
* Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (c) 2001 IBM Corp.
* Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
* Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
* Copyright (c) 2002 NEC Corporation
* Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
* Copyright (c) 2002,2003 NEC Corporation
*
* All rights reserved.
*
......@@ -26,8 +26,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <gregkh@us.ibm.com>,
* <h-aono@ap.jp.nec.com>,
* <t-kouchi@cq.jp.nec.com>
* <t-kochi@bq.jp.nec.com>
*
*/
......@@ -35,6 +34,7 @@
#define _ACPIPHP_H
#include <linux/acpi.h>
#include <linux/kobject.h> /* for KOBJ_NAME_LEN */
#include "pci_hotplug.h"
#define dbg(format, arg...) \
......@@ -49,7 +49,7 @@
#define SLOT_MAGIC 0x67267322
/* name size which is used for entries in pcihpfs */
#define SLOT_NAME_SIZE 32 /* ACPI{_SUN}-{BUS}:{DEV} */
#define SLOT_NAME_SIZE KOBJ_NAME_LEN /* {_SUN} */
struct acpiphp_bridge;
struct acpiphp_slot;
......@@ -212,11 +212,7 @@ struct acpiphp_func {
#define FUNC_HAS_PS2 (0x00000040)
#define FUNC_HAS_PS3 (0x00000080)
/* not yet */
#define SLOT_SUPPORT_66MHZ (0x00010000)
#define SLOT_SUPPORT_100MHZ (0x00020000)
#define SLOT_SUPPORT_133MHZ (0x00040000)
#define SLOT_SUPPORT_PCIX (0x00080000)
#define FUNC_EXISTS (0x10000000) /* to make sure we call _EJ0 only for existing funcs */
/* function prototypes */
......
......@@ -5,8 +5,8 @@
* Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (c) 2001 IBM Corp.
* Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
* Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
* Copyright (c) 2002 NEC Corporation
* Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
* Copyright (c) 2002,2003 NEC Corporation
*
* All rights reserved.
*
......@@ -26,8 +26,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <gregkh@us.ibm.com>,
* <h-aono@ap.jp.nec.com>,
* <t-kouchi@cq.jp.nec.com>
* <t-kochi@bq.jp.nec.com>
*
*/
......@@ -57,7 +56,7 @@ int acpiphp_debug;
static int num_slots;
#define DRIVER_VERSION "0.4"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kouchi@cq.jp.nec.com>"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>"
#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver"
MODULE_AUTHOR(DRIVER_AUTHOR);
......@@ -376,10 +375,8 @@ static int init_acpi (void)
*/
static void make_slot_name (struct slot *slot)
{
snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x",
slot->acpi_slot->sun,
slot->acpi_slot->bridge->bus,
slot->acpi_slot->device);
snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%u",
slot->acpi_slot->sun);
}
/**
......
/*
* ACPI PCI HotPlug glue functions to ACPI CA subsystem
*
* Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
* Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
* Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
* Copyright (c) 2002 NEC Corporation
* Copyright (c) 2002,2003 NEC Corporation
*
* All rights reserved.
*
......@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <t-kouchi@cq.jp.nec.com>
* Send feedback to <t-kochi@bq.jp.nec.com>
*
*/
......@@ -204,7 +204,6 @@ register_slot (acpi_handle handle, u32 lvl, void *context, void **rv)
if (ACPI_FAILURE(status)) {
err("failed to register interrupt notify handler\n");
kfree(newfunc);
return status;
}
......@@ -617,9 +616,8 @@ find_p2p_bridge (acpi_handle handle, u32 lvl, void *context, void **rv)
/* find hot-pluggable slots, and then find P2P bridge */
static int add_bridges(struct acpi_device *device)
static int add_bridge(acpi_handle handle)
{
acpi_handle *handle = device->handle;
acpi_status status;
unsigned long tmp;
int seg, bus;
......@@ -673,6 +671,12 @@ static int add_bridges(struct acpi_device *device)
}
static void remove_bridge (acpi_handle handle)
{
/* No-op for now .. */
}
static int power_on_slot (struct acpiphp_slot *slot)
{
acpi_status status;
......@@ -725,9 +729,7 @@ static int power_off_slot (struct acpiphp_slot *slot)
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
if (func->flags & FUNC_HAS_PS3) {
dbg("%s: executing _PS3 on %s\n", __FUNCTION__,
func->pci_dev->slot_name);
if (func->flags & (FUNC_HAS_PS3 | FUNC_EXISTS)) {
status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
if (ACPI_FAILURE(status)) {
warn("%s: _PS3 failed\n", __FUNCTION__);
......@@ -740,10 +742,8 @@ static int power_off_slot (struct acpiphp_slot *slot)
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
if (func->flags & FUNC_HAS_EJ0) {
dbg("%s: executing _EJ0 on %s\n", __FUNCTION__,
func->pci_dev->slot_name);
/* We don't want to call _EJ0 on non-existing functions. */
if (func->flags & (FUNC_HAS_EJ0 | FUNC_EXISTS)) {
/* _EJ0 method take one argument */
arg_list.count = 1;
arg_list.pointer = &arg;
......@@ -756,6 +756,7 @@ static int power_off_slot (struct acpiphp_slot *slot)
retval = -1;
goto err_exit;
}
func->flags &= (~FUNC_EXISTS);
}
}
......@@ -835,6 +836,8 @@ static int enable_device (struct acpiphp_slot *slot)
retval = acpiphp_configure_function(func);
if (retval)
goto err_exit;
func->flags |= FUNC_EXISTS;
}
slot->flags |= SLOT_ENABLED;
......@@ -1029,13 +1032,10 @@ static void handle_hotplug_event_func (acpi_handle handle, u32 type, void *conte
}
}
static struct acpi_driver acpi_pci_hp_driver = {
.name = "pci_hp",
.class = "",
.ids = ACPI_PCI_HOST_HID,
.ops = {
.add = add_bridges,
}
static struct acpi_pci_driver acpi_pci_hp_driver = {
.add = add_bridge,
.remove = remove_bridge,
};
/**
......@@ -1044,17 +1044,15 @@ static struct acpi_driver acpi_pci_hp_driver = {
*/
int acpiphp_glue_init (void)
{
acpi_status status;
int num;
if (list_empty(&pci_root_buses))
return -1;
status = acpi_bus_register_driver(&acpi_pci_hp_driver);
num = acpi_pci_register_driver(&acpi_pci_hp_driver);
if (ACPI_FAILURE(status)) {
err("%s: acpi_walk_namespace() failed\n", __FUNCTION__);
if (num <= 0)
return -1;
}
return 0;
}
......
......@@ -4,7 +4,7 @@
* Copyright (c) 1995,2001 Compaq Computer Corporation
* Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (c) 2001,2002 IBM Corp.
* Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
* Copyright (c) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
* Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
* Copyright (c) 2002 NEC Corporation
*
......@@ -25,7 +25,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <t-kouchi@cq.jp.nec.com>
* Send feedback to <t-kochi@bq.jp.nec.com>
*
*/
......
......@@ -5,7 +5,7 @@
* Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (c) 2001 IBM Corp.
* Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
* Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com)
* Copyright (c) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
* Copyright (c) 2002 NEC Corporation
*
* All rights reserved.
......@@ -25,7 +25,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <gregkh@us.ibm.com>,<h-aono@ap.jp.nec.com>
* Send feedback to <gregkh@us.ibm.com>, <t-kochi@bq.jp.nec.com>
*
*/
......
......@@ -106,6 +106,10 @@
:"0"(n_hi), "1"(n_lo))
#ifdef CONFIG_ACPI_HT_ONLY
extern int acpi_lapic;
#define acpi_ioapic 0
#else
#ifndef CONFIG_ACPI_BOOT
#define acpi_lapic 0
#define acpi_ioapic 0
......@@ -120,6 +124,7 @@ extern int acpi_ioapic;
#else
#define acpi_ioapic 0
#endif
#endif
/* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */
#define FIX_ACPI_PAGES 4
......
......@@ -403,8 +403,8 @@ int acpi_pci_irq_init (void);
struct acpi_pci_driver {
struct acpi_pci_driver *next;
int (*add)(acpi_handle *handle);
void (*remove)(acpi_handle *handle);
int (*add)(acpi_handle handle);
void (*remove)(acpi_handle handle);
};
int acpi_pci_register_driver(struct acpi_pci_driver *driver);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment