免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4436 | 回复: 5
打印 上一主题 下一主题

[硬件及驱动] 一个copy_to_user无法实现功能的问题,跪求解决! [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-11-05 16:17 |只看该作者 |倒序浏览
本帖最后由 yv9200 于 2014-11-05 16:23 编辑

我们之前开发的是在ubuntu开发的驱动以及应用程序,架构X86 32,应用程序32位,内核版本为2.6.26.3,开发完可以正常使用。但目前工作需用把它移植到mips64的中标麒麟的系统上,遇到了和驱动开发有关的问题,之前是ioctl无法调用成功,后来把.unlocked_ioctl改成compat_ioctl后,ioctl可以正常工作,新的问题是通过ioctl找到的信息无法通过copy_to_user传到用户空间,导致程序无法工作,我在网上找了一些文章说是32位的应用程序和64位的操作系统有冲突,说是需要把copy_to_user第一个参数从原来的32位改成64位就好了 ,我把那个指针的类型从unsigned long 改成unsigned long long ,仍然不能给用户空间返回正确的值。求大神解答!

论坛徽章:
9
辰龙
日期:2014-08-18 20:38:42未羊
日期:2014-09-04 08:50:45丑牛
日期:2014-09-06 00:12:55寅虎
日期:2014-12-22 20:50:56摩羯座
日期:2015-01-14 22:28:15巳蛇
日期:2015-01-23 20:39:272015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之青岛
日期:2016-03-13 23:37:1915-16赛季CBA联赛之深圳
日期:2016-03-29 18:52:38
2 [报告]
发表于 2014-11-05 23:05 |只看该作者
回复 1# yv9200


  这个好弄呀,内核里头已经有大量的compat_ioctl的参考实例。多看看别人各种情况下是怎么写的就可以了。

论坛徽章:
9
辰龙
日期:2014-08-18 20:38:42未羊
日期:2014-09-04 08:50:45丑牛
日期:2014-09-06 00:12:55寅虎
日期:2014-12-22 20:50:56摩羯座
日期:2015-01-14 22:28:15巳蛇
日期:2015-01-23 20:39:272015年辞旧岁徽章
日期:2015-03-03 16:54:1515-16赛季CBA联赛之青岛
日期:2016-03-13 23:37:1915-16赛季CBA联赛之深圳
日期:2016-03-29 18:52:38
3 [报告]
发表于 2014-11-05 23:13 |只看该作者
下面是driver/scsi/ch.c的一个样例,这样的例子还有很多。自己慢慢学一下就行。要注意的只是:第一个参数的内容会按32位程序的布局来安排,因此内核在使用时,要注意转换,其它就没什么了。

  1. static long ch_ioctl_compat(struct file * file,
  2.                             unsigned int cmd, unsigned long arg)
  3. {
  4.         scsi_changer *ch = file->private_data;
  5.        
  6.         switch (cmd) {
  7.         case CHIOGPARAMS:
  8.         case CHIOGVPARAMS:
  9.         case CHIOPOSITION:
  10.         case CHIOMOVE:
  11.         case CHIOEXCHANGE:
  12.         case CHIOGELEM:
  13.         case CHIOINITELEM:
  14.         case CHIOSVOLTAG:
  15.                 /* compatible */
  16.                 return ch_ioctl(NULL /* inode, unused */,
  17.                                 file, cmd, arg);
  18.         case CHIOGSTATUS32:
  19.         {
  20.                 struct changer_element_status32 ces32;
  21.                 unsigned char __user *data;
  22.                
  23.                 if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32)))
  24.                         return -EFAULT;
  25.                 if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES)
  26.                         return -EINVAL;

  27.                 data = compat_ptr(ces32.ces_data);
  28.                 return ch_gstatus(ch, ces32.ces_type, data);
  29.         }
  30.         default:
  31.                 // return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
  32.                 return -ENOIOCTLCMD;

  33.         }
  34. }
  35. #endif
复制代码

