Pull cpu-hotplug into release branch
[linux-2.6] / 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, result;
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                         result = -ENODEV;
1350                         goto end;
1351                 }
1352
1353                 down(&video->sem);
1354                 list_add_tail(&data->entry, &video->video_device_list);
1355                 up(&video->sem);
1356
1357                 acpi_video_device_add_fs(device);
1358
1359                 return_VALUE(0);
1360         }
1361
1362       end:
1363         return_VALUE(-ENOENT);
1364 }
1365
1366 /*
1367  *  Arg:
1368  *      video   : video bus device 
1369  *
1370  *  Return:
1371  *      none
1372  *  
1373  *  Enumerate the video device list of the video bus, 
1374  *  bind the ids with the corresponding video devices
1375  *  under the video bus.
1376  */
1377
1378 static void acpi_video_device_rebind(struct acpi_video_bus *video)
1379 {
1380         struct list_head *node, *next;
1381         list_for_each_safe(node, next, &video->video_device_list) {
1382                 struct acpi_video_device *dev =
1383                     container_of(node, struct acpi_video_device, entry);
1384                 acpi_video_device_bind(video, dev);
1385         }
1386 }
1387
1388 /*
1389  *  Arg:
1390  *      video   : video bus device 
1391  *      device  : video output device under the video 
1392  *              bus
1393  *
1394  *  Return:
1395  *      none
1396  *  
1397  *  Bind the ids with the corresponding video devices
1398  *  under the video bus.
1399  */
1400
1401 static void
1402 acpi_video_device_bind(struct acpi_video_bus *video,
1403                        struct acpi_video_device *device)
1404 {
1405         int i;
1406         ACPI_FUNCTION_TRACE("acpi_video_device_bind");
1407
1408 #define IDS_VAL(i) video->attached_array[i].value.int_val
1409 #define IDS_BIND(i) video->attached_array[i].bind_info
1410
1411         for (i = 0; IDS_VAL(i) != ACPI_VIDEO_HEAD_INVALID &&
1412              i < video->attached_count; i++) {
1413                 if (device->device_id == (IDS_VAL(i) & 0xffff)) {
1414                         IDS_BIND(i) = device;
1415                         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i));
1416                 }
1417         }
1418 #undef IDS_VAL
1419 #undef IDS_BIND
1420 }
1421
1422 /*
1423  *  Arg:
1424  *      video   : video bus device 
1425  *
1426  *  Return:
1427  *      < 0     : error
1428  *  
1429  *  Call _DOD to enumerate all devices attached to display adapter
1430  *
1431  */
1432
1433 static int acpi_video_device_enumerate(struct acpi_video_bus *video)
1434 {
1435         int status;
1436         int count;
1437         int i;
1438         struct acpi_video_enumerated_device *active_device_list;
1439         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1440         union acpi_object *dod = NULL;
1441         union acpi_object *obj;
1442
1443         ACPI_FUNCTION_TRACE("acpi_video_device_enumerate");
1444
1445         status = acpi_evaluate_object(video->handle, "_DOD", NULL, &buffer);
1446         if (!ACPI_SUCCESS(status)) {
1447                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _DOD\n"));
1448                 return_VALUE(status);
1449         }
1450
1451         dod = (union acpi_object *)buffer.pointer;
1452         if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
1453                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DOD data\n"));
1454                 status = -EFAULT;
1455                 goto out;
1456         }
1457
1458         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
1459                           dod->package.count));
1460
1461         active_device_list = kmalloc((1 +
1462                                       dod->package.count) *
1463                                      sizeof(struct
1464                                             acpi_video_enumerated_device),
1465                                      GFP_KERNEL);
1466
1467         if (!active_device_list) {
1468                 status = -ENOMEM;
1469                 goto out;
1470         }
1471
1472         count = 0;
1473         for (i = 0; i < dod->package.count; i++) {
1474                 obj = (union acpi_object *)&dod->package.elements[i];
1475
1476                 if (obj->type != ACPI_TYPE_INTEGER) {
1477                         ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1478                                           "Invalid _DOD data\n"));
1479                         active_device_list[i].value.int_val =
1480                             ACPI_VIDEO_HEAD_INVALID;
1481                 }
1482                 active_device_list[i].value.int_val = obj->integer.value;
1483                 active_device_list[i].bind_info = NULL;
1484                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i,
1485                                   (int)obj->integer.value));
1486                 count++;
1487         }
1488         active_device_list[count].value.int_val = ACPI_VIDEO_HEAD_END;
1489
1490         kfree(video->attached_array);
1491
1492         video->attached_array = active_device_list;
1493         video->attached_count = count;
1494       out:
1495         acpi_os_free(buffer.pointer);
1496         return_VALUE(status);
1497 }
1498
1499 /*
1500  *  Arg:
1501  *      video   : video bus device 
1502  *      event   : Nontify Event
1503  *
1504  *  Return:
1505  *      < 0     : error
1506  *  
1507  *      1. Find out the current active output device.
1508  *      2. Identify the next output device to switch
1509  *      3. call _DSS to do actual switch.
1510  */
1511
1512 static int acpi_video_switch_output(struct acpi_video_bus *video, int event)
1513 {
1514         struct list_head *node, *next;
1515         struct acpi_video_device *dev = NULL;
1516         struct acpi_video_device *dev_next = NULL;
1517         struct acpi_video_device *dev_prev = NULL;
1518         unsigned long state;
1519         int status = 0;
1520
1521         ACPI_FUNCTION_TRACE("acpi_video_switch_output");
1522
1523         list_for_each_safe(node, next, &video->video_device_list) {
1524                 dev = container_of(node, struct acpi_video_device, entry);
1525                 status = acpi_video_device_get_state(dev, &state);
1526                 if (state & 0x2) {
1527                         dev_next =
1528                             container_of(node->next, struct acpi_video_device,
1529                                          entry);
1530                         dev_prev =
1531                             container_of(node->prev, struct acpi_video_device,
1532                                          entry);
1533                         goto out;
1534                 }
1535         }
1536         dev_next = container_of(node->next, struct acpi_video_device, entry);
1537         dev_prev = container_of(node->prev, struct acpi_video_device, entry);
1538       out:
1539         switch (event) {
1540         case ACPI_VIDEO_NOTIFY_CYCLE:
1541         case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:
1542                 acpi_video_device_set_state(dev, 0);
1543                 acpi_video_device_set_state(dev_next, 0x80000001);
1544                 break;
1545         case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:
1546                 acpi_video_device_set_state(dev, 0);
1547                 acpi_video_device_set_state(dev_prev, 0x80000001);
1548         default:
1549                 break;
1550         }
1551
1552         return_VALUE(status);
1553 }
1554
1555 static int
1556 acpi_video_get_next_level(struct acpi_video_device *device,
1557                           u32 level_current, u32 event)
1558 {
1559         /*Fix me */
1560         return level_current;
1561 }
1562
1563 static void
1564 acpi_video_switch_brightness(struct acpi_video_device *device, int event)
1565 {
1566         unsigned long level_current, level_next;
1567         acpi_video_device_lcd_get_level_current(device, &level_current);
1568         level_next = acpi_video_get_next_level(device, level_current, event);
1569         acpi_video_device_lcd_set_level(device, level_next);
1570 }
1571
1572 static int
1573 acpi_video_bus_get_devices(struct acpi_video_bus *video,
1574                            struct acpi_device *device)
1575 {
1576         int status = 0;
1577         struct list_head *node, *next;
1578
1579         ACPI_FUNCTION_TRACE("acpi_video_get_devices");
1580
1581         acpi_video_device_enumerate(video);
1582
1583         list_for_each_safe(node, next, &device->children) {
1584                 struct acpi_device *dev =
1585                     list_entry(node, struct acpi_device, node);
1586
1587                 if (!dev)
1588                         continue;
1589
1590                 status = acpi_video_bus_get_one_device(dev, video);
1591                 if (ACPI_FAILURE(status)) {
1592                         ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1593                                           "Cant attach device\n"));
1594                         continue;
1595                 }
1596
1597         }
1598         return_VALUE(status);
1599 }
1600
1601 static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
1602 {
1603         acpi_status status;
1604         struct acpi_video_bus *video;
1605
1606         ACPI_FUNCTION_TRACE("acpi_video_bus_put_one_device");
1607
1608         if (!device || !device->video)
1609                 return_VALUE(-ENOENT);
1610
1611         video = device->video;
1612
1613         down(&video->sem);
1614         list_del(&device->entry);
1615         up(&video->sem);
1616         acpi_video_device_remove_fs(device->dev);
1617
1618         status = acpi_remove_notify_handler(device->handle,
1619                                             ACPI_DEVICE_NOTIFY,
1620                                             acpi_video_device_notify);
1621         if (ACPI_FAILURE(status))
1622                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1623                                   "Error removing notify handler\n"));
1624
1625         return_VALUE(0);
1626 }
1627
1628 static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
1629 {
1630         int status;
1631         struct list_head *node, *next;
1632
1633         ACPI_FUNCTION_TRACE("acpi_video_bus_put_devices");
1634
1635         list_for_each_safe(node, next, &video->video_device_list) {
1636                 struct acpi_video_device *data =
1637                     list_entry(node, struct acpi_video_device, entry);
1638                 if (!data)
1639                         continue;
1640
1641                 status = acpi_video_bus_put_one_device(data);
1642                 if (ACPI_FAILURE(status))
1643                         printk(KERN_WARNING PREFIX
1644                                "hhuuhhuu bug in acpi video driver.\n");
1645
1646                 kfree(data->brightness);
1647
1648                 kfree(data);
1649         }
1650
1651         return_VALUE(0);
1652 }
1653
1654 /* acpi_video interface */
1655
1656 static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
1657 {
1658         return acpi_video_bus_DOS(video, 1, 0);
1659 }
1660
1661 static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
1662 {
1663         return acpi_video_bus_DOS(video, 0, 1);
1664 }
1665
1666 static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
1667 {
1668         struct acpi_video_bus *video = (struct acpi_video_bus *)data;
1669         struct acpi_device *device = NULL;
1670
1671         ACPI_FUNCTION_TRACE("acpi_video_bus_notify");
1672         printk("video bus notify\n");
1673
1674         if (!video)
1675                 return_VOID;
1676
1677         if (acpi_bus_get_device(handle, &device))
1678                 return_VOID;
1679
1680         switch (event) {
1681         case ACPI_VIDEO_NOTIFY_SWITCH:  /* User request that a switch occur,
1682                                          * most likely via hotkey. */
1683                 acpi_bus_generate_event(device, event, 0);
1684                 break;
1685
1686         case ACPI_VIDEO_NOTIFY_PROBE:   /* User plug or remove a video
1687                                          * connector. */
1688                 acpi_video_device_enumerate(video);
1689                 acpi_video_device_rebind(video);
1690                 acpi_video_switch_output(video, event);
1691                 acpi_bus_generate_event(device, event, 0);
1692                 break;
1693
1694         case ACPI_VIDEO_NOTIFY_CYCLE:   /* Cycle Display output hotkey pressed. */
1695         case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:     /* Next Display output hotkey pressed. */
1696         case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:     /* previous Display output hotkey pressed. */
1697                 acpi_video_switch_output(video, event);
1698                 acpi_bus_generate_event(device, event, 0);
1699                 break;
1700
1701         default:
1702                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1703                                   "Unsupported event [0x%x]\n", event));
1704                 break;
1705         }
1706
1707         return_VOID;
1708 }
1709
1710 static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
1711 {
1712         struct acpi_video_device *video_device =
1713             (struct acpi_video_device *)data;
1714         struct acpi_device *device = NULL;
1715
1716         ACPI_FUNCTION_TRACE("acpi_video_device_notify");
1717
1718         printk("video device notify\n");
1719         if (!video_device)
1720                 return_VOID;
1721
1722         if (acpi_bus_get_device(handle, &device))
1723                 return_VOID;
1724
1725         switch (event) {
1726         case ACPI_VIDEO_NOTIFY_SWITCH:  /* change in status (cycle output device) */
1727         case ACPI_VIDEO_NOTIFY_PROBE:   /* change in status (output device status) */
1728                 acpi_bus_generate_event(device, event, 0);
1729                 break;
1730         case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:        /* Cycle brightness */
1731         case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:  /* Increase brightness */
1732         case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:  /* Decrease brightness */
1733         case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
1734         case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:     /* display device off */
1735                 acpi_video_switch_brightness(video_device, event);
1736                 acpi_bus_generate_event(device, event, 0);
1737                 break;
1738         default:
1739                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1740                                   "Unsupported event [0x%x]\n", event));
1741                 break;
1742         }
1743         return_VOID;
1744 }
1745
1746 static int acpi_video_bus_add(struct acpi_device *device)
1747 {
1748         int result = 0;
1749         acpi_status status = 0;
1750         struct acpi_video_bus *video = NULL;
1751
1752         ACPI_FUNCTION_TRACE("acpi_video_bus_add");
1753
1754         if (!device)
1755                 return_VALUE(-EINVAL);
1756
1757         video = kmalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
1758         if (!video)
1759                 return_VALUE(-ENOMEM);
1760         memset(video, 0, sizeof(struct acpi_video_bus));
1761
1762         video->handle = device->handle;
1763         strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
1764         strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
1765         acpi_driver_data(device) = video;
1766
1767         acpi_video_bus_find_cap(video);
1768         result = acpi_video_bus_check(video);
1769         if (result)
1770                 goto end;
1771
1772         result = acpi_video_bus_add_fs(device);
1773         if (result)
1774                 goto end;
1775
1776         init_MUTEX(&video->sem);
1777         INIT_LIST_HEAD(&video->video_device_list);
1778
1779         acpi_video_bus_get_devices(video, device);
1780         acpi_video_bus_start_devices(video);
1781
1782         status = acpi_install_notify_handler(video->handle,
1783                                              ACPI_DEVICE_NOTIFY,
1784                                              acpi_video_bus_notify, video);
1785         if (ACPI_FAILURE(status)) {
1786                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1787                                   "Error installing notify handler\n"));
1788                 result = -ENODEV;
1789                 goto end;
1790         }
1791
1792         printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s  rom: %s  post: %s)\n",
1793                ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
1794                video->flags.multihead ? "yes" : "no",
1795                video->flags.rom ? "yes" : "no",
1796                video->flags.post ? "yes" : "no");
1797
1798       end:
1799         if (result) {
1800                 acpi_video_bus_remove_fs(device);
1801                 kfree(video);
1802         }
1803
1804         return_VALUE(result);
1805 }
1806
1807 static int acpi_video_bus_remove(struct acpi_device *device, int type)
1808 {
1809         acpi_status status = 0;
1810         struct acpi_video_bus *video = NULL;
1811
1812         ACPI_FUNCTION_TRACE("acpi_video_bus_remove");
1813
1814         if (!device || !acpi_driver_data(device))
1815                 return_VALUE(-EINVAL);
1816
1817         video = (struct acpi_video_bus *)acpi_driver_data(device);
1818
1819         acpi_video_bus_stop_devices(video);
1820
1821         status = acpi_remove_notify_handler(video->handle,
1822                                             ACPI_DEVICE_NOTIFY,
1823                                             acpi_video_bus_notify);
1824         if (ACPI_FAILURE(status))
1825                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1826                                   "Error removing notify handler\n"));
1827
1828         acpi_video_bus_put_devices(video);
1829         acpi_video_bus_remove_fs(device);
1830
1831         kfree(video->attached_array);
1832         kfree(video);
1833
1834         return_VALUE(0);
1835 }
1836
1837 static int
1838 acpi_video_bus_match(struct acpi_device *device, struct acpi_driver *driver)
1839 {
1840         acpi_handle h_dummy1;
1841         acpi_handle h_dummy2;
1842         acpi_handle h_dummy3;
1843
1844         ACPI_FUNCTION_TRACE("acpi_video_bus_match");
1845
1846         if (!device || !driver)
1847                 return_VALUE(-EINVAL);
1848
1849         /* Since there is no HID, CID for ACPI Video drivers, we have
1850          * to check well known required nodes for each feature we support.
1851          */
1852
1853         /* Does this device able to support video switching ? */
1854         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
1855             ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
1856                 return_VALUE(0);
1857
1858         /* Does this device able to retrieve a video ROM ? */
1859         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
1860                 return_VALUE(0);
1861
1862         /* Does this device able to configure which video head to be POSTed ? */
1863         if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
1864             ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
1865             ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
1866                 return_VALUE(0);
1867
1868         return_VALUE(-ENODEV);
1869 }
1870
1871 static int __init acpi_video_init(void)
1872 {
1873         int result = 0;
1874
1875         ACPI_FUNCTION_TRACE("acpi_video_init");
1876
1877         /*
1878            acpi_dbg_level = 0xFFFFFFFF;
1879            acpi_dbg_layer = 0x08000000;
1880          */
1881
1882         acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
1883         if (!acpi_video_dir)
1884                 return_VALUE(-ENODEV);
1885         acpi_video_dir->owner = THIS_MODULE;
1886
1887         result = acpi_bus_register_driver(&acpi_video_bus);
1888         if (result < 0) {
1889                 remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
1890                 return_VALUE(-ENODEV);
1891         }
1892
1893         return_VALUE(0);
1894 }
1895
1896 static void __exit acpi_video_exit(void)
1897 {
1898         ACPI_FUNCTION_TRACE("acpi_video_exit");
1899
1900         acpi_bus_unregister_driver(&acpi_video_bus);
1901
1902         remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
1903
1904         return_VOID;
1905 }
1906
1907 module_init(acpi_video_init);
1908 module_exit(acpi_video_exit);