⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smifb.c

📁 sm501-712 linux驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
smifb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
	*var = *get_con_var(info, con);
	return 0;
}

static int
smifb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
{
	struct fb_cmap *dcmap = get_con_cmap(info, con);

	fb_copy_cmap(dcmap, cmap, kspc ? 0 : 2);
	return 0;
}

static struct fb_ops smifb_ops = {
	owner:			THIS_MODULE,
	fb_get_fix:		smifb_get_fix,
	fb_get_var:		smifb_get_var,
	fb_set_var:		smifb_set_var,
	fb_get_cmap:	smifb_get_cmap,
	fb_set_cmap:	smifb_set_cmap,
};

/*
 *  smifb_switch():
 *	Change to the specified console.  Palette and video mode
 *      are changed to the console's stored parameters.
 */
static int smifb_switch(int con, struct fb_info *info)
{
	struct smifb_info *sfb = (struct smifb_info *)info;
	struct display *disp;
	struct fb_cmap *cmap;

	if (con == sfb->currcon) {
		return 0;
	}

	if (sfb->currcon >= 0) {
		disp = fb_display + sfb->currcon;

		/*
		 * Save the old colormap and video mode.
		 */
		disp->var = sfb->fb.var;
		if (disp->cmap.len)
			fb_copy_cmap(&sfb->fb.cmap, &disp->cmap, 0);
	}

	sfb->currcon = con;
	disp = fb_display + con;

	if (disp->cmap.len)
		cmap = &disp->cmap;
	else
		cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);

	fb_copy_cmap(cmap, &sfb->fb.cmap, 0);

	sfb->fb.var = disp->var;
	sfb->fb.var.activate = FB_ACTIVATE_NOW;

	smifb_set_var(&sfb->fb.var, con, info);

	return 0;
}

/*
 * Formal definition of the VESA spec:
 *  On
 *  	This refers to the state of the display when it is in full operation
 *  Stand-By
 *  	This defines an optional operating state of minimal power reduction with
 *  	the shortest recovery time
 *  Suspend
 *  	This refers to a level of power management in which substantial power
 *  	reduction is achieved by the display.  The display can have a longer
 *  	recovery time from this state than from the Stand-by state
 *  Off
 *  	This indicates that the display is consuming the lowest level of power
 *  	and is non-operational. Recovery from this state may optionally require
 *  	the user to manually power on the monitor
 *
 *  Now, the fbdev driver adds an additional state, (blank), where they
 *  turn off the video (maybe by colormap tricks), but don't mess with the
 *  video itself: think of it semantically between on and Stand-By.
 *
 *  So here's what we should do in our fbdev blank routine:
 *
 *  	VESA_NO_BLANKING (mode 0)	Video on,  front/back light on
 *  	VESA_VSYNC_SUSPEND (mode 1)  	Video on,  front/back light off
 *  	VESA_HSYNC_SUSPEND (mode 2)  	Video on,  front/back light off
 *  	VESA_POWERDOWN (mode 3)		Video off, front/back light off
 *
 *  This will match the matrox implementation.
 */
/*
 * smifb_blank():
 *	Blank the display by setting all palette values to zero.  Note, the
 * 	12 and 16 bpp modes don't really use the palette, so this will not
 *      blank the display in all modes.
 */
static void smifb_blank(int blank, struct fb_info *info)
{
//	struct smifb_info *sfb = (struct smifb_info *)info;

	switch (blank) {
	case VESA_POWERDOWN:
	case VESA_VSYNC_SUSPEND:
	case VESA_HSYNC_SUSPEND:
	case VESA_NO_BLANKING:
	}
}

static int smifb_updatevar(int con, struct fb_info *info)
{
	return 0;
}

/*
 * Alloc struct smifb_info and assign the default value
 */
static struct smifb_info * __devinit
smi_alloc_fb_info(struct pci_dev *dev, char *name)
{
    struct smifb_info *sfb;

    sfb = kmalloc(sizeof(struct smifb_info) + sizeof(struct display) +
                  sizeof(u32) * 16, GFP_KERNEL);

    if (!sfb)
        return NULL;

    memset(sfb, 0, sizeof(struct smifb_info) + sizeof(struct display));

    sfb->currcon        = -1;
    sfb->dev            = dev;

    strcpy(sfb->fb.fix.id, name);

    sfb->fb.fix.type		= FB_TYPE_PACKED_PIXELS;
    sfb->fb.fix.type_aux	= 0;
    sfb->fb.fix.xpanstep	= 0;
    sfb->fb.fix.ypanstep	= 0;
    sfb->fb.fix.ywrapstep	= 0;
    sfb->fb.fix.accel		= FB_ACCEL_NONE;

    sfb->fb.var.nonstd		= 0;
    sfb->fb.var.activate	= FB_ACTIVATE_NOW;
    sfb->fb.var.height		= -1;
    sfb->fb.var.width		= -1;
    sfb->fb.var.accel_flags	= 0;
    sfb->fb.var.vmode		= FB_VMODE_NONINTERLACED;

    strcpy(sfb->fb.modename, sfb->fb.fix.id);
    strcpy(sfb->fb.fontname, "VGA8x8");

    sfb->fb.fbops		= &smifb_ops;
    sfb->fb.changevar	= NULL;
    sfb->fb.switch_con	= smifb_switch;
    sfb->fb.updatevar	= smifb_updatevar;
    sfb->fb.blank		= smifb_blank;
    sfb->fb.flags		= FBINFO_FLAG_DEFAULT;
    sfb->fb.node		= -1;
    sfb->fb.disp		= (struct display *)(sfb + 1);
    sfb->fb.pseudo_palette	= (void *)(sfb->fb.disp + 1);

    return sfb;
}

