xref: /linux/drivers/acpi/event.c (revision d39d0ed196aa1685bb24771e92f78633c66ac9cb)
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
21 ACPI_MODULE_NAME("event");
22 
23 #ifdef CONFIG_ACPI_PROC_EVENT
24 /* Global vars for handling event proc entry */
25 static DEFINE_SPINLOCK(acpi_system_event_lock);
26 int event_is_open = 0;
27 extern struct list_head acpi_bus_event_list;
28 extern wait_queue_head_t acpi_bus_event_queue;
29 
30 static 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 
47 static ssize_t
48 acpi_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 
91 static 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 
99 static 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 
107 static 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 */
117 static BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
118 
119 int 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 }
130 EXPORT_SYMBOL(acpi_notifier_call_chain);
131 
132 int register_acpi_notifier(struct notifier_block *nb)
133 {
134 	return blocking_notifier_chain_register(&acpi_chain_head, nb);
135 }
136 EXPORT_SYMBOL(register_acpi_notifier);
137 
138 int unregister_acpi_notifier(struct notifier_block *nb)
139 {
140 	return blocking_notifier_chain_unregister(&acpi_chain_head, nb);
141 }
142 EXPORT_SYMBOL(unregister_acpi_notifier);
143 
144 #ifdef CONFIG_NET
145 static unsigned int acpi_event_seqnum;
146 struct 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 */
154 enum {
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 */
162 enum {
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 
173 static 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 
180 static struct genl_multicast_group acpi_event_mcgrp = {
181 	.name = ACPI_GENL_MCAST_GROUP_NAME,
182 };
183 
184 int 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 
245 EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
246 
247 static 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
264 int 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 
271 EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
272 
273 static int acpi_event_genetlink_init(void)
274 {
275 	return -ENODEV;
276 }
277 #endif
278 
279 static 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 
306 fs_initcall(acpi_event_init);
307