ca37da537bd676455274f67086260831e2ca313a
[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                 printk(KERN_ERR PREFIX "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                 printk(KERN_ERR PREFIX "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                                         printk(KERN_ERR PREFIX "Invalid data\n");
564                                         continue;
565                                 }
566                                 br->levels[count] = (u32) o->integer.value;
567                                 count++;
568                         }
569                       out:
570                         if (count < 2) {
571                                 kfree(br->levels);
572                                 kfree(br);
573                         } else {
574                                 br->count = count;
575                                 device->brightness = br;
576                                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
577                                                   "found %d brightness levels\n",
578                                                   count));
579                         }
580                 }
581         }
582
583         kfree(obj);
584
585         return_VOID;
586 }
587
588 /*
589  *  Arg:        
590  *      device  : video output device (VGA)
591  *
592  *  Return Value:
593  *      None
594  *
595  *  Find out all required AML method defined under the video bus device.
596  */
597
598 static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
599 {
600         acpi_handle h_dummy1;
601
602         memset(&video->cap, 0, 4);
603         if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_DOS", &h_dummy1))) {
604                 video->cap._DOS = 1;
605         }
606         if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_DOD", &h_dummy1))) {
607                 video->cap._DOD = 1;
608         }
609         if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_ROM", &h_dummy1))) {
610                 video->cap._ROM = 1;
611         }
612         if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_GPD", &h_dummy1))) {
613                 video->cap._GPD = 1;
614         }
615         if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_SPD", &h_dummy1))) {
616                 video->cap._SPD = 1;
617         }
618         if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_VPO", &h_dummy1))) {
619                 video->cap._VPO = 1;
620         }
621 }
622
623 /*
624  * Check whether the video bus device has required AML method to
625  * support the desired features
626  */
627
628 static int acpi_video_bus_check(struct acpi_video_bus *video)
629 {
630         acpi_status status = -ENOENT;
631
632         ACPI_FUNCTION_TRACE("acpi_video_bus_check");
633
634         if (!video)
635                 return_VALUE(-EINVAL);
636
637         /* Since there is no HID, CID and so on for VGA driver, we have
638          * to check well known required nodes.
639          */
640
641         /* Does this device able to support video switching ? */
642         if (video->cap._DOS) {
643                 video->flags.multihead = 1;
644                 status = 0;
645         }
646
647         /* Does this device able to retrieve a retrieve a video ROM ? */
648         if (video->cap._ROM) {
649                 video->flags.rom = 1;
650                 status = 0;
651         }
652
653         /* Does this device able to configure which video device to POST ? */
654         if (video->cap._GPD && video->cap._SPD && video->cap._VPO) {
655                 video->flags.post = 1;
656                 status = 0;
657         }
658
659         return_VALUE(status);
660 }
661
662 /* --------------------------------------------------------------------------
663                               FS Interface (/proc)
664    -------------------------------------------------------------------------- */
665
666 static struct proc_dir_entry *acpi_video_dir;
667
668 /* video devices */
669
670 static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
671 {
672         struct acpi_video_device *dev =
673             (struct acpi_video_device *)seq->private;
674
675         ACPI_FUNCTION_TRACE("acpi_video_device_info_seq_show");
676
677         if (!dev)
678                 goto end;
679
680         seq_printf(seq, "device_id:    0x%04x\n", (u32) dev->device_id);
681         seq_printf(seq, "type:         ");
682         if (dev->flags.crt)
683                 seq_printf(seq, "CRT\n");
684         else if (dev->flags.lcd)
685                 seq_printf(seq, "LCD\n");
686         else if (dev->flags.tvout)
687                 seq_printf(seq, "TVOUT\n");
688         else
689                 seq_printf(seq, "UNKNOWN\n");
690
691         seq_printf(seq, "known by bios: %s\n", dev->flags.bios ? "yes" : "no");
692
693       end:
694         return_VALUE(0);
695 }
696
697 static int
698 acpi_video_device_info_open_fs(struct inode *inode, struct file *file)
699 {
700         return single_open(file, acpi_video_device_info_seq_show,
701                            PDE(inode)->data);
702 }
703
704 static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
705 {
706         int status;
707         struct acpi_video_device *dev =
708             (struct acpi_video_device *)seq->private;
709         unsigned long state;
710
711         ACPI_FUNCTION_TRACE("acpi_video_device_state_seq_show");
712
713         if (!dev)
714                 goto end;
715
716         status = acpi_video_device_get_state(dev, &state);
717         seq_printf(seq, "state:     ");
718         if (ACPI_SUCCESS(status))
719                 seq_printf(seq, "0x%02lx\n", state);
720         else
721                 seq_printf(seq, "<not supported>\n");
722
723         status = acpi_video_device_query(dev, &state);
724         seq_printf(seq, "query:     ");
725         if (ACPI_SUCCESS(status))
726                 seq_printf(seq, "0x%02lx\n", state);
727         else
728                 seq_printf(seq, "<not supported>\n");
729
730       end:
731         return_VALUE(0);
732 }
733
734 static int
735 acpi_video_device_state_open_fs(struct inode *inode, struct file *file)
736 {
737         return single_open(file, acpi_video_device_state_seq_show,
738                            PDE(inode)->data);
739 }
740
741 static ssize_t
742 acpi_video_device_write_state(struct file *file,
743                               const char __user * buffer,
744                               size_t count, loff_t * data)
745 {
746         int status;
747         struct seq_file *m = (struct seq_file *)file->private_data;
748         struct acpi_video_device *dev = (struct acpi_video_device *)m->private;
749         char str[12] = { 0 };
750         u32 state = 0;
751
752         ACPI_FUNCTION_TRACE("acpi_video_device_write_state");
753
754         if (!dev || count + 1 > sizeof str)
755                 return_VALUE(-EINVAL);
756
757         if (copy_from_user(str, buffer, count))
758                 return_VALUE(-EFAULT);
759
760         str[count] = 0;
761         state = simple_strtoul(str, NULL, 0);
762         state &= ((1ul << 31) | (1ul << 30) | (1ul << 0));
763
764         status = acpi_video_device_set_state(dev, state);
765
766         if (status)
767                 return_VALUE(-EFAULT);
768
769         return_VALUE(count);
770 }
771
772 static int
773 acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset)
774 {
775         struct acpi_video_device *dev =
776             (struct acpi_video_device *)seq->private;
777         int i;
778
779         ACPI_FUNCTION_TRACE("acpi_video_device_brightness_seq_show");
780
781         if (!dev || !dev->brightness) {
782                 seq_printf(seq, "<not supported>\n");
783                 return_VALUE(0);
784         }
785
786         seq_printf(seq, "levels: ");
787         for (i = 0; i < dev->brightness->count; i++)
788                 seq_printf(seq, " %d", dev->brightness->levels[i]);
789         seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr);
790
791         return_VALUE(0);
792 }
793
794 static int
795 acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file)
796 {
797         return single_open(file, acpi_video_device_brightness_seq_show,
798                            PDE(inode)->data);
799 }
800
801 static ssize_t
802 acpi_video_device_write_brightness(struct file *file,
803                                    const char __user * buffer,
804                                    size_t count, loff_t * data)
805 {
806         struct seq_file *m = (struct seq_file *)file->private_data;
807         struct acpi_video_device *dev = (struct acpi_video_device *)m->private;
808         char str[4] = { 0 };
809         unsigned int level = 0;
810         int i;
811
812         ACPI_FUNCTION_TRACE("acpi_video_device_write_brightness");
813
814         if (!dev || !dev->brightness || count + 1 > sizeof str)
815                 return_VALUE(-EINVAL);
816
817         if (copy_from_user(str, buffer, count))
818                 return_VALUE(-EFAULT);
819
820         str[count] = 0;
821         level = simple_strtoul(str, NULL, 0);
822
823         if (level > 100)
824                 return_VALUE(-EFAULT);
825
826         /* validate though the list of available levels */
827         for (i = 0; i < dev->brightness->count; i++)
828                 if (level == dev->brightness->levels[i]) {
829                         if (ACPI_SUCCESS
830                             (acpi_video_device_lcd_set_level(dev, level)))
831                                 dev->brightness->curr = level;
832                         break;
833                 }
834
835         return_VALUE(count);
836 }
837
838 static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset)
839 {
840         struct acpi_video_device *dev =
841             (struct acpi_video_device *)seq->private;
842         int status;
843         int i;
844         union acpi_object *edid = NULL;
845
846         ACPI_FUNCTION_TRACE("acpi_video_device_EDID_seq_show");
847
848         if (!dev)
849                 goto out;
850
851         status = acpi_video_device_EDID(dev, &edid, 128);
852         if (ACPI_FAILURE(status)) {
853                 status = acpi_video_device_EDID(dev, &edid, 256);
854         }
855
856         if (ACPI_FAILURE(status)) {
857                 goto out;
858         }
859
860         if (edid && edid->type == ACPI_TYPE_BUFFER) {
861                 for (i = 0; i < edid->buffer.length; i++)
862                         seq_putc(seq, edid->buffer.pointer[i]);
863         }
864
865       out:
866         if (!edid)
867                 seq_printf(seq, "<not supported>\n");
868         else
869                 kfree(edid);
870
871         return_VALUE(0);
872 }
873
874 static int
875 acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file)
876 {
877         return single_open(file, acpi_video_device_EDID_seq_show,
878                            PDE(inode)->data);
879 }
880
881 static int acpi_video_device_add_fs(struct acpi_device *device)
882 {
883         struct proc_dir_entry *entry = NULL;
884         struct acpi_video_device *vid_dev;
885
886         ACPI_FUNCTION_TRACE("acpi_video_device_add_fs");
887
888         if (!device)
889                 return_VALUE(-ENODEV);
890
891         vid_dev = (struct acpi_video_device *)acpi_driver_data(device);
892         if (!vid_dev)
893                 return_VALUE(-ENODEV);
894
895         if (!acpi_device_dir(device)) {
896                 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
897                                                      vid_dev->video->dir);
898                 if (!acpi_device_dir(device))
899                         return_VALUE(-ENODEV);
900                 acpi_device_dir(device)->owner = THIS_MODULE;
901         }
902
903         /* 'info' [R] */
904         entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
905         if (!entry)
906                 return_VALUE(-ENODEV);
907         else {
908                 entry->proc_fops = &acpi_video_device_info_fops;
909                 entry->data = acpi_driver_data(device);
910                 entry->owner = THIS_MODULE;
911         }
912
913         /* 'state' [R/W] */
914         entry =
915             create_proc_entry("state", S_IFREG | S_IRUGO | S_IWUSR,
916                               acpi_device_dir(device));
917         if (!entry)
918                 return_VALUE(-ENODEV);
919         else {
920                 acpi_video_device_state_fops.write = acpi_video_device_write_state;
921                 entry->proc_fops = &acpi_video_device_state_fops;
922                 entry->data = acpi_driver_data(device);
923                 entry->owner = THIS_MODULE;
924         }
925
926         /* 'brightness' [R/W] */
927         entry =
928             create_proc_entry("brightness", S_IFREG | S_IRUGO | S_IWUSR,
929                               acpi_device_dir(device));
930         if (!entry)
931                 return_VALUE(-ENODEV);
932         else {
933                 acpi_video_device_brightness_fops.write = acpi_video_device_write_brightness;
934                 entry->proc_fops = &acpi_video_device_brightness_fops;
935                 entry->data = acpi_driver_data(device);
936                 entry->owner = THIS_MODULE;
937         }
938
939         /* 'EDID' [R] */
940         entry = create_proc_entry("EDID", S_IRUGO, acpi_device_dir(device));
941         if (!entry)
942                 return_VALUE(-ENODEV);
943         else {
944                 entry->proc_fops = &acpi_video_device_EDID_fops;
945                 entry->data = acpi_driver_data(device);
946                 entry->owner = THIS_MODULE;
947         }
948
949         return_VALUE(0);
950 }
951
952 static int acpi_video_device_remove_fs(struct acpi_device *device)
953 {
954         struct acpi_video_device *vid_dev;
955         ACPI_FUNCTION_TRACE("acpi_video_device_remove_fs");
956
957         vid_dev = (struct acpi_video_device *)acpi_driver_data(device);
958         if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
959                 return_VALUE(-ENODEV);
960
961         if (acpi_device_dir(device)) {
962                 remove_proc_entry("info", acpi_device_dir(device));
963                 remove_proc_entry("state", acpi_device_dir(device));
964                 remove_proc_entry("brightness", acpi_device_dir(device));
965                 remove_proc_entry("EDID", acpi_device_dir(device));
966                 remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
967                 acpi_device_dir(device) = NULL;
968         }
969
970         return_VALUE(0);
971 }
972
973 /* video bus */
974 static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset)
975 {
976         struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
977
978         ACPI_FUNCTION_TRACE("acpi_video_bus_info_seq_show");
979
980         if (!video)
981                 goto end;
982
983         seq_printf(seq, "Switching heads:              %s\n",
984                    video->flags.multihead ? "yes" : "no");
985         seq_printf(seq, "Video ROM:                    %s\n",
986                    video->flags.rom ? "yes" : "no");
987         seq_printf(seq, "Device to be POSTed on boot:  %s\n",
988                    video->flags.post ? "yes" : "no");
989
990       end:
991         return_VALUE(0);
992 }
993
994 static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file)
995 {
996         return single_open(file, acpi_video_bus_info_seq_show,
997                            PDE(inode)->data);
998 }
999
1000 static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset)
1001 {
1002         struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
1003
1004         ACPI_FUNCTION_TRACE("acpi_video_bus_ROM_seq_show");
1005
1006         if (!video)
1007                 goto end;
1008
1009         printk(KERN_INFO PREFIX "Please implement %s\n", __FUNCTION__);
1010         seq_printf(seq, "<TODO>\n");
1011
1012       end:
1013         return_VALUE(0);
1014 }
1015
1016 static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file)
1017 {
1018         return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data);
1019 }
1020
1021 static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
1022 {
1023         struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
1024         unsigned long options;
1025         int status;
1026
1027         ACPI_FUNCTION_TRACE("acpi_video_bus_POST_info_seq_show");
1028
1029         if (!video)
1030                 goto end;
1031
1032         status = acpi_video_bus_POST_options(video, &options);
1033         if (ACPI_SUCCESS(status)) {
1034                 if (!(options & 1)) {
1035                         printk(KERN_WARNING PREFIX
1036                                "The motherboard VGA device is not listed as a possible POST device.\n");
1037                         printk(KERN_WARNING PREFIX
1038                                "This indicate a BIOS bug.  Please contact the manufacturer.\n");
1039                 }
1040                 printk("%lx\n", options);
1041                 seq_printf(seq, "can POST: <intgrated video>");
1042                 if (options & 2)
1043                         seq_printf(seq, " <PCI video>");
1044                 if (options & 4)
1045                         seq_printf(seq, " <AGP video>");
1046                 seq_putc(seq, '\n');
1047         } else
1048                 seq_printf(seq, "<not supported>\n");
1049       end:
1050         return_VALUE(0);
1051 }
1052
1053 static int
1054 acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file)
1055 {
1056         return single_open(file, acpi_video_bus_POST_info_seq_show,
1057                            PDE(inode)->data);
1058 }
1059
1060 static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
1061 {
1062         struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
1063         int status;
1064         unsigned long id;
1065
1066         ACPI_FUNCTION_TRACE("acpi_video_bus_POST_seq_show");
1067
1068         if (!video)
1069                 goto end;
1070
1071         status = acpi_video_bus_get_POST(video, &id);
1072         if (!ACPI_SUCCESS(status)) {
1073                 seq_printf(seq, "<not supported>\n");
1074                 goto end;
1075         }
1076         seq_printf(seq, "device posted is <%s>\n", device_decode[id & 3]);
1077
1078       end:
1079         return_VALUE(0);
1080 }
1081
1082 static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset)
1083 {
1084         struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
1085
1086         ACPI_FUNCTION_TRACE("acpi_video_bus_DOS_seq_show");
1087
1088         seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting);
1089
1090         return_VALUE(0);
1091 }
1092
1093 static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file)
1094 {
1095         return single_open(file, acpi_video_bus_POST_seq_show,
1096                            PDE(inode)->data);
1097 }
1098
1099 static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file)
1100 {
1101         return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data);
1102 }
1103
1104 static ssize_t
1105 acpi_video_bus_write_POST(struct file *file,
1106                           const char __user * buffer,
1107                           size_t count, loff_t * data)
1108 {
1109         int status;
1110         struct seq_file *m = (struct seq_file *)file->private_data;
1111         struct acpi_video_bus *video = (struct acpi_video_bus *)m->private;
1112         char str[12] = { 0 };
1113         unsigned long opt, options;
1114
1115         ACPI_FUNCTION_TRACE("acpi_video_bus_write_POST");
1116
1117         if (!video || count + 1 > sizeof str)
1118                 return_VALUE(-EINVAL);
1119
1120         status = acpi_video_bus_POST_options(video, &options);
1121         if (!ACPI_SUCCESS(status))
1122                 return_VALUE(-EINVAL);
1123
1124         if (copy_from_user(str, buffer, count))
1125                 return_VALUE(-EFAULT);
1126
1127         str[count] = 0;
1128         opt = strtoul(str, NULL, 0);
1129         if (opt > 3)
1130                 return_VALUE(-EFAULT);
1131
1132         /* just in case an OEM 'forget' the motherboard... */
1133         options |= 1;
1134
1135         if (options & (1ul << opt)) {
1136                 status = acpi_video_bus_set_POST(video, opt);
1137                 if (!ACPI_SUCCESS(status))
1138                         return_VALUE(-EFAULT);
1139
1140         }
1141
1142         return_VALUE(count);
1143 }
1144
1145 static ssize_t
1146 acpi_video_bus_write_DOS(struct file *file,
1147                          const char __user * buffer,
1148                          size_t count, loff_t * data)
1149 {
1150         int status;
1151         struct seq_file *m = (struct seq_file *)file->private_data;
1152         struct acpi_video_bus *video = (struct acpi_video_bus *)m->private;
1153         char str[12] = { 0 };
1154         unsigned long opt;
1155
1156         ACPI_FUNCTION_TRACE("acpi_video_bus_write_DOS");
1157
1158         if (!video || count + 1 > sizeof str)
1159                 return_VALUE(-EINVAL);
1160
1161         if (copy_from_user(str, buffer, count))
1162                 return_VALUE(-EFAULT);
1163
1164         str[count] = 0;
1165         opt = strtoul(str, NULL, 0);
1166         if (opt > 7)
1167                 return_VALUE(-EFAULT);
1168
1169         status = acpi_video_bus_DOS(video, opt & 0x3, (opt & 0x4) >> 2);
1170
1171         if (!ACPI_SUCCESS(status))
1172                 return_VALUE(-EFAULT);
1173
1174         return_VALUE(count);
1175 }
1176
1177 static int acpi_video_bus_add_fs(struct acpi_device *device)
1178 {
1179         struct proc_dir_entry *entry = NULL;
1180         struct acpi_video_bus *video;
1181
1182         ACPI_FUNCTION_TRACE("acpi_video_bus_add_fs");
1183
1184         video = (struct acpi_video_bus *)acpi_driver_data(device);
1185
1186         if (!acpi_device_dir(device)) {
1187                 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
1188                                                      acpi_video_dir);
1189                 if (!acpi_device_dir(device))
1190                         return_VALUE(-ENODEV);
1191                 video->dir = acpi_device_dir(device);
1192                 acpi_device_dir(device)->owner = THIS_MODULE;
1193         }
1194
1195         /* 'info' [R] */
1196         entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
1197         if (!entry)
1198                 return_VALUE(-ENODEV);
1199         else {
1200                 entry->proc_fops = &acpi_video_bus_info_fops;
1201                 entry->data = acpi_driver_data(device);
1202                 entry->owner = THIS_MODULE;
1203         }
1204
1205         /* 'ROM' [R] */
1206         entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device));
1207         if (!entry)
1208                 return_VALUE(-ENODEV);
1209         else {
1210                 entry->proc_fops = &acpi_video_bus_ROM_fops;
1211                 entry->data = acpi_driver_data(device);
1212                 entry->owner = THIS_MODULE;
1213         }
1214
1215         /* 'POST_info' [R] */
1216         entry =
1217             create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device));
1218         if (!entry)
1219                 return_VALUE(-ENODEV);
1220         else {
1221                 entry->proc_fops = &acpi_video_bus_POST_info_fops;
1222                 entry->data = acpi_driver_data(device);
1223                 entry->owner = THIS_MODULE;
1224         }
1225
1226         /* 'POST' [R/W] */
1227         entry =
1228             create_proc_entry("POST", S_IFREG | S_IRUGO | S_IRUSR,
1229                               acpi_device_dir(device));
1230         if (!entry)
1231                 return_VALUE(-ENODEV);
1232         else {
1233                 acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST;
1234                 entry->proc_fops = &acpi_video_bus_POST_fops;
1235                 entry->data = acpi_driver_data(device);
1236                 entry->owner = THIS_MODULE;
1237         }
1238
1239         /* 'DOS' [R/W] */
1240         entry =
1241             create_proc_entry("DOS", S_IFREG | S_IRUGO | S_IRUSR,
1242                               acpi_device_dir(device));
1243         if (!entry)
1244                 return_VALUE(-ENODEV);
1245         else {
1246                 acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS;
1247                 entry->proc_fops = &acpi_video_bus_DOS_fops;
1248                 entry->data = acpi_driver_data(device);
1249                 entry->owner = THIS_MODULE;
1250         }
1251
1252         return_VALUE(0);
1253 }
1254
1255 static int acpi_video_bus_remove_fs(struct acpi_device *device)
1256 {
1257         struct acpi_video_bus *video;
1258
1259         ACPI_FUNCTION_TRACE("acpi_video_bus_remove_fs");
1260
1261         video = (struct acpi_video_bus *)acpi_driver_data(device);
1262
1263         if (acpi_device_dir(device)) {
1264                 remove_proc_entry("info", acpi_device_dir(device));
1265                 remove_proc_entry("ROM", acpi_device_dir(device));
1266                 remove_proc_entry("POST_info", acpi_device_dir(device));
1267                 remove_proc_entry("POST", acpi_device_dir(device));
1268                 remove_proc_entry("DOS", acpi_device_dir(device));
1269                 remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
1270                 acpi_device_dir(device) = NULL;
1271         }
1272
1273         return_VALUE(0);
1274 }
1275
1276 /* --------------------------------------------------------------------------
1277                                  Driver Interface
1278    -------------------------------------------------------------------------- */
1279
1280 /* device interface */
1281
1282 static int
1283 acpi_video_bus_get_one_device(struct acpi_device *device,
1284                               struct acpi_video_bus *video)
1285 {
1286         unsigned long device_id;
1287         int status;
1288         struct acpi_video_device *data;
1289
1290         ACPI_FUNCTION_TRACE("acpi_video_bus_get_one_device");
1291
1292         if (!device || !video)
1293                 return_VALUE(-EINVAL);
1294
1295         status =
1296             acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
1297         if (ACPI_SUCCESS(status)) {
1298
1299                 data = kmalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
1300                 if (!data)
1301                         return_VALUE(-ENOMEM);
1302
1303                 memset(data, 0, sizeof(struct acpi_video_device));
1304
1305                 data->handle = device->handle;
1306                 strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
1307                 strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
1308                 acpi_driver_data(device) = data;
1309
1310                 data->device_id = device_id;
1311                 data->video = video;
1312                 data->dev = device;
1313
1314                 switch (device_id & 0xffff) {
1315                 case 0x0100:
1316                         data->flags.crt = 1;
1317                         break;
1318                 case 0x0400:
1319                         data->flags.lcd = 1;
1320                         break;
1321                 case 0x0200:
1322                         data->flags.tvout = 1;
1323                         break;
1324                 default:
1325                         data->flags.unknown = 1;
1326                         break;
1327                 }
1328
1329                 acpi_video_device_bind(video, data);
1330                 acpi_video_device_find_cap(data);
1331
1332                 status = acpi_install_notify_handler(data->handle,
1333                                                      ACPI_DEVICE_NOTIFY,
1334                                                      acpi_video_device_notify,
1335                                                      data);
1336                 if (ACPI_FAILURE(status)) {
1337                         ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1338                                           "Error installing notify handler\n"));
1339                         if(data->brightness)
1340                                 kfree(data->brightness->levels);
1341                         kfree(data->brightness);
1342                         kfree(data);
1343                         return -ENODEV;
1344                 }
1345
1346                 down(&video->sem);
1347                 list_add_tail(&data->entry, &video->video_device_list);
1348                 up(&video->sem);
1349
1350                 acpi_video_device_add_fs(device);
1351
1352                 return_VALUE(0);
1353         }
1354
1355         return_VALUE(-ENOENT);
1356 }
1357
1358 /*
1359  *  Arg:
1360  *      video   : video bus device 
1361  *
1362  *  Return:
1363  *      none
1364  *  
1365  *  Enumerate the video device list of the video bus, 
1366  *  bind the ids with the corresponding video devices
1367  *  under the video bus.
1368  */
1369
1370 static void acpi_video_device_rebind(struct acpi_video_bus *video)
1371 {
1372         struct list_head *node, *next;
1373         list_for_each_safe(node, next, &video->video_device_list) {
1374                 struct acpi_video_device *dev =
1375                     container_of(node, struct acpi_video_device, entry);
1376                 acpi_video_device_bind(video, dev);
1377         }
1378 }
1379
1380 /*
1381  *  Arg:
1382  *      video   : video bus device 
1383  *      device  : video output device under the video 
1384  *              bus
1385  *
1386  *  Return:
1387  *      none
1388  *  
1389  *  Bind the ids with the corresponding video devices
1390  *  under the video bus.
1391  */
1392
1393 static void
1394 acpi_video_device_bind(struct acpi_video_bus *video,
1395                        struct acpi_video_device *device)
1396 {
1397         int i;
1398         ACPI_FUNCTION_TRACE("acpi_video_device_bind");
1399
1400 #define IDS_VAL(i) video->attached_array[i].value.int_val
1401 #define IDS_BIND(i) video->attached_array[i].bind_info
1402
1403         for (i = 0; IDS_VAL(i) != ACPI_VIDEO_HEAD_INVALID &&
1404              i < video->attached_count; i++) {
1405                 if (device->device_id == (IDS_VAL(i) & 0xffff)) {
1406                         IDS_BIND(i) = device;
1407                         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i));
1408                 }
1409         }
1410 #undef IDS_VAL
1411 #undef IDS_BIND
1412 }
1413
1414 /*
1415  *  Arg:
1416  *      video   : video bus device 
1417  *
1418  *  Return:
1419  *      < 0     : error
1420  *  
1421  *  Call _DOD to enumerate all devices attached to display adapter
1422  *
1423  */
1424
1425 static int acpi_video_device_enumerate(struct acpi_video_bus *video)
1426 {
1427         int status;
1428         int count;
1429         int i;
1430         struct acpi_video_enumerated_device *active_device_list;
1431         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1432         union acpi_object *dod = NULL;
1433         union acpi_object *obj;
1434
1435         ACPI_FUNCTION_TRACE("acpi_video_device_enumerate");
1436
1437         status = acpi_evaluate_object(video->handle, "_DOD", NULL, &buffer);
1438         if (!ACPI_SUCCESS(status)) {
1439                 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD"));
1440                 return_VALUE(status);
1441         }
1442
1443         dod = (union acpi_object *)buffer.pointer;
1444         if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
1445                 ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data"));
1446                 status = -EFAULT;
1447                 goto out;
1448         }
1449
1450         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
1451                           dod->package.count));
1452
1453         active_device_list = kmalloc((1 +
1454                                       dod->package.count) *
1455                                      sizeof(struct
1456                                             acpi_video_enumerated_device),
1457                                      GFP_KERNEL);
1458
1459         if (!active_device_list) {
1460                 status = -ENOMEM;
1461                 goto out;
1462         }
1463
1464         count = 0;
1465         for (i = 0; i < dod->package.count; i++) {
1466                 obj = (union acpi_object *)&dod->package.elements[i];
1467
1468                 if (obj->type != ACPI_TYPE_INTEGER) {
1469                         printk(KERN_ERR PREFIX "Invalid _DOD data\n");
1470                         active_device_list[i].value.int_val =
1471                             ACPI_VIDEO_HEAD_INVALID;
1472                 }
1473                 active_device_list[i].value.int_val = obj->integer.value;
1474                 active_device_list[i].bind_info = NULL;
1475                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i,
1476                                   (int)obj->integer.value));
1477                 count++;
1478         }
1479         active_device_list[count].value.int_val = ACPI_VIDEO_HEAD_END;
1480
1481         kfree(video->attached_array);
1482
1483         video->attached_array = active_device_list;
1484         video->attached_count = count;
1485       out:
1486         acpi_os_free(buffer.pointer);
1487         return_VALUE(status);
1488 }
1489
1490 /*
1491  *  Arg:
1492  *      video   : video bus device 
1493  *      event   : Nontify Event
1494  *
1495  *  Return:
1496  *      < 0     : error
1497  *  
1498  *      1. Find out the current active output device.
1499  *      2. Identify the next output device to switch
1500  *      3. call _DSS to do actual switch.
1501  */
1502
1503 static int acpi_video_switch_output(struct acpi_video_bus *video, int event)
1504 {
1505         struct list_head *node, *next;
1506         struct acpi_video_device *dev = NULL;
1507         struct acpi_video_device *dev_next = NULL;
1508         struct acpi_video_device *dev_prev = NULL;
1509         unsigned long state;
1510         int status = 0;
1511
1512         ACPI_FUNCTION_TRACE("acpi_video_switch_output");
1513
1514         list_for_each_safe(node, next, &video->video_device_list) {
1515                 dev = container_of(node, struct acpi_video_device, entry);
1516                 status = acpi_video_device_get_state(dev, &state);
1517                 if (state & 0x2) {
1518                         dev_next =
1519                             container_of(node->next, struct acpi_video_device,
1520                                          entry);
1521                         dev_prev =
1522                             container_of(node->prev, struct acpi_video_device,
1523                                          entry);
1524                         goto out;
1525                 }
1526         }
1527         dev_next = container_of(node->next, struct acpi_video_device, entry);
1528         dev_prev = container_of(node->prev, struct acpi_video_device, entry);
1529       out:
1530         switch (event) {
1531         case ACPI_VIDEO_NOTIFY_CYCLE:
1532         case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:
1533                 acpi_video_device_set_state(dev, 0);
1534                 acpi_video_device_set_state(dev_next, 0x80000001);
1535                 break;
1536         case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:
1537                 acpi_video_device_set_state(dev, 0);
1538                 acpi_video_device_set_state(dev_prev, 0x80000001);
1539         default:
1540                 break;
1541         }
1542
1543         return_VALUE(status);
1544 }
1545
1546 static int
1547 acpi_video_get_next_level(struct acpi_video_device *device,
1548                           u32 level_current, u32 event)
1549 {
1550         /*Fix me */
1551         return level_current;
1552 }
1553
1554 static void
1555 acpi_video_switch_brightness(struct acpi_video_device *device, int event)
1556 {
1557         unsigned long level_current, level_next;
1558         acpi_video_device_lcd_get_level_current(device, &level_current);
1559         level_next = acpi_video_get_next_level(device, level_current, event);
1560         acpi_video_device_lcd_set_level(device, level_next);
1561 }
1562
1563 static int
1564 acpi_video_bus_get_devices(struct acpi_video_bus *video,
1565                            struct acpi_device *device)
1566 {
1567         int status = 0;
1568         struct list_head *node, *next;
1569
1570         ACPI_FUNCTION_TRACE("acpi_video_get_devices");
1571
1572         acpi_video_device_enumerate(video);
1573
1574         list_for_each_safe(node, next, &device->children) {
1575                 struct acpi_device *dev =
1576                     list_entry(node, struct acpi_device, node);
1577
1578                 if (!dev)
1579                         continue;
1580
1581                 status = acpi_video_bus_get_one_device(dev, video);
1582                 if (ACPI_FAILURE(status)) {
1583                         ACPI_EXCEPTION((AE_INFO, status, "Cant attach device"));
1584                         continue;
1585                 }
1586
1587         }
1588         return_VALUE(status);
1589 }
1590
1591 static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
1592 {
1593         acpi_status status;
1594         struct acpi_video_bus *video;
1595
1596         ACPI_FUNCTION_TRACE("acpi_video_bus_put_one_device");
1597
1598         if (!device || !device->video)
1599                 return_VALUE(-ENOENT);
1600
1601         video = device->video;
1602
1603         down(&video->sem);
1604         list_del(&device->entry);
1605         up(&video->sem);
1606         acpi_video_device_remove_fs(device->dev);
1607
1608         status = acpi_remove_notify_handler(device->handle,
1609                                             ACPI_DEVICE_NOTIFY,
1610                                             acpi_video_device_notify);
1611
1612         return_VALUE(0);
1613 }
1614
1615 static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
1616 {
1617         int status;
1618         struct list_head *node, *next;
1619
1620         ACPI_FUNCTION_TRACE("acpi_video_bus_put_devices");
1621
1622         list_for_each_safe(node, next, &video->video_device_list) {
1623                 struct acpi_video_device *data =
1624                     list_entry(node, struct acpi_video_device, entry);
1625                 if (!data)
1626                         continue;
1627
1628                 status = acpi_video_bus_put_one_device(data);
1629                 if (ACPI_FAILURE(status))
1630                         printk(KERN_WARNING PREFIX
1631                                "hhuuhhuu bug in acpi video driver.\n");
1632
1633                 if (data->brightness)
1634                         kfree(data->brightness->levels);
1635                 kfree(data->brightness);
1636                 kfree(data);
1637         }
1638
1639         return_VALUE(0);
1640 }
1641
1642 /* acpi_video interface */
1643
1644 static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
1645 {
1646         return acpi_video_bus_DOS(video, 1, 0);
1647 }
1648
1649 static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
1650 {
1651         return acpi_video_bus_DOS(video, 0, 1);
1652 }
1653
1654 static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
1655 {
1656         struct acpi_video_bus *video = (struct acpi_video_bus *)data;
1657         struct acpi_device *device = NULL;
1658
1659         ACPI_FUNCTION_TRACE("acpi_video_bus_notify");
1660         printk("video bus notify\n");
1661
1662         if (!video)
1663                 return_VOID;
1664
1665         if (acpi_bus_get_device(handle, &device))
1666                 return_VOID;
1667
1668         switch (event) {
1669         case ACPI_VIDEO_NOTIFY_SWITCH:  /* User request that a switch occur,
1670                                          * most likely via hotkey. */
1671                 acpi_bus_generate_event(device, event, 0);
1672                 break;
1673
1674         case ACPI_VIDEO_NOTIFY_PROBE:   /* User plug or remove a video
1675                                          * connector. */
1676                 acpi_video_device_enumerate(video);
1677                 acpi_video_device_rebind(video);
1678                 acpi_video_switch_output(video, event);
1679                 acpi_bus_generate_event(device, event, 0);
1680                 break;
1681
1682         case ACPI_VIDEO_NOTIFY_CYCLE:   /* Cycle Display output hotkey pressed. */
1683         case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:     /* Next Display output hotkey pressed. */
1684         case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:     /* previous Display output hotkey pressed. */
1685                 acpi_video_switch_output(video, event);
1686                 acpi_bus_generate_event(device, event, 0);
1687                 break;
1688
1689         default:
1690                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1691                                   "Unsupported event [0x%x]\n", event));
1692                 break;
1693         }
1694
1695         return_VOID;
1696 }
1697
1698 static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
1699 {
1700         struct acpi_video_device *video_device =
1701             (struct acpi_video_device *)data;
1702         struct acpi_device *device = NULL;
1703
1704         ACPI_FUNCTION_TRACE("acpi_video_device_notify");
1705
1706         printk("video device notify\n");
1707         if (!video_device)
1708                 return_VOID;
1709
1710         if (acpi_bus_get_device(handle, &device))
1711                 return_VOID;
1712
1713         switch (event) {
1714         case ACPI_VIDEO_NOTIFY_SWITCH:  /* change in status (cycle output device) */
1715         case ACPI_VIDEO_NOTIFY_PROBE:   /* change in status (output device status) */
1716                 acpi_bus_generate_event(device, event, 0);
1717                 break;
1718         case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:        /* Cycle brightness */
1719         case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:  /* Increase brightness */
1720         case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:  /* Decrease brightness */
1721         case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
1722         case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:     /* display device off */
1723                 acpi_video_switch_brightness(video_device, event);
1724                 acpi_bus_generate_event(device, event, 0);
1725                 break;
1726         default:
1727                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1728                                   "Unsupported event [0x%x]\n", event));
1729                 break;
1730         }
1731         return_VOID;
1732 }
1733
1734 static int acpi_video_bus_add(struct acpi_device *device)
1735 {
1736         int result = 0;
1737         acpi_status status = 0;
1738         struct acpi_video_bus *video = NULL;
1739
1740         ACPI_FUNCTION_TRACE("acpi_video_bus_add");
1741
1742         if (!device)
1743                 return_VALUE(-EINVAL);
1744
1745         video = kmalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
1746         if (!video)
1747                 return_VALUE(-ENOMEM);
1748         memset(video, 0, sizeof(struct acpi_video_bus));
1749
1750         video->handle = device->handle;
1751         strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
1752         strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
1753         acpi_driver_data(device) = video;
1754
1755         acpi_video_bus_find_cap(video);
1756         result = acpi_video_bus_check(video);
1757         if (result)
1758                 goto end;
1759
1760         result = acpi_video_bus_add_fs(device);
1761         if (result)
1762                 goto end;
1763
1764         init_MUTEX(&video->sem);
1765         INIT_LIST_HEAD(&video->video_device_list);
1766
1767         acpi_video_bus_get_devices(video, device);
1768         acpi_video_bus_start_devices(video);
1769
1770         status = acpi_install_notify_handler(video->handle,
1771                                              ACPI_DEVICE_NOTIFY,
1772                                              acpi_video_bus_notify, video);
1773         if (ACPI_FAILURE(status)) {
1774                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1775                                   "Error installing notify handler\n"));
1776                 acpi_video_bus_stop_devices(video);
1777                 acpi_video_bus_put_devices(video);
1778                 kfree(video->attached_array);
1779                 acpi_video_bus_remove_fs(device);
1780                 result = -ENODEV;
1781                 goto end;
1782         }
1783
1784         printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s  rom: %s  post: %s)\n",
1785                ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
1786                video->flags.multihead ? "yes" : "no",
1787                video->flags.rom ? "yes" : "no",
1788                video->flags.post ? "yes" : "no");
1789
1790       end:
1791         if (result)
1792                 kfree(video);
1793
1794         return_VALUE(result);
1795 }
1796
1797 static int acpi_video_bus_remove(struct acpi_device *device, int type)
1798 {
1799         acpi_status status = 0;
1800         struct acpi_video_bus *video = NULL;
1801
1802         ACPI_FUNCTION_TRACE("acpi_video_bus_remove");
1803
1804         if (!device || !acpi_driver_data(device))
1805                 return_VALUE(-EINVAL);
1806
1807         video = (struct acpi_video_bus *)acpi_driver_data(device);
1808
1809         acpi_video_bus_stop_devices(video);
1810
1811         status = acpi_remove_notify_handler(video->handle,
1812                                             ACPI_DEVICE_NOTIFY,
1813                                             acpi_video_bus_notify);
1814
1815         acpi_video_bus_put_devices(video);
1816         acpi_video_bus_remove_fs(device);
1817
1818         kfree(video->attached_array);
1819         kfree(video);
1820
1821         return_VALUE(0);
1822 }
1823
1824 static int
1825 acpi_video_bus_match(struct acpi_device *device, struct acpi_driver *driver)
1826 {
1827         acpi_handle h_dummy1;
1828         acpi_handle h_dummy2;
1829         acpi_handle h_dummy3;
1830
1831         ACPI_FUNCTION_TRACE("acpi_video_bus_match");
1832
1833         if (!device || !driver)
1834                 return_VALUE(-EINVAL);
1835
1836         /* Since there is no HID, CID for ACPI Video drivers, we have
1837          * to check well known required nodes for each feature we support.
1838          */
1839
1840         /* Does this device able to support video switching ? */
1841         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
1842             ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
1843                 return_VALUE(0);
1844
1845         /* Does this device able to retrieve a video ROM ? */
1846         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
1847                 return_VALUE(0);
1848
1849         /* Does this device able to configure which video head to be POSTed ? */
1850         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
1851             ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
1852             ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
1853                 return_VALUE(0);
1854
1855         return_VALUE(-ENODEV);
1856 }
1857
1858 static int __init acpi_video_init(void)
1859 {
1860         int result = 0;
1861
1862         ACPI_FUNCTION_TRACE("acpi_video_init");
1863
1864         /*
1865            acpi_dbg_level = 0xFFFFFFFF;
1866            acpi_dbg_layer = 0x08000000;
1867          */
1868
1869         acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
1870         if (!acpi_video_dir)
1871                 return_VALUE(-ENODEV);
1872         acpi_video_dir->owner = THIS_MODULE;
1873
1874         result = acpi_bus_register_driver(&acpi_video_bus);
1875         if (result < 0) {
1876                 remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
1877                 return_VALUE(-ENODEV);
1878         }
1879
1880         return_VALUE(0);
1881 }
1882
1883 static void __exit acpi_video_exit(void)
1884 {
1885         ACPI_FUNCTION_TRACE("acpi_video_exit");
1886
1887         acpi_bus_unregister_driver(&acpi_video_bus);
1888
1889         remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
1890
1891         return_VOID;
1892 }
1893
1894 module_init(acpi_video_init);
1895 module_exit(acpi_video_exit);