ec.c 22.0 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 *  ec.c - ACPI Embedded Controller Driver (v2.0)
L
Linus Torvalds 已提交
3
 *
4 5
 *  Copyright (C) 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
 *  Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
L
Linus Torvalds 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 *  Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or (at
 *  your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
D
Dmitry Torokhov 已提交
36
#include <linux/interrupt.h>
37
#include <linux/list.h>
L
Linus Torvalds 已提交
38 39 40 41 42 43 44 45 46
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/actypes.h>

#define ACPI_EC_CLASS			"embedded_controller"
#define ACPI_EC_HID			"PNP0C09"
#define ACPI_EC_DEVICE_NAME		"Embedded Controller"
#define ACPI_EC_FILE_INFO		"info"
47

48 49
#undef PREFIX
#define PREFIX				"ACPI: EC: "
50

51
/* EC status register */
L
Linus Torvalds 已提交
52 53
#define ACPI_EC_FLAG_OBF	0x01	/* Output buffer full */
#define ACPI_EC_FLAG_IBF	0x02	/* Input buffer full */
D
Dmitry Torokhov 已提交
54
#define ACPI_EC_FLAG_BURST	0x10	/* burst mode */
L
Linus Torvalds 已提交
55
#define ACPI_EC_FLAG_SCI	0x20	/* EC-SCI occurred */
56

57
/* EC commands */
58
enum ec_command {
A
Alexey Starikovskiy 已提交
59 60 61 62 63
	ACPI_EC_COMMAND_READ = 0x80,
	ACPI_EC_COMMAND_WRITE = 0x81,
	ACPI_EC_BURST_ENABLE = 0x82,
	ACPI_EC_BURST_DISABLE = 0x83,
	ACPI_EC_COMMAND_QUERY = 0x84,
64
};
65

66
/* EC events */
67
enum ec_event {
68
	ACPI_EC_EVENT_OBF_1 = 1,	/* Output buffer full */
A
Alexey Starikovskiy 已提交
69
	ACPI_EC_EVENT_IBF_0,	/* Input buffer empty */
70 71
};

72
#define ACPI_EC_DELAY		500	/* Wait 500ms max. during EC ops */
73 74
#define ACPI_EC_UDELAY_GLK	1000	/* Wait 1ms max. to get global lock */

75
static enum ec_mode {
A
Alexey Starikovskiy 已提交
76 77
	EC_INTR = 1,		/* Output buffer full */
	EC_POLL,		/* Input buffer empty */
78
} acpi_ec_mode = EC_INTR;
79

L
Len Brown 已提交
80 81 82
static int acpi_ec_remove(struct acpi_device *device, int type);
static int acpi_ec_start(struct acpi_device *device);
static int acpi_ec_stop(struct acpi_device *device, int type);
83
static int acpi_ec_add(struct acpi_device *device);
L
Linus Torvalds 已提交
84 85

static struct acpi_driver acpi_ec_driver = {
L
Len Brown 已提交
86
	.name = "ec",
L
Len Brown 已提交
87 88 89
	.class = ACPI_EC_CLASS,
	.ids = ACPI_EC_HID,
	.ops = {
90
		.add = acpi_ec_add,
L
Len Brown 已提交
91 92 93 94
		.remove = acpi_ec_remove,
		.start = acpi_ec_start,
		.stop = acpi_ec_stop,
		},
L
Linus Torvalds 已提交
95
};
96 97

/* If we find an EC via the ECDT, we need to keep a ptr to its context */
98
/* External interfaces use first EC only, so remember */
99 100 101 102 103 104 105 106 107 108
typedef int (*acpi_ec_query_func) (void *data);

struct acpi_ec_query_handler {
	struct list_head node;
	acpi_ec_query_func func;
	acpi_handle handle;
	void *data;
	u8 query_bit;
};

109
static struct acpi_ec {
110
	acpi_handle handle;
111
	unsigned long gpe;
112 113
	unsigned long command_addr;
	unsigned long data_addr;
114
	unsigned long global_lock;
115
	struct mutex lock;
116
	atomic_t query_pending;
117
	atomic_t event_count;
118
	wait_queue_head_t wait;
119
	struct list_head list;
120
} *boot_ec, *first_ec;
121

L
Linus Torvalds 已提交
122 123 124 125
/* --------------------------------------------------------------------------
                             Transaction Management
   -------------------------------------------------------------------------- */

126
static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
L
Linus Torvalds 已提交
127
{
128
	return inb(ec->command_addr);
D
Dmitry Torokhov 已提交
129 130
}

131
static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
132
{
133
	return inb(ec->data_addr);
134 135
}

136
static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
L
Luming Yu 已提交
137
{
138
	outb(command, ec->command_addr);
L
Luming Yu 已提交
139 140
}

141
static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
L
Luming Yu 已提交
142
{
143
	outb(data, ec->data_addr);
144
}
L
Luming Yu 已提交
145

146 147
static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event,
				       unsigned old_count)
