at v3.5-rc2 308 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/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);