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