diff options
Diffstat (limited to 'drivers/video/console')
-rw-r--r-- | drivers/video/console/Kconfig | 22 | ||||
-rw-r--r-- | drivers/video/console/Makefile | 6 | ||||
-rw-r--r-- | drivers/video/console/bitblit.c | 53 | ||||
-rw-r--r-- | drivers/video/console/fbcon.c | 486 | ||||
-rw-r--r-- | drivers/video/console/fbcon.h | 61 | ||||
-rw-r--r-- | drivers/video/console/fbcon_ccw.c | 426 | ||||
-rw-r--r-- | drivers/video/console/fbcon_cw.c | 410 | ||||
-rw-r--r-- | drivers/video/console/fbcon_rotate.c | 117 | ||||
-rw-r--r-- | drivers/video/console/fbcon_rotate.h | 98 | ||||
-rw-r--r-- | drivers/video/console/fbcon_ud.c | 452 | ||||
-rw-r--r-- | drivers/video/console/newport_con.c | 1 | ||||
-rw-r--r-- | drivers/video/console/softcursor.c | 72 | ||||
-rw-r--r-- | drivers/video/console/sticore.c | 126 | ||||
-rw-r--r-- | drivers/video/console/tileblit.c | 13 | ||||
-rw-r--r-- | drivers/video/console/vgacon.c | 15 |
15 files changed, 2065 insertions, 293 deletions
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index eb83a7874c7..5f74df99340 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -28,7 +28,7 @@ config VGA_CONSOLE config VIDEO_SELECT bool "Video mode selection support" - depends on (X86 || X86_64) && VGA_CONSOLE + depends on X86 && VGA_CONSOLE ---help--- This enables support for text mode selection on kernel startup. If you want to take advantage of some high-resolution text mode your @@ -98,6 +98,18 @@ config FRAMEBUFFER_CONSOLE tristate "Framebuffer Console support" depends on FB select CRC32 + help + Low-level framebuffer-based console driver. + +config FRAMEBUFFER_CONSOLE_ROTATION + bool "Framebuffer Console Rotation" + depends on FRAMEBUFFER_CONSOLE + help + Enable display rotation for the framebuffer console. This is done + in software and may be significantly slower than a normally oriented + display. Note that the rotation is done at the console level only + such that other users of the framebuffer will remain normally + oriented. config STI_CONSOLE tristate "STI text console" @@ -110,7 +122,7 @@ config STI_CONSOLE config FONTS bool "Select compiled-in fonts" - depends on FRAMEBUFFER_CONSOLE + depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE help Say Y here if you would like to use fonts other than the default your frame buffer console usually use. @@ -123,7 +135,7 @@ config FONTS config FONT_8x8 bool "VGA 8x8 font" if FONTS - depends on FRAMEBUFFER_CONSOLE + depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE default y if !SPARC32 && !SPARC64 && !FONTS help This is the "high resolution" font for the VGA frame buffer (the one @@ -137,7 +149,7 @@ config FONT_8x8 config FONT_8x16 bool "VGA 8x16 font" if FONTS - depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y || USB_SISUSBVGA_CON + depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y || STI_CONSOLE || USB_SISUSBVGA_CON default y if !SPARC32 && !SPARC64 && !FONTS help This is the "high resolution" font for the VGA frame buffer (the one @@ -147,7 +159,7 @@ config FONT_8x16 config FONT_6x11 bool "Mac console 6x11 font (not supported by all drivers)" if FONTS - depends on FRAMEBUFFER_CONSOLE + depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE default y if !SPARC32 && !SPARC64 && !FONTS && MAC help Small console font with Macintosh-style high-half glyphs. Some Mac diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile index 42c7b8dcd22..9b26dda18a3 100644 --- a/drivers/video/console/Makefile +++ b/drivers/video/console/Makefile @@ -26,10 +26,14 @@ obj-$(CONFIG_PROM_CONSOLE) += promcon.o promcon_tbl.o obj-$(CONFIG_STI_CONSOLE) += sticon.o sticore.o font.o obj-$(CONFIG_VGA_CONSOLE) += vgacon.o obj-$(CONFIG_MDA_CONSOLE) += mdacon.o -obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o +obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o softcursor.o ifeq ($(CONFIG_FB_TILEBLITTING),y) obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += tileblit.o endif +ifeq ($(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION),y) +obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon_rotate.o fbcon_cw.o fbcon_ud.o \ + fbcon_ccw.o +endif obj-$(CONFIG_FB_STI) += sticore.o font.o diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c index 9f70e512b88..e65fc3ef763 100644 --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c @@ -22,35 +22,6 @@ /* * Accelerated handlers. */ -#define FBCON_ATTRIBUTE_UNDERLINE 1 -#define FBCON_ATTRIBUTE_REVERSE 2 -#define FBCON_ATTRIBUTE_BOLD 4 - -static inline int real_y(struct display *p, int ypos) -{ - int rows = p->vrows; - - ypos += p->yscroll; - return ypos < rows ? ypos : ypos - rows; -} - - -static inline int get_attribute(struct fb_info *info, u16 c) -{ - int attribute = 0; - - if (fb_get_color_depth(&info->var, &info->fix) == 1) { - if (attr_underline(c)) - attribute |= FBCON_ATTRIBUTE_UNDERLINE; - if (attr_reverse(c)) - attribute |= FBCON_ATTRIBUTE_REVERSE; - if (attr_bold(c)) - attribute |= FBCON_ATTRIBUTE_BOLD; - } - - return attribute; -} - static inline void update_attr(u8 *dst, u8 *src, int attribute, struct vc_data *vc) { @@ -272,6 +243,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int w = (vc->vc_font.width + 7) >> 3, c; int y = real_y(p, vc->vc_y); int attribute, use_sw = (vc->vc_cursor_type & 0x10); + int err = 1; char *src; cursor.set = 0; @@ -408,11 +380,27 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, cursor.image.depth = 1; cursor.rop = ROP_XOR; - info->fbops->fb_cursor(info, &cursor); + if (info->fbops->fb_cursor) + err = info->fbops->fb_cursor(info, &cursor); + + if (err) + soft_cursor(info, &cursor); ops->cursor_reset = 0; } +static int bit_update_start(struct fb_info *info) +{ + struct fbcon_ops *ops = info->fbcon_par; + int err; + + err = fb_pan_display(info, &ops->var); + ops->var.xoffset = info->var.xoffset; + ops->var.yoffset = info->var.yoffset; + ops->var.vmode = info->var.vmode; + return err; +} + void fbcon_set_bitops(struct fbcon_ops *ops) { ops->bmove = bit_bmove; @@ -420,6 +408,11 @@ void fbcon_set_bitops(struct fbcon_ops *ops) ops->putcs = bit_putcs; ops->clear_margins = bit_clear_margins; ops->cursor = bit_cursor; + ops->update_start = bit_update_start; + ops->rotate_font = NULL; + + if (ops->rotate) + fbcon_set_rotate(ops); } EXPORT_SYMBOL(fbcon_set_bitops); diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 0fc8bb499c3..bcea87c3cc0 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -106,7 +106,8 @@ enum { FBCON_LOGO_DONTSHOW = -3 /* do not show the logo */ }; -struct display fb_display[MAX_NR_CONSOLES]; +static struct display fb_display[MAX_NR_CONSOLES]; + static signed char con2fb_map[MAX_NR_CONSOLES]; static signed char con2fb_map_boot[MAX_NR_CONSOLES]; static int logo_height; @@ -130,6 +131,9 @@ static char fontname[40]; /* current fb_info */ static int info_idx = -1; +/* console rotation */ +static int rotate; + static const struct consw fb_con; #define CM_SOFTBACK (8) @@ -176,7 +180,6 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines); /* * Internal routines */ -static __inline__ int real_y(struct display *p, int ypos); static __inline__ void ywrap_up(struct vc_data *vc, int count); static __inline__ void ywrap_down(struct vc_data *vc, int count); static __inline__ void ypan_up(struct vc_data *vc, int count); @@ -189,6 +192,8 @@ static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *va int unit); static void fbcon_redraw_move(struct vc_data *vc, struct display *p, int line, int count, int dy); +static void fbcon_modechanged(struct fb_info *info); +static void fbcon_set_all_vcs(struct fb_info *info); #ifdef CONFIG_MAC /* @@ -203,6 +208,88 @@ static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp) } #endif +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION +static inline void fbcon_set_rotation(struct fb_info *info, struct display *p) +{ + struct fbcon_ops *ops = info->fbcon_par; + + if (!(info->flags & FBINFO_MISC_TILEBLITTING) && + p->con_rotate < 4) + ops->rotate = p->con_rotate; + else + ops->rotate = 0; +} + +static void fbcon_rotate(struct fb_info *info, u32 rotate) +{ + struct fbcon_ops *ops= info->fbcon_par; + struct fb_info *fb_info; + + if (!ops || ops->currcon == -1) + return; + + fb_info = registered_fb[con2fb_map[ops->currcon]]; + + if (info == fb_info) { + struct display *p = &fb_display[ops->currcon]; + + if (rotate < 4) + p->con_rotate = rotate; + else + p->con_rotate = 0; + + fbcon_modechanged(info); + } +} + +static void fbcon_rotate_all(struct fb_info *info, u32 rotate) +{ + struct fbcon_ops *ops = info->fbcon_par; + struct vc_data *vc; + struct display *p; + int i; + + if (!ops || ops->currcon < 0 || rotate > 3) + return; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + vc = vc_cons[i].d; + if (!vc || vc->vc_mode != KD_TEXT || + registered_fb[con2fb_map[i]] != info) + continue; + + p = &fb_display[vc->vc_num]; + p->con_rotate = rotate; + } + + fbcon_set_all_vcs(info); +} +#else +static inline void fbcon_set_rotation(struct fb_info *info, struct display *p) +{ + struct fbcon_ops *ops = info->fbcon_par; + + ops->rotate = FB_ROTATE_UR; +} + +static void fbcon_rotate(struct fb_info *info, u32 rotate) +{ + return; +} + +static void fbcon_rotate_all(struct fb_info *info, u32 rotate) +{ + return; +} +#endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */ + +static int fbcon_get_rotate(struct fb_info *info) +{ + struct fbcon_ops *ops = info->fbcon_par; + + return (ops) ? ops->rotate : 0; +} + static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info) { struct fbcon_ops *ops = info->fbcon_par; @@ -281,6 +368,18 @@ static inline int get_color(struct vc_data *vc, struct fb_info *info, return color; } +static void fbcon_update_softback(struct vc_data *vc) +{ + int l = fbcon_softback_size / vc->vc_size_row; + + if (l > 5) + softback_end = softback_buf + l * vc->vc_size_row; + else + /* Smaller scrollback makes no sense, and 0 would screw + the operation totally */ + softback_top = 0; +} + static void fb_flashcursor(void *private) { struct fb_info *info = private; @@ -410,6 +509,14 @@ static int __init fb_console_setup(char *this_opt) last_fb_vc = simple_strtoul(options, &options, 10) - 1; fbcon_is_default = 0; } + + if (!strncmp(options, "rotate:", 7)) { + options += 7; + if (*options) + rotate = simple_strtoul(options, &options, 0); + if (rotate > 3) + rotate = 0; + } } return 0; } @@ -468,6 +575,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, int cols, int rows, int new_cols, int new_rows) { /* Need to make room for the logo */ + struct fbcon_ops *ops = info->fbcon_par; int cnt, erase = vc->vc_video_erase_char, step; unsigned short *save = NULL, *r, *q; @@ -477,7 +585,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, */ if (fb_get_color_depth(&info->var, &info->fix) == 1) erase &= ~0x400; - logo_height = fb_prepare_logo(info); + logo_height = fb_prepare_logo(info, ops->rotate); logo_lines = (logo_height + vc->vc_font.height - 1) / vc->vc_font.height; q = (unsigned short *) (vc->vc_origin + @@ -544,10 +652,14 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info, { struct fbcon_ops *ops = info->fbcon_par; + ops->p = (p) ? p : &fb_display[vc->vc_num]; + if ((info->flags & FBINFO_MISC_TILEBLITTING)) fbcon_set_tileops(vc, info, p, ops); - else + else { + fbcon_set_rotation(info, ops->p); fbcon_set_bitops(ops); + } } #else static void set_blitting_type(struct vc_data *vc, struct fb_info *info, @@ -556,6 +668,8 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info, struct fbcon_ops *ops = info->fbcon_par; info->flags &= ~FBINFO_MISC_TILEBLITTING; + ops->p = (p) ? p : &fb_display[vc->vc_num]; + fbcon_set_rotation(info, ops->p); fbcon_set_bitops(ops); } #endif /* CONFIG_MISC_TILEBLITTING */ @@ -615,9 +729,19 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, fbcon_del_cursor_timer(oldinfo); kfree(ops->cursor_state.mask); kfree(ops->cursor_data); + kfree(ops->fontbuffer); kfree(oldinfo->fbcon_par); oldinfo->fbcon_par = NULL; module_put(oldinfo->fbops->owner); + /* + If oldinfo and newinfo are driving the same hardware, + the fb_release() method of oldinfo may attempt to + restore the hardware state. This will leave the + newinfo in an undefined state. Thus, a call to + fb_set_par() may be needed for the newinfo. + */ + if (newinfo->fbops->fb_set_par) + newinfo->fbops->fb_set_par(newinfo); } return err; @@ -806,7 +930,9 @@ static const char *fbcon_startup(void) memset(ops, 0, sizeof(struct fbcon_ops)); ops->currcon = -1; ops->graphics = 1; + ops->cur_rotate = -1; info->fbcon_par = ops; + p->con_rotate = rotate; set_blitting_type(vc, info, NULL); if (info->fix.type != FB_TYPE_TEXT) { @@ -845,8 +971,10 @@ static const char *fbcon_startup(void) vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ } - cols = info->var.xres / vc->vc_font.width; - rows = info->var.yres / vc->vc_font.height; + cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); + rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); + cols /= vc->vc_font.width; + rows /= vc->vc_font.height; vc_resize(vc, cols, rows); DPRINTK("mode: %s\n", info->fix.id); @@ -932,8 +1060,6 @@ static void fbcon_init(struct vc_data *vc, int init) (info->fix.type == FB_TYPE_TEXT)) logo = 0; - info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ - if (var_to_display(p, &info->var, info)) return; @@ -965,13 +1091,18 @@ static void fbcon_init(struct vc_data *vc, int init) if (!*vc->vc_uni_pagedir_loc) con_copy_unimap(vc, svc); + ops = info->fbcon_par; + p->con_rotate = rotate; + set_blitting_type(vc, info, NULL); + cols = vc->vc_cols; rows = vc->vc_rows; - new_cols = info->var.xres / vc->vc_font.width; - new_rows = info->var.yres / vc->vc_font.height; + new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); + new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); + new_cols /= vc->vc_font.width; + new_rows /= vc->vc_font.height; vc_resize(vc, new_cols, new_rows); - ops = info->fbcon_par; /* * We must always set the mode. The mode of the previous console * driver could be in the same resolution but we are using different @@ -1007,16 +1138,14 @@ static void fbcon_init(struct vc_data *vc, int init) if (logo) fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows); - if (vc == svc && softback_buf) { - int l = fbcon_softback_size / vc->vc_size_row; - if (l > 5) - softback_end = softback_buf + l * vc->vc_size_row; - else { - /* Smaller scrollback makes no sense, and 0 would screw - the operation totally */ - softback_top = 0; - } + if (vc == svc && softback_buf) + fbcon_update_softback(vc); + + if (ops->rotate_font && ops->rotate_font(info, vc, p)) { + ops->rotate = FB_ROTATE_UR; + set_blitting_type(vc, info, p); } + } static void fbcon_deinit(struct vc_data *vc) @@ -1053,15 +1182,6 @@ static void fbcon_deinit(struct vc_data *vc) * restriction is simplicity & efficiency at the moment. */ -static __inline__ int real_y(struct display *p, int ypos) -{ - int rows = p->vrows; - - ypos += p->yscroll; - return ypos < rows ? ypos : ypos - rows; -} - - static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, int width) { @@ -1149,13 +1269,6 @@ static int scrollback_phys_max = 0; static int scrollback_max = 0; static int scrollback_current = 0; -static int update_var(int con, struct fb_info *info) -{ - if (con == ((struct fbcon_ops *)info->fbcon_par)->currcon) - return fb_pan_display(info, &info->var); - return 0; -} - /* * If no vc is existent yet, just set struct display */ @@ -1165,7 +1278,6 @@ static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *va struct display *p = &fb_display[unit]; struct display *t = &fb_display[fg_console]; - var->xoffset = var->yoffset = p->yscroll = 0; if (var_to_display(p, var, info)) return; @@ -1181,9 +1293,9 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, struct display *p = &fb_display[vc->vc_num], *t; struct vc_data **default_mode = vc->vc_display_fg; struct vc_data *svc = *default_mode; + struct fbcon_ops *ops = info->fbcon_par; int rows, cols, charcnt = 256; - var->xoffset = var->yoffset = p->yscroll = 0; if (var_to_display(p, var, info)) return; t = &fb_display[svc->vc_num]; @@ -1200,9 +1312,10 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, var->activate = FB_ACTIVATE_NOW; info->var.activate = var->activate; - info->var.yoffset = info->var.xoffset = 0; + var->yoffset = info->var.yoffset; + var->xoffset = info->var.xoffset; fb_set_var(info, var); - + ops->var = info->var; vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; if (charcnt == 256) { @@ -1218,38 +1331,32 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, if (!*vc->vc_uni_pagedir_loc) con_copy_unimap(vc, svc); - cols = var->xres / vc->vc_font.width; - rows = var->yres / vc->vc_font.height; + cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); + rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); + cols /= vc->vc_font.width; + rows /= vc->vc_font.height; vc_resize(vc, cols, rows); + if (CON_IS_VISIBLE(vc)) { update_screen(vc); - if (softback_buf) { - int l = fbcon_softback_size / vc->vc_size_row; - - if (l > 5) - softback_end = softback_buf + l * - vc->vc_size_row; - else { - /* Smaller scrollback makes no sense, and 0 - would screw the operation totally */ - softback_top = 0; - } - } + if (softback_buf) + fbcon_update_softback(vc); } } static __inline__ void ywrap_up(struct vc_data *vc, int count) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; struct display *p = &fb_display[vc->vc_num]; p->yscroll += count; if (p->yscroll >= p->vrows) /* Deal with wrap */ p->yscroll -= p->vrows; - info->var.xoffset = 0; - info->var.yoffset = p->yscroll * vc->vc_font.height; - info->var.vmode |= FB_VMODE_YWRAP; - update_var(vc->vc_num, info); + ops->var.xoffset = 0; + ops->var.yoffset = p->yscroll * vc->vc_font.height; + ops->var.vmode |= FB_VMODE_YWRAP; + ops->update_start(info); scrollback_max += count; if (scrollback_max > scrollback_phys_max) scrollback_max = scrollback_phys_max; @@ -1259,15 +1366,16 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count) static __inline__ void ywrap_down(struct vc_data *vc, int count) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; struct display *p = &fb_display[vc->vc_num]; p->yscroll -= count; if (p->yscroll < 0) /* Deal with wrap */ p->yscroll += p->vrows; - info->var.xoffset = 0; - info->var.yoffset = p->yscroll * vc->vc_font.height; - info->var.vmode |= FB_VMODE_YWRAP; - update_var(vc->vc_num, info); + ops->var.xoffset = 0; + ops->var.yoffset = p->yscroll * vc->vc_font.height; + ops->var.vmode |= FB_VMODE_YWRAP; + ops->update_start(info); scrollback_max -= count; if (scrollback_max < 0) scrollback_max = 0; @@ -1286,10 +1394,11 @@ static __inline__ void ypan_up(struct vc_data *vc, int count) 0, 0, 0, vc->vc_rows, vc->vc_cols); p->yscroll -= p->vrows - vc->vc_rows; } - info->var.xoffset = 0; - info->var.yoffset = p->yscroll * vc->vc_font.height; - info->var.vmode &= ~FB_VMODE_YWRAP; - update_var(vc->vc_num, info); + + ops->var.xoffset = 0; + ops->var.yoffset = p->yscroll * vc->vc_font.height; + ops->var.vmode &= ~FB_VMODE_YWRAP; + ops->update_start(info); fbcon_clear_margins(vc, 1); scrollback_max += count; if (scrollback_max > scrollback_phys_max) @@ -1300,6 +1409,7 @@ static __inline__ void ypan_up(struct vc_data *vc, int count) static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; struct display *p = &fb_display[vc->vc_num]; int redraw = 0; @@ -1309,12 +1419,13 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) redraw = 1; } - info->var.xoffset = 0; - info->var.yoffset = p->yscroll * vc->vc_font.height; - info->var.vmode &= ~FB_VMODE_YWRAP; if (redraw) fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); - update_var(vc->vc_num, info); + + ops->var.xoffset = 0; + ops->var.yoffset = p->yscroll * vc->vc_font.height; + ops->var.vmode &= ~FB_VMODE_YWRAP; + ops->update_start(info); fbcon_clear_margins(vc, 1); scrollback_max += count; if (scrollback_max > scrollback_phys_max) @@ -1334,10 +1445,11 @@ static __inline__ void ypan_down(struct vc_data *vc, int count) 0, vc->vc_rows, vc->vc_cols); p->yscroll += p->vrows - vc->vc_rows; } - info->var.xoffset = 0; - info->var.yoffset = p->yscroll * vc->vc_font.height; - info->var.vmode &= ~FB_VMODE_YWRAP; - update_var(vc->vc_num, info); + + ops->var.xoffset = 0; + ops->var.yoffset = p->yscroll * vc->vc_font.height; + ops->var.vmode &= ~FB_VMODE_YWRAP; + ops->update_start(info); fbcon_clear_margins(vc, 1); scrollback_max -= count; if (scrollback_max < 0) @@ -1348,6 +1460,7 @@ static __inline__ void ypan_down(struct vc_data *vc, int count) static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; struct display *p = &fb_display[vc->vc_num]; int redraw = 0; @@ -1356,12 +1469,14 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) p->yscroll += p->vrows - vc->vc_rows; redraw = 1; } - info->var.xoffset = 0; - info->var.yoffset = p->yscroll * vc->vc_font.height; - info->var.vmode &= ~FB_VMODE_YWRAP; + if (redraw) fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); - update_var(vc->vc_num, info); + + ops->var.xoffset = 0; + ops->var.yoffset = p->yscroll * vc->vc_font.height; + ops->var.vmode &= ~FB_VMODE_YWRAP; + ops->update_start(info); fbcon_clear_margins(vc, 1); scrollback_max -= count; if (scrollback_max < 0) @@ -1835,31 +1950,41 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int s height, width); } -static __inline__ void updatescrollmode(struct display *p, struct fb_info *info, +static __inline__ void updatescrollmode(struct display *p, + struct fb_info *info, struct vc_data *vc) { + struct fbcon_ops *ops = info->fbcon_par; int fh = vc->vc_font.height; int cap = info->flags; - int good_pan = (cap & FBINFO_HWACCEL_YPAN) - && divides(info->fix.ypanstep, vc->vc_font.height) - && info->var.yres_virtual > info->var.yres; - int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) - && divides(info->fix.ywrapstep, vc->vc_font.height) - && divides(vc->vc_font.height, info->var.yres_virtual); + u16 t = 0; + int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep, + info->fix.xpanstep); + int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t); + int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); + int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual, + info->var.xres_virtual); + int good_pan = (cap & FBINFO_HWACCEL_YPAN) && + divides(ypan, vc->vc_font.height) && vyres > yres; + int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) && + divides(ywrap, vc->vc_font.height) && + divides(vc->vc_font.height, vyres); int reading_fast = cap & FBINFO_READS_FAST; - int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED); - int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && !(cap & FBINFO_HWACCEL_DISABLED); - - p->vrows = info->var.yres_virtual/fh; - if (info->var.yres > (fh * (vc->vc_rows + 1))) - p->vrows -= (info->var.yres - (fh * vc->vc_rows)) / fh; - if ((info->var.yres % fh) && (info->var.yres_virtual % fh < - info->var.yres % fh)) + int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && + !(cap & FBINFO_HWACCEL_DISABLED); + int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && + !(cap & FBINFO_HWACCEL_DISABLED); + + p->vrows = vyres/fh; + if (yres > (fh * (vc->vc_rows + 1))) + p->vrows -= (yres - (fh * vc->vc_rows)) / fh; + if ((yres % fh) && (vyres % fh < yres % fh)) p->vrows--; if (good_wrap || good_pan) { if (reading_fast || fast_copyarea) - p->scrollmode = good_wrap ? SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE; + p->scrollmode = good_wrap ? + SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE; else p->scrollmode = good_wrap ? SCROLL_REDRAW : SCROLL_PAN_REDRAW; @@ -1875,41 +2000,34 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, unsigned int height) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; struct display *p = &fb_display[vc->vc_num]; struct fb_var_screeninfo var = info->var; - int x_diff, y_diff; - int fw = vc->vc_font.width; - int fh = vc->vc_font.height; - - var.xres = width * fw; - var.yres = height * fh; + int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh; + + virt_w = FBCON_SWAP(ops->rotate, width, height); + virt_h = FBCON_SWAP(ops->rotate, height, width); + virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width, + vc->vc_font.height); + virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height, + vc->vc_font.width); + var.xres = virt_w * virt_fw; + var.yres = virt_h * virt_fh; x_diff = info->var.xres - var.xres; y_diff = info->var.yres - var.yres; - if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) { + if (x_diff < 0 || x_diff > virt_fw || + y_diff < 0 || y_diff > virt_fh) { struct fb_videomode *mode; DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); mode = fb_find_best_mode(&var, &info->modelist); if (mode == NULL) return -EINVAL; + display_to_var(&var, p); fb_videomode_to_var(&var, mode); - if (width > var.xres/fw || height > var.yres/fh) + + if (virt_w > var.xres/virt_fw || virt_h > var.yres/virt_fh) return -EINVAL; - /* - * The following can probably have any value... Do we need to - * set all of them? - */ - var.bits_per_pixel = p->bits_per_pixel; - var.xres_virtual = p->xres_virtual; - var.yres_virtual = p->yres_virtual; - var.accel_flags = p->accel_flags; - var.width = p->width; - var.height = p->height; - var.red = p->red; - var.green = p->green; - var.blue = p->blue; - var.transp = p->transp; - var.nonstd = p->nonstd; DPRINTK("resize now %ix%i\n", var.xres, var.yres); if (CON_IS_VISIBLE(vc)) { @@ -1918,6 +2036,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, fb_set_var(info, &var); } var_to_display(p, &info->var, info); + ops->var = info->var; } updatescrollmode(p, info, vc); return 0; @@ -1926,26 +2045,20 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, static int fbcon_switch(struct vc_data *vc) { struct fb_info *info, *old_info = NULL; + struct fbcon_ops *ops; struct display *p = &fb_display[vc->vc_num]; struct fb_var_screeninfo var; int i, prev_console; info = registered_fb[con2fb_map[vc->vc_num]]; + ops = info->fbcon_par; if (softback_top) { - int l = fbcon_softback_size / vc->vc_size_row; if (softback_lines) fbcon_set_origin(vc); softback_top = softback_curr = softback_in = softback_buf; softback_lines = 0; - - if (l > 5) - softback_end = softback_buf + l * vc->vc_size_row; - else { - /* Smaller scrollback makes no sense, and 0 would screw - the operation totally */ - softback_top = 0; - } + fbcon_update_softback(vc); } if (logo_shown >= 0) { @@ -1957,7 +2070,7 @@ static int fbcon_switch(struct vc_data *vc) logo_shown = FBCON_LOGO_CANSHOW; } - prev_console = ((struct fbcon_ops *)info->fbcon_par)->currcon; + prev_console = ops->currcon; if (prev_console != -1) old_info = registered_fb[con2fb_map[prev_console]]; /* @@ -1970,9 +2083,9 @@ static int fbcon_switch(struct vc_data *vc) */ for (i = 0; i < FB_MAX; i++) { if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) { - struct fbcon_ops *ops = registered_fb[i]->fbcon_par; + struct fbcon_ops *o = registered_fb[i]->fbcon_par; - ops->currcon = vc->vc_num; + o->currcon = vc->vc_num; } } memset(&var, 0, sizeof(struct fb_var_screeninfo)); @@ -1984,8 +2097,11 @@ static int fbcon_switch(struct vc_data *vc) * in fb_set_var() */ info->var.activate = var.activate; - info->var.yoffset = info->var.xoffset = p->yscroll = 0; + var.yoffset = info->var.yoffset; + var.xoffset = info->var.xoffset; + var.vmode = info->var.vmode; fb_set_var(info, &var); + ops->var = info->var; if (old_info != NULL && old_info != info) { if (info->fbops->fb_set_par) @@ -1995,7 +2111,12 @@ static int fbcon_switch(struct vc_data *vc) } set_blitting_type(vc, info, p); - ((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1; + ops->cursor_reset = 1; + + if (ops->rotate_font && ops->rotate_font(info, vc, p)) { + ops->rotate = FB_ROTATE_UR; + set_blitting_type(vc, info, p); + } vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; @@ -2015,10 +2136,11 @@ static int fbcon_switch(struct vc_data *vc) scrollback_phys_max = 0; break; } + scrollback_max = 0; scrollback_current = 0; - - update_var(vc->vc_num, info); + ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; + ops->update_start(info); fbcon_set_palette(vc, color_table); fbcon_clear_margins(vc, 0); @@ -2026,7 +2148,7 @@ static int fbcon_switch(struct vc_data *vc) logo_shown = fg_console; /* This is protected above by initmem_freed */ - fb_show_logo(info); + fb_show_logo(info, ops->rotate); update_region(vc, vc->vc_origin + vc->vc_size_row * vc->vc_top, vc->vc_size_row * (vc->vc_bottom - @@ -2065,6 +2187,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; fb_set_var(info, &var); ops->graphics = 0; + ops->var = info->var; } } @@ -2153,6 +2276,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, const u8 * data, int userfont) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; struct display *p = &fb_display[vc->vc_num]; int resize; int cnt; @@ -2232,20 +2356,15 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, } if (resize) { - /* reset wrap/pan */ - info->var.xoffset = info->var.yoffset = p->yscroll = 0; - vc_resize(vc, info->var.xres / w, info->var.yres / h); - if (CON_IS_VISIBLE(vc) && softback_buf) { - int l = fbcon_softback_size / vc->vc_size_row; - if (l > 5) - softback_end = - softback_buf + l * vc->vc_size_row; - else { - /* Smaller scrollback makes no sense, and 0 would screw - the operation totally */ - softback_top = 0; - } - } + int cols, rows; + + cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); + rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); + cols /= w; + rows /= h; + vc_resize(vc, cols, rows); + if (CON_IS_VISIBLE(vc) && softback_buf) + fbcon_update_softback(vc); } else if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { fbcon_clear_margins(vc, 0); @@ -2471,6 +2590,7 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt) static int fbcon_scrolldelta(struct vc_data *vc, int lines) { struct fb_info *info = registered_fb[con2fb_map[fg_console]]; + struct fbcon_ops *ops = info->fbcon_par; struct display *p = &fb_display[fg_console]; int offset, limit, scrollback_old; @@ -2547,9 +2667,11 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) offset += limit; else if (offset >= limit) offset -= limit; - info->var.xoffset = 0; - info->var.yoffset = offset * vc->vc_font.height; - update_var(vc->vc_num, info); + + ops->var.xoffset = 0; + ops->var.yoffset = offset * vc->vc_font.height; + ops->update_start(info); + if (!scrollback_current) fbcon_cursor(vc, CM_DRAW); return 0; @@ -2597,34 +2719,29 @@ static void fbcon_modechanged(struct fb_info *info) if (!ops || ops->currcon < 0) return; vc = vc_cons[ops->currcon].d; - if (vc->vc_mode != KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info) + if (vc->vc_mode != KD_TEXT || + registered_fb[con2fb_map[ops->currcon]] != info) return; p = &fb_display[vc->vc_num]; - - info->var.xoffset = info->var.yoffset = p->yscroll = 0; + set_blitting_type(vc, info, p); if (CON_IS_VISIBLE(vc)) { var_to_display(p, &info->var, info); - cols = info->var.xres / vc->vc_font.width; - rows = info->var.yres / vc->vc_font.height; + cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); + rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); + cols /= vc->vc_font.width; + rows /= vc->vc_font.height; vc_resize(vc, cols, rows); updatescrollmode(p, info, vc); scrollback_max = 0; scrollback_current = 0; - update_var(vc->vc_num, info); + ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; + ops->update_start(info); fbcon_set_palette(vc, color_table); update_screen(vc); - if (softback_buf) { - int l = fbcon_softback_size / vc->vc_size_row; - if (l > 5) - softback_end = softback_buf + l * vc->vc_size_row; - else { - /* Smaller scrollback makes no sense, and 0 - would screw the operation totally */ - softback_top = 0; - } - } + if (softback_buf) + fbcon_update_softback(vc); } } @@ -2645,30 +2762,24 @@ static void fbcon_set_all_vcs(struct fb_info *info) continue; p = &fb_display[vc->vc_num]; - - info->var.xoffset = info->var.yoffset = p->yscroll = 0; + set_blitting_type(vc, info, p); var_to_display(p, &info->var, info); - cols = info->var.xres / vc->vc_font.width; - rows = info->var.yres / vc->vc_font.height; + cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); + rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); + cols /= vc->vc_font.width; + rows /= vc->vc_font.height; vc_resize(vc, cols, rows); if (CON_IS_VISIBLE(vc)) { updatescrollmode(p, info, vc); scrollback_max = 0; scrollback_current = 0; - update_var(vc->vc_num, info); + ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; + ops->update_start(info); fbcon_set_palette(vc, color_table); update_screen(vc); - if (softback_buf) { - int l = fbcon_softback_size / vc->vc_size_row; - if (l > 5) - softback_end = softback_buf + l * vc->vc_size_row; - else { - /* Smaller scrollback makes no sense, and 0 - would screw the operation totally */ - softback_top = 0; - } - } + if (softback_buf) + fbcon_update_softback(vc); } } } @@ -2758,7 +2869,8 @@ static void fbcon_new_modelist(struct fb_info *info) continue; vc = vc_cons[i].d; display_to_var(&var, &fb_display[i]); - mode = fb_find_nearest_mode(&var, &info->modelist); + mode = fb_find_nearest_mode(fb_display[i].mode, + &info->modelist); fb_videomode_to_var(&var, mode); if (vc) @@ -2813,6 +2925,14 @@ static int fbcon_event_notify(struct notifier_block *self, case FB_EVENT_NEW_MODELIST: fbcon_new_modelist(info); break; + case FB_EVENT_SET_CON_ROTATE: + fbcon_rotate(info, *(int *)event->data); + break; + case FB_EVENT_GET_CON_ROTATE: + ret = fbcon_get_rotate(info); + break; + case FB_EVENT_SET_CON_ROTATE_ALL: + fbcon_rotate_all(info, *(int *)event->data); } return ret; diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 0738cd62def..6892e7ff34d 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -27,15 +27,15 @@ */ struct display { - /* Filled in by the frame buffer device */ - u_short inverse; /* != 0 text black on white as default */ /* Filled in by the low-level console driver */ const u_char *fontdata; int userfont; /* != 0 if fontdata kmalloc()ed */ u_short scrollmode; /* Scroll Method */ + u_short inverse; /* != 0 text black on white as default */ short yscroll; /* Hardware scrolling */ int vrows; /* number of virtual rows */ int cursor_shape; + int con_rotate; u32 xres_virtual; u32 yres_virtual; u32 height; @@ -63,17 +63,27 @@ struct fbcon_ops { void (*clear_margins)(struct vc_data *vc, struct fb_info *info, int bottom_only); void (*cursor)(struct vc_data *vc, struct fb_info *info, - struct display *p, int mode, int softback_lines, int fg, int bg); - + struct display *p, int mode, int softback_lines, + int fg, int bg); + int (*update_start)(struct fb_info *info); + int (*rotate_font)(struct fb_info *info, struct vc_data *vc, + struct display *p); + struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */ struct timer_list cursor_timer; /* Cursor timer */ struct fb_cursor cursor_state; + struct display *p; int currcon; /* Current VC. */ int cursor_flash; int cursor_reset; int blank_state; int graphics; int flags; + int rotate; + int cur_rotate; char *cursor_data; + u8 *fontbuffer; + u8 *fontdata; + u32 fd_size; }; /* * Attribute Decoding @@ -167,5 +177,48 @@ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, struct display *p, struct fbcon_ops *ops); #endif extern void fbcon_set_bitops(struct fbcon_ops *ops); +extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); + +#define FBCON_ATTRIBUTE_UNDERLINE 1 +#define FBCON_ATTRIBUTE_REVERSE 2 +#define FBCON_ATTRIBUTE_BOLD 4 + +static inline int real_y(struct display *p, int ypos) +{ + int rows = p->vrows; + + ypos += p->yscroll; + return ypos < rows ? ypos : ypos - rows; +} + + +static inline int get_attribute(struct fb_info *info, u16 c) +{ + int attribute = 0; + + if (fb_get_color_depth(&info->var, &info->fix) == 1) { + if (attr_underline(c)) + attribute |= FBCON_ATTRIBUTE_UNDERLINE; + if (attr_reverse(c)) + attribute |= FBCON_ATTRIBUTE_REVERSE; + if (attr_bold(c)) + attribute |= FBCON_ATTRIBUTE_BOLD; + } + + return attribute; +} + +#define FBCON_SWAP(i,r,v) ({ \ + typeof(r) _r = (r); \ + typeof(v) _v = (v); \ + (void) (&_r == &_v); \ + (i == FB_ROTATE_UR || i == FB_ROTATE_UD) ? _r : _v; }) + +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION +extern void fbcon_set_rotate(struct fbcon_ops *ops); +#else +#define fbcon_set_rotate(x) do {} while(0) +#endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */ #endif /* _VIDEO_FBCON_H */ + diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c new file mode 100644 index 00000000000..4952b66ae20 --- /dev/null +++ b/drivers/video/console/fbcon_ccw.c @@ -0,0 +1,426 @@ +/* + * linux/drivers/video/console/fbcon_ccw.c -- Software Rotation - 270 degrees + * + * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/vt_kern.h> +#include <linux/console.h> +#include <asm/types.h> +#include "fbcon.h" +#include "fbcon_rotate.h" + +/* + * Rotation 270 degrees + */ + +static inline void ccw_update_attr(u8 *dst, u8 *src, int attribute, + struct vc_data *vc) +{ + int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2; + int width = (vc->vc_font.height + 7) >> 3; + int mod = vc->vc_font.height % 8; + u8 c, msk = ~(0xff << offset), msk1 = 0; + + if (mod) + msk <<= (8 - mod); + + if (offset > mod) + msk1 |= 0x01; + + for (i = 0; i < vc->vc_font.width; i++) { + for (j = 0; j < width; j++) { + c = *src; + + if (attribute & FBCON_ATTRIBUTE_UNDERLINE) { + if (j == width - 1) + c |= msk; + + if (msk1 && j == width - 2) + c |= msk1; + } + + if (attribute & FBCON_ATTRIBUTE_BOLD && i) + *(dst - width) |= c; + + if (attribute & FBCON_ATTRIBUTE_REVERSE) + c = ~c; + src++; + *dst++ = c; + } + } +} + + +static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) +{ + struct fbcon_ops *ops = info->fbcon_par; + struct fb_copyarea area; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + + area.sx = sy * vc->vc_font.height; + area.sy = vyres - ((sx + width) * vc->vc_font.width); + area.dx = dy * vc->vc_font.height; + area.dy = vyres - ((dx + width) * vc->vc_font.width); + area.width = height * vc->vc_font.height; + area.height = width * vc->vc_font.width; + + info->fbops->fb_copyarea(info, &area); +} + +static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int height, int width) +{ + struct fbcon_ops *ops = info->fbcon_par; + struct fb_fillrect region; + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + + region.color = attr_bgcol_ec(bgshift,vc); + region.dx = sy * vc->vc_font.height; + region.dy = vyres - ((sx + width) * vc->vc_font.width); + region.height = width * vc->vc_font.width; + region.width = height * vc->vc_font.height; + region.rop = ROP_COPY; + + info->fbops->fb_fillrect(info, ®ion); +} + +static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info, + const u16 *s, u32 attr, u32 cnt, + u32 d_pitch, u32 s_pitch, u32 cellsize, + struct fb_image *image, u8 *buf, u8 *dst) +{ + struct fbcon_ops *ops = info->fbcon_par; + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 idx = (vc->vc_font.height + 7) >> 3; + u8 *src; + + while (cnt--) { + src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize; + + if (attr) { + ccw_update_attr(buf, src, attr, vc); + src = buf; + } + + if (likely(idx == 1)) + __fb_pad_aligned_buffer(dst, d_pitch, src, idx, + vc->vc_font.width); + else + fb_pad_aligned_buffer(dst, d_pitch, src, idx, + vc->vc_font.width); + + dst += d_pitch * vc->vc_font.width; + } + + info->fbops->fb_imageblit(info, image); +} + +static void ccw_putcs(struct vc_data *vc, struct fb_info *info, + const unsigned short *s, int count, int yy, int xx, + int fg, int bg) +{ + struct fb_image image; + struct fbcon_ops *ops = info->fbcon_par; + u32 width = (vc->vc_font.height + 7)/8; + u32 cellsize = width * vc->vc_font.width; + u32 maxcnt = info->pixmap.size/cellsize; + u32 scan_align = info->pixmap.scan_align - 1; + u32 buf_align = info->pixmap.buf_align - 1; + u32 cnt, pitch, size; + u32 attribute = get_attribute(info, scr_readw(s)); + u8 *dst, *buf = NULL; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + + if (!ops->fontbuffer) + return; + + image.fg_color = fg; + image.bg_color = bg; + image.dx = yy * vc->vc_font.height; + image.dy = vyres - ((xx + count) * vc->vc_font.width); + image.width = vc->vc_font.height; + image.depth = 1; + + if (attribute) { + buf = kmalloc(cellsize, GFP_KERNEL); + if (!buf) + return; + } + + s += count - 1; + + while (count) { + if (count > maxcnt) + cnt = maxcnt; + else + cnt = count; + + image.height = vc->vc_font.width * cnt; + pitch = ((image.width + 7) >> 3) + scan_align; + pitch &= ~scan_align; + size = pitch * image.height + buf_align; + size &= ~buf_align; + dst = fb_get_buffer_offset(info, &info->pixmap, size); + image.data = dst; + ccw_putcs_aligned(vc, info, s, attribute, cnt, pitch, + width, cellsize, &image, buf, dst); + image.dy += image.height; + count -= cnt; + s -= cnt; + } + + /* buf is always NULL except when in monochrome mode, so in this case + it's a gain to check buf against NULL even though kfree() handles + NULL pointers just fine */ + if (unlikely(buf)) + kfree(buf); + +} + +static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info, + int bottom_only) +{ + unsigned int cw = vc->vc_font.width; + unsigned int ch = vc->vc_font.height; + unsigned int rw = info->var.yres - (vc->vc_cols*cw); + unsigned int bh = info->var.xres - (vc->vc_rows*ch); + unsigned int bs = vc->vc_rows*ch; + struct fb_fillrect region; + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + + region.color = attr_bgcol_ec(bgshift,vc); + region.rop = ROP_COPY; + + if (rw && !bottom_only) { + region.dx = 0; + region.dy = info->var.yoffset; + region.height = rw; + region.width = info->var.xres_virtual; + info->fbops->fb_fillrect(info, ®ion); + } + + if (bh) { + region.dx = info->var.xoffset + bs; + region.dy = 0; + region.height = info->var.yres_virtual; + region.width = bh; + info->fbops->fb_fillrect(info, ®ion); + } +} + +static void ccw_cursor(struct vc_data *vc, struct fb_info *info, + struct display *p, int mode, int softback_lines, + int fg, int bg) +{ + struct fb_cursor cursor; + struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int w = (vc->vc_font.height + 7) >> 3, c; + int y = real_y(p, vc->vc_y); + int attribute, use_sw = (vc->vc_cursor_type & 0x10); + int err = 1, dx, dy; + char *src; + u32 vyres = GETVYRES(p->scrollmode, info); + + if (!ops->fontbuffer) + return; + + cursor.set = 0; + + if (softback_lines) { + if (y + softback_lines >= vc->vc_rows) { + mode = CM_ERASE; + ops->cursor_flash = 0; + return; + } else + y += softback_lines; + } + + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); + src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); + + if (ops->cursor_state.image.data != src || + ops->cursor_reset) { + ops->cursor_state.image.data = src; + cursor.set |= FB_CUR_SETIMAGE; + } + + if (attribute) { + u8 *dst; + + dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC); + if (!dst) + return; + kfree(ops->cursor_data); + ops->cursor_data = dst; + ccw_update_attr(dst, src, attribute, vc); + src = dst; + } + + if (ops->cursor_state.image.fg_color != fg || + ops->cursor_state.image.bg_color != bg || + ops->cursor_reset) { + ops->cursor_state.image.fg_color = fg; + ops->cursor_state.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + + if (ops->cursor_state.image.height != vc->vc_font.width || + ops->cursor_state.image.width != vc->vc_font.height || + ops->cursor_reset) { + ops->cursor_state.image.height = vc->vc_font.width; + ops->cursor_state.image.width = vc->vc_font.height; + cursor.set |= FB_CUR_SETSIZE; + } + + dx = y * vc->vc_font.height; + dy = vyres - ((vc->vc_x + 1) * vc->vc_font.width); + + if (ops->cursor_state.image.dx != dx || + ops->cursor_state.image.dy != dy || + ops->cursor_reset) { + ops->cursor_state.image.dx = dx; + ops->cursor_state.image.dy = dy; + cursor.set |= FB_CUR_SETPOS; + } + + if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || + ops->cursor_reset) { + ops->cursor_state.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if (cursor.set & FB_CUR_SETSIZE || + vc->vc_cursor_type != p->cursor_shape || + ops->cursor_state.mask == NULL || + ops->cursor_reset) { + char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC); + int cur_height, size, i = 0; + int width = (vc->vc_font.width + 7)/8; + + if (!mask) + return; + + tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC); + + if (!tmp) { + kfree(mask); + return; + } + + kfree(ops->cursor_state.mask); + ops->cursor_state.mask = mask; + + p->cursor_shape = vc->vc_cursor_type; + cursor.set |= FB_CUR_SETSHAPE; + + switch (p->cursor_shape & CUR_HWMASK) { + case CUR_NONE: + cur_height = 0; + break; + case CUR_UNDERLINE: + cur_height = (vc->vc_font.height < 10) ? 1 : 2; + break; + case CUR_LOWER_THIRD: + cur_height = vc->vc_font.height/3; + break; + case CUR_LOWER_HALF: + cur_height = vc->vc_font.height >> 1; + break; + case CUR_TWO_THIRDS: + cur_height = (vc->vc_font.height << 1)/3; + break; + case CUR_BLOCK: + default: + cur_height = vc->vc_font.height; + break; + } + + size = (vc->vc_font.height - cur_height) * width; + while (size--) + tmp[i++] = 0; + size = cur_height * width; + while (size--) + tmp[i++] = 0xff; + memset(mask, 0, w * vc->vc_font.width); + rotate_ccw(tmp, mask, vc->vc_font.width, vc->vc_font.height); + kfree(tmp); + } + + switch (mode) { + case CM_ERASE: + ops->cursor_state.enable = 0; + break; + case CM_DRAW: + case CM_MOVE: + default: + ops->cursor_state.enable = (use_sw) ? 0 : 1; + break; + } + + cursor.image.data = src; + cursor.image.fg_color = ops->cursor_state.image.fg_color; + cursor.image.bg_color = ops->cursor_state.image.bg_color; + cursor.image.dx = ops->cursor_state.image.dx; + cursor.image.dy = ops->cursor_state.image.dy; + cursor.image.height = ops->cursor_state.image.height; + cursor.image.width = ops->cursor_state.image.width; + cursor.hot.x = ops->cursor_state.hot.x; + cursor.hot.y = ops->cursor_state.hot.y; + cursor.mask = ops->cursor_state.mask; + cursor.enable = ops->cursor_state.enable; + cursor.image.depth = 1; + cursor.rop = ROP_XOR; + + if (info->fbops->fb_cursor) + err = info->fbops->fb_cursor(info, &cursor); + + if (err) + soft_cursor(info, &cursor); + + ops->cursor_reset = 0; +} + +int ccw_update_start(struct fb_info *info) +{ + struct fbcon_ops *ops = info->fbcon_par; + u32 yoffset; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + int err; + + yoffset = (vyres - info->var.yres) - ops->var.xoffset; + ops->var.xoffset = ops->var.yoffset; + ops->var.yoffset = yoffset; + err = fb_pan_display(info, &ops->var); + ops->var.xoffset = info->var.xoffset; + ops->var.yoffset = info->var.yoffset; + ops->var.vmode = info->var.vmode; + return err; +} + +void fbcon_rotate_ccw(struct fbcon_ops *ops) +{ + ops->bmove = ccw_bmove; + ops->clear = ccw_clear; + ops->putcs = ccw_putcs; + ops->clear_margins = ccw_clear_margins; + ops->cursor = ccw_cursor; + ops->update_start = ccw_update_start; +} +EXPORT_SYMBOL(fbcon_rotate_ccw); + +MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); +MODULE_DESCRIPTION("Console Rotation (270 degrees) Support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c new file mode 100644 index 00000000000..6d92b845620 --- /dev/null +++ b/drivers/video/console/fbcon_cw.c @@ -0,0 +1,410 @@ +/* + * linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 90 degrees + * + * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/vt_kern.h> +#include <linux/console.h> +#include <asm/types.h> +#include "fbcon.h" +#include "fbcon_rotate.h" + +/* + * Rotation 90 degrees + */ + +static inline void cw_update_attr(u8 *dst, u8 *src, int attribute, + struct vc_data *vc) +{ + int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2; + int width = (vc->vc_font.height + 7) >> 3; + u8 c, t = 0, msk = ~(0xff >> offset); + + for (i = 0; i < vc->vc_font.width; i++) { + for (j = 0; j < width; j++) { + c = *src; + if (attribute & FBCON_ATTRIBUTE_UNDERLINE && !j) + c |= msk; + if (attribute & FBCON_ATTRIBUTE_BOLD && i) + c |= *(src-width); + if (attribute & FBCON_ATTRIBUTE_REVERSE) + c = ~c; + src++; + *dst++ = c; + t = c; + } + } +} + + +static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) +{ + struct fbcon_ops *ops = info->fbcon_par; + struct fb_copyarea area; + u32 vxres = GETVXRES(ops->p->scrollmode, info); + + area.sx = vxres - ((sy + height) * vc->vc_font.height); + area.sy = sx * vc->vc_font.width; + area.dx = vxres - ((dy + height) * vc->vc_font.height); + area.dy = dx * vc->vc_font.width; + area.width = height * vc->vc_font.height; + area.height = width * vc->vc_font.width; + + info->fbops->fb_copyarea(info, &area); +} + +static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int height, int width) +{ + struct fbcon_ops *ops = info->fbcon_par; + struct fb_fillrect region; + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + u32 vxres = GETVXRES(ops->p->scrollmode, info); + + region.color = attr_bgcol_ec(bgshift,vc); + region.dx = vxres - ((sy + height) * vc->vc_font.height); + region.dy = sx * vc->vc_font.width; + region.height = width * vc->vc_font.width; + region.width = height * vc->vc_font.height; + region.rop = ROP_COPY; + + info->fbops->fb_fillrect(info, ®ion); +} + +static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info, + const u16 *s, u32 attr, u32 cnt, + u32 d_pitch, u32 s_pitch, u32 cellsize, + struct fb_image *image, u8 *buf, u8 *dst) +{ + struct fbcon_ops *ops = info->fbcon_par; + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 idx = (vc->vc_font.height + 7) >> 3; + u8 *src; + + while (cnt--) { + src = ops->fontbuffer + (scr_readw(s++) & charmask)*cellsize; + + if (attr) { + cw_update_attr(buf, src, attr, vc); + src = buf; + } + + if (likely(idx == 1)) + __fb_pad_aligned_buffer(dst, d_pitch, src, idx, + vc->vc_font.width); + else + fb_pad_aligned_buffer(dst, d_pitch, src, idx, + vc->vc_font.width); + + dst += d_pitch * vc->vc_font.width; + } + + info->fbops->fb_imageblit(info, image); +} + +static void cw_putcs(struct vc_data *vc, struct fb_info *info, + const unsigned short *s, int count, int yy, int xx, + int fg, int bg) +{ + struct fb_image image; + struct fbcon_ops *ops = info->fbcon_par; + u32 width = (vc->vc_font.height + 7)/8; + u32 cellsize = width * vc->vc_font.width; + u32 maxcnt = info->pixmap.size/cellsize; + u32 scan_align = info->pixmap.scan_align - 1; + u32 buf_align = info->pixmap.buf_align - 1; + u32 cnt, pitch, size; + u32 attribute = get_attribute(info, scr_readw(s)); + u8 *dst, *buf = NULL; + u32 vxres = GETVXRES(ops->p->scrollmode, info); + + if (!ops->fontbuffer) + return; + + image.fg_color = fg; + image.bg_color = bg; + image.dx = vxres - ((yy + 1) * vc->vc_font.height); + image.dy = xx * vc->vc_font.width; + image.width = vc->vc_font.height; + image.depth = 1; + + if (attribute) { + buf = kmalloc(cellsize, GFP_KERNEL); + if (!buf) + return; + } + + while (count) { + if (count > maxcnt) + cnt = maxcnt; + else + cnt = count; + + image.height = vc->vc_font.width * cnt; + pitch = ((image.width + 7) >> 3) + scan_align; + pitch &= ~scan_align; + size = pitch * image.height + buf_align; + size &= ~buf_align; + dst = fb_get_buffer_offset(info, &info->pixmap, size); + image.data = dst; + cw_putcs_aligned(vc, info, s, attribute, cnt, pitch, + width, cellsize, &image, buf, dst); + image.dy += image.height; + count -= cnt; + s += cnt; + } + + /* buf is always NULL except when in monochrome mode, so in this case + it's a gain to check buf against NULL even though kfree() handles + NULL pointers just fine */ + if (unlikely(buf)) + kfree(buf); + +} + +static void cw_clear_margins(struct vc_data *vc, struct fb_info *info, + int bottom_only) +{ + unsigned int cw = vc->vc_font.width; + unsigned int ch = vc->vc_font.height; + unsigned int rw = info->var.yres - (vc->vc_cols*cw); + unsigned int bh = info->var.xres - (vc->vc_rows*ch); + unsigned int rs = info->var.yres - rw; + struct fb_fillrect region; + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + + region.color = attr_bgcol_ec(bgshift,vc); + region.rop = ROP_COPY; + + if (rw && !bottom_only) { + region.dx = 0; + region.dy = info->var.yoffset + rs; + region.height = rw; + region.width = info->var.xres_virtual; + info->fbops->fb_fillrect(info, ®ion); + } + + if (bh) { + region.dx = info->var.xoffset; + region.dy = info->var.yoffset; + region.height = info->var.yres; + region.width = bh; + info->fbops->fb_fillrect(info, ®ion); + } +} + +static void cw_cursor(struct vc_data *vc, struct fb_info *info, + struct display *p, int mode, int softback_lines, + int fg, int bg) +{ + struct fb_cursor cursor; + struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int w = (vc->vc_font.height + 7) >> 3, c; + int y = real_y(p, vc->vc_y); + int attribute, use_sw = (vc->vc_cursor_type & 0x10); + int err = 1, dx, dy; + char *src; + u32 vxres = GETVXRES(p->scrollmode, info); + + if (!ops->fontbuffer) + return; + + cursor.set = 0; + + if (softback_lines) { + if (y + softback_lines >= vc->vc_rows) { + mode = CM_ERASE; + ops->cursor_flash = 0; + return; + } else + y += softback_lines; + } + + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); + src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); + + if (ops->cursor_state.image.data != src || + ops->cursor_reset) { + ops->cursor_state.image.data = src; + cursor.set |= FB_CUR_SETIMAGE; + } + + if (attribute) { + u8 *dst; + + dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC); + if (!dst) + return; + kfree(ops->cursor_data); + ops->cursor_data = dst; + cw_update_attr(dst, src, attribute, vc); + src = dst; + } + + if (ops->cursor_state.image.fg_color != fg || + ops->cursor_state.image.bg_color != bg || + ops->cursor_reset) { + ops->cursor_state.image.fg_color = fg; + ops->cursor_state.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + + if (ops->cursor_state.image.height != vc->vc_font.width || + ops->cursor_state.image.width != vc->vc_font.height || + ops->cursor_reset) { + ops->cursor_state.image.height = vc->vc_font.width; + ops->cursor_state.image.width = vc->vc_font.height; + cursor.set |= FB_CUR_SETSIZE; + } + + dx = vxres - ((y * vc->vc_font.height) + vc->vc_font.height); + dy = vc->vc_x * vc->vc_font.width; + + if (ops->cursor_state.image.dx != dx || + ops->cursor_state.image.dy != dy || + ops->cursor_reset) { + ops->cursor_state.image.dx = dx; + ops->cursor_state.image.dy = dy; + cursor.set |= FB_CUR_SETPOS; + } + + if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || + ops->cursor_reset) { + ops->cursor_state.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if (cursor.set & FB_CUR_SETSIZE || + vc->vc_cursor_type != p->cursor_shape || + ops->cursor_state.mask == NULL || + ops->cursor_reset) { + char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC); + int cur_height, size, i = 0; + int width = (vc->vc_font.width + 7)/8; + + if (!mask) + return; + + tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC); + + if (!tmp) { + kfree(mask); + return; + } + + kfree(ops->cursor_state.mask); + ops->cursor_state.mask = mask; + + p->cursor_shape = vc->vc_cursor_type; + cursor.set |= FB_CUR_SETSHAPE; + + switch (p->cursor_shape & CUR_HWMASK) { + case CUR_NONE: + cur_height = 0; + break; + case CUR_UNDERLINE: + cur_height = (vc->vc_font.height < 10) ? 1 : 2; + break; + case CUR_LOWER_THIRD: + cur_height = vc->vc_font.height/3; + break; + case CUR_LOWER_HALF: + cur_height = vc->vc_font.height >> 1; + break; + case CUR_TWO_THIRDS: + cur_height = (vc->vc_font.height << 1)/3; + break; + case CUR_BLOCK: + default: + cur_height = vc->vc_font.height; + break; + } + + size = (vc->vc_font.height - cur_height) * width; + while (size--) + tmp[i++] = 0; + size = cur_height * width; + while (size--) + tmp[i++] = 0xff; + memset(mask, 0, w * vc->vc_font.width); + rotate_cw(tmp, mask, vc->vc_font.width, vc->vc_font.height); + kfree(tmp); + } + + switch (mode) { + case CM_ERASE: + ops->cursor_state.enable = 0; + break; + case CM_DRAW: + case CM_MOVE: + default: + ops->cursor_state.enable = (use_sw) ? 0 : 1; + break; + } + + cursor.image.data = src; + cursor.image.fg_color = ops->cursor_state.image.fg_color; + cursor.image.bg_color = ops->cursor_state.image.bg_color; + cursor.image.dx = ops->cursor_state.image.dx; + cursor.image.dy = ops->cursor_state.image.dy; + cursor.image.height = ops->cursor_state.image.height; + cursor.image.width = ops->cursor_state.image.width; + cursor.hot.x = ops->cursor_state.hot.x; + cursor.hot.y = ops->cursor_state.hot.y; + cursor.mask = ops->cursor_state.mask; + cursor.enable = ops->cursor_state.enable; + cursor.image.depth = 1; + cursor.rop = ROP_XOR; + + if (info->fbops->fb_cursor) + err = info->fbops->fb_cursor(info, &cursor); + + if (err) + soft_cursor(info, &cursor); + + ops->cursor_reset = 0; +} + +int cw_update_start(struct fb_info *info) +{ + struct fbcon_ops *ops = info->fbcon_par; + u32 vxres = GETVXRES(ops->p->scrollmode, info); + u32 xoffset; + int err; + + xoffset = vxres - (info->var.xres + ops->var.yoffset); + ops->var.yoffset = ops->var.xoffset; + ops->var.xoffset = xoffset; + err = fb_pan_display(info, &ops->var); + ops->var.xoffset = info->var.xoffset; + ops->var.yoffset = info->var.yoffset; + ops->var.vmode = info->var.vmode; + return err; +} + +void fbcon_rotate_cw(struct fbcon_ops *ops) +{ + ops->bmove = cw_bmove; + ops->clear = cw_clear; + ops->putcs = cw_putcs; + ops->clear_margins = cw_clear_margins; + ops->cursor = cw_cursor; + ops->update_start = cw_update_start; +} +EXPORT_SYMBOL(fbcon_rotate_cw); + +MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); +MODULE_DESCRIPTION("Console Rotation (90 degrees) Support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/console/fbcon_rotate.c b/drivers/video/console/fbcon_rotate.c new file mode 100644 index 00000000000..ec0dd8fe241 --- /dev/null +++ b/drivers/video/console/fbcon_rotate.c @@ -0,0 +1,117 @@ +/* + * linux/drivers/video/console/fbcon_rotate.c -- Software Rotation + * + * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/vt_kern.h> +#include <linux/console.h> +#include <asm/types.h> +#include "fbcon.h" +#include "fbcon_rotate.h" + +static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc, + struct display *p) +{ + struct fbcon_ops *ops = info->fbcon_par; + int len, err = 0; + int s_cellsize, d_cellsize, i; + const u8 *src; + u8 *dst; + + if (vc->vc_font.data == ops->fontdata && + p->con_rotate == ops->cur_rotate) + goto finished; + + src = ops->fontdata = vc->vc_font.data; + ops->cur_rotate = p->con_rotate; + len = (!p->userfont) ? 256 : FNTCHARCNT(src); + s_cellsize = ((vc->vc_font.width + 7)/8) * + vc->vc_font.height; + d_cellsize = s_cellsize; + + if (ops->rotate == FB_ROTATE_CW || + ops->rotate == FB_ROTATE_CCW) + d_cellsize = ((vc->vc_font.height + 7)/8) * + vc->vc_font.width; + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + if (ops->fd_size < d_cellsize * len) { + dst = kmalloc(d_cellsize * len, GFP_KERNEL); + + if (dst == NULL) { + err = -ENOMEM; + goto finished; + } + + ops->fd_size = d_cellsize * len; + kfree(ops->fontbuffer); + ops->fontbuffer = dst; + } + + dst = ops->fontbuffer; + memset(dst, 0, ops->fd_size); + + switch (ops->rotate) { + case FB_ROTATE_UD: + for (i = len; i--; ) { + rotate_ud(src, dst, vc->vc_font.width, + vc->vc_font.height); + + src += s_cellsize; + dst += d_cellsize; + } + break; + case FB_ROTATE_CW: + for (i = len; i--; ) { + rotate_cw(src, dst, vc->vc_font.width, + vc->vc_font.height); + src += s_cellsize; + dst += d_cellsize; + } + break; + case FB_ROTATE_CCW: + for (i = len; i--; ) { + rotate_ccw(src, dst, vc->vc_font.width, + vc->vc_font.height); + src += s_cellsize; + dst += d_cellsize; + } + break; + } + +finished: + return err; +} + +void fbcon_set_rotate(struct fbcon_ops *ops) +{ + ops->rotate_font = fbcon_rotate_font; + + switch(ops->rotate) { + case FB_ROTATE_CW: + fbcon_rotate_cw(ops); + break; + case FB_ROTATE_UD: + fbcon_rotate_ud(ops); + break; + case FB_ROTATE_CCW: + fbcon_rotate_ccw(ops); + break; + } +} +EXPORT_SYMBOL(fbcon_set_rotate); + +MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); +MODULE_DESCRIPTION("Console Rotation Support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/console/fbcon_rotate.h b/drivers/video/console/fbcon_rotate.h new file mode 100644 index 00000000000..1b8f92fdc6a --- /dev/null +++ b/drivers/video/console/fbcon_rotate.h @@ -0,0 +1,98 @@ +/* + * linux/drivers/video/console/fbcon_rotate.h -- Software Display Rotation + * + * Copyright (C) 2005 Antonino Daplas <adaplas@pol.net> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef _FBCON_ROTATE_H +#define _FBCON_ROTATE_H + +#define FNTCHARCNT(fd) (((int *)(fd))[-3]) + +#define GETVYRES(s,i) ({ \ + (s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \ + (i)->var.yres : (i)->var.yres_virtual; }) + +#define GETVXRES(s,i) ({ \ + (s == SCROLL_REDRAW || s == SCROLL_MOVE || !(i)->fix.xpanstep) ? \ + (i)->var.xres : (i)->var.xres_virtual; }) + + +static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat) +{ + u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8; + + pat +=index; + return (*pat) & (0x80 >> bit); +} + +static inline void pattern_set_bit(u32 x, u32 y, u32 pitch, char *pat) +{ + u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8; + + pat += index; + + (*pat) |= 0x80 >> bit; +} + +static inline void rotate_ud(const char *in, char *out, u32 width, u32 height) +{ + int i, j; + int shift = (8 - (width % 8)) & 7; + + width = (width + 7) & ~7; + + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + if (pattern_test_bit(j, i, width, in)) + pattern_set_bit(width - (1 + j + shift), + height - (1 + i), + width, out); + } + + } +} + +static inline void rotate_cw(const char *in, char *out, u32 width, u32 height) +{ + int i, j, h = height, w = width; + int shift = (8 - (height % 8)) & 7; + + width = (width + 7) & ~7; + height = (height + 7) & ~7; + + for (i = 0; i < h; i++) { + for (j = 0; j < w; j++) { + if (pattern_test_bit(j, i, width, in)) + pattern_set_bit(height - 1 - i - shift, j, + height, out); + + } + } +} + +static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height) +{ + int i, j, h = height, w = width; + int shift = (8 - (width % 8)) & 7; + + width = (width + 7) & ~7; + height = (height + 7) & ~7; + + for (i = 0; i < h; i++) { + for (j = 0; j < w; j++) { + if (pattern_test_bit(j, i, width, in)) + pattern_set_bit(i, width - 1 - j - shift, + height, out); + } + } +} + +extern void fbcon_rotate_cw(struct fbcon_ops *ops); +extern void fbcon_rotate_ud(struct fbcon_ops *ops); +extern void fbcon_rotate_ccw(struct fbcon_ops *ops); +#endif diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c new file mode 100644 index 00000000000..c4d7c89212b --- /dev/null +++ b/drivers/video/console/fbcon_ud.c @@ -0,0 +1,452 @@ +/* + * linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 180 degrees + * + * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/vt_kern.h> +#include <linux/console.h> +#include <asm/types.h> +#include "fbcon.h" +#include "fbcon_rotate.h" + +/* + * Rotation 180 degrees + */ + +static inline void ud_update_attr(u8 *dst, u8 *src, int attribute, + struct vc_data *vc) +{ + int i, offset = (vc->vc_font.height < 10) ? 1 : 2; + int width = (vc->vc_font.width + 7) >> 3; + unsigned int cellsize = vc->vc_font.height * width; + u8 c; + + offset = offset * width; + + for (i = 0; i < cellsize; i++) { + c = src[i]; + if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i < offset) + c = 0xff; + if (attribute & FBCON_ATTRIBUTE_BOLD) + c |= c << 1; + if (attribute & FBCON_ATTRIBUTE_REVERSE) + c = ~c; + dst[i] = c; + } +} + + +static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int dy, int dx, int height, int width) +{ + struct fbcon_ops *ops = info->fbcon_par; + struct fb_copyarea area; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + u32 vxres = GETVXRES(ops->p->scrollmode, info); + + area.sy = vyres - ((sy + height) * vc->vc_font.height); + area.sx = vxres - ((sx + width) * vc->vc_font.width); + area.dy = vyres - ((dy + height) * vc->vc_font.height); + area.dx = vxres - ((dx + width) * vc->vc_font.width); + area.height = height * vc->vc_font.height; + area.width = width * vc->vc_font.width; + + info->fbops->fb_copyarea(info, &area); +} + +static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy, + int sx, int height, int width) +{ + struct fbcon_ops *ops = info->fbcon_par; + struct fb_fillrect region; + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + u32 vxres = GETVXRES(ops->p->scrollmode, info); + + region.color = attr_bgcol_ec(bgshift,vc); + region.dy = vyres - ((sy + height) * vc->vc_font.height); + region.dx = vxres - ((sx + width) * vc->vc_font.width); + region.width = width * vc->vc_font.width; + region.height = height * vc->vc_font.height; + region.rop = ROP_COPY; + + info->fbops->fb_fillrect(info, ®ion); +} + +static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info, + const u16 *s, u32 attr, u32 cnt, + u32 d_pitch, u32 s_pitch, u32 cellsize, + struct fb_image *image, u8 *buf, u8 *dst) +{ + struct fbcon_ops *ops = info->fbcon_par; + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 idx = vc->vc_font.width >> 3; + u8 *src; + + while (cnt--) { + src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize; + + if (attr) { + ud_update_attr(buf, src, attr, vc); + src = buf; + } + + if (likely(idx == 1)) + __fb_pad_aligned_buffer(dst, d_pitch, src, idx, + image->height); + else + fb_pad_aligned_buffer(dst, d_pitch, src, idx, + image->height); + + dst += s_pitch; + } + + info->fbops->fb_imageblit(info, image); +} + +static inline void ud_putcs_unaligned(struct vc_data *vc, + struct fb_info *info, const u16 *s, + u32 attr, u32 cnt, u32 d_pitch, + u32 s_pitch, u32 cellsize, + struct fb_image *image, u8 *buf, + u8 *dst) +{ + struct fbcon_ops *ops = info->fbcon_par; + u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + u32 shift_low = 0, mod = vc->vc_font.width % 8; + u32 shift_high = 8; + u32 idx = vc->vc_font.width >> 3; + u8 *src; + + while (cnt--) { + src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize; + + if (attr) { + ud_update_attr(buf, src, attr, vc); + src = buf; + } + + fb_pad_unaligned_buffer(dst, d_pitch, src, idx, + image->height, shift_high, + shift_low, mod); + shift_low += mod; + dst += (shift_low >= 8) ? s_pitch : s_pitch - 1; + shift_low &= 7; + shift_high = 8 - shift_low; + } + + info->fbops->fb_imageblit(info, image); + +} + +static void ud_putcs(struct vc_data *vc, struct fb_info *info, + const unsigned short *s, int count, int yy, int xx, + int fg, int bg) +{ + struct fb_image image; + struct fbcon_ops *ops = info->fbcon_par; + u32 width = (vc->vc_font.width + 7)/8; + u32 cellsize = width * vc->vc_font.height; + u32 maxcnt = info->pixmap.size/cellsize; + u32 scan_align = info->pixmap.scan_align - 1; + u32 buf_align = info->pixmap.buf_align - 1; + u32 mod = vc->vc_font.width % 8, cnt, pitch, size; + u32 attribute = get_attribute(info, scr_readw(s)); + u8 *dst, *buf = NULL; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + u32 vxres = GETVXRES(ops->p->scrollmode, info); + + if (!ops->fontbuffer) + return; + + image.fg_color = fg; + image.bg_color = bg; + image.dy = vyres - ((yy * vc->vc_font.height) + vc->vc_font.height); + image.dx = vxres - ((xx + count) * vc->vc_font.width); + image.height = vc->vc_font.height; + image.depth = 1; + + if (attribute) { + buf = kmalloc(cellsize, GFP_KERNEL); + if (!buf) + return; + } + + s += count - 1; + + while (count) { + if (count > maxcnt) + cnt = maxcnt; + else + cnt = count; + + image.width = vc->vc_font.width * cnt; + pitch = ((image.width + 7) >> 3) + scan_align; + pitch &= ~scan_align; + size = pitch * image.height + buf_align; + size &= ~buf_align; + dst = fb_get_buffer_offset(info, &info->pixmap, size); + image.data = dst; + + if (!mod) + ud_putcs_aligned(vc, info, s, attribute, cnt, pitch, + width, cellsize, &image, buf, dst); + else + ud_putcs_unaligned(vc, info, s, attribute, cnt, pitch, + width, cellsize, &image, + buf, dst); + + image.dx += image.width; + count -= cnt; + s -= cnt; + xx += cnt; + } + + /* buf is always NULL except when in monochrome mode, so in this case + it's a gain to check buf against NULL even though kfree() handles + NULL pointers just fine */ + if (unlikely(buf)) + kfree(buf); + +} + +static void ud_clear_margins(struct vc_data *vc, struct fb_info *info, + int bottom_only) +{ + unsigned int cw = vc->vc_font.width; + unsigned int ch = vc->vc_font.height; + unsigned int rw = info->var.xres - (vc->vc_cols*cw); + unsigned int bh = info->var.yres - (vc->vc_rows*ch); + struct fb_fillrect region; + int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; + + region.color = attr_bgcol_ec(bgshift,vc); + region.rop = ROP_COPY; + + if (rw && !bottom_only) { + region.dy = 0; + region.dx = info->var.xoffset; + region.width = rw; + region.height = info->var.yres_virtual; + info->fbops->fb_fillrect(info, ®ion); + } + + if (bh) { + region.dy = info->var.yoffset; + region.dx = info->var.xoffset; + region.height = bh; + region.width = info->var.xres; + info->fbops->fb_fillrect(info, ®ion); + } +} + +static void ud_cursor(struct vc_data *vc, struct fb_info *info, + struct display *p, int mode, int softback_lines, + int fg, int bg) +{ + struct fb_cursor cursor; + struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; + unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + int w = (vc->vc_font.width + 7) >> 3, c; + int y = real_y(p, vc->vc_y); + int attribute, use_sw = (vc->vc_cursor_type & 0x10); + int err = 1, dx, dy; + char *src; + u32 vyres = GETVYRES(p->scrollmode, info); + u32 vxres = GETVXRES(p->scrollmode, info); + + if (!ops->fontbuffer) + return; + + cursor.set = 0; + + if (softback_lines) { + if (y + softback_lines >= vc->vc_rows) { + mode = CM_ERASE; + ops->cursor_flash = 0; + return; + } else + y += softback_lines; + } + + c = scr_readw((u16 *) vc->vc_pos); + attribute = get_attribute(info, c); + src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height)); + + if (ops->cursor_state.image.data != src || + ops->cursor_reset) { + ops->cursor_state.image.data = src; + cursor.set |= FB_CUR_SETIMAGE; + } + + if (attribute) { + u8 *dst; + + dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC); + if (!dst) + return; + kfree(ops->cursor_data); + ops->cursor_data = dst; + ud_update_attr(dst, src, attribute, vc); + src = dst; + } + + if (ops->cursor_state.image.fg_color != fg || + ops->cursor_state.image.bg_color != bg || + ops->cursor_reset) { + ops->cursor_state.image.fg_color = fg; + ops->cursor_state.image.bg_color = bg; + cursor.set |= FB_CUR_SETCMAP; + } + + if (ops->cursor_state.image.height != vc->vc_font.height || + ops->cursor_state.image.width != vc->vc_font.width || + ops->cursor_reset) { + ops->cursor_state.image.height = vc->vc_font.height; + ops->cursor_state.image.width = vc->vc_font.width; + cursor.set |= FB_CUR_SETSIZE; + } + + dy = vyres - ((y * vc->vc_font.height) + vc->vc_font.height); + dx = vxres - ((vc->vc_x * vc->vc_font.width) + vc->vc_font.width); + + if (ops->cursor_state.image.dx != dx || + ops->cursor_state.image.dy != dy || + ops->cursor_reset) { + ops->cursor_state.image.dx = dx; + ops->cursor_state.image.dy = dy; + cursor.set |= FB_CUR_SETPOS; + } + + if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || + ops->cursor_reset) { + ops->cursor_state.hot.x = cursor.hot.y = 0; + cursor.set |= FB_CUR_SETHOT; + } + + if (cursor.set & FB_CUR_SETSIZE || + vc->vc_cursor_type != p->cursor_shape || + ops->cursor_state.mask == NULL || + ops->cursor_reset) { + char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC); + int cur_height, size, i = 0; + u8 msk = 0xff; + + if (!mask) + return; + + kfree(ops->cursor_state.mask); + ops->cursor_state.mask = mask; + + p->cursor_shape = vc->vc_cursor_type; + cursor.set |= FB_CUR_SETSHAPE; + + switch (p->cursor_shape & CUR_HWMASK) { + case CUR_NONE: + cur_height = 0; + break; + case CUR_UNDERLINE: + cur_height = (vc->vc_font.height < 10) ? 1 : 2; + break; + case CUR_LOWER_THIRD: + cur_height = vc->vc_font.height/3; + break; + case CUR_LOWER_HALF: + cur_height = vc->vc_font.height >> 1; + break; + case CUR_TWO_THIRDS: + cur_height = (vc->vc_font.height << 1)/3; + break; + case CUR_BLOCK: + default: + cur_height = vc->vc_font.height; + break; + } + + size = cur_height * w; + + while (size--) + mask[i++] = msk; + + size = (vc->vc_font.height - cur_height) * w; + + while (size--) + mask[i++] = ~msk; + } + + switch (mode) { + case CM_ERASE: + ops->cursor_state.enable = 0; + break; + case CM_DRAW: + case CM_MOVE: + default: + ops->cursor_state.enable = (use_sw) ? 0 : 1; + break; + } + + cursor.image.data = src; + cursor.image.fg_color = ops->cursor_state.image.fg_color; + cursor.image.bg_color = ops->cursor_state.image.bg_color; + cursor.image.dx = ops->cursor_state.image.dx; + cursor.image.dy = ops->cursor_state.image.dy; + cursor.image.height = ops->cursor_state.image.height; + cursor.image.width = ops->cursor_state.image.width; + cursor.hot.x = ops->cursor_state.hot.x; + cursor.hot.y = ops->cursor_state.hot.y; + cursor.mask = ops->cursor_state.mask; + cursor.enable = ops->cursor_state.enable; + cursor.image.depth = 1; + cursor.rop = ROP_XOR; + + if (info->fbops->fb_cursor) + err = info->fbops->fb_cursor(info, &cursor); + + if (err) + soft_cursor(info, &cursor); + + ops->cursor_reset = 0; +} + +int ud_update_start(struct fb_info *info) +{ + struct fbcon_ops *ops = info->fbcon_par; + u32 xoffset, yoffset; + u32 vyres = GETVYRES(ops->p->scrollmode, info); + u32 vxres = GETVXRES(ops->p->scrollmode, info); + int err; + + xoffset = (vxres - info->var.xres) - ops->var.xoffset; + yoffset = (vyres - info->var.yres) - ops->var.yoffset; + ops->var.xoffset = xoffset; + ops->var.yoffset = yoffset; + err = fb_pan_display(info, &ops->var); + ops->var.xoffset = info->var.xoffset; + ops->var.yoffset = info->var.yoffset; + ops->var.vmode = info->var.vmode; + return err; +} + +void fbcon_rotate_ud(struct fbcon_ops *ops) +{ + ops->bmove = ud_bmove; + ops->clear = ud_clear; + ops->putcs = ud_putcs; + ops->clear_margins = ud_clear_margins; + ops->cursor = ud_cursor; + ops->update_start = ud_update_start; +} +EXPORT_SYMBOL(fbcon_rotate_ud); + +MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); +MODULE_DESCRIPTION("Console Rotation (180 degrees) Support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index e793ffd39db..762c7a59314 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -32,7 +32,6 @@ #include <linux/font.h> -extern struct font_desc font_vga_8x16; extern unsigned long sgi_gfxaddr; #define FONT_DATA ((unsigned char *)font_vga_8x16.data) diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c new file mode 100644 index 00000000000..8529bf08db2 --- /dev/null +++ b/drivers/video/console/softcursor.c @@ -0,0 +1,72 @@ +/* + * linux/drivers/video/softcursor.c -- Generic software cursor for frame buffer devices + * + * Created 14 Nov 2002 by James Simmons + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/module.h> +#include <linux/string.h> +#include <linux/tty.h> +#include <linux/fb.h> +#include <linux/slab.h> + +#include <asm/uaccess.h> +#include <asm/io.h> + +int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + unsigned int scan_align = info->pixmap.scan_align - 1; + unsigned int buf_align = info->pixmap.buf_align - 1; + unsigned int i, size, dsize, s_pitch, d_pitch; + struct fb_image *image; + u8 *dst, *src; + + if (info->state != FBINFO_STATE_RUNNING) + return 0; + + s_pitch = (cursor->image.width + 7) >> 3; + dsize = s_pitch * cursor->image.height; + + src = kmalloc(dsize + sizeof(struct fb_image), GFP_ATOMIC); + if (!src) + return -ENOMEM; + + image = (struct fb_image *) (src + dsize); + *image = cursor->image; + d_pitch = (s_pitch + scan_align) & ~scan_align; + + size = d_pitch * image->height + buf_align; + size &= ~buf_align; + dst = fb_get_buffer_offset(info, &info->pixmap, size); + + if (cursor->enable) { + switch (cursor->rop) { + case ROP_XOR: + for (i = 0; i < dsize; i++) + src[i] = image->data[i] ^ cursor->mask[i]; + break; + case ROP_COPY: + default: + for (i = 0; i < dsize; i++) + src[i] = image->data[i] & cursor->mask[i]; + break; + } + } else + memcpy(src, image->data, dsize); + + fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, image->height); + image->data = dst; + info->fbops->fb_imageblit(info, image); + kfree(src); + return 0; +} + +EXPORT_SYMBOL(soft_cursor); + +MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>"); +MODULE_DESCRIPTION("Generic software cursor"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c index d940f605acb..a7bcd17112c 100644 --- a/drivers/video/console/sticore.c +++ b/drivers/video/console/sticore.c @@ -511,12 +511,12 @@ sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name ) struct sti_cooked_font *cooked_font; if (!fbfont_name || !strlen(fbfont_name)) - return NULL; + return NULL; fbfont = find_font(fbfont_name); if (!fbfont) - fbfont = get_default_font(1024,768); + fbfont = get_default_font(1024,768); if (!fbfont) - return NULL; + return NULL; DPRINTK((KERN_DEBUG "selected %dx%d fb-font %s\n", fbfont->width, fbfont->height, fbfont->name)); @@ -527,7 +527,7 @@ sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name ) nf = kmalloc(size, GFP_KERNEL); if (!nf) - return NULL; + return NULL; memset(nf, 0, size); nf->first_char = 0; @@ -546,8 +546,8 @@ sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name ) cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL); if (!cooked_font) { - kfree(nf); - return NULL; + kfree(nf); + return NULL; } cooked_font->raw = nf; @@ -595,7 +595,7 @@ sti_select_font(struct sti_cooked_rom *rom, static void __init sti_dump_rom(struct sti_rom *rom) { - printk(KERN_INFO " id %04x-%04x, conforms to spec rev. %d.%02x\n", + printk(KERN_INFO " id %04x-%04x, conforms to spec rev. %d.%02x\n", rom->graphics_id[0], rom->graphics_id[1], rom->revno[0] >> 4, @@ -651,15 +651,16 @@ sti_search_font(struct sti_cooked_rom *rom, int height, int width) struct sti_cooked_font *font; int i = 0; - for(font = rom->font_start; font; font = font->next_font, i++) { - if((font->raw->width == width) && (font->raw->height == height)) + for (font = rom->font_start; font; font = font->next_font, i++) { + if ((font->raw->width == width) && + (font->raw->height == height)) return i; } return 0; } -#define BMODE_RELOCATE(offset) offset = (offset) / 4; -#define BMODE_LAST_ADDR_OFFS 0x50 +#define BMODE_RELOCATE(offset) offset = (offset) / 4; +#define BMODE_LAST_ADDR_OFFS 0x50 static void * __init sti_bmode_font_raw(struct sti_cooked_font *f) @@ -700,35 +701,35 @@ sti_get_bmode_rom (unsigned long address) { struct sti_rom *raw; u32 size; - struct sti_rom_font *raw_font, *font_start; - + struct sti_rom_font *raw_font, *font_start; + sti_bmode_rom_copy(address + BMODE_LAST_ADDR_OFFS, sizeof(size), &size); - - size = (size+3) / 4; + + size = (size+3) / 4; raw = kmalloc(size, GFP_KERNEL); if (raw) { - sti_bmode_rom_copy(address, size, raw); - memmove (&raw->res004, &raw->type[0], 0x3c); - raw->type[3] = raw->res004; + sti_bmode_rom_copy(address, size, raw); + memmove (&raw->res004, &raw->type[0], 0x3c); + raw->type[3] = raw->res004; - BMODE_RELOCATE (raw->region_list); - BMODE_RELOCATE (raw->font_start); + BMODE_RELOCATE (raw->region_list); + BMODE_RELOCATE (raw->font_start); - BMODE_RELOCATE (raw->init_graph); - BMODE_RELOCATE (raw->state_mgmt); - BMODE_RELOCATE (raw->font_unpmv); - BMODE_RELOCATE (raw->block_move); - BMODE_RELOCATE (raw->inq_conf); + BMODE_RELOCATE (raw->init_graph); + BMODE_RELOCATE (raw->state_mgmt); + BMODE_RELOCATE (raw->font_unpmv); + BMODE_RELOCATE (raw->block_move); + BMODE_RELOCATE (raw->inq_conf); - raw_font = ((void *)raw) + raw->font_start; - font_start = raw_font; + raw_font = ((void *)raw) + raw->font_start; + font_start = raw_font; - while (raw_font->next_font) { - BMODE_RELOCATE (raw_font->next_font); - raw_font = ((void *)font_start) + raw_font->next_font; - } + while (raw_font->next_font) { + BMODE_RELOCATE (raw_font->next_font); + raw_font = ((void *)font_start) + raw_font->next_font; + } } - return raw; + return raw; } struct sti_rom * __init @@ -736,15 +737,15 @@ sti_get_wmode_rom (unsigned long address) { struct sti_rom *raw; unsigned long size; - + /* read the ROM size directly from the struct in ROM */ size = gsc_readl(address + offsetof(struct sti_rom,last_addr)); raw = kmalloc(size, GFP_KERNEL); - if(raw) - sti_rom_copy(address, size, raw); + if (raw) + sti_rom_copy(address, size, raw); - return raw; + return raw; } int __init @@ -757,14 +758,14 @@ sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address) if (!cooked) goto out_err; - if (wordmode) - raw = sti_get_wmode_rom (address); - else - raw = sti_get_bmode_rom (address); + if (wordmode) + raw = sti_get_wmode_rom (address); + else + raw = sti_get_bmode_rom (address); + + if (!raw) + goto out_err; - if (!raw) - goto out_err; - if (!sti_cook_fonts(cooked, raw)) { printk(KERN_ERR "No font found for STI at %08lx\n", address); goto out_err; @@ -787,7 +788,7 @@ sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address) sti->font_width = sti->font->raw->width; sti->font_height = sti->font->raw->height; if (!wordmode) - sti->font->raw = sti_bmode_font_raw(sti->font); + sti->font->raw = sti_bmode_font_raw(sti->font); sti->sti_mem_request = raw->sti_mem_req; sti->graphics_id[0] = raw->graphics_id[0]; @@ -811,16 +812,16 @@ sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd u32 sig; if (num_sti_roms >= MAX_STI_ROMS) { - printk(KERN_WARNING "maximum number of STI ROMS reached !\n"); - return NULL; + printk(KERN_WARNING "maximum number of STI ROMS reached !\n"); + return NULL; } sti = kmalloc(sizeof(*sti), GFP_KERNEL); if (!sti) { - printk(KERN_ERR "Not enough memory !\n"); - return NULL; + printk(KERN_ERR "Not enough memory !\n"); + return NULL; } - + memset(sti, 0, sizeof(*sti)); spin_lock_init(&sti->lock); @@ -932,28 +933,21 @@ static void __init sticore_check_for_default_sti(struct sti_struct *sti, char *p */ static int __init sticore_pa_init(struct parisc_device *dev) { - unsigned long rom = 0; char pa_path[21]; struct sti_struct *sti = NULL; - - if(dev->num_addrs) { - rom = dev->addr[0]; - } - if (!rom) { - rom = dev->hpa; - DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa)); - sti = sti_try_rom_generic(rom, dev->hpa, NULL); - rom = PAGE0->proc_sti; - } - if (!sti) { - DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa)); - sti = sti_try_rom_generic(rom, dev->hpa, NULL); - } + int hpa = dev->hpa.start; + + if (dev->num_addrs && dev->addr[0]) + sti = sti_try_rom_generic(dev->addr[0], hpa, NULL); + if (!sti) + sti = sti_try_rom_generic(hpa, hpa, NULL); + if (!sti) + sti = sti_try_rom_generic(PAGE0->proc_sti, hpa, NULL); if (!sti) return 1; - + print_pa_hwpath(dev, pa_path); - sticore_check_for_default_sti (sti, pa_path); + sticore_check_for_default_sti(sti, pa_path); return 0; } diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c index 7f76e2c6a4a..cb25324a563 100644 --- a/drivers/video/console/tileblit.c +++ b/drivers/video/console/tileblit.c @@ -118,6 +118,18 @@ static void tile_cursor(struct vc_data *vc, struct fb_info *info, info->tileops->fb_tilecursor(info, &cursor); } +static int tile_update_start(struct fb_info *info) +{ + struct fbcon_ops *ops = info->fbcon_par; + int err; + + err = fb_pan_display(info, &ops->var); + ops->var.xoffset = info->var.xoffset; + ops->var.yoffset = info->var.yoffset; + ops->var.vmode = info->var.vmode; + return err; +} + void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, struct display *p, struct fbcon_ops *ops) { @@ -128,6 +140,7 @@ void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, ops->putcs = tile_putcs; ops->clear_margins = tile_clear_margins; ops->cursor = tile_cursor; + ops->update_start = tile_update_start; if (p) { map.width = vc->vc_font.width; diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 6ef6f7760e4..167de397e4b 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -448,7 +448,8 @@ static void vgacon_cursor(struct vc_data *c, int mode) vgacon_scrolldelta(c, 0); switch (mode) { case CM_ERASE: - write_vga(14, (vga_vram_end - vga_vram_base - 1) / 2); + write_vga(14, (c->vc_pos - vga_vram_base) / 2); + vgacon_set_cursor_size(c->vc_x, 31, 30); break; case CM_MOVE: @@ -565,7 +566,11 @@ static int vgacon_switch(struct vc_data *c) scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf, c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size); - vgacon_doresize(c, c->vc_cols, c->vc_rows); + if (!(vga_video_num_columns % 2) && + vga_video_num_columns <= ORIG_VIDEO_COLS && + vga_video_num_lines <= (ORIG_VIDEO_LINES * + vga_default_font_height) / c->vc_font.height) + vgacon_doresize(c, c->vc_cols, c->vc_rows); } return 0; /* Redrawing not needed */ @@ -575,6 +580,7 @@ static void vga_set_palette(struct vc_data *vc, unsigned char *table) { int i, j; + vga_w(state.vgabase, VGA_PEL_MSK, 0xff); for (i = j = 0; i < 16; i++) { vga_w(state.vgabase, VGA_PEL_IW, table[i]); vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2); @@ -717,6 +723,7 @@ static void vga_pal_blank(struct vgastate *state) { int i; + vga_w(state->vgabase, VGA_PEL_MSK, 0xff); for (i = 0; i < 16; i++) { vga_w(state->vgabase, VGA_PEL_IW, i); vga_w(state->vgabase, VGA_PEL_D, 0); @@ -959,6 +966,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight) outb_p(0x12, vga_video_port_reg); /* Vertical display limit */ outb_p(vde, vga_video_port_val); spin_unlock_irq(&vga_lock); + vga_video_font_height = fontheight; for (i = 0; i < MAX_NR_CONSOLES; i++) { struct vc_data *c = vc_cons[i].d; @@ -1023,7 +1031,8 @@ static int vgacon_resize(struct vc_data *c, unsigned int width, if (width % 2 || width > ORIG_VIDEO_COLS || height > (ORIG_VIDEO_LINES * vga_default_font_height)/ c->vc_font.height) - return -EINVAL; + /* let svgatextmode tinker with video timings */ + return 0; if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */ vgacon_doresize(c, width, height); |