Linux-2.4.0-test2
[davej-history.git] / drivers / video / sisfb.c
blobd42448fbf8b08648ea2dbaabf89ec4826ae81c3b
1 /*
2 * SiS 300/630/540 frame buffer device For Kernal 2.3.x
4 * This driver is partly based on the VBE 2.0 compliant graphic
5 * boards framebuffer driver, which is
6 *
7 * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
9 */
11 #define EXPORT_SYMTAB
12 #undef SISFBDEBUG
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
18 #include <linux/mm.h>
19 #include <linux/tty.h>
20 #include <linux/malloc.h>
21 #include <linux/delay.h>
22 #include <linux/fb.h>
23 #include <linux/console.h>
24 #include <linux/selection.h>
25 #include <linux/ioport.h>
26 #include <linux/init.h>
27 #include <linux/pci.h>
28 #include <linux/vt_kern.h>
29 #include <linux/capability.h>
30 #include <linux/sisfb.h>
32 #include <asm/io.h>
33 #include <asm/mtrr.h>
35 #include <video/fbcon.h>
36 #include <video/fbcon-cfb8.h>
37 #include <video/fbcon-cfb16.h>
38 #include <video/fbcon-cfb24.h>
39 #include <video/fbcon-cfb32.h>
41 /* ------------------- Constant Definitions ------------------------- */
43 #define FALSE 0
44 #define TRUE 1
46 /* Draw Function
47 #define FBIOGET_GLYPH 0x4620
48 #define FBIOGET_HWCINFO 0x4621
50 #define BR(x) (0x8200 | (x) << 2)
52 #define BITBLT 0x00000000
53 #define COLOREXP 0x00000001
54 #define ENCOLOREXP 0x00000002
55 #define MULTIPLE_SCANLINE 0x00000003
56 #define LINE 0x00000004
57 #define TRAPAZOID_FILL 0x00000005
58 #define TRANSPARENT_BITBLT 0x00000006
60 #define SRCVIDEO 0x00000000
61 #define SRCSYSTEM 0x00000010
62 #define SRCAGP 0x00000020
64 #define PATFG 0x00000000
65 #define PATPATREG 0x00000040
66 #define PATMONO 0x00000080
68 #define X_INC 0x00010000
69 #define X_DEC 0x00000000
70 #define Y_INC 0x00020000
71 #define Y_DEC 0x00000000
73 #define NOCLIP 0x00000000
74 #define NOMERGECLIP 0x04000000
75 #define CLIPENABLE 0x00040000
76 #define CLIPWITHOUTMERGE 0x04040000
78 #define OPAQUE 0x00000000
79 #define TRANSPARENT 0x00100000
81 #define DSTAGP 0x02000000
82 #define DSTVIDEO 0x02000000
84 #define LINE_STYLE 0x00800000
85 #define NO_RESET_COUNTER 0x00400000
86 #define NO_LAST_PIXEL 0x00200000
88 /* capabilities */
89 #define TURBO_QUEUE_CAP 0x80
90 #define HW_CURSOR_CAP 0x40
92 /* VGA register Offsets */
93 #define SEQ_ADR (0x14)
94 #define SEQ_DATA (0x15)
95 #define DAC_ADR (0x18)
96 #define DAC_DATA (0x19)
97 #define CRTC_ADR (0x24)
98 #define CRTC_DATA (0x25)
100 /* SiS indexed register indexes */
101 #define IND_SIS_PASSWORD (0x05)
102 #define IND_SIS_DRAM_SIZE (0x14)
103 #define IND_SIS_MODULE_ENABLE (0x1E)
104 #define IND_SIS_PCI_ADDRESS_SET (0x20)
105 #define IND_SIS_TURBOQUEUE_ADR (0x26)
106 #define IND_SIS_TURBOQUEUE_SET (0x27)
108 /* Sis register value */
109 #define SIS_PASSWORD (0x86)
111 #define SIS_2D_ENABLE (0x40)
113 #define SIS_MEM_MAP_IO_ENABLE (0x01)
114 #define SIS_PCI_ADDR_ENABLE (0x80)
116 #define MMIO_SIZE 0x20000 /* 128K MMIO capability */
117 #define MAX_ROM_SCAN 0x10000
119 #define RESERVED_MEM_SIZE_4M 0x400000 /* 4M */
120 #define RESERVED_MEM_SIZE_8M 0x800000 /* 8M */
122 /* Mode set stuff */
123 #define DEFAULT_MODE 0
125 #define ModeInfoFlag 0x07
126 #define MemoryInfoFlag 0x1E0
127 #define MemorySizeShift 0x05
128 #define ModeVGA 0x03
129 #define ModeEGA 0x02
130 #define CRT1Len 17
131 #define DoubleScanMode 0x8000
132 #define HalfDCLK 0x1000
134 #define InterlaceMode 0x80
135 #define LineCompareOff 0x400
136 #define DACInfoFlag 0x18
138 #define VCLKStartFreq 25
140 #define SIS_Glamour 0x0300
141 #define SIS_Trojan 0x6300
142 #define SIS_Spartan 0x5300
144 /* heap stuff */
145 #define OH_ALLOC_SIZE 4000
146 #define SENTINEL 0x7fffffff
148 #define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */
149 #define HW_CURSOR_AREA_SIZE 0x1000 /* 4K */
151 /* video connection status */
152 #define VB_COMPOSITE 0x01
153 #define VB_SVIDEO 0x02
154 #define VB_SCART 0x04
155 #define VB_LCD 0x08
156 #define VB_CRT2 0x10
157 #define CRT1 0x20
158 #define VB_HDTV 0x40
160 /* ------------------- Global Variables ----------------------------- */
162 struct video_info ivideo;
164 struct GlyInfo {
165 unsigned char ch;
166 int fontwidth;
167 int fontheight;
168 u8 gmask[72];
169 int ngmask;
172 /* Supported SiS Chips list */
173 static struct board {
174 u16 vendor, device;
175 const char *name;
176 } dev_list[] = {
178 PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, {
179 PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540, "SIS 540"}, {
180 PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, "SIS 630"}, {
181 0, 0, NULL}
184 /* card parameters */
185 unsigned long rom_base;
186 unsigned long rom_vbase;
188 /* mode */
189 int video_type = FB_TYPE_PACKED_PIXELS;
190 int video_linelength;
191 int video_cmap_len;
192 int sisfb_off = 0;
194 static struct fb_var_screeninfo default_var = {
195 0, 0, 0, 0, 0, 0, 0, 0,
196 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
197 0, FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
199 FB_VMODE_NONINTERLACED,
200 {0, 0, 0, 0, 0, 0}
203 static struct display disp;
204 static struct fb_info fb_info;
205 static struct {
206 u16 blue, green, red, pad;
207 } palette[256];
208 static union {
209 #ifdef FBCON_HAS_CFB16
210 u16 cfb16[16];
211 #endif
212 #ifdef FBCON_HAS_CFB24
213 u32 cfb24[16];
214 #endif
215 #ifdef FBCON_HAS_CFB32
216 u32 cfb32[16];
217 #endif
218 } fbcon_cmap;
220 static int inverse = 0;
221 static int currcon = 0;
223 static struct display_switch sisfb_sw;
225 u8 caps = 0;
227 /* ModeSet stuff */
229 u16 P3c4, P3d4, P3c0, P3ce, P3c2, P3ca, P3c6, P3c7, P3c8, P3c9, P3da;
230 u16 CRT1VCLKLen;
231 u16 flag_clearbuffer;
232 u16 CRT1VCLKLen;
233 int ModeIDOffset, StandTable, CRT1Table, ScreenOffset, MCLKData, ECLKData;
234 int REFIndex, ModeType;
235 int VCLKData;
236 int RAMType;
238 int mode_idx = -1;
239 u8 mode_no = 0;
240 u8 rate_idx = 0;
242 static const struct _sisbios_mode {
243 char name[15];
244 u8 mode_no;
245 u16 xres;
246 u16 yres;
247 u16 bpp;
248 u16 rate_idx;
249 u16 cols;
250 u16 rows;
251 } sisbios_mode[] = {
253 "640x480x8", 0x2E, 640, 480, 8, 1, 80, 30}, {
254 "640x480x16", 0x44, 640, 480, 16, 1, 80, 30}, {
255 "640x480x32", 0x62, 640, 480, 32, 1, 80, 30}, {
256 "800x600x8", 0x30, 800, 600, 8, 2, 100, 37}, {
257 "800x600x16", 0x47, 800, 600, 16, 2, 100, 37}, {
258 "800x600x32", 0x63, 800, 600, 32, 2, 100, 37}, {
259 "1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48}, {
260 "1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48}, {
261 "1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48}, {
262 "1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64}, {
263 "1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64}, {
264 "1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64}, {
265 "1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75}, {
266 "1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75}, {
267 "1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75}, {
268 "1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75}, {
269 "1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75}, {
270 "1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75}, {
271 "\0", 0x00, 0, 0, 0, 0, 0, 0}
274 static struct _vrate {
275 u16 idx;
276 u16 xres;
277 u16 yres;
278 u16 refresh;
279 } vrate[] = {
281 1, 640, 480, 60}, {
282 2, 640, 480, 72}, {
283 3, 640, 480, 75}, {
284 4, 640, 480, 85}, {
285 5, 640, 480, 100}, {
286 6, 640, 480, 120}, {
287 7, 640, 480, 160}, {
288 8, 640, 480, 200}, {
289 1, 800, 600, 56}, {
290 2, 800, 600, 60}, {
291 3, 800, 600, 72}, {
292 4, 800, 600, 75}, {
293 5, 800, 600, 85}, {
294 6, 800, 600, 100}, {
295 7, 800, 600, 120}, {
296 8, 800, 600, 160}, {
297 1, 1024, 768, 56}, {
298 2, 1024, 768, 60}, {
299 3, 1024, 768, 72}, {
300 4, 1024, 768, 75}, {
301 5, 1024, 768, 85}, {
302 6, 1024, 768, 100}, {
303 7, 1024, 768, 120}, {
304 1, 1280, 1024, 43}, {
305 2, 1280, 1024, 60}, {
306 3, 1280, 1024, 75}, {
307 4, 1280, 1024, 85}, {
308 1, 1600, 1200, 60}, {
309 2, 1600, 1200, 65}, {
310 3, 1600, 1200, 70}, {
311 4, 1600, 1200, 75}, {
312 5, 1600, 1200, 85}, {
313 1, 1920, 1440, 60}, {
314 0, 0, 0, 0}
318 u16 DRAMType[17][5] =
319 { {0x0C, 0x0A, 0x02, 0x40, 0x39}, {0x0D, 0x0A, 0x01, 0x40, 0x48},
320 {0x0C, 0x09, 0x02, 0x20, 0x35}, {0x0D, 0x09, 0x01, 0x20, 0x44},
321 {0x0C, 0x08, 0x02, 0x10, 0x31}, {0x0D, 0x08, 0x01, 0x10, 0x40},
322 {0x0C, 0x0A, 0x01, 0x20, 0x34}, {0x0C, 0x09, 0x01, 0x08, 0x32},
323 {0x0B, 0x08, 0x02, 0x08, 0x21}, {0x0C, 0x08, 0x01, 0x08, 0x30},
324 {0x0A, 0x08, 0x02, 0x04, 0x11}, {0x0B, 0x0A, 0x01, 0x10, 0x28},
325 {0x09, 0x08, 0x02, 0x02, 0x01}, {0x0B, 0x09, 0x01, 0x08, 0x24},
326 {0x0B, 0x08, 0x01, 0x04, 0x20}, {0x0A, 0x08, 0x01, 0x02, 0x10},
327 {0x09, 0x08, 0x01, 0x01, 0x00}
330 u16 MDA_DAC[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
332 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
333 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
336 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
337 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
340 u16 CGA_DAC[] = { 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
341 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
342 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
343 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
344 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
345 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
346 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
347 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
350 u16 EGA_DAC[] = { 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
351 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
352 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
353 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
354 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
355 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
356 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
357 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
360 u16 VGA_DAC[] = { 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
361 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
362 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18,
363 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F,
364 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F,
365 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00,
366 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18,
367 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04,
368 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
369 0x0B, 0x0C, 0x0D, 0x0F, 0x10
372 /* HEAP stuff */
374 struct OH {
375 struct OH *pohNext;
376 struct OH *pohPrev;
377 unsigned long ulOffset;
378 unsigned long ulSize;
381 struct OHALLOC {
382 struct OHALLOC *pohaNext;
383 struct OH aoh[1];
386 struct HEAP {
387 struct OH ohFree;
388 struct OH ohUsed;
389 struct OH *pohFreeList;
390 struct OHALLOC *pohaChain;
392 unsigned long ulMaxFreeSize;
395 struct HEAP heap;
396 unsigned long heap_start;
397 unsigned long heap_end;
398 unsigned long heap_size;
400 unsigned int tqueue_pos;
401 unsigned long hwcursor_vbase;
403 /* Draw Function stuff */
404 u32 command_reg;
406 /* -------------------- Macro definitions --------------------------- */
408 #ifdef SISFBDEBUG
409 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
410 #else
411 #define DPRINTK(fmt, args...)
412 #endif
414 #define vgawb(reg,data) \
415 (outb(data, ivideo.vga_base+reg))
416 #define vgaww(reg,data) \
417 (outw(data, ivideo.vga_base+reg))
418 #define vgawl(reg,data) \
419 (outl(data, ivideo.vga_base+reg))
420 #define vgarb(reg) \
421 (inb(ivideo.vga_base+reg))
423 /* ---------------------- Routine Prototype ------------------------- */
425 /* Interface used by the world */
426 int sisfb_setup(char *options);
427 static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
428 struct fb_info *info);
429 static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
430 struct fb_info *info);
431 static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
432 struct fb_info *info);
433 static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
434 struct fb_info *info);
435 static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
436 struct fb_info *info);
437 static int sisfb_pan_display(struct fb_var_screeninfo *var, int con,
438 struct fb_info *info);
439 static int sisfb_ioctl(struct inode *inode, struct file *file,
440 unsigned int cmd, unsigned long arg, int con,
441 struct fb_info *info);
443 /* Interface to the low level console driver */
444 int sisfb_init(void);
445 static int sisfb_update_var(int con, struct fb_info *info);
446 static int sisfb_switch(int con, struct fb_info *info);
447 static void sisfb_blank(int blank, struct fb_info *info);
449 /* Internal routines */
450 static void crtc_to_var(struct fb_var_screeninfo *var);
451 static void sisfb_set_disp(int con, struct fb_var_screeninfo *var);
452 static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
453 unsigned *blue, unsigned *transp,
454 struct fb_info *fb_info);
455 static int sis_setcolreg(unsigned regno, unsigned red, unsigned green,
456 unsigned blue, unsigned transp,
457 struct fb_info *fb_info);
458 static void do_install_cmap(int con, struct fb_info *info);
459 static int do_set_var(struct fb_var_screeninfo *var, int isactive,
460 struct fb_info *info);
462 /* set-mode routines */
463 static void set_reg1(u16 port, u16 index, u16 data);
464 static void set_reg3(u16 port, u16 data);
465 static void set_reg4(u16 port, unsigned long data);
466 static u8 get_reg1(u16 port, u16 index);
467 static u8 get_reg2(u16 port);
468 static u32 get_reg3(u16 port);
469 static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo);
470 static int search_modeID(unsigned long ROMAddr, u16 ModeNo);
471 static int check_memory_size(unsigned long ROMAddr);
472 static void get_mode_ptr(unsigned long ROMAddr, u16 ModeNo);
473 static void set_seq_regs(unsigned long ROMAddr);
474 static void set_misc_regs(unsigned long ROMAddr);
475 static void set_crtc_regs(unsigned long ROMAddr);
476 static void set_attregs(unsigned long ROMAddr);
477 static void set_grc_regs(unsigned long ROMAddr);
478 static void ClearExt1Regs(void);
479 static u16 GetRefindexLength(unsigned long ROMAddr, u16 ModeNo);
480 static int get_rate_ptr(unsigned long ROMAddr, u16 ModeNo);
481 static void set_sync(unsigned long ROMAddr);
482 static void set_crt1_crtc(unsigned long ROMAddr);
483 static void set_crt1_offset(unsigned long ROMAddr);
484 static u16 get_vclk_len(unsigned long ROMAddr);
485 static void set_crt1_vclk(unsigned long ROMAddr);
486 static void set_vclk_state(unsigned long ROMAddr, u16 ModeNo);
487 static u16 calc_delay2(unsigned long ROMAddr, u16 key);
488 static u16 calc_delay(unsigned long ROMAddr, u16 key);
489 static void set_crt1_FIFO(unsigned long ROMAddr);
490 static void set_crt1_FIFO2(unsigned long ROMAddr);
491 static void set_crt1_mode_regs(unsigned long ROMAddr, u16 ModeNo);
492 static void set_interlace(unsigned long ROMAddr, u16 ModeNo);
493 static void write_DAC(u16 dl, u16 ah, u16 al, u16 dh);
494 static void load_DAC(unsigned long ROMAddr);
495 static void display_on(void);
497 static int SiSSetMode(u16 ModeNo);
498 static void pre_setmode(void);
499 static void post_setmode(void);
500 static void search_mode(const char *name);
501 static u8 search_refresh_rate(unsigned int rate);
503 /* heap routines */
504 static int sisfb_heap_init(void);
505 static struct OH *poh_new_node(void);
506 static struct OH *poh_allocate(unsigned long size);
507 static struct OH *poh_free(unsigned long base);
508 static void delete_node(struct OH *poh);
509 static void insert_node(struct OH *pohList, struct OH *poh);
510 static void free_node(struct OH *poh);
512 /* ---------------------- Internal Routines ------------------------- */
514 inline static u32 RD32(unsigned char *base, s32 off)
516 return readl(base + off);
519 inline static void WR32(unsigned char *base, s32 off, u32 v)
521 writel(v, base + off);
524 inline static void WR16(unsigned char *base, s32 off, u16 v)
526 writew(v, base + off);
529 inline static void WR8(unsigned char *base, s32 off, u8 v)
531 writeb(v, base + off);
534 inline static u32 regrl(s32 off)
536 return RD32(ivideo.mmio_vbase, off);
539 inline static void regwl(s32 off, u32 v)
541 WR32(ivideo.mmio_vbase, off, v);
544 inline static void regww(s32 off, u16 v)
546 WR16(ivideo.mmio_vbase, off, v);
549 inline static void regwb(s32 off, u8 v)
551 WR8(ivideo.mmio_vbase, off, v);
555 * Get CRTC registers to set var
557 static void crtc_to_var(struct fb_var_screeninfo *var)
559 u16 VRE, VBE, VRS, VBS, VDE, VT;
560 u16 HRE, HBE, HRS, HBS, HDE, HT;
561 u8 uSRdata, uCRdata, uCRdata2, uCRdata3, uMRdata;
562 int A, B, C, D, E, F, temp;
563 double hrate, drate;
565 vgawb(SEQ_ADR, 0x6);
566 uSRdata = vgarb(SEQ_DATA);
568 if (uSRdata & 0x20)
569 var->vmode = FB_VMODE_INTERLACED;
570 else
571 var->vmode = FB_VMODE_NONINTERLACED;
573 switch ((uSRdata & 0x1c) >> 2) {
574 case 0:
575 var->bits_per_pixel = 8;
576 break;
577 case 2:
578 var->bits_per_pixel = 16;
579 break;
580 case 4:
581 var->bits_per_pixel = 32;
582 break;
585 switch (var->bits_per_pixel) {
586 case 8:
587 var->red.length = 6;
588 var->green.length = 6;
589 var->blue.length = 6;
590 video_cmap_len = 256;
591 break;
592 case 16: /* RGB 565 */
593 var->red.offset = 11;
594 var->red.length = 5;
595 var->green.offset = 5;
596 var->green.length = 6;
597 var->blue.offset = 0;
598 var->blue.length = 5;
599 var->transp.offset = 0;
600 var->transp.length = 0;
601 video_cmap_len = 16;
603 break;
604 case 24: /* RGB 888 */
605 var->red.offset = 16;
606 var->red.length = 8;
607 var->green.offset = 8;
608 var->green.length = 8;
609 var->blue.offset = 0;
610 var->blue.length = 8;
611 var->transp.offset = 0;
612 var->transp.length = 0;
613 video_cmap_len = 16;
614 break;
615 case 32:
616 var->red.offset = 16;
617 var->red.length = 8;
618 var->green.offset = 8;
619 var->green.length = 8;
620 var->blue.offset = 0;
621 var->blue.length = 8;
622 var->transp.offset = 24;
623 var->transp.length = 8;
624 video_cmap_len = 16;
625 break;
628 vgawb(SEQ_ADR, 0xa);
629 uSRdata = vgarb(SEQ_DATA);
631 vgawb(CRTC_ADR, 0x6);
632 uCRdata = vgarb(CRTC_DATA);
633 vgawb(CRTC_ADR, 0x7);
634 uCRdata2 = vgarb(CRTC_DATA);
635 VT =
636 (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x01) << 8) |
637 ((u16) (uCRdata2 & 0x20) << 4) | ((u16) (uSRdata & 0x01) <<
638 10);
639 A = VT + 2;
641 vgawb(CRTC_ADR, 0x12);
642 uCRdata = vgarb(CRTC_DATA);
643 VDE =
644 (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x02) << 7) |
645 ((u16) (uCRdata2 & 0x40) << 3) | ((u16) (uSRdata & 0x02) << 9);
646 E = VDE + 1;
648 vgawb(CRTC_ADR, 0x10);
649 uCRdata = vgarb(CRTC_DATA);
650 VRS =
651 (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x04) << 6) |
652 ((u16) (uCRdata2 & 0x80) << 2) | ((u16) (uSRdata & 0x08) << 7);
653 F = VRS + 1 - E;
655 vgawb(CRTC_ADR, 0x15);
656 uCRdata = vgarb(CRTC_DATA);
657 vgawb(CRTC_ADR, 0x9);
658 uCRdata3 = vgarb(CRTC_DATA);
659 VBS =
660 (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x08) << 5) |
661 ((u16) (uCRdata3 & 0x20) << 4) | ((u16) (uSRdata & 0x04) << 8);
663 vgawb(CRTC_ADR, 0x16);
664 uCRdata = vgarb(CRTC_DATA);
665 VBE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x10) << 4);
666 temp = VBE - ((E - 1) & 511);
667 B = (temp > 0) ? temp : (temp + 512);
669 vgawb(CRTC_ADR, 0x11);
670 uCRdata = vgarb(CRTC_DATA);
671 VRE = (uCRdata & 0x0f) | ((uSRdata & 0x20) >> 1);
672 temp = VRE - ((E + F - 1) & 31);
673 C = (temp > 0) ? temp : (temp + 32);
675 D = B - F - C;
677 var->yres = var->yres_virtual = E;
678 var->upper_margin = D;
679 var->lower_margin = F;
680 var->vsync_len = C;
682 vgawb(SEQ_ADR, 0xb);
683 uSRdata = vgarb(SEQ_DATA);
685 vgawb(CRTC_ADR, 0x0);
686 uCRdata = vgarb(CRTC_DATA);
687 HT = (uCRdata & 0xff) | ((u16) (uSRdata & 0x03) << 8);
688 A = HT + 5;
690 vgawb(CRTC_ADR, 0x1);
691 uCRdata = vgarb(CRTC_DATA);
692 HDE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x0C) << 6);
693 E = HDE + 1;
695 vgawb(CRTC_ADR, 0x4);
696 uCRdata = vgarb(CRTC_DATA);
697 HRS = (uCRdata & 0xff) | ((u16) (uSRdata & 0xC0) << 2);
698 F = HRS - E - 3;
700 vgawb(CRTC_ADR, 0x2);
701 uCRdata = vgarb(CRTC_DATA);
702 HBS = (uCRdata & 0xff) | ((u16) (uSRdata & 0x30) << 4);
704 vgawb(SEQ_ADR, 0xc);
705 uSRdata = vgarb(SEQ_DATA);
706 vgawb(CRTC_ADR, 0x3);
707 uCRdata = vgarb(CRTC_DATA);
708 vgawb(CRTC_ADR, 0x5);
709 uCRdata2 = vgarb(CRTC_DATA);
710 HBE =
711 (uCRdata & 0x1f) | ((u16) (uCRdata2 & 0x80) >> 2) |
712 ((u16) (uSRdata & 0x03) << 6);
713 HRE = (uCRdata2 & 0x1f) | ((uSRdata & 0x04) << 3);
715 temp = HBE - ((E - 1) & 255);
716 B = (temp > 0) ? temp : (temp + 256);
718 temp = HRE - ((E + F + 3) & 63);
719 C = (temp > 0) ? temp : (temp + 64);
721 D = B - F - C;
723 var->xres = var->xres_virtual = E * 8;
724 var->left_margin = D * 8;
725 var->right_margin = F * 8;
726 var->hsync_len = C * 8;
728 var->activate = FB_ACTIVATE_NOW;
730 var->sync = 0;
732 uMRdata = vgarb(0x1C);
733 if (uMRdata & 0x80)
734 var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
735 else
736 var->sync |= FB_SYNC_VERT_HIGH_ACT;
738 if (uMRdata & 0x40)
739 var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
740 else
741 var->sync |= FB_SYNC_HOR_HIGH_ACT;
743 VT += 2;
744 VT <<= 1;
745 HT = (HT + 5) * 8;
747 hrate = (double) ivideo.refresh_rate * (double) VT / 2;
748 drate = hrate * HT;
749 var->pixclock = (u32) (1E12 / drate);
752 static void sisfb_set_disp(int con, struct fb_var_screeninfo *var)
754 struct fb_fix_screeninfo fix;
755 struct display *display;
756 struct display_switch *sw;
757 u32 flags;
759 if (con >= 0)
760 display = &fb_display[con];
761 else
762 display = &disp; /* used during initialization */
764 sisfb_get_fix(&fix, con, 0);
766 display->screen_base = ivideo.video_vbase;
767 display->visual = fix.visual;
768 display->type = fix.type;
769 display->type_aux = fix.type_aux;
770 display->ypanstep = fix.ypanstep;
771 display->ywrapstep = fix.ywrapstep;
772 display->line_length = fix.line_length;
773 display->next_line = fix.line_length;
774 /*display->can_soft_blank = 1; */
775 display->can_soft_blank = 0;
776 display->inverse = inverse;
777 display->var = *var;
779 save_flags(flags);
780 switch (ivideo.video_bpp) {
781 #ifdef FBCON_HAS_CFB8
782 case 8:
783 sw = &fbcon_cfb8;
784 break;
785 #endif
786 #ifdef FBCON_HAS_CFB16
787 case 15:
788 case 16:
789 sw = &fbcon_cfb16;
790 display->dispsw_data = fbcon_cmap.cfb16;
791 break;
792 #endif
793 #ifdef FBCON_HAS_CFB24
794 case 24:
795 sw = &fbcon_cfb24;
796 display->dispsw_data = fbcon_cmap.cfb24;
797 break;
798 #endif
799 #ifdef FBCON_HAS_CFB32
800 case 32:
801 sw = &fbcon_cfb32;
802 display->dispsw_data = fbcon_cmap.cfb32;
803 break;
804 #endif
805 default:
806 sw = &fbcon_dummy;
807 return;
809 memcpy(&sisfb_sw, sw, sizeof(*sw));
810 display->dispsw = &sisfb_sw;
811 restore_flags(flags);
813 display->scrollmode = SCROLL_YREDRAW;
814 sisfb_sw.bmove = fbcon_redraw_bmove;
819 * Read a single color register and split it into colors/transparent.
820 * Return != 0 for invalid regno.
823 static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
824 unsigned *blue, unsigned *transp,
825 struct fb_info *fb_info)
827 if (regno >= video_cmap_len)
828 return 1;
830 *red = palette[regno].red;
831 *green = palette[regno].green;
832 *blue = palette[regno].blue;
833 *transp = 0;
834 return 0;
838 * Set a single color register. The values supplied are already
839 * rounded down to the hardware's capabilities (according to the
840 * entries in the var structure). Return != 0 for invalid regno.
843 static int sis_setcolreg(unsigned regno, unsigned red, unsigned green,
844 unsigned blue, unsigned transp,
845 struct fb_info *fb_info)
848 if (regno >= video_cmap_len)
849 return 1;
851 palette[regno].red = red;
852 palette[regno].green = green;
853 palette[regno].blue = blue;
855 switch (ivideo.video_bpp) {
856 #ifdef FBCON_HAS_CFB8
857 case 8:
858 vgawb(DAC_ADR, regno);
859 vgawb(DAC_DATA, red >> 10);
860 vgawb(DAC_DATA, green >> 10);
861 vgawb(DAC_DATA, blue >> 10);
862 break;
863 #endif
864 #ifdef FBCON_HAS_CFB16
865 case 15:
866 case 16:
867 fbcon_cmap.cfb16[regno] =
868 ((red & 0xf800)) |
869 ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
870 break;
871 #endif
872 #ifdef FBCON_HAS_CFB24
873 case 24:
874 red >>= 8;
875 green >>= 8;
876 blue >>= 8;
877 fbcon_cmap.cfb24[regno] =
878 (red << 16) | (green << 8) | (blue);
879 break;
880 #endif
881 #ifdef FBCON_HAS_CFB32
882 case 32:
883 red >>= 8;
884 green >>= 8;
885 blue >>= 8;
886 fbcon_cmap.cfb32[regno] =
887 (red << 16) | (green << 8) | (blue);
888 break;
889 #endif
891 return 0;
894 static void do_install_cmap(int con, struct fb_info *info)
896 if (con != currcon)
897 return;
899 if (fb_display[con].cmap.len)
900 fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info);
901 else
902 fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
903 sis_setcolreg, info);
906 static int do_set_var(struct fb_var_screeninfo *var, int isactive,
907 struct fb_info *info)
909 unsigned int htotal =
910 var->left_margin + var->xres + var->right_margin +
911 var->hsync_len;
912 unsigned int vtotal =
913 var->upper_margin + var->yres + var->lower_margin +
914 var->vsync_len;
915 double drate = 0, hrate = 0;
916 int found_mode = 0;
918 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
919 vtotal <<= 1;
920 else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
921 vtotal <<= 2;
922 else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
923 var->yres <<= 1;
926 if (!htotal || !vtotal) {
927 DPRINTK("Invalid 'var' Information!\n");
928 return 1;
931 drate = 1E12 / var->pixclock;
932 hrate = drate / htotal;
933 ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
935 mode_idx = 0;
936 while ((sisbios_mode[mode_idx].mode_no != 0)
937 && (sisbios_mode[mode_idx].xres <= var->xres)) {
938 if ((sisbios_mode[mode_idx].xres == var->xres)
939 && (sisbios_mode[mode_idx].yres == var->yres)
940 && (sisbios_mode[mode_idx].bpp == var->bits_per_pixel)) {
941 mode_no = sisbios_mode[mode_idx].mode_no;
942 found_mode = 1;
943 break;
945 mode_idx++;
948 if (!found_mode) {
949 printk("sisfb does not support mode %dx%d-%d\n", var->xres,
950 var->yres, var->bits_per_pixel);
951 return 1;
954 if (search_refresh_rate(ivideo.refresh_rate) == 0) { /* not supported rate */
955 rate_idx = sisbios_mode[mode_idx].rate_idx;
956 ivideo.refresh_rate = 60;
960 if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
961 && isactive) {
962 pre_setmode();
964 if (SiSSetMode(mode_no)) {
965 DPRINTK("sisfb: set mode[0x%x]: failed\n",
966 mode_no);
967 return 1;
970 post_setmode();
972 ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
973 ivideo.video_width = sisbios_mode[mode_idx].xres;
974 ivideo.video_height = sisbios_mode[mode_idx].yres;
975 video_linelength =
976 ivideo.video_width * (ivideo.video_bpp >> 3);
978 DPRINTK("Current Mode: %dx%d-%d line_length=%d\n",
979 ivideo.video_width, ivideo.video_height,
980 ivideo.video_bpp, video_linelength);
983 return 0;
986 /* ---------------------- Draw Funtions ----------------------------- */
988 static void sis_get_glyph(struct GlyInfo *gly)
990 struct display *p = &fb_display[currcon];
991 u16 c;
992 u8 *cdat;
993 int widthb;
994 u8 *gbuf = gly->gmask;
995 int size;
998 gly->fontheight = fontheight(p);
999 gly->fontwidth = fontwidth(p);
1000 widthb = (fontwidth(p) + 7) / 8;
1002 c = gly->ch & p->charmask;
1003 if (fontwidth(p) <= 8)
1004 cdat = p->fontdata + c * fontheight(p);
1005 else
1006 cdat = p->fontdata + (c * fontheight(p) << 1);
1008 size = fontheight(p) * widthb;
1009 memcpy(gbuf, cdat, size);
1010 gly->ngmask = size;
1014 /* ---------------------- HEAP Routines ----------------------------- */
1017 * Heap Initialization
1020 static int sisfb_heap_init(void)
1022 struct OH *poh;
1023 u8 jTemp, tq_state;
1025 if(ivideo.video_size > 0x800000) /* video ram is large than 8M */
1026 heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_8M;
1027 else
1028 heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_4M;
1030 heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
1031 heap_size = heap_end - heap_start;
1034 /* Setting for Turbo Queue */
1035 if (heap_size >= TURBO_QUEUE_AREA_SIZE) {
1036 tqueue_pos =
1037 (ivideo.video_size -
1038 TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
1039 jTemp = (u8) (tqueue_pos & 0xff);
1040 vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET);
1041 tq_state = vgarb(SEQ_DATA);
1042 tq_state |= 0xf0;
1043 tq_state &= 0xfc;
1044 tq_state |= (u8) (tqueue_pos >> 8);
1045 vgawb(SEQ_DATA, tq_state);
1046 vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR);
1047 vgawb(SEQ_DATA, jTemp);
1049 caps |= TURBO_QUEUE_CAP;
1051 heap_end -= TURBO_QUEUE_AREA_SIZE;
1052 heap_size -= TURBO_QUEUE_AREA_SIZE;
1055 /* Setting for HW cursor(4K) */
1056 if (heap_size >= HW_CURSOR_AREA_SIZE) {
1057 heap_end -= HW_CURSOR_AREA_SIZE;
1058 heap_size -= HW_CURSOR_AREA_SIZE;
1059 hwcursor_vbase = heap_end;
1061 caps |= HW_CURSOR_CAP;
1064 heap.pohaChain = NULL;
1065 heap.pohFreeList = NULL;
1067 poh = poh_new_node();
1069 if (poh == NULL)
1070 return 1;
1072 /* The first node describles the entire heap size */
1073 poh->pohNext = &heap.ohFree;
1074 poh->pohPrev = &heap.ohFree;
1075 poh->ulSize = heap_end - heap_start + 1;
1076 poh->ulOffset = heap_start - (unsigned long) ivideo.video_vbase;
1078 DPRINTK("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n",
1079 (char *) heap_start, (char *) heap_end,
1080 (unsigned int) poh->ulSize / 1024);
1082 DPRINTK("sisfb:First Node offset:0x%x, size:%dk\n",
1083 (unsigned int) poh->ulOffset, (unsigned int) poh->ulSize / 1024);
1085 /* The second node in our free list sentinel */
1086 heap.ohFree.pohNext = poh;
1087 heap.ohFree.pohPrev = poh;
1088 heap.ohFree.ulSize = 0;
1089 heap.ulMaxFreeSize = poh->ulSize;
1091 /* Initialize the discardable list */
1092 heap.ohUsed.pohNext = &heap.ohUsed;
1093 heap.ohUsed.pohPrev = &heap.ohUsed;
1094 heap.ohUsed.ulSize = SENTINEL;
1096 return 0;
1100 * Allocates a basic memory unit in which we'll pack our data structures.
1103 static struct OH *poh_new_node(void)
1105 int i;
1106 unsigned long cOhs;
1107 struct OHALLOC *poha;
1108 struct OH *poh;
1110 if (heap.pohFreeList == NULL) {
1111 poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
1113 poha->pohaNext = heap.pohaChain;
1114 heap.pohaChain = poha;
1116 cOhs =
1117 (OH_ALLOC_SIZE -
1118 sizeof(struct OHALLOC)) / sizeof(struct OH) + 1;
1120 poh = &poha->aoh[0];
1121 for (i = cOhs - 1; i != 0; i--) {
1122 poh->pohNext = poh + 1;
1123 poh = poh + 1;
1126 poh->pohNext = NULL;
1127 heap.pohFreeList = &poha->aoh[0];
1130 poh = heap.pohFreeList;
1131 heap.pohFreeList = poh->pohNext;
1133 return (poh);
1137 * Allocates space, return NULL when failed
1140 static struct OH *poh_allocate(unsigned long size)
1142 struct OH *pohThis;
1143 struct OH *pohRoot;
1144 int bAllocated = 0;
1146 if (size > heap.ulMaxFreeSize) {
1147 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
1148 (unsigned int) size / 1024);
1149 return (NULL);
1152 pohThis = heap.ohFree.pohNext;
1154 while (pohThis != &heap.ohFree) {
1155 if (size <= pohThis->ulSize) {
1156 bAllocated = 1;
1157 break;
1159 pohThis = pohThis->pohNext;
1162 if (!bAllocated) {
1163 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
1164 (unsigned int) size / 1024);
1165 return (NULL);
1168 if (size == pohThis->ulSize) {
1169 pohRoot = pohThis;
1170 delete_node(pohThis);
1171 } else {
1172 pohRoot = poh_new_node();
1174 if (pohRoot == NULL) {
1175 return (NULL);
1178 pohRoot->ulOffset = pohThis->ulOffset;
1179 pohRoot->ulSize = size;
1181 pohThis->ulOffset += size;
1182 pohThis->ulSize -= size;
1185 heap.ulMaxFreeSize -= size;
1187 pohThis = &heap.ohUsed;
1188 insert_node(pohThis, pohRoot);
1190 return (pohRoot);
1194 * To remove a node from a list.
1197 static void delete_node(struct OH *poh)
1199 struct OH *pohPrev;
1200 struct OH *pohNext;
1203 pohPrev = poh->pohPrev;
1204 pohNext = poh->pohNext;
1206 pohPrev->pohNext = pohNext;
1207 pohNext->pohPrev = pohPrev;
1209 return;
1213 * To insert a node into a list.
1216 static void insert_node(struct OH *pohList, struct OH *poh)
1218 struct OH *pohTemp;
1220 pohTemp = pohList->pohNext;
1222 pohList->pohNext = poh;
1223 pohTemp->pohPrev = poh;
1225 poh->pohPrev = pohList;
1226 poh->pohNext = pohTemp;
1230 * Frees an off-screen heap allocation.
1233 static struct OH *poh_free(unsigned long base)
1236 struct OH *pohThis;
1237 struct OH *pohFreed;
1238 struct OH *pohPrev;
1239 struct OH *pohNext;
1240 unsigned long ulUpper;
1241 unsigned long ulLower;
1242 int foundNode = 0;
1244 pohFreed = heap.ohUsed.pohNext;
1246 while (pohFreed != &heap.ohUsed) {
1247 if (pohFreed->ulOffset == base) {
1248 foundNode = 1;
1249 break;
1252 pohFreed = pohFreed->pohNext;
1255 if (!foundNode)
1256 return (NULL);
1258 heap.ulMaxFreeSize += pohFreed->ulSize;
1260 pohPrev = pohNext = NULL;
1261 ulUpper = pohFreed->ulOffset + pohFreed->ulSize;
1262 ulLower = pohFreed->ulOffset;
1264 pohThis = heap.ohFree.pohNext;
1266 while (pohThis != &heap.ohFree) {
1267 if (pohThis->ulOffset == ulUpper) {
1268 pohNext = pohThis;
1270 else if ((pohThis->ulOffset + pohThis->ulSize) ==
1271 ulLower) {
1272 pohPrev = pohThis;
1274 pohThis = pohThis->pohNext;
1277 delete_node(pohFreed);
1279 if (pohPrev && pohNext) {
1280 pohPrev->ulSize += (pohFreed->ulSize + pohNext->ulSize);
1281 delete_node(pohNext);
1282 free_node(pohFreed);
1283 free_node(pohNext);
1284 return (pohPrev);
1287 if (pohPrev) {
1288 pohPrev->ulSize += pohFreed->ulSize;
1289 free_node(pohFreed);
1290 return (pohPrev);
1293 if (pohNext) {
1294 pohNext->ulSize += pohFreed->ulSize;
1295 pohNext->ulOffset = pohFreed->ulOffset;
1296 free_node(pohFreed);
1297 return (pohNext);
1300 insert_node(&heap.ohFree, pohFreed);
1302 return (pohFreed);
1306 * Frees our basic data structure allocation unit by adding it to a free
1307 * list.
1310 static void free_node(struct OH *poh)
1312 if (poh == NULL) {
1313 return;
1316 poh->pohNext = heap.pohFreeList;
1317 heap.pohFreeList = poh;
1319 return;
1322 void sis_malloc(struct sis_memreq *req)
1324 struct OH *poh;
1326 poh = poh_allocate(req->size);
1328 if (poh == NULL) {
1329 req->offset = 0;
1330 req->size = 0;
1331 DPRINTK("sisfb: VMEM Allocation Failed\n");
1332 } else {
1333 DPRINTK("sisfb: VMEM Allocation Successed : 0x%p\n",
1334 (char *) (poh->ulOffset +
1335 (unsigned long) ivideo.video_vbase));
1337 req->offset = poh->ulOffset;
1338 req->size = poh->ulSize;
1343 void sis_free(unsigned long base)
1345 struct OH *poh;
1347 poh = poh_free(base);
1349 if (poh == NULL) {
1350 DPRINTK("sisfb: poh_free() failed at base 0x%x\n",
1351 (unsigned int) base);
1358 /* ---------------------- SetMode Routines -------------------------- */
1360 static void set_reg1(u16 port, u16 index, u16 data)
1362 outb((u8) (index & 0xff), port);
1363 port++;
1364 outb((u8) (data & 0xff), port);
1367 static void set_reg3(u16 port, u16 data)
1369 outb((u8) (data & 0xff), port);
1372 static void set_reg4(u16 port, unsigned long data)
1374 outl((u32) (data & 0xffffffff), port);
1377 static u8 get_reg1(u16 port, u16 index)
1379 u8 data;
1381 outb((u8) (index & 0xff), port);
1382 port += 1;
1383 data = inb(port);
1384 return (data);
1387 static u8 get_reg2(u16 port)
1389 u8 data;
1391 data = inb(port);
1393 return (data);
1396 static u32 get_reg3(u16 port)
1398 u32 data;
1400 data = inl(port);
1401 return (data);
1404 static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo)
1406 #if 0
1407 unsigned char ModeID;
1408 u16 modeidlength;
1409 u16 usModeIDOffset;
1411 modeidlength = 0;
1412 usModeIDOffset = *((u16 *) (ROMAddr + 0x20A));
1413 ModeID = *((unsigned char *) (ROMAddr + usModeIDOffset));
1414 while (ModeID != 0x2E) {
1415 modeidlength++;
1416 usModeIDOffset = usModeIDOffset + 1;
1417 ModeID = *((unsigned char *) (ROMAddr + usModeIDOffset));
1419 return (modeidlength);
1420 #endif
1421 return(10);
1424 static int search_modeID(unsigned long ROMAddr, u16 ModeNo)
1426 unsigned char ModeID;
1427 u16 usIDLength;
1428 unsigned int count = 0;
1430 ModeIDOffset = *((u16 *) (ROMAddr + 0x20A));
1431 ModeID = *((unsigned char *) (ROMAddr + ModeIDOffset));
1432 usIDLength = get_modeID_length(ROMAddr, ModeNo);
1433 while (ModeID != 0xff && ModeID != ModeNo) {
1434 ModeIDOffset = ModeIDOffset + usIDLength;
1435 ModeID = *((unsigned char *) (ROMAddr + ModeIDOffset));
1436 if (count++ >= 0xff)
1437 break;
1439 if (ModeID == 0xff)
1440 return (FALSE);
1441 else
1442 return (TRUE);
1445 static int check_memory_size(unsigned long ROMAddr)
1447 u16 memorysize;
1448 u16 modeflag;
1449 u16 temp;
1451 modeflag = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
1452 ModeType = modeflag & ModeInfoFlag;
1454 memorysize = modeflag & MemoryInfoFlag;
1455 memorysize = memorysize >> MemorySizeShift;
1456 memorysize++;
1458 temp = get_reg1(P3c4, 0x14);
1459 temp = temp & 0x3F;
1460 temp++;
1462 if (temp < memorysize)
1463 return (FALSE);
1464 else
1465 return (TRUE);
1468 static void get_mode_ptr(unsigned long ROMAddr, u16 ModeNo)
1470 unsigned char index;
1472 StandTable = *((u16 *) (ROMAddr + 0x202));
1474 if (ModeNo <= 13)
1475 index =
1476 *((unsigned char *) (ROMAddr + ModeIDOffset + 0x03));
1477 else {
1478 if (ModeType <= 0x02)
1479 index = 0x1B;
1480 else
1481 index = 0x0F;
1484 StandTable = StandTable + 64 * index;
1488 static void set_seq_regs(unsigned long ROMAddr)
1490 unsigned char SRdata;
1491 u16 i;
1493 set_reg1(P3c4, 0x00, 0x03);
1494 StandTable = StandTable + 0x05;
1495 SRdata = *((unsigned char *) (ROMAddr + StandTable));
1496 SRdata = SRdata | 0x20;
1497 set_reg1(P3c4, 0x01, SRdata);
1499 for (i = 02; i <= 04; i++) {
1500 StandTable++;
1501 SRdata = *((unsigned char *) (ROMAddr + StandTable));
1502 set_reg1(P3c4, i, SRdata);
1506 static void set_misc_regs(unsigned long ROMAddr)
1508 unsigned char Miscdata;
1510 StandTable++;
1511 Miscdata = *((unsigned char *) (ROMAddr + StandTable));
1512 set_reg3(P3c2, Miscdata);
1515 static void set_crtc_regs(unsigned long ROMAddr)
1517 unsigned char CRTCdata;
1518 u16 i;
1520 CRTCdata = (unsigned char) get_reg1(P3d4, 0x11);
1521 CRTCdata = CRTCdata & 0x7f;
1522 set_reg1(P3d4, 0x11, CRTCdata);
1524 for (i = 0; i <= 0x18; i++) {
1525 StandTable++;
1526 CRTCdata = *((unsigned char *) (ROMAddr + StandTable));
1527 set_reg1(P3d4, i, CRTCdata);
1531 static void set_attregs(unsigned long ROMAddr)
1533 unsigned char ARdata;
1534 u16 i;
1536 for (i = 0; i <= 0x13; i++) {
1537 StandTable++;
1538 ARdata = *((unsigned char *) (ROMAddr + StandTable));
1540 get_reg2(P3da);
1541 set_reg3(P3c0, i);
1542 set_reg3(P3c0, ARdata);
1544 get_reg2(P3da);
1545 set_reg3(P3c0, 0x14);
1546 set_reg3(P3c0, 0x00);
1548 get_reg2(P3da);
1549 set_reg3(P3c0, 0x20);
1552 static void set_grc_regs(unsigned long ROMAddr)
1554 unsigned char GRdata;
1555 u16 i;
1557 for (i = 0; i <= 0x08; i++) {
1558 StandTable++;
1559 GRdata = *((unsigned char *) (ROMAddr + StandTable));
1560 set_reg1(P3ce, i, GRdata);
1562 if (ModeType > ModeVGA) {
1563 GRdata = (unsigned char) get_reg1(P3ce, 0x05);
1564 GRdata = GRdata & 0xBF;
1565 set_reg1(P3ce, 0x05, GRdata);
1569 static void ClearExt1Regs(void)
1571 u16 i;
1573 for (i = 0x0A; i <= 0x0E; i++)
1574 set_reg1(P3c4, i, 0x00);
1577 static u16 GetRefindexLength(unsigned long ROMAddr, u16 ModeNo)
1579 unsigned char ModeID;
1580 unsigned char temp;
1581 u16 refindexlength;
1582 u16 usModeIDOffset;
1583 u16 usREFIndex;
1584 u16 usIDLength;
1586 usModeIDOffset = *((u16 *) (ROMAddr + 0x20A));
1587 ModeID = *((unsigned char *) (ROMAddr + usModeIDOffset));
1588 usIDLength = get_modeID_length(ROMAddr, ModeNo);
1589 while (ModeID != 0x40) {
1590 usModeIDOffset = usModeIDOffset + usIDLength;
1591 ModeID = *((unsigned char *) (ROMAddr + usModeIDOffset));
1594 refindexlength = 1;
1595 usREFIndex = *((u16 *) (ROMAddr + usModeIDOffset + 0x04));
1596 usREFIndex++;
1597 temp = *((unsigned char *) (ROMAddr + usREFIndex));
1598 while (temp != 0xFF) {
1599 refindexlength++;
1600 usREFIndex++;
1601 temp = *((unsigned char *) (ROMAddr + usREFIndex));
1603 return (refindexlength);
1606 static int get_rate_ptr(unsigned long ROMAddr, u16 ModeNo)
1608 short index;
1609 u16 temp;
1610 u16 ulRefIndexLength;
1612 if (ModeNo < 0x14)
1613 return (FALSE);
1615 index = get_reg1(P3d4, 0x33);
1616 index = index & 0x0F;
1617 if (index != 0)
1618 index--;
1620 REFIndex = *((u16 *) (ROMAddr + ModeIDOffset + 0x04));
1622 ulRefIndexLength = GetRefindexLength(ROMAddr, ModeNo);
1624 do {
1625 temp = *((u16 *) (ROMAddr + REFIndex));
1626 if (temp == 0xFFFF)
1627 break;
1628 temp = temp & ModeInfoFlag;
1629 if (temp < ModeType)
1630 break;
1632 REFIndex = REFIndex + ulRefIndexLength;
1633 index--;
1634 } while (index >= 0);
1636 REFIndex = REFIndex - ulRefIndexLength;
1637 return (TRUE);
1640 static void set_sync(unsigned long ROMAddr)
1642 u16 sync;
1643 u16 temp;
1645 sync = *((u16 *) (ROMAddr + REFIndex));
1646 sync = sync & 0xC0;
1647 temp = 0x2F;
1648 temp = temp | sync;
1649 set_reg3(P3c2, temp);
1652 static void set_crt1_crtc(unsigned long ROMAddr)
1654 unsigned char index;
1655 unsigned char data;
1656 u16 i;
1658 index = *((unsigned char *) (ROMAddr + REFIndex + 0x02));
1659 CRT1Table = *((u16 *) (ROMAddr + 0x204));
1660 CRT1Table = CRT1Table + index * CRT1Len;
1662 data = (unsigned char) get_reg1(P3d4, 0x11);
1663 data = data & 0x7F;
1664 set_reg1(P3d4, 0x11, data);
1666 CRT1Table--;
1667 for (i = 0; i <= 0x05; i++) {
1668 CRT1Table++;
1669 data = *((unsigned char *) (ROMAddr + CRT1Table));
1670 set_reg1(P3d4, i, data);
1672 for (i = 0x06; i <= 0x07; i++) {
1673 CRT1Table++;
1674 data = *((unsigned char *) (ROMAddr + CRT1Table));
1675 set_reg1(P3d4, i, data);
1677 for (i = 0x10; i <= 0x12; i++) {
1678 CRT1Table++;
1679 data = *((unsigned char *) (ROMAddr + CRT1Table));
1680 set_reg1(P3d4, i, data);
1682 for (i = 0x15; i <= 0x16; i++) {
1683 CRT1Table++;
1684 data = *((unsigned char *) (ROMAddr + CRT1Table));
1685 set_reg1(P3d4, i, data);
1687 for (i = 0x0A; i <= 0x0C; i++) {
1688 CRT1Table++;
1689 data = *((unsigned char *) (ROMAddr + CRT1Table));
1690 set_reg1(P3c4, i, data);
1693 CRT1Table++;
1694 data = *((unsigned char *) (ROMAddr + CRT1Table));
1695 data = data & 0xE0;
1696 set_reg1(P3c4, 0x0E, data);
1698 data = (unsigned char) get_reg1(P3d4, 0x09);
1699 data = data & 0xDF;
1700 i = *((unsigned char *) (ROMAddr + CRT1Table));
1701 i = i & 0x01;
1702 i = i << 5;
1703 data = data | i;
1704 i = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
1705 i = i & DoubleScanMode;
1706 if (i)
1707 data = data | 0x80;
1708 set_reg1(P3d4, 0x09, data);
1710 if (ModeType > 0x03)
1711 set_reg1(P3d4, 0x14, 0x4F);
1714 static void set_crt1_offset(unsigned long ROMAddr)
1716 u16 temp, ah, al;
1717 u16 temp2, i;
1718 u16 DisplayUnit;
1720 temp = *((unsigned char *) (ROMAddr + ModeIDOffset + 0x03));
1721 temp = temp >> 4;
1722 ScreenOffset = *((u16 *) (ROMAddr + 0x206));
1723 temp = *((unsigned char *) (ROMAddr + ScreenOffset + temp));
1725 temp2 = *((u16 *) (ROMAddr + REFIndex + 0x00));
1726 temp2 = temp2 & InterlaceMode;
1727 if (temp2)
1728 temp = temp << 1;
1729 temp2 = ModeType - ModeEGA;
1730 switch (temp2) {
1731 case 0:
1732 temp2 = 1;
1733 break;
1734 case 1:
1735 temp2 = 2;
1736 break;
1737 case 2:
1738 temp2 = 4;
1739 break;
1740 case 3:
1741 temp2 = 4;
1742 break;
1743 case 4:
1744 temp2 = 6;
1745 break;
1746 case 5:
1747 temp2 = 8;
1748 break;
1750 temp = temp * temp2;
1751 DisplayUnit = temp;
1753 temp2 = temp;
1754 temp = temp >> 8;
1755 temp = temp & 0x0F;
1756 i = get_reg1(P3c4, 0x0E);
1757 i = i & 0xF0;
1758 i = i | temp;
1759 set_reg1(P3c4, 0x0E, i);
1761 temp = (unsigned char) temp2;
1762 temp = temp & 0xFF;
1763 set_reg1(P3d4, 0x13, temp);
1765 temp2 = *((u16 *) (ROMAddr + REFIndex + 0x00));
1766 temp2 = temp2 & InterlaceMode;
1767 if (temp2)
1768 DisplayUnit >>= 1;
1770 DisplayUnit = DisplayUnit << 5;
1771 ah = (DisplayUnit & 0xff00) >> 8;
1772 al = DisplayUnit & 0x00ff;
1773 if (al == 0)
1774 ah = ah + 1;
1775 else
1776 ah = ah + 2;
1777 set_reg1(P3c4, 0x10, ah);
1780 static u16 get_vclk_len(unsigned long ROMAddr)
1782 u16 VCLKDataStart, vclklabel, temp;
1783 VCLKDataStart = *((u16 *) (ROMAddr + 0x208));
1784 for (temp = 0;; temp++) {
1785 vclklabel = *((u16 *) (ROMAddr + VCLKDataStart + temp));
1786 if (vclklabel == VCLKStartFreq) {
1787 temp = temp + 2;
1788 return (temp);
1791 return (0);
1794 static void set_crt1_vclk(unsigned long ROMAddr)
1796 u16 i;
1797 unsigned char index, data;
1799 index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
1800 CRT1VCLKLen = get_vclk_len(ROMAddr);
1801 data = index * CRT1VCLKLen;
1802 VCLKData = *((u16 *) (ROMAddr + 0x208));
1803 VCLKData = VCLKData + data;
1805 set_reg1(P3c4, 0x31, 0);
1807 for (i = 0x2B; i <= 0x2C; i++) {
1808 data = *((unsigned char *) (ROMAddr + VCLKData));
1809 set_reg1(P3c4, i, data);
1810 VCLKData++;
1812 set_reg1(P3c4, 0x2D, 0x80);
1815 static void set_vclk_state(unsigned long ROMAddr, u16 ModeNo)
1817 u16 data, data2;
1818 u16 VCLK;
1819 unsigned char index;
1821 index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
1822 CRT1VCLKLen = get_vclk_len(ROMAddr);
1823 data = index * CRT1VCLKLen;
1824 VCLKData = *((u16 *) (ROMAddr + 0x208));
1825 VCLKData = VCLKData + data + (CRT1VCLKLen - 2);
1827 VCLK = *((u16 *) (ROMAddr + VCLKData));
1828 if (ModeNo <= 0x13)
1829 VCLK = 0;
1831 data = get_reg1(P3c4, 0x07);
1832 data = data & 0x7B;
1833 if (VCLK >= 150)
1834 data = data | 0x80;
1835 set_reg1(P3c4, 0x07, data);
1837 data = get_reg1(P3c4, 0x32);
1838 data = data & 0xD7;
1839 if (VCLK >= 150)
1840 data = data | 0x08;
1841 set_reg1(P3c4, 0x32, data);
1843 data2 = 0x03;
1844 if (VCLK > 135)
1845 data2 = 0x02;
1846 if (VCLK > 160)
1847 data2 = 0x01;
1848 if (VCLK > 260)
1849 data2 = 0x00;
1850 data = get_reg1(P3c4, 0x07);
1851 data = data & 0xFC;
1852 data = data | data2;
1853 set_reg1(P3c4, 0x07, data);
1856 static u16 calc_delay2(unsigned long ROMAddr, u16 key)
1858 u16 data, index;
1859 unsigned char LatencyFactor[] = {
1860 88, 80, 78, 72, 70, 00,
1861 00, 79, 77, 71, 69, 49,
1862 88, 80, 78, 72, 70, 00,
1863 00, 72, 70, 64, 62, 44
1865 index = 0;
1866 data = get_reg1(P3c4, 0x14);
1867 if (data & 0x80)
1868 index = index + 12;
1870 data = get_reg1(P3c4, 0x15);
1871 data = (data & 0xf0) >> 4;
1872 if (data & 0x01)
1873 index = index + 6;
1875 data = data >> 1;
1876 index = index + data;
1877 data = LatencyFactor[index];
1879 return (data);
1882 static u16 calc_delay(unsigned long ROMAddr, u16 key)
1884 u16 data, data2, temp0, temp1;
1885 unsigned char ThLowA[] = {
1886 61, 3, 52, 5, 68, 7, 100, 11,
1887 43, 3, 42, 5, 54, 7, 78, 11,
1888 34, 3, 37, 5, 47, 7, 67, 11
1890 unsigned char ThLowB[] = {
1891 81, 4, 72, 6, 88, 8, 120, 12,
1892 55, 4, 54, 6, 66, 8, 90, 12,
1893 42, 4, 45, 6, 55, 8, 75, 12
1895 unsigned char ThTiming[] = { 1, 2, 2, 3, 0, 1, 1, 2 };
1897 data = get_reg1(P3c4, 0x16);
1898 data = data >> 6;
1899 data2 = get_reg1(P3c4, 0x14);
1900 data2 = (data2 >> 4) & 0x0C;
1901 data = data | data2;
1902 data = data < 1;
1903 if (key == 0) {
1904 temp0 = (u16) ThLowA[data];
1905 temp1 = (u16) ThLowA[data + 1];
1906 } else {
1907 temp0 = (u16) ThLowB[data];
1908 temp1 = (u16) ThLowB[data + 1];
1911 data2 = 0;
1912 data = get_reg1(P3c4, 0x18);
1913 if (data & 0x02)
1914 data2 = data2 | 0x01;
1915 if (data & 0x20)
1916 data2 = data2 | 0x02;
1917 if (data & 0x40)
1918 data2 = data2 | 0x04;
1920 data = temp1 * ThTiming[data2] + temp0;
1921 return (data);
1925 static void set_crt1_FIFO(unsigned long ROMAddr)
1927 u16 index, data, VCLK, data2, MCLKOffset, MCLK, colorth = 1;
1928 u16 ah, bl, A, B;
1930 index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
1931 CRT1VCLKLen = get_vclk_len(ROMAddr);
1932 data = index * CRT1VCLKLen;
1933 VCLKData = *((u16 *) (ROMAddr + 0x208));
1934 VCLKData = VCLKData + data + (CRT1VCLKLen - 2);
1935 VCLK = *((u16 *) (ROMAddr + VCLKData));
1937 MCLKOffset = *((u16 *) (ROMAddr + 0x20C));
1938 index = get_reg1(P3c4, 0x3A);
1939 index = index & 07;
1940 MCLKOffset = MCLKOffset + index * 5;
1941 MCLK = *((unsigned char *) (ROMAddr + MCLKOffset + 0x03));
1943 data2 = ModeType - 0x02;
1944 switch (data2) {
1945 case 0:
1946 colorth = 1;
1947 break;
1948 case 1:
1949 colorth = 2;
1950 break;
1951 case 2:
1952 colorth = 4;
1953 break;
1954 case 3:
1955 colorth = 4;
1956 break;
1957 case 4:
1958 colorth = 6;
1959 break;
1960 case 5:
1961 colorth = 8;
1962 break;
1965 do {
1966 B = (calc_delay(ROMAddr, 0) * VCLK * colorth);
1967 B = B / (16 * MCLK);
1968 B++;
1970 A = (calc_delay(ROMAddr, 1) * VCLK * colorth);
1971 A = A / (16 * MCLK);
1972 A++;
1974 if (A < 4)
1975 A = 0;
1976 else
1977 A = A - 4;
1979 if (A > B)
1980 bl = A;
1981 else
1982 bl = B;
1984 bl++;
1985 if (bl > 0x13) {
1986 data = get_reg1(P3c4, 0x16);
1987 data = data >> 6;
1988 if (data != 0) {
1989 data--;
1990 data = data << 6;
1991 data2 = get_reg1(P3c4, 0x16);
1992 data2 = (data2 & 0x3f) | data;
1993 set_reg1(P3c4, 0x16, data2);
1994 } else
1995 bl = 0x13;
1997 } while (bl > 0x13);
1999 ah = bl;
2000 ah = ah << 4;
2001 ah = ah | 0x0f;
2002 set_reg1(P3c4, 0x08, ah);
2004 data = bl;
2005 data = data & 0x10;
2006 data = data << 1;
2007 data2 = get_reg1(P3c4, 0x0F);
2008 data2 = data2 & 0x9f;
2009 data2 = data2 | data;
2010 set_reg1(P3c4, 0x0F, data2);
2012 data = bl + 3;
2013 if (data > 0x0f)
2014 data = 0x0f;
2015 set_reg1(P3c4, 0x3b, 0x00);
2016 data2 = get_reg1(P3c4, 0x09);
2017 data2 = data2 & 0xF0;
2018 data2 = data2 | data;
2019 set_reg1(P3c4, 0x09, data2);
2023 static void set_crt1_FIFO2(unsigned long ROMAddr)
2025 u16 index, data, VCLK, data2, MCLKOffset, MCLK, colorth = 1;
2026 u16 ah, bl, B;
2027 unsigned long eax;
2029 index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
2030 CRT1VCLKLen = get_vclk_len(ROMAddr);
2031 data = index * CRT1VCLKLen;
2032 VCLKData = *((u16 *) (ROMAddr + 0x208));
2033 VCLKData = VCLKData + data + (CRT1VCLKLen - 2);
2034 VCLK = *((u16 *) (ROMAddr + VCLKData));
2036 MCLKOffset = *((u16 *) (ROMAddr + 0x20C));
2037 index = get_reg1(P3c4, 0x1A);
2038 index = index & 07;
2039 MCLKOffset = MCLKOffset + index * 5;
2040 MCLK = *((u16 *) (ROMAddr + MCLKOffset + 0x03));
2042 data2 = ModeType - 0x02;
2043 switch (data2) {
2044 case 0:
2045 colorth = 1;
2046 break;
2047 case 1:
2048 colorth = 1;
2049 break;
2050 case 2:
2051 colorth = 2;
2052 break;
2053 case 3:
2054 colorth = 2;
2055 break;
2056 case 4:
2057 colorth = 3;
2058 break;
2059 case 5:
2060 colorth = 4;
2061 break;
2064 do {
2065 B = (calc_delay2(ROMAddr, 0) * VCLK * colorth);
2066 if (B % (16 * MCLK) == 0) {
2067 B = B / (16 * MCLK);
2068 bl = B + 1;
2069 } else {
2070 B = B / (16 * MCLK);
2071 bl = B + 2;
2074 if (bl > 0x13) {
2075 data = get_reg1(P3c4, 0x15);
2076 data = data & 0xf0;
2077 if (data != 0xb0) {
2078 data = data + 0x20;
2079 if (data == 0xa0)
2080 data = 0x30;
2081 data2 = get_reg1(P3c4, 0x15);
2082 data2 = (data2 & 0x0f) | data;
2083 set_reg1(P3c4, 0x15, data2);
2084 } else
2085 bl = 0x13;
2087 } while (bl > 0x13);
2089 data2 = get_reg1(P3c4, 0x15);
2090 data2 = (data2 & 0xf0) >> 4;
2091 data2 = data2 << 24;
2093 set_reg4(0xcf8, 0x80000050);
2094 eax = get_reg3(0xcfc);
2095 eax = eax & 0x0f0ffffff;
2096 eax = eax | data2;
2097 set_reg4(0xcfc, eax);
2099 ah = bl;
2100 ah = ah << 4;
2101 ah = ah | 0x0f;
2102 set_reg1(P3c4, 0x08, ah);
2104 data = bl;
2105 data = data & 0x10;
2106 data = data << 1;
2107 data2 = get_reg1(P3c4, 0x0F);
2108 data2 = data2 & 0x9f;
2109 data2 = data2 | data;
2110 set_reg1(P3c4, 0x0F, data2);
2112 data = bl + 3;
2113 if (data > 0x0f)
2114 data = 0x0f;
2115 set_reg1(P3c4, 0x3b, 0x00);
2116 data2 = get_reg1(P3c4, 0x09);
2117 data2 = data2 & 0xF0;
2118 data2 = data2 | data;
2119 set_reg1(P3c4, 0x09, data2);
2122 static void set_crt1_mode_regs(unsigned long ROMAddr, u16 ModeNo)
2125 u16 data, data2, data3;
2127 if (ModeNo > 0x13)
2128 data = *((u16 *) (ROMAddr + REFIndex + 0x00));
2129 else
2130 data = 0;
2132 data2 = 0;
2133 if (ModeNo > 0x13)
2134 if (ModeType > 0x02) {
2135 data2 = data2 | 0x02;
2136 data3 = ModeType - ModeVGA;
2137 data3 = data3 << 2;
2138 data2 = data2 | data3;
2141 data = data & InterlaceMode;
2142 if (data)
2143 data2 = data2 | 0x20;
2144 set_reg1(P3c4, 0x06, data2);
2146 data = get_reg1(P3c4, 0x01);
2147 data = data & 0xF7;
2148 data2 = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
2149 data2 = data2 & HalfDCLK;
2150 if (data2)
2151 data = data | 0x08;
2152 set_reg1(P3c4, 0x01, data);
2154 data = get_reg1(P3c4, 0x0F);
2155 data = data & 0xF7;
2156 data2 = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
2157 data2 = data2 & LineCompareOff;
2158 if (data2)
2159 data = data | 0x08;
2160 set_reg1(P3c4, 0x0F, data);
2162 data = get_reg1(P3c4, 0x21);
2163 data = data & 0x1F;
2164 if (ModeType == 0x00)
2165 data = data | 0x60;
2166 else if (ModeType <= 0x02)
2167 data = data | 0x00;
2168 else
2169 data = data | 0xA0;
2170 set_reg1(P3c4, 0x21, data);
2174 static void set_interlace(unsigned long ROMAddr, u16 ModeNo)
2176 unsigned long Temp;
2177 u16 data, Temp2;
2179 Temp = (unsigned long) get_reg1(P3d4, 0x01);
2180 Temp++;
2181 Temp = Temp * 8;
2183 if (Temp == 1024)
2184 data = 0x0035;
2185 else if (Temp == 1280)
2186 data = 0x0048;
2187 else
2188 data = 0x0000;
2190 Temp2 = *((u16 *) (ROMAddr + REFIndex + 0x00));
2191 Temp2 &= InterlaceMode;
2192 if (Temp2 == 0)
2193 data = 0x0000;
2195 set_reg1(P3d4, 0x19, data);
2197 Temp = (unsigned long) get_reg1(P3d4, 0x1A);
2198 Temp2 = (u16) (Temp & 0xFC);
2199 set_reg1(P3d4, 0x1A, (u16) Temp);
2201 Temp = (unsigned long) get_reg1(P3c4, 0x0f);
2202 Temp2 = (u16) Temp & 0xBF;
2203 if (ModeNo == 0x37)
2204 Temp2 = Temp2 | 0x40;
2205 set_reg1(P3d4, 0x1A, (u16) Temp2);
2208 static void write_DAC(u16 dl, u16 ah, u16 al, u16 dh)
2210 u16 temp;
2211 u16 bh, bl;
2213 bh = ah;
2214 bl = al;
2215 if (dl != 0) {
2216 temp = bh;
2217 bh = dh;
2218 dh = temp;
2219 if (dl == 1) {
2220 temp = bl;
2221 bl = dh;
2222 dh = temp;
2223 } else {
2224 temp = bl;
2225 bl = bh;
2226 bh = temp;
2229 set_reg3(P3c9, (u16) dh);
2230 set_reg3(P3c9, (u16) bh);
2231 set_reg3(P3c9, (u16) bl);
2235 static void load_DAC(unsigned long ROMAddr)
2237 u16 data, data2;
2238 u16 time, i, j, k;
2239 u16 m, n, o;
2240 u16 si, di, bx, dl;
2241 u16 al, ah, dh;
2242 u16 *table = VGA_DAC;
2244 data = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
2245 data = data & DACInfoFlag;
2246 time = 64;
2247 if (data == 0x00)
2248 table = MDA_DAC;
2249 if (data == 0x08)
2250 table = CGA_DAC;
2251 if (data == 0x10)
2252 table = EGA_DAC;
2253 if (data == 0x18) {
2254 time = 256;
2255 table = VGA_DAC;
2257 if (time == 256)
2258 j = 16;
2259 else
2260 j = time;
2262 set_reg3(P3c6, 0xFF);
2263 set_reg3(P3c8, 0x00);
2265 for (i = 0; i < j; i++) {
2266 data = table[i];
2267 for (k = 0; k < 3; k++) {
2268 data2 = 0;
2269 if (data & 0x01)
2270 data2 = 0x2A;
2271 if (data & 0x02)
2272 data2 = data2 + 0x15;
2273 set_reg3(P3c9, data2);
2274 data = data >> 2;
2278 if (time == 256) {
2279 for (i = 16; i < 32; i++) {
2280 data = table[i];
2281 for (k = 0; k < 3; k++)
2282 set_reg3(P3c9, data);
2284 si = 32;
2285 for (m = 0; m < 9; m++) {
2286 di = si;
2287 bx = si + 0x04;
2288 dl = 0;
2289 for (n = 0; n < 3; n++) {
2290 for (o = 0; o < 5; o++) {
2291 dh = table[si];
2292 ah = table[di];
2293 al = table[bx];
2294 si++;
2295 write_DAC(dl, ah, al, dh);
2297 si = si - 2;
2298 for (o = 0; o < 3; o++) {
2299 dh = table[bx];
2300 ah = table[di];
2301 al = table[si];
2302 si--;
2303 write_DAC(dl, ah, al, dh);
2305 dl++;
2307 si = si + 5;
2312 static void display_on(void)
2314 u16 data;
2316 data = get_reg1(P3c4, 0x01);
2317 data = data & 0xDF;
2318 set_reg1(P3c4, 0x01, data);
2321 static int SiSSetMode(u16 ModeNo)
2323 unsigned long temp;
2324 u16 cr30flag, cr31flag;
2325 unsigned long ROMAddr = rom_vbase;
2326 u16 BaseAddr = (u16) ivideo.vga_base;
2328 P3c4 = BaseAddr + 0x14;
2329 P3d4 = BaseAddr + 0x24;
2330 P3c0 = BaseAddr + 0x10;
2331 P3ce = BaseAddr + 0x1e;
2332 P3c2 = BaseAddr + 0x12;
2333 P3ca = BaseAddr + 0x1a;
2334 P3c6 = BaseAddr + 0x16;
2335 P3c7 = BaseAddr + 0x17;
2336 P3c8 = BaseAddr + 0x18;
2337 P3c9 = BaseAddr + 0x19;
2338 P3da = BaseAddr + 0x2A;
2340 temp = search_modeID(ROMAddr, ModeNo);
2342 if (temp == 0)
2343 return (0);
2345 temp = check_memory_size(ROMAddr);
2346 if (temp == 0)
2347 return (0);
2349 cr30flag = (unsigned char) get_reg1(P3d4, 0x30);
2350 if (((cr30flag & 0x01) == 1) || ((cr30flag & 0x02) == 0)) {
2351 get_mode_ptr(ROMAddr, ModeNo);
2352 set_seq_regs(ROMAddr);
2353 set_misc_regs(ROMAddr);
2354 set_crtc_regs(ROMAddr);
2355 set_attregs(ROMAddr);
2356 set_grc_regs(ROMAddr);
2357 ClearExt1Regs();
2358 temp = get_rate_ptr(ROMAddr, ModeNo);
2359 if (temp) {
2360 set_sync(ROMAddr);
2361 set_crt1_crtc(ROMAddr);
2362 set_crt1_offset(ROMAddr);
2363 set_crt1_vclk(ROMAddr);
2364 set_vclk_state(ROMAddr, ModeNo);
2365 if ((ivideo.chip_id == SIS_Trojan)
2366 || (ivideo.chip_id == SIS_Spartan))
2367 set_crt1_FIFO2(ROMAddr);
2368 else /* SiS 300 */
2369 set_crt1_FIFO(ROMAddr);
2371 set_crt1_mode_regs(ROMAddr, ModeNo);
2372 if ((ivideo.chip_id == SIS_Trojan)
2373 || (ivideo.chip_id ==
2374 SIS_Spartan)) set_interlace(ROMAddr, ModeNo);
2375 load_DAC(ROMAddr);
2377 /* clear OnScreen */
2378 memset((char *) ivideo.video_vbase, 0,
2379 video_linelength * ivideo.video_height);
2381 cr31flag = (unsigned char) get_reg1(P3d4, 0x31);
2383 display_on();
2385 return (0);
2388 static void pre_setmode(void)
2390 vgawb(CRTC_ADR, 0x30);
2391 vgawb(CRTC_DATA, 0x00);
2393 vgawb(CRTC_ADR, 0x31);
2394 vgawb(CRTC_DATA, 0x60);
2396 DPRINTK("Setting CR33 = 0x%x\n", rate_idx & 0x0f);
2398 /* set CRT1 refresh rate */
2399 vgawb(CRTC_ADR, 0x33);
2400 vgawb(CRTC_DATA, rate_idx & 0x0f);
2403 static void post_setmode(void)
2405 u8 uTemp;
2407 /* turn on CRT1 */
2408 vgawb(CRTC_ADR, 0x17);
2409 uTemp = vgarb(CRTC_DATA);
2410 uTemp |= 0x80;
2411 vgawb(CRTC_DATA, uTemp);
2413 /* disable 24-bit palette RAM and Gamma correction */
2414 vgawb(SEQ_ADR, 0x07);
2415 uTemp = vgarb(SEQ_DATA);
2416 uTemp &= ~0x04;
2417 vgawb(SEQ_DATA, uTemp);
2420 static void search_mode(const char *name)
2422 int i = 0;
2424 if (name == NULL)
2425 return;
2427 while (sisbios_mode[i].mode_no != 0) {
2428 if (!strcmp(name, sisbios_mode[i].name)) {
2429 mode_idx = i;
2430 break;
2432 i++;
2434 if (mode_idx < 0)
2435 DPRINTK("Invalid user mode : %s\n", name);
2438 static u8 search_refresh_rate(unsigned int rate)
2440 u16 xres, yres;
2441 int i = 0;
2443 xres = sisbios_mode[mode_idx].xres;
2444 yres = sisbios_mode[mode_idx].yres;
2446 while ((vrate[i].idx != 0) && (vrate[i].xres <= xres)) {
2447 if ((vrate[i].xres == xres) && (vrate[i].yres == yres)
2448 && (vrate[i].refresh == rate)) {
2449 rate_idx = vrate[i].idx;
2450 return rate_idx;
2452 i++;
2455 DPRINTK("sisfb: Unsupported rate %d in %dx%d mode\n", rate, xres,
2456 yres);
2458 return 0;
2463 /* ------------------ Public Routines ------------------------------- */
2466 * Get the Fixed Part of the Display
2469 static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
2470 struct fb_info *info)
2472 DPRINTK("sisfb: sisfb_get_fix:[%d]\n", con);
2474 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
2475 strcpy(fix->id, fb_info.modename);
2477 fix->smem_start = ivideo.video_base;
2478 if(ivideo.video_size > 0x800000)
2479 fix->smem_len = RESERVED_MEM_SIZE_8M; /* reserved for Xserver */
2480 else
2481 fix->smem_len = RESERVED_MEM_SIZE_4M; /* reserved for Xserver */
2483 fix->type = video_type;
2484 fix->type_aux = 0;
2485 if (ivideo.video_bpp == 8)
2486 fix->visual = FB_VISUAL_PSEUDOCOLOR;
2487 else
2488 fix->visual = FB_VISUAL_TRUECOLOR;
2489 fix->xpanstep = 0;
2490 fix->ypanstep = 0;
2491 fix->ywrapstep = 0;
2492 fix->line_length = video_linelength;
2493 fix->mmio_start = ivideo.mmio_base;
2494 fix->mmio_len = MMIO_SIZE;
2495 fix->accel = FB_ACCEL_SIS_GLAMOUR;
2496 fix->reserved[0] = ivideo.video_size & 0xFFFF;
2497 fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
2498 fix->reserved[2] = caps; /* capabilities */
2500 return 0;
2504 * Get the User Defined Part of the Display
2507 static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
2508 struct fb_info *info)
2510 DPRINTK("sisfb: sisfb_get_var:[%d]\n", con);
2512 if (con == -1)
2513 memcpy(var, &default_var,
2514 sizeof(struct fb_var_screeninfo));
2515 else
2516 *var = fb_display[con].var;
2517 return 0;
2521 * Set the User Defined Part of the Display
2524 static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
2525 struct fb_info *info)
2527 int err;
2528 unsigned int cols, rows;
2530 fb_display[con].var.activate = FB_ACTIVATE_NOW;
2532 /* Set mode */
2533 if (do_set_var(var, con == currcon, info)) {
2534 crtc_to_var(var); /* return current mode to user */
2535 return -EINVAL;
2538 /* get actual setting value */
2539 crtc_to_var(var);
2541 /* update display of current console */
2542 sisfb_set_disp(con, var);
2544 if (info->changevar)
2545 (*info->changevar) (con);
2547 if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
2548 return err;
2550 do_install_cmap(con, info);
2552 /* inform console to update struct display */
2553 cols = sisbios_mode[mode_idx].cols;
2554 rows = sisbios_mode[mode_idx].rows;
2555 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
2557 return 0;
2562 * Get the Colormap
2565 static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
2566 struct fb_info *info)
2568 DPRINTK("sisfb: sisfb_get_cmap:[%d]\n", con);
2570 if (con == currcon)
2571 return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
2572 else if (fb_display[con].cmap.len) /* non default colormap? */
2573 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
2574 else
2575 fb_copy_cmap(fb_default_cmap(video_cmap_len),
2576 cmap, kspc ? 0 : 2);
2577 return 0;
2581 * Set the Colormap
2584 static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
2585 struct fb_info *info)
2587 int err;
2589 if (!fb_display[con].cmap.len) { /* no colormap allocated */
2590 err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0);
2591 if (err)
2592 return err;
2594 if (con == currcon) /* current console */
2595 return fb_set_cmap(cmap, kspc, sis_setcolreg, info);
2596 else
2597 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
2598 return 0;
2602 * Pan or Wrap the Display
2605 static int sisfb_pan_display(struct fb_var_screeninfo *var, int con,
2606 struct fb_info *info)
2608 /* not support virtual screen yet */
2609 return -EINVAL;
2612 static int sisfb_ioctl(struct inode *inode, struct file *file,
2613 unsigned int cmd, unsigned long arg, int con,
2614 struct fb_info *info)
2616 switch (cmd) {
2617 case FBIO_ALLOC:
2618 if(!capable(CAP_SYS_RAWIO))
2619 return -EPERM;
2620 sis_malloc((struct sis_memreq *) arg);
2621 break;
2622 case FBIO_FREE:
2623 if(!capable(CAP_SYS_RAWIO))
2624 return -EPERM;
2625 sis_free(*(unsigned long *) arg);
2626 break;
2627 case FBIOGET_GLYPH:
2628 sis_get_glyph((struct GlyInfo *) arg);
2629 break;
2630 case FBIOGET_HWCINFO:
2632 unsigned long *hwc_offset = (unsigned long *) arg;
2634 if (caps | HW_CURSOR_CAP)
2635 *hwc_offset = hwcursor_vbase -
2636 (unsigned long) ivideo.video_vbase;
2637 else
2638 *hwc_offset = 0;
2640 break;
2642 default:
2643 return -EINVAL;
2645 return 0;
2648 static int sisfb_mmap(struct fb_info *info, struct file *file,
2649 struct vm_area_struct *vma)
2651 struct fb_var_screeninfo var;
2652 unsigned long start;
2653 unsigned long off;
2654 u32 len;
2656 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
2657 return -EINVAL;
2658 off = vma->vm_pgoff << PAGE_SHIFT;
2660 /* frame buffer memory */
2661 start = (unsigned long) ivideo.video_base;
2662 len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
2664 if (off >= len) {
2665 /* memory mapped io */
2666 off -= len;
2667 sisfb_get_var(&var, currcon, info);
2668 if (var.accel_flags)
2669 return -EINVAL;
2670 start = (unsigned long) ivideo.mmio_base;
2671 len = PAGE_ALIGN((start & ~PAGE_MASK) + MMIO_SIZE);
2674 start &= PAGE_MASK;
2675 if ((vma->vm_end - vma->vm_start + off) > len)
2676 return -EINVAL;
2677 off += start;
2678 vma->vm_pgoff = off >> PAGE_SHIFT;
2680 #if defined(__i386__)
2681 if (boot_cpu_data.x86 > 3)
2682 pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
2683 #endif
2684 if (io_remap_page_range(vma->vm_start, off,
2685 vma->vm_end - vma->vm_start,
2686 vma->vm_page_prot)) return -EAGAIN;
2687 return 0;
2690 static struct fb_ops sisfb_ops = {
2691 owner: THIS_MODULE,
2692 fb_get_fix: sisfb_get_fix,
2693 fb_get_var: sisfb_get_var,
2694 fb_set_var: sisfb_set_var,
2695 fb_get_cmap: sisfb_get_cmap,
2696 fb_set_cmap: sisfb_set_cmap,
2697 fb_pan_display: sisfb_pan_display,
2698 fb_ioctl: sisfb_ioctl,
2699 fb_mmap: sisfb_mmap,
2702 int sisfb_setup(char *options)
2704 char *this_opt;
2706 fb_info.fontname[0] = '\0';
2707 ivideo.refresh_rate = 0;
2709 if (!options || !*options)
2710 return 0;
2712 for (this_opt = strtok(options, ","); this_opt;
2713 this_opt = strtok(NULL, ",")) {
2714 if (!*this_opt)
2715 continue;
2717 if (!strcmp(this_opt, "inverse")) {
2718 inverse = 1;
2719 fb_invert_cmaps();
2720 } else if (!strncmp(this_opt, "font:", 5)) {
2721 strcpy(fb_info.fontname, this_opt + 5);
2722 } else if (!strncmp(this_opt, "mode:", 5)) {
2723 search_mode(this_opt + 5);
2724 } else if (!strncmp(this_opt, "vrate:", 6)) {
2725 ivideo.refresh_rate =
2726 simple_strtoul(this_opt + 6, NULL, 0);
2727 } else if (!strncmp(this_opt, "off", 3)) {
2728 sisfb_off = 1;
2729 } else
2730 DPRINTK("invalid parameter %s\n", this_opt);
2732 return 0;
2735 static int sisfb_update_var(int con, struct fb_info *info)
2737 return 0;
2741 * Switch Console (called by fbcon.c)
2744 static int sisfb_switch(int con, struct fb_info *info)
2746 int cols, rows;
2748 DPRINTK("sisfb: switch console from [%d] to [%d]\n", currcon, con);
2750 /* update colormap of current console */
2751 if (fb_display[currcon].cmap.len)
2752 fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
2754 fb_display[con].var.activate = FB_ACTIVATE_NOW;
2756 /* same mode, needn't change mode actually */
2758 if (!memcmp(&fb_display[con].var, &fb_display[currcon].var, sizeof(struct fb_var_screeninfo)))
2760 currcon = con;
2761 return 1;
2764 currcon = con;
2766 do_set_var(&fb_display[con].var, 1, info);
2768 sisfb_set_disp(con, &fb_display[con].var);
2770 /* Install new colormap */
2771 do_install_cmap(con, info);
2773 cols = sisbios_mode[mode_idx].cols;
2774 rows = sisbios_mode[mode_idx].rows;
2775 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
2777 sisfb_update_var(con, info);
2779 return 1;
2783 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
2785 static void sisfb_blank(int blank, struct fb_info *info)
2787 u8 CRData;
2789 vgawb(CRTC_ADR, 0x17);
2790 CRData = vgarb(CRTC_DATA);
2792 if (blank > 0) /* turn off CRT1 */
2793 CRData &= 0x7f;
2794 else /* turn on CRT1 */
2795 CRData |= 0x80;
2797 vgawb(CRTC_ADR, 0x17);
2798 vgawb(CRTC_DATA, CRData);
2801 int __init sisfb_init(void)
2803 struct pci_dev *pdev;
2804 struct board *b;
2805 int pdev_valid = 0;
2806 unsigned char jTemp;
2808 if (sisfb_off)
2809 return -ENXIO;
2811 pci_for_each_dev(pdev) {
2812 for (b = dev_list; b->vendor; b++)
2814 if ((b->vendor == pdev->vendor)
2815 && (b->device == pdev->device))
2817 pdev_valid = 1;
2818 strcpy(fb_info.modename, b->name);
2819 ivideo.chip_id = pdev->device;
2820 break;
2824 if (pdev_valid)
2825 break;
2828 if (!pdev_valid)
2829 return -1;
2831 ivideo.video_base = pdev->resource[0].start & ~0x7FFFFF;
2832 ivideo.mmio_base = pdev->resource[1].start & ~0x3FFF;
2833 ivideo.vga_base = (pdev->resource[2].start & 0xFFFFFC) + 0x30;
2834 rom_base = 0x000C0000;
2836 request_region(rom_base, 32, "sisfb");
2838 /* set passwd */
2839 vgawb(SEQ_ADR, IND_SIS_PASSWORD);
2840 vgawb(SEQ_DATA, SIS_PASSWORD);
2842 /* Enable MMIO & PCI linear address */
2843 vgawb(SEQ_ADR, IND_SIS_PCI_ADDRESS_SET);
2844 jTemp = vgarb(SEQ_DATA);
2845 jTemp |= SIS_PCI_ADDR_ENABLE;
2846 jTemp |= SIS_MEM_MAP_IO_ENABLE;
2847 vgawb(SEQ_DATA, jTemp);
2849 /* get video ram size by SR14 */
2850 vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
2851 ivideo.video_size = ((int) ((vgarb(SEQ_DATA) & 0x3f) + 1) << 20);
2853 if (mode_idx < 0)
2854 mode_idx = DEFAULT_MODE; /* 0:640x480x8 */
2856 mode_no = sisbios_mode[mode_idx].mode_no;
2858 if (ivideo.refresh_rate != 0)
2859 search_refresh_rate(ivideo.refresh_rate);
2861 if (rate_idx == 0) {
2862 rate_idx = sisbios_mode[mode_idx].rate_idx; /* set to default refresh rate 60MHz */
2863 ivideo.refresh_rate = 60;
2866 ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
2867 ivideo.video_width = sisbios_mode[mode_idx].xres;
2868 ivideo.video_height = sisbios_mode[mode_idx].yres;
2869 video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
2871 if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB"))
2873 printk(KERN_ERR
2874 "sisfb: abort, cannot reserve video memory at 0x%lx\n",
2875 ivideo.video_base);
2876 return -1;
2879 if (!request_mem_region(ivideo.mmio_base, MMIO_SIZE, "sisfb MMIO"))
2881 printk(KERN_ERR
2882 "sisfb: abort, cannot reserve mmio memory at 0x%lx\n",
2883 ivideo.mmio_base);
2884 return -1;
2887 ivideo.video_vbase = ioremap(ivideo.video_base, ivideo.video_size);
2888 ivideo.mmio_vbase = ioremap(ivideo.mmio_base, MMIO_SIZE);
2889 rom_vbase = (unsigned long) ioremap(rom_base, MAX_ROM_SCAN);
2891 printk(KERN_INFO
2892 "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
2893 ivideo.video_base, ivideo.video_vbase,
2894 ivideo.video_size / 1024);
2895 printk(KERN_INFO "sisfb: mode is %dx%dx%d, linelength=%d\n",
2896 ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
2897 video_linelength);
2899 /* enable 2D engine */
2900 vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE);
2901 jTemp = vgarb(SEQ_DATA);
2902 jTemp |= SIS_2D_ENABLE;
2903 vgawb(SEQ_DATA, jTemp);
2905 pre_setmode();
2907 if (SiSSetMode(mode_no)) {
2908 DPRINTK("sisfb: set mode[0x%x]: failed\n", 0x30);
2909 return -1;
2912 post_setmode();
2914 crtc_to_var(&default_var);
2916 fb_info.changevar = NULL;
2917 fb_info.node = -1;
2918 fb_info.fbops = &sisfb_ops;
2919 fb_info.disp = &disp;
2920 fb_info.switch_con = &sisfb_switch;
2921 fb_info.updatevar = &sisfb_update_var;
2922 fb_info.blank = &sisfb_blank;
2923 fb_info.flags = FBINFO_FLAG_DEFAULT;
2925 sisfb_set_disp(-1, &default_var);
2927 if (sisfb_heap_init()) {
2928 DPRINTK("sisfb: Failed to enable offscreen heap\n");
2931 /* to avoid the inversed bgcolor bug of the initial state */
2932 vc_resize_con(1, 1, 0);
2934 if (register_framebuffer(&fb_info) < 0)
2935 return -EINVAL;
2937 ivideo.status = CRT1;
2939 printk(KERN_INFO "fb%d: %s frame buffer device\n",
2940 GET_FB_IDX(fb_info.node), fb_info.modename);
2942 return 0;
2945 #ifdef MODULE
2947 static char *mode = NULL;
2948 static unsigned int rate = 0;
2950 MODULE_PARM(mode, "s");
2951 MODULE_PARM(rate, "i");
2953 int init_module(void)
2955 if (mode)
2956 search_mode(mode);
2958 ivideo.refresh_rate = rate;
2960 sisfb_init();
2962 return 0;
2965 void cleanup_module(void)
2967 unregister_framebuffer(&fb_info);
2969 #endif /* MODULE */
2972 EXPORT_SYMBOL(sis_malloc);
2973 EXPORT_SYMBOL(sis_free);
2975 EXPORT_SYMBOL(ivideo);