Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c7f439b9 authored by David S. Miller's avatar David S. Miller
Browse files

[VIDEO]: Fix OOPS in all SBUS framebuffer drivers.



All of these drivers use a silly:

struct all_info {
	struct fb_info info;
	struct foo_par par;
};

struct all_info *all = kzalloc(sizeof(*all), GFP_KERNEL);
all->info.par = &all->par;

etc. etc. code sequence, basically replicating the provided
framebuffer_alloc()/framebuffer_release(), and doing it badly.

Not only is this massive code duplication, it also caused a
bug in that we weren't setting the fb_info->device pointer
which results in an OOPS when fb_is_primary_device() runs.

Fix all of this by using framebuffer_{alloc,release}() and
passing in "&of_device->dev" as the device pointer.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a0afaa6a
Loading
Loading
Loading
Loading
+53 −52
Original line number Diff line number Diff line
@@ -279,90 +279,91 @@ static void __devinit bw2_do_default_mode(struct bw2_par *par,
	}
}

struct all_info {
	struct fb_info info;
	struct bw2_par par;
};

static int __devinit bw2_init_one(struct of_device *op)
static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match)
{
	struct device_node *dp = op->node;
	struct all_info *all;
	struct fb_info *info;
	struct bw2_par *par;
	int linebytes, err;

	all = kzalloc(sizeof(*all), GFP_KERNEL);
	if (!all)
		return -ENOMEM;
	info = framebuffer_alloc(sizeof(struct bw2_par), &op->dev);

	err = -ENOMEM;
	if (!info)
		goto out_err;
	par = info->par;

	spin_lock_init(&all->par.lock);
	spin_lock_init(&par->lock);

	all->par.physbase = op->resource[0].start;
	all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
	par->physbase = op->resource[0].start;
	par->which_io = op->resource[0].flags & IORESOURCE_BITS;

	sbusfb_fill_var(&all->info.var, dp->node, 1);
	sbusfb_fill_var(&info->var, dp->node, 1);
	linebytes = of_getintprop_default(dp, "linebytes",
					  all->info.var.xres);
					  info->var.xres);

	all->info.var.red.length = all->info.var.green.length =
		all->info.var.blue.length = all->info.var.bits_per_pixel;
	all->info.var.red.offset = all->info.var.green.offset =
		all->info.var.blue.offset = 0;
	info->var.red.length = info->var.green.length =
		info->var.blue.length = info->var.bits_per_pixel;
	info->var.red.offset = info->var.green.offset =
		info->var.blue.offset = 0;

	all->par.regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,
	par->regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,
			       sizeof(struct bw2_regs), "bw2 regs");
	if (!par->regs)
		goto out_release_fb;

	if (!of_find_property(dp, "width", NULL))
		bw2_do_default_mode(&all->par, &all->info, &linebytes);
		bw2_do_default_mode(par, info, &linebytes);

	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
	par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);

	all->info.flags = FBINFO_DEFAULT;
	all->info.fbops = &bw2_ops;
	info->flags = FBINFO_DEFAULT;
	info->fbops = &bw2_ops;

	all->info.screen_base =
		of_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram");
	all->info.par = &all->par;
	info->screen_base = of_ioremap(&op->resource[0], 0,
				       par->fbsize, "bw2 ram");
	if (!info->screen_base)
		goto out_unmap_regs;

	bw2_blank(0, &all->info);
	bw2_blank(0, info);

	bw2_init_fix(&all->info, linebytes);
	bw2_init_fix(info, linebytes);

	err= register_framebuffer(&all->info);
	if (err < 0) {
		of_iounmap(&op->resource[0],
			   all->par.regs, sizeof(struct bw2_regs));
		of_iounmap(&op->resource[0],
			   all->info.screen_base, all->par.fbsize);
		kfree(all);
		return err;
	}
	err = register_framebuffer(info);
	if (err < 0)
		goto out_unmap_screen;

	dev_set_drvdata(&op->dev, all);
	dev_set_drvdata(&op->dev, info);

	printk("%s: bwtwo at %lx:%lx\n",
	       dp->full_name,
	       all->par.which_io, all->par.physbase);
	       dp->full_name, par->which_io, par->physbase);

	return 0;
}

static int __devinit bw2_probe(struct of_device *dev, const struct of_device_id *match)
{
	struct of_device *op = to_of_device(&dev->dev);
out_unmap_screen:
	of_iounmap(&op->resource[0], info->screen_base, par->fbsize);

out_unmap_regs:
	of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));

	return bw2_init_one(op);
out_release_fb:
	framebuffer_release(info);

out_err:
	return err;
}

static int __devexit bw2_remove(struct of_device *op)
{
	struct all_info *all = dev_get_drvdata(&op->dev);
	struct fb_info *info = dev_get_drvdata(&op->dev);
	struct bw2_par *par = info->par;

	unregister_framebuffer(&all->info);
	unregister_framebuffer(info);

	of_iounmap(&op->resource[0], all->par.regs, sizeof(struct bw2_regs));
	of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize);
	of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
	of_iounmap(&op->resource[0], info->screen_base, par->fbsize);

	kfree(all);
	framebuffer_release(info);

	dev_set_drvdata(&op->dev, NULL);

+72 −78
Original line number Diff line number Diff line
@@ -448,81 +448,79 @@ static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __devinitdata = {
	{ .size = 0 }
};

struct all_info {
	struct fb_info info;
	struct cg14_par par;
};

static void cg14_unmap_regs(struct of_device *op, struct all_info *all)
static void cg14_unmap_regs(struct of_device *op, struct fb_info *info,
			    struct cg14_par *par)
{
	if (all->par.regs)
	if (par->regs)
		of_iounmap(&op->resource[0],
			   all->par.regs, sizeof(struct cg14_regs));
	if (all->par.clut)
			   par->regs, sizeof(struct cg14_regs));
	if (par->clut)
		of_iounmap(&op->resource[0],
			   all->par.clut, sizeof(struct cg14_clut));
	if (all->par.cursor)
			   par->clut, sizeof(struct cg14_clut));
	if (par->cursor)
		of_iounmap(&op->resource[0],
			   all->par.cursor, sizeof(struct cg14_cursor));
	if (all->info.screen_base)
			   par->cursor, sizeof(struct cg14_cursor));
	if (info->screen_base)
		of_iounmap(&op->resource[1],
			   all->info.screen_base, all->par.fbsize);
			   info->screen_base, par->fbsize);
}

static int __devinit cg14_init_one(struct of_device *op)
static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match)
{
	struct device_node *dp = op->node;
	struct all_info *all;
	struct fb_info *info;
	struct cg14_par *par;
	int is_8mb, linebytes, i, err;

	all = kzalloc(sizeof(*all), GFP_KERNEL);
	if (!all)
		return -ENOMEM;
	info = framebuffer_alloc(sizeof(struct cg14_par), &op->dev);

	err = -ENOMEM;
	if (!info)
		goto out_err;
	par = info->par;

	spin_lock_init(&all->par.lock);
	spin_lock_init(&par->lock);

	sbusfb_fill_var(&all->info.var, dp->node, 8);
	all->info.var.red.length = 8;
	all->info.var.green.length = 8;
	all->info.var.blue.length = 8;
	sbusfb_fill_var(&info->var, dp->node, 8);
	info->var.red.length = 8;
	info->var.green.length = 8;
	info->var.blue.length = 8;

	linebytes = of_getintprop_default(dp, "linebytes",
					  all->info.var.xres);
	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
					  info->var.xres);
	par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);

	if (!strcmp(dp->parent->name, "sbus") ||
	    !strcmp(dp->parent->name, "sbi")) {
		all->par.physbase = op->resource[0].start;
		all->par.iospace = op->resource[0].flags & IORESOURCE_BITS;
		par->physbase = op->resource[0].start;
		par->iospace = op->resource[0].flags & IORESOURCE_BITS;
	} else {
		all->par.physbase = op->resource[1].start;
		all->par.iospace = op->resource[0].flags & IORESOURCE_BITS;
		par->physbase = op->resource[1].start;
		par->iospace = op->resource[0].flags & IORESOURCE_BITS;
	}

	all->par.regs = of_ioremap(&op->resource[0], 0,
	par->regs = of_ioremap(&op->resource[0], 0,
			       sizeof(struct cg14_regs), "cg14 regs");
	all->par.clut = of_ioremap(&op->resource[0], CG14_CLUT1,
	par->clut = of_ioremap(&op->resource[0], CG14_CLUT1,
			       sizeof(struct cg14_clut), "cg14 clut");
	all->par.cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS,
	par->cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS,
				 sizeof(struct cg14_cursor), "cg14 cursor");

	all->info.screen_base = of_ioremap(&op->resource[1], 0,
					   all->par.fbsize, "cg14 ram");
	info->screen_base = of_ioremap(&op->resource[1], 0,
				       par->fbsize, "cg14 ram");

	if (!all->par.regs || !all->par.clut || !all->par.cursor ||
	    !all->info.screen_base)
		cg14_unmap_regs(op, all);
	if (!par->regs || !par->clut || !par->cursor || !info->screen_base)
		goto out_unmap_regs;

	is_8mb = (((op->resource[1].end - op->resource[1].start) + 1) ==
		  (8 * 1024 * 1024));

	BUILD_BUG_ON(sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map));
	BUILD_BUG_ON(sizeof(par->mmap_map) != sizeof(__cg14_mmap_map));
		
	memcpy(&all->par.mmap_map, &__cg14_mmap_map,
	       sizeof(all->par.mmap_map));
	memcpy(&par->mmap_map, &__cg14_mmap_map, sizeof(par->mmap_map));

	for (i = 0; i < CG14_MMAP_ENTRIES; i++) {
		struct sbus_mmap_map *map = &all->par.mmap_map[i];
		struct sbus_mmap_map *map = &par->mmap_map[i];

		if (!map->size)
			break;
@@ -536,59 +534,55 @@ static int __devinit cg14_init_one(struct of_device *op)
			map->size *= 2;
	}

	all->par.mode = MDI_8_PIX;
	all->par.ramsize = (is_8mb ? 0x800000 : 0x400000);
	par->mode = MDI_8_PIX;
	par->ramsize = (is_8mb ? 0x800000 : 0x400000);

	all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
	all->info.fbops = &cg14_ops;
	all->info.par = &all->par;
	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
	info->fbops = &cg14_ops;

	__cg14_reset(&all->par);
	__cg14_reset(par);

	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
		cg14_unmap_regs(op, all);
		kfree(all);
		return -ENOMEM;
	}
	fb_set_cmap(&all->info.cmap, &all->info);
	if (fb_alloc_cmap(&info->cmap, 256, 0))
		goto out_unmap_regs;

	cg14_init_fix(&all->info, linebytes, dp);
	fb_set_cmap(&info->cmap, info);

	err = register_framebuffer(&all->info);
	if (err < 0) {
		fb_dealloc_cmap(&all->info.cmap);
		cg14_unmap_regs(op, all);
		kfree(all);
		return err;
	}
	cg14_init_fix(info, linebytes, dp);

	err = register_framebuffer(info);
	if (err < 0)
		goto out_dealloc_cmap;

	dev_set_drvdata(&op->dev, all);
	dev_set_drvdata(&op->dev, info);

	printk("%s: cgfourteen at %lx:%lx, %dMB\n",
	       dp->full_name,
	       all->par.iospace, all->par.physbase,
	       all->par.ramsize >> 20);
	       par->iospace, par->physbase,
	       par->ramsize >> 20);

	return 0;
}

static int __devinit cg14_probe(struct of_device *dev, const struct of_device_id *match)
{
	struct of_device *op = to_of_device(&dev->dev);
out_dealloc_cmap:
	fb_dealloc_cmap(&info->cmap);

out_unmap_regs:
	cg14_unmap_regs(op, info, par);

	return cg14_init_one(op);
out_err:
	return err;
}

static int __devexit cg14_remove(struct of_device *op)
{
	struct all_info *all = dev_get_drvdata(&op->dev);
	struct fb_info *info = dev_get_drvdata(&op->dev);
	struct cg14_par *par = info->par;

	unregister_framebuffer(&all->info);
	fb_dealloc_cmap(&all->info.cmap);
	unregister_framebuffer(info);
	fb_dealloc_cmap(&info->cmap);

	cg14_unmap_regs(op, all);
	cg14_unmap_regs(op, info, par);

	kfree(all);
	framebuffer_release(info);

	dev_set_drvdata(&op->dev, NULL);

+67 −69
Original line number Diff line number Diff line
@@ -353,104 +353,102 @@ static void __devinit cg3_do_default_mode(struct cg3_par *par)
	}
}

