Commit 864bdfb912e372670b5b2541dac9d273a4a7722a

Authored by Zhang Rui
Committed by Len Brown
1 parent 872aad45d6

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>

Showing 3 changed files with 165 additions and 8 deletions Side-by-side Diff

... ... @@ -292,6 +292,10 @@
292 292 if (!device)
293 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 299 /* drop event on the floor if no one's listening */
296 300 if (!event_is_open)
297 301 return 0;
drivers/acpi/event.c
... ... @@ -11,6 +11,8 @@
11 11 #include <linux/init.h>
12 12 #include <linux/poll.h>
13 13 #include <acpi/acpi_drivers.h>
  14 +#include <net/netlink.h>
  15 +#include <net/genetlink.h>
14 16  
15 17 #define _COMPONENT ACPI_SYSTEM_COMPONENT
16 18 ACPI_MODULE_NAME("event");
... ... @@ -48,7 +50,6 @@
48 50 static int chars_remaining = 0;
49 51 static char *ptr;
50 52  
51   -
52 53 if (!chars_remaining) {
53 54 memset(&event, 0, sizeof(struct acpi_bus_event));
54 55  
55 56  
56 57  
57 58  
58 59  
... ... @@ -106,24 +107,175 @@
106 107 .poll = acpi_system_poll_event,
107 108 };
108 109  
  110 +#ifdef CONFIG_NET
  111 +unsigned int acpi_event_seqnum;
  112 +struct 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 */
  120 +enum {
  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 */
  128 +enum {
  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 +
  138 +static 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 */
  146 +static 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 +
  156 +static struct genl_ops acpi_event_genl_ops = {
  157 + .cmd = ACPI_GENL_CMD_EVENT,
  158 + .doit = acpi_genl_cmd_event,
  159 +};
  160 +
  161 +int 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 +}
  224 +EXPORT_SYMBOL(acpi_bus_generate_genetlink_event);
  225 +
  226 +static 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
  243 +int acpi_bus_generate_genetlink_event(struct acpi_device *device, u8 type,
  244 + int data)
  245 +{
  246 + return 0;
  247 +}
  248 +EXPORT_SYMBOL(acpi_bus_generate_genetlink_event);
  249 +
  250 +static int acpi_event_genetlink_init(void)
  251 +{
  252 + return -ENODEV;
  253 +}
  254 +#endif
  255 +
109 256 static int __init acpi_event_init(void)
110 257 {
111 258 struct proc_dir_entry *entry;
112 259 int error = 0;
113 260  
114   -
115 261 if (acpi_disabled)
116 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 270 /* 'event' [R] */
119 271 entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
120 272 if (entry)
121 273 entry->proc_fops = &acpi_system_event_ops;
122   - else {
123   - error = -ENODEV;
124   - }
125   - return error;
  274 + else
  275 + return -ENODEV;
  276 +
  277 + return 0;
126 278 }
127 279  
128   -subsys_initcall(acpi_event_init);
  280 +fs_initcall(acpi_event_init);
include/acpi/acpi_bus.h
... ... @@ -321,7 +321,8 @@
321 321 };
322 322  
323 323 extern struct kset acpi_subsys;
324   -
  324 +extern int acpi_bus_generate_genetlink_event(struct acpi_device *device,
  325 + u8 type, int data);
325 326 /*
326 327 * External Functions
327 328 */