aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <mzxreary@0pointer.de>2007-05-04 08:16:19 -0400
committerLen Brown <len.brown@intel.com>2007-05-10 03:52:22 -0400
commit00eb43a1897a8845d0edb198cec69ac5f1f299dd (patch)
tree32cab402e51882c7854eab20556f0da75525cdc7
parenta64e62a07097f67108f0b68bc15216c3a4a5299b (diff)
acpi,msi-laptop: Fall back to EC polling mode for MSI laptop specific EC commands
The ACPI EC that is used in MSI laptops knows some non-standard commands for changing the screen brighntess and a few other things, which are used by the msi-laptop.c driver. Unfortunately for these commands no GPE events for IBF and OBF are triggered. Since nowadays the EC code uses the ec_intr=1 mode by default, this causes these operations to timeout, although they don't fail. In result, all operations that you can do with the msi-laptop.c driver take more or less 1s to complete, which is awfully slow. In one of the more recent kernels (2.6.20?) the EC subsystem has been revamped. With that change the EC timeout has been increased. before that increase the MSI EC accesses were slow -- but not *that* slow, hence I took notice of this limitation of the MSI EC hardware only very recently. The standard EC operations on the MSI EC as defined in the ACPI spec support GPE events properly. The following patch adds a new argument "force_poll" to the ec_transaction() function (and friends). If set to 1, the function will poll for IBF/OBF even if ec_intr=1 is enabled. If set to 0 the current behaviour is used. The msi-laptop driver is modified to make use of this new flag, so that OBF/IBF is polled for the special MSI EC transactions -- but only for them. Signed-off-by: Lennart Poettering <mzxreary@0pointer.de> Acked-by: Alexey Starikovskiy <aystarik@gmail.com> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/acpi/ec.c39
-rw-r--r--drivers/misc/msi-laptop.c12
-rw-r--r--include/linux/acpi.h3
3 files changed, 31 insertions, 23 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e08cf98f504f..82f496c07675 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -147,9 +147,10 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event,
147 return 0; 147 return 0;
148} 148}
149 149
150static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count) 150static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event,
151 unsigned count, int force_poll)
151{ 152{
152 if (acpi_ec_mode == EC_POLL) { 153 if (unlikely(force_poll) || acpi_ec_mode == EC_POLL) {
153 unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); 154 unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
154 while (time_before(jiffies, delay)) { 155 while (time_before(jiffies, delay)) {
155 if (acpi_ec_check_status(ec, event, 0)) 156 if (acpi_ec_check_status(ec, event, 0))
@@ -173,14 +174,15 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count)
173 174
174static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, 175static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
175 const u8 * wdata, unsigned wdata_len, 176 const u8 * wdata, unsigned wdata_len,
176 u8 * rdata, unsigned rdata_len) 177 u8 * rdata, unsigned rdata_len,
178 int force_poll)
177{ 179{
178 int result = 0; 180 int result = 0;
179 unsigned count = atomic_read(&ec->event_count); 181 unsigned count = atomic_read(&ec->event_count);
180 acpi_ec_write_cmd(ec, command); 182 acpi_ec_write_cmd(ec, command);
181 183
182 for (; wdata_len > 0; --wdata_len) { 184 for (; wdata_len > 0; --wdata_len) {
183 result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count); 185 result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll);
184 if (result) { 186 if (result) {
185 printk(KERN_ERR PREFIX 187 printk(KERN_ERR PREFIX
186 "write_cmd timeout, command = %d\n", command); 188 "write_cmd timeout, command = %d\n", command);
@@ -191,7 +193,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
191 } 193 }
192 194
193 if (!rdata_len) { 195 if (!rdata_len) {
194 result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count); 196 result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll);
195 if (result) { 197 if (result) {
196 printk(KERN_ERR PREFIX 198 printk(KERN_ERR PREFIX
197 "finish-write timeout, command = %d\n", command); 199 "finish-write timeout, command = %d\n", command);
@@ -202,7 +204,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
202 } 204 }
203 205
204 for (; rdata_len > 0; --rdata_len) { 206 for (; rdata_len > 0; --rdata_len) {
205 result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, count); 207 result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, count, force_poll);
206 if (result) { 208 if (result) {
207 printk(KERN_ERR PREFIX "read timeout, command = %d\n", 209 printk(KERN_ERR PREFIX "read timeout, command = %d\n",
208 command); 210 command);
@@ -217,7 +219,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
217 219
218static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, 220static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
219 const u8 * wdata, unsigned wdata_len, 221 const u8 * wdata, unsigned wdata_len,
220 u8 * rdata, unsigned rdata_len) 222 u8 * rdata, unsigned rdata_len,
223 int force_poll)
221{ 224{
222 int status; 225 int status;
223 u32 glk; 226 u32 glk;
@@ -240,7 +243,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
240 /* Make sure GPE is enabled before doing transaction */ 243 /* Make sure GPE is enabled before doing transaction */
241 acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); 244 acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
242 245
243 status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0); 246 status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0);
244 if (status) { 247 if (status) {
245 printk(KERN_DEBUG PREFIX 248 printk(KERN_DEBUG PREFIX
246 "input buffer is not empty, aborting transaction\n"); 249 "input buffer is not empty, aborting transaction\n");
@@ -249,7 +252,8 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
249 252
250 status = acpi_ec_transaction_unlocked(ec, command, 253 status = acpi_ec_transaction_unlocked(ec, command,
251 wdata, wdata_len, 254 wdata, wdata_len,
252 rdata, rdata_len); 255 rdata, rdata_len,
256 force_poll);
253 257
254 end: 258 end:
255 259
@@ -267,12 +271,12 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
267int acpi_ec_burst_enable(struct acpi_ec *ec) 271int acpi_ec_burst_enable(struct acpi_ec *ec)
268{ 272{
269 u8 d; 273 u8 d;
270 return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1); 274 return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1, 0);
271} 275}
272 276
273int acpi_ec_burst_disable(struct acpi_ec *ec) 277int acpi_ec_burst_disable(struct acpi_ec *ec)
274{ 278{
275 return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0); 279 return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0, 0);
276} 280}
277 281
278static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) 282static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
@@ -281,7 +285,7 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
281 u8 d; 285 u8 d;
282 286
283 result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ, 287 result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ,
284 &address, 1, &d, 1); 288 &address, 1, &d, 1, 0);
285 *data = d; 289 *data = d;
286 return result; 290 return result;
287} 291}
@@ -290,7 +294,7 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
290{ 294{
291 u8 wdata[2] = { address, data }; 295 u8 wdata[2] = { address, data };
292 return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, 296 return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE,
293 wdata, 2, NULL, 0); 297 wdata, 2, NULL, 0, 0);
294} 298}
295 299
296/* 300/*
@@ -349,13 +353,15 @@ EXPORT_SYMBOL(ec_write);
349 353
350int ec_transaction(u8 command, 354int ec_transaction(u8 command,
351 const u8 * wdata, unsigned wdata_len, 355 const u8 * wdata, unsigned wdata_len,
352 u8 * rdata, unsigned rdata_len) 356 u8 * rdata, unsigned rdata_len,
357 int force_poll)
353{ 358{
354 if (!first_ec) 359 if (!first_ec)
355 return -ENODEV; 360 return -ENODEV;
356 361
357 return acpi_ec_transaction(first_ec, command, wdata, 362 return acpi_ec_transaction(first_ec, command, wdata,
358 wdata_len, rdata, rdata_len); 363 wdata_len, rdata, rdata_len,
364 force_poll);
359} 365}
360 366
361EXPORT_SYMBOL(ec_transaction); 367EXPORT_SYMBOL(ec_transaction);
@@ -374,7 +380,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
374 * bit to be cleared (and thus clearing the interrupt source). 380 * bit to be cleared (and thus clearing the interrupt source).
375 */ 381 */
376 382
377 result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1); 383 result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1, 0);
378 if (result) 384 if (result)
379 return result; 385 return result;
380 386
@@ -410,6 +416,7 @@ static u32 acpi_ec_gpe_handler(void *data)
410 acpi_status status = AE_OK; 416 acpi_status status = AE_OK;
411 u8 value; 417 u8 value;
412 struct acpi_ec *ec = data; 418 struct acpi_ec *ec = data;
419
413 atomic_inc(&ec->event_count); 420 atomic_inc(&ec->event_count);
414 421
415 if (acpi_ec_mode == EC_INTR) { 422 if (acpi_ec_mode == EC_INTR) {
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
index 68c4b58525ba..41e901f53e7c 100644
--- a/drivers/misc/msi-laptop.c
+++ b/drivers/misc/msi-laptop.c
@@ -85,7 +85,7 @@ static int set_lcd_level(int level)
85 buf[0] = 0x80; 85 buf[0] = 0x80;
86 buf[1] = (u8) (level*31); 86 buf[1] = (u8) (level*31);
87 87
88 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0); 88 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0, 1);
89} 89}
90 90
91static int get_lcd_level(void) 91static int get_lcd_level(void)
@@ -93,7 +93,7 @@ static int get_lcd_level(void)
93 u8 wdata = 0, rdata; 93 u8 wdata = 0, rdata;
94 int result; 94 int result;
95 95
96 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1); 96 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1);
97 if (result < 0) 97 if (result < 0)
98 return result; 98 return result;
99 99
@@ -105,7 +105,7 @@ static int get_auto_brightness(void)
105 u8 wdata = 4, rdata; 105 u8 wdata = 4, rdata;
106 int result; 106 int result;
107 107
108 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1); 108 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1);
109 if (result < 0) 109 if (result < 0)
110 return result; 110 return result;
111 111
@@ -119,14 +119,14 @@ static int set_auto_brightness(int enable)
119 119
120 wdata[0] = 4; 120 wdata[0] = 4;
121 121
122 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1); 122 result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1, 1);
123 if (result < 0) 123 if (result < 0)
124 return result; 124 return result;
125 125
126 wdata[0] = 0x84; 126 wdata[0] = 0x84;
127 wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0); 127 wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0);
128 128
129 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0); 129 return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1);
130} 130}
131 131
132static int get_wireless_state(int *wlan, int *bluetooth) 132static int get_wireless_state(int *wlan, int *bluetooth)
@@ -134,7 +134,7 @@ static int get_wireless_state(int *wlan, int *bluetooth)
134 u8 wdata = 0, rdata; 134 u8 wdata = 0, rdata;
135 int result; 135 int result;
136 136
137 result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1); 137 result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1, 1);
138 if (result < 0) 138 if (result < 0)
139 return -1; 139 return -1;
140 140
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 8bcfaa4c66ae..fccd8b548d93 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -182,7 +182,8 @@ extern int ec_read(u8 addr, u8 *val);
182extern int ec_write(u8 addr, u8 val); 182extern int ec_write(u8 addr, u8 val);
183extern int ec_transaction(u8 command, 183extern int ec_transaction(u8 command,
184 const u8 *wdata, unsigned wdata_len, 184 const u8 *wdata, unsigned wdata_len,
185 u8 *rdata, unsigned rdata_len); 185 u8 *rdata, unsigned rdata_len,
186 int force_poll);
186 187
187#endif /*CONFIG_ACPI_EC*/ 188#endif /*CONFIG_ACPI_EC*/
188 189