11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * event.c - exporting ACPI events via procfs
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
10214f2c90b970e098e75cf719c0c5b0f1fe69b716Paul Gortmaker#include <linux/export.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/poll.h>
145a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <acpi/acpi_drivers.h>
16864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#include <net/netlink.h>
17864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#include <net/genetlink.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19a192a9580bcc41692be1f36b77c3b681827f566aLen Brown#include "internal.h"
20a192a9580bcc41692be1f36b77c3b681827f566aLen Brown
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define _COMPONENT		ACPI_SYSTEM_COMPONENT
22f52fd66d2ea794010c2d7536cf8e6abed0ac4947Len BrownACPI_MODULE_NAME("event");
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2414e04fb34ffa82ee61ae69f98d8fca12d2e8e31cLen Brown#ifdef CONFIG_ACPI_PROC_EVENT
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Global vars for handling event proc entry */
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(acpi_system_event_lock);
274be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownint event_is_open = 0;
284be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownextern struct list_head acpi_bus_event_list;
294be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownextern wait_queue_head_t acpi_bus_event_queue;
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
314be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_system_open_event(struct inode *inode, struct file *file)
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
33c65ade4dc8b486e8c8b9b0a6399789a5428e2039Pavel Machek	spin_lock_irq(&acpi_system_event_lock);
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35c65ade4dc8b486e8c8b9b0a6399789a5428e2039Pavel Machek	if (event_is_open)
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_busy;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	event_is_open = 1;
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40c65ade4dc8b486e8c8b9b0a6399789a5428e2039Pavel Machek	spin_unlock_irq(&acpi_system_event_lock);
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
434be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown      out_busy:
44c65ade4dc8b486e8c8b9b0a6399789a5428e2039Pavel Machek	spin_unlock_irq(&acpi_system_event_lock);
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EBUSY;
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
494be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_system_read_event(struct file *file, char __user * buffer, size_t count,
504be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		       loff_t * ppos)
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
524be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	int result = 0;
534be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct acpi_bus_event event;
544be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	static char str[ACPI_MAX_STRING];
554be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	static int chars_remaining = 0;
564be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	static char *ptr;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!chars_remaining) {
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memset(&event, 0, sizeof(struct acpi_bus_event));
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((file->f_flags & O_NONBLOCK)
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    && (list_empty(&acpi_bus_event_list)))
63d550d98d3317378d93a4869db204725d270ec812Patrick Mochel			return -EAGAIN;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		result = acpi_bus_receive_event(&event);
665cc9eeef9a9567acdfc2f6943f24381bf460f008Pavel Machek		if (result)
67d550d98d3317378d93a4869db204725d270ec812Patrick Mochel			return result;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
694be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		chars_remaining = sprintf(str, "%s %s %08x %08x\n",
704be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					  event.device_class ? event.
714be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					  device_class : "<unknown>",
724be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					  event.bus_id ? event.
734be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					  bus_id : "<unknown>", event.type,
744be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown					  event.data);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ptr = str;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chars_remaining < count) {
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = chars_remaining;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_to_user(buffer, ptr, count))
83d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return -EFAULT;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*ppos += count;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chars_remaining -= count;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ptr += count;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
89d550d98d3317378d93a4869db204725d270ec812Patrick Mochel	return count;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
924be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic int acpi_system_close_event(struct inode *inode, struct file *file)
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
944be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	spin_lock_irq(&acpi_system_event_lock);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	event_is_open = 0;
964be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	spin_unlock_irq(&acpi_system_event_lock);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownstatic unsigned int acpi_system_poll_event(struct file *file, poll_table * wait)
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	poll_wait(file, &acpi_bus_event_queue, wait);
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!list_empty(&acpi_bus_event_list))
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return POLLIN | POLLRDNORM;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
108d75080328affb4b268da430b7074cc8139cc662aArjan van de Venstatic const struct file_operations acpi_system_event_ops = {
109cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev	.owner = THIS_MODULE,
1104be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.open = acpi_system_open_event,
1114be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.read = acpi_system_read_event,
1124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.release = acpi_system_close_event,
1134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.poll = acpi_system_poll_event,
1146038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann	.llseek = default_llseek,
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
11614e04fb34ffa82ee61ae69f98d8fca12d2e8e31cLen Brown#endif	/* CONFIG_ACPI_PROC_EVENT */
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1189ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui/* ACPI notifier chain */
119c8e773fa4f6a999a80d9fa3836f412e259ab6fa1Adrian Bunkstatic BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
1209ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui
1219ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Ruiint acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data)
1229ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui{
1239ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	struct acpi_bus_event event;
1249ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui
1259ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	strcpy(event.device_class, dev->pnp.device_class);
1269ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	strcpy(event.bus_id, dev->pnp.bus_id);
1279ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	event.type = type;
1289ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	event.data = data;
1299ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event)
1309ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui                        == NOTIFY_BAD) ? -EINVAL : 0;
1319ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui}
1329ee85241fdaab358dff1d8647f20a478cfa512a1Zhang RuiEXPORT_SYMBOL(acpi_notifier_call_chain);
1339ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui
1349ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Ruiint register_acpi_notifier(struct notifier_block *nb)
1359ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui{
1369ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	return blocking_notifier_chain_register(&acpi_chain_head, nb);
1379ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui}
1389ee85241fdaab358dff1d8647f20a478cfa512a1Zhang RuiEXPORT_SYMBOL(register_acpi_notifier);
1399ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui
1409ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Ruiint unregister_acpi_notifier(struct notifier_block *nb)
1419ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui{
1429ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	return blocking_notifier_chain_unregister(&acpi_chain_head, nb);
1439ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui}
1449ee85241fdaab358dff1d8647f20a478cfa512a1Zhang RuiEXPORT_SYMBOL(unregister_acpi_notifier);
1459ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui
146864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#ifdef CONFIG_NET
147e13d87473284131a7ead8121d5d29345101f68a4Adrian Bunkstatic unsigned int acpi_event_seqnum;
148864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruistruct acpi_genl_event {
149864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	acpi_device_class device_class;
150864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	char bus_id[15];
151864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	u32 type;
152864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	u32 data;
153864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui};
154864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
155864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui/* attributes of acpi_genl_family */
156864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruienum {
157864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	ACPI_GENL_ATTR_UNSPEC,
158864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	ACPI_GENL_ATTR_EVENT,	/* ACPI event info needed by user space */
159864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	__ACPI_GENL_ATTR_MAX,
160864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui};
161864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)
162864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
163864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui/* commands supported by the acpi_genl_family */
164864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruienum {
165864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	ACPI_GENL_CMD_UNSPEC,
166864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	ACPI_GENL_CMD_EVENT,	/* kernel->user notifications for ACPI events */
167864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	__ACPI_GENL_CMD_MAX,
168864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui};
169864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1)
170864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
1719c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui#define ACPI_GENL_FAMILY_NAME		"acpi_event"
1729c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui#define ACPI_GENL_VERSION		0x01
1739c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui#define ACPI_GENL_MCAST_GROUP_NAME 	"acpi_mc_group"
174864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
175864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruistatic struct genl_family acpi_event_genl_family = {
176864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	.id = GENL_ID_GENERATE,
1779c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui	.name = ACPI_GENL_FAMILY_NAME,
178864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	.version = ACPI_GENL_VERSION,
179864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	.maxattr = ACPI_GENL_ATTR_MAX,
180864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui};
181864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
1829c977a453ed62396d067b75f3f272b3fb1ea3accZhang Ruistatic struct genl_multicast_group acpi_event_mcgrp = {
1839c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui	.name = ACPI_GENL_MCAST_GROUP_NAME,
184864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui};
185864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
186962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Ruiint acpi_bus_generate_netlink_event(const char *device_class,
187962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui				      const char *bus_id,
188864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui				      u8 type, int data)
189864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui{
190864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	struct sk_buff *skb;
191864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	struct nlattr *attr;
192864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	struct acpi_genl_event *event;
193864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	void *msg_header;
194864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	int size;
195864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	int result;
196864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
197864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	/* allocate memory */
198864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	size = nla_total_size(sizeof(struct acpi_genl_event)) +
199864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	    nla_total_size(0);
200864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
201864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	skb = genlmsg_new(size, GFP_ATOMIC);
202864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	if (!skb)
203864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		return -ENOMEM;
204864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
205864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	/* add the genetlink message header */
206864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
207864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui				 &acpi_event_genl_family, 0,
208864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui				 ACPI_GENL_CMD_EVENT);
209864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	if (!msg_header) {
210864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		nlmsg_free(skb);
211864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		return -ENOMEM;
212864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	}
213864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
214864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	/* fill the data */
215864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	attr =
216864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	    nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
217864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui			sizeof(struct acpi_genl_event));
218864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	if (!attr) {
219864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		nlmsg_free(skb);
220864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		return -EINVAL;
221864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	}
222864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
223864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	event = nla_data(attr);
224864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	if (!event) {
225864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		nlmsg_free(skb);
226864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		return -EINVAL;
227864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	}
228864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
229864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	memset(event, 0, sizeof(struct acpi_genl_event));
230864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
231962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui	strcpy(event->device_class, device_class);
232962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui	strcpy(event->bus_id, bus_id);
233864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	event->type = type;
234864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	event->data = data;
235864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
236864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	/* send multicast genetlink message */
237864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	result = genlmsg_end(skb, msg_header);
238864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	if (result < 0) {
239864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		nlmsg_free(skb);
240864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		return result;
241864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	}
242864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
243ff491a7334acfd74e515c896632e37e401f52676Pablo Neira Ayuso	genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
244864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	return 0;
245864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui}
246864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
247962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang RuiEXPORT_SYMBOL(acpi_bus_generate_netlink_event);
248962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui
249864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruistatic int acpi_event_genetlink_init(void)
250864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui{
251864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	int result;
252864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
253864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	result = genl_register_family(&acpi_event_genl_family);
254864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	if (result)
255864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		return result;
256864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
2579c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui	result = genl_register_mc_group(&acpi_event_genl_family,
2589c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui					&acpi_event_mcgrp);
259864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	if (result)
260864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		genl_unregister_family(&acpi_event_genl_family);
261864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
262864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	return result;
263864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui}
264864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
265864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#else
2663e069ee0c30d6f28b79e409ef2df1ffa427897aeLen Brownint acpi_bus_generate_netlink_event(const char *device_class,
2673e069ee0c30d6f28b79e409ef2df1ffa427897aeLen Brown				      const char *bus_id,
2683e069ee0c30d6f28b79e409ef2df1ffa427897aeLen Brown				      u8 type, int data)
269864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui{
270864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	return 0;
271864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui}
272864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
27366baf327ae5d4c17e75d1f501145e79eaeeaf649Henrique de Moraes HolschuhEXPORT_SYMBOL(acpi_bus_generate_netlink_event);
274962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui
275864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruistatic int acpi_event_genetlink_init(void)
276864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui{
277864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	return -ENODEV;
278864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui}
279864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#endif
280864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_event_init(void)
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
28314e04fb34ffa82ee61ae69f98d8fca12d2e8e31cLen Brown#ifdef CONFIG_ACPI_PROC_EVENT
2844be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct proc_dir_entry *entry;
28514e04fb34ffa82ee61ae69f98d8fca12d2e8e31cLen Brown#endif
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error = 0;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_disabled)
289d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return 0;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	/* create genetlink for acpi event */
292864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	error = acpi_event_genetlink_init();
293864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	if (error)
294864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		printk(KERN_WARNING PREFIX
295864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		       "Failed to create genetlink family for ACPI event\n");
296864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
29714e04fb34ffa82ee61ae69f98d8fca12d2e8e31cLen Brown#ifdef CONFIG_ACPI_PROC_EVENT
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 'event' [R] */
299cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev	entry = proc_create("event", S_IRUSR, acpi_root_dir,
300cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev			    &acpi_system_event_ops);
301cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev	if (!entry)
302864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		return -ENODEV;
30314e04fb34ffa82ee61ae69f98d8fca12d2e8e31cLen Brown#endif
304864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
305864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	return 0;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
308864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruifs_initcall(acpi_event_init);
309