Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 465 → Rev 466

/shark/trunk/drivers/fb/fbmem.c
0,0 → 1,1393
/*
* linux/drivers/video/fbmem.c
*
* Copyright (C) 1994 Martin Schaller
*
* 2001 - Documented with DocBook
* - Brad Douglas <brad@neruo.com>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/module.h>
 
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/tty.h>
#include <linux/init.h>
#include <linux/linux_logo.h>
#include <linux/proc_fs.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
#include <linux/devfs_fs_kernel.h>
 
#if defined(__mc68000__) || defined(CONFIG_APUS)
#include <asm/setup.h>
#endif
 
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/pgtable.h>
 
#include <linux/fb.h>
 
#ifdef CONFIG_FRAMEBUFFER_CONSOLE
#include "console/fbcon.h"
#endif
/*
* Frame buffer device initialization and setup routines
*/
 
extern int acornfb_init(void);
extern int acornfb_setup(char*);
extern int amifb_init(void);
extern int amifb_setup(char*);
extern int anakinfb_init(void);
extern int atafb_init(void);
extern int atafb_setup(char*);
extern int macfb_init(void);
extern int macfb_setup(char*);
extern int cyberfb_init(void);
extern int cyberfb_setup(char*);
extern int pm2fb_init(void);
extern int pm2fb_setup(char*);
extern int pm3fb_init(void);
extern int pm3fb_setup(char*);
extern int clps711xfb_init(void);
extern int cyber2000fb_init(void);
extern int cyber2000fb_setup(char*);
extern int retz3fb_init(void);
extern int retz3fb_setup(char*);
extern int clgenfb_init(void);
extern int clgenfb_setup(char*);
extern int hitfb_init(void);
extern int vfb_init(void);
extern int vfb_setup(char*);
extern int offb_init(void);
extern int atyfb_init(void);
extern int atyfb_setup(char*);
extern int aty128fb_init(void);
extern int aty128fb_setup(char*);
extern int neofb_init(void);
extern int neofb_setup(char*);
extern int igafb_init(void);
extern int igafb_setup(char*);
extern int imsttfb_init(void);
extern int imsttfb_setup(char*);
extern int dnfb_init(void);
extern int tgafb_init(void);
extern int tgafb_setup(char*);
extern int virgefb_init(void);
extern int virgefb_setup(char*);
extern int resolver_video_setup(char*);
extern int s3triofb_init(void);
extern int vesafb_init(void);
extern int vesafb_setup(char*);
extern int vga16fb_init(void);
extern int vga16fb_setup(char*);
extern int hgafb_init(void);
extern int hgafb_setup(char*);
extern int matroxfb_init(void);
extern int matroxfb_setup(char*);
extern int hpfb_init(void);
extern int control_init(void);
extern int control_setup(char*);
extern int platinum_init(void);
extern int platinum_setup(char*);
extern int valkyriefb_init(void);
extern int valkyriefb_setup(char*);
extern int chips_init(void);
extern int g364fb_init(void);
extern int sa1100fb_init(void);
extern int fm2fb_init(void);
extern int fm2fb_setup(char*);
extern int q40fb_init(void);
extern int sun3fb_init(void);
extern int sun3fb_setup(char *);
extern int sgivwfb_init(void);
extern int sgivwfb_setup(char*);
extern int rivafb_init(void);
extern int rivafb_setup(char*);
extern int tdfxfb_init(void);
extern int tdfxfb_setup(char*);
extern int tridentfb_init(void);
extern int tridentfb_setup(char*);
extern int sisfb_init(void);
extern int sisfb_setup(char*);
extern int stifb_init(void);
extern int stifb_setup(char*);
extern int pmagbafb_init(void);
extern int pmagbbfb_init(void);
extern int maxinefb_init(void);
extern int tx3912fb_init(void);
extern int tx3912fb_setup(char*);
extern int radeonfb_init(void);
extern int radeonfb_setup(char*);
extern int e1355fb_init(void);
extern int e1355fb_setup(char*);
extern int pvr2fb_init(void);
extern int pvr2fb_setup(char*);
extern int sstfb_init(void);
extern int sstfb_setup(char*);
extern int i810fb_init(void);
extern int i810fb_setup(char*);
extern int ffb_init(void);
extern int ffb_setup(char*);
extern int cg6_init(void);
extern int cg6_setup(char*);
extern int cg3_init(void);
extern int cg3_setup(char*);
extern int bw2_init(void);
extern int bw2_setup(char*);
extern int cg14_init(void);
extern int cg14_setup(char*);
extern int p9100_init(void);
extern int p9100_setup(char*);
extern int tcx_init(void);
extern int tcx_setup(char*);
extern int leo_init(void);
extern int leo_setup(char*);
 
