patch-2.3.13 linux/drivers/video/atyfb.c

Next file: linux/drivers/video/cgfourteenfb.c
Previous file: linux/drivers/video/aty.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.12/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
@@ -1,4 +1,4 @@
-/*  $Id: atyfb.c,v 1.107 1999/06/08 19:59:03 geert Exp $
+/*  $Id: atyfb.c,v 1.109 1999/08/08 01:38:05 davem Exp $
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
  *	Copyright (C) 1997-1998  Geert Uytterhoeven
@@ -72,8 +72,8 @@
 #ifdef __sparc__
 #include <asm/pbm.h>
 #include <asm/fbio.h>
-#include <asm/uaccess.h>
 #endif
+#include <asm/uaccess.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -136,6 +136,8 @@
     u8 pll_ext_cntl;
     u32 dsp_config;	/* Mach64 GTB DSP */
     u32 dsp_on_off;	/* Mach64 GTB DSP */
+    u8 mclk_post_div_real;
+    u8 vclk_post_div_real;
 };
 
 
@@ -189,6 +191,7 @@
 
 struct fb_info_aty {
     struct fb_info fb_info;
+    struct fb_info_aty *next;
     unsigned long ati_regbase_phys;
     unsigned long ati_regbase;
     unsigned long frame_buffer_phys;
@@ -340,16 +343,19 @@
 			   const struct pll_gx *pll);
 static int aty_var_to_pll_18818(u32 vclk_per, struct pll_gx *pll);
 static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll);
-static int aty_pll_gx_to_var(const struct pll_gx *pll, u32 *vclk_per,
+static u32 aty_pll_gx_to_var(const struct pll_gx *pll,
 			     const struct fb_info_aty *info);
 static void aty_set_pll_ct(const struct fb_info_aty *info,
 			   const struct pll_ct *pll);
-static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
-		      u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div,
-		      u8 bpp, struct pll_ct *pll);
+static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
+			    struct pll_ct *pll);
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp,
+		      struct pll_ct *pll);
+static void aty_calc_pll_ct(const struct fb_info_aty *info,
+			    struct pll_ct *pll);
 static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
 			     u8 bpp, struct pll_ct *pll);
-static int aty_pll_ct_to_var(const struct pll_ct *pll, u32 *vclk_per,
+static u32 aty_pll_ct_to_var(const struct pll_ct *pll,
 			     const struct fb_info_aty *info);
 static void atyfb_set_par(const struct atyfb_par *par,
 			  struct fb_info_aty *info);
@@ -465,7 +471,7 @@
 };
 
 
