Committer: Michael Beasley <mike@snafu.setup>
[mikesnafu-overlay.git] / drivers / video / vga16fb.c
blob9b3c5923365e7dd62e60982f9d6c27341f68cdf5
1 /*
2 * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver
3 *
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>
17 #include <linux/mm.h>
18 #include <linux/slab.h>
19 #include <linux/delay.h>
20 #include <linux/fb.h>
21 #include <linux/ioport.h>
22 #include <linux/init.h>
23 #include <linux/platform_device.h>
24 #include <linux/screen_info.h>
26 #include <asm/io.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
44 #define MODE_SKIP4 1
45 #define MODE_8BPP 2
46 #define MODE_CFB 4
47 #define MODE_TEXT 8
49 /* --------------------------------------------------------------------- */
52 * card parameters
55 struct vga16fb_par {
56 /* structure holding original VGA register settings when the
57 screen is blanked */
58 struct {
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 */
71 } vga_state;
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;
77 u8 crtc[VGA_CRT_C];
80 /* --------------------------------------------------------------------- */
82 static struct fb_var_screeninfo vga16fb_defined __initdata = {
83 .xres = 640,
84 .yres = 480,
85 .xres_virtual = 640,
86 .yres_virtual = 480,
87 .bits_per_pixel = 4,
88 .activate = FB_ACTIVATE_TEST,
89 .height = -1,
90 .width = -1,
91 .pixclock = 39721,
92 .left_margin = 48,
93 .right_margin = 16,
94 .upper_margin = 33,
95 .lower_margin = 10,
96 .hsync_len = 96,
97 .vsync_len = 2,
98 .vmode = FB_VMODE_NONINTERLACED,
101 /* name should not depend on EGA/VGA */
102 static struct fb_fix_screeninfo vga16fb_fix __initdata = {
103 .id = "VGA16 VGA",
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,
109 .xpanstep = 8,
110 .ypanstep = 1,
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
125 OR. */
126 static inline void rmw(volatile char __iomem *p)
128 readb(p);
129 writeb(1, 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)
136 int oldmode;
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);
141 return oldmode;
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)
162 int oldop;
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);
167 return oldop;
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)
174 int oldsr;
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);
179 return oldsr;
182 /* Set the Set/Reset Register and return its old value. */
183 static inline int setcolor(int color)
185 int oldcolor;
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);
190 return oldcolor;
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;
209 u32 xoffset, pos;
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;
217 } else {
218 if (info->var.nonstd)
219 xoffset--;
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);
230 else
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;
242 } else {
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;
251 } else { /* 8bpp */
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;
256 } else {
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,
266 int mul, int div)
268 static const struct {
269 u32 pixclock;
270 u8 misc;
271 u8 seq_clock_mode;
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}};
278 int err;
280 pixclock = (pixclock * mul) / div;
281 best = vgaclocks;
282 err = pixclock - best->pixclock;
283 if (err < 0) err = -err;
284 for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
285 int tmp;
287 tmp = pixclock - ptr->pixclock;
288 if (tmp < 0) tmp = -tmp;
289 if (tmp < err) {
290 err = tmp;
291 best = ptr;
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 |
309 VGA_SAVE_CMAP;
310 save_vga(&par->state);
312 par->ref_count++;
313 mutex_unlock(&par->open_lock);
315 return 0;
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);
325 return -EINVAL;
327 if (par->ref_count == 1)
328 restore_vga(&par->state);
329 par->ref_count--;
330 mutex_unlock(&par->open_lock);
332 return 0;
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;
342 u32 pos;
343 u8 r7, rMode;
344 int shift;
345 int mode;
346 u32 maxmem;
348 par->pel_msk = 0xFF;
350 if (var->bits_per_pixel == 4) {
351 if (var->nonstd) {
352 if (!par->isVGA)
353 return -EINVAL;
354 shift = 3;
355 mode = MODE_SKIP4 | MODE_CFB;
356 maxmem = 16384;
357 par->pel_msk = 0x0F;
358 } else {
359 shift = 3;
360 mode = 0;
361 maxmem = 65536;
363 } else if (var->bits_per_pixel == 8) {
364 if (!par->isVGA)
365 return -EINVAL; /* no support on EGA */
366 shift = 2;
367 if (var->nonstd) {
368 mode = MODE_8BPP | MODE_CFB;
369 maxmem = 65536;
370 } else {
371 mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;
372 maxmem = 16384;
374 } else
375 return -EINVAL;
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;
384 if (vxres < xres)
385 vxres = xres;
386 if (xres + xoffset > vxres)
387 xoffset = vxres - xres;
389 var->xres = 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;
396 xres >>= shift;
397 right >>= shift;
398 hslen >>= shift;
399 left >>= shift;
400 vxres >>= shift;
401 xtotal = xres + right + hslen + left;
402 if (xtotal >= 256)
403 FAIL("xtotal too big");
404 if (hslen > 32)
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;
411 pos = xres + right;
412 par->crtc[VGA_CRTC_H_SYNC_START] = pos;
413 pos += hslen;
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;
417 if (pos & 0x20)
418 par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
420 yres = var->yres;
421 lower = var->lower_margin;
422 vslen = var->vsync_len;
423 upper = var->upper_margin;
424 vyres = var->yres_virtual;
425 yoffset = var->yoffset;
427 if (yres > vyres)
428 vyres = yres;
429 if (vxres * vyres > maxmem) {
430 vyres = maxmem / vxres;
431 if (vyres < yres)
432 return -ENOMEM;
434 if (yoffset + yres > vyres)
435 yoffset = vyres - yres;
436 var->yres = 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) {
444 yres <<= 1;
445 lower <<= 1;
446 vslen <<= 1;
447 upper <<= 1;
449 ytotal = yres + lower + vslen + upper;
450 if (ytotal > 1024) {
451 ytotal >>= 1;
452 yres >>= 1;
453 lower >>= 1;
454 vslen >>= 1;
455 upper >>= 1;
456 rMode = 0x04;
457 } else
458 rMode = 0x00;
459 if (ytotal > 1024)
460 FAIL("ytotal too big");
461 if (vslen > 16)
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)
474 xoffset--;
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;
480 pos = yres - 1;
481 par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
482 par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
483 if (pos & 0x100)
484 r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
485 if (pos & 0x200) {
486 r7 |= 0x40; /* 0x40 -> DISP_END */
487 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
489 pos += lower;
490 par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
491 if (pos & 0x100)
492 r7 |= 0x04;
493 if (pos & 0x200)
494 r7 |= 0x80;
495 pos += vslen;
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 */
500 if (vxres >= 512)
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 */
505 else
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)
515 par->misc &= ~0x40;
516 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
517 par->misc &= ~0x80;
519 par->mode = mode;
521 if (mode & MODE_8BPP)
522 /* pixel clock == vga clock / 2 */
523 vga16fb_clock_chip(par, var->pixclock, info, 1, 2);
524 else
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;
534 var->height = -1;
535 var->width = -1;
536 var->accel_flags = 0;
537 return 0;
539 #undef FAIL
541 static int vga16fb_set_par(struct fb_info *info)
543 struct vga16fb_par *par = info->par;
544 u8 gdc[VGA_GFX_C];
545 u8 seq[VGA_SEQ_C];
546 u8 atc[VGA_ATT_C];
547 int fh, i;
549 seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv;
550 if (par->mode & MODE_TEXT)
551 seq[VGA_SEQ_PLANE_WRITE] = 0x03;
552 else
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;
559 else
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;
570 } else {
571 if (par->mode & MODE_CFB)
572 gdc[VGA_GFX_MODE] = 0x40;
573 else
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++)
581 atc[i] = 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;
586 else
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;
592 else
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]
599 & ~0x1F) | (fh - 1);
602 vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
604 /* Enable graphics register modification */
605 if (!par->isVGA) {
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);
616 if (par->isVGA)
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. */
648 mdelay(50);
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);
656 return 0;
659 static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
661 static const unsigned char map[] = { 000, 001, 010, 011 };
662 int val;
664 if (regno >= 16)
665 return;
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;
686 int gray;
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.
695 if (regno >= 256)
696 return 1;
698 gray = info->var.grayscale;
700 if (gray) {
701 /* gray = 0.30*R + 0.59*G + 0.11*B */
702 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
704 if (par->isVGA)
705 vga16_setpalette(regno,red,green,blue);
706 else
707 ega16_setpalette(regno,red,green,blue);
708 return 0;
711 static int vga16fb_pan_display(struct fb_var_screeninfo *var,
712 struct fb_info *info)
714 vga16fb_pan_var(info, var);
715 return 0;
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;
737 //cli();
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);
744 //sti();
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 */
759 //cli();
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);
795 //sti();
798 static void vga_vesa_unblank(struct vga16fb_par *par)
800 unsigned char SeqCtrlIndex;
801 unsigned char CrtCtrlIndex;
803 //cli();
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);
818 /* Overflow */
819 vga_io_wcrt(0x07, par->vga_state.Overflow);
820 /* StartVertRetrace */
821 vga_io_wcrt(0x10, par->vga_state.StartVertRetrace);
822 /* EndVertRetrace */
823 vga_io_wcrt(0x11, par->vga_state.EndVertRetrace);
824 /* ModeControl */
825 vga_io_wcrt(0x17, par->vga_state.ModeControl);
826 /* ClockingMode */
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);
832 //sti();
835 static void vga_pal_blank(void)
837 int i;
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;
852 switch (blank) {
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;
861 break;
862 case FB_BLANK_NORMAL: /* blank */
863 vga_pal_blank();
864 par->palette_blanked = 1;
865 break;
866 default: /* VESA blanking */
867 vga_vesa_blank(par, blank);
868 par->vesa_blanked = 1;
869 break;
871 return 0;
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;
881 char oldop, oldsr;
882 char __iomem *where;
884 dx /= 4;
885 where = info->screen_base + dx + rect->dy * info->fix.line_length;
887 if (rect->rop == ROP_COPY) {
888 oldop = setop(0);
889 oldsr = setsr(0);
891 width /= 4;
892 line_ofs = info->fix.line_length - width;
893 setmask(0xff);
895 height = rect->height;
897 while (height--) {
898 int x;
900 /* we can do memset... */
901 for (x = width; x > 0; --x) {
902 writeb(rect->color, where);
903 where++;
905 where += line_ofs;
907 } else {
908 char oldcolor = setcolor(0xf);
909 int y;
911 oldop = setop(0x18);
912 oldsr = setsr(0xf);
913 setmask(0x0F);
914 for (y = 0; y < rect->height; y++) {
915 rmw(where);
916 rmw(where+1);
917 where += info->fix.line_length;
919 setcolor(oldcolor);
921 setmask(oldmask);
922 setsr(oldsr);
923 setop(oldop);
924 setmode(oldmode);
925 setindex(oldindex);
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;
931 char __iomem *dst;
933 vxres = info->var.xres_virtual;
934 vyres = info->var.yres_virtual;
936 if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
937 return;
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;
958 switch (rect->rop) {
959 case ROP_COPY:
960 setmode(0);
961 setop(0);
962 setsr(0xf);
963 setcolor(rect->color);
964 selectmask();
966 setmask(0xff);
968 while (height--) {
969 for (x = 0; x < width; x++) {
970 writeb(0, dst);
971 dst++;
973 dst += line_ofs;
975 break;
976 case ROP_XOR:
977 setmode(0);
978 setop(0x18);
979 setsr(0xf);
980 setcolor(0xf);
981 selectmask();
983 setmask(0xff);
984 while (height--) {
985 for (x = 0; x < width; x++) {
986 rmw(dst);
987 dst++;
989 dst += line_ofs;
991 break;
993 } else
994 vga_8planes_fillrect(info, rect);
995 break;
996 case FB_TYPE_PACKED_PIXELS:
997 default:
998 cfb_fillrect(info, rect);
999 break;
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;
1010 u32 sx, dx, width;
1011 char __iomem *dest;
1012 char __iomem *src;
1014 height = area->height;
1016 sx = area->sx / 4;
1017 dx = area->dx / 4;
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;
1024 while (height--) {
1025 for (x = 0; x < width; x++) {
1026 readb(src);
1027 writeb(0, dest);
1028 src++;
1029 dest++;
1031 src += line_ofs;
1032 dest += line_ofs;
1034 } else {
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;
1040 while (height--) {
1041 for (x = 0; x < width; x++) {
1042 --src;
1043 --dest;
1044 readb(src);
1045 writeb(0, dest);
1047 src -= line_ofs;
1048 dest -= line_ofs;
1052 setsr(oldsr);
1053 setop(oldop);
1054 setmode(oldmode);
1055 setindex(oldindex);
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 ||
1070 area->sy > vyres)
1071 return;
1073 /* clip the destination */
1074 old_dx = area->dx;
1075 old_dy = area->dy;
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;
1087 width = x2 - dx;
1088 height = y2 - dy;
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)
1096 return;
1098 switch (info->fix.type) {
1099 case FB_TYPE_VGA_PLANES:
1100 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1101 width = width/8;
1102 height = height;
1103 line_ofs = info->fix.line_length - width;
1105 setmode(1);
1106 setop(0);
1107 setsr(0xf);
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;
1112 while (height--) {
1113 for (x = 0; x < width; x++) {
1114 readb(src);
1115 writeb(0, dst);
1116 dst++;
1117 src++;
1119 src += line_ofs;
1120 dst += line_ofs;
1122 } else {
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;
1127 while (height--) {
1128 for (x = 0; x < width; x++) {
1129 dst--;
1130 src--;
1131 readb(src);
1132 writeb(0, dst);
1134 src -= line_ofs;
1135 dst -= line_ofs;
1138 } else
1139 vga_8planes_copyarea(info, area);
1140 break;
1141 case FB_TYPE_PACKED_PIXELS:
1142 default:
1143 cfb_copyarea(info, area);
1144 break;
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;
1158 #else
1159 #error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1160 #endif
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;
1170 u32 dx = image->dx;
1171 char __iomem *where;
1172 int y;
1174 dx /= 4;
1175 where = info->screen_base + dx + image->dy * info->fix.line_length;
1177 setmask(0xff);
1178 writeb(image->bg_color, where);
1179 readb(where);
1180 selectmask();
1181 setmask(image->fg_color ^ image->bg_color);
1182 setmode(0x42);
1183 setop(0x18);
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);
1186 setmask(oldmask);
1187 setsr(oldsr);
1188 setop(oldop);
1189 setmode(oldmode);
1190 setindex(oldindex);
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;
1199 char __iomem *dst;
1200 int x, y;
1202 switch (info->fix.type) {
1203 case FB_TYPE_VGA_PLANES:
1204 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1205 if (par->isVGA) {
1206 setmode(2);
1207 setop(0);
1208 setsr(0xf);
1209 setcolor(image->fg_color);
1210 selectmask();
1212 setmask(0xff);
1213 writeb(image->bg_color, where);
1214 rmb();
1215 readb(where); /* fill latches */
1216 setmode(3);
1217 wmb();
1218 for (y = 0; y < image->height; y++) {
1219 dst = where;
1220 for (x = image->width/8; x--;)
1221 writeb(*cdat++, dst++);
1222 where += info->fix.line_length;
1224 wmb();
1225 } else {
1226 setmode(0);
1227 setop(0);
1228 setsr(0xf);
1229 setcolor(image->bg_color);
1230 selectmask();
1232 setmask(0xff);
1233 for (y = 0; y < image->height; y++) {
1234 dst = where;
1235 for (x=image->width/8; x--;){
1236 rmw(dst);
1237 setcolor(image->fg_color);
1238 selectmask();
1239 if (*cdat) {
1240 setmask(*cdat++);
1241 rmw(dst++);
1244 where += info->fix.line_length;
1247 } else
1248 vga_8planes_imageblit(info, image);
1249 break;
1250 case FB_TYPE_PACKED_PIXELS:
1251 default:
1252 cfb_imageblit(info, image);
1253 break;
1257 static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
1260 * Draw logo
1262 struct vga16fb_par *par = info->par;
1263 char __iomem *where =
1264 info->screen_base + image->dy * info->fix.line_length +
1265 image->dx/8;
1266 const char *cdat = image->data;
1267 char __iomem *dst;
1268 int x, y;
1270 switch (info->fix.type) {
1271 case FB_TYPE_VGA_PLANES:
1272 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
1273 par->isVGA) {
1274 setsr(0xf);
1275 setop(0);
1276 setmode(0);
1278 for (y = 0; y < image->height; y++) {
1279 for (x = 0; x < image->width; x++) {
1280 dst = where + x/8;
1282 setcolor(*cdat);
1283 selectmask();
1284 setmask(1 << (7 - (x % 8)));
1285 fb_readb(dst);
1286 fb_writeb(0, dst);
1288 cdat++;
1290 where += info->fix.line_length;
1293 break;
1294 case FB_TYPE_PACKED_PIXELS:
1295 cfb_imageblit(info, image);
1296 break;
1297 default:
1298 break;
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);
1306 else
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,
1324 #ifndef MODULE
1325 static int vga16fb_setup(char *options)
1327 char *this_opt;
1329 if (!options || !*options)
1330 return 0;
1332 while ((this_opt = strsep(&options, ",")) != NULL) {
1333 if (!*this_opt) continue;
1335 return 0;
1337 #endif
1339 static int __init vga16fb_probe(struct platform_device *dev)
1341 struct fb_info *info;
1342 struct vga16fb_par *par;
1343 int i;
1344 int ret = 0;
1346 printk(KERN_DEBUG "vga16fb: initializing\n");
1347 info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
1349 if (!info) {
1350 ret = -ENOMEM;
1351 goto err_fb_alloc;
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");
1359 ret = -ENOMEM;
1360 goto err_ioremap;
1363 printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
1364 par = info->par;
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);
1388 if (ret) {
1389 printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
1390 ret = -ENOMEM;
1391 goto err_alloc_cmap;
1394 if (vga16fb_check_var(&info->var, info)) {
1395 printk(KERN_ERR "vga16fb: unable to validate variable\n");
1396 ret = -EINVAL;
1397 goto err_check_var;
1400 vga16fb_update_fix(info);
1402 if (register_framebuffer(info) < 0) {
1403 printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
1404 ret = -EINVAL;
1405 goto err_check_var;
1408 printk(KERN_INFO "fb%d: %s frame buffer device\n",
1409 info->node, info->fix.id);
1410 platform_set_drvdata(dev, info);
1412 return 0;
1414 err_check_var:
1415 fb_dealloc_cmap(&info->cmap);
1416 err_alloc_cmap:
1417 iounmap(info->screen_base);
1418 err_ioremap:
1419 framebuffer_release(info);
1420 err_fb_alloc:
1421 return ret;
1424 static int vga16fb_remove(struct platform_device *dev)
1426 struct fb_info *info = platform_get_drvdata(dev);
1428 if (info) {
1429 unregister_framebuffer(info);
1430 iounmap(info->screen_base);
1431 fb_dealloc_cmap(&info->cmap);
1432 /* XXX unshare VGA regions */
1433 framebuffer_release(info);
1436 return 0;
1439 static struct platform_driver vga16fb_driver = {
1440 .probe = vga16fb_probe,
1441 .remove = vga16fb_remove,
1442 .driver = {
1443 .name = "vga16fb",
1447 static struct platform_device *vga16fb_device;
1449 static int __init vga16fb_init(void)
1451 int ret;
1452 #ifndef MODULE
1453 char *option = NULL;
1455 if (fb_get_options("vga16fb", &option))
1456 return -ENODEV;
1458 vga16fb_setup(option);
1459 #endif
1460 ret = platform_driver_register(&vga16fb_driver);
1462 if (!ret) {
1463 vga16fb_device = platform_device_alloc("vga16fb", 0);
1465 if (vga16fb_device)
1466 ret = platform_device_add(vga16fb_device);
1467 else
1468 ret = -ENOMEM;
1470 if (ret) {
1471 platform_device_put(vga16fb_device);
1472 platform_driver_unregister(&vga16fb_driver);
1476 return ret;
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 * ---------------------------------------------------------------------------
1493 * Local variables:
1494 * c-basic-offset: 8
1495 * End: