您尚未登录。

楼主 # 2022-06-25 10:40:47

jkl
会员
注册时间: 2019-11-18
已发帖子: 265
积分: 148.5

发生一件很奇怪的事情,不知道问题出在哪里,大家帮忙看一下?

在应用层调用ioctl函数,内核获取的应用层传过去的一个结构体内容,其中有两个结构体成员内容对不上,其他的结构体成员值都是对的,这是怎么回事?
这是驱动层的IOCTL:

long disp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
//	printk("%s %d %s\n",__FILE__,__LINE__,__FUNCTION__);
	unsigned long karg[4];
	unsigned long ubuffer[4] = { 0 };
	s32 ret = 0;
	int num_screens = 2;
	struct disp_manager *mgr = NULL;
	struct disp_device *dispdev = NULL;
	struct disp_enhance *enhance = NULL;
	struct disp_smbl *smbl = NULL;
	struct disp_capture *cptr = NULL;
#if defined(SUPPORT_EINK)
	struct disp_eink_manager *eink_manager = NULL;
#endif

#ifdef EINK_FLUSH_TIME_TEST
	do_gettimeofday(&ioctrl_start_timer);
#endif				/*test eink time */

	num_screens = bsp_disp_feat_get_num_screens();

	if (copy_from_user
	    ((void *)karg, (void __user *)arg, 4 * sizeof(unsigned long))) {
		__wrn("copy_from_user fail\n");
		return -EFAULT;
	}
	
	ubuffer[0] = *(unsigned long *)karg;
	ubuffer[1] = (*(unsigned long *)(karg + 1));
	ubuffer[2] = (*(unsigned long *)(karg + 2));
	ubuffer[3] = (*(unsigned long *)(karg + 3));

	if (ubuffer[0] < num_screens)
		mgr = g_disp_drv.mgr[ubuffer[0]];
	if (mgr) {
		dispdev = mgr->device;
		enhance = mgr->enhance;
		smbl = mgr->smbl;
		cptr = mgr->cptr;
	}
#if defined(SUPPORT_EINK)
	eink_manager = g_disp_drv.eink_manager[0];

	if (!eink_manager)
		__wrn("eink_manager is NULL!\n");

#endif

	if (cmd < DISP_FB_REQUEST) {
		if (ubuffer[0] >= num_screens) {
			__wrn
			    ("para err, cmd = 0x%x,screen id = %d\n",
			     cmd, (int)ubuffer[0]);
			return -1;
		}
	}
	if (DISPLAY_DEEP_SLEEP & suspend_status) {
		__wrn("ioctl:%x fail when in suspend!\n", cmd);
		return -1;
	}

	if (cmd == DISP_print)
		__wrn("cmd:0x%x,%ld,%ld\n", cmd, ubuffer[0], ubuffer[1]);

	switch (cmd) {
	。。。。。。。。
		/* ----layer---- */
	case DISP_LAYER_SET_CONFIG:
	{
		printk("%s %d %s\n",__FILE__,__LINE__,__FUNCTION__);
		unsigned int i = 0;
		const unsigned int lyr_cfg_size = ARRAY_SIZE(lyr_cfg);

		mutex_lock(&g_disp_drv.mlock);

		if (ubuffer[2] > lyr_cfg_size) {
			__wrn("Total layer number is %d\n", lyr_cfg_size);
			mutex_unlock(&g_disp_drv.mlock);
			return -EFAULT;
		}

		if (copy_from_user(lyr_cfg,
			(void __user *)ubuffer[1],
			sizeof(struct disp_layer_config) * ubuffer[2]))	{
			__wrn("copy_from_user fail\n");
			mutex_unlock(&g_disp_drv.mlock);

			return  -EFAULT;
		}

		printk("lyr_cfg[0].info.alpha_mode = %d,lyr_cfg[0].info.alpha_value = %x,lyr_cfg[0].info.fb.size[0].width = %d,lyr_cfg[0].info.fb.size[0].height = %d,lyr_cfg[0].channel = %d,lyr_cfg[0].layer_id = %d,lyr_cfg[0].enable = %d\n",
			lyr_cfg[0].info.alpha_mode ,
			lyr_cfg[0].info.alpha_value ,
			lyr_cfg[0].info.fb.size[0].width ,
			lyr_cfg[0].info.fb.size[0].height ,
			lyr_cfg[0].channel ,
			lyr_cfg[0].layer_id ,
			lyr_cfg[0].enable);


#if !defined(CONFIG_EINK_PANEL_USED)
		printk("%s %d %s\n",__FILE__,__LINE__,__FUNCTION__);
		if (mgr && mgr->set_layer_config)
			ret = mgr->set_layer_config(mgr, lyr_cfg, ubuffer[2]);
		printk("%s %d %s\n",__FILE__,__LINE__,__FUNCTION__);
#endif
		mutex_unlock(&g_disp_drv.mlock);
		break;
	}



	。。。。


	default:
		ret = disp_ioctl_extend(cmd, (unsigned long)ubuffer);
		break;
	}

	return ret;
}

这是应用层测试主函数:

int main(int argc, char *argv[])
{
	unsigned long arg[3];
/* 一个 struct disp_layer_config 结构体对应一个图层的全部信息 */
	struct disp_layer_config config;
	unsigned int width = 1024;
	unsigned int height = 600;
	unsigned int ret = 0;
	

	disp = open("/dev/disp", O_RDWR);
    if (disp == -1) {
        printf("hdmitester: open /dev/disp failed(%s)\n", strerror(errno));
		return 0;
//        goto err;
    }

	memset(&config, 0, sizeof(struct disp_layer_config));
	/* 选择图层所属的通道以及本图层 ID(0-3)*/
	config.channel = 0;
	config.layer_id = 0;
	config.enable = 1;
	config.info.mode = LAYER_MODE_BUFFER;
	// config.info.fb.addr[0] = (unsigned long long)mem_in; //FB 物理地址
	config.info.fb.size[0].width = width;
	config.info.fb.size[0].height = height;
	config.info.fb.align[0] = 4;//bytes
	config.info.fb.format = DISP_FORMAT_ARGB_8888; //DISP_FORMAT_YUV420_P
	
	/* crop 表示裁剪区域的大小 */
	config.info.fb.crop.x = 0;
	config.info.fb.crop.y = 0;
	/* 定点小数。 高 32bit 为整数,低 32bit 为小数 */ 
	config.info.fb.crop.width = ((unsigned long)width) << 32; 
	/* 定点小数。 高 32bit 为整数,低 32bit 为小数 */
	config.info.fb.crop.height= ((unsigned long)height)<<32;
	config.info.fb.flags = DISP_BF_NORMAL;
	config.info.fb.scan = DISP_SCAN_PROGRESSIVE;
	config.info.alpha_mode = 1; //global pixel alpha
	config.info.alpha_value = 0xff;//global alpha value
	/* 显示窗口的大小 */
	config.info.screen_win.x = 0;
	config.info.screen_win.y = 0;
	config.info.screen_win.width = width;
	config.info.screen_win.height= height;
	config.info.id = 0;
	/* 上层调用 DE 显示引擎所用的 ioctl 接口 */
	arg[0] = 0;//screen 0 即选择显示通路 0
	arg[1] = (unsigned long)&config;
	arg[2] = 1; //只设置一个图层即当前图层
	ret = ioctl(disp, DISP_LAYER_SET_CONFIG, (void*)arg);


	printf("%s() <<<\n",__func__);
    return 0;
}

调试信息:

root@TinaLinux:/# ./lcd_test 
[   17.914242] drivers/video/fbdev/sunxi/disp2/disp/dev_disp.c 3885 disp_ioctl
[   17.922099] lyr_cfg[0].info.alpha_mode = 1,lyr_cfg[0].info.alpha_value = ff,lyr_cfg[0].info.fb.size[0].width = 1024,lyr_cfg[0].info.fb.size[0].height = 600,lyr_cfg[0].channel = 1024,lyr_cfg[0].layer_id = 600,lyr_cfg[0].enable = 1
[   17.944952] drivers/video/fbdev/sunxi/disp2/disp/dev_disp.c 3933 disp_ioctl
[   17.952800] [DISP] disp_get_layer,line:111:
[   17.952805] disp_get_layer (0,1024,600) fail
[   17.962388] drivers/video/fbdev/sunxi/disp2/disp/dev_disp.c 3936 disp_ioctl

通道值和图层值对不上

最近编辑记录 jkl (2022-06-25 10:41:50)

离线

#1 2022-06-27 10:44:38

dg
会员
注册时间: 2018-11-22
已发帖子: 38
积分: 91

Re: 发生一件很奇怪的事情,不知道问题出在哪里,大家帮忙看一下?

2个结构体的定义完全一样吗?
字节对齐选项是一样的吗?
定义完全一样,字节对齐选项一样,就不存在内容对不上的问题

另外,从用户态的数据转到内核态。有没有 copy from/to user ?
如果没有也有问题。可能一方的内存已经释放了,内容比较已经没有意义了。

离线

#2 2022-06-27 16:05:28

dg
会员
注册时间: 2018-11-22
已发帖子: 38
积分: 91

Re: 发生一件很奇怪的事情,不知道问题出在哪里,大家帮忙看一下?

用户层只传了3个参数
int main(int argc, char *argv[])
{
	unsigned long arg[3];
        ...
        arg[2] = 1; //只设置一个图层即当前图层
        ...
}
//内核层取4个?
	ubuffer[0] = *(unsigned long *)karg;
	ubuffer[1] = (*(unsigned long *)(karg + 1));
	ubuffer[2] = (*(unsigned long *)(karg + 2));
	ubuffer[3] = (*(unsigned long *)(karg + 3));

离线

#3 2022-06-27 17:14:12

benlypan
会员
注册时间: 2021-07-08
已发帖子: 49
积分: 133.5

Re: 发生一件很奇怪的事情,不知道问题出在哪里,大家帮忙看一下?

T113 的 sdk(Linux Kernel 5.4) 里的 disp_layer_config 的结构改了,加了两个成员变大了,我一时没看出来,被这个问题搞了一两个小时。不知你跟我的问题是否一样。

离线

#4 2023-12-01 11:09:06

wuyu
会员
注册时间: 2021-10-10
已发帖子: 32
积分: 13

Re: 发生一件很奇怪的事情,不知道问题出在哪里,大家帮忙看一下?

benlypan 说:

T113 的 sdk(Linux Kernel 5.4) 里的 disp_layer_config 的结构改了,加了两个成员变大了,我一时没看出来,被这个问题搞了一两个小时。不知你跟我的问题是否一样。

通过ioctl函数传递的图层参数,framebuffer地址(即上面的config.info.fb.addr[0])到底是物理地址还是虚拟地址?这个framebuffer由应用层提供,有没有什么特别要求?比如地址对齐要求、连续内存要求等等。另外哪里能找到有关的说明文档或者参考代码?

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn