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