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