Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * event.c - exporting ACPI events via procfs
0004  *
0005  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
0006  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
0007  *
0008  */
0009 
0010 #define pr_fmt(fmt) "ACPI: " fmt
0011 
0012 #include <linux/spinlock.h>
0013 #include <linux/export.h>
0014 #include <linux/proc_fs.h>
0015 #include <linux/init.h>
0016 #include <linux/poll.h>
0017 #include <linux/gfp.h>
0018 #include <linux/acpi.h>
0019 #include <net/netlink.h>
0020 #include <net/genetlink.h>
0021 
0022 #include "internal.h"
0023 
0024 /* ACPI notifier chain */
0025 static BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
0026 
0027 int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data)
0028 {
0029     struct acpi_bus_event event;
0030 
0031     strcpy(event.device_class, dev->pnp.device_class);
0032     strcpy(event.bus_id, dev->pnp.bus_id);
0033     event.type = type;
0034     event.data = data;
0035     return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event)
0036             == NOTIFY_BAD) ? -EINVAL : 0;
0037 }
0038 EXPORT_SYMBOL(acpi_notifier_call_chain);
0039 
0040 int register_acpi_notifier(struct notifier_block *nb)
0041 {
0042     return blocking_notifier_chain_register(&acpi_chain_head, nb);
0043 }
0044 EXPORT_SYMBOL(register_acpi_notifier);
0045 
0046 int unregister_acpi_notifier(struct notifier_block *nb)
0047 {
0048     return blocking_notifier_chain_unregister(&acpi_chain_head, nb);
0049 }
0050 EXPORT_SYMBOL(unregister_acpi_notifier);
0051 
0052 #ifdef CONFIG_NET
0053 static unsigned int acpi_event_seqnum;
0054 struct acpi_genl_event {
0055     acpi_device_class device_class;
0056     char bus_id[15];
0057     u32 type;
0058     u32 data;
0059 };
0060 
0061 /* attributes of acpi_genl_family */
0062 enum {
0063     ACPI_GENL_ATTR_UNSPEC,
0064     ACPI_GENL_ATTR_EVENT,   /* ACPI event info needed by user space */
0065     __ACPI_GENL_ATTR_MAX,
0066 };
0067 #define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)
0068 
0069 /* commands supported by the acpi_genl_family */
0070 enum {
0071     ACPI_GENL_CMD_UNSPEC,
0072     ACPI_GENL_CMD_EVENT,    /* kernel->user notifications for ACPI events */
0073     __ACPI_GENL_CMD_MAX,
0074 };
0075 #define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1)
0076 
0077 #define ACPI_GENL_FAMILY_NAME       "acpi_event"
0078 #define ACPI_GENL_VERSION       0x01
0079 #define ACPI_GENL_MCAST_GROUP_NAME  "acpi_mc_group"
0080 
0081 static const struct genl_multicast_group acpi_event_mcgrps[] = {
0082     { .name = ACPI_GENL_MCAST_GROUP_NAME, },
0083 };
0084 
0085 static struct genl_family acpi_event_genl_family __ro_after_init = {
0086     .module = THIS_MODULE,
0087     .name = ACPI_GENL_FAMILY_NAME,
0088     .version = ACPI_GENL_VERSION,
0089     .maxattr = ACPI_GENL_ATTR_MAX,
0090     .mcgrps = acpi_event_mcgrps,
0091     .n_mcgrps = ARRAY_SIZE(acpi_event_mcgrps),
0092 };
0093 
0094 int acpi_bus_generate_netlink_event(const char *device_class,
0095                       const char *bus_id,
0096                       u8 type, int data)
0097 {
0098     struct sk_buff *skb;
0099     struct nlattr *attr;
0100     struct acpi_genl_event *event;
0101     void *msg_header;
0102     int size;
0103 
0104     /* allocate memory */
0105     size = nla_total_size(sizeof(struct acpi_genl_event)) +
0106         nla_total_size(0);
0107 
0108     skb = genlmsg_new(size, GFP_ATOMIC);
0109     if (!skb)
0110         return -ENOMEM;
0111 
0112     /* add the genetlink message header */
0113     msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
0114                  &acpi_event_genl_family, 0,
0115                  ACPI_GENL_CMD_EVENT);
0116     if (!msg_header) {
0117         nlmsg_free(skb);
0118         return -ENOMEM;
0119     }
0120 
0121     /* fill the data */
0122     attr =
0123         nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
0124             sizeof(struct acpi_genl_event));
0125     if (!attr) {
0126         nlmsg_free(skb);
0127         return -EINVAL;
0128     }
0129 
0130     event = nla_data(attr);
0131     memset(event, 0, sizeof(struct acpi_genl_event));
0132 
0133     strscpy(event->device_class, device_class, sizeof(event->device_class));
0134     strscpy(event->bus_id, bus_id, sizeof(event->bus_id));
0135     event->type = type;
0136     event->data = data;
0137 
0138     /* send multicast genetlink message */
0139     genlmsg_end(skb, msg_header);
0140 
0141     genlmsg_multicast(&acpi_event_genl_family, skb, 0, 0, GFP_ATOMIC);
0142     return 0;
0143 }
0144 
0145 EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
0146 
0147 static int __init acpi_event_genetlink_init(void)
0148 {
0149     return genl_register_family(&acpi_event_genl_family);
0150 }
0151 
0152 #else
0153 int acpi_bus_generate_netlink_event(const char *device_class,
0154                       const char *bus_id,
0155                       u8 type, int data)
0156 {
0157     return 0;
0158 }
0159 
0160 EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
0161 
0162 static int acpi_event_genetlink_init(void)
0163 {
0164     return -ENODEV;
0165 }
0166 #endif
0167 
0168 static int __init acpi_event_init(void)
0169 {
0170     int error;
0171 
0172     if (acpi_disabled)
0173         return 0;
0174 
0175     /* create genetlink for acpi event */
0176     error = acpi_event_genetlink_init();
0177     if (error)
0178         pr_warn("Failed to create genetlink family for ACPI event\n");
0179 
0180     return 0;
0181 }
0182 
0183 fs_initcall(acpi_event_init);