X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=drivers%2Fvideo%2Ffbmem.c;h=215ac579f901674c1fc242e5d0681d4a0e206985;hb=9900abfb5e8192f0eafcd9b9dd5d54011e46c76c;hp=28225265159a7c42b36239918695d7e20bc1f399;hpb=4559b438225b01942e1661759db0df55883b1bc0;p=powerpc.git diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 2822526515..215ac579f9 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -33,17 +33,10 @@ #include #include #include +#include -#if defined(__mc68000__) || defined(CONFIG_APUS) -#include -#endif - -#include -#include -#include -#include +#include -#include /* * Frame buffer device initialization and setup routines @@ -354,71 +347,208 @@ static void fb_rotate_logo(struct fb_info *info, u8 *dst, if (rotate == FB_ROTATE_UD) { fb_rotate_logo_ud(image->data, dst, image->width, image->height); - image->dx = info->var.xres - image->width; - image->dy = info->var.yres - image->height; + image->dx = info->var.xres - image->width - image->dx; + image->dy = info->var.yres - image->height - image->dy; } else if (rotate == FB_ROTATE_CW) { fb_rotate_logo_cw(image->data, dst, image->width, image->height); tmp = image->width; image->width = image->height; image->height = tmp; - image->dx = info->var.xres - image->width; + tmp = image->dy; + image->dy = image->dx; + image->dx = info->var.xres - image->width - tmp; } else if (rotate == FB_ROTATE_CCW) { fb_rotate_logo_ccw(image->data, dst, image->width, image->height); tmp = image->width; image->width = image->height; image->height = tmp; - image->dy = info->var.yres - image->height; + tmp = image->dx; + image->dx = image->dy; + image->dy = info->var.yres - image->height - tmp; } image->data = dst; } static void fb_do_show_logo(struct fb_info *info, struct fb_image *image, - int rotate) + int rotate, unsigned int num) { - int x; + unsigned int x; if (rotate == FB_ROTATE_UR) { - for (x = 0; x < num_online_cpus() && - x * (fb_logo.logo->width + 8) <= - info->var.xres - fb_logo.logo->width; x++) { + for (x = 0; + x < num && image->dx + image->width <= info->var.xres; + x++) { info->fbops->fb_imageblit(info, image); - image->dx += fb_logo.logo->width + 8; + image->dx += image->width + 8; } } else if (rotate == FB_ROTATE_UD) { - for (x = 0; x < num_online_cpus() && - x * (fb_logo.logo->width + 8) <= - info->var.xres - fb_logo.logo->width; x++) { + for (x = 0; x < num && image->dx >= 0; x++) { info->fbops->fb_imageblit(info, image); - image->dx -= fb_logo.logo->width + 8; + image->dx -= image->width + 8; } } else if (rotate == FB_ROTATE_CW) { - for (x = 0; x < num_online_cpus() && - x * (fb_logo.logo->width + 8) <= - info->var.yres - fb_logo.logo->width; x++) { + for (x = 0; + x < num && image->dy + image->height <= info->var.yres; + x++) { info->fbops->fb_imageblit(info, image); - image->dy += fb_logo.logo->width + 8; + image->dy += image->height + 8; } } else if (rotate == FB_ROTATE_CCW) { - for (x = 0; x < num_online_cpus() && - x * (fb_logo.logo->width + 8) <= - info->var.yres - fb_logo.logo->width; x++) { + for (x = 0; x < num && image->dy >= 0; x++) { info->fbops->fb_imageblit(info, image); - image->dy -= fb_logo.logo->width + 8; + image->dy -= image->height + 8; + } + } +} + +static int fb_show_logo_line(struct fb_info *info, int rotate, + const struct linux_logo *logo, int y, + unsigned int n) +{ + u32 *palette = NULL, *saved_pseudo_palette = NULL; + unsigned char *logo_new = NULL, *logo_rotate = NULL; + struct fb_image image; + + /* Return if the frame buffer is not mapped or suspended */ + if (logo == NULL || info->state != FBINFO_STATE_RUNNING || + info->flags & FBINFO_MODULE) + return 0; + + image.depth = 8; + image.data = logo->data; + + if (fb_logo.needs_cmapreset) + fb_set_logocmap(info, logo); + + if (fb_logo.needs_truepalette || + fb_logo.needs_directpalette) { + palette = kmalloc(256 * 4, GFP_KERNEL); + if (palette == NULL) + return 0; + + if (fb_logo.needs_truepalette) + fb_set_logo_truepalette(info, logo, palette); + else + fb_set_logo_directpalette(info, logo, palette); + + saved_pseudo_palette = info->pseudo_palette; + info->pseudo_palette = palette; + } + + if (fb_logo.depth <= 4) { + logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL); + if (logo_new == NULL) { + kfree(palette); + if (saved_pseudo_palette) + info->pseudo_palette = saved_pseudo_palette; + return 0; + } + image.data = logo_new; + fb_set_logo(info, logo, logo_new, fb_logo.depth); + } + + image.dx = 0; + image.dy = y; + image.width = logo->width; + image.height = logo->height; + + if (rotate) { + logo_rotate = kmalloc(logo->width * + logo->height, GFP_KERNEL); + if (logo_rotate) + fb_rotate_logo(info, logo_rotate, &image, rotate); + } + + fb_do_show_logo(info, &image, rotate, n); + + kfree(palette); + if (saved_pseudo_palette != NULL) + info->pseudo_palette = saved_pseudo_palette; + kfree(logo_new); + kfree(logo_rotate); + return logo->height; +} + + +#ifdef CONFIG_FB_LOGO_EXTRA + +#define FB_LOGO_EX_NUM_MAX 10 +static struct logo_data_extra { + const struct linux_logo *logo; + unsigned int n; +} fb_logo_ex[FB_LOGO_EX_NUM_MAX]; +static unsigned int fb_logo_ex_num; + +void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n) +{ + if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX) + return; + + fb_logo_ex[fb_logo_ex_num].logo = logo; + fb_logo_ex[fb_logo_ex_num].n = n; + fb_logo_ex_num++; +} + +static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height, + unsigned int yres) +{ + unsigned int i; + + /* FIXME: logo_ex supports only truecolor fb. */ + if (info->fix.visual != FB_VISUAL_TRUECOLOR) + fb_logo_ex_num = 0; + + for (i = 0; i < fb_logo_ex_num; i++) { + height += fb_logo_ex[i].logo->height; + if (height > yres) { + height -= fb_logo_ex[i].logo->height; + fb_logo_ex_num = i; + break; } } + return height; +} + +static int fb_show_extra_logos(struct fb_info *info, int y, int rotate) +{ + unsigned int i; + + for (i = 0; i < fb_logo_ex_num; i++) + y += fb_show_logo_line(info, rotate, + fb_logo_ex[i].logo, y, fb_logo_ex[i].n); + + return y; +} + +#else /* !CONFIG_FB_LOGO_EXTRA */ + +static inline int fb_prepare_extra_logos(struct fb_info *info, + unsigned int height, + unsigned int yres) +{ + return height; +} + +static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate) +{ + return y; } +#endif /* CONFIG_FB_LOGO_EXTRA */ + + int fb_prepare_logo(struct fb_info *info, int rotate) { int depth = fb_get_color_depth(&info->var, &info->fix); - int yres; + unsigned int yres; memset(&fb_logo, 0, sizeof(struct logo_data)); - if (info->flags & FBINFO_MISC_TILEBLITTING) + if (info->flags & FBINFO_MISC_TILEBLITTING || + info->flags & FBINFO_MODULE) return 0; if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { @@ -455,7 +585,7 @@ int fb_prepare_logo(struct fb_info *info, int rotate) if (!fb_logo.logo) { return 0; } - + if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD) yres = info->var.yres; else @@ -472,74 +602,20 @@ int fb_prepare_logo(struct fb_info *info, int rotate) else if (fb_logo.logo->type == LINUX_LOGO_VGA16) fb_logo.depth = 4; else - fb_logo.depth = 1; - return fb_logo.logo->height; + fb_logo.depth = 1; + + return fb_prepare_extra_logos(info, fb_logo.logo->height, yres); } int fb_show_logo(struct fb_info *info, int rotate) { - u32 *palette = NULL, *saved_pseudo_palette = NULL; - unsigned char *logo_new = NULL, *logo_rotate = NULL; - struct fb_image image; - - /* Return if the frame buffer is not mapped or suspended */ - if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING) - return 0; - - image.depth = 8; - image.data = fb_logo.logo->data; - - if (fb_logo.needs_cmapreset) - fb_set_logocmap(info, fb_logo.logo); - - if (fb_logo.needs_truepalette || - fb_logo.needs_directpalette) { - palette = kmalloc(256 * 4, GFP_KERNEL); - if (palette == NULL) - return 0; - - if (fb_logo.needs_truepalette) - fb_set_logo_truepalette(info, fb_logo.logo, palette); - else - fb_set_logo_directpalette(info, fb_logo.logo, palette); - - saved_pseudo_palette = info->pseudo_palette; - info->pseudo_palette = palette; - } - - if (fb_logo.depth <= 4) { - logo_new = kmalloc(fb_logo.logo->width * fb_logo.logo->height, - GFP_KERNEL); - if (logo_new == NULL) { - kfree(palette); - if (saved_pseudo_palette) - info->pseudo_palette = saved_pseudo_palette; - return 0; - } - image.data = logo_new; - fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth); - } - - image.dx = 0; - image.dy = 0; - image.width = fb_logo.logo->width; - image.height = fb_logo.logo->height; - - if (rotate) { - logo_rotate = kmalloc(fb_logo.logo->width * - fb_logo.logo->height, GFP_KERNEL); - if (logo_rotate) - fb_rotate_logo(info, logo_rotate, &image, rotate); - } + int y; - fb_do_show_logo(info, &image, rotate); + y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, + num_online_cpus()); + y = fb_show_extra_logos(info, y, rotate); - kfree(palette); - if (saved_pseudo_palette != NULL) - info->pseudo_palette = saved_pseudo_palette; - kfree(logo_new); - kfree(logo_rotate); - return fb_logo.logo->height; + return y; } #else int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } @@ -586,7 +662,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) return -EPERM; if (info->fbops->fb_read) - return info->fbops->fb_read(file, buf, count, ppos); + return info->fbops->fb_read(info, buf, count, ppos); total_size = info->screen_size; @@ -661,7 +737,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) return -EPERM; if (info->fbops->fb_write) - return info->fbops->fb_write(file, buf, count, ppos); + return info->fbops->fb_write(info, buf, count, ppos); total_size = info->screen_size; @@ -771,14 +847,37 @@ fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) return 0; } +static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, + u32 activate) +{ + struct fb_event event; + struct fb_blit_caps caps, fbcaps; + int err = 0; + + memset(&caps, 0, sizeof(caps)); + memset(&fbcaps, 0, sizeof(fbcaps)); + caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0; + event.info = info; + event.data = ∩︀ + fb_notifier_call_chain(FB_EVENT_GET_REQ, &event); + info->fbops->fb_get_caps(info, &fbcaps, var); + + if (((fbcaps.x ^ caps.x) & caps.x) || + ((fbcaps.y ^ caps.y) & caps.y) || + (fbcaps.len < caps.len)) + err = -EINVAL; + + return err; +} + int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) { - int err, flags = info->flags; + int flags = info->flags; + int ret = 0; if (var->activate & FB_ACTIVATE_INV_MODE) { struct fb_videomode mode1, mode2; - int ret = 0; fb_var_to_videomode(&mode1, var); fb_var_to_videomode(&mode2, &info->var); @@ -796,40 +895,51 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) if (!ret) fb_delete_videomode(&mode1, &info->modelist); - return ret; + + ret = (ret) ? -EINVAL : 0; + goto done; } if ((var->activate & FB_ACTIVATE_FORCE) || memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { + u32 activate = var->activate; + if (!info->fbops->fb_check_var) { *var = info->var; - return 0; + goto done; } - if ((err = info->fbops->fb_check_var(var, info))) - return err; + ret = info->fbops->fb_check_var(var, info); + + if (ret) + goto done; if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { struct fb_videomode mode; - int err = 0; + + if (info->fbops->fb_get_caps) { + ret = fb_check_caps(info, var, activate); + + if (ret) + goto done; + } info->var = *var; + if (info->fbops->fb_set_par) info->fbops->fb_set_par(info); fb_pan_display(info, &info->var); - fb_set_cmap(&info->cmap, info); - fb_var_to_videomode(&mode, &info->var); if (info->modelist.prev && info->modelist.next && !list_empty(&info->modelist)) - err = fb_add_videomode(&mode, &info->modelist); + ret = fb_add_videomode(&mode, &info->modelist); - if (!err && (flags & FBINFO_MISC_USEREVENT)) { + if (!ret && (flags & FBINFO_MISC_USEREVENT)) { struct fb_event event; - int evnt = (var->activate & FB_ACTIVATE_ALL) ? + int evnt = (activate & FB_ACTIVATE_ALL) ? FB_EVENT_MODE_CHANGE_ALL : FB_EVENT_MODE_CHANGE; @@ -839,7 +949,9 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) } } } - return 0; + + done: + return ret; } int @@ -1117,17 +1229,15 @@ fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } #endif -static int +static int fb_mmap(struct file *file, struct vm_area_struct * vma) { int fbidx = iminor(file->f_path.dentry->d_inode); struct fb_info *info = registered_fb[fbidx]; struct fb_ops *fb = info->fbops; unsigned long off; -#if !defined(__sparc__) || defined(__sparc_v9__) unsigned long start; u32 len; -#endif if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; @@ -1142,12 +1252,6 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) return res; } -#if defined(__sparc__) && !defined(__sparc_v9__) - /* Should never get here, all fb drivers should have their own - mmap routines */ - return -EINVAL; -#else - /* !sparc32... */ lock_kernel(); /* frame buffer memory */ @@ -1171,46 +1275,11 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) vma->vm_pgoff = off >> PAGE_SHIFT; /* This is an IO map - tell maydump to skip this VMA */ vma->vm_flags |= VM_IO | VM_RESERVED; -#if defined(__mc68000__) -#if defined(CONFIG_SUN3) - pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE; -#elif defined(CONFIG_MMU) - if (CPU_IS_020_OR_030) - pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030; - if (CPU_IS_040_OR_060) { - pgprot_val(vma->vm_page_prot) &= _CACHEMASK040; - /* Use no-cache mode, serialized */ - pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S; - } -#endif -#elif defined(__powerpc__) - vma->vm_page_prot = phys_mem_access_prot(file, off >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot); -#elif defined(__alpha__) - /* Caching is off in the I/O space quadrant by design. */ -#elif defined(__i386__) || defined(__x86_64__) - if (boot_cpu_data.x86 > 3) - pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; -#elif defined(__mips__) || defined(__sparc_v9__) - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); -#elif defined(__hppa__) - pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; -#elif defined(__arm__) || defined(__sh__) || defined(__m32r__) - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); -#elif defined(__ia64__) - if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); - else - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); -#else -#warning What do we have to do here?? -#endif + fb_pgprotect(file, vma, off); if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0; -#endif /* !sparc32 */ } static int @@ -1266,6 +1335,9 @@ static const struct file_operations fb_fops = { #ifdef HAVE_ARCH_FB_UNMAPPED_AREA .get_unmapped_area = get_fb_unmapped_area, #endif +#ifdef CONFIG_FB_DEFERRED_IO + .fsync = fb_deferred_io_fsync, +#endif }; struct class *fb_class; @@ -1316,6 +1388,12 @@ register_framebuffer(struct fb_info *fb_info) } fb_info->pixmap.offset = 0; + if (!fb_info->pixmap.blit_x) + fb_info->pixmap.blit_x = ~(u32)0; + + if (!fb_info->pixmap.blit_y) + fb_info->pixmap.blit_y = ~(u32)0; + if (!fb_info->modelist.prev || !fb_info->modelist.next) INIT_LIST_HEAD(&fb_info->modelist); @@ -1337,17 +1415,34 @@ register_framebuffer(struct fb_info *fb_info) * * Returns negative errno on error, or zero for success. * + * This function will also notify the framebuffer console + * to release the driver. + * + * This is meant to be called within a driver's module_exit() + * function. If this is called outside module_exit(), ensure + * that the driver implements fb_open() and fb_release() to + * check that no processes are using the device. */ int unregister_framebuffer(struct fb_info *fb_info) { struct fb_event event; - int i; + int i, ret = 0; i = fb_info->node; - if (!registered_fb[i]) - return -EINVAL; + if (!registered_fb[i]) { + ret = -EINVAL; + goto done; + } + + event.info = fb_info; + ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); + + if (ret) { + ret = -EINVAL; + goto done; + } if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) @@ -1359,7 +1454,8 @@ unregister_framebuffer(struct fb_info *fb_info) device_destroy(fb_class, MKDEV(FB_MAJOR, i)); event.info = fb_info; fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); - return 0; +done: + return ret; } /**