fbdev: move FBIO_WAITFORVSYNC to linux/fb.h
[safe/jmp/linux-2.6] / drivers / video / neofb.c
index a2e201d..588527a 100644 (file)
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/mm.h>
-#include <linux/tty.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 #ifdef CONFIG_TOSHIBA
 #include <linux/toshiba.h>
-extern int tosh_smm(SMMRegisters *regs);
 #endif
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
-#include <asm/uaccess.h>
 
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
@@ -165,20 +161,20 @@ static int neoFindMode(int xres, int yres, int depth)
 
        switch (depth) {
        case 8:
-               size = sizeof(bios8) / sizeof(biosMode);
+               size = ARRAY_SIZE(bios8);
                mode = bios8;
                break;
        case 16:
-               size = sizeof(bios16) / sizeof(biosMode);
+               size = ARRAY_SIZE(bios16);
                mode = bios16;
                break;
        case 24:
-               size = sizeof(bios24) / sizeof(biosMode);
+               size = ARRAY_SIZE(bios24);
                mode = bios24;
                break;
 #ifdef NO_32BIT_SUPPORT_YET
        case 32:
-               size = sizeof(bios32) / sizeof(biosMode);
+               size = ARRAY_SIZE(bios32);
                mode = bios32;
                break;
 #endif
@@ -205,7 +201,6 @@ static int neoFindMode(int xres, int yres, int depth)
  *
  * Determine the closest clock frequency to the one requested.
  */
-#define REF_FREQ 0xe517                /* 14.31818 in 20.12 fixed point */
 #define MAX_N 127
 #define MAX_D 31
 #define MAX_F 1
@@ -215,27 +210,24 @@ static void neoCalcVCLK(const struct fb_info *info,
 {
        int n, d, f;
        int n_best = 0, d_best = 0, f_best = 0;
-       long f_best_diff = (0x7ffff << 12);     /* 20.12 */
-       long f_target = (freq << 12) / 1000;    /* 20.12 */
+       long f_best_diff = 0x7ffff;
 
        for (f = 0; f <= MAX_F; f++)
-               for (n = 0; n <= MAX_N; n++)
-                       for (d = 0; d <= MAX_D; d++) {
-                               long f_out;     /* 20.12 */
-                               long f_diff;    /* 20.12 */
-
-                               f_out =
-                                   ((((n + 1) << 12) / ((d +
-                                                         1) *
-                                                        (1 << f))) >> 12)
-                                   * REF_FREQ;
-                               f_diff = abs(f_out - f_target);
-                               if (f_diff < f_best_diff) {
+               for (d = 0; d <= MAX_D; d++)
+                       for (n = 0; n <= MAX_N; n++) {
+                               long f_out;
+                               long f_diff;
+
+                               f_out = ((14318 * (n + 1)) / (d + 1)) >> f;
+                               f_diff = abs(f_out - freq);
+                               if (f_diff <= f_best_diff) {
                                        f_best_diff = f_diff;
                                        n_best = n;
                                        d_best = d;
                                        f_best = f;
                                }
+                               if (f_out > freq)
+                                       break;
                        }
 
        if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
@@ -252,11 +244,11 @@ static void neoCalcVCLK(const struct fb_info *info,
        par->VCLK3Denominator = d_best;
 
 #ifdef NEOFB_DEBUG
-       printk("neoVCLK: f:%d NumLow=%d NumHi=%d Den=%d Df=%d\n",
-              f_target >> 12,
+       printk(KERN_DEBUG "neoVCLK: f:%ld NumLow=%d NumHi=%d Den=%d Df=%ld\n",
+              freq,
               par->VCLK3NumeratorLow,
               par->VCLK3NumeratorHigh,
-              par->VCLK3Denominator, f_best_diff >> 12);
+              par->VCLK3Denominator, f_best_diff);
 #endif
 }
 
@@ -267,15 +259,20 @@ static void neoCalcVCLK(const struct fb_info *info,
  */
 
 static int vgaHWInit(const struct fb_var_screeninfo *var,
-                    const struct fb_info *info,
-                    struct neofb_par *par, struct xtimings *timings)
+                    struct neofb_par *par)
 {
+       int hsync_end = var->xres + var->right_margin + var->hsync_len;
+       int htotal = (hsync_end + var->left_margin) >> 3;
+       int vsync_start = var->yres + var->lower_margin;
+       int vsync_end = vsync_start + var->vsync_len;
+       int vtotal = vsync_end + var->upper_margin;
+
        par->MiscOutReg = 0x23;
 
-       if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
+       if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
                par->MiscOutReg |= 0x40;
 
-       if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
+       if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
                par->MiscOutReg |= 0x80;
 
        /*
@@ -290,25 +287,25 @@ static int vgaHWInit(const struct fb_var_screeninfo *var,
        /*
         * CRTC Controller
         */
-       par->CRTC[0] = (timings->HTotal >> 3) - 5;
-       par->CRTC[1] = (timings->HDisplay >> 3) - 1;
-       par->CRTC[2] = (timings->HDisplay >> 3) - 1;
-       par->CRTC[3] = (((timings->HTotal >> 3) - 1) & 0x1F) | 0x80;
-       par->CRTC[4] = (timings->HSyncStart >> 3);
-       par->CRTC[5] = ((((timings->HTotal >> 3) - 1) & 0x20) << 2)
-           | (((timings->HSyncEnd >> 3)) & 0x1F);
-       par->CRTC[6] = (timings->VTotal - 2) & 0xFF;
-       par->CRTC[7] = (((timings->VTotal - 2) & 0x100) >> 8)
-           | (((timings->VDisplay - 1) & 0x100) >> 7)
-           | ((timings->VSyncStart & 0x100) >> 6)
-           | (((timings->VDisplay - 1) & 0x100) >> 5)
-           | 0x10 | (((timings->VTotal - 2) & 0x200) >> 4)
-           | (((timings->VDisplay - 1) & 0x200) >> 3)
-           | ((timings->VSyncStart & 0x200) >> 2);
+       par->CRTC[0] = htotal - 5;
+       par->CRTC[1] = (var->xres >> 3) - 1;
+       par->CRTC[2] = (var->xres >> 3) - 1;
+       par->CRTC[3] = ((htotal - 1) & 0x1F) | 0x80;
+       par->CRTC[4] = ((var->xres + var->right_margin) >> 3);
+       par->CRTC[5] = (((htotal - 1) & 0x20) << 2)
+           | (((hsync_end >> 3)) & 0x1F);
+       par->CRTC[6] = (vtotal - 2) & 0xFF;
+       par->CRTC[7] = (((vtotal - 2) & 0x100) >> 8)
+           | (((var->yres - 1) & 0x100) >> 7)
+           | ((vsync_start & 0x100) >> 6)
+           | (((var->yres - 1) & 0x100) >> 5)
+           | 0x10 | (((vtotal - 2) & 0x200) >> 4)
+           | (((var->yres - 1) & 0x200) >> 3)
+           | ((vsync_start & 0x200) >> 2);
        par->CRTC[8] = 0x00;
-       par->CRTC[9] = (((timings->VDisplay - 1) & 0x200) >> 4) | 0x40;
+       par->CRTC[9] = (((var->yres - 1) & 0x200) >> 4) | 0x40;
 
-       if (timings->dblscan)
+       if (var->vmode & FB_VMODE_DOUBLE)
                par->CRTC[9] |= 0x80;
 
        par->CRTC[10] = 0x00;
@@ -317,13 +314,13 @@ static int vgaHWInit(const struct fb_var_screeninfo *var,
        par->CRTC[13] = 0x00;
        par->CRTC[14] = 0x00;
        par->CRTC[15] = 0x00;
-       par->CRTC[16] = timings->VSyncStart & 0xFF;
-       par->CRTC[17] = (timings->VSyncEnd & 0x0F) | 0x20;
-       par->CRTC[18] = (timings->VDisplay - 1) & 0xFF;
+       par->CRTC[16] = vsync_start & 0xFF;
+       par->CRTC[17] = (vsync_end & 0x0F) | 0x20;
+       par->CRTC[18] = (var->yres - 1) & 0xFF;
        par->CRTC[19] = var->xres_virtual >> 4;
        par->CRTC[20] = 0x00;
-       par->CRTC[21] = (timings->VDisplay - 1) & 0xFF;
-       par->CRTC[22] = (timings->VTotal - 1) & 0xFF;
+       par->CRTC[21] = (var->yres - 1) & 0xFF;
+       par->CRTC[22] = (vtotal - 1) & 0xFF;
        par->CRTC[23] = 0xC3;
        par->CRTC[24] = 0xFF;
 
@@ -429,11 +426,11 @@ static void vgaHWProtect(int on)
 {
        unsigned char tmp;
 
+       tmp = vga_rseq(NULL, 0x01);
        if (on) {
                /*
                 * Turn off screen and disable sequencer.
                 */
-               tmp = vga_rseq(NULL, 0x01);
                vga_wseq(NULL, 0x00, 0x01);             /* Synchronous Reset */
                vga_wseq(NULL, 0x01, tmp | 0x20);       /* disable the display */
 
@@ -442,7 +439,6 @@ static void vgaHWProtect(int on)
                /*
                 * Reenable sequencer, then turn on screen.
                 */
-               tmp = vga_rseq(NULL, 0x01);
                vga_wseq(NULL, 0x01, tmp & ~0x20);      /* reenable display */
                vga_wseq(NULL, 0x00, 0x03);             /* clear synchronousreset */
 
@@ -486,10 +482,9 @@ static void vgaHWRestore(const struct fb_info *info,
 static inline int neo2200_sync(struct fb_info *info)
 {
        struct neofb_par *par = info->par;
-       int waitcycles;
 
        while (readl(&par->neo2200->bltStat) & 1)
-               waitcycles++;
+               cpu_relax();
        return 0;
 }
 
@@ -561,14 +556,14 @@ static int
 neofb_open(struct fb_info *info, int user)
 {
        struct neofb_par *par = info->par;
-       int cnt = atomic_read(&par->ref_count);
 
-       if (!cnt) {
+       if (!par->ref_count) {
                memset(&par->state, 0, sizeof(struct vgastate));
                par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS;
                save_vga(&par->state);
        }
-       atomic_inc(&par->ref_count);
+       par->ref_count++;
+
        return 0;
 }
 
@@ -576,14 +571,15 @@ static int
 neofb_release(struct fb_info *info, int user)
 {
        struct neofb_par *par = info->par;
-       int cnt = atomic_read(&par->ref_count);
 
-       if (!cnt)
+       if (!par->ref_count)
                return -EINVAL;
-       if (cnt == 1) {
+
+       if (par->ref_count == 1) {
                restore_vga(&par->state);
        }
-       atomic_dec(&par->ref_count);
+       par->ref_count--;
+
        return 0;
 }
 
@@ -591,34 +587,14 @@ static int
 neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
        struct neofb_par *par = info->par;
-       unsigned int pixclock = var->pixclock;
-       struct xtimings timings;
        int memlen, vramlen;
        int mode_ok = 0;
 
        DBG("neofb_check_var");
 
-       if (!pixclock)
-               pixclock = 10000;       /* 10ns = 100MHz */
-       timings.pixclock = 1000000000 / pixclock;
-       if (timings.pixclock < 1)
-               timings.pixclock = 1;
-
-       if (timings.pixclock > par->maxClock)
+       if (PICOS2KHZ(var->pixclock) > par->maxClock)
                return -EINVAL;
 
-       timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
-       timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
-       timings.HDisplay = var->xres;
-       timings.HSyncStart = timings.HDisplay + var->right_margin;
-       timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
-       timings.HTotal = timings.HSyncEnd + var->left_margin;
-       timings.VDisplay = var->yres;
-       timings.VSyncStart = timings.VDisplay + var->lower_margin;
-       timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
-       timings.VTotal = timings.VSyncEnd + var->upper_margin;
-       timings.sync = var->sync;
-
        /* Is the mode larger than the LCD panel? */
        if (par->internal_display &&
             ((var->xres > par->NeoPanelWidth) ||
@@ -664,11 +640,12 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        var->red.msb_right = 0;
        var->green.msb_right = 0;
        var->blue.msb_right = 0;
+       var->transp.msb_right = 0;
 
+       var->transp.offset = 0;
+       var->transp.length = 0;
        switch (var->bits_per_pixel) {
        case 8:         /* PSEUDOCOLOUR, 256 */
-               var->transp.offset = 0;
-               var->transp.length = 0;
                var->red.offset = 0;
                var->red.length = 8;
                var->green.offset = 0;
@@ -678,8 +655,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
                break;
 
        case 16:                /* DIRECTCOLOUR, 64k */
-               var->transp.offset = 0;
-               var->transp.length = 0;
                var->red.offset = 11;
                var->red.length = 5;
                var->green.offset = 5;
@@ -689,8 +664,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
                break;
 
        case 24:                /* TRUECOLOUR, 16m */
-               var->transp.offset = 0;
-               var->transp.length = 0;
                var->red.offset = 16;
                var->red.length = 8;
                var->green.offset = 8;
@@ -721,8 +694,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        if (vramlen > 4 * 1024 * 1024)
                vramlen = 4 * 1024 * 1024;
 
-       if (var->yres_virtual < var->yres)
-               var->yres_virtual = var->yres;
        if (var->xres_virtual < var->xres)
                var->xres_virtual = var->xres;
 
@@ -739,8 +710,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
           if it was possible. We should return -EINVAL, but I disagree */
        if (var->yres_virtual < var->yres)
                var->yres = var->yres_virtual;
-       if (var->xres_virtual < var->xres)
-               var->xres = var->xres_virtual;
        if (var->xoffset + var->xres > var->xres_virtual)
                var->xoffset = var->xres_virtual - var->xres;
        if (var->yoffset + var->yres > var->yres_virtual)
@@ -758,11 +727,11 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 static int neofb_set_par(struct fb_info *info)
 {
        struct neofb_par *par = info->par;
-       struct xtimings timings;
        unsigned char temp;
        int i, clock_hi = 0;
        int lcd_stretch;
        int hoffset, voffset;
+       int vsync_start, vtotal;
 
        DBG("neofb_set_par");
 
@@ -770,28 +739,15 @@ static int neofb_set_par(struct fb_info *info)
 
        vgaHWProtect(1);        /* Blank the screen */
 
-       timings.dblscan = info->var.vmode & FB_VMODE_DOUBLE;
-       timings.interlaced = info->var.vmode & FB_VMODE_INTERLACED;
-       timings.HDisplay = info->var.xres;
-       timings.HSyncStart = timings.HDisplay + info->var.right_margin;
-       timings.HSyncEnd = timings.HSyncStart + info->var.hsync_len;
-       timings.HTotal = timings.HSyncEnd + info->var.left_margin;
-       timings.VDisplay = info->var.yres;
-       timings.VSyncStart = timings.VDisplay + info->var.lower_margin;
-       timings.VSyncEnd = timings.VSyncStart + info->var.vsync_len;
-       timings.VTotal = timings.VSyncEnd + info->var.upper_margin;
-       timings.sync = info->var.sync;
-       timings.pixclock = PICOS2KHZ(info->var.pixclock);
-
-       if (timings.pixclock < 1)
-               timings.pixclock = 1;
+       vsync_start = info->var.yres + info->var.lower_margin;
+       vtotal = vsync_start + info->var.vsync_len + info->var.upper_margin;
 
        /*
         * This will allocate the datastructure and initialize all of the
         * generic VGA registers.
         */
 
-       if (vgaHWInit(&info->var, info, par, &timings))
+       if (vgaHWInit(&info->var, par))
                return -EINVAL;
 
        /*
@@ -830,10 +786,10 @@ static int neofb_set_par(struct fb_info *info)
        par->ExtCRTDispAddr = 0x10;
 
        /* Vertical Extension */
-       par->VerticalExt = (((timings.VTotal - 2) & 0x400) >> 10)
-           | (((timings.VDisplay - 1) & 0x400) >> 9)
-           | (((timings.VSyncStart) & 0x400) >> 8)
-           | (((timings.VSyncStart) & 0x400) >> 7);
+       par->VerticalExt = (((vtotal - 2) & 0x400) >> 10)
+           | (((info->var.yres - 1) & 0x400) >> 9)
+           | (((vsync_start) & 0x400) >> 8)
+           | (((vsync_start) & 0x400) >> 7);
 
        /* Fast write bursts on unless disabled. */
        if (par->pci_burst)
@@ -994,7 +950,7 @@ static int neofb_set_par(struct fb_info *info)
         * Calculate the VCLK that most closely matches the requested dot
         * clock.
         */
-       neoCalcVCLK(info, par, timings.pixclock);
+       neoCalcVCLK(info, par, PICOS2KHZ(info->var.pixclock));
 
        /* Since we program the clocks ourselves, always use VCLK3. */
        par->MiscOutReg |= 0x0C;
@@ -1216,8 +1172,11 @@ static int neofb_set_par(struct fb_info *info)
        return 0;
 }
 
-static void neofb_update_start(struct fb_info *info,
-                              struct fb_var_screeninfo *var)
+/*
+ *    Pan or Wrap the Display
+ */
+static int neofb_pan_display(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
 {
        struct neofb_par *par = info->par;
        struct vgastate *state = &par->state;
@@ -1246,35 +1205,7 @@ static void neofb_update_start(struct fb_info *info,
        vga_wgfx(state->vgabase, 0x0E, (((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
 
        neoLock(state);
-}
-
-/*
- *    Pan or Wrap the Display
- */
-static int neofb_pan_display(struct fb_var_screeninfo *var,
-                            struct fb_info *info)
-{
-       u_int y_bottom;
-
-       y_bottom = var->yoffset;
-
-       if (!(var->vmode & FB_VMODE_YWRAP))
-               y_bottom += var->yres;
-
-       if (var->xoffset > (var->xres_virtual - var->xres))
-               return -EINVAL;
-       if (y_bottom > info->var.yres_virtual)
-               return -EINVAL;
-
-       neofb_update_start(info, 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;
 }
 
@@ -1284,34 +1215,36 @@ static int neofb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        if (regno >= fb->cmap.len || regno > 255)
                return -EINVAL;
 
-       switch (fb->var.bits_per_pixel) {
-       case 8:
+       if (fb->var.bits_per_pixel <= 8) {
                outb(regno, 0x3c8);
 
                outb(red >> 10, 0x3c9);
                outb(green >> 10, 0x3c9);
                outb(blue >> 10, 0x3c9);
-               break;
-       case 16:
-               ((u32 *) fb->pseudo_palette)[regno] =
+       } else if (regno < 16) {
+               switch (fb->var.bits_per_pixel) {
+               case 16:
+                       ((u32 *) fb->pseudo_palette)[regno] =
                                ((red & 0xf800)) | ((green & 0xfc00) >> 5) |
                                ((blue & 0xf800) >> 11);
-               break;
-       case 24:
-               ((u32 *) fb->pseudo_palette)[regno] =
+                       break;
+               case 24:
+                       ((u32 *) fb->pseudo_palette)[regno] =
                                ((red & 0xff00) << 8) | ((green & 0xff00)) |
                                ((blue & 0xff00) >> 8);
-               break;
+                       break;
 #ifdef NO_32BIT_SUPPORT_YET
-       case 32:
-               ((u32 *) fb->pseudo_palette)[regno] =
+               case 32:
+                       ((u32 *) fb->pseudo_palette)[regno] =
                                ((transp & 0xff00) << 16) | ((red & 0xff00) << 8) |
                                ((green & 0xff00)) | ((blue & 0xff00) >> 8);
-               break;
+                       break;
 #endif
-       default:
-               return 1;
+               default:
+                       return 1;
+               }
        }
+
        return 0;
 }
 
@@ -1335,17 +1268,22 @@ static int neofb_blank(int blank_mode, struct fb_info *info)
         *  run "setterm -powersave powerdown" to take advantage
         */
        struct neofb_par *par = info->par;
-       int seqflags, lcdflags, dpmsflags, reg;
-
+       int seqflags, lcdflags, dpmsflags, reg, tmpdisp;
 
        /*
-        * Reload the value stored in the register, if sensible. It might have
-        * been changed via FN keystroke.
+        * Read back the register bits related to display configuration. They might
+        * have been changed underneath the driver via Fn key stroke.
+        */
+       neoUnlock();
+       tmpdisp = vga_rgfx(NULL, 0x20) & 0x03;
+       neoLock(&par->state);
+
+       /* In case we blank the screen, we want to store the possibly new
+        * configuration in the driver. During un-blank, we re-apply this setting,
+        * since the LCD bit will be cleared in order to switch off the backlight.
         */
        if (par->PanelDispCntlRegRead) {
-               neoUnlock();
-               par->PanelDispCntlReg1 = vga_rgfx(NULL, 0x20) & 0x03;
-               neoLock(&par->state);
+               par->PanelDispCntlReg1 = tmpdisp;
        }
        par->PanelDispCntlRegRead = !blank_mode;
 
@@ -1380,12 +1318,21 @@ static int neofb_blank(int blank_mode, struct fb_info *info)
                break;
        case FB_BLANK_NORMAL:           /* just blank screen (backlight stays on) */
                seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */
-               lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */
+               /*
+                * During a blank operation with the LID shut, we might store "LCD off"
+                * by mistake. Due to timing issues, the BIOS may switch the lights
+                * back on, and we turn it back off once we "unblank".
+                *
+                * So here is an attempt to implement ">=" - if we are in the process
+                * of unblanking, and the LCD bit is unset in the driver but set in the
+                * register, we must keep it.
+                */
+               lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */
                dpmsflags = 0x00;       /* no hsync/vsync suppression */
                break;
        case FB_BLANK_UNBLANK:          /* unblank */
                seqflags = 0;                   /* Enable sequencer */
-               lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */
+               lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */
                dpmsflags = 0x00;       /* no hsync/vsync suppression */
 #ifdef CONFIG_TOSHIBA
                /* Do we still need this ? */
@@ -1506,7 +1453,8 @@ neo2200_imageblit(struct fb_info *info, const struct fb_image *image)
                         * is less than 16 bits wide. This is due to insufficient
                         * padding when writing the image. We need to adjust
                         * struct fb_pixmap. Not yet done. */
-                       return cfb_imageblit(info, image);
+                       cfb_imageblit(info, image);
+                       return;
                }
                bltCntl_flags = NEO_BC0_SRC_MONO;
        } else if (image->depth == info->var.bits_per_pixel) {
@@ -1514,7 +1462,8 @@ neo2200_imageblit(struct fb_info *info, const struct fb_image *image)
        } else {
                /* We don't currently support hardware acceleration if image
                 * depth is different from display */
-               return cfb_imageblit(info, image);
+               cfb_imageblit(info, image);
+               return;
        }
 
        switch (info->var.bits_per_pixel) {
@@ -1910,9 +1859,6 @@ static int __devinit neo_init_hw(struct fb_info *info)
        int maxClock = 65000;
        int CursorMem = 1024;
        int CursorOff = 0x100;
-       int linearSize = 1024;
-       int maxWidth = 1024;
-       int maxHeight = 1024;
 
        DBG("neo_init_hw");
 
@@ -1922,7 +1868,7 @@ static int __devinit neo_init_hw(struct fb_info *info)
        printk(KERN_DEBUG "--- Neo extended register dump ---\n");
        for (int w = 0; w < 0x85; w++)
                printk(KERN_DEBUG "CR %p: %p\n", (void *) w,
-                      (void *) vga_rcrt(NULL, w);
+                      (void *) vga_rcrt(NULL, w));
        for (int w = 0; w < 0xC7; w++)
                printk(KERN_DEBUG "GR %p: %p\n", (void *) w,
                       (void *) vga_rgfx(NULL, w));
@@ -1931,81 +1877,52 @@ static int __devinit neo_init_hw(struct fb_info *info)
        case FB_ACCEL_NEOMAGIC_NM2070:
                videoRam = 896;
                maxClock = 65000;
-               CursorMem = 2048;
-               CursorOff = 0x100;
-               linearSize = 1024;
-               maxWidth = 1024;
-               maxHeight = 1024;
                break;
        case FB_ACCEL_NEOMAGIC_NM2090:
        case FB_ACCEL_NEOMAGIC_NM2093:
-               videoRam = 1152;
-               maxClock = 80000;
-               CursorMem = 2048;
-               CursorOff = 0x100;
-               linearSize = 2048;
-               maxWidth = 1024;
-               maxHeight = 1024;
-               break;
        case FB_ACCEL_NEOMAGIC_NM2097:
                videoRam = 1152;
                maxClock = 80000;
-               CursorMem = 1024;
-               CursorOff = 0x100;
-               linearSize = 2048;
-               maxWidth = 1024;
-               maxHeight = 1024;
                break;
        case FB_ACCEL_NEOMAGIC_NM2160:
                videoRam = 2048;
                maxClock = 90000;
-               CursorMem = 1024;
-               CursorOff = 0x100;
-               linearSize = 2048;
-               maxWidth = 1024;
-               maxHeight = 1024;
                break;
        case FB_ACCEL_NEOMAGIC_NM2200:
                videoRam = 2560;
                maxClock = 110000;
-               CursorMem = 1024;
-               CursorOff = 0x1000;
-               linearSize = 4096;
-               maxWidth = 1280;
-               maxHeight = 1024;       /* ???? */
-
-               par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;
                break;
        case FB_ACCEL_NEOMAGIC_NM2230:
                videoRam = 3008;
                maxClock = 110000;
-               CursorMem = 1024;
-               CursorOff = 0x1000;
-               linearSize = 4096;
-               maxWidth = 1280;
-               maxHeight = 1024;       /* ???? */
-
-               par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;
                break;
        case FB_ACCEL_NEOMAGIC_NM2360:
                videoRam = 4096;
                maxClock = 110000;
-               CursorMem = 1024;
-               CursorOff = 0x1000;
-               linearSize = 4096;
-               maxWidth = 1280;
-               maxHeight = 1024;       /* ???? */
-
-               par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;
                break;
        case FB_ACCEL_NEOMAGIC_NM2380:
                videoRam = 6144;
                maxClock = 110000;
+               break;
+       }
+       switch (info->fix.accel) {
+       case FB_ACCEL_NEOMAGIC_NM2070:
+       case FB_ACCEL_NEOMAGIC_NM2090:
+       case FB_ACCEL_NEOMAGIC_NM2093:
+               CursorMem = 2048;
+               CursorOff = 0x100;
+               break;
+       case FB_ACCEL_NEOMAGIC_NM2097:
+       case FB_ACCEL_NEOMAGIC_NM2160:
+               CursorMem = 1024;
+               CursorOff = 0x100;
+               break;
+       case FB_ACCEL_NEOMAGIC_NM2200:
+       case FB_ACCEL_NEOMAGIC_NM2230:
+       case FB_ACCEL_NEOMAGIC_NM2360:
+       case FB_ACCEL_NEOMAGIC_NM2380:
                CursorMem = 1024;
                CursorOff = 0x1000;
-               linearSize = 8192;
-               maxWidth = 1280;
-               maxHeight = 1024;       /* ???? */
 
                par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;
                break;
@@ -2019,7 +1936,7 @@ static int __devinit neo_init_hw(struct fb_info *info)
 */
        par->maxClock = maxClock;
        par->cursorOff = CursorOff;
-       return ((videoRam * 1024));
+       return videoRam * 1024;
 }
 
 
@@ -2048,40 +1965,49 @@ static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const st
 
        switch (info->fix.accel) {
        case FB_ACCEL_NEOMAGIC_NM2070:
-               sprintf(info->fix.id, "MagicGraph 128");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128");
                break;
        case FB_ACCEL_NEOMAGIC_NM2090:
-               sprintf(info->fix.id, "MagicGraph 128V");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128V");
                break;
        case FB_ACCEL_NEOMAGIC_NM2093:
-               sprintf(info->fix.id, "MagicGraph 128ZV");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128ZV");
                break;
        case FB_ACCEL_NEOMAGIC_NM2097:
-               sprintf(info->fix.id, "MagicGraph 128ZV+");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128ZV+");
                break;
        case FB_ACCEL_NEOMAGIC_NM2160:
-               sprintf(info->fix.id, "MagicGraph 128XD");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 128XD");
                break;
        case FB_ACCEL_NEOMAGIC_NM2200:
-               sprintf(info->fix.id, "MagicGraph 256AV");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 256AV");
                info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
                               FBINFO_HWACCEL_COPYAREA |
                               FBINFO_HWACCEL_FILLRECT;
                break;
        case FB_ACCEL_NEOMAGIC_NM2230:
-               sprintf(info->fix.id, "MagicGraph 256AV+");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 256AV+");
                info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
                               FBINFO_HWACCEL_COPYAREA |
                               FBINFO_HWACCEL_FILLRECT;
                break;
        case FB_ACCEL_NEOMAGIC_NM2360:
-               sprintf(info->fix.id, "MagicGraph 256ZX");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 256ZX");
                info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
                               FBINFO_HWACCEL_COPYAREA |
                               FBINFO_HWACCEL_FILLRECT;
                break;
        case FB_ACCEL_NEOMAGIC_NM2380:
-               sprintf(info->fix.id, "MagicGraph 256XL+");
+               snprintf(info->fix.id, sizeof(info->fix.id),
+                               "MagicGraph 256XL+");
                info->flags |= FBINFO_HWACCEL_IMAGEBLIT |
                               FBINFO_HWACCEL_COPYAREA |
                               FBINFO_HWACCEL_FILLRECT;