148
{
149
	u8 status = acpi_ec_read_status(ec);
150 151
	if (old_count == atomic_read(&ec->event_count))
		return 0;
A
Alexey Starikovskiy 已提交
152
	if (event == ACPI_EC_EVENT_OBF_1) {
153 154
		if (status & ACPI_EC_FLAG_OBF)
			return 1;
A
Alexey Starikovskiy 已提交
155
	} else if (event == ACPI_EC_EVENT_IBF_0) {
156 157
		if (!(status & ACPI_EC_FLAG_IBF))
			return 1;
L
Luming Yu 已提交
158 159
	}

160
	return 0;
L
Luming Yu 已提交
161
}
D
Dmitry Torokhov 已提交
162

163 164
static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event,
                        unsigned count, int force_poll)
165
{
166
	if (unlikely(force_poll) || acpi_ec_mode == EC_POLL) {
167 168
		unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
		while (time_before(jiffies, delay)) {
169
			if (acpi_ec_check_status(ec, event, 0))
170 171
				return 0;
		}
172 173
	} else {
		if (wait_event_timeout(ec->wait,
174
				       acpi_ec_check_status(ec, event, count),
175
				       msecs_to_jiffies(ACPI_EC_DELAY)) ||
176
		    acpi_ec_check_status(ec, event, 0)) {
177
			return 0;
178 179 180
		} else {
			printk(KERN_ERR PREFIX "acpi_ec_wait timeout,"
			       " status = %d, expect_event = %d\n",
A
Alexey Starikovskiy 已提交
181
			       acpi_ec_read_status(ec), event);
182
		}
183
	}
L
Linus Torvalds 已提交
184

185
	return -ETIME;
L
Linus Torvalds 已提交
186 187
}

188
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
A
Alexey Starikovskiy 已提交
189
					const u8 * wdata, unsigned wdata_len,
190 191
					u8 * rdata, unsigned rdata_len,
					int force_poll)
L
Luming Yu 已提交
192
{
193
	int result = 0;
194
	unsigned count = atomic_read(&ec->event_count);
195
	acpi_ec_write_cmd(ec, command);
L
Luming Yu 已提交
196

A
Alexey Starikovskiy 已提交
197
	for (; wdata_len > 0; --wdata_len) {
198
		result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll);
199
		if (result) {
A
Alexey Starikovskiy 已提交
200 201
			printk(KERN_ERR PREFIX
			       "write_cmd timeout, command = %d\n", command);
202 203
			goto end;
		}
204
		count = atomic_read(&ec->event_count);
205
		acpi_ec_write_data(ec, *(wdata++));
206
	}
L
Luming Yu 已提交
207

208
	if (!rdata_len) {
209
		result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll);
210
		if (result) {
A
Alexey Starikovskiy 已提交
211 212
			printk(KERN_ERR PREFIX
			       "finish-write timeout, command = %d\n", command);
213 214
			goto end;
		}
215 216
	} else if (command == ACPI_EC_COMMAND_QUERY) {
		atomic_set(&ec->query_pending, 0);
217
	}
L
Luming Yu 已提交
218

A
Alexey Starikovskiy 已提交
219
	for (; rdata_len > 0; --rdata_len) {
220
		result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, count, force_poll);
221 222
		if (result) {
			printk(KERN_ERR PREFIX "read timeout, command = %d\n",
A
Alexey Starikovskiy 已提交
223
			       command);
224 225
			goto end;
		}
226
		count = atomic_read(&ec->event_count);
227
		*(rdata++) = acpi_ec_read_data(ec);
228
	}
229 230
      end:
	return result;
L
Luming Yu 已提交
231 232
}

233
static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
A
Alexey Starikovskiy 已提交
234
			       const u8 * wdata, unsigned wdata_len,