static struct {
const char *name;
int (*init)(void);
int (*setup)(char*);
} fb_drivers[] __initdata = {
 
/*
* Chipset specific drivers that use resource management
*/
#ifdef CONFIG_FB_RETINAZ3
{ "retz3fb", retz3fb_init, retz3fb_setup },
#endif
#ifdef CONFIG_FB_AMIGA
{ "amifb", amifb_init, amifb_setup },
#endif
#ifdef CONFIG_FB_ANAKIN
{ "anakinfb", anakinfb_init, NULL },
#endif
#ifdef CONFIG_FB_CLPS711X
{ "clps711xfb", clps711xfb_init, NULL },
#endif
#ifdef CONFIG_FB_CYBER
{ "cyberfb", cyberfb_init, cyberfb_setup },
#endif
#ifdef CONFIG_FB_CYBER2000
{ "cyber2000fb", cyber2000fb_init, cyber2000fb_setup },
#endif
#ifdef CONFIG_FB_PM2
{ "pm2fb", pm2fb_init, pm2fb_setup },
#endif
#ifdef CONFIG_FB_PM3
{ "pm3fb", pm3fb_init, pm3fb_setup },
#endif
#ifdef CONFIG_FB_CLGEN
{ "clgenfb", clgenfb_init, clgenfb_setup },
#endif
#ifdef CONFIG_FB_ATY
{ "atyfb", atyfb_init, atyfb_setup },
#endif
#ifdef CONFIG_FB_MATROX
{ "matroxfb", matroxfb_init, matroxfb_setup },
#endif
#ifdef CONFIG_FB_ATY128
{ "aty128fb", aty128fb_init, aty128fb_setup },
#endif
#ifdef CONFIG_FB_NEOMAGIC
{ "neofb", neofb_init, neofb_setup },
#endif
#ifdef CONFIG_FB_VIRGE
{ "virgefb", virgefb_init, virgefb_setup },
#endif
#ifdef CONFIG_FB_RIVA
{ "rivafb", rivafb_init, rivafb_setup },
#endif
#ifdef CONFIG_FB_3DFX
{ "tdfxfb", tdfxfb_init, tdfxfb_setup },
#endif
#ifdef CONFIG_FB_RADEON
{ "radeonfb", radeonfb_init, radeonfb_setup },
#endif
#ifdef CONFIG_FB_CONTROL
{ "controlfb", control_init, control_setup },
#endif
#ifdef CONFIG_FB_PLATINUM
{ "platinumfb", platinum_init, platinum_setup },
#endif
#ifdef CONFIG_FB_VALKYRIE
{ "valkyriefb", valkyriefb_init, valkyriefb_setup },
#endif
#ifdef CONFIG_FB_CT65550
{ "chipsfb", chips_init, NULL },
#endif
#ifdef CONFIG_FB_IMSTT
{ "imsttfb", imsttfb_init, imsttfb_setup },
#endif
#ifdef CONFIG_FB_S3TRIO
{ "s3triofb", s3triofb_init, NULL },
#endif
#ifdef CONFIG_FB_FM2
{ "fm2fb", fm2fb_init, fm2fb_setup },
#endif
#ifdef CONFIG_FB_SIS
{ "sisfb", sisfb_init, sisfb_setup },
#endif
#ifdef CONFIG_FB_TRIDENT
{ "tridentfb", tridentfb_init, tridentfb_setup },
#endif
#ifdef CONFIG_FB_I810
{ "i810fb", i810fb_init, i810fb_setup },
#endif
#ifdef CONFIG_FB_STI
{ "stifb", stifb_init, stifb_setup },
#endif
#ifdef CONFIG_FB_FFB
{ "ffb", ffb_init, ffb_setup },
#endif
#ifdef CONFIG_FB_CG6
{ "cg6fb", cg6_init, cg6_setup },
#endif
#ifdef CONFIG_FB_CG3
{ "cg3fb", cg3_init, cg3_setup },
#endif
#ifdef CONFIG_FB_BW2
{ "bw2fb", bw2_init, bw2_setup },
#endif
#ifdef CONFIG_FB_CG14
{ "cg14fb", cg14_init, cg14_setup },
#endif
#ifdef CONFIG_FB_P9100
{ "p9100fb", p9100_init, p9100_setup },
#endif
#ifdef CONFIG_FB_TCX
{ "tcxfb", tcx_init, tcx_setup },
#endif
#ifdef CONFIG_FB_LEO
{ "leofb", leo_init, leo_setup },
#endif
 
/*
* Generic drivers that are used as fallbacks
*
* These depend on resource management and must be initialized
* _after_ all other frame buffer devices that use resource
* management!
*/
 
#ifdef CONFIG_FB_OF
{ "offb", offb_init, NULL },
#endif
#ifdef CONFIG_FB_VESA
{ "vesafb", vesafb_init, vesafb_setup },
#endif
 
/*
* Chipset specific drivers that don't use resource management (yet)
*/
 
#ifdef CONFIG_FB_SGIVW
{ "sgivwfb", sgivwfb_init, sgivwfb_setup },
#endif
#ifdef CONFIG_FB_ACORN
{ "acornfb", acornfb_init, acornfb_setup },
#endif
#ifdef CONFIG_FB_ATARI
{ "atafb", atafb_init, atafb_setup },
#endif
#ifdef CONFIG_FB_MAC
{ "macfb", macfb_init, macfb_setup },
#endif
#ifdef CONFIG_FB_HGA
{ "hgafb", hgafb_init, hgafb_setup },
#endif
#ifdef CONFIG_FB_IGA
{ "igafb", igafb_init, igafb_setup },
#endif
#ifdef CONFIG_APOLLO
{ "apollofb", dnfb_init, NULL },
#endif
#ifdef CONFIG_FB_Q40
{ "q40fb", q40fb_init, NULL },
#endif
#ifdef CONFIG_FB_TGA
{ "tgafb", tgafb_init, tgafb_setup },
#endif
#ifdef CONFIG_FB_HP300
{ "hpfb", hpfb_init, NULL },
#endif
#ifdef CONFIG_FB_G364
{ "g364fb", g364fb_init, NULL },
#endif
#ifdef CONFIG_FB_SA1100
{ "sa1100fb", sa1100fb_init, NULL },
#endif
#ifdef CONFIG_FB_SUN3
{ "sun3fb", sun3fb_init, sun3fb_setup },
#endif
#ifdef CONFIG_FB_HIT
{ "hitfb", hitfb_init, NULL },
#endif
#ifdef CONFIG_FB_TX3912
{ "tx3912fb", tx3912fb_init, tx3912fb_setup },
#endif
#ifdef CONFIG_FB_E1355
{ "e1355fb", e1355fb_init, e1355fb_setup },
#endif
#ifdef CONFIG_FB_PVR2
{ "pvr2fb", pvr2fb_init, pvr2fb_setup },
#endif
#ifdef CONFIG_FB_PMAG_BA
{ "pmagbafb", pmagbafb_init, NULL },
#endif
#ifdef CONFIG_FB_PMAGB_B
{ "pmagbbfb", pmagbbfb_init, NULL },
#endif
#ifdef CONFIG_FB_MAXINE
{ "maxinefb", maxinefb_init, NULL },
#endif
#ifdef CONFIG_FB_VOODOO1
{ "sstfb", sstfb_init, sstfb_setup },
#endif
/*
* Generic drivers that don't use resource management (yet)
*/
 
#ifdef CONFIG_FB_VGA16
{ "vga16fb", vga16fb_init, vga16fb_setup },
#endif
 
#ifdef CONFIG_GSP_RESOLVER
/* Not a real frame buffer device... */
{ "resolverfb", NULL, resolver_video_setup },
#endif
 
#ifdef CONFIG_FB_VIRTUAL
/*
* Vfb must be last to avoid that it becomes your primary display if
* other display devices are present
*/
{ "vfb", vfb_init, vfb_setup },
#endif
};
 
#define NUM_FB_DRIVERS (sizeof(fb_drivers)/sizeof(*fb_drivers))
#define FBPIXMAPSIZE 8192
 
extern const char *global_mode_option;
 
static initcall_t pref_init_funcs[FB_MAX];
static int num_pref_init_funcs __initdata = 0;
struct fb_info *registered_fb[FB_MAX];
int num_registered_fb;
 
