diff options
Diffstat (limited to 'drivers/acpi/event.c')
-rw-r--r-- | drivers/acpi/event.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c new file mode 100644 index 000000000000..43c49f66a328 --- /dev/null +++ b/drivers/acpi/event.c @@ -0,0 +1,140 @@ +/* + * event.c - exporting ACPI events via procfs + * + * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> + * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> + * + */ + +#include <linux/spinlock.h> +#include <linux/proc_fs.h> +#include <linux/init.h> +#include <linux/poll.h> +#include <acpi/acpi_drivers.h> + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME ("event") + +/* Global vars for handling event proc entry */ +static DEFINE_SPINLOCK(acpi_system_event_lock); +int event_is_open = 0; +extern struct list_head acpi_bus_event_list; +extern wait_queue_head_t acpi_bus_event_queue; + +static int +acpi_system_open_event(struct inode *inode, struct file *file) +{ + spin_lock_irq (&acpi_system_event_lock); + + if(event_is_open) + goto out_busy; + + event_is_open = 1; + + spin_unlock_irq (&acpi_system_event_lock); + return 0; + +out_busy: + spin_unlock_irq (&acpi_system_event_lock); + return -EBUSY; +} + +static ssize_t +acpi_system_read_event ( + struct file *file, + char __user *buffer, + size_t count, + loff_t *ppos) +{ + int result = 0; + struct acpi_bus_event event; + static char str[ACPI_MAX_STRING]; + static int chars_remaining = 0; + static char *ptr; + + + ACPI_FUNCTION_TRACE("acpi_system_read_event"); + + if (!chars_remaining) { + memset(&event, 0, sizeof(struct acpi_bus_event)); + + if ((file->f_flags & O_NONBLOCK) + && (list_empty(&acpi_bus_event_list))) + return_VALUE(-EAGAIN); + + result = acpi_bus_receive_event(&event); + if (result) { + return_VALUE(-EIO); + } + + chars_remaining = sprintf(str, "%s %s %08x %08x\n", + event.device_class?event.device_class:"<unknown>", + event.bus_id?event.bus_id:"<unknown>", + event.type, event.data); + ptr = str; + } + + if (chars_remaining < count) { + count = chars_remaining; + } + + if (copy_to_user(buffer, ptr, count)) + return_VALUE(-EFAULT); + + *ppos += count; + chars_remaining -= count; + ptr += count; + + return_VALUE(count); +} + +static int +acpi_system_close_event(struct inode *inode, struct file *file) +{ + spin_lock_irq (&acpi_system_event_lock); + event_is_open = 0; + spin_unlock_irq (&acpi_system_event_lock); + return 0; +} + +static unsigned int +acpi_system_poll_event( + struct file *file, + poll_table *wait) +{ + poll_wait(file, &acpi_bus_event_queue, wait); + if (!list_empty(&acpi_bus_event_list)) + return POLLIN | POLLRDNORM; + return 0; +} + +static struct file_operations acpi_system_event_ops = { + .open = acpi_system_open_event, + .read = acpi_system_read_event, + .release = acpi_system_close_event, + .poll = acpi_system_poll_event, +}; + +static int __init acpi_event_init(void) +{ + struct proc_dir_entry *entry; + int error = 0; + + ACPI_FUNCTION_TRACE("acpi_event_init"); + + if (acpi_disabled) + return_VALUE(0); + + /* 'event' [R] */ + entry = create_proc_entry("event", S_IRUSR, acpi_root_dir); + if (entry) + entry->proc_fops = &acpi_system_event_ops; + else { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Unable to create '%s' proc fs entry\n","event" )); + error = -EFAULT; + } + return_VALUE(error); +} + +subsys_initcall(acpi_event_init); |