static int __init macfb_init()

in fbdev/macfb.c [540:899]


static int __init macfb_init(void)
{
	int video_cmap_len, video_is_nubus = 0;
	struct nubus_rsrc *ndev = NULL;
	char *option = NULL;
	int err;

	if (fb_get_options("macfb", &option))
		return -ENODEV;
	macfb_setup(option);

	if (!MACH_IS_MAC) 
		return -ENODEV;

	if (mac_bi_data.id == MAC_MODEL_Q630 ||
	    mac_bi_data.id == MAC_MODEL_P588)
		return -ENODEV; /* See valkyriefb.c */

	macfb_defined.xres = mac_bi_data.dimensions & 0xFFFF;
	macfb_defined.yres = mac_bi_data.dimensions >> 16;
	macfb_defined.bits_per_pixel = mac_bi_data.videodepth;

	macfb_fix.line_length = mac_bi_data.videorow;
	macfb_fix.smem_len    = macfb_fix.line_length * macfb_defined.yres;
	/* Note: physical address (since 2.1.127) */
	macfb_fix.smem_start  = mac_bi_data.videoaddr;

	/*
	 * This is actually redundant with the initial mappings.
	 * However, there are some non-obvious aspects to the way
	 * those mappings are set up, so this is in fact the safest
	 * way to ensure that this driver will work on every possible Mac
	 */
	fb_info.screen_base = ioremap(mac_bi_data.videoaddr,
				      macfb_fix.smem_len);
	if (!fb_info.screen_base)
		return -ENODEV;

	pr_info("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
	        macfb_fix.smem_start, fb_info.screen_base,
	        macfb_fix.smem_len / 1024);
	pr_info("macfb: mode is %dx%dx%d, linelength=%d\n",
	        macfb_defined.xres, macfb_defined.yres,
	        macfb_defined.bits_per_pixel, macfb_fix.line_length);

	/* Fill in the available video resolution */
	macfb_defined.xres_virtual = macfb_defined.xres;
	macfb_defined.yres_virtual = macfb_defined.yres;
	macfb_defined.height       = PIXEL_TO_MM(macfb_defined.yres);
	macfb_defined.width        = PIXEL_TO_MM(macfb_defined.xres);

	/* Some dummy values for timing to make fbset happy */
	macfb_defined.pixclock     = 10000000 / macfb_defined.xres *
				     1000 / macfb_defined.yres;
	macfb_defined.left_margin  = (macfb_defined.xres / 8) & 0xf8;
	macfb_defined.hsync_len    = (macfb_defined.xres / 8) & 0xf8;

	switch (macfb_defined.bits_per_pixel) {
	case 1:
		macfb_defined.red.length = macfb_defined.bits_per_pixel;
		macfb_defined.green.length = macfb_defined.bits_per_pixel;
		macfb_defined.blue.length = macfb_defined.bits_per_pixel;
		video_cmap_len = 2;
		macfb_fix.visual = FB_VISUAL_MONO01;
		break;
	case 2:
	case 4:
	case 8:
		macfb_defined.red.length = macfb_defined.bits_per_pixel;
		macfb_defined.green.length = macfb_defined.bits_per_pixel;
		macfb_defined.blue.length = macfb_defined.bits_per_pixel;
		video_cmap_len = 1 << macfb_defined.bits_per_pixel;
		macfb_fix.visual = FB_VISUAL_PSEUDOCOLOR;
		break;
	case 16:
		macfb_defined.transp.offset = 15;
		macfb_defined.transp.length = 1;
		macfb_defined.red.offset = 10;
		macfb_defined.red.length = 5;
		macfb_defined.green.offset = 5;
		macfb_defined.green.length = 5;
		macfb_defined.blue.offset = 0;
		macfb_defined.blue.length = 5;
		video_cmap_len = 16;
		/*
		 * Should actually be FB_VISUAL_DIRECTCOLOR, but this
		 * works too
		 */
		macfb_fix.visual = FB_VISUAL_TRUECOLOR;
		break;
	case 24:
	case 32:
		macfb_defined.red.offset = 16;
		macfb_defined.red.length = 8;
		macfb_defined.green.offset = 8;
		macfb_defined.green.length = 8;
		macfb_defined.blue.offset = 0;
		macfb_defined.blue.length = 8;
		video_cmap_len = 16;
		macfb_fix.visual = FB_VISUAL_TRUECOLOR;
		break;
	default:
		pr_err("macfb: unknown or unsupported bit depth: %d\n",
		       macfb_defined.bits_per_pixel);
		err = -EINVAL;
		goto fail_unmap;
	}
	
	/*
	 * We take a wild guess that if the video physical address is
	 * in nubus slot space, that the nubus card is driving video.
	 * Penguin really ought to tell us whether we are using internal
	 * video or not.
	 * Hopefully we only find one of them.  Otherwise our NuBus
	 * code is really broken :-)
	 */

	for_each_func_rsrc(ndev) {
		unsigned long base = ndev->board->slot_addr;

		if (mac_bi_data.videoaddr < base ||
		    mac_bi_data.videoaddr - base > 0xFFFFFF)
			continue;

		if (ndev->category != NUBUS_CAT_DISPLAY ||
		    ndev->type != NUBUS_TYPE_VIDEO)
			continue;

		video_is_nubus = 1;
		slot_addr = (unsigned char *)base;

		switch(ndev->dr_hw) {
		case NUBUS_DRHW_APPLE_MDC:
			strcpy(macfb_fix.id, "Mac Disp. Card");
			macfb_setpalette = mdc_setpalette;
			break;
		case NUBUS_DRHW_APPLE_TFB:
			strcpy(macfb_fix.id, "Toby");
			macfb_setpalette = toby_setpalette;
			break;
		case NUBUS_DRHW_APPLE_JET:
			strcpy(macfb_fix.id, "Jet");
			macfb_setpalette = jet_setpalette;
			break;
		default:
			strcpy(macfb_fix.id, "Generic NuBus");
			break;
		}
	}

	/* If it's not a NuBus card, it must be internal video */
	if (!video_is_nubus)
		switch (mac_bi_data.id) {
		/*
		 * DAFB Quadras
		 * Note: these first four have the v7 DAFB, which is
		 * known to be rather unlike the ones used in the
		 * other models
		 */
		case MAC_MODEL_P475:
		case MAC_MODEL_P475F:
		case MAC_MODEL_P575:
		case MAC_MODEL_Q605:

		case MAC_MODEL_Q800:
		case MAC_MODEL_Q650:
		case MAC_MODEL_Q610:
		case MAC_MODEL_C650:
		case MAC_MODEL_C610:
		case MAC_MODEL_Q700:
		case MAC_MODEL_Q900:
		case MAC_MODEL_Q950:
			strcpy(macfb_fix.id, "DAFB");
			macfb_setpalette = dafb_setpalette;
			dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000);
			break;

		/*
		 * LC II uses the V8 framebuffer
		 */
		case MAC_MODEL_LCII:
			strcpy(macfb_fix.id, "V8");
			macfb_setpalette = v8_brazil_setpalette;
			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
			break;

		/*
		 * IIvi, IIvx use the "Brazil" framebuffer (which is
		 * very much like the V8, it seems, and probably uses
		 * the same DAC)
		 */
		case MAC_MODEL_IIVI:
		case MAC_MODEL_IIVX:
		case MAC_MODEL_P600:
			strcpy(macfb_fix.id, "Brazil");
			macfb_setpalette = v8_brazil_setpalette;
			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
			break;

		/*
		 * LC III (and friends) use the Sonora framebuffer
		 * Incidentally this is also used in the non-AV models
		 * of the x100 PowerMacs
		 * These do in fact seem to use the same DAC interface
		 * as the LC II.
		 */
		case MAC_MODEL_LCIII:
		case MAC_MODEL_P520:
		case MAC_MODEL_P550:
		case MAC_MODEL_P460:
			strcpy(macfb_fix.id, "Sonora");
			macfb_setpalette = v8_brazil_setpalette;
			v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000);
			break;

		/*
		 * IIci and IIsi use the infamous RBV chip
		 * (the IIsi is just a rebadged and crippled
		 * IIci in a different case, BTW)
		 */
		case MAC_MODEL_IICI:
		case MAC_MODEL_IISI:
			strcpy(macfb_fix.id, "RBV");
			macfb_setpalette = rbv_setpalette;
			rbv_cmap_regs = ioremap(DAC_BASE, 0x1000);
			break;

		/*
		 * AVs use the Civic framebuffer
		 */
		case MAC_MODEL_Q840:
		case MAC_MODEL_C660:
			strcpy(macfb_fix.id, "Civic");
			macfb_setpalette = civic_setpalette;
			civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000);
			break;

		
		/*
		 * Assorted weirdos
		 * We think this may be like the LC II
		 */
		case MAC_MODEL_LC:
			strcpy(macfb_fix.id, "LC");
			if (vidtest) {
				macfb_setpalette = v8_brazil_setpalette;
				v8_brazil_cmap_regs =
					ioremap(DAC_BASE, 0x1000);
			}
			break;

		/*
		 * We think this may be like the LC II
		 */
		case MAC_MODEL_CCL:
			strcpy(macfb_fix.id, "Color Classic");
			if (vidtest) {
				macfb_setpalette = v8_brazil_setpalette;
				v8_brazil_cmap_regs =
					ioremap(DAC_BASE, 0x1000);
			}
			break;

		/*
		 * And we *do* mean "weirdos"
		 */
		case MAC_MODEL_TV:
			strcpy(macfb_fix.id, "Mac TV");
			break;

		/*
		 * These don't have colour, so no need to worry
		 */
		case MAC_MODEL_SE30:
		case MAC_MODEL_CLII:
			strcpy(macfb_fix.id, "Monochrome");
			break;

		/*
		 * Powerbooks are particularly difficult.  Many of
		 * them have separate framebuffers for external and
		 * internal video, which is admittedly pretty cool,
		 * but will be a bit of a headache to support here.
		 * Also, many of them are grayscale, and we don't
		 * really support that.
		 */

		/*
		 * Slot 0 ROM says TIM. No external video. B&W.
		 */
		case MAC_MODEL_PB140:
		case MAC_MODEL_PB145:
		case MAC_MODEL_PB170:
			strcpy(macfb_fix.id, "DDC");
			break;

		/*
		 * Internal is GSC, External (if present) is ViSC
		 */
		case MAC_MODEL_PB150:	/* no external video */
		case MAC_MODEL_PB160:
		case MAC_MODEL_PB165:
		case MAC_MODEL_PB180:
		case MAC_MODEL_PB210:
		case MAC_MODEL_PB230:
			strcpy(macfb_fix.id, "GSC");
			break;

		/*
		 * Internal is TIM, External is ViSC
		 */
		case MAC_MODEL_PB165C:
		case MAC_MODEL_PB180C:
			strcpy(macfb_fix.id, "TIM");
			break;

		/*
		 * Internal is CSC, External is Keystone+Ariel.
		 */
		case MAC_MODEL_PB190:	/* external video is optional */
		case MAC_MODEL_PB520:
		case MAC_MODEL_PB250:
		case MAC_MODEL_PB270C:
		case MAC_MODEL_PB280:
		case MAC_MODEL_PB280C:
			strcpy(macfb_fix.id, "CSC");
			macfb_setpalette = csc_setpalette;
			csc_cmap_regs = ioremap(CSC_BASE, 0x1000);
			break;

		default:
			strcpy(macfb_fix.id, "Unknown");
			break;
		}

	fb_info.fbops		= &macfb_ops;
	fb_info.var		= macfb_defined;
	fb_info.fix		= macfb_fix;
	fb_info.pseudo_palette	= pseudo_palette;
	fb_info.flags		= FBINFO_DEFAULT;

	err = fb_alloc_cmap(&fb_info.cmap, video_cmap_len, 0);
	if (err)
		goto fail_unmap;

	err = register_framebuffer(&fb_info);
	if (err)
		goto fail_dealloc;

	fb_info(&fb_info, "%s frame buffer device\n", fb_info.fix.id);

	return 0;

fail_dealloc:
	fb_dealloc_cmap(&fb_info.cmap);
fail_unmap:
	iounmap(fb_info.screen_base);
	iounmap_macfb();
	return err;
}