File Index
Files and directories
Sign in
FILE

vga16fb.c

File preview with syntax highlighting.

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