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
;
74 int palette_blanked
, vesa_blanked
, mode
, isVGA
;
75 u8 misc
, pel_msk
, vss
, clkdiv
;
79 /* --------------------------------------------------------------------- */
81 static struct fb_var_screeninfo vga16fb_defined __initdata
= {
87 .activate
= FB_ACTIVATE_TEST
,
97 .vmode
= FB_VMODE_NONINTERLACED
,
100 /* name should not depend on EGA/VGA */
101 static struct fb_fix_screeninfo vga16fb_fix __initdata
= {
103 .smem_start
= VGA_FB_PHYS
,
104 .smem_len
= VGA_FB_PHYS_LEN
,
105 .type
= FB_TYPE_VGA_PLANES
,
106 .type_aux
= FB_AUX_VGA_PLANES_VGA4
,
107 .visual
= FB_VISUAL_PSEUDOCOLOR
,
110 .line_length
= 640/8,
111 .accel
= FB_ACCEL_NONE
114 /* The VGA's weird architecture often requires that we read a byte and
115 write a byte to the same location. It doesn't matter *what* byte
116 we write, however. This is because all the action goes on behind
117 the scenes in the VGA's 32-bit latch register, and reading and writing
118 video memory just invokes latch behavior.
120 To avoid race conditions (is this necessary?), reading and writing
121 the memory byte should be done with a single instruction. One
122 suitable instruction is the x86 bitwise OR. The following
123 read-modify-write routine should optimize to one such bitwise
125 static inline void rmw(volatile char __iomem
*p
)
131 /* Set the Graphics Mode Register, and return its previous value.
132 Bits 0-1 are write mode, bit 3 is read mode. */
133 static inline int setmode(int mode
)
137 vga_io_w(GRAPHICS_ADDR_REG
, GRAPHICS_MODE_INDEX
);
138 oldmode
= vga_io_r(GRAPHICS_DATA_REG
);
139 vga_io_w(GRAPHICS_DATA_REG
, mode
);
143 /* Select the Bit Mask Register and return its value. */
144 static inline int selectmask(void)
146 return vga_io_rgfx(BIT_MASK_INDEX
);
149 /* Set the value of the Bit Mask Register. It must already have been
150 selected with selectmask(). */
151 static inline void setmask(int mask
)
153 vga_io_w(GRAPHICS_DATA_REG
, mask
);
156 /* Set the Data Rotate Register and return its old value.
157 Bits 0-2 are rotate count, bits 3-4 are logical operation
158 (0=NOP, 1=AND, 2=OR, 3=XOR). */
159 static inline int setop(int op
)
163 vga_io_w(GRAPHICS_ADDR_REG
, DATA_ROTATE_INDEX
);
164 oldop
= vga_io_r(GRAPHICS_DATA_REG
);
165 vga_io_w(GRAPHICS_DATA_REG
, op
);
169 /* Set the Enable Set/Reset Register and return its old value.
170 The code here always uses value 0xf for thsi register. */
171 static inline int setsr(int sr
)
175 vga_io_w(GRAPHICS_ADDR_REG
, ENABLE_SET_RESET_INDEX
);
176 oldsr
= vga_io_r(GRAPHICS_DATA_REG
);
177 vga_io_w(GRAPHICS_DATA_REG
, sr
);
181 /* Set the Set/Reset Register and return its old value. */
182 static inline int setcolor(int color
)
186 vga_io_w(GRAPHICS_ADDR_REG
, SET_RESET_INDEX
);
187 oldcolor
= vga_io_r(GRAPHICS_DATA_REG
);
188 vga_io_w(GRAPHICS_DATA_REG
, color
);
192 /* Return the value in the Graphics Address Register. */
193 static inline int getindex(void)
195 return vga_io_r(GRAPHICS_ADDR_REG
);
198 /* Set the value in the Graphics Address Register. */
199 static inline void setindex(int index
)
201 vga_io_w(GRAPHICS_ADDR_REG
, index
);
204 static void vga16fb_pan_var(struct fb_info
*info
,
205 struct fb_var_screeninfo
*var
)
207 struct vga16fb_par
*par
= info
->par
;
210 xoffset
= var
->xoffset
;
211 if (info
->var
.bits_per_pixel
== 8) {
212 pos
= (info
->var
.xres_virtual
* var
->yoffset
+ xoffset
) >> 2;
213 } else if (par
->mode
& MODE_TEXT
) {
214 int fh
= 16; // FIXME !!! font height. Fugde for now.
215 pos
= (info
->var
.xres_virtual
* (var
->yoffset
/ fh
) + xoffset
) >> 3;
217 if (info
->var
.nonstd
)
219 pos
= (info
->var
.xres_virtual
* var
->yoffset
+ xoffset
) >> 3;
221 vga_io_wcrt(VGA_CRTC_START_HI
, pos
>> 8);
222 vga_io_wcrt(VGA_CRTC_START_LO
, pos
& 0xFF);
223 /* if we support CFB4, then we must! support xoffset with pixel
224 * granularity if someone supports xoffset in bit resolution */
225 vga_io_r(VGA_IS1_RC
); /* reset flip-flop */
226 vga_io_w(VGA_ATT_IW
, VGA_ATC_PEL
);
227 if (var
->bits_per_pixel
== 8)
228 vga_io_w(VGA_ATT_IW
, (xoffset
& 3) << 1);
230 vga_io_w(VGA_ATT_IW
, xoffset
& 7);
231 vga_io_r(VGA_IS1_RC
);
232 vga_io_w(VGA_ATT_IW
, 0x20);
235 static void vga16fb_update_fix(struct fb_info
*info
)
237 if (info
->var
.bits_per_pixel
== 4) {
238 if (info
->var
.nonstd
) {
239 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
240 info
->fix
.line_length
= info
->var
.xres_virtual
/ 2;
242 info
->fix
.type
= FB_TYPE_VGA_PLANES
;
243 info
->fix
.type_aux
= FB_AUX_VGA_PLANES_VGA4
;
244 info
->fix
.line_length
= info
->var
.xres_virtual
/ 8;
246 } else if (info
->var
.bits_per_pixel
== 0) {
247 info
->fix
.type
= FB_TYPE_TEXT
;
248 info
->fix
.type_aux
= FB_AUX_TEXT_CGA
;
249 info
->fix
.line_length
= info
->var
.xres_virtual
/ 4;
251 if (info
->var
.nonstd
) {
252 info
->fix
.type
= FB_TYPE_VGA_PLANES
;
253 info
->fix
.type_aux
= FB_AUX_VGA_PLANES_CFB8
;
254 info
->fix
.line_length
= info
->var
.xres_virtual
/ 4;
256 info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
257 info
->fix
.line_length
= info
->var
.xres_virtual
;
262 static void vga16fb_clock_chip(struct vga16fb_par
*par
,
263 unsigned int pixclock
,
264 const struct fb_info
*info
,
267 static const struct {
271 } *ptr
, *best
, vgaclocks
[] = {
272 { 79442 /* 12.587 */, 0x00, 0x08},
273 { 70616 /* 14.161 */, 0x04, 0x08},
274 { 39721 /* 25.175 */, 0x00, 0x00},
275 { 35308 /* 28.322 */, 0x04, 0x00},
276 { 0 /* bad */, 0x00, 0x00}};
279 pixclock
= (pixclock
* mul
) / div
;
281 err
= pixclock
- best
->pixclock
;
282 if (err
< 0) err
= -err
;
283 for (ptr
= vgaclocks
+ 1; ptr
->pixclock
; ptr
++) {
286 tmp
= pixclock
- ptr
->pixclock
;
287 if (tmp
< 0) tmp
= -tmp
;
293 par
->misc
|= best
->misc
;
294 par
->clkdiv
= best
->seq_clock_mode
;
295 pixclock
= (best
->pixclock
* div
) / mul
;
298 #define FAIL(X) return -EINVAL
300 static int vga16fb_open(struct fb_info
*info
, int user
)
302 struct vga16fb_par
*par
= info
->par
;
303 int cnt
= atomic_read(&par
->ref_count
);
306 memset(&par
->state
, 0, sizeof(struct vgastate
));
307 par
->state
.flags
= VGA_SAVE_FONTS
| VGA_SAVE_MODE
|
309 save_vga(&par
->state
);
311 atomic_inc(&par
->ref_count
);
315 static int vga16fb_release(struct fb_info
*info
, int user
)
317 struct vga16fb_par
*par
= info
->par
;
318 int cnt
= atomic_read(&par
->ref_count
);
323 restore_vga(&par
->state
);
324 atomic_dec(&par
->ref_count
);
329 static int vga16fb_check_var(struct fb_var_screeninfo
*var
,
330 struct fb_info
*info
)
332 struct vga16fb_par
*par
= info
->par
;
333 u32 xres
, right
, hslen
, left
, xtotal
;
334 u32 yres
, lower
, vslen
, upper
, ytotal
;
335 u32 vxres
, xoffset
, vyres
, yoffset
;
344 if (var
->bits_per_pixel
== 4) {
349 mode
= MODE_SKIP4
| MODE_CFB
;
357 } else if (var
->bits_per_pixel
== 8) {
359 return -EINVAL
; /* no support on EGA */
362 mode
= MODE_8BPP
| MODE_CFB
;
365 mode
= MODE_SKIP4
| MODE_8BPP
| MODE_CFB
;
371 xres
= (var
->xres
+ 7) & ~7;
372 vxres
= (var
->xres_virtual
+ 0xF) & ~0xF;
373 xoffset
= (var
->xoffset
+ 7) & ~7;
374 left
= (var
->left_margin
+ 7) & ~7;
375 right
= (var
->right_margin
+ 7) & ~7;
376 hslen
= (var
->hsync_len
+ 7) & ~7;
380 if (xres
+ xoffset
> vxres
)
381 xoffset
= vxres
- xres
;
384 var
->right_margin
= right
;
385 var
->hsync_len
= hslen
;
386 var
->left_margin
= left
;
387 var
->xres_virtual
= vxres
;
388 var
->xoffset
= xoffset
;
395 xtotal
= xres
+ right
+ hslen
+ left
;
397 FAIL("xtotal too big");
399 FAIL("hslen too big");
400 if (right
+ hslen
+ left
> 64)
401 FAIL("hblank too big");
402 par
->crtc
[VGA_CRTC_H_TOTAL
] = xtotal
- 5;
403 par
->crtc
[VGA_CRTC_H_BLANK_START
] = xres
- 1;
404 par
->crtc
[VGA_CRTC_H_DISP
] = xres
- 1;
406 par
->crtc
[VGA_CRTC_H_SYNC_START
] = pos
;
408 par
->crtc
[VGA_CRTC_H_SYNC_END
] = pos
& 0x1F;
409 pos
+= left
- 2; /* blank_end + 2 <= total + 5 */
410 par
->crtc
[VGA_CRTC_H_BLANK_END
] = (pos
& 0x1F) | 0x80;
412 par
->crtc
[VGA_CRTC_H_SYNC_END
] |= 0x80;
415 lower
= var
->lower_margin
;
416 vslen
= var
->vsync_len
;
417 upper
= var
->upper_margin
;
418 vyres
= var
->yres_virtual
;
419 yoffset
= var
->yoffset
;
423 if (vxres
* vyres
> maxmem
) {
424 vyres
= maxmem
/ vxres
;
428 if (yoffset
+ yres
> vyres
)
429 yoffset
= vyres
- yres
;
431 var
->lower_margin
= lower
;
432 var
->vsync_len
= vslen
;
433 var
->upper_margin
= upper
;
434 var
->yres_virtual
= vyres
;
435 var
->yoffset
= yoffset
;
437 if (var
->vmode
& FB_VMODE_DOUBLE
) {
443 ytotal
= yres
+ lower
+ vslen
+ upper
;
454 FAIL("ytotal too big");
456 FAIL("vslen too big");
457 par
->crtc
[VGA_CRTC_V_TOTAL
] = ytotal
- 2;
458 r7
= 0x10; /* disable linecompare */
459 if (ytotal
& 0x100) r7
|= 0x01;
460 if (ytotal
& 0x200) r7
|= 0x20;
461 par
->crtc
[VGA_CRTC_PRESET_ROW
] = 0;
462 par
->crtc
[VGA_CRTC_MAX_SCAN
] = 0x40; /* 1 scanline, no linecmp */
463 if (var
->vmode
& FB_VMODE_DOUBLE
)
464 par
->crtc
[VGA_CRTC_MAX_SCAN
] |= 0x80;
465 par
->crtc
[VGA_CRTC_CURSOR_START
] = 0x20;
466 par
->crtc
[VGA_CRTC_CURSOR_END
] = 0x00;
467 if ((mode
& (MODE_CFB
| MODE_8BPP
)) == MODE_CFB
)
469 pos
= yoffset
* vxres
+ (xoffset
>> shift
);
470 par
->crtc
[VGA_CRTC_START_HI
] = pos
>> 8;
471 par
->crtc
[VGA_CRTC_START_LO
] = pos
& 0xFF;
472 par
->crtc
[VGA_CRTC_CURSOR_HI
] = 0x00;
473 par
->crtc
[VGA_CRTC_CURSOR_LO
] = 0x00;
475 par
->crtc
[VGA_CRTC_V_DISP_END
] = pos
& 0xFF;
476 par
->crtc
[VGA_CRTC_V_BLANK_START
] = pos
& 0xFF;
478 r7
|= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
480 r7
|= 0x40; /* 0x40 -> DISP_END */
481 par
->crtc
[VGA_CRTC_MAX_SCAN
] |= 0x20; /* BLANK_START */
484 par
->crtc
[VGA_CRTC_V_SYNC_START
] = pos
& 0xFF;
490 par
->crtc
[VGA_CRTC_V_SYNC_END
] = (pos
& 0x0F) & ~0x10; /* disabled IRQ */
491 pos
+= upper
- 1; /* blank_end + 1 <= ytotal + 2 */
492 par
->crtc
[VGA_CRTC_V_BLANK_END
] = pos
& 0xFF; /* 0x7F for original VGA,
493 but some SVGA chips requires all 8 bits to set */
495 FAIL("vxres too long");
496 par
->crtc
[VGA_CRTC_OFFSET
] = vxres
>> 1;
497 if (mode
& MODE_SKIP4
)
498 par
->crtc
[VGA_CRTC_UNDERLINE
] = 0x5F; /* 256, cfb8 */
500 par
->crtc
[VGA_CRTC_UNDERLINE
] = 0x1F; /* 16, vgap */
501 par
->crtc
[VGA_CRTC_MODE
] = rMode
| ((mode
& MODE_TEXT
) ? 0xA3 : 0xE3);
502 par
->crtc
[VGA_CRTC_LINE_COMPARE
] = 0xFF;
503 par
->crtc
[VGA_CRTC_OVERFLOW
] = r7
;
505 par
->vss
= 0x00; /* 3DA */
507 par
->misc
= 0xE3; /* enable CPU, ports 0x3Dx, positive sync */
508 if (var
->sync
& FB_SYNC_HOR_HIGH_ACT
)
510 if (var
->sync
& FB_SYNC_VERT_HIGH_ACT
)
515 if (mode
& MODE_8BPP
)
516 /* pixel clock == vga clock / 2 */
517 vga16fb_clock_chip(par
, var
->pixclock
, info
, 1, 2);
519 /* pixel clock == vga clock */
520 vga16fb_clock_chip(par
, var
->pixclock
, info
, 1, 1);
522 var
->red
.offset
= var
->green
.offset
= var
->blue
.offset
=
523 var
->transp
.offset
= 0;
524 var
->red
.length
= var
->green
.length
= var
->blue
.length
=
525 (par
->isVGA
) ? 6 : 2;
526 var
->transp
.length
= 0;
527 var
->activate
= FB_ACTIVATE_NOW
;
530 var
->accel_flags
= 0;
535 static int vga16fb_set_par(struct fb_info
*info
)
537 struct vga16fb_par
*par
= info
->par
;
543 seq
[VGA_SEQ_CLOCK_MODE
] = 0x01 | par
->clkdiv
;
544 if (par
->mode
& MODE_TEXT
)
545 seq
[VGA_SEQ_PLANE_WRITE
] = 0x03;
547 seq
[VGA_SEQ_PLANE_WRITE
] = 0x0F;
548 seq
[VGA_SEQ_CHARACTER_MAP
] = 0x00;
549 if (par
->mode
& MODE_TEXT
)
550 seq
[VGA_SEQ_MEMORY_MODE
] = 0x03;
551 else if (par
->mode
& MODE_SKIP4
)
552 seq
[VGA_SEQ_MEMORY_MODE
] = 0x0E;
554 seq
[VGA_SEQ_MEMORY_MODE
] = 0x06;
556 gdc
[VGA_GFX_SR_VALUE
] = 0x00;
557 gdc
[VGA_GFX_SR_ENABLE
] = 0x00;
558 gdc
[VGA_GFX_COMPARE_VALUE
] = 0x00;
559 gdc
[VGA_GFX_DATA_ROTATE
] = 0x00;
560 gdc
[VGA_GFX_PLANE_READ
] = 0;
561 if (par
->mode
& MODE_TEXT
) {
562 gdc
[VGA_GFX_MODE
] = 0x10;
563 gdc
[VGA_GFX_MISC
] = 0x06;
565 if (par
->mode
& MODE_CFB
)
566 gdc
[VGA_GFX_MODE
] = 0x40;
568 gdc
[VGA_GFX_MODE
] = 0x00;
569 gdc
[VGA_GFX_MISC
] = 0x05;
571 gdc
[VGA_GFX_COMPARE_MASK
] = 0x0F;
572 gdc
[VGA_GFX_BIT_MASK
] = 0xFF;
574 for (i
= 0x00; i
< 0x10; i
++)
576 if (par
->mode
& MODE_TEXT
)
577 atc
[VGA_ATC_MODE
] = 0x04;
578 else if (par
->mode
& MODE_8BPP
)
579 atc
[VGA_ATC_MODE
] = 0x41;
581 atc
[VGA_ATC_MODE
] = 0x81;
582 atc
[VGA_ATC_OVERSCAN
] = 0x00; /* 0 for EGA, 0xFF for VGA */
583 atc
[VGA_ATC_PLANE_ENABLE
] = 0x0F;
584 if (par
->mode
& MODE_8BPP
)
585 atc
[VGA_ATC_PEL
] = (info
->var
.xoffset
& 3) << 1;
587 atc
[VGA_ATC_PEL
] = info
->var
.xoffset
& 7;
588 atc
[VGA_ATC_COLOR_PAGE
] = 0x00;
590 if (par
->mode
& MODE_TEXT
) {
591 fh
= 16; // FIXME !!! Fudge font height.
592 par
->crtc
[VGA_CRTC_MAX_SCAN
] = (par
->crtc
[VGA_CRTC_MAX_SCAN
]
596 vga_io_w(VGA_MIS_W
, vga_io_r(VGA_MIS_R
) | 0x01);
598 /* Enable graphics register modification */
600 vga_io_w(EGA_GFX_E0
, 0x00);
601 vga_io_w(EGA_GFX_E1
, 0x01);
604 /* update misc output register */
605 vga_io_w(VGA_MIS_W
, par
->misc
);
607 /* synchronous reset on */
608 vga_io_wseq(0x00, 0x01);
611 vga_io_w(VGA_PEL_MSK
, par
->pel_msk
);
613 /* write sequencer registers */
614 vga_io_wseq(VGA_SEQ_CLOCK_MODE
, seq
[VGA_SEQ_CLOCK_MODE
] | 0x20);
615 for (i
= 2; i
< VGA_SEQ_C
; i
++) {
616 vga_io_wseq(i
, seq
[i
]);
619 /* synchronous reset off */
620 vga_io_wseq(0x00, 0x03);
622 /* deprotect CRT registers 0-7 */
623 vga_io_wcrt(VGA_CRTC_V_SYNC_END
, par
->crtc
[VGA_CRTC_V_SYNC_END
]);
625 /* write CRT registers */
626 for (i
= 0; i
< VGA_CRTC_REGS
; i
++) {
627 vga_io_wcrt(i
, par
->crtc
[i
]);
630 /* write graphics controller registers */
631 for (i
= 0; i
< VGA_GFX_C
; i
++) {
632 vga_io_wgfx(i
, gdc
[i
]);
635 /* write attribute controller registers */
636 for (i
= 0; i
< VGA_ATT_C
; i
++) {
637 vga_io_r(VGA_IS1_RC
); /* reset flip-flop */
638 vga_io_wattr(i
, atc
[i
]);
641 /* Wait for screen to stabilize. */
644 vga_io_wseq(VGA_SEQ_CLOCK_MODE
, seq
[VGA_SEQ_CLOCK_MODE
]);
646 vga_io_r(VGA_IS1_RC
);
647 vga_io_w(VGA_ATT_IW
, 0x20);
649 vga16fb_update_fix(info
);
653 static void ega16_setpalette(int regno
, unsigned red
, unsigned green
, unsigned blue
)
655 static const unsigned char map
[] = { 000, 001, 010, 011 };
660 val
= map
[red
>>14] | ((map
[green
>>14]) << 1) | ((map
[blue
>>14]) << 2);
661 vga_io_r(VGA_IS1_RC
); /* ! 0x3BA */
662 vga_io_wattr(regno
, val
);
663 vga_io_r(VGA_IS1_RC
); /* some clones need it */
664 vga_io_w(VGA_ATT_IW
, 0x20); /* unblank screen */
667 static void vga16_setpalette(int regno
, unsigned red
, unsigned green
, unsigned blue
)
669 outb(regno
, dac_reg
);
670 outb(red
>> 10, dac_val
);
671 outb(green
>> 10, dac_val
);
672 outb(blue
>> 10, dac_val
);
675 static int vga16fb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
676 unsigned blue
, unsigned transp
,
677 struct fb_info
*info
)
679 struct vga16fb_par
*par
= info
->par
;
683 * Set a single color register. The values supplied are
684 * already rounded down to the hardware's capabilities
685 * (according to the entries in the `var' structure). Return
686 * != 0 for invalid regno.
692 gray
= info
->var
.grayscale
;
695 /* gray = 0.30*R + 0.59*G + 0.11*B */
696 red
= green
= blue
= (red
* 77 + green
* 151 + blue
* 28) >> 8;
699 vga16_setpalette(regno
,red
,green
,blue
);
701 ega16_setpalette(regno
,red
,green
,blue
);
705 static int vga16fb_pan_display(struct fb_var_screeninfo
*var
,
706 struct fb_info
*info
)
708 vga16fb_pan_var(info
, var
);
712 /* The following VESA blanking code is taken from vgacon.c. The VGA
713 blanking code was originally by Huang shi chao, and modified by
714 Christoph Rimek (chrimek@toppoint.de) and todd j. derr
715 (tjd@barefoot.org) for Linux. */
716 #define attrib_port VGA_ATC_IW
717 #define seq_port_reg VGA_SEQ_I
718 #define seq_port_val VGA_SEQ_D
719 #define gr_port_reg VGA_GFX_I
720 #define gr_port_val VGA_GFX_D
721 #define video_misc_rd VGA_MIS_R
722 #define video_misc_wr VGA_MIS_W
723 #define vga_video_port_reg VGA_CRT_IC
724 #define vga_video_port_val VGA_CRT_DC
726 static void vga_vesa_blank(struct vga16fb_par
*par
, int mode
)
728 unsigned char SeqCtrlIndex
;
729 unsigned char CrtCtrlIndex
;
732 SeqCtrlIndex
= vga_io_r(seq_port_reg
);
733 CrtCtrlIndex
= vga_io_r(vga_video_port_reg
);
735 /* save original values of VGA controller registers */
736 if(!par
->vesa_blanked
) {
737 par
->vga_state
.CrtMiscIO
= vga_io_r(video_misc_rd
);
740 par
->vga_state
.HorizontalTotal
= vga_io_rcrt(0x00); /* HorizontalTotal */
741 par
->vga_state
.HorizDisplayEnd
= vga_io_rcrt(0x01); /* HorizDisplayEnd */
742 par
->vga_state
.StartHorizRetrace
= vga_io_rcrt(0x04); /* StartHorizRetrace */
743 par
->vga_state
.EndHorizRetrace
= vga_io_rcrt(0x05); /* EndHorizRetrace */
744 par
->vga_state
.Overflow
= vga_io_rcrt(0x07); /* Overflow */
745 par
->vga_state
.StartVertRetrace
= vga_io_rcrt(0x10); /* StartVertRetrace */
746 par
->vga_state
.EndVertRetrace
= vga_io_rcrt(0x11); /* EndVertRetrace */
747 par
->vga_state
.ModeControl
= vga_io_rcrt(0x17); /* ModeControl */
748 par
->vga_state
.ClockingMode
= vga_io_rseq(0x01); /* ClockingMode */
751 /* assure that video is enabled */
752 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
754 vga_io_wseq(0x01, par
->vga_state
.ClockingMode
| 0x20);
756 /* test for vertical retrace in process.... */
757 if ((par
->vga_state
.CrtMiscIO
& 0x80) == 0x80)
758 vga_io_w(video_misc_wr
, par
->vga_state
.CrtMiscIO
& 0xef);
761 * Set <End of vertical retrace> to minimum (0) and
762 * <Start of vertical Retrace> to maximum (incl. overflow)
763 * Result: turn off vertical sync (VSync) pulse.
765 if (mode
& FB_BLANK_VSYNC_SUSPEND
) {
766 outb_p(0x10,vga_video_port_reg
); /* StartVertRetrace */
767 outb_p(0xff,vga_video_port_val
); /* maximum value */
768 outb_p(0x11,vga_video_port_reg
); /* EndVertRetrace */
769 outb_p(0x40,vga_video_port_val
); /* minimum (bits 0..3) */
770 outb_p(0x07,vga_video_port_reg
); /* Overflow */
771 outb_p(par
->vga_state
.Overflow
| 0x84,vga_video_port_val
); /* bits 9,10 of vert. retrace */
774 if (mode
& FB_BLANK_HSYNC_SUSPEND
) {
776 * Set <End of horizontal retrace> to minimum (0) and
777 * <Start of horizontal Retrace> to maximum
778 * Result: turn off horizontal sync (HSync) pulse.
780 outb_p(0x04,vga_video_port_reg
); /* StartHorizRetrace */
781 outb_p(0xff,vga_video_port_val
); /* maximum */
782 outb_p(0x05,vga_video_port_reg
); /* EndHorizRetrace */
783 outb_p(0x00,vga_video_port_val
); /* minimum (0) */
786 /* restore both index registers */
787 outb_p(SeqCtrlIndex
,seq_port_reg
);
788 outb_p(CrtCtrlIndex
,vga_video_port_reg
);
792 static void vga_vesa_unblank(struct vga16fb_par
*par
)
794 unsigned char SeqCtrlIndex
;
795 unsigned char CrtCtrlIndex
;
798 SeqCtrlIndex
= vga_io_r(seq_port_reg
);
799 CrtCtrlIndex
= vga_io_r(vga_video_port_reg
);
801 /* restore original values of VGA controller registers */
802 vga_io_w(video_misc_wr
, par
->vga_state
.CrtMiscIO
);
804 /* HorizontalTotal */
805 vga_io_wcrt(0x00, par
->vga_state
.HorizontalTotal
);
806 /* HorizDisplayEnd */
807 vga_io_wcrt(0x01, par
->vga_state
.HorizDisplayEnd
);
808 /* StartHorizRetrace */
809 vga_io_wcrt(0x04, par
->vga_state
.StartHorizRetrace
);
810 /* EndHorizRetrace */
811 vga_io_wcrt(0x05, par
->vga_state
.EndHorizRetrace
);
813 vga_io_wcrt(0x07, par
->vga_state
.Overflow
);
814 /* StartVertRetrace */
815 vga_io_wcrt(0x10, par
->vga_state
.StartVertRetrace
);
817 vga_io_wcrt(0x11, par
->vga_state
.EndVertRetrace
);
819 vga_io_wcrt(0x17, par
->vga_state
.ModeControl
);
821 vga_io_wseq(0x01, par
->vga_state
.ClockingMode
);
823 /* restore index/control registers */
824 vga_io_w(seq_port_reg
, SeqCtrlIndex
);
825 vga_io_w(vga_video_port_reg
, CrtCtrlIndex
);
829 static void vga_pal_blank(void)
833 for (i
=0; i
<16; i
++) {
834 outb_p (i
, dac_reg
) ;
835 outb_p (0, dac_val
) ;
836 outb_p (0, dac_val
) ;
837 outb_p (0, dac_val
) ;
841 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
842 static int vga16fb_blank(int blank
, struct fb_info
*info
)
844 struct vga16fb_par
*par
= info
->par
;
847 case FB_BLANK_UNBLANK
: /* Unblank */
848 if (par
->vesa_blanked
) {
849 vga_vesa_unblank(par
);
850 par
->vesa_blanked
= 0;
852 if (par
->palette_blanked
) {
853 par
->palette_blanked
= 0;
856 case FB_BLANK_NORMAL
: /* blank */
858 par
->palette_blanked
= 1;
860 default: /* VESA blanking */
861 vga_vesa_blank(par
, blank
);
862 par
->vesa_blanked
= 1;
868 static void vga_8planes_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
870 u32 dx
= rect
->dx
, width
= rect
->width
;
871 char oldindex
= getindex();
872 char oldmode
= setmode(0x40);
873 char oldmask
= selectmask();
874 int line_ofs
, height
;
879 where
= info
->screen_base
+ dx
+ rect
->dy
* info
->fix
.line_length
;
881 if (rect
->rop
== ROP_COPY
) {
886 line_ofs
= info
->fix
.line_length
- width
;
889 height
= rect
->height
;
894 /* we can do memset... */
895 for (x
= width
; x
> 0; --x
) {
896 writeb(rect
->color
, where
);
902 char oldcolor
= setcolor(0xf);
908 for (y
= 0; y
< rect
->height
; y
++) {
911 where
+= info
->fix
.line_length
;
922 static void vga16fb_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
924 int x
, x2
, y2
, vxres
, vyres
, width
, height
, line_ofs
;
927 vxres
= info
->var
.xres_virtual
;
928 vyres
= info
->var
.yres_virtual
;
930 if (!rect
->width
|| !rect
->height
|| rect
->dx
> vxres
|| rect
->dy
> vyres
)
933 /* We could use hardware clipping but on many cards you get around
934 * hardware clipping by writing to framebuffer directly. */
936 x2
= rect
->dx
+ rect
->width
;
937 y2
= rect
->dy
+ rect
->height
;
938 x2
= x2
< vxres
? x2
: vxres
;
939 y2
= y2
< vyres
? y2
: vyres
;
940 width
= x2
- rect
->dx
;
942 switch (info
->fix
.type
) {
943 case FB_TYPE_VGA_PLANES
:
944 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
946 height
= y2
- rect
->dy
;
947 width
= rect
->width
/8;
949 line_ofs
= info
->fix
.line_length
- width
;
950 dst
= info
->screen_base
+ (rect
->dx
/8) + rect
->dy
* info
->fix
.line_length
;
957 setcolor(rect
->color
);
963 for (x
= 0; x
< width
; x
++) {
979 for (x
= 0; x
< width
; x
++) {
988 vga_8planes_fillrect(info
, rect
);
990 case FB_TYPE_PACKED_PIXELS
:
992 cfb_fillrect(info
, rect
);
997 static void vga_8planes_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
999 char oldindex
= getindex();
1000 char oldmode
= setmode(0x41);
1001 char oldop
= setop(0);
1002 char oldsr
= setsr(0xf);
1003 int height
, line_ofs
, x
;
1008 height
= area
->height
;
1012 width
= area
->width
/ 4;
1014 if (area
->dy
< area
->sy
|| (area
->dy
== area
->sy
&& dx
< sx
)) {
1015 line_ofs
= info
->fix
.line_length
- width
;
1016 dest
= info
->screen_base
+ dx
+ area
->dy
* info
->fix
.line_length
;
1017 src
= info
->screen_base
+ sx
+ area
->sy
* info
->fix
.line_length
;
1019 for (x
= 0; x
< width
; x
++) {
1029 line_ofs
= info
->fix
.line_length
- width
;
1030 dest
= info
->screen_base
+ dx
+ width
+
1031 (area
->dy
+ height
- 1) * info
->fix
.line_length
;
1032 src
= info
->screen_base
+ sx
+ width
+
1033 (area
->sy
+ height
- 1) * info
->fix
.line_length
;
1035 for (x
= 0; x
< width
; x
++) {
1052 static void vga16fb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
1054 u32 dx
= area
->dx
, dy
= area
->dy
, sx
= area
->sx
, sy
= area
->sy
;
1055 int x
, x2
, y2
, old_dx
, old_dy
, vxres
, vyres
;
1056 int height
, width
, line_ofs
;
1057 char __iomem
*dst
= NULL
;
1058 char __iomem
*src
= NULL
;
1060 vxres
= info
->var
.xres_virtual
;
1061 vyres
= info
->var
.yres_virtual
;
1063 if (area
->dx
> vxres
|| area
->sx
> vxres
|| area
->dy
> vyres
||
1067 /* clip the destination */
1072 * We could use hardware clipping but on many cards you get around
1073 * hardware clipping by writing to framebuffer directly.
1075 x2
= area
->dx
+ area
->width
;
1076 y2
= area
->dy
+ area
->height
;
1077 dx
= area
->dx
> 0 ? area
->dx
: 0;
1078 dy
= area
->dy
> 0 ? area
->dy
: 0;
1079 x2
= x2
< vxres
? x2
: vxres
;
1080 y2
= y2
< vyres
? y2
: vyres
;
1084 /* update sx1,sy1 */
1085 sx
+= (dx
- old_dx
);
1086 sy
+= (dy
- old_dy
);
1088 /* the source must be completely inside the virtual screen */
1089 if (sx
< 0 || sy
< 0 || (sx
+ width
) > vxres
|| (sy
+ height
) > vyres
)
1092 switch (info
->fix
.type
) {
1093 case FB_TYPE_VGA_PLANES
:
1094 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
1097 line_ofs
= info
->fix
.line_length
- width
;
1103 if (dy
< sy
|| (dy
== sy
&& dx
< sx
)) {
1104 dst
= info
->screen_base
+ (dx
/8) + dy
* info
->fix
.line_length
;
1105 src
= info
->screen_base
+ (sx
/8) + sy
* info
->fix
.line_length
;
1107 for (x
= 0; x
< width
; x
++) {
1117 dst
= info
->screen_base
+ (dx
/8) + width
+
1118 (dy
+ height
- 1) * info
->fix
.line_length
;
1119 src
= info
->screen_base
+ (sx
/8) + width
+
1120 (sy
+ height
- 1) * info
->fix
.line_length
;
1122 for (x
= 0; x
< width
; x
++) {
1133 vga_8planes_copyarea(info
, area
);
1135 case FB_TYPE_PACKED_PIXELS
:
1137 cfb_copyarea(info
, area
);
1142 #define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
1143 #define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
1144 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
1146 #if defined(__LITTLE_ENDIAN)
1147 static const u16 transl_l
[] = TRANS_MASK_LOW
;
1148 static const u16 transl_h
[] = TRANS_MASK_HIGH
;
1149 #elif defined(__BIG_ENDIAN)
1150 static const u16 transl_l
[] = TRANS_MASK_HIGH
;
1151 static const u16 transl_h
[] = TRANS_MASK_LOW
;
1153 #error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1156 static void vga_8planes_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
1158 char oldindex
= getindex();
1159 char oldmode
= setmode(0x40);
1160 char oldop
= setop(0);
1161 char oldsr
= setsr(0);
1162 char oldmask
= selectmask();
1163 const char *cdat
= image
->data
;
1165 char __iomem
*where
;
1169 where
= info
->screen_base
+ dx
+ image
->dy
* info
->fix
.line_length
;
1172 writeb(image
->bg_color
, where
);
1175 setmask(image
->fg_color
^ image
->bg_color
);
1178 for (y
= 0; y
< image
->height
; y
++, where
+= info
->fix
.line_length
)
1179 writew(transl_h
[cdat
[y
]&0xF] | transl_l
[cdat
[y
] >> 4], where
);
1187 static void vga_imageblit_expand(struct fb_info
*info
, const struct fb_image
*image
)
1189 char __iomem
*where
= info
->screen_base
+ (image
->dx
/8) +
1190 image
->dy
* info
->fix
.line_length
;
1191 struct vga16fb_par
*par
= info
->par
;
1192 char *cdat
= (char *) image
->data
;
1196 switch (info
->fix
.type
) {
1197 case FB_TYPE_VGA_PLANES
:
1198 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
) {
1203 setcolor(image
->fg_color
);
1207 writeb(image
->bg_color
, where
);
1209 readb(where
); /* fill latches */
1212 for (y
= 0; y
< image
->height
; y
++) {
1214 for (x
= image
->width
/8; x
--;)
1215 writeb(*cdat
++, dst
++);
1216 where
+= info
->fix
.line_length
;
1223 setcolor(image
->bg_color
);
1227 for (y
= 0; y
< image
->height
; y
++) {
1229 for (x
=image
->width
/8; x
--;){
1231 setcolor(image
->fg_color
);
1238 where
+= info
->fix
.line_length
;
1242 vga_8planes_imageblit(info
, image
);
1244 case FB_TYPE_PACKED_PIXELS
:
1246 cfb_imageblit(info
, image
);
1251 static void vga_imageblit_color(struct fb_info
*info
, const struct fb_image
*image
)
1256 struct vga16fb_par
*par
= info
->par
;
1257 char __iomem
*where
=
1258 info
->screen_base
+ image
->dy
* info
->fix
.line_length
+
1260 const char *cdat
= image
->data
;
1264 switch (info
->fix
.type
) {
1265 case FB_TYPE_VGA_PLANES
:
1266 if (info
->fix
.type_aux
== FB_AUX_VGA_PLANES_VGA4
&&
1272 for (y
= 0; y
< image
->height
; y
++) {
1273 for (x
= 0; x
< image
->width
; x
++) {
1278 setmask(1 << (7 - (x
% 8)));
1284 where
+= info
->fix
.line_length
;
1288 case FB_TYPE_PACKED_PIXELS
:
1289 cfb_imageblit(info
, image
);
1296 static void vga16fb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
1298 if (image
->depth
== 1)
1299 vga_imageblit_expand(info
, image
);
1301 vga_imageblit_color(info
, image
);
1304 static struct fb_ops vga16fb_ops
= {
1305 .owner
= THIS_MODULE
,
1306 .fb_open
= vga16fb_open
,
1307 .fb_release
= vga16fb_release
,
1308 .fb_check_var
= vga16fb_check_var
,
1309 .fb_set_par
= vga16fb_set_par
,
1310 .fb_setcolreg
= vga16fb_setcolreg
,
1311 .fb_pan_display
= vga16fb_pan_display
,
1312 .fb_blank
= vga16fb_blank
,
1313 .fb_fillrect
= vga16fb_fillrect
,
1314 .fb_copyarea
= vga16fb_copyarea
,
1315 .fb_imageblit
= vga16fb_imageblit
,
1319 static int vga16fb_setup(char *options
)
1323 if (!options
|| !*options
)
1326 while ((this_opt
= strsep(&options
, ",")) != NULL
) {
1327 if (!*this_opt
) continue;
1333 static int __init
vga16fb_probe(struct platform_device
*dev
)
1335 struct fb_info
*info
;
1336 struct vga16fb_par
*par
;
1340 printk(KERN_DEBUG
"vga16fb: initializing\n");
1341 info
= framebuffer_alloc(sizeof(struct vga16fb_par
), &dev
->dev
);
1348 /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
1349 info
->screen_base
= (void __iomem
*)VGA_MAP_MEM(VGA_FB_PHYS
, 0);
1351 if (!info
->screen_base
) {
1352 printk(KERN_ERR
"vga16fb: unable to map device\n");
1357 printk(KERN_INFO
"vga16fb: mapped to 0x%p\n", info
->screen_base
);
1360 par
->isVGA
= ORIG_VIDEO_ISVGA
;
1361 par
->palette_blanked
= 0;
1362 par
->vesa_blanked
= 0;
1364 i
= par
->isVGA
? 6 : 2;
1366 vga16fb_defined
.red
.length
= i
;
1367 vga16fb_defined
.green
.length
= i
;
1368 vga16fb_defined
.blue
.length
= i
;
1370 /* name should not depend on EGA/VGA */
1371 info
->fbops
= &vga16fb_ops
;
1372 info
->var
= vga16fb_defined
;
1373 info
->fix
= vga16fb_fix
;
1374 info
->flags
= FBINFO_FLAG_DEFAULT
|
1375 FBINFO_HWACCEL_YPAN
;
1377 i
= (info
->var
.bits_per_pixel
== 8) ? 256 : 16;
1378 ret
= fb_alloc_cmap(&info
->cmap
, i
, 0);
1380 printk(KERN_ERR
"vga16fb: unable to allocate colormap\n");
1382 goto err_alloc_cmap
;
1385 if (vga16fb_check_var(&info
->var
, info
)) {
1386 printk(KERN_ERR
"vga16fb: unable to validate variable\n");
1391 vga16fb_update_fix(info
);
1393 if (register_framebuffer(info
) < 0) {
1394 printk(KERN_ERR
"vga16fb: unable to register framebuffer\n");
1399 printk(KERN_INFO
"fb%d: %s frame buffer device\n",
1400 info
->node
, info
->fix
.id
);
1401 platform_set_drvdata(dev
, info
);
1406 fb_dealloc_cmap(&info
->cmap
);
1408 iounmap(info
->screen_base
);
1410 framebuffer_release(info
);
1415 static int vga16fb_remove(struct platform_device
*dev
)
1417 struct fb_info
*info
= platform_get_drvdata(dev
);
1420 unregister_framebuffer(info
);
1421 iounmap(info
->screen_base
);
1422 fb_dealloc_cmap(&info
->cmap
);
1423 /* XXX unshare VGA regions */
1424 framebuffer_release(info
);
1430 static struct platform_driver vga16fb_driver
= {
1431 .probe
= vga16fb_probe
,
1432 .remove
= vga16fb_remove
,
1438 static struct platform_device
*vga16fb_device
;
1440 static int __init
vga16fb_init(void)
1444 char *option
= NULL
;
1446 if (fb_get_options("vga16fb", &option
))
1449 vga16fb_setup(option
);
1451 ret
= platform_driver_register(&vga16fb_driver
);
1454 vga16fb_device
= platform_device_alloc("vga16fb", 0);
1457 ret
= platform_device_add(vga16fb_device
);
1462 platform_device_put(vga16fb_device
);
1463 platform_driver_unregister(&vga16fb_driver
);
1470 static void __exit
vga16fb_exit(void)
1472 platform_device_unregister(vga16fb_device
);
1473 platform_driver_unregister(&vga16fb_driver
);
1476 MODULE_LICENSE("GPL");
1477 module_init(vga16fb_init
);
1478 module_exit(vga16fb_exit
);
1482 * Overrides for Emacs so that we follow Linus's tabbing style.
1483 * ---------------------------------------------------------------------------