235 236
			       u8 * rdata, unsigned rdata_len,
			       int force_poll)
L
Linus Torvalds 已提交
237
{
238
	int status;
L
Len Brown 已提交
239
	u32 glk;
L
Linus Torvalds 已提交
240

241
	if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
242
		return -EINVAL;
L
Linus Torvalds 已提交
243

A
Alexey Starikovskiy 已提交
244 245
	if (rdata)
		memset(rdata, 0, rdata_len);
L
Linus Torvalds 已提交
246

247
	mutex_lock(&ec->lock);
248
	if (ec->global_lock) {
L
Linus Torvalds 已提交
249
		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
250 251
		if (ACPI_FAILURE(status)) {
			mutex_unlock(&ec->lock);
252
			return -ENODEV;
253
		}
L
Linus Torvalds 已提交
254
	}
D
Dmitry Torokhov 已提交
255

256
	/* Make sure GPE is enabled before doing transaction */
257
	acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
258

259
	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0);
260
	if (status) {
261
		printk(KERN_ERR PREFIX
A
Alexey Starikovskiy 已提交
262
		       "input buffer is not empty, aborting transaction\n");
D
Dmitry Torokhov 已提交
263
		goto end;
264
	}
L
Linus Torvalds 已提交
265

A
Alexey Starikovskiy 已提交
266 267
	status = acpi_ec_transaction_unlocked(ec, command,
					      wdata, wdata_len,
268 269
					      rdata, rdata_len,
					      force_poll);
L
Linus Torvalds 已提交
270

A
Alexey Starikovskiy 已提交
271
      end:
L
Linus Torvalds 已提交
272

273
	if (ec->global_lock)
L
Linus Torvalds 已提交
274
		acpi_release_global_lock(glk);
275
	mutex_unlock(&ec->lock);
L
Linus Torvalds 已提交
276

277
	return status;
L
Linus Torvalds 已提交
278 279
}

280 281 282 283 284 285 286
/*
 * Note: samsung nv5000 doesn't work with ec burst mode.
 * http://bugzilla.kernel.org/show_bug.cgi?id=4980
 */
int acpi_ec_burst_enable(struct acpi_ec *ec)
{
	u8 d;
287
	return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1, 0);
288 289 290 291
}

int acpi_ec_burst_disable(struct acpi_ec *ec)
{
292
	return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0, 0);
293 294
}

A
Alexey Starikovskiy 已提交
295
static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
296 297 298 299 300
{
	int result;
	u8 d;

	result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ,
301
				     &address, 1, &d, 1, 0);
302 303 304
	*data = d;
	return result;
}
305

306 307
static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
{
A
Alexey Starikovskiy 已提交
308 309
	u8 wdata[2] = { address, data };
	return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE,
310
				   wdata, 2, NULL, 0, 0);
311 312
}

L
Linus Torvalds 已提交
313 314 315
/*
 * Externally callable EC access functions. For now, assume 1 EC only
 */
316 317 318 319
int ec_burst_enable(void)
{
	if (!first_ec)
		return -ENODEV;
320
	return acpi_ec_burst_enable(first_ec);
321 322 323 324 325 326 327 328
}

EXPORT_SYMBOL(ec_burst_enable);

int ec_burst_disable(void)
{
	if (!first_ec)
		return -ENODEV;
329
	return acpi_ec_burst_disable(first_ec);
330 331 332 333
}

EXPORT_SYMBOL(ec_burst_disable);

A
Alexey Starikovskiy 已提交
334
int ec_read(u8 addr, u8 * val)
L
Linus Torvalds 已提交
335 336
{
	int err;
337
	u8 temp_data;
L
Linus Torvalds 已提交
338 339 340 341

	if (!first_ec)
		return -ENODEV;

342
	err = acpi_ec_read(first_ec, addr, &temp_data);
L
Linus Torvalds 已提交
343 344 345 346

	if (!err) {
		*val = temp_data;
		return 0;
L
Len Brown 已提交
347
	} else
L
Linus Torvalds 已提交
348 349
		return err;
}
L
Len Brown 已提交
350

L
Linus Torvalds 已提交
351 352
EXPORT_SYMBOL(ec_read);

L
Len Brown 已提交
353
int ec_write(u8 addr, u8 val)
L
Linus Torvalds 已提交
354 355 356 357 358 359
{
	int err;

	if (!first_ec)
		return -ENODEV;

360
	err = acpi_ec_write(first_ec, addr, val);
L
Linus Torvalds 已提交
361 362 363

	return err;
}
L
Len Brown 已提交
364