struct all_info {
	struct fb_info info;
	struct cg3_par par;
};

static int __devinit cg3_init_one(struct of_device *op)
static int __devinit cg3_probe(struct of_device *op,
			       const struct of_device_id *match)
{
	struct device_node *dp = op->node;
	struct all_info *all;
	struct fb_info *info;
	struct cg3_par *par;
	int linebytes, err;

	all = kzalloc(sizeof(*all), GFP_KERNEL);
	if (!all)
		return -ENOMEM;
	info = framebuffer_alloc(sizeof(struct cg3_par), &op->dev);

	spin_lock_init(&all->par.lock);
	err = -ENOMEM;
	if (!info)
		goto out_err;
	par = info->par;

	all->par.physbase = op->resource[0].start;
	all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
	spin_lock_init(&par->lock);

	sbusfb_fill_var(&all->info.var, dp->node, 8);
	all->info.var.red.length = 8;
	all->info.var.green.length = 8;
	all->info.var.blue.length = 8;
	par->physbase = op->resource[0].start;
	par->which_io = op->resource[0].flags & IORESOURCE_BITS;

	sbusfb_fill_var(&info->var, dp->node, 8);
	info->var.red.length = 8;
	info->var.green.length = 8;
	info->var.blue.length = 8;
	if (!strcmp(dp->name, "cgRDI"))
		all->par.flags |= CG3_FLAG_RDI;
	if (all->par.flags & CG3_FLAG_RDI)
		cg3_rdi_maybe_fixup_var(&all->info.var, dp);
		par->flags |= CG3_FLAG_RDI;
	if (par->flags & CG3_FLAG_RDI)
		cg3_rdi_maybe_fixup_var(&info->var, dp);

	linebytes = of_getintprop_default(dp, "linebytes",
					  all->info.var.xres);
	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
					  info->var.xres);
	par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);

	all->par.regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,
	par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,
			       sizeof(struct cg3_regs), "cg3 regs");
	if (!par->regs)
		goto out_release_fb;

	all->info.flags = FBINFO_DEFAULT;
	all->info.fbops = &cg3_ops;
	all->info.screen_base =
		of_ioremap(&op->resource[0], CG3_RAM_OFFSET,
			   all->par.fbsize, "cg3 ram");
	all->info.par = &all->par;
	info->flags = FBINFO_DEFAULT;
	info->fbops = &cg3_ops;
	info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET,
				       par->fbsize, "cg3 ram");
	if (!info->screen_base)
		goto out_unmap_regs;

	cg3_blank(0, &all->info);
	cg3_blank(0, info);

	if (!of_find_property(dp, "width", NULL))
		cg3_do_default_mode(&all->par);

	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
		of_iounmap(&op->resource[0],
			   all->par.regs, sizeof(struct cg3_regs));
		of_iounmap(&op->resource[0],
			   all->info.screen_base, all->par.fbsize);
		kfree(all);
		return -ENOMEM;
	}
	fb_set_cmap(&all->info.cmap, &all->info);

	cg3_init_fix(&all->info, linebytes, dp);

	err = register_framebuffer(&all->info);
	if (err < 0) {
		fb_dealloc_cmap(&all->info.cmap);
		of_iounmap(&op->resource[0],
			   all->par.regs, sizeof(struct cg3_regs));
		of_iounmap(&op->resource[0],
			   all->info.screen_base, all->par.fbsize);
		kfree(all);
		return err;
	}
		cg3_do_default_mode(par);

	if (fb_alloc_cmap(&info->cmap, 256, 0))
		goto out_unmap_screen;

	fb_set_cmap(&info->cmap, info);

	dev_set_drvdata(&op->dev, all);
	cg3_init_fix(info, linebytes, dp);

	err = register_framebuffer(info);
	if (err < 0)
		goto out_dealloc_cmap;

	dev_set_drvdata(&op->dev, info);

	printk("%s: cg3 at %lx:%lx\n",
	       dp->full_name, all->par.which_io, all->par.physbase);
	       dp->full_name, par->which_io, par->physbase);

	return 0;
}

static int __devinit cg3_probe(struct of_device *dev,
			       const struct of_device_id *match)
{
	struct of_device *op = to_of_device(&dev->dev);
out_dealloc_cmap:
	fb_dealloc_cmap(&info->cmap);

	return cg3_init_one(op);
out_unmap_screen:
	of_iounmap(&op->resource[0], info->screen_base, par->fbsize);

out_unmap_regs:
	of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));

out_release_fb:
	framebuffer_release(info);

out_err:
	return err;
}

static int __devexit cg3_remove(struct of_device *op)
{
	struct all_info *all = dev_get_drvdata(&op->dev);
	struct fb_info *info = dev_get_drvdata(&op->dev);
	struct cg3_par *par = info->par;

	unregister_framebuffer(&all->info);
	fb_dealloc_cmap(&all->info.cmap);
	unregister_framebuffer(info);
	fb_dealloc_cmap(&info->cmap);

	of_iounmap(&op->resource[0], all->par.regs, sizeof(struct cg3_regs));
	of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize);
	of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
	of_iounmap(&op->resource[0], info->screen_base, par->fbsize);

	kfree(all);
	framebuffer_release(info);

	dev_set_drvdata(&op->dev, NULL);

+73 −88
Original line number Diff line number Diff line
@@ -653,135 +653,120 @@ static void cg6_chip_init(struct fb_info *info)
	sbus_writel(info->var.yres - 1, &fbc->clipmaxy);
}

struct all_info {
	struct fb_info info;
	struct cg6_par par;
};

static void cg6_unmap_regs(struct of_device *op, struct all_info *all)
static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
			   struct cg6_par *par)
{
	if (all->par.fbc)
		of_iounmap(&op->resource[0], all->par.fbc, 4096);
	if (all->par.tec)
		of_iounmap(&op->resource[0],
			   all->par.tec, sizeof(struct cg6_tec));
	if (all->par.thc)
		of_iounmap(&op->resource[0],
			   all->par.thc, sizeof(struct cg6_thc));
	if (all->par.bt)
		of_iounmap(&op->resource[0],
			   all->par.bt, sizeof(struct bt_regs));
	if (all->par.fhc)
		of_iounmap(&op->resource[0],
			   all->par.fhc, sizeof(u32));

	if (all->info.screen_base)
		of_iounmap(&op->resource[0],
			   all->info.screen_base, all->par.fbsize);
	if (par->fbc)
		of_iounmap(&op->resource[0], par->fbc, 4096);
	if (par->tec)
		of_iounmap(&op->resource[0], par->tec, sizeof(struct cg6_tec));
	if (par->thc)
		of_iounmap(&op->resource[0], par->thc, sizeof(struct cg6_thc));
	if (par->bt)
		of_iounmap(&op->resource[0], par->bt, sizeof(struct bt_regs));
	if (par->fhc)
		of_iounmap(&op->resource[0], par->fhc, sizeof(u32));

	if (info->screen_base)
		of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
}