#ifdef CONFIG_FB_OF
static int ofonly __initdata = 0;
#endif
 
/*
* Drawing helpers.
*/
u8 sys_inbuf(u8 *src)
{
return *src;
}
 
void sys_outbuf(u8 *src, u8 *dst, unsigned int size)
{
memcpy(dst, src, size);
}
 
void move_buf_aligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch,
u32 s_pitch, u32 height)
{
int i;
 
for (i = height; i--; ) {
info->pixmap.outbuf(src, dst, s_pitch);
src += s_pitch;
dst += d_pitch;
}
}
 
void move_buf_unaligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch,
u32 height, u32 mask, u32 shift_high, u32 shift_low,
u32 mod, u32 idx)
{
int i, j;
u8 tmp;
 
for (i = height; i--; ) {
for (j = 0; j < idx; j++) {
tmp = info->pixmap.inbuf(dst+j);
tmp &= mask;
tmp |= *src >> shift_low;
info->pixmap.outbuf(&tmp, dst+j, 1);
tmp = *src << shift_high;
info->pixmap.outbuf(&tmp, dst+j+1, 1);
src++;
}
tmp = info->pixmap.inbuf(dst+idx);
tmp &= mask;
tmp |= *src >> shift_low;
info->pixmap.outbuf(&tmp, dst+idx, 1);
if (shift_high < mod) {
tmp = *src << shift_high;
info->pixmap.outbuf(&tmp, dst+idx+1, 1);
}
src++;
dst += d_pitch;
}
}
 
/*
* we need to lock this section since fb_cursor
* may use fb_imageblit()
*/
u32 fb_get_buffer_offset(struct fb_info *info, u32 size)
{
u32 align = info->pixmap.buf_align - 1;
u32 offset, count = 1000;
 
spin_lock(&info->pixmap.lock);
offset = info->pixmap.offset + align;
offset &= ~align;
if (offset + size > info->pixmap.size) {
while (atomic_read(&info->pixmap.count) && count--);
if (info->fbops->fb_sync &&
info->pixmap.flags & FB_PIXMAP_SYNC)
info->fbops->fb_sync(info);
offset = 0;
}
info->pixmap.offset = offset + size;
atomic_inc(&info->pixmap.count);
smp_mb__after_atomic_inc();
spin_unlock(&info->pixmap.lock);
return offset;
}
 
#ifdef CONFIG_LOGO
#include <linux/linux_logo.h>
 
static inline unsigned safe_shift(unsigned d, int n)
{
return n < 0 ? d >> -n : d << n;
}
 
static void __init fb_set_logocmap(struct fb_info *info,
const struct linux_logo *logo)
{
struct fb_cmap palette_cmap;
u16 palette_green[16];
u16 palette_blue[16];
u16 palette_red[16];
int i, j, n;
const unsigned char *clut = logo->clut;
 
palette_cmap.start = 0;
palette_cmap.len = 16;
palette_cmap.red = palette_red;
palette_cmap.green = palette_green;
palette_cmap.blue = palette_blue;
palette_cmap.transp = NULL;
 
for (i = 0; i < logo->clutsize; i += n) {
n = logo->clutsize - i;
/* palette_cmap provides space for only 16 colors at once */
if (n > 16)
n = 16;
palette_cmap.start = 32 + i;
palette_cmap.len = n;
for (j = 0; j < n; ++j) {
palette_cmap.red[j] = clut[0] << 8 | clut[0];
palette_cmap.green[j] = clut[1] << 8 | clut[1];
palette_cmap.blue[j] = clut[2] << 8 | clut[2];
clut += 3;
}
fb_set_cmap(&palette_cmap, 1, info);
}
}
 
static void __init fb_set_logo_truepalette(struct fb_info *info,
const struct linux_logo *logo,
u32 *palette)
{
unsigned char mask[9] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff };
unsigned char redmask, greenmask, bluemask;
int redshift, greenshift, blueshift;
int i;
const unsigned char *clut = logo->clut;
 
/*
* We have to create a temporary palette since console palette is only
* 16 colors long.
*/
/* Bug: Doesn't obey msb_right ... (who needs that?) */
redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8];
greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8];
bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8];
redshift = info->var.red.offset - (8 - info->var.red.length);
greenshift = info->var.green.offset - (8 - info->var.green.length);
blueshift = info->var.blue.offset - (8 - info->var.blue.length);
 
for ( i = 0; i < logo->clutsize; i++) {
palette[i+32] = (safe_shift((clut[0] & redmask), redshift) |
safe_shift((clut[1] & greenmask), greenshift) |
safe_shift((clut[2] & bluemask), blueshift));
clut += 3;
}
}
 
static void __init fb_set_logo_directpalette(struct fb_info *info,
const struct linux_logo *logo,
u32 *palette)
{
int redshift, greenshift, blueshift;
int i;
 
redshift = info->var.red.offset;
greenshift = info->var.green.offset;
blueshift = info->var.blue.offset;
 
for (i = 32; i < logo->clutsize; i++)
palette[i] = i << redshift | i << greenshift | i << blueshift;
}
 
static void __init fb_set_logo(struct fb_info *info,
const struct linux_logo *logo, u8 *dst,
int depth)
{
int i, j, shift;
const u8 *src = logo->data;
u8 d, xor = 0;
 
switch (depth) {
case 4:
for (i = 0; i < logo->height; i++)
for (j = 0; j < logo->width; src++) {
*dst++ = *src >> 4;
j++;
if (j < logo->width) {
*dst++ = *src & 0x0f;
j++;
}
}
break;
case ~1:
xor = 0xff;
case 1:
for (i = 0; i < logo->height; i++) {
shift = 7;
d = *src++ ^ xor;
for (j = 0; j < logo->width; j++) {
*dst++ = (d >> shift) & 1;
shift = (shift-1) & 7;
if (shift == 7)
d = *src++ ^ xor;
}
}
break;
}
}
 
/*
* Three (3) kinds of logo maps exist. linux_logo_clut224 (>16 colors),
* linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors). Depending on
* the visual format and color depth of the framebuffer, the DAC, the
* pseudo_palette, and the logo data will be adjusted accordingly.
*
* Case 1 - linux_logo_clut224:
* Color exceeds the number of console colors (16), thus we set the hardware DAC
* using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set.
*
* For visuals that require color info from the pseudo_palette, we also construct
* one for temporary use. The "needs_directpalette" or "needs_truepalette" flags
* will be set.
*
* Case 2 - linux_logo_vga16:
* The number of colors just matches the console colors, thus there is no need
* to set the DAC or the pseudo_palette. However, the bitmap is packed, ie,
* each byte contains color information for two pixels (upper and lower nibble).
* To be consistent with fb_imageblit() usage, we therefore separate the two
* nibbles into separate bytes. The "depth" flag will be set to 4.
*
* Case 3 - linux_logo_mono:
* This is similar with Case 2. Each byte contains information for 8 pixels.
* We isolate each bit and expand each into a byte. The "depth" flag will
* be set to 1.
*/
static struct logo_data {
int depth;
int needs_directpalette;
int needs_truepalette;
int needs_cmapreset;
const struct linux_logo *logo;
} fb_logo;
 
int fb_prepare_logo(struct fb_info *info)
{
memset(&fb_logo, 0, sizeof(struct logo_data));
 
switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
if (info->var.bits_per_pixel >= 8)
fb_logo.needs_truepalette = 1;
break;
case FB_VISUAL_DIRECTCOLOR:
if (info->var.bits_per_pixel >= 24) {
fb_logo.needs_directpalette = 1;
fb_logo.needs_cmapreset = 1;
}
break;
case FB_VISUAL_PSEUDOCOLOR:
fb_logo.needs_cmapreset = 1;
break;
}
 
/* Return if no suitable logo was found */
fb_logo.logo = fb_find_logo(info->var.bits_per_pixel);
if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) {
fb_logo.logo = NULL;
return 0;
}
/* What depth we asked for might be different from what we get */
if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
fb_logo.depth = 8;
else if (fb_logo.logo->type == LINUX_LOGO_VGA16)
fb_logo.depth = 4;
else
fb_logo.depth = 1;
return fb_logo.logo->height;
}
 
int fb_show_logo(struct fb_info *info)
{
u32 *palette = NULL, *saved_pseudo_palette = NULL;
unsigned char *logo_new = NULL;
struct fb_image image;
int x;
 
/* Return if the frame buffer is not mapped */
if (fb_logo.logo == NULL)
return 0;
 
image.depth = fb_logo.depth;
image.data = fb_logo.logo->data;
 
if (fb_logo.needs_cmapreset)
fb_set_logocmap(info, fb_logo.logo);
 
if (fb_logo.needs_truepalette ||
fb_logo.needs_directpalette) {
palette = kmalloc(256 * 4, GFP_KERNEL);
if (palette == NULL)
return 0;
 
if (fb_logo.needs_truepalette)
fb_set_logo_truepalette(info, fb_logo.logo, palette);
else
fb_set_logo_directpalette(info, fb_logo.logo, palette);
 
saved_pseudo_palette = info->pseudo_palette;
info->pseudo_palette = palette;
}
 
if (fb_logo.depth == 4) {
logo_new = kmalloc(fb_logo.logo->width * fb_logo.logo->height,
GFP_KERNEL);
if (logo_new == NULL) {
if (palette)
kfree(palette);
if (saved_pseudo_palette)
info->pseudo_palette = saved_pseudo_palette;
return 0;
}
image.data = logo_new;
fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth);
}
 
image.width = fb_logo.logo->width;
image.height = fb_logo.logo->height;
image.dy = 0;
 
for (x = 0; x < num_online_cpus() * (fb_logo.logo->width + 8) &&
x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) {
image.dx = x;
info->fbops->fb_imageblit(info, &image);
//atomic_dec(&info->pixmap.count);
//smp_mb__after_atomic_dec();
}
if (palette != NULL)
kfree(palette);
if (saved_pseudo_palette != NULL)
info->pseudo_palette = saved_pseudo_palette;
if (logo_new != NULL)
kfree(logo_new);
return fb_logo.logo->height;
}
#else
int fb_prepare_logo(struct fb_info *info) { return 0; }
int fb_show_logo(struct fb_info *info) { return 0; }
#endif /* CONFIG_LOGO */
 
static int fbmem_read_proc(char *buf, char **start, off_t offset,
int len, int *eof, void *private)
{
struct fb_info **fi;
int clen;
 
clen = 0;
for (fi = registered_fb; fi < &registered_fb[FB_MAX] && len < 4000; fi++)
if (*fi)
clen += sprintf26(buf + clen, "%d %s\n",
(*fi)->node,
(*fi)->fix.id);
*start = buf + offset;
if (clen > offset)
clen -= offset;
else
clen = 0;
return clen < len ? clen : len;
}
 
static ssize_t
fb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
struct inode *inode = file->f_dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
 
if (!info || ! info->screen_base)
return -ENODEV;
 
if (info->fbops->fb_read)
return info->fbops->fb_read(file, buf, count, ppos);
if (p >= info->fix.smem_len)
return 0;
if (count >= info->fix.smem_len)
count = info->fix.smem_len;
if (count + p > info->fix.smem_len)
count = info->fix.smem_len - p;
if (info->fbops->fb_sync)
info->fbops->fb_sync(info);
if (count) {
char *base_addr;
 
base_addr = info->screen_base;
count -= copy_to_user(buf, base_addr+p, count);
if (!count)
return -EFAULT;
*ppos += count;
}
return count;
}
 
static ssize_t
fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
struct inode *inode = file->f_dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
int err;
 
if (!info || !info->screen_base)
return -ENODEV;
 
if (info->fbops->fb_write)
return info->fbops->fb_write(file, buf, count, ppos);
if (p > info->fix.smem_len)
return -ENOSPC;
if (count >= info->fix.smem_len)
count = info->fix.smem_len;
err = 0;
if (count + p > info->fix.smem_len) {
count = info->fix.smem_len - p;
err = -ENOSPC;
}
if (info->fbops->fb_sync)
info->fbops->fb_sync(info);
if (count) {
char *base_addr;
 
base_addr = info->screen_base;
count -= copy_from_user(base_addr+p, buf, count);
*ppos += count;
err = -EFAULT;
}
if (count)
return count;
return err;
}
 
#ifdef CONFIG_KMOD
static void try_to_load(int fb)
{
request_module("fb%d", fb);
}
#endif /* CONFIG_KMOD */
 