-static inline u32 aty_ld_le32(volatile unsigned int regindex,
+static inline u32 aty_ld_le32(unsigned int regindex,
 			      const struct fb_info_aty *info)
 {
     unsigned long temp;
@@ -473,7 +479,7 @@
 
 #if defined(__powerpc__)
     temp = info->ati_regbase;
-    asm("lwbrx %0,%1,%2" : "=r"(val) : "r" (regindex), "r" (temp));
+    asm("lwbrx %0,%1,%2" : "=r"(val) : "b" (regindex), "r" (temp));
 #elif defined(__sparc_v9__)
     temp = info->ati_regbase + regindex;
     asm("lduwa [%1] %2, %0" : "=r" (val) : "r" (temp), "i" (ASI_PL));
@@ -484,14 +490,14 @@
     return val;
 }
 
-static inline void aty_st_le32(volatile unsigned int regindex, u32 val,
+static inline void aty_st_le32(unsigned int regindex, u32 val,
 			       const struct fb_info_aty *info)
 {
     unsigned long temp;
 
 #if defined(__powerpc__)
     temp = info->ati_regbase;
-    asm("stwbrx %0,%1,%2" : : "r" (val), "r" (regindex), "r" (temp) :
+    asm("stwbrx %0,%1,%2" : : "r" (val), "b" (regindex), "r" (temp) :
 	"memory");
 #elif defined(__sparc_v9__)
     temp = info->ati_regbase + regindex;
@@ -502,13 +508,13 @@
 #endif
 }
 
-static inline u8 aty_ld_8(volatile unsigned int regindex,
+static inline u8 aty_ld_8(unsigned int regindex,
 			  const struct fb_info_aty *info)
 {
     return *(volatile u8 *)(info->ati_regbase+regindex);
 }
 
-static inline void aty_st_8(volatile unsigned int regindex, u8 val,
+static inline void aty_st_8(unsigned int regindex, u8 val,
 			    const struct fb_info_aty *info)
 {
     *(volatile u8 *)(info->ati_regbase+regindex) = val;
@@ -941,8 +947,10 @@
 	}
 }
 
-__initfunc(static struct aty_cursor *
-aty_init_cursor(struct fb_info_aty *fb))
+static struct fb_info_aty *fb_list = NULL;
+
+static struct aty_cursor * __init 
+aty_init_cursor(struct fb_info_aty *fb)
 {
 	struct aty_cursor *cursor;
 	unsigned long addr;
@@ -1452,7 +1460,7 @@
 
     /* FIXME: ATI18818?? */
 
-static int aty_pll_gx_to_var(const struct pll_gx *pll, u32 *vclk_per,
+static u32 aty_pll_gx_to_var(const struct pll_gx *pll,
 			     const struct fb_info_aty *info)
 {
     u8 df, vco_div_count, ref_div_count;
@@ -1461,9 +1469,7 @@
     vco_div_count = pll->m & 0x3f;
     ref_div_count = pll->n;
 
-    *vclk_per = ((info->ref_clk_per*ref_div_count)<<(3-df))/(vco_div_count+65);
-
-    return 0;
+    return ((info->ref_clk_per*ref_div_count)<<(3-df))/(vco_div_count+65);
 }
 
 
@@ -1495,16 +1501,15 @@
     }
 }
 
-static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
-		      u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div,
-		      u8 bpp, struct pll_ct *pll)
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp,
+		      struct pll_ct *pll)
 {
     u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on;
     u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size;
 
     /* xclocks_per_row<<11 */
-    xclks_per_row = (mclk_fb_div*vclk_post_div*64<<11)/
-		    (vclk_fb_div*mclk_post_div*bpp);
+    xclks_per_row = (pll->mclk_fb_div*pll->vclk_post_div_real*64<<11)/
+		    (pll->vclk_fb_div*pll->mclk_post_div_real*bpp);
     if (xclks_per_row < (1<<11))
 	FAIL("Dotclock to high");
     if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == VT_CHIP_ID ||
@@ -1564,63 +1569,59 @@
     return 0;
 }
 
-static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
-			     u8 bpp, struct pll_ct *pll)
+static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
+			    struct pll_ct *pll)
 {
     u32 q, x;			/* x is a workaround for sparc64-linux-gcc */
-    u8 pll_ref_div, pll_gen_cntl, pll_ext_cntl;
-    u8 mclk_fb_div, mclk_post_div, mpostdiv = 0;
-    u8 vclk_fb_div, vclk_post_div, vpostdiv = 0;
-    int err;
-
     x = x;			/* x is a workaround for sparc64-linux-gcc */
 
-    pll->pll_vclk_cntl = 0x03;	/* VCLK = PLL_VCLK/VCLKx_POST */
-
-    pll_ref_div = info->pll_per*2*255/info->ref_clk_per;
+    pll->pll_ref_div = info->pll_per*2*255/info->ref_clk_per;
 
     /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
-    q = info->ref_clk_per*pll_ref_div*4/info->mclk_per;	/* actually 8*q */
+    q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per;	/* actually 8*q */
     if (q < 16*8 || q > 255*8)
 	FAIL("mclk out of range");
     else if (q < 32*8)
-	mclk_post_div = 8;
+	pll->mclk_post_div_real = 8;
     else if (q < 64*8)
-	mclk_post_div = 4;
+	pll->mclk_post_div_real = 4;
     else if (q < 128*8)
-	mclk_post_div = 2;
+	pll->mclk_post_div_real = 2;
     else
-	mclk_post_div = 1;
-    mclk_fb_div = q*mclk_post_div/8;
+	pll->mclk_post_div_real = 1;
+    pll->mclk_fb_div = q*pll->mclk_post_div_real/8;
 
     /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
-    q = info->ref_clk_per*pll_ref_div*4/vclk_per;	/* actually 8*q */
+    q = info->ref_clk_per*pll->pll_ref_div*4/vclk_per;	/* actually 8*q */
     if (q < 16*8 || q > 255*8)
 	FAIL("vclk out of range");
     else if (q < 32*8)
-	vclk_post_div = 8;
+	pll->vclk_post_div_real = 8;
     else if (q < 64*8)
-	vclk_post_div = 4;
+	pll->vclk_post_div_real = 4;
     else if (q < 128*8)
-	vclk_post_div = 2;
+	pll->vclk_post_div_real = 2;
     else
-	vclk_post_div = 1;
-    vclk_fb_div = q*vclk_post_div/8;
+	pll->vclk_post_div_real = 1;
+    pll->vclk_fb_div = q*pll->vclk_post_div_real/8;
+    return 0;
+}
 
