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/tty.h>
19 #include <linux/slab.h>
20 #include <linux/delay.h>
22 #include <linux/ioport.h>
23 #include <linux/init.h>
26 #include <video/vga.h>
28 #define GRAPHICS_ADDR_REG VGA_GFX_I /* Graphics address register. */
29 #define GRAPHICS_DATA_REG VGA_GFX_D /* Graphics data register. */
31 #define SET_RESET_INDEX VGA_GFX_SR_VALUE /* Set/Reset Register index. */
32 #define ENABLE_SET_RESET_INDEX VGA_GFX_SR_ENABLE /* Enable Set/Reset Register index. */
33 #define DATA_ROTATE_INDEX VGA_GFX_DATA_ROTATE /* Data Rotate Register index. */
34 #define GRAPHICS_MODE_INDEX VGA_GFX_MODE /* Graphics Mode Register index. */
35 #define BIT_MASK_INDEX VGA_GFX_BIT_MASK /* Bit Mask Register index. */
37 #define dac_reg (VGA_PEL_IW)
38 #define dac_val (VGA_PEL_D)
40 #define VGA_FB_PHYS 0xA0000
41 #define VGA_FB_PHYS_LEN 65536
48 /* --------------------------------------------------------------------- */
54 static struct fb_info vga16fb
;
56 static struct vga16fb_par
{
57 /* structure holding original VGA register settings when the
60 unsigned char SeqCtrlIndex
; /* Sequencer Index reg. */
61 unsigned char CrtCtrlIndex
; /* CRT-Contr. Index reg. */
62 unsigned char CrtMiscIO
; /* Miscellaneous register */
63 unsigned char HorizontalTotal
; /* CRT-Controller:00h */
64 unsigned char HorizDisplayEnd
; /* CRT-Controller:01h */
65 unsigned char StartHorizRetrace
; /* CRT-Controller:04h */
66 unsigned char EndHorizRetrace
; /* CRT-Controller:05h */
67 unsigned char Overflow
; /* CRT-Controller:07h */
68 unsigned char StartVertRetrace
; /* CRT-Controller:10h */
69 unsigned char EndVertRetrace
; /* CRT-Controller:11h */
70 unsigned char ModeControl
; /* CRT-Controller:17h */
71 unsigned char ClockingMode
; /* Seq-Controller:01h */
73 struct vgastate state
;
75 int palette_blanked
, vesa_blanked
, mode
, isVGA
;
76 u8 misc
, pel_msk
, vss
, clkdiv
;
80 /* --------------------------------------------------------------------- */
82 static struct fb_var_screeninfo vga16fb_defined
= {
88 .activate
= FB_ACTIVATE_TEST
,
98 .vmode
= FB_VMODE_NONINTERLACED
,
101 /* name should not depend on EGA/VGA */
102 static struct fb_fix_screeninfo vga16fb_fix __initdata
= {
104 .smem_start
= VGA_FB_PHYS
,
105 .smem_len
= VGA_FB_PHYS_LEN
,
106 .type
= FB_TYPE_VGA_PLANES
,
107 .type_aux
= FB_AUX_VGA_PLANES_VGA4
,
108 .visual
= FB_VISUAL_PSEUDOCOLOR
,
111 .line_length
= 640/8,
112 .accel
= FB_ACCEL_NONE
115 /* The VGA's weird architecture often requires that we read a byte and
116 write a byte to the same location. It doesn't matter *what* byte
117 we write, however. This is because all the action goes on behind
118 the scenes in the VGA's 32-bit latch register, and reading and writing
119 video memory just invokes latch behavior.
121 To avoid race conditions (is this necessary?), reading and writing
122 the memory byte should be done with a single instruction. One
123 suitable instruction is the x86 bitwise OR. The following
124 read-modify-write routine should optimize to one such bitwise
126 static inline void rmw(volatile char __iomem
*p
)
132 /* Set the Graphics Mode Register, and return its previous value.
133 Bits 0-1 are write mode, bit 3 is read mode. */
134 static inline int setmode(int mode
)
138 vga_io_w(GRAPHICS_ADDR_REG
, GRAPHICS_MODE_INDEX
);
139 oldmode
= vga_io_r(GRAPHICS_DATA_REG
);
140 vga_io_w(GRAPHICS_DATA_REG
, mode
);
144 /* Select the Bit Mask Register and return its value. */
145 static inline int selectmask(void)
147 return vga_io_rgfx(BIT_MASK_INDEX
);
150 /* Set the value of the Bit Mask Register. It must already have been
151 selected with selectmask(). */
152 static inline void setmask(int mask
)
154 vga_io_w(GRAPHICS_DATA_REG
, mask
);
157 /* Set the Data Rotate Register and return its old value.
158 Bits 0-2 are rotate count, bits 3-4 are logical operation
159 (0=NOP, 1=AND, 2=OR, 3=XOR). */
160 static inline int setop(int op
)
164 vga_io_w(GRAPHICS_ADDR_REG
, DATA_ROTATE_INDEX
);
165 oldop
= vga_io_r(GRAPHICS_DATA_REG
);
166 vga_io_w(GRAPHICS_DATA_REG
, op
);
170 /* Set the Enable Set/Reset Register and return its old value.
171 The code here always uses value 0xf for thsi register. */
172 static inline int setsr(int sr
)
176 vga_io_w(GRAPHICS_ADDR_REG
, ENABLE_SET_RESET_INDEX
);
177 oldsr
= vga_io_r(GRAPHICS_DATA_REG
);
178 vga_io_w(GRAPHICS_DATA_REG
, sr
);
182 /* Set the Set/Reset Register and return its old value. */
183 static inline int setcolor(int color
)
187 vga_io_w(GRAPHICS_ADDR_REG
, SET_RESET_INDEX
);
188 oldcolor
= vga_io_r(GRAPHICS_DATA_REG
);
189 vga_io_w(GRAPHICS_DATA_REG
, color
);
193 /* Return the value in the Graphics Address Register. */
194 static inline int getindex(void)
196 return vga_io_r(GRAPHICS_ADDR_REG
);
199 /* Set the value in the Graphics Address Register. */
200 static inline void setindex(int index
)
202 vga_io_w(GRAPHICS_ADDR_REG
, index
);
205 static void vga16fb_pan_var(struct fb_info
*info
,
206 struct fb_var_screeninfo
*var
)
208 struct vga16fb_par
*par
= (struct vga16fb_par
*) info
->par
;
211 xoffset
= var
->xoffset
;
212 if (info
->var
.bits_per_pixel
== 8) {
213 pos
= (info
->var
.xres_virtual
* var
->yoffset
+ xoffset
) >> 2;
214 } else if (par
->mode
& MODE_TEXT
) {
215 int fh
= 16; // FIXME !!! font height. Fugde for now.
216 pos
= (info
->var
.xres_virtual
* (var
->yoffset
/ fh
) + xoffset
) >> 3;
218 if (info
->var
.nonstd
)
220 pos
= (info
->var
.xres_virtual
* var
->yoffset
+ xoffset
) >> 3;
222 vga_io_wcrt(VGA_CRTC_START_HI
, pos
>> 8);
223 vga_io_wcrt(VGA_CRTC_START_LO
, pos
& 0xFF);
224 /* if we support CFB4, then we must! support xoffset with pixel
225 * granularity if someone supports xoffset in bit resolution */
226 vga_io_r(VGA_IS1_RC
); /* reset flip-flop */
227 vga_io_w(VGA_ATT_IW
, VGA_ATC_PEL
);
228 if (var
->bits_per_pixel
== 8)
229 vga_io_w(VGA_ATT_IW
, (xoffset
& 3) << 1);
231 vga_io_w(VGA_ATT_IW
, xoffset
& 7);
232 vga_io_r(VGA_IS1_RC
);
233 vga_io_w(VGA_ATT_IW
, 0x20);
236 static void vga16fb_update_fix(struct fb_info
*info
)
238 if (info
->var
.bits_per_pixel
== 4) {
239 if (info
->var
.nonstd
) {
240 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
241 info
->fix
.line_length
= info
->var
.xres_virtual
/ 2;
243 info
->fix
.type
= FB_TYPE_VGA_PLANES
;
244 info
->fix
.type_aux
= FB_AUX_VGA_PLANES_VGA4
;
245 info
->fix
.line_length
= info
->var
.xres_virtual
/ 8;
247 } else if (info
->var
.bits_per_pixel
== 0) {
248 info
->fix
.type
= FB_TYPE_TEXT
;
249 info
->fix
.type_aux
= FB_AUX_TEXT_CGA
;
250 info
->fix
.line_length
= info
->var
.xres_virtual
/ 4;
252 if (info
->var
.nonstd
) {
253 info
->fix
.type
= FB_TYPE_VGA_PLANES
;
254 info
->fix
.type_aux
= FB_AUX_VGA_PLANES_CFB8
;
255 info
->fix
.line_length
= info
->var
.xres_virtual
/ 4;
257 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
258 info
->fix
.line_length
= info
->var
.xres_virtual
;
263 static void vga16fb_clock_chip(struct vga16fb_par
*par
,
264 unsigned int pixclock
,
265 const struct fb_info
*info
,
272 } *ptr
, *best
, vgaclocks
[] = {
273 { 79442 /* 12.587 */, 0x00, 0x08},
274 { 70616 /* 14.161 */, 0x04, 0x08},
275 { 39721 /* 25.175 */, 0x00, 0x00},
276 { 35308 /* 28.322 */, 0x04, 0x00},
277 { 0 /* bad */, 0x00, 0x00}};
280 pixclock
= (pixclock
* mul
) / div
;
282 err
= pixclock
- best
->pixclock
;
283 if (err
< 0) err
= -err
;
284 for (ptr
= vgaclocks
+ 1; ptr
->pixclock
; ptr
++) {
287 tmp
= pixclock
- ptr
->pixclock
;
288 if (tmp
< 0) tmp
= -tmp
;
294 par
->misc
|= best
->misc
;
295 par
->clkdiv
= best
->seq_clock_mode
;
296 pixclock
= (best
->pixclock
* div
) / mul
;
299 #define FAIL(X) return -EINVAL
301 static int vga16fb_open(struct fb_info
*info
, int user
)
303 struct vga16fb_par
*par
= (struct vga16fb_par
*) info
->par
;
304 int cnt
= atomic_read(&par
->ref_count
);
307 memset(&par
->state
, 0, sizeof(struct vgastate
));
308 par
->state
.flags
= VGA_SAVE_FONTS
| VGA_SAVE_MODE
|
310 save_vga(&par
->state
);
312 atomic_inc(&par
->ref_count
);
316 static int vga16fb_release(struct fb_info
*info
, int user
)
318 struct vga16fb_par
*par
= (struct vga16fb_par
*) info
->par
;
319 int cnt
= atomic_read(&par
->ref_count
);
324 restore_vga(&par
->state
);
325 atomic_dec(&par
->ref_count
);
330 static int vga16fb_check_var(struct fb_var_screeninfo
*var
,
331 struct fb_info
*info
)
333 struct vga16fb_par
*par
= (struct vga16fb_par
*) info
->par
;
334 u32 xres
, right
, hslen
, left
, xtotal
;
335 u32 yres
, lower
, vslen
, upper
, ytotal
;
336 u32 vxres
, xoffset
, vyres
, yoffset
;
345 if (var
->bits_per_pixel
== 4) {
350 mode
= MODE_SKIP4
| MODE_CFB
;
358 } else if (var
->bits_per_pixel
== 8) {
360 return -EINVAL
; /* no support on EGA */
363 mode
= MODE_8BPP
| MODE_CFB
;
366 mode
= MODE_SKIP4
| MODE_8BPP
| MODE_CFB
;
372 xres
= (var
->xres
+ 7) & ~7;
373 vxres
= (var
->xres_virtual
+ 0xF) & ~0xF;
374 xoffset
= (var
->xoffset
+ 7) & ~7;
375 left
= (var
->left_margin
+ 7) & ~7;
376 right
= (var
->right_margin
+ 7) & ~7;
377 hslen
= (var
->hsync_len
+ 7) & ~7;
381 if (xres
+ xoffset
> vxres
)
382 xoffset
= vxres
- xres
;
385 var
->right_margin
= right
;
386 var
->hsync_len
= hslen
;
387 var
->left_margin
= left
;
388 var
->xres_virtual
= vxres
;
389 var
->xoffset
= xoffset
;
396 xtotal
= xres
+ right
+ hslen
+ left
;
398 FAIL("xtotal too big");
400 FAIL("hslen too big");
401 if (right
+ hslen
+ left
> 64)
402 FAIL("hblank too big");
403 par
->crtc
[VGA_CRTC_H_TOTAL
] = xtotal
- 5;
404 par
->crtc
[VGA_CRTC_H_BLANK_START
] = xres
- 1;
405 par
->crtc
[VGA_CRTC_H_DISP
] = xres
- 1;
407 par
->crtc
[VGA_CRTC_H_SYNC_START
] = pos
;
409 par
->crtc
[VGA_CRTC_H_SYNC_END
] = pos
& 0x1F;
410 pos
+= left
- 2; /* blank_end + 2 <= total + 5 */
411 par
->crtc
[VGA_CRTC_H_BLANK_END
] = (pos
& 0x1F) | 0x80;
413 par
->crtc
[VGA_CRTC_H_SYNC_END
] |= 0x80;
416 lower
= var
->lower_margin
;
417 vslen
= var
->vsync_len
;
418 upper
= var
->upper_margin
;
419 vyres
= var
->yres_virtual
;
420 yoffset
= var
->yoffset
;
424 if (vxres
* vyres
> maxmem
) {
425 vyres
= maxmem
/ vxres
;
429 if (yoffset
+ yres
> vyres
)
430 yoffset
= vyres
- yres
;
432 var
->lower_margin
= lower
;
433 var
->vsync_len
= vslen
;
434 var
->upper_margin
= upper
;
435 var
->yres_virtual
= vyres
;
436 var
->yoffset
= yoffset
;
438 if (var
->vmode
& FB_VMODE_DOUBLE
) {
444 ytotal
= yres
+ lower
+ vslen
+ upper
;
455 FAIL("ytotal too big");
457 FAIL("vslen too big");
458 par
->crtc
[VGA_CRTC_V_TOTAL
] = ytotal
- 2;
459 r7
= 0x10; /* disable linecompare */
460 if (ytotal
& 0x100) r7
|= 0x01;
461 if (ytotal
& 0x200) r7
|= 0x20;
462 par
->crtc
[VGA_CRTC_PRESET_ROW
] = 0;
463 par
->crtc
[VGA_CRTC_MAX_SCAN
] = 0x40; /* 1 scanline, no linecmp */
464 if (var
->vmode
& FB_VMODE_DOUBLE
)
465 par
->crtc
[VGA_CRTC_MAX_SCAN
] |= 0x80;
466 par
->crtc
[VGA_CRTC_CURSOR_START
] = 0x20;
467 par
->crtc
[VGA_CRTC_CURSOR_END
] = 0x00;
468 if ((mode
& (MODE_CFB
| MODE_8BPP
)) == MODE_CFB
)
470 pos
= yoffset
* vxres
+ (xoffset
>> shift
);
471 par
->crtc
[VGA_CRTC_START_HI
] = pos
>> 8;
472 par
->crtc
[VGA_CRTC_START_LO
] = pos
& 0xFF;
473 par
->crtc
[VGA_CRTC_CURSOR_HI
] = 0x00;
474 par
->crtc
[VGA_CRTC_CURSOR_LO
] = 0x00;
476 par
->crtc
[VGA_CRTC_V_DISP_END
] = pos
& 0xFF;
477 par
->crtc
[VGA_CRTC_V_BLANK_START
] = pos
& 0xFF;
479 r7
|= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
481 r7
|= 0x40; /* 0x40 -> DISP_END */
482 par
->crtc
[VGA_CRTC_MAX_SCAN
] |= 0x20; /* BLANK_START */
485 par
->crtc
[VGA_CRTC_V_SYNC_START
] = pos
& 0xFF;
491 par
->crtc
[VGA_CRTC_V_SYNC_END
] = (pos
& 0x0F) & ~0x10; /* disabled IRQ */
492 pos
+= upper
- 1; /* blank_end + 1 <= ytotal + 2 */
493 par
->crtc
[VGA_CRTC_V_BLANK_END
] = pos
& 0xFF; /* 0x7F for original VGA,
494 but some SVGA chips requires all 8 bits to set */
496 FAIL("vxres too long");
497 par
->crtc
[VGA_CRTC_OFFSET
] = vxres
>> 1;
498 if (mode
& MODE_SKIP4
)
499 par
->crtc
[VGA_CRTC_UNDERLINE
] = 0x5F; /* 256, cfb8 */
501 par
->crtc
[VGA_CRTC_UNDERLINE
] = 0x1F; /* 16, vgap */
502 par
->crtc
[VGA_CRTC_MODE
] = rMode
| ((mode
& MODE_TEXT
) ? 0xA3 : 0xE3);
503 par
->crtc
[VGA_CRTC_LINE_COMPARE
] = 0xFF;
504 par
->crtc
[VGA_CRTC_OVERFLOW
] = r7
;
506 par
->vss
= 0x00; /* 3DA */
508 par
->misc
= 0xE3; /* enable CPU, ports 0x3Dx, positive sync */
509 if (var
->sync
& FB_SYNC_HOR_HIGH_ACT
)
511 if (var
->sync
& FB_SYNC_VERT_HIGH_ACT
)
516 if (mode
& MODE_8BPP
)
517 /* pixel clock == vga clock / 2 */
518 vga16fb_clock_chip(par
, var
->pixclock
, info
, 1, 2);
520 /* pixel clock == vga clock */
521 vga16fb_clock_chip(par
, var
->pixclock
, info
, 1, 1);
523 var
->red
.offset
= var
->green
.offset
= var
->blue
.offset
=
524 var
->transp
.offset
= 0;
525 var
->red
.length
= var
->green
.length
= var
->blue
.length
=
526 (par
->isVGA
) ? 6 : 2;
527 var
->transp
.length
= 0;
528 var
->activate
= FB_ACTIVATE_NOW
;
531 var
->accel_flags
= 0;
536 static int vga16fb_set_par(struct fb_info
*info
)
538 struct vga16fb_par
*par
= (struct vga16fb_par
*) info
->par
;
544 seq
[VGA_SEQ_CLOCK_MODE
] = 0x01 | par
->clkdiv
;
545 if (par
->mode
& MODE_TEXT
)
546 seq
[VGA_SEQ_PLANE_WRITE
] = 0x03;
548 seq
[VGA_SEQ_PLANE_WRITE
] = 0x0F;
549 seq
[VGA_SEQ_CHARACTER_MAP
] = 0x00;
550 if (par
->mode
& MODE_TEXT
)
551 seq
[VGA_SEQ_MEMORY_MODE
] = 0x03;
552 else if (par
->mode
& MODE_SKIP4
)
553 seq
[VGA_SEQ_MEMORY_MODE
] = 0x0E;
555 seq
[VGA_SEQ_MEMORY_MODE
] = 0x06;
557 gdc
[VGA_GFX_SR_VALUE
] = 0x00;
558 gdc
[VGA_GFX_SR_ENABLE
] = 0x00;
559 gdc
[VGA_GFX_COMPARE_VALUE
] = 0x00;
560 gdc
[VGA_GFX_DATA_ROTATE
] = 0x00;
561 gdc
[VGA_GFX_PLANE_READ
] = 0;
562 if (par
->mode
& MODE_TEXT
) {
563 gdc
[VGA_GFX_MODE
] = 0x10;
564 gdc
[VGA_GFX_MISC
] = 0x06;
566 if (par
->mode
& MODE_CFB
)
567 gdc
[VGA_GFX_MODE
] = 0x40;
569 gdc
[VGA_GFX_MODE
] = 0x00;
570 gdc
[VGA_GFX_MISC
] = 0x05;
572 gdc
[VGA_GFX_COMPARE_MASK
] = 0x0F;
573 gdc
[VGA_GFX_BIT_MASK
] = 0xFF;
575 for (i
= 0x00; i
< 0x10; i
++)
577 if (par
->mode
& MODE_TEXT
)
578 atc
[VGA_ATC_MODE
] = 0x04;
579 else if (par
->mode
& MODE_8BPP
)
580 atc
[VGA_ATC_MODE
] = 0x41;
582 atc
[VGA_ATC_MODE
] = 0x81;
583 atc
[VGA_ATC_OVERSCAN
] = 0x00; /* 0 for EGA, 0xFF for VGA */
584 atc
[VGA_ATC_PLANE_ENABLE
] = 0x0F;
585 if (par
->mode
& MODE_8BPP
)
586 atc
[VGA_ATC_PEL
] = (info
->var
.xoffset
& 3) << 1;
588 atc
[VGA_ATC_PEL
] = info
->var
.xoffset
& 7;
589 atc
[VGA_ATC_COLOR_PAGE
] = 0x00;
591 if (par
->mode
& MODE_TEXT
) {
592 fh
= 16; // FIXME !!! Fudge font height.
593 par
->crtc
[VGA_CRTC_MAX_SCAN
] = (par
->crtc
[VGA_CRTC_MAX_SCAN
]
597 vga_io_w(VGA_MIS_W
, vga_io_r(VGA_MIS_R
) | 0x01);
599 /* Enable graphics register modification */
601 vga_io_w(EGA_GFX_E0
, 0x00);
602 vga_io_w(EGA_GFX_E1
, 0x01);
605 /* update misc output register */
606 vga_io_w(VGA_MIS_W
, par
->misc
);
608 /* synchronous reset on */
609 vga_io_wseq(0x00, 0x01);
612 vga_io_w(VGA_PEL_MSK
, par
->pel_msk
);
614 /* write sequencer registers */
615 vga_io_wseq(VGA_SEQ_CLOCK_MODE
, seq
[VGA_SEQ_CLOCK_MODE
] | 0x20);
616 for (i
= 2; i
< VGA_SEQ_C
; i
++) {
617 vga_io_wseq(i
, seq
[i
]);
620 /* synchronous reset off */
621 vga_io_wseq(0x00, 0x03);
623 /* deprotect CRT registers 0-7 */
624 vga_io_wcrt(VGA_CRTC_V_SYNC_END
, par
->crtc
[VGA_CRTC_V_SYNC_END
]);
626 /* write CRT registers */
627 for (i
= 0; i
< VGA_CRTC_REGS
; i
++) {
628 vga_io_wcrt(i
, par
->crtc
[i
]);
631 /* write graphics controller registers */
632 for (i
= 0; i
< VGA_GFX_C
; i
++) {
633 vga_io_wgfx(i
, gdc
[i
]);
636 /* write attribute controller registers */
637 for (i
= 0; i
< VGA_ATT_C
; i
++) {
638 vga_io_r(VGA_IS1_RC
); /* reset flip-flop */
639 vga_io_wattr(i
, atc
[i
]);
642 /* Wait for screen to stabilize. */
645 vga_io_wseq(VGA_SEQ_CLOCK_MODE
, seq
[VGA_SEQ_CLOCK_MODE
]);
647 vga_io_r(VGA_IS1_RC
);
648 vga_io_w(VGA_ATT_IW
, 0x20);
650 vga16fb_update_fix(info
);
654 static void ega16_setpalette(int regno
, unsigned red
, unsigned green
, unsigned blue
)
656 static unsigned char map
[] = { 000, 001, 010, 011 };
661 val
= map
[red
>>14] | ((map
[green
>>14]) << 1) | ((map
[blue
>>14]) << 2);
662 vga_io_r(VGA_IS1_RC
); /* ! 0x3BA */
663 vga_io_wattr(regno
, val
);
664 vga_io_r(VGA_IS1_RC
); /* some clones need it */
665 vga_io_w(VGA_ATT_IW
, 0x20); /* unblank screen */
668 static void vga16_setpalette(int regno
, unsigned red
, unsigned green
, unsigned blue
)
670 outb(regno
, dac_reg
);
671 outb(red
>> 10, dac_val
);
672 outb(green
>> 10, dac_val
);
673 outb(blue
>> 10, dac_val
);
676 static int vga16fb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
677 unsigned blue
, unsigned transp
,
678 struct fb_info
*info
)
680 struct vga16fb_par
*par
= (struct vga16fb_par
*) info
->par
;
684 * Set a single color register. The values supplied are
685 * already rounded down to the hardware's capabilities
686 * (according to the entries in the `var' structure). Return
687 * != 0 for invalid regno.
693 gray
= info
->var
.grayscale
;
696 /* gray = 0.30*R + 0.59*G + 0.11*B */
697 red
= green
= blue
= (red
* 77 + green
* 151 + blue
* 28) >> 8;
700 vga16_setpalette(regno
,red
,green
,blue
);
702 ega16_setpalette(regno
,red
,green
,blue
);
706 static int vga16fb_pan_display(struct fb_var_screeninfo
*var
,
707 struct fb_info
*info
)
709 if (var
->xoffset
+ info
->var
.xres
> info
->var
.xres_virtual
||
710 var
->yoffset
+ info
->var
.yres
> info
->var
.yres_virtual
)
713 vga16fb_pan_var(info
, var
);
715 info
->var
.xoffset
= var
->xoffset
;
716 info
->var
.yoffset
= var
->yoffset
;
717 info
->var
.vmode
&= ~FB_VMODE_YWRAP
;
721 /* The following VESA blanking code is taken from vgacon.c. The VGA
722 blanking code was originally by Huang shi chao, and modified by
723 Christoph Rimek (chrimek@toppoint.de) and todd j. derr
724 (tjd@barefoot.org) for Linux. */
725 #define attrib_port VGA_ATC_IW
726 #define seq_port_reg VGA_SEQ_I
727 #define seq_port_val VGA_SEQ_D
728 #define gr_port_reg VGA_GFX_I
729 #define gr_port_val VGA_GFX_D
730 #define video_misc_rd VGA_MIS_R
731 #define video_misc_wr VGA_MIS_W
732 #define vga_video_port_reg VGA_CRT_IC
733 #define vga_video_port_val VGA_CRT_DC
735 static void vga_vesa_blank(struct vga16fb_par
*par
, int mode
)
737 unsigned char SeqCtrlIndex
;
738 unsigned char CrtCtrlIndex
;
741 SeqCtrlIndex
= vga_io_r(seq_port_reg
);
742 CrtCtrlIndex
= vga_io_r(vga_video_port_reg
);
744 /* save original values of VGA controller registers */
745 if(!par
->vesa_blanked
) {
746 par
->vga_state
.CrtMiscIO
= vga_io_r(video_misc_rd
);
749 par
->vga_state
.HorizontalTotal
= vga_io_rcrt(0x00); /* HorizontalTotal */
750 par
->vga_state
.HorizDisplayEnd
= vga_io_rcrt(0x01); /* HorizDisplayEnd */
751 par
->vga_state
.StartHorizRetrace
= vga_io_rcrt(0x04); /* StartHorizRetrace */
752 par
->vga_state
.EndHorizRetrace
= vga_io_rcrt(0x05); /* EndHorizRetrace */
753 par
->vga_state
.Overflow
= vga_io_rcrt(0x07); /* Overflow */
754 par
->vga_state
.StartVertRetrace
= vga_io_rcrt(0x10); /* StartVertRetrace */
755 par
->vga_state
.EndVertRetrace
= vga_io_rcrt(0x11); /* EndVertRetrace */
756 par
->vga_state
.ModeControl
= vga_io_rcrt(0x17); /* ModeControl */
757 par
->vga_state
.ClockingMode
= vga_io_rseq(0x01); /* ClockingMode */
760 /* assure that video is enabled */
761 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
763 vga_io_wseq(0x01, par
->vga_state
.ClockingMode
| 0x20);
765 /* test for vertical retrace in process.... */
766 if ((par
->vga_state
.CrtMiscIO
& 0x80) == 0x80)
767 vga_io_w(video_misc_wr
, par
->vga_state
.CrtMiscIO
& 0xef);
770 * Set <End of vertical retrace> to minimum (0) and
771 * <Start of vertical Retrace> to maximum (incl. overflow)
772 * Result: turn off vertical sync (VSync) pulse.
774 if (mode
& FB_BLANK_VSYNC_SUSPEND
) {
775 outb_p(0x10,vga_video_port_reg
); /* StartVertRetrace */
776 outb_p(0xff,vga_video_port_val
); /* maximum value */
777 outb_p(0x11,vga_video_port_reg
); /* EndVertRetrace */
778 outb_p(0x40,vga_video_port_val
); /* minimum (bits 0..3) */
779 outb_p(0x07,vga_video_port_reg
); /* Overflow */
780 outb_p(par
->vga_state
.Overflow
| 0x84,vga_video_port_val
); /* bits 9,10 of vert. retrace */
783 if (mode
& FB_BLANK_HSYNC_SUSPEND
) {
785 * Set <End of horizontal retrace> to minimum (0) and
786 * <Start of horizontal Retrace> to maximum
787 * Result: turn off horizontal sync (HSync) pulse.
789 outb_p(0x04,vga_video_port_reg
); /* StartHorizRetrace */
790 outb_p(0xff,vga_video_port_val
); /* maximum */
791 outb_p(0x05,vga_video_port_reg
); /* EndHorizRetrace */
792 outb_p(0x00,vga_video_port_val
); /* minimum (0) */
795 /* restore both index registers */
796 outb_p(SeqCtrlIndex
,seq_port_reg
);
797 outb_p(CrtCtrlIndex
,vga_video_port_reg
);
801 static void vga_vesa_unblank(struct vga16fb_par
*par
)
803 unsigned char SeqCtrlIndex
;
804 unsigned char CrtCtrlIndex
;
807 SeqCtrlIndex
= vga_io_r(seq_port_reg
);
808 CrtCtrlIndex
= vga_io_r(vga_video_port_reg
);
810 /* restore original values of VGA controller registers */
811 vga_io_w(video_misc_wr
, par
->vga_state
.CrtMiscIO
);
813 /* HorizontalTotal */
814 vga_io_wcrt(0x00, par
->vga_state
.HorizontalTotal
);
815 /* HorizDisplayEnd */
816 vga_io_wcrt(0x01, par
->vga_state
.HorizDisplayEnd
);
817 /* StartHorizRetrace */
818 vga_io_wcrt(0x04, par
->vga_state
.StartHorizRetrace
);
819 /* EndHorizRetrace */
820 vga_io_wcrt(0x05, par
->vga_state
.EndHorizRetrace
);
822 vga_io_wcrt(0x07, par
->vga_state
.Overflow
);
823 /* StartVertRetrace */
824 vga_io_wcrt(0x10, par
->vga_state
.StartVertRetrace
);
826 vga_io_wcrt(0x11, par
->vga_state
.EndVertRetrace
);
828 vga_io_wcrt(0x17, par
->vga_state
.ModeControl
);
830 vga_io_wseq(0x01, par
->vga_state
.ClockingMode
);
832 /* restore index/control registers */
833 vga_io_w(seq_port_reg
, SeqCtrlIndex
);
834 vga_io_w(vga_video_port_reg
, CrtCtrlIndex
);
838 static void vga_pal_blank(void)
842 for (i
=0; i
<16; i
++) {
843 outb_p (i
, dac_reg
) ;
844 outb_p (0, dac_val
) ;
845 outb_p (0, dac_val
) ;
846 outb_p (0, dac_val
) ;
850 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
851 static int vga16fb_blank(int blank
, struct fb_info
*info
)
853 struct vga16fb_par
*par
= (struct vga16fb_par
*) info
->par
;
856 case FB_BLANK_UNBLANK
: /* Unblank */
857 if (par
->vesa_blanked
) {
858 vga_vesa_unblank(par
);
859 par
->vesa_blanked
= 0;
861 if (par
->palette_blanked
) {
862 par
->palette_blanked
= 0;
865 case FB_BLANK_NORMAL
: /* blank */
867 par
->palette_blanked
= 1;
869 default: /* VESA blanking */
870 vga_vesa_blank(par
, blank
);
871 par
->vesa_blanked
= 1;
877 static void vga_8planes_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
879 u32 dx
= rect
->dx
, width
= rect
->width
;
880 char oldindex
= getindex();
881 char oldmode
= setmode(0x40);
882 char oldmask
= selectmask();
883 int line_ofs
, height
;
888 where
= info
->screen_base
+ dx
+ rect
->dy
* info
->fix
.line_length
;
890 if (rect
->rop
== ROP_COPY
) {
895 line_ofs
= info
->fix
.line_length
- width
;
898 height
= rect
->height
;
903 /* we can do memset... */
904 for (x
= width
; x
> 0; --x
) {
905 writeb(rect
->color
, where
);
911 char oldcolor
= setcolor(0xf);
917 for (y
= 0; y
< rect
->height
; y
++) {
920 where
+= info
->fix
.line_length
;
931 static void vga16fb_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
933 int x
, x2
, y2
, vxres
, vyres
, width
, height
, line_ofs
;
936 vxres
= info
->var
.xres_virtual
;
937 vyres
= info
->var
.yres_virtual
;
939 if (!rect
->width
|| !rect
->height
|| rect
->dx
> vxres
|| rect
->dy
> vyres
)
942 /* We could use hardware clipping but on many cards you get around
943 * hardware clipping by writing to framebuffer directly. */
945 x2
= rect
->dx
+ rect
->width
;
946 y2
= rect
->dy
+ rect
->height
;
947 x2
= x2
< vxres
? x2
: vxres
;
948 y2
= y2
< vyres
? y2
: vyres
;
949 width
= x2
- rect
->dx
;
951 switch (info
->fix
.type
) {
952 case FB_TYPE_VGA_PLANES
:
953 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
955 height
= y2
- rect
->dy
;
956 width
= rect
->width
/8;
958 line_ofs
= info
->fix
.line_length
- width
;
959 dst
= info
->screen_base
+ (rect
->dx
/8) + rect
->dy
* info
->fix
.line_length
;
966 setcolor(rect
->color
);
972 for (x
= 0; x
< width
; x
++) {
988 for (x
= 0; x
< width
; x
++) {
997 vga_8planes_fillrect(info
, rect
);
999 case FB_TYPE_PACKED_PIXELS
:
1001 cfb_fillrect(info
, rect
);
1006 static void vga_8planes_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
1008 char oldindex
= getindex();
1009 char oldmode
= setmode(0x41);
1010 char oldop
= setop(0);
1011 char oldsr
= setsr(0xf);
1012 int height
, line_ofs
, x
;
1017 height
= area
->height
;
1021 width
= area
->width
/ 4;
1023 if (area
->dy
< area
->sy
|| (area
->dy
== area
->sy
&& dx
< sx
)) {
1024 line_ofs
= info
->fix
.line_length
- width
;
1025 dest
= info
->screen_base
+ dx
+ area
->dy
* info
->fix
.line_length
;
1026 src
= info
->screen_base
+ sx
+ area
->sy
* info
->fix
.line_length
;
1028 for (x
= 0; x
< width
; x
++) {
1038 line_ofs
= info
->fix
.line_length
- width
;
1039 dest
= info
->screen_base
+ dx
+ width
+
1040 (area
->dy
+ height
- 1) * info
->fix
.line_length
;
1041 src
= info
->screen_base
+ sx
+ width
+
1042 (area
->sy
+ height
- 1) * info
->fix
.line_length
;
1044 for (x
= 0; x
< width
; x
++) {
1061 static void vga16fb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
1063 u32 dx
= area
->dx
, dy
= area
->dy
, sx
= area
->sx
, sy
= area
->sy
;
1064 int x
, x2
, y2
, old_dx
, old_dy
, vxres
, vyres
;
1065 int height
, width
, line_ofs
;
1066 char __iomem
*dst
= NULL
;
1067 char __iomem
*src
= NULL
;
1069 vxres
= info
->var
.xres_virtual
;
1070 vyres
= info
->var
.yres_virtual
;
1072 if (area
->dx
> vxres
|| area
->sx
> vxres
|| area
->dy
> vyres
||
1076 /* clip the destination */
1081 * We could use hardware clipping but on many cards you get around
1082 * hardware clipping by writing to framebuffer directly.
1084 x2
= area
->dx
+ area
->width
;
1085 y2
= area
->dy
+ area
->height
;
1086 dx
= area
->dx
> 0 ? area
->dx
: 0;
1087 dy
= area
->dy
> 0 ? area
->dy
: 0;
1088 x2
= x2
< vxres
? x2
: vxres
;
1089 y2
= y2
< vyres
? y2
: vyres
;
1093 /* update sx1,sy1 */
1094 sx
+= (dx
- old_dx
);
1095 sy
+= (dy
- old_dy
);
1097 /* the source must be completely inside the virtual screen */
1098 if (sx
< 0 || sy
< 0 || (sx
+ width
) > vxres
|| (sy
+ height
) > vyres
)
1101 switch (info
->fix
.type
) {
1102 case FB_TYPE_VGA_PLANES
:
1103 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
1106 line_ofs
= info
->fix
.line_length
- width
;
1112 if (dy
< sy
|| (dy
== sy
&& dx
< sx
)) {
1113 dst
= info
->screen_base
+ (dx
/8) + dy
* info
->fix
.line_length
;
1114 src
= info
->screen_base
+ (sx
/8) + sy
* info
->fix
.line_length
;
1116 for (x
= 0; x
< width
; x
++) {
1126 dst
= info
->screen_base
+ (dx
/8) + width
+
1127 (dy
+ height
- 1) * info
->fix
.line_length
;
1128 src
= info
->screen_base
+ (sx
/8) + width
+
1129 (sy
+ height
- 1) * info
->fix
.line_length
;
1131 for (x
= 0; x
< width
; x
++) {
1142 vga_8planes_copyarea(info
, area
);
1144 case FB_TYPE_PACKED_PIXELS
:
1146 cfb_copyarea(info
, area
);
1151 #ifdef __LITTLE_ENDIAN
1152 static unsigned int transl_l
[] =
1153 {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF};
1154 static unsigned int transl_h
[] =
1155 {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00,
1156 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00};
1159 static unsigned int transl_h
[] =
1160 {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF};
1161 static unsigned int transl_l
[] =
1162 {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00,
1163 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00};
1165 #error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1169 static void vga_8planes_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
1171 char oldindex
= getindex();
1172 char oldmode
= setmode(0x40);
1173 char oldop
= setop(0);
1174 char oldsr
= setsr(0);
1175 char oldmask
= selectmask();
1176 const char *cdat
= image
->data
;
1178 char __iomem
*where
;
1182 where
= info
->screen_base
+ dx
+ image
->dy
* info
->fix
.line_length
;
1185 writeb(image
->bg_color
, where
);
1188 setmask(image
->fg_color
^ image
->bg_color
);
1191 for (y
= 0; y
< image
->height
; y
++, where
+= info
->fix
.line_length
)
1192 writew(transl_h
[cdat
[y
]&0xF] | transl_l
[cdat
[y
] >> 4], where
);
1200 static void vga_imageblit_expand(struct fb_info
*info
, const struct fb_image
*image
)
1202 char __iomem
*where
= info
->screen_base
+ (image
->dx
/8) +
1203 image
->dy
* info
->fix
.line_length
;
1204 struct vga16fb_par
*par
= (struct vga16fb_par
*) info
->par
;
1205 char *cdat
= (char *) image
->data
;
1209 switch (info
->fix
.type
) {
1210 case FB_TYPE_VGA_PLANES
:
1211 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
1216 setcolor(image
->fg_color
);
1220 writeb(image
->bg_color
, where
);
1222 readb(where
); /* fill latches */
1225 for (y
= 0; y
< image
->height
; y
++) {
1227 for (x
= image
->width
/8; x
--;)
1228 writeb(*cdat
++, dst
++);
1229 where
+= info
->fix
.line_length
;
1236 setcolor(image
->bg_color
);
1240 for (y
= 0; y
< image
->height
; y
++) {
1242 for (x
=image
->width
/8; x
--;){
1244 setcolor(image
->fg_color
);
1251 where
+= info
->fix
.line_length
;
1255 vga_8planes_imageblit(info
, image
);
1257 case FB_TYPE_PACKED_PIXELS
:
1259 cfb_imageblit(info
, image
);
1264 static void vga_imageblit_color(struct fb_info
*info
, const struct fb_image
*image
)
1269 struct vga16fb_par
*par
= (struct vga16fb_par
*) info
->par
;
1270 char __iomem
*where
=
1271 info
->screen_base
+ image
->dy
* info
->fix
.line_length
+
1273 const char *cdat
= image
->data
;
1277 switch (info
->fix
.type
) {
1278 case FB_TYPE_VGA_PLANES
:
1279 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
&&
1285 for (y
= 0; y
< image
->height
; y
++) {
1286 for (x
= 0; x
< image
->width
; x
++) {
1291 setmask(1 << (7 - (x
% 8)));
1297 where
+= info
->fix
.line_length
;
1301 case FB_TYPE_PACKED_PIXELS
:
1302 cfb_imageblit(info
, image
);
1309 static void vga16fb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
1311 if (image
->depth
== 1)
1312 vga_imageblit_expand(info
, image
);
1314 vga_imageblit_color(info
, image
);
1317 static struct fb_ops vga16fb_ops
= {
1318 .owner
= THIS_MODULE
,
1319 .fb_open
= vga16fb_open
,
1320 .fb_release
= vga16fb_release
,
1321 .fb_check_var
= vga16fb_check_var
,
1322 .fb_set_par
= vga16fb_set_par
,
1323 .fb_setcolreg
= vga16fb_setcolreg
,
1324 .fb_pan_display
= vga16fb_pan_display
,
1325 .fb_blank
= vga16fb_blank
,
1326 .fb_fillrect
= vga16fb_fillrect
,
1327 .fb_copyarea
= vga16fb_copyarea
,
1328 .fb_imageblit
= vga16fb_imageblit
,
1329 .fb_cursor
= soft_cursor
,
1333 static int vga16fb_setup(char *options
)
1337 if (!options
|| !*options
)
1340 while ((this_opt
= strsep(&options
, ",")) != NULL
) {
1341 if (!*this_opt
) continue;
1347 static int __init
vga16fb_init(void)
1352 char *option
= NULL
;
1354 if (fb_get_options("vga16fb", &option
))
1357 vga16fb_setup(option
);
1359 printk(KERN_DEBUG
"vga16fb: initializing\n");
1361 /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
1363 vga16fb
.screen_base
= (void __iomem
*)VGA_MAP_MEM(VGA_FB_PHYS
);
1364 if (!vga16fb
.screen_base
) {
1365 printk(KERN_ERR
"vga16fb: unable to map device\n");
1369 printk(KERN_INFO
"vga16fb: mapped to 0x%p\n", vga16fb
.screen_base
);
1371 vga16_par
.isVGA
= ORIG_VIDEO_ISVGA
;
1372 vga16_par
.palette_blanked
= 0;
1373 vga16_par
.vesa_blanked
= 0;
1375 i
= vga16_par
.isVGA
? 6 : 2;
1377 vga16fb_defined
.red
.length
= i
;
1378 vga16fb_defined
.green
.length
= i
;
1379 vga16fb_defined
.blue
.length
= i
;
1381 /* name should not depend on EGA/VGA */
1382 vga16fb
.fbops
= &vga16fb_ops
;
1383 vga16fb
.var
= vga16fb_defined
;
1384 vga16fb
.fix
= vga16fb_fix
;
1385 vga16fb
.par
= &vga16_par
;
1386 vga16fb
.flags
= FBINFO_FLAG_DEFAULT
|
1387 FBINFO_HWACCEL_YPAN
;
1389 i
= (vga16fb_defined
.bits_per_pixel
== 8) ? 256 : 16;
1390 ret
= fb_alloc_cmap(&vga16fb
.cmap
, i
, 0);
1392 printk(KERN_ERR
"vga16fb: unable to allocate colormap\n");
1394 goto err_alloc_cmap
;
1397 if (vga16fb_check_var(&vga16fb
.var
, &vga16fb
)) {
1398 printk(KERN_ERR
"vga16fb: unable to validate variable\n");
1403 vga16fb_update_fix(&vga16fb
);
1405 if (register_framebuffer(&vga16fb
) < 0) {
1406 printk(KERN_ERR
"vga16fb: unable to register framebuffer\n");
1411 printk(KERN_INFO
"fb%d: %s frame buffer device\n",
1412 vga16fb
.node
, vga16fb
.fix
.id
);
1417 fb_dealloc_cmap(&vga16fb
.cmap
);
1419 iounmap(vga16fb
.screen_base
);
1424 static void __exit
vga16fb_exit(void)
1426 unregister_framebuffer(&vga16fb
);
1427 iounmap(vga16fb
.screen_base
);
1428 fb_dealloc_cmap(&vga16fb
.cmap
);
1429 /* XXX unshare VGA regions */
1432 MODULE_LICENSE("GPL");
1433 module_init(vga16fb_init
);
1434 module_exit(vga16fb_exit
);
1438 * Overrides for Emacs so that we follow Linus's tabbing style.
1439 * ---------------------------------------------------------------------------