]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - drivers/acpi/video.c
Pull video into release branch
[linux-2.6.git] / drivers / acpi / video.c
1 /*
2  *  video.c - ACPI Video Driver ($Revision:$)
3  *
4  *  Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
5  *  Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
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/list.h>
31 #include <linux/proc_fs.h>
32 #include <linux/seq_file.h>
33
34 #include <asm/uaccess.h>
35
36 #include <acpi/acpi_bus.h>
37 #include <acpi/acpi_drivers.h>
38
39 #define ACPI_VIDEO_COMPONENT            0x08000000
40 #define ACPI_VIDEO_CLASS                "video"
41 #define ACPI_VIDEO_DRIVER_NAME          "ACPI Video Driver"
42 #define ACPI_VIDEO_BUS_NAME             "Video Bus"
43 #define ACPI_VIDEO_DEVICE_NAME          "Video Device"
44 #define ACPI_VIDEO_NOTIFY_SWITCH        0x80
45 #define ACPI_VIDEO_NOTIFY_PROBE         0x81
46 #define ACPI_VIDEO_NOTIFY_CYCLE         0x82
47 #define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT   0x83
48 #define ACPI_VIDEO_NOTIFY_PREV_OUTPUT   0x84
49
50 #define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS      0x82
51 #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS        0x83
52 #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS        0x84
53 #define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS       0x85
54 #define ACPI_VIDEO_NOTIFY_DISPLAY_OFF           0x86
55
56 #define ACPI_VIDEO_HEAD_INVALID         (~0u - 1)
57 #define ACPI_VIDEO_HEAD_END             (~0u)
58
59 #define _COMPONENT              ACPI_VIDEO_COMPONENT
60 ACPI_MODULE_NAME("acpi_video")
61
62     MODULE_AUTHOR("Bruno Ducrot");
63 MODULE_DESCRIPTION(ACPI_VIDEO_DRIVER_NAME);
64 MODULE_LICENSE("GPL");
65
66 static int acpi_video_bus_add(struct acpi_device *device);
67 static int acpi_video_bus_remove(struct acpi_device *device, int type);
68 static int acpi_video_bus_match(struct acpi_device *device,
69                                 struct acpi_driver *driver);
70
71 static struct acpi_driver acpi_video_bus = {
72         .name = ACPI_VIDEO_DRIVER_NAME,
73         .class = ACPI_VIDEO_CLASS,
74         .ops = {
75                 .add = acpi_video_bus_add,
76                 .remove = acpi_video_bus_remove,
77                 .match = acpi_video_bus_match,
78                 },
79 };
80
81 struct acpi_video_bus_flags {
82         u8 multihead:1;         /* can switch video heads */
83         u8 rom:1;               /* can retrieve a video rom */
84         u8 post:1;              /* can configure the head to */
85         u8 reserved:5;
86 };
87
88 struct acpi_video_bus_cap {
89         u8 _DOS:1;              /*Enable/Disable output switching */
90         u8 _DOD:1;              /*Enumerate all devices attached to display adapter */
91         u8 _ROM:1;              /*Get ROM Data */
92         u8 _GPD:1;              /*Get POST Device */
93         u8 _SPD:1;              /*Set POST Device */
94         u8 _VPO:1;              /*Video POST Options */
95         u8 reserved:2;
96 };
97
98 struct acpi_video_device_attrib {
99         u32 display_index:4;    /* A zero-based instance of the Display */
100         u32 display_port_attachment:4;  /*This field differenates displays type */
101         u32 display_type:4;     /*Describe the specific type in use */
102         u32 vendor_specific:4;  /*Chipset Vendor Specifi */
103         u32 bios_can_detect:1;  /*BIOS can detect the device */
104         u32 depend_on_vga:1;    /*Non-VGA output device whose power is related to 
105                                    the VGA device. */
106         u32 pipe_id:3;          /*For VGA multiple-head devices. */
107         u32 reserved:10;        /*Must be 0 */
108         u32 device_id_scheme:1; /*Device ID Scheme */
109 };
110
111 struct acpi_video_enumerated_device {
112         union {
113                 u32 int_val;
114                 struct acpi_video_device_attrib attrib;
115         } value;
116         struct acpi_video_device *bind_info;
117 };
118
119 struct acpi_video_bus {
120         acpi_handle handle;
121         u8 dos_setting;
122         struct acpi_video_enumerated_device *attached_array;
123         u8 attached_count;
124         struct acpi_video_bus_cap cap;
125         struct acpi_video_bus_flags flags;
126         struct semaphore sem;
127         struct list_head video_device_list;
128         struct proc_dir_entry *dir;
129 };
130
131 struct acpi_video_device_flags {
132         u8 crt:1;
133         u8 lcd:1;
134         u8 tvout:1;
135         u8 bios:1;
136         u8 unknown:1;
137         u8 reserved:3;
138 };
139
140 struct acpi_video_device_cap {
141         u8 _ADR:1;              /*Return the unique ID */
142         u8 _BCL:1;              /*Query list of brightness control levels supported */
143         u8 _BCM:1;              /*Set the brightness level */
144         u8 _DDC:1;              /*Return the EDID for this device */
145         u8 _DCS:1;              /*Return status of output device */
146         u8 _DGS:1;              /*Query graphics state */
147         u8 _DSS:1;              /*Device state set */
148         u8 _reserved:1;
149 };
150
151 struct acpi_video_device_brightness {
152         int curr;
153         int count;
154         int *levels;
155 };
156
157 struct acpi_video_device {
158         acpi_handle handle;
159         unsigned long device_id;
160         struct acpi_video_device_flags flags;
161         struct acpi_video_device_cap cap;
162         struct list_head entry;
163         struct acpi_video_bus *video;
164         struct acpi_device *dev;
165         struct acpi_video_device_brightness *brightness;
166 };
167
168 /* bus */
169 static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file);
170 static struct file_operations acpi_video_bus_info_fops = {
171         .open = acpi_video_bus_info_open_fs,
172         .read = seq_read,
173         .llseek = seq_lseek,
174         .release = single_release,
175 };
176
177 static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file);
178 static struct file_operations acpi_video_bus_ROM_fops = {
179         .open = acpi_video_bus_ROM_open_fs,
180         .read = seq_read,
181         .llseek = seq_lseek,
182         .release = single_release,
183 };
184
185 static int acpi_video_bus_POST_info_open_fs(struct inode *inode,
186                                             struct file *file);
187 static struct file_operations acpi_video_bus_POST_info_fops = {
188         .open = acpi_video_bus_POST_info_open_fs,
189         .read = seq_read,
190         .llseek = seq_lseek,
191         .release = single_release,
192 };
193
194 static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file);
195 static struct file_operations acpi_video_bus_POST_fops = {
196         .open = acpi_video_bus_POST_open_fs,
197         .read = seq_read,
198         .llseek = seq_lseek,
199         .release = single_release,
200 };
201
202 static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file);
203 static struct file_operations acpi_video_bus_DOS_fops = {
204         .open = acpi_video_bus_DOS_open_fs,
205         .read = seq_read,
206         .llseek = seq_lseek,
207         .release = single_release,
208 };
209
210 /* device */
211 static int acpi_video_device_info_open_fs(struct inode *inode,
212                                           struct file *file);
213 static struct file_operations acpi_video_device_info_fops = {
214         .open = acpi_video_device_info_open_fs,
215         .read = seq_read,
216         .llseek = seq_lseek,
217         .release = single_release,
218 };
219
220 static int acpi_video_device_state_open_fs(struct inode *inode,
221                                            struct file *file);
222 static struct file_operations acpi_video_device_state_fops = {
223         .open = acpi_video_device_state_open_fs,
224         .read = seq_read,
225         .llseek = seq_lseek,
226         .release = single_release,
227 };
228
229 static int acpi_video_device_brightness_open_fs(struct inode *inode,
230                                                 struct file *file);
231 static struct file_operations acpi_video_device_brightness_fops = {
232         .open = acpi_video_device_brightness_open_fs,
233         .read = seq_read,
234         .llseek = seq_lseek,
235         .release = single_release,
236 };
237
238 static int acpi_video_device_EDID_open_fs(struct inode *inode,
239                                           struct file *file);
240 static struct file_operations acpi_video_device_EDID_fops = {
241         .open = acpi_video_device_EDID_open_fs,
242         .read = seq_read,
243         .llseek = seq_lseek,
244         .release = single_release,
245 };
246
247 static char device_decode[][30] = {
248         "motherboard VGA device",
249         "PCI VGA device",
250         "AGP VGA device",
251         "UNKNOWN",
252 };
253
254 static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data);
255 static void acpi_video_device_rebind(struct acpi_video_bus *video);
256 static void acpi_video_device_bind(struct acpi_video_bus *video,
257                                    struct acpi_video_device *device);
258 static int acpi_video_device_enumerate(struct acpi_video_bus *video);
259 static int acpi_video_switch_output(struct acpi_video_bus *video, int event);
260 static int acpi_video_get_next_level(struct acpi_video_device *device,
261                                      u32 level_current, u32 event);
262 static void acpi_video_switch_brightness(struct acpi_video_device *device,
263                                          int event);
264
265 /* --------------------------------------------------------------------------
266                                Video Management
267    -------------------------------------------------------------------------- */
268
269 /* device */
270
271 static int
272 acpi_video_device_query(struct acpi_video_device *device, unsigned long *state)
273 {
274         int status;
275         ACPI_FUNCTION_TRACE("acpi_video_device_query");
276         status = acpi_evaluate_integer(device->handle, "_DGS", NULL, state);
277
278         return_VALUE(status);
279 }
280
281 static int
282 acpi_video_device_get_state(struct acpi_video_device *device,
283                             unsigned long *state)
284 {
285         int status;
286
287         ACPI_FUNCTION_TRACE("acpi_video_device_get_state");
288
289         status = acpi_evaluate_integer(device->handle, "_DCS", NULL, state);
290
291         return_VALUE(status);
292 }
293
294 static int
295 acpi_video_device_set_state(struct acpi_video_device *device, int state)
296 {
297         int status;
298         union acpi_object arg0 = { ACPI_TYPE_INTEGER };
299         struct acpi_object_list args = { 1, &arg0 };
300         unsigned long ret;
301
302         ACPI_FUNCTION_TRACE("acpi_video_device_set_state");
303
304         arg0.integer.value = state;
305         status = acpi_evaluate_integer(device->handle, "_DSS", &args, &ret);
306
307         return_VALUE(status);
308 }
309
310 static int
311 acpi_video_device_lcd_query_levels(struct acpi_video_device *device,
312                                    union acpi_object **levels)
313 {
314         int status;
315         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
316         union acpi_object *obj;
317
318         ACPI_FUNCTION_TRACE("acpi_video_device_lcd_query_levels");
319
320         *levels = NULL;
321
322         status = acpi_evaluate_object(device->handle, "_BCL", NULL, &buffer);
323         if (!ACPI_SUCCESS(status))
324                 return_VALUE(status);
325         obj = (union acpi_object *)buffer.pointer;
326         if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
327                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _BCL data\n"));
328                 status = -EFAULT;
329                 goto err;
330         }
331
332         *levels = obj;
333
334         return_VALUE(0);
335
336       err:
337         kfree(buffer.pointer);
338
339         return_VALUE(status);
340 }
341
342 static int
343 acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
344 {
345         int status;
346         union acpi_object arg0 = { ACPI_TYPE_INTEGER };
347         struct acpi_object_list args = { 1, &arg0 };
348
349         ACPI_FUNCTION_TRACE("acpi_video_device_lcd_set_level");
350
351         arg0.integer.value = level;
352         status = acpi_evaluate_object(device->handle, "_BCM", &args, NULL);
353
354         printk(KERN_DEBUG "set_level status: %x\n", status);
355         return_VALUE(status);
356 }
357
358 static int
359 acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
360                                         unsigned long *level)
361 {
362         int status;
363         ACPI_FUNCTION_TRACE("acpi_video_device_lcd_get_level_current");
364
365         status = acpi_evaluate_integer(device->handle, "_BQC", NULL, level);
366
367         return_VALUE(status);
368 }
369
370 static int
371 acpi_video_device_EDID(struct acpi_video_device *device,
372                        union acpi_object **edid, ssize_t length)
373 {
374         int status;
375         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
376         union acpi_object *obj;
377         union acpi_object arg0 = { ACPI_TYPE_INTEGER };
378         struct acpi_object_list args = { 1, &arg0 };
379
380         ACPI_FUNCTION_TRACE("acpi_video_device_get_EDID");
381
382         *edid = NULL;
383
384         if (!device)
385                 return_VALUE(-ENODEV);
386         if (length == 128)
387                 arg0.integer.value = 1;
388         else if (length == 256)
389                 arg0.integer.value = 2;
390         else
391                 return_VALUE(-EINVAL);
392
393         status = acpi_evaluate_object(device->handle, "_DDC", &args, &buffer);
394         if (ACPI_FAILURE(status))
395                 return_VALUE(-ENODEV);
396
397         obj = (union acpi_object *)buffer.pointer;
398
399         if (obj && obj->type == ACPI_TYPE_BUFFER)
400                 *edid = obj;
401         else {
402                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DDC data\n"));
403                 status = -EFAULT;
404                 kfree(obj);
405         }
406
407         return_VALUE(status);
408 }
409
410 /* bus */
411
412 static int
413 acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
414 {
415         int status;
416         unsigned long tmp;
417         union acpi_object arg0 = { ACPI_TYPE_INTEGER };
418         struct acpi_object_list args = { 1, &arg0 };
419
420         ACPI_FUNCTION_TRACE("acpi_video_bus_set_POST");
421
422         arg0.integer.value = option;
423
424         status = acpi_evaluate_integer(video->handle, "_SPD", &args, &tmp);
425         if (ACPI_SUCCESS(status))
426                 status = tmp ? (-EINVAL) : (AE_OK);
427
428         return_VALUE(status);
429 }
430
431 static int
432 acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long *id)
433 {
434         int status;
435
436         ACPI_FUNCTION_TRACE("acpi_video_bus_get_POST");
437
438         status = acpi_evaluate_integer(video->handle, "_GPD", NULL, id);
439
440         return_VALUE(status);
441 }
442
443 static int
444 acpi_video_bus_POST_options(struct acpi_video_bus *video,
445                             unsigned long *options)
446 {
447         int status;
448         ACPI_FUNCTION_TRACE("acpi_video_bus_POST_options");
449
450         status = acpi_evaluate_integer(video->handle, "_VPO", NULL, options);
451         *options &= 3;
452
453         return_VALUE(status);
454 }
455
456 /*
457  *  Arg:
458  *      video           : video bus device pointer
459  *      bios_flag       : 
460  *              0.      The system BIOS should NOT automatically switch(toggle)
461  *                      the active display output.
462  *              1.      The system BIOS should automatically switch (toggle) the
463  *                      active display output. No swich event.
464  *              2.      The _DGS value should be locked.
465  *              3.      The system BIOS should not automatically switch (toggle) the
466  *                      active display output, but instead generate the display switch
467  *                      event notify code.
468  *      lcd_flag        :
469  *              0.      The system BIOS should automatically control the brightness level
470  *                      of the LCD, when the power changes from AC to DC
471  *              1.      The system BIOS should NOT automatically control the brightness 
472  *                      level of the LCD, when the power changes from AC to DC.
473  * Return Value:
474  *              -1      wrong arg.
475  */
476
477 static int
478 acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
479 {
480         acpi_integer status = 0;
481         union acpi_object arg0 = { ACPI_TYPE_INTEGER };
482         struct acpi_object_list args = { 1, &arg0 };
483
484         ACPI_FUNCTION_TRACE("acpi_video_bus_DOS");
485
486         if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) {
487                 status = -1;
488                 goto Failed;
489         }
490         arg0.integer.value = (lcd_flag << 2) | bios_flag;
491         video->dos_setting = arg0.integer.value;
492         acpi_evaluate_object(video->handle, "_DOS", &args, NULL);
493
494       Failed:
495         return_VALUE(status);
496 }
497
498 /*
499  *  Arg:        
500  *      device  : video output device (LCD, CRT, ..)
501  *
502  *  Return Value:
503  *      None
504  *
505  *  Find out all required AML method defined under the output
506  *  device.
507  */
508
509 static void acpi_video_device_find_cap(struct acpi_video_device *device)
510 {
511         acpi_integer status;
512         acpi_handle h_dummy1;
513         int i;
514         union acpi_object *obj = NULL;
515         struct acpi_video_device_brightness *br = NULL;
516
517         ACPI_FUNCTION_TRACE("acpi_video_device_find_cap");
518
519         memset(&device->cap, 0, 4);
520
521         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ADR", &h_dummy1))) {
522                 device->cap._ADR = 1;
523         }
524         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_BCL", &h_dummy1))) {
525                 device->cap._BCL = 1;
526         }
527         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_BCM", &h_dummy1))) {
528                 device->cap._BCM = 1;
529         }
530         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DDC", &h_dummy1))) {
531                 device->cap._DDC = 1;
532         }
533         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DCS", &h_dummy1))) {
534                 device->cap._DCS = 1;
535         }
536         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DGS", &h_dummy1))) {
537                 device->cap._DGS = 1;
538         }
539         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DSS", &h_dummy1))) {
540                 device->cap._DSS = 1;
541         }
542
543         status = acpi_video_device_lcd_query_levels(device, &obj);
544
545         if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count >= 2) {
546                 int count = 0;
547                 union acpi_object *o;
548
549                 br = kmalloc(sizeof(*br), GFP_KERNEL);
550                 if (!br) {
551                         printk(KERN_ERR "can't allocate memory\n");
552                 } else {
553                         memset(br, 0, sizeof(*br));
554                         br->levels = kmalloc(obj->package.count *
555                                              sizeof *(br->levels), GFP_KERNEL);
556                         if (!br->levels)
557                                 goto out;
558
559                         for (i = 0; i < obj->package.count; i++) {
560                                 o = (union acpi_object *)&obj->package.
561                                     elements[i];
562                                 if (o->type != ACPI_TYPE_INTEGER) {
563                                         ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
564                                                           "Invalid data\n"));
565                                         continue;
566                                 }
567                                 br->levels[count] = (u32) o->integer.value;
568                                 count++;
569                         }
570                       out:
571                         if (count < 2) {
572                                 kfree(br->levels);
573                                 kfree(br);
574                         } else {
575                                 br->count = count;
576                                 device->brightness = br;
577                                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
578                                                   "found %d brightness levels\n",
579                                                   count));
580                         }
581                 }
582         }
583
584         kfree(obj);
585
586         return_VOID;
587 }
588
589 /*
590  *  Arg:        
591  *      device  : video output device (VGA)
592  *
593  *  Return Value:
594  *      None
595  *
596  *  Find out all required AML method defined under the video bus device.
597  */
598
599 static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
600 {
601         acpi_handle h_dummy1;
602
603         memset(&video->cap, 0, 4);
604         if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_DOS", &h_dummy1))) {
605                 video->cap._DOS = 1;
606         }
607         if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_DOD", &h_dummy1))) {
608                 video->cap._DOD = 1;
609         }
610         if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_ROM", &h_dummy1))) {
611                 video->cap._ROM = 1;
612         }
613         if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_GPD", &h_dummy1))) {
614                 video->cap._GPD = 1;
615         }
616         if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_SPD", &h_dummy1))) {
617                 video->cap._SPD = 1;
618         }
619         if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_VPO", &h_dummy1))) {
620                 video->cap._VPO = 1;
621         }
622 }
623
624 /*
625  * Check whether the video bus device has required AML method to
626  * support the desired features
627  */
628
629 static int acpi_video_bus_check(struct acpi_video_bus *video)
630 {
631         acpi_status status = -ENOENT;
632
633         ACPI_FUNCTION_TRACE("acpi_video_bus_check");
634
635         if (!video)
636                 return_VALUE(-EINVAL);
637
638         /* Since there is no HID, CID and so on for VGA driver, we have
639          * to check well known required nodes.
640          */
641
642         /* Does this device able to support video switching ? */
643         if (video->cap._DOS) {
644                 video->flags.multihead = 1;
645                 status = 0;
646         }
647
648         /* Does this device able to retrieve a retrieve a video ROM ? */
649         if (video->cap._ROM) {
650                 video->flags.rom = 1;
651                 status = 0;
652         }
653
654         /* Does this device able to configure which video device to POST ? */
655         if (video->cap._GPD && video->cap._SPD && video->cap._VPO) {
656                 video->flags.post = 1;
657                 status = 0;
658         }
659
660         return_VALUE(status);
661 }
662
663 /* --------------------------------------------------------------------------
664                               FS Interface (/proc)
665    -------------------------------------------------------------------------- */
666
667 static struct proc_dir_entry *acpi_video_dir;
668
669 /* video devices */
670
671 static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
672 {
673         struct acpi_video_device *dev =
674             (struct acpi_video_device *)seq->private;
675
676         ACPI_FUNCTION_TRACE("acpi_video_device_info_seq_show");
677
678         if (!dev)
679                 goto end;
680
681         seq_printf(seq, "device_id:    0x%04x\n", (u32) dev->device_id);
682         seq_printf(seq, "type:         ");
683         if (dev->flags.crt)
684                 seq_printf(seq, "CRT\n");
685         else if (dev->flags.lcd)
686                 seq_printf(seq, "LCD\n");
687         else if (dev->flags.tvout)
688                 seq_printf(seq, "TVOUT\n");
689         else
690                 seq_printf(seq, "UNKNOWN\n");
691
692         seq_printf(seq, "known by bios: %s\n", dev->flags.bios ? "yes" : "no");
693
694       end:
695         return_VALUE(0);
696 }
697
698 static int
699 acpi_video_device_info_open_fs(struct inode *inode, struct file *file)
700 {
701         return single_open(file, acpi_video_device_info_seq_show,
702                            PDE(inode)->data);
703 }
704
705 static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
706 {
707         int status;
708         struct acpi_video_device *dev =
709             (struct acpi_video_device *)seq->private;
710         unsigned long state;
711
712         ACPI_FUNCTION_TRACE("acpi_video_device_state_seq_show");
713
714         if (!dev)
715                 goto end;
716
717         status = acpi_video_device_get_state(dev, &state);
718         seq_printf(seq, "state:     ");
719         if (ACPI_SUCCESS(status))
720                 seq_printf(seq, "0x%02lx\n", state);
721         else
722                 seq_printf(seq, "<not supported>\n");
723
724         status = acpi_video_device_query(dev, &state);
725         seq_printf(seq, "query:     ");
726         if (ACPI_SUCCESS(status))
727                 seq_printf(seq, "0x%02lx\n", state);
728         else
729                 seq_printf(seq, "<not supported>\n");
730
731       end:
732         return_VALUE(0);
733 }
734
735 static int
736 acpi_video_device_state_open_fs(struct inode *inode, struct file *file)
737 {
738         return single_open(file, acpi_video_device_state_seq_show,
739                            PDE(inode)->data);
740 }
741
742 static ssize_t
743 acpi_video_device_write_state(struct file *file,
744                               const char __user * buffer,
745                               size_t count, loff_t * data)
746 {
747         int status;
748         struct seq_file *m = (struct seq_file *)file->private_data;
749         struct acpi_video_device *dev = (struct acpi_video_device *)m->private;
750         char str[12] = { 0 };
751         u32 state = 0;
752
753         ACPI_FUNCTION_TRACE("acpi_video_device_write_state");
754
755         if (!dev || count + 1 > sizeof str)
756                 return_VALUE(-EINVAL);
757
758         if (copy_from_user(str, buffer, count))
759                 return_VALUE(-EFAULT);
760
761         str[count] = 0;
762         state = simple_strtoul(str, NULL, 0);
763         state &= ((1ul << 31) | (1ul << 30) | (1ul << 0));
764
765         status = acpi_video_device_set_state(dev, state);
766
767         if (status)
768                 return_VALUE(-EFAULT);
769
770         return_VALUE(count);
771 }
772
773 static int
774 acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset)
775 {
776         struct acpi_video_device *dev =
777             (struct acpi_video_device *)seq->private;
778         int i;
779
780         ACPI_FUNCTION_TRACE("acpi_video_device_brightness_seq_show");
781
782         if (!dev || !dev->brightness) {
783                 seq_printf(seq, "<not supported>\n");
784                 return_VALUE(0);
785         }
786
787         seq_printf(seq, "levels: ");
788         for (i = 0; i < dev->brightness->count; i++)
789                 seq_printf(seq, " %d", dev->brightness->levels[i]);
790         seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr);
791
792         return_VALUE(0);
793 }
794
795 static int
796 acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file)
797 {
798         return single_open(file, acpi_video_device_brightness_seq_show,
799                            PDE(inode)->data);
800 }
801
802 static ssize_t
803 acpi_video_device_write_brightness(struct file *file,
804                                    const char __user * buffer,
805                                    size_t count, loff_t * data)
806 {
807         struct seq_file *m = (struct seq_file *)file->private_data;
808         struct acpi_video_device *dev = (struct acpi_video_device *)m->private;
809         char str[4] = { 0 };
810         unsigned int level = 0;
811         int i;
812
813         ACPI_FUNCTION_TRACE("acpi_video_device_write_brightness");
814
815         if (!dev || !dev->brightness || count + 1 > sizeof str)
816                 return_VALUE(-EINVAL);
817
818         if (copy_from_user(str, buffer, count))
819                 return_VALUE(-EFAULT);
820
821         str[count] = 0;
822         level = simple_strtoul(str, NULL, 0);
823
824         if (level > 100)
825                 return_VALUE(-EFAULT);
826
827         /* validate though the list of available levels */
828         for (i = 0; i < dev->brightness->count; i++)
829                 if (level == dev->brightness->levels[i]) {
830                         if (ACPI_SUCCESS
831                             (acpi_video_device_lcd_set_level(dev, level)))
832                                 dev->brightness->curr = level;
833                         break;
834                 }
835
836         return_VALUE(count);
837 }
838
839 static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset)
840 {
841         struct acpi_video_device *dev =
842             (struct acpi_video_device *)seq->private;
843         int status;
844         int i;
845         union acpi_object *edid = NULL;
846
847         ACPI_FUNCTION_TRACE("acpi_video_device_EDID_seq_show");
848
849         if (!dev)
850                 goto out;
851
852         status = acpi_video_device_EDID(dev, &edid, 128);
853         if (ACPI_FAILURE(status)) {
854                 status = acpi_video_device_EDID(dev, &edid, 256);
855         }
856
857         if (ACPI_FAILURE(status)) {
858                 goto out;
859         }
860
861         if (edid && edid->type == ACPI_TYPE_BUFFER) {
862                 for (i = 0; i < edid->buffer.length; i++)
863                         seq_putc(seq, edid->buffer.pointer[i]);
864         }
865
866       out:
867         if (!edid)
868                 seq_printf(seq, "<not supported>\n");
869         else
870                 kfree(edid);
871
872         return_VALUE(0);
873 }
874
875 static int
876 acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file)
877 {
878         return single_open(file, acpi_video_device_EDID_seq_show,
879                            PDE(inode)->data);
880 }
881
882 static int acpi_video_device_add_fs(struct acpi_device *device)
883 {
884         struct proc_dir_entry *entry = NULL;
885         struct acpi_video_device *vid_dev;
886
887         ACPI_FUNCTION_TRACE("acpi_video_device_add_fs");
888
889         if (!device)
890                 return_VALUE(-ENODEV);
891
892         vid_dev = (struct acpi_video_device *)acpi_driver_data(device);
893         if (!vid_dev)
894                 return_VALUE(-ENODEV);
895
896         if (!acpi_device_dir(device)) {
897                 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
898                                                      vid_dev->video->dir);
899                 if (!acpi_device_dir(device))
900                         return_VALUE(-ENODEV);
901                 acpi_device_dir(device)->owner = THIS_MODULE;
902         }
903
904         /* 'info' [R] */
905         entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
906         if (!entry)
907                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
908                                   "Unable to create 'info' fs entry\n"));
909         else {
910                 entry->proc_fops = &acpi_video_device_info_fops;
911                 entry->data = acpi_driver_data(device);
912                 entry->owner = THIS_MODULE;
913         }
914
915         /* 'state' [R/W] */
916         entry =
917             create_proc_entry("state", S_IFREG | S_IRUGO | S_IWUSR,
918                               acpi_device_dir(device));
919         if (!entry)
920                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
921                                   "Unable to create 'state' fs entry\n"));
922         else {
923                 acpi_video_device_state_fops.write = acpi_video_device_write_state;
924                 entry->proc_fops = &acpi_video_device_state_fops;
925                 entry->data = acpi_driver_data(device);
926                 entry->owner = THIS_MODULE;
927         }
928
929         /* 'brightness' [R/W] */
930         entry =
931             create_proc_entry("brightness", S_IFREG | S_IRUGO | S_IWUSR,
932                               acpi_device_dir(device));
933         if (!entry)
934                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
935                                   "Unable to create 'brightness' fs entry\n"));
936         else {
937                 acpi_video_device_brightness_fops.write = acpi_video_device_write_brightness;
938                 entry->proc_fops = &acpi_video_device_brightness_fops;
939                 entry->data = acpi_driver_data(device);
940                 entry->owner = THIS_MODULE;
941         }
942
943         /* 'EDID' [R] */
944         entry = create_proc_entry("EDID", S_IRUGO, acpi_device_dir(device));
945         if (!entry)
946                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
947                                   "Unable to create 'brightness' fs entry\n"));
948         else {
949                 entry->proc_fops = &acpi_video_device_EDID_fops;
950                 entry->data = acpi_driver_data(device);
951                 entry->owner = THIS_MODULE;
952         }
953
954         return_VALUE(0);
955 }
956
957 static int acpi_video_device_remove_fs(struct acpi_device *device)
958 {
959         struct acpi_video_device *vid_dev;
960         ACPI_FUNCTION_TRACE("acpi_video_device_remove_fs");
961
962         vid_dev = (struct acpi_video_device *)acpi_driver_data(device);
963         if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
964                 return_VALUE(-ENODEV);
965
966         if (acpi_device_dir(device)) {
967                 remove_proc_entry("info", acpi_device_dir(device));
968                 remove_proc_entry("state", acpi_device_dir(device));
969                 remove_proc_entry("brightness", acpi_device_dir(device));
970                 remove_proc_entry("EDID", acpi_device_dir(device));
971                 remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
972                 acpi_device_dir(device) = NULL;
973         }
974
975         return_VALUE(0);
976 }
977
978 /* video bus */
979 static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset)
980 {
981         struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
982
983         ACPI_FUNCTION_TRACE("acpi_video_bus_info_seq_show");
984
985         if (!video)
986                 goto end;
987
988         seq_printf(seq, "Switching heads:              %s\n",
989                    video->flags.multihead ? "yes" : "no");
990         seq_printf(seq, "Video ROM:                    %s\n",
991                    video->flags.rom ? "yes" : "no");
992         seq_printf(seq, "Device to be POSTed on boot:  %s\n",
993                    video->flags.post ? "yes" : "no");
994
995       end:
996         return_VALUE(0);
997 }
998
999 static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file)
1000 {
1001         return single_open(file, acpi_video_bus_info_seq_show,
1002                            PDE(inode)->data);
1003 }
1004
1005 static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset)
1006 {
1007         struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
1008
1009         ACPI_FUNCTION_TRACE("acpi_video_bus_ROM_seq_show");
1010
1011         if (!video)
1012                 goto end;
1013
1014         printk(KERN_INFO PREFIX "Please implement %s\n", __FUNCTION__);
1015         seq_printf(seq, "<TODO>\n");
1016
1017       end:
1018         return_VALUE(0);
1019 }
1020
1021 static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file)
1022 {
1023         return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data);
1024 }
1025
1026 static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
1027 {
1028         struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
1029         unsigned long options;
1030         int status;
1031
1032         ACPI_FUNCTION_TRACE("acpi_video_bus_POST_info_seq_show");
1033
1034         if (!video)
1035                 goto end;
1036
1037         status = acpi_video_bus_POST_options(video, &options);
1038         if (ACPI_SUCCESS(status)) {
1039                 if (!(options & 1)) {
1040                         printk(KERN_WARNING PREFIX
1041                                "The motherboard VGA device is not listed as a possible POST device.\n");
1042                         printk(KERN_WARNING PREFIX
1043                                "This indicate a BIOS bug.  Please contact the manufacturer.\n");
1044                 }
1045                 printk("%lx\n", options);
1046                 seq_printf(seq, "can POST: <intgrated video>");
1047                 if (options & 2)
1048                         seq_printf(seq, " <PCI video>");
1049                 if (options & 4)
1050                         seq_printf(seq, " <AGP video>");
1051                 seq_putc(seq, '\n');
1052         } else
1053                 seq_printf(seq, "<not supported>\n");
1054       end:
1055         return_VALUE(0);
1056 }
1057
1058 static int
1059 acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file)
1060 {
1061         return single_open(file, acpi_video_bus_POST_info_seq_show,
1062                            PDE(inode)->data);
1063 }
1064
1065 static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
1066 {
1067         struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
1068         int status;
1069         unsigned long id;
1070
1071         ACPI_FUNCTION_TRACE("acpi_video_bus_POST_seq_show");
1072
1073         if (!video)
1074                 goto end;
1075
1076         status = acpi_video_bus_get_POST(video, &id);
1077         if (!ACPI_SUCCESS(status)) {
1078                 seq_printf(seq, "<not supported>\n");
1079                 goto end;
1080         }
1081         seq_printf(seq, "device posted is <%s>\n", device_decode[id & 3]);
1082
1083       end:
1084         return_VALUE(0);
1085 }
1086
1087 static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset)
1088 {
1089         struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
1090
1091         ACPI_FUNCTION_TRACE("acpi_video_bus_DOS_seq_show");
1092
1093         seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting);
1094
1095         return_VALUE(0);
1096 }
1097
1098 static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file)
1099 {
1100         return single_open(file, acpi_video_bus_POST_seq_show,
1101                            PDE(inode)->data);
1102 }
1103
1104 static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file)
1105 {
1106         return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data);
1107 }
1108
1109 static ssize_t
1110 acpi_video_bus_write_POST(struct file *file,
1111                           const char __user * buffer,
1112                           size_t count, loff_t * data)
1113 {
1114         int status;
1115         struct seq_file *m = (struct seq_file *)file->private_data;
1116         struct acpi_video_bus *video = (struct acpi_video_bus *)m->private;
1117         char str[12] = { 0 };
1118         unsigned long opt, options;
1119
1120         ACPI_FUNCTION_TRACE("acpi_video_bus_write_POST");
1121
1122         if (!video || count + 1 > sizeof str)
1123                 return_VALUE(-EINVAL);
1124
1125         status = acpi_video_bus_POST_options(video, &options);
1126         if (!ACPI_SUCCESS(status))
1127                 return_VALUE(-EINVAL);
1128
1129         if (copy_from_user(str, buffer, count))
1130                 return_VALUE(-EFAULT);
1131
1132         str[count] = 0;
1133         opt = strtoul(str, NULL, 0);
1134         if (opt > 3)
1135                 return_VALUE(-EFAULT);
1136
1137         /* just in case an OEM 'forget' the motherboard... */
1138         options |= 1;
1139
1140         if (options & (1ul << opt)) {
1141                 status = acpi_video_bus_set_POST(video, opt);
1142                 if (!ACPI_SUCCESS(status))
1143                         return_VALUE(-EFAULT);
1144
1145         }
1146
1147         return_VALUE(count);
1148 }
1149
1150 static ssize_t
1151 acpi_video_bus_write_DOS(struct file *file,
1152                          const char __user * buffer,
1153                          size_t count, loff_t * data)
1154 {
1155         int status;
1156         struct seq_file *m = (struct seq_file *)file->private_data;
1157         struct acpi_video_bus *video = (struct acpi_video_bus *)m->private;
1158         char str[12] = { 0 };
1159         unsigned long opt;
1160
1161         ACPI_FUNCTION_TRACE("acpi_video_bus_write_DOS");
1162
1163         if (!video || count + 1 > sizeof str)
1164                 return_VALUE(-EINVAL);
1165
1166         if (copy_from_user(str, buffer, count))
1167                 return_VALUE(-EFAULT);
1168
1169         str[count] = 0;
1170         opt = strtoul(str, NULL, 0);
1171         if (opt > 7)
1172                 return_VALUE(-EFAULT);
1173
1174         status = acpi_video_bus_DOS(video, opt & 0x3, (opt & 0x4) >> 2);
1175
1176         if (!ACPI_SUCCESS(status))
1177                 return_VALUE(-EFAULT);
1178
1179         return_VALUE(count);
1180 }
1181
1182 static int acpi_video_bus_add_fs(struct acpi_device *device)
1183 {
1184         struct proc_dir_entry *entry = NULL;
1185         struct acpi_video_bus *video;
1186
1187         ACPI_FUNCTION_TRACE("acpi_video_bus_add_fs");
1188
1189         video = (struct acpi_video_bus *)acpi_driver_data(device);
1190
1191         if (!acpi_device_dir(device)) {
1192                 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
1193                                                      acpi_video_dir);
1194                 if (!acpi_device_dir(device))
1195                         return_VALUE(-ENODEV);
1196                 video->dir = acpi_device_dir(device);
1197                 acpi_device_dir(device)->owner = THIS_MODULE;
1198         }
1199
1200         /* 'info' [R] */
1201         entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
1202         if (!entry)
1203                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1204                                   "Unable to create 'info' fs entry\n"));
1205         else {
1206                 entry->proc_fops = &acpi_video_bus_info_fops;
1207                 entry->data = acpi_driver_data(device);
1208                 entry->owner = THIS_MODULE;
1209         }
1210
1211         /* 'ROM' [R] */
1212         entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device));
1213         if (!entry)
1214                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1215                                   "Unable to create 'ROM' fs entry\n"));
1216         else {
1217                 entry->proc_fops = &acpi_video_bus_ROM_fops;
1218                 entry->data = acpi_driver_data(device);
1219                 entry->owner = THIS_MODULE;
1220         }
1221
1222         /* 'POST_info' [R] */
1223         entry =
1224             create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device));
1225         if (!entry)
1226                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1227                                   "Unable to create 'POST_info' fs entry\n"));
1228         else {
1229                 entry->proc_fops = &acpi_video_bus_POST_info_fops;
1230                 entry->data = acpi_driver_data(device);
1231                 entry->owner = THIS_MODULE;
1232         }
1233
1234         /* 'POST' [R/W] */
1235         entry =
1236             create_proc_entry("POST", S_IFREG | S_IRUGO | S_IRUSR,
1237                               acpi_device_dir(device));
1238         if (!entry)
1239                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1240                                   "Unable to create 'POST' fs entry\n"));
1241         else {
1242                 acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST;
1243                 entry->proc_fops = &acpi_video_bus_POST_fops;
1244                 entry->data = acpi_driver_data(device);
1245                 entry->owner = THIS_MODULE;
1246         }
1247
1248         /* 'DOS' [R/W] */
1249         entry =
1250             create_proc_entry("DOS", S_IFREG | S_IRUGO | S_IRUSR,
1251                               acpi_device_dir(device));
1252         if (!entry)
1253                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1254                                   "Unable to create 'DOS' fs entry\n"));
1255         else {
1256                 acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS;
1257                 entry->proc_fops = &acpi_video_bus_DOS_fops;
1258                 entry->data = acpi_driver_data(device);
1259                 entry->owner = THIS_MODULE;
1260         }
1261
1262         return_VALUE(0);
1263 }
1264
1265 static int acpi_video_bus_remove_fs(struct acpi_device *device)
1266 {
1267         struct acpi_video_bus *video;
1268
1269         ACPI_FUNCTION_TRACE("acpi_video_bus_remove_fs");
1270
1271         video = (struct acpi_video_bus *)acpi_driver_data(device);
1272
1273         if (acpi_device_dir(device)) {
1274                 remove_proc_entry("info", acpi_device_dir(device));
1275                 remove_proc_entry("ROM", acpi_device_dir(device));
1276                 remove_proc_entry("POST_info", acpi_device_dir(device));
1277                 remove_proc_entry("POST", acpi_device_dir(device));
1278                 remove_proc_entry("DOS", acpi_device_dir(device));
1279                 remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
1280                 acpi_device_dir(device) = NULL;
1281         }
1282
1283         return_VALUE(0);
1284 }
1285
1286 /* --------------------------------------------------------------------------
1287                                  Driver Interface
1288    -------------------------------------------------------------------------- */
1289
1290 /* device interface */
1291
1292 static int
1293 acpi_video_bus_get_one_device(struct acpi_device *device,
1294                               struct acpi_video_bus *video)
1295 {
1296         unsigned long device_id;
1297         int status;
1298         struct acpi_video_device *data;
1299
1300         ACPI_FUNCTION_TRACE("acpi_video_bus_get_one_device");
1301
1302         if (!device || !video)
1303                 return_VALUE(-EINVAL);
1304
1305         status =
1306             acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
1307         if (ACPI_SUCCESS(status)) {
1308
1309                 data = kmalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
1310                 if (!data)
1311                         return_VALUE(-ENOMEM);
1312
1313                 memset(data, 0, sizeof(struct acpi_video_device));
1314
1315                 data->handle = device->handle;
1316                 strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
1317                 strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
1318                 acpi_driver_data(device) = data;
1319
1320                 data->device_id = device_id;
1321                 data->video = video;
1322                 data->dev = device;
1323
1324                 switch (device_id & 0xffff) {
1325                 case 0x0100:
1326                         data->flags.crt = 1;
1327                         break;
1328                 case 0x0400:
1329                         data->flags.lcd = 1;
1330                         break;
1331                 case 0x0200:
1332                         data->flags.tvout = 1;
1333                         break;
1334                 default:
1335                         data->flags.unknown = 1;
1336                         break;
1337                 }
1338
1339                 acpi_video_device_bind(video, data);
1340                 acpi_video_device_find_cap(data);
1341
1342                 status = acpi_install_notify_handler(data->handle,
1343                                                      ACPI_DEVICE_NOTIFY,
1344                                                      acpi_video_device_notify,
1345                                                      data);
1346                 if (ACPI_FAILURE(status)) {
1347                         ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1348                                           "Error installing notify handler\n"));
1349                         if(data->brightness)
1350                                 kfree(data->brightness->levels);
1351                         kfree(data->brightness);
1352                         kfree(data);
1353                         return -ENODEV;
1354                 }
1355
1356                 down(&video->sem);
1357                 list_add_tail(&data->entry, &video->video_device_list);
1358                 up(&video->sem);
1359
1360                 acpi_video_device_add_fs(device);
1361
1362                 return_VALUE(0);
1363         }
1364
1365         return_VALUE(-ENOENT);
1366 }
1367
1368 /*
1369  *  Arg:
1370  *      video   : video bus device 
1371  *
1372  *  Return:
1373  *      none
1374  *  
1375  *  Enumerate the video device list of the video bus, 
1376  *  bind the ids with the corresponding video devices
1377  *  under the video bus.
1378  */
1379
1380 static void acpi_video_device_rebind(struct acpi_video_bus *video)
1381 {
1382         struct list_head *node, *next;
1383         list_for_each_safe(node, next, &video->video_device_list) {
1384                 struct acpi_video_device *dev =
1385                     container_of(node, struct acpi_video_device, entry);
1386                 acpi_video_device_bind(video, dev);
1387         }
1388 }
1389
1390 /*
1391  *  Arg:
1392  *      video   : video bus device 
1393  *      device  : video output device under the video 
1394  *              bus
1395  *
1396  *  Return:
1397  *      none
1398  *  
1399  *  Bind the ids with the corresponding video devices
1400  *  under the video bus.
1401  */
1402
1403 static void
1404 acpi_video_device_bind(struct acpi_video_bus *video,
1405                        struct acpi_video_device *device)
1406 {
1407         int i;
1408         ACPI_FUNCTION_TRACE("acpi_video_device_bind");
1409
1410 #define IDS_VAL(i) video->attached_array[i].value.int_val
1411 #define IDS_BIND(i) video->attached_array[i].bind_info
1412
1413         for (i = 0; IDS_VAL(i) != ACPI_VIDEO_HEAD_INVALID &&
1414              i < video->attached_count; i++) {
1415                 if (device->device_id == (IDS_VAL(i) & 0xffff)) {
1416                         IDS_BIND(i) = device;
1417                         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i));
1418                 }
1419         }
1420 #undef IDS_VAL
1421 #undef IDS_BIND
1422 }
1423
1424 /*
1425  *  Arg:
1426  *      video   : video bus device 
1427  *
1428  *  Return:
1429  *      < 0     : error
1430  *  
1431  *  Call _DOD to enumerate all devices attached to display adapter
1432  *
1433  */
1434
1435 static int acpi_video_device_enumerate(struct acpi_video_bus *video)
1436 {
1437         int status;
1438         int count;
1439         int i;
1440         struct acpi_video_enumerated_device *active_device_list;
1441         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1442         union acpi_object *dod = NULL;
1443         union acpi_object *obj;
1444
1445         ACPI_FUNCTION_TRACE("acpi_video_device_enumerate");
1446
1447         status = acpi_evaluate_object(video->handle, "_DOD", NULL, &buffer);
1448         if (!ACPI_SUCCESS(status)) {
1449                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _DOD\n"));
1450                 return_VALUE(status);
1451         }
1452
1453         dod = (union acpi_object *)buffer.pointer;
1454         if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
1455                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DOD data\n"));
1456                 status = -EFAULT;
1457                 goto out;
1458         }
1459
1460         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
1461                           dod->package.count));
1462
1463         active_device_list = kmalloc((1 +
1464                                       dod->package.count) *
1465                                      sizeof(struct
1466                                             acpi_video_enumerated_device),
1467                                      GFP_KERNEL);
1468
1469         if (!active_device_list) {
1470                 status = -ENOMEM;
1471                 goto out;
1472         }
1473
1474         count = 0;
1475         for (i = 0; i < dod->package.count; i++) {
1476                 obj = (union acpi_object *)&dod->package.elements[i];
1477
1478                 if (obj->type != ACPI_TYPE_INTEGER) {
1479                         ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1480                                           "Invalid _DOD data\n"));
1481                         active_device_list[i].value.int_val =
1482                             ACPI_VIDEO_HEAD_INVALID;
1483                 }
1484                 active_device_list[i].value.int_val = obj->integer.value;
1485                 active_device_list[i].bind_info = NULL;
1486                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i,
1487                                   (int)obj->integer.value));
1488                 count++;
1489         }
1490         active_device_list[count].value.int_val = ACPI_VIDEO_HEAD_END;
1491
1492         kfree(video->attached_array);
1493
1494         video->attached_array = active_device_list;
1495         video->attached_count = count;
1496       out:
1497         acpi_os_free(buffer.pointer);
1498         return_VALUE(status);
1499 }
1500
1501 /*
1502  *  Arg:
1503  *      video   : video bus device 
1504  *      event   : Nontify Event
1505  *
1506  *  Return:
1507  *      < 0     : error
1508  *  
1509  *      1. Find out the current active output device.
1510  *      2. Identify the next output device to switch
1511  *      3. call _DSS to do actual switch.
1512  */
1513
1514 static int acpi_video_switch_output(struct acpi_video_bus *video, int event)
1515 {
1516         struct list_head *node, *next;
1517         struct acpi_video_device *dev = NULL;
1518         struct acpi_video_device *dev_next = NULL;
1519         struct acpi_video_device *dev_prev = NULL;
1520         unsigned long state;
1521         int status = 0;
1522
1523         ACPI_FUNCTION_TRACE("acpi_video_switch_output");
1524
1525         list_for_each_safe(node, next, &video->video_device_list) {
1526                 dev = container_of(node, struct acpi_video_device, entry);
1527                 status = acpi_video_device_get_state(dev, &state);
1528                 if (state & 0x2) {
1529                         dev_next =
1530                             container_of(node->next, struct acpi_video_device,
1531                                          entry);
1532                         dev_prev =
1533                             container_of(node->prev, struct acpi_video_device,
1534                                          entry);
1535                         goto out;
1536                 }
1537         }
1538         dev_next = container_of(node->next, struct acpi_video_device, entry);
1539         dev_prev = container_of(node->prev, struct acpi_video_device, entry);
1540       out:
1541         switch (event) {
1542         case ACPI_VIDEO_NOTIFY_CYCLE:
1543         case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:
1544                 acpi_video_device_set_state(dev, 0);
1545                 acpi_video_device_set_state(dev_next, 0x80000001);
1546                 break;
1547         case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:
1548                 acpi_video_device_set_state(dev, 0);
1549                 acpi_video_device_set_state(dev_prev, 0x80000001);
1550         default:
1551                 break;
1552         }
1553
1554         return_VALUE(status);
1555 }
1556
1557 static int
1558 acpi_video_get_next_level(struct acpi_video_device *device,
1559                           u32 level_current, u32 event)
1560 {
1561         /*Fix me */
1562         return level_current;
1563 }
1564
1565 static void
1566 acpi_video_switch_brightness(struct acpi_video_device *device, int event)
1567 {
1568         unsigned long level_current, level_next;
1569         acpi_video_device_lcd_get_level_current(device, &level_current);
1570         level_next = acpi_video_get_next_level(device, level_current, event);
1571         acpi_video_device_lcd_set_level(device, level_next);
1572 }
1573
1574 static int
1575 acpi_video_bus_get_devices(struct acpi_video_bus *video,
1576                            struct acpi_device *device)
1577 {
1578         int status = 0;
1579         struct list_head *node, *next;
1580
1581         ACPI_FUNCTION_TRACE("acpi_video_get_devices");
1582
1583         acpi_video_device_enumerate(video);
1584
1585         list_for_each_safe(node, next, &device->children) {
1586                 struct acpi_device *dev =
1587                     list_entry(node, struct acpi_device, node);
1588
1589                 if (!dev)
1590                         continue;
1591
1592                 status = acpi_video_bus_get_one_device(dev, video);
1593                 if (ACPI_FAILURE(status)) {
1594                         ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1595                                           "Cant attach device\n"));
1596                         continue;
1597                 }
1598
1599         }
1600         return_VALUE(status);
1601 }
1602
1603 static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
1604 {
1605         acpi_status status;
1606         struct acpi_video_bus *video;
1607
1608         ACPI_FUNCTION_TRACE("acpi_video_bus_put_one_device");
1609
1610         if (!device || !device->video)
1611                 return_VALUE(-ENOENT);
1612
1613         video = device->video;
1614
1615         down(&video->sem);
1616         list_del(&device->entry);
1617         up(&video->sem);
1618         acpi_video_device_remove_fs(device->dev);
1619
1620         status = acpi_remove_notify_handler(device->handle,
1621                                             ACPI_DEVICE_NOTIFY,
1622                                             acpi_video_device_notify);
1623         if (ACPI_FAILURE(status))
1624                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1625                                   "Error removing notify handler\n"));
1626
1627         return_VALUE(0);
1628 }
1629
1630 static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
1631 {
1632         int status;
1633         struct list_head *node, *next;
1634
1635         ACPI_FUNCTION_TRACE("acpi_video_bus_put_devices");
1636
1637         list_for_each_safe(node, next, &video->video_device_list) {
1638                 struct acpi_video_device *data =
1639                     list_entry(node, struct acpi_video_device, entry);
1640                 if (!data)
1641                         continue;
1642
1643                 status = acpi_video_bus_put_one_device(data);
1644                 if (ACPI_FAILURE(status))
1645                         printk(KERN_WARNING PREFIX
1646                                "hhuuhhuu bug in acpi video driver.\n");
1647
1648                 if (data->brightness);
1649                         kfree(data->brightness->levels);
1650                 kfree(data->brightness);
1651                 kfree(data);
1652         }
1653
1654         return_VALUE(0);
1655 }
1656
1657 /* acpi_video interface */
1658
1659 static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
1660 {
1661         return acpi_video_bus_DOS(video, 1, 0);
1662 }
1663
1664 static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
1665 {
1666         return acpi_video_bus_DOS(video, 0, 1);
1667 }
1668
1669 static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
1670 {
1671         struct acpi_video_bus *video = (struct acpi_video_bus *)data;
1672         struct acpi_device *device = NULL;
1673
1674         ACPI_FUNCTION_TRACE("acpi_video_bus_notify");
1675         printk("video bus notify\n");
1676
1677         if (!video)
1678                 return_VOID;
1679
1680         if (acpi_bus_get_device(handle, &device))
1681                 return_VOID;
1682
1683         switch (event) {
1684         case ACPI_VIDEO_NOTIFY_SWITCH:  /* User request that a switch occur,
1685                                          * most likely via hotkey. */
1686                 acpi_bus_generate_event(device, event, 0);
1687                 break;
1688
1689         case ACPI_VIDEO_NOTIFY_PROBE:   /* User plug or remove a video
1690                                          * connector. */
1691                 acpi_video_device_enumerate(video);
1692                 acpi_video_device_rebind(video);
1693                 acpi_video_switch_output(video, event);
1694                 acpi_bus_generate_event(device, event, 0);
1695                 break;
1696
1697         case ACPI_VIDEO_NOTIFY_CYCLE:   /* Cycle Display output hotkey pressed. */
1698         case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:     /* Next Display output hotkey pressed. */
1699         case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:     /* previous Display output hotkey pressed. */
1700                 acpi_video_switch_output(video, event);
1701                 acpi_bus_generate_event(device, event, 0);
1702                 break;
1703
1704         default:
1705                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1706                                   "Unsupported event [0x%x]\n", event));
1707                 break;
1708         }
1709
1710         return_VOID;
1711 }
1712
1713 static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
1714 {
1715         struct acpi_video_device *video_device =
1716             (struct acpi_video_device *)data;
1717         struct acpi_device *device = NULL;
1718
1719         ACPI_FUNCTION_TRACE("acpi_video_device_notify");
1720
1721         printk("video device notify\n");
1722         if (!video_device)
1723                 return_VOID;
1724
1725         if (acpi_bus_get_device(handle, &device))
1726                 return_VOID;
1727
1728         switch (event) {
1729         case ACPI_VIDEO_NOTIFY_SWITCH:  /* change in status (cycle output device) */
1730         case ACPI_VIDEO_NOTIFY_PROBE:   /* change in status (output device status) */
1731                 acpi_bus_generate_event(device, event, 0);
1732                 break;
1733         case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:        /* Cycle brightness */
1734         case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:  /* Increase brightness */
1735         case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:  /* Decrease brightness */
1736         case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
1737         case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:     /* display device off */
1738                 acpi_video_switch_brightness(video_device, event);
1739                 acpi_bus_generate_event(device, event, 0);
1740                 break;
1741         default:
1742                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1743                                   "Unsupported event [0x%x]\n", event));
1744                 break;
1745         }
1746         return_VOID;
1747 }
1748
1749 static int acpi_video_bus_add(struct acpi_device *device)
1750 {
1751         int result = 0;
1752         acpi_status status = 0;
1753         struct acpi_video_bus *video = NULL;
1754
1755         ACPI_FUNCTION_TRACE("acpi_video_bus_add");
1756
1757         if (!device)
1758                 return_VALUE(-EINVAL);
1759
1760         video = kmalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
1761         if (!video)
1762                 return_VALUE(-ENOMEM);
1763         memset(video, 0, sizeof(struct acpi_video_bus));
1764
1765         video->handle = device->handle;
1766         strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
1767         strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
1768         acpi_driver_data(device) = video;
1769
1770         acpi_video_bus_find_cap(video);
1771         result = acpi_video_bus_check(video);
1772         if (result)
1773                 goto end;
1774
1775         result = acpi_video_bus_add_fs(device);
1776         if (result)
1777                 goto end;
1778
1779         init_MUTEX(&video->sem);
1780         INIT_LIST_HEAD(&video->video_device_list);
1781
1782         acpi_video_bus_get_devices(video, device);
1783         acpi_video_bus_start_devices(video);
1784
1785         status = acpi_install_notify_handler(video->handle,
1786                                              ACPI_DEVICE_NOTIFY,
1787                                              acpi_video_bus_notify, video);
1788         if (ACPI_FAILURE(status)) {
1789                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1790                                   "Error installing notify handler\n"));
1791                 acpi_video_bus_stop_devices(video);
1792                 acpi_video_bus_put_devices(video);
1793                 kfree(video->attached_array);
1794                 acpi_video_bus_remove_fs(device);
1795                 result = -ENODEV;
1796                 goto end;
1797         }
1798
1799         printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s  rom: %s  post: %s)\n",
1800                ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
1801                video->flags.multihead ? "yes" : "no",
1802                video->flags.rom ? "yes" : "no",
1803                video->flags.post ? "yes" : "no");
1804
1805       end:
1806         if (result)
1807                 kfree(video);
1808
1809         return_VALUE(result);
1810 }
1811
1812 static int acpi_video_bus_remove(struct acpi_device *device, int type)
1813 {
1814         acpi_status status = 0;
1815         struct acpi_video_bus *video = NULL;
1816
1817         ACPI_FUNCTION_TRACE("acpi_video_bus_remove");
1818
1819         if (!device || !acpi_driver_data(device))
1820                 return_VALUE(-EINVAL);
1821
1822         video = (struct acpi_video_bus *)acpi_driver_data(device);
1823
1824         acpi_video_bus_stop_devices(video);
1825
1826         status = acpi_remove_notify_handler(video->handle,
1827                                             ACPI_DEVICE_NOTIFY,
1828                                             acpi_video_bus_notify);
1829         if (ACPI_FAILURE(status))
1830                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1831                                   "Error removing notify handler\n"));
1832
1833         acpi_video_bus_put_devices(video);
1834         acpi_video_bus_remove_fs(device);
1835
1836         kfree(video->attached_array);
1837         kfree(video);
1838
1839         return_VALUE(0);
1840 }
1841
1842 static int
1843 acpi_video_bus_match(struct acpi_device *device, struct acpi_driver *driver)
1844 {
1845         acpi_handle h_dummy1;
1846         acpi_handle h_dummy2;
1847         acpi_handle h_dummy3;
1848
1849         ACPI_FUNCTION_TRACE("acpi_video_bus_match");
1850
1851         if (!device || !driver)
1852                 return_VALUE(-EINVAL);
1853
1854         /* Since there is no HID, CID for ACPI Video drivers, we have
1855          * to check well known required nodes for each feature we support.
1856          */
1857
1858         /* Does this device able to support video switching ? */
1859         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
1860             ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
1861                 return_VALUE(0);
1862
1863         /* Does this device able to retrieve a video ROM ? */
1864         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
1865                 return_VALUE(0);
1866
1867         /* Does this device able to configure which video head to be POSTed ? */
1868         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
1869             ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
1870             ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
1871                 return_VALUE(0);
1872
1873         return_VALUE(-ENODEV);
1874 }
1875
1876 static int __init acpi_video_init(void)
1877 {
1878         int result = 0;
1879
1880         ACPI_FUNCTION_TRACE("acpi_video_init");
1881
1882         /*
1883            acpi_dbg_level = 0xFFFFFFFF;
1884            acpi_dbg_layer = 0x08000000;
1885          */
1886
1887         acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
1888         if (!acpi_video_dir)
1889                 return_VALUE(-ENODEV);
1890         acpi_video_dir->owner = THIS_MODULE;
1891
1892         result = acpi_bus_register_driver(&acpi_video_bus);
1893         if (result < 0) {
1894                 remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
1895                 return_VALUE(-ENODEV);
1896         }
1897
1898         return_VALUE(0);
1899 }
1900
1901 static void __exit acpi_video_exit(void)
1902 {
1903         ACPI_FUNCTION_TRACE("acpi_video_exit");
1904
1905         acpi_bus_unregister_driver(&acpi_video_bus);
1906
1907         remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
1908
1909         return_VOID;
1910 }
1911
1912 module_init(acpi_video_init);
1913 module_exit(acpi_video_exit);