int
fb_cursor(struct fb_info *info, struct fb_cursor *sprite)
{
struct fb_cursor cursor;
int err;
if (copy_from_user(&cursor, sprite, sizeof(struct fb_cursor)))
return -EFAULT;
 
if (cursor.set & FB_CUR_SETCUR)
info->cursor.enable = 1;
if (cursor.set & FB_CUR_SETCMAP) {
err = fb_copy_cmap(&cursor.image.cmap, &sprite->image.cmap, 1);
if (err)
return err;
}
if (cursor.set & FB_CUR_SETSHAPE) {
int size = ((cursor.image.width + 7) >> 3) * cursor.image.height;
if ((cursor.image.height != info->cursor.image.height) ||
(cursor.image.width != info->cursor.image.width))
cursor.set |= FB_CUR_SETSIZE;
cursor.image.data = kmalloc(size, GFP_KERNEL);
if (!cursor.image.data)
return -ENOMEM;
cursor.mask = kmalloc(size, GFP_KERNEL);
if (!cursor.mask) {
kfree(cursor.image.data);
return -ENOMEM;
}
if (copy_from_user(&cursor.image.data, sprite->image.data, size) ||
copy_from_user(cursor.mask, sprite->mask, size)) {
kfree(cursor.image.data);
kfree(cursor.mask);
return -EFAULT;
}
}
info->cursor.set = cursor.set;
info->cursor.rop = cursor.rop;
err = info->fbops->fb_cursor(info, &cursor);
return err;
}
 
int
fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
{
int xoffset = var->xoffset;
int yoffset = var->yoffset;
int err;
 
if (xoffset < 0 || yoffset < 0 || !info->fbops->fb_pan_display ||
xoffset + info->var.xres > info->var.xres_virtual ||
yoffset + info->var.yres > info->var.yres_virtual)
return -EINVAL;
if ((err = info->fbops->fb_pan_display(var, info)))
return err;
info->var.xoffset = var->xoffset;
info->var.yoffset = var->yoffset;
if (var->vmode & FB_VMODE_YWRAP)
info->var.vmode |= FB_VMODE_YWRAP;
else
info->var.vmode &= ~FB_VMODE_YWRAP;
return 0;
}
 
int
fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
{
int err;
 
if (memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
if (!info->fbops->fb_check_var) {
*var = info->var;
return 0;
}
 
if ((err = info->fbops->fb_check_var(var, info)))
return err;
 
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
info->var = *var;
 
if (info->fbops->fb_set_par)
info->fbops->fb_set_par(info);
 
fb_pan_display(info, &info->var);
 
fb_set_cmap(&info->cmap, 1, info);
}
}
return 0;
}
 
int
fb_blank(struct fb_info *info, int blank)
{
/* ??? Variable sized stack allocation. */
u16 black[info->cmap.len];
struct fb_cmap cmap;
if (info->fbops->fb_blank && !info->fbops->fb_blank(blank, info))
return 0;
if (blank) {
memset(black, 0, info->cmap.len * sizeof(u16));
cmap.red = cmap.green = cmap.blue = black;
cmap.transp = info->cmap.transp ? black : NULL;
cmap.start = info->cmap.start;
cmap.len = info->cmap.len;
} else
cmap = info->cmap;
return fb_set_cmap(&cmap, 1, info);
}
 
static int
fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
struct fb_ops *fb = info->fbops;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
#ifdef CONFIG_FRAMEBUFFER_CONSOLE
struct fb_con2fbmap con2fb;
#endif
struct fb_cmap cmap;
int i;
if (!fb)
return -ENODEV;
switch (cmd) {
case FBIOGET_VSCREENINFO:
return copy_to_user((void *) arg, &info->var,
sizeof(var)) ? -EFAULT : 0;
case FBIOPUT_VSCREENINFO:
if (copy_from_user(&var, (void *) arg, sizeof(var)))
return -EFAULT;
i = fb_set_var(info, &var);
if (i) return i;
if (copy_to_user((void *) arg, &var, sizeof(var)))
return -EFAULT;
return 0;
case FBIOGET_FSCREENINFO:
return copy_to_user((void *) arg, &info->fix,
sizeof(fix)) ? -EFAULT : 0;
case FBIOPUTCMAP:
if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
return -EFAULT;
return (fb_set_cmap(&cmap, 0, info));
case FBIOGETCMAP:
if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
return -EFAULT;
return (fb_copy_cmap(&info->cmap, &cmap, 0));
case FBIOPAN_DISPLAY:
if (copy_from_user(&var, (void *) arg, sizeof(var)))
return -EFAULT;
if ((i = fb_pan_display(info, &var)))
return i;
if (copy_to_user((void *) arg, &var, sizeof(var)))
return -EFAULT;
return 0;
case FBIO_CURSOR:
return (fb_cursor(info, (struct fb_cursor *) arg));
#ifdef CONFIG_FRAMEBUFFER_CONSOLE
case FBIOGET_CON2FBMAP:
if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
return -EFAULT;
if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
return -EINVAL;
con2fb.framebuffer = con2fb_map[con2fb.console-1];
return copy_to_user((void *)arg, &con2fb,
sizeof(con2fb)) ? -EFAULT : 0;
case FBIOPUT_CON2FBMAP:
if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
return - EFAULT;
if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES)
return -EINVAL;
if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
return -EINVAL;
#ifdef CONFIG_KMOD
if (!registered_fb[con2fb.framebuffer])
try_to_load(con2fb.framebuffer);
#endif /* CONFIG_KMOD */
if (!registered_fb[con2fb.framebuffer])
return -EINVAL;
if (con2fb.console != 0)
set_con2fb_map(con2fb.console-1, con2fb.framebuffer);
else
fb_console_init();
return 0;
#endif /* CONFIG_FRAMEBUFFER_CONSOLE */
case FBIOBLANK:
return fb_blank(info, arg);
default:
if (fb->fb_ioctl == NULL)
return -EINVAL;
return fb->fb_ioctl(inode, file, cmd, arg, info);
}
}
 
