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/slab.h>
19 #include <linux/delay.h>
21 #include <linux/ioport.h>
22 #include <linux/init.h>
23 #include <linux/platform_device.h>
24 #include <linux/screen_info.h>
27 #include <video/vga.h>
29 #define GRAPHICS_ADDR_REG VGA_GFX_I /* Graphics address register. */
30 #define GRAPHICS_DATA_REG VGA_GFX_D /* Graphics data register. */
32 #define SET_RESET_INDEX VGA_GFX_SR_VALUE /* Set/Reset Register index. */
33 #define ENABLE_SET_RESET_INDEX VGA_GFX_SR_ENABLE /* Enable Set/Reset Register index. */
34 #define DATA_ROTATE_INDEX VGA_GFX_DATA_ROTATE /* Data Rotate Register index. */
35 #define GRAPHICS_MODE_INDEX VGA_GFX_MODE /* Graphics Mode Register index. */
36 #define BIT_MASK_INDEX VGA_GFX_BIT_MASK /* Bit Mask Register index. */
38 #define dac_reg (VGA_PEL_IW)
39 #define dac_val (VGA_PEL_D)
41 #define VGA_FB_PHYS 0xA0000
42 #define VGA_FB_PHYS_LEN 65536
49 /* --------------------------------------------------------------------- */
56 /* structure holding original VGA register settings when the
59 unsigned char SeqCtrlIndex
; /* Sequencer Index reg. */
60 unsigned char CrtCtrlIndex
; /* CRT-Contr. Index reg. */
61 unsigned char CrtMiscIO
; /* Miscellaneous register */
62 unsigned char HorizontalTotal
; /* CRT-Controller:00h */
63 unsigned char HorizDisplayEnd
; /* CRT-Controller:01h */
64 unsigned char StartHorizRetrace
;/* CRT-Controller:04h */
65 unsigned char EndHorizRetrace
; /* CRT-Controller:05h */
66 unsigned char Overflow
; /* CRT-Controller:07h */
67 unsigned char StartVertRetrace
; /* CRT-Controller:10h */
68 unsigned char EndVertRetrace
; /* CRT-Controller:11h */
69 unsigned char ModeControl
; /* CRT-Controller:17h */
70 unsigned char ClockingMode
; /* Seq-Controller:01h */
72 struct vgastate state
;
73 struct mutex open_lock
;
74 unsigned int ref_count
;
75 int palette_blanked
, vesa_blanked
, mode
, isVGA
;
76 u8 misc
, pel_msk
, vss
, clkdiv
;
80 /* --------------------------------------------------------------------- */
82 static struct fb_var_screeninfo vga16fb_defined __initdata
= {
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
= 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
,
268 static const struct {
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
= info
->par
;
305 mutex_lock(&par
->open_lock
);
306 if (!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
);
313 mutex_unlock(&par
->open_lock
);
318 static int vga16fb_release(struct fb_info
*info
, int user
)
320 struct vga16fb_par
*par
= info
->par
;
322 mutex_lock(&par
->open_lock
);
323 if (!par
->ref_count
) {
324 mutex_unlock(&par
->open_lock
);
327 if (par
->ref_count
== 1)
328 restore_vga(&par
->state
);
330 mutex_unlock(&par
->open_lock
);
335 static int vga16fb_check_var(struct fb_var_screeninfo
*var
,
336 struct fb_info
*info
)
338 struct vga16fb_par
*par
= info
->par
;
339 u32 xres
, right
, hslen
, left
, xtotal
;
340 u32 yres
, lower
, vslen
, upper
, ytotal
;
341 u32 vxres
, xoffset
, vyres
, yoffset
;
350 if (var
->bits_per_pixel
== 4) {
355 mode
= MODE_SKIP4
| MODE_CFB
;
363 } else if (var
->bits_per_pixel
== 8) {
365 return -EINVAL
; /* no support on EGA */
368 mode
= MODE_8BPP
| MODE_CFB
;
371 mode
= MODE_SKIP4
| MODE_8BPP
| MODE_CFB
;
377 xres
= (var
->xres
+ 7) & ~7;
378 vxres
= (var
->xres_virtual
+ 0xF) & ~0xF;
379 xoffset
= (var
->xoffset
+ 7) & ~7;
380 left
= (var
->left_margin
+ 7) & ~7;
381 right
= (var
->right_margin
+ 7) & ~7;
382 hslen
= (var
->hsync_len
+ 7) & ~7;
386 if (xres
+ xoffset
> vxres
)
387 xoffset
= vxres
- xres
;
390 var
->right_margin
= right
;
391 var
->hsync_len
= hslen
;
392 var
->left_margin
= left
;
393 var
->xres_virtual
= vxres
;
394 var
->xoffset
= xoffset
;
401 xtotal
= xres
+ right
+ hslen
+ left
;
403 FAIL("xtotal too big");
405 FAIL("hslen too big");
406 if (right
+ hslen
+ left
> 64)
407 FAIL("hblank too big");
408 par
->crtc
[VGA_CRTC_H_TOTAL
] = xtotal
- 5;
409 par
->crtc
[VGA_CRTC_H_BLANK_START
] = xres
- 1;
410 par
->crtc
[VGA_CRTC_H_DISP
] = xres
- 1;
412 par
->crtc
[VGA_CRTC_H_SYNC_START
] = pos
;
414 par
->crtc
[VGA_CRTC_H_SYNC_END
] = pos
& 0x1F;
415 pos
+= left
- 2; /* blank_end + 2 <= total + 5 */
416 par
->crtc
[VGA_CRTC_H_BLANK_END
] = (pos
& 0x1F) | 0x80;
418 par
->crtc
[VGA_CRTC_H_SYNC_END
] |= 0x80;
421 lower
= var
->lower_margin
;
422 vslen
= var
->vsync_len
;
423 upper
= var
->upper_margin
;
424 vyres
= var
->yres_virtual
;
425 yoffset
= var
->yoffset
;
429 if (vxres
* vyres
> maxmem
) {
430 vyres
= maxmem
/ vxres
;
434 if (yoffset
+ yres
> vyres
)
435 yoffset
= vyres
- yres
;
437 var
->lower_margin
= lower
;
438 var
->vsync_len
= vslen
;
439 var
->upper_margin
= upper
;
440 var
->yres_virtual
= vyres
;
441 var
->yoffset
= yoffset
;
443 if (var
->vmode
& FB_VMODE_DOUBLE
) {
449 ytotal
= yres
+ lower
+ vslen
+ upper
;
460 FAIL("ytotal too big");
462 FAIL("vslen too big");
463 par
->crtc
[VGA_CRTC_V_TOTAL
] = ytotal
- 2;
464 r7
= 0x10; /* disable linecompare */
465 if (ytotal
& 0x100) r7
|= 0x01;
466 if (ytotal
& 0x200) r7
|= 0x20;
467 par
->crtc
[VGA_CRTC_PRESET_ROW
] = 0;
468 par
->crtc
[VGA_CRTC_MAX_SCAN
] = 0x40; /* 1 scanline, no linecmp */
469 if (var
->vmode
& FB_VMODE_DOUBLE
)
470 par
->crtc
[VGA_CRTC_MAX_SCAN
] |= 0x80;
471 par
->crtc
[VGA_CRTC_CURSOR_START
] = 0x20;
472 par
->crtc
[VGA_CRTC_CURSOR_END
] = 0x00;
473 if ((mode
& (MODE_CFB
| MODE_8BPP
)) == MODE_CFB
)
475 pos
= yoffset
* vxres
+ (xoffset
>> shift
);
476 par
->crtc
[VGA_CRTC_START_HI
] = pos
>> 8;
477 par
->crtc
[VGA_CRTC_START_LO
] = pos
& 0xFF;
478 par
->crtc
[VGA_CRTC_CURSOR_HI
] = 0x00;
479 par
->crtc
[VGA_CRTC_CURSOR_LO
] = 0x00;
481 par
->crtc
[VGA_CRTC_V_DISP_END
] = pos
& 0xFF;
482 par
->crtc
[VGA_CRTC_V_BLANK_START
] = pos
& 0xFF;
484 r7
|= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
486 r7
|= 0x40; /* 0x40 -> DISP_END */
487 par
->crtc
[VGA_CRTC_MAX_SCAN
] |= 0x20; /* BLANK_START */
490 par
->crtc
[VGA_CRTC_V_SYNC_START
] = pos
& 0xFF;
496 par
->crtc
[VGA_CRTC_V_SYNC_END
] = (pos
& 0x0F) & ~0x10; /* disabled IRQ */
497 pos
+= upper
- 1; /* blank_end + 1 <= ytotal + 2 */
498 par
->crtc
[VGA_CRTC_V_BLANK_END
] = pos
& 0xFF; /* 0x7F for original VGA,
499 but some SVGA chips requires all 8 bits to set */
501 FAIL("vxres too long");
502 par
->crtc
[VGA_CRTC_OFFSET
] = vxres
>> 1;
503 if (mode
& MODE_SKIP4
)
504 par
->crtc
[VGA_CRTC_UNDERLINE
] = 0x5F; /* 256, cfb8 */
506 par
->crtc
[VGA_CRTC_UNDERLINE
] = 0x1F; /* 16, vgap */
507 par
->crtc
[VGA_CRTC_MODE
] = rMode
| ((mode
& MODE_TEXT
) ? 0xA3 : 0xE3);
508 par
->crtc
[VGA_CRTC_LINE_COMPARE
] = 0xFF;
509 par
->crtc
[VGA_CRTC_OVERFLOW
] = r7
;
511 par
->vss
= 0x00; /* 3DA */
513 par
->misc
= 0xE3; /* enable CPU, ports 0x3Dx, positive sync */
514 if (var
->sync
& FB_SYNC_HOR_HIGH_ACT
)
516 if (var
->sync
& FB_SYNC_VERT_HIGH_ACT
)
521 if (mode
& MODE_8BPP
)
522 /* pixel clock == vga clock / 2 */
523 vga16fb_clock_chip(par
, var
->pixclock
, info
, 1, 2);
525 /* pixel clock == vga clock */
526 vga16fb_clock_chip(par
, var
->pixclock
, info
, 1, 1);
528 var
->red
.offset
= var
->green
.offset
= var
->blue
.offset
=
529 var
->transp
.offset
= 0;
530 var
->red
.length
= var
->green
.length
= var
->blue
.length
=
531 (par
->isVGA
) ? 6 : 2;
532 var
->transp
.length
= 0;
533 var
->activate
= FB_ACTIVATE_NOW
;
536 var
->accel_flags
= 0;
541 static int vga16fb_set_par(struct fb_info
*info
)
543 struct vga16fb_par
*par
= info
->par
;
549 seq
[VGA_SEQ_CLOCK_MODE
] = 0x01 | par
->clkdiv
;
550 if (par
->mode
& MODE_TEXT
)
551 seq
[VGA_SEQ_PLANE_WRITE
] = 0x03;
553 seq
[VGA_SEQ_PLANE_WRITE
] = 0x0F;
554 seq
[VGA_SEQ_CHARACTER_MAP
] = 0x00;
555 if (par
->mode
& MODE_TEXT
)
556 seq
[VGA_SEQ_MEMORY_MODE
] = 0x03;
557 else if (par
->mode
& MODE_SKIP4
)
558 seq
[VGA_SEQ_MEMORY_MODE
] = 0x0E;
560 seq
[VGA_SEQ_MEMORY_MODE
] = 0x06;
562 gdc
[VGA_GFX_SR_VALUE
] = 0x00;
563 gdc
[VGA_GFX_SR_ENABLE
] = 0x00;
564 gdc
[VGA_GFX_COMPARE_VALUE
] = 0x00;
565 gdc
[VGA_GFX_DATA_ROTATE
] = 0x00;
566 gdc
[VGA_GFX_PLANE_READ
] = 0;
567 if (par
->mode
& MODE_TEXT
) {
568 gdc
[VGA_GFX_MODE
] = 0x10;
569 gdc
[VGA_GFX_MISC
] = 0x06;
571 if (par
->mode
& MODE_CFB
)
572 gdc
[VGA_GFX_MODE
] = 0x40;
574 gdc
[VGA_GFX_MODE
] = 0x00;
575 gdc
[VGA_GFX_MISC
] = 0x05;
577 gdc
[VGA_GFX_COMPARE_MASK
] = 0x0F;
578 gdc
[VGA_GFX_BIT_MASK
] = 0xFF;
580 for (i
= 0x00; i
< 0x10; i
++)
582 if (par
->mode
& MODE_TEXT
)
583 atc
[VGA_ATC_MODE
] = 0x04;
584 else if (par
->mode
& MODE_8BPP
)
585 atc
[VGA_ATC_MODE
] = 0x41;
587 atc
[VGA_ATC_MODE
] = 0x81;
588 atc
[VGA_ATC_OVERSCAN
] = 0x00; /* 0 for EGA, 0xFF for VGA */
589 atc
[VGA_ATC_PLANE_ENABLE
] = 0x0F;
590 if (par
->mode
& MODE_8BPP
)
591 atc
[VGA_ATC_PEL
] = (info
->var
.xoffset
& 3) << 1;
593 atc
[VGA_ATC_PEL
] = info
->var
.xoffset
& 7;
594 atc
[VGA_ATC_COLOR_PAGE
] = 0x00;
596 if (par
->mode
& MODE_TEXT
) {
597 fh
= 16; // FIXME !!! Fudge font height.
598 par
->crtc
[VGA_CRTC_MAX_SCAN
] = (par
->crtc
[VGA_CRTC_MAX_SCAN
]
602 vga_io_w(VGA_MIS_W
, vga_io_r(VGA_MIS_R
) | 0x01);
604 /* Enable graphics register modification */
606 vga_io_w(EGA_GFX_E0
, 0x00);
607 vga_io_w(EGA_GFX_E1
, 0x01);
610 /* update misc output register */
611 vga_io_w(VGA_MIS_W
, par
->misc
);
613 /* synchronous reset on */
614 vga_io_wseq(0x00, 0x01);
617 vga_io_w(VGA_PEL_MSK
, par
->pel_msk
);
619 /* write sequencer registers */
620 vga_io_wseq(VGA_SEQ_CLOCK_MODE
, seq
[VGA_SEQ_CLOCK_MODE
] | 0x20);
621 for (i
= 2; i
< VGA_SEQ_C
; i
++) {
622 vga_io_wseq(i
, seq
[i
]);
625 /* synchronous reset off */
626 vga_io_wseq(0x00, 0x03);
628 /* deprotect CRT registers 0-7 */
629 vga_io_wcrt(VGA_CRTC_V_SYNC_END
, par
->crtc
[VGA_CRTC_V_SYNC_END
]);
631 /* write CRT registers */
632 for (i
= 0; i
< VGA_CRTC_REGS
; i
++) {
633 vga_io_wcrt(i
, par
->crtc
[i
]);
636 /* write graphics controller registers */
637 for (i
= 0; i
< VGA_GFX_C
; i
++) {
638 vga_io_wgfx(i
, gdc
[i
]);
641 /* write attribute controller registers */
642 for (i
= 0; i
< VGA_ATT_C
; i
++) {
643 vga_io_r(VGA_IS1_RC
); /* reset flip-flop */
644 vga_io_wattr(i
, atc
[i
]);
647 /* Wait for screen to stabilize. */
650 vga_io_wseq(VGA_SEQ_CLOCK_MODE
, seq
[VGA_SEQ_CLOCK_MODE
]);
652 vga_io_r(VGA_IS1_RC
);
653 vga_io_w(VGA_ATT_IW
, 0x20);
655 vga16fb_update_fix(info
);
659 static void ega16_setpalette(int regno
, unsigned red
, unsigned green
, unsigned blue
)
661 static const unsigned char map
[] = { 000, 001, 010, 011 };
666 val
= map
[red
>>14] | ((map
[green
>>14]) << 1) | ((map
[blue
>>14]) << 2);
667 vga_io_r(VGA_IS1_RC
); /* ! 0x3BA */
668 vga_io_wattr(regno
, val
);
669 vga_io_r(VGA_IS1_RC
); /* some clones need it */
670 vga_io_w(VGA_ATT_IW
, 0x20); /* unblank screen */
673 static void vga16_setpalette(int regno
, unsigned red
, unsigned green
, unsigned blue
)
675 outb(regno
, dac_reg
);
676 outb(red
>> 10, dac_val
);
677 outb(green
>> 10, dac_val
);
678 outb(blue
>> 10, dac_val
);
681 static int vga16fb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
682 unsigned blue
, unsigned transp
,
683 struct fb_info
*info
)
685 struct vga16fb_par
*par
= info
->par
;
689 * Set a single color register. The values supplied are
690 * already rounded down to the hardware's capabilities
691 * (according to the entries in the `var' structure). Return
692 * != 0 for invalid regno.
698 gray
= info
->var
.grayscale
;
701 /* gray = 0.30*R + 0.59*G + 0.11*B */
702 red
= green
= blue
= (red
* 77 + green
* 151 + blue
* 28) >> 8;
705 vga16_setpalette(regno
,red
,green
,blue
);
707 ega16_setpalette(regno
,red
,green
,blue
);
711 static int vga16fb_pan_display(struct fb_var_screeninfo
*var
,
712 struct fb_info
*info
)
714 vga16fb_pan_var(info
, var
);
718 /* The following VESA blanking code is taken from vgacon.c. The VGA
719 blanking code was originally by Huang shi chao, and modified by
720 Christoph Rimek (chrimek@toppoint.de) and todd j. derr
721 (tjd@barefoot.org) for Linux. */
722 #define attrib_port VGA_ATC_IW
723 #define seq_port_reg VGA_SEQ_I
724 #define seq_port_val VGA_SEQ_D
725 #define gr_port_reg VGA_GFX_I
726 #define gr_port_val VGA_GFX_D
727 #define video_misc_rd VGA_MIS_R
728 #define video_misc_wr VGA_MIS_W
729 #define vga_video_port_reg VGA_CRT_IC
730 #define vga_video_port_val VGA_CRT_DC
732 static void vga_vesa_blank(struct vga16fb_par
*par
, int mode
)
734 unsigned char SeqCtrlIndex
;
735 unsigned char CrtCtrlIndex
;
738 SeqCtrlIndex
= vga_io_r(seq_port_reg
);
739 CrtCtrlIndex
= vga_io_r(vga_video_port_reg
);
741 /* save original values of VGA controller registers */
742 if(!par
->vesa_blanked
) {
743 par
->vga_state
.CrtMiscIO
= vga_io_r(video_misc_rd
);
746 par
->vga_state
.HorizontalTotal
= vga_io_rcrt(0x00); /* HorizontalTotal */
747 par
->vga_state
.HorizDisplayEnd
= vga_io_rcrt(0x01); /* HorizDisplayEnd */
748 par
->vga_state
.StartHorizRetrace
= vga_io_rcrt(0x04); /* StartHorizRetrace */
749 par
->vga_state
.EndHorizRetrace
= vga_io_rcrt(0x05); /* EndHorizRetrace */
750 par
->vga_state
.Overflow
= vga_io_rcrt(0x07); /* Overflow */
751 par
->vga_state
.StartVertRetrace
= vga_io_rcrt(0x10); /* StartVertRetrace */
752 par
->vga_state
.EndVertRetrace
= vga_io_rcrt(0x11); /* EndVertRetrace */
753 par
->vga_state
.ModeControl
= vga_io_rcrt(0x17); /* ModeControl */
754 par
->vga_state
.ClockingMode
= vga_io_rseq(0x01); /* ClockingMode */
757 /* assure that video is enabled */
758 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
760 vga_io_wseq(0x01, par
->vga_state
.ClockingMode
| 0x20);
762 /* test for vertical retrace in process.... */
763 if ((par
->vga_state
.CrtMiscIO
& 0x80) == 0x80)
764 vga_io_w(video_misc_wr
, par
->vga_state
.CrtMiscIO
& 0xef);
767 * Set <End of vertical retrace> to minimum (0) and
768 * <Start of vertical Retrace> to maximum (incl. overflow)
769 * Result: turn off vertical sync (VSync) pulse.
771 if (mode
& FB_BLANK_VSYNC_SUSPEND
) {
772 outb_p(0x10,vga_video_port_reg
); /* StartVertRetrace */
773 outb_p(0xff,vga_video_port_val
); /* maximum value */
774 outb_p(0x11,vga_video_port_reg
); /* EndVertRetrace */
775 outb_p(0x40,vga_video_port_val
); /* minimum (bits 0..3) */
776 outb_p(0x07,vga_video_port_reg
); /* Overflow */
777 outb_p(par
->vga_state
.Overflow
| 0x84,vga_video_port_val
); /* bits 9,10 of vert. retrace */
780 if (mode
& FB_BLANK_HSYNC_SUSPEND
) {
782 * Set <End of horizontal retrace> to minimum (0) and
783 * <Start of horizontal Retrace> to maximum
784 * Result: turn off horizontal sync (HSync) pulse.
786 outb_p(0x04,vga_video_port_reg
); /* StartHorizRetrace */
787 outb_p(0xff,vga_video_port_val
); /* maximum */
788 outb_p(0x05,vga_video_port_reg
); /* EndHorizRetrace */
789 outb_p(0x00,vga_video_port_val
); /* minimum (0) */
792 /* restore both index registers */
793 outb_p(SeqCtrlIndex
,seq_port_reg
);
794 outb_p(CrtCtrlIndex
,vga_video_port_reg
);
798 static void vga_vesa_unblank(struct vga16fb_par
*par
)
800 unsigned char SeqCtrlIndex
;
801 unsigned char CrtCtrlIndex
;
804 SeqCtrlIndex
= vga_io_r(seq_port_reg
);
805 CrtCtrlIndex
= vga_io_r(vga_video_port_reg
);
807 /* restore original values of VGA controller registers */
808 vga_io_w(video_misc_wr
, par
->vga_state
.CrtMiscIO
);
810 /* HorizontalTotal */
811 vga_io_wcrt(0x00, par
->vga_state
.HorizontalTotal
);
812 /* HorizDisplayEnd */
813 vga_io_wcrt(0x01, par
->vga_state
.HorizDisplayEnd
);
814 /* StartHorizRetrace */
815 vga_io_wcrt(0x04, par
->vga_state
.StartHorizRetrace
);
816 /* EndHorizRetrace */
817 vga_io_wcrt(0x05, par
->vga_state
.EndHorizRetrace
);
819 vga_io_wcrt(0x07, par
->vga_state
.Overflow
);
820 /* StartVertRetrace */
821 vga_io_wcrt(0x10, par
->vga_state
.StartVertRetrace
);
823 vga_io_wcrt(0x11, par
->vga_state
.EndVertRetrace
);
825 vga_io_wcrt(0x17, par
->vga_state
.ModeControl
);
827 vga_io_wseq(0x01, par
->vga_state
.ClockingMode
);
829 /* restore index/control registers */
830 vga_io_w(seq_port_reg
, SeqCtrlIndex
);
831 vga_io_w(vga_video_port_reg
, CrtCtrlIndex
);
835 static void vga_pal_blank(void)
839 for (i
=0; i
<16; i
++) {
840 outb_p (i
, dac_reg
) ;
841 outb_p (0, dac_val
) ;
842 outb_p (0, dac_val
) ;
843 outb_p (0, dac_val
) ;
847 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
848 static int vga16fb_blank(int blank
, struct fb_info
*info
)
850 struct vga16fb_par
*par
= info
->par
;
853 case FB_BLANK_UNBLANK
: /* Unblank */
854 if (par
->vesa_blanked
) {
855 vga_vesa_unblank(par
);
856 par
->vesa_blanked
= 0;
858 if (par
->palette_blanked
) {
859 par
->palette_blanked
= 0;
862 case FB_BLANK_NORMAL
: /* blank */
864 par
->palette_blanked
= 1;
866 default: /* VESA blanking */
867 vga_vesa_blank(par
, blank
);
868 par
->vesa_blanked
= 1;
874 static void vga_8planes_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
876 u32 dx
= rect
->dx
, width
= rect
->width
;
877 char oldindex
= getindex();
878 char oldmode
= setmode(0x40);
879 char oldmask
= selectmask();
880 int line_ofs
, height
;
885 where
= info
->screen_base
+ dx
+ rect
->dy
* info
->fix
.line_length
;
887 if (rect
->rop
== ROP_COPY
) {
892 line_ofs
= info
->fix
.line_length
- width
;
895 height
= rect
->height
;
900 /* we can do memset... */
901 for (x
= width
; x
> 0; --x
) {
902 writeb(rect
->color
, where
);
908 char oldcolor
= setcolor(0xf);
914 for (y
= 0; y
< rect
->height
; y
++) {
917 where
+= info
->fix
.line_length
;
928 static void vga16fb_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
930 int x
, x2
, y2
, vxres
, vyres
, width
, height
, line_ofs
;
933 vxres
= info
->var
.xres_virtual
;
934 vyres
= info
->var
.yres_virtual
;
936 if (!rect
->width
|| !rect
->height
|| rect
->dx
> vxres
|| rect
->dy
> vyres
)
939 /* We could use hardware clipping but on many cards you get around
940 * hardware clipping by writing to framebuffer directly. */
942 x2
= rect
->dx
+ rect
->width
;
943 y2
= rect
->dy
+ rect
->height
;
944 x2
= x2
< vxres
? x2
: vxres
;
945 y2
= y2
< vyres
? y2
: vyres
;
946 width
= x2
- rect
->dx
;
948 switch (info
->fix
.type
) {
949 case FB_TYPE_VGA_PLANES
:
950 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
952 height
= y2
- rect
->dy
;
953 width
= rect
->width
/8;
955 line_ofs
= info
->fix
.line_length
- width
;
956 dst
= info
->screen_base
+ (rect
->dx
/8) + rect
->dy
* info
->fix
.line_length
;
963 setcolor(rect
->color
);
969 for (x
= 0; x
< width
; x
++) {
985 for (x
= 0; x
< width
; x
++) {
994 vga_8planes_fillrect(info
, rect
);
996 case FB_TYPE_PACKED_PIXELS
:
998 cfb_fillrect(info
, rect
);
1003 static void vga_8planes_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
1005 char oldindex
= getindex();
1006 char oldmode
= setmode(0x41);
1007 char oldop
= setop(0);
1008 char oldsr
= setsr(0xf);
1009 int height
, line_ofs
, x
;
1014 height
= area
->height
;
1018 width
= area
->width
/ 4;
1020 if (area
->dy
< area
->sy
|| (area
->dy
== area
->sy
&& dx
< sx
)) {
1021 line_ofs
= info
->fix
.line_length
- width
;
1022 dest
= info
->screen_base
+ dx
+ area
->dy
* info
->fix
.line_length
;
1023 src
= info
->screen_base
+ sx
+ area
->sy
* info
->fix
.line_length
;
1025 for (x
= 0; x
< width
; x
++) {
1035 line_ofs
= info
->fix
.line_length
- width
;
1036 dest
= info
->screen_base
+ dx
+ width
+
1037 (area
->dy
+ height
- 1) * info
->fix
.line_length
;
1038 src
= info
->screen_base
+ sx
+ width
+
1039 (area
->sy
+ height
- 1) * info
->fix
.line_length
;
1041 for (x
= 0; x
< width
; x
++) {
1058 static void vga16fb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
1060 u32 dx
= area
->dx
, dy
= area
->dy
, sx
= area
->sx
, sy
= area
->sy
;
1061 int x
, x2
, y2
, old_dx
, old_dy
, vxres
, vyres
;
1062 int height
, width
, line_ofs
;
1063 char __iomem
*dst
= NULL
;
1064 char __iomem
*src
= NULL
;
1066 vxres
= info
->var
.xres_virtual
;
1067 vyres
= info
->var
.yres_virtual
;
1069 if (area
->dx
> vxres
|| area
->sx
> vxres
|| area
->dy
> vyres
||
1073 /* clip the destination */
1078 * We could use hardware clipping but on many cards you get around
1079 * hardware clipping by writing to framebuffer directly.
1081 x2
= area
->dx
+ area
->width
;
1082 y2
= area
->dy
+ area
->height
;
1083 dx
= area
->dx
> 0 ? area
->dx
: 0;
1084 dy
= area
->dy
> 0 ? area
->dy
: 0;
1085 x2
= x2
< vxres
? x2
: vxres
;
1086 y2
= y2
< vyres
? y2
: vyres
;
1090 /* update sx1,sy1 */
1091 sx
+= (dx
- old_dx
);
1092 sy
+= (dy
- old_dy
);
1094 /* the source must be completely inside the virtual screen */
1095 if (sx
< 0 || sy
< 0 || (sx
+ width
) > vxres
|| (sy
+ height
) > vyres
)
1098 switch (info
->fix
.type
) {
1099 case FB_TYPE_VGA_PLANES
:
1100 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
1103 line_ofs
= info
->fix
.line_length
- width
;
1109 if (dy
< sy
|| (dy
== sy
&& dx
< sx
)) {
1110 dst
= info
->screen_base
+ (dx
/8) + dy
* info
->fix
.line_length
;
1111 src
= info
->screen_base
+ (sx
/8) + sy
* info
->fix
.line_length
;
1113 for (x
= 0; x
< width
; x
++) {
1123 dst
= info
->screen_base
+ (dx
/8) + width
+
1124 (dy
+ height
- 1) * info
->fix
.line_length
;
1125 src
= info
->screen_base
+ (sx
/8) + width
+
1126 (sy
+ height
- 1) * info
->fix
.line_length
;
1128 for (x
= 0; x
< width
; x
++) {
1139 vga_8planes_copyarea(info
, area
);
1141 case FB_TYPE_PACKED_PIXELS
:
1143 cfb_copyarea(info
, area
);
1148 #define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
1149 #define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
1150 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
1152 #if defined(__LITTLE_ENDIAN)
1153 static const u16 transl_l
[] = TRANS_MASK_LOW
;
1154 static const u16 transl_h
[] = TRANS_MASK_HIGH
;
1155 #elif defined(__BIG_ENDIAN)
1156 static const u16 transl_l
[] = TRANS_MASK_HIGH
;
1157 static const u16 transl_h
[] = TRANS_MASK_LOW
;
1159 #error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1162 static void vga_8planes_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
1164 char oldindex
= getindex();
1165 char oldmode
= setmode(0x40);
1166 char oldop
= setop(0);
1167 char oldsr
= setsr(0);
1168 char oldmask
= selectmask();
1169 const char *cdat
= image
->data
;
1171 char __iomem
*where
;
1175 where
= info
->screen_base
+ dx
+ image
->dy
* info
->fix
.line_length
;
1178 writeb(image
->bg_color
, where
);
1181 setmask(image
->fg_color
^ image
->bg_color
);
1184 for (y
= 0; y
< image
->height
; y
++, where
+= info
->fix
.line_length
)
1185 writew(transl_h
[cdat
[y
]&0xF] | transl_l
[cdat
[y
] >> 4], where
);
1193 static void vga_imageblit_expand(struct fb_info
*info
, const struct fb_image
*image
)
1195 char __iomem
*where
= info
->screen_base
+ (image
->dx
/8) +
1196 image
->dy
* info
->fix
.line_length
;
1197 struct vga16fb_par
*par
= info
->par
;
1198 char *cdat
= (char *) image
->data
;
1202 switch (info
->fix
.type
) {
1203 case FB_TYPE_VGA_PLANES
:
1204 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
1209 setcolor(image
->fg_color
);
1213 writeb(image
->bg_color
, where
);
1215 readb(where
); /* fill latches */
1218 for (y
= 0; y
< image
->height
; y
++) {
1220 for (x
= image
->width
/8; x
--;)
1221 writeb(*cdat
++, dst
++);
1222 where
+= info
->fix
.line_length
;
1229 setcolor(image
->bg_color
);
1233 for (y
= 0; y
< image
->height
; y
++) {
1235 for (x
=image
->width
/8; x
--;){
1237 setcolor(image
->fg_color
);
1244 where
+= info
->fix
.line_length
;
1248 vga_8planes_imageblit(info
, image
);
1250 case FB_TYPE_PACKED_PIXELS
:
1252 cfb_imageblit(info
, image
);
1257 static void vga_imageblit_color(struct fb_info
*info
, const struct fb_image
*image
)
1262 struct vga16fb_par
*par
= info
->par
;
1263 char __iomem
*where
=
1264 info
->screen_base
+ image
->dy
* info
->fix
.line_length
+
1266 const char *cdat
= image
->data
;
1270 switch (info
->fix
.type
) {
1271 case FB_TYPE_VGA_PLANES
:
1272 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
&&
1278 for (y
= 0; y
< image
->height
; y
++) {
1279 for (x
= 0; x
< image
->width
; x
++) {
1284 setmask(1 << (7 - (x
% 8)));
1290 where
+= info
->fix
.line_length
;
1294 case FB_TYPE_PACKED_PIXELS
:
1295 cfb_imageblit(info
, image
);
1302 static void vga16fb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
1304 if (image
->depth
== 1)
1305 vga_imageblit_expand(info
, image
);
1307 vga_imageblit_color(info
, image
);
1310 static struct fb_ops vga16fb_ops
= {
1311 .owner
= THIS_MODULE
,
1312 .fb_open
= vga16fb_open
,
1313 .fb_release
= vga16fb_release
,
1314 .fb_check_var
= vga16fb_check_var
,
1315 .fb_set_par
= vga16fb_set_par
,
1316 .fb_setcolreg
= vga16fb_setcolreg
,
1317 .fb_pan_display
= vga16fb_pan_display
,
1318 .fb_blank
= vga16fb_blank
,
1319 .fb_fillrect
= vga16fb_fillrect
,
1320 .fb_copyarea
= vga16fb_copyarea
,
1321 .fb_imageblit
= vga16fb_imageblit
,
1325 static int vga16fb_setup(char *options
)
1329 if (!options
|| !*options
)
1332 while ((this_opt
= strsep(&options
, ",")) != NULL
) {
1333 if (!*this_opt
) continue;
1339 static int __init
vga16fb_probe(struct platform_device
*dev
)
1341 struct fb_info
*info
;
1342 struct vga16fb_par
*par
;
1346 printk(KERN_DEBUG
"vga16fb: initializing\n");
1347 info
= framebuffer_alloc(sizeof(struct vga16fb_par
), &dev
->dev
);
1354 /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
1355 info
->screen_base
= (void __iomem
*)VGA_MAP_MEM(VGA_FB_PHYS
, 0);
1357 if (!info
->screen_base
) {
1358 printk(KERN_ERR
"vga16fb: unable to map device\n");
1363 printk(KERN_INFO
"vga16fb: mapped to 0x%p\n", info
->screen_base
);
1366 mutex_init(&par
->open_lock
);
1367 par
->isVGA
= screen_info
.orig_video_isVGA
;
1368 par
->palette_blanked
= 0;
1369 par
->vesa_blanked
= 0;
1371 i
= par
->isVGA
? 6 : 2;
1373 vga16fb_defined
.red
.length
= i
;
1374 vga16fb_defined
.green
.length
= i
;
1375 vga16fb_defined
.blue
.length
= i
;
1377 /* name should not depend on EGA/VGA */
1378 info
->fbops
= &vga16fb_ops
;
1379 info
->var
= vga16fb_defined
;
1380 info
->fix
= vga16fb_fix
;
1381 /* supports rectangles with widths of multiples of 8 */
1382 info
->pixmap
.blit_x
= 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
1383 info
->flags
= FBINFO_FLAG_DEFAULT
|
1384 FBINFO_HWACCEL_YPAN
;
1386 i
= (info
->var
.bits_per_pixel
== 8) ? 256 : 16;
1387 ret
= fb_alloc_cmap(&info
->cmap
, i
, 0);
1389 printk(KERN_ERR
"vga16fb: unable to allocate colormap\n");
1391 goto err_alloc_cmap
;
1394 if (vga16fb_check_var(&info
->var
, info
)) {
1395 printk(KERN_ERR
"vga16fb: unable to validate variable\n");
1400 vga16fb_update_fix(info
);
1402 if (register_framebuffer(info
) < 0) {
1403 printk(KERN_ERR
"vga16fb: unable to register framebuffer\n");
1408 printk(KERN_INFO
"fb%d: %s frame buffer device\n",
1409 info
->node
, info
->fix
.id
);
1410 platform_set_drvdata(dev
, info
);
1415 fb_dealloc_cmap(&info
->cmap
);
1417 iounmap(info
->screen_base
);
1419 framebuffer_release(info
);
1424 static int vga16fb_remove(struct platform_device
*dev
)
1426 struct fb_info
*info
= platform_get_drvdata(dev
);
1429 unregister_framebuffer(info
);
1430 iounmap(info
->screen_base
);
1431 fb_dealloc_cmap(&info
->cmap
);
1432 /* XXX unshare VGA regions */
1433 framebuffer_release(info
);
1439 static struct platform_driver vga16fb_driver
= {
1440 .probe
= vga16fb_probe
,
1441 .remove
= vga16fb_remove
,
1447 static struct platform_device
*vga16fb_device
;
1449 static int __init
vga16fb_init(void)
1453 char *option
= NULL
;
1455 if (fb_get_options("vga16fb", &option
))
1458 vga16fb_setup(option
);
1460 ret
= platform_driver_register(&vga16fb_driver
);
1463 vga16fb_device
= platform_device_alloc("vga16fb", 0);
1466 ret
= platform_device_add(vga16fb_device
);
1471 platform_device_put(vga16fb_device
);
1472 platform_driver_unregister(&vga16fb_driver
);
1479 static void __exit
vga16fb_exit(void)
1481 platform_device_unregister(vga16fb_device
);
1482 platform_driver_unregister(&vga16fb_driver
);
1485 MODULE_LICENSE("GPL");
1486 module_init(vga16fb_init
);
1487 module_exit(vga16fb_exit
);
1491 * Overrides for Emacs so that we follow Linus's tabbing style.
1492 * ---------------------------------------------------------------------------