static int __init amifb_probe()

in fbdev/amifb.c [3542:3762]


static int __init amifb_probe(struct platform_device *pdev)
{
	struct fb_info *info;
	int tag, i, err = 0;
	u_long chipptr;
	u_int defmode;

#ifndef MODULE
	char *option = NULL;

	if (fb_get_options("amifb", &option)) {
		amifb_video_off();
		return -ENODEV;
	}
	amifb_setup(option);
#endif
	custom.dmacon = DMAF_ALL | DMAF_MASTER;

	info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev);
	if (!info)
		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(info->fix.id, "OCS");
default_chipset:
		chipset = TAG_OCS;
		maxdepth[TAG_SHRES] = 0;	/* OCS means no SHRES */
		maxdepth[TAG_HIRES] = 4;
		maxdepth[TAG_LORES] = 6;
		maxfmode = TAG_FMODE_1;
		defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC;
		info->fix.smem_len = VIDEOMEMSIZE_OCS;
		break;
#endif /* CONFIG_FB_AMIGA_OCS */

#ifdef CONFIG_FB_AMIGA_ECS
	case CS_ECS:
		strcat(info->fix.id, "ECS");
		chipset = TAG_ECS;
		maxdepth[TAG_SHRES] = 2;
		maxdepth[TAG_HIRES] = 4;
		maxdepth[TAG_LORES] = 6;
		maxfmode = TAG_FMODE_1;
		if (AMIGAHW_PRESENT(AMBER_FF))
			defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL
						     : DEFMODE_AMBER_NTSC;
		else
			defmode = amiga_vblank == 50 ? DEFMODE_PAL
						     : DEFMODE_NTSC;
		if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT >
		    VIDEOMEMSIZE_ECS_2M)
			info->fix.smem_len = VIDEOMEMSIZE_ECS_2M;
		else
			info->fix.smem_len = VIDEOMEMSIZE_ECS_1M;
		break;
#endif /* CONFIG_FB_AMIGA_ECS */

#ifdef CONFIG_FB_AMIGA_AGA
	case CS_AGA:
		strcat(info->fix.id, "AGA");
		chipset = TAG_AGA;
		maxdepth[TAG_SHRES] = 8;
		maxdepth[TAG_HIRES] = 8;
		maxdepth[TAG_LORES] = 8;
		maxfmode = TAG_FMODE_4;
		defmode = DEFMODE_AGA;
		if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT >
		    VIDEOMEMSIZE_AGA_2M)
			info->fix.smem_len = VIDEOMEMSIZE_AGA_2M;
		else
			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(info->fix.id, "Unknown");
		goto default_chipset;
#else /* CONFIG_FB_AMIGA_OCS */
		err = -ENODEV;
		goto release;
#endif /* CONFIG_FB_AMIGA_OCS */
		break;
	}

	/*
	 * Calculate the Pixel Clock Values for this Machine
	 */

	{
	u_long tmp = DIVUL(200000000000ULL, amiga_eclock);

	pixclock[TAG_SHRES] = (tmp + 4) / 8;	/* SHRES:  35 ns / 28 MHz */
	pixclock[TAG_HIRES] = (tmp + 2) / 4;	/* HIRES:  70 ns / 14 MHz */
	pixclock[TAG_LORES] = (tmp + 1) / 2;	/* LORES: 140 ns /  7 MHz */
	}

	/*
	 * Replace the Tag Values with the Real Pixel Clock Values
	 */

	for (i = 0; i < NUM_TOTAL_MODES; i++) {
		struct fb_videomode *mode = &ami_modedb[i];
		tag = mode->pixclock;
		if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) {
			mode->pixclock = pixclock[tag];
		}
	}

	if (amifb_hfmin) {
		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)
		 */
		info->monspecs.hfmin = 15000;
		info->monspecs.hfmax = 38000;
		info->monspecs.vfmin = 49;
		info->monspecs.vfmax = 90;
	}

	info->fbops = &amifb_ops;
	info->flags = FBINFO_DEFAULT;
	info->device = &pdev->dev;

	if (!fb_find_mode(&info->var, info, mode_option, ami_modedb,
			  NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
		err = -EINVAL;
		goto release;
	}

	fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES,
				 &info->modelist);

	round_down_bpp = 0;
	chipptr = chipalloc(info->fix.smem_len + SPRITEMEMSIZE +
			    DUMMYSPRITEMEMSIZE + COPINITSIZE +
			    4 * COPLISTSIZE);
	if (!chipptr) {
		err = -ENOMEM;
		goto release;
	}

	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);
	assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE);
	assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE);
	assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE);
	assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE);

	/*
	 * access the videomem with writethrough cache
	 */
	info->fix.smem_start = (u_long)ZTWO_PADDR(videomemory);
	videomemory = (u_long)ioremap_wt(info->fix.smem_start,
					 info->fix.smem_len);
	if (!videomemory) {
		dev_warn(&pdev->dev,
			 "Unable to map videomem cached writethrough\n");
		info->screen_base = ZTWO_VADDR(info->fix.smem_start);
	} else
		info->screen_base = (char *)videomemory;

	memset(dummysprite, 0, DUMMYSPRITEMEMSIZE);

	/*
	 * Make sure the Copper has something to do
	 */
	ami_init_copper();

	/*
	 * Enable Display DMA
	 */
	custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
			DMAF_BLITTER | DMAF_SPRITE;

	err = request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,
			  "fb vertb handler", info->par);
	if (err)
		goto disable_dma;

	err = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0);
	if (err)
		goto free_irq;

	platform_set_drvdata(pdev, info);

	err = register_framebuffer(info);
	if (err)
		goto unset_drvdata;

	fb_info(info, "%s frame buffer device, using %dK of video memory\n",
		info->fix.id, info->fix.smem_len>>10);

	return 0;

unset_drvdata:
	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;
}