diff options
Diffstat (limited to 'drivers/video')
24 files changed, 2360 insertions, 262 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 44b6ca290ce3..25b6ca6ad081 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -593,38 +593,6 @@ config FB_EPSON1355 | |||
593 | framebuffer. Product specs at | 593 | framebuffer. Product specs at |
594 | <http://www.erd.epson.com/vdc/html/products.htm>. | 594 | <http://www.erd.epson.com/vdc/html/products.htm>. |
595 | 595 | ||
596 | config FB_E1356 | ||
597 | tristate "Epson SED1356 framebuffer support" | ||
598 | depends on FB && EXPERIMENTAL && PCI && MIPS | ||
599 | |||
600 | config PB1000_CRT | ||
601 | bool "Use CRT on Pb1000 (J65)" | ||
602 | depends on MIPS_PB1000=y && FB_E1356 | ||
603 | |||
604 | config PB1000_NTSC | ||
605 | bool "Use Compsite NTSC on Pb1000 (J63)" | ||
606 | depends on MIPS_PB1000=y && FB_E1356 | ||
607 | |||
608 | config PB1000_TFT | ||
609 | bool "Use TFT Panel on Pb1000 (J64)" | ||
610 | depends on MIPS_PB1000=y && FB_E1356 | ||
611 | |||
612 | config PB1500_CRT | ||
613 | bool "Use CRT on Pb1500 " if MIPS_PB1500=y | ||
614 | depends on FB_E1356 | ||
615 | |||
616 | config PB1500_CRT | ||
617 | prompt "Use CRT on Pb1100 " | ||
618 | depends on FB_E1356 && MIPS_PB1100=y | ||
619 | |||
620 | config PB1500_TFT | ||
621 | bool "Use TFT Panel on Pb1500 " if MIPS_PB1500=y | ||
622 | depends on FB_E1356 | ||
623 | |||
624 | config PB1500_TFT | ||
625 | prompt "Use TFT Panel on Pb1100 " | ||
626 | depends on FB_E1356 && MIPS_PB1100=y | ||
627 | |||
628 | config FB_S1D13XXX | 596 | config FB_S1D13XXX |
629 | tristate "Epson S1D13XXX framebuffer support" | 597 | tristate "Epson S1D13XXX framebuffer support" |
630 | depends on FB | 598 | depends on FB |
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 467a1d7ebbde..a3c2c45e29e0 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c | |||
@@ -518,7 +518,7 @@ static struct amba_driver clcd_driver = { | |||
518 | .id_table = clcdfb_id_table, | 518 | .id_table = clcdfb_id_table, |
519 | }; | 519 | }; |
520 | 520 | ||
521 | int __init amba_clcdfb_init(void) | 521 | static int __init amba_clcdfb_init(void) |
522 | { | 522 | { |
523 | if (fb_get_options("ambafb", NULL)) | 523 | if (fb_get_options("ambafb", NULL)) |
524 | return -ENODEV; | 524 | return -ENODEV; |
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index acc81cb01d56..9d5015e99372 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c | |||
@@ -5,7 +5,6 @@ | |||
5 | * | 5 | * |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/version.h> | ||
9 | #include <linux/module.h> | 8 | #include <linux/module.h> |
10 | #include <linux/init.h> | 9 | #include <linux/init.h> |
11 | #include <linux/device.h> | 10 | #include <linux/device.h> |
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 470e6f0ee4dd..68c690605aa7 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c | |||
@@ -5,7 +5,6 @@ | |||
5 | * | 5 | * |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/version.h> | ||
9 | #include <linux/module.h> | 8 | #include <linux/module.h> |
10 | #include <linux/init.h> | 9 | #include <linux/init.h> |
11 | #include <linux/device.h> | 10 | #include <linux/device.h> |
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index da664cea7eca..a7770c4f17d0 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c | |||
@@ -80,10 +80,12 @@ static u32 cfb_tab32[] = { | |||
80 | #define LEFT_POS(bpp) (32 - bpp) | 80 | #define LEFT_POS(bpp) (32 - bpp) |
81 | #define SHIFT_HIGH(val, bits) ((val) >> (bits)) | 81 | #define SHIFT_HIGH(val, bits) ((val) >> (bits)) |
82 | #define SHIFT_LOW(val, bits) ((val) << (bits)) | 82 | #define SHIFT_LOW(val, bits) ((val) << (bits)) |
83 | #define BIT_NR(b) (7 - (b)) | ||
83 | #else | 84 | #else |
84 | #define LEFT_POS(bpp) (0) | 85 | #define LEFT_POS(bpp) (0) |
85 | #define SHIFT_HIGH(val, bits) ((val) << (bits)) | 86 | #define SHIFT_HIGH(val, bits) ((val) << (bits)) |
86 | #define SHIFT_LOW(val, bits) ((val) >> (bits)) | 87 | #define SHIFT_LOW(val, bits) ((val) >> (bits)) |
88 | #define BIT_NR(b) (b) | ||
87 | #endif | 89 | #endif |
88 | 90 | ||
89 | static inline void color_imageblit(const struct fb_image *image, | 91 | static inline void color_imageblit(const struct fb_image *image, |
@@ -177,7 +179,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * | |||
177 | 179 | ||
178 | while (j--) { | 180 | while (j--) { |
179 | l--; | 181 | l--; |
180 | color = (*s & (1 << l)) ? fgcolor : bgcolor; | 182 | color = (*s & 1 << (BIT_NR(l))) ? fgcolor : bgcolor; |
181 | color <<= LEFT_POS(bpp); | 183 | color <<= LEFT_POS(bpp); |
182 | val |= SHIFT_HIGH(color, shift); | 184 | val |= SHIFT_HIGH(color, shift); |
183 | 185 | ||
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index fadf7c5d216e..94c5f1392cce 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig | |||
@@ -101,6 +101,16 @@ config FRAMEBUFFER_CONSOLE | |||
101 | help | 101 | help |
102 | Low-level framebuffer-based console driver. | 102 | Low-level framebuffer-based console driver. |
103 | 103 | ||
104 | config FRAMEBUFFER_CONSOLE_ROTATION | ||
105 | bool "Framebuffer Console Rotation" | ||
106 | depends on FRAMEBUFFER_CONSOLE | ||
107 | help | ||
108 | Enable display rotation for the framebuffer console. This is done | ||
109 | in software and may be significantly slower than a normally oriented | ||
110 | display. Note that the rotation is done at the console level only | ||
111 | such that other users of the framebuffer will remain normally | ||
112 | oriented. | ||
113 | |||
104 | config STI_CONSOLE | 114 | config STI_CONSOLE |
105 | tristate "STI text console" | 115 | tristate "STI text console" |
106 | depends on PARISC | 116 | depends on PARISC |
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile index 5222628accce..fed600c9ca55 100644 --- a/drivers/video/console/Makefile +++ b/drivers/video/console/Makefile | |||
@@ -31,6 +31,10 @@ obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o softcursor.o | |||
31 | ifeq ($(CONFIG_FB_TILEBLITTING),y) | 31 | ifeq ($(CONFIG_FB_TILEBLITTING),y) |
32 | obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += tileblit.o | 32 | obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += tileblit.o |
33 | endif | 33 | endif |
34 | ifeq ($(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION),y) | ||
35 | obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon_rotate.o fbcon_cw.o fbcon_ud.o \ | ||
36 | fbcon_ccw.o | ||
37 | endif | ||
34 | 38 | ||
35 | obj-$(CONFIG_FB_STI) += sticore.o font.o | 39 | obj-$(CONFIG_FB_STI) += sticore.o font.o |
36 | 40 | ||
diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c index 67857b3cfc8b..e65fc3ef7630 100644 --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c | |||
@@ -22,35 +22,6 @@ | |||
22 | /* | 22 | /* |
23 | * Accelerated handlers. | 23 | * Accelerated handlers. |
24 | */ | 24 | */ |
25 | #define FBCON_ATTRIBUTE_UNDERLINE 1 | ||
26 | #define FBCON_ATTRIBUTE_REVERSE 2 | ||
27 | #define FBCON_ATTRIBUTE_BOLD 4 | ||
28 | |||
29 | static inline int real_y(struct display *p, int ypos) | ||
30 | { | ||
31 | int rows = p->vrows; | ||
32 | |||
33 | ypos += p->yscroll; | ||
34 | return ypos < rows ? ypos : ypos - rows; | ||
35 | } | ||
36 | |||
37 | |||
38 | static inline int get_attribute(struct fb_info *info, u16 c) | ||
39 | { | ||
40 | int attribute = 0; | ||
41 | |||
42 | if (fb_get_color_depth(&info->var, &info->fix) == 1) { | ||
43 | if (attr_underline(c)) | ||
44 | attribute |= FBCON_ATTRIBUTE_UNDERLINE; | ||
45 | if (attr_reverse(c)) | ||
46 | attribute |= FBCON_ATTRIBUTE_REVERSE; | ||
47 | if (attr_bold(c)) | ||
48 | attribute |= FBCON_ATTRIBUTE_BOLD; | ||
49 | } | ||
50 | |||
51 | return attribute; | ||
52 | } | ||
53 | |||
54 | static inline void update_attr(u8 *dst, u8 *src, int attribute, | 25 | static inline void update_attr(u8 *dst, u8 *src, int attribute, |
55 | struct vc_data *vc) | 26 | struct vc_data *vc) |
56 | { | 27 | { |
@@ -418,6 +389,18 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, | |||
418 | ops->cursor_reset = 0; | 389 | ops->cursor_reset = 0; |
419 | } | 390 | } |
420 | 391 | ||
392 | static int bit_update_start(struct fb_info *info) | ||
393 | { | ||
394 | struct fbcon_ops *ops = info->fbcon_par; | ||
395 | int err; | ||
396 | |||
397 | err = fb_pan_display(info, &ops->var); | ||
398 | ops->var.xoffset = info->var.xoffset; | ||
399 | ops->var.yoffset = info->var.yoffset; | ||
400 | ops->var.vmode = info->var.vmode; | ||
401 | return err; | ||
402 | } | ||
403 | |||
421 | void fbcon_set_bitops(struct fbcon_ops *ops) | 404 | void fbcon_set_bitops(struct fbcon_ops *ops) |
422 | { | 405 | { |
423 | ops->bmove = bit_bmove; | 406 | ops->bmove = bit_bmove; |
@@ -425,6 +408,11 @@ void fbcon_set_bitops(struct fbcon_ops *ops) | |||
425 | ops->putcs = bit_putcs; | 408 | ops->putcs = bit_putcs; |
426 | ops->clear_margins = bit_clear_margins; | 409 | ops->clear_margins = bit_clear_margins; |
427 | ops->cursor = bit_cursor; | 410 | ops->cursor = bit_cursor; |
411 | ops->update_start = bit_update_start; | ||
412 | ops->rotate_font = NULL; | ||
413 | |||
414 | if (ops->rotate) | ||
415 | fbcon_set_rotate(ops); | ||
428 | } | 416 | } |
429 | 417 | ||
430 | EXPORT_SYMBOL(fbcon_set_bitops); | 418 | EXPORT_SYMBOL(fbcon_set_bitops); |
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 3cf1b61ff1f8..e7802ffe549a 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c | |||
@@ -107,6 +107,8 @@ enum { | |||
107 | }; | 107 | }; |
108 | 108 | ||
109 | struct display fb_display[MAX_NR_CONSOLES]; | 109 | struct display fb_display[MAX_NR_CONSOLES]; |
110 | EXPORT_SYMBOL(fb_display); | ||
111 | |||
110 | static signed char con2fb_map[MAX_NR_CONSOLES]; | 112 | static signed char con2fb_map[MAX_NR_CONSOLES]; |
111 | static signed char con2fb_map_boot[MAX_NR_CONSOLES]; | 113 | static signed char con2fb_map_boot[MAX_NR_CONSOLES]; |
112 | static int logo_height; | 114 | static int logo_height; |
@@ -130,6 +132,9 @@ static char fontname[40]; | |||
130 | /* current fb_info */ | 132 | /* current fb_info */ |
131 | static int info_idx = -1; | 133 | static int info_idx = -1; |
132 | 134 | ||
135 | /* console rotation */ | ||
136 | static int rotate; | ||
137 | |||
133 | static const struct consw fb_con; | 138 | static const struct consw fb_con; |
134 | 139 | ||
135 | #define CM_SOFTBACK (8) | 140 | #define CM_SOFTBACK (8) |
@@ -176,7 +181,6 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines); | |||
176 | /* | 181 | /* |
177 | * Internal routines | 182 | * Internal routines |
178 | */ | 183 | */ |
179 | static __inline__ int real_y(struct display *p, int ypos); | ||
180 | static __inline__ void ywrap_up(struct vc_data *vc, int count); | 184 | static __inline__ void ywrap_up(struct vc_data *vc, int count); |
181 | static __inline__ void ywrap_down(struct vc_data *vc, int count); | 185 | static __inline__ void ywrap_down(struct vc_data *vc, int count); |
182 | static __inline__ void ypan_up(struct vc_data *vc, int count); | 186 | static __inline__ void ypan_up(struct vc_data *vc, int count); |
@@ -189,6 +193,8 @@ static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *va | |||
189 | int unit); | 193 | int unit); |
190 | static void fbcon_redraw_move(struct vc_data *vc, struct display *p, | 194 | static void fbcon_redraw_move(struct vc_data *vc, struct display *p, |
191 | int line, int count, int dy); | 195 | int line, int count, int dy); |
196 | static void fbcon_modechanged(struct fb_info *info); | ||
197 | static void fbcon_set_all_vcs(struct fb_info *info); | ||
192 | 198 | ||
193 | #ifdef CONFIG_MAC | 199 | #ifdef CONFIG_MAC |
194 | /* | 200 | /* |
@@ -203,6 +209,88 @@ static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp) | |||
203 | } | 209 | } |
204 | #endif | 210 | #endif |
205 | 211 | ||
212 | #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION | ||
213 | static inline void fbcon_set_rotation(struct fb_info *info, struct display *p) | ||
214 | { | ||
215 | struct fbcon_ops *ops = info->fbcon_par; | ||
216 | |||
217 | if (!(info->flags & FBINFO_MISC_TILEBLITTING) && | ||
218 | p->con_rotate < 4) | ||
219 | ops->rotate = p->con_rotate; | ||
220 | else | ||
221 | ops->rotate = 0; | ||
222 | } | ||
223 | |||
224 | static void fbcon_rotate(struct fb_info *info, u32 rotate) | ||
225 | { | ||
226 | struct fbcon_ops *ops= info->fbcon_par; | ||
227 | struct fb_info *fb_info; | ||
228 | |||
229 | if (!ops || ops->currcon == -1) | ||
230 | return; | ||
231 | |||
232 | fb_info = registered_fb[con2fb_map[ops->currcon]]; | ||
233 | |||
234 | if (info == fb_info) { | ||
235 | struct display *p = &fb_display[ops->currcon]; | ||
236 | |||
237 | if (rotate < 4) | ||
238 | p->con_rotate = rotate; | ||
239 | else | ||
240 | p->con_rotate = 0; | ||
241 | |||
242 | fbcon_modechanged(info); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | static void fbcon_rotate_all(struct fb_info *info, u32 rotate) | ||
247 | { | ||
248 | struct fbcon_ops *ops = info->fbcon_par; | ||
249 | struct vc_data *vc; | ||
250 | struct display *p; | ||
251 | int i; | ||
252 | |||
253 | if (!ops || ops->currcon < 0 || rotate > 3) | ||
254 | return; | ||
255 | |||
256 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | ||
257 | vc = vc_cons[i].d; | ||
258 | if (!vc || vc->vc_mode != KD_TEXT || | ||
259 | registered_fb[con2fb_map[i]] != info) | ||
260 | continue; | ||
261 | |||
262 | p = &fb_display[vc->vc_num]; | ||
263 | p->con_rotate = rotate; | ||
264 | } | ||
265 | |||
266 | fbcon_set_all_vcs(info); | ||
267 | } | ||
268 | #else | ||
269 | static inline void fbcon_set_rotation(struct fb_info *info, struct display *p) | ||
270 | { | ||
271 | struct fbcon_ops *ops = info->fbcon_par; | ||
272 | |||
273 | ops->rotate = FB_ROTATE_UR; | ||
274 | } | ||
275 | |||
276 | static void fbcon_rotate(struct fb_info *info, u32 rotate) | ||
277 | { | ||
278 | return; | ||
279 | } | ||
280 | |||
281 | static void fbcon_rotate_all(struct fb_info *info, u32 rotate) | ||
282 | { | ||
283 | return; | ||
284 | } | ||
285 | #endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */ | ||
286 | |||
287 | static int fbcon_get_rotate(struct fb_info *info) | ||
288 | { | ||
289 | struct fbcon_ops *ops = info->fbcon_par; | ||
290 | |||
291 | return (ops) ? ops->rotate : 0; | ||
292 | } | ||
293 | |||
206 | static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info) | 294 | static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info) |
207 | { | 295 | { |
208 | struct fbcon_ops *ops = info->fbcon_par; | 296 | struct fbcon_ops *ops = info->fbcon_par; |
@@ -422,6 +510,14 @@ static int __init fb_console_setup(char *this_opt) | |||
422 | last_fb_vc = simple_strtoul(options, &options, 10) - 1; | 510 | last_fb_vc = simple_strtoul(options, &options, 10) - 1; |
423 | fbcon_is_default = 0; | 511 | fbcon_is_default = 0; |
424 | } | 512 | } |
513 | |||
514 | if (!strncmp(options, "rotate:", 7)) { | ||
515 | options += 7; | ||
516 | if (*options) | ||
517 | rotate = simple_strtoul(options, &options, 0); | ||
518 | if (rotate > 3) | ||
519 | rotate = 0; | ||
520 | } | ||
425 | } | 521 | } |
426 | return 0; | 522 | return 0; |
427 | } | 523 | } |
@@ -480,6 +576,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, | |||
480 | int cols, int rows, int new_cols, int new_rows) | 576 | int cols, int rows, int new_cols, int new_rows) |
481 | { | 577 | { |
482 | /* Need to make room for the logo */ | 578 | /* Need to make room for the logo */ |
579 | struct fbcon_ops *ops = info->fbcon_par; | ||
483 | int cnt, erase = vc->vc_video_erase_char, step; | 580 | int cnt, erase = vc->vc_video_erase_char, step; |
484 | unsigned short *save = NULL, *r, *q; | 581 | unsigned short *save = NULL, *r, *q; |
485 | 582 | ||
@@ -489,7 +586,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, | |||
489 | */ | 586 | */ |
490 | if (fb_get_color_depth(&info->var, &info->fix) == 1) | 587 | if (fb_get_color_depth(&info->var, &info->fix) == 1) |
491 | erase &= ~0x400; | 588 | erase &= ~0x400; |
492 | logo_height = fb_prepare_logo(info); | 589 | logo_height = fb_prepare_logo(info, ops->rotate); |
493 | logo_lines = (logo_height + vc->vc_font.height - 1) / | 590 | logo_lines = (logo_height + vc->vc_font.height - 1) / |
494 | vc->vc_font.height; | 591 | vc->vc_font.height; |
495 | q = (unsigned short *) (vc->vc_origin + | 592 | q = (unsigned short *) (vc->vc_origin + |
@@ -558,16 +655,24 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info, | |||
558 | 655 | ||
559 | if ((info->flags & FBINFO_MISC_TILEBLITTING)) | 656 | if ((info->flags & FBINFO_MISC_TILEBLITTING)) |
560 | fbcon_set_tileops(vc, info, p, ops); | 657 | fbcon_set_tileops(vc, info, p, ops); |
561 | else | 658 | else { |
659 | struct display *disp; | ||
660 | |||
661 | disp = (p) ? p : &fb_display[vc->vc_num]; | ||
662 | fbcon_set_rotation(info, disp); | ||
562 | fbcon_set_bitops(ops); | 663 | fbcon_set_bitops(ops); |
664 | } | ||
563 | } | 665 | } |
564 | #else | 666 | #else |
565 | static void set_blitting_type(struct vc_data *vc, struct fb_info *info, | 667 | static void set_blitting_type(struct vc_data *vc, struct fb_info *info, |
566 | struct display *p) | 668 | struct display *p) |
567 | { | 669 | { |
568 | struct fbcon_ops *ops = info->fbcon_par; | 670 | struct fbcon_ops *ops = info->fbcon_par; |
671 | struct display *disp; | ||
569 | 672 | ||
570 | info->flags &= ~FBINFO_MISC_TILEBLITTING; | 673 | info->flags &= ~FBINFO_MISC_TILEBLITTING; |
674 | disp = (p) ? p : &fb_display[vc->vc_num]; | ||
675 | fbcon_set_rotation(info, disp); | ||
571 | fbcon_set_bitops(ops); | 676 | fbcon_set_bitops(ops); |
572 | } | 677 | } |
573 | #endif /* CONFIG_MISC_TILEBLITTING */ | 678 | #endif /* CONFIG_MISC_TILEBLITTING */ |
@@ -627,6 +732,7 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, | |||
627 | fbcon_del_cursor_timer(oldinfo); | 732 | fbcon_del_cursor_timer(oldinfo); |
628 | kfree(ops->cursor_state.mask); | 733 | kfree(ops->cursor_state.mask); |
629 | kfree(ops->cursor_data); | 734 | kfree(ops->cursor_data); |
735 | kfree(ops->fontbuffer); | ||
630 | kfree(oldinfo->fbcon_par); | 736 | kfree(oldinfo->fbcon_par); |
631 | oldinfo->fbcon_par = NULL; | 737 | oldinfo->fbcon_par = NULL; |
632 | module_put(oldinfo->fbops->owner); | 738 | module_put(oldinfo->fbops->owner); |
@@ -827,7 +933,9 @@ static const char *fbcon_startup(void) | |||
827 | memset(ops, 0, sizeof(struct fbcon_ops)); | 933 | memset(ops, 0, sizeof(struct fbcon_ops)); |
828 | ops->currcon = -1; | 934 | ops->currcon = -1; |
829 | ops->graphics = 1; | 935 | ops->graphics = 1; |
936 | ops->cur_rotate = -1; | ||
830 | info->fbcon_par = ops; | 937 | info->fbcon_par = ops; |
938 | p->con_rotate = rotate; | ||
831 | set_blitting_type(vc, info, NULL); | 939 | set_blitting_type(vc, info, NULL); |
832 | 940 | ||
833 | if (info->fix.type != FB_TYPE_TEXT) { | 941 | if (info->fix.type != FB_TYPE_TEXT) { |
@@ -866,8 +974,10 @@ static const char *fbcon_startup(void) | |||
866 | vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ | 974 | vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ |
867 | } | 975 | } |
868 | 976 | ||
869 | cols = info->var.xres / vc->vc_font.width; | 977 | cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); |
870 | rows = info->var.yres / vc->vc_font.height; | 978 | rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); |
979 | cols /= vc->vc_font.width; | ||
980 | rows /= vc->vc_font.height; | ||
871 | vc_resize(vc, cols, rows); | 981 | vc_resize(vc, cols, rows); |
872 | 982 | ||
873 | DPRINTK("mode: %s\n", info->fix.id); | 983 | DPRINTK("mode: %s\n", info->fix.id); |
@@ -953,8 +1063,6 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
953 | (info->fix.type == FB_TYPE_TEXT)) | 1063 | (info->fix.type == FB_TYPE_TEXT)) |
954 | logo = 0; | 1064 | logo = 0; |
955 | 1065 | ||
956 | info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ | ||
957 | |||
958 | if (var_to_display(p, &info->var, info)) | 1066 | if (var_to_display(p, &info->var, info)) |
959 | return; | 1067 | return; |
960 | 1068 | ||
@@ -986,13 +1094,18 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
986 | if (!*vc->vc_uni_pagedir_loc) | 1094 | if (!*vc->vc_uni_pagedir_loc) |
987 | con_copy_unimap(vc, svc); | 1095 | con_copy_unimap(vc, svc); |
988 | 1096 | ||
1097 | ops = info->fbcon_par; | ||
1098 | p->con_rotate = rotate; | ||
1099 | set_blitting_type(vc, info, NULL); | ||
1100 | |||
989 | cols = vc->vc_cols; | 1101 | cols = vc->vc_cols; |
990 | rows = vc->vc_rows; | 1102 | rows = vc->vc_rows; |
991 | new_cols = info->var.xres / vc->vc_font.width; | 1103 | new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); |
992 | new_rows = info->var.yres / vc->vc_font.height; | 1104 | new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); |
1105 | new_cols /= vc->vc_font.width; | ||
1106 | new_rows /= vc->vc_font.height; | ||
993 | vc_resize(vc, new_cols, new_rows); | 1107 | vc_resize(vc, new_cols, new_rows); |
994 | 1108 | ||
995 | ops = info->fbcon_par; | ||
996 | /* | 1109 | /* |
997 | * We must always set the mode. The mode of the previous console | 1110 | * We must always set the mode. The mode of the previous console |
998 | * driver could be in the same resolution but we are using different | 1111 | * driver could be in the same resolution but we are using different |
@@ -1030,6 +1143,12 @@ static void fbcon_init(struct vc_data *vc, int init) | |||
1030 | 1143 | ||
1031 | if (vc == svc && softback_buf) | 1144 | if (vc == svc && softback_buf) |
1032 | fbcon_update_softback(vc); | 1145 | fbcon_update_softback(vc); |
1146 | |||
1147 | if (ops->rotate_font && ops->rotate_font(info, vc, p)) { | ||
1148 | ops->rotate = FB_ROTATE_UR; | ||
1149 | set_blitting_type(vc, info, p); | ||
1150 | } | ||
1151 | |||
1033 | } | 1152 | } |
1034 | 1153 | ||
1035 | static void fbcon_deinit(struct vc_data *vc) | 1154 | static void fbcon_deinit(struct vc_data *vc) |
@@ -1066,15 +1185,6 @@ static void fbcon_deinit(struct vc_data *vc) | |||
1066 | * restriction is simplicity & efficiency at the moment. | 1185 | * restriction is simplicity & efficiency at the moment. |
1067 | */ | 1186 | */ |
1068 | 1187 | ||
1069 | static __inline__ int real_y(struct display *p, int ypos) | ||
1070 | { | ||
1071 | int rows = p->vrows; | ||
1072 | |||
1073 | ypos += p->yscroll; | ||
1074 | return ypos < rows ? ypos : ypos - rows; | ||
1075 | } | ||
1076 | |||
1077 | |||
1078 | static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, | 1188 | static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height, |
1079 | int width) | 1189 | int width) |
1080 | { | 1190 | { |
@@ -1162,13 +1272,6 @@ static int scrollback_phys_max = 0; | |||
1162 | static int scrollback_max = 0; | 1272 | static int scrollback_max = 0; |
1163 | static int scrollback_current = 0; | 1273 | static int scrollback_current = 0; |
1164 | 1274 | ||
1165 | static int update_var(int con, struct fb_info *info) | ||
1166 | { | ||
1167 | if (con == ((struct fbcon_ops *)info->fbcon_par)->currcon) | ||
1168 | return fb_pan_display(info, &info->var); | ||
1169 | return 0; | ||
1170 | } | ||
1171 | |||
1172 | /* | 1275 | /* |
1173 | * If no vc is existent yet, just set struct display | 1276 | * If no vc is existent yet, just set struct display |
1174 | */ | 1277 | */ |
@@ -1178,7 +1281,6 @@ static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *va | |||
1178 | struct display *p = &fb_display[unit]; | 1281 | struct display *p = &fb_display[unit]; |
1179 | struct display *t = &fb_display[fg_console]; | 1282 | struct display *t = &fb_display[fg_console]; |
1180 | 1283 | ||
1181 | var->xoffset = var->yoffset = p->yscroll = 0; | ||
1182 | if (var_to_display(p, var, info)) | 1284 | if (var_to_display(p, var, info)) |
1183 | return; | 1285 | return; |
1184 | 1286 | ||
@@ -1194,9 +1296,9 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, | |||
1194 | struct display *p = &fb_display[vc->vc_num], *t; | 1296 | struct display *p = &fb_display[vc->vc_num], *t; |
1195 | struct vc_data **default_mode = vc->vc_display_fg; | 1297 | struct vc_data **default_mode = vc->vc_display_fg; |
1196 | struct vc_data *svc = *default_mode; | 1298 | struct vc_data *svc = *default_mode; |
1299 | struct fbcon_ops *ops = info->fbcon_par; | ||
1197 | int rows, cols, charcnt = 256; | 1300 | int rows, cols, charcnt = 256; |
1198 | 1301 | ||
1199 | var->xoffset = var->yoffset = p->yscroll = 0; | ||
1200 | if (var_to_display(p, var, info)) | 1302 | if (var_to_display(p, var, info)) |
1201 | return; | 1303 | return; |
1202 | t = &fb_display[svc->vc_num]; | 1304 | t = &fb_display[svc->vc_num]; |
@@ -1213,9 +1315,10 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, | |||
1213 | 1315 | ||
1214 | var->activate = FB_ACTIVATE_NOW; | 1316 | var->activate = FB_ACTIVATE_NOW; |
1215 | info->var.activate = var->activate; | 1317 | info->var.activate = var->activate; |
1216 | info->var.yoffset = info->var.xoffset = 0; | 1318 | var->yoffset = info->var.yoffset; |
1319 | var->xoffset = info->var.xoffset; | ||
1217 | fb_set_var(info, var); | 1320 | fb_set_var(info, var); |
1218 | 1321 | ops->var = info->var; | |
1219 | vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); | 1322 | vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); |
1220 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; | 1323 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; |
1221 | if (charcnt == 256) { | 1324 | if (charcnt == 256) { |
@@ -1231,9 +1334,12 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, | |||
1231 | if (!*vc->vc_uni_pagedir_loc) | 1334 | if (!*vc->vc_uni_pagedir_loc) |
1232 | con_copy_unimap(vc, svc); | 1335 | con_copy_unimap(vc, svc); |
1233 | 1336 | ||
1234 | cols = var->xres / vc->vc_font.width; | 1337 | cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); |
1235 | rows = var->yres / vc->vc_font.height; | 1338 | rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); |
1339 | cols /= vc->vc_font.width; | ||
1340 | rows /= vc->vc_font.height; | ||
1236 | vc_resize(vc, cols, rows); | 1341 | vc_resize(vc, cols, rows); |
1342 | |||
1237 | if (CON_IS_VISIBLE(vc)) { | 1343 | if (CON_IS_VISIBLE(vc)) { |
1238 | update_screen(vc); | 1344 | update_screen(vc); |
1239 | if (softback_buf) | 1345 | if (softback_buf) |
@@ -1244,15 +1350,16 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, | |||
1244 | static __inline__ void ywrap_up(struct vc_data *vc, int count) | 1350 | static __inline__ void ywrap_up(struct vc_data *vc, int count) |
1245 | { | 1351 | { |
1246 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 1352 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
1353 | struct fbcon_ops *ops = info->fbcon_par; | ||
1247 | struct display *p = &fb_display[vc->vc_num]; | 1354 | struct display *p = &fb_display[vc->vc_num]; |
1248 | 1355 | ||
1249 | p->yscroll += count; | 1356 | p->yscroll += count; |
1250 | if (p->yscroll >= p->vrows) /* Deal with wrap */ | 1357 | if (p->yscroll >= p->vrows) /* Deal with wrap */ |
1251 | p->yscroll -= p->vrows; | 1358 | p->yscroll -= p->vrows; |
1252 | info->var.xoffset = 0; | 1359 | ops->var.xoffset = 0; |
1253 | info->var.yoffset = p->yscroll * vc->vc_font.height; | 1360 | ops->var.yoffset = p->yscroll * vc->vc_font.height; |
1254 | info->var.vmode |= FB_VMODE_YWRAP; | 1361 | ops->var.vmode |= FB_VMODE_YWRAP; |
1255 | update_var(vc->vc_num, info); | 1362 | ops->update_start(info); |
1256 | scrollback_max += count; | 1363 | scrollback_max += count; |
1257 | if (scrollback_max > scrollback_phys_max) | 1364 | if (scrollback_max > scrollback_phys_max) |
1258 | scrollback_max = scrollback_phys_max; | 1365 | scrollback_max = scrollback_phys_max; |
@@ -1262,15 +1369,16 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count) | |||
1262 | static __inline__ void ywrap_down(struct vc_data *vc, int count) | 1369 | static __inline__ void ywrap_down(struct vc_data *vc, int count) |
1263 | { | 1370 | { |
1264 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 1371 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
1372 | struct fbcon_ops *ops = info->fbcon_par; | ||
1265 | struct display *p = &fb_display[vc->vc_num]; | 1373 | struct display *p = &fb_display[vc->vc_num]; |
1266 | 1374 | ||
1267 | p->yscroll -= count; | 1375 | p->yscroll -= count; |
1268 | if (p->yscroll < 0) /* Deal with wrap */ | 1376 | if (p->yscroll < 0) /* Deal with wrap */ |
1269 | p->yscroll += p->vrows; | 1377 | p->yscroll += p->vrows; |
1270 | info->var.xoffset = 0; | 1378 | ops->var.xoffset = 0; |
1271 | info->var.yoffset = p->yscroll * vc->vc_font.height; | 1379 | ops->var.yoffset = p->yscroll * vc->vc_font.height; |
1272 | info->var.vmode |= FB_VMODE_YWRAP; | 1380 | ops->var.vmode |= FB_VMODE_YWRAP; |
1273 | update_var(vc->vc_num, info); | 1381 | ops->update_start(info); |
1274 | scrollback_max -= count; | 1382 | scrollback_max -= count; |
1275 | if (scrollback_max < 0) | 1383 | if (scrollback_max < 0) |
1276 | scrollback_max = 0; | 1384 | scrollback_max = 0; |
@@ -1289,10 +1397,11 @@ static __inline__ void ypan_up(struct vc_data *vc, int count) | |||
1289 | 0, 0, 0, vc->vc_rows, vc->vc_cols); | 1397 | 0, 0, 0, vc->vc_rows, vc->vc_cols); |
1290 | p->yscroll -= p->vrows - vc->vc_rows; | 1398 | p->yscroll -= p->vrows - vc->vc_rows; |
1291 | } | 1399 | } |
1292 | info->var.xoffset = 0; | 1400 | |
1293 | info->var.yoffset = p->yscroll * vc->vc_font.height; | 1401 | ops->var.xoffset = 0; |
1294 | info->var.vmode &= ~FB_VMODE_YWRAP; | 1402 | ops->var.yoffset = p->yscroll * vc->vc_font.height; |
1295 | update_var(vc->vc_num, info); | 1403 | ops->var.vmode &= ~FB_VMODE_YWRAP; |
1404 | ops->update_start(info); | ||
1296 | fbcon_clear_margins(vc, 1); | 1405 | fbcon_clear_margins(vc, 1); |
1297 | scrollback_max += count; | 1406 | scrollback_max += count; |
1298 | if (scrollback_max > scrollback_phys_max) | 1407 | if (scrollback_max > scrollback_phys_max) |
@@ -1303,6 +1412,7 @@ static __inline__ void ypan_up(struct vc_data *vc, int count) | |||
1303 | static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) | 1412 | static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) |
1304 | { | 1413 | { |
1305 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 1414 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
1415 | struct fbcon_ops *ops = info->fbcon_par; | ||
1306 | struct display *p = &fb_display[vc->vc_num]; | 1416 | struct display *p = &fb_display[vc->vc_num]; |
1307 | int redraw = 0; | 1417 | int redraw = 0; |
1308 | 1418 | ||
@@ -1312,12 +1422,13 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) | |||
1312 | redraw = 1; | 1422 | redraw = 1; |
1313 | } | 1423 | } |
1314 | 1424 | ||
1315 | info->var.xoffset = 0; | ||
1316 | info->var.yoffset = p->yscroll * vc->vc_font.height; | ||
1317 | info->var.vmode &= ~FB_VMODE_YWRAP; | ||
1318 | if (redraw) | 1425 | if (redraw) |
1319 | fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); | 1426 | fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); |
1320 | update_var(vc->vc_num, info); | 1427 | |
1428 | ops->var.xoffset = 0; | ||
1429 | ops->var.yoffset = p->yscroll * vc->vc_font.height; | ||
1430 | ops->var.vmode &= ~FB_VMODE_YWRAP; | ||
1431 | ops->update_start(info); | ||
1321 | fbcon_clear_margins(vc, 1); | 1432 | fbcon_clear_margins(vc, 1); |
1322 | scrollback_max += count; | 1433 | scrollback_max += count; |
1323 | if (scrollback_max > scrollback_phys_max) | 1434 | if (scrollback_max > scrollback_phys_max) |
@@ -1337,10 +1448,11 @@ static __inline__ void ypan_down(struct vc_data *vc, int count) | |||
1337 | 0, vc->vc_rows, vc->vc_cols); | 1448 | 0, vc->vc_rows, vc->vc_cols); |
1338 | p->yscroll += p->vrows - vc->vc_rows; | 1449 | p->yscroll += p->vrows - vc->vc_rows; |
1339 | } | 1450 | } |
1340 | info->var.xoffset = 0; | 1451 | |
1341 | info->var.yoffset = p->yscroll * vc->vc_font.height; | 1452 | ops->var.xoffset = 0; |
1342 | info->var.vmode &= ~FB_VMODE_YWRAP; | 1453 | ops->var.yoffset = p->yscroll * vc->vc_font.height; |
1343 | update_var(vc->vc_num, info); | 1454 | ops->var.vmode &= ~FB_VMODE_YWRAP; |
1455 | ops->update_start(info); | ||
1344 | fbcon_clear_margins(vc, 1); | 1456 | fbcon_clear_margins(vc, 1); |
1345 | scrollback_max -= count; | 1457 | scrollback_max -= count; |
1346 | if (scrollback_max < 0) | 1458 | if (scrollback_max < 0) |
@@ -1351,6 +1463,7 @@ static __inline__ void ypan_down(struct vc_data *vc, int count) | |||
1351 | static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) | 1463 | static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) |
1352 | { | 1464 | { |
1353 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 1465 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
1466 | struct fbcon_ops *ops = info->fbcon_par; | ||
1354 | struct display *p = &fb_display[vc->vc_num]; | 1467 | struct display *p = &fb_display[vc->vc_num]; |
1355 | int redraw = 0; | 1468 | int redraw = 0; |
1356 | 1469 | ||
@@ -1359,12 +1472,14 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) | |||
1359 | p->yscroll += p->vrows - vc->vc_rows; | 1472 | p->yscroll += p->vrows - vc->vc_rows; |
1360 | redraw = 1; | 1473 | redraw = 1; |
1361 | } | 1474 | } |
1362 | info->var.xoffset = 0; | 1475 | |
1363 | info->var.yoffset = p->yscroll * vc->vc_font.height; | ||
1364 | info->var.vmode &= ~FB_VMODE_YWRAP; | ||
1365 | if (redraw) | 1476 | if (redraw) |
1366 | fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); | 1477 | fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); |
1367 | update_var(vc->vc_num, info); | 1478 | |
1479 | ops->var.xoffset = 0; | ||
1480 | ops->var.yoffset = p->yscroll * vc->vc_font.height; | ||
1481 | ops->var.vmode &= ~FB_VMODE_YWRAP; | ||
1482 | ops->update_start(info); | ||
1368 | fbcon_clear_margins(vc, 1); | 1483 | fbcon_clear_margins(vc, 1); |
1369 | scrollback_max -= count; | 1484 | scrollback_max -= count; |
1370 | if (scrollback_max < 0) | 1485 | if (scrollback_max < 0) |
@@ -1838,31 +1953,41 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int s | |||
1838 | height, width); | 1953 | height, width); |
1839 | } | 1954 | } |
1840 | 1955 | ||
1841 | static __inline__ void updatescrollmode(struct display *p, struct fb_info *info, | 1956 | static __inline__ void updatescrollmode(struct display *p, |
1957 | struct fb_info *info, | ||
1842 | struct vc_data *vc) | 1958 | struct vc_data *vc) |
1843 | { | 1959 | { |
1960 | struct fbcon_ops *ops = info->fbcon_par; | ||
1844 | int fh = vc->vc_font.height; | 1961 | int fh = vc->vc_font.height; |
1845 | int cap = info->flags; | 1962 | int cap = info->flags; |
1846 | int good_pan = (cap & FBINFO_HWACCEL_YPAN) | 1963 | u16 t = 0; |
1847 | && divides(info->fix.ypanstep, vc->vc_font.height) | 1964 | int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep, |
1848 | && info->var.yres_virtual > info->var.yres; | 1965 | info->fix.xpanstep); |
1849 | int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) | 1966 | int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t); |
1850 | && divides(info->fix.ywrapstep, vc->vc_font.height) | 1967 | int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); |
1851 | && divides(vc->vc_font.height, info->var.yres_virtual); | 1968 | int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual, |
1969 | info->var.xres_virtual); | ||
1970 | int good_pan = (cap & FBINFO_HWACCEL_YPAN) && | ||
1971 | divides(ypan, vc->vc_font.height) && vyres > yres; | ||
1972 | int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) && | ||
1973 | divides(ywrap, vc->vc_font.height) && | ||
1974 | divides(vc->vc_font.height, vyres); | ||
1852 | int reading_fast = cap & FBINFO_READS_FAST; | 1975 | int reading_fast = cap & FBINFO_READS_FAST; |
1853 | int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED); | 1976 | int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && |
1854 | int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && !(cap & FBINFO_HWACCEL_DISABLED); | 1977 | !(cap & FBINFO_HWACCEL_DISABLED); |
1855 | 1978 | int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && | |
1856 | p->vrows = info->var.yres_virtual/fh; | 1979 | !(cap & FBINFO_HWACCEL_DISABLED); |
1857 | if (info->var.yres > (fh * (vc->vc_rows + 1))) | 1980 | |
1858 | p->vrows -= (info->var.yres - (fh * vc->vc_rows)) / fh; | 1981 | p->vrows = vyres/fh; |
1859 | if ((info->var.yres % fh) && (info->var.yres_virtual % fh < | 1982 | if (yres > (fh * (vc->vc_rows + 1))) |
1860 | info->var.yres % fh)) | 1983 | p->vrows -= (yres - (fh * vc->vc_rows)) / fh; |
1984 | if ((yres % fh) && (vyres % fh < yres % fh)) | ||
1861 | p->vrows--; | 1985 | p->vrows--; |
1862 | 1986 | ||
1863 | if (good_wrap || good_pan) { | 1987 | if (good_wrap || good_pan) { |
1864 | if (reading_fast || fast_copyarea) | 1988 | if (reading_fast || fast_copyarea) |
1865 | p->scrollmode = good_wrap ? SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE; | 1989 | p->scrollmode = good_wrap ? |
1990 | SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE; | ||
1866 | else | 1991 | else |
1867 | p->scrollmode = good_wrap ? SCROLL_REDRAW : | 1992 | p->scrollmode = good_wrap ? SCROLL_REDRAW : |
1868 | SCROLL_PAN_REDRAW; | 1993 | SCROLL_PAN_REDRAW; |
@@ -1878,17 +2003,23 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, | |||
1878 | unsigned int height) | 2003 | unsigned int height) |
1879 | { | 2004 | { |
1880 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 2005 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
2006 | struct fbcon_ops *ops = info->fbcon_par; | ||
1881 | struct display *p = &fb_display[vc->vc_num]; | 2007 | struct display *p = &fb_display[vc->vc_num]; |
1882 | struct fb_var_screeninfo var = info->var; | 2008 | struct fb_var_screeninfo var = info->var; |
1883 | int x_diff, y_diff; | 2009 | int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh; |
1884 | int fw = vc->vc_font.width; | 2010 | |
1885 | int fh = vc->vc_font.height; | 2011 | virt_w = FBCON_SWAP(ops->rotate, width, height); |
1886 | 2012 | virt_h = FBCON_SWAP(ops->rotate, height, width); | |
1887 | var.xres = width * fw; | 2013 | virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width, |
1888 | var.yres = height * fh; | 2014 | vc->vc_font.height); |
2015 | virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height, | ||
2016 | vc->vc_font.width); | ||
2017 | var.xres = virt_w * virt_fw; | ||
2018 | var.yres = virt_h * virt_fh; | ||
1889 | x_diff = info->var.xres - var.xres; | 2019 | x_diff = info->var.xres - var.xres; |
1890 | y_diff = info->var.yres - var.yres; | 2020 | y_diff = info->var.yres - var.yres; |
1891 | if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) { | 2021 | if (x_diff < 0 || x_diff > virt_fw || |
2022 | y_diff < 0 || y_diff > virt_fh) { | ||
1892 | struct fb_videomode *mode; | 2023 | struct fb_videomode *mode; |
1893 | 2024 | ||
1894 | DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); | 2025 | DPRINTK("attempting resize %ix%i\n", var.xres, var.yres); |
@@ -1898,7 +2029,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, | |||
1898 | display_to_var(&var, p); | 2029 | display_to_var(&var, p); |
1899 | fb_videomode_to_var(&var, mode); | 2030 | fb_videomode_to_var(&var, mode); |
1900 | 2031 | ||
1901 | if (width > var.xres/fw || height > var.yres/fh) | 2032 | if (virt_w > var.xres/virt_fw || virt_h > var.yres/virt_fh) |
1902 | return -EINVAL; | 2033 | return -EINVAL; |
1903 | 2034 | ||
1904 | DPRINTK("resize now %ix%i\n", var.xres, var.yres); | 2035 | DPRINTK("resize now %ix%i\n", var.xres, var.yres); |
@@ -1908,6 +2039,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, | |||
1908 | fb_set_var(info, &var); | 2039 | fb_set_var(info, &var); |
1909 | } | 2040 | } |
1910 | var_to_display(p, &info->var, info); | 2041 | var_to_display(p, &info->var, info); |
2042 | ops->var = info->var; | ||
1911 | } | 2043 | } |
1912 | updatescrollmode(p, info, vc); | 2044 | updatescrollmode(p, info, vc); |
1913 | return 0; | 2045 | return 0; |
@@ -1916,11 +2048,13 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, | |||
1916 | static int fbcon_switch(struct vc_data *vc) | 2048 | static int fbcon_switch(struct vc_data *vc) |
1917 | { | 2049 | { |
1918 | struct fb_info *info, *old_info = NULL; | 2050 | struct fb_info *info, *old_info = NULL; |
2051 | struct fbcon_ops *ops; | ||
1919 | struct display *p = &fb_display[vc->vc_num]; | 2052 | struct display *p = &fb_display[vc->vc_num]; |
1920 | struct fb_var_screeninfo var; | 2053 | struct fb_var_screeninfo var; |
1921 | int i, prev_console; | 2054 | int i, prev_console; |
1922 | 2055 | ||
1923 | info = registered_fb[con2fb_map[vc->vc_num]]; | 2056 | info = registered_fb[con2fb_map[vc->vc_num]]; |
2057 | ops = info->fbcon_par; | ||
1924 | 2058 | ||
1925 | if (softback_top) { | 2059 | if (softback_top) { |
1926 | if (softback_lines) | 2060 | if (softback_lines) |
@@ -1939,7 +2073,7 @@ static int fbcon_switch(struct vc_data *vc) | |||
1939 | logo_shown = FBCON_LOGO_CANSHOW; | 2073 | logo_shown = FBCON_LOGO_CANSHOW; |
1940 | } | 2074 | } |
1941 | 2075 | ||
1942 | prev_console = ((struct fbcon_ops *)info->fbcon_par)->currcon; | 2076 | prev_console = ops->currcon; |
1943 | if (prev_console != -1) | 2077 | if (prev_console != -1) |
1944 | old_info = registered_fb[con2fb_map[prev_console]]; | 2078 | old_info = registered_fb[con2fb_map[prev_console]]; |
1945 | /* | 2079 | /* |
@@ -1952,9 +2086,9 @@ static int fbcon_switch(struct vc_data *vc) | |||
1952 | */ | 2086 | */ |
1953 | for (i = 0; i < FB_MAX; i++) { | 2087 | for (i = 0; i < FB_MAX; i++) { |
1954 | if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) { | 2088 | if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) { |
1955 | struct fbcon_ops *ops = registered_fb[i]->fbcon_par; | 2089 | struct fbcon_ops *o = registered_fb[i]->fbcon_par; |
1956 | 2090 | ||
1957 | ops->currcon = vc->vc_num; | 2091 | o->currcon = vc->vc_num; |
1958 | } | 2092 | } |
1959 | } | 2093 | } |
1960 | memset(&var, 0, sizeof(struct fb_var_screeninfo)); | 2094 | memset(&var, 0, sizeof(struct fb_var_screeninfo)); |
@@ -1966,8 +2100,11 @@ static int fbcon_switch(struct vc_data *vc) | |||
1966 | * in fb_set_var() | 2100 | * in fb_set_var() |
1967 | */ | 2101 | */ |
1968 | info->var.activate = var.activate; | 2102 | info->var.activate = var.activate; |
1969 | info->var.yoffset = info->var.xoffset = p->yscroll = 0; | 2103 | var.yoffset = info->var.yoffset; |
2104 | var.xoffset = info->var.xoffset; | ||
2105 | var.vmode = info->var.vmode; | ||
1970 | fb_set_var(info, &var); | 2106 | fb_set_var(info, &var); |
2107 | ops->var = info->var; | ||
1971 | 2108 | ||
1972 | if (old_info != NULL && old_info != info) { | 2109 | if (old_info != NULL && old_info != info) { |
1973 | if (info->fbops->fb_set_par) | 2110 | if (info->fbops->fb_set_par) |
@@ -1977,7 +2114,12 @@ static int fbcon_switch(struct vc_data *vc) | |||
1977 | } | 2114 | } |
1978 | 2115 | ||
1979 | set_blitting_type(vc, info, p); | 2116 | set_blitting_type(vc, info, p); |
1980 | ((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1; | 2117 | ops->cursor_reset = 1; |
2118 | |||
2119 | if (ops->rotate_font && ops->rotate_font(info, vc, p)) { | ||
2120 | ops->rotate = FB_ROTATE_UR; | ||
2121 | set_blitting_type(vc, info, p); | ||
2122 | } | ||
1981 | 2123 | ||
1982 | vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); | 2124 | vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1); |
1983 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; | 2125 | vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; |
@@ -1997,10 +2139,11 @@ static int fbcon_switch(struct vc_data *vc) | |||
1997 | scrollback_phys_max = 0; | 2139 | scrollback_phys_max = 0; |
1998 | break; | 2140 | break; |
1999 | } | 2141 | } |
2142 | |||
2000 | scrollback_max = 0; | 2143 | scrollback_max = 0; |
2001 | scrollback_current = 0; | 2144 | scrollback_current = 0; |
2002 | 2145 | ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; | |
2003 | update_var(vc->vc_num, info); | 2146 | ops->update_start(info); |
2004 | fbcon_set_palette(vc, color_table); | 2147 | fbcon_set_palette(vc, color_table); |
2005 | fbcon_clear_margins(vc, 0); | 2148 | fbcon_clear_margins(vc, 0); |
2006 | 2149 | ||
@@ -2008,7 +2151,7 @@ static int fbcon_switch(struct vc_data *vc) | |||
2008 | 2151 | ||
2009 | logo_shown = fg_console; | 2152 | logo_shown = fg_console; |
2010 | /* This is protected above by initmem_freed */ | 2153 | /* This is protected above by initmem_freed */ |
2011 | fb_show_logo(info); | 2154 | fb_show_logo(info, ops->rotate); |
2012 | update_region(vc, | 2155 | update_region(vc, |
2013 | vc->vc_origin + vc->vc_size_row * vc->vc_top, | 2156 | vc->vc_origin + vc->vc_size_row * vc->vc_top, |
2014 | vc->vc_size_row * (vc->vc_bottom - | 2157 | vc->vc_size_row * (vc->vc_bottom - |
@@ -2047,6 +2190,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) | |||
2047 | var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; | 2190 | var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE; |
2048 | fb_set_var(info, &var); | 2191 | fb_set_var(info, &var); |
2049 | ops->graphics = 0; | 2192 | ops->graphics = 0; |
2193 | ops->var = info->var; | ||
2050 | } | 2194 | } |
2051 | } | 2195 | } |
2052 | 2196 | ||
@@ -2135,6 +2279,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, | |||
2135 | const u8 * data, int userfont) | 2279 | const u8 * data, int userfont) |
2136 | { | 2280 | { |
2137 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; | 2281 | struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; |
2282 | struct fbcon_ops *ops = info->fbcon_par; | ||
2138 | struct display *p = &fb_display[vc->vc_num]; | 2283 | struct display *p = &fb_display[vc->vc_num]; |
2139 | int resize; | 2284 | int resize; |
2140 | int cnt; | 2285 | int cnt; |
@@ -2214,9 +2359,13 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, | |||
2214 | } | 2359 | } |
2215 | 2360 | ||
2216 | if (resize) { | 2361 | if (resize) { |
2217 | /* reset wrap/pan */ | 2362 | int cols, rows; |
2218 | info->var.xoffset = info->var.yoffset = p->yscroll = 0; | 2363 | |
2219 | vc_resize(vc, info->var.xres / w, info->var.yres / h); | 2364 | cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); |
2365 | rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); | ||
2366 | cols /= w; | ||
2367 | rows /= h; | ||
2368 | vc_resize(vc, cols, rows); | ||
2220 | if (CON_IS_VISIBLE(vc) && softback_buf) | 2369 | if (CON_IS_VISIBLE(vc) && softback_buf) |
2221 | fbcon_update_softback(vc); | 2370 | fbcon_update_softback(vc); |
2222 | } else if (CON_IS_VISIBLE(vc) | 2371 | } else if (CON_IS_VISIBLE(vc) |
@@ -2444,6 +2593,7 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt) | |||
2444 | static int fbcon_scrolldelta(struct vc_data *vc, int lines) | 2593 | static int fbcon_scrolldelta(struct vc_data *vc, int lines) |
2445 | { | 2594 | { |
2446 | struct fb_info *info = registered_fb[con2fb_map[fg_console]]; | 2595 | struct fb_info *info = registered_fb[con2fb_map[fg_console]]; |
2596 | struct fbcon_ops *ops = info->fbcon_par; | ||
2447 | struct display *p = &fb_display[fg_console]; | 2597 | struct display *p = &fb_display[fg_console]; |
2448 | int offset, limit, scrollback_old; | 2598 | int offset, limit, scrollback_old; |
2449 | 2599 | ||
@@ -2520,9 +2670,11 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) | |||
2520 | offset += limit; | 2670 | offset += limit; |
2521 | else if (offset >= limit) | 2671 | else if (offset >= limit) |
2522 | offset -= limit; | 2672 | offset -= limit; |
2523 | info->var.xoffset = 0; | 2673 | |
2524 | info->var.yoffset = offset * vc->vc_font.height; | 2674 | ops->var.xoffset = 0; |
2525 | update_var(vc->vc_num, info); | 2675 | ops->var.yoffset = offset * vc->vc_font.height; |
2676 | ops->update_start(info); | ||
2677 | |||
2526 | if (!scrollback_current) | 2678 | if (!scrollback_current) |
2527 | fbcon_cursor(vc, CM_DRAW); | 2679 | fbcon_cursor(vc, CM_DRAW); |
2528 | return 0; | 2680 | return 0; |
@@ -2570,22 +2722,25 @@ static void fbcon_modechanged(struct fb_info *info) | |||
2570 | if (!ops || ops->currcon < 0) | 2722 | if (!ops || ops->currcon < 0) |
2571 | return; | 2723 | return; |
2572 | vc = vc_cons[ops->currcon].d; | 2724 | vc = vc_cons[ops->currcon].d; |
2573 | if (vc->vc_mode != KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info) | 2725 | if (vc->vc_mode != KD_TEXT || |
2726 | registered_fb[con2fb_map[ops->currcon]] != info) | ||
2574 | return; | 2727 | return; |
2575 | 2728 | ||
2576 | p = &fb_display[vc->vc_num]; | 2729 | p = &fb_display[vc->vc_num]; |
2577 | 2730 | set_blitting_type(vc, info, p); | |
2578 | info->var.xoffset = info->var.yoffset = p->yscroll = 0; | ||
2579 | 2731 | ||
2580 | if (CON_IS_VISIBLE(vc)) { | 2732 | if (CON_IS_VISIBLE(vc)) { |
2581 | var_to_display(p, &info->var, info); | 2733 | var_to_display(p, &info->var, info); |
2582 | cols = info->var.xres / vc->vc_font.width; | 2734 | cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); |
2583 | rows = info->var.yres / vc->vc_font.height; | 2735 | rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); |
2736 | cols /= vc->vc_font.width; | ||
2737 | rows /= vc->vc_font.height; | ||
2584 | vc_resize(vc, cols, rows); | 2738 | vc_resize(vc, cols, rows); |
2585 | updatescrollmode(p, info, vc); | 2739 | updatescrollmode(p, info, vc); |
2586 | scrollback_max = 0; | 2740 | scrollback_max = 0; |
2587 | scrollback_current = 0; | 2741 | scrollback_current = 0; |
2588 | update_var(vc->vc_num, info); | 2742 | ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; |
2743 | ops->update_start(info); | ||
2589 | fbcon_set_palette(vc, color_table); | 2744 | fbcon_set_palette(vc, color_table); |
2590 | update_screen(vc); | 2745 | update_screen(vc); |
2591 | if (softback_buf) | 2746 | if (softback_buf) |
@@ -2610,18 +2765,20 @@ static void fbcon_set_all_vcs(struct fb_info *info) | |||
2610 | continue; | 2765 | continue; |
2611 | 2766 | ||
2612 | p = &fb_display[vc->vc_num]; | 2767 | p = &fb_display[vc->vc_num]; |
2613 | 2768 | set_blitting_type(vc, info, p); | |
2614 | info->var.xoffset = info->var.yoffset = p->yscroll = 0; | ||
2615 | var_to_display(p, &info->var, info); | 2769 | var_to_display(p, &info->var, info); |
2616 | cols = info->var.xres / vc->vc_font.width; | 2770 | cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); |
2617 | rows = info->var.yres / vc->vc_font.height; | 2771 | rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); |
2772 | cols /= vc->vc_font.width; | ||
2773 | rows /= vc->vc_font.height; | ||
2618 | vc_resize(vc, cols, rows); | 2774 | vc_resize(vc, cols, rows); |
2619 | 2775 | ||
2620 | if (CON_IS_VISIBLE(vc)) { | 2776 | if (CON_IS_VISIBLE(vc)) { |
2621 | updatescrollmode(p, info, vc); | 2777 | updatescrollmode(p, info, vc); |
2622 | scrollback_max = 0; | 2778 | scrollback_max = 0; |
2623 | scrollback_current = 0; | 2779 | scrollback_current = 0; |
2624 | update_var(vc->vc_num, info); | 2780 | ops->var.xoffset = ops->var.yoffset = p->yscroll = 0; |
2781 | ops->update_start(info); | ||
2625 | fbcon_set_palette(vc, color_table); | 2782 | fbcon_set_palette(vc, color_table); |
2626 | update_screen(vc); | 2783 | update_screen(vc); |
2627 | if (softback_buf) | 2784 | if (softback_buf) |
@@ -2771,6 +2928,14 @@ static int fbcon_event_notify(struct notifier_block *self, | |||
2771 | case FB_EVENT_NEW_MODELIST: | 2928 | case FB_EVENT_NEW_MODELIST: |
2772 | fbcon_new_modelist(info); | 2929 | fbcon_new_modelist(info); |
2773 | break; | 2930 | break; |
2931 | case FB_EVENT_SET_CON_ROTATE: | ||
2932 | fbcon_rotate(info, *(int *)event->data); | ||
2933 | break; | ||
2934 | case FB_EVENT_GET_CON_ROTATE: | ||
2935 | ret = fbcon_get_rotate(info); | ||
2936 | break; | ||
2937 | case FB_EVENT_SET_CON_ROTATE_ALL: | ||
2938 | fbcon_rotate_all(info, *(int *)event->data); | ||
2774 | } | 2939 | } |
2775 | 2940 | ||
2776 | return ret; | 2941 | return ret; |
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index b68e0e2c2d16..accfd7bd8e93 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h | |||
@@ -27,15 +27,15 @@ | |||
27 | */ | 27 | */ |
28 | 28 | ||
29 | struct display { | 29 | struct display { |
30 | /* Filled in by the frame buffer device */ | ||
31 | u_short inverse; /* != 0 text black on white as default */ | ||
32 | /* Filled in by the low-level console driver */ | 30 | /* Filled in by the low-level console driver */ |
33 | const u_char *fontdata; | 31 | const u_char *fontdata; |
34 | int userfont; /* != 0 if fontdata kmalloc()ed */ | 32 | int userfont; /* != 0 if fontdata kmalloc()ed */ |
35 | u_short scrollmode; /* Scroll Method */ | 33 | u_short scrollmode; /* Scroll Method */ |
34 | u_short inverse; /* != 0 text black on white as default */ | ||
36 | short yscroll; /* Hardware scrolling */ | 35 | short yscroll; /* Hardware scrolling */ |
37 | int vrows; /* number of virtual rows */ | 36 | int vrows; /* number of virtual rows */ |
38 | int cursor_shape; | 37 | int cursor_shape; |
38 | int con_rotate; | ||
39 | u32 xres_virtual; | 39 | u32 xres_virtual; |
40 | u32 yres_virtual; | 40 | u32 yres_virtual; |
41 | u32 height; | 41 | u32 height; |
@@ -52,6 +52,8 @@ struct display { | |||
52 | struct fb_videomode *mode; | 52 | struct fb_videomode *mode; |
53 | }; | 53 | }; |
54 | 54 | ||
55 | extern struct display fb_display[]; | ||
56 | |||
55 | struct fbcon_ops { | 57 | struct fbcon_ops { |
56 | void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, | 58 | void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, |
57 | int sx, int dy, int dx, int height, int width); | 59 | int sx, int dy, int dx, int height, int width); |
@@ -63,8 +65,12 @@ struct fbcon_ops { | |||
63 | void (*clear_margins)(struct vc_data *vc, struct fb_info *info, | 65 | void (*clear_margins)(struct vc_data *vc, struct fb_info *info, |
64 | int bottom_only); | 66 | int bottom_only); |
65 | void (*cursor)(struct vc_data *vc, struct fb_info *info, | 67 | void (*cursor)(struct vc_data *vc, struct fb_info *info, |
66 | struct display *p, int mode, int softback_lines, int fg, int bg); | 68 | struct display *p, int mode, int softback_lines, |
67 | 69 | int fg, int bg); | |
70 | int (*update_start)(struct fb_info *info); | ||
71 | int (*rotate_font)(struct fb_info *info, struct vc_data *vc, | ||
72 | struct display *p); | ||
73 | struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */ | ||
68 | struct timer_list cursor_timer; /* Cursor timer */ | 74 | struct timer_list cursor_timer; /* Cursor timer */ |
69 | struct fb_cursor cursor_state; | 75 | struct fb_cursor cursor_state; |
70 | int currcon; /* Current VC. */ | 76 | int currcon; /* Current VC. */ |
@@ -73,7 +79,12 @@ struct fbcon_ops { | |||
73 | int blank_state; | 79 | int blank_state; |
74 | int graphics; | 80 | int graphics; |
75 | int flags; | 81 | int flags; |
82 | int rotate; | ||
83 | int cur_rotate; | ||
76 | char *cursor_data; | 84 | char *cursor_data; |
85 | u8 *fontbuffer; | ||
86 | u8 *fontdata; | ||
87 | u32 fd_size; | ||
77 | }; | 88 | }; |
78 | /* | 89 | /* |
79 | * Attribute Decoding | 90 | * Attribute Decoding |
@@ -168,4 +179,47 @@ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, | |||
168 | #endif | 179 | #endif |
169 | extern void fbcon_set_bitops(struct fbcon_ops *ops); | 180 | extern void fbcon_set_bitops(struct fbcon_ops *ops); |
170 | extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); | 181 | extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); |
182 | |||
183 | #define FBCON_ATTRIBUTE_UNDERLINE 1 | ||
184 | #define FBCON_ATTRIBUTE_REVERSE 2 | ||
185 | #define FBCON_ATTRIBUTE_BOLD 4 | ||
186 | |||
187 | static inline int real_y(struct display *p, int ypos) | ||
188 | { | ||
189 | int rows = p->vrows; | ||
190 | |||
191 | ypos += p->yscroll; | ||
192 | return ypos < rows ? ypos : ypos - rows; | ||
193 | } | ||
194 | |||
195 | |||
196 | static inline int get_attribute(struct fb_info *info, u16 c) | ||
197 | { | ||
198 | int attribute = 0; | ||
199 | |||
200 | if (fb_get_color_depth(&info->var, &info->fix) == 1) { | ||
201 | if (attr_underline(c)) | ||
202 | attribute |= FBCON_ATTRIBUTE_UNDERLINE; | ||
203 | if (attr_reverse(c)) | ||
204 | attribute |= FBCON_ATTRIBUTE_REVERSE; | ||
205 | if (attr_bold(c)) | ||
206 | attribute |= FBCON_ATTRIBUTE_BOLD; | ||
207 | } | ||
208 | |||
209 | return attribute; | ||
210 | } | ||
211 | |||
212 | #define FBCON_SWAP(i,r,v) ({ \ | ||
213 | typeof(r) _r = (r); \ | ||
214 | typeof(v) _v = (v); \ | ||
215 | (void) (&_r == &_v); \ | ||
216 | (i == FB_ROTATE_UR || i == FB_ROTATE_UD) ? _r : _v; }) | ||
217 | |||
218 | #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION | ||
219 | extern void fbcon_set_rotate(struct fbcon_ops *ops); | ||
220 | #else | ||
221 | #define fbcon_set_rotate(x) do {} while(0) | ||
222 | #endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */ | ||
223 | |||
171 | #endif /* _VIDEO_FBCON_H */ | 224 | #endif /* _VIDEO_FBCON_H */ |
225 | |||
diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c new file mode 100644 index 000000000000..680aabab73c5 --- /dev/null +++ b/drivers/video/console/fbcon_ccw.c | |||
@@ -0,0 +1,428 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/console/fbcon_ccw.c -- Software Rotation - 270 degrees | ||
3 | * | ||
4 | * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net> | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive for | ||
8 | * more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/string.h> | ||
14 | #include <linux/fb.h> | ||
15 | #include <linux/vt_kern.h> | ||
16 | #include <linux/console.h> | ||
17 | #include <asm/types.h> | ||
18 | #include "fbcon.h" | ||
19 | #include "fbcon_rotate.h" | ||
20 | |||
21 | /* | ||
22 | * Rotation 270 degrees | ||
23 | */ | ||
24 | |||
25 | static inline void ccw_update_attr(u8 *dst, u8 *src, int attribute, | ||
26 | struct vc_data *vc) | ||
27 | { | ||
28 | int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2; | ||
29 | int width = (vc->vc_font.height + 7) >> 3; | ||
30 | int mod = vc->vc_font.height % 8; | ||
31 | u8 c, msk = ~(0xff << offset), msk1 = 0; | ||
32 | |||
33 | if (mod) | ||
34 | msk <<= (8 - mod); | ||
35 | |||
36 | if (offset > mod) | ||
37 | set_bit(FBCON_BIT(7), (void *)&msk1); | ||
38 | |||
39 | for (i = 0; i < vc->vc_font.width; i++) { | ||
40 | for (j = 0; j < width; j++) { | ||
41 | c = *src; | ||
42 | |||
43 | if (attribute & FBCON_ATTRIBUTE_UNDERLINE) { | ||
44 | if (j == width - 1) | ||
45 | c |= msk; | ||
46 | |||
47 | if (msk1 && j == width - 2) | ||
48 | c |= msk1; | ||
49 | } | ||
50 | |||
51 | if (attribute & FBCON_ATTRIBUTE_BOLD && i) | ||
52 | *(dst - width) |= c; | ||
53 | |||
54 | if (attribute & FBCON_ATTRIBUTE_REVERSE) | ||
55 | c = ~c; | ||
56 | src++; | ||
57 | *dst++ = c; | ||
58 | } | ||
59 | } | ||
60 | } | ||
61 | |||
62 | |||
63 | static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy, | ||
64 | int sx, int dy, int dx, int height, int width) | ||
65 | { | ||
66 | struct display *p = &fb_display[vc->vc_num]; | ||
67 | struct fb_copyarea area; | ||
68 | u32 vyres = GETVYRES(p->scrollmode, info); | ||
69 | |||
70 | area.sx = sy * vc->vc_font.height; | ||
71 | area.sy = vyres - ((sx + width) * vc->vc_font.width); | ||
72 | area.dx = dy * vc->vc_font.height; | ||
73 | area.dy = vyres - ((dx + width) * vc->vc_font.width); | ||
74 | area.width = height * vc->vc_font.height; | ||
75 | area.height = width * vc->vc_font.width; | ||
76 | |||
77 | info->fbops->fb_copyarea(info, &area); | ||
78 | } | ||
79 | |||
80 | static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy, | ||
81 | int sx, int height, int width) | ||
82 | { | ||
83 | struct display *p = &fb_display[vc->vc_num]; | ||
84 | struct fb_fillrect region; | ||
85 | int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; | ||
86 | u32 vyres = GETVYRES(p->scrollmode, info); | ||
87 | |||
88 | region.color = attr_bgcol_ec(bgshift,vc); | ||
89 | region.dx = sy * vc->vc_font.height; | ||
90 | region.dy = vyres - ((sx + width) * vc->vc_font.width); | ||
91 | region.height = width * vc->vc_font.width; | ||
92 | region.width = height * vc->vc_font.height; | ||
93 | region.rop = ROP_COPY; | ||
94 | |||
95 | info->fbops->fb_fillrect(info, ®ion); | ||
96 | } | ||
97 | |||
98 | static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info, | ||
99 | const u16 *s, u32 attr, u32 cnt, | ||
100 | u32 d_pitch, u32 s_pitch, u32 cellsize, | ||
101 | struct fb_image *image, u8 *buf, u8 *dst) | ||
102 | { | ||
103 | struct fbcon_ops *ops = info->fbcon_par; | ||
104 | u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; | ||
105 | u32 idx = (vc->vc_font.height + 7) >> 3; | ||
106 | u8 *src; | ||
107 | |||
108 | while (cnt--) { | ||
109 | src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize; | ||
110 | |||
111 | if (attr) { | ||
112 | ccw_update_attr(buf, src, attr, vc); | ||
113 | src = buf; | ||
114 | } | ||
115 | |||
116 | if (likely(idx == 1)) | ||
117 | __fb_pad_aligned_buffer(dst, d_pitch, src, idx, | ||
118 | vc->vc_font.width); | ||
119 | else | ||
120 | fb_pad_aligned_buffer(dst, d_pitch, src, idx, | ||
121 | vc->vc_font.width); | ||
122 | |||
123 | dst += d_pitch * vc->vc_font.width; | ||
124 | } | ||
125 | |||
126 | info->fbops->fb_imageblit(info, image); | ||
127 | } | ||
128 | |||
129 | static void ccw_putcs(struct vc_data *vc, struct fb_info *info, | ||
130 | const unsigned short *s, int count, int yy, int xx, | ||
131 | int fg, int bg) | ||
132 | { | ||
133 | struct fb_image image; | ||
134 | struct display *p = &fb_display[vc->vc_num]; | ||
135 | struct fbcon_ops *ops = info->fbcon_par; | ||
136 | u32 width = (vc->vc_font.height + 7)/8; | ||
137 | u32 cellsize = width * vc->vc_font.width; | ||
138 | u32 maxcnt = info->pixmap.size/cellsize; | ||
139 | u32 scan_align = info->pixmap.scan_align - 1; | ||
140 | u32 buf_align = info->pixmap.buf_align - 1; | ||
141 | u32 cnt, pitch, size; | ||
142 | u32 attribute = get_attribute(info, scr_readw(s)); | ||
143 | u8 *dst, *buf = NULL; | ||
144 | u32 vyres = GETVYRES(p->scrollmode, info); | ||
145 | |||
146 | if (!ops->fontbuffer) | ||
147 | return; | ||
148 | |||
149 | image.fg_color = fg; | ||
150 | image.bg_color = bg; | ||
151 | image.dx = yy * vc->vc_font.height; | ||
152 | image.dy = vyres - ((xx + count) * vc->vc_font.width); | ||
153 | image.width = vc->vc_font.height; | ||
154 | image.depth = 1; | ||
155 | |||
156 | if (attribute) { | ||
157 | buf = kmalloc(cellsize, GFP_KERNEL); | ||
158 | if (!buf) | ||
159 | return; | ||
160 | } | ||
161 | |||
162 | s += count - 1; | ||
163 | |||
164 | while (count) { | ||
165 | if (count > maxcnt) | ||
166 | cnt = maxcnt; | ||
167 | else | ||
168 | cnt = count; | ||
169 | |||
170 | image.height = vc->vc_font.width * cnt; | ||
171 | pitch = ((image.width + 7) >> 3) + scan_align; | ||
172 | pitch &= ~scan_align; | ||
173 | size = pitch * image.height + buf_align; | ||
174 | size &= ~buf_align; | ||
175 | dst = fb_get_buffer_offset(info, &info->pixmap, size); | ||
176 | image.data = dst; | ||
177 | ccw_putcs_aligned(vc, info, s, attribute, cnt, pitch, | ||
178 | width, cellsize, &image, buf, dst); | ||
179 | image.dy += image.height; | ||
180 | count -= cnt; | ||
181 | s -= cnt; | ||
182 | } | ||
183 | |||
184 | /* buf is always NULL except when in monochrome mode, so in this case | ||
185 | it's a gain to check buf against NULL even though kfree() handles | ||
186 | NULL pointers just fine */ | ||
187 | if (unlikely(buf)) | ||
188 | kfree(buf); | ||
189 | |||
190 | } | ||
191 | |||
192 | static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info, | ||
193 | int bottom_only) | ||
194 | { | ||
195 | unsigned int cw = vc->vc_font.width; | ||
196 | unsigned int ch = vc->vc_font.height; | ||
197 | unsigned int rw = info->var.yres - (vc->vc_cols*cw); | ||
198 | unsigned int bh = info->var.xres - (vc->vc_rows*ch); | ||
199 | unsigned int bs = vc->vc_rows*ch; | ||
200 | struct fb_fillrect region; | ||
201 | int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; | ||
202 | |||
203 | region.color = attr_bgcol_ec(bgshift,vc); | ||
204 | region.rop = ROP_COPY; | ||
205 | |||
206 | if (rw && !bottom_only) { | ||
207 | region.dx = 0; | ||
208 | region.dy = info->var.yoffset; | ||
209 | region.height = rw; | ||
210 | region.width = info->var.xres_virtual; | ||
211 | info->fbops->fb_fillrect(info, ®ion); | ||
212 | } | ||
213 | |||
214 | if (bh) { | ||
215 | region.dx = info->var.xoffset + bs; | ||
216 | region.dy = 0; | ||
217 | region.height = info->var.yres_virtual; | ||
218 | region.width = bh; | ||
219 | info->fbops->fb_fillrect(info, ®ion); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | static void ccw_cursor(struct vc_data *vc, struct fb_info *info, | ||
224 | struct display *p, int mode, int softback_lines, | ||
225 | int fg, int bg) | ||
226 | { | ||
227 | struct fb_cursor cursor; | ||
228 | struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; | ||
229 | unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; | ||
230 | int w = (vc->vc_font.height + 7) >> 3, c; | ||
231 | int y = real_y(p, vc->vc_y); | ||
232 | int attribute, use_sw = (vc->vc_cursor_type & 0x10); | ||
233 | int err = 1, dx, dy; | ||
234 | char *src; | ||
235 | u32 vyres = GETVYRES(p->scrollmode, info); | ||
236 | |||
237 | if (!ops->fontbuffer) | ||
238 | return; | ||
239 | |||
240 | cursor.set = 0; | ||
241 | |||
242 | if (softback_lines) { | ||
243 | if (y + softback_lines >= vc->vc_rows) { | ||
244 | mode = CM_ERASE; | ||
245 | ops->cursor_flash = 0; | ||
246 | return; | ||
247 | } else | ||
248 | y += softback_lines; | ||
249 | } | ||
250 | |||
251 | c = scr_readw((u16 *) vc->vc_pos); | ||
252 | attribute = get_attribute(info, c); | ||
253 | src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); | ||
254 | |||
255 | if (ops->cursor_state.image.data != src || | ||
256 | ops->cursor_reset) { | ||
257 | ops->cursor_state.image.data = src; | ||
258 | cursor.set |= FB_CUR_SETIMAGE; | ||
259 | } | ||
260 | |||
261 | if (attribute) { | ||
262 | u8 *dst; | ||
263 | |||
264 | dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC); | ||
265 | if (!dst) | ||
266 | return; | ||
267 | kfree(ops->cursor_data); | ||
268 | ops->cursor_data = dst; | ||
269 | ccw_update_attr(dst, src, attribute, vc); | ||
270 | src = dst; | ||
271 | } | ||
272 | |||
273 | if (ops->cursor_state.image.fg_color != fg || | ||
274 | ops->cursor_state.image.bg_color != bg || | ||
275 | ops->cursor_reset) { | ||
276 | ops->cursor_state.image.fg_color = fg; | ||
277 | ops->cursor_state.image.bg_color = bg; | ||
278 | cursor.set |= FB_CUR_SETCMAP; | ||
279 | } | ||
280 | |||
281 | if (ops->cursor_state.image.height != vc->vc_font.width || | ||
282 | ops->cursor_state.image.width != vc->vc_font.height || | ||
283 | ops->cursor_reset) { | ||
284 | ops->cursor_state.image.height = vc->vc_font.width; | ||
285 | ops->cursor_state.image.width = vc->vc_font.height; | ||
286 | cursor.set |= FB_CUR_SETSIZE; | ||
287 | } | ||
288 | |||
289 | dx = y * vc->vc_font.height; | ||
290 | dy = vyres - ((vc->vc_x + 1) * vc->vc_font.width); | ||
291 | |||
292 | if (ops->cursor_state.image.dx != dx || | ||
293 | ops->cursor_state.image.dy != dy || | ||
294 | ops->cursor_reset) { | ||
295 | ops->cursor_state.image.dx = dx; | ||
296 | ops->cursor_state.image.dy = dy; | ||
297 | cursor.set |= FB_CUR_SETPOS; | ||
298 | } | ||
299 | |||
300 | if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || | ||
301 | ops->cursor_reset) { | ||
302 | ops->cursor_state.hot.x = cursor.hot.y = 0; | ||
303 | cursor.set |= FB_CUR_SETHOT; | ||
304 | } | ||
305 | |||
306 | if (cursor.set & FB_CUR_SETSIZE || | ||
307 | vc->vc_cursor_type != p->cursor_shape || | ||
308 | ops->cursor_state.mask == NULL || | ||
309 | ops->cursor_reset) { | ||
310 | char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC); | ||
311 | int cur_height, size, i = 0; | ||
312 | int width = (vc->vc_font.width + 7)/8; | ||
313 | |||
314 | if (!mask) | ||
315 | return; | ||
316 | |||
317 | tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC); | ||
318 | |||
319 | if (!tmp) { | ||
320 | kfree(mask); | ||
321 | return; | ||
322 | } | ||
323 | |||
324 | kfree(ops->cursor_state.mask); | ||
325 | ops->cursor_state.mask = mask; | ||
326 | |||
327 | p->cursor_shape = vc->vc_cursor_type; | ||
328 | cursor.set |= FB_CUR_SETSHAPE; | ||
329 | |||
330 | switch (p->cursor_shape & CUR_HWMASK) { | ||
331 | case CUR_NONE: | ||
332 | cur_height = 0; | ||
333 | break; | ||
334 | case CUR_UNDERLINE: | ||
335 | cur_height = (vc->vc_font.height < 10) ? 1 : 2; | ||
336 | break; | ||
337 | case CUR_LOWER_THIRD: | ||
338 | cur_height = vc->vc_font.height/3; | ||
339 | break; | ||
340 | case CUR_LOWER_HALF: | ||
341 | cur_height = vc->vc_font.height >> 1; | ||
342 | break; | ||
343 | case CUR_TWO_THIRDS: | ||
344 | cur_height = (vc->vc_font.height << 1)/3; | ||
345 | break; | ||
346 | case CUR_BLOCK: | ||
347 | default: | ||
348 | cur_height = vc->vc_font.height; | ||
349 | break; | ||
350 | } | ||
351 | |||
352 | size = (vc->vc_font.height - cur_height) * width; | ||
353 | while (size--) | ||
354 | tmp[i++] = 0; | ||
355 | size = cur_height * width; | ||
356 | while (size--) | ||
357 | tmp[i++] = 0xff; | ||
358 | memset(mask, 0, w * vc->vc_font.width); | ||
359 | rotate_ccw(tmp, mask, vc->vc_font.width, vc->vc_font.height); | ||
360 | kfree(tmp); | ||
361 | } | ||
362 | |||
363 | switch (mode) { | ||
364 | case CM_ERASE: | ||
365 | ops->cursor_state.enable = 0; | ||
366 | break; | ||
367 | case CM_DRAW: | ||
368 | case CM_MOVE: | ||
369 | default: | ||
370 | ops->cursor_state.enable = (use_sw) ? 0 : 1; | ||
371 | break; | ||
372 | } | ||
373 | |||
374 | cursor.image.data = src; | ||
375 | cursor.image.fg_color = ops->cursor_state.image.fg_color; | ||
376 | cursor.image.bg_color = ops->cursor_state.image.bg_color; | ||
377 | cursor.image.dx = ops->cursor_state.image.dx; | ||
378 | cursor.image.dy = ops->cursor_state.image.dy; | ||
379 | cursor.image.height = ops->cursor_state.image.height; | ||
380 | cursor.image.width = ops->cursor_state.image.width; | ||
381 | cursor.hot.x = ops->cursor_state.hot.x; | ||
382 | cursor.hot.y = ops->cursor_state.hot.y; | ||
383 | cursor.mask = ops->cursor_state.mask; | ||
384 | cursor.enable = ops->cursor_state.enable; | ||
385 | cursor.image.depth = 1; | ||
386 | cursor.rop = ROP_XOR; | ||
387 | |||
388 | if (info->fbops->fb_cursor) | ||
389 | err = info->fbops->fb_cursor(info, &cursor); | ||
390 | |||
391 | if (err) | ||
392 | soft_cursor(info, &cursor); | ||
393 | |||
394 | ops->cursor_reset = 0; | ||
395 | } | ||
396 | |||
397 | int ccw_update_start(struct fb_info *info) | ||
398 | { | ||
399 | struct fbcon_ops *ops = info->fbcon_par; | ||
400 | struct display *p = &fb_display[ops->currcon]; | ||
401 | u32 yoffset; | ||
402 | u32 vyres = GETVYRES(p->scrollmode, info); | ||
403 | int err; | ||
404 | |||
405 | yoffset = (vyres - info->var.yres) - ops->var.xoffset; | ||
406 | ops->var.xoffset = ops->var.yoffset; | ||
407 | ops->var.yoffset = yoffset; | ||
408 | err = fb_pan_display(info, &ops->var); | ||
409 | ops->var.xoffset = info->var.xoffset; | ||
410 | ops->var.yoffset = info->var.yoffset; | ||
411 | ops->var.vmode = info->var.vmode; | ||
412 | return err; | ||
413 | } | ||
414 | |||
415 | void fbcon_rotate_ccw(struct fbcon_ops *ops) | ||
416 | { | ||
417 | ops->bmove = ccw_bmove; | ||
418 | ops->clear = ccw_clear; | ||
419 | ops->putcs = ccw_putcs; | ||
420 | ops->clear_margins = ccw_clear_margins; | ||
421 | ops->cursor = ccw_cursor; | ||
422 | ops->update_start = ccw_update_start; | ||
423 | } | ||
424 | EXPORT_SYMBOL(fbcon_rotate_ccw); | ||
425 | |||
426 | MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); | ||
427 | MODULE_DESCRIPTION("Console Rotation (270 degrees) Support"); | ||
428 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c new file mode 100644 index 000000000000..6c6f3b6dd175 --- /dev/null +++ b/drivers/video/console/fbcon_cw.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 90 degrees | ||
3 | * | ||
4 | * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net> | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive for | ||
8 | * more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/string.h> | ||
14 | #include <linux/fb.h> | ||
15 | #include <linux/vt_kern.h> | ||
16 | #include <linux/console.h> | ||
17 | #include <asm/types.h> | ||
18 | #include "fbcon.h" | ||
19 | #include "fbcon_rotate.h" | ||
20 | |||
21 | /* | ||
22 | * Rotation 90 degrees | ||
23 | */ | ||
24 | |||
25 | static inline void cw_update_attr(u8 *dst, u8 *src, int attribute, | ||
26 | struct vc_data *vc) | ||
27 | { | ||
28 | int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2; | ||
29 | int width = (vc->vc_font.height + 7) >> 3; | ||
30 | u8 c, t = 0, msk = ~(0xff >> offset); | ||
31 | |||
32 | for (i = 0; i < vc->vc_font.width; i++) { | ||
33 | for (j = 0; j < width; j++) { | ||
34 | c = *src; | ||
35 | if (attribute & FBCON_ATTRIBUTE_UNDERLINE && !j) | ||
36 | c |= msk; | ||
37 | if (attribute & FBCON_ATTRIBUTE_BOLD && i) | ||
38 | c |= *(src-width); | ||
39 | if (attribute & FBCON_ATTRIBUTE_REVERSE) | ||
40 | c = ~c; | ||
41 | src++; | ||
42 | *dst++ = c; | ||
43 | t = c; | ||
44 | } | ||
45 | } | ||
46 | } | ||
47 | |||
48 | |||
49 | static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy, | ||
50 | int sx, int dy, int dx, int height, int width) | ||
51 | { | ||
52 | struct display *p = &fb_display[vc->vc_num]; | ||
53 | struct fb_copyarea area; | ||
54 | u32 vxres = GETVXRES(p->scrollmode, info); | ||
55 | |||
56 | area.sx = vxres - ((sy + height) * vc->vc_font.height); | ||
57 | area.sy = sx * vc->vc_font.width; | ||
58 | area.dx = vxres - ((dy + height) * vc->vc_font.height); | ||
59 | area.dy = dx * vc->vc_font.width; | ||
60 | area.width = height * vc->vc_font.height; | ||
61 | area.height = width * vc->vc_font.width; | ||
62 | |||
63 | info->fbops->fb_copyarea(info, &area); | ||
64 | } | ||
65 | |||
66 | static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy, | ||
67 | int sx, int height, int width) | ||
68 | { | ||
69 | struct display *p = &fb_display[vc->vc_num]; | ||
70 | struct fb_fillrect region; | ||
71 | int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; | ||
72 | u32 vxres = GETVXRES(p->scrollmode, info); | ||
73 | |||
74 | region.color = attr_bgcol_ec(bgshift,vc); | ||
75 | region.dx = vxres - ((sy + height) * vc->vc_font.height); | ||
76 | region.dy = sx * vc->vc_font.width; | ||
77 | region.height = width * vc->vc_font.width; | ||
78 | region.width = height * vc->vc_font.height; | ||
79 | region.rop = ROP_COPY; | ||
80 | |||
81 | info->fbops->fb_fillrect(info, ®ion); | ||
82 | } | ||
83 | |||
84 | static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info, | ||
85 | const u16 *s, u32 attr, u32 cnt, | ||
86 | u32 d_pitch, u32 s_pitch, u32 cellsize, | ||
87 | struct fb_image *image, u8 *buf, u8 *dst) | ||
88 | { | ||
89 | struct fbcon_ops *ops = info->fbcon_par; | ||
90 | u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; | ||
91 | u32 idx = (vc->vc_font.height + 7) >> 3; | ||
92 | u8 *src; | ||
93 | |||
94 | while (cnt--) { | ||
95 | src = ops->fontbuffer + (scr_readw(s++) & charmask)*cellsize; | ||
96 | |||
97 | if (attr) { | ||
98 | cw_update_attr(buf, src, attr, vc); | ||
99 | src = buf; | ||
100 | } | ||
101 | |||
102 | if (likely(idx == 1)) | ||
103 | __fb_pad_aligned_buffer(dst, d_pitch, src, idx, | ||
104 | vc->vc_font.width); | ||
105 | else | ||
106 | fb_pad_aligned_buffer(dst, d_pitch, src, idx, | ||
107 | vc->vc_font.width); | ||
108 | |||
109 | dst += d_pitch * vc->vc_font.width; | ||
110 | } | ||
111 | |||
112 | info->fbops->fb_imageblit(info, image); | ||
113 | } | ||
114 | |||
115 | static void cw_putcs(struct vc_data *vc, struct fb_info *info, | ||
116 | const unsigned short *s, int count, int yy, int xx, | ||
117 | int fg, int bg) | ||
118 | { | ||
119 | struct fb_image image; | ||
120 | struct display *p = &fb_display[vc->vc_num]; | ||
121 | struct fbcon_ops *ops = info->fbcon_par; | ||
122 | u32 width = (vc->vc_font.height + 7)/8; | ||
123 | u32 cellsize = width * vc->vc_font.width; | ||
124 | u32 maxcnt = info->pixmap.size/cellsize; | ||
125 | u32 scan_align = info->pixmap.scan_align - 1; | ||
126 | u32 buf_align = info->pixmap.buf_align - 1; | ||
127 | u32 cnt, pitch, size; | ||
128 | u32 attribute = get_attribute(info, scr_readw(s)); | ||
129 | u8 *dst, *buf = NULL; | ||
130 | u32 vxres = GETVXRES(p->scrollmode, info); | ||
131 | |||
132 | if (!ops->fontbuffer) | ||
133 | return; | ||
134 | |||
135 | image.fg_color = fg; | ||
136 | image.bg_color = bg; | ||
137 | image.dx = vxres - ((yy + 1) * vc->vc_font.height); | ||
138 | image.dy = xx * vc->vc_font.width; | ||
139 | image.width = vc->vc_font.height; | ||
140 | image.depth = 1; | ||
141 | |||
142 | if (attribute) { | ||
143 | buf = kmalloc(cellsize, GFP_KERNEL); | ||
144 | if (!buf) | ||
145 | return; | ||
146 | } | ||
147 | |||
148 | while (count) { | ||
149 | if (count > maxcnt) | ||
150 | cnt = maxcnt; | ||
151 | else | ||
152 | cnt = count; | ||
153 | |||
154 | image.height = vc->vc_font.width * cnt; | ||
155 | pitch = ((image.width + 7) >> 3) + scan_align; | ||
156 | pitch &= ~scan_align; | ||
157 | size = pitch * image.height + buf_align; | ||
158 | size &= ~buf_align; | ||
159 | dst = fb_get_buffer_offset(info, &info->pixmap, size); | ||
160 | image.data = dst; | ||
161 | cw_putcs_aligned(vc, info, s, attribute, cnt, pitch, | ||
162 | width, cellsize, &image, buf, dst); | ||
163 | image.dy += image.height; | ||
164 | count -= cnt; | ||
165 | s += cnt; | ||
166 | } | ||
167 | |||
168 | /* buf is always NULL except when in monochrome mode, so in this case | ||
169 | it's a gain to check buf against NULL even though kfree() handles | ||
170 | NULL pointers just fine */ | ||
171 | if (unlikely(buf)) | ||
172 | kfree(buf); | ||
173 | |||
174 | } | ||
175 | |||
176 | static void cw_clear_margins(struct vc_data *vc, struct fb_info *info, | ||
177 | int bottom_only) | ||
178 | { | ||
179 | unsigned int cw = vc->vc_font.width; | ||
180 | unsigned int ch = vc->vc_font.height; | ||
181 | unsigned int rw = info->var.yres - (vc->vc_cols*cw); | ||
182 | unsigned int bh = info->var.xres - (vc->vc_rows*ch); | ||
183 | unsigned int rs = info->var.yres - rw; | ||
184 | struct fb_fillrect region; | ||
185 | int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; | ||
186 | |||
187 | region.color = attr_bgcol_ec(bgshift,vc); | ||
188 | region.rop = ROP_COPY; | ||
189 | |||
190 | if (rw && !bottom_only) { | ||
191 | region.dx = 0; | ||
192 | region.dy = info->var.yoffset + rs; | ||
193 | region.height = rw; | ||
194 | region.width = info->var.xres_virtual; | ||
195 | info->fbops->fb_fillrect(info, ®ion); | ||
196 | } | ||
197 | |||
198 | if (bh) { | ||
199 | region.dx = info->var.xoffset; | ||
200 | region.dy = info->var.yoffset; | ||
201 | region.height = info->var.yres; | ||
202 | region.width = bh; | ||
203 | info->fbops->fb_fillrect(info, ®ion); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | static void cw_cursor(struct vc_data *vc, struct fb_info *info, | ||
208 | struct display *p, int mode, int softback_lines, | ||
209 | int fg, int bg) | ||
210 | { | ||
211 | struct fb_cursor cursor; | ||
212 | struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; | ||
213 | unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; | ||
214 | int w = (vc->vc_font.height + 7) >> 3, c; | ||
215 | int y = real_y(p, vc->vc_y); | ||
216 | int attribute, use_sw = (vc->vc_cursor_type & 0x10); | ||
217 | int err = 1, dx, dy; | ||
218 | char *src; | ||
219 | u32 vxres = GETVXRES(p->scrollmode, info); | ||
220 | |||
221 | if (!ops->fontbuffer) | ||
222 | return; | ||
223 | |||
224 | cursor.set = 0; | ||
225 | |||
226 | if (softback_lines) { | ||
227 | if (y + softback_lines >= vc->vc_rows) { | ||
228 | mode = CM_ERASE; | ||
229 | ops->cursor_flash = 0; | ||
230 | return; | ||
231 | } else | ||
232 | y += softback_lines; | ||
233 | } | ||
234 | |||
235 | c = scr_readw((u16 *) vc->vc_pos); | ||
236 | attribute = get_attribute(info, c); | ||
237 | src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); | ||
238 | |||
239 | if (ops->cursor_state.image.data != src || | ||
240 | ops->cursor_reset) { | ||
241 | ops->cursor_state.image.data = src; | ||
242 | cursor.set |= FB_CUR_SETIMAGE; | ||
243 | } | ||
244 | |||
245 | if (attribute) { | ||
246 | u8 *dst; | ||
247 | |||
248 | dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC); | ||
249 | if (!dst) | ||
250 | return; | ||
251 | kfree(ops->cursor_data); | ||
252 | ops->cursor_data = dst; | ||
253 | cw_update_attr(dst, src, attribute, vc); | ||
254 | src = dst; | ||
255 | } | ||
256 | |||
257 | if (ops->cursor_state.image.fg_color != fg || | ||
258 | ops->cursor_state.image.bg_color != bg || | ||
259 | ops->cursor_reset) { | ||
260 | ops->cursor_state.image.fg_color = fg; | ||
261 | ops->cursor_state.image.bg_color = bg; | ||
262 | cursor.set |= FB_CUR_SETCMAP; | ||
263 | } | ||
264 | |||
265 | if (ops->cursor_state.image.height != vc->vc_font.width || | ||
266 | ops->cursor_state.image.width != vc->vc_font.height || | ||
267 | ops->cursor_reset) { | ||
268 | ops->cursor_state.image.height = vc->vc_font.width; | ||
269 | ops->cursor_state.image.width = vc->vc_font.height; | ||
270 | cursor.set |= FB_CUR_SETSIZE; | ||
271 | } | ||
272 | |||
273 | dx = vxres - ((y * vc->vc_font.height) + vc->vc_font.height); | ||
274 | dy = vc->vc_x * vc->vc_font.width; | ||
275 | |||
276 | if (ops->cursor_state.image.dx != dx || | ||
277 | ops->cursor_state.image.dy != dy || | ||
278 | ops->cursor_reset) { | ||
279 | ops->cursor_state.image.dx = dx; | ||
280 | ops->cursor_state.image.dy = dy; | ||
281 | cursor.set |= FB_CUR_SETPOS; | ||
282 | } | ||
283 | |||
284 | if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || | ||
285 | ops->cursor_reset) { | ||
286 | ops->cursor_state.hot.x = cursor.hot.y = 0; | ||
287 | cursor.set |= FB_CUR_SETHOT; | ||
288 | } | ||
289 | |||
290 | if (cursor.set & FB_CUR_SETSIZE || | ||
291 | vc->vc_cursor_type != p->cursor_shape || | ||
292 | ops->cursor_state.mask == NULL || | ||
293 | ops->cursor_reset) { | ||
294 | char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC); | ||
295 | int cur_height, size, i = 0; | ||
296 | int width = (vc->vc_font.width + 7)/8; | ||
297 | |||
298 | if (!mask) | ||
299 | return; | ||
300 | |||
301 | tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC); | ||
302 | |||
303 | if (!tmp) { | ||
304 | kfree(mask); | ||
305 | return; | ||
306 | } | ||
307 | |||
308 | kfree(ops->cursor_state.mask); | ||
309 | ops->cursor_state.mask = mask; | ||
310 | |||
311 | p->cursor_shape = vc->vc_cursor_type; | ||
312 | cursor.set |= FB_CUR_SETSHAPE; | ||
313 | |||
314 | switch (p->cursor_shape & CUR_HWMASK) { | ||
315 | case CUR_NONE: | ||
316 | cur_height = 0; | ||
317 | break; | ||
318 | case CUR_UNDERLINE: | ||
319 | cur_height = (vc->vc_font.height < 10) ? 1 : 2; | ||
320 | break; | ||
321 | case CUR_LOWER_THIRD: | ||
322 | cur_height = vc->vc_font.height/3; | ||
323 | break; | ||
324 | case CUR_LOWER_HALF: | ||
325 | cur_height = vc->vc_font.height >> 1; | ||
326 | break; | ||
327 | case CUR_TWO_THIRDS: | ||
328 | cur_height = (vc->vc_font.height << 1)/3; | ||
329 | break; | ||
330 | case CUR_BLOCK: | ||
331 | default: | ||
332 | cur_height = vc->vc_font.height; | ||
333 | break; | ||
334 | } | ||
335 | |||
336 | size = (vc->vc_font.height - cur_height) * width; | ||
337 | while (size--) | ||
338 | tmp[i++] = 0; | ||
339 | size = cur_height * width; | ||
340 | while (size--) | ||
341 | tmp[i++] = 0xff; | ||
342 | memset(mask, 0, w * vc->vc_font.width); | ||
343 | rotate_cw(tmp, mask, vc->vc_font.width, vc->vc_font.height); | ||
344 | kfree(tmp); | ||
345 | } | ||
346 | |||
347 | switch (mode) { | ||
348 | case CM_ERASE: | ||
349 | ops->cursor_state.enable = 0; | ||
350 | break; | ||
351 | case CM_DRAW: | ||
352 | case CM_MOVE: | ||
353 | default: | ||
354 | ops->cursor_state.enable = (use_sw) ? 0 : 1; | ||
355 | break; | ||
356 | } | ||
357 | |||
358 | cursor.image.data = src; | ||
359 | cursor.image.fg_color = ops->cursor_state.image.fg_color; | ||
360 | cursor.image.bg_color = ops->cursor_state.image.bg_color; | ||
361 | cursor.image.dx = ops->cursor_state.image.dx; | ||
362 | cursor.image.dy = ops->cursor_state.image.dy; | ||
363 | cursor.image.height = ops->cursor_state.image.height; | ||
364 | cursor.image.width = ops->cursor_state.image.width; | ||
365 | cursor.hot.x = ops->cursor_state.hot.x; | ||
366 | cursor.hot.y = ops->cursor_state.hot.y; | ||
367 | cursor.mask = ops->cursor_state.mask; | ||
368 | cursor.enable = ops->cursor_state.enable; | ||
369 | cursor.image.depth = 1; | ||
370 | cursor.rop = ROP_XOR; | ||
371 | |||
372 | if (info->fbops->fb_cursor) | ||
373 | err = info->fbops->fb_cursor(info, &cursor); | ||
374 | |||
375 | if (err) | ||
376 | soft_cursor(info, &cursor); | ||
377 | |||
378 | ops->cursor_reset = 0; | ||
379 | } | ||
380 | |||
381 | int cw_update_start(struct fb_info *info) | ||
382 | { | ||
383 | struct fbcon_ops *ops = info->fbcon_par; | ||
384 | struct display *p = &fb_display[ops->currcon]; | ||
385 | u32 vxres = GETVXRES(p->scrollmode, info); | ||
386 | u32 xoffset; | ||
387 | int err; | ||
388 | |||
389 | xoffset = vxres - (info->var.xres + ops->var.yoffset); | ||
390 | ops->var.yoffset = ops->var.xoffset; | ||
391 | ops->var.xoffset = xoffset; | ||
392 | err = fb_pan_display(info, &ops->var); | ||
393 | ops->var.xoffset = info->var.xoffset; | ||
394 | ops->var.yoffset = info->var.yoffset; | ||
395 | ops->var.vmode = info->var.vmode; | ||
396 | return err; | ||
397 | } | ||
398 | |||
399 | void fbcon_rotate_cw(struct fbcon_ops *ops) | ||
400 | { | ||
401 | ops->bmove = cw_bmove; | ||
402 | ops->clear = cw_clear; | ||
403 | ops->putcs = cw_putcs; | ||
404 | ops->clear_margins = cw_clear_margins; | ||
405 | ops->cursor = cw_cursor; | ||
406 | ops->update_start = cw_update_start; | ||
407 | } | ||
408 | EXPORT_SYMBOL(fbcon_rotate_cw); | ||
409 | |||
410 | MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); | ||
411 | MODULE_DESCRIPTION("Console Rotation (90 degrees) Support"); | ||
412 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/console/fbcon_rotate.c b/drivers/video/console/fbcon_rotate.c new file mode 100644 index 000000000000..ec0dd8fe241c --- /dev/null +++ b/drivers/video/console/fbcon_rotate.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/console/fbcon_rotate.c -- Software Rotation | ||
3 | * | ||
4 | * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net> | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive for | ||
8 | * more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/string.h> | ||
14 | #include <linux/fb.h> | ||
15 | #include <linux/vt_kern.h> | ||
16 | #include <linux/console.h> | ||
17 | #include <asm/types.h> | ||
18 | #include "fbcon.h" | ||
19 | #include "fbcon_rotate.h" | ||
20 | |||
21 | static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc, | ||
22 | struct display *p) | ||
23 | { | ||
24 | struct fbcon_ops *ops = info->fbcon_par; | ||
25 | int len, err = 0; | ||
26 | int s_cellsize, d_cellsize, i; | ||
27 | const u8 *src; | ||
28 | u8 *dst; | ||
29 | |||
30 | if (vc->vc_font.data == ops->fontdata && | ||
31 | p->con_rotate == ops->cur_rotate) | ||
32 | goto finished; | ||
33 | |||
34 | src = ops->fontdata = vc->vc_font.data; | ||
35 | ops->cur_rotate = p->con_rotate; | ||
36 | len = (!p->userfont) ? 256 : FNTCHARCNT(src); | ||
37 | s_cellsize = ((vc->vc_font.width + 7)/8) * | ||
38 | vc->vc_font.height; | ||
39 | d_cellsize = s_cellsize; | ||
40 | |||
41 | if (ops->rotate == FB_ROTATE_CW || | ||
42 | ops->rotate == FB_ROTATE_CCW) | ||
43 | d_cellsize = ((vc->vc_font.height + 7)/8) * | ||
44 | vc->vc_font.width; | ||
45 | |||
46 | if (info->fbops->fb_sync) | ||
47 | info->fbops->fb_sync(info); | ||
48 | |||
49 | if (ops->fd_size < d_cellsize * len) { | ||
50 | dst = kmalloc(d_cellsize * len, GFP_KERNEL); | ||
51 | |||
52 | if (dst == NULL) { | ||
53 | err = -ENOMEM; | ||
54 | goto finished; | ||
55 | } | ||
56 | |||
57 | ops->fd_size = d_cellsize * len; | ||
58 | kfree(ops->fontbuffer); | ||
59 | ops->fontbuffer = dst; | ||
60 | } | ||
61 | |||
62 | dst = ops->fontbuffer; | ||
63 | memset(dst, 0, ops->fd_size); | ||
64 | |||
65 | switch (ops->rotate) { | ||
66 | case FB_ROTATE_UD: | ||
67 | for (i = len; i--; ) { | ||
68 | rotate_ud(src, dst, vc->vc_font.width, | ||
69 | vc->vc_font.height); | ||
70 | |||
71 | src += s_cellsize; | ||
72 | dst += d_cellsize; | ||
73 | } | ||
74 | break; | ||
75 | case FB_ROTATE_CW: | ||
76 | for (i = len; i--; ) { | ||
77 | rotate_cw(src, dst, vc->vc_font.width, | ||
78 | vc->vc_font.height); | ||
79 | src += s_cellsize; | ||
80 | dst += d_cellsize; | ||
81 | } | ||
82 | break; | ||
83 | case FB_ROTATE_CCW: | ||
84 | for (i = len; i--; ) { | ||
85 | rotate_ccw(src, dst, vc->vc_font.width, | ||
86 | vc->vc_font.height); | ||
87 | src += s_cellsize; | ||
88 | dst += d_cellsize; | ||
89 | } | ||
90 | break; | ||
91 | } | ||
92 | |||
93 | finished: | ||
94 | return err; | ||
95 | } | ||
96 | |||
97 | void fbcon_set_rotate(struct fbcon_ops *ops) | ||
98 | { | ||
99 | ops->rotate_font = fbcon_rotate_font; | ||
100 | |||
101 | switch(ops->rotate) { | ||
102 | case FB_ROTATE_CW: | ||
103 | fbcon_rotate_cw(ops); | ||
104 | break; | ||
105 | case FB_ROTATE_UD: | ||
106 | fbcon_rotate_ud(ops); | ||
107 | break; | ||
108 | case FB_ROTATE_CCW: | ||
109 | fbcon_rotate_ccw(ops); | ||
110 | break; | ||
111 | } | ||
112 | } | ||
113 | EXPORT_SYMBOL(fbcon_set_rotate); | ||
114 | |||
115 | MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); | ||
116 | MODULE_DESCRIPTION("Console Rotation Support"); | ||
117 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/console/fbcon_rotate.h b/drivers/video/console/fbcon_rotate.h new file mode 100644 index 000000000000..90c672096c2e --- /dev/null +++ b/drivers/video/console/fbcon_rotate.h | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/console/fbcon_rotate.h -- Software Display Rotation | ||
3 | * | ||
4 | * Copyright (C) 2005 Antonino Daplas <adaplas@pol.net> | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #ifndef _FBCON_ROTATE_H | ||
12 | #define _FBCON_ROTATE_H | ||
13 | |||
14 | #define FNTCHARCNT(fd) (((int *)(fd))[-3]) | ||
15 | |||
16 | #define GETVYRES(s,i) ({ \ | ||
17 | (s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \ | ||
18 | (i)->var.yres : (i)->var.yres_virtual; }) | ||
19 | |||
20 | #define GETVXRES(s,i) ({ \ | ||
21 | (s == SCROLL_REDRAW || s == SCROLL_MOVE || !(i)->fix.xpanstep) ? \ | ||
22 | (i)->var.xres : (i)->var.xres_virtual; }) | ||
23 | |||
24 | /* | ||
25 | * The bitmap is always big endian | ||
26 | */ | ||
27 | #if defined(__LITTLE_ENDIAN) | ||
28 | #define FBCON_BIT(b) (7 - (b)) | ||
29 | #else | ||
30 | #define FBCON_BIT(b) (b) | ||
31 | #endif | ||
32 | |||
33 | static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat) | ||
34 | { | ||
35 | u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8; | ||
36 | |||
37 | pat +=index; | ||
38 | return (test_bit(FBCON_BIT(bit), (void *)pat)); | ||
39 | } | ||
40 | |||
41 | static inline void pattern_set_bit(u32 x, u32 y, u32 pitch, char *pat) | ||
42 | { | ||
43 | u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8; | ||
44 | |||
45 | pat += index; | ||
46 | set_bit(FBCON_BIT(bit), (void *)pat); | ||
47 | } | ||
48 | |||
49 | static inline void rotate_ud(const char *in, char *out, u32 width, u32 height) | ||
50 | { | ||
51 | int i, j; | ||
52 | int shift = width % 8; | ||
53 | |||
54 | width = (width + 7) & ~7; | ||
55 | |||
56 | for (i = 0; i < height; i++) { | ||
57 | for (j = 0; j < width; j++) { | ||
58 | if (pattern_test_bit(j, i, width, in)) | ||
59 | pattern_set_bit(width - (1 + j + shift), | ||
60 | height - (1 + i), | ||
61 | width, out); | ||
62 | } | ||
63 | |||
64 | } | ||
65 | } | ||
66 | |||
67 | static inline void rotate_cw(const char *in, char *out, u32 width, u32 height) | ||
68 | { | ||
69 | int i, j, h = height, w = width; | ||
70 | int shift = (8 - (height % 8)) & 7; | ||
71 | |||
72 | width = (width + 7) & ~7; | ||
73 | height = (height + 7) & ~7; | ||
74 | |||
75 | for (i = 0; i < h; i++) { | ||
76 | for (j = 0; j < w; j++) { | ||
77 | if (pattern_test_bit(j, i, width, in)) | ||
78 | pattern_set_bit(height - 1 - i - shift, j, | ||
79 | height, out); | ||
80 | |||
81 | } | ||
82 | } | ||
83 | } | ||
84 | |||
85 | static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height) | ||
86 | { | ||
87 | int i, j, h = height, w = width; | ||
88 | int shift = width % 8; | ||
89 | |||
90 | width = (width + 7) & ~7; | ||
91 | height = (height + 7) & ~7; | ||
92 | |||
93 | for (i = 0; i < h; i++) { | ||
94 | for (j = 0; j < w; j++) { | ||
95 | if (pattern_test_bit(j, i, width, in)) | ||
96 | pattern_set_bit(i, width - 1 - j - shift, | ||
97 | height, out); | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | |||
102 | extern void fbcon_rotate_cw(struct fbcon_ops *ops); | ||
103 | extern void fbcon_rotate_ud(struct fbcon_ops *ops); | ||
104 | extern void fbcon_rotate_ccw(struct fbcon_ops *ops); | ||
105 | #endif | ||
diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c new file mode 100644 index 000000000000..2e1d9d4249cd --- /dev/null +++ b/drivers/video/console/fbcon_ud.c | |||
@@ -0,0 +1,454 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 180 degrees | ||
3 | * | ||
4 | * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net> | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive for | ||
8 | * more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/string.h> | ||
14 | #include <linux/fb.h> | ||
15 | #include <linux/vt_kern.h> | ||
16 | #include <linux/console.h> | ||
17 | #include <asm/types.h> | ||
18 | #include "fbcon.h" | ||
19 | #include "fbcon_rotate.h" | ||
20 | |||
21 | /* | ||
22 | * Rotation 180 degrees | ||
23 | */ | ||
24 | |||
25 | static inline void ud_update_attr(u8 *dst, u8 *src, int attribute, | ||
26 | struct vc_data *vc) | ||
27 | { | ||
28 | int i, offset = (vc->vc_font.height < 10) ? 1 : 2; | ||
29 | int width = (vc->vc_font.width + 7) >> 3; | ||
30 | unsigned int cellsize = vc->vc_font.height * width; | ||
31 | u8 c; | ||
32 | |||
33 | offset = offset * width; | ||
34 | |||
35 | for (i = 0; i < cellsize; i++) { | ||
36 | c = src[i]; | ||
37 | if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i < offset) | ||
38 | c = 0xff; | ||
39 | if (attribute & FBCON_ATTRIBUTE_BOLD) | ||
40 | c |= c << 1; | ||
41 | if (attribute & FBCON_ATTRIBUTE_REVERSE) | ||
42 | c = ~c; | ||
43 | dst[i] = c; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | |||
48 | static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy, | ||
49 | int sx, int dy, int dx, int height, int width) | ||
50 | { | ||
51 | struct display *p = &fb_display[vc->vc_num]; | ||
52 | struct fb_copyarea area; | ||
53 | u32 vyres = GETVYRES(p->scrollmode, info); | ||
54 | u32 vxres = GETVXRES(p->scrollmode, info); | ||
55 | |||
56 | area.sy = vyres - ((sy + height) * vc->vc_font.height); | ||
57 | area.sx = vxres - ((sx + width) * vc->vc_font.width); | ||
58 | area.dy = vyres - ((dy + height) * vc->vc_font.height); | ||
59 | area.dx = vxres - ((dx + width) * vc->vc_font.width); | ||
60 | area.height = height * vc->vc_font.height; | ||
61 | area.width = width * vc->vc_font.width; | ||
62 | |||
63 | info->fbops->fb_copyarea(info, &area); | ||
64 | } | ||
65 | |||
66 | static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy, | ||
67 | int sx, int height, int width) | ||
68 | { | ||
69 | struct display *p = &fb_display[vc->vc_num]; | ||
70 | struct fb_fillrect region; | ||
71 | int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; | ||
72 | u32 vyres = GETVYRES(p->scrollmode, info); | ||
73 | u32 vxres = GETVXRES(p->scrollmode, info); | ||
74 | |||
75 | region.color = attr_bgcol_ec(bgshift,vc); | ||
76 | region.dy = vyres - ((sy + height) * vc->vc_font.height); | ||
77 | region.dx = vxres - ((sx + width) * vc->vc_font.width); | ||
78 | region.width = width * vc->vc_font.width; | ||
79 | region.height = height * vc->vc_font.height; | ||
80 | region.rop = ROP_COPY; | ||
81 | |||
82 | info->fbops->fb_fillrect(info, ®ion); | ||
83 | } | ||
84 | |||
85 | static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info, | ||
86 | const u16 *s, u32 attr, u32 cnt, | ||
87 | u32 d_pitch, u32 s_pitch, u32 cellsize, | ||
88 | struct fb_image *image, u8 *buf, u8 *dst) | ||
89 | { | ||
90 | struct fbcon_ops *ops = info->fbcon_par; | ||
91 | u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; | ||
92 | u32 idx = vc->vc_font.width >> 3; | ||
93 | u8 *src; | ||
94 | |||
95 | while (cnt--) { | ||
96 | src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize; | ||
97 | |||
98 | if (attr) { | ||
99 | ud_update_attr(buf, src, attr, vc); | ||
100 | src = buf; | ||
101 | } | ||
102 | |||
103 | if (likely(idx == 1)) | ||
104 | __fb_pad_aligned_buffer(dst, d_pitch, src, idx, | ||
105 | image->height); | ||
106 | else | ||
107 | fb_pad_aligned_buffer(dst, d_pitch, src, idx, | ||
108 | image->height); | ||
109 | |||
110 | dst += s_pitch; | ||
111 | } | ||
112 | |||
113 | info->fbops->fb_imageblit(info, image); | ||
114 | } | ||
115 | |||
116 | static inline void ud_putcs_unaligned(struct vc_data *vc, | ||
117 | struct fb_info *info, const u16 *s, | ||
118 | u32 attr, u32 cnt, u32 d_pitch, | ||
119 | u32 s_pitch, u32 cellsize, | ||
120 | struct fb_image *image, u8 *buf, | ||
121 | u8 *dst) | ||
122 | { | ||
123 | struct fbcon_ops *ops = info->fbcon_par; | ||
124 | u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; | ||
125 | u32 shift_low = 0, mod = vc->vc_font.width % 8; | ||
126 | u32 shift_high = 8; | ||
127 | u32 idx = vc->vc_font.width >> 3; | ||
128 | u8 *src; | ||
129 | |||
130 | while (cnt--) { | ||
131 | src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize; | ||
132 | |||
133 | if (attr) { | ||
134 | ud_update_attr(buf, src, attr, vc); | ||
135 | src = buf; | ||
136 | } | ||
137 | |||
138 | fb_pad_unaligned_buffer(dst, d_pitch, src, idx, | ||
139 | image->height, shift_high, | ||
140 | shift_low, mod); | ||
141 | shift_low += mod; | ||
142 | dst += (shift_low >= 8) ? s_pitch : s_pitch - 1; | ||
143 | shift_low &= 7; | ||
144 | shift_high = 8 - shift_low; | ||
145 | } | ||
146 | |||
147 | info->fbops->fb_imageblit(info, image); | ||
148 | |||
149 | } | ||
150 | |||
151 | static void ud_putcs(struct vc_data *vc, struct fb_info *info, | ||
152 | const unsigned short *s, int count, int yy, int xx, | ||
153 | int fg, int bg) | ||
154 | { | ||
155 | struct fb_image image; | ||
156 | struct display *p = &fb_display[vc->vc_num]; | ||
157 | struct fbcon_ops *ops = info->fbcon_par; | ||
158 | u32 width = (vc->vc_font.width + 7)/8; | ||
159 | u32 cellsize = width * vc->vc_font.height; | ||
160 | u32 maxcnt = info->pixmap.size/cellsize; | ||
161 | u32 scan_align = info->pixmap.scan_align - 1; | ||
162 | u32 buf_align = info->pixmap.buf_align - 1; | ||
163 | u32 mod = vc->vc_font.width % 8, cnt, pitch, size; | ||
164 | u32 attribute = get_attribute(info, scr_readw(s)); | ||
165 | u8 *dst, *buf = NULL; | ||
166 | u32 vyres = GETVYRES(p->scrollmode, info); | ||
167 | u32 vxres = GETVXRES(p->scrollmode, info); | ||
168 | |||
169 | if (!ops->fontbuffer) | ||
170 | return; | ||
171 | |||
172 | image.fg_color = fg; | ||
173 | image.bg_color = bg; | ||
174 | image.dy = vyres - ((yy * vc->vc_font.height) + vc->vc_font.height); | ||
175 | image.dx = vxres - ((xx + count) * vc->vc_font.width); | ||
176 | image.height = vc->vc_font.height; | ||
177 | image.depth = 1; | ||
178 | |||
179 | if (attribute) { | ||
180 | buf = kmalloc(cellsize, GFP_KERNEL); | ||
181 | if (!buf) | ||
182 | return; | ||
183 | } | ||
184 | |||
185 | s += count - 1; | ||
186 | |||
187 | while (count) { | ||
188 | if (count > maxcnt) | ||
189 | cnt = maxcnt; | ||
190 | else | ||
191 | cnt = count; | ||
192 | |||
193 | image.width = vc->vc_font.width * cnt; | ||
194 | pitch = ((image.width + 7) >> 3) + scan_align; | ||
195 | pitch &= ~scan_align; | ||
196 | size = pitch * image.height + buf_align; | ||
197 | size &= ~buf_align; | ||
198 | dst = fb_get_buffer_offset(info, &info->pixmap, size); | ||
199 | image.data = dst; | ||
200 | |||
201 | if (!mod) | ||
202 | ud_putcs_aligned(vc, info, s, attribute, cnt, pitch, | ||
203 | width, cellsize, &image, buf, dst); | ||
204 | else | ||
205 | ud_putcs_unaligned(vc, info, s, attribute, cnt, pitch, | ||
206 | width, cellsize, &image, | ||
207 | buf, dst); | ||
208 | |||
209 | image.dx += image.width; | ||
210 | count -= cnt; | ||
211 | s -= cnt; | ||
212 | xx += cnt; | ||
213 | } | ||
214 | |||
215 | /* buf is always NULL except when in monochrome mode, so in this case | ||
216 | it's a gain to check buf against NULL even though kfree() handles | ||
217 | NULL pointers just fine */ | ||
218 | if (unlikely(buf)) | ||
219 | kfree(buf); | ||
220 | |||
221 | } | ||
222 | |||
223 | static void ud_clear_margins(struct vc_data *vc, struct fb_info *info, | ||
224 | int bottom_only) | ||
225 | { | ||
226 | unsigned int cw = vc->vc_font.width; | ||
227 | unsigned int ch = vc->vc_font.height; | ||
228 | unsigned int rw = info->var.xres - (vc->vc_cols*cw); | ||
229 | unsigned int bh = info->var.yres - (vc->vc_rows*ch); | ||
230 | struct fb_fillrect region; | ||
231 | int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; | ||
232 | |||
233 | region.color = attr_bgcol_ec(bgshift,vc); | ||
234 | region.rop = ROP_COPY; | ||
235 | |||
236 | if (rw && !bottom_only) { | ||
237 | region.dy = 0; | ||
238 | region.dx = info->var.xoffset; | ||
239 | region.width = rw; | ||
240 | region.height = info->var.yres_virtual; | ||
241 | info->fbops->fb_fillrect(info, ®ion); | ||
242 | } | ||
243 | |||
244 | if (bh) { | ||
245 | region.dy = info->var.yoffset; | ||
246 | region.dx = info->var.xoffset; | ||
247 | region.height = bh; | ||
248 | region.width = info->var.xres; | ||
249 | info->fbops->fb_fillrect(info, ®ion); | ||
250 | } | ||
251 | } | ||
252 | |||
253 | static void ud_cursor(struct vc_data *vc, struct fb_info *info, | ||
254 | struct display *p, int mode, int softback_lines, | ||
255 | int fg, int bg) | ||
256 | { | ||
257 | struct fb_cursor cursor; | ||
258 | struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par; | ||
259 | unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; | ||
260 | int w = (vc->vc_font.width + 7) >> 3, c; | ||
261 | int y = real_y(p, vc->vc_y); | ||
262 | int attribute, use_sw = (vc->vc_cursor_type & 0x10); | ||
263 | int err = 1, dx, dy; | ||
264 | char *src; | ||
265 | u32 vyres = GETVYRES(p->scrollmode, info); | ||
266 | u32 vxres = GETVXRES(p->scrollmode, info); | ||
267 | |||
268 | if (!ops->fontbuffer) | ||
269 | return; | ||
270 | |||
271 | cursor.set = 0; | ||
272 | |||
273 | if (softback_lines) { | ||
274 | if (y + softback_lines >= vc->vc_rows) { | ||
275 | mode = CM_ERASE; | ||
276 | ops->cursor_flash = 0; | ||
277 | return; | ||
278 | } else | ||
279 | y += softback_lines; | ||
280 | } | ||
281 | |||
282 | c = scr_readw((u16 *) vc->vc_pos); | ||
283 | attribute = get_attribute(info, c); | ||
284 | src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height)); | ||
285 | |||
286 | if (ops->cursor_state.image.data != src || | ||
287 | ops->cursor_reset) { | ||
288 | ops->cursor_state.image.data = src; | ||
289 | cursor.set |= FB_CUR_SETIMAGE; | ||
290 | } | ||
291 | |||
292 | if (attribute) { | ||
293 | u8 *dst; | ||
294 | |||
295 | dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC); | ||
296 | if (!dst) | ||
297 | return; | ||
298 | kfree(ops->cursor_data); | ||
299 | ops->cursor_data = dst; | ||
300 | ud_update_attr(dst, src, attribute, vc); | ||
301 | src = dst; | ||
302 | } | ||
303 | |||
304 | if (ops->cursor_state.image.fg_color != fg || | ||
305 | ops->cursor_state.image.bg_color != bg || | ||
306 | ops->cursor_reset) { | ||
307 | ops->cursor_state.image.fg_color = fg; | ||
308 | ops->cursor_state.image.bg_color = bg; | ||
309 | cursor.set |= FB_CUR_SETCMAP; | ||
310 | } | ||
311 | |||
312 | if (ops->cursor_state.image.height != vc->vc_font.height || | ||
313 | ops->cursor_state.image.width != vc->vc_font.width || | ||
314 | ops->cursor_reset) { | ||
315 | ops->cursor_state.image.height = vc->vc_font.height; | ||
316 | ops->cursor_state.image.width = vc->vc_font.width; | ||
317 | cursor.set |= FB_CUR_SETSIZE; | ||
318 | } | ||
319 | |||
320 | dy = vyres - ((y * vc->vc_font.height) + vc->vc_font.height); | ||
321 | dx = vxres - ((vc->vc_x * vc->vc_font.width) + vc->vc_font.width); | ||
322 | |||
323 | if (ops->cursor_state.image.dx != dx || | ||
324 | ops->cursor_state.image.dy != dy || | ||
325 | ops->cursor_reset) { | ||
326 | ops->cursor_state.image.dx = dx; | ||
327 | ops->cursor_state.image.dy = dy; | ||
328 | cursor.set |= FB_CUR_SETPOS; | ||
329 | } | ||
330 | |||
331 | if (ops->cursor_state.hot.x || ops->cursor_state.hot.y || | ||
332 | ops->cursor_reset) { | ||
333 | ops->cursor_state.hot.x = cursor.hot.y = 0; | ||
334 | cursor.set |= FB_CUR_SETHOT; | ||
335 | } | ||
336 | |||
337 | if (cursor.set & FB_CUR_SETSIZE || | ||
338 | vc->vc_cursor_type != p->cursor_shape || | ||
339 | ops->cursor_state.mask == NULL || | ||
340 | ops->cursor_reset) { | ||
341 | char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC); | ||
342 | int cur_height, size, i = 0; | ||
343 | u8 msk = 0xff; | ||
344 | |||
345 | if (!mask) | ||
346 | return; | ||
347 | |||
348 | kfree(ops->cursor_state.mask); | ||
349 | ops->cursor_state.mask = mask; | ||
350 | |||
351 | p->cursor_shape = vc->vc_cursor_type; | ||
352 | cursor.set |= FB_CUR_SETSHAPE; | ||
353 | |||
354 | switch (p->cursor_shape & CUR_HWMASK) { | ||
355 | case CUR_NONE: | ||
356 | cur_height = 0; | ||
357 | break; | ||
358 | case CUR_UNDERLINE: | ||
359 | cur_height = (vc->vc_font.height < 10) ? 1 : 2; | ||
360 | break; | ||
361 | case CUR_LOWER_THIRD: | ||
362 | cur_height = vc->vc_font.height/3; | ||
363 | break; | ||
364 | case CUR_LOWER_HALF: | ||
365 | cur_height = vc->vc_font.height >> 1; | ||
366 | break; | ||
367 | case CUR_TWO_THIRDS: | ||
368 | cur_height = (vc->vc_font.height << 1)/3; | ||
369 | break; | ||
370 | case CUR_BLOCK: | ||
371 | default: | ||
372 | cur_height = vc->vc_font.height; | ||
373 | break; | ||
374 | } | ||
375 | |||
376 | size = cur_height * w; | ||
377 | |||
378 | while (size--) | ||
379 | mask[i++] = msk; | ||
380 | |||
381 | size = (vc->vc_font.height - cur_height) * w; | ||
382 | |||
383 | while (size--) | ||
384 | mask[i++] = ~msk; | ||
385 | } | ||
386 | |||
387 | switch (mode) { | ||
388 | case CM_ERASE: | ||
389 | ops->cursor_state.enable = 0; | ||
390 | break; | ||
391 | case CM_DRAW: | ||
392 | case CM_MOVE: | ||
393 | default: | ||
394 | ops->cursor_state.enable = (use_sw) ? 0 : 1; | ||
395 | break; | ||
396 | } | ||
397 | |||
398 | cursor.image.data = src; | ||
399 | cursor.image.fg_color = ops->cursor_state.image.fg_color; | ||
400 | cursor.image.bg_color = ops->cursor_state.image.bg_color; | ||
401 | cursor.image.dx = ops->cursor_state.image.dx; | ||
402 | cursor.image.dy = ops->cursor_state.image.dy; | ||
403 | cursor.image.height = ops->cursor_state.image.height; | ||
404 | cursor.image.width = ops->cursor_state.image.width; | ||
405 | cursor.hot.x = ops->cursor_state.hot.x; | ||
406 | cursor.hot.y = ops->cursor_state.hot.y; | ||
407 | cursor.mask = ops->cursor_state.mask; | ||
408 | cursor.enable = ops->cursor_state.enable; | ||
409 | cursor.image.depth = 1; | ||
410 | cursor.rop = ROP_XOR; | ||
411 | |||
412 | if (info->fbops->fb_cursor) | ||
413 | err = info->fbops->fb_cursor(info, &cursor); | ||
414 | |||
415 | if (err) | ||
416 | soft_cursor(info, &cursor); | ||
417 | |||
418 | ops->cursor_reset = 0; | ||
419 | } | ||
420 | |||
421 | int ud_update_start(struct fb_info *info) | ||
422 | { | ||
423 | struct fbcon_ops *ops = info->fbcon_par; | ||
424 | struct display *p = &fb_display[ops->currcon]; | ||
425 | u32 xoffset, yoffset; | ||
426 | u32 vyres = GETVYRES(p->scrollmode, info); | ||
427 | u32 vxres = GETVXRES(p->scrollmode, info); | ||
428 | int err; | ||
429 | |||
430 | xoffset = (vxres - info->var.xres) - ops->var.xoffset; | ||
431 | yoffset = (vyres - info->var.yres) - ops->var.yoffset; | ||
432 | ops->var.xoffset = xoffset; | ||
433 | ops->var.yoffset = yoffset; | ||
434 | err = fb_pan_display(info, &ops->var); | ||
435 | ops->var.xoffset = info->var.xoffset; | ||
436 | ops->var.yoffset = info->var.yoffset; | ||
437 | ops->var.vmode = info->var.vmode; | ||
438 | return err; | ||
439 | } | ||
440 | |||
441 | void fbcon_rotate_ud(struct fbcon_ops *ops) | ||
442 | { | ||
443 | ops->bmove = ud_bmove; | ||
444 | ops->clear = ud_clear; | ||
445 | ops->putcs = ud_putcs; | ||
446 | ops->clear_margins = ud_clear_margins; | ||
447 | ops->cursor = ud_cursor; | ||
448 | ops->update_start = ud_update_start; | ||
449 | } | ||
450 | EXPORT_SYMBOL(fbcon_rotate_ud); | ||
451 | |||
452 | MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); | ||
453 | MODULE_DESCRIPTION("Console Rotation (180 degrees) Support"); | ||
454 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c index 7f76e2c6a4a1..cb25324a5635 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, | |||
118 | info->tileops->fb_tilecursor(info, &cursor); | 118 | info->tileops->fb_tilecursor(info, &cursor); |
119 | } | 119 | } |
120 | 120 | ||
121 | static int tile_update_start(struct fb_info *info) | ||
122 | { | ||
123 | struct fbcon_ops *ops = info->fbcon_par; | ||
124 | int err; | ||
125 | |||
126 | err = fb_pan_display(info, &ops->var); | ||
127 | ops->var.xoffset = info->var.xoffset; | ||
128 | ops->var.yoffset = info->var.yoffset; | ||
129 | ops->var.vmode = info->var.vmode; | ||
130 | return err; | ||
131 | } | ||
132 | |||
121 | void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, | 133 | void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, |
122 | struct display *p, struct fbcon_ops *ops) | 134 | struct display *p, struct fbcon_ops *ops) |
123 | { | 135 | { |
@@ -128,6 +140,7 @@ void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, | |||
128 | ops->putcs = tile_putcs; | 140 | ops->putcs = tile_putcs; |
129 | ops->clear_margins = tile_clear_margins; | 141 | ops->clear_margins = tile_clear_margins; |
130 | ops->cursor = tile_cursor; | 142 | ops->cursor = tile_cursor; |
143 | ops->update_start = tile_update_start; | ||
131 | 144 | ||
132 | if (p) { | 145 | if (p) { |
133 | map.width = vc->vc_font.width; | 146 | map.width = vc->vc_font.width; |
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index e2667ddab3f1..9f180096c896 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/config.h> | 14 | #include <linux/config.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | 16 | ||
17 | #include <linux/compat.h> | ||
17 | #include <linux/types.h> | 18 | #include <linux/types.h> |
18 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
19 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
@@ -323,9 +324,103 @@ static struct logo_data { | |||
323 | const struct linux_logo *logo; | 324 | const struct linux_logo *logo; |
324 | } fb_logo; | 325 | } fb_logo; |
325 | 326 | ||
326 | int fb_prepare_logo(struct fb_info *info) | 327 | static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height) |
328 | { | ||
329 | u32 size = width * height, i; | ||
330 | |||
331 | out += size - 1; | ||
332 | |||
333 | for (i = size; i--; ) | ||
334 | *out-- = *in++; | ||
335 | } | ||
336 | |||
337 | static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height) | ||
338 | { | ||
339 | int i, j, w = width - 1; | ||
340 | |||
341 | for (i = 0; i < height; i++) | ||
342 | for (j = 0; j < width; j++) | ||
343 | out[height * j + w - i] = *in++; | ||
344 | } | ||
345 | |||
346 | static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height) | ||
347 | { | ||
348 | int i, j, w = width - 1; | ||
349 | |||
350 | for (i = 0; i < height; i++) | ||
351 | for (j = 0; j < width; j++) | ||
352 | out[height * (w - j) + i] = *in++; | ||
353 | } | ||
354 | |||
355 | static void fb_rotate_logo(struct fb_info *info, u8 *dst, | ||
356 | struct fb_image *image, int rotate) | ||
357 | { | ||
358 | u32 tmp; | ||
359 | |||
360 | if (rotate == FB_ROTATE_UD) { | ||
361 | image->dx = info->var.xres - image->width; | ||
362 | image->dy = info->var.yres - image->height; | ||
363 | fb_rotate_logo_ud(image->data, dst, image->width, | ||
364 | image->height); | ||
365 | } else if (rotate == FB_ROTATE_CW) { | ||
366 | tmp = image->width; | ||
367 | image->width = image->height; | ||
368 | image->height = tmp; | ||
369 | image->dx = info->var.xres - image->height; | ||
370 | fb_rotate_logo_cw(image->data, dst, image->width, | ||
371 | image->height); | ||
372 | } else if (rotate == FB_ROTATE_CCW) { | ||
373 | tmp = image->width; | ||
374 | image->width = image->height; | ||
375 | image->height = tmp; | ||
376 | image->dy = info->var.yres - image->width; | ||
377 | fb_rotate_logo_ccw(image->data, dst, image->width, | ||
378 | image->height); | ||
379 | } | ||
380 | |||
381 | image->data = dst; | ||
382 | } | ||
383 | |||
384 | static void fb_do_show_logo(struct fb_info *info, struct fb_image *image, | ||
385 | int rotate) | ||
386 | { | ||
387 | int x; | ||
388 | |||
389 | if (rotate == FB_ROTATE_UR) { | ||
390 | for (x = 0; x < num_online_cpus() && | ||
391 | x * (fb_logo.logo->width + 8) <= | ||
392 | info->var.xres - fb_logo.logo->width; x++) { | ||
393 | info->fbops->fb_imageblit(info, image); | ||
394 | image->dx += fb_logo.logo->width + 8; | ||
395 | } | ||
396 | } else if (rotate == FB_ROTATE_UD) { | ||
397 | for (x = 0; x < num_online_cpus() && | ||
398 | x * (fb_logo.logo->width + 8) <= | ||
399 | info->var.xres - fb_logo.logo->width; x++) { | ||
400 | info->fbops->fb_imageblit(info, image); | ||
401 | image->dx -= fb_logo.logo->width + 8; | ||
402 | } | ||
403 | } else if (rotate == FB_ROTATE_CW) { | ||
404 | for (x = 0; x < num_online_cpus() && | ||
405 | x * (fb_logo.logo->width + 8) <= | ||
406 | info->var.yres - fb_logo.logo->width; x++) { | ||
407 | info->fbops->fb_imageblit(info, image); | ||
408 | image->dy += fb_logo.logo->width + 8; | ||
409 | } | ||
410 | } else if (rotate == FB_ROTATE_CCW) { | ||
411 | for (x = 0; x < num_online_cpus() && | ||
412 | x * (fb_logo.logo->width + 8) <= | ||
413 | info->var.yres - fb_logo.logo->width; x++) { | ||
414 | info->fbops->fb_imageblit(info, image); | ||
415 | image->dy -= fb_logo.logo->width + 8; | ||
416 | } | ||
417 | } | ||
418 | } | ||
419 | |||
420 | int fb_prepare_logo(struct fb_info *info, int rotate) | ||
327 | { | 421 | { |
328 | int depth = fb_get_color_depth(&info->var, &info->fix); | 422 | int depth = fb_get_color_depth(&info->var, &info->fix); |
423 | int yres; | ||
329 | 424 | ||
330 | memset(&fb_logo, 0, sizeof(struct logo_data)); | 425 | memset(&fb_logo, 0, sizeof(struct logo_data)); |
331 | 426 | ||
@@ -358,10 +453,16 @@ int fb_prepare_logo(struct fb_info *info) | |||
358 | /* Return if no suitable logo was found */ | 453 | /* Return if no suitable logo was found */ |
359 | fb_logo.logo = fb_find_logo(depth); | 454 | fb_logo.logo = fb_find_logo(depth); |
360 | 455 | ||
361 | if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) { | 456 | if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD) |
457 | yres = info->var.yres; | ||
458 | else | ||
459 | yres = info->var.xres; | ||
460 | |||
461 | if (fb_logo.logo && fb_logo.logo->height > yres) { | ||
362 | fb_logo.logo = NULL; | 462 | fb_logo.logo = NULL; |
363 | return 0; | 463 | return 0; |
364 | } | 464 | } |
465 | |||
365 | /* What depth we asked for might be different from what we get */ | 466 | /* What depth we asked for might be different from what we get */ |
366 | if (fb_logo.logo->type == LINUX_LOGO_CLUT224) | 467 | if (fb_logo.logo->type == LINUX_LOGO_CLUT224) |
367 | fb_logo.depth = 8; | 468 | fb_logo.depth = 8; |
@@ -372,12 +473,11 @@ int fb_prepare_logo(struct fb_info *info) | |||
372 | return fb_logo.logo->height; | 473 | return fb_logo.logo->height; |
373 | } | 474 | } |
374 | 475 | ||
375 | int fb_show_logo(struct fb_info *info) | 476 | int fb_show_logo(struct fb_info *info, int rotate) |
376 | { | 477 | { |
377 | u32 *palette = NULL, *saved_pseudo_palette = NULL; | 478 | u32 *palette = NULL, *saved_pseudo_palette = NULL; |
378 | unsigned char *logo_new = NULL; | 479 | unsigned char *logo_new = NULL, *logo_rotate = NULL; |
379 | struct fb_image image; | 480 | struct fb_image image; |
380 | int x; | ||
381 | 481 | ||
382 | /* Return if the frame buffer is not mapped or suspended */ | 482 | /* Return if the frame buffer is not mapped or suspended */ |
383 | if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING) | 483 | if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING) |
@@ -417,25 +517,30 @@ int fb_show_logo(struct fb_info *info) | |||
417 | fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth); | 517 | fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth); |
418 | } | 518 | } |
419 | 519 | ||
520 | image.dx = 0; | ||
521 | image.dy = 0; | ||
420 | image.width = fb_logo.logo->width; | 522 | image.width = fb_logo.logo->width; |
421 | image.height = fb_logo.logo->height; | 523 | image.height = fb_logo.logo->height; |
422 | image.dy = 0; | ||
423 | 524 | ||
424 | for (x = 0; x < num_online_cpus() * (fb_logo.logo->width + 8) && | 525 | if (rotate) { |
425 | x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) { | 526 | logo_rotate = kmalloc(fb_logo.logo->width * |
426 | image.dx = x; | 527 | fb_logo.logo->height, GFP_KERNEL); |
427 | info->fbops->fb_imageblit(info, &image); | 528 | if (logo_rotate) |
529 | fb_rotate_logo(info, logo_rotate, &image, rotate); | ||
428 | } | 530 | } |
429 | 531 | ||
532 | fb_do_show_logo(info, &image, rotate); | ||
533 | |||
430 | kfree(palette); | 534 | kfree(palette); |
431 | if (saved_pseudo_palette != NULL) | 535 | if (saved_pseudo_palette != NULL) |
432 | info->pseudo_palette = saved_pseudo_palette; | 536 | info->pseudo_palette = saved_pseudo_palette; |
433 | kfree(logo_new); | 537 | kfree(logo_new); |
538 | kfree(logo_rotate); | ||
434 | return fb_logo.logo->height; | 539 | return fb_logo.logo->height; |
435 | } | 540 | } |
436 | #else | 541 | #else |
437 | int fb_prepare_logo(struct fb_info *info) { return 0; } | 542 | int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } |
438 | int fb_show_logo(struct fb_info *info) { return 0; } | 543 | int fb_show_logo(struct fb_info *info, int rotate) { return 0; } |
439 | #endif /* CONFIG_LOGO */ | 544 | #endif /* CONFIG_LOGO */ |
440 | 545 | ||
441 | static int fbmem_read_proc(char *buf, char **start, off_t offset, | 546 | static int fbmem_read_proc(char *buf, char **start, off_t offset, |
@@ -829,18 +934,154 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
829 | } | 934 | } |
830 | 935 | ||
831 | #ifdef CONFIG_COMPAT | 936 | #ifdef CONFIG_COMPAT |
937 | struct fb_fix_screeninfo32 { | ||
938 | char id[16]; | ||
939 | compat_caddr_t smem_start; | ||
940 | u32 smem_len; | ||
941 | u32 type; | ||
942 | u32 type_aux; | ||
943 | u32 visual; | ||
944 | u16 xpanstep; | ||
945 | u16 ypanstep; | ||
946 | u16 ywrapstep; | ||
947 | u32 line_length; | ||
948 | compat_caddr_t mmio_start; | ||
949 | u32 mmio_len; | ||
950 | u32 accel; | ||
951 | u16 reserved[3]; | ||
952 | }; | ||
953 | |||
954 | struct fb_cmap32 { | ||
955 | u32 start; | ||
956 | u32 len; | ||
957 | compat_caddr_t red; | ||
958 | compat_caddr_t green; | ||
959 | compat_caddr_t blue; | ||
960 | compat_caddr_t transp; | ||
961 | }; | ||
962 | |||
963 | static int fb_getput_cmap(struct inode *inode, struct file *file, | ||
964 | unsigned int cmd, unsigned long arg) | ||
965 | { | ||
966 | struct fb_cmap_user __user *cmap; | ||
967 | struct fb_cmap32 __user *cmap32; | ||
968 | __u32 data; | ||
969 | int err; | ||
970 | |||
971 | cmap = compat_alloc_user_space(sizeof(*cmap)); | ||
972 | cmap32 = compat_ptr(arg); | ||
973 | |||
974 | if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32))) | ||
975 | return -EFAULT; | ||
976 | |||
977 | if (get_user(data, &cmap32->red) || | ||
978 | put_user(compat_ptr(data), &cmap->red) || | ||
979 | get_user(data, &cmap32->green) || | ||
980 | put_user(compat_ptr(data), &cmap->green) || | ||
981 | get_user(data, &cmap32->blue) || | ||
982 | put_user(compat_ptr(data), &cmap->blue) || | ||
983 | get_user(data, &cmap32->transp) || | ||
984 | put_user(compat_ptr(data), &cmap->transp)) | ||
985 | return -EFAULT; | ||
986 | |||
987 | err = fb_ioctl(inode, file, cmd, (unsigned long) cmap); | ||
988 | |||
989 | if (!err) { | ||
990 | if (copy_in_user(&cmap32->start, | ||
991 | &cmap->start, | ||
992 | 2 * sizeof(__u32))) | ||
993 | err = -EFAULT; | ||
994 | } | ||
995 | return err; | ||
996 | } | ||
997 | |||
998 | static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix, | ||
999 | struct fb_fix_screeninfo32 __user *fix32) | ||
1000 | { | ||
1001 | __u32 data; | ||
1002 | int err; | ||
1003 | |||
1004 | err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id)); | ||
1005 | |||
1006 | data = (__u32) (unsigned long) fix->smem_start; | ||
1007 | err |= put_user(data, &fix32->smem_start); | ||
1008 | |||
1009 | err |= put_user(fix->smem_len, &fix32->smem_len); | ||
1010 | err |= put_user(fix->type, &fix32->type); | ||
1011 | err |= put_user(fix->type_aux, &fix32->type_aux); | ||
1012 | err |= put_user(fix->visual, &fix32->visual); | ||
1013 | err |= put_user(fix->xpanstep, &fix32->xpanstep); | ||
1014 | err |= put_user(fix->ypanstep, &fix32->ypanstep); | ||
1015 | err |= put_user(fix->ywrapstep, &fix32->ywrapstep); | ||
1016 | err |= put_user(fix->line_length, &fix32->line_length); | ||
1017 | |||
1018 | data = (__u32) (unsigned long) fix->mmio_start; | ||
1019 | err |= put_user(data, &fix32->mmio_start); | ||
1020 | |||
1021 | err |= put_user(fix->mmio_len, &fix32->mmio_len); | ||
1022 | err |= put_user(fix->accel, &fix32->accel); | ||
1023 | err |= copy_to_user(fix32->reserved, fix->reserved, | ||
1024 | sizeof(fix->reserved)); | ||
1025 | |||
1026 | return err; | ||
1027 | } | ||
1028 | |||
1029 | static int fb_get_fscreeninfo(struct inode *inode, struct file *file, | ||
1030 | unsigned int cmd, unsigned long arg) | ||
1031 | { | ||
1032 | mm_segment_t old_fs; | ||
1033 | struct fb_fix_screeninfo fix; | ||
1034 | struct fb_fix_screeninfo32 __user *fix32; | ||
1035 | int err; | ||
1036 | |||
1037 | fix32 = compat_ptr(arg); | ||
1038 | |||
1039 | old_fs = get_fs(); | ||
1040 | set_fs(KERNEL_DS); | ||
1041 | err = fb_ioctl(inode, file, cmd, (unsigned long) &fix); | ||
1042 | set_fs(old_fs); | ||
1043 | |||
1044 | if (!err) | ||
1045 | err = do_fscreeninfo_to_user(&fix, fix32); | ||
1046 | |||
1047 | return err; | ||
1048 | } | ||
1049 | |||
832 | static long | 1050 | static long |
833 | fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 1051 | fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
834 | { | 1052 | { |
835 | int fbidx = iminor(file->f_dentry->d_inode); | 1053 | struct inode *inode = file->f_dentry->d_inode; |
1054 | int fbidx = iminor(inode); | ||
836 | struct fb_info *info = registered_fb[fbidx]; | 1055 | struct fb_info *info = registered_fb[fbidx]; |
837 | struct fb_ops *fb = info->fbops; | 1056 | struct fb_ops *fb = info->fbops; |
838 | long ret; | 1057 | long ret = -ENOIOCTLCMD; |
839 | 1058 | ||
840 | if (fb->fb_compat_ioctl == NULL) | ||
841 | return -ENOIOCTLCMD; | ||
842 | lock_kernel(); | 1059 | lock_kernel(); |
843 | ret = fb->fb_compat_ioctl(file, cmd, arg, info); | 1060 | switch(cmd) { |
1061 | case FBIOGET_VSCREENINFO: | ||
1062 | case FBIOPUT_VSCREENINFO: | ||
1063 | case FBIOPAN_DISPLAY: | ||
1064 | case FBIOGET_CON2FBMAP: | ||
1065 | case FBIOPUT_CON2FBMAP: | ||
1066 | arg = (unsigned long) compat_ptr(arg); | ||
1067 | case FBIOBLANK: | ||
1068 | ret = fb_ioctl(inode, file, cmd, arg); | ||
1069 | break; | ||
1070 | |||
1071 | case FBIOGET_FSCREENINFO: | ||
1072 | ret = fb_get_fscreeninfo(inode, file, cmd, arg); | ||
1073 | break; | ||
1074 | |||
1075 | case FBIOGETCMAP: | ||
1076 | case FBIOPUTCMAP: | ||
1077 | ret = fb_getput_cmap(inode, file, cmd, arg); | ||
1078 | break; | ||
1079 | |||
1080 | default: | ||
1081 | if (fb->fb_compat_ioctl) | ||
1082 | ret = fb->fb_compat_ioctl(file, cmd, arg, info); | ||
1083 | break; | ||
1084 | } | ||
844 | unlock_kernel(); | 1085 | unlock_kernel(); |
845 | return ret; | 1086 | return ret; |
846 | } | 1087 | } |
@@ -1215,6 +1456,28 @@ int fb_new_modelist(struct fb_info *info) | |||
1215 | return err; | 1456 | return err; |
1216 | } | 1457 | } |
1217 | 1458 | ||
1459 | /** | ||
1460 | * fb_con_duit - user<->fbcon passthrough | ||
1461 | * @info: struct fb_info | ||
1462 | * @event: notification event to be passed to fbcon | ||
1463 | * @data: private data | ||
1464 | * | ||
1465 | * DESCRIPTION | ||
1466 | * This function is an fbcon-user event passing channel | ||
1467 | * which bypasses fbdev. This is hopefully temporary | ||
1468 | * until a user interface for fbcon is created | ||
1469 | */ | ||
1470 | int fb_con_duit(struct fb_info *info, int event, void *data) | ||
1471 | { | ||
1472 | struct fb_event evnt; | ||
1473 | |||
1474 | evnt.info = info; | ||
1475 | evnt.data = data; | ||
1476 | |||
1477 | return notifier_call_chain(&fb_notifier_list, event, &evnt); | ||
1478 | } | ||
1479 | EXPORT_SYMBOL(fb_con_duit); | ||
1480 | |||
1218 | static char *video_options[FB_MAX]; | 1481 | static char *video_options[FB_MAX]; |
1219 | static int ofonly; | 1482 | static int ofonly; |
1220 | 1483 | ||
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 007c8e9b2b39..08dac9580d15 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c | |||
@@ -213,6 +213,70 @@ static ssize_t show_bpp(struct class_device *class_device, char *buf) | |||
213 | return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel); | 213 | return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel); |
214 | } | 214 | } |
215 | 215 | ||
216 | static ssize_t store_rotate(struct class_device *class_device, const char *buf, | ||
217 | size_t count) | ||
218 | { | ||
219 | struct fb_info *fb_info = class_get_devdata(class_device); | ||
220 | struct fb_var_screeninfo var; | ||
221 | char **last = NULL; | ||
222 | int err; | ||
223 | |||
224 | var = fb_info->var; | ||
225 | var.rotate = simple_strtoul(buf, last, 0); | ||
226 | |||
227 | if ((err = activate(fb_info, &var))) | ||
228 | return err; | ||
229 | |||
230 | return count; | ||
231 | } | ||
232 | |||
233 | |||
234 | static ssize_t show_rotate(struct class_device *class_device, char *buf) | ||
235 | { | ||
236 | struct fb_info *fb_info = class_get_devdata(class_device); | ||
237 | |||
238 | return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate); | ||
239 | } | ||
240 | |||
241 | static ssize_t store_con_rotate(struct class_device *class_device, | ||
242 | const char *buf, size_t count) | ||
243 | { | ||
244 | struct fb_info *fb_info = class_get_devdata(class_device); | ||
245 | int rotate; | ||
246 | char **last = NULL; | ||
247 | |||
248 | acquire_console_sem(); | ||
249 | rotate = simple_strtoul(buf, last, 0); | ||
250 | fb_con_duit(fb_info, FB_EVENT_SET_CON_ROTATE, &rotate); | ||
251 | release_console_sem(); | ||
252 | return count; | ||
253 | } | ||
254 | |||
255 | static ssize_t store_con_rotate_all(struct class_device *class_device, | ||
256 | const char *buf, size_t count) | ||
257 | { | ||
258 | struct fb_info *fb_info = class_get_devdata(class_device); | ||
259 | int rotate; | ||
260 | char **last = NULL; | ||
261 | |||
262 | acquire_console_sem(); | ||
263 | rotate = simple_strtoul(buf, last, 0); | ||
264 | fb_con_duit(fb_info, FB_EVENT_SET_CON_ROTATE_ALL, &rotate); | ||
265 | release_console_sem(); | ||
266 | return count; | ||
267 | } | ||
268 | |||
269 | static ssize_t show_con_rotate(struct class_device *class_device, char *buf) | ||
270 | { | ||
271 | struct fb_info *fb_info = class_get_devdata(class_device); | ||
272 | int rotate; | ||
273 | |||
274 | acquire_console_sem(); | ||
275 | rotate = fb_con_duit(fb_info, FB_EVENT_GET_CON_ROTATE, NULL); | ||
276 | release_console_sem(); | ||
277 | return snprintf(buf, PAGE_SIZE, "%d\n", rotate); | ||
278 | } | ||
279 | |||
216 | static ssize_t store_virtual(struct class_device *class_device, | 280 | static ssize_t store_virtual(struct class_device *class_device, |
217 | const char * buf, size_t count) | 281 | const char * buf, size_t count) |
218 | { | 282 | { |
@@ -440,6 +504,9 @@ static struct class_device_attribute class_device_attrs[] = { | |||
440 | __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual), | 504 | __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual), |
441 | __ATTR(name, S_IRUGO, show_name, NULL), | 505 | __ATTR(name, S_IRUGO, show_name, NULL), |
442 | __ATTR(stride, S_IRUGO, show_stride, NULL), | 506 | __ATTR(stride, S_IRUGO, show_stride, NULL), |
507 | __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), | ||
508 | __ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate), | ||
509 | __ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all), | ||
443 | }; | 510 | }; |
444 | 511 | ||
445 | int fb_init_class_device(struct fb_info *fb_info) | 512 | int fb_init_class_device(struct fb_info *fb_info) |
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 0799b999b314..427689e584da 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c | |||
@@ -122,7 +122,6 @@ | |||
122 | #include <linux/pci.h> | 122 | #include <linux/pci.h> |
123 | #include <linux/vmalloc.h> | 123 | #include <linux/vmalloc.h> |
124 | #include <linux/pagemap.h> | 124 | #include <linux/pagemap.h> |
125 | #include <linux/version.h> | ||
126 | 125 | ||
127 | #include <asm/io.h> | 126 | #include <asm/io.h> |
128 | 127 | ||
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index ac94c2e5ff85..624c4bc96f0d 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c | |||
@@ -34,7 +34,6 @@ | |||
34 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
35 | #include <linux/vmalloc.h> | 35 | #include <linux/vmalloc.h> |
36 | #include <linux/pagemap.h> | 36 | #include <linux/pagemap.h> |
37 | #include <linux/version.h> | ||
38 | 37 | ||
39 | #include <asm/io.h> | 38 | #include <asm/io.h> |
40 | 39 | ||
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 1789a52d776a..1da2f84bdc25 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c | |||
@@ -251,6 +251,10 @@ static const struct fb_videomode modedb[] = { | |||
251 | NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3, | 251 | NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3, |
252 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | 252 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, |
253 | FB_VMODE_NONINTERLACED | 253 | FB_VMODE_NONINTERLACED |
254 | }, { | ||
255 | /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */ | ||
256 | NULL, 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6, | ||
257 | FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
254 | }, | 258 | }, |
255 | }; | 259 | }; |
256 | 260 | ||
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index f0dfb35e3191..09e2f2841901 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c | |||
@@ -1315,10 +1315,14 @@ static void savagefb_set_fix(struct fb_info *info) | |||
1315 | info->fix.line_length = info->var.xres_virtual * | 1315 | info->fix.line_length = info->var.xres_virtual * |
1316 | info->var.bits_per_pixel / 8; | 1316 | info->var.bits_per_pixel / 8; |
1317 | 1317 | ||
1318 | if (info->var.bits_per_pixel == 8) | 1318 | if (info->var.bits_per_pixel == 8) { |
1319 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | 1319 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; |
1320 | else | 1320 | info->fix.xpanstep = 4; |
1321 | } else { | ||
1321 | info->fix.visual = FB_VISUAL_TRUECOLOR; | 1322 | info->fix.visual = FB_VISUAL_TRUECOLOR; |
1323 | info->fix.xpanstep = 2; | ||
1324 | } | ||
1325 | |||
1322 | } | 1326 | } |
1323 | 1327 | ||
1324 | #if defined(CONFIG_FB_SAVAGE_ACCEL) | 1328 | #if defined(CONFIG_FB_SAVAGE_ACCEL) |
@@ -1363,7 +1367,6 @@ static int savagefb_set_par (struct fb_info *info) | |||
1363 | par->minClock = 10000; | 1367 | par->minClock = 10000; |
1364 | 1368 | ||
1365 | savagefb_set_par_int (par); | 1369 | savagefb_set_par_int (par); |
1366 | savagefb_update_start (par, var); | ||
1367 | fb_set_cmap (&info->cmap, info); | 1370 | fb_set_cmap (&info->cmap, info); |
1368 | savagefb_set_fix(info); | 1371 | savagefb_set_fix(info); |
1369 | savagefb_set_clip(info); | 1372 | savagefb_set_clip(info); |
@@ -1873,7 +1876,6 @@ static int __devinit savage_init_fb_info (struct fb_info *info, | |||
1873 | 1876 | ||
1874 | info->fix.type = FB_TYPE_PACKED_PIXELS; | 1877 | info->fix.type = FB_TYPE_PACKED_PIXELS; |
1875 | info->fix.type_aux = 0; | 1878 | info->fix.type_aux = 0; |
1876 | info->fix.xpanstep = 2; | ||
1877 | info->fix.ypanstep = 1; | 1879 | info->fix.ypanstep = 1; |
1878 | info->fix.ywrapstep = 0; | 1880 | info->fix.ywrapstep = 0; |
1879 | info->fix.accel = id->driver_data; | 1881 | info->fix.accel = id->driver_data; |
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index 690bb6fe8281..226ae8a88482 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/fb.h> | 21 | #include <linux/fb.h> |
22 | #include <linux/ioport.h> | 22 | #include <linux/ioport.h> |
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/platform_device.h> | ||
24 | 25 | ||
25 | #include <asm/io.h> | 26 | #include <asm/io.h> |
26 | #include <video/vga.h> | 27 | #include <video/vga.h> |
@@ -51,35 +52,33 @@ | |||
51 | * card parameters | 52 | * card parameters |
52 | */ | 53 | */ |
53 | 54 | ||
54 | static struct fb_info vga16fb; | 55 | struct vga16fb_par { |
55 | |||
56 | static struct vga16fb_par { | ||
57 | /* structure holding original VGA register settings when the | 56 | /* structure holding original VGA register settings when the |
58 | screen is blanked */ | 57 | screen is blanked */ |
59 | struct { | 58 | struct { |
60 | unsigned char SeqCtrlIndex; /* Sequencer Index reg. */ | 59 | unsigned char SeqCtrlIndex; /* Sequencer Index reg. */ |
61 | unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */ | 60 | unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */ |
62 | unsigned char CrtMiscIO; /* Miscellaneous register */ | 61 | unsigned char CrtMiscIO; /* Miscellaneous register */ |
63 | unsigned char HorizontalTotal; /* CRT-Controller:00h */ | 62 | unsigned char HorizontalTotal; /* CRT-Controller:00h */ |
64 | unsigned char HorizDisplayEnd; /* CRT-Controller:01h */ | 63 | unsigned char HorizDisplayEnd; /* CRT-Controller:01h */ |
65 | unsigned char StartHorizRetrace; /* CRT-Controller:04h */ | 64 | unsigned char StartHorizRetrace;/* CRT-Controller:04h */ |
66 | unsigned char EndHorizRetrace; /* CRT-Controller:05h */ | 65 | unsigned char EndHorizRetrace; /* CRT-Controller:05h */ |
67 | unsigned char Overflow; /* CRT-Controller:07h */ | 66 | unsigned char Overflow; /* CRT-Controller:07h */ |
68 | unsigned char StartVertRetrace; /* CRT-Controller:10h */ | 67 | unsigned char StartVertRetrace; /* CRT-Controller:10h */ |
69 | unsigned char EndVertRetrace; /* CRT-Controller:11h */ | 68 | unsigned char EndVertRetrace; /* CRT-Controller:11h */ |
70 | unsigned char ModeControl; /* CRT-Controller:17h */ | 69 | unsigned char ModeControl; /* CRT-Controller:17h */ |
71 | unsigned char ClockingMode; /* Seq-Controller:01h */ | 70 | unsigned char ClockingMode; /* Seq-Controller:01h */ |
72 | } vga_state; | 71 | } vga_state; |
73 | struct vgastate state; | 72 | struct vgastate state; |
74 | atomic_t ref_count; | 73 | atomic_t ref_count; |
75 | int palette_blanked, vesa_blanked, mode, isVGA; | 74 | int palette_blanked, vesa_blanked, mode, isVGA; |
76 | u8 misc, pel_msk, vss, clkdiv; | 75 | u8 misc, pel_msk, vss, clkdiv; |
77 | u8 crtc[VGA_CRT_C]; | 76 | u8 crtc[VGA_CRT_C]; |
78 | } vga16_par; | 77 | }; |
79 | 78 | ||
80 | /* --------------------------------------------------------------------- */ | 79 | /* --------------------------------------------------------------------- */ |
81 | 80 | ||
82 | static struct fb_var_screeninfo vga16fb_defined = { | 81 | static struct fb_var_screeninfo vga16fb_defined __initdata = { |
83 | .xres = 640, | 82 | .xres = 640, |
84 | .yres = 480, | 83 | .yres = 480, |
85 | .xres_virtual = 640, | 84 | .xres_virtual = 640, |
@@ -205,7 +204,7 @@ static inline void setindex(int index) | |||
205 | static void vga16fb_pan_var(struct fb_info *info, | 204 | static void vga16fb_pan_var(struct fb_info *info, |
206 | struct fb_var_screeninfo *var) | 205 | struct fb_var_screeninfo *var) |
207 | { | 206 | { |
208 | struct vga16fb_par *par = (struct vga16fb_par *) info->par; | 207 | struct vga16fb_par *par = info->par; |
209 | u32 xoffset, pos; | 208 | u32 xoffset, pos; |
210 | 209 | ||
211 | xoffset = var->xoffset; | 210 | xoffset = var->xoffset; |
@@ -300,7 +299,7 @@ static void vga16fb_clock_chip(struct vga16fb_par *par, | |||
300 | 299 | ||
301 | static int vga16fb_open(struct fb_info *info, int user) | 300 | static int vga16fb_open(struct fb_info *info, int user) |
302 | { | 301 | { |
303 | struct vga16fb_par *par = (struct vga16fb_par *) info->par; | 302 | struct vga16fb_par *par = info->par; |
304 | int cnt = atomic_read(&par->ref_count); | 303 | int cnt = atomic_read(&par->ref_count); |
305 | 304 | ||
306 | if (!cnt) { | 305 | if (!cnt) { |
@@ -315,7 +314,7 @@ static int vga16fb_open(struct fb_info *info, int user) | |||
315 | 314 | ||
316 | static int vga16fb_release(struct fb_info *info, int user) | 315 | static int vga16fb_release(struct fb_info *info, int user) |
317 | { | 316 | { |
318 | struct vga16fb_par *par = (struct vga16fb_par *) info->par; | 317 | struct vga16fb_par *par = info->par; |
319 | int cnt = atomic_read(&par->ref_count); | 318 | int cnt = atomic_read(&par->ref_count); |
320 | 319 | ||
321 | if (!cnt) | 320 | if (!cnt) |
@@ -330,7 +329,7 @@ static int vga16fb_release(struct fb_info *info, int user) | |||
330 | static int vga16fb_check_var(struct fb_var_screeninfo *var, | 329 | static int vga16fb_check_var(struct fb_var_screeninfo *var, |
331 | struct fb_info *info) | 330 | struct fb_info *info) |
332 | { | 331 | { |
333 | struct vga16fb_par *par = (struct vga16fb_par *) info->par; | 332 | struct vga16fb_par *par = info->par; |
334 | u32 xres, right, hslen, left, xtotal; | 333 | u32 xres, right, hslen, left, xtotal; |
335 | u32 yres, lower, vslen, upper, ytotal; | 334 | u32 yres, lower, vslen, upper, ytotal; |
336 | u32 vxres, xoffset, vyres, yoffset; | 335 | u32 vxres, xoffset, vyres, yoffset; |
@@ -535,7 +534,7 @@ static int vga16fb_check_var(struct fb_var_screeninfo *var, | |||
535 | 534 | ||
536 | static int vga16fb_set_par(struct fb_info *info) | 535 | static int vga16fb_set_par(struct fb_info *info) |
537 | { | 536 | { |
538 | struct vga16fb_par *par = (struct vga16fb_par *) info->par; | 537 | struct vga16fb_par *par = info->par; |
539 | u8 gdc[VGA_GFX_C]; | 538 | u8 gdc[VGA_GFX_C]; |
540 | u8 seq[VGA_SEQ_C]; | 539 | u8 seq[VGA_SEQ_C]; |
541 | u8 atc[VGA_ATT_C]; | 540 | u8 atc[VGA_ATT_C]; |
@@ -677,7 +676,7 @@ static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
677 | unsigned blue, unsigned transp, | 676 | unsigned blue, unsigned transp, |
678 | struct fb_info *info) | 677 | struct fb_info *info) |
679 | { | 678 | { |
680 | struct vga16fb_par *par = (struct vga16fb_par *) info->par; | 679 | struct vga16fb_par *par = info->par; |
681 | int gray; | 680 | int gray; |
682 | 681 | ||
683 | /* | 682 | /* |
@@ -850,7 +849,7 @@ static void vga_pal_blank(void) | |||
850 | /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ | 849 | /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ |
851 | static int vga16fb_blank(int blank, struct fb_info *info) | 850 | static int vga16fb_blank(int blank, struct fb_info *info) |
852 | { | 851 | { |
853 | struct vga16fb_par *par = (struct vga16fb_par *) info->par; | 852 | struct vga16fb_par *par = info->par; |
854 | 853 | ||
855 | switch (blank) { | 854 | switch (blank) { |
856 | case FB_BLANK_UNBLANK: /* Unblank */ | 855 | case FB_BLANK_UNBLANK: /* Unblank */ |
@@ -1201,7 +1200,7 @@ static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *im | |||
1201 | { | 1200 | { |
1202 | char __iomem *where = info->screen_base + (image->dx/8) + | 1201 | char __iomem *where = info->screen_base + (image->dx/8) + |
1203 | image->dy * info->fix.line_length; | 1202 | image->dy * info->fix.line_length; |
1204 | struct vga16fb_par *par = (struct vga16fb_par *) info->par; | 1203 | struct vga16fb_par *par = info->par; |
1205 | char *cdat = (char *) image->data; | 1204 | char *cdat = (char *) image->data; |
1206 | char __iomem *dst; | 1205 | char __iomem *dst; |
1207 | int x, y; | 1206 | int x, y; |
@@ -1266,7 +1265,7 @@ static void vga_imageblit_color(struct fb_info *info, const struct fb_image *ima | |||
1266 | /* | 1265 | /* |
1267 | * Draw logo | 1266 | * Draw logo |
1268 | */ | 1267 | */ |
1269 | struct vga16fb_par *par = (struct vga16fb_par *) info->par; | 1268 | struct vga16fb_par *par = info->par; |
1270 | char __iomem *where = | 1269 | char __iomem *where = |
1271 | info->screen_base + image->dy * info->fix.line_length + | 1270 | info->screen_base + image->dy * info->fix.line_length + |
1272 | image->dx/8; | 1271 | image->dx/8; |
@@ -1343,89 +1342,141 @@ static int vga16fb_setup(char *options) | |||
1343 | } | 1342 | } |
1344 | #endif | 1343 | #endif |
1345 | 1344 | ||
1346 | static int __init vga16fb_init(void) | 1345 | static int __init vga16fb_probe(struct device *device) |
1347 | { | 1346 | { |
1347 | struct platform_device *dev = to_platform_device(device); | ||
1348 | struct fb_info *info; | ||
1349 | struct vga16fb_par *par; | ||
1348 | int i; | 1350 | int i; |
1349 | int ret; | 1351 | int ret = 0; |
1350 | #ifndef MODULE | ||
1351 | char *option = NULL; | ||
1352 | 1352 | ||
1353 | if (fb_get_options("vga16fb", &option)) | ||
1354 | return -ENODEV; | ||
1355 | |||
1356 | vga16fb_setup(option); | ||
1357 | #endif | ||
1358 | printk(KERN_DEBUG "vga16fb: initializing\n"); | 1353 | printk(KERN_DEBUG "vga16fb: initializing\n"); |
1354 | info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev); | ||
1355 | |||
1356 | if (!info) { | ||
1357 | ret = -ENOMEM; | ||
1358 | goto err_fb_alloc; | ||
1359 | } | ||
1359 | 1360 | ||
1360 | /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ | 1361 | /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ |
1362 | info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS); | ||
1361 | 1363 | ||
1362 | vga16fb.screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS); | 1364 | if (!info->screen_base) { |
1363 | if (!vga16fb.screen_base) { | ||
1364 | printk(KERN_ERR "vga16fb: unable to map device\n"); | 1365 | printk(KERN_ERR "vga16fb: unable to map device\n"); |
1365 | ret = -ENOMEM; | 1366 | ret = -ENOMEM; |
1366 | goto err_ioremap; | 1367 | goto err_ioremap; |
1367 | } | 1368 | } |
1368 | printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.screen_base); | ||
1369 | 1369 | ||
1370 | vga16_par.isVGA = ORIG_VIDEO_ISVGA; | 1370 | printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base); |
1371 | vga16_par.palette_blanked = 0; | 1371 | par = info->par; |
1372 | vga16_par.vesa_blanked = 0; | ||
1373 | 1372 | ||
1374 | i = vga16_par.isVGA? 6 : 2; | 1373 | par->isVGA = ORIG_VIDEO_ISVGA; |
1374 | par->palette_blanked = 0; | ||
1375 | par->vesa_blanked = 0; | ||
1376 | |||
1377 | i = par->isVGA? 6 : 2; | ||
1375 | 1378 | ||
1376 | vga16fb_defined.red.length = i; | 1379 | vga16fb_defined.red.length = i; |
1377 | vga16fb_defined.green.length = i; | 1380 | vga16fb_defined.green.length = i; |
1378 | vga16fb_defined.blue.length = i; | 1381 | vga16fb_defined.blue.length = i; |
1379 | 1382 | ||
1380 | /* name should not depend on EGA/VGA */ | 1383 | /* name should not depend on EGA/VGA */ |
1381 | vga16fb.fbops = &vga16fb_ops; | 1384 | info->fbops = &vga16fb_ops; |
1382 | vga16fb.var = vga16fb_defined; | 1385 | info->var = vga16fb_defined; |
1383 | vga16fb.fix = vga16fb_fix; | 1386 | info->fix = vga16fb_fix; |
1384 | vga16fb.par = &vga16_par; | 1387 | info->flags = FBINFO_FLAG_DEFAULT | |
1385 | vga16fb.flags = FBINFO_FLAG_DEFAULT | | ||
1386 | FBINFO_HWACCEL_YPAN; | 1388 | FBINFO_HWACCEL_YPAN; |
1387 | 1389 | ||
1388 | i = (vga16fb_defined.bits_per_pixel == 8) ? 256 : 16; | 1390 | i = (info->var.bits_per_pixel == 8) ? 256 : 16; |
1389 | ret = fb_alloc_cmap(&vga16fb.cmap, i, 0); | 1391 | ret = fb_alloc_cmap(&info->cmap, i, 0); |
1390 | if (ret) { | 1392 | if (ret) { |
1391 | printk(KERN_ERR "vga16fb: unable to allocate colormap\n"); | 1393 | printk(KERN_ERR "vga16fb: unable to allocate colormap\n"); |
1392 | ret = -ENOMEM; | 1394 | ret = -ENOMEM; |
1393 | goto err_alloc_cmap; | 1395 | goto err_alloc_cmap; |
1394 | } | 1396 | } |
1395 | 1397 | ||
1396 | if (vga16fb_check_var(&vga16fb.var, &vga16fb)) { | 1398 | if (vga16fb_check_var(&info->var, info)) { |
1397 | printk(KERN_ERR "vga16fb: unable to validate variable\n"); | 1399 | printk(KERN_ERR "vga16fb: unable to validate variable\n"); |
1398 | ret = -EINVAL; | 1400 | ret = -EINVAL; |
1399 | goto err_check_var; | 1401 | goto err_check_var; |
1400 | } | 1402 | } |
1401 | 1403 | ||
1402 | vga16fb_update_fix(&vga16fb); | 1404 | vga16fb_update_fix(info); |
1403 | 1405 | ||
1404 | if (register_framebuffer(&vga16fb) < 0) { | 1406 | if (register_framebuffer(info) < 0) { |
1405 | printk(KERN_ERR "vga16fb: unable to register framebuffer\n"); | 1407 | printk(KERN_ERR "vga16fb: unable to register framebuffer\n"); |
1406 | ret = -EINVAL; | 1408 | ret = -EINVAL; |
1407 | goto err_check_var; | 1409 | goto err_check_var; |
1408 | } | 1410 | } |
1409 | 1411 | ||
1410 | printk(KERN_INFO "fb%d: %s frame buffer device\n", | 1412 | printk(KERN_INFO "fb%d: %s frame buffer device\n", |
1411 | vga16fb.node, vga16fb.fix.id); | 1413 | info->node, info->fix.id); |
1414 | dev_set_drvdata(device, info); | ||
1412 | 1415 | ||
1413 | return 0; | 1416 | return 0; |
1414 | 1417 | ||
1415 | err_check_var: | 1418 | err_check_var: |
1416 | fb_dealloc_cmap(&vga16fb.cmap); | 1419 | fb_dealloc_cmap(&info->cmap); |
1417 | err_alloc_cmap: | 1420 | err_alloc_cmap: |
1418 | iounmap(vga16fb.screen_base); | 1421 | iounmap(info->screen_base); |
1419 | err_ioremap: | 1422 | err_ioremap: |
1423 | framebuffer_release(info); | ||
1424 | err_fb_alloc: | ||
1425 | return ret; | ||
1426 | } | ||
1427 | |||
1428 | static int vga16fb_remove(struct device *device) | ||
1429 | { | ||
1430 | struct fb_info *info = dev_get_drvdata(device); | ||
1431 | |||
1432 | if (info) { | ||
1433 | unregister_framebuffer(info); | ||
1434 | iounmap(info->screen_base); | ||
1435 | fb_dealloc_cmap(&info->cmap); | ||
1436 | /* XXX unshare VGA regions */ | ||
1437 | framebuffer_release(info); | ||
1438 | } | ||
1439 | |||
1440 | return 0; | ||
1441 | } | ||
1442 | |||
1443 | static struct device_driver vga16fb_driver = { | ||
1444 | .name = "vga16fb", | ||
1445 | .bus = &platform_bus_type, | ||
1446 | .probe = vga16fb_probe, | ||
1447 | .remove = vga16fb_remove, | ||
1448 | }; | ||
1449 | |||
1450 | static struct platform_device vga16fb_device = { | ||
1451 | .name = "vga16fb", | ||
1452 | }; | ||
1453 | |||
1454 | static int __init vga16fb_init(void) | ||
1455 | { | ||
1456 | int ret; | ||
1457 | #ifndef MODULE | ||
1458 | char *option = NULL; | ||
1459 | |||
1460 | if (fb_get_options("vga16fb", &option)) | ||
1461 | return -ENODEV; | ||
1462 | |||
1463 | vga16fb_setup(option); | ||
1464 | #endif | ||
1465 | ret = driver_register(&vga16fb_driver); | ||
1466 | |||
1467 | if (!ret) { | ||
1468 | ret = platform_device_register(&vga16fb_device); | ||
1469 | if (ret) | ||
1470 | driver_unregister(&vga16fb_driver); | ||
1471 | } | ||
1472 | |||
1420 | return ret; | 1473 | return ret; |
1421 | } | 1474 | } |
1422 | 1475 | ||
1423 | static void __exit vga16fb_exit(void) | 1476 | static void __exit vga16fb_exit(void) |
1424 | { | 1477 | { |
1425 | unregister_framebuffer(&vga16fb); | 1478 | platform_device_unregister(&vga16fb_device); |
1426 | iounmap(vga16fb.screen_base); | 1479 | driver_unregister(&vga16fb_driver); |
1427 | fb_dealloc_cmap(&vga16fb.cmap); | ||
1428 | /* XXX unshare VGA regions */ | ||
1429 | } | 1480 | } |
1430 | 1481 | ||
1431 | MODULE_LICENSE("GPL"); | 1482 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/vgastate.c b/drivers/video/vgastate.c index ca92940f3943..d9e01daee630 100644 --- a/drivers/video/vgastate.c +++ b/drivers/video/vgastate.c | |||
@@ -485,11 +485,6 @@ int restore_vga (struct vgastate *state) | |||
485 | return 0; | 485 | return 0; |
486 | } | 486 | } |
487 | 487 | ||
488 | #ifdef MODULE | ||
489 | int init_module(void) { return 0; }; | ||
490 | void cleanup_module(void) {}; | ||
491 | #endif | ||
492 | |||
493 | EXPORT_SYMBOL(save_vga); | 488 | EXPORT_SYMBOL(save_vga); |
494 | EXPORT_SYMBOL(restore_vga); | 489 | EXPORT_SYMBOL(restore_vga); |
495 | 490 | ||