| |
| #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); |
| |
| } |
| |