📄 fbmem.2.6
字号:
}
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 __init 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, 1, info);
}
}
static void __init 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 __init 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 __init 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:
if (info->var.bits_per_pixel >= 8)
fb_logo.needs_truepalette = 1;
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_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;
info->fbops->fb_imageblit(info, &image);
}
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;
}
#else
int 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_t
fb_read(struct file *file, char *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_t
fb_write(struct file *file, const char *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_KMOD
static void try_to_load(int fb)
{
request_module("fb%d", fb);
}
#endif /* CONFIG_KMOD */
void
fb_load_cursor_image(struct fb_info *info)
{
unsigned int width = (info->cursor.image.width + 7) >> 3;
u8 *data = (u8 *) info->cursor.image.data;
info->sprite.outbuf(info, info->sprite.addr, data, width);
}
int
fb_cursor(struct fb_info *info, struct fb_cursor *sprite)
{
struct fb_cursor cursor;
int err;
if (copy_from_user(&cursor, sprite, sizeof(struct fb_cursor)))
return -EFAULT;
if (cursor.set & FB_CUR_SETCUR)
info->cursor.enable = 1;
if (cursor.set & FB_CUR_SETCMAP) {
err = fb_copy_cmap(&cursor.image.cmap, &sprite->image.cmap, 1);
if (err)
return err;
}
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;
cursor.image.data = kmalloc(size, GFP_KERNEL);
if (!cursor.image.data)
return -ENOMEM;
cursor.mask = kmalloc(size, GFP_KERNEL);
if (!cursor.mask) {
kfree(cursor.image.data);
return -ENOMEM;
}
if (copy_from_user(&cursor.image.data, sprite->image.data, size) ||
copy_from_user(cursor.mask, sprite->mask, size)) {
kfree(cursor.image.data);
kfree(cursor.mask);
return -EFAULT;
}
}
info->cursor.set = cursor.set;
info->cursor.rop = cursor.rop;
err = info->fbops->fb_cursor(info, &cursor);
return err;
}
int
fb_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;
}
int
fb_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);
fb_pan_display(info, &info->var);
fb_set_cmap(&info->cmap, 1, info);
notifier_call_chain(&fb_notifier_list, FB_EVENT_MODE_CHANGE, info);
}
}
return 0;
}
int
fb_blank(struct fb_info *info, int blank)
{
/* ??? Variable sized stack allocation. */
u16 black[info->cmap.len];
struct fb_cmap cmap;
if (info->fbops->fb_blank && !info->fbops->fb_blank(blank, info))
return 0;
if (blank) {
memset(black, 0, info->cmap.len * sizeof(u16));
cmap.red = cmap.green = cmap.blue = black;
cmap.transp = info->cmap.transp ? black : NULL;
cmap.start = info->cmap.start;
cmap.len = info->cmap.len;
} else
cmap = info->cmap;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -