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