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/cg14.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/cg14.c')
-rw-r--r-- | drivers/video/cg14.c | 150 |
1 files changed, 72 insertions, 78 deletions
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index b071bb632b97..41f6dbf61be7 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c | |||
@@ -448,81 +448,79 @@ static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __devinitdata = { | |||
448 | { .size = 0 } | 448 | { .size = 0 } |
449 | }; | 449 | }; |
450 | 450 | ||
451 | struct all_info { | 451 | static void cg14_unmap_regs(struct of_device *op, struct fb_info *info, |
452 | struct fb_info info; | 452 | struct cg14_par *par) |
453 | struct cg14_par par; | ||
454 | }; | ||
455 | |||
456 | static void cg14_unmap_regs(struct of_device *op, struct all_info *all) | ||
457 | { | 453 | { |
458 | if (all->par.regs) | 454 | if (par->regs) |
459 | of_iounmap(&op->resource[0], | 455 | of_iounmap(&op->resource[0], |
460 | all->par.regs, sizeof(struct cg14_regs)); | 456 | par->regs, sizeof(struct cg14_regs)); |
461 | if (all->par.clut) | 457 | if (par->clut) |
462 | of_iounmap(&op->resource[0], | 458 | of_iounmap(&op->resource[0], |
463 | all->par.clut, sizeof(struct cg14_clut)); | 459 | par->clut, sizeof(struct cg14_clut)); |
464 | if (all->par.cursor) | 460 | if (par->cursor) |
465 | of_iounmap(&op->resource[0], | 461 | of_iounmap(&op->resource[0], |
466 | all->par.cursor, sizeof(struct cg14_cursor)); | 462 | par->cursor, sizeof(struct cg14_cursor)); |
467 | if (all->info.screen_base) | 463 | if (info->screen_base) |
468 | of_iounmap(&op->resource[1], | 464 | of_iounmap(&op->resource[1], |
469 | all->info.screen_base, all->par.fbsize); | 465 | info->screen_base, par->fbsize); |
470 | } | 466 | } |
471 | 467 | ||
472 | static int __devinit cg14_init_one(struct of_device *op) | 468 | static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match) |
473 | { | 469 | { |
474 | struct device_node *dp = op->node; | 470 | struct device_node *dp = op->node; |
475 | struct all_info *all; | 471 | struct fb_info *info; |
472 | struct cg14_par *par; | ||
476 | int is_8mb, linebytes, i, err; | 473 | int is_8mb, linebytes, i, err; |
477 | 474 | ||
478 | all = kzalloc(sizeof(*all), GFP_KERNEL); | 475 | info = framebuffer_alloc(sizeof(struct cg14_par), &op->dev); |
479 | if (!all) | 476 | |
480 | return -ENOMEM; | 477 | err = -ENOMEM; |
478 | if (!info) | ||
479 | goto out_err; | ||
480 | par = info->par; | ||
481 | 481 | ||
482 | spin_lock_init(&all->par.lock); | 482 | spin_lock_init(&par->lock); |
483 | 483 | ||
484 | sbusfb_fill_var(&all->info.var, dp->node, 8); | 484 | sbusfb_fill_var(&info->var, dp->node, 8); |
485 | all->info.var.red.length = 8; | 485 | info->var.red.length = 8; |
486 | all->info.var.green.length = 8; | 486 | info->var.green.length = 8; |
487 | all->info.var.blue.length = 8; | 487 | info->var.blue.length = 8; |
488 | 488 | ||
489 | linebytes = of_getintprop_default(dp, "linebytes", | 489 | linebytes = of_getintprop_default(dp, "linebytes", |
490 | all->info.var.xres); | 490 | info->var.xres); |
491 | all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); | 491 | par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); |
492 | 492 | ||
493 | if (!strcmp(dp->parent->name, "sbus") || | 493 | if (!strcmp(dp->parent->name, "sbus") || |
494 | !strcmp(dp->parent->name, "sbi")) { | 494 | !strcmp(dp->parent->name, "sbi")) { |
495 | all->par.physbase = op->resource[0].start; | 495 | par->physbase = op->resource[0].start; |
496 | all->par.iospace = op->resource[0].flags & IORESOURCE_BITS; | 496 | par->iospace = op->resource[0].flags & IORESOURCE_BITS; |
497 | } else { | 497 | } else { |
498 | all->par.physbase = op->resource[1].start; | 498 | par->physbase = op->resource[1].start; |
499 | all->par.iospace = op->resource[0].flags & IORESOURCE_BITS; | 499 | par->iospace = op->resource[0].flags & IORESOURCE_BITS; |
500 | } | 500 | } |
501 | 501 | ||
502 | all->par.regs = of_ioremap(&op->resource[0], 0, | 502 | par->regs = of_ioremap(&op->resource[0], 0, |
503 | sizeof(struct cg14_regs), "cg14 regs"); | 503 | sizeof(struct cg14_regs), "cg14 regs"); |
504 | all->par.clut = of_ioremap(&op->resource[0], CG14_CLUT1, | 504 | par->clut = of_ioremap(&op->resource[0], CG14_CLUT1, |
505 | sizeof(struct cg14_clut), "cg14 clut"); | 505 | sizeof(struct cg14_clut), "cg14 clut"); |
506 | all->par.cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS, | 506 | par->cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS, |
507 | sizeof(struct cg14_cursor), "cg14 cursor"); | 507 | sizeof(struct cg14_cursor), "cg14 cursor"); |
508 | 508 | ||
509 | all->info.screen_base = of_ioremap(&op->resource[1], 0, | 509 | info->screen_base = of_ioremap(&op->resource[1], 0, |
510 | all->par.fbsize, "cg14 ram"); | 510 | par->fbsize, "cg14 ram"); |
511 | 511 | ||
512 | if (!all->par.regs || !all->par.clut || !all->par.cursor || | 512 | if (!par->regs || !par->clut || !par->cursor || !info->screen_base) |
513 | !all->info.screen_base) | 513 | goto out_unmap_regs; |
514 | cg14_unmap_regs(op, all); | ||
515 | 514 | ||
516 | is_8mb = (((op->resource[1].end - op->resource[1].start) + 1) == | 515 | is_8mb = (((op->resource[1].end - op->resource[1].start) + 1) == |
517 | (8 * 1024 * 1024)); | 516 | (8 * 1024 * 1024)); |
518 | 517 | ||
519 | BUILD_BUG_ON(sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map)); | 518 | BUILD_BUG_ON(sizeof(par->mmap_map) != sizeof(__cg14_mmap_map)); |
520 | 519 | ||
521 | memcpy(&all->par.mmap_map, &__cg14_mmap_map, | 520 | memcpy(&par->mmap_map, &__cg14_mmap_map, sizeof(par->mmap_map)); |
522 | sizeof(all->par.mmap_map)); | ||
523 | 521 | ||
524 | for (i = 0; i < CG14_MMAP_ENTRIES; i++) { | 522 | for (i = 0; i < CG14_MMAP_ENTRIES; i++) { |
525 | struct sbus_mmap_map *map = &all->par.mmap_map[i]; | 523 | struct sbus_mmap_map *map = &par->mmap_map[i]; |
526 | 524 | ||
527 | if (!map->size) | 525 | if (!map->size) |
528 | break; | 526 | break; |
@@ -536,59 +534,55 @@ static int __devinit cg14_init_one(struct of_device *op) | |||
536 | map->size *= 2; | 534 | map->size *= 2; |
537 | } | 535 | } |
538 | 536 | ||
539 | all->par.mode = MDI_8_PIX; | 537 | par->mode = MDI_8_PIX; |
540 | all->par.ramsize = (is_8mb ? 0x800000 : 0x400000); | 538 | par->ramsize = (is_8mb ? 0x800000 : 0x400000); |
541 | 539 | ||
542 | all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; | 540 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; |
543 | all->info.fbops = &cg14_ops; | 541 | info->fbops = &cg14_ops; |
544 | all->info.par = &all->par; | ||
545 | 542 | ||
546 | __cg14_reset(&all->par); | 543 | __cg14_reset(par); |
547 | 544 | ||
548 | if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { | 545 | if (fb_alloc_cmap(&info->cmap, 256, 0)) |
549 | cg14_unmap_regs(op, all); | 546 | goto out_unmap_regs; |
550 | kfree(all); | ||
551 | return -ENOMEM; | ||
552 | } | ||
553 | fb_set_cmap(&all->info.cmap, &all->info); | ||
554 | 547 | ||
555 | cg14_init_fix(&all->info, linebytes, dp); | 548 | fb_set_cmap(&info->cmap, info); |
556 | 549 | ||
557 | err = register_framebuffer(&all->info); | 550 | cg14_init_fix(info, linebytes, dp); |
558 | if (err < 0) { | 551 | |
559 | fb_dealloc_cmap(&all->info.cmap); | 552 | err = register_framebuffer(info); |
560 | cg14_unmap_regs(op, all); | 553 | if (err < 0) |
561 | kfree(all); | 554 | goto out_dealloc_cmap; |
562 | return err; | ||
563 | } | ||
564 | 555 | ||
565 | dev_set_drvdata(&op->dev, all); | 556 | dev_set_drvdata(&op->dev, info); |
566 | 557 | ||
567 | printk("%s: cgfourteen at %lx:%lx, %dMB\n", | 558 | printk("%s: cgfourteen at %lx:%lx, %dMB\n", |
568 | dp->full_name, | 559 | dp->full_name, |
569 | all->par.iospace, all->par.physbase, | 560 | par->iospace, par->physbase, |
570 | all->par.ramsize >> 20); | 561 | par->ramsize >> 20); |
571 | 562 | ||
572 | return 0; | 563 | return 0; |
573 | } | ||
574 | 564 | ||
575 | static int __devinit cg14_probe(struct of_device *dev, const struct of_device_id *match) | 565 | out_dealloc_cmap: |
576 | { | 566 | fb_dealloc_cmap(&info->cmap); |
577 | struct of_device *op = to_of_device(&dev->dev); | 567 | |
568 | out_unmap_regs: | ||
569 | cg14_unmap_regs(op, info, par); | ||
578 | 570 | ||
579 | return cg14_init_one(op); | 571 | out_err: |
572 | return err; | ||
580 | } | 573 | } |
581 | 574 | ||
582 | static int __devexit cg14_remove(struct of_device *op) | 575 | static int __devexit cg14_remove(struct of_device *op) |
583 | { | 576 | { |
584 | struct all_info *all = dev_get_drvdata(&op->dev); | 577 | struct fb_info *info = dev_get_drvdata(&op->dev); |
578 | struct cg14_par *par = info->par; | ||
585 | 579 | ||
586 | unregister_framebuffer(&all->info); | 580 | unregister_framebuffer(info); |
587 | fb_dealloc_cmap(&all->info.cmap); | 581 | fb_dealloc_cmap(&info->cmap); |
588 | 582 | ||
589 | cg14_unmap_regs(op, all); | 583 | cg14_unmap_regs(op, info, par); |
590 | 584 | ||
591 | kfree(all); | 585 | framebuffer_release(info); |
592 | 586 | ||
593 | dev_set_drvdata(&op->dev, NULL); | 587 | dev_set_drvdata(&op->dev, NULL); |
594 | 588 | ||