static int
fb_mmap(struct file *file, struct vm_area_struct * vma)
{
int fbidx = iminor(file->f_dentry->d_inode);
struct fb_info *info = registered_fb[fbidx];
struct fb_ops *fb = info->fbops;
unsigned long off;
#if !defined(__sparc__) || defined(__sparc_v9__)
unsigned long start;
u32 len;
#endif
 
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
return -EINVAL;
off = vma->vm_pgoff << PAGE_SHIFT;
if (!fb)
return -ENODEV;
if (fb->fb_mmap) {
int res;
lock_kernel();
res = fb->fb_mmap(info, file, vma);
unlock_kernel();
return res;
}
 
#if defined(__sparc__) && !defined(__sparc_v9__)
/* Should never get here, all fb drivers should have their own
mmap routines */
return -EINVAL;
#else
/* !sparc32... */
lock_kernel();
 
/* frame buffer memory */
start = info->fix.smem_start;
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
if (off >= len) {
/* memory mapped io */
off -= len;
if (info->var.accel_flags) {
unlock_kernel();
return -EINVAL;
}
start = info->fix.mmio_start;
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
}
unlock_kernel();
start &= PAGE_MASK;
if ((vma->vm_end - vma->vm_start + off) > len)
return -EINVAL;
off += start;
vma->vm_pgoff = off >> PAGE_SHIFT;
/* This is an IO map - tell maydump to skip this VMA */
vma->vm_flags |= VM_IO;
#if defined(__sparc_v9__)
vma->vm_flags |= (VM_SHM | VM_LOCKED);
if (io_remap_page_range(vma, vma->vm_start, off,
vma->vm_end - vma->vm_start, vma->vm_page_prot, 0))
return -EAGAIN;
#else
#if defined(__mc68000__)
#if defined(CONFIG_SUN3)
pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
#elif defined(CONFIG_MMU)
if (CPU_IS_020_OR_030)
pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
if (CPU_IS_040_OR_060) {
pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
/* Use no-cache mode, serialized */
pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
}
#endif
#elif defined(__powerpc__)
pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
#elif defined(__alpha__)
/* Caching is off in the I/O space quadrant by design. */
#elif defined(__i386__) || defined(__x86_64__)
if (boot_cpu_data.x86 > 3)
pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
#elif defined(__mips__)
pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
#elif defined(__sh__)
pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
#elif defined(__hppa__)
pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
#elif defined(__ia64__) || defined(__arm__)
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
#else
#warning What do we have to do here??
#endif
if (io_remap_page_range(vma, vma->vm_start, off,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
#endif /* !__sparc_v9__ */
return 0;
#endif /* !sparc32 */
}
 
static int
fb_open(struct inode *inode, struct file *file)
{
int fbidx = iminor(inode);
struct fb_info *info;
int res = 0;
 
if (fbidx >= FB_MAX)
return -ENODEV;
#ifdef CONFIG_KMOD
if (!(info = registered_fb[fbidx]))
try_to_load(fbidx);
#endif /* CONFIG_KMOD */
if (!(info = registered_fb[fbidx]))
return -ENODEV;
if (!try_module_get(info->fbops->owner))
return -ENODEV;
if (info->fbops->fb_open) {
res = info->fbops->fb_open(info,1);
if (res)
module_put(info->fbops->owner);
}
return res;
}
 
static int
fb_release(struct inode *inode, struct file *file)
{
int fbidx = iminor(inode);
struct fb_info *info;
 
lock_kernel();
info = registered_fb[fbidx];
if (info->fbops->fb_release)
info->fbops->fb_release(info,1);
module_put(info->fbops->owner);
unlock_kernel();
return 0;
}
 
static struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.ioctl = fb_ioctl,
.mmap = fb_mmap,
.open = fb_open,
.release = fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
.get_unmapped_area = get_fb_unmapped_area,
#endif
};
 
/**
* register_framebuffer - registers a frame buffer device
* @fb_info: frame buffer info structure
*
* Registers a frame buffer device @fb_info.
*
* Returns negative errno on error, or zero for success.
*
*/
 
int
register_framebuffer(struct fb_info *fb_info)
{
int i;
 
if (num_registered_fb == FB_MAX)
return -ENXIO;
num_registered_fb++;
for (i = 0 ; i < FB_MAX; i++)
if (!registered_fb[i])
break;
fb_info->node = i;
if (fb_info->pixmap.addr == NULL) {
fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
if (fb_info->pixmap.addr) {
fb_info->pixmap.size = FBPIXMAPSIZE;
fb_info->pixmap.buf_align = 1;
fb_info->pixmap.scan_align = 1;
fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
}
}
fb_info->pixmap.offset = 0;
if (fb_info->pixmap.outbuf == NULL)
fb_info->pixmap.outbuf = sys_outbuf;
if (fb_info->pixmap.inbuf == NULL)
fb_info->pixmap.inbuf = sys_inbuf;
spin_lock_init(&fb_info->pixmap.lock);
 
registered_fb[i] = fb_info;
 
devfs_mk_cdev(MKDEV(FB_MAJOR, i),
S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i);
return 0;
}
 
 
/**
* unregister_framebuffer - releases a frame buffer device
* @fb_info: frame buffer info structure
*
* Unregisters a frame buffer device @fb_info.
*
* Returns negative errno on error, or zero for success.
*
*/
 
int
unregister_framebuffer(struct fb_info *fb_info)
{
int i;
 
i = fb_info->node;
if (!registered_fb[i])
return -EINVAL;
devfs_remove("fb/%d", i);
 
if (fb_info->pixmap.addr)
kfree(fb_info->pixmap.addr);
registered_fb[i]=NULL;
num_registered_fb--;
return 0;
}
 
 
/**
* fbmem_init - init frame buffer subsystem
*
* Initialize the frame buffer subsystem.
*
* NOTE: This function is _only_ to be called by drivers/char/mem.c.
*
*/
 
void __init
fbmem_init(void)
{
int i;
 
create_proc_read_entry("fb", 0, 0, fbmem_read_proc, NULL);
 
devfs_mk_dir("fb");
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
 
#ifdef CONFIG_FB_OF
if (ofonly) {
offb_init();
return;
}
#endif
 
/*
* Probe for all builtin frame buffer devices
*/
for (i = 0; i < num_pref_init_funcs; i++)
pref_init_funcs[i]();
 
for (i = 0; i < NUM_FB_DRIVERS; i++)
if (fb_drivers[i].init)
fb_drivers[i].init();
}
 
 
/**
* video_setup - process command line options
* @options: string of options
*
* Process command line options for frame buffer subsystem.
*
* NOTE: This function is a __setup and __init function.
*
* Returns zero.
*
*/
 
int __init video_setup(char *options)
{
int i, j;
 
if (!options || !*options)
return 0;
#ifdef CONFIG_FB_OF
if (!strcmp(options, "ofonly")) {
ofonly = 1;
return 0;
}
#endif
 
if (num_pref_init_funcs == FB_MAX)
return 0;
 
for (i = 0; i < NUM_FB_DRIVERS; i++) {
j = strlen(fb_drivers[i].name);
if (!strncmp(options, fb_drivers[i].name, j) &&
options[j] == ':') {
if (!strcmp(options+j+1, "off"))
fb_drivers[i].init = NULL;
else {
if (fb_drivers[i].init) {
pref_init_funcs[num_pref_init_funcs++] =
fb_drivers[i].init;
fb_drivers[i].init = NULL;
}
if (fb_drivers[i].setup)
fb_drivers[i].setup(options+j+1);
}
return 0;
}
}
 
/*
* If we get here no fb was specified.
* We consider the argument to be a global video mode option.
*/
global_mode_option = options;
return 0;
}
 
__setup("video=", video_setup);
 
/*
* Visible symbols for modules
*/
 
EXPORT_SYMBOL(register_framebuffer);
EXPORT_SYMBOL(unregister_framebuffer);
EXPORT_SYMBOL(num_registered_fb);
EXPORT_SYMBOL(registered_fb);
EXPORT_SYMBOL(fb_prepare_logo);
EXPORT_SYMBOL(fb_show_logo);
EXPORT_SYMBOL(fb_set_var);
EXPORT_SYMBOL(fb_blank);
EXPORT_SYMBOL(fb_pan_display);
EXPORT_SYMBOL(fb_get_buffer_offset);
EXPORT_SYMBOL(move_buf_unaligned);
EXPORT_SYMBOL(move_buf_aligned);
 
MODULE_LICENSE("GPL");
/shark/trunk/drivers/fb/vesafb.c
0,0 → 1,387
/*
* framebuffer driver for VBE 2.0 compliant graphic boards
*
* switching to graphics mode happens at boot time (while
* running in real mode, see arch/i386/boot/video.S).
*
* (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
*
*/
 
#include <linuxcomp.h>
 
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/ioport.h>
#include <linux/init.h>
#ifdef __i386__
#include <video/edid.h>
#endif
#include <asm/io.h>
#include <asm/mtrr.h>
 
#define dac_reg (0x3c8)
#define dac_val (0x3c9)
 
/* --------------------------------------------------------------------- */
 
static struct fb_var_screeninfo vesafb_defined __initdata = {
.activate = FB_ACTIVATE_NOW,
.height = -1,
.width = -1,
.right_margin = 32,
.upper_margin = 16,
.lower_margin = 4,
.vsync_len = 4,
.vmode = FB_VMODE_NONINTERLACED,
};
 
static struct fb_fix_screeninfo vesafb_fix __initdata = {
.id = "VESA VGA",
.type = FB_TYPE_PACKED_PIXELS,
.accel = FB_ACCEL_NONE,
};
 
static struct fb_info fb_info;
static u32 pseudo_palette[17];
 
static int inverse = 0;
static int mtrr = 1;
 
static int pmi_setpal = 0; /* pmi for palette changes ??? */
static int ypan = 0; /* 0..nothing, 1..ypan, 2..ywrap */
static unsigned short *pmi_base = 0;
static void (*pmi_start)(void);
static void (*pmi_pal)(void);
 
/* --------------------------------------------------------------------- */
 
static int vesafb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
#ifdef __i386__
int offset;
 
if (!ypan)
return -EINVAL;
if (var->xoffset)
return -EINVAL;
if (var->yoffset > var->yres_virtual)
return -EINVAL;
if ((ypan==1) && var->yoffset+var->yres > var->yres_virtual)
return -EINVAL;
 
offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4;
 
__asm__ __volatile__(
"call *(%%edi)"
: /* no return value */
: "a" (0x4f07), /* EAX */
"b" (0), /* EBX */
"c" (offset), /* ECX */
"d" (offset >> 16), /* EDX */
"D" (&pmi_start)); /* EDI */
#endif
return 0;
}
 
static void vesa_setpalette(int regno, unsigned red, unsigned green, unsigned blue)
{
#ifdef __i386__
struct { u_char blue, green, red, pad; } entry;
 
if (pmi_setpal) {
entry.red = red >> 10;
entry.green = green >> 10;
entry.blue = blue >> 10;
entry.pad = 0;
__asm__ __volatile__(
"call *(%%esi)"
: /* no return value */
: "a" (0x4f09), /* EAX */
"b" (0), /* EBX */
"c" (1), /* ECX */
"d" (regno), /* EDX */
"D" (&entry), /* EDI */
"S" (&pmi_pal)); /* ESI */
} else {
/* without protected mode interface, try VGA registers... */
outb_p(regno, dac_reg);
outb_p(red >> 10, dac_val);
outb_p(green >> 10, dac_val);
outb_p(blue >> 10, dac_val);
}
#endif
}
 
static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
/*
* Set a single color register. The values supplied are
* already rounded down to the hardware's capabilities
* (according to the entries in the `var' structure). Return
* != 0 for invalid regno.
*/
if (regno >= info->cmap.len)
return 1;
 
switch (info->var.bits_per_pixel) {
case 8:
vesa_setpalette(regno,red,green,blue);
break;
case 16:
if (info->var.red.offset == 10) {
/* 1:5:5:5 */
((u32*) (info->pseudo_palette))[regno] =
((red & 0xf800) >> 1) |
((green & 0xf800) >> 6) |
((blue & 0xf800) >> 11);
} else {
/* 0:5:6:5 */
((u32*) (info->pseudo_palette))[regno] =
((red & 0xf800) ) |
((green & 0xfc00) >> 5) |
((blue & 0xf800) >> 11);
}
break;
case 24:
red >>= 8;
green >>= 8;
blue >>= 8;
((u32 *)(info->pseudo_palette))[regno] =
(red << info->var.red.offset) |
(green << info->var.green.offset) |
(blue << info->var.blue.offset);
break;
case 32:
red >>= 8;
green >>= 8;
blue >>= 8;
((u32 *)(info->pseudo_palette))[regno] =
(red << info->var.red.offset) |
(green << info->var.green.offset) |
(blue << info->var.blue.offset);
break;
}
return 0;
}
 
static struct fb_ops vesafb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = vesafb_setcolreg,
.fb_pan_display = vesafb_pan_display,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_cursor = soft_cursor,
};
 
int __init vesafb_setup(char *options)
{
char *this_opt;
if (!options || !*options)
return 0;
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt) continue;
if (! strcmp(this_opt, "inverse"))
inverse=1;
else if (! strcmp(this_opt, "redraw"))
ypan=0;
else if (! strcmp(this_opt, "ypan"))
ypan=1;
else if (! strcmp(this_opt, "ywrap"))
ypan=2;
else if (! strcmp(this_opt, "vgapal"))
pmi_setpal=0;
else if (! strcmp(this_opt, "pmipal"))
pmi_setpal=1;
else if (! strcmp(this_opt, "mtrr"))
mtrr=1;
else if (! strcmp(this_opt, "nomtrr"))
mtrr=0;
}
return 0;
}
 
int __init vesafb_init(void)
{
int video_cmap_len;
int i;
 
if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB)
return -ENXIO;
 
