📄 amifb.c
字号:
* Hardware limits for AGA: * * parameter min max step * --------- --- ---- ---- * diwstrt_h 0 2047 1 * diwstrt_v 0 2047 1 * diwstop_h 0 4095 1 * diwstop_v 0 4095 1 * * ddfstrt 0 2032 16 * ddfstop 0 2032 16 * * htotal 8 2048 8 * hsstrt 0 2040 8 * hsstop 0 2040 8 * vtotal 1 4096 1 * vsstrt 0 4095 1 * vsstop 0 4095 1 * hcenter 0 2040 8 * * hbstrt 0 2047 1 * hbstop 0 2047 1 * vbstrt 0 4095 1 * vbstop 0 4095 1 * * Horizontal values are in 35 ns (SHRES) pixels * Vertical values are in half scanlines *//* bplcon1 (smooth scrolling) */#define hscroll2hw(hscroll) \ (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \ ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f))/* diwstrt/diwstop/diwhigh (visible display window) */#define diwstrt2hw(diwstrt_h, diwstrt_v) \ (((diwstrt_v)<<7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff))#define diwstop2hw(diwstop_h, diwstop_v) \ (((diwstop_v)<<7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff))#define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \ (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \ ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \ ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007))/* ddfstrt/ddfstop (display DMA) */#define ddfstrt2hw(ddfstrt) div8(ddfstrt)#define ddfstop2hw(ddfstop) div8(ddfstop)/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */#define hsstrt2hw(hsstrt) (div8(hsstrt))#define hsstop2hw(hsstop) (div8(hsstop))#define htotal2hw(htotal) (div8(htotal)-1)#define vsstrt2hw(vsstrt) (div2(vsstrt))#define vsstop2hw(vsstop) (div2(vsstop))#define vtotal2hw(vtotal) (div2(vtotal)-1)#define hcenter2hw(htotal) (div8(htotal))/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */#define hbstrt2hw(hbstrt) (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff))#define hbstop2hw(hbstop) (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff))#define vbstrt2hw(vbstrt) (div2(vbstrt))#define vbstop2hw(vbstop) (div2(vbstop))/* colour */#define rgb2hw8_high(red, green, blue) \ (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4))#define rgb2hw8_low(red, green, blue) \ (((red & 0x0f)<<8) | ((green & 0x0f)<<4) | (blue & 0x0f))#define rgb2hw4(red, green, blue) \ (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4))#define rgb2hw2(red, green, blue) \ (((red & 0xc0)<<4) | (green & 0xc0) | ((blue & 0xc0)>>4))/* sprpos/sprctl (sprite positioning) */#define spr2hw_pos(start_v, start_h) \ (((start_v)<<7&0xff00) | ((start_h)>>3&0x00ff))#define spr2hw_ctl(start_v, start_h, stop_v) \ (((stop_v)<<7&0xff00) | ((start_v)>>4&0x0040) | ((stop_v)>>5&0x0020) | \ ((start_h)<<3&0x0018) | ((start_v)>>7&0x0004) | ((stop_v)>>8&0x0002) | \ ((start_h)>>2&0x0001))/* get current vertical position of beam */#define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe)) /* * Copper Initialisation List */#define COPINITSIZE (sizeof(copins)*40)enum { cip_bplcon0}; /* * Long Frame/Short Frame Copper List * Don't change the order, build_copper()/rebuild_copper() rely on this */#define COPLISTSIZE (sizeof(copins)*64)enum { cop_wait, cop_bplcon0, cop_spr0ptrh, cop_spr0ptrl, cop_diwstrt, cop_diwstop, cop_diwhigh,}; /* * Pixel modes for Bitplanes and Sprites */static u_short bplpixmode[3] = { BPC0_SHRES, /* 35 ns */ BPC0_HIRES, /* 70 ns */ 0 /* 140 ns */};static u_short sprpixmode[3] = { BPC3_SPRES1 | BPC3_SPRES0, /* 35 ns */ BPC3_SPRES1, /* 70 ns */ BPC3_SPRES0 /* 140 ns */}; /* * Fetch modes for Bitplanes and Sprites */static u_short bplfetchmode[3] = { 0, /* 1x */ FMODE_BPL32, /* 2x */ FMODE_BPAGEM | FMODE_BPL32 /* 4x */};static u_short sprfetchmode[3] = { 0, /* 1x */ FMODE_SPR32, /* 2x */ FMODE_SPAGEM | FMODE_SPR32 /* 4x */}; /* * Interface used by the world */int amifb_setup(char*);static int amifb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);static int amifb_set_par(struct fb_info *info);static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info);static int amifb_blank(int blank, struct fb_info *info);static int amifb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);static void amifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);static void amifb_copyarea(struct fb_info *info, const struct fb_copyarea *region);static void amifb_imageblit(struct fb_info *info, const struct fb_image *image);static int amifb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); /* * Interface to the low level console driver */static void amifb_deinit(void); /* * Internal routines */static int flash_cursor(void);static irqreturn_t amifb_interrupt(int irq, void *dev_id);static u_long chipalloc(u_long size);static void chipfree(void); /* * Hardware routines */static int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par);static int ami_encode_var(struct fb_var_screeninfo *var, struct amifb_par *par);static void ami_pan_var(struct fb_var_screeninfo *var);static int ami_update_par(void);static void ami_update_display(void);static void ami_init_display(void);static void ami_do_blank(void);static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix);static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data);static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data);static int ami_get_cursorstate(struct fb_cursorstate *state);static int ami_set_cursorstate(struct fb_cursorstate *state);static void ami_set_sprite(void);static void ami_init_copper(void);static void ami_reinit_copper(void);static void ami_build_copper(void);static void ami_rebuild_copper(void);static struct fb_ops amifb_ops = { .owner = THIS_MODULE, .fb_check_var = amifb_check_var, .fb_set_par = amifb_set_par, .fb_setcolreg = amifb_setcolreg, .fb_blank = amifb_blank, .fb_pan_display = amifb_pan_display, .fb_fillrect = amifb_fillrect, .fb_copyarea = amifb_copyarea, .fb_imageblit = amifb_imageblit, .fb_ioctl = amifb_ioctl,};static void __init amifb_setup_mcap(char *spec){ char *p; int vmin, vmax, hmin, hmax; /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax> * <V*> vertical freq. in Hz * <H*> horizontal freq. in kHz */ if (!(p = strsep(&spec, ";")) || !*p) return; vmin = simple_strtoul(p, NULL, 10); if (vmin <= 0) return; if (!(p = strsep(&spec, ";")) || !*p) return; vmax = simple_strtoul(p, NULL, 10); if (vmax <= 0 || vmax <= vmin) return; if (!(p = strsep(&spec, ";")) || !*p) return; hmin = 1000 * simple_strtoul(p, NULL, 10); if (hmin <= 0) return; if (!(p = strsep(&spec, "")) || !*p) return; hmax = 1000 * simple_strtoul(p, NULL, 10); if (hmax <= 0 || hmax <= hmin) return; fb_info.monspecs.vfmin = vmin; fb_info.monspecs.vfmax = vmax; fb_info.monspecs.hfmin = hmin; fb_info.monspecs.hfmax = hmax;}int __init amifb_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")) { amifb_inverse = 1; fb_invert_cmaps(); } else if (!strcmp(this_opt, "ilbm")) amifb_ilbm = 1; else if (!strncmp(this_opt, "monitorcap:", 11)) amifb_setup_mcap(this_opt+11); else if (!strncmp(this_opt, "fstart:", 7)) min_fstrt = simple_strtoul(this_opt+7, NULL, 0); else mode_option = this_opt; } if (min_fstrt < 48) min_fstrt = 48; return 0;}static int amifb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ int err; struct amifb_par par; /* Validate wanted screen parameters */ if ((err = ami_decode_var(var, &par))) return err; /* Encode (possibly rounded) screen parameters */ ami_encode_var(var, &par); return 0;}static int amifb_set_par(struct fb_info *info){ struct amifb_par *par = (struct amifb_par *)info->par; do_vmode_pan = 0; do_vmode_full = 0; /* Decode wanted screen parameters */ ami_decode_var(&info->var, par); /* Set new videomode */ ami_build_copper(); /* Set VBlank trigger */ do_vmode_full = 1; /* Update fix for new screen parameters */ if (par->bpp == 1) { info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.type_aux = 0; } else if (amifb_ilbm) { info->fix.type = FB_TYPE_INTERLEAVED_PLANES; info->fix.type_aux = par->next_line; } else { info->fix.type = FB_TYPE_PLANES; info->fix.type_aux = 0; } info->fix.line_length = div8(upx(16<<maxfmode, par->vxres)); if (par->vmode & FB_VMODE_YWRAP) { info->fix.ywrapstep = 1; info->fix.xpanstep = 0; info->fix.ypanstep = 0; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP | FBINFO_READS_FAST; /* override SCROLL_REDRAW */ } else { info->fix.ywrapstep = 0; if (par->vmode & FB_VMODE_SMOOTH_XPAN) info->fix.xpanstep = 1; else info->fix.xpanstep = 16<<maxfmode; info->fix.ypanstep = 1; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; } return 0;} /* * Pan or Wrap the Display * * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag */static int amifb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info){ if (var->vmode & FB_VMODE_YWRAP) { if (var->yoffset < 0 || var->yoffset >= info->var.yres_virtual || var->xoffset) return -EINVAL; } else { /* * TODO: There will be problems when xpan!=1, so some columns * on the right side will never be seen */ if (var->xoffset+info->var.xres > upx(16<<maxfmode, info->var.xres_virtual) || var->yoffset+info->var.yres > info->var.yres_virtual) return -EINVAL; } ami_pan_var(var); 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;}#if BITS_PER_LONG == 32#define BYTES_PER_LONG 4#define SHIFT_PER_LONG 5#elif BITS_PER_LONG == 64#define BYTES_PER_LONG 8#define SHIFT_PER_LONG 6#else#define Please update me#endif /* * Compose two values, using a bitmask as decision value * This is equivalent to (a & mask) | (b & ~mask) */static inline unsigned long comp(unsigned long a, unsigned long b, unsigned long mask){ return ((a ^ b) & mask) ^ b;}static inline unsigned long xor(unsigned long a, unsigned long b, unsigned long mask){ return (a & mask) ^ b;} /* * Unaligned forward bit copy using 32-bit or 64-bit memory accesses */static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, int src_idx, u32 n){ unsigned long first, last; int shift = dst_idx-src_idx, left, right; unsigned long d0, d1; int m; if (!n) return; shift = dst_idx-src_idx; first = ~0UL >> dst_idx; last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); if (!shift) { // Same alignment for source and dest if (dst_idx+n <= BITS_PER_LONG) { // Single word if (last) first &= last; *dst = comp(*src, *dst, first); } else { // Multiple destination words // Leading bits if (first) { *dst = comp(*src, *dst, first); dst++; src++; n -= BITS_PER_LONG-dst_idx; } // Main chunk n /= BITS_PER_LONG; while (n >= 8) { *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; *dst++ = *src++; n -= 8; } while (n--) *dst++ = *src++; // Trailing bits if (last) *dst = comp(*src, *dst, last); } } else { // Different alignment for source and dest right = shift & (BITS_PER_LONG-1); left = -shift & (BITS_PER_LONG-1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -