From 61640c295bbe8bb863c7c26b54ea365dd5be6991 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 21 Nov 2011 21:53:59 +0100 Subject: [PATCH] fbdev/amifb: Use framebuffer_alloc() Use framebuffer_alloc() instead of static fb_info and currentpar variables. Also sanitize the error path and cleanup code (e.g. missing free_irq()). Signed-off-by: Geert Uytterhoeven Signed-off-by: Florian Tobias Schandinat --- drivers/video/amifb.c | 286 +++++++++++++++++++++--------------------- 1 file changed, 146 insertions(+), 140 deletions(-) diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 2bfaf1b86d4..f23cae094f1 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -710,7 +710,7 @@ static u_short *lofsprite, *shfsprite, *dummysprite; * Current Video Mode */ -static struct amifb_par { +struct amifb_par { /* General Values */ @@ -773,15 +773,6 @@ static struct amifb_par { /* Additional AGA Hardware Registers */ u_short fmode; /* vmode */ -} currentpar; - - -static struct fb_info fb_info = { - .fix = { - .id = "Amiga ", - .visual = FB_VISUAL_PSEUDOCOLOR, - .accel = FB_ACCEL_AMIGABLITT - } }; @@ -1130,8 +1121,8 @@ static u_short sprfetchmode[3] = { * it up, if it's too big, return -EINVAL. */ -static int ami_decode_var(struct fb_var_screeninfo *var, - struct amifb_par *par) +static int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par, + const struct fb_info *info) { u_short clk_shift, line_shift; u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; @@ -1449,14 +1440,14 @@ static int ami_decode_var(struct fb_var_screeninfo *var, if (amifb_ilbm) { par->next_plane = div8(upx(16 << maxfmode, par->vxres)); par->next_line = par->bpp * par->next_plane; - if (par->next_line * par->vyres > fb_info.fix.smem_len) { + if (par->next_line * par->vyres > info->fix.smem_len) { DPRINTK("too few video mem\n"); return -EINVAL; } } else { par->next_line = div8(upx(16 << maxfmode, par->vxres)); par->next_plane = par->vyres * par->next_line; - if (par->next_plane * par->bpp > fb_info.fix.smem_len) { + if (par->next_plane * par->bpp > info->fix.smem_len) { DPRINTK("too few video mem\n"); return -EINVAL; } @@ -1519,8 +1510,8 @@ static int ami_decode_var(struct fb_var_screeninfo *var, * other values read out of the hardware. */ -static int ami_encode_var(struct fb_var_screeninfo *var, - struct amifb_par *par) +static void ami_encode_var(struct fb_var_screeninfo *var, + struct amifb_par *par) { u_short clk_shift, line_shift; @@ -1596,8 +1587,6 @@ static int ami_encode_var(struct fb_var_screeninfo *var, var->sync |= FB_SYNC_EXT; if (par->vmode & FB_VMODE_YWRAP) var->vmode |= FB_VMODE_YWRAP; - - return 0; } @@ -1605,9 +1594,9 @@ static int ami_encode_var(struct fb_var_screeninfo *var, * Update hardware */ -static int ami_update_par(void) +static void ami_update_par(struct fb_info *info) { - struct amifb_par *par = ¤tpar; + struct amifb_par *par = info->par; short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; clk_shift = par->clk_shift; @@ -1649,11 +1638,11 @@ static int ami_update_par(void) par->bpl1mod = par->bpl2mod; if (par->yoffset) { - par->bplpt0 = fb_info.fix.smem_start + + par->bplpt0 = info->fix.smem_start + par->next_line * par->yoffset + move; if (par->vmode & FB_VMODE_YWRAP) { if (par->yoffset > par->vyres - par->yres) { - par->bplpt0wrap = fb_info.fix.smem_start + move; + par->bplpt0wrap = info->fix.smem_start + move; if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v + par->vyres - par->yoffset)) @@ -1661,12 +1650,10 @@ static int ami_update_par(void) } } } else - par->bplpt0 = fb_info.fix.smem_start + move; + par->bplpt0 = info->fix.smem_start + move; if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) par->bplpt0 += par->next_line; - - return 0; } @@ -1677,9 +1664,9 @@ static int ami_update_par(void) * in `var'. */ -static void ami_pan_var(struct fb_var_screeninfo *var) +static void ami_pan_var(struct fb_var_screeninfo *var, struct fb_info *info) { - struct amifb_par *par = ¤tpar; + struct amifb_par *par = info->par; par->xoffset = var->xoffset; par->yoffset = var->yoffset; @@ -1689,15 +1676,13 @@ static void ami_pan_var(struct fb_var_screeninfo *var) par->vmode &= ~FB_VMODE_YWRAP; do_vmode_pan = 0; - ami_update_par(); + ami_update_par(info); do_vmode_pan = 1; } -static void ami_update_display(void) +static void ami_update_display(const struct amifb_par *par) { - struct amifb_par *par = ¤tpar; - custom.bplcon1 = par->bplcon1; custom.bpl1mod = par->bpl1mod; custom.bpl2mod = par->bpl2mod; @@ -1709,9 +1694,8 @@ static void ami_update_display(void) * Change the video mode (called by VBlank interrupt) */ -static void ami_init_display(void) +static void ami_init_display(const struct amifb_par *par) { - struct amifb_par *par = ¤tpar; int i; custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; @@ -1764,9 +1748,8 @@ static void ami_init_display(void) * (Un)Blank the screen (called by VBlank interrupt) */ -static void ami_do_blank(void) +static void ami_do_blank(const struct amifb_par *par) { - struct amifb_par *par = ¤tpar; #if defined(CONFIG_FB_AMIGA_AGA) u_short bplcon3 = par->bplcon3; #endif @@ -1843,10 +1826,9 @@ static void ami_do_blank(void) is_blanked = do_blank > 0 ? do_blank : 0; } -static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix) +static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, + const struct amifb_par *par) { - struct amifb_par *par = ¤tpar; - fix->crsr_width = fix->crsr_xsize = par->crsr.width; fix->crsr_height = fix->crsr_ysize = par->crsr.height; fix->crsr_color1 = 17; @@ -1854,9 +1836,10 @@ static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix) return 0; } -static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data) +static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, + u_char __user *data, + const struct amifb_par *par) { - struct amifb_par *par = ¤tpar; register u_short *lspr, *sspr; #ifdef __mc68000__ register u_long datawords asm ("d2"); @@ -1929,9 +1912,9 @@ static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user * return 0; } -static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data) +static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, + u_char __user *data, struct amifb_par *par) { - struct amifb_par *par = ¤tpar; register u_short *lspr, *sspr; #ifdef __mc68000__ register u_long datawords asm ("d2"); @@ -2047,20 +2030,18 @@ static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user * return 0; } -static int ami_get_cursorstate(struct fb_cursorstate *state) +static int ami_get_cursorstate(struct fb_cursorstate *state, + const struct amifb_par *par) { - struct amifb_par *par = ¤tpar; - state->xoffset = par->crsr.crsr_x; state->yoffset = par->crsr.crsr_y; state->mode = cursormode; return 0; } -static int ami_set_cursorstate(struct fb_cursorstate *state) +static int ami_set_cursorstate(struct fb_cursorstate *state, + struct amifb_par *par) { - struct amifb_par *par = ¤tpar; - par->crsr.crsr_x = state->xoffset; par->crsr.crsr_y = state->yoffset; if ((cursormode = state->mode) == FB_CURSOR_OFF) @@ -2069,9 +2050,8 @@ static int ami_set_cursorstate(struct fb_cursorstate *state) return 0; } -static void ami_set_sprite(void) +static void ami_set_sprite(const struct amifb_par *par) { - struct amifb_par *par = ¤tpar; copins *copl, *cops; u_short hs, vs, ve; u_long pl, ps, pt; @@ -2153,10 +2133,8 @@ static void __init ami_init_copper(void) custom.copjmp1 = 0; } -static void ami_reinit_copper(void) +static void ami_reinit_copper(const struct amifb_par *par) { - struct amifb_par *par = ¤tpar; - copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; copdisplay.wait->l = CWAIT(32, par->diwstrt_v - 4); } @@ -2168,9 +2146,8 @@ static void ami_reinit_copper(void) * We only change the things that are not static */ -static void ami_rebuild_copper(void) +static void ami_rebuild_copper(const struct amifb_par *par) { - struct amifb_par *par = ¤tpar; copins *copl, *cops; u_short line, h_end1, h_end2; short i; @@ -2182,7 +2159,7 @@ static void ami_rebuild_copper(void) h_end1 = par->htotal - 32; h_end2 = par->ddfstop + 64; - ami_set_sprite(); + ami_set_sprite(par); copl = copdisplay.rebuild[1]; p = par->bplpt0; @@ -2259,9 +2236,9 @@ static void ami_rebuild_copper(void) * Build the Copper List */ -static void ami_build_copper(void) +static void ami_build_copper(struct fb_info *info) { - struct amifb_par *par = ¤tpar; + struct amifb_par *par = info->par; copins *copl, *cops; u_long p; @@ -2326,8 +2303,8 @@ static void ami_build_copper(void) } copdisplay.rebuild[1] = copl; - ami_update_par(); - ami_rebuild_copper(); + ami_update_par(info); + ami_rebuild_copper(info->par); } @@ -2405,7 +2382,8 @@ static int amifb_check_var(struct fb_var_screeninfo *var, struct amifb_par par; /* Validate wanted screen parameters */ - if ((err = ami_decode_var(var, &par))) + err = ami_decode_var(var, &par, info); + if (err) return err; /* Encode (possibly rounded) screen parameters */ @@ -2417,15 +2395,18 @@ static int amifb_check_var(struct fb_var_screeninfo *var, static int amifb_set_par(struct fb_info *info) { struct amifb_par *par = info->par; + int error; do_vmode_pan = 0; do_vmode_full = 0; /* Decode wanted screen parameters */ - ami_decode_var(&info->var, par); + error = ami_decode_var(&info->var, par, info); + if (error) + return error; /* Set new videomode */ - ami_build_copper(); + ami_build_copper(info); /* Set VBlank trigger */ do_vmode_full = 1; @@ -2471,10 +2452,12 @@ static int amifb_set_par(struct fb_info *info) static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) { + const struct amifb_par *par = info->par; + if (IS_AGA) { if (regno > 255) return 1; - } else if (currentpar.bplcon0 & BPC0_SHRES) { + } else if (par->bplcon0 & BPC0_SHRES) { if (regno > 3) return 1; } else { @@ -2501,7 +2484,7 @@ static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, if (regno || !is_blanked) { #if defined(CONFIG_FB_AMIGA_AGA) if (IS_AGA) { - u_short bplcon3 = currentpar.bplcon3; + u_short bplcon3 = par->bplcon3; VBlankOff(); custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000); custom.color[regno & 31] = rgb2hw8_high(red, green, @@ -2515,7 +2498,7 @@ static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, } else #endif #if defined(CONFIG_FB_AMIGA_ECS) - if (currentpar.bplcon0 & BPC0_SHRES) { + if (par->bplcon0 & BPC0_SHRES) { u_short color, mask; int i; @@ -2572,7 +2555,7 @@ static int amifb_pan_display(struct fb_var_screeninfo *var, var->yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL; } - ami_pan_var(var); + ami_pan_var(var, info); info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) @@ -3418,7 +3401,7 @@ static int amifb_ioctl(struct fb_info *info, switch (cmd) { case FBIOGET_FCURSORINFO: - i = ami_get_fix_cursorinfo(&crsr.fix); + i = ami_get_fix_cursorinfo(&crsr.fix, info->par); if (i) return i; return copy_to_user(argp, &crsr.fix, @@ -3426,7 +3409,8 @@ static int amifb_ioctl(struct fb_info *info, case FBIOGET_VCURSORINFO: i = ami_get_var_cursorinfo(&crsr.var, - ((struct fb_var_cursorinfo __user *)arg)->data); + ((struct fb_var_cursorinfo __user *)arg)->data, + info->par); if (i) return i; return copy_to_user(argp, &crsr.var, @@ -3436,10 +3420,11 @@ static int amifb_ioctl(struct fb_info *info, if (copy_from_user(&crsr.var, argp, sizeof(crsr.var))) return -EFAULT; return ami_set_var_cursorinfo(&crsr.var, - ((struct fb_var_cursorinfo __user *)arg)->data); + ((struct fb_var_cursorinfo __user *)arg)->data, + info->par); case FBIOGET_CURSORSTATE: - i = ami_get_cursorstate(&crsr.state); + i = ami_get_cursorstate(&crsr.state, info->par); if (i) return i; return copy_to_user(argp, &crsr.state, @@ -3448,7 +3433,7 @@ static int amifb_ioctl(struct fb_info *info, case FBIOPUT_CURSORSTATE: if (copy_from_user(&crsr.state, argp, sizeof(crsr.state))) return -EFAULT; - return ami_set_cursorstate(&crsr.state); + return ami_set_cursorstate(&crsr.state, info->par); } return -EINVAL; } @@ -3479,32 +3464,34 @@ static int flash_cursor(void) static irqreturn_t amifb_interrupt(int irq, void *dev_id) { + struct amifb_par *par = dev_id; + if (do_vmode_pan || do_vmode_full) - ami_update_display(); + ami_update_display(par); if (do_vmode_full) - ami_init_display(); + ami_init_display(par); if (do_vmode_pan) { flash_cursor(); - ami_rebuild_copper(); + ami_rebuild_copper(par); do_cursor = do_vmode_pan = 0; } else if (do_cursor) { flash_cursor(); - ami_set_sprite(); + ami_set_sprite(par); do_cursor = 0; } else { if (flash_cursor()) - ami_set_sprite(); + ami_set_sprite(par); } if (do_blank) { - ami_do_blank(); + ami_do_blank(par); do_blank = 0; } if (do_vmode_full) { - ami_reinit_copper(); + ami_reinit_copper(par); do_vmode_full = 0; } return IRQ_HANDLED; @@ -3549,23 +3536,13 @@ static inline void chipfree(void) } -static void amifb_deinit(struct platform_device *pdev) -{ - if (fb_info.cmap.len) - fb_dealloc_cmap(&fb_info.cmap); - chipfree(); - if (videomemory) - iounmap((void *)videomemory); - custom.dmacon = DMAF_ALL | DMAF_MASTER; -} - - /* * Initialisation */ static int __init amifb_probe(struct platform_device *pdev) { + struct fb_info *info; int tag, i, err = 0; u_long chipptr; u_int defmode; @@ -3581,10 +3558,20 @@ static int __init amifb_probe(struct platform_device *pdev) #endif custom.dmacon = DMAF_ALL | DMAF_MASTER; + info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev); + if (!info) { + dev_err(&pdev->dev, "framebuffer_alloc failed\n"); + return -ENOMEM; + } + + strcpy(info->fix.id, "Amiga "); + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + info->fix.accel = FB_ACCEL_AMIGABLITT; + switch (amiga_chipset) { #ifdef CONFIG_FB_AMIGA_OCS case CS_OCS: - strcat(fb_info.fix.id, "OCS"); + strcat(info->fix.id, "OCS"); default_chipset: chipset = TAG_OCS; maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ @@ -3592,13 +3579,13 @@ default_chipset: maxdepth[TAG_LORES] = 6; maxfmode = TAG_FMODE_1; defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC; - fb_info.fix.smem_len = VIDEOMEMSIZE_OCS; + info->fix.smem_len = VIDEOMEMSIZE_OCS; break; #endif /* CONFIG_FB_AMIGA_OCS */ #ifdef CONFIG_FB_AMIGA_ECS case CS_ECS: - strcat(fb_info.fix.id, "ECS"); + strcat(info->fix.id, "ECS"); chipset = TAG_ECS; maxdepth[TAG_SHRES] = 2; maxdepth[TAG_HIRES] = 4; @@ -3612,15 +3599,15 @@ default_chipset: : DEFMODE_NTSC; if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > VIDEOMEMSIZE_ECS_2M) - fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M; + info->fix.smem_len = VIDEOMEMSIZE_ECS_2M; else - fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M; + info->fix.smem_len = VIDEOMEMSIZE_ECS_1M; break; #endif /* CONFIG_FB_AMIGA_ECS */ #ifdef CONFIG_FB_AMIGA_AGA case CS_AGA: - strcat(fb_info.fix.id, "AGA"); + strcat(info->fix.id, "AGA"); chipset = TAG_AGA; maxdepth[TAG_SHRES] = 8; maxdepth[TAG_HIRES] = 8; @@ -3629,20 +3616,20 @@ default_chipset: defmode = DEFMODE_AGA; if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > VIDEOMEMSIZE_AGA_2M) - fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M; + info->fix.smem_len = VIDEOMEMSIZE_AGA_2M; else - fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M; + info->fix.smem_len = VIDEOMEMSIZE_AGA_1M; break; #endif /* CONFIG_FB_AMIGA_AGA */ default: #ifdef CONFIG_FB_AMIGA_OCS printk("Unknown graphics chipset, defaulting to OCS\n"); - strcat(fb_info.fix.id, "Unknown"); + strcat(info->fix.id, "Unknown"); goto default_chipset; #else /* CONFIG_FB_AMIGA_OCS */ err = -ENODEV; - goto amifb_error; + goto release; #endif /* CONFIG_FB_AMIGA_OCS */ break; } @@ -3672,44 +3659,43 @@ default_chipset: } if (amifb_hfmin) { - fb_info.monspecs.hfmin = amifb_hfmin; - fb_info.monspecs.hfmax = amifb_hfmax; - fb_info.monspecs.vfmin = amifb_vfmin; - fb_info.monspecs.vfmax = amifb_vfmax; + info->monspecs.hfmin = amifb_hfmin; + info->monspecs.hfmax = amifb_hfmax; + info->monspecs.vfmin = amifb_vfmin; + info->monspecs.vfmax = amifb_vfmax; } else { /* * These are for a typical Amiga monitor (e.g. A1960) */ - fb_info.monspecs.hfmin = 15000; - fb_info.monspecs.hfmax = 38000; - fb_info.monspecs.vfmin = 49; - fb_info.monspecs.vfmax = 90; + info->monspecs.hfmin = 15000; + info->monspecs.hfmax = 38000; + info->monspecs.vfmin = 49; + info->monspecs.vfmax = 90; } - fb_info.fbops = &amifb_ops; - fb_info.par = ¤tpar; - fb_info.flags = FBINFO_DEFAULT; - fb_info.device = &pdev->dev; + info->fbops = &amifb_ops; + info->flags = FBINFO_DEFAULT; + info->device = &pdev->dev; - if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb, + if (!fb_find_mode(&info->var, info, mode_option, ami_modedb, NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { err = -EINVAL; - goto amifb_error; + goto release; } fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES, - &fb_info.modelist); + &info->modelist); round_down_bpp = 0; - chipptr = chipalloc(fb_info.fix.smem_len + SPRITEMEMSIZE + + chipptr = chipalloc(info->fix.smem_len + SPRITEMEMSIZE + DUMMYSPRITEMEMSIZE + COPINITSIZE + 4 * COPLISTSIZE); if (!chipptr) { err = -ENOMEM; - goto amifb_error; + goto release; } - assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len); + assignchunk(videomemory, u_long, chipptr, info->fix.smem_len); assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); @@ -3721,14 +3707,15 @@ default_chipset: /* * access the videomem with writethrough cache */ - fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory); - videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start, - fb_info.fix.smem_len); + info->fix.smem_start = (u_long)ZTWO_PADDR(videomemory); + videomemory = (u_long)ioremap_writethrough(info->fix.smem_start, + info->fix.smem_len); if (!videomemory) { - printk("amifb: WARNING! unable to map videomem cached writethrough\n"); - fb_info.screen_base = (char *)ZTWO_VADDR(fb_info.fix.smem_start); + dev_warn(&pdev->dev, + "Unable to map videomem cached writethrough\n"); + info->screen_base = (char *)ZTWO_VADDR(info->fix.smem_start); } else - fb_info.screen_base = (char *)videomemory; + info->screen_base = (char *)videomemory; memset(dummysprite, 0, DUMMYSPRITEMEMSIZE); @@ -3743,36 +3730,55 @@ default_chipset: custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | DMAF_BLITTER | DMAF_SPRITE; - if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, - "fb vertb handler", ¤tpar)) { - err = -EBUSY; - goto amifb_error; - } + err = request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, + "fb vertb handler", info->par); + if (err) + goto disable_dma; - err = fb_alloc_cmap(&fb_info.cmap, 1 << fb_info.var.bits_per_pixel, 0); + err = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0); if (err) - goto amifb_error; + goto free_irq; - if (register_framebuffer(&fb_info) < 0) { - err = -EINVAL; - goto amifb_error; - } + dev_set_drvdata(&pdev->dev, info); + + err = register_framebuffer(info); + if (err) + goto unset_drvdata; printk("fb%d: %s frame buffer device, using %dK of video memory\n", - fb_info.node, fb_info.fix.id, fb_info.fix.smem_len>>10); + info->node, info->fix.id, info->fix.smem_len>>10); return 0; -amifb_error: - amifb_deinit(pdev); +unset_drvdata: + dev_set_drvdata(&pdev->dev, NULL); + fb_dealloc_cmap(&info->cmap); +free_irq: + free_irq(IRQ_AMIGA_COPPER, info->par); +disable_dma: + custom.dmacon = DMAF_ALL | DMAF_MASTER; + if (videomemory) + iounmap((void *)videomemory); + chipfree(); +release: + framebuffer_release(info); return err; } static int __exit amifb_remove(struct platform_device *pdev) { - unregister_framebuffer(&fb_info); - amifb_deinit(pdev); + struct fb_info *info = dev_get_drvdata(&pdev->dev); + + unregister_framebuffer(info); + dev_set_drvdata(&pdev->dev, NULL); + fb_dealloc_cmap(&info->cmap); + free_irq(IRQ_AMIGA_COPPER, info->par); + custom.dmacon = DMAF_ALL | DMAF_MASTER; + if (videomemory) + iounmap((void *)videomemory); + chipfree(); + framebuffer_release(info); amifb_video_off(); return 0; } -- 2.46.0