论坛徽章:
0
4 [报告]
发表于 2014-11-13 10:04 |只看该作者
这是我的ioctl里面的一段代码 标注为红色的那个debug可以打印出数值,但传到应用程序,那个结构体打印出的都是默认的值,我发现copy_to_user里的第一个参数已经被转化为64位。
case VDRIVER_SCAN_CARDS:
                {
                        vdriver_debug("\n");
                        vdriver_debug("VDRIVER_SCAN_CARDS............\n");
                        vd_scan_cards = kmalloc(sizeof(VD_PCI_SCAN_CARDS), GFP_KERNEL);
                        if(copy_from_user(vd_scan_cards, (VD_PCI_SCAN_CARDS *)arg, sizeof(VD_PCI_SCAN_CARDS)))
                        {
                                vdriver_error("VDRIVER_SCAN_CARDS comand error !\n");
                                return -EFAULT;
                        }
                        vendorid = vd_scan_cards->searchId.dwVendorId;
                        deviceid = vd_scan_cards->searchId.dwDeviceId;
                        if(deviceid == 0)
                        {
                                deviceid = PCI_ANY_ID;
                        }
                        if(vendorid == 0)
                        {
                                vendorid = PCI_ANY_ID;
                        }
                        vdriver_debug("The usr params vendorid is %x,deviceid is %x\n",vendorid, deviceid);
                        do
                        {
                                pci_dev = pci_get_device(vendorid, deviceid, pci_dev);
                                vdriver_debug("vdriver scan cards the pci_dev is %x\n",(unsigned int)pci_dev);
                                if(pci_dev != NULL)
                                {
                                        vd_scan_cards->cardId[card_count].dwVendorId = pci_dev->vendor;
                                        vd_scan_cards->cardId[card_count].dwDeviceId = pci_dev->device;
                                        vdriver_debug("vdriver scan cards VendorId is %x,DeviceId is %x\n",pci_dev->vendor,pci_dev->device);
                                        busnum = (pci_dev->bus->number);
                                        devnum = ((pci_dev->devfn)>>3) & 0x1f;
                                        funnum = (pci_dev->devfn) & 0x7;
                                        vd_scan_cards->cardSlot[card_count].dwBus = busnum;
                                        vd_scan_cards->cardSlot[card_count].dwSlot = devnum;
                                        vd_scan_cards->cardSlot[card_count].dwFunction = funnum;
                                        vdriver_debug("vdriver scan cards dwBus is %d,dwSlot is %d,dwFunction is %d\n",(unsigned int)vd_scan_cards->cardSlot[card_count].dwBus,
                                                                 (unsigned int)vd_scan_cards->cardSlot[card_count].dwSlot,(unsigned int)vd_scan_cards->cardSlot[card_count].dwFunction);
                                        card_ir = pci_dev->irq;
                                        vdriver_debug("vdriver scan cards interrupt num is %x\n",card_ir);
                                        card_count ++;
                                }
                        }
                        while(pci_dev != 0);
                        vd_scan_cards->dwCards = card_count;
                        vdriver_debug("Total scan the card number is %d...........\n",(unsigned int)vd_scan_cards->dwCards);
                        if (copy_to_user((VD_PCI_SCAN_CARDS *)arg, vd_scan_cards, sizeof(VD_PCI_SCAN_CARDS)))
                                return -EFAULT;
                        kfree(vd_scan_cards);
                        break;
                }回复 3# Tinnal


   

论坛徽章:
0
5 [报告]
发表于 2014-11-21 15:54 |只看该作者
如果你是uint32_t那么用打印用%u 如果是int32_t 那么用%d 如果是uint64_t 那么用%lu 如果是int64_t那么用%l打印。如果还有问题,检查是不是结构体字节对齐的问题。
你的问题不是copy_to_user和copy_from_user的问题。
此外vd_scan_cards 你需要判断是否分配成功, 另外 return 之前 你需要释放掉。

论坛徽章:
0
6 [报告]
发表于 2014-11-21 17:53 |只看该作者
多谢大神的解答,问题得以解决,是结构体字节对齐的问题。回复 5# playmud


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP