📄 pm2fb.c
字号:
simple_strtoul(r, &q, 0); if (r == q) break; } if (i < 3) w = 0; } if (w) { for (r = q; *r && (*r < '0' || *r > '9'); r++); h = simple_strtoul(r, &q, 0); if (r == q) w = 0; } if (w == 640 && h == 480) w = 0; if (w) { for (i=0; user_mode[i].name[0] && (w != user_mode[i].par.width || h != user_mode[i].par.height); i++); if (user_mode[i].name[0]) memcpy(&p->current_par, &user_mode[i].par, sizeof(user_mode[i].par)); } } }#else if (pm2fb_options.flags & OPTF_VIRTUAL) { p->regions.rg_base = __pa(pci_resource_start(pci->dev, 0)); p->regions.fb_base = __pa(pci_resource_start(pci->dev, 1)); } else { p->regions.rg_base = pci_resource_start(pci->dev, 0); p->regions.fb_base = pci_resource_start(pci->dev, 1); }#endif#ifdef PM2FB_BE_APERTURE p->regions.rg_base += PM2_REGS_SIZE;#endif if ((m=MMAP(p->regions.rg_base, PM2_REGS_SIZE))) { pci->mem_control=RD32(m, PM2R_MEM_CONTROL); pci->boot_address=RD32(m, PM2R_BOOT_ADDRESS); pci->mem_config=RD32(m, PM2R_MEM_CONFIG); switch (pci->mem_config & PM2F_MEM_CONFIG_RAM_MASK) { case PM2F_MEM_BANKS_1: p->regions.fb_size=0x200000; break; case PM2F_MEM_BANKS_2: p->regions.fb_size=0x400000; break; case PM2F_MEM_BANKS_3: p->regions.fb_size=0x600000; break; case PM2F_MEM_BANKS_4: p->regions.fb_size=0x800000; break; } p->memclock=CVPPC_MEMCLOCK; UNMAP(m, PM2_REGS_SIZE); return 1; } DPRINTK("MMAP() failed.\n"); return 0;}static void pm2pci_init(struct pm2fb_info* p) { struct pm2pci_par* pci=&p->board_par.pci; WAIT_FIFO(p, 3); pm2_WR(p, PM2R_MEM_CONTROL, pci->mem_control); pm2_WR(p, PM2R_BOOT_ADDRESS, pci->boot_address); DEFW(); pm2_WR(p, PM2R_MEM_CONFIG, pci->mem_config);}#endif /* CONFIG_FB_PM2_PCI *//*************************************************************************** * Console hw acceleration ***************************************************************************/static int pm2fb_blank(int blank_mode, struct fb_info_gen* info) { struct pm2fb_info* i=(struct pm2fb_info* )info; u32 video; if (!i->current_par_valid) return 1; video=i->current_par.video; if (blank_mode>0) { switch (blank_mode-1) { case VESA_NO_BLANKING: /* FIXME */ video=video&~(PM2F_VIDEO_ENABLE); break; case VESA_HSYNC_SUSPEND: video=video&~(PM2F_HSYNC_MASK| PM2F_BLANK_LOW); break; case VESA_VSYNC_SUSPEND: video=video&~(PM2F_VSYNC_MASK| PM2F_BLANK_LOW); break; case VESA_POWERDOWN: video=video&~(PM2F_VSYNC_MASK| PM2F_HSYNC_MASK| PM2F_BLANK_LOW); break; } } WAIT_FIFO(i, 1); pm2_WR(i, PM2R_VIDEO_CONTROL, video); return 0;}static int pm2fb_pan_display(const struct fb_var_screeninfo* var, struct fb_info_gen* info) { struct pm2fb_info* i=(struct pm2fb_info* )info; if (!i->current_par_valid) return -EINVAL; i->current_par.base=to3264(var->yoffset*i->current_par.width+ var->xoffset, i->current_par.depth, 1); WAIT_FIFO(i, 1); pm2_WR(i, PM2R_SCREEN_BASE, i->current_par.base); return 0;}static void pm2fb_pp_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) { if (fontwidthlog(p)) { sx=sx<<fontwidthlog(p); dx=dx<<fontwidthlog(p); width=width<<fontwidthlog(p); } else { sx=sx*fontwidth(p); dx=dx*fontwidth(p); width=width*fontwidth(p); } sy=sy*fontheight(p); dy=dy*fontheight(p); height=height*fontheight(p); pm2fb_pp_copy((struct pm2fb_info* )p->fb_info, sx, sy, dx, dy, width, height);}static void pm2fb_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) { if (fontwidthlog(p)) { sx=sx<<fontwidthlog(p); dx=dx<<fontwidthlog(p); width=width<<fontwidthlog(p); } else { sx=sx*fontwidth(p); dx=dx*fontwidth(p); width=width*fontwidth(p); } sy=sy*fontheight(p); dy=dy*fontheight(p); height=height*fontheight(p); pm2fb_block_op((struct pm2fb_info* )p->fb_info, 1, sx, sy, dx, dy, width, height, 0);}#ifdef FBCON_HAS_CFB8static void pm2fb_clear8(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { u32 c; sx=sx*fontwidth(p); width=width*fontwidth(p); sy=sy*fontheight(p); height=height*fontheight(p); c=attr_bgcol_ec(p, conp); c|=c<<8; c|=c<<16; pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy, width, height, c);}static void pm2fb_clear_margins8(struct vc_data* conp, struct display* p, int bottom_only) { u32 c; u32 sx; u32 sy; c=attr_bgcol_ec(p, conp); c|=c<<8; c|=c<<16; sx=conp->vc_cols*fontwidth(p); sy=conp->vc_rows*fontheight(p); if (!bottom_only) pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, 0, (p->var.xres-sx), p->var.yres_virtual, c); pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, 0, p->var.yoffset+sy, sx, p->var.yres-sy, c);}static struct display_switch pm2_cfb8 = { setup: fbcon_cfb8_setup, bmove: pm2fb_pp_bmove,#ifdef __alpha__ /* Not sure why, but this works and the other does not. */ /* Also, perhaps we need a separate routine to wait for the blitter to stop before doing this? */ /* In addition, maybe we need to do this for 16 and 32 bit depths? */ clear: fbcon_cfb8_clear,#else clear: pm2fb_clear8,#endif putc: fbcon_cfb8_putc, putcs: fbcon_cfb8_putcs, revc: fbcon_cfb8_revc, cursor: pm2fb_cursor, set_font: pm2fb_set_font, clear_margins: pm2fb_clear_margins8, fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };#endif /* FBCON_HAS_CFB8 */#ifdef FBCON_HAS_CFB16static void pm2fb_clear16(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { u32 c; sx=sx*fontwidth(p); width=width*fontwidth(p); sy=sy*fontheight(p); height=height*fontheight(p); c=((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; c|=c<<16; pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy, width, height, c);}static void pm2fb_clear_margins16(struct vc_data* conp, struct display* p, int bottom_only) { u32 c; u32 sx; u32 sy; c = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; c|=c<<16; sx=conp->vc_cols*fontwidth(p); sy=conp->vc_rows*fontheight(p); if (!bottom_only) pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, 0, (p->var.xres-sx), p->var.yres_virtual, c); pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, 0, p->var.yoffset+sy, sx, p->var.yres-sy, c);}static struct display_switch pm2_cfb16 = { setup: fbcon_cfb16_setup, bmove: pm2fb_pp_bmove, clear: pm2fb_clear16, putc: fbcon_cfb16_putc, putcs: fbcon_cfb16_putcs, revc: fbcon_cfb16_revc, cursor: pm2fb_cursor, set_font: pm2fb_set_font, clear_margins: pm2fb_clear_margins16, fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)};#endif /* FBCON_HAS_CFB16 */#ifdef FBCON_HAS_CFB24/* * fast fill for 24bpp works only when red==green==blue */static void pm2fb_clear24(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info; u32 c; c=attr_bgcol_ec(p, conp); if ( i->palette[c].red==i->palette[c].green && i->palette[c].green==i->palette[c].blue) { c=((u32 *)p->dispsw_data)[c]; c|=(c&0xff0000)<<8; sx=sx*fontwidth(p); width=width*fontwidth(p); sy=sy*fontheight(p); height=height*fontheight(p); pm2fb_block_op(i, 0, 0, 0, sx, sy, width, height, c); } else fbcon_cfb24_clear(conp, p, sy, sx, height, width);}static void pm2fb_clear_margins24(struct vc_data* conp, struct display* p, int bottom_only) { struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info; u32 c; u32 sx; u32 sy; c=attr_bgcol_ec(p, conp); if ( i->palette[c].red==i->palette[c].green && i->palette[c].green==i->palette[c].blue) { c=((u32 *)p->dispsw_data)[c]; c|=(c&0xff0000)<<8; sx=conp->vc_cols*fontwidth(p); sy=conp->vc_rows*fontheight(p); if (!bottom_only) pm2fb_block_op(i, 0, 0, 0, sx, 0, (p->var.xres-sx), p->var.yres_virtual, c); pm2fb_block_op(i, 0, 0, 0, 0, p->var.yoffset+sy, sx, p->var.yres-sy, c); } else fbcon_cfb24_clear_margins(conp, p, bottom_only);}static struct display_switch pm2_cfb24 = { setup: fbcon_cfb24_setup, bmove: pm2fb_bmove, clear: pm2fb_clear24, putc: fbcon_cfb24_putc, putcs: fbcon_cfb24_putcs, revc: fbcon_cfb24_revc, cursor: pm2fb_cursor, set_font: pm2fb_set_font, clear_margins: pm2fb_clear_margins24, fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)};#endif /* FBCON_HAS_CFB24 */#ifdef FBCON_HAS_CFB32static void pm2fb_clear32(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { u32 c; sx=sx*fontwidth(p); width=width*fontwidth(p); sy=sy*fontheight(p); height=height*fontheight(p); c=((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy, width, height, c);}static void pm2fb_clear_margins32(struct vc_data* conp, struct display* p, int bottom_only) { u32 c; u32 sx; u32 sy; c = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; sx=conp->vc_cols*fontwidth(p); sy=conp->vc_rows*fontheight(p); if (!bottom_only) pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, 0, (p->var.xres-sx), p->var.yres_virtual, c); pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, 0, p->var.yoffset+sy, sx, p->var.yres-sy, c);}static struct display_switch pm2_cfb32 = { setup: fbcon_cfb32_setup, bmove: pm2fb_bmove, clear: pm2fb_clear32, putc: fbcon_cfb32_putc, putcs: fbcon_cfb32_putcs, revc: fbcon_cfb32_revc, cursor: pm2fb_cursor, set_font: pm2fb_set_font, clear_margins: pm2fb_clear_margins32, fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)};#endif /* FBCON_HAS_CFB32 *//*************************************************************************** * Framebuffer functions ***************************************************************************/static void pm2fb_detect(void) {}static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix, const void* par, struct fb_info_gen* info) { struct pm2fb_info* i=(struct pm2fb_info* )info; struct pm2fb_par* p=(struct pm2fb_par* )par; strcpy(fix->id, permedia2_name); fix->smem_start=i->regions.p_fb; fix->smem_len=i->regions.fb_size; fix->mmio_start=i->regions.p_regs; fix->mmio_len=PM2_REGS_SIZE; fix->accel=FB_ACCEL_3DLABS_PERMEDIA2; fix->type=FB_TYPE_PACKED_PIXELS; fix->visual=p->depth==8?FB_VISUAL_PSEUDOCOLOR:FB_VISUAL_TRUECOLOR; if (i->current_par_valid) fix->line_length=i->current_par.width*(i->current_par.depth/8); else fix->line_length=0; fix->xpanstep=p->depth==24?8:64/p->depth; fix->ypanstep=1; fix->ywrapstep=0; return 0;}#ifdef PM2FB_MASTER_DEBUGstatic void pm2fb_display_var(const struct fb_var_screeninfo* var) { printk( KERN_DEBUG"- struct fb_var_screeninfo ---------------------------------------------------\n"); printk( KERN_DEBUG "resolution: %ux%ux%u (virtual %ux%u+%u+%u)\n", var->xres, var->yres, var->bits_per_pixel, var->xres_virtual, var->yres_virtual, var->xoffset, var->yoffset); printk( KERN_DEBUG "color: %c%c " "R(%u,%u,%u), G(%u,%u,%u), B(%u,%u,%u), T(%u,%u,%u)\n", var->grayscale?'G':'C', var->nonstd?'N':'S', var->red.offset, var->red.length, var->red.msb_right, var->green.offset, var->green.length, var->green.msb_right, var->blue.offset, var->blue.length, var->blue.msb_right, var->transp.offset, var->transp.length, var->transp.msb_right); printk( KERN_DEBUG "timings: %ups (%u,%u)-(%u,%u)+%u+%u\n", var->pixclock, var->left_margin, var->upper_margin, var->right_margin, var->lower_margin, var->hsync_len, var->vsync_len); printk( KERN_DEBUG "activate %08x accel_flags %08x sync %08x vmode %08x\n", var->activate, var->accel_flags, var->sync, var->vmode); printk( KERN_DEBUG"------------------------------------------------------------------------------\n");}#define pm2fb_decode_var pm2fb_wrapped_decode_var#endifstatic int pm2fb_decode_var(const struct fb_var_screeninfo* var, void* par, struct fb_info_gen* info) { struct pm2fb_info* i=(struct pm2fb_info* )info; struct pm2fb_par p; u32 xres; int data64; memset(&p, 0, sizeof(struct pm2fb_par)); p.width=(var->xres_virtual+7)&~7; p.height=var->yres_virtual; p.depth=(var->bits_per_pixel+7)&~7; p.depth=p.depth>32?32:p.depth; data64=p.depth>8 || i->type == PM2_TYPE_PERMEDIA2V; xres=(var->xres+31)&~31; if (p.width<xres+var->xoffset) p.width=xres+var->xoffset; if (p.height<var->yres+var->yoffset) p.height=var->yres+var->yoffset; if (!partprod(xres)) { DPRINTK("width not supported: %u\n", xres); return -EINVAL; } if (p.width>2047) { DPRINTK("virtual width not supported: %u\n", p.width); return -EINVAL; } if (var->yres<200) { DPRINTK("height not supported: %u\n", (u32 )var->yres); return -EINVAL; } if (p.height<200 || p.height>2047) { DPRINTK("virtual height not supported: %u\n", p.height); return -EINVAL; } if (p.depth>32) { DPRINTK("depth not supported: %u\n", p.depth); return -EINVAL; } if (p.width*p.height*p.depth/8>i->regions.fb_size) { DPRINTK("no memory for screen (%ux%ux%u)\n", p.width, p.height, p.depth); return -EINVAL; } p.pixclock=PICOS2KHZ(var->pixclock); if (p.pixclock>PM2_MAX_PIXCLOCK) { DPRINTK("pixclock too high (%uKHz)\n", p.pixclock); return -EINVAL; } p.hsstart=to3264(var->right_margin, p.depth, data64); p.hsend=p.hsstart+to3264(var->hsync_len, p.depth, data64); p.hbend=p.hsend+to3264(var->left_margin, p.depth, data64); p.htotal=to3264(xres, p.depth, data64)+p.hbend-1; p.vsstart=var->lower_margin?var->lower_margin-1:0; /* FIXME! */ p.vsend=var->lower_margin+var->vsync_len-1; p.vbend=var->lower_margin+var->vsync_len+var->upper_margin; p.vtotal=var->yres+p.vbend-1; p.stride=to3264(p.width, p.depth, 1); p.base=to3264(var->yoffset*xres+var->xoffset, p.depth, 1); if (data64) p.video|=PM2F_DATA_64_ENABLE; if (var->sync & FB_SYNC_HOR_HIGH_ACT) p.video|=PM2F_HSYNC_ACT_HIGH; else p.video|=PM2F_HSYNC_ACT_LOW; if (var->sync & FB_SYNC_VERT_HIGH_ACT) p.video|=PM2F_VSYNC_ACT_HIGH; else p.video|=PM2F_VSYNC_ACT_LOW; if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) { DPRINTK("interlaced not supported\n"); return -EINVAL; } if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE) p.video|=PM2F_LINE_DOUBLE; if (var->activate==FB_ACTIVATE_NOW) p.video|=PM2F_VIDEO_ENABLE; *((struct pm2fb_par* )par)=p; return 0;}#ifdef PM2FB_MASTER_DEBUG#undef pm2fb_decode_varstatic int pm2fb_decode_var(const struct fb_var_screeninfo* var, void* par, struct fb_info_gen* info) { int result; result=pm2fb_wrapped_decode_var(var, par, info); pm2fb_display_var(var); return result;}#endifstatic int pm2fb_encode_var(struct fb_var_screeninfo* var, const void* par, struct fb_info_gen* info) { struct pm2fb_par* p=(struct pm2fb_par* )par; struct fb_var_screeninfo v; u32 base; memset(&v, 0, sizeof(struct fb_var_screeninfo)); v.xres_virtual=p->width; v.yres_virtual=p->height; v.xres=(p->htotal+1)-p->hbend; v.yres=(p->vtotal+1)-p->vbend; v.right_margin=p->hsstart; v.hsync_len=p->hsend-p->hsstart; v.left_margin=p->hbend-p->hsend; v.lower_margin=p->vsstart+1; v.vsync_len=p->vsend-v.lower_margin+1; v.upper_margin=p->vbend-v.lower_margin-v.vsync_len; v.bits_per_pixel=p->depth;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -