diff options
Diffstat (limited to 'drivers/acpi/video.c')
-rw-r--r-- | drivers/acpi/video.c | 336 |
1 files changed, 256 insertions, 80 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 67cc36dc9b82..ab06143672bc 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #include <linux/thermal.h> | 37 | #include <linux/thermal.h> |
38 | #include <linux/video_output.h> | 38 | #include <linux/video_output.h> |
39 | #include <linux/sort.h> | 39 | #include <linux/sort.h> |
40 | #include <linux/pci.h> | ||
41 | #include <linux/pci_ids.h> | ||
40 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
41 | 43 | ||
42 | #include <acpi/acpi_bus.h> | 44 | #include <acpi/acpi_bus.h> |
@@ -162,16 +164,26 @@ struct acpi_video_device_cap { | |||
162 | u8 _BCL:1; /*Query list of brightness control levels supported */ | 164 | u8 _BCL:1; /*Query list of brightness control levels supported */ |
163 | u8 _BCM:1; /*Set the brightness level */ | 165 | u8 _BCM:1; /*Set the brightness level */ |
164 | u8 _BQC:1; /* Get current brightness level */ | 166 | u8 _BQC:1; /* Get current brightness level */ |
167 | u8 _BCQ:1; /* Some buggy BIOS uses _BCQ instead of _BQC */ | ||
165 | u8 _DDC:1; /*Return the EDID for this device */ | 168 | u8 _DDC:1; /*Return the EDID for this device */ |
166 | u8 _DCS:1; /*Return status of output device */ | 169 | u8 _DCS:1; /*Return status of output device */ |
167 | u8 _DGS:1; /*Query graphics state */ | 170 | u8 _DGS:1; /*Query graphics state */ |
168 | u8 _DSS:1; /*Device state set */ | 171 | u8 _DSS:1; /*Device state set */ |
169 | }; | 172 | }; |
170 | 173 | ||
174 | struct acpi_video_brightness_flags { | ||
175 | u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */ | ||
176 | u8 _BCL_reversed:1; /* _BCL package is in a reversed order*/ | ||
177 | u8 _BCL_use_index:1; /* levels in _BCL are index values */ | ||
178 | u8 _BCM_use_index:1; /* input of _BCM is an index value */ | ||
179 | u8 _BQC_use_index:1; /* _BQC returns an index value */ | ||
180 | }; | ||
181 | |||
171 | struct acpi_video_device_brightness { | 182 | struct acpi_video_device_brightness { |
172 | int curr; | 183 | int curr; |
173 | int count; | 184 | int count; |
174 | int *levels; | 185 | int *levels; |
186 | struct acpi_video_brightness_flags flags; | ||
175 | }; | 187 | }; |
176 | 188 | ||
177 | struct acpi_video_device { | 189 | struct acpi_video_device { |
@@ -189,7 +201,7 @@ struct acpi_video_device { | |||
189 | 201 | ||
190 | /* bus */ | 202 | /* bus */ |
191 | static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file); | 203 | static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file); |
192 | static struct file_operations acpi_video_bus_info_fops = { | 204 | static const struct file_operations acpi_video_bus_info_fops = { |
193 | .owner = THIS_MODULE, | 205 | .owner = THIS_MODULE, |
194 | .open = acpi_video_bus_info_open_fs, | 206 | .open = acpi_video_bus_info_open_fs, |
195 | .read = seq_read, | 207 | .read = seq_read, |
@@ -198,7 +210,7 @@ static struct file_operations acpi_video_bus_info_fops = { | |||
198 | }; | 210 | }; |
199 | 211 | ||
200 | static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file); | 212 | static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file); |
201 | static struct file_operations acpi_video_bus_ROM_fops = { | 213 | static const struct file_operations acpi_video_bus_ROM_fops = { |
202 | .owner = THIS_MODULE, | 214 | .owner = THIS_MODULE, |
203 | .open = acpi_video_bus_ROM_open_fs, | 215 | .open = acpi_video_bus_ROM_open_fs, |
204 | .read = seq_read, | 216 | .read = seq_read, |
@@ -208,7 +220,7 @@ static struct file_operations acpi_video_bus_ROM_fops = { | |||
208 | 220 | ||
209 | static int acpi_video_bus_POST_info_open_fs(struct inode *inode, | 221 | static int acpi_video_bus_POST_info_open_fs(struct inode *inode, |
210 | struct file *file); | 222 | struct file *file); |
211 | static struct file_operations acpi_video_bus_POST_info_fops = { | 223 | static const struct file_operations acpi_video_bus_POST_info_fops = { |
212 | .owner = THIS_MODULE, | 224 | .owner = THIS_MODULE, |
213 | .open = acpi_video_bus_POST_info_open_fs, | 225 | .open = acpi_video_bus_POST_info_open_fs, |
214 | .read = seq_read, | 226 | .read = seq_read, |
@@ -217,19 +229,25 @@ static struct file_operations acpi_video_bus_POST_info_fops = { | |||
217 | }; | 229 | }; |
218 | 230 | ||
219 | static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file); | 231 | static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file); |
220 | static struct file_operations acpi_video_bus_POST_fops = { | 232 | static ssize_t acpi_video_bus_write_POST(struct file *file, |
233 | const char __user *buffer, size_t count, loff_t *data); | ||
234 | static const struct file_operations acpi_video_bus_POST_fops = { | ||
221 | .owner = THIS_MODULE, | 235 | .owner = THIS_MODULE, |
222 | .open = acpi_video_bus_POST_open_fs, | 236 | .open = acpi_video_bus_POST_open_fs, |
223 | .read = seq_read, | 237 | .read = seq_read, |
238 | .write = acpi_video_bus_write_POST, | ||
224 | .llseek = seq_lseek, | 239 | .llseek = seq_lseek, |
225 | .release = single_release, | 240 | .release = single_release, |
226 | }; | 241 | }; |
227 | 242 | ||
228 | static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file); | 243 | static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file); |
229 | static struct file_operations acpi_video_bus_DOS_fops = { | 244 | static ssize_t acpi_video_bus_write_DOS(struct file *file, |
245 | const char __user *buffer, size_t count, loff_t *data); | ||
246 | static const struct file_operations acpi_video_bus_DOS_fops = { | ||
230 | .owner = THIS_MODULE, | 247 | .owner = THIS_MODULE, |
231 | .open = acpi_video_bus_DOS_open_fs, | 248 | .open = acpi_video_bus_DOS_open_fs, |
232 | .read = seq_read, | 249 | .read = seq_read, |
250 | .write = acpi_video_bus_write_DOS, | ||
233 | .llseek = seq_lseek, | 251 | .llseek = seq_lseek, |
234 | .release = single_release, | 252 | .release = single_release, |
235 | }; | 253 | }; |
@@ -237,7 +255,7 @@ static struct file_operations acpi_video_bus_DOS_fops = { | |||
237 | /* device */ | 255 | /* device */ |
238 | static int acpi_video_device_info_open_fs(struct inode *inode, | 256 | static int acpi_video_device_info_open_fs(struct inode *inode, |
239 | struct file *file); | 257 | struct file *file); |
240 | static struct file_operations acpi_video_device_info_fops = { | 258 | static const struct file_operations acpi_video_device_info_fops = { |
241 | .owner = THIS_MODULE, | 259 | .owner = THIS_MODULE, |
242 | .open = acpi_video_device_info_open_fs, | 260 | .open = acpi_video_device_info_open_fs, |
243 | .read = seq_read, | 261 | .read = seq_read, |
@@ -247,27 +265,33 @@ static struct file_operations acpi_video_device_info_fops = { | |||
247 | 265 | ||
248 | static int acpi_video_device_state_open_fs(struct inode *inode, | 266 | static int acpi_video_device_state_open_fs(struct inode *inode, |
249 | struct file *file); | 267 | struct file *file); |
250 | static struct file_operations acpi_video_device_state_fops = { | 268 | static ssize_t acpi_video_device_write_state(struct file *file, |
269 | const char __user *buffer, size_t count, loff_t *data); | ||
270 | static const struct file_operations acpi_video_device_state_fops = { | ||
251 | .owner = THIS_MODULE, | 271 | .owner = THIS_MODULE, |
252 | .open = acpi_video_device_state_open_fs, | 272 | .open = acpi_video_device_state_open_fs, |
253 | .read = seq_read, | 273 | .read = seq_read, |
274 | .write = acpi_video_device_write_state, | ||
254 | .llseek = seq_lseek, | 275 | .llseek = seq_lseek, |
255 | .release = single_release, | 276 | .release = single_release, |
256 | }; | 277 | }; |
257 | 278 | ||
258 | static int acpi_video_device_brightness_open_fs(struct inode *inode, | 279 | static int acpi_video_device_brightness_open_fs(struct inode *inode, |
259 | struct file *file); | 280 | struct file *file); |
281 | static ssize_t acpi_video_device_write_brightness(struct file *file, | ||
282 | const char __user *buffer, size_t count, loff_t *data); | ||
260 | static struct file_operations acpi_video_device_brightness_fops = { | 283 | static struct file_operations acpi_video_device_brightness_fops = { |
261 | .owner = THIS_MODULE, | 284 | .owner = THIS_MODULE, |
262 | .open = acpi_video_device_brightness_open_fs, | 285 | .open = acpi_video_device_brightness_open_fs, |
263 | .read = seq_read, | 286 | .read = seq_read, |
287 | .write = acpi_video_device_write_brightness, | ||
264 | .llseek = seq_lseek, | 288 | .llseek = seq_lseek, |
265 | .release = single_release, | 289 | .release = single_release, |
266 | }; | 290 | }; |
267 | 291 | ||
268 | static int acpi_video_device_EDID_open_fs(struct inode *inode, | 292 | static int acpi_video_device_EDID_open_fs(struct inode *inode, |
269 | struct file *file); | 293 | struct file *file); |
270 | static struct file_operations acpi_video_device_EDID_fops = { | 294 | static const struct file_operations acpi_video_device_EDID_fops = { |
271 | .owner = THIS_MODULE, | 295 | .owner = THIS_MODULE, |
272 | .open = acpi_video_device_EDID_open_fs, | 296 | .open = acpi_video_device_EDID_open_fs, |
273 | .read = seq_read, | 297 | .read = seq_read, |
@@ -275,7 +299,7 @@ static struct file_operations acpi_video_device_EDID_fops = { | |||
275 | .release = single_release, | 299 | .release = single_release, |
276 | }; | 300 | }; |
277 | 301 | ||
278 | static char device_decode[][30] = { | 302 | static const char device_decode[][30] = { |
279 | "motherboard VGA device", | 303 | "motherboard VGA device", |
280 | "PCI VGA device", | 304 | "PCI VGA device", |
281 | "AGP VGA device", | 305 | "AGP VGA device", |
@@ -294,7 +318,7 @@ static int acpi_video_device_lcd_get_level_current( | |||
294 | unsigned long long *level); | 318 | unsigned long long *level); |
295 | static int acpi_video_get_next_level(struct acpi_video_device *device, | 319 | static int acpi_video_get_next_level(struct acpi_video_device *device, |
296 | u32 level_current, u32 event); | 320 | u32 level_current, u32 event); |
297 | static void acpi_video_switch_brightness(struct acpi_video_device *device, | 321 | static int acpi_video_switch_brightness(struct acpi_video_device *device, |
298 | int event); | 322 | int event); |
299 | static int acpi_video_device_get_state(struct acpi_video_device *device, | 323 | static int acpi_video_device_get_state(struct acpi_video_device *device, |
300 | unsigned long long *state); | 324 | unsigned long long *state); |
@@ -308,7 +332,9 @@ static int acpi_video_get_brightness(struct backlight_device *bd) | |||
308 | int i; | 332 | int i; |
309 | struct acpi_video_device *vd = | 333 | struct acpi_video_device *vd = |
310 | (struct acpi_video_device *)bl_get_data(bd); | 334 | (struct acpi_video_device *)bl_get_data(bd); |
311 | acpi_video_device_lcd_get_level_current(vd, &cur_level); | 335 | |
336 | if (acpi_video_device_lcd_get_level_current(vd, &cur_level)) | ||
337 | return -EINVAL; | ||
312 | for (i = 2; i < vd->brightness->count; i++) { | 338 | for (i = 2; i < vd->brightness->count; i++) { |
313 | if (vd->brightness->levels[i] == cur_level) | 339 | if (vd->brightness->levels[i] == cur_level) |
314 | /* The first two entries are special - see page 575 | 340 | /* The first two entries are special - see page 575 |
@@ -320,12 +346,12 @@ static int acpi_video_get_brightness(struct backlight_device *bd) | |||
320 | 346 | ||
321 | static int acpi_video_set_brightness(struct backlight_device *bd) | 347 | static int acpi_video_set_brightness(struct backlight_device *bd) |
322 | { | 348 | { |
323 | int request_level = bd->props.brightness+2; | 349 | int request_level = bd->props.brightness + 2; |
324 | struct acpi_video_device *vd = | 350 | struct acpi_video_device *vd = |
325 | (struct acpi_video_device *)bl_get_data(bd); | 351 | (struct acpi_video_device *)bl_get_data(bd); |
326 | acpi_video_device_lcd_set_level(vd, | 352 | |
327 | vd->brightness->levels[request_level]); | 353 | return acpi_video_device_lcd_set_level(vd, |
328 | return 0; | 354 | vd->brightness->levels[request_level]); |
329 | } | 355 | } |
330 | 356 | ||
331 | static struct backlight_ops acpi_backlight_ops = { | 357 | static struct backlight_ops acpi_backlight_ops = { |
@@ -358,32 +384,37 @@ static struct output_properties acpi_output_properties = { | |||
358 | 384 | ||
359 | 385 | ||
360 | /* thermal cooling device callbacks */ | 386 | /* thermal cooling device callbacks */ |
361 | static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf) | 387 | static int video_get_max_state(struct thermal_cooling_device *cdev, unsigned |
388 | long *state) | ||
362 | { | 389 | { |
363 | struct acpi_device *device = cdev->devdata; | 390 | struct acpi_device *device = cdev->devdata; |
364 | struct acpi_video_device *video = acpi_driver_data(device); | 391 | struct acpi_video_device *video = acpi_driver_data(device); |
365 | 392 | ||
366 | return sprintf(buf, "%d\n", video->brightness->count - 3); | 393 | *state = video->brightness->count - 3; |
394 | return 0; | ||
367 | } | 395 | } |
368 | 396 | ||
369 | static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf) | 397 | static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned |
398 | long *state) | ||
370 | { | 399 | { |
371 | struct acpi_device *device = cdev->devdata; | 400 | struct acpi_device *device = cdev->devdata; |
372 | struct acpi_video_device *video = acpi_driver_data(device); | 401 | struct acpi_video_device *video = acpi_driver_data(device); |
373 | unsigned long long level; | 402 | unsigned long long level; |
374 | int state; | 403 | int offset; |
375 | 404 | ||
376 | acpi_video_device_lcd_get_level_current(video, &level); | 405 | if (acpi_video_device_lcd_get_level_current(video, &level)) |
377 | for (state = 2; state < video->brightness->count; state++) | 406 | return -EINVAL; |
378 | if (level == video->brightness->levels[state]) | 407 | for (offset = 2; offset < video->brightness->count; offset++) |
379 | return sprintf(buf, "%d\n", | 408 | if (level == video->brightness->levels[offset]) { |
380 | video->brightness->count - state - 1); | 409 | *state = video->brightness->count - offset - 1; |
410 | return 0; | ||
411 | } | ||
381 | 412 | ||
382 | return -EINVAL; | 413 | return -EINVAL; |
383 | } | 414 | } |
384 | 415 | ||
385 | static int | 416 | static int |
386 | video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) | 417 | video_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) |
387 | { | 418 | { |
388 | struct acpi_device *device = cdev->devdata; | 419 | struct acpi_device *device = cdev->devdata; |
389 | struct acpi_video_device *video = acpi_driver_data(device); | 420 | struct acpi_video_device *video = acpi_driver_data(device); |
@@ -479,34 +510,68 @@ acpi_video_device_lcd_query_levels(struct acpi_video_device *device, | |||
479 | static int | 510 | static int |
480 | acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) | 511 | acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) |
481 | { | 512 | { |
482 | int status = AE_OK; | 513 | int status; |
483 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 514 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
484 | struct acpi_object_list args = { 1, &arg0 }; | 515 | struct acpi_object_list args = { 1, &arg0 }; |
485 | int state; | 516 | int state; |
486 | 517 | ||
487 | |||
488 | arg0.integer.value = level; | 518 | arg0.integer.value = level; |
489 | 519 | ||
490 | if (device->cap._BCM) | 520 | status = acpi_evaluate_object(device->dev->handle, "_BCM", |
491 | status = acpi_evaluate_object(device->dev->handle, "_BCM", | 521 | &args, NULL); |
492 | &args, NULL); | 522 | if (ACPI_FAILURE(status)) { |
523 | ACPI_ERROR((AE_INFO, "Evaluating _BCM failed")); | ||
524 | return -EIO; | ||
525 | } | ||
526 | |||
493 | device->brightness->curr = level; | 527 | device->brightness->curr = level; |
494 | for (state = 2; state < device->brightness->count; state++) | 528 | for (state = 2; state < device->brightness->count; state++) |
495 | if (level == device->brightness->levels[state]) | 529 | if (level == device->brightness->levels[state]) { |
496 | device->backlight->props.brightness = state - 2; | 530 | if (device->backlight) |
531 | device->backlight->props.brightness = state - 2; | ||
532 | return 0; | ||
533 | } | ||
497 | 534 | ||
498 | return status; | 535 | ACPI_ERROR((AE_INFO, "Current brightness invalid")); |
536 | return -EINVAL; | ||
499 | } | 537 | } |
500 | 538 | ||
501 | static int | 539 | static int |
502 | acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, | 540 | acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, |
503 | unsigned long long *level) | 541 | unsigned long long *level) |
504 | { | 542 | { |
505 | if (device->cap._BQC) | 543 | acpi_status status = AE_OK; |
506 | return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, | 544 | |
507 | level); | 545 | if (device->cap._BQC || device->cap._BCQ) { |
546 | char *buf = device->cap._BQC ? "_BQC" : "_BCQ"; | ||
547 | |||
548 | status = acpi_evaluate_integer(device->dev->handle, buf, | ||
549 | NULL, level); | ||
550 | if (ACPI_SUCCESS(status)) { | ||
551 | if (device->brightness->flags._BQC_use_index) { | ||
552 | if (device->brightness->flags._BCL_reversed) | ||
553 | *level = device->brightness->count | ||
554 | - 3 - (*level); | ||
555 | *level = device->brightness->levels[*level + 2]; | ||
556 | |||
557 | } | ||
558 | device->brightness->curr = *level; | ||
559 | return 0; | ||
560 | } else { | ||
561 | /* Fixme: | ||
562 | * should we return an error or ignore this failure? | ||
563 | * dev->brightness->curr is a cached value which stores | ||
564 | * the correct current backlight level in most cases. | ||
565 | * ACPI video backlight still works w/ buggy _BQC. | ||
566 | * http://bugzilla.kernel.org/show_bug.cgi?id=12233 | ||
567 | */ | ||
568 | ACPI_WARNING((AE_INFO, "Evaluating %s failed", buf)); | ||
569 | device->cap._BQC = device->cap._BCQ = 0; | ||
570 | } | ||
571 | } | ||
572 | |||
508 | *level = device->brightness->curr; | 573 | *level = device->brightness->curr; |
509 | return AE_OK; | 574 | return 0; |
510 | } | 575 | } |
511 | 576 | ||
512 | static int | 577 | static int |
@@ -655,9 +720,11 @@ static int | |||
655 | acpi_video_init_brightness(struct acpi_video_device *device) | 720 | acpi_video_init_brightness(struct acpi_video_device *device) |
656 | { | 721 | { |
657 | union acpi_object *obj = NULL; | 722 | union acpi_object *obj = NULL; |
658 | int i, max_level = 0, count = 0; | 723 | int i, max_level = 0, count = 0, level_ac_battery = 0; |
724 | unsigned long long level, level_old; | ||
659 | union acpi_object *o; | 725 | union acpi_object *o; |
660 | struct acpi_video_device_brightness *br = NULL; | 726 | struct acpi_video_device_brightness *br = NULL; |
727 | int result = -EINVAL; | ||
661 | 728 | ||
662 | if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { | 729 | if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { |
663 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " | 730 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " |
@@ -671,13 +738,16 @@ acpi_video_init_brightness(struct acpi_video_device *device) | |||
671 | br = kzalloc(sizeof(*br), GFP_KERNEL); | 738 | br = kzalloc(sizeof(*br), GFP_KERNEL); |
672 | if (!br) { | 739 | if (!br) { |
673 | printk(KERN_ERR "can't allocate memory\n"); | 740 | printk(KERN_ERR "can't allocate memory\n"); |
741 | result = -ENOMEM; | ||
674 | goto out; | 742 | goto out; |
675 | } | 743 | } |
676 | 744 | ||
677 | br->levels = kmalloc(obj->package.count * sizeof *(br->levels), | 745 | br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels), |
678 | GFP_KERNEL); | 746 | GFP_KERNEL); |
679 | if (!br->levels) | 747 | if (!br->levels) { |
748 | result = -ENOMEM; | ||
680 | goto out_free; | 749 | goto out_free; |
750 | } | ||
681 | 751 | ||
682 | for (i = 0; i < obj->package.count; i++) { | 752 | for (i = 0; i < obj->package.count; i++) { |
683 | o = (union acpi_object *)&obj->package.elements[i]; | 753 | o = (union acpi_object *)&obj->package.elements[i]; |
@@ -692,18 +762,86 @@ acpi_video_init_brightness(struct acpi_video_device *device) | |||
692 | count++; | 762 | count++; |
693 | } | 763 | } |
694 | 764 | ||
695 | /* don't sort the first two brightness levels */ | 765 | /* |
696 | sort(&br->levels[2], count - 2, sizeof(br->levels[2]), | 766 | * some buggy BIOS don't export the levels |
697 | acpi_video_cmp_level, NULL); | 767 | * when machine is on AC/Battery in _BCL package. |
698 | 768 | * In this case, the first two elements in _BCL packages | |
699 | if (count < 2) | 769 | * are also supported brightness levels that OS should take care of. |
700 | goto out_free_levels; | 770 | */ |
771 | for (i = 2; i < count; i++) | ||
772 | if (br->levels[i] == br->levels[0] || | ||
773 | br->levels[i] == br->levels[1]) | ||
774 | level_ac_battery++; | ||
775 | |||
776 | if (level_ac_battery < 2) { | ||
777 | level_ac_battery = 2 - level_ac_battery; | ||
778 | br->flags._BCL_no_ac_battery_levels = 1; | ||
779 | for (i = (count - 1 + level_ac_battery); i >= 2; i--) | ||
780 | br->levels[i] = br->levels[i - level_ac_battery]; | ||
781 | count += level_ac_battery; | ||
782 | } else if (level_ac_battery > 2) | ||
783 | ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package\n")); | ||
784 | |||
785 | /* Check if the _BCL package is in a reversed order */ | ||
786 | if (max_level == br->levels[2]) { | ||
787 | br->flags._BCL_reversed = 1; | ||
788 | sort(&br->levels[2], count - 2, sizeof(br->levels[2]), | ||
789 | acpi_video_cmp_level, NULL); | ||
790 | } else if (max_level != br->levels[count - 1]) | ||
791 | ACPI_ERROR((AE_INFO, | ||
792 | "Found unordered _BCL package\n")); | ||
701 | 793 | ||
702 | br->count = count; | 794 | br->count = count; |
703 | device->brightness = br; | 795 | device->brightness = br; |
704 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count)); | 796 | |
797 | /* Check the input/output of _BQC/_BCL/_BCM */ | ||
798 | if ((max_level < 100) && (max_level <= (count - 2))) | ||
799 | br->flags._BCL_use_index = 1; | ||
800 | |||
801 | /* | ||
802 | * _BCM is always consistent with _BCL, | ||
803 | * at least for all the laptops we have ever seen. | ||
804 | */ | ||
805 | br->flags._BCM_use_index = br->flags._BCL_use_index; | ||
806 | |||
807 | /* _BQC uses INDEX while _BCL uses VALUE in some laptops */ | ||
808 | br->curr = max_level; | ||
809 | result = acpi_video_device_lcd_get_level_current(device, &level_old); | ||
810 | if (result) | ||
811 | goto out_free_levels; | ||
812 | |||
813 | result = acpi_video_device_lcd_set_level(device, br->curr); | ||
814 | if (result) | ||
815 | goto out_free_levels; | ||
816 | |||
817 | result = acpi_video_device_lcd_get_level_current(device, &level); | ||
818 | if (result) | ||
819 | goto out_free_levels; | ||
820 | |||
821 | if ((level != level_old) && !br->flags._BCM_use_index) { | ||
822 | /* Note: | ||
823 | * This piece of code does not work correctly if the current | ||
824 | * brightness levels is 0. | ||
825 | * But I guess boxes that boot with such a dark screen are rare | ||
826 | * and no more code is needed to cover this specifial case. | ||
827 | */ | ||
828 | |||
829 | if (level_ac_battery != 2) { | ||
830 | /* | ||
831 | * For now, we don't support the _BCL like this: | ||
832 | * 16, 15, 0, 1, 2, 3, ..., 14, 15, 16 | ||
833 | * because we may mess up the index returned by _BQC. | ||
834 | * Plus: we have not got a box like this. | ||
835 | */ | ||
836 | ACPI_ERROR((AE_INFO, "_BCL not supported\n")); | ||
837 | } | ||
838 | br->flags._BQC_use_index = 1; | ||
839 | } | ||
840 | |||
841 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
842 | "found %d brightness levels\n", count - 2)); | ||
705 | kfree(obj); | 843 | kfree(obj); |
706 | return max_level; | 844 | return result; |
707 | 845 | ||
708 | out_free_levels: | 846 | out_free_levels: |
709 | kfree(br->levels); | 847 | kfree(br->levels); |
@@ -712,7 +850,7 @@ out_free: | |||
712 | out: | 850 | out: |
713 | device->brightness = NULL; | 851 | device->brightness = NULL; |
714 | kfree(obj); | 852 | kfree(obj); |
715 | return 0; | 853 | return result; |
716 | } | 854 | } |
717 | 855 | ||
718 | /* | 856 | /* |
@@ -729,7 +867,6 @@ out: | |||
729 | static void acpi_video_device_find_cap(struct acpi_video_device *device) | 867 | static void acpi_video_device_find_cap(struct acpi_video_device *device) |
730 | { | 868 | { |
731 | acpi_handle h_dummy1; | 869 | acpi_handle h_dummy1; |
732 | u32 max_level = 0; | ||
733 | 870 | ||
734 | 871 | ||
735 | memset(&device->cap, 0, sizeof(device->cap)); | 872 | memset(&device->cap, 0, sizeof(device->cap)); |
@@ -745,6 +882,12 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
745 | } | 882 | } |
746 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1))) | 883 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1))) |
747 | device->cap._BQC = 1; | 884 | device->cap._BQC = 1; |
885 | else if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCQ", | ||
886 | &h_dummy1))) { | ||
887 | printk(KERN_WARNING FW_BUG "_BCQ is used instead of _BQC\n"); | ||
888 | device->cap._BCQ = 1; | ||
889 | } | ||
890 | |||
748 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { | 891 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { |
749 | device->cap._DDC = 1; | 892 | device->cap._DDC = 1; |
750 | } | 893 | } |
@@ -758,13 +901,14 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
758 | device->cap._DSS = 1; | 901 | device->cap._DSS = 1; |
759 | } | 902 | } |
760 | 903 | ||
761 | if (acpi_video_backlight_support()) | 904 | if (acpi_video_backlight_support()) { |
762 | max_level = acpi_video_init_brightness(device); | ||
763 | |||
764 | if (device->cap._BCL && device->cap._BCM && max_level > 0) { | ||
765 | int result; | 905 | int result; |
766 | static int count = 0; | 906 | static int count = 0; |
767 | char *name; | 907 | char *name; |
908 | |||
909 | result = acpi_video_init_brightness(device); | ||
910 | if (result) | ||
911 | return; | ||
768 | name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); | 912 | name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); |
769 | if (!name) | 913 | if (!name) |
770 | return; | 914 | return; |
@@ -773,18 +917,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
773 | device->backlight = backlight_device_register(name, | 917 | device->backlight = backlight_device_register(name, |
774 | NULL, device, &acpi_backlight_ops); | 918 | NULL, device, &acpi_backlight_ops); |
775 | device->backlight->props.max_brightness = device->brightness->count-3; | 919 | device->backlight->props.max_brightness = device->brightness->count-3; |
776 | /* | ||
777 | * If there exists the _BQC object, the _BQC object will be | ||
778 | * called to get the current backlight brightness. Otherwise | ||
779 | * the brightness will be set to the maximum. | ||
780 | */ | ||
781 | if (device->cap._BQC) | ||
782 | device->backlight->props.brightness = | ||
783 | acpi_video_get_brightness(device->backlight); | ||
784 | else | ||
785 | device->backlight->props.brightness = | ||
786 | device->backlight->props.max_brightness; | ||
787 | backlight_update_status(device->backlight); | ||
788 | kfree(name); | 920 | kfree(name); |
789 | 921 | ||
790 | device->cdev = thermal_cooling_device_register("LCD", | 922 | device->cdev = thermal_cooling_device_register("LCD", |
@@ -1061,13 +1193,12 @@ acpi_video_device_write_brightness(struct file *file, | |||
1061 | /* validate through the list of available levels */ | 1193 | /* validate through the list of available levels */ |
1062 | for (i = 2; i < dev->brightness->count; i++) | 1194 | for (i = 2; i < dev->brightness->count; i++) |
1063 | if (level == dev->brightness->levels[i]) { | 1195 | if (level == dev->brightness->levels[i]) { |
1064 | if (ACPI_SUCCESS | 1196 | if (!acpi_video_device_lcd_set_level(dev, level)) |
1065 | (acpi_video_device_lcd_set_level(dev, level))) | 1197 | return count; |
1066 | dev->brightness->curr = level; | ||
1067 | break; | 1198 | break; |
1068 | } | 1199 | } |
1069 | 1200 | ||
1070 | return count; | 1201 | return -EINVAL; |
1071 | } | 1202 | } |
1072 | 1203 | ||
1073 | static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset) | 1204 | static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset) |
@@ -1132,7 +1263,6 @@ static int acpi_video_device_add_fs(struct acpi_device *device) | |||
1132 | goto err_remove_dir; | 1263 | goto err_remove_dir; |
1133 | 1264 | ||
1134 | /* 'state' [R/W] */ | 1265 | /* 'state' [R/W] */ |
1135 | acpi_video_device_state_fops.write = acpi_video_device_write_state; | ||
1136 | entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR, | 1266 | entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR, |
1137 | device_dir, | 1267 | device_dir, |
1138 | &acpi_video_device_state_fops, | 1268 | &acpi_video_device_state_fops, |
@@ -1141,8 +1271,6 @@ static int acpi_video_device_add_fs(struct acpi_device *device) | |||
1141 | goto err_remove_info; | 1271 | goto err_remove_info; |
1142 | 1272 | ||
1143 | /* 'brightness' [R/W] */ | 1273 | /* 'brightness' [R/W] */ |
1144 | acpi_video_device_brightness_fops.write = | ||
1145 | acpi_video_device_write_brightness; | ||
1146 | entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR, | 1274 | entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR, |
1147 | device_dir, | 1275 | device_dir, |
1148 | &acpi_video_device_brightness_fops, | 1276 | &acpi_video_device_brightness_fops, |
@@ -1423,7 +1551,6 @@ static int acpi_video_bus_add_fs(struct acpi_device *device) | |||
1423 | goto err_remove_rom; | 1551 | goto err_remove_rom; |
1424 | 1552 | ||
1425 | /* 'POST' [R/W] */ | 1553 | /* 'POST' [R/W] */ |
1426 | acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST; | ||
1427 | entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IWUSR, | 1554 | entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IWUSR, |
1428 | device_dir, | 1555 | device_dir, |
1429 | &acpi_video_bus_POST_fops, | 1556 | &acpi_video_bus_POST_fops, |
@@ -1432,7 +1559,6 @@ static int acpi_video_bus_add_fs(struct acpi_device *device) | |||
1432 | goto err_remove_post_info; | 1559 | goto err_remove_post_info; |
1433 | 1560 | ||
1434 | /* 'DOS' [R/W] */ | 1561 | /* 'DOS' [R/W] */ |
1435 | acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS; | ||
1436 | entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IWUSR, | 1562 | entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IWUSR, |
1437 | device_dir, | 1563 | device_dir, |
1438 | &acpi_video_bus_DOS_fops, | 1564 | &acpi_video_bus_DOS_fops, |
@@ -1745,15 +1871,29 @@ acpi_video_get_next_level(struct acpi_video_device *device, | |||
1745 | } | 1871 | } |
1746 | } | 1872 | } |
1747 | 1873 | ||
1748 | static void | 1874 | static int |
1749 | acpi_video_switch_brightness(struct acpi_video_device *device, int event) | 1875 | acpi_video_switch_brightness(struct acpi_video_device *device, int event) |
1750 | { | 1876 | { |
1751 | unsigned long long level_current, level_next; | 1877 | unsigned long long level_current, level_next; |
1878 | int result = -EINVAL; | ||
1879 | |||
1752 | if (!device->brightness) | 1880 | if (!device->brightness) |
1753 | return; | 1881 | goto out; |
1754 | acpi_video_device_lcd_get_level_current(device, &level_current); | 1882 | |
1883 | result = acpi_video_device_lcd_get_level_current(device, | ||
1884 | &level_current); | ||
1885 | if (result) | ||
1886 | goto out; | ||
1887 | |||
1755 | level_next = acpi_video_get_next_level(device, level_current, event); | 1888 | level_next = acpi_video_get_next_level(device, level_current, event); |
1756 | acpi_video_device_lcd_set_level(device, level_next); | 1889 | |
1890 | result = acpi_video_device_lcd_set_level(device, level_next); | ||
1891 | |||
1892 | out: | ||
1893 | if (result) | ||
1894 | printk(KERN_ERR PREFIX "Failed to switch the brightness\n"); | ||
1895 | |||
1896 | return result; | ||
1757 | } | 1897 | } |
1758 | 1898 | ||
1759 | static int | 1899 | static int |
@@ -2120,7 +2260,27 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) | |||
2120 | return 0; | 2260 | return 0; |
2121 | } | 2261 | } |
2122 | 2262 | ||
2123 | static int __init acpi_video_init(void) | 2263 | static int __init intel_opregion_present(void) |
2264 | { | ||
2265 | #if defined(CONFIG_DRM_I915) || defined(CONFIG_DRM_I915_MODULE) | ||
2266 | struct pci_dev *dev = NULL; | ||
2267 | u32 address; | ||
2268 | |||
2269 | for_each_pci_dev(dev) { | ||
2270 | if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) | ||
2271 | continue; | ||
2272 | if (dev->vendor != PCI_VENDOR_ID_INTEL) | ||
2273 | continue; | ||
2274 | pci_read_config_dword(dev, 0xfc, &address); | ||
2275 | if (!address) | ||
2276 | continue; | ||
2277 | return 1; | ||
2278 | } | ||
2279 | #endif | ||
2280 | return 0; | ||
2281 | } | ||
2282 | |||
2283 | int acpi_video_register(void) | ||
2124 | { | 2284 | { |
2125 | int result = 0; | 2285 | int result = 0; |
2126 | 2286 | ||
@@ -2136,6 +2296,22 @@ static int __init acpi_video_init(void) | |||
2136 | 2296 | ||
2137 | return 0; | 2297 | return 0; |
2138 | } | 2298 | } |
2299 | EXPORT_SYMBOL(acpi_video_register); | ||
2300 | |||
2301 | /* | ||
2302 | * This is kind of nasty. Hardware using Intel chipsets may require | ||
2303 | * the video opregion code to be run first in order to initialise | ||
2304 | * state before any ACPI video calls are made. To handle this we defer | ||
2305 | * registration of the video class until the opregion code has run. | ||
2306 | */ | ||
2307 | |||
2308 | static int __init acpi_video_init(void) | ||
2309 | { | ||
2310 | if (intel_opregion_present()) | ||
2311 | return 0; | ||
2312 | |||
2313 | return acpi_video_register(); | ||
2314 | } | ||
2139 | 2315 | ||
2140 | static void __exit acpi_video_exit(void) | 2316 | static void __exit acpi_video_exit(void) |
2141 | { | 2317 | { |