/*
 * Unmap in the memory mapped IO registers
 *
 */

static void __devinit
smi_unmap_mmio(struct smifb_info *sfb)
{
    if (sfb && SMILFB)
    {
        iounmap(SMILFB);
        SMIRegs = NULL;
    }
}

/*
 * Map in the screen memory
 *
 */
static int __devinit
smi_map_smem(struct smifb_info *sfb, struct pci_dev *dev, u_long smem_len)
{
    sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
    sfb->fb.fix.smem_len  = smem_len;

    sfb->fb.screen_base = SMILFB;

    if (!sfb->fb.screen_base)
    {
        printk("%s: unable to map screen memory\n",sfb->fb.fix.id);
        return -ENOMEM;
    }

    return 0;
}


/*
 * Unmap in the screen memory
 *
 */
static void __devinit
smi_unmap_smem(struct smifb_info *sfb)
{
    if (sfb && sfb->fb.screen_base)
    {
        iounmap(sfb->fb.screen_base);
        sfb->fb.screen_base = NULL;
    }
}

/*
 * We need to wake up the LynxEM+, and make sure its in linear memory mode.
 */
static inline void __devinit
smi_init_hw(void)
{
    outb(0x18, 0x3c4);
    outb(0x11, 0x3c5);
}

static void __devinit
smi_free_fb_info(struct smifb_info *sfb)
{
	if (sfb) {
		fb_alloc_cmap(&sfb->fb.cmap, 0, 0);
		kfree(sfb);
	}
}


u16 SMI_ChipIDs[numChipIDs] = {0x710, 0x712, 0x720};

int __init smifb_init(void)
{
    struct smifb_info *sfb;
    u_long smem_size;
    char name[16];
    int err;
    u8 val;
	char *m_pLAW;
	ulong m_pLAWPhysical;

	struct pci_dev *pdev = NULL;
	int i = 0;

	do {
		pdev = pci_find_device(0x126f,SMI_ChipIDs[i], pdev);
		if (pdev == NULL)
			i++;
		else {
			hw.chipID = SMI_ChipIDs[i];
			break;
		}
	} while (i< numChipIDs);

    sprintf(name, "smifb");

    err = pci_enable_device(pdev); // enable SMI video chip
    if (err) {
        return err;
    }

    err = -ENOMEM;
    sfb = smi_alloc_fb_info(pdev, name);
    if (!sfb) {
        goto failed;
    }

    smi_init_hw();

	// Map address and memory detection
	m_pLAWPhysical = pci_resource_start(pdev,0);
	switch (hw.chipID) {
		case 0x710:
		case 0x712:
			sfb->fb.fix.mmio_start = m_pLAWPhysical + 0x00700000;
			sfb->fb.fix.mmio_len   = 0x00100000;

    		hw.m_pLFB = SMILFB = ioremap(m_pLAWPhysical, 0x00800000);
    		hw.m_pMMIO = SMIRegs = SMILFB + 0x00700000;
			hw.m_pDPR = hw.m_pLFB + 0x00408000;
			hw.m_pVPR = hw.m_pLFB + 0x0040c000;

    		if (!SMIRegs)
    		{
        		printk("%s: unable to map memory mapped IO\n",sfb->fb.fix.id);
        		return -ENOMEM;
    		}

			smi_seqw(0x62,0x7A);
    		smi_seqw(0x6a,0x0c);
    		smi_seqw(0x6b,0x02);
    		smem_size = 0x00400000;

    		//LynxEM+ memory dection
    		*(u32 *)(SMILFB + 4) = 0xAA551133;
    		if (*(u32 *)(SMILFB + 4) != 0xAA551133)
    		{
    			smem_size = 0x00200000;
        		// Program the MCLK to 130 MHz
        		smi_seqw(0x6a,0x12);
        		smi_seqw(0x6b,0x02);
        		smi_seqw(0x62,0x3e);
     		}
			break;
		case 0x720:
			sfb->fb.fix.mmio_start = m_pLAWPhysical + 0x000c0000;
			sfb->fb.fix.mmio_len   = 0x00040000;

			m_pLAW = ioremap(m_pLAWPhysical, 0x00a00000);
			hw.m_pLFB = SMILFB = m_pLAW + 0x00200000;
			hw.m_pMMIO = SMIRegs = m_pLAW + 0x000c0000;
			hw.m_pDPR = m_pLAW;
			hw.m_pVPR = m_pLAW + 0x800;

			smi_seqw(0x62,0xff);
			smi_seqw(0x6a,0x0d);
			smi_seqw(0x6b,0x02);
			smem_size = 0x00400000;

			break;
	}

	sfb->fb.var.xres = 640;
	sfb->fb.var.yres = 480;
	sfb->fb.var.bits_per_pixel = 16;

   	sfb->fb.var.xres_virtual = sfb->fb.var.xres;

	sfb->fb.var.yres_virtual = sfb->fb.var.yres;

    err = smi_map_smem(sfb, pdev, smem_size);

    if (err) {
		goto failed;
    }

	smifb_set_var(&sfb->fb.var, -1, &sfb->fb);

	err = register_framebuffer(&sfb->fb);
	if (err < 0) {
		goto failed;
    }

	MOD_INC_USE_COUNT;
	printk("Silicon Motion, Inc. LynxEM+ Init complete.\n");

	return 0;

failed:
	smi_unmap_smem(sfb);
	smi_unmap_mmio(sfb);
	smi_free_fb_info(sfb);

	return err;
}_V,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -