示例#1
0
文件: fbmem.c 项目: andreiw/mkunity
static int 
fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma)
{
	struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
	struct fb_fix_screeninfo fix;

	if (! fb)
		return -ENODEV;
	fb->fb_get_fix(&fix, PROC_CONSOLE());
	if ((vma->vm_end - vma->vm_start + vma->vm_offset) > fix.smem_len)
		return -EINVAL;
	vma->vm_offset += fix.smem_start;
	if (vma->vm_offset & ~PAGE_MASK)
		return -ENXIO;
	if (m68k_is040or060) {
		pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
		/* Use write-through cache mode */
		pgprot_val(vma->vm_page_prot) |= _PAGE_CACHE040W;
	}
	if (remap_page_range(vma->vm_start, vma->vm_offset,
			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
		return -EAGAIN;
	vma->vm_inode = inode;
	inode->i_count++;
	return 0;
}
示例#2
0
文件: fb.c 项目: Keripo/linux-ipod
int __init ipodfb_init(void)
{
	fb_info.gen.fbhw = &ipod_switch;

	fb_info.gen.fbhw->detect();

	strcpy(fb_info.gen.info.modename, "iPod");

	fb_info.gen.info.changevar = NULL;
	fb_info.gen.info.node = -1;
	fb_info.gen.info.fbops = &ipodfb_ops;
	fb_info.gen.info.disp = &disp;
	fb_info.gen.info.switch_con = &fbgen_switch;
	fb_info.gen.info.updatevar = &fbgen_update_var;
	fb_info.gen.info.blank = &fbgen_blank;
	fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;

	/* This should give a reasonable default video mode */
	fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
	fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
	fbgen_set_disp(-1, &fb_info.gen);
	fbgen_install_cmap(0, &fb_info.gen);

	if ( register_framebuffer(&fb_info.gen.info) < 0 ) {
		return -EINVAL;
	}

	init_lcd();

	printk(KERN_INFO "fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename);

	/* uncomment this if your driver cannot be unloaded */
	/* MOD_INC_USE_COUNT; */
	return 0;
}
示例#3
0
int __init vfb_init(void)
{
    if (!vfb_enable)
	return -ENXIO;

    if (!(videomemory = (u_long)vmalloc(videomemorysize)))
	return -ENOMEM;

    strcpy(fb_info.modename, vfb_name);
    fb_info.changevar = NULL;
    fb_info.node = -1;
    fb_info.fbops = &vfb_ops;
    fb_info.disp = &disp;
    fb_info.switch_con = &vfbcon_switch;
    fb_info.updatevar = &vfbcon_updatevar;
    fb_info.blank = &vfbcon_blank;
    fb_info.flags = FBINFO_FLAG_DEFAULT;

    vfb_set_var(&vfb_default, -1, &fb_info);

    if (register_framebuffer(&fb_info) < 0) {
	vfree((void *)videomemory);
	return -EINVAL;
    }

    printk(KERN_INFO "fb%d: Virtual frame buffer device, using %ldK of video memory\n",
	   GET_FB_IDX(fb_info.node), videomemorysize>>10);
    return 0;
}
示例#4
0
static inline int i2c_ddc2_init(struct matroxfb_dh_maven_info* minfo2) {
	struct i2c_bit_adapter *b = &minfo2->ddc2;

	b->adapter = matrox_ddc2_adapter_template;
	b->bac = matrox_ddc2_algo_template;
	sprintf(b->adapter.name, "DDC:fb%u #1 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
	return i2c_bus_reg(b, minfo2->primary_dev);
}
示例#5
0
static int __init init_one(int slot)
{
	unsigned long base_addr = CKSEG1ADDR(get_tc_base_addr(slot));
	struct aafb_info *ip = &my_fb_info[slot];

	memset(ip, 0, sizeof(struct aafb_info));

	/*
	 * Framebuffer display memory base address and friends.
	 */
	ip->bt455 = (struct bt455_regs *) (base_addr + PMAG_AA_BT455_OFFSET);
	ip->bt431 = (struct bt431_regs *) (base_addr + PMAG_AA_BT431_OFFSET);
	ip->fb_start = base_addr + PMAG_AA_ONBOARD_FBMEM_OFFSET;
	ip->fb_size = 2048 * 1024; /* fb_fix_screeninfo.smem_length
				      seems to be physical */
	ip->fb_line_length = 2048;

	/*
	 * Let there be consoles..
	 */
	strcpy(ip->info.modename, "PMAG-AA");
	ip->info.node = -1;
	ip->info.flags = FBINFO_FLAG_DEFAULT;
	ip->info.fbops = &aafb_ops;
	ip->info.disp = &ip->disp;
	ip->info.changevar = NULL;
	ip->info.switch_con = &aafb_switch;
	ip->info.updatevar = &aafb_update_var;
	ip->info.blank = &aafb_blank;

	aafb_set_disp(&ip->disp, currcon, ip);

	/*
	 * Configure the RAM DACs.
	 */
	bt455_erase_cursor(ip->bt455);

	/* Init colormap. */
	bt455_write_cmap_entry(ip->bt455, 0, 0x00, 0x00, 0x00);
	bt455_write_cmap_entry(ip->bt455, 1, 0x0f, 0x0f, 0x0f);

	/* Init hardware cursor. */
	bt431_init_cursor(ip->bt431);
	aafb_cursor_init(ip);

	/* Clear the screen. */
	memset ((void *)ip->fb_start, 0, ip->fb_size);

	if (register_framebuffer(&ip->info) < 0)
		return -EINVAL;

	printk(KERN_INFO "fb%d: %s frame buffer in TC slot %d\n",
	       GET_FB_IDX(ip->info.node), ip->info.modename, slot);

	return 0;
}
示例#6
0
文件: fbmem.c 项目: andreiw/mkunity
int
unregister_framebuffer(int node)
{
	int i=GET_FB_IDX(node);
	if (! registered_fb[i])
		return -EINVAL; 
	registered_fb[i]=NULL;
	registered_fb_var[i]=NULL;
	return 0;
}
示例#7
0
文件: fbmem.c 项目: andreiw/mkunity
static void 
fb_release(struct inode *inode, struct file *file)
{
	int fbidx=GET_FB_IDX(inode->i_rdev);
	int vidx=GET_FB_VAR_IDX(inode->i_rdev);
	if (! vidx)
		return;
	if (! (--fb_open_count[fbidx]))
		fb_curr_open[fbidx]=0;
}
示例#8
0
文件: igafb.c 项目: dmgerman/original
static int __init iga_init(struct fb_info_iga *info)
{
        char vramsz = iga_inb(info, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL) 
		                                         & MEM_SIZE_ALIAS;
        switch (vramsz) {
        case MEM_SIZE_1M:
                info->total_vram = 0x100000;
                break;
        case MEM_SIZE_2M:
                info->total_vram = 0x200000;
                break;
        case MEM_SIZE_4M:
        case MEM_SIZE_RESERVED:
                info->total_vram = 0x400000;
                break;
        }

        if (default_var.bits_per_pixel > 8) {
                info->video_cmap_len = 16;
        } else {
                info->video_cmap_len = 256;
        }
	{
		int j, k;
		for (j = 0; j < 16; j++) {
			k = color_table[j];
			info->palette[j].red = default_red[k];
			info->palette[j].green = default_grn[k];
			info->palette[j].blue = default_blu[k];
		}
	}

	strcpy(info->fb_info.modename, igafb_name);
	info->fb_info.node = -1;
	info->fb_info.fbops = &igafb_ops;
	info->fb_info.disp = &info->disp;
	strcpy(info->fb_info.fontname, fontname);
	info->fb_info.changevar = NULL;
	info->fb_info.switch_con = &igafb_switch;
	info->fb_info.updatevar = &igafb_update_var;
	info->fb_info.blank = &igafb_blank;
	info->fb_info.flags=FBINFO_FLAG_DEFAULT;

	igafb_set_disp(-1, info);

	if (register_framebuffer(&info->fb_info) < 0)
		return 0;

	printk("fb%d: %s frame buffer device at 0x%08lx [%dMB VRAM]\n",
	       GET_FB_IDX(info->fb_info.node), igafb_name, 
	       info->frame_buffer_phys, info->total_vram >> 20);

	iga_blank_border(info); 
	return 1;
}
int __init mc68x328fb_init(void)
{
	/*
	 *  initialize the default mode from the LCD controller registers
	 */
	mc68x328fb_default.xres = LXMAX;
	mc68x328fb_default.yres = LYMAX+1;
	mc68x328fb_default.bits_per_pixel = 1 << (LPICF & 0x03);
	// BOGO: assume a panel is color if the bus width is 8 bits
	if((LPICF & 0x0c) == 0x0c) {
	    mc68x328fb_default.xres /= 3;
	    mc68x328fb_default.bits_per_pixel *= 3;
	}
	mc68x328fb_default.xres_virtual = mc68x328fb_default.xres;
	mc68x328fb_default.yres_virtual = mc68x328fb_default.yres;
	videomemory = LSSA;
	videomemorysize = (mc68x328fb_default.xres+7) / 8 *
		mc68x328fb_default.yres * mc68x328fb_default.bits_per_pixel;

    strcpy(fb_info.modename, mc68x328fb_name);
    fb_info.changevar = NULL;
    fb_info.node = -1;
    fb_info.fbops = &mc68x328fb_ops;
    fb_info.disp = &disp;
    fb_info.switch_con = &vfbcon_switch;
    fb_info.updatevar = &vfbcon_updatevar;
    fb_info.blank = &vfbcon_blank;
    fb_info.flags = FBINFO_FLAG_DEFAULT;

    mc68x328fb_set_var(&mc68x328fb_default, -1, &fb_info);

    if (register_framebuffer(&fb_info) < 0) {
	return -EINVAL;
    }

    printk(KERN_INFO "fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info.node),
		mc68x328fb_name);
	printk(KERN_INFO "fb%d: %dx%dx%d at 0x%08lx\n", GET_FB_IDX(fb_info.node),
		mc68x328fb_default.xres, mc68x328fb_default.yres,
		1 << mc68x328fb_default.bits_per_pixel, videomemory);
    return 0;
}
static int __init init_one(int slot)
{
	unsigned long base_addr = CKSEG1ADDR(get_tc_base_addr(slot));
	struct aafb_info *ip = &my_fb_info[slot];

	memset(ip, 0, sizeof(struct aafb_info));

	ip->bt455 = (struct bt455_regs *) (base_addr + PMAG_AA_BT455_OFFSET);
	ip->bt431 = (struct bt431_regs *) (base_addr + PMAG_AA_BT431_OFFSET);
	ip->fb_start = base_addr + PMAG_AA_ONBOARD_FBMEM_OFFSET;
	ip->fb_size = 2048 * 1024; 
	ip->fb_line_length = 2048;

	strcpy(ip->info.modename, "PMAG-AA");
	ip->info.node = -1;
	ip->info.flags = FBINFO_FLAG_DEFAULT;
	ip->info.fbops = &aafb_ops;
	ip->info.disp = &ip->disp;
	ip->info.changevar = NULL;
	ip->info.switch_con = &aafb_switch;
	ip->info.updatevar = &aafb_update_var;
	ip->info.blank = &aafb_blank;

	aafb_set_disp(&ip->disp, currcon, ip);

	bt455_erase_cursor(ip->bt455);

	
	bt455_write_cmap_entry(ip->bt455, 0, 0x00, 0x00, 0x00);
	bt455_write_cmap_entry(ip->bt455, 1, 0x0f, 0x0f, 0x0f);

	
	bt431_init_cursor(ip->bt431);
	aafb_cursor_init(ip);

	
	memset ((void *)ip->fb_start, 0, ip->fb_size);

	if (register_framebuffer(&ip->info) < 0)
		return -EINVAL;

	printk(KERN_INFO "fb%d: %s frame buffer in TC slot %d\n",
	       GET_FB_IDX(ip->info.node), ip->info.modename, slot);

	return 0;
}
示例#11
0
int console_setmode(struct vc_mode *mode, int doit)
{
    struct fb_var_screeninfo var;
    int cmode, err;

    if (!console_fb_info)
        return -EOPNOTSUPP;

    switch(mode->depth) {
        case 0:
        case 8:
            cmode = CMODE_8;
            break;
        case 16:
            cmode = CMODE_16;
            break;
        case 24:
        case 32:
            cmode = CMODE_32;
            break;
        default:
            return -EINVAL;
    }

    if ((err = mac_vmode_to_var(mode->mode, cmode, &var)))
        return err;

    var.activate = FB_ACTIVATE_TEST;
    err = console_fb_info->fbops->fb_set_var(&var, fg_console,
                                             console_fb_info);
    if (err || !doit)
        return err;
    else {
        int unit;

        var.activate = FB_ACTIVATE_NOW;
        for (unit = 0; unit < MAX_NR_CONSOLES; unit++)
            if (fb_display[unit].conp &&
                (GET_FB_IDX(console_fb_info->node) == con2fb_map[unit]))
                console_fb_info->fbops->fb_set_var(&var, unit,
                                                   console_fb_info);
    }

    return 0;
}
示例#12
0
文件: fbmem.c 项目: andreiw/mkunity
static int 
fb_write(struct inode *inode, struct file *file, const char *buf, int count)
{
	unsigned long p = file->f_pos;
	struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
	struct fb_fix_screeninfo fix;
	char *base_addr;
	int copy_size;

	if (! fb)
		return -ENODEV;
	if (count < 0)
		return -EINVAL;
	fb->fb_get_fix(&fix, PROC_CONSOLE());
	base_addr=(char *) fix.smem_start;
	copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p);
	memcpy_fromfs(base_addr+p, buf, copy_size); 
	file->f_pos += copy_size;
	return copy_size;
}
示例#13
0
文件: fbmem.c 项目: andreiw/mkunity
static int
fb_open(struct inode *inode, struct file *file)
{
	int fbidx=GET_FB_IDX(inode->i_rdev);
	int vidx=GET_FB_VAR_IDX(inode->i_rdev);
	struct fb_ops *fb = registered_fb[fbidx];
	int err;
	
	if (! vidx)		/* fb?current always succeeds */ 
		return 0;
	if (vidx > registered_fb_var_num[fbidx])
		return -EINVAL;
	if (fb_curr_open[fbidx] && fb_curr_open[fbidx] != vidx)
		return -EBUSY;
 	if (file->f_mode & 2) /* only set parameters if opened writeable */
		if ((err=fb->fb_set_var(registered_fb_var[fbidx] + vidx-1, PROC_CONSOLE())))
			return err;
	fb_curr_open[fbidx] = vidx;
	fb_open_count[fbidx]++;
	return 0;
}
示例#14
0
文件: fbmem.c 项目: andreiw/mkunity
static int 
fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
	 unsigned long arg)
{
	struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
	struct fb_cmap cmap;
	struct fb_var_screeninfo var;
	struct fb_fix_screeninfo fix;

	int i,fbidx,vidx;
	
	if (! fb)
		return -ENODEV;
	switch (cmd) {
	case FBIOGET_VSCREENINFO:
		i = verify_area(VERIFY_WRITE, (void *) arg, 
				sizeof(struct fb_var_screeninfo));
		if (i) return i;
		fbidx=GET_FB_IDX(inode->i_rdev);
		vidx=GET_FB_VAR_IDX(inode->i_rdev);
		if (! vidx) /* ask device driver for current */
			i=fb->fb_get_var(&var, PROC_CONSOLE());
		else
			var=registered_fb_var[fbidx][vidx-1];
		memcpy_tofs((void *) arg, &var, sizeof(var));
		return i;
	case FBIOPUT_VSCREENINFO:
		i = verify_area(VERIFY_WRITE, (void *) arg, 
				sizeof(struct fb_var_screeninfo));
		if (i) return i;
		memcpy_fromfs(&var, (void *) arg, sizeof(var));
		i=fb->fb_set_var(&var, PROC_CONSOLE());
		memcpy_tofs((void *) arg, &var, sizeof(var));
		fbidx=GET_FB_IDX(inode->i_rdev);
		vidx=GET_FB_VAR_IDX(inode->i_rdev);
		if (! i && vidx)
			registered_fb_var[fbidx][vidx-1]=var;
		return i;
	case FBIOGET_FSCREENINFO:
		i = verify_area(VERIFY_WRITE, (void *) arg, 
				sizeof(struct fb_fix_screeninfo));
		if (i)	return i;
		i=fb->fb_get_fix(&fix, PROC_CONSOLE());
		memcpy_tofs((void *) arg, &fix, sizeof(fix));
		return i;
	case FBIOPUTCMAP:
		i = verify_area(VERIFY_READ, (void *) arg,
				sizeof(struct fb_cmap));
		if (i) return i;
		memcpy_fromfs(&cmap, (void *) arg, sizeof(cmap));
		i = verify_area(VERIFY_READ, (void *) cmap.red, 
				cmap.len * sizeof(unsigned short));
		if (i) return i;
		i = verify_area(VERIFY_READ, (void *) cmap.green, 
				cmap.len * sizeof(unsigned short));
		if (i) return i;
		i = verify_area(VERIFY_READ, (void *) cmap.blue, 
				cmap.len * sizeof(unsigned short));
		if (i) return i;
		if (cmap.transp) {
			i = verify_area(VERIFY_READ, (void *) cmap.transp, 
					cmap.len * sizeof(unsigned short));
			if (i) return i;
		}
		return (fb->fb_set_cmap(&cmap, 0, PROC_CONSOLE()));
	case FBIOGETCMAP:
		i = verify_area(VERIFY_READ, (void *) arg,
				sizeof(struct fb_cmap));
		if (i)	return i;
		memcpy_fromfs(&cmap, (void *) arg, sizeof(cmap));
		i = verify_area(VERIFY_WRITE, (void *) cmap.red, 
				cmap.len * sizeof(unsigned short));
		if (i) return i;
		i = verify_area(VERIFY_WRITE, (void *) cmap.green, 
				cmap.len * sizeof(unsigned short));
		if (i) return i;
		i = verify_area(VERIFY_WRITE, (void *) cmap.blue, 
				cmap.len * sizeof(unsigned short));
		if (i) return i;
		if (cmap.transp) {
			i = verify_area(VERIFY_WRITE, (void *) cmap.transp, 
					cmap.len * sizeof(unsigned short));
			if (i) return i;
		}
		return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE()));
	case FBIOPAN_DISPLAY:
		i = verify_area(VERIFY_WRITE, (void *) arg, 
				sizeof(struct fb_var_screeninfo));
		if (i) return i;
		memcpy_fromfs(&var, (void *) arg, sizeof(var));
		i=fb->fb_pan_display(&var, PROC_CONSOLE());
		memcpy_tofs((void *) arg, &var, sizeof(var));
		fbidx=GET_FB_IDX(inode->i_rdev);
		vidx=GET_FB_VAR_IDX(inode->i_rdev);
		if (! i && vidx)
			registered_fb_var[fbidx][vidx-1]=var;
		return i;
	default:
		return (fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE()));
	}
}
//----------------------------------------------------------------------------- 
//
// Initialise the chip and the frame buffer driver. 
//
//----------------------------------------------------------------------------- 
int __init
rubyfb_init(void)
{
	int i; ///// TESTING
	int j; ///// TESTING
	
	fb_info.FrameBufferAddress = alloc_framebuffer();
	if (!fb_info.FrameBufferAddress) {
		printk
		    ("rubyfb_init: Failed to allocate memory for the framebuffer.\n");
		return -EINVAL;
	}
	// Clear the allocated memory
	memset(fb_info.FrameBufferAddress, 0, RUBY_PHYSICAL_MEM_SIZE);

	// Tell the lower levels what our addresses are
	ruby_set_addresses(fb_info.FrameBufferAddress,
			   fb_info.FrameBufferDmaAddress);

	ruby_init_display();


	strcpy(fb_info.gen.info.modename, "ruby");
	fb_info.gen.info.changevar = NULL;
	fb_info.gen.info.node = -1;
	fb_info.gen.info.fbops = &ruby_ops;
	fb_info.gen.info.disp = &disp;

	fb_info.gen.info.switch_con = &fbgen_switch;
	fb_info.gen.info.updatevar = &fbgen_update_var;
	fb_info.gen.info.blank = &fbgen_blank;

	strcpy(fb_info.gen.info.fontname, default_fontname);
	fb_info.gen.parsize = 0;
	fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
	fb_info.gen.fbhw = &ruby_hwswitch;
	fb_info.gen.fbhw->detect();

	fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
	disp.var.activate = FB_ACTIVATE_NOW;
	fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
	fbgen_set_disp(-1, &fb_info.gen);
	fbgen_install_cmap(0, &fb_info.gen);

	if (register_framebuffer(&fb_info.gen.info) < 0) {
		printk("Failed to register the %s framebuffer device.\n",
		       fb_info.gen.info.modename);
		free_framebuffer();
		return -EINVAL;
	}
	if (periodic_flush_enable) {
		init_timer(&fb_info.ruby_timer);
		fb_info.ruby_timer.function = ruby_flush;
		fb_info.ruby_timer.data = 0;
		fb_info.ruby_timer.expires = (unsigned long) jiffies + HZ + 100;
		add_timer(&fb_info.ruby_timer);
	}


/////////////////////////////
//////   Display Logo       //////
///////////////////////////

/////	ruby_display_logo();

	


	printk("fb%d: %s framebuffer device installed.\n",
	       GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename);

	printk("Display %s features %d x %d at %d bpp.\n",
	       fb_info.gen.info.modename,
	       RUBY_DISPLAY_WIDTH, RUBY_DISPLAY_HEIGHT, RUBY_DISPLAY_BPP);

	return 0;
}
static int __init
probe(int index)
{
	u32 *phys_reg_addr;
	struct xilinxfb_info *i;
	struct page *page, *end_page;

	switch (index) {
#if defined(CONFIG_XILINX_TFT_CNTLR_REF_0_INSTANCE)
	case 0:
		phys_reg_addr = 
			(u32 *) CONFIG_XILINX_TFT_CNTLR_REF_0_DCR_BASEADDR;
		break;
#if defined(CONFIG_XILINX_TFT_CNTRLR_REF_1_INSTANCE)
	case 1:
		phys_reg_addr = 
			(u32 *) CONFIG_XILINX_TFT_CNTLR_REF_1_DCR_BASEADDR;
		break;
#if defined(CONFIG_XILINX_TFT_CNTRLR_REF_2_INSTANCE)
	case 2:
		phys_reg_addr = 
			(u32 *) CONFIG_XILINX_TFT_CNTLR_REF_2_DCR_BASEADDR;
		break;
#if defined(CONFIG_XILINX_TFT_CNTLR_REF_3_INSTANCE)
#error Edit this file to add more devices.
#endif				/* 3 */
#endif				/* 2 */
#endif				/* 1 */
#endif				/* 0 */
	default:
		return -ENODEV;
	}

	/* Convert DCR register address to OPB address */
	phys_reg_addr = (unsigned *)(((unsigned)phys_reg_addr*4)+0xd0000000);

	/* Allocate the info and zero it out. */
	i = (struct xilinxfb_info *) kmalloc(sizeof (struct xilinxfb_info),
					     GFP_KERNEL);
	if (!i) {
		printk(KERN_ERR "Could not allocate Xilinx "
		       "frame buffer #%d information.\n", index);
		return -ENOMEM;
	}
	memset(i, 0, sizeof (struct xilinxfb_info));

	/* Make it the head of info_list. */
	spin_lock(&info_lock);
	i->next = info_list;
	info_list = i;
	spin_unlock(&info_lock);

	/*
	 * At this point, things are ok for us to call remove_head_info() to
	 * clean up if we run into any problems; i is on info_list and
	 * all the pointers are zeroed because of the memset above.
	 */

	i->fb_virt_start = (unsigned long) consistent_alloc(GFP_KERNEL|GFP_DMA,
							    FB_SIZE,
							    &i->fb_phys);
	if (!i->fb_virt_start) {
		printk(KERN_ERR "Could not allocate frame buffer memory "
		       "for Xilinx device #%d.\n", index);
		remove_head_info();
		return -ENOMEM;
	}

	/*
	 * The 2.4 PPC version of consistent_alloc does not set the
	 * pages reserved.  The pages need to be reserved so that mmap
	 * will work.  This means that we need the following code.  When
	 * consistent_alloc gets fixed, this will no longer be needed.
	 * Note that in 2.4, consistent_alloc doesn't free up the extra
	 * pages either.  This is already fixed in 2.5.
	 */
	page = virt_to_page(__va(i->fb_phys));
	end_page = page + ((FB_SIZE+PAGE_SIZE-1)/PAGE_SIZE);
	while (page < end_page)
		mem_map_reserve(page++);

	/* Clear the frame buffer. */
	memset((void *) i->fb_virt_start, 0, FB_SIZE);

	/* Map the control registers in. */
	i->regs = (u32 *) ioremap((unsigned long) phys_reg_addr, NUM_REGS);

	/* Tell the hardware where the frame buffer is. */
	out_be32(i->regs + REG_FB_ADDR, i->fb_phys);

	/* Turn on the display. */
	out_be32(i->regs + REG_CTRL, REG_CTRL_DEFAULT);

	current_par.var.xres = XRES;
	current_par.var.xres_virtual = XRES_VIRTUAL;
	current_par.var.yres = YRES;
	current_par.var.yres_virtual = YRES_VIRTUAL;
	current_par.var.bits_per_pixel = BITS_PER_PIXEL;

	i->gen.parsize = sizeof (struct xilinxfb_par);
	i->gen.fbhw = &xilinx_switch;

	strcpy(i->gen.info.modename, "Xilinx LCD");
	i->gen.info.changevar = NULL;
	i->gen.info.node = -1;

	i->gen.info.fbops = &xilinxfb_ops;
	i->gen.info.disp = &i->disp;
	i->gen.info.switch_con = &fbgen_switch;
	i->gen.info.updatevar = &fbgen_update_var;
	i->gen.info.blank = &fbgen_blank;
	i->gen.info.flags = FBINFO_FLAG_DEFAULT;

	/* This should give a reasonable default video mode */
	fbgen_get_var(&i->disp.var, -1, &i->gen.info);
	fbgen_do_set_var(&i->disp.var, 1, &i->gen);
	fbgen_set_disp(-1, &i->gen);
	fbgen_install_cmap(0, &i->gen);
	if (register_framebuffer(&i->gen.info) < 0) {
		printk(KERN_ERR "Could not register frame buffer "
		       "for Xilinx device #%d.\n", index);
		remove_head_info();
		return -EINVAL;
	}
	printk(KERN_INFO "fb%d: %s frame buffer at 0x%08X mapped to 0x%08lX\n",
	       GET_FB_IDX(i->gen.info.node), i->gen.info.modename,
	       i->fb_phys, i->fb_virt_start);

	return 0;
}