Blame view

drivers/acpi/ec.c 27.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
2
   *  ec.c - ACPI Embedded Controller Driver (v2.1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
   *
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
4
   *  Copyright (C) 2006-2008 Alexey Starikovskiy <astarikovskiy@suse.de>
01f224626   Alexey Starikovskiy   ACPI: EC: Cleanup...
5
   *  Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   *  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.
   *
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   */
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
28
  /* Uncomment next line to get verbose printout */
d772b3b32   Márton Németh   ACPI: EC: "DEBUG"...
29
  /* #define DEBUG */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
34
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/types.h>
  #include <linux/delay.h>
451566f45   Dmitry Torokhov   [ACPI] Enable EC ...
35
  #include <linux/interrupt.h>
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
36
  #include <linux/list.h>
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
37
  #include <linux/spinlock.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
38
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
  #include <asm/io.h>
  #include <acpi/acpi_bus.h>
  #include <acpi/acpi_drivers.h>
eb27cae8a   Len Brown   ACPI: linux/acpi....
42
  #include <linux/dmi.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

1195a0981   Thomas Renninger   ACPI: Provide /sy...
44
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  #define ACPI_EC_CLASS			"embedded_controller"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
  #define ACPI_EC_DEVICE_NAME		"Embedded Controller"
  #define ACPI_EC_FILE_INFO		"info"
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
48

1195a0981   Thomas Renninger   ACPI: Provide /sy...
49
  #undef PREFIX
af3fd1404   Alexey Starikovskiy   ACPI: ec: Remove ...
50
  #define PREFIX				"ACPI: EC: "
4350933a7   Alexey Starikovskiy   ACPI EC: drop usa...
51

703959d47   Denis M. Sadykov   ACPI: EC: Remove ...
52
  /* EC status register */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
  #define ACPI_EC_FLAG_OBF	0x01	/* Output buffer full */
  #define ACPI_EC_FLAG_IBF	0x02	/* Input buffer full */
451566f45   Dmitry Torokhov   [ACPI] Enable EC ...
55
  #define ACPI_EC_FLAG_BURST	0x10	/* burst mode */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  #define ACPI_EC_FLAG_SCI	0x20	/* EC-SCI occurred */
4350933a7   Alexey Starikovskiy   ACPI EC: drop usa...
57

703959d47   Denis M. Sadykov   ACPI: EC: Remove ...
58
  /* EC commands */
3261ff4db   Alexey Starikovskiy   ACPI: ec: Change ...
59
  enum ec_command {
6ccedb10e   Alexey Starikovskiy   ACPI: ec: Lindent...
60
61
62
63
64
  	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,
3261ff4db   Alexey Starikovskiy   ACPI: ec: Change ...
65
  };
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
66

5c4064124   Alexey Starikovskiy   ACPI: ec: Increas...
67
  #define ACPI_EC_DELAY		500	/* Wait 500ms max. during EC ops */
703959d47   Denis M. Sadykov   ACPI: EC: Remove ...
68
  #define ACPI_EC_UDELAY_GLK	1000	/* Wait 1ms max. to get global lock */
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
69
  #define ACPI_EC_MSI_UDELAY	550	/* Wait 550us for MSI EC */
703959d47   Denis M. Sadykov   ACPI: EC: Remove ...
70

06cf7d3c7   Alexey Starikovskiy   ACPI: EC: lower i...
71
  #define ACPI_EC_STORM_THRESHOLD 8	/* number of false interrupts
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
72
  					   per one transaction */
080e412cc   Alexey Starikovskiy   ACPI: EC: Replace...
73
  enum {
080e412cc   Alexey Starikovskiy   ACPI: EC: Replace...
74
  	EC_FLAGS_QUERY_PENDING,		/* Query is pending */
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
75
  	EC_FLAGS_GPE_STORM,		/* GPE storm detected */
f6bb13aa1   Rafael J. Wysocki   ACPI / EC / PM: C...
76
  	EC_FLAGS_HANDLERS_INSTALLED,	/* Handlers for GPE and
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
77
  					 * OpReg are installed */
fe955682d   Rafael J. Wysocki   ACPI / EC / PM: F...
78
  	EC_FLAGS_BLOCKED,		/* Transactions are blocked */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  };
6ffb221a8   Denis M. Sadykov   ACPI: EC: Simplif...
80

7a18e96dc   Thomas Renninger   ACPI: Make Embedd...
81
82
83
84
  /* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */
  static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
  module_param(ec_delay, uint, 0644);
  MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
6ffb221a8   Denis M. Sadykov   ACPI: EC: Simplif...
85
  /* If we find an EC via the ECDT, we need to keep a ptr to its context */
d033879c9   Alexey Starikovskiy   ACPI: EC: first_e...
86
  /* External interfaces use first EC only, so remember */
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
87
88
89
90
91
92
93
94
95
  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;
  };
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
96
  struct transaction {
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
97
98
99
  	const u8 *wdata;
  	u8 *rdata;
  	unsigned short irq_count;
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
100
  	u8 command;
a2f93aead   Alexey Starikovskiy   ACPI: EC: restart...
101
102
  	u8 wi;
  	u8 ri;
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
103
104
  	u8 wlen;
  	u8 rlen;
dd15f8c42   Alexey Starikovskiy   ACPI: EC: wait fo...
105
  	bool done;
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
106
  };
1195a0981   Thomas Renninger   ACPI: Provide /sy...
107
108
  struct acpi_ec *boot_ec, *first_ec;
  EXPORT_SYMBOL(first_ec);
703959d47   Denis M. Sadykov   ACPI: EC: Remove ...
109

5423a0cb3   Alexey Starikovskiy   ACPI: EC: Add del...
110
  static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
0adf3c746   Alexey Starikovskiy   ACPI: EC: Rewrite...
111
  static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
478fa03b3   Alexey Starikovskiy   ACPI: EC: Don't p...
112
  static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
5423a0cb3   Alexey Starikovskiy   ACPI: EC: Add del...
113

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
  /* --------------------------------------------------------------------------
                               Transaction Management
     -------------------------------------------------------------------------- */
