Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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