Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/acpi/event.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* event.c - exporting ACPI events via procfs
4
*
5
* Copyright (C) 2001, 2002 Andy Grover <[email protected]>
6
* Copyright (C) 2001, 2002 Paul Diefenbaugh <[email protected]>
7
*
8
*/
9
10
#define pr_fmt(fmt) "ACPI: " fmt
11
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 */
25
static BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
26
27
int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data)
28
{
29
struct acpi_bus_event event;
30
31
strscpy(event.device_class, dev->pnp.device_class);
32
strscpy(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
}
38
EXPORT_SYMBOL(acpi_notifier_call_chain);
39
40
int register_acpi_notifier(struct notifier_block *nb)
41
{
42
return blocking_notifier_chain_register(&acpi_chain_head, nb);
43
}
44
EXPORT_SYMBOL(register_acpi_notifier);
45
46
int unregister_acpi_notifier(struct notifier_block *nb)
47
{
48
return blocking_notifier_chain_unregister(&acpi_chain_head, nb);
49
}
50
EXPORT_SYMBOL(unregister_acpi_notifier);
51
52
#ifdef CONFIG_NET
53
static unsigned int acpi_event_seqnum;
54
struct 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 */
62
enum {
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 */
70
enum {
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 0x01
79
#define ACPI_GENL_MCAST_GROUP_NAME "acpi_mc_group"
80
81
static const struct genl_multicast_group acpi_event_mcgrps[] = {
82
{ .name = ACPI_GENL_MCAST_GROUP_NAME, },
83
};
84
85
static 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
94
int 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
145
EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
146
147
static int __init acpi_event_genetlink_init(void)
148
{
149
return genl_register_family(&acpi_event_genl_family);
150
}
151
152
#else
153
int 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
160
EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
161
162
static int acpi_event_genetlink_init(void)
163
{
164
return -ENODEV;
165
}
166
#endif
167
168
static 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
183
fs_initcall(acpi_event_init);
184
185