File: /usr/src/linux/drivers/acpi/ospm/ec/ecmain.c
1 /*****************************************************************************
2 *
3 * Module Name: ecmain.c
4 * $Revision: 28 $
5 *
6 *****************************************************************************/
7
8 /*
9 * Copyright (C) 2000, 2001 Andrew Grover
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26
27 #include <acpi.h>
28 #include "ec.h"
29
30 #define _COMPONENT ACPI_EC
31 MODULE_NAME ("ecmain")
32
33
34 /****************************************************************************
35 * Internal Functions
36 ****************************************************************************/
37
38 /****************************************************************************
39 *
40 * FUNCTION: ec_print
41 *
42 * PARAMETERS:
43 *
44 * RETURN:
45 *
46 * DESCRIPTION: Prints out information on a specific ec.
47 *
48 ****************************************************************************/
49
50 void
51 ec_print (
52 EC_CONTEXT *ec)
53 {
54 #ifdef ACPI_DEBUG
55 acpi_buffer buffer;
56 #endif /*ACPI_DEBUG*/
57
58 PROC_NAME("ec_print");
59
60 if (!ec) {
61 return;
62 }
63
64 acpi_os_printf("EC: found, GPE %d\n", ec->gpe_bit);
65
66 #ifdef ACPI_DEBUG
67 buffer.length = 256;
68 buffer.pointer = acpi_os_callocate(buffer.length);
69 if (!buffer.pointer) {
70 return;
71 }
72
73 /*
74 * Get the full pathname for this ACPI object.
75 */
76 acpi_get_name(ec->acpi_handle, ACPI_FULL_PATHNAME, &buffer);
77
78 /*
79 * Print out basic thermal zone information.
80 */
81 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n"));
82 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| Embedded_controller[%02x]:[%p] %s\n", ec->device_handle, ec->acpi_handle, buffer.pointer));
83 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "| gpe_bit[%02x] status/command_port[%02x] data_port[%02x]\n", ec->gpe_bit, ec->status_port, ec->data_port));
84 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, "+------------------------------------------------------------\n"));
85
86 acpi_os_free(buffer.pointer);
87 #endif /*ACPI_DEBUG*/
88
89 return;
90 }
91
92
93 /****************************************************************************
94 *
95 * FUNCTION: ec_get_port_values
96 *
97 * PARAMETERS:
98 *
99 * RETURN:
100 *
101 * DESCRIPTION: Evaluate _CRS to get the current resources (I/O port
102 * addresses) for this EC.
103 *
104 ****************************************************************************/
105
106 acpi_status
107 ec_get_port_values(
108 EC_CONTEXT *ec)
109 {
110 acpi_status status = AE_OK;
111 acpi_buffer buffer;
112 acpi_resource *resource = NULL;
113
114 FUNCTION_TRACE("ec_get_port_values");
115
116 if (!ec) {
117 return_ACPI_STATUS(AE_BAD_PARAMETER);
118 }
119
120 buffer.length = 0;
121 buffer.pointer = NULL;
122
123 status = acpi_get_current_resources(ec->acpi_handle, &buffer);
124 if (status != AE_BUFFER_OVERFLOW) {
125 return_ACPI_STATUS(status);
126 }
127
128 buffer.pointer = acpi_os_callocate(buffer.length);
129 if (!buffer.pointer) {
130 return_ACPI_STATUS(AE_NO_MEMORY);
131 }
132
133 status = acpi_get_current_resources(ec->acpi_handle, &buffer);
134 if (ACPI_FAILURE(status)) {
135 goto end;
136 }
137
138 resource = (acpi_resource *) buffer.pointer;
139 ec->data_port = resource->data.io.min_base_address;
140
141 resource = NEXT_RESOURCE(resource);
142
143 ec->status_port = ec->command_port =
144 resource->data.io.min_base_address;
145 end:
146 acpi_os_free(buffer.pointer);
147
148 return_ACPI_STATUS(status);
149 }
150
151
152 /****************************************************************************
153 *
154 * FUNCTION: ec_add_device
155 *
156 * PARAMETERS:
157 *
158 * RETURN:
159 *
160 * DESCRIPTION:
161 *
162 ****************************************************************************/
163
164 acpi_status
165 ec_add_device(
166 BM_HANDLE device_handle,
167 void **context)
168 {
169 acpi_status status = AE_OK;
170 BM_DEVICE *device = NULL;
171 EC_CONTEXT *ec = NULL;
172 u8 gpe_handler = FALSE;
173 u8 space_handler = FALSE;
174
175 FUNCTION_TRACE("ec_add_device");
176
177 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Adding EC device [%02x].\n", device_handle));
178
179 if (!context || *context) {
180 return_ACPI_STATUS(AE_BAD_PARAMETER);
181 }
182
183 /*
184 * Get information on this device.
185 */
186 status = bm_get_device_info(device_handle, &device);
187 if (ACPI_FAILURE(status)) {
188 return_ACPI_STATUS(status);
189 }
190
191 /*
192 * Allocate a new EC_CONTEXT structure.
193 */
194 ec = acpi_os_callocate(sizeof(EC_CONTEXT));
195 if (!ec) {
196 return_ACPI_STATUS(AE_NO_MEMORY);
197 }
198
199 ec->device_handle = device->handle;
200 ec->acpi_handle = device->acpi_handle;
201
202 /*
203 * Get the I/O port addresses for the command/status and data ports.
204 */
205 status = ec_get_port_values(ec);
206 if (ACPI_FAILURE(status)) {
207 goto end;
208 }
209
210 /*
211 * See if we need to obtain the global lock for EC transactions.
212 */
213 status = bm_evaluate_simple_integer(ec->acpi_handle, "_GLK",
214 &ec->use_global_lock);
215 if (status == AE_NOT_FOUND) {
216 ec->use_global_lock = 0;
217 }
218 else if (ACPI_FAILURE(status)) {
219 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "EC _GLK failed\n"));
220 goto end;
221 }
222
223 /*
224 * Install a handler for servicing this EC's GPE.
225 */
226 status = ec_install_gpe_handler(ec);
227 if (ACPI_FAILURE(status)) {
228 goto end;
229 }
230 else {
231 gpe_handler = TRUE;
232 }
233
234 /*
235 * Install a handler for servicing this EC's address space.
236 */
237 status = ec_install_space_handler(ec);
238 if (ACPI_FAILURE(status)) {
239 goto end;
240 }
241 else {
242 space_handler = TRUE;
243 }
244
245 /*
246 * Create a semaphore to serialize EC transactions.
247 */
248 status = acpi_os_create_semaphore(1,1, &(ec->mutex));
249 if (ACPI_FAILURE(status)) {
250 goto end;
251 }
252
253 /*
254 * Context now contains information specific to this EC. Note
255 * that we'll get this pointer back on every ec_request() and
256 * ec_notify().
257 */
258 *context = ec;
259
260 ec_print(ec);
261
262 end:
263 if (ACPI_FAILURE(status)) {
264
265 if (gpe_handler) {
266 ec_remove_gpe_handler(ec);
267 }
268
269 if (space_handler) {
270 ec_remove_space_handler(ec);
271 }
272
273 if (ec->mutex) {
274 acpi_os_delete_semaphore(ec->mutex);
275 }
276
277 acpi_os_free(ec);
278 }
279
280 return_ACPI_STATUS(status);
281 }
282
283
284 /****************************************************************************
285 *
286 * FUNCTION: ec_remove_device
287 *
288 * PARAMETERS:
289 *
290 * RETURN:
291 *
292 * DESCRIPTION:
293 *
294 ****************************************************************************/
295
296 acpi_status
297 ec_remove_device(
298 void **context)
299 {
300 acpi_status status = AE_OK;
301 EC_CONTEXT *ec = NULL;
302
303 FUNCTION_TRACE("ec_remove_device");
304
305 if (!context || !*context) {
306 return_ACPI_STATUS(AE_BAD_PARAMETER);
307 }
308
309 ec = (EC_CONTEXT*)*context;
310
311 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing EC device [%02x].\n", ec->device_handle));
312
313 ec_remove_space_handler(ec);
314
315 ec_remove_gpe_handler(ec);
316
317 if (ec->mutex) {
318 acpi_os_delete_semaphore(ec->mutex);
319 }
320
321 acpi_os_free(ec);
322
323 *context = NULL;
324
325 return_ACPI_STATUS(status);
326 }
327
328
329 /****************************************************************************
330 * External Functions
331 ****************************************************************************/
332
333 /****************************************************************************
334 *
335 * FUNCTION: ec_initialize
336 *
337 * PARAMETERS:
338 *
339 * RETURN:
340 *
341 * DESCRIPTION:
342 *
343 ****************************************************************************/
344
345 acpi_status
346 ec_initialize (void)
347 {
348 acpi_status status = AE_OK;
349 BM_DEVICE_ID criteria;
350 BM_DRIVER driver;
351
352 FUNCTION_TRACE("ec_initialize");
353
354 MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID));
355 MEMSET(&driver, 0, sizeof(BM_DRIVER));
356
357 /*
358 * Register driver for AC Adapter devices.
359 */
360 MEMCPY(criteria.hid, EC_HID_EC, sizeof(EC_HID_EC));
361
362 driver.notify = &ec_notify;
363 driver.request = &ec_request;
364
365 status = bm_register_driver(&criteria, &driver);
366
367 return_ACPI_STATUS(status);
368 }
369
370
371 /****************************************************************************
372 *
373 * FUNCTION: ec_terminate
374 *
375 * PARAMETERS:
376 *
377 * RETURN:
378 *
379 * DESCRIPTION:
380 *
381 ****************************************************************************/
382
383 acpi_status
384 ec_terminate(void)
385 {
386 acpi_status status = AE_OK;
387 BM_DEVICE_ID criteria;
388 BM_DRIVER driver;
389
390 FUNCTION_TRACE("ec_terminate");
391
392 MEMSET(&criteria, 0, sizeof(BM_DEVICE_ID));
393 MEMSET(&driver, 0, sizeof(BM_DRIVER));
394
395 /*
396 * Unregister driver for AC Adapter devices.
397 */
398 MEMCPY(criteria.hid, EC_HID_EC, sizeof(EC_HID_EC));
399
400 driver.notify = &ec_notify;
401 driver.request = &ec_request;
402
403 status = bm_unregister_driver(&criteria, &driver);
404
405 return_ACPI_STATUS(status);
406 }
407
408
409 /****************************************************************************
410 *
411 * FUNCTION: ec_notify
412 *
413 * PARAMETERS:
414 *
415 * RETURN:
416 *
417 * DESCRIPTION:
418 *
419 ****************************************************************************/
420
421 acpi_status
422 ec_notify (
423 BM_NOTIFY notify,
424 BM_HANDLE device_handle,
425 void **context)
426 {
427 acpi_status status = AE_OK;
428
429 FUNCTION_TRACE("ec_notify");
430
431 switch (notify) {
432
433 case BM_NOTIFY_DEVICE_ADDED:
434 status = ec_add_device(device_handle, context);
435 break;
436
437 case BM_NOTIFY_DEVICE_REMOVED:
438 status = ec_remove_device(context);
439 break;
440
441 default:
442 status = AE_SUPPORT;
443 break;
444 }
445
446 return_ACPI_STATUS(status);
447 }
448
449
450 /****************************************************************************
451 *
452 * FUNCTION: ec_request
453 *
454 * PARAMETERS:
455 *
456 * RETURN:
457 *
458 * DESCRIPTION:
459 *
460 ****************************************************************************/
461
462 acpi_status
463 ec_request (
464 BM_REQUEST *request,
465 void *context)
466 {
467 acpi_status status = AE_OK;
468 EC_REQUEST *ec_request = NULL;
469 EC_CONTEXT *ec = NULL;
470
471 FUNCTION_TRACE("ec_request");
472
473 /*
474 * Must have a valid request structure and context.
475 */
476 if (!request || !context)
477 return_ACPI_STATUS(AE_BAD_PARAMETER);
478
479 /*
480 * buffer must contain a valid EC_REQUEST structure.
481 */
482 status = bm_cast_buffer(&(request->buffer), (void**)&ec_request,
483 sizeof(EC_REQUEST));
484 if (ACPI_FAILURE(status))
485 return_ACPI_STATUS(status);
486
487 /*
488 * context contains information specific to this EC.
489 */
490 ec = (EC_CONTEXT*)context;
491
492 /*
493 * Perform the Transaction.
494 */
495 status = ec_transaction(ec, ec_request);
496
497 return_ACPI_STATUS(status);
498 }
499