OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [acpi/] [button.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  acpi_button.c - ACPI Button Driver ($Revision: 1.1.1.1 $)
3
 *
4
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6
 *
7
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or (at
12
 *  your option) any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful, but
15
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 *  General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License along
20
 *  with this program; if not, write to the Free Software Foundation, Inc.,
21
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22
 *
23
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24
 */
25
 
26
#include <linux/kernel.h>
27
#include <linux/module.h>
28
#include <linux/init.h>
29
#include <linux/types.h>
30
#include <linux/compatmac.h>
31
#include <linux/proc_fs.h>
32
#include <acpi/acpi_bus.h>
33
#include <acpi/acpi_drivers.h>
34
 
35
 
36
#define _COMPONENT              ACPI_BUTTON_COMPONENT
37
ACPI_MODULE_NAME                ("acpi_button")
38
 
39
MODULE_AUTHOR("Paul Diefenbaugh");
40
MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME);
41
MODULE_LICENSE("GPL");
42
 
43
#define PREFIX                  "ACPI: "
44
 
45
 
46
static int acpi_button_add (struct acpi_device *device);
47
static int acpi_button_remove (struct acpi_device *device, int type);
48
 
49
static struct acpi_driver acpi_button_driver = {
50
        .name =         ACPI_BUTTON_DRIVER_NAME,
51
        .class =        ACPI_BUTTON_CLASS,
52
        .ids =          "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E",
53
        .ops =          {
54
                                .add =          acpi_button_add,
55
                                .remove =       acpi_button_remove,
56
                        },
57
};
58
 
59
struct acpi_button {
60
        acpi_handle             handle;
61
        struct acpi_device      *device;        /* Fixed button kludge */
62
        u8                      type;
63
        unsigned long           pushed;
64
};
65
 
66
 
67
/* --------------------------------------------------------------------------
68
                              FS Interface (/proc)
69
   -------------------------------------------------------------------------- */
70
 
71
static struct proc_dir_entry    *acpi_button_dir;
72
 
73
static int
74
acpi_button_read_info (
75
        char                    *page,
76
        char                    **start,
77
        off_t                   off,
78
        int                     count,
79
        int                     *eof,
80
        void                    *data)
81
{
82
        struct acpi_button      *button = (struct acpi_button *) data;
83
        char                    *p = page;
84
        int                     len = 0;
85
 
86
        ACPI_FUNCTION_TRACE("acpi_button_read_info");
87
 
88
        if (!button || !button->device || (off != 0))
89
                goto end;
90
 
91
        p += sprintf(p, "type:                    %s\n",
92
                acpi_device_name(button->device));
93
 
94
end:
95
        len = (p - page);
96
        if (len <= off+count) *eof = 1;
97
        *start = page + off;
98
        len -= off;
99
        if (len>count) len = count;
100
        if (len<0) len = 0;
101
 
102
        return_VALUE(len);
103
}
104
 
105
static int
106
acpi_button_lid_read_state(
107
        char                    *page,
108
        char                    **start,
109
        off_t                   off,
110
        int                     count,
111
        int                     *eof,
112
        void                    *data)
113
{
114
        struct acpi_button      *button = (struct acpi_button *) data;
115
        char                    *p = page;
116
        int                     len = 0;
117
        acpi_status             status=AE_OK;
118
        unsigned long           state;
119
 
120
        ACPI_FUNCTION_TRACE("acpi_button_lid_read_state");
121
 
122
        if (!button || !button->device || (off != 0))
123
                goto end;
124
 
125
        status=acpi_evaluate_integer(button->handle,"_LID",NULL,&state);
126
        if (ACPI_FAILURE(status)){
127
            p += sprintf(p, "state:      unsupported\n");
128
        }
129
        else{
130
            p += sprintf(p, "state:      %s\n", (state ? "open" : "closed"));
131
        }
132
 
133
end:
134
        len = (p - page);
135
        if (len <= off+count) *eof = 1;
136
        *start = page + off;
137
        len -= off;
138
        if (len>count) len = count;
139
        if (len<0) len = 0;
140
 
141
        return_VALUE(len);
142
}
143
 
