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