L
Linus Torvalds 已提交
365 366
EXPORT_SYMBOL(ec_write);

367
int ec_transaction(u8 command,
368
		   const u8 * wdata, unsigned wdata_len,
369 370
		   u8 * rdata, unsigned rdata_len,
		   int force_poll)
L
Luming Yu 已提交
371
{
372 373
	if (!first_ec)
		return -ENODEV;
L
Luming Yu 已提交
374

375
	return acpi_ec_transaction(first_ec, command, wdata,
376 377
				   wdata_len, rdata, rdata_len,
				   force_poll);
L
Luming Yu 已提交
378
}
L
Linus Torvalds 已提交
379

380 381
EXPORT_SYMBOL(ec_transaction);

A
Alexey Starikovskiy 已提交
382
static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
383 384
{
	int result;
A
Alexey Starikovskiy 已提交
385
	u8 d;
L
Linus Torvalds 已提交
386

A
Alexey Starikovskiy 已提交
387 388
	if (!ec || !data)
		return -EINVAL;
L
Linus Torvalds 已提交
389

A
Alexey Starikovskiy 已提交
390 391 392 393 394
	/*
	 * Query the EC to find out which _Qxx method we need to evaluate.
	 * Note that successful completion of the query causes the ACPI_EC_SCI
	 * bit to be cleared (and thus clearing the interrupt source).
	 */
395

396
	result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1, 0);
A
Alexey Starikovskiy 已提交
397 398
	if (result)
		return result;
L
Linus Torvalds 已提交
399

A
Alexey Starikovskiy 已提交
400 401
	if (!d)
		return -ENODATA;
L
Linus Torvalds 已提交
402

A
Alexey Starikovskiy 已提交
403 404
	*data = d;
	return 0;
L
Linus Torvalds 已提交
405 406 407 408 409
}

/* --------------------------------------------------------------------------
                                Event Management
   -------------------------------------------------------------------------- */
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
			      acpi_handle handle, acpi_ec_query_func func,
			      void *data)
{
	struct acpi_ec_query_handler *handler =
	    kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL);
	if (!handler)
		return -ENOMEM;

	handler->query_bit = query_bit;
	handler->handle = handle;
	handler->func = func;
	handler->data = data;
	mutex_lock(&ec->lock);
	list_add_tail(&handler->node, &ec->list);
	mutex_unlock(&ec->lock);
	return 0;
}

EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);

void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
{
	struct acpi_ec_query_handler *handler;
	mutex_lock(&ec->lock);
	list_for_each_entry(handler, &ec->list, node) {
		if (query_bit == handler->query_bit) {
			list_del(&handler->node);
			kfree(handler);
			break;
		}
	}
	mutex_unlock(&ec->lock);
}

EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
L
Linus Torvalds 已提交
446

L
Len Brown 已提交
447
static void acpi_ec_gpe_query(void *ec_cxt)
L
Luming Yu 已提交
448
{
449
	struct acpi_ec *ec = ec_cxt;
450
	u8 value = 0;
451
	struct acpi_ec_query_handler *handler, copy;
L
Luming Yu 已提交
452

453
	if (!ec || acpi_ec_query(ec, &value))
454
		return;
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
	mutex_lock(&ec->lock);
	list_for_each_entry(handler, &ec->list, node) {
		if (value == handler->query_bit) {
			/* have custom handler for this bit */
			memcpy(&copy, handler, sizeof(copy));
			mutex_unlock(&ec->lock);
			if (copy.func) {
				copy.func(copy.data);
			} else if (copy.handle) {
				acpi_evaluate_object(copy.handle, NULL, NULL, NULL);
			}
			return;
		}
	}
	mutex_unlock(&ec->lock);
	printk(KERN_ERR PREFIX "Handler for query 0x%x is not found!\n", value);
L
Luming Yu 已提交
471
}
L
Linus Torvalds 已提交
472

L
Len Brown 已提交
473
static u32 acpi_ec_gpe_handler(void *data)
L
Linus Torvalds 已提交
474
{
L
Len Brown 已提交
475
	acpi_status status = AE_OK;
476
	u8 value;
477
	struct acpi_ec *ec = data;
478

479
	atomic_inc(&ec->event_count);
480

481
	if (acpi_ec_mode == EC_INTR) {
482
		wake_up(&ec->wait);
D
Dmitry Torokhov 已提交
483 484
	}

485
	value = acpi_ec_read_status(ec);
486 487
	if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) {
		atomic_set(&ec->query_pending, 1);
A
Alexey Starikovskiy 已提交
488
		status =
489
		    acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
L
Len Brown 已提交
490
	}
