?? smifb.c
字號:
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 + -