matroxfb_crtc2.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:23k
- /*
- *
- * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
- *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
- *
- * Version: 1.52 2001/05/25
- *
- */
- #include "matroxfb_maven.h"
- #include "matroxfb_crtc2.h"
- #include "matroxfb_misc.h"
- #include "matroxfb_DAC1064.h"
- #include <linux/matroxfb.h>
- #include <asm/uaccess.h>
- /* **************************************************** */
- static int mem = 8192;
- MODULE_PARM(mem, "i");
- MODULE_PARM_DESC(mem, "Memory size reserved for dualhead (default=8MB)");
- /* **************************************************** */
- static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green,
- unsigned *blue, unsigned *transp, struct fb_info* info) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- if (regno > 16)
- return 1;
- *red = m2info->palette[regno].red;
- *blue = m2info->palette[regno].blue;
- *green = m2info->palette[regno].green;
- *transp = m2info->palette[regno].transp;
- return 0;
- #undef m2info
- }
- static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp, struct fb_info* info) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- struct display* p;
- if (regno > 16)
- return 1;
- m2info->palette[regno].red = red;
- m2info->palette[regno].blue = blue;
- m2info->palette[regno].green = green;
- m2info->palette[regno].transp = transp;
- p = m2info->currcon_display;
- if (p->var.grayscale) {
- /* gray = 0.30*R + 0.59*G + 0.11*B */
- red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
- }
- red = CNVT_TOHW(red, p->var.red.length);
- green = CNVT_TOHW(green, p->var.green.length);
- blue = CNVT_TOHW(blue, p->var.blue.length);
- transp = CNVT_TOHW(transp, p->var.transp.length);
- switch (p->var.bits_per_pixel) {
- #ifdef FBCON_HAS_CFB16
- case 16:
- m2info->cmap.cfb16[regno] =
- (red << p->var.red.offset) |
- (green << p->var.green.offset) |
- (blue << p->var.blue.offset) |
- (transp << p->var.transp.offset);
- break;
- #endif
- #ifdef FBCON_HAS_CFB32
- case 32:
- m2info->cmap.cfb32[regno] =
- (red << p->var.red.offset) |
- (green << p->var.green.offset) |
- (blue << p->var.blue.offset) |
- (transp << p->var.transp.offset);
- break;
- #endif
- }
- return 0;
- #undef m2info
- }
- static void do_install_cmap(struct matroxfb_dh_fb_info* m2info, struct display* p) {
- if (p->cmap.len)
- fb_set_cmap(&p->cmap, 1, matroxfb_dh_setcolreg, &m2info->fbcon);
- else
- fb_set_cmap(fb_default_cmap(16), 1, matroxfb_dh_setcolreg, &m2info->fbcon);
- }
- static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
- struct my_timming* mt,
- struct display* p,
- int mode,
- unsigned int pos) {
- u_int32_t tmp;
- MINFO_FROM(m2info->primary_dev);
- switch (mode) {
- case 15:
- tmp = 0x00200000;
- break;
- case 16:
- tmp = 0x00400000;
- break;
- /* case 32: */
- default:
- tmp = 0x00800000;
- break;
- }
- if (ACCESS_FBINFO(output.sh)) {
- tmp |= 0x00000001; /* enable CRTC2 */
- if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
- if (ACCESS_FBINFO(devflags.g450dac)) {
- tmp |= 0x00000006; /* source from secondary pixel PLL */
- /* no vidrst */
- } else {
- tmp |= 0x00000002; /* source from VDOCLK */
- tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
- /* MGA TVO is our clock source */
- }
- } else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
- tmp |= 0x00000004; /* source from pixclock */
- /* PIXPLL is our clock source */
- }
- if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY)
- tmp |= 0x00100000; /* connect CRTC2 to DAC */
- }
- if (mt->interlaced) {
- tmp |= 0x02000000; /* interlaced, second field is bigger, as G450 apparently ignores it */
- mt->VDisplay >>= 1;
- mt->VSyncStart >>= 1;
- mt->VSyncEnd >>= 1;
- mt->VTotal >>= 1;
- }
- mga_outl(0x3C10, tmp | 0x10000000); /* depth and so on... 0x10000000 is VIDRST polarity */
- mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8));
- mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8));
- mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1));
- mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1));
- mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart)); /* preload */
- {
- u_int32_t linelen = p->var.xres_virtual * (p->var.bits_per_pixel >> 3);
- if (mt->interlaced) {
- /* field #0 is smaller, so... */
- mga_outl(0x3C2C, pos); /* field #1 vmemory start */
- mga_outl(0x3C28, pos + linelen); /* field #0 vmemory start */
- linelen <<= 1;
- } else {
- mga_outl(0x3C28, pos); /* vmemory start */
- }
- mga_outl(0x3C40, linelen);
- }
- tmp = 0x0FFF0000; /* line compare */
- if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
- tmp |= 0x00000100;
- if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
- tmp |= 0x00000200;
- mga_outl(0x3C44, tmp);
- mga_outl(0x3C4C, 0); /* data control */
- }
- static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info,
- struct display* p) {
- /* no acceleration for secondary head... */
- }
- static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info,
- struct fb_var_screeninfo* var) {
- unsigned int pos;
- unsigned int linelen;
- unsigned int pixelsize;
- #define minfo (m2info->primary_dev)
- pixelsize = var->bits_per_pixel >> 3;
- linelen = var->xres_virtual * pixelsize;
- pos = var->yoffset * linelen + var->xoffset * pixelsize;
- pos += m2info->video.offbase;
- if (var->vmode & FB_VMODE_INTERLACED) {
- mga_outl(0x3C2C, pos);
- mga_outl(0x3C28, pos + linelen);
- } else {
- mga_outl(0x3C28, pos);
- }
- #undef minfo
- }
- static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info,
- struct display* p,
- struct fb_var_screeninfo* var,
- int *visual,
- int *video_cmap_len,
- int *mode) {
- unsigned int mask;
- unsigned int memlen;
- unsigned int vramlen;
- switch (var->bits_per_pixel) {
- #ifdef FBCON_HAS_CFB16
- case 16: mask = 0x1F;
- break;
- #endif
- #ifdef FBCON_HAS_CFB32
- case 32: mask = 0x0F;
- break;
- #endif
- default: return -EINVAL;
- }
- vramlen = m2info->video.len_usable;
- if (var->yres_virtual < var->yres)
- var->yres_virtual = var->yres;
- if (var->xres_virtual < var->xres)
- var->xres_virtual = var->xres;
- var->xres_virtual = (var->xres_virtual + mask) & ~mask;
- if (var->yres_virtual > 32767)
- return -EINVAL;
- memlen = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel >> 3);
- if (memlen > vramlen)
- return -EINVAL;
- if (var->xoffset + var->xres > var->xres_virtual)
- var->xoffset = var->xres_virtual - var->xres;
- if (var->yoffset + var->yres > var->yres_virtual)
- var->yoffset = var->yres_virtual - var->yres;
- var->xres &= ~7;
- var->left_margin &= ~7;
- var->right_margin &= ~7;
- var->hsync_len &= ~7;
- *mode = var->bits_per_pixel;
- if (var->bits_per_pixel == 16) {
- if (var->green.length == 5) {
- var->red.offset = 10;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 5;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = 15;
- var->transp.length = 1;
- *mode = 15;
- } else {
- var->red.offset = 11;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = 0;
- var->transp.length = 0;
- }
- } else {
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 24;
- var->transp.length = 8;
- }
- *visual = FB_VISUAL_TRUECOLOR;
- *video_cmap_len = 16;
- return 0;
- }
- static void initMatroxDH(struct matroxfb_dh_fb_info* m2info, struct display* p) {
- switch (p->var.bits_per_pixel) {
- #ifdef FBCON_HAS_CFB16
- case 16:
- p->dispsw_data = m2info->cmap.cfb16;
- p->dispsw = &fbcon_cfb16;
- break;
- #endif
- #ifdef FBCON_HAS_CFB32
- case 32:
- p->dispsw_data = m2info->cmap.cfb32;
- p->dispsw = &fbcon_cfb32;
- break;
- #endif
- default:
- p->dispsw_data = NULL;
- p->dispsw = &fbcon_dummy;
- break;
- }
- }
- static int matroxfb_dh_open(struct fb_info* info, int user) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- MINFO_FROM(m2info->primary_dev);
- if (MINFO) {
- if (ACCESS_FBINFO(dead)) {
- return -ENXIO;
- }
- }
- return 0;
- #undef m2info
- }
- static int matroxfb_dh_release(struct fb_info* info, int user) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- MINFO_FROM(m2info->primary_dev);
- if (MINFO) {
- }
- return 0;
- #undef m2info
- }
- static int matroxfb_dh_get_fix(struct fb_fix_screeninfo* fix, int con,
- struct fb_info* info) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- struct display* p;
- if (con >= 0)
- p = fb_display + con;
- else
- p = m2info->fbcon.disp;
- memset(fix, 0, sizeof(*fix));
- strcpy(fix->id, "MATROX DH");
- fix->smem_start = m2info->video.base;
- fix->smem_len = m2info->video.len_usable;
- fix->type = p->type;
- fix->type_aux = p->type_aux;
- fix->visual = p->visual;
- fix->xpanstep = 8; /* TBD */
- fix->ypanstep = 1;
- fix->ywrapstep = 0;
- fix->line_length = p->line_length;
- fix->mmio_start = m2info->mmio.base;
- fix->mmio_len = m2info->mmio.len;
- fix->accel = 0; /* no accel... */
- return 0;
- #undef m2info
- }
- static int matroxfb_dh_get_var(struct fb_var_screeninfo* var, int con,
- struct fb_info* info) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- if (con < 0)
- *var = m2info->fbcon.disp->var;
- else
- *var = fb_display[con].var;
- return 0;
- #undef m2info
- }
- static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
- struct fb_info* info) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- struct display* p;
- int chgvar;
- int visual;
- int cmap_len;
- int mode;
- int err;
- MINFO_FROM(m2info->primary_dev);
- if (con < 0)
- p = m2info->fbcon.disp;
- else
- p = fb_display + con;
- if ((err = matroxfb_dh_decode_var(m2info, p, var, &visual, &cmap_len, &mode)) != 0)
- return err;
- switch (var->activate & FB_ACTIVATE_MASK) {
- case FB_ACTIVATE_TEST: return 0;
- case FB_ACTIVATE_NXTOPEN:
- case FB_ACTIVATE_NOW: break;
- default: return -EINVAL;
- }
- if (con >= 0) {
- chgvar = (p->var.xres != var->xres) ||
- (p->var.yres != var->yres) ||
- (p->var.xres_virtual != var->xres_virtual) ||
- (p->var.yres_virtual != var->yres_virtual) ||
- (p->var.bits_per_pixel != var->bits_per_pixel) ||
- memcmp(&p->var.red, &var->red, sizeof(var->red)) ||
- memcmp(&p->var.green, &var->green, sizeof(var->green)) ||
- memcmp(&p->var.blue, &var->blue, sizeof(var->blue));
- } else
- chgvar = 0;
- p->var = *var;
- /* cmap */
- p->screen_base = vaddr_va(m2info->video.vbase);
- p->visual = visual;
- p->ypanstep = 1;
- p->ywrapstep = 0;
- p->type = FB_TYPE_PACKED_PIXELS;
- p->type_aux = 0;
- p->next_line = p->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
- p->can_soft_blank = 0;
- p->inverse = 0; /* TBD */
- initMatroxDH(m2info, p);
- if (chgvar && info && info->changevar)
- info->changevar(con);
- if (con == m2info->currcon) {
- struct my_timming mt;
- struct matrox_hw_state* hw;
- struct matrox_hw_state* ohw;
- unsigned int pos;
- matroxfb_var2my(var, &mt);
- /* CRTC2 delay */
- mt.delay = 34;
- hw = ACCESS_FBINFO(newhw);
- ohw = ACCESS_FBINFO(currenthw);
- /* copy last setting... */
- memcpy(hw, ohw, sizeof(*hw));
- pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3;
- pos += m2info->video.offbase;
- DAC1064_global_init(PMINFO hw);
- if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
- if (ACCESS_FBINFO(primout))
- ACCESS_FBINFO(primout)->compute(MINFO, &mt, hw);
- }
- if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
- down_read(&ACCESS_FBINFO(altout.lock));
- if (ACCESS_FBINFO(altout.output))
- ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt, hw);
- up_read(&ACCESS_FBINFO(altout.lock));
- }
- matroxfb_dh_restore(m2info, &mt, p, mode, pos);
- DAC1064_global_restore(PMINFO hw);
- if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
- if (ACCESS_FBINFO(primout))
- ACCESS_FBINFO(primout)->program(MINFO, hw);
- }
- if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
- down_read(&ACCESS_FBINFO(altout.lock));
- if (ACCESS_FBINFO(altout.output))
- ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device), hw);
- up_read(&ACCESS_FBINFO(altout.lock));
- }
- if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
- if (ACCESS_FBINFO(primout))
- ACCESS_FBINFO(primout)->start(MINFO);
- }
- if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
- down_read(&ACCESS_FBINFO(altout.lock));
- if (ACCESS_FBINFO(altout.output))
- ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device));
- up_read(&ACCESS_FBINFO(altout.lock));
- }
- matroxfb_dh_cfbX_init(m2info, p);
- do_install_cmap(m2info, p);
- }
- return 0;
- #undef m2info
- }
- static int matroxfb_dh_get_cmap(struct fb_cmap* cmap, int kspc, int con,
- struct fb_info* info) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- struct display* dsp;
- if (con < 0)
- dsp = m2info->fbcon.disp;
- else
- dsp = fb_display + con;
- if (con == m2info->currcon)
- return fb_get_cmap(cmap, kspc, matroxfb_dh_getcolreg, info);
- else if (dsp->cmap.len)
- fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(16), cmap, kspc ? 0 : 2);
- return 0;
- #undef m2info
- }
- static int matroxfb_dh_set_cmap(struct fb_cmap* cmap, int kspc, int con,
- struct fb_info* info) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- struct display* dsp;
- if (con < 0)
- dsp = m2info->fbcon.disp;
- else
- dsp = fb_display + con;
- if (dsp->cmap.len != 16) {
- int err;
- err = fb_alloc_cmap(&dsp->cmap, 16, 0);
- if (err)
- return err;
- }
- if (con == m2info->currcon)
- return fb_set_cmap(cmap, kspc, matroxfb_dh_setcolreg, info);
- else
- fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
- return 0;
- #undef m2info
- }
- static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, int con,
- struct fb_info* info) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
- var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
- return -EINVAL;
- if (con == m2info->currcon)
- matroxfb_dh_pan_var(m2info, var);
- fb_display[con].var.xoffset = var->xoffset;
- fb_display[con].var.yoffset = var->yoffset;
- return 0;
- #undef m2info
- }
- static int matroxfb_dh_switch(int con, struct fb_info* info);
- static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info* m2info, struct fb_vblank* vblank) {
- MINFO_FROM(m2info->primary_dev);
- memset(vblank, 0, sizeof(*vblank));
- vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VBLANK;
- /* mask out reserved bits + field number (odd/even) */
- vblank->vcount = mga_inl(0x3C48) & 0x000007FF;
- /* compatibility stuff */
- if (vblank->vcount >= m2info->currcon_display->var.yres)
- vblank->flags |= FB_VBLANK_VBLANKING;
- return 0;
- }
- static int matroxfb_dh_ioctl(struct inode* inode,
- struct file* file,
- unsigned int cmd,
- unsigned long arg,
- int con,
- struct fb_info* info) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- MINFO_FROM(m2info->primary_dev);
- DBG("matroxfb_crtc2_ioctl")
- switch (cmd) {
- case FBIOGET_VBLANK:
- {
- struct fb_vblank vblank;
- int err;
- err = matroxfb_dh_get_vblank(m2info, &vblank);
- if (err)
- return err;
- if (copy_to_user((struct fb_vblank*)arg, &vblank, sizeof(vblank)))
- return -EFAULT;
- return 0;
- }
- case MATROXFB_SET_OUTPUT_MODE:
- case MATROXFB_GET_OUTPUT_MODE:
- case MATROXFB_GET_ALL_OUTPUTS:
- {
- return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(inode, file, cmd, arg, con, &ACCESS_FBINFO(fbcon));
- }
- case MATROXFB_SET_OUTPUT_CONNECTION:
- {
- u_int32_t tmp;
- if (get_user(tmp, (u_int32_t*)arg))
- return -EFAULT;
- if (tmp & ~ACCESS_FBINFO(output.all))
- return -EINVAL;
- if (tmp & ACCESS_FBINFO(output.ph))
- return -EINVAL;
- if (tmp & MATROXFB_OUTPUT_CONN_DFP)
- return -EINVAL;
- if ((ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) && tmp)
- return -EINVAL;
- if (tmp == ACCESS_FBINFO(output.sh))
- return 0;
- ACCESS_FBINFO(output.sh) = tmp;
- matroxfb_dh_switch(m2info->currcon, info);
- return 0;
- }
- case MATROXFB_GET_OUTPUT_CONNECTION:
- {
- if (put_user(ACCESS_FBINFO(output.sh), (u_int32_t*)arg))
- return -EFAULT;
- return 0;
- }
- case MATROXFB_GET_AVAILABLE_OUTPUTS:
- {
- u_int32_t tmp;
- /* we do not support DFP from CRTC2 */
- tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.ph) & ~MATROXFB_OUTPUT_CONN_DFP;
- /* CRTC1 in DFP mode disables CRTC2 at all (I know, I'm lazy) */
- if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
- tmp = 0;
- if (put_user(tmp, (u_int32_t*)arg))
- return -EFAULT;
- return 0;
- }
- }
- return -EINVAL;
- #undef m2info
- }
- static struct fb_ops matroxfb_dh_ops = {
- owner: THIS_MODULE,
- fb_open: matroxfb_dh_open,
- fb_release: matroxfb_dh_release,
- fb_get_fix: matroxfb_dh_get_fix,
- fb_get_var: matroxfb_dh_get_var,
- fb_set_var: matroxfb_dh_set_var,
- fb_get_cmap: matroxfb_dh_get_cmap,
- fb_set_cmap: matroxfb_dh_set_cmap,
- fb_pan_display: matroxfb_dh_pan_display,
- fb_ioctl: matroxfb_dh_ioctl,
- };
- static int matroxfb_dh_switch(int con, struct fb_info* info) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- struct fb_cmap* cmap;
- struct display* p;
- if (m2info->currcon >= 0) {
- cmap = &m2info->currcon_display->cmap;
- if (cmap->len) {
- fb_get_cmap(cmap, 1, matroxfb_dh_getcolreg, info);
- }
- }
- m2info->currcon = con;
- if (con < 0)
- p = m2info->fbcon.disp;
- else
- p = fb_display + con;
- m2info->currcon_display = p;
- p->var.activate = FB_ACTIVATE_NOW;
- matroxfb_dh_set_var(&p->var, con, info);
- return 0;
- #undef m2info
- }
- static int matroxfb_dh_updatevar(int con, struct fb_info* info) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- matroxfb_dh_pan_var(m2info, &fb_display[con].var);
- return 0;
- #undef m2info
- }
- static void matroxfb_dh_blank(int blank, struct fb_info* info) {
- #define m2info ((struct matroxfb_dh_fb_info*)info)
- switch (blank) {
- case 1:
- case 2:
- case 3:
- case 4:
- default:;
- }
- /* do something... */
- #undef m2info
- }
- static struct fb_var_screeninfo matroxfb_dh_defined = {
- 640,480,640,480,/* W,H, virtual W,H */
- 0,0, /* offset */
- 32, /* depth */
- 0, /* gray */
- {0,0,0}, /* R */
- {0,0,0}, /* G */
- {0,0,0}, /* B */
- {0,0,0}, /* alpha */
- 0, /* nonstd */
- FB_ACTIVATE_NOW,
- -1,-1, /* display size */
- 0, /* accel flags */
- 39721L,48L,16L,33L,10L,
- 96L,2,0, /* no sync info */
- FB_VMODE_NONINTERLACED,
- {0,0,0,0,0,0}
- };
- static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) {
- #define minfo (m2info->primary_dev)
- struct display* d;
- void* oldcrtc2;
- d = kmalloc(sizeof(*d), GFP_KERNEL);
- if (!d) {
- return -ENOMEM;
- }
- memset(d, 0, sizeof(*d));
- strcpy(m2info->fbcon.modename, "MATROX CRTC2");
- m2info->fbcon.changevar = NULL;
- m2info->fbcon.node = -1;
- m2info->fbcon.fbops = &matroxfb_dh_ops;
- m2info->fbcon.disp = d;
- m2info->fbcon.switch_con = &matroxfb_dh_switch;
- m2info->fbcon.updatevar = &matroxfb_dh_updatevar;
- m2info->fbcon.blank = &matroxfb_dh_blank;
- m2info->fbcon.flags = FBINFO_FLAG_DEFAULT;
- m2info->currcon = -1;
- m2info->currcon_display = d;
- if (mem < 64)
- mem *= 1024;
- if (mem < 64*1024)
- mem *= 1024;
- mem &= ~0x00000FFF; /* PAGE_MASK? */
- if (ACCESS_FBINFO(video.len_usable) + mem <= ACCESS_FBINFO(video.len))
- m2info->video.offbase = ACCESS_FBINFO(video.len) - mem;
- else if (ACCESS_FBINFO(video.len) < mem) {
- kfree(d);
- return -ENOMEM;
- } else { /* check yres on first head... */
- m2info->video.borrowed = mem;
- ACCESS_FBINFO(video.len_usable) -= mem;
- m2info->video.offbase = ACCESS_FBINFO(video.len_usable);
- }
- m2info->video.base = ACCESS_FBINFO(video.base) + m2info->video.offbase;
- m2info->video.len = m2info->video.len_usable = m2info->video.len_maximum = mem;
- m2info->video.vbase.vaddr = vaddr_va(ACCESS_FBINFO(video.vbase)) + m2info->video.offbase;
- m2info->mmio.base = ACCESS_FBINFO(mmio.base);
- m2info->mmio.vbase = ACCESS_FBINFO(mmio.vbase);
- m2info->mmio.len = ACCESS_FBINFO(mmio.len);
- /*
- * If we have unused output, connect CRTC2 to it...
- */
- if ((ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) &&
- !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) &&
- !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)) {
- ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY;
- ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP;
- }
- matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon);
- if (register_framebuffer(&m2info->fbcon)) {
- kfree(d);
- return -ENXIO;
- }
- if (m2info->currcon < 0) {
- matroxfb_dh_set_var(&matroxfb_dh_defined, -1, &m2info->fbcon);
- }
- down_write(&ACCESS_FBINFO(crtc2.lock));
- oldcrtc2 = ACCESS_FBINFO(crtc2.info);
- ACCESS_FBINFO(crtc2.info) = &m2info->fbcon;
- up_write(&ACCESS_FBINFO(crtc2.lock));
- if (oldcrtc2) {
- printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %pn",
- oldcrtc2);
- }
- return 0;
- #undef minfo
- }
- /* ************************** */
- static int matroxfb_dh_registerfb(struct matroxfb_dh_fb_info* m2info) {
- #define minfo (m2info->primary_dev)
- if (matroxfb_dh_regit(PMINFO m2info)) {
- printk(KERN_ERR "matroxfb_crtc2: secondary head failed to registern");
- return -1;
- }
- printk(KERN_INFO "matroxfb_crtc2: secondary head of fb%u was registered as fb%un",
- GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), GET_FB_IDX(m2info->fbcon.node));
- m2info->fbcon_registered = 1;
- return 0;
- #undef minfo
- }
- static void matroxfb_dh_deregisterfb(struct matroxfb_dh_fb_info* m2info) {
- #define minfo (m2info->primary_dev)
- if (m2info->fbcon_registered) {
- int id;
- struct fb_info* crtc2;
- down_write(&ACCESS_FBINFO(crtc2.lock));
- crtc2 = ACCESS_FBINFO(crtc2.info);
- if (crtc2 == &m2info->fbcon)
- ACCESS_FBINFO(crtc2.info) = NULL;
- up_write(&ACCESS_FBINFO(crtc2.lock));
- if (crtc2 != &m2info->fbcon) {
- printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %pn",
- crtc2, &m2info->fbcon);
- printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.n");
- return;
- }
- id = GET_FB_IDX(m2info->fbcon.node);
- unregister_framebuffer(&m2info->fbcon);
- kfree(m2info->fbcon.disp);
- /* return memory back to primary head */
- ACCESS_FBINFO(video.len_usable) += m2info->video.borrowed;
- printk(KERN_INFO "matroxfb_crtc2: fb%u unregisteredn", id);
- m2info->fbcon_registered = 0;
- }
- #undef minfo
- }
- static void* matroxfb_crtc2_probe(struct matrox_fb_info* minfo) {
- struct matroxfb_dh_fb_info* m2info;
- /* hardware is CRTC2 incapable... */
- if (!ACCESS_FBINFO(devflags.crtc2))
- return NULL;
- m2info = (struct matroxfb_dh_fb_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
- if (!m2info) {
- printk(KERN_ERR "matroxfb_crtc2: Not enough memory for CRTC2 control structsn");
- return NULL;
- }
- memset(m2info, 0, sizeof(*m2info));
- m2info->primary_dev = MINFO;
- if (matroxfb_dh_registerfb(m2info)) {
- kfree(m2info);
- printk(KERN_ERR "matroxfb_crtc2: CRTC2 framebuffer failed to registern");
- return NULL;
- }
- return m2info;
- }
- static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) {
- matroxfb_dh_deregisterfb(crtc2);
- }
- static struct matroxfb_driver crtc2 = {
- name: "Matrox G400 CRTC2",
- probe: matroxfb_crtc2_probe,
- remove: matroxfb_crtc2_remove };
- static int matroxfb_crtc2_init(void) {
- matroxfb_register_driver(&crtc2);
- return 0;
- }
- static void matroxfb_crtc2_exit(void) {
- matroxfb_unregister_driver(&crtc2);
- }
- MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
- MODULE_DESCRIPTION("Matrox G400 CRTC2 driver");
- MODULE_LICENSE("GPL");
- module_init(matroxfb_crtc2_init);
- module_exit(matroxfb_crtc2_exit);
- /* we do not have __setup() yet */