patch-2.3.26 linux/drivers/video/tdfxfb.c
Next file: linux/fs/Config.in
Previous file: linux/drivers/video/sgivwfb.c
Back to the patch index
Back to the overall index
- Lines: 2071
- Date:
Wed Nov 3 14:01:41 1999
- Orig file:
v2.3.25/linux/drivers/video/tdfxfb.c
- Orig date:
Mon Oct 11 15:38:15 1999
diff -u --recursive --new-file v2.3.25/linux/drivers/video/tdfxfb.c linux/drivers/video/tdfxfb.c
@@ -8,15 +8,17 @@
* All rights reserved
*
* Created : Thu Sep 23 18:17:43 1999, hmallat
- * Last modified: Thu Oct 7 18:39:04 1999, hmallat
+ * Last modified: Tue Nov 2 21:19:47 1999, hmallat
*
* Lots of the information here comes from the Daryll Strauss' Banshee
* patches to the XF86 server, and the rest comes from the 3dfx
* Banshee specification. I'm very much indebted to Daryll for his
* work on the X server.
*
- * Voodoo3 support was contributed Harold Oga. Thanks!
- *
+ * Voodoo3 support was contributed Harold Oga. Lots of additions
+ * (proper acceleration, 24 bpp, hardware cursor) and bug fixes by Attila
+ * Kesmarki. Thanks guys!
+ *
* While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
* I do wish the next version is a bit more complete. Without the XF86
* patches I couldn't have gotten even this far... for instance, the
@@ -29,21 +31,24 @@
*
* TODO:
* - support for 16/32 bpp needs fixing (funky bootup penguin)
- * - multihead support (it's all hosed now with pokes to VGA standard
- * register locations, but shouldn't be that hard to change, some
- * other code needs to be changed too where the fb_info (which should
- * be an array of head-specific information) is referred to directly.
- * are referred to )
- * - hw cursor
- * - better acceleration support (e.g., font blitting from fb memory?)
+ * - multihead support (basically need to support an array of fb_infos)
* - banshee and voodoo3 now supported -- any others? afaik, the original
* voodoo was a 3d-only card, so we won't consider that. what about
* voodoo2?
- * - 24bpp
- * - panning (doesn't seem to work properly yet)
+ * - support other architectures (PPC, Alpha); does the fact that the VGA
+ * core can be accessed only thru I/O (not memory mapped) complicate
+ * things?
*
* Version history:
*
+ * 0.1.3 (released 1999-11-02) added Attila's panning support, code
+ * reorg, hwcursor address page size alignment
+ * (for mmaping both frame buffer and regs),
+ * and my changes to get rid of hardcoded
+ * VGA i/o register locations (uses PCI
+ * configuration info now)
+ * 0.1.2 (released 1999-10-19) added Attila Kesmarki's bug fixes and
+ * improvements
* 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga.
* 0.1.0 (released 1999-10-06) initial version
*
@@ -69,10 +74,16 @@
#include <linux/kd.h>
#include <linux/vt_kern.h>
#include <asm/io.h>
+#include <linux/timer.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
#include <video/fbcon-cfb32.h>
#ifndef LINUX_VERSION_CODE
@@ -87,6 +98,12 @@
#define PCI_DEVICE_ID_3DFX_VOODOO3 0x0005
#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+/* nothing? */
+#else
+#include <linux/spinlock.h>
+#endif
+
/* membase0 register offsets */
#define STATUS 0x00
#define PCIINIT0 0x04
@@ -167,24 +184,26 @@
#define BIT(x) (1UL << (x))
-#define ROP_COPY 0xcc
+/* COMMAND_2D reg. values */
+#define ROP_COPY 0xcc // src
+#define ROP_INVERT 0x55 // NOT dst
+#define ROP_XOR 0x66 // src XOR dst
+#define AUTOINC_DSTX BIT(10)
+#define AUTOINC_DSTY BIT(11)
#define COMMAND_2D_FILLRECT 0x05
-#define COMMAND_2D_BITBLT 0x01
+#define COMMAND_2D_S2S_BITBLT 0x01 // screen to screen
+#define COMMAND_2D_H2S_BITBLT 0x03 // host to screen
-#define COMMAND_3D_NOP 0x00
+#define COMMAND_3D_NOP 0x00
#define STATUS_RETRACE BIT(6)
#define STATUS_BUSY BIT(9)
-
#define MISCINIT1_CLUT_INV BIT(0)
#define MISCINIT1_2DBLOCK_DIS BIT(15)
-
#define DRAMINIT0_SGRAM_NUM BIT(26)
#define DRAMINIT0_SGRAM_TYPE BIT(27)
-
#define DRAMINIT1_MEM_SDRAM BIT(30)
-
#define VGAINIT0_VGA_DISABLE BIT(0)
#define VGAINIT0_EXT_TIMING BIT(1)
#define VGAINIT0_8BIT_DAC BIT(2)
@@ -196,17 +215,15 @@
#define VGAINIT0_EXTSHIFTOUT BIT(12)
#define VGAINIT0_DECODE_3C6 BIT(13)
#define VGAINIT0_SGRAM_HBLANK_DISABLE BIT(22)
-
#define VGAINIT1_MASK 0x1fffff
-
#define VIDCFG_VIDPROC_ENABLE BIT(0)
#define VIDCFG_CURS_X11 BIT(1)
#define VIDCFG_HALF_MODE BIT(4)
#define VIDCFG_DESK_ENABLE BIT(7)
#define VIDCFG_CLUT_BYPASS BIT(10)
#define VIDCFG_2X BIT(26)
+#define VIDCFG_HWCURSOR_ENABLE BIT(27)
#define VIDCFG_PIXFMT_SHIFT 18
-
#define DACMODE_2X BIT(0)
/* VGA rubbish, need to change this for multihead support */
@@ -220,9 +237,6 @@
#define IS1_R 0x3da
#define GRA_I 0x3ce
#define GRA_D 0x3cf
-#define DAC_IR 0x3c7
-#define DAC_IW 0x3c8
-#define DAC_D 0x3c9
#ifndef FB_ACCEL_3DFX_BANSHEE
#define FB_ACCEL_3DFX_BANSHEE 31
@@ -238,9 +252,9 @@
#define TDFXF_HSYNC_MASK 0x03
#define TDFXF_VSYNC_MASK 0x0c
-/* #define TDFXFB_DEBUG */
+//#define TDFXFB_DEBUG
#ifdef TDFXFB_DEBUG
-#define DPRINTK(a,b...) printk("fb: %s: " a, __FUNCTION__ , ## b)
+#define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b)
#else
#define DPRINTK(a,b...)
#endif
@@ -271,6 +285,9 @@
unsigned long screensize;
unsigned long stride;
unsigned long cursloc;
+ unsigned long curspataddr;
+ unsigned long cursc0;
+ unsigned long cursc1;
unsigned long startaddr;
unsigned long clip0min;
unsigned long clip0max;
@@ -305,6 +322,7 @@
u32 video;
u32 accel_flags;
+ u32 cmap_len;
};
struct fb_info_tdfx {
@@ -319,21 +337,37 @@
unsigned long bufbase_phys;
unsigned long bufbase_virt;
unsigned long bufbase_size;
+ unsigned long iobase;
- struct { u8 red, green, blue, pad; } palette[256];
+ struct { unsigned red, green, blue, pad; } palette[256];
struct tdfxfb_par default_par;
struct tdfxfb_par current_par;
struct display disp;
struct display_switch dispsw;
-
+#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)
union {
#ifdef FBCON_HAS_CFB16
u16 cfb16[16];
#endif
+#ifdef FBCON_HAS_CFB24
+ u32 cfb24[16];
+#endif
#ifdef FBCON_HAS_CFB32
u32 cfb32[16];
#endif
} fbcon_cmap;
+#endif
+ struct {
+ int type;
+ int state;
+ int w,u,d;
+ int x,y,redraw;
+ unsigned long enable,disable;
+ unsigned long cursorimage;
+ struct timer_list timer;
+ } cursor;
+
+ spinlock_t DAClock;
};
/*
@@ -411,9 +445,30 @@
u_int blue,
u_int transp,
struct fb_info* fb);
-static void tdfxfb_install_cmap(int con,
+static void tdfxfb_install_cmap(struct display *d,
struct fb_info *info);
+static void tdfxfb_hwcursor_init(void);
+static void tdfxfb_createcursorshape(struct display* p);
+static void tdfxfb_createcursor(struct display * p);
+
+/*
+ * do_xxx: Hardware-specific functions
+ */
+static void do_pan_var(struct fb_var_screeninfo* var, struct fb_info_tdfx *i);
+static void do_flashcursor(unsigned long ptr);
+static void do_bitblt(u32 curx, u32 cury, u32 dstx,u32 dsty,
+ u32 width, u32 height,u32 stride,u32 bpp);
+static void do_fillrect(u32 x, u32 y, u32 w,u32 h,
+ u32 color,u32 stride,u32 bpp,u32 rop);
+static void do_putc(u32 fgx, u32 bgx,struct display *p,
+ int c, int yy,int xx);
+static void do_putcs(u32 fgx, u32 bgx,struct display *p,
+ const unsigned short *s,int count, int yy,int xx);
+static u32 do_calc_pll(int freq, int* freq_out);
+static void do_write_regs(struct banshee_reg* reg);
+static unsigned long do_lfb_size(void);
+
/*
* Interface used by the world
*/
@@ -437,7 +492,8 @@
tdfxfb_set_cmap,
tdfxfb_pan_display,
tdfxfb_ioctl,
- NULL
+ NULL, // fb_mmap
+ NULL // fb_rasterimg
};
struct mode {
@@ -449,7 +505,7 @@
struct mode default_mode[] = {
{ "640x480-8@60", /* @ 60 Hz */
{
- 640, 480, 640, 480, 0, 0, 8, 0,
+ 640, 480, 640, 1024, 0, 0, 8, 0,
{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
39722, 40, 24, 32, 11, 96, 2,
@@ -493,7 +549,26 @@
15385, 168, 8, 29, 3, 144, 6,
0, FB_VMODE_NONINTERLACED
}
- }
+ },
+ { "1024x768-24@60", /* @ 60 Hz */
+ {
+ 1024, 768, 1024, 768, 0, 0, 24, 0,
+ {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
+ 15385, 168, 8, 29, 3, 144, 6,
+ 0, FB_VMODE_NONINTERLACED
+ }
+ },
+ { "1024x768-32@60", /* @ 60 Hz */
+ {
+ 1024, 768, 1024, 768, 0, 0, 32, 0,
+ {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
+ 15385, 168, 8, 29, 3, 144, 6,
+ 0, FB_VMODE_NONINTERLACED
+ }
+ }
+
#endif
};
@@ -504,55 +579,81 @@
static struct fb_info_tdfx fb_info;
-static int __initdata noaccel = 0;
-static int __initdata nopan = 0;
-static int __initdata nowrap = 0;
-static int __initdata inverse = 0;
+static int noaccel = 0;
+static int nopan = 0;
+static int nowrap = 1; // not implemented (yet)
+static int inverse = 0;
+static int nomtrr = 0;
+static int nohwcursor = 0;
static char __initdata fontname[40] = { 0 };
static const char *mode_option __initdata = NULL;
-/* ------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------
+ * Hardware-specific funcions
+ * ------------------------------------------------------------------------- */
+
+#ifdef VGA_REG_IO
+static inline u8 vga_inb(u32 reg) { return inb(reg); }
+static inline u16 vga_inw(u32 reg) { return inw(reg); }
+static inline u16 vga_inl(u32 reg) { return inl(reg); }
+
+static inline void vga_outb(u32 reg, u8 val) { outb(val, reg); }
+static inline void vga_outw(u32 reg, u16 val) { outw(val, reg); }
+static inline void vga_outl(u32 reg, u32 val) { outl(val, reg); }
+#else
+static inline u8 vga_inb(u32 reg) {
+ return inb(fb_info.iobase + reg - 0x300);
+}
+static inline u16 vga_inw(u32 reg) {
+ return inw(fb_info.iobase + reg - 0x300);
+}
+static inline u16 vga_inl(u32 reg) {
+ return inl(fb_info.iobase + reg - 0x300);
+}
-static inline __u8 vga_inb(__u32 reg) { return inb(reg); }
-static inline __u16 vga_inw(__u32 reg) { return inw(reg); }
-static inline __u16 vga_inl(__u32 reg) { return inl(reg); }
-
-static inline void vga_outb(__u32 reg, __u8 val) { outb(val, reg); }
-static inline void vga_outw(__u32 reg, __u16 val) { outw(val, reg); }
-static inline void vga_outl(__u32 reg, __u32 val) { outl(val, reg); }
+static inline void vga_outb(u32 reg, u8 val) {
+ outb(val, fb_info.iobase + reg - 0x300);
+}
+static inline void vga_outw(u32 reg, u16 val) {
+ outw(val, fb_info.iobase + reg - 0x300);
+}
+static inline void vga_outl(u32 reg, u32 val) {
+ outl(val, fb_info.iobase + reg - 0x300);
+}
+#endif
-static inline void gra_outb(__u32 idx, __u8 val) {
+static inline void gra_outb(u32 idx, u8 val) {
vga_outb(GRA_I, idx); vga_outb(GRA_D, val);
}
-static inline __u8 gra_inb(__u32 idx) {
+static inline u8 gra_inb(u32 idx) {
vga_outb(GRA_I, idx); return vga_inb(GRA_D);
}
-static inline void seq_outb(__u32 idx, __u8 val) {
+static inline void seq_outb(u32 idx, u8 val) {
vga_outb(SEQ_I, idx); vga_outb(SEQ_D, val);
}
-static inline __u8 seq_inb(__u32 idx) {
+static inline u8 seq_inb(u32 idx) {
vga_outb(SEQ_I, idx); return vga_inb(SEQ_D);
}
-static inline void crt_outb(__u32 idx, __u8 val) {
+static inline void crt_outb(u32 idx, u8 val) {
vga_outb(CRT_I, idx); vga_outb(CRT_D, val);
}
-static inline __u8 crt_inb(__u32 idx) {
+static inline u8 crt_inb(u32 idx) {
vga_outb(CRT_I, idx); return vga_inb(CRT_D);
}
-static inline void att_outb(__u32 idx, __u8 val) {
+static inline void att_outb(u32 idx, u8 val) {
unsigned char tmp;
tmp = vga_inb(IS1_R);
vga_outb(ATT_IW, idx);
vga_outb(ATT_IW, val);
}
-static inline __u8 att_inb(__u32 idx) {
+static inline u8 att_inb(u32 idx) {
unsigned char tmp;
tmp = vga_inb(IS1_R);
vga_outb(ATT_IW, idx);
@@ -585,11 +686,11 @@
vga_outb(ATT_IW, 0x20);
}
-static inline __u32 tdfx_inl(unsigned int reg) {
+static inline u32 tdfx_inl(unsigned int reg) {
return readl(fb_info.regbase_virt + reg);
}
-static inline void tdfx_outl(unsigned int reg, __u32 val) {
+static inline void tdfx_outl(unsigned int reg, u32 val) {
writel(val, fb_info.regbase_virt + reg);
}
@@ -608,81 +709,226 @@
if(i == 3) break;
}
}
+/*
+ * Set the color of a palette entry in 8bpp mode
+ */
+static inline void do_setpalentry(unsigned regno, u32 c) {
+ banshee_make_room(2); tdfx_outl(DACADDR, regno); tdfx_outl(DACDATA, c); }
-static void banshee_fillrect(__u32 x,
- __u32 y,
- __u32 w,
- __u32 h,
- __u32 color,
- __u32 stride,
- __u32 bpp) {
- banshee_make_room(2);
- tdfx_outl(DSTFORMAT,
- (stride & 0x3fff) |
- (bpp == 8 ? 0x10000 :
- bpp == 16 ? 0x30000 : 0x50000));
- tdfx_outl(COLORFORE, color);
-
- banshee_make_room(3);
- tdfx_outl(COMMAND_2D, COMMAND_2D_FILLRECT | (ROP_COPY << 24));
- tdfx_outl(DSTSIZE, (w & 0x1fff) | ((h & 0x1fff) << 16));
- tdfx_outl(LAUNCH_2D, (x & 0x1fff) | ((y & 0x1fff) << 16));
-}
-
-static void banshee_bitblt(__u32 curx,
- __u32 cury,
- __u32 dstx,
- __u32 dsty,
- __u32 width,
- __u32 height,
- __u32 stride,
- __u32 bpp) {
- int xdir, ydir;
-
- xdir = dstx < curx ? 1 : -1;
- ydir = dsty < cury ? 1 : -1;
-
- banshee_make_room(4);
- tdfx_outl(SRCFORMAT,
- (stride & 0x3fff) |
- (bpp == 8 ? 0x10000 :
- bpp == 16 ? 0x30000 : 0x50000));
- tdfx_outl(DSTFORMAT,
- (stride & 0x3fff) |
- (bpp == 8 ? 0x10000 :
- bpp == 16 ? 0x30000 : 0x50000));
- tdfx_outl(COMMAND_2D,
- COMMAND_2D_BITBLT |
- (xdir == -1 ? BIT(14) : 0) |
- (ydir == -1 ? BIT(15) : 0));
- tdfx_outl(COMMANDEXTRA_2D, 0); /* no color keying */
-
- if(xdir == -1) {
- curx += width - 1;
- dstx += width - 1;
- }
- if(ydir == -1) {
- cury += height - 1;
- dsty += height - 1;
- }
-
- /* Consecutive overlapping regions can hang the board --
- since we allow mmap'ing of control registers, we cannot
- __safely__ assume anything, like XF86 does... */
- banshee_make_room(1);
- tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
+/*
+ * Set the starting position of the visible screen to var->yoffset
+ */
+static void do_pan_var(struct fb_var_screeninfo* var, struct fb_info_tdfx *i)
+{
+ u32 addr;
+ addr = var->yoffset*i->current_par.lpitch;
+ banshee_make_room(1);
+ tdfx_outl(VIDDESKSTART, addr);
+}
+
+/*
+ * Invert the hardware cursor image (timerfunc)
+ */
+static void do_flashcursor(unsigned long ptr)
+{
+ struct fb_info_tdfx* i=(struct fb_info_tdfx *)ptr;
+ spin_lock(&i->DAClock);
+ banshee_make_room(1);
+ tdfx_outl( VIDPROCCFG, tdfx_inl(VIDPROCCFG) ^ VIDCFG_HWCURSOR_ENABLE );
+ i->cursor.timer.expires=jiffies+HZ/2;
+ add_timer(&i->cursor.timer);
+ spin_unlock(&i->DAClock);
+}
- banshee_make_room(3);
- tdfx_outl(DSTSIZE, (width & 0x1fff) | ((height & 0x1fff) << 16));
- tdfx_outl(DSTXY, (dstx & 0x1fff) | ((dsty & 0x1fff) << 16));
- tdfx_outl(LAUNCH_2D, (curx & 0x1fff) | ((cury & 0x1fff) << 16));
+/*
+ * FillRect 2D command (solidfill or invert (via ROP_XOR))
+ */
+static void do_fillrect(u32 x, u32 y, u32 w, u32 h,
+ u32 color, u32 stride, u32 bpp, u32 rop) {
+
+ u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
+
+ banshee_make_room(5);
+ tdfx_outl(DSTFORMAT, fmt);
+ tdfx_outl(COLORFORE, color);
+ tdfx_outl(COMMAND_2D, COMMAND_2D_FILLRECT | (rop << 24));
+ tdfx_outl(DSTSIZE, w | (h << 16));
+ tdfx_outl(LAUNCH_2D, x | (y << 16));
+ banshee_wait_idle();
}
-static __u32 banshee_calc_pll(int freq, int* freq_out) {
+/*
+ * Screen-to-Screen BitBlt 2D command (for the bmove fb op.)
+ */
+
+static void do_bitblt(u32 curx,
+ u32 cury,
+ u32 dstx,
+ u32 dsty,
+ u32 width,
+ u32 height,
+ u32 stride,
+ u32 bpp) {
+
+ u32 blitcmd = COMMAND_2D_S2S_BITBLT | (ROP_COPY << 24);
+ u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
+
+ if (curx <= dstx) {
+ //-X
+ blitcmd |= BIT(14);
+ curx += width-1;
+ dstx += width-1;
+ }
+ if (cury <= dsty) {
+ //-Y
+ blitcmd |= BIT(15);
+ cury += height-1;
+ dsty += height-1;
+ }
+
+ banshee_make_room(6);
+
+ tdfx_outl(SRCFORMAT, fmt);
+ tdfx_outl(DSTFORMAT, fmt);
+ tdfx_outl(COMMAND_2D, blitcmd);
+ tdfx_outl(DSTSIZE, width | (height << 16));
+ tdfx_outl(DSTXY, dstx | (dsty << 16));
+ tdfx_outl(LAUNCH_2D, curx | (cury << 16));
+ banshee_wait_idle();
+}
+
+static void do_putc(u32 fgx, u32 bgx,
+ struct display *p,
+ int c, int yy,int xx)
+{
+ int i;
+ int stride=fb_info.current_par.lpitch;
+ u32 bpp=fb_info.current_par.bpp;
+ int fw=(fontwidth(p)+7)>>3;
+ u8 *chardata=p->fontdata+(c&p->charmask)*fontheight(p)*fw;
+ u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
+
+ xx *= fontwidth(p);
+ yy *= fontheight(p);
+
+ banshee_make_room(8+((fontheight(p)*fw+3)>>2) );
+ tdfx_outl(COLORFORE, fgx);
+ tdfx_outl(COLORBACK, bgx);
+ tdfx_outl(SRCXY, 0);
+ tdfx_outl(DSTXY, xx | (yy << 16));
+ tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (ROP_COPY << 24));
+ tdfx_outl(SRCFORMAT, 0x400000);
+ tdfx_outl(DSTFORMAT, fmt);
+ tdfx_outl(DSTSIZE, fontwidth(p) | (fontheight(p) << 16));
+ i=fontheight(p);
+ switch (fw) {
+ case 1:
+ while (i>=4) {
+ tdfx_outl(LAUNCH_2D,*(u32*)chardata);
+ chardata+=4;
+ i-=4;
+ }
+ switch (i) {
+ case 0: break;
+ case 1: tdfx_outl(LAUNCH_2D,*chardata); break;
+ case 2: tdfx_outl(LAUNCH_2D,*(u16*)chardata); break;
+ case 3: tdfx_outl(LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
+ }
+ break;
+ case 2:
+ while (i>=2) {
+ tdfx_outl(LAUNCH_2D,*(u32*)chardata);
+ chardata+=4;
+ i-=2;
+ }
+ if (i) tdfx_outl(LAUNCH_2D,*(u16*)chardata);
+ break;
+ default:
+ // Is there a font with width more that 16 pixels ?
+ for (i=fontheight(p);i>0;i--) {
+ tdfx_outl(LAUNCH_2D,*(u32*)chardata);
+ chardata+=4;
+ }
+ break;
+ }
+ banshee_wait_idle();
+}
+
+static void do_putcs(u32 fgx, u32 bgx,
+ struct display *p,
+ const unsigned short *s,
+ int count, int yy,int xx)
+{
+ int i;
+ int stride=fb_info.current_par.lpitch;
+ u32 bpp=fb_info.current_par.bpp;
+ int fw=(fontwidth(p)+7)>>3;
+ int w=fontwidth(p);
+ int h=fontheight(p);
+ int regsneed=1+((h*fw+3)>>2);
+ u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
+
+ xx *= w;
+ yy = (yy*h) << 16;
+ banshee_make_room(8);
+
+ tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
+ tdfx_outl(COLORFORE, fgx);
+ tdfx_outl(COLORBACK, bgx);
+ tdfx_outl(SRCFORMAT, 0x400000);
+ tdfx_outl(DSTFORMAT, fmt);
+ tdfx_outl(DSTSIZE, w | (h << 16));
+ tdfx_outl(SRCXY, 0);
+ tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (ROP_COPY << 24));
+
+ while (count--) {
+ u8 *chardata=p->fontdata+(scr_readw(s++) & p->charmask)*h*fw;
+
+ banshee_make_room(regsneed);
+ tdfx_outl(DSTXY, xx | yy);
+ xx+=w;
+
+ i=h;
+ switch (fw) {
+ case 1:
+ while (i>=4) {
+ tdfx_outl(LAUNCH_2D,*(u32*)chardata);
+ chardata+=4;
+ i-=4;
+ }
+ switch (i) {
+ case 0: break;
+ case 1: tdfx_outl(LAUNCH_2D,*chardata); break;
+ case 2: tdfx_outl(LAUNCH_2D,*(u16*)chardata); break;
+ case 3: tdfx_outl(LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
+ }
+ break;
+ case 2:
+ while (i>=2) {
+ tdfx_outl(LAUNCH_2D,*(u32*)chardata);
+ chardata+=4;
+ i-=2;
+ }
+ if (i) tdfx_outl(LAUNCH_2D,*(u16*)chardata);
+ break;
+ default:
+ // Is there a font with width more that 16 pixels ?
+ for (;i>0;i--) {
+ tdfx_outl(LAUNCH_2D,*(u32*)chardata);
+ chardata+=4;
+ }
+ break;
+ }
+ }
+ banshee_wait_idle();
+}
+
+static u32 do_calc_pll(int freq, int* freq_out) {
int m, n, k, best_m, best_n, best_k, f_cur, best_error;
int fref = 14318;
- /* this really could be done with more intelligence */
+ /* this really could be done with more intelligence --
+ 255*63*4 = 64260 iterations is silly */
best_error = freq;
best_n = best_m = best_k = 0;
for(n = 1; n < 256; n++) {
@@ -703,13 +949,10 @@
k = best_k;
*freq_out = fref*(n + 2)/(m + 2)/(1 << k);
- DPRINTK("freq = %d kHz, freq_out = %d kHz\n", freq, *freq_out);
- DPRINTK("N = %d, M = %d, K = %d\n", n, m, k);
-
return (n << 8) | (m << 2) | k;
}
-static void banshee_write_regs(struct banshee_reg* reg) {
+static void do_write_regs(struct banshee_reg* reg) {
int i;
banshee_wait_idle();
@@ -747,17 +990,25 @@
vga_enable_palette();
vga_enable_video();
- banshee_make_room(9);
+ banshee_make_room(11);
tdfx_outl(VGAINIT0, reg->vgainit0);
tdfx_outl(DACMODE, reg->dacmode);
tdfx_outl(VIDDESKSTRIDE, reg->stride);
- tdfx_outl(HWCURPATADDR, reg->cursloc);
+ if (nohwcursor) {
+ tdfx_outl(HWCURPATADDR, 0);
+ } else {
+ tdfx_outl(HWCURPATADDR, reg->curspataddr);
+ tdfx_outl(HWCURC0, reg->cursc0);
+ tdfx_outl(HWCURC1, reg->cursc1);
+ tdfx_outl(HWCURLOC, reg->cursloc);
+ }
+
tdfx_outl(VIDSCREENSIZE, reg->screensize);
tdfx_outl(VIDDESKSTART, reg->startaddr);
tdfx_outl(VIDPROCCFG, reg->vidcfg);
tdfx_outl(VGAINIT1, reg->vgainit1);
- banshee_make_room(7);
+ banshee_make_room(8);
tdfx_outl(SRCBASE, reg->srcbase);
tdfx_outl(DSTBASE, reg->dstbase);
tdfx_outl(COMMANDEXTRA_2D, 0);
@@ -765,15 +1016,16 @@
tdfx_outl(CLIP0MAX, 0x0fff0fff);
tdfx_outl(CLIP1MIN, 0);
tdfx_outl(CLIP1MAX, 0x0fff0fff);
+ tdfx_outl(SRCXY, 0);
banshee_wait_idle();
}
-static unsigned long tdfx_lfb_size(void) {
- __u32 draminit0 = 0;
- __u32 draminit1 = 0;
- __u32 miscinit1 = 0;
- __u32 lfbsize = 0;
+static unsigned long do_lfb_size(void) {
+ u32 draminit0 = 0;
+ u32 draminit1 = 0;
+ u32 miscinit1 = 0;
+ u32 lfbsize = 0;
int sgram_p = 0;
if(!((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) ||
@@ -782,7 +1034,7 @@
draminit0 = tdfx_inl(DRAMINIT0);
draminit1 = tdfx_inl(DRAMINIT1);
-
+
sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
lfbsize = sgram_p ?
@@ -794,19 +1046,53 @@
miscinit1 = tdfx_inl(MISCINIT1);
miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
miscinit1 |= MISCINIT1_CLUT_INV;
+
+ banshee_make_room(1);
tdfx_outl(MISCINIT1, miscinit1);
return lfbsize;
}
-static void fbcon_banshee_bmove(struct display* p,
+/* -------------------------------------------------------------------------
+ * Hardware independent part, interface to the world
+ * ------------------------------------------------------------------------- */
+
+#define tdfx_cfb24_putc tdfx_cfb32_putc
+#define tdfx_cfb24_putcs tdfx_cfb32_putcs
+#define tdfx_cfb24_clear tdfx_cfb32_clear
+
+static void tdfx_cfbX_clear_margins(struct vc_data* conp, struct display* p,
+ int bottom_only)
+{
+ unsigned int cw=fontwidth(p);
+ unsigned int ch=fontheight(p);
+ unsigned int rw=p->var.xres % cw; // it be in a non-standard mode or not?
+ unsigned int bh=p->var.yres % ch;
+ unsigned int rs=p->var.xres - rw;
+ unsigned int bs=p->var.yres - bh;
+
+ if (!bottom_only && rw) {
+ do_fillrect( p->var.xoffset+rs, 0,
+ rw, p->var.yres_virtual, 0,
+ fb_info.current_par.lpitch,
+ fb_info.current_par.bpp, ROP_COPY);
+ }
+
+ if (bh) {
+ do_fillrect( p->var.xoffset, p->var.yoffset+bs,
+ rs, bh, 0,
+ fb_info.current_par.lpitch,
+ fb_info.current_par.bpp, ROP_COPY);
+ }
+}
+static void tdfx_cfbX_bmove(struct display* p,
int sy,
int sx,
int dy,
int dx,
int height,
int width) {
- banshee_bitblt(fontwidth(p)*sx,
+ do_bitblt(fontwidth(p)*sx,
fontheight(p)*sy,
fontwidth(p)*dx,
fontheight(p)*dy,
@@ -815,64 +1101,221 @@
fb_info.current_par.lpitch,
fb_info.current_par.bpp);
}
+static void tdfx_cfb8_putc(struct vc_data* conp,
+ struct display* p,
+ int c, int yy,int xx)
+{
+ u32 fgx,bgx;
+ fgx=attr_fgcol(p, c);
+ bgx=attr_bgcol(p, c);
+ do_putc( fgx,bgx,p,c,yy,xx );
+}
+
+static void tdfx_cfb16_putc(struct vc_data* conp,
+ struct display* p,
+ int c, int yy,int xx)
+{
+ u32 fgx,bgx;
+ fgx=((u16*)p->dispsw_data)[attr_fgcol(p,c)];
+ bgx=((u16*)p->dispsw_data)[attr_bgcol(p,c)];
+ do_putc( fgx,bgx,p,c,yy,xx );
+}
+
+static void tdfx_cfb32_putc(struct vc_data* conp,
+ struct display* p,
+ int c, int yy,int xx)
+{
+ u32 fgx,bgx;
+ fgx=((u32*)p->dispsw_data)[attr_fgcol(p,c)];
+ bgx=((u32*)p->dispsw_data)[attr_bgcol(p,c)];
+ do_putc( fgx,bgx,p,c,yy,xx );
+}
+static void tdfx_cfb8_putcs(struct vc_data* conp,
+ struct display* p,
+ const unsigned short *s,int count,int yy,int xx)
+{
+ u32 fgx,bgx;
+ fgx=attr_fgcol(p, *s);
+ bgx=attr_bgcol(p, *s);
+ do_putcs( fgx,bgx,p,s,count,yy,xx );
+}
+static void tdfx_cfb16_putcs(struct vc_data* conp,
+ struct display* p,
+ const unsigned short *s,int count,int yy,int xx)
+{
+ u32 fgx,bgx;
+ fgx=((u16*)p->dispsw_data)[attr_fgcol(p,*s)];
+ bgx=((u16*)p->dispsw_data)[attr_bgcol(p,*s)];
+ do_putcs( fgx,bgx,p,s,count,yy,xx );
+}
+static void tdfx_cfb32_putcs(struct vc_data* conp,
+ struct display* p,
+ const unsigned short *s,int count,int yy,int xx)
+{
+ u32 fgx,bgx;
+ fgx=((u32*)p->dispsw_data)[attr_fgcol(p,*s)];
+ bgx=((u32*)p->dispsw_data)[attr_bgcol(p,*s)];
+ do_putcs( fgx,bgx,p,s,count,yy,xx );
+}
-static void fbcon_banshee_clear(struct vc_data* conp,
+static void tdfx_cfb8_clear(struct vc_data* conp,
struct display* p,
int sy,
int sx,
int height,
int width) {
- unsigned int bg;
+ u32 bg;
bg = attr_bgcol_ec(p,conp);
- banshee_fillrect(fontwidth(p)*sx,
+ do_fillrect(fontwidth(p)*sx,
fontheight(p)*sy,
fontwidth(p)*width,
fontheight(p)*height,
bg,
fb_info.current_par.lpitch,
- fb_info.current_par.bpp);
+ fb_info.current_par.bpp,ROP_COPY);
}
+static void tdfx_cfb16_clear(struct vc_data* conp,
+ struct display* p,
+ int sy,
+ int sx,
+ int height,
+ int width) {
+ u32 bg;
+
+ bg = ((u16*)p->dispsw_data)[attr_bgcol_ec(p,conp)];
+ do_fillrect(fontwidth(p)*sx,
+ fontheight(p)*sy,
+ fontwidth(p)*width,
+ fontheight(p)*height,
+ bg,
+ fb_info.current_par.lpitch,
+ fb_info.current_par.bpp,ROP_COPY);
+}
+
+static void tdfx_cfb32_clear(struct vc_data* conp,
+ struct display* p,
+ int sy,
+ int sx,
+ int height,
+ int width) {
+ u32 bg;
+
+ bg = ((u32*)p->dispsw_data)[attr_bgcol_ec(p,conp)];
+ do_fillrect(fontwidth(p)*sx,
+ fontheight(p)*sy,
+ fontwidth(p)*width,
+ fontheight(p)*height,
+ bg,
+ fb_info.current_par.lpitch,
+ fb_info.current_par.bpp,ROP_COPY);
+}
+static void tdfx_cfbX_revc(struct display *p, int xx, int yy)
+{
+ int bpp=fb_info.current_par.bpp;
+
+ do_fillrect( xx * fontwidth(p), yy * fontheight(p),
+ fontwidth(p), fontheight(p),
+ (bpp==8) ? 0x0f : 0xffffffff,
+ fb_info.current_par.lpitch, bpp, ROP_XOR);
+
+}
+static void tdfx_cfbX_cursor(struct display *p, int mode, int x, int y)
+{
+ unsigned long flags;
+ int tip;
+ struct fb_info_tdfx *info=(struct fb_info_tdfx *)p->fb_info;
+
+ tip=p->conp->vc_cursor_type & CUR_HWMASK;
+ if (mode==CM_ERASE) {
+ if (info->cursor.state != CM_ERASE) {
+ spin_lock_irqsave(&info->DAClock,flags);
+ info->cursor.state=CM_ERASE;
+ del_timer(&(info->cursor.timer));
+ tdfx_outl(VIDPROCCFG,info->cursor.disable);
+ spin_unlock_irqrestore(&info->DAClock,flags);
+ }
+ return;
+ }
+ if ((p->conp->vc_cursor_type & CUR_HWMASK) != info->cursor.type)
+ tdfxfb_createcursor(p);
+ x *= fontwidth(p);
+ y *= fontheight(p);
+ y -= p->var.yoffset;
+ spin_lock_irqsave(&info->DAClock,flags);
+ if ((x!=info->cursor.x) ||
+ (y!=info->cursor.y) ||
+ (info->cursor.redraw)) {
+ info->cursor.x=x;
+ info->cursor.y=y;
+ info->cursor.redraw=0;
+ x += 63;
+ y += 63;
+ banshee_make_room(2);
+ tdfx_outl(VIDPROCCFG, info->cursor.disable);
+ tdfx_outl(HWCURLOC, (y << 16) + x);
+ }
+ info->cursor.state = CM_DRAW;
+ mod_timer(&info->cursor.timer,jiffies+HZ/2);
+ banshee_make_room(1);
+ tdfx_outl(VIDPROCCFG, info->cursor.enable);
+ spin_unlock_irqrestore(&info->DAClock,flags);
+ return;
+}
#ifdef FBCON_HAS_CFB8
static struct display_switch fbcon_banshee8 = {
fbcon_cfb8_setup,
- fbcon_banshee_bmove,
- fbcon_banshee_clear,
- fbcon_cfb8_putc,
- fbcon_cfb8_putcs,
- fbcon_cfb8_revc,
+ tdfx_cfbX_bmove,
+ tdfx_cfb8_clear,
+ tdfx_cfb8_putc,
+ tdfx_cfb8_putcs,
+ tdfx_cfbX_revc,
+ tdfx_cfbX_cursor,
NULL,
- NULL,
- fbcon_cfb8_clear_margins,
+ tdfx_cfbX_clear_margins,
FONTWIDTH(8)
};
#endif
#ifdef FBCON_HAS_CFB16
static struct display_switch fbcon_banshee16 = {
fbcon_cfb16_setup,
- fbcon_banshee_bmove,
- fbcon_banshee_clear,
- fbcon_cfb16_putc,
- fbcon_cfb16_putcs,
- fbcon_cfb16_revc,
+ tdfx_cfbX_bmove,
+ tdfx_cfb16_clear,
+ tdfx_cfb16_putc,
+ tdfx_cfb16_putcs,
+ tdfx_cfbX_revc,
+ tdfx_cfbX_cursor,
NULL,
+ tdfx_cfbX_clear_margins,
+ FONTWIDTH(8)
+};
+#endif
+#ifdef FBCON_HAS_CFB24
+static struct display_switch fbcon_banshee24 = {
+ fbcon_cfb24_setup,
+ tdfx_cfbX_bmove,
+ tdfx_cfb24_clear,
+ tdfx_cfb24_putc,
+ tdfx_cfb24_putcs,
+ tdfx_cfbX_revc,
+ tdfx_cfbX_cursor,
NULL,
- fbcon_cfb16_clear_margins,
+ tdfx_cfbX_clear_margins,
FONTWIDTH(8)
};
#endif
#ifdef FBCON_HAS_CFB32
static struct display_switch fbcon_banshee32 = {
fbcon_cfb32_setup,
- fbcon_banshee_bmove,
- fbcon_banshee_clear,
- fbcon_cfb32_putc,
- fbcon_cfb32_putcs,
- fbcon_cfb32_revc,
- NULL,
+ tdfx_cfbX_bmove,
+ tdfx_cfb32_clear,
+ tdfx_cfb32_putc,
+ tdfx_cfb32_putcs,
+ tdfx_cfbX_revc,
+ tdfx_cfbX_cursor,
NULL,
- fbcon_cfb32_clear_margins,
+ tdfx_cfbX_clear_margins,
FONTWIDTH(8)
};
#endif
@@ -883,13 +1326,13 @@
struct fb_info_tdfx* info) {
struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
struct banshee_reg reg;
- __u32 cpp;
- __u32 hd, hs, he, ht, hbs, hbe;
- __u32 vd, vs, ve, vt, vbs, vbe;
- __u32 wd;
+ u32 cpp;
+ u32 hd, hs, he, ht, hbs, hbe;
+ u32 vd, vs, ve, vt, vbs, vbe;
+ u32 wd;
int fout;
int freq;
-
+
memset(®, 0, sizeof(reg));
cpp = (par->bpp + 7)/8;
@@ -1018,11 +1461,21 @@
reg.vidcfg =
VIDCFG_VIDPROC_ENABLE |
VIDCFG_DESK_ENABLE |
+ VIDCFG_CURS_X11 |
((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
(cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
+
+ fb_info.cursor.enable=reg.vidcfg | VIDCFG_HWCURSOR_ENABLE;
+ fb_info.cursor.disable=reg.vidcfg;
+
reg.stride = par->width*cpp;
reg.cursloc = 0;
-
+
+ reg.cursc0 = 0;
+ reg.cursc1 = 0xffffff;
+
+ reg.curspataddr = fb_info.cursor.cursorimage;
+
reg.startaddr = par->baseline*reg.stride;
reg.srcbase = reg.startaddr;
reg.dstbase = reg.startaddr;
@@ -1037,18 +1490,19 @@
reg.dacmode |= DACMODE_2X;
reg.vidcfg |= VIDCFG_2X;
}
- reg.vidpll = banshee_calc_pll(freq, &fout);
+ reg.vidpll = do_calc_pll(freq, &fout);
#if 0
- reg.mempll = banshee_calc_pll(..., &fout);
- reg.gfxpll = banshee_calc_pll(..., &fout);
+ reg.mempll = do_calc_pll(..., &fout);
+ reg.gfxpll = do_calc_pll(..., &fout);
#endif
reg.screensize = par->width | (par->height << 12);
reg.vidcfg &= ~VIDCFG_HALF_MODE;
- banshee_write_regs(®);
+ do_write_regs(®);
i->current_par = *par;
+
}
static int tdfxfb_decode_var(const struct fb_var_screeninfo* var,
@@ -1058,6 +1512,7 @@
if(var->bits_per_pixel != 8 &&
var->bits_per_pixel != 16 &&
+ var->bits_per_pixel != 24 &&
var->bits_per_pixel != 32) {
DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
return -EINVAL;
@@ -1078,18 +1533,12 @@
return -EINVAL;
}
- if(nopan && nowrap) {
- if(var->yres != var->yres_virtual) {
- DPRINTK("virtual y resolution != physical y resolution not supported\n");
- return -EINVAL;
- }
- } else {
- if(var->yres > var->yres_virtual) {
- DPRINTK("virtual y resolution < physical y resolution not possible\n");
- return -EINVAL;
- }
+ if(var->yres > var->yres_virtual) {
+ DPRINTK("virtual y resolution < physical y resolution not possible\n");
+ return -EINVAL;
}
+ /* fixme: does Voodoo3 support interlace? Banshee doesn't */
if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
DPRINTK("interlace not supported\n");
return -EINVAL;
@@ -1106,8 +1555,9 @@
par->height_virt = var->yres_virtual;
par->bpp = var->bits_per_pixel;
par->ppitch = var->bits_per_pixel;
- par->lpitch = par->width*par->ppitch/8;
-
+ par->lpitch = par->width* ((par->ppitch+7)>>3);
+ par->cmap_len = (par->bpp == 8) ? 256 : 16;
+
par->baseline = 0;
if(par->width < 320 || par->width > 2048) {
@@ -1190,6 +1640,11 @@
v.blue.offset = 0;
v.blue.length = 5;
break;
+ case 24:
+ v.red.offset=16;
+ v.green.offset=8;
+ v.blue.offset=0;
+ v.red.length = v.green.length = v.blue.length = 8;
case 32:
v.red.offset = 16;
v.green.offset = 8;
@@ -1230,10 +1685,10 @@
switch(info->dev) {
case PCI_DEVICE_ID_3DFX_BANSHEE:
case PCI_DEVICE_ID_3DFX_VOODOO3:
- if (info->dev == PCI_DEVICE_ID_3DFX_BANSHEE)
- strcpy(fix->id, "3Dfx Banshee");
- else
- strcpy(fix->id, "3Dfx Voodoo3");
+ strcpy(fix->id,
+ info->dev == PCI_DEVICE_ID_3DFX_BANSHEE
+ ? "3Dfx Banshee"
+ : "3Dfx Voodoo3");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
fix->smem_start = (char*)info->bufbase_phys;
fix->smem_len = info->bufbase_size;
@@ -1249,12 +1704,12 @@
fix->type = FB_TYPE_PACKED_PIXELS;
fix->type_aux = 0;
fix->line_length = par->lpitch;
- fix->visual = par->bpp == 8
- ? FB_VISUAL_PSEUDOCOLOR
- : FB_VISUAL_DIRECTCOLOR;
+ fix->visual = (par->bpp == 8)
+ ? FB_VISUAL_PSEUDOCOLOR
+ : FB_VISUAL_DIRECTCOLOR;
fix->xpanstep = 0;
- fix->ypanstep = (nowrap && nopan) ? 0 : 1;
+ fix->ypanstep = nopan ? 0 : 1;
fix->ywrapstep = nowrap ? 0 : 1;
break;
@@ -1290,19 +1745,20 @@
*var = fb_display[con].var;
return 0;
}
-
+
static void tdfxfb_set_disp(struct display *disp,
struct fb_info_tdfx *info,
int bpp,
int accel) {
- DPRINTK("actually, %s using acceleration!\n",
- noaccel ? "NOT" : "");
+ if (disp->dispsw && disp->conp)
+ fb_con.con_cursor(disp->conp, CM_ERASE);
switch(bpp) {
#ifdef FBCON_HAS_CFB8
case 8:
info->dispsw = noaccel ? fbcon_cfb8 : fbcon_banshee8;
disp->dispsw = &info->dispsw;
+ if (nohwcursor) fbcon_banshee8.cursor = NULL;
break;
#endif
#ifdef FBCON_HAS_CFB16
@@ -1310,6 +1766,15 @@
info->dispsw = noaccel ? fbcon_cfb16 : fbcon_banshee16;
disp->dispsw = &info->dispsw;
disp->dispsw_data = info->fbcon_cmap.cfb16;
+ if (nohwcursor) fbcon_banshee16.cursor = NULL;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ info->dispsw = noaccel ? fbcon_cfb24 : fbcon_banshee24;
+ disp->dispsw = &info->dispsw;
+ disp->dispsw_data = info->fbcon_cmap.cfb24;
+ if (nohwcursor) fbcon_banshee24.cursor = NULL;
break;
#endif
#ifdef FBCON_HAS_CFB32
@@ -1317,161 +1782,159 @@
info->dispsw = noaccel ? fbcon_cfb32 : fbcon_banshee32;
disp->dispsw = &info->dispsw;
disp->dispsw_data = info->fbcon_cmap.cfb32;
+ if (nohwcursor) fbcon_banshee32.cursor = NULL;
break;
#endif
default:
info->dispsw = fbcon_dummy;
disp->dispsw = &info->dispsw;
}
+
}
static int tdfxfb_set_var(struct fb_var_screeninfo *var,
int con,
struct fb_info *fb) {
- struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
- struct tdfxfb_par par;
- struct display *display;
- int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
- int activate = var->activate;
-
- if(con >= 0)
- display = &fb_display[con];
- else
- display = fb->disp; /* used during initialization */
-
- if((err = tdfxfb_decode_var(var, &par, info)))
- return err;
-
- tdfxfb_encode_var(var, &par, info);
-
- if((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- oldxres = display->var.xres;
- oldyres = display->var.yres;
- oldvxres = display->var.xres_virtual;
- oldvyres = display->var.yres_virtual;
- oldbpp = display->var.bits_per_pixel;
- oldaccel = display->var.accel_flags;
- display->var = *var;
- if(con < 0 ||
- oldxres != var->xres ||
- oldyres != var->yres ||
- oldvxres != var->xres_virtual ||
- oldvyres != var->yres_virtual ||
- oldbpp != var->bits_per_pixel ||
- oldaccel != var->accel_flags) {
- struct fb_fix_screeninfo fix;
-
- tdfxfb_encode_fix(&fix, &par, info);
- display->screen_base = (char *)info->bufbase_virt;
- display->visual = fix.visual;
- display->type = fix.type;
- display->type_aux = fix.type_aux;
- display->ypanstep = fix.ypanstep;
- display->ywrapstep = fix.ywrapstep;
- display->line_length = fix.line_length;
- display->next_line = fix.line_length;
- display->can_soft_blank = 1;
- display->inverse = inverse;
- accel = var->accel_flags & FB_ACCELF_TEXT;
- tdfxfb_set_disp(display, info, par.bpp, accel);
-
- if(nopan && nowrap) {
- display->scrollmode = SCROLL_YREDRAW;
-#ifdef FBCON_HAS_CFB8
- fbcon_banshee8.bmove = fbcon_redraw_bmove;
-#endif
-#ifdef FBCON_HAS_CFB16
- fbcon_banshee16.bmove = fbcon_redraw_bmove;
-#endif
-#ifdef FBCON_HAS_CFB32
- fbcon_banshee32.bmove = fbcon_redraw_bmove;
-#endif
+ struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
+ struct tdfxfb_par par;
+ struct display *display;
+ int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
+ int activate = var->activate;
+ int j,k;
+
+ if(con >= 0)
+ display = &fb_display[con];
+ else
+ display = fb->disp; /* used during initialization */
+
+ if((err = tdfxfb_decode_var(var, &par, info)))
+ return err;
+
+ tdfxfb_encode_var(var, &par, info);
+
+ if((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+ oldxres = display->var.xres;
+ oldyres = display->var.yres;
+ oldvxres = display->var.xres_virtual;
+ oldvyres = display->var.yres_virtual;
+ oldbpp = display->var.bits_per_pixel;
+ oldaccel = display->var.accel_flags;
+ display->var = *var;
+ if(con < 0 ||
+ oldxres != var->xres ||
+ oldyres != var->yres ||
+ oldvxres != var->xres_virtual ||
+ oldvyres != var->yres_virtual ||
+ oldbpp != var->bits_per_pixel ||
+ oldaccel != var->accel_flags) {
+ struct fb_fix_screeninfo fix;
+
+ tdfxfb_encode_fix(&fix, &par, info);
+ display->screen_base = (char *)info->bufbase_virt;
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->line_length = fix.line_length;
+ display->next_line = fix.line_length;
+ display->can_soft_blank = 1;
+ display->inverse = inverse;
+ accel = var->accel_flags & FB_ACCELF_TEXT;
+ tdfxfb_set_disp(display, info, par.bpp, accel);
+
+ if(nopan) display->scrollmode = SCROLL_YREDRAW;
+
+ if (info->fb_info.changevar)
+ (*info->fb_info.changevar)(con);
}
- if (info->fb_info.changevar)
- (*info->fb_info.changevar)(con);
- }
- if(!info->fb_info.display_fg ||
- info->fb_info.display_fg->vc_num == con ||
- con < 0)
- tdfxfb_set_par(&par, info);
- if(oldbpp != var->bits_per_pixel || con < 0) {
- if((err = fb_alloc_cmap(&display->cmap, 0, 0)))
- return err;
- tdfxfb_install_cmap(con, &info->fb_info);
- }
- }
+ if (var->bits_per_pixel==8)
+ for(j = 0; j < 16; j++) {
+ k = color_table[j];
+ fb_info.palette[j].red = default_red[k];
+ fb_info.palette[j].green = default_grn[k];
+ fb_info.palette[j].blue = default_blu[k];
+ }
+
+ del_timer(&(info->cursor.timer));
+ fb_info.cursor.state=CM_ERASE;
+ if(!info->fb_info.display_fg ||
+ info->fb_info.display_fg->vc_num == con ||
+ con < 0)
+ tdfxfb_set_par(&par, info);
+ if (!nohwcursor)
+ if (display && display->conp)
+ tdfxfb_createcursor( display );
+ info->cursor.redraw=1;
+ if(oldbpp != var->bits_per_pixel || con < 0) {
+ if((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+ return err;
+ tdfxfb_install_cmap(display, &(info->fb_info));
+ }
+ }
- return 0;
+ return 0;
}
static int tdfxfb_pan_display(struct fb_var_screeninfo* var,
int con,
struct fb_info* fb) {
struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
- __u32 addr;
- if(nowrap && nopan) {
- return -EINVAL;
- } else {
- if(var->xoffset)
- return -EINVAL;
- if(var->yoffset < 0)
- return -EINVAL;
- if(nopan && var->yoffset > var->yres_virtual)
- return -EINVAL;
- if(nowrap && var->yoffset + var->yres > var->yres_virtual)
- return -EINVAL;
-
- i->current_par.baseline = var->yoffset;
-
- addr = var->yoffset*i->current_par.lpitch;
- tdfx_outl(VIDDESKSTART, addr);
- tdfx_outl(SRCBASE, addr);
- tdfx_outl(DSTBASE, addr);
- return 0;
- }
+ if(nopan) return -EINVAL;
+ if(var->xoffset) return -EINVAL;
+ if(var->yoffset > var->yres_virtual) return -EINVAL;
+ if(nowrap &&
+ (var->yoffset + var->yres > var->yres_virtual)) return -EINVAL;
+
+ if (con==currcon)
+ do_pan_var(var,i);
+
+ fb_display[con].var.xoffset=var->xoffset;
+ fb_display[con].var.yoffset=var->yoffset;
+ return 0;
}
static int tdfxfb_get_cmap(struct fb_cmap *cmap,
int kspc,
int con,
struct fb_info *fb) {
- if(!fb->display_fg || con == fb->display_fg->vc_num) {
- /* current console? */
- return fb_get_cmap(cmap, kspc, tdfxfb_getcolreg, fb);
- } else if(fb_display[con].cmap.len) {
- /* non default colormap? */
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- } else {
- int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
- fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
- }
- return 0;
+
+ struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
+ struct display *d=(con<0) ? fb->disp : fb_display + con;
+
+ if(con == currcon) {
+ /* current console? */
+ return fb_get_cmap(cmap, kspc, tdfxfb_getcolreg, fb);
+ } else if(d->cmap.len) {
+ /* non default colormap? */
+ fb_copy_cmap(&d->cmap, cmap, kspc ? 0 : 2);
+ } else {
+ fb_copy_cmap(fb_default_cmap(i->current_par.cmap_len), cmap, kspc ? 0 : 2);
+ }
+ return 0;
}
static int tdfxfb_set_cmap(struct fb_cmap *cmap,
int kspc,
int con,
struct fb_info *fb) {
- int err;
- struct display *disp;
+ struct display *d=(con<0) ? fb->disp : fb_display + con;
+ struct fb_info_tdfx *i = (struct fb_info_tdfx*)fb;
- if(con >= 0)
- disp = &fb_display[con];
- else
- disp = fb->disp;
- if(!disp->cmap.len) { /* no colormap allocated? */
- int size = disp->var.bits_per_pixel == 16 ? 32 : 256;
- if((err = fb_alloc_cmap(&disp->cmap, size, 0)))
- return err;
- }
- if(!fb->display_fg || con == fb->display_fg->vc_num) {
- /* current console? */
- return fb_set_cmap(cmap, kspc, tdfxfb_setcolreg, fb);
- } else {
- fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
- }
- return 0;
+ int cmap_len= (i->current_par.bpp == 8) ? 256 : 16;
+ if (d->cmap.len!=cmap_len) {
+ int err;
+ if((err = fb_alloc_cmap(&d->cmap, cmap_len, 0)))
+ return err;
+ }
+ if(con == currcon) {
+ /* current console? */
+ return fb_set_cmap(cmap, kspc, tdfxfb_setcolreg, fb);
+ } else {
+ fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1);
+ }
+ return 0;
}
static int tdfxfb_ioctl(struct inode *inode,
@@ -1480,7 +1943,16 @@
u_long arg,
int con,
struct fb_info *fb) {
- return -EINVAL;
+/* These IOCTLs ar just for testing only...
+ switch (cmd) {
+ case 0x4680:
+ nowrap=nopan=0;
+ return 0;
+ case 0x4681:
+ nowrap=nopan=1;
+ return 0;
+ }*/
+ return -EINVAL;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
@@ -1490,8 +1962,7 @@
#endif
struct pci_dev *pdev = NULL;
struct fb_var_screeninfo var;
- int j, k;
-
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
if(!pcibios_present()) return;
#else
@@ -1503,7 +1974,10 @@
(pdev->vendor == PCI_VENDOR_ID_3DFX) &&
((pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE) ||
(pdev->device == PCI_DEVICE_ID_3DFX_VOODOO3))) {
-
+ char* name = pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE
+ ? "Banshee"
+ : "Voodoo3";
+
fb_info.dev = pdev->device;
fb_info.max_pixclock =
pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE
@@ -1512,82 +1986,79 @@
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
fb_info.regbase_phys = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
- fb_info.regbase_size = 1 << 25;
+ fb_info.regbase_size = 1 << 24;
fb_info.regbase_virt =
- (__u32)ioremap_nocache(fb_info.regbase_phys, 1 << 25);
+ (u32)ioremap_nocache(fb_info.regbase_phys, 1 << 24);
if(!fb_info.regbase_virt) {
- if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
- printk("fb: Can't remap Banshee register area.\n");
- else
- printk("fb: Can't remap Voodoo3 register area.\n");
+ printk("fb: Can't remap %s register area.\n", name);
return;
}
fb_info.bufbase_phys = pdev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK;
- if(!(fb_info.bufbase_size = tdfx_lfb_size())) {
- if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
- printk("fb: Can't count Banshee memory.\n");
- else
- printk("fb: Can't count Voodoo3 memory.\n");
+ if(!(fb_info.bufbase_size = do_lfb_size())) {
+ printk("fb: Can't count %s memory.\n", name);
iounmap((void*)fb_info.regbase_virt);
return;
}
fb_info.bufbase_virt =
- (__u32)ioremap_nocache(fb_info.bufbase_phys, 1 << 25);
+ (u32)ioremap_nocache(fb_info.bufbase_phys, fb_info.bufbase_size);
if(!fb_info.regbase_virt) {
- if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
- printk("fb: Can't remap Banshee framebuffer.\n");
- else
- printk("fb: Can't remap Voodoo3 framebuffer.\n");
+ printk("fb: Can't remap %s framebuffer.\n", name);
iounmap((void*)fb_info.regbase_virt);
return;
}
+
+ fb_info.iobase = pdev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK;
#else
fb_info.regbase_phys = pdev->resource[0].start;
- fb_info.regbase_size = 1 << 25;
+ fb_info.regbase_size = 1 << 24;
fb_info.regbase_virt =
- (__u32)ioremap_nocache(fb_info.regbase_phys, 1 << 25);
+ (u32)ioremap_nocache(fb_info.regbase_phys, 1 << 24);
if(!fb_info.regbase_virt) {
- if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
- printk("fb: Can't remap Banshee register area.\n");
- else
- printk("fb: Can't remap Voodoo3 register area.\n");
+ printk("fb: Can't remap %s register area.\n", name);
return -ENXIO;
}
fb_info.bufbase_phys = pdev->resource[1].start;
- if(!(fb_info.bufbase_size = tdfx_lfb_size())) {
+ if(!(fb_info.bufbase_size = do_lfb_size())) {
iounmap((void*)fb_info.regbase_virt);
- if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
- printk("fb: Can't count Banshee memory.\n");
- else
- printk("fb: Can't count Voodoo3 memory.\n");
+ printk("fb: Can't count %s memory.\n", name);
return -ENXIO;
}
fb_info.bufbase_virt =
- (__u32)ioremap_nocache(fb_info.bufbase_phys, 1 << 25);
+ (u32)ioremap_nocache(fb_info.bufbase_phys, fb_info.bufbase_size);
if(!fb_info.regbase_virt) {
- if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
- printk("fb: Can't remap Banshee framebuffer.\n");
- else
- printk("fb: Can't remap Voodoo3 framebuffer.\n");
+ printk("fb: Can't remap %s framebuffer.\n", name);
iounmap((void*)fb_info.regbase_virt);
return -ENXIO;
}
+
+ fb_info.iobase = pdev->resource[2].start;
#endif
- if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
- printk("fb: Banshee memory = %ldK\n", fb_info.bufbase_size >> 10);
- else
- printk("fb: Voodoo3 memory = %ldK\n", fb_info.bufbase_size >> 10);
-
+ printk("fb: %s memory = %ldK\n", name, fb_info.bufbase_size >> 10);
+
+#ifdef CONFIG_MTRR
+ if (!nomtrr) {
+ if (mtrr_add(fb_info.bufbase_phys, fb_info.bufbase_size,
+ MTRR_TYPE_WRCOMB, 1)>=0)
+ printk("fb: MTRR's turned on\n");
+ }
+#endif
+
/* clear framebuffer memory */
memset_io(fb_info.bufbase_virt, 0, fb_info.bufbase_size);
-
- if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
- strcpy(fb_info.fb_info.modename, "3Dfx Banshee");
- else
- strcpy(fb_info.fb_info.modename, "3Dfx Voodoo3");
+ currcon = -1;
+ if (!nohwcursor) tdfxfb_hwcursor_init();
+
+ fb_info.cursor.timer.function = do_flashcursor;
+ fb_info.cursor.state = CM_ERASE;
+ fb_info.cursor.timer.prev = fb_info.cursor.timer.next=NULL;
+ fb_info.cursor.timer.data = (unsigned long)(&fb_info);
+ spin_lock_init(&fb_info.DAClock);
+
+ strcpy(fb_info.fb_info.modename, "3Dfx ");
+ strcat(fb_info.fb_info.modename, name);
fb_info.fb_info.changevar = NULL;
fb_info.fb_info.node = -1;
fb_info.fb_info.fbops = &tdfxfb_ops;
@@ -1624,6 +2095,7 @@
else var.accel_flags |= FB_ACCELF_TEXT;
if(tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
+ /* this is getting really bad!... */
printk("tdfxfb: can't decode default video mode\n");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
return;
@@ -1634,33 +2106,7 @@
}
fb_info.disp.screen_base = (void*)fb_info.bufbase_virt;
- fb_info.disp.visual =
- var.bits_per_pixel == 8
- ? FB_VISUAL_PSEUDOCOLOR
- : FB_VISUAL_DIRECTCOLOR;
- fb_info.disp.type = FB_TYPE_PACKED_PIXELS;
- fb_info.disp.type_aux = 0;
-
- fb_info.disp.ypanstep = (nowrap && nopan) ? 0 : 1;
- fb_info.disp.ywrapstep = nowrap ? 0 : 1;
-
- fb_info.disp.line_length =
- fb_info.disp.next_line =
- var.xres*(var.bits_per_pixel + 7)/8;
- fb_info.disp.can_soft_blank = 1;
- fb_info.disp.inverse = inverse;
- fb_info.disp.scrollmode = SCROLL_YREDRAW;
fb_info.disp.var = var;
- tdfxfb_set_disp(&fb_info.disp, &fb_info,
- var.bits_per_pixel,
- 0);
-
- for(j = 0; j < 16; j++) {
- k = color_table[j];
- fb_info.palette[j].red = default_red[k];
- fb_info.palette[j].green = default_grn[k];
- fb_info.palette[j].blue = default_blu[k];
- }
if(tdfxfb_set_var(&var, -1, &fb_info.fb_info)) {
printk("tdfxfb: can't set default video mode\n");
@@ -1694,6 +2140,7 @@
}
}
+ /* hmm, no frame suitable buffer found ... */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
return;
#else
@@ -1715,11 +2162,17 @@
inverse = 1;
fb_invert_cmaps();
} else if(!strcmp(this_opt, "noaccel")) {
- noaccel = 1;
+ noaccel = nopan = nowrap = nohwcursor = 1;
} else if(!strcmp(this_opt, "nopan")) {
nopan = 1;
} else if(!strcmp(this_opt, "nowrap")) {
nowrap = 1;
+ } else if (!strcmp(this_opt, "nohwcursor")) {
+ nohwcursor = 1;
+#ifdef CONFIG_MTRR
+ } else if (!strcmp(this_opt, "nomtrr")) {
+ nomtrr = 1;
+#endif
} else if (!strncmp(this_opt, "font:", 5)) {
strncpy(fontname, this_opt + 5, 40);
} else {
@@ -1739,26 +2192,39 @@
static int tdfxfb_switch_con(int con,
struct fb_info *fb) {
- struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
- struct tdfxfb_par par;
-
- /* Do we have to save the colormap? */
- if(fb_display[currcon].cmap.len)
- fb_get_cmap(&fb_display[currcon].cmap, 1, tdfxfb_getcolreg, fb);
-
- currcon = con;
-
- tdfxfb_decode_var(&fb_display[con].var, &par, info);
- tdfxfb_set_par(&par, info);
- tdfxfb_set_disp(&fb_display[con],
- info,
- par.bpp,
- par.accel_flags & FB_ACCELF_TEXT);
+ struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
+ struct tdfxfb_par par;
- tdfxfb_install_cmap(con, fb);
- tdfxfb_updatevar(con, fb);
-
- return 1;
+ /* Do we have to save the colormap? */
+ if (currcon>=0)
+ if(fb_display[currcon].cmap.len)
+ fb_get_cmap(&fb_display[currcon].cmap, 1, tdfxfb_getcolreg, fb);
+
+ currcon = con;
+ fb_display[currcon].var.activate = FB_ACTIVATE_NOW;
+ tdfxfb_decode_var(&fb_display[con].var, &par, info);
+ tdfxfb_set_par(&par, info);
+ if (fb_display[con].dispsw && fb_display[con].conp)
+ fb_con.con_cursor(fb_display[con].conp, CM_ERASE);
+
+ del_timer(&(info->cursor.timer));
+ fb_info.cursor.state=CM_ERASE;
+
+ if (!nohwcursor)
+ if (fb_display[con].conp)
+ tdfxfb_createcursor( &fb_display[con] );
+
+ info->cursor.redraw=1;
+
+ tdfxfb_set_disp(&fb_display[con],
+ info,
+ par.bpp,
+ par.accel_flags & FB_ACCELF_TEXT);
+
+ tdfxfb_install_cmap(&fb_display[con], fb);
+ tdfxfb_updatevar(con, fb);
+
+ return 1;
}
/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
@@ -1793,6 +2259,7 @@
dacmode &= ~(BIT(1) | BIT(3));
dacmode |= state;
+ banshee_make_room(1);
tdfx_outl(DACMODE, dacmode);
if(vgablank)
vga_disable_video();
@@ -1804,12 +2271,11 @@
static int tdfxfb_updatevar(int con,
struct fb_info* fb) {
- if(con != currcon || (nowrap && nopan)) {
- return 0;
- } else {
- struct fb_var_screeninfo* var = &fb_display[currcon].var;
- return tdfxfb_pan_display(var, con, fb);
- }
+
+ struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
+ if ((con==currcon) && (!nopan))
+ do_pan_var(&fb_display[con].var,i);
+ return 0;
}
static int tdfxfb_getcolreg(unsigned regno,
@@ -1818,15 +2284,16 @@
unsigned* blue,
unsigned* transp,
struct fb_info* fb) {
- struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
+ struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
- if(regno < 256) {
- *red = i->palette[regno].red << 8 | i->palette[regno].red;
- *green = i->palette[regno].green << 8 | i->palette[regno].green;
- *blue = i->palette[regno].blue << 8 | i->palette[regno].blue;
- *transp = 0;
- }
- return regno > 255;
+ if (regno > i->current_par.cmap_len) return 1;
+
+ *red = i->palette[regno].red;
+ *green = i->palette[regno].green;
+ *blue = i->palette[regno].blue;
+ *transp = 0;
+
+ return 0;
}
static int tdfxfb_setcolreg(unsigned regno,
@@ -1835,12 +2302,21 @@
unsigned blue,
unsigned transp,
struct fb_info* info) {
- struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
-
- if(regno < 16) {
- switch(i->current_par.bpp) {
+ struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
+ u32 rgbcol;
+ if (regno >= i->current_par.cmap_len) return 1;
+
+ i->palette[regno].red = red;
+ i->palette[regno].green = green;
+ i->palette[regno].blue = blue;
+
+ switch(i->current_par.bpp) {
#ifdef FBCON_HAS_CFB8
case 8:
+ rgbcol=(((u32)red & 0xff00) << 8) |
+ (((u32)green & 0xff00) << 0) |
+ (((u32)blue & 0xff00) >> 8);
+ do_setpalentry(regno,rgbcol);
break;
#endif
#ifdef FBCON_HAS_CFB16
@@ -1849,6 +2325,14 @@
(((u32)red & 0xf800) >> 0) |
(((u32)green & 0xfc00) >> 5) |
(((u32)blue & 0xf800) >> 11);
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ i->fbcon_cmap.cfb24[regno] =
+ (((u32)red & 0xff00) << 8) |
+ (((u32)green & 0xff00) << 0) |
+ (((u32)blue & 0xff00) >> 8);
break;
#endif
#ifdef FBCON_HAS_CFB32
@@ -1862,30 +2346,105 @@
default:
DPRINTK("bad depth %u\n", i->current_par.bpp);
break;
- }
- }
- if(regno < 256) {
- i->palette[regno].red = red >> 8;
- i->palette[regno].green = green >> 8;
- i->palette[regno].blue = blue >> 8;
- if(i->current_par.bpp == 8) {
- vga_outb(DAC_IW, (unsigned char)regno);
- vga_outb(DAC_D, (unsigned char)(red >> 8));
- vga_outb(DAC_D, (unsigned char)(green >> 8));
- vga_outb(DAC_D, (unsigned char)(blue >> 8));
- }
- }
- return regno > 255;
+ }
+ return 0;
}
-static void tdfxfb_install_cmap(int con,
- struct fb_info* info) {
- if(con != currcon) return;
- if(fb_display[con].cmap.len) {
- fb_set_cmap(&fb_display[con].cmap, 1, tdfxfb_setcolreg, info);
- } else {
- int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
- fb_set_cmap(fb_default_cmap(size), 1, tdfxfb_setcolreg, info);
- }
+static void tdfxfb_install_cmap(struct display *d,struct fb_info *info)
+{
+ struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
+
+ if(d->cmap.len) {
+ fb_set_cmap(&(d->cmap), 1, tdfxfb_setcolreg, info);
+ } else {
+ fb_set_cmap(fb_default_cmap(i->current_par.cmap_len), 1,
+ tdfxfb_setcolreg, info);
+ }
+}
+
+static void tdfxfb_createcursorshape(struct display* p)
+{
+ unsigned int h,cu,cd;
+
+ h=fontheight(p);
+ cd=h;
+ if (cd >= 10) cd --;
+ fb_info.cursor.type=p->conp->vc_cursor_type & CUR_HWMASK;
+ switch (fb_info.cursor.type) {
+ case CUR_NONE:
+ cu=cd;
+ break;
+ case CUR_UNDERLINE:
+ cu=cd - 2;
+ break;
+ case CUR_LOWER_THIRD:
+ cu=(h * 2) / 3;
+ break;
+ case CUR_LOWER_HALF:
+ cu=h / 2;
+ break;
+ case CUR_TWO_THIRDS:
+ cu=h / 3;
+ break;
+ case CUR_BLOCK:
+ default:
+ cu=0;
+ cd = h;
+ break;
+ }
+ fb_info.cursor.w=fontwidth(p);
+ fb_info.cursor.u=cu;
+ fb_info.cursor.d=cd;
+}
+
+static void tdfxfb_createcursor(struct display *p)
+{
+ u8 *cursorbase;
+ u32 xline;
+ unsigned int i;
+ unsigned int h,to;
+
+ tdfxfb_createcursorshape(p);
+ xline = (1 << fb_info.cursor.w)-1;
+ cursorbase=(u8*)fb_info.bufbase_virt;
+ h=fb_info.cursor.cursorimage;
+
+ to=fb_info.cursor.u;
+ for (i = 0; i < to; i++) {
+ writel(0, cursorbase+h);
+ writel(0, cursorbase+h+4);
+ writel(~0, cursorbase+h+8);
+ writel(~0, cursorbase+h+12);
+ h += 16;
+ }
+
+ to = fb_info.cursor.d;
+
+ for (; i < to; i++) {
+ writel(xline, cursorbase+h);
+ writel(0, cursorbase+h+4);
+ writel(~0, cursorbase+h+8);
+ writel(~0, cursorbase+h+12);
+ h += 16;
+ }
+
+ for (; i < 64; i++) {
+ writel(0, cursorbase+h);
+ writel(0, cursorbase+h+4);
+ writel(~0, cursorbase+h+8);
+ writel(~0, cursorbase+h+12);
+ h += 16;
+ }
+}
+
+static void tdfxfb_hwcursor_init(void)
+{
+ unsigned int start;
+ start = (fb_info.bufbase_size-1024) & PAGE_MASK;
+ fb_info.bufbase_size=start;
+ fb_info.cursor.cursorimage=fb_info.bufbase_size;
+ printk("tdfxfb: reserving 1024 bytes for the hwcursor at 0x%08lx\n",
+ fb_info.regbase_virt+fb_info.cursor.cursorimage);
}
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)