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 22 ACPI_MODULE_NAME("event"); 23 24 #ifdef CONFIG_ACPI_PROC_EVENT 25 /* Global vars for handling event proc entry */ 26 static DEFINE_SPINLOCK(acpi_system_event_lock); 27 int event_is_open = 0; 28 extern struct list_head acpi_bus_event_list; 29 extern wait_queue_head_t acpi_bus_event_queue; 30 31 static 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 48 static ssize_t 49 acpi_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 92 static 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 100 static 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 108 static 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 */ 119 static BLOCKING_NOTIFIER_HEAD(acpi_chain_head); 120 121 int 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 } 132 EXPORT_SYMBOL(acpi_notifier_call_chain); 133 134 int register_acpi_notifier(struct notifier_block *nb) 135 { 136 return blocking_notifier_chain_register(&acpi_chain_head, nb); 137 } 138 EXPORT_SYMBOL(register_acpi_notifier); 139 140 int unregister_acpi_notifier(struct notifier_block *nb) 141 { 142 return blocking_notifier_chain_unregister(&acpi_chain_head, nb); 143 } 144 EXPORT_SYMBOL(unregister_acpi_notifier); 145 146 #ifdef CONFIG_NET 147 static unsigned int acpi_event_seqnum; 148 struct 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 */ 156 enum { 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 */ 164 enum { 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 175 static 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 182 static struct genl_multicast_group acpi_event_mcgrp = { 183 .name = ACPI_GENL_MCAST_GROUP_NAME, 184 }; 185 186 int 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 247 EXPORT_SYMBOL(acpi_bus_generate_netlink_event); 248 249 static 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 266 int 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 273 EXPORT_SYMBOL(acpi_bus_generate_netlink_event); 274 275 static int acpi_event_genetlink_init(void) 276 { 277 return -ENODEV; 278 } 279 #endif 280 281 static 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 308 fs_initcall(acpi_event_init); 309