⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fbcon.c

📁 Linux程序设计权威指南代码.包含所有章节代码
💻 C
📖 第 1 页 / 共 5 页
字号:
static int fbcon_blank(struct vc_data *conp, int blank){    struct display *p = &fb_display[conp->vc_num];    struct fb_info *info = p->fb_info;    if (blank < 0)	/* Entering graphics mode */	return 0;    fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW);    if (!p->can_soft_blank) {	if (blank) {	    if (p->visual == FB_VISUAL_MONO01) {		if (p->screen_base)		    mymemset(p->screen_base,			     p->var.xres_virtual*p->var.yres_virtual*			     p->var.bits_per_pixel>>3);	    } else {	    	unsigned short oldc;	    	u_int height;	    	u_int y_break;	    	oldc = conp->vc_video_erase_char;	    	conp->vc_video_erase_char &= p->charmask;	    	height = conp->vc_rows;		y_break = p->vrows-p->yscroll;		if (height > y_break) {			p->dispsw->clear(conp, p, real_y(p, 0), 0, y_break, conp->vc_cols);			p->dispsw->clear(conp, p, real_y(p, y_break), 0, height-y_break, conp->vc_cols);		} else			p->dispsw->clear(conp, p, real_y(p, 0), 0, height, conp->vc_cols);		conp->vc_video_erase_char = oldc;	    }	    return 0;	} else {	    /* Tell console.c that it has to restore the screen itself */	    return 1;	}    }    (*info->blank)(blank, info);    return 0;}static void fbcon_free_font(struct display *p){    if (p->userfont && p->fontdata &&        (--REFCOUNT(p->fontdata) == 0))	kfree(p->fontdata - FONT_EXTRA_WORDS*sizeof(int));    p->fontdata = NULL;    p->userfont = 0;}static inline int fbcon_get_font(int unit, struct console_font_op *op){    struct display *p = &fb_display[unit];    u8 *data = op->data;    u8 *fontdata = p->fontdata;    int i, j;#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY    if (fontwidth(p) != 8) return -EINVAL;#endif    op->width = fontwidth(p);    op->height = fontheight(p);    op->charcount = (p->charmask == 0x1ff) ? 512 : 256;    if (!op->data) return 0;        if (op->width <= 8) {	j = fontheight(p);    	for (i = 0; i < op->charcount; i++) {	    memcpy(data, fontdata, j);	    memset(data+j, 0, 32-j);	    data += 32;	    fontdata += j;	}    }#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY    else if (op->width <= 16) {	j = fontheight(p) * 2;	for (i = 0; i < op->charcount; i++) {	    memcpy(data, fontdata, j);	    memset(data+j, 0, 64-j);	    data += 64;	    fontdata += j;	}    } else if (op->width <= 24) {	for (i = 0; i < op->charcount; i++) {	    for (j = 0; j < fontheight(p); j++) {		*data++ = fontdata[0];		*data++ = fontdata[1];		*data++ = fontdata[2];		fontdata += sizeof(u32);	    }	    memset(data, 0, 3*(32-j));	    data += 3 * (32 - j);	}    } else {	j = fontheight(p) * 4;	for (i = 0; i < op->charcount; i++) {	    memcpy(data, fontdata, j);	    memset(data+j, 0, 128-j);	    data += 128;	    fontdata += j;	}    }#endif    return 0;}static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int userfont){    struct display *p = &fb_display[unit];    int resize;    int w = op->width;    int h = op->height;    int cnt;    char *old_data = NULL;    if (!fontwidthvalid(p,w)) {        if (userfont && op->op != KD_FONT_OP_COPY)	    kfree(data - FONT_EXTRA_WORDS*sizeof(int));	return -ENXIO;    }    if (CON_IS_VISIBLE(p->conp) && softback_lines)	fbcon_set_origin(p->conp);	    resize = (w != fontwidth(p)) || (h != fontheight(p));    if (p->userfont)        old_data = p->fontdata;    if (userfont)        cnt = FNTCHARCNT(data);    else    	cnt = 256;    p->fontdata = data;    if ((p->userfont = userfont))        REFCOUNT(data)++;    p->_fontwidth = w;    p->_fontheight = h;    if (p->conp->vc_hi_font_mask && cnt == 256) {    	p->conp->vc_hi_font_mask = 0;    	if (p->conp->vc_can_do_color)	    p->conp->vc_complement_mask >>= 1;    	p->fgshift--;    	p->bgshift--;    	p->charmask = 0xff;	/* ++Edmund: reorder the attribute bits */	if (p->conp->vc_can_do_color) {	    struct vc_data *conp = p->conp;	    unsigned short *cp = (unsigned short *) conp->vc_origin;	    int count = conp->vc_screenbuf_size/2;	    unsigned short c;	    for (; count > 0; count--, cp++) {	        c = scr_readw(cp);		scr_writew(((c & 0xfe00) >> 1) | (c & 0xff), cp);	    }	    c = conp->vc_video_erase_char;	    conp->vc_video_erase_char = ((c & 0xfe00) >> 1) | (c & 0xff);	    conp->vc_attr >>= 1;	}    } else if (!p->conp->vc_hi_font_mask && cnt == 512) {    	p->conp->vc_hi_font_mask = 0x100;    	if (p->conp->vc_can_do_color)	    p->conp->vc_complement_mask <<= 1;    	p->fgshift++;    	p->bgshift++;    	p->charmask = 0x1ff;	/* ++Edmund: reorder the attribute bits */	{	    struct vc_data *conp = p->conp;	    unsigned short *cp = (unsigned short *) conp->vc_origin;	    int count = conp->vc_screenbuf_size/2;	    unsigned short c;	    for (; count > 0; count--, cp++) {	        unsigned short newc;	        c = scr_readw(cp);		if (conp->vc_can_do_color)		    newc = ((c & 0xff00) << 1) | (c & 0xff);		else		    newc = c & ~0x100;		scr_writew(newc, cp);	    }	    c = conp->vc_video_erase_char;	    if (conp->vc_can_do_color) {		conp->vc_video_erase_char = ((c & 0xff00) << 1) | (c & 0xff);		conp->vc_attr <<= 1;	    } else	        conp->vc_video_erase_char = c & ~0x100;	}    }    fbcon_font_widths(p);    if (resize) {    	struct vc_data *conp = p->conp;	/* reset wrap/pan */	p->var.xoffset = p->var.yoffset = p->yscroll = 0;	p->vrows = p->var.yres_virtual/h;	if ((p->var.yres % h) && (p->var.yres_virtual % h < p->var.yres % h))	    p->vrows--;	updatescrollmode(p);	vc_resize_con( p->var.yres/h, p->var.xres/w, unit );        if (CON_IS_VISIBLE(conp) && softback_buf) {	    int l = fbcon_softback_size / conp->vc_size_row;	    if (l > 5)		softback_end = softback_buf + l * conp->vc_size_row;	    else {		/* Smaller scrollback makes no sense, and 0 would screw		   the operation totally */		softback_top = 0;    	    }    	}    } else if (CON_IS_VISIBLE(p->conp) && vt_cons[unit]->vc_mode == KD_TEXT) {	if (p->dispsw->clear_margins)	    p->dispsw->clear_margins(p->conp, p, 0);	update_screen(unit);    }    if (old_data && (--REFCOUNT(old_data) == 0))	kfree(old_data - FONT_EXTRA_WORDS*sizeof(int));    return 0;}static inline int fbcon_copy_font(int unit, struct console_font_op *op){    struct display *od, *p = &fb_display[unit];    int h = op->height;    if (h < 0 || !vc_cons_allocated( h ))        return -ENOTTY;    if (h == unit)        return 0; /* nothing to do */    od = &fb_display[h];    if (od->fontdata == p->fontdata)        return 0; /* already the same font... */    op->width = fontwidth(od);    op->height = fontheight(od);    return fbcon_do_set_font(unit, op, od->fontdata, od->userfont);}static inline int fbcon_set_font(int unit, struct console_font_op *op){    int w = op->width;    int h = op->height;    int size = h;    int i, k;    u8 *new_data, *data = op->data, *p;#ifdef CONFIG_FBCON_FONTWIDTH8_ONLY    if (w != 8)    	return -EINVAL;#endif    if ((w <= 0) || (w > 32) || (op->charcount != 256 && op->charcount != 512))        return -EINVAL;        if (w > 8) {     	if (w <= 16)    		size *= 2;    	else    		size *= 4;    }    size *= op->charcount;           if (!(new_data = kmalloc(FONT_EXTRA_WORDS*sizeof(int)+size, GFP_USER)))        return -ENOMEM;    new_data += FONT_EXTRA_WORDS*sizeof(int);    FNTSIZE(new_data) = size;    FNTCHARCNT(new_data) = op->charcount;    REFCOUNT(new_data) = 0; /* usage counter */    p = new_data;    if (w <= 8) {	for (i = 0; i < op->charcount; i++) {	    memcpy(p, data, h);	    data += 32;	    p += h;	}    }#ifndef CONFIG_FBCON_FONTWIDTH8_ONLY    else if (w <= 16) {	h *= 2;	for (i = 0; i < op->charcount; i++) {	    memcpy(p, data, h);	    data += 64;	    p += h;	}    } else if (w <= 24) {	for (i = 0; i < op->charcount; i++) {	    int j;	    for (j = 0; j < h; j++) {	        memcpy(p, data, 3);		p[3] = 0;		data += 3;		p += sizeof(u32);	    }	    data += 3*(32 - h);	}    } else {	h *= 4;	for (i = 0; i < op->charcount; i++) {	    memcpy(p, data, h);	    data += 128;	    p += h;	}    }#endif    /* we can do it in u32 chunks because of charcount is 256 or 512, so       font length must be multiple of 256, at least. And 256 is multiple       of 4 */    k = 0;    while (p > new_data) k += *--(u32 *)p;    FNTSUM(new_data) = k;    /* Check if the same font is on some other console already */    for (i = 0; i < MAX_NR_CONSOLES; i++) {    	if (fb_display[i].userfont &&    	    fb_display[i].fontdata &&    	    FNTSUM(fb_display[i].fontdata) == k &&    	    FNTSIZE(fb_display[i].fontdata) == size &&    	    fontwidth(&fb_display[i]) == w &&	    !memcmp(fb_display[i].fontdata, new_data, size)) {	    kfree(new_data - FONT_EXTRA_WORDS*sizeof(int));	    new_data = fb_display[i].fontdata;	    break;    	}    }    return fbcon_do_set_font(unit, op, new_data, 1);}static inline int fbcon_set_def_font(int unit, struct console_font_op *op){    char name[MAX_FONT_NAME];    struct fbcon_font_desc *f;    struct display *p = &fb_display[unit];    if (!op->data)	f = fbcon_get_default_font(p->var.xres, p->var.yres);    else if (strncpy_from_user(name, op->data, MAX_FONT_NAME-1) < 0)	return -EFAULT;    else {	name[MAX_FONT_NAME-1] = 0;	if (!(f = fbcon_find_font(name)))	    return -ENOENT;    }    op->width = f->width;    op->height = f->height;    return fbcon_do_set_font(unit, op, f->data, 0);}static int fbcon_font_op(struct vc_data *conp, struct console_font_op *op){    int unit = conp->vc_num;    switch (op->op) {	case KD_FONT_OP_SET:	    return fbcon_set_font(unit, op);	case KD_FONT_OP_GET:	    return fbcon_get_font(unit, op);	case KD_FONT_OP_SET_DEFAULT:	    return fbcon_set_def_font(unit, op);	case KD_FONT_OP_COPY:	    return fbcon_copy_font(unit, op);	default:	    return -ENOSYS;    }}static u16 palette_red[16];static u16 palette_green[16];static u16 palette_blue[16];static struct fb_cmap palette_cmap  = {    0, 16, palette_red, palette_green, palette_blue, NULL};static int fbcon_set_palette(struct vc_data *conp, unsigned char *table){    int unit = conp->vc_num;    struct display *p = &fb_display[unit];    int i, j, k;    u8 val;    if (!conp->vc_can_do_color || (!p->can_soft_blank && console_blanked))	return -EINVAL;    for (i = j = 0; i < 16; i++) {	k = table[i];	val = conp->vc_palette[j++];	palette_red[k] = (val<<8)|val;	val = conp->vc_palette[j++];	palette_green[k] = (val<<8)|val;	val = conp->vc_palette[j++];	palette_blue[k] = (val<<8)|val;    }    if (p->var.bits_per_pixel <= 4)	palette_cmap.len = 1<<p->var.bits_per_pixel;    else	palette_cmap.len = 16;    palette_cmap.start = 0;    return p->fb_info->fbops->fb_set_cmap(&palette_cmap, 1, unit, p->fb_info);}static u16 *fbcon_screen_pos(struct vc_data *conp, int offset){    int line;    unsigned long p;    if (conp->vc_num != fg_console || !softback_lines)    	return (u16 *)(conp->vc_origin + offset);    line = offset / conp->vc_size_row;    if (line >= softback_lines)    	return (u16 *)(conp->vc_origin + offset - softback_lines * conp->vc_size_row);    p = softback_curr + offset;    if (p >= softback_end)    	p += softback_buf - softback_end;    return (u16 *)p;}static unsigned long fbcon_getxy(struct vc_data *conp, unsigned long pos, int *px, int *py){    int x, y;    unsigned long ret;    if (pos >= conp->vc_origin && pos < conp->vc_scr_end) {    	unsigned long offset = (pos - conp->vc_origin) / 2;    	    	x = offset % conp->vc_cols;    	y = offset / conp->vc_cols;    	if (conp->vc_num == fg_console)    	    y += softback_lines;    	ret = pos + (conp->vc_cols - x) * 2;    } else if (conp->vc_num == fg_console && softback_lines) {    	unsigned long offset = (pos - softback_curr) / 2;    	    	x = offset % conp->vc_cols;    	y = offset / conp->vc_cols;    	if (pos < softback_curr)	    y += (softback_end - softback_buf) / conp->vc_size_row;	ret = pos + (conp->vc_cols - x) * 2;	if (ret == softback_end)	    ret = softback_buf;	if (ret == softback_in)	    ret = conp->vc_origin;    } else {    	/* Should not happen */    	x = y = 0;    	ret = conp->vc_origin;    }    if (px) *px = x;    if (py) *py = y;    return ret;}/* As we might be inside of softback, we may work with non-contiguous buffer,   that's why we have to use a separate routine. */static void fbcon_invert_region(struct vc_data *conp, u16 *p, int cnt){    while (cnt--) {	if (!conp->vc_can_do_color)	    *p++ ^= 0x0800;	else if (conp->vc_hi_font_mask == 0x100) {	    u16 a = *p;	    a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);	    *p++ = a;	} else {	    u16 a = *p;	    a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);	    *p++ = a;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -