全志科技公司A83T Qt Linux 支持gadget

用国产的CPU和linux系统做产品,由于以前对全志的芯片有些高性价比的印象,所有选了全志的8核64位的A83T,看手册是支持高速USB HOST和DRD(主从双角色),产品是设备类的,作为Device连接到电脑,看到linux有个Gadget,可以实现Device枚举。
号称支持ubuntu,linuxQt和Android三系统,实际上,Qt是可以支持的,但是gadget根本就出不来,Make menuconfig时选择这些也不起作用,电脑根本无反应,但是跑Android系统没有问题,所以,排除是硬件问题,由于和Android底层使用的是同一个Bsp,估计整个硬件的驱动应该是没有问题,应该是某个或某几个小细节没有处理好,因为寄存器也基本不公开,也没有可能去改查底层的寄存器设置,而且寄存器的设置理论上是不存在问题的,因为Android用的好好的。
网上查一部分资料,大致对gadget有了点印象,因为之前调试过裸机的USB设备通信,从插入计算机无反应来讲,应该是连枚举都没有枚举,同时用usb trace抓包,发现,的确,没有检测到Usb线上的反应,先从这一点入手,看看整个usb的系统在插入电脑的那一刻是怎么做的。
先找到控制usb从设备的底层代码,分为两部分,一部分是SOC芯片的设备控制器,代码里叫udc,位置位于linux-3.4/drivers/usb/sunxi_usb/udc/文件夹下,共有8个文件
全志科技公司A83T Qt Linux 支持gadget
,基本上构成了对udc设备的各种操作,然后和gadget里的具体的usb设备驱动绑定到一起,实现枚举。因为我们做的是打印机设备,所以用gadget的printer设备进行枚举,gadget的printer设备在linux-3.4/drivers/usb/gadget/目录下,有linux自带的各种gadget设备的枚举,因为我们的比较简单,只用printer.c即可。
没有别的办法,先打日志,看看启动过程,为什么没有枚举,看来看去,发现udc里面有个函数引出给别的地方,sunxi_usb_device_enable函数没有被调用过,通过查找,在另外的文件中有调用,位置在linux-3.4/drivers/usb/sunxi_usb/manager下,通过看这几个文件发现,终于明白了插入的过程了。裸机的usb插入是靠的usb设备控制器引擎的中断来启动,linux下没有研究过,不过从全志的做法上看是通过建立一个线程,定时检测USB接口的状态变化来初始化UDC,既可以通过vbus,id检测,也可以通过dp,dm的变化检测,这个设置在system_config.fex中可以进行设置。
通过对线程添加打印日志发现,插入usb和拔出时,线程均能非常好的检测到usb的状态变化,说明硬件和线程检测都没有问题,但是并没有初始化enable设备。找来找去发现了一个端倪,有一个函数叫做get_usb_gadget_functions,他是检测到usb设备插入后,进行驱动属性检测的,/sys/class/android_usb/android0/functions,检测的是sysfs的一个属性,乖乖,我哪有这个属性啊,所以插入usb就退出了。本着最小改动的原则,给gadget的printer长出一个属性来,也不费劲,就是填几行代码的事,基本从别的文件中拷贝过来,啥功能也不同,就是让这个检测可以通过即可。这个改动完成之后,插入主机,终于可以调用sunxi_usb_device_enable,但还是没有开始枚举,这就怪了。只能再看udc。
发现了一个变量static u8 is_udc_enable = 0; / is udc enable by gadget? /,再看看android的gadget使用的,有个属性可以通过用户层sysfs设置变量,瞬间想到以前用android手机时可以通过界面的勾选,选择不同的枚举设备,选择不枚举只充电。估计就出在这个变量上,直接设置为1.顺利枚举成功。

枚举之后发现另外一个问题,拔出设备,再重新插上,没问题。但是一旦使用open,read设备之后,再拔出设备,貌似就死机了,shell也死掉了,以为系统整个挂掉了,后来发现过一段时间有提示,应该是系统没整个死掉,那就应该是死锁了。再次测试,只open,close,不read,也没有问题,看来问题就出现在read上,read在gadget层,只调用了一次udc的udc queue,把完成函数注册上而已。先对比看看吧,把整个过程都通过日志打印出来,看看是挂在了哪个环节上。

先看看没和设备交互时的流程
[ 78.068994] [sunxi_usb_udc]FUN:filtrate_irq_misc
[ 78.074384] [sunxi_usb_udc]irq:suspend
[ 78.078830] [printer]FUN:printer_disconnect
[ 78.078984] [printer]FUN:printer_reset_interface
[ 78.078984] [sunxi_usb_udc]FUN:sunxi_udc_ep_disable
[ 78.078984] [sunxi_usb_udc]FUN:sunxi_udc_nuke
[ 78.078984] [sunxi_usb_udc]FUN:sunxi_udc_ep_disable
[ 78.078984] [sunxi_usb_udc]FUN:sunxi_udc_nuke
[ 79.030069] [sunxi_usb_udc]FUN:sunxi_usb_device_disable
[ 79.036089] [printer]FUN:printer_disconnect
[ 79.041000] [printer]FUN:printer_reset_interface
[ 79.046380] [sunxi_usb_udc]FUN:sunxi_udc_stop_dma_work
大致上是先挂起,然后复位接口,取消端点,然后停止一切相关。在看看读取之后的流程
[ 1044.506474] [sunxi_usb_udc]FUN:filtrate_irq_misc
[ 1044.511917] [sunxi_usb_udc]irq:suspend
[ 1044.516310] [printer]FUN:printer_disconnect
[ 1044.516462] [printer]FUN:printer_reset_interface
[ 1044.516462] [sunxi_usb_udc]FUN:sunxi_udc_ep_disable
[ 1044.516462] [sunxi_usb_udc]FUN:sunxi_udc_nuke
[ 1044.516462] [sunxi_usb_udc]FUN:sunxi_udc_ep_disable
[ 1044.516462] [sunxi_usb_udc]FUN:sunxi_udc_nuke
[ 1044.516462] [sunxi_usb_udc]FUN:sunxi_udc_done
[ 1044.516462] [printer]FUN:rx_complete
死在gadget的rx_complete函数里,找到函数所在的位置,一个非常可以的东西
spin_lock_irqsave(&dev->lock, flags);在这个之后打印一个信息,发现,果然,是挂在了这里。那肯定是有人和他冲突了,你也要抢这个,肯定是别人也要抢,因为正常的read过程也调用这个,就不会卡死,那他的上级不就是udc_nuke了,这个是唯一的不同之处,
nuke函数里没有啥,就是清空端点没有完成的工作,那就再往上找找。
sunxi_udc_ep_disable函数在调用nuke之前,赤果果的写着spin_lock_irqsave(&ep->dev->lock, flags),好吧,好吧,你高兴就好,还是本着最小改动原则,告诉rx_complete,如果不是正常的数据接收,亲,你别再抢了好伐。教训完它,果然OK了。

转载于:https://blog.51cto.com/13558393/2056498

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值