blob: 693397f7588a68a6bd0a00c6065d4387e4cf1be5 [file] [log] [blame]
/*
*
* Copyright (c) International Business Machines Corp., 2001
*
* 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
*/
/*
* FILE : LtpAcpiCmds.c
* DESCRIPTION :
* HISTORY:
* 06/09/2003 Initial creation mridge@us.ibm.com
* -Ported
* updated - 01/09/2005 Updates from Intel to add functionality
*
* 01/03/2009 Márton Németh <nm127@freemail.hu>
* - Updated for Linux kernel 2.6.28
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/ioctl.h>
#include <linux/pm.h>
#include <linux/acpi.h>
#include <linux/genhd.h>
#include <asm/uaccess.h>
#include "LtpAcpi.h"
#ifndef ACPI_EC_UDELAY_GLK
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
#endif
static int ltpdev_open(struct block_device *bdev, fmode_t mode);
static int ltpdev_release(struct gendisk *disk, fmode_t mode);
static int ltpdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, unsigned long arg);
static u32 ltp_test_sleep_button_ev_handler(void *context);
static u32 ltp_test_power_button_ev_handler(void *context);
static u32 acpi_ec_gpe_handler(void *context);
static void acpi_bus_notify (acpi_handle handle, u32 type, void *data);
static acpi_status ltp_get_dev_callback (acpi_handle obj, u32 depth, void *context, void **ret);
static acpi_status acpi_ec_io_ports (struct acpi_resource *resource, void *context);
#if 0
static acpi_status acpi_ec_space_setup (acpi_handle region_handle,
u32 function,
void *handler_context,
void **return_context);
static acpi_status acpi_ec_space_handler (u32 function,
acpi_physical_address address,
u32 bit_width,
acpi_integer *value,
void *handler_context,
void *region_context);
#endif
static struct block_device_operations blkops = {
open: ltpdev_open,
release: ltpdev_release,
ioctl: ltpdev_ioctl,
};
int ltp_acpi_major = LTPMAJOR;
int test_iteration = 0;
static char genhd_flags = 0;
static struct gendisk * gd_ptr;
struct acpi_ec {
acpi_handle handle;
unsigned long uid;
unsigned long long gpe_bit;
struct acpi_generic_address status_addr;
struct acpi_generic_address command_addr;
struct acpi_generic_address data_addr;
unsigned long global_lock;
spinlock_t lock;
};
MODULE_AUTHOR("Martin Ridgeway <mridge@us.ibm.com>");
MODULE_DESCRIPTION(ACPI_LTP_TEST_DRIVER_NAME);
MODULE_LICENSE("GPL");
/*
* Device operations for the virtual ACPI devices
*/
extern struct acpi_device *acpi_root;
static int ltpdev_open(struct block_device *dev, fmode_t mode)
{
printk(KERN_ALERT "ltpdev_open \n");
return 0;
}
static int ltpdev_release(struct gendisk *disk, fmode_t mode)
{
printk(KERN_ALERT "ltpdev_release \n");
return 0;
}
static u32 ltp_test_power_button_ev_handler(void *context)
{
printk(KERN_ALERT "ltp_test_power_button_ev_handler \n");
return 1;
}
static u32 ltp_test_sleep_button_ev_handler(void *context)
{
printk(KERN_ALERT "ltp_test_sleep_button_ev_handler \n");
return 1;
}
static int ltpdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, unsigned long arg)
{
acpi_status status;
// acpi_handle sys_bus_handle;
acpi_handle start_handle = 0;
acpi_handle parent_handle;
acpi_handle child_handle;
acpi_handle next_child_handle;
acpi_status level;
struct acpi_ec *ec;
struct acpi_device *device;
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
#if 0
acpi_handle tmp_handle;
struct acpi_table_ecdt *ecdt_ptr;
struct acpi_buffer dsdt = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_buffer batt_buffer = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_buffer format = {sizeof(ACPI_BATTERY_FORMAT_BIF),
ACPI_BATTERY_FORMAT_BIF};
struct acpi_buffer data = {0, NULL};
union acpi_object *package = NULL;
u32 start_ticks, stop_ticks, total_ticks;
#endif
u32 i, bm_status;
u8 type_a, type_b;
u32 global_lock = 0;
int state = 0;
/*****************************************************************************/
printk(KERN_ALERT "ltpdev_ioctl \n");
switch (cmd) {
case LTPDEV_CMD:
parent_handle = start_handle;
child_handle = 0;
level = 1;
test_iteration++;
printk(KERN_ALERT "-- IOCTL called to start ACPI tests -- Iteration:%d\n",test_iteration);
printk(KERN_ALERT "TEST -- acpi_get_handle \n");
status = acpi_get_handle (0, ACPI_NS_SYSTEM_BUS, &parent_handle);
printk(KERN_ALERT "TEST -- acpi_get_object_info \n");
status = acpi_get_object_info (parent_handle, &buffer);
printk(KERN_ALERT "TEST -- acpi_get_next_object \n");
status = acpi_get_next_object (ACPI_TYPE_ANY, parent_handle,
child_handle, &next_child_handle);
printk(KERN_ALERT "TEST -- acpi_get_parent \n");
status = acpi_get_parent(parent_handle, &parent_handle);
printk(KERN_ALERT "TEST -- acpi_evaluate_object \n");
status = acpi_evaluate_object(parent_handle, "_ON", NULL, NULL);
printk(KERN_ALERT "TEST -- acpi_get_table \n");
// status = acpi_get_table(ACPI_TABLE_RSDP, 1, &dsdt);
// status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt);
// status = acpi_get_table(ACPI_TABLE_FADT, 1, &dsdt);
// status = acpi_get_table(ACPI_TABLE_FACS, 1, &dsdt);
// status = acpi_get_table(ACPI_TABLE_PSDT, 1, &dsdt);
// status = acpi_get_table(ACPI_TABLE_SSDT, 1, &dsdt);
// status = acpi_get_table(ACPI_TABLE_XSDT, 1, &dsdt);
#if 0
printk(KERN_ALERT "TEST -- acpi_get_firmware_table \n");
status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
(struct acpi_table_header **) &dsdt);
#endif
printk(KERN_ALERT "TEST -- acpi_install_notify_handler \n");
status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY, &acpi_bus_notify, NULL);
printk(KERN_ALERT "TEST -- acpi_remove_notify_handler \n");
status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY, &acpi_bus_notify);
printk(KERN_ALERT "TEST -- acpi_install_fixed_event_handler \n");
status = acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, ltp_test_power_button_ev_handler, NULL);
if (status)
printk(KERN_ALERT "Failed installing fixed event handler \n");
printk(KERN_ALERT "TEST -- acpi_remove_fixed_event_handler \n");
status = acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, ltp_test_power_button_ev_handler);
if (status)
printk(KERN_ALERT "Failed removing fixed event handler \n");
printk(KERN_ALERT "TEST -- acpi_install_fixed_event_handler \n");
status = acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, ltp_test_sleep_button_ev_handler, NULL);
if (status)
printk(KERN_ALERT "Failed installing fixed event handler \n");
printk(KERN_ALERT "TEST -- acpi_remove_fixed_event_handler \n");
status = acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, ltp_test_sleep_button_ev_handler);
if (status)
printk(KERN_ALERT "Failed removing fixed event handler \n");
printk(KERN_ALERT "TEST -- acpi_acquire_global_lock \n");
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &global_lock);
printk(KERN_ALERT "TEST -- acpi_release_global_lock \n");
status = acpi_release_global_lock(global_lock);
printk(KERN_ALERT "TEST -- acpi_bus_get_device \n");
status = acpi_bus_get_device(next_child_handle, &device);
#if 0
printk(KERN_ALERT "TEST -- acpi_bus_find_driver \n");
status = acpi_bus_find_driver(device);
#endif
printk(KERN_ALERT "TEST -- acpi_bus_get_power \n");
status = acpi_bus_get_power(next_child_handle, &state);
if (status)
printk(KERN_ALERT "Error reading power state \n");
printk(KERN_ALERT "TEST -- acpi_driver_data \n");
ec = acpi_driver_data(device);
if (!ec) {
printk(KERN_ALERT "Failure getting device data \n");
}
else {
printk(KERN_ALERT "TEST -- acpi_install_gpe_handler \n");
ec->status_addr = ec->command_addr;
status = acpi_install_gpe_handler(device, ec->gpe_bit, ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec);
/*
status = acpi_install_address_space_handler (ACPI_ROOT_OBJECT,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler,
&acpi_ec_space_setup, ec);
if (status) {
printk(KERN_ALERT "Failed installing address space handler \n");
}
acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler);
*/
printk(KERN_ALERT "TEST -- acpi_remove_gpe_handler \n");
acpi_remove_gpe_handler(device, ec->gpe_bit, &acpi_ec_gpe_handler);
}
printk(KERN_ALERT "TEST -- acpi_get_current_resources \n");
status = acpi_get_current_resources (next_child_handle, &buffer);
if (status) {
printk(KERN_ALERT "Failed get_current_resources %d\n",status);
}
#ifdef ACPI_FUTURE_USAGE
printk(KERN_ALERT "TEST -- acpi_get_possible_resources \n");
status = acpi_get_possible_resources (next_child_handle, &buffer);
if (status) {
printk(KERN_ALERT "Failed get_possible_resources %d\n",status);
}
#endif
printk(KERN_ALERT "TEST -- acpi_walk_resources \n");
status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
acpi_ec_io_ports, ec);
if (status) {
printk(KERN_ALERT "Failed walk_resources %d\n",status);
}
printk(KERN_ALERT "TEST -- acpi_evaluate_integer \n");
status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe_bit);
if (status)
printk(KERN_ALERT "Error obtaining GPE bit assignment\n");
#if 0
printk(KERN_ALERT "TEST -- acpi_get_timer \n");
status = acpi_get_timer(&total_ticks);
if (status) {
printk(KERN_ALERT "Failed get_timer %d\n",status);
}
else {
printk(KERN_ALERT "get_timer -- total_ticks %d\n",total_ticks);
}
start_ticks = 20;
stop_ticks = 30;
printk(KERN_ALERT "TEST -- acpi_get_timer_duration \n");
status = acpi_get_timer_duration(start_ticks, stop_ticks, &total_ticks);
if (status) {
printk(KERN_ALERT "Failed get_timer_duration %d\n",status);
}
else {
printk(KERN_ALERT "get_timer_duration total_ticks %d\n",total_ticks);
}
#endif
for (i = 0; i < ACPI_S_STATE_COUNT; i++) {
printk(KERN_ALERT "TEST -- acpi_get_sleep_type_data \n");
status = acpi_get_sleep_type_data(i, &type_a, &type_b);
if (status) {
printk(KERN_ALERT "Failed get_sleep_type_data %d\n",status);
}
else {
printk(KERN_ALERT "get_sleep_type_data [%d] type_a:%d type_b:%d\n",i, type_a,type_b);
}
}
printk(KERN_ALERT "TEST -- acpi_get_register \n");
/*
* ACPICA: Remove obsolete Flags parameter.
* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=d8c71b6d3b21cf21ad775e1cf6da95bf87bd5ad4
*
*/
acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
if (!bm_status) {
printk(KERN_ALERT "Failed get_register [%d]\n",bm_status);
}
else {
printk(KERN_ALERT "get_register [%d] \n",bm_status);
}
// Puts system to sleep, permenately !!!
// status = acpi_enter_sleep_state(ACPI_STATE_S1);
#if 0
printk(KERN_ALERT "TEST -- acpi_get_system_info \n");
status = acpi_get_system_info(&buffer);
if (status) {
printk(KERN_ALERT "Failed get_system_info %d\n",status);
}
else {
printk(KERN_ALERT "get_system_info buffer.length:%d buffer.pointer:%p\n",buffer.length, buffer.pointer);
acpi_os_printf("os_printf OK %d\n",status);
if (buffer.pointer) {
acpi_os_free(buffer.pointer);
}
}
#endif
printk(KERN_ALERT "TEST -- acpi_get_devices \n");
status = acpi_get_devices(NULL, ltp_get_dev_callback, "LTP0001", NULL);
if (status) {
printk(KERN_ALERT "Failed get_devices %d\n",status);
}
// status = acpi_os_create_semaphore(1, 1, &tmp_handle);
if (status) {
printk(KERN_ALERT "Failed os_create_semaphore %d\n",status);
}
else {
printk(KERN_ALERT "os_create_semaphore OK, no deleteing %d\n",status);
// acpi_os_delete_semaphore(tmp_handle);
}
#if 0
printk(KERN_ALERT "TEST -- acpi_get_system_info \n");
status = acpi_get_system_info(&batt_buffer);
if (status) {
printk(KERN_ALERT "Failed get_system_info %d\n",status);
}
else {
printk(KERN_ALERT "get_system_info buffer.length:%d buffer.pointer:%p\n",buffer.length, buffer.pointer);
package = (union acpi_object *) batt_buffer.pointer;
/* Extract Package Data */
printk(KERN_ALERT "TEST -- acpi_extract_package \n");
status = acpi_extract_package(package, &format, &data);
data.pointer = kmalloc(data.length, GFP_KERNEL);
if (!data.pointer) {
printk(KERN_ALERT "Failed getting memory kalloc \n");
}
else {
memset(data.pointer, 0, data.length);
printk(KERN_ALERT "TEST -- acpi_extract_package \n");
status = acpi_extract_package(package, &format, &data);
kfree(data.pointer);
}
// acpi_os_free(buffer.pointer);
}
#endif
printk(KERN_ALERT "-- IOCTL ACPI tests Complete -- Iteration:%d\n",test_iteration);
break;
}
return 0;
}
static acpi_status ltp_get_dev_callback (acpi_handle obj, u32 depth, void *context, void **ret)
{
char *name = context;
char fullname[20];
/*
* Only SBA shows up in ACPI namespace, so its CSR space
* includes both SBA and IOC. Make SBA and IOC show up
* separately in PCI space.
*/
sprintf(fullname, "%s SBA", name);
printk(KERN_ALERT "get_dev_callback SBA name %s \n", fullname);
sprintf(fullname, "%s IOC", name);
printk(KERN_ALERT "get_dev_callback IOC name %s \n", fullname);
return 0;
}
/**
* acpi_bus_notify
* ---------------
* Callback for all 'system-level' device notifications (values 0x00-0x7F).
*/
static void acpi_bus_notify (acpi_handle handle,
u32 type,
void *data)
{
printk(KERN_ALERT "Register ACPI Bus Notify callback function \n");
}
static u32 acpi_ec_gpe_handler(void *context)
{
printk(KERN_ALERT "Register ACPI ec_gpe_handler callback function \n");
return 1;
}
static acpi_status acpi_ec_io_ports (struct acpi_resource *resource, void *context)
{
return 0;
}
#if 0
static acpi_status acpi_ec_space_handler (u32 function,
acpi_physical_address address,
u32 bit_width,
acpi_integer *value,
void *handler_context,
void *region_context)
{
int result = 0;
struct acpi_ec *ec = NULL;
u32 temp = 0;
ACPI_FUNCTION_TRACE("acpi_ec_space_handler");
if ((address > 0xFF) || (bit_width != 8) || !value || !handler_context)
return_VALUE(AE_BAD_PARAMETER);
ec = (struct acpi_ec *) handler_context;
switch (function) {
case ACPI_READ:
result = 0;
*value = (acpi_integer) temp;
break;
case ACPI_WRITE:
result = 0;
break;
default:
result = -EINVAL;
break;
}
switch (result) {
case -EINVAL:
return_VALUE(AE_BAD_PARAMETER);
break;
case -ENODEV:
return_VALUE(AE_NOT_FOUND);
break;
case -ETIME:
return_VALUE(AE_TIME);
break;
default:
return_VALUE(AE_OK);
}
}
static acpi_status acpi_ec_space_setup (
acpi_handle region_handle,
u32 function,
void *handler_context,
void **return_context)
{
/*
* The EC object is in the handler context and is needed
* when calling the acpi_ec_space_handler.
*/
*return_context = handler_context;
return AE_OK;
}
#endif
int init_module(void)
{
int result;
printk(KERN_ALERT "ltpdev_init_module \n");
result = register_blkdev(ltp_acpi_major, LTP_ACPI_DEV_NAME);
printk(KERN_ALERT "LTP ACPI: register_blkdev result=%d major %d\n",result, ltp_acpi_major);
if (result < 0) {
printk(KERN_ALERT "LTP ACPI: can't get major %d\n",ltp_acpi_major);
return result;
}
// if (ltp_acpi_major == 0)
// ltp_acpi_major = result; /* dynamic */
gd_ptr = kmalloc(sizeof(struct gendisk *), GFP_KERNEL);
if (!gd_ptr) {
printk(KERN_ALERT "ERROR getting memory !!!\n");
return 0;
}
gd_ptr = alloc_disk(1);
printk(KERN_ALERT "gd_ptr after alloc = %p \n",gd_ptr);
gd_ptr->major = ltp_acpi_major;
gd_ptr->first_minor = 0;
gd_ptr->fops = &blkops;
// gd_ptr->minor_shift = MINOR_SHIFT_BITS;
gd_ptr->driverfs_dev = NULL;
// gd_ptr->disk_de = NULL;
gd_ptr->flags = genhd_flags;
sprintf(gd_ptr->disk_name, LTP_ACPI_DEV_NAME);
add_disk(gd_ptr);
return 0;
}
void cleanup_module(void)
{
printk(KERN_ALERT "Exiting module and cleaning up \n");
put_disk(gd_ptr);
del_gendisk(gd_ptr);
unregister_blkdev(ltp_acpi_major, LTP_ACPI_DEV_NAME);
}