]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/video/vga16fb.c
tdfxfb: add mode_option module parameter
[mirror_ubuntu-artful-kernel.git] / drivers / video / vga16fb.c
CommitLineData
1da177e4
LT
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>
7 *
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.
11 */
12
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>
1da177e4
LT
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>
120ddb41 23#include <linux/platform_device.h>
a8f340e3 24#include <linux/screen_info.h>
1da177e4
LT
25
26#include <asm/io.h>
27#include <video/vga.h>
28
29#define GRAPHICS_ADDR_REG VGA_GFX_I /* Graphics address register. */
30#define GRAPHICS_DATA_REG VGA_GFX_D /* Graphics data register. */
31
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. */
37
38#define dac_reg (VGA_PEL_IW)
39#define dac_val (VGA_PEL_D)
40
41#define VGA_FB_PHYS 0xA0000
42#define VGA_FB_PHYS_LEN 65536
43
44#define MODE_SKIP4 1
45#define MODE_8BPP 2
46#define MODE_CFB 4
47#define MODE_TEXT 8
48
49/* --------------------------------------------------------------------- */
50
51/*
52 * card parameters
53 */
54
120ddb41 55struct vga16fb_par {
1da177e4
LT
56 /* structure holding original VGA register settings when the
57 screen is blanked */
58 struct {
120ddb41
AD
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 */
1da177e4
LT
71 } vga_state;
72 struct vgastate state;
c4f28e54
JS
73 struct mutex open_lock;
74 unsigned int ref_count;
1da177e4
LT
75 int palette_blanked, vesa_blanked, mode, isVGA;
76 u8 misc, pel_msk, vss, clkdiv;
77 u8 crtc[VGA_CRT_C];
120ddb41 78};
1da177e4
LT
79
80/* --------------------------------------------------------------------- */
81
120ddb41 82static struct fb_var_screeninfo vga16fb_defined __initdata = {
1da177e4
LT
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,
99};
100
101/* name should not depend on EGA/VGA */
102static 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
113};
114
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.
120
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. */
126static inline void rmw(volatile char __iomem *p)
127{
128 readb(p);
129 writeb(1, p);
130}
131
132/* Set the Graphics Mode Register, and return its previous value.
133 Bits 0-1 are write mode, bit 3 is read mode. */
134static inline int setmode(int mode)
135{
136 int oldmode;
137
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;
142}
143
144/* Select the Bit Mask Register and return its value. */
145static inline int selectmask(void)
146{
147 return vga_io_rgfx(BIT_MASK_INDEX);
148}
149
150/* Set the value of the Bit Mask Register. It must already have been
151 selected with selectmask(). */
152static inline void setmask(int mask)
153{
154 vga_io_w(GRAPHICS_DATA_REG, mask);
155}
156
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). */
160static inline int setop(int op)
161{
162 int oldop;
163
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;
168}
169
170/* Set the Enable Set/Reset Register and return its old value.
171 The code here always uses value 0xf for thsi register. */
172static inline int setsr(int sr)
173{
174 int oldsr;
175
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;
180}
181
182/* Set the Set/Reset Register and return its old value. */
183static inline int setcolor(int color)
184{
185 int oldcolor;
186
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;
191}
192
193/* Return the value in the Graphics Address Register. */
194static inline int getindex(void)
195{
196 return vga_io_r(GRAPHICS_ADDR_REG);
197}
198
199/* Set the value in the Graphics Address Register. */
200static inline void setindex(int index)
201{
202 vga_io_w(GRAPHICS_ADDR_REG, index);
203}
204
205static void vga16fb_pan_var(struct fb_info *info,
206 struct fb_var_screeninfo *var)
207{
120ddb41 208 struct vga16fb_par *par = info->par;
1da177e4
LT
209 u32 xoffset, pos;
210
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;
221 }
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);
234}
235
236static void vga16fb_update_fix(struct fb_info *info)
237{
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;
246 }
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;
259 }
260 }
261}
262
263static void vga16fb_clock_chip(struct vga16fb_par *par,
264 unsigned int pixclock,
265 const struct fb_info *info,
266 int mul, int div)
267{
ec1a7b3d 268 static const struct {
1da177e4
LT
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;
279
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;
286
287 tmp = pixclock - ptr->pixclock;
288 if (tmp < 0) tmp = -tmp;
289 if (tmp < err) {
290 err = tmp;
291 best = ptr;
292 }
293 }
294 par->misc |= best->misc;
295 par->clkdiv = best->seq_clock_mode;
296 pixclock = (best->pixclock * div) / mul;
297}
298
299#define FAIL(X) return -EINVAL
300
301static int vga16fb_open(struct fb_info *info, int user)
302{
120ddb41 303 struct vga16fb_par *par = info->par;
1da177e4 304
c4f28e54
JS
305 mutex_lock(&par->open_lock);
306 if (!par->ref_count) {
1da177e4
LT
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);
311 }
c4f28e54
JS
312 par->ref_count++;
313 mutex_unlock(&par->open_lock);
314
1da177e4
LT
315 return 0;
316}
317
318static int vga16fb_release(struct fb_info *info, int user)
319{
120ddb41 320 struct vga16fb_par *par = info->par;
1da177e4 321
c4f28e54
JS
322 mutex_lock(&par->open_lock);
323 if (!par->ref_count) {
324 mutex_unlock(&par->open_lock);
1da177e4 325 return -EINVAL;
c4f28e54
JS
326 }
327 if (par->ref_count == 1)
1da177e4 328 restore_vga(&par->state);
c4f28e54
JS
329 par->ref_count--;
330 mutex_unlock(&par->open_lock);
1da177e4
LT
331
332 return 0;
333}
334
335static int vga16fb_check_var(struct fb_var_screeninfo *var,
336 struct fb_info *info)
337{
120ddb41 338 struct vga16fb_par *par = info->par;
1da177e4
LT
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;
347
348 par->pel_msk = 0xFF;
349
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;
362 }
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;
373 }
374 } else
375 return -EINVAL;
376
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;
383
384 if (vxres < xres)
385 vxres = xres;
386 if (xres + xoffset > vxres)
387 xoffset = vxres - xres;
388
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;
395
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;
419
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;
426
427 if (yres > vyres)
428 vyres = yres;
429 if (vxres * vyres > maxmem) {
430 vyres = maxmem / vxres;
431 if (vyres < yres)
432 return -ENOMEM;
433 }
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;
442
443 if (var->vmode & FB_VMODE_DOUBLE) {
444 yres <<= 1;
445 lower <<= 1;
446 vslen <<= 1;
447 upper <<= 1;
448 }
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 */
488 }
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;
510
511 par->vss = 0x00; /* 3DA */
512
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;
518
519 par->mode = mode;
520
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);
527
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;
538}
539#undef FAIL
540
541static int vga16fb_set_par(struct fb_info *info)
542{
120ddb41 543 struct vga16fb_par *par = info->par;
1da177e4
LT
544 u8 gdc[VGA_GFX_C];
545 u8 seq[VGA_SEQ_C];
546 u8 atc[VGA_ATT_C];
547 int fh, i;
548
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;
561
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;
576 }
577 gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
578 gdc[VGA_GFX_BIT_MASK] = 0xFF;
579
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;
595
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);
600 }
601
602 vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
603
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);
608 }
609
610 /* update misc output register */
611 vga_io_w(VGA_MIS_W, par->misc);
612
613 /* synchronous reset on */
614 vga_io_wseq(0x00, 0x01);
615
616 if (par->isVGA)
617 vga_io_w(VGA_PEL_MSK, par->pel_msk);
618
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]);
623 }
624
625 /* synchronous reset off */
626 vga_io_wseq(0x00, 0x03);
627
628 /* deprotect CRT registers 0-7 */
629 vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
630
631 /* write CRT registers */
632 for (i = 0; i < VGA_CRTC_REGS; i++) {
633 vga_io_wcrt(i, par->crtc[i]);
634 }
635
636 /* write graphics controller registers */
637 for (i = 0; i < VGA_GFX_C; i++) {
638 vga_io_wgfx(i, gdc[i]);
639 }
640
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]);
645 }
646
647 /* Wait for screen to stabilize. */
648 mdelay(50);
649
650 vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]);
651
652 vga_io_r(VGA_IS1_RC);
653 vga_io_w(VGA_ATT_IW, 0x20);
654
655 vga16fb_update_fix(info);
656 return 0;
657}
658
659static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
660{
ec1a7b3d 661 static const unsigned char map[] = { 000, 001, 010, 011 };
1da177e4
LT
662 int val;
663
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 */
671}
672
673static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
674{
675 outb(regno, dac_reg);
676 outb(red >> 10, dac_val);
677 outb(green >> 10, dac_val);
678 outb(blue >> 10, dac_val);
679}
680
681static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
682 unsigned blue, unsigned transp,
683 struct fb_info *info)
684{
120ddb41 685 struct vga16fb_par *par = info->par;
1da177e4
LT
686 int gray;
687
688 /*
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.
693 */
694
695 if (regno >= 256)
696 return 1;
697
698 gray = info->var.grayscale;
699
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;
703 }
704 if (par->isVGA)
705 vga16_setpalette(regno,red,green,blue);
706 else
707 ega16_setpalette(regno,red,green,blue);
708 return 0;
709}
710
711static int vga16fb_pan_display(struct fb_var_screeninfo *var,
712 struct fb_info *info)
713{
1da177e4 714 vga16fb_pan_var(info, var);
1da177e4
LT
715 return 0;
716}
717
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
731
732static void vga_vesa_blank(struct vga16fb_par *par, int mode)
733{
734 unsigned char SeqCtrlIndex;
735 unsigned char CrtCtrlIndex;
736
737 //cli();
738 SeqCtrlIndex = vga_io_r(seq_port_reg);
739 CrtCtrlIndex = vga_io_r(vga_video_port_reg);
740
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();
745
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 */
755 }
756
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);
761
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);
765
766 /*
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.
770 */
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 */
778 }
779
780 if (mode & FB_BLANK_HSYNC_SUSPEND) {
781 /*
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.
785 */
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) */
790 }
791
792 /* restore both index registers */
793 outb_p(SeqCtrlIndex,seq_port_reg);
794 outb_p(CrtCtrlIndex,vga_video_port_reg);
795 //sti();
796}
797
798static void vga_vesa_unblank(struct vga16fb_par *par)
799{
800 unsigned char SeqCtrlIndex;
801 unsigned char CrtCtrlIndex;
802
803 //cli();
804 SeqCtrlIndex = vga_io_r(seq_port_reg);
805 CrtCtrlIndex = vga_io_r(vga_video_port_reg);
806
807 /* restore original values of VGA controller registers */
808 vga_io_w(video_misc_wr, par->vga_state.CrtMiscIO);
809
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);
828
829 /* restore index/control registers */
830 vga_io_w(seq_port_reg, SeqCtrlIndex);
831 vga_io_w(vga_video_port_reg, CrtCtrlIndex);
832 //sti();
833}
834
835static void vga_pal_blank(void)
836{
837 int i;
838
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) ;
844 }
845}
846
847/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
848static int vga16fb_blank(int blank, struct fb_info *info)
849{
120ddb41 850 struct vga16fb_par *par = info->par;
1da177e4
LT
851
852 switch (blank) {
853 case FB_BLANK_UNBLANK: /* Unblank */
854 if (par->vesa_blanked) {
855 vga_vesa_unblank(par);
856 par->vesa_blanked = 0;
857 }
858 if (par->palette_blanked) {
859 par->palette_blanked = 0;
860 }
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;
870 }
871 return 0;
872}
873
874static void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
875{
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;
883
884 dx /= 4;
885 where = info->screen_base + dx + rect->dy * info->fix.line_length;
886
887 if (rect->rop == ROP_COPY) {
888 oldop = setop(0);
889 oldsr = setsr(0);
890
891 width /= 4;
892 line_ofs = info->fix.line_length - width;
893 setmask(0xff);
894
895 height = rect->height;
896
897 while (height--) {
898 int x;
899
900 /* we can do memset... */
901 for (x = width; x > 0; --x) {
902 writeb(rect->color, where);
903 where++;
904 }
905 where += line_ofs;
906 }
907 } else {
908 char oldcolor = setcolor(0xf);
909 int y;
910
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;
918 }
919 setcolor(oldcolor);
920 }
921 setmask(oldmask);
922 setsr(oldsr);
923 setop(oldop);
924 setmode(oldmode);
925 setindex(oldindex);
926}
927
928static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
929{
930 int x, x2, y2, vxres, vyres, width, height, line_ofs;
931 char __iomem *dst;
932
933 vxres = info->var.xres_virtual;
934 vyres = info->var.yres_virtual;
935
936 if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
937 return;
938
939 /* We could use hardware clipping but on many cards you get around
940 * hardware clipping by writing to framebuffer directly. */
941
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;
947
948 switch (info->fix.type) {
949 case FB_TYPE_VGA_PLANES:
950 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
951
952 height = y2 - rect->dy;
953 width = rect->width/8;
954
955 line_ofs = info->fix.line_length - width;
956 dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length;
957
958 switch (rect->rop) {
959 case ROP_COPY:
960 setmode(0);
961 setop(0);
962 setsr(0xf);
963 setcolor(rect->color);
964 selectmask();
965
966 setmask(0xff);
967
968 while (height--) {
969 for (x = 0; x < width; x++) {
970 writeb(0, dst);
971 dst++;
972 }
973 dst += line_ofs;
974 }
975 break;
976 case ROP_XOR:
977 setmode(0);
978 setop(0x18);
979 setsr(0xf);
980 setcolor(0xf);
981 selectmask();
982
983 setmask(0xff);
984 while (height--) {
985 for (x = 0; x < width; x++) {
986 rmw(dst);
987 dst++;
988 }
989 dst += line_ofs;
990 }
991 break;
992 }
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;
1000 }
1001}
1002
1003static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1004{
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;
1013
1014 height = area->height;
1015
1016 sx = area->sx / 4;
1017 dx = area->dx / 4;
1018 width = area->width / 4;
1019
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++;
1030 }
1031 src += line_ofs;
1032 dest += line_ofs;
1033 }
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);
1046 }
1047 src -= line_ofs;
1048 dest -= line_ofs;
1049 }
1050 }
1051
1052 setsr(oldsr);
1053 setop(oldop);
1054 setmode(oldmode);
1055 setindex(oldindex);
1056}
1057
1058static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1059{
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;
1065
1066 vxres = info->var.xres_virtual;
1067 vyres = info->var.yres_virtual;
1068
1069 if (area->dx > vxres || area->sx > vxres || area->dy > vyres ||
1070 area->sy > vyres)
1071 return;
1072
1073 /* clip the destination */
1074 old_dx = area->dx;
1075 old_dy = area->dy;
1076
1077 /*
1078 * We could use hardware clipping but on many cards you get around
1079 * hardware clipping by writing to framebuffer directly.
1080 */
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;
1089
77a6e7ab
RK
1090 if (sx + dx < old_dx || sy + dy < old_dy)
1091 return;
1092
1da177e4
LT
1093 /* update sx1,sy1 */
1094 sx += (dx - old_dx);
1095 sy += (dy - old_dy);
1096
1097 /* the source must be completely inside the virtual screen */
77a6e7ab 1098 if (sx + width > vxres || sy + height > vyres)
1da177e4
LT
1099 return;
1100
1101 switch (info->fix.type) {
1102 case FB_TYPE_VGA_PLANES:
1103 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1104 width = width/8;
1105 height = height;
1106 line_ofs = info->fix.line_length - width;
1107
1108 setmode(1);
1109 setop(0);
1110 setsr(0xf);
1111
1112 if (dy < sy || (dy == sy && dx < sx)) {
1113 dst = info->screen_base + (dx/8) + dy * info->fix.line_length;
1114 src = info->screen_base + (sx/8) + sy * info->fix.line_length;
1115 while (height--) {
1116 for (x = 0; x < width; x++) {
1117 readb(src);
1118 writeb(0, dst);
1119 dst++;
1120 src++;
1121 }
1122 src += line_ofs;
1123 dst += line_ofs;
1124 }
1125 } else {
1126 dst = info->screen_base + (dx/8) + width +
1127 (dy + height - 1) * info->fix.line_length;
1128 src = info->screen_base + (sx/8) + width +
1129 (sy + height - 1) * info->fix.line_length;
1130 while (height--) {
1131 for (x = 0; x < width; x++) {
1132 dst--;
1133 src--;
1134 readb(src);
1135 writeb(0, dst);
1136 }
1137 src -= line_ofs;
1138 dst -= line_ofs;
1139 }
1140 }
1141 } else
1142 vga_8planes_copyarea(info, area);
1143 break;
1144 case FB_TYPE_PACKED_PIXELS:
1145 default:
1146 cfb_copyarea(info, area);
1147 break;
1148 }
1149}
1150
ec1a7b3d
HD
1151#define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
1152#define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
1153 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
1154
1155#if defined(__LITTLE_ENDIAN)
1156static const u16 transl_l[] = TRANS_MASK_LOW;
1157static const u16 transl_h[] = TRANS_MASK_HIGH;
1158#elif defined(__BIG_ENDIAN)
1159static const u16 transl_l[] = TRANS_MASK_HIGH;
1160static const u16 transl_h[] = TRANS_MASK_LOW;
1da177e4
LT
1161#else
1162#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1163#endif
1da177e4
LT
1164
1165static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
1166{
1167 char oldindex = getindex();
1168 char oldmode = setmode(0x40);
1169 char oldop = setop(0);
1170 char oldsr = setsr(0);
1171 char oldmask = selectmask();
1172 const char *cdat = image->data;
1173 u32 dx = image->dx;
1174 char __iomem *where;
1175 int y;
1176
1177 dx /= 4;
1178 where = info->screen_base + dx + image->dy * info->fix.line_length;
1179
1180 setmask(0xff);
1181 writeb(image->bg_color, where);
1182 readb(where);
1183 selectmask();
1184 setmask(image->fg_color ^ image->bg_color);
1185 setmode(0x42);
1186 setop(0x18);
1187 for (y = 0; y < image->height; y++, where += info->fix.line_length)
1188 writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where);
1189 setmask(oldmask);
1190 setsr(oldsr);
1191 setop(oldop);
1192 setmode(oldmode);
1193 setindex(oldindex);
1194}
1195
1196static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
1197{
1198 char __iomem *where = info->screen_base + (image->dx/8) +
1199 image->dy * info->fix.line_length;
120ddb41 1200 struct vga16fb_par *par = info->par;
1da177e4
LT
1201 char *cdat = (char *) image->data;
1202 char __iomem *dst;
1203 int x, y;
1204
1205 switch (info->fix.type) {
1206 case FB_TYPE_VGA_PLANES:
1207 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1208 if (par->isVGA) {
1209 setmode(2);
1210 setop(0);
1211 setsr(0xf);
1212 setcolor(image->fg_color);
1213 selectmask();
1214
1215 setmask(0xff);
1216 writeb(image->bg_color, where);
1217 rmb();
1218 readb(where); /* fill latches */
1219 setmode(3);
1220 wmb();
1221 for (y = 0; y < image->height; y++) {
1222 dst = where;
1223 for (x = image->width/8; x--;)
1224 writeb(*cdat++, dst++);
1225 where += info->fix.line_length;
1226 }
1227 wmb();
1228 } else {
1229 setmode(0);
1230 setop(0);
1231 setsr(0xf);
1232 setcolor(image->bg_color);
1233 selectmask();
1234
1235 setmask(0xff);
1236 for (y = 0; y < image->height; y++) {
1237 dst = where;
1238 for (x=image->width/8; x--;){
1239 rmw(dst);
1240 setcolor(image->fg_color);
1241 selectmask();
1242 if (*cdat) {
1243 setmask(*cdat++);
1244 rmw(dst++);
1245 }
1246 }
1247 where += info->fix.line_length;
1248 }
1249 }
1250 } else
1251 vga_8planes_imageblit(info, image);
1252 break;
1253 case FB_TYPE_PACKED_PIXELS:
1254 default:
1255 cfb_imageblit(info, image);
1256 break;
1257 }
1258}
1259
1260static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
1261{
1262 /*
1263 * Draw logo
1264 */
120ddb41 1265 struct vga16fb_par *par = info->par;
1da177e4
LT
1266 char __iomem *where =
1267 info->screen_base + image->dy * info->fix.line_length +
1268 image->dx/8;
1269 const char *cdat = image->data;
1270 char __iomem *dst;
1271 int x, y;
1272
1273 switch (info->fix.type) {
1274 case FB_TYPE_VGA_PLANES:
1275 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
1276 par->isVGA) {
1277 setsr(0xf);
1278 setop(0);
1279 setmode(0);
1280
1281 for (y = 0; y < image->height; y++) {
1282 for (x = 0; x < image->width; x++) {
1283 dst = where + x/8;
1284
1285 setcolor(*cdat);
1286 selectmask();
1287 setmask(1 << (7 - (x % 8)));
1288 fb_readb(dst);
1289 fb_writeb(0, dst);
1290
1291 cdat++;
1292 }
1293 where += info->fix.line_length;
1294 }
1295 }
1296 break;
1297 case FB_TYPE_PACKED_PIXELS:
1298 cfb_imageblit(info, image);
1299 break;
1300 default:
1301 break;
1302 }
1303}
1304
1305static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
1306{
1307 if (image->depth == 1)
1308 vga_imageblit_expand(info, image);
1309 else
1310 vga_imageblit_color(info, image);
1311}
1312
1313static struct fb_ops vga16fb_ops = {
1314 .owner = THIS_MODULE,
1315 .fb_open = vga16fb_open,
1316 .fb_release = vga16fb_release,
1317 .fb_check_var = vga16fb_check_var,
1318 .fb_set_par = vga16fb_set_par,
1319 .fb_setcolreg = vga16fb_setcolreg,
1320 .fb_pan_display = vga16fb_pan_display,
1321 .fb_blank = vga16fb_blank,
1322 .fb_fillrect = vga16fb_fillrect,
1323 .fb_copyarea = vga16fb_copyarea,
1324 .fb_imageblit = vga16fb_imageblit,
1da177e4
LT
1325};
1326
1327#ifndef MODULE
1328static int vga16fb_setup(char *options)
1329{
1330 char *this_opt;
1331
1332 if (!options || !*options)
1333 return 0;
1334
1335 while ((this_opt = strsep(&options, ",")) != NULL) {
1336 if (!*this_opt) continue;
1337 }
1338 return 0;
1339}
1340#endif
1341
ae6d3218 1342static int __init vga16fb_probe(struct platform_device *dev)
1da177e4 1343{
120ddb41
AD
1344 struct fb_info *info;
1345 struct vga16fb_par *par;
1da177e4 1346 int i;
120ddb41 1347 int ret = 0;
1da177e4 1348
1da177e4 1349 printk(KERN_DEBUG "vga16fb: initializing\n");
120ddb41
AD
1350 info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
1351
1352 if (!info) {
1353 ret = -ENOMEM;
1354 goto err_fb_alloc;
1355 }
1da177e4
LT
1356
1357 /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
4f1bcaf0 1358 info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0);
1da177e4 1359
120ddb41 1360 if (!info->screen_base) {
1da177e4
LT
1361 printk(KERN_ERR "vga16fb: unable to map device\n");
1362 ret = -ENOMEM;
1363 goto err_ioremap;
1364 }
1da177e4 1365
120ddb41
AD
1366 printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
1367 par = info->par;
1da177e4 1368
c4f28e54 1369 mutex_init(&par->open_lock);
3ea33510 1370 par->isVGA = screen_info.orig_video_isVGA;
120ddb41
AD
1371 par->palette_blanked = 0;
1372 par->vesa_blanked = 0;
1373
1374 i = par->isVGA? 6 : 2;
1da177e4
LT
1375
1376 vga16fb_defined.red.length = i;
1377 vga16fb_defined.green.length = i;
1378 vga16fb_defined.blue.length = i;
1379
1380 /* name should not depend on EGA/VGA */
120ddb41
AD
1381 info->fbops = &vga16fb_ops;
1382 info->var = vga16fb_defined;
1383 info->fix = vga16fb_fix;
7e645ffd
AD
1384 /* supports rectangles with widths of multiples of 8 */
1385 info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
120ddb41 1386 info->flags = FBINFO_FLAG_DEFAULT |
1da177e4
LT
1387 FBINFO_HWACCEL_YPAN;
1388
120ddb41
AD
1389 i = (info->var.bits_per_pixel == 8) ? 256 : 16;
1390 ret = fb_alloc_cmap(&info->cmap, i, 0);
1da177e4
LT
1391 if (ret) {
1392 printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
1393 ret = -ENOMEM;
1394 goto err_alloc_cmap;
1395 }
1396
120ddb41 1397 if (vga16fb_check_var(&info->var, info)) {
1da177e4
LT
1398 printk(KERN_ERR "vga16fb: unable to validate variable\n");
1399 ret = -EINVAL;
1400 goto err_check_var;
1401 }
1402
120ddb41 1403 vga16fb_update_fix(info);
1da177e4 1404
120ddb41 1405 if (register_framebuffer(info) < 0) {
1da177e4
LT
1406 printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
1407 ret = -EINVAL;
1408 goto err_check_var;
1409 }
1410
1411 printk(KERN_INFO "fb%d: %s frame buffer device\n",
120ddb41 1412 info->node, info->fix.id);
ae6d3218 1413 platform_set_drvdata(dev, info);
1da177e4
LT
1414
1415 return 0;
1416
1417 err_check_var:
120ddb41 1418 fb_dealloc_cmap(&info->cmap);
1da177e4 1419 err_alloc_cmap:
120ddb41 1420 iounmap(info->screen_base);
1da177e4 1421 err_ioremap:
120ddb41
AD
1422 framebuffer_release(info);
1423 err_fb_alloc:
1424 return ret;
1425}
1426
ae6d3218 1427static int vga16fb_remove(struct platform_device *dev)
120ddb41 1428{
ae6d3218 1429 struct fb_info *info = platform_get_drvdata(dev);
120ddb41
AD
1430
1431 if (info) {
1432 unregister_framebuffer(info);
1433 iounmap(info->screen_base);
1434 fb_dealloc_cmap(&info->cmap);
1435 /* XXX unshare VGA regions */
1436 framebuffer_release(info);
1437 }
1438
1439 return 0;
1440}
1441
ae6d3218 1442static struct platform_driver vga16fb_driver = {
120ddb41
AD
1443 .probe = vga16fb_probe,
1444 .remove = vga16fb_remove,
ae6d3218
AD
1445 .driver = {
1446 .name = "vga16fb",
1447 },
120ddb41
AD
1448};
1449
ae6d3218 1450static struct platform_device *vga16fb_device;
120ddb41
AD
1451
1452static int __init vga16fb_init(void)
1453{
1454 int ret;
1455#ifndef MODULE
1456 char *option = NULL;
1457
1458 if (fb_get_options("vga16fb", &option))
1459 return -ENODEV;
1460
1461 vga16fb_setup(option);
1462#endif
ae6d3218 1463 ret = platform_driver_register(&vga16fb_driver);
120ddb41
AD
1464
1465 if (!ret) {
ae6d3218
AD
1466 vga16fb_device = platform_device_alloc("vga16fb", 0);
1467
1468 if (vga16fb_device)
1469 ret = platform_device_add(vga16fb_device);
1470 else
1471 ret = -ENOMEM;
1472
1473 if (ret) {
1474 platform_device_put(vga16fb_device);
1475 platform_driver_unregister(&vga16fb_driver);
1476 }
120ddb41
AD
1477 }
1478
1da177e4
LT
1479 return ret;
1480}
1481
1482static void __exit vga16fb_exit(void)
1483{
ae6d3218
AD
1484 platform_device_unregister(vga16fb_device);
1485 platform_driver_unregister(&vga16fb_driver);
1da177e4
LT
1486}
1487
1488MODULE_LICENSE("GPL");
1489module_init(vga16fb_init);
1490module_exit(vga16fb_exit);
1491
1492
1493/*
1494 * Overrides for Emacs so that we follow Linus's tabbing style.
1495 * ---------------------------------------------------------------------------
1496 * Local variables:
1497 * c-basic-offset: 8
1498 * End:
1499 */
1500