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