0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/module.h>
0014 #include <linux/kernel.h>
0015 #include <linux/errno.h>
0016 #include <linux/string.h>
0017 #include <linux/mm.h>
0018 #include <linux/delay.h>
0019 #include <linux/fb.h>
0020 #include <linux/ioport.h>
0021 #include <linux/init.h>
0022 #include <linux/platform_device.h>
0023 #include <linux/screen_info.h>
0024
0025 #include <asm/io.h>
0026 #include <video/vga.h>
0027
0028 #define VGA_FB_PHYS 0xA0000
0029 #define VGA_FB_PHYS_LEN 65536
0030
0031 #define MODE_SKIP4 1
0032 #define MODE_8BPP 2
0033 #define MODE_CFB 4
0034 #define MODE_TEXT 8
0035
0036
0037
0038
0039
0040
0041
0042 struct vga16fb_par {
0043
0044
0045 struct {
0046 unsigned char SeqCtrlIndex;
0047 unsigned char CrtCtrlIndex;
0048 unsigned char CrtMiscIO;
0049 unsigned char HorizontalTotal;
0050 unsigned char HorizDisplayEnd;
0051 unsigned char StartHorizRetrace;
0052 unsigned char EndHorizRetrace;
0053 unsigned char Overflow;
0054 unsigned char StartVertRetrace;
0055 unsigned char EndVertRetrace;
0056 unsigned char ModeControl;
0057 unsigned char ClockingMode;
0058 } vga_state;
0059 struct vgastate state;
0060 unsigned int ref_count;
0061 int palette_blanked, vesa_blanked, mode, isVGA;
0062 u8 misc, pel_msk, vss, clkdiv;
0063 u8 crtc[VGA_CRT_C];
0064 };
0065
0066
0067
0068 static struct fb_var_screeninfo vga16fb_defined = {
0069 .xres = 640,
0070 .yres = 480,
0071 .xres_virtual = 640,
0072 .yres_virtual = 480,
0073 .bits_per_pixel = 4,
0074 .activate = FB_ACTIVATE_TEST,
0075 .height = -1,
0076 .width = -1,
0077 .pixclock = 39721,
0078 .left_margin = 48,
0079 .right_margin = 16,
0080 .upper_margin = 33,
0081 .lower_margin = 10,
0082 .hsync_len = 96,
0083 .vsync_len = 2,
0084 .vmode = FB_VMODE_NONINTERLACED,
0085 };
0086
0087
0088 static const struct fb_fix_screeninfo vga16fb_fix = {
0089 .id = "VGA16 VGA",
0090 .smem_start = VGA_FB_PHYS,
0091 .smem_len = VGA_FB_PHYS_LEN,
0092 .type = FB_TYPE_VGA_PLANES,
0093 .type_aux = FB_AUX_VGA_PLANES_VGA4,
0094 .visual = FB_VISUAL_PSEUDOCOLOR,
0095 .xpanstep = 8,
0096 .ypanstep = 1,
0097 .line_length = 640 / 8,
0098 .accel = FB_ACCEL_NONE
0099 };
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112 static inline void rmw(volatile char __iomem *p)
0113 {
0114 readb(p);
0115 writeb(1, p);
0116 }
0117
0118
0119
0120 static inline int setmode(int mode)
0121 {
0122 int oldmode;
0123
0124 oldmode = vga_io_rgfx(VGA_GFX_MODE);
0125 vga_io_w(VGA_GFX_D, mode);
0126 return oldmode;
0127 }
0128
0129
0130 static inline int selectmask(void)
0131 {
0132 return vga_io_rgfx(VGA_GFX_BIT_MASK);
0133 }
0134
0135
0136
0137 static inline void setmask(int mask)
0138 {
0139 vga_io_w(VGA_GFX_D, mask);
0140 }
0141
0142
0143
0144
0145 static inline int setop(int op)
0146 {
0147 int oldop;
0148
0149 oldop = vga_io_rgfx(VGA_GFX_DATA_ROTATE);
0150 vga_io_w(VGA_GFX_D, op);
0151 return oldop;
0152 }
0153
0154
0155
0156 static inline int setsr(int sr)
0157 {
0158 int oldsr;
0159
0160 oldsr = vga_io_rgfx(VGA_GFX_SR_ENABLE);
0161 vga_io_w(VGA_GFX_D, sr);
0162 return oldsr;
0163 }
0164
0165
0166 static inline int setcolor(int color)
0167 {
0168 int oldcolor;
0169
0170 oldcolor = vga_io_rgfx(VGA_GFX_SR_VALUE);
0171 vga_io_w(VGA_GFX_D, color);
0172 return oldcolor;
0173 }
0174
0175
0176 static inline int getindex(void)
0177 {
0178 return vga_io_r(VGA_GFX_I);
0179 }
0180
0181
0182 static inline void setindex(int index)
0183 {
0184 vga_io_w(VGA_GFX_I, index);
0185 }
0186
0187
0188 static inline int check_mode_supported(void)
0189 {
0190
0191 #if defined(CONFIG_X86)
0192
0193 if (screen_info.orig_video_isVGA != VIDEO_TYPE_EGAC &&
0194 screen_info.orig_video_isVGA != VIDEO_TYPE_VGAC)
0195 return -ENODEV;
0196
0197 if (screen_info.orig_video_mode != 0x0D &&
0198 screen_info.orig_video_mode != 0x0E &&
0199 screen_info.orig_video_mode != 0x10 &&
0200 screen_info.orig_video_mode != 0x12)
0201 return -ENODEV;
0202 #endif
0203 return 0;
0204 }
0205
0206 static void vga16fb_pan_var(struct fb_info *info,
0207 struct fb_var_screeninfo *var)
0208 {
0209 struct vga16fb_par *par = info->par;
0210 u32 xoffset, pos;
0211
0212 xoffset = var->xoffset;
0213 if (info->var.bits_per_pixel == 8) {
0214 pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2;
0215 } else if (par->mode & MODE_TEXT) {
0216 int fh = 16;
0217 pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3;
0218 } else {
0219 if (info->var.nonstd)
0220 xoffset--;
0221 pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3;
0222 }
0223 vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8);
0224 vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF);
0225
0226
0227 vga_io_r(VGA_IS1_RC);
0228 vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
0229 if (info->var.bits_per_pixel == 8)
0230 vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
0231 else
0232 vga_io_w(VGA_ATT_IW, xoffset & 7);
0233 vga_io_r(VGA_IS1_RC);
0234 vga_io_w(VGA_ATT_IW, 0x20);
0235 }
0236
0237 static void vga16fb_update_fix(struct fb_info *info)
0238 {
0239 if (info->var.bits_per_pixel == 4) {
0240 if (info->var.nonstd) {
0241 info->fix.type = FB_TYPE_PACKED_PIXELS;
0242 info->fix.line_length = info->var.xres_virtual / 2;
0243 } else {
0244 info->fix.type = FB_TYPE_VGA_PLANES;
0245 info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4;
0246 info->fix.line_length = info->var.xres_virtual / 8;
0247 }
0248 } else if (info->var.bits_per_pixel == 0) {
0249 info->fix.type = FB_TYPE_TEXT;
0250 info->fix.type_aux = FB_AUX_TEXT_CGA;
0251 info->fix.line_length = info->var.xres_virtual / 4;
0252 } else {
0253 if (info->var.nonstd) {
0254 info->fix.type = FB_TYPE_VGA_PLANES;
0255 info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8;
0256 info->fix.line_length = info->var.xres_virtual / 4;
0257 } else {
0258 info->fix.type = FB_TYPE_PACKED_PIXELS;
0259 info->fix.line_length = info->var.xres_virtual;
0260 }
0261 }
0262 }
0263
0264 static void vga16fb_clock_chip(struct vga16fb_par *par,
0265 unsigned int *pixclock,
0266 const struct fb_info *info,
0267 int mul, int div)
0268 {
0269 static const struct {
0270 u32 pixclock;
0271 u8 misc;
0272 u8 seq_clock_mode;
0273 } *ptr, *best, vgaclocks[] = {
0274 { 79442 , 0x00, 0x08},
0275 { 70616 , 0x04, 0x08},
0276 { 39721 , 0x00, 0x00},
0277 { 35308 , 0x04, 0x00},
0278 { 0 , 0x00, 0x00}};
0279 int err;
0280
0281 *pixclock = (*pixclock * mul) / div;
0282 best = vgaclocks;
0283 err = *pixclock - best->pixclock;
0284 if (err < 0) err = -err;
0285 for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
0286 int tmp;
0287
0288 tmp = *pixclock - ptr->pixclock;
0289 if (tmp < 0) tmp = -tmp;
0290 if (tmp < err) {
0291 err = tmp;
0292 best = ptr;
0293 }
0294 }
0295 par->misc |= best->misc;
0296 par->clkdiv = best->seq_clock_mode;
0297 *pixclock = (best->pixclock * div) / mul;
0298 }
0299
0300 #define FAIL(X) return -EINVAL
0301
0302 static int vga16fb_open(struct fb_info *info, int user)
0303 {
0304 struct vga16fb_par *par = info->par;
0305
0306 if (!par->ref_count) {
0307 memset(&par->state, 0, sizeof(struct vgastate));
0308 par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
0309 VGA_SAVE_CMAP;
0310 save_vga(&par->state);
0311 }
0312 par->ref_count++;
0313
0314 return 0;
0315 }
0316
0317 static int vga16fb_release(struct fb_info *info, int user)
0318 {
0319 struct vga16fb_par *par = info->par;
0320
0321 if (!par->ref_count)
0322 return -EINVAL;
0323
0324 if (par->ref_count == 1)
0325 restore_vga(&par->state);
0326 par->ref_count--;
0327
0328 return 0;
0329 }
0330
0331 static int vga16fb_check_var(struct fb_var_screeninfo *var,
0332 struct fb_info *info)
0333 {
0334 struct vga16fb_par *par = info->par;
0335 u32 xres, right, hslen, left, xtotal;
0336 u32 yres, lower, vslen, upper, ytotal;
0337 u32 vxres, xoffset, vyres, yoffset;
0338 u32 pos;
0339 u8 r7, rMode;
0340 int shift;
0341 int mode;
0342 u32 maxmem;
0343
0344 par->pel_msk = 0xFF;
0345
0346 if (var->bits_per_pixel == 4) {
0347 if (var->nonstd) {
0348 if (!par->isVGA)
0349 return -EINVAL;
0350 shift = 3;
0351 mode = MODE_SKIP4 | MODE_CFB;
0352 maxmem = 16384;
0353 par->pel_msk = 0x0F;
0354 } else {
0355 shift = 3;
0356 mode = 0;
0357 maxmem = 65536;
0358 }
0359 } else if (var->bits_per_pixel == 8) {
0360 if (!par->isVGA)
0361 return -EINVAL;
0362 shift = 2;
0363 if (var->nonstd) {
0364 mode = MODE_8BPP | MODE_CFB;
0365 maxmem = 65536;
0366 } else {
0367 mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;
0368 maxmem = 16384;
0369 }
0370 } else
0371 return -EINVAL;
0372
0373 xres = (var->xres + 7) & ~7;
0374 vxres = (var->xres_virtual + 0xF) & ~0xF;
0375 xoffset = (var->xoffset + 7) & ~7;
0376 left = (var->left_margin + 7) & ~7;
0377 right = (var->right_margin + 7) & ~7;
0378 hslen = (var->hsync_len + 7) & ~7;
0379
0380 if (vxres < xres)
0381 vxres = xres;
0382 if (xres + xoffset > vxres)
0383 xoffset = vxres - xres;
0384
0385 var->xres = xres;
0386 var->right_margin = right;
0387 var->hsync_len = hslen;
0388 var->left_margin = left;
0389 var->xres_virtual = vxres;
0390 var->xoffset = xoffset;
0391
0392 xres >>= shift;
0393 right >>= shift;
0394 hslen >>= shift;
0395 left >>= shift;
0396 vxres >>= shift;
0397 xtotal = xres + right + hslen + left;
0398 if (xtotal >= 256)
0399 FAIL("xtotal too big");
0400 if (hslen > 32)
0401 FAIL("hslen too big");
0402 if (right + hslen + left > 64)
0403 FAIL("hblank too big");
0404 par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
0405 par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
0406 par->crtc[VGA_CRTC_H_DISP] = xres - 1;
0407 pos = xres + right;
0408 par->crtc[VGA_CRTC_H_SYNC_START] = pos;
0409 pos += hslen;
0410 par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
0411 pos += left - 2;
0412 par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
0413 if (pos & 0x20)
0414 par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
0415
0416 yres = var->yres;
0417 lower = var->lower_margin;
0418 vslen = var->vsync_len;
0419 upper = var->upper_margin;
0420 vyres = var->yres_virtual;
0421 yoffset = var->yoffset;
0422
0423 if (yres > vyres)
0424 vyres = yres;
0425 if (vxres * vyres > maxmem) {
0426 vyres = maxmem / vxres;
0427 if (vyres < yres)
0428 return -ENOMEM;
0429 }
0430 if (yoffset + yres > vyres)
0431 yoffset = vyres - yres;
0432 var->yres = yres;
0433 var->lower_margin = lower;
0434 var->vsync_len = vslen;
0435 var->upper_margin = upper;
0436 var->yres_virtual = vyres;
0437 var->yoffset = yoffset;
0438
0439 if (var->vmode & FB_VMODE_DOUBLE) {
0440 yres <<= 1;
0441 lower <<= 1;
0442 vslen <<= 1;
0443 upper <<= 1;
0444 }
0445 ytotal = yres + lower + vslen + upper;
0446 if (ytotal > 1024) {
0447 ytotal >>= 1;
0448 yres >>= 1;
0449 lower >>= 1;
0450 vslen >>= 1;
0451 upper >>= 1;
0452 rMode = 0x04;
0453 } else
0454 rMode = 0x00;
0455 if (ytotal > 1024)
0456 FAIL("ytotal too big");
0457 if (vslen > 16)
0458 FAIL("vslen too big");
0459 par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
0460 r7 = 0x10;
0461 if (ytotal & 0x100) r7 |= 0x01;
0462 if (ytotal & 0x200) r7 |= 0x20;
0463 par->crtc[VGA_CRTC_PRESET_ROW] = 0;
0464 par->crtc[VGA_CRTC_MAX_SCAN] = 0x40;
0465 if (var->vmode & FB_VMODE_DOUBLE)
0466 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
0467 par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
0468 par->crtc[VGA_CRTC_CURSOR_END] = 0x00;
0469 if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB)
0470 xoffset--;
0471 pos = yoffset * vxres + (xoffset >> shift);
0472 par->crtc[VGA_CRTC_START_HI] = pos >> 8;
0473 par->crtc[VGA_CRTC_START_LO] = pos & 0xFF;
0474 par->crtc[VGA_CRTC_CURSOR_HI] = 0x00;
0475 par->crtc[VGA_CRTC_CURSOR_LO] = 0x00;
0476 pos = yres - 1;
0477 par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
0478 par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
0479 if (pos & 0x100)
0480 r7 |= 0x0A;
0481 if (pos & 0x200) {
0482 r7 |= 0x40;
0483 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20;
0484 }
0485 pos += lower;
0486 par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
0487 if (pos & 0x100)
0488 r7 |= 0x04;
0489 if (pos & 0x200)
0490 r7 |= 0x80;
0491 pos += vslen;
0492 par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10;
0493 pos += upper - 1;
0494 par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF;
0495
0496 if (vxres >= 512)
0497 FAIL("vxres too long");
0498 par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
0499 if (mode & MODE_SKIP4)
0500 par->crtc[VGA_CRTC_UNDERLINE] = 0x5F;
0501 else
0502 par->crtc[VGA_CRTC_UNDERLINE] = 0x1F;
0503 par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3);
0504 par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
0505 par->crtc[VGA_CRTC_OVERFLOW] = r7;
0506
0507 par->vss = 0x00;
0508
0509 par->misc = 0xE3;
0510 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
0511 par->misc &= ~0x40;
0512 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
0513 par->misc &= ~0x80;
0514
0515 par->mode = mode;
0516
0517 if (mode & MODE_8BPP)
0518
0519 vga16fb_clock_chip(par, &var->pixclock, info, 1, 2);
0520 else
0521
0522 vga16fb_clock_chip(par, &var->pixclock, info, 1, 1);
0523
0524 var->red.offset = var->green.offset = var->blue.offset =
0525 var->transp.offset = 0;
0526 var->red.length = var->green.length = var->blue.length =
0527 (par->isVGA) ? 6 : 2;
0528 var->transp.length = 0;
0529 var->activate = FB_ACTIVATE_NOW;
0530 var->height = -1;
0531 var->width = -1;
0532 var->accel_flags = 0;
0533 return 0;
0534 }
0535 #undef FAIL
0536
0537 static int vga16fb_set_par(struct fb_info *info)
0538 {
0539 struct vga16fb_par *par = info->par;
0540 u8 gdc[VGA_GFX_C];
0541 u8 seq[VGA_SEQ_C];
0542 u8 atc[VGA_ATT_C];
0543 int fh, i;
0544
0545 seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv;
0546 if (par->mode & MODE_TEXT)
0547 seq[VGA_SEQ_PLANE_WRITE] = 0x03;
0548 else
0549 seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
0550 seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
0551 if (par->mode & MODE_TEXT)
0552 seq[VGA_SEQ_MEMORY_MODE] = 0x03;
0553 else if (par->mode & MODE_SKIP4)
0554 seq[VGA_SEQ_MEMORY_MODE] = 0x0E;
0555 else
0556 seq[VGA_SEQ_MEMORY_MODE] = 0x06;
0557
0558 gdc[VGA_GFX_SR_VALUE] = 0x00;
0559 gdc[VGA_GFX_SR_ENABLE] = 0x00;
0560 gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
0561 gdc[VGA_GFX_DATA_ROTATE] = 0x00;
0562 gdc[VGA_GFX_PLANE_READ] = 0;
0563 if (par->mode & MODE_TEXT) {
0564 gdc[VGA_GFX_MODE] = 0x10;
0565 gdc[VGA_GFX_MISC] = 0x06;
0566 } else {
0567 if (par->mode & MODE_CFB)
0568 gdc[VGA_GFX_MODE] = 0x40;
0569 else
0570 gdc[VGA_GFX_MODE] = 0x00;
0571 gdc[VGA_GFX_MISC] = 0x05;
0572 }
0573 gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
0574 gdc[VGA_GFX_BIT_MASK] = 0xFF;
0575
0576 for (i = 0x00; i < 0x10; i++)
0577 atc[i] = i;
0578 if (par->mode & MODE_TEXT)
0579 atc[VGA_ATC_MODE] = 0x04;
0580 else if (par->mode & MODE_8BPP)
0581 atc[VGA_ATC_MODE] = 0x41;
0582 else
0583 atc[VGA_ATC_MODE] = 0x81;
0584 atc[VGA_ATC_OVERSCAN] = 0x00;
0585 atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
0586 if (par->mode & MODE_8BPP)
0587 atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1;
0588 else
0589 atc[VGA_ATC_PEL] = info->var.xoffset & 7;
0590 atc[VGA_ATC_COLOR_PAGE] = 0x00;
0591
0592 if (par->mode & MODE_TEXT) {
0593 fh = 16;
0594 par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN]
0595 & ~0x1F) | (fh - 1);
0596 }
0597
0598 vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
0599
0600
0601 if (!par->isVGA) {
0602 vga_io_w(EGA_GFX_E0, 0x00);
0603 vga_io_w(EGA_GFX_E1, 0x01);
0604 }
0605
0606
0607 vga_io_w(VGA_MIS_W, par->misc);
0608
0609
0610 vga_io_wseq(0x00, 0x01);
0611
0612 if (par->isVGA)
0613 vga_io_w(VGA_PEL_MSK, par->pel_msk);
0614
0615
0616 vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20);
0617 for (i = 2; i < VGA_SEQ_C; i++) {
0618 vga_io_wseq(i, seq[i]);
0619 }
0620
0621
0622 vga_io_wseq(0x00, 0x03);
0623
0624
0625 vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
0626
0627
0628 for (i = 0; i < VGA_CRTC_REGS; i++) {
0629 vga_io_wcrt(i, par->crtc[i]);
0630 }
0631
0632
0633 for (i = 0; i < VGA_GFX_C; i++) {
0634 vga_io_wgfx(i, gdc[i]);
0635 }
0636
0637
0638 for (i = 0; i < VGA_ATT_C; i++) {
0639 vga_io_r(VGA_IS1_RC);
0640 vga_io_wattr(i, atc[i]);
0641 }
0642
0643
0644 mdelay(50);
0645
0646 vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]);
0647
0648 vga_io_r(VGA_IS1_RC);
0649 vga_io_w(VGA_ATT_IW, 0x20);
0650
0651 vga16fb_update_fix(info);
0652 return 0;
0653 }
0654
0655 static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
0656 {
0657 static const unsigned char map[] = { 000, 001, 010, 011 };
0658 int val;
0659
0660 if (regno >= 16)
0661 return;
0662 val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
0663 vga_io_r(VGA_IS1_RC);
0664 vga_io_wattr(regno, val);
0665 vga_io_r(VGA_IS1_RC);
0666 vga_io_w(VGA_ATT_IW, 0x20);
0667 }
0668
0669 static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
0670 {
0671 outb(regno, VGA_PEL_IW);
0672 outb(red >> 10, VGA_PEL_D);
0673 outb(green >> 10, VGA_PEL_D);
0674 outb(blue >> 10, VGA_PEL_D);
0675 }
0676
0677 static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
0678 unsigned blue, unsigned transp,
0679 struct fb_info *info)
0680 {
0681 struct vga16fb_par *par = info->par;
0682 int gray;
0683
0684
0685
0686
0687
0688
0689
0690
0691 if (regno >= 256)
0692 return 1;
0693
0694 gray = info->var.grayscale;
0695
0696 if (gray) {
0697
0698 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
0699 }
0700 if (par->isVGA)
0701 vga16_setpalette(regno,red,green,blue);
0702 else
0703 ega16_setpalette(regno,red,green,blue);
0704 return 0;
0705 }
0706
0707 static int vga16fb_pan_display(struct fb_var_screeninfo *var,
0708 struct fb_info *info)
0709 {
0710 vga16fb_pan_var(info, var);
0711 return 0;
0712 }
0713
0714
0715
0716
0717
0718
0719 static void vga_vesa_blank(struct vga16fb_par *par, int mode)
0720 {
0721 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
0722 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
0723
0724
0725 if(!par->vesa_blanked) {
0726 par->vga_state.CrtMiscIO = vga_io_r(VGA_MIS_R);
0727
0728
0729 par->vga_state.HorizontalTotal = vga_io_rcrt(0x00);
0730 par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01);
0731 par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04);
0732 par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05);
0733 par->vga_state.Overflow = vga_io_rcrt(0x07);
0734 par->vga_state.StartVertRetrace = vga_io_rcrt(0x10);
0735 par->vga_state.EndVertRetrace = vga_io_rcrt(0x11);
0736 par->vga_state.ModeControl = vga_io_rcrt(0x17);
0737 par->vga_state.ClockingMode = vga_io_rseq(0x01);
0738 }
0739
0740
0741
0742 vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20);
0743
0744
0745 if ((par->vga_state.CrtMiscIO & 0x80) == 0x80)
0746 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO & 0xef);
0747
0748
0749
0750
0751
0752
0753 if (mode & FB_BLANK_VSYNC_SUSPEND) {
0754 vga_io_wcrt(VGA_CRTC_V_SYNC_START, 0xff);
0755 vga_io_wcrt(VGA_CRTC_V_SYNC_END, 0x40);
0756
0757 vga_io_wcrt(VGA_CRTC_OVERFLOW, par->vga_state.Overflow | 0x84);
0758 }
0759
0760 if (mode & FB_BLANK_HSYNC_SUSPEND) {
0761
0762
0763
0764
0765
0766 vga_io_wcrt(VGA_CRTC_H_SYNC_START, 0xff);
0767 vga_io_wcrt(VGA_CRTC_H_SYNC_END, 0x00);
0768 }
0769
0770
0771 outb_p(SeqCtrlIndex, VGA_SEQ_I);
0772 outb_p(CrtCtrlIndex, VGA_CRT_IC);
0773 }
0774
0775 static void vga_vesa_unblank(struct vga16fb_par *par)
0776 {
0777 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
0778 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
0779
0780
0781 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO);
0782
0783
0784 vga_io_wcrt(0x00, par->vga_state.HorizontalTotal);
0785
0786 vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd);
0787
0788 vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace);
0789
0790 vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace);
0791
0792 vga_io_wcrt(0x07, par->vga_state.Overflow);
0793
0794 vga_io_wcrt(0x10, par->vga_state.StartVertRetrace);
0795
0796 vga_io_wcrt(0x11, par->vga_state.EndVertRetrace);
0797
0798 vga_io_wcrt(0x17, par->vga_state.ModeControl);
0799
0800 vga_io_wseq(0x01, par->vga_state.ClockingMode);
0801
0802
0803 vga_io_w(VGA_SEQ_I, SeqCtrlIndex);
0804 vga_io_w(VGA_CRT_IC, CrtCtrlIndex);
0805 }
0806
0807 static void vga_pal_blank(void)
0808 {
0809 int i;
0810
0811 for (i=0; i<16; i++) {
0812 outb_p(i, VGA_PEL_IW);
0813 outb_p(0, VGA_PEL_D);
0814 outb_p(0, VGA_PEL_D);
0815 outb_p(0, VGA_PEL_D);
0816 }
0817 }
0818
0819
0820 static int vga16fb_blank(int blank, struct fb_info *info)
0821 {
0822 struct vga16fb_par *par = info->par;
0823
0824 switch (blank) {
0825 case FB_BLANK_UNBLANK:
0826 if (par->vesa_blanked) {
0827 vga_vesa_unblank(par);
0828 par->vesa_blanked = 0;
0829 }
0830 if (par->palette_blanked) {
0831 par->palette_blanked = 0;
0832 }
0833 break;
0834 case FB_BLANK_NORMAL:
0835 vga_pal_blank();
0836 par->palette_blanked = 1;
0837 break;
0838 default:
0839 vga_vesa_blank(par, blank);
0840 par->vesa_blanked = 1;
0841 break;
0842 }
0843 return 0;
0844 }
0845
0846 static void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
0847 {
0848 u32 dx = rect->dx, width = rect->width;
0849 char oldindex = getindex();
0850 char oldmode = setmode(0x40);
0851 char oldmask = selectmask();
0852 int line_ofs, height;
0853 char oldop, oldsr;
0854 char __iomem *where;
0855
0856 dx /= 4;
0857 where = info->screen_base + dx + rect->dy * info->fix.line_length;
0858
0859 if (rect->rop == ROP_COPY) {
0860 oldop = setop(0);
0861 oldsr = setsr(0);
0862
0863 width /= 4;
0864 line_ofs = info->fix.line_length - width;
0865 setmask(0xff);
0866
0867 height = rect->height;
0868
0869 while (height--) {
0870 int x;
0871
0872
0873 for (x = width; x > 0; --x) {
0874 writeb(rect->color, where);
0875 where++;
0876 }
0877 where += line_ofs;
0878 }
0879 } else {
0880 char oldcolor = setcolor(0xf);
0881 int y;
0882
0883 oldop = setop(0x18);
0884 oldsr = setsr(0xf);
0885 setmask(0x0F);
0886 for (y = 0; y < rect->height; y++) {
0887 rmw(where);
0888 rmw(where+1);
0889 where += info->fix.line_length;
0890 }
0891 setcolor(oldcolor);
0892 }
0893 setmask(oldmask);
0894 setsr(oldsr);
0895 setop(oldop);
0896 setmode(oldmode);
0897 setindex(oldindex);
0898 }
0899
0900 static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
0901 {
0902 int x, x2, y2, vxres, vyres, width, height, line_ofs;
0903 char __iomem *dst;
0904
0905 vxres = info->var.xres_virtual;
0906 vyres = info->var.yres_virtual;
0907
0908 if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
0909 return;
0910
0911
0912
0913
0914 x2 = rect->dx + rect->width;
0915 y2 = rect->dy + rect->height;
0916 x2 = x2 < vxres ? x2 : vxres;
0917 y2 = y2 < vyres ? y2 : vyres;
0918 width = x2 - rect->dx;
0919
0920 switch (info->fix.type) {
0921 case FB_TYPE_VGA_PLANES:
0922 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
0923
0924 height = y2 - rect->dy;
0925 width = rect->width/8;
0926
0927 line_ofs = info->fix.line_length - width;
0928 dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length;
0929
0930 switch (rect->rop) {
0931 case ROP_COPY:
0932 setmode(0);
0933 setop(0);
0934 setsr(0xf);
0935 setcolor(rect->color);
0936 selectmask();
0937
0938 setmask(0xff);
0939
0940 while (height--) {
0941 for (x = 0; x < width; x++) {
0942 writeb(0, dst);
0943 dst++;
0944 }
0945 dst += line_ofs;
0946 }
0947 break;
0948 case ROP_XOR:
0949 setmode(0);
0950 setop(0x18);
0951 setsr(0xf);
0952 setcolor(0xf);
0953 selectmask();
0954
0955 setmask(0xff);
0956 while (height--) {
0957 for (x = 0; x < width; x++) {
0958 rmw(dst);
0959 dst++;
0960 }
0961 dst += line_ofs;
0962 }
0963 break;
0964 }
0965 } else
0966 vga_8planes_fillrect(info, rect);
0967 break;
0968 case FB_TYPE_PACKED_PIXELS:
0969 default:
0970 cfb_fillrect(info, rect);
0971 break;
0972 }
0973 }
0974
0975 static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
0976 {
0977 char oldindex = getindex();
0978 char oldmode = setmode(0x41);
0979 char oldop = setop(0);
0980 char oldsr = setsr(0xf);
0981 int height, line_ofs, x;
0982 u32 sx, dx, width;
0983 char __iomem *dest;
0984 char __iomem *src;
0985
0986 height = area->height;
0987
0988 sx = area->sx / 4;
0989 dx = area->dx / 4;
0990 width = area->width / 4;
0991
0992 if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) {
0993 line_ofs = info->fix.line_length - width;
0994 dest = info->screen_base + dx + area->dy * info->fix.line_length;
0995 src = info->screen_base + sx + area->sy * info->fix.line_length;
0996 while (height--) {
0997 for (x = 0; x < width; x++) {
0998 readb(src);
0999 writeb(0, dest);
1000 src++;
1001 dest++;
1002 }
1003 src += line_ofs;
1004 dest += line_ofs;
1005 }
1006 } else {
1007 line_ofs = info->fix.line_length - width;
1008 dest = info->screen_base + dx + width +
1009 (area->dy + height - 1) * info->fix.line_length;
1010 src = info->screen_base + sx + width +
1011 (area->sy + height - 1) * info->fix.line_length;
1012 while (height--) {
1013 for (x = 0; x < width; x++) {
1014 --src;
1015 --dest;
1016 readb(src);
1017 writeb(0, dest);
1018 }
1019 src -= line_ofs;
1020 dest -= line_ofs;
1021 }
1022 }
1023
1024 setsr(oldsr);
1025 setop(oldop);
1026 setmode(oldmode);
1027 setindex(oldindex);
1028 }
1029
1030 static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1031 {
1032 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
1033 int x, x2, y2, old_dx, old_dy, vxres, vyres;
1034 int height, width, line_ofs;
1035 char __iomem *dst = NULL;
1036 char __iomem *src = NULL;
1037
1038 vxres = info->var.xres_virtual;
1039 vyres = info->var.yres_virtual;
1040
1041 if (area->dx > vxres || area->sx > vxres || area->dy > vyres ||
1042 area->sy > vyres)
1043 return;
1044
1045
1046 old_dx = area->dx;
1047 old_dy = area->dy;
1048
1049
1050
1051
1052
1053 x2 = area->dx + area->width;
1054 y2 = area->dy + area->height;
1055 dx = area->dx > 0 ? area->dx : 0;
1056 dy = area->dy > 0 ? area->dy : 0;
1057 x2 = x2 < vxres ? x2 : vxres;
1058 y2 = y2 < vyres ? y2 : vyres;
1059 width = x2 - dx;
1060 height = y2 - dy;
1061
1062 if (sx + dx < old_dx || sy + dy < old_dy)
1063 return;
1064
1065
1066 sx += (dx - old_dx);
1067 sy += (dy - old_dy);
1068
1069
1070 if (sx + width > vxres || sy + height > vyres)
1071 return;
1072
1073 switch (info->fix.type) {
1074 case FB_TYPE_VGA_PLANES:
1075 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1076 width = width/8;
1077 line_ofs = info->fix.line_length - width;
1078
1079 setmode(1);
1080 setop(0);
1081 setsr(0xf);
1082
1083 if (dy < sy || (dy == sy && dx < sx)) {
1084 dst = info->screen_base + (dx/8) + dy * info->fix.line_length;
1085 src = info->screen_base + (sx/8) + sy * info->fix.line_length;
1086 while (height--) {
1087 for (x = 0; x < width; x++) {
1088 readb(src);
1089 writeb(0, dst);
1090 dst++;
1091 src++;
1092 }
1093 src += line_ofs;
1094 dst += line_ofs;
1095 }
1096 } else {
1097 dst = info->screen_base + (dx/8) + width +
1098 (dy + height - 1) * info->fix.line_length;
1099 src = info->screen_base + (sx/8) + width +
1100 (sy + height - 1) * info->fix.line_length;
1101 while (height--) {
1102 for (x = 0; x < width; x++) {
1103 dst--;
1104 src--;
1105 readb(src);
1106 writeb(0, dst);
1107 }
1108 src -= line_ofs;
1109 dst -= line_ofs;
1110 }
1111 }
1112 } else
1113 vga_8planes_copyarea(info, area);
1114 break;
1115 case FB_TYPE_PACKED_PIXELS:
1116 default:
1117 cfb_copyarea(info, area);
1118 break;
1119 }
1120 }
1121
1122 #define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
1123 #define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
1124 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
1125
1126 #if defined(__LITTLE_ENDIAN)
1127 static const u16 transl_l[] = TRANS_MASK_LOW;
1128 static const u16 transl_h[] = TRANS_MASK_HIGH;
1129 #elif defined(__BIG_ENDIAN)
1130 static const u16 transl_l[] = TRANS_MASK_HIGH;
1131 static const u16 transl_h[] = TRANS_MASK_LOW;
1132 #else
1133 #error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1134 #endif
1135
1136 static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
1137 {
1138 char oldindex = getindex();
1139 char oldmode = setmode(0x40);
1140 char oldop = setop(0);
1141 char oldsr = setsr(0);
1142 char oldmask = selectmask();
1143 const unsigned char *cdat = image->data;
1144 u32 dx = image->dx;
1145 char __iomem *where;
1146 int y;
1147
1148 dx /= 4;
1149 where = info->screen_base + dx + image->dy * info->fix.line_length;
1150
1151 setmask(0xff);
1152 writeb(image->bg_color, where);
1153 readb(where);
1154 selectmask();
1155 setmask(image->fg_color ^ image->bg_color);
1156 setmode(0x42);
1157 setop(0x18);
1158 for (y = 0; y < image->height; y++, where += info->fix.line_length)
1159 writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where);
1160 setmask(oldmask);
1161 setsr(oldsr);
1162 setop(oldop);
1163 setmode(oldmode);
1164 setindex(oldindex);
1165 }
1166
1167 static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
1168 {
1169 char __iomem *where = info->screen_base + (image->dx/8) +
1170 image->dy * info->fix.line_length;
1171 struct vga16fb_par *par = info->par;
1172 char *cdat = (char *) image->data;
1173 char __iomem *dst;
1174 int x, y;
1175
1176 switch (info->fix.type) {
1177 case FB_TYPE_VGA_PLANES:
1178 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1179 if (par->isVGA) {
1180 setmode(2);
1181 setop(0);
1182 setsr(0xf);
1183 setcolor(image->fg_color);
1184 selectmask();
1185
1186 setmask(0xff);
1187 writeb(image->bg_color, where);
1188 rmb();
1189 readb(where);
1190 setmode(3);
1191 wmb();
1192 for (y = 0; y < image->height; y++) {
1193 dst = where;
1194 for (x = image->width/8; x--;)
1195 writeb(*cdat++, dst++);
1196 where += info->fix.line_length;
1197 }
1198 wmb();
1199 } else {
1200 setmode(0);
1201 setop(0);
1202 setsr(0xf);
1203 setcolor(image->bg_color);
1204 selectmask();
1205
1206 setmask(0xff);
1207 for (y = 0; y < image->height; y++) {
1208 dst = where;
1209 for (x=image->width/8; x--;){
1210 rmw(dst);
1211 setcolor(image->fg_color);
1212 selectmask();
1213 if (*cdat) {
1214 setmask(*cdat++);
1215 rmw(dst++);
1216 }
1217 }
1218 where += info->fix.line_length;
1219 }
1220 }
1221 } else
1222 vga_8planes_imageblit(info, image);
1223 break;
1224 case FB_TYPE_PACKED_PIXELS:
1225 default:
1226 cfb_imageblit(info, image);
1227 break;
1228 }
1229 }
1230
1231 static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
1232 {
1233
1234
1235
1236 struct vga16fb_par *par = info->par;
1237 char __iomem *where =
1238 info->screen_base + image->dy * info->fix.line_length +
1239 image->dx/8;
1240 const char *cdat = image->data;
1241 char __iomem *dst;
1242 int x, y;
1243
1244 switch (info->fix.type) {
1245 case FB_TYPE_VGA_PLANES:
1246 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
1247 par->isVGA) {
1248 setsr(0xf);
1249 setop(0);
1250 setmode(0);
1251
1252 for (y = 0; y < image->height; y++) {
1253 for (x = 0; x < image->width; x++) {
1254 dst = where + x/8;
1255
1256 setcolor(*cdat);
1257 selectmask();
1258 setmask(1 << (7 - (x % 8)));
1259 fb_readb(dst);
1260 fb_writeb(0, dst);
1261
1262 cdat++;
1263 }
1264 where += info->fix.line_length;
1265 }
1266 }
1267 break;
1268 case FB_TYPE_PACKED_PIXELS:
1269 cfb_imageblit(info, image);
1270 break;
1271 default:
1272 break;
1273 }
1274 }
1275
1276 static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
1277 {
1278 if (image->depth == 1)
1279 vga_imageblit_expand(info, image);
1280 else
1281 vga_imageblit_color(info, image);
1282 }
1283
1284 static void vga16fb_destroy(struct fb_info *info)
1285 {
1286 iounmap(info->screen_base);
1287 fb_dealloc_cmap(&info->cmap);
1288
1289 framebuffer_release(info);
1290 }
1291
1292 static const struct fb_ops vga16fb_ops = {
1293 .owner = THIS_MODULE,
1294 .fb_open = vga16fb_open,
1295 .fb_release = vga16fb_release,
1296 .fb_destroy = vga16fb_destroy,
1297 .fb_check_var = vga16fb_check_var,
1298 .fb_set_par = vga16fb_set_par,
1299 .fb_setcolreg = vga16fb_setcolreg,
1300 .fb_pan_display = vga16fb_pan_display,
1301 .fb_blank = vga16fb_blank,
1302 .fb_fillrect = vga16fb_fillrect,
1303 .fb_copyarea = vga16fb_copyarea,
1304 .fb_imageblit = vga16fb_imageblit,
1305 };
1306
1307 #ifndef MODULE
1308 static int __init vga16fb_setup(char *options)
1309 {
1310 char *this_opt;
1311
1312 if (!options || !*options)
1313 return 0;
1314
1315 while ((this_opt = strsep(&options, ",")) != NULL) {
1316 if (!*this_opt) continue;
1317 }
1318 return 0;
1319 }
1320 #endif
1321
1322 static int vga16fb_probe(struct platform_device *dev)
1323 {
1324 struct fb_info *info;
1325 struct vga16fb_par *par;
1326 int i;
1327 int ret = 0;
1328
1329 printk(KERN_DEBUG "vga16fb: initializing\n");
1330 info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
1331
1332 if (!info) {
1333 ret = -ENOMEM;
1334 goto err_fb_alloc;
1335 }
1336 info->apertures = alloc_apertures(1);
1337 if (!info->apertures) {
1338 ret = -ENOMEM;
1339 goto err_ioremap;
1340 }
1341
1342
1343 info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0);
1344
1345 if (!info->screen_base) {
1346 printk(KERN_ERR "vga16fb: unable to map device\n");
1347 ret = -ENOMEM;
1348 goto err_ioremap;
1349 }
1350
1351 printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
1352 par = info->par;
1353
1354 #if defined(CONFIG_X86)
1355 par->isVGA = screen_info.orig_video_isVGA == VIDEO_TYPE_VGAC;
1356 #else
1357
1358 par->isVGA = screen_info.orig_video_isVGA;
1359 #endif
1360 par->palette_blanked = 0;
1361 par->vesa_blanked = 0;
1362
1363 i = par->isVGA? 6 : 2;
1364
1365 vga16fb_defined.red.length = i;
1366 vga16fb_defined.green.length = i;
1367 vga16fb_defined.blue.length = i;
1368
1369
1370 info->fbops = &vga16fb_ops;
1371 info->var = vga16fb_defined;
1372 info->fix = vga16fb_fix;
1373
1374 info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
1375 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
1376 FBINFO_HWACCEL_YPAN;
1377
1378 i = (info->var.bits_per_pixel == 8) ? 256 : 16;
1379 ret = fb_alloc_cmap(&info->cmap, i, 0);
1380 if (ret) {
1381 printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
1382 ret = -ENOMEM;
1383 goto err_alloc_cmap;
1384 }
1385
1386 if (vga16fb_check_var(&info->var, info)) {
1387 printk(KERN_ERR "vga16fb: unable to validate variable\n");
1388 ret = -EINVAL;
1389 goto err_check_var;
1390 }
1391
1392 vga16fb_update_fix(info);
1393
1394 info->apertures->ranges[0].base = VGA_FB_PHYS;
1395 info->apertures->ranges[0].size = VGA_FB_PHYS_LEN;
1396
1397 if (register_framebuffer(info) < 0) {
1398 printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
1399 ret = -EINVAL;
1400 goto err_check_var;
1401 }
1402
1403 fb_info(info, "%s frame buffer device\n", info->fix.id);
1404 platform_set_drvdata(dev, info);
1405
1406 return 0;
1407
1408 err_check_var:
1409 fb_dealloc_cmap(&info->cmap);
1410 err_alloc_cmap:
1411 iounmap(info->screen_base);
1412 err_ioremap:
1413 framebuffer_release(info);
1414 err_fb_alloc:
1415 return ret;
1416 }
1417
1418 static int vga16fb_remove(struct platform_device *dev)
1419 {
1420 struct fb_info *info = platform_get_drvdata(dev);
1421
1422 if (info)
1423 unregister_framebuffer(info);
1424
1425 return 0;
1426 }
1427
1428 static struct platform_driver vga16fb_driver = {
1429 .probe = vga16fb_probe,
1430 .remove = vga16fb_remove,
1431 .driver = {
1432 .name = "vga16fb",
1433 },
1434 };
1435
1436 static struct platform_device *vga16fb_device;
1437
1438 static int __init vga16fb_init(void)
1439 {
1440 int ret;
1441 #ifndef MODULE
1442 char *option = NULL;
1443
1444 if (fb_get_options("vga16fb", &option))
1445 return -ENODEV;
1446
1447 vga16fb_setup(option);
1448 #endif
1449
1450 ret = check_mode_supported();
1451 if (ret)
1452 return ret;
1453
1454 ret = platform_driver_register(&vga16fb_driver);
1455
1456 if (!ret) {
1457 vga16fb_device = platform_device_alloc("vga16fb", 0);
1458
1459 if (vga16fb_device)
1460 ret = platform_device_add(vga16fb_device);
1461 else
1462 ret = -ENOMEM;
1463
1464 if (ret) {
1465 platform_device_put(vga16fb_device);
1466 platform_driver_unregister(&vga16fb_driver);
1467 }
1468 }
1469
1470 return ret;
1471 }
1472
1473 static void __exit vga16fb_exit(void)
1474 {
1475 platform_device_unregister(vga16fb_device);
1476 platform_driver_unregister(&vga16fb_driver);
1477 }
1478
1479 MODULE_DESCRIPTION("Legacy VGA framebuffer device driver");
1480 MODULE_LICENSE("GPL");
1481 module_init(vga16fb_init);
1482 module_exit(vga16fb_exit);