491

D
Dmitry Torokhov 已提交
492
	return status == AE_OK ?
L
Len Brown 已提交
493
	    ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
L
Linus Torvalds 已提交
494 495 496 497 498 499 500
}

/* --------------------------------------------------------------------------
                             Address Space Management
   -------------------------------------------------------------------------- */

static acpi_status
L
Len Brown 已提交
501 502
acpi_ec_space_setup(acpi_handle region_handle,
		    u32 function, void *handler_context, void **return_context)
L
Linus Torvalds 已提交
503 504 505 506 507
{
	/*
	 * The EC object is in the handler context and is needed
	 * when calling the acpi_ec_space_handler.
	 */
L
Len Brown 已提交
508 509
	*return_context = (function != ACPI_REGION_DEACTIVATE) ?
	    handler_context : NULL;
L
Linus Torvalds 已提交
510 511 512 513 514

	return AE_OK;
}

static acpi_status
515 516
acpi_ec_space_handler(u32 function, acpi_physical_address address,
		      u32 bits, acpi_integer *value,
L
Len Brown 已提交
517
		      void *handler_context, void *region_context)
L
Linus Torvalds 已提交
518
{
519
	struct acpi_ec *ec = handler_context;
520 521
	int result = 0, i = 0;
	u8 temp = 0;
L
Linus Torvalds 已提交
522 523

	if ((address > 0xFF) || !value || !handler_context)
524
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
525

526
	if (function != ACPI_READ && function != ACPI_WRITE)
527
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
528

529 530
	if (bits != 8 && acpi_strict)
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
531

532 533 534 535 536 537 538 539 540 541
	while (bits - i > 0) {
		if (function == ACPI_READ) {
			result = acpi_ec_read(ec, address, &temp);
			(*value) |= ((acpi_integer)temp) << i;
		} else {
			temp = 0xff & ((*value) >> i);
			result = acpi_ec_write(ec, address, temp);
		}
		i += 8;
		++address;
L
Linus Torvalds 已提交
542 543 544 545
	}

	switch (result) {
	case -EINVAL:
546
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
547 548
		break;
	case -ENODEV:
549
		return AE_NOT_FOUND;
L
Linus Torvalds 已提交
550 551
		break;
	case -ETIME:
552
		return AE_TIME;
L
Linus Torvalds 已提交
553 554
		break;
	default:
555
		return AE_OK;
L
Linus Torvalds 已提交
556 557 558 559 560 561 562
	}
}

/* --------------------------------------------------------------------------
                              FS Interface (/proc)
   -------------------------------------------------------------------------- */

L
Len Brown 已提交
563
static struct proc_dir_entry *acpi_ec_dir;
L
Linus Torvalds 已提交
564

L
Len Brown 已提交
565
static int acpi_ec_read_info(struct seq_file *seq, void *offset)
L
Linus Torvalds 已提交
566
{
567
	struct acpi_ec *ec = seq->private;
L
Linus Torvalds 已提交
568 569 570 571

	if (!ec)
		goto end;

572 573 574 575
	seq_printf(seq, "gpe:\t\t\t0x%02x\n", (u32) ec->gpe);
	seq_printf(seq, "ports:\t\t\t0x%02x, 0x%02x\n",
		   (unsigned)ec->command_addr, (unsigned)ec->data_addr);
	seq_printf(seq, "use global lock:\t%s\n",
576
		   ec->global_lock ? "yes" : "no");
L
Len Brown 已提交
577
      end:
578
	return 0;
L
Linus Torvalds 已提交
579 580 581 582 583 584 585
}

static int acpi_ec_info_open_fs(struct inode *inode, struct file *file)
{
	return single_open(file, acpi_ec_read_info, PDE(inode)->data);
}

586
static struct file_operations acpi_ec_info_ops = {
L
Len Brown 已提交
587 588 589 590
	.open = acpi_ec_info_open_fs,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
L
Linus Torvalds 已提交
591 592 593
	.owner = THIS_MODULE,
};

