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 }; 114 #endif /* CONFIG_ACPI_PROC_EVENT */ 115 116 /* ACPI notifier chain */ 117 static BLOCKING_NOTIFIER_HEAD(acpi_chain_head); 118 119 int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data) 120 { 121 struct acpi_bus_event event; 122 123 strcpy(event.device_class, dev->pnp.device_class); 124 strcpy(event.bus_id, dev->pnp.bus_id); 125 event.type = type; 126 event.data = data; 127 return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event) 128 == NOTIFY_BAD) ? -EINVAL : 0; 129 } 130 EXPORT_SYMBOL(acpi_notifier_call_chain); 131 132 int register_acpi_notifier(struct notifier_block *nb) 133 { 134 return blocking_notifier_chain_register(&acpi_chain_head, nb); 135 } 136 EXPORT_SYMBOL(register_acpi_notifier); 137 138 int unregister_acpi_notifier(struct notifier_block *nb) 139 { 140 return blocking_notifier_chain_unregister(&acpi_chain_head, nb); 141 } 142 EXPORT_SYMBOL(unregister_acpi_notifier); 143 144 #ifdef CONFIG_NET 145 static unsigned int acpi_event_seqnum; 146 struct acpi_genl_event { 147 acpi_device_class device_class; 148 char bus_id[15]; 149 u32 type; 150 u32 data; 151 }; 152 153 /* attributes of acpi_genl_family */ 154 enum { 155 ACPI_GENL_ATTR_UNSPEC, 156 ACPI_GENL_ATTR_EVENT, /* ACPI event info needed by user space */ 157 __ACPI_GENL_ATTR_MAX, 158 }; 159 #define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1) 160 161 /* commands supported by the acpi_genl_family */ 162 enum { 163 ACPI_GENL_CMD_UNSPEC, 164 ACPI_GENL_CMD_EVENT, /* kernel->user notifications for ACPI events */ 165 __ACPI_GENL_CMD_MAX, 166 }; 167 #define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1) 168 169 #define ACPI_GENL_FAMILY_NAME "acpi_event" 170 #define ACPI_GENL_VERSION 0x01 171 #define ACPI_GENL_MCAST_GROUP_NAME "acpi_mc_group" 172 173 static struct genl_family acpi_event_genl_family = { 174 .id = GENL_ID_GENERATE, 175 .name = ACPI_GENL_FAMILY_NAME, 176 .version = ACPI_GENL_VERSION, 177 .maxattr = ACPI_GENL_ATTR_MAX, 178 }; 179 180 static struct genl_multicast_group acpi_event_mcgrp = { 181 .name = ACPI_GENL_MCAST_GROUP_NAME, 182 }; 183 184 int acpi_bus_generate_netlink_event(const char *device_class, 185 const char *bus_id, 186 u8 type, int data) 187 { 188 struct sk_buff *skb; 189 struct nlattr *attr; 190 struct acpi_genl_event *event; 191 void *msg_header; 192 int size; 193 int result; 194 195 /* allocate memory */ 196 size = nla_total_size(sizeof(struct acpi_genl_event)) + 197 nla_total_size(0); 198 199 skb = genlmsg_new(size, GFP_ATOMIC); 200 if (!skb) 201 return -ENOMEM; 202 203 /* add the genetlink message header */ 204 msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++, 205 &acpi_event_genl_family, 0, 206 ACPI_GENL_CMD_EVENT); 207 if (!msg_header) { 208 nlmsg_free(skb); 209 return -ENOMEM; 210 } 211 212 /* fill the data */ 213 attr = 214 nla_reserve(skb, ACPI_GENL_ATTR_EVENT, 215 sizeof(struct acpi_genl_event)); 216 if (!attr) { 217 nlmsg_free(skb); 218 return -EINVAL; 219 } 220 221 event = nla_data(attr); 222 if (!event) { 223 nlmsg_free(skb); 224 return -EINVAL; 225 } 226 227 memset(event, 0, sizeof(struct acpi_genl_event)); 228 229 strcpy(event->device_class, device_class); 230 strcpy(event->bus_id, bus_id); 231 event->type = type; 232 event->data = data; 233 234 /* send multicast genetlink message */ 235 result = genlmsg_end(skb, msg_header); 236 if (result < 0) { 237 nlmsg_free(skb); 238 return result; 239 } 240 241 genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC); 242 return 0; 243 } 244 245 EXPORT_SYMBOL(acpi_bus_generate_netlink_event); 246 247 static int acpi_event_genetlink_init(void) 248 { 249 int result; 250 251 result = genl_register_family(&acpi_event_genl_family); 252 if (result) 253 return result; 254 255 result = genl_register_mc_group(&acpi_event_genl_family, 256 &acpi_event_mcgrp); 257 if (result) 258 genl_unregister_family(&acpi_event_genl_family); 259 260 return result; 261 } 262 263 #else 264 int acpi_bus_generate_netlink_event(const char *device_class, 265 const char *bus_id, 266 u8 type, int data) 267 { 268 return 0; 269 } 270 271 EXPORT_SYMBOL(acpi_bus_generate_netlink_event); 272 273 static int acpi_event_genetlink_init(void) 274 { 275 return -ENODEV; 276 } 277 #endif 278 279 static int __init acpi_event_init(void) 280 { 281 #ifdef CONFIG_ACPI_PROC_EVENT 282 struct proc_dir_entry *entry; 283 #endif 284 int error = 0; 285 286 if (acpi_disabled) 287 return 0; 288 289 /* create genetlink for acpi event */ 290 error = acpi_event_genetlink_init(); 291 if (error) 292 printk(KERN_WARNING PREFIX 293 "Failed to create genetlink family for ACPI event\n"); 294 295 #ifdef CONFIG_ACPI_PROC_EVENT 296 /* 'event' [R] */ 297 entry = proc_create("event", S_IRUSR, acpi_root_dir, 298 &acpi_system_event_ops); 299 if (!entry) 300 return -ENODEV; 301 #endif 302 303 return 0; 304 } 305 306 fs_initcall(acpi_event_init); 307