- pre5:
[davej-history.git] / drivers / video / sis / sis_main.c
blob592180c18810f07a13ade3988bbc553b657d8659
1 /*
2 * SiS 300/630/540 frame buffer device For Kernal 2.4.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/config.h>
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/errno.h>
18 #include <linux/string.h>
19 #include <linux/mm.h>
20 #include <linux/tty.h>
21 #include <linux/malloc.h>
22 #include <linux/delay.h>
23 #include <linux/fb.h>
24 #include <linux/console.h>
25 #include <linux/selection.h>
26 #include <linux/ioport.h>
27 #include <linux/init.h>
28 #include <linux/pci.h>
29 #include <linux/vt_kern.h>
30 #include <linux/capability.h>
31 #include <linux/sisfb.h>
32 #include <linux/fs.h>
34 #include <asm/io.h>
35 #include <asm/mtrr.h>
37 #include <video/fbcon.h>
38 #include <video/fbcon-cfb8.h>
39 #include <video/fbcon-cfb16.h>
40 #include <video/fbcon-cfb24.h>
41 #include <video/fbcon-cfb32.h>
43 #include "sis.h"
44 #ifdef NOBIOS
45 #include "bios.h"
46 #endif
48 /* ------------------- Constant Definitions ------------------------- */
50 /* capabilities */
51 #define TURBO_QUEUE_CAP 0x80
52 #define HW_CURSOR_CAP 0x40
54 /* VGA register Offsets */
55 #define SEQ_ADR (0x14)
56 #define SEQ_DATA (0x15)
57 #define DAC_ADR (0x18)
58 #define DAC_DATA (0x19)
59 #define CRTC_ADR (0x24)
60 #define CRTC_DATA (0x25)
62 #define DAC2_ADR 0x16 - 0x30
63 #define DAC2_DATA 0x17 - 0x30
66 /* SiS indexed register indexes */
67 #define IND_SIS_PASSWORD (0x05)
68 #define IND_SIS_DRAM_SIZE (0x14)
69 #define IND_SIS_MODULE_ENABLE (0x1E)
70 #define IND_SIS_PCI_ADDRESS_SET (0x20)
71 #define IND_SIS_TURBOQUEUE_ADR (0x26)
72 #define IND_SIS_TURBOQUEUE_SET (0x27)
74 /* Sis register value */
75 #define SIS_PASSWORD (0x86)
77 #define SIS_2D_ENABLE (0x40)
79 #define SIS_MEM_MAP_IO_ENABLE (0x01)
80 #define SIS_PCI_ADDR_ENABLE (0x80)
82 //#define MMIO_SIZE 0x10000 /* 64K MMIO capability */
83 #define MAX_ROM_SCAN 0x10000
85 #define RESERVED_MEM_SIZE_4M 0x400000 /* 4M */
86 #define RESERVED_MEM_SIZE_8M 0x800000 /* 8M */
88 /* Mode set stuff */
89 #define DEFAULT_MODE 0 /* 640x480x8 */
90 #define DEFAULT_LCDMODE 9 /* 800x600x8 */
91 #define DEFAULT_TVMODE 9 /* 800x600x8 */
93 /* heap stuff */
94 #define OH_ALLOC_SIZE 4000
95 #define SENTINEL 0x7fffffff
97 #define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */
98 #define HW_CURSOR_AREA_SIZE 0x1000 /* 4K */
100 /* ------------------- Global Variables ----------------------------- */
102 struct video_info ivideo;
103 HW_DEVICE_EXTENSION HwExt={0,0,0,0,0,0};
105 struct GlyInfo {
106 unsigned char ch;
107 int fontwidth;
108 int fontheight;
109 u8 gmask[72];
110 int ngmask;
113 /* Supported SiS Chips list */
114 static struct board {
115 u16 vendor, device;
116 const char *name;
117 } dev_list[] = {
118 {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"},
119 {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"},
120 {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"},
121 {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_730_VGA, "SIS 730"},
122 {0, 0, NULL}
125 /* card parameters */
126 unsigned long rom_base;
127 unsigned long rom_vbase;
129 /* mode */
130 static int video_type = FB_TYPE_PACKED_PIXELS;
131 static int video_linelength;
132 static int video_cmap_len;
133 static int sisfb_off = 0;
134 static int crt1off = 0;
136 static struct fb_var_screeninfo default_var = {
137 0, 0, 0, 0,
138 0, 0,
141 {0, 8, 0},
142 {0, 8, 0},
143 {0, 8, 0},
144 {0, 0, 0},
146 FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
148 FB_VMODE_NONINTERLACED,
149 {0, 0, 0, 0, 0, 0}
152 static struct display disp;
153 static struct fb_info fb_info;
154 static struct {
155 u16 blue, green, red, pad;
156 } palette[256];
157 static union {
158 #ifdef FBCON_HAS_CFB16
159 u16 cfb16[16];
160 #endif
161 #ifdef FBCON_HAS_CFB24
162 u32 cfb24[16];
163 #endif
164 #ifdef FBCON_HAS_CFB32
165 u32 cfb32[16];
166 #endif
167 } fbcon_cmap;
169 static int inverse = 0;
170 static int currcon = 0;
172 static struct display_switch sisfb_sw;
174 static u8 caps = 0;
175 static unsigned long MMIO_SIZE = 0;
177 /* ModeSet stuff */
178 unsigned char uDispType = 0;
179 int mode_idx = -1;
180 u8 mode_no = 0;
181 u8 rate_idx = 0;
183 static const struct _sisbios_mode {
184 char name[15];
185 u8 mode_no;
186 u16 xres;
187 u16 yres;
188 u16 bpp;
189 u16 rate_idx;
190 u16 cols;
191 u16 rows;
192 } sisbios_mode[] = {
193 {"640x480x8", 0x2E, 640, 480, 8, 1, 80, 30},
194 {"640x480x16", 0x44, 640, 480, 16, 1, 80, 30},
195 {"640x480x32", 0x62, 640, 480, 32, 1, 80, 30},
196 {"720x480x8", 0x31, 720, 480, 8, 1, 90, 30}, /* NTSC TV */
197 {"720x480x16", 0x33, 720, 480, 16, 1, 90, 30},
198 {"720x480x32", 0x35, 720, 480, 32, 1, 90, 30},
199 {"720x576x8", 0x32, 720, 576, 8, 1, 90, 36}, /* PAL TV */
200 {"720x576x16", 0x34, 720, 576, 16, 1, 90, 36},
201 {"720x576x32", 0x36, 720, 576, 32, 1, 90, 36},
202 {"800x600x8", 0x30, 800, 600, 8, 2, 100, 37},
203 {"800x600x16", 0x47, 800, 600, 16, 2, 100, 37},
204 {"800x600x32", 0x63, 800, 600, 32, 2, 100, 37},
205 {"1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48},
206 {"1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48},
207 {"1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48},
208 {"1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64},
209 {"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64},
210 {"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64},
211 {"1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75},
212 {"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75},
213 {"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75},
214 {"1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75},
215 {"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75},
216 {"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75},
217 {"\0", 0x00, 0, 0, 0, 0, 0, 0}
220 static struct _vrate {
221 u16 idx;
222 u16 xres;
223 u16 yres;
224 u16 refresh;
225 } vrate[] = {
226 {1, 640, 480, 60}, {2, 640, 480, 72}, {3, 640, 480, 75}, {4, 640, 480, 85},
227 {5, 640, 480, 100}, {6, 640, 480, 120}, {7, 640, 480, 160}, {8, 640, 480, 200},
228 {1, 720, 480, 60},
229 {1, 720, 576, 50},
230 {1, 800, 600, 56}, {2, 800, 600, 60}, {3, 800, 600, 72}, {4, 800, 600, 75},
231 {5, 800, 600, 85}, {6, 800, 600, 100}, {7, 800, 600, 120}, {8, 800, 600, 160},
232 {1, 1024, 768, 43}, {2, 1024, 768, 60}, {3, 1024, 768, 70}, {4, 1024, 768, 75},
233 {5, 1024, 768, 85}, {6, 1024, 768, 100}, {7, 1024, 768, 120},
234 {1, 1280, 1024, 43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85},
235 {1, 1600, 1200, 60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75},
236 {5, 1600, 1200, 85},
237 {1, 1920, 1440, 60},
238 {0, 0, 0, 0}
242 /* HEAP stuff */
244 struct OH {
245 struct OH *pohNext;
246 struct OH *pohPrev;
247 unsigned long ulOffset;
248 unsigned long ulSize;
251 struct OHALLOC {
252 struct OHALLOC *pohaNext;
253 struct OH aoh[1];
256 struct HEAP {
257 struct OH ohFree;
258 struct OH ohUsed;
259 struct OH *pohFreeList;
260 struct OHALLOC *pohaChain;
262 unsigned long ulMaxFreeSize;
265 struct HEAP heap;
266 unsigned long heap_start;
267 unsigned long heap_end;
268 unsigned long heap_size;
270 unsigned int tqueue_pos;
271 unsigned long hwcursor_vbase;
274 /* -------------------- Macro definitions --------------------------- */
276 #ifdef SISFBDEBUG
277 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
278 #else
279 #define DPRINTK(fmt, args...)
280 #endif
282 #define vgawb(reg,data) \
283 (outb(data, ivideo.vga_base+reg))
284 #define vgaww(reg,data) \
285 (outw(data, ivideo.vga_base+reg))
286 #define vgawl(reg,data) \
287 (outl(data, ivideo.vga_base+reg))
288 #define vgarb(reg) \
289 (inb(ivideo.vga_base+reg))
291 /* ---------------------- Routine Prototype ------------------------- */
293 /* Interface used by the world */
294 int sisfb_setup(char *options);
295 static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
296 struct fb_info *info);
297 static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
298 struct fb_info *info);
299 static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
300 struct fb_info *info);
301 static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
302 struct fb_info *info);
303 static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
304 struct fb_info *info);
305 static int sisfb_ioctl(struct inode *inode, struct file *file,
306 unsigned int cmd, unsigned long arg, int con,
307 struct fb_info *info);
309 /* Interface to the low level console driver */
310 int sisfb_init(void);
311 static int sisfb_update_var(int con, struct fb_info *info);
312 static int sisfb_switch(int con, struct fb_info *info);
313 static void sisfb_blank(int blank, struct fb_info *info);
315 /* Internal routines */
316 static void crtc_to_var(struct fb_var_screeninfo *var);
317 static void sisfb_set_disp(int con, struct fb_var_screeninfo *var);
318 static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
319 unsigned *blue, unsigned *transp,
320 struct fb_info *fb_info);
321 static int sis_setcolreg(unsigned regno, unsigned red, unsigned green,
322 unsigned blue, unsigned transp,
323 struct fb_info *fb_info);
324 static void do_install_cmap(int con, struct fb_info *info);
325 static int do_set_var(struct fb_var_screeninfo *var, int isactive,
326 struct fb_info *info);
328 /* set-mode routines */
329 void SetReg1(u16 port, u16 index, u16 data);
330 void SetReg3(u16 port, u16 data);
331 void SetReg4(u16 port, unsigned long data);
332 u8 GetReg1(u16 port, u16 index);
333 u8 GetReg2(u16 port);
334 u32 GetReg3(u16 port);
335 extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,
336 USHORT ModeNo);
337 extern BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension);
338 static void pre_setmode(void);
339 static void post_setmode(void);
340 static void search_mode(const char *name);
341 static u8 search_refresh_rate(unsigned int rate);
343 /* heap routines */
344 static int sisfb_heap_init(void);
345 static struct OH *poh_new_node(void);
346 static struct OH *poh_allocate(unsigned long size);
347 static struct OH *poh_free(unsigned long base);
348 static void delete_node(struct OH *poh);
349 static void insert_node(struct OH *pohList, struct OH *poh);
350 static void free_node(struct OH *poh);
352 /* ---------------------- Internal Routines ------------------------- */
354 inline static u32 RD32(unsigned char *base, s32 off)
356 return readl(base + off);
359 inline static void WR32(unsigned char *base, s32 off, u32 v)
361 writel(v, base + off);
364 inline static void WR16(unsigned char *base, s32 off, u16 v)
366 writew(v, base + off);
369 inline static void WR8(unsigned char *base, s32 off, u8 v)
371 writeb(v, base + off);
374 inline static u32 regrl(s32 off)
376 return RD32(ivideo.mmio_vbase, off);
379 inline static void regwl(s32 off, u32 v)
381 WR32(ivideo.mmio_vbase, off, v);
384 inline static void regww(s32 off, u16 v)
386 WR16(ivideo.mmio_vbase, off, v);
389 inline static void regwb(s32 off, u8 v)
391 WR8(ivideo.mmio_vbase, off, v);
395 * Get CRTC registers to set var
397 static void crtc_to_var(struct fb_var_screeninfo *var)
399 u16 VRE, VBE, VRS, VBS, VDE, VT;
400 u16 HRE, HBE, HRS, HBS, HDE, HT;
401 u8 uSRdata, uCRdata, uCRdata2, uCRdata3, uMRdata;
402 int A, B, C, D, E, F, temp;
403 double hrate, drate;
405 vgawb(SEQ_ADR, 0x6);
406 uSRdata = vgarb(SEQ_DATA);
408 if (uSRdata & 0x20)
409 var->vmode = FB_VMODE_INTERLACED;
410 else
411 var->vmode = FB_VMODE_NONINTERLACED;
413 switch ((uSRdata & 0x1c) >> 2) {
414 case 0:
415 var->bits_per_pixel = 8;
416 break;
417 case 2:
418 var->bits_per_pixel = 16;
419 break;
420 case 4:
421 var->bits_per_pixel = 32;
422 break;
425 switch (var->bits_per_pixel) {
426 case 8:
427 var->red.length = 6;
428 var->green.length = 6;
429 var->blue.length = 6;
430 video_cmap_len = 256;
431 break;
432 case 16: /* RGB 565 */
433 var->red.offset = 11;
434 var->red.length = 5;
435 var->green.offset = 5;
436 var->green.length = 6;
437 var->blue.offset = 0;
438 var->blue.length = 5;
439 var->transp.offset = 0;
440 var->transp.length = 0;
441 video_cmap_len = 16;
443 break;
444 case 24: /* RGB 888 */
445 var->red.offset = 16;
446 var->red.length = 8;
447 var->green.offset = 8;
448 var->green.length = 8;
449 var->blue.offset = 0;
450 var->blue.length = 8;
451 var->transp.offset = 0;
452 var->transp.length = 0;
453 video_cmap_len = 16;
454 break;
455 case 32:
456 var->red.offset = 16;
457 var->red.length = 8;
458 var->green.offset = 8;
459 var->green.length = 8;
460 var->blue.offset = 0;
461 var->blue.length = 8;
462 var->transp.offset = 24;
463 var->transp.length = 8;
464 video_cmap_len = 16;
465 break;
468 vgawb(SEQ_ADR, 0xa);
469 uSRdata = vgarb(SEQ_DATA);
471 vgawb(CRTC_ADR, 0x6);
472 uCRdata = vgarb(CRTC_DATA);
473 vgawb(CRTC_ADR, 0x7);
474 uCRdata2 = vgarb(CRTC_DATA);
475 VT =
476 (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x01) << 8) |
477 ((u16) (uCRdata2 & 0x20) << 4) | ((u16) (uSRdata & 0x01) <<
478 10);
479 A = VT + 2;
481 vgawb(CRTC_ADR, 0x12);
482 uCRdata = vgarb(CRTC_DATA);
483 VDE =
484 (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x02) << 7) |
485 ((u16) (uCRdata2 & 0x40) << 3) | ((u16) (uSRdata & 0x02) << 9);
486 E = VDE + 1;
488 vgawb(CRTC_ADR, 0x10);
489 uCRdata = vgarb(CRTC_DATA);
490 VRS =
491 (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x04) << 6) |
492 ((u16) (uCRdata2 & 0x80) << 2) | ((u16) (uSRdata & 0x08) << 7);
493 F = VRS + 1 - E;
495 vgawb(CRTC_ADR, 0x15);
496 uCRdata = vgarb(CRTC_DATA);
497 vgawb(CRTC_ADR, 0x9);
498 uCRdata3 = vgarb(CRTC_DATA);
499 VBS =
500 (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x08) << 5) |
501 ((u16) (uCRdata3 & 0x20) << 4) | ((u16) (uSRdata & 0x04) << 8);
503 vgawb(CRTC_ADR, 0x16);
504 uCRdata = vgarb(CRTC_DATA);
505 VBE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x10) << 4);
506 temp = VBE - ((E - 1) & 511);
507 B = (temp > 0) ? temp : (temp + 512);
509 vgawb(CRTC_ADR, 0x11);
510 uCRdata = vgarb(CRTC_DATA);
511 VRE = (uCRdata & 0x0f) | ((uSRdata & 0x20) >> 1);
512 temp = VRE - ((E + F - 1) & 31);
513 C = (temp > 0) ? temp : (temp + 32);
515 D = B - F - C;
517 var->yres = var->yres_virtual = E;
518 var->upper_margin = D;
519 var->lower_margin = F;
520 var->vsync_len = C;
522 vgawb(SEQ_ADR, 0xb);
523 uSRdata = vgarb(SEQ_DATA);
525 vgawb(CRTC_ADR, 0x0);
526 uCRdata = vgarb(CRTC_DATA);
527 HT = (uCRdata & 0xff) | ((u16) (uSRdata & 0x03) << 8);
528 A = HT + 5;
530 vgawb(CRTC_ADR, 0x1);
531 uCRdata = vgarb(CRTC_DATA);
532 HDE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x0C) << 6);
533 E = HDE + 1;
535 vgawb(CRTC_ADR, 0x4);
536 uCRdata = vgarb(CRTC_DATA);
537 HRS = (uCRdata & 0xff) | ((u16) (uSRdata & 0xC0) << 2);
538 F = HRS - E - 3;
540 vgawb(CRTC_ADR, 0x2);
541 uCRdata = vgarb(CRTC_DATA);
542 HBS = (uCRdata & 0xff) | ((u16) (uSRdata & 0x30) << 4);
544 vgawb(SEQ_ADR, 0xc);
545 uSRdata = vgarb(SEQ_DATA);
546 vgawb(CRTC_ADR, 0x3);
547 uCRdata = vgarb(CRTC_DATA);
548 vgawb(CRTC_ADR, 0x5);
549 uCRdata2 = vgarb(CRTC_DATA);
550 HBE =
551 (uCRdata & 0x1f) | ((u16) (uCRdata2 & 0x80) >> 2) |
552 ((u16) (uSRdata & 0x03) << 6);
553 HRE = (uCRdata2 & 0x1f) | ((uSRdata & 0x04) << 3);
555 temp = HBE - ((E - 1) & 255);
556 B = (temp > 0) ? temp : (temp + 256);
558 temp = HRE - ((E + F + 3) & 63);
559 C = (temp > 0) ? temp : (temp + 64);
561 D = B - F - C;
563 var->xres = var->xres_virtual = E * 8;
564 var->left_margin = D * 8;
565 var->right_margin = F * 8;
566 var->hsync_len = C * 8;
568 var->activate = FB_ACTIVATE_NOW;
570 var->sync = 0;
572 uMRdata = vgarb(0x1C);
573 if (uMRdata & 0x80)
574 var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
575 else
576 var->sync |= FB_SYNC_VERT_HIGH_ACT;
578 if (uMRdata & 0x40)
579 var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
580 else
581 var->sync |= FB_SYNC_HOR_HIGH_ACT;
583 VT += 2;
584 VT <<= 1;
585 HT = (HT + 5) * 8;
587 hrate = (double) ivideo.refresh_rate * (double) VT / 2;
588 drate = hrate * HT;
589 var->pixclock = (u32) (1E12 / drate);
592 static void sisfb_set_disp(int con, struct fb_var_screeninfo *var)
594 struct fb_fix_screeninfo fix;
595 struct display *display;
596 struct display_switch *sw;
597 u32 flags;
599 if (con >= 0)
600 display = &fb_display[con];
601 else
602 display = &disp; /* used during initialization */
604 sisfb_get_fix(&fix, con, 0);
606 display->screen_base = ivideo.video_vbase;
607 display->visual = fix.visual;
608 display->type = fix.type;
609 display->type_aux = fix.type_aux;
610 display->ypanstep = fix.ypanstep;
611 display->ywrapstep = fix.ywrapstep;
612 display->line_length = fix.line_length;
613 display->next_line = fix.line_length;
614 /*display->can_soft_blank = 1; */
615 display->can_soft_blank = 0;
616 display->inverse = inverse;
617 display->var = *var;
619 save_flags(flags);
620 switch (ivideo.video_bpp) {
621 #ifdef FBCON_HAS_CFB8
622 case 8:
623 sw = &fbcon_cfb8;
624 break;
625 #endif
626 #ifdef FBCON_HAS_CFB16
627 case 15:
628 case 16:
629 sw = &fbcon_cfb16;
630 display->dispsw_data = fbcon_cmap.cfb16;
631 break;
632 #endif
633 #ifdef FBCON_HAS_CFB24
634 case 24:
635 sw = &fbcon_cfb24;
636 display->dispsw_data = fbcon_cmap.cfb24;
637 break;
638 #endif
639 #ifdef FBCON_HAS_CFB32
640 case 32:
641 sw = &fbcon_cfb32;
642 display->dispsw_data = fbcon_cmap.cfb32;
643 break;
644 #endif
645 default:
646 sw = &fbcon_dummy;
647 return;
649 memcpy(&sisfb_sw, sw, sizeof(*sw));
650 display->dispsw = &sisfb_sw;
651 restore_flags(flags);
653 display->scrollmode = SCROLL_YREDRAW;
654 sisfb_sw.bmove = fbcon_redraw_bmove;
659 * Read a single color register and split it into colors/transparent.
660 * Return != 0 for invalid regno.
662 static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
663 unsigned *transp, struct fb_info *fb_info)
665 if (regno >= video_cmap_len)
666 return 1;
668 *red = palette[regno].red;
669 *green = palette[regno].green;
670 *blue = palette[regno].blue;
671 *transp = 0;
672 return 0;
676 * Set a single color register. The values supplied are already
677 * rounded down to the hardware's capabilities (according to the
678 * entries in the var structure). Return != 0 for invalid regno.
680 static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
681 unsigned transp, struct fb_info *fb_info)
684 if (regno >= video_cmap_len)
685 return 1;
687 palette[regno].red = red;
688 palette[regno].green = green;
689 palette[regno].blue = blue;
691 switch (ivideo.video_bpp) {
692 #ifdef FBCON_HAS_CFB8
693 case 8:
694 vgawb(DAC_ADR, regno);
695 vgawb(DAC_DATA, red >> 10);
696 vgawb(DAC_DATA, green >> 10);
697 vgawb(DAC_DATA, blue >> 10);
698 if(uDispType & MASK_DISPTYPE_DISP2)
700 /* VB connected */
701 vgawb(DAC2_ADR, regno);
702 vgawb(DAC2_DATA, red >> 8);
703 vgawb(DAC2_DATA, green >> 8);
704 vgawb(DAC2_DATA, blue >> 8);
707 break;
708 #endif
709 #ifdef FBCON_HAS_CFB16
710 case 15:
711 case 16:
712 fbcon_cmap.cfb16[regno] =
713 ((red & 0xf800)) |
714 ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
715 break;
716 #endif
717 #ifdef FBCON_HAS_CFB24
718 case 24:
719 red >>= 8;
720 green >>= 8;
721 blue >>= 8;
722 fbcon_cmap.cfb24[regno] =
723 (red << 16) | (green << 8) | (blue);
724 break;
725 #endif
726 #ifdef FBCON_HAS_CFB32
727 case 32:
728 red >>= 8;
729 green >>= 8;
730 blue >>= 8;
731 fbcon_cmap.cfb32[regno] =
732 (red << 16) | (green << 8) | (blue);
733 break;
734 #endif
736 return 0;
739 static void do_install_cmap(int con, struct fb_info *info)
741 if (con != currcon)
742 return;
744 if (fb_display[con].cmap.len)
745 fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info);
746 else
747 fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
748 sis_setcolreg, info);
751 static int do_set_var(struct fb_var_screeninfo *var, int isactive,
752 struct fb_info *info)
754 unsigned int htotal =
755 var->left_margin + var->xres + var->right_margin +
756 var->hsync_len;
757 unsigned int vtotal =
758 var->upper_margin + var->yres + var->lower_margin +
759 var->vsync_len;
760 double drate = 0, hrate = 0;
761 int found_mode = 0;
762 int old_mode;
764 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
765 vtotal <<= 1;
766 else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
767 vtotal <<= 2;
768 else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
769 var->yres <<= 1;
772 if (!htotal || !vtotal) {
773 DPRINTK("Invalid 'var' Information!\n");
774 return 1;
777 drate = 1E12 / var->pixclock;
778 hrate = drate / htotal;
779 ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
781 old_mode = mode_idx;
782 mode_idx = 0;
784 while ((sisbios_mode[mode_idx].mode_no != 0)
785 && (sisbios_mode[mode_idx].xres <= var->xres)) {
786 if ((sisbios_mode[mode_idx].xres == var->xres)
787 && (sisbios_mode[mode_idx].yres == var->yres)
788 && (sisbios_mode[mode_idx].bpp == var->bits_per_pixel)) {
789 mode_no = sisbios_mode[mode_idx].mode_no;
790 found_mode = 1;
791 break;
793 mode_idx++;
796 if(found_mode)
798 switch(uDispType & MASK_DISPTYPE_DISP2)
800 case MASK_DISPTYPE_LCD:
801 switch(HwExt.usLCDType)
803 case LCD1024:
804 if(var->xres > 1024)
805 found_mode = 0;
806 break;
807 case LCD1280:
808 if(var->xres > 1280)
809 found_mode = 0;
810 break;
811 case LCD2048:
812 if(var->xres > 2048)
813 found_mode = 0;
814 break;
815 case LCD1920:
816 if(var->xres > 1920)
817 found_mode = 0;
818 break;
819 case LCD1600:
820 if(var->xres > 1600)
821 found_mode = 0;
822 break;
823 case LCD800:
824 if(var->xres > 800)
825 found_mode = 0;
826 break;
827 case LCD640:
828 if(var->xres > 640)
829 found_mode = 0;
830 break;
831 default:
832 found_mode = 0;
834 if(var->xres == 720) /* mode only for TV */
835 found_mode = 0;
836 break;
837 case MASK_DISPTYPE_TV:
838 switch(var->xres)
840 case 800:
841 case 640:
842 break;
843 case 720:
844 if(ivideo.TV_type == TVMODE_NTSC)
846 if(sisbios_mode[mode_idx].yres != 480)
847 found_mode = 0;
849 else if(ivideo.TV_type == TVMODE_PAL)
851 if(sisbios_mode[mode_idx].yres != 576)
852 found_mode = 0;
854 break;
855 default:
856 /* illegal mode */
857 found_mode = 0;
859 break;
863 if (!found_mode) {
864 printk("sisfb does not support mode %dx%d-%d\n", var->xres,
865 var->yres, var->bits_per_pixel);
866 mode_idx = old_mode;
867 return 1;
870 if (search_refresh_rate(ivideo.refresh_rate) == 0) {
871 /* not supported rate */
872 rate_idx = sisbios_mode[mode_idx].rate_idx;
873 ivideo.refresh_rate = 60;
876 if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
877 pre_setmode();
879 if (SiSSetMode(&HwExt, mode_no)) {
880 DPRINTK("sisfb: set mode[0x%x]: failed\n",
881 mode_no);
882 return 1;
885 post_setmode();
887 printk(KERN_DEBUG "Current Mode: %dx%dx%d-%d \n", sisbios_mode[mode_idx].xres,
888 sisbios_mode[mode_idx].yres, sisbios_mode[mode_idx].bpp, ivideo.refresh_rate);
890 ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
891 ivideo.video_vwidth = ivideo.video_width = sisbios_mode[mode_idx].xres;
892 ivideo.video_vheight = ivideo.video_height = sisbios_mode[mode_idx].yres;
893 ivideo.org_x = ivideo.org_y = 0;
894 video_linelength =
895 ivideo.video_width * (ivideo.video_bpp >> 3);
897 DPRINTK("Current Mode: %dx%d-%d line_length=%d\n",
898 ivideo.video_width, ivideo.video_height,
899 ivideo.video_bpp, video_linelength);
902 return 0;
905 /* ---------------------- Draw Funtions ----------------------------- */
907 static void sis_get_glyph(struct GlyInfo *gly)
909 struct display *p = &fb_display[currcon];
910 u16 c;
911 u8 *cdat;
912 int widthb;
913 u8 *gbuf = gly->gmask;
914 int size;
917 gly->fontheight = fontheight(p);
918 gly->fontwidth = fontwidth(p);
919 widthb = (fontwidth(p) + 7) / 8;
921 c = gly->ch & p->charmask;
922 if (fontwidth(p) <= 8)
923 cdat = p->fontdata + c * fontheight(p);
924 else
925 cdat = p->fontdata + (c * fontheight(p) << 1);
927 size = fontheight(p) * widthb;
928 memcpy(gbuf, cdat, size);
929 gly->ngmask = size;
933 /* ---------------------- HEAP Routines ----------------------------- */
936 * Heap Initialization
939 static int sisfb_heap_init(void)
941 struct OH *poh;
942 u8 jTemp, tq_state;
944 if(ivideo.video_size > 0x800000)
945 /* video ram is large than 8M */
946 heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_8M;
947 else
948 heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_4M;
950 heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
951 heap_size = heap_end - heap_start;
954 /* Setting for Turbo Queue */
955 if (heap_size >= TURBO_QUEUE_AREA_SIZE) {
956 tqueue_pos =
957 (ivideo.video_size -
958 TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
959 jTemp = (u8) (tqueue_pos & 0xff);
960 vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET);
961 tq_state = vgarb(SEQ_DATA);
962 tq_state |= 0xf0;
963 tq_state &= 0xfc;
964 tq_state |= (u8) (tqueue_pos >> 8);
965 vgawb(SEQ_DATA, tq_state);
966 vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR);
967 vgawb(SEQ_DATA, jTemp);
969 caps |= TURBO_QUEUE_CAP;
971 heap_end -= TURBO_QUEUE_AREA_SIZE;
972 heap_size -= TURBO_QUEUE_AREA_SIZE;
975 /* Setting for HW cursor(4K) */
976 if (heap_size >= HW_CURSOR_AREA_SIZE) {
977 heap_end -= HW_CURSOR_AREA_SIZE;
978 heap_size -= HW_CURSOR_AREA_SIZE;
979 hwcursor_vbase = heap_end;
981 caps |= HW_CURSOR_CAP;
984 heap.pohaChain = NULL;
985 heap.pohFreeList = NULL;
987 poh = poh_new_node();
989 if (poh == NULL)
990 return 1;
992 /* The first node describles the entire heap size */
993 poh->pohNext = &heap.ohFree;
994 poh->pohPrev = &heap.ohFree;
995 poh->ulSize = heap_end - heap_start + 1;
996 poh->ulOffset = heap_start - (unsigned long) ivideo.video_vbase;
998 DPRINTK("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n",
999 (char *) heap_start, (char *) heap_end,
1000 (unsigned int) poh->ulSize / 1024);
1002 DPRINTK("sisfb:First Node offset:0x%x, size:%dk\n",
1003 (unsigned int) poh->ulOffset, (unsigned int) poh->ulSize / 1024);
1005 /* The second node in our free list sentinel */
1006 heap.ohFree.pohNext = poh;
1007 heap.ohFree.pohPrev = poh;
1008 heap.ohFree.ulSize = 0;
1009 heap.ulMaxFreeSize = poh->ulSize;
1011 /* Initialize the discardable list */
1012 heap.ohUsed.pohNext = &heap.ohUsed;
1013 heap.ohUsed.pohPrev = &heap.ohUsed;
1014 heap.ohUsed.ulSize = SENTINEL;
1016 return 0;
1020 * Allocates a basic memory unit in which we'll pack our data structures.
1023 static struct OH *poh_new_node(void)
1025 int i;
1026 unsigned long cOhs;
1027 struct OHALLOC *poha;
1028 struct OH *poh;
1030 if (heap.pohFreeList == NULL) {
1031 poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
1033 poha->pohaNext = heap.pohaChain;
1034 heap.pohaChain = poha;
1036 cOhs =
1037 (OH_ALLOC_SIZE -
1038 sizeof(struct OHALLOC)) / sizeof(struct OH) + 1;
1040 poh = &poha->aoh[0];
1041 for (i = cOhs - 1; i != 0; i--) {
1042 poh->pohNext = poh + 1;
1043 poh = poh + 1;
1046 poh->pohNext = NULL;
1047 heap.pohFreeList = &poha->aoh[0];
1050 poh = heap.pohFreeList;
1051 heap.pohFreeList = poh->pohNext;
1053 return (poh);
1057 * Allocates space, return NULL when failed
1060 static struct OH *poh_allocate(unsigned long size)
1062 struct OH *pohThis;
1063 struct OH *pohRoot;
1064 int bAllocated = 0;
1066 if (size > heap.ulMaxFreeSize) {
1067 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
1068 (unsigned int) size / 1024);
1069 return (NULL);
1072 pohThis = heap.ohFree.pohNext;
1074 while (pohThis != &heap.ohFree) {
1075 if (size <= pohThis->ulSize) {
1076 bAllocated = 1;
1077 break;
1079 pohThis = pohThis->pohNext;
1082 if (!bAllocated) {
1083 DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
1084 (unsigned int) size / 1024);
1085 return (NULL);
1088 if (size == pohThis->ulSize) {
1089 pohRoot = pohThis;
1090 delete_node(pohThis);
1091 } else {
1092 pohRoot = poh_new_node();
1094 if (pohRoot == NULL) {
1095 return (NULL);
1098 pohRoot->ulOffset = pohThis->ulOffset;
1099 pohRoot->ulSize = size;
1101 pohThis->ulOffset += size;
1102 pohThis->ulSize -= size;
1105 heap.ulMaxFreeSize -= size;
1107 pohThis = &heap.ohUsed;
1108 insert_node(pohThis, pohRoot);
1110 return (pohRoot);
1114 * To remove a node from a list.
1117 static void delete_node(struct OH *poh)
1119 struct OH *pohPrev;
1120 struct OH *pohNext;
1123 pohPrev = poh->pohPrev;
1124 pohNext = poh->pohNext;
1126 pohPrev->pohNext = pohNext;
1127 pohNext->pohPrev = pohPrev;
1129 return;
1133 * To insert a node into a list.
1136 static void insert_node(struct OH *pohList, struct OH *poh)
1138 struct OH *pohTemp;
1140 pohTemp = pohList->pohNext;
1142 pohList->pohNext = poh;
1143 pohTemp->pohPrev = poh;
1145 poh->pohPrev = pohList;
1146 poh->pohNext = pohTemp;
1150 * Frees an off-screen heap allocation.
1153 static struct OH *poh_free(unsigned long base)
1156 struct OH *pohThis;
1157 struct OH *pohFreed;
1158 struct OH *pohPrev;
1159 struct OH *pohNext;
1160 unsigned long ulUpper;
1161 unsigned long ulLower;
1162 int foundNode = 0;
1164 pohFreed = heap.ohUsed.pohNext;
1166 while (pohFreed != &heap.ohUsed) {
1167 if (pohFreed->ulOffset == base) {
1168 foundNode = 1;
1169 break;
1172 pohFreed = pohFreed->pohNext;
1175 if (!foundNode)
1176 return (NULL);
1178 heap.ulMaxFreeSize += pohFreed->ulSize;
1180 pohPrev = pohNext = NULL;
1181 ulUpper = pohFreed->ulOffset + pohFreed->ulSize;
1182 ulLower = pohFreed->ulOffset;
1184 pohThis = heap.ohFree.pohNext;
1186 while (pohThis != &heap.ohFree) {
1187 if (pohThis->ulOffset == ulUpper) {
1188 pohNext = pohThis;
1190 else if ((pohThis->ulOffset + pohThis->ulSize) ==
1191 ulLower) {
1192 pohPrev = pohThis;
1194 pohThis = pohThis->pohNext;
1197 delete_node(pohFreed);
1199 if (pohPrev && pohNext) {
1200 pohPrev->ulSize += (pohFreed->ulSize + pohNext->ulSize);
1201 delete_node(pohNext);
1202 free_node(pohFreed);
1203 free_node(pohNext);
1204 return (pohPrev);
1207 if (pohPrev) {
1208 pohPrev->ulSize += pohFreed->ulSize;
1209 free_node(pohFreed);
1210 return (pohPrev);
1213 if (pohNext) {
1214 pohNext->ulSize += pohFreed->ulSize;
1215 pohNext->ulOffset = pohFreed->ulOffset;
1216 free_node(pohFreed);
1217 return (pohNext);
1220 insert_node(&heap.ohFree, pohFreed);
1222 return (pohFreed);
1226 * Frees our basic data structure allocation unit by adding it to a free
1227 * list.
1230 static void free_node(struct OH *poh)
1232 if (poh == NULL) {
1233 return;
1236 poh->pohNext = heap.pohFreeList;
1237 heap.pohFreeList = poh;
1239 return;
1242 void sis_malloc(struct sis_memreq *req)
1244 struct OH *poh;
1246 poh = poh_allocate(req->size);
1248 if (poh == NULL) {
1249 req->offset = 0;
1250 req->size = 0;
1251 DPRINTK("sisfb: VMEM Allocation Failed\n");
1252 } else {
1253 DPRINTK("sisfb: VMEM Allocation Successed : 0x%p\n",
1254 (char *) (poh->ulOffset +
1255 (unsigned long) ivideo.video_vbase));
1257 req->offset = poh->ulOffset;
1258 req->size = poh->ulSize;
1263 void sis_free(unsigned long base)
1265 struct OH *poh;
1267 poh = poh_free(base);
1269 if (poh == NULL) {
1270 DPRINTK("sisfb: poh_free() failed at base 0x%x\n",
1271 (unsigned int) base);
1275 void sis_dispinfo(struct ap_data *rec)
1277 rec->minfo.bpp = ivideo.video_bpp;
1278 rec->minfo.xres = ivideo.video_width;
1279 rec->minfo.yres = ivideo.video_height;
1280 rec->minfo.v_xres = ivideo.video_vwidth;
1281 rec->minfo.v_yres = ivideo.video_vheight;
1282 rec->minfo.org_x = ivideo.org_x;
1283 rec->minfo.org_y = ivideo.org_y;
1284 rec->minfo.vrate = ivideo.refresh_rate;
1285 rec->iobase = ivideo.vga_base - 0x30;
1286 rec->mem_size = ivideo.video_size;
1287 rec->disp_state = ivideo.disp_state;
1288 switch(HwExt.jChipID)
1290 case SIS_Glamour:
1291 rec->chip = SiS_300;
1292 break;
1293 case SIS_Trojan:
1294 if((HwExt.revision_id & 0xf0) == 0x30)
1295 rec->chip = SiS_630S;
1296 else
1297 rec->chip = SiS_630;
1298 break;
1299 case SIS_Spartan:
1300 rec->chip = SiS_540;
1301 break;
1302 case SIS_730:
1303 rec->chip = SiS_730;
1304 break;
1305 default:
1306 rec->chip = SiS_UNKNOWN;
1307 break;
1312 /* ---------------------- SetMode Routines -------------------------- */
1314 void SetReg1(u16 port, u16 index, u16 data)
1316 outb((u8) (index & 0xff), port);
1317 port++;
1318 outb((u8) (data & 0xff), port);
1321 void SetReg3(u16 port, u16 data)
1323 outb((u8) (data & 0xff), port);
1326 void SetReg4(u16 port, unsigned long data)
1328 outl((u32) (data & 0xffffffff), port);
1331 u8 GetReg1(u16 port, u16 index)
1333 u8 data;
1335 outb((u8) (index & 0xff), port);
1336 port += 1;
1337 data = inb(port);
1338 return (data);
1341 u8 GetReg2(u16 port)
1343 u8 data;
1345 data = inb(port);
1347 return (data);
1350 u32 GetReg3(u16 port)
1352 u32 data;
1354 data = inl(port);
1355 return (data);
1358 void ClearDAC(u16 port)
1360 int i,j;
1362 vgawb(DAC_ADR, 0x00);
1363 for(i=0; i<256; i++)
1364 for(j=0; j<3; j++)
1365 vgawb(DAC_DATA, 0);
1368 void ClearBuffer(PHW_DEVICE_EXTENSION pHwExt)
1370 memset((char *) ivideo.video_vbase, 0,
1371 video_linelength * ivideo.video_height);
1374 static void pre_setmode(void)
1376 unsigned char uCR30=0, uCR31=0;
1378 switch(uDispType & MASK_DISPTYPE_DISP2)
1380 case MASK_DISPTYPE_CRT2:
1381 uCR30 = 0x41;
1382 uCR31 = 0x40;
1383 break;
1384 case MASK_DISPTYPE_LCD:
1385 uCR30 = 0x21;
1386 uCR31 = 0x40;
1387 break;
1388 case MASK_DISPTYPE_TV:
1389 if(ivideo.TV_type == TVMODE_HIVISION)
1390 uCR30 = 0x81;
1391 else if(ivideo.TV_plug == TVPLUG_SVIDEO)
1392 uCR30 = 0x09;
1393 else if(ivideo.TV_plug == TVPLUG_COMPOSITE)
1394 uCR30 = 0x05;
1395 else if(ivideo.TV_plug == TVPLUG_SCART)
1396 uCR30 = 0x11;
1397 uCR31 = 0x40; /* CR31[0] will be set in setmode() */
1398 break;
1399 default:
1400 uCR30 = 0x00;
1401 uCR31 = 0x60;
1404 vgawb(CRTC_ADR, 0x30);
1405 vgawb(CRTC_DATA, uCR30);
1406 vgawb(CRTC_ADR, 0x31);
1407 vgawb(CRTC_DATA, uCR31);
1408 vgawb(CRTC_ADR, 0x33);
1409 vgawb(CRTC_DATA, rate_idx & 0x0f);
1412 static void post_setmode(void)
1414 u8 uTemp;
1416 vgawb(CRTC_ADR, 0x17);
1417 uTemp = vgarb(CRTC_DATA);
1419 if(crt1off) /* turn off CRT1 */
1420 uTemp &= ~0x80;
1421 else /* turn on CRT1 */
1422 uTemp |= 0x80;
1423 vgawb(CRTC_DATA, uTemp);
1425 /* disable 24-bit palette RAM and Gamma correction */
1426 vgawb(SEQ_ADR, 0x07);
1427 uTemp = vgarb(SEQ_DATA);
1428 uTemp &= ~0x04;
1429 vgawb(SEQ_DATA, uTemp);
1432 static void search_mode(const char *name)
1434 int i = 0;
1436 if (name == NULL)
1437 return;
1439 while (sisbios_mode[i].mode_no != 0) {
1440 if (!strcmp(name, sisbios_mode[i].name)) {
1441 mode_idx = i;
1442 break;
1444 i++;
1447 if (mode_idx < 0)
1448 DPRINTK("Invalid user mode : %s\n", name);
1451 static u8 search_refresh_rate(unsigned int rate)
1453 u16 xres, yres;
1454 int i = 0;
1456 xres = sisbios_mode[mode_idx].xres;
1457 yres = sisbios_mode[mode_idx].yres;
1459 while ((vrate[i].idx != 0) && (vrate[i].xres <= xres)) {
1460 if ((vrate[i].xres == xres) && (vrate[i].yres == yres)
1461 && (vrate[i].refresh == rate)) {
1462 rate_idx = vrate[i].idx;
1463 return rate_idx;
1465 i++;
1468 DPRINTK("sisfb: Unsupported rate %d in %dx%d mode\n", rate, xres,
1469 yres);
1471 return 0;
1474 /* ------------------ Public Routines ------------------------------- */
1477 * Get the Fixed Part of the Display
1480 static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
1481 struct fb_info *info)
1483 DPRINTK("sisfb: sisfb_get_fix:[%d]\n", con);
1485 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1486 strcpy(fix->id, fb_info.modename);
1488 fix->smem_start = ivideo.video_base;
1489 if(ivideo.video_size > 0x800000)
1490 fix->smem_len = RESERVED_MEM_SIZE_8M; /* reserved for Xserver */
1491 else
1492 fix->smem_len = RESERVED_MEM_SIZE_4M; /* reserved for Xserver */
1494 fix->type = video_type;
1495 fix->type_aux = 0;
1496 if (ivideo.video_bpp == 8)
1497 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1498 else
1499 fix->visual = FB_VISUAL_TRUECOLOR;
1500 fix->xpanstep = 0;
1501 fix->ypanstep = 0;
1502 fix->ywrapstep = 0;
1503 fix->line_length = video_linelength;
1504 fix->mmio_start = ivideo.mmio_base;
1505 fix->mmio_len = MMIO_SIZE;
1506 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1507 fix->reserved[0] = ivideo.video_size & 0xFFFF;
1508 fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
1509 fix->reserved[2] = caps; /* capabilities */
1511 return 0;
1515 * Get the User Defined Part of the Display
1518 static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
1519 struct fb_info *info)
1521 DPRINTK("sisfb: sisfb_get_var:[%d]\n", con);
1523 if (con == -1)
1524 memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
1525 else
1526 *var = fb_display[con].var;
1527 return 0;
1531 * Set the User Defined Part of the Display
1534 static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
1535 struct fb_info *info)
1537 int err;
1538 unsigned int cols, rows;
1540 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1542 /* Set mode */
1543 if (do_set_var(var, con == currcon, info)) {
1544 crtc_to_var(var); /* return current mode to user */
1545 return -EINVAL;
1548 /* get actual setting value */
1549 crtc_to_var(var);
1551 /* update display of current console */
1552 sisfb_set_disp(con, var);
1554 if (info->changevar)
1555 (*info->changevar) (con);
1557 if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
1558 return err;
1560 do_install_cmap(con, info);
1562 /* inform console to update struct display */
1563 cols = sisbios_mode[mode_idx].cols;
1564 rows = sisbios_mode[mode_idx].rows;
1565 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1567 return 0;
1572 * Get the Colormap
1575 static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
1576 struct fb_info *info)
1578 DPRINTK("sisfb: sisfb_get_cmap:[%d]\n", con);
1580 if (con == currcon)
1581 return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
1582 else if (fb_display[con].cmap.len) /* non default colormap? */
1583 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
1584 else
1585 fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2);
1586 return 0;
1590 * Set the Colormap
1593 static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
1594 struct fb_info *info)
1596 int err;
1598 if (!fb_display[con].cmap.len) { /* no colormap allocated */
1599 err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0);
1600 if (err)
1601 return err;
1603 if (con == currcon) /* current console */
1604 return fb_set_cmap(cmap, kspc, sis_setcolreg, info);
1605 else
1606 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
1607 return 0;
1610 static int sisfb_ioctl(struct inode *inode, struct file *file,
1611 unsigned int cmd, unsigned long arg, int con,
1612 struct fb_info *info)
1614 switch (cmd) {
1615 case FBIO_ALLOC:
1616 if(!capable(CAP_SYS_RAWIO))
1617 return -EPERM;
1618 sis_malloc((struct sis_memreq *) arg);
1619 break;
1620 case FBIO_FREE:
1621 if(!capable(CAP_SYS_RAWIO))
1622 return -EPERM;
1623 sis_free(*(unsigned long *) arg);
1624 break;
1625 case FBIOGET_GLYPH:
1626 sis_get_glyph((struct GlyInfo *) arg);
1627 break;
1628 case FBIOGET_HWCINFO:
1630 unsigned long *hwc_offset = (unsigned long *) arg;
1632 if (caps & HW_CURSOR_CAP)
1633 *hwc_offset = hwcursor_vbase -
1634 (unsigned long) ivideo.video_vbase;
1635 else
1636 *hwc_offset = 0;
1638 break;
1640 case FBIOPUT_MODEINFO:
1642 struct mode_info *x = (struct mode_info *)arg;
1644 /* Set Mode Parameters by XServer */
1645 ivideo.video_bpp = x->bpp;
1646 ivideo.video_width = x->xres;
1647 ivideo.video_height = x->yres;
1648 ivideo.video_vwidth = x->v_xres;
1649 ivideo.video_vheight = x->v_yres;
1650 ivideo.org_x = x->org_x;
1651 ivideo.org_y = x->org_y;
1652 ivideo.refresh_rate = x->vrate;
1654 break;
1656 case FBIOGET_DISPINFO:
1657 sis_dispinfo((struct ap_data *)arg);
1658 break;
1659 default:
1660 return -EINVAL;
1662 return 0;
1665 static int sisfb_mmap(struct fb_info *info, struct file *file,
1666 struct vm_area_struct *vma)
1668 struct fb_var_screeninfo var;
1669 unsigned long start;
1670 unsigned long off;
1671 u32 len;
1673 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1674 return -EINVAL;
1675 off = vma->vm_pgoff << PAGE_SHIFT;
1677 /* frame buffer memory */
1678 start = (unsigned long) ivideo.video_base;
1679 len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
1681 if (off >= len) {
1682 /* memory mapped io */
1683 off -= len;
1684 sisfb_get_var(&var, currcon, info);
1685 if (var.accel_flags)
1686 return -EINVAL;
1687 start = (unsigned long) ivideo.mmio_base;
1688 len = PAGE_ALIGN((start & ~PAGE_MASK) + MMIO_SIZE);
1691 start &= PAGE_MASK;
1692 if ((vma->vm_end - vma->vm_start + off) > len)
1693 return -EINVAL;
1694 off += start;
1695 vma->vm_pgoff = off >> PAGE_SHIFT;
1697 #if defined(__i386__)
1698 if (boot_cpu_data.x86 > 3)
1699 pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
1700 #endif
1701 if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
1702 vma->vm_page_prot))
1703 return -EAGAIN;
1704 return 0;
1707 static struct fb_ops sisfb_ops = {
1708 owner: THIS_MODULE,
1709 fb_get_fix: sisfb_get_fix,
1710 fb_get_var: sisfb_get_var,
1711 fb_set_var: sisfb_set_var,
1712 fb_get_cmap: sisfb_get_cmap,
1713 fb_set_cmap: sisfb_set_cmap,
1714 fb_ioctl: sisfb_ioctl,
1715 fb_mmap: sisfb_mmap,
1718 int sisfb_setup(char *options)
1720 char *this_opt;
1722 fb_info.fontname[0] = '\0';
1723 ivideo.refresh_rate = 0;
1725 if (!options || !*options)
1726 return 0;
1728 for (this_opt = strtok(options, ","); this_opt;
1729 this_opt = strtok(NULL, ",")) {
1730 if (!*this_opt)
1731 continue;
1733 if (!strcmp(this_opt, "inverse")) {
1734 inverse = 1;
1735 fb_invert_cmaps();
1736 } else if (!strncmp(this_opt, "font:", 5)) {
1737 strcpy(fb_info.fontname, this_opt + 5);
1738 } else if (!strncmp(this_opt, "mode:", 5)) {
1739 search_mode(this_opt + 5);
1740 } else if (!strncmp(this_opt, "vrate:", 6)) {
1741 ivideo.refresh_rate =
1742 simple_strtoul(this_opt + 6, NULL, 0);
1743 } else if (!strncmp(this_opt, "off", 3)) {
1744 sisfb_off = 1;
1745 } else if (!strncmp(this_opt, "crt1off", 7)) {
1746 crt1off = 1;
1747 } else
1748 DPRINTK("invalid parameter %s\n", this_opt);
1750 return 0;
1753 static int sisfb_update_var(int con, struct fb_info *info)
1755 return 0;
1759 * Switch Console (called by fbcon.c)
1762 static int sisfb_switch(int con, struct fb_info *info)
1764 int cols, rows;
1766 DPRINTK("sisfb: switch console from [%d] to [%d]\n", currcon, con);
1768 /* update colormap of current console */
1769 if (fb_display[currcon].cmap.len)
1770 fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
1772 fb_display[con].var.activate = FB_ACTIVATE_NOW;
1774 /* same mode, needn't change mode actually */
1776 if (!memcmp(&fb_display[con].var, &fb_display[currcon].var, sizeof(struct fb_var_screeninfo)))
1778 currcon = con;
1779 return 1;
1782 currcon = con;
1784 do_set_var(&fb_display[con].var, 1, info);
1786 sisfb_set_disp(con, &fb_display[con].var);
1788 /* Install new colormap */
1789 do_install_cmap(con, info);
1791 cols = sisbios_mode[mode_idx].cols;
1792 rows = sisbios_mode[mode_idx].rows;
1793 vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
1795 sisfb_update_var(con, info);
1797 return 1;
1801 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
1803 static void sisfb_blank(int blank, struct fb_info *info)
1805 u8 CRData;
1807 vgawb(CRTC_ADR, 0x17);
1808 CRData = vgarb(CRTC_DATA);
1810 if (blank > 0) /* turn off CRT1 */
1811 CRData &= 0x7f;
1812 else /* turn on CRT1 */
1813 CRData |= 0x80;
1815 vgawb(CRTC_ADR, 0x17);
1816 vgawb(CRTC_DATA, CRData);
1819 int has_VB(void)
1821 u8 uSR38, uSR39, uVBChipID;
1823 vgawb(SEQ_ADR, 0x38);
1824 uSR38 = vgarb(SEQ_DATA);
1825 vgawb(SEQ_ADR, 0x39);
1826 uSR39 = vgarb(SEQ_DATA);
1827 vgawb(IND_SIS_CRT2_PORT_14, 0x0);
1828 uVBChipID = vgarb(IND_SIS_CRT2_PORT_14+1);
1830 if (
1831 ( (HwExt.jChipID == SIS_Glamour) && (uSR38 & 0x20) ) /* 300 */
1833 ( (HwExt.jChipID >= SIS_Trojan ) && (uSR38 & 0x20) && (!(uSR39 & 0x80)) ) /* 630/540 */
1835 ( (HwExt.jChipID == SIS_Trojan ) && ((HwExt.revision_id & 0xf0) == 0x30) && (uVBChipID == 1) ) /* 630s */
1837 ( (HwExt.jChipID == SIS_730) && (uVBChipID == 1) ) /* 730 */
1840 ivideo.hasVB = HASVB_301;
1841 return TRUE;
1843 else
1845 ivideo.hasVB = HASVB_NONE;
1846 return FALSE;
1850 void sis_get301info(void)
1852 u8 uCRData;
1853 unsigned long disp_state=0;
1855 if (HwExt.jChipID >= SIS_Trojan)
1857 if (!has_VB())
1859 vgawb(CRTC_ADR, 0x37);
1860 uCRData = vgarb(CRTC_DATA);
1862 switch((uCRData >> 1) & 0x07)
1864 case 2:
1865 ivideo.hasVB = HASVB_LVDS;
1866 break;
1867 case 4:
1868 ivideo.hasVB = HASVB_LVDS_CHRONTEL;
1869 break;
1870 case 3:
1871 ivideo.hasVB = HASVB_TRUMPION;
1872 break;
1873 default:
1874 break;
1878 else
1880 has_VB();
1883 vgawb(CRTC_ADR, 0x32);
1884 uCRData = vgarb(CRTC_DATA);
1886 switch(uDispType)
1888 case MASK_DISPTYPE_CRT2:
1889 disp_state = DISPTYPE_CRT2;
1890 break;
1891 case MASK_DISPTYPE_LCD:
1892 disp_state = DISPTYPE_LCD;
1893 break;
1894 case MASK_DISPTYPE_TV:
1895 disp_state = DISPTYPE_TV;
1896 break;
1899 if(disp_state & 0x7)
1901 if(crt1off)
1902 disp_state |= DISPMODE_SINGLE;
1903 else
1904 disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1);
1906 else
1907 disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1;
1909 ivideo.disp_state = disp_state;
1913 int __init sisfb_init(void)
1915 struct pci_dev *pdev = NULL;
1916 struct board *b;
1917 int pdev_valid = 0;
1918 unsigned char jTemp;
1919 u8 uSRData, uCRData;
1921 outb(0x77, 0x80);
1923 if (sisfb_off)
1924 return -ENXIO;
1926 pci_for_each_dev(pdev) {
1927 for (b = dev_list; b->vendor; b++)
1929 if ((b->vendor == pdev->vendor)
1930 && (b->device == pdev->device))
1932 pdev_valid = 1;
1933 strcpy(fb_info.modename, b->name);
1934 ivideo.chip_id = pdev->device;
1935 pci_read_config_byte(pdev, PCI_REVISION_ID, &HwExt.revision_id);
1936 break;
1940 if (pdev_valid)
1941 break;
1944 if (!pdev_valid)
1945 return -1;
1947 switch(ivideo.chip_id)
1949 case PCI_DEVICE_ID_SI_300:
1950 HwExt.jChipID = SIS_Glamour;
1951 break;
1952 case PCI_DEVICE_ID_SI_630_VGA:
1953 HwExt.jChipID = SIS_Trojan;
1954 break;
1955 case PCI_DEVICE_ID_SI_540_VGA:
1956 HwExt.jChipID = SIS_Spartan;
1957 break;
1958 case PCI_DEVICE_ID_SI_730_VGA:
1959 HwExt.jChipID = SIS_730;
1960 break;
1963 ivideo.video_base = pci_resource_start(pdev, 0);
1964 ivideo.mmio_base = pci_resource_start(pdev, 1);
1965 ivideo.vga_base = pci_resource_start(pdev, 2) + 0x30;
1967 HwExt.IOAddress = (unsigned short)ivideo.vga_base;
1968 rom_base = 0x000C0000;
1970 MMIO_SIZE = pci_resource_len(pdev, 1);
1972 #ifdef NOBIOS
1973 if (pci_enable_device(pdev))
1974 return -EIO;
1975 /* Image file instead of VGA-bios */
1976 HwExt.VirtualRomBase = rom_vbase = (unsigned long) RomData;
1977 #else
1978 #ifdef CONFIG_FB_SIS_LINUXBIOS
1979 if (pci_enable_device(pdev))
1980 return -EIO;
1981 HwExt.VirtualRomBase = rom_vbase = 0;
1982 #else
1983 request_region(rom_base, 32, "sisfb");
1984 HwExt.VirtualRomBase = rom_vbase
1985 = (unsigned long) ioremap(rom_base, MAX_ROM_SCAN);
1986 #endif
1987 #endif
1988 /* set passwd */
1989 vgawb(SEQ_ADR, IND_SIS_PASSWORD);
1990 vgawb(SEQ_DATA, SIS_PASSWORD);
1992 /* Enable MMIO & PCI linear address */
1993 vgawb(SEQ_ADR, IND_SIS_PCI_ADDRESS_SET);
1994 jTemp = vgarb(SEQ_DATA);
1995 jTemp |= SIS_PCI_ADDR_ENABLE;
1996 jTemp |= SIS_MEM_MAP_IO_ENABLE;
1997 vgawb(SEQ_DATA, jTemp);
1999 #ifdef CONFIG_FB_SIS_LINUXBIOS
2000 pdev_valid = 0;
2001 pci_for_each_dev(pdev) {
2002 u8 uPCIData=0;
2004 if ((pdev->vendor == PCI_VENDOR_ID_SI) && (pdev->device==0x630))
2006 pci_read_config_byte(pdev, 0x63, &uPCIData);
2007 uPCIData = (uPCIData & 0x70) >> 4;
2008 ivideo.video_size = (unsigned int)(1 << (uPCIData+21));
2009 pdev_valid = 1;
2010 break;
2014 if (!pdev_valid)
2015 return -1;
2016 #else
2017 vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
2018 ivideo.video_size = ((unsigned int) ((vgarb(SEQ_DATA) & 0x3f) + 1) << 20);
2019 #endif
2022 /* get CRT2 connection state */
2023 vgawb(SEQ_ADR, 0x17);
2024 uSRData = vgarb(SEQ_DATA);
2025 vgawb(CRTC_ADR, 0x32);
2026 uCRData = vgarb(CRTC_DATA);
2028 ivideo.TV_plug = ivideo.TV_type = 0;
2029 if((uSRData&0x0F) && (HwExt.jChipID>=SIS_Trojan))
2031 /* CRT1 connect detection */
2032 if((uSRData & 0x01) && !crt1off)
2033 crt1off = 0;
2034 else
2036 if(uSRData&0x0E) /* DISP2 connected */
2037 crt1off = 1;
2038 else
2039 crt1off = 0;
2042 /* detection priority : CRT2 > LCD > TV */
2043 if(uSRData & 0x08 )
2044 uDispType = MASK_DISPTYPE_CRT2;
2045 else if(uSRData & 0x02)
2046 uDispType = MASK_DISPTYPE_LCD;
2047 else if(uSRData & 0x04)
2049 if(uSRData & 0x80)
2051 ivideo.TV_type = TVMODE_HIVISION;
2052 ivideo.TV_plug = TVPLUG_SVIDEO;
2054 else if(uSRData & 0x20)
2055 ivideo.TV_plug = TVPLUG_SVIDEO;
2056 else if(uSRData & 0x10)
2057 ivideo.TV_plug = TVPLUG_COMPOSITE;
2058 else if(uSRData & 0x40)
2059 ivideo.TV_plug = TVPLUG_SCART;
2061 if(ivideo.TV_type == 0)
2063 u8 uSR16;
2064 vgawb(SEQ_ADR, 0x16);
2065 uSR16 = vgarb(SEQ_DATA);
2066 if(uSR16 & 0x20)
2067 ivideo.TV_type = TVMODE_PAL;
2068 else
2069 ivideo.TV_type = TVMODE_NTSC;
2072 uDispType = MASK_DISPTYPE_TV;
2075 else
2077 if((uCRData & 0x20) && !crt1off)
2078 crt1off = 0;
2079 else
2081 if(uCRData&0x5F) /* DISP2 connected */
2082 crt1off = 1;
2083 else
2084 crt1off = 0;
2087 if(uCRData & 0x10)
2088 uDispType = MASK_DISPTYPE_CRT2;
2089 else if(uCRData & 0x08)
2090 uDispType = MASK_DISPTYPE_LCD;
2091 else if(uCRData & 0x47)
2093 uDispType = MASK_DISPTYPE_TV;
2095 if(uCRData & 0x40)
2097 ivideo.TV_type = TVMODE_HIVISION;
2098 ivideo.TV_plug = TVPLUG_SVIDEO;
2100 else if(uCRData & 0x02)
2101 ivideo.TV_plug = TVPLUG_SVIDEO;
2102 else if(uCRData & 0x01)
2103 ivideo.TV_plug = TVPLUG_COMPOSITE;
2104 else if(uCRData & 0x04)
2105 ivideo.TV_plug = TVPLUG_SCART;
2107 if(ivideo.TV_type == 0)
2109 u8 uTemp;
2110 uTemp = *((u8 *)(HwExt.VirtualRomBase+0x52));
2111 if(uTemp&0x40)
2113 uTemp=*((u8 *)(HwExt.VirtualRomBase+0x53));
2115 else
2117 vgawb(SEQ_ADR, 0x38);
2118 uTemp = vgarb(SEQ_DATA);
2120 if(uTemp & 0x01)
2121 ivideo.TV_type = TVMODE_PAL;
2122 else
2123 ivideo.TV_type = TVMODE_NTSC;
2128 if(uDispType == MASK_DISPTYPE_LCD) // LCD conntected
2130 // TODO: set LCDType by EDID
2131 HwExt.usLCDType = LCD1024;
2134 if (HwExt.jChipID >= SIS_Trojan)
2136 vgawb(SEQ_ADR, 0x1A);
2137 uSRData = vgarb(SEQ_DATA);
2138 if (uSRData & 0x10)
2139 HwExt.bIntegratedMMEnabled = TRUE;
2140 else
2141 HwExt.bIntegratedMMEnabled = FALSE;
2144 if(mode_idx >= 0) /* mode found */
2146 /* Filtering mode for VB */
2147 switch(uDispType & MASK_DISPTYPE_DISP2)
2149 case MASK_DISPTYPE_LCD:
2150 switch(HwExt.usLCDType)
2152 case LCD1024:
2153 if(sisbios_mode[mode_idx].xres > 1024)
2154 mode_idx = -1;
2155 break;
2156 case LCD1280:
2157 if(sisbios_mode[mode_idx].xres > 1280)
2158 mode_idx = -1;
2159 break;
2160 case LCD2048:
2161 if(sisbios_mode[mode_idx].xres > 2048)
2162 mode_idx = -1;
2163 break;
2164 case LCD1920:
2165 if(sisbios_mode[mode_idx].xres > 1920)
2166 mode_idx = -1;
2167 break;
2168 case LCD1600:
2169 if(sisbios_mode[mode_idx].xres > 1600)
2170 mode_idx = -1;
2171 break;
2172 case LCD800:
2173 if(sisbios_mode[mode_idx].xres > 800)
2174 mode_idx = -1;
2175 break;
2176 case LCD640:
2177 if(sisbios_mode[mode_idx].xres > 640)
2178 mode_idx = -1;
2179 break;
2180 default:
2181 mode_idx = -1;
2184 if(sisbios_mode[mode_idx].xres == 720) /* only for TV */
2185 mode_idx = -1;
2186 break;
2187 case MASK_DISPTYPE_TV:
2188 switch(sisbios_mode[mode_idx].xres)
2190 case 800:
2191 case 640:
2192 break;
2193 case 720:
2194 if(ivideo.TV_type == TVMODE_NTSC)
2196 if(sisbios_mode[mode_idx].yres != 480)
2197 mode_idx = -1;
2199 else if(ivideo.TV_type == TVMODE_PAL)
2201 if(sisbios_mode[mode_idx].yres != 576)
2202 mode_idx = -1;
2204 break;
2205 default:
2206 /* illegal mode */
2207 mode_idx = -1;
2209 break;
2213 if (mode_idx < 0)
2215 switch(uDispType & MASK_DISPTYPE_DISP2)
2217 case MASK_DISPTYPE_LCD:
2218 mode_idx = DEFAULT_LCDMODE;
2219 break;
2220 case MASK_DISPTYPE_TV:
2221 mode_idx = DEFAULT_TVMODE;
2222 break;
2223 default:
2224 mode_idx = DEFAULT_MODE;
2228 #ifdef CONFIG_FB_SIS_LINUXBIOS
2229 mode_idx = DEFAULT_MODE;
2230 rate_idx = sisbios_mode[mode_idx].rate_idx;
2231 /* set to default refresh rate 60MHz */
2232 ivideo.refresh_rate = 60;
2233 #endif
2235 mode_no = sisbios_mode[mode_idx].mode_no;
2237 if (ivideo.refresh_rate != 0)
2238 search_refresh_rate(ivideo.refresh_rate);
2240 if (rate_idx == 0) {
2241 rate_idx = sisbios_mode[mode_idx].rate_idx;
2242 /* set to default refresh rate 60MHz */
2243 ivideo.refresh_rate = 60;
2246 ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
2247 ivideo.video_vwidth = ivideo.video_width = sisbios_mode[mode_idx].xres;
2248 ivideo.video_vheight = ivideo.video_height = sisbios_mode[mode_idx].yres;
2249 ivideo.org_x = ivideo.org_y = 0;
2250 video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
2252 printk(KERN_DEBUG "FB base: 0x%lx, size: 0x%dK\n",
2253 ivideo.video_base, (unsigned int)ivideo.video_size/1024);
2254 printk(KERN_DEBUG "MMIO base: 0x%lx, size: 0x%dK\n",
2255 ivideo.mmio_base, (unsigned int)MMIO_SIZE/1024);
2258 if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB"))
2260 printk(KERN_ERR "sisfb: cannot reserve frame buffer memory\n");
2261 return -ENODEV;
2264 if (!request_mem_region(ivideo.mmio_base, MMIO_SIZE, "sisfb MMIO"))
2266 printk(KERN_ERR "sisfb: cannot reserve MMIO region\n");
2267 release_mem_region(ivideo.video_base, ivideo.video_size);
2268 return -ENODEV;
2271 HwExt.VirtualVideoMemoryAddress = ivideo.video_vbase
2272 = ioremap(ivideo.video_base, ivideo.video_size);
2273 ivideo.mmio_vbase = ioremap(ivideo.mmio_base, MMIO_SIZE);
2275 #ifdef NOBIOS
2276 SiSInit300(&HwExt);
2277 #else
2278 #ifdef CONFIG_FB_SIS_LINUXBIOS
2279 SiSInit300(&HwExt);
2280 #endif
2281 #endif
2282 printk(KERN_INFO
2283 "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
2284 ivideo.video_base, ivideo.video_vbase,
2285 ivideo.video_size / 1024);
2286 printk(KERN_INFO "sisfb: mode is %dx%dx%d, linelength=%d\n",
2287 ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
2288 video_linelength);
2290 /* enable 2D engine */
2291 vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE);
2292 jTemp = vgarb(SEQ_DATA);
2293 jTemp |= SIS_2D_ENABLE;
2294 vgawb(SEQ_DATA, jTemp);
2296 pre_setmode();
2298 if (SiSSetMode(&HwExt, mode_no)) {
2299 DPRINTK("sisfb: set mode[0x%x]: failed\n", mode_no);
2300 return -1;
2303 post_setmode();
2305 /* Get VB functions */
2306 sis_get301info();
2308 crtc_to_var(&default_var);
2310 fb_info.changevar = NULL;
2311 fb_info.node = -1;
2312 fb_info.fbops = &sisfb_ops;
2313 fb_info.disp = &disp;
2314 fb_info.switch_con = &sisfb_switch;
2315 fb_info.updatevar = &sisfb_update_var;
2316 fb_info.blank = &sisfb_blank;
2317 fb_info.flags = FBINFO_FLAG_DEFAULT;
2319 sisfb_set_disp(-1, &default_var);
2321 if (sisfb_heap_init()) {
2322 DPRINTK("sisfb: Failed to enable offscreen heap\n");
2325 /* to avoid the inversed bgcolor bug of the initial state */
2326 vc_resize_con(1, 1, 0);
2328 if (register_framebuffer(&fb_info) < 0)
2329 return -EINVAL;
2331 printk(KERN_INFO "fb%d: %s frame buffer device\n",
2332 GET_FB_IDX(fb_info.node), fb_info.modename);
2334 return 0;
2337 #ifdef MODULE
2339 static char *mode = NULL;
2340 static unsigned int rate = 0;
2341 static unsigned int crt1 = 1;
2343 MODULE_PARM(mode, "s");
2344 MODULE_PARM(rate, "i");
2345 MODULE_PARM(crt1, "i"); /* default: CRT1 enable */
2347 int init_module(void)
2349 if (mode)
2350 search_mode(mode);
2352 ivideo.refresh_rate = rate;
2354 if(crt1 == 0)
2355 crt1off = 1;
2356 else
2357 crt1off = 0;
2359 sisfb_init();
2361 return 0;
2364 void cleanup_module(void)
2366 unregister_framebuffer(&fb_info);
2368 #endif /* MODULE */
2371 EXPORT_SYMBOL(sis_malloc);
2372 EXPORT_SYMBOL(sis_free);
2374 EXPORT_SYMBOL(ivideo);