Branch data Line data Source code
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 : 0 : int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data)
29 : : {
30 : 0 : struct acpi_bus_event event;
31 : :
32 : 0 : strcpy(event.device_class, dev->pnp.device_class);
33 : 0 : strcpy(event.bus_id, dev->pnp.bus_id);
34 : 0 : event.type = type;
35 : 0 : event.data = data;
36 : 0 : return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event)
37 [ # # ]: 0 : == NOTIFY_BAD) ? -EINVAL : 0;
38 : : }
39 : : EXPORT_SYMBOL(acpi_notifier_call_chain);
40 : :
41 : 0 : int register_acpi_notifier(struct notifier_block *nb)
42 : : {
43 : 0 : return blocking_notifier_chain_register(&acpi_chain_head, nb);
44 : : }
45 : : EXPORT_SYMBOL(register_acpi_notifier);
46 : :
47 : 0 : int unregister_acpi_notifier(struct notifier_block *nb)
48 : : {
49 : 0 : 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 : 0 : int acpi_bus_generate_netlink_event(const char *device_class,
96 : : const char *bus_id,
97 : : u8 type, int data)
98 : : {
99 : 0 : struct sk_buff *skb;
100 : 0 : struct nlattr *attr;
101 : 0 : struct acpi_genl_event *event;
102 : 0 : void *msg_header;
103 : 0 : int size;
104 : :
105 : : /* allocate memory */
106 : 0 : size = nla_total_size(sizeof(struct acpi_genl_event)) +
107 : : nla_total_size(0);
108 : :
109 : 0 : skb = genlmsg_new(size, GFP_ATOMIC);
110 [ # # ]: 0 : if (!skb)
111 : : return -ENOMEM;
112 : :
113 : : /* add the genetlink message header */
114 : 0 : msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
115 : : &acpi_event_genl_family, 0,
116 : : ACPI_GENL_CMD_EVENT);
117 [ # # ]: 0 : if (!msg_header) {
118 : 0 : nlmsg_free(skb);
119 : 0 : return -ENOMEM;
120 : : }
121 : :
122 : : /* fill the data */
123 : 0 : attr =
124 : 0 : nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
125 : : sizeof(struct acpi_genl_event));
126 [ # # ]: 0 : if (!attr) {
127 : 0 : nlmsg_free(skb);
128 : 0 : return -EINVAL;
129 : : }
130 : :
131 : 0 : event = nla_data(attr);
132 : 0 : memset(event, 0, sizeof(struct acpi_genl_event));
133 : :
134 : 0 : strscpy(event->device_class, device_class, sizeof(event->device_class));
135 : 0 : strscpy(event->bus_id, bus_id, sizeof(event->bus_id));
136 : 0 : event->type = type;
137 : 0 : event->data = data;
138 : :
139 : : /* send multicast genetlink message */
140 : 0 : genlmsg_end(skb, msg_header);
141 : :
142 : 0 : genlmsg_multicast(&acpi_event_genl_family, skb, 0, 0, GFP_ATOMIC);
143 : 0 : return 0;
144 : : }
145 : :
146 : : EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
147 : :
148 : 3 : static int __init acpi_event_genetlink_init(void)
149 : : {
150 : 3 : 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 : 3 : static int __init acpi_event_init(void)
170 : : {
171 : 3 : int error = 0;
172 : :
173 [ + - ]: 3 : if (acpi_disabled)
174 : : return 0;
175 : :
176 : : /* create genetlink for acpi event */
177 : 3 : error = acpi_event_genetlink_init();
178 [ - + ]: 3 : if (error)
179 : 0 : 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);
|