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/cg3.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/cg3.c')
-rw-r--r-- | drivers/video/cg3.c | 136 |
1 files changed, 67 insertions, 69 deletions
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index f042428a84f4..5741b46ade1b 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c | |||
@@ -353,104 +353,102 @@ static void __devinit cg3_do_default_mode(struct cg3_par *par) | |||
353 | } | 353 | } |
354 | } | 354 | } |
355 | 355 | ||
356 | struct all_info { | 356 | static int __devinit cg3_probe(struct of_device *op, |
357 | struct fb_info info; | 357 | const struct of_device_id *match) |
358 | struct cg3_par par; | ||
359 | }; | ||
360 | |||
361 | static int __devinit cg3_init_one(struct of_device *op) | ||
362 | { | 358 | { |
363 | struct device_node *dp = op->node; | 359 | struct device_node *dp = op->node; |
364 | struct all_info *all; | 360 | struct fb_info *info; |
361 | struct cg3_par *par; | ||
365 | int linebytes, err; | 362 | int linebytes, err; |
366 | 363 | ||
367 | all = kzalloc(sizeof(*all), GFP_KERNEL); | 364 | info = framebuffer_alloc(sizeof(struct cg3_par), &op->dev); |
368 | if (!all) | ||
369 | return -ENOMEM; | ||
370 | 365 | ||
371 | spin_lock_init(&all->par.lock); | 366 | err = -ENOMEM; |
367 | if (!info) | ||
368 | goto out_err; | ||
369 | par = info->par; | ||
372 | 370 | ||
373 | all->par.physbase = op->resource[0].start; | 371 | spin_lock_init(&par->lock); |
374 | all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; | ||
375 | 372 | ||
376 | sbusfb_fill_var(&all->info.var, dp->node, 8); | 373 | par->physbase = op->resource[0].start; |
377 | all->info.var.red.length = 8; | 374 | par->which_io = op->resource[0].flags & IORESOURCE_BITS; |
378 | all->info.var.green.length = 8; | 375 | |
379 | all->info.var.blue.length = 8; | 376 | sbusfb_fill_var(&info->var, dp->node, 8); |
377 | info->var.red.length = 8; | ||
378 | info->var.green.length = 8; | ||
379 | info->var.blue.length = 8; | ||
380 | if (!strcmp(dp->name, "cgRDI")) | 380 | if (!strcmp(dp->name, "cgRDI")) |
381 | all->par.flags |= CG3_FLAG_RDI; | 381 | par->flags |= CG3_FLAG_RDI; |
382 | if (all->par.flags & CG3_FLAG_RDI) | 382 | if (par->flags & CG3_FLAG_RDI) |
383 | cg3_rdi_maybe_fixup_var(&all->info.var, dp); | 383 | cg3_rdi_maybe_fixup_var(&info->var, dp); |
384 | 384 | ||
385 | linebytes = of_getintprop_default(dp, "linebytes", | 385 | linebytes = of_getintprop_default(dp, "linebytes", |
386 | all->info.var.xres); | 386 | info->var.xres); |
387 | all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); | 387 | par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); |
388 | 388 | ||
389 | all->par.regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET, | 389 | par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET, |
390 | sizeof(struct cg3_regs), "cg3 regs"); | 390 | sizeof(struct cg3_regs), "cg3 regs"); |
391 | if (!par->regs) | ||
392 | goto out_release_fb; | ||
391 | 393 | ||
392 | all->info.flags = FBINFO_DEFAULT; | 394 | info->flags = FBINFO_DEFAULT; |
393 | all->info.fbops = &cg3_ops; | 395 | info->fbops = &cg3_ops; |
394 | all->info.screen_base = | 396 | info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET, |
395 | of_ioremap(&op->resource[0], CG3_RAM_OFFSET, | 397 | par->fbsize, "cg3 ram"); |
396 | all->par.fbsize, "cg3 ram"); | 398 | if (!info->screen_base) |
397 | all->info.par = &all->par; | 399 | goto out_unmap_regs; |
398 | 400 | ||
399 | cg3_blank(0, &all->info); | 401 | cg3_blank(0, info); |
400 | 402 | ||
401 | if (!of_find_property(dp, "width", NULL)) | 403 | if (!of_find_property(dp, "width", NULL)) |
402 | cg3_do_default_mode(&all->par); | 404 | cg3_do_default_mode(par); |
403 | 405 | ||
404 | if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { | 406 | if (fb_alloc_cmap(&info->cmap, 256, 0)) |
405 | of_iounmap(&op->resource[0], | 407 | goto out_unmap_screen; |
406 | all->par.regs, sizeof(struct cg3_regs)); | 408 | |
407 | of_iounmap(&op->resource[0], | 409 | fb_set_cmap(&info->cmap, info); |
408 | all->info.screen_base, all->par.fbsize); | ||
409 | kfree(all); | ||
410 | return -ENOMEM; | ||
411 | } | ||
412 | fb_set_cmap(&all->info.cmap, &all->info); | ||
413 | |||
414 | cg3_init_fix(&all->info, linebytes, dp); | ||
415 | |||
416 | err = register_framebuffer(&all->info); | ||
417 | if (err < 0) { | ||
418 | fb_dealloc_cmap(&all->info.cmap); | ||
419 | of_iounmap(&op->resource[0], | ||
420 | all->par.regs, sizeof(struct cg3_regs)); | ||
421 | of_iounmap(&op->resource[0], | ||
422 | all->info.screen_base, all->par.fbsize); | ||
423 | kfree(all); | ||
424 | return err; | ||
425 | } | ||
426 | 410 | ||
427 | dev_set_drvdata(&op->dev, all); | 411 | cg3_init_fix(info, linebytes, dp); |
412 | |||
413 | err = register_framebuffer(info); | ||
414 | if (err < 0) | ||
415 | goto out_dealloc_cmap; | ||
416 | |||
417 | dev_set_drvdata(&op->dev, info); | ||
428 | 418 | ||
429 | printk("%s: cg3 at %lx:%lx\n", | 419 | printk("%s: cg3 at %lx:%lx\n", |
430 | dp->full_name, all->par.which_io, all->par.physbase); | 420 | dp->full_name, par->which_io, par->physbase); |
431 | 421 | ||
432 | return 0; | 422 | return 0; |
433 | } | ||
434 | 423 | ||
435 | static int __devinit cg3_probe(struct of_device *dev, | 424 | out_dealloc_cmap: |
436 | const struct of_device_id *match) | 425 | fb_dealloc_cmap(&info->cmap); |
437 | { | 426 | |
438 | struct of_device *op = to_of_device(&dev->dev); | 427 | out_unmap_screen: |
428 | of_iounmap(&op->resource[0], info->screen_base, par->fbsize); | ||
429 | |||
430 | out_unmap_regs: | ||
431 | of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); | ||
432 | |||
433 | out_release_fb: | ||
434 | framebuffer_release(info); | ||
439 | 435 | ||
440 | return cg3_init_one(op); | 436 | out_err: |
437 | return err; | ||
441 | } | 438 | } |
442 | 439 | ||
443 | static int __devexit cg3_remove(struct of_device *op) | 440 | static int __devexit cg3_remove(struct of_device *op) |
444 | { | 441 | { |
445 | struct all_info *all = dev_get_drvdata(&op->dev); | 442 | struct fb_info *info = dev_get_drvdata(&op->dev); |
443 | struct cg3_par *par = info->par; | ||
446 | 444 | ||
447 | unregister_framebuffer(&all->info); | 445 | unregister_framebuffer(info); |
448 | fb_dealloc_cmap(&all->info.cmap); | 446 | fb_dealloc_cmap(&info->cmap); |
449 | 447 | ||
450 | of_iounmap(&op->resource[0], all->par.regs, sizeof(struct cg3_regs)); | 448 | of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); |
451 | of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize); | 449 | of_iounmap(&op->resource[0], info->screen_base, par->fbsize); |
452 | 450 | ||
453 | kfree(all); | 451 | framebuffer_release(info); |
454 | 452 | ||
455 | dev_set_drvdata(&op->dev, NULL); | 453 | dev_set_drvdata(&op->dev, NULL); |
456 | 454 | ||