aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhang Rui <rui.zhang@intel.com>2007-06-18 23:40:03 -0400
committerLen Brown <len.brown@intel.com>2007-07-03 14:50:58 -0400
commit864bdfb912e372670b5b2541dac9d273a4a7722a (patch)
tree6f3bd48b2ea92130a2f2b8add2c393cb01151ac7
parent872aad45d6174570dd2e1defc3efee50f2cfcc72 (diff)
ACPI: Export events via generic netlink
Upon ACPI events, send an "acpi_event" via Generic Netlink. This is in addition to /proc/acpi/event, which remains intact for now. Thanks to Jamal for his great help. Signed-off-by: Zhang Rui <rui.zhang@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/acpi/bus.c4
-rw-r--r--drivers/acpi/event.c166
-rw-r--r--include/acpi/acpi_bus.h3
3 files changed, 165 insertions, 8 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index e5084ececb6f..6b2658c96242 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -292,6 +292,10 @@ int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data)
292 if (!device) 292 if (!device)
293 return -EINVAL; 293 return -EINVAL;
294 294
295 if (acpi_bus_generate_genetlink_event(device, type, data))
296 printk(KERN_WARNING PREFIX
297 "Failed to generate an ACPI event via genetlink!\n");
298
295 /* drop event on the floor if no one's listening */ 299 /* drop event on the floor if no one's listening */
296 if (!event_is_open) 300 if (!event_is_open)
297 return 0; 301 return 0;
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 3b23562e6f92..98627b02f547 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -11,6 +11,8 @@
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/poll.h> 12#include <linux/poll.h>
13#include <acpi/acpi_drivers.h> 13#include <acpi/acpi_drivers.h>
14#include <net/netlink.h>
15#include <net/genetlink.h>
14 16
15#define _COMPONENT ACPI_SYSTEM_COMPONENT 17#define _COMPONENT ACPI_SYSTEM_COMPONENT
16ACPI_MODULE_NAME("event"); 18ACPI_MODULE_NAME("event");
@@ -48,7 +50,6 @@ acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
48 static int chars_remaining = 0; 50 static int chars_remaining = 0;
49 static char *ptr; 51 static char *ptr;
50 52
51
52 if (!chars_remaining) { 53 if (!chars_remaining) {
53 memset(&event, 0, sizeof(struct acpi_bus_event)); 54 memset(&event, 0, sizeof(struct acpi_bus_event));
54 55
@@ -106,23 +107,174 @@ static const struct file_operations acpi_system_event_ops = {
106 .poll = acpi_system_poll_event, 107 .poll = acpi_system_poll_event,
107}; 108};
108 109
110#ifdef CONFIG_NET
111unsigned int acpi_event_seqnum;
112struct acpi_genl_event {
113 acpi_device_class device_class;
114 char bus_id[15];
115 u32 type;
116 u32 data;
117};
118
119/* attributes of acpi_genl_family */
120enum {
121 ACPI_GENL_ATTR_UNSPEC,
122 ACPI_GENL_ATTR_EVENT, /* ACPI event info needed by user space */
123 __ACPI_GENL_ATTR_MAX,
124};
125#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)
126
127/* commands supported by the acpi_genl_family */
128enum {
129 ACPI_GENL_CMD_UNSPEC,
130 ACPI_GENL_CMD_EVENT, /* kernel->user notifications for ACPI events */
131 __ACPI_GENL_CMD_MAX,
132};
133#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1)
134
135#define ACPI_GENL_NAME "acpi_event"
136#define ACPI_GENL_VERSION 0x01
137
138static struct genl_family acpi_event_genl_family = {
139 .id = GENL_ID_GENERATE,
140 .name = ACPI_GENL_NAME,
141 .version = ACPI_GENL_VERSION,
142 .maxattr = ACPI_GENL_ATTR_MAX,
143};
144
145/* .doit: standard command callback */
146static int acpi_genl_cmd_event(struct sk_buff *skb, struct genl_info *info)
147{
148 struct acpi_genl_event *event = info->userhdr;
149
150 if (!event)
151 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "ACPI event: NULL\n"));
152
153 return 0;
154}
155
156static struct genl_ops acpi_event_genl_ops = {
157 .cmd = ACPI_GENL_CMD_EVENT,
158 .doit = acpi_genl_cmd_event,
159};
160
161int acpi_bus_generate_genetlink_event(struct acpi_device *device,
162 u8 type, int data)
163{
164 struct sk_buff *skb;
165 struct nlattr *attr;
166 struct acpi_genl_event *event;
167 void *msg_header;
168 int size;
169 int result;
170
171 /* allocate memory */
172 size = nla_total_size(sizeof(struct acpi_genl_event)) +
173 nla_total_size(0);
174
175 skb = genlmsg_new(size, GFP_ATOMIC);
176 if (!skb)
177 return -ENOMEM;
178
179 /* add the genetlink message header */
180 msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
181 &acpi_event_genl_family, 0,
182 ACPI_GENL_CMD_EVENT);
183 if (!msg_header) {
184 nlmsg_free(skb);
185 return -ENOMEM;
186 }
187
188 /* fill the data */
189 attr =
190 nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
191 sizeof(struct acpi_genl_event));
192 if (!attr) {
193 nlmsg_free(skb);
194 return -EINVAL;
195 }
196
197 event = nla_data(attr);
198 if (!event) {
199 nlmsg_free(skb);
200 return -EINVAL;
201 }
202
203 memset(event, 0, sizeof(struct acpi_genl_event));
204
205 strcpy(event->device_class, device->pnp.device_class);
206 strcpy(event->bus_id, device->dev.bus_id);
207 event->type = type;
208 event->data = data;
209
210 /* send multicast genetlink message */
211 result = genlmsg_end(skb, msg_header);
212 if (result < 0) {
213 nlmsg_free(skb);
214 return result;
215 }
216
217 result =
218 genlmsg_multicast(skb, 0, acpi_event_genl_family.id, GFP_ATOMIC);
219 if (result)
220 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
221 "Failed to send a Genetlink message!\n"));
222 return 0;
223}
224EXPORT_SYMBOL(acpi_bus_generate_genetlink_event);
225
226static int acpi_event_genetlink_init(void)
227{
228 int result;
229
230 result = genl_register_family(&acpi_event_genl_family);
231 if (result)
232 return result;
233
234 result =
235 genl_register_ops(&acpi_event_genl_family, &acpi_event_genl_ops);
236 if (result)
237 genl_unregister_family(&acpi_event_genl_family);
238
239 return result;
240}
241
242#else
243int acpi_bus_generate_genetlink_event(struct acpi_device *device, u8 type,
244 int data)
245{
246 return 0;
247}
248EXPORT_SYMBOL(acpi_bus_generate_genetlink_event);
249
250static int acpi_event_genetlink_init(void)
251{
252 return -ENODEV;
253}
254#endif
255
109static int __init acpi_event_init(void) 256static int __init acpi_event_init(void)
110{ 257{
111 struct proc_dir_entry *entry; 258 struct proc_dir_entry *entry;
112 int error = 0; 259 int error = 0;
113 260
114
115 if (acpi_disabled) 261 if (acpi_disabled)
116 return 0; 262 return 0;
117 263
264 /* create genetlink for acpi event */
265 error = acpi_event_genetlink_init();
266 if (error)
267 printk(KERN_WARNING PREFIX
268 "Failed to create genetlink family for ACPI event\n");
269
118 /* 'event' [R] */ 270 /* 'event' [R] */
119 entry = create_proc_entry("event", S_IRUSR, acpi_root_dir); 271 entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
120 if (entry) 272 if (entry)
121 entry->proc_fops = &acpi_system_event_ops; 273 entry->proc_fops = &acpi_system_event_ops;
122 else { 274 else
123 error = -ENODEV; 275 return -ENODEV;
124 } 276
125 return error; 277 return 0;
126} 278}
127 279
128subsys_initcall(acpi_event_init); 280fs_initcall(acpi_event_init);
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index c6fa5e023bc7..5e3dcf3299bf 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -321,7 +321,8 @@ struct acpi_bus_event {
321}; 321};
322 322
323extern struct kset acpi_subsys; 323extern struct kset acpi_subsys;
324 324extern int acpi_bus_generate_genetlink_event(struct acpi_device *device,
325 u8 type, int data);
325/* 326/*
326 * External Functions 327 * External Functions
327 */ 328 */