📄 fbmem.c
字号:
/* What depth we asked for might be different from what we get */ if (fb_logo.logo->type == LINUX_LOGO_CLUT224) fb_logo.depth = 8; else if (fb_logo.logo->type == LINUX_LOGO_VGA16) fb_logo.depth = 4; else fb_logo.depth = 1; if (fb_logo.depth > 4 && depth > 4) { switch (info->fix.visual) { case FB_VISUAL_TRUECOLOR: fb_logo.needs_truepalette = 1; break; case FB_VISUAL_DIRECTCOLOR: fb_logo.needs_directpalette = 1; fb_logo.needs_cmapreset = 1; break; case FB_VISUAL_PSEUDOCOLOR: fb_logo.needs_cmapreset = 1; break; } } return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);}int fb_show_logo(struct fb_info *info, int rotate){ int y; y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, num_online_cpus()); y = fb_show_extra_logos(info, y, rotate); return y;}#elseint fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }int fb_show_logo(struct fb_info *info, int rotate) { return 0; }#endif /* CONFIG_LOGO */static void *fb_seq_start(struct seq_file *m, loff_t *pos){ return (*pos < FB_MAX) ? pos : NULL;}static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos){ (*pos)++; return (*pos < FB_MAX) ? pos : NULL;}static void fb_seq_stop(struct seq_file *m, void *v){}static int fb_seq_show(struct seq_file *m, void *v){ int i = *(loff_t *)v; struct fb_info *fi = registered_fb[i]; if (fi) seq_printf(m, "%d %s\n", fi->node, fi->fix.id); return 0;}static const struct seq_operations proc_fb_seq_ops = { .start = fb_seq_start, .next = fb_seq_next, .stop = fb_seq_stop, .show = fb_seq_show,};static int proc_fb_open(struct inode *inode, struct file *file){ return seq_open(file, &proc_fb_seq_ops);}static const struct file_operations fb_proc_fops = { .owner = THIS_MODULE, .open = proc_fb_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release,};static ssize_tfb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){ unsigned long p = *ppos; struct inode *inode = file->f_path.dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; u32 *buffer, *dst; u32 __iomem *src; int c, i, cnt = 0, err = 0; unsigned long total_size; if (!info || ! info->screen_base) return -ENODEV; if (info->state != FBINFO_STATE_RUNNING) return -EPERM; if (info->fbops->fb_read) return info->fbops->fb_read(info, buf, count, ppos); total_size = info->screen_size; if (total_size == 0) total_size = info->fix.smem_len; if (p >= total_size) return 0; if (count >= total_size) count = total_size; if (count + p > total_size) count = total_size - p; buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); if (!buffer) return -ENOMEM; src = (u32 __iomem *) (info->screen_base + p); if (info->fbops->fb_sync) info->fbops->fb_sync(info); while (count) { c = (count > PAGE_SIZE) ? PAGE_SIZE : count; dst = buffer; for (i = c >> 2; i--; ) *dst++ = fb_readl(src++); if (c & 3) { u8 *dst8 = (u8 *) dst; u8 __iomem *src8 = (u8 __iomem *) src; for (i = c & 3; i--;) *dst8++ = fb_readb(src8++); src = (u32 __iomem *) src8; } if (copy_to_user(buf, buffer, c)) { err = -EFAULT; break; } *ppos += c; buf += c; cnt += c; count -= c; } kfree(buffer); return (err) ? err : cnt;}static ssize_tfb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){ unsigned long p = *ppos; struct inode *inode = file->f_path.dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; u32 *buffer, *src; u32 __iomem *dst; int c, i, cnt = 0, err = 0; unsigned long total_size; if (!info || !info->screen_base) return -ENODEV; if (info->state != FBINFO_STATE_RUNNING) return -EPERM; if (info->fbops->fb_write) return info->fbops->fb_write(info, buf, count, ppos); total_size = info->screen_size; if (total_size == 0) total_size = info->fix.smem_len; if (p > total_size) return -EFBIG; if (count > total_size) { err = -EFBIG; count = total_size; } if (count + p > total_size) { if (!err) err = -ENOSPC; count = total_size - p; } buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); if (!buffer) return -ENOMEM; dst = (u32 __iomem *) (info->screen_base + p); if (info->fbops->fb_sync) info->fbops->fb_sync(info); while (count) { c = (count > PAGE_SIZE) ? PAGE_SIZE : count; src = buffer; if (copy_from_user(src, buf, c)) { err = -EFAULT; break; } for (i = c >> 2; i--; ) fb_writel(*src++, dst++); if (c & 3) { u8 *src8 = (u8 *) src; u8 __iomem *dst8 = (u8 __iomem *) dst; for (i = c & 3; i--; ) fb_writeb(*src8++, dst8++); dst = (u32 __iomem *) dst8; } *ppos += c; buf += c; cnt += c; count -= c; } kfree(buffer); return (cnt) ? cnt : err;}intfb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var){ struct fb_fix_screeninfo *fix = &info->fix; unsigned int yres = info->var.yres; int err = 0; if (var->yoffset > 0) { if (var->vmode & FB_VMODE_YWRAP) { if (!fix->ywrapstep || (var->yoffset % fix->ywrapstep)) err = -EINVAL; else yres = 0; } else if (!fix->ypanstep || (var->yoffset % fix->ypanstep)) err = -EINVAL; } if (var->xoffset > 0 && (!fix->xpanstep || (var->xoffset % fix->xpanstep))) err = -EINVAL; if (err || !info->fbops->fb_pan_display || var->yoffset + yres > info->var.yres_virtual || var->xoffset + info->var.xres > info->var.xres_virtual) return -EINVAL; if ((err = info->fbops->fb_pan_display(var, info))) return err; info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) info->var.vmode |= FB_VMODE_YWRAP; else info->var.vmode &= ~FB_VMODE_YWRAP; 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;}intfb_set_var(struct fb_info *info, struct fb_var_screeninfo *var){ int flags = info->flags; int ret = 0; if (var->activate & FB_ACTIVATE_INV_MODE) { struct fb_videomode mode1, mode2; fb_var_to_videomode(&mode1, var); fb_var_to_videomode(&mode2, &info->var); /* make sure we don't delete the videomode of current var */ ret = fb_mode_is_equal(&mode1, &mode2); if (!ret) { struct fb_event event; event.info = info; event.data = &mode1; ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event); } if (!ret) fb_delete_videomode(&mode1, &info->modelist); 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; goto done; } 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; 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)) ret = fb_add_videomode(&mode, &info->modelist); if (!ret && (flags & FBINFO_MISC_USEREVENT)) { struct fb_event event; int evnt = (activate & FB_ACTIVATE_ALL) ? FB_EVENT_MODE_CHANGE_ALL : FB_EVENT_MODE_CHANGE; info->flags &= ~FBINFO_MISC_USEREVENT; event.info = info; event.data = &mode; fb_notifier_call_chain(evnt, &event); } } } done: return ret;}intfb_blank(struct fb_info *info, int blank){ int ret = -EINVAL; if (blank > FB_BLANK_POWERDOWN) blank = FB_BLANK_POWERDOWN; if (info->fbops->fb_blank) ret = info->fbops->fb_blank(blank, info); if (!ret) { struct fb_event event; event.info = info; event.data = ␣ fb_notifier_call_chain(FB_EVENT_BLANK, &event); } return ret;}static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg){ struct fb_ops *fb; struct fb_var_screeninfo var; struct fb_fix_screeninfo fix; struct fb_con2fbmap con2fb; struct fb_cmap cmap_from; struct fb_cmap_user cmap; struct fb_event event; void __user *argp = (void __user *)arg; long ret = 0; switch (cmd) { case FBIOGET_VSCREENINFO: if (!lock_fb_info(info)) return -ENODEV; var = info->var; unlock_fb_info(info); ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0; break; case FBIOPUT_VSCREENINFO: if (copy_from_user(&var, argp, sizeof(var))) return -EFAULT; if (!lock_fb_info(info)) return -ENODEV; acquire_console_sem(); info->flags |= FBINFO_MISC_USEREVENT; ret = fb_set_var(info, &var); info->flags &= ~FBINFO_MISC_USEREVENT; release_console_sem(); unlock_fb_info(info); if (!ret && copy_to_user(argp, &var, sizeof(var))) ret = -EFAULT; break; case FBIOGET_FSCREENINFO: if (!lock_fb_info(info)) return -ENODEV; fix = info->fix; unlock_fb_info(info); ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0; break; case FBIOPUTCMAP: if (copy_from_user(&cmap, argp, sizeof(cmap))) return -EFAULT; ret = fb_set_user_cmap(&cmap, info); break; case FBIOGETCMAP: if (copy_from_user(&cmap, argp, sizeof(cmap))) return -EFAULT; if (!lock_fb_info(info)) return -ENODEV; cmap_from = info->cmap; unlock_fb_info(info); ret = fb_cmap_to_user(&cmap_from, &cmap); break; case FBIOPAN_DISPLAY: if (copy_from_user(&var, argp, sizeof(var))) return -EFAULT; if (!lock_fb_info(info)) return -ENODEV; acquire_console_sem(); ret = fb_pan_display(info, &var); release_console_sem(); unlock_fb_info(info); if (ret == 0 && copy_to_user(argp, &var, sizeof(var))) return -EFAULT; break; case FBIO_CURSOR: ret = -EINVAL; break; case FBIOGET_CON2FBMAP: if (copy_from_user(&con2fb, argp, sizeof(con2fb))) return -EFAULT; if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) return -EINVAL; con2fb.framebuffer = -1; event.data = &con2fb; if (!lock_fb_info(info)) return -ENODEV; event.info = info; fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event); unlock_fb_info(info); ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; break; case FBIOPUT_CON2FBMAP: if (copy_from_user(&con2fb, argp, sizeof(con2fb))) return -EFAULT; if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) return -EINVAL; if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) return -EINVAL; if (!registered_fb[con2fb.framebuffer]) request_module("fb%d", con2fb.framebuffer); if (!registered_fb[con2fb.framebuffer]) { ret = -EINVAL; break; } event.data = &con2fb; if (!lock_fb_info(info)) return -ENODEV; event.info = info; ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event); unlock_fb_info(info); break; case FBIOBLANK: if (!lock_fb_info(info)) return -ENODEV; acquire_console_sem(); info->flags |= FBINFO_MISC_USEREVENT; ret = fb_blank(info, arg); info->flags &= ~FBINFO_MISC_USEREVENT; release_console_sem(); unlock_fb_info(info); break; default: if (!lock_fb_info(info)) return -ENODEV; fb = info->fbops; if (fb->fb_ioctl) ret = fb->fb_ioctl(info, cmd, arg); else ret = -ENOTTY; unlock_fb_info(info); } return ret;}static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ struct inode *inode = file->f_path.dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; return do_fb_ioctl(info, cmd, arg);}#ifdef CONFIG_COMPATstruct fb_fix_screeninfo32 { char id[16]; compat_caddr_t smem_start; u32 smem_len; u32 type; u32 type_aux; u32 visual; u16 xpanstep; u16 ypanstep; u16 ywrapstep; u32 line_length; compat_caddr_t mmio_start; u32 mmio_len; u32 accel; u16 reserved[3];};struct fb_cmap32 { u32 start; u32 len; compat_caddr_t red; compat_caddr_t green; compat_caddr_t blue; compat_caddr_t transp;};static int fb_getput_cmap(struct fb_info *info, unsigned int cmd, unsigned long arg){ struct fb_cmap_user __user *cmap; struct fb_cmap32 __user *cmap32; __u32 data; int err; cmap = compat_alloc_user_space(sizeof(*cmap)); cmap32 = compat_ptr(arg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -