linux usb drivers开发

来源:互联网 发布:歌曲网络认识你 编辑:程序博客网 时间:2024/05/16 12:47

 

Linux下的硬件驱动——USB设备(上)(驱动配置部分)

http://www.ibm.com/developerworks/cn/linux/l-usb/index1.html

 

Linux下的硬件驱动——USB设备(下)(驱动开发部分)

http://www.ibm.com/developerworks/cn/linux/l-usb/index2.html


关于kernel2.6中USB host controller driver 的问题

 
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的usb driver把usb规范中对usb接口的操作集中到了core里面,针对不同设备的implement分别归为host、gadget、storage 等。基本确定问题就在ohci-s3c2410.c里。 

跟踪进入ohci-s3c2410.c,这里面主要完成s3c2410 usb host设备的初始化工作,包括电源、时钟、寄存器等。 

其实很多问题在互联网上已经被遇到和解决,我们要做的就是多参考别人的成功经验,这样可以节省时间,同时能够帮助我们找到一些思路。借助google这双强大的翅膀,我们来看看能找到什么: 

http://www.linux-usb.org/FAQ.html#ts6 

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 preventing your USB host controller from getting hardware interrupts. When Linux submits a request, but never hears back from the controller, this is the diagnostic you’ll see. To see if this is the problem, look at /proc/interrupts to see if the interrupt count for your host controller driver ever goes up. If it doesn’t, this is the problem: either your BIOS isn’t telling the truth to Linux (ACPI sometimes confuses these things, or setting the expected OS to windows in your BIOS), or Linux doesn’t understand what it’s saying. 

Sometimes a BIOS fix will be available for your motherboard, and in other cases a more recent kernel will have a Linux fix. You may be able to work around this by passing the noapic boot option to your kernel, or (when you’re using an add-in PCI card) moving the USB adapter to some other PCI slot. If you’re using a current kernel and BIOS, report this problem to the Linux-kernel mailing list, with details 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@lists.sourceforge.net/msg33670.html 

跟踪ohci-s3c2410.c,发现to_s3c2410_info返回NULL,很明显,是platform_data没有定义,在 include/asm/arch/usb-control.h中已经有struct s3c2410_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进行设置的代码,问题很可能就在这里,user manual说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); 
}

不需要修改Kconfig和Makefile,把ohci-s3c2410.c放到drivers/usb/host/目录,编辑drivers/usb/host/ohci-hcd.c,翻到末尾处增加以下红色部分代码: 

#ifdef CONFIG_SOC_AU1X00 
#include "ohci-au1xxx.c" 
#endif 

#ifdef CONFIG_ARCH_S3C2410 
#include "ohci-s3c2410.c" 
#endif 


#if !(defined(CONFIG_PCI) \ 
|| defined(CONFIG_SA1111) \ 
|| defined(CONFIG_ARCH_OMAP) \ 
|| defined (CONFIG_ARCH_LH7A404) \ 
|| defined (CONFIG_PXA27x) \ 
|| defined (CONFIG_SOC_AU1X00) \ 
|| defined (CONFIG_ARCH_S3C2410) \ 

#error "missing bus glue for ohci-hcd" 
#endif

经过修改可以找到USB设备,但是无法mount上,已经把文件系统支持编译进内核了,但是还是提示“sda:unknown partition table”,无法mount,这该如何解决呢
使能CONFIG_MSDOS_PARTITION选项

感谢panjet提供的经验,对我很有帮助! 

我按照你的方法在linux 2.6.14内核中加入s3c2410 ohci驱动,现在还有一些问题,请指点一下。 

>然后在smdk2410_init中完成初始化: 
>s3c_device_usb.dev.platform_data = &smdk2410_usbcfg; 
我一直没找到smdk2410_init这个函数,2.6.11的内核也搜索过。请问在哪个文件中? 
目前我把 
s3c_device_usb.dev.platform_data = &smdk2410_usbcfg; 
加在arch/arm/mach-s3c2410/s3c2410.c中的int __init s3c2410_init(void)函数中 

加入了usb massive storage, scsi等支持,编译好内核后下载,U盘的一些信息如下: 
启动信息: 
s3c2410-ohci s3c2410-ohci: S3C24XX OHCI 
s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1 
s3c2410-ohci s3c2410-ohci: irq 42, io mem 0x49000000 
usb usb1: Product: S3C24XX OHCI 
usb usb1: Manufacturer: Linux 2.6.14 ohci_hcd 
usb usb1: SerialNumber: s3c24xx 
hub 1-0:1.0: USB hub found 
hub 1-0:1.0: 2 ports detected 
Initializing USB Mass Storage driver... 
usb 1-1: new full speed USB device using s3c2410-ohci and address 2 
usb 1-1: Product: Solid state disk 
usb 1-1: Manufacturer: USB 
usb 1-1: SerialNumber: 103016D43E4492CA 
scsi0 : SCSI emulation for USB Mass Storage devices 
usbcore: registered new driver usb-storage 
USB Mass Storage support registered. 

OHCI驱动已经支持 

INIT: version 2.86 booting 
Vendor: kpm Model: kpm Rev: 1.11 
Type: Direct-Access ANSI SCSI revision: 02 
SCSI device sda: 129024 512-byte hdwr sectors (66 MB) 
sda: Write Protect is off 
sda: assuming drive cache: write through 
SCSI device sda: 129024 512-byte hdwr sectors (66 MB) 
sda: Write Protect is off 
sda: assuming drive cache: write through 
/dev/scsi/host0/bus0/target0/lun0:<7>usb-storage: queuecommand called 
p1 
Attached scsi removable disk sda at scsi0, channel 0, id 0, lun 0 
Attached scsi generic sg0 at scsi0, channel 0, id 0, lun 0, type 0 

U盘信息也已正确识别,并已attach 

bash-3.00# cat /proc/scsi/scsi 
Attached devices: 
Host: scsi0 Channel: 00 Id: 00 Lun: 00 
Vendor: kpm Model: kpm Rev: 1.11 
Type: Direct-Access ANSI SCSI revision: 02 

bash-3.00# cat /proc/scsi/usb-storage/0 
Host scsi0: usb-storage 
Vendor: USB 
Product: Solid state disk 
Serial Number: 103016D43E4492CA 
Protocol: Transparent SCSI 
Transport: Bulk 
Quirks: 

bash-3.00# cat /proc/bus/usb/devices 

T: Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2 
B: Alloc= 0/900 us ( 0%), #Int= 0, #Iso= 0 
D: Ver= 1.10 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 
P: Vendor=0000 ProdID=0000 Rev= 2.06 
S: Manufacturer=Linux 2.6.14 ohci_hcd 
S: Product=S3C24XX OHCI 
S: SerialNumber=s3c24xx 
C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr= 0mA 
I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub 
E: Ad=81(I) Atr=03(Int.) MxPS= 2 Ivl=255ms 

