📄 fbmem.c
字号:
return addr; } /* See if we fit in the remaining pixmap space */ offset = buf->offset + align; offset &= ~align; if (offset + size > buf->size) { /* We do not fit. In order to be able to re-use the buffer, * we must ensure no asynchronous DMA'ing or whatever operation * is in progress, we sync for that. */ if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) info->fbops->fb_sync(info); offset = 0; } buf->offset = offset + size; addr += offset; return addr;}#ifdef CONFIG_LOGO#include <linux/linux_logo.h>static inline unsigned safe_shift(unsigned d, int n){ return n < 0 ? d >> -n : d << n;}static void fb_set_logocmap(struct fb_info *info, const struct linux_logo *logo){ struct fb_cmap palette_cmap; u16 palette_green[16]; u16 palette_blue[16]; u16 palette_red[16]; int i, j, n; const unsigned char *clut = logo->clut; palette_cmap.start = 0; palette_cmap.len = 16; palette_cmap.red = palette_red; palette_cmap.green = palette_green; palette_cmap.blue = palette_blue; palette_cmap.transp = NULL; for (i = 0; i < logo->clutsize; i += n) { n = logo->clutsize - i; /* palette_cmap provides space for only 16 colors at once */ if (n > 16) n = 16; palette_cmap.start = 32 + i; palette_cmap.len = n; for (j = 0; j < n; ++j) { palette_cmap.red[j] = clut[0] << 8 | clut[0]; palette_cmap.green[j] = clut[1] << 8 | clut[1]; palette_cmap.blue[j] = clut[2] << 8 | clut[2]; clut += 3; } fb_set_cmap(&palette_cmap, info); }}static void fb_set_logo_truepalette(struct fb_info *info, const struct linux_logo *logo, u32 *palette){ unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff }; unsigned char redmask, greenmask, bluemask; int redshift, greenshift, blueshift; int i; const unsigned char *clut = logo->clut; /* * We have to create a temporary palette since console palette is only * 16 colors long. */ /* Bug: Doesn't obey msb_right ... (who needs that?) */ redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8]; greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8]; bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8]; redshift = info->var.red.offset - (8 - info->var.red.length); greenshift = info->var.green.offset - (8 - info->var.green.length); blueshift = info->var.blue.offset - (8 - info->var.blue.length); for ( i = 0; i < logo->clutsize; i++) { palette[i+32] = (safe_shift((clut[0] & redmask), redshift) | safe_shift((clut[1] & greenmask), greenshift) | safe_shift((clut[2] & bluemask), blueshift)); clut += 3; }}static void fb_set_logo_directpalette(struct fb_info *info, const struct linux_logo *logo, u32 *palette){ int redshift, greenshift, blueshift; int i; redshift = info->var.red.offset; greenshift = info->var.green.offset; blueshift = info->var.blue.offset; for (i = 32; i < logo->clutsize; i++) palette[i] = i << redshift | i << greenshift | i << blueshift;}static void fb_set_logo(struct fb_info *info, const struct linux_logo *logo, u8 *dst, int depth){ int i, j, shift; const u8 *src = logo->data; u8 d, xor = 0; switch (depth) { case 4: for (i = 0; i < logo->height; i++) for (j = 0; j < logo->width; src++) { *dst++ = *src >> 4; j++; if (j < logo->width) { *dst++ = *src & 0x0f; j++; } } break; case ~1: xor = 0xff; case 1: for (i = 0; i < logo->height; i++) { shift = 7; d = *src++ ^ xor; for (j = 0; j < logo->width; j++) { *dst++ = (d >> shift) & 1; shift = (shift-1) & 7; if (shift == 7) d = *src++ ^ xor; } } break; }}/* * Three (3) kinds of logo maps exist. linux_logo_clut224 (>16 colors), * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors). Depending on * the visual format and color depth of the framebuffer, the DAC, the * pseudo_palette, and the logo data will be adjusted accordingly. * * Case 1 - linux_logo_clut224: * Color exceeds the number of console colors (16), thus we set the hardware DAC * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set. * * For visuals that require color info from the pseudo_palette, we also construct * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags * will be set. * * Case 2 - linux_logo_vga16: * The number of colors just matches the console colors, thus there is no need * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie, * each byte contains color information for two pixels (upper and lower nibble). * To be consistent with fb_imageblit() usage, we therefore separate the two * nibbles into separate bytes. The "depth" flag will be set to 4. * * Case 3 - linux_logo_mono: * This is similar with Case 2. Each byte contains information for 8 pixels. * We isolate each bit and expand each into a byte. The "depth" flag will * be set to 1. */static struct logo_data { int depth; int needs_directpalette; int needs_truepalette; int needs_cmapreset; const struct linux_logo *logo;} fb_logo;int fb_prepare_logo(struct fb_info *info){ memset(&fb_logo, 0, sizeof(struct logo_data)); switch (info->fix.visual) { case FB_VISUAL_TRUECOLOR:#ifndef CONFIG_LOGO_LINUX_TFT16 if (info->var.bits_per_pixel >= 8) fb_logo.needs_truepalette = 1;#endif break; case FB_VISUAL_DIRECTCOLOR: if (info->var.bits_per_pixel >= 24) { fb_logo.needs_directpalette = 1; fb_logo.needs_cmapreset = 1; } break; case FB_VISUAL_PSEUDOCOLOR: fb_logo.needs_cmapreset = 1; break; } /* Return if no suitable logo was found */ fb_logo.logo = fb_find_logo(info->var.bits_per_pixel); if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) { fb_logo.logo = NULL; return 0; } /* What depth we asked for might be different from what we get */ if (fb_logo.logo->type == LINUX_LOGO_TFT16) fb_logo.depth = 16; else 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; return fb_logo.logo->height;}int fb_show_logo(struct fb_info *info){ u32 *palette = NULL, *saved_pseudo_palette = NULL; unsigned char *logo_new = NULL; struct fb_image image; int x; /* Return if the frame buffer is not mapped or suspended */ if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING) return 0; image.depth = fb_logo.depth; 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) { if (palette) 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.width = fb_logo.logo->width; image.height = fb_logo.logo->height; image.dy = 0; for (x = 0; x < num_online_cpus() * (fb_logo.logo->width + 8) && x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) { image.dx = x;#ifndef CONFIG_LOGO_LINUX_TFT16 info->fbops->fb_imageblit(info, &image);#else image.dy = 0; for(; image.dy<image.height&&image.dy<info->var.yres; image.dy++) memcpy(info->screen_base+info->fix.line_length*image.dy+image.dx*2, image.data+image.dy*image.width*2, image.width*2);#endif } if (palette != NULL) kfree(palette); if (saved_pseudo_palette != NULL) info->pseudo_palette = saved_pseudo_palette; if (logo_new != NULL) kfree(logo_new); return fb_logo.logo->height;}#elseint fb_prepare_logo(struct fb_info *info) { return 0; }int fb_show_logo(struct fb_info *info) { return 0; }#endif /* CONFIG_LOGO */static int fbmem_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *private){ struct fb_info **fi; int clen; clen = 0; for (fi = registered_fb; fi < ®istered_fb[FB_MAX] && len < 4000; fi++) if (*fi) clen += sprintf(buf + clen, "%d %s\n", (*fi)->node, (*fi)->fix.id); *start = buf + offset; if (clen > offset) clen -= offset; else clen = 0; return clen < len ? clen : len;}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_dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; 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(file, buf, count, ppos); if (p >= info->fix.smem_len) return 0; if (count >= info->fix.smem_len) count = info->fix.smem_len; if (count + p > info->fix.smem_len) count = info->fix.smem_len - p; if (info->fbops->fb_sync) info->fbops->fb_sync(info); if (count) { char *base_addr; base_addr = info->screen_base; count -= copy_to_user(buf, base_addr+p, count); if (!count) return -EFAULT; *ppos += count; } return count;}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_dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; int err; 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(file, buf, count, ppos); if (p > info->fix.smem_len) return -ENOSPC; if (count >= info->fix.smem_len) count = info->fix.smem_len; err = 0; if (count + p > info->fix.smem_len) { count = info->fix.smem_len - p; err = -ENOSPC; } if (info->fbops->fb_sync) info->fbops->fb_sync(info); if (count) { char *base_addr; base_addr = info->screen_base; count -= copy_from_user(base_addr+p, buf, count); *ppos += count; err = -EFAULT; } if (count) return count; return err;}#ifdef CONFIG_KMODstatic void try_to_load(int fb){ request_module("fb%d", fb);}#endif /* CONFIG_KMOD */voidfb_load_cursor_image(struct fb_info *info){ unsigned int width = (info->cursor.image.width + 7) >> 3; u8 *data = (u8 *) info->cursor.image.data; if (info->sprite.outbuf) info->sprite.outbuf(info, info->sprite.addr, data, width); else memcpy(info->sprite.addr, data, width);}intfb_cursor(struct fb_info *info, struct fb_cursor_user __user *sprite){ struct fb_cursor_user cursor_user; struct fb_cursor cursor; char *data = NULL, *mask = NULL; u16 *red = NULL, *green = NULL, *blue = NULL, *transp = NULL; int err = -EINVAL; if (copy_from_user(&cursor_user, sprite, sizeof(struct fb_cursor_user))) return -EFAULT; memcpy(&cursor, &cursor_user, sizeof(cursor)); cursor.mask = NULL; cursor.image.data = NULL; cursor.image.cmap.red = NULL; cursor.image.cmap.green = NULL; cursor.image.cmap.blue = NULL; cursor.image.cmap.transp = NULL; if (cursor.set & FB_CUR_SETCUR) info->cursor.enable = 1; if (cursor.set & FB_CUR_SETCMAP) { unsigned len = cursor.image.cmap.len; if ((int)len <= 0) goto out; len *= 2; err = -ENOMEM; red = kmalloc(len, GFP_USER); green = kmalloc(len, GFP_USER); blue = kmalloc(len, GFP_USER); if (!red || !green || !blue) goto out; if (cursor_user.image.cmap.transp) { transp = kmalloc(len, GFP_USER); if (!transp) goto out; } err = -EFAULT; if (copy_from_user(red, cursor_user.image.cmap.red, len)) goto out; if (copy_from_user(green, cursor_user.image.cmap.green, len)) goto out; if (copy_from_user(blue, cursor_user.image.cmap.blue, len)) goto out; if (transp) { if (copy_from_user(transp, cursor_user.image.cmap.transp, len)) goto out; } cursor.image.cmap.red = red; cursor.image.cmap.green = green; cursor.image.cmap.blue = blue; cursor.image.cmap.transp = transp; } if (cursor.set & FB_CUR_SETSHAPE) { int size = ((cursor.image.width + 7) >> 3) * cursor.image.height; if ((cursor.image.height != info->cursor.image.height) || (cursor.image.width != info->cursor.image.width)) cursor.set |= FB_CUR_SETSIZE; err = -ENOMEM; data = kmalloc(size, GFP_USER); mask = kmalloc(size, GFP_USER); if (!mask || !data) goto out; err = -EFAULT; if (copy_from_user(data, cursor_user.image.data, size) || copy_from_user(mask, cursor_user.mask, size)) goto out; cursor.image.data = data; cursor.mask = mask; } info->cursor.set = cursor.set; info->cursor.rop = cursor.rop; err = info->fbops->fb_cursor(info, &cursor);out: kfree(data); kfree(mask); kfree(red); kfree(green); kfree(blue); kfree(transp); return err;}intfb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var){ int xoffset = var->xoffset; int yoffset = var->yoffset; int err; if (xoffset < 0 || yoffset < 0 || !info->fbops->fb_pan_display || xoffset + info->var.xres > info->var.xres_virtual || yoffset + info->var.yres > info->var.yres_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;}intfb_set_var(struct fb_info *info, struct fb_var_screeninfo *var){ int err; if ((var->activate & FB_ACTIVATE_FORCE) || memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { if (!info->fbops->fb_check_var) { *var = info->var; return 0; } if ((err = info->fbops->fb_check_var(var, info))) return err; if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { info->var = *var; if (info->fbops->fb_set_par) info->fbops->fb_set_par(info);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -