import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / acpi / ospm / ec / ecmain.c
1 /*****************************************************************************
2  *
3  * Module Name: ecmain.c
4  *   $Revision: 1.1.1.1 $
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, (char*)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 }