144
static int
145
acpi_button_add_fs (
146
        struct acpi_device      *device)
147
{
148
        struct proc_dir_entry   *entry = NULL;
149
        struct acpi_button      *button = NULL;
150
 
151
        ACPI_FUNCTION_TRACE("acpi_button_add_fs");
152
 
153
        if (!device || !acpi_driver_data(device))
154
                return_VALUE(-EINVAL);
155
 
156
        button = acpi_driver_data(device);
157
 
158
        switch (button->type) {
159
        case ACPI_BUTTON_TYPE_POWER:
160
        case ACPI_BUTTON_TYPE_POWERF:
161
                        entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER,
162
                                acpi_button_dir);
163
                break;
164
        case ACPI_BUTTON_TYPE_SLEEP:
165
        case ACPI_BUTTON_TYPE_SLEEPF:
166
                        entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP,
167
                                acpi_button_dir);
168
                break;
169
        case ACPI_BUTTON_TYPE_LID:
170
                        entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID,
171
                                acpi_button_dir);
172
                break;
173
        }
174
 
175
        acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
176
        if (!acpi_device_dir(device))
177
                return_VALUE(-ENODEV);
178
 
179
        /* 'info' [R] */
180
        entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
181
                S_IRUGO, acpi_device_dir(device));
182
        if (!entry)
183
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
184
                        "Unable to create '%s' fs entry\n",
185
                        ACPI_BUTTON_FILE_INFO));
186
        else {
187
                entry->read_proc = acpi_button_read_info;
188
                entry->data = acpi_driver_data(device);
189
        }
190
 
191
        if (button->type==ACPI_BUTTON_TYPE_LID){
192
            /* 'state' [R] */
193
            entry = create_proc_entry(ACPI_BUTTON_FILE_STATE,
194
                        S_IRUGO, acpi_device_dir(device));
195
            if (!entry)
196
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
197
                          "Unable to create '%s' fs entry\n",
198
                           ACPI_BUTTON_FILE_STATE));
199
            else {
200
                entry->read_proc = acpi_button_lid_read_state;
201
                entry->data = acpi_driver_data(device);
202
            }
203
        }
204
 
205
        return_VALUE(0);
206
}
207
 
208
 
209
static int
210
acpi_button_remove_fs (
211
        struct acpi_device      *device)
212
{
213
        ACPI_FUNCTION_TRACE("acpi_button_remove_fs");
214
 
215
        if (acpi_device_dir(device)) {
216
                remove_proc_entry(acpi_device_bid(device), acpi_button_dir);
217
                acpi_device_dir(device) = NULL;
218
        }
219
 
220
        return_VALUE(0);
221
}
222
 
223
 
224
/* --------------------------------------------------------------------------
225
                                Driver Interface
226
   -------------------------------------------------------------------------- */
227
 
228
void
229
acpi_button_notify (
230
        acpi_handle             handle,
231
        u32                     event,
232
        void                    *data)
233
{
234
        struct acpi_button      *button = (struct acpi_button *) data;
235
 
236
        ACPI_FUNCTION_TRACE("acpi_button_notify");
237
 
238
        if (!button || !button->device)
239
                return_VOID;
240
 
241
        switch (event) {
242
        case ACPI_BUTTON_NOTIFY_STATUS:
243
                acpi_bus_generate_event(button->device, event, ++button->pushed);
244
                break;
245
        default:
246
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
247
                        "Unsupported event [0x%x]\n", event));
248
                break;
249
        }
250
 
251
        return_VOID;
252
}
253
 
254
 
255
acpi_status
256
acpi_button_notify_fixed (
257
        void                    *data)
