blob: 262d2c5b8fb9c630d13aa7251df5b1f6c36add63 [file] [log] [blame]
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/pm.h>
#include <linux/acpi.h>
#include <linux/genhd.h>
#include <asm/uaccess.h>
#include "LtpAcpi.h"
static int ltpdev_open( struct inode *inode, struct file *pfile);
static int ltpdev_release( struct inode *inode, struct file *pfile);
static int ltpdev_ioctl ( struct inode *pinode, struct file *pfile, unsigned int cmd, unsigned long arg );
static void acpi_bus_notify (acpi_handle handle, u32 type, void *data);
static void acpi_ec_gpe_handler (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);
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);
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 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
*/
static struct pm_dev *ltp_pm_dev = NULL;
extern struct acpi_device *acpi_root;
static int ltpdev_open (struct inode *pinode, struct file *pfile)
{
printk(KERN_ALERT "ltpdev_open \n");
return 0;
}
static int ltpdev_release (struct inode *pinode, struct file *pfile)
{
printk(KERN_ALERT "ltpdev_release \n");
return 0;
}
static int ltpdev_ioctl ( struct inode *pinode, struct file *pfile, unsigned int 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_handle tmp_handle;
acpi_status level;
struct acpi_buffer dsdt = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_table_ecdt *ecdt_ptr;
struct acpi_ec *ec;
struct acpi_device *device;
struct acpi_buffer buffer = {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, i, bm_status;
u8 type_a, type_b;
/*****************************************************************************/
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_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);
printk(KERN_ALERT "TEST -- acpi_get_firmware_table \n");
status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
(struct acpi_table_header **) &ecdt_ptr);
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_bus_get_device \n");
status = acpi_bus_get_device(next_child_handle, &device);
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(ec->gpe_bit, ACPI_EVENT_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(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);
}
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);
}
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_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);
}
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");
acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS,
&bm_status, ACPI_MTX_DO_NOT_LOCK);
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);
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);
}
}
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);
}
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);
}
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)
{
acpi_status status;
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;
}
static int ltp_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
{
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 void acpi_ec_gpe_handler (void *data)
{
printk(KERN_ALERT "Register ACPI ec_gpe_handler callback function \n");
}
static acpi_status acpi_ec_io_ports (struct acpi_resource *resource, void *context)
{
return 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;
}
int init_module(void)
{
int result;
printk(KERN_ALERT "ltpdev_init_module \n");
ltp_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, ltp_pm_callback);
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->capacity = MAX_NUM_DISKS;
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");
pm_unregister(ltp_pm_dev);
put_disk(gd_ptr);
del_gendisk(gd_ptr);
unregister_blkdev(ltp_acpi_major, LTP_ACPI_DEV_NAME);
}