一步一步解决 kernel 2.6 usb host driver
(以下讨论基于kernel 2.6.11,ARM9 s3c2410,arm-linux-gcc 3.4.1 )
=================================================
2.6在s3c2410上usb host不工作的直接结果就是提示110错误:
usb 1-1: device descriptor read/64, error -110
追踪错误代码,我们来看看能不能找到导致这个错误的线索。
include/asm-generic/errno.h
#define EPROTO 71 /* Protocol error */
#define EILSEQ 84 /* Illegal byte sequence */
#define ETIMEDOUT 110 /* Connection timed out */
Documentation/usb/error-codes.txt
-EPROTO (*, **) a) bitstuff error
b) no response packet received within the
prescribed bus turn-around time
c) unknown USB error
-EILSEQ (*, **) a) CRC mismatch
b) no response packet received within the
prescribed bus turn-around time
c) unknown USB error
-ETIMEDOUT (**) No response packet received within the prescribed
bus turn-around time. This error may instead be
reported as -EPROTO or -EILSEQ.
由此我们可以判断,这个错误与 usb设备的超时有关。报告这个错误的地方在drivers/usb/core/hub.c中的hub_port_init部分,由于usb_get_device_descriptor获取 usb 设备信息的时候产生了超时。这样基本可以确定三种情况,1、usb设备及接口有问题;2、usb core有问题;3、usb driver有问题。
我们可以很容易地排除1和2的可能性,问题应该在usb driver implement部分造成的。2.6的usbdriver把usb规范中对usb接口的操作集中到了core里面,针对不同设备的implement分别归为host、gadget、storage等。基本确定问题就在ohci-s3c2410.c里。
跟踪进入ohci-s3c2410.c,这里面主要完成s3c2410 usb host设备的初始化工作,包括电源、时钟、寄存器等。
其实很多问题在互联网上已经被遇到和解决,我们要做的就是多参考别人的成功经验,这样可以节省时间,同时能够帮助我们找到一些思路。借助google这双强大的翅膀,我们来看看能找到什么:
http://www.linux-usb.org/FAQ.html
Q: Why doesn’t USB work at all? I get “device not accepting address”.
A: You may have some problem with your PCI setup that’s preventingyour USB host controller from getting hardware interrupts. When Linuxsubmits a request, but never hears back from the controller, this isthe diagnostic you’ll see. To see if this is the problem, look at/proc/interrupts to see if the interrupt count for your host controllerdriver ever goes up. If it doesn’t, this is the problem: either yourBIOS isn’t telling the truth to Linux (ACPI sometimes confuses thesethings, or setting the expected OS to windows in your BIOS), or Linuxdoesn’t understand what it’s saying.
Sometimes a BIOS fix will be available for your motherboard, andin other cases a more recent kernel will have a Linux fix. You may beable to work around this by passing the noapic boot option to yourkernel, or (when you’re using an add-in PCI card) moving the USBadapter to some other PCI slot. If you’re using a current kernel andBIOS, report this problem to the Linux-kernel mailing list, withdetails about your motherboard and BIOS.
google返回的大量结果中有个建议是设置old_scheme_first标志,让驱动程序优先处理采用老式结构的设备:
设置old_scheme_first=y
测试结果并没有太大帮助,不是这个原因引发的。
linux-usb-devel mail list 上Ben大哥正在不断更新他的ohci-s3c2410 driver,但好像还没最终完成。
http://www.mail-archive.com/linux-usb-devel%40lists.sourceforge.net/msg33670.html
跟踪ohci-s3c2410.c,发现to_s3c2410_info返回NULL,很明显,是platform_data没有定义,在include/asm/arch/usb-control.h中已经有structs3c2410_hcd_info,那么仿照simtec的usb-simtec.c,来构造自己的platform_data。
static struct s3c2410_hcd_info smdk2410_usbcfg = {
.port[0] = {
.flags = S3C_HCDFLG_USED
},
};
然后在smdk2410_init中完成初始化:
s3c_device_usb.dev.platform_data = &smdk2410_usbcfg;
重新make zImage,情况有所变化:
初始化usb controller的过程中有一行debug信息:
s3c2410-ohci: CTRL: TypeReq=0x2303 val=0x8 idx=0x1 len=0 ==> -115
在include/asm-generic/errno.h中查了一下这个错误代码:
#define EINPROGRESS 115 /* Operation now in progress */
在Documentation/usb/error-codes.txt中的解释是:
-EINPROGRESS URB still pending, no results yet
(That is, if drivers see this it’s a bug.)
这时无论插入什么USB设备,USB鼠标、U盘、USB无线网卡,都报告:
<6>usb 1-1: new full speed USB device using s3c2410-ohci and address 2
<7>s3c2410-ohci s3c2410-ohci: urb c3c430c0 path 1 ep0in 5ec20000 cc 5 –> status -110
看上去这两个错误应该存在关联,可能前面的115错误导致了后面的110错误;在跟踪过程中发现115错误是在GetPortStatus时产生的,从这个情况来看,可以暂时屏蔽0hci-s3c2410.c中GetPortStatus的实现部分,继续观察变化,结果还是110错误,因此可以排除115 造成110错误的假设。
最后怀疑是时钟设置的问题,便参照2.4.18的代码在clk_enable(clk);后面加了个udelay(11);但是错误还是没有解决。
那么需要对ohci-s3c2410.c进行详细的排查了,2.6把系统资源进行了详细的分类,这使得驱动程序要完成初始化相应设备寄存器的工作,查遍 ohci-s3c2410.c,竟然没有对s3c24102410的UPLLCON进行设置的代码,问题很可能就在这里,usermanual说UPLLCON需要48.00MHz output, 于是在s3c2410_start_hc里增加:
__raw_writel((0x78<<12)|(0x02<<4)|(0x03), S3C2410_UPLLCON);
OK!usb host可以工作了,但是在第一次上电还会出现110错误,reset后才可以正常,2410上的这个UPLLCON问题由来已久,2.4内核也经常出现,原因是UPLLCON的值没有设置成功,那么就需要对设置的值进行检查,直到成功为止。
把上面的代码修改为:
unsigned long upllvalue = (0x78<<12)|(0x02<<4)|(0x03);
while (upllvalue != __raw_readl(S3C2410_UPLLCON))
{
__raw_writel(upllvalue, S3C2410_UPLLCON);
mdelay(1);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论