]> git.pld-linux.org Git - packages/kernel.git/blob - 01-neofb-0.3.1-linux-2.4.18-pre6.patch
- added -r to depmod to actually check modules instead of rejecting
[packages/kernel.git] / 01-neofb-0.3.1-linux-2.4.18-pre6.patch
1 diff -Naur linux-2.4.18-pre6/Documentation/Configure.help linux/Documentation/Configure.help
2 --- linux-2.4.18-pre6/Documentation/Configure.help      Wed Jan 23 13:38:48 2002
3 +++ linux/Documentation/Configure.help  Wed Jan 23 13:42:09 2002
4 @@ -4145,6 +4145,16 @@
5    This driver supports the L7200 Color LCD.
6    Say Y if you want graphics support.
7  
8 +NeoMagic display support (EXPERIMENTAL)
9 +CONFIG_FB_NEOMAGIC
10 +  This driver supports notebooks with NeoMagic PCI chips.
11 +  Say Y if you have such a graphics card. 
12 +
13 +  The driver is also available as a module ( = code which can be
14 +  inserted and removed from the running kernel whenever you want). The
15 +  module will be called neofb.o. If you want to compile it as a
16 +  module, say M here and read Documentation/modules.txt.
17 +
18  PowerMac "control" frame buffer device support
19  CONFIG_FB_CONTROL
20    This driver supports a frame buffer for the graphics adapter in the
21 diff -Naur linux-2.4.18-pre6/drivers/video/Config.in linux/drivers/video/Config.in
22 --- linux-2.4.18-pre6/drivers/video/Config.in   Wed Jan 23 13:38:53 2002
23 +++ linux/drivers/video/Config.in       Wed Jan 23 13:42:09 2002
24 @@ -143,6 +143,7 @@
25             bool '    SIS 630/540/730 support' CONFIG_FB_SIS_300
26             bool '    SIS 315H/315 support' CONFIG_FB_SIS_315
27          fi
28 +        tristate '  NeoMagic display support (EXPERIMENTAL)' CONFIG_FB_NEOMAGIC
29          tristate '  3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
30          tristate '  3Dfx Voodoo Graphics (sst1) support (EXPERIMENTAL)' CONFIG_FB_VOODOO1
31        fi
32 @@ -268,7 +269,7 @@
33            "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
34            "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
35            "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
36 -          "$CONFIG_FB_SIS" = "y" ]; then
37 +          "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
38          define_tristate CONFIG_FBCON_CFB8 y
39        else
40          if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
41 @@ -288,7 +289,7 @@
42               "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
43               "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
44               "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
45 -             "$CONFIG_FB_TX3912" = "m" ]; then
46 +             "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
47             define_tristate CONFIG_FBCON_CFB8 m
48          fi
49        fi
50 @@ -304,7 +305,8 @@
51            "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
52            "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
53            "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
54 -          "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" ]; then
55 +          "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
56 +          "$CONFIG_FB_NEOMAGIC" = "y" ]; then
57          define_tristate CONFIG_FBCON_CFB16 y
58        else
59          if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
60 @@ -319,7 +321,8 @@
61               "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
62               "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
63               "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
64 -             "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" ]; then
65 +             "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
66 +             "$CONFIG_FB_NEOMAGIC" = "m" ]; then
67             define_tristate CONFIG_FBCON_CFB16 m
68          fi
69        fi
70 @@ -328,7 +331,7 @@
71            "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
72             "$CONFIG_FB_ATY128" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
73            "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
74 -          "$CONFIG_FB_VOODOO1" = "y" ]; then
75 +          "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
76          define_tristate CONFIG_FBCON_CFB24 y
77        else
78          if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
79 @@ -336,7 +339,7 @@
80               "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
81               "$CONFIG_FB_ATY128" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
82               "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_PVR2" = "m" -o \
83 -             "$CONFIG_FB_VOODOO1" = "m" ]; then
84 +             "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
85             define_tristate CONFIG_FBCON_CFB24 m
86          fi
87        fi
88 diff -Naur linux-2.4.18-pre6/drivers/video/Makefile linux/drivers/video/Makefile
89 --- linux-2.4.18-pre6/drivers/video/Makefile    Thu Oct 25 22:53:52 2001
90 +++ linux/drivers/video/Makefile        Wed Jan 23 13:42:09 2002
91 @@ -49,6 +49,7 @@
92  obj-$(CONFIG_FB_ATARI)            += atafb.o
93  obj-$(CONFIG_FB_ATY128)           += aty128fb.o
94  obj-$(CONFIG_FB_RADEON)                  += radeonfb.o
95 +obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o
96  obj-$(CONFIG_FB_IGA)              += igafb.o
97  obj-$(CONFIG_FB_CONTROL)          += controlfb.o
98  obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o
99 diff -Naur linux-2.4.18-pre6/drivers/video/fbmem.c linux/drivers/video/fbmem.c
100 --- linux-2.4.18-pre6/drivers/video/fbmem.c     Fri Dec 21 18:41:55 2001
101 +++ linux/drivers/video/fbmem.c Wed Jan 23 13:42:09 2002
102 @@ -72,6 +72,8 @@
103  extern int atyfb_setup(char*);
104  extern int aty128fb_init(void);
105  extern int aty128fb_setup(char*);
106 +extern int neofb_init(void);
107 +extern int neofb_setup(char*);
108  extern int igafb_init(void);
109  extern int igafb_setup(char*);
110  extern int imsttfb_init(void);
111 @@ -171,6 +173,9 @@
112  #endif
113  #ifdef CONFIG_FB_ATY128
114         { "aty128fb", aty128fb_init, aty128fb_setup },
115 +#endif
116 +#ifdef CONFIG_FB_NEOMAGIC
117 +       { "neo", neofb_init, neofb_setup },
118  #endif
119  #ifdef CONFIG_FB_VIRGE
120         { "virge", virgefb_init, virgefb_setup },
121 diff -Naur linux-2.4.18-pre6/drivers/video/neofb.c linux/drivers/video/neofb.c
122 --- linux-2.4.18-pre6/drivers/video/neofb.c     Thu Jan  1 01:00:00 1970
123 +++ linux/drivers/video/neofb.c Wed Jan 23 13:50:08 2002
124 @@ -0,0 +1,2421 @@
125 +/*
126 + * linux/drivers/video/neofb.c -- NeoMagic Framebuffer Driver
127 + *
128 + * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
129 + *
130 + *
131 + * Card specific code is based on XFree86's neomagic driver.
132 + * Framebuffer framework code is based on code of cyber2000fb.
133 + *
134 + * This file is subject to the terms and conditions of the GNU General
135 + * Public License.  See the file COPYING in the main directory of this
136 + * archive for more details.
137 + *
138 + *
139 + * 0.3.1
140 + *  - added module license (dok)
141 + *
142 + * 0.3
143 + *  - hardware accelerated clear and move for 2200 and above (dok)
144 + *  - maximum allowed dotclock is handled now (dok)
145 + *
146 + * 0.2.1
147 + *  - correct panning after X usage (dok)
148 + *  - added module and kernel parameters (dok)
149 + *  - no stretching if external display is enabled (dok)
150 + *
151 + * 0.2
152 + *  - initial version (dok)
153 + *
154 + *
155 + * TODO
156 + * - ioctl for internal/external switching
157 + * - blanking
158 + * - 32bit depth support, maybe impossible
159 + * - disable pan-on-sync, need specs
160 + *
161 + * BUGS
162 + * - white margin on bootup like with tdfxfb (colormap problem?)
163 + *
164 + */
165 +
166 +#include <linux/config.h>
167 +#include <linux/module.h>
168 +#include <linux/kernel.h>
169 +#include <linux/errno.h>
170 +#include <linux/string.h>
171 +#include <linux/mm.h>
172 +#include <linux/tty.h>
173 +#include <linux/malloc.h>
174 +#include <linux/delay.h>
175 +#include <linux/fb.h>
176 +#include <linux/pci.h>
177 +#include <linux/init.h>
178 +
179 +#include <asm/io.h>
180 +#include <asm/irq.h>
181 +#include <asm/pgtable.h>
182 +#include <asm/system.h>
183 +#include <asm/uaccess.h>
184 +
185 +#ifdef CONFIG_MTRR
186 +#include <asm/mtrr.h>
187 +#endif
188 +
189 +#include <video/fbcon.h>
190 +#include <video/fbcon-cfb8.h>
191 +#include <video/fbcon-cfb16.h>
192 +#include <video/fbcon-cfb24.h>
193 +#include <video/fbcon-cfb32.h>
194 +
195 +#include "neofb.h"
196 +
197 +
198 +#define NEOFB_VERSION "0.3.1"
199 +
200 +/* --------------------------------------------------------------------- */
201 +
202 +static int disabled   = 0;
203 +static int internal   = 0;
204 +static int external   = 0;
205 +static int nostretch  = 0;
206 +static int nopciburst = 0;
207 +
208 +
209 +#ifdef MODULE
210 +
211 +MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@convergence.de>");
212 +MODULE_LICENSE("GPL");
213 +MODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips");
214 +MODULE_PARM(disabled, "i");
215 +MODULE_PARM_DESC(disabled, "Disable this driver's initialization.");
216 +MODULE_PARM(internal, "i");
217 +MODULE_PARM_DESC(internal, "Enable output on internal LCD Display.");
218 +MODULE_PARM(external, "i");
219 +MODULE_PARM_DESC(external, "Enable output on external CRT.");
220 +MODULE_PARM(nostretch, "i");
221 +MODULE_PARM_DESC(nostretch, "Disable stretching of modes smaller than LCD.");
222 +MODULE_PARM(nopciburst, "i");
223 +MODULE_PARM_DESC(nopciburst, "Disable PCI burst mode.");
224 +
225 +#endif
226 +
227 +
228 +/* --------------------------------------------------------------------- */
229 +
230 +static biosMode bios8[] = {    
231 +    { 320, 240, 0x40 },
232 +    { 300, 400, 0x42 },    
233 +    { 640, 400, 0x20 },
234 +    { 640, 480, 0x21 },
235 +    { 800, 600, 0x23 },
236 +    { 1024, 768, 0x25 },
237 +};
238 +
239 +static biosMode bios16[] = {
240 +    { 320, 200, 0x2e },
241 +    { 320, 240, 0x41 },
242 +    { 300, 400, 0x43 },
243 +    { 640, 480, 0x31 },
244 +    { 800, 600, 0x34 },
245 +    { 1024, 768, 0x37 },
246 +};
247 +
248 +static biosMode bios24[] = {
249 +    { 640, 480, 0x32 },
250 +    { 800, 600, 0x35 },
251 +    { 1024, 768, 0x38 }
252 +};
253 +
254 +#ifdef NO_32BIT_SUPPORT_YET
255 +/* FIXME: guessed values, wrong */
256 +static biosMode bios32[] = {
257 +    { 640, 480, 0x33 },
258 +    { 800, 600, 0x36 },
259 +    { 1024, 768, 0x39 }
260 +    };
261 +#endif
262 +
263 +static int neoFindMode (int xres, int yres, int depth)
264 +{
265 +  int xres_s;
266 +  int i, size;
267 +  biosMode *mode;
268 +
269 +  switch (depth)
270 +    {
271 +    case 8:
272 +      size = sizeof(bios8) / sizeof(biosMode);
273 +      mode = bios8;
274 +      break;
275 +    case 16:
276 +      size = sizeof(bios16) / sizeof(biosMode);
277 +      mode = bios16;
278 +      break;
279 +    case 24:
280 +      size = sizeof(bios24) / sizeof(biosMode);
281 +      mode = bios24;
282 +      break;
283 +#ifdef NO_32BIT_SUPPORT_YET
284 +    case 32:
285 +      size = sizeof(bios32) / sizeof(biosMode);
286 +      mode = bios32;
287 +      break;
288 +#endif
289 +    default:
290 +      return 0;
291 +    }
292 +
293 +  for (i = 0; i < size; i++)
294 +    {
295 +      if (xres <= mode[i].x_res)
296 +       {
297 +         xres_s = mode[i].x_res;
298 +         for (; i < size; i++)
299 +           {
300 +             if (mode[i].x_res != xres_s)
301 +               return mode[i-1].mode;
302 +             if (yres <= mode[i].y_res)
303 +               return mode[i].mode;
304 +           }
305 +       }
306 +    }
307 +  return mode[size - 1].mode;
308 +}
309 +
310 +/* -------------------- Hardware specific routines ------------------------- */
311 +
312 +/*
313 + * Hardware Acceleration for Neo2200+
314 + */
315 +static inline void neo2200_wait_idle (struct neofb_info *fb)
316 +{
317 +  int waitcycles;
318 +
319 +  while (fb->neo2200->bltStat & 1)
320 +    waitcycles++;
321 +}
322 +
323 +static inline void neo2200_wait_fifo (struct neofb_info *fb,
324 +                                      int requested_fifo_space)
325 +{
326 +  //  ndev->neo.waitfifo_calls++;
327 +  //  ndev->neo.waitfifo_sum += requested_fifo_space;
328 +
329 +  /* FIXME: does not work
330 +  if (neo_fifo_space < requested_fifo_space)
331 +    {
332 +      neo_fifo_waitcycles++;
333 +
334 +      while (1)
335 +        {
336 +          neo_fifo_space = (neo2200->bltStat >> 8);
337 +          if (neo_fifo_space >= requested_fifo_space)
338 +            break;
339 +        }
340 +    }
341 +  else
342 +    {
343 +      neo_fifo_cache_hits++;
344 +    }
345 +
346 +  neo_fifo_space -= requested_fifo_space;
347 +  */
348 +
349 +  neo2200_wait_idle (fb);
350 +}
351 +
352 +static inline void neo2200_accel_init (struct neofb_info        *fb,
353 +                                      struct fb_var_screeninfo *var)
354 +{
355 +  Neo2200 *neo2200 = fb->neo2200;
356 +  u32 bltMod, pitch;
357 +
358 +  neo2200_wait_idle (fb);
359 +
360 +  switch (var->bits_per_pixel)
361 +    {
362 +    case 8:
363 +      bltMod = NEO_MODE1_DEPTH8;
364 +      pitch  = var->xres_virtual;
365 +      break;
366 +    case 15:
367 +    case 16:
368 +      bltMod = NEO_MODE1_DEPTH16;
369 +      pitch  = var->xres_virtual * 2;
370 +      break;
371 +    default:
372 +      printk( KERN_ERR "neofb: neo2200_accel_init: unexpected bits per pixel!\n" );
373 +      return;
374 +    }
375 +
376 +  neo2200->bltStat = bltMod << 16;
377 +  neo2200->pitch   = (pitch << 16) | pitch;
378 +}
379 +
380 +static void neo2200_accel_setup (struct display *p)
381 +{
382 +  struct neofb_info        *fb  = (struct neofb_info *)p->fb_info;
383 +  struct fb_var_screeninfo *var = &p->fb_info->var;
384 +
385 +  fb->dispsw->setup(p);
386 +
387 +  neo2200_accel_init (fb, var);
388 +}
389 +
390 +static void
391 +neo2200_accel_bmove (struct display *p, int sy, int sx, int dy, int dx,
392 +                    int height, int width)
393 +{
394 +  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
395 +  struct fb_var_screeninfo *var = &p->fb_info->var;
396 +  Neo2200 *neo2200 = fb->neo2200;
397 +  u_long src, dst;
398 +  int bpp, pitch, inc_y;
399 +  u_int fh, fw;
400 +
401 +  /* setting blitting direction does not work, so this case is unaccelerated */
402 +  if (sx != dx)
403 +    {
404 +      neo2200_wait_idle (fb);
405 +      fb->dispsw->bmove(p, sy, sx, dy, dx, height, width);
406 +      return;
407 +    }
408 +
409 +  bpp    = (var->bits_per_pixel+7) / 8;
410 +  pitch  = var->xres_virtual * bpp;
411 +
412 +  fw     = fontwidth(p);
413 +  sx    *= fw * bpp;
414 +  dx    *= fw * bpp;
415 +  width *= fw;
416 +
417 +  fh     = fontheight(p);
418 +  sy    *= fh;
419 +  dy    *= fh;
420 +
421 +  if (sy > dy)
422 +    inc_y = fh;
423 +  else
424 +    {
425 +      inc_y  = -fh;
426 +      sy    += (height - 1) * fh;
427 +      dy    += (height - 1) * fh;
428 +    }
429 +
430 +  neo2200_wait_fifo (fb, 1);
431 +
432 +  /* set blt control */
433 +  neo2200->bltCntl = NEO_BC3_FIFO_EN      |
434 +                     NEO_BC3_SKIP_MAPPING |  0x0c0000;
435 +
436 +  /* looks silly, but setting the blitting direction did not work */
437 +  while (height--)
438 +    {
439 +      src = sx + sy * pitch;
440 +      dst = dx + dy * pitch;
441 +
442 +      neo2200_wait_fifo (fb, 3);
443 +
444 +      neo2200->srcStart = src;
445 +      neo2200->dstStart = dst;
446 +      neo2200->xyExt = (fh << 16) | (width & 0xffff);
447 +
448 +      sy += inc_y;
449 +      dy += inc_y;
450 +    }
451 +}
452 +
453 +static void
454 +neo2200_accel_clear (struct vc_data *conp, struct display *p, int sy, int sx,
455 +                    int height, int width)
456 +{
457 +  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
458 +  struct fb_var_screeninfo *var = &p->fb_info->var;
459 +  Neo2200 *neo2200 = fb->neo2200;
460 +  u_long dst;
461 +  u_int fw, fh;
462 +  u32 bgx = attr_bgcol_ec(p, conp);
463 +
464 +  fw = fontwidth(p);
465 +  fh = fontheight(p);
466 +
467 +  dst    = sx * fw + sy * var->xres_virtual * fh;
468 +  width  = width * fw;
469 +  height = height * fh;
470 +
471 +  neo2200_wait_fifo (fb, 4);
472 +
473 +  /* set blt control */
474 +  neo2200->bltCntl  = NEO_BC3_FIFO_EN      |
475 +                      NEO_BC0_SRC_IS_FG    |
476 +                      NEO_BC3_SKIP_MAPPING |  0x0c0000;
477 +
478 +  switch (var->bits_per_pixel)
479 +    {
480 +    case 8:
481 +      neo2200->fgColor = bgx;
482 +      break;
483 +    case 16:
484 +      neo2200->fgColor = ((u16 *)(p->fb_info)->pseudo_palette)[bgx];
485 +      break;
486 +    }
487 +
488 +  neo2200->dstStart = dst * ((var->bits_per_pixel+7) / 8);
489 +
490 +  neo2200->xyExt    = (height << 16) | (width & 0xffff);
491 +}
492 +
493 +static void
494 +neo2200_accel_putc (struct vc_data *conp, struct display *p, int c,
495 +                   int yy, int xx)
496 +{
497 +  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
498 +
499 +  neo2200_wait_idle (fb);
500 +  fb->dispsw->putc(conp, p, c, yy, xx);
501 +}
502 +
503 +static void
504 +neo2200_accel_putcs (struct vc_data *conp, struct display *p,
505 +                    const unsigned short *s, int count, int yy, int xx)
506 +{
507 +  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
508 +
509 +  neo2200_wait_idle (fb);
510 +  fb->dispsw->putcs(conp, p, s, count, yy, xx);
511 +}
512 +
513 +static void neo2200_accel_revc (struct display *p, int xx, int yy)
514 +{
515 +  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
516 +       
517 +  neo2200_wait_idle (fb);
518 +  fb->dispsw->revc (p, xx, yy);
519 +}
520 +
521 +static void
522 +neo2200_accel_clear_margins (struct vc_data *conp, struct display *p,
523 +                            int bottom_only)
524 +{
525 +  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
526 +
527 +  fb->dispsw->clear_margins (conp, p, bottom_only);
528 +}
529 +
530 +static struct display_switch fbcon_neo2200_accel = {
531 +  setup:               neo2200_accel_setup,
532 +  bmove:               neo2200_accel_bmove,
533 +  clear:               neo2200_accel_clear,
534 +  putc:                        neo2200_accel_putc,
535 +  putcs:               neo2200_accel_putcs,
536 +  revc:                        neo2200_accel_revc,
537 +  clear_margins:       neo2200_accel_clear_margins,
538 +  fontwidthmask:       FONTWIDTH(8)|FONTWIDTH(16)
539 +};
540 +
541 +
542 +/* --------------------------------------------------------------------- */
543 +
544 +/*
545 + *    Set a single color register. Return != 0 for invalid regno.
546 + */
547 +static int neo_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
548 +                        u_int transp, struct fb_info *fb)
549 +{
550 +  struct neofb_info *info = (struct neofb_info *)fb;
551 +
552 +  if (regno >= NR_PALETTE)
553 +    return -EINVAL;
554 +
555 +  info->palette[regno].red    = red;
556 +  info->palette[regno].green  = green;
557 +  info->palette[regno].blue   = blue;
558 +  info->palette[regno].transp = transp;
559 +
560 +  switch (fb->var.bits_per_pixel)
561 +    {
562 +#ifdef FBCON_HAS_CFB8
563 +    case 8:
564 +      outb(regno, 0x3c8);
565 +
566 +      outb(red   >> 10, 0x3c9);
567 +      outb(green >> 10, 0x3c9);
568 +      outb(blue  >> 10, 0x3c9);
569 +      break;
570 +#endif
571 +
572 +#ifdef FBCON_HAS_CFB16
573 +    case 16:
574 +      if (regno < 16)
575 +       ((u16 *)fb->pseudo_palette)[regno] = ((red   & 0xf800)      ) |
576 +                                            ((green & 0xfc00) >>  5) |
577 +                                             ((blue  & 0xf800) >> 11);
578 +      break;
579 +#endif
580 +
581 +#ifdef FBCON_HAS_CFB24
582 +    case 24:
583 +      if (regno < 16)
584 +       ((u32 *)fb->pseudo_palette)[regno] = ((red   & 0xff00) << 8) |
585 +                                             ((green & 0xff00)     ) |
586 +                                            ((blue  & 0xff00) >> 8);
587 +      break;
588 +#endif
589 +
590 +#ifdef NO_32BIT_SUPPORT_YET
591 +#ifdef FBCON_HAS_CFB32
592 +    case 32:
593 +      if (regno < 16)
594 +       ((u32 *)fb->pseudo_palette)[regno] = ((transp & 0xff00) << 16) |
595 +                                            ((red    & 0xff00) <<  8) |
596 +                                             ((green  & 0xff00)      ) |
597 +                                            ((blue   & 0xff00) >>  8);
598 +      break;
599 +#endif
600 +#endif
601 +
602 +    default:
603 +      return 1;
604 +    }
605 +
606 +  return 0;
607 +}
608 +
609 +static void vgaHWLock (void)
610 +{
611 +  /* Protect CRTC[0-7] */
612 +  VGAwCR (0x11, VGArCR (0x11) | 0x80);
613 +}
614 +
615 +static void vgaHWUnlock (void)
616 +{
617 +  /* Unprotect CRTC[0-7] */
618 +  VGAwCR (0x11, VGArCR (0x11) & ~0x80);
619 +}
620 +
621 +static void neoLock (void)
622 +{
623 +  VGAwGR (0x09, 0x00);
624 +  vgaHWLock();
625 +}
626 +
627 +static void neoUnlock (void)
628 +{
629 +  vgaHWUnlock();
630 +  VGAwGR (0x09, 0x26);
631 +}
632 +
633 +/*
634 + * vgaHWSeqReset
635 + *      perform a sequencer reset.
636 + */
637 +void
638 +vgaHWSeqReset(int start)
639 +{
640 +  if (start)
641 +    VGAwSEQ (0x00, 0x01);              /* Synchronous Reset */
642 +  else
643 +    VGAwSEQ (0x00, 0x03);              /* End Reset */
644 +}
645 +
646 +void
647 +vgaHWProtect(int on)
648 +{
649 +  unsigned char tmp;
650 +  
651 +  if (on)
652 +    {
653 +      /*
654 +       * Turn off screen and disable sequencer.
655 +       */
656 +      tmp = VGArSEQ (0x01);
657 +
658 +      vgaHWSeqReset (1);                       /* start synchronous reset */
659 +      VGAwSEQ (0x01, tmp | 0x20);      /* disable the display */
660 +
661 +      VGAenablePalette();
662 +    }
663 +  else
664 +    {
665 +      /*
666 +       * Reenable sequencer, then turn on screen.
667 +       */
668 +  
669 +      tmp = VGArSEQ (0x01);
670 +
671 +      VGAwSEQ (0x01, tmp & ~0x20);     /* reenable display */
672 +      vgaHWSeqReset (0);               /* clear synchronousreset */
673 +
674 +      VGAdisablePalette();
675 +    }
676 +}
677 +
678 +static void vgaHWRestore (const struct neofb_info *info,
679 +                         const struct neofb_par  *par)
680 +{
681 +  int i;
682 +
683 +  VGAwMISC (par->MiscOutReg);
684 +
685 +  for (i = 1; i < 5; i++)
686 +    VGAwSEQ (i, par->Sequencer[i]);
687 +  
688 +  /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
689 +  VGAwCR (17, par->CRTC[17] & ~0x80);
690 +
691 +  for (i = 0; i < 25; i++)
692 +    VGAwCR (i, par->CRTC[i]);
693 +
694 +  for (i = 0; i < 9; i++)
695 +    VGAwGR (i, par->Graphics[i]);
696 +
697 +  VGAenablePalette();
698 +
699 +  for (i = 0; i < 21; i++)
700 +    VGAwATTR (i, par->Attribute[i]);
701 +
702 +  VGAdisablePalette();
703 +}
704 +
705 +static void neofb_set_par (struct neofb_info       *info,
706 +                          const struct neofb_par  *par)
707 +{
708 +  unsigned char temp;
709 +  int i;
710 +  int clock_hi = 0;
711 +    
712 +  DBG("neofb_set_par");
713 +
714 +  neoUnlock();
715 +
716 +  vgaHWProtect (1);            /* Blank the screen */
717 +
718 +  /* linear colormap for non palettized modes */
719 +  switch (par->depth)
720 +    {
721 +    case 8:
722 +      break;
723 +    case 16:
724 +      for (i=0; i<64; i++)
725 +       {
726 +         outb(i, 0x3c8);
727 +         
728 +         outb(i << 1, 0x3c9);
729 +         outb(i, 0x3c9);
730 +         outb(i << 1, 0x3c9);
731 +       }
732 +      break;
733 +    case 24:
734 +#ifdef NO_32BIT_SUPPORT_YET
735 +    case 32:
736 +#endif
737 +      for (i=0; i<256; i++)
738 +       {
739 +         outb(i, 0x3c8);
740 +         
741 +         outb(i, 0x3c9);
742 +         outb(i, 0x3c9);
743 +         outb(i, 0x3c9);
744 +       }
745 +      break;
746 +    }
747 +    
748 +  /* alread unlocked above */
749 +  /* BOGUS  VGAwGR (0x09, 0x26);*/
750 +    
751 +  /* don't know what this is, but it's 0 from bootup anyway */
752 +  VGAwGR (0x15, 0x00);
753 +
754 +  /* was set to 0x01 by my bios in text and vesa modes */
755 +  VGAwGR (0x0A, par->GeneralLockReg);
756 +
757 +  /*
758 +   * The color mode needs to be set before calling vgaHWRestore
759 +   * to ensure the DAC is initialized properly.
760 +   *
761 +   * NOTE: Make sure we don't change bits make sure we don't change
762 +   * any reserved bits.
763 +   */
764 +  temp = VGArGR(0x90);
765 +  switch (info->accel)
766 +    {
767 +    case FB_ACCEL_NEOMAGIC_NM2070:
768 +      temp &= 0xF0; /* Save bits 7:4 */
769 +      temp |= (par->ExtColorModeSelect & ~0xF0);
770 +      break;
771 +    case FB_ACCEL_NEOMAGIC_NM2090:
772 +    case FB_ACCEL_NEOMAGIC_NM2093:
773 +    case FB_ACCEL_NEOMAGIC_NM2097:
774 +    case FB_ACCEL_NEOMAGIC_NM2160:
775 +    case FB_ACCEL_NEOMAGIC_NM2200:
776 +    case FB_ACCEL_NEOMAGIC_NM2230:
777 +    case FB_ACCEL_NEOMAGIC_NM2360:
778 +    case FB_ACCEL_NEOMAGIC_NM2380:
779 +      temp &= 0x70; /* Save bits 6:4 */
780 +      temp |= (par->ExtColorModeSelect & ~0x70);
781 +      break;
782 +    }
783 +
784 +  VGAwGR(0x90,temp);
785 +
786 +  /*
787 +   * In some rare cases a lockup might occur if we don't delay
788 +   * here. (Reported by Miles Lane)
789 +   */
790 +  //mdelay(200);
791 +
792 +  /*
793 +   * Disable horizontal and vertical graphics and text expansions so
794 +   * that vgaHWRestore works properly.
795 +   */
796 +  temp = VGArGR(0x25);
797 +  temp &= 0x39;
798 +  VGAwGR (0x25, temp);
799 +
800 +  /*
801 +   * Sleep for 200ms to make sure that the two operations above have
802 +   * had time to take effect.
803 +   */
804 +  mdelay(200);
805 +
806 +  /*
807 +   * This function handles restoring the generic VGA registers.  */
808 +  vgaHWRestore (info, par);
809 +
810 +
811 +  VGAwGR(0x0E, par->ExtCRTDispAddr);
812 +  VGAwGR(0x0F, par->ExtCRTOffset);
813 +  temp = VGArGR(0x10);
814 +  temp &= 0x0F; /* Save bits 3:0 */
815 +  temp |= (par->SysIfaceCntl1 & ~0x0F); /* VESA Bios sets bit 1! */
816 +  VGAwGR(0x10, temp);
817 +
818 +  VGAwGR(0x11, par->SysIfaceCntl2);
819 +  VGAwGR(0x15, 0 /*par->SingleAddrPage*/);
820 +  VGAwGR(0x16, 0 /*par->DualAddrPage*/);
821 +
822 +  temp = VGArGR(0x20);
823 +  switch (info->accel)
824 +    {
825 +    case FB_ACCEL_NEOMAGIC_NM2070:
826 +      temp &= 0xFC; /* Save bits 7:2 */
827 +      temp |= (par->PanelDispCntlReg1 & ~0xFC);
828 +      break;
829 +    case FB_ACCEL_NEOMAGIC_NM2090:
830 +    case FB_ACCEL_NEOMAGIC_NM2093:
831 +    case FB_ACCEL_NEOMAGIC_NM2097:
832 +    case FB_ACCEL_NEOMAGIC_NM2160:
833 +      temp &= 0xDC; /* Save bits 7:6,4:2 */
834 +      temp |= (par->PanelDispCntlReg1 & ~0xDC);
835 +      break;
836 +    case FB_ACCEL_NEOMAGIC_NM2200:
837 +    case FB_ACCEL_NEOMAGIC_NM2230:
838 +    case FB_ACCEL_NEOMAGIC_NM2360:
839 +    case FB_ACCEL_NEOMAGIC_NM2380:
840 +      temp &= 0x98; /* Save bits 7,4:3 */
841 +      temp |= (par->PanelDispCntlReg1 & ~0x98);
842 +      break;
843 +    }
844 +  VGAwGR(0x20, temp);
845 +
846 +  temp = VGArGR(0x25);
847 +  temp &= 0x38; /* Save bits 5:3 */
848 +  temp |= (par->PanelDispCntlReg2 & ~0x38);
849 +  VGAwGR(0x25, temp);
850 +
851 +  if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
852 +    {
853 +      temp = VGArGR(0x30);
854 +      temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
855 +      temp |= (par->PanelDispCntlReg3 & ~0xEF);
856 +      VGAwGR(0x30, temp);
857 +    }
858 +
859 +  VGAwGR(0x28, par->PanelVertCenterReg1);
860 +  VGAwGR(0x29, par->PanelVertCenterReg2);
861 +  VGAwGR(0x2a, par->PanelVertCenterReg3);
862 +
863 +  if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
864 +    {
865 +      VGAwGR(0x32, par->PanelVertCenterReg4);
866 +      VGAwGR(0x33, par->PanelHorizCenterReg1);
867 +      VGAwGR(0x34, par->PanelHorizCenterReg2);
868 +      VGAwGR(0x35, par->PanelHorizCenterReg3);
869 +    }
870 +
871 +  if (info->accel == FB_ACCEL_NEOMAGIC_NM2160)
872 +    VGAwGR(0x36, par->PanelHorizCenterReg4);
873 +
874 +  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
875 +      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
876 +      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
877 +      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
878 +    {
879 +      VGAwGR(0x36, par->PanelHorizCenterReg4);
880 +      VGAwGR(0x37, par->PanelVertCenterReg5);
881 +      VGAwGR(0x38, par->PanelHorizCenterReg5);
882 +
883 +      clock_hi = 1;
884 +    }
885 +
886 +  /* Program VCLK3 if needed. */
887 +  if (par->ProgramVCLK
888 +      && ((VGArGR(0x9B) != par->VCLK3NumeratorLow)
889 +         || (VGArGR(0x9F) !=  par->VCLK3Denominator)
890 +         || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
891 +                          != (par->VCLK3NumeratorHigh & ~0x0F)))))
892 +    {
893 +      VGAwGR(0x9B, par->VCLK3NumeratorLow);
894 +      if (clock_hi)
895 +       {
896 +         temp = VGArGR(0x8F);
897 +         temp &= 0x0F; /* Save bits 3:0 */
898 +         temp |= (par->VCLK3NumeratorHigh & ~0x0F);
899 +         VGAwGR(0x8F, temp);
900 +       }
901 +      VGAwGR(0x9F, par->VCLK3Denominator);
902 +    }
903 +
904 +  if (par->biosMode)
905 +    VGAwCR(0x23, par->biosMode);
906 +    
907 +  VGAwGR (0x93, 0xc0); /* Gives 5x faster framebuffer writes !!! */
908 +
909 +  /* Program vertical extension register */
910 +  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
911 +      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
912 +      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
913 +      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
914 +    {
915 +      VGAwCR(0x70, par->VerticalExt);
916 +    }
917 +
918 +
919 +  vgaHWProtect (0);            /* Turn on screen */
920 +
921 +  /* Calling this also locks offset registers required in update_start */
922 +  neoLock();
923 +}
924 +
925 +static void neofb_update_start (struct neofb_info *info, struct fb_var_screeninfo *var)
926 +{
927 +  int oldExtCRTDispAddr;
928 +  int Base; 
929 +
930 +  DBG("neofb_update_start");
931 +
932 +  Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2;
933 +  Base *= (var->bits_per_pixel + 7) / 8;
934 +
935 +  neoUnlock();
936 +
937 +  /*
938 +   * These are the generic starting address registers.
939 +   */
940 +  VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
941 +  VGAwCR(0x0D, (Base & 0x00FF));
942 +
943 +  /*
944 +   * Make sure we don't clobber some other bits that might already
945 +   * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
946 +   * be needed.
947 +   */
948 +  oldExtCRTDispAddr = VGArGR(0x0E);
949 +  VGAwGR(0x0E,(((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
950 +
951 +  neoLock();
952 +}
953 +
954 +/*
955 + * Set the Colormap
956 + */
957 +static int neofb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
958 +                         struct fb_info *fb)
959 +{
960 +  struct neofb_info *info = (struct neofb_info *)fb;
961 +  struct display* disp = (con < 0) ? fb->disp : (fb_display + con);
962 +  struct fb_cmap *dcmap = &disp->cmap;
963 +  int err = 0;
964 +
965 +  /* no colormap allocated? */
966 +  if (!dcmap->len)
967 +    {
968 +      int size;
969 +
970 +      if (fb->var.bits_per_pixel == 8)
971 +       size = NR_PALETTE;
972 +      else
973 +       size = 32;
974 +
975 +      err = fb_alloc_cmap (dcmap, size, 0);
976 +    }
977 +
978 +  /*
979 +   * we should be able to remove this test once fbcon has been
980 +   * "improved" --rmk
981 +   */
982 +  if (!err && con == info->currcon)
983 +    {
984 +      err = fb_set_cmap (cmap, kspc, neo_setcolreg, fb);
985 +      dcmap = &fb->cmap;
986 +    }
987 +
988 +  if (!err)
989 +    fb_copy_cmap (cmap, dcmap, kspc ? 0 : 1);
990 +
991 +  return err;
992 +}
993 +
994 +/*
995 + * neoCalcVCLK --
996 + *
997 + * Determine the closest clock frequency to the one requested.
998 + */
999 +#define REF_FREQ 14.31818
1000 +#define MAX_N 127
1001 +#define MAX_D 31
1002 +#define MAX_F 1
1003 +
1004 +static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, long freq)
1005 +{
1006 +  int n, d, f;
1007 +  double f_out;
1008 +  double f_diff;
1009 +  int n_best = 0, d_best = 0, f_best = 0;
1010 +  double f_best_diff = 999999.0;
1011 +  double f_target = freq/1000.0;
1012 +
1013 +  for (f = 0; f <= MAX_F; f++)
1014 +    for (n = 0; n <= MAX_N; n++)
1015 +      for (d = 0; d <= MAX_D; d++)
1016 +       {
1017 +         f_out = (n+1.0)/((d+1.0)*(1<<f))*REF_FREQ;
1018 +         f_diff = abs(f_out-f_target);
1019 +         if (f_diff < f_best_diff)
1020 +           {
1021 +             f_best_diff = f_diff;
1022 +             n_best = n;
1023 +             d_best = d;
1024 +             f_best = f;
1025 +           }
1026 +       }
1027 +
1028 +  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
1029 +      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
1030 +      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
1031 +      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
1032 +    {
1033 +      /* NOT_DONE:  We are trying the full range of the 2200 clock.
1034 +        We should be able to try n up to 2047 */
1035 +      par->VCLK3NumeratorLow  = n_best;
1036 +      par->VCLK3NumeratorHigh = (f_best << 7);
1037 +    }
1038 +  else
1039 +    par->VCLK3NumeratorLow  = n_best | (f_best << 7);
1040 +
1041 +  par->VCLK3Denominator = d_best;
1042 +
1043 +#ifdef NEOFB_DEBUG
1044 +  printk ("neoVCLK: f:%f NumLow=%d NumHi=%d Den=%d Df=%f\n",
1045 +         f_target,
1046 +         par->VCLK3NumeratorLow,
1047 +         par->VCLK3NumeratorHigh,
1048 +         par->VCLK3Denominator,
1049 +         f_best_diff);
1050 +#endif
1051 +}
1052 +
1053 +/*
1054 + * vgaHWInit --
1055 + *      Handle the initialization, etc. of a screen.
1056 + *      Return FALSE on failure.
1057 + */
1058 +
1059 +static int vgaHWInit (const struct fb_var_screeninfo *var,
1060 +                     const struct neofb_info        *info,
1061 +                     struct neofb_par               *par,
1062 +                     struct xtimings                *timings)
1063 +{
1064 +  par->MiscOutReg = 0x23;
1065 +
1066 +  if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
1067 +    par->MiscOutReg |= 0x40;
1068 +
1069 +  if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
1070 +    par->MiscOutReg |= 0x80;
1071 +    
1072 +  /*
1073 +   * Time Sequencer
1074 +   */
1075 +  par->Sequencer[0] = 0x00;
1076 +  par->Sequencer[1] = 0x01;
1077 +  par->Sequencer[2] = 0x0F;
1078 +  par->Sequencer[3] = 0x00;                             /* Font select */
1079 +  par->Sequencer[4] = 0x0E;                             /* Misc */
1080 +
1081 +  /*
1082 +   * CRTC Controller
1083 +   */
1084 +  par->CRTC[0]  = (timings->HTotal >> 3) - 5;
1085 +  par->CRTC[1]  = (timings->HDisplay >> 3) - 1;
1086 +  par->CRTC[2]  = (timings->HDisplay >> 3) - 1;
1087 +  par->CRTC[3]  = (((timings->HTotal >> 3) - 1) & 0x1F) | 0x80;
1088 +  par->CRTC[4]  = (timings->HSyncStart >> 3);
1089 +  par->CRTC[5]  = ((((timings->HTotal >> 3) - 1) & 0x20) << 2)
1090 +    | (((timings->HSyncEnd >> 3)) & 0x1F);
1091 +  par->CRTC[6]  = (timings->VTotal - 2) & 0xFF;
1092 +  par->CRTC[7]  = (((timings->VTotal - 2) & 0x100) >> 8)
1093 +    | (((timings->VDisplay - 1) & 0x100) >> 7)
1094 +    | ((timings->VSyncStart & 0x100) >> 6)
1095 +    | (((timings->VDisplay - 1) & 0x100) >> 5)
1096 +    | 0x10
1097 +    | (((timings->VTotal - 2) & 0x200)   >> 4)
1098 +    | (((timings->VDisplay - 1) & 0x200) >> 3)
1099 +    | ((timings->VSyncStart & 0x200) >> 2);
1100 +  par->CRTC[8]  = 0x00;
1101 +  par->CRTC[9]  = (((timings->VDisplay - 1) & 0x200) >> 4) | 0x40;
1102 +
1103 +  if (timings->dblscan)
1104 +    par->CRTC[9] |= 0x80;
1105 +
1106 +  par->CRTC[10] = 0x00;
1107 +  par->CRTC[11] = 0x00;
1108 +  par->CRTC[12] = 0x00;
1109 +  par->CRTC[13] = 0x00;
1110 +  par->CRTC[14] = 0x00;
1111 +  par->CRTC[15] = 0x00;
1112 +  par->CRTC[16] = timings->VSyncStart & 0xFF;
1113 +  par->CRTC[17] = (timings->VSyncEnd & 0x0F) | 0x20;
1114 +  par->CRTC[18] = (timings->VDisplay - 1) & 0xFF;
1115 +  par->CRTC[19] = var->xres_virtual >> 4;
1116 +  par->CRTC[20] = 0x00;
1117 +  par->CRTC[21] = (timings->VDisplay - 1) & 0xFF; 
1118 +  par->CRTC[22] = (timings->VTotal - 1) & 0xFF;
1119 +  par->CRTC[23] = 0xC3;
1120 +  par->CRTC[24] = 0xFF;
1121 +
1122 +  /*
1123 +   * are these unnecessary?
1124 +   * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
1125 +   * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
1126 +   */
1127 +
1128 +  /*
1129 +   * Graphics Display Controller
1130 +   */
1131 +  par->Graphics[0] = 0x00;
1132 +  par->Graphics[1] = 0x00;
1133 +  par->Graphics[2] = 0x00;
1134 +  par->Graphics[3] = 0x00;
1135 +  par->Graphics[4] = 0x00;
1136 +  par->Graphics[5] = 0x40;
1137 +  par->Graphics[6] = 0x05;   /* only map 64k VGA memory !!!! */
1138 +  par->Graphics[7] = 0x0F;
1139 +  par->Graphics[8] = 0xFF;
1140 +  
1141 +
1142 +  par->Attribute[0]  = 0x00; /* standard colormap translation */
1143 +  par->Attribute[1]  = 0x01;
1144 +  par->Attribute[2]  = 0x02;
1145 +  par->Attribute[3]  = 0x03;
1146 +  par->Attribute[4]  = 0x04;
1147 +  par->Attribute[5]  = 0x05;
1148 +  par->Attribute[6]  = 0x06;
1149 +  par->Attribute[7]  = 0x07;
1150 +  par->Attribute[8]  = 0x08;
1151 +  par->Attribute[9]  = 0x09;
1152 +  par->Attribute[10] = 0x0A;
1153 +  par->Attribute[11] = 0x0B;
1154 +  par->Attribute[12] = 0x0C;
1155 +  par->Attribute[13] = 0x0D;
1156 +  par->Attribute[14] = 0x0E;
1157 +  par->Attribute[15] = 0x0F;
1158 +  par->Attribute[16] = 0x41;
1159 +  par->Attribute[17] = 0xFF;
1160 +  par->Attribute[18] = 0x0F;
1161 +  par->Attribute[19] = 0x00;
1162 +  par->Attribute[20] = 0x00;
1163 +
1164 +  return 0;
1165 +}
1166 +
1167 +static int neofb_decode_var (struct fb_var_screeninfo        *var,
1168 +                             const struct neofb_info         *info,
1169 +                             struct neofb_par                *par)
1170 +{
1171 +  struct xtimings timings;
1172 +  int lcd_stretch;
1173 +  int hoffset, voffset;
1174 +  int memlen, vramlen;
1175 +  int mode_ok = 0;
1176 +  unsigned int pixclock = var->pixclock;
1177 +
1178 +  DBG("neofb_decode_var");
1179 +
1180 +  if (!pixclock) pixclock = 10000;     /* 10ns = 100MHz */
1181 +  timings.pixclock = 1000000000 / pixclock;
1182 +  if (timings.pixclock < 1) timings.pixclock = 1;
1183 +  timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
1184 +  timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
1185 +  timings.HDisplay = var->xres;
1186 +  timings.HSyncStart = timings.HDisplay + var->right_margin;
1187 +  timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
1188 +  timings.HTotal = timings.HSyncEnd + var->left_margin;
1189 +  timings.VDisplay = var->yres;
1190 +  timings.VSyncStart = timings.VDisplay + var->lower_margin;
1191 +  timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
1192 +  timings.VTotal = timings.VSyncEnd + var->upper_margin;
1193 +  timings.sync = var->sync;
1194 +
1195 +  if (timings.pixclock > info->maxClock)
1196 +    return -EINVAL;
1197 +
1198 +  /* Is the mode larger than the LCD panel? */
1199 +  if ((var->xres > info->NeoPanelWidth) ||
1200 +      (var->yres > info->NeoPanelHeight))
1201 +    {
1202 +      printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel (%dx%d)\n",
1203 +             var->xres,
1204 +             var->yres,
1205 +             info->NeoPanelWidth,
1206 +             info->NeoPanelHeight);
1207 +      return -EINVAL;
1208 +    }
1209 +
1210 +  /* Is the mode one of the acceptable sizes? */
1211 +  switch (var->xres)
1212 +    {
1213 +    case 1280:
1214 +      if (var->yres == 1024)
1215 +       mode_ok = 1;
1216 +      break;
1217 +    case 1024:
1218 +      if (var->yres == 768)
1219 +       mode_ok = 1;
1220 +      break;
1221 +    case  800:
1222 +      if (var->yres == 600)
1223 +       mode_ok = 1;
1224 +      break;
1225 +    case  640:
1226 +      if (var->yres == 480)
1227 +       mode_ok = 1;
1228 +      break;
1229 +    }
1230 +
1231 +  if (!mode_ok)
1232 +    {
1233 +      printk (KERN_INFO "Mode (%dx%d) won't display properly on LCD\n",
1234 +             var->xres, var->yres);
1235 +      return -EINVAL;
1236 +    }
1237 +
1238 +
1239 +  switch (var->bits_per_pixel)
1240 +    {
1241 +#ifdef FBCON_HAS_CFB8
1242 +    case 8:
1243 +      break;
1244 +#endif
1245 +
1246 +#ifdef FBCON_HAS_CFB16
1247 +    case 16:
1248 +      break;
1249 +#endif
1250 +
1251 +#ifdef FBCON_HAS_CFB24
1252 +    case 24:
1253 +      break;
1254 +#endif
1255 +
1256 +#ifdef NO_32BIT_SUPPORT_YET
1257 +# ifdef FBCON_HAS_CFB32
1258 +    case 32:
1259 +      break;
1260 +# endif
1261 +#endif
1262 +
1263 +    default:
1264 +      return -EINVAL;
1265 +    }
1266 +
1267 +  par->depth = var->bits_per_pixel;
1268 +
1269 +  vramlen = info->video.len;
1270 +  if (vramlen > 4*1024*1024)
1271 +    vramlen = 4*1024*1024;
1272 +
1273 +  if (var->yres_virtual < var->yres)
1274 +    var->yres_virtual = var->yres;
1275 +  if (var->xres_virtual < var->xres)
1276 +    var->xres_virtual = var->xres;
1277 +
1278 +  memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
1279 +  if (memlen > vramlen)
1280 +    {
1281 +      var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
1282 +      memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
1283 +    }
1284 +
1285 +  /* we must round yres/xres down, we already rounded y/xres_virtual up
1286 +     if it was possible. We should return -EINVAL, but I disagree */
1287 +  if (var->yres_virtual < var->yres)
1288 +    var->yres = var->yres_virtual;
1289 +  if (var->xres_virtual < var->xres)
1290 +    var->xres = var->xres_virtual;
1291 +  if (var->xoffset + var->xres > var->xres_virtual)
1292 +    var->xoffset = var->xres_virtual - var->xres;
1293 +  if (var->yoffset + var->yres > var->yres_virtual)
1294 +    var->yoffset = var->yres_virtual - var->yres;
1295 +
1296 +
1297 +  /*
1298 +   * This will allocate the datastructure and initialize all of the
1299 +   * generic VGA registers.
1300 +   */
1301 +
1302 +  if (vgaHWInit (var, info, par, &timings))
1303 +    return -EINVAL;
1304 +
1305 +  /*
1306 +   * The default value assigned by vgaHW.c is 0x41, but this does
1307 +   * not work for NeoMagic.
1308 +   */
1309 +  par->Attribute[16] = 0x01;
1310 +
1311 +  switch (var->bits_per_pixel)
1312 +    {
1313 +    case  8:
1314 +      par->CRTC[0x13]   = var->xres_virtual >> 3;
1315 +      par->ExtCRTOffset = var->xres_virtual >> 11;
1316 +      par->ExtColorModeSelect = 0x11;
1317 +      break;
1318 +    case 16:
1319 +      par->CRTC[0x13]   = var->xres_virtual >> 2;
1320 +      par->ExtCRTOffset = var->xres_virtual >> 10;
1321 +      par->ExtColorModeSelect = 0x13;
1322 +      break;
1323 +    case 24:
1324 +      par->CRTC[0x13]   = (var->xres_virtual * 3) >> 3;
1325 +      par->ExtCRTOffset = (var->xres_virtual * 3) >> 11;
1326 +      par->ExtColorModeSelect = 0x14;
1327 +      break;
1328 +#ifdef NO_32BIT_SUPPORT_YET
1329 +    case 32: /* FIXME: guessed values */
1330 +      par->CRTC[0x13]   = var->xres_virtual >> 1;
1331 +      par->ExtCRTOffset = var->xres_virtual >> 9;
1332 +      par->ExtColorModeSelect = 0x15;
1333 +      break;
1334 +#endif
1335 +    default:
1336 +      break;
1337 +    }
1338 +       
1339 +  par->ExtCRTDispAddr = 0x10;
1340 +
1341 +  /* Vertical Extension */
1342 +  par->VerticalExt = (((timings.VTotal -2) & 0x400) >> 10 )
1343 +    | (((timings.VDisplay -1) & 0x400) >> 9 )
1344 +    | (((timings.VSyncStart) & 0x400) >> 8 )
1345 +    | (((timings.VSyncStart) & 0x400) >> 7 );
1346 +
1347 +  /* Fast write bursts on unless disabled. */
1348 +  if (info->pci_burst)
1349 +    par->SysIfaceCntl1 = 0x30; 
1350 +  else
1351 +    par->SysIfaceCntl1 = 0x00; 
1352 +
1353 +  par->SysIfaceCntl2 = 0xc0; /* VESA Bios sets this to 0x80! */
1354 +
1355 +  /* Enable any user specified display devices. */
1356 +  par->PanelDispCntlReg1 = 0x00;
1357 +  if (info->internal_display)
1358 +    par->PanelDispCntlReg1 |= 0x02;
1359 +  if (info->external_display)
1360 +    par->PanelDispCntlReg1 |= 0x01;
1361 +
1362 +  /* If the user did not specify any display devices, then... */
1363 +  if (par->PanelDispCntlReg1 == 0x00) {
1364 +    /* Default to internal (i.e., LCD) only. */
1365 +    par->PanelDispCntlReg1 |= 0x02;
1366 +  }
1367 +
1368 +  /* If we are using a fixed mode, then tell the chip we are. */
1369 +  switch (var->xres)
1370 +    {
1371 +    case 1280:
1372 +      par->PanelDispCntlReg1 |= 0x60;
1373 +      break;
1374 +    case 1024:
1375 +      par->PanelDispCntlReg1 |= 0x40;
1376 +      break;
1377 +    case 800:
1378 +      par->PanelDispCntlReg1 |= 0x20;
1379 +      break;
1380 +    case 640:
1381 +    default:
1382 +      break;
1383 +    }
1384 +  
1385 +  /* Setup shadow register locking. */
1386 +  switch (par->PanelDispCntlReg1 & 0x03)
1387 +    {
1388 +    case 0x01: /* External CRT only mode: */
1389 +      par->GeneralLockReg = 0x00;
1390 +      /* We need to program the VCLK for external display only mode. */
1391 +      par->ProgramVCLK = 1;
1392 +      break;
1393 +    case 0x02: /* Internal LCD only mode: */
1394 +    case 0x03: /* Simultaneous internal/external (LCD/CRT) mode: */
1395 +      par->GeneralLockReg = 0x01;
1396 +      /* Don't program the VCLK when using the LCD. */
1397 +      par->ProgramVCLK = 0;
1398 +      break;
1399 +    }
1400 +
1401 +  /*
1402 +   * If the screen is to be stretched, turn on stretching for the
1403 +   * various modes.
1404 +   *
1405 +   * OPTION_LCD_STRETCH means stretching should be turned off!
1406 +   */
1407 +  par->PanelDispCntlReg2 = 0x00;
1408 +  par->PanelDispCntlReg3 = 0x00;
1409 +
1410 +  if (info->lcd_stretch &&
1411 +      (par->PanelDispCntlReg1 == 0x02) &&  /* LCD only */
1412 +      (var->xres != info->NeoPanelWidth))
1413 +    {
1414 +      switch (var->xres)
1415 +       {
1416 +       case  320: /* Needs testing.  KEM -- 24 May 98 */
1417 +       case  400: /* Needs testing.  KEM -- 24 May 98 */
1418 +       case  640:
1419 +       case  800:
1420 +       case 1024:
1421 +         lcd_stretch = 1;
1422 +         par->PanelDispCntlReg2 |= 0xC6;
1423 +         break;
1424 +       default:
1425 +         lcd_stretch = 0;
1426 +         /* No stretching in these modes. */
1427 +       }
1428 +    }
1429 +  else
1430 +    lcd_stretch = 0;
1431 +
1432 +  /*
1433 +   * If the screen is to be centerd, turn on the centering for the
1434 +   * various modes.
1435 +   */
1436 +  par->PanelVertCenterReg1  = 0x00;
1437 +  par->PanelVertCenterReg2  = 0x00;
1438 +  par->PanelVertCenterReg3  = 0x00;
1439 +  par->PanelVertCenterReg4  = 0x00;
1440 +  par->PanelVertCenterReg5  = 0x00;
1441 +  par->PanelHorizCenterReg1 = 0x00;
1442 +  par->PanelHorizCenterReg2 = 0x00;
1443 +  par->PanelHorizCenterReg3 = 0x00;
1444 +  par->PanelHorizCenterReg4 = 0x00;
1445 +  par->PanelHorizCenterReg5 = 0x00;
1446 +
1447 +
1448 +  if (par->PanelDispCntlReg1 & 0x02)
1449 +    {
1450 +      if (var->xres == info->NeoPanelWidth)
1451 +       {
1452 +         /*
1453 +          * No centering required when the requested display width
1454 +          * equals the panel width.
1455 +          */
1456 +       }
1457 +      else
1458 +       {
1459 +         par->PanelDispCntlReg2 |= 0x01;
1460 +         par->PanelDispCntlReg3 |= 0x10;
1461 +
1462 +         /* Calculate the horizontal and vertical offsets. */
1463 +         if (!lcd_stretch)
1464 +           {
1465 +             hoffset = ((info->NeoPanelWidth - var->xres) >> 4) - 1;
1466 +             voffset = ((info->NeoPanelHeight - var->yres) >> 1) - 2;
1467 +           }
1468 +         else
1469 +           {
1470 +             /* Stretched modes cannot be centered. */
1471 +             hoffset = 0;
1472 +             voffset = 0;
1473 +           }
1474 +
1475 +         switch (var->xres)
1476 +           {
1477 +           case  320: /* Needs testing.  KEM -- 24 May 98 */
1478 +             par->PanelHorizCenterReg3 = hoffset;
1479 +             par->PanelVertCenterReg2  = voffset;
1480 +             break;
1481 +           case  400: /* Needs testing.  KEM -- 24 May 98 */
1482 +             par->PanelHorizCenterReg4 = hoffset;
1483 +             par->PanelVertCenterReg1  = voffset;
1484 +             break;
1485 +           case  640:
1486 +             par->PanelHorizCenterReg1 = hoffset;
1487 +             par->PanelVertCenterReg3  = voffset;
1488 +             break;
1489 +           case  800:
1490 +             par->PanelHorizCenterReg2 = hoffset;
1491 +             par->PanelVertCenterReg4  = voffset;
1492 +             break;
1493 +           case 1024:
1494 +             par->PanelHorizCenterReg5 = hoffset;
1495 +             par->PanelVertCenterReg5  = voffset;
1496 +             break;
1497 +           case 1280:
1498 +           default:
1499 +             /* No centering in these modes. */
1500 +             break;
1501 +           }
1502 +       }
1503 +    }
1504 +
1505 +  par->biosMode = neoFindMode (var->xres, var->yres, var->bits_per_pixel);
1506 +    
1507 +  /*
1508 +   * Calculate the VCLK that most closely matches the requested dot
1509 +   * clock.
1510 +   */
1511 +  neoCalcVCLK (info, par, timings.pixclock);
1512 +
1513 +  /* Since we program the clocks ourselves, always use VCLK3. */
1514 +  par->MiscOutReg |= 0x0C;
1515 +
1516 +  return 0;
1517 +}
1518 +
1519 +static int neofb_set_var (struct fb_var_screeninfo *var, int con,
1520 +                          struct fb_info *fb)
1521 +{
1522 +  struct neofb_info *info = (struct neofb_info *)fb;
1523 +  struct display *display;
1524 +  struct neofb_par par;
1525 +  int err, chgvar = 0;
1526 +
1527 +  DBG("neofb_set_var");
1528 +
1529 +  err = neofb_decode_var (var, info, &par);
1530 +  if (err)
1531 +    return err;
1532 +
1533 +  if (var->activate & FB_ACTIVATE_TEST)
1534 +    return 0;
1535 +
1536 +  if (con < 0)
1537 +    {
1538 +      display = fb->disp;
1539 +      chgvar = 0;
1540 +    }
1541 +  else
1542 +    {
1543 +      display = fb_display + con;
1544 +
1545 +      if (fb->var.xres != var->xres)
1546 +       chgvar = 1;
1547 +      if (fb->var.yres != var->yres)
1548 +       chgvar = 1;
1549 +      if (fb->var.xres_virtual != var->xres_virtual)
1550 +       chgvar = 1;
1551 +      if (fb->var.yres_virtual != var->yres_virtual)
1552 +       chgvar = 1;
1553 +      if (fb->var.bits_per_pixel != var->bits_per_pixel)
1554 +       chgvar = 1;
1555 +    }
1556 +
1557 +  if (!info->neo2200)
1558 +    var->accel_flags &= ~FB_ACCELF_TEXT;
1559 +
1560 +  var->red.msb_right   = 0;
1561 +  var->green.msb_right = 0;
1562 +  var->blue.msb_right  = 0;
1563 +
1564 +  switch (var->bits_per_pixel)
1565 +    {
1566 +#ifdef FBCON_HAS_CFB8
1567 +    case 8:    /* PSEUDOCOLOUR, 256 */
1568 +      var->transp.offset   = 0;
1569 +      var->transp.length   = 0;
1570 +      var->red.offset      = 0;
1571 +      var->red.length      = 8;
1572 +      var->green.offset           = 0;
1573 +      var->green.length           = 8;
1574 +      var->blue.offset    = 0;
1575 +      var->blue.length    = 8;
1576 +      
1577 +      fb->fix.visual       = FB_VISUAL_PSEUDOCOLOR;
1578 +      info->dispsw         = &fbcon_cfb8;
1579 +      display->dispsw_data = NULL;
1580 +      display->next_line   = var->xres_virtual;
1581 +      break;
1582 +#endif
1583 +
1584 +#ifdef FBCON_HAS_CFB16
1585 +    case 16: /* DIRECTCOLOUR, 64k */
1586 +      var->transp.offset   = 0;
1587 +      var->transp.length   = 0;
1588 +      var->red.offset      = 11;
1589 +      var->red.length      = 5;
1590 +      var->green.offset    = 5;
1591 +      var->green.length    = 6;
1592 +      var->blue.offset     = 0;
1593 +      var->blue.length     = 5;
1594 +
1595 +      fb->fix.visual       = FB_VISUAL_DIRECTCOLOR;
1596 +      info->dispsw         = &fbcon_cfb16;
1597 +      display->dispsw_data = fb->pseudo_palette;
1598 +      display->next_line   = var->xres_virtual * 2;
1599 +      break;
1600 +#endif
1601 +
1602 +#ifdef FBCON_HAS_CFB24
1603 +    case 24: /* TRUECOLOUR, 16m */
1604 +      var->transp.offset   = 0;
1605 +      var->transp.length   = 0;
1606 +      var->red.offset      = 16;
1607 +      var->red.length      = 8;
1608 +      var->green.offset    = 8;
1609 +      var->green.length    = 8;
1610 +      var->blue.offset     = 0;
1611 +      var->blue.length     = 8;
1612 +
1613 +      fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1614 +      info->dispsw         = &fbcon_cfb24;
1615 +      display->dispsw_data = fb->pseudo_palette;
1616 +      display->next_line   = var->xres_virtual * 3;
1617 +
1618 +      var->accel_flags    &= ~FB_ACCELF_TEXT;
1619 +      break;
1620 +#endif
1621 +
1622 +#ifdef NO_32BIT_SUPPORT_YET
1623 +# ifdef FBCON_HAS_CFB32
1624 +    case 32: /* TRUECOLOUR, 16m */
1625 +      var->transp.offset   = 24;
1626 +      var->transp.length   = 8;
1627 +      var->red.offset      = 16;
1628 +      var->red.length      = 8;
1629 +      var->green.offset    = 8;
1630 +      var->green.length    = 8;
1631 +      var->blue.offset     = 0;
1632 +      var->blue.length     = 8;
1633 +
1634 +      fb->fix.visual       = FB_VISUAL_TRUECOLOR;
1635 +      info->dispsw         = &fbcon_cfb32;
1636 +      display->dispsw_data = fb->pseudo_palette;
1637 +      display->next_line   = var->xres_virtual * 4;
1638 +
1639 +      var->accel_flags    &= ~FB_ACCELF_TEXT;
1640 +      break;
1641 +# endif
1642 +#endif
1643 +
1644 +    default:
1645 +      printk (KERN_WARNING "neofb: no support for %dbpp\n", var->bits_per_pixel);
1646 +      info->dispsw      = &fbcon_dummy;
1647 +      var->accel_flags &= ~FB_ACCELF_TEXT;
1648 +      break;
1649 +    }
1650 +
1651 +  if (var->accel_flags & FB_ACCELF_TEXT)
1652 +    display->dispsw = &fbcon_neo2200_accel;
1653 +  else
1654 +    display->dispsw = info->dispsw;
1655 +
1656 +  fb->fix.line_length = display->next_line;
1657 +
1658 +  display->screen_base    = fb->screen_base;
1659 +  display->line_length    = fb->fix.line_length;
1660 +  display->visual         = fb->fix.visual;
1661 +  display->type                  = fb->fix.type;
1662 +  display->type_aux       = fb->fix.type_aux;
1663 +  display->ypanstep       = fb->fix.ypanstep;
1664 +  display->ywrapstep      = fb->fix.ywrapstep;
1665 +  display->can_soft_blank = 1;
1666 +  display->inverse        = 0;
1667 +
1668 +  fb->var = *var;
1669 +  fb->var.activate &= ~FB_ACTIVATE_ALL;
1670 +
1671 +  /*
1672 +   * Update the old var.  The fbcon drivers still use this.
1673 +   * Once they are using cfb->fb.var, this can be dropped.
1674 +   *                                   --rmk
1675 +   */
1676 +  display->var = fb->var;
1677 +
1678 +  /*
1679 +   * If we are setting all the virtual consoles, also set the
1680 +   * defaults used to create new consoles.
1681 +   */
1682 +  if (var->activate & FB_ACTIVATE_ALL)
1683 +    fb->disp->var = fb->var;
1684 +
1685 +  if (chgvar && fb && fb->changevar)
1686 +    fb->changevar (con);
1687 +
1688 +  if (con == info->currcon)
1689 +    {
1690 +      if (chgvar || con < 0)
1691 +        neofb_set_par (info, &par);
1692 +
1693 +      neofb_update_start (info, var);
1694 +      fb_set_cmap (&fb->cmap, 1, neo_setcolreg, fb);
1695 +
1696 +      if (var->accel_flags & FB_ACCELF_TEXT)
1697 +       neo2200_accel_init (info, var);
1698 +    }
1699 +
1700 +  return 0;
1701 +}
1702 +
1703 +/*
1704 + *    Pan or Wrap the Display
1705 + */
1706 +static int neofb_pan_display (struct fb_var_screeninfo *var, int con,
1707 +                             struct fb_info *fb)
1708 +{
1709 +  struct neofb_info *info = (struct neofb_info *)fb;
1710 +  u_int y_bottom;
1711 +
1712 +  y_bottom = var->yoffset;
1713 +
1714 +  if (!(var->vmode & FB_VMODE_YWRAP))
1715 +    y_bottom += var->yres;
1716 +
1717 +  if (var->xoffset > (var->xres_virtual - var->xres))
1718 +    return -EINVAL;
1719 +  if (y_bottom > fb->var.yres_virtual)
1720 +    return -EINVAL;
1721 +
1722 +  neofb_update_start (info, var);
1723 +
1724 +  fb->var.xoffset = var->xoffset;
1725 +  fb->var.yoffset = var->yoffset;
1726 +
1727 +  if (var->vmode & FB_VMODE_YWRAP)
1728 +    fb->var.vmode |= FB_VMODE_YWRAP;
1729 +  else
1730 +    fb->var.vmode &= ~FB_VMODE_YWRAP;
1731 +
1732 +  return 0;
1733 +}
1734 +
1735 +
1736 +/*
1737 + *    Update the `var' structure (called by fbcon.c)
1738 + *
1739 + *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1740 + *    Since it's called by a kernel driver, no range checking is done.
1741 + */
1742 +static int neofb_updatevar (int con, struct fb_info *fb)
1743 +{
1744 +  struct neofb_info *info = (struct neofb_info *)fb;
1745 +
1746 +  neofb_update_start (info, &fb_display[con].var);
1747 +
1748 +  return 0;
1749 +}
1750 +
1751 +static int neofb_switch (int con, struct fb_info *fb)
1752 +{
1753 +  struct neofb_info *info = (struct neofb_info *)fb;
1754 +  struct display *disp;
1755 +  struct fb_cmap *cmap;
1756 +
1757 +  if (info->currcon >= 0)
1758 +    {
1759 +      disp = fb_display + info->currcon;
1760 +
1761 +      /*
1762 +       * Save the old colormap and video mode.
1763 +       */
1764 +      disp->var = fb->var;
1765 +      if (disp->cmap.len)
1766 +       fb_copy_cmap(&fb->cmap, &disp->cmap, 0);
1767 +    }
1768 +
1769 +  info->currcon = con;
1770 +  disp = fb_display + con;
1771 +
1772 +  /*
1773 +   * Install the new colormap and change the video mode.  By default,
1774 +   * fbcon sets all the colormaps and video modes to the default
1775 +   * values at bootup.
1776 +   *
1777 +   * Really, we want to set the colourmap size depending on the
1778 +   * depth of the new video mode.  For now, we leave it at its
1779 +   * default 256 entry.
1780 +   */
1781 +  if (disp->cmap.len)
1782 +    cmap = &disp->cmap;
1783 +  else
1784 +    cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
1785 +
1786 +  fb_copy_cmap(cmap, &fb->cmap, 0);
1787 +
1788 +  disp->var.activate = FB_ACTIVATE_NOW;
1789 +  neofb_set_var(&disp->var, con, fb);
1790 +
1791 +  return 0;
1792 +}
1793 +
1794 +/*
1795 + *    (Un)Blank the display.
1796 + */
1797 +static void neofb_blank (int blank, struct fb_info *fb)
1798 +{
1799 +  //  struct neofb_info *info = (struct neofb_info *)fb;
1800 +
1801 +  /*
1802 +   *  Blank the screen if blank_mode != 0, else unblank. If
1803 +   *  blank == NULL then the caller blanks by setting the CLUT
1804 +   *  (Color Look Up Table) to all black. Return 0 if blanking
1805 +   *  succeeded, != 0 if un-/blanking failed due to e.g. a
1806 +   *  video mode which doesn't support it. Implements VESA
1807 +   *  suspend and powerdown modes on hardware that supports
1808 +   *  disabling hsync/vsync:
1809 +   *    blank_mode == 2: suspend vsync
1810 +   *    blank_mode == 3: suspend hsync
1811 +   *    blank_mode == 4: powerdown
1812 +   *
1813 +   *  wms...Enable VESA DMPS compatible powerdown mode
1814 +   *  run "setterm -powersave powerdown" to take advantage
1815 +   */
1816 +     
1817 +  switch (blank)
1818 +    {
1819 +    case 4:    /* powerdown - both sync lines down */
1820 +      break;   
1821 +    case 3:    /* hsync off */
1822 +      break;   
1823 +    case 2:    /* vsync off */
1824 +      break;   
1825 +    case 1:    /* just software blanking of screen */
1826 +      break;
1827 +    default: /* case 0, or anything else: unblank */
1828 +      break;
1829 +    }
1830 +}
1831 +
1832 +/*
1833 + * Get the currently displayed virtual consoles colormap.
1834 + */
1835 +static int gen_get_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *fb)
1836 +{
1837 +  fb_copy_cmap (&fb->cmap, cmap, kspc ? 0 : 2);
1838 +  return 0;
1839 +}
1840 +
1841 +/*
1842 + * Get the currently displayed virtual consoles fixed part of the display.
1843 + */
1844 +static int gen_get_fix (struct fb_fix_screeninfo *fix, int con, struct fb_info *fb)
1845 +{
1846 +  *fix = fb->fix;
1847 +  return 0;
1848 +}
1849 +
1850 +/*
1851 + * Get the current user defined part of the display.
1852 + */
1853 +static int gen_get_var (struct fb_var_screeninfo *var, int con, struct fb_info *fb)
1854 +{
1855 +  *var = fb->var;
1856 +  return 0;
1857 +}
1858 +
1859 +static struct fb_ops neofb_ops = {
1860 +  owner:          THIS_MODULE,
1861 +  fb_set_var:     neofb_set_var,
1862 +  fb_set_cmap:    neofb_set_cmap,
1863 +  fb_pan_display: neofb_pan_display,
1864 +  fb_get_fix:     gen_get_fix,
1865 +  fb_get_var:     gen_get_var,
1866 +  fb_get_cmap:    gen_get_cmap,
1867 +};
1868 +
1869 +/* --------------------------------------------------------------------- */
1870 +
1871 +static struct fb_var_screeninfo __devinitdata neofb_var640x480x8 = {
1872 +       accel_flags:    FB_ACCELF_TEXT,
1873 +       xres:           640,
1874 +       yres:           480,
1875 +       xres_virtual:   640,
1876 +       yres_virtual:   30000,
1877 +       bits_per_pixel: 8,
1878 +       pixclock:       39722,
1879 +       left_margin:    48,
1880 +       right_margin:   16,
1881 +       upper_margin:   33,
1882 +       lower_margin:   10,
1883 +       hsync_len:      96,
1884 +       vsync_len:      2,
1885 +       sync:           0,
1886 +       vmode:          FB_VMODE_NONINTERLACED
1887 +};
1888 +
1889 +static struct fb_var_screeninfo __devinitdata neofb_var800x600x8 = {
1890 +       accel_flags:    FB_ACCELF_TEXT,
1891 +       xres:           800,
1892 +       yres:           600,
1893 +       xres_virtual:   800,
1894 +       yres_virtual:   30000,
1895 +       bits_per_pixel: 8,
1896 +       pixclock:       25000,
1897 +       left_margin:    88,
1898 +       right_margin:   40,
1899 +       upper_margin:   23,
1900 +       lower_margin:   1,
1901 +       hsync_len:      128,
1902 +       vsync_len:      4,
1903 +       sync:           FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
1904 +       vmode:          FB_VMODE_NONINTERLACED
1905 +};
1906 +
1907 +static struct fb_var_screeninfo __devinitdata neofb_var1024x768x8 = {
1908 +       accel_flags:    FB_ACCELF_TEXT,
1909 +       xres:           1024,
1910 +       yres:           768,
1911 +       xres_virtual:   1024,
1912 +       yres_virtual:   30000,
1913 +       bits_per_pixel: 8,
1914 +       pixclock:       15385,
1915 +       left_margin:    160,
1916 +       right_margin:   24,
1917 +       upper_margin:   29,
1918 +       lower_margin:   3,
1919 +       hsync_len:      136,
1920 +       vsync_len:      6,
1921 +       sync:           FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
1922 +       vmode:          FB_VMODE_NONINTERLACED
1923 +};
1924 +
1925 +#ifdef NOT_DONE
1926 +static struct fb_var_screeninfo __devinitdata neofb_var1280x1024x8 = {
1927 +       accel_flags:    FB_ACCELF_TEXT,
1928 +       xres:           1280,
1929 +       yres:           1024,
1930 +       xres_virtual:   1280,
1931 +       yres_virtual:   30000,
1932 +       bits_per_pixel: 8,
1933 +       pixclock:       9260,
1934 +       left_margin:    248,
1935 +       right_margin:   48,
1936 +       upper_margin:   38,
1937 +       lower_margin:   1,
1938 +       hsync_len:      112,
1939 +       vsync_len:      3,
1940 +       sync:           FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
1941 +       vmode:          FB_VMODE_NONINTERLACED
1942 +};
1943 +#endif
1944 +
1945 +static struct fb_var_screeninfo *neofb_var = NULL;
1946 +
1947 +
1948 +static int __devinit neo_map_mmio (struct neofb_info *info)
1949 +{
1950 +  DBG("neo_map_mmio");
1951 +
1952 +  info->mmio.pbase = pci_resource_start (info->pcidev, 1);
1953 +  info->mmio.len   = MMIO_SIZE;
1954 +
1955 +  if (!request_mem_region (info->mmio.pbase, MMIO_SIZE, "memory mapped I/O"))
1956 +    {
1957 +      printk ("neofb: memory mapped IO in use\n");
1958 +      return -EBUSY;
1959 +    }
1960 +
1961 +  info->mmio.vbase = ioremap (info->mmio.pbase, MMIO_SIZE);
1962 +  if (!info->mmio.vbase)
1963 +    {
1964 +      printk ("neofb: unable to map memory mapped IO\n");
1965 +      release_mem_region (info->mmio.pbase, info->mmio.len);
1966 +      return -ENOMEM;
1967 +    }
1968 +  else
1969 +    printk (KERN_INFO "neofb: mapped io at %p\n", info->mmio.vbase);
1970 +
1971 +  info->fb.fix.mmio_start = info->mmio.pbase;
1972 +  info->fb.fix.mmio_len   = info->mmio.len;
1973 +
1974 +  return 0;
1975 +}
1976 +
1977 +static void __devinit neo_unmap_mmio (struct neofb_info *info)
1978 +{
1979 +  DBG("neo_unmap_mmio");
1980 +
1981 +  if (info->mmio.vbase)
1982 +    {
1983 +      iounmap (info->mmio.vbase);
1984 +      info->mmio.vbase = NULL;
1985 +
1986 +      release_mem_region (info->mmio.pbase, info->mmio.len);
1987 +    }
1988 +}
1989 +
1990 +static int __devinit neo_map_video (struct neofb_info *info, int video_len)
1991 +{
1992 +  DBG("neo_map_video");
1993 +
1994 +  info->video.pbase = pci_resource_start (info->pcidev, 0);
1995 +  info->video.len   = video_len;
1996 +
1997 +  if (!request_mem_region (info->video.pbase, info->video.len, "frame buffer"))
1998 +    {
1999 +      printk ("neofb: frame buffer in use\n");
2000 +      return -EBUSY;
2001 +    }
2002 +
2003 +  info->video.vbase = ioremap (info->video.pbase, info->video.len);
2004 +  if (!info->video.vbase)
2005 +    {
2006 +      printk ("neofb: unable to map screen memory\n");
2007 +      release_mem_region (info->video.pbase, info->video.len);
2008 +      return -ENOMEM;
2009 +    }
2010 +  else
2011 +    printk (KERN_INFO "neofb: mapped framebuffer at %p\n", info->video.vbase);
2012 +
2013 +  info->fb.fix.smem_start = info->video.pbase;
2014 +  info->fb.fix.smem_len   = info->video.len;
2015 +  info->fb.screen_base    = info->video.vbase;
2016 +
2017 +#ifdef CONFIG_MTRR
2018 +  info->video.mtrr = mtrr_add (info->video.pbase, pci_resource_len (info->pcidev, 0), MTRR_TYPE_WRCOMB, 1);
2019 +#endif
2020 +
2021 +  /* Clear framebuffer, it's all white in memory after boot */
2022 +  memset (info->video.vbase, 0, info->video.len);
2023 +
2024 +  return 0;
2025 +}
2026 +
2027 +static void __devinit neo_unmap_video (struct neofb_info *info)
2028 +{
2029 +  DBG("neo_unmap_video");
2030 +
2031 +  if (info->video.vbase)
2032 +    {
2033 +#ifdef CONFIG_MTRR
2034 +      mtrr_del (info->video.mtrr, info->video.pbase, info->video.len);
2035 +#endif
2036 +
2037 +      iounmap (info->video.vbase);
2038 +      info->video.vbase = NULL;
2039 +      info->fb.screen_base = NULL;
2040 +
2041 +      release_mem_region (info->video.pbase, info->video.len);
2042 +    }
2043 +}
2044 +
2045 +static int __devinit neo_init_hw (struct neofb_info *info)
2046 +{
2047 +  int videoRam = 896;
2048 +  int maxClock = 65000;
2049 +  int CursorMem = 1024;
2050 +  int CursorOff = 0x100;
2051 +  int linearSize = 1024;
2052 +  int maxWidth = 1024;
2053 +  int maxHeight = 1024;
2054 +  unsigned char type, display;
2055 +  int w;
2056 +    
2057 +  DBG("neo_init_hw");
2058 +
2059 +  neoUnlock();
2060 +
2061 +#if 0
2062 +  printk (KERN_DEBUG "--- Neo extended register dump ---\n");
2063 +  for (w=0; w<0x85; w++)
2064 +    printk (KERN_DEBUG "CR %p: %p\n", (void*)w, (void*)VGArCR (w));
2065 +  for (w=0; w<0xC7; w++)
2066 +    printk (KERN_DEBUG "GR %p: %p\n", (void*)w, (void*)VGArGR (w));
2067 +#endif
2068 +
2069 +  /* Determine the panel type */
2070 +  VGAwGR(0x09,0x26);
2071 +  type = VGArGR(0x21);
2072 +  display = VGArGR(0x20);
2073 +    
2074 +  /* Determine panel width -- used in NeoValidMode. */
2075 +  w = VGArGR(0x20);
2076 +  VGAwGR(0x09,0x00);
2077 +  switch ((w & 0x18) >> 3)
2078 +    {
2079 +    case 0x00:
2080 +      info->NeoPanelWidth  = 640;
2081 +      info->NeoPanelHeight = 480;
2082 +      neofb_var = &neofb_var640x480x8;
2083 +      break;
2084 +    case 0x01:
2085 +      info->NeoPanelWidth  = 800;
2086 +      info->NeoPanelHeight = 600;
2087 +      neofb_var = &neofb_var800x600x8;
2088 +      break;
2089 +    case 0x02:
2090 +      info->NeoPanelWidth  = 1024;
2091 +      info->NeoPanelHeight = 768;
2092 +      neofb_var = &neofb_var1024x768x8;
2093 +      break;
2094 +    case 0x03:
2095 +      /* 1280x1024 panel support needs to be added */
2096 +#ifdef NOT_DONE
2097 +      info->NeoPanelWidth  = 1280;
2098 +      info->NeoPanelHeight = 1024;
2099 +      neofb_var = &neofb_var1280x1024x8;
2100 +      break;
2101 +#else
2102 +      printk (KERN_ERR "neofb: Only 640x480, 800x600 and 1024x768 panels are currently supported\n");
2103 +      return -1;
2104 +#endif
2105 +    default:
2106 +      info->NeoPanelWidth  = 640;
2107 +      info->NeoPanelHeight = 480;
2108 +      neofb_var = &neofb_var640x480x8;
2109 +      break;
2110 +    }
2111 +
2112 +  printk (KERN_INFO "Panel is a %dx%d %s %s display\n",
2113 +         info->NeoPanelWidth,
2114 +         info->NeoPanelHeight,
2115 +         (type & 0x02) ? "color" : "monochrome",
2116 +         (type & 0x10) ? "TFT" : "dual scan");
2117 +
2118 +  switch (info->accel)
2119 +    {
2120 +    case FB_ACCEL_NEOMAGIC_NM2070:
2121 +      videoRam   = 896;
2122 +      maxClock   = 65000;
2123 +      CursorMem  = 2048;
2124 +      CursorOff  = 0x100;
2125 +      linearSize = 1024;
2126 +      maxWidth   = 1024;
2127 +      maxHeight  = 1024;
2128 +      break;
2129 +    case FB_ACCEL_NEOMAGIC_NM2090:
2130 +    case FB_ACCEL_NEOMAGIC_NM2093:
2131 +      videoRam   = 1152;
2132 +      maxClock   = 80000;
2133 +      CursorMem  = 2048;
2134 +      CursorOff  = 0x100;
2135 +      linearSize = 2048;
2136 +      maxWidth   = 1024;
2137 +      maxHeight  = 1024;
2138 +      break;
2139 +    case FB_ACCEL_NEOMAGIC_NM2097:
2140 +      videoRam   = 1152;
2141 +      maxClock   = 80000;
2142 +      CursorMem  = 1024;
2143 +      CursorOff  = 0x100;
2144 +      linearSize = 2048;
2145 +      maxWidth   = 1024;
2146 +      maxHeight  = 1024;
2147 +      break;
2148 +    case FB_ACCEL_NEOMAGIC_NM2160:
2149 +      videoRam   = 2048;
2150 +      maxClock   = 90000;
2151 +      CursorMem  = 1024;
2152 +      CursorOff  = 0x100;
2153 +      linearSize = 2048;
2154 +      maxWidth   = 1024;
2155 +      maxHeight  = 1024;
2156 +      break;
2157 +    case FB_ACCEL_NEOMAGIC_NM2200:
2158 +      videoRam   = 2560;
2159 +      maxClock   = 110000;
2160 +      CursorMem  = 1024;
2161 +      CursorOff  = 0x1000;
2162 +      linearSize = 4096;
2163 +      maxWidth   = 1280;
2164 +      maxHeight  = 1024;  /* ???? */
2165 +
2166 +      info->neo2200 = (Neo2200*) info->mmio.vbase;
2167 +      break;
2168 +    case FB_ACCEL_NEOMAGIC_NM2230:
2169 +      videoRam   = 3008;
2170 +      maxClock   = 110000;
2171 +      CursorMem  = 1024;
2172 +      CursorOff  = 0x1000;
2173 +      linearSize = 4096;
2174 +      maxWidth   = 1280;
2175 +      maxHeight  = 1024;  /* ???? */
2176 +
2177 +      info->neo2200 = (Neo2200*) info->mmio.vbase;
2178 +      break;
2179 +    case FB_ACCEL_NEOMAGIC_NM2360:
2180 +      videoRam   = 4096;
2181 +      maxClock   = 110000;
2182 +      CursorMem  = 1024;
2183 +      CursorOff  = 0x1000;
2184 +      linearSize = 4096;
2185 +      maxWidth   = 1280;
2186 +      maxHeight  = 1024;  /* ???? */
2187 +
2188 +      info->neo2200 = (Neo2200*) info->mmio.vbase;
2189 +      break;
2190 +    case FB_ACCEL_NEOMAGIC_NM2380:
2191 +      videoRam   = 6144;
2192 +      maxClock   = 110000;
2193 +      CursorMem  = 1024;
2194 +      CursorOff  = 0x1000;
2195 +      linearSize = 8192;
2196 +      maxWidth   = 1280;
2197 +      maxHeight  = 1024;  /* ???? */
2198 +
2199 +      info->neo2200 = (Neo2200*) info->mmio.vbase;
2200 +      break;
2201 +    }
2202 +
2203 +  info->maxClock = maxClock;
2204 +
2205 +  return videoRam * 1024;
2206 +}
2207 +
2208 +
2209 +static struct neofb_info * __devinit neo_alloc_fb_info (struct pci_dev *dev,
2210 +                                                       const struct pci_device_id *id)
2211 +{
2212 +  struct neofb_info *info;
2213 +
2214 +  info = kmalloc (sizeof(struct neofb_info) + sizeof(struct display) +
2215 +                 sizeof(u32) * 16, GFP_KERNEL);
2216 +
2217 +  if (!info)
2218 +    return NULL;
2219 +
2220 +  memset (info, 0, sizeof(struct neofb_info) + sizeof(struct display));
2221 +
2222 +  info->currcon = -1;
2223 +  info->pcidev  = dev;
2224 +  info->accel   = id->driver_data;
2225 +
2226 +  info->pci_burst   = !nopciburst;
2227 +  info->lcd_stretch = !nostretch;
2228 +
2229 +  if (!internal && !external)
2230 +    {
2231 +      info->internal_display = 1;
2232 +      info->external_display = 0;
2233 +    }
2234 +  else
2235 +    {
2236 +      info->internal_display = internal;
2237 +      info->external_display = external;
2238 +    }
2239 +
2240 +  switch (info->accel)
2241 +    {
2242 +    case FB_ACCEL_NEOMAGIC_NM2070:
2243 +      sprintf (info->fb.fix.id, "MagicGraph 128");
2244 +      break;
2245 +    case FB_ACCEL_NEOMAGIC_NM2090:
2246 +      sprintf (info->fb.fix.id, "MagicGraph 128V");
2247 +      break;
2248 +    case FB_ACCEL_NEOMAGIC_NM2093:
2249 +      sprintf (info->fb.fix.id, "MagicGraph 128ZV");
2250 +      break;
2251 +    case FB_ACCEL_NEOMAGIC_NM2097:
2252 +      sprintf (info->fb.fix.id, "MagicGraph 128ZV+");
2253 +      break;
2254 +    case FB_ACCEL_NEOMAGIC_NM2160:
2255 +      sprintf (info->fb.fix.id, "MagicGraph 128XD");
2256 +      break;
2257 +    case FB_ACCEL_NEOMAGIC_NM2200:
2258 +      sprintf (info->fb.fix.id, "MagicGraph 256AV");
2259 +      break;
2260 +    case FB_ACCEL_NEOMAGIC_NM2230:
2261 +      sprintf (info->fb.fix.id, "MagicGraph 256AV+");
2262 +      break;
2263 +    case FB_ACCEL_NEOMAGIC_NM2360:
2264 +      sprintf (info->fb.fix.id, "MagicGraph 256ZX");
2265 +      break;
2266 +    case FB_ACCEL_NEOMAGIC_NM2380:
2267 +      sprintf (info->fb.fix.id, "MagicGraph 256XL+");
2268 +      break;
2269 +    }
2270 +
2271 +  info->fb.fix.type       = FB_TYPE_PACKED_PIXELS;
2272 +  info->fb.fix.type_aux           = 0;
2273 +  info->fb.fix.xpanstep           = 0;
2274 +  info->fb.fix.ypanstep           = 4;
2275 +  info->fb.fix.ywrapstep   = 0;
2276 +  info->fb.fix.accel       = id->driver_data;
2277 +
2278 +  info->fb.var.nonstd      = 0;
2279 +  info->fb.var.activate    = FB_ACTIVATE_NOW;
2280 +  info->fb.var.height      = -1;
2281 +  info->fb.var.width       = -1;
2282 +  info->fb.var.accel_flags = 0;
2283 +
2284 +  strcpy (info->fb.modename, info->fb.fix.id);
2285 +
2286 +  info->fb.fbops          = &neofb_ops;
2287 +  info->fb.changevar      = NULL;
2288 +  info->fb.switch_con     = neofb_switch;
2289 +  info->fb.updatevar      = neofb_updatevar;
2290 +  info->fb.blank          = neofb_blank;
2291 +  info->fb.flags          = FBINFO_FLAG_DEFAULT;
2292 +  info->fb.disp           = (struct display *)(info + 1);
2293 +  info->fb.pseudo_palette = (void *)(info->fb.disp + 1);
2294 +
2295 +  fb_alloc_cmap (&info->fb.cmap, NR_PALETTE, 0);
2296 +
2297 +  return info;
2298 +}
2299 +
2300 +static void __devinit neo_free_fb_info (struct neofb_info *info)
2301 +{
2302 +  if (info)
2303 +    {
2304 +      /*
2305 +       * Free the colourmap
2306 +       */
2307 +      fb_alloc_cmap (&info->fb.cmap, 0, 0);
2308 +
2309 +      kfree (info);
2310 +    }
2311 +}
2312 +
2313 +/* --------------------------------------------------------------------- */
2314 +
2315 +static int __devinit neofb_probe (struct pci_dev* dev, const struct pci_device_id* id)
2316 +{
2317 +  struct neofb_info *info;
2318 +  u_int h_sync, v_sync;
2319 +  int err;
2320 +  int video_len;
2321 +
2322 +  DBG("neofb_probe");
2323 +
2324 +  err = pci_enable_device (dev);
2325 +  if (err)
2326 +    return err;
2327 +
2328 +  err = -ENOMEM;
2329 +  info = neo_alloc_fb_info (dev, id);
2330 +  if (!info)
2331 +    goto failed;
2332 +
2333 +  err = neo_map_mmio (info);
2334 +  if (err)
2335 +    goto failed;
2336 +
2337 +  video_len = neo_init_hw (info);
2338 +  if (video_len < 0)
2339 +    {
2340 +      err = video_len;
2341 +      goto failed;
2342 +    }
2343 +
2344 +  err = neo_map_video (info, video_len);
2345 +  if (err)
2346 +    goto failed;
2347 +
2348 +  neofb_set_var (neofb_var, -1, &info->fb);
2349 +
2350 +  /*
2351 +   * Calculate the hsync and vsync frequencies.  Note that
2352 +   * we split the 1e12 constant up so that we can preserve
2353 +   * the precision and fit the results into 32-bit registers.
2354 +   *  (1953125000 * 512 = 1e12)
2355 +   */
2356 +  h_sync = 1953125000 / info->fb.var.pixclock;
2357 +  h_sync = h_sync * 512 / (info->fb.var.xres + info->fb.var.left_margin +
2358 +                          info->fb.var.right_margin + info->fb.var.hsync_len);
2359 +  v_sync = h_sync / (info->fb.var.yres + info->fb.var.upper_margin +
2360 +                    info->fb.var.lower_margin + info->fb.var.vsync_len);
2361 +
2362 +  printk(KERN_INFO "neofb v" NEOFB_VERSION ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
2363 +        info->fb.fix.smem_len >> 10,
2364 +        info->fb.var.xres, info->fb.var.yres,
2365 +        h_sync / 1000, h_sync % 1000, v_sync);
2366 +
2367 +
2368 +  err = register_framebuffer (&info->fb);
2369 +  if (err < 0)
2370 +    goto failed;
2371 +
2372 +  printk (KERN_INFO "fb%d: %s frame buffer device\n",
2373 +         GET_FB_IDX(info->fb.node), info->fb.modename);
2374 +
2375 +  /*
2376 +   * Our driver data
2377 +   */
2378 +  dev->driver_data = info;
2379 +
2380 +  return 0;
2381 +
2382 +failed:
2383 +  neo_unmap_video (info);
2384 +  neo_unmap_mmio (info);
2385 +  neo_free_fb_info (info);
2386 +
2387 +  return err;
2388 +}
2389 +
2390 +static void __devexit neofb_remove (struct pci_dev *dev)
2391 +{
2392 +  struct neofb_info *info = (struct neofb_info *)dev->driver_data;
2393 +
2394 +  DBG("neofb_remove");
2395 +
2396 +  if (info)
2397 +    {
2398 +      /*
2399 +       * If unregister_framebuffer fails, then
2400 +       * we will be leaving hooks that could cause
2401 +       * oopsen laying around.
2402 +       */
2403 +      if (unregister_framebuffer (&info->fb))
2404 +       printk (KERN_WARNING "neofb: danger danger!  Oopsen imminent!\n");
2405 +
2406 +      neo_unmap_video (info);
2407 +      neo_unmap_mmio (info);
2408 +      neo_free_fb_info (info);
2409 +
2410 +      /*
2411 +       * Ensure that the driver data is no longer
2412 +       * valid.
2413 +       */
2414 +      dev->driver_data = NULL;
2415 +    }
2416 +}
2417 +
2418 +static struct pci_device_id neofb_devices[] __devinitdata = {
2419 +  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070,
2420 +   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070},
2421 +
2422 +  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090,
2423 +   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090},
2424 +
2425 +  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093,
2426 +   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093},
2427 +
2428 +  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097,
2429 +   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097},
2430 +
2431 +  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160,
2432 +   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160},
2433 +
2434 +  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200,
2435 +   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200},
2436 +
2437 +  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230,
2438 +   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230},
2439 +
2440 +  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360,
2441 +   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360},
2442 +
2443 +  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380,
2444 +   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380},
2445 +
2446 +  {0, 0, 0, 0, 0, 0, 0}
2447 +};
2448 +
2449 +MODULE_DEVICE_TABLE(pci, neofb_devices);
2450 +
2451 +static struct pci_driver neofb_driver = {
2452 +  name:      "neofb",
2453 +  id_table:  neofb_devices,
2454 +  probe:     neofb_probe,
2455 +  remove:    neofb_remove
2456 +};
2457 +
2458 +/* **************************** init-time only **************************** */
2459 +
2460 +static void __init neo_init (void)
2461 +{
2462 +  DBG("neo_init");
2463 +  pci_register_driver (&neofb_driver);
2464 +}
2465 +
2466 +/* **************************** exit-time only **************************** */
2467 +
2468 +static void __exit neo_done (void)
2469 +{
2470 +  DBG("neo_done");
2471 +  pci_unregister_driver (&neofb_driver);
2472 +}
2473 +
2474 +
2475 +#ifndef MODULE
2476 +
2477 +/* ************************* init in-kernel code ************************** */
2478 +
2479 +int __init neofb_setup (char *options)
2480 +{
2481 +  char *this_opt;
2482 +
2483 +  DBG("neofb_setup");
2484 +
2485 +  if (!options || !*options)
2486 +    return 0;
2487 +
2488 +  for (this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,","))
2489 +    {
2490 +      if (!*this_opt) continue;
2491 +
2492 +      if (!strncmp(this_opt, "disabled", 8))
2493 +       disabled = 1;
2494 +      if (!strncmp(this_opt, "internal", 8))
2495 +       internal = 1;
2496 +      if (!strncmp(this_opt, "external", 8))
2497 +       external = 1;
2498 +      if (!strncmp(this_opt, "nostretch", 9))
2499 +       nostretch = 1;
2500 +      if (!strncmp(this_opt, "nopciburst", 10))
2501 +       nopciburst = 1;
2502 +    }
2503 +
2504 +  return 0;
2505 +}
2506 +
2507 +static int __init initialized = 0;
2508 +
2509 +int __init neofb_init(void)
2510 +{
2511 +  DBG("neofb_init");
2512 +
2513 +  if (disabled)
2514 +    return -ENXIO;
2515 +
2516 +  if (!initialized)
2517 +    {
2518 +      initialized = 1;
2519 +      neo_init();
2520 +    }
2521 +
2522 +  /* never return failure, user can hotplug card later... */
2523 +  return 0;
2524 +}
2525 +
2526 +#else
2527 +
2528 +/* *************************** init module code **************************** */
2529 +
2530 +int __init init_module(void)
2531 +{
2532 +  DBG("init_module");
2533 +
2534 +  if (disabled)
2535 +    return -ENXIO;
2536 +
2537 +  neo_init();
2538 +
2539 +  /* never return failure; user can hotplug card later... */
2540 +  return 0;
2541 +}
2542 +
2543 +#endif /* MODULE */
2544 +
2545 +module_exit(neo_done);
2546 diff -Naur linux-2.4.18-pre6/drivers/video/neofb.h linux/drivers/video/neofb.h
2547 --- linux-2.4.18-pre6/drivers/video/neofb.h     Thu Jan  1 01:00:00 1970
2548 +++ linux/drivers/video/neofb.h Wed Jan 23 13:42:09 2002
2549 @@ -0,0 +1,294 @@
2550 +/*
2551 + * linux/drivers/video/neofb.h -- NeoMagic Framebuffer Driver
2552 + *
2553 + * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
2554 + *
2555 + * This file is subject to the terms and conditions of the GNU General
2556 + * Public License.  See the file COPYING in the main directory of this
2557 + * archive for more details.
2558 + */
2559 +
2560 +
2561 +#ifdef NEOFB_DEBUG
2562 +# define DBG(x)                printk (KERN_DEBUG "neofb: %s\n", (x));
2563 +#else
2564 +# define DBG(x)
2565 +#endif
2566 +
2567 +
2568 +#define PCI_CHIP_NM2070 0x0001
2569 +#define PCI_CHIP_NM2090 0x0002
2570 +#define PCI_CHIP_NM2093 0x0003
2571 +#define PCI_CHIP_NM2097 0x0083
2572 +#define PCI_CHIP_NM2160 0x0004
2573 +#define PCI_CHIP_NM2200 0x0005
2574 +#define PCI_CHIP_NM2230 0x0025
2575 +#define PCI_CHIP_NM2360 0x0006
2576 +#define PCI_CHIP_NM2380 0x0016
2577 +
2578 +
2579 +struct xtimings {
2580 +  unsigned int pixclock;
2581 +  unsigned int HDisplay;
2582 +  unsigned int HSyncStart;
2583 +  unsigned int HSyncEnd;
2584 +  unsigned int HTotal;
2585 +  unsigned int VDisplay;
2586 +  unsigned int VSyncStart;
2587 +  unsigned int VSyncEnd;
2588 +  unsigned int VTotal;
2589 +  unsigned int sync;
2590 +  int         dblscan;
2591 +  int         interlaced;
2592 +};
2593 +
2594 +
2595 +/* --------------------------------------------------------------------- */
2596 +
2597 +typedef volatile struct {
2598 +  __u32 bltStat;
2599 +  __u32 bltCntl;
2600 +  __u32 xpColor;
2601 +  __u32 fgColor;
2602 +  __u32 bgColor;
2603 +  __u32 pitch;
2604 +  __u32 clipLT;
2605 +  __u32 clipRB;
2606 +  __u32 srcBitOffset;
2607 +  __u32 srcStart;
2608 +  __u32 reserved0;
2609 +  __u32 dstStart;
2610 +  __u32 xyExt;
2611 +
2612 +  __u32 reserved1[19];
2613 +
2614 +  __u32 pageCntl;
2615 +  __u32 pageBase;
2616 +  __u32 postBase;
2617 +  __u32 postPtr;
2618 +  __u32 dataPtr;
2619 +} Neo2200;
2620 +
2621 +#define NR_PALETTE     256
2622 +
2623 +#define MMIO_SIZE 0x200000
2624 +
2625 +#define NEO_EXT_CR_MAX 0x85
2626 +#define NEO_EXT_GR_MAX 0xC7
2627 +
2628 +struct neofb_par {
2629 +
2630 +  int depth;
2631 +
2632 +  unsigned char MiscOutReg;     /* Misc */
2633 +  unsigned char CRTC[25];       /* Crtc Controller */
2634 +  unsigned char Sequencer[5];   /* Video Sequencer */
2635 +  unsigned char Graphics[9];    /* Video Graphics */
2636 +  unsigned char Attribute[21];  /* Video Atribute */
2637 +
2638 +  unsigned char GeneralLockReg;
2639 +  unsigned char ExtCRTDispAddr;
2640 +  unsigned char ExtCRTOffset;
2641 +  unsigned char SysIfaceCntl1;
2642 +  unsigned char SysIfaceCntl2;
2643 +  unsigned char ExtColorModeSelect;
2644 +  unsigned char biosMode;
2645 +
2646 +  unsigned char PanelDispCntlReg1;
2647 +  unsigned char PanelDispCntlReg2;
2648 +  unsigned char PanelDispCntlReg3;
2649 +  unsigned char PanelVertCenterReg1;
2650 +  unsigned char PanelVertCenterReg2;
2651 +  unsigned char PanelVertCenterReg3;
2652 +  unsigned char PanelVertCenterReg4;
2653 +  unsigned char PanelVertCenterReg5;
2654 +  unsigned char PanelHorizCenterReg1;
2655 +  unsigned char PanelHorizCenterReg2;
2656 +  unsigned char PanelHorizCenterReg3;
2657 +  unsigned char PanelHorizCenterReg4;
2658 +  unsigned char PanelHorizCenterReg5;
2659 +
2660 +  int           ProgramVCLK;
2661 +  unsigned char VCLK3NumeratorLow;
2662 +  unsigned char VCLK3NumeratorHigh;
2663 +  unsigned char VCLK3Denominator;
2664 +  unsigned char VerticalExt;
2665 +};
2666 +
2667 +struct neofb_info {
2668 +
2669 +  struct fb_info  fb;
2670 +  struct display_switch        *dispsw;
2671 +
2672 +  struct pci_dev *pcidev;
2673 +
2674 +  int   currcon;
2675 +
2676 +  int   accel;
2677 +  char *name;
2678 +
2679 +  struct {
2680 +    u8    *vbase;
2681 +    u32    pbase;
2682 +    u32    len;
2683 +#ifdef CONFIG_MTRR
2684 +    int    mtrr;
2685 +#endif
2686 +  } video;
2687 +
2688 +  struct {
2689 +    u8    *vbase;
2690 +    u32    pbase;
2691 +    u32    len;
2692 +  } mmio;
2693 +
2694 +  Neo2200 *neo2200;
2695 +
2696 +  /* Panels size */
2697 +  int NeoPanelWidth;
2698 +  int NeoPanelHeight;
2699 +
2700 +  int maxClock;
2701 +
2702 +  int pci_burst;
2703 +  int lcd_stretch;
2704 +  int internal_display;
2705 +  int external_display;
2706 +
2707 +  struct {
2708 +    u16 red, green, blue, transp;
2709 +  } palette[NR_PALETTE];
2710 +};
2711 +
2712 +
2713 +typedef struct {
2714 +    int x_res;
2715 +    int y_res;
2716 +    int mode;
2717 +} biosMode;
2718 +
2719 +
2720 +/* vga IO functions */
2721 +static inline u8 VGArCR (u8 index)
2722 +{
2723 +  outb (index, 0x3d4);
2724 +  return inb (0x3d5);
2725 +}
2726 +
2727 +static inline void VGAwCR (u8 index, u8 val)
2728 +{
2729 +  outb (index, 0x3d4);
2730 +  outb (val, 0x3d5);
2731 +}
2732 +
2733 +static inline u8 VGArGR (u8 index)
2734 +{
2735 +  outb (index, 0x3ce);
2736 +  return inb (0x3cf);
2737 +}
2738 +
2739 +static inline void VGAwGR (u8 index, u8 val)
2740 +{
2741 +  outb (index, 0x3ce);
2742 +  outb (val, 0x3cf);
2743 +}
2744 +
2745 +static inline u8 VGArSEQ (u8 index)
2746 +{
2747 +  outb (index, 0x3c4);
2748 +  return inb (0x3c5);
2749 +}
2750 +
2751 +static inline void VGAwSEQ (u8 index, u8 val)
2752 +{
2753 +  outb (index, 0x3c4);
2754 +  outb (val, 0x3c5);
2755 +}
2756 +
2757 +
2758 +static int paletteEnabled = 0;
2759 +
2760 +static inline void VGAenablePalette (void)
2761 +{
2762 +  u8 tmp;
2763 +
2764 +  tmp = inb (0x3da);
2765 +  outb (0x00, 0x3c0);
2766 +  paletteEnabled = 1;
2767 +}
2768 +
2769 +static inline void VGAdisablePalette (void)
2770 +{
2771 +  u8 tmp;
2772 +
2773 +  tmp = inb (0x3da);
2774 +  outb (0x20, 0x3c0);
2775 +  paletteEnabled = 0;
2776 +}
2777 +
2778 +static inline void VGAwATTR (u8 index, u8 value)
2779 +{
2780 +  u8 tmp;
2781 +
2782 +  if (paletteEnabled)
2783 +    index &= ~0x20;
2784 +  else
2785 +    index |= 0x20;
2786 +
2787 +  tmp = inb (0x3da);
2788 +  outb (index, 0x3c0);
2789 +  outb (value, 0x3c0);
2790 +}
2791 +
2792 +static inline void VGAwMISC (u8 value)
2793 +{
2794 +  outb (value, 0x3c2);
2795 +}
2796 +
2797 +
2798 +#define NEO_BS0_BLT_BUSY        0x00000001
2799 +#define NEO_BS0_FIFO_AVAIL      0x00000002
2800 +#define NEO_BS0_FIFO_PEND       0x00000004
2801 +
2802 +#define NEO_BC0_DST_Y_DEC       0x00000001
2803 +#define NEO_BC0_X_DEC           0x00000002
2804 +#define NEO_BC0_SRC_TRANS       0x00000004
2805 +#define NEO_BC0_SRC_IS_FG       0x00000008
2806 +#define NEO_BC0_SRC_Y_DEC       0x00000010
2807 +#define NEO_BC0_FILL_PAT        0x00000020
2808 +#define NEO_BC0_SRC_MONO        0x00000040
2809 +#define NEO_BC0_SYS_TO_VID      0x00000080
2810 +
2811 +#define NEO_BC1_DEPTH8          0x00000100
2812 +#define NEO_BC1_DEPTH16         0x00000200
2813 +#define NEO_BC1_X_320           0x00000400
2814 +#define NEO_BC1_X_640           0x00000800
2815 +#define NEO_BC1_X_800           0x00000c00
2816 +#define NEO_BC1_X_1024          0x00001000
2817 +#define NEO_BC1_X_1152          0x00001400
2818 +#define NEO_BC1_X_1280          0x00001800
2819 +#define NEO_BC1_X_1600          0x00001c00
2820 +#define NEO_BC1_DST_TRANS       0x00002000
2821 +#define NEO_BC1_MSTR_BLT        0x00004000
2822 +#define NEO_BC1_FILTER_Z        0x00008000
2823 +
2824 +#define NEO_BC2_WR_TR_DST       0x00800000
2825 +
2826 +#define NEO_BC3_SRC_XY_ADDR     0x01000000
2827 +#define NEO_BC3_DST_XY_ADDR     0x02000000
2828 +#define NEO_BC3_CLIP_ON         0x04000000
2829 +#define NEO_BC3_FIFO_EN         0x08000000
2830 +#define NEO_BC3_BLT_ON_ADDR     0x10000000
2831 +#define NEO_BC3_SKIP_MAPPING    0x80000000
2832 +
2833 +#define NEO_MODE1_DEPTH8        0x0100
2834 +#define NEO_MODE1_DEPTH16       0x0200
2835 +#define NEO_MODE1_DEPTH24       0x0300
2836 +#define NEO_MODE1_X_320         0x0400
2837 +#define NEO_MODE1_X_640         0x0800
2838 +#define NEO_MODE1_X_800         0x0c00
2839 +#define NEO_MODE1_X_1024        0x1000
2840 +#define NEO_MODE1_X_1152        0x1400
2841 +#define NEO_MODE1_X_1280        0x1800
2842 +#define NEO_MODE1_X_1600        0x1c00
2843 +#define NEO_MODE1_BLT_ON_ADDR   0x2000
2844 diff -Naur linux-2.4.18-pre6/include/linux/fb.h linux/include/linux/fb.h
2845 --- linux-2.4.18-pre6/include/linux/fb.h        Mon Dec 11 22:16:53 2000
2846 +++ linux/include/linux/fb.h    Wed Jan 23 13:42:09 2002
2847 @@ -94,6 +94,18 @@
2848  #define FB_ACCEL_IGS_CYBER5000 35      /* CyberPro 5000                */
2849  #define FB_ACCEL_SIS_GLAMOUR    36     /* SiS 300/630/540              */
2850  
2851 +
2852 +#define FB_ACCEL_NEOMAGIC_NM2070 90    /* NeoMagic NM2070              */
2853 +#define FB_ACCEL_NEOMAGIC_NM2090 91    /* NeoMagic NM2090              */
2854 +#define FB_ACCEL_NEOMAGIC_NM2093 92    /* NeoMagic NM2093              */
2855 +#define FB_ACCEL_NEOMAGIC_NM2097 93    /* NeoMagic NM2097              */
2856 +#define FB_ACCEL_NEOMAGIC_NM2160 94    /* NeoMagic NM2160              */
2857 +#define FB_ACCEL_NEOMAGIC_NM2200 95    /* NeoMagic NM2200              */
2858 +#define FB_ACCEL_NEOMAGIC_NM2230 96    /* NeoMagic NM2230              */
2859 +#define FB_ACCEL_NEOMAGIC_NM2360 97    /* NeoMagic NM2360              */
2860 +#define FB_ACCEL_NEOMAGIC_NM2380 98    /* NeoMagic NM2380              */
2861 +
2862 +
2863  struct fb_fix_screeninfo {
2864         char id[16];                    /* identification string eg "TT Builtin" */
2865         unsigned long smem_start;       /* Start of frame buffer mem */
2866
This page took 0.290252 seconds and 3 git commands to generate.