1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * event.c - exporting ACPI events via procfs 4 * 5 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 6 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 7 * 8 */ 9 10 #include <linux/spinlock.h> 11 #include <linux/export.h> 12 #include <linux/proc_fs.h> 13 #include <linux/init.h> 14 #include <linux/poll.h> 15 #include <linux/gfp.h> 16 #include <linux/acpi.h> 17 #include <net/netlink.h> 18 #include <net/genetlink.h> 19 20 #include "internal.h" 21 22 #define _COMPONENT ACPI_SYSTEM_COMPONENT 23 ACPI_MODULE_NAME("event"); 24 25 /* ACPI notifier chain */ 26 static BLOCKING_NOTIFIER_HEAD(acpi_chain_head); 27 28 int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data) 29 { 30 struct acpi_bus_event event; 31 32 strcpy(event.device_class, dev->pnp.device_class); 33 strcpy(event.bus_id, dev->pnp.bus_id); 34 event.type = type; 35 event.data = data; 36 return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event) 37 == NOTIFY_BAD) ? -EINVAL : 0; 38 } 39 EXPORT_SYMBOL(acpi_notifier_call_chain); 40 41 int register_acpi_notifier(struct notifier_block *nb) 42 { 43 return blocking_notifier_chain_register(&acpi_chain_head, nb); 44 } 45 EXPORT_SYMBOL(register_acpi_notifier); 46 47 int unregister_acpi_notifier(struct notifier_block *nb) 48 { 49 return blocking_notifier_chain_unregister(&acpi_chain_head, nb); 50 } 51 EXPORT_SYMBOL(unregister_acpi_notifier); 52 53 #ifdef CONFIG_NET 54 static unsigned int acpi_event_seqnum; 55 struct acpi_genl_event { 56 acpi_device_class device_class; 57 char bus_id[15]; 58 u32 type; 59 u32 data; 60 }; 61 62 /* attributes of acpi_genl_family */ 63 enum { 64 ACPI_GENL_ATTR_UNSPEC, 65 ACPI_GENL_ATTR_EVENT, /* ACPI event info needed by user space */ 66 __ACPI_GENL_ATTR_MAX, 67 }; 68 #define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1) 69 70 /* commands supported by the acpi_genl_family */ 71 enum { 72 ACPI_GENL_CMD_UNSPEC, 73 ACPI_GENL_CMD_EVENT, /* kernel->user notifications for ACPI events */ 74 __ACPI_GENL_CMD_MAX, 75 }; 76 #define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1) 77 78 #define ACPI_GENL_FAMILY_NAME "acpi_event" 79 #define ACPI_GENL_VERSION 0x01 80 #define ACPI_GENL_MCAST_GROUP_NAME "acpi_mc_group" 81 82 static const struct genl_multicast_group acpi_event_mcgrps[] = { 83 { .name = ACPI_GENL_MCAST_GROUP_NAME, }, 84 }; 85 86 static struct genl_family acpi_event_genl_family __ro_after_init = { 87 .module = THIS_MODULE, 88 .name = ACPI_GENL_FAMILY_NAME, 89 .version = ACPI_GENL_VERSION, 90 .maxattr = ACPI_GENL_ATTR_MAX, 91 .mcgrps = acpi_event_mcgrps, 92 .n_mcgrps = ARRAY_SIZE(acpi_event_mcgrps), 93 }; 94 95 int acpi_bus_generate_netlink_event(const char *device_class, 96 const char *bus_id, 97 u8 type, int data) 98 { 99 struct sk_buff *skb; 100 struct nlattr *attr; 101 struct acpi_genl_event *event; 102 void *msg_header; 103 int size; 104 105 /* allocate memory */ 106 size = nla_total_size(sizeof(struct acpi_genl_event)) + 107 nla_total_size(0); 108 109 skb = genlmsg_new(size, GFP_ATOMIC); 110 if (!skb) 111 return -ENOMEM; 112 113 /* add the genetlink message header */ 114 msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++, 115 &acpi_event_genl_family, 0, 116 ACPI_GENL_CMD_EVENT); 117 if (!msg_header) { 118 nlmsg_free(skb); 119 return -ENOMEM; 120 } 121 122 /* fill the data */ 123 attr = 124 nla_reserve(skb, ACPI_GENL_ATTR_EVENT, 125 sizeof(struct acpi_genl_event)); 126 if (!attr) { 127 nlmsg_free(skb); 128 return -EINVAL; 129 } 130 131 event = nla_data(attr); 132 memset(event, 0, sizeof(struct acpi_genl_event)); 133 134 strcpy(event->device_class, device_class); 135 strcpy(event->bus_id, bus_id); 136 event->type = type; 137 event->data = data; 138 139 /* send multicast genetlink message */ 140 genlmsg_end(skb, msg_header); 141 142 genlmsg_multicast(&acpi_event_genl_family, skb, 0, 0, GFP_ATOMIC); 143 return 0; 144 } 145 146 EXPORT_SYMBOL(acpi_bus_generate_netlink_event); 147 148 static int __init acpi_event_genetlink_init(void) 149 { 150 return genl_register_family(&acpi_event_genl_family); 151 } 152 153 #else 154 int acpi_bus_generate_netlink_event(const char *device_class, 155 const char *bus_id, 156 u8 type, int data) 157 { 158 return 0; 159 } 160 161 EXPORT_SYMBOL(acpi_bus_generate_netlink_event); 162 163 static int acpi_event_genetlink_init(void) 164 { 165 return -ENODEV; 166 } 167 #endif 168 169 static int __init acpi_event_init(void) 170 { 171 int error = 0; 172 173 if (acpi_disabled) 174 return 0; 175 176 /* create genetlink for acpi event */ 177 error = acpi_event_genetlink_init(); 178 if (error) 179 printk(KERN_WARNING PREFIX 180 "Failed to create genetlink family for ACPI event\n"); 181 return 0; 182 } 183 184 fs_initcall(acpi_event_init); 185