258
{
259
        struct acpi_button      *button = (struct acpi_button *) data;
260
 
261
        ACPI_FUNCTION_TRACE("acpi_button_notify_fixed");
262
 
263
        if (!button)
264
                return_ACPI_STATUS(AE_BAD_PARAMETER);
265
 
266
        acpi_button_notify(button->handle, ACPI_BUTTON_NOTIFY_STATUS, button);
267
 
268
        return_ACPI_STATUS(AE_OK);
269
}
270
 
271
 
272
static int
273
acpi_button_add (
274
        struct acpi_device      *device)
275
{
276
        int                     result = 0;
277
        acpi_status             status = AE_OK;
278
        struct acpi_button      *button = NULL;
279
 
280
        static struct acpi_device *power_button;
281
        static struct acpi_device *sleep_button;
282
        static struct acpi_device *lid_button;
283
 
284
        ACPI_FUNCTION_TRACE("acpi_button_add");
285
 
286
        if (!device)
287
                return_VALUE(-EINVAL);
288
 
289
        button = kmalloc(sizeof(struct acpi_button), GFP_KERNEL);
290
        if (!button)
291
                return_VALUE(-ENOMEM);
292
        memset(button, 0, sizeof(struct acpi_button));
293
 
294
        button->device = device;
295
        button->handle = device->handle;
296
        acpi_driver_data(device) = button;
297
 
298
        /*
299
         * Determine the button type (via hid), as fixed-feature buttons
300
         * need to be handled a bit differently than generic-space.
301
         */
302
        if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) {
303
                button->type = ACPI_BUTTON_TYPE_POWER;
304
                sprintf(acpi_device_name(device), "%s",
305
                        ACPI_BUTTON_DEVICE_NAME_POWER);
306
                sprintf(acpi_device_class(device), "%s/%s",
307
                        ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
308
        }
309
        else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) {
310
                button->type = ACPI_BUTTON_TYPE_POWERF;
311
                sprintf(acpi_device_name(device), "%s",
312
                        ACPI_BUTTON_DEVICE_NAME_POWERF);
313
                sprintf(acpi_device_class(device), "%s/%s",
314
                        ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
315
        }
316
        else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEP)) {
317
                button->type = ACPI_BUTTON_TYPE_SLEEP;
318
                sprintf(acpi_device_name(device), "%s",
319
                        ACPI_BUTTON_DEVICE_NAME_SLEEP);
320
                sprintf(acpi_device_class(device), "%s/%s",
321
                        ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
322
        }
323
        else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) {
324
                button->type = ACPI_BUTTON_TYPE_SLEEPF;
325
                sprintf(acpi_device_name(device), "%s",
326
                        ACPI_BUTTON_DEVICE_NAME_SLEEPF);
327
                sprintf(acpi_device_class(device), "%s/%s",
328
                        ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
329
        }
330
        else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_LID)) {
331
                button->type = ACPI_BUTTON_TYPE_LID;
332
                sprintf(acpi_device_name(device), "%s",
333
                        ACPI_BUTTON_DEVICE_NAME_LID);
334
                sprintf(acpi_device_class(device), "%s/%s",
335
                        ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
336
        }
337
        else {
338
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported hid [%s]\n",
339
                        acpi_device_hid(device)));
340
                result = -ENODEV;
341
                goto end;
342
        }
343
 
344
        /*
345
         * Ensure only one button of each type is used.
346
         */
347
        switch (button->type) {
348
        case ACPI_BUTTON_TYPE_POWER:
349
        case ACPI_BUTTON_TYPE_POWERF:
350
                if (!power_button)
351
                        power_button = device;
352
                else {
353
                        kfree(button);
354
                        return_VALUE(-ENODEV);
355
                }
356
                break;
357
        case ACPI_BUTTON_TYPE_SLEEP:
358
        case ACPI_BUTTON_TYPE_SLEEPF:
359
                if (!sleep_button)
360
                        sleep_button = device;
361
                else {
362
                        kfree(button);
363
                        return_VALUE(-ENODEV);
364
                }
365
                break;
366
        case ACPI_BUTTON_TYPE_LID:
367
                if (!lid_button)
368
                        lid_button = device;
369
                else {
370
                        kfree(button);
371
                        return_VALUE(-ENODEV);
372
                }
373
                break;
374
        }
