📄 fbcon.c
字号:
* At the moment fbcon_putc() cannot blit across vertical wrap boundary * Implies should only really hardware scroll in rows. Only reason for * restriction is simplicity & efficiency at the moment. */static __inline__ int real_y(struct display *p, int y){ int rows = p->vrows; y += p->yscroll; return(y < rows ? y : y-rows);}static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height, int width){ int unit = conp->vc_num; struct display *p = &disp[unit]; u_int y_break; if (!p->can_soft_blank && console_blanked) return(0); if ((sy <= p->cursor_y) && (p->cursor_y < sy+height) && (sx <= p->cursor_x) && (p->cursor_x < sx+width)) CURSOR_UNDRAWN(); /* Split blits that cross physical y_wrap boundary */ y_break = p->vrows-p->yscroll; if (sy < y_break && sy+height-1 >= y_break) { u_int b = y_break-sy; p->dispsw->clear(conp, p, real_y(p, sy), sx, b, width); p->dispsw->clear(conp, p, real_y(p, sy+b), sx, height-b, width); } else p->dispsw->clear(conp, p, real_y(p, sy), sx, height, width); return(0);}static int fbcon_putc(struct vc_data *conp, int c, int y, int x){ int unit = conp->vc_num; struct display *p = &disp[unit]; if (!p->can_soft_blank && console_blanked) return(0); if ((p->cursor_x == x) && (p->cursor_y == y)) CURSOR_UNDRAWN(); p->dispsw->putc(conp, p, c, real_y(p, y), x); return(0);}static int fbcon_putcs(struct vc_data *conp, const char *s, int count, int y, int x){ int unit = conp->vc_num; struct display *p = &disp[unit]; if (!p->can_soft_blank && console_blanked) return(0); if ((p->cursor_y == y) && (x <= p->cursor_x) && (p->cursor_x < x+count)) CURSOR_UNDRAWN(); p->dispsw->putcs(conp, p, s, count, real_y(p, y), x); return(0);}static int fbcon_cursor(struct vc_data *conp, int mode){ int unit = conp->vc_num; struct display *p = &disp[unit]; if (CURSOR_UNDRAWN ()) p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y)); p->cursor_x = conp->vc_x; p->cursor_y = conp->vc_y; switch (mode) { case CM_ERASE: cursor_on = 0; break; case CM_MOVE: case CM_DRAW: vbl_cursor_cnt = CURSOR_DRAW_DELAY; cursor_on = 1; break; } return(0);}static void fbcon_vbl_handler(int irq, struct pt_regs *fp, void *dummy){ struct display *p; if (!cursor_on) return; if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) { /* Here no check is possible for console changing. The console * switching code should set vbl_cursor_cnt to an appropriate value. */ p = &disp[fg_console]; p->dispsw->rev_char(p, p->cursor_x, real_y(p, p->cursor_y)); cursor_drawn ^= 1; vbl_cursor_cnt = cursor_blink_rate; }}static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count){ int unit = conp->vc_num; struct display *p = &disp[unit]; if (!p->can_soft_blank && console_blanked) return(0); fbcon_cursor(conp, CM_ERASE); /* * ++Geert: Only use ywrap/ypan if the console is in text mode */ switch (dir) { case SM_UP: if (t == 0 && b == conp->vc_rows && vt_cons[unit]->vc_mode == KD_TEXT) { if (count > conp->vc_rows) /* Maximum realistic size */ count = conp->vc_rows; switch (p->scrollmode) { case SCROLL_YWRAP: p->yscroll += count; if (p->yscroll >= p->vrows) /* Deal with wrap */ p->yscroll -= p->vrows; p->var.xoffset = 0; p->var.yoffset = p->yscroll*p->fontheight; p->var.vmode |= FB_VMODE_YWRAP; fb_info->updatevar(unit); break; case SCROLL_YPAN: p->yscroll += count; if (p->yscroll+conp->vc_rows > p->vrows) { p->dispsw->bmove(p, p->yscroll, 0, 0, 0, b-count, conp->vc_cols); p->yscroll = 0; } p->var.xoffset = 0; p->var.yoffset = p->yscroll*p->fontheight; p->var.vmode &= ~FB_VMODE_YWRAP; fb_info->updatevar(unit); break; case SCROLL_YMOVE: p->dispsw->bmove(p, count, 0, 0, 0, b-count, conp->vc_cols); break; } } else fbcon_bmove(conp, t+count, 0, t, 0, b-t-count, conp->vc_cols); fbcon_clear(conp, b-count, 0, count, conp->vc_cols); break; case SM_DOWN: if (t == 0 && b == conp->vc_rows && vt_cons[unit]->vc_mode == KD_TEXT) { if (count > conp->vc_rows) /* Maximum realistic size */ count = conp->vc_rows; switch (p->scrollmode) { case SCROLL_YWRAP: p->yscroll -= count; if (p->yscroll < 0) /* Deal with wrap */ p->yscroll += p->vrows; p->var.xoffset = 0; p->var.yoffset = p->yscroll*p->fontheight; p->var.vmode |= FB_VMODE_YWRAP; fb_info->updatevar(unit); break; case SCROLL_YPAN: p->yscroll -= count; if (p->yscroll < 0) { p->yscroll = p->vrows-conp->vc_rows; p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, b-count, conp->vc_cols); } p->var.xoffset = 0; p->var.yoffset = p->yscroll*p->fontheight; p->var.vmode &= ~FB_VMODE_YWRAP; fb_info->updatevar(unit); break; case SCROLL_YMOVE: p->dispsw->bmove(p, 0, 0, count, 0, b-count, conp->vc_cols); break; } } else fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols); /* Fixed bmove() should end Arno's frustration with copying? * Confucius says: * Man who copies in wrong direction, end up with trashed data */ fbcon_clear(conp, t, 0, count, conp->vc_cols); break; case SM_LEFT: fbcon_bmove(conp, 0, t+count, 0, t, conp->vc_rows, b-t-count); fbcon_clear(conp, 0, b-count, conp->vc_rows, count); break; case SM_RIGHT: fbcon_bmove(conp, 0, t, 0, t+count, conp->vc_rows, b-t-count); fbcon_clear(conp, 0, t, conp->vc_rows, count); break; } return(0);}static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, int height, int width){ int unit = conp->vc_num; struct display *p = &disp[unit]; if (!p->can_soft_blank && console_blanked) return(0); if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) && (sx <= p->cursor_x) && (p->cursor_x < sx+width)) || ((dy <= p->cursor_y) && (p->cursor_y < dy+height) && (dx <= p->cursor_x) && (p->cursor_x < dx+width))) fbcon_cursor(conp, CM_ERASE); /* Split blits that cross physical y_wrap case. * Pathological case involves 4 blits, better to use recursive * code rather than unrolled case * * Recursive invocations don't need to erase the cursor over and * over again, so we use fbcon_bmove_rec() */ fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll); return(0);}static void fbcon_bmove_rec(struct display *p, int sy, int sx, int dy, int dx, int height, int width, u_int y_break){ u_int b; if (sy < y_break && sy+height > y_break) { b = y_break-sy; if (dy < sy) { /* Avoid trashing self */ fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break); fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break); } else { fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break); fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break); } return; } if (dy < y_break && dy+height > y_break) { b = y_break-dy; if (dy < sy) { /* Avoid trashing self */ fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break); fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break); } else { fbcon_bmove_rec(p, sy+b, sx, dy+b, dx, height-b, width, y_break); fbcon_bmove_rec(p, sy, sx, dy, dx, b, width, y_break); } return; } p->dispsw->bmove(p, real_y(p, sy), sx, real_y(p, dy), dx, height, width);}static int fbcon_switch(struct vc_data *conp){ if (fb_info && fb_info->switch_con) (*fb_info->switch_con)(conp->vc_num); return(0);}static int fbcon_blank(int blank){ struct display *p = &disp[fg_console]; fbcon_cursor(p->conp, blank ? CM_ERASE : CM_DRAW); if (!p->can_soft_blank) if (blank) { if (p->visual == FB_VISUAL_MONO01) mymemset(p->screen_base, p->var.xres_virtual*p->var.yres_virtual* p->var.bits_per_pixel>>3); else mymemclear(p->screen_base, p->var.xres_virtual*p->var.yres_virtual* p->var.bits_per_pixel>>3); return(0); } else { /* Tell console.c that it has to restore the screen itself */ return(1); } (*fb_info->blank)(blank); return(0);}static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data){ int unit = conp->vc_num; struct display *p = &disp[unit]; int i, size, alloc; size = (p->fontwidth+7)/8 * p->fontheight * 256; alloc = (*w+7)/8 * *h * 256; *w = p->fontwidth; *h = p->fontheight; if (alloc < size) /* allocation length not sufficient */ return( -ENAMETOOLONG ); if ((i = verify_area( VERIFY_WRITE, (void *)data, size ))) return i; memcpy_tofs( data, p->fontdata, size ); return( 0 );}#define REFCOUNT(fd) (((int *)(fd))[-1])static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data){ int unit = conp->vc_num; struct display *p = &disp[unit]; int i, size, userspace = 1, resize; char *old_data = NULL, *new_data; if (w < 0) w = p->fontwidth; if (h < 0) h = p->fontheight; printk("Set_font, w=%d, h=%d, data=%s\n", w, h, data); if (w == 0) { /* engage predefined font, name in 'data' */ char name[MAX_FONT_NAME+1]; if ((i = verify_area( VERIFY_READ, (void *)data, MAX_FONT_NAME ))) return i; memcpy_fromfs( name, data, MAX_FONT_NAME ); name[sizeof(name)-1] = 0; if (!findsoftfont( name, &w, &h, (u_char **)&data )) return( -ENOENT ); userspace = 0; } else if (w == 1) { /* copy font from some other console in 'h'*/ struct display *op; if (h < 0 || !vc_cons_allocated( h )) return( -ENOTTY ); if (h == unit) return( 0 ); /* nothing to do */ op = &disp[h]; if (op->fontdata == p->fontdata) return( 0 ); /* already the same font... */ resize = (op->fontwidth != p->fontwidth) || (op->fontheight != p->fontheight); if (p->userfont) old_data = p->fontdata; p->fontdata = op->fontdata; w = p->fontwidth = op->fontwidth; h = p->fontheight = op->fontheight; if ((p->userfont = op->userfont)) REFCOUNT(p->fontdata)++; /* increment usage counter */ goto activate; } if ((p->dispsw != &dispsw_mono) && (w != 8)) /* Currently only fontwidth == 8 supported */ return( -ENXIO ); if ((p->dispsw == &dispsw_mono) && (w != 8) && (w != 4)) return( -ENXIO ); resize = (w != p->fontwidth) || (h != p->fontheight); size = (w+7)/8 * h * 256; if (p->userfont) old_data = p->fontdata; if (userspace) { if ((i = verify_area( VERIFY_READ, (void *)data, size ))) return i; if (!(new_data = kmalloc( sizeof(int)+size, GFP_USER ))) return( -ENOMEM ); new_data += sizeof(int); REFCOUNT(new_data) = 1; /* usage counter */ memcpy_fromfs( new_data, data, size ); p->fontdata = new_data; p->userfont = 1; } else { p->fontdata = data; p->userfont = 0; } p->fontwidth = w; p->fontheight = h; activate: if (resize) { p->var.xoffset = p->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ if (divides(p->ywrapstep, p->fontheight)) p->scrollmode = SCROLL_YWRAP; else if (divides(p->ypanstep, p->fontheight) && p->var.yres_virtual >= p->var.yres+p->fontheight) p->scrollmode = SCROLL_YPAN; else p->scrollmode = SCROLL_YMOVE; vc_resize_con( p->var.yres/h, p->var.xres/w, unit ); } else if (unit == fg_console) update_screen( unit ); if (old_data) { if (--REFCOUNT(old_data) == 0) { kfree( old_data - sizeof(int) ); } } return( 0 );}/* ====================================================================== *//* * Low Level Operations for the various display memory organizations. * * Currently only the following organizations are supported here: * * - Monochrome * - Color Interleaved Planes
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -