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 20 ACPI_MODULE_NAME("event"); 21 22 #ifdef CONFIG_ACPI_PROC_EVENT 23 /* Global vars for handling event proc entry */ 24 static DEFINE_SPINLOCK(acpi_system_event_lock); 25 int event_is_open = 0; 26 extern struct list_head acpi_bus_event_list; 27 extern wait_queue_head_t acpi_bus_event_queue; 28 29 static 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 46 static ssize_t 47 acpi_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 90 static 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 98 static 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 106 static 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 */ 116 static BLOCKING_NOTIFIER_HEAD(acpi_chain_head); 117 118 int 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 } 129 EXPORT_SYMBOL(acpi_notifier_call_chain); 130 131 int register_acpi_notifier(struct notifier_block *nb) 132 { 133 return blocking_notifier_chain_register(&acpi_chain_head, nb); 134 } 135 EXPORT_SYMBOL(register_acpi_notifier); 136 137 int unregister_acpi_notifier(struct notifier_block *nb) 138 { 139 return blocking_notifier_chain_unregister(&acpi_chain_head, nb); 140 } 141 EXPORT_SYMBOL(unregister_acpi_notifier); 142 143 #ifdef CONFIG_NET 144 static unsigned int acpi_event_seqnum; 145 struct 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 */ 153 enum { 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 */ 161 enum { 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 172 static 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 179 static struct genl_multicast_group acpi_event_mcgrp = { 180 .name = ACPI_GENL_MCAST_GROUP_NAME, 181 }; 182 183 int 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 244 EXPORT_SYMBOL(acpi_bus_generate_netlink_event); 245 246 static 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 263 int 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 270 EXPORT_SYMBOL(acpi_bus_generate_netlink_event); 271 272 static int acpi_event_genetlink_init(void) 273 { 274 return -ENODEV; 275 } 276 #endif 277 278 static 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 305 fs_initcall(acpi_event_init); 306