patch-2.2.18 linux/drivers/video/cyber2000fb.c
Next file: linux/drivers/video/cyber2000fb.h
Previous file: linux/drivers/video/chipsfb.c
Back to the patch index
Back to the overall index
- Lines: 1417
- Date:
Fri Sep 15 23:31:13 2000
- Orig file:
v2.2.17/drivers/video/cyber2000fb.c
- Orig date:
Fri Apr 21 12:46:38 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c
@@ -35,7 +35,9 @@
#define DEFAULT_YRES 480
#define DEFAULT_BPP 8
-static volatile unsigned char *CyberRegs;
+#define MMIO_SIZE 0x000c0000
+
+static char *CyberRegs;
#include "cyber2000fb.h"
@@ -45,7 +47,7 @@
static struct display_switch *dispsw;
static struct fb_var_screeninfo __initdata init_var = {};
-#ifdef DEBUG
+#if defined(DEBUG) && defined(CONFIG_DEBUG_LL)
static void debug_printf(char *fmt, ...)
{
char buffer[128];
@@ -61,168 +63,6 @@
#define debug_printf(x...) do { } while (0)
#endif
-/*
- * Predefined Video Modes
- */
-static const struct res cyber2000_res[] = {
- {
- 640, 480,
- {
- 0x5f, 0x4f, 0x50, 0x80, 0x52, 0x9d, 0x0b, 0x3e,
- 0x00, 0x40,
- 0xe9, 0x8b, 0xdf, 0x50, 0x00, 0xe6, 0x04, 0xc3
- },
- 0x00,
- { 0xd2, 0xce, 0xdb, 0x54 }
- },
-
- {
- 800, 600,
- {
- 0x7f, 0x63, 0x64, 0x00, 0x66, 0x10, 0x6f, 0xf0,
- 0x00, 0x60,
- 0x5b, 0x8f, 0x57, 0x64, 0x00, 0x59, 0x6e, 0xe3
- },
- 0x00,
- { 0x52, 0x85, 0xdb, 0x54 }
- },
-
- {
- 1024, 768,
- {
- 0x9f, 0x7f, 0x80, 0x80, 0x8b, 0x94, 0x1e, 0xfd,
- 0x00, 0x60,
- 0x03, 0x86, 0xff, 0x80, 0x0f, 0x00, 0x1e, 0xe3
- },
- 0x00,
- { 0xd0, 0x52, 0xdb, 0x54 }
- },
-#if 0
- {
- 1152, 886,
- {
- },
- {
- }
- },
-#endif
- {
- 1280, 1024,
- {
- 0xce, 0x9f, 0xa0, 0x8f, 0xa2, 0x1f, 0x28, 0x52,
- 0x00, 0x40,
- 0x08, 0x8f, 0xff, 0xa0, 0x00, 0x03, 0x27, 0xe3
- },
- 0x1d,
- { 0xb4, 0x4b, 0xdb, 0x54 }
- },
-
- {
- 1600, 1200,
- {
- 0xff, 0xc7, 0xc9, 0x9f, 0xcf, 0xa0, 0xfe, 0x10,
- 0x00, 0x40,
- 0xcf, 0x89, 0xaf, 0xc8, 0x00, 0xbc, 0xf1, 0xe3
- },
- 0x1f,
- { 0xbd, 0x10, 0xdb, 0x54 }
- }
-};
-
-#define NUM_TOTAL_MODES arraysize(cyber2000_res)
-
-static const char igs_regs[] = {
- 0x10, 0x10, 0x12, 0x00, 0x13, 0x00,
- 0x30, 0x21, 0x31, 0x00, 0x32, 0x00, 0x33, 0x01,
- 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
- 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01,
- 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
- 0x70, 0x0b, 0x71, 0x10, 0x72, 0x45, 0x73, 0x30,
- 0x74, 0x1b, 0x75, 0x1e, 0x76, 0x00, 0x7a, 0xc8
-};
-
-static const char crtc_idx[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
-};
-
-static void cyber2000_init_hw(const struct res *res)
-{
- int i;
-
- debug_printf("init vga hw for %dx%d\n", res->xres, res->yres);
-
- cyber2000_outb(0xef, 0x3c2);
- cyber2000_crtcw(0x0b, 0x11);
- cyber2000_attrw(0x00, 0x11);
-
- cyber2000_seqw(0x01, 0x00);
- cyber2000_seqw(0x01, 0x01);
- cyber2000_seqw(0x0f, 0x02);
- cyber2000_seqw(0x00, 0x03);
- cyber2000_seqw(0x0e, 0x04);
- cyber2000_seqw(0x03, 0x00);
-
- for (i = 0; i < sizeof(crtc_idx); i++)
- cyber2000_crtcw(res->crtc_regs[i], crtc_idx[i]);
-
- for (i = 0x0a; i < 0x10; i++)
- cyber2000_crtcw(0, i);
-
- cyber2000_crtcw(0xff, 0x18);
-
- cyber2000_grphw(0x00, 0x00);
- cyber2000_grphw(0x00, 0x01);
- cyber2000_grphw(0x00, 0x02);
- cyber2000_grphw(0x00, 0x03);
- cyber2000_grphw(0x00, 0x04);
- cyber2000_grphw(0x60, 0x05);
- cyber2000_grphw(0x05, 0x06);
- cyber2000_grphw(0x0f, 0x07);
- cyber2000_grphw(0xff, 0x08);
-
- for (i = 0; i < 16; i++)
- cyber2000_attrw(i, i);
-
- cyber2000_attrw(0x01, 0x10);
- cyber2000_attrw(0x00, 0x11);
- cyber2000_attrw(0x0f, 0x12);
- cyber2000_attrw(0x00, 0x13);
- cyber2000_attrw(0x00, 0x14);
-
- for (i = 0; i < sizeof(igs_regs); i += 2)
- cyber2000_grphw(igs_regs[i+1], igs_regs[i]);
-
- cyber2000_grphw(res->crtc_ofl, 0x11);
-
- for (i = 0; i < 4; i += 1)
- cyber2000_grphw(res->clk_regs[i], 0xb0 + i);
-
- cyber2000_grphw(0x01, 0x90);
- cyber2000_grphw(0x80, 0xb9);
- cyber2000_grphw(0x00, 0xb9);
-
- cyber2000_outb(0x56, 0x3ce);
- i = cyber2000_inb(0x3cf);
- cyber2000_outb(i | 4, 0x3cf);
- cyber2000_outb(0x04, 0x3c6);
- cyber2000_outb(i, 0x3cf);
-
- cyber2000_outb(0x20, 0x3c0);
- cyber2000_outb(0xff, 0x3c6);
-
- for (i = 0; i < 256; i++) {
- cyber2000_outb(i, 0x3c8);
- cyber2000_outb(0, 0x3c9);
- cyber2000_outb(0, 0x3c9);
- cyber2000_outb(0, 0x3c9);
- }
-}
-
-
-static struct fb_ops cyber2000fb_ops;
-
/* -------------------- Hardware specific routines ------------------------- */
/*
@@ -232,10 +72,10 @@
{
int count = 10000;
- while (cyber2000_inb(0xbf011) & 0x80) {
+ while (cyber2000_inb(CO_REG_CONTROL) & 0x80) {
if (!count--) {
debug_printf("accel_wait timed out\n");
- cyber2000_outb(0, 0xbf011);
+ cyber2000_outb(0, CO_REG_CONTROL);
return;
}
udelay(10);
@@ -252,45 +92,54 @@
cyber2000_accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
int height, int width)
{
- unsigned long src, dst, chwidth = p->var.xres_virtual * fontheight(p);
- int v = 0x8000;
+ unsigned long src, dst;
+ unsigned int fh, fw;
+ int cmd = CO_CMD_L_PATTERN_FGCOL;
+
+ fw = fontwidth(p);
+ sx *= fw;
+ dx *= fw;
+ width *= fw;
+ width -= 1;
if (sx < dx) {
- sx += width - 1;
- dx += width - 1;
- v |= 4;
+ sx += width;
+ dx += width;
+ cmd |= CO_CMD_L_INC_LEFT;
}
+ fh = fontheight(p);
+ sy *= fh;
+ dy *= fh;
+ height *= fh;
+ height -= 1;
+
if (sy < dy) {
- sy += height - 1;
- dy += height - 1;
- v |= 2;
+ sy += height;
+ dy += height;
+ cmd |= CO_CMD_L_INC_UP;
}
- sx *= fontwidth(p);
- dx *= fontwidth(p);
- src = sx + sy * chwidth;
- dst = dx + dy * chwidth;
- width = width * fontwidth(p) - 1;
- height = height * fontheight(p) - 1;
+ src = sx + sy * p->var.xres_virtual;
+ dst = dx + dy * p->var.xres_virtual;
cyber2000_accel_wait();
- cyber2000_outb(0x00, 0xbf011);
- cyber2000_outb(0x03, 0xbf048);
- cyber2000_outw(width, 0xbf060);
+ cyber2000_outb(0x00, CO_REG_CONTROL);
+ cyber2000_outb(0x03, CO_REG_FORE_MIX);
+ cyber2000_outw(width, CO_REG_WIDTH);
if (p->var.bits_per_pixel != 24) {
- cyber2000_outl(dst, 0xbf178);
- cyber2000_outl(src, 0xbf170);
+ cyber2000_outl(dst, CO_REG_DEST_PTR);
+ cyber2000_outl(src, CO_REG_SRC_PTR);
} else {
- cyber2000_outl(dst * 3, 0xbf178);
- cyber2000_outb(dst, 0xbf078);
- cyber2000_outl(src * 3, 0xbf170);
+ cyber2000_outl(dst * 3, CO_REG_DEST_PTR);
+ cyber2000_outb(dst, CO_REG_X_PHASE);
+ cyber2000_outl(src * 3, CO_REG_SRC_PTR);
}
- cyber2000_outw(height, 0xbf062);
- cyber2000_outw(v, 0xbf07c);
- cyber2000_outw(0x2800, 0xbf07e);
+ cyber2000_outw(height, CO_REG_HEIGHT);
+ cyber2000_outw(cmd, CO_REG_CMD_L);
+ cyber2000_outw(0x2800, CO_REG_CMD_H);
}
static void
@@ -298,35 +147,40 @@
int height, int width)
{
unsigned long dst;
+ unsigned int fw, fh;
u32 bgx = attr_bgcol_ec(p, conp);
- dst = sx * fontwidth(p) + sy * p->var.xres_virtual * fontheight(p);
- width = width * fontwidth(p) - 1;
- height = height * fontheight(p) - 1;
+ fw = fontwidth(p);
+ fh = fontheight(p);
+
+ dst = sx * fw + sy * p->var.xres_virtual * fh;
+ width = width * fw - 1;
+ height = height * fh - 1;
cyber2000_accel_wait();
- cyber2000_outb(0x00, 0xbf011);
- cyber2000_outb(0x03, 0xbf048);
- cyber2000_outw(width, 0xbf060);
- cyber2000_outw(height, 0xbf062);
+ cyber2000_outb(0x00, CO_REG_CONTROL);
+ cyber2000_outb(0x03, CO_REG_FORE_MIX);
+ cyber2000_outw(width, CO_REG_WIDTH);
+ cyber2000_outw(height, CO_REG_HEIGHT);
switch (p->var.bits_per_pixel) {
+ case 15:
case 16:
bgx = ((u16 *)p->dispsw_data)[bgx];
case 8:
- cyber2000_outl(dst, 0xbf178);
+ cyber2000_outl(dst, CO_REG_DEST_PTR);
break;
case 24:
- cyber2000_outl(dst * 3, 0xbf178);
- cyber2000_outb(dst, 0xbf078);
+ cyber2000_outl(dst * 3, CO_REG_DEST_PTR);
+ cyber2000_outb(dst, CO_REG_X_PHASE);
bgx = ((u32 *)p->dispsw_data)[bgx];
break;
}
- cyber2000_outl(bgx, 0xbf058);
- cyber2000_outw(0x8000, 0xbf07c);
- cyber2000_outw(0x0800, 0xbf07e);
+ cyber2000_outl(bgx, CO_REG_FOREGROUND);
+ cyber2000_outw(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L);
+ cyber2000_outw(0x0800, CO_REG_CMD_H);
}
static void
@@ -415,14 +269,27 @@
current_par.palette[regno].blue = blue;
switch (fb_display[current_par.currcon].var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
case 8:
cyber2000_outb(regno, 0x3c8);
cyber2000_outb(red, 0x3c9);
cyber2000_outb(green, 0x3c9);
cyber2000_outb(blue, 0x3c9);
break;
+#endif
#ifdef FBCON_HAS_CFB16
+ case 15:
+ if (regno < 32) {
+ cyber2000_outb(regno << 3, 0x3c8);
+ cyber2000_outb(red, 0x3c9);
+ cyber2000_outb(green, 0x3c9);
+ cyber2000_outb(blue, 0x3c9);
+ }
+ if (regno < 16)
+ current_par.c_table.cfb16[regno] = regno | regno << 5 | regno << 10;
+ break;
+
case 16:
if (regno < 64) {
/* write green */
@@ -464,86 +331,136 @@
return 0;
}
-static int cyber2000fb_set_timing(struct fb_var_screeninfo *var)
-{
- int width = var->xres_virtual;
- int scr_pitch, fetchrow;
- int i;
- char b, col;
+struct par_info {
+ /*
+ * Hardware
+ */
+ unsigned char clock_mult;
+ unsigned char clock_div;
+ unsigned char visualid;
+ unsigned char pixformat;
+ unsigned char crtc_ofl;
+ unsigned char crtc[19];
+ unsigned int width;
+ unsigned int pitch;
- switch (var->bits_per_pixel) {
- case 8: /* PSEUDOCOLOUR, 256 */
- b = 0;
- col = 1;
- scr_pitch = var->xres_virtual / 8;
- break;
+ /*
+ * Other
+ */
+ unsigned int visual;
+};
- case 16:/* DIRECTCOLOUR, 64k */
- b = 1;
- col = 2;
- scr_pitch = var->xres_virtual / 8 * 2;
- break;
- case 24:/* TRUECOLOUR, 16m */
- b = 2;
- col = 4;
- scr_pitch = var->xres_virtual / 8 * 3;
- width *= 3;
- break;
+static const char crtc_idx[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
+};
- default:
- return 1;
+static void cyber2000fb_set_timing(struct par_info *hw)
+{
+ unsigned int fetchrow, i;
+
+ /*
+ * Blank palette
+ */
+ for (i = 0; i < 256; i++) {
+ cyber2000_outb(i, 0x3c8);
+ cyber2000_outb(0, 0x3c9);
+ cyber2000_outb(0, 0x3c9);
+ cyber2000_outb(0, 0x3c9);
}
- for (i = 0; i < NUM_TOTAL_MODES; i++)
- if (var->xres == cyber2000_res[i].xres &&
- var->yres == cyber2000_res[i].yres)
- break;
+ cyber2000_outb(0xef, 0x3c2);
+ cyber2000_crtcw(0x11, 0x0b);
+ cyber2000_attrw(0x11, 0x00);
- if (i < NUM_TOTAL_MODES)
- cyber2000_init_hw(cyber2000_res + i);
+ cyber2000_seqw(0x00, 0x01);
+ cyber2000_seqw(0x01, 0x01);
+ cyber2000_seqw(0x02, 0x0f);
+ cyber2000_seqw(0x03, 0x00);
+ cyber2000_seqw(0x04, 0x0e);
+ cyber2000_seqw(0x00, 0x03);
- fetchrow = scr_pitch + 1;
+ for (i = 0; i < sizeof(crtc_idx); i++)
+ cyber2000_crtcw(crtc_idx[i], hw->crtc[i]);
+
+ for (i = 0x0a; i < 0x10; i++)
+ cyber2000_crtcw(i, 0);
+
+ cyber2000_grphw(0x11, hw->crtc_ofl);
+ cyber2000_grphw(0x00, 0x00);
+ cyber2000_grphw(0x01, 0x00);
+ cyber2000_grphw(0x02, 0x00);
+ cyber2000_grphw(0x03, 0x00);
+ cyber2000_grphw(0x04, 0x00);
+ cyber2000_grphw(0x05, 0x60);
+ cyber2000_grphw(0x06, 0x05);
+ cyber2000_grphw(0x07, 0x0f);
+ cyber2000_grphw(0x08, 0xff);
- debug_printf("Setting regs: pitch=%X, fetchrow=%X, col=%X, b=%X\n",
- scr_pitch, fetchrow, col, b);
+ /* Attribute controller registers */
+ for (i = 0; i < 16; i++)
+ cyber2000_attrw(i, i);
- cyber2000_outb(0x13, 0x3d4);
- cyber2000_outb(scr_pitch, 0x3d5);
- cyber2000_outb(0x14, 0x3ce);
- cyber2000_outb(fetchrow, 0x3cf);
- cyber2000_outb(0x15, 0x3ce);
- /* FIXME: is this the right way round? */
- cyber2000_outb(((fetchrow >> 4) & 0xf0) | ((scr_pitch >> 8) & 0x0f), 0x3cf);
- cyber2000_outb(0x77, 0x3ce);
- cyber2000_outb(col, 0x3cf);
+ cyber2000_attrw(0x10, 0x01);
+ cyber2000_attrw(0x11, 0x00);
+ cyber2000_attrw(0x12, 0x0f);
+ cyber2000_attrw(0x13, 0x00);
+ cyber2000_attrw(0x14, 0x00);
+
+ /* PLL registers */
+ cyber2000_grphw(0xb0, hw->clock_mult);
+ cyber2000_grphw(0xb1, hw->clock_div);
+ cyber2000_grphw(0xb2, 0xdb);
+ cyber2000_grphw(0xb3, 0x54); /* MCLK: 75MHz */
+ cyber2000_grphw(0x90, 0x01);
+ cyber2000_grphw(0xb9, 0x80);
+ cyber2000_grphw(0xb9, 0x00);
+ cyber2000_outb(0x56, 0x3ce);
+ i = cyber2000_inb(0x3cf);
+ cyber2000_outb(i | 4, 0x3cf);
+ cyber2000_outb(0x04, 0x3c6);
+ cyber2000_outb(i, 0x3cf);
- cyber2000_outb(0x33, 0x3ce);
- cyber2000_outb(0x1c, 0x3cf);
+ cyber2000_outb(0x20, 0x3c0);
+ cyber2000_outb(0xff, 0x3c6);
- cyber2000_outw(width - 1, 0xbf018);
- cyber2000_outw(width - 1, 0xbf218);
- cyber2000_outb(b, 0xbf01c);
+ fetchrow = hw->pitch + 1;
+ cyber2000_grphw(0x14, fetchrow);
+ /* FIXME: is this the right way round? */
+ cyber2000_grphw(0x15, ((fetchrow >> 4) & 0xf0) | ((hw->pitch >> 8) & 0x0f));
+ cyber2000_grphw(0x77, hw->visualid);
+ cyber2000_grphw(0x33, 0x1c);
- return 0;
+ /*
+ * Set up accelerator registers
+ */
+ cyber2000_outw(hw->width, CO_REG_SRC_WIDTH);
+ cyber2000_outw(hw->width, CO_REG_DEST_WIDTH);
+ cyber2000_outb(hw->pixformat, CO_REG_PIX_FORMAT);
}
-static inline void
+static inline int
cyber2000fb_update_start(struct fb_var_screeninfo *var)
{
-#if 0
unsigned int base;
base = var->yoffset * var->xres_virtual + var->xoffset;
- cyber2000_outb(0x0c, 0x3d4);
- cyber2000_outb(base, 0x3d5);
- cyber2000_outb(0x0d, 0x3d4);
- cyber2000_outb(base >> 8, 0x3d5);
- /* FIXME: need the upper bits of the start offset */
-/* cyber2000_outb(0x??, 0x3d4);
- cyber2000_outb(base >> 16, 0x3d5);*/
-#endif
+ base >>= 2;
+
+ if (base >= 1 << 20)
+ return -EINVAL;
+
+ /*
+ * FIXME: need the upper bits of the start offset
+ */
+ cyber2000_grphw(0x10, base >> 16 | 0x10);
+ cyber2000_crtcw(0x0c, base >> 8);
+ cyber2000_crtcw(0x0d, base);
+
+ return 0;
}
/*
@@ -612,29 +529,257 @@
return err;
}
+static int cyber2000fb_decode_crtc(struct par_info *hw, struct fb_var_screeninfo *var)
+{
+ unsigned int Htotal, Hblankend, Hsyncend;
+ unsigned int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
+#define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
+
+ hw->crtc[13] = hw->pitch;
+ hw->crtc[17] = 0xe3;
+ hw->crtc[14] = 0;
+ hw->crtc[8] = 0;
+
+ Htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+ if (Htotal > 2080)
+ return -EINVAL;
+
+ hw->crtc[0] = (Htotal >> 3) - 5; /* Htotal */
+ hw->crtc[1] = (var->xres >> 3) - 1; /* Hdispend */
+ hw->crtc[2] = var->xres >> 3; /* Hblankstart */
+ hw->crtc[4] = (var->xres + var->right_margin) >> 3; /* Hsyncstart */
+
+ Hblankend = (Htotal - 4*8) >> 3;
+
+ hw->crtc[3] = BIT(Hblankend, 0, 0x1f, 0) | /* Hblankend */
+ BIT(1, 0, 0x01, 7);
+
+ Hsyncend = (var->xres + var->right_margin + var->hsync_len) >> 3;
+
+ hw->crtc[5] = BIT(Hsyncend, 0, 0x1f, 0) | /* Hsyncend */
+ BIT(Hblankend, 5, 0x01, 7);
+
+ Vdispend = var->yres - 1;
+ Vsyncstart = var->yres + var->lower_margin;
+ Vsyncend = var->yres + var->lower_margin + var->vsync_len;
+ Vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin - 2;
+
+ if (Vtotal > 2047)
+ return -EINVAL;
+
+ Vblankstart = var->yres + 6;
+ Vblankend = Vtotal - 10;
+
+ hw->crtc[6] = Vtotal;
+ hw->crtc[7] = BIT(Vtotal, 8, 0x01, 0) |
+ BIT(Vdispend, 8, 0x01, 1) |
+ BIT(Vsyncstart, 8, 0x01, 2) |
+ BIT(Vblankstart,8, 0x01, 3) |
+ BIT(1, 0, 0x01, 4) |
+ BIT(Vtotal, 9, 0x01, 5) |
+ BIT(Vdispend, 9, 0x01, 6) |
+ BIT(Vsyncstart, 9, 0x01, 7);
+ hw->crtc[9] = BIT(0, 0, 0x1f, 0) |
+ BIT(Vblankstart,9, 0x01, 5) |
+ BIT(1, 0, 0x01, 6);
+ hw->crtc[10] = Vsyncstart;
+ hw->crtc[11] = BIT(Vsyncend, 0, 0x0f, 0) |
+ BIT(1, 0, 0x01, 7);
+ hw->crtc[12] = Vdispend;
+ hw->crtc[15] = Vblankstart;
+ hw->crtc[16] = Vblankend;
+ hw->crtc[18] = 0xff;
+
+ /* overflow - graphics reg 0x11 */
+/* 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10 4=LINECOMP:10 5-IVIDEO 6=FIXCNT */
+ hw->crtc_ofl =
+ BIT(Vtotal, 10, 0x01, 0) |
+ BIT(Vdispend, 10, 0x01, 1) |
+ BIT(Vsyncstart, 10, 0x01, 2) |
+ BIT(Vblankstart,10, 0x01, 3) |
+ 1 << 4;
+
+ return 0;
+}
+
+/*
+ * The following was discovered by a good monitor,
+ * bit twiddling, theorising and but mostly luck.
+ * Strangely, it looks like everyone elses' PLL!
+ *
+ * Clock registers:
+ * fclock = fpll / div2
+ * fpll = fref * mult / div1
+ * where:
+ * fref = 14.318MHz (69842ps)
+ * mult = reg0xb0.7:0
+ * div1 = (reg0xb1.5:0 + 1)
+ * div2 = 2^(reg0xb1.7:6)
+ * fpll should be between 115 and 260 MHz
+ * (8696ps and 3846ps)
+ */
static int
-cyber2000fb_decode_var(struct fb_var_screeninfo *var, int con, int *visual)
+cyber2000fb_decode_clock(struct par_info *hw, struct fb_var_screeninfo *var)
{
+ static unsigned int divisors_2000[] = { 1, 2, 4, 8 };
+ static unsigned int divisors_2010[] = { 1, 2, 4, 6 };
+ u_long pll_ps = var->pixclock;
+ const u_long ref_ps = 69842;
+ unsigned int *divisors;
+ u_int div2, t_div1, best_div1, best_mult;
+ int best_diff;
+
+ /*
+ * Step 1:
+ * find div2 such that 115MHz < fpll < 260MHz
+ * and 0 <= div2 < 4
+ */
+ if (current_par.dev_id == PCI_DEVICE_ID_INTERG_2010)
+ divisors = divisors_2010;
+ else
+ divisors = divisors_2000;
+
+ for (div2 = 0; div2 < 4; div2++) {
+ u_long new_pll;
+
+ new_pll = pll_ps / divisors[div2];
+ if (8696 > new_pll && new_pll > 3846) {
+ pll_ps = new_pll;
+ break;
+ }
+ }
+
+ if (div2 == 4)
+ return -EINVAL;
+
+ /*
+ * Step 2:
+ * Given pll_ps and ref_ps, find:
+ * pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005
+ * where { 1 < best_div1 < 32, 1 < best_mult < 256 }
+ * pll_ps_calc = best_div1 / (ref_ps * best_mult)
+ */
+ best_diff = 0x7fffffff;
+ best_mult = 32;
+ best_div1 = 255;
+ for (t_div1 = 32; t_div1 > 1; t_div1 -= 1) {
+ u_int rr, t_mult, t_pll_ps;
+ int diff;
+
+ /*
+ * Find the multiplier for this divisor
+ */
+ rr = ref_ps * t_div1;
+ t_mult = (rr + pll_ps / 2) / pll_ps;
+
+ /*
+ * Is the multiplier within the correct range?
+ */
+ if (t_mult > 256 || t_mult < 2)
+ continue;
+
+ /*
+ * Calculate the actual clock period from this multiplier
+ * and divisor, and estimate the error.
+ */
+ t_pll_ps = (rr + t_mult / 2) / t_mult;
+ diff = pll_ps - t_pll_ps;
+ if (diff < 0)
+ diff = -diff;
+
+ if (diff < best_diff) {
+ best_diff = diff;
+ best_mult = t_mult;
+ best_div1 = t_div1;
+ }
+
+ /*
+ * If we hit an exact value, there is no point in continuing.
+ */
+ if (diff == 0)
+ break;
+ }
+
+ /*
+ * Step 3:
+ * combine values
+ */
+ hw->clock_mult = best_mult - 1;
+ hw->clock_div = div2 << 6 | (best_div1 - 1);
+
+ return 0;
+}
+
+/*
+ * Decode the info required for the hardware.
+ * This involves the PLL parameters for the dot clock,
+ * CRTC registers, and accelerator settings.
+ */
+static int
+cyber2000fb_decode_var(struct fb_var_screeninfo *var, int con, struct par_info *hw)
+{
+ int err;
+
+ hw->width = var->xres_virtual;
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
- case 8:
- *visual = FB_VISUAL_PSEUDOCOLOR;
+ case 8: /* PSEUDOCOLOUR, 256 */
+ hw->visual = FB_VISUAL_PSEUDOCOLOR;
+ hw->pixformat = PIXFORMAT_8BPP;
+ hw->visualid = VISUALID_256;
+ hw->pitch = hw->width >> 3;
break;
#endif
#ifdef FBCON_HAS_CFB16
- case 16:
- *visual = FB_VISUAL_DIRECTCOLOR;
+ case 15:/* DIRECTCOLOUR, 32k */
+ hw->visual = FB_VISUAL_DIRECTCOLOR;
+ hw->pixformat = PIXFORMAT_16BPP;
+ hw->visualid = VISUALID_32K;
+ hw->pitch = hw->width >> 2;
+ break;
+
+ case 16:/* DIRECTCOLOUR, 64k */
+ hw->visual = FB_VISUAL_DIRECTCOLOR;
+ hw->pixformat = PIXFORMAT_16BPP;
+ hw->visualid = VISUALID_64K;
+ hw->pitch = hw->width >> 2;
break;
#endif
#ifdef FBCON_HAS_CFB24
- case 24:
- *visual = FB_VISUAL_TRUECOLOR;
+ case 24:/* TRUECOLOUR, 16m */
+ hw->visual = FB_VISUAL_TRUECOLOR;
+ hw->pixformat = PIXFORMAT_24BPP;
+ hw->visualid = VISUALID_16M;
+ hw->width *= 3;
+ hw->pitch = hw->width >> 3;
break;
#endif
default:
return -EINVAL;
}
+ err = cyber2000fb_decode_clock(hw, var);
+ if (err)
+ return err;
+
+ err = cyber2000fb_decode_crtc(hw, var);
+ if (err)
+ return err;
+
+ debug_printf("Clock: %02X %02X\n",
+ hw->clock_mult, hw->clock_div);
+ {
+ int i;
+
+ for (i = 0; i < 19; i++)
+ debug_printf("%2d ", i);
+ debug_printf("\n");
+ for (i = 0; i < 18; i++)
+ debug_printf("%02X ", hw->crtc[i]);
+ debug_printf("%02X\n", hw->crtc_ofl);
+ }
+ hw->width -= 1;
+
return 0;
}
@@ -648,17 +793,17 @@
struct display *display;
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, "Cyber2000");
+ strcpy(fix->id, current_par.dev_name);
if (con >= 0)
display = fb_display + con;
else
display = &global_disp;
- fix->smem_start = (char *)current_par.screen_base_p;
+ fix->smem_start = (void *)current_par.screen_base_p;
fix->smem_len = current_par.screen_size;
- fix->mmio_start = (char *)current_par.regs_base_p;
- fix->mmio_len = 0x000c0000;
+ fix->mmio_start = (void *)current_par.regs_base_p;
+ fix->mmio_len = MMIO_SIZE;
fix->type = display->type;
fix->type_aux = display->type_aux;
fix->xpanstep = 0;
@@ -694,14 +839,15 @@
cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
struct display *display;
- int err, chgvar = 0, visual;
+ struct par_info hw;
+ int err, chgvar = 0;
if (con >= 0)
display = fb_display + con;
else
display = &global_disp;
- err = cyber2000fb_decode_var(var, con, &visual);
+ err = cyber2000fb_decode_var(var, con, &hw);
if (err)
return err;
@@ -737,15 +883,17 @@
}
display->var = *var;
+ display->var.activate &= ~FB_ACTIVATE_ALL;
- display->screen_base = (char *)current_par.screen_base;
- display->visual = visual;
+ if (var->activate & FB_ACTIVATE_ALL)
+ global_disp.var = display->var;
+
+ display->screen_base = current_par.screen_base;
+ display->visual = hw.visual;
display->type = FB_TYPE_PACKED_PIXELS;
display->type_aux = 0;
- display->ypanstep = 0;
+ display->ypanstep = 1;
display->ywrapstep = 0;
- display->line_length =
- display->next_line = (var->xres_virtual * var->bits_per_pixel) / 8;
display->can_soft_blank = 1;
display->inverse = 0;
@@ -754,27 +902,33 @@
case 8:
dispsw = &fbcon_cfb8;
display->dispsw_data = NULL;
+ display->next_line = var->xres_virtual;
break;
#endif
#ifdef FBCON_HAS_CFB16
+ case 15:
case 16:
dispsw = &fbcon_cfb16;
display->dispsw_data = current_par.c_table.cfb16;
+ display->next_line = var->xres_virtual * 2;
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
dispsw = &fbcon_cfb24;
display->dispsw_data = current_par.c_table.cfb24;
+ display->next_line = var->xres_virtual * 3;
break;
#endif
default:
- printk(KERN_WARNING "cyber2000: no support for %dbpp\n",
- display->var.bits_per_pixel);
+ printk(KERN_WARNING "%s: no support for %dbpp\n",
+ current_par.dev_name, display->var.bits_per_pixel);
dispsw = &fbcon_dummy;
break;
}
+ display->line_length = display->next_line;
+
if (display->var.accel_flags & FB_ACCELF_TEXT &&
dispsw != &fbcon_dummy)
display->dispsw = &fbcon_cyber_accel;
@@ -788,7 +942,7 @@
struct fb_cmap *cmap;
cyber2000fb_update_start(var);
- cyber2000fb_set_timing(var);
+ cyber2000fb_set_timing(&hw);
if (display->cmap.len)
cmap = &display->cmap;
@@ -818,9 +972,9 @@
return -EINVAL;
if (y_bottom > fb_display[con].var.yres_virtual)
return -EINVAL;
-return -EINVAL;
- cyber2000fb_update_start(var);
+ if (cyber2000fb_update_start(var))
+ return -EINVAL;
fb_display[con].var.xoffset = var->xoffset;
fb_display[con].var.yoffset = var->yoffset;
@@ -849,9 +1003,12 @@
static int
cyber2000fb_updatevar(int con, struct fb_info *info)
{
+ int ret = 0;
+
if (con == current_par.currcon)
- cyber2000fb_update_start(&fb_display[con].var);
- return 0;
+ ret = cyber2000fb_update_start(&fb_display[con].var);
+
+ return ret;
}
static int
@@ -882,27 +1039,53 @@
{
int i;
- if (blank) {
+ /*
+ * Blank the screen if blank_mode != 0, else unblank. If
+ * blank == NULL then the caller blanks by setting the CLUT
+ * (Color Look Up Table) to all black. Return 0 if blanking
+ * succeeded, != 0 if un-/blanking failed due to e.g. a
+ * video mode which doesn't support it. Implements VESA
+ * suspend and powerdown modes on hardware that supports
+ * disabling hsync/vsync:
+ * blank_mode == 2: suspend vsync
+ * blank_mode == 3: suspend hsync
+ * blank_mode == 4: powerdown
+ *
+ * wms...Enable VESA DMPS compatible powerdown mode
+ * run "setterm -powersave powerdown" to take advantage
+ */
+
+ switch (blank) {
+ case 4: /* powerdown - both sync lines down */
+ cyber2000_grphw(0x16, 0x05);
+ break;
+ case 3: /* hsync off */
+ cyber2000_grphw(0x16, 0x01);
+ break;
+ case 2: /* vsync off */
+ cyber2000_grphw(0x16, 0x04);
+ break;
+ case 1: /* just software blanking of screen */
+ cyber2000_grphw(0x16, 0x00);
for (i = 0; i < 256; i++) {
cyber2000_outb(i, 0x3c8);
cyber2000_outb(0, 0x3c9);
cyber2000_outb(0, 0x3c9);
cyber2000_outb(0, 0x3c9);
}
- } else {
+ break;
+ default: /* case 0, or anything else: unblank */
+ cyber2000_grphw(0x16, 0x00);
for (i = 0; i < 256; i++) {
cyber2000_outb(i, 0x3c8);
cyber2000_outb(current_par.palette[i].red, 0x3c9);
cyber2000_outb(current_par.palette[i].green, 0x3c9);
cyber2000_outb(current_par.palette[i].blue, 0x3c9);
}
+ break;
}
}
-__initfunc(void cyber2000fb_setup(char *options, int *ints))
-{
-}
-
static struct fb_ops cyber2000fb_ops =
{
cyber2000fb_open,
@@ -916,8 +1099,96 @@
cyber2000fb_ioctl
};
-__initfunc(static void
-cyber2000fb_init_fbinfo(void))
+int cyber2000fb_attach(struct cyberpro_info *info)
+{
+ if (current_par.initialised) {
+ info->regs = CyberRegs;
+ info->fb = current_par.screen_base;
+ info->fb_size = current_par.screen_size;
+
+ strncpy(info->dev_name, current_par.dev_name, sizeof(info->dev_name));
+
+ MOD_INC_USE_COUNT;
+ }
+
+ return current_par.initialised;
+}
+
+void cyber2000fb_detach(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+EXPORT_SYMBOL(cyber2000fb_attach);
+EXPORT_SYMBOL(cyber2000fb_detach);
+
+#define fb_videomode fb_2_3_videomode
+
+/* stuff from 2.3 */
+struct fb_videomode {
+ const char *name;
+ u32 refresh;
+ u32 xres;
+ u32 yres;
+ u32 pixclock;
+ u32 left_margin;
+ u32 right_margin;
+ u32 upper_margin;
+ u32 lower_margin;
+ u32 hsync_len;
+ u32 vsync_len;
+ u32 sync;
+ u32 vmode;
+};
+
+static int fb_find_mode(struct fb_var_screeninfo *var, struct fb_info *info,
+ const char *mode_option, const struct fb_videomode *db,
+ unsigned int dbsize, const struct fb_videomode *default_mode,
+ unsigned int default_bpp)
+{
+ var->xres = default_mode->xres;
+ var->yres = default_mode->yres;
+ var->xres_virtual = default_mode->xres;
+ var->yres_virtual = default_mode->yres;
+ var->xoffset = 0;
+ var->yoffset = 0;
+ var->bits_per_pixel = default_bpp;
+ var->activate = 0;
+ var->pixclock = default_mode->pixclock;
+ var->left_margin = default_mode->left_margin;
+ var->right_margin = default_mode->right_margin;
+ var->upper_margin = default_mode->upper_margin;
+ var->lower_margin = default_mode->lower_margin;
+ var->hsync_len = default_mode->hsync_len;
+ var->vsync_len = default_mode->vsync_len;
+ var->sync = default_mode->sync;
+ var->vmode = default_mode->vmode;
+ return 3;
+}
+
+/*
+ * These parameters give
+ * 640x480, hsync 31.5kHz, vsync 60Hz
+ */
+static struct fb_videomode __initdata
+cyber2000fb_default_mode = {
+ name: NULL,
+ refresh: 60,
+ xres: 640,
+ yres: 480,
+ pixclock: 39722,
+ left_margin: 56,
+ right_margin: 16,
+ upper_margin: 34,
+ lower_margin: 9,
+ hsync_len: 88,
+ vsync_len: 2,
+ sync: FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ vmode: FB_VMODE_NONINTERLACED
+};
+
+static void __init
+cyber2000fb_init_fbinfo(void)
{
static int first = 1;
@@ -941,18 +1212,15 @@
* setup initial parameters
*/
memset(&init_var, 0, sizeof(init_var));
- init_var.xres_virtual =
- init_var.xres = DEFAULT_XRES;
- init_var.yres_virtual =
- init_var.yres = DEFAULT_YRES;
- init_var.bits_per_pixel = DEFAULT_BPP;
init_var.red.msb_right = 0;
init_var.green.msb_right = 0;
init_var.blue.msb_right = 0;
switch(init_var.bits_per_pixel) {
- case 8:
+ default:
+ init_var.bits_per_pixel = 8;
+ case 8: /* PSEUDOCOLOUR */
init_var.bits_per_pixel = 8;
init_var.red.offset = 0;
init_var.red.length = 8;
@@ -962,7 +1230,17 @@
init_var.blue.length = 8;
break;
- case 16:
+ case 15: /* RGB555 */
+ init_var.bits_per_pixel = 15;
+ init_var.red.offset = 10;
+ init_var.red.length = 5;
+ init_var.green.offset = 5;
+ init_var.green.length = 5;
+ init_var.blue.offset = 0;
+ init_var.blue.length = 5;
+ break;
+
+ case 16: /* RGB565 */
init_var.bits_per_pixel = 16;
init_var.red.offset = 11;
init_var.red.length = 5;
@@ -972,7 +1250,7 @@
init_var.blue.length = 5;
break;
- case 24:
+ case 24: /* RGB888 */
init_var.bits_per_pixel = 24;
init_var.red.offset = 16;
init_var.red.length = 8;
@@ -988,36 +1266,175 @@
init_var.height = -1;
init_var.width = -1;
init_var.accel_flags = FB_ACCELF_TEXT;
- init_var.sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT;
- init_var.vmode = FB_VMODE_NONINTERLACED;
}
/*
+ * Cyber2000 options:
+ *
+ * font:fontname
+ * Set the fontname
+ *
+ * res:XxY
+ * Set the default display resolution
+ */
+static void __init
+cyber2000fb_parse_font(char *opt)
+{
+ strcpy(fb_info.fontname, opt);
+}
+
+static struct options {
+ char *name;
+ void (*parse)(char *opt);
+} opt_table[] __initdata = {
+ { "font", cyber2000fb_parse_font },
+ { NULL, NULL }
+};
+
+int __init
+cyber2000fb_setup(char *options)
+{
+ struct options *optp;
+ char *opt;
+
+ if (!options || !*options)
+ return 0;
+
+ cyber2000fb_init_fbinfo();
+
+ for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
+ if (!*opt)
+ continue;
+
+ for (optp = opt_table; optp->name; optp++) {
+ int optlen;
+
+ optlen = strlen(optp->name);
+
+ if (strncmp(opt, optp->name, optlen) == 0 &&
+ opt[optlen] == ':') {
+ optp->parse(opt + optlen + 1);
+ break;
+ }
+ }
+
+ if (!optp->name)
+ printk(KERN_ERR "CyberPro20x0: unknown parameter: %s\n",
+ opt);
+ }
+ return 0;
+}
+
+static char igs_regs[] __initdata = {
+ 0x10, 0x10, 0x12, 0x00, 0x13, 0x00,
+ 0x16, 0x00,
+/* 0x30, 0x21,*/ 0x31, 0x00, 0x32, 0x00, 0x33, 0x01,
+ 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
+ 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01,
+ 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
+ 0x70, 0x0b,/* 0x71, 0x10, 0x72, 0x45,*/ 0x73, 0x30,
+ 0x74, 0x1b, 0x75, 0x1e, 0x76, 0x00, 0x7a, 0xc8
+};
+
+static void __init cyber2000fb_hw_init(void)
+{
+ int i;
+
+ for (i = 0; i < sizeof(igs_regs); i += 2)
+ cyber2000_grphw(igs_regs[i], igs_regs[i+1]);
+}
+
+static unsigned short device_ids[] __initdata = {
+ PCI_DEVICE_ID_INTERG_2000,
+ PCI_DEVICE_ID_INTERG_2010,
+ PCI_DEVICE_ID_INTERG_5000
+};
+
+/*
* Initialization
*/
-__initfunc(void cyber2000fb_init(void))
+int __init cyber2000fb_init(void)
{
- struct pci_dev *dev;
+ struct pci_dev *dev = NULL;
u_int h_sync, v_sync;
+ u_long mmio_base, smem_base, smem_size;
+ int err = 0, i;
+
+ for (i = 0; i < sizeof(device_ids) / sizeof(device_ids[0]); i++) {
+ dev = pci_find_device(PCI_VENDOR_ID_INTERG,
+ device_ids[i], NULL);
+ if (dev)
+ break;
+ }
- dev = pci_find_device(PCI_VENDOR_ID_INTERG, 0x2000, NULL);
if (!dev)
- return;
+ return -ENXIO;
+
+ sprintf(current_par.dev_name, "CyberPro%4X", dev->device);
- CyberRegs = bus_to_virt(dev->base_address[0]) + 0x00800000;/*FIXME*/
+ smem_base = dev->base_address[0] & ~3;
+ mmio_base = smem_base + 0x00800000;
+ current_par.dev_id = dev->device;
+
+ /*
+ * Map in the registers
+ */
+ CyberRegs = ioremap(mmio_base, MMIO_SIZE);
+ if (!CyberRegs) {
+ printk("%s: unable to map memory mapped IO\n",
+ current_par.dev_name);
+ err = -ENOMEM;
+ goto release_mmio_resource;
+ }
cyber2000_outb(0x18, 0x46e8);
cyber2000_outb(0x01, 0x102);
cyber2000_outb(0x08, 0x46e8);
+ /*
+ * get the video RAM size from the VGA register.
+ * This should have been already initialised by the BIOS,
+ * but if it's garbage, claim default 1MB VRAM (woody)
+ */
+ cyber2000_outb(0x72, 0x3ce);
+ switch (cyber2000_inb(0x3cf) & 3) {
+ case 2: smem_size = 0x00400000; break;
+ case 1: smem_size = 0x00200000; break;
+ default: smem_size = 0x00100000; break;
+ }
+
+ /*
+ * Map in screen memory
+ */
+ current_par.screen_base = ioremap(smem_base, smem_size);
+ if (!current_par.screen_base) {
+ printk("%s: unable to map screen memory\n",
+ current_par.dev_name);
+ err = -ENOMEM;
+ goto release_smem_resource;
+ }
+current_par.screen_base += IO_FUDGE_FACTOR;
+ current_par.screen_size = smem_size;
+ current_par.screen_base_p = smem_base + 0x80000000;
+ current_par.regs_base_p = mmio_base + 0x80000000;
+ current_par.currcon = -1;
+
cyber2000fb_init_fbinfo();
- current_par.currcon = -1;
- current_par.screen_base_p = 0x80000000 + dev->base_address[0];
- current_par.screen_base = (u_int)bus_to_virt(dev->base_address[0]);
- current_par.screen_size = 0x00200000;
- current_par.regs_base_p = 0x80800000 + dev->base_address[0];
+ if (!fb_find_mode(&init_var, &fb_info, NULL,
+ NULL, 0, &cyber2000fb_default_mode, 8)) {
+ printk("%s: no valid mode found\n",
+ current_par.dev_name);
+ goto release_smem_resource;
+ }
+ init_var.yres_virtual = smem_size * 8 /
+ (init_var.bits_per_pixel * init_var.xres_virtual);
+
+ if (init_var.yres_virtual < init_var.yres)
+ init_var.yres_virtual = init_var.yres;
+
+ cyber2000fb_hw_init();
cyber2000fb_set_var(&init_var, -1, &fb_info);
h_sync = 1953125000 / init_var.pixclock;
@@ -1026,23 +1443,40 @@
v_sync = h_sync / (init_var.yres + init_var.upper_margin +
init_var.lower_margin + init_var.vsync_len);
- printk("Cyber2000: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+ printk("%s: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+ current_par.dev_name,
current_par.screen_size >> 10,
init_var.xres, init_var.yres,
h_sync / 1000, h_sync % 1000, v_sync);
- if (register_framebuffer(&fb_info) < 0)
- return;
+ if (register_framebuffer(&fb_info) < 0) {
+ err = -EINVAL;
+ goto release_smem;
+ }
+
+ current_par.initialised = 1;
MOD_INC_USE_COUNT; /* TODO: This driver cannot be unloaded yet */
-}
+ return 0;
+release_smem:
+ iounmap(current_par.screen_base);
+release_smem_resource:
+ iounmap(CyberRegs);
+release_mmio_resource:
+ return err;
+}
#ifdef MODULE
-int init_module(void)
+int __init init_module(void)
{
- cyber2000fb_init();
+ int ret;
+
+ ret = cyber2000fb_init();
+ if (ret)
+ return ret;
+
return 0;
}
@@ -1052,6 +1486,12 @@
decremented to zero */
unregister_framebuffer(&fb_info);
/* TODO: clean up ... */
+
+ iounmap(current_par.screen_base);
+ iounmap(CyberRegs);
+
+ release_mem_region(smem_base, current_par.screen_size);
+ release_mem_region(mmio_base, MMIO_SIZE);
}
#endif /* MODULE */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)