6ffb221a8   Denis M. Sadykov   ACPI: EC: Simplif...
117
  static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
  {
3ebe08a74   Márton Németh   ACPI: EC: use pri...
119
  	u8 x = inb(ec->command_addr);
86dae0154   Márton Németh   ACPI: EC: add lea...
120
121
  	pr_debug(PREFIX "---> status = 0x%2.2x
  ", x);
3ebe08a74   Márton Németh   ACPI: EC: use pri...
122
  	return x;
451566f45   Dmitry Torokhov   [ACPI] Enable EC ...
123
  }
6ffb221a8   Denis M. Sadykov   ACPI: EC: Simplif...
124
  static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
703959d47   Denis M. Sadykov   ACPI: EC: Remove ...
125
  {
3ebe08a74   Márton Németh   ACPI: EC: use pri...
126
  	u8 x = inb(ec->data_addr);
86dae0154   Márton Németh   ACPI: EC: add lea...
127
128
  	pr_debug(PREFIX "---> data = 0x%2.2x
  ", x);
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
129
  	return x;
7c6db5e51   Denis M. Sadykov   ACPI: EC: Remove ...
130
  }
6ffb221a8   Denis M. Sadykov   ACPI: EC: Simplif...
131
  static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
45bea1555   Luming Yu   [ACPI] Add "ec_po...
132
  {
86dae0154   Márton Németh   ACPI: EC: add lea...
133
134
  	pr_debug(PREFIX "<--- command = 0x%2.2x
  ", command);
6ffb221a8   Denis M. Sadykov   ACPI: EC: Simplif...
135
  	outb(command, ec->command_addr);
45bea1555   Luming Yu   [ACPI] Add "ec_po...
136
  }
6ffb221a8   Denis M. Sadykov   ACPI: EC: Simplif...
137
  static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
45bea1555   Luming Yu   [ACPI] Add "ec_po...
138
  {
86dae0154   Márton Németh   ACPI: EC: add lea...
139
140
  	pr_debug(PREFIX "<--- data = 0x%2.2x
  ", data);
6ffb221a8   Denis M. Sadykov   ACPI: EC: Simplif...
141
  	outb(data, ec->data_addr);
703959d47   Denis M. Sadykov   ACPI: EC: Remove ...
142
  }
45bea1555   Luming Yu   [ACPI] Add "ec_po...
143

7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
144
  static int ec_transaction_done(struct acpi_ec *ec)
6ffb221a8   Denis M. Sadykov   ACPI: EC: Simplif...
145
  {
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
146
147
  	unsigned long flags;
  	int ret = 0;
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
148
  	spin_lock_irqsave(&ec->curr_lock, flags);
dd15f8c42   Alexey Starikovskiy   ACPI: EC: wait fo...
149
  	if (!ec->curr || ec->curr->done)
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
150
  		ret = 1;
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
151
  	spin_unlock_irqrestore(&ec->curr_lock, flags);
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
152
  	return ret;
45bea1555   Luming Yu   [ACPI] Add "ec_po...
153
  }
451566f45   Dmitry Torokhov   [ACPI] Enable EC ...
154

a2f93aead   Alexey Starikovskiy   ACPI: EC: restart...
155
156
157
158
159
160
  static void start_transaction(struct acpi_ec *ec)
  {
  	ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0;
  	ec->curr->done = false;
  	acpi_ec_write_cmd(ec, ec->curr->command);
  }
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
161
  static void advance_transaction(struct acpi_ec *ec, u8 status)
7c6db5e51   Denis M. Sadykov   ACPI: EC: Remove ...
162
  {
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
163
  	unsigned long flags;
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
164
165
  	spin_lock_irqsave(&ec->curr_lock, flags);
  	if (!ec->curr)
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
166
  		goto unlock;
a2f93aead   Alexey Starikovskiy   ACPI: EC: restart...
167
168
169
170
171
  	if (ec->curr->wlen > ec->curr->wi) {
  		if ((status & ACPI_EC_FLAG_IBF) == 0)
  			acpi_ec_write_data(ec,
  				ec->curr->wdata[ec->curr->wi++]);
  		else
dd15f8c42   Alexey Starikovskiy   ACPI: EC: wait fo...
172
  			goto err;
a2f93aead   Alexey Starikovskiy   ACPI: EC: restart...
173
  	} else if (ec->curr->rlen > ec->curr->ri) {
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
174
  		if ((status & ACPI_EC_FLAG_OBF) == 1) {
a2f93aead   Alexey Starikovskiy   ACPI: EC: restart...
175
176
  			ec->curr->rdata[ec->curr->ri++] = acpi_ec_read_data(ec);
  			if (ec->curr->rlen == ec->curr->ri)
dd15f8c42   Alexey Starikovskiy   ACPI: EC: wait fo...
177
  				ec->curr->done = true;
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
178
  		} else
dd15f8c42   Alexey Starikovskiy   ACPI: EC: wait fo...
179
  			goto err;
a2f93aead   Alexey Starikovskiy   ACPI: EC: restart...
180
181
  	} else if (ec->curr->wlen == ec->curr->wi &&
  		   (status & ACPI_EC_FLAG_IBF) == 0)
dd15f8c42   Alexey Starikovskiy   ACPI: EC: wait fo...
182
183
184
185
  		ec->curr->done = true;
  	goto unlock;
  err:
  	/* false interrupt, state didn't change */
7b4d46922   Alexey Starikovskiy   ACPI: EC: count i...
186
187
  	if (in_interrupt())
  		++ec->curr->irq_count;
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
188
  unlock:
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
189
  	spin_unlock_irqrestore(&ec->curr_lock, flags);
845625cdc   Alexey Starikovskiy   ACPI: EC: Add pol...
190
  }
03d1d99c5   Alexey Starikovskiy   ACPI: EC: fix dme...
191

a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
192
  static int acpi_ec_sync_query(struct acpi_ec *ec);
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
193

a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
194
  static int ec_check_sci_sync(struct acpi_ec *ec, u8 state)
7c6db5e51   Denis M. Sadykov   ACPI: EC: Remove ...
195
  {
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
196
197
  	if (state & ACPI_EC_FLAG_SCI) {
  		if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
198
  			return acpi_ec_sync_query(ec);
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
199
200
201
202
203
204
  	}
  	return 0;
  }
  
  static int ec_poll(struct acpi_ec *ec)
  {
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
205
206
207
208
  	unsigned long flags;
  	int repeat = 2; /* number of command restarts */
  	while (repeat--) {
  		unsigned long delay = jiffies +
7a18e96dc   Thomas Renninger   ACPI: Make Embedd...
209
  			msecs_to_jiffies(ec_delay);
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  		do {
  			/* don't sleep with disabled interrupts */
  			if (EC_FLAGS_MSI || irqs_disabled()) {
  				udelay(ACPI_EC_MSI_UDELAY);
  				if (ec_transaction_done(ec))
  					return 0;
  			} else {
  				if (wait_event_timeout(ec->wait,
  						ec_transaction_done(ec),
  						msecs_to_jiffies(1)))
  					return 0;
  			}
  			advance_transaction(ec, acpi_ec_read_status(ec));
  		} while (time_before(jiffies, delay));
e12ac3d01   Alexey Starikovskiy   ACPI: EC: Restart...
224
  		if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
225
  			break;
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
226
227
228
229
230
  		pr_debug(PREFIX "controller reset, restart transaction
  ");
  		spin_lock_irqsave(&ec->curr_lock, flags);
  		start_transaction(ec);
  		spin_unlock_irqrestore(&ec->curr_lock, flags);
af3fd1404   Alexey Starikovskiy   ACPI: ec: Remove ...
231
  	}
b77d81b26   Alexey Starikovskiy   ACPI: EC: Replace...
232
  	return -ETIME;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  }
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
234
  static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
235
  					struct transaction *t)
45bea1555   Luming Yu   [ACPI] Add "ec_po...
236
  {
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
237
  	unsigned long tmp;
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
238
  	int ret = 0;
5423a0cb3   Alexey Starikovskiy   ACPI: EC: Add del...
239
  	if (EC_FLAGS_MSI)
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
240
  		udelay(ACPI_EC_MSI_UDELAY);
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
241
  	/* start transaction */
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
242
  	spin_lock_irqsave(&ec->curr_lock, tmp);
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
243
  	/* following two actions should be kept atomic */
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
244
  	ec->curr = t;
a2f93aead   Alexey Starikovskiy   ACPI: EC: restart...
245
  	start_transaction(ec);
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
246
  	if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
080e412cc   Alexey Starikovskiy   ACPI: EC: Replace...
247
  		clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
248
  	spin_unlock_irqrestore(&ec->curr_lock, tmp);
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
249
  	ret = ec_poll(ec);
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
250
251
252
  	spin_lock_irqsave(&ec->curr_lock, tmp);
  	ec->curr = NULL;
  	spin_unlock_irqrestore(&ec->curr_lock, tmp);
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
253
254
255
256
257
258
259
  	return ret;
  }
  
  static int ec_check_ibf0(struct acpi_ec *ec)
  {
  	u8 status = acpi_ec_read_status(ec);
  	return (status & ACPI_EC_FLAG_IBF) == 0;
45bea1555   Luming Yu   [ACPI] Add "ec_po...
260
  }
c0ff17720   Alexey Starikovskiy   ACPI: EC: Check f...
261
262
  static int ec_wait_ibf0(struct acpi_ec *ec)
  {
7a18e96dc   Thomas Renninger   ACPI: Make Embedd...
263
  	unsigned long delay = jiffies + msecs_to_jiffies(ec_delay);
c0ff17720   Alexey Starikovskiy   ACPI: EC: Check f...
264
  	/* interrupt wait manually if GPE mode is not active */
c0ff17720   Alexey Starikovskiy   ACPI: EC: Check f...
265
  	while (time_before(jiffies, delay))
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
266
267
  		if (wait_event_timeout(ec->wait, ec_check_ibf0(ec),
  					msecs_to_jiffies(1)))
c0ff17720   Alexey Starikovskiy   ACPI: EC: Check f...
268
269
  			return 0;
  	return -ETIME;
45bea1555   Luming Yu   [ACPI] Add "ec_po...
270
  }
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
271
  static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
  {
d7a76e4cb   Lennart Poettering   ACPI: consolidate...
273
  	int status;
50526df60   Len Brown   [ACPI] Lindent dr...
274
  	u32 glk;
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
275
  	if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
d550d98d3   Patrick Mochel   ACPI: delete trac...
276
  		return -EINVAL;
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
277
278
  	if (t->rdata)
  		memset(t->rdata, 0, t->rlen);
523953b41   Alexey Starikovskiy   ACPI: ec: Acquire...
279
  	mutex_lock(&ec->lock);
fe955682d   Rafael J. Wysocki   ACPI / EC / PM: F...
280
  	if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) {
f6bb13aa1   Rafael J. Wysocki   ACPI / EC / PM: C...
281
282
283
  		status = -EINVAL;
  		goto unlock;
  	}
703959d47   Denis M. Sadykov   ACPI: EC: Remove ...
284
  	if (ec->global_lock) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
c24e912b6   Alexey Starikovskiy   ACPI: ec: add unl...
286
  		if (ACPI_FAILURE(status)) {
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
287
288
  			status = -ENODEV;
  			goto unlock;
c24e912b6   Alexey Starikovskiy   ACPI: ec: add unl...
289
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  	}
c0ff17720   Alexey Starikovskiy   ACPI: EC: Check f...
291
  	if (ec_wait_ibf0(ec)) {
3ebe08a74   Márton Németh   ACPI: EC: use pri...
292
293
294
  		pr_err(PREFIX "input buffer is not empty, "
  				"aborting transaction
  ");
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
295
  		status = -ETIME;
451566f45   Dmitry Torokhov   [ACPI] Enable EC ...
296
  		goto end;
716e084ed   Luming Yu   [ACPI] Fix "ec_bu...
297
  	}
a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
298
299
300
301
  	pr_debug(PREFIX "transaction start
  ");
  	/* disable GPE during transaction if storm is detected */
  	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
3784730b0   Rafael J. Wysocki   ACPI / EC: Do not...
302
303
  		/* It has to be disabled, so that it doesn't trigger. */
  		acpi_disable_gpe(NULL, ec->gpe);
a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
304
  	}
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
305
  	status = acpi_ec_transaction_unlocked(ec, t);
a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
306
307
308
309
  
  	/* check if we received SCI during transaction */
  	ec_check_sci_sync(ec, acpi_ec_read_status(ec));
  	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
54070101f   Alexey Starikovskiy   ACPI: EC: Add wai...
310
  		msleep(1);
3784730b0   Rafael J. Wysocki   ACPI / EC: Do not...
311
312
  		/* It is safe to enable the GPE outside of the transaction. */
  		acpi_enable_gpe(NULL, ec->gpe);
a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
313
314
315
316
317
318
  	} else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
  		pr_info(PREFIX "GPE storm detected, "
  			"transactions will use polling mode
  ");
  		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
  	}
54070101f   Alexey Starikovskiy   ACPI: EC: Add wai...
319
320
  	pr_debug(PREFIX "transaction end
  ");
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
321
  end:
703959d47   Denis M. Sadykov   ACPI: EC: Remove ...
322
  	if (ec->global_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
  		acpi_release_global_lock(glk);
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
324
  unlock:
523953b41   Alexey Starikovskiy   ACPI: ec: Acquire...
325
  	mutex_unlock(&ec->lock);
d550d98d3   Patrick Mochel   ACPI: delete trac...
326
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  }
8a383ef0b   Roel Kluin   ACPI: ec.c, pci_l...
328
  static int acpi_ec_burst_enable(struct acpi_ec *ec)
c45aac43f   Alexey Starikovskiy   ACPI: EC: enable ...
329
330
  {
  	u8 d;
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
331
332
333
  	struct transaction t = {.command = ACPI_EC_BURST_ENABLE,
  				.wdata = NULL, .rdata = &d,
  				.wlen = 0, .rlen = 1};
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
334
  	return acpi_ec_transaction(ec, &t);
c45aac43f   Alexey Starikovskiy   ACPI: EC: enable ...
335
  }
8a383ef0b   Roel Kluin   ACPI: ec.c, pci_l...
336
  static int acpi_ec_burst_disable(struct acpi_ec *ec)
c45aac43f   Alexey Starikovskiy   ACPI: EC: enable ...
337
  {
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
338
339
340
  	struct transaction t = {.command = ACPI_EC_BURST_DISABLE,
  				.wdata = NULL, .rdata = NULL,
  				.wlen = 0, .rlen = 0};
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
341
  	return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ?
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
342
  				acpi_ec_transaction(ec, &t) : 0;
c45aac43f   Alexey Starikovskiy   ACPI: EC: enable ...
343
  }
6ccedb10e   Alexey Starikovskiy   ACPI: ec: Lindent...
344
  static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
3576cf619   Denis M. Sadykov   ACPI: EC: Unify p...
345
346
347
  {
  	int result;
  	u8 d;
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
348
349
350
  	struct transaction t = {.command = ACPI_EC_COMMAND_READ,
  				.wdata = &address, .rdata = &d,
  				.wlen = 1, .rlen = 1};
3576cf619   Denis M. Sadykov   ACPI: EC: Unify p...
351

2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
352
  	result = acpi_ec_transaction(ec, &t);
3576cf619   Denis M. Sadykov   ACPI: EC: Unify p...
353
354
355
  	*data = d;
  	return result;
  }
6ffb221a8   Denis M. Sadykov   ACPI: EC: Simplif...
356

3576cf619   Denis M. Sadykov   ACPI: EC: Unify p...
357
358
  static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
  {
6ccedb10e   Alexey Starikovskiy   ACPI: ec: Lindent...
359
  	u8 wdata[2] = { address, data };
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
360
361
362
  	struct transaction t = {.command = ACPI_EC_COMMAND_WRITE,
  				.wdata = wdata, .rdata = NULL,
  				.wlen = 2, .rlen = 0};
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
363
  	return acpi_ec_transaction(ec, &t);
3576cf619   Denis M. Sadykov   ACPI: EC: Unify p...
364
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
367
  /*
   * Externally callable EC access functions. For now, assume 1 EC only
   */
c45aac43f   Alexey Starikovskiy   ACPI: EC: enable ...
368
369
  int ec_burst_enable(void)
  {
c45aac43f   Alexey Starikovskiy   ACPI: EC: enable ...
370
371
  	if (!first_ec)
  		return -ENODEV;
d033879c9   Alexey Starikovskiy   ACPI: EC: first_e...
372
  	return acpi_ec_burst_enable(first_ec);
c45aac43f   Alexey Starikovskiy   ACPI: EC: enable ...
373
374
375
376
377
378
  }
  
  EXPORT_SYMBOL(ec_burst_enable);
  
  int ec_burst_disable(void)
  {
c45aac43f   Alexey Starikovskiy   ACPI: EC: enable ...
379
380
  	if (!first_ec)
  		return -ENODEV;
d033879c9   Alexey Starikovskiy   ACPI: EC: first_e...
381
  	return acpi_ec_burst_disable(first_ec);
c45aac43f   Alexey Starikovskiy   ACPI: EC: enable ...
382
383
384
  }
  
  EXPORT_SYMBOL(ec_burst_disable);
6ccedb10e   Alexey Starikovskiy   ACPI: ec: Lindent...
385
  int ec_read(u8 addr, u8 * val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
  	int err;
6ffb221a8   Denis M. Sadykov   ACPI: EC: Simplif...
388
  	u8 temp_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
  
  	if (!first_ec)
  		return -ENODEV;
d033879c9   Alexey Starikovskiy   ACPI: EC: first_e...
392
  	err = acpi_ec_read(first_ec, addr, &temp_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
396
  
  	if (!err) {
  		*val = temp_data;
  		return 0;
50526df60   Len Brown   [ACPI] Lindent dr...
397
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
  		return err;
  }
50526df60   Len Brown   [ACPI] Lindent dr...
400

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
  EXPORT_SYMBOL(ec_read);
50526df60   Len Brown   [ACPI] Lindent dr...
402
  int ec_write(u8 addr, u8 val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
406
407
  	int err;
  
  	if (!first_ec)
  		return -ENODEV;
d033879c9   Alexey Starikovskiy   ACPI: EC: first_e...
408
  	err = acpi_ec_write(first_ec, addr, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
411
  
  	return err;
  }
50526df60   Len Brown   [ACPI] Lindent dr...
412

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
  EXPORT_SYMBOL(ec_write);
616362de2   Randy Dunlap   ACPI: make ec_tra...
414
  int ec_transaction(u8 command,
9e1972196   Alexey Starikovskiy   ACPI: ec: fix rac...
415
  		   const u8 * wdata, unsigned wdata_len,
1cb7b1e0d   Thomas Renninger   ACPI EC: remove d...
416
  		   u8 * rdata, unsigned rdata_len)
45bea1555   Luming Yu   [ACPI] Add "ec_po...
417
  {
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
418
419
420
  	struct transaction t = {.command = command,
  				.wdata = wdata, .rdata = rdata,
  				.wlen = wdata_len, .rlen = rdata_len};
d7a76e4cb   Lennart Poettering   ACPI: consolidate...
421
422
  	if (!first_ec)
  		return -ENODEV;
45bea1555   Luming Yu   [ACPI] Add "ec_po...
423

2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
424
  	return acpi_ec_transaction(first_ec, &t);
45bea1555   Luming Yu   [ACPI] Add "ec_po...
425
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426

ab9e43c64   Lennart Poettering   ACPI: EC: export ...
427
  EXPORT_SYMBOL(ec_transaction);
fe955682d   Rafael J. Wysocki   ACPI / EC / PM: F...
428
  void acpi_ec_block_transactions(void)
f6bb13aa1   Rafael J. Wysocki   ACPI / EC / PM: C...
429
430
431
432
433
434
435
436
  {
  	struct acpi_ec *ec = first_ec;
  
  	if (!ec)
  		return;
  
  	mutex_lock(&ec->lock);
  	/* Prevent transactions from being carried out */
fe955682d   Rafael J. Wysocki   ACPI / EC / PM: F...
437
  	set_bit(EC_FLAGS_BLOCKED, &ec->flags);
f6bb13aa1   Rafael J. Wysocki   ACPI / EC / PM: C...
438
439
  	mutex_unlock(&ec->lock);
  }
fe955682d   Rafael J. Wysocki   ACPI / EC / PM: F...
440
  void acpi_ec_unblock_transactions(void)
f6bb13aa1   Rafael J. Wysocki   ACPI / EC / PM: C...
441
442
443
444
445
446
447
448
  {
  	struct acpi_ec *ec = first_ec;
  
  	if (!ec)
  		return;
  
  	mutex_lock(&ec->lock);
  	/* Allow transactions to be carried out again */
fe955682d   Rafael J. Wysocki   ACPI / EC / PM: F...
449
  	clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
f6bb13aa1   Rafael J. Wysocki   ACPI / EC / PM: C...
450
451
  	mutex_unlock(&ec->lock);
  }
fe955682d   Rafael J. Wysocki   ACPI / EC / PM: F...
452
  void acpi_ec_unblock_transactions_early(void)
d5a64513c   Rafael J. Wysocki   ACPI / EC / PM: F...
453
454
455
456
457
458
  {
  	/*
  	 * Allow transactions to happen again (this function is called from
  	 * atomic context during wakeup, so we don't need to acquire the mutex).
  	 */
  	if (first_ec)
fe955682d   Rafael J. Wysocki   ACPI / EC / PM: F...
459
  		clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags);
d5a64513c   Rafael J. Wysocki   ACPI / EC / PM: F...
460
  }
a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
461
  static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
3576cf619   Denis M. Sadykov   ACPI: EC: Unify p...
462
463
  {
  	int result;
6ccedb10e   Alexey Starikovskiy   ACPI: ec: Lindent...
464
  	u8 d;
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
465
466
467
  	struct transaction t = {.command = ACPI_EC_COMMAND_QUERY,
  				.wdata = NULL, .rdata = &d,
  				.wlen = 0, .rlen = 1};
6ccedb10e   Alexey Starikovskiy   ACPI: ec: Lindent...
468
469
  	if (!ec || !data)
  		return -EINVAL;
6ccedb10e   Alexey Starikovskiy   ACPI: ec: Lindent...
470
471
472
473
474
  	/*
  	 * 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).
  	 */
a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
475
  	result = acpi_ec_transaction_unlocked(ec, &t);
6ccedb10e   Alexey Starikovskiy   ACPI: ec: Lindent...
476
477
  	if (result)
  		return result;
6ccedb10e   Alexey Starikovskiy   ACPI: ec: Lindent...
478
479
  	if (!d)
  		return -ENODATA;
6ccedb10e   Alexey Starikovskiy   ACPI: ec: Lindent...
480
481
  	*data = d;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
  /* --------------------------------------------------------------------------
                                  Event Management
     -------------------------------------------------------------------------- */
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
486
487
488
489
490
491
492
493
494
495
496
497
498
499
  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);
30c08574d   Alexey Starikovskiy   ACPI: EC: Add new...
500
  	list_add(&handler->node, &ec->list);
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
501
502
503
504
505
506
507
508
  	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)
  {
1544fdbc8   Adrian Bunk   ACPI: EC: fix use...
509
  	struct acpi_ec_query_handler *handler, *tmp;
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
510
  	mutex_lock(&ec->lock);
1544fdbc8   Adrian Bunk   ACPI: EC: fix use...
511
  	list_for_each_entry_safe(handler, tmp, &ec->list, node) {
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
512
513
514
  		if (query_bit == handler->query_bit) {
  			list_del(&handler->node);
  			kfree(handler);
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
515
516
517
518
519
520
  		}
  	}
  	mutex_unlock(&ec->lock);
  }
  
  EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521

a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
522
  static void acpi_ec_run(void *cxt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
  {
a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
524
525
  	struct acpi_ec_query_handler *handler = cxt;
  	if (!handler)
e41334c0a   Alexey Starikovskiy   ACPI: ec: Remove ...
526
  		return;
a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
  	pr_debug(PREFIX "start query execution
  ");
  	if (handler->func)
  		handler->func(handler->data);
  	else if (handler->handle)
  		acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
  	pr_debug(PREFIX "stop query execution
  ");
  	kfree(handler);
  }
  
  static int acpi_ec_sync_query(struct acpi_ec *ec)
  {
  	u8 value = 0;
  	int status;
  	struct acpi_ec_query_handler *handler, *copy;
  	if ((status = acpi_ec_query_unlocked(ec, &value)))
  		return status;
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
545
546
547
  	list_for_each_entry(handler, &ec->list, node) {
  		if (value == handler->query_bit) {
  			/* have custom handler for this bit */
a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
548
549
550
551
552
553
  			copy = kmalloc(sizeof(*handler), GFP_KERNEL);
  			if (!copy)
  				return -ENOMEM;
  			memcpy(copy, handler, sizeof(*copy));
  			pr_debug(PREFIX "push query execution (0x%2x) on queue
  ", value);
f5347867c   Alexey Starikovskiy   ACPI: SBS: Move S...
554
555
  			return acpi_os_execute((copy->func) ?
  				OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
556
  				acpi_ec_run, copy);
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
557
558
  		}
  	}
a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
559
560
561
562
563
564
565
566
567
568
  	return 0;
  }
  
  static void acpi_ec_gpe_query(void *ec_cxt)
  {
  	struct acpi_ec *ec = ec_cxt;
  	if (!ec)
  		return;
  	mutex_lock(&ec->lock);
  	acpi_ec_sync_query(ec);
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
569
  	mutex_unlock(&ec->lock);
45bea1555   Luming Yu   [ACPI] Add "ec_po...
570
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571

a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
572
573
574
575
576
577
578
579
580
581
582
583
  static int ec_check_sci(struct acpi_ec *ec, u8 state)
  {
  	if (state & ACPI_EC_FLAG_SCI) {
  		if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
  			pr_debug(PREFIX "push gpe query to the queue
  ");
  			return acpi_os_execute(OSL_NOTIFY_HANDLER,
  				acpi_ec_gpe_query, ec);
  		}
  	}
  	return 0;
  }
8b6cd8ad1   Lin Ming   ACPICA: New GPE h...
584
585
  static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
  	u32 gpe_number, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
  {
3d02b90be   Alexey Starikovskiy   ACPI: EC: Remove ...
587
  	struct acpi_ec *ec = data;
00eb43a18   Lennart Poettering   acpi,msi-laptop: ...
588

3ebe08a74   Márton Németh   ACPI: EC: use pri...
589
590
  	pr_debug(PREFIX "~~~> interrupt
  ");
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
591

a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
592
593
594
  	advance_transaction(ec, acpi_ec_read_status(ec));
  	if (ec_transaction_done(ec) &&
  	    (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) {
2a84cb985   Alexey Starikovskiy   ACPI: EC: Merge I...
595
  		wake_up(&ec->wait);
a62e8f197   Alexey Starikovskiy   ACPI: EC: Acceler...
596
597
  		ec_check_sci(ec, acpi_ec_read_status(ec));
  	}
bba63a296   Lin Ming   ACPICA: Implicit ...
598
  	return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
845625cdc   Alexey Starikovskiy   ACPI: EC: Add pol...
599
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
602
603
604
  /* --------------------------------------------------------------------------
                               Address Space Management
     -------------------------------------------------------------------------- */
  
  static acpi_status
5b7734b44   Alexey Starikovskiy   ACPI EC: Re-facto...
605
  acpi_ec_space_handler(u32 function, acpi_physical_address address,
dadf28a10   Alexey Starikovskiy   ACPI: EC: Allow m...
606
  		      u32 bits, u64 *value64,
50526df60   Len Brown   [ACPI] Lindent dr...
607
  		      void *handler_context, void *region_context)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
  {
3d02b90be   Alexey Starikovskiy   ACPI: EC: Remove ...
609
  	struct acpi_ec *ec = handler_context;
dadf28a10   Alexey Starikovskiy   ACPI: EC: Allow m...
610
611
  	int result = 0, i, bytes = bits / 8;
  	u8 *value = (u8 *)value64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
  	if ((address > 0xFF) || !value || !handler_context)
d550d98d3   Patrick Mochel   ACPI: delete trac...
614
  		return AE_BAD_PARAMETER;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615

5b7734b44   Alexey Starikovskiy   ACPI EC: Re-facto...
616
  	if (function != ACPI_READ && function != ACPI_WRITE)
d550d98d3   Patrick Mochel   ACPI: delete trac...
617
  		return AE_BAD_PARAMETER;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618

dadf28a10   Alexey Starikovskiy   ACPI: EC: Allow m...
619
  	if (EC_FLAGS_MSI || bits > 8)
6a63b06f3   Alexey Starikovskiy   ACPI: EC: use BUR...
620
  		acpi_ec_burst_enable(ec);
b3b233c7d   Alexey Starikovskiy   ACPI: EC: Some ha...
621

dadf28a10   Alexey Starikovskiy   ACPI: EC: Allow m...
622
623
624
625
  	for (i = 0; i < bytes; ++i, ++address, ++value)
  		result = (function == ACPI_READ) ?
  			acpi_ec_read(ec, address, value) :
  			acpi_ec_write(ec, address, *value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626

dadf28a10   Alexey Starikovskiy   ACPI: EC: Allow m...
627
  	if (EC_FLAGS_MSI || bits > 8)
6a63b06f3   Alexey Starikovskiy   ACPI: EC: use BUR...
628
  		acpi_ec_burst_disable(ec);
b3b233c7d   Alexey Starikovskiy   ACPI: EC: Some ha...
629

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
  	switch (result) {
  	case -EINVAL:
d550d98d3   Patrick Mochel   ACPI: delete trac...
632
  		return AE_BAD_PARAMETER;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
634
  		break;
  	case -ENODEV:
d550d98d3   Patrick Mochel   ACPI: delete trac...
635
  		return AE_NOT_FOUND;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
  		break;
  	case -ETIME:
d550d98d3   Patrick Mochel   ACPI: delete trac...
638
  		return AE_TIME;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
640
  		break;
  	default:
d550d98d3   Patrick Mochel   ACPI: delete trac...
641
  		return AE_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
  /* --------------------------------------------------------------------------
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
                                 Driver Interface
     -------------------------------------------------------------------------- */
c0900c351   Alexey Starikovskiy   ACPI: EC: Clean E...
647
648
  static acpi_status
  ec_parse_io_ports(struct acpi_resource *resource, void *context);
c0900c351   Alexey Starikovskiy   ACPI: EC: Clean E...
649
650
651
652
653
  static struct acpi_ec *make_acpi_ec(void)
  {
  	struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
  	if (!ec)
  		return NULL;
080e412cc   Alexey Starikovskiy   ACPI: EC: Replace...
654
  	ec->flags = 1 << EC_FLAGS_QUERY_PENDING;
c0900c351   Alexey Starikovskiy   ACPI: EC: Clean E...
655
656
  	mutex_init(&ec->lock);
  	init_waitqueue_head(&ec->wait);
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
657
  	INIT_LIST_HEAD(&ec->list);
8463200a0   Alexey Starikovskiy   ACPI: EC: Rename ...
658
  	spin_lock_init(&ec->curr_lock);
c0900c351   Alexey Starikovskiy   ACPI: EC: Clean E...
659
660
  	return ec;
  }
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
661

cd8c93a4e   Alexey Starikovskiy   ACPI: EC: If ECDT...
662
  static acpi_status
c019b1933   Alexey Starikovskiy   ACPI: EC: Fix "no...
663
664
665
  acpi_ec_register_query_methods(acpi_handle handle, u32 level,
  			       void *context, void **return_value)
  {
0175d562a   Lin Ming   ACPI: ec.c: call ...
666
667
  	char node_name[5];
  	struct acpi_buffer buffer = { sizeof(node_name), node_name };
c019b1933   Alexey Starikovskiy   ACPI: EC: Fix "no...
668
669
  	struct acpi_ec *ec = context;
  	int value = 0;
0175d562a   Lin Ming   ACPI: ec.c: call ...
670
671
672
673
674
  	acpi_status status;
  
  	status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
  
  	if (ACPI_SUCCESS(status) && sscanf(node_name, "_Q%x", &value) == 1) {
c019b1933   Alexey Starikovskiy   ACPI: EC: Fix "no...
675
676
677
678
679
680
  		acpi_ec_add_query_handler(ec, value, handle, NULL, NULL);
  	}
  	return AE_OK;
  }
  
  static acpi_status
cd8c93a4e   Alexey Starikovskiy   ACPI: EC: If ECDT...
681
  ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
682
  {
cd8c93a4e   Alexey Starikovskiy   ACPI: EC: If ECDT...
683
  	acpi_status status;
d21cf3c16   Alexey Starikovskiy   ACPI EC: Fix regr...
684
  	unsigned long long tmp = 0;
cd8c93a4e   Alexey Starikovskiy   ACPI: EC: If ECDT...
685
686
  
  	struct acpi_ec *ec = context;
a5032bfdd   Alexey Starikovskiy   ACPI: EC: Always ...
687
688
689
  
  	/* clear addr values, ec_parse_io_ports depend on it */
  	ec->command_addr = ec->data_addr = 0;
cd8c93a4e   Alexey Starikovskiy   ACPI: EC: If ECDT...
690
691
692
693
  	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
  				     ec_parse_io_ports, ec);
  	if (ACPI_FAILURE(status))
  		return status;
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
694
695
696
  
  	/* Get GPE bit assignment (EC events). */
  	/* TODO: Add support for _GPE returning a package */
27663c585   Matthew Wilcox   ACPI: Change acpi...
697
  	status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
cd8c93a4e   Alexey Starikovskiy   ACPI: EC: If ECDT...
698
699
  	if (ACPI_FAILURE(status))
  		return status;
27663c585   Matthew Wilcox   ACPI: Change acpi...
700
  	ec->gpe = tmp;
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
701
  	/* Use the global lock for all EC transactions? */
d21cf3c16   Alexey Starikovskiy   ACPI EC: Fix regr...
702
  	tmp = 0;
27663c585   Matthew Wilcox   ACPI: Change acpi...
703
704
  	acpi_evaluate_integer(handle, "_GLK", NULL, &tmp);
  	ec->global_lock = tmp;
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
705
  	ec->handle = handle;
cd8c93a4e   Alexey Starikovskiy   ACPI: EC: If ECDT...
706
  	return AE_CTRL_TERMINATE;
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
707
  }
5efc54761   Bjorn Helgaas   ACPI: EC: move ac...
708
709
710
711
712
713
714
715
716
717
  static int ec_install_handlers(struct acpi_ec *ec)
  {
  	acpi_status status;
  	if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
  		return 0;
  	status = acpi_install_gpe_handler(NULL, ec->gpe,
  				  ACPI_GPE_EDGE_TRIGGERED,
  				  &acpi_ec_gpe_handler, ec);
  	if (ACPI_FAILURE(status))
  		return -ENODEV;
9630bdd9b   Rafael J. Wysocki   ACPI: Use GPE ref...
718

a44061aa8   Rafael J. Wysocki   ACPICA: Remove wa...
719
  	acpi_enable_gpe(NULL, ec->gpe);
5efc54761   Bjorn Helgaas   ACPI: EC: move ac...
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
  	status = acpi_install_address_space_handler(ec->handle,
  						    ACPI_ADR_SPACE_EC,
  						    &acpi_ec_space_handler,
  						    NULL, ec);
  	if (ACPI_FAILURE(status)) {
  		if (status == AE_NOT_FOUND) {
  			/*
  			 * Maybe OS fails in evaluating the _REG object.
  			 * The AE_NOT_FOUND error will be ignored and OS
  			 * continue to initialize EC.
  			 */
  			printk(KERN_ERR "Fail in evaluating the _REG object"
  				" of EC device. Broken bios is suspected.
  ");
  		} else {
  			acpi_remove_gpe_handler(NULL, ec->gpe,
  				&acpi_ec_gpe_handler);
a44061aa8   Rafael J. Wysocki   ACPICA: Remove wa...
737
  			acpi_disable_gpe(NULL, ec->gpe);
5efc54761   Bjorn Helgaas   ACPI: EC: move ac...
738
739
740
741
742
743
744
  			return -ENODEV;
  		}
  	}
  
  	set_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
  	return 0;
  }
4c6110606   Alexey Starikovskiy   ACPI: EC: Drop EC...
745
746
  static void ec_remove_handlers(struct acpi_ec *ec)
  {
a44061aa8   Rafael J. Wysocki   ACPICA: Remove wa...
747
  	acpi_disable_gpe(NULL, ec->gpe);
4c6110606   Alexey Starikovskiy   ACPI: EC: Drop EC...
748
749
  	if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
  				ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
3ebe08a74   Márton Németh   ACPI: EC: use pri...
750
751
  		pr_err(PREFIX "failed to remove space handler
  ");
4c6110606   Alexey Starikovskiy   ACPI: EC: Drop EC...
752
753
  	if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
  				&acpi_ec_gpe_handler)))
3ebe08a74   Márton Németh   ACPI: EC: use pri...
754
755
  		pr_err(PREFIX "failed to remove gpe handler
  ");
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
756
  	clear_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags);
4c6110606   Alexey Starikovskiy   ACPI: EC: Drop EC...
757
  }
703959d47   Denis M. Sadykov   ACPI: EC: Remove ...
758
  static int acpi_ec_add(struct acpi_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
  {
703959d47   Denis M. Sadykov   ACPI: EC: Remove ...
760
  	struct acpi_ec *ec = NULL;
d02be0470   Bjorn Helgaas   ACPI: EC: remove ...
761
  	int ret;
45bea1555   Luming Yu   [ACPI] Add "ec_po...
762

c0900c351   Alexey Starikovskiy   ACPI: EC: Clean E...
763
764
  	strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
  	strcpy(acpi_device_class(device), ACPI_EC_CLASS);
4c6110606   Alexey Starikovskiy   ACPI: EC: Drop EC...
765
  	/* Check for boot EC */
ce52ddf58   Alexey Starikovskiy   ACPI: EC: Don't d...
766
767
768
769
770
771
772
773
774
  	if (boot_ec &&
  	    (boot_ec->handle == device->handle ||
  	     boot_ec->handle == ACPI_ROOT_OBJECT)) {
  		ec = boot_ec;
  		boot_ec = NULL;
  	} else {
  		ec = make_acpi_ec();
  		if (!ec)
  			return -ENOMEM;
a5032bfdd   Alexey Starikovskiy   ACPI: EC: Always ...
775
776
777
  	}
  	if (ec_parse_device(device->handle, 0, ec, NULL) !=
  		AE_CTRL_TERMINATE) {
ce52ddf58   Alexey Starikovskiy   ACPI: EC: Don't d...
778
779
  			kfree(ec);
  			return -EINVAL;
4c6110606   Alexey Starikovskiy   ACPI: EC: Drop EC...
780
  	}
ce52ddf58   Alexey Starikovskiy   ACPI: EC: Don't d...
781
782
  	/* Find and register all query methods */
  	acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
2263576cf   Lin Ming   ACPICA: Add post-...
783
  			    acpi_ec_register_query_methods, NULL, ec, NULL);
ce52ddf58   Alexey Starikovskiy   ACPI: EC: Don't d...
784

4c6110606   Alexey Starikovskiy   ACPI: EC: Drop EC...
785
786
  	if (!first_ec)
  		first_ec = ec;
db89b4f0d   Pavel Machek   ACPI: catch calls...
787
  	device->driver_data = ec;
de4f10466   Thomas Renninger   acpi ec: Fix poss...
788
789
790
791
792
  
  	WARN(!request_region(ec->data_addr, 1, "EC data"),
  	     "Could not request EC data io port 0x%lx", ec->data_addr);
  	WARN(!request_region(ec->command_addr, 1, "EC cmd"),
  	     "Could not request EC cmd io port 0x%lx", ec->command_addr);
3ebe08a74   Márton Németh   ACPI: EC: use pri...
793
794
  	pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx
  ",
4c6110606   Alexey Starikovskiy   ACPI: EC: Drop EC...
795
  			  ec->gpe, ec->command_addr, ec->data_addr);
5efc54761   Bjorn Helgaas   ACPI: EC: move ac...
796
797
798
799
800
801
  
  	ret = ec_install_handlers(ec);
  
  	/* EC is fully operational, allow queries */
  	clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  }
50526df60   Len Brown   [ACPI] Lindent dr...
803
  static int acpi_ec_remove(struct acpi_device *device, int type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
  {
01f224626   Alexey Starikovskiy   ACPI: EC: Cleanup...
805
  	struct acpi_ec *ec;
07ddf768d   Adrian Bunk   ACPI: EC: acpi_ec...
806
  	struct acpi_ec_query_handler *handler, *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
  	if (!device)
d550d98d3   Patrick Mochel   ACPI: delete trac...
809
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
  
  	ec = acpi_driver_data(device);
cf745ec7a   Bjorn Helgaas   ACPI: EC: remove ...
812
  	ec_remove_handlers(ec);
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
813
  	mutex_lock(&ec->lock);
07ddf768d   Adrian Bunk   ACPI: EC: acpi_ec...
814
  	list_for_each_entry_safe(handler, tmp, &ec->list, node) {
837012ede   Alexey Starikovskiy   ACPI EC: Add supp...
815
816
817
818
  		list_del(&handler->node);
  		kfree(handler);
  	}
  	mutex_unlock(&ec->lock);
de4f10466   Thomas Renninger   acpi ec: Fix poss...
819
820
  	release_region(ec->data_addr, 1);
  	release_region(ec->command_addr, 1);
db89b4f0d   Pavel Machek   ACPI: catch calls...
821
  	device->driver_data = NULL;
d033879c9   Alexey Starikovskiy   ACPI: EC: first_e...
822
  	if (ec == first_ec)
c0900c351   Alexey Starikovskiy   ACPI: EC: Clean E...
823
  		first_ec = NULL;
4c6110606   Alexey Starikovskiy   ACPI: EC: Drop EC...
824
  	kfree(ec);
d550d98d3   Patrick Mochel   ACPI: delete trac...
825
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  static acpi_status
c0900c351   Alexey Starikovskiy   ACPI: EC: Clean E...
828
  ec_parse_io_ports(struct acpi_resource *resource, void *context)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
  {
3d02b90be   Alexey Starikovskiy   ACPI: EC: Remove ...
830
  	struct acpi_ec *ec = context;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831

01f224626   Alexey Starikovskiy   ACPI: EC: Cleanup...
832
  	if (resource->type != ACPI_RESOURCE_TYPE_IO)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
  		return AE_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834
835
836
837
838
839
  
  	/*
  	 * The first address region returned is the data port, and
  	 * the second address region returned is the status/command
  	 * port.
  	 */
de4f10466   Thomas Renninger   acpi ec: Fix poss...
840
  	if (ec->data_addr == 0)
6ffb221a8   Denis M. Sadykov   ACPI: EC: Simplif...
841
  		ec->data_addr = resource->data.io.minimum;
de4f10466   Thomas Renninger   acpi ec: Fix poss...
842
  	else if (ec->command_addr == 0)
6ffb221a8   Denis M. Sadykov   ACPI: EC: Simplif...
843
  		ec->command_addr = resource->data.io.minimum;
01f224626   Alexey Starikovskiy   ACPI: EC: Cleanup...
844
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
  		return AE_CTRL_TERMINATE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
  	return AE_OK;
  }
c04209a79   Alexey Starikovskiy   ACPI: EC: Enable ...
849
850
  int __init acpi_boot_ec_enable(void)
  {
7c6db4e05   Alexey Starikovskiy   ACPI: EC: do tran...
851
  	if (!boot_ec || test_bit(EC_FLAGS_HANDLERS_INSTALLED, &boot_ec->flags))
c04209a79   Alexey Starikovskiy   ACPI: EC: Enable ...
852
853
854
855
856
857
858
  		return 0;
  	if (!ec_install_handlers(boot_ec)) {
  		first_ec = boot_ec;
  		return 0;
  	}
  	return -EFAULT;
  }
223883b7a   Alexey Starikovskiy   ACPI: EC: Switch ...
859
860
861
862
  static const struct acpi_device_id ec_device_ids[] = {
  	{"PNP0C09", 0},
  	{"", 0},
  };
478fa03b3   Alexey Starikovskiy   ACPI: EC: Don't p...
863
864
865
866
867
868
  /* Some BIOS do not survive early DSDT scan, skip it */
  static int ec_skip_dsdt_scan(const struct dmi_system_id *id)
  {
  	EC_FLAGS_SKIP_DSDT_SCAN = 1;
  	return 0;
  }
0adf3c746   Alexey Starikovskiy   ACPI: EC: Rewrite...
869
870
871
872
873
874
875
876
877
878
  /* ASUStek often supplies us with broken ECDT, validate it */
  static int ec_validate_ecdt(const struct dmi_system_id *id)
  {
  	EC_FLAGS_VALIDATE_ECDT = 1;
  	return 0;
  }
  
  /* MSI EC needs special treatment, enable it */
  static int ec_flag_msi(const struct dmi_system_id *id)
  {
55b313f24   Alexey Starikovskiy   ACPI: EC: Fix MSI...
879
880
  	printk(KERN_DEBUG PREFIX "Detected MSI hardware, enabling workarounds.
  ");
0adf3c746   Alexey Starikovskiy   ACPI: EC: Rewrite...
881
882
883
884
885
886
887
  	EC_FLAGS_MSI = 1;
  	EC_FLAGS_VALIDATE_ECDT = 1;
  	return 0;
  }
  
  static struct dmi_system_id __initdata ec_dmi_table[] = {
  	{
478fa03b3   Alexey Starikovskiy   ACPI: EC: Don't p...
888
889
890
891
  	ec_skip_dsdt_scan, "Compal JFL92", {
  	DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
  	DMI_MATCH(DMI_BOARD_NAME, "JFL92") }, NULL},
  	{
0adf3c746   Alexey Starikovskiy   ACPI: EC: Rewrite...
892
  	ec_flag_msi, "MSI hardware", {
55b313f24   Alexey Starikovskiy   ACPI: EC: Fix MSI...
893
894
895
896
897
898
899
  	DMI_MATCH(DMI_BIOS_VENDOR, "Micro-Star")}, NULL},
  	{
  	ec_flag_msi, "MSI hardware", {
  	DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star")}, NULL},
  	{
  	ec_flag_msi, "MSI hardware", {
  	DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star")}, NULL},
0adf3c746   Alexey Starikovskiy   ACPI: EC: Rewrite...
900
  	{
a5dc4f898   Alexey Starikovskiy   ACPI: EC: Add ano...
901
902
903
  	ec_flag_msi, "MSI hardware", {
  	DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR")}, NULL},
  	{
534bc4e3d   Zhang Rui   ACPI EC: enable M...
904
905
906
907
908
909
910
911
  	ec_flag_msi, "Quanta hardware", {
  	DMI_MATCH(DMI_SYS_VENDOR, "Quanta"),
  	DMI_MATCH(DMI_PRODUCT_NAME, "TW8/SW8/DW8"),}, NULL},
  	{
  	ec_flag_msi, "Quanta hardware", {
  	DMI_MATCH(DMI_SYS_VENDOR, "Quanta"),
  	DMI_MATCH(DMI_PRODUCT_NAME, "TW9/SW9"),}, NULL},
  	{
0adf3c746   Alexey Starikovskiy   ACPI: EC: Rewrite...
912
913
  	ec_validate_ecdt, "ASUS hardware", {
  	DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL},
af986d101   Peter Collingbourne   ACPI: EC: add ano...
914
915
916
  	{
  	ec_validate_ecdt, "ASUS hardware", {
  	DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc.") }, NULL},
0adf3c746   Alexey Starikovskiy   ACPI: EC: Rewrite...
917
918
  	{},
  };
c0900c351   Alexey Starikovskiy   ACPI: EC: Clean E...
919
920
  int __init acpi_ec_ecdt_probe(void)
  {
c0900c351   Alexey Starikovskiy   ACPI: EC: Clean E...
921
  	acpi_status status;
c6cb0e878   Alexey Starikovskiy   ACPI: EC: Don't t...
922
  	struct acpi_ec *saved_ec = NULL;
50526df60   Len Brown   [ACPI] Lindent dr...
923
  	struct acpi_table_ecdt *ecdt_ptr;
45bea1555   Luming Yu   [ACPI] Add "ec_po...
924

d66d969df   Alexey Starikovskiy   ACPI: EC: Rename ...
925
926
  	boot_ec = make_acpi_ec();
  	if (!boot_ec)
c0900c351   Alexey Starikovskiy   ACPI: EC: Clean E...
927
928
929
930
  		return -ENOMEM;
  	/*
  	 * Generate a boot ec context
  	 */
0adf3c746   Alexey Starikovskiy   ACPI: EC: Rewrite...
931
  	dmi_check_system(ec_dmi_table);
15a58ed12   Alexey Starikovskiy   ACPICA: Remove du...
932
933
  	status = acpi_get_table(ACPI_SIG_ECDT, 1,
  				(struct acpi_table_header **)&ecdt_ptr);
cd8c93a4e   Alexey Starikovskiy   ACPI: EC: If ECDT...
934
  	if (ACPI_SUCCESS(status)) {
3ebe08a74   Márton Németh   ACPI: EC: use pri...
935
936
  		pr_info(PREFIX "EC description table is found, configuring boot EC
  ");
cd8c93a4e   Alexey Starikovskiy   ACPI: EC: If ECDT...
937
938
939
  		boot_ec->command_addr = ecdt_ptr->control.address;
  		boot_ec->data_addr = ecdt_ptr->data.address;
  		boot_ec->gpe = ecdt_ptr->gpe;
4af8e10a6   Len Brown   Revert "ACPI: EC:...
940
  		boot_ec->handle = ACPI_ROOT_OBJECT;
ce52ddf58   Alexey Starikovskiy   ACPI: EC: Don't d...
941
  		acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle);
c6cb0e878   Alexey Starikovskiy   ACPI: EC: Don't t...
942
  		/* Don't trust ECDT, which comes from ASUSTek */
0adf3c746   Alexey Starikovskiy   ACPI: EC: Rewrite...
943
  		if (!EC_FLAGS_VALIDATE_ECDT)
c5279dee2   Alexey Starikovskiy   ACPI: EC: Add som...
944
  			goto install;
d6bd535d8   Julia Lawall   ACPI: EC: Use kme...
945
  		saved_ec = kmemdup(boot_ec, sizeof(struct acpi_ec), GFP_KERNEL);
c6cb0e878   Alexey Starikovskiy   ACPI: EC: Don't t...
946
947
  		if (!saved_ec)
  			return -ENOMEM;
c5279dee2   Alexey Starikovskiy   ACPI: EC: Add som...
948
  	/* fall through */
cd8c93a4e   Alexey Starikovskiy   ACPI: EC: If ECDT...
949
  	}
0adf3c746   Alexey Starikovskiy   ACPI: EC: Rewrite...
950

478fa03b3   Alexey Starikovskiy   ACPI: EC: Don't p...
951
952
  	if (EC_FLAGS_SKIP_DSDT_SCAN)
  		return -ENODEV;
c5279dee2   Alexey Starikovskiy   ACPI: EC: Add som...
953
954
  	/* This workaround is needed only on some broken machines,
  	 * which require early EC, but fail to provide ECDT */
c5279dee2   Alexey Starikovskiy   ACPI: EC: Add som...
955
956
957
958
959
960
961
  	printk(KERN_DEBUG PREFIX "Look up EC in DSDT
  ");
  	status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device,
  					boot_ec, NULL);
  	/* Check that acpi_get_devices actually find something */
  	if (ACPI_FAILURE(status) || !boot_ec->handle)
  		goto error;
c6cb0e878   Alexey Starikovskiy   ACPI: EC: Don't t...
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
  	if (saved_ec) {
  		/* try to find good ECDT from ASUSTek */
  		if (saved_ec->command_addr != boot_ec->command_addr ||
  		    saved_ec->data_addr != boot_ec->data_addr ||
  		    saved_ec->gpe != boot_ec->gpe ||
  		    saved_ec->handle != boot_ec->handle)
  			pr_info(PREFIX "ASUSTek keeps feeding us with broken "
  			"ECDT tables, which are very hard to workaround. "
  			"Trying to use DSDT EC info instead. Please send "
  			"output of acpidump to linux-acpi@vger.kernel.org
  ");
  		kfree(saved_ec);
  		saved_ec = NULL;
  	} else {
  		/* We really need to limit this workaround, the only ASUS,
  		* which needs it, has fake EC._INI method, so use it as flag.
  		* Keep boot_ec struct as it will be needed soon.
  		*/
  		acpi_handle dummy;
  		if (!dmi_name_in_vendors("ASUS") ||
  		    ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI",
  							&dummy)))
  			return -ENODEV;
  	}
c5279dee2   Alexey Starikovskiy   ACPI: EC: Add som...
986
987
  install:
  	if (!ec_install_handlers(boot_ec)) {
d033879c9   Alexey Starikovskiy   ACPI: EC: first_e...
988
  		first_ec = boot_ec;
e82843210   Alexey Starikovskiy   ACPI: EC: Put ins...
989
  		return 0;
d033879c9   Alexey Starikovskiy   ACPI: EC: first_e...
990
  	}
c5279dee2   Alexey Starikovskiy   ACPI: EC: Add som...
991
  error:
d66d969df   Alexey Starikovskiy   ACPI: EC: Rename ...
992
993
  	kfree(boot_ec);
  	boot_ec = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994
995
  	return -ENODEV;
  }
223883b7a   Alexey Starikovskiy   ACPI: EC: Switch ...
996
997
998
999
1000
1001
1002
  static struct acpi_driver acpi_ec_driver = {
  	.name = "ec",
  	.class = ACPI_EC_CLASS,
  	.ids = ec_device_ids,
  	.ops = {
  		.add = acpi_ec_add,
  		.remove = acpi_ec_remove,
223883b7a   Alexey Starikovskiy   ACPI: EC: Switch ...
1003
1004
  		},
  };
a5f820feb   Bjorn Helgaas   ACPI: call acpi_e...
1005
  int __init acpi_ec_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
  {
50526df60   Len Brown   [ACPI] Lindent dr...
1007
  	int result = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009
1010
  	/* Now register the driver for the EC */
  	result = acpi_bus_register_driver(&acpi_ec_driver);
49c6c5ff9   Thomas Renninger   ACPI: Remove /pro...
1011
  	if (result < 0)
d550d98d3   Patrick Mochel   ACPI: delete trac...
1012
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013

d550d98d3   Patrick Mochel   ACPI: delete trac...
1014
  	return result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
1017
  /* EC driver currently not unloadable */
  #if 0
50526df60   Len Brown   [ACPI] Lindent dr...
1018
  static void __exit acpi_ec_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1019
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
1021
  
  	acpi_bus_unregister_driver(&acpi_ec_driver);
d550d98d3   Patrick Mochel   ACPI: delete trac...
1022
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023
  }
7843932ac   Alexey Starikovskiy   ACPI: EC: auto se...
1024
  #endif	/* 0 */