📄 epson1356fb.c
字号:
writew(addr_offset, &dispmode->mem_addr_offset0); writeb(0, &dispmode->pixel_panning); // reset BitBlt engine e1356fb_engine_init(par, info);#ifdef E1356FB_VERBOSE_DEBUG dump_display_regs(dispcfg, dispmode);#endif /* clear out framebuffer memory */ fbfill(fb_info.membase_virt, 0, fb_info.fb_size); // finally, enable display! writeb(main_display_mode, &info->reg.misc->disp_mode); }static inte1356fb_verify_timing(struct e1356fb_par* par, const struct fb_info_e1356* info){ int disp_type = info->fix.disp_type; // timing boundary checks if (par->horiz_ndp > max_hndp[disp_type]) { DPRINTK("horiz_ndp too big: %d\n", par->horiz_ndp); return -EINVAL; } if (par->vert_ndp > max_vndp[disp_type]) { DPRINTK("vert_ndp too big: %d\n", par->vert_ndp); return -EINVAL; } if (disp_type != DISP_TYPE_LCD) { if (par->hsync_start > max_hsync_start[(par->bpp==16)][disp_type]) { DPRINTK("hsync_start too big: %d\n", par->hsync_start); return -EINVAL; } if (par->vsync_start > max_vsync_start[disp_type]) { DPRINTK("vsync_start too big: %d\n", par->vsync_start); return -EINVAL; } if (!IS_TV(disp_type)) { if (par->hsync_width > max_hsync_width[disp_type]) { DPRINTK("hsync_width too big: %d\n", par->hsync_width); return -EINVAL; } if (par->vsync_width > max_vsync_width[disp_type]) { DPRINTK("vsync_width too big: %d\n", par->vsync_width); return -EINVAL; } } } if (IS_TV(disp_type)) { int tv_pixclk = (disp_type == DISP_TYPE_NTSC) ? NTSC_PIXCLOCK : PAL_PIXCLOCK; if (info->fix.tv_filt & TV_FILT_FLICKER) tv_pixclk *= 2; if (par->ipclk.pixclk_d != tv_pixclk) { DPRINTK("invalid TV pixel clock %u kHz\n", par->ipclk.pixclk_d); return -EINVAL; } } if (e1356_calc_pixclock(info, &par->ipclk) < 0) { DPRINTK("can't set pixel clock %u kHz\n", par->ipclk.pixclk_d); return -EINVAL; } #ifdef E1356FB_VERBOSE_DEBUG DPRINTK("desired pixclock = %d kHz, actual = %d kHz, error = %d%%\n", par->ipclk.pixclk_d, par->ipclk.pixclk, par->ipclk.error);#endif if (disp_type != DISP_TYPE_LCD) { if (par->horiz_ndp < par->hsync_start + par->hsync_width) { DPRINTK("invalid horiz. timing\n"); return -EINVAL; } if (par->vert_ndp < par->vsync_start + par->vsync_width) { DPRINTK("invalid vert. timing\n"); return -EINVAL; } // SED1356 Hardware Functional Spec, section 13.5 if (disp_type == DISP_TYPE_NTSC && ((par->width + par->horiz_ndp != 910) || (par->height + 2*par->vert_ndp+1 != 525))) { DPRINTK("invalid NTSC timing\n"); return -EINVAL; } else if (disp_type == DISP_TYPE_PAL && ((par->width + par->horiz_ndp != 1135) || (par->height + 2*par->vert_ndp+1 != 625))) { DPRINTK("invalid PAL timing\n"); return -EINVAL; } } par->hsync_freq = (1000 * par->ipclk.pixclk) / (par->width + par->horiz_ndp); par->vsync_freq = par->hsync_freq / (par->height + par->vert_ndp); if (par->hsync_freq < 30000 || par->hsync_freq > 90000) { DPRINTK("hsync freq too %s: %u Hz\n", par->hsync_freq < 30000 ? "low" : "high", par->hsync_freq); return -EINVAL; } if (par->vsync_freq < 50 || par->vsync_freq > 110) { DPRINTK("vsync freq too %s: %u Hz\n", par->vsync_freq < 50 ? "low" : "high", par->vsync_freq); return -EINVAL; } return 0;}static inte1356fb_verify_par(struct e1356fb_par* par, const struct fb_info_e1356* info){ int disp_type = info->fix.disp_type; if (par->bpp != 8 && par->bpp != 16) { DPRINTK("depth not supported: %u bpp\n", par->bpp); return -EINVAL; } if (par->width > par->width_virt) { DPRINTK("virtual x resolution < physical x resolution not possible\n"); return -EINVAL; } if (par->height > par->height_virt) { DPRINTK("virtual y resolution < physical y resolution not possible\n"); return -EINVAL; } if (par->width < 320 || par->width > 1024) { DPRINTK("width not supported: %u\n", par->width); return -EINVAL; } if ((disp_type == DISP_TYPE_LCD && (par->width % 16)) || (disp_type == DISP_TYPE_TFT && (par->width % 8))) { DPRINTK("invalid width for panel type: %u\n", par->width); return -EINVAL; } if (par->height < 200 || par->height > 1024) { DPRINTK("height not supported: %u\n", par->height); return -EINVAL; } if (par->width_virt * par->height_virt * par->Bpp > info->fb_size) { DPRINTK("not enough memory for virtual screen (%ux%ux%u)\n", par->width_virt, par->height_virt, par->bpp); return -EINVAL; } return e1356fb_verify_timing(par, info);}static inte1356fb_var_to_par(const struct fb_var_screeninfo* var, struct e1356fb_par* par, const struct fb_info_e1356* info){ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { DPRINTK("interlace not supported\n"); return -EINVAL; } memset(par, 0, sizeof(struct e1356fb_par)); par->width = (var->xres + 15) & ~15; /* could sometimes be 8 */ par->width_virt = var->xres_virtual; par->height = var->yres; par->height_virt = var->yres_virtual; par->bpp = var->bits_per_pixel; par->Bpp = (par->bpp + 7) >> 3; par->ipclk.pixclk_d = PICOS2KHZ(var->pixclock); par->hsync_start = var->right_margin; par->hsync_width = var->hsync_len; par->vsync_start = var->lower_margin; par->vsync_width = var->vsync_len; par->horiz_ndp = var->left_margin + var->right_margin + var->hsync_len; par->vert_ndp = var->upper_margin + var->lower_margin + var->vsync_len; par->hsync_pol = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 1 : 0; par->vsync_pol = (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 1 : 0; par->cmap_len = (par->bpp == 8) ? 256 : 16; return e1356fb_verify_par(par, info);}static inte1356fb_par_to_var(struct fb_var_screeninfo* var, struct e1356fb_par* par, const struct fb_info_e1356* info){ struct fb_var_screeninfo v; int ret; // First, make sure par is valid. if ((ret = e1356fb_verify_par(par, info))) return ret; memset(&v, 0, sizeof(struct fb_var_screeninfo)); v.xres_virtual = par->width_virt; v.yres_virtual = par->height_virt; v.xres = par->width; v.yres = par->height; v.right_margin = par->hsync_start; v.hsync_len = par->hsync_width; v.left_margin = par->horiz_ndp - par->hsync_start - par->hsync_width; v.lower_margin = par->vsync_start; v.vsync_len = par->vsync_width; v.upper_margin = par->vert_ndp - par->vsync_start - par->vsync_width; v.bits_per_pixel = par->bpp; switch(par->bpp) { case 8: v.red.offset = v.green.offset = v.blue.offset = 0; v.red.length = v.green.length = v.blue.length = 4; break; case 16: v.red.offset = 11; v.red.length = 5; v.green.offset = 5; v.green.length = 6; v.blue.offset = 0; v.blue.length = 5; break; } v.height = v.width = -1; v.pixclock = KHZ2PICOS(par->ipclk.pixclk); if (par->hsync_pol) v.sync |= FB_SYNC_HOR_HIGH_ACT; if (par->vsync_pol) v.sync |= FB_SYNC_VERT_HIGH_ACT; *var = v; return 0;}static inte1356fb_encode_fix(struct fb_fix_screeninfo* fix, const struct e1356fb_par* par, const struct fb_info_e1356* info){ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "Epson SED1356"); fix->smem_start = info->fix.membase_phys; fix->smem_len = info->fb_size; fix->mmio_start = info->fix.regbase_phys; fix->mmio_len = info->regbase_size; fix->accel = FB_ACCEL_EPSON_SED1356; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; fix->line_length = par->width_virt * par->Bpp; fix->visual = (par->bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; fix->xpanstep = info->fix.nopan ? 0 : 1; fix->ypanstep = info->fix.nopan ? 0 : 1; fix->ywrapstep = 0; return 0;}static int e1356fb_open(struct fb_info *fb, int user){ struct fb_info_e1356 *info = (struct fb_info_e1356*)fb; if (user) { info->open++; } MOD_INC_USE_COUNT; return 0;}static int e1356fb_release(struct fb_info *fb, int user){ struct fb_info_e1356 *info = (struct fb_info_e1356*)fb; if (user && info->open) { info->open--; if (info->open == 0) info->mmaped = 0; } MOD_DEC_USE_COUNT; return 0;}static inte1356fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *fb){ const struct fb_info_e1356 *info = (struct fb_info_e1356*)fb; struct e1356fb_par par; //DPRINTK("\n"); if (con == -1) par = info->current_par; else e1356fb_var_to_par(&fb_display[con].var, &par, info); e1356fb_encode_fix(fix, &par, info); return 0;}static inte1356fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb){ struct fb_info_e1356 *info = (struct fb_info_e1356*)fb; //DPRINTK("\n"); if (con == -1) e1356fb_par_to_var(var, &info->current_par, info); else *var = fb_display[con].var; return 0;} static voide1356fb_set_dispsw(struct display *disp, struct fb_info_e1356 *info, int bpp, int accel){ struct e1356fb_fix* fix = &info->fix; //DPRINTK("\n"); if (disp->dispsw && disp->conp) fb_con.con_cursor(disp->conp, CM_ERASE); switch (bpp) {#ifdef FBCON_HAS_CFB8 case 8: disp->dispsw = fix->noaccel ? &fbcon_cfb8 : &fbcon_e1356_8; if (fix->nohwcursor) fbcon_e1356_8.cursor = NULL; break;#endif#ifdef FBCON_HAS_CFB16 case 16: disp->dispsw = fix->noaccel ? &fbcon_cfb16 : &fbcon_e1356_16; disp->dispsw_data = info->fbcon_cmap16; if (fix->nohwcursor) fbcon_e1356_16.cursor = NULL; break;#endif default: disp->dispsw = &fbcon_dummy; } }static inte1356fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb){ struct fb_info_e1356 *info = (struct fb_info_e1356*)fb; struct e1356fb_par par; struct display *display; int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err; int activate = var->activate; int j,k; DPRINTK("\n"); if (con >= 0) display = &fb_display[con]; else display = fb->disp; /* used during initialization */ if ((err = e1356fb_var_to_par(var, &par, info))) { struct fb_videomode *dm; /* * this mode didn't pass the tests. Try the * corresponding mode from our own modedb. */ DPRINTK("req mode failed, trying SED1356 %dx%d mode\n", var->xres, var->yres); if (e1356fb_get_mode(info, var->xres, var->yres, NULL, &dm) < 0) { DPRINTK("no SED1356 %dx%d mode found, failed\n", var->xres, var->yres); return err; } fb_videomode_to_var(dm, var); if ((err = e1356fb_var_to_par(var, &par, info))) { DPRINTK("SED1356 %dx%d mode failed\n", var->xres, var->yres); return err; } } if (info->fix.tv_filt & TV_FILT_FLICKER) printk("e1356fb: TV flicker filter enabled\n"); e1356fb_par_to_var(var, &par, info); if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { oldxres = display->var.xres; oldyres = display->var.yres; oldvxres = display->var.xres_virtual; oldvyres = display->var.yres_virtual; oldbpp = display->var.bits_per_pixel; oldaccel = display->var.accel_flags; display->var = *var; if (con < 0 || oldxres != var->xres || oldyres != var->yres || oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) { struct fb_fix_screeninfo fix; e1356fb_encode_fix(&fix, &par, info); display->screen_base = info->membase_virt; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; display->ypanstep = fix.ypanstep; display->ywrapstep = fix.ywrapstep; display->line_length = fix.line_length; display->next_line = fix.line_length; display->can_soft_blank = 1; display->inverse = 0; accel = var->accel_flags & FB_ACCELF_TEXT; e1356fb_set_dispsw(display, info, par.bpp, accel); if (info->fix.nopan) display->scrollmode = SCROLL_YREDRAW; if (info->fb_info.changevar) (*info->fb_info.changevar)(con); } if (var->bits_per_pixel==8) for(j = 0; j < 16; j++) { k = color_table[j]; fb_info.palette[j].red = default_red[k]; fb_info.palette[j].green = default_grn[k]; fb_info.palette[j].blue = default_blu[k]; } del_timer(&(info->cursor.timer)); fb_info.cursor.state=CM_ERASE; if (!info->fb_info.display_fg || info->fb_info.display_fg->vc_num == con || con < 0) e1356fb_set_par(&par, info); if (!info->fix.nohwcursor) if (display && display->conp) e1356fb_createcursor( display ); info->cursor.redraw = 1; if (oldbpp != var->bits_per_pixel || con < 0) { if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) return err;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -