[go: nahoru, domu]

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>
158b48463f89429af408ff695244dc627e1acff4f7Lv Zheng#include <linux/acpi.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
249ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui/* ACPI notifier chain */
25c8e773fa4f6a999a80d9fa3836f412e259ab6fa1Adrian Bunkstatic BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
269ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui
279ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Ruiint acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data)
289ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui{
299ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	struct acpi_bus_event event;
309ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui
319ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	strcpy(event.device_class, dev->pnp.device_class);
329ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	strcpy(event.bus_id, dev->pnp.bus_id);
339ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	event.type = type;
349ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	event.data = data;
359ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event)
369ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui                        == NOTIFY_BAD) ? -EINVAL : 0;
379ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui}
389ee85241fdaab358dff1d8647f20a478cfa512a1Zhang RuiEXPORT_SYMBOL(acpi_notifier_call_chain);
399ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui
409ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Ruiint register_acpi_notifier(struct notifier_block *nb)
419ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui{
429ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	return blocking_notifier_chain_register(&acpi_chain_head, nb);
439ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui}
449ee85241fdaab358dff1d8647f20a478cfa512a1Zhang RuiEXPORT_SYMBOL(register_acpi_notifier);
459ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui
469ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Ruiint unregister_acpi_notifier(struct notifier_block *nb)
479ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui{
489ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui	return blocking_notifier_chain_unregister(&acpi_chain_head, nb);
499ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui}
509ee85241fdaab358dff1d8647f20a478cfa512a1Zhang RuiEXPORT_SYMBOL(unregister_acpi_notifier);
519ee85241fdaab358dff1d8647f20a478cfa512a1Zhang Rui
52864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#ifdef CONFIG_NET
53e13d87473284131a7ead8121d5d29345101f68a4Adrian Bunkstatic unsigned int acpi_event_seqnum;
54864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruistruct acpi_genl_event {
55864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	acpi_device_class device_class;
56864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	char bus_id[15];
57864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	u32 type;
58864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	u32 data;
59864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui};
60864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
61864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui/* attributes of acpi_genl_family */
62864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruienum {
63864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	ACPI_GENL_ATTR_UNSPEC,
64864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	ACPI_GENL_ATTR_EVENT,	/* ACPI event info needed by user space */
65864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	__ACPI_GENL_ATTR_MAX,
66864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui};
67864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)
68864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
69864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui/* commands supported by the acpi_genl_family */
70864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruienum {
71864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	ACPI_GENL_CMD_UNSPEC,
72864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	ACPI_GENL_CMD_EVENT,	/* kernel->user notifications for ACPI events */
73864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	__ACPI_GENL_CMD_MAX,
74864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui};
75864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1)
76864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
779c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui#define ACPI_GENL_FAMILY_NAME		"acpi_event"
789c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui#define ACPI_GENL_VERSION		0x01
799c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui#define ACPI_GENL_MCAST_GROUP_NAME 	"acpi_mc_group"
80864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
812a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Bergstatic const struct genl_multicast_group acpi_event_mcgrps[] = {
822a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg	{ .name = ACPI_GENL_MCAST_GROUP_NAME, },
832a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg};
842a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg
85864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruistatic struct genl_family acpi_event_genl_family = {
86864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	.id = GENL_ID_GENERATE,
879c977a453ed62396d067b75f3f272b3fb1ea3accZhang Rui	.name = ACPI_GENL_FAMILY_NAME,
88864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	.version = ACPI_GENL_VERSION,
89864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	.maxattr = ACPI_GENL_ATTR_MAX,
902a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg	.mcgrps = acpi_event_mcgrps,
912a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg	.n_mcgrps = ARRAY_SIZE(acpi_event_mcgrps),
92864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui};
93864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
94962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Ruiint acpi_bus_generate_netlink_event(const char *device_class,
95962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui				      const char *bus_id,
96864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui				      u8 type, int data)
97864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui{
98864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	struct sk_buff *skb;
99864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	struct nlattr *attr;
100864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	struct acpi_genl_event *event;
101864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	void *msg_header;
102864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	int size;
103864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	int result;
104864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
105864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	/* allocate memory */
106864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	size = nla_total_size(sizeof(struct acpi_genl_event)) +
107864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	    nla_total_size(0);
108864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
109864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	skb = genlmsg_new(size, GFP_ATOMIC);
110864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	if (!skb)
111864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		return -ENOMEM;
112864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
113864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	/* add the genetlink message header */
114864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
115864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui				 &acpi_event_genl_family, 0,
116864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui				 ACPI_GENL_CMD_EVENT);
117864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	if (!msg_header) {
118864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		nlmsg_free(skb);
119864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		return -ENOMEM;
120864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	}
121864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
122864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	/* fill the data */
123864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	attr =
124864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	    nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
125864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui			sizeof(struct acpi_genl_event));
126864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	if (!attr) {
127864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		nlmsg_free(skb);
128864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		return -EINVAL;
129864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	}
130864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
131864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	event = nla_data(attr);
132864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	memset(event, 0, sizeof(struct acpi_genl_event));
133864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
134962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui	strcpy(event->device_class, device_class);
135962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui	strcpy(event->bus_id, bus_id);
136864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	event->type = type;
137864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	event->data = data;
138864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
139864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	/* send multicast genetlink message */
140864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	result = genlmsg_end(skb, msg_header);
141864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	if (result < 0) {
142864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		nlmsg_free(skb);
143864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		return result;
144864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	}
145864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
1462a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg	genlmsg_multicast(&acpi_event_genl_family, skb, 0, 0, GFP_ATOMIC);
147864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	return 0;
148864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui}
149864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
150962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang RuiEXPORT_SYMBOL(acpi_bus_generate_netlink_event);
151962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui
152864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruistatic int acpi_event_genetlink_init(void)
153864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui{
1542a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg	return genl_register_family(&acpi_event_genl_family);
155864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui}
156864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
157864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#else
1583e069ee0c30d6f28b79e409ef2df1ffa427897aeLen Brownint acpi_bus_generate_netlink_event(const char *device_class,
1593e069ee0c30d6f28b79e409ef2df1ffa427897aeLen Brown				      const char *bus_id,
1603e069ee0c30d6f28b79e409ef2df1ffa427897aeLen Brown				      u8 type, int data)
161864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui{
162864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	return 0;
163864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui}
164864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
16566baf327ae5d4c17e75d1f501145e79eaeeaf649Henrique de Moraes HolschuhEXPORT_SYMBOL(acpi_bus_generate_netlink_event);
166962ce8ca0604af0c3c5609f7613d4ec5fcfac623Zhang Rui
167864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruistatic int acpi_event_genetlink_init(void)
168864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui{
169864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	return -ENODEV;
170864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui}
171864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui#endif
172864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init acpi_event_init(void)
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error = 0;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (acpi_disabled)
178d550d98d3317378d93a4869db204725d270ec812Patrick Mochel		return 0;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
180864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	/* create genetlink for acpi event */
181864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	error = acpi_event_genetlink_init();
182864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	if (error)
183864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		printk(KERN_WARNING PREFIX
184864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui		       "Failed to create genetlink family for ACPI event\n");
185864bdfb912e372670b5b2541dac9d273a4a7722aZhang Rui	return 0;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
188864bdfb912e372670b5b2541dac9d273a4a7722aZhang Ruifs_initcall(acpi_event_init);
189