L
Len Brown 已提交
594
static int acpi_ec_add_fs(struct acpi_device *device)
L
Linus Torvalds 已提交
595
{
L
Len Brown 已提交
596
	struct proc_dir_entry *entry = NULL;
L
Linus Torvalds 已提交
597 598 599

	if (!acpi_device_dir(device)) {
		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
L
Len Brown 已提交
600
						     acpi_ec_dir);
L
Linus Torvalds 已提交
601
		if (!acpi_device_dir(device))
602
			return -ENODEV;
L
Linus Torvalds 已提交
603 604 605
	}

	entry = create_proc_entry(ACPI_EC_FILE_INFO, S_IRUGO,
L
Len Brown 已提交
606
				  acpi_device_dir(device));
L
Linus Torvalds 已提交
607
	if (!entry)
608
		return -ENODEV;
L
Linus Torvalds 已提交
609 610 611 612 613 614
	else {
		entry->proc_fops = &acpi_ec_info_ops;
		entry->data = acpi_driver_data(device);
		entry->owner = THIS_MODULE;
	}

615
	return 0;
L
Linus Torvalds 已提交
616 617
}

L
Len Brown 已提交
618
static int acpi_ec_remove_fs(struct acpi_device *device)
L
Linus Torvalds 已提交
619 620 621 622 623 624 625 626
{

	if (acpi_device_dir(device)) {
		remove_proc_entry(ACPI_EC_FILE_INFO, acpi_device_dir(device));
		remove_proc_entry(acpi_device_bid(device), acpi_ec_dir);
		acpi_device_dir(device) = NULL;
	}

627
	return 0;
L
Linus Torvalds 已提交
628 629 630 631 632
}

/* --------------------------------------------------------------------------
                               Driver Interface
   -------------------------------------------------------------------------- */
633 634 635 636 637 638 639 640 641
static acpi_status
ec_parse_io_ports(struct acpi_resource *resource, void *context);

static struct acpi_ec *make_acpi_ec(void)
{
	struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
	if (!ec)
		return NULL;

642
	atomic_set(&ec->query_pending, 1);
643 644 645
	atomic_set(&ec->event_count, 1);
	mutex_init(&ec->lock);
	init_waitqueue_head(&ec->wait);
646
	INIT_LIST_HEAD(&ec->list);
647 648 649

	return ec;
}
L
Linus Torvalds 已提交
650

651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
static acpi_status
acpi_ec_register_query_methods(acpi_handle handle, u32 level,
			       void *context, void **return_value)
{
	struct acpi_namespace_node *node = handle;
	struct acpi_ec *ec = context;
	int value = 0;
	if (sscanf(node->name.ascii, "_Q%x", &value) == 1) {
		acpi_ec_add_query_handler(ec, value, handle, NULL, NULL);
	}
	return AE_OK;
}

static int ec_parse_device(struct acpi_ec *ec, acpi_handle handle)
{
	if (ACPI_FAILURE(acpi_walk_resources(handle, METHOD_NAME__CRS,
				     ec_parse_io_ports, ec)))
		return -EINVAL;

	/* Get GPE bit assignment (EC events). */
	/* TODO: Add support for _GPE returning a package */
	if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe)))
		return -EINVAL;

	/* Use the global lock for all EC transactions? */
	acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);

	/* Find and register all query methods */
	acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
			    acpi_ec_register_query_methods, ec, NULL);

	ec->handle = handle;

	printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx",
			  ec->gpe, ec->command_addr, ec->data_addr);

	return 0;
}

690
static int acpi_ec_add(struct acpi_device *device)
L
Linus Torvalds 已提交
691
{
692
	struct acpi_ec *ec = NULL;
L
Luming Yu 已提交
693 694

	if (!device)
695
		return -EINVAL;
L
Luming Yu 已提交
696

697 698 699 700
	strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
	strcpy(acpi_device_class(device), ACPI_EC_CLASS);

	ec = make_acpi_ec();
L
Luming Yu 已提交
701
	if (!ec)
702
		return -ENOMEM;
703

704
	if (ec_parse_device(ec, device->handle)) {
705 706
		kfree(ec);
		return -EINVAL;
L
Luming Yu 已提交
707
	}
L
Linus Torvalds 已提交
708

709
	/* Check if we found the boot EC */
710 711
	if (boot_ec) {
		if (boot_ec->gpe == ec->gpe) {
712
			/* We might have incorrect info for GL at boot time */
713 714
			mutex_lock(&boot_ec->lock);
			boot_ec->global_lock = ec->global_lock;
715 716
			/* Copy handlers from new ec into boot ec */
			list_splice(&ec->list, &boot_ec->list);
717
			mutex_unlock(&boot_ec->lock);
718
			kfree(ec);
719
			ec = boot_ec;
720
		}
721 722
	} else
		first_ec = ec;
723 724
	ec->handle = device->handle;
	acpi_driver_data(device) = ec;
L
Linus Torvalds 已提交
725

726 727
	acpi_ec_add_fs(device);
	return 0;
L
Linus Torvalds 已提交
728 729
}

