ep93xxfb.c
来自「非常珍贵的LINUX下的专门针对CIRRUS公司的EP93XX平台的驱动源代码」· C语言 代码 · 共 2,214 行 · 第 1/4 页
C
2,214 行
}#ifdef CONFIG_EP93XX_GRAPHICS#ifdef CONFIG_FB_EP93XX_8BPP#define BITS_PER_PIXEL 8#define BYTES_PER_PIXEL 1#define PIXEL_MASK 3#define PIXEL_SHIFT 2#define PIXEL_FORMAT 0x00040000#endif#ifdef CONFIG_FB_EP93XX_16BPP_565#define BITS_PER_PIXEL 16#define BYTES_PER_PIXEL 2#define PIXEL_MASK 1#define PIXEL_SHIFT 1#define PIXEL_FORMAT 0x00080000#endif#define BYTES_PER_LINE (fb_info.var.xres * BYTES_PER_PIXEL)static DECLARE_WAIT_QUEUE_HEAD(ep93xxfb_wait_in);static voidep93xxfb_irq_handler(int i, void *blah, struct pt_regs *regs){ outl(0x00000000, BLOCKCTRL); wake_up_interruptible(&ep93xxfb_wait_in);}static voidep93xxfb_wait(void){ DECLARE_WAITQUEUE(wait, current); add_wait_queue(&ep93xxfb_wait_in, &wait); current->state = TASK_INTERRUPTIBLE; while (inl(BLOCKCTRL) & 0x00000001) { schedule(); current->state = TASK_INTERRUPTIBLE; } remove_wait_queue(&ep93xxfb_wait_in, &wait); current->state = TASK_RUNNING;}static unsigned char pucBlitBuf[4096];static intep93xxfb_blit(struct ep93xx_blit *blit){ unsigned long value = 0, size, dx1, dx2, dy1, sx1, sx2, sy1; if ((blit->dx >= fb_info.var.xres) || (blit->dy >= fb_info.var.yres) || ((blit->dx + blit->width - 1) >= fb_info.var.xres) || ((blit->dy + blit->height - 1) >= fb_info.var.yres)) return -EFAULT; value = blit->flags & (BLIT_TRANSPARENT | BLIT_MASK_MASK | BLIT_DEST_MASK | BLIT_1BPP_SOURCE); if ((blit->flags & BLIT_SOURCE_MASK) == BLIT_SOURCE_MEMORY) { if (blit->flags & BLIT_1BPP_SOURCE) { size = blit->swidth * blit->height / 8; if (size <= 4096) copy_from_user(pucBlitBuf, blit->data, size); else { for (size = blit->height; size; ) { blit->height = 32768 / blit->swidth; if (blit->height > size) blit->height = size; ep93xxfb_blit(blit); blit->dy += blit->height; blit->data += blit->swidth * blit->height / 8; size -= blit->height; } return 0; } if (blit->flags & BLIT_TRANSPARENT) value ^= 0x00004000; outl(0x00000007, SRCPIXELSTRT); outl(blit->swidth >> 5, SRCLINELENGTH); outl((blit->width - 1) >> 5, BLKSRCWIDTH); outl(blit->bgcolor, BACKGROUND); } else { size = blit->swidth * blit->height * BYTES_PER_PIXEL; if (size <= 4096) copy_from_user(pucBlitBuf, blit->data, size); else { for (size = blit->height; size; ) { blit->height = 4096 / BYTES_PER_PIXEL / blit->swidth; if (blit->height > size) blit->height = size; ep93xxfb_blit(blit); blit->dy += blit->height; blit->data += blit->swidth * blit->height * BYTES_PER_PIXEL; size -= blit->height; } return 0; } outl(0x00000000, SRCPIXELSTRT); outl(blit->swidth >> PIXEL_SHIFT, SRCLINELENGTH); outl((blit->width - 1) >> PIXEL_SHIFT, BLKSRCWIDTH); } outl(virt_to_phys(pucBlitBuf), BLKSRCSTRT); dx1 = blit->dx; dy1 = blit->dy; dx2 = blit->dx + blit->width - 1; } else { if ((blit->sx >= fb_info.var.xres) || (blit->sy >= fb_info.var.yres) || ((blit->sx + blit->width - 1) >= fb_info.var.xres) || ((blit->sy + blit->height - 1) >= fb_info.var.yres)) return -EFAULT; if ((blit->dy == blit->sy) && (blit->dx == blit->sx)) return 0; if ((blit->dy == blit->sy) && (blit->dx > blit->sx) && (blit->dx < (blit->sx + blit->width - 1))) { dx1 = blit->dx + blit->width - 1; dx2 = blit->dx; sx1 = blit->sx + blit->width - 1; sx2 = blit->sx; value |= 0x000000a0; } else { dx1 = blit->dx; dx2 = blit->dx + blit->width - 1; sx1 = blit->sx; sx2 = blit->sx + blit->width - 1; } if (blit->dy <= blit->sy) { dy1 = blit->dy; sy1 = blit->sy; } else { dy1 = blit->dy + blit->height - 1; sy1 = blit->sy + blit->height - 1; value |= 0x00000140; } outl(((sx1 & PIXEL_MASK) * BITS_PER_PIXEL) | (((sx2 & PIXEL_MASK) * BITS_PER_PIXEL) << 16), SRCPIXELSTRT); outl(inl(VIDSCRNPAGE) + (sy1 * BYTES_PER_LINE) + ((sx1 * BYTES_PER_PIXEL) & ~PIXEL_MASK), BLKSRCSTRT); outl(BYTES_PER_LINE / 4, SRCLINELENGTH); if (sx1 < sx2) outl((sx2 >> PIXEL_SHIFT) - (sx1 >> PIXEL_SHIFT), BLKSRCWIDTH); else outl((sx1 >> PIXEL_SHIFT) - (sx2 >> PIXEL_SHIFT), BLKSRCWIDTH); } outl(((dx1 & PIXEL_MASK) * BITS_PER_PIXEL) | (((dx2 & PIXEL_MASK) * BITS_PER_PIXEL) << 16), DESTPIXELSTRT); outl(inl(VIDSCRNPAGE) + (dy1 * BYTES_PER_LINE) + ((dx1 * BYTES_PER_PIXEL) & ~PIXEL_MASK), BLKDSTSTRT); outl(BYTES_PER_LINE / 4, DESTLINELENGTH); if (dx1 < dx2) outl((dx2 >> PIXEL_SHIFT) - (dx1 >> PIXEL_SHIFT), BLKDESTWIDTH); else outl((dx1 >> PIXEL_SHIFT) - (dx2 >> PIXEL_SHIFT), BLKDESTWIDTH); outl(blit->height - 1, BLKDESTHEIGHT); outl(blit->fgcolor, BLOCKMASK); outl(blit->transcolor, TRANSPATTRN); outl(value | PIXEL_FORMAT | 0x00000003, BLOCKCTRL); ep93xxfb_wait(); return 0;}static intep93xxfb_fill(struct ep93xx_fill *fill){ if ((fill->dx >= fb_info.var.xres) || (fill->dy >= fb_info.var.yres)) return -EFAULT; if ((fill->dx + fill->width - 1) >= fb_info.var.xres) fill->width = fb_info.var.xres - fill->dx; if ((fill->dy + fill->height - 1) >= fb_info.var.yres) fill->height = fb_info.var.yres - fill->dy; outl(mypar.p_screen_base + (fill->dy * BYTES_PER_LINE) + ((fill->dx * BYTES_PER_PIXEL) & ~PIXEL_MASK), BLKDSTSTRT); outl(((fill->dx & PIXEL_MASK) * BITS_PER_PIXEL) | ((((fill->dx + fill->width - 1) & PIXEL_MASK) * BITS_PER_PIXEL) << 16), DESTPIXELSTRT); outl(BYTES_PER_LINE / 4, DESTLINELENGTH); outl(((fill->dx + fill->width - 1) >> PIXEL_SHIFT) - (fill->dx >> PIXEL_SHIFT), BLKDESTWIDTH); outl(fill->height - 1, BLKDESTHEIGHT); outl(fill->color, BLOCKMASK); outl(PIXEL_FORMAT | 0x0000000b, BLOCKCTRL); ep93xxfb_wait(); return 0;}static unsigned longisqrt(unsigned long a){ unsigned long rem = 0; unsigned long root = 0; int i; for (i = 0; i < 16; i++) { root <<= 1; rem = ((rem << 2) + (a >> 30)); a <<= 2; root++; if (root <= rem) { rem -= root; root++; } else root--; } return root >> 1;}static intep93xxfb_line(struct ep93xx_line *line){ unsigned long value = 0; long dx, dy, count, xinc, yinc, xval, yval, incr; if ((line->x1 >= fb_info.var.xres) || (line->x2 >= fb_info.var.xres) || (line->y1 >= fb_info.var.yres) || (line->y2 >= fb_info.var.yres)) return -EFAULT; dx = line->x2 - line->x1; if (dx < 0) { value |= 0x00000020; dx *= -1; } dy = line->y2 - line->y1; if (dy < 0) { value |= 0x00000040; dy *= -1; } if (line->flags & LINE_PRECISE) { count = isqrt(((dy * dy) + (dx * dx)) * 4096); xinc = (4095 * 64 * dx) / count; yinc = (4095 * 64 * dy) / count; xval = 2048; yval = 2048; count = 0; while (dx || dy) { incr = 0; xval -= xinc; if (xval <= 0) { xval += 4096; dx--; incr = 1; } yval -= yinc; if (yval <= 0) { yval += 4096; dy--; incr = 1; } count += incr; } } else { if (dx == dy) { xinc = 4095; yinc = 4095; count = dx; } else if (dx < dy) { xinc = (dx * 4095) / dy; yinc = 4095; count = dy; } else { xinc = 4095; yinc = (dy * 4095) / dx; count = dx; } } outl(0x08000800, LINEINIT); if (line->flags & LINE_PATTERN) outl(line->pattern, LINEPATTRN); else outl(0x000fffff, LINEPATTRN); outl(mypar.p_screen_base + (line->y1 * BYTES_PER_LINE) + ((line->x1 * BYTES_PER_PIXEL) & ~PIXEL_MASK), BLKDSTSTRT); outl(((line->x1 & PIXEL_MASK) * BITS_PER_PIXEL) | ((((line->x1 + dx - 1) & PIXEL_MASK) * BITS_PER_PIXEL) << 16), DESTPIXELSTRT); outl(BYTES_PER_LINE / 4, DESTLINELENGTH); outl(line->fgcolor, BLOCKMASK); outl(line->bgcolor, BACKGROUND); outl((yinc << 16) | xinc, LINEINC); outl(count & 0xfff, BLKDESTWIDTH); outl(0, BLKDESTHEIGHT); value |= (line->flags & LINE_BACKGROUND) ? 0x00004000 : 0; outl(value | PIXEL_FORMAT | 0x00000013, BLOCKCTRL); ep93xxfb_wait(); return 0;}#endifstatic intep93xxfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, int con, struct fb_info *info){ struct ep93xx_cursor cursor; struct ep93xx_blit blit; struct ep93xx_fill fill; struct ep93xx_line line; unsigned long caps; switch (cmd) { case FBIO_EP93XX_GET_CAPS: caps = EP93XX_CAP_CURSOR;#ifdef CONFIG_EP93XX_GRAPHICS caps |= EP93XX_CAP_LINE | EP93XX_CAP_FILL | EP93XX_CAP_BLIT;#endif copy_to_user((void *)arg, &caps, sizeof(unsigned long)); return 0; case FBIO_EP93XX_CURSOR: copy_from_user(&cursor, (void *)arg, sizeof(struct ep93xx_cursor)); ep93xxfb_cursor(&cursor); return 0;#ifdef CONFIG_EP93XX_GRAPHICS case FBIO_EP93XX_LINE: copy_from_user(&line, (void *)arg, sizeof(struct ep93xx_line)); return ep93xxfb_line(&line); case FBIO_EP93XX_FILL: copy_from_user(&fill, (void *)arg, sizeof(struct ep93xx_fill)); return ep93xxfb_fill(&fill); case FBIO_EP93XX_BLIT: copy_from_user(&blit, (void *)arg, sizeof(struct ep93xx_blit)); return ep93xxfb_blit(&blit);#endif default: return -EFAULT; }}//=============================================================================// CheckAdjustVar//=============================================================================// Check and adjust the video params in 'var'. If a value doesn't fit, round it// up, if it's too big, return -EINVAL.//// Suggestion: Round up in the following order: bits_per_pixel, xres, yres,// xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,// horizontal timing, vertical timing.//// Note: This is similar to generic fb call sequence// (decode_var, set_par, decode_var)// in that var gets fixed if fixable and error if not. The translating// to parameter settings is handled inside activate_var below.//=============================================================================static int CheckAdjustVar(struct fb_var_screeninfo *var){ DPRINTK("Entering\n"); // // Just set virtual to actual resolution. // var->xres_virtual = mypar.xres; var->yres_virtual = mypar.yres; DPRINTK("check: var->bpp=%d\n", var->bits_per_pixel); switch (var->bits_per_pixel) {#ifdef FBCON_HAS_CFB4 case 4: //TBD need to adjust var break;#endif#ifdef FBCON_HAS_CFB8 case 8: /* through palette */ var->red.length = 4; //TBD is this used? should be 8? //TBD what about offset? var->green = var->red; var->blue = var->red; var->transp.length = 0; break;#endif#ifdef FBCON_HAS_CFB16 case 16: /* RGB 565 */ var->red.length = 5; var->blue.length = 5; var->green.length = 6; var->transp.length = 0; var->red.offset = 11; var->green.offset = 5; var->blue.offset = 0; var->transp.offset = 0; break;#endif default: DPRINTK("Invalid var->bits_per_pixel = %d\n",var->bits_per_pixel); return -EINVAL; } return 0;}//// Entry: con valid console number// or -1 to indicate current console// (note: current console maybe default initially)//// var pointer to var structure already allocated by caller.//// Action: Set pointed at var structure to fb_display[con].var or current.//// Exit: none//// Note: This function called by fb_mem.c,static intep93xxfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ //TBD I do not expect call with con=-1 //TBD Maybe I do not really need to support this?? if (con == -1) DPRINTK("get_var called with con=-1\n"); DPRINTK("con=%d\n", con); if (con == -1) { //TBD need to set var with current settings. //TBD why can't we just take copy it from info?? //ep93xxfb_get_par(&par); //ep93xxfb_encode_var(var, &par); //TBD for now current settings is always equal to //TBD default display settings //TBD Is this really complete? *var = global_disp.var; // copies structure } else *var = fb_display[con].var; // copies structure return 0;}/* * ep93xxfb_set_var(): * * Entry: con -1 means set default display * else set fb_display[con] * * var static var structure to define video mode * * Action: Settings are tweaked to get a usable display mode. * Set console display values for specified console, * if console valid. Else set default display values. * * Exit: Returns error if cannot tweak settings to usable mode. */static intep93xxfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct display *display; int err, chgvar = 0; if (con == -1) DPRINTK("called with con=-1\n"); // // Display is not passed in, but we alter as side-effect // if (con >= 0) // // Display settings for console // display = &fb_display[con]; else // // Set default display settings // display = &global_disp; // // Check and adjust var if need be to get usable display mode, else return // error if impossible to adjust // if ((err = CheckAdjustVar(var))) return err; // Update parameters DPRINTK("check: var->bpp=%d\n", var->bits_per_pixel); switch (var->bits_per_pixel) {#ifdef FBCON_HAS_CFB4 case 4: mypar.visual = FB_VISUAL_PSEUDOCOLOR; mypar.palette_size = 16; break;#endif#ifdef FBCON_HAS_CFB8 case 8: mypar.visual = FB_VISUAL_PSEUDOCOLOR; mypar.palette_size = 256; break;#endif#ifdef FBCON_HAS_CFB16 case 16: mypar.visual = FB_VISUAL_TRUECOLOR; mypar.palette_size = 16; break;#endif default: DPRINTK("ERROR! Bad bpp %d\n", var->bits_per_pixel); return -EINVAL; } if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST) return 0; else if (((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) && ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NXTOPEN)) return -EINVAL; if (con >= 0) if ((display->var.xres != var->xres) || (display->var.yres != var->yres) || (display->var.xres_virtual != var->xres_virtual) || (display->var.yres_virtual != var->yres_virtual) || (display->var.sync != var->sync) || (display->var.bits_per_pixel != var->bits_per_pixel) || (memcmp(&display->var.red, &var->red, sizeof(var->red))) || (memcmp(&display->var.green, &var->green, sizeof(var->green))) || (memcmp(&display->var.blue, &var->blue, sizeof(var->blue)))) chgvar = 1; DPRINTK("display->var.xres %d\n",display->var.xres); DPRINTK("display->var.yres %d\n",display->var.yres); DPRINTK("display->var.xres_virtual %d\n",display->var.xres_virtual); DPRINTK("display->var.yres_virtual %d\n",display->var.yres_virtual); //TBD is this complete? display->var = *var; // copies structure display->screen_base = mypar.v_screen_base; display->visual = mypar.visual; display->type = FB_TYPE_PACKED_PIXELS;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?