-    if ((err = aty_dsp_gt(info, mclk_fb_div, mclk_post_div, vclk_fb_div,
-			  vclk_post_div, bpp, pll)))
-	return err;
+static void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll)
+{
+    u8 mpostdiv = 0;
+    u8 vpostdiv = 0;
 
     if ((((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) ||
 	 (Gx == GV_CHIP_ID) || (Gx == GW_CHIP_ID) || (Gx == GZ_CHIP_ID) ||
 	 (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
 	 (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) ||
 	 (Gx == VU_CHIP_ID)) && (info->ram_type >= SDRAM))
-	pll_gen_cntl = 0x04;
+	pll->pll_gen_cntl = 0x04;
     else
-	pll_gen_cntl = 0x84;
+	pll->pll_gen_cntl = 0x84;
 
-    switch (mclk_post_div) {
+    switch (pll->mclk_post_div_real) {
 	case 1:
 	    mpostdiv = 0;
 	    break;
@@ -1637,61 +1638,64 @@
 	    mpostdiv = 3;
 	    break;
     }
-    pll_gen_cntl |= mpostdiv<<4;	/* mclk */
+    pll->pll_gen_cntl |= mpostdiv<<4;	/* mclk */
 
     if (Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48))
-	pll_ext_cntl = 0;
+	pll->pll_ext_cntl = 0;
     else
-    	pll_ext_cntl = mpostdiv;	/* xclk == mclk */
+    	pll->pll_ext_cntl = mpostdiv;	/* xclk == mclk */
 
-    switch (vclk_post_div) {
+    switch (pll->vclk_post_div_real) {
 	case 2:
 	    vpostdiv = 1;
 	    break;
 	case 3:
-	    pll_ext_cntl |= 0x10;
+	    pll->pll_ext_cntl |= 0x10;
 	case 1:
 	    vpostdiv = 0;
 	    break;
 	case 6:
-	    pll_ext_cntl |= 0x10;
+	    pll->pll_ext_cntl |= 0x10;
 	case 4:
 	    vpostdiv = 2;
 	    break;
 	case 12:
-	    pll_ext_cntl |= 0x10;
+	    pll->pll_ext_cntl |= 0x10;
 	case 8:
 	    vpostdiv = 3;
 	    break;
     }
-    vclk_post_div = vpostdiv;
 
-    pll->pll_ref_div = pll_ref_div;
-    pll->pll_gen_cntl = pll_gen_cntl;
-    pll->mclk_fb_div = mclk_fb_div;
-    pll->vclk_post_div = vclk_post_div;
-    pll->vclk_fb_div = vclk_fb_div;
-    pll->pll_ext_cntl = pll_ext_cntl;
+    pll->pll_vclk_cntl = 0x03;	/* VCLK = PLL_VCLK/VCLKx_POST */
+    pll->vclk_post_div = vpostdiv;
+}
+
+static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
+			     u8 bpp, struct pll_ct *pll)
+{
+    int err;
+
+    if ((err = aty_valid_pll_ct(info, vclk_per, pll)))
+	return err;
+    if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID ||
+	  Gx == ET_CHIP_ID ||
+	  ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)))) {
+	if ((err = aty_dsp_gt(info, bpp, pll)))
+	    return err;
+    }
+    aty_calc_pll_ct(info, pll);
     return 0;
 }
 
-static int aty_pll_ct_to_var(const struct pll_ct *pll, u32 *vclk_per,
+static u32 aty_pll_ct_to_var(const struct pll_ct *pll,
 			     const struct fb_info_aty *info)
 {
+    u32 ref_clk_per = info->ref_clk_per;
     u8 pll_ref_div = pll->pll_ref_div;
     u8 vclk_fb_div = pll->vclk_fb_div;
-    u8 vclk_post_div = pll->vclk_post_div;
-    u8 pll_ext_cntl = pll->pll_ext_cntl;
-    static u8 vclk_post_div_tab[] = {
-	1, 2, 4, 8,
-	3, 0, 6, 12
-    };
-    u8 vpostdiv = vclk_post_div_tab[((pll_ext_cntl & 0x10) >> 2) |
-				    (vclk_post_div & 3)];
-    if (vpostdiv == 0)
-	return -EINVAL;
-    *vclk_per = pll_ref_div*vpostdiv*info->ref_clk_per/vclk_fb_div/2;
-    return 0;
+    u8 vclk_post_div = pll->vclk_post_div_real;
+
+    return ref_clk_per*pll_ref_div*vclk_post_div/vclk_fb_div/2;
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1739,7 +1743,7 @@
 					
     } else {
 	aty_set_pll_ct(info, &par->pll.ct);
-	i = aty_ld_le32(MEM_CNTL, info) & 0xf30fffff;
+	i = aty_ld_le32(MEM_CNTL, info) & 0xf00fffff;
 	if (!(Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48)))
 	    i |= info->mem_refresh_rate << 20;
 	switch (par->crtc.bpp) {
@@ -1844,11 +1848,9 @@
     if ((err = aty_crtc_to_var(&par->crtc, var)))
 	return err;
     if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
-	err = aty_pll_gx_to_var(&par->pll.gx, &var->pixclock, info);
+	var->pixclock = aty_pll_gx_to_var(&par->pll.gx, info);
     else
-	err = aty_pll_ct_to_var(&par->pll.ct, &var->pixclock, info);
-    if (err)
-	return err;
+	var->pixclock = aty_pll_ct_to_var(&par->pll.ct, info);
 
     var->height = -1;
     var->width = -1;
@@ -2194,36 +2196,101 @@
 }
 
 
+#ifdef DEBUG
+#define ATYIO_CLKR		0x41545900	/* ATY\00 */
+#define ATYIO_CLKW		0x41545901	/* ATY\01 */
+
+struct atyclk {
+    u32 ref_clk_per;
+    u8 pll_ref_div;
+    u8 mclk_fb_div;
+    u8 mclk_post_div;		/* 1,2,3,4,8 */
+    u8 vclk_fb_div;
+    u8 vclk_post_div;		/* 1,2,3,4,6,8,12 */
+    u32 dsp_xclks_per_row;	/* 0-16383 */
+    u32 dsp_loop_latency;	/* 0-15 */
+    u32 dsp_precision;		/* 0-7 */
+    u32 dsp_on;			/* 0-2047 */
+    u32 dsp_off;		/* 0-2047 */
+};
+#endif
+
 static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg, int con, struct fb_info *info)
+		       u_long arg, int con, struct fb_info *info2)
 {
+    struct fb_info_aty *info = (struct fb_info_aty *)info2;
 #ifdef __sparc__
-    struct fb_info_aty *fb = (struct fb_info_aty *)info;
     struct fbtype fbtyp;
     struct display *disp;
     
     if (con >= 0)
     	disp = &fb_display[con];
     else
-        disp = info->disp;
+        disp = info2->disp;
+#endif
 
     switch (cmd) {
+#ifdef __sparc__
     case FBIOGTYPE:
 	fbtyp.fb_type = FBTYPE_PCI_GENERIC;
-	fbtyp.fb_width = fb->current_par.crtc.vxres;
-	fbtyp.fb_height = fb->current_par.crtc.vyres;
-	fbtyp.fb_depth = fb->current_par.crtc.bpp;
+	fbtyp.fb_width = info->current_par.crtc.vxres;
+	fbtyp.fb_height = info->current_par.crtc.vyres;
+	fbtyp.fb_depth = info->current_par.crtc.bpp;
 	fbtyp.fb_cmsize = disp->cmap.len;
-	fbtyp.fb_size = fb->total_vram;
+	fbtyp.fb_size = info->total_vram;
 	copy_to_user_ret((struct fbtype *)arg, &fbtyp, sizeof(fbtyp), -EFAULT);
 	break;
+#endif /* __sparc__ */
+#ifdef DEBUG
+    case ATYIO_CLKR:
+	if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
+	    struct atyclk clk;
+	    struct pll_ct *pll = &info->current_par.pll.ct;
+	    u32 dsp_config = pll->dsp_config;
+	    u32 dsp_on_off = pll->dsp_on_off;
+	    clk.ref_clk_per = info->ref_clk_per;
+	    clk.pll_ref_div = pll->pll_ref_div;
+	    clk.mclk_fb_div = pll->mclk_fb_div;
+	    clk.mclk_post_div = pll->mclk_post_div_real;
+	    clk.vclk_fb_div = pll->vclk_fb_div;
+	    clk.vclk_post_div = pll->vclk_post_div_real;
+	    clk.dsp_xclks_per_row = dsp_config & 0x3fff;
+	    clk.dsp_loop_latency = (dsp_config>>16) & 0xf;
+	    clk.dsp_precision = (dsp_config>>20) & 7;
+	    clk.dsp_on = dsp_on_off & 0x7ff;
+	    clk.dsp_off = (dsp_on_off>>16) & 0x7ff;
+	    copy_to_user_ret((struct atyclk *)arg, &clk, sizeof(clk),
+			     -EFAULT);
+	} else
+	    return -EINVAL;
+	break;
+    case ATYIO_CLKW:
+	if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
+	    struct atyclk clk;
+	    struct pll_ct *pll = &info->current_par.pll.ct;
+	    copy_from_user_ret(&clk, (struct atyclk *)arg, sizeof(clk),
+			       -EFAULT);
+	    info->ref_clk_per = clk.ref_clk_per;
+	    pll->pll_ref_div = clk.pll_ref_div;
+	    pll->mclk_fb_div = clk.mclk_fb_div;
+	    pll->mclk_post_div_real = clk.mclk_post_div;
+	    pll->vclk_fb_div = clk.vclk_fb_div;
+	    pll->vclk_post_div_real = clk.vclk_post_div;
+	    pll->dsp_config = (clk.dsp_xclks_per_row & 0x3fff) |
+			      ((clk.dsp_loop_latency & 0xf)<<16) |
+			      ((clk.dsp_precision & 7)<<20);
+	    pll->dsp_on_off = (clk.dsp_on & 0x7ff) |
+			      ((clk.dsp_off & 0x7ff)<<16);
+	    aty_calc_pll_ct(info, pll);
+	    aty_set_pll_ct(info, pll);
+	} else
+	    return -EINVAL;
+	break;
+#endif /* DEBUG */
     default:
 	return -EINVAL;
     }
     return 0;
-#else
-    return -EINVAL;
-#endif
 }
 
 #ifdef __sparc__
@@ -2424,7 +2491,7 @@
      *  Initialisation
      */
 
-__initfunc(static int aty_init(struct fb_info_aty *info, const char *name))
+static int __init aty_init(struct fb_info_aty *info, const char *name)
 {
     u32 chip_id;
     u32 i;
@@ -2746,12 +2813,15 @@
     if (register_framebuffer(&info->fb_info) < 0)
 	return 0;
 
+    info->next = fb_list;
+    fb_list = info;
+
     printk("fb%d: %s frame buffer device on %s\n",
 	   GET_FB_IDX(info->fb_info.node), atyfb_name, name);
     return 1;
 }
 
-__initfunc(void atyfb_init(void))
+void __init atyfb_init(void)
 {
 #if defined(CONFIG_FB_OF)
     /* We don't want to be called like this. */
@@ -2779,6 +2849,7 @@
     for (pdev = pci_devices; pdev; pdev = pdev->next) {
 	if (((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
 	    (pdev->vendor == PCI_VENDOR_ID_ATI)) {
+	    struct resource *rp;
 
 	    info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
 	    if (!info) {
@@ -2787,12 +2858,12 @@
 	    }
 	    memset(info, 0, sizeof(struct fb_info_aty));
 
-	    addr = pdev->base_address[0];
-	    if ((addr & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
-		addr = pdev->base_address[1];
+	    rp = &pdev->resource[0];
+	    if (rp->flags & IORESOURCE_IOPORT)
+		    rp = &pdev->resource[1];
+	    addr = rp->start;
 	    if (!addr)
 		continue;
-	    addr &= PCI_BASE_ADDRESS_MEM_MASK;
 
 #ifdef __sparc__
 	    /*
@@ -2811,7 +2882,7 @@
 	     * Figure mmap addresses from PCI config space.
 	     * Split Framebuffer in big- and little-endian halfs.
 	     */
-	    for (i = 0; i < 6 && pdev->base_address[i]; i++)
+	    for (i = 0; i < 6 && pdev->resource[i].start; i++)
 		/* nothing */;
 	    j = i + 4;
 
@@ -2823,14 +2894,15 @@
 	    }
 	    memset(info->mmap_map, 0, j * sizeof(*info->mmap_map));
 
-	    for (i = 0, j = 2; i < 6 && pdev->base_address[i]; i++) {
+	    for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {
+		struct resource *rp = &pdev->resource[i];
 		int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);
 		unsigned long base;
 		u32 size, pbase;
 
-		base = pdev->base_address[i];
+		base = rp->start;
 
-		io = (base & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+		io = (rp->flags & IORESOURCE_IOPORT);
 
 		pci_read_config_dword(pdev, breg, &pbase);
 		pci_write_config_dword(pdev, breg, 0xffffffff);
@@ -3096,7 +3168,7 @@
 }
 
 #ifdef CONFIG_FB_OF
-__initfunc(void atyfb_of_init(struct device_node *dp))
+void __init atyfb_of_init(struct device_node *dp)
 {
     unsigned long addr;
     u8 bus, devfn;
@@ -3135,7 +3207,7 @@
 						   0x1000);
 
     if(! info->ati_regbase) {
-	    printk("atyfb_init: ioremap() returned NULL\n");
+	    printk("atyfb_of_init: ioremap() returned NULL\n");
 	    kfree(info);
 	    return;
     }
@@ -3162,7 +3234,7 @@
     info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
 
     if(! info->frame_buffer) {
-	    printk("atyfb_init: ioremap() returned NULL\n");
+	    printk("atyfb_of_init: ioremap() returned NULL\n");
 	    kfree(info);
 	    return;
     }
@@ -3180,7 +3252,7 @@
 #endif /* CONFIG_FB_OF */
 
 
-__initfunc(void atyfb_setup(char *options, int *ints))
+void __init atyfb_setup(char *options, int *ints)
 {
     char *this_opt;
 
@@ -3251,7 +3323,7 @@
 }
 
 #ifdef CONFIG_ATARI
-__initfunc(static int store_video_par(char *video_str, unsigned char m64_num))
+static int __init store_video_par(char *video_str, unsigned char m64_num)
 {
     char *p;
     unsigned long vmembase, size, guiregbase;
@@ -3280,7 +3352,7 @@
     return -1;
 }
 
-__initfunc(static char *strtoke(char *s, const char *ct))
+static char __init *strtoke(char *s, const char *ct)
 {
     static char *ssave = NULL;
     char *sbegin, *send;
@@ -3869,4 +3941,45 @@
     fbcon_aty32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_aty32_clear_margins,
     FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
+#endif
+
+#ifdef MODULE
+int __init init_module(void)
+{
+    atyfb_init();
+    return fb_list ? 0 : -ENXIO;
+}
+
+void cleanup_module(void)
+{
+    while (fb_list) {
+	struct fb_info_aty *info = fb_list;
+	fb_list = info->next;
+
+	unregister_framebuffer(&info->fb_info);
+
+#ifndef __sparc__
+	if (info->ati_regbase)
+	    iounmap((void *)info->ati_regbase);
+	if (info->frame_buffer)
+	    iounmap((void *)info->frame_buffer);
+#ifdef __BIG_ENDIAN
+	if (info->cursor && info->cursor->ram)
+	    iounmap(info->cursor->ram);
+#endif
+#endif
+
+	if (info->cursor) {
+	    if (info->cursor->timer)
+		kfree(info->cursor->timer);
+	    kfree(info->cursor);
+	}
+#ifdef __sparc__
+	if (info->mmap_map)
+	    kfree(info->mmap_map);
+#endif
+	kfree(info);
+    }
+}
+
 #endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)