brintos

brintos / linux-shallow public Read only

0
0
Text · 20.0 KiB · 821b89a Raw
675 lines · c
1/*2 * Common utility functions for VGA-based graphics cards.3 *4 * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>5 *6 * This file is subject to the terms and conditions of the GNU General Public7 * License.  See the file COPYING in the main directory of this archive for8 * more details.9 *10 * Some parts are based on David Boucher's viafb (http://davesdomain.org.uk/viafb/)11 */12 13#include <linux/module.h>14#include <linux/kernel.h>15#include <linux/string.h>16#include <linux/fb.h>17#include <linux/math.h>18#include <linux/svga.h>19#include <asm/types.h>20#include <asm/io.h>21 22 23/* Write a CRT register value spread across multiple registers */24void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value)25{26	u8 regval, bitval, bitnum;27 28	while (regset->regnum != VGA_REGSET_END_VAL) {29		regval = vga_rcrt(regbase, regset->regnum);30		bitnum = regset->lowbit;31		while (bitnum <= regset->highbit) {32			bitval = 1 << bitnum;33			regval = regval & ~bitval;34			if (value & 1) regval = regval | bitval;35			bitnum ++;36			value = value >> 1;37		}38		vga_wcrt(regbase, regset->regnum, regval);39		regset ++;40	}41}42 43/* Write a sequencer register value spread across multiple registers */44void svga_wseq_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value)45{46	u8 regval, bitval, bitnum;47 48	while (regset->regnum != VGA_REGSET_END_VAL) {49		regval = vga_rseq(regbase, regset->regnum);50		bitnum = regset->lowbit;51		while (bitnum <= regset->highbit) {52			bitval = 1 << bitnum;53			regval = regval & ~bitval;54			if (value & 1) regval = regval | bitval;55			bitnum ++;56			value = value >> 1;57		}58		vga_wseq(regbase, regset->regnum, regval);59		regset ++;60	}61}62 63static unsigned int svga_regset_size(const struct vga_regset *regset)64{65	u8 count = 0;66 67	while (regset->regnum != VGA_REGSET_END_VAL) {68		count += regset->highbit - regset->lowbit + 1;69		regset ++;70	}71	return 1 << count;72}73 74 75/* ------------------------------------------------------------------------- */76 77 78/* Set graphics controller registers to sane values */79void svga_set_default_gfx_regs(void __iomem *regbase)80{81	/* All standard GFX registers (GR00 - GR08) */82	vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0x00);83	vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0x00);84	vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0x00);85	vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0x00);86	vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0x00);87	vga_wgfx(regbase, VGA_GFX_MODE, 0x00);88/*	vga_wgfx(regbase, VGA_GFX_MODE, 0x20); */89/*	vga_wgfx(regbase, VGA_GFX_MODE, 0x40); */90	vga_wgfx(regbase, VGA_GFX_MISC, 0x05);91/*	vga_wgfx(regbase, VGA_GFX_MISC, 0x01); */92	vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 0x0F);93	vga_wgfx(regbase, VGA_GFX_BIT_MASK, 0xFF);94}95 96/* Set attribute controller registers to sane values */97void svga_set_default_atc_regs(void __iomem *regbase)98{99	u8 count;100 101	vga_r(regbase, 0x3DA);102	vga_w(regbase, VGA_ATT_W, 0x00);103 104	/* All standard ATC registers (AR00 - AR14) */105	for (count = 0; count <= 0xF; count ++)106		svga_wattr(regbase, count, count);107 108	svga_wattr(regbase, VGA_ATC_MODE, 0x01);109/*	svga_wattr(regbase, VGA_ATC_MODE, 0x41); */110	svga_wattr(regbase, VGA_ATC_OVERSCAN, 0x00);111	svga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 0x0F);112	svga_wattr(regbase, VGA_ATC_PEL, 0x00);113	svga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0x00);114 115	vga_r(regbase, 0x3DA);116	vga_w(regbase, VGA_ATT_W, 0x20);117}118 119/* Set sequencer registers to sane values */120void svga_set_default_seq_regs(void __iomem *regbase)121{122	/* Standard sequencer registers (SR01 - SR04), SR00 is not set */123	vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, VGA_SR01_CHAR_CLK_8DOTS);124	vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, VGA_SR02_ALL_PLANES);125	vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0x00);126/*	vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE | VGA_SR04_CHN_4M); */127	vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE);128}129 130/* Set CRTC registers to sane values */131void svga_set_default_crt_regs(void __iomem *regbase)132{133	/* Standard CRT registers CR03 CR08 CR09 CR14 CR17 */134	svga_wcrt_mask(regbase, 0x03, 0x80, 0x80);	/* Enable vertical retrace EVRA */135	vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0);136	svga_wcrt_mask(regbase, VGA_CRTC_MAX_SCAN, 0, 0x1F);137	vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0);138	vga_wcrt(regbase, VGA_CRTC_MODE, 0xE3);139}140 141void svga_set_textmode_vga_regs(void __iomem *regbase)142{143	/* svga_wseq_mask(regbase, 0x1, 0x00, 0x01); */   /* Switch 8/9 pixel per char */144	vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM);145	vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x03);146 147	vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, 0x0f); /* 0x4f */148	vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0x1f);149	svga_wcrt_mask(regbase, VGA_CRTC_MODE, 0x23, 0x7f);150 151	vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0x0d);152	vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 0x0e);153	vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0x00);154	vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0x00);155 156	vga_wgfx(regbase, VGA_GFX_MODE, 0x10); /* Odd/even memory mode */157	vga_wgfx(regbase, VGA_GFX_MISC, 0x0E); /* Misc graphics register - text mode enable */158	vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 0x00);159 160	vga_r(regbase, 0x3DA);161	vga_w(regbase, VGA_ATT_W, 0x00);162 163	svga_wattr(regbase, 0x10, 0x0C);			/* Attribute Mode Control Register - text mode, blinking and line graphics */164	svga_wattr(regbase, 0x13, 0x08);			/* Horizontal Pixel Panning Register  */165 166	vga_r(regbase, 0x3DA);167	vga_w(regbase, VGA_ATT_W, 0x20);168}169 170#if 0171void svga_dump_var(struct fb_var_screeninfo *var, int node)172{173	pr_debug("fb%d: var.vmode         : 0x%X\n", node, var->vmode);174	pr_debug("fb%d: var.xres          : %d\n", node, var->xres);175	pr_debug("fb%d: var.yres          : %d\n", node, var->yres);176	pr_debug("fb%d: var.bits_per_pixel: %d\n", node, var->bits_per_pixel);177	pr_debug("fb%d: var.xres_virtual  : %d\n", node, var->xres_virtual);178	pr_debug("fb%d: var.yres_virtual  : %d\n", node, var->yres_virtual);179	pr_debug("fb%d: var.left_margin   : %d\n", node, var->left_margin);180	pr_debug("fb%d: var.right_margin  : %d\n", node, var->right_margin);181	pr_debug("fb%d: var.upper_margin  : %d\n", node, var->upper_margin);182	pr_debug("fb%d: var.lower_margin  : %d\n", node, var->lower_margin);183	pr_debug("fb%d: var.hsync_len     : %d\n", node, var->hsync_len);184	pr_debug("fb%d: var.vsync_len     : %d\n", node, var->vsync_len);185	pr_debug("fb%d: var.sync          : 0x%X\n", node, var->sync);186	pr_debug("fb%d: var.pixclock      : %d\n\n", node, var->pixclock);187}188#endif  /*  0  */189 190 191/* ------------------------------------------------------------------------- */192 193 194void svga_settile(struct fb_info *info, struct fb_tilemap *map)195{196	const u8 *font = map->data;197	u8 __iomem *fb = (u8 __iomem *)info->screen_base;198	int i, c;199 200	if ((map->width != 8) || (map->height != 16) ||201	    (map->depth != 1) || (map->length != 256)) {202		fb_err(info, "unsupported font parameters: width %d, height %d, depth %d, length %d\n",203		       map->width, map->height, map->depth, map->length);204		return;205	}206 207	fb += 2;208	for (c = 0; c < map->length; c++) {209		for (i = 0; i < map->height; i++) {210			fb_writeb(font[i], fb + i * 4);211//			fb[i * 4] = font[i];212		}213		fb += 128;214		font += map->height;215	}216}217 218/* Copy area in text (tileblit) mode */219void svga_tilecopy(struct fb_info *info, struct fb_tilearea *area)220{221	int dx, dy;222	/*  colstride is halved in this function because u16 are used */223	int colstride = 1 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);224	int rowstride = colstride * (info->var.xres_virtual / 8);225	u16 __iomem *fb = (u16 __iomem *) info->screen_base;226	u16 __iomem *src, *dst;227 228	if ((area->sy > area->dy) ||229	    ((area->sy == area->dy) && (area->sx > area->dx))) {230		src = fb + area->sx * colstride + area->sy * rowstride;231		dst = fb + area->dx * colstride + area->dy * rowstride;232	    } else {233		src = fb + (area->sx + area->width - 1) * colstride234			 + (area->sy + area->height - 1) * rowstride;235		dst = fb + (area->dx + area->width - 1) * colstride236			 + (area->dy + area->height - 1) * rowstride;237 238		colstride = -colstride;239		rowstride = -rowstride;240	    }241 242	for (dy = 0; dy < area->height; dy++) {243		u16 __iomem *src2 = src;244		u16 __iomem *dst2 = dst;245		for (dx = 0; dx < area->width; dx++) {246			fb_writew(fb_readw(src2), dst2);247//			*dst2 = *src2;248			src2 += colstride;249			dst2 += colstride;250		}251		src += rowstride;252		dst += rowstride;253	}254}255 256/* Fill area in text (tileblit) mode */257void svga_tilefill(struct fb_info *info, struct fb_tilerect *rect)258{259	int dx, dy;260	int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);261	int rowstride = colstride * (info->var.xres_virtual / 8);262	int attr = (0x0F & rect->bg) << 4 | (0x0F & rect->fg);263	u8 __iomem *fb = (u8 __iomem *)info->screen_base;264	fb += rect->sx * colstride + rect->sy * rowstride;265 266	for (dy = 0; dy < rect->height; dy++) {267		u8 __iomem *fb2 = fb;268		for (dx = 0; dx < rect->width; dx++) {269			fb_writeb(rect->index, fb2);270			fb_writeb(attr, fb2 + 1);271			fb2 += colstride;272		}273		fb += rowstride;274	}275}276 277/* Write text in text (tileblit) mode */278void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit)279{280	int dx, dy, i;281	int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);282	int rowstride = colstride * (info->var.xres_virtual / 8);283	int attr = (0x0F & blit->bg) << 4 | (0x0F & blit->fg);284	u8 __iomem *fb = (u8 __iomem *)info->screen_base;285	fb += blit->sx * colstride + blit->sy * rowstride;286 287	i=0;288	for (dy=0; dy < blit->height; dy ++) {289		u8 __iomem *fb2 = fb;290		for (dx = 0; dx < blit->width; dx ++) {291			fb_writeb(blit->indices[i], fb2);292			fb_writeb(attr, fb2 + 1);293			fb2 += colstride;294			i ++;295			if (i == blit->length) return;296		}297		fb += rowstride;298	}299 300}301 302/* Set cursor in text (tileblit) mode */303void svga_tilecursor(void __iomem *regbase, struct fb_info *info, struct fb_tilecursor *cursor)304{305	u8 cs = 0x0d;306	u8 ce = 0x0e;307	u16 pos =  cursor->sx + (info->var.xoffset /  8)308		+ (cursor->sy + (info->var.yoffset / 16))309		   * (info->var.xres_virtual / 8);310 311	if (! cursor -> mode)312		return;313 314	svga_wcrt_mask(regbase, 0x0A, 0x20, 0x20); /* disable cursor */315 316	if (cursor -> shape == FB_TILE_CURSOR_NONE)317		return;318 319	switch (cursor -> shape) {320	case FB_TILE_CURSOR_UNDERLINE:321		cs = 0x0d;322		break;323	case FB_TILE_CURSOR_LOWER_THIRD:324		cs = 0x09;325		break;326	case FB_TILE_CURSOR_LOWER_HALF:327		cs = 0x07;328		break;329	case FB_TILE_CURSOR_TWO_THIRDS:330		cs = 0x05;331		break;332	case FB_TILE_CURSOR_BLOCK:333		cs = 0x01;334		break;335	}336 337	/* set cursor position */338	vga_wcrt(regbase, 0x0E, pos >> 8);339	vga_wcrt(regbase, 0x0F, pos & 0xFF);340 341	vga_wcrt(regbase, 0x0B, ce); /* set cursor end */342	vga_wcrt(regbase, 0x0A, cs); /* set cursor start and enable it */343}344 345int svga_get_tilemax(struct fb_info *info)346{347	return 256;348}349 350/* Get capabilities of accelerator based on the mode */351 352void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,353		   struct fb_var_screeninfo *var)354{355	if (var->bits_per_pixel == 0) {356		/* can only support 256 8x16 bitmap */357		bitmap_zero(caps->x, FB_MAX_BLIT_WIDTH);358		set_bit(8 - 1, caps->x);359		bitmap_zero(caps->y, FB_MAX_BLIT_HEIGHT);360		set_bit(16 - 1, caps->y);361		caps->len = 256;362	} else {363		if (var->bits_per_pixel == 4) {364			bitmap_zero(caps->x, FB_MAX_BLIT_WIDTH);365			set_bit(8 - 1, caps->x);366		} else {367			bitmap_fill(caps->x, FB_MAX_BLIT_WIDTH);368		}369		bitmap_fill(caps->y, FB_MAX_BLIT_HEIGHT);370		caps->len = ~(u32)0;371	}372}373EXPORT_SYMBOL(svga_get_caps);374 375/* ------------------------------------------------------------------------- */376 377 378/*379 *  Compute PLL settings (M, N, R)380 *  F_VCO = (F_BASE * M) / N381 *  F_OUT = F_VCO / (2^R)382 */383int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u16 *r, int node)384{385	u16 am, an, ar;386	u32 f_vco, f_current, delta_current, delta_best;387 388	pr_debug("fb%d: ideal frequency: %d kHz\n", node, (unsigned int) f_wanted);389 390	ar = pll->r_max;391	f_vco = f_wanted << ar;392 393	/* overflow check */394	if ((f_vco >> ar) != f_wanted)395		return -EINVAL;396 397	/* It is usually better to have greater VCO clock398	   because of better frequency stability.399	   So first try r_max, then r smaller. */400	while ((ar > pll->r_min) && (f_vco > pll->f_vco_max)) {401		ar--;402		f_vco = f_vco >> 1;403	}404 405	/* VCO bounds check */406	if ((f_vco < pll->f_vco_min) || (f_vco > pll->f_vco_max))407		return -EINVAL;408 409	delta_best = 0xFFFFFFFF;410	*m = 0;411	*n = 0;412	*r = ar;413 414	am = pll->m_min;415	an = pll->n_min;416 417	while ((am <= pll->m_max) && (an <= pll->n_max)) {418		f_current = (pll->f_base * am) / an;419		delta_current = abs_diff (f_current, f_vco);420 421		if (delta_current < delta_best) {422			delta_best = delta_current;423			*m = am;424			*n = an;425		}426 427		if (f_current <= f_vco) {428			am ++;429		} else {430			an ++;431		}432	}433 434	f_current = (pll->f_base * *m) / *n;435	pr_debug("fb%d: found frequency: %d kHz (VCO %d kHz)\n", node, (int) (f_current >> ar), (int) f_current);436	pr_debug("fb%d: m = %d n = %d r = %d\n", node, (unsigned int) *m, (unsigned int) *n, (unsigned int) *r);437	return 0;438}439 440 441/* ------------------------------------------------------------------------- */442 443 444/* Check CRT timing values */445int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, int node)446{447	u32 value;448 449	var->xres         = (var->xres+7)&~7;450	var->left_margin  = (var->left_margin+7)&~7;451	var->right_margin = (var->right_margin+7)&~7;452	var->hsync_len    = (var->hsync_len+7)&~7;453 454	/* Check horizontal total */455	value = var->xres + var->left_margin + var->right_margin + var->hsync_len;456	if (((value / 8) - 5) >= svga_regset_size (tm->h_total_regs))457		return -EINVAL;458 459	/* Check horizontal display and blank start */460	value = var->xres;461	if (((value / 8) - 1) >= svga_regset_size (tm->h_display_regs))462		return -EINVAL;463	if (((value / 8) - 1) >= svga_regset_size (tm->h_blank_start_regs))464		return -EINVAL;465 466	/* Check horizontal sync start */467	value = var->xres + var->right_margin;468	if (((value / 8) - 1) >= svga_regset_size (tm->h_sync_start_regs))469		return -EINVAL;470 471	/* Check horizontal blank end (or length) */472	value = var->left_margin + var->right_margin + var->hsync_len;473	if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_blank_end_regs)))474		return -EINVAL;475 476	/* Check horizontal sync end (or length) */477	value = var->hsync_len;478	if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_sync_end_regs)))479		return -EINVAL;480 481	/* Check vertical total */482	value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;483	if ((value - 1) >= svga_regset_size(tm->v_total_regs))484		return -EINVAL;485 486	/* Check vertical display and blank start */487	value = var->yres;488	if ((value - 1) >= svga_regset_size(tm->v_display_regs))489		return -EINVAL;490	if ((value - 1) >= svga_regset_size(tm->v_blank_start_regs))491		return -EINVAL;492 493	/* Check vertical sync start */494	value = var->yres + var->lower_margin;495	if ((value - 1) >= svga_regset_size(tm->v_sync_start_regs))496		return -EINVAL;497 498	/* Check vertical blank end (or length) */499	value = var->upper_margin + var->lower_margin + var->vsync_len;500	if ((value == 0) || (value >= svga_regset_size (tm->v_blank_end_regs)))501		return -EINVAL;502 503	/* Check vertical sync end  (or length) */504	value = var->vsync_len;505	if ((value == 0) || (value >= svga_regset_size (tm->v_sync_end_regs)))506		return -EINVAL;507 508	return 0;509}510 511/* Set CRT timing registers */512void svga_set_timings(void __iomem *regbase, const struct svga_timing_regs *tm,513		      struct fb_var_screeninfo *var,514		      u32 hmul, u32 hdiv, u32 vmul, u32 vdiv, u32 hborder, int node)515{516	u8 regval;517	u32 value;518 519	value = var->xres + var->left_margin + var->right_margin + var->hsync_len;520	value = (value * hmul) / hdiv;521	pr_debug("fb%d: horizontal total      : %d\n", node, value);522	svga_wcrt_multi(regbase, tm->h_total_regs, (value / 8) - 5);523 524	value = var->xres;525	value = (value * hmul) / hdiv;526	pr_debug("fb%d: horizontal display    : %d\n", node, value);527	svga_wcrt_multi(regbase, tm->h_display_regs, (value / 8) - 1);528 529	value = var->xres;530	value = (value * hmul) / hdiv;531	pr_debug("fb%d: horizontal blank start: %d\n", node, value);532	svga_wcrt_multi(regbase, tm->h_blank_start_regs, (value / 8) - 1 + hborder);533 534	value = var->xres + var->left_margin + var->right_margin + var->hsync_len;535	value = (value * hmul) / hdiv;536	pr_debug("fb%d: horizontal blank end  : %d\n", node, value);537	svga_wcrt_multi(regbase, tm->h_blank_end_regs, (value / 8) - 1 - hborder);538 539	value = var->xres + var->right_margin;540	value = (value * hmul) / hdiv;541	pr_debug("fb%d: horizontal sync start : %d\n", node, value);542	svga_wcrt_multi(regbase, tm->h_sync_start_regs, (value / 8));543 544	value = var->xres + var->right_margin + var->hsync_len;545	value = (value * hmul) / hdiv;546	pr_debug("fb%d: horizontal sync end   : %d\n", node, value);547	svga_wcrt_multi(regbase, tm->h_sync_end_regs, (value / 8));548 549	value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;550	value = (value * vmul) / vdiv;551	pr_debug("fb%d: vertical total        : %d\n", node, value);552	svga_wcrt_multi(regbase, tm->v_total_regs, value - 2);553 554	value = var->yres;555	value = (value * vmul) / vdiv;556	pr_debug("fb%d: vertical display      : %d\n", node, value);557	svga_wcrt_multi(regbase, tm->v_display_regs, value - 1);558 559	value = var->yres;560	value = (value * vmul) / vdiv;561	pr_debug("fb%d: vertical blank start  : %d\n", node, value);562	svga_wcrt_multi(regbase, tm->v_blank_start_regs, value);563 564	value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;565	value = (value * vmul) / vdiv;566	pr_debug("fb%d: vertical blank end    : %d\n", node, value);567	svga_wcrt_multi(regbase, tm->v_blank_end_regs, value - 2);568 569	value = var->yres + var->lower_margin;570	value = (value * vmul) / vdiv;571	pr_debug("fb%d: vertical sync start   : %d\n", node, value);572	svga_wcrt_multi(regbase, tm->v_sync_start_regs, value);573 574	value = var->yres + var->lower_margin + var->vsync_len;575	value = (value * vmul) / vdiv;576	pr_debug("fb%d: vertical sync end     : %d\n", node, value);577	svga_wcrt_multi(regbase, tm->v_sync_end_regs, value);578 579	/* Set horizontal and vertical sync pulse polarity in misc register */580 581	regval = vga_r(regbase, VGA_MIS_R);582	if (var->sync & FB_SYNC_HOR_HIGH_ACT) {583		pr_debug("fb%d: positive horizontal sync\n", node);584		regval = regval & ~0x80;585	} else {586		pr_debug("fb%d: negative horizontal sync\n", node);587		regval = regval | 0x80;588	}589	if (var->sync & FB_SYNC_VERT_HIGH_ACT) {590		pr_debug("fb%d: positive vertical sync\n", node);591		regval = regval & ~0x40;592	} else {593		pr_debug("fb%d: negative vertical sync\n\n", node);594		regval = regval | 0x40;595	}596	vga_w(regbase, VGA_MIS_W, regval);597}598 599 600/* ------------------------------------------------------------------------- */601 602 603static inline int match_format(const struct svga_fb_format *frm,604			       struct fb_var_screeninfo *var)605{606	int i = 0;607	int stored = -EINVAL;608 609	while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL)610	{611		if ((var->bits_per_pixel == frm->bits_per_pixel) &&612		    (var->red.length     <= frm->red.length)     &&613		    (var->green.length   <= frm->green.length)   &&614		    (var->blue.length    <= frm->blue.length)    &&615		    (var->transp.length  <= frm->transp.length)  &&616		    (var->nonstd	 == frm->nonstd))617			return i;618		if (var->bits_per_pixel == frm->bits_per_pixel)619			stored = i;620		i++;621		frm++;622	}623	return stored;624}625 626int svga_match_format(const struct svga_fb_format *frm,627		      struct fb_var_screeninfo *var,628		      struct fb_fix_screeninfo *fix)629{630	int i = match_format(frm, var);631 632	if (i >= 0) {633		var->bits_per_pixel = frm[i].bits_per_pixel;634		var->red            = frm[i].red;635		var->green          = frm[i].green;636		var->blue           = frm[i].blue;637		var->transp         = frm[i].transp;638		var->nonstd         = frm[i].nonstd;639		if (fix != NULL) {640			fix->type      = frm[i].type;641			fix->type_aux  = frm[i].type_aux;642			fix->visual    = frm[i].visual;643			fix->xpanstep  = frm[i].xpanstep;644		}645	}646 647	return i;648}649 650 651EXPORT_SYMBOL(svga_wcrt_multi);652EXPORT_SYMBOL(svga_wseq_multi);653 654EXPORT_SYMBOL(svga_set_default_gfx_regs);655EXPORT_SYMBOL(svga_set_default_atc_regs);656EXPORT_SYMBOL(svga_set_default_seq_regs);657EXPORT_SYMBOL(svga_set_default_crt_regs);658EXPORT_SYMBOL(svga_set_textmode_vga_regs);659 660EXPORT_SYMBOL(svga_settile);661EXPORT_SYMBOL(svga_tilecopy);662EXPORT_SYMBOL(svga_tilefill);663EXPORT_SYMBOL(svga_tileblit);664EXPORT_SYMBOL(svga_tilecursor);665EXPORT_SYMBOL(svga_get_tilemax);666 667EXPORT_SYMBOL(svga_compute_pll);668EXPORT_SYMBOL(svga_check_timings);669EXPORT_SYMBOL(svga_set_timings);670EXPORT_SYMBOL(svga_match_format);671 672MODULE_AUTHOR("Ondrej Zajicek <santiago@crfreenet.org>");673MODULE_DESCRIPTION("Common utility functions for VGA-based graphics cards");674MODULE_LICENSE("GPL");675