• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/acpi/
1/*
2 * event.c - exporting ACPI events via procfs
3 *
4 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6 *
7 */
8
9#include <linux/spinlock.h>
10#include <linux/proc_fs.h>
11#include <linux/init.h>
12#include <linux/poll.h>
13#include <linux/gfp.h>
14#include <acpi/acpi_drivers.h>
15#include <net/netlink.h>
16#include <net/genetlink.h>
17
18#include "internal.h"
19
20#define _COMPONENT		ACPI_SYSTEM_COMPONENT
21ACPI_MODULE_NAME("event");
22
23#ifdef CONFIG_ACPI_PROC_EVENT
24/* Global vars for handling event proc entry */
25static DEFINE_SPINLOCK(acpi_system_event_lock);
26int event_is_open = 0;
27extern struct list_head acpi_bus_event_list;
28extern wait_queue_head_t acpi_bus_event_queue;
29
30static int acpi_system_open_event(struct inode *inode, struct file *file)
31{
32	spin_lock_irq(&acpi_system_event_lock);
33
34	if (event_is_open)
35		goto out_busy;
36
37	event_is_open = 1;
38
39	spin_unlock_irq(&acpi_system_event_lock);
40	return 0;
41
42      out_busy:
43	spin_unlock_irq(&acpi_system_event_lock);
44	return -EBUSY;
45}
46
47static ssize_t
48acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
49		       loff_t * ppos)
50{
51	int result = 0;
52	struct acpi_bus_event event;
53	static char str[ACPI_MAX_STRING];
54	static int chars_remaining = 0;
55	static char *ptr;
56
57	if (!chars_remaining) {
58		memset(&event, 0, sizeof(struct acpi_bus_event));
59
60		if ((file->f_flags & O_NONBLOCK)
61		    && (list_empty(&acpi_bus_event_list)))
62			return -EAGAIN;
63
64		result = acpi_bus_receive_event(&event);
65		if (result)
66			return result;
67
68		chars_remaining = sprintf(str, "%s %s %08x %08x\n",
69					  event.device_class ? event.
70					  device_class : "<unknown>",
71					  event.bus_id ? event.
72					  bus_id : "<unknown>", event.type,
73					  event.data);
74		ptr = str;
75	}
76
77	if (chars_remaining < count) {
78		count = chars_remaining;
79	}
80
81	if (copy_to_user(buffer, ptr, count))
82		return -EFAULT;
83
84	*ppos += count;
85	chars_remaining -= count;
86	ptr += count;
87
88	return count;
89}
90
91static int acpi_system_close_event(struct inode *inode, struct file *file)
92{
93	spin_lock_irq(&acpi_system_event_lock);
94	event_is_open = 0;
95	spin_unlock_irq(&acpi_system_event_lock);
96	return 0;
97}
98
99static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait)
100{
101	poll_wait(file, &acpi_bus_event_queue, wait);
102	if (!list_empty(&acpi_bus_event_list))
103		return POLLIN | POLLRDNORM;
104	return 0;
105}
106
107static const struct file_operations acpi_system_event_ops = {
108	.owner = THIS_MODULE,
109	.open = acpi_system_open_event,
110	.read = acpi_system_read_event,
111	.release = acpi_system_close_event,
112	.poll = acpi_system_poll_event,
113};
114#endif	/* CONFIG_ACPI_PROC_EVENT */
115
116/* ACPI notifier chain */
117static BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
118
119int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data)
120{
121	struct acpi_bus_event event;
122
123	strcpy(event.device_class, dev->pnp.device_class);
124	strcpy(event.bus_id, dev->pnp.bus_id);
125	event.type = type;
126	event.data = data;
127	return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event)
128                        == NOTIFY_BAD) ? -EINVAL : 0;
129}
130EXPORT_SYMBOL(acpi_notifier_call_chain);
131
132int register_acpi_notifier(struct notifier_block *nb)
133{
134	return blocking_notifier_chain_register(&acpi_chain_head, nb);
135}
136EXPORT_SYMBOL(register_acpi_notifier);
137
138int unregister_acpi_notifier(struct notifier_block *nb)
139{
140	return blocking_notifier_chain_unregister(&acpi_chain_head, nb);
141}
142EXPORT_SYMBOL(unregister_acpi_notifier);
143
144#ifdef CONFIG_NET
145static unsigned int acpi_event_seqnum;
146struct acpi_genl_event {
147	acpi_device_class device_class;
148	char bus_id[15];
149	u32 type;
150	u32 data;
151};
152
153/* attributes of acpi_genl_family */
154enum {
155	ACPI_GENL_ATTR_UNSPEC,
156	ACPI_GENL_ATTR_EVENT,	/* ACPI event info needed by user space */
157	__ACPI_GENL_ATTR_MAX,
158};
159#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)
160
161/* commands supported by the acpi_genl_family */
162enum {
163	ACPI_GENL_CMD_UNSPEC,
164	ACPI_GENL_CMD_EVENT,	/* kernel->user notifications for ACPI events */
165	__ACPI_GENL_CMD_MAX,
166};
167#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1)
168
169#define ACPI_GENL_FAMILY_NAME		"acpi_event"
170#define ACPI_GENL_VERSION		0x01
171#define ACPI_GENL_MCAST_GROUP_NAME 	"acpi_mc_group"
172
173static struct genl_family acpi_event_genl_family = {
174	.id = GENL_ID_GENERATE,
175	.name = ACPI_GENL_FAMILY_NAME,
176	.version = ACPI_GENL_VERSION,
177	.maxattr = ACPI_GENL_ATTR_MAX,
178};
179
180static struct genl_multicast_group acpi_event_mcgrp = {
181	.name = ACPI_GENL_MCAST_GROUP_NAME,
182};
183
184int acpi_bus_generate_netlink_event(const char *device_class,
185				      const char *bus_id,
186				      u8 type, int data)
187{
188	struct sk_buff *skb;
189	struct nlattr *attr;
190	struct acpi_genl_event *event;
191	void *msg_header;
192	int size;
193	int result;
194
195	/* allocate memory */
196	size = nla_total_size(sizeof(struct acpi_genl_event)) +
197	    nla_total_size(0);
198
199	skb = genlmsg_new(size, GFP_ATOMIC);
200	if (!skb)
201		return -ENOMEM;
202
203	/* add the genetlink message header */
204	msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
205				 &acpi_event_genl_family, 0,
206				 ACPI_GENL_CMD_EVENT);
207	if (!msg_header) {
208		nlmsg_free(skb);
209		return -ENOMEM;
210	}
211
212	/* fill the data */
213	attr =
214	    nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
215			sizeof(struct acpi_genl_event));
216	if (!attr) {
217		nlmsg_free(skb);
218		return -EINVAL;
219	}
220
221	event = nla_data(attr);
222	if (!event) {
223		nlmsg_free(skb);
224		return -EINVAL;
225	}
226
227	memset(event, 0, sizeof(struct acpi_genl_event));
228
229	strcpy(event->device_class, device_class);
230	strcpy(event->bus_id, bus_id);
231	event->type = type;
232	event->data = data;
233
234	/* send multicast genetlink message */
235	result = genlmsg_end(skb, msg_header);
236	if (result < 0) {
237		nlmsg_free(skb);
238		return result;
239	}
240
241	genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
242	return 0;
243}
244
245EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
246
247static int acpi_event_genetlink_init(void)
248{
249	int result;
250
251	result = genl_register_family(&acpi_event_genl_family);
252	if (result)
253		return result;
254
255	result = genl_register_mc_group(&acpi_event_genl_family,
256					&acpi_event_mcgrp);
257	if (result)
258		genl_unregister_family(&acpi_event_genl_family);
259
260	return result;
261}
262
263#else
264int acpi_bus_generate_netlink_event(const char *device_class,
265				      const char *bus_id,
266				      u8 type, int data)
267{
268	return 0;
269}
270
271EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
272
273static int acpi_event_genetlink_init(void)
274{
275	return -ENODEV;
276}
277#endif
278
279static int __init acpi_event_init(void)
280{
281#ifdef CONFIG_ACPI_PROC_EVENT
282	struct proc_dir_entry *entry;
283#endif
284	int error = 0;
285
286	if (acpi_disabled)
287		return 0;
288
289	/* create genetlink for acpi event */
290	error = acpi_event_genetlink_init();
291	if (error)
292		printk(KERN_WARNING PREFIX
293		       "Failed to create genetlink family for ACPI event\n");
294
295#ifdef CONFIG_ACPI_PROC_EVENT
296	/* 'event' [R] */
297	entry = proc_create("event", S_IRUSR, acpi_root_dir,
298			    &acpi_system_event_ops);
299	if (!entry)
300		return -ENODEV;
301#endif
302
303	return 0;
304}
305
306fs_initcall(acpi_event_init);
307