Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[deliverable/linux.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
1da177e4
LT
29#define VGA_FB_PHYS 0xA0000
30#define VGA_FB_PHYS_LEN 65536
31
32#define MODE_SKIP4 1
33#define MODE_8BPP 2
34#define MODE_CFB 4
35#define MODE_TEXT 8
36
37/* --------------------------------------------------------------------- */
38
39/*
40 * card parameters
41 */
42
120ddb41 43struct vga16fb_par {
1da177e4
LT
44 /* structure holding original VGA register settings when the
45 screen is blanked */
46 struct {
120ddb41
AD
47 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
48 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
49 unsigned char CrtMiscIO; /* Miscellaneous register */
50 unsigned char HorizontalTotal; /* CRT-Controller:00h */
51 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
52 unsigned char StartHorizRetrace;/* CRT-Controller:04h */
53 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
54 unsigned char Overflow; /* CRT-Controller:07h */
55 unsigned char StartVertRetrace; /* CRT-Controller:10h */
56 unsigned char EndVertRetrace; /* CRT-Controller:11h */
57 unsigned char ModeControl; /* CRT-Controller:17h */
58 unsigned char ClockingMode; /* Seq-Controller:01h */
1da177e4
LT
59 } vga_state;
60 struct vgastate state;
c4f28e54
JS
61 struct mutex open_lock;
62 unsigned int ref_count;
1da177e4
LT
63 int palette_blanked, vesa_blanked, mode, isVGA;
64 u8 misc, pel_msk, vss, clkdiv;
65 u8 crtc[VGA_CRT_C];
120ddb41 66};
1da177e4
LT
67
68/* --------------------------------------------------------------------- */
69
120ddb41 70static struct fb_var_screeninfo vga16fb_defined __initdata = {
1da177e4
LT
71 .xres = 640,
72 .yres = 480,
73 .xres_virtual = 640,
74 .yres_virtual = 480,
75 .bits_per_pixel = 4,
76 .activate = FB_ACTIVATE_TEST,
77 .height = -1,
78 .width = -1,
79 .pixclock = 39721,
80 .left_margin = 48,
81 .right_margin = 16,
82 .upper_margin = 33,
83 .lower_margin = 10,
84 .hsync_len = 96,
85 .vsync_len = 2,
86 .vmode = FB_VMODE_NONINTERLACED,
87};
88
89/* name should not depend on EGA/VGA */
90static struct fb_fix_screeninfo vga16fb_fix __initdata = {
91 .id = "VGA16 VGA",
92 .smem_start = VGA_FB_PHYS,
93 .smem_len = VGA_FB_PHYS_LEN,
94 .type = FB_TYPE_VGA_PLANES,
95 .type_aux = FB_AUX_VGA_PLANES_VGA4,
96 .visual = FB_VISUAL_PSEUDOCOLOR,
97 .xpanstep = 8,
98 .ypanstep = 1,
98219374 99 .line_length = 640 / 8,
1da177e4
LT
100 .accel = FB_ACCEL_NONE
101};
102
103/* The VGA's weird architecture often requires that we read a byte and
104 write a byte to the same location. It doesn't matter *what* byte
105 we write, however. This is because all the action goes on behind
106 the scenes in the VGA's 32-bit latch register, and reading and writing
107 video memory just invokes latch behavior.
108
109 To avoid race conditions (is this necessary?), reading and writing
110 the memory byte should be done with a single instruction. One
111 suitable instruction is the x86 bitwise OR. The following
112 read-modify-write routine should optimize to one such bitwise
113 OR. */
114static inline void rmw(volatile char __iomem *p)
115{
116 readb(p);
117 writeb(1, p);
118}
119
120/* Set the Graphics Mode Register, and return its previous value.
121 Bits 0-1 are write mode, bit 3 is read mode. */
122static inline int setmode(int mode)
123{
124 int oldmode;
125
98219374
KH
126 oldmode = vga_io_rgfx(VGA_GFX_MODE);
127 vga_io_w(VGA_GFX_D, mode);
1da177e4
LT
128 return oldmode;
129}
130
131/* Select the Bit Mask Register and return its value. */
132static inline int selectmask(void)
133{
98219374 134 return vga_io_rgfx(VGA_GFX_BIT_MASK);
1da177e4
LT
135}
136
137/* Set the value of the Bit Mask Register. It must already have been
138 selected with selectmask(). */
139static inline void setmask(int mask)
140{
98219374 141 vga_io_w(VGA_GFX_D, mask);
1da177e4
LT
142}
143
144/* Set the Data Rotate Register and return its old value.
145 Bits 0-2 are rotate count, bits 3-4 are logical operation
146 (0=NOP, 1=AND, 2=OR, 3=XOR). */
147static inline int setop(int op)
148{
149 int oldop;
150
98219374
KH
151 oldop = vga_io_rgfx(VGA_GFX_DATA_ROTATE);
152 vga_io_w(VGA_GFX_D, op);
1da177e4
LT
153 return oldop;
154}
155
156/* Set the Enable Set/Reset Register and return its old value.
157 The code here always uses value 0xf for thsi register. */
158static inline int setsr(int sr)
159{
160 int oldsr;
161
98219374
KH
162 oldsr = vga_io_rgfx(VGA_GFX_SR_ENABLE);
163 vga_io_w(VGA_GFX_D, sr);
1da177e4
LT
164 return oldsr;
165}
166
167/* Set the Set/Reset Register and return its old value. */
168static inline int setcolor(int color)
169{
170 int oldcolor;
171
98219374
KH
172 oldcolor = vga_io_rgfx(VGA_GFX_SR_VALUE);
173 vga_io_w(VGA_GFX_D, color);
1da177e4
LT
174 return oldcolor;
175}
176
177/* Return the value in the Graphics Address Register. */
178static inline int getindex(void)
179{
98219374 180 return vga_io_r(VGA_GFX_I);
1da177e4
LT
181}
182
183/* Set the value in the Graphics Address Register. */
184static inline void setindex(int index)
185{
98219374 186 vga_io_w(VGA_GFX_I, index);
1da177e4
LT
187}
188
189static void vga16fb_pan_var(struct fb_info *info,
190 struct fb_var_screeninfo *var)
191{
120ddb41 192 struct vga16fb_par *par = info->par;
1da177e4
LT
193 u32 xoffset, pos;
194
195 xoffset = var->xoffset;
196 if (info->var.bits_per_pixel == 8) {
197 pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2;
198 } else if (par->mode & MODE_TEXT) {
199 int fh = 16; // FIXME !!! font height. Fugde for now.
200 pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3;
201 } else {
202 if (info->var.nonstd)
203 xoffset--;
204 pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3;
205 }
206 vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8);
207 vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF);
208 /* if we support CFB4, then we must! support xoffset with pixel
209 * granularity if someone supports xoffset in bit resolution */
210 vga_io_r(VGA_IS1_RC); /* reset flip-flop */
211 vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);
212 if (var->bits_per_pixel == 8)
213 vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);
214 else
215 vga_io_w(VGA_ATT_IW, xoffset & 7);
216 vga_io_r(VGA_IS1_RC);
217 vga_io_w(VGA_ATT_IW, 0x20);
218}
219
220static void vga16fb_update_fix(struct fb_info *info)
221{
222 if (info->var.bits_per_pixel == 4) {
223 if (info->var.nonstd) {
224 info->fix.type = FB_TYPE_PACKED_PIXELS;
225 info->fix.line_length = info->var.xres_virtual / 2;
226 } else {
227 info->fix.type = FB_TYPE_VGA_PLANES;
228 info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4;
229 info->fix.line_length = info->var.xres_virtual / 8;
230 }
231 } else if (info->var.bits_per_pixel == 0) {
232 info->fix.type = FB_TYPE_TEXT;
233 info->fix.type_aux = FB_AUX_TEXT_CGA;
234 info->fix.line_length = info->var.xres_virtual / 4;
235 } else { /* 8bpp */
236 if (info->var.nonstd) {
237 info->fix.type = FB_TYPE_VGA_PLANES;
238 info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8;
239 info->fix.line_length = info->var.xres_virtual / 4;
240 } else {
241 info->fix.type = FB_TYPE_PACKED_PIXELS;
242 info->fix.line_length = info->var.xres_virtual;
243 }
244 }
245}
246
247static void vga16fb_clock_chip(struct vga16fb_par *par,
248 unsigned int pixclock,
249 const struct fb_info *info,
250 int mul, int div)
251{
ec1a7b3d 252 static const struct {
1da177e4
LT
253 u32 pixclock;
254 u8 misc;
255 u8 seq_clock_mode;
256 } *ptr, *best, vgaclocks[] = {
257 { 79442 /* 12.587 */, 0x00, 0x08},
258 { 70616 /* 14.161 */, 0x04, 0x08},
259 { 39721 /* 25.175 */, 0x00, 0x00},
260 { 35308 /* 28.322 */, 0x04, 0x00},
261 { 0 /* bad */, 0x00, 0x00}};
262 int err;
263
264 pixclock = (pixclock * mul) / div;
265 best = vgaclocks;
266 err = pixclock - best->pixclock;
267 if (err < 0) err = -err;
268 for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {
269 int tmp;
270
271 tmp = pixclock - ptr->pixclock;
272 if (tmp < 0) tmp = -tmp;
273 if (tmp < err) {
274 err = tmp;
275 best = ptr;
276 }
277 }
278 par->misc |= best->misc;
279 par->clkdiv = best->seq_clock_mode;
280 pixclock = (best->pixclock * div) / mul;
281}
282
283#define FAIL(X) return -EINVAL
284
285static int vga16fb_open(struct fb_info *info, int user)
286{
120ddb41 287 struct vga16fb_par *par = info->par;
1da177e4 288
c4f28e54
JS
289 mutex_lock(&par->open_lock);
290 if (!par->ref_count) {
1da177e4
LT
291 memset(&par->state, 0, sizeof(struct vgastate));
292 par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
293 VGA_SAVE_CMAP;
294 save_vga(&par->state);
295 }
c4f28e54
JS
296 par->ref_count++;
297 mutex_unlock(&par->open_lock);
298
1da177e4
LT
299 return 0;
300}
301
302static int vga16fb_release(struct fb_info *info, int user)
303{
120ddb41 304 struct vga16fb_par *par = info->par;
1da177e4 305
c4f28e54
JS
306 mutex_lock(&par->open_lock);
307 if (!par->ref_count) {
308 mutex_unlock(&par->open_lock);
1da177e4 309 return -EINVAL;
c4f28e54
JS
310 }
311 if (par->ref_count == 1)
1da177e4 312 restore_vga(&par->state);
c4f28e54
JS
313 par->ref_count--;
314 mutex_unlock(&par->open_lock);
1da177e4
LT
315
316 return 0;
317}
318
319static int vga16fb_check_var(struct fb_var_screeninfo *var,
320 struct fb_info *info)
321{
120ddb41 322 struct vga16fb_par *par = info->par;
1da177e4
LT
323 u32 xres, right, hslen, left, xtotal;
324 u32 yres, lower, vslen, upper, ytotal;
325 u32 vxres, xoffset, vyres, yoffset;
326 u32 pos;
327 u8 r7, rMode;
328 int shift;
329 int mode;
330 u32 maxmem;
331
332 par->pel_msk = 0xFF;
333
334 if (var->bits_per_pixel == 4) {
335 if (var->nonstd) {
336 if (!par->isVGA)
337 return -EINVAL;
338 shift = 3;
339 mode = MODE_SKIP4 | MODE_CFB;
340 maxmem = 16384;
341 par->pel_msk = 0x0F;
342 } else {
343 shift = 3;
344 mode = 0;
345 maxmem = 65536;
346 }
347 } else if (var->bits_per_pixel == 8) {
348 if (!par->isVGA)
349 return -EINVAL; /* no support on EGA */
350 shift = 2;
351 if (var->nonstd) {
352 mode = MODE_8BPP | MODE_CFB;
353 maxmem = 65536;
354 } else {
355 mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;
356 maxmem = 16384;
357 }
358 } else
359 return -EINVAL;
360
361 xres = (var->xres + 7) & ~7;
362 vxres = (var->xres_virtual + 0xF) & ~0xF;
363 xoffset = (var->xoffset + 7) & ~7;
364 left = (var->left_margin + 7) & ~7;
365 right = (var->right_margin + 7) & ~7;
366 hslen = (var->hsync_len + 7) & ~7;
367
368 if (vxres < xres)
369 vxres = xres;
370 if (xres + xoffset > vxres)
371 xoffset = vxres - xres;
372
373 var->xres = xres;
374 var->right_margin = right;
375 var->hsync_len = hslen;
376 var->left_margin = left;
377 var->xres_virtual = vxres;
378 var->xoffset = xoffset;
379
380 xres >>= shift;
381 right >>= shift;
382 hslen >>= shift;
383 left >>= shift;
384 vxres >>= shift;
385 xtotal = xres + right + hslen + left;
386 if (xtotal >= 256)
387 FAIL("xtotal too big");
388 if (hslen > 32)
389 FAIL("hslen too big");
390 if (right + hslen + left > 64)
391 FAIL("hblank too big");
392 par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;
393 par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;
394 par->crtc[VGA_CRTC_H_DISP] = xres - 1;
395 pos = xres + right;
396 par->crtc[VGA_CRTC_H_SYNC_START] = pos;
397 pos += hslen;
398 par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;
399 pos += left - 2; /* blank_end + 2 <= total + 5 */
400 par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;
401 if (pos & 0x20)
402 par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;
403
404 yres = var->yres;
405 lower = var->lower_margin;
406 vslen = var->vsync_len;
407 upper = var->upper_margin;
408 vyres = var->yres_virtual;
409 yoffset = var->yoffset;
410
411 if (yres > vyres)
412 vyres = yres;
413 if (vxres * vyres > maxmem) {
414 vyres = maxmem / vxres;
415 if (vyres < yres)
416 return -ENOMEM;
417 }
418 if (yoffset + yres > vyres)
419 yoffset = vyres - yres;
420 var->yres = yres;
421 var->lower_margin = lower;
422 var->vsync_len = vslen;
423 var->upper_margin = upper;
424 var->yres_virtual = vyres;
425 var->yoffset = yoffset;
426
427 if (var->vmode & FB_VMODE_DOUBLE) {
428 yres <<= 1;
429 lower <<= 1;
430 vslen <<= 1;
431 upper <<= 1;
432 }
433 ytotal = yres + lower + vslen + upper;
434 if (ytotal > 1024) {
435 ytotal >>= 1;
436 yres >>= 1;
437 lower >>= 1;
438 vslen >>= 1;
439 upper >>= 1;
440 rMode = 0x04;
441 } else
442 rMode = 0x00;
443 if (ytotal > 1024)
444 FAIL("ytotal too big");
445 if (vslen > 16)
446 FAIL("vslen too big");
447 par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;
448 r7 = 0x10; /* disable linecompare */
449 if (ytotal & 0x100) r7 |= 0x01;
450 if (ytotal & 0x200) r7 |= 0x20;
451 par->crtc[VGA_CRTC_PRESET_ROW] = 0;
452 par->crtc[VGA_CRTC_MAX_SCAN] = 0x40; /* 1 scanline, no linecmp */
453 if (var->vmode & FB_VMODE_DOUBLE)
454 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;
455 par->crtc[VGA_CRTC_CURSOR_START] = 0x20;
456 par->crtc[VGA_CRTC_CURSOR_END] = 0x00;
457 if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB)
458 xoffset--;
459 pos = yoffset * vxres + (xoffset >> shift);
460 par->crtc[VGA_CRTC_START_HI] = pos >> 8;
461 par->crtc[VGA_CRTC_START_LO] = pos & 0xFF;
462 par->crtc[VGA_CRTC_CURSOR_HI] = 0x00;
463 par->crtc[VGA_CRTC_CURSOR_LO] = 0x00;
464 pos = yres - 1;
465 par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;
466 par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;
467 if (pos & 0x100)
468 r7 |= 0x0A; /* 0x02 -> DISP_END, 0x08 -> BLANK_START */
469 if (pos & 0x200) {
470 r7 |= 0x40; /* 0x40 -> DISP_END */
471 par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */
472 }
473 pos += lower;
474 par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;
475 if (pos & 0x100)
476 r7 |= 0x04;
477 if (pos & 0x200)
478 r7 |= 0x80;
479 pos += vslen;
480 par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */
481 pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */
482 par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,
483 but some SVGA chips requires all 8 bits to set */
484 if (vxres >= 512)
485 FAIL("vxres too long");
486 par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;
487 if (mode & MODE_SKIP4)
488 par->crtc[VGA_CRTC_UNDERLINE] = 0x5F; /* 256, cfb8 */
489 else
490 par->crtc[VGA_CRTC_UNDERLINE] = 0x1F; /* 16, vgap */
491 par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3);
492 par->crtc[VGA_CRTC_LINE_COMPARE] = 0xFF;
493 par->crtc[VGA_CRTC_OVERFLOW] = r7;
494
495 par->vss = 0x00; /* 3DA */
496
497 par->misc = 0xE3; /* enable CPU, ports 0x3Dx, positive sync */
498 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
499 par->misc &= ~0x40;
500 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
501 par->misc &= ~0x80;
502
503 par->mode = mode;
504
505 if (mode & MODE_8BPP)
506 /* pixel clock == vga clock / 2 */
507 vga16fb_clock_chip(par, var->pixclock, info, 1, 2);
508 else
509 /* pixel clock == vga clock */
510 vga16fb_clock_chip(par, var->pixclock, info, 1, 1);
511
512 var->red.offset = var->green.offset = var->blue.offset =
513 var->transp.offset = 0;
514 var->red.length = var->green.length = var->blue.length =
515 (par->isVGA) ? 6 : 2;
516 var->transp.length = 0;
517 var->activate = FB_ACTIVATE_NOW;
518 var->height = -1;
519 var->width = -1;
520 var->accel_flags = 0;
521 return 0;
522}
523#undef FAIL
524
525static int vga16fb_set_par(struct fb_info *info)
526{
120ddb41 527 struct vga16fb_par *par = info->par;
1da177e4
LT
528 u8 gdc[VGA_GFX_C];
529 u8 seq[VGA_SEQ_C];
530 u8 atc[VGA_ATT_C];
531 int fh, i;
532
533 seq[VGA_SEQ_CLOCK_MODE] = 0x01 | par->clkdiv;
534 if (par->mode & MODE_TEXT)
535 seq[VGA_SEQ_PLANE_WRITE] = 0x03;
536 else
537 seq[VGA_SEQ_PLANE_WRITE] = 0x0F;
538 seq[VGA_SEQ_CHARACTER_MAP] = 0x00;
539 if (par->mode & MODE_TEXT)
540 seq[VGA_SEQ_MEMORY_MODE] = 0x03;
541 else if (par->mode & MODE_SKIP4)
542 seq[VGA_SEQ_MEMORY_MODE] = 0x0E;
543 else
544 seq[VGA_SEQ_MEMORY_MODE] = 0x06;
545
546 gdc[VGA_GFX_SR_VALUE] = 0x00;
547 gdc[VGA_GFX_SR_ENABLE] = 0x00;
548 gdc[VGA_GFX_COMPARE_VALUE] = 0x00;
549 gdc[VGA_GFX_DATA_ROTATE] = 0x00;
550 gdc[VGA_GFX_PLANE_READ] = 0;
551 if (par->mode & MODE_TEXT) {
552 gdc[VGA_GFX_MODE] = 0x10;
553 gdc[VGA_GFX_MISC] = 0x06;
554 } else {
555 if (par->mode & MODE_CFB)
556 gdc[VGA_GFX_MODE] = 0x40;
557 else
558 gdc[VGA_GFX_MODE] = 0x00;
559 gdc[VGA_GFX_MISC] = 0x05;
560 }
561 gdc[VGA_GFX_COMPARE_MASK] = 0x0F;
562 gdc[VGA_GFX_BIT_MASK] = 0xFF;
563
564 for (i = 0x00; i < 0x10; i++)
565 atc[i] = i;
566 if (par->mode & MODE_TEXT)
567 atc[VGA_ATC_MODE] = 0x04;
568 else if (par->mode & MODE_8BPP)
569 atc[VGA_ATC_MODE] = 0x41;
570 else
571 atc[VGA_ATC_MODE] = 0x81;
572 atc[VGA_ATC_OVERSCAN] = 0x00; /* 0 for EGA, 0xFF for VGA */
573 atc[VGA_ATC_PLANE_ENABLE] = 0x0F;
574 if (par->mode & MODE_8BPP)
575 atc[VGA_ATC_PEL] = (info->var.xoffset & 3) << 1;
576 else
577 atc[VGA_ATC_PEL] = info->var.xoffset & 7;
578 atc[VGA_ATC_COLOR_PAGE] = 0x00;
579
580 if (par->mode & MODE_TEXT) {
581 fh = 16; // FIXME !!! Fudge font height.
582 par->crtc[VGA_CRTC_MAX_SCAN] = (par->crtc[VGA_CRTC_MAX_SCAN]
583 & ~0x1F) | (fh - 1);
584 }
585
586 vga_io_w(VGA_MIS_W, vga_io_r(VGA_MIS_R) | 0x01);
587
588 /* Enable graphics register modification */
589 if (!par->isVGA) {
590 vga_io_w(EGA_GFX_E0, 0x00);
591 vga_io_w(EGA_GFX_E1, 0x01);
592 }
593
594 /* update misc output register */
595 vga_io_w(VGA_MIS_W, par->misc);
596
597 /* synchronous reset on */
598 vga_io_wseq(0x00, 0x01);
599
600 if (par->isVGA)
601 vga_io_w(VGA_PEL_MSK, par->pel_msk);
602
603 /* write sequencer registers */
604 vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE] | 0x20);
605 for (i = 2; i < VGA_SEQ_C; i++) {
606 vga_io_wseq(i, seq[i]);
607 }
608
609 /* synchronous reset off */
610 vga_io_wseq(0x00, 0x03);
611
612 /* deprotect CRT registers 0-7 */
613 vga_io_wcrt(VGA_CRTC_V_SYNC_END, par->crtc[VGA_CRTC_V_SYNC_END]);
614
615 /* write CRT registers */
616 for (i = 0; i < VGA_CRTC_REGS; i++) {
617 vga_io_wcrt(i, par->crtc[i]);
618 }
619
620 /* write graphics controller registers */
621 for (i = 0; i < VGA_GFX_C; i++) {
622 vga_io_wgfx(i, gdc[i]);
623 }
624
625 /* write attribute controller registers */
626 for (i = 0; i < VGA_ATT_C; i++) {
627 vga_io_r(VGA_IS1_RC); /* reset flip-flop */
628 vga_io_wattr(i, atc[i]);
629 }
630
631 /* Wait for screen to stabilize. */
632 mdelay(50);
633
634 vga_io_wseq(VGA_SEQ_CLOCK_MODE, seq[VGA_SEQ_CLOCK_MODE]);
635
636 vga_io_r(VGA_IS1_RC);
637 vga_io_w(VGA_ATT_IW, 0x20);
638
639 vga16fb_update_fix(info);
640 return 0;
641}
642
643static void ega16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
644{
ec1a7b3d 645 static const unsigned char map[] = { 000, 001, 010, 011 };
1da177e4
LT
646 int val;
647
648 if (regno >= 16)
649 return;
650 val = map[red>>14] | ((map[green>>14]) << 1) | ((map[blue>>14]) << 2);
651 vga_io_r(VGA_IS1_RC); /* ! 0x3BA */
652 vga_io_wattr(regno, val);
653 vga_io_r(VGA_IS1_RC); /* some clones need it */
654 vga_io_w(VGA_ATT_IW, 0x20); /* unblank screen */
655}
656
657static void vga16_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
658{
98219374
KH
659 outb(regno, VGA_PEL_IW);
660 outb(red >> 10, VGA_PEL_D);
661 outb(green >> 10, VGA_PEL_D);
662 outb(blue >> 10, VGA_PEL_D);
1da177e4
LT
663}
664
665static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
666 unsigned blue, unsigned transp,
667 struct fb_info *info)
668{
120ddb41 669 struct vga16fb_par *par = info->par;
1da177e4
LT
670 int gray;
671
672 /*
673 * Set a single color register. The values supplied are
674 * already rounded down to the hardware's capabilities
675 * (according to the entries in the `var' structure). Return
676 * != 0 for invalid regno.
677 */
678
679 if (regno >= 256)
680 return 1;
681
682 gray = info->var.grayscale;
683
684 if (gray) {
685 /* gray = 0.30*R + 0.59*G + 0.11*B */
686 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
687 }
688 if (par->isVGA)
689 vga16_setpalette(regno,red,green,blue);
690 else
691 ega16_setpalette(regno,red,green,blue);
692 return 0;
693}
694
695static int vga16fb_pan_display(struct fb_var_screeninfo *var,
696 struct fb_info *info)
697{
1da177e4 698 vga16fb_pan_var(info, var);
1da177e4
LT
699 return 0;
700}
701
702/* The following VESA blanking code is taken from vgacon.c. The VGA
703 blanking code was originally by Huang shi chao, and modified by
704 Christoph Rimek (chrimek@toppoint.de) and todd j. derr
705 (tjd@barefoot.org) for Linux. */
1da177e4
LT
706
707static void vga_vesa_blank(struct vga16fb_par *par, int mode)
708{
98219374
KH
709 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
710 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
1da177e4 711
1da177e4
LT
712 /* save original values of VGA controller registers */
713 if(!par->vesa_blanked) {
98219374 714 par->vga_state.CrtMiscIO = vga_io_r(VGA_MIS_R);
1da177e4
LT
715 //sti();
716
717 par->vga_state.HorizontalTotal = vga_io_rcrt(0x00); /* HorizontalTotal */
718 par->vga_state.HorizDisplayEnd = vga_io_rcrt(0x01); /* HorizDisplayEnd */
719 par->vga_state.StartHorizRetrace = vga_io_rcrt(0x04); /* StartHorizRetrace */
720 par->vga_state.EndHorizRetrace = vga_io_rcrt(0x05); /* EndHorizRetrace */
721 par->vga_state.Overflow = vga_io_rcrt(0x07); /* Overflow */
722 par->vga_state.StartVertRetrace = vga_io_rcrt(0x10); /* StartVertRetrace */
723 par->vga_state.EndVertRetrace = vga_io_rcrt(0x11); /* EndVertRetrace */
724 par->vga_state.ModeControl = vga_io_rcrt(0x17); /* ModeControl */
725 par->vga_state.ClockingMode = vga_io_rseq(0x01); /* ClockingMode */
726 }
727
728 /* assure that video is enabled */
729 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
1da177e4
LT
730 vga_io_wseq(0x01, par->vga_state.ClockingMode | 0x20);
731
732 /* test for vertical retrace in process.... */
733 if ((par->vga_state.CrtMiscIO & 0x80) == 0x80)
98219374 734 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO & 0xef);
1da177e4
LT
735
736 /*
737 * Set <End of vertical retrace> to minimum (0) and
738 * <Start of vertical Retrace> to maximum (incl. overflow)
739 * Result: turn off vertical sync (VSync) pulse.
740 */
741 if (mode & FB_BLANK_VSYNC_SUSPEND) {
98219374
KH
742 vga_io_wcrt(VGA_CRTC_V_SYNC_START, 0xff);
743 vga_io_wcrt(VGA_CRTC_V_SYNC_END, 0x40);
744 /* bits 9,10 of vert. retrace */
745 vga_io_wcrt(VGA_CRTC_OVERFLOW, par->vga_state.Overflow | 0x84);
1da177e4
LT
746 }
747
748 if (mode & FB_BLANK_HSYNC_SUSPEND) {
749 /*
750 * Set <End of horizontal retrace> to minimum (0) and
751 * <Start of horizontal Retrace> to maximum
752 * Result: turn off horizontal sync (HSync) pulse.
753 */
98219374
KH
754 vga_io_wcrt(VGA_CRTC_H_SYNC_START, 0xff);
755 vga_io_wcrt(VGA_CRTC_H_SYNC_END, 0x00);
1da177e4
LT
756 }
757
758 /* restore both index registers */
98219374
KH
759 outb_p(SeqCtrlIndex, VGA_SEQ_I);
760 outb_p(CrtCtrlIndex, VGA_CRT_IC);
1da177e4
LT
761}
762
763static void vga_vesa_unblank(struct vga16fb_par *par)
764{
98219374
KH
765 unsigned char SeqCtrlIndex = vga_io_r(VGA_SEQ_I);
766 unsigned char CrtCtrlIndex = vga_io_r(VGA_CRT_IC);
1da177e4 767
1da177e4 768 /* restore original values of VGA controller registers */
98219374 769 vga_io_w(VGA_MIS_W, par->vga_state.CrtMiscIO);
1da177e4
LT
770
771 /* HorizontalTotal */
772 vga_io_wcrt(0x00, par->vga_state.HorizontalTotal);
773 /* HorizDisplayEnd */
774 vga_io_wcrt(0x01, par->vga_state.HorizDisplayEnd);
775 /* StartHorizRetrace */
776 vga_io_wcrt(0x04, par->vga_state.StartHorizRetrace);
777 /* EndHorizRetrace */
778 vga_io_wcrt(0x05, par->vga_state.EndHorizRetrace);
779 /* Overflow */
780 vga_io_wcrt(0x07, par->vga_state.Overflow);
781 /* StartVertRetrace */
782 vga_io_wcrt(0x10, par->vga_state.StartVertRetrace);
783 /* EndVertRetrace */
784 vga_io_wcrt(0x11, par->vga_state.EndVertRetrace);
785 /* ModeControl */
786 vga_io_wcrt(0x17, par->vga_state.ModeControl);
787 /* ClockingMode */
788 vga_io_wseq(0x01, par->vga_state.ClockingMode);
789
790 /* restore index/control registers */
98219374
KH
791 vga_io_w(VGA_SEQ_I, SeqCtrlIndex);
792 vga_io_w(VGA_CRT_IC, CrtCtrlIndex);
1da177e4
LT
793}
794
795static void vga_pal_blank(void)
796{
797 int i;
798
799 for (i=0; i<16; i++) {
98219374
KH
800 outb_p(i, VGA_PEL_IW);
801 outb_p(0, VGA_PEL_D);
802 outb_p(0, VGA_PEL_D);
803 outb_p(0, VGA_PEL_D);
1da177e4
LT
804 }
805}
806
807/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
808static int vga16fb_blank(int blank, struct fb_info *info)
809{
120ddb41 810 struct vga16fb_par *par = info->par;
1da177e4
LT
811
812 switch (blank) {
813 case FB_BLANK_UNBLANK: /* Unblank */
814 if (par->vesa_blanked) {
815 vga_vesa_unblank(par);
816 par->vesa_blanked = 0;
817 }
818 if (par->palette_blanked) {
819 par->palette_blanked = 0;
820 }
821 break;
822 case FB_BLANK_NORMAL: /* blank */
823 vga_pal_blank();
824 par->palette_blanked = 1;
825 break;
826 default: /* VESA blanking */
827 vga_vesa_blank(par, blank);
828 par->vesa_blanked = 1;
829 break;
830 }
831 return 0;
832}
833
834static void vga_8planes_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
835{
836 u32 dx = rect->dx, width = rect->width;
837 char oldindex = getindex();
838 char oldmode = setmode(0x40);
839 char oldmask = selectmask();
840 int line_ofs, height;
841 char oldop, oldsr;
842 char __iomem *where;
843
844 dx /= 4;
845 where = info->screen_base + dx + rect->dy * info->fix.line_length;
846
847 if (rect->rop == ROP_COPY) {
848 oldop = setop(0);
849 oldsr = setsr(0);
850
851 width /= 4;
852 line_ofs = info->fix.line_length - width;
853 setmask(0xff);
854
855 height = rect->height;
856
857 while (height--) {
858 int x;
859
860 /* we can do memset... */
861 for (x = width; x > 0; --x) {
862 writeb(rect->color, where);
863 where++;
864 }
865 where += line_ofs;
866 }
867 } else {
868 char oldcolor = setcolor(0xf);
869 int y;
870
871 oldop = setop(0x18);
872 oldsr = setsr(0xf);
873 setmask(0x0F);
874 for (y = 0; y < rect->height; y++) {
875 rmw(where);
876 rmw(where+1);
877 where += info->fix.line_length;
878 }
879 setcolor(oldcolor);
880 }
881 setmask(oldmask);
882 setsr(oldsr);
883 setop(oldop);
884 setmode(oldmode);
885 setindex(oldindex);
886}
887
888static void vga16fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
889{
890 int x, x2, y2, vxres, vyres, width, height, line_ofs;
891 char __iomem *dst;
892
893 vxres = info->var.xres_virtual;
894 vyres = info->var.yres_virtual;
895
896 if (!rect->width || !rect->height || rect->dx > vxres || rect->dy > vyres)
897 return;
898
899 /* We could use hardware clipping but on many cards you get around
900 * hardware clipping by writing to framebuffer directly. */
901
902 x2 = rect->dx + rect->width;
903 y2 = rect->dy + rect->height;
904 x2 = x2 < vxres ? x2 : vxres;
905 y2 = y2 < vyres ? y2 : vyres;
906 width = x2 - rect->dx;
907
908 switch (info->fix.type) {
909 case FB_TYPE_VGA_PLANES:
910 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
911
912 height = y2 - rect->dy;
913 width = rect->width/8;
914
915 line_ofs = info->fix.line_length - width;
916 dst = info->screen_base + (rect->dx/8) + rect->dy * info->fix.line_length;
917
918 switch (rect->rop) {
919 case ROP_COPY:
920 setmode(0);
921 setop(0);
922 setsr(0xf);
923 setcolor(rect->color);
924 selectmask();
925
926 setmask(0xff);
927
928 while (height--) {
929 for (x = 0; x < width; x++) {
930 writeb(0, dst);
931 dst++;
932 }
933 dst += line_ofs;
934 }
935 break;
936 case ROP_XOR:
937 setmode(0);
938 setop(0x18);
939 setsr(0xf);
940 setcolor(0xf);
941 selectmask();
942
943 setmask(0xff);
944 while (height--) {
945 for (x = 0; x < width; x++) {
946 rmw(dst);
947 dst++;
948 }
949 dst += line_ofs;
950 }
951 break;
952 }
953 } else
954 vga_8planes_fillrect(info, rect);
955 break;
956 case FB_TYPE_PACKED_PIXELS:
957 default:
958 cfb_fillrect(info, rect);
959 break;
960 }
961}
962
963static void vga_8planes_copyarea(struct fb_info *info, const struct fb_copyarea *area)
964{
965 char oldindex = getindex();
966 char oldmode = setmode(0x41);
967 char oldop = setop(0);
968 char oldsr = setsr(0xf);
969 int height, line_ofs, x;
970 u32 sx, dx, width;
971 char __iomem *dest;
972 char __iomem *src;
973
974 height = area->height;
975
976 sx = area->sx / 4;
977 dx = area->dx / 4;
978 width = area->width / 4;
979
980 if (area->dy < area->sy || (area->dy == area->sy && dx < sx)) {
981 line_ofs = info->fix.line_length - width;
982 dest = info->screen_base + dx + area->dy * info->fix.line_length;
983 src = info->screen_base + sx + area->sy * info->fix.line_length;
984 while (height--) {
985 for (x = 0; x < width; x++) {
986 readb(src);
987 writeb(0, dest);
988 src++;
989 dest++;
990 }
991 src += line_ofs;
992 dest += line_ofs;
993 }
994 } else {
995 line_ofs = info->fix.line_length - width;
996 dest = info->screen_base + dx + width +
997 (area->dy + height - 1) * info->fix.line_length;
998 src = info->screen_base + sx + width +
999 (area->sy + height - 1) * info->fix.line_length;
1000 while (height--) {
1001 for (x = 0; x < width; x++) {
1002 --src;
1003 --dest;
1004 readb(src);
1005 writeb(0, dest);
1006 }
1007 src -= line_ofs;
1008 dest -= line_ofs;
1009 }
1010 }
1011
1012 setsr(oldsr);
1013 setop(oldop);
1014 setmode(oldmode);
1015 setindex(oldindex);
1016}
1017
1018static void vga16fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1019{
1020 u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
1021 int x, x2, y2, old_dx, old_dy, vxres, vyres;
1022 int height, width, line_ofs;
1023 char __iomem *dst = NULL;
1024 char __iomem *src = NULL;
1025
1026 vxres = info->var.xres_virtual;
1027 vyres = info->var.yres_virtual;
1028
1029 if (area->dx > vxres || area->sx > vxres || area->dy > vyres ||
1030 area->sy > vyres)
1031 return;
1032
1033 /* clip the destination */
1034 old_dx = area->dx;
1035 old_dy = area->dy;
1036
1037 /*
1038 * We could use hardware clipping but on many cards you get around
1039 * hardware clipping by writing to framebuffer directly.
1040 */
1041 x2 = area->dx + area->width;
1042 y2 = area->dy + area->height;
1043 dx = area->dx > 0 ? area->dx : 0;
1044 dy = area->dy > 0 ? area->dy : 0;
1045 x2 = x2 < vxres ? x2 : vxres;
1046 y2 = y2 < vyres ? y2 : vyres;
1047 width = x2 - dx;
1048 height = y2 - dy;
1049
77a6e7ab
RK
1050 if (sx + dx < old_dx || sy + dy < old_dy)
1051 return;
1052
1da177e4
LT
1053 /* update sx1,sy1 */
1054 sx += (dx - old_dx);
1055 sy += (dy - old_dy);
1056
1057 /* the source must be completely inside the virtual screen */
77a6e7ab 1058 if (sx + width > vxres || sy + height > vyres)
1da177e4
LT
1059 return;
1060
1061 switch (info->fix.type) {
1062 case FB_TYPE_VGA_PLANES:
1063 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1064 width = width/8;
1065 height = height;
1066 line_ofs = info->fix.line_length - width;
1067
1068 setmode(1);
1069 setop(0);
1070 setsr(0xf);
1071
1072 if (dy < sy || (dy == sy && dx < sx)) {
1073 dst = info->screen_base + (dx/8) + dy * info->fix.line_length;
1074 src = info->screen_base + (sx/8) + sy * info->fix.line_length;
1075 while (height--) {
1076 for (x = 0; x < width; x++) {
1077 readb(src);
1078 writeb(0, dst);
1079 dst++;
1080 src++;
1081 }
1082 src += line_ofs;
1083 dst += line_ofs;
1084 }
1085 } else {
1086 dst = info->screen_base + (dx/8) + width +
1087 (dy + height - 1) * info->fix.line_length;
1088 src = info->screen_base + (sx/8) + width +
1089 (sy + height - 1) * info->fix.line_length;
1090 while (height--) {
1091 for (x = 0; x < width; x++) {
1092 dst--;
1093 src--;
1094 readb(src);
1095 writeb(0, dst);
1096 }
1097 src -= line_ofs;
1098 dst -= line_ofs;
1099 }
1100 }
1101 } else
1102 vga_8planes_copyarea(info, area);
1103 break;
1104 case FB_TYPE_PACKED_PIXELS:
1105 default:
1106 cfb_copyarea(info, area);
1107 break;
1108 }
1109}
1110
ec1a7b3d
HD
1111#define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
1112#define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
1113 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
1114
1115#if defined(__LITTLE_ENDIAN)
1116static const u16 transl_l[] = TRANS_MASK_LOW;
1117static const u16 transl_h[] = TRANS_MASK_HIGH;
1118#elif defined(__BIG_ENDIAN)
1119static const u16 transl_l[] = TRANS_MASK_HIGH;
1120static const u16 transl_h[] = TRANS_MASK_LOW;
1da177e4
LT
1121#else
1122#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1123#endif
1da177e4
LT
1124
1125static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
1126{
1127 char oldindex = getindex();
1128 char oldmode = setmode(0x40);
1129 char oldop = setop(0);
1130 char oldsr = setsr(0);
1131 char oldmask = selectmask();
1132 const char *cdat = image->data;
1133 u32 dx = image->dx;
1134 char __iomem *where;
1135 int y;
1136
1137 dx /= 4;
1138 where = info->screen_base + dx + image->dy * info->fix.line_length;
1139
1140 setmask(0xff);
1141 writeb(image->bg_color, where);
1142 readb(where);
1143 selectmask();
1144 setmask(image->fg_color ^ image->bg_color);
1145 setmode(0x42);
1146 setop(0x18);
1147 for (y = 0; y < image->height; y++, where += info->fix.line_length)
1148 writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where);
1149 setmask(oldmask);
1150 setsr(oldsr);
1151 setop(oldop);
1152 setmode(oldmode);
1153 setindex(oldindex);
1154}
1155
1156static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
1157{
1158 char __iomem *where = info->screen_base + (image->dx/8) +
1159 image->dy * info->fix.line_length;
120ddb41 1160 struct vga16fb_par *par = info->par;
1da177e4
LT
1161 char *cdat = (char *) image->data;
1162 char __iomem *dst;
1163 int x, y;
1164
1165 switch (info->fix.type) {
1166 case FB_TYPE_VGA_PLANES:
1167 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1168 if (par->isVGA) {
1169 setmode(2);
1170 setop(0);
1171 setsr(0xf);
1172 setcolor(image->fg_color);
1173 selectmask();
1174
1175 setmask(0xff);
1176 writeb(image->bg_color, where);
1177 rmb();
1178 readb(where); /* fill latches */
1179 setmode(3);
1180 wmb();
1181 for (y = 0; y < image->height; y++) {
1182 dst = where;
1183 for (x = image->width/8; x--;)
1184 writeb(*cdat++, dst++);
1185 where += info->fix.line_length;
1186 }
1187 wmb();
1188 } else {
1189 setmode(0);
1190 setop(0);
1191 setsr(0xf);
1192 setcolor(image->bg_color);
1193 selectmask();
1194
1195 setmask(0xff);
1196 for (y = 0; y < image->height; y++) {
1197 dst = where;
1198 for (x=image->width/8; x--;){
1199 rmw(dst);
1200 setcolor(image->fg_color);
1201 selectmask();
1202 if (*cdat) {
1203 setmask(*cdat++);
1204 rmw(dst++);
1205 }
1206 }
1207 where += info->fix.line_length;
1208 }
1209 }
1210 } else
1211 vga_8planes_imageblit(info, image);
1212 break;
1213 case FB_TYPE_PACKED_PIXELS:
1214 default:
1215 cfb_imageblit(info, image);
1216 break;
1217 }
1218}
1219
1220static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
1221{
1222 /*
1223 * Draw logo
1224 */
120ddb41 1225 struct vga16fb_par *par = info->par;
1da177e4
LT
1226 char __iomem *where =
1227 info->screen_base + image->dy * info->fix.line_length +
1228 image->dx/8;
1229 const char *cdat = image->data;
1230 char __iomem *dst;
1231 int x, y;
1232
1233 switch (info->fix.type) {
1234 case FB_TYPE_VGA_PLANES:
1235 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
1236 par->isVGA) {
1237 setsr(0xf);
1238 setop(0);
1239 setmode(0);
1240
1241 for (y = 0; y < image->height; y++) {
1242 for (x = 0; x < image->width; x++) {
1243 dst = where + x/8;
1244
1245 setcolor(*cdat);
1246 selectmask();
1247 setmask(1 << (7 - (x % 8)));
1248 fb_readb(dst);
1249 fb_writeb(0, dst);
1250
1251 cdat++;
1252 }
1253 where += info->fix.line_length;
1254 }
1255 }
1256 break;
1257 case FB_TYPE_PACKED_PIXELS:
1258 cfb_imageblit(info, image);
1259 break;
1260 default:
1261 break;
1262 }
1263}
1264
1265static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
1266{
1267 if (image->depth == 1)
1268 vga_imageblit_expand(info, image);
1269 else
1270 vga_imageblit_color(info, image);
1271}
1272
1273static struct fb_ops vga16fb_ops = {
1274 .owner = THIS_MODULE,
1275 .fb_open = vga16fb_open,
1276 .fb_release = vga16fb_release,
1277 .fb_check_var = vga16fb_check_var,
1278 .fb_set_par = vga16fb_set_par,
1279 .fb_setcolreg = vga16fb_setcolreg,
1280 .fb_pan_display = vga16fb_pan_display,
1281 .fb_blank = vga16fb_blank,
1282 .fb_fillrect = vga16fb_fillrect,
1283 .fb_copyarea = vga16fb_copyarea,
1284 .fb_imageblit = vga16fb_imageblit,
1da177e4
LT
1285};
1286
1287#ifndef MODULE
1288static int vga16fb_setup(char *options)
1289{
1290 char *this_opt;
1291
1292 if (!options || !*options)
1293 return 0;
1294
1295 while ((this_opt = strsep(&options, ",")) != NULL) {
1296 if (!*this_opt) continue;
1297 }
1298 return 0;
1299}
1300#endif
1301
ae6d3218 1302static int __init vga16fb_probe(struct platform_device *dev)
1da177e4 1303{
120ddb41
AD
1304 struct fb_info *info;
1305 struct vga16fb_par *par;
1da177e4 1306 int i;
120ddb41 1307 int ret = 0;
1da177e4 1308
1da177e4 1309 printk(KERN_DEBUG "vga16fb: initializing\n");
120ddb41
AD
1310 info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
1311
1312 if (!info) {
1313 ret = -ENOMEM;
1314 goto err_fb_alloc;
1315 }
1da177e4
LT
1316
1317 /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
4f1bcaf0 1318 info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0);
1da177e4 1319
120ddb41 1320 if (!info->screen_base) {
1da177e4
LT
1321 printk(KERN_ERR "vga16fb: unable to map device\n");
1322 ret = -ENOMEM;
1323 goto err_ioremap;
1324 }
1da177e4 1325
120ddb41
AD
1326 printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
1327 par = info->par;
1da177e4 1328
c4f28e54 1329 mutex_init(&par->open_lock);
3ea33510 1330 par->isVGA = screen_info.orig_video_isVGA;
120ddb41
AD
1331 par->palette_blanked = 0;
1332 par->vesa_blanked = 0;
1333
1334 i = par->isVGA? 6 : 2;
1da177e4
LT
1335
1336 vga16fb_defined.red.length = i;
1337 vga16fb_defined.green.length = i;
1338 vga16fb_defined.blue.length = i;
1339
1340 /* name should not depend on EGA/VGA */
120ddb41
AD
1341 info->fbops = &vga16fb_ops;
1342 info->var = vga16fb_defined;
1343 info->fix = vga16fb_fix;
7e645ffd
AD
1344 /* supports rectangles with widths of multiples of 8 */
1345 info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
120ddb41 1346 info->flags = FBINFO_FLAG_DEFAULT |
1da177e4
LT
1347 FBINFO_HWACCEL_YPAN;
1348
120ddb41
AD
1349 i = (info->var.bits_per_pixel == 8) ? 256 : 16;
1350 ret = fb_alloc_cmap(&info->cmap, i, 0);
1da177e4
LT
1351 if (ret) {
1352 printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
1353 ret = -ENOMEM;
1354 goto err_alloc_cmap;
1355 }
1356
120ddb41 1357 if (vga16fb_check_var(&info->var, info)) {
1da177e4
LT
1358 printk(KERN_ERR "vga16fb: unable to validate variable\n");
1359 ret = -EINVAL;
1360 goto err_check_var;
1361 }
1362
120ddb41 1363 vga16fb_update_fix(info);
1da177e4 1364
120ddb41 1365 if (register_framebuffer(info) < 0) {
1da177e4
LT
1366 printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
1367 ret = -EINVAL;
1368 goto err_check_var;
1369 }
1370
1371 printk(KERN_INFO "fb%d: %s frame buffer device\n",
120ddb41 1372 info->node, info->fix.id);
ae6d3218 1373 platform_set_drvdata(dev, info);
1da177e4
LT
1374
1375 return 0;
1376
1377 err_check_var:
120ddb41 1378 fb_dealloc_cmap(&info->cmap);
1da177e4 1379 err_alloc_cmap:
120ddb41 1380 iounmap(info->screen_base);
1da177e4 1381 err_ioremap:
120ddb41
AD
1382 framebuffer_release(info);
1383 err_fb_alloc:
1384 return ret;
1385}
1386
ae6d3218 1387static int vga16fb_remove(struct platform_device *dev)
120ddb41 1388{
ae6d3218 1389 struct fb_info *info = platform_get_drvdata(dev);
120ddb41
AD
1390
1391 if (info) {
1392 unregister_framebuffer(info);
1393 iounmap(info->screen_base);
1394 fb_dealloc_cmap(&info->cmap);
1395 /* XXX unshare VGA regions */
1396 framebuffer_release(info);
1397 }
1398
1399 return 0;
1400}
1401
ae6d3218 1402static struct platform_driver vga16fb_driver = {
120ddb41
AD
1403 .probe = vga16fb_probe,
1404 .remove = vga16fb_remove,
ae6d3218
AD
1405 .driver = {
1406 .name = "vga16fb",
1407 },
120ddb41
AD
1408};
1409
ae6d3218 1410static struct platform_device *vga16fb_device;
120ddb41
AD
1411
1412static int __init vga16fb_init(void)
1413{
1414 int ret;
1415#ifndef MODULE
1416 char *option = NULL;
1417
1418 if (fb_get_options("vga16fb", &option))
1419 return -ENODEV;
1420
1421 vga16fb_setup(option);
1422#endif
ae6d3218 1423 ret = platform_driver_register(&vga16fb_driver);
120ddb41
AD
1424
1425 if (!ret) {
ae6d3218
AD
1426 vga16fb_device = platform_device_alloc("vga16fb", 0);
1427
1428 if (vga16fb_device)
1429 ret = platform_device_add(vga16fb_device);
1430 else
1431 ret = -ENOMEM;
1432
1433 if (ret) {
1434 platform_device_put(vga16fb_device);
1435 platform_driver_unregister(&vga16fb_driver);
1436 }
120ddb41
AD
1437 }
1438
1da177e4
LT
1439 return ret;
1440}
1441
1442static void __exit vga16fb_exit(void)
1443{
ae6d3218
AD
1444 platform_device_unregister(vga16fb_device);
1445 platform_driver_unregister(&vga16fb_driver);
1da177e4
LT
1446}
1447
98219374 1448MODULE_DESCRIPTION("Legacy VGA framebuffer device driver");
1da177e4
LT
1449MODULE_LICENSE("GPL");
1450module_init(vga16fb_init);
1451module_exit(vga16fb_exit);
1452
1453
1454/*
1455 * Overrides for Emacs so that we follow Linus's tabbing style.
1456 * ---------------------------------------------------------------------------
1457 * Local variables:
1458 * c-basic-offset: 8
1459 * End:
1460 */
1461
This page took 0.769812 seconds and 5 git commands to generate.