event.c 6.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9
/*
 * event.c - exporting ACPI events via procfs
 *
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
 *
 */

#include <linux/spinlock.h>
10
#include <linux/export.h>
L
Linus Torvalds 已提交
11 12 13
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/poll.h>
14
#include <linux/gfp.h>
L
Linus Torvalds 已提交
15
#include <acpi/acpi_drivers.h>
16 17
#include <net/netlink.h>
#include <net/genetlink.h>
L
Linus Torvalds 已提交
18

19 20
#include "internal.h"

L
Linus Torvalds 已提交
21
#define _COMPONENT		ACPI_SYSTEM_COMPONENT
22
ACPI_MODULE_NAME("event");
L
Linus Torvalds 已提交
23

24
#ifdef CONFIG_ACPI_PROC_EVENT
L
Linus Torvalds 已提交
25 26
/* Global vars for handling event proc entry */
static DEFINE_SPINLOCK(acpi_system_event_lock);
L
Len Brown 已提交
27 28 29
int event_is_open = 0;
extern struct list_head acpi_bus_event_list;
extern wait_queue_head_t acpi_bus_event_queue;
L
Linus Torvalds 已提交
30

L
Len Brown 已提交
31
static int acpi_system_open_event(struct inode *inode, struct file *file)
L
Linus Torvalds 已提交
32
{
P
Pavel Machek 已提交
33
	spin_lock_irq(&acpi_system_event_lock);
L
Linus Torvalds 已提交
34

P
Pavel Machek 已提交
35
	if (event_is_open)
L
Linus Torvalds 已提交
36 37 38 39
		goto out_busy;

	event_is_open = 1;

P
Pavel Machek 已提交
40
	spin_unlock_irq(&acpi_system_event_lock);
L
Linus Torvalds 已提交
41 42
	return 0;

L
Len Brown 已提交
43
      out_busy:
P
Pavel Machek 已提交
44
	spin_unlock_irq(&acpi_system_event_lock);
L
Linus Torvalds 已提交
45 46 47 48
	return -EBUSY;
}

static ssize_t
L
Len Brown 已提交
49 50
acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
		       loff_t * ppos)
L
Linus Torvalds 已提交
51
{
L
Len Brown 已提交
52 53 54 55 56
	int result = 0;
	struct acpi_bus_event event;
	static char str[ACPI_MAX_STRING];
	static int chars_remaining = 0;
	static char *ptr;
L
Linus Torvalds 已提交
57 58 59 60 61 62

	if (!chars_remaining) {
		memset(&event, 0, sizeof(struct acpi_bus_event));

		if ((file->f_flags & O_NONBLOCK)
		    && (list_empty(&acpi_bus_event_list)))
63
			return -EAGAIN;
L
Linus Torvalds 已提交
64 65

		result = acpi_bus_receive_event(&event);
66
		if (result)
67
			return result;
L
Linus Torvalds 已提交
68

L
Len Brown 已提交
69 70 71 72 73 74
		chars_remaining = sprintf(str, "%s %s %08x %08x\n",
					  event.device_class ? event.
					  device_class : "<unknown>",
					  event.bus_id ? event.
					  bus_id : "<unknown>", event.type,
					  event.data);
L
Linus Torvalds 已提交
75 76 77 78 79 80 81 82
		ptr = str;
	}

	if (chars_remaining < count) {
		count = chars_remaining;
	}

	if (copy_to_user(buffer, ptr, count))
83
		return -EFAULT;
L
Linus Torvalds 已提交
84 85 86 87 88

	*ppos += count;
	chars_remaining -= count;
	ptr += count;

89
	return count;
L
Linus Torvalds 已提交
90 91
}

L
Len Brown 已提交
92
static int acpi_system_close_event(struct inode *inode, struct file *file)
L
Linus Torvalds 已提交
93
{
L
Len Brown 已提交
94
	spin_lock_irq(&acpi_system_event_lock);
L
Linus Torvalds 已提交
95
	event_is_open = 0;
L
Len Brown 已提交
96
	spin_unlock_irq(&acpi_system_event_lock);
L
Linus Torvalds 已提交
97 98 99
	return 0;
}

L
Len Brown 已提交
100
static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait)
L
Linus Torvalds 已提交
101 102 103 104 105 106 107
{
	poll_wait(file, &acpi_bus_event_queue, wait);
	if (!list_empty(&acpi_bus_event_list))
		return POLLIN | POLLRDNORM;
	return 0;
}

108
static const struct file_operations acpi_system_event_ops = {
109
	.owner = THIS_MODULE,
L
Len Brown 已提交
110 111 112 113
	.open = acpi_system_open_event,
	.read = acpi_system_read_event,
	.release = acpi_system_close_event,
	.poll = acpi_system_poll_event,
114
	.llseek = default_llseek,
L
Linus Torvalds 已提交
115
};
116
#endif	/* CONFIG_ACPI_PROC_EVENT */
L
Linus Torvalds 已提交
117

118
/* ACPI notifier chain */
A
Adrian Bunk 已提交
119
static BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145

int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data)
{
	struct acpi_bus_event event;

	strcpy(event.device_class, dev->pnp.device_class);
	strcpy(event.bus_id, dev->pnp.bus_id);
	event.type = type;
	event.data = data;
	return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event)
                        == NOTIFY_BAD) ? -EINVAL : 0;
}
EXPORT_SYMBOL(acpi_notifier_call_chain);

