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

📄 aty128fb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	var.activate = FB_ACTIVATE_NOW;	aty128_init_engine(par);	par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);	par->pdev = pdev;	par->asleep = 0;	par->lock_blank = 0;#ifdef CONFIG_FB_ATY128_BACKLIGHT	if (backlight)		aty128_bl_init(par);#endif	if (register_framebuffer(info) < 0)		return 0;	printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",	       info->node, info->fix.id, video_card);	return 1;	/* success! */}#ifdef CONFIG_PCI/* register a card    ++ajoshi */static int __devinit aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent){	unsigned long fb_addr, reg_addr;	struct aty128fb_par *par;	struct fb_info *info;	int err;#ifndef __sparc__	void __iomem *bios = NULL;#endif	/* Enable device in PCI config */	if ((err = pci_enable_device(pdev))) {		printk(KERN_ERR "aty128fb: Cannot enable PCI device: %d\n",				err);		return -ENODEV;	}	fb_addr = pci_resource_start(pdev, 0);	if (!request_mem_region(fb_addr, pci_resource_len(pdev, 0),				"aty128fb FB")) {		printk(KERN_ERR "aty128fb: cannot reserve frame "				"buffer memory\n");		return -ENODEV;	}	reg_addr = pci_resource_start(pdev, 2);	if (!request_mem_region(reg_addr, pci_resource_len(pdev, 2),				"aty128fb MMIO")) {		printk(KERN_ERR "aty128fb: cannot reserve MMIO region\n");		goto err_free_fb;	}	/* We have the resources. Now virtualize them */	info = framebuffer_alloc(sizeof(struct aty128fb_par), &pdev->dev);	if (info == NULL) {		printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n");		goto err_free_mmio;	}	par = info->par;	info->pseudo_palette = par->pseudo_palette;	/* Virtualize mmio region */	info->fix.mmio_start = reg_addr;	par->regbase = pci_ioremap_bar(pdev, 2);	if (!par->regbase)		goto err_free_info;	/* Grab memory size from the card */	// How does this relate to the resource length from the PCI hardware?	par->vram_size = aty_ld_le32(CNFG_MEMSIZE) & 0x03FFFFFF;	/* Virtualize the framebuffer */	info->screen_base = ioremap(fb_addr, par->vram_size);	if (!info->screen_base)		goto err_unmap_out;	/* Set up info->fix */	info->fix = aty128fb_fix;	info->fix.smem_start = fb_addr;	info->fix.smem_len = par->vram_size;	info->fix.mmio_start = reg_addr;	/* If we can't test scratch registers, something is seriously wrong */	if (!register_test(par)) {		printk(KERN_ERR "aty128fb: Can't write to video register!\n");		goto err_out;	}#ifndef __sparc__	bios = aty128_map_ROM(par, pdev);#ifdef CONFIG_X86	if (bios == NULL)		bios = aty128_find_mem_vbios(par);#endif	if (bios == NULL)		printk(KERN_INFO "aty128fb: BIOS not located, guessing timings.\n");	else {		printk(KERN_INFO "aty128fb: Rage128 BIOS located\n");		aty128_get_pllinfo(par, bios);		pci_unmap_rom(pdev, bios);	}#endif /* __sparc__ */	aty128_timings(par);	pci_set_drvdata(pdev, info);	if (!aty128_init(pdev, ent))		goto err_out;#ifdef CONFIG_MTRR	if (mtrr) {		par->mtrr.vram = mtrr_add(info->fix.smem_start,				par->vram_size, MTRR_TYPE_WRCOMB, 1);		par->mtrr.vram_valid = 1;		/* let there be speed */		printk(KERN_INFO "aty128fb: Rage128 MTRR set to ON\n");	}#endif /* CONFIG_MTRR */	return 0;err_out:	iounmap(info->screen_base);err_unmap_out:	iounmap(par->regbase);err_free_info:	framebuffer_release(info);err_free_mmio:	release_mem_region(pci_resource_start(pdev, 2),			pci_resource_len(pdev, 2));err_free_fb:	release_mem_region(pci_resource_start(pdev, 0),			pci_resource_len(pdev, 0));	return -ENODEV;}static void __devexit aty128_remove(struct pci_dev *pdev){	struct fb_info *info = pci_get_drvdata(pdev);	struct aty128fb_par *par;	if (!info)		return;	par = info->par;	unregister_framebuffer(info);#ifdef CONFIG_FB_ATY128_BACKLIGHT	aty128_bl_exit(info->bl_dev);#endif#ifdef CONFIG_MTRR	if (par->mtrr.vram_valid)		mtrr_del(par->mtrr.vram, info->fix.smem_start,			 par->vram_size);#endif /* CONFIG_MTRR */	iounmap(par->regbase);	iounmap(info->screen_base);	release_mem_region(pci_resource_start(pdev, 0),			   pci_resource_len(pdev, 0));	release_mem_region(pci_resource_start(pdev, 2),			   pci_resource_len(pdev, 2));	framebuffer_release(info);}#endif /* CONFIG_PCI */    /*     *  Blank the display.     */static int aty128fb_blank(int blank, struct fb_info *fb){	struct aty128fb_par *par = fb->par;	u8 state;	if (par->lock_blank || par->asleep)		return 0;	switch (blank) {	case FB_BLANK_NORMAL:		state = 4;		break;	case FB_BLANK_VSYNC_SUSPEND:		state = 6;		break;	case FB_BLANK_HSYNC_SUSPEND:		state = 5;		break;	case FB_BLANK_POWERDOWN:		state = 7;		break;	case FB_BLANK_UNBLANK:	default:		state = 0;		break;	}	aty_st_8(CRTC_EXT_CNTL+1, state);	if (par->chip_gen == rage_M3) {		aty128_set_crt_enable(par, par->crt_on && !blank);		aty128_set_lcd_enable(par, par->lcd_on && !blank);	}	return 0;}/* *  Set a single color register. The values supplied are already *  rounded down to the hardware's capabilities (according to the *  entries in the var structure). Return != 0 for invalid regno. */static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,			      u_int transp, struct fb_info *info){	struct aty128fb_par *par = info->par;	if (regno > 255	    || (par->crtc.depth == 16 && regno > 63)	    || (par->crtc.depth == 15 && regno > 31))		return 1;	red >>= 8;	green >>= 8;	blue >>= 8;	if (regno < 16) {		int i;		u32 *pal = info->pseudo_palette;		switch (par->crtc.depth) {		case 15:			pal[regno] = (regno << 10) | (regno << 5) | regno;			break;		case 16:			pal[regno] = (regno << 11) | (regno << 6) | regno;			break;		case 24:			pal[regno] = (regno << 16) | (regno << 8) | regno;			break;		case 32:			i = (regno << 8) | regno;			pal[regno] = (i << 16) | i;			break;		}	}	if (par->crtc.depth == 16 && regno > 0) {		/*		 * With the 5-6-5 split of bits for RGB at 16 bits/pixel, we		 * have 32 slots for R and B values but 64 slots for G values.		 * Thus the R and B values go in one slot but the G value		 * goes in a different slot, and we have to avoid disturbing		 * the other fields in the slots we touch.		 */		par->green[regno] = green;		if (regno < 32) {			par->red[regno] = red;			par->blue[regno] = blue;			aty128_st_pal(regno * 8, red, par->green[regno*2],				      blue, par);		}		red = par->red[regno/2];		blue = par->blue[regno/2];		regno <<= 2;	} else if (par->crtc.bpp == 16)		regno <<= 3;	aty128_st_pal(regno, red, green, blue, par);	return 0;}#define ATY_MIRROR_LCD_ON	0x00000001#define ATY_MIRROR_CRT_ON	0x00000002/* out param: u32*	backlight value: 0 to 15 */#define FBIO_ATY128_GET_MIRROR	_IOR('@', 1, __u32)/* in param: u32*	backlight value: 0 to 15 */#define FBIO_ATY128_SET_MIRROR	_IOW('@', 2, __u32)static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg){	struct aty128fb_par *par = info->par;	u32 value;	int rc;    	switch (cmd) {	case FBIO_ATY128_SET_MIRROR:		if (par->chip_gen != rage_M3)			return -EINVAL;		rc = get_user(value, (__u32 __user *)arg);		if (rc)			return rc;		par->lcd_on = (value & 0x01) != 0;		par->crt_on = (value & 0x02) != 0;		if (!par->crt_on && !par->lcd_on)			par->lcd_on = 1;		aty128_set_crt_enable(par, par->crt_on);			aty128_set_lcd_enable(par, par->lcd_on);			return 0;	case FBIO_ATY128_GET_MIRROR:		if (par->chip_gen != rage_M3)			return -EINVAL;		value = (par->crt_on << 1) | par->lcd_on;		return put_user(value, (__u32 __user *)arg);	}	return -EINVAL;}#if 0    /*     *  Accelerated functions     */static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,				   u_int width, u_int height,				   struct fb_info_aty128 *par){    u32 save_dp_datatype, save_dp_cntl, dstval;    if (!width || !height)        return;    dstval = depth_to_dst(par->current_par.crtc.depth);    if (dstval == DST_24BPP) {        srcx *= 3;        dstx *= 3;        width *= 3;    } else if (dstval == -EINVAL) {        printk("aty128fb: invalid depth or RGBA\n");        return;    }    wait_for_fifo(2, par);    save_dp_datatype = aty_ld_le32(DP_DATATYPE);    save_dp_cntl     = aty_ld_le32(DP_CNTL);    wait_for_fifo(6, par);    aty_st_le32(SRC_Y_X, (srcy << 16) | srcx);    aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT);    aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);    aty_st_le32(DP_DATATYPE, save_dp_datatype | dstval | SRC_DSTCOLOR);    aty_st_le32(DST_Y_X, (dsty << 16) | dstx);    aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);    par->blitter_may_be_busy = 1;    wait_for_fifo(2, par);    aty_st_le32(DP_DATATYPE, save_dp_datatype);    aty_st_le32(DP_CNTL, save_dp_cntl); }    /*     * Text mode accelerated functions     */static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,			int height, int width){    sx     *= fontwidth(p);    sy     *= fontheight(p);    dx     *= fontwidth(p);    dy     *= fontheight(p);    width  *= fontwidth(p);    height *= fontheight(p);    aty128_rectcopy(sx, sy, dx, dy, width, height,			(struct fb_info_aty128 *)p->fb_info);}#endif /* 0 */static void aty128_set_suspend(struct aty128fb_par *par, int suspend){	u32	pmgt;	struct pci_dev *pdev = par->pdev;	if (!par->pm_reg)		return;			/* Set the chip into the appropriate suspend mode (we use D2,	 * D3 would require a complete re-initialisation of the chip,	 * including PCI config registers, clocks, AGP configuration, ...)	 *	 * For resume, the core will have already brought us back to D0	 */	if (suspend) {		/* Make sure CRTC2 is reset. Remove that the day we decide to		 * actually use CRTC2 and replace it with real code for disabling		 * the CRTC2 output during sleep		 */		aty_st_le32(CRTC2_GEN_CNTL, aty_ld_le32(CRTC2_GEN_CNTL) &			~(CRTC2_EN));		/* Set the power management mode to be PCI based */		/* Use this magic value for now */		pmgt = 0x0c005407;		aty_st_pll(POWER_MANAGEMENT, pmgt);		(void)aty_ld_pll(POWER_MANAGEMENT);		aty_st_le32(BUS_CNTL1, 0x00000010);		aty_st_le32(MEM_POWER_MISC, 0x0c830000);		mdelay(100);		/* Switch PCI power management to D2 */		pci_set_power_state(pdev, PCI_D2);	}}static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state){	struct fb_info *info = pci_get_drvdata(pdev);	struct aty128fb_par *par = info->par;	/* Because we may change PCI D state ourselves, we need to	 * first save the config space content so the core can	 * restore it properly on resume.	 */	pci_save_state(pdev);	/* We don't do anything but D2, for now we return 0, but	 * we may want to change that. How do we know if the BIOS	 * can properly take care of D3 ? Also, with swsusp, we	 * know we'll be rebooted, ...	 */#ifndef CONFIG_PPC_PMAC	/* HACK ALERT ! Once I find a proper way to say to each driver	 * individually what will happen with it's PCI slot, I'll change	 * that. On laptops, the AGP slot is just unclocked, so D2 is	 * expected, while on desktops, the card is powered off	 */	return 0;#endif /* CONFIG_PPC_PMAC */	 	if (state.event == pdev->dev.power.power_state.event)		return 0;	printk(KERN_DEBUG "aty128fb: suspending...\n");		acquire_console_sem();	fb_set_suspend(info, 1);	/* Make sure engine is reset */	wait_for_idle(par);	aty128_reset_engine(par);	wait_for_idle(par);	/* Blank display and LCD */	aty128fb_blank(FB_BLANK_POWERDOWN, info);	/* Sleep */	par->asleep = 1;	par->lock_blank = 1;#ifdef CONFIG_PPC_PMAC	/* On powermac, we have hooks to properly suspend/resume AGP now,	 * use them here. We'll ultimately need some generic support here,	 * but the generic code isn't quite ready for that yet	 */	pmac_suspend_agp_for_card(pdev);#endif /* CONFIG_PPC_PMAC */	/* We need a way to make sure the fbdev layer will _not_ touch the	 * framebuffer before we put the chip to suspend state. On 2.4, I	 * used dummy fb ops, 2.5 need proper support for this at the	 * fbdev level	 */	if (state.event != PM_EVENT_ON)		aty128_set_suspend(par, 1);	release_console_sem();	pdev->dev.power.power_state = state;	return 0;}static int aty128_do_resume(struct pci_dev *pdev){	struct fb_info *info = pci_get_drvdata(pdev);	struct aty128fb_par *par = info->par;	if (pdev->dev.power.power_state.event == PM_EVENT_ON)		return 0;	/* PCI state will have been restored by the core, so	 * we should be in D0 now with

⌨️ 快捷键说明

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