diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-07-28 01:31:46 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-30 03:27:33 -0400 |
commit | c7f439b99efbea74c70a5531f92566db5a6731f2 (patch) | |
tree | 7053ceffa23d54670862e14d0bc2eec9d5d42427 /drivers/video/bw2.c | |
parent | a0afaa6ab12cf696d170c22a8fdfd88c3e33555c (diff) |
[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: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/video/bw2.c')
-rw-r--r-- | drivers/video/bw2.c | 105 |
1 files changed, 53 insertions, 52 deletions
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index b0b2e40bbd9f..718b9f83736e 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c | |||
@@ -279,90 +279,91 @@ static void __devinit bw2_do_default_mode(struct bw2_par *par, | |||
279 | } | 279 | } |
280 | } | 280 | } |
281 | 281 | ||
282 | struct all_info { | 282 | static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match) |
283 | struct fb_info info; | ||
284 | struct bw2_par par; | ||
285 | }; | ||
286 | |||
287 | static int __devinit bw2_init_one(struct of_device *op) | ||
288 | { | 283 | { |
289 | struct device_node *dp = op->node; | 284 | struct device_node *dp = op->node; |
290 | struct all_info *all; | 285 | struct fb_info *info; |
286 | struct bw2_par *par; | ||
291 | int linebytes, err; | 287 | int linebytes, err; |
292 | 288 | ||
293 | all = kzalloc(sizeof(*all), GFP_KERNEL); | 289 | info = framebuffer_alloc(sizeof(struct bw2_par), &op->dev); |
294 | if (!all) | ||
295 | return -ENOMEM; | ||
296 | 290 | ||
297 | spin_lock_init(&all->par.lock); | 291 | err = -ENOMEM; |
292 | if (!info) | ||
293 | goto out_err; | ||
294 | par = info->par; | ||
298 | 295 | ||
299 | all->par.physbase = op->resource[0].start; | 296 | spin_lock_init(&par->lock); |
300 | all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; | ||
301 | 297 | ||
302 | sbusfb_fill_var(&all->info.var, dp->node, 1); | 298 | par->physbase = op->resource[0].start; |
299 | par->which_io = op->resource[0].flags & IORESOURCE_BITS; | ||
300 | |||
301 | sbusfb_fill_var(&info->var, dp->node, 1); | ||
303 | linebytes = of_getintprop_default(dp, "linebytes", | 302 | linebytes = of_getintprop_default(dp, "linebytes", |
304 | all->info.var.xres); | 303 | info->var.xres); |
305 | 304 | ||
306 | all->info.var.red.length = all->info.var.green.length = | 305 | info->var.red.length = info->var.green.length = |
307 | all->info.var.blue.length = all->info.var.bits_per_pixel; | 306 | info->var.blue.length = info->var.bits_per_pixel; |
308 | all->info.var.red.offset = all->info.var.green.offset = | 307 | info->var.red.offset = info->var.green.offset = |
309 | all->info.var.blue.offset = 0; | 308 | info->var.blue.offset = 0; |
310 | 309 | ||
311 | all->par.regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET, | 310 | par->regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET, |
312 | sizeof(struct bw2_regs), "bw2 regs"); | 311 | sizeof(struct bw2_regs), "bw2 regs"); |
312 | if (!par->regs) | ||
313 | goto out_release_fb; | ||
313 | 314 | ||
314 | if (!of_find_property(dp, "width", NULL)) | 315 | if (!of_find_property(dp, "width", NULL)) |
315 | bw2_do_default_mode(&all->par, &all->info, &linebytes); | 316 | bw2_do_default_mode(par, info, &linebytes); |
316 | 317 | ||
317 | all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); | 318 | par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); |
318 | 319 | ||
319 | all->info.flags = FBINFO_DEFAULT; | 320 | info->flags = FBINFO_DEFAULT; |
320 | all->info.fbops = &bw2_ops; | 321 | info->fbops = &bw2_ops; |
321 | 322 | ||
322 | all->info.screen_base = | 323 | info->screen_base = of_ioremap(&op->resource[0], 0, |
323 | of_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram"); | 324 | par->fbsize, "bw2 ram"); |
324 | all->info.par = &all->par; | 325 | if (!info->screen_base) |
326 | goto out_unmap_regs; | ||
325 | 327 | ||
326 | bw2_blank(0, &all->info); | 328 | bw2_blank(0, info); |
327 | 329 | ||
328 | bw2_init_fix(&all->info, linebytes); | 330 | bw2_init_fix(info, linebytes); |
329 | 331 | ||
330 | err= register_framebuffer(&all->info); | 332 | err = register_framebuffer(info); |
331 | if (err < 0) { | 333 | if (err < 0) |
332 | of_iounmap(&op->resource[0], | 334 | goto out_unmap_screen; |
333 | all->par.regs, sizeof(struct bw2_regs)); | ||
334 | of_iounmap(&op->resource[0], | ||
335 | all->info.screen_base, all->par.fbsize); | ||
336 | kfree(all); | ||
337 | return err; | ||
338 | } | ||
339 | 335 | ||
340 | dev_set_drvdata(&op->dev, all); | 336 | dev_set_drvdata(&op->dev, info); |
341 | 337 | ||
342 | printk("%s: bwtwo at %lx:%lx\n", | 338 | printk("%s: bwtwo at %lx:%lx\n", |
343 | dp->full_name, | 339 | dp->full_name, par->which_io, par->physbase); |
344 | all->par.which_io, all->par.physbase); | ||
345 | 340 | ||
346 | return 0; | 341 | return 0; |
347 | } | ||
348 | 342 | ||
349 | static int __devinit bw2_probe(struct of_device *dev, const struct of_device_id *match) | 343 | out_unmap_screen: |
350 | { | 344 | of_iounmap(&op->resource[0], info->screen_base, par->fbsize); |
351 | struct of_device *op = to_of_device(&dev->dev); | 345 | |
346 | out_unmap_regs: | ||
347 | of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); | ||
348 | |||
349 | out_release_fb: | ||
350 | framebuffer_release(info); | ||
352 | 351 | ||
353 | return bw2_init_one(op); | 352 | out_err: |
353 | return err; | ||
354 | } | 354 | } |
355 | 355 | ||
356 | static int __devexit bw2_remove(struct of_device *op) | 356 | static int __devexit bw2_remove(struct of_device *op) |
357 | { | 357 | { |
358 | struct all_info *all = dev_get_drvdata(&op->dev); | 358 | struct fb_info *info = dev_get_drvdata(&op->dev); |
359 | struct bw2_par *par = info->par; | ||
359 | 360 | ||
360 | unregister_framebuffer(&all->info); | 361 | unregister_framebuffer(info); |
361 | 362 | ||
362 | of_iounmap(&op->resource[0], all->par.regs, sizeof(struct bw2_regs)); | 363 | of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); |
363 | of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize); | 364 | of_iounmap(&op->resource[0], info->screen_base, par->fbsize); |
364 | 365 | ||
365 | kfree(all); | 366 | framebuffer_release(info); |
366 | 367 | ||
367 | dev_set_drvdata(&op->dev, NULL); | 368 | dev_set_drvdata(&op->dev, NULL); |
368 | 369 | ||