linux/drivers/acpi/event.c
<<
>>
Prefs
   1/*
   2 * event.c - exporting ACPI events via procfs
   3 *
   4 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
   5 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
   6 *
   7 */
   8
   9#include <linux/spinlock.h>
  10#include <linux/proc_fs.h>
  11#include <linux/init.h>
  12#include <linux/poll.h>
  13#include <acpi/acpi_drivers.h>
  14#include <net/netlink.h>
  15#include <net/genetlink.h>
  16
  17#define _COMPONENT              ACPI_SYSTEM_COMPONENT
  18ACPI_MODULE_NAME("event");
  19
  20#ifdef CONFIG_ACPI_PROC_EVENT
  21/* Global vars for handling event proc entry */
  22static DEFINE_SPINLOCK(acpi_system_event_lock);
  23int event_is_open = 0;
  24extern struct list_head acpi_bus_event_list;
  25extern wait_queue_head_t acpi_bus_event_queue;
  26
  27static int acpi_system_open_event(struct inode *inode, struct file *file)
  28{
  29        spin_lock_irq(&acpi_system_event_lock);
  30
  31        if (event_is_open)
  32                goto out_busy;
  33
  34        event_is_open = 1;
  35
  36        spin_unlock_irq(&acpi_system_event_lock);
  37        return 0;
  38
  39      out_busy:
  40        spin_unlock_irq(&acpi_system_event_lock);
  41        return -EBUSY;
  42}
  43
  44static ssize_t
  45acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
  46                       loff_t * ppos)
  47{
  48        int result = 0;
  49        struct acpi_bus_event event;
  50        static char str[ACPI_MAX_STRING];
  51        static int chars_remaining = 0;
  52        static char *ptr;
  53
  54        if (!chars_remaining) {
  55                memset(&event, 0, sizeof(struct acpi_bus_event));
  56
  57                if ((file->f_flags & O_NONBLOCK)
  58                    && (list_empty(&acpi_bus_event_list)))
  59                        return -EAGAIN;
  60
  61                result = acpi_bus_receive_event(&event);
  62                if (result)
  63                        return result;
  64
  65                chars_remaining = sprintf(str, "%s %s %08x %08x\n",
  66                                          event.device_class ? event.
  67                                          device_class : "<unknown>",
  68                                          event.bus_id ? event.
  69                                          bus_id : "<unknown>", event.type,
  70                                          event.data);
  71                ptr = str;
  72        }
  73
  74        if (chars_remaining < count) {
  75                count = chars_remaining;
  76        }
  77
  78        if (copy_to_user(buffer, ptr, count))
  79                return -EFAULT;
  80
  81        *ppos += count;
  82        chars_remaining -= count;
  83        ptr += count;
  84
  85        return count;
  86}
  87
  88static int acpi_system_close_event(struct inode *inode, struct file *file)
  89{
  90        spin_lock_irq(&acpi_system_event_lock);
  91        event_is_open = 0;
  92        spin_unlock_irq(&acpi_system_event_lock);
  93        return 0;
  94}
  95
  96static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait)
  97{
  98        poll_wait(file, &acpi_bus_event_queue, wait);
  99        if (!list_empty(&acpi_bus_event_list))
 100                return POLLIN | POLLRDNORM;
 101        return 0;
 102}
 103
 104static const struct file_operations acpi_system_event_ops = {
 105        .owner = THIS_MODULE,
 106        .open = acpi_system_open_event,
 107        .read = acpi_system_read_event,
 108        .release = acpi_system_close_event,
 109        .poll = acpi_system_poll_event,
 110};
 111#endif  /* CONFIG_ACPI_PROC_EVENT */
 112
 113/* ACPI notifier chain */
 114static BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
 115
 116int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data)
 117{
 118        struct acpi_bus_event event;
 119
 120        strcpy(event.device_class, dev->pnp.device_class);
 121        strcpy(event.bus_id, dev->pnp.bus_id);
 122        event.type = type;
 123        event.data = data;
 124        return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event)
 125                        == NOTIFY_BAD) ? -EINVAL : 0;
 126}
 127EXPORT_SYMBOL(acpi_notifier_call_chain);
 128
 129int register_acpi_notifier(struct notifier_block *nb)
 130{
 131        return blocking_notifier_chain_register(&acpi_chain_head, nb);
 132}
 133EXPORT_SYMBOL(register_acpi_notifier);
 134
 135int unregister_acpi_notifier(struct notifier_block *nb)
 136{
 137        return blocking_notifier_chain_unregister(&acpi_chain_head, nb);
 138}
 139EXPORT_SYMBOL(unregister_acpi_notifier);
 140
 141#ifdef CONFIG_NET
 142static unsigned int acpi_event_seqnum;
 143struct acpi_genl_event {
 144        acpi_device_class device_class;
 145        char bus_id[15];
 146        u32 type;
 147        u32 data;
 148};
 149
 150/* attributes of acpi_genl_family */
 151enum {
 152        ACPI_GENL_ATTR_UNSPEC,
 153        ACPI_GENL_ATTR_EVENT,   /* ACPI event info needed by user space */
 154        __ACPI_GENL_ATTR_MAX,
 155};
 156#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)
 157
 158/* commands supported by the acpi_genl_family */
 159enum {
 160        ACPI_GENL_CMD_UNSPEC,
 161        ACPI_GENL_CMD_EVENT,    /* kernel->user notifications for ACPI events */
 162        __ACPI_GENL_CMD_MAX,
 163};
 164#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1)
 165
 166#define ACPI_GENL_FAMILY_NAME           "acpi_event"
 167#define ACPI_GENL_VERSION               0x01
 168#define ACPI_GENL_MCAST_GROUP_NAME      "acpi_mc_group"
 169
 170static struct genl_family acpi_event_genl_family = {
 171        .id = GENL_ID_GENERATE,
 172        .name = ACPI_GENL_FAMILY_NAME,
 173        .version = ACPI_GENL_VERSION,
 174        .maxattr = ACPI_GENL_ATTR_MAX,
 175};
 176
 177static struct genl_multicast_group acpi_event_mcgrp = {
 178        .name = ACPI_GENL_MCAST_GROUP_NAME,
 179};
 180
 181int acpi_bus_generate_netlink_event(const char *device_class,
 182                                      const char *bus_id,
 183                                      u8 type, int data)
 184{
 185        struct sk_buff *skb;
 186        struct nlattr *attr;
 187        struct acpi_genl_event *event;
 188        void *msg_header;
 189        int size;
 190        int result;
 191
 192        /* allocate memory */
 193        size = nla_total_size(sizeof(struct acpi_genl_event)) +
 194            nla_total_size(0);
 195
 196        skb = genlmsg_new(size, GFP_ATOMIC);
 197        if (!skb)
 198                return -ENOMEM;
 199
 200        /* add the genetlink message header */
 201        msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
 202                                 &acpi_event_genl_family, 0,
 203                                 ACPI_GENL_CMD_EVENT);
 204        if (!msg_header) {
 205                nlmsg_free(skb);
 206                return -ENOMEM;
 207        }
 208
 209        /* fill the data */
 210        attr =
 211            nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
 212                        sizeof(struct acpi_genl_event));
 213        if (!attr) {
 214                nlmsg_free(skb);
 215                return -EINVAL;
 216        }
 217
 218        event = nla_data(attr);
 219        if (!event) {
 220                nlmsg_free(skb);
 221                return -EINVAL;
 222        }
 223
 224        memset(event, 0, sizeof(struct acpi_genl_event));
 225
 226        strcpy(event->device_class, device_class);
 227        strcpy(event->bus_id, bus_id);
 228        event->type = type;
 229        event->data = data;
 230
 231        /* send multicast genetlink message */
 232        result = genlmsg_end(skb, msg_header);
 233        if (result < 0) {
 234                nlmsg_free(skb);
 235                return result;
 236        }
 237
 238        genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
 239        return 0;
 240}
 241
 242EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
 243
 244static int acpi_event_genetlink_init(void)
 245{
 246        int result;
 247
 248        result = genl_register_family(&acpi_event_genl_family);
 249        if (result)
 250                return result;
 251
 252        result = genl_register_mc_group(&acpi_event_genl_family,
 253                                        &acpi_event_mcgrp);
 254        if (result)
 255                genl_unregister_family(&acpi_event_genl_family);
 256
 257        return result;
 258}
 259
 260#else
 261int acpi_bus_generate_netlink_event(const char *device_class,
 262                                      const char *bus_id,
 263                                      u8 type, int data)
 264{
 265        return 0;
 266}
 267
 268EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
 269
 270static int acpi_event_genetlink_init(void)
 271{
 272        return -ENODEV;
 273}
 274#endif
 275
 276static int __init acpi_event_init(void)
 277{
 278#ifdef CONFIG_ACPI_PROC_EVENT
 279        struct proc_dir_entry *entry;
 280#endif
 281        int error = 0;
 282
 283        if (acpi_disabled)
 284                return 0;
 285
 286        /* create genetlink for acpi event */
 287        error = acpi_event_genetlink_init();
 288        if (error)
 289                printk(KERN_WARNING PREFIX
 290                       "Failed to create genetlink family for ACPI event\n");
 291
 292#ifdef CONFIG_ACPI_PROC_EVENT
 293        /* 'event' [R] */
 294        entry = proc_create("event", S_IRUSR, acpi_root_dir,
 295                            &acpi_system_event_ops);
 296        if (!entry)
 297                return -ENODEV;
 298#endif
 299
 300        return 0;
 301}
 302
 303fs_initcall(acpi_event_init);
 304