L
Len Brown 已提交
730
static int acpi_ec_remove(struct acpi_device *device, int type)
L
Linus Torvalds 已提交
731
{
732
	struct acpi_ec *ec;
733
	struct acpi_ec_query_handler *handler;
L
Linus Torvalds 已提交
734 735

	if (!device)
736
		return -EINVAL;
L
Linus Torvalds 已提交
737 738

	ec = acpi_driver_data(device);
739 740 741 742 743 744
	mutex_lock(&ec->lock);
	list_for_each_entry(handler, &ec->list, node) {
		list_del(&handler->node);
		kfree(handler);
	}
	mutex_unlock(&ec->lock);
L
Linus Torvalds 已提交
745
	acpi_ec_remove_fs(device);
746
	acpi_driver_data(device) = NULL;
747
	if (ec == first_ec)
748 749 750
		first_ec = NULL;

	/* Don't touch boot EC */
751
	if (boot_ec != ec)
752
		kfree(ec);
753
	return 0;
L
Linus Torvalds 已提交
754 755 756
}

static acpi_status
757
ec_parse_io_ports(struct acpi_resource *resource, void *context)
L
Linus Torvalds 已提交
758
{
759
	struct acpi_ec *ec = context;
L
Linus Torvalds 已提交
760

761
	if (resource->type != ACPI_RESOURCE_TYPE_IO)
L
Linus Torvalds 已提交
762 763 764 765 766 767 768
		return AE_OK;

	/*
	 * The first address region returned is the data port, and
	 * the second address region returned is the status/command
	 * port.
	 */
769
	if (ec->data_addr == 0)
770
		ec->data_addr = resource->data.io.minimum;
771
	else if (ec->command_addr == 0)
772
		ec->command_addr = resource->data.io.minimum;
773
	else
L
Linus Torvalds 已提交
774 775 776 777 778
		return AE_CTRL_TERMINATE;

	return AE_OK;
}

779 780
static int ec_install_handlers(struct acpi_ec *ec)
{
781 782 783 784
	acpi_status status;
	status = acpi_install_gpe_handler(NULL, ec->gpe,
					  ACPI_GPE_EDGE_TRIGGERED,
					  &acpi_ec_gpe_handler, ec);
785 786
	if (ACPI_FAILURE(status))
		return -ENODEV;
787

788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
	acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
	acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);

	status = acpi_install_address_space_handler(ec->handle,
						    ACPI_ADR_SPACE_EC,
						    &acpi_ec_space_handler,
						    &acpi_ec_space_setup, ec);
	if (ACPI_FAILURE(status)) {
		acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
		return -ENODEV;
	}

	return 0;
}

L
Len Brown 已提交
803
static int acpi_ec_start(struct acpi_device *device)
L
Linus Torvalds 已提交
804
{
805
	struct acpi_ec *ec;
806
	int ret = 0;
L
Linus Torvalds 已提交
807 808

	if (!device)
809
		return -EINVAL;
L
Linus Torvalds 已提交
810 811 812 813

	ec = acpi_driver_data(device);

	if (!ec)
814
		return -EINVAL;
L
Linus Torvalds 已提交
815

816
	/* Boot EC is already working */
817 818 819 820 821
	if (ec != boot_ec)
		ret = ec_install_handlers(ec);

	/* EC is fully operational, allow queries */
	atomic_set(&ec->query_pending, 0);
822

823
	return ret;
L
Linus Torvalds 已提交
824 825
}

