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