diff options
Diffstat (limited to 'drivers/video/fbmem.c')
-rw-r--r-- | drivers/video/fbmem.c | 131 |
1 files changed, 91 insertions, 40 deletions
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 28225265159a..38c2e2558f5e 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -354,59 +354,59 @@ static void fb_rotate_logo(struct fb_info *info, u8 *dst, | |||
354 | if (rotate == FB_ROTATE_UD) { | 354 | if (rotate == FB_ROTATE_UD) { |
355 | fb_rotate_logo_ud(image->data, dst, image->width, | 355 | fb_rotate_logo_ud(image->data, dst, image->width, |
356 | image->height); | 356 | image->height); |
357 | image->dx = info->var.xres - image->width; | 357 | image->dx = info->var.xres - image->width - image->dx; |
358 | image->dy = info->var.yres - image->height; | 358 | image->dy = info->var.yres - image->height - image->dy; |
359 | } else if (rotate == FB_ROTATE_CW) { | 359 | } else if (rotate == FB_ROTATE_CW) { |
360 | fb_rotate_logo_cw(image->data, dst, image->width, | 360 | fb_rotate_logo_cw(image->data, dst, image->width, |
361 | image->height); | 361 | image->height); |
362 | tmp = image->width; | 362 | tmp = image->width; |
363 | image->width = image->height; | 363 | image->width = image->height; |
364 | image->height = tmp; | 364 | image->height = tmp; |
365 | image->dx = info->var.xres - image->width; | 365 | tmp = image->dy; |
366 | image->dy = image->dx; | ||
367 | image->dx = info->var.xres - image->width - tmp; | ||
366 | } else if (rotate == FB_ROTATE_CCW) { | 368 | } else if (rotate == FB_ROTATE_CCW) { |
367 | fb_rotate_logo_ccw(image->data, dst, image->width, | 369 | fb_rotate_logo_ccw(image->data, dst, image->width, |
368 | image->height); | 370 | image->height); |
369 | tmp = image->width; | 371 | tmp = image->width; |
370 | image->width = image->height; | 372 | image->width = image->height; |
371 | image->height = tmp; | 373 | image->height = tmp; |
372 | image->dy = info->var.yres - image->height; | 374 | tmp = image->dx; |
375 | image->dx = image->dy; | ||
376 | image->dy = info->var.yres - image->height - tmp; | ||
373 | } | 377 | } |
374 | 378 | ||
375 | image->data = dst; | 379 | image->data = dst; |
376 | } | 380 | } |
377 | 381 | ||
378 | static void fb_do_show_logo(struct fb_info *info, struct fb_image *image, | 382 | static void fb_do_show_logo(struct fb_info *info, struct fb_image *image, |
379 | int rotate) | 383 | int rotate, unsigned int num) |
380 | { | 384 | { |
381 | int x; | 385 | unsigned int x; |
382 | 386 | ||
383 | if (rotate == FB_ROTATE_UR) { | 387 | if (rotate == FB_ROTATE_UR) { |
384 | for (x = 0; x < num_online_cpus() && | 388 | for (x = 0; |
385 | x * (fb_logo.logo->width + 8) <= | 389 | x < num && image->dx + image->width <= info->var.xres; |
386 | info->var.xres - fb_logo.logo->width; x++) { | 390 | x++) { |
387 | info->fbops->fb_imageblit(info, image); | 391 | info->fbops->fb_imageblit(info, image); |
388 | image->dx += fb_logo.logo->width + 8; | 392 | image->dx += image->width + 8; |
389 | } | 393 | } |
390 | } else if (rotate == FB_ROTATE_UD) { | 394 | } else if (rotate == FB_ROTATE_UD) { |
391 | for (x = 0; x < num_online_cpus() && | 395 | for (x = 0; x < num && image->dx >= 0; x++) { |
392 | x * (fb_logo.logo->width + 8) <= | ||
393 | info->var.xres - fb_logo.logo->width; x++) { | ||
394 | info->fbops->fb_imageblit(info, image); | 396 | info->fbops->fb_imageblit(info, image); |
395 | image->dx -= fb_logo.logo->width + 8; | 397 | image->dx -= image->width + 8; |
396 | } | 398 | } |
397 | } else if (rotate == FB_ROTATE_CW) { | 399 | } else if (rotate == FB_ROTATE_CW) { |
398 | for (x = 0; x < num_online_cpus() && | 400 | for (x = 0; |
399 | x * (fb_logo.logo->width + 8) <= | 401 | x < num && image->dy + image->height <= info->var.yres; |
400 | info->var.yres - fb_logo.logo->width; x++) { | 402 | x++) { |
401 | info->fbops->fb_imageblit(info, image); | 403 | info->fbops->fb_imageblit(info, image); |
402 | image->dy += fb_logo.logo->width + 8; | 404 | image->dy += image->height + 8; |
403 | } | 405 | } |
404 | } else if (rotate == FB_ROTATE_CCW) { | 406 | } else if (rotate == FB_ROTATE_CCW) { |
405 | for (x = 0; x < num_online_cpus() && | 407 | for (x = 0; x < num && image->dy >= 0; x++) { |
406 | x * (fb_logo.logo->width + 8) <= | ||
407 | info->var.yres - fb_logo.logo->width; x++) { | ||
408 | info->fbops->fb_imageblit(info, image); | 408 | info->fbops->fb_imageblit(info, image); |
409 | image->dy -= fb_logo.logo->width + 8; | 409 | image->dy -= image->height + 8; |
410 | } | 410 | } |
411 | } | 411 | } |
412 | } | 412 | } |
@@ -418,7 +418,8 @@ int fb_prepare_logo(struct fb_info *info, int rotate) | |||
418 | 418 | ||
419 | memset(&fb_logo, 0, sizeof(struct logo_data)); | 419 | memset(&fb_logo, 0, sizeof(struct logo_data)); |
420 | 420 | ||
421 | if (info->flags & FBINFO_MISC_TILEBLITTING) | 421 | if (info->flags & FBINFO_MISC_TILEBLITTING || |
422 | info->flags & FBINFO_MODULE) | ||
422 | return 0; | 423 | return 0; |
423 | 424 | ||
424 | if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { | 425 | if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { |
@@ -483,7 +484,8 @@ int fb_show_logo(struct fb_info *info, int rotate) | |||
483 | struct fb_image image; | 484 | struct fb_image image; |
484 | 485 | ||
485 | /* Return if the frame buffer is not mapped or suspended */ | 486 | /* Return if the frame buffer is not mapped or suspended */ |
486 | if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING) | 487 | if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING || |
488 | info->flags & FBINFO_MODULE) | ||
487 | return 0; | 489 | return 0; |
488 | 490 | ||
489 | image.depth = 8; | 491 | image.depth = 8; |
@@ -532,7 +534,7 @@ int fb_show_logo(struct fb_info *info, int rotate) | |||
532 | fb_rotate_logo(info, logo_rotate, &image, rotate); | 534 | fb_rotate_logo(info, logo_rotate, &image, rotate); |
533 | } | 535 | } |
534 | 536 | ||
535 | fb_do_show_logo(info, &image, rotate); | 537 | fb_do_show_logo(info, &image, rotate, num_online_cpus()); |
536 | 538 | ||
537 | kfree(palette); | 539 | kfree(palette); |
538 | if (saved_pseudo_palette != NULL) | 540 | if (saved_pseudo_palette != NULL) |
@@ -586,7 +588,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
586 | return -EPERM; | 588 | return -EPERM; |
587 | 589 | ||
588 | if (info->fbops->fb_read) | 590 | if (info->fbops->fb_read) |
589 | return info->fbops->fb_read(file, buf, count, ppos); | 591 | return info->fbops->fb_read(info, buf, count, ppos); |
590 | 592 | ||
591 | total_size = info->screen_size; | 593 | total_size = info->screen_size; |
592 | 594 | ||
@@ -661,7 +663,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
661 | return -EPERM; | 663 | return -EPERM; |
662 | 664 | ||
663 | if (info->fbops->fb_write) | 665 | if (info->fbops->fb_write) |
664 | return info->fbops->fb_write(file, buf, count, ppos); | 666 | return info->fbops->fb_write(info, buf, count, ppos); |
665 | 667 | ||
666 | total_size = info->screen_size; | 668 | total_size = info->screen_size; |
667 | 669 | ||
@@ -771,14 +773,37 @@ fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) | |||
771 | return 0; | 773 | return 0; |
772 | } | 774 | } |
773 | 775 | ||
776 | static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, | ||
777 | u32 activate) | ||
778 | { | ||
779 | struct fb_event event; | ||
780 | struct fb_blit_caps caps, fbcaps; | ||
781 | int err = 0; | ||
782 | |||
783 | memset(&caps, 0, sizeof(caps)); | ||
784 | memset(&fbcaps, 0, sizeof(fbcaps)); | ||
785 | caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0; | ||
786 | event.info = info; | ||
787 | event.data = ∩︀ | ||
788 | fb_notifier_call_chain(FB_EVENT_GET_REQ, &event); | ||
789 | info->fbops->fb_get_caps(info, &fbcaps, var); | ||
790 | |||
791 | if (((fbcaps.x ^ caps.x) & caps.x) || | ||
792 | ((fbcaps.y ^ caps.y) & caps.y) || | ||
793 | (fbcaps.len < caps.len)) | ||
794 | err = -EINVAL; | ||
795 | |||
796 | return err; | ||
797 | } | ||
798 | |||
774 | int | 799 | int |
775 | fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) | 800 | fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) |
776 | { | 801 | { |
777 | int err, flags = info->flags; | 802 | int flags = info->flags; |
803 | int ret = 0; | ||
778 | 804 | ||
779 | if (var->activate & FB_ACTIVATE_INV_MODE) { | 805 | if (var->activate & FB_ACTIVATE_INV_MODE) { |
780 | struct fb_videomode mode1, mode2; | 806 | struct fb_videomode mode1, mode2; |
781 | int ret = 0; | ||
782 | 807 | ||
783 | fb_var_to_videomode(&mode1, var); | 808 | fb_var_to_videomode(&mode1, var); |
784 | fb_var_to_videomode(&mode2, &info->var); | 809 | fb_var_to_videomode(&mode2, &info->var); |
@@ -796,40 +821,51 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) | |||
796 | if (!ret) | 821 | if (!ret) |
797 | fb_delete_videomode(&mode1, &info->modelist); | 822 | fb_delete_videomode(&mode1, &info->modelist); |
798 | 823 | ||
799 | return ret; | 824 | |
825 | ret = (ret) ? -EINVAL : 0; | ||
826 | goto done; | ||
800 | } | 827 | } |
801 | 828 | ||
802 | if ((var->activate & FB_ACTIVATE_FORCE) || | 829 | if ((var->activate & FB_ACTIVATE_FORCE) || |
803 | memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { | 830 | memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { |
831 | u32 activate = var->activate; | ||
832 | |||
804 | if (!info->fbops->fb_check_var) { | 833 | if (!info->fbops->fb_check_var) { |
805 | *var = info->var; | 834 | *var = info->var; |
806 | return 0; | 835 | goto done; |
807 | } | 836 | } |
808 | 837 | ||
809 | if ((err = info->fbops->fb_check_var(var, info))) | 838 | ret = info->fbops->fb_check_var(var, info); |
810 | return err; | 839 | |
840 | if (ret) | ||
841 | goto done; | ||
811 | 842 | ||
812 | if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { | 843 | if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { |
813 | struct fb_videomode mode; | 844 | struct fb_videomode mode; |
814 | int err = 0; | 845 | |
846 | if (info->fbops->fb_get_caps) { | ||
847 | ret = fb_check_caps(info, var, activate); | ||
848 | |||
849 | if (ret) | ||
850 | goto done; | ||
851 | } | ||
815 | 852 | ||
816 | info->var = *var; | 853 | info->var = *var; |
854 | |||
817 | if (info->fbops->fb_set_par) | 855 | if (info->fbops->fb_set_par) |
818 | info->fbops->fb_set_par(info); | 856 | info->fbops->fb_set_par(info); |
819 | 857 | ||
820 | fb_pan_display(info, &info->var); | 858 | fb_pan_display(info, &info->var); |
821 | |||
822 | fb_set_cmap(&info->cmap, info); | 859 | fb_set_cmap(&info->cmap, info); |
823 | |||
824 | fb_var_to_videomode(&mode, &info->var); | 860 | fb_var_to_videomode(&mode, &info->var); |
825 | 861 | ||
826 | if (info->modelist.prev && info->modelist.next && | 862 | if (info->modelist.prev && info->modelist.next && |
827 | !list_empty(&info->modelist)) | 863 | !list_empty(&info->modelist)) |
828 | err = fb_add_videomode(&mode, &info->modelist); | 864 | ret = fb_add_videomode(&mode, &info->modelist); |
829 | 865 | ||
830 | if (!err && (flags & FBINFO_MISC_USEREVENT)) { | 866 | if (!ret && (flags & FBINFO_MISC_USEREVENT)) { |
831 | struct fb_event event; | 867 | struct fb_event event; |
832 | int evnt = (var->activate & FB_ACTIVATE_ALL) ? | 868 | int evnt = (activate & FB_ACTIVATE_ALL) ? |
833 | FB_EVENT_MODE_CHANGE_ALL : | 869 | FB_EVENT_MODE_CHANGE_ALL : |
834 | FB_EVENT_MODE_CHANGE; | 870 | FB_EVENT_MODE_CHANGE; |
835 | 871 | ||
@@ -839,7 +875,9 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) | |||
839 | } | 875 | } |
840 | } | 876 | } |
841 | } | 877 | } |
842 | return 0; | 878 | |
879 | done: | ||
880 | return ret; | ||
843 | } | 881 | } |
844 | 882 | ||
845 | int | 883 | int |
@@ -1198,6 +1236,10 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) | |||
1198 | pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; | 1236 | pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; |
1199 | #elif defined(__arm__) || defined(__sh__) || defined(__m32r__) | 1237 | #elif defined(__arm__) || defined(__sh__) || defined(__m32r__) |
1200 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | 1238 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); |
1239 | #elif defined(__avr32__) | ||
1240 | vma->vm_page_prot = __pgprot((pgprot_val(vma->vm_page_prot) | ||
1241 | & ~_PAGE_CACHABLE) | ||
1242 | | (_PAGE_BUFFER | _PAGE_DIRTY)); | ||
1201 | #elif defined(__ia64__) | 1243 | #elif defined(__ia64__) |
1202 | if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) | 1244 | if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) |
1203 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | 1245 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); |
@@ -1266,6 +1308,9 @@ static const struct file_operations fb_fops = { | |||
1266 | #ifdef HAVE_ARCH_FB_UNMAPPED_AREA | 1308 | #ifdef HAVE_ARCH_FB_UNMAPPED_AREA |
1267 | .get_unmapped_area = get_fb_unmapped_area, | 1309 | .get_unmapped_area = get_fb_unmapped_area, |
1268 | #endif | 1310 | #endif |
1311 | #ifdef CONFIG_FB_DEFERRED_IO | ||
1312 | .fsync = fb_deferred_io_fsync, | ||
1313 | #endif | ||
1269 | }; | 1314 | }; |
1270 | 1315 | ||
1271 | struct class *fb_class; | 1316 | struct class *fb_class; |
@@ -1316,6 +1361,12 @@ register_framebuffer(struct fb_info *fb_info) | |||
1316 | } | 1361 | } |
1317 | fb_info->pixmap.offset = 0; | 1362 | fb_info->pixmap.offset = 0; |
1318 | 1363 | ||
1364 | if (!fb_info->pixmap.blit_x) | ||
1365 | fb_info->pixmap.blit_x = ~(u32)0; | ||
1366 | |||
1367 | if (!fb_info->pixmap.blit_y) | ||
1368 | fb_info->pixmap.blit_y = ~(u32)0; | ||
1369 | |||
1319 | if (!fb_info->modelist.prev || !fb_info->modelist.next) | 1370 | if (!fb_info->modelist.prev || !fb_info->modelist.next) |
1320 | INIT_LIST_HEAD(&fb_info->modelist); | 1371 | INIT_LIST_HEAD(&fb_info->modelist); |
1321 | 1372 | ||