blob: 2a14d28c41633ff92b28b9e253d1fb3530349fb0 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/slab.h>
19#include <linux/delay.h>
20#include <linux/fb.h>
21#include <linux/ioport.h>
22#include <linux/init.h>
Antonino A. Daplas120ddb42005-11-08 21:39:16 -080023#include <linux/platform_device.h>
Jon Smirla8f340e2006-07-10 04:44:12 -070024#include <linux/screen_info.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
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
Antonino A. Daplas120ddb42005-11-08 21:39:16 -080055struct vga16fb_par {
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 /* structure holding original VGA register settings when the
57 screen is blanked */
58 struct {
Antonino A. Daplas120ddb42005-11-08 21:39:16 -080059 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 } vga_state;
72 struct vgastate state;
Jiri Slabyc4f28e52007-02-12 00:55:11 -080073 struct mutex open_lock;
74 unsigned int ref_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 int palette_blanked, vesa_blanked, mode, isVGA;
76 u8 misc, pel_msk, vss, clkdiv;
77 u8 crtc[VGA_CRT_C];
Antonino A. Daplas120ddb42005-11-08 21:39:16 -080078};
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80/* --------------------------------------------------------------------- */
81
Antonino A. Daplas120ddb42005-11-08 21:39:16 -080082static struct fb_var_screeninfo vga16fb_defined __initdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 .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{
Antonino A. Daplas120ddb42005-11-08 21:39:16 -0800208 struct vga16fb_par *par = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 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{
Helge Dellerec1a7b32006-12-08 02:40:31 -0800268 static const struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 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{
Antonino A. Daplas120ddb42005-11-08 21:39:16 -0800303 struct vga16fb_par *par = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Jiri Slabyc4f28e52007-02-12 00:55:11 -0800305 mutex_lock(&par->open_lock);
306 if (!par->ref_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 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 }
Jiri Slabyc4f28e52007-02-12 00:55:11 -0800312 par->ref_count++;
313 mutex_unlock(&par->open_lock);
314
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 return 0;
316}
317
318static int vga16fb_release(struct fb_info *info, int user)
319{
Antonino A. Daplas120ddb42005-11-08 21:39:16 -0800320 struct vga16fb_par *par = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
Jiri Slabyc4f28e52007-02-12 00:55:11 -0800322 mutex_lock(&par->open_lock);
323 if (!par->ref_count) {
324 mutex_unlock(&par->open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 return -EINVAL;
Jiri Slabyc4f28e52007-02-12 00:55:11 -0800326 }
327 if (par->ref_count == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 restore_vga(&par->state);
Jiri Slabyc4f28e52007-02-12 00:55:11 -0800329 par->ref_count--;
330 mutex_unlock(&par->open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332 return 0;
333}
334
335static int vga16fb_check_var(struct fb_var_screeninfo *var,
336 struct fb_info *info)
337{
Antonino A. Daplas120ddb42005-11-08 21:39:16 -0800338 struct vga16fb_par *par = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 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{
Antonino A. Daplas120ddb42005-11-08 21:39:16 -0800543 struct vga16fb_par *par = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 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{
Helge Dellerec1a7b32006-12-08 02:40:31 -0800661 static const unsigned char map[] = { 000, 001, 010, 011 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 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{
Antonino A. Daplas120ddb42005-11-08 21:39:16 -0800685 struct vga16fb_par *par = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 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{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 vga16fb_pan_var(info, var);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 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{
Antonino A. Daplas120ddb42005-11-08 21:39:16 -0800850 struct vga16fb_par *par = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
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
1090 /* update sx1,sy1 */
1091 sx += (dx - old_dx);
1092 sy += (dy - old_dy);
1093
1094 /* the source must be completely inside the virtual screen */
1095 if (sx < 0 || sy < 0 || (sx + width) > vxres || (sy + height) > vyres)
1096 return;
1097
1098 switch (info->fix.type) {
1099 case FB_TYPE_VGA_PLANES:
1100 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1101 width = width/8;
1102 height = height;
1103 line_ofs = info->fix.line_length - width;
1104
1105 setmode(1);
1106 setop(0);
1107 setsr(0xf);
1108
1109 if (dy < sy || (dy == sy && dx < sx)) {
1110 dst = info->screen_base + (dx/8) + dy * info->fix.line_length;
1111 src = info->screen_base + (sx/8) + sy * info->fix.line_length;
1112 while (height--) {
1113 for (x = 0; x < width; x++) {
1114 readb(src);
1115 writeb(0, dst);
1116 dst++;
1117 src++;
1118 }
1119 src += line_ofs;
1120 dst += line_ofs;
1121 }
1122 } else {
1123 dst = info->screen_base + (dx/8) + width +
1124 (dy + height - 1) * info->fix.line_length;
1125 src = info->screen_base + (sx/8) + width +
1126 (sy + height - 1) * info->fix.line_length;
1127 while (height--) {
1128 for (x = 0; x < width; x++) {
1129 dst--;
1130 src--;
1131 readb(src);
1132 writeb(0, dst);
1133 }
1134 src -= line_ofs;
1135 dst -= line_ofs;
1136 }
1137 }
1138 } else
1139 vga_8planes_copyarea(info, area);
1140 break;
1141 case FB_TYPE_PACKED_PIXELS:
1142 default:
1143 cfb_copyarea(info, area);
1144 break;
1145 }
1146}
1147
Helge Dellerec1a7b32006-12-08 02:40:31 -08001148#define TRANS_MASK_LOW {0x0,0x8,0x4,0xC,0x2,0xA,0x6,0xE,0x1,0x9,0x5,0xD,0x3,0xB,0x7,0xF}
1149#define TRANS_MASK_HIGH {0x000, 0x800, 0x400, 0xC00, 0x200, 0xA00, 0x600, 0xE00, \
1150 0x100, 0x900, 0x500, 0xD00, 0x300, 0xB00, 0x700, 0xF00}
1151
1152#if defined(__LITTLE_ENDIAN)
1153static const u16 transl_l[] = TRANS_MASK_LOW;
1154static const u16 transl_h[] = TRANS_MASK_HIGH;
1155#elif defined(__BIG_ENDIAN)
1156static const u16 transl_l[] = TRANS_MASK_HIGH;
1157static const u16 transl_h[] = TRANS_MASK_LOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158#else
1159#error "Only __BIG_ENDIAN and __LITTLE_ENDIAN are supported in vga-planes"
1160#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
1162static void vga_8planes_imageblit(struct fb_info *info, const struct fb_image *image)
1163{
1164 char oldindex = getindex();
1165 char oldmode = setmode(0x40);
1166 char oldop = setop(0);
1167 char oldsr = setsr(0);
1168 char oldmask = selectmask();
1169 const char *cdat = image->data;
1170 u32 dx = image->dx;
1171 char __iomem *where;
1172 int y;
1173
1174 dx /= 4;
1175 where = info->screen_base + dx + image->dy * info->fix.line_length;
1176
1177 setmask(0xff);
1178 writeb(image->bg_color, where);
1179 readb(where);
1180 selectmask();
1181 setmask(image->fg_color ^ image->bg_color);
1182 setmode(0x42);
1183 setop(0x18);
1184 for (y = 0; y < image->height; y++, where += info->fix.line_length)
1185 writew(transl_h[cdat[y]&0xF] | transl_l[cdat[y] >> 4], where);
1186 setmask(oldmask);
1187 setsr(oldsr);
1188 setop(oldop);
1189 setmode(oldmode);
1190 setindex(oldindex);
1191}
1192
1193static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *image)
1194{
1195 char __iomem *where = info->screen_base + (image->dx/8) +
1196 image->dy * info->fix.line_length;
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001197 struct vga16fb_par *par = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 char *cdat = (char *) image->data;
1199 char __iomem *dst;
1200 int x, y;
1201
1202 switch (info->fix.type) {
1203 case FB_TYPE_VGA_PLANES:
1204 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4) {
1205 if (par->isVGA) {
1206 setmode(2);
1207 setop(0);
1208 setsr(0xf);
1209 setcolor(image->fg_color);
1210 selectmask();
1211
1212 setmask(0xff);
1213 writeb(image->bg_color, where);
1214 rmb();
1215 readb(where); /* fill latches */
1216 setmode(3);
1217 wmb();
1218 for (y = 0; y < image->height; y++) {
1219 dst = where;
1220 for (x = image->width/8; x--;)
1221 writeb(*cdat++, dst++);
1222 where += info->fix.line_length;
1223 }
1224 wmb();
1225 } else {
1226 setmode(0);
1227 setop(0);
1228 setsr(0xf);
1229 setcolor(image->bg_color);
1230 selectmask();
1231
1232 setmask(0xff);
1233 for (y = 0; y < image->height; y++) {
1234 dst = where;
1235 for (x=image->width/8; x--;){
1236 rmw(dst);
1237 setcolor(image->fg_color);
1238 selectmask();
1239 if (*cdat) {
1240 setmask(*cdat++);
1241 rmw(dst++);
1242 }
1243 }
1244 where += info->fix.line_length;
1245 }
1246 }
1247 } else
1248 vga_8planes_imageblit(info, image);
1249 break;
1250 case FB_TYPE_PACKED_PIXELS:
1251 default:
1252 cfb_imageblit(info, image);
1253 break;
1254 }
1255}
1256
1257static void vga_imageblit_color(struct fb_info *info, const struct fb_image *image)
1258{
1259 /*
1260 * Draw logo
1261 */
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001262 struct vga16fb_par *par = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 char __iomem *where =
1264 info->screen_base + image->dy * info->fix.line_length +
1265 image->dx/8;
1266 const char *cdat = image->data;
1267 char __iomem *dst;
1268 int x, y;
1269
1270 switch (info->fix.type) {
1271 case FB_TYPE_VGA_PLANES:
1272 if (info->fix.type_aux == FB_AUX_VGA_PLANES_VGA4 &&
1273 par->isVGA) {
1274 setsr(0xf);
1275 setop(0);
1276 setmode(0);
1277
1278 for (y = 0; y < image->height; y++) {
1279 for (x = 0; x < image->width; x++) {
1280 dst = where + x/8;
1281
1282 setcolor(*cdat);
1283 selectmask();
1284 setmask(1 << (7 - (x % 8)));
1285 fb_readb(dst);
1286 fb_writeb(0, dst);
1287
1288 cdat++;
1289 }
1290 where += info->fix.line_length;
1291 }
1292 }
1293 break;
1294 case FB_TYPE_PACKED_PIXELS:
1295 cfb_imageblit(info, image);
1296 break;
1297 default:
1298 break;
1299 }
1300}
1301
1302static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image)
1303{
1304 if (image->depth == 1)
1305 vga_imageblit_expand(info, image);
1306 else
1307 vga_imageblit_color(info, image);
1308}
1309
1310static struct fb_ops vga16fb_ops = {
1311 .owner = THIS_MODULE,
1312 .fb_open = vga16fb_open,
1313 .fb_release = vga16fb_release,
1314 .fb_check_var = vga16fb_check_var,
1315 .fb_set_par = vga16fb_set_par,
1316 .fb_setcolreg = vga16fb_setcolreg,
1317 .fb_pan_display = vga16fb_pan_display,
1318 .fb_blank = vga16fb_blank,
1319 .fb_fillrect = vga16fb_fillrect,
1320 .fb_copyarea = vga16fb_copyarea,
1321 .fb_imageblit = vga16fb_imageblit,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322};
1323
1324#ifndef MODULE
1325static int vga16fb_setup(char *options)
1326{
1327 char *this_opt;
1328
1329 if (!options || !*options)
1330 return 0;
1331
1332 while ((this_opt = strsep(&options, ",")) != NULL) {
1333 if (!*this_opt) continue;
1334 }
1335 return 0;
1336}
1337#endif
1338
Antonino A. Daplasae6d3212006-06-26 00:26:35 -07001339static int __init vga16fb_probe(struct platform_device *dev)
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001340{
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001341 struct fb_info *info;
1342 struct vga16fb_par *par;
1343 int i;
1344 int ret = 0;
1345
1346 printk(KERN_DEBUG "vga16fb: initializing\n");
1347 info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
1348
1349 if (!info) {
1350 ret = -ENOMEM;
1351 goto err_fb_alloc;
1352 }
1353
1354 /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
Bjorn Helgaas4f1bcaf2006-06-22 14:47:32 -07001355 info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0);
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001356
1357 if (!info->screen_base) {
1358 printk(KERN_ERR "vga16fb: unable to map device\n");
1359 ret = -ENOMEM;
1360 goto err_ioremap;
1361 }
1362
1363 printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
1364 par = info->par;
1365
Jiri Slabyc4f28e52007-02-12 00:55:11 -08001366 mutex_init(&par->open_lock);
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001367 par->isVGA = ORIG_VIDEO_ISVGA;
1368 par->palette_blanked = 0;
1369 par->vesa_blanked = 0;
1370
1371 i = par->isVGA? 6 : 2;
1372
1373 vga16fb_defined.red.length = i;
1374 vga16fb_defined.green.length = i;
1375 vga16fb_defined.blue.length = i;
1376
1377 /* name should not depend on EGA/VGA */
1378 info->fbops = &vga16fb_ops;
1379 info->var = vga16fb_defined;
1380 info->fix = vga16fb_fix;
Antonino A. Daplas7e645ff2007-05-08 00:40:08 -07001381 /* supports rectangles with widths of multiples of 8 */
1382 info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001383 info->flags = FBINFO_FLAG_DEFAULT |
1384 FBINFO_HWACCEL_YPAN;
1385
1386 i = (info->var.bits_per_pixel == 8) ? 256 : 16;
1387 ret = fb_alloc_cmap(&info->cmap, i, 0);
1388 if (ret) {
1389 printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
1390 ret = -ENOMEM;
1391 goto err_alloc_cmap;
1392 }
1393
1394 if (vga16fb_check_var(&info->var, info)) {
1395 printk(KERN_ERR "vga16fb: unable to validate variable\n");
1396 ret = -EINVAL;
1397 goto err_check_var;
1398 }
1399
1400 vga16fb_update_fix(info);
1401
1402 if (register_framebuffer(info) < 0) {
1403 printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
1404 ret = -EINVAL;
1405 goto err_check_var;
1406 }
1407
1408 printk(KERN_INFO "fb%d: %s frame buffer device\n",
1409 info->node, info->fix.id);
Antonino A. Daplasae6d3212006-06-26 00:26:35 -07001410 platform_set_drvdata(dev, info);
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001411
1412 return 0;
1413
1414 err_check_var:
1415 fb_dealloc_cmap(&info->cmap);
1416 err_alloc_cmap:
1417 iounmap(info->screen_base);
1418 err_ioremap:
1419 framebuffer_release(info);
1420 err_fb_alloc:
1421 return ret;
1422}
1423
Antonino A. Daplasae6d3212006-06-26 00:26:35 -07001424static int vga16fb_remove(struct platform_device *dev)
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001425{
Antonino A. Daplasae6d3212006-06-26 00:26:35 -07001426 struct fb_info *info = platform_get_drvdata(dev);
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001427
1428 if (info) {
1429 unregister_framebuffer(info);
1430 iounmap(info->screen_base);
1431 fb_dealloc_cmap(&info->cmap);
1432 /* XXX unshare VGA regions */
1433 framebuffer_release(info);
1434 }
1435
1436 return 0;
1437}
1438
Antonino A. Daplasae6d3212006-06-26 00:26:35 -07001439static struct platform_driver vga16fb_driver = {
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001440 .probe = vga16fb_probe,
1441 .remove = vga16fb_remove,
Antonino A. Daplasae6d3212006-06-26 00:26:35 -07001442 .driver = {
1443 .name = "vga16fb",
1444 },
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001445};
1446
Antonino A. Daplasae6d3212006-06-26 00:26:35 -07001447static struct platform_device *vga16fb_device;
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001448
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449static int __init vga16fb_init(void)
1450{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 int ret;
1452#ifndef MODULE
1453 char *option = NULL;
1454
1455 if (fb_get_options("vga16fb", &option))
1456 return -ENODEV;
1457
1458 vga16fb_setup(option);
1459#endif
Antonino A. Daplasae6d3212006-06-26 00:26:35 -07001460 ret = platform_driver_register(&vga16fb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
Antonino A. Daplas120ddb42005-11-08 21:39:16 -08001462 if (!ret) {
Antonino A. Daplasae6d3212006-06-26 00:26:35 -07001463 vga16fb_device = platform_device_alloc("vga16fb", 0);
1464
1465 if (vga16fb_device)
1466 ret = platform_device_add(vga16fb_device);
1467 else
1468 ret = -ENOMEM;
1469
1470 if (ret) {
1471 platform_device_put(vga16fb_device);
1472 platform_driver_unregister(&vga16fb_driver);
1473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 }
1475
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 return ret;
1477}
1478
1479static void __exit vga16fb_exit(void)
1480{
Antonino A. Daplasae6d3212006-06-26 00:26:35 -07001481 platform_device_unregister(vga16fb_device);
1482 platform_driver_unregister(&vga16fb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483}
1484
1485MODULE_LICENSE("GPL");
1486module_init(vga16fb_init);
1487module_exit(vga16fb_exit);
1488
1489
1490/*
1491 * Overrides for Emacs so that we follow Linus's tabbing style.
1492 * ---------------------------------------------------------------------------
1493 * Local variables:
1494 * c-basic-offset: 8
1495 * End:
1496 */
1497