L
Len Brown 已提交
826
static int acpi_ec_stop(struct acpi_device *device, int type)
L
Linus Torvalds 已提交
827
{
828 829
	acpi_status status;
	struct acpi_ec *ec;
L
Linus Torvalds 已提交
830 831

	if (!device)
832
		return -EINVAL;
L
Linus Torvalds 已提交
833 834

	ec = acpi_driver_data(device);
835 836 837 838
	if (!ec)
		return -EINVAL;

	/* Don't touch boot EC */
839
	if (ec == boot_ec)
840
		return 0;
L
Linus Torvalds 已提交
841

842
	status = acpi_remove_address_space_handler(ec->handle,
L
Len Brown 已提交
843 844
						   ACPI_ADR_SPACE_EC,
						   &acpi_ec_space_handler);
L
Linus Torvalds 已提交
845
	if (ACPI_FAILURE(status))
846
		return -ENODEV;
L
Linus Torvalds 已提交
847

A
Alexey Starikovskiy 已提交
848
	status = acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
L
Linus Torvalds 已提交
849
	if (ACPI_FAILURE(status))
850
		return -ENODEV;
L
Linus Torvalds 已提交
851

852
	return 0;
L
Linus Torvalds 已提交
853 854
}

855 856 857 858
int __init acpi_ec_ecdt_probe(void)
{
	int ret;
	acpi_status status;
L
Len Brown 已提交
859
	struct acpi_table_ecdt *ecdt_ptr;
L
Luming Yu 已提交
860

861 862
	boot_ec = make_acpi_ec();
	if (!boot_ec)
863 864 865 866 867
		return -ENOMEM;
	/*
	 * Generate a boot ec context
	 */

868 869
	status = acpi_get_table(ACPI_SIG_ECDT, 1,
				(struct acpi_table_header **)&ecdt_ptr);
L
Luming Yu 已提交
870
	if (ACPI_FAILURE(status))
871
		goto error;
L
Luming Yu 已提交
872

873
	printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n");
L
Luming Yu 已提交
874

875 876 877 878
	boot_ec->command_addr = ecdt_ptr->control.address;
	boot_ec->data_addr = ecdt_ptr->data.address;
	boot_ec->gpe = ecdt_ptr->gpe;
	boot_ec->handle = ACPI_ROOT_OBJECT;
L
Linus Torvalds 已提交
879

880
	ret = ec_install_handlers(boot_ec);
881 882
	if (!ret) {
		first_ec = boot_ec;
883
		return 0;
884
	}
885
      error:
886 887
	kfree(boot_ec);
	boot_ec = NULL;
L
Linus Torvalds 已提交
888 889 890 891

	return -ENODEV;
}

L
Len Brown 已提交
892
static int __init acpi_ec_init(void)
L
Linus Torvalds 已提交
893
{
L
Len Brown 已提交
894
	int result = 0;
L
Linus Torvalds 已提交
895 896

	if (acpi_disabled)
897
		return 0;
L
Linus Torvalds 已提交
898 899 900

	acpi_ec_dir = proc_mkdir(ACPI_EC_CLASS, acpi_root_dir);
	if (!acpi_ec_dir)
901
		return -ENODEV;
L
Linus Torvalds 已提交
902 903 904 905 906

	/* Now register the driver for the EC */
	result = acpi_bus_register_driver(&acpi_ec_driver);
	if (result < 0) {
		remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
907
		return -ENODEV;
L
Linus Torvalds 已提交
908 909
	}

910
	return result;
L
Linus Torvalds 已提交
911 912 913 914 915 916
}

subsys_initcall(acpi_ec_init);

/* EC driver currently not unloadable */
#if 0
L
Len Brown 已提交
917
static void __exit acpi_ec_exit(void)
L
Linus Torvalds 已提交
918 919 920 921 922 923
{

	acpi_bus_unregister_driver(&acpi_ec_driver);

	remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);

924
	return;
L
Linus Torvalds 已提交
925
}
L
Len Brown 已提交
926
#endif				/* 0 */
L
Linus Torvalds 已提交
927

928
static int __init acpi_ec_set_intr_mode(char *str)
L
Luming Yu 已提交
929
{
930
	int intr;
931

932
	if (!get_option(&str, &intr))
933 934
		return 0;

935 936
	acpi_ec_mode = (intr) ? EC_INTR : EC_POLL;

937
	printk(KERN_NOTICE PREFIX "%s mode.\n", intr ? "interrupt" : "polling");
938

939
	return 1;
L
Luming Yu 已提交
940
}
L
Len Brown 已提交
941

942
__setup("ec_intr=", acpi_ec_set_intr_mode);