375
 
376
        result = acpi_button_add_fs(device);
377
        if (result)
378
                goto end;
379
 
380
        switch (button->type) {
381
        case ACPI_BUTTON_TYPE_POWERF:
382
                status = acpi_install_fixed_event_handler (
383
                        ACPI_EVENT_POWER_BUTTON,
384
                        acpi_button_notify_fixed,
385
                        button);
386
                break;
387
        case ACPI_BUTTON_TYPE_SLEEPF:
388
                status = acpi_install_fixed_event_handler (
389
                        ACPI_EVENT_SLEEP_BUTTON,
390
                        acpi_button_notify_fixed,
391
                        button);
392
                break;
393
        default:
394
                status = acpi_install_notify_handler (
395
                        button->handle,
396
                        ACPI_DEVICE_NOTIFY,
397
                        acpi_button_notify,
398
                        button);
399
                break;
400
        }
401
 
402
        if (ACPI_FAILURE(status)) {
403
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
404
                        "Error installing notify handler\n"));
405
                result = -ENODEV;
406
                goto end;
407
        }
408
 
409
        printk(KERN_INFO PREFIX "%s [%s]\n",
410
                acpi_device_name(device), acpi_device_bid(device));
411
 
412
end:
413
        if (result) {
414
                acpi_button_remove_fs(device);
415
                kfree(button);
416
        }
417
 
418
        return_VALUE(result);
419
}
420
 
421
 
422
static int
423
acpi_button_remove (struct acpi_device *device, int type)
424
{
425
        acpi_status             status = 0;
426
        struct acpi_button      *button = NULL;
427
 
428
        ACPI_FUNCTION_TRACE("acpi_button_remove");
429
 
430
        if (!device || !acpi_driver_data(device))
431
                return_VALUE(-EINVAL);
432
 
433
        button = acpi_driver_data(device);
434
 
435
        /* Unregister for device notifications. */
436
        switch (button->type) {
437
        case ACPI_BUTTON_TYPE_POWERF:
438
                status = acpi_remove_fixed_event_handler(
439
                        ACPI_EVENT_POWER_BUTTON, acpi_button_notify_fixed);
440
                break;
441
        case ACPI_BUTTON_TYPE_SLEEPF:
442
                status = acpi_remove_fixed_event_handler(
443
                        ACPI_EVENT_SLEEP_BUTTON, acpi_button_notify_fixed);
444
                break;
445
        default:
446
                status = acpi_remove_notify_handler(button->handle,
447
                        ACPI_DEVICE_NOTIFY, acpi_button_notify);
448
                break;
449
        }
450
 
451
        if (ACPI_FAILURE(status))
452
                ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
453
                        "Error removing notify handler\n"));
454
 
455
        acpi_button_remove_fs(device);
456
 
457
        kfree(button);
458
 
459
        return_VALUE(0);
460
}
461
 
462
 
463
static int __init
464
acpi_button_init (void)
465
{
466
        int                     result = 0;
467
 
468
        ACPI_FUNCTION_TRACE("acpi_button_init");
469
 
470
        acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
471
        if (!acpi_button_dir)
472
                return_VALUE(-ENODEV);
473
 
474
        result = acpi_bus_register_driver(&acpi_button_driver);
475
        if (result < 0) {
476
                remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
477
                return_VALUE(-ENODEV);
478
        }
479
 
480
        return_VALUE(0);
481
}
482
 
483
 
484
static void __exit
485
acpi_button_exit (void)
486
{
487
        ACPI_FUNCTION_TRACE("acpi_button_exit");
488
 
489
        acpi_bus_unregister_driver(&acpi_button_driver);
490
 
491
        remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
492
 
493
        return_VOID;
494
}
495
 
496
 
497
module_init(acpi_button_init);
498
module_exit(acpi_button_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.