在应用层调用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)
离线
2个结构体的定义完全一样吗?
字节对齐选项是一样的吗?
定义完全一样,字节对齐选项一样,就不存在内容对不上的问题
另外,从用户态的数据转到内核态。有没有 copy from/to user ?
如果没有也有问题。可能一方的内存已经释放了,内容比较已经没有意义了。
离线
用户层只传了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));
离线
T113 的 sdk(Linux Kernel 5.4) 里的 disp_layer_config 的结构改了,加了两个成员变大了,我一时没看出来,被这个问题搞了一两个小时。不知你跟我的问题是否一样。
离线
T113 的 sdk(Linux Kernel 5.4) 里的 disp_layer_config 的结构改了,加了两个成员变大了,我一时没看出来,被这个问题搞了一两个小时。不知你跟我的问题是否一样。
通过ioctl函数传递的图层参数,framebuffer地址(即上面的config.info.fb.addr[0])到底是物理地址还是虚拟地址?这个framebuffer由应用层提供,有没有什么特别要求?比如地址对齐要求、连续内存要求等等。另外哪里能找到有关的说明文档或者参考代码?
离线