ACPI: fix acpi_driver.name usage
[GitHub/mt8127/android_kernel_alcatel_ttab.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
82cae999
RZ
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
1da177e4 67#define _COMPONENT ACPI_VIDEO_COMPONENT
f52fd66d 68ACPI_MODULE_NAME("video");
1da177e4 69
f52fd66d 70MODULE_AUTHOR("Bruno Ducrot");
1da177e4
LT
71MODULE_DESCRIPTION(ACPI_VIDEO_DRIVER_NAME);
72MODULE_LICENSE("GPL");
73
4be44fcd
LB
74static int acpi_video_bus_add(struct acpi_device *device);
75static int acpi_video_bus_remove(struct acpi_device *device, int type);
1da177e4
LT
76
77static struct acpi_driver acpi_video_bus = {
c2b6705b 78 .name = "video",
1da177e4 79 .class = ACPI_VIDEO_CLASS,
ae843332 80 .ids = ACPI_VIDEO_HID,
1da177e4
LT
81 .ops = {
82 .add = acpi_video_bus_add,
83 .remove = acpi_video_bus_remove,
4be44fcd 84 },
1da177e4
LT
85};
86
87struct acpi_video_bus_flags {
4be44fcd
LB
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;
1da177e4
LT
92};
93
94struct acpi_video_bus_cap {
4be44fcd
LB
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;
1da177e4
LT
102};
103
4be44fcd
LB
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 */
1da177e4
LT
115};
116
117struct acpi_video_enumerated_device {
118 union {
119 u32 int_val;
4be44fcd 120 struct acpi_video_device_attrib attrib;
1da177e4
LT
121 } value;
122 struct acpi_video_device *bind_info;
123};
124
125struct acpi_video_bus {
e6afa0de 126 struct acpi_device *device;
4be44fcd 127 u8 dos_setting;
1da177e4 128 struct acpi_video_enumerated_device *attached_array;
4be44fcd
LB
129 u8 attached_count;
130 struct acpi_video_bus_cap cap;
1da177e4 131 struct acpi_video_bus_flags flags;
4be44fcd
LB
132 struct semaphore sem;
133 struct list_head video_device_list;
134 struct proc_dir_entry *dir;
1da177e4
LT
135};
136
137struct acpi_video_device_flags {
4be44fcd
LB
138 u8 crt:1;
139 u8 lcd:1;
140 u8 tvout:1;
82cae999 141 u8 dvi:1;
4be44fcd
LB
142 u8 bios:1;
143 u8 unknown:1;
82cae999 144 u8 reserved:2;
1da177e4
LT
145};
146
147struct acpi_video_device_cap {
4be44fcd
LB
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 */
2f3d000a 151 u8 _BQC:1; /* Get current brightness level */
4be44fcd
LB
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 */
1da177e4
LT
156};
157
158struct acpi_video_device_brightness {
4be44fcd
LB
159 int curr;
160 int count;
161 int *levels;
1da177e4
LT
162};
163
164struct acpi_video_device {
4be44fcd
LB
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;
1da177e4 171 struct acpi_video_device_brightness *brightness;
2f3d000a
YL
172 struct backlight_device *backlight;
173 struct backlight_properties *data;
1da177e4
LT
174};
175
1da177e4
LT
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 = {
4be44fcd
LB
179 .open = acpi_video_bus_info_open_fs,
180 .read = seq_read,
181 .llseek = seq_lseek,
182 .release = single_release,
1da177e4
LT
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 = {
4be44fcd
LB
187 .open = acpi_video_bus_ROM_open_fs,
188 .read = seq_read,
189 .llseek = seq_lseek,
190 .release = single_release,
1da177e4
LT
191};
192
4be44fcd
LB
193static int acpi_video_bus_POST_info_open_fs(struct inode *inode,
194 struct file *file);
1da177e4 195static struct file_operations acpi_video_bus_POST_info_fops = {
4be44fcd
LB
196 .open = acpi_video_bus_POST_info_open_fs,
197 .read = seq_read,
198 .llseek = seq_lseek,
199 .release = single_release,
1da177e4
LT
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 = {
4be44fcd
LB
204 .open = acpi_video_bus_POST_open_fs,
205 .read = seq_read,
206 .llseek = seq_lseek,
207 .release = single_release,
1da177e4
LT
208};
209
1da177e4
LT
210static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file);
211static struct file_operations acpi_video_bus_DOS_fops = {
4be44fcd
LB
212 .open = acpi_video_bus_DOS_open_fs,
213 .read = seq_read,
214 .llseek = seq_lseek,
215 .release = single_release,
1da177e4
LT
216};
217
218/* device */
4be44fcd
LB
219static int acpi_video_device_info_open_fs(struct inode *inode,
220 struct file *file);
1da177e4 221static struct file_operations acpi_video_device_info_fops = {
4be44fcd
LB
222 .open = acpi_video_device_info_open_fs,
223 .read = seq_read,
224 .llseek = seq_lseek,
225 .release = single_release,
1da177e4
LT
226};
227
4be44fcd
LB
228static int acpi_video_device_state_open_fs(struct inode *inode,
229 struct file *file);
1da177e4 230static struct file_operations acpi_video_device_state_fops = {
4be44fcd
LB
231 .open = acpi_video_device_state_open_fs,
232 .read = seq_read,
233 .llseek = seq_lseek,
234 .release = single_release,
1da177e4
LT
235};
236
4be44fcd
LB
237static int acpi_video_device_brightness_open_fs(struct inode *inode,
238 struct file *file);
1da177e4 239static struct file_operations acpi_video_device_brightness_fops = {
4be44fcd
LB
240 .open = acpi_video_device_brightness_open_fs,
241 .read = seq_read,
242 .llseek = seq_lseek,
243 .release = single_release,
1da177e4
LT
244};
245
4be44fcd
LB
246static int acpi_video_device_EDID_open_fs(struct inode *inode,
247 struct file *file);
1da177e4 248static struct file_operations acpi_video_device_EDID_fops = {
4be44fcd
LB
249 .open = acpi_video_device_EDID_open_fs,
250 .read = seq_read,
251 .llseek = seq_lseek,
252 .release = single_release,
1da177e4
LT
253};
254
4be44fcd 255static char device_decode[][30] = {
1da177e4
LT
256 "motherboard VGA device",
257 "PCI VGA device",
258 "AGP VGA device",
259 "UNKNOWN",
260};
261
4be44fcd
LB
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);
1da177e4 266static int acpi_video_device_enumerate(struct acpi_video_bus *video);
4be44fcd 267static int acpi_video_switch_output(struct acpi_video_bus *video, int event);
2f3d000a
YL
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);
4be44fcd
LB
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);
1da177e4 277
2f3d000a
YL
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
1da177e4
LT
297/* --------------------------------------------------------------------------
298 Video Management
299 -------------------------------------------------------------------------- */
300
301/* device */
302
303static int
4be44fcd 304acpi_video_device_query(struct acpi_video_device *device, unsigned long *state)
1da177e4 305{
4be44fcd 306 int status;
90130268
PM
307
308 status = acpi_evaluate_integer(device->dev->handle, "_DGS", NULL, state);
1da177e4 309
d550d98d 310 return status;
1da177e4
LT
311}
312
313static int
4be44fcd
LB
314acpi_video_device_get_state(struct acpi_video_device *device,
315 unsigned long *state)
1da177e4 316{
4be44fcd 317 int status;
1da177e4 318
90130268 319 status = acpi_evaluate_integer(device->dev->handle, "_DCS", NULL, state);
1da177e4 320
d550d98d 321 return status;
1da177e4
LT
322}
323
324static int
4be44fcd 325acpi_video_device_set_state(struct acpi_video_device *device, int state)
1da177e4 326{
4be44fcd
LB
327 int status;
328 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
329 struct acpi_object_list args = { 1, &arg0 };
824b558b 330 unsigned long ret;
1da177e4 331
1da177e4
LT
332
333 arg0.integer.value = state;
90130268 334 status = acpi_evaluate_integer(device->dev->handle, "_DSS", &args, &ret);
1da177e4 335
d550d98d 336 return status;
1da177e4
LT
337}
338
339static int
4be44fcd
LB
340acpi_video_device_lcd_query_levels(struct acpi_video_device *device,
341 union acpi_object **levels)
1da177e4 342{
4be44fcd
LB
343 int status;
344 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
345 union acpi_object *obj;
1da177e4 346
1da177e4
LT
347
348 *levels = NULL;
349
90130268 350 status = acpi_evaluate_object(device->dev->handle, "_BCL", NULL, &buffer);
1da177e4 351 if (!ACPI_SUCCESS(status))
d550d98d 352 return status;
4be44fcd 353 obj = (union acpi_object *)buffer.pointer;
6665bda7 354 if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
6468463a 355 printk(KERN_ERR PREFIX "Invalid _BCL data\n");
1da177e4
LT
356 status = -EFAULT;
357 goto err;
358 }
359
360 *levels = obj;
361
d550d98d 362 return 0;
1da177e4 363
4be44fcd 364 err:
6044ec88 365 kfree(buffer.pointer);
1da177e4 366
d550d98d 367 return status;
1da177e4
LT
368}
369
370static int
4be44fcd 371acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
1da177e4 372{
4be44fcd
LB
373 int status;
374 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
375 struct acpi_object_list args = { 1, &arg0 };
1da177e4 376
1da177e4
LT
377
378 arg0.integer.value = level;
90130268 379 status = acpi_evaluate_object(device->dev->handle, "_BCM", &args, NULL);
1da177e4
LT
380
381 printk(KERN_DEBUG "set_level status: %x\n", status);
d550d98d 382 return status;
1da177e4
LT
383}
384
385static int
4be44fcd
LB
386acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
387 unsigned long *level)
1da177e4 388{
4be44fcd 389 int status;
1da177e4 390
90130268 391 status = acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, level);
1da177e4 392
d550d98d 393 return status;
1da177e4
LT
394}
395
396static int
4be44fcd
LB
397acpi_video_device_EDID(struct acpi_video_device *device,
398 union acpi_object **edid, ssize_t length)
1da177e4 399{
4be44fcd
LB
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 };
1da177e4 405
1da177e4
LT
406
407 *edid = NULL;
408
409 if (!device)
d550d98d 410 return -ENODEV;
1da177e4
LT
411 if (length == 128)
412 arg0.integer.value = 1;
413 else if (length == 256)
414 arg0.integer.value = 2;
415 else
d550d98d 416 return -EINVAL;
1da177e4 417
90130268 418 status = acpi_evaluate_object(device->dev->handle, "_DDC", &args, &buffer);
1da177e4 419 if (ACPI_FAILURE(status))
d550d98d 420 return -ENODEV;
1da177e4 421
50dd0969 422 obj = buffer.pointer;
1da177e4
LT
423
424 if (obj && obj->type == ACPI_TYPE_BUFFER)
425 *edid = obj;
426 else {
6468463a 427 printk(KERN_ERR PREFIX "Invalid _DDC data\n");
1da177e4
LT
428 status = -EFAULT;
429 kfree(obj);
430 }
431
d550d98d 432 return status;
1da177e4
LT
433}
434
1da177e4
LT
435/* bus */
436
437static int
4be44fcd 438acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
1da177e4 439{
4be44fcd
LB
440 int status;
441 unsigned long tmp;
442 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
443 struct acpi_object_list args = { 1, &arg0 };
1da177e4 444
1da177e4
LT
445
446 arg0.integer.value = option;
447
90130268 448 status = acpi_evaluate_integer(video->device->handle, "_SPD", &args, &tmp);
1da177e4 449 if (ACPI_SUCCESS(status))
4be44fcd 450 status = tmp ? (-EINVAL) : (AE_OK);
1da177e4 451
d550d98d 452 return status;
1da177e4
LT
453}
454
455static int
4be44fcd 456acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long *id)
1da177e4
LT
457{
458 int status;
459
90130268 460 status = acpi_evaluate_integer(video->device->handle, "_GPD", NULL, id);
1da177e4 461
d550d98d 462 return status;
1da177e4
LT
463}
464
465static int
4be44fcd
LB
466acpi_video_bus_POST_options(struct acpi_video_bus *video,
467 unsigned long *options)
1da177e4 468{
4be44fcd 469 int status;
1da177e4 470
90130268 471 status = acpi_evaluate_integer(video->device->handle, "_VPO", NULL, options);
1da177e4
LT
472 *options &= 3;
473
d550d98d 474 return status;
1da177e4
LT
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
4be44fcd 499acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
1da177e4 500{
4be44fcd
LB
501 acpi_integer status = 0;
502 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
503 struct acpi_object_list args = { 1, &arg0 };
1da177e4 504
1da177e4 505
4be44fcd 506 if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) {
1da177e4
LT
507 status = -1;
508 goto Failed;
509 }
510 arg0.integer.value = (lcd_flag << 2) | bios_flag;
511 video->dos_setting = arg0.integer.value;
90130268 512 acpi_evaluate_object(video->device->handle, "_DOS", &args, NULL);
1da177e4 513
4be44fcd 514 Failed:
d550d98d 515 return status;
1da177e4
LT
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
4be44fcd 529static void acpi_video_device_find_cap(struct acpi_video_device *device)
1da177e4 530{
4be44fcd 531 acpi_integer status;
1da177e4
LT
532 acpi_handle h_dummy1;
533 int i;
2f3d000a 534 u32 max_level = 0;
1da177e4
LT
535 union acpi_object *obj = NULL;
536 struct acpi_video_device_brightness *br = NULL;
537
1da177e4 538
4be44fcd 539 memset(&device->cap, 0, 4);
1da177e4 540
90130268 541 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) {
1da177e4
LT
542 device->cap._ADR = 1;
543 }
90130268 544 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCL", &h_dummy1))) {
4be44fcd 545 device->cap._BCL = 1;
1da177e4 546 }
90130268 547 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) {
4be44fcd 548 device->cap._BCM = 1;
1da177e4 549 }
2f3d000a
YL
550 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1)))
551 device->cap._BQC = 1;
90130268 552 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
4be44fcd 553 device->cap._DDC = 1;
1da177e4 554 }
90130268 555 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DCS", &h_dummy1))) {
1da177e4
LT
556 device->cap._DCS = 1;
557 }
90130268 558 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DGS", &h_dummy1))) {
1da177e4
LT
559 device->cap._DGS = 1;
560 }
90130268 561 if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DSS", &h_dummy1))) {
1da177e4
LT
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;
4be44fcd 570
36bcbec7 571 br = kzalloc(sizeof(*br), GFP_KERNEL);
1da177e4
LT
572 if (!br) {
573 printk(KERN_ERR "can't allocate memory\n");
574 } else {
d1dd0c23 575 br->levels = kmalloc(obj->package.count *
4be44fcd 576 sizeof *(br->levels), GFP_KERNEL);
1da177e4
LT
577 if (!br->levels)
578 goto out;
579
580 for (i = 0; i < obj->package.count; i++) {
4be44fcd
LB
581 o = (union acpi_object *)&obj->package.
582 elements[i];
1da177e4 583 if (o->type != ACPI_TYPE_INTEGER) {
6468463a 584 printk(KERN_ERR PREFIX "Invalid data\n");
1da177e4
LT
585 continue;
586 }
587 br->levels[count] = (u32) o->integer.value;
2f3d000a
YL
588 if (br->levels[count] > max_level)
589 max_level = br->levels[count];
1da177e4
LT
590 count++;
591 }
4be44fcd 592 out:
1da177e4 593 if (count < 2) {
d1dd0c23 594 kfree(br->levels);
1da177e4
LT
595 kfree(br);
596 } else {
597 br->count = count;
598 device->brightness = br;
4be44fcd
LB
599 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
600 "found %d brightness levels\n",
601 count));
1da177e4
LT
602 }
603 }
604 }
605
d1dd0c23 606 kfree(obj);
1da177e4 607
2f3d000a
YL
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 }
d550d98d 639 return;
1da177e4
LT
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
4be44fcd 652static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
1da177e4 653{
4be44fcd 654 acpi_handle h_dummy1;
1da177e4 655
4be44fcd 656 memset(&video->cap, 0, 4);
90130268 657 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) {
1da177e4
LT
658 video->cap._DOS = 1;
659 }
90130268 660 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOD", &h_dummy1))) {
1da177e4
LT
661 video->cap._DOD = 1;
662 }
90130268 663 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_ROM", &h_dummy1))) {
1da177e4
LT
664 video->cap._ROM = 1;
665 }
90130268 666 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_GPD", &h_dummy1))) {
1da177e4
LT
667 video->cap._GPD = 1;
668 }
90130268 669 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_SPD", &h_dummy1))) {
1da177e4
LT
670 video->cap._SPD = 1;
671 }
90130268 672 if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_VPO", &h_dummy1))) {
1da177e4
LT
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
4be44fcd 682static int acpi_video_bus_check(struct acpi_video_bus *video)
1da177e4 683{
4be44fcd 684 acpi_status status = -ENOENT;
1da177e4 685
1da177e4
LT
686
687 if (!video)
d550d98d 688 return -EINVAL;
1da177e4
LT
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 ? */
4be44fcd 695 if (video->cap._DOS) {
1da177e4
LT
696 video->flags.multihead = 1;
697 status = 0;
698 }
699
700 /* Does this device able to retrieve a retrieve a video ROM ? */
4be44fcd 701 if (video->cap._ROM) {
1da177e4
LT
702 video->flags.rom = 1;
703 status = 0;
704 }
705
706 /* Does this device able to configure which video device to POST ? */
4be44fcd 707 if (video->cap._GPD && video->cap._SPD && video->cap._VPO) {
1da177e4
LT
708 video->flags.post = 1;
709 status = 0;
710 }
711
d550d98d 712 return status;
1da177e4
LT
713}
714
715/* --------------------------------------------------------------------------
716 FS Interface (/proc)
717 -------------------------------------------------------------------------- */
718
4be44fcd 719static struct proc_dir_entry *acpi_video_dir;
1da177e4
LT
720
721/* video devices */
722
4be44fcd 723static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
1da177e4 724{
50dd0969 725 struct acpi_video_device *dev = seq->private;
1da177e4 726
1da177e4
LT
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");
82cae999
RZ
739 else if (dev->flags.dvi)
740 seq_printf(seq, "DVI\n");
1da177e4
LT
741 else
742 seq_printf(seq, "UNKNOWN\n");
743
4be44fcd 744 seq_printf(seq, "known by bios: %s\n", dev->flags.bios ? "yes" : "no");
1da177e4 745
4be44fcd 746 end:
d550d98d 747 return 0;
1da177e4
LT
748}
749
750static int
4be44fcd 751acpi_video_device_info_open_fs(struct inode *inode, struct file *file)
1da177e4
LT
752{
753 return single_open(file, acpi_video_device_info_seq_show,
754 PDE(inode)->data);
755}
756
4be44fcd 757static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
1da177e4 758{
4be44fcd 759 int status;
50dd0969 760 struct acpi_video_device *dev = seq->private;
4be44fcd 761 unsigned long state;
1da177e4 762
1da177e4
LT
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
4be44fcd 781 end:
d550d98d 782 return 0;
1da177e4
LT
783}
784
785static int
4be44fcd 786acpi_video_device_state_open_fs(struct inode *inode, struct file *file)
1da177e4
LT
787{
788 return single_open(file, acpi_video_device_state_seq_show,
789 PDE(inode)->data);
790}
791
792static ssize_t
4be44fcd
LB
793acpi_video_device_write_state(struct file *file,
794 const char __user * buffer,
795 size_t count, loff_t * data)
1da177e4 796{
4be44fcd 797 int status;
50dd0969
JE
798 struct seq_file *m = file->private_data;
799 struct acpi_video_device *dev = m->private;
4be44fcd
LB
800 char str[12] = { 0 };
801 u32 state = 0;
1da177e4 802
1da177e4
LT
803
804 if (!dev || count + 1 > sizeof str)
d550d98d 805 return -EINVAL;
1da177e4
LT
806
807 if (copy_from_user(str, buffer, count))
d550d98d 808 return -EFAULT;
1da177e4
LT
809
810 str[count] = 0;
811 state = simple_strtoul(str, NULL, 0);
4be44fcd 812 state &= ((1ul << 31) | (1ul << 30) | (1ul << 0));
1da177e4
LT
813
814 status = acpi_video_device_set_state(dev, state);
815
816 if (status)
d550d98d 817 return -EFAULT;
1da177e4 818
d550d98d 819 return count;
1da177e4
LT
820}
821
822static int
4be44fcd 823acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset)
1da177e4 824{
50dd0969 825 struct acpi_video_device *dev = seq->private;
4be44fcd 826 int i;
1da177e4 827
1da177e4
LT
828
829 if (!dev || !dev->brightness) {
830 seq_printf(seq, "<not supported>\n");
d550d98d 831 return 0;
1da177e4
LT
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
d550d98d 839 return 0;
1da177e4
LT
840}
841
842static int
4be44fcd 843acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file)
1da177e4
LT
844{
845 return single_open(file, acpi_video_device_brightness_seq_show,
846 PDE(inode)->data);
847}
848
849static ssize_t
4be44fcd
LB
850acpi_video_device_write_brightness(struct file *file,
851 const char __user * buffer,
852 size_t count, loff_t * data)
1da177e4 853{
50dd0969
JE
854 struct seq_file *m = file->private_data;
855 struct acpi_video_device *dev = m->private;
4be44fcd
LB
856 char str[4] = { 0 };
857 unsigned int level = 0;
858 int i;
1da177e4 859
1da177e4 860
59d399d3 861 if (!dev || !dev->brightness || count + 1 > sizeof str)
d550d98d 862 return -EINVAL;
1da177e4
LT
863
864 if (copy_from_user(str, buffer, count))
d550d98d 865 return -EFAULT;
1da177e4
LT
866
867 str[count] = 0;
868 level = simple_strtoul(str, NULL, 0);
4be44fcd 869
1da177e4 870 if (level > 100)
d550d98d 871 return -EFAULT;
1da177e4
LT
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]) {
4be44fcd
LB
876 if (ACPI_SUCCESS
877 (acpi_video_device_lcd_set_level(dev, level)))
1da177e4
LT
878 dev->brightness->curr = level;
879 break;
880 }
881
d550d98d 882 return count;
1da177e4
LT
883}
884
4be44fcd 885static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset)
1da177e4 886{
50dd0969 887 struct acpi_video_device *dev = seq->private;
4be44fcd
LB
888 int status;
889 int i;
890 union acpi_object *edid = NULL;
1da177e4 891
1da177e4
LT
892
893 if (!dev)
894 goto out;
895
4be44fcd 896 status = acpi_video_device_EDID(dev, &edid, 128);
1da177e4 897 if (ACPI_FAILURE(status)) {
4be44fcd 898 status = acpi_video_device_EDID(dev, &edid, 256);
1da177e4
LT
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
4be44fcd 910 out:
1da177e4
LT
911 if (!edid)
912 seq_printf(seq, "<not supported>\n");
913 else
914 kfree(edid);
915
d550d98d 916 return 0;
1da177e4
LT
917}
918
919static int
4be44fcd 920acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file)
1da177e4
LT
921{
922 return single_open(file, acpi_video_device_EDID_seq_show,
923 PDE(inode)->data);
924}
925
4be44fcd 926static int acpi_video_device_add_fs(struct acpi_device *device)
1da177e4 927{
4be44fcd 928 struct proc_dir_entry *entry = NULL;
1da177e4
LT
929 struct acpi_video_device *vid_dev;
930
1da177e4
LT
931
932 if (!device)
d550d98d 933 return -ENODEV;
1da177e4 934
50dd0969 935 vid_dev = acpi_driver_data(device);
1da177e4 936 if (!vid_dev)
d550d98d 937 return -ENODEV;
1da177e4
LT
938
939 if (!acpi_device_dir(device)) {
940 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
4be44fcd 941 vid_dev->video->dir);
1da177e4 942 if (!acpi_device_dir(device))
d550d98d 943 return -ENODEV;
1da177e4
LT
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)
d550d98d 950 return -ENODEV;
1da177e4
LT
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] */
4be44fcd
LB
958 entry =
959 create_proc_entry("state", S_IFREG | S_IRUGO | S_IWUSR,
960 acpi_device_dir(device));
1da177e4 961 if (!entry)
d550d98d 962 return -ENODEV;
1da177e4 963 else {
d479e908 964 acpi_video_device_state_fops.write = acpi_video_device_write_state;
1da177e4 965 entry->proc_fops = &acpi_video_device_state_fops;
1da177e4
LT
966 entry->data = acpi_driver_data(device);
967 entry->owner = THIS_MODULE;
968 }
969
970 /* 'brightness' [R/W] */
4be44fcd
LB
971 entry =
972 create_proc_entry("brightness", S_IFREG | S_IRUGO | S_IWUSR,
973 acpi_device_dir(device));
1da177e4 974 if (!entry)
d550d98d 975 return -ENODEV;
1da177e4 976 else {
d479e908 977 acpi_video_device_brightness_fops.write = acpi_video_device_write_brightness;
1da177e4 978 entry->proc_fops = &acpi_video_device_brightness_fops;
1da177e4
LT
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)
d550d98d 986 return -ENODEV;
1da177e4
LT
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
d550d98d 993 return 0;
1da177e4
LT
994}
995
4be44fcd 996static int acpi_video_device_remove_fs(struct acpi_device *device)
1da177e4
LT
997{
998 struct acpi_video_device *vid_dev;
1da177e4 999
50dd0969 1000 vid_dev = acpi_driver_data(device);
1da177e4 1001 if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
d550d98d 1002 return -ENODEV;
1da177e4
LT
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));
4be44fcd 1009 remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
1da177e4
LT
1010 acpi_device_dir(device) = NULL;
1011 }
1012
d550d98d 1013 return 0;
1da177e4
LT
1014}
1015
1da177e4 1016/* video bus */
4be44fcd 1017static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset)
1da177e4 1018{
50dd0969 1019 struct acpi_video_bus *video = seq->private;
1da177e4 1020
1da177e4
LT
1021
1022 if (!video)
1023 goto end;
1024
1025 seq_printf(seq, "Switching heads: %s\n",
4be44fcd 1026 video->flags.multihead ? "yes" : "no");
1da177e4 1027 seq_printf(seq, "Video ROM: %s\n",
4be44fcd 1028 video->flags.rom ? "yes" : "no");
1da177e4 1029 seq_printf(seq, "Device to be POSTed on boot: %s\n",
4be44fcd 1030 video->flags.post ? "yes" : "no");
1da177e4 1031
4be44fcd 1032 end:
d550d98d 1033 return 0;
1da177e4
LT
1034}
1035
4be44fcd 1036static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file)
1da177e4 1037{
4be44fcd
LB
1038 return single_open(file, acpi_video_bus_info_seq_show,
1039 PDE(inode)->data);
1da177e4
LT
1040}
1041
4be44fcd 1042static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset)
1da177e4 1043{
50dd0969 1044 struct acpi_video_bus *video = seq->private;
1da177e4 1045
1da177e4
LT
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
4be44fcd 1053 end:
d550d98d 1054 return 0;
1da177e4
LT
1055}
1056
4be44fcd 1057static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file)
1da177e4
LT
1058{
1059 return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data);
1060}
1061
4be44fcd 1062static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
1da177e4 1063{
50dd0969 1064 struct acpi_video_bus *video = seq->private;
4be44fcd
LB
1065 unsigned long options;
1066 int status;
1da177e4 1067
1da177e4
LT
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)) {
4be44fcd
LB
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");
1da177e4
LT
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");
4be44fcd 1089 end:
d550d98d 1090 return 0;
1da177e4
LT
1091}
1092
1093static int
4be44fcd 1094acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file)
1da177e4 1095{
4be44fcd
LB
1096 return single_open(file, acpi_video_bus_POST_info_seq_show,
1097 PDE(inode)->data);
1da177e4
LT
1098}
1099
4be44fcd 1100static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
1da177e4 1101{
50dd0969 1102 struct acpi_video_bus *video = seq->private;
4be44fcd
LB
1103 int status;
1104 unsigned long id;
1da177e4 1105
1da177e4
LT
1106
1107 if (!video)
1108 goto end;
1109
4be44fcd 1110 status = acpi_video_bus_get_POST(video, &id);
1da177e4
LT
1111 if (!ACPI_SUCCESS(status)) {
1112 seq_printf(seq, "<not supported>\n");
1113 goto end;
1114 }
4be44fcd 1115 seq_printf(seq, "device posted is <%s>\n", device_decode[id & 3]);
1da177e4 1116
4be44fcd 1117 end:
d550d98d 1118 return 0;
1da177e4
LT
1119}
1120
4be44fcd 1121static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset)
1da177e4 1122{
50dd0969 1123 struct acpi_video_bus *video = seq->private;
1da177e4 1124
1da177e4 1125
4be44fcd 1126 seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting);
1da177e4 1127
d550d98d 1128 return 0;
1da177e4
LT
1129}
1130
4be44fcd 1131static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file)
1da177e4 1132{
4be44fcd
LB
1133 return single_open(file, acpi_video_bus_POST_seq_show,
1134 PDE(inode)->data);
1da177e4
LT
1135}
1136
4be44fcd 1137static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file)
1da177e4
LT
1138{
1139 return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data);
1140}
1141
1142static ssize_t
4be44fcd
LB
1143acpi_video_bus_write_POST(struct file *file,
1144 const char __user * buffer,
1145 size_t count, loff_t * data)
1da177e4 1146{
4be44fcd 1147 int status;
50dd0969
JE
1148 struct seq_file *m = file->private_data;
1149 struct acpi_video_bus *video = m->private;
4be44fcd
LB
1150 char str[12] = { 0 };
1151 unsigned long opt, options;
1da177e4 1152
1da177e4 1153
1da177e4 1154 if (!video || count + 1 > sizeof str)
d550d98d 1155 return -EINVAL;
1da177e4
LT
1156
1157 status = acpi_video_bus_POST_options(video, &options);
1158 if (!ACPI_SUCCESS(status))
d550d98d 1159 return -EINVAL;
1da177e4
LT
1160
1161 if (copy_from_user(str, buffer, count))
d550d98d 1162 return -EFAULT;
1da177e4
LT
1163
1164 str[count] = 0;
1165 opt = strtoul(str, NULL, 0);
1166 if (opt > 3)
d550d98d 1167 return -EFAULT;
1da177e4
LT
1168
1169 /* just in case an OEM 'forget' the motherboard... */
1170 options |= 1;
1171
1172 if (options & (1ul << opt)) {
4be44fcd 1173 status = acpi_video_bus_set_POST(video, opt);
1da177e4 1174 if (!ACPI_SUCCESS(status))
d550d98d 1175 return -EFAULT;
1da177e4
LT
1176
1177 }
1178
d550d98d 1179 return count;
1da177e4
LT
1180}
1181
1182static ssize_t
4be44fcd
LB
1183acpi_video_bus_write_DOS(struct file *file,
1184 const char __user * buffer,
1185 size_t count, loff_t * data)
1da177e4 1186{
4be44fcd 1187 int status;
50dd0969
JE
1188 struct seq_file *m = file->private_data;
1189 struct acpi_video_bus *video = m->private;
4be44fcd
LB
1190 char str[12] = { 0 };
1191 unsigned long opt;
1da177e4 1192
1da177e4 1193
1da177e4 1194 if (!video || count + 1 > sizeof str)
d550d98d 1195 return -EINVAL;
1da177e4
LT
1196
1197 if (copy_from_user(str, buffer, count))
d550d98d 1198 return -EFAULT;
1da177e4
LT
1199
1200 str[count] = 0;
1201 opt = strtoul(str, NULL, 0);
1202 if (opt > 7)
d550d98d 1203 return -EFAULT;
1da177e4 1204
4be44fcd 1205 status = acpi_video_bus_DOS(video, opt & 0x3, (opt & 0x4) >> 2);
1da177e4
LT
1206
1207 if (!ACPI_SUCCESS(status))
d550d98d 1208 return -EFAULT;
1da177e4 1209
d550d98d 1210 return count;
1da177e4
LT
1211}
1212
4be44fcd 1213static int acpi_video_bus_add_fs(struct acpi_device *device)
1da177e4 1214{
4be44fcd
LB
1215 struct proc_dir_entry *entry = NULL;
1216 struct acpi_video_bus *video;
1da177e4 1217
1da177e4 1218
50dd0969 1219 video = acpi_driver_data(device);
1da177e4
LT
1220
1221 if (!acpi_device_dir(device)) {
1222 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
4be44fcd 1223 acpi_video_dir);
1da177e4 1224 if (!acpi_device_dir(device))
d550d98d 1225 return -ENODEV;
1da177e4
LT
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)
d550d98d 1233 return -ENODEV;
1da177e4
LT
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)
d550d98d 1243 return -ENODEV;
1da177e4
LT
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] */
4be44fcd
LB
1251 entry =
1252 create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device));
1da177e4 1253 if (!entry)
d550d98d 1254 return -ENODEV;
1da177e4
LT
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] */
4be44fcd
LB
1262 entry =
1263 create_proc_entry("POST", S_IFREG | S_IRUGO | S_IRUSR,
1264 acpi_device_dir(device));
1da177e4 1265 if (!entry)
d550d98d 1266 return -ENODEV;
1da177e4 1267 else {
d479e908 1268 acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST;
1da177e4 1269 entry->proc_fops = &acpi_video_bus_POST_fops;
1da177e4
LT
1270 entry->data = acpi_driver_data(device);
1271 entry->owner = THIS_MODULE;
1272 }
1273
1274 /* 'DOS' [R/W] */
4be44fcd
LB
1275 entry =
1276 create_proc_entry("DOS", S_IFREG | S_IRUGO | S_IRUSR,
1277 acpi_device_dir(device));
1da177e4 1278 if (!entry)
d550d98d 1279 return -ENODEV;
1da177e4 1280 else {
d479e908 1281 acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS;
1da177e4 1282 entry->proc_fops = &acpi_video_bus_DOS_fops;
1da177e4
LT
1283 entry->data = acpi_driver_data(device);
1284 entry->owner = THIS_MODULE;
1285 }
1286
d550d98d 1287 return 0;
1da177e4
LT
1288}
1289
4be44fcd 1290static int acpi_video_bus_remove_fs(struct acpi_device *device)
1da177e4 1291{
4be44fcd 1292 struct acpi_video_bus *video;
1da177e4 1293
1da177e4 1294
50dd0969 1295 video = acpi_driver_data(device);
1da177e4
LT
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));
4be44fcd 1303 remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
1da177e4
LT
1304 acpi_device_dir(device) = NULL;
1305 }
1306
d550d98d 1307 return 0;
1da177e4
LT
1308}
1309
1310/* --------------------------------------------------------------------------
1311 Driver Interface
1312 -------------------------------------------------------------------------- */
1313
1314/* device interface */
82cae999
RZ
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}
1da177e4
LT
1325
1326static int
4be44fcd
LB
1327acpi_video_bus_get_one_device(struct acpi_device *device,
1328 struct acpi_video_bus *video)
1da177e4 1329{
4be44fcd 1330 unsigned long device_id;
973bf491 1331 int status;
4be44fcd 1332 struct acpi_video_device *data;
82cae999 1333 struct acpi_video_device_attrib* attribute;
1da177e4
LT
1334
1335 if (!device || !video)
d550d98d 1336 return -EINVAL;
1da177e4 1337
4be44fcd
LB
1338 status =
1339 acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
1da177e4
LT
1340 if (ACPI_SUCCESS(status)) {
1341
36bcbec7 1342 data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
1da177e4 1343 if (!data)
d550d98d 1344 return -ENOMEM;
1da177e4 1345
1da177e4
LT
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
82cae999
RZ
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
1da177e4 1377 data->flags.unknown = 1;
4be44fcd 1378
1da177e4
LT
1379 acpi_video_device_bind(video, data);
1380 acpi_video_device_find_cap(data);
1381
90130268 1382 status = acpi_install_notify_handler(device->handle,
4be44fcd
LB
1383 ACPI_DEVICE_NOTIFY,
1384 acpi_video_device_notify,
1385 data);
1da177e4
LT
1386 if (ACPI_FAILURE(status)) {
1387 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
4be44fcd 1388 "Error installing notify handler\n"));
973bf491
YL
1389 if(data->brightness)
1390 kfree(data->brightness->levels);
1391 kfree(data->brightness);
1392 kfree(data);
1393 return -ENODEV;
1da177e4
LT
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
d550d98d 1402 return 0;
1da177e4
LT
1403 }
1404
d550d98d 1405 return -ENOENT;
1da177e4
LT
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.
4be44fcd 1418 */
1da177e4 1419
4be44fcd 1420static void acpi_video_device_rebind(struct acpi_video_bus *video)
1da177e4 1421{
4be44fcd 1422 struct list_head *node, *next;
1da177e4 1423 list_for_each_safe(node, next, &video->video_device_list) {
4be44fcd
LB
1424 struct acpi_video_device *dev =
1425 container_of(node, struct acpi_video_device, entry);
1426 acpi_video_device_bind(video, dev);
1da177e4
LT
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.
4be44fcd 1441 */
1da177e4
LT
1442
1443static void
4be44fcd
LB
1444acpi_video_device_bind(struct acpi_video_bus *video,
1445 struct acpi_video_device *device)
1da177e4 1446{
4be44fcd 1447 int i;
1da177e4
LT
1448
1449#define IDS_VAL(i) video->attached_array[i].value.int_val
1450#define IDS_BIND(i) video->attached_array[i].bind_info
4be44fcd
LB
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)) {
1da177e4
LT
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 *
4be44fcd 1472 */
1da177e4
LT
1473
1474static int acpi_video_device_enumerate(struct acpi_video_bus *video)
1475{
4be44fcd
LB
1476 int status;
1477 int count;
1478 int i;
1da177e4 1479 struct acpi_video_enumerated_device *active_device_list;
4be44fcd
LB
1480 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1481 union acpi_object *dod = NULL;
1482 union acpi_object *obj;
1da177e4 1483
90130268 1484 status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer);
1da177e4 1485 if (!ACPI_SUCCESS(status)) {
a6fc6720 1486 ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD"));
d550d98d 1487 return status;
1da177e4
LT
1488 }
1489
50dd0969 1490 dod = buffer.pointer;
1da177e4 1491 if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
a6fc6720 1492 ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data"));
1da177e4
LT
1493 status = -EFAULT;
1494 goto out;
1495 }
1496
1497 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
4be44fcd 1498 dod->package.count));
1da177e4 1499
4be44fcd
LB
1500 active_device_list = kmalloc((1 +
1501 dod->package.count) *
1502 sizeof(struct
1503 acpi_video_enumerated_device),
1504 GFP_KERNEL);
1da177e4
LT
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++) {
50dd0969 1513 obj = &dod->package.elements[i];
1da177e4
LT
1514
1515 if (obj->type != ACPI_TYPE_INTEGER) {
6468463a 1516 printk(KERN_ERR PREFIX "Invalid _DOD data\n");
4be44fcd
LB
1517 active_device_list[i].value.int_val =
1518 ACPI_VIDEO_HEAD_INVALID;
1da177e4
LT
1519 }
1520 active_device_list[i].value.int_val = obj->integer.value;
1521 active_device_list[i].bind_info = NULL;
4be44fcd
LB
1522 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i,
1523 (int)obj->integer.value));
1da177e4
LT
1524 count++;
1525 }
1526 active_device_list[count].value.int_val = ACPI_VIDEO_HEAD_END;
1527
6044ec88 1528 kfree(video->attached_array);
4be44fcd 1529
1da177e4
LT
1530 video->attached_array = active_device_list;
1531 video->attached_count = count;
4be44fcd 1532 out:
02438d87 1533 kfree(buffer.pointer);
d550d98d 1534 return status;
1da177e4
LT
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.
4be44fcd 1548 */
1da177e4 1549
4be44fcd 1550static int acpi_video_switch_output(struct acpi_video_bus *video, int event)
1da177e4 1551{
4be44fcd
LB
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;
1da177e4
LT
1556 unsigned long state;
1557 int status = 0;
1558
1da177e4
LT
1559
1560 list_for_each_safe(node, next, &video->video_device_list) {
7334571f 1561 dev = container_of(node, struct acpi_video_device, entry);
1da177e4 1562 status = acpi_video_device_get_state(dev, &state);
4be44fcd
LB
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);
1da177e4
LT
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);
4be44fcd 1575 out:
1da177e4
LT
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
d550d98d 1589 return status;
1da177e4
LT
1590}
1591
4be44fcd
LB
1592static int
1593acpi_video_get_next_level(struct acpi_video_device *device,
1594 u32 level_current, u32 event)
1da177e4 1595{
f4715189
TT
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 }
1da177e4
LT
1624}
1625
1da177e4 1626static void
4be44fcd 1627acpi_video_switch_brightness(struct acpi_video_device *device, int event)
1da177e4
LT
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
4be44fcd
LB
1636acpi_video_bus_get_devices(struct acpi_video_bus *video,
1637 struct acpi_device *device)
1da177e4 1638{
4be44fcd
LB
1639 int status = 0;
1640 struct list_head *node, *next;
1da177e4 1641
1da177e4
LT
1642
1643 acpi_video_device_enumerate(video);
1644
1645 list_for_each_safe(node, next, &device->children) {
4be44fcd
LB
1646 struct acpi_device *dev =
1647 list_entry(node, struct acpi_device, node);
1da177e4
LT
1648
1649 if (!dev)
1650 continue;
1651
1652 status = acpi_video_bus_get_one_device(dev, video);
1653 if (ACPI_FAILURE(status)) {
a6fc6720 1654 ACPI_EXCEPTION((AE_INFO, status, "Cant attach device"));
1da177e4
LT
1655 continue;
1656 }
1657
1658 }
d550d98d 1659 return status;
1da177e4
LT
1660}
1661
4be44fcd 1662static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
1da177e4 1663{
031ec77b 1664 acpi_status status;
1da177e4
LT
1665 struct acpi_video_bus *video;
1666
1da177e4
LT
1667
1668 if (!device || !device->video)
d550d98d 1669 return -ENOENT;
1da177e4
LT
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
90130268 1678 status = acpi_remove_notify_handler(device->dev->handle,
4be44fcd
LB
1679 ACPI_DEVICE_NOTIFY,
1680 acpi_video_device_notify);
2f3d000a
YL
1681 if (device->backlight){
1682 backlight_device_unregister(device->backlight);
1683 kfree(device->data);
1684 }
d550d98d 1685 return 0;
1da177e4
LT
1686}
1687
4be44fcd 1688static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
1da177e4 1689{
4be44fcd
LB
1690 int status;
1691 struct list_head *node, *next;
1da177e4 1692
1da177e4
LT
1693
1694 list_for_each_safe(node, next, &video->video_device_list) {
4be44fcd
LB
1695 struct acpi_video_device *data =
1696 list_entry(node, struct acpi_video_device, entry);
1da177e4
LT
1697 if (!data)
1698 continue;
1699
1700 status = acpi_video_bus_put_one_device(data);
4be44fcd
LB
1701 if (ACPI_FAILURE(status))
1702 printk(KERN_WARNING PREFIX
1703 "hhuuhhuu bug in acpi video driver.\n");
1da177e4 1704
d384ea69 1705 if (data->brightness)
973bf491 1706 kfree(data->brightness->levels);
6044ec88 1707 kfree(data->brightness);
1da177e4
LT
1708 kfree(data);
1709 }
1710
d550d98d 1711 return 0;
1da177e4
LT
1712}
1713
1714/* acpi_video interface */
1715
4be44fcd 1716static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
1da177e4
LT
1717{
1718 return acpi_video_bus_DOS(video, 1, 0);
1719}
1720
4be44fcd 1721static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
1da177e4
LT
1722{
1723 return acpi_video_bus_DOS(video, 0, 1);
1724}
1725
4be44fcd 1726static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
1da177e4 1727{
50dd0969 1728 struct acpi_video_bus *video = data;
4be44fcd 1729 struct acpi_device *device = NULL;
1da177e4 1730
1da177e4
LT
1731 printk("video bus notify\n");
1732
1733 if (!video)
d550d98d 1734 return;
1da177e4 1735
e6afa0de 1736 device = video->device;
1da177e4
LT
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
4be44fcd
LB
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. */
1da177e4
LT
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,
4be44fcd 1761 "Unsupported event [0x%x]\n", event));
1da177e4
LT
1762 break;
1763 }
1764
d550d98d 1765 return;
1da177e4
LT
1766}
1767
4be44fcd 1768static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
1da177e4 1769{
50dd0969 1770 struct acpi_video_device *video_device = data;
4be44fcd 1771 struct acpi_device *device = NULL;
1da177e4 1772
1da177e4 1773 if (!video_device)
d550d98d 1774 return;
1da177e4 1775
e6afa0de 1776 device = video_device->dev;
1da177e4
LT
1777
1778 switch (event) {
4be44fcd
LB
1779 case ACPI_VIDEO_NOTIFY_SWITCH: /* change in status (cycle output device) */
1780 case ACPI_VIDEO_NOTIFY_PROBE: /* change in status (output device status) */
1da177e4
LT
1781 acpi_bus_generate_event(device, event, 0);
1782 break;
4be44fcd
LB
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);
1da177e4
LT
1789 acpi_bus_generate_event(device, event, 0);
1790 break;
1791 default:
1792 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
4be44fcd 1793 "Unsupported event [0x%x]\n", event));
1da177e4
LT
1794 break;
1795 }
d550d98d 1796 return;
1da177e4
LT
1797}
1798
4be44fcd 1799static int acpi_video_bus_add(struct acpi_device *device)
1da177e4 1800{
4be44fcd
LB
1801 int result = 0;
1802 acpi_status status = 0;
1803 struct acpi_video_bus *video = NULL;
1da177e4 1804
4be44fcd 1805
1da177e4 1806 if (!device)
d550d98d 1807 return -EINVAL;
1da177e4 1808
36bcbec7 1809 video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
1da177e4 1810 if (!video)
d550d98d 1811 return -ENOMEM;
1da177e4 1812
e6afa0de 1813 video->device = device;
1da177e4
LT
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
90130268 1833 status = acpi_install_notify_handler(device->handle,
4be44fcd
LB
1834 ACPI_DEVICE_NOTIFY,
1835 acpi_video_bus_notify, video);
1da177e4
LT
1836 if (ACPI_FAILURE(status)) {
1837 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
4be44fcd 1838 "Error installing notify handler\n"));
973bf491
YL
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);
1da177e4
LT
1843 result = -ENODEV;
1844 goto end;
1845 }
1846
1847 printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s rom: %s post: %s)\n",
4be44fcd
LB
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");
1da177e4 1852
4be44fcd 1853 end:
973bf491 1854 if (result)
1da177e4 1855 kfree(video);
1da177e4 1856
d550d98d 1857 return result;
1da177e4
LT
1858}
1859
4be44fcd 1860static int acpi_video_bus_remove(struct acpi_device *device, int type)
1da177e4 1861{
4be44fcd
LB
1862 acpi_status status = 0;
1863 struct acpi_video_bus *video = NULL;
1da177e4 1864
1da177e4
LT
1865
1866 if (!device || !acpi_driver_data(device))
d550d98d 1867 return -EINVAL;
1da177e4 1868
50dd0969 1869 video = acpi_driver_data(device);
1da177e4
LT
1870
1871 acpi_video_bus_stop_devices(video);
1872
90130268 1873 status = acpi_remove_notify_handler(video->device->handle,
4be44fcd
LB
1874 ACPI_DEVICE_NOTIFY,
1875 acpi_video_bus_notify);
1da177e4
LT
1876
1877 acpi_video_bus_put_devices(video);
1878 acpi_video_bus_remove_fs(device);
1879
6044ec88 1880 kfree(video->attached_array);
1da177e4
LT
1881 kfree(video);
1882
d550d98d 1883 return 0;
1da177e4
LT
1884}
1885
4be44fcd 1886static int __init acpi_video_init(void)
1da177e4 1887{
4be44fcd 1888 int result = 0;
1da177e4 1889
1da177e4
LT
1890
1891 /*
4be44fcd
LB
1892 acpi_dbg_level = 0xFFFFFFFF;
1893 acpi_dbg_layer = 0x08000000;
1894 */
1da177e4
LT
1895
1896 acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
1897 if (!acpi_video_dir)
d550d98d 1898 return -ENODEV;
1da177e4
LT
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);
d550d98d 1904 return -ENODEV;
1da177e4
LT
1905 }
1906
d550d98d 1907 return 0;
1da177e4
LT
1908}
1909
4be44fcd 1910static void __exit acpi_video_exit(void)
1da177e4 1911{
1da177e4
LT
1912
1913 acpi_bus_unregister_driver(&acpi_video_bus);
1914
1915 remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
1916
d550d98d 1917 return;
1da177e4
LT
1918}
1919
1920module_init(acpi_video_init);
1921module_exit(acpi_video_exit);