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