2 * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver
4 * Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz>
5 * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
6 * Based on VESA framebuffer (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file COPYING in the main directory of this
10 * archive for more details.
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/string.h>
18 #include <linux/delay.h>
20 #include <linux/ioport.h>
21 #include <linux/init.h>
22 #include <linux/platform_device.h>
23 #include <linux/screen_info.h>
26 #include <video/vga.h>
28 #define VGA_FB_PHYS 0xA0000
29 #define VGA_FB_PHYS_LEN 65536
36 /* --------------------------------------------------------------------- */
43 /* structure holding original VGA register settings when the
46 unsigned char SeqCtrlIndex
; /* Sequencer Index reg. */
47 unsigned char CrtCtrlIndex
; /* CRT-Contr. Index reg. */
48 unsigned char CrtMiscIO
; /* Miscellaneous register */
49 unsigned char HorizontalTotal
; /* CRT-Controller:00h */
50 unsigned char HorizDisplayEnd
; /* CRT-Controller:01h */
51 unsigned char StartHorizRetrace
;/* CRT-Controller:04h */
52 unsigned char EndHorizRetrace
; /* CRT-Controller:05h */
53 unsigned char Overflow
; /* CRT-Controller:07h */
54 unsigned char StartVertRetrace
; /* CRT-Controller:10h */
55 unsigned char EndVertRetrace
; /* CRT-Controller:11h */
56 unsigned char ModeControl
; /* CRT-Controller:17h */
57 unsigned char ClockingMode
; /* Seq-Controller:01h */
59 struct vgastate state
;
60 unsigned int ref_count
;
61 int palette_blanked
, vesa_blanked
, mode
, isVGA
;
62 u8 misc
, pel_msk
, vss
, clkdiv
;
66 /* --------------------------------------------------------------------- */
68 static struct fb_var_screeninfo vga16fb_defined __initdata
= {
74 .activate
= FB_ACTIVATE_TEST
,
84 .vmode
= FB_VMODE_NONINTERLACED
,
87 /* name should not depend on EGA/VGA */
88 static struct fb_fix_screeninfo vga16fb_fix __initdata
= {
90 .smem_start
= VGA_FB_PHYS
,
91 .smem_len
= VGA_FB_PHYS_LEN
,
92 .type
= FB_TYPE_VGA_PLANES
,
93 .type_aux
= FB_AUX_VGA_PLANES_VGA4
,
94 .visual
= FB_VISUAL_PSEUDOCOLOR
,
97 .line_length
= 640 / 8,
98 .accel
= FB_ACCEL_NONE
101 /* The VGA's weird architecture often requires that we read a byte and
102 write a byte to the same location. It doesn't matter *what* byte
103 we write, however. This is because all the action goes on behind
104 the scenes in the VGA's 32-bit latch register, and reading and writing
105 video memory just invokes latch behavior.
107 To avoid race conditions (is this necessary?), reading and writing
108 the memory byte should be done with a single instruction. One
109 suitable instruction is the x86 bitwise OR. The following
110 read-modify-write routine should optimize to one such bitwise
112 static inline void rmw(volatile char __iomem
*p
)
118 /* Set the Graphics Mode Register, and return its previous value.
119 Bits 0-1 are write mode, bit 3 is read mode. */
120 static inline int setmode(int mode
)
124 oldmode
= vga_io_rgfx(VGA_GFX_MODE
);
125 vga_io_w(VGA_GFX_D
, mode
);
129 /* Select the Bit Mask Register and return its value. */
130 static inline int selectmask(void)
132 return vga_io_rgfx(VGA_GFX_BIT_MASK
);
135 /* Set the value of the Bit Mask Register. It must already have been
136 selected with selectmask(). */
137 static inline void setmask(int mask
)
139 vga_io_w(VGA_GFX_D
, mask
);
142 /* Set the Data Rotate Register and return its old value.
143 Bits 0-2 are rotate count, bits 3-4 are logical operation
144 (0=NOP, 1=AND, 2=OR, 3=XOR). */
145 static inline int setop(int op
)
149 oldop
= vga_io_rgfx(VGA_GFX_DATA_ROTATE
);
150 vga_io_w(VGA_GFX_D
, op
);
154 /* Set the Enable Set/Reset Register and return its old value.
155 The code here always uses value 0xf for thsi register. */
156 static inline int setsr(int sr
)
160 oldsr
= vga_io_rgfx(VGA_GFX_SR_ENABLE
);
161 vga_io_w(VGA_GFX_D
, sr
);
165 /* Set the Set/Reset Register and return its old value. */
166 static inline int setcolor(int color
)
170 oldcolor
= vga_io_rgfx(VGA_GFX_SR_VALUE
);
171 vga_io_w(VGA_GFX_D
, color
);
175 /* Return the value in the Graphics Address Register. */
176 static inline int getindex(void)
178 return vga_io_r(VGA_GFX_I
);
181 /* Set the value in the Graphics Address Register. */
182 static inline void setindex(int index
)
184 vga_io_w(VGA_GFX_I
, index
);
187 static void vga16fb_pan_var(struct fb_info
*info
,
188 struct fb_var_screeninfo
*var
)
190 struct vga16fb_par
*par
= info
->par
;
193 xoffset
= var
->xoffset
;
194 if (info
->var
.bits_per_pixel
== 8) {
195 pos
= (info
->var
.xres_virtual
* var
->yoffset
+ xoffset
) >> 2;
196 } else if (par
->mode
& MODE_TEXT
) {
197 int fh
= 16; // FIXME !!! font height. Fugde for now.
198 pos
= (info
->var
.xres_virtual
* (var
->yoffset
/ fh
) + xoffset
) >> 3;
200 if (info
->var
.nonstd
)
202 pos
= (info
->var
.xres_virtual
* var
->yoffset
+ xoffset
) >> 3;
204 vga_io_wcrt(VGA_CRTC_START_HI
, pos
>> 8);
205 vga_io_wcrt(VGA_CRTC_START_LO
, pos
& 0xFF);
206 /* if we support CFB4, then we must! support xoffset with pixel
207 * granularity if someone supports xoffset in bit resolution */
208 vga_io_r(VGA_IS1_RC
); /* reset flip-flop */
209 vga_io_w(VGA_ATT_IW
, VGA_ATC_PEL
);
210 if (var
->bits_per_pixel
== 8)
211 vga_io_w(VGA_ATT_IW
, (xoffset
& 3) << 1);
213 vga_io_w(VGA_ATT_IW
, xoffset
& 7);
214 vga_io_r(VGA_IS1_RC
);
215 vga_io_w(VGA_ATT_IW
, 0x20);
218 static void vga16fb_update_fix(struct fb_info
*info
)
220 if (info
->var
.bits_per_pixel
== 4) {
221 if (info
->var
.nonstd
) {
222 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
223 info
->fix
.line_length
= info
->var
.xres_virtual
/ 2;
225 info
->fix
.type
= FB_TYPE_VGA_PLANES
;
226 info
->fix
.type_aux
= FB_AUX_VGA_PLANES_VGA4
;
227 info
->fix
.line_length
= info
->var
.xres_virtual
/ 8;
229 } else if (info
->var
.bits_per_pixel
== 0) {
230 info
->fix
.type
= FB_TYPE_TEXT
;
231 info
->fix
.type_aux
= FB_AUX_TEXT_CGA
;
232 info
->fix
.line_length
= info
->var
.xres_virtual
/ 4;
234 if (info
->var
.nonstd
) {
235 info
->fix
.type
= FB_TYPE_VGA_PLANES
;
236 info
->fix
.type_aux
= FB_AUX_VGA_PLANES_CFB8
;
237 info
->fix
.line_length
= info
->var
.xres_virtual
/ 4;
239 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
240 info
->fix
.line_length
= info
->var
.xres_virtual
;
245 static void vga16fb_clock_chip(struct vga16fb_par
*par
,
246 unsigned int pixclock
,
247 const struct fb_info
*info
,
250 static const struct {
254 } *ptr
, *best
, vgaclocks
[] = {
255 { 79442 /* 12.587 */, 0x00, 0x08},
256 { 70616 /* 14.161 */, 0x04, 0x08},
257 { 39721 /* 25.175 */, 0x00, 0x00},
258 { 35308 /* 28.322 */, 0x04, 0x00},
259 { 0 /* bad */, 0x00, 0x00}};
262 pixclock
= (pixclock
* mul
) / div
;
264 err
= pixclock
- best
->pixclock
;
265 if (err
< 0) err
= -err
;
266 for (ptr
= vgaclocks
+ 1; ptr
->pixclock
; ptr
++) {
269 tmp
= pixclock
- ptr
->pixclock
;
270 if (tmp
< 0) tmp
= -tmp
;
276 par
->misc
|= best
->misc
;
277 par
->clkdiv
= best
->seq_clock_mode
;
278 pixclock
= (best
->pixclock
* div
) / mul
;
281 #define FAIL(X) return -EINVAL
283 static int vga16fb_open(struct fb_info
*info
, int user
)
285 struct vga16fb_par
*par
= info
->par
;
287 if (!par
->ref_count
) {
288 memset(&par
->state
, 0, sizeof(struct vgastate
));
289 par
->state
.flags
= VGA_SAVE_FONTS
| VGA_SAVE_MODE
|
291 save_vga(&par
->state
);
298 static int vga16fb_release(struct fb_info
*info
, int user
)
300 struct vga16fb_par
*par
= info
->par
;
305 if (par
->ref_count
== 1)
306 restore_vga(&par
->state
);
312 static int vga16fb_check_var(struct fb_var_screeninfo
*var
,
313 struct fb_info
*info
)
315 struct vga16fb_par
*par
= info
->par
;
316 u32 xres
, right
, hslen
, left
, xtotal
;
317 u32 yres
, lower
, vslen
, upper
, ytotal
;
318 u32 vxres
, xoffset
, vyres
, yoffset
;
327 if (var
->bits_per_pixel
== 4) {
332 mode
= MODE_SKIP4
| MODE_CFB
;
340 } else if (var
->bits_per_pixel
== 8) {
342 return -EINVAL
; /* no support on EGA */
345 mode
= MODE_8BPP
| MODE_CFB
;
348 mode
= MODE_SKIP4
| MODE_8BPP
| MODE_CFB
;
354 xres
= (var
->xres
+ 7) & ~7;
355 vxres
= (var
->xres_virtual
+ 0xF) & ~0xF;
356 xoffset
= (var
->xoffset
+ 7) & ~7;
357 left
= (var
->left_margin
+ 7) & ~7;
358 right
= (var
->right_margin
+ 7) & ~7;
359 hslen
= (var
->hsync_len
+ 7) & ~7;
363 if (xres
+ xoffset
> vxres
)
364 xoffset
= vxres
- xres
;
367 var
->right_margin
= right
;
368 var
->hsync_len
= hslen
;
369 var
->left_margin
= left
;
370 var
->xres_virtual
= vxres
;
371 var
->xoffset
= xoffset
;
378 xtotal
= xres
+ right
+ hslen
+ left
;
380 FAIL("xtotal too big");
382 FAIL("hslen too big");
383 if (right
+ hslen
+ left
> 64)
384 FAIL("hblank too big");
385 par
->crtc
[VGA_CRTC_H_TOTAL
] = xtotal
- 5;
386 par
->crtc
[VGA_CRTC_H_BLANK_START
] = xres
- 1;
387 par
->crtc
[VGA_CRTC_H_DISP
] = xres
- 1;
389 par
->crtc
[VGA_CRTC_H_SYNC_START
] = pos
;
391 par
->crtc
[VGA_CRTC_H_SYNC_END
] = pos
& 0x1F;
392 pos
+= left
- 2; /* blank_end + 2 <= total + 5 */
393 par
->crtc
[VGA_CRTC_H_BLANK_END
] = (pos
& 0x1F) | 0x80;
395 par
->crtc
[VGA_CRTC_H_SYNC_END
] |= 0x80;
398 lower
= var
->lower_margin
;
399 vslen
= var
->vsync_len
;
400 upper
= var
->upper_margin
;
401 vyres
= var
->yres_virtual
;
402 yoffset
= var
->yoffset
;
406 if (vxres
* vyres
> maxmem
) {
407 vyres
= maxmem
/ vxres
;
411 if (yoffset
+ yres
> vyres
)
412 yoffset
= vyres
- yres
;
414 var
->lower_margin
= lower
;
415 var
->vsync_len
= vslen
;
416 var
->upper_margin
= upper
;
417 var
->yres_virtual
= vyres
;
418 var
->yoffset
= yoffset
;
420 if (var
->vmode
& FB_VMODE_DOUBLE
) {
426 ytotal
= yres
+ lower
+ vslen
+ upper
;
437 FAIL("ytotal too big");
439 FAIL("vslen too big");
440 par
->crtc
[VGA_CRTC_V_TOTAL
] = ytotal
- 2;
441 r7
= 0x10; /* disable linecompare */
442 if (ytotal
& 0x100) r7
|= 0x01;
443 if (ytotal
& 0x200) r7
|= 0x20;
444 par
->crtc
[VGA_CRTC_PRESET_ROW
] = 0;
445 par
->crtc
[VGA_CRTC_MAX_SCAN
] = 0x40; /* 1 scanline, no linecmp */
446 if (var
->vmode
& FB_VMODE_DOUBLE
)
447 par
->crtc
[VGA_CRTC_MAX_SCAN
] |= 0x80;
448 par
->crtc
[VGA_CRTC_CURSOR_START
] = 0x20;
449 par
->crtc
[VGA_CRTC_CURSOR_END
] = 0x00;
450 if ((mode
& (MODE_CFB
| MODE_8BPP
)) == MODE_CFB
)
452 pos
= yoffset
* vxres
+ (xoffset
>> shift
);
453 par
->crtc
[VGA_CRTC_START_HI
] = pos
>> 8;
454 par
->crtc
[VGA_CRTC_START_LO
] = pos
& 0xFF;
455 par
->crtc
[VGA_CRTC_CURSOR_HI
] = 0x00;
456 par
->crtc
[VGA_CRTC_CURSOR_LO
] = 0x00;
458 par
->crtc
[VGA_CRTC_V_DISP_END
] = pos
& 0xFF;
459 par
->crtc
[VGA_CRTC_V_BLANK_START
] = pos
& 0xFF;
461 r7
|= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
463 r7
|= 0x40; /* 0x40 -> DISP_END */
464 par
->crtc
[VGA_CRTC_MAX_SCAN
] |= 0x20; /* BLANK_START */
467 par
->crtc
[VGA_CRTC_V_SYNC_START
] = pos
& 0xFF;
473 par
->crtc
[VGA_CRTC_V_SYNC_END
] = (pos
& 0x0F) & ~0x10; /* disabled IRQ */
474 pos
+= upper
- 1; /* blank_end + 1 <= ytotal + 2 */
475 par
->crtc
[VGA_CRTC_V_BLANK_END
] = pos
& 0xFF; /* 0x7F for original VGA,
476 but some SVGA chips requires all 8 bits to set */
478 FAIL("vxres too long");
479 par
->crtc
[VGA_CRTC_OFFSET
] = vxres
>> 1;
480 if (mode
& MODE_SKIP4
)
481 par
->crtc
[VGA_CRTC_UNDERLINE
] = 0x5F; /* 256, cfb8 */
483 par
->crtc
[VGA_CRTC_UNDERLINE
] = 0x1F; /* 16, vgap */
484 par
->crtc
[VGA_CRTC_MODE
] = rMode
| ((mode
& MODE_TEXT
) ? 0xA3 : 0xE3);
485 par
->crtc
[VGA_CRTC_LINE_COMPARE
] = 0xFF;
486 par
->crtc
[VGA_CRTC_OVERFLOW
] = r7
;
488 par
->vss
= 0x00; /* 3DA */
490 par
->misc
= 0xE3; /* enable CPU, ports 0x3Dx, positive sync */
491 if (var
->sync
& FB_SYNC_HOR_HIGH_ACT
)
493 if (var
->sync
& FB_SYNC_VERT_HIGH_ACT
)
498 if (mode
& MODE_8BPP
)
499 /* pixel clock == vga clock / 2 */
500 vga16fb_clock_chip(par
, var
->pixclock
, info
, 1, 2);
502 /* pixel clock == vga clock */
503 vga16fb_clock_chip(par
, var
->pixclock
, info
, 1, 1);
505 var
->red
.offset
= var
->green
.offset
= var
->blue
.offset
=
506 var
->transp
.offset
= 0;
507 var
->red
.length
= var
->green
.length
= var
->blue
.length
=
508 (par
->isVGA
) ? 6 : 2;
509 var
->transp
.length
= 0;
510 var
->activate
= FB_ACTIVATE_NOW
;
513 var
->accel_flags
= 0;
518 static int vga16fb_set_par(struct fb_info
*info
)
520 struct vga16fb_par
*par
= info
->par
;
526 seq
[VGA_SEQ_CLOCK_MODE
] = 0x01 | par
->clkdiv
;
527 if (par
->mode
& MODE_TEXT
)
528 seq
[VGA_SEQ_PLANE_WRITE
] = 0x03;
530 seq
[VGA_SEQ_PLANE_WRITE
] = 0x0F;
531 seq
[VGA_SEQ_CHARACTER_MAP
] = 0x00;
532 if (par
->mode
& MODE_TEXT
)
533 seq
[VGA_SEQ_MEMORY_MODE
] = 0x03;
534 else if (par
->mode
& MODE_SKIP4
)
535 seq
[VGA_SEQ_MEMORY_MODE
] = 0x0E;
537 seq
[VGA_SEQ_MEMORY_MODE
] = 0x06;
539 gdc
[VGA_GFX_SR_VALUE
] = 0x00;
540 gdc
[VGA_GFX_SR_ENABLE
] = 0x00;
541 gdc
[VGA_GFX_COMPARE_VALUE
] = 0x00;
542 gdc
[VGA_GFX_DATA_ROTATE
] = 0x00;
543 gdc
[VGA_GFX_PLANE_READ
] = 0;
544 if (par
->mode
& MODE_TEXT
) {
545 gdc
[VGA_GFX_MODE
] = 0x10;
546 gdc
[VGA_GFX_MISC
] = 0x06;
548 if (par
->mode
& MODE_CFB
)
549 gdc
[VGA_GFX_MODE
] = 0x40;
551 gdc
[VGA_GFX_MODE
] = 0x00;
552 gdc
[VGA_GFX_MISC
] = 0x05;
554 gdc
[VGA_GFX_COMPARE_MASK
] = 0x0F;
555 gdc
[VGA_GFX_BIT_MASK
] = 0xFF;
557 for (i
= 0x00; i
< 0x10; i
++)
559 if (par
->mode
& MODE_TEXT
)
560 atc
[VGA_ATC_MODE
] = 0x04;
561 else if (par
->mode
& MODE_8BPP
)
562 atc
[VGA_ATC_MODE
] = 0x41;
564 atc
[VGA_ATC_MODE
] = 0x81;
565 atc
[VGA_ATC_OVERSCAN
] = 0x00; /* 0 for EGA, 0xFF for VGA */
566 atc
[VGA_ATC_PLANE_ENABLE
] = 0x0F;
567 if (par
->mode
& MODE_8BPP
)
568 atc
[VGA_ATC_PEL
] = (info
->var
.xoffset
& 3) << 1;
570 atc
[VGA_ATC_PEL
] = info
->var
.xoffset
& 7;
571 atc
[VGA_ATC_COLOR_PAGE
] = 0x00;
573 if (par
->mode
& MODE_TEXT
) {
574 fh
= 16; // FIXME !!! Fudge font height.
575 par
->crtc
[VGA_CRTC_MAX_SCAN
] = (par
->crtc
[VGA_CRTC_MAX_SCAN
]
579 vga_io_w(VGA_MIS_W
, vga_io_r(VGA_MIS_R
) | 0x01);
581 /* Enable graphics register modification */
583 vga_io_w(EGA_GFX_E0
, 0x00);
584 vga_io_w(EGA_GFX_E1
, 0x01);
587 /* update misc output register */
588 vga_io_w(VGA_MIS_W
, par
->misc
);
590 /* synchronous reset on */
591 vga_io_wseq(0x00, 0x01);
594 vga_io_w(VGA_PEL_MSK
, par
->pel_msk
);
596 /* write sequencer registers */
597 vga_io_wseq(VGA_SEQ_CLOCK_MODE
, seq
[VGA_SEQ_CLOCK_MODE
] | 0x20);
598 for (i
= 2; i
< VGA_SEQ_C
; i
++) {
599 vga_io_wseq(i
, seq
[i
]);
602 /* synchronous reset off */
603 vga_io_wseq(0x00, 0x03);
605 /* deprotect CRT registers 0-7 */
606 vga_io_wcrt(VGA_CRTC_V_SYNC_END
, par
->crtc
[VGA_CRTC_V_SYNC_END
]);
608 /* write CRT registers */
609 for (i
= 0; i
< VGA_CRTC_REGS
; i
++) {
610 vga_io_wcrt(i
, par
->crtc
[i
]);
613 /* write graphics controller registers */
614 for (i
= 0; i
< VGA_GFX_C
; i
++) {
615 vga_io_wgfx(i
, gdc
[i
]);
618 /* write attribute controller registers */
619 for (i
= 0; i
< VGA_ATT_C
; i
++) {
620 vga_io_r(VGA_IS1_RC
); /* reset flip-flop */
621 vga_io_wattr(i
, atc
[i
]);
624 /* Wait for screen to stabilize. */
627 vga_io_wseq(VGA_SEQ_CLOCK_MODE
, seq
[VGA_SEQ_CLOCK_MODE
]);
629 vga_io_r(VGA_IS1_RC
);
630 vga_io_w(VGA_ATT_IW
, 0x20);
632 vga16fb_update_fix(info
);
636 static void ega16_setpalette(int regno
, unsigned red
, unsigned green
, unsigned blue
)
638 static const unsigned char map
[] = { 000, 001, 010, 011 };
643 val
= map
[red
>>14] | ((map
[green
>>14]) << 1) | ((map
[blue
>>14]) << 2);
644 vga_io_r(VGA_IS1_RC
); /* ! 0x3BA */
645 vga_io_wattr(regno
, val
);
646 vga_io_r(VGA_IS1_RC
); /* some clones need it */
647 vga_io_w(VGA_ATT_IW
, 0x20); /* unblank screen */
650 static void vga16_setpalette(int regno
, unsigned red
, unsigned green
, unsigned blue
)
652 outb(regno
, VGA_PEL_IW
);
653 outb(red
>> 10, VGA_PEL_D
);
654 outb(green
>> 10, VGA_PEL_D
);
655 outb(blue
>> 10, VGA_PEL_D
);
658 static int vga16fb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
659 unsigned blue
, unsigned transp
,
660 struct fb_info
*info
)
662 struct vga16fb_par
*par
= info
->par
;
666 * Set a single color register. The values supplied are
667 * already rounded down to the hardware's capabilities
668 * (according to the entries in the `var' structure). Return
669 * != 0 for invalid regno.
675 gray
= info
->var
.grayscale
;
678 /* gray = 0.30*R + 0.59*G + 0.11*B */
679 red
= green
= blue
= (red
* 77 + green
* 151 + blue
* 28) >> 8;
682 vga16_setpalette(regno
,red
,green
,blue
);
684 ega16_setpalette(regno
,red
,green
,blue
);
688 static int vga16fb_pan_display(struct fb_var_screeninfo
*var
,
689 struct fb_info
*info
)
691 vga16fb_pan_var(info
, var
);
695 /* The following VESA blanking code is taken from vgacon.c. The VGA
696 blanking code was originally by Huang shi chao, and modified by
697 Christoph Rimek (chrimek@toppoint.de) and todd j. derr
698 (tjd@barefoot.org) for Linux. */
700 static void vga_vesa_blank(struct vga16fb_par
*par
, int mode
)
702 unsigned char SeqCtrlIndex
= vga_io_r(VGA_SEQ_I
);
703 unsigned char CrtCtrlIndex
= vga_io_r(VGA_CRT_IC
);
705 /* save original values of VGA controller registers */
706 if(!par
->vesa_blanked
) {
707 par
->vga_state
.CrtMiscIO
= vga_io_r(VGA_MIS_R
);
710 par
->vga_state
.HorizontalTotal
= vga_io_rcrt(0x00); /* HorizontalTotal */
711 par
->vga_state
.HorizDisplayEnd
= vga_io_rcrt(0x01); /* HorizDisplayEnd */
712 par
->vga_state
.StartHorizRetrace
= vga_io_rcrt(0x04); /* StartHorizRetrace */
713 par
->vga_state
.EndHorizRetrace
= vga_io_rcrt(0x05); /* EndHorizRetrace */
714 par
->vga_state
.Overflow
= vga_io_rcrt(0x07); /* Overflow */
715 par
->vga_state
.StartVertRetrace
= vga_io_rcrt(0x10); /* StartVertRetrace */
716 par
->vga_state
.EndVertRetrace
= vga_io_rcrt(0x11); /* EndVertRetrace */
717 par
->vga_state
.ModeControl
= vga_io_rcrt(0x17); /* ModeControl */
718 par
->vga_state
.ClockingMode
= vga_io_rseq(0x01); /* ClockingMode */
721 /* assure that video is enabled */
722 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
723 vga_io_wseq(0x01, par
->vga_state
.ClockingMode
| 0x20);
725 /* test for vertical retrace in process.... */
726 if ((par
->vga_state
.CrtMiscIO
& 0x80) == 0x80)
727 vga_io_w(VGA_MIS_W
, par
->vga_state
.CrtMiscIO
& 0xef);
730 * Set <End of vertical retrace> to minimum (0) and
731 * <Start of vertical Retrace> to maximum (incl. overflow)
732 * Result: turn off vertical sync (VSync) pulse.
734 if (mode
& FB_BLANK_VSYNC_SUSPEND
) {
735 vga_io_wcrt(VGA_CRTC_V_SYNC_START
, 0xff);
736 vga_io_wcrt(VGA_CRTC_V_SYNC_END
, 0x40);
737 /* bits 9,10 of vert. retrace */
738 vga_io_wcrt(VGA_CRTC_OVERFLOW
, par
->vga_state
.Overflow
| 0x84);
741 if (mode
& FB_BLANK_HSYNC_SUSPEND
) {
743 * Set <End of horizontal retrace> to minimum (0) and
744 * <Start of horizontal Retrace> to maximum
745 * Result: turn off horizontal sync (HSync) pulse.
747 vga_io_wcrt(VGA_CRTC_H_SYNC_START
, 0xff);
748 vga_io_wcrt(VGA_CRTC_H_SYNC_END
, 0x00);
751 /* restore both index registers */
752 outb_p(SeqCtrlIndex
, VGA_SEQ_I
);
753 outb_p(CrtCtrlIndex
, VGA_CRT_IC
);
756 static void vga_vesa_unblank(struct vga16fb_par
*par
)
758 unsigned char SeqCtrlIndex
= vga_io_r(VGA_SEQ_I
);
759 unsigned char CrtCtrlIndex
= vga_io_r(VGA_CRT_IC
);
761 /* restore original values of VGA controller registers */
762 vga_io_w(VGA_MIS_W
, par
->vga_state
.CrtMiscIO
);
764 /* HorizontalTotal */
765 vga_io_wcrt(0x00, par
->vga_state
.HorizontalTotal
);
766 /* HorizDisplayEnd */
767 vga_io_wcrt(0x01, par
->vga_state
.HorizDisplayEnd
);
768 /* StartHorizRetrace */
769 vga_io_wcrt(0x04, par
->vga_state
.StartHorizRetrace
);
770 /* EndHorizRetrace */
771 vga_io_wcrt(0x05, par
->vga_state
.EndHorizRetrace
);
773 vga_io_wcrt(0x07, par
->vga_state
.Overflow
);
774 /* StartVertRetrace */
775 vga_io_wcrt(0x10, par
->vga_state
.StartVertRetrace
);
777 vga_io_wcrt(0x11, par
->vga_state
.EndVertRetrace
);
779 vga_io_wcrt(0x17, par
->vga_state
.ModeControl
);
781 vga_io_wseq(0x01, par
->vga_state
.ClockingMode
);
783 /* restore index/control registers */
784 vga_io_w(VGA_SEQ_I
, SeqCtrlIndex
);
785 vga_io_w(VGA_CRT_IC
, CrtCtrlIndex
);
788 static void vga_pal_blank(void)
792 for (i
=0; i
<16; i
++) {
793 outb_p(i
, VGA_PEL_IW
);
794 outb_p(0, VGA_PEL_D
);
795 outb_p(0, VGA_PEL_D
);
796 outb_p(0, VGA_PEL_D
);
800 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
801 static int vga16fb_blank(int blank
, struct fb_info
*info
)
803 struct vga16fb_par
*par
= info
->par
;
806 case FB_BLANK_UNBLANK
: /* Unblank */
807 if (par
->vesa_blanked
) {
808 vga_vesa_unblank(par
);
809 par
->vesa_blanked
= 0;
811 if (par
->palette_blanked
) {
812 par
->palette_blanked
= 0;
815 case FB_BLANK_NORMAL
: /* blank */
817 par
->palette_blanked
= 1;
819 default: /* VESA blanking */
820 vga_vesa_blank(par
, blank
);
821 par
->vesa_blanked
= 1;
827 static void vga_8planes_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
829 u32 dx
= rect
->dx
, width
= rect
->width
;
830 char oldindex
= getindex();
831 char oldmode
= setmode(0x40);
832 char oldmask
= selectmask();
833 int line_ofs
, height
;
838 where
= info
->screen_base
+ dx
+ rect
->dy
* info
->fix
.line_length
;
840 if (rect
->rop
== ROP_COPY
) {
845 line_ofs
= info
->fix
.line_length
- width
;
848 height
= rect
->height
;
853 /* we can do memset... */
854 for (x
= width
; x
> 0; --x
) {
855 writeb(rect
->color
, where
);
861 char oldcolor
= setcolor(0xf);
867 for (y
= 0; y
< rect
->height
; y
++) {
870 where
+= info
->fix
.line_length
;
881 static void vga16fb_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
883 int x
, x2
, y2
, vxres
, vyres
, width
, height
, line_ofs
;
886 vxres
= info
->var
.xres_virtual
;
887 vyres
= info
->var
.yres_virtual
;
889 if (!rect
->width
|| !rect
->height
|| rect
->dx
> vxres
|| rect
->dy
> vyres
)
892 /* We could use hardware clipping but on many cards you get around
893 * hardware clipping by writing to framebuffer directly. */
895 x2
= rect
->dx
+ rect
->width
;
896 y2
= rect
->dy
+ rect
->height
;
897 x2
= x2
< vxres
? x2
: vxres
;
898 y2
= y2
< vyres
? y2
: vyres
;
899 width
= x2
- rect
->dx
;
901 switch (info
->fix
.type
) {
902 case FB_TYPE_VGA_PLANES
:
903 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
905 height
= y2
- rect
->dy
;
906 width
= rect
->width
/8;
908 line_ofs
= info
->fix
.line_length
- width
;
909 dst
= info
->screen_base
+ (rect
->dx
/8) + rect
->dy
* info
->fix
.line_length
;
916 setcolor(rect
->color
);
922 for (x
= 0; x
< width
; x
++) {
938 for (x
= 0; x
< width
; x
++) {
947 vga_8planes_fillrect(info
, rect
);
949 case FB_TYPE_PACKED_PIXELS
:
951 cfb_fillrect(info
, rect
);
956 static void vga_8planes_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
958 char oldindex
= getindex();
959 char oldmode
= setmode(0x41);
960 char oldop
= setop(0);
961 char oldsr
= setsr(0xf);
962 int height
, line_ofs
, x
;
967 height
= area
->height
;
971 width
= area
->width
/ 4;
973 if (area
->dy
< area
->sy
|| (area
->dy
== area
->sy
&& dx
< sx
)) {
974 line_ofs
= info
->fix
.line_length
- width
;
975 dest
= info
->screen_base
+ dx
+ area
->dy
* info
->fix
.line_length
;
976 src
= info
->screen_base
+ sx
+ area
->sy
* info
->fix
.line_length
;
978 for (x
= 0; x
< width
; x
++) {
988 line_ofs
= info
->fix
.line_length
- width
;
989 dest
= info
->screen_base
+ dx
+ width
+
990 (area
->dy
+ height
- 1) * info
->fix
.line_length
;
991 src
= info
->screen_base
+ sx
+ width
+
992 (area
->sy
+ height
- 1) * info
->fix
.line_length
;
994 for (x
= 0; x
< width
; x
++) {
1011 static void vga16fb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
1013 u32 dx
= area
->dx
, dy
= area
->dy
, sx
= area
->sx
, sy
= area
->sy
;
1014 int x
, x2
, y2
, old_dx
, old_dy
, vxres
, vyres
;
1015 int height
, width
, line_ofs
;
1016 char __iomem
*dst
= NULL
;
1017 char __iomem
*src
= NULL
;
1019 vxres
= info
->var
.xres_virtual
;
1020 vyres
= info
->var
.yres_virtual
;
1022 if (area
->dx
> vxres
|| area
->sx
> vxres
|| area
->dy
> vyres
||
1026 /* clip the destination */
1031 * We could use hardware clipping but on many cards you get around
1032 * hardware clipping by writing to framebuffer directly.
1034 x2
= area
->dx
+ area
->width
;
1035 y2
= area
->dy
+ area
->height
;
1036 dx
= area
->dx
> 0 ? area
->dx
: 0;
1037 dy
= area
->dy
> 0 ? area
->dy
: 0;
1038 x2
= x2
< vxres
? x2
: vxres
;
1039 y2
= y2
< vyres
? y2
: vyres
;
1043 if (sx
+ dx
< old_dx
|| sy
+ dy
< old_dy
)
1046 /* update sx1,sy1 */
1047 sx
+= (dx
- old_dx
);
1048 sy
+= (dy
- old_dy
);
1050 /* the source must be completely inside the virtual screen */
1051 if (sx
+ width
> vxres
|| sy
+ height
> vyres
)
1054 switch (info
->fix
.type
) {
1055 case FB_TYPE_VGA_PLANES
:
1056 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
1059 line_ofs
= info
->fix
.line_length
- width
;
1065 if (dy
< sy
|| (dy
== sy
&& dx
< sx
)) {
1066 dst
= info
->screen_base
+ (dx
/8) + dy
* info
->fix
.line_length
;
1067 src
= info
->screen_base
+ (sx
/8) + sy
* info
->fix
.line_length
;
1069 for (x
= 0; x
< width
; x
++) {
1079 dst
= info
->screen_base
+ (dx
/8) + width
+
1080 (dy
+ height
- 1) * info
->fix
.line_length
;
1081 src
= info
->screen_base
+ (sx
/8) + width
+
1082 (sy
+ height
- 1) * info
->fix
.line_length
;
1084 for (x
= 0; x
< width
; x
++) {
1095 vga_8planes_copyarea(info
, area
);
1097 case FB_TYPE_PACKED_PIXELS
:
1099 cfb_copyarea(info
, area
);
1104 #define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
1105 #define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
1106 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
1108 #if defined(__LITTLE_ENDIAN)
1109 static const u16 transl_l
[] = TRANS_MASK_LOW
;
1110 static const u16 transl_h
[] = TRANS_MASK_HIGH
;
1111 #elif defined(__BIG_ENDIAN)
1112 static const u16 transl_l
[] = TRANS_MASK_HIGH
;
1113 static const u16 transl_h
[] = TRANS_MASK_LOW
;
1115 #error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1118 static void vga_8planes_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
1120 char oldindex
= getindex();
1121 char oldmode
= setmode(0x40);
1122 char oldop
= setop(0);
1123 char oldsr
= setsr(0);
1124 char oldmask
= selectmask();
1125 const char *cdat
= image
->data
;
1127 char __iomem
*where
;
1131 where
= info
->screen_base
+ dx
+ image
->dy
* info
->fix
.line_length
;
1134 writeb(image
->bg_color
, where
);
1137 setmask(image
->fg_color
^ image
->bg_color
);
1140 for (y
= 0; y
< image
->height
; y
++, where
+= info
->fix
.line_length
)
1141 writew(transl_h
[cdat
[y
]&0xF] | transl_l
[cdat
[y
] >> 4], where
);
1149 static void vga_imageblit_expand(struct fb_info
*info
, const struct fb_image
*image
)
1151 char __iomem
*where
= info
->screen_base
+ (image
->dx
/8) +
1152 image
->dy
* info
->fix
.line_length
;
1153 struct vga16fb_par
*par
= info
->par
;
1154 char *cdat
= (char *) image
->data
;
1158 switch (info
->fix
.type
) {
1159 case FB_TYPE_VGA_PLANES
:
1160 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
1165 setcolor(image
->fg_color
);
1169 writeb(image
->bg_color
, where
);
1171 readb(where
); /* fill latches */
1174 for (y
= 0; y
< image
->height
; y
++) {
1176 for (x
= image
->width
/8; x
--;)
1177 writeb(*cdat
++, dst
++);
1178 where
+= info
->fix
.line_length
;
1185 setcolor(image
->bg_color
);
1189 for (y
= 0; y
< image
->height
; y
++) {
1191 for (x
=image
->width
/8; x
--;){
1193 setcolor(image
->fg_color
);
1200 where
+= info
->fix
.line_length
;
1204 vga_8planes_imageblit(info
, image
);
1206 case FB_TYPE_PACKED_PIXELS
:
1208 cfb_imageblit(info
, image
);
1213 static void vga_imageblit_color(struct fb_info
*info
, const struct fb_image
*image
)
1218 struct vga16fb_par
*par
= info
->par
;
1219 char __iomem
*where
=
1220 info
->screen_base
+ image
->dy
* info
->fix
.line_length
+
1222 const char *cdat
= image
->data
;
1226 switch (info
->fix
.type
) {
1227 case FB_TYPE_VGA_PLANES
:
1228 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
&&
1234 for (y
= 0; y
< image
->height
; y
++) {
1235 for (x
= 0; x
< image
->width
; x
++) {
1240 setmask(1 << (7 - (x
% 8)));
1246 where
+= info
->fix
.line_length
;
1250 case FB_TYPE_PACKED_PIXELS
:
1251 cfb_imageblit(info
, image
);
1258 static void vga16fb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
1260 if (image
->depth
== 1)
1261 vga_imageblit_expand(info
, image
);
1263 vga_imageblit_color(info
, image
);
1266 static struct fb_ops vga16fb_ops
= {
1267 .owner
= THIS_MODULE
,
1268 .fb_open
= vga16fb_open
,
1269 .fb_release
= vga16fb_release
,
1270 .fb_check_var
= vga16fb_check_var
,
1271 .fb_set_par
= vga16fb_set_par
,
1272 .fb_setcolreg
= vga16fb_setcolreg
,
1273 .fb_pan_display
= vga16fb_pan_display
,
1274 .fb_blank
= vga16fb_blank
,
1275 .fb_fillrect
= vga16fb_fillrect
,
1276 .fb_copyarea
= vga16fb_copyarea
,
1277 .fb_imageblit
= vga16fb_imageblit
,
1281 static int vga16fb_setup(char *options
)
1285 if (!options
|| !*options
)
1288 while ((this_opt
= strsep(&options
, ",")) != NULL
) {
1289 if (!*this_opt
) continue;
1295 static int __devinit
vga16fb_probe(struct platform_device
*dev
)
1297 struct fb_info
*info
;
1298 struct vga16fb_par
*par
;
1302 printk(KERN_DEBUG
"vga16fb: initializing\n");
1303 info
= framebuffer_alloc(sizeof(struct vga16fb_par
), &dev
->dev
);
1310 /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
1311 info
->screen_base
= (void __iomem
*)VGA_MAP_MEM(VGA_FB_PHYS
, 0);
1313 if (!info
->screen_base
) {
1314 printk(KERN_ERR
"vga16fb: unable to map device\n");
1319 printk(KERN_INFO
"vga16fb: mapped to 0x%p\n", info
->screen_base
);
1322 par
->isVGA
= screen_info
.orig_video_isVGA
;
1323 par
->palette_blanked
= 0;
1324 par
->vesa_blanked
= 0;
1326 i
= par
->isVGA
? 6 : 2;
1328 vga16fb_defined
.red
.length
= i
;
1329 vga16fb_defined
.green
.length
= i
;
1330 vga16fb_defined
.blue
.length
= i
;
1332 /* name should not depend on EGA/VGA */
1333 info
->fbops
= &vga16fb_ops
;
1334 info
->var
= vga16fb_defined
;
1335 info
->fix
= vga16fb_fix
;
1336 /* supports rectangles with widths of multiples of 8 */
1337 info
->pixmap
.blit_x
= 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
1338 info
->flags
= FBINFO_FLAG_DEFAULT
|
1339 FBINFO_HWACCEL_YPAN
;
1341 i
= (info
->var
.bits_per_pixel
== 8) ? 256 : 16;
1342 ret
= fb_alloc_cmap(&info
->cmap
, i
, 0);
1344 printk(KERN_ERR
"vga16fb: unable to allocate colormap\n");
1346 goto err_alloc_cmap
;
1349 if (vga16fb_check_var(&info
->var
, info
)) {
1350 printk(KERN_ERR
"vga16fb: unable to validate variable\n");
1355 vga16fb_update_fix(info
);
1357 if (register_framebuffer(info
) < 0) {
1358 printk(KERN_ERR
"vga16fb: unable to register framebuffer\n");
1363 printk(KERN_INFO
"fb%d: %s frame buffer device\n",
1364 info
->node
, info
->fix
.id
);
1365 platform_set_drvdata(dev
, info
);
1370 fb_dealloc_cmap(&info
->cmap
);
1372 iounmap(info
->screen_base
);
1374 framebuffer_release(info
);
1379 static int vga16fb_remove(struct platform_device
*dev
)
1381 struct fb_info
*info
= platform_get_drvdata(dev
);
1384 unregister_framebuffer(info
);
1385 iounmap(info
->screen_base
);
1386 fb_dealloc_cmap(&info
->cmap
);
1387 /* XXX unshare VGA regions */
1388 framebuffer_release(info
);
1394 static struct platform_driver vga16fb_driver
= {
1395 .probe
= vga16fb_probe
,
1396 .remove
= vga16fb_remove
,
1402 static struct platform_device
*vga16fb_device
;
1404 static int __init
vga16fb_init(void)
1408 char *option
= NULL
;
1410 if (fb_get_options("vga16fb", &option
))
1413 vga16fb_setup(option
);
1415 ret
= platform_driver_register(&vga16fb_driver
);
1418 vga16fb_device
= platform_device_alloc("vga16fb", 0);
1421 ret
= platform_device_add(vga16fb_device
);
1426 platform_device_put(vga16fb_device
);
1427 platform_driver_unregister(&vga16fb_driver
);
1434 static void __exit
vga16fb_exit(void)
1436 platform_device_unregister(vga16fb_device
);
1437 platform_driver_unregister(&vga16fb_driver
);
1440 MODULE_DESCRIPTION("Legacy VGA framebuffer device driver");
1441 MODULE_LICENSE("GPL");
1442 module_init(vga16fb_init
);
1443 module_exit(vga16fb_exit
);
1447 * Overrides for Emacs so that we follow Linus's tabbing style.
1448 * ---------------------------------------------------------------------------