int register_acpi_notifier(struct notifier_block *nb)
{
	return blocking_notifier_chain_register(&acpi_chain_head, nb);
}
EXPORT_SYMBOL(register_acpi_notifier);

int unregister_acpi_notifier(struct notifier_block *nb)
{
	return blocking_notifier_chain_unregister(&acpi_chain_head, nb);
}
EXPORT_SYMBOL(unregister_acpi_notifier);

146
#ifdef CONFIG_NET
A
Adrian Bunk 已提交
147
static unsigned int acpi_event_seqnum;
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
struct acpi_genl_event {
	acpi_device_class device_class;
	char bus_id[15];
	u32 type;
	u32 data;
};

/* attributes of acpi_genl_family */
enum {
	ACPI_GENL_ATTR_UNSPEC,
	ACPI_GENL_ATTR_EVENT,	/* ACPI event info needed by user space */
	__ACPI_GENL_ATTR_MAX,
};
#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)

/* commands supported by the acpi_genl_family */
enum {
	ACPI_GENL_CMD_UNSPEC,
	ACPI_GENL_CMD_EVENT,	/* kernel->user notifications for ACPI events */
	__ACPI_GENL_CMD_MAX,
};
#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1)

171 172 173
#define ACPI_GENL_FAMILY_NAME		"acpi_event"
#define ACPI_GENL_VERSION		0x01
#define ACPI_GENL_MCAST_GROUP_NAME 	"acpi_mc_group"
174 175 176

static struct genl_family acpi_event_genl_family = {
	.id = GENL_ID_GENERATE,
177
	.name = ACPI_GENL_FAMILY_NAME,
178 179 180 181
	.version = ACPI_GENL_VERSION,
	.maxattr = ACPI_GENL_ATTR_MAX,
};

182 183
static struct genl_multicast_group acpi_event_mcgrp = {
	.name = ACPI_GENL_MCAST_GROUP_NAME,
184 185
};

186 187
int acpi_bus_generate_netlink_event(const char *device_class,
				      const char *bus_id,
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
				      u8 type, int data)
{
	struct sk_buff *skb;
	struct nlattr *attr;
	struct acpi_genl_event *event;
	void *msg_header;
	int size;
	int result;

	/* allocate memory */
	size = nla_total_size(sizeof(struct acpi_genl_event)) +
	    nla_total_size(0);

	skb = genlmsg_new(size, GFP_ATOMIC);
	if (!skb)
		return -ENOMEM;

	/* add the genetlink message header */
	msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
				 &acpi_event_genl_family, 0,
				 ACPI_GENL_CMD_EVENT);
	if (!msg_header) {
		nlmsg_free(skb);
		return -ENOMEM;
	}

	/* fill the data */
	attr =
	    nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
			sizeof(struct acpi_genl_event));
	if (!attr) {
		nlmsg_free(skb);
		return -EINVAL;
	}

	event = nla_data(attr);
	if (!event) {
		nlmsg_free(skb);
		return -EINVAL;
	}

	memset(event, 0, sizeof(struct acpi_genl_event));

231 232
	strcpy(event->device_class, device_class);
	strcpy(event->bus_id, bus_id);
233 234 235 236 237 238 239 240 241 242
	event->type = type;
	event->data = data;

	/* send multicast genetlink message */
	result = genlmsg_end(skb, msg_header);
	if (result < 0) {
		nlmsg_free(skb);
		return result;
	}

243
	genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
244 245 246
	return 0;
}

247 248
EXPORT_SYMBOL(acpi_bus_generate_netlink_event);

249 250 251 252 253 254 255 256
static int acpi_event_genetlink_init(void)
{
	int result;

	result = genl_register_family(&acpi_event_genl_family);
	if (result)
		return result;

257 258
	result = genl_register_mc_group(&acpi_event_genl_family,
					&acpi_event_mcgrp);
259 260 261 262 263 264 265
	if (result)
		genl_unregister_family(&acpi_event_genl_family);

	return result;
}

#else
L
Len Brown 已提交
266 267 268
int acpi_bus_generate_netlink_event(const char *device_class,
				      const char *bus_id,
				      u8 type, int data)
269 270 271 272
{
	return 0;
}

273
EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
274

275 276 277 278 279 280
static int acpi_event_genetlink_init(void)
{
	return -ENODEV;
}
#endif

L
Linus Torvalds 已提交
281 282
static int __init acpi_event_init(void)
{
283
#ifdef CONFIG_ACPI_PROC_EVENT
L
Len Brown 已提交
284
	struct proc_dir_entry *entry;
285
#endif
L
Linus Torvalds 已提交
286 287 288
	int error = 0;

	if (acpi_disabled)
289
		return 0;
L
Linus Torvalds 已提交
290

291 292 293 294 295 296
	/* create genetlink for acpi event */
	error = acpi_event_genetlink_init();
	if (error)
		printk(KERN_WARNING PREFIX
		       "Failed to create genetlink family for ACPI event\n");

297
#ifdef CONFIG_ACPI_PROC_EVENT
L
Linus Torvalds 已提交
298
	/* 'event' [R] */
299 300 301
	entry = proc_create("event", S_IRUSR, acpi_root_dir,
			    &acpi_system_event_ops);
	if (!entry)
302
		return -ENODEV;
303
#endif
304 305

	return 0;
L
Linus Torvalds 已提交
306 307
}

308
fs_initcall(acpi_event_init);