static int __devinit cg6_init_one(struct of_device *op)
static int __devinit cg6_probe(struct of_device *op, const struct of_device_id *match)
{
	struct device_node *dp = op->node;
	struct all_info *all;
	struct fb_info *info;
	struct cg6_par *par;
	int linebytes, err;

	all = kzalloc(sizeof(*all), GFP_KERNEL);
	if (!all)
		return -ENOMEM;
	info = framebuffer_alloc(sizeof(struct cg6_par), &op->dev);

	err = -ENOMEM;
	if (!info)
		goto out_err;
	par = info->par;

	spin_lock_init(&all->par.lock);
	spin_lock_init(&par->lock);

	all->par.physbase = op->resource[0].start;
	all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
	par->physbase = op->resource[0].start;
	par->which_io = op->resource[0].flags & IORESOURCE_BITS;

	sbusfb_fill_var(&all->info.var, dp->node, 8);
	all->info.var.red.length = 8;
	all->info.var.green.length = 8;
	all->info.var.blue.length = 8;
	sbusfb_fill_var(&info->var, dp->node, 8);
	info->var.red.length = 8;
	info->var.green.length = 8;
	info->var.blue.length = 8;

	linebytes = of_getintprop_default(dp, "linebytes",
					  all->info.var.xres);
	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
					  info->var.xres);
	par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
	if (of_find_property(dp, "dblbuf", NULL))
		all->par.fbsize *= 4;
		par->fbsize *= 4;

	all->par.fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
	par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
				  4096, "cgsix fbc");
	all->par.tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET,
	par->tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET,
				  sizeof(struct cg6_tec), "cgsix tec");
	all->par.thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET,
	par->thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET,
				  sizeof(struct cg6_thc), "cgsix thc");
	all->par.bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET,
	par->bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET,
				 sizeof(struct bt_regs), "cgsix dac");
	all->par.fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET,
	par->fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET,
				  sizeof(u32), "cgsix fhc");

	all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
                          FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
	all->info.fbops = &cg6_ops;

	all->info.screen_base =  of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
					    all->par.fbsize, "cgsix ram");
	if (!all->par.fbc || !all->par.tec || !all->par.thc ||
	    !all->par.bt || !all->par.fhc || !all->info.screen_base) {
		cg6_unmap_regs(op, all);
		kfree(all);
		return -ENOMEM;
	}
	info->fbops = &cg6_ops;

	all->info.par = &all->par;
	info->screen_base =  of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
					    par->fbsize, "cgsix ram");
	if (!par->fbc || !par->tec || !par->thc ||
	    !par->bt || !par->fhc || !info->screen_base)
		goto out_unmap_regs;

	all->info.var.accel_flags = FB_ACCELF_TEXT;
	info->var.accel_flags = FB_ACCELF_TEXT;

	cg6_bt_init(&all->par);
	cg6_chip_init(&all->info);
	cg6_blank(0, &all->info);
	cg6_bt_init(par);
	cg6_chip_init(info);
	cg6_blank(0, info);

	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
		cg6_unmap_regs(op, all);
		kfree(all);
		return -ENOMEM;
	}
	if (fb_alloc_cmap(&info->cmap, 256, 0))
		goto out_unmap_regs;

	fb_set_cmap(&all->info.cmap, &all->info);
	cg6_init_fix(&all->info, linebytes);
	fb_set_cmap(&info->cmap, info);
	cg6_init_fix(info, linebytes);

	err = register_framebuffer(&all->info);
	if (err < 0) {
		cg6_unmap_regs(op, all);
		fb_dealloc_cmap(&all->info.cmap);
		kfree(all);
		return err;
	}
	err = register_framebuffer(info);
	if (err < 0)
		goto out_dealloc_cmap;

	dev_set_drvdata(&op->dev, all);
	dev_set_drvdata(&op->dev, info);

	printk("%s: CGsix [%s] at %lx:%lx\n",
	       dp->full_name,
	       all->info.fix.id,
	       all->par.which_io, all->par.physbase);
	       dp->full_name, info->fix.id,
	       par->which_io, par->physbase);

	return 0;
}

static int __devinit cg6_probe(struct of_device *dev, const struct of_device_id *match)
{
	struct of_device *op = to_of_device(&dev->dev);
out_dealloc_cmap:
	fb_dealloc_cmap(&info->cmap);

	return cg6_init_one(op);
out_unmap_regs:
	cg6_unmap_regs(op, info, par);

out_err:
	return err;
}

static int __devexit cg6_remove(struct of_device *op)
{
	struct all_info *all = dev_get_drvdata(&op->dev);
	struct fb_info *info = dev_get_drvdata(&op->dev);
	struct cg6_par *par = info->par;

	unregister_framebuffer(&all->info);
	fb_dealloc_cmap(&all->info.cmap);
	unregister_framebuffer(info);
	fb_dealloc_cmap(&info->cmap);

	cg6_unmap_regs(op, all);
	cg6_unmap_regs(op, info, par);

	kfree(all);
	framebuffer_release(info);

	dev_set_drvdata(&op->dev, NULL);

+79 −91

File changed.

Preview size limit exceeded, changes collapsed.

Loading