vesafb_fix.smem_start = screen_info.lfb_base;
vesafb_defined.bits_per_pixel = screen_info.lfb_depth;
if (15 == vesafb_defined.bits_per_pixel)
vesafb_defined.bits_per_pixel = 16;
vesafb_defined.xres = screen_info.lfb_width;
vesafb_defined.yres = screen_info.lfb_height;
vesafb_fix.line_length = screen_info.lfb_linelength;
vesafb_fix.smem_len = screen_info.lfb_size * 65536;
vesafb_fix.visual = (vesafb_defined.bits_per_pixel == 8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
 
/* limit framebuffer size to 16 MB. Otherwise we'll eat tons of
* kernel address space for nothing if the gfx card has alot of
* memory (>= 128 MB isn't uncommon these days ...) */
if (vesafb_fix.smem_len > 16 * 1024 * 1024)
vesafb_fix.smem_len = 16 * 1024 * 1024;
 
#ifndef __i386__
screen_info.vesapm_seg = 0;
#endif
 
if (!request_mem_region(vesafb_fix.smem_start, vesafb_fix.smem_len, "vesafb")) {
printk(KERN_WARNING
"vesafb: abort, cannot reserve video memory at 0x%lx\n",
vesafb_fix.smem_start);
/* We cannot make this fatal. Sometimes this comes from magic
spaces our resource handlers simply don't know about */
}
 
fb_info.screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
if (!fb_info.screen_base) {
release_mem_region(vesafb_fix.smem_start, vesafb_fix.smem_len);
printk(KERN_ERR
"vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n",
vesafb_fix.smem_len, vesafb_fix.smem_start);
return -EIO;
}
 
printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
vesafb_fix.smem_start, fb_info.screen_base, vesafb_fix.smem_len/1024);
printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages);
 
if (screen_info.vesapm_seg) {
printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n",
screen_info.vesapm_seg,screen_info.vesapm_off);
}
 
if (screen_info.vesapm_seg < 0xc000)
ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
 
if (ypan || pmi_setpal) {
pmi_base = (unsigned short*)phys_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
pmi_pal = (void*)((char*)pmi_base + pmi_base[2]);
printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal);
if (pmi_base[3]) {
printk(KERN_INFO "vesafb: pmi: ports = ");
for (i = pmi_base[3]/2; pmi_base[i] != 0xffff; i++)
printk("%x ",pmi_base[i]);
printk("\n");
if (pmi_base[i] != 0xffff) {
/*
* memory areas not supported (yet?)
*
* Rules are: we have to set up a descriptor for the requested
* memory area and pass it in the ES register to the BIOS function.
*/
printk(KERN_INFO "vesafb: can't handle memory requests, pmi disabled\n");
ypan = pmi_setpal = 0;
}
}
}
 
vesafb_defined.xres_virtual = vesafb_defined.xres;
vesafb_defined.yres_virtual = vesafb_fix.smem_len / vesafb_fix.line_length;
if (ypan && vesafb_defined.yres_virtual > vesafb_defined.yres) {
printk(KERN_INFO "vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n",
(ypan > 1) ? "ywrap" : "ypan",vesafb_defined.yres_virtual);
} else {
printk(KERN_INFO "vesafb: scrolling: redraw\n");
vesafb_defined.yres_virtual = vesafb_defined.yres;
ypan = 0;
}
 
/* some dummy values for timing to make fbset happy */
vesafb_defined.pixclock = 10000000 / vesafb_defined.xres * 1000 / vesafb_defined.yres;
vesafb_defined.left_margin = (vesafb_defined.xres / 8) & 0xf8;
vesafb_defined.hsync_len = (vesafb_defined.xres / 8) & 0xf8;
if (vesafb_defined.bits_per_pixel > 8) {
vesafb_defined.red.offset = screen_info.red_pos;
vesafb_defined.red.length = screen_info.red_size;
vesafb_defined.green.offset = screen_info.green_pos;
vesafb_defined.green.length = screen_info.green_size;
vesafb_defined.blue.offset = screen_info.blue_pos;
vesafb_defined.blue.length = screen_info.blue_size;
vesafb_defined.transp.offset = screen_info.rsvd_pos;
vesafb_defined.transp.length = screen_info.rsvd_size;
printk(KERN_INFO "vesafb: directcolor: "
"size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
screen_info.rsvd_size,
screen_info.red_size,
screen_info.green_size,
screen_info.blue_size,
screen_info.rsvd_pos,
screen_info.red_pos,
screen_info.green_pos,
screen_info.blue_pos);
video_cmap_len = 16;
} else {
vesafb_defined.red.length = 6;
vesafb_defined.green.length = 6;
vesafb_defined.blue.length = 6;
video_cmap_len = 256;
}
 
vesafb_fix.ypanstep = ypan ? 1 : 0;
vesafb_fix.ywrapstep = (ypan>1) ? 1 : 0;
 
/* request failure does not faze us, as vgacon probably has this
* region already (FIXME) */
request_region(0x3c0, 32, "vesafb");
 
if (mtrr) {
int temp_size = vesafb_fix.smem_len;
/* Find the largest power-of-two */
while (temp_size & (temp_size - 1))
temp_size &= (temp_size - 1);
/* Try and find a power of two to add */
while (temp_size && mtrr_add(vesafb_fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) {
temp_size >>= 1;
}
}
fb_info.fbops = &vesafb_ops;
fb_info.var = vesafb_defined;
fb_info.fix = vesafb_fix;
fb_info.pseudo_palette = pseudo_palette;
fb_info.flags = FBINFO_FLAG_DEFAULT;
 
fb_alloc_cmap(&fb_info.cmap, video_cmap_len, 0);
 
if (register_framebuffer(&fb_info)<0)
return -EINVAL;
 
printk(KERN_INFO "fb%d: %s frame buffer device\n",
fb_info.node, fb_info.fix.id);
return 0;
}
 
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
* End:
*/
 
MODULE_LICENSE("GPL");
/shark/trunk/drivers/fb/makefile
0,0 → 1,23
# Frame Buffer Linux 2.6 Driver
 
ifndef BASE
BASE=../..
endif
 
include $(BASE)/config/config.mk
 
LIBRARY = fb
 
OBJS_PATH = $(BASE)/drivers/fb
 
OBJS = fbmem.o vesafb.o
 
OTHERINCL += -I$(BASE)/drivers/linuxc26/include
 
C_OPT += -D__KERNEL__ -D__i386__
 
include $(BASE)/config/lib.mk
 
clean::
rm -f $(OBJS)