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/leo.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/leo.c')
-rw-r--r-- | drivers/video/leo.c | 147 |
1 files changed, 70 insertions, 77 deletions
diff --git a/drivers/video/leo.c b/drivers/video/leo.c index a038aa5a9e1c..45b9a5d55dec 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c | |||
@@ -525,130 +525,123 @@ static void leo_fixup_var_rgb(struct fb_var_screeninfo *var) | |||
525 | var->transp.length = 0; | 525 | var->transp.length = 0; |
526 | } | 526 | } |
527 | 527 | ||
528 | struct all_info { | 528 | static void leo_unmap_regs(struct of_device *op, struct fb_info *info, |
529 | struct fb_info info; | 529 | struct leo_par *par) |
530 | struct leo_par par; | ||
531 | }; | ||
532 | |||
533 | static void leo_unmap_regs(struct of_device *op, struct all_info *all) | ||
534 | { | 530 | { |
535 | if (all->par.lc_ss0_usr) | 531 | if (par->lc_ss0_usr) |
536 | of_iounmap(&op->resource[0], all->par.lc_ss0_usr, 0x1000); | 532 | of_iounmap(&op->resource[0], par->lc_ss0_usr, 0x1000); |
537 | if (all->par.ld_ss0) | 533 | if (par->ld_ss0) |
538 | of_iounmap(&op->resource[0], all->par.ld_ss0, 0x1000); | 534 | of_iounmap(&op->resource[0], par->ld_ss0, 0x1000); |
539 | if (all->par.ld_ss1) | 535 | if (par->ld_ss1) |
540 | of_iounmap(&op->resource[0], all->par.ld_ss1, 0x1000); | 536 | of_iounmap(&op->resource[0], par->ld_ss1, 0x1000); |
541 | if (all->par.lx_krn) | 537 | if (par->lx_krn) |
542 | of_iounmap(&op->resource[0], all->par.lx_krn, 0x1000); | 538 | of_iounmap(&op->resource[0], par->lx_krn, 0x1000); |
543 | if (all->par.cursor) | 539 | if (par->cursor) |
544 | of_iounmap(&op->resource[0], | 540 | of_iounmap(&op->resource[0], |
545 | all->par.cursor, sizeof(struct leo_cursor)); | 541 | par->cursor, sizeof(struct leo_cursor)); |
546 | if (all->info.screen_base) | 542 | if (info->screen_base) |
547 | of_iounmap(&op->resource[0], all->info.screen_base, 0x800000); | 543 | of_iounmap(&op->resource[0], info->screen_base, 0x800000); |
548 | } | 544 | } |
549 | 545 | ||
550 | static int __devinit leo_init_one(struct of_device *op) | 546 | static int __devinit leo_probe(struct of_device *op, const struct of_device_id *match) |
551 | { | 547 | { |
552 | struct device_node *dp = op->node; | 548 | struct device_node *dp = op->node; |
553 | struct all_info *all; | 549 | struct fb_info *info; |
550 | struct leo_par *par; | ||
554 | int linebytes, err; | 551 | int linebytes, err; |
555 | 552 | ||
556 | all = kzalloc(sizeof(*all), GFP_KERNEL); | 553 | info = framebuffer_alloc(sizeof(struct leo_par), &op->dev); |
557 | if (!all) | 554 | |
558 | return -ENOMEM; | 555 | err = -ENOMEM; |
556 | if (!info) | ||
557 | goto out_err; | ||
558 | par = info->par; | ||
559 | 559 | ||
560 | spin_lock_init(&all->par.lock); | 560 | spin_lock_init(&par->lock); |
561 | 561 | ||
562 | all->par.physbase = op->resource[0].start; | 562 | par->physbase = op->resource[0].start; |
563 | all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; | 563 | par->which_io = op->resource[0].flags & IORESOURCE_BITS; |
564 | 564 | ||
565 | sbusfb_fill_var(&all->info.var, dp->node, 32); | 565 | sbusfb_fill_var(&info->var, dp->node, 32); |
566 | leo_fixup_var_rgb(&all->info.var); | 566 | leo_fixup_var_rgb(&info->var); |
567 | 567 | ||
568 | linebytes = of_getintprop_default(dp, "linebytes", | 568 | linebytes = of_getintprop_default(dp, "linebytes", |
569 | all->info.var.xres); | 569 | info->var.xres); |
570 | all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); | 570 | par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); |
571 | 571 | ||
572 | all->par.lc_ss0_usr = | 572 | par->lc_ss0_usr = |
573 | of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR, | 573 | of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR, |
574 | 0x1000, "leolc ss0usr"); | 574 | 0x1000, "leolc ss0usr"); |
575 | all->par.ld_ss0 = | 575 | par->ld_ss0 = |
576 | of_ioremap(&op->resource[0], LEO_OFF_LD_SS0, | 576 | of_ioremap(&op->resource[0], LEO_OFF_LD_SS0, |
577 | 0x1000, "leold ss0"); | 577 | 0x1000, "leold ss0"); |
578 | all->par.ld_ss1 = | 578 | par->ld_ss1 = |
579 | of_ioremap(&op->resource[0], LEO_OFF_LD_SS1, | 579 | of_ioremap(&op->resource[0], LEO_OFF_LD_SS1, |
580 | 0x1000, "leold ss1"); | 580 | 0x1000, "leold ss1"); |
581 | all->par.lx_krn = | 581 | par->lx_krn = |
582 | of_ioremap(&op->resource[0], LEO_OFF_LX_KRN, | 582 | of_ioremap(&op->resource[0], LEO_OFF_LX_KRN, |
583 | 0x1000, "leolx krn"); | 583 | 0x1000, "leolx krn"); |
584 | all->par.cursor = | 584 | par->cursor = |
585 | of_ioremap(&op->resource[0], LEO_OFF_LX_CURSOR, | 585 | of_ioremap(&op->resource[0], LEO_OFF_LX_CURSOR, |
586 | sizeof(struct leo_cursor), "leolx cursor"); | 586 | sizeof(struct leo_cursor), "leolx cursor"); |
587 | all->info.screen_base = | 587 | info->screen_base = |
588 | of_ioremap(&op->resource[0], LEO_OFF_SS0, | 588 | of_ioremap(&op->resource[0], LEO_OFF_SS0, |
589 | 0x800000, "leo ram"); | 589 | 0x800000, "leo ram"); |
590 | if (!all->par.lc_ss0_usr || | 590 | if (!par->lc_ss0_usr || |
591 | !all->par.ld_ss0 || | 591 | !par->ld_ss0 || |
592 | !all->par.ld_ss1 || | 592 | !par->ld_ss1 || |
593 | !all->par.lx_krn || | 593 | !par->lx_krn || |
594 | !all->par.cursor || | 594 | !par->cursor || |
595 | !all->info.screen_base) { | 595 | !info->screen_base) |
596 | leo_unmap_regs(op, all); | 596 | goto out_unmap_regs; |
597 | kfree(all); | ||
598 | return -ENOMEM; | ||
599 | } | ||
600 | 597 | ||
601 | all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; | 598 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; |
602 | all->info.fbops = &leo_ops; | 599 | info->fbops = &leo_ops; |
603 | all->info.par = &all->par; | ||
604 | 600 | ||
605 | leo_init_wids(&all->info); | 601 | leo_init_wids(info); |
606 | leo_init_hw(&all->info); | 602 | leo_init_hw(info); |
607 | 603 | ||
608 | leo_blank(0, &all->info); | 604 | leo_blank(0, info); |
609 | 605 | ||
610 | if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { | 606 | if (fb_alloc_cmap(&info->cmap, 256, 0)) |
611 | leo_unmap_regs(op, all); | 607 | goto out_unmap_regs; |
612 | kfree(all); | ||
613 | return -ENOMEM;; | ||
614 | } | ||
615 | 608 | ||
616 | leo_init_fix(&all->info, dp); | 609 | leo_init_fix(info, dp); |
617 | 610 | ||
618 | err = register_framebuffer(&all->info); | 611 | err = register_framebuffer(info); |
619 | if (err < 0) { | 612 | if (err < 0) |
620 | fb_dealloc_cmap(&all->info.cmap); | 613 | goto out_dealloc_cmap; |
621 | leo_unmap_regs(op, all); | ||
622 | kfree(all); | ||
623 | return err; | ||
624 | } | ||
625 | 614 | ||
626 | dev_set_drvdata(&op->dev, all); | 615 | dev_set_drvdata(&op->dev, info); |
627 | 616 | ||
628 | printk("%s: leo at %lx:%lx\n", | 617 | printk("%s: leo at %lx:%lx\n", |
629 | dp->full_name, | 618 | dp->full_name, |
630 | all->par.which_io, all->par.physbase); | 619 | par->which_io, par->physbase); |
631 | 620 | ||
632 | return 0; | 621 | return 0; |
633 | } | ||
634 | 622 | ||
635 | static int __devinit leo_probe(struct of_device *dev, const struct of_device_id *match) | 623 | out_dealloc_cmap: |
636 | { | 624 | fb_dealloc_cmap(&info->cmap); |
637 | struct of_device *op = to_of_device(&dev->dev); | 625 | |
626 | out_unmap_regs: | ||
627 | leo_unmap_regs(op, info, par); | ||
628 | framebuffer_release(info); | ||
638 | 629 | ||
639 | return leo_init_one(op); | 630 | out_err: |
631 | return err; | ||
640 | } | 632 | } |
641 | 633 | ||
642 | static int __devexit leo_remove(struct of_device *op) | 634 | static int __devexit leo_remove(struct of_device *op) |
643 | { | 635 | { |
644 | struct all_info *all = dev_get_drvdata(&op->dev); | 636 | struct fb_info *info = dev_get_drvdata(&op->dev); |
637 | struct leo_par *par = info->par; | ||
645 | 638 | ||
646 | unregister_framebuffer(&all->info); | 639 | unregister_framebuffer(info); |
647 | fb_dealloc_cmap(&all->info.cmap); | 640 | fb_dealloc_cmap(&info->cmap); |
648 | 641 | ||
649 | leo_unmap_regs(op, all); | 642 | leo_unmap_regs(op, info, par); |
650 | 643 | ||
651 | kfree(all); | 644 | framebuffer_release(info); |
652 | 645 | ||
653 | dev_set_drvdata(&op->dev, NULL); | 646 | dev_set_drvdata(&op->dev, NULL); |
654 | 647 | ||