11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * event.c - exporting ACPI events via procfs 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 10214f2c90b970e098e75cf719c0c5b0f1fe69b716Paul Gortmaker#include <linux/export.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/poll.h> 145a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 158b48463f89429af408ff695244dc627e1acff4f7Lv Zheng#include <linux/acpi.h> 16864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#include <net/netlink.h> 17864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#include <net/genetlink.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19a192a9580bcc41692be1f36b77c3b681827f566aLen Brown#include "internal.h" 20a192a9580bcc41692be1f36b77c3b681827f566aLen Brown 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define _COMPONENT ACPI_SYSTEM_COMPONENT 22f52fd66d2ea794010c2d7536cf8e6abed0ac4947Len BrownACPI_MODULE_NAME("event"); 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 249ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui/* ACPI notifier chain */ 25c8e773fa4f6a999a80d9fa3836f412e259ab6fa1Adrian Bunkstatic BLOCKING_NOTIFIER_HEAD(acpi_chain_head); 269ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui 279ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Ruiint acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data) 289ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui{ 299ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui struct acpi_bus_event event; 309ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui 319ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui strcpy(event.device_class, dev->pnp.device_class); 329ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui strcpy(event.bus_id, dev->pnp.bus_id); 339ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui event.type = type; 349ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui event.data = data; 359ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event) 369ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui == NOTIFY_BAD) ? -EINVAL : 0; 379ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui} 389ee85241fdaab358dff1d8647f20a478cfa512a1Zhang RuiEXPORT_SYMBOL(acpi_notifier_call_chain); 399ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui 409ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Ruiint register_acpi_notifier(struct notifier_block *nb) 419ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui{ 429ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui return blocking_notifier_chain_register(&acpi_chain_head, nb); 439ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui} 449ee85241fdaab358dff1d8647f20a478cfa512a1Zhang RuiEXPORT_SYMBOL(register_acpi_notifier); 459ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui 469ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Ruiint unregister_acpi_notifier(struct notifier_block *nb) 479ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui{ 489ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui return blocking_notifier_chain_unregister(&acpi_chain_head, nb); 499ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui} 509ee85241fdaab358dff1d8647f20a478cfa512a1Zhang RuiEXPORT_SYMBOL(unregister_acpi_notifier); 519ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui 52864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#ifdef CONFIG_NET 53e13d87473284131a7ead8121d5d29345101f68a4Adrian Bunkstatic unsigned int acpi_event_seqnum; 54864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruistruct acpi_genl_event { 55864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui acpi_device_class device_class; 56864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui char bus_id[15]; 57864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui u32 type; 58864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui u32 data; 59864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui}; 60864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 61864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui/* attributes of acpi_genl_family */ 62864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruienum { 63864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui ACPI_GENL_ATTR_UNSPEC, 64864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui ACPI_GENL_ATTR_EVENT, /* ACPI event info needed by user space */ 65864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui __ACPI_GENL_ATTR_MAX, 66864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui}; 67864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1) 68864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 69864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui/* commands supported by the acpi_genl_family */ 70864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruienum { 71864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui ACPI_GENL_CMD_UNSPEC, 72864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui ACPI_GENL_CMD_EVENT, /* kernel->user notifications for ACPI events */ 73864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui __ACPI_GENL_CMD_MAX, 74864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui}; 75864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1) 76864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 779c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui#define ACPI_GENL_FAMILY_NAME "acpi_event" 789c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui#define ACPI_GENL_VERSION 0x01 799c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui#define ACPI_GENL_MCAST_GROUP_NAME "acpi_mc_group" 80864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 812a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Bergstatic const struct genl_multicast_group acpi_event_mcgrps[] = { 822a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg { .name = ACPI_GENL_MCAST_GROUP_NAME, }, 832a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg}; 842a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg 85864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruistatic struct genl_family acpi_event_genl_family = { 86864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui .id = GENL_ID_GENERATE, 879c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui .name = ACPI_GENL_FAMILY_NAME, 88864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui .version = ACPI_GENL_VERSION, 89864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui .maxattr = ACPI_GENL_ATTR_MAX, 902a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg .mcgrps = acpi_event_mcgrps, 912a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg .n_mcgrps = ARRAY_SIZE(acpi_event_mcgrps), 92864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui}; 93864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 94962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Ruiint acpi_bus_generate_netlink_event(const char *device_class, 95962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui const char *bus_id, 96864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui u8 type, int data) 97864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui{ 98864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui struct sk_buff *skb; 99864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui struct nlattr *attr; 100864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui struct acpi_genl_event *event; 101864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui void *msg_header; 102864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui int size; 103864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui int result; 104864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 105864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui /* allocate memory */ 106864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui size = nla_total_size(sizeof(struct acpi_genl_event)) + 107864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui nla_total_size(0); 108864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 109864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui skb = genlmsg_new(size, GFP_ATOMIC); 110864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui if (!skb) 111864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui return -ENOMEM; 112864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 113864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui /* add the genetlink message header */ 114864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++, 115864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui &acpi_event_genl_family, 0, 116864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui ACPI_GENL_CMD_EVENT); 117864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui if (!msg_header) { 118864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui nlmsg_free(skb); 119864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui return -ENOMEM; 120864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui } 121864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 122864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui /* fill the data */ 123864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui attr = 124864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui nla_reserve(skb, ACPI_GENL_ATTR_EVENT, 125864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui sizeof(struct acpi_genl_event)); 126864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui if (!attr) { 127864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui nlmsg_free(skb); 128864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui return -EINVAL; 129864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui } 130864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 131864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui event = nla_data(attr); 132864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui memset(event, 0, sizeof(struct acpi_genl_event)); 133864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 134962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui strcpy(event->device_class, device_class); 135962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui strcpy(event->bus_id, bus_id); 136864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui event->type = type; 137864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui event->data = data; 138864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 139864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui /* send multicast genetlink message */ 140864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui result = genlmsg_end(skb, msg_header); 141864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui if (result < 0) { 142864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui nlmsg_free(skb); 143864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui return result; 144864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui } 145864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 1462a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg genlmsg_multicast(&acpi_event_genl_family, skb, 0, 0, GFP_ATOMIC); 147864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui return 0; 148864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui} 149864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 150962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang RuiEXPORT_SYMBOL(acpi_bus_generate_netlink_event); 151962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui 152864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruistatic int acpi_event_genetlink_init(void) 153864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui{ 1542a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg return genl_register_family(&acpi_event_genl_family); 155864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui} 156864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 157864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#else 1583e069ee0c30d6f28b79e409ef2df1ffa427897aeLen Brownint acpi_bus_generate_netlink_event(const char *device_class, 1593e069ee0c30d6f28b79e409ef2df1ffa427897aeLen Brown const char *bus_id, 1603e069ee0c30d6f28b79e409ef2df1ffa427897aeLen Brown u8 type, int data) 161864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui{ 162864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui return 0; 163864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui} 164864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 16566baf327ae5d4c17e75d1f501145e79eaeeaf649Henrique de Moraes HolschuhEXPORT_SYMBOL(acpi_bus_generate_netlink_event); 166962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui 167864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruistatic int acpi_event_genetlink_init(void) 168864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui{ 169864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui return -ENODEV; 170864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui} 171864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#endif 172864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_event_init(void) 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error = 0; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (acpi_disabled) 178d550d98d3317378d93a4869db204725d270ec812Patrick Mochel return 0; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 180864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui /* create genetlink for acpi event */ 181864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui error = acpi_event_genetlink_init(); 182864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui if (error) 183864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui printk(KERN_WARNING PREFIX 184864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui "Failed to create genetlink family for ACPI event\n"); 185864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui return 0; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 188864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruifs_initcall(acpi_event_init); 189