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 21 ACPI_MODULE_NAME("event"); 22 23 #ifdef CONFIG_ACPI_PROC_EVENT 24 /* Global vars for handling event proc entry */ 25 static DEFINE_SPINLOCK(acpi_system_event_lock); 26 int event_is_open = 0; 27 extern struct list_head acpi_bus_event_list; 28 extern wait_queue_head_t acpi_bus_event_queue; 29 30 static 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 47 static ssize_t 48 acpi_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 91 static 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 99 static 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 107 static 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 */ 118 static BLOCKING_NOTIFIER_HEAD(acpi_chain_head); 119 120 int 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 } 131 EXPORT_SYMBOL(acpi_notifier_call_chain); 132 133 int register_acpi_notifier(struct notifier_block *nb) 134 { 135 return blocking_notifier_chain_register(&acpi_chain_head, nb); 136 } 137 EXPORT_SYMBOL(register_acpi_notifier); 138 139 int unregister_acpi_notifier(struct notifier_block *nb) 140 { 141 return blocking_notifier_chain_unregister(&acpi_chain_head, nb); 142 } 143 EXPORT_SYMBOL(unregister_acpi_notifier); 144 145 #ifdef CONFIG_NET 146 static unsigned int acpi_event_seqnum; 147 struct 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 */ 155 enum { 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 */ 163 enum { 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 174 static 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 181 static struct genl_multicast_group acpi_event_mcgrp = { 182 .name = ACPI_GENL_MCAST_GROUP_NAME, 183 }; 184 185 int 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 246 EXPORT_SYMBOL(acpi_bus_generate_netlink_event); 247 248 static 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 265 int 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 272 EXPORT_SYMBOL(acpi_bus_generate_netlink_event); 273 274 static int acpi_event_genetlink_init(void) 275 { 276 return -ENODEV; 277 } 278 #endif 279 280 static 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 307 fs_initcall(acpi_event_init); 308