T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 
D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 
P: Vendor=0ea0 ProdID=6803 Rev= 1.00 
S: Manufacturer=USB 
S: Product=Solid state disk 
S: SerialNumber=103016D43E4492CA 
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA 
I: If#= 0 Alt= 0 #EPs= 3 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage 
E: Ad=81(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms 
E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms 
E: Ad=83(I) Atr=03(Int.) MxPS= 2 Ivl=1ms 

上述信息说明U盘已经识别并挂载(我这么认为),应该是可以mount了,但在/dev下我找不到挂载点,如sda,也就没法读U盘的数据。内核 中已经支持了usb massive storage, scsi, msdos partition/ filesystem。 

请问这个问题如何解决? 是不是内核中还需要修改一些配置

搞定了这个问题,没有加入对应文件系统的language编码支持。 
配置如下: 
File systems --> 
DOS/FAT/NT Filesystems --->

  • MSDOS fs support
  • VFAT (Windows-95) fs support 
    (437) Default codepage for FAT 
    (iso8859-1) Default iocharset for FAT 
    Native Language Support --> 
    (iso8859-1) Default NLS Option
  • Codepage 437 (United States, Canada)
  • NLS ISO 8859-1 (Latin 1; Western European Languages



  • 关于smdk2410_init函数的问题,不少网友来信询问,补充如下: 

    通过查看arch/arm/mach-s3c2410/mach-bast.c的 MACHINE_START/MACHINE_END 节我们可以看到有一个 
    .init_machine的成员,可以用来设置用户自定义的初始化信息。 
    而在原始的arch/arm/mach-s3c2410/mach-smdk2410.c中是没有这个成员的,我们可以仿照mach-bast.c加入 
    这个成员,给它传递一个初始化函数的地址。 

    首先在 MACHINE_START/MACHINE_END 节前面的位置这样定义这个初始化函数: 

    void __init smdk2410_init(void) 

    s3c_device_usb.dev.platform_data = &smdk2410_usbcfg; 


    然后在 MACHINE_START/MACHINE_END 节中加入一行 .init_machine = &smdk2410_init, 或者用宏 
    INIT_MACHINE申明: INIT_MACHINE(smdk2410_init),可以放在INITIRQ行的下面。 

    这样系统在启动的过程中就会调用smdk2410_init完成初始化信息的设置工作


    linux-2.6.28系统移植s3c6410开发板USB不能识别的处理

    初始化OK,一插上usb就报如下错误:

    / # usb 1-1: new full speed USB device using s3c2410-ohci and address 2
    usb 1-1: device descriptor read/64, error -62
    usb 1-1: device descriptor read/64, error -62
    usb 1-1: new full speed USB device using s3c2410-ohci and address 3
    usb 1-1: device descriptor read/64, error -62
    usb 1-1: device descriptor read/64, error -62
    usb 1-1: new full speed USB device using s3c2410-ohci and address 4
    usb 1-1: device not accepting address 4, error -62
    usb 1-1: new full speed USB device using s3c2410-ohci and address 5
    usb 1-1: device not accepting address 5, error -62
    hub 1-0:1.0: unable to enumerate USB device on port 1

    解决方法:

    根据终端打印的错误

    cd include/asm-generic/errno.h
     u-boot/include/asm-arm/errno.H

    找到:
    #define ETIME 62 /*timer expired*/

    再由:
    error-codes.txt 去找usb error code
    http://ftp.gnu.org/tmp/linux-libre-fsf2_2.6.28/linux-2.6.28/Documentation/usb/error-codes.txt

    -ETIME (**)      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、usbcore有问题3、usb driver有问题。


    我们可以很容易的派出1.2的可能性,问题应该在usb driverimplement部分造成。2.6的内核usb driver把usb规范中对usb的操作集中到了core里面,针对不同设备的implement 分别归为hostgadgetstorage等。基本确定问题就在ohci-s3c2410.c中。


    原来是USB Host的48MHz时钟没有起来。

    s3c6410支持三个PLL分别是APLL,MPLL和EPLL。APLL为ARM提供时钟,产生ARMCLK,MPLL为所有和AXI/AHB/APB相连的模块提供时钟,产生HCLK和PCLK,EPLL为特殊的外设提供时钟,产生SCLK。

    如图所示为EPLL_CON的 M、 P 和 S的取值。


    根据s3c6410的数据手册:


    如图所示,描述的是用于IrDA和USB host 的时钟发生器,通常USB借口需要48M的操作时钟。

    从图中可也以说明,HCLK_GATE,PCLK_GATE和SCL_GATE控制时钟操作。如果一个位设置,则通过每个时钟分频器相应的时钟将会被提供,否则,将被屏蔽。

    HCLK_GATE控制HCLK,用于每个Ips。每个IP的AHB接口逻辑被独立地屏蔽,以减少动态电力消耗。PCLK_GATE控制PCLK。通过SCLK_GATE时钟被控制。

    根据上图EPLL通道写出一下程序。

    58 #define EPLL_CON01               0

    359 

    360 #define UPLL_SRC_MASK    ((1<<2)|(3<<5))

    361 #define UPLL_SRC         ((1<<2)|(1<<5))

    362 #define UPLL_DIV1_MASK   (0xf<<20)

    363 #define UPLL_DIV1        (0<<20)

    364 #define UPLL_GATE_MASK   (1<<30)

    365 #define UPLL_GATE        (1<<30)

    void set_upll(void)

    368 {

    369         unsigned int tmp;

    370 

    371         while(__raw_readl(S3C_EPLL_CON0)!=EPLL_CON00)

    372         __raw_writel(EPLL_CON00,S3C_EPLL_CON0);

    373 

    374         while(__raw_readl(S3C_EPLL_CON1)!=EPLL_CON01)

    375         __raw_writel(EPLL_CON01,S3C_EPLL_CON1);

    376 

    377         while(((tmp= __raw_readl(S3C_CLK_SRC))&UPLL_SRC_MASK)!=UPLL_SRC)

    378                 __raw_writel((tmp&UPLL_SRC_MASK)|UPLL_SRC,S3C_CLK_SRC);

    379         while(((tmp=__raw_readl(S3C_CLK_DIV1))&UPLL_DIV1_MASK)!=UPLL_DIV1)

    380                 __raw_writel((tmp&UPLL_DIV1_MASK)|UPLL_DIV1,S3C_CLK_DIV1);

    381         while(((tmp=__raw_readl(S3C_SCLK_GATE))&UPLL_GATE_MASK)!=UPLL_GATE)

    382                 __raw_writel((tmp&UPLL_GATE_MASK)|UPLL_GATE,S3C_SCLK_GATE);

    383 }

    probe中加入上面的函数修改USB host的时钟:


    386 static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,

    387                                   struct platform_device *dev)

    388 {

    389         struct usb_hcd *hcd = NULL;

    390         int retval;

    391 

    392 #if !defined(CONFIG_ARCH_2410)

    393         usb_host_clk_en();

    394 #endif

    395 

    396         set_upll();

    然后编译内核。

    USB的不能识别的错误就解决了




    如何在Ubuntu上驱动腾达W541U V2.0 (RT2070)无线网卡【使用2011新驱动】

    这个破网卡,实在无语,网上已经有够多的帖子谈它的驱动问题了。经过一翻折腾,今天把过程记录下来,为自己留着,也为给大家参考。

     

    网上的帖子多使用的是官方2009年的旧驱动来编译。这个旧版本有在2.6.31以上内核需要打补丁的问题,麻烦。因此去官网上下载了2011年最新的驱动来编译,可以省很多事。

     

    官网上最新驱动下载链接在此,我用goo.gl缩短了地址:http://goo.gl/2ILQZ

    打开的页面会要求你填姓名和邮箱才能下载。其实是可以随便填的,乱填也无所谓。

     

    下载回来的源码包: 2011_0107_RT3070_RT3370_Linux_STA_v2.5.0.1_DPO .tar.gz

     

    以下是步骤(主机为Ubuntu 10.04.2 LTS):

    1、解压源码;

    2、在common/rtusb_dev_id.c中找到#ifdef RT3070,在这个宏定义所在的struct里加入:

          {USB_DEVICE(0x148F,0x2070)}, /* Ralink 2070 */

         保存;

    3、在os/linux/config.mk中找到并修改:

          HAS_WPA_SUPPLICANT=y

          以及

          HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=y

          保存;

    4、在os/linux/usb_main_dev.c中加入:

          MODULE_LICENSE("GPL");

         保存;

    5、 在源码根目录下make install

    6、Ubuntu 自带有一些RT芯片的驱动,但这些驱动模块并不能使RT2070正常工作,反而会影响我们编译出的模块,使之不能Scan。因此做blacklist屏蔽这些驱动模块:

    编辑 /etc/modprobe.d/blacklist.conf

    加入下面3行:

    blacklist rt2x00usb

    blacklist rt2x00lib

    blacklist rt2800usb

    保存。

    7、使得每次开机时自动加载驱动模块。编辑/etc/modules文件,加入:

     

    rt3070sta

    保存。

     

    重启你的Ubuntu,一切搞定。


    RT3070_STA_驱动移植文档

    移植环境:
           
    主机操作系统:Ubantu10.10
           
    目标系统:at91sam9m10内核linux-2.6.30
           
    交叉编译器:arm-none-linux-gnueabi-

     

    驱动版本:2011_0107_RT3070_RT3370_Linux_STA_v2.5.0.1_DPO

     

    Networkingsupport

    Wireless

    -*-Wirelessextensions

    [*]Wirelessextensions sysfs files

    DeviceDrivers

    Networkdevice support

    WierlessLAN

    [*]WirelessLAN(IEEE 802.11)

    <M>Ralinkdriver support



    1.下载RT3070驱动源码
    版本:2011_0107_RT3070_RT3370_Linux_STA_v2.5.0.1_DPO
    download: 
    下载页面

    选到 T8070/RT3070/RT3370/RT5370/RT5372USB  这个然后随便输入名字和邮箱即可下载。

     

    2.RT3070驱动修改

    解压 tar-zxvf 2011_0107_RT3070_RT3370_Linux_STA_v2.5.0.1_DPO.tar.gz

    进入RT3070_Linux_STA目录,看到有一个README_STA_usb文件,里面介绍了如何加载该驱动,先浏览一下

     

    2.1 先设好环境变量
    exportPATH=/usr/local/arm/arm-2007q1/bin:$PATH

     

    2.2 makefile修改 (-为去掉设置,+为新加的设置)
    #vimakefile

    -#PLATFORM = PC
    + PLATFORM = IXP
    #(
    选用的是IXP)

    ifeq($(PLATFORM),IXP)

    -LINUX_SRC = /project/stable/Gmtek/snapgear-uclibc/linux-2.6.x
    -CROSS_COMPILE = arm-linux-
    + LINUX_SRC = /home/rpf413/at91/linux/linux-2.6.30
    + CROSS_COMPILE = /usr/local/arm/arm-2007q1/bin/arm-none-linux-gnueabi-
    endif


    2.3 /os/linux/config.mk
    修改
    #cd/os/linux/
    #vi config.mk

    #Support Wpa_Supplicant
    - HAS_WPA_SUPPLICANT=n
    +HAS_WPA_SUPPLICANT=y

    #Support Native WpaSupplicant for Network Maganger
    -HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=n
    +HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=y

    ifeq($(PLATFORM),IXP)
    - WFLAGS +=-DRT_BIG_ENDIAN
    #
    加这个选项,模块运行时显示出错,CPU不能工作
    endif

    ifeq($(PLATFORM),IXP)

     -CFLAGS := -v -D__KERNEL__ -DMODULE -I$(LINUX_SRC)/include-I$(RT28xx_DIR)/include -mbig-endian -Wall -Wstrict-prototypes-Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -Uarm -fno-common-pipe -mapcs-32 -D__LINUX_ARM_ARCH__=5 -mcpu=xscale -mtune=xscale-malignment-traps -msoft-float $(WFLAGS)
            -EXTRA_CFLAGS := -v $(WFLAGS) -I$(RT28xx_DIR)/include -mbig-endian
     +EXTRA_CFLAGS := -v $(WFLAGS) -I$(RT28xx_DIR)/include
     exportCFLAGS       
    endif

     

    3、  编译源码
    make
    通过,2011_0107_RT3070_RT3370_Linux_STA_v2.5.0.1_DPO/os/linux目录下生成了rt3070sta.ko,也就是RT3070的驱动了

     makeKBUILD_NOPEDANTIC=1

    4.   拷贝驱动到目标系统
    RT2870STA.dat拷贝到/etc/Wireless/RT2870STA目录下
    rt3070sta.ko拷贝到/xxx/目录下xxx自定


     

    5.加载驱动模块
    insmod/xxx/rt3070sta.ko

    出现以下错误

    insmod:error inserting 'rt3070sta.ko': -1 Unknown symbol inmodule
    rt3070sta: Unknown symbol usb_alloc_urb
    rt3070sta:Unknown symbol usb_free_urb
    rt3070sta: Unknown symbolusb_register
    rt3070sta: Unknown symbol usb_put_dev
    rt3070sta:Unknown symbol usb_get_dev
    rt3070sta: Unknown symbolusb_submit_urb
    rt3070sta: Unknown symbolusb_control_msg
    rt3070sta: Unknown symbolusb_deregister
    rt3070sta: Unknown symbol usb_kill_urb
    rt3070sta:Unknown symbol usb_buffer_free
    rt3070sta: Unknown symbolusb_buffer_alloc
    insmod: cannot insert `rt3070sta.ko': Unknownsymbol in module (-1): No such file or directory

    原因未加载USB驱动

    请修改UTIL/os/linux/usb_main_dev.c文件,在文件的开头加上如下一行程序:

    MODULE_LICENSE(“GPL”)

    重新编译:

    MakeARCH=armCROSS_COMPILE=/usr/local/arm/arm-2007q1/bin/arm-none-linux-gnueabi-

      

    5.3 然后再加载rt3070sta.ko

    手动添加:/etc/Wireless/RT2870STA/RT2870STA.dat
    insmod/xxx/rt3070sta.ko
    显示
    rtusbinit rt2870 --->

    ===pAd = d1af4000, size = 514424 ===

    <--RTMPAllocTxRxRingMemory, Status=0
    <-- RTMPAllocAdapterBlock,Status=0
    usbcore: registered new driver rt2870

    加载成功

    #ifconfig-a 可以查看到ra0设备的存在

    若无密码或密码为WEP加密,则此时可以启动无线,若密码为WPA加密,则需移植wpa_supplicant,往后再说移植

     

    6.无密码或密码为WEP加密:
    6.1 
    启动无线
    #ifconfigra0 up  
    (Efusefor 3062/3562/3572) Size=0x2d [2d0-2fc]
    RTMP_TimerListAdd: addtimer obj d1b3c620!
    RTMP_TimerListAdd: add timer objd1b3c650!
    RTMP_TimerListAdd: add timer objd1b3c680!
    RTMP_TimerListAdd: add timer objd1b3c5f0!
    RTMP_TimerListAdd: add timer objd1b3c560!
    RTMP_TimerListAdd: add timer objd1b3c590!
    RTMP_TimerListAdd: add timer objd1b06b94!
    RTMP_TimerListAdd: add timer objd1af5f54!
    RTMP_TimerListAdd: add timer objd1af5f8c!
    RTMP_TimerListAdd: add timer objd1b06c38!
    RTMP_TimerListAdd: add timer objd1b06b34!
    RTMP_TimerListAdd: add timer objd1b06c04!
    -->RTUSBVenderReset
    <--RTUSBVenderReset
    Key1Stris Invalid key length(0) or Type(0)
    Key2Str is Invalid keylength(0) or Type(0)
    Key3Str is Invalid key length(0) orType(0)
    Key4Str is Invalid key length(0) or Type(0)
    1. Phy Mode= 5
    2. Phy Mode = 5
    phy mode> Error! The chip does notsupport 5G band 5!
    RTMPSetPhyMode: channel is out of range, usefirst channel=1
    (Efuse for 3062/3562/3572) Size=0x2d [2d0-2fc]
    3.Phy Mode = 9
    MCS Set = ff 00 00 00 01
    <==== rt28xx_init,Status=0
    0x1300 = 00064300

    启动成功

     

    6.2 设置ip
    #ifconfigra0 192.168.50.166 netmask 255.255.255.0

     

    6.3 扫描无线网络
    #iwlistra0 scan
    ===>rt_ioctl_giwscan.9(9) BSS returned, data->length = 1476
    ra0       Scancompleted :
              Cell01 - Address:F0:7D:68:96:A6:C2
                        Protocol:802.11b/g/n
                        ESSID:"dlinktf"
                        Mode:Managed
                        Frequency:2.412GHz (Channel 1)
                        Quality=18/100  Signallevel=-83 dBm  Noise level=-92dBm
                        Encryptionkey:on
                        BitRates:54 Mb/s
              Cell02 - Address:F4:EC:38:55:AF:BC
                        Protocol:802.11b/g/n
                        ESSID:"visview"
                        Mode:Managed
                        Frequency:2.427GHz (Channel 4)
                        Quality=18/100  Signallevel=-83 dBm  Noise level=-91dBm
                        Encryptionkey:off
                        BitRates:54 Mb/s

    显示以上信息说明模块已经正常工作

     

    6.4 设置SSIDWEP加密算法
    可以参考里面的iwpriv_usage.txt进行配置,


    6.4.1 
    无密码
    ConfigSTA to link with AP which is OPEN/NONE(Authentication/Encryption)
    1.iwpriv ra0 set NetworkType=Infra
    2. iwpriv ra0 setAuthMode=OPEN
    3. iwpriv ra0 set EncrypType=NONE
    4. iwpriv ra0set SSID="AP's SSID"

     

    6.4.2 WEP加密算法
    iwprivra0 set NetworkType=Infra
    iwpriv ra0 set AuthMode=SHARED
    iwprivra0 set EncrypType=WEP
    iwpriv ra0 set DefaultKeyID=1
    iwpriv ra0set Key1="AP's wep key"
    iwpriv ra0 set SSID="AP'sSSID"

    设置完一会,等网络连接好就可以了。



    WPA加密详见openssl驱动移植wpa_supplicant驱动移植

    RT3070wifi驱动的相关文章

    • bridge-utils驱动移植(2011-06-0314:54:38)

    • wpa_supplicant驱动移植(2011-06-0314:24:17)

    • Openss驱动移植(2011-06-0314:14:02)

    • wireless_tools移植(2011-06-0313:40:09)

    • [首篇]Linux无线WIFI模块驱动移植(基于RT3070(2011-06-0312:00:29)

    • RT3070wifi驱动的全部文章



    http://blog168.chinaunix.net/space.php?uid=7406469&do=blog&id=353430



     


     

    嵌入式linux下usb驱动开发方法--看完少走弯路

    嵌入式linux下的usb属于所有驱动中相当复杂的一个子系统,要想将她彻底征服,至少需要个把月的时间,不信?那是你没做过。

    本人做过2年的嵌入式驱动开发,usb占了一大半的时间。期间走了不少弯路,下面将我的血的经验教训总结下,为要从事和正在从事的战友们做一点点贡献吧:)

    首先,扫盲;

    要做的是阅读usb Spec(英文的哦,其实很多文章、书籍和资料真有水平的还是原创的好,就像食品往往经过加工就变了味,之前如果没有接触过的话可以先看看中文的,大概先有个印象),这个工作其实是很复杂很枯燥的一部分。看Spec的同时可以到网上大概浏览下usb开发的相关知识,这个阶段就是扫盲,不求精进。至少你得知道usb的四种传输类型吧,你得知道usb从上电开始的几个状态吧,你得知道usb设备都有哪些吧,等等。

    第二步,窥全貌;

    usb设备是如何工作起来的?其实usb子系统是分层次工作的,他们配合默契,做好自己的份内之事,一切以大局为重。usb驱动可以分为usb设备驱动,usb控制器驱动,hub驱动,总线驱动等等。我建议你还是顺着设备驱动的这根主线往下走吧。

    在真正开始分析usb驱动代码这之前,你需要了解linux模块机制,linux驱动的platform总线构架,之类。一个模块被加载后,从driver的角度来说,真正将设备驱动起来是从probe开始的。这个你该知道。你得知道为什么usb可以即插即用,做软件的朋友该知道线程这个东西吧,和她有关系的。usb系统里面一个最重要的角色该出场了,urb。一切的一切都要围绕她进行。pipe为她铺路,数据由她承载。usb设备驱动的工作就是准备好这个urb后她的使命就基本完成了,那她把urb给了谁?这就是之前提到的usb控制器驱动,host。

    至于host,现在市场上有很多款,如果你老板给你用的是市面上用的最成熟的像EHCI,那么你太幸运了。这个基本不用你写,只要稍加修改,把她注册到总线上即可。如果你很不幸,使用了像musb这样的host,你惨了,有你苦头吃了。

    第三步,精益求精;

    这个时候驱动你也调过了,也许这时候已经跑起来了,也许还没跑起来。可能你开始浮躁了,到这个时候咋的也过去个把月了,如果还没出成果难免心急。好,这时候如果是这样,你该做什么呢?    重新看Spec,重新看整个驱动过程,重复之前做过的事情。这次你再看绝对和之前不一样了。这时候你要学会的是,坚持,耐力.................

    最后,给大家介绍一下我自认为不错的资料,你可以参考。像复旦一哥们写的linux那点事儿(大家嫌麻烦可以到我这里下载Linux那些事儿之我是U盘.pdf),ldd3,最好的资料是源代码。



     

    嵌入式Linux USB WIFI驱动的移植

    硬件平台:飞思卡尔 MX258 开发板

    操作系统: Linux2.6.31

    WIFI :     RT2860 USB WIFI 模组

    交叉编译环境: gcc version 4.1.2

     

    调试步骤:

    第一步:测试 USB   HOST 接口

    在 menuconfig 中将 USB HOST 设置为内核模式:

    点击查看原始尺寸

     

    重新编译内核后启动开发板,插入 U 盘并挂载:

    mount /dev/sda1 /tmp

    ls /tmp

    可以看到 U 盘已经正常挂载,测试 USB   HOST OK!

    第二步:网上下载雷凌最新的 USB 驱动,

    2011_0107_RT3070_RT3370_Linux_STA_v2[1].5.0.1_DPO.tar.bz2

    拷备到 Linux 目录并解压:

    tar  jxf  2011_0107_RT3070_RT3370_Linux_STA_v2[1].5.0.1_DPO.tar.bz2

    由于上面名字很长,可以修改为简短的名字:

    mv  2011_0107_RT3070_RT3370_Linux_STA_v2[1].5.0.1_DPO  RT3070_Linux_STA

    第三步:进入 RT3070_Linux_STA 目录,看到有一个 README_STA_usb 文件,里面介绍了如何加载该驱动:

    =======================================================================

    Build Instructions: 

    ====================

     

    1> $tar -xvzf DPB_RT2870_Linux_STA_x.x.x.x.tgz

        go to "./DPB_RT2870_Linux_STA_x.x.x.x" directory.

       

    2> In Makefile

               set the "MODE = STA" in Makefile and chose the TARGET to Linux by set "TARGET = LINUX"

               define the linux kernel source include file path LINUX_SRC

               modify to meet your need.

     

    3> In os/linux/config.mk

             define the GCC and LD of the target machine

             define the compiler flags CFLAGS

             modify to meet your need.

             ** Build for being controlled by NetworkManager or wpa_supplicant wext functions

                Please set 'HAS_WPA_SUPPLICANT=y' and 'HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=y'.

                => #>cd wpa_supplicant-x.x

                => #>./wpa_supplicant -Dwext -ira0 -c wpa_supplicant.conf -d

             ** Build for being controlled by WpaSupplicant with Ralink Driver

                Please set 'HAS_WPA_SUPPLICANT=y' and 'HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=n'.

                => #>cd wpa_supplicant-0.5.7

                => #>./wpa_supplicant -Dralink -ira0 -c wpa_supplicant.conf -d

     

    4> $make

             # compile driver source code

             # To fix "error: too few arguments to function ˉ iwe_stream_add_event"

               => $patch -i os/linux/sta_ioctl.c.patch os/linux/sta_ioctl.c

     

    5> $cp RT2870STA.dat  /etc/Wireless/RT2870STA/RT2870STA.dat

       

    6> load driver, go to "os/linux/" directory.

        #[kernel 2.4]

        #    $/sbin/insmod rt2870sta.o

        #    $/sbin/ifconfig ra0 inet YOUR_IP up

       

        #[kernel 2.6]

        #    $/sbin/insmod rt2870sta.ko

        #    $/sbin/ifconfig ra0 inet YOUR_IP up

     

    7> unload driver   

        $/sbin/ifconfig ra0 down

             $/sbin/rmmod rt2870sta

    这里 go to "./DPB_RT2870_Linux_STA_x.x.x.x" directory. 即我们刚解压的 RT3070_Linux_STA目录。修改该目录下的 makefile 文件,以下只给出修改部分:

    #PLATFORM = PC

    PLATFORM = RALINK_2880

     

    ifeq ($(PLATFORM), RALINK_2880)

    LINUX_SRC = /home/lqm/share/G360/kernel_kfb

    CROSS_COMPILE = /opt/freescale/usr/local/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi-

    endif

    ifeq ($(RT28xx_MODE),APSTA)

             cp -f $(RT28xx_DIR)/os/linux/rt$(CHIPSET)apsta.ko /tftpboot

    ifeq ($(OSABL),YES)

             cp -f $(RT28xx_DIR)/os/linux/rtutil$(CHIPSET)apsta.ko /tftpboot

             cp -f $(RT28xx_DIR)/os/linux/rtnet$(CHIPSET)apsta.ko /tftpboot

    endif

    else

             cp -f $(RT28xx_DIR)/os/linux/rt$(CHIPSET)sta.ko /home/lqm/share/NFS/tmp

    注意,虽然我们使用的是 2860 模组,我们这里仍然可以定义 PLATFORM 为 RALINK_2880,只要后面对应的编译环境正确就可以了。 LINUX_SRC 表示内核的目录, CORSS_COMPILE 为交叉编译环境,最末一行为编译完后将生成的 KO 文件复制到 NFS 文件系统的 tmp 目录。

    第四步:按照第三步 README_STA_usb 给出的提示,修改 config.mk 文件,这里也只给出修改部分:

    # Support Wpa_Supplicant

    HAS_WPA_SUPPLICANT=y

    # Support Native WpaSupplicant for Network Maganger

    HAS_NATIVE_WPA_SUPPLICANT_SUPPORT=n

    CC := /opt/freescale/usr/local/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi-gcc

    LD := /opt/freescale/usr/local/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi-ld

    ifeq ($(PLATFORM), RALINK_2880)

    EXTRA_CFLAGS := -D__KERNEL__ -I$(LINUX_SRC)/include -I$(RT28xx_DIR)/include -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -Uarm -fno-common -pipe -D__LINUX_ARM_ARCH__=5 -march=armv5te -msoft-float -Uarm -DMODULE -DMODVERSIONS -include $(LINUX_SRC)/include/config/modversions.h $(WFLAGS)

    export EXTRA_CFLAGS

    endif

    注意,这里 CC 为交叉编译环境, LD 为交叉编译的链接。默认 EXTRA_CFLAGS 为 CFLAGS ,这里需要修改为 EXTRA_CFLAGS ,否则编译时会提示如下错误:

    scripts/Makefile.build:49: *** CFLAGS was changed in "/home/lqm/share/RT3070_Linux_STA/os/linux/Makefile". Fix it to use EXTRA_CFLAGS 。 停止。

    LINUX_ARM_ARCH 一定要设置为 5 , -march 一定要设置得和 CPU 匹配,由于这里为 MX258,因此设置为 armv5te ,不可设置为 armv5t 或 armv5 ,否则出现如下错误:

      CC [M]  /home/lqm/share/RT3070_Linux_STA/os/linux/../../os/linux/rt_main_dev.o

    {standard input}: Assembler messages:

    {standard input}:340: Error: selected processor does not support `pld [r5,#0]'

    {standard input}:349: Error: selected processor does not support `pld [r5,#0]'

    make[2]: *** [/home/lqm/share/RT3070_Linux_STA/os/linux/../../os/linux/rt_main_dev.o] 错误 1

    make[1]: *** [_module_/home/lqm/share/RT3070_Linux_STA/os/linux] 错误 2

    make[1]: Leaving directory `/home/lqm/share/G360/kernel_kfb'

    make: *** [LINUX] 错误 2

    [root@lqm RT3070_Linux_STA]#

     

    第五步: make

     

    如果编译一切正常,将会在 \RT3070_Linux_STA\os\linux 目录下生成 rt3070sta.ko 文件。

    第六步:将 USB WIFI 模组插到开发板的 USB HOST 端口,将 rt3070sta.ko 文件复制到文件系统的 /tmp目录,重启开发板,进入文件系统后加载驱动:

    cd  /tmp

    insmod  rt3070sta.ko

    这时会提示如下信息:

    root@freescale ~$ cd /tmp

    root@freescale /tmp$ insmod rt3070sta.ko

    rtusb init rt2870 --->

     

     

    === pAd = c49eb000, size = 509592 ===

     

    <-- RTMPAllocTxRxRingMemory, Status=0

    <-- RTMPAllocAdapterBlock, Status=0

    usbcore: registered new interface driver rt2870

    root@freescale /tmp$

    第七步:配置无线网卡

    首先检测开发板的网络设备:

    ifconfig

    可以看到这时只有 eth0 和 lo 两个网络信号,使用如下命令设置无线网卡的网络地址:

    ifconfig ra0 192.168.1.5

    打印信息如下:

    root@freescale /tmp$ ifconfig ra0 192.168.1.5

    (Efuse for 3062/3562/3572) Size=0x2d [2d0-2fc]

    RTMP_TimerListAdd: add timer obj c4a32d88!

    RTMP_TimerListAdd: add timer obj c4a32db4!

    RTMP_TimerListAdd: add timer obj c4a32de0!

    RTMP_TimerListAdd: add timer obj c4a32d5c!

    RTMP_TimerListAdd: add timer obj c4a32cd8!

    RTMP_TimerListAdd: add timer obj c4a32d04!

    RTMP_TimerListAdd: add timer obj c49fd91c!

    RTMP_TimerListAdd: add timer obj c49ece5c!

    RTMP_TimerListAdd: add timer obj c49ece90!

    RTMP_TimerListAdd: add timer obj c49fd9b4!

    RTMP_TimerListAdd: add timer obj c49fd8c4!

    RTMP_TimerListAdd: add timer obj c49fd984!

    -->RTUSBVenderReset

    <--RTUSBVenderReset

    Key1Str is Invalid key length(0) or Type(0)

    Key2Str is Invalid key length(0) or Type(0)

    Key3Str is Invalid key length(0) or Type(0)

    Key4Str is Invalid key length(0) or Type(0)

    1. Phy Mode = 5

    2. Phy Mode = 5

    NVM is Efuse and its size =2d[2d0-2fc]

    phy mode> Error! The chip does not support 5G band 5!

    RTMPSetPhyMode: channel is out of range, use first channel=1

    (Efuse for 3062/3562/3572) Size=0x2d [2d0-2fc]

    3. Phy Mode = 9

    MCS Set = ff 00 00 00 01

    <==== rt28xx_init, Status=0

    0x1300 = 00064300

    root@freescale /tmp$

    再使用 ifconfig 查看网络设备:

    root@freescale /tmp$ ifconfig

    eth0      Link encap:Ethernet  HWaddr 00:04:9F:00:EB:33 

              inet addr:172.18.2.133  Bcast:172.18.255.255  Mask:255.255.0.0

              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

              RX packets:3182 errors:0 dropped:0 overruns:0 frame:0

              TX packets:1380 errors:0 dropped:0 overruns:0 carrier:0

              collisions:0 txqueuelen:1000

              RX bytes:3079209 (2.9 MiB)  TX bytes:227540 (222.2 KiB)

              Base address:0xa000

     

    lo        Link encap:Local Loopback 

              inet addr:127.0.0.1  Mask:255.0.0.0

              UP LOOPBACK RUNNING  MTU:16436  Metric:1

              RX packets:0 errors:0 dropped:0 overruns:0 frame:0

              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

              collisions:0 txqueuelen:0

              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

     

    ra0       Link encap:Ethernet  HWaddr 00:E0:61:37:D0:10 

              inet addr:192.168.1.5  Bcast:192.168.1.255  Mask:255.255.255.0

              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

              RX packets:631 errors:0 dropped:0 overruns:0 frame:0

               TX packets:83 errors:0 dropped:0 overruns:0 carrier:0

              collisions:0 txqueuelen:1000

              RX bytes:92470 (90.3 KiB)  TX bytes:8736 (8.5 KiB)

     

    root@freescale /tmp$

    可以看到这时多了一组 ra0 设备,它就是无线网卡的相关信息。

    第八步:下载并编译无线网络工具 wireless_tools.29.tar.gz

    tar  zxf  wireless_tools.29.tar.gz

    cd  wireless_tools.29

    修改 makefile ,修改部分如下:

    ## Compiler to use (modify this for cross compile).

    CC = arm-none-linux-gnueabi-gcc

    ## Other tools you need to modify for cross compile (static lib only).

    AR = arm-none-linux-gnueabi-ar

    RANLIB = arm-none-linux-gnueabi-ranlib

    修改后 make ,成功后会在当前目录生成 iwspy , iwpriv , iwlist 以及 iwconfig 等文件。我们只需将这四个文件拷备到 NFS 文件系统的 sbin 目录,然后将当前目录的 libiw.so.29 库文件拷到 NFS 文件系统的lib 目录,无线网络工具即安装完成。

     

    第九步:查看无线网络:

     

    iwlist ra0 scanning

    这时如果设备周边有无线信号,将会搜索出这些信号并打印出来,例如:

    dBm

                         Encryption key:on

                        Bit Rates:54 Mb/s

                        IE: WPA Version 1

                            Group Cipher : TKIP

                            Pairwise Ciphers (2) : CCMP TKIP

                            Authentication Suites (1) : PSK

                        IE: IEEE 802.11i/WPA2 Version 1

                            Group Cipher : TKIP

                            Pairwise Ciphers (2) : CCMP TKIP

                            Authentication Suites (1) : PSK

              Cell 23 - Address: 00:25:5E:1E:38:5A

                        Protocol:802.11b/g

                        ESSID:"ChinaNet-UWfq"

                        Mode:Managed

                        Frequency:2.412 GHz (Channel 1)

                        Quality=26/100  Signal level=-79 dBm  Noise level=-74 dBm

                        Encryption key:on

                        Bit Rates:54 Mb/s

                        IE: WPA Version 1

                            Group Cipher : TKIP

                            Pairwise Ciphers (1) : TKIP

                             Authentication Suites (1) : PSK

                        IE: Unknown: DD0E0050F204104A0001101044000102

              Cell 24 - Address: 00:25:5E:1D:2F:FF

                        Protocol:802.11b/g

                        ESSID:"ChinaNet-eSpK"

                         Mode:Managed

                        Frequency:2.437 GHz (Channel 6)

                        Quality=42/100





    使用usbfs与内核驱动之间的冲突

    usb驱动分为通过usbfs操作设备的用户空间驱动,内核空间的内核驱动。两者不能同时进行,否则容易引发对共享资源访问的问题,死锁!使用了内核驱动,就不能在usbfs里驱动该设备。libusb中须要先detach内核驱动后,才能claim interface,否则claim会返回的vice busy的错误。如果你不dettach,也不claim interface,也能使用libusb对设备进行访问,但是,容易导致内核usbfs瘫痪,这是不允许的。


    如果不能dettach内核驱动,那么你不能通过usbfs访问设备,也就是不能使用libusb。若确实需要usbfs才能完成的操作,如控制传输,中断传输等,可以在内核驱动里给ioctl添加对应的功能,即可通过内核驱动完成usb设备的所有原始通信。


    使用libusb读写ft232的eeprom,不允许把内核驱动dettach的情况下,经常导致usbfs瘫痪,所有usb都处于disk sleep状态。这里我之用得到control传输,经过一番思考,我在内核驱动里面的ioctl里添加了USBDEVFS_CONTROL选项,通过内核驱动完成usb control msg,测试了好几天,没发现任何问题。好,基本完成任务。


    以下是我的操作:

    在设备驱动文件ftdi_sio.c的ioctl函数里面添加:

    [cpp] view plaincopy
    1. static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)  
    2. {  
    3.     struct ftdi_private *priv = usb_get_serial_port_data(port);  
    4.   
    5.     int  ret, mask;  
    6.       
    7.     dbg("%s cmd 0x%04x", __FUNCTION__, cmd);  
    8.   
    9.     /* Based on code from acm.c and others */  
    10.     switch (cmd) {  
    11.   
    12.     /* To support usb_control_msg to ttyUSB */  
    13.     case USBDEVFS_CONTROL:  
    14.         dev_printk(KERN_DEBUG, &port->serial->dev->dev, "%s: CONTROL\n", __FUNCTION__);  
    15.         return tty_control(port, (void __user *)arg);  
    16.         break;  
    17.   
    18.     case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */  
    19.         。。。。。。  

    以下是从usbfs的proc_control()移植过来的控制传输函数:

    [cpp] view plaincopy
    1. static int tty_control(struct usb_serial_port *port, void __user *arg)  
    2. {  
    3.     struct usb_device *dev = port->serial->dev;  
    4.     struct usbdevfs_ctrltransfer ctrl;  
    5.     unsigned int tmo;  
    6.     unsigned char *tbuf;  
    7.     int i, j, ret;  
    8.   
    9.     if (copy_from_user(&ctrl, arg, sizeof(ctrl)))  
    10.         return -EFAULT;  
    11.     //if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex)))  
    12.         //return ret;  
    13.     if (ctrl.wLength > PAGE_SIZE)  
    14.         return -EINVAL;  
    15.     if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))  
    16.         return -ENOMEM;  
    17.     tmo = (ctrl.timeout * HZ + 999) / 1000;  
    18.     if (ctrl.bRequestType & 0x80) {  
    19.         if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) {  
    20.             free_page((unsigned long)tbuf);  
    21.             return -EINVAL;  
    22.         }  
    23.         dev_printk(KERN_DEBUG, &dev->dev, "control read: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex);  
    24.   
    25.         i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,  
    26.                        ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);  
    27.         if ((i > 0) && ctrl.wLength) {  
    28.             if (copy_to_user(ctrl.data, tbuf, ctrl.wLength)) {  
    29.                 free_page((unsigned long)tbuf);  
    30.                 return -EFAULT;  
    31.             }  
    32.         }  
    33.     } else {  
    34.         if (ctrl.wLength) {  
    35.             if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) {  
    36.                 free_page((unsigned long)tbuf);  
    37.                 return -EFAULT;  
    38.             }  
    39.         }  
    40.         dev_printk(KERN_DEBUG, &dev->dev, "control write: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex);  
    41.         i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,  
    42.                        ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo);  
    43.     }  
    44.     free_page((unsigned long)tbuf);  
    45.     if (i<0) {  
    46.         dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "  
    47.                "failed cmd %s rqt %u rq %u len %u ret %d\n",  
    48.                current->comm, ctrl.bRequestType, ctrl.bRequest,  
    49.                ctrl.wLength, i);  
    50.     }  
    51.     return i;  
    52. }  


    好了,编译加载后,设备文件就支持usb_control_msg了。以下是用户程序的usb_control_msg

    [cpp] view plaincopy
    1. #define IOCTL_USB_CONTROL   _IOWR('U', 0, struct usb_ctrltransfer)  
    2.   
    3. struct usb_ctrltransfer {  
    4.     /* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */  
    5.     u_int8_t  bRequestType;  
    6.     u_int8_t  bRequest;  
    7.     u_int16_t wValue;  
    8.     u_int16_t wIndex;  
    9.     u_int16_t wLength;  
    10.   
    11.     u_int32_t timeout;    /* in milliseconds */  
    12.   
    13.     /* pointer to data */  
    14.     void *data;  
    15. };  
    16.   
    17. static int usb_control_msg(int fd, int requesttype, int request,  
    18.     int value, int index, char *bytes, int size, int timeout)  
    19. {  
    20.   struct usb_ctrltransfer ctrl;  
    21.   int ret;  
    22.   
    23.   ctrl.bRequestType = requesttype;  
    24.   ctrl.bRequest = request;  
    25.   ctrl.wValue = value;  
    26.   ctrl.wIndex = index;  
    27.   ctrl.wLength = size;  
    28.   
    29.   ctrl.data = bytes;  
    30.   ctrl.timeout = timeout;  
    31.   
    32.   ret = ioctl(fd, IOCTL_USB_CONTROL, &ctrl);  
    33.   if (ret < 0)  
    34.     printf("usb_control_msg: %s\n", strerror(errno));  
    35.   
    36.   return ret;  
    37. }  

    其实,上面的usb_ctrltransfer和usbdevice_fs.h 里的struct usbdevfs_ctrltransfer是一样的,只是为了方便查阅,才定义了另外一个在源文件里。

    linux-2.6.8.1/include/linux/usbdevice_fs.h

    [cpp] view plaincopy
    1. /* usbdevfs ioctl codes */  
    2.   
    3. struct usbdevfs_ctrltransfer {  
    4.     __u8 bRequestType;  
    5.     __u8 bRequest;  
    6.     __u16 wValue;  
    7.     __u16 wIndex;  
    8.     __u16 wLength;  
    9.     __u32 timeout;  /* in milliseconds */  
    10.      void __user *data;  
    11. };  
    12.   
    13. #define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)  




    /*-----------------------------------------下面是w90x900 usb host调试纪实-------------------------------------------*/

    w90x900驱动之USB HOST

    44.bmp 1.1.1.嵌入式开发联盟2 p; d& o6 w* Q/ I- V& ]
    USB 2.0 Host Controller概述4 ^! G3 C" ?3 C/ A1 Q
    嵌入式开发联盟5 Q- Z" s2 @, q# V0 o- A6 T
    111.bmp 



    上图为USB2.0协议的规范框图,灰色部分是EHCI规范的范围。EHCI 规范定义了USB2.0 host controller寄存器层面的接口,同时包括了host controller driverhost controller软硬件之间的接口,华邦集成了USB2.0host就是说华邦ARM9系列有EHCI规范部分的寄存器层面的接口。嵌入式开发联盟" H* C- O; r4 t! f7 f

    # r$ _- J3 Q' O/ Z

    33.bmp 
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,0 ~: I  J, R! L" s- ?; y) g! \! z4 e3 H

    嵌入式开发联盟: q4 T7 N. D4 O% ~5 c% X

    USB 2.0 Host Controller一般包含1个支持高速模式的eHC0~多个支持低速、全速模式的companion HCs,这样可以同时支持三种速度模式的USB设备。Port Routing Logic根据软件的配置以及所插入的usb device speed mode,将port1~portN映射到cHCs 或者 eHC的对应端口:

    EHCD driver
    没有配置eHCport routing logic将所插入设备的port映射到cHCs的对应port


    EHCD driver 
    配置了eHC后,当一个USB设备插入root hub port时,先要做一件routing的事情。所有的root hub port默认是被EHCI占有的,所以,EHCI和插入的USBb设备通信,看是不是高速设备,如果是就开始映射高速端口。如果不是,EHCI就放弃这个port的占有权,让给companion HC(uhci/ohci)去管理。
    嵌入式开发联盟. }0 l. `: ~* u8 U% S6 O5 Z9 `
       华邦910有两个USB host端口。嵌入式开发联盟4 t) d. X3 U. y; D" B+ z/ M" n+ K$ H
    1.1.2.
    华邦USB 2.0 Host Controller驱动编写
     LinuxUSB子系统的结构图如下:
    我们所谓的开发Linux USB驱动主要是开发hc_driverusb_driver,但是Linux已经开发了大部分的USB接口驱动usb_driver,那么留给我们所要做的就是写华邦ARM9的硬件host寄存器就是为了实现hc_driver驱动。 



    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,# [! y5 ]0 _( o


    华邦ARM9host驱动符合上面讲解的platform_driver_register注册驱动的接口,所以从probe函数开始执行:
    www.mcuos.com/ m# S5 v# a7 E; j; v
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。& o9 o% P1 O, }
    static struct platform_driver ehci_hcd_w90x900_driver = {我们只做简洁、专业的嵌入式开发技术论坛。5 r; P1 j, E, _1 |: r& c

    www.mcuos.com5 ^2 D$ M# Y5 d: M" _1 a
    .probe = ehci_w90x900_probe,


    .remove = ehci_w90x900_remove,


    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,; g4 z, F  W, ~5 c4 @. ~
    .driver = {
    % J! {: L0 M+ M9 h: b
    2 J( [3 \1 L% r
    % c4 N2 w7 W. p, H  I

    .name = "w90x900-ehci",

    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。. l* y5 s6 l: j  J5 c

    .owner= THIS_MODULE,

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,% O) k* F0 \9 o0 U4 {/ i
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,9 |) {* |- E3 g. O: B
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。- r/ O6 I) a7 V4 ]
    },

    };
    www.mcuos.com& p. G2 H* p- M  {) C1 y
    static int ehci_w90x900_probe(struct platform_device *pdev)
    {

    if (usb_disabled())

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,2 h1 h2 e1 v3 [: A# o. M" z
    return -ENODEV;
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。8 U+ A& p; o1 Z3 \
    嵌入式开发联盟* ^$ W  a1 A  H

    return 
    usb_w90x900_probe(&ehci_w90x900_hc_driver, pdev);
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,% Z% k% S& R6 o& v& N! {
    }

    我们只做简洁、专业的嵌入式开发技术论坛。: E4 G" L. t4 S5 n% S
    usb_w90x900_probe函数探测真正的host controller驱动hc_driver

    static const struct hc_driver ehci_w90x900_hc_driver = {- 我们只做简洁、实用、专业的嵌入式开发技术论坛。1 _8 w$ W7 I# j  w/ u

    .description = hcd_name,

    嵌入式开发联盟! [( l6 I0 g* m
    .product_desc = "Winbond w90x900 EHCI Host Controller",

    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。4 y4 T( F" L6 l/ M+ ^
    .hcd_priv_size = sizeof(struct ehci_hcd),
    嵌入式开发联盟  d. y0 n- u9 X; F; L2 Z
    嵌入式开发联盟$ f9 t3 f' s: T# ]9 w$ G7 _& O
    嵌入式开发联盟5 p% r6 h7 t: Q# N
    /*
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。4 j3 o& b9 |) d) y  x# |7 A
    www.mcuos.com! f: X# f3 u  N1 n
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,1 ^, d& B# i! T4 N2 r
    * generic hardware linkage
    我们只做简洁、专业的嵌入式开发技术论坛。3 b8 v$ m( \8 q8 Q/ }& K  ^
    " v! T" H& A( J9 [7 E# P
    嵌入式开发联盟1 P; l9 g) N+ d
    */
    我们只做简洁、专业的嵌入式开发技术论坛。- U, W2 b& t/ y
           .irq = ehci_irq,
           .flags = HCD_USB2|HCD_MEMORY,
    ( C3 G! o( g  N$ h& w  q/ }

    /*


    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。4 ]8 X( O& T! o
    * basic lifecycle operations

    嵌入式开发联盟* r+ w/ M; f3 ]0 W/ E  B8 Q
    : T9 S( [! z- V- j% J) i
    */
    ' `0 U* L3 J1 f
           .reset = ehci_init,
           .start = ehci_run,

    嵌入式开发联盟: s; O) S+ g* z4 W' }8 |
    .stop = ehci_stop,
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。0 b* s6 {# [7 s# [( z$ O
    ; c( j& W6 i' T( R4 A/ F
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,% n& q: B' P  X" t
    /*
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。6 Y& ?' D/ A; Z9 A% Q

    + ?0 g' ~  Q1 d* [. V$ r
    * managing i/o requests and associated device resources
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,3 b' ?& Z8 \; d* v
    www.mcuos.com1 e* C7 H% _: m$ Q# D6 O' w# b" a
    $ p& Z3 \2 y6 ?0 z
    */


    .urb_enqueue = ehci_urb_enqueue,


    .urb_dequeue = ehci_urb_dequeue,

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,5 B; [6 t4 {9 ^( b5 V5 H" U! W
    .endpoint_disable = ehci_endpoint_disable,

    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。  K# P5 R9 ]# B2 W9 P; l8 }
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,0 f- p8 l0 y; n; N  S
    /*



    * scheduling support
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。1 ?' B- V8 w' ], k6 t/ G$ l  x
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。# m7 y) X% Y4 P' d  o& g1 }7 x$ Y
    www.mcuos.com- r3 O- G) o* e$ _& f
    */

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,) S6 X- G: z' d3 b
    .get_frame_number = ehci_get_frame,
    嵌入式开发联盟2 ~! i7 }- D1 r; [( T


    /*

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,0 R# g1 H, e) t7 x- D2 m
    我们只做简洁、专业的嵌入式开发技术论坛。% {$ @/ E7 {8 a* s6 L1 m: m
    * root hub support

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,9 {) W6 [0 s+ ?5 S1 c& C& G, a

    */


    .hub_status_data = ehci_hub_status_data,

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,  k( [8 @* q3 W. ]* N0 L
    .hub_control = ehci_hub_control,

    #ifdefwww.mcuos.com: y% Z* J- ^# v/ R
    CONFIG_PM
    0 U8 S% h! |. q: f; O6 C+ b& }; p

    .bus_suspend = ehci_bus_suspend,


    .bus_resume = ehci_bus_resume,

    #endif
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。, F4 O+ d3 F3 {& L: g
    };
    我们只做简洁、专业的嵌入式开发技术论坛。4 b: g0 k9 i( f+ d
    自此从usb_w90x900_probe开始正式进入usb驱动之旅。嵌入式开发联盟6 {# N& U3 T+ P" @6 R. x
    int usb_w90x900_probe(const struct hc_driver *driver,& V4 ^# b' |( g


    struct platform_device *pdev)
    www.mcuos.com9 Z8 t4 r* s0 J
    {嵌入式开发联盟+ p6 J8 a0 F  t' F. Y" }# T5 z
    //介绍两个重要的结构体:

    struct usb_hcd *hcd;
    //
    描述usb主控制设备的数据结构体,抽象的数据结构。

    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。: C1 k; N; t, v! U
    struct ehci_hcd *ehci;
     /
    描述华邦910芯片的usb主控制设备的数据结构体,具体的数据结构,具体到某款芯片的ehci还是uhci主控制器。

    www.mcuos.com; A6 r5 M4 T8 i8 H/ b2 C: O
    int retval;
    3 d  `$ \8 Y! I' U; X
    我们只做简洁、专业的嵌入式开发技术论坛。; x: b6 e; A* y7 Y3 D* z
    /* enable USB Host clock */
    嵌入式开发联盟) S5 L6 f. v6 B' L7 T' `6 W
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,% G: J% q' Q; O1 A
    outl(inl(W90X900_CLKEN) | 0x200, W90X900_CLKEN);

           arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,, h" @- S# P. c/ l7 d6 F  L; V
    www.mcuos.com5 J( b3 t' k: b) r* X
    if (pdev->resource[1].flags != IORESOURCE_IRQ) {


    pr_debug("resource[1] is not IORESOURCE_IRQ");


    retval = -ENOMEM;


    }

           - 我们只做简洁、实用、专业的嵌入式开发技术论坛。" X% R& l1 T# }8 Y+ {6 ]
    //创建一个hcd结构体定义为:usb_hcd,为华邦910usbhost controller的数据结构分配一个空间,初始化usb_host总线,初始化主控制器轮询hub状态的timer使用的是前面讲过的内核timer,设置主控制器驱动为hc_driver.
    usb_bus -- 搬运usb数据
    usb_bus->controller指向华邦910usb主控制器www.mcuos.com) n. t  h; r9 ~! [* M& E8 O6 a# ^
        usb_bus->root_hub
    指向该usb总线上的根Hub,这里初始化为空嵌入式开发联盟( k6 {$ n7 u3 v! ^
    www.mcuos.com7 o/ U: k- v) U. g$ z$ L
    hcd = 
    usb_create_hcd(driver, &pdev->dev, "w90x900 EHCI");

    www.mcuos.com. Y9 g9 E  i$ z
    if (!hcd) {

    www.mcuos.com1 R$ Y- m, u2 Y; P1 U
    retval = -ENOMEM;


    goto err1;

    我们只做简洁、专业的嵌入式开发技术论坛。# |9 |4 w, `+ ~& r3 H) b, j1 [
    }



           hcd->rsrc_start = pdev->resource[0].start;- 我们只做简洁、实用、专业的嵌入式开发技术论坛。" \6 K9 G) |3 Q2 e( V9 z
           hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,. I2 x2 Z/ T' x' J
    我们只做简洁、专业的嵌入式开发技术论坛。+ W- x: w& s# ]5 R
    if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
    www.mcuos.com3 I$ w5 N) b2 `& E7 U% b8 S1 J+ ^
    9 [, n' y/ M% P2 G" d7 O+ `" G
    pr_debug("request_mem_region failed");
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,/ i. z/ e6 t$ m4 r* P  g
    嵌入式开发联盟3 R7 \9 T1 R6 [$ A# Z
    retval = -EBUSY;
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。0 V  r* |+ g2 \& g1 E
    ' c' E* F/ ^/ a* d0 |% [' a+ C
    goto err2;
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。0 ]! ]4 C, L+ C7 ?. h* a
    嵌入式开发联盟- j, f' O6 T" G: s6 P7 W
    }


           hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);

    if (hcd->regs == NULL) {
    嵌入式开发联盟6 s  e. z6 \% d( e% O
    我们只做简洁、专业的嵌入式开发技术论坛。9 q; n2 Z! r* K4 D+ N' ]' m
    pr_debug("error mapping memory\n");
    www.mcuos.com8 I% E+ H6 b1 B4 b6 P% k. e" T% Y

    retval = -EFAULT;

    我们只做简洁、专业的嵌入式开发技术论坛。+ Z# O6 W5 K. W7 U, E; G3 g# |
    goto err3;
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,) ]  u- R  t% r% ^
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。4 s% ~% _& [5 D" @! z4 ^) t
    }
    : L7 i3 u/ i7 f$ O8 J6 m7 P# m
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,8 x6 x' F- `$ C1 q; D- k
           www.mcuos.com3 |7 E% N0 M9 _0 p7 _. ~$ M0 p
    嵌入式开发联盟- D# z3 J! q# l9 W( K
    ehci = hcd_to_ehci(hcd);
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,- k3 c, a6 J& z- t

    ehci->caps = hcd->regs;

    , x7 {: F4 s! K$ c( _9 \
    ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));

    www.mcuos.com" T% B' J8 o: V

    usb_io_map_addr = (unsigned int)ehci->caps;
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,. T1 t( g# Y) O. q
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。/ @' y% |+ m8 H: C/ A6 z

    // Set over current low


    outl(0x08, W90X900_VA_USBOHCIHOST + 0x204);

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,* \* V$ [: c, v9 |6 l8 j
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。5 h$ I% C; f& V' Q% _
    www.mcuos.com7 v3 f" S4 k& Z- D
    /* enable PHY 0 */
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。( X! W7 }- C) J. {. P7 N
           writel(0x160, &ehci->regs->phy_ctr0);: c8 W# f' P$ L

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,% e* S5 d6 @$ i$ Z* t
    /* enable PHY 1 */
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。8 G5 {0 S! l8 V6 z! W3 [
           writel(0x520, &ehci->regs->phy_ctr1);arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,) x$ Y: W. \4 m( M7 a7 N
           3 O7 M. b) p" Q
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,1 m) h* a) F. R1 X$ y
    /* cache this readonly data; minimize chip reads */


    ehci->hcs_params = readl(&ehci->caps->hcs_params);
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,) \, R& C2 C$ U! T3 y2 p1 H
    嵌入式开发联盟; Z6 @" @/ e  \6 N- g3 S
    ehci->sbrn = 0x20;
    我们只做简洁、专业的嵌入式开发技术论坛。. W, R8 g% O0 c, C' ^% T
    //该函数负责注册usb host总线,分配一个根hub结构并初始化hcd->self.root_hub = rhdev;
    //这个函数很重要主要讲解一下:嵌入式开发联盟# ?7 t  e, P. }  f! f# s- \
    $ R9 q( f/ H9 g4 q
    retval = 
    usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
    我们只做简洁、专业的嵌入式开发技术论坛。4 y5 b3 l- h7 k6 H+ T/ {) e
    # Z/ n5 n7 A8 o. y3 ], i5 ?

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,; ^5 t9 J1 @4 p% N/ ]8 b
    if (retval != 0)
    www.mcuos.com$ _% s& d+ E; y' h
    我们只做简洁、专业的嵌入式开发技术论坛。5 ~( D9 F9 U" r7 t7 X
    goto err4;
    www.mcuos.com, T: x7 T, B3 v/ V1 e; U


    /* enable EHCI */
    www.mcuos.com4 M8 B4 K8 c9 t. `

    //ehci->regs->configured_flag = 1;, @8 q& j- j+ j( ~; Q  {1 q* t6 B9 H: U

           writel(1, &ehci->regs->configured_flag);

    www.mcuos.com/ \0 C, o: {; x9 f% J% h1 d
    return retval;


    我们只做简洁、专业的嵌入式开发技术论坛。7 d) x6 N1 e  A- N$ o( ^; u' u
    err4:

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,7 \  H* S' y1 M. P/ @+ X
    iounmap(hcd->regs);
    0 x: {% \; B" f3 N9 W( g5 h. Q  e

    err3:


    release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
    嵌入式开发联盟7 n/ H& ^! R+ h% v$ Y  b

    err2:
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,8 o- J9 r8 O, f) u* g

    usb_put_hcd(hcd);

    9 @: [% |3 L' ?0 v
    err1:
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,2 X6 n! a  {# @6 `1 ^+ c/ Z
    www.mcuos.com7 k" q, d7 @5 Z" y# I
    //printk("init %s fail, %d\n", "wb_ehci", retval);

    嵌入式开发联盟8 w" t, ]* ]' |8 y1 \
    2 I: X. s, \& K
    printk("akl;fjasl;k;dk");

    www.mcuos.com3 z; ^4 }+ k9 U
    //while(1);
    嵌入式开发联盟+ l4 U& d4 [+ f% N: V
    www.mcuos.com- \: T0 G+ H8 _3 ~3 W/ C' g/ P
    return retval;
    我们只做简洁、专业的嵌入式开发技术论坛。9 ?* F, L7 l/ P0 Q0 s+ n- C# o
    }
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。3 P; p- L/ |) K3 `: }  ?
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,( [; I; M( p3 g1 I# _' C  W; s
    我们只做简洁、专业的嵌入式开发技术论坛。0 d$ r$ X7 ~, j& Q
    int usb_add_hcd(struct usb_hcd *hcd,0 R- ~# Q+ a+ ]: _3 ]

    unsigned int irqnum, unsigned long irqflags)

    {www.mcuos.com5 t6 [9 y3 W: a) p" z& Z- o2 l* x

    int retval;
    嵌入式开发联盟5 c5 m0 g% E8 r
    嵌入式开发联盟8 ?3 G7 _3 Z+ q2 v6 i! j/ ?
    struct usb_device *rhdev;
    嵌入式开发联盟" |2 F: a. F# m' i: P
    www.mcuos.com& t- q- d% f; |$ S5 ]) x

    dev_info(hcd->self.controller, "%s\n", hcd->product_desc);

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,0 ~" F8 Y6 [* n3 W8 x/ N; c$ v

    set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
    嵌入式开发联盟3 m/ b. k+ t- `  s3 h) N
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,. Y6 a+ {; ?1 _

    /* HC is in reset state, but accessible.
    Now do the one-time init,


    4 x* ?  N; e" L2 g5 T
    * bottom up so that hcds can customize the root hubs before khubd

    www.mcuos.com! X9 ]: f/ G  o

    * starts talking to them.arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,; i# e; g0 f+ @8 |' P) |* _
    (Note, bus id is assigned early too.)

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,. @! [1 v5 }: V" d6 i7 J. R0 w0 N

    */


    if ((retval = hcd_buffer_create(hcd)) != 0) {


    dev_dbg(hcd->self.controller, "pool alloc failed\n");
    4 Z( E+ ~# e) _. Y0 T
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,' F! e) @0 O; K9 k5 }5 k
    return retval;
    我们只做简洁、专业的嵌入式开发技术论坛。  }$ @! W: b, i% L, k8 R: T
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,! G0 k2 x: k9 D8 n' ?
    }

    //注册上面初始化的usb_host总线,就相当于usb _host驱动( L3 u! k- L1 f
    嵌入式开发联盟8 g9 e5 E8 o0 _8 ?4 O) X1 A
    if ((retval = 
    usb_register_bus(&hcd->self)) < 0)

    嵌入式开发联盟( x* p% q! i: s$ ?: G
    goto err_register_bus;

    //分配root hub结构- 我们只做简洁、实用、专业的嵌入式开发技术论坛。7 {4 d! O8 t. i

    if ((rhdev = 
    usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
    我们只做简洁、专业的嵌入式开发技术论坛。: ?5 Y! w3 s3 ?. C' z1 K" U+ K
    我们只做简洁、专业的嵌入式开发技术论坛。* G; x- T1 M" l
    dev_err(hcd->self.controller, "unable to allocate root hub\n");


    retval = -ENOMEM;
    3 J  R, b+ U" k& h
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,$ i7 G  |7 U. _) }  }/ p
    goto err_allocate_root_hub;
    我们只做简洁、专业的嵌入式开发技术论坛。7 ~) V+ c' M; {2 X1 ?9 Q

    }
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,; y2 m! s1 h* V/ b3 e* g  M
    //初始化hub速度
           rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :+ H1 d6 y' s6 J: t1 u6 j1 X
    www.mcuos.com/ F7 f" n2 n3 A: O
    USB_SPEED_FULL;

    //把该hub结构付给usb-host总线的根hub指针我们只做简洁、专业的嵌入式开发技术论坛。3 e3 Z8 i: X6 a3 s
           hcd->self.root_hub = rhdev;


    /* wakeup flag init defaults to "everything works" for root hubs,
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。7 I3 H% B* F# V/ w+ A
    我们只做简洁、专业的嵌入式开发技术论坛。# g, {% {# C0 I$ D* K
    嵌入式开发联盟9 v7 i. `& r  Z3 W% ^
    * but drivers can override it in reset() if needed, along with
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。; \" M+ R0 j$ g% G. e
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,+ J6 Q- ]) Y) a1 `" e: V

    * recording the overall controller's system wakeup capability.
    我们只做简洁、专业的嵌入式开发技术论坛。0 h8 h! v1 \9 A: i
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。) t( x" C& Q2 a

    */
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,. N7 T+ S# V! `+ W$ o( E

    device_init_wakeup(&rhdev->dev, 1);
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,1 o" W( `8 |. g' ~( P
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,1 Y0 d& u% [! x9 I0 s& ~2 Q
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,' r, f' y) u, F9 S; y8 g
    /* "reset" is misnamed; its role is now one-time init. the controller
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。& i( H1 R$ c( r# i3 l7 j; Q
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。8 [6 i! L8 U* w4 n, k& W$ w

    * should already have been reset (and boot firmware kicked off etc).

    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。# @, G& D9 K$ N9 o

    */

    //调用上面的.reset = ehci_init,函数
    6 A2 D' n# X, @* p9 \1 T4 s
    if (hcd->driver->reset && 
    (retval = hcd->driver->reset(hcd)) < 0) {
    www.mcuos.com' S0 D% [5 Z  v5 x
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。  B/ q1 z# Z* A
    dev_err(hcd->self.controller, "can't setup\n");

    我们只做简洁、专业的嵌入式开发技术论坛。- |. [2 o- h8 g
    goto err_hcd_driver_setup;
    www.mcuos.com% B2 U; F$ J; ~' e# ?* G9 o$ j# u
    www.mcuos.com# @( x" T/ a, j5 }& V2 j
    }

    www.mcuos.com* V: f, D- ^( f3 E
    - l8 k2 e) O0 A3 f! @4 L  s  X7 @
    /* NOTE: root hub and controller capabilities may not be the same */

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,& V0 C8 o9 e8 r: ?4 _+ z+ ?' K3 W( x. U
    if (device_can_wakeup(hcd->self.controller)


    && device_can_wakeup(&hcd->self.root_hub->dev))
    www.mcuos.com0 h: C( x4 Z$ ^9 E: n) p, T

    dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");

    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。+ |8 y' Y# R4 h8 h
    7 A1 X) S: ~6 q
    /* enable irqs just before we start the controller */


    if (
    hcd->driver->irq) {
    www.mcuos.com( D3 A' U6 l* U) g3 P" U
    //判断.irq = ehci_irq是否定义,若定义则开始申请irqwww.mcuos.com/ I$ o7 Y3 l0 e) ~
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。- u- |/ l, I2 o! Z# m) J& e
    char嵌入式开发联盟1 s0 h( e9 e& j
    buf[8], *bufp = buf;
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,; y1 V  U( l& x# Y4 l6 k5 n; u

    #ifdef __sparc__

    bufp = __irq_itoa(irqnum);

    #else嵌入式开发联盟# J3 n- n; o% _5 G* f( W; H: w

    sprintf(buf, "%d", irqnum);

    #endif

    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。$ V+ _2 S% O$ `" y0 `2 D' r
    snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",

    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。% l( V8 W' B% K$ z9 I. [
    hcd->driver->description, hcd->self.busnum);


    //printk("====> request irq %d for usb\n", irqnum);


    if ((retval = 
    request_irq(irqnum, &usb_hcd_irq, irqflags,

    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。( @4 {; o! f( D& U+ B2 F) K# S8 l
    hcd->irq_descr, hcd)) != 0) {


    dev_err(hcd->self.controller,

    嵌入式开发联盟; G8 r' e! ^/ e; E6 W% ]4 p
    "request interrupt %s failed\n", bufp);
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,# N. _+ Q) \0 S# \' ]  V+ @0 N

    goto err_request_irq;

    嵌入式开发联盟% g0 r8 a) z0 y1 c4 b
    }
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,8 i5 Y" }" z$ ?9 R( J) R6 ]
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。0 p) e! q" U  e4 H6 ]
    //=============- 我们只做简洁、实用、专业的嵌入式开发技术论坛。3 E, A% ]9 S+ p- F' I; c5 k' G
    enable IRQ group

                  *(unsigned int volatile *)(0xf0000084) |= 0x300;嵌入式开发联盟; \& h% L; A( e4 v2 O. e! `9 h( g

    //============
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,7 a4 c9 Z- i8 p/ H
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。* N$ |3 l( j5 v4 U
    hcd->irq = irqnum;

    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,' l3 p1 h. Z6 d' F, L
    dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp,



    (hcd->driver->flags & HCD_MEMORY) ?
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,# {' F; c7 [( z  M3 m3 y9 ~; w% s! e

    "io mem" : "io base",


    (unsigned long long)hcd->rsrc_start);
    www.mcuos.com4 T5 y! n$ r0 ^9 X/ E3 ?( a

    } else {
    嵌入式开发联盟3 l3 c7 J2 [, a4 Q. S' P$ [+ x
    ( W7 O& r4 o$ j
    hcd->irq = -1;
    * A* o; j& G; X

    if (hcd->rsrc_start)
    % n5 C1 B, z1 E7 o$ I

    dev_info(hcd->self.controller, "%s 0x%08llx\n",
    嵌入式开发联盟" Q  U8 o: u, E# H0 H! F# l. s) z: \

    (hcd->driver->flags & HCD_MEMORY) ?


    "io mem" : "io base",


    (unsigned long long)hcd->rsrc_start);
    嵌入式开发联盟6 {% |% T" R# R

    }
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。3 x4 X: `/ {) X  H- ^9 ]


    if ((
    retval = hcd->driver->start(hcd)) < 0) {
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,, s" y" b# [4 n/ w
    //调用.start = ehci_run,正式开始启动usb工作
    ( j8 @  B- q: N
    www.mcuos.com8 I( Y; t9 u1 _0 a
    printk("start up error\\\\\\\\\\\\\\\\\\n");
    0 I" \* y7 H; }+ u$ ^
    $ `6 Z% r+ g0 U6 G
    dev_err(hcd->self.controller, "startup error %d\n", retval);
    ( X+ F  E/ G8 b( k& ^1 N+ a+ v6 S# ~! v

    goto err_hcd_driver_start;

    % n9 w% {7 _/ m; Y' G8 Y& W. Z
    }
    我们只做简洁、专业的嵌入式开发技术论坛。6 s; [7 e+ Q* ?$ o
    我们只做简洁、专业的嵌入式开发技术论坛。& X% U. X, C  V7 n! I5 L7 C" W
    $ E7 Q! k  G* D1 y7 ^9 h+ Q' P* Q1 ]
    /* starting here, usbcore will pay attention to this root hub */


    rhdev->bus_mA = min(500u, hcd->power_budget);

    //注册根Hub,并开始轮询根Hub的状态变化
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye,. f, p+ t& `: @- b
    if ((retval = register_root_hub(hcd)) != 0)


    goto err_register_root_hub;


    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。. l: L/ `" G0 V, ~3 ~$ ?6 ]1 e* i
    if (hcd->uses_new_polling && hcd->poll_rh)

                  usb_hcd_poll_rh_status(hcd);//轮询- 我们只做简洁、实用、专业的嵌入式开发技术论坛。. o& w) D6 V/ v

    return retval;
    嵌入式开发联盟  a* f6 o2 N1 x/ T. ?9 N. F
    - 我们只做简洁、实用、专业的嵌入式开发技术论坛。& G/ m- k, U. d
    err_register_root_hub:5 O, C) M" a- V- b0 J+ y

    hcd->driver->stop(hcd);
      z$ f  o, V* Z6 F- y
    err_hcd_driver_start:嵌入式开发联盟9 N6 O/ b. ~7 q: r  O# e. `" c
    $ V0 R) J7 ]5 a8 s" J: P3 [
    if (hcd->irq >= 0)


    free_irq(irqnum, hcd);

    err_request_irq:
    err_hcd_driver_setup:
    www.mcuos.com: R0 {5 E0 W, l* g
    hcd->self.root_hub = NULL;


    usb_put_dev(rhdev);

    err_allocate_root_hub:嵌入式开发联盟4 U( N  o& Q& \  r/ Z5 a" a
    我们只做简洁、专业的嵌入式开发技术论坛。; Z! E) B4 {# @7 D) L
    usb_deregister_bus(&hcd->self);

    err_register_bus:

    hcd_buffer_destroy(hcd);
    arm,linux,winbond,nuvoton,w90p710,w90n745,开源,嵌入式,操作系统,嵌入式开发,嵌入式联盟,linux,ecos,uclinux,t-kernel,freeos,rtems,ucos,skyeye," V9 {# m# h2 ^! }
    ( w" g# n0 J" O$ Q# m
    return retval;

    }
    /*-----------------------------------------上面是w90x900 usb host调试纪实-------------------------------------------*/

    /*-----------------------------------------下面是s3c6410 usb host调试纪实-------------------------------------------*/
    共需要修改个文件:
    kernel下:
    drivers/usb/kconfig
    drivers/usb/host/ohci-hcd.c
    arch/arm/mach-s3c6410/mach-smdk6410.c
    arch/arm/plat-s3c64xx/devs.c
    U-boot-nand下:
    board/samsung/smdk6410/lowlevel_init.S
     
     
    下面是攻略:
    [S3C6410]USB-HOST驱动完成
     

    idea6410开发手册中提到使用usb-host功能必须将无源晶振改为48MHz有源晶振,最近看了一下,使用OHCI兼容的USB-Host功能,可以通过EPLL提供时钟,也就是说外接晶振完全无用。果然,经过一晚的奋斗,USB-HOST功能搞定,记录一下过程。

    (1)首先看了S3C6410的数据手册,25章USB-HOST就薄薄两页,和S3C2410基本一样,大意是你去参考OHCI手册吧。
    这说明S3C6410的USB基本上是做好的,兼容OHCI,不需要我们做太多修改。

    (2)修改内核,添加USB支持,添加OHCI HOST HCD支持,添加U盘等支持。发现以前写的帖子还蛮管用的:
    http://hi.baidu.com/aokikyon/blog/item/8545893e3a8a6ffc838b1307.html

    还得修改/drivers/usb/kconfig

    添加config USB_ARCH_HAS_OHCI对S3C64XX的支持

    default y if ARCH_S3C64XX

    (3)选择完毕,开始编译,发现以下问题:
    CC      drivers/usb/host/ohci-hcd.o
    drivers/usb/host/ohci-hcd.c:1091:2: error: #error "missing bus glue for ohci-hcd"
    make[3]: *** [drivers/usb/host/ohci-hcd.o] 错误 1
    make[2]: *** [drivers/usb/host] 错误 2
    make[1]: *** [drivers/usb] 错误 2
    make: *** [drivers] 错误 2

    看了一下OHCI文件,发现要想三星芯片使用,需要包含ohci-s3c2410.c文件,如果没哟包含这个文件,就会提示找不到hcd的以上错误。
    这段代码在ohci-hcd.c中是这样定义的
    #ifdef CONFIG_ARCH_S3C2410
    #include "ohci-s3c2410.c"
    #define PLATFORM_DRIVER   ohci_hcd_s3c2410_driver
    #endif

    由于我们使用的是S3C6410,并没有CONFIG_ARCH_S3C2410,手动修改一下好了:
    #ifdef CONFIG_ARCH_S3C64XX
    #include "ohci-s3c2410.c"
    #define PLATFORM_DRIVER   ohci_hcd_s3c2410_driver
    #endif

    (4)编译完毕后完全没有反应,参考2.6.24代码,发现需要添加platform-device注册信息:
    /plat-s3c64xx/devs.c
    /* USB Host Controller */
    static struct resource s3c_usb_resource[] = {
    [0] = {
       .start = S3C24XX_PA_USBHOST,
       .end   = S3C24XX_PA_USBHOST + S3C24XX_SZ_USBHOST - 1,
       .flags = IORESOURCE_MEM,
    },
    #if !defined(CONFIG_CPU_S3C6400) && !defined(CONFIG_CPU_S3C6410)
    [1] = {
       .start = IRQ_USBH,
       .end   = IRQ_USBH,
       .flags = IORESOURCE_IRQ,
    }
    #else
    [1] = {
       .start = IRQ_UHOST,
       .end   = IRQ_UHOST,
       .flags = IORESOURCE_IRQ,
    }
    #endif
    };

    static u64 s3c_device_usb_dmamask = 0xffffffffUL;

    struct platform_device s3c_device_usb = {
    .name    = "s3c2410-ohci",
    .id    = -1,
    .num_resources   = ARRAY_SIZE(s3c_usb_resource),
    .resource   = s3c_usb_resource,
    .dev              = {
       .dma_mask = &s3c_device_usb_dmamask,
       .coherent_dma_mask = 0xffffffffUL
    }
    };
    EXPORT_SYMBOL(s3c_device_usb);

    编译后还是发现错误,S3C24XX_PA_USBHOST、S3C24XX_PA_USBHOST、IRQ_USBH都没有定义。
    查找半天后发现HOST的物理地址0x74300000没有定义,手动填入这个地址好了。
    SIZE大概写一个尺寸,比如1K就可以(实际上用到很少)。
    至于中断号,开始我填了中断控制器中的位置47,可惜不对,后来发现头文件中有定义,填IRQ_USBH.
    一下是修改后代码:
    /* USB Host Controller add by rockie */

    static struct resource s3c_usb_resource[] = {
    [0] = {
       .start = 0x74300000,//S3C24XX_PA_USBHOST,
       .end   = 0x74301000,//S3C24XX_PA_USBHOST + S3C24XX_SZ_USBHOST - 1,
       .flags = IORESOURCE_MEM,
    },
    [1] = {
       .start = IRQ_USBH,//IRQ_UHOST,
       .end   = IRQ_USBH,//IRQ_UHOST,
       .flags = IORESOURCE_IRQ,
    }
    };

    static u64 s3c_device_usb_dmamask = 0xffffffffUL;

    struct platform_device s3c_device_usb = {
    .name    = "s3c2410-ohci",
    .id    = -1,
    .num_resources   = ARRAY_SIZE(s3c_usb_resource),
    .resource   = s3c_usb_resource,
    .dev              = {
       .dma_mask = &s3c_device_usb_dmamask,
       .coherent_dma_mask = 0xffffffffUL
    }
    };

    EXPORT_SYMBOL(s3c_device_usb);

    还需要注册进平台设备:
    /mach-smdk6410/mach-s3c6410.c添加

    static struct platform_device *smdk6410_devices[] __initdata = {
    ...
    &s3c_device_usb, //<——添加这句即可
    ...
    }


    (5)编译完毕,初始化怎么还是错误?
    ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
    s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
    s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
    s3c2410-ohci s3c2410-ohci: irq 79, io mem 0x74300000
    s3c2410-ohci s3c2410-ohci: init err (00000000 0000)
    ohci_hcd: can't start s3c24xx
    s3c2410-ohci s3c2410-ohci: startup error -75
    s3c2410-ohci s3c2410-ohci: USB bus 1 deregistered
    s3c2410-ohci: probe of s3c2410-ohci failed with error -75
    Initializing USB Mass Storage driver...
    usbcore: registered new interface driver usb-storage
    USB Mass Storage support registered.

    原来还要完成初始化时钟的函数:
    /mach-smdk6410/mach-s3c6410.c

    #if defined(CONFIG_USB_GADGET_S3C_OTGD) || defined(CONFIG_USB_OHCI_HCD)
    #include <plat/regs-otg.h>

    #include <linux/usb/ch9.h> 
    #endif

    /*************************************************************************************
    * USB HOST
    **************************************************************************************/
    #ifdef CONFIG_USB_OHCI_HCD
    void usb_host_clk_en(int usb_host_clksrc) 
    {
    printk("Usb Host CLK enable! 2009 by Rockie \n");

    switch (usb_host_clksrc) 
    {
    case 0: // epll clk 
       writel((readl(S3C_CLK_SRC)& ~S3C_CLKSRC_UHOST_MASK) | S3C_CLKSRC_EPLL_CLKSEL | S3C_CLKSRC_UHOST_EPLL, S3C_CLK_SRC);

       // USB host colock divider ratio is 2 /
       //writel((readl(S3C_CLK_DIV1)& ~S3C_CLKDIVN_UHOST_MASK) | S3C_CLKDIV1_USBDIV2, S3C_CLK_DIV1);
       *(volatile unsigned long*) S3C_CLK_DIV1 |= (0<<20); 
       break;
    case 1: // oscillator 48M clk /
       writel(readl(S3C_CLK_SRC)& ~S3C_CLKSRC_UHOST_MASK, S3C_CLK_SRC);
       //otg_phy_init(otg_phy_clk);

       // USB host colock divider ratio is 1 /
       //writel(readl(S3C_CLK_DIV1)& ~S3C_CLKDIVN_UHOST_MASK, S3C_CLK_DIV1);
       *(volatile unsigned long*) S3C_CLK_DIV1 |= (0<<20);
       break;
    default:
       printk(KERN_INFO "Unknown USB Host Clock Source\n");
       BUG();
       break;

    }

    writel(readl(S3C_HCLK_GATE)|S3C_CLKCON_HCLK_UHOST|S3C_CLKCON_HCLK_SECUR, S3C_HCLK_GATE);
    writel(readl(S3C_SCLK_GATE)|S3C_CLKCON_SCLK_UHOST, S3C_SCLK_GATE);

    }
    EXPORT_SYMBOL(usb_host_clk_en); 
    #endif

    最后别忘了初始化时调用这个函数(在smdk6410_machine_init函数中调用,用前需声明):
    usb_host_clk_en(0);

    最好用宏圈住

    #ifdef CONFIG_USB_OHCI_HCD
    usb_host_clk_en(0);
    #endif

    (6)初始化通过
    ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
    s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
    s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
    s3c2410-ohci s3c2410-ohci: irq 79, io mem 0x74300000
    usb usb1: New USB device found, idVendor=1d6b, idProduct=0001
    usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
    usb usb1: Product: S3C24XX OHCI
    usb usb1: Manufacturer: Linux 2.6.29 ohci_hcd
    usb usb1: SerialNumber: s3c24xx
    usb usb1: configuration #1 chosen from 1 choice
    hub 1-0:1.0: USB hub found
    hub 1-0:1.0: 2 ports detected
    Initializing USB Mass Storage driver...
    usbcore: registered new interface driver usb-storage
    USB Mass Storage support registered.

    但是插上U盘提示错误:
    / # usb 1-1: new full speed USB device using s3c2410-ohci and address 2
    usb 1-1: device descriptor read/64, error -62
    usb 1-1: device descriptor read/64, error -62
    usb 1-1: new full speed USB device using s3c2410-ohci and address 3
    usb 1-1: device descriptor read/64, error -62
    usb 1-1: device descriptor read/64, error -62
    usb 1-1: new full speed USB device using s3c2410-ohci and address 4
    usb 1-1: device not accepting address 4, error -62
    usb 1-1: new full speed USB device using s3c2410-ohci and address 5
    usb 1-1: device not accepting address 5, error -62
    hub 1-0:1.0: unable to enumerate USB device on port 1

    怎么回事呢?原来EPLL初始化时只有24MHz,怎么分频也到不了48MHz啊!
    S3C24XX Clocks, (c) 2004 Simtec Electronics
    S3C64XX: PLL settings, A=666000000, M=532000000, E=24000000
    S3C64XX: HCLK2=266000000, HCLK=133000000, PCLK=66500000
    mout_apll: source is fout_apll (1), rate is 666000000
    mout_epll: source is fout_epll (1), rate is 24000000
    mout_mpll: source is mpll (1), rate is 532000000
    mmc_bus: source is mout_epll (0), rate is 24000000
    mmc_bus: source is mout_epll (0), rate is 24000000
    mmc_bus: source is mout_epll (0), rate is 24000000
    usb-bus-host: source is clk_48m (0), rate is 48000000
    uclk1: source is dout_mpll (1), rate is 66500000
    spi-bus: source is mout_epll (0), rate is 24000000
    spi-bus: source is mout_epll (0), rate is 24000000
    audio-bus: source is mout_epll (0), rate is 24000000
    audio-bus: source is mout_epll (0), rate is 24000000
    irda-bus: source is mout_epll (0), rate is 24000000

    在Linux内核里尝试修改EPLL_CON0,M=0x20 P=1 S=3,计算出32*12MHz/(2^3)=48MHz
    可是Linux中总是写这个寄存器不成功,最后怒了,直接修改U-boot,从汇编了改了回来。
    在board/samsung/smdk6410/lowlevel_init.S(这里是编译u-boot-nand的源码)中有用到
    ldr r1, =APLL_VAL
    str r1, [r0, #APLL_CON_OFFSET] //这里写APLL_CON寄存器
    ldr r1, =MPLL_VAL
    str r1, [r0, #MPLL_CON_OFFSET] //这里写MPLL_CON寄存器

    ldr r1, =0x80200203    /* FOUT of EPLL is 96MHz */
    str r1, [r0, #EPLL_CON0_OFFSET]
    ldr r1, =0x0
    str r1, [r0, #EPLL_CON1_OFFSET]

    ldr r1, [r0, #CLK_SRC_OFFSET] /* APLL, MPLL, EPLL select to Fout */

    看这段,注释EPLL是96MHz,实际这样配置只有24MHz。
    ldr r1, =0x80200203    /* FOUT of EPLL is 24MHz */
    修改为
    ldr r1, =0x80200103    /* FOUT of EPLL is 48MHz */

    s3c6410支持三个PLL分别是APLLMPLLEPLLAPLLARM提供时钟,产生ARMCLKMPLL为所有和AXI/AHB/APB相连的模块提供时钟,产生HCLKPCLKEPLL为特殊的外设提供时钟,产生SCLK。详见S3C6410处理器介绍

    (7)编译,通过。
    S3C24XX Clocks, (c) 2004 Simtec Electronics
    S3C64XX: PLL settings, A=666000000, M=532000000, E=48000000
    S3C64XX: HCLK2=266000000, HCLK=133000000, PCLK=66500000
    mout_apll: source is fout_apll (1), rate is 666000000
    mout_epll: source is fout_epll (1), rate is 48000000
    mout_mpll: source is mpll (1), rate is 532000000
    mmc_bus: source is mout_epll (0), rate is 48000000
    mmc_bus: source is mout_epll (0), rate is 48000000
    mmc_bus: source is mout_epll (0), rate is 48000000
    usb-bus-host: source is clk_48m (0), rate is 48000000
    uclk1: source is dout_mpll (1), rate is 66500000
    spi-bus: source is mout_epll (0), rate is 48000000
    spi-bus: source is mout_epll (0), rate is 48000000
    audio-bus: source is mout_epll (0), rate is 48000000
    audio-bus: source is mout_epll (0), rate is 48000000
    irda-bus: source is mout_epll (0), rate is 48000000

    ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
    s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
    s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
    s3c2410-ohci s3c2410-ohci: irq 79, io mem 0x74300000
    usb usb1: New USB device found, idVendor=1d6b, idProduct=0001
    usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
    usb usb1: Product: S3C24XX OHCI
    usb usb1: Manufacturer: Linux 2.6.29 ohci_hcd
    usb usb1: SerialNumber: s3c24xx
    usb usb1: configuration #1 chosen from 1 choice
    hub 1-0:1.0: USB hub found
    hub 1-0:1.0: 2 ports detected
    Initializing USB Mass Storage driver...


    至此USB-HOST功能可以正常使用:
    / # usb 1-1: new full speed USB device using s3c2410-ohci and address 2
    usb 1-1: New USB device found, idVendor=1976, idProduct=1307
    usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
    usb 1-1: Product: USB Reader
    usb 1-1: Manufacturer: ChipsBnk
    usb 1-1: SerialNumber: 110074973765
    usb 1-1: configuration #1 chosen from 1 choice
    uba: unknown partition table

    / # mount -t vfat /dev/uba1 /mnt
    / # cd mnt
    /mnt # ls
    4020 NorFlash_bootloader
    ??
    ?????
    ??????
    ??ACM????200?
    ?tcp ip?????? ????????????(???????).pdf
    ARMKiller???????????.doc
    Jlink Driver
    TCPIP list
    elf
    elf2
    elf3
    elf5
    elf6
    elf7
    ieka
    linux-2.6.28.tar.bz2
    modsile
    reserve_mmu
    test_sdram.elf
    xme30.zip
    /mnt # cd .. 
    / # umount /mnt
    / # usb 1-1: USB disconnect, address 2

    接下来调试VIAUSBMODEM,除了修改VIAUSBModem.c和VIAUSBModem.h两个文件外还需要修改:

    /driver/usb/serial/kconfig

    /driver/usb/serial/makefile两个文件

     

    原文:http://blog.csdn.net/ken831001/article/details/7293002