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

📄 ps3fb.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (frame > par->num_frames - 1) {		dev_dbg(info->device, "%s: invalid frame number (%u)\n",			__func__, frame);		error = -EINVAL;		goto out;	}	i = par->res_index;	xdr_line_length = info->fix.line_length;	ddr_line_length = ps3fb_res[i].xres * BPP;	xdr_base = frame * info->var.yres_virtual * xdr_line_length;	ddr_base = frame * ps3fb_res[i].yres * ddr_line_length;	ps3fb_sync_image(info->device, ddr_base + par->full_offset,			 ddr_base + par->fb_offset, xdr_base + par->pan_offset,			 par->width, par->height, ddr_line_length,			 xdr_line_length);out:	return error;}static int ps3fb_open(struct fb_info *info, int user){	atomic_inc(&ps3fb.f_count);	return 0;}static int ps3fb_release(struct fb_info *info, int user){	if (atomic_dec_and_test(&ps3fb.f_count)) {		if (atomic_read(&ps3fb.ext_flip)) {			atomic_set(&ps3fb.ext_flip, 0);			if (!try_acquire_console_sem()) {				ps3fb_sync(info, 0);	/* single buffer */				release_console_sem();			}		}	}	return 0;}    /*     *  Setting the video mode has been split into two parts.     *  First part, xxxfb_check_var, must not write anything     *  to hardware, it should only verify and adjust var.     *  This means it doesn't alter par but it does use hardware     *  data from it to check this var.     */static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){	u32 xdr_line_length, ddr_line_length;	int mode;	dev_dbg(info->device, "var->xres:%u info->var.xres:%u\n", var->xres,		info->var.xres);	dev_dbg(info->device, "var->yres:%u info->var.yres:%u\n", var->yres,		info->var.yres);	/* FIXME For now we do exact matches only */	mode = ps3fb_find_mode(var, &ddr_line_length, &xdr_line_length);	if (!mode)		return -EINVAL;	/* Virtual screen */	if (var->xres_virtual < var->xres)		var->xres_virtual = var->xres;	if (var->yres_virtual < var->yres)		var->yres_virtual = var->yres;	if (var->xres_virtual > xdr_line_length / BPP) {		dev_dbg(info->device,			"Horizontal virtual screen size too large\n");		return -EINVAL;	}	if (var->xoffset + var->xres > var->xres_virtual ||	    var->yoffset + var->yres > var->yres_virtual) {		dev_dbg(info->device, "panning out-of-range\n");		return -EINVAL;	}	/* We support ARGB8888 only */	if (var->bits_per_pixel > 32 || var->grayscale ||	    var->red.offset > 16 || var->green.offset > 8 ||	    var->blue.offset > 0 || var->transp.offset > 24 ||	    var->red.length > 8 || var->green.length > 8 ||	    var->blue.length > 8 || var->transp.length > 8 ||	    var->red.msb_right || var->green.msb_right ||	    var->blue.msb_right || var->transp.msb_right || var->nonstd) {		dev_dbg(info->device, "We support ARGB8888 only\n");		return -EINVAL;	}	var->bits_per_pixel = 32;	var->red.offset = 16;	var->green.offset = 8;	var->blue.offset = 0;	var->transp.offset = 24;	var->red.length = 8;	var->green.length = 8;	var->blue.length = 8;	var->transp.length = 8;	var->red.msb_right = 0;	var->green.msb_right = 0;	var->blue.msb_right = 0;	var->transp.msb_right = 0;	/* Rotation is not supported */	if (var->rotate) {		dev_dbg(info->device, "Rotation is not supported\n");		return -EINVAL;	}	/* Memory limit */	if (var->yres_virtual * xdr_line_length > ps3fb.xdr_size) {		dev_dbg(info->device, "Not enough memory\n");		return -ENOMEM;	}	var->height = -1;	var->width = -1;	return 0;}    /*     * This routine actually sets the video mode.     */static int ps3fb_set_par(struct fb_info *info){	struct ps3fb_par *par = info->par;	unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines;	int i;	unsigned long offset;	u64 dst;	dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n",		info->var.xres, info->var.xres_virtual,		info->var.yres, info->var.yres_virtual, info->var.pixclock);	mode = ps3fb_find_mode(&info->var, &ddr_line_length, &xdr_line_length);	if (!mode)		return -EINVAL;	i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode);	par->res_index = i;	info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);	info->fix.smem_len = ps3fb.xdr_size;	info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;	info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;	info->fix.line_length = xdr_line_length;	info->screen_base = (char __iomem *)ps3fb.xdr_ea;	par->num_frames = ps3fb.xdr_size /			  max(ps3fb_res[i].yres * ddr_line_length,			      info->var.yres_virtual * xdr_line_length);	/* Keep the special bits we cannot set using fb_var_screeninfo */	par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode;	par->width = info->var.xres;	par->height = info->var.yres;	offset = VP_OFF(i);	par->fb_offset = GPU_ALIGN_UP(offset);	par->full_offset = par->fb_offset - offset;	par->pan_offset = info->var.yoffset * xdr_line_length +			  info->var.xoffset * BPP;	if (par->new_mode_id != par->mode_id) {		if (ps3av_set_video_mode(par->new_mode_id)) {			par->new_mode_id = par->mode_id;			return -EINVAL;		}		par->mode_id = par->new_mode_id;	}	/* Clear XDR frame buffer memory */	memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size);	/* Clear DDR frame buffer memory */	lines = ps3fb_res[i].yres * par->num_frames;	if (par->full_offset)		lines++;	maxlines = ps3fb.xdr_size / ddr_line_length;	for (dst = 0; lines; dst += maxlines * ddr_line_length) {		unsigned int l = min(lines, maxlines);		ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l,				 ddr_line_length, ddr_line_length);		lines -= l;	}	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 ps3fb_setcolreg(unsigned int regno, unsigned int red,			   unsigned int green, unsigned int blue,			   unsigned int transp, struct fb_info *info){	if (regno >= 16)		return 1;	red >>= 8;	green >>= 8;	blue >>= 8;	transp >>= 8;	((u32 *)info->pseudo_palette)[regno] = transp << 24 | red << 16 |					       green << 8 | blue;	return 0;}static int ps3fb_pan_display(struct fb_var_screeninfo *var,			     struct fb_info *info){	struct ps3fb_par *par = info->par;	par->pan_offset = var->yoffset * info->fix.line_length +			  var->xoffset * BPP;	return 0;}    /*     *  As we have a virtual frame buffer, we need our own mmap function     */static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma){	unsigned long size, offset;	size = vma->vm_end - vma->vm_start;	offset = vma->vm_pgoff << PAGE_SHIFT;	if (offset + size > info->fix.smem_len)		return -EINVAL;	offset += info->fix.smem_start;	if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,			    size, vma->vm_page_prot))		return -EAGAIN;	dev_dbg(info->device, "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n",		offset, vma->vm_start);	return 0;}    /*     * Blank the display     */static int ps3fb_blank(int blank, struct fb_info *info){	int retval;	dev_dbg(info->device, "%s: blank:%d\n", __func__, blank);	switch (blank) {	case FB_BLANK_POWERDOWN:	case FB_BLANK_HSYNC_SUSPEND:	case FB_BLANK_VSYNC_SUSPEND:	case FB_BLANK_NORMAL:		retval = ps3av_video_mute(1);	/* mute on */		if (!retval)			ps3fb.is_blanked = 1;		break;	default:		/* unblank */		retval = ps3av_video_mute(0);	/* mute off */		if (!retval)			ps3fb.is_blanked = 0;		break;	}	return retval;}static int ps3fb_get_vblank(struct fb_vblank *vblank){	memset(vblank, 0, sizeof(*vblank));	vblank->flags = FB_VBLANK_HAVE_VSYNC;	return 0;}static int ps3fb_wait_for_vsync(u32 crtc){	int ret;	u64 count;	count = ps3fb.vblank_count;	ret = wait_event_interruptible_timeout(ps3fb.wait_vsync,					       count != ps3fb.vblank_count,					       HZ / 10);	if (!ret)		return -ETIMEDOUT;	return 0;}static void ps3fb_flip_ctl(int on, void *data){	struct ps3fb_priv *priv = data;	if (on)		atomic_dec_if_positive(&priv->ext_flip);	else		atomic_inc(&priv->ext_flip);}    /*     * ioctl     */static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,		       unsigned long arg){	void __user *argp = (void __user *)arg;	u32 val;	int retval = -EFAULT;	switch (cmd) {	case FBIOGET_VBLANK:		{			struct fb_vblank vblank;			dev_dbg(info->device, "FBIOGET_VBLANK:\n");			retval = ps3fb_get_vblank(&vblank);			if (retval)				break;			if (copy_to_user(argp, &vblank, sizeof(vblank)))				retval = -EFAULT;			break;		}	case FBIO_WAITFORVSYNC:		{			u32 crt;			dev_dbg(info->device, "FBIO_WAITFORVSYNC:\n");			if (get_user(crt, (u32 __user *) arg))				break;			retval = ps3fb_wait_for_vsync(crt);			break;		}	case PS3FB_IOCTL_SETMODE:		{			struct ps3fb_par *par = info->par;			const struct fb_videomode *mode;			struct fb_var_screeninfo var;			if (copy_from_user(&val, argp, sizeof(val)))				break;			if (!(val & PS3AV_MODE_MASK)) {				u32 id = ps3av_get_auto_mode();				if (id > 0)					val = (val & ~PS3AV_MODE_MASK) | id;			}			dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val);			retval = -EINVAL;			mode = ps3fb_default_mode(val);			if (mode) {				var = info->var;				fb_videomode_to_var(&var, mode);				acquire_console_sem();				info->flags |= FBINFO_MISC_USEREVENT;				/* Force, in case only special bits changed */				var.activate |= FB_ACTIVATE_FORCE;				par->new_mode_id = val;				retval = fb_set_var(info, &var);				info->flags &= ~FBINFO_MISC_USEREVENT;				release_console_sem();			}			break;		}	case PS3FB_IOCTL_GETMODE:		val = ps3av_get_mode();		dev_dbg(info->device, "PS3FB_IOCTL_GETMODE:%x\n", val);		if (!copy_to_user(argp, &val, sizeof(val)))			retval = 0;		break;	case PS3FB_IOCTL_SCREENINFO:		{			struct ps3fb_par *par = info->par;			struct ps3fb_ioctl_res res;			dev_dbg(info->device, "PS3FB_IOCTL_SCREENINFO:\n");			res.xres = info->fix.line_length / BPP;			res.yres = info->var.yres_virtual;			res.xoff = (res.xres - info->var.xres) / 2;			res.yoff = (res.yres - info->var.yres) / 2;			res.num_frames = par->num_frames;			if (!copy_to_user(argp, &res, sizeof(res)))				retval = 0;			break;		}	case PS3FB_IOCTL_ON:		dev_dbg(info->device, "PS3FB_IOCTL_ON:\n");		atomic_inc(&ps3fb.ext_flip);		retval = 0;		break;	case PS3FB_IOCTL_OFF:		dev_dbg(info->device, "PS3FB_IOCTL_OFF:\n");		atomic_dec_if_positive(&ps3fb.ext_flip);		retval = 0;		break;	case PS3FB_IOCTL_FSEL:		if (copy_from_user(&val, argp, sizeof(val)))			break;		dev_dbg(info->device, "PS3FB_IOCTL_FSEL:%d\n", val);		acquire_console_sem();		retval = ps3fb_sync(info, val);		release_console_sem();		break;	default:		retval = -ENOIOCTLCMD;		break;	}	return retval;}static int ps3fbd(void *arg){	struct fb_info *info = arg;	set_freezable();	while (!kthread_should_stop()) {		try_to_freeze();		set_current_state(TASK_INTERRUPTIBLE);		if (ps3fb.is_kicked) {			ps3fb.is_kicked = 0;			acquire_